glsl: delay optimisations on individual shaders when cache is available
[mesa.git] / src / compiler / glsl / shader_cache.cpp
index b0f8e02566883369e48214f6305f863bdbbdde8e..e51fecd651851ebea231fbb62d0e4677aa494f82 100644 (file)
@@ -57,7 +57,7 @@
 #include "main/core.h"
 #include "nir.h"
 #include "program.h"
-#include "util/disk_cache.h"
+#include "shader_cache.h"
 #include "util/mesa-sha1.h"
 #include "util/string_to_uint_map.h"
 
@@ -207,6 +207,354 @@ decode_type_from_blob(struct blob_reader *blob)
    }
 }
 
+static void
+write_subroutines(struct blob *metadata, struct gl_shader_program *prog)
+{
+   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
+      struct gl_linked_shader *sh = prog->_LinkedShaders[i];
+      if (!sh)
+         continue;
+
+      struct gl_program *glprog = sh->Program;
+
+      blob_write_uint32(metadata, glprog->sh.NumSubroutineUniforms);
+      blob_write_uint32(metadata, glprog->sh.MaxSubroutineFunctionIndex);
+      blob_write_uint32(metadata, glprog->sh.NumSubroutineFunctions);
+      for (unsigned j = 0; j < glprog->sh.NumSubroutineFunctions; j++) {
+         int num_types = glprog->sh.SubroutineFunctions[j].num_compat_types;
+
+         blob_write_string(metadata, glprog->sh.SubroutineFunctions[j].name);
+         blob_write_uint32(metadata, glprog->sh.SubroutineFunctions[j].index);
+         blob_write_uint32(metadata, num_types);
+
+         for (int k = 0; k < num_types; k++) {
+            encode_type_to_blob(metadata,
+                                glprog->sh.SubroutineFunctions[j].types[k]);
+         }
+      }
+   }
+}
+
+static void
+read_subroutines(struct blob_reader *metadata, struct gl_shader_program *prog)
+{
+   struct gl_subroutine_function *subs;
+
+   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
+      struct gl_linked_shader *sh = prog->_LinkedShaders[i];
+      if (!sh)
+         continue;
+
+      struct gl_program *glprog = sh->Program;
+
+      glprog->sh.NumSubroutineUniforms = blob_read_uint32(metadata);
+      glprog->sh.MaxSubroutineFunctionIndex = blob_read_uint32(metadata);
+      glprog->sh.NumSubroutineFunctions = blob_read_uint32(metadata);
+
+      subs = rzalloc_array(prog, struct gl_subroutine_function,
+                           glprog->sh.NumSubroutineFunctions);
+      glprog->sh.SubroutineFunctions = subs;
+
+      for (unsigned j = 0; j < glprog->sh.NumSubroutineFunctions; j++) {
+         subs[j].name = ralloc_strdup(prog, blob_read_string (metadata));
+         subs[j].index = (int) blob_read_uint32(metadata);
+         subs[j].num_compat_types = (int) blob_read_uint32(metadata);
+
+         subs[j].types = rzalloc_array(prog, const struct glsl_type *,
+                                       subs[j].num_compat_types);
+         for (int k = 0; k < subs[j].num_compat_types; k++) {
+            subs[j].types[k] = decode_type_from_blob(metadata);
+         }
+      }
+   }
+}
+
+static void
+write_buffer_block(struct blob *metadata, struct gl_uniform_block *b)
+{
+   blob_write_string(metadata, b->Name);
+   blob_write_uint32(metadata, b->NumUniforms);
+   blob_write_uint32(metadata, b->Binding);
+   blob_write_uint32(metadata, b->UniformBufferSize);
+   blob_write_uint32(metadata, b->stageref);
+
+   for (unsigned j = 0; j < b->NumUniforms; j++) {
+      blob_write_string(metadata, b->Uniforms[j].Name);
+      blob_write_string(metadata, b->Uniforms[j].IndexName);
+      encode_type_to_blob(metadata, b->Uniforms[j].Type);
+      blob_write_uint32(metadata, b->Uniforms[j].Offset);
+   }
+}
+
+static void
+write_buffer_blocks(struct blob *metadata, struct gl_shader_program *prog)
+{
+   blob_write_uint32(metadata, prog->data->NumUniformBlocks);
+   blob_write_uint32(metadata, prog->data->NumShaderStorageBlocks);
+
+   for (unsigned i = 0; i < prog->data->NumUniformBlocks; i++) {
+      write_buffer_block(metadata, &prog->data->UniformBlocks[i]);
+   }
+
+   for (unsigned i = 0; i < prog->data->NumShaderStorageBlocks; i++) {
+      write_buffer_block(metadata, &prog->data->ShaderStorageBlocks[i]);
+   }
+
+   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
+      struct gl_linked_shader *sh = prog->_LinkedShaders[i];
+      if (!sh)
+         continue;
+
+      struct gl_program *glprog = sh->Program;
+
+      blob_write_uint32(metadata, glprog->info.num_ubos);
+      blob_write_uint32(metadata, glprog->info.num_ssbos);
+
+      for (unsigned j = 0; j < glprog->info.num_ubos; j++) {
+         uint32_t offset =
+            glprog->sh.UniformBlocks[j] - prog->data->UniformBlocks;
+         blob_write_uint32(metadata, offset);
+      }
+
+      for (unsigned j = 0; j < glprog->info.num_ssbos; j++) {
+         uint32_t offset = glprog->sh.ShaderStorageBlocks[j] -
+            prog->data->ShaderStorageBlocks;
+         blob_write_uint32(metadata, offset);
+      }
+   }
+}
+
+static void
+read_buffer_block(struct blob_reader *metadata, struct gl_uniform_block *b,
+                  struct gl_shader_program *prog)
+{
+      b->Name = ralloc_strdup(prog->data, blob_read_string (metadata));
+      b->NumUniforms = blob_read_uint32(metadata);
+      b->Binding = blob_read_uint32(metadata);
+      b->UniformBufferSize = blob_read_uint32(metadata);
+      b->stageref = blob_read_uint32(metadata);
+
+      b->Uniforms =
+         rzalloc_array(prog->data, struct gl_uniform_buffer_variable,
+                       b->NumUniforms);
+      for (unsigned j = 0; j < b->NumUniforms; j++) {
+         b->Uniforms[j].Name = ralloc_strdup(prog->data,
+                                             blob_read_string (metadata));
+
+         char *index_name = blob_read_string(metadata);
+         if (strcmp(b->Uniforms[j].Name, index_name) == 0) {
+            b->Uniforms[j].IndexName = b->Uniforms[j].Name;
+         } else {
+            b->Uniforms[j].IndexName = ralloc_strdup(prog->data, index_name);
+         }
+
+         b->Uniforms[j].Type = decode_type_from_blob(metadata);
+         b->Uniforms[j].Offset = blob_read_uint32(metadata);
+      }
+}
+
+static void
+read_buffer_blocks(struct blob_reader *metadata,
+                   struct gl_shader_program *prog)
+{
+   prog->data->NumUniformBlocks = blob_read_uint32(metadata);
+   prog->data->NumShaderStorageBlocks = blob_read_uint32(metadata);
+
+   prog->data->UniformBlocks =
+      rzalloc_array(prog->data, struct gl_uniform_block,
+                    prog->data->NumUniformBlocks);
+
+   prog->data->ShaderStorageBlocks =
+      rzalloc_array(prog->data, struct gl_uniform_block,
+                    prog->data->NumShaderStorageBlocks);
+
+   for (unsigned i = 0; i < prog->data->NumUniformBlocks; i++) {
+      read_buffer_block(metadata, &prog->data->UniformBlocks[i], prog);
+   }
+
+   for (unsigned i = 0; i < prog->data->NumShaderStorageBlocks; i++) {
+      read_buffer_block(metadata, &prog->data->ShaderStorageBlocks[i], prog);
+   }
+
+   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
+      struct gl_linked_shader *sh = prog->_LinkedShaders[i];
+      if (!sh)
+         continue;
+
+      struct gl_program *glprog = sh->Program;
+
+      glprog->info.num_ubos = blob_read_uint32(metadata);
+      glprog->info.num_ssbos = blob_read_uint32(metadata);
+
+      glprog->sh.UniformBlocks =
+         rzalloc_array(glprog, gl_uniform_block *, glprog->info.num_ubos);
+      glprog->sh.ShaderStorageBlocks =
+         rzalloc_array(glprog, gl_uniform_block *, glprog->info.num_ssbos);
+
+      for (unsigned j = 0; j < glprog->info.num_ubos; j++) {
+         uint32_t offset = blob_read_uint32(metadata);
+         glprog->sh.UniformBlocks[j] = prog->data->UniformBlocks + offset;
+      }
+
+      for (unsigned j = 0; j < glprog->info.num_ssbos; j++) {
+         uint32_t offset = blob_read_uint32(metadata);
+         glprog->sh.ShaderStorageBlocks[j] =
+            prog->data->ShaderStorageBlocks + offset;
+      }
+   }
+}
+
+static void
+write_atomic_buffers(struct blob *metadata, struct gl_shader_program *prog)
+{
+   blob_write_uint32(metadata, prog->data->NumAtomicBuffers);
+
+   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
+      if (prog->_LinkedShaders[i]) {
+         struct gl_program *glprog = prog->_LinkedShaders[i]->Program;
+         blob_write_uint32(metadata, glprog->info.num_abos);
+      }
+   }
+
+   for (unsigned i = 0; i < prog->data->NumAtomicBuffers; i++) {
+      blob_write_uint32(metadata, prog->data->AtomicBuffers[i].Binding);
+      blob_write_uint32(metadata, prog->data->AtomicBuffers[i].MinimumSize);
+      blob_write_uint32(metadata, prog->data->AtomicBuffers[i].NumUniforms);
+
+      blob_write_bytes(metadata, prog->data->AtomicBuffers[i].StageReferences,
+                       sizeof(prog->data->AtomicBuffers[i].StageReferences));
+
+      for (unsigned j = 0; j < prog->data->AtomicBuffers[i].NumUniforms; j++) {
+         blob_write_uint32(metadata, prog->data->AtomicBuffers[i].Uniforms[j]);
+      }
+   }
+}
+
+static void
+read_atomic_buffers(struct blob_reader *metadata,
+                     struct gl_shader_program *prog)
+{
+   prog->data->NumAtomicBuffers = blob_read_uint32(metadata);
+   prog->data->AtomicBuffers =
+      rzalloc_array(prog, gl_active_atomic_buffer,
+                    prog->data->NumAtomicBuffers);
+
+   struct gl_active_atomic_buffer **stage_buff_list[MESA_SHADER_STAGES];
+   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
+      if (prog->_LinkedShaders[i]) {
+         struct gl_program *glprog = prog->_LinkedShaders[i]->Program;
+
+         glprog->info.num_abos = blob_read_uint32(metadata);
+         glprog->sh.AtomicBuffers =
+            rzalloc_array(glprog, gl_active_atomic_buffer *,
+                          glprog->info.num_abos);
+         stage_buff_list[i] = glprog->sh.AtomicBuffers;
+      }
+   }
+
+   for (unsigned i = 0; i < prog->data->NumAtomicBuffers; i++) {
+      prog->data->AtomicBuffers[i].Binding = blob_read_uint32(metadata);
+      prog->data->AtomicBuffers[i].MinimumSize = blob_read_uint32(metadata);
+      prog->data->AtomicBuffers[i].NumUniforms = blob_read_uint32(metadata);
+
+      blob_copy_bytes(metadata,
+                      (uint8_t *) &prog->data->AtomicBuffers[i].StageReferences,
+                      sizeof(prog->data->AtomicBuffers[i].StageReferences));
+
+      prog->data->AtomicBuffers[i].Uniforms = rzalloc_array(prog, unsigned,
+         prog->data->AtomicBuffers[i].NumUniforms);
+
+      for (unsigned j = 0; j < prog->data->AtomicBuffers[i].NumUniforms; j++) {
+         prog->data->AtomicBuffers[i].Uniforms[j] = blob_read_uint32(metadata);
+      }
+
+      for (unsigned j = 0; j < MESA_SHADER_STAGES; j++) {
+         if (prog->data->AtomicBuffers[i].StageReferences[j]) {
+            *stage_buff_list[j] = &prog->data->AtomicBuffers[i];
+            stage_buff_list[j]++;
+         }
+      }
+   }
+}
+
+static void
+write_xfb(struct blob *metadata, struct gl_shader_program *shProg)
+{
+   struct gl_program *prog = shProg->last_vert_prog;
+
+   if (!prog) {
+      blob_write_uint32(metadata, ~0u);
+      return;
+   }
+
+   struct gl_transform_feedback_info *ltf = prog->sh.LinkedTransformFeedback;
+
+   blob_write_uint32(metadata, prog->info.stage);
+
+   blob_write_uint32(metadata, ltf->NumOutputs);
+   blob_write_uint32(metadata, ltf->ActiveBuffers);
+   blob_write_uint32(metadata, ltf->NumVarying);
+
+   blob_write_bytes(metadata, ltf->Outputs,
+                    sizeof(struct gl_transform_feedback_output) *
+                       ltf->NumOutputs);
+
+   for (int i = 0; i < ltf->NumVarying; i++) {
+      blob_write_string(metadata, ltf->Varyings[i].Name);
+      blob_write_uint32(metadata, ltf->Varyings[i].Type);
+      blob_write_uint32(metadata, ltf->Varyings[i].BufferIndex);
+      blob_write_uint32(metadata, ltf->Varyings[i].Size);
+      blob_write_uint32(metadata, ltf->Varyings[i].Offset);
+   }
+
+   blob_write_bytes(metadata, ltf->Buffers,
+                    sizeof(struct gl_transform_feedback_buffer) *
+                       MAX_FEEDBACK_BUFFERS);
+}
+
+static void
+read_xfb(struct blob_reader *metadata, struct gl_shader_program *shProg)
+{
+   unsigned xfb_stage = blob_read_uint32(metadata);
+
+   if (xfb_stage == ~0u)
+      return;
+
+   struct gl_program *prog = shProg->_LinkedShaders[xfb_stage]->Program;
+   struct gl_transform_feedback_info *ltf =
+      rzalloc(prog, struct gl_transform_feedback_info);
+
+   prog->sh.LinkedTransformFeedback = ltf;
+   shProg->last_vert_prog = prog;
+
+   ltf->NumOutputs = blob_read_uint32(metadata);
+   ltf->ActiveBuffers = blob_read_uint32(metadata);
+   ltf->NumVarying = blob_read_uint32(metadata);
+
+   ltf->Outputs = rzalloc_array(prog, struct gl_transform_feedback_output,
+                                ltf->NumOutputs);
+
+   blob_copy_bytes(metadata, (uint8_t *) ltf->Outputs,
+                   sizeof(struct gl_transform_feedback_output) *
+                      ltf->NumOutputs);
+
+   ltf->Varyings = rzalloc_array(prog,
+                                 struct gl_transform_feedback_varying_info,
+                                 ltf->NumVarying);
+
+   for (int i = 0; i < ltf->NumVarying; i++) {
+      ltf->Varyings[i].Name = ralloc_strdup(prog, blob_read_string(metadata));
+      ltf->Varyings[i].Type = blob_read_uint32(metadata);
+      ltf->Varyings[i].BufferIndex = blob_read_uint32(metadata);
+      ltf->Varyings[i].Size = blob_read_uint32(metadata);
+      ltf->Varyings[i].Offset = blob_read_uint32(metadata);
+   }
+
+   blob_copy_bytes(metadata, (uint8_t *) ltf->Buffers,
+                   sizeof(struct gl_transform_feedback_buffer) *
+                      MAX_FEEDBACK_BUFFERS);
+}
+
 static void
 write_uniforms(struct blob *metadata, struct gl_shader_program *prog)
 {
@@ -220,11 +568,14 @@ write_uniforms(struct blob *metadata, struct gl_shader_program *prog)
       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].matrix_stride);
       blob_write_uint32(metadata, prog->data->UniformStorage[i].row_major);
       blob_write_uint32(metadata,
@@ -233,6 +584,26 @@ write_uniforms(struct blob *metadata, struct gl_shader_program *prog)
                         prog->data->UniformStorage[i].top_level_array_size);
       blob_write_uint32(metadata,
                         prog->data->UniformStorage[i].top_level_array_stride);
+      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 (!prog->data->UniformStorage[i].builtin &&
+          !prog->data->UniformStorage[i].is_shader_storage &&
+          prog->data->UniformStorage[i].block_index == -1) {
+         unsigned vec_size =
+            values_for_type(prog->data->UniformStorage[i].type) *
+            MAX2(prog->data->UniformStorage[i].array_elements, 1);
+         blob_write_bytes(metadata, prog->data->UniformStorage[i].storage,
+                          sizeof(union gl_constant_value) * vec_size);
+      }
    }
 }
 
@@ -261,45 +632,148 @@ read_uniforms(struct blob_reader *metadata, struct gl_shader_program *prog)
       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].matrix_stride = blob_read_uint32(metadata);
       uniforms[i].row_major = 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);
+
+      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 (!prog->data->UniformStorage[i].builtin &&
+          !prog->data->UniformStorage[i].is_shader_storage &&
+          prog->data->UniformStorage[i].block_index == -1) {
+         unsigned vec_size =
+            values_for_type(prog->data->UniformStorage[i].type) *
+            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
+{
+   remap_type_inactive_explicit_location,
+   remap_type_null_ptr,
+   remap_type_uniform_offset
+};
 
 static void
-write_uniform_remap_table(struct blob *metadata,
-                          struct gl_shader_program *prog)
+write_uniform_remap_table_entry(struct blob *metadata,
+                                gl_uniform_storage *uniform_storage,
+                                gl_uniform_storage *entry)
+{
+   if (entry == INACTIVE_UNIFORM_EXPLICIT_LOCATION) {
+      blob_write_uint32(metadata, remap_type_inactive_explicit_location);
+   } else if (entry == NULL) {
+      blob_write_uint32(metadata, remap_type_null_ptr);
+   } else {
+      blob_write_uint32(metadata, remap_type_uniform_offset);
+
+      uint32_t offset = entry - uniform_storage;
+      blob_write_uint32(metadata, offset);
+   }
+}
+
+static void
+write_uniform_remap_tables(struct blob *metadata,
+                           struct gl_shader_program *prog)
 {
    blob_write_uint32(metadata, prog->NumUniformRemapTable);
 
    for (unsigned i = 0; i < prog->NumUniformRemapTable; i++) {
-      blob_write_uint32(metadata, prog->UniformRemapTable[i] -
-                           prog->data->UniformStorage);
+      write_uniform_remap_table_entry(metadata, prog->data->UniformStorage,
+                                      prog->UniformRemapTable[i]);
+   }
+
+   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
+      struct gl_linked_shader *sh = prog->_LinkedShaders[i];
+      if (sh) {
+         struct gl_program *glprog = sh->Program;
+         blob_write_uint32(metadata, glprog->sh.NumSubroutineUniformRemapTable);
+
+         for (unsigned j = 0; j < glprog->sh.NumSubroutineUniformRemapTable; j++) {
+            write_uniform_remap_table_entry(metadata,
+                                            prog->data->UniformStorage,
+                                            glprog->sh.SubroutineUniformRemapTable[j]);
+         }
+      }
    }
 }
 
 static void
-read_uniform_remap_table(struct blob_reader *metadata,
-                         struct gl_shader_program *prog)
+read_uniform_remap_table_entry(struct blob_reader *metadata,
+                               gl_uniform_storage *uniform_storage,
+                               gl_uniform_storage **entry,
+                               enum uniform_remap_type type)
+{
+   if (type == remap_type_inactive_explicit_location) {
+      *entry = INACTIVE_UNIFORM_EXPLICIT_LOCATION;
+   } else if (type == remap_type_null_ptr) {
+      *entry = NULL;
+   } else {
+      uint32_t uni_offset = blob_read_uint32(metadata);
+      *entry = uniform_storage + uni_offset;
+   }
+}
+
+static void
+read_uniform_remap_tables(struct blob_reader *metadata,
+                          struct gl_shader_program *prog)
 {
    prog->NumUniformRemapTable = blob_read_uint32(metadata);
 
-   prog->UniformRemapTable =rzalloc_array(prog, struct gl_uniform_storage *,
-                                          prog->NumUniformRemapTable);
+   prog->UniformRemapTable = rzalloc_array(prog, struct gl_uniform_storage *,
+                                           prog->NumUniformRemapTable);
 
    for (unsigned i = 0; i < prog->NumUniformRemapTable; i++) {
-      prog->UniformRemapTable[i] =
-         prog->data->UniformStorage + blob_read_uint32(metadata);
+      enum uniform_remap_type type =
+         (enum uniform_remap_type) blob_read_uint32(metadata);
+
+      read_uniform_remap_table_entry(metadata, prog->data->UniformStorage,
+                                     &prog->UniformRemapTable[i], type);
+   }
+
+   for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
+      struct gl_linked_shader *sh = prog->_LinkedShaders[i];
+      if (sh) {
+         struct gl_program *glprog = sh->Program;
+         glprog->sh.NumSubroutineUniformRemapTable = blob_read_uint32(metadata);
+
+         glprog->sh.SubroutineUniformRemapTable =
+            rzalloc_array(glprog, struct gl_uniform_storage *,
+                          glprog->sh.NumSubroutineUniformRemapTable);
+
+         for (unsigned j = 0; j < glprog->sh.NumSubroutineUniformRemapTable; j++) {
+            enum uniform_remap_type type =
+               (enum uniform_remap_type) blob_read_uint32(metadata);
+
+            read_uniform_remap_table_entry(metadata,
+                                           prog->data->UniformStorage,
+                                           &glprog->sh.SubroutineUniformRemapTable[j],
+                                           type);
+         }
+      }
    }
 }
 
@@ -373,6 +847,226 @@ read_hash_tables(struct blob_reader *metadata, struct gl_shader_program *prog)
    read_hash_table(metadata, prog->FragDataIndexBindings);
 }
 
+static void
+write_shader_subroutine_index(struct blob *metadata,
+                              struct gl_linked_shader *sh,
+                              struct gl_program_resource *res)
+{
+   assert(sh);
+
+   for (unsigned j = 0; j < sh->Program->sh.NumSubroutineFunctions; j++) {
+      if (strcmp(((gl_subroutine_function *)res->Data)->name,
+                 sh->Program->sh.SubroutineFunctions[j].name) == 0) {
+         blob_write_uint32(metadata, j);
+         break;
+      }
+   }
+}
+
+static void
+write_program_resource_data(struct blob *metadata,
+                            struct gl_shader_program *prog,
+                            struct gl_program_resource *res)
+{
+   struct gl_linked_shader *sh;
+
+   switch(res->Type) {
+   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);
+
+      if (var->interface_type)
+         encode_type_to_blob(metadata, var->interface_type);
+
+      if (var->outermost_struct_type)
+         encode_type_to_blob(metadata, var->outermost_struct_type);
+
+      blob_write_string(metadata, var->name);
+      break;
+   }
+   case GL_UNIFORM_BLOCK:
+      for (unsigned i = 0; i < prog->data->NumUniformBlocks; i++) {
+         if (strcmp(((gl_uniform_block *)res->Data)->Name,
+                    prog->data->UniformBlocks[i].Name) == 0) {
+            blob_write_uint32(metadata, i);
+            break;
+         }
+      }
+      break;
+   case GL_SHADER_STORAGE_BLOCK:
+      for (unsigned i = 0; i < prog->data->NumShaderStorageBlocks; i++) {
+         if (strcmp(((gl_uniform_block *)res->Data)->Name,
+                    prog->data->ShaderStorageBlocks[i].Name) == 0) {
+            blob_write_uint32(metadata, i);
+            break;
+         }
+      }
+      break;
+   case GL_BUFFER_VARIABLE:
+   case GL_VERTEX_SUBROUTINE_UNIFORM:
+   case GL_GEOMETRY_SUBROUTINE_UNIFORM:
+   case GL_FRAGMENT_SUBROUTINE_UNIFORM:
+   case GL_COMPUTE_SUBROUTINE_UNIFORM:
+   case GL_TESS_CONTROL_SUBROUTINE_UNIFORM:
+   case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM:
+   case GL_UNIFORM:
+      for (unsigned i = 0; i < prog->data->NumUniformStorage; i++) {
+         if (strcmp(((gl_uniform_storage *)res->Data)->name,
+                    prog->data->UniformStorage[i].name) == 0) {
+            blob_write_uint32(metadata, i);
+            break;
+         }
+      }
+      break;
+   case GL_ATOMIC_COUNTER_BUFFER:
+      for (unsigned i = 0; i < prog->data->NumAtomicBuffers; i++) {
+         if (((gl_active_atomic_buffer *)res->Data)->Binding ==
+             prog->data->AtomicBuffers[i].Binding) {
+            blob_write_uint32(metadata, i);
+            break;
+         }
+      }
+      break;
+   case GL_TRANSFORM_FEEDBACK_BUFFER:
+      for (unsigned i = 0; i < MAX_FEEDBACK_BUFFERS; i++) {
+         if (((gl_transform_feedback_buffer *)res->Data)->Binding ==
+             prog->last_vert_prog->sh.LinkedTransformFeedback->Buffers[i].Binding) {
+            blob_write_uint32(metadata, i);
+            break;
+         }
+      }
+      break;
+   case GL_TRANSFORM_FEEDBACK_VARYING:
+      for (int i = 0; i < prog->last_vert_prog->sh.LinkedTransformFeedback->NumVarying; i++) {
+         if (strcmp(((gl_transform_feedback_varying_info *)res->Data)->Name,
+                    prog->last_vert_prog->sh.LinkedTransformFeedback->Varyings[i].Name) == 0) {
+            blob_write_uint32(metadata, i);
+            break;
+         }
+      }
+      break;
+   case GL_VERTEX_SUBROUTINE:
+   case GL_TESS_CONTROL_SUBROUTINE:
+   case GL_TESS_EVALUATION_SUBROUTINE:
+   case GL_GEOMETRY_SUBROUTINE:
+   case GL_FRAGMENT_SUBROUTINE:
+   case GL_COMPUTE_SUBROUTINE:
+      sh =
+         prog->_LinkedShaders[_mesa_shader_stage_from_subroutine(res->Type)];
+      write_shader_subroutine_index(metadata, sh, res);
+      break;
+   default:
+      assert(!"Support for writing resource not yet implemented.");
+   }
+}
+
+static void
+read_program_resource_data(struct blob_reader *metadata,
+                           struct gl_shader_program *prog,
+                           struct gl_program_resource *res)
+{
+   struct gl_linked_shader *sh;
+
+   switch(res->Type) {
+   case GL_PROGRAM_INPUT:
+   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);
+
+      if (var->interface_type)
+         var->interface_type = decode_type_from_blob(metadata);
+
+      if (var->outermost_struct_type)
+         var->outermost_struct_type = decode_type_from_blob(metadata);
+
+      var->name = ralloc_strdup(prog, blob_read_string(metadata));
+
+      res->Data = var;
+      break;
+   }
+   case GL_UNIFORM_BLOCK:
+      res->Data = &prog->data->UniformBlocks[blob_read_uint32(metadata)];
+      break;
+   case GL_SHADER_STORAGE_BLOCK:
+      res->Data = &prog->data->ShaderStorageBlocks[blob_read_uint32(metadata)];
+      break;
+   case GL_BUFFER_VARIABLE:
+   case GL_VERTEX_SUBROUTINE_UNIFORM:
+   case GL_GEOMETRY_SUBROUTINE_UNIFORM:
+   case GL_FRAGMENT_SUBROUTINE_UNIFORM:
+   case GL_COMPUTE_SUBROUTINE_UNIFORM:
+   case GL_TESS_CONTROL_SUBROUTINE_UNIFORM:
+   case GL_TESS_EVALUATION_SUBROUTINE_UNIFORM:
+   case GL_UNIFORM:
+      res->Data = &prog->data->UniformStorage[blob_read_uint32(metadata)];
+      break;
+   case GL_ATOMIC_COUNTER_BUFFER:
+      res->Data = &prog->data->AtomicBuffers[blob_read_uint32(metadata)];
+      break;
+   case GL_TRANSFORM_FEEDBACK_BUFFER:
+      res->Data = &prog->last_vert_prog->
+         sh.LinkedTransformFeedback->Buffers[blob_read_uint32(metadata)];
+      break;
+   case GL_TRANSFORM_FEEDBACK_VARYING:
+      res->Data = &prog->last_vert_prog->
+         sh.LinkedTransformFeedback->Varyings[blob_read_uint32(metadata)];
+      break;
+   case GL_VERTEX_SUBROUTINE:
+   case GL_TESS_CONTROL_SUBROUTINE:
+   case GL_TESS_EVALUATION_SUBROUTINE:
+   case GL_GEOMETRY_SUBROUTINE:
+   case GL_FRAGMENT_SUBROUTINE:
+   case GL_COMPUTE_SUBROUTINE:
+      sh =
+         prog->_LinkedShaders[_mesa_shader_stage_from_subroutine(res->Type)];
+      res->Data =
+         &sh->Program->sh.SubroutineFunctions[blob_read_uint32(metadata)];
+      break;
+   default:
+      assert(!"Support for reading resource not yet implemented.");
+   }
+}
+
+static void
+write_program_resource_list(struct blob *metadata,
+                            struct gl_shader_program *prog)
+{
+   blob_write_uint32(metadata, prog->data->NumProgramResourceList);
+
+   for (unsigned i = 0; i < prog->data->NumProgramResourceList; i++) {
+      blob_write_uint32(metadata, prog->data->ProgramResourceList[i].Type);
+      write_program_resource_data(metadata, prog,
+                                  &prog->data->ProgramResourceList[i]);
+      blob_write_bytes(metadata,
+                       &prog->data->ProgramResourceList[i].StageReferences,
+                       sizeof(prog->data->ProgramResourceList[i].StageReferences));
+   }
+}
+
+static void
+read_program_resource_list(struct blob_reader *metadata,
+                           struct gl_shader_program *prog)
+{
+   prog->data->NumProgramResourceList = blob_read_uint32(metadata);
+
+   prog->data->ProgramResourceList =
+      ralloc_array(prog, gl_program_resource,
+                   prog->data->NumProgramResourceList);
+
+   for (unsigned i = 0; i < prog->data->NumProgramResourceList; i++) {
+      prog->data->ProgramResourceList[i].Type = blob_read_uint32(metadata);
+      read_program_resource_data(metadata, prog,
+                                 &prog->data->ProgramResourceList[i]);
+      blob_copy_bytes(metadata,
+                      (uint8_t *) &prog->data->ProgramResourceList[i].StageReferences,
+                      sizeof(prog->data->ProgramResourceList[i].StageReferences));
+   }
+}
+
 static void
 write_shader_parameters(struct blob *metadata,
                         struct gl_program_parameter_list *params)
@@ -407,6 +1101,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);
@@ -437,6 +1132,17 @@ write_shader_metadata(struct blob *metadata, gl_linked_shader *shader)
                     sizeof(glprog->TexturesUsed));
    blob_write_uint64(metadata, glprog->SamplersUsed);
 
+   blob_write_bytes(metadata, glprog->SamplerUnits,
+                    sizeof(glprog->SamplerUnits));
+   blob_write_bytes(metadata, glprog->sh.SamplerTargets,
+                    sizeof(glprog->sh.SamplerTargets));
+   blob_write_uint32(metadata, glprog->ShadowSamplers);
+
+   blob_write_bytes(metadata, glprog->sh.ImageAccess,
+                    sizeof(glprog->sh.ImageAccess));
+   blob_write_bytes(metadata, glprog->sh.ImageUnits,
+                    sizeof(glprog->sh.ImageUnits));
+
    write_shader_parameters(metadata, glprog->Parameters);
 }
 
@@ -449,6 +1155,17 @@ read_shader_metadata(struct blob_reader *metadata,
                    sizeof(glprog->TexturesUsed));
    glprog->SamplersUsed = blob_read_uint64(metadata);
 
+   blob_copy_bytes(metadata, (uint8_t *) glprog->SamplerUnits,
+                   sizeof(glprog->SamplerUnits));
+   blob_copy_bytes(metadata, (uint8_t *) glprog->sh.SamplerTargets,
+                   sizeof(glprog->sh.SamplerTargets));
+   glprog->ShadowSamplers = blob_read_uint32(metadata);
+
+   blob_copy_bytes(metadata, (uint8_t *) glprog->sh.ImageAccess,
+                   sizeof(glprog->sh.ImageAccess));
+   blob_copy_bytes(metadata, (uint8_t *) glprog->sh.ImageUnits,
+                   sizeof(glprog->sh.ImageUnits));
+
    glprog->Parameters = _mesa_new_parameter_list();
    read_shader_parameters(metadata, glprog->Parameters);
 }
@@ -504,10 +1221,11 @@ 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_create();
 
    write_uniforms(metadata, prog);
 
@@ -532,24 +1250,34 @@ shader_cache_write_program_metadata(struct gl_context *ctx,
       }
    }
 
-   write_uniform_remap_table(metadata, prog);
+   write_xfb(metadata, prog);
+
+   write_uniform_remap_tables(metadata, prog);
+
+   write_atomic_buffers(metadata, prog);
+
+   write_buffer_blocks(metadata, prog);
+
+   write_subroutines(metadata, prog);
+
+   write_program_resource_list(metadata, prog);
 
    char sha1_buf[41];
    for (unsigned i = 0; i < prog->NumShaders; i++) {
       disk_cache_put_key(cache, prog->Shaders[i]->sha1);
       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);
+   blob_destroy(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);
    }
 }
 
@@ -564,7 +1292,7 @@ shader_cache_read_program_metadata(struct gl_context *ctx,
       return false;
 
    struct disk_cache *cache = ctx->Cache;
-   if (!cache)
+   if (!cache || prog->data->cache_fallback)
       return false;
 
    /* Include bindings when creating sha1. These bindings change the resulting
@@ -583,14 +1311,28 @@ 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);
+
+   /* 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;
@@ -612,8 +1354,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;
@@ -635,7 +1378,17 @@ shader_cache_read_program_metadata(struct gl_context *ctx,
                                        &metadata);
    }
 
-   read_uniform_remap_table(&metadata, prog);
+   read_xfb(&metadata, prog);
+
+   read_uniform_remap_tables(&metadata, prog);
+
+   read_atomic_buffers(&metadata, prog);
+
+   read_buffer_blocks(&metadata, prog);
+
+   read_subroutines(&metadata, prog);
+
+   read_program_resource_list(&metadata, prog);
 
    if (metadata.current != metadata.end || metadata.overrun) {
       /* Something has gone wrong discard the item from the cache and rebuild
@@ -657,6 +1410,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;