diff --git a/src/gallium/drivers/radeonsi/si_pipe.c b/src/gallium/drivers/radeonsi/si_pipe.c index eff8d690959..aac3363b106 100644 --- a/src/gallium/drivers/radeonsi/si_pipe.c +++ b/src/gallium/drivers/radeonsi/si_pipe.c @@ -53,6 +53,8 @@ static void si_destroy_context(struct pipe_context *context) si_pm4_delete_state(sctx, gs_onoff, sctx->gs_on); si_pm4_delete_state(sctx, gs_onoff, sctx->gs_off); + if (sctx->pstipple_sampler_state) + sctx->b.b.delete_sampler_state(&sctx->b.b, sctx->pstipple_sampler_state); if (sctx->dummy_pixel_shader) { sctx->b.b.delete_fs_state(&sctx->b.b, sctx->dummy_pixel_shader); } diff --git a/src/gallium/drivers/radeonsi/si_pipe.h b/src/gallium/drivers/radeonsi/si_pipe.h index 02820a1dd2d..059fe0dc99b 100644 --- a/src/gallium/drivers/radeonsi/si_pipe.h +++ b/src/gallium/drivers/radeonsi/si_pipe.h @@ -133,6 +133,7 @@ struct si_context { void *custom_blend_resolve; void *custom_blend_decompress; void *custom_blend_fastclear; + void *pstipple_sampler_state; struct si_screen *screen; struct si_pm4_state *init_config; diff --git a/src/gallium/drivers/radeonsi/si_shader.c b/src/gallium/drivers/radeonsi/si_shader.c index 2c1dac928a2..e6849ad22c7 100644 --- a/src/gallium/drivers/radeonsi/si_shader.c +++ b/src/gallium/drivers/radeonsi/si_shader.c @@ -37,6 +37,7 @@ #include "radeon/radeon_elf_util.h" #include "radeon/radeon_llvm_emit.h" #include "util/u_memory.h" +#include "util/u_pstipple.h" #include "tgsi/tgsi_parse.h" #include "tgsi/tgsi_util.h" #include "tgsi/tgsi_dump.h" @@ -2742,16 +2743,26 @@ static int si_generate_gs_copy_shader(struct si_screen *sscreen, int si_shader_create(struct si_screen *sscreen, struct si_shader *shader) { struct si_shader_selector *sel = shader->selector; + struct tgsi_token *tokens = sel->tokens; struct si_shader_context si_shader_ctx; struct lp_build_tgsi_context * bld_base; + struct tgsi_shader_info stipple_shader_info; LLVMModuleRef mod; int r = 0; + bool poly_stipple = sel->type == PIPE_SHADER_FRAGMENT && + shader->key.ps.poly_stipple; bool dump = r600_can_dump_shader(&sscreen->b, sel->tokens); + if (poly_stipple) { + tokens = util_pstipple_create_fragment_shader(tokens, NULL, + SI_POLY_STIPPLE_SAMPLER); + tgsi_scan_shader(tokens, &stipple_shader_info); + } + /* Dump TGSI code before doing TGSI->LLVM conversion in case the * conversion fails. */ if (dump) { - tgsi_dump(sel->tokens, 0); + tgsi_dump(tokens, 0); si_dump_streamout(&sel->so); } @@ -2768,7 +2779,7 @@ int si_shader_create(struct si_screen *sscreen, struct si_shader *shader) shader->db_shader_control |= S_02880C_KILL_ENABLE(1); shader->uses_instanceid = sel->info.uses_instanceid; - bld_base->info = &sel->info; + bld_base->info = poly_stipple ? &stipple_shader_info : &sel->info; bld_base->emit_fetch_funcs[TGSI_FILE_CONSTANT] = fetch_constant; bld_base->op_actions[TGSI_OPCODE_TEX] = tex_action; @@ -2799,7 +2810,7 @@ int si_shader_create(struct si_screen *sscreen, struct si_shader *shader) si_shader_ctx.radeon_bld.load_system_value = declare_system_value; si_shader_ctx.shader = shader; - si_shader_ctx.type = tgsi_get_processor_type(sel->tokens); + si_shader_ctx.type = tgsi_get_processor_type(tokens); si_shader_ctx.screen = sscreen; switch (si_shader_ctx.type) { @@ -2848,7 +2859,7 @@ int si_shader_create(struct si_screen *sscreen, struct si_shader *shader) bld_base->uint_bld.elem_type, ""); } - if (!lp_build_tgsi_llvm(bld_base, sel->tokens)) { + if (!lp_build_tgsi_llvm(bld_base, tokens)) { fprintf(stderr, "Failed to translate shader from TGSI to LLVM\n"); goto out; } @@ -2880,7 +2891,8 @@ int si_shader_create(struct si_screen *sscreen, struct si_shader *shader) out: for (int i = 0; i < SI_NUM_CONST_BUFFERS; i++) FREE(si_shader_ctx.constants[i]); - + if (poly_stipple) + tgsi_free_tokens(tokens); return r; } diff --git a/src/gallium/drivers/radeonsi/si_shader.h b/src/gallium/drivers/radeonsi/si_shader.h index 1d7efc23f59..551c7dc9f23 100644 --- a/src/gallium/drivers/radeonsi/si_shader.h +++ b/src/gallium/drivers/radeonsi/si_shader.h @@ -125,6 +125,7 @@ union si_shader_key { unsigned color_two_side:1; unsigned alpha_func:3; unsigned alpha_to_one:1; + unsigned poly_stipple:1; } ps; struct { unsigned instance_divisors[SI_NUM_VERTEX_BUFFERS]; diff --git a/src/gallium/drivers/radeonsi/si_state.c b/src/gallium/drivers/radeonsi/si_state.c index 2deee4516d9..fb353ad419d 100644 --- a/src/gallium/drivers/radeonsi/si_state.c +++ b/src/gallium/drivers/radeonsi/si_state.c @@ -32,6 +32,7 @@ #include "util/u_format.h" #include "util/u_format_s3tc.h" #include "util/u_memory.h" +#include "util/u_pstipple.h" static void si_init_atom(struct r600_atom *atom, struct r600_atom **list_elem, void (*emit)(struct si_context *ctx, struct r600_atom *state), @@ -616,6 +617,7 @@ static void *si_create_rs_state(struct pipe_context *ctx, rs->multisample_enable = state->multisample; rs->clip_plane_enable = state->clip_plane_enable; rs->line_stipple_enable = state->line_stipple_enable; + rs->poly_stipple_enable = state->poly_stipple_enable; polygon_dual_mode = (state->fill_front != PIPE_POLYGON_MODE_FILL || state->fill_back != PIPE_POLYGON_MODE_FILL); @@ -2760,6 +2762,56 @@ static void si_set_index_buffer(struct pipe_context *ctx, static void si_set_polygon_stipple(struct pipe_context *ctx, const struct pipe_poly_stipple *state) { + struct si_context *sctx = (struct si_context *)ctx; + struct pipe_resource *tex; + struct pipe_sampler_view *view; + bool is_zero = true; + bool is_one = true; + int i; + + /* The hardware obeys 0 and 1 swizzles in the descriptor even if + * the resource is NULL/invalid. Take advantage of this fact and skip + * texture allocation if the stipple pattern is constant. + * + * This is an optimization for the common case when stippling isn't + * used but set_polygon_stipple is still called by st/mesa. + */ + for (i = 0; i < Elements(state->stipple); i++) { + is_zero = is_zero && state->stipple[i] == 0; + is_one = is_one && state->stipple[i] == 0xffffffff; + } + + if (is_zero || is_one) { + struct pipe_sampler_view templ = {{0}}; + + templ.swizzle_r = PIPE_SWIZZLE_ZERO; + templ.swizzle_g = PIPE_SWIZZLE_ZERO; + templ.swizzle_b = PIPE_SWIZZLE_ZERO; + /* The pattern should be inverted in the texture. */ + templ.swizzle_a = is_zero ? PIPE_SWIZZLE_ONE : PIPE_SWIZZLE_ZERO; + + view = ctx->create_sampler_view(ctx, NULL, &templ); + } else { + /* Create a new texture. */ + tex = util_pstipple_create_stipple_texture(ctx, state->stipple); + if (!tex) + return; + + view = util_pstipple_create_sampler_view(ctx, tex); + pipe_resource_reference(&tex, NULL); + } + + ctx->set_sampler_views(ctx, PIPE_SHADER_FRAGMENT, + SI_POLY_STIPPLE_SAMPLER, 1, &view); + pipe_sampler_view_reference(&view, NULL); + + /* Bind the sampler state if needed. */ + if (!sctx->pstipple_sampler_state) { + sctx->pstipple_sampler_state = util_pstipple_create_sampler(ctx); + ctx->bind_sampler_states(ctx, PIPE_SHADER_FRAGMENT, + SI_POLY_STIPPLE_SAMPLER, 1, + &sctx->pstipple_sampler_state); + } } static void si_texture_barrier(struct pipe_context *ctx) diff --git a/src/gallium/drivers/radeonsi/si_state.h b/src/gallium/drivers/radeonsi/si_state.h index 263728963d4..d1ed53065ca 100644 --- a/src/gallium/drivers/radeonsi/si_state.h +++ b/src/gallium/drivers/radeonsi/si_state.h @@ -67,6 +67,7 @@ struct si_state_rasterizer { unsigned clip_plane_enable; float offset_units; float offset_scale; + bool poly_stipple_enable; }; struct si_state_dsa { diff --git a/src/gallium/drivers/radeonsi/si_state_shaders.c b/src/gallium/drivers/radeonsi/si_state_shaders.c index a40926800dd..27ccc8e5034 100644 --- a/src/gallium/drivers/radeonsi/si_state_shaders.c +++ b/src/gallium/drivers/radeonsi/si_state_shaders.c @@ -376,6 +376,11 @@ static INLINE void si_shader_selector_key(struct pipe_context *ctx, sctx->queued.named.rasterizer->multisample_enable && !sctx->framebuffer.cb0_is_integer; } + + key->ps.poly_stipple = sctx->queued.named.rasterizer->poly_stipple_enable && + ((sctx->current_rast_prim >= PIPE_PRIM_TRIANGLES && + sctx->current_rast_prim <= PIPE_PRIM_POLYGON) || + sctx->current_rast_prim >= PIPE_PRIM_TRIANGLES_ADJACENCY); } if (sctx->queued.named.dsa) { key->ps.alpha_func = sctx->queued.named.dsa->alpha_func;