mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-23 04:18:14 +02:00
Iterate the system values list when adding varyings to the program
resource list in the NIR linker. This is needed to avoid CTS
regressions when using the NIR to build the GLSL resource list in
an upcoming series. Presumably it also fixes a bug with the current
ARB_gl_spirv support.
Fixes: ffdb44d3a0 ("nir/linker: Add inputs/outputs to the program resource list")
Reviewed-by: Alejandro Piñeiro <apinheiro@igalia.com>
282 lines
10 KiB
C
282 lines
10 KiB
C
/*
|
|
* Copyright © 2018 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 "nir.h"
|
|
#include "gl_nir_linker.h"
|
|
#include "linker_util.h"
|
|
#include "main/mtypes.h"
|
|
#include "ir_uniform.h" /* for gl_uniform_storage */
|
|
|
|
/* This file included general link methods, using NIR, instead of IR as
|
|
* the counter-part glsl/linker.cpp
|
|
*
|
|
* Also note that this is tailored for ARB_gl_spirv needs and particularities
|
|
*/
|
|
|
|
static bool
|
|
add_vars_from_list(const struct gl_context *ctx,
|
|
struct gl_shader_program *prog, struct set *resource_set,
|
|
const struct exec_list *var_list, unsigned stage,
|
|
GLenum programInterface)
|
|
{
|
|
nir_foreach_variable(var, var_list) {
|
|
if (var->data.how_declared == nir_var_hidden)
|
|
continue;
|
|
|
|
int loc_bias = 0;
|
|
switch(var->data.mode) {
|
|
case nir_var_system_value:
|
|
case nir_var_shader_in:
|
|
if (programInterface != GL_PROGRAM_INPUT)
|
|
continue;
|
|
loc_bias = (stage == MESA_SHADER_VERTEX) ? VERT_ATTRIB_GENERIC0
|
|
: VARYING_SLOT_VAR0;
|
|
break;
|
|
case nir_var_shader_out:
|
|
if (programInterface != GL_PROGRAM_OUTPUT)
|
|
continue;
|
|
loc_bias = (stage == MESA_SHADER_FRAGMENT) ? FRAG_RESULT_DATA0
|
|
: VARYING_SLOT_VAR0;
|
|
break;
|
|
default:
|
|
continue;
|
|
}
|
|
|
|
if (var->data.patch)
|
|
loc_bias = VARYING_SLOT_PATCH0;
|
|
|
|
struct gl_shader_variable *sh_var =
|
|
rzalloc(prog, struct gl_shader_variable);
|
|
|
|
/* In the ARB_gl_spirv spec, names are considered optional debug info, so
|
|
* the linker needs to work without them. Returning them is optional.
|
|
* For simplicity, we ignore names.
|
|
*/
|
|
sh_var->name = NULL;
|
|
sh_var->type = var->type;
|
|
sh_var->location = var->data.location - loc_bias;
|
|
sh_var->index = var->data.index;
|
|
|
|
if (!link_util_add_program_resource(prog, resource_set,
|
|
programInterface,
|
|
sh_var, 1 << stage)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
add_interface_variables(const struct gl_context *ctx,
|
|
struct gl_shader_program *prog,
|
|
struct set *resource_set,
|
|
unsigned stage, GLenum programInterface)
|
|
{
|
|
struct gl_linked_shader *sh = prog->_LinkedShaders[stage];
|
|
if (!sh)
|
|
return true;
|
|
|
|
nir_shader *nir = sh->Program->nir;
|
|
assert(nir);
|
|
|
|
switch (programInterface) {
|
|
case GL_PROGRAM_INPUT: {
|
|
bool result = add_vars_from_list(ctx, prog, resource_set,
|
|
&nir->inputs, stage, programInterface);
|
|
result &= add_vars_from_list(ctx, prog, resource_set, &nir->system_values,
|
|
stage, programInterface);
|
|
return result;
|
|
}
|
|
case GL_PROGRAM_OUTPUT:
|
|
return add_vars_from_list(ctx, prog, resource_set, &nir->outputs, stage,
|
|
programInterface);
|
|
default:
|
|
assert("!Should not get here");
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/* TODO: as we keep adding features, this method is becoming more and more
|
|
* similar to its GLSL counterpart at linker.cpp. Eventually it would be good
|
|
* to check if they could be refactored, and reduce code duplication somehow
|
|
*/
|
|
void
|
|
nir_build_program_resource_list(struct gl_context *ctx,
|
|
struct gl_shader_program *prog)
|
|
{
|
|
/* Rebuild resource list. */
|
|
if (prog->data->ProgramResourceList) {
|
|
ralloc_free(prog->data->ProgramResourceList);
|
|
prog->data->ProgramResourceList = NULL;
|
|
prog->data->NumProgramResourceList = 0;
|
|
}
|
|
|
|
int input_stage = MESA_SHADER_STAGES, output_stage = 0;
|
|
|
|
/* Determine first input and final output stage. These are used to
|
|
* detect which variables should be enumerated in the resource list
|
|
* for GL_PROGRAM_INPUT and GL_PROGRAM_OUTPUT.
|
|
*/
|
|
for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
|
|
if (!prog->_LinkedShaders[i])
|
|
continue;
|
|
if (input_stage == MESA_SHADER_STAGES)
|
|
input_stage = i;
|
|
output_stage = i;
|
|
}
|
|
|
|
/* Empty shader, no resources. */
|
|
if (input_stage == MESA_SHADER_STAGES && output_stage == 0)
|
|
return;
|
|
|
|
struct set *resource_set = _mesa_pointer_set_create(NULL);
|
|
|
|
/* Add inputs and outputs to the resource list. */
|
|
if (!add_interface_variables(ctx, prog, resource_set, input_stage,
|
|
GL_PROGRAM_INPUT)) {
|
|
return;
|
|
}
|
|
|
|
if (!add_interface_variables(ctx, prog, resource_set, output_stage,
|
|
GL_PROGRAM_OUTPUT)) {
|
|
return;
|
|
}
|
|
|
|
/* Add transform feedback varyings and buffers. */
|
|
if (prog->last_vert_prog) {
|
|
struct gl_transform_feedback_info *linked_xfb =
|
|
prog->last_vert_prog->sh.LinkedTransformFeedback;
|
|
|
|
/* Add varyings. */
|
|
if (linked_xfb->NumVarying > 0) {
|
|
for (int i = 0; i < linked_xfb->NumVarying; i++) {
|
|
if (!link_util_add_program_resource(prog, resource_set,
|
|
GL_TRANSFORM_FEEDBACK_VARYING,
|
|
&linked_xfb->Varyings[i], 0))
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* Add buffers. */
|
|
for (unsigned i = 0; i < ctx->Const.MaxTransformFeedbackBuffers; i++) {
|
|
if ((linked_xfb->ActiveBuffers >> i) & 1) {
|
|
linked_xfb->Buffers[i].Binding = i;
|
|
if (!link_util_add_program_resource(prog, resource_set,
|
|
GL_TRANSFORM_FEEDBACK_BUFFER,
|
|
&linked_xfb->Buffers[i], 0))
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Add uniforms
|
|
*
|
|
* Here, it is expected that nir_link_uniforms() has already been
|
|
* called, so that UniformStorage table is already available.
|
|
*/
|
|
int top_level_array_base_offset = -1;
|
|
int top_level_array_size_in_bytes = -1;
|
|
int second_element_offset = -1;
|
|
int block_index = -1;
|
|
for (unsigned i = 0; i < prog->data->NumUniformStorage; i++) {
|
|
struct gl_uniform_storage *uniform = &prog->data->UniformStorage[i];
|
|
|
|
/* Do not add uniforms internally used by Mesa. */
|
|
if (uniform->hidden)
|
|
continue;
|
|
|
|
if (!link_util_should_add_buffer_variable(prog, uniform,
|
|
top_level_array_base_offset,
|
|
top_level_array_size_in_bytes,
|
|
second_element_offset, block_index))
|
|
continue;
|
|
|
|
|
|
if (prog->data->UniformStorage[i].offset >= second_element_offset) {
|
|
top_level_array_base_offset =
|
|
prog->data->UniformStorage[i].offset;
|
|
|
|
top_level_array_size_in_bytes =
|
|
prog->data->UniformStorage[i].top_level_array_size *
|
|
prog->data->UniformStorage[i].top_level_array_stride;
|
|
|
|
/* Set or reset the second element offset. For non arrays this
|
|
* will be set to -1.
|
|
*/
|
|
second_element_offset = top_level_array_size_in_bytes ?
|
|
top_level_array_base_offset +
|
|
prog->data->UniformStorage[i].top_level_array_stride : -1;
|
|
}
|
|
block_index = uniform->block_index;
|
|
|
|
|
|
GLenum interface = uniform->is_shader_storage ? GL_BUFFER_VARIABLE : GL_UNIFORM;
|
|
if (!link_util_add_program_resource(prog, resource_set, interface, uniform,
|
|
uniform->active_shader_mask)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
for (unsigned i = 0; i < prog->data->NumUniformBlocks; i++) {
|
|
if (!link_util_add_program_resource(prog, resource_set, GL_UNIFORM_BLOCK,
|
|
&prog->data->UniformBlocks[i],
|
|
prog->data->UniformBlocks[i].stageref))
|
|
return;
|
|
}
|
|
|
|
for (unsigned i = 0; i < prog->data->NumShaderStorageBlocks; i++) {
|
|
if (!link_util_add_program_resource(prog, resource_set, GL_SHADER_STORAGE_BLOCK,
|
|
&prog->data->ShaderStorageBlocks[i],
|
|
prog->data->ShaderStorageBlocks[i].stageref))
|
|
return;
|
|
}
|
|
|
|
/* Add atomic counter buffers. */
|
|
for (unsigned i = 0; i < prog->data->NumAtomicBuffers; i++) {
|
|
if (!link_util_add_program_resource(prog, resource_set, GL_ATOMIC_COUNTER_BUFFER,
|
|
&prog->data->AtomicBuffers[i], 0))
|
|
return;
|
|
}
|
|
|
|
_mesa_set_destroy(resource_set, NULL);
|
|
}
|
|
|
|
bool
|
|
gl_nir_link(struct gl_context *ctx, struct gl_shader_program *prog,
|
|
const struct gl_nir_linker_options *options)
|
|
{
|
|
if (!gl_nir_link_uniform_blocks(ctx, prog))
|
|
return false;
|
|
|
|
if (!gl_nir_link_uniforms(ctx, prog, options->fill_parameters))
|
|
return false;
|
|
|
|
gl_nir_link_assign_atomic_counter_resources(ctx, prog);
|
|
gl_nir_link_assign_xfb_resources(ctx, prog);
|
|
|
|
return true;
|
|
}
|