radeonsi: implement polygon stippling
authorMarek Olšák <marek.olsak@amd.com>
Sat, 31 Jan 2015 20:43:37 +0000 (21:43 +0100)
committerMarek Olšák <marek.olsak@amd.com>
Wed, 4 Feb 2015 13:34:13 +0000 (14:34 +0100)
Reviewed-by: Michel Dänzer <michel.daenzer@amd.com>
src/gallium/drivers/radeonsi/si_pipe.c
src/gallium/drivers/radeonsi/si_pipe.h
src/gallium/drivers/radeonsi/si_shader.c
src/gallium/drivers/radeonsi/si_shader.h
src/gallium/drivers/radeonsi/si_state.c
src/gallium/drivers/radeonsi/si_state.h
src/gallium/drivers/radeonsi/si_state_shaders.c

index eff8d6909597562849ebb0eecad60854909c1c45..aac3363b1068c0a311b3dadc0ab8609f9f3b76e9 100644 (file)
@@ -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);
        }
index 02820a1dd2dc28fa3d239d7c0a0fd33e7f996332..059fe0dc99beb55539efa0ebc068af53c7c50713 100644 (file)
@@ -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;
 
index 2c1dac928a2be88c006ac03c1123649c71165846..e6849ad22c77b75574eed18512de4fb374c6ffa0 100644 (file)
@@ -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;
 }
 
index 1d7efc23f593cf4d897fd8ee4f790a4f212993b9..551c7dc9f23e01aa0629ae13ee2c5ce4e1e99b5d 100644 (file)
@@ -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];
index 2deee4516d972af5fc6e6c5f0fe0bd29299f23f8..fb353ad419d42706604f3f9f05d69c6a4fd0445c 100644 (file)
@@ -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)
index 263728963d4624aede61a5eac0d01bca9dfae5ed..d1ed53065ca13d27ee3be1fcac92c452e199cef8 100644 (file)
@@ -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 {
index a40926800ddd3f51c080cf8d1628da9270569559..27ccc8e5034194d91169379aadb5f493cf95a5db 100644 (file)
@@ -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;