Discussion:
V3 i965/Gallium ARB_get_program_binary support
Add Reply
Timothy Arceri
2017-11-29 01:24:36 UTC
Reply
Permalink
Raw Message
V3:
This is basically the V2 that Jordan sent with feedback addressed,
gallium support added, some minor functional changes such as only
storing the default uniforms to either disk or program binary cache
(rather than fixing them up later) and some refactoring to allow
greater code sharing between gallium and i965.

This series adds i965/gallium support for ARB_get_program_binary
with greater than 0 supported formats. Today we support this extension,
but advertise support for 0 formats. This series allows i965/gallium
to advertise support for 1 format.

This series defines a common Mesa format for ARB_get_program_binary,
along with helper functions to read and write the format. The binary
saved can only be reloaded on the exact same Mesa build using the
exact same hardware.

The i965/gallium implementation saves out a serialized nir/tgsi
represenation of the program. For i965 we can later add support for
saving the gen binary program as well. (We will still need the nir
program for state based recompiles.)

This implementation passes piglit, deqp and glcts functions. It also
works with (and fixes a crash in) Dead Island with makes use of the
extension.
Timothy Arceri
2017-11-29 01:24:37 UTC
Reply
Permalink
Raw Message
From: Jordan Justen <***@intel.com>

Signed-off-by: Jordan Justen <***@intel.com>
Reviewed-by: Ian Romanick <***@intel.com>
Reviewed-by: Nicolai Hähnle <***@amd.com>
Reviewed-by: Timothy Arceri <***@itsqueeze.com>
---
docs/specs/enums.txt | 3 +++
src/mapi/glapi/registry/gl.xml | 7 ++++++-
2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/docs/specs/enums.txt b/docs/specs/enums.txt
index eb4aa396c56..bf3ca9c1762 100644
--- a/docs/specs/enums.txt
+++ b/docs/specs/enums.txt
@@ -56,20 +56,23 @@ GL_MESA_program_debug: (obsolete)
GL_VERTEX_PROGRAM_CALLBACK_DATA_MESA 0x8BB7

GL_MESAX_texture_stack:
GL_TEXTURE_1D_STACK_MESAX 0x8759
GL_TEXTURE_2D_STACK_MESAX 0x875A
GL_PROXY_TEXTURE_1D_STACK_MESAX 0x875B
GL_PROXY_TEXTURE_2D_STACK_MESAX 0x875C
GL_TEXTURE_1D_STACK_BINDING_MESAX 0x875D
GL_TEXTURE_2D_STACK_BINDING_MESAX 0x875E

+GL_MESA_program_binary_formats:
+ GL_PROGRAM_BINARY_FORMAT_MESA 0x875F
+
GL_MESA_tile_raster_order
GL_TILE_RASTER_ORDER_FIXED_MESA 0x8BB8
GL_TILE_RASTER_ORDER_INCREASING_X_MESA 0x8BB9
GL_TILE_RASTER_ORDER_INCREASING_Y_MESA 0x8BBA

EGL_MESA_drm_image
EGL_DRM_BUFFER_FORMAT_MESA 0x31D0
EGL_DRM_BUFFER_USE_MESA 0x31D1
EGL_DRM_BUFFER_FORMAT_ARGB32_MESA 0x31D2
EGL_DRM_BUFFER_MESA 0x31D3
diff --git a/src/mapi/glapi/registry/gl.xml b/src/mapi/glapi/registry/gl.xml
index cbabe11b398..833478aa515 100644
--- a/src/mapi/glapi/registry/gl.xml
+++ b/src/mapi/glapi/registry/gl.xml
@@ -5498,21 +5498,21 @@ typedef unsigned int GLhandleARB;
<enum value="0x8758" name="GL_PACK_INVERT_MESA"/>
<enum value="0x8759" name="GL_DEBUG_OBJECT_MESA" comment="NOT an alias. Accidental reuse of GL_TEXTURE_1D_STACK_MESAX"/>
<enum value="0x8759" name="GL_TEXTURE_1D_STACK_MESAX"/>
<enum value="0x875A" name="GL_DEBUG_PRINT_MESA" comment="NOT an alias. Accidental reuse of GL_TEXTURE_2D_STACK_MESAX"/>
<enum value="0x875A" name="GL_TEXTURE_2D_STACK_MESAX"/>
<enum value="0x875B" name="GL_DEBUG_ASSERT_MESA" comment="NOT an alias. Accidental reuse of GL_PROXY_TEXTURE_1D_STACK_MESAX"/>
<enum value="0x875B" name="GL_PROXY_TEXTURE_1D_STACK_MESAX"/>
<enum value="0x875C" name="GL_PROXY_TEXTURE_2D_STACK_MESAX"/>
<enum value="0x875D" name="GL_TEXTURE_1D_STACK_BINDING_MESAX"/>
<enum value="0x875E" name="GL_TEXTURE_2D_STACK_BINDING_MESAX"/>
- <unused start="0x875F" vendor="MESA"/>
+ <enum value="0x875F" name="GL_PROGRAM_BINARY_FORMAT_MESA"/>
</enums>

<enums namespace="GL" start="0x8760" end="0x883F" vendor="AMD">
<enum value="0x8760" name="GL_STATIC_ATI"/>
<enum value="0x8761" name="GL_DYNAMIC_ATI"/>
<enum value="0x8762" name="GL_PRESERVE_ATI"/>
<enum value="0x8763" name="GL_DISCARD_ATI"/>
<enum value="0x8764" name="GL_BUFFER_SIZE"/>
<enum value="0x8764" name="GL_BUFFER_SIZE_ARB"/>
<enum value="0x8764" name="GL_OBJECT_BUFFER_SIZE_ATI"/>
@@ -44354,20 +44354,25 @@ typedef unsigned int GLhandleARB;
<enum name="GL_PROXY_TEXTURE_2D_STACK_MESAX"/>
<enum name="GL_TEXTURE_1D_STACK_BINDING_MESAX"/>
<enum name="GL_TEXTURE_2D_STACK_BINDING_MESAX"/>
</require>
</extension>
<extension name="GL_MESA_pack_invert" supported="gl">
<require>
<enum name="GL_PACK_INVERT_MESA"/>
</require>
</extension>
+ <extension name="GL_MESA_program_binary_formats" supported="gl|gles2">
+ <require>
+ <enum name="GL_PROGRAM_BINARY_FORMAT_MESA"/>
+ </require>
+ </extension>
<extension name="GL_MESA_resize_buffers" supported="gl">
<require>
<command name="glResizeBuffersMESA"/>
</require>
</extension>
<extension name="GL_MESA_shader_integer_functions" supported="gl|gles2"/>
<extension name="GL_MESA_window_pos" supported="gl">
<require>
<command name="glWindowPos2dMESA"/>
<command name="glWindowPos2dvMESA"/>
--
2.14.3
Timothy Arceri
2017-11-29 01:24:38 UTC
Reply
Permalink
Raw Message
From: Jordan Justen <***@intel.com>

Thus was merged into the OpenGL Registry in version
667c5a253781834b40a6ae9eb19d05af4542cfe1.

Ref: https://github.com/KhronosGroup/OpenGL-Registry/pull/127
Signed-off-by: Jordan Justen <***@intel.com>
Reviewed-by: Nicolai Hähnle <***@amd.com>
---
include/GL/glext.h | 5 +++++
include/GLES2/gl2ext.h | 5 +++++
2 files changed, 10 insertions(+)

diff --git a/include/GL/glext.h b/include/GL/glext.h
index 0ae78920e1f..75fd1f61185 100644
--- a/include/GL/glext.h
+++ b/include/GL/glext.h
@@ -9205,20 +9205,25 @@ GLAPI void APIENTRY glGetPerfQueryInfoINTEL (GLuint queryId, GLuint queryNameLen
#define GL_PROXY_TEXTURE_2D_STACK_MESAX 0x875C
#define GL_TEXTURE_1D_STACK_BINDING_MESAX 0x875D
#define GL_TEXTURE_2D_STACK_BINDING_MESAX 0x875E
#endif /* GL_MESAX_texture_stack */

#ifndef GL_MESA_pack_invert
#define GL_MESA_pack_invert 1
#define GL_PACK_INVERT_MESA 0x8758
#endif /* GL_MESA_pack_invert */

+#ifndef GL_MESA_program_binary_formats
+#define GL_MESA_program_binary_formats 1
+#define GL_PROGRAM_BINARY_FORMAT_MESA 0x875F
+#endif /* GL_MESA_program_binary_formats */
+
#ifndef GL_MESA_resize_buffers
#define GL_MESA_resize_buffers 1
typedef void (APIENTRYP PFNGLRESIZEBUFFERSMESAPROC) (void);
#ifdef GL_GLEXT_PROTOTYPES
GLAPI void APIENTRY glResizeBuffersMESA (void);
#endif
#endif /* GL_MESA_resize_buffers */

#ifndef GL_MESA_shader_integer_functions
#define GL_MESA_shader_integer_functions 1
diff --git a/include/GLES2/gl2ext.h b/include/GLES2/gl2ext.h
index cc90a6cf5d7..a7d19a1fc83 100644
--- a/include/GLES2/gl2ext.h
+++ b/include/GLES2/gl2ext.h
@@ -2327,20 +2327,25 @@ GL_APICALL void GL_APIENTRY glDeletePerfQueryINTEL (GLuint queryHandle);
GL_APICALL void GL_APIENTRY glEndPerfQueryINTEL (GLuint queryHandle);
GL_APICALL void GL_APIENTRY glGetFirstPerfQueryIdINTEL (GLuint *queryId);
GL_APICALL void GL_APIENTRY glGetNextPerfQueryIdINTEL (GLuint queryId, GLuint *nextQueryId);
GL_APICALL void GL_APIENTRY glGetPerfCounterInfoINTEL (GLuint queryId, GLuint counterId, GLuint counterNameLength, GLchar *counterName, GLuint counterDescLength, GLchar *counterDesc, GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum, GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue);
GL_APICALL void GL_APIENTRY glGetPerfQueryDataINTEL (GLuint queryHandle, GLuint flags, GLsizei dataSize, GLvoid *data, GLuint *bytesWritten);
GL_APICALL void GL_APIENTRY glGetPerfQueryIdByNameINTEL (GLchar *queryName, GLuint *queryId);
GL_APICALL void GL_APIENTRY glGetPerfQueryInfoINTEL (GLuint queryId, GLuint queryNameLength, GLchar *queryName, GLuint *dataSize, GLuint *noCounters, GLuint *noInstances, GLuint *capsMask);
#endif
#endif /* GL_INTEL_performance_query */

+#ifndef GL_MESA_program_binary_formats
+#define GL_MESA_program_binary_formats 1
+#define GL_PROGRAM_BINARY_FORMAT_MESA 0x875F
+#endif /* GL_MESA_program_binary_formats */
+
#ifndef GL_MESA_shader_integer_functions
#define GL_MESA_shader_integer_functions 1
#endif /* GL_MESA_shader_integer_functions */

#ifndef GL_NVX_blend_equation_advanced_multi_draw_buffers
#define GL_NVX_blend_equation_advanced_multi_draw_buffers 1
#endif /* GL_NVX_blend_equation_advanced_multi_draw_buffers */

#ifndef GL_NV_bindless_texture
#define GL_NV_bindless_texture 1
--
2.14.3
Timothy Arceri
2017-11-29 01:24:39 UTC
Reply
Permalink
Raw Message
From: Jordan Justen <***@intel.com>

This will allow us to use the program serialization to implement
ARB_get_program_binary.

Signed-off-by: Jordan Justen <***@intel.com>
Reviewed-by: Timothy Arceri <***@itsqueeze.com>
---
src/compiler/Makefile.sources | 2 +
src/compiler/glsl/meson.build | 2 +
src/compiler/glsl/serialize.cpp | 1238 ++++++++++++++++++++++++++++++++++++
src/compiler/glsl/serialize.h | 50 ++
src/compiler/glsl/shader_cache.cpp | 1185 +---------------------------------
src/compiler/shader_info.h | 1 +
6 files changed, 1297 insertions(+), 1181 deletions(-)
create mode 100644 src/compiler/glsl/serialize.cpp
create mode 100644 src/compiler/glsl/serialize.h

diff --git a/src/compiler/Makefile.sources b/src/compiler/Makefile.sources
index 2ab8e163a26..5338329edf6 100644
--- a/src/compiler/Makefile.sources
+++ b/src/compiler/Makefile.sources
@@ -133,20 +133,22 @@ LIBGLSL_FILES = \
glsl/opt_rebalance_tree.cpp \
glsl/opt_redundant_jumps.cpp \
glsl/opt_structure_splitting.cpp \
glsl/opt_swizzle.cpp \
glsl/opt_tree_grafting.cpp \
glsl/opt_vectorize.cpp \
glsl/program.h \
glsl/propagate_invariance.cpp \
glsl/s_expression.cpp \
glsl/s_expression.h \
+ glsl/serialize.cpp \
+ glsl/serialize.h \
glsl/string_to_uint_map.cpp \
glsl/string_to_uint_map.h

LIBGLSL_SHADER_CACHE_FILES = \
glsl/shader_cache.cpp \
glsl/shader_cache.h

# glsl_compiler

GLSL_COMPILER_CXX_FILES = \
diff --git a/src/compiler/glsl/meson.build b/src/compiler/glsl/meson.build
index 5b505c007a0..6aaa9bab05c 100644
--- a/src/compiler/glsl/meson.build
+++ b/src/compiler/glsl/meson.build
@@ -174,20 +174,22 @@ files_libglsl = files(
'opt_structure_splitting.cpp',
'opt_swizzle.cpp',
'opt_tree_grafting.cpp',
'opt_vectorize.cpp',
'program.h',
'propagate_invariance.cpp',
's_expression.cpp',
's_expression.h',
'string_to_uint_map.cpp',
'string_to_uint_map.h',
+ 'serialize.cpp',
+ 'serialize.h',
'shader_cache.cpp',
'shader_cache.h',
)

files_libglsl_standalone = files(
'ir_builder_print_visitor.cpp',
'ir_builder_print_visitor.h',
'opt_add_neg_to_sub.h',
'standalone_scaffolding.cpp',
'standalone_scaffolding.h',
diff --git a/src/compiler/glsl/serialize.cpp b/src/compiler/glsl/serialize.cpp
new file mode 100644
index 00000000000..81781f32dfd
--- /dev/null
+++ b/src/compiler/glsl/serialize.cpp
@@ -0,0 +1,1238 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file serialize.cpp
+ *
+ * GLSL serialization
+ *
+ * Supports serializing and deserializing glsl programs using a blob.
+ */
+
+#include "compiler/glsl_types.h"
+#include "compiler/shader_info.h"
+#include "ir_uniform.h"
+#include "main/mtypes.h"
+#include "string_to_uint_map.h"
+
+extern "C" {
+#include "main/shaderobj.h"
+#include "program/program.h"
+}
+
+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 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)
+{
+ blob_write_uint32(metadata, prog->SamplersValidated);
+ blob_write_uint32(metadata, prog->data->NumUniformStorage);
+ blob_write_uint32(metadata, prog->data->NumUniformDataSlots);
+
+ for (unsigned i = 0; i < prog->data->NumUniformStorage; i++) {
+ 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].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
+read_uniforms(struct blob_reader *metadata, struct gl_shader_program *prog)
+{
+ struct gl_uniform_storage *uniforms;
+ union gl_constant_value *data;
+
+ prog->SamplersValidated = blob_read_uint32(metadata);
+ prog->data->NumUniformStorage = blob_read_uint32(metadata);
+ prog->data->NumUniformDataSlots = blob_read_uint32(metadata);
+
+ uniforms = rzalloc_array(prog->data, struct gl_uniform_storage,
+ prog->data->NumUniformStorage);
+ prog->data->UniformStorage = uniforms;
+
+ data = rzalloc_array(uniforms, union gl_constant_value,
+ prog->data->NumUniformDataSlots);
+ prog->data->UniformDataSlots = data;
+
+ prog->UniformHash = new string_to_uint_map;
+
+ for (unsigned i = 0; i < prog->data->NumUniformStorage; i++) {
+ 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].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
+{
+ remap_type_inactive_explicit_location,
+ remap_type_null_ptr,
+ remap_type_uniform_offset
+};
+
+static void
+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++) {
+ 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_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);
+
+ for (unsigned i = 0; i < prog->NumUniformRemapTable; i++) {
+ 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);
+ }
+ }
+ }
+}
+
+struct whte_closure
+{
+ struct blob *blob;
+ size_t num_entries;
+};
+
+static void
+write_hash_table_entry(const char *key, unsigned value, void *closure)
+{
+ struct whte_closure *whte = (struct whte_closure *) closure;
+
+ blob_write_string(whte->blob, key);
+ blob_write_uint32(whte->blob, value);
+
+ whte->num_entries++;
+}
+
+static void
+write_hash_table(struct blob *metadata, struct string_to_uint_map *hash)
+{
+ size_t offset;
+ struct whte_closure whte;
+
+ whte.blob = metadata;
+ whte.num_entries = 0;
+
+ offset = metadata->size;
+
+ /* Write a placeholder for the hashtable size. */
+ blob_write_uint32 (metadata, 0);
+
+ hash->iterate(write_hash_table_entry, &whte);
+
+ /* Overwrite with the computed number of entries written. */
+ blob_overwrite_uint32 (metadata, offset, whte.num_entries);
+}
+
+static void
+read_hash_table(struct blob_reader *metadata, struct string_to_uint_map *hash)
+{
+ size_t i, num_entries;
+ const char *key;
+ uint32_t value;
+
+ num_entries = blob_read_uint32 (metadata);
+
+ for (i = 0; i < num_entries; i++) {
+ key = blob_read_string(metadata);
+ value = blob_read_uint32(metadata);
+
+ hash->put(value, key);
+ }
+}
+
+static void
+write_hash_tables(struct blob *metadata, struct gl_shader_program *prog)
+{
+ write_hash_table(metadata, prog->AttributeBindings);
+ write_hash_table(metadata, prog->FragDataBindings);
+ write_hash_table(metadata, prog->FragDataIndexBindings);
+}
+
+static void
+read_hash_tables(struct blob_reader *metadata, struct gl_shader_program *prog)
+{
+ read_hash_table(metadata, prog->AttributeBindings);
+ read_hash_table(metadata, prog->FragDataBindings);
+ 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
+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,
+ 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;
+
+ encode_type_to_blob(metadata, var->type);
+ encode_type_to_blob(metadata, var->interface_type);
+ encode_type_to_blob(metadata, var->outermost_struct_type);
+
+ blob_write_string(metadata, var->name);
+
+ size_t s_var_size, s_var_ptrs;
+ get_shader_var_and_pointer_sizes(&s_var_size, &s_var_ptrs, var);
+
+ /* 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:
+ 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);
+
+ var->type = decode_type_from_blob(metadata);
+ var->interface_type = decode_type_from_blob(metadata);
+ var->outermost_struct_type = decode_type_from_blob(metadata);
+
+ var->name = ralloc_strdup(prog, blob_read_string(metadata));
+
+ size_t s_var_size, s_var_ptrs;
+ get_shader_var_and_pointer_sizes(&s_var_size, &s_var_ptrs, var);
+
+ blob_copy_bytes(metadata, ((uint8_t *) var) + s_var_ptrs,
+ s_var_size - s_var_ptrs);
+
+ 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->data, 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)
+{
+ blob_write_uint32(metadata, params->NumParameters);
+ uint32_t i = 0;
+
+ while (i < params->NumParameters) {
+ struct gl_program_parameter *param = &params->Parameters[i];
+
+ blob_write_uint32(metadata, param->Type);
+ blob_write_string(metadata, param->Name);
+ blob_write_uint32(metadata, param->Size);
+ blob_write_uint32(metadata, param->DataType);
+ blob_write_bytes(metadata, param->StateIndexes,
+ sizeof(param->StateIndexes));
+
+ i += (param->Size + 3) / 4;
+ }
+
+ blob_write_bytes(metadata, params->ParameterValues,
+ sizeof(gl_constant_value) * 4 * params->NumParameters);
+
+ blob_write_uint32(metadata, params->StateFlags);
+}
+
+static void
+read_shader_parameters(struct blob_reader *metadata,
+ struct gl_program_parameter_list *params)
+{
+ gl_state_index state_indexes[STATE_LENGTH];
+ 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);
+ unsigned size = blob_read_uint32(metadata);
+ unsigned data_type = blob_read_uint32(metadata);
+ blob_copy_bytes(metadata, (uint8_t *) state_indexes,
+ sizeof(state_indexes));
+
+ _mesa_add_parameter(params, type, name, size, data_type,
+ NULL, state_indexes);
+
+ i += (size + 3) / 4;
+ }
+
+ blob_copy_bytes(metadata, (uint8_t *) params->ParameterValues,
+ sizeof(gl_constant_value) * 4 * params->NumParameters);
+
+ params->StateFlags = blob_read_uint32(metadata);
+}
+
+static void
+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));
+ 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));
+
+ 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
+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);
+
+ 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));
+
+ 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
+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,
+ struct gl_shader_program *prog,
+ struct blob_reader *metadata)
+{
+ struct gl_program *glprog;
+
+ struct gl_linked_shader *linked = rzalloc(NULL, struct gl_linked_shader);
+ linked->Stage = stage;
+
+ glprog = ctx->Driver.NewProgram(ctx, _mesa_shader_stage_to_program(stage),
+ prog->Name, false);
+ glprog->info.stage = stage;
+ linked->Program = glprog;
+
+ 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) + 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);
+ prog->_LinkedShaders[stage] = linked;
+}
+
+extern "C" void
+serialize_glsl_program(struct blob *blob, struct gl_context *ctx,
+ struct gl_shader_program *prog)
+{
+ write_uniforms(blob, prog);
+
+ write_hash_tables(blob, prog);
+
+ blob_write_uint32(blob, prog->data->Version);
+ blob_write_uint32(blob, 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(blob, sh);
+
+ if (sh->Program->info.name)
+ blob_write_string(blob, sh->Program->info.name);
+ else
+ blob_write_string(blob, "");
+
+ if (sh->Program->info.label)
+ blob_write_string(blob, sh->Program->info.label);
+ else
+ blob_write_string(blob, "");
+
+ 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(blob,
+ ((char *) &sh->Program->info) + s_info_ptrs,
+ s_info_size - s_info_ptrs);
+ }
+ }
+
+ write_xfb(blob, prog);
+
+ write_uniform_remap_tables(blob, prog);
+
+ write_atomic_buffers(blob, prog);
+
+ write_buffer_blocks(blob, prog);
+
+ write_subroutines(blob, prog);
+
+ write_program_resource_list(blob, prog);
+}
+
+extern "C" bool
+deserialize_glsl_program(struct blob_reader *blob, struct gl_context *ctx,
+ struct gl_shader_program *prog)
+{
+ /* Fixed function programs generated by Mesa can't be serialized. */
+ if (prog->Name == 0)
+ return false;
+
+ assert(prog->data->UniformStorage == NULL);
+
+ read_uniforms(blob, prog);
+
+ read_hash_tables(blob, prog);
+
+ prog->data->Version = blob_read_uint32(blob);
+ prog->data->linked_stages = blob_read_uint32(blob);
+
+ unsigned mask = prog->data->linked_stages;
+ while (mask) {
+ const int j = u_bit_scan(&mask);
+ create_linked_shader_and_program(ctx, (gl_shader_stage) j, prog,
+ blob);
+ }
+
+ read_xfb(blob, prog);
+
+ read_uniform_remap_tables(blob, prog);
+
+ read_atomic_buffers(blob, prog);
+
+ read_buffer_blocks(blob, prog);
+
+ read_subroutines(blob, prog);
+
+ read_program_resource_list(blob, prog);
+
+ return !blob->overrun;
+}
diff --git a/src/compiler/glsl/serialize.h b/src/compiler/glsl/serialize.h
new file mode 100644
index 00000000000..789e307e992
--- /dev/null
+++ b/src/compiler/glsl/serialize.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2017 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef GLSL_SERIALIZE
+#define GLSL_SERIALIZE
+
+#include <stdbool.h>
+
+struct blob;
+struct blob_reader;
+struct gl_context;
+struct gl_shader_program;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void
+serialize_glsl_program(struct blob *blob, struct gl_context *ctx,
+ struct gl_shader_program *prog);
+
+bool
+deserialize_glsl_program(struct blob_reader *blob, struct gl_context *ctx,
+ struct gl_shader_program *prog);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* GLSL_SERIALIZE */
diff --git a/src/compiler/glsl/shader_cache.cpp b/src/compiler/glsl/shader_cache.cpp
index cc63c1c3afd..5e1682b351c 100644
--- a/src/compiler/glsl/shader_cache.cpp
+++ b/src/compiler/glsl/shader_cache.cpp
@@ -37,1165 +37,57 @@
*
* In order to avoid caching any actual IR we use the put_key/get_key support
* in the disk_cache to put the SHA-1 hash for each successfully compiled
* shader into the cache, and optimisticly return early from glCompileShader
* (if the identical shader had been successfully compiled in the past),
* in the hope that the final linked shader will be found in the cache.
* If anything goes wrong (shader variant not found, backend cache item is
* corrupt, etc) we will use a fallback path to compile and link the IR.
*/

-#include "blob.h"
#include "compiler/shader_info.h"
#include "glsl_symbol_table.h"
#include "glsl_parser_extras.h"
#include "ir.h"
#include "ir_optimization.h"
#include "ir_rvalue_visitor.h"
#include "ir_uniform.h"
#include "linker.h"
#include "link_varyings.h"
#include "main/core.h"
#include "nir.h"
#include "program.h"
+#include "serialize.h"
#include "shader_cache.h"
#include "util/mesa-sha1.h"
#include "string_to_uint_map.h"

extern "C" {
#include "main/enums.h"
#include "main/shaderobj.h"
#include "program/program.h"
}

static void
compile_shaders(struct gl_context *ctx, struct gl_shader_program *prog) {
for (unsigned i = 0; i < prog->NumShaders; i++) {
_mesa_glsl_compile_shader(ctx, prog->Shaders[i], false, false, true);
}
}

-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 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)
-{
- blob_write_uint32(metadata, prog->SamplersValidated);
- blob_write_uint32(metadata, prog->data->NumUniformStorage);
- blob_write_uint32(metadata, prog->data->NumUniformDataSlots);
-
- for (unsigned i = 0; i < prog->data->NumUniformStorage; i++) {
- 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].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
-read_uniforms(struct blob_reader *metadata, struct gl_shader_program *prog)
-{
- struct gl_uniform_storage *uniforms;
- union gl_constant_value *data;
-
- prog->SamplersValidated = blob_read_uint32(metadata);
- prog->data->NumUniformStorage = blob_read_uint32(metadata);
- prog->data->NumUniformDataSlots = blob_read_uint32(metadata);
-
- uniforms = rzalloc_array(prog->data, struct gl_uniform_storage,
- prog->data->NumUniformStorage);
- prog->data->UniformStorage = uniforms;
-
- data = rzalloc_array(uniforms, union gl_constant_value,
- prog->data->NumUniformDataSlots);
- prog->data->UniformDataSlots = data;
-
- prog->UniformHash = new string_to_uint_map;
-
- for (unsigned i = 0; i < prog->data->NumUniformStorage; i++) {
- 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].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
-{
- remap_type_inactive_explicit_location,
- remap_type_null_ptr,
- remap_type_uniform_offset
-};
-
-static void
-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++) {
- 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_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);
-
- for (unsigned i = 0; i < prog->NumUniformRemapTable; i++) {
- 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);
- }
- }
- }
-}
-
-struct whte_closure
-{
- struct blob *blob;
- size_t num_entries;
-};
-
-static void
-write_hash_table_entry(const char *key, unsigned value, void *closure)
-{
- struct whte_closure *whte = (struct whte_closure *) closure;
-
- blob_write_string(whte->blob, key);
- blob_write_uint32(whte->blob, value);
-
- whte->num_entries++;
-}
-
-static void
-write_hash_table(struct blob *metadata, struct string_to_uint_map *hash)
-{
- size_t offset;
- struct whte_closure whte;
-
- whte.blob = metadata;
- whte.num_entries = 0;
-
- offset = metadata->size;
-
- /* Write a placeholder for the hashtable size. */
- blob_write_uint32 (metadata, 0);
-
- hash->iterate(write_hash_table_entry, &whte);
-
- /* Overwrite with the computed number of entries written. */
- blob_overwrite_uint32 (metadata, offset, whte.num_entries);
-}
-
-static void
-read_hash_table(struct blob_reader *metadata, struct string_to_uint_map *hash)
-{
- size_t i, num_entries;
- const char *key;
- uint32_t value;
-
- num_entries = blob_read_uint32 (metadata);
-
- for (i = 0; i < num_entries; i++) {
- key = blob_read_string(metadata);
- value = blob_read_uint32(metadata);
-
- hash->put(value, key);
- }
-}
-
-static void
-write_hash_tables(struct blob *metadata, struct gl_shader_program *prog)
-{
- write_hash_table(metadata, prog->AttributeBindings);
- write_hash_table(metadata, prog->FragDataBindings);
- write_hash_table(metadata, prog->FragDataIndexBindings);
-}
-
-static void
-read_hash_tables(struct blob_reader *metadata, struct gl_shader_program *prog)
-{
- read_hash_table(metadata, prog->AttributeBindings);
- read_hash_table(metadata, prog->FragDataBindings);
- 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
-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,
- 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;
-
- encode_type_to_blob(metadata, var->type);
- encode_type_to_blob(metadata, var->interface_type);
- encode_type_to_blob(metadata, var->outermost_struct_type);
-
- blob_write_string(metadata, var->name);
-
- size_t s_var_size, s_var_ptrs;
- get_shader_var_and_pointer_sizes(&s_var_size, &s_var_ptrs, var);
-
- /* 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:
- 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);
-
- var->type = decode_type_from_blob(metadata);
- var->interface_type = decode_type_from_blob(metadata);
- var->outermost_struct_type = decode_type_from_blob(metadata);
-
- var->name = ralloc_strdup(prog, blob_read_string(metadata));
-
- size_t s_var_size, s_var_ptrs;
- get_shader_var_and_pointer_sizes(&s_var_size, &s_var_ptrs, var);
-
- blob_copy_bytes(metadata, ((uint8_t *) var) + s_var_ptrs,
- s_var_size - s_var_ptrs);
-
- 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->data, 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)
-{
- blob_write_uint32(metadata, params->NumParameters);
- uint32_t i = 0;
-
- while (i < params->NumParameters) {
- struct gl_program_parameter *param = &params->Parameters[i];
-
- blob_write_uint32(metadata, param->Type);
- blob_write_string(metadata, param->Name);
- blob_write_uint32(metadata, param->Size);
- blob_write_uint32(metadata, param->DataType);
- blob_write_bytes(metadata, param->StateIndexes,
- sizeof(param->StateIndexes));
-
- i += (param->Size + 3) / 4;
- }
-
- blob_write_bytes(metadata, params->ParameterValues,
- sizeof(gl_constant_value) * 4 * params->NumParameters);
-
- blob_write_uint32(metadata, params->StateFlags);
-}
-
-static void
-read_shader_parameters(struct blob_reader *metadata,
- struct gl_program_parameter_list *params)
-{
- gl_state_index state_indexes[STATE_LENGTH];
- 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);
- unsigned size = blob_read_uint32(metadata);
- unsigned data_type = blob_read_uint32(metadata);
- blob_copy_bytes(metadata, (uint8_t *) state_indexes,
- sizeof(state_indexes));
-
- _mesa_add_parameter(params, type, name, size, data_type,
- NULL, state_indexes);
-
- i += (size + 3) / 4;
- }
-
- blob_copy_bytes(metadata, (uint8_t *) params->ParameterValues,
- sizeof(gl_constant_value) * 4 * params->NumParameters);
-
- params->StateFlags = blob_read_uint32(metadata);
-}
-
-static void
-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));
- 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));
-
- 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
-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);
-
- 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));
-
- 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
create_binding_str(const char *key, unsigned value, void *closure)
{
char **bindings_str = (char **) 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,
- struct gl_shader_program *prog,
- struct blob_reader *metadata)
-{
- struct gl_program *glprog;
-
- struct gl_linked_shader *linked = rzalloc(NULL, struct gl_linked_shader);
- linked->Stage = stage;
-
- glprog = ctx->Driver.NewProgram(ctx, _mesa_shader_stage_to_program(stage),
- prog->Name, false);
- glprog->info.stage = stage;
- linked->Program = glprog;
-
- 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) + 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);
- prog->_LinkedShaders[stage] = linked;
-}
-
void
shader_cache_write_program_metadata(struct gl_context *ctx,
struct gl_shader_program *prog)
{
struct disk_cache *cache = ctx->Cache;
if (!cache)
return;

/* Exit early when we are dealing with a ff shader with no source file to
* generate a source from.
@@ -1203,64 +95,21 @@ shader_cache_write_program_metadata(struct gl_context *ctx,
* TODO: In future we should use another method to generate a key for ff
* programs.
*/
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_init(&metadata);

- write_uniforms(&metadata, prog);
-
- write_hash_tables(&metadata, prog);
-
- 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);
-
- if (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);
- 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_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);
+ serialize_glsl_program(&metadata, ctx, 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;

@@ -1372,49 +221,23 @@ 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",
sha1buf);
}

struct blob_reader metadata;
blob_reader_init(&metadata, buffer, size);

- assert(prog->data->UniformStorage == NULL);
-
- read_uniforms(&metadata, prog);
-
- read_hash_tables(&metadata, prog);
-
- prog->data->Version = blob_read_uint32(&metadata);
- prog->data->linked_stages = blob_read_uint32(&metadata);
-
- unsigned mask = prog->data->linked_stages;
- while (mask) {
- const int j = u_bit_scan(&mask);
- create_linked_shader_and_program(ctx, (gl_shader_stage) j, prog,
- &metadata);
- }
-
- 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);
+ bool deserialized = deserialize_glsl_program(&metadata, ctx, prog);

- if (metadata.current != metadata.end || metadata.overrun) {
+ if (!deserialized || metadata.current != metadata.end || metadata.overrun) {
/* Something has gone wrong discard the item from the cache and rebuild
* from source.
*/
assert(!"Invalid GLSL shader disk cache item!");

if (ctx->_Shader->Flags & GLSL_CACHE_INFO) {
fprintf(stderr, "Error reading program from cache (invalid GLSL "
"cache item)\n");
}

diff --git a/src/compiler/shader_info.h b/src/compiler/shader_info.h
index bcb3f0fffac..812b2473042 100644
--- a/src/compiler/shader_info.h
+++ b/src/compiler/shader_info.h
@@ -19,20 +19,21 @@
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/

#ifndef SHADER_INFO_H
#define SHADER_INFO_H

#include "shader_enums.h"
+#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef struct shader_info {
const char *name;

/* Descriptive name provided by the client; may be NULL */
const char *label;
--
2.14.3
Timothy Arceri
2017-11-29 01:24:40 UTC
Reply
Permalink
Raw Message
From: Jordan Justen <***@intel.com>

The ARB_get_program_binary extension requires that uniform values in a
program be restored to their initial value just after linking.

This patch saves off the initial values just after linking. When the
program is restored by glProgramBinary, we can use this to copy the
initial value of uniforms into UniformDataSlots.

V2 (Timothy Arceri):
- Store UniformDataDefaults only when serializing GLSL as this
is what we want for both disk cache and ARB_get_program_binary.
This saves us having to come back later and reset the Uniforms
on program binary restores.

Signed-off-by: Timothy Arceri <***@itsqueeze.com>
Signed-off-by: Jordan Justen <***@intel.com> (v1)
---
src/compiler/glsl/link_uniform_initializers.cpp | 2 ++
src/compiler/glsl/link_uniforms.cpp | 3 +++
src/compiler/glsl/serialize.cpp | 16 ++++++++++++++--
src/mesa/main/mtypes.h | 11 +++++++++++
4 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/src/compiler/glsl/link_uniform_initializers.cpp b/src/compiler/glsl/link_uniform_initializers.cpp
index f70d9100e12..2395f5cf695 100644
--- a/src/compiler/glsl/link_uniform_initializers.cpp
+++ b/src/compiler/glsl/link_uniform_initializers.cpp
@@ -347,12 +347,14 @@ link_set_uniform_initializers(struct gl_shader_program *prog,
assert(!"Explicit binding not on a sampler, UBO or atomic.");
}
} else if (var->constant_initializer) {
linker::set_uniform_initializer(mem_ctx, prog, var->name,
var->type, var->constant_initializer,
boolean_true);
}
}
}

+ memcpy(prog->data->UniformDataDefaults, prog->data->UniformDataSlots,
+ sizeof(union gl_constant_value) * prog->data->NumUniformDataSlots);
ralloc_free(mem_ctx);
}
diff --git a/src/compiler/glsl/link_uniforms.cpp b/src/compiler/glsl/link_uniforms.cpp
index 46c746bc701..15813cb0aed 100644
--- a/src/compiler/glsl/link_uniforms.cpp
+++ b/src/compiler/glsl/link_uniforms.cpp
@@ -1358,20 +1358,23 @@ link_assign_uniform_storage(struct gl_context *ctx,

unsigned int boolean_true = ctx->Const.UniformBooleanTrue;

union gl_constant_value *data;
if (prog->data->UniformStorage == NULL) {
prog->data->UniformStorage = rzalloc_array(prog->data,
struct gl_uniform_storage,
prog->data->NumUniformStorage);
data = rzalloc_array(prog->data->UniformStorage,
union gl_constant_value, num_data_slots);
+ prog->data->UniformDataDefaults =
+ rzalloc_array(prog->data->UniformStorage,
+ union gl_constant_value, num_data_slots);
} else {
data = prog->data->UniformDataSlots;
}

#ifndef NDEBUG
union gl_constant_value *data_end = &data[num_data_slots];
#endif

parcel_out_uniform_storage parcel(prog, prog->UniformHash,
prog->data->UniformStorage, data,
diff --git a/src/compiler/glsl/serialize.cpp b/src/compiler/glsl/serialize.cpp
index 81781f32dfd..529b74e2002 100644
--- a/src/compiler/glsl/serialize.cpp
+++ b/src/compiler/glsl/serialize.cpp
@@ -442,21 +442,24 @@ write_uniforms(struct blob *metadata, struct gl_shader_program *prog)
* 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,
+ unsigned slot =
+ prog->data->UniformStorage[i].storage -
+ prog->data->UniformDataSlots;
+ blob_write_bytes(metadata, &prog->data->UniformDataDefaults[slot],
sizeof(union gl_constant_value) * vec_size);
}
}
}

static void
read_uniforms(struct blob_reader *metadata, struct gl_shader_program *prog)
{
struct gl_uniform_storage *uniforms;
union gl_constant_value *data;
@@ -465,20 +468,23 @@ read_uniforms(struct blob_reader *metadata, struct gl_shader_program *prog)
prog->data->NumUniformStorage = blob_read_uint32(metadata);
prog->data->NumUniformDataSlots = blob_read_uint32(metadata);

uniforms = rzalloc_array(prog->data, struct gl_uniform_storage,
prog->data->NumUniformStorage);
prog->data->UniformStorage = uniforms;

data = rzalloc_array(uniforms, union gl_constant_value,
prog->data->NumUniformDataSlots);
prog->data->UniformDataSlots = data;
+ prog->data->UniformDataDefaults =
+ rzalloc_array(uniforms, union gl_constant_value,
+ prog->data->NumUniformDataSlots);

prog->UniformHash = new string_to_uint_map;

for (unsigned i = 0; i < prog->data->NumUniformStorage; i++) {
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].builtin = blob_read_uint32(metadata);
uniforms[i].remap_location = blob_read_uint32(metadata);
uniforms[i].block_index = blob_read_uint32(metadata);
@@ -505,28 +511,34 @@ read_uniforms(struct blob_reader *metadata, struct gl_shader_program *prog)
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);
+ unsigned slot =
+ prog->data->UniformStorage[i].storage -
+ prog->data->UniformDataSlots;
blob_copy_bytes(metadata,
- (uint8_t *) prog->data->UniformStorage[i].storage,
+ (uint8_t *) &prog->data->UniformDataSlots[slot],
sizeof(union gl_constant_value) * vec_size);

assert(vec_size + prog->data->UniformStorage[i].storage <=
data + prog->data->NumUniformDataSlots);
}
}
+
+ memcpy(prog->data->UniformDataDefaults, prog->data->UniformDataSlots,
+ sizeof(union gl_constant_value) * prog->data->NumUniformDataSlots);
}

enum uniform_remap_type
{
remap_type_inactive_explicit_location,
remap_type_null_ptr,
remap_type_uniform_offset
};

static void
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index 96775824ea6..548cf944aa8 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -2880,20 +2880,31 @@ struct gl_shader_program_data
struct gl_uniform_block *UniformBlocks;
struct gl_uniform_block *ShaderStorageBlocks;

struct gl_active_atomic_buffer *AtomicBuffers;
unsigned NumAtomicBuffers;

/* Shader cache variables used during restore */
unsigned NumUniformDataSlots;
union gl_constant_value *UniformDataSlots;

+ /* Used to hold initial uniform values for program binary restores.
+ *
+ * From the ARB_get_program_binary spec:
+ *
+ * "A successful call to ProgramBinary will reset all uniform
+ * variables to their initial values. The initial value is either
+ * the value of the variable's initializer as specified in the
+ * original shader source, or 0 if no initializer was present.
+ */
+ union gl_constant_value *UniformDataDefaults;
+
GLboolean Validated;

/** List of all active resources after linking. */
struct gl_program_resource *ProgramResourceList;
unsigned NumProgramResourceList;

enum gl_link_status LinkStatus; /**< GL_LINK_STATUS */
GLchar *InfoLog;

unsigned Version; /**< GLSL version used for linking */
--
2.14.3
Tapani Pälli
2017-12-07 12:14:48 UTC
Reply
Permalink
Raw Message
Post by Timothy Arceri
The ARB_get_program_binary extension requires that uniform values in a
program be restored to their initial value just after linking.
This patch saves off the initial values just after linking. When the
program is restored by glProgramBinary, we can use this to copy the
initial value of uniforms into UniformDataSlots.
- Store UniformDataDefaults only when serializing GLSL as this
is what we want for both disk cache and ARB_get_program_binary.
This saves us having to come back later and reset the Uniforms
on program binary restores.
---
src/compiler/glsl/link_uniform_initializers.cpp | 2 ++
src/compiler/glsl/link_uniforms.cpp | 3 +++
src/compiler/glsl/serialize.cpp | 16 ++++++++++++++--
src/mesa/main/mtypes.h | 11 +++++++++++
4 files changed, 30 insertions(+), 2 deletions(-)
diff --git a/src/compiler/glsl/link_uniform_initializers.cpp b/src/compiler/glsl/link_uniform_initializers.cpp
index f70d9100e12..2395f5cf695 100644
--- a/src/compiler/glsl/link_uniform_initializers.cpp
+++ b/src/compiler/glsl/link_uniform_initializers.cpp
@@ -347,12 +347,14 @@ link_set_uniform_initializers(struct gl_shader_program *prog,
assert(!"Explicit binding not on a sampler, UBO or atomic.");
}
} else if (var->constant_initializer) {
linker::set_uniform_initializer(mem_ctx, prog, var->name,
var->type, var->constant_initializer,
boolean_true);
}
}
}
+ memcpy(prog->data->UniformDataDefaults, prog->data->UniformDataSlots,
+ sizeof(union gl_constant_value) * prog->data->NumUniformDataSlots);
ralloc_free(mem_ctx);
}
diff --git a/src/compiler/glsl/link_uniforms.cpp b/src/compiler/glsl/link_uniforms.cpp
index 46c746bc701..15813cb0aed 100644
--- a/src/compiler/glsl/link_uniforms.cpp
+++ b/src/compiler/glsl/link_uniforms.cpp
@@ -1358,20 +1358,23 @@ link_assign_uniform_storage(struct gl_context *ctx,
unsigned int boolean_true = ctx->Const.UniformBooleanTrue;
union gl_constant_value *data;
if (prog->data->UniformStorage == NULL) {
prog->data->UniformStorage = rzalloc_array(prog->data,
struct gl_uniform_storage,
prog->data->NumUniformStorage);
data = rzalloc_array(prog->data->UniformStorage,
union gl_constant_value, num_data_slots);
+ prog->data->UniformDataDefaults =
+ rzalloc_array(prog->data->UniformStorage,
+ union gl_constant_value, num_data_slots);
} else {
data = prog->data->UniformDataSlots;
}
#ifndef NDEBUG
union gl_constant_value *data_end = &data[num_data_slots];
#endif
parcel_out_uniform_storage parcel(prog, prog->UniformHash,
prog->data->UniformStorage, data,
diff --git a/src/compiler/glsl/serialize.cpp b/src/compiler/glsl/serialize.cpp
index 81781f32dfd..529b74e2002 100644
--- a/src/compiler/glsl/serialize.cpp
+++ b/src/compiler/glsl/serialize.cpp
@@ -442,21 +442,24 @@ write_uniforms(struct blob *metadata, struct gl_shader_program *prog)
* 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,
+ unsigned slot =
+ prog->data->UniformStorage[i].storage -
+ prog->data->UniformDataSlots;
+ blob_write_bytes(metadata, &prog->data->UniformDataDefaults[slot],
sizeof(union gl_constant_value) * vec_size);
}
}
}
static void
read_uniforms(struct blob_reader *metadata, struct gl_shader_program *prog)
{
struct gl_uniform_storage *uniforms;
union gl_constant_value *data;
@@ -465,20 +468,23 @@ read_uniforms(struct blob_reader *metadata, struct gl_shader_program *prog)
prog->data->NumUniformStorage = blob_read_uint32(metadata);
prog->data->NumUniformDataSlots = blob_read_uint32(metadata);
uniforms = rzalloc_array(prog->data, struct gl_uniform_storage,
prog->data->NumUniformStorage);
prog->data->UniformStorage = uniforms;
data = rzalloc_array(uniforms, union gl_constant_value,
prog->data->NumUniformDataSlots);
prog->data->UniformDataSlots = data;
+ prog->data->UniformDataDefaults =
+ rzalloc_array(uniforms, union gl_constant_value,
+ prog->data->NumUniformDataSlots);
prog->UniformHash = new string_to_uint_map;
for (unsigned i = 0; i < prog->data->NumUniformStorage; i++) {
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].builtin = blob_read_uint32(metadata);
uniforms[i].remap_location = blob_read_uint32(metadata);
uniforms[i].block_index = blob_read_uint32(metadata);
@@ -505,28 +511,34 @@ read_uniforms(struct blob_reader *metadata, struct gl_shader_program *prog)
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);
+ unsigned slot =
+ prog->data->UniformStorage[i].storage -
+ prog->data->UniformDataSlots;
blob_copy_bytes(metadata,
- (uint8_t *) prog->data->UniformStorage[i].storage,
+ (uint8_t *) &prog->data->UniformDataSlots[slot],
sizeof(union gl_constant_value) * vec_size);
assert(vec_size + prog->data->UniformStorage[i].storage <=
data + prog->data->NumUniformDataSlots);
}
}
+
+ memcpy(prog->data->UniformDataDefaults, prog->data->UniformDataSlots,
+ sizeof(union gl_constant_value) * prog->data->NumUniformDataSlots);
}
enum uniform_remap_type
{
remap_type_inactive_explicit_location,
remap_type_null_ptr,
remap_type_uniform_offset
};
static void
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index 96775824ea6..548cf944aa8 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -2880,20 +2880,31 @@ struct gl_shader_program_data
struct gl_uniform_block *UniformBlocks;
struct gl_uniform_block *ShaderStorageBlocks;
struct gl_active_atomic_buffer *AtomicBuffers;
unsigned NumAtomicBuffers;
/* Shader cache variables used during restore */
unsigned NumUniformDataSlots;
union gl_constant_value *UniformDataSlots;
+ /* Used to hold initial uniform values for program binary restores.
+ *
+ *
+ * "A successful call to ProgramBinary will reset all uniform
+ * variables to their initial values. The initial value is either
+ * the value of the variable's initializer as specified in the
+ * original shader source, or 0 if no initializer was present.
+ */
+ union gl_constant_value *UniformDataDefaults;
+
GLboolean Validated;
/** List of all active resources after linking. */
struct gl_program_resource *ProgramResourceList;
unsigned NumProgramResourceList;
enum gl_link_status LinkStatus; /**< GL_LINK_STATUS */
GLchar *InfoLog;
unsigned Version; /**< GLSL version used for linking */
Timothy Arceri
2017-11-29 01:24:42 UTC
Reply
Permalink
Raw Message
From: Jordan Justen <***@intel.com>

Signed-off-by: Jordan Justen <***@intel.com>
Reviewed-by: Timothy Arceri <***@itsqueeze.com>
---
src/mesa/drivers/dri/i965/brw_program.c | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/src/mesa/drivers/dri/i965/brw_program.c b/src/mesa/drivers/dri/i965/brw_program.c
index 2a647cdd734..30cc14e88a2 100644
--- a/src/mesa/drivers/dri/i965/brw_program.c
+++ b/src/mesa/drivers/dri/i965/brw_program.c
@@ -793,11 +793,17 @@ brw_program_deserialize_nir(struct gl_context *ctx, struct gl_program *prog,
{
if (!prog->nir) {
assert(prog->driver_cache_blob && prog->driver_cache_blob_size > 0);
const struct nir_shader_compiler_options *options =
ctx->Const.ShaderCompilerOptions[stage].NirOptions;
struct blob_reader reader;
blob_reader_init(&reader, prog->driver_cache_blob,
prog->driver_cache_blob_size);
prog->nir = nir_deserialize(NULL, options, &reader);
}
+
+ if (prog->driver_cache_blob) {
+ ralloc_free(prog->driver_cache_blob);
+ prog->driver_cache_blob = NULL;
+ prog->driver_cache_blob_size = 0;
+ }
}
--
2.14.3
Timothy Arceri
2017-11-29 01:24:41 UTC
Reply
Permalink
Raw Message
From: Jordan Justen <***@intel.com>

Signed-off-by: Jordan Justen <***@intel.com>
Reviewed-by: Timothy Arceri <***@itsqueeze.com>
---
src/mesa/drivers/dri/i965/brw_disk_cache.c | 31 ++++++++----------------------
src/mesa/drivers/dri/i965/brw_program.c | 16 +++++++++++++++
src/mesa/drivers/dri/i965/brw_program.h | 4 ++++
3 files changed, 28 insertions(+), 23 deletions(-)

diff --git a/src/mesa/drivers/dri/i965/brw_disk_cache.c b/src/mesa/drivers/dri/i965/brw_disk_cache.c
index 853ea98af03..65bb52726eb 100644
--- a/src/mesa/drivers/dri/i965/brw_disk_cache.c
+++ b/src/mesa/drivers/dri/i965/brw_disk_cache.c
@@ -17,21 +17,20 @@
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/

#include "compiler/blob.h"
#include "compiler/glsl/ir_uniform.h"
#include "compiler/glsl/shader_cache.h"
-#include "compiler/nir/nir_serialize.h"
#include "main/mtypes.h"
#include "util/build_id.h"
#include "util/debug.h"
#include "util/disk_cache.h"
#include "util/macros.h"
#include "util/mesa-sha1.h"

#include "brw_context.h"
#include "brw_program.h"
#include "brw_cs.h"
@@ -54,41 +53,20 @@ gen_shader_sha1(struct brw_context *brw, struct gl_program *prog,

_mesa_sha1_compute(key, brw_prog_key_size(stage), sha1);
_mesa_sha1_format(sha1_buf, sha1);
offset += snprintf(manifest + offset, sizeof(manifest) - offset,
"%s_key: %s\n", _mesa_shader_stage_to_abbrev(stage),
sha1_buf);

_mesa_sha1_compute(manifest, strlen(manifest), out_sha1);
}

-static void
-restore_serialized_nir_shader(struct brw_context *brw, struct gl_program *prog,
- gl_shader_stage stage)
-{
- prog->program_written_to_cache = false;
- if (brw->ctx._Shader->Flags & GLSL_CACHE_INFO) {
- fprintf(stderr, "falling back to nir %s.\n",
- _mesa_shader_stage_to_abbrev(prog->info.stage));
- }
-
- if (!prog->nir) {
- assert(prog->driver_cache_blob && prog->driver_cache_blob_size > 0);
- const struct nir_shader_compiler_options *options =
- brw->ctx.Const.ShaderCompilerOptions[stage].NirOptions;
- struct blob_reader reader;
- blob_reader_init(&reader, prog->driver_cache_blob,
- prog->driver_cache_blob_size);
- prog->nir = nir_deserialize(NULL, options, &reader);
- }
-}
-
static void
write_blob_program_data(struct blob *binary, gl_shader_stage stage,
const void *program,
struct brw_stage_prog_data *prog_data)
{
/* Write prog_data to blob. */
blob_write_bytes(binary, prog_data, brw_prog_data_size(stage));

/* Write program to blob. */
blob_write_bytes(binary, program, prog_data->program_size);
@@ -291,21 +269,28 @@ brw_disk_cache_upload_program(struct brw_context *brw, gl_shader_stage stage)
if (!read_and_upload(brw, cache, prog, stage))
goto fail;

if (brw->ctx._Shader->Flags & GLSL_CACHE_INFO) {
fprintf(stderr, "read gen program from cache\n");
}

return true;

fail:
- restore_serialized_nir_shader(brw, prog, stage);
+ prog->program_written_to_cache = false;
+ if (brw->ctx._Shader->Flags & GLSL_CACHE_INFO) {
+ fprintf(stderr, "falling back to nir %s.\n",
+ _mesa_shader_stage_to_abbrev(prog->info.stage));
+ }
+
+ brw_program_deserialize_nir(&brw->ctx, prog, stage);
+
return false;
}

static void
write_program_data(struct brw_context *brw, struct gl_program *prog,
void *key, struct brw_stage_prog_data *prog_data,
uint32_t prog_offset, struct disk_cache *cache,
gl_shader_stage stage)
{
struct blob binary;
diff --git a/src/mesa/drivers/dri/i965/brw_program.c b/src/mesa/drivers/dri/i965/brw_program.c
index 755d4973cc0..2a647cdd734 100644
--- a/src/mesa/drivers/dri/i965/brw_program.c
+++ b/src/mesa/drivers/dri/i965/brw_program.c
@@ -33,20 +33,21 @@
#include "main/imports.h"
#include "program/prog_parameter.h"
#include "program/prog_print.h"
#include "program/prog_to_nir.h"
#include "program/program.h"
#include "program/programopt.h"
#include "tnl/tnl.h"
#include "util/ralloc.h"
#include "compiler/glsl/ir.h"
#include "compiler/glsl/glsl_to_nir.h"
+#include "compiler/nir/nir_serialize.h"

#include "brw_program.h"
#include "brw_context.h"
#include "compiler/brw_nir.h"
#include "brw_defines.h"
#include "intel_batchbuffer.h"

static bool
brw_nir_lower_uniforms(nir_shader *nir, bool is_scalar)
{
@@ -778,10 +779,25 @@ brw_assign_common_binding_table_offsets(const struct gen_device_info *devinfo,
next_binding_table_offset += num_textures;

stage_prog_data->binding_table.plane_start[2] = next_binding_table_offset;
next_binding_table_offset += num_textures;

/* prog_data->base.binding_table.size will be set by brw_mark_surface_used. */

assert(next_binding_table_offset <= BRW_MAX_SURFACES);
return next_binding_table_offset;
}
+
+void
+brw_program_deserialize_nir(struct gl_context *ctx, struct gl_program *prog,
+ gl_shader_stage stage)
+{
+ if (!prog->nir) {
+ assert(prog->driver_cache_blob && prog->driver_cache_blob_size > 0);
+ const struct nir_shader_compiler_options *options =
+ ctx->Const.ShaderCompilerOptions[stage].NirOptions;
+ struct blob_reader reader;
+ blob_reader_init(&reader, prog->driver_cache_blob,
+ prog->driver_cache_blob_size);
+ prog->nir = nir_deserialize(NULL, options, &reader);
+ }
+}
diff --git a/src/mesa/drivers/dri/i965/brw_program.h b/src/mesa/drivers/dri/i965/brw_program.h
index 701b8da482e..bd9b4ad168a 100644
--- a/src/mesa/drivers/dri/i965/brw_program.h
+++ b/src/mesa/drivers/dri/i965/brw_program.h
@@ -74,20 +74,24 @@ void brw_populate_sampler_prog_key_data(struct gl_context *ctx,
bool brw_debug_recompile_sampler_key(struct brw_context *brw,
const struct brw_sampler_prog_key_data *old_key,
const struct brw_sampler_prog_key_data *key);

uint32_t
brw_assign_common_binding_table_offsets(const struct gen_device_info *devinfo,
const struct gl_program *prog,
struct brw_stage_prog_data *stage_prog_data,
uint32_t next_binding_table_offset);

+void
+brw_program_deserialize_nir(struct gl_context *ctx, struct gl_program *prog,
+ gl_shader_stage stage);
+
void
brw_stage_prog_data_free(const void *prog_data);

void
brw_dump_arb_asm(const char *stage, struct gl_program *prog);

bool brw_vs_precompile(struct gl_context *ctx, struct gl_program *prog);
bool brw_tcs_precompile(struct gl_context *ctx,
struct gl_shader_program *shader_prog,
struct gl_program *prog);
--
2.14.3
Timothy Arceri
2017-11-29 01:24:45 UTC
Reply
Permalink
Raw Message
From: Jordan Justen <***@intel.com>

Signed-off-by: Jordan Justen <***@intel.com>
Reviewed-by: Nicolai Hähnle <***@amd.com>
---
src/mesa/main/get_hash_params.py | 2 +-
src/mesa/main/mtypes.h | 3 +++
2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/mesa/main/get_hash_params.py b/src/mesa/main/get_hash_params.py
index 20ef6e4977a..6d99a029ed2 100644
--- a/src/mesa/main/get_hash_params.py
+++ b/src/mesa/main/get_hash_params.py
@@ -317,21 +317,21 @@ descriptor=[

# GL_ARB_ES2_compatibility
[ "SHADER_COMPILER", "CONST(1), extra_ARB_ES2_compatibility_api_es2" ],
[ "MAX_VARYING_VECTORS", "CONTEXT_INT(Const.MaxVarying), extra_ARB_ES2_compatibility_api_es2" ],
[ "MAX_VERTEX_UNIFORM_VECTORS", "LOC_CUSTOM, TYPE_INT, 0, extra_ARB_ES2_compatibility_api_es2" ],
[ "MAX_FRAGMENT_UNIFORM_VECTORS", "LOC_CUSTOM, TYPE_INT, 0, extra_ARB_ES2_compatibility_api_es2" ],
[ "NUM_SHADER_BINARY_FORMATS", "CONST(0), extra_ARB_ES2_compatibility_api_es2" ],
[ "SHADER_BINARY_FORMATS", "LOC_CUSTOM, TYPE_INVALID, 0, extra_ARB_ES2_compatibility_api_es2" ],

# GL_ARB_get_program_binary / GL_OES_get_program_binary
- [ "NUM_PROGRAM_BINARY_FORMATS", "CONST(0), NO_EXTRA" ],
+ [ "NUM_PROGRAM_BINARY_FORMATS", "CONTEXT_UINT(Const.NumProgramBinaryFormats), NO_EXTRA" ],
[ "PROGRAM_BINARY_FORMATS", "LOC_CUSTOM, TYPE_INVALID, 0, NO_EXTRA" ],

# GL_INTEL_performance_query
[ "PERFQUERY_QUERY_NAME_LENGTH_MAX_INTEL", "CONST(MAX_PERFQUERY_QUERY_NAME_LENGTH), extra_INTEL_performance_query" ],
[ "PERFQUERY_COUNTER_NAME_LENGTH_MAX_INTEL", "CONST(MAX_PERFQUERY_COUNTER_NAME_LENGTH), extra_INTEL_performance_query" ],
[ "PERFQUERY_COUNTER_DESC_LENGTH_MAX_INTEL", "CONST(MAX_PERFQUERY_COUNTER_DESC_LENGTH), extra_INTEL_performance_query" ],
[ "PERFQUERY_GPA_EXTENDED_COUNTERS_INTEL", "CONST(PERFQUERY_HAVE_GPA_EXTENDED_COUNTERS), extra_INTEL_performance_query" ],

# GL_KHR_context_flush_control
[ "CONTEXT_RELEASE_BEHAVIOR", "CONTEXT_ENUM(Const.ContextReleaseBehavior), NO_EXTRA" ],
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index 548cf944aa8..7e25bc62280 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -4012,20 +4012,23 @@ struct gl_constants
bool NoPrimitiveBoundingBoxOutput;

/** GL_ARB_sparse_buffer */
GLuint SparseBufferPageSize;

/** Used as an input for sha1 generation in the on-disk shader cache */
unsigned char *dri_config_options_sha1;

/** When drivers are OK with mapped buffers during draw and other calls. */
bool AllowMappedBuffersDuringExecution;
+
+ /** GL_ARB_get_program_binary */
+ GLuint NumProgramBinaryFormats;
};


/**
* Enable flag for each OpenGL extension. Different device drivers will
* enable different extensions at runtime.
*/
struct gl_extensions
{
GLboolean dummy; /* don't remove this! */
--
2.14.3
Timothy Arceri
2017-11-29 01:24:46 UTC
Reply
Permalink
Raw Message
From: Jordan Justen <***@intel.com>

Mesa supports either 0 or 1 formats. If 1 format is supported, it is
GL_PROGRAM_BINARY_FORMAT_MESA as defined in the
GL_MESA_program_binary_formats extension spec.

Signed-off-by: Jordan Justen <***@intel.com>
Reviewed-by: Nicolai Hähnle <***@amd.com>
---
src/mesa/main/get.c | 9 +++++++++
src/mesa/main/get_hash_params.py | 2 +-
2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/src/mesa/main/get.c b/src/mesa/main/get.c
index ea8d932b182..c1b1a89ee05 100644
--- a/src/mesa/main/get.c
+++ b/src/mesa/main/get.c
@@ -1144,20 +1144,29 @@ find_custom_value(struct gl_context *ctx, const struct value_desc *d, union valu
* All three (VBO, TEXTURE, RENDERBUFFER) queries return
* the same numbers here.
*/
v->value_int_4[0] = info.avail_device_memory;
v->value_int_4[1] = info.avail_device_memory;
v->value_int_4[2] = info.avail_staging_memory;
v->value_int_4[3] = info.avail_staging_memory;
}
}
break;
+
+ /* GL_ARB_get_program_binary */
+ case GL_PROGRAM_BINARY_FORMATS:
+ assert(ctx->Const.NumProgramBinaryFormats <= 1);
+ v->value_int_n.n = MIN2(ctx->Const.NumProgramBinaryFormats, 1);
+ if (ctx->Const.NumProgramBinaryFormats > 0) {
+ v->value_int_n.ints[0] = GL_PROGRAM_BINARY_FORMAT_MESA;
+ }
+ break;
}
}

/**
* Check extra constraints on a struct value_desc descriptor
*
* If a struct value_desc has a non-NULL extra pointer, it means that
* there are a number of extra constraints to check or actions to
* perform. The extras is just an integer array where each integer
* encode different constraints or actions.
diff --git a/src/mesa/main/get_hash_params.py b/src/mesa/main/get_hash_params.py
index 6d99a029ed2..eac250a1ecf 100644
--- a/src/mesa/main/get_hash_params.py
+++ b/src/mesa/main/get_hash_params.py
@@ -318,21 +318,21 @@ descriptor=[
# GL_ARB_ES2_compatibility
[ "SHADER_COMPILER", "CONST(1), extra_ARB_ES2_compatibility_api_es2" ],
[ "MAX_VARYING_VECTORS", "CONTEXT_INT(Const.MaxVarying), extra_ARB_ES2_compatibility_api_es2" ],
[ "MAX_VERTEX_UNIFORM_VECTORS", "LOC_CUSTOM, TYPE_INT, 0, extra_ARB_ES2_compatibility_api_es2" ],
[ "MAX_FRAGMENT_UNIFORM_VECTORS", "LOC_CUSTOM, TYPE_INT, 0, extra_ARB_ES2_compatibility_api_es2" ],
[ "NUM_SHADER_BINARY_FORMATS", "CONST(0), extra_ARB_ES2_compatibility_api_es2" ],
[ "SHADER_BINARY_FORMATS", "LOC_CUSTOM, TYPE_INVALID, 0, extra_ARB_ES2_compatibility_api_es2" ],

# GL_ARB_get_program_binary / GL_OES_get_program_binary
[ "NUM_PROGRAM_BINARY_FORMATS", "CONTEXT_UINT(Const.NumProgramBinaryFormats), NO_EXTRA" ],
- [ "PROGRAM_BINARY_FORMATS", "LOC_CUSTOM, TYPE_INVALID, 0, NO_EXTRA" ],
+ [ "PROGRAM_BINARY_FORMATS", "LOC_CUSTOM, TYPE_INT_N, 0, NO_EXTRA" ],

# GL_INTEL_performance_query
[ "PERFQUERY_QUERY_NAME_LENGTH_MAX_INTEL", "CONST(MAX_PERFQUERY_QUERY_NAME_LENGTH), extra_INTEL_performance_query" ],
[ "PERFQUERY_COUNTER_NAME_LENGTH_MAX_INTEL", "CONST(MAX_PERFQUERY_COUNTER_NAME_LENGTH), extra_INTEL_performance_query" ],
[ "PERFQUERY_COUNTER_DESC_LENGTH_MAX_INTEL", "CONST(MAX_PERFQUERY_COUNTER_DESC_LENGTH), extra_INTEL_performance_query" ],
[ "PERFQUERY_GPA_EXTENDED_COUNTERS_INTEL", "CONST(PERFQUERY_HAVE_GPA_EXTENDED_COUNTERS), extra_INTEL_performance_query" ],

# GL_KHR_context_flush_control
[ "CONTEXT_RELEASE_BEHAVIOR", "CONTEXT_ENUM(Const.ContextReleaseBehavior), NO_EXTRA" ],
--
2.14.3
Timothy Arceri
2017-11-29 01:24:43 UTC
Reply
Permalink
Raw Message
From: Jordan Justen <***@intel.com>

Signed-off-by: Jordan Justen <***@intel.com>
Reviewed-by: Timothy Arceri <***@itsqueeze.com>
---
src/mesa/drivers/dri/i965/brw_link.cpp | 9 ++-------
src/mesa/drivers/dri/i965/brw_program.c | 12 ++++++++++++
src/mesa/drivers/dri/i965/brw_program.h | 3 +++
3 files changed, 17 insertions(+), 7 deletions(-)

diff --git a/src/mesa/drivers/dri/i965/brw_link.cpp b/src/mesa/drivers/dri/i965/brw_link.cpp
index d18521e792d..6ac3a79a41e 100644
--- a/src/mesa/drivers/dri/i965/brw_link.cpp
+++ b/src/mesa/drivers/dri/i965/brw_link.cpp
@@ -295,27 +295,22 @@ brw_link_shader(struct gl_context *ctx, struct gl_shader_program *shProg)
continue;

struct gl_program *prog = shader->Program;
brw_shader_gather_info(prog->nir, prog);

NIR_PASS_V(prog->nir, nir_lower_samplers, shProg);
NIR_PASS_V(prog->nir, nir_lower_atomics, shProg);
NIR_PASS_V(prog->nir, nir_lower_atomics_to_ssbo,
prog->nir->info.num_abos);

- if (brw->ctx.Cache) {
- struct blob writer;
- blob_init(&writer);
- nir_serialize(&writer, prog->nir);
- prog->driver_cache_blob = ralloc_size(NULL, writer.size);
- memcpy(prog->driver_cache_blob, writer.data, writer.size);
- prog->driver_cache_blob_size = writer.size;
+ if (ctx->Cache) {
+ brw_program_serialize_nir(ctx, prog, (gl_shader_stage)stage);
}

infos[stage] = &prog->nir->info;

update_xfb_info(prog->sh.LinkedTransformFeedback, infos[stage]);

/* Make a pass over the IR to add state references for any built-in
* uniforms that are used. This has to be done now (during linking).
* Code generation doesn't happen until the first time this shader is
* used for rendering. Waiting until then to generate the parameters is
diff --git a/src/mesa/drivers/dri/i965/brw_program.c b/src/mesa/drivers/dri/i965/brw_program.c
index 30cc14e88a2..c8513c947da 100644
--- a/src/mesa/drivers/dri/i965/brw_program.c
+++ b/src/mesa/drivers/dri/i965/brw_program.c
@@ -780,20 +780,32 @@ brw_assign_common_binding_table_offsets(const struct gen_device_info *devinfo,

stage_prog_data->binding_table.plane_start[2] = next_binding_table_offset;
next_binding_table_offset += num_textures;

/* prog_data->base.binding_table.size will be set by brw_mark_surface_used. */

assert(next_binding_table_offset <= BRW_MAX_SURFACES);
return next_binding_table_offset;
}

+void
+brw_program_serialize_nir(struct gl_context *ctx, struct gl_program *prog,
+ gl_shader_stage stage)
+{
+ struct blob writer;
+ blob_init(&writer);
+ nir_serialize(&writer, prog->nir);
+ prog->driver_cache_blob = ralloc_size(NULL, writer.size);
+ memcpy(prog->driver_cache_blob, writer.data, writer.size);
+ prog->driver_cache_blob_size = writer.size;
+}
+
void
brw_program_deserialize_nir(struct gl_context *ctx, struct gl_program *prog,
gl_shader_stage stage)
{
if (!prog->nir) {
assert(prog->driver_cache_blob && prog->driver_cache_blob_size > 0);
const struct nir_shader_compiler_options *options =
ctx->Const.ShaderCompilerOptions[stage].NirOptions;
struct blob_reader reader;
blob_reader_init(&reader, prog->driver_cache_blob,
diff --git a/src/mesa/drivers/dri/i965/brw_program.h b/src/mesa/drivers/dri/i965/brw_program.h
index bd9b4ad168a..a5e41522841 100644
--- a/src/mesa/drivers/dri/i965/brw_program.h
+++ b/src/mesa/drivers/dri/i965/brw_program.h
@@ -75,20 +75,23 @@ bool brw_debug_recompile_sampler_key(struct brw_context *brw,
const struct brw_sampler_prog_key_data *old_key,
const struct brw_sampler_prog_key_data *key);

uint32_t
brw_assign_common_binding_table_offsets(const struct gen_device_info *devinfo,
const struct gl_program *prog,
struct brw_stage_prog_data *stage_prog_data,
uint32_t next_binding_table_offset);

void
+brw_program_serialize_nir(struct gl_context *ctx, struct gl_program *prog,
+ gl_shader_stage stage);
+void
brw_program_deserialize_nir(struct gl_context *ctx, struct gl_program *prog,
gl_shader_stage stage);

void
brw_stage_prog_data_free(const void *prog_data);

void
brw_dump_arb_asm(const char *stage, struct gl_program *prog);

bool brw_vs_precompile(struct gl_context *ctx, struct gl_program *prog);
--
2.14.3
Timothy Arceri
2017-11-29 01:24:44 UTC
Reply
Permalink
Raw Message
From: Jordan Justen <***@intel.com>

Signed-off-by: Jordan Justen <***@intel.com>
Reviewed-by: Timothy Arceri <***@itsqueeze.com>
---
src/mesa/drivers/dri/i965/brw_program.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/src/mesa/drivers/dri/i965/brw_program.c b/src/mesa/drivers/dri/i965/brw_program.c
index c8513c947da..8d321656fef 100644
--- a/src/mesa/drivers/dri/i965/brw_program.c
+++ b/src/mesa/drivers/dri/i965/brw_program.c
@@ -790,20 +790,21 @@ brw_assign_common_binding_table_offsets(const struct gen_device_info *devinfo,
void
brw_program_serialize_nir(struct gl_context *ctx, struct gl_program *prog,
gl_shader_stage stage)
{
struct blob writer;
blob_init(&writer);
nir_serialize(&writer, prog->nir);
prog->driver_cache_blob = ralloc_size(NULL, writer.size);
memcpy(prog->driver_cache_blob, writer.data, writer.size);
prog->driver_cache_blob_size = writer.size;
+ blob_finish(&writer);
}

void
brw_program_deserialize_nir(struct gl_context *ctx, struct gl_program *prog,
gl_shader_stage stage)
{
if (!prog->nir) {
assert(prog->driver_cache_blob && prog->driver_cache_blob_size > 0);
const struct nir_shader_compiler_options *options =
ctx->Const.ShaderCompilerOptions[stage].NirOptions;
--
2.14.3
Timothy Arceri
2017-11-29 01:24:47 UTC
Reply
Permalink
Raw Message
---
src/mesa/main/dd.h | 17 +++++++++++++++++
1 file changed, 17 insertions(+)

diff --git a/src/mesa/main/dd.h b/src/mesa/main/dd.h
index da03b2e8b94..4e4d2a6f37d 100644
--- a/src/mesa/main/dd.h
+++ b/src/mesa/main/dd.h
@@ -1119,20 +1119,37 @@ struct dd_function_table {
* of fd after the call returns.
*
* Accessing fd after ImportMemoryObjectFd returns results in undefined
* behaviour. This is consistent with EXT_external_object_fd.
*/
void (*ImportMemoryObjectFd)(struct gl_context *ctx,
struct gl_memory_object *memObj,
GLuint64 size,
int fd);
/*@}*/
+
+ /**
+ * \name GL_ARB_get_program_binary
+ */
+ /*@{*/
+ /**
+ * Calls to retrieve/store a binary serialized copy of the current program.
+ */
+ void (*GetProgramBinaryDriverSHA1)(struct gl_context *ctx, uint8_t *sha1);
+
+ void (*ProgramBinarySerializeDriverBlob)(struct gl_context *ctx,
+ struct gl_program *prog);
+
+ void (*ProgramBinaryDeserializeDriverBlob)(struct gl_context *ctx,
+ struct gl_shader_program *shProg,
+ struct gl_program *prog);
+ /*@}*/
};


/**
* Per-vertex functions.
*
* These are the functions which can appear between glBegin and glEnd.
* Depending on whether we're inside or outside a glBegin/End pair
* and whether we're in immediate mode or building a display list, these
* functions behave differently. This structure allows us to switch
--
2.14.3
Jordan Justen
2017-11-29 09:31:26 UTC
Reply
Permalink
Raw Message
Post by Timothy Arceri
---
src/mesa/main/dd.h | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/src/mesa/main/dd.h b/src/mesa/main/dd.h
index da03b2e8b94..4e4d2a6f37d 100644
--- a/src/mesa/main/dd.h
+++ b/src/mesa/main/dd.h
@@ -1119,20 +1119,37 @@ struct dd_function_table {
* of fd after the call returns.
*
* Accessing fd after ImportMemoryObjectFd returns results in undefined
* behaviour. This is consistent with EXT_external_object_fd.
*/
void (*ImportMemoryObjectFd)(struct gl_context *ctx,
struct gl_memory_object *memObj,
GLuint64 size,
int fd);
+
+ /**
+ * \name GL_ARB_get_program_binary
+ */
+ /**
+ * Calls to retrieve/store a binary serialized copy of the current program.
+ */
+ void (*GetProgramBinaryDriverSHA1)(struct gl_context *ctx, uint8_t *sha1);
+
+ void (*ProgramBinarySerializeDriverBlob)(struct gl_context *ctx,
+ struct gl_program *prog);
+
+ void (*ProgramBinaryDeserializeDriverBlob)(struct gl_context *ctx,
+ struct gl_shader_program *shProg,
+ struct gl_program *prog);
};
/**
* Per-vertex functions.
*
* These are the functions which can appear between glBegin and glEnd.
* Depending on whether we're inside or outside a glBegin/End pair
* and whether we're in immediate mode or building a display list, these
* functions behave differently. This structure allows us to switch
--
2.14.3
_______________________________________________
mesa-dev mailing list
https://lists.freedesktop.org/mailman/listinfo/mesa-dev
Timothy Arceri
2017-11-29 01:24:50 UTC
Reply
Permalink
Raw Message
From: Jordan Justen <***@intel.com>

V2: call generic _mesa_get_program_binary() helper rather than driver
function directly to allow greater code sharing.

Signed-off-by: Timothy Arceri <***@itsqueeze.com>
Signed-off-by: Jordan Justen <***@intel.com> (v1)
Reviewed-by: Nicolai Hähnle <***@amd.com> (v1)
---
src/mesa/main/shaderapi.c | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/src/mesa/main/shaderapi.c b/src/mesa/main/shaderapi.c
index 82a7fde697b..b728b320ac4 100644
--- a/src/mesa/main/shaderapi.c
+++ b/src/mesa/main/shaderapi.c
@@ -2192,26 +2192,29 @@ _mesa_GetProgramBinary(GLuint program, GLsizei bufSize, GLsizei *length,
* INVALID_OPERATION error.
*/
if (!shProg->data->LinkStatus) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glGetProgramBinary(program %u not linked)",
shProg->Name);
*length = 0;
return;
}

- *length = 0;
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glGetProgramBinary(driver supports zero binary formats)");
-
- (void) binaryFormat;
- (void) binary;
+ if (ctx->Const.NumProgramBinaryFormats == 0) {
+ *length = 0;
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glGetProgramBinary(driver supports zero binary formats)");
+ } else {
+ _mesa_get_program_binary(ctx, shProg, bufSize, length, binaryFormat,
+ binary);
+ assert(*length == 0 || *binaryFormat == GL_PROGRAM_BINARY_FORMAT_MESA);
+ }
}

void GLAPIENTRY
_mesa_ProgramBinary(GLuint program, GLenum binaryFormat,
const GLvoid *binary, GLsizei length)
{
struct gl_shader_program *shProg;
GET_CURRENT_CONTEXT(ctx);

shProg = _mesa_lookup_shader_program_err(ctx, program, "glProgramBinary");
--
2.14.3
Timothy Arceri
2017-11-29 01:24:51 UTC
Reply
Permalink
Raw Message
From: Jordan Justen <***@intel.com>

V2: call generic mesa_program_binary() helper rather than driver
function directly to allow greater code sharing.

Signed-off-by: Timothy Arceri <***@itsqueeze.com>
Signed-off-by: Jordan Justen <***@intel.com> (v1)
Reviewed-by: Nicolai Hähnle <***@amd.com> (v1)
---
src/mesa/main/shaderapi.c | 36 +++++++++++++++++++-----------------
1 file changed, 19 insertions(+), 17 deletions(-)

diff --git a/src/mesa/main/shaderapi.c b/src/mesa/main/shaderapi.c
index b728b320ac4..51031e12ec9 100644
--- a/src/mesa/main/shaderapi.c
+++ b/src/mesa/main/shaderapi.c
@@ -2214,47 +2214,49 @@ void GLAPIENTRY
_mesa_ProgramBinary(GLuint program, GLenum binaryFormat,
const GLvoid *binary, GLsizei length)
{
struct gl_shader_program *shProg;
GET_CURRENT_CONTEXT(ctx);

shProg = _mesa_lookup_shader_program_err(ctx, program, "glProgramBinary");
if (!shProg)
return;

- (void) binaryFormat;
- (void) binary;
-
/* Section 2.3.1 (Errors) of the OpenGL 4.5 spec says:
*
* "If a negative number is provided where an argument of type sizei or
* sizeiptr is specified, an INVALID_VALUE error is generated."
*/
if (length < 0) {
_mesa_error(ctx, GL_INVALID_VALUE, "glProgramBinary(length < 0)");
return;
}

- /* The ARB_get_program_binary spec says:
- *
- * "<binaryFormat> and <binary> must be those returned by a previous
- * call to GetProgramBinary, and <length> must be the length of the
- * program binary as returned by GetProgramBinary or GetProgramiv with
- * <pname> PROGRAM_BINARY_LENGTH. Loading the program binary will fail,
- * setting the LINK_STATUS of <program> to FALSE, if these conditions
- * are not met."
- *
- * Since any value of binaryFormat passed "is not one of those specified as
- * allowable for [this] command, an INVALID_ENUM error is generated."
- */
- shProg->data->LinkStatus = linking_failure;
- _mesa_error(ctx, GL_INVALID_ENUM, "glProgramBinary");
+ if (ctx->Const.NumProgramBinaryFormats == 0 ||
+ binaryFormat != GL_PROGRAM_BINARY_FORMAT_MESA) {
+ /* The ARB_get_program_binary spec says:
+ *
+ * "<binaryFormat> and <binary> must be those returned by a previous
+ * call to GetProgramBinary, and <length> must be the length of the
+ * program binary as returned by GetProgramBinary or GetProgramiv with
+ * <pname> PROGRAM_BINARY_LENGTH. Loading the program binary will fail,
+ * setting the LINK_STATUS of <program> to FALSE, if these conditions
+ * are not met."
+ *
+ * Since any value of binaryFormat passed "is not one of those specified as
+ * allowable for [this] command, an INVALID_ENUM error is generated."
+ */
+ shProg->data->LinkStatus = linking_failure;
+ _mesa_error(ctx, GL_INVALID_ENUM, "glProgramBinary");
+ } else {
+ _mesa_program_binary(ctx, shProg, binaryFormat, binary, length);
+ }
}


static ALWAYS_INLINE void
program_parameteri(struct gl_context *ctx, struct gl_shader_program *shProg,
GLuint pname, GLint value, bool no_error)
{
switch (pname) {
case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
/* This enum isn't part of the OES extension for OpenGL ES 2.0, but it
--
2.14.3
Tapani Pälli
2017-12-08 05:33:58 UTC
Reply
Permalink
Raw Message
13,14,15
Post by Timothy Arceri
V2: call generic mesa_program_binary() helper rather than driver
function directly to allow greater code sharing.
---
src/mesa/main/shaderapi.c | 36 +++++++++++++++++++-----------------
1 file changed, 19 insertions(+), 17 deletions(-)
diff --git a/src/mesa/main/shaderapi.c b/src/mesa/main/shaderapi.c
index b728b320ac4..51031e12ec9 100644
--- a/src/mesa/main/shaderapi.c
+++ b/src/mesa/main/shaderapi.c
@@ -2214,47 +2214,49 @@ void GLAPIENTRY
_mesa_ProgramBinary(GLuint program, GLenum binaryFormat,
const GLvoid *binary, GLsizei length)
{
struct gl_shader_program *shProg;
GET_CURRENT_CONTEXT(ctx);
shProg = _mesa_lookup_shader_program_err(ctx, program, "glProgramBinary");
if (!shProg)
return;
- (void) binaryFormat;
- (void) binary;
-
*
* "If a negative number is provided where an argument of type sizei or
* sizeiptr is specified, an INVALID_VALUE error is generated."
*/
if (length < 0) {
_mesa_error(ctx, GL_INVALID_VALUE, "glProgramBinary(length < 0)");
return;
}
- *
- * "<binaryFormat> and <binary> must be those returned by a previous
- * call to GetProgramBinary, and <length> must be the length of the
- * program binary as returned by GetProgramBinary or GetProgramiv with
- * <pname> PROGRAM_BINARY_LENGTH. Loading the program binary will fail,
- * setting the LINK_STATUS of <program> to FALSE, if these conditions
- * are not met."
- *
- * Since any value of binaryFormat passed "is not one of those specified as
- * allowable for [this] command, an INVALID_ENUM error is generated."
- */
- shProg->data->LinkStatus = linking_failure;
- _mesa_error(ctx, GL_INVALID_ENUM, "glProgramBinary");
+ if (ctx->Const.NumProgramBinaryFormats == 0 ||
+ binaryFormat != GL_PROGRAM_BINARY_FORMAT_MESA) {
+ *
+ * "<binaryFormat> and <binary> must be those returned by a previous
+ * call to GetProgramBinary, and <length> must be the length of the
+ * program binary as returned by GetProgramBinary or GetProgramiv with
+ * <pname> PROGRAM_BINARY_LENGTH. Loading the program binary will fail,
+ * setting the LINK_STATUS of <program> to FALSE, if these conditions
+ * are not met."
+ *
+ * Since any value of binaryFormat passed "is not one of those specified as
+ * allowable for [this] command, an INVALID_ENUM error is generated."
+ */
+ shProg->data->LinkStatus = linking_failure;
+ _mesa_error(ctx, GL_INVALID_ENUM, "glProgramBinary");
+ } else {
+ _mesa_program_binary(ctx, shProg, binaryFormat, binary, length);
+ }
}
static ALWAYS_INLINE void
program_parameteri(struct gl_context *ctx, struct gl_shader_program *shProg,
GLuint pname, GLint value, bool no_error)
{
switch (pname) {
/* This enum isn't part of the OES extension for OpenGL ES 2.0, but it
Timothy Arceri
2017-11-29 01:24:49 UTC
Reply
Permalink
Raw Message
From: Jordan Justen <***@intel.com>

V2: call generic _mesa_get_program_binary_length() helper
rather than driver function directly to allow greater
code sharing.

Signed-off-by: Timothy Arceri <***@itsqueeze.com>
Signed-off-by: Jordan Justen <***@intel.com> (v1)
Reviewed-by: Nicolai Hähnle <***@amd.com>i (v1)
---
src/mesa/main/shaderapi.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/mesa/main/shaderapi.c b/src/mesa/main/shaderapi.c
index 72824355838..82a7fde697b 100644
--- a/src/mesa/main/shaderapi.c
+++ b/src/mesa/main/shaderapi.c
@@ -38,20 +38,21 @@


#include <stdbool.h>
#include "main/glheader.h"
#include "main/context.h"
#include "main/dispatch.h"
#include "main/enums.h"
#include "main/hash.h"
#include "main/mtypes.h"
#include "main/pipelineobj.h"
+#include "main/program_binary.h"
#include "main/shaderapi.h"
#include "main/shaderobj.h"
#include "main/transformfeedback.h"
#include "main/uniforms.h"
#include "compiler/glsl/glsl_parser_extras.h"
#include "compiler/glsl/ir.h"
#include "compiler/glsl/ir_uniform.h"
#include "compiler/glsl/program.h"
#include "program/program.h"
#include "program/prog_print.h"
@@ -827,21 +828,25 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname,
* GL_ARB_get_program_binary extension or OpenGL ES 3.0.
*
* On desktop, we ignore the 3.0+ requirement because it is silly.
*/
if (!_mesa_is_desktop_gl(ctx) && !_mesa_is_gles3(ctx))
break;

*params = shProg->BinaryRetreivableHint;
return;
case GL_PROGRAM_BINARY_LENGTH:
- *params = 0;
+ if (ctx->Const.NumProgramBinaryFormats == 0) {
+ *params = 0;
+ } else {
+ _mesa_get_program_binary_length(ctx, shProg, params);
+ }
return;
case GL_ACTIVE_ATOMIC_COUNTER_BUFFERS:
if (!ctx->Extensions.ARB_shader_atomic_counters)
break;

*params = shProg->data->NumAtomicBuffers;
return;
case GL_COMPUTE_WORK_GROUP_SIZE: {
int i;
if (!_mesa_has_compute_shaders(ctx))
--
2.14.3
Timothy Arceri
2017-11-29 01:24:53 UTC
Reply
Permalink
Raw Message
We will need this for ARB_get_program_binary binary support.
---
src/mesa/state_tracker/st_program.c | 21 ++++++++++++---------
src/mesa/state_tracker/st_program.h | 12 ++++++++++++
src/mesa/state_tracker/st_shader_cache.c | 15 +++++++++------
src/mesa/state_tracker/st_shader_cache.h | 3 +--
4 files changed, 34 insertions(+), 17 deletions(-)

diff --git a/src/mesa/state_tracker/st_program.c b/src/mesa/state_tracker/st_program.c
index 5c0a58104fc..e02e5c25f71 100644
--- a/src/mesa/state_tracker/st_program.c
+++ b/src/mesa/state_tracker/st_program.c
@@ -527,27 +527,26 @@ st_translate_vertex_program(struct st_context *st,
output_semantic_name,
output_semantic_index);

if (error) {
debug_printf("%s: failed to translate Mesa program:\n", __func__);
_mesa_print_program(&stvp->Base);
debug_assert(0);
return false;
}

- unsigned num_tokens;
- stvp->tgsi.tokens = ureg_get_tokens(ureg, &num_tokens);
+ stvp->tgsi.tokens = ureg_get_tokens(ureg, &stvp->num_tgsi_tokens);
ureg_destroy(ureg);

if (stvp->glsl_to_tgsi) {
stvp->glsl_to_tgsi = NULL;
- st_store_tgsi_in_disk_cache(st, &stvp->Base, NULL, num_tokens);
+ st_store_tgsi_in_disk_cache(st, &stvp->Base, NULL);
}

return stvp->tgsi.tokens != NULL;
}

static struct st_vp_variant *
st_create_vp_variant(struct st_context *st,
struct st_vertex_program *stvp,
const struct st_vp_variant_key *key)
{
@@ -985,27 +984,26 @@ st_translate_fragment_program(struct st_context *st,
inputMapping,
input_semantic_name,
input_semantic_index,
interpMode,
/* outputs */
fs_num_outputs,
outputMapping,
fs_output_semantic_name,
fs_output_semantic_index);

- unsigned num_tokens;
- stfp->tgsi.tokens = ureg_get_tokens(ureg, &num_tokens);
+ stfp->tgsi.tokens = ureg_get_tokens(ureg, &stfp->num_tgsi_tokens);
ureg_destroy(ureg);

if (stfp->glsl_to_tgsi) {
stfp->glsl_to_tgsi = NULL;
- st_store_tgsi_in_disk_cache(st, &stfp->Base, NULL, num_tokens);
+ st_store_tgsi_in_disk_cache(st, &stfp->Base, NULL);
}

return stfp->tgsi.tokens != NULL;
}

static struct st_fp_variant *
st_create_fp_variant(struct st_context *st,
struct st_fragment_program *stfp,
const struct st_fp_variant_key *key)
{
@@ -1393,29 +1391,34 @@ st_translate_program_common(struct st_context *st,
inputSlotToAttr,
input_semantic_name,
input_semantic_index,
NULL,
/* outputs */
num_outputs,
outputMapping,
output_semantic_name,
output_semantic_index);

- unsigned num_tokens;
- out_state->tokens = ureg_get_tokens(ureg, &num_tokens);
+ if (tgsi_processor == PIPE_SHADER_COMPUTE) {
+ struct st_compute_program *stcp = (struct st_compute_program *) prog;
+ out_state->tokens = ureg_get_tokens(ureg, &stcp->num_tgsi_tokens);
+ } else {
+ struct st_common_program *stcp = (struct st_common_program *) prog;
+ out_state->tokens = ureg_get_tokens(ureg, &stcp->num_tgsi_tokens);
+ }
ureg_destroy(ureg);

st_translate_stream_output_info(glsl_to_tgsi,
outputMapping,
&out_state->stream_output);

- st_store_tgsi_in_disk_cache(st, prog, out_state, num_tokens);
+ st_store_tgsi_in_disk_cache(st, prog, out_state);

if ((ST_DEBUG & DEBUG_TGSI) && (ST_DEBUG & DEBUG_MESA)) {
_mesa_print_program(prog);
debug_printf("\n");
}

if (ST_DEBUG & DEBUG_TGSI) {
tgsi_dump(out_state->tokens, 0);
debug_printf("\n");
}
diff --git a/src/mesa/state_tracker/st_program.h b/src/mesa/state_tracker/st_program.h
index 0e6c8e00c6e..a520ffbecb4 100644
--- a/src/mesa/state_tracker/st_program.h
+++ b/src/mesa/state_tracker/st_program.h
@@ -143,20 +143,23 @@ struct st_fragment_program
struct gl_program Base;
struct pipe_shader_state tgsi;
struct glsl_to_tgsi_visitor* glsl_to_tgsi;
struct ati_fragment_shader *ati_fs;
uint64_t affected_states; /**< ST_NEW_* flags to mark dirty when binding */

/* used when bypassing glsl_to_tgsi: */
struct gl_shader_program *shader_program;

struct st_fp_variant *variants;
+
+ /* Used by the shader cache and ARB_get_program_binary */
+ unsigned num_tgsi_tokens;
};



/** Vertex program variant key */
struct st_vp_variant_key
{
struct st_context *st; /**< variants are per-context */
boolean passthrough_edgeflags;

@@ -215,20 +218,23 @@ struct st_vertex_program

/** Maps VARYING_SLOT_x to slot */
ubyte result_to_output[VARYING_SLOT_MAX];

/** List of translated variants of this vertex program.
*/
struct st_vp_variant *variants;

/** SHA1 hash of linked tgsi shader program, used for on-disk cache */
unsigned char sha1[20];
+
+ /* Used by the shader cache and ARB_get_program_binary */
+ unsigned num_tgsi_tokens;
};



/** Key shared by all shaders except VP, FP */
struct st_basic_variant_key
{
struct st_context *st; /**< variants are per-context */
};

@@ -257,40 +263,46 @@ struct st_common_program
struct glsl_to_tgsi_visitor* glsl_to_tgsi;
uint64_t affected_states; /**< ST_NEW_* flags to mark dirty when binding */

/* used when bypassing glsl_to_tgsi: */
struct gl_shader_program *shader_program;

struct st_basic_variant *variants;

/** SHA1 hash of linked tgsi shader program, used for on-disk cache */
unsigned char sha1[20];
+
+ /* Used by the shader cache and ARB_get_program_binary */
+ unsigned num_tgsi_tokens;
};


/**
* Derived from Mesa gl_program:
*/
struct st_compute_program
{
struct gl_program Base; /**< The Mesa compute program */
struct pipe_compute_state tgsi;
struct glsl_to_tgsi_visitor* glsl_to_tgsi;
uint64_t affected_states; /**< ST_NEW_* flags to mark dirty when binding */

/* used when bypassing glsl_to_tgsi: */
struct gl_shader_program *shader_program;

struct st_basic_variant *variants;

/** SHA1 hash of linked tgsi shader program, used for on-disk cache */
unsigned char sha1[20];
+
+ /* Used by the shader cache and ARB_get_program_binary */
+ unsigned num_tgsi_tokens;
};


static inline struct st_fragment_program *
st_fragment_program( struct gl_program *fp )
{
return (struct st_fragment_program *)fp;
}


diff --git a/src/mesa/state_tracker/st_shader_cache.c b/src/mesa/state_tracker/st_shader_cache.c
index a5e33133b3c..a9413fb0534 100644
--- a/src/mesa/state_tracker/st_shader_cache.c
+++ b/src/mesa/state_tracker/st_shader_cache.c
@@ -49,22 +49,21 @@ write_tgsi_to_cache(struct blob *blob, struct pipe_shader_state *tgsi,
prog->driver_cache_blob = ralloc_size(NULL, blob->size);
memcpy(prog->driver_cache_blob, blob->data, blob->size);
prog->driver_cache_blob_size = blob->size;
}

/**
* Store tgsi and any other required state in on-disk shader cache.
*/
void
st_store_tgsi_in_disk_cache(struct st_context *st, struct gl_program *prog,
- struct pipe_shader_state *out_state,
- unsigned num_tokens)
+ struct pipe_shader_state *out_state)
{
if (!st->ctx->Cache)
return;

/* Exit early when we are dealing with a ff shader with no source file to
* generate a source from.
*/
static const char zero[sizeof(prog->sh.data->sha1)] = {0};
if (memcmp(prog->sh.data->sha1, zero, sizeof(prog->sh.data->sha1)) == 0)
return;
@@ -76,38 +75,42 @@ st_store_tgsi_in_disk_cache(struct st_context *st, struct gl_program *prog,
case MESA_SHADER_VERTEX: {
struct st_vertex_program *stvp = (struct st_vertex_program *) prog;

blob_write_uint32(&blob, stvp->num_inputs);
blob_write_bytes(&blob, stvp->index_to_input,
sizeof(stvp->index_to_input));
blob_write_bytes(&blob, stvp->result_to_output,
sizeof(stvp->result_to_output));

write_stream_out_to_cache(&blob, &stvp->tgsi);
- write_tgsi_to_cache(&blob, &stvp->tgsi, prog, num_tokens);
+ write_tgsi_to_cache(&blob, &stvp->tgsi, prog, stvp->num_tgsi_tokens);
break;
}
case MESA_SHADER_TESS_CTRL:
case MESA_SHADER_TESS_EVAL:
case MESA_SHADER_GEOMETRY: {
+ struct st_common_program *stcp = (struct st_common_program *) prog;
+
write_stream_out_to_cache(&blob, out_state);
- write_tgsi_to_cache(&blob, out_state, prog, num_tokens);
+ write_tgsi_to_cache(&blob, out_state, prog, stcp->num_tgsi_tokens);
break;
}
case MESA_SHADER_FRAGMENT: {
struct st_fragment_program *stfp = (struct st_fragment_program *) prog;

- write_tgsi_to_cache(&blob, &stfp->tgsi, prog, num_tokens);
+ write_tgsi_to_cache(&blob, &stfp->tgsi, prog, stfp->num_tgsi_tokens);
break;
}
case MESA_SHADER_COMPUTE: {
- write_tgsi_to_cache(&blob, out_state, prog, num_tokens);
+ struct st_compute_program *stcp = (struct st_compute_program *) prog;
+
+ write_tgsi_to_cache(&blob, out_state, prog, stcp->num_tgsi_tokens);
break;
}
default:
unreachable("Unsupported stage");
}

if (st->ctx->_Shader->Flags & GLSL_CACHE_INFO) {
fprintf(stderr, "putting %s tgsi_tokens in cache\n",
_mesa_shader_stage_to_string(prog->info.stage));
}
diff --git a/src/mesa/state_tracker/st_shader_cache.h b/src/mesa/state_tracker/st_shader_cache.h
index 090d7d85cc8..7644d437521 100644
--- a/src/mesa/state_tracker/st_shader_cache.h
+++ b/src/mesa/state_tracker/st_shader_cache.h
@@ -31,16 +31,15 @@
#ifdef __cplusplus
extern "C" {
#endif

bool
st_load_tgsi_from_disk_cache(struct gl_context *ctx,
struct gl_shader_program *prog);

void
st_store_tgsi_in_disk_cache(struct st_context *st, struct gl_program *prog,
- struct pipe_shader_state *out_state,
- unsigned num_tokens);
+ struct pipe_shader_state *out_state);

#ifdef __cplusplus
}
#endif
--
2.14.3
Timothy Arceri
2017-11-29 01:24:52 UTC
Reply
Permalink
Raw Message
From: Jordan Justen <***@intel.com>

The GL_ARB_get_program_binary extension spec says:

"If ProgramBinary fails to load a binary, no error is generated, but
any information about a previous link or load of that program object
is lost."

v2:
* Re-initialize shProg->data after clear. (Jordan)
(Required after 6a72eba755fea15a0d97abb913a6315d9d32e274)

Signed-off-by: Jordan Justen <***@intel.com>
Reviewed-by: Nicolai Hähnle <***@amd.com>
---
src/mesa/main/shaderapi.c | 3 +++
1 file changed, 3 insertions(+)

diff --git a/src/mesa/main/shaderapi.c b/src/mesa/main/shaderapi.c
index 51031e12ec9..4607cbb99bc 100644
--- a/src/mesa/main/shaderapi.c
+++ b/src/mesa/main/shaderapi.c
@@ -2214,20 +2214,23 @@ void GLAPIENTRY
_mesa_ProgramBinary(GLuint program, GLenum binaryFormat,
const GLvoid *binary, GLsizei length)
{
struct gl_shader_program *shProg;
GET_CURRENT_CONTEXT(ctx);

shProg = _mesa_lookup_shader_program_err(ctx, program, "glProgramBinary");
if (!shProg)
return;

+ _mesa_clear_shader_program_data(ctx, shProg);
+ shProg->data = _mesa_create_shader_program_data();
+
/* Section 2.3.1 (Errors) of the OpenGL 4.5 spec says:
*
* "If a negative number is provided where an argument of type sizei or
* sizeiptr is specified, an INVALID_VALUE error is generated."
*/
if (length < 0) {
_mesa_error(ctx, GL_INVALID_VALUE, "glProgramBinary(length < 0)");
return;
}
--
2.14.3
Timothy Arceri
2017-11-29 01:24:54 UTC
Reply
Permalink
Raw Message
We can instead just get this from st_*_program.
---
src/mesa/state_tracker/st_program.c | 6 +++---
src/mesa/state_tracker/st_shader_cache.c | 22 ++++++++++++----------
src/mesa/state_tracker/st_shader_cache.h | 3 +--
3 files changed, 16 insertions(+), 15 deletions(-)

diff --git a/src/mesa/state_tracker/st_program.c b/src/mesa/state_tracker/st_program.c
index e02e5c25f71..b865f817385 100644
--- a/src/mesa/state_tracker/st_program.c
+++ b/src/mesa/state_tracker/st_program.c
@@ -532,21 +532,21 @@ st_translate_vertex_program(struct st_context *st,
_mesa_print_program(&stvp->Base);
debug_assert(0);
return false;
}

stvp->tgsi.tokens = ureg_get_tokens(ureg, &stvp->num_tgsi_tokens);
ureg_destroy(ureg);

if (stvp->glsl_to_tgsi) {
stvp->glsl_to_tgsi = NULL;
- st_store_tgsi_in_disk_cache(st, &stvp->Base, NULL);
+ st_store_tgsi_in_disk_cache(st, &stvp->Base);
}

return stvp->tgsi.tokens != NULL;
}

static struct st_vp_variant *
st_create_vp_variant(struct st_context *st,
struct st_vertex_program *stvp,
const struct st_vp_variant_key *key)
{
@@ -989,21 +989,21 @@ st_translate_fragment_program(struct st_context *st,
fs_num_outputs,
outputMapping,
fs_output_semantic_name,
fs_output_semantic_index);

stfp->tgsi.tokens = ureg_get_tokens(ureg, &stfp->num_tgsi_tokens);
ureg_destroy(ureg);

if (stfp->glsl_to_tgsi) {
stfp->glsl_to_tgsi = NULL;
- st_store_tgsi_in_disk_cache(st, &stfp->Base, NULL);
+ st_store_tgsi_in_disk_cache(st, &stfp->Base);
}

return stfp->tgsi.tokens != NULL;
}

static struct st_fp_variant *
st_create_fp_variant(struct st_context *st,
struct st_fragment_program *stfp,
const struct st_fp_variant_key *key)
{
@@ -1404,21 +1404,21 @@ st_translate_program_common(struct st_context *st,
} else {
struct st_common_program *stcp = (struct st_common_program *) prog;
out_state->tokens = ureg_get_tokens(ureg, &stcp->num_tgsi_tokens);
}
ureg_destroy(ureg);

st_translate_stream_output_info(glsl_to_tgsi,
outputMapping,
&out_state->stream_output);

- st_store_tgsi_in_disk_cache(st, prog, out_state);
+ st_store_tgsi_in_disk_cache(st, prog);

if ((ST_DEBUG & DEBUG_TGSI) && (ST_DEBUG & DEBUG_MESA)) {
_mesa_print_program(prog);
debug_printf("\n");
}

if (ST_DEBUG & DEBUG_TGSI) {
tgsi_dump(out_state->tokens, 0);
debug_printf("\n");
}
diff --git a/src/mesa/state_tracker/st_shader_cache.c b/src/mesa/state_tracker/st_shader_cache.c
index a9413fb0534..1d9b1727552 100644
--- a/src/mesa/state_tracker/st_shader_cache.c
+++ b/src/mesa/state_tracker/st_shader_cache.c
@@ -32,38 +32,36 @@

static void
write_stream_out_to_cache(struct blob *blob,
struct pipe_shader_state *tgsi)
{
blob_write_bytes(blob, &tgsi->stream_output,
sizeof(tgsi->stream_output));
}

static void
-write_tgsi_to_cache(struct blob *blob, struct pipe_shader_state *tgsi,
+write_tgsi_to_cache(struct blob *blob, const struct tgsi_token *tokens,
struct gl_program *prog, unsigned num_tokens)
{
blob_write_uint32(blob, num_tokens);
- blob_write_bytes(blob, tgsi->tokens,
- num_tokens * sizeof(struct tgsi_token));
+ blob_write_bytes(blob, tokens, num_tokens * sizeof(struct tgsi_token));

prog->driver_cache_blob = ralloc_size(NULL, blob->size);
memcpy(prog->driver_cache_blob, blob->data, blob->size);
prog->driver_cache_blob_size = blob->size;
}

/**
* Store tgsi and any other required state in on-disk shader cache.
*/
void
-st_store_tgsi_in_disk_cache(struct st_context *st, struct gl_program *prog,
- struct pipe_shader_state *out_state)
+st_store_tgsi_in_disk_cache(struct st_context *st, struct gl_program *prog)
{
if (!st->ctx->Cache)
return;

/* Exit early when we are dealing with a ff shader with no source file to
* generate a source from.
*/
static const char zero[sizeof(prog->sh.data->sha1)] = {0};
if (memcmp(prog->sh.data->sha1, zero, sizeof(prog->sh.data->sha1)) == 0)
return;
@@ -75,42 +73,46 @@ st_store_tgsi_in_disk_cache(struct st_context *st, struct gl_program *prog,
case MESA_SHADER_VERTEX: {
struct st_vertex_program *stvp = (struct st_vertex_program *) prog;

blob_write_uint32(&blob, stvp->num_inputs);
blob_write_bytes(&blob, stvp->index_to_input,
sizeof(stvp->index_to_input));
blob_write_bytes(&blob, stvp->result_to_output,
sizeof(stvp->result_to_output));

write_stream_out_to_cache(&blob, &stvp->tgsi);
- write_tgsi_to_cache(&blob, &stvp->tgsi, prog, stvp->num_tgsi_tokens);
+ write_tgsi_to_cache(&blob, stvp->tgsi.tokens, prog,
+ stvp->num_tgsi_tokens);
break;
}
case MESA_SHADER_TESS_CTRL:
case MESA_SHADER_TESS_EVAL:
case MESA_SHADER_GEOMETRY: {
struct st_common_program *stcp = (struct st_common_program *) prog;

- write_stream_out_to_cache(&blob, out_state);
- write_tgsi_to_cache(&blob, out_state, prog, stcp->num_tgsi_tokens);
+ write_stream_out_to_cache(&blob, &stcp->tgsi);
+ write_tgsi_to_cache(&blob, stcp->tgsi.tokens, prog,
+ stcp->num_tgsi_tokens);
break;
}
case MESA_SHADER_FRAGMENT: {
struct st_fragment_program *stfp = (struct st_fragment_program *) prog;

- write_tgsi_to_cache(&blob, &stfp->tgsi, prog, stfp->num_tgsi_tokens);
+ write_tgsi_to_cache(&blob, stfp->tgsi.tokens, prog,
+ stfp->num_tgsi_tokens);
break;
}
case MESA_SHADER_COMPUTE: {
struct st_compute_program *stcp = (struct st_compute_program *) prog;

- write_tgsi_to_cache(&blob, out_state, prog, stcp->num_tgsi_tokens);
+ write_tgsi_to_cache(&blob, stcp->tgsi.prog, prog,
+ stcp->num_tgsi_tokens);
break;
}
default:
unreachable("Unsupported stage");
}

if (st->ctx->_Shader->Flags & GLSL_CACHE_INFO) {
fprintf(stderr, "putting %s tgsi_tokens in cache\n",
_mesa_shader_stage_to_string(prog->info.stage));
}
diff --git a/src/mesa/state_tracker/st_shader_cache.h b/src/mesa/state_tracker/st_shader_cache.h
index 7644d437521..81a2935d7ba 100644
--- a/src/mesa/state_tracker/st_shader_cache.h
+++ b/src/mesa/state_tracker/st_shader_cache.h
@@ -30,16 +30,15 @@

#ifdef __cplusplus
extern "C" {
#endif

bool
st_load_tgsi_from_disk_cache(struct gl_context *ctx,
struct gl_shader_program *prog);

void
-st_store_tgsi_in_disk_cache(struct st_context *st, struct gl_program *prog,
- struct pipe_shader_state *out_state);
+st_store_tgsi_in_disk_cache(struct st_context *st, struct gl_program *prog);

#ifdef __cplusplus
}
#endif
--
2.14.3
Timothy Arceri
2017-11-29 01:24:48 UTC
Reply
Permalink
Raw Message
From: Jordan Justen <***@intel.com>

V2 (Timothy Arceri):
- add extra code comment
- stop passing around void *binary and just pass
program_binary_header *hdr instead.
- move to src/mesa/main rather than src/util

V3 (Timothy Arceri):
- Move more code out of the backend and into the common
helpers.

Signed-off-by: Jordan Justen <***@intel.com>
---
src/mesa/Makefile.sources | 2 +
src/mesa/main/program_binary.c | 291 +++++++++++++++++++++++++++++++++++++++++
src/mesa/main/program_binary.h | 56 ++++++++
src/mesa/meson.build | 2 +
4 files changed, 351 insertions(+)
create mode 100644 src/mesa/main/program_binary.c
create mode 100644 src/mesa/main/program_binary.h

diff --git a/src/mesa/Makefile.sources b/src/mesa/Makefile.sources
index 6da1e3fef9d..d8b1eb1f995 100644
--- a/src/mesa/Makefile.sources
+++ b/src/mesa/Makefile.sources
@@ -166,20 +166,22 @@ MAIN_FILES = \
main/pixel.c \
main/pixel.h \
main/pixelstore.c \
main/pixelstore.h \
main/pixeltransfer.c \
main/pixeltransfer.h \
main/points.c \
main/points.h \
main/polygon.c \
main/polygon.h \
+ main/program_binary.c \
+ main/program_binary.h \
main/program_resource.c \
main/program_resource.h \
main/querymatrix.c \
main/querymatrix.h \
main/queryobj.c \
main/queryobj.h \
main/rastpos.c \
main/rastpos.h \
main/readpix.c \
main/readpix.h \
diff --git a/src/mesa/main/program_binary.c b/src/mesa/main/program_binary.c
new file mode 100644
index 00000000000..2786487362f
--- /dev/null
+++ b/src/mesa/main/program_binary.c
@@ -0,0 +1,291 @@
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (c) 2017 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file program_binary.c
+ *
+ * Helper functions for serializing a binary program.
+ */
+
+
+#include "compiler/blob.h"
+#include "compiler/glsl/serialize.h"
+#include "main/errors.h"
+#include "main/mtypes.h"
+#include "util/crc32.h"
+#include "program_binary.h"
+#include "program/prog_parameter.h"
+
+/**
+ * Mesa supports one binary format, but it must differentiate between formats
+ * produced by different drivers and different Mesa versions.
+ *
+ * Mesa uses a uint32_t value to specify an internal format. The only format
+ * defined has one uint32_t value of 0, followed by 20 bytes specifying a sha1
+ * that uniquely identifies the Mesa driver type and version.
+ */
+
+struct program_binary_header {
+ /* If internal_format is 0, it must be followed by the 20 byte sha1 that
+ * identifies the Mesa driver and version supported. If we want to support
+ * something besides a sha1, then a new internal_format value can be added.
+ */
+ uint32_t internal_format;
+ uint8_t sha1[20];
+ /* Fields following sha1 can be changed since the sha1 will guarantee that
+ * the binary only works with the same Mesa version.
+ */
+ uint32_t size;
+ uint32_t crc32;
+};
+
+/**
+ * Returns the header size needed for a binary
+ */
+static unsigned
+get_program_binary_header_size(void)
+{
+ return sizeof(struct program_binary_header);
+}
+
+static bool
+write_program_binary(const void *payload, unsigned payload_size,
+ const void *sha1, void *binary, unsigned binary_size,
+ GLenum *binary_format)
+{
+ struct program_binary_header *hdr = binary;
+
+ if (binary_size < sizeof(*hdr))
+ return false;
+
+ /* binary_size is the size of the buffer provided by the application.
+ * Make sure our program (payload) will fit in the buffer.
+ */
+ if (payload_size > binary_size - sizeof(*hdr))
+ return false;
+
+ hdr->internal_format = 0;
+ memcpy(hdr->sha1, sha1, sizeof(hdr->sha1));
+ memcpy(hdr + 1, payload, payload_size);
+ hdr->size = payload_size;
+
+ hdr->crc32 = util_hash_crc32(hdr + 1, payload_size);
+ *binary_format = GL_PROGRAM_BINARY_FORMAT_MESA;
+
+ return true;
+}
+
+static bool
+simple_header_checks(const struct program_binary_header *hdr, unsigned length)
+{
+ if (hdr == NULL || length < sizeof(*hdr))
+ return false;
+
+ if (hdr->internal_format != 0)
+ return false;
+
+ return true;
+}
+
+static bool
+check_crc32(const struct program_binary_header *hdr, unsigned length)
+{
+ uint32_t crc32;
+ unsigned crc32_len;
+
+ crc32_len = hdr->size;
+ if (crc32_len > length - sizeof(*hdr))
+ return false;
+
+ crc32 = util_hash_crc32(hdr + 1, crc32_len);
+ if (hdr->crc32 != crc32)
+ return false;
+
+ return true;
+}
+
+static bool
+is_program_binary_valid(GLenum binary_format, const void *sha1,
+ const struct program_binary_header *hdr,
+ unsigned length)
+{
+ if (binary_format != GL_PROGRAM_BINARY_FORMAT_MESA)
+ return false;
+
+ if (!simple_header_checks(hdr, length))
+ return false;
+
+ if (memcmp(hdr->sha1, sha1, sizeof(hdr->sha1)) != 0)
+ return false;
+
+ if (!check_crc32(hdr, length))
+ return false;
+
+ return true;
+}
+
+/**
+ * Returns the payload within the binary.
+ *
+ * If NULL is returned, then the binary not supported. If non-NULL is
+ * returned, it will be a pointer contained within the specified `binary`
+ * buffer.
+ *
+ * This can be used to access the payload of `binary` during the
+ * glProgramBinary call.
+ */
+static const void*
+get_program_binary_payload(GLenum binary_format, const void *sha1,
+ const void *binary, unsigned length)
+{
+ const struct program_binary_header *hdr = binary;
+ if (!is_program_binary_valid(binary_format, sha1, hdr, length))
+ return NULL;
+ return (const uint8_t*)binary + sizeof(*hdr);
+}
+
+static void
+write_program_payload(struct gl_context *ctx, struct blob *blob,
+ struct gl_shader_program *sh_prog)
+{
+ bool serialize[MESA_SHADER_STAGES];
+ for (unsigned stage = 0; stage < MESA_SHADER_STAGES; stage++) {
+ struct gl_linked_shader *shader = sh_prog->_LinkedShaders[stage];
+ serialize[stage] = shader && shader->Program->driver_cache_blob == NULL;
+ if (serialize[stage])
+ ctx->Driver.ProgramBinarySerializeDriverBlob(ctx, shader->Program);
+ }
+
+ serialize_glsl_program(blob, ctx, sh_prog);
+
+ for (unsigned stage = 0; stage < MESA_SHADER_STAGES; stage++) {
+ if (!serialize[stage])
+ continue;
+
+ struct gl_program *prog = sh_prog->_LinkedShaders[stage]->Program;
+ ralloc_free(prog->driver_cache_blob);
+ prog->driver_cache_blob = NULL;
+ prog->driver_cache_blob_size = 0;
+ }
+}
+
+static bool
+read_program_payload(struct gl_context *ctx, struct blob_reader *blob,
+ GLenum binary_format, struct gl_shader_program *sh_prog)
+{
+ if (!deserialize_glsl_program(blob, ctx, sh_prog))
+ return false;
+
+ unsigned int stage;
+ for (stage = 0; stage < ARRAY_SIZE(sh_prog->_LinkedShaders); stage++) {
+ struct gl_linked_shader *shader = sh_prog->_LinkedShaders[stage];
+ if (!shader)
+ continue;
+
+ ctx->Driver.ProgramBinaryDeserializeDriverBlob(ctx, sh_prog,
+ shader->Program);
+ }
+
+ return true;
+}
+
+void
+_mesa_get_program_binary_length(struct gl_context *ctx,
+ struct gl_shader_program *sh_prog,
+ GLint *length)
+{
+ struct blob blob;
+ blob_init_fixed(&blob, NULL, SIZE_MAX);
+ write_program_payload(ctx, &blob, sh_prog);
+ *length = get_program_binary_header_size() + blob.size;
+ blob_finish(&blob);
+}
+
+void
+_mesa_get_program_binary(struct gl_context *ctx,
+ struct gl_shader_program *sh_prog,
+ GLsizei buf_size, GLsizei *length,
+ GLenum *binary_format, GLvoid *binary)
+{
+ struct blob blob;
+ uint8_t driver_sha1[20];
+ unsigned header_size = get_program_binary_header_size();
+
+ ctx->Driver.GetProgramBinaryDriverSHA1(ctx, driver_sha1);
+
+ blob_init(&blob);
+
+ if (buf_size < header_size)
+ goto fail;
+
+ write_program_payload(ctx, &blob, sh_prog);
+ if (blob.size + header_size > buf_size ||
+ blob.out_of_memory)
+ goto fail;
+
+ bool written = write_program_binary(blob.data, blob.size, driver_sha1,
+ binary, buf_size, binary_format);
+ if (!written || blob.out_of_memory)
+ goto fail;
+
+ *length = header_size + blob.size;
+
+ blob_finish(&blob);
+ return;
+
+fail:
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glGetProgramBinary(buffer too small)");
+ *length = 0;
+ blob_finish(&blob);
+}
+
+void
+_mesa_program_binary(struct gl_context *ctx, struct gl_shader_program *sh_prog,
+ GLenum binary_format, const GLvoid *binary,
+ GLsizei length)
+{
+ uint8_t driver_sha1[20];
+ unsigned header_size = get_program_binary_header_size();
+
+ ctx->Driver.GetProgramBinaryDriverSHA1(ctx, driver_sha1);
+
+ const void *payload = get_program_binary_payload(binary_format, driver_sha1,
+ binary, length);
+
+ if (payload == NULL) {
+ sh_prog->data->LinkStatus = linking_failure;
+ return;
+ }
+
+ struct blob_reader blob;
+ blob_reader_init(&blob, payload, length - header_size);
+
+ if (!read_program_payload(ctx, &blob, binary_format, sh_prog)) {
+ sh_prog->data->LinkStatus = linking_failure;
+ return;
+ }
+
+ sh_prog->data->LinkStatus = linking_success;
+}
diff --git a/src/mesa/main/program_binary.h b/src/mesa/main/program_binary.h
new file mode 100644
index 00000000000..9e16b9ec54d
--- /dev/null
+++ b/src/mesa/main/program_binary.h
@@ -0,0 +1,56 @@
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 2004-2007 Brian Paul All Rights Reserved.
+ * Copyright (C) 2010 VMware, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef PROGRAM_BINARY_H
+#define PROGRAM_BINARY_H
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void
+_mesa_get_program_binary_length(struct gl_context *ctx,
+ struct gl_shader_program *sh_prog,
+ GLint *length);
+
+void
+_mesa_get_program_binary(struct gl_context *ctx,
+ struct gl_shader_program *sh_prog,
+ GLsizei buf_size, GLsizei *length,
+ GLenum *binary_format, GLvoid *binary);
+
+void
+_mesa_program_binary(struct gl_context *ctx, struct gl_shader_program *sh_prog,
+ GLenum binary_format, const GLvoid *binary,
+ GLsizei length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PROGRAM_BINARY_H */
diff --git a/src/mesa/meson.build b/src/mesa/meson.build
index 05a3a9ac55d..670c3d22d24 100644
--- a/src/mesa/meson.build
+++ b/src/mesa/meson.build
@@ -208,20 +208,22 @@ files_libmesa_common = files(
'main/pixel.c',
'main/pixel.h',
'main/pixelstore.c',
'main/pixelstore.h',
'main/pixeltransfer.c',
'main/pixeltransfer.h',
'main/points.c',
'main/points.h',
'main/polygon.c',
'main/polygon.h',
+ 'main/program_binary.c',
+ 'main/program_binary.h',
'main/program_resource.c',
'main/program_resource.h',
'main/querymatrix.c',
'main/querymatrix.h',
'main/queryobj.c',
'main/queryobj.h',
'main/rastpos.c',
'main/rastpos.h',
'main/readpix.c',
'main/readpix.h',
--
2.14.3
Tapani Pälli
2017-12-07 13:53:04 UTC
Reply
Permalink
Raw Message
This looks good as well, I've spent also some quality debugger time
today with these bits and my EGL_ANDROID_blob_cache branch. I'll be
using these functions and probably do some minor refactors so that
glGetProgramBinary() errors won't get printed when Android cache calls this.
Post by Timothy Arceri
- add extra code comment
- stop passing around void *binary and just pass
program_binary_header *hdr instead.
- move to src/mesa/main rather than src/util
- Move more code out of the backend and into the common
helpers.
---
src/mesa/Makefile.sources | 2 +
src/mesa/main/program_binary.c | 291 +++++++++++++++++++++++++++++++++++++++++
src/mesa/main/program_binary.h | 56 ++++++++
src/mesa/meson.build | 2 +
4 files changed, 351 insertions(+)
create mode 100644 src/mesa/main/program_binary.c
create mode 100644 src/mesa/main/program_binary.h
diff --git a/src/mesa/Makefile.sources b/src/mesa/Makefile.sources
index 6da1e3fef9d..d8b1eb1f995 100644
--- a/src/mesa/Makefile.sources
+++ b/src/mesa/Makefile.sources
@@ -166,20 +166,22 @@ MAIN_FILES = \
main/pixel.c \
main/pixel.h \
main/pixelstore.c \
main/pixelstore.h \
main/pixeltransfer.c \
main/pixeltransfer.h \
main/points.c \
main/points.h \
main/polygon.c \
main/polygon.h \
+ main/program_binary.c \
+ main/program_binary.h \
main/program_resource.c \
main/program_resource.h \
main/querymatrix.c \
main/querymatrix.h \
main/queryobj.c \
main/queryobj.h \
main/rastpos.c \
main/rastpos.h \
main/readpix.c \
main/readpix.h \
diff --git a/src/mesa/main/program_binary.c b/src/mesa/main/program_binary.c
new file mode 100644
index 00000000000..2786487362f
--- /dev/null
+++ b/src/mesa/main/program_binary.c
@@ -0,0 +1,291 @@
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (c) 2017 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file program_binary.c
+ *
+ * Helper functions for serializing a binary program.
+ */
+
+
+#include "compiler/blob.h"
+#include "compiler/glsl/serialize.h"
+#include "main/errors.h"
+#include "main/mtypes.h"
+#include "util/crc32.h"
+#include "program_binary.h"
+#include "program/prog_parameter.h"
+
+/**
+ * Mesa supports one binary format, but it must differentiate between formats
+ * produced by different drivers and different Mesa versions.
+ *
+ * Mesa uses a uint32_t value to specify an internal format. The only format
+ * defined has one uint32_t value of 0, followed by 20 bytes specifying a sha1
+ * that uniquely identifies the Mesa driver type and version.
+ */
+
+struct program_binary_header {
+ /* If internal_format is 0, it must be followed by the 20 byte sha1 that
+ * identifies the Mesa driver and version supported. If we want to support
+ * something besides a sha1, then a new internal_format value can be added.
+ */
+ uint32_t internal_format;
+ uint8_t sha1[20];
+ /* Fields following sha1 can be changed since the sha1 will guarantee that
+ * the binary only works with the same Mesa version.
+ */
+ uint32_t size;
+ uint32_t crc32;
+};
+
+/**
+ * Returns the header size needed for a binary
+ */
+static unsigned
+get_program_binary_header_size(void)
+{
+ return sizeof(struct program_binary_header);
+}
+
+static bool
+write_program_binary(const void *payload, unsigned payload_size,
+ const void *sha1, void *binary, unsigned binary_size,
+ GLenum *binary_format)
+{
+ struct program_binary_header *hdr = binary;
+
+ if (binary_size < sizeof(*hdr))
+ return false;
+
+ /* binary_size is the size of the buffer provided by the application.
+ * Make sure our program (payload) will fit in the buffer.
+ */
+ if (payload_size > binary_size - sizeof(*hdr))
+ return false;
+
+ hdr->internal_format = 0;
+ memcpy(hdr->sha1, sha1, sizeof(hdr->sha1));
+ memcpy(hdr + 1, payload, payload_size);
+ hdr->size = payload_size;
+
+ hdr->crc32 = util_hash_crc32(hdr + 1, payload_size);
+ *binary_format = GL_PROGRAM_BINARY_FORMAT_MESA;
+
+ return true;
+}
+
+static bool
+simple_header_checks(const struct program_binary_header *hdr, unsigned length)
+{
+ if (hdr == NULL || length < sizeof(*hdr))
+ return false;
+
+ if (hdr->internal_format != 0)
+ return false;
+
+ return true;
+}
+
+static bool
+check_crc32(const struct program_binary_header *hdr, unsigned length)
+{
+ uint32_t crc32;
+ unsigned crc32_len;
+
+ crc32_len = hdr->size;
+ if (crc32_len > length - sizeof(*hdr))
+ return false;
+
+ crc32 = util_hash_crc32(hdr + 1, crc32_len);
+ if (hdr->crc32 != crc32)
+ return false;
+
+ return true;
+}
+
+static bool
+is_program_binary_valid(GLenum binary_format, const void *sha1,
+ const struct program_binary_header *hdr,
+ unsigned length)
+{
+ if (binary_format != GL_PROGRAM_BINARY_FORMAT_MESA)
+ return false;
+
+ if (!simple_header_checks(hdr, length))
+ return false;
+
+ if (memcmp(hdr->sha1, sha1, sizeof(hdr->sha1)) != 0)
+ return false;
+
+ if (!check_crc32(hdr, length))
+ return false;
+
+ return true;
+}
+
+/**
+ * Returns the payload within the binary.
+ *
+ * If NULL is returned, then the binary not supported. If non-NULL is
+ * returned, it will be a pointer contained within the specified `binary`
+ * buffer.
+ *
+ * This can be used to access the payload of `binary` during the
+ * glProgramBinary call.
+ */
+static const void*
+get_program_binary_payload(GLenum binary_format, const void *sha1,
+ const void *binary, unsigned length)
+{
+ const struct program_binary_header *hdr = binary;
+ if (!is_program_binary_valid(binary_format, sha1, hdr, length))
+ return NULL;
+ return (const uint8_t*)binary + sizeof(*hdr);
+}
+
+static void
+write_program_payload(struct gl_context *ctx, struct blob *blob,
+ struct gl_shader_program *sh_prog)
+{
+ bool serialize[MESA_SHADER_STAGES];
+ for (unsigned stage = 0; stage < MESA_SHADER_STAGES; stage++) {
+ struct gl_linked_shader *shader = sh_prog->_LinkedShaders[stage];
+ serialize[stage] = shader && shader->Program->driver_cache_blob == NULL;
+ if (serialize[stage])
+ ctx->Driver.ProgramBinarySerializeDriverBlob(ctx, shader->Program);
+ }
+
+ serialize_glsl_program(blob, ctx, sh_prog);
+
+ for (unsigned stage = 0; stage < MESA_SHADER_STAGES; stage++) {
+ if (!serialize[stage])
+ continue;
+
+ struct gl_program *prog = sh_prog->_LinkedShaders[stage]->Program;
+ ralloc_free(prog->driver_cache_blob);
+ prog->driver_cache_blob = NULL;
+ prog->driver_cache_blob_size = 0;
+ }
+}
+
+static bool
+read_program_payload(struct gl_context *ctx, struct blob_reader *blob,
+ GLenum binary_format, struct gl_shader_program *sh_prog)
+{
+ if (!deserialize_glsl_program(blob, ctx, sh_prog))
+ return false;
+
+ unsigned int stage;
+ for (stage = 0; stage < ARRAY_SIZE(sh_prog->_LinkedShaders); stage++) {
+ struct gl_linked_shader *shader = sh_prog->_LinkedShaders[stage];
+ if (!shader)
+ continue;
+
+ ctx->Driver.ProgramBinaryDeserializeDriverBlob(ctx, sh_prog,
+ shader->Program);
+ }
+
+ return true;
+}
+
+void
+_mesa_get_program_binary_length(struct gl_context *ctx,
+ struct gl_shader_program *sh_prog,
+ GLint *length)
+{
+ struct blob blob;
+ blob_init_fixed(&blob, NULL, SIZE_MAX);
+ write_program_payload(ctx, &blob, sh_prog);
+ *length = get_program_binary_header_size() + blob.size;
+ blob_finish(&blob);
+}
+
+void
+_mesa_get_program_binary(struct gl_context *ctx,
+ struct gl_shader_program *sh_prog,
+ GLsizei buf_size, GLsizei *length,
+ GLenum *binary_format, GLvoid *binary)
+{
+ struct blob blob;
+ uint8_t driver_sha1[20];
+ unsigned header_size = get_program_binary_header_size();
+
+ ctx->Driver.GetProgramBinaryDriverSHA1(ctx, driver_sha1);
+
+ blob_init(&blob);
+
+ if (buf_size < header_size)
+ goto fail;
+
+ write_program_payload(ctx, &blob, sh_prog);
+ if (blob.size + header_size > buf_size ||
+ blob.out_of_memory)
+ goto fail;
+
+ bool written = write_program_binary(blob.data, blob.size, driver_sha1,
+ binary, buf_size, binary_format);
+ if (!written || blob.out_of_memory)
+ goto fail;
+
+ *length = header_size + blob.size;
+
+ blob_finish(&blob);
+ return;
+
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glGetProgramBinary(buffer too small)");
+ *length = 0;
+ blob_finish(&blob);
+}
+
+void
+_mesa_program_binary(struct gl_context *ctx, struct gl_shader_program *sh_prog,
+ GLenum binary_format, const GLvoid *binary,
+ GLsizei length)
+{
+ uint8_t driver_sha1[20];
+ unsigned header_size = get_program_binary_header_size();
+
+ ctx->Driver.GetProgramBinaryDriverSHA1(ctx, driver_sha1);
+
+ const void *payload = get_program_binary_payload(binary_format, driver_sha1,
+ binary, length);
+
+ if (payload == NULL) {
+ sh_prog->data->LinkStatus = linking_failure;
+ return;
+ }
+
+ struct blob_reader blob;
+ blob_reader_init(&blob, payload, length - header_size);
+
+ if (!read_program_payload(ctx, &blob, binary_format, sh_prog)) {
+ sh_prog->data->LinkStatus = linking_failure;
+ return;
+ }
+
+ sh_prog->data->LinkStatus = linking_success;
+}
diff --git a/src/mesa/main/program_binary.h b/src/mesa/main/program_binary.h
new file mode 100644
index 00000000000..9e16b9ec54d
--- /dev/null
+++ b/src/mesa/main/program_binary.h
@@ -0,0 +1,56 @@
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 2004-2007 Brian Paul All Rights Reserved.
+ * Copyright (C) 2010 VMware, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef PROGRAM_BINARY_H
+#define PROGRAM_BINARY_H
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void
+_mesa_get_program_binary_length(struct gl_context *ctx,
+ struct gl_shader_program *sh_prog,
+ GLint *length);
+
+void
+_mesa_get_program_binary(struct gl_context *ctx,
+ struct gl_shader_program *sh_prog,
+ GLsizei buf_size, GLsizei *length,
+ GLenum *binary_format, GLvoid *binary);
+
+void
+_mesa_program_binary(struct gl_context *ctx, struct gl_shader_program *sh_prog,
+ GLenum binary_format, const GLvoid *binary,
+ GLsizei length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PROGRAM_BINARY_H */
diff --git a/src/mesa/meson.build b/src/mesa/meson.build
index 05a3a9ac55d..670c3d22d24 100644
--- a/src/mesa/meson.build
+++ b/src/mesa/meson.build
@@ -208,20 +208,22 @@ files_libmesa_common = files(
'main/pixel.c',
'main/pixel.h',
'main/pixelstore.c',
'main/pixelstore.h',
'main/pixeltransfer.c',
'main/pixeltransfer.h',
'main/points.c',
'main/points.h',
'main/polygon.c',
'main/polygon.h',
+ 'main/program_binary.c',
+ 'main/program_binary.h',
'main/program_resource.c',
'main/program_resource.h',
'main/querymatrix.c',
'main/querymatrix.h',
'main/queryobj.c',
'main/queryobj.h',
'main/rastpos.c',
'main/rastpos.h',
'main/readpix.c',
'main/readpix.h',
Timothy Arceri
2017-11-29 01:24:56 UTC
Reply
Permalink
Raw Message
This will be used by ARB_get_program_binary.
---
src/mesa/state_tracker/st_shader_cache.c | 6 ++++++
src/mesa/state_tracker/st_shader_cache.h | 3 +++
2 files changed, 9 insertions(+)

diff --git a/src/mesa/state_tracker/st_shader_cache.c b/src/mesa/state_tracker/st_shader_cache.c
index 62d62f76117..a971b0d7ee7 100644
--- a/src/mesa/state_tracker/st_shader_cache.c
+++ b/src/mesa/state_tracker/st_shader_cache.c
@@ -23,20 +23,26 @@

#include <stdio.h>
#include "st_debug.h"
#include "st_program.h"
#include "st_shader_cache.h"
#include "compiler/glsl/program.h"
#include "pipe/p_shader_tokens.h"
#include "program/ir_to_mesa.h"
#include "util/u_memory.h"

+void
+st_get_program_binary_driver_sha1(struct gl_context *ctx, uint8_t *sha1)
+{
+ disk_cache_compute_key(ctx->Cache, NULL, 0, sha1);
+}
+
static void
write_stream_out_to_cache(struct blob *blob,
struct pipe_shader_state *tgsi)
{
blob_write_bytes(blob, &tgsi->stream_output,
sizeof(tgsi->stream_output));
}

static void
write_tgsi_to_cache(struct blob *blob, const struct tgsi_token *tokens,
diff --git a/src/mesa/state_tracker/st_shader_cache.h b/src/mesa/state_tracker/st_shader_cache.h
index 358c6ecef88..488035c7ed5 100644
--- a/src/mesa/state_tracker/st_shader_cache.h
+++ b/src/mesa/state_tracker/st_shader_cache.h
@@ -25,20 +25,23 @@
#include "compiler/blob.h"
#include "main/mtypes.h"
#include "pipe/p_state.h"
#include "util/disk_cache.h"
#include "util/mesa-sha1.h"

#ifdef __cplusplus
extern "C" {
#endif

+void
+st_get_program_binary_driver_sha1(struct gl_context *ctx, uint8_t *sha1);
+
void
st_serialise_tgsi_program(struct gl_context *ctx, struct gl_program *prog);

void
st_deserialise_tgsi_program(struct gl_context *ctx,
struct gl_shader_program *shProg,
struct gl_program *prog);

bool
st_load_tgsi_from_disk_cache(struct gl_context *ctx,
--
2.14.3
Timothy Arceri
2017-11-29 01:24:57 UTC
Reply
Permalink
Raw Message
This resolves a game bug in Deal Island. The game doesn't properly
handle ARB_get_program_binary with 0 supported formats, and ends up
crashing.

This will enable ARB_get_program_binary binary support for any
driver that currently enables the on-disk shader cache.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=85564
---
src/mesa/state_tracker/st_context.c | 6 ++++++
src/mesa/state_tracker/st_extensions.c | 4 ++++
2 files changed, 10 insertions(+)

diff --git a/src/mesa/state_tracker/st_context.c b/src/mesa/state_tracker/st_context.c
index da1cca471ba..6f6dd857d97 100644
--- a/src/mesa/state_tracker/st_context.c
+++ b/src/mesa/state_tracker/st_context.c
@@ -67,20 +67,21 @@
#include "st_cb_strings.h"
#include "st_cb_texturebarrier.h"
#include "st_cb_viewport.h"
#include "st_atom.h"
#include "st_draw.h"
#include "st_extensions.h"
#include "st_gen_mipmap.h"
#include "st_pbo.h"
#include "st_program.h"
#include "st_sampler_view.h"
+#include "st_shader_cache.h"
#include "st_vdpau.h"
#include "st_texture.h"
#include "pipe/p_context.h"
#include "util/u_inlines.h"
#include "util/u_upload_mgr.h"
#include "util/u_vbuf.h"
#include "cso_cache/cso_context.h"


DEBUG_GET_ONCE_BOOL_OPTION(mesa_mvp_dp4, "MESA_MVP_DP4", FALSE)
@@ -753,11 +754,16 @@ st_init_driver_functions(struct pipe_screen *screen,

if (screen->get_param(screen, PIPE_CAP_STRING_MARKER))
functions->EmitStringMarker = st_emit_string_marker;

functions->Enable = st_Enable;
functions->UpdateState = st_invalidate_state;
functions->QueryMemoryInfo = st_query_memory_info;
functions->SetBackgroundContext = st_set_background_context;
functions->GetDriverUuid = st_get_device_uuid;
functions->GetDeviceUuid = st_get_driver_uuid;
+
+ /* GL_ARB_get_program_binary */
+ functions->GetProgramBinaryDriverSHA1 = st_get_program_binary_driver_sha1;
+ functions->ProgramBinarySerializeDriverBlob = st_serialise_tgsi_program;
+ functions->ProgramBinaryDeserializeDriverBlob = st_deserialise_tgsi_program;
}
diff --git a/src/mesa/state_tracker/st_extensions.c b/src/mesa/state_tracker/st_extensions.c
index de3d1ef4e9b..d4cb901f911 100644
--- a/src/mesa/state_tracker/st_extensions.c
+++ b/src/mesa/state_tracker/st_extensions.c
@@ -410,20 +410,24 @@ void st_init_limits(struct pipe_screen *screen,
c->Program[MESA_SHADER_FRAGMENT].MaxUniformBlocks +
c->Program[MESA_SHADER_COMPUTE].MaxUniformBlocks;
assert(c->MaxCombinedUniformBlocks <= MAX_COMBINED_UNIFORM_BUFFERS);
}

c->GLSLFragCoordIsSysVal =
screen->get_param(screen, PIPE_CAP_TGSI_FS_POSITION_IS_SYSVAL);
c->GLSLFrontFacingIsSysVal =
screen->get_param(screen, PIPE_CAP_TGSI_FS_FACE_IS_INTEGER_SYSVAL);

+ /* GL_ARB_get_program_binary */
+ if (screen->get_disk_shader_cache && screen->get_disk_shader_cache(screen))
+ c->NumProgramBinaryFormats = 1;
+
c->MaxAtomicBufferBindings =
c->Program[MESA_SHADER_FRAGMENT].MaxAtomicBuffers;

if (!ssbo_atomic) {
/* for separate atomic buffers - there atomic buffer size will be
limited */
c->MaxAtomicBufferSize = c->Program[MESA_SHADER_FRAGMENT].MaxAtomicCounters * ATOMIC_COUNTER_SIZE;
/* on all HW with separate atomic (evergreen) the following
lines are true. not sure it's worth adding CAPs for this at this
stage. */
--
2.14.3
Timothy Arceri
2017-11-29 01:24:55 UTC
Reply
Permalink
Raw Message
These will be shared between the on-disk shader cache and
ARB_get_program_binary.
---
src/mesa/state_tracker/st_shader_cache.c | 265 ++++++++++++++++---------------
src/mesa/state_tracker/st_shader_cache.h | 8 +
2 files changed, 146 insertions(+), 127 deletions(-)

diff --git a/src/mesa/state_tracker/st_shader_cache.c b/src/mesa/state_tracker/st_shader_cache.c
index 1d9b1727552..62d62f76117 100644
--- a/src/mesa/state_tracker/st_shader_cache.c
+++ b/src/mesa/state_tracker/st_shader_cache.c
@@ -43,36 +43,23 @@ write_tgsi_to_cache(struct blob *blob, const struct tgsi_token *tokens,
struct gl_program *prog, unsigned num_tokens)
{
blob_write_uint32(blob, num_tokens);
blob_write_bytes(blob, tokens, num_tokens * sizeof(struct tgsi_token));

prog->driver_cache_blob = ralloc_size(NULL, blob->size);
memcpy(prog->driver_cache_blob, blob->data, blob->size);
prog->driver_cache_blob_size = blob->size;
}

-/**
- * Store tgsi and any other required state in on-disk shader cache.
- */
void
-st_store_tgsi_in_disk_cache(struct st_context *st, struct gl_program *prog)
+st_serialise_tgsi_program(struct gl_context *ctx, struct gl_program *prog)
{
- if (!st->ctx->Cache)
- return;
-
- /* Exit early when we are dealing with a ff shader with no source file to
- * generate a source from.
- */
- static const char zero[sizeof(prog->sh.data->sha1)] = {0};
- if (memcmp(prog->sh.data->sha1, zero, sizeof(prog->sh.data->sha1)) == 0)
- return;
-
struct blob blob;
blob_init(&blob);

switch (prog->info.stage) {
case MESA_SHADER_VERTEX: {
struct st_vertex_program *stvp = (struct st_vertex_program *) prog;

blob_write_uint32(&blob, stvp->num_inputs);
blob_write_bytes(&blob, stvp->index_to_input,
sizeof(stvp->index_to_input));
@@ -105,193 +92,217 @@ st_store_tgsi_in_disk_cache(struct st_context *st, struct gl_program *prog)
struct st_compute_program *stcp = (struct st_compute_program *) prog;

write_tgsi_to_cache(&blob, stcp->tgsi.prog, prog,
stcp->num_tgsi_tokens);
break;
}
default:
unreachable("Unsupported stage");
}

+ blob_finish(&blob);
+}
+
+/**
+ * Store tgsi and any other required state in on-disk shader cache.
+ */
+void
+st_store_tgsi_in_disk_cache(struct st_context *st, struct gl_program *prog)
+{
+ if (!st->ctx->Cache)
+ return;
+
+ /* Exit early when we are dealing with a ff shader with no source file to
+ * generate a source from.
+ */
+ static const char zero[sizeof(prog->sh.data->sha1)] = {0};
+ if (memcmp(prog->sh.data->sha1, zero, sizeof(prog->sh.data->sha1)) == 0)
+ return;
+
+ st_serialise_tgsi_program(st->ctx, prog);
+
if (st->ctx->_Shader->Flags & GLSL_CACHE_INFO) {
fprintf(stderr, "putting %s tgsi_tokens in cache\n",
_mesa_shader_stage_to_string(prog->info.stage));
}
-
- blob_finish(&blob);
}

static void
read_stream_out_from_cache(struct blob_reader *blob_reader,
struct pipe_shader_state *tgsi)
{
blob_copy_bytes(blob_reader, (uint8_t *) &tgsi->stream_output,
sizeof(tgsi->stream_output));
}

static void
read_tgsi_from_cache(struct blob_reader *blob_reader,
const struct tgsi_token **tokens)
{
uint32_t num_tokens = blob_read_uint32(blob_reader);
unsigned tokens_size = num_tokens * sizeof(struct tgsi_token);
*tokens = (const struct tgsi_token*) MALLOC(tokens_size);
blob_copy_bytes(blob_reader, (uint8_t *) *tokens, tokens_size);
}

-bool
-st_load_tgsi_from_disk_cache(struct gl_context *ctx,
- struct gl_shader_program *prog)
+void
+st_deserialise_tgsi_program(struct gl_context *ctx,
+ struct gl_shader_program *shProg,
+ struct gl_program *prog)
{
- if (!ctx->Cache)
- return false;
-
- /* If we didn't load the GLSL metadata from cache then we could not have
- * loaded the tgsi either.
- */
- if (prog->data->LinkStatus != linking_skipped)
- return false;
-
struct st_context *st = st_context(ctx);
- for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
- if (prog->_LinkedShaders[i] == NULL)
- continue;
+ size_t size = prog->driver_cache_blob_size;
+ uint8_t *buffer = (uint8_t *) prog->driver_cache_blob;

- struct gl_program *glprog = prog->_LinkedShaders[i]->Program;
+ struct blob_reader blob_reader;
+ blob_reader_init(&blob_reader, buffer, size);

- size_t size = glprog->driver_cache_blob_size;
- uint8_t *buffer = (uint8_t *) glprog->driver_cache_blob;
+ switch (prog->info.stage) {
+ case MESA_SHADER_VERTEX: {
+ struct st_vertex_program *stvp = (struct st_vertex_program *) prog;

- struct blob_reader blob_reader;
- blob_reader_init(&blob_reader, buffer, size);
+ st_release_vp_variants(st, stvp);

- switch (glprog->info.stage) {
- case MESA_SHADER_VERTEX: {
- struct st_vertex_program *stvp = (struct st_vertex_program *) glprog;
+ stvp->num_inputs = blob_read_uint32(&blob_reader);
+ blob_copy_bytes(&blob_reader, (uint8_t *) stvp->index_to_input,
+ sizeof(stvp->index_to_input));
+ blob_copy_bytes(&blob_reader, (uint8_t *) stvp->result_to_output,
+ sizeof(stvp->result_to_output));

- st_release_vp_variants(st, stvp);
+ read_stream_out_from_cache(&blob_reader, &stvp->tgsi);
+ read_tgsi_from_cache(&blob_reader, &stvp->tgsi.tokens);

- stvp->num_inputs = blob_read_uint32(&blob_reader);
- blob_copy_bytes(&blob_reader, (uint8_t *) stvp->index_to_input,
- sizeof(stvp->index_to_input));
- blob_copy_bytes(&blob_reader, (uint8_t *) stvp->result_to_output,
- sizeof(stvp->result_to_output));
+ if (st->vp == stvp)
+ st->dirty |= ST_NEW_VERTEX_PROGRAM(st, stvp);

- read_stream_out_from_cache(&blob_reader, &stvp->tgsi);
- read_tgsi_from_cache(&blob_reader, &stvp->tgsi.tokens);
+ break;
+ }
+ case MESA_SHADER_TESS_CTRL: {
+ struct st_common_program *sttcp = st_common_program(prog);

- if (st->vp == stvp)
- st->dirty |= ST_NEW_VERTEX_PROGRAM(st, stvp);
+ st_release_basic_variants(st, sttcp->Base.Target,
+ &sttcp->variants, &sttcp->tgsi);

- break;
- }
- case MESA_SHADER_TESS_CTRL: {
- struct st_common_program *sttcp = st_common_program(glprog);
+ read_stream_out_from_cache(&blob_reader, &sttcp->tgsi);
+ read_tgsi_from_cache(&blob_reader, &sttcp->tgsi.tokens);

- st_release_basic_variants(st, sttcp->Base.Target,
- &sttcp->variants, &sttcp->tgsi);
+ if (st->tcp == sttcp)
+ st->dirty |= sttcp->affected_states;

- read_stream_out_from_cache(&blob_reader, &sttcp->tgsi);
- read_tgsi_from_cache(&blob_reader, &sttcp->tgsi.tokens);
+ break;
+ }
+ case MESA_SHADER_TESS_EVAL: {
+ struct st_common_program *sttep = st_common_program(prog);

- if (st->tcp == sttcp)
- st->dirty |= sttcp->affected_states;
+ st_release_basic_variants(st, sttep->Base.Target,
+ &sttep->variants, &sttep->tgsi);

- break;
- }
- case MESA_SHADER_TESS_EVAL: {
- struct st_common_program *sttep = st_common_program(glprog);
+ read_stream_out_from_cache(&blob_reader, &sttep->tgsi);
+ read_tgsi_from_cache(&blob_reader, &sttep->tgsi.tokens);

- st_release_basic_variants(st, sttep->Base.Target,
- &sttep->variants, &sttep->tgsi);
+ if (st->tep == sttep)
+ st->dirty |= sttep->affected_states;

- read_stream_out_from_cache(&blob_reader, &sttep->tgsi);
- read_tgsi_from_cache(&blob_reader, &sttep->tgsi.tokens);
+ break;
+ }
+ case MESA_SHADER_GEOMETRY: {
+ struct st_common_program *stgp = st_common_program(prog);

- if (st->tep == sttep)
- st->dirty |= sttep->affected_states;
+ st_release_basic_variants(st, stgp->Base.Target, &stgp->variants,
+ &stgp->tgsi);

- break;
- }
- case MESA_SHADER_GEOMETRY: {
- struct st_common_program *stgp = st_common_program(glprog);
+ read_stream_out_from_cache(&blob_reader, &stgp->tgsi);
+ read_tgsi_from_cache(&blob_reader, &stgp->tgsi.tokens);

- st_release_basic_variants(st, stgp->Base.Target, &stgp->variants,
- &stgp->tgsi);
+ if (st->gp == stgp)
+ st->dirty |= stgp->affected_states;

- read_stream_out_from_cache(&blob_reader, &stgp->tgsi);
- read_tgsi_from_cache(&blob_reader, &stgp->tgsi.tokens);
+ break;
+ }
+ case MESA_SHADER_FRAGMENT: {
+ struct st_fragment_program *stfp = (struct st_fragment_program *) prog;

- if (st->gp == stgp)
- st->dirty |= stgp->affected_states;
+ st_release_fp_variants(st, stfp);

- break;
- }
- case MESA_SHADER_FRAGMENT: {
- struct st_fragment_program *stfp =
- (struct st_fragment_program *) glprog;
+ read_tgsi_from_cache(&blob_reader, &stfp->tgsi.tokens);

- st_release_fp_variants(st, stfp);
+ if (st->fp == stfp)
+ st->dirty |= stfp->affected_states;

- read_tgsi_from_cache(&blob_reader, &stfp->tgsi.tokens);
+ break;
+ }
+ case MESA_SHADER_COMPUTE: {
+ struct st_compute_program *stcp = (struct st_compute_program *) prog;

- if (st->fp == stfp)
- st->dirty |= stfp->affected_states;
+ st_release_cp_variants(st, stcp);

- break;
- }
- case MESA_SHADER_COMPUTE: {
- struct st_compute_program *stcp =
- (struct st_compute_program *) glprog;
+ read_tgsi_from_cache(&blob_reader,
+ (const struct tgsi_token**) &stcp->tgsi.prog);

- st_release_cp_variants(st, stcp);
+ stcp->tgsi.req_local_mem = stcp->Base.info.cs.shared_size;
+ stcp->tgsi.req_private_mem = 0;
+ stcp->tgsi.req_input_mem = 0;

- read_tgsi_from_cache(&blob_reader,
- (const struct tgsi_token**) &stcp->tgsi.prog);
+ if (st->cp == stcp)
+ st->dirty |= stcp->affected_states;

- stcp->tgsi.req_local_mem = stcp->Base.info.cs.shared_size;
- stcp->tgsi.req_private_mem = 0;
- stcp->tgsi.req_input_mem = 0;
+ break;
+ }
+ default:
+ unreachable("Unsupported stage");
+ }

- if (st->cp == stcp)
- st->dirty |= stcp->affected_states;
+ /* Make sure we don't try to read more data than we wrote. This should
+ * never happen in release builds but its useful to have this check to
+ * catch development bugs.
+ */
+ if (blob_reader.current != blob_reader.end || blob_reader.overrun) {
+ assert(!"Invalid TGSI shader disk cache item!");

- break;
- }
- default:
- unreachable("Unsupported stage");
+ if (ctx->_Shader->Flags & GLSL_CACHE_INFO) {
+ fprintf(stderr, "Error reading program from cache (invalid "
+ "TGSI cache item)\n");
}
+ }

- /* Make sure we don't try to read more data than we wrote. This should
- * never happen in release builds but its useful to have this check to
- * catch development bugs.
- */
- if (blob_reader.current != blob_reader.end || blob_reader.overrun) {
- assert(!"Invalid TGSI shader disk cache item!");
-
- if (ctx->_Shader->Flags & GLSL_CACHE_INFO) {
- fprintf(stderr, "Error reading program from cache (invalid "
- "TGSI cache item)\n");
- }
- }
+ st_set_prog_affected_state_flags(prog);
+ _mesa_associate_uniform_storage(ctx, shProg, prog, false);

- if (ctx->_Shader->Flags & GLSL_CACHE_INFO) {
- fprintf(stderr, "%s tgsi_tokens retrieved from cache\n",
- _mesa_shader_stage_to_string(i));
- }
+ /* Create Gallium shaders now instead of on demand. */
+ if (ST_DEBUG & DEBUG_PRECOMPILE ||
+ st->shader_has_one_variant[prog->info.stage])
+ st_precompile_shader_variant(st, prog);
+}
+
+bool
+st_load_tgsi_from_disk_cache(struct gl_context *ctx,
+ struct gl_shader_program *prog)
+{
+ if (!ctx->Cache)
+ return false;
+
+ /* If we didn't load the GLSL metadata from cache then we could not have
+ * loaded the tgsi either.
+ */
+ if (prog->data->LinkStatus != linking_skipped)
+ return false;

- st_set_prog_affected_state_flags(glprog);
- _mesa_associate_uniform_storage(ctx, prog, glprog, false);
+ for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
+ if (prog->_LinkedShaders[i] == NULL)
+ continue;

- /* Create Gallium shaders now instead of on demand. */
- if (ST_DEBUG & DEBUG_PRECOMPILE ||
- st->shader_has_one_variant[glprog->info.stage])
- st_precompile_shader_variant(st, glprog);
+ struct gl_program *glprog = prog->_LinkedShaders[i]->Program;
+ st_deserialise_tgsi_program(ctx, prog, glprog);

/* We don't need the cached blob anymore so free it */
ralloc_free(glprog->driver_cache_blob);
glprog->driver_cache_blob = NULL;
glprog->driver_cache_blob_size = 0;
+
+ if (ctx->_Shader->Flags & GLSL_CACHE_INFO) {
+ fprintf(stderr, "%s tgsi_tokens retrieved from cache\n",
+ _mesa_shader_stage_to_string(i));
+ }
}

return true;
}
diff --git a/src/mesa/state_tracker/st_shader_cache.h b/src/mesa/state_tracker/st_shader_cache.h
index 81a2935d7ba..358c6ecef88 100644
--- a/src/mesa/state_tracker/st_shader_cache.h
+++ b/src/mesa/state_tracker/st_shader_cache.h
@@ -25,20 +25,28 @@
#include "compiler/blob.h"
#include "main/mtypes.h"
#include "pipe/p_state.h"
#include "util/disk_cache.h"
#include "util/mesa-sha1.h"

#ifdef __cplusplus
extern "C" {
#endif

+void
+st_serialise_tgsi_program(struct gl_context *ctx, struct gl_program *prog);
+
+void
+st_deserialise_tgsi_program(struct gl_context *ctx,
+ struct gl_shader_program *shProg,
+ struct gl_program *prog);
+
bool
st_load_tgsi_from_disk_cache(struct gl_context *ctx,
struct gl_shader_program *prog);

void
st_store_tgsi_in_disk_cache(struct st_context *st, struct gl_program *prog);

#ifdef __cplusplus
}
#endif
--
2.14.3
Timothy Arceri
2017-11-29 01:24:58 UTC
Reply
Permalink
Raw Message
From: Jordan Justen <***@intel.com>

This resolves an apparent game bug described in 85564. The game
doesn't properly handle ARB_get_program_binary with 0 supported
formats.

V2 (Timothy Arceri):
- less driver code as more has been moved into the common helpers.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=85564
Signed-off-by: Timothy Arceri <***@itsqueeze.com>
Signed-off-by: Jordan Justen <***@intel.com> (v1)
---
src/mesa/drivers/dri/i965/Makefile.sources | 1 +
src/mesa/drivers/dri/i965/brw_context.c | 10 ++++
src/mesa/drivers/dri/i965/brw_context.h | 16 ++++++
src/mesa/drivers/dri/i965/brw_program.h | 7 ---
src/mesa/drivers/dri/i965/brw_program_binary.c | 72 ++++++++++++++++++++++++++
src/mesa/drivers/dri/i965/meson.build | 1 +
6 files changed, 100 insertions(+), 7 deletions(-)
create mode 100644 src/mesa/drivers/dri/i965/brw_program_binary.c

diff --git a/src/mesa/drivers/dri/i965/Makefile.sources b/src/mesa/drivers/dri/i965/Makefile.sources
index 2980cdb3c54..3fba8dc17ef 100644
--- a/src/mesa/drivers/dri/i965/Makefile.sources
+++ b/src/mesa/drivers/dri/i965/Makefile.sources
@@ -30,20 +30,21 @@ i965_FILES = \
brw_meta_util.h \
brw_misc_state.c \
brw_multisample_state.h \
brw_nir_uniforms.cpp \
brw_object_purgeable.c \
brw_pipe_control.c \
brw_performance_query.h \
brw_performance_query.c \
brw_program.c \
brw_program.h \
+ brw_program_binary.c \
brw_program_cache.c \
brw_primitive_restart.c \
brw_queryobj.c \
brw_reset.c \
brw_sf.c \
brw_state.h \
brw_state_upload.c \
brw_structs.h \
brw_surface_formats.c \
brw_sync.c \
diff --git a/src/mesa/drivers/dri/i965/brw_context.c b/src/mesa/drivers/dri/i965/brw_context.c
index dd55b436698..5cd759f7356 100644
--- a/src/mesa/drivers/dri/i965/brw_context.c
+++ b/src/mesa/drivers/dri/i965/brw_context.c
@@ -322,20 +322,27 @@ brw_init_driver_functions(struct brw_context *brw,
functions->BeginTransformFeedback = brw_begin_transform_feedback;
functions->EndTransformFeedback = brw_end_transform_feedback;
functions->PauseTransformFeedback = brw_pause_transform_feedback;
functions->ResumeTransformFeedback = brw_resume_transform_feedback;
functions->GetTransformFeedbackVertexCount =
brw_get_transform_feedback_vertex_count;
}

if (devinfo->gen >= 6)
functions->GetSamplePosition = gen6_get_sample_position;
+
+ /* GL_ARB_get_program_binary */
+ brw_program_binary_init(brw->screen->deviceID);
+ functions->GetProgramBinaryDriverSHA1 = brw_get_program_binary_driver_sha1;
+ functions->ProgramBinarySerializeDriverBlob = brw_program_serialize_nir;
+ functions->ProgramBinaryDeserializeDriverBlob =
+ brw_deserialize_program_binary;
}

static void
brw_initialize_context_constants(struct brw_context *brw)
{
const struct gen_device_info *devinfo = &brw->screen->devinfo;
struct gl_context *ctx = &brw->ctx;
const struct brw_compiler *compiler = brw->screen->compiler;

const bool stage_exists[MESA_SHADER_STAGES] = {
@@ -689,20 +696,23 @@ brw_initialize_context_constants(struct brw_context *brw)
* pull an entire cache line at a time for constant offset loads both of
* which support almost any alignment.
*
* [1] glsl-1.40/uniform_buffer/vs-float-array-variable-index.shader_test
*/
if (devinfo->gen >= 7)
ctx->Const.UseSTD430AsDefaultPacking = true;

if (!(ctx->Const.ContextFlags & GL_CONTEXT_FLAG_DEBUG_BIT))
ctx->Const.AllowMappedBuffersDuringExecution = true;
+
+ /* GL_ARB_get_program_binary */
+ ctx->Const.NumProgramBinaryFormats = 1;
}

static void
brw_initialize_cs_context_constants(struct brw_context *brw)
{
struct gl_context *ctx = &brw->ctx;
const struct intel_screen *screen = brw->screen;
struct gen_device_info *devinfo = &brw->screen->devinfo;

/* FINISHME: Do this for all platforms that the kernel supports */
diff --git a/src/mesa/drivers/dri/i965/brw_context.h b/src/mesa/drivers/dri/i965/brw_context.h
index b3d7c6baf8a..da88bea739e 100644
--- a/src/mesa/drivers/dri/i965/brw_context.h
+++ b/src/mesa/drivers/dri/i965/brw_context.h
@@ -1539,20 +1539,36 @@ gen7_upload_urb(struct brw_context *brw, unsigned vs_size,
/* brw_reset.c */
extern GLenum
brw_get_graphics_reset_status(struct gl_context *ctx);
void
brw_check_for_reset(struct brw_context *brw);

/* brw_compute.c */
extern void
brw_init_compute_functions(struct dd_function_table *functions);

+/* brw_program_binary.c */
+extern void
+brw_program_binary_init(unsigned device_id);
+extern void
+brw_get_program_binary_driver_sha1(struct gl_context *ctx, uint8_t *sha1);
+extern void
+brw_deserialize_program_binary(struct gl_context *ctx,
+ struct gl_shader_program *shProg,
+ struct gl_program *prog);
+void
+brw_program_serialize_nir(struct gl_context *ctx, struct gl_program *prog,
+ gl_shader_stage stage);
+void
+brw_program_deserialize_nir(struct gl_context *ctx, struct gl_program *prog,
+ gl_shader_stage stage);
+
/*======================================================================
* Inline conversion functions. These are better-typed than the
* macros used previously:
*/
static inline struct brw_context *
brw_context( struct gl_context *ctx )
{
return (struct brw_context *)ctx;
}

diff --git a/src/mesa/drivers/dri/i965/brw_program.h b/src/mesa/drivers/dri/i965/brw_program.h
index a5e41522841..701b8da482e 100644
--- a/src/mesa/drivers/dri/i965/brw_program.h
+++ b/src/mesa/drivers/dri/i965/brw_program.h
@@ -74,27 +74,20 @@ void brw_populate_sampler_prog_key_data(struct gl_context *ctx,
bool brw_debug_recompile_sampler_key(struct brw_context *brw,
const struct brw_sampler_prog_key_data *old_key,
const struct brw_sampler_prog_key_data *key);

uint32_t
brw_assign_common_binding_table_offsets(const struct gen_device_info *devinfo,
const struct gl_program *prog,
struct brw_stage_prog_data *stage_prog_data,
uint32_t next_binding_table_offset);

-void
-brw_program_serialize_nir(struct gl_context *ctx, struct gl_program *prog,
- gl_shader_stage stage);
-void
-brw_program_deserialize_nir(struct gl_context *ctx, struct gl_program *prog,
- gl_shader_stage stage);
-
void
brw_stage_prog_data_free(const void *prog_data);

void
brw_dump_arb_asm(const char *stage, struct gl_program *prog);

bool brw_vs_precompile(struct gl_context *ctx, struct gl_program *prog);
bool brw_tcs_precompile(struct gl_context *ctx,
struct gl_shader_program *shader_prog,
struct gl_program *prog);
diff --git a/src/mesa/drivers/dri/i965/brw_program_binary.c b/src/mesa/drivers/dri/i965/brw_program_binary.c
new file mode 100644
index 00000000000..f1b327de4b3
--- /dev/null
+++ b/src/mesa/drivers/dri/i965/brw_program_binary.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2017 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "util/build_id.h"
+#include "util/mesa-sha1.h"
+
+#include "brw_context.h"
+#include "brw_program.h"
+
+static uint8_t driver_sha1[20];
+
+void
+brw_program_binary_init(unsigned device_id)
+{
+ const struct build_id_note *note =
+ build_id_find_nhdr_for_addr(brw_program_binary_init);
+ assert(note);
+
+ /**
+ * With Mesa's megadrivers, taking the sha1 of i965_dri.so may not be
+ * unique. Therefore, we make a sha1 of the "i965" string and the sha1
+ * build id from i965_dri.so.
+ */
+ struct mesa_sha1 ctx;
+ _mesa_sha1_init(&ctx);
+ char renderer[10];
+ assert(device_id < 0x10000);
+ int len = snprintf(renderer, sizeof(renderer), "i965_%04x", device_id);
+ assert(len == sizeof(renderer) - 1);
+ _mesa_sha1_update(&ctx, renderer, len);
+ _mesa_sha1_update(&ctx, build_id_data(note), build_id_length(note));
+ _mesa_sha1_final(&ctx, driver_sha1);
+}
+
+void
+brw_get_program_binary_driver_sha1(struct gl_context *ctx, uint8_t *sha1)
+{
+ memcpy(sha1, driver_sha1, sizeof(uint8_t) * 20);
+}
+
+/* This is just a wrapper around brw_program_deserialize_nir() as i965
+ * doesn't need gl_shader_program like other drivers do.
+ */
+void
+brw_deserialize_program_binary(struct gl_context *ctx,
+ struct gl_shader_program *shProg,
+ struct gl_program *prog)
+{
+ brw_program_deserialize_nir(ctx, prog, prog->info.stage);
+}
diff --git a/src/mesa/drivers/dri/i965/meson.build b/src/mesa/drivers/dri/i965/meson.build
index 09e1179adc4..5d8b983a154 100644
--- a/src/mesa/drivers/dri/i965/meson.build
+++ b/src/mesa/drivers/dri/i965/meson.build
@@ -50,20 +50,21 @@ files_i965 = files(
'brw_meta_util.h',
'brw_misc_state.c',
'brw_multisample_state.h',
'brw_nir_uniforms.cpp',
'brw_object_purgeable.c',
'brw_pipe_control.c',
'brw_performance_query.h',
'brw_performance_query.c',
'brw_program.c',
'brw_program.h',
+ 'brw_program_binary.c',
'brw_program_cache.c',
'brw_primitive_restart.c',
'brw_queryobj.c',
'brw_reset.c',
'brw_sf.c',
'brw_state.h',
'brw_state_upload.c',
'brw_structs.h',
'brw_surface_formats.c',
'brw_sync.c',
--
2.14.3
Tapani Pälli
2017-12-07 06:26:01 UTC
Reply
Permalink
Raw Message
LGTM
Post by Timothy Arceri
This resolves an apparent game bug described in 85564. The game
doesn't properly handle ARB_get_program_binary with 0 supported
formats.
- less driver code as more has been moved into the common helpers.
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=85564
---
src/mesa/drivers/dri/i965/Makefile.sources | 1 +
src/mesa/drivers/dri/i965/brw_context.c | 10 ++++
src/mesa/drivers/dri/i965/brw_context.h | 16 ++++++
src/mesa/drivers/dri/i965/brw_program.h | 7 ---
src/mesa/drivers/dri/i965/brw_program_binary.c | 72 ++++++++++++++++++++++++++
src/mesa/drivers/dri/i965/meson.build | 1 +
6 files changed, 100 insertions(+), 7 deletions(-)
create mode 100644 src/mesa/drivers/dri/i965/brw_program_binary.c
diff --git a/src/mesa/drivers/dri/i965/Makefile.sources b/src/mesa/drivers/dri/i965/Makefile.sources
index 2980cdb3c54..3fba8dc17ef 100644
--- a/src/mesa/drivers/dri/i965/Makefile.sources
+++ b/src/mesa/drivers/dri/i965/Makefile.sources
@@ -30,20 +30,21 @@ i965_FILES = \
brw_meta_util.h \
brw_misc_state.c \
brw_multisample_state.h \
brw_nir_uniforms.cpp \
brw_object_purgeable.c \
brw_pipe_control.c \
brw_performance_query.h \
brw_performance_query.c \
brw_program.c \
brw_program.h \
+ brw_program_binary.c \
brw_program_cache.c \
brw_primitive_restart.c \
brw_queryobj.c \
brw_reset.c \
brw_sf.c \
brw_state.h \
brw_state_upload.c \
brw_structs.h \
brw_surface_formats.c \
brw_sync.c \
diff --git a/src/mesa/drivers/dri/i965/brw_context.c b/src/mesa/drivers/dri/i965/brw_context.c
index dd55b436698..5cd759f7356 100644
--- a/src/mesa/drivers/dri/i965/brw_context.c
+++ b/src/mesa/drivers/dri/i965/brw_context.c
@@ -322,20 +322,27 @@ brw_init_driver_functions(struct brw_context *brw,
functions->BeginTransformFeedback = brw_begin_transform_feedback;
functions->EndTransformFeedback = brw_end_transform_feedback;
functions->PauseTransformFeedback = brw_pause_transform_feedback;
functions->ResumeTransformFeedback = brw_resume_transform_feedback;
functions->GetTransformFeedbackVertexCount =
brw_get_transform_feedback_vertex_count;
}
if (devinfo->gen >= 6)
functions->GetSamplePosition = gen6_get_sample_position;
+
+ /* GL_ARB_get_program_binary */
+ brw_program_binary_init(brw->screen->deviceID);
+ functions->GetProgramBinaryDriverSHA1 = brw_get_program_binary_driver_sha1;
+ functions->ProgramBinarySerializeDriverBlob = brw_program_serialize_nir;
+ functions->ProgramBinaryDeserializeDriverBlob =
+ brw_deserialize_program_binary;
}
static void
brw_initialize_context_constants(struct brw_context *brw)
{
const struct gen_device_info *devinfo = &brw->screen->devinfo;
struct gl_context *ctx = &brw->ctx;
const struct brw_compiler *compiler = brw->screen->compiler;
const bool stage_exists[MESA_SHADER_STAGES] = {
@@ -689,20 +696,23 @@ brw_initialize_context_constants(struct brw_context *brw)
* pull an entire cache line at a time for constant offset loads both of
* which support almost any alignment.
*
* [1] glsl-1.40/uniform_buffer/vs-float-array-variable-index.shader_test
*/
if (devinfo->gen >= 7)
ctx->Const.UseSTD430AsDefaultPacking = true;
if (!(ctx->Const.ContextFlags & GL_CONTEXT_FLAG_DEBUG_BIT))
ctx->Const.AllowMappedBuffersDuringExecution = true;
+
+ /* GL_ARB_get_program_binary */
+ ctx->Const.NumProgramBinaryFormats = 1;
}
static void
brw_initialize_cs_context_constants(struct brw_context *brw)
{
struct gl_context *ctx = &brw->ctx;
const struct intel_screen *screen = brw->screen;
struct gen_device_info *devinfo = &brw->screen->devinfo;
/* FINISHME: Do this for all platforms that the kernel supports */
diff --git a/src/mesa/drivers/dri/i965/brw_context.h b/src/mesa/drivers/dri/i965/brw_context.h
index b3d7c6baf8a..da88bea739e 100644
--- a/src/mesa/drivers/dri/i965/brw_context.h
+++ b/src/mesa/drivers/dri/i965/brw_context.h
@@ -1539,20 +1539,36 @@ gen7_upload_urb(struct brw_context *brw, unsigned vs_size,
/* brw_reset.c */
extern GLenum
brw_get_graphics_reset_status(struct gl_context *ctx);
void
brw_check_for_reset(struct brw_context *brw);
/* brw_compute.c */
extern void
brw_init_compute_functions(struct dd_function_table *functions);
+/* brw_program_binary.c */
+extern void
+brw_program_binary_init(unsigned device_id);
+extern void
+brw_get_program_binary_driver_sha1(struct gl_context *ctx, uint8_t *sha1);
+extern void
+brw_deserialize_program_binary(struct gl_context *ctx,
+ struct gl_shader_program *shProg,
+ struct gl_program *prog);
+void
+brw_program_serialize_nir(struct gl_context *ctx, struct gl_program *prog,
+ gl_shader_stage stage);
+void
+brw_program_deserialize_nir(struct gl_context *ctx, struct gl_program *prog,
+ gl_shader_stage stage);
+
/*======================================================================
* Inline conversion functions. These are better-typed than the
*/
static inline struct brw_context *
brw_context( struct gl_context *ctx )
{
return (struct brw_context *)ctx;
}
diff --git a/src/mesa/drivers/dri/i965/brw_program.h b/src/mesa/drivers/dri/i965/brw_program.h
index a5e41522841..701b8da482e 100644
--- a/src/mesa/drivers/dri/i965/brw_program.h
+++ b/src/mesa/drivers/dri/i965/brw_program.h
@@ -74,27 +74,20 @@ void brw_populate_sampler_prog_key_data(struct gl_context *ctx,
bool brw_debug_recompile_sampler_key(struct brw_context *brw,
const struct brw_sampler_prog_key_data *old_key,
const struct brw_sampler_prog_key_data *key);
uint32_t
brw_assign_common_binding_table_offsets(const struct gen_device_info *devinfo,
const struct gl_program *prog,
struct brw_stage_prog_data *stage_prog_data,
uint32_t next_binding_table_offset);
-void
-brw_program_serialize_nir(struct gl_context *ctx, struct gl_program *prog,
- gl_shader_stage stage);
-void
-brw_program_deserialize_nir(struct gl_context *ctx, struct gl_program *prog,
- gl_shader_stage stage);
-
void
brw_stage_prog_data_free(const void *prog_data);
void
brw_dump_arb_asm(const char *stage, struct gl_program *prog);
bool brw_vs_precompile(struct gl_context *ctx, struct gl_program *prog);
bool brw_tcs_precompile(struct gl_context *ctx,
struct gl_shader_program *shader_prog,
struct gl_program *prog);
diff --git a/src/mesa/drivers/dri/i965/brw_program_binary.c b/src/mesa/drivers/dri/i965/brw_program_binary.c
new file mode 100644
index 00000000000..f1b327de4b3
--- /dev/null
+++ b/src/mesa/drivers/dri/i965/brw_program_binary.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2017 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdint.h>
+
+#include "util/build_id.h"
+#include "util/mesa-sha1.h"
+
+#include "brw_context.h"
+#include "brw_program.h"
+
+static uint8_t driver_sha1[20];
+
+void
+brw_program_binary_init(unsigned device_id)
+{
+ const struct build_id_note *note =
+ build_id_find_nhdr_for_addr(brw_program_binary_init);
+ assert(note);
+
+ /**
+ * With Mesa's megadrivers, taking the sha1 of i965_dri.so may not be
+ * unique. Therefore, we make a sha1 of the "i965" string and the sha1
+ * build id from i965_dri.so.
+ */
+ struct mesa_sha1 ctx;
+ _mesa_sha1_init(&ctx);
+ char renderer[10];
+ assert(device_id < 0x10000);
+ int len = snprintf(renderer, sizeof(renderer), "i965_%04x", device_id);
+ assert(len == sizeof(renderer) - 1);
+ _mesa_sha1_update(&ctx, renderer, len);
+ _mesa_sha1_update(&ctx, build_id_data(note), build_id_length(note));
+ _mesa_sha1_final(&ctx, driver_sha1);
+}
+
+void
+brw_get_program_binary_driver_sha1(struct gl_context *ctx, uint8_t *sha1)
+{
+ memcpy(sha1, driver_sha1, sizeof(uint8_t) * 20);
+}
+
+/* This is just a wrapper around brw_program_deserialize_nir() as i965
+ * doesn't need gl_shader_program like other drivers do.
+ */
+void
+brw_deserialize_program_binary(struct gl_context *ctx,
+ struct gl_shader_program *shProg,
+ struct gl_program *prog)
+{
+ brw_program_deserialize_nir(ctx, prog, prog->info.stage);
+}
diff --git a/src/mesa/drivers/dri/i965/meson.build b/src/mesa/drivers/dri/i965/meson.build
index 09e1179adc4..5d8b983a154 100644
--- a/src/mesa/drivers/dri/i965/meson.build
+++ b/src/mesa/drivers/dri/i965/meson.build
@@ -50,20 +50,21 @@ files_i965 = files(
'brw_meta_util.h',
'brw_misc_state.c',
'brw_multisample_state.h',
'brw_nir_uniforms.cpp',
'brw_object_purgeable.c',
'brw_pipe_control.c',
'brw_performance_query.h',
'brw_performance_query.c',
'brw_program.c',
'brw_program.h',
+ 'brw_program_binary.c',
'brw_program_cache.c',
'brw_primitive_restart.c',
'brw_queryobj.c',
'brw_reset.c',
'brw_sf.c',
'brw_state.h',
'brw_state_upload.c',
'brw_structs.h',
'brw_surface_formats.c',
'brw_sync.c',
Timothy Arceri
2017-11-29 01:24:59 UTC
Reply
Permalink
Raw Message
From: Jordan Justen <***@intel.com>

Signed-off-by: Jordan Justen <***@intel.com>
---
docs/features.txt | 2 +-
docs/relnotes/17.4.0.html | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/docs/features.txt b/docs/features.txt
index 01cd133ef01..39aaa4f603b 100644
--- a/docs/features.txt
+++ b/docs/features.txt
@@ -132,21 +132,21 @@ GL 4.0, GLSL 4.00 --- all DONE: i965/gen7+, nvc0, r600, radeonsi
GL_ARB_texture_cube_map_array DONE (i965/gen6+, nv50, llvmpipe, softpipe)
GL_ARB_texture_gather DONE (freedreno, i965/gen6+, nv50, llvmpipe, softpipe, swr)
GL_ARB_texture_query_lod DONE (freedreno, i965, nv50, llvmpipe, softpipe)
GL_ARB_transform_feedback2 DONE (i965/gen6+, nv50, llvmpipe, softpipe, swr)
GL_ARB_transform_feedback3 DONE (i965/gen7+, llvmpipe, softpipe, swr)


GL 4.1, GLSL 4.10 --- all DONE: i965/gen7+, nvc0, r600, radeonsi

GL_ARB_ES2_compatibility DONE (freedreno, i965, nv50, llvmpipe, softpipe, swr)
- GL_ARB_get_program_binary DONE (0 binary formats)
+ GL_ARB_get_program_binary DONE (0 or 1 binary formats)
GL_ARB_separate_shader_objects DONE (all drivers)
GL_ARB_shader_precision DONE (i965/gen7+, all drivers that support GLSL 4.10)
GL_ARB_vertex_attrib_64bit DONE (i965/gen7+, llvmpipe, softpipe)
GL_ARB_viewport_array DONE (i965, nv50, llvmpipe, softpipe)


GL 4.2, GLSL 4.20 -- all DONE: i965/gen7+, nvc0, r600, radeonsi

GL_ARB_texture_compression_bptc DONE (freedreno, i965)
GL_ARB_compressed_texture_pixel_storage DONE (all drivers)
diff --git a/docs/relnotes/17.4.0.html b/docs/relnotes/17.4.0.html
index ec2386b3305..2e884fa764e 100644
--- a/docs/relnotes/17.4.0.html
+++ b/docs/relnotes/17.4.0.html
@@ -42,20 +42,21 @@ TBD.
<p>
Note: some of the new features are only available with certain drivers.
</p>

<ul>
<li>Disk shader cache support for i965 when MESA_GLSL_CACHE_DISABLE environment variable is set to "0" or "false"</li>
<li>GL_ARB_shader_atomic_counters and GL_ARB_shader_atomic_counter_ops on r600/evergreen+</li>
<li>GL_ARB_shader_image_load_store and GL_ARB_shader_image_size on r600/evergreen+</li>
<li>GL_ARB_cull_distance on r600/evergreen+</li>
<li>OpenGL 4.2 on r600/evergreen with hw fp64 support</li>
+<li>Support 1 binary format for GL_ARB_get_program_binary on i965</li>
</ul>

<h2>Bug fixes</h2>

<ul>
TBD
</ul>

<h2>Changes</h2>
--
2.14.3
Tapani Pälli
2017-12-07 06:26:27 UTC
Reply
Permalink
Raw Message
Post by Timothy Arceri
---
docs/features.txt | 2 +-
docs/relnotes/17.4.0.html | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/docs/features.txt b/docs/features.txt
index 01cd133ef01..39aaa4f603b 100644
--- a/docs/features.txt
+++ b/docs/features.txt
@@ -132,21 +132,21 @@ GL 4.0, GLSL 4.00 --- all DONE: i965/gen7+, nvc0, r600, radeonsi
GL_ARB_texture_cube_map_array DONE (i965/gen6+, nv50, llvmpipe, softpipe)
GL_ARB_texture_gather DONE (freedreno, i965/gen6+, nv50, llvmpipe, softpipe, swr)
GL_ARB_texture_query_lod DONE (freedreno, i965, nv50, llvmpipe, softpipe)
GL_ARB_transform_feedback2 DONE (i965/gen6+, nv50, llvmpipe, softpipe, swr)
GL_ARB_transform_feedback3 DONE (i965/gen7+, llvmpipe, softpipe, swr)
GL 4.1, GLSL 4.10 --- all DONE: i965/gen7+, nvc0, r600, radeonsi
GL_ARB_ES2_compatibility DONE (freedreno, i965, nv50, llvmpipe, softpipe, swr)
- GL_ARB_get_program_binary DONE (0 binary formats)
+ GL_ARB_get_program_binary DONE (0 or 1 binary formats)
GL_ARB_separate_shader_objects DONE (all drivers)
GL_ARB_shader_precision DONE (i965/gen7+, all drivers that support GLSL 4.10)
GL_ARB_vertex_attrib_64bit DONE (i965/gen7+, llvmpipe, softpipe)
GL_ARB_viewport_array DONE (i965, nv50, llvmpipe, softpipe)
GL 4.2, GLSL 4.20 -- all DONE: i965/gen7+, nvc0, r600, radeonsi
GL_ARB_texture_compression_bptc DONE (freedreno, i965)
GL_ARB_compressed_texture_pixel_storage DONE (all drivers)
diff --git a/docs/relnotes/17.4.0.html b/docs/relnotes/17.4.0.html
index ec2386b3305..2e884fa764e 100644
--- a/docs/relnotes/17.4.0.html
+++ b/docs/relnotes/17.4.0.html
@@ -42,20 +42,21 @@ TBD.
<p>
Note: some of the new features are only available with certain drivers.
</p>
<ul>
<li>Disk shader cache support for i965 when MESA_GLSL_CACHE_DISABLE environment variable is set to "0" or "false"</li>
<li>GL_ARB_shader_atomic_counters and GL_ARB_shader_atomic_counter_ops on r600/evergreen+</li>
<li>GL_ARB_shader_image_load_store and GL_ARB_shader_image_size on r600/evergreen+</li>
<li>GL_ARB_cull_distance on r600/evergreen+</li>
<li>OpenGL 4.2 on r600/evergreen with hw fp64 support</li>
+<li>Support 1 binary format for GL_ARB_get_program_binary on i965</li>
</ul>
<h2>Bug fixes</h2>
<ul>
TBD
</ul>
<h2>Changes</h2>
Timothy Arceri
2017-12-05 05:03:28 UTC
Reply
Permalink
Raw Message
Ping! The outstanding patches for review are:

4, 12, 22, 23

Gallium specific patches:

17-21

The following have a v1 r-b Nicolai but have changed since:

13, 14, 15

Branch available here:

https://github.com/tarceri/Mesa.git gallium-program-binary
Post by Timothy Arceri
This is basically the V2 that Jordan sent with feedback addressed,
gallium support added, some minor functional changes such as only
storing the default uniforms to either disk or program binary cache
(rather than fixing them up later) and some refactoring to allow
greater code sharing between gallium and i965.
This series adds i965/gallium support for ARB_get_program_binary
with greater than 0 supported formats. Today we support this extension,
but advertise support for 0 formats. This series allows i965/gallium
to advertise support for 1 format.
This series defines a common Mesa format for ARB_get_program_binary,
along with helper functions to read and write the format. The binary
saved can only be reloaded on the exact same Mesa build using the
exact same hardware.
The i965/gallium implementation saves out a serialized nir/tgsi
represenation of the program. For i965 we can later add support for
saving the gen binary program as well. (We will still need the nir
program for state based recompiles.)
This implementation passes piglit, deqp and glcts functions. It also
works with (and fixes a crash in) Dead Island with makes use of the
extension.
_______________________________________________
mesa-dev mailing list
https://lists.freedesktop.org/mailman/listinfo/mesa-dev
Mike Lothian
2017-12-06 00:08:18 UTC
Reply
Permalink
Raw Message
I can confirm this fixes the Dead Island crash, which makes this the first
time I've been able to play the game since purchasing it :D

The patches doesn't apply cleanly to master so I used the following fixup
https://github.com/FireBurn/mesa/tree/gallium-program-binary

If you're happy with that feel free to add my Tested-by
Post by Timothy Arceri
4, 12, 22, 23
17-21
13, 14, 15
https://github.com/tarceri/Mesa.git gallium-program-binary
Post by Timothy Arceri
This is basically the V2 that Jordan sent with feedback addressed,
gallium support added, some minor functional changes such as only
storing the default uniforms to either disk or program binary cache
(rather than fixing them up later) and some refactoring to allow
greater code sharing between gallium and i965.
This series adds i965/gallium support for ARB_get_program_binary
with greater than 0 supported formats. Today we support this extension,
but advertise support for 0 formats. This series allows i965/gallium
to advertise support for 1 format.
This series defines a common Mesa format for ARB_get_program_binary,
along with helper functions to read and write the format. The binary
saved can only be reloaded on the exact same Mesa build using the
exact same hardware.
The i965/gallium implementation saves out a serialized nir/tgsi
represenation of the program. For i965 we can later add support for
saving the gen binary program as well. (We will still need the nir
program for state based recompiles.)
This implementation passes piglit, deqp and glcts functions. It also
works with (and fixes a crash in) Dead Island with makes use of the
extension.
_______________________________________________
mesa-dev mailing list
https://lists.freedesktop.org/mailman/listinfo/mesa-dev
_______________________________________________
mesa-dev mailing list
https://lists.freedesktop.org/mailman/listinfo/mesa-dev
Tapani Pälli
2017-12-07 11:47:59 UTC
Reply
Permalink
Raw Message
Hi;

I've been testing this functionality with little app I have and I
noticed one thing by accident.

If I call link twice for a regular program like this:

glLinkProgram(program);
glLinkProgram(program);

everything's fine, sequential calls do not generate errors. However for
program loaded via glProgramBinaryOES it seems not ok for some reason.
Should it be? It throws error on glUseProgram() saying that program not
linked.

Thanks;
Post by Timothy Arceri
This is basically the V2 that Jordan sent with feedback addressed,
gallium support added, some minor functional changes such as only
storing the default uniforms to either disk or program binary cache
(rather than fixing them up later) and some refactoring to allow
greater code sharing between gallium and i965.
This series adds i965/gallium support for ARB_get_program_binary
with greater than 0 supported formats. Today we support this extension,
but advertise support for 0 formats. This series allows i965/gallium
to advertise support for 1 format.
This series defines a common Mesa format for ARB_get_program_binary,
along with helper functions to read and write the format. The binary
saved can only be reloaded on the exact same Mesa build using the
exact same hardware.
The i965/gallium implementation saves out a serialized nir/tgsi
represenation of the program. For i965 we can later add support for
saving the gen binary program as well. (We will still need the nir
program for state based recompiles.)
This implementation passes piglit, deqp and glcts functions. It also
works with (and fixes a crash in) Dead Island with makes use of the
extension.
_______________________________________________
mesa-dev mailing list
https://lists.freedesktop.org/mailman/listinfo/mesa-dev
Tapani Pälli
2017-12-07 12:10:20 UTC
Reply
Permalink
Raw Message
Post by Tapani Pälli
Hi;
I've been testing this functionality with little app I have and I
noticed one thing by accident.
glLinkProgram(program);
glLinkProgram(program);
everything's fine, sequential calls do not generate errors. However for
program loaded via glProgramBinaryOES it seems not ok for some reason.
Should it be? It throws error on glUseProgram() saying that program not
linked.
Studying specs a bit more it is supposed to fail, there are no shaders
to link. If I attach new shaders after glProgramBinaryOES and then call
glLinkProgram() it links succesfully and works fine. So no worries!
Post by Tapani Pälli
Thanks;
Post by Timothy Arceri
This is basically the V2 that Jordan sent with feedback addressed,
gallium support added, some minor functional changes such as only
storing the default uniforms to either disk or program binary cache
(rather than fixing them up later) and some refactoring to allow
greater code sharing between gallium and i965.
This series adds i965/gallium support for ARB_get_program_binary
with greater than 0 supported formats. Today we support this extension,
but advertise support for 0 formats. This series allows i965/gallium
to advertise support for 1 format.
This series defines a common Mesa format for ARB_get_program_binary,
along with helper functions to read and write the format. The binary
saved can only be reloaded on the exact same Mesa build using the
exact same hardware.
The i965/gallium implementation saves out a serialized nir/tgsi
represenation of the program. For i965 we can later add support for
saving the gen binary program as well. (We will still need the nir
program for state based recompiles.)
This implementation passes piglit, deqp and glcts functions. It also
works with (and fixes a crash in) Dead Island with makes use of the
extension.
_______________________________________________
mesa-dev mailing list
https://lists.freedesktop.org/mailman/listinfo/mesa-dev
_______________________________________________
mesa-dev mailing list
https://lists.freedesktop.org/mailman/listinfo/mesa-dev
Loading...