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
)) {
157 /* Add transform feedback varyings and buffers. */
158 if (prog
->last_vert_prog
) {
159 struct gl_transform_feedback_info
*linked_xfb
=
160 prog
->last_vert_prog
->sh
.LinkedTransformFeedback
;
163 if (linked_xfb
->NumVarying
> 0) {
164 for (int i
= 0; i
< linked_xfb
->NumVarying
; i
++) {
165 if (!link_util_add_program_resource(prog
, resource_set
,
166 GL_TRANSFORM_FEEDBACK_VARYING
,
167 &linked_xfb
->Varyings
[i
], 0))
173 for (unsigned i
= 0; i
< ctx
->Const
.MaxTransformFeedbackBuffers
; i
++) {
174 if ((linked_xfb
->ActiveBuffers
>> i
) & 1) {
175 linked_xfb
->Buffers
[i
].Binding
= i
;
176 if (!link_util_add_program_resource(prog
, resource_set
,
177 GL_TRANSFORM_FEEDBACK_BUFFER
,
178 &linked_xfb
->Buffers
[i
], 0))
186 * Here, it is expected that nir_link_uniforms() has already been
187 * called, so that UniformStorage table is already available.
189 int top_level_array_base_offset
= -1;
190 int top_level_array_size_in_bytes
= -1;
191 int second_element_offset
= -1;
192 int block_index
= -1;
193 for (unsigned i
= 0; i
< prog
->data
->NumUniformStorage
; i
++) {
194 struct gl_uniform_storage
*uniform
= &prog
->data
->UniformStorage
[i
];
196 /* Do not add uniforms internally used by Mesa. */
200 if (!link_util_should_add_buffer_variable(prog
, uniform
,
201 top_level_array_base_offset
,
202 top_level_array_size_in_bytes
,
203 second_element_offset
, block_index
))
207 if (prog
->data
->UniformStorage
[i
].offset
>= second_element_offset
) {
208 top_level_array_base_offset
=
209 prog
->data
->UniformStorage
[i
].offset
;
211 top_level_array_size_in_bytes
=
212 prog
->data
->UniformStorage
[i
].top_level_array_size
*
213 prog
->data
->UniformStorage
[i
].top_level_array_stride
;
215 /* Set or reset the second element offset. For non arrays this
218 second_element_offset
= top_level_array_size_in_bytes
?
219 top_level_array_base_offset
+
220 prog
->data
->UniformStorage
[i
].top_level_array_stride
: -1;
222 block_index
= uniform
->block_index
;
225 GLenum interface
= uniform
->is_shader_storage
? GL_BUFFER_VARIABLE
: GL_UNIFORM
;
226 if (!link_util_add_program_resource(prog
, resource_set
, interface
, uniform
,
227 uniform
->active_shader_mask
)) {
233 for (unsigned i
= 0; i
< prog
->data
->NumUniformBlocks
; i
++) {
234 if (!link_util_add_program_resource(prog
, resource_set
, GL_UNIFORM_BLOCK
,
235 &prog
->data
->UniformBlocks
[i
],
236 prog
->data
->UniformBlocks
[i
].stageref
))
240 for (unsigned i
= 0; i
< prog
->data
->NumShaderStorageBlocks
; i
++) {
241 if (!link_util_add_program_resource(prog
, resource_set
, GL_SHADER_STORAGE_BLOCK
,
242 &prog
->data
->ShaderStorageBlocks
[i
],
243 prog
->data
->ShaderStorageBlocks
[i
].stageref
))
247 /* Add atomic counter buffers. */
248 for (unsigned i
= 0; i
< prog
->data
->NumAtomicBuffers
; i
++) {
249 if (!link_util_add_program_resource(prog
, resource_set
, GL_ATOMIC_COUNTER_BUFFER
,
250 &prog
->data
->AtomicBuffers
[i
], 0))
254 _mesa_set_destroy(resource_set
, NULL
);
258 gl_nir_link(struct gl_context
*ctx
, struct gl_shader_program
*prog
,
259 const struct gl_nir_linker_options
*options
)
261 if (!gl_nir_link_uniform_blocks(ctx
, prog
))
264 if (!gl_nir_link_uniforms(ctx
, prog
, options
->fill_parameters
))
267 gl_nir_link_assign_atomic_counter_resources(ctx
, prog
);
268 gl_nir_link_assign_xfb_resources(ctx
, prog
);