1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright (C) 2022 Lima Project
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * SPDX-License-Identifier: MIT
5bf215546Sopenharmony_ci *
6bf215546Sopenharmony_ci */
7bf215546Sopenharmony_ci
8bf215546Sopenharmony_ci#include "drm-uapi/lima_drm.h"
9bf215546Sopenharmony_ci
10bf215546Sopenharmony_ci#include "util/u_math.h"
11bf215546Sopenharmony_ci#include "util/format/u_format.h"
12bf215546Sopenharmony_ci#include "util/u_surface.h"
13bf215546Sopenharmony_ci#include "util/u_inlines.h"
14bf215546Sopenharmony_ci#include "util/hash_table.h"
15bf215546Sopenharmony_ci
16bf215546Sopenharmony_ci#include "lima_context.h"
17bf215546Sopenharmony_ci#include "lima_gpu.h"
18bf215546Sopenharmony_ci#include "lima_resource.h"
19bf215546Sopenharmony_ci#include "lima_texture.h"
20bf215546Sopenharmony_ci#include "lima_format.h"
21bf215546Sopenharmony_ci#include "lima_job.h"
22bf215546Sopenharmony_ci#include "lima_screen.h"
23bf215546Sopenharmony_ci#include "lima_bo.h"
24bf215546Sopenharmony_ci#include "lima_parser.h"
25bf215546Sopenharmony_ci#include "lima_util.h"
26bf215546Sopenharmony_ci#include "lima_blit.h"
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_civoid
29bf215546Sopenharmony_cilima_pack_blit_cmd(struct lima_job *job,
30bf215546Sopenharmony_ci                   struct util_dynarray *cmd_array,
31bf215546Sopenharmony_ci                   struct pipe_surface *psurf,
32bf215546Sopenharmony_ci                   const struct pipe_box *src,
33bf215546Sopenharmony_ci                   const struct pipe_box *dst,
34bf215546Sopenharmony_ci                   unsigned filter,
35bf215546Sopenharmony_ci                   bool scissor,
36bf215546Sopenharmony_ci                   unsigned sample_mask,
37bf215546Sopenharmony_ci                   unsigned mrt_idx)
38bf215546Sopenharmony_ci{
39bf215546Sopenharmony_ci   #define lima_blit_render_state_offset 0x0000
40bf215546Sopenharmony_ci   #define lima_blit_gl_pos_offset       0x0040
41bf215546Sopenharmony_ci   #define lima_blit_varying_offset      0x0080
42bf215546Sopenharmony_ci   #define lima_blit_tex_desc_offset     0x00c0
43bf215546Sopenharmony_ci   #define lima_blit_tex_array_offset    0x0100
44bf215546Sopenharmony_ci   #define lima_blit_buffer_size         0x0140
45bf215546Sopenharmony_ci
46bf215546Sopenharmony_ci   struct lima_context *ctx = job->ctx;
47bf215546Sopenharmony_ci   struct lima_surface *surf = lima_surface(psurf);
48bf215546Sopenharmony_ci   int level = psurf->u.tex.level;
49bf215546Sopenharmony_ci   unsigned first_layer = psurf->u.tex.first_layer;
50bf215546Sopenharmony_ci   float fb_width = dst->width, fb_height = dst->height;
51bf215546Sopenharmony_ci
52bf215546Sopenharmony_ci   uint32_t va;
53bf215546Sopenharmony_ci   void *cpu = lima_job_create_stream_bo(
54bf215546Sopenharmony_ci      job, LIMA_PIPE_PP, lima_blit_buffer_size, &va);
55bf215546Sopenharmony_ci
56bf215546Sopenharmony_ci   struct lima_screen *screen = lima_screen(ctx->base.screen);
57bf215546Sopenharmony_ci
58bf215546Sopenharmony_ci   uint32_t reload_shader_first_instr_size =
59bf215546Sopenharmony_ci      ((uint32_t *)(screen->pp_buffer->map + pp_reload_program_offset))[0] & 0x1f;
60bf215546Sopenharmony_ci   uint32_t reload_shader_va = screen->pp_buffer->va + pp_reload_program_offset;
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_ci   struct lima_render_state reload_render_state = {
63bf215546Sopenharmony_ci      .alpha_blend = 0xf03b1ad2,
64bf215546Sopenharmony_ci      .depth_test = 0x0000000e,
65bf215546Sopenharmony_ci      .depth_range = 0xffff0000,
66bf215546Sopenharmony_ci      .stencil_front = 0x00000007,
67bf215546Sopenharmony_ci      .stencil_back = 0x00000007,
68bf215546Sopenharmony_ci      .multi_sample = 0x00000007,
69bf215546Sopenharmony_ci      .shader_address = reload_shader_va | reload_shader_first_instr_size,
70bf215546Sopenharmony_ci      .varying_types = 0x00000001,
71bf215546Sopenharmony_ci      .textures_address = va + lima_blit_tex_array_offset,
72bf215546Sopenharmony_ci      .aux0 = 0x00004021,
73bf215546Sopenharmony_ci      .varyings_address = va + lima_blit_varying_offset,
74bf215546Sopenharmony_ci   };
75bf215546Sopenharmony_ci
76bf215546Sopenharmony_ci   reload_render_state.multi_sample |= (sample_mask << 12);
77bf215546Sopenharmony_ci
78bf215546Sopenharmony_ci   if (job->key.cbuf) {
79bf215546Sopenharmony_ci      fb_width = job->key.cbuf->width;
80bf215546Sopenharmony_ci      fb_height = job->key.cbuf->height;
81bf215546Sopenharmony_ci   } else {
82bf215546Sopenharmony_ci      fb_width = job->key.zsbuf->width;
83bf215546Sopenharmony_ci      fb_height = job->key.zsbuf->height;
84bf215546Sopenharmony_ci   }
85bf215546Sopenharmony_ci
86bf215546Sopenharmony_ci   if (util_format_is_depth_or_stencil(psurf->format)) {
87bf215546Sopenharmony_ci      reload_render_state.alpha_blend &= 0x0fffffff;
88bf215546Sopenharmony_ci      if (psurf->format != PIPE_FORMAT_Z16_UNORM)
89bf215546Sopenharmony_ci         reload_render_state.depth_test |= 0x400;
90bf215546Sopenharmony_ci      if (surf->reload & PIPE_CLEAR_DEPTH)
91bf215546Sopenharmony_ci         reload_render_state.depth_test |= 0x801;
92bf215546Sopenharmony_ci      if (surf->reload & PIPE_CLEAR_STENCIL) {
93bf215546Sopenharmony_ci         reload_render_state.depth_test |= 0x1000;
94bf215546Sopenharmony_ci         reload_render_state.stencil_front = 0x0000024f;
95bf215546Sopenharmony_ci         reload_render_state.stencil_back = 0x0000024f;
96bf215546Sopenharmony_ci         reload_render_state.stencil_test = 0x0000ffff;
97bf215546Sopenharmony_ci      }
98bf215546Sopenharmony_ci   }
99bf215546Sopenharmony_ci
100bf215546Sopenharmony_ci   memcpy(cpu + lima_blit_render_state_offset, &reload_render_state,
101bf215546Sopenharmony_ci          sizeof(reload_render_state));
102bf215546Sopenharmony_ci
103bf215546Sopenharmony_ci   lima_tex_desc *td = cpu + lima_blit_tex_desc_offset;
104bf215546Sopenharmony_ci   memset(td, 0, lima_min_tex_desc_size);
105bf215546Sopenharmony_ci   lima_texture_desc_set_res(ctx, td, psurf->texture, level, level,
106bf215546Sopenharmony_ci                             first_layer, mrt_idx);
107bf215546Sopenharmony_ci   td->format = lima_format_get_texel_reload(psurf->format);
108bf215546Sopenharmony_ci   td->unnorm_coords = 1;
109bf215546Sopenharmony_ci   td->sampler_dim = LIMA_SAMPLER_DIM_2D;
110bf215546Sopenharmony_ci   td->min_img_filter_nearest = 1;
111bf215546Sopenharmony_ci   td->mag_img_filter_nearest = 1;
112bf215546Sopenharmony_ci   td->wrap_s = LIMA_TEX_WRAP_CLAMP_TO_EDGE;
113bf215546Sopenharmony_ci   td->wrap_t = LIMA_TEX_WRAP_CLAMP_TO_EDGE;
114bf215546Sopenharmony_ci   td->wrap_r = LIMA_TEX_WRAP_CLAMP_TO_EDGE;
115bf215546Sopenharmony_ci
116bf215546Sopenharmony_ci   if (filter != PIPE_TEX_FILTER_NEAREST) {
117bf215546Sopenharmony_ci      td->min_img_filter_nearest = 0;
118bf215546Sopenharmony_ci      td->mag_img_filter_nearest = 0;
119bf215546Sopenharmony_ci   }
120bf215546Sopenharmony_ci
121bf215546Sopenharmony_ci   uint32_t *ta = cpu + lima_blit_tex_array_offset;
122bf215546Sopenharmony_ci   ta[0] = va + lima_blit_tex_desc_offset;
123bf215546Sopenharmony_ci
124bf215546Sopenharmony_ci   float reload_gl_pos[] = {
125bf215546Sopenharmony_ci      dst->x + dst->width, dst->y,      0, 1,
126bf215546Sopenharmony_ci      dst->x,              dst->y,      0, 1,
127bf215546Sopenharmony_ci      dst->x, dst->y + dst->height,     0, 1,
128bf215546Sopenharmony_ci   };
129bf215546Sopenharmony_ci   memcpy(cpu + lima_blit_gl_pos_offset, reload_gl_pos,
130bf215546Sopenharmony_ci          sizeof(reload_gl_pos));
131bf215546Sopenharmony_ci
132bf215546Sopenharmony_ci   float reload_varying[] = {
133bf215546Sopenharmony_ci      src->x + src->width, src->y,
134bf215546Sopenharmony_ci      src->x,              src->y,
135bf215546Sopenharmony_ci      src->x,              src->y + src->height,
136bf215546Sopenharmony_ci      0, 0, /* unused */
137bf215546Sopenharmony_ci   };
138bf215546Sopenharmony_ci   memcpy(cpu + lima_blit_varying_offset, reload_varying,
139bf215546Sopenharmony_ci          sizeof(reload_varying));
140bf215546Sopenharmony_ci
141bf215546Sopenharmony_ci   PLBU_CMD_BEGIN(cmd_array, scissor ? 22 : 20);
142bf215546Sopenharmony_ci
143bf215546Sopenharmony_ci   PLBU_CMD_VIEWPORT_LEFT(0);
144bf215546Sopenharmony_ci   PLBU_CMD_VIEWPORT_RIGHT(fui(fb_width));
145bf215546Sopenharmony_ci   PLBU_CMD_VIEWPORT_BOTTOM(0);
146bf215546Sopenharmony_ci   PLBU_CMD_VIEWPORT_TOP(fui(fb_height));
147bf215546Sopenharmony_ci
148bf215546Sopenharmony_ci   PLBU_CMD_RSW_VERTEX_ARRAY(
149bf215546Sopenharmony_ci      va + lima_blit_render_state_offset,
150bf215546Sopenharmony_ci      va + lima_blit_gl_pos_offset);
151bf215546Sopenharmony_ci
152bf215546Sopenharmony_ci
153bf215546Sopenharmony_ci   if (scissor) {
154bf215546Sopenharmony_ci      int minx = MIN2(dst->x, dst->x + dst->width);
155bf215546Sopenharmony_ci      int maxx = MAX2(dst->x, dst->x + dst->width);
156bf215546Sopenharmony_ci      int miny = MIN2(dst->y, dst->y + dst->height);
157bf215546Sopenharmony_ci      int maxy = MAX2(dst->y, dst->y + dst->height);
158bf215546Sopenharmony_ci
159bf215546Sopenharmony_ci      PLBU_CMD_SCISSORS(minx, maxx, miny, maxy);
160bf215546Sopenharmony_ci      lima_damage_rect_union(&job->damage_rect, minx, maxx, miny, maxy);
161bf215546Sopenharmony_ci   }
162bf215546Sopenharmony_ci
163bf215546Sopenharmony_ci   PLBU_CMD_UNKNOWN2();
164bf215546Sopenharmony_ci   PLBU_CMD_UNKNOWN1();
165bf215546Sopenharmony_ci
166bf215546Sopenharmony_ci   PLBU_CMD_INDICES(screen->pp_buffer->va + pp_shared_index_offset);
167bf215546Sopenharmony_ci   PLBU_CMD_INDEXED_DEST(va + lima_blit_gl_pos_offset);
168bf215546Sopenharmony_ci   PLBU_CMD_DRAW_ELEMENTS(0xf, 0, 3);
169bf215546Sopenharmony_ci
170bf215546Sopenharmony_ci   PLBU_CMD_END();
171bf215546Sopenharmony_ci
172bf215546Sopenharmony_ci   lima_dump_command_stream_print(job->dump, cpu, lima_blit_buffer_size,
173bf215546Sopenharmony_ci                                  false, "blit plbu cmd at va %x\n", va);
174bf215546Sopenharmony_ci}
175bf215546Sopenharmony_ci
176bf215546Sopenharmony_cistatic struct pipe_surface *
177bf215546Sopenharmony_cilima_get_blit_surface(struct pipe_context *pctx,
178bf215546Sopenharmony_ci                      struct pipe_resource *prsc,
179bf215546Sopenharmony_ci                      unsigned level)
180bf215546Sopenharmony_ci{
181bf215546Sopenharmony_ci   struct pipe_surface tmpl;
182bf215546Sopenharmony_ci
183bf215546Sopenharmony_ci   memset(&tmpl, 0, sizeof(tmpl));
184bf215546Sopenharmony_ci   tmpl.format = prsc->format;
185bf215546Sopenharmony_ci   tmpl.u.tex.level = level;
186bf215546Sopenharmony_ci   tmpl.u.tex.first_layer = 0;
187bf215546Sopenharmony_ci   tmpl.u.tex.last_layer = 0;
188bf215546Sopenharmony_ci
189bf215546Sopenharmony_ci   return pctx->create_surface(pctx, prsc, &tmpl);
190bf215546Sopenharmony_ci}
191bf215546Sopenharmony_ci
192bf215546Sopenharmony_cibool
193bf215546Sopenharmony_cilima_do_blit(struct pipe_context *pctx,
194bf215546Sopenharmony_ci             const struct pipe_blit_info *info)
195bf215546Sopenharmony_ci{
196bf215546Sopenharmony_ci   struct lima_context *ctx = lima_context(pctx);
197bf215546Sopenharmony_ci   unsigned reload_flags = PIPE_CLEAR_COLOR0;
198bf215546Sopenharmony_ci   uint8_t identity[4] = { PIPE_SWIZZLE_X, PIPE_SWIZZLE_Y,
199bf215546Sopenharmony_ci                           PIPE_SWIZZLE_Z, PIPE_SWIZZLE_W };
200bf215546Sopenharmony_ci
201bf215546Sopenharmony_ci   if (lima_debug & LIMA_DEBUG_NO_BLIT)
202bf215546Sopenharmony_ci      return false;
203bf215546Sopenharmony_ci
204bf215546Sopenharmony_ci   /* Blitting of swizzled formats (R and RG) isn't implemented yet */
205bf215546Sopenharmony_ci   if (memcmp(identity,
206bf215546Sopenharmony_ci              lima_format_get_texel_swizzle(info->src.resource->format),
207bf215546Sopenharmony_ci              sizeof(identity)))
208bf215546Sopenharmony_ci      return false;
209bf215546Sopenharmony_ci
210bf215546Sopenharmony_ci   if (memcmp(identity,
211bf215546Sopenharmony_ci              lima_format_get_texel_swizzle(info->dst.resource->format),
212bf215546Sopenharmony_ci              sizeof(identity)))
213bf215546Sopenharmony_ci      return false;
214bf215546Sopenharmony_ci
215bf215546Sopenharmony_ci   if (util_format_is_depth_or_stencil(info->src.resource->format)) {
216bf215546Sopenharmony_ci      const struct util_format_description *desc =
217bf215546Sopenharmony_ci         util_format_description(info->src.resource->format);
218bf215546Sopenharmony_ci      reload_flags = 0;
219bf215546Sopenharmony_ci      if (util_format_has_depth(desc))
220bf215546Sopenharmony_ci         reload_flags |= PIPE_CLEAR_DEPTH;
221bf215546Sopenharmony_ci      if (util_format_has_stencil(desc))
222bf215546Sopenharmony_ci         reload_flags |= PIPE_CLEAR_STENCIL;
223bf215546Sopenharmony_ci   }
224bf215546Sopenharmony_ci
225bf215546Sopenharmony_ci   if (!lima_format_pixel_supported(info->dst.resource->format))
226bf215546Sopenharmony_ci      return false;
227bf215546Sopenharmony_ci
228bf215546Sopenharmony_ci   if (!lima_format_texel_supported(info->src.resource->format))
229bf215546Sopenharmony_ci      return false;
230bf215546Sopenharmony_ci
231bf215546Sopenharmony_ci   if (info->dst.resource->target != PIPE_TEXTURE_2D ||
232bf215546Sopenharmony_ci       info->src.resource->target != PIPE_TEXTURE_2D)
233bf215546Sopenharmony_ci      return false;
234bf215546Sopenharmony_ci
235bf215546Sopenharmony_ci   if (info->dst.box.x < 0 || info->dst.box.y < 0 ||
236bf215546Sopenharmony_ci       info->src.box.x < 0 || info->src.box.y < 0)
237bf215546Sopenharmony_ci      return false;
238bf215546Sopenharmony_ci
239bf215546Sopenharmony_ci   if (info->src.box.depth != 1 ||
240bf215546Sopenharmony_ci       info->dst.box.depth != 1)
241bf215546Sopenharmony_ci      return false;
242bf215546Sopenharmony_ci
243bf215546Sopenharmony_ci   /* Scissored blit isn't implemented yet */
244bf215546Sopenharmony_ci   if (info->scissor_enable)
245bf215546Sopenharmony_ci      return false;
246bf215546Sopenharmony_ci
247bf215546Sopenharmony_ci   if ((reload_flags & PIPE_CLEAR_COLOR) && !(info->mask & PIPE_MASK_RGBA))
248bf215546Sopenharmony_ci      return false;
249bf215546Sopenharmony_ci
250bf215546Sopenharmony_ci   if ((reload_flags & PIPE_CLEAR_DEPTH) && !(info->mask & PIPE_MASK_Z))
251bf215546Sopenharmony_ci      return false;
252bf215546Sopenharmony_ci
253bf215546Sopenharmony_ci   if ((reload_flags & PIPE_CLEAR_STENCIL) && !(info->mask & PIPE_MASK_S))
254bf215546Sopenharmony_ci      return false;
255bf215546Sopenharmony_ci
256bf215546Sopenharmony_ci   struct pipe_surface *dst_surf =
257bf215546Sopenharmony_ci         lima_get_blit_surface(pctx, info->dst.resource, info->dst.level);
258bf215546Sopenharmony_ci   struct lima_surface *lima_dst_surf = lima_surface(dst_surf);
259bf215546Sopenharmony_ci
260bf215546Sopenharmony_ci   struct pipe_surface *src_surf =
261bf215546Sopenharmony_ci         lima_get_blit_surface(pctx, info->src.resource, info->src.level);
262bf215546Sopenharmony_ci
263bf215546Sopenharmony_ci   struct lima_job *job;
264bf215546Sopenharmony_ci
265bf215546Sopenharmony_ci   if (util_format_is_depth_or_stencil(info->dst.resource->format))
266bf215546Sopenharmony_ci      job = lima_job_get_with_fb(ctx, NULL, dst_surf);
267bf215546Sopenharmony_ci   else
268bf215546Sopenharmony_ci      job = lima_job_get_with_fb(ctx, dst_surf, NULL);
269bf215546Sopenharmony_ci
270bf215546Sopenharmony_ci   struct lima_resource *src_res = lima_resource(src_surf->texture);
271bf215546Sopenharmony_ci   struct lima_resource *dst_res = lima_resource(dst_surf->texture);
272bf215546Sopenharmony_ci
273bf215546Sopenharmony_ci   lima_flush_job_accessing_bo(ctx, src_res->bo, true);
274bf215546Sopenharmony_ci   lima_flush_job_accessing_bo(ctx, dst_res->bo, true);
275bf215546Sopenharmony_ci
276bf215546Sopenharmony_ci   lima_job_add_bo(job, LIMA_PIPE_PP, src_res->bo, LIMA_SUBMIT_BO_READ);
277bf215546Sopenharmony_ci   _mesa_hash_table_insert(ctx->write_jobs, &dst_res->base, job);
278bf215546Sopenharmony_ci   lima_job_add_bo(job, LIMA_PIPE_PP, dst_res->bo, LIMA_SUBMIT_BO_WRITE);
279bf215546Sopenharmony_ci
280bf215546Sopenharmony_ci   if (info->src.resource->nr_samples > 1) {
281bf215546Sopenharmony_ci      for (int i = 0; i < MIN2(info->src.resource->nr_samples, LIMA_MAX_SAMPLES); i++) {
282bf215546Sopenharmony_ci         lima_pack_blit_cmd(job, &job->plbu_cmd_array,
283bf215546Sopenharmony_ci                            src_surf, &info->src.box,
284bf215546Sopenharmony_ci                            &info->dst.box, info->filter, true,
285bf215546Sopenharmony_ci                            1 << i, i);
286bf215546Sopenharmony_ci      }
287bf215546Sopenharmony_ci   } else {
288bf215546Sopenharmony_ci      lima_pack_blit_cmd(job, &job->plbu_cmd_array,
289bf215546Sopenharmony_ci                         src_surf, &info->src.box,
290bf215546Sopenharmony_ci                         &info->dst.box, info->filter, true,
291bf215546Sopenharmony_ci                         0xf, 0);
292bf215546Sopenharmony_ci   }
293bf215546Sopenharmony_ci
294bf215546Sopenharmony_ci   bool tile_aligned = false;
295bf215546Sopenharmony_ci
296bf215546Sopenharmony_ci   if (info->dst.box.x == 0 && info->dst.box.y == 0 &&
297bf215546Sopenharmony_ci       info->dst.box.width == lima_dst_surf->base.width &&
298bf215546Sopenharmony_ci       info->dst.box.height == lima_dst_surf->base.height)
299bf215546Sopenharmony_ci      tile_aligned = true;
300bf215546Sopenharmony_ci
301bf215546Sopenharmony_ci   if (info->dst.box.x % 16 == 0 && info->dst.box.y % 16 == 0 &&
302bf215546Sopenharmony_ci       info->dst.box.width % 16 == 0 && info->dst.box.height % 16 == 0)
303bf215546Sopenharmony_ci      tile_aligned = true;
304bf215546Sopenharmony_ci
305bf215546Sopenharmony_ci   /* Reload if dest is not aligned to tile boundaries */
306bf215546Sopenharmony_ci   if (!tile_aligned)
307bf215546Sopenharmony_ci      lima_dst_surf->reload = reload_flags;
308bf215546Sopenharmony_ci   else
309bf215546Sopenharmony_ci      lima_dst_surf->reload = 0;
310bf215546Sopenharmony_ci
311bf215546Sopenharmony_ci   job->resolve = reload_flags;
312bf215546Sopenharmony_ci
313bf215546Sopenharmony_ci   lima_do_job(job);
314bf215546Sopenharmony_ci
315bf215546Sopenharmony_ci   pipe_surface_reference(&dst_surf, NULL);
316bf215546Sopenharmony_ci   pipe_surface_reference(&src_surf, NULL);
317bf215546Sopenharmony_ci
318bf215546Sopenharmony_ci   return true;
319bf215546Sopenharmony_ci}
320