static void *vc4_get_yuv_vs(struct pipe_context *pctx) { struct vc4_context *vc4 = vc4_context(pctx); struct pipe_screen *pscreen = pctx->screen; if (vc4->yuv_linear_blit_vs) return vc4->yuv_linear_blit_vs; const struct nir_shader_compiler_options *options = pscreen->get_compiler_options(pscreen, PIPE_SHADER_IR_NIR, PIPE_SHADER_VERTEX); nir_builder b; nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_VERTEX, options); b.shader->info.name = ralloc_strdup(b.shader, "linear_blit_vs"); const struct glsl_type *vec4 = glsl_vec4_type(); nir_variable *pos_in = nir_variable_create(b.shader, nir_var_shader_in, vec4, "pos"); nir_variable *pos_out = nir_variable_create(b.shader, nir_var_shader_out, vec4, "gl_Position"); pos_out->data.location = VARYING_SLOT_POS; nir_store_var(&b, pos_out, nir_load_var(&b, pos_in), 0xf); struct pipe_shader_state shader_tmpl = { .type = PIPE_SHADER_IR_NIR, .ir.nir = b.shader, }; vc4->yuv_linear_blit_vs = pctx->create_vs_state(pctx, &shader_tmpl); return vc4->yuv_linear_blit_vs; } static void *vc4_get_yuv_fs(struct pipe_context *pctx, int cpp) { struct vc4_context *vc4 = vc4_context(pctx); struct pipe_screen *pscreen = pctx->screen; struct pipe_shader_state **cached_shader; const char *name; if (cpp == 1) { cached_shader = &vc4->yuv_linear_blit_fs_8bit; name = "linear_blit_8bit_fs"; } else { cached_shader = &vc4->yuv_linear_blit_fs_16bit; name = "linear_blit_16bit_fs"; } if (*cached_shader) return *cached_shader; const struct nir_shader_compiler_options *options = pscreen->get_compiler_options(pscreen, PIPE_SHADER_IR_NIR, PIPE_SHADER_FRAGMENT); nir_builder b; nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_FRAGMENT, options); b.shader->info.name = ralloc_strdup(b.shader, name); const struct glsl_type *vec4 = glsl_vec4_type(); const struct glsl_type *glsl_int = glsl_int_type(); nir_variable *color_out = nir_variable_create(b.shader, nir_var_shader_out, vec4, "f_color"); color_out->data.location = FRAG_RESULT_COLOR; nir_variable *pos_in = nir_variable_create(b.shader, nir_var_shader_in, vec4, "pos"); pos_in->data.location = VARYING_SLOT_POS; nir_ssa_def *pos = nir_load_var(&b, pos_in); nir_ssa_def *one = nir_imm_int(&b, 1); nir_ssa_def *two = nir_imm_int(&b, 2); nir_ssa_def *x = nir_f2i32(&b, nir_channel(&b, pos, 0)); nir_ssa_def *y = nir_f2i32(&b, nir_channel(&b, pos, 1)); nir_variable *stride_in = nir_variable_create(b.shader, nir_var_uniform, glsl_int, "stride"); nir_ssa_def *stride = nir_load_var(&b, stride_in); nir_ssa_def *x_offset; nir_ssa_def *y_offset; if (cpp == 1) { nir_ssa_def *intra_utile_x_offset = nir_ishl(&b, nir_iand(&b, x, one), two); nir_ssa_def *inter_utile_x_offset = nir_ishl(&b, nir_iand(&b, x, nir_imm_int(&b, ~3)), one); x_offset = nir_iadd(&b, intra_utile_x_offset, inter_utile_x_offset); y_offset = nir_imul(&b, nir_iadd(&b, nir_ishl(&b, y, one), nir_ushr(&b, nir_iand(&b, x, two), one)), stride); } else { x_offset = nir_ishl(&b, x, two); y_offset = nir_imul(&b, y, stride); } nir_intrinsic_instr *load = nir_intrinsic_instr_create(b.shader, nir_intrinsic_load_ubo); load->num_components = 1; nir_ssa_dest_init(&load->instr, &load->dest, load->num_components, 32, NULL); load->src[0] = nir_src_for_ssa(one); load->src[1] = nir_src_for_ssa(nir_iadd(&b, x_offset, y_offset)); nir_builder_instr_insert(&b, &load->instr); nir_store_var(&b, color_out, nir_unpack_unorm_4x8(&b, &load->dest.ssa), 0xf); struct pipe_shader_state shader_tmpl = { .type = PIPE_SHADER_IR_NIR, .ir.nir = b.shader, }; *cached_shader = pctx->create_fs_state(pctx, &shader_tmpl); return *cached_shader; } static bool vc4_yuv_blit(struct pipe_context *pctx, const struct pipe_blit_info *info) { struct vc4_context *vc4 = vc4_context(pctx); struct vc4_resource *src = vc4_resource(info->src.resource); struct vc4_resource *dst = vc4_resource(info->dst.resource); bool ok; if (src->tiled) return false; if (src->base.format != PIPE_FORMAT_R8_UNORM && src->base.format != PIPE_FORMAT_R8G8_UNORM) return false; /* YUV blits always turn raster-order to tiled */ assert(dst->base.format == src->base.format); assert(dst->tiled); /* Always 1:1 and at the origin */ assert(info->src.box.x == 0 && info->dst.box.x == 0); assert(info->src.box.y == 0 && info->dst.box.y == 0); assert(info->src.box.width == info->dst.box.width); assert(info->src.box.height == info->dst.box.height); if ((src->slices[info->src.level].offset & 3) || (src->slices[info->src.level].stride & 3)) { perf_debug("YUV-blit src texture offset/stride misaligned: 0x%08x/%d\n", src->slices[info->src.level].offset, src->slices[info->src.level].stride); goto fallback; } vc4_blitter_save(vc4); /* Create a renderable surface mapping the T-tiled shadow buffer. */ struct pipe_surface dst_tmpl; util_blitter_default_dst_texture(&dst_tmpl, info->dst.resource, info->dst.level, info->dst.box.z); dst_tmpl.format = PIPE_FORMAT_RGBA8888_UNORM; struct pipe_surface *dst_surf = pctx->create_surface(pctx, info->dst.resource, &dst_tmpl); if (!dst_surf) { fprintf(stderr, "Failed to create YUV dst surface\n"); util_blitter_unset_running_flag(vc4->blitter); return false; } dst_surf->width /= 2; if (dst->cpp == 1) dst_surf->height /= 2; /* Set the constant buffer. */ uint32_t stride = src->slices[info->src.level].stride; struct pipe_constant_buffer cb_uniforms = { .user_buffer = &stride, .buffer_size = sizeof(stride), }; pctx->set_constant_buffer(pctx, PIPE_SHADER_FRAGMENT, 0, &cb_uniforms); struct pipe_constant_buffer cb_src = { .buffer = info->src.resource, .buffer_offset = src->slices[info->src.level].offset, .buffer_size = (src->bo->size - src->slices[info->src.level].offset), }; pctx->set_constant_buffer(pctx, PIPE_SHADER_FRAGMENT, 1, &cb_src); /* Unbind the textures, to make sure we don't try to recurse into the * shadow blit. */ pctx->set_sampler_views(pctx, PIPE_SHADER_FRAGMENT, 0, 0, NULL); pctx->bind_sampler_states(pctx, PIPE_SHADER_FRAGMENT, 0, 0, NULL); util_blitter_custom_shader(vc4->blitter, dst_surf, vc4_get_yuv_vs(pctx), vc4_get_yuv_fs(pctx, src->cpp)); util_blitter_restore_textures(vc4->blitter); util_blitter_restore_constant_buffer_state(vc4->blitter); /* Restore cb1 (util_blitter doesn't handle this one). */ struct pipe_constant_buffer cb_disabled = { 0 }; pctx->set_constant_buffer(pctx, PIPE_SHADER_FRAGMENT, 1, &cb_disabled); pipe_surface_reference(&dst_surf, NULL); return true; fallback: /* Do an immediate SW fallback, since the render blit path * would just recurse. */ ok = util_try_blit_via_copy_region(pctx, info); assert(ok); (void)ok; return true; } static bool vc4_render_blit(struct pipe_context *ctx, struct pipe_blit_info *info) { struct vc4_context *vc4 = vc4_context(ctx); if (!util_blitter_is_blit_supported(vc4->blitter, info)) { fprintf(stderr, "blit unsupported %s -> %s\n", util_format_short_name(info->src.resource->format), util_format_short_name(info->dst.resource->format)); return false; } /* Enable the scissor, so we get a minimal set of tiles rendered. */ if (!info->scissor_enable) { info->scissor_enable = true; info->scissor.minx = info->dst.box.x; info->scissor.miny = info->dst.box.y; info->scissor.maxx = info->dst.box.x + info->dst.box.width; info->scissor.maxy = info->dst.box.y + info->dst.box.height; } vc4_blitter_save(vc4); util_blitter_blit(vc4->blitter, info); return true; } /* Optimal hardware path for blitting pixels. * Scaling, format conversion, up- and downsampling (resolve) are allowed. */ void vc4_blit(struct pipe_context *pctx, const struct pipe_blit_info *blit_info) { struct pipe_blit_info info = *blit_info; if (vc4_yuv_blit(pctx, blit_info)) return; if (vc4_tile_blit(pctx, blit_info)) return; if (info.mask & PIPE_MASK_S) { if (util_try_blit_via_copy_region(pctx, &info)) return; info.mask &= ~PIPE_MASK_S; fprintf(stderr, "cannot blit stencil, skipping\n"); } if (vc4_render_blit(pctx, &info)) return; fprintf(stderr, "Unsupported blit\n"); }
static void r600_msaa_color_resolve(struct pipe_context *ctx, const struct pipe_blit_info *info) { struct r600_context *rctx = (struct r600_context *)ctx; struct pipe_screen *screen = ctx->screen; struct pipe_resource *tmp, templ; struct pipe_blit_info blit; unsigned sample_mask = rctx->chip_class == CAYMAN ? ~0 : ((1ull << MAX2(1, info->src.resource->nr_samples)) - 1); assert(info->src.level == 0); assert(info->src.box.depth == 1); assert(info->dst.box.depth == 1); if (is_simple_msaa_resolve(info)) { r600_blitter_begin(ctx, R600_COLOR_RESOLVE); util_blitter_custom_resolve_color(rctx->blitter, info->dst.resource, info->dst.level, info->dst.box.z, info->src.resource, info->src.box.z, sample_mask, rctx->custom_blend_resolve, int_to_norm_format(info->dst.format)); r600_blitter_end(ctx); return; } /* resolve into a temporary texture, then blit */ templ.target = PIPE_TEXTURE_2D; templ.format = info->src.resource->format; templ.width0 = info->src.resource->width0; templ.height0 = info->src.resource->height0; templ.depth0 = 1; templ.array_size = 1; templ.last_level = 0; templ.nr_samples = 0; templ.usage = PIPE_USAGE_STATIC; templ.bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW; templ.flags = 0; tmp = screen->resource_create(screen, &templ); /* resolve */ r600_blitter_begin(ctx, R600_COLOR_RESOLVE); util_blitter_custom_resolve_color(rctx->blitter, tmp, 0, 0, info->src.resource, info->src.box.z, sample_mask, rctx->custom_blend_resolve, int_to_norm_format(tmp->format)); r600_blitter_end(ctx); /* blit */ blit = *info; blit.src.resource = tmp; blit.src.box.z = 0; r600_blitter_begin(ctx, R600_BLIT); util_blitter_blit(rctx->blitter, &blit); r600_blitter_end(ctx); pipe_resource_reference(&tmp, NULL); }
static void swr_blit(struct pipe_context *pipe, const struct pipe_blit_info *blit_info) { struct swr_context *ctx = swr_context(pipe); /* Make a copy of the const blit_info, so we can modify it */ struct pipe_blit_info info = *blit_info; if (info.render_condition_enable && !swr_check_render_cond(pipe)) return; if (info.src.resource->nr_samples > 1 && info.dst.resource->nr_samples <= 1 && !util_format_is_depth_or_stencil(info.src.resource->format) && !util_format_is_pure_integer(info.src.resource->format)) { debug_printf("swr_blit: color resolve : %d -> %d\n", info.src.resource->nr_samples, info.dst.resource->nr_samples); /* Resolve is done as part of the surface store. */ swr_store_dirty_resource(pipe, info.src.resource, SWR_TILE_RESOLVED); struct pipe_resource *src_resource = info.src.resource; struct pipe_resource *resolve_target = swr_resource(src_resource)->resolve_target; /* The resolve target becomes the new source for the blit. */ info.src.resource = resolve_target; } if (util_try_blit_via_copy_region(pipe, &info)) { return; /* done */ } if (info.mask & PIPE_MASK_S) { debug_printf("swr: cannot blit stencil, skipping\n"); info.mask &= ~PIPE_MASK_S; } if (!util_blitter_is_blit_supported(ctx->blitter, &info)) { debug_printf("swr: blit unsupported %s -> %s\n", util_format_short_name(info.src.resource->format), util_format_short_name(info.dst.resource->format)); return; } if (ctx->active_queries) { ctx->api.pfnSwrEnableStatsFE(ctx->swrContext, FALSE); ctx->api.pfnSwrEnableStatsBE(ctx->swrContext, FALSE); } util_blitter_save_vertex_buffer_slot(ctx->blitter, ctx->vertex_buffer); util_blitter_save_vertex_elements(ctx->blitter, (void *)ctx->velems); util_blitter_save_vertex_shader(ctx->blitter, (void *)ctx->vs); util_blitter_save_geometry_shader(ctx->blitter, (void*)ctx->gs); util_blitter_save_so_targets( ctx->blitter, ctx->num_so_targets, (struct pipe_stream_output_target **)ctx->so_targets); util_blitter_save_rasterizer(ctx->blitter, (void *)ctx->rasterizer); util_blitter_save_viewport(ctx->blitter, &ctx->viewport); util_blitter_save_scissor(ctx->blitter, &ctx->scissor); util_blitter_save_fragment_shader(ctx->blitter, ctx->fs); util_blitter_save_blend(ctx->blitter, (void *)ctx->blend); util_blitter_save_depth_stencil_alpha(ctx->blitter, (void *)ctx->depth_stencil); util_blitter_save_stencil_ref(ctx->blitter, &ctx->stencil_ref); util_blitter_save_sample_mask(ctx->blitter, ctx->sample_mask); util_blitter_save_framebuffer(ctx->blitter, &ctx->framebuffer); util_blitter_save_fragment_sampler_states( ctx->blitter, ctx->num_samplers[PIPE_SHADER_FRAGMENT], (void **)ctx->samplers[PIPE_SHADER_FRAGMENT]); util_blitter_save_fragment_sampler_views( ctx->blitter, ctx->num_sampler_views[PIPE_SHADER_FRAGMENT], ctx->sampler_views[PIPE_SHADER_FRAGMENT]); util_blitter_save_render_condition(ctx->blitter, ctx->render_cond_query, ctx->render_cond_cond, ctx->render_cond_mode); util_blitter_blit(ctx->blitter, &info); if (ctx->active_queries) { ctx->api.pfnSwrEnableStatsFE(ctx->swrContext, TRUE); ctx->api.pfnSwrEnableStatsBE(ctx->swrContext, TRUE); } }
static bool do_hardware_msaa_resolve(struct pipe_context *ctx, const struct pipe_blit_info *info) { struct si_context *sctx = (struct si_context*)ctx; struct r600_texture *src = (struct r600_texture*)info->src.resource; struct r600_texture *dst = (struct r600_texture*)info->dst.resource; unsigned dst_width = u_minify(info->dst.resource->width0, info->dst.level); unsigned dst_height = u_minify(info->dst.resource->height0, info->dst.level); enum pipe_format format = info->src.format; unsigned sample_mask = ~0; struct pipe_resource *tmp, templ; struct pipe_blit_info blit; /* Check basic requirements for hw resolve. */ if (!(info->src.resource->nr_samples > 1 && info->dst.resource->nr_samples <= 1 && !util_format_is_pure_integer(format) && !util_format_is_depth_or_stencil(format) && util_max_layer(info->src.resource, 0) == 0)) return false; /* Hardware MSAA resolve doesn't work if SPI format = NORM16_ABGR and * the format is R16G16. Use R16A16, which does work. */ if (format == PIPE_FORMAT_R16G16_UNORM) format = PIPE_FORMAT_R16A16_UNORM; if (format == PIPE_FORMAT_R16G16_SNORM) format = PIPE_FORMAT_R16A16_SNORM; /* Check the remaining requirements for hw resolve. */ if (util_max_layer(info->dst.resource, info->dst.level) == 0 && !info->scissor_enable && (info->mask & PIPE_MASK_RGBA) == PIPE_MASK_RGBA && util_is_format_compatible(util_format_description(info->src.format), util_format_description(info->dst.format)) && dst_width == info->src.resource->width0 && dst_height == info->src.resource->height0 && info->dst.box.x == 0 && info->dst.box.y == 0 && info->dst.box.width == dst_width && info->dst.box.height == dst_height && info->dst.box.depth == 1 && info->src.box.x == 0 && info->src.box.y == 0 && info->src.box.width == dst_width && info->src.box.height == dst_height && info->src.box.depth == 1 && dst->surface.level[info->dst.level].mode >= RADEON_SURF_MODE_1D && (!dst->cmask.size || !dst->dirty_level_mask)) { /* dst cannot be fast-cleared */ /* Check the last constraint. */ if (src->surface.micro_tile_mode != dst->surface.micro_tile_mode) { /* The next fast clear will switch to this mode to * get direct hw resolve next time if the mode is * different now. */ src->last_msaa_resolve_target_micro_mode = dst->surface.micro_tile_mode; goto resolve_to_temp; } /* Resolving into a surface with DCC is unsupported. Since * it's being overwritten anyway, clear it to uncompressed. * This is still the fastest codepath even with this clear. */ if (dst->dcc_offset && dst->surface.level[info->dst.level].dcc_enabled) { vi_dcc_clear_level(&sctx->b, dst, info->dst.level, 0xFFFFFFFF); dst->dirty_level_mask &= ~(1 << info->dst.level); } /* Resolve directly from src to dst. */ si_blitter_begin(ctx, SI_COLOR_RESOLVE | (info->render_condition_enable ? 0 : SI_DISABLE_RENDER_COND)); util_blitter_custom_resolve_color(sctx->blitter, info->dst.resource, info->dst.level, info->dst.box.z, info->src.resource, info->src.box.z, sample_mask, sctx->custom_blend_resolve, format); si_blitter_end(ctx); return true; } resolve_to_temp: /* Shader-based resolve is VERY SLOW. Instead, resolve into * a temporary texture and blit. */ memset(&templ, 0, sizeof(templ)); templ.target = PIPE_TEXTURE_2D; templ.format = info->src.resource->format; templ.width0 = info->src.resource->width0; templ.height0 = info->src.resource->height0; templ.depth0 = 1; templ.array_size = 1; templ.usage = PIPE_USAGE_DEFAULT; templ.flags = R600_RESOURCE_FLAG_FORCE_TILING | R600_RESOURCE_FLAG_DISABLE_DCC; /* The src and dst microtile modes must be the same. */ if (src->surface.micro_tile_mode == V_009910_ADDR_SURF_DISPLAY_MICRO_TILING) templ.bind = PIPE_BIND_SCANOUT; else templ.bind = 0; tmp = ctx->screen->resource_create(ctx->screen, &templ); if (!tmp) return false; assert(src->surface.micro_tile_mode == ((struct r600_texture*)tmp)->surface.micro_tile_mode); /* resolve */ si_blitter_begin(ctx, SI_COLOR_RESOLVE | (info->render_condition_enable ? 0 : SI_DISABLE_RENDER_COND)); util_blitter_custom_resolve_color(sctx->blitter, tmp, 0, 0, info->src.resource, info->src.box.z, sample_mask, sctx->custom_blend_resolve, format); si_blitter_end(ctx); /* blit */ blit = *info; blit.src.resource = tmp; blit.src.box.z = 0; si_blitter_begin(ctx, SI_BLIT | (info->render_condition_enable ? 0 : SI_DISABLE_RENDER_COND)); util_blitter_blit(sctx->blitter, &blit); si_blitter_end(ctx); pipe_resource_reference(&tmp, NULL); return true; }