1/* 2 * Copyright © 2013 Intel Corporation 3 * 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: 10 * 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 13 * Software. 14 * 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. 22 */ 23 24#include "glsl_parser_extras.h" 25#include "ir.h" 26#include "ir_uniform.h" 27#include "linker.h" 28#include "main/errors.h" 29#include "main/macros.h" 30#include "main/mtypes.h" 31 32namespace { 33 /* 34 * Atomic counter uniform as seen by the program. 35 */ 36 struct active_atomic_counter_uniform { 37 unsigned uniform_loc; 38 ir_variable *var; 39 }; 40 41 /* 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(). 45 */ 46 struct active_atomic_buffer { 47 active_atomic_buffer() 48 : uniforms(0), num_uniforms(0), stage_counter_references(), size(0) 49 {} 50 51 ~active_atomic_buffer() 52 { 53 free(uniforms); 54 } 55 56 void push_back(unsigned uniform_loc, ir_variable *var) 57 { 58 active_atomic_counter_uniform *new_uniforms; 59 60 new_uniforms = (active_atomic_counter_uniform *) 61 realloc(uniforms, sizeof(active_atomic_counter_uniform) * 62 (num_uniforms + 1)); 63 64 if (new_uniforms == NULL) { 65 _mesa_error_no_memory(__func__); 66 return; 67 } 68 69 uniforms = new_uniforms; 70 uniforms[num_uniforms].uniform_loc = uniform_loc; 71 uniforms[num_uniforms].var = var; 72 num_uniforms++; 73 } 74 75 active_atomic_counter_uniform *uniforms; 76 unsigned num_uniforms; 77 unsigned stage_counter_references[MESA_SHADER_STAGES]; 78 unsigned size; 79 }; 80 81 int 82 cmp_actives(const void *a, const void *b) 83 { 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; 86 87 return int(first->var->data.offset) - int(second->var->data.offset); 88 } 89 90 bool 91 check_atomic_counters_overlap(const ir_variable *x, const ir_variable *y) 92 { 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())); 97 } 98 99 void 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) 105 { 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 110 * 111 * However this code marks all the counters as active even when they 112 * might not be used. 113 */ 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, 118 shader_stage); 119 } 120 } else { 121 active_atomic_buffer *buf = &buffers[var->data.binding]; 122 gl_uniform_storage *const storage = 123 &prog->data->UniformStorage[*uniform_loc]; 124 125 /* If this is the first time the buffer is used, increment 126 * the counter of buffers used. 127 */ 128 if (buf->size == 0) 129 (*num_buffers)++; 130 131 buf->push_back(*uniform_loc, var); 132 133 /* When checking for atomic counters we should count every member in 134 * an array as an atomic counter reference. 135 */ 136 if (t->is_array()) 137 buf->stage_counter_references[shader_stage] += t->length; 138 else 139 buf->stage_counter_references[shader_stage]++; 140 buf->size = MAX2(buf->size, *offset + t->atomic_size()); 141 142 storage->offset = *offset; 143 *offset += t->atomic_size(); 144 145 (*uniform_loc)++; 146 } 147 } 148 149 active_atomic_buffer * 150 find_active_atomic_counters(struct gl_context *ctx, 151 struct gl_shader_program *prog, 152 unsigned *num_buffers) 153 { 154 active_atomic_buffer *const buffers = 155 new active_atomic_buffer[ctx->Const.MaxAtomicBufferBindings]; 156 157 *num_buffers = 0; 158 159 for (unsigned i = 0; i < MESA_SHADER_STAGES; ++i) { 160 struct gl_linked_shader *sh = prog->_LinkedShaders[i]; 161 if (sh == NULL) 162 continue; 163 164 foreach_in_list(ir_instruction, node, sh->ir) { 165 ir_variable *var = node->as_variable(); 166 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); 172 } 173 } 174 } 175 176 for (unsigned i = 0; i < ctx->Const.MaxAtomicBufferBindings; i++) { 177 if (buffers[i].size == 0) 178 continue; 179 180 qsort(buffers[i].uniforms, buffers[i].num_uniforms, 181 sizeof(active_atomic_counter_uniform), 182 cmp_actives); 183 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. 187 */ 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); 196 } 197 } 198 } 199 return buffers; 200 } 201} 202 203void 204link_assign_atomic_counter_resources(struct gl_context *ctx, 205 struct gl_shader_program *prog) 206{ 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); 211 212 prog->data->AtomicBuffers = rzalloc_array(prog->data, gl_active_atomic_buffer, 213 num_buffers); 214 prog->data->NumAtomicBuffers = num_buffers; 215 216 unsigned i = 0; 217 for (unsigned binding = 0; 218 binding < ctx->Const.MaxAtomicBufferBindings; 219 binding++) { 220 221 /* If the binding was not used, skip. 222 */ 223 if (abs[binding].size == 0) 224 continue; 225 226 active_atomic_buffer &ab = abs[binding]; 227 gl_active_atomic_buffer &mab = prog->data->AtomicBuffers[i]; 228 229 /* Assign buffer-specific fields. */ 230 mab.Binding = binding; 231 mab.MinimumSize = ab.size; 232 mab.Uniforms = rzalloc_array(prog->data->AtomicBuffers, GLuint, 233 ab.num_uniforms); 234 mab.NumUniforms = ab.num_uniforms; 235 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]; 241 242 mab.Uniforms[j] = ab.uniforms[j].uniform_loc; 243 if (!var->data.explicit_binding) 244 var->data.binding = i; 245 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; 252 } 253 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]++; 259 } else { 260 mab.StageReferences[j] = GL_FALSE; 261 } 262 } 263 264 i++; 265 } 266 267 /* Store a list pointers to atomic buffers per stage and store the index 268 * to the intra-stage buffer list in uniform storage. 269 */ 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]); 277 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; 284 285 for (unsigned u = 0; u < atomic_buffer->NumUniforms; u++) { 286 prog->data->UniformStorage[atomic_buffer->Uniforms[u]].opaque[j].index = 287 intra_stage_idx; 288 prog->data->UniformStorage[atomic_buffer->Uniforms[u]].opaque[j].active = 289 true; 290 } 291 292 intra_stage_idx++; 293 } 294 } 295 } 296 } 297 298 delete [] abs; 299 assert(i == num_buffers); 300} 301 302void 303link_check_atomic_counter_resources(struct gl_context *ctx, 304 struct gl_shader_program *prog) 305{ 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; 313 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 317 * requires. 318 */ 319 for (unsigned i = 0; i < ctx->Const.MaxAtomicBufferBindings; i++) { 320 if (abs[i].size == 0) 321 continue; 322 323 for (unsigned j = 0; j < MESA_SHADER_STAGES; ++j) { 324 const unsigned n = abs[i].stage_counter_references[j]; 325 326 if (n) { 327 atomic_counters[j] += n; 328 total_atomic_counters += n; 329 atomic_buffers[j]++; 330 total_atomic_buffers++; 331 } 332 } 333 } 334 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)); 340 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)); 344 } 345 346 if (total_atomic_counters > ctx->Const.MaxCombinedAtomicCounters) 347 linker_error(prog, "Too many combined atomic counters"); 348 349 if (total_atomic_buffers > ctx->Const.MaxCombinedAtomicBuffers) 350 linker_error(prog, "Too many combined atomic buffers"); 351 352 delete [] abs; 353} 354