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 "linker_util.h"
26 #include "gl_nir_linker.h"
27 #include "compiler/glsl/ir_uniform.h" /* for gl_uniform_storage */
28 #include "main/context.h"
30 /* This file do the common link for GLSL atomic counter uniforms, using NIR,
31 * instead of IR as the counter-part glsl/link_uniforms.cpp
33 * Also note that this is tailored for ARB_gl_spirv needs and particularities
36 struct active_atomic_counter_uniform
{
41 struct active_atomic_buffer
{
42 struct active_atomic_counter_uniform
*uniforms
;
43 unsigned num_uniforms
;
44 unsigned uniform_buffer_size
;
45 unsigned stage_counter_references
[MESA_SHADER_STAGES
];
50 add_atomic_counter(const void *ctx
,
51 struct active_atomic_buffer
*buffer
,
55 if (buffer
->num_uniforms
>= buffer
->uniform_buffer_size
) {
56 if (buffer
->uniform_buffer_size
== 0)
57 buffer
->uniform_buffer_size
= 1;
59 buffer
->uniform_buffer_size
*= 2;
60 buffer
->uniforms
= reralloc(ctx
,
62 struct active_atomic_counter_uniform
,
63 buffer
->uniform_buffer_size
);
66 struct active_atomic_counter_uniform
*uniform
=
67 buffer
->uniforms
+ buffer
->num_uniforms
;
68 uniform
->loc
= uniform_loc
;
70 buffer
->num_uniforms
++;
74 process_atomic_variable(const struct glsl_type
*t
,
75 struct gl_shader_program
*prog
,
76 unsigned *uniform_loc
,
78 struct active_atomic_buffer
*buffers
,
79 unsigned *num_buffers
,
81 unsigned shader_stage
)
83 /* FIXME: Arrays of arrays get counted separately. For example:
84 * x1[3][3][2] = 9 uniforms, 18 atomic counters
85 * x2[3][2] = 3 uniforms, 6 atomic counters
86 * x3[2] = 1 uniform, 2 atomic counters
88 * However this code marks all the counters as active even when they
91 if (glsl_type_is_array(t
) &&
92 glsl_type_is_array(glsl_get_array_element(t
))) {
93 for (unsigned i
= 0; i
< glsl_get_length(t
); i
++) {
94 process_atomic_variable(glsl_get_array_element(t
),
103 struct active_atomic_buffer
*buf
= buffers
+ var
->data
.binding
;
104 struct gl_uniform_storage
*const storage
=
105 &prog
->data
->UniformStorage
[*uniform_loc
];
107 /* If this is the first time the buffer is used, increment
108 * the counter of buffers used.
113 add_atomic_counter(buffers
, /* ctx */
118 /* When checking for atomic counters we should count every member in
119 * an array as an atomic counter reference.
121 if (glsl_type_is_array(t
))
122 buf
->stage_counter_references
[shader_stage
] += glsl_get_length(t
);
124 buf
->stage_counter_references
[shader_stage
]++;
125 buf
->size
= MAX2(buf
->size
, *offset
+ glsl_atomic_size(t
));
127 storage
->offset
= *offset
;
128 *offset
+= glsl_atomic_size(t
);
134 static struct active_atomic_buffer
*
135 find_active_atomic_counters(struct gl_context
*ctx
,
136 struct gl_shader_program
*prog
,
137 unsigned *num_buffers
)
139 struct active_atomic_buffer
*buffers
=
140 rzalloc_array(NULL
, /* ctx */
141 struct active_atomic_buffer
,
142 ctx
->Const
.MaxAtomicBufferBindings
);
145 for (unsigned i
= 0; i
< MESA_SHADER_STAGES
; ++i
) {
146 struct gl_linked_shader
*sh
= prog
->_LinkedShaders
[i
];
150 nir_shader
*nir
= sh
->Program
->nir
;
152 nir_foreach_variable(var
, &nir
->uniforms
) {
153 if (!glsl_contains_atomic(var
->type
))
156 int offset
= var
->data
.offset
;
157 unsigned uniform_loc
= var
->data
.location
;
159 process_atomic_variable(var
->type
,
174 check_atomic_counters_overlap(const nir_variable
*x
, const nir_variable
*y
)
176 return ((x
->data
.offset
>= y
->data
.offset
&&
177 x
->data
.offset
< y
->data
.offset
+ glsl_atomic_size(y
->type
)) ||
178 (y
->data
.offset
>= x
->data
.offset
&&
179 y
->data
.offset
< x
->data
.offset
+ glsl_atomic_size(x
->type
)));
183 cmp_active_counter_offsets(const void *a
, const void *b
)
185 const struct active_atomic_counter_uniform
*const first
=
186 (struct active_atomic_counter_uniform
*) a
;
187 const struct active_atomic_counter_uniform
*const second
=
188 (struct active_atomic_counter_uniform
*) b
;
190 return first
->var
->data
.offset
- second
->var
->data
.offset
;
194 gl_nir_link_assign_atomic_counter_resources(struct gl_context
*ctx
,
195 struct gl_shader_program
*prog
)
197 unsigned num_buffers
;
198 unsigned num_atomic_buffers
[MESA_SHADER_STAGES
] = {0};
199 struct active_atomic_buffer
*abs
=
200 find_active_atomic_counters(ctx
, prog
, &num_buffers
);
202 prog
->data
->AtomicBuffers
=
203 rzalloc_array(prog
->data
, struct gl_active_atomic_buffer
, num_buffers
);
204 prog
->data
->NumAtomicBuffers
= num_buffers
;
206 unsigned buffer_idx
= 0;
207 for (unsigned binding
= 0;
208 binding
< ctx
->Const
.MaxAtomicBufferBindings
;
211 /* If the binding was not used, skip.
213 if (abs
[binding
].size
== 0)
216 struct active_atomic_buffer
*ab
= abs
+ binding
;
217 struct gl_active_atomic_buffer
*mab
=
218 prog
->data
->AtomicBuffers
+ buffer_idx
;
220 /* Assign buffer-specific fields. */
221 mab
->Binding
= binding
;
222 mab
->MinimumSize
= ab
->size
;
223 mab
->Uniforms
= rzalloc_array(prog
->data
->AtomicBuffers
, GLuint
,
225 mab
->NumUniforms
= ab
->num_uniforms
;
227 /* Assign counter-specific fields. */
228 for (unsigned j
= 0; j
< ab
->num_uniforms
; j
++) {
229 nir_variable
*var
= ab
->uniforms
[j
].var
;
230 struct gl_uniform_storage
*storage
=
231 &prog
->data
->UniformStorage
[ab
->uniforms
[j
].loc
];
233 mab
->Uniforms
[j
] = ab
->uniforms
[j
].loc
;
235 storage
->atomic_buffer_index
= buffer_idx
;
236 storage
->offset
= var
->data
.offset
;
237 if (glsl_type_is_array(var
->type
)) {
238 const struct glsl_type
*without_array
=
239 glsl_without_array(var
->type
);
240 storage
->array_stride
= glsl_atomic_size(without_array
);
242 storage
->array_stride
= 0;
244 if (!glsl_type_is_matrix(var
->type
))
245 storage
->matrix_stride
= 0;
248 /* Assign stage-specific fields. */
249 for (unsigned stage
= 0; stage
< MESA_SHADER_STAGES
; ++stage
) {
250 if (ab
->stage_counter_references
[stage
]) {
251 mab
->StageReferences
[stage
] = GL_TRUE
;
252 num_atomic_buffers
[stage
]++;
254 mab
->StageReferences
[stage
] = GL_FALSE
;
261 /* Store a list pointers to atomic buffers per stage and store the index
262 * to the intra-stage buffer list in uniform storage.
264 for (unsigned stage
= 0; stage
< MESA_SHADER_STAGES
; ++stage
) {
265 if (prog
->_LinkedShaders
[stage
] == NULL
||
266 num_atomic_buffers
[stage
] <= 0)
269 struct gl_program
*gl_prog
= prog
->_LinkedShaders
[stage
]->Program
;
270 gl_prog
->info
.num_abos
= num_atomic_buffers
[stage
];
271 gl_prog
->sh
.AtomicBuffers
=
272 rzalloc_array(gl_prog
,
273 struct gl_active_atomic_buffer
*,
274 num_atomic_buffers
[stage
]);
276 gl_prog
->nir
->info
.num_abos
= num_atomic_buffers
[stage
];
278 unsigned intra_stage_idx
= 0;
279 for (unsigned i
= 0; i
< num_buffers
; i
++) {
280 struct gl_active_atomic_buffer
*atomic_buffer
=
281 &prog
->data
->AtomicBuffers
[i
];
282 if (!atomic_buffer
->StageReferences
[stage
])
285 gl_prog
->sh
.AtomicBuffers
[intra_stage_idx
] = atomic_buffer
;
287 for (unsigned u
= 0; u
< atomic_buffer
->NumUniforms
; u
++) {
288 GLuint uniform_loc
= atomic_buffer
->Uniforms
[u
];
289 struct gl_opaque_uniform_index
*opaque
=
290 prog
->data
->UniformStorage
[uniform_loc
].opaque
+ stage
;
291 opaque
->index
= intra_stage_idx
;
292 opaque
->active
= true;
299 assert(buffer_idx
== num_buffers
);
305 gl_nir_link_check_atomic_counter_resources(struct gl_context
*ctx
,
306 struct gl_shader_program
*prog
)
308 unsigned num_buffers
;
309 struct active_atomic_buffer
*abs
=
310 find_active_atomic_counters(ctx
, prog
, &num_buffers
);
311 unsigned atomic_counters
[MESA_SHADER_STAGES
] = {0};
312 unsigned atomic_buffers
[MESA_SHADER_STAGES
] = {0};
313 unsigned total_atomic_counters
= 0;
314 unsigned total_atomic_buffers
= 0;
316 /* Sum the required resources. Note that this counts buffers and
317 * counters referenced by several shader stages multiple times
318 * against the combined limit -- That's the behavior the spec
321 for (unsigned i
= 0; i
< ctx
->Const
.MaxAtomicBufferBindings
; i
++) {
322 if (abs
[i
].size
== 0)
325 qsort(abs
[i
].uniforms
, abs
[i
].num_uniforms
,
326 sizeof(struct active_atomic_counter_uniform
),
327 cmp_active_counter_offsets
);
329 for (unsigned j
= 1; j
< abs
[i
].num_uniforms
; j
++) {
330 /* If an overlapping counter found, it must be a reference to the
331 * same counter from a different shader stage.
333 if (check_atomic_counters_overlap(abs
[i
].uniforms
[j
-1].var
,
334 abs
[i
].uniforms
[j
].var
)
335 && strcmp(abs
[i
].uniforms
[j
-1].var
->name
,
336 abs
[i
].uniforms
[j
].var
->name
) != 0) {
337 linker_error(prog
, "Atomic counter %s declared at offset %d "
338 "which is already in use.",
339 abs
[i
].uniforms
[j
].var
->name
,
340 abs
[i
].uniforms
[j
].var
->data
.offset
);
344 for (unsigned j
= 0; j
< MESA_SHADER_STAGES
; ++j
) {
345 const unsigned n
= abs
[i
].stage_counter_references
[j
];
348 atomic_counters
[j
] += n
;
349 total_atomic_counters
+= n
;
351 total_atomic_buffers
++;
356 /* Check that they are within the supported limits. */
357 for (unsigned i
= 0; i
< MESA_SHADER_STAGES
; i
++) {
358 if (atomic_counters
[i
] > ctx
->Const
.Program
[i
].MaxAtomicCounters
)
359 linker_error(prog
, "Too many %s shader atomic counters",
360 _mesa_shader_stage_to_string(i
));
362 if (atomic_buffers
[i
] > ctx
->Const
.Program
[i
].MaxAtomicBuffers
)
363 linker_error(prog
, "Too many %s shader atomic counter buffers",
364 _mesa_shader_stage_to_string(i
));
367 if (total_atomic_counters
> ctx
->Const
.MaxCombinedAtomicCounters
)
368 linker_error(prog
, "Too many combined atomic counters");
370 if (total_atomic_buffers
> ctx
->Const
.MaxCombinedAtomicBuffers
)
371 linker_error(prog
, "Too many combined atomic buffers");