1b8e80941Smrg/*
2b8e80941Smrg * Copyright © 2015-2017 Broadcom
3b8e80941Smrg *
4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5b8e80941Smrg * copy of this software and associated documentation files (the "Software"),
6b8e80941Smrg * to deal in the Software without restriction, including without limitation
7b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the
9b8e80941Smrg * Software is furnished to do so, subject to the following conditions:
10b8e80941Smrg *
11b8e80941Smrg * The above copyright notice and this permission notice (including the next
12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the
13b8e80941Smrg * Software.
14b8e80941Smrg *
15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20b8e80941Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21b8e80941Smrg * IN THE SOFTWARE.
22b8e80941Smrg */
23b8e80941Smrg
24b8e80941Smrg#include "util/u_format.h"
25b8e80941Smrg#include "util/u_surface.h"
26b8e80941Smrg#include "util/u_blitter.h"
27b8e80941Smrg#include "v3d_context.h"
28b8e80941Smrg#include "v3d_tiling.h"
29b8e80941Smrg
30b8e80941Smrg#if 0
31b8e80941Smrgstatic struct pipe_surface *
32b8e80941Smrgv3d_get_blit_surface(struct pipe_context *pctx,
33b8e80941Smrg                     struct pipe_resource *prsc, unsigned level)
34b8e80941Smrg{
35b8e80941Smrg        struct pipe_surface tmpl;
36b8e80941Smrg
37b8e80941Smrg        memset(&tmpl, 0, sizeof(tmpl));
38b8e80941Smrg        tmpl.format = prsc->format;
39b8e80941Smrg        tmpl.u.tex.level = level;
40b8e80941Smrg        tmpl.u.tex.first_layer = 0;
41b8e80941Smrg        tmpl.u.tex.last_layer = 0;
42b8e80941Smrg
43b8e80941Smrg        return pctx->create_surface(pctx, prsc, &tmpl);
44b8e80941Smrg}
45b8e80941Smrg
46b8e80941Smrgstatic bool
47b8e80941Smrgis_tile_unaligned(unsigned size, unsigned tile_size)
48b8e80941Smrg{
49b8e80941Smrg        return size & (tile_size - 1);
50b8e80941Smrg}
51b8e80941Smrg
52b8e80941Smrgstatic bool
53b8e80941Smrgv3d_tile_blit(struct pipe_context *pctx, const struct pipe_blit_info *info)
54b8e80941Smrg{
55b8e80941Smrg        struct v3d_context *v3d = v3d_context(pctx);
56b8e80941Smrg        bool msaa = (info->src.resource->nr_samples > 1 ||
57b8e80941Smrg                     info->dst.resource->nr_samples > 1);
58b8e80941Smrg        int tile_width = msaa ? 32 : 64;
59b8e80941Smrg        int tile_height = msaa ? 32 : 64;
60b8e80941Smrg
61b8e80941Smrg        if (util_format_is_depth_or_stencil(info->dst.resource->format))
62b8e80941Smrg                return false;
63b8e80941Smrg
64b8e80941Smrg        if (info->scissor_enable)
65b8e80941Smrg                return false;
66b8e80941Smrg
67b8e80941Smrg        if ((info->mask & PIPE_MASK_RGBA) == 0)
68b8e80941Smrg                return false;
69b8e80941Smrg
70b8e80941Smrg        if (info->dst.box.x != info->src.box.x ||
71b8e80941Smrg            info->dst.box.y != info->src.box.y ||
72b8e80941Smrg            info->dst.box.width != info->src.box.width ||
73b8e80941Smrg            info->dst.box.height != info->src.box.height) {
74b8e80941Smrg                return false;
75b8e80941Smrg        }
76b8e80941Smrg
77b8e80941Smrg        int dst_surface_width = u_minify(info->dst.resource->width0,
78b8e80941Smrg                                         info->dst.level);
79b8e80941Smrg        int dst_surface_height = u_minify(info->dst.resource->height0,
80b8e80941Smrg                                         info->dst.level);
81b8e80941Smrg        if (is_tile_unaligned(info->dst.box.x, tile_width) ||
82b8e80941Smrg            is_tile_unaligned(info->dst.box.y, tile_height) ||
83b8e80941Smrg            (is_tile_unaligned(info->dst.box.width, tile_width) &&
84b8e80941Smrg             info->dst.box.x + info->dst.box.width != dst_surface_width) ||
85b8e80941Smrg            (is_tile_unaligned(info->dst.box.height, tile_height) &&
86b8e80941Smrg             info->dst.box.y + info->dst.box.height != dst_surface_height)) {
87b8e80941Smrg                return false;
88b8e80941Smrg        }
89b8e80941Smrg
90b8e80941Smrg        /* VC5_PACKET_LOAD_TILE_BUFFER_GENERAL uses the
91b8e80941Smrg         * VC5_PACKET_TILE_RENDERING_MODE_CONFIG's width (determined by our
92b8e80941Smrg         * destination surface) to determine the stride.  This may be wrong
93b8e80941Smrg         * when reading from texture miplevels > 0, which are stored in
94b8e80941Smrg         * POT-sized areas.  For MSAA, the tile addresses are computed
95b8e80941Smrg         * explicitly by the RCL, but still use the destination width to
96b8e80941Smrg         * determine the stride (which could be fixed by explicitly supplying
97b8e80941Smrg         * it in the ABI).
98b8e80941Smrg         */
99b8e80941Smrg        struct v3d_resource *rsc = v3d_resource(info->src.resource);
100b8e80941Smrg
101b8e80941Smrg        uint32_t stride;
102b8e80941Smrg
103b8e80941Smrg        if (info->src.resource->nr_samples > 1)
104b8e80941Smrg                stride = align(dst_surface_width, 32) * 4 * rsc->cpp;
105b8e80941Smrg        /* XXX else if (rsc->slices[info->src.level].tiling == VC5_TILING_FORMAT_T)
106b8e80941Smrg           stride = align(dst_surface_width * rsc->cpp, 128); */
107b8e80941Smrg        else
108b8e80941Smrg                stride = align(dst_surface_width * rsc->cpp, 16);
109b8e80941Smrg
110b8e80941Smrg        if (stride != rsc->slices[info->src.level].stride)
111b8e80941Smrg                return false;
112b8e80941Smrg
113b8e80941Smrg        if (info->dst.resource->format != info->src.resource->format)
114b8e80941Smrg                return false;
115b8e80941Smrg
116b8e80941Smrg        if (false) {
117b8e80941Smrg                fprintf(stderr, "RCL blit from %d,%d to %d,%d (%d,%d)\n",
118b8e80941Smrg                        info->src.box.x,
119b8e80941Smrg                        info->src.box.y,
120b8e80941Smrg                        info->dst.box.x,
121b8e80941Smrg                        info->dst.box.y,
122b8e80941Smrg                        info->dst.box.width,
123b8e80941Smrg                        info->dst.box.height);
124b8e80941Smrg        }
125b8e80941Smrg
126b8e80941Smrg        struct pipe_surface *dst_surf =
127b8e80941Smrg                v3d_get_blit_surface(pctx, info->dst.resource, info->dst.level);
128b8e80941Smrg        struct pipe_surface *src_surf =
129b8e80941Smrg                v3d_get_blit_surface(pctx, info->src.resource, info->src.level);
130b8e80941Smrg
131b8e80941Smrg        v3d_flush_jobs_reading_resource(v3d, info->src.resource);
132b8e80941Smrg
133b8e80941Smrg        struct v3d_job *job = v3d_get_job(v3d, dst_surf, NULL);
134b8e80941Smrg        pipe_surface_reference(&job->color_read, src_surf);
135b8e80941Smrg
136b8e80941Smrg        /* If we're resolving from MSAA to single sample, we still need to run
137b8e80941Smrg         * the engine in MSAA mode for the load.
138b8e80941Smrg         */
139b8e80941Smrg        if (!job->msaa && info->src.resource->nr_samples > 1) {
140b8e80941Smrg                job->msaa = true;
141b8e80941Smrg                job->tile_width = 32;
142b8e80941Smrg                job->tile_height = 32;
143b8e80941Smrg        }
144b8e80941Smrg
145b8e80941Smrg        job->draw_min_x = info->dst.box.x;
146b8e80941Smrg        job->draw_min_y = info->dst.box.y;
147b8e80941Smrg        job->draw_max_x = info->dst.box.x + info->dst.box.width;
148b8e80941Smrg        job->draw_max_y = info->dst.box.y + info->dst.box.height;
149b8e80941Smrg        job->draw_width = dst_surf->width;
150b8e80941Smrg        job->draw_height = dst_surf->height;
151b8e80941Smrg
152b8e80941Smrg        job->tile_width = tile_width;
153b8e80941Smrg        job->tile_height = tile_height;
154b8e80941Smrg        job->msaa = msaa;
155b8e80941Smrg        job->needs_flush = true;
156b8e80941Smrg        job->resolve |= PIPE_CLEAR_COLOR;
157b8e80941Smrg
158b8e80941Smrg        v3d_job_submit(v3d, job);
159b8e80941Smrg
160b8e80941Smrg        pipe_surface_reference(&dst_surf, NULL);
161b8e80941Smrg        pipe_surface_reference(&src_surf, NULL);
162b8e80941Smrg
163b8e80941Smrg        return true;
164b8e80941Smrg}
165b8e80941Smrg#endif
166b8e80941Smrg
167b8e80941Smrgvoid
168b8e80941Smrgv3d_blitter_save(struct v3d_context *v3d)
169b8e80941Smrg{
170b8e80941Smrg        util_blitter_save_fragment_constant_buffer_slot(v3d->blitter,
171b8e80941Smrg                                                        v3d->constbuf[PIPE_SHADER_FRAGMENT].cb);
172b8e80941Smrg        util_blitter_save_vertex_buffer_slot(v3d->blitter, v3d->vertexbuf.vb);
173b8e80941Smrg        util_blitter_save_vertex_elements(v3d->blitter, v3d->vtx);
174b8e80941Smrg        util_blitter_save_vertex_shader(v3d->blitter, v3d->prog.bind_vs);
175b8e80941Smrg        util_blitter_save_so_targets(v3d->blitter, v3d->streamout.num_targets,
176b8e80941Smrg                                     v3d->streamout.targets);
177b8e80941Smrg        util_blitter_save_rasterizer(v3d->blitter, v3d->rasterizer);
178b8e80941Smrg        util_blitter_save_viewport(v3d->blitter, &v3d->viewport);
179b8e80941Smrg        util_blitter_save_scissor(v3d->blitter, &v3d->scissor);
180b8e80941Smrg        util_blitter_save_fragment_shader(v3d->blitter, v3d->prog.bind_fs);
181b8e80941Smrg        util_blitter_save_blend(v3d->blitter, v3d->blend);
182b8e80941Smrg        util_blitter_save_depth_stencil_alpha(v3d->blitter, v3d->zsa);
183b8e80941Smrg        util_blitter_save_stencil_ref(v3d->blitter, &v3d->stencil_ref);
184b8e80941Smrg        util_blitter_save_sample_mask(v3d->blitter, v3d->sample_mask);
185b8e80941Smrg        util_blitter_save_framebuffer(v3d->blitter, &v3d->framebuffer);
186b8e80941Smrg        util_blitter_save_fragment_sampler_states(v3d->blitter,
187b8e80941Smrg                        v3d->tex[PIPE_SHADER_FRAGMENT].num_samplers,
188b8e80941Smrg                        (void **)v3d->tex[PIPE_SHADER_FRAGMENT].samplers);
189b8e80941Smrg        util_blitter_save_fragment_sampler_views(v3d->blitter,
190b8e80941Smrg                        v3d->tex[PIPE_SHADER_FRAGMENT].num_textures,
191b8e80941Smrg                        v3d->tex[PIPE_SHADER_FRAGMENT].textures);
192b8e80941Smrg        util_blitter_save_so_targets(v3d->blitter, v3d->streamout.num_targets,
193b8e80941Smrg                                     v3d->streamout.targets);
194b8e80941Smrg}
195b8e80941Smrg
196b8e80941Smrgstatic bool
197b8e80941Smrgv3d_render_blit(struct pipe_context *ctx, struct pipe_blit_info *info)
198b8e80941Smrg{
199b8e80941Smrg        struct v3d_context *v3d = v3d_context(ctx);
200b8e80941Smrg        struct v3d_resource *src = v3d_resource(info->src.resource);
201b8e80941Smrg        struct pipe_resource *tiled = NULL;
202b8e80941Smrg
203b8e80941Smrg        if (!src->tiled) {
204b8e80941Smrg                struct pipe_box box = {
205b8e80941Smrg                        .x = 0,
206b8e80941Smrg                        .y = 0,
207b8e80941Smrg                        .width = u_minify(info->src.resource->width0,
208b8e80941Smrg                                           info->src.level),
209b8e80941Smrg                        .height = u_minify(info->src.resource->height0,
210b8e80941Smrg                                           info->src.level),
211b8e80941Smrg                        .depth = 1,
212b8e80941Smrg                };
213b8e80941Smrg                struct pipe_resource tmpl = {
214b8e80941Smrg                        .target = info->src.resource->target,
215b8e80941Smrg                        .format = info->src.resource->format,
216b8e80941Smrg                        .width0 = box.width,
217b8e80941Smrg                        .height0 = box.height,
218b8e80941Smrg                        .depth0 = 1,
219b8e80941Smrg                        .array_size = 1,
220b8e80941Smrg                };
221b8e80941Smrg                tiled = ctx->screen->resource_create(ctx->screen, &tmpl);
222b8e80941Smrg                if (!tiled) {
223b8e80941Smrg                        fprintf(stderr, "Failed to create tiled blit temp\n");
224b8e80941Smrg                        return false;
225b8e80941Smrg                }
226b8e80941Smrg                ctx->resource_copy_region(ctx,
227b8e80941Smrg                                          tiled, 0,
228b8e80941Smrg                                          0, 0, 0,
229b8e80941Smrg                                          info->src.resource, info->src.level,
230b8e80941Smrg                                          &box);
231b8e80941Smrg                info->src.level = 0;
232b8e80941Smrg                info->src.resource = tiled;
233b8e80941Smrg        }
234b8e80941Smrg
235b8e80941Smrg        if (!util_blitter_is_blit_supported(v3d->blitter, info)) {
236b8e80941Smrg                fprintf(stderr, "blit unsupported %s -> %s\n",
237b8e80941Smrg                    util_format_short_name(info->src.resource->format),
238b8e80941Smrg                    util_format_short_name(info->dst.resource->format));
239b8e80941Smrg                return false;
240b8e80941Smrg        }
241b8e80941Smrg
242b8e80941Smrg        v3d_blitter_save(v3d);
243b8e80941Smrg        util_blitter_blit(v3d->blitter, info);
244b8e80941Smrg
245b8e80941Smrg        pipe_resource_reference(&tiled, NULL);
246b8e80941Smrg
247b8e80941Smrg        return true;
248b8e80941Smrg}
249b8e80941Smrg
250b8e80941Smrg/* Implement stencil blits by reinterpreting the stencil data as an RGBA8888
251b8e80941Smrg * or R8 texture.
252b8e80941Smrg */
253b8e80941Smrgstatic void
254b8e80941Smrgv3d_stencil_blit(struct pipe_context *ctx, const struct pipe_blit_info *info)
255b8e80941Smrg{
256b8e80941Smrg        struct v3d_context *v3d = v3d_context(ctx);
257b8e80941Smrg        struct v3d_resource *src = v3d_resource(info->src.resource);
258b8e80941Smrg        struct v3d_resource *dst = v3d_resource(info->dst.resource);
259b8e80941Smrg        enum pipe_format src_format, dst_format;
260b8e80941Smrg
261b8e80941Smrg        if (src->separate_stencil) {
262b8e80941Smrg                src = src->separate_stencil;
263b8e80941Smrg                src_format = PIPE_FORMAT_R8_UNORM;
264b8e80941Smrg        } else {
265b8e80941Smrg                src_format = PIPE_FORMAT_RGBA8888_UNORM;
266b8e80941Smrg        }
267b8e80941Smrg
268b8e80941Smrg        if (dst->separate_stencil) {
269b8e80941Smrg                dst = dst->separate_stencil;
270b8e80941Smrg                dst_format = PIPE_FORMAT_R8_UNORM;
271b8e80941Smrg        } else {
272b8e80941Smrg                dst_format = PIPE_FORMAT_RGBA8888_UNORM;
273b8e80941Smrg        }
274b8e80941Smrg
275b8e80941Smrg        /* Initialize the surface. */
276b8e80941Smrg        struct pipe_surface dst_tmpl = {
277b8e80941Smrg                .u.tex = {
278b8e80941Smrg                        .level = info->dst.level,
279b8e80941Smrg                        .first_layer = info->dst.box.z,
280b8e80941Smrg                        .last_layer = info->dst.box.z,
281b8e80941Smrg                },
282b8e80941Smrg                .format = dst_format,
283b8e80941Smrg        };
284b8e80941Smrg        struct pipe_surface *dst_surf =
285b8e80941Smrg                ctx->create_surface(ctx, &dst->base, &dst_tmpl);
286b8e80941Smrg
287b8e80941Smrg        /* Initialize the sampler view. */
288b8e80941Smrg        struct pipe_sampler_view src_tmpl = {
289b8e80941Smrg                .target = src->base.target,
290b8e80941Smrg                .format = src_format,
291b8e80941Smrg                .u.tex = {
292b8e80941Smrg                        .first_level = info->src.level,
293b8e80941Smrg                        .last_level = info->src.level,
294b8e80941Smrg                        .first_layer = 0,
295b8e80941Smrg                        .last_layer = (PIPE_TEXTURE_3D ?
296b8e80941Smrg                                       u_minify(src->base.depth0,
297b8e80941Smrg                                                info->src.level) - 1 :
298b8e80941Smrg                                       src->base.array_size - 1),
299b8e80941Smrg                },
300b8e80941Smrg                .swizzle_r = PIPE_SWIZZLE_X,
301b8e80941Smrg                .swizzle_g = PIPE_SWIZZLE_Y,
302b8e80941Smrg                .swizzle_b = PIPE_SWIZZLE_Z,
303b8e80941Smrg                .swizzle_a = PIPE_SWIZZLE_W,
304b8e80941Smrg        };
305b8e80941Smrg        struct pipe_sampler_view *src_view =
306b8e80941Smrg                ctx->create_sampler_view(ctx, &src->base, &src_tmpl);
307b8e80941Smrg
308b8e80941Smrg        v3d_blitter_save(v3d);
309b8e80941Smrg        util_blitter_blit_generic(v3d->blitter, dst_surf, &info->dst.box,
310b8e80941Smrg                                  src_view, &info->src.box,
311b8e80941Smrg                                  src->base.width0, src->base.height0,
312b8e80941Smrg                                  PIPE_MASK_R,
313b8e80941Smrg                                  PIPE_TEX_FILTER_NEAREST,
314b8e80941Smrg                                  info->scissor_enable ? &info->scissor : NULL,
315b8e80941Smrg                                  info->alpha_blend);
316b8e80941Smrg
317b8e80941Smrg        pipe_surface_reference(&dst_surf, NULL);
318b8e80941Smrg        pipe_sampler_view_reference(&src_view, NULL);
319b8e80941Smrg}
320b8e80941Smrg
321b8e80941Smrg/* Disable level 0 write, just write following mipmaps */
322b8e80941Smrg#define V3D_TFU_IOA_DIMTW (1 << 0)
323b8e80941Smrg#define V3D_TFU_IOA_FORMAT_SHIFT 3
324b8e80941Smrg#define V3D_TFU_IOA_FORMAT_LINEARTILE 3
325b8e80941Smrg#define V3D_TFU_IOA_FORMAT_UBLINEAR_1_COLUMN 4
326b8e80941Smrg#define V3D_TFU_IOA_FORMAT_UBLINEAR_2_COLUMN 5
327b8e80941Smrg#define V3D_TFU_IOA_FORMAT_UIF_NO_XOR 6
328b8e80941Smrg#define V3D_TFU_IOA_FORMAT_UIF_XOR 7
329b8e80941Smrg
330b8e80941Smrg#define V3D_TFU_ICFG_NUMMM_SHIFT 5
331b8e80941Smrg#define V3D_TFU_ICFG_TTYPE_SHIFT 9
332b8e80941Smrg
333b8e80941Smrg#define V3D_TFU_ICFG_OPAD_SHIFT 22
334b8e80941Smrg
335b8e80941Smrg#define V3D_TFU_ICFG_FORMAT_SHIFT 18
336b8e80941Smrg#define V3D_TFU_ICFG_FORMAT_RASTER 0
337b8e80941Smrg#define V3D_TFU_ICFG_FORMAT_SAND_128 1
338b8e80941Smrg#define V3D_TFU_ICFG_FORMAT_SAND_256 2
339b8e80941Smrg#define V3D_TFU_ICFG_FORMAT_LINEARTILE 11
340b8e80941Smrg#define V3D_TFU_ICFG_FORMAT_UBLINEAR_1_COLUMN 12
341b8e80941Smrg#define V3D_TFU_ICFG_FORMAT_UBLINEAR_2_COLUMN 13
342b8e80941Smrg#define V3D_TFU_ICFG_FORMAT_UIF_NO_XOR 14
343b8e80941Smrg#define V3D_TFU_ICFG_FORMAT_UIF_XOR 15
344b8e80941Smrg
345b8e80941Smrgstatic bool
346b8e80941Smrgv3d_tfu(struct pipe_context *pctx,
347b8e80941Smrg        struct pipe_resource *pdst,
348b8e80941Smrg        struct pipe_resource *psrc,
349b8e80941Smrg        unsigned int src_level,
350b8e80941Smrg        unsigned int base_level,
351b8e80941Smrg        unsigned int last_level,
352b8e80941Smrg        unsigned int src_layer,
353b8e80941Smrg        unsigned int dst_layer)
354b8e80941Smrg{
355b8e80941Smrg        struct v3d_context *v3d = v3d_context(pctx);
356b8e80941Smrg        struct v3d_screen *screen = v3d->screen;
357b8e80941Smrg        struct v3d_resource *src = v3d_resource(psrc);
358b8e80941Smrg        struct v3d_resource *dst = v3d_resource(pdst);
359b8e80941Smrg        struct v3d_resource_slice *src_base_slice = &src->slices[src_level];
360b8e80941Smrg        struct v3d_resource_slice *dst_base_slice = &dst->slices[base_level];
361b8e80941Smrg        int msaa_scale = pdst->nr_samples > 1 ? 2 : 1;
362b8e80941Smrg        int width = u_minify(pdst->width0, base_level) * msaa_scale;
363b8e80941Smrg        int height = u_minify(pdst->height0, base_level) * msaa_scale;
364b8e80941Smrg
365b8e80941Smrg        if (psrc->format != pdst->format)
366b8e80941Smrg                return false;
367b8e80941Smrg        if (psrc->nr_samples != pdst->nr_samples)
368b8e80941Smrg                return false;
369b8e80941Smrg
370b8e80941Smrg        uint32_t tex_format = v3d_get_tex_format(&screen->devinfo,
371b8e80941Smrg                                                 pdst->format);
372b8e80941Smrg
373b8e80941Smrg        if (!v3d_tfu_supports_tex_format(&screen->devinfo, tex_format))
374b8e80941Smrg                return false;
375b8e80941Smrg
376b8e80941Smrg        if (pdst->target != PIPE_TEXTURE_2D || psrc->target != PIPE_TEXTURE_2D)
377b8e80941Smrg                return false;
378b8e80941Smrg
379b8e80941Smrg        /* Can't write to raster. */
380b8e80941Smrg        if (dst_base_slice->tiling == VC5_TILING_RASTER)
381b8e80941Smrg                return false;
382b8e80941Smrg
383b8e80941Smrg        v3d_flush_jobs_writing_resource(v3d, psrc);
384b8e80941Smrg        v3d_flush_jobs_reading_resource(v3d, pdst);
385b8e80941Smrg
386b8e80941Smrg        struct drm_v3d_submit_tfu tfu = {
387b8e80941Smrg                .ios = (height << 16) | width,
388b8e80941Smrg                .bo_handles = {
389b8e80941Smrg                        dst->bo->handle,
390b8e80941Smrg                        src != dst ? src->bo->handle : 0
391b8e80941Smrg                },
392b8e80941Smrg                .in_sync = v3d->out_sync,
393b8e80941Smrg                .out_sync = v3d->out_sync,
394b8e80941Smrg        };
395b8e80941Smrg        uint32_t src_offset = (src->bo->offset +
396b8e80941Smrg                               v3d_layer_offset(psrc, src_level, src_layer));
397b8e80941Smrg        tfu.iia |= src_offset;
398b8e80941Smrg        if (src_base_slice->tiling == VC5_TILING_RASTER) {
399b8e80941Smrg                tfu.icfg |= (V3D_TFU_ICFG_FORMAT_RASTER <<
400b8e80941Smrg                             V3D_TFU_ICFG_FORMAT_SHIFT);
401b8e80941Smrg        } else {
402b8e80941Smrg                tfu.icfg |= ((V3D_TFU_ICFG_FORMAT_LINEARTILE +
403b8e80941Smrg                              (src_base_slice->tiling - VC5_TILING_LINEARTILE)) <<
404b8e80941Smrg                             V3D_TFU_ICFG_FORMAT_SHIFT);
405b8e80941Smrg        }
406b8e80941Smrg
407b8e80941Smrg        uint32_t dst_offset = (dst->bo->offset +
408b8e80941Smrg                               v3d_layer_offset(pdst, src_level, dst_layer));
409b8e80941Smrg        tfu.ioa |= dst_offset;
410b8e80941Smrg        if (last_level != base_level)
411b8e80941Smrg                tfu.ioa |= V3D_TFU_IOA_DIMTW;
412b8e80941Smrg        tfu.ioa |= ((V3D_TFU_IOA_FORMAT_LINEARTILE +
413b8e80941Smrg                     (dst_base_slice->tiling - VC5_TILING_LINEARTILE)) <<
414b8e80941Smrg                    V3D_TFU_IOA_FORMAT_SHIFT);
415b8e80941Smrg
416b8e80941Smrg        tfu.icfg |= tex_format << V3D_TFU_ICFG_TTYPE_SHIFT;
417b8e80941Smrg        tfu.icfg |= (last_level - base_level) << V3D_TFU_ICFG_NUMMM_SHIFT;
418b8e80941Smrg
419b8e80941Smrg        switch (src_base_slice->tiling) {
420b8e80941Smrg        case VC5_TILING_UIF_NO_XOR:
421b8e80941Smrg        case VC5_TILING_UIF_XOR:
422b8e80941Smrg                tfu.iis |= (src_base_slice->padded_height /
423b8e80941Smrg                            (2 * v3d_utile_height(src->cpp)));
424b8e80941Smrg                break;
425b8e80941Smrg        case VC5_TILING_RASTER:
426b8e80941Smrg                tfu.iis |= src_base_slice->stride / src->cpp;
427b8e80941Smrg                break;
428b8e80941Smrg        case VC5_TILING_LINEARTILE:
429b8e80941Smrg        case VC5_TILING_UBLINEAR_1_COLUMN:
430b8e80941Smrg        case VC5_TILING_UBLINEAR_2_COLUMN:
431b8e80941Smrg                break;
432b8e80941Smrg       }
433b8e80941Smrg
434b8e80941Smrg        /* If we're writing level 0 (!IOA_DIMTW), then we need to supply the
435b8e80941Smrg         * OPAD field for the destination (how many extra UIF blocks beyond
436b8e80941Smrg         * those necessary to cover the height).  When filling mipmaps, the
437b8e80941Smrg         * miplevel 1+ tiling state is inferred.
438b8e80941Smrg         */
439b8e80941Smrg        if (dst_base_slice->tiling == VC5_TILING_UIF_NO_XOR ||
440b8e80941Smrg            dst_base_slice->tiling == VC5_TILING_UIF_XOR) {
441b8e80941Smrg                int uif_block_h = 2 * v3d_utile_height(dst->cpp);
442b8e80941Smrg                int implicit_padded_height = align(height, uif_block_h);
443b8e80941Smrg
444b8e80941Smrg                tfu.icfg |= (((dst_base_slice->padded_height -
445b8e80941Smrg                               implicit_padded_height) / uif_block_h) <<
446b8e80941Smrg                             V3D_TFU_ICFG_OPAD_SHIFT);
447b8e80941Smrg        }
448b8e80941Smrg
449b8e80941Smrg        int ret = v3d_ioctl(screen->fd, DRM_IOCTL_V3D_SUBMIT_TFU, &tfu);
450b8e80941Smrg        if (ret != 0) {
451b8e80941Smrg                fprintf(stderr, "Failed to submit TFU job: %d\n", ret);
452b8e80941Smrg                return false;
453b8e80941Smrg        }
454b8e80941Smrg
455b8e80941Smrg        dst->writes++;
456b8e80941Smrg
457b8e80941Smrg        return true;
458b8e80941Smrg}
459b8e80941Smrg
460b8e80941Smrgboolean
461b8e80941Smrgv3d_generate_mipmap(struct pipe_context *pctx,
462b8e80941Smrg                    struct pipe_resource *prsc,
463b8e80941Smrg                    enum pipe_format format,
464b8e80941Smrg                    unsigned int base_level,
465b8e80941Smrg                    unsigned int last_level,
466b8e80941Smrg                    unsigned int first_layer,
467b8e80941Smrg                    unsigned int last_layer)
468b8e80941Smrg{
469b8e80941Smrg        if (format != prsc->format)
470b8e80941Smrg                return false;
471b8e80941Smrg
472b8e80941Smrg        /* We could maybe support looping over layers for array textures, but
473b8e80941Smrg         * we definitely don't support 3D.
474b8e80941Smrg         */
475b8e80941Smrg        if (first_layer != last_layer)
476b8e80941Smrg                return false;
477b8e80941Smrg
478b8e80941Smrg        return v3d_tfu(pctx,
479b8e80941Smrg                       prsc, prsc,
480b8e80941Smrg                       base_level,
481b8e80941Smrg                       base_level, last_level,
482b8e80941Smrg                       first_layer, first_layer);
483b8e80941Smrg}
484b8e80941Smrg
485b8e80941Smrgstatic bool
486b8e80941Smrgv3d_tfu_blit(struct pipe_context *pctx, const struct pipe_blit_info *info)
487b8e80941Smrg{
488b8e80941Smrg        int dst_width = u_minify(info->dst.resource->width0, info->dst.level);
489b8e80941Smrg        int dst_height = u_minify(info->dst.resource->height0, info->dst.level);
490b8e80941Smrg
491b8e80941Smrg        if ((info->mask & PIPE_MASK_RGBA) == 0)
492b8e80941Smrg                return false;
493b8e80941Smrg
494b8e80941Smrg        if (info->scissor_enable ||
495b8e80941Smrg            info->dst.box.x != 0 ||
496b8e80941Smrg            info->dst.box.y != 0 ||
497b8e80941Smrg            info->dst.box.width != dst_width ||
498b8e80941Smrg            info->dst.box.height != dst_height ||
499b8e80941Smrg            info->src.box.x != 0 ||
500b8e80941Smrg            info->src.box.y != 0 ||
501b8e80941Smrg            info->src.box.width != info->dst.box.width ||
502b8e80941Smrg            info->src.box.height != info->dst.box.height) {
503b8e80941Smrg                return false;
504b8e80941Smrg        }
505b8e80941Smrg
506b8e80941Smrg        if (info->dst.format != info->src.format)
507b8e80941Smrg                return false;
508b8e80941Smrg
509b8e80941Smrg        return v3d_tfu(pctx, info->dst.resource, info->src.resource,
510b8e80941Smrg                       info->src.level,
511b8e80941Smrg                       info->dst.level, info->dst.level,
512b8e80941Smrg                       info->src.box.z, info->dst.box.z);
513b8e80941Smrg}
514b8e80941Smrg
515b8e80941Smrg/* Optimal hardware path for blitting pixels.
516b8e80941Smrg * Scaling, format conversion, up- and downsampling (resolve) are allowed.
517b8e80941Smrg */
518b8e80941Smrgvoid
519b8e80941Smrgv3d_blit(struct pipe_context *pctx, const struct pipe_blit_info *blit_info)
520b8e80941Smrg{
521b8e80941Smrg        struct v3d_context *v3d = v3d_context(pctx);
522b8e80941Smrg        struct pipe_blit_info info = *blit_info;
523b8e80941Smrg
524b8e80941Smrg        if (info.mask & PIPE_MASK_S) {
525b8e80941Smrg                v3d_stencil_blit(pctx, blit_info);
526b8e80941Smrg                info.mask &= ~PIPE_MASK_S;
527b8e80941Smrg        }
528b8e80941Smrg
529b8e80941Smrg        if (v3d_tfu_blit(pctx, blit_info))
530b8e80941Smrg                info.mask &= ~PIPE_MASK_RGBA;
531b8e80941Smrg
532b8e80941Smrg        if (info.mask)
533b8e80941Smrg                v3d_render_blit(pctx, &info);
534b8e80941Smrg
535b8e80941Smrg        /* Flush our blit jobs immediately.  They're unlikely to get reused by
536b8e80941Smrg         * normal drawing or other blits, and without flushing we can easily
537b8e80941Smrg         * run into unexpected OOMs when blits are used for a large series of
538b8e80941Smrg         * texture uploads before using the textures.
539b8e80941Smrg         */
540b8e80941Smrg        v3d_flush_jobs_writing_resource(v3d, info.dst.resource);
541b8e80941Smrg}
542