diff --git a/src/gallium/auxiliary/util/u_blitter.c b/src/gallium/auxiliary/util/u_blitter.c index d5b886ca36f..e21076c99f3 100644 --- a/src/gallium/auxiliary/util/u_blitter.c +++ b/src/gallium/auxiliary/util/u_blitter.c @@ -107,6 +107,9 @@ struct blitter_context_priv */ void *fs_pack_color_zs[TGSI_TEXTURE_COUNT][10]; + /* FS which is meant for replicating indevidual stencil-buffer bits */ + void *fs_stencil_blit_fallback[2]; + /* Blend state. */ void *blend[PIPE_MASK_RGBA+1][2]; /**< blend state with writemask */ void *blend_clear[GET_CLEAR_BLEND_STATE_IDX(PIPE_CLEAR_COLOR)+1]; @@ -116,6 +119,7 @@ struct blitter_context_priv void *dsa_write_depth_keep_stencil; void *dsa_keep_depth_stencil; void *dsa_keep_depth_write_stencil; + void *dsa_replicate_stencil_bit[8]; /* Vertex elements states. */ void *velem_state; @@ -494,6 +498,11 @@ void util_blitter_destroy(struct blitter_context *blitter) pipe->delete_depth_stencil_alpha_state(pipe, ctx->dsa_write_depth_stencil); pipe->delete_depth_stencil_alpha_state(pipe, ctx->dsa_keep_depth_write_stencil); + for (i = 0; i < ARRAY_SIZE(ctx->dsa_replicate_stencil_bit); i++) { + if (ctx->dsa_replicate_stencil_bit[i]) + pipe->delete_depth_stencil_alpha_state(pipe, ctx->dsa_replicate_stencil_bit[i]); + } + unsigned scissor, msaa; for (scissor = 0; scissor < 2; scissor++) { for (msaa = 0; msaa < 2; msaa++) { @@ -565,6 +574,10 @@ void util_blitter_destroy(struct blitter_context *blitter) if (ctx->fs_write_all_cbufs) ctx->delete_fs_state(pipe, ctx->fs_write_all_cbufs); + for (i = 0; i < ARRAY_SIZE(ctx->fs_stencil_blit_fallback); ++i) + if (ctx->fs_stencil_blit_fallback[i]) + ctx->delete_fs_state(pipe, ctx->fs_stencil_blit_fallback[i]); + pipe->delete_sampler_state(pipe, ctx->sampler_state_rect_linear); pipe->delete_sampler_state(pipe, ctx->sampler_state_rect); pipe->delete_sampler_state(pipe, ctx->sampler_state_linear); @@ -2764,3 +2777,127 @@ void util_blitter_custom_shader(struct blitter_context *blitter, util_blitter_restore_render_cond(blitter); util_blitter_unset_running_flag(blitter); } + +static void * +get_stencil_blit_fallback_fs(struct blitter_context_priv *ctx, bool msaa_src) +{ + if (!ctx->fs_stencil_blit_fallback[msaa_src]) { + ctx->fs_stencil_blit_fallback[msaa_src] = + util_make_fs_stencil_blit(ctx->base.pipe, msaa_src); + } + + return ctx->fs_stencil_blit_fallback[msaa_src]; +} + +static void * +get_stencil_blit_fallback_dsa(struct blitter_context_priv *ctx, unsigned i) +{ + assert(i < ARRAY_SIZE(ctx->dsa_replicate_stencil_bit)); + if (!ctx->dsa_replicate_stencil_bit[i]) { + struct pipe_depth_stencil_alpha_state dsa = { 0 }; + dsa.depth.func = PIPE_FUNC_ALWAYS; + dsa.stencil[0].enabled = 1; + dsa.stencil[0].func = PIPE_FUNC_ALWAYS; + dsa.stencil[0].fail_op = PIPE_STENCIL_OP_REPLACE; + dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE; + dsa.stencil[0].zfail_op = PIPE_STENCIL_OP_REPLACE; + dsa.stencil[0].valuemask = 0xff; + dsa.stencil[0].writemask = 1u << i; + + ctx->dsa_replicate_stencil_bit[i] = + ctx->base.pipe->create_depth_stencil_alpha_state(ctx->base.pipe, &dsa); + } + return ctx->dsa_replicate_stencil_bit[i]; +} + +/** + * Performs a series of draws to implement stencil blits texture without + * requiring stencil writes, updating a single bit per pixel at the time. + */ +void +util_blitter_stencil_fallback(struct blitter_context *blitter, + struct pipe_resource *dst, + unsigned dst_level, + unsigned dstx, unsigned dsty, unsigned dstz, + struct pipe_resource *src, + unsigned src_level, + const struct pipe_box *srcbox) +{ + struct blitter_context_priv *ctx = (struct blitter_context_priv *)blitter; + struct pipe_context *pipe = ctx->base.pipe; + + /* check the saved state */ + util_blitter_set_running_flag(blitter); + blitter_check_saved_vertex_states(ctx); + blitter_check_saved_fragment_states(ctx); + blitter_check_saved_fb_state(ctx); + blitter_disable_render_cond(ctx); + + /* Initialize the surface. */ + struct pipe_surface *dst_view, dst_templ; + util_blitter_default_dst_texture(&dst_templ, dst, dst_level, dstz); + dst_view = pipe->create_surface(pipe, dst, &dst_templ); + + /* Initialize the sampler view. */ + struct pipe_sampler_view src_templ, *src_view; + util_blitter_default_src_texture(blitter, &src_templ, src, src_level); + src_templ.format = util_format_stencil_only(src_templ.format); + src_view = pipe->create_sampler_view(pipe, src, &src_templ); + + /* bind states */ + pipe->bind_blend_state(pipe, ctx->blend[PIPE_MASK_RGBA][0]); + pipe->bind_fs_state(pipe, + get_stencil_blit_fallback_fs(ctx, src->nr_samples > 1)); + + /* set a framebuffer state */ + struct pipe_framebuffer_state fb_state = { 0 }; + fb_state.width = srcbox->width; + fb_state.height = srcbox->height; + fb_state.zsbuf = dst_view; + pipe->set_framebuffer_state(pipe, &fb_state); + pipe->set_sample_mask(pipe, ~0); + + blitter_set_common_draw_rect_state(ctx, false, + util_framebuffer_get_num_samples(&fb_state) > 1); + blitter_set_dst_dimensions(ctx, srcbox->width, srcbox->height); + + pipe->clear_depth_stencil(pipe, dst_view, PIPE_CLEAR_STENCIL, 0.0, 0, + dstx, dsty, srcbox->width, srcbox->height, + true); + + pipe->set_sampler_views(pipe, PIPE_SHADER_FRAGMENT, 0, 1, &src_view); + pipe->bind_sampler_states(pipe, PIPE_SHADER_FRAGMENT, 0, 1, &ctx->sampler_state); + + unsigned stencil_bits = + util_format_get_component_bits(dst->format, + UTIL_FORMAT_COLORSPACE_ZS, 1); + + struct pipe_stencil_ref sr = { { (1u << stencil_bits) - 1 } }; + pipe->set_stencil_ref(pipe, &sr); + + for (int i = 0; i < stencil_bits; ++i) { + uint32_t mask = 1 << i; + struct pipe_constant_buffer cb = { + .user_buffer = &mask, + .buffer_size = sizeof(mask), + }; + pipe->set_constant_buffer(pipe, PIPE_SHADER_FRAGMENT, blitter->cb_slot, + &cb); + + pipe->bind_depth_stencil_alpha_state(pipe, + get_stencil_blit_fallback_dsa(ctx, i)); + + blitter->draw_rectangle(blitter, ctx->velem_state, get_vs_passthrough_pos, + dstx, dsty, + dstx + srcbox->width, dsty + srcbox->height, + 0, stencil_bits, UTIL_BLITTER_ATTRIB_NONE, NULL); + } + + util_blitter_restore_vertex_states(blitter); + util_blitter_restore_fragment_states(blitter); + util_blitter_restore_textures(blitter); + util_blitter_restore_fb_state(blitter); + util_blitter_restore_render_cond(blitter); + util_blitter_restore_constant_buffer_state(blitter); + util_blitter_unset_running_flag(blitter); +} diff --git a/src/gallium/auxiliary/util/u_blitter.h b/src/gallium/auxiliary/util/u_blitter.h index 72130adb422..b82609af65d 100644 --- a/src/gallium/auxiliary/util/u_blitter.h +++ b/src/gallium/auxiliary/util/u_blitter.h @@ -400,6 +400,16 @@ void util_blitter_custom_shader(struct blitter_context *blitter, struct pipe_surface *dstsurf, void *custom_vs, void *custom_fs); +/* Used by D3D12 for non-MSAA -> MSAA stencil blits */ +void util_blitter_stencil_fallback(struct blitter_context *blitter, + struct pipe_resource *dst, + unsigned dst_level, + unsigned dstx, unsigned dsty, + unsigned dstz, + struct pipe_resource *src, + unsigned src_level, + const struct pipe_box *srcbox); + /* The functions below should be used to save currently bound constant state * objects inside a driver. The objects are automatically restored at the end * of the util_blitter_{clear, copy_region, fill_region} functions and then