zink: move shader keys to be persistent on pipeline state
authorMike Blumenkrantz <michael.blumenkrantz@gmail.com>
Wed, 1 Sep 2021 19:44:34 +0000 (15:44 -0400)
committerMike Blumenkrantz <michael.blumenkrantz@gmail.com>
Thu, 16 Sep 2021 03:52:32 +0000 (23:52 -0400)
save a cycle or two zeroing and populating this on every recalc

Reviewed-by: Dave Airlie <airlied@redhat.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/12842>

src/gallium/drivers/zink/zink_compiler.c
src/gallium/drivers/zink/zink_compiler.h
src/gallium/drivers/zink/zink_context.c
src/gallium/drivers/zink/zink_context.h
src/gallium/drivers/zink/zink_draw.cpp
src/gallium/drivers/zink/zink_framebuffer.c
src/gallium/drivers/zink/zink_pipeline.h
src/gallium/drivers/zink/zink_program.c
src/gallium/drivers/zink/zink_program.h
src/gallium/drivers/zink/zink_shader_keys.h
src/gallium/drivers/zink/zink_state.c

index 39cd814..dd8c531 100644 (file)
@@ -782,7 +782,7 @@ zink_compiler_assign_io(nir_shader *producer, nir_shader *consumer)
 }
 
 VkShaderModule
-zink_shader_compile(struct zink_screen *screen, struct zink_shader *zs, nir_shader *base_nir, struct zink_shader_key *key)
+zink_shader_compile(struct zink_screen *screen, struct zink_shader *zs, nir_shader *base_nir, const struct zink_shader_key *key)
 {
    VkShaderModule mod = VK_NULL_HANDLE;
    void *streamout = NULL;
index b9e7321..270bf12 100644 (file)
@@ -99,7 +99,7 @@ zink_screen_init_compiler(struct zink_screen *screen);
 void
 zink_compiler_assign_io(nir_shader *producer, nir_shader *consumer);
 VkShaderModule
-zink_shader_compile(struct zink_screen *screen, struct zink_shader *zs, nir_shader *nir, struct zink_shader_key *key);
+zink_shader_compile(struct zink_screen *screen, struct zink_shader *zs, nir_shader *nir, const struct zink_shader_key *key);
 
 struct zink_shader *
 zink_shader_create(struct zink_screen *screen, struct nir_shader *nir,
index 0df1870..1d98bcb 100644 (file)
@@ -1000,12 +1000,22 @@ zink_set_inlinable_constants(struct pipe_context *pctx,
 {
    struct zink_context *ctx = (struct zink_context *)pctx;
    const uint32_t bit = BITFIELD_BIT(shader);
+   uint32_t *inlinable_uniforms;
+   struct zink_shader_key *key = NULL;
 
+   if (shader == PIPE_SHADER_COMPUTE) {
+      inlinable_uniforms = ctx->compute_inlinable_uniforms;
+   } else {
+      key = &ctx->gfx_pipeline_state.shader_keys.key[shader];
+      inlinable_uniforms = key->base.inlined_uniform_values;
+   }
    if (!(ctx->inlinable_uniforms_valid_mask & bit) ||
-       memcmp(ctx->inlinable_uniforms[shader], values, num_values * 4)) {
-      memcpy(ctx->inlinable_uniforms[shader], values, num_values * 4);
+       memcmp(inlinable_uniforms, values, num_values * 4)) {
+      memcpy(inlinable_uniforms, values, num_values * 4);
       ctx->dirty_shader_stages |= bit;
       ctx->inlinable_uniforms_valid_mask |= bit;
+      if (key)
+         key->inline_uniforms = true;
    }
 }
 
@@ -1020,6 +1030,21 @@ unbind_ubo(struct zink_context *ctx, struct zink_resource *res, enum pipe_shader
 }
 
 static void
+invalidate_inlined_uniforms(struct zink_context *ctx, enum pipe_shader_type pstage)
+{
+   unsigned bit = BITFIELD_BIT(pstage);
+   if (!(ctx->inlinable_uniforms_valid_mask & bit))
+      return;
+   ctx->inlinable_uniforms_valid_mask &= ~bit;
+   ctx->dirty_shader_stages |= bit;
+   if (pstage == PIPE_SHADER_COMPUTE)
+      return;
+
+   struct zink_shader_key *key = &ctx->gfx_pipeline_state.shader_keys.key[pstage];
+   key->inline_uniforms = false;
+}
+
+static void
 zink_set_constant_buffer(struct pipe_context *pctx,
                          enum pipe_shader_type shader, uint index,
                          bool take_ownership,
@@ -1086,7 +1111,7 @@ zink_set_constant_buffer(struct pipe_context *pctx,
    }
    if (index == 0) {
       /* Invalidate current inlinable uniforms. */
-      ctx->inlinable_uniforms_valid_mask &= ~(1 << shader);
+      invalidate_inlined_uniforms(ctx, shader);
    }
 
    if (update)
@@ -2066,7 +2091,6 @@ zink_set_framebuffer_state(struct pipe_context *pctx,
       ctx->scissor_changed = true;
    rebind_fb_state(ctx, NULL, true);
    ctx->fb_state.samples = util_framebuffer_get_num_samples(state);
-   uint8_t rast_samples = ctx->fb_state.samples - 1;
    /* get_framebuffer adds a ref if the fb is reused or created;
     * always do get_framebuffer first to avoid deleting the same fb
     * we're about to use
@@ -2095,9 +2119,16 @@ zink_set_framebuffer_state(struct pipe_context *pctx,
    ctx->fb_changed |= ctx->framebuffer != fb;
    ctx->framebuffer = fb;
 
-   /* in vulkan, gl_SampleMask needs to be explicitly ignored for sampleCount == 1 */
-   if ((ctx->gfx_pipeline_state.rast_samples > 0) != (rast_samples > 0))
-      ctx->dirty_shader_stages |= 1 << PIPE_SHADER_FRAGMENT;
+   uint8_t rast_samples = ctx->fb_state.samples - 1;
+   /* update the shader key if applicable:
+    * if gl_SampleMask[] is written to, we have to ensure that we get a shader with the same sample count:
+    * in GL, rast_samples==1 means ignore gl_SampleMask[]
+    * in VK, gl_SampleMask[] is never ignored
+    */
+   if (rast_samples != ctx->gfx_pipeline_state.rast_samples &&
+       (!ctx->gfx_stages[PIPE_SHADER_FRAGMENT] ||
+        ctx->gfx_stages[PIPE_SHADER_FRAGMENT]->nir->info.outputs_written & (1 << FRAG_RESULT_SAMPLE_MASK)))
+      zink_set_fs_key(ctx)->samples = ctx->fb_state.samples > 0;
    if (ctx->gfx_pipeline_state.rast_samples != rast_samples) {
       ctx->sample_locations_changed |= ctx->gfx_pipeline_state.sample_locations_enabled;
       ctx->gfx_pipeline_state.dirty = true;
@@ -3646,6 +3677,12 @@ zink_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags)
    if (!ctx->blitter)
       goto fail;
 
+   ctx->gfx_pipeline_state.shader_keys.last_vertex.key.vs_base.last_vertex_stage = true;
+   ctx->last_vertex_stage_dirty = true;
+   ctx->gfx_pipeline_state.shader_keys.key[PIPE_SHADER_VERTEX].size = sizeof(struct zink_vs_key_base);
+   ctx->gfx_pipeline_state.shader_keys.key[PIPE_SHADER_TESS_EVAL].size = sizeof(struct zink_vs_key_base);
+   ctx->gfx_pipeline_state.shader_keys.key[PIPE_SHADER_GEOMETRY].size = sizeof(struct zink_vs_key_base);
+   ctx->gfx_pipeline_state.shader_keys.key[PIPE_SHADER_FRAGMENT].size = sizeof(struct zink_fs_key);
    _mesa_hash_table_init(&ctx->compute_program_cache, ctx, _mesa_hash_pointer, _mesa_key_pointer_equal);
    _mesa_hash_table_init(&ctx->framebuffer_cache, ctx, hash_framebuffer_imageless, equals_framebuffer_imageless);
    _mesa_set_init(&ctx->render_pass_state_cache, ctx, hash_rp_state, equals_rp_state);
index d53b99d..abfe019 100644 (file)
@@ -193,7 +193,7 @@ struct zink_context {
 
    unsigned shader_has_inlinable_uniforms_mask;
    unsigned inlinable_uniforms_valid_mask;
-   uint32_t inlinable_uniforms[PIPE_SHADER_TYPES][MAX_INLINABLE_UNIFORMS];
+   uint32_t compute_inlinable_uniforms[MAX_INLINABLE_UNIFORMS];
 
    struct pipe_constant_buffer ubos[PIPE_SHADER_TYPES][PIPE_MAX_CONSTANT_BUFFERS];
    struct pipe_shader_buffer ssbos[PIPE_SHADER_TYPES][PIPE_MAX_SHADER_BUFFERS];
index 1895cd3..fde0363 100644 (file)
@@ -179,6 +179,9 @@ update_gfx_program(struct zink_context *ctx)
    if (ctx->last_vertex_stage_dirty) {
       enum pipe_shader_type pstage = pipe_shader_type_from_mesa(ctx->last_vertex_stage->nir->info.stage);
       ctx->dirty_shader_stages |= BITFIELD_BIT(pstage);
+      memcpy(&ctx->gfx_pipeline_state.shader_keys.key[pstage].key.vs_base,
+             &ctx->gfx_pipeline_state.shader_keys.last_vertex.key.vs_base,
+             sizeof(struct zink_vs_key_base));
       ctx->last_vertex_stage_dirty = false;
    }
    unsigned bits = BITFIELD_MASK(PIPE_SHADER_COMPUTE);
@@ -489,14 +492,13 @@ zink_draw_vbo(struct pipe_context *pctx,
    uint8_t vertices_per_patch = ctx->gfx_pipeline_state.patch_vertices ? ctx->gfx_pipeline_state.patch_vertices - 1 : 0;
    if (ctx->gfx_pipeline_state.vertices_per_patch != vertices_per_patch)
       ctx->gfx_pipeline_state.dirty = true;
-   bool drawid_broken = ctx->gfx_pipeline_state.drawid_broken;
-   ctx->gfx_pipeline_state.drawid_broken = false;
+   bool drawid_broken = false;
    if (reads_drawid && (!dindirect || !dindirect->buffer))
-      ctx->gfx_pipeline_state.drawid_broken = (drawid_offset != 0 ||
-                           (!HAS_MULTIDRAW && num_draws > 1) ||
-                           (HAS_MULTIDRAW && num_draws > 1 && !dinfo->increment_draw_id));
-   if (drawid_broken != ctx->gfx_pipeline_state.drawid_broken)
-      ctx->dirty_shader_stages |= BITFIELD_BIT(PIPE_SHADER_VERTEX);
+      drawid_broken = (drawid_offset != 0 ||
+                      (!HAS_MULTIDRAW && num_draws > 1) ||
+                      (HAS_MULTIDRAW && num_draws > 1 && !dinfo->increment_draw_id));
+   if (drawid_broken != zink_get_last_vertex_key(ctx)->push_drawid)
+      zink_set_last_vertex_key(ctx)->push_drawid = drawid_broken;
    ctx->gfx_pipeline_state.vertices_per_patch = vertices_per_patch;
    if (mode_changed) {
       bool points_changed = false;
@@ -508,7 +510,7 @@ zink_draw_vbo(struct pipe_context *pctx,
          points_changed = true;
       }
       if (points_changed && ctx->rast_state->base.point_quad_rasterization)
-         ctx->dirty_shader_stages |= BITFIELD_BIT(PIPE_SHADER_FRAGMENT);
+         zink_set_fs_point_coord_key(ctx);
    }
    ctx->gfx_pipeline_state.gfx_prim_mode = mode;
 
@@ -762,7 +764,7 @@ zink_draw_vbo(struct pipe_context *pctx,
       VKCTX(CmdBeginTransformFeedbackEXT)(batch->state->cmdbuf, 0, ctx->num_so_targets, counter_buffers, counter_buffer_offsets);
    }
 
-   bool needs_drawid = reads_drawid && ctx->gfx_pipeline_state.drawid_broken;
+   bool needs_drawid = reads_drawid && zink_get_last_vertex_key(ctx)->push_drawid;
    work_count += num_draws;
    if (index_size > 0) {
       if (dindirect && dindirect->buffer) {
index 3d0f1ed..ef785c5 100644 (file)
@@ -160,7 +160,7 @@ zink_get_framebuffer_imageless(struct zink_context *ctx)
    state.width = MAX2(ctx->fb_state.width, 1);
    state.height = MAX2(ctx->fb_state.height, 1);
    state.layers = MAX2(util_framebuffer_get_num_layers(&ctx->fb_state), 1) - 1;
-   state.samples = ctx->gfx_pipeline_state.rast_samples;
+   state.samples = ctx->fb_state.samples - 1;
 
    struct zink_framebuffer *fb;
    struct hash_entry *entry = _mesa_hash_table_search(&ctx->framebuffer_cache, &state);
@@ -289,7 +289,7 @@ zink_get_framebuffer(struct zink_context *ctx)
    state.width = MAX2(ctx->fb_state.width, 1);
    state.height = MAX2(ctx->fb_state.height, 1);
    state.layers = MAX2(util_framebuffer_get_num_layers(&ctx->fb_state), 1) - 1;
-   state.samples = ctx->gfx_pipeline_state.rast_samples;
+   state.samples = ctx->fb_state.samples - 1;
 
    struct zink_framebuffer *fb;
    simple_mtx_lock(&screen->framebuffer_mtx);
index d79f50b..4acc6c4 100644 (file)
@@ -27,6 +27,7 @@
 #include <vulkan/vulkan.h>
 
 #include "pipe/p_state.h"
+#include "zink_shader_keys.h"
 #include "zink_state.h"
 
 struct zink_blend_state;
@@ -75,11 +76,10 @@ struct zink_gfx_pipeline_state {
    bool have_EXT_extended_dynamic_state;
    bool have_EXT_extended_dynamic_state2;
    uint8_t has_points; //either gs outputs points or prim type is points
-   uint8_t coord_replace_bits;
-   bool coord_replace_yinvert;
-   bool drawid_broken;
-   uint32_t decomposed_attrs;
-   uint32_t decomposed_attrs_without_w;
+   struct {
+      struct zink_shader_key key[5];
+      struct zink_shader_key last_vertex;
+   } shader_keys;
    struct zink_blend_state *blend_state;
    struct zink_render_pass *render_pass;
    VkPipeline pipeline;
index 8d75ad8..a79cb5b 100644 (file)
@@ -69,17 +69,15 @@ debug_describe_zink_compute_program(char *buf, const struct zink_compute_program
 /* copied from iris */
 struct keybox {
    uint16_t size;
-   gl_shader_stage stage;
    uint8_t data[0];
 };
 
 static struct keybox *
-make_keybox(void *mem_ctx, gl_shader_stage stage, const void *key, uint32_t key_size, void *base, uint32_t base_size)
+make_keybox(void *mem_ctx, const void *key, uint32_t key_size, const void *base, uint32_t base_size)
 {
    struct keybox *keybox =
       ralloc_size(mem_ctx, sizeof(struct keybox) + key_size + base_size);
 
-   keybox->stage = stage;
    keybox->size = key_size + base_size;
    memcpy(keybox->data, key, key_size);
    if (base_size)
@@ -91,7 +89,7 @@ static uint32_t
 keybox_hash(const void *void_key)
 {
    const struct keybox *key = void_key;
-   return _mesa_hash_data(&key->stage, key->size + sizeof(key->stage));
+   return _mesa_hash_data(&key->data, key->size);
 }
 
 static bool
@@ -104,81 +102,9 @@ keybox_equals(const void *void_a, const void *void_b)
    return memcmp(a->data, b->data, a->size) == 0;
 }
 
-static void
-shader_key_vs_gen(struct zink_screen *screen, struct zink_shader *zs,
-                       struct zink_shader *shaders[ZINK_SHADER_COUNT], struct zink_shader_key *key,
-                       const struct zink_gfx_pipeline_state *state)
-{
-   struct zink_vs_key_base *vs_key = &key->key.vs_base;
-   const struct zink_rasterizer_hw_state *rast_state = (void*)state;
-   key->size = sizeof(struct zink_vs_key_base);
-
-   vs_key->clip_halfz = rast_state->clip_halfz;
-   switch (zs->nir->info.stage) {
-   case MESA_SHADER_VERTEX:
-      vs_key->last_vertex_stage = !shaders[PIPE_SHADER_TESS_EVAL] && !shaders[PIPE_SHADER_GEOMETRY];
-      vs_key->push_drawid = state->drawid_broken;
-      break;
-   case MESA_SHADER_TESS_EVAL:
-      vs_key->last_vertex_stage = !shaders[PIPE_SHADER_GEOMETRY];
-      break;
-   case MESA_SHADER_GEOMETRY:
-      vs_key->last_vertex_stage = true;
-      break;
-   default:
-      unreachable("impossible case");
-   }
-}
-
-static void
-shader_key_fs_gen(struct zink_screen *screen, struct zink_shader *zs,
-                  struct zink_shader *shaders[ZINK_SHADER_COUNT], struct zink_shader_key *key,
-                  const struct zink_gfx_pipeline_state *state)
-{
-   struct zink_fs_key *fs_key = &key->key.fs;
-   key->size = sizeof(struct zink_fs_key);
-
-   /* if gl_SampleMask[] is written to, we have to ensure that we get a shader with the same sample count:
-    * in GL, rast_samples==1 means ignore gl_SampleMask[]
-    * in VK, gl_SampleMask[] is never ignored
-    */
-   if (zs->nir->info.outputs_written & (1 << FRAG_RESULT_SAMPLE_MASK))
-      fs_key->samples = state->render_pass->state.samples;
-   fs_key->force_dual_color_blend = screen->driconf.dual_color_blend_by_location &&
-                                    state->blend_state &&
-                                    state->blend_state->dual_src_blend &&
-                                    state->blend_state->attachments[1].blendEnable;
-   if (state->has_points && state->coord_replace_bits) {
-      fs_key->coord_replace_bits = state->coord_replace_bits;
-      fs_key->coord_replace_yinvert = state->coord_replace_yinvert;
-   }
-}
-
-static void
-shader_key_tcs_gen(struct zink_screen *screen, struct zink_shader *zs,
-                   struct zink_shader *shaders[ZINK_SHADER_COUNT], struct zink_shader_key *key,
-                   const struct zink_gfx_pipeline_state *state)
-{
-   key->size = 0;
-}
-
-typedef void (*zink_shader_key_gen)(struct zink_screen *screen, struct zink_shader *zs,
-                                    struct zink_shader *shaders[ZINK_SHADER_COUNT],
-                                    struct zink_shader_key *key,
-                                    const struct zink_gfx_pipeline_state *state);
-static zink_shader_key_gen shader_key_vtbl[] =
-{
-   [MESA_SHADER_VERTEX] = shader_key_vs_gen,
-   [MESA_SHADER_TESS_CTRL] = shader_key_tcs_gen,
-   /* reusing vs key for now since we're only using clip_halfz */
-   [MESA_SHADER_TESS_EVAL] = shader_key_vs_gen,
-   [MESA_SHADER_GEOMETRY] = shader_key_vs_gen,
-   [MESA_SHADER_FRAGMENT] = shader_key_fs_gen,
-};
-
 /* return pointer to make function reusable */
 static inline struct zink_shader_module **
-get_default_shader_module_ptr(struct zink_gfx_program *prog, struct zink_shader *zs, struct zink_shader_key *key)
+get_default_shader_module_ptr(struct zink_gfx_program *prog, struct zink_shader *zs, const struct zink_shader_key *key)
 {
    if (zs->nir->info.stage == MESA_SHADER_VERTEX ||
        zs->nir->info.stage == MESA_SHADER_TESS_EVAL) {
@@ -196,60 +122,36 @@ get_shader_module_for_stage(struct zink_context *ctx, struct zink_screen *screen
 {
    gl_shader_stage stage = zs->nir->info.stage;
    enum pipe_shader_type pstage = pipe_shader_type_from_mesa(stage);
-   struct zink_shader_key key = {0};
    VkShaderModule mod;
    struct zink_shader_module *zm;
    struct zink_shader_module **default_zm = NULL;
    struct keybox *keybox;
    uint32_t hash;
    unsigned base_size = 0;
+   bool is_default_variant;
+   const struct zink_shader_key *key = &state->shader_keys.key[pstage];
 
-   shader_key_vtbl[stage](screen, zs, prog->shaders, &key, state);
-   if (ctx && stage == MESA_SHADER_VERTEX) {
-      unsigned size = MAX2(ctx->element_state->decomposed_attrs_size, ctx->element_state->decomposed_attrs_without_w_size);
-      switch (size) {
-      case 1:
-         key.key.vs.u8.decomposed_attrs = ctx->element_state->decomposed_attrs;
-         key.key.vs.u8.decomposed_attrs_without_w = ctx->element_state->decomposed_attrs_without_w;
-         break;
-      case 2:
-         key.key.vs.u16.decomposed_attrs = ctx->element_state->decomposed_attrs;
-         key.key.vs.u16.decomposed_attrs_without_w = ctx->element_state->decomposed_attrs_without_w;
-         break;
-      case 4:
-         key.key.vs.u32.decomposed_attrs = ctx->element_state->decomposed_attrs;
-         key.key.vs.u32.decomposed_attrs_without_w = ctx->element_state->decomposed_attrs_without_w;
-         break;
-      default: break;
-      }
-      key.key.vs.size = size;
-      key.size += 2 * size;
-   }
    /* this is default variant if there is no default or it matches the default */
    if (pstage != PIPE_SHADER_TESS_CTRL && prog->default_variant_key[pstage]) {
       const struct keybox *tmp = prog->default_variant_key[pstage];
       /* if comparing against the existing default, use the base variant key size since
        * we're only checking the stage-specific data
        */
-      key.is_default_variant = tmp->size == key.size && !memcmp(tmp->data, &key, key.size);
+      is_default_variant = tmp->size == key->size && !memcmp(tmp->data, &key, key->size);
    } else
-      key.is_default_variant = true;
+      is_default_variant = true;
 
    if (ctx && zs->nir->info.num_inlinable_uniforms &&
        ctx->inlinable_uniforms_valid_mask & BITFIELD64_BIT(pstage)) {
-      key.inline_uniforms = true;
-      memcpy(key.base.inlined_uniform_values,
-             ctx->inlinable_uniforms[pstage],
-             zs->nir->info.num_inlinable_uniforms * 4);
       base_size = zs->nir->info.num_inlinable_uniforms * sizeof(uint32_t);
-      key.is_default_variant = false;
+      is_default_variant = false;
    }
-   if (key.is_default_variant) {
-      default_zm = get_default_shader_module_ptr(prog, zs, &key);
+   if (is_default_variant) {
+      default_zm = get_default_shader_module_ptr(prog, zs, key);
       if (*default_zm)
          return *default_zm;
    }
-   keybox = make_keybox(prog, stage, &key, key.size, &key.base, base_size);
+   keybox = make_keybox(prog, key, key->size, &key->base, base_size);
    hash = keybox_hash(keybox);
    struct hash_entry *entry = _mesa_hash_table_search_pre_hashed(&prog->base.shader_cache[pstage],
                                                                  hash, keybox);
@@ -264,7 +166,7 @@ get_shader_module_for_stage(struct zink_context *ctx, struct zink_screen *screen
          return NULL;
       }
       zm->hash = hash;
-      mod = zink_shader_compile(screen, zs, prog->nir[stage], &key);
+      mod = zink_shader_compile(screen, zs, prog->nir[stage], key);
       if (!mod) {
          ralloc_free(keybox);
          FREE(zm);
@@ -273,7 +175,7 @@ get_shader_module_for_stage(struct zink_context *ctx, struct zink_screen *screen
       zm->shader = mod;
 
       _mesa_hash_table_insert_pre_hashed(&prog->base.shader_cache[pstage], hash, keybox, zm);
-      if (key.is_default_variant) {
+      if (is_default_variant) {
          /* previously returned */
          *default_zm = zm;
          zm->default_variant = true;
@@ -955,15 +857,34 @@ bind_stage(struct zink_context *ctx, enum pipe_shader_type stage,
 }
 
 static void
+bind_last_vertex_stage(struct zink_context *ctx)
+{
+   enum pipe_shader_type old = ctx->last_vertex_stage ? pipe_shader_type_from_mesa(ctx->last_vertex_stage->nir->info.stage) : PIPE_SHADER_TYPES;
+   if (ctx->gfx_stages[PIPE_SHADER_GEOMETRY])
+      ctx->last_vertex_stage = ctx->gfx_stages[PIPE_SHADER_GEOMETRY];
+   else if (ctx->gfx_stages[PIPE_SHADER_TESS_EVAL])
+      ctx->last_vertex_stage = ctx->gfx_stages[PIPE_SHADER_TESS_EVAL];
+   else
+      ctx->last_vertex_stage = ctx->gfx_stages[PIPE_SHADER_VERTEX];
+   enum pipe_shader_type current = ctx->last_vertex_stage ? pipe_shader_type_from_mesa(ctx->last_vertex_stage->nir->info.stage) : PIPE_SHADER_VERTEX;
+   if (old != current) {
+      if (old != PIPE_SHADER_TYPES) {
+         memset(&ctx->gfx_pipeline_state.shader_keys.key[old].key.vs_base, 0, sizeof(struct zink_vs_key_base));
+         ctx->dirty_shader_stages |= BITFIELD_BIT(old);
+      }
+      ctx->last_vertex_stage_dirty = true;
+   }
+}
+
+static void
 zink_bind_vs_state(struct pipe_context *pctx,
                    void *cso)
 {
    struct zink_context *ctx = zink_context(pctx);
+   if (!cso && !ctx->gfx_stages[PIPE_SHADER_VERTEX])
+      return;
+   void *prev = ctx->gfx_stages[PIPE_SHADER_VERTEX];
    bind_stage(ctx, PIPE_SHADER_VERTEX, cso);
-   if (!ctx->gfx_stages[PIPE_SHADER_GEOMETRY] &&
-       !ctx->gfx_stages[PIPE_SHADER_TESS_EVAL]) {
-      ctx->last_vertex_stage = cso;
-   }
    if (cso) {
       struct zink_shader *zs = cso;
       ctx->shader_reads_drawid = BITSET_TEST(zs->nir->info.system_values_read, SYSTEM_VALUE_DRAW_ID);
@@ -972,6 +893,9 @@ zink_bind_vs_state(struct pipe_context *pctx,
       ctx->shader_reads_drawid = false;
       ctx->shader_reads_basevertex = false;
    }
+   if (ctx->last_vertex_stage == prev)
+      ctx->last_vertex_stage = cso;
+
 }
 
 static void
@@ -979,6 +903,8 @@ zink_bind_fs_state(struct pipe_context *pctx,
                    void *cso)
 {
    struct zink_context *ctx = zink_context(pctx);
+   if (!cso && !ctx->gfx_stages[PIPE_SHADER_FRAGMENT])
+      return;
    bind_stage(ctx, PIPE_SHADER_FRAGMENT, cso);
    ctx->fbfetch_outputs = 0;
    if (cso) {
@@ -998,20 +924,15 @@ zink_bind_gs_state(struct pipe_context *pctx,
                    void *cso)
 {
    struct zink_context *ctx = zink_context(pctx);
+   if (!cso && !ctx->gfx_stages[PIPE_SHADER_GEOMETRY])
+      return;
    bool had_points = ctx->gfx_stages[PIPE_SHADER_GEOMETRY] ? ctx->gfx_stages[PIPE_SHADER_GEOMETRY]->nir->info.gs.output_primitive == GL_POINTS : false;
-   if (!!ctx->gfx_stages[PIPE_SHADER_GEOMETRY] != !!cso)
-      ctx->dirty_shader_stages |= BITFIELD_BIT(PIPE_SHADER_VERTEX) |
-                                  BITFIELD_BIT(PIPE_SHADER_TESS_EVAL);
    bind_stage(ctx, PIPE_SHADER_GEOMETRY, cso);
+   bind_last_vertex_stage(ctx);
    if (cso) {
-      ctx->last_vertex_stage = cso;
       if (!had_points && ctx->last_vertex_stage->nir->info.gs.output_primitive == GL_POINTS)
          ctx->gfx_pipeline_state.has_points++;
    } else {
-      if (ctx->gfx_stages[PIPE_SHADER_TESS_EVAL])
-         ctx->last_vertex_stage = ctx->gfx_stages[PIPE_SHADER_TESS_EVAL];
-      else
-         ctx->last_vertex_stage = ctx->gfx_stages[PIPE_SHADER_VERTEX];
       if (had_points)
          ctx->gfx_pipeline_state.has_points--;
    }
@@ -1029,21 +950,17 @@ zink_bind_tes_state(struct pipe_context *pctx,
                    void *cso)
 {
    struct zink_context *ctx = zink_context(pctx);
+   if (!cso && !ctx->gfx_stages[PIPE_SHADER_TESS_EVAL])
+      return;
    if (!!ctx->gfx_stages[PIPE_SHADER_TESS_EVAL] != !!cso) {
       if (!cso) {
          /* if unsetting a TESS that uses a generated TCS, ensure the TCS is unset */
          if (ctx->gfx_stages[PIPE_SHADER_TESS_EVAL]->generated)
             ctx->gfx_stages[PIPE_SHADER_TESS_CTRL] = NULL;
       }
-      ctx->dirty_shader_stages |= BITFIELD_BIT(PIPE_SHADER_VERTEX);
    }
    bind_stage(ctx, PIPE_SHADER_TESS_EVAL, cso);
-   if (!ctx->gfx_stages[PIPE_SHADER_GEOMETRY]) {
-      if (cso)
-         ctx->last_vertex_stage = cso;
-      else
-         ctx->last_vertex_stage = ctx->gfx_stages[PIPE_SHADER_VERTEX];
-   }
+   bind_last_vertex_stage(ctx);
 }
 
 static void *
index b0b586b..3ccbaa2 100644 (file)
@@ -278,6 +278,59 @@ zink_program_has_descriptors(const struct zink_program *pg)
 {
    return pg->num_dsl > 0;
 }
+
+static inline struct zink_fs_key *
+zink_set_fs_key(struct zink_context *ctx)
+{
+   ctx->dirty_shader_stages |= BITFIELD_BIT(PIPE_SHADER_FRAGMENT);
+   return (struct zink_fs_key *)&ctx->gfx_pipeline_state.shader_keys.key[PIPE_SHADER_FRAGMENT];
+}
+
+static inline const struct zink_fs_key *
+zink_get_fs_key(struct zink_context *ctx)
+{
+   return (const struct zink_fs_key *)&ctx->gfx_pipeline_state.shader_keys.key[PIPE_SHADER_FRAGMENT];
+}
+
+static inline struct zink_vs_key *
+zink_set_vs_key(struct zink_context *ctx)
+{
+   ctx->dirty_shader_stages |= BITFIELD_BIT(PIPE_SHADER_VERTEX);
+   return (struct zink_vs_key *)&ctx->gfx_pipeline_state.shader_keys.key[PIPE_SHADER_VERTEX];
+}
+
+static inline const struct zink_vs_key *
+zink_get_vs_key(struct zink_context *ctx)
+{
+   return (const struct zink_vs_key *)&ctx->gfx_pipeline_state.shader_keys.key[PIPE_SHADER_VERTEX];
+}
+
+static inline struct zink_vs_key_base *
+zink_set_last_vertex_key(struct zink_context *ctx)
+{
+   ctx->last_vertex_stage_dirty = true;
+   return (struct zink_vs_key_base *)&ctx->gfx_pipeline_state.shader_keys.last_vertex;
+}
+
+static inline const struct zink_vs_key_base *
+zink_get_last_vertex_key(struct zink_context *ctx)
+{
+   return (const struct zink_vs_key_base *)&ctx->gfx_pipeline_state.shader_keys.last_vertex;
+}
+
+static inline void
+zink_set_fs_point_coord_key(struct zink_context *ctx)
+{
+   const struct zink_fs_key *fs = zink_get_fs_key(ctx);
+   bool disable = !ctx->gfx_pipeline_state.has_points || !ctx->rast_state->base.sprite_coord_enable;
+   uint8_t coord_replace_bits = disable ? 0 : ctx->rast_state->base.sprite_coord_enable;
+   bool coord_replace_yinvert = disable ? false : !!ctx->rast_state->base.sprite_coord_mode;
+   if (fs->coord_replace_bits != coord_replace_bits || fs->coord_replace_yinvert != coord_replace_yinvert) {
+      zink_set_fs_key(ctx)->coord_replace_bits = coord_replace_bits;
+      zink_set_fs_key(ctx)->coord_replace_yinvert = coord_replace_yinvert;
+   }
+}
+
 #ifdef __cplusplus
 }
 #endif
index a0731f8..318728e 100644 (file)
@@ -26,6 +26,8 @@
 #ifndef ZINK_SHADER_KEYS_H
 # define ZINK_SHADER_KEYS_H
 
+#include "compiler/shader_info.h"
+
 struct zink_vs_key_base {
    bool clip_halfz;
    bool push_drawid;
@@ -79,7 +81,6 @@ struct zink_shader_key {
    struct zink_shader_key_base base;
    unsigned inline_uniforms:1;
    uint32_t size;
-   bool is_default_variant;
 };
 
 static inline const struct zink_fs_key *
index 00b4b38..68e8d41 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "zink_context.h"
 #include "zink_format.h"
+#include "zink_program.h"
 #include "zink_screen.h"
 
 #include "compiler/shader_enums.h"
@@ -178,11 +179,45 @@ zink_bind_vertex_elements_state(struct pipe_context *pctx,
          ctx->vertex_state_changed = !zink_screen(pctx->screen)->info.have_EXT_vertex_input_dynamic_state;
          ctx->vertex_buffers_dirty = ctx->element_state->hw_state.num_bindings > 0;
       }
-      if (ctx->element_state->decomposed_attrs != state->decomposed_attrs ||
-          ctx->element_state->decomposed_attrs_without_w != state->decomposed_attrs_without_w)
-         ctx->dirty_shader_stages |= BITFIELD_BIT(PIPE_SHADER_VERTEX);
-      state->decomposed_attrs = ctx->element_state->decomposed_attrs;
-      state->decomposed_attrs_without_w = ctx->element_state->decomposed_attrs_without_w;
+      const struct zink_vs_key *vs = zink_get_vs_key(ctx);
+      uint32_t decomposed_attrs = 0, decomposed_attrs_without_w = 0;
+      switch (vs->size) {
+      case 1:
+         decomposed_attrs = vs->u8.decomposed_attrs;
+         decomposed_attrs_without_w = vs->u8.decomposed_attrs_without_w;
+         break;
+      case 2:
+         decomposed_attrs = vs->u16.decomposed_attrs;
+         decomposed_attrs_without_w = vs->u16.decomposed_attrs_without_w;
+         break;
+      case 4:
+         decomposed_attrs = vs->u16.decomposed_attrs;
+         decomposed_attrs_without_w = vs->u16.decomposed_attrs_without_w;
+         break;
+      }
+      if (ctx->element_state->decomposed_attrs != decomposed_attrs ||
+          ctx->element_state->decomposed_attrs_without_w != decomposed_attrs_without_w) {
+         unsigned size = MAX2(ctx->element_state->decomposed_attrs_size, ctx->element_state->decomposed_attrs_without_w_size);
+         struct zink_shader_key *key = (struct zink_shader_key *)zink_set_vs_key(ctx);
+         key->size -= 2 * key->key.vs.size;
+         switch (size) {
+         case 1:
+            key->key.vs.u8.decomposed_attrs = ctx->element_state->decomposed_attrs;
+            key->key.vs.u8.decomposed_attrs_without_w = ctx->element_state->decomposed_attrs_without_w;
+            break;
+         case 2:
+            key->key.vs.u16.decomposed_attrs = ctx->element_state->decomposed_attrs;
+            key->key.vs.u16.decomposed_attrs_without_w = ctx->element_state->decomposed_attrs_without_w;
+            break;
+         case 4:
+            key->key.vs.u32.decomposed_attrs = ctx->element_state->decomposed_attrs;
+            key->key.vs.u32.decomposed_attrs_without_w = ctx->element_state->decomposed_attrs_without_w;
+            break;
+         default: break;
+         }
+         key->key.vs.size = size;
+         key->size += 2 * size;
+      }
       state->element_state = &ctx->element_state->hw_state;
    } else {
      state->element_state = NULL;
@@ -380,6 +415,10 @@ zink_bind_blend_state(struct pipe_context *pctx, void *cso)
       state->blend_state = cso;
       state->blend_id = blend ? blend->hash : 0;
       state->dirty = true;
+      bool force_dual_color_blend = zink_screen(pctx->screen)->driconf.dual_color_blend_by_location &&
+                                    blend && blend->dual_src_blend && state->blend_state->attachments[1].blendEnable;
+      if (force_dual_color_blend != zink_get_fs_key(ctx)->force_dual_color_blend)
+         zink_set_fs_key(ctx)->force_dual_color_blend = force_dual_color_blend;
       ctx->blend_state_changed = true;
    }
 }
@@ -635,7 +674,6 @@ zink_bind_rasterizer_state(struct pipe_context *pctx, void *cso)
 {
    struct zink_context *ctx = zink_context(pctx);
    struct zink_screen *screen = zink_screen(pctx->screen);
-   bool clip_halfz = ctx->rast_state ? ctx->rast_state->base.clip_halfz : false;
    bool point_quad_rasterization = ctx->rast_state ? ctx->rast_state->base.point_quad_rasterization : false;
    bool scissor = ctx->rast_state ? ctx->rast_state->base.scissor : false;
    bool pv_last = ctx->rast_state ? ctx->rast_state->hw_state.pv_last : false;
@@ -654,8 +692,8 @@ zink_bind_rasterizer_state(struct pipe_context *pctx, void *cso)
       ctx->gfx_pipeline_state.dirty = true;
       ctx->rast_state_changed = true;
 
-      if (clip_halfz != ctx->rast_state->base.clip_halfz) {
-         ctx->last_vertex_stage_dirty = true;
+      if (zink_get_last_vertex_key(ctx)->clip_halfz != ctx->rast_state->base.clip_halfz) {
+         zink_set_last_vertex_key(ctx)->clip_halfz = ctx->rast_state->base.clip_halfz;
          ctx->vp_state_changed = true;
       }
 
@@ -663,11 +701,8 @@ zink_bind_rasterizer_state(struct pipe_context *pctx, void *cso)
          ctx->gfx_pipeline_state.dyn_state1.front_face = ctx->rast_state->front_face;
          ctx->gfx_pipeline_state.dirty |= !zink_screen(pctx->screen)->info.have_EXT_extended_dynamic_state;
       }
-      if (ctx->rast_state->base.point_quad_rasterization != point_quad_rasterization) {
-         ctx->dirty_shader_stages |= BITFIELD_BIT(PIPE_SHADER_FRAGMENT);
-         ctx->gfx_pipeline_state.coord_replace_bits = ctx->rast_state->base.sprite_coord_enable;
-         ctx->gfx_pipeline_state.coord_replace_yinvert = !!ctx->rast_state->base.sprite_coord_mode;
-      }
+      if (ctx->rast_state->base.point_quad_rasterization != point_quad_rasterization)
+         zink_set_fs_point_coord_key(ctx);
       if (ctx->rast_state->base.scissor != scissor)
          ctx->scissor_changed = true;
    }