#include "gl_nir_linker.h"
#include "linker_util.h"
#include "main/mtypes.h"
+#include "main/shaderobj.h"
#include "ir_uniform.h" /* for gl_uniform_storage */
-/* This file included general link methods, using NIR, instead of IR as
+/**
+ * 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
+can_remove_uniform(nir_variable *var)
+{
+ /* Section 2.11.6 (Uniform Variables) of the OpenGL ES 3.0.3 spec
+ * says:
+ *
+ * "All members of a named uniform block declared with a shared or
+ * std140 layout qualifier are considered active, even if they are not
+ * referenced in any shader in the program. The uniform block itself is
+ * also considered active, even if no member of the block is
+ * referenced."
+ *
+ * Although the spec doesn't state it std430 layouts are expect to behave
+ * the same way. If the variable is in a uniform block with one of those
+ * layouts, do not eliminate it.
+ */
+ if (nir_variable_is_in_block(var) &&
+ (glsl_get_ifc_packing(var->interface_type) !=
+ GLSL_INTERFACE_PACKING_PACKED))
+ return false;
+
+ if (glsl_get_base_type(glsl_without_array(var->type)) ==
+ GLSL_TYPE_SUBROUTINE)
+ return false;
+
+ /* Uniform initializers could get used by another stage */
+ if (var->constant_initializer)
+ return false;
+
+ return true;
+}
+
/**
* Built-in / reserved GL variables names start with "gl_"
*/
}
return true;
}
- /* fallthrough */
}
+ /* fallthrough */
default: {
/* The ARB_program_interface_query spec says:
*/
void
nir_build_program_resource_list(struct gl_context *ctx,
- struct gl_shader_program *prog)
+ struct gl_shader_program *prog,
+ bool rebuild_resourse_list)
{
/* Rebuild resource list. */
- if (prog->data->ProgramResourceList) {
+ if (prog->data->ProgramResourceList && rebuild_resourse_list) {
ralloc_free(prog->data->ProgramResourceList);
prog->data->ProgramResourceList = NULL;
prog->data->NumProgramResourceList = 0;
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)
+ if (uniform->hidden) {
+ for (int j = MESA_SHADER_VERTEX; j < MESA_SHADER_STAGES; j++) {
+ if (!uniform->opaque[j].active ||
+ glsl_get_base_type(uniform->type) != GLSL_TYPE_SUBROUTINE)
+ continue;
+
+ GLenum type =
+ _mesa_shader_stage_to_subroutine_uniform((gl_shader_stage)j);
+ /* add shader subroutines */
+ if (!link_util_add_program_resource(prog, resource_set,
+ type, uniform, 0))
+ return;
+ }
+
continue;
+ }
if (!link_util_should_add_buffer_variable(prog, uniform,
top_level_array_base_offset,
return;
}
+ unsigned mask = prog->data->linked_stages;
+ while (mask) {
+ const int i = u_bit_scan(&mask);
+ struct gl_program *p = prog->_LinkedShaders[i]->Program;
+
+ GLuint type = _mesa_shader_stage_to_subroutine((gl_shader_stage)i);
+ for (unsigned j = 0; j < p->sh.NumSubroutineFunctions; j++) {
+ if (!link_util_add_program_resource(prog, resource_set,
+ type,
+ &p->sh.SubroutineFunctions[j],
+ 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)
+gl_nir_link_spirv(struct gl_context *ctx, struct gl_shader_program *prog,
+ const struct gl_nir_linker_options *options)
{
+ for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
+ struct gl_linked_shader *shader = prog->_LinkedShaders[i];
+ if (shader) {
+ nir_remove_dead_variables(shader->Program->nir, nir_var_uniform,
+ &can_remove_uniform);
+ }
+ }
+
if (!gl_nir_link_uniform_blocks(ctx, prog))
return false;
return true;
}
+
+/**
+ * Validate shader image resources.
+ */
+static void
+check_image_resources(struct gl_context *ctx, struct gl_shader_program *prog)
+{
+ unsigned total_image_units = 0;
+ unsigned fragment_outputs = 0;
+ unsigned total_shader_storage_blocks = 0;
+
+ if (!ctx->Extensions.ARB_shader_image_load_store)
+ return;
+
+ for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
+ struct gl_linked_shader *sh = prog->_LinkedShaders[i];
+ if (!sh)
+ continue;
+
+ total_image_units += sh->Program->info.num_images;
+ total_shader_storage_blocks += sh->Program->info.num_ssbos;
+ }
+
+ if (total_image_units > ctx->Const.MaxCombinedImageUniforms)
+ linker_error(prog, "Too many combined image uniforms\n");
+
+ struct gl_linked_shader *frag_sh =
+ prog->_LinkedShaders[MESA_SHADER_FRAGMENT];
+ if (frag_sh) {
+ uint64_t frag_outputs_written = frag_sh->Program->info.outputs_written;
+ fragment_outputs = util_bitcount64(frag_outputs_written);
+ }
+
+ if (total_image_units + fragment_outputs + total_shader_storage_blocks >
+ ctx->Const.MaxCombinedShaderOutputResources)
+ linker_error(prog, "Too many combined image uniforms, shader storage "
+ " buffers and fragment outputs\n");
+}
+
+bool
+gl_nir_link_glsl(struct gl_context *ctx, struct gl_shader_program *prog)
+{
+ for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
+ struct gl_linked_shader *shader = prog->_LinkedShaders[i];
+ if (shader) {
+ nir_remove_dead_variables(shader->Program->nir, nir_var_uniform,
+ &can_remove_uniform);
+ }
+ }
+
+ if (!gl_nir_link_uniforms(ctx, prog, true))
+ return false;
+
+ link_util_calculate_subroutine_compat(prog);
+ link_util_check_uniform_resources(ctx, prog);
+ link_util_check_subroutine_resources(prog);
+ check_image_resources(ctx, prog);
+ gl_nir_link_assign_atomic_counter_resources(ctx, prog);
+ gl_nir_link_check_atomic_counter_resources(ctx, prog);
+
+ if (prog->data->LinkStatus == LINKING_FAILURE)
+ return false;
+
+ return true;
+}