Signed-off-by: Jordan Justen <jordan.l.jus...@intel.com> --- src/mesa/drivers/dri/i965/Makefile.sources | 1 + src/mesa/drivers/dri/i965/brw_context.c | 9 ++ src/mesa/drivers/dri/i965/brw_context.h | 16 ++ src/mesa/drivers/dri/i965/brw_program_binary.c | 200 +++++++++++++++++++++++++ src/mesa/drivers/dri/i965/meson.build | 1 + 5 files changed, 227 insertions(+) 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 @@ -37,6 +37,7 @@ i965_FILES = \ 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 \ diff --git a/src/mesa/drivers/dri/i965/brw_context.c b/src/mesa/drivers/dri/i965/brw_context.c index 0ebd4329935..b685e53852b 100644 --- a/src/mesa/drivers/dri/i965/brw_context.c +++ b/src/mesa/drivers/dri/i965/brw_context.c @@ -329,6 +329,12 @@ brw_init_driver_functions(struct brw_context *brw, if (devinfo->gen >= 6) functions->GetSamplePosition = gen6_get_sample_position; + + /* GL_ARB_get_program_binary */ + brw_program_binary_init(brw->screen->deviceID); + functions->GetProgramBinaryLength = brw_get_program_binary_length; + functions->GetProgramBinary = brw_get_program_binary; + functions->ProgramBinary = brw_program_binary; } static void @@ -697,6 +703,9 @@ brw_initialize_context_constants(struct brw_context *brw) if (!(ctx->Const.ContextFlags & GL_CONTEXT_FLAG_DEBUG_BIT)) ctx->Const.AllowMappedBuffersDuringExecution = true; + + /* GL_ARB_get_program_binary */ + ctx->Const.NumProgramBinaryFormats = 1; } static void diff --git a/src/mesa/drivers/dri/i965/brw_context.h b/src/mesa/drivers/dri/i965/brw_context.h index 8aa0c5ff64c..0c10db0ef34 100644 --- a/src/mesa/drivers/dri/i965/brw_context.h +++ b/src/mesa/drivers/dri/i965/brw_context.h @@ -1556,6 +1556,22 @@ brw_check_for_reset(struct brw_context *brw); 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_length(struct gl_context *ctx, + struct gl_shader_program *sh_prog, + GLint *length); +extern void +brw_get_program_binary(struct gl_context *ctx, + struct gl_shader_program *sh_prog, + GLsizei bufSize, GLsizei *length, + GLenum *binary_format, GLvoid *binary); +extern void +brw_program_binary(struct gl_context *ctx, struct gl_shader_program *sh_prog, + GLenum binary_format, const GLvoid *binary, GLsizei length); + /*====================================================================== * Inline conversion functions. These are better-typed than the * macros used previously: 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..55a2d097b8c --- /dev/null +++ b/src/mesa/drivers/dri/i965/brw_program_binary.c @@ -0,0 +1,200 @@ +/* + * 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 "compiler/blob.h" +#include "compiler/glsl/serialize.h" +#include "compiler/nir/nir_serialize.h" +#include "main/mtypes.h" +#include "util/build_id.h" +#include "util/debug.h" +#include "util/mesa-sha1.h" +#include "util/program_binary.h" +#include "program/prog_parameter.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); +} + +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]) + brw_program_serialize_nir(ctx, shader->Program, stage); + } + + 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) +{ + bool deserialized; + + deserialized = deserialize_glsl_program(blob, ctx, sh_prog); + + if (!deserialized) + 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; + + brw_program_deserialize_nir(ctx, shader->Program, stage); + } + + return deserialized; +} + +void +brw_get_program_binary_length(struct gl_context *ctx, + struct gl_shader_program *sh_prog, + GLint *length) +{ + struct blob blob; + blob_init(&blob); + write_program_payload(ctx, &blob, sh_prog); + + void *temp_buf = malloc(get_program_binary_max_size(blob.size)); + assert(temp_buf); + + GLenum binary_format; + unsigned final_size; + get_program_binary(blob.data, blob.size, driver_sha1, temp_buf, + get_program_binary_max_size(blob.size), &final_size, + &binary_format); + + free(temp_buf); + blob_finish(&blob); + + *length = final_size; +} + +void +brw_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; + blob_init(&blob); + write_program_payload(ctx, &blob, sh_prog); + + unsigned final_size = 0; + if (blob.out_of_memory || + !get_program_binary(blob.data, blob.size, driver_sha1, binary, buf_size, + &final_size, binary_format)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetProgramBinary(buffer too small)"); + *length = 0; + } else { + *length = final_size; + } + blob_finish(&blob); +} + +extern void +brw_program_binary(struct gl_context *ctx, struct gl_shader_program *sh_prog, + GLenum binary_format, const GLvoid *binary, GLsizei length) +{ + void *extracted_payload = NULL; + const void *payload = NULL; + unsigned payload_length; + int payload_offset = 0; + + if (is_program_binary_valid(binary_format, driver_sha1, binary, + length)) { + payload_offset = program_binary_payload_offset(binary, length); + if (payload_offset < 0) { + extract_program_binary_payload(binary, length, &extracted_payload, + &payload_length); + payload = extracted_payload; + } else { + payload = ((const uint8_t*)binary) + payload_offset; + } + } + + bool payload_ok = false; + + if (payload != NULL) { + struct blob_reader blob; + blob_reader_init(&blob, payload, payload_length); + payload_ok = read_program_payload(ctx, &blob, binary_format, sh_prog); + } + + if (payload_ok) { + /* Reset uniforms to initial values as required by extension spec. */ + struct gl_shader_program_data *data = sh_prog->data; + unsigned size = + sizeof(union gl_constant_value) * data->NumUniformDataSlots; + memcpy(data->UniformDataSlots, data->UniformDataDefaults, size); + + sh_prog->data->LinkStatus = linking_success; + } else { + sh_prog->data->LinkStatus = linking_failure; + } + + if (extracted_payload) + ralloc_free(extracted_payload); +} 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 @@ -57,6 +57,7 @@ files_i965 = files( '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', -- 2.14.1 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev