glsl: drop cache_fallback
[mesa.git] / src / compiler / glsl / shader_cache.cpp
index 2c96966bc31cc6ba8640e8f322b5bc7abcf605ef..89da19914fe8f8135a5aaf83af1a3806d721e06a 100644 (file)
@@ -59,7 +59,7 @@
 #include "program.h"
 #include "shader_cache.h"
 #include "util/mesa-sha1.h"
-#include "util/string_to_uint_map.h"
+#include "string_to_uint_map.h"
 
 extern "C" {
 #include "main/enums.h"
@@ -74,139 +74,6 @@ compile_shaders(struct gl_context *ctx, struct gl_shader_program *prog) {
    }
 }
 
-static void
-encode_type_to_blob(struct blob *blob, const glsl_type *type)
-{
-   uint32_t encoding;
-
-   switch (type->base_type) {
-   case GLSL_TYPE_UINT:
-   case GLSL_TYPE_INT:
-   case GLSL_TYPE_FLOAT:
-   case GLSL_TYPE_BOOL:
-   case GLSL_TYPE_DOUBLE:
-   case GLSL_TYPE_UINT64:
-   case GLSL_TYPE_INT64:
-      encoding = (type->base_type << 24) |
-         (type->vector_elements << 4) |
-         (type->matrix_columns);
-      break;
-   case GLSL_TYPE_SAMPLER:
-      encoding = (type->base_type) << 24 |
-         (type->sampler_dimensionality << 4) |
-         (type->sampler_shadow << 3) |
-         (type->sampler_array << 2) |
-         (type->sampled_type);
-      break;
-   case GLSL_TYPE_SUBROUTINE:
-      encoding = type->base_type << 24;
-      blob_write_uint32(blob, encoding);
-      blob_write_string(blob, type->name);
-      return;
-   case GLSL_TYPE_IMAGE:
-      encoding = (type->base_type) << 24 |
-         (type->sampler_dimensionality << 3) |
-         (type->sampler_array << 2) |
-         (type->sampled_type);
-      break;
-   case GLSL_TYPE_ATOMIC_UINT:
-      encoding = (type->base_type << 24);
-      break;
-   case GLSL_TYPE_ARRAY:
-      blob_write_uint32(blob, (type->base_type) << 24);
-      blob_write_uint32(blob, type->length);
-      encode_type_to_blob(blob, type->fields.array);
-      return;
-   case GLSL_TYPE_STRUCT:
-   case GLSL_TYPE_INTERFACE:
-      blob_write_uint32(blob, (type->base_type) << 24);
-      blob_write_string(blob, type->name);
-      blob_write_uint32(blob, type->length);
-      blob_write_bytes(blob, type->fields.structure,
-                       sizeof(glsl_struct_field) * type->length);
-      for (unsigned i = 0; i < type->length; i++) {
-         encode_type_to_blob(blob, type->fields.structure[i].type);
-         blob_write_string(blob, type->fields.structure[i].name);
-      }
-
-      if (type->base_type == GLSL_TYPE_INTERFACE) {
-         blob_write_uint32(blob, type->interface_packing);
-         blob_write_uint32(blob, type->interface_row_major);
-      }
-      return;
-   case GLSL_TYPE_VOID:
-   case GLSL_TYPE_ERROR:
-   default:
-      assert(!"Cannot encode type!");
-      encoding = 0;
-      break;
-   }
-
-   blob_write_uint32(blob, encoding);
-}
-
-static const glsl_type *
-decode_type_from_blob(struct blob_reader *blob)
-{
-   uint32_t u = blob_read_uint32(blob);
-   glsl_base_type base_type = (glsl_base_type) (u >> 24);
-
-   switch (base_type) {
-   case GLSL_TYPE_UINT:
-   case GLSL_TYPE_INT:
-   case GLSL_TYPE_FLOAT:
-   case GLSL_TYPE_BOOL:
-   case GLSL_TYPE_DOUBLE:
-   case GLSL_TYPE_UINT64:
-   case GLSL_TYPE_INT64:
-      return glsl_type::get_instance(base_type, (u >> 4) & 0x0f, u & 0x0f);
-   case GLSL_TYPE_SAMPLER:
-      return glsl_type::get_sampler_instance((enum glsl_sampler_dim) ((u >> 4) & 0x07),
-                                             (u >> 3) & 0x01,
-                                             (u >> 2) & 0x01,
-                                             (glsl_base_type) ((u >> 0) & 0x03));
-   case GLSL_TYPE_SUBROUTINE:
-      return glsl_type::get_subroutine_instance(blob_read_string(blob));
-   case GLSL_TYPE_IMAGE:
-      return glsl_type::get_image_instance((enum glsl_sampler_dim) ((u >> 3) & 0x07),
-                                             (u >> 2) & 0x01,
-                                             (glsl_base_type) ((u >> 0) & 0x03));
-   case GLSL_TYPE_ATOMIC_UINT:
-      return glsl_type::atomic_uint_type;
-   case GLSL_TYPE_ARRAY: {
-      unsigned length = blob_read_uint32(blob);
-      return glsl_type::get_array_instance(decode_type_from_blob(blob),
-                                           length);
-   }
-   case GLSL_TYPE_STRUCT:
-   case GLSL_TYPE_INTERFACE: {
-      char *name = blob_read_string(blob);
-      unsigned num_fields = blob_read_uint32(blob);
-      glsl_struct_field *fields = (glsl_struct_field *)
-         blob_read_bytes(blob, sizeof(glsl_struct_field) * num_fields);
-      for (unsigned i = 0; i < num_fields; i++) {
-         fields[i].type = decode_type_from_blob(blob);
-         fields[i].name = blob_read_string(blob);
-      }
-
-      if (base_type == GLSL_TYPE_INTERFACE) {
-         enum glsl_interface_packing packing =
-            (glsl_interface_packing) blob_read_uint32(blob);
-         bool row_major = blob_read_uint32(blob);
-         return glsl_type::get_interface_instance(fields, num_fields,
-                                                  packing, row_major, name);
-      } else {
-         return glsl_type::get_record_instance(fields, num_fields, name);
-      }
-   }
-   case GLSL_TYPE_VOID:
-   case GLSL_TYPE_ERROR:
-   default:
-      assert(!"Cannot decode type!");
-      return NULL;
-   }
-}
-
 static void
 write_subroutines(struct blob *metadata, struct gl_shader_program *prog)
 {
@@ -555,6 +422,17 @@ read_xfb(struct blob_reader *metadata, struct gl_shader_program *shProg)
                       MAX_FEEDBACK_BUFFERS);
 }
 
+static bool
+has_uniform_storage(struct gl_shader_program *prog, unsigned idx)
+{
+   if (!prog->data->UniformStorage[idx].builtin &&
+       !prog->data->UniformStorage[idx].is_shader_storage &&
+       prog->data->UniformStorage[idx].block_index == -1)
+      return true;
+
+   return false;
+}
+
 static void
 write_uniforms(struct blob *metadata, struct gl_shader_program *prog)
 {
@@ -566,24 +444,49 @@ write_uniforms(struct blob *metadata, struct gl_shader_program *prog)
       encode_type_to_blob(metadata, prog->data->UniformStorage[i].type);
       blob_write_uint32(metadata, prog->data->UniformStorage[i].array_elements);
       blob_write_string(metadata, prog->data->UniformStorage[i].name);
-      blob_write_uint32(metadata, prog->data->UniformStorage[i].storage -
-                                  prog->data->UniformDataSlots);
+      blob_write_uint32(metadata, prog->data->UniformStorage[i].builtin);
       blob_write_uint32(metadata, prog->data->UniformStorage[i].remap_location);
       blob_write_uint32(metadata, prog->data->UniformStorage[i].block_index);
       blob_write_uint32(metadata, prog->data->UniformStorage[i].atomic_buffer_index);
       blob_write_uint32(metadata, prog->data->UniformStorage[i].offset);
       blob_write_uint32(metadata, prog->data->UniformStorage[i].array_stride);
+      blob_write_uint32(metadata, prog->data->UniformStorage[i].hidden);
+      blob_write_uint32(metadata, prog->data->UniformStorage[i].is_shader_storage);
+      blob_write_uint32(metadata, prog->data->UniformStorage[i].active_shader_mask);
       blob_write_uint32(metadata, prog->data->UniformStorage[i].matrix_stride);
       blob_write_uint32(metadata, prog->data->UniformStorage[i].row_major);
+      blob_write_uint32(metadata, prog->data->UniformStorage[i].is_bindless);
       blob_write_uint32(metadata,
                         prog->data->UniformStorage[i].num_compatible_subroutines);
       blob_write_uint32(metadata,
                         prog->data->UniformStorage[i].top_level_array_size);
       blob_write_uint32(metadata,
                         prog->data->UniformStorage[i].top_level_array_stride);
+
+     if (has_uniform_storage(prog, i)) {
+         blob_write_uint32(metadata, prog->data->UniformStorage[i].storage -
+                                     prog->data->UniformDataSlots);
+      }
+
       blob_write_bytes(metadata, prog->data->UniformStorage[i].opaque,
                        sizeof(prog->data->UniformStorage[i].opaque));
    }
+
+   /* Here we cache all uniform values. We do this to retain values for
+    * uniforms with initialisers and also hidden uniforms that may be lowered
+    * constant arrays. We could possibly just store the values we need but for
+    * now we just store everything.
+    */
+   blob_write_uint32(metadata, prog->data->NumHiddenUniforms);
+   for (unsigned i = 0; i < prog->data->NumUniformStorage; i++) {
+      if (has_uniform_storage(prog, i)) {
+         unsigned vec_size =
+            prog->data->UniformStorage[i].type->component_slots() *
+            MAX2(prog->data->UniformStorage[i].array_elements, 1);
+         blob_write_bytes(metadata, prog->data->UniformStorage[i].storage,
+                          sizeof(union gl_constant_value) * vec_size);
+      }
+   }
 }
 
 static void
@@ -610,23 +513,47 @@ read_uniforms(struct blob_reader *metadata, struct gl_shader_program *prog)
       uniforms[i].type = decode_type_from_blob(metadata);
       uniforms[i].array_elements = blob_read_uint32(metadata);
       uniforms[i].name = ralloc_strdup(prog, blob_read_string (metadata));
-      uniforms[i].storage = data + blob_read_uint32(metadata);
+      uniforms[i].builtin = blob_read_uint32(metadata);
       uniforms[i].remap_location = blob_read_uint32(metadata);
       uniforms[i].block_index = blob_read_uint32(metadata);
       uniforms[i].atomic_buffer_index = blob_read_uint32(metadata);
       uniforms[i].offset = blob_read_uint32(metadata);
       uniforms[i].array_stride = blob_read_uint32(metadata);
+      uniforms[i].hidden = blob_read_uint32(metadata);
+      uniforms[i].is_shader_storage = blob_read_uint32(metadata);
+      uniforms[i].active_shader_mask = blob_read_uint32(metadata);
       uniforms[i].matrix_stride = blob_read_uint32(metadata);
       uniforms[i].row_major = blob_read_uint32(metadata);
+      uniforms[i].is_bindless = blob_read_uint32(metadata);
       uniforms[i].num_compatible_subroutines = blob_read_uint32(metadata);
       uniforms[i].top_level_array_size = blob_read_uint32(metadata);
       uniforms[i].top_level_array_stride = blob_read_uint32(metadata);
       prog->UniformHash->put(i, uniforms[i].name);
 
+      if (has_uniform_storage(prog, i)) {
+         uniforms[i].storage = data + blob_read_uint32(metadata);
+      }
+
       memcpy(uniforms[i].opaque,
              blob_read_bytes(metadata, sizeof(uniforms[i].opaque)),
              sizeof(uniforms[i].opaque));
    }
+
+   /* Restore uniform values. */
+   prog->data->NumHiddenUniforms = blob_read_uint32(metadata);
+   for (unsigned i = 0; i < prog->data->NumUniformStorage; i++) {
+      if (has_uniform_storage(prog, i)) {
+         unsigned vec_size =
+            prog->data->UniformStorage[i].type->component_slots() *
+            MAX2(prog->data->UniformStorage[i].array_elements, 1);
+         blob_copy_bytes(metadata,
+                         (uint8_t *) prog->data->UniformStorage[i].storage,
+                         sizeof(union gl_constant_value) * vec_size);
+
+        assert(vec_size + prog->data->UniformStorage[i].storage <=
+               data +  prog->data->NumUniformDataSlots);
+      }
+   }
 }
 
 enum uniform_remap_type
@@ -821,6 +748,18 @@ write_shader_subroutine_index(struct blob *metadata,
    }
 }
 
+static void
+get_shader_var_and_pointer_sizes(size_t *s_var_size, size_t *s_var_ptrs,
+                                 const gl_shader_variable *var)
+{
+   *s_var_size = sizeof(gl_shader_variable);
+   *s_var_ptrs =
+      sizeof(var->type) +
+      sizeof(var->interface_type) +
+      sizeof(var->outermost_struct_type) +
+      sizeof(var->name);
+}
+
 static void
 write_program_resource_data(struct blob *metadata,
                             struct gl_shader_program *prog,
@@ -832,16 +771,19 @@ write_program_resource_data(struct blob *metadata,
    case GL_PROGRAM_INPUT:
    case GL_PROGRAM_OUTPUT: {
       const gl_shader_variable *var = (gl_shader_variable *)res->Data;
-      blob_write_bytes(metadata, var, sizeof(gl_shader_variable));
+
       encode_type_to_blob(metadata, var->type);
+      encode_type_to_blob(metadata, var->interface_type);
+      encode_type_to_blob(metadata, var->outermost_struct_type);
 
-      if (var->interface_type)
-         encode_type_to_blob(metadata, var->interface_type);
+      blob_write_string(metadata, var->name);
 
-      if (var->outermost_struct_type)
-         encode_type_to_blob(metadata, var->outermost_struct_type);
+      size_t s_var_size, s_var_ptrs;
+      get_shader_var_and_pointer_sizes(&s_var_size, &s_var_ptrs, var);
 
-      blob_write_string(metadata, var->name);
+      /* Write gl_shader_variable skipping over the pointers */
+      blob_write_bytes(metadata, ((char *)var) + s_var_ptrs,
+                       s_var_size - s_var_ptrs);
       break;
    }
    case GL_UNIFORM_BLOCK:
@@ -932,16 +874,17 @@ read_program_resource_data(struct blob_reader *metadata,
    case GL_PROGRAM_OUTPUT: {
       gl_shader_variable *var = ralloc(prog, struct gl_shader_variable);
 
-      blob_copy_bytes(metadata, (uint8_t *) var, sizeof(gl_shader_variable));
       var->type = decode_type_from_blob(metadata);
+      var->interface_type = decode_type_from_blob(metadata);
+      var->outermost_struct_type = decode_type_from_blob(metadata);
 
-      if (var->interface_type)
-         var->interface_type = decode_type_from_blob(metadata);
+      var->name = ralloc_strdup(prog, blob_read_string(metadata));
 
-      if (var->outermost_struct_type)
-         var->outermost_struct_type = decode_type_from_blob(metadata);
+      size_t s_var_size, s_var_ptrs;
+      get_shader_var_and_pointer_sizes(&s_var_size, &s_var_ptrs, var);
 
-      var->name = ralloc_strdup(prog, blob_read_string(metadata));
+      blob_copy_bytes(metadata, ((uint8_t *) var) + s_var_ptrs,
+                      s_var_size - s_var_ptrs);
 
       res->Data = var;
       break;
@@ -1059,6 +1002,7 @@ read_shader_parameters(struct blob_reader *metadata,
    uint32_t i = 0;
    uint32_t num_parameters = blob_read_uint32(metadata);
 
+   _mesa_reserve_parameter_storage(params, num_parameters);
    while (i < num_parameters) {
       gl_register_file type = (gl_register_file) blob_read_uint32(metadata);
       const char *name = blob_read_string(metadata);
@@ -1084,6 +1028,7 @@ write_shader_metadata(struct blob *metadata, gl_linked_shader *shader)
 {
    assert(shader->Program);
    struct gl_program *glprog = shader->Program;
+   unsigned i;
 
    blob_write_bytes(metadata, glprog->TexturesUsed,
                     sizeof(glprog->TexturesUsed));
@@ -1100,7 +1045,34 @@ write_shader_metadata(struct blob *metadata, gl_linked_shader *shader)
    blob_write_bytes(metadata, glprog->sh.ImageUnits,
                     sizeof(glprog->sh.ImageUnits));
 
+   size_t ptr_size = sizeof(GLvoid *);
+
+   blob_write_uint32(metadata, glprog->sh.NumBindlessSamplers);
+   blob_write_uint32(metadata, glprog->sh.HasBoundBindlessSampler);
+   for (i = 0; i < glprog->sh.NumBindlessSamplers; i++) {
+      blob_write_bytes(metadata, &glprog->sh.BindlessSamplers[i],
+                       sizeof(struct gl_bindless_sampler) - ptr_size);
+   }
+
+   blob_write_uint32(metadata, glprog->sh.NumBindlessImages);
+   blob_write_uint32(metadata, glprog->sh.HasBoundBindlessImage);
+   for (i = 0; i < glprog->sh.NumBindlessImages; i++) {
+      blob_write_bytes(metadata, &glprog->sh.BindlessImages[i],
+                       sizeof(struct gl_bindless_image) - ptr_size);
+   }
+
+   blob_write_bytes(metadata, &glprog->sh.fs.BlendSupport,
+                    sizeof(glprog->sh.fs.BlendSupport));
+
    write_shader_parameters(metadata, glprog->Parameters);
+
+   assert((glprog->driver_cache_blob == NULL) ==
+          (glprog->driver_cache_blob_size == 0));
+   blob_write_uint32(metadata, (uint32_t)glprog->driver_cache_blob_size);
+   if (glprog->driver_cache_blob_size > 0) {
+      blob_write_bytes(metadata, glprog->driver_cache_blob,
+                       glprog->driver_cache_blob_size);
+   }
 }
 
 static void
@@ -1108,6 +1080,8 @@ read_shader_metadata(struct blob_reader *metadata,
                      struct gl_program *glprog,
                      gl_linked_shader *linked)
 {
+   unsigned i;
+
    blob_copy_bytes(metadata, (uint8_t *) glprog->TexturesUsed,
                    sizeof(glprog->TexturesUsed));
    glprog->SamplersUsed = blob_read_uint64(metadata);
@@ -1123,8 +1097,47 @@ read_shader_metadata(struct blob_reader *metadata,
    blob_copy_bytes(metadata, (uint8_t *) glprog->sh.ImageUnits,
                    sizeof(glprog->sh.ImageUnits));
 
+   size_t ptr_size = sizeof(GLvoid *);
+
+   glprog->sh.NumBindlessSamplers = blob_read_uint32(metadata);
+   glprog->sh.HasBoundBindlessSampler = blob_read_uint32(metadata);
+   if (glprog->sh.NumBindlessSamplers > 0) {
+      glprog->sh.BindlessSamplers =
+         rzalloc_array(glprog, gl_bindless_sampler,
+                       glprog->sh.NumBindlessSamplers);
+
+      for (i = 0; i < glprog->sh.NumBindlessSamplers; i++) {
+         blob_copy_bytes(metadata, (uint8_t *) &glprog->sh.BindlessSamplers[i],
+                         sizeof(struct gl_bindless_sampler) - ptr_size);
+      }
+   }
+
+   glprog->sh.NumBindlessImages = blob_read_uint32(metadata);
+   glprog->sh.HasBoundBindlessImage = blob_read_uint32(metadata);
+   if (glprog->sh.NumBindlessImages > 0) {
+      glprog->sh.BindlessImages =
+         rzalloc_array(glprog, gl_bindless_image,
+                       glprog->sh.NumBindlessImages);
+
+      for (i = 0; i < glprog->sh.NumBindlessImages; i++) {
+         blob_copy_bytes(metadata, (uint8_t *) &glprog->sh.BindlessImages[i],
+                        sizeof(struct gl_bindless_image) - ptr_size);
+      }
+   }
+
+   blob_copy_bytes(metadata, (uint8_t *) &glprog->sh.fs.BlendSupport,
+                   sizeof(glprog->sh.fs.BlendSupport));
+
    glprog->Parameters = _mesa_new_parameter_list();
    read_shader_parameters(metadata, glprog->Parameters);
+
+   glprog->driver_cache_blob_size = (size_t)blob_read_uint32(metadata);
+   if (glprog->driver_cache_blob_size > 0) {
+      glprog->driver_cache_blob =
+         (uint8_t*)ralloc_size(glprog, glprog->driver_cache_blob_size);
+      blob_copy_bytes(metadata, glprog->driver_cache_blob,
+                      glprog->driver_cache_blob_size);
+   }
 }
 
 static void
@@ -1134,6 +1147,14 @@ create_binding_str(const char *key, unsigned value, void *closure)
    ralloc_asprintf_append(bindings_str, "%s:%u,", key, value);
 }
 
+static void
+get_shader_info_and_pointer_sizes(size_t *s_info_size, size_t *s_info_ptrs,
+                                  shader_info *info)
+{
+   *s_info_size = sizeof(shader_info);
+   *s_info_ptrs = sizeof(info->name) + sizeof(info->label);
+}
+
 static void
 create_linked_shader_and_program(struct gl_context *ctx,
                                  gl_shader_stage stage,
@@ -1152,12 +1173,16 @@ create_linked_shader_and_program(struct gl_context *ctx,
 
    read_shader_metadata(metadata, glprog, linked);
 
+   glprog->info.name = ralloc_strdup(glprog, blob_read_string(metadata));
+   glprog->info.label = ralloc_strdup(glprog, blob_read_string(metadata));
+
+   size_t s_info_size, s_info_ptrs;
+   get_shader_info_and_pointer_sizes(&s_info_size, &s_info_ptrs,
+                                     &glprog->info);
+
    /* Restore shader info */
-   blob_copy_bytes(metadata, (uint8_t *) &glprog->info, sizeof(shader_info));
-   if (glprog->info.name)
-      glprog->info.name = ralloc_strdup(glprog, blob_read_string(metadata));
-   if (glprog->info.label)
-      glprog->info.label = ralloc_strdup(glprog, blob_read_string(metadata));
+   blob_copy_bytes(metadata, ((uint8_t *) &glprog->info) + s_info_ptrs,
+                   s_info_size - s_info_ptrs);
 
    _mesa_reference_shader_program_data(ctx, &glprog->sh.data, prog->data);
    _mesa_reference_program(ctx, &linked->Program, glprog);
@@ -1178,63 +1203,89 @@ shader_cache_write_program_metadata(struct gl_context *ctx,
     * TODO: In future we should use another method to generate a key for ff
     * programs.
     */
-   if (*prog->data->sha1 == 0)
+   static const char zero[sizeof(prog->data->sha1)] = {0};
+   if (memcmp(prog->data->sha1, zero, sizeof(prog->data->sha1)) == 0)
       return;
 
-   struct blob *metadata = blob_create(NULL);
+   struct blob metadata;
+   blob_init(&metadata);
 
-   write_uniforms(metadata, prog);
+   write_uniforms(&metadata, prog);
 
-   write_hash_tables(metadata, prog);
+   write_hash_tables(&metadata, prog);
 
-   blob_write_uint32(metadata, prog->data->Version);
-   blob_write_uint32(metadata, prog->data->linked_stages);
+   blob_write_uint32(&metadata, prog->data->Version);
+   blob_write_uint32(&metadata, prog->data->linked_stages);
 
    for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
       struct gl_linked_shader *sh = prog->_LinkedShaders[i];
       if (sh) {
-         write_shader_metadata(metadata, sh);
-
-         /* Store nir shader info */
-         blob_write_bytes(metadata, &sh->Program->info, sizeof(shader_info));
+         write_shader_metadata(&metadata, sh);
 
          if (sh->Program->info.name)
-            blob_write_string(metadata, sh->Program->info.name);
+            blob_write_string(&metadata, sh->Program->info.name);
+         else
+            blob_write_string(&metadata, "");
 
          if (sh->Program->info.label)
-            blob_write_string(metadata, sh->Program->info.label);
+            blob_write_string(&metadata, sh->Program->info.label);
+         else
+            blob_write_string(&metadata, "");
+
+         size_t s_info_size, s_info_ptrs;
+         get_shader_info_and_pointer_sizes(&s_info_size, &s_info_ptrs,
+                                           &sh->Program->info);
+
+         /* Store shader info */
+         blob_write_bytes(&metadata,
+                          ((char *) &sh->Program->info) + s_info_ptrs,
+                          s_info_size - s_info_ptrs);
       }
    }
 
-   write_xfb(metadata, prog);
+   write_xfb(&metadata, prog);
 
-   write_uniform_remap_tables(metadata, prog);
+   write_uniform_remap_tables(&metadata, prog);
 
-   write_atomic_buffers(metadata, prog);
+   write_atomic_buffers(&metadata, prog);
 
-   write_buffer_blocks(metadata, prog);
+   write_buffer_blocks(&metadata, prog);
 
-   write_subroutines(metadata, prog);
+   write_subroutines(&metadata, prog);
 
-   write_program_resource_list(metadata, prog);
+   write_program_resource_list(&metadata, prog);
+
+   struct cache_item_metadata cache_item_metadata;
+   cache_item_metadata.type = CACHE_ITEM_TYPE_GLSL;
+   cache_item_metadata.keys =
+      (cache_key *) malloc(prog->NumShaders * sizeof(cache_key));
+   cache_item_metadata.num_keys = prog->NumShaders;
+
+   if (!cache_item_metadata.keys)
+      goto fail;
 
    char sha1_buf[41];
    for (unsigned i = 0; i < prog->NumShaders; i++) {
       disk_cache_put_key(cache, prog->Shaders[i]->sha1);
+      memcpy(cache_item_metadata.keys[i], prog->Shaders[i]->sha1,
+             sizeof(cache_key));
       if (ctx->_Shader->Flags & GLSL_CACHE_INFO) {
-         fprintf(stderr, "marking shader: %s\n",
-                 _mesa_sha1_format(sha1_buf, prog->Shaders[i]->sha1));
+         _mesa_sha1_format(sha1_buf, prog->Shaders[i]->sha1);
+         fprintf(stderr, "marking shader: %s\n", sha1_buf);
       }
    }
 
-   disk_cache_put(cache, prog->data->sha1, metadata->data, metadata->size);
-
-   ralloc_free(metadata);
+   disk_cache_put(cache, prog->data->sha1, metadata.data, metadata.size,
+                  &cache_item_metadata);
 
    if (ctx->_Shader->Flags & GLSL_CACHE_INFO) {
-      fprintf(stderr, "putting program metadata in cache: %s\n",
-              _mesa_sha1_format(sha1_buf, prog->data->sha1));
+      _mesa_sha1_format(sha1_buf, prog->data->sha1);
+      fprintf(stderr, "putting program metadata in cache: %s\n", sha1_buf);
    }
+
+fail:
+   free(cache_item_metadata.keys);
+   blob_finish(&metadata);
 }
 
 bool
@@ -1248,7 +1299,7 @@ shader_cache_read_program_metadata(struct gl_context *ctx,
       return false;
 
    struct disk_cache *cache = ctx->Cache;
-   if (!cache)
+   if (!cache || prog->data->skip_cache)
       return false;
 
    /* Include bindings when creating sha1. These bindings change the resulting
@@ -1267,14 +1318,38 @@ shader_cache_read_program_metadata(struct gl_context *ctx,
    ralloc_asprintf_append(&buf, "sso: %s\n",
                           prog->SeparateShader ? "T" : "F");
 
+   /* A shader might end up producing different output depending on the glsl
+    * version supported by the compiler. For example a different path might be
+    * taken by the preprocessor, so add the version to the hash input.
+    */
+   ralloc_asprintf_append(&buf, "api: %d glsl: %d fglsl: %d\n",
+                          ctx->API, ctx->Const.GLSLVersion,
+                          ctx->Const.ForceGLSLVersion);
+
+   /* We run the preprocessor on shaders after hashing them, so we need to
+    * add any extension override vars to the hash. If we don't do this the
+    * preprocessor could result in different output and we could load the
+    * wrong shader.
+    */
+   char *ext_override = getenv("MESA_EXTENSION_OVERRIDE");
+   if (ext_override) {
+      ralloc_asprintf_append(&buf, "ext:%s", ext_override);
+   }
+
+   /* DRI config options may also change the output from the compiler so
+    * include them as an input to sha1 creation.
+    */
    char sha1buf[41];
+   _mesa_sha1_format(sha1buf, ctx->Const.dri_config_options_sha1);
+   ralloc_strcat(&buf, sha1buf);
+
    for (unsigned i = 0; i < prog->NumShaders; i++) {
       struct gl_shader *sh = prog->Shaders[i];
+      _mesa_sha1_format(sha1buf, sh->sha1);
       ralloc_asprintf_append(&buf, "%s: %s\n",
-                             _mesa_shader_stage_to_abbrev(sh->Stage),
-                             _mesa_sha1_format(sha1buf, sh->sha1));
+                             _mesa_shader_stage_to_abbrev(sh->Stage), sha1buf);
    }
-   _mesa_sha1_compute(buf, strlen(buf), prog->data->sha1);
+   disk_cache_compute_key(cache, buf, strlen(buf), prog->data->sha1);
    ralloc_free(buf);
 
    size_t size;
@@ -1296,8 +1371,9 @@ shader_cache_read_program_metadata(struct gl_context *ctx,
    }
 
    if (ctx->_Shader->Flags & GLSL_CACHE_INFO) {
+      _mesa_sha1_format(sha1buf, prog->data->sha1);
       fprintf(stderr, "loading shader program meta data from cache: %s\n",
-              _mesa_sha1_format(sha1buf, prog->data->sha1));
+              sha1buf);
    }
 
    struct blob_reader metadata;
@@ -1351,6 +1427,23 @@ shader_cache_read_program_metadata(struct gl_context *ctx,
    /* This is used to flag a shader retrieved from cache */
    prog->data->LinkStatus = linking_skipped;
 
+   /* Since the program load was successful, CompileStatus of all shaders at
+    * this point should normally be compile_skipped. However because of how
+    * the eviction works, it may happen that some of the individual shader keys
+    * have been evicted, resulting in unnecessary recompiles on this load, so
+    * mark them again to skip such recompiles next time.
+    */
+   char sha1_buf[41];
+   for (unsigned i = 0; i < prog->NumShaders; i++) {
+      if (prog->Shaders[i]->CompileStatus == compiled_no_opts) {
+         disk_cache_put_key(cache, prog->Shaders[i]->sha1);
+         if (ctx->_Shader->Flags & GLSL_CACHE_INFO) {
+            _mesa_sha1_format(sha1_buf, prog->Shaders[i]->sha1);
+            fprintf(stderr, "re-marking shader: %s\n", sha1_buf);
+         }
+      }
+   }
+
    free (buffer);
 
    return true;