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