[Mesa-dev] [PATCH v2 16/17] i965: Add ARB_get_program_binary support using nir_serialization
Timothy Arceri
tarceri at itsqueeze.com
Tue Nov 21 11:16:42 UTC 2017
On 21/11/17 09:27, Jordan Justen wrote:
> This works-around an apparent game bug described in 85564. It appears
Change this to:
This resolves an apparent game bug ???
> that the game doesn't properly handle ARB_get_program_binary with 0
> supported formats.
>
> Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=85564
> Signed-off-by: Jordan Justen <jordan.l.justen at 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 | 187 +++++++++++++++++++++++++
> src/mesa/drivers/dri/i965/meson.build | 1 +
> 5 files changed, 214 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 dd55b436698..80664c5f7b1 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
> @@ -696,6 +702,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 b3d7c6baf8a..e1aa69c534e 100644
> --- a/src/mesa/drivers/dri/i965/brw_context.h
> +++ b/src/mesa/drivers/dri/i965/brw_context.h
> @@ -1546,6 +1546,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..8173f2cf182
> --- /dev/null
> +++ b/src/mesa/drivers/dri/i965/brw_program_binary.c
> @@ -0,0 +1,187 @@
> +/*
> + * 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_fixed(&blob, NULL, SIZE_MAX);
> + write_program_payload(ctx, &blob, sh_prog);
> + *length = get_program_binary_header_size() + blob.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;
> + unsigned header_size = get_program_binary_header_size();
> + void *payload = (uint8_t*)binary + header_size;
> +
> + if (buf_size < header_size) {
> + blob_init_fixed(&blob, NULL, 0);
> + blob.out_of_memory = true;
> + } else {
> + blob_init(&blob);
> + write_program_payload(ctx, &blob, sh_prog);
> + if (blob.size + header_size > buf_size)
> + blob.out_of_memory = true;
> + }
> +
> + if (!blob.out_of_memory &&
> + !write_program_binary(blob.data, blob.size, driver_sha1, binary,
> + buf_size, binary_format)) {
> + blob.out_of_memory = true;
> + }
> +
> + if (blob.out_of_memory) {
> + _mesa_error(ctx, GL_INVALID_OPERATION,
> + "glGetProgramBinary(buffer too small)");
> + *length = 0;
> + } else {
> + *length = header_size + blob.size;
> + }
> + blob_finish(&blob);
I find this harder to follow than it should be, also it feels wrong to
use blob.out_of_memory like that. Can we change it to?
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);
> +}
> +
> +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;
> + unsigned header_size = get_program_binary_header_size();
> + const void *payload = get_program_binary_payload(binary_format, driver_sha1,
> + binary, length);
> + bool payload_ok = false;
> +
> + if (payload != NULL) {
> + struct blob_reader blob;
> + blob_reader_init(&blob, payload, length - header_size);
> + 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);
Since we are going to move program_binary.c out of util and into Mesa it
would be good if you could turn this reset code into a helper and move
it into that file.
> +
> + sh_prog->data->LinkStatus = linking_success;
> + } else {
> + sh_prog->data->LinkStatus = linking_failure;
> + }
> +
> + if (extracted_payload)
> + ralloc_free(extracted_payload);
extracted_payload is unused.
> +}
> 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',
>
More information about the mesa-dev
mailing list