1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2015 Broadcom
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci#include "util/format/u_format.h"
25bf215546Sopenharmony_ci#include "util/u_surface.h"
26bf215546Sopenharmony_ci#include "util/u_blitter.h"
27bf215546Sopenharmony_ci#include "compiler/nir/nir_builder.h"
28bf215546Sopenharmony_ci#include "vc4_context.h"
29bf215546Sopenharmony_ci
30bf215546Sopenharmony_cistatic struct pipe_surface *
31bf215546Sopenharmony_civc4_get_blit_surface(struct pipe_context *pctx,
32bf215546Sopenharmony_ci                     struct pipe_resource *prsc, unsigned level)
33bf215546Sopenharmony_ci{
34bf215546Sopenharmony_ci        struct pipe_surface tmpl;
35bf215546Sopenharmony_ci
36bf215546Sopenharmony_ci        memset(&tmpl, 0, sizeof(tmpl));
37bf215546Sopenharmony_ci        tmpl.format = prsc->format;
38bf215546Sopenharmony_ci        tmpl.u.tex.level = level;
39bf215546Sopenharmony_ci        tmpl.u.tex.first_layer = 0;
40bf215546Sopenharmony_ci        tmpl.u.tex.last_layer = 0;
41bf215546Sopenharmony_ci
42bf215546Sopenharmony_ci        return pctx->create_surface(pctx, prsc, &tmpl);
43bf215546Sopenharmony_ci}
44bf215546Sopenharmony_ci
45bf215546Sopenharmony_cistatic bool
46bf215546Sopenharmony_ciis_tile_unaligned(unsigned size, unsigned tile_size)
47bf215546Sopenharmony_ci{
48bf215546Sopenharmony_ci        return size & (tile_size - 1);
49bf215546Sopenharmony_ci}
50bf215546Sopenharmony_ci
51bf215546Sopenharmony_cistatic bool
52bf215546Sopenharmony_civc4_tile_blit(struct pipe_context *pctx, const struct pipe_blit_info *info)
53bf215546Sopenharmony_ci{
54bf215546Sopenharmony_ci        struct vc4_context *vc4 = vc4_context(pctx);
55bf215546Sopenharmony_ci        bool msaa = (info->src.resource->nr_samples > 1 ||
56bf215546Sopenharmony_ci                     info->dst.resource->nr_samples > 1);
57bf215546Sopenharmony_ci        int tile_width = msaa ? 32 : 64;
58bf215546Sopenharmony_ci        int tile_height = msaa ? 32 : 64;
59bf215546Sopenharmony_ci
60bf215546Sopenharmony_ci        if (util_format_is_depth_or_stencil(info->dst.resource->format))
61bf215546Sopenharmony_ci                return false;
62bf215546Sopenharmony_ci
63bf215546Sopenharmony_ci        if (info->scissor_enable)
64bf215546Sopenharmony_ci                return false;
65bf215546Sopenharmony_ci
66bf215546Sopenharmony_ci        if ((info->mask & PIPE_MASK_RGBA) == 0)
67bf215546Sopenharmony_ci                return false;
68bf215546Sopenharmony_ci
69bf215546Sopenharmony_ci        if (info->dst.box.x != info->src.box.x ||
70bf215546Sopenharmony_ci            info->dst.box.y != info->src.box.y ||
71bf215546Sopenharmony_ci            info->dst.box.width != info->src.box.width ||
72bf215546Sopenharmony_ci            info->dst.box.height != info->src.box.height) {
73bf215546Sopenharmony_ci                return false;
74bf215546Sopenharmony_ci        }
75bf215546Sopenharmony_ci
76bf215546Sopenharmony_ci        int dst_surface_width = u_minify(info->dst.resource->width0,
77bf215546Sopenharmony_ci                                         info->dst.level);
78bf215546Sopenharmony_ci        int dst_surface_height = u_minify(info->dst.resource->height0,
79bf215546Sopenharmony_ci                                         info->dst.level);
80bf215546Sopenharmony_ci        if (is_tile_unaligned(info->dst.box.x, tile_width) ||
81bf215546Sopenharmony_ci            is_tile_unaligned(info->dst.box.y, tile_height) ||
82bf215546Sopenharmony_ci            (is_tile_unaligned(info->dst.box.width, tile_width) &&
83bf215546Sopenharmony_ci             info->dst.box.x + info->dst.box.width != dst_surface_width) ||
84bf215546Sopenharmony_ci            (is_tile_unaligned(info->dst.box.height, tile_height) &&
85bf215546Sopenharmony_ci             info->dst.box.y + info->dst.box.height != dst_surface_height)) {
86bf215546Sopenharmony_ci                return false;
87bf215546Sopenharmony_ci        }
88bf215546Sopenharmony_ci
89bf215546Sopenharmony_ci        /* VC4_PACKET_LOAD_TILE_BUFFER_GENERAL uses the
90bf215546Sopenharmony_ci         * VC4_PACKET_TILE_RENDERING_MODE_CONFIG's width (determined by our
91bf215546Sopenharmony_ci         * destination surface) to determine the stride.  This may be wrong
92bf215546Sopenharmony_ci         * when reading from texture miplevels > 0, which are stored in
93bf215546Sopenharmony_ci         * POT-sized areas.  For MSAA, the tile addresses are computed
94bf215546Sopenharmony_ci         * explicitly by the RCL, but still use the destination width to
95bf215546Sopenharmony_ci         * determine the stride (which could be fixed by explicitly supplying
96bf215546Sopenharmony_ci         * it in the ABI).
97bf215546Sopenharmony_ci         */
98bf215546Sopenharmony_ci        struct vc4_resource *rsc = vc4_resource(info->src.resource);
99bf215546Sopenharmony_ci
100bf215546Sopenharmony_ci        uint32_t stride;
101bf215546Sopenharmony_ci
102bf215546Sopenharmony_ci        if (info->src.resource->nr_samples > 1)
103bf215546Sopenharmony_ci                stride = align(dst_surface_width, 32) * 4 * rsc->cpp;
104bf215546Sopenharmony_ci        else if (rsc->slices[info->src.level].tiling == VC4_TILING_FORMAT_T)
105bf215546Sopenharmony_ci                stride = align(dst_surface_width * rsc->cpp, 128);
106bf215546Sopenharmony_ci        else
107bf215546Sopenharmony_ci                stride = align(dst_surface_width * rsc->cpp, 16);
108bf215546Sopenharmony_ci
109bf215546Sopenharmony_ci        if (stride != rsc->slices[info->src.level].stride)
110bf215546Sopenharmony_ci                return false;
111bf215546Sopenharmony_ci
112bf215546Sopenharmony_ci        if (info->dst.resource->format != info->src.resource->format)
113bf215546Sopenharmony_ci                return false;
114bf215546Sopenharmony_ci
115bf215546Sopenharmony_ci        if (false) {
116bf215546Sopenharmony_ci                fprintf(stderr, "RCL blit from %d,%d to %d,%d (%d,%d)\n",
117bf215546Sopenharmony_ci                        info->src.box.x,
118bf215546Sopenharmony_ci                        info->src.box.y,
119bf215546Sopenharmony_ci                        info->dst.box.x,
120bf215546Sopenharmony_ci                        info->dst.box.y,
121bf215546Sopenharmony_ci                        info->dst.box.width,
122bf215546Sopenharmony_ci                        info->dst.box.height);
123bf215546Sopenharmony_ci        }
124bf215546Sopenharmony_ci
125bf215546Sopenharmony_ci        struct pipe_surface *dst_surf =
126bf215546Sopenharmony_ci                vc4_get_blit_surface(pctx, info->dst.resource, info->dst.level);
127bf215546Sopenharmony_ci        struct pipe_surface *src_surf =
128bf215546Sopenharmony_ci                vc4_get_blit_surface(pctx, info->src.resource, info->src.level);
129bf215546Sopenharmony_ci
130bf215546Sopenharmony_ci        vc4_flush_jobs_reading_resource(vc4, info->src.resource);
131bf215546Sopenharmony_ci
132bf215546Sopenharmony_ci        struct vc4_job *job = vc4_get_job(vc4, dst_surf, NULL);
133bf215546Sopenharmony_ci        pipe_surface_reference(&job->color_read, src_surf);
134bf215546Sopenharmony_ci
135bf215546Sopenharmony_ci        job->draw_min_x = info->dst.box.x;
136bf215546Sopenharmony_ci        job->draw_min_y = info->dst.box.y;
137bf215546Sopenharmony_ci        job->draw_max_x = info->dst.box.x + info->dst.box.width;
138bf215546Sopenharmony_ci        job->draw_max_y = info->dst.box.y + info->dst.box.height;
139bf215546Sopenharmony_ci        job->draw_width = dst_surf->width;
140bf215546Sopenharmony_ci        job->draw_height = dst_surf->height;
141bf215546Sopenharmony_ci
142bf215546Sopenharmony_ci        job->tile_width = tile_width;
143bf215546Sopenharmony_ci        job->tile_height = tile_height;
144bf215546Sopenharmony_ci        job->msaa = msaa;
145bf215546Sopenharmony_ci        job->needs_flush = true;
146bf215546Sopenharmony_ci        job->resolve |= PIPE_CLEAR_COLOR;
147bf215546Sopenharmony_ci
148bf215546Sopenharmony_ci        vc4_job_submit(vc4, job);
149bf215546Sopenharmony_ci
150bf215546Sopenharmony_ci        pipe_surface_reference(&dst_surf, NULL);
151bf215546Sopenharmony_ci        pipe_surface_reference(&src_surf, NULL);
152bf215546Sopenharmony_ci
153bf215546Sopenharmony_ci        return true;
154bf215546Sopenharmony_ci}
155bf215546Sopenharmony_ci
156bf215546Sopenharmony_civoid
157bf215546Sopenharmony_civc4_blitter_save(struct vc4_context *vc4)
158bf215546Sopenharmony_ci{
159bf215546Sopenharmony_ci        util_blitter_save_fragment_constant_buffer_slot(vc4->blitter,
160bf215546Sopenharmony_ci                                                        vc4->constbuf[PIPE_SHADER_FRAGMENT].cb);
161bf215546Sopenharmony_ci        util_blitter_save_vertex_buffer_slot(vc4->blitter, vc4->vertexbuf.vb);
162bf215546Sopenharmony_ci        util_blitter_save_vertex_elements(vc4->blitter, vc4->vtx);
163bf215546Sopenharmony_ci        util_blitter_save_vertex_shader(vc4->blitter, vc4->prog.bind_vs);
164bf215546Sopenharmony_ci        util_blitter_save_rasterizer(vc4->blitter, vc4->rasterizer);
165bf215546Sopenharmony_ci        util_blitter_save_viewport(vc4->blitter, &vc4->viewport);
166bf215546Sopenharmony_ci        util_blitter_save_scissor(vc4->blitter, &vc4->scissor);
167bf215546Sopenharmony_ci        util_blitter_save_fragment_shader(vc4->blitter, vc4->prog.bind_fs);
168bf215546Sopenharmony_ci        util_blitter_save_blend(vc4->blitter, vc4->blend);
169bf215546Sopenharmony_ci        util_blitter_save_depth_stencil_alpha(vc4->blitter, vc4->zsa);
170bf215546Sopenharmony_ci        util_blitter_save_stencil_ref(vc4->blitter, &vc4->stencil_ref);
171bf215546Sopenharmony_ci        util_blitter_save_sample_mask(vc4->blitter, vc4->sample_mask, 0);
172bf215546Sopenharmony_ci        util_blitter_save_framebuffer(vc4->blitter, &vc4->framebuffer);
173bf215546Sopenharmony_ci        util_blitter_save_fragment_sampler_states(vc4->blitter,
174bf215546Sopenharmony_ci                        vc4->fragtex.num_samplers,
175bf215546Sopenharmony_ci                        (void **)vc4->fragtex.samplers);
176bf215546Sopenharmony_ci        util_blitter_save_fragment_sampler_views(vc4->blitter,
177bf215546Sopenharmony_ci                        vc4->fragtex.num_textures, vc4->fragtex.textures);
178bf215546Sopenharmony_ci}
179bf215546Sopenharmony_ci
180bf215546Sopenharmony_cistatic void *vc4_get_yuv_vs(struct pipe_context *pctx)
181bf215546Sopenharmony_ci{
182bf215546Sopenharmony_ci   struct vc4_context *vc4 = vc4_context(pctx);
183bf215546Sopenharmony_ci   struct pipe_screen *pscreen = pctx->screen;
184bf215546Sopenharmony_ci
185bf215546Sopenharmony_ci   if (vc4->yuv_linear_blit_vs)
186bf215546Sopenharmony_ci           return vc4->yuv_linear_blit_vs;
187bf215546Sopenharmony_ci
188bf215546Sopenharmony_ci   const struct nir_shader_compiler_options *options =
189bf215546Sopenharmony_ci           pscreen->get_compiler_options(pscreen,
190bf215546Sopenharmony_ci                                         PIPE_SHADER_IR_NIR,
191bf215546Sopenharmony_ci                                         PIPE_SHADER_VERTEX);
192bf215546Sopenharmony_ci
193bf215546Sopenharmony_ci   nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_VERTEX, options,
194bf215546Sopenharmony_ci                                                  "linear_blit_vs");
195bf215546Sopenharmony_ci
196bf215546Sopenharmony_ci   const struct glsl_type *vec4 = glsl_vec4_type();
197bf215546Sopenharmony_ci   nir_variable *pos_in = nir_variable_create(b.shader, nir_var_shader_in,
198bf215546Sopenharmony_ci                                              vec4, "pos");
199bf215546Sopenharmony_ci
200bf215546Sopenharmony_ci   nir_variable *pos_out = nir_variable_create(b.shader, nir_var_shader_out,
201bf215546Sopenharmony_ci                                               vec4, "gl_Position");
202bf215546Sopenharmony_ci   pos_out->data.location = VARYING_SLOT_POS;
203bf215546Sopenharmony_ci
204bf215546Sopenharmony_ci   nir_store_var(&b, pos_out, nir_load_var(&b, pos_in), 0xf);
205bf215546Sopenharmony_ci
206bf215546Sopenharmony_ci   struct pipe_shader_state shader_tmpl = {
207bf215546Sopenharmony_ci           .type = PIPE_SHADER_IR_NIR,
208bf215546Sopenharmony_ci           .ir.nir = b.shader,
209bf215546Sopenharmony_ci   };
210bf215546Sopenharmony_ci
211bf215546Sopenharmony_ci   vc4->yuv_linear_blit_vs = pctx->create_vs_state(pctx, &shader_tmpl);
212bf215546Sopenharmony_ci
213bf215546Sopenharmony_ci   return vc4->yuv_linear_blit_vs;
214bf215546Sopenharmony_ci}
215bf215546Sopenharmony_ci
216bf215546Sopenharmony_cistatic void *vc4_get_yuv_fs(struct pipe_context *pctx, int cpp)
217bf215546Sopenharmony_ci{
218bf215546Sopenharmony_ci   struct vc4_context *vc4 = vc4_context(pctx);
219bf215546Sopenharmony_ci   struct pipe_screen *pscreen = pctx->screen;
220bf215546Sopenharmony_ci   struct pipe_shader_state **cached_shader;
221bf215546Sopenharmony_ci   const char *name;
222bf215546Sopenharmony_ci
223bf215546Sopenharmony_ci   if (cpp == 1) {
224bf215546Sopenharmony_ci           cached_shader = &vc4->yuv_linear_blit_fs_8bit;
225bf215546Sopenharmony_ci           name = "linear_blit_8bit_fs";
226bf215546Sopenharmony_ci   } else {
227bf215546Sopenharmony_ci           cached_shader = &vc4->yuv_linear_blit_fs_16bit;
228bf215546Sopenharmony_ci           name = "linear_blit_16bit_fs";
229bf215546Sopenharmony_ci   }
230bf215546Sopenharmony_ci
231bf215546Sopenharmony_ci   if (*cached_shader)
232bf215546Sopenharmony_ci           return *cached_shader;
233bf215546Sopenharmony_ci
234bf215546Sopenharmony_ci   const struct nir_shader_compiler_options *options =
235bf215546Sopenharmony_ci           pscreen->get_compiler_options(pscreen,
236bf215546Sopenharmony_ci                                         PIPE_SHADER_IR_NIR,
237bf215546Sopenharmony_ci                                         PIPE_SHADER_FRAGMENT);
238bf215546Sopenharmony_ci
239bf215546Sopenharmony_ci   nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_FRAGMENT,
240bf215546Sopenharmony_ci                                                  options, "%s", name);
241bf215546Sopenharmony_ci
242bf215546Sopenharmony_ci   const struct glsl_type *vec4 = glsl_vec4_type();
243bf215546Sopenharmony_ci   const struct glsl_type *glsl_int = glsl_int_type();
244bf215546Sopenharmony_ci
245bf215546Sopenharmony_ci   nir_variable *color_out = nir_variable_create(b.shader, nir_var_shader_out,
246bf215546Sopenharmony_ci                                                 vec4, "f_color");
247bf215546Sopenharmony_ci   color_out->data.location = FRAG_RESULT_COLOR;
248bf215546Sopenharmony_ci
249bf215546Sopenharmony_ci   nir_variable *pos_in = nir_variable_create(b.shader, nir_var_shader_in,
250bf215546Sopenharmony_ci                                              vec4, "pos");
251bf215546Sopenharmony_ci   pos_in->data.location = VARYING_SLOT_POS;
252bf215546Sopenharmony_ci   nir_ssa_def *pos = nir_load_var(&b, pos_in);
253bf215546Sopenharmony_ci
254bf215546Sopenharmony_ci   nir_ssa_def *one = nir_imm_int(&b, 1);
255bf215546Sopenharmony_ci   nir_ssa_def *two = nir_imm_int(&b, 2);
256bf215546Sopenharmony_ci
257bf215546Sopenharmony_ci   nir_ssa_def *x = nir_f2i32(&b, nir_channel(&b, pos, 0));
258bf215546Sopenharmony_ci   nir_ssa_def *y = nir_f2i32(&b, nir_channel(&b, pos, 1));
259bf215546Sopenharmony_ci
260bf215546Sopenharmony_ci   nir_variable *stride_in = nir_variable_create(b.shader, nir_var_uniform,
261bf215546Sopenharmony_ci                                                 glsl_int, "stride");
262bf215546Sopenharmony_ci   nir_ssa_def *stride = nir_load_var(&b, stride_in);
263bf215546Sopenharmony_ci
264bf215546Sopenharmony_ci   nir_ssa_def *x_offset;
265bf215546Sopenharmony_ci   nir_ssa_def *y_offset;
266bf215546Sopenharmony_ci   if (cpp == 1) {
267bf215546Sopenharmony_ci           nir_ssa_def *intra_utile_x_offset =
268bf215546Sopenharmony_ci                   nir_ishl(&b, nir_iand(&b, x, one), two);
269bf215546Sopenharmony_ci           nir_ssa_def *inter_utile_x_offset =
270bf215546Sopenharmony_ci                   nir_ishl(&b, nir_iand(&b, x, nir_imm_int(&b, ~3)), one);
271bf215546Sopenharmony_ci
272bf215546Sopenharmony_ci           x_offset = nir_iadd(&b,
273bf215546Sopenharmony_ci                               intra_utile_x_offset,
274bf215546Sopenharmony_ci                               inter_utile_x_offset);
275bf215546Sopenharmony_ci           y_offset = nir_imul(&b,
276bf215546Sopenharmony_ci                               nir_iadd(&b,
277bf215546Sopenharmony_ci                                        nir_ishl(&b, y, one),
278bf215546Sopenharmony_ci                                        nir_ushr(&b, nir_iand(&b, x, two), one)),
279bf215546Sopenharmony_ci                               stride);
280bf215546Sopenharmony_ci   } else {
281bf215546Sopenharmony_ci           x_offset = nir_ishl(&b, x, two);
282bf215546Sopenharmony_ci           y_offset = nir_imul(&b, y, stride);
283bf215546Sopenharmony_ci   }
284bf215546Sopenharmony_ci
285bf215546Sopenharmony_ci   nir_ssa_def *load =
286bf215546Sopenharmony_ci      nir_load_ubo(&b, 1, 32, one, nir_iadd(&b, x_offset, y_offset),
287bf215546Sopenharmony_ci                   .align_mul = 4,
288bf215546Sopenharmony_ci                   .align_offset = 0,
289bf215546Sopenharmony_ci                   .range_base = 0,
290bf215546Sopenharmony_ci                   .range = ~0);
291bf215546Sopenharmony_ci
292bf215546Sopenharmony_ci   nir_store_var(&b, color_out,
293bf215546Sopenharmony_ci                 nir_unpack_unorm_4x8(&b, load),
294bf215546Sopenharmony_ci                 0xf);
295bf215546Sopenharmony_ci
296bf215546Sopenharmony_ci   struct pipe_shader_state shader_tmpl = {
297bf215546Sopenharmony_ci           .type = PIPE_SHADER_IR_NIR,
298bf215546Sopenharmony_ci           .ir.nir = b.shader,
299bf215546Sopenharmony_ci   };
300bf215546Sopenharmony_ci
301bf215546Sopenharmony_ci   *cached_shader = pctx->create_fs_state(pctx, &shader_tmpl);
302bf215546Sopenharmony_ci
303bf215546Sopenharmony_ci   return *cached_shader;
304bf215546Sopenharmony_ci}
305bf215546Sopenharmony_ci
306bf215546Sopenharmony_cistatic bool
307bf215546Sopenharmony_civc4_yuv_blit(struct pipe_context *pctx, const struct pipe_blit_info *info)
308bf215546Sopenharmony_ci{
309bf215546Sopenharmony_ci        struct vc4_context *vc4 = vc4_context(pctx);
310bf215546Sopenharmony_ci        struct vc4_resource *src = vc4_resource(info->src.resource);
311bf215546Sopenharmony_ci        struct vc4_resource *dst = vc4_resource(info->dst.resource);
312bf215546Sopenharmony_ci        bool ok;
313bf215546Sopenharmony_ci
314bf215546Sopenharmony_ci        if (src->tiled)
315bf215546Sopenharmony_ci                return false;
316bf215546Sopenharmony_ci        if (src->base.format != PIPE_FORMAT_R8_UNORM &&
317bf215546Sopenharmony_ci            src->base.format != PIPE_FORMAT_R8G8_UNORM)
318bf215546Sopenharmony_ci                return false;
319bf215546Sopenharmony_ci
320bf215546Sopenharmony_ci        /* YUV blits always turn raster-order to tiled */
321bf215546Sopenharmony_ci        assert(dst->base.format == src->base.format);
322bf215546Sopenharmony_ci        assert(dst->tiled);
323bf215546Sopenharmony_ci
324bf215546Sopenharmony_ci        /* Always 1:1 and at the origin */
325bf215546Sopenharmony_ci        assert(info->src.box.x == 0 && info->dst.box.x == 0);
326bf215546Sopenharmony_ci        assert(info->src.box.y == 0 && info->dst.box.y == 0);
327bf215546Sopenharmony_ci        assert(info->src.box.width == info->dst.box.width);
328bf215546Sopenharmony_ci        assert(info->src.box.height == info->dst.box.height);
329bf215546Sopenharmony_ci
330bf215546Sopenharmony_ci        if ((src->slices[info->src.level].offset & 3) ||
331bf215546Sopenharmony_ci            (src->slices[info->src.level].stride & 3)) {
332bf215546Sopenharmony_ci                perf_debug("YUV-blit src texture offset/stride misaligned: 0x%08x/%d\n",
333bf215546Sopenharmony_ci                           src->slices[info->src.level].offset,
334bf215546Sopenharmony_ci                           src->slices[info->src.level].stride);
335bf215546Sopenharmony_ci                goto fallback;
336bf215546Sopenharmony_ci        }
337bf215546Sopenharmony_ci
338bf215546Sopenharmony_ci        vc4_blitter_save(vc4);
339bf215546Sopenharmony_ci
340bf215546Sopenharmony_ci        /* Create a renderable surface mapping the T-tiled shadow buffer.
341bf215546Sopenharmony_ci         */
342bf215546Sopenharmony_ci        struct pipe_surface dst_tmpl;
343bf215546Sopenharmony_ci        util_blitter_default_dst_texture(&dst_tmpl, info->dst.resource,
344bf215546Sopenharmony_ci                                         info->dst.level, info->dst.box.z);
345bf215546Sopenharmony_ci        dst_tmpl.format = PIPE_FORMAT_RGBA8888_UNORM;
346bf215546Sopenharmony_ci        struct pipe_surface *dst_surf =
347bf215546Sopenharmony_ci                pctx->create_surface(pctx, info->dst.resource, &dst_tmpl);
348bf215546Sopenharmony_ci        if (!dst_surf) {
349bf215546Sopenharmony_ci                fprintf(stderr, "Failed to create YUV dst surface\n");
350bf215546Sopenharmony_ci                util_blitter_unset_running_flag(vc4->blitter);
351bf215546Sopenharmony_ci                return false;
352bf215546Sopenharmony_ci        }
353bf215546Sopenharmony_ci        dst_surf->width = align(dst_surf->width, 8) / 2;
354bf215546Sopenharmony_ci        if (dst->cpp == 1)
355bf215546Sopenharmony_ci                dst_surf->height /= 2;
356bf215546Sopenharmony_ci
357bf215546Sopenharmony_ci        /* Set the constant buffer. */
358bf215546Sopenharmony_ci        uint32_t stride = src->slices[info->src.level].stride;
359bf215546Sopenharmony_ci        struct pipe_constant_buffer cb_uniforms = {
360bf215546Sopenharmony_ci                .user_buffer = &stride,
361bf215546Sopenharmony_ci                .buffer_size = sizeof(stride),
362bf215546Sopenharmony_ci        };
363bf215546Sopenharmony_ci        pctx->set_constant_buffer(pctx, PIPE_SHADER_FRAGMENT, 0, false, &cb_uniforms);
364bf215546Sopenharmony_ci        struct pipe_constant_buffer cb_src = {
365bf215546Sopenharmony_ci                .buffer = info->src.resource,
366bf215546Sopenharmony_ci                .buffer_offset = src->slices[info->src.level].offset,
367bf215546Sopenharmony_ci                .buffer_size = (src->bo->size -
368bf215546Sopenharmony_ci                                src->slices[info->src.level].offset),
369bf215546Sopenharmony_ci        };
370bf215546Sopenharmony_ci        pctx->set_constant_buffer(pctx, PIPE_SHADER_FRAGMENT, 1, false, &cb_src);
371bf215546Sopenharmony_ci
372bf215546Sopenharmony_ci        /* Unbind the textures, to make sure we don't try to recurse into the
373bf215546Sopenharmony_ci         * shadow blit.
374bf215546Sopenharmony_ci         */
375bf215546Sopenharmony_ci        pctx->set_sampler_views(pctx, PIPE_SHADER_FRAGMENT, 0, 0, 0, false, NULL);
376bf215546Sopenharmony_ci        pctx->bind_sampler_states(pctx, PIPE_SHADER_FRAGMENT, 0, 0, NULL);
377bf215546Sopenharmony_ci
378bf215546Sopenharmony_ci        util_blitter_custom_shader(vc4->blitter, dst_surf,
379bf215546Sopenharmony_ci                                   vc4_get_yuv_vs(pctx),
380bf215546Sopenharmony_ci                                   vc4_get_yuv_fs(pctx, src->cpp));
381bf215546Sopenharmony_ci
382bf215546Sopenharmony_ci        util_blitter_restore_textures(vc4->blitter);
383bf215546Sopenharmony_ci        util_blitter_restore_constant_buffer_state(vc4->blitter);
384bf215546Sopenharmony_ci        /* Restore cb1 (util_blitter doesn't handle this one). */
385bf215546Sopenharmony_ci        struct pipe_constant_buffer cb_disabled = { 0 };
386bf215546Sopenharmony_ci        pctx->set_constant_buffer(pctx, PIPE_SHADER_FRAGMENT, 1, false, &cb_disabled);
387bf215546Sopenharmony_ci
388bf215546Sopenharmony_ci        pipe_surface_reference(&dst_surf, NULL);
389bf215546Sopenharmony_ci
390bf215546Sopenharmony_ci        return true;
391bf215546Sopenharmony_ci
392bf215546Sopenharmony_cifallback:
393bf215546Sopenharmony_ci        /* Do an immediate SW fallback, since the render blit path
394bf215546Sopenharmony_ci         * would just recurse.
395bf215546Sopenharmony_ci         */
396bf215546Sopenharmony_ci        ok = util_try_blit_via_copy_region(pctx, info, false);
397bf215546Sopenharmony_ci        assert(ok); (void)ok;
398bf215546Sopenharmony_ci
399bf215546Sopenharmony_ci        return true;
400bf215546Sopenharmony_ci}
401bf215546Sopenharmony_ci
402bf215546Sopenharmony_cistatic bool
403bf215546Sopenharmony_civc4_render_blit(struct pipe_context *ctx, struct pipe_blit_info *info)
404bf215546Sopenharmony_ci{
405bf215546Sopenharmony_ci        struct vc4_context *vc4 = vc4_context(ctx);
406bf215546Sopenharmony_ci
407bf215546Sopenharmony_ci        if (!util_blitter_is_blit_supported(vc4->blitter, info)) {
408bf215546Sopenharmony_ci                fprintf(stderr, "blit unsupported %s -> %s\n",
409bf215546Sopenharmony_ci                    util_format_short_name(info->src.resource->format),
410bf215546Sopenharmony_ci                    util_format_short_name(info->dst.resource->format));
411bf215546Sopenharmony_ci                return false;
412bf215546Sopenharmony_ci        }
413bf215546Sopenharmony_ci
414bf215546Sopenharmony_ci        /* Enable the scissor, so we get a minimal set of tiles rendered. */
415bf215546Sopenharmony_ci        if (!info->scissor_enable) {
416bf215546Sopenharmony_ci                info->scissor_enable = true;
417bf215546Sopenharmony_ci                info->scissor.minx = info->dst.box.x;
418bf215546Sopenharmony_ci                info->scissor.miny = info->dst.box.y;
419bf215546Sopenharmony_ci                info->scissor.maxx = info->dst.box.x + info->dst.box.width;
420bf215546Sopenharmony_ci                info->scissor.maxy = info->dst.box.y + info->dst.box.height;
421bf215546Sopenharmony_ci        }
422bf215546Sopenharmony_ci
423bf215546Sopenharmony_ci        vc4_blitter_save(vc4);
424bf215546Sopenharmony_ci        util_blitter_blit(vc4->blitter, info);
425bf215546Sopenharmony_ci
426bf215546Sopenharmony_ci        return true;
427bf215546Sopenharmony_ci}
428bf215546Sopenharmony_ci
429bf215546Sopenharmony_ci/* Optimal hardware path for blitting pixels.
430bf215546Sopenharmony_ci * Scaling, format conversion, up- and downsampling (resolve) are allowed.
431bf215546Sopenharmony_ci */
432bf215546Sopenharmony_civoid
433bf215546Sopenharmony_civc4_blit(struct pipe_context *pctx, const struct pipe_blit_info *blit_info)
434bf215546Sopenharmony_ci{
435bf215546Sopenharmony_ci        struct pipe_blit_info info = *blit_info;
436bf215546Sopenharmony_ci
437bf215546Sopenharmony_ci        if (vc4_yuv_blit(pctx, blit_info))
438bf215546Sopenharmony_ci                return;
439bf215546Sopenharmony_ci
440bf215546Sopenharmony_ci        if (vc4_tile_blit(pctx, blit_info))
441bf215546Sopenharmony_ci                return;
442bf215546Sopenharmony_ci
443bf215546Sopenharmony_ci        if (info.mask & PIPE_MASK_S) {
444bf215546Sopenharmony_ci                if (util_try_blit_via_copy_region(pctx, &info, false))
445bf215546Sopenharmony_ci                        return;
446bf215546Sopenharmony_ci
447bf215546Sopenharmony_ci                info.mask &= ~PIPE_MASK_S;
448bf215546Sopenharmony_ci                fprintf(stderr, "cannot blit stencil, skipping\n");
449bf215546Sopenharmony_ci        }
450bf215546Sopenharmony_ci
451bf215546Sopenharmony_ci        if (vc4_render_blit(pctx, &info))
452bf215546Sopenharmony_ci                return;
453bf215546Sopenharmony_ci
454bf215546Sopenharmony_ci        fprintf(stderr, "Unsupported blit\n");
455bf215546Sopenharmony_ci}
456