• 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 (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