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 28void 29lima_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 176static struct pipe_surface * 177lima_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 192bool 193lima_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