2 * Copyright © 2013 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
21 * DEALINGS IN THE SOFTWARE.
24 #include "glsl_parser_extras.h"
26 #include "ir_uniform.h"
28 #include "main/errors.h"
29 #include "main/macros.h"
30 #include "main/mtypes.h"
34 * Atomic counter uniform as seen by the program.
36 struct active_atomic_counter_uniform
{
42 * Atomic counter buffer referenced by the program. There is a one
43 * to one correspondence between these and the objects that can be
44 * queried using glGetActiveAtomicCounterBufferiv().
46 struct active_atomic_buffer
{
47 active_atomic_buffer()
48 : uniforms(0), num_uniforms(0), stage_counter_references(), size(0)
51 ~active_atomic_buffer()
56 void push_back(unsigned uniform_loc
, ir_variable
*var
)
58 active_atomic_counter_uniform
*new_uniforms
;
60 new_uniforms
= (active_atomic_counter_uniform
*)
61 realloc(uniforms
, sizeof(active_atomic_counter_uniform
) *
64 if (new_uniforms
== NULL
) {
65 _mesa_error_no_memory(__func__
);
69 uniforms
= new_uniforms
;
70 uniforms
[num_uniforms
].uniform_loc
= uniform_loc
;
71 uniforms
[num_uniforms
].var
= var
;
75 active_atomic_counter_uniform
*uniforms
;
76 unsigned num_uniforms
;
77 unsigned stage_counter_references
[MESA_SHADER_STAGES
];
82 cmp_actives(const void *a
, const void *b
)
84 const active_atomic_counter_uniform
*const first
= (active_atomic_counter_uniform
*) a
;
85 const active_atomic_counter_uniform
*const second
= (active_atomic_counter_uniform
*) b
;
87 return int(first
->var
->data
.offset
) - int(second
->var
->data
.offset
);
91 check_atomic_counters_overlap(const ir_variable
*x
, const ir_variable
*y
)
93 return ((x
->data
.offset
>= y
->data
.offset
&&
94 x
->data
.offset
< y
->data
.offset
+ y
->type
->atomic_size()) ||
95 (y
->data
.offset
>= x
->data
.offset
&&
96 y
->data
.offset
< x
->data
.offset
+ x
->type
->atomic_size()));
100 process_atomic_variable(const glsl_type
*t
, struct gl_shader_program
*prog
,
101 unsigned *uniform_loc
, ir_variable
*var
,
102 active_atomic_buffer
*const buffers
,
103 unsigned *num_buffers
, int *offset
,
104 const unsigned shader_stage
)
106 /* FIXME: Arrays of arrays get counted separately. For example:
107 * x1[3][3][2] = 9 uniforms, 18 atomic counters
108 * x2[3][2] = 3 uniforms, 6 atomic counters
109 * x3[2] = 1 uniform, 2 atomic counters
111 * However this code marks all the counters as active even when they
114 if (t
->is_array() && t
->fields
.array
->is_array()) {
115 for (unsigned i
= 0; i
< t
->length
; i
++) {
116 process_atomic_variable(t
->fields
.array
, prog
, uniform_loc
,
117 var
, buffers
, num_buffers
, offset
,
121 active_atomic_buffer
*buf
= &buffers
[var
->data
.binding
];
122 gl_uniform_storage
*const storage
=
123 &prog
->data
->UniformStorage
[*uniform_loc
];
125 /* If this is the first time the buffer is used, increment
126 * the counter of buffers used.
131 buf
->push_back(*uniform_loc
, var
);
133 /* When checking for atomic counters we should count every member in
134 * an array as an atomic counter reference.
137 buf
->stage_counter_references
[shader_stage
] += t
->length
;
139 buf
->stage_counter_references
[shader_stage
]++;
140 buf
->size
= MAX2(buf
->size
, *offset
+ t
->atomic_size());
142 storage
->offset
= *offset
;
143 *offset
+= t
->atomic_size();
149 active_atomic_buffer
*
150 find_active_atomic_counters(struct gl_context
*ctx
,
151 struct gl_shader_program
*prog
,
152 unsigned *num_buffers
)
154 active_atomic_buffer
*const buffers
=
155 new active_atomic_buffer
[ctx
->Const
.MaxAtomicBufferBindings
];
159 for (unsigned i
= 0; i
< MESA_SHADER_STAGES
; ++i
) {
160 struct gl_linked_shader
*sh
= prog
->_LinkedShaders
[i
];
164 foreach_in_list(ir_instruction
, node
, sh
->ir
) {
165 ir_variable
*var
= node
->as_variable();
167 if (var
&& var
->type
->contains_atomic()) {
168 int offset
= var
->data
.offset
;
169 unsigned uniform_loc
= var
->data
.location
;
170 process_atomic_variable(var
->type
, prog
, &uniform_loc
,
171 var
, buffers
, num_buffers
, &offset
, i
);
176 for (unsigned i
= 0; i
< ctx
->Const
.MaxAtomicBufferBindings
; i
++) {
177 if (buffers
[i
].size
== 0)
180 qsort(buffers
[i
].uniforms
, buffers
[i
].num_uniforms
,
181 sizeof(active_atomic_counter_uniform
),
184 for (unsigned j
= 1; j
< buffers
[i
].num_uniforms
; j
++) {
185 /* If an overlapping counter found, it must be a reference to the
186 * same counter from a different shader stage.
188 if (check_atomic_counters_overlap(buffers
[i
].uniforms
[j
-1].var
,
189 buffers
[i
].uniforms
[j
].var
)
190 && strcmp(buffers
[i
].uniforms
[j
-1].var
->name
,
191 buffers
[i
].uniforms
[j
].var
->name
) != 0) {
192 linker_error(prog
, "Atomic counter %s declared at offset %d "
193 "which is already in use.",
194 buffers
[i
].uniforms
[j
].var
->name
,
195 buffers
[i
].uniforms
[j
].var
->data
.offset
);
204 link_assign_atomic_counter_resources(struct gl_context
*ctx
,
205 struct gl_shader_program
*prog
)
207 unsigned num_buffers
;
208 unsigned num_atomic_buffers
[MESA_SHADER_STAGES
] = {};
209 active_atomic_buffer
*abs
=
210 find_active_atomic_counters(ctx
, prog
, &num_buffers
);
212 prog
->data
->AtomicBuffers
= rzalloc_array(prog
->data
, gl_active_atomic_buffer
,
214 prog
->data
->NumAtomicBuffers
= num_buffers
;
217 for (unsigned binding
= 0;
218 binding
< ctx
->Const
.MaxAtomicBufferBindings
;
221 /* If the binding was not used, skip.
223 if (abs
[binding
].size
== 0)
226 active_atomic_buffer
&ab
= abs
[binding
];
227 gl_active_atomic_buffer
&mab
= prog
->data
->AtomicBuffers
[i
];
229 /* Assign buffer-specific fields. */
230 mab
.Binding
= binding
;
231 mab
.MinimumSize
= ab
.size
;
232 mab
.Uniforms
= rzalloc_array(prog
->data
->AtomicBuffers
, GLuint
,
234 mab
.NumUniforms
= ab
.num_uniforms
;
236 /* Assign counter-specific fields. */
237 for (unsigned j
= 0; j
< ab
.num_uniforms
; j
++) {
238 ir_variable
*const var
= ab
.uniforms
[j
].var
;
239 gl_uniform_storage
*const storage
=
240 &prog
->data
->UniformStorage
[ab
.uniforms
[j
].uniform_loc
];
242 mab
.Uniforms
[j
] = ab
.uniforms
[j
].uniform_loc
;
243 if (!var
->data
.explicit_binding
)
244 var
->data
.binding
= i
;
246 storage
->atomic_buffer_index
= i
;
247 storage
->offset
= var
->data
.offset
;
248 storage
->array_stride
= (var
->type
->is_array() ?
249 var
->type
->without_array()->atomic_size() : 0);
250 if (!var
->type
->is_matrix())
251 storage
->matrix_stride
= 0;
254 /* Assign stage-specific fields. */
255 for (unsigned j
= 0; j
< MESA_SHADER_STAGES
; ++j
) {
256 if (ab
.stage_counter_references
[j
]) {
257 mab
.StageReferences
[j
] = GL_TRUE
;
258 num_atomic_buffers
[j
]++;
260 mab
.StageReferences
[j
] = GL_FALSE
;
267 /* Store a list pointers to atomic buffers per stage and store the index
268 * to the intra-stage buffer list in uniform storage.
270 for (unsigned j
= 0; j
< MESA_SHADER_STAGES
; ++j
) {
271 if (prog
->_LinkedShaders
[j
] && num_atomic_buffers
[j
] > 0) {
272 struct gl_program
*gl_prog
= prog
->_LinkedShaders
[j
]->Program
;
273 gl_prog
->info
.num_abos
= num_atomic_buffers
[j
];
274 gl_prog
->sh
.AtomicBuffers
=
275 rzalloc_array(gl_prog
, gl_active_atomic_buffer
*,
276 num_atomic_buffers
[j
]);
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
[j
]) {
283 gl_prog
->sh
.AtomicBuffers
[intra_stage_idx
] = atomic_buffer
;
285 for (unsigned u
= 0; u
< atomic_buffer
->NumUniforms
; u
++) {
286 prog
->data
->UniformStorage
[atomic_buffer
->Uniforms
[u
]].opaque
[j
].index
=
288 prog
->data
->UniformStorage
[atomic_buffer
->Uniforms
[u
]].opaque
[j
].active
=
299 assert(i
== num_buffers
);
303 link_check_atomic_counter_resources(struct gl_context
*ctx
,
304 struct gl_shader_program
*prog
)
306 unsigned num_buffers
;
307 active_atomic_buffer
*const abs
=
308 find_active_atomic_counters(ctx
, prog
, &num_buffers
);
309 unsigned atomic_counters
[MESA_SHADER_STAGES
] = {};
310 unsigned atomic_buffers
[MESA_SHADER_STAGES
] = {};
311 unsigned total_atomic_counters
= 0;
312 unsigned total_atomic_buffers
= 0;
314 /* Sum the required resources. Note that this counts buffers and
315 * counters referenced by several shader stages multiple times
316 * against the combined limit -- That's the behavior the spec
319 for (unsigned i
= 0; i
< ctx
->Const
.MaxAtomicBufferBindings
; i
++) {
320 if (abs
[i
].size
== 0)
323 for (unsigned j
= 0; j
< MESA_SHADER_STAGES
; ++j
) {
324 const unsigned n
= abs
[i
].stage_counter_references
[j
];
327 atomic_counters
[j
] += n
;
328 total_atomic_counters
+= n
;
330 total_atomic_buffers
++;
335 /* Check that they are within the supported limits. */
336 for (unsigned i
= 0; i
< MESA_SHADER_STAGES
; i
++) {
337 if (atomic_counters
[i
] > ctx
->Const
.Program
[i
].MaxAtomicCounters
)
338 linker_error(prog
, "Too many %s shader atomic counters",
339 _mesa_shader_stage_to_string(i
));
341 if (atomic_buffers
[i
] > ctx
->Const
.Program
[i
].MaxAtomicBuffers
)
342 linker_error(prog
, "Too many %s shader atomic counter buffers",
343 _mesa_shader_stage_to_string(i
));
346 if (total_atomic_counters
> ctx
->Const
.MaxCombinedAtomicCounters
)
347 linker_error(prog
, "Too many combined atomic counters");
349 if (total_atomic_buffers
> ctx
->Const
.MaxCombinedAtomicBuffers
)
350 linker_error(prog
, "Too many combined atomic buffers");