• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 (info->swizzle_enable)
206       return false;
207 
208    if (memcmp(identity,
209               lima_format_get_texel_swizzle(info->src.resource->format),
210               sizeof(identity)))
211       return false;
212 
213    if (memcmp(identity,
214               lima_format_get_texel_swizzle(info->dst.resource->format),
215               sizeof(identity)))
216       return false;
217 
218    if (util_format_is_depth_or_stencil(info->src.resource->format)) {
219       const struct util_format_description *desc =
220          util_format_description(info->src.resource->format);
221       reload_flags = 0;
222       if (util_format_has_depth(desc))
223          reload_flags |= PIPE_CLEAR_DEPTH;
224       if (util_format_has_stencil(desc))
225          reload_flags |= PIPE_CLEAR_STENCIL;
226    }
227 
228    if (!lima_format_pixel_supported(info->dst.resource->format))
229       return false;
230 
231    if (!lima_format_texel_supported(info->src.resource->format))
232       return false;
233 
234    if (info->dst.resource->target != PIPE_TEXTURE_2D ||
235        info->src.resource->target != PIPE_TEXTURE_2D)
236       return false;
237 
238    if (info->dst.box.x < 0 || info->dst.box.y < 0 ||
239        info->src.box.x < 0 || info->src.box.y < 0)
240       return false;
241 
242    if (info->src.box.depth != 1 ||
243        info->dst.box.depth != 1)
244       return false;
245 
246    /* Scissored blit isn't implemented yet */
247    if (info->scissor_enable)
248       return false;
249 
250    if ((reload_flags & PIPE_CLEAR_COLOR) && !(info->mask & PIPE_MASK_RGBA))
251       return false;
252 
253    if ((reload_flags & PIPE_CLEAR_DEPTH) && !(info->mask & PIPE_MASK_Z))
254       return false;
255 
256    if ((reload_flags & PIPE_CLEAR_STENCIL) && !(info->mask & PIPE_MASK_S))
257       return false;
258 
259    struct pipe_surface *dst_surf =
260          lima_get_blit_surface(pctx, info->dst.resource, info->dst.level);
261    struct lima_surface *lima_dst_surf = lima_surface(dst_surf);
262 
263    struct pipe_surface *src_surf =
264          lima_get_blit_surface(pctx, info->src.resource, info->src.level);
265 
266    struct lima_job *job;
267 
268    if (util_format_is_depth_or_stencil(info->dst.resource->format))
269       job = lima_job_get_with_fb(ctx, NULL, dst_surf);
270    else
271       job = lima_job_get_with_fb(ctx, dst_surf, NULL);
272 
273    struct lima_resource *src_res = lima_resource(src_surf->texture);
274    struct lima_resource *dst_res = lima_resource(dst_surf->texture);
275 
276    lima_flush_job_accessing_bo(ctx, src_res->bo, true);
277    lima_flush_job_accessing_bo(ctx, dst_res->bo, true);
278 
279    lima_job_add_bo(job, LIMA_PIPE_PP, src_res->bo, LIMA_SUBMIT_BO_READ);
280    _mesa_hash_table_insert(ctx->write_jobs, &dst_res->base, job);
281    lima_job_add_bo(job, LIMA_PIPE_PP, dst_res->bo, LIMA_SUBMIT_BO_WRITE);
282 
283    if (info->src.resource->nr_samples > 1) {
284       for (int i = 0; i < MIN2(info->src.resource->nr_samples, LIMA_MAX_SAMPLES); i++) {
285          lima_pack_blit_cmd(job, &job->plbu_cmd_array,
286                             src_surf, &info->src.box,
287                             &info->dst.box, info->filter, true,
288                             1 << i, i);
289       }
290    } else {
291       lima_pack_blit_cmd(job, &job->plbu_cmd_array,
292                          src_surf, &info->src.box,
293                          &info->dst.box, info->filter, true,
294                          0xf, 0);
295    }
296 
297    bool tile_aligned = false;
298 
299    if (info->dst.box.x == 0 && info->dst.box.y == 0 &&
300        info->dst.box.width == lima_dst_surf->base.width &&
301        info->dst.box.height == lima_dst_surf->base.height)
302       tile_aligned = true;
303 
304    if (info->dst.box.x % 16 == 0 && info->dst.box.y % 16 == 0 &&
305        info->dst.box.width % 16 == 0 && info->dst.box.height % 16 == 0)
306       tile_aligned = true;
307 
308    /* Reload if dest is not aligned to tile boundaries */
309    if (!tile_aligned)
310       lima_dst_surf->reload = reload_flags;
311    else
312       lima_dst_surf->reload = 0;
313 
314    job->resolve = reload_flags;
315 
316    lima_do_job(job);
317 
318    pipe_surface_reference(&dst_surf, NULL);
319    pipe_surface_reference(&src_surf, NULL);
320 
321    return true;
322 }
323