2 * Copyright © 2018 Intel Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 #include "gl_nir_linker.h"
26 #include "linker_util.h"
27 #include "main/mtypes.h"
28 #include "ir_uniform.h" /* for gl_uniform_storage */
30 /* This file included general link methods, using NIR, instead of IR as
31 * the counter-part glsl/linker.cpp
33 * Also note that this is tailored for ARB_gl_spirv needs and particularities
37 add_interface_variables(const struct gl_context
*cts
,
38 struct gl_shader_program
*prog
,
39 struct set
*resource_set
,
40 unsigned stage
, GLenum programInterface
)
42 const struct exec_list
*var_list
= NULL
;
44 struct gl_linked_shader
*sh
= prog
->_LinkedShaders
[stage
];
48 nir_shader
*nir
= sh
->Program
->nir
;
51 switch (programInterface
) {
52 case GL_PROGRAM_INPUT
:
53 var_list
= &nir
->inputs
;
55 case GL_PROGRAM_OUTPUT
:
56 var_list
= &nir
->outputs
;
59 assert("!Should not get here");
63 nir_foreach_variable(var
, var_list
) {
64 if (var
->data
.how_declared
== nir_var_hidden
)
68 switch(var
->data
.mode
) {
69 case nir_var_system_value
:
70 case nir_var_shader_in
:
71 if (programInterface
!= GL_PROGRAM_INPUT
)
73 loc_bias
= (stage
== MESA_SHADER_VERTEX
) ? VERT_ATTRIB_GENERIC0
76 case nir_var_shader_out
:
77 if (programInterface
!= GL_PROGRAM_OUTPUT
)
79 loc_bias
= (stage
== MESA_SHADER_FRAGMENT
) ? FRAG_RESULT_DATA0
87 loc_bias
= VARYING_SLOT_PATCH0
;
89 struct gl_shader_variable
*sh_var
=
90 rzalloc(prog
, struct gl_shader_variable
);
92 /* In the ARB_gl_spirv spec, names are considered optional debug info, so
93 * the linker needs to work without them. Returning them is optional.
94 * For simplicity, we ignore names.
97 sh_var
->type
= var
->type
;
98 sh_var
->location
= var
->data
.location
- loc_bias
;
99 sh_var
->index
= var
->data
.index
;
101 if (!link_util_add_program_resource(prog
, resource_set
,
103 sh_var
, 1 << stage
)) {
111 /* TODO: as we keep adding features, this method is becoming more and more
112 * similar to its GLSL counterpart at linker.cpp. Eventually it would be good
113 * to check if they could be refactored, and reduce code duplication somehow
116 nir_build_program_resource_list(struct gl_context
*ctx
,
117 struct gl_shader_program
*prog
)
119 /* Rebuild resource list. */
120 if (prog
->data
->ProgramResourceList
) {
121 ralloc_free(prog
->data
->ProgramResourceList
);
122 prog
->data
->ProgramResourceList
= NULL
;
123 prog
->data
->NumProgramResourceList
= 0;
126 int input_stage
= MESA_SHADER_STAGES
, output_stage
= 0;
128 /* Determine first input and final output stage. These are used to
129 * detect which variables should be enumerated in the resource list
130 * for GL_PROGRAM_INPUT and GL_PROGRAM_OUTPUT.
132 for (unsigned i
= 0; i
< MESA_SHADER_STAGES
; i
++) {
133 if (!prog
->_LinkedShaders
[i
])
135 if (input_stage
== MESA_SHADER_STAGES
)
140 /* Empty shader, no resources. */
141 if (input_stage
== MESA_SHADER_STAGES
&& output_stage
== 0)
144 struct set
*resource_set
= _mesa_pointer_set_create(NULL
);
146 /* Add inputs and outputs to the resource list. */
147 if (!add_interface_variables(ctx
, prog
, resource_set
, input_stage
,
152 if (!add_interface_variables(ctx
, prog
, resource_set
, output_stage
,
153 GL_PROGRAM_OUTPUT
)) {
159 * Here, it is expected that nir_link_uniforms() has already been
160 * called, so that UniformStorage table is already available.
162 int top_level_array_base_offset
= -1;
163 int top_level_array_size_in_bytes
= -1;
164 int second_element_offset
= -1;
165 int block_index
= -1;
166 for (unsigned i
= 0; i
< prog
->data
->NumUniformStorage
; i
++) {
167 struct gl_uniform_storage
*uniform
= &prog
->data
->UniformStorage
[i
];
169 /* Do not add uniforms internally used by Mesa. */
173 if (!link_util_should_add_buffer_variable(prog
, uniform
,
174 top_level_array_base_offset
,
175 top_level_array_size_in_bytes
,
176 second_element_offset
, block_index
))
180 if (prog
->data
->UniformStorage
[i
].offset
>= second_element_offset
) {
181 top_level_array_base_offset
=
182 prog
->data
->UniformStorage
[i
].offset
;
184 top_level_array_size_in_bytes
=
185 prog
->data
->UniformStorage
[i
].top_level_array_size
*
186 prog
->data
->UniformStorage
[i
].top_level_array_stride
;
188 /* Set or reset the second element offset. For non arrays this
191 second_element_offset
= top_level_array_size_in_bytes
?
192 top_level_array_base_offset
+
193 prog
->data
->UniformStorage
[i
].top_level_array_stride
: -1;
195 block_index
= uniform
->block_index
;
198 GLenum interface
= uniform
->is_shader_storage
? GL_BUFFER_VARIABLE
: GL_UNIFORM
;
199 if (!link_util_add_program_resource(prog
, resource_set
, interface
, uniform
,
200 uniform
->active_shader_mask
)) {
206 for (unsigned i
= 0; i
< prog
->data
->NumUniformBlocks
; i
++) {
207 if (!link_util_add_program_resource(prog
, resource_set
, GL_UNIFORM_BLOCK
,
208 &prog
->data
->UniformBlocks
[i
],
209 prog
->data
->UniformBlocks
[i
].stageref
))
213 for (unsigned i
= 0; i
< prog
->data
->NumShaderStorageBlocks
; i
++) {
214 if (!link_util_add_program_resource(prog
, resource_set
, GL_SHADER_STORAGE_BLOCK
,
215 &prog
->data
->ShaderStorageBlocks
[i
],
216 prog
->data
->ShaderStorageBlocks
[i
].stageref
))
220 _mesa_set_destroy(resource_set
, NULL
);