1b8e80941Smrg/* 2b8e80941Smrg * Copyright © 2013 Intel Corporation 3b8e80941Smrg * 4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5b8e80941Smrg * copy of this software and associated documentation files (the "Software"), 6b8e80941Smrg * to deal in the Software without restriction, including without limitation 7b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the 9b8e80941Smrg * Software is furnished to do so, subject to the following conditions: 10b8e80941Smrg * 11b8e80941Smrg * The above copyright notice and this permission notice (including the next 12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the 13b8e80941Smrg * Software. 14b8e80941Smrg * 15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20b8e80941Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21b8e80941Smrg * DEALINGS IN THE SOFTWARE. 22b8e80941Smrg */ 23b8e80941Smrg 24b8e80941Smrg#include "glsl_parser_extras.h" 25b8e80941Smrg#include "ir.h" 26b8e80941Smrg#include "ir_uniform.h" 27b8e80941Smrg#include "linker.h" 28b8e80941Smrg#include "main/errors.h" 29b8e80941Smrg#include "main/macros.h" 30b8e80941Smrg#include "main/mtypes.h" 31b8e80941Smrg 32b8e80941Smrgnamespace { 33b8e80941Smrg /* 34b8e80941Smrg * Atomic counter uniform as seen by the program. 35b8e80941Smrg */ 36b8e80941Smrg struct active_atomic_counter_uniform { 37b8e80941Smrg unsigned uniform_loc; 38b8e80941Smrg ir_variable *var; 39b8e80941Smrg }; 40b8e80941Smrg 41b8e80941Smrg /* 42b8e80941Smrg * Atomic counter buffer referenced by the program. There is a one 43b8e80941Smrg * to one correspondence between these and the objects that can be 44b8e80941Smrg * queried using glGetActiveAtomicCounterBufferiv(). 45b8e80941Smrg */ 46b8e80941Smrg struct active_atomic_buffer { 47b8e80941Smrg active_atomic_buffer() 48b8e80941Smrg : uniforms(0), num_uniforms(0), stage_counter_references(), size(0) 49b8e80941Smrg {} 50b8e80941Smrg 51b8e80941Smrg ~active_atomic_buffer() 52b8e80941Smrg { 53b8e80941Smrg free(uniforms); 54b8e80941Smrg } 55b8e80941Smrg 56b8e80941Smrg void push_back(unsigned uniform_loc, ir_variable *var) 57b8e80941Smrg { 58b8e80941Smrg active_atomic_counter_uniform *new_uniforms; 59b8e80941Smrg 60b8e80941Smrg new_uniforms = (active_atomic_counter_uniform *) 61b8e80941Smrg realloc(uniforms, sizeof(active_atomic_counter_uniform) * 62b8e80941Smrg (num_uniforms + 1)); 63b8e80941Smrg 64b8e80941Smrg if (new_uniforms == NULL) { 65b8e80941Smrg _mesa_error_no_memory(__func__); 66b8e80941Smrg return; 67b8e80941Smrg } 68b8e80941Smrg 69b8e80941Smrg uniforms = new_uniforms; 70b8e80941Smrg uniforms[num_uniforms].uniform_loc = uniform_loc; 71b8e80941Smrg uniforms[num_uniforms].var = var; 72b8e80941Smrg num_uniforms++; 73b8e80941Smrg } 74b8e80941Smrg 75b8e80941Smrg active_atomic_counter_uniform *uniforms; 76b8e80941Smrg unsigned num_uniforms; 77b8e80941Smrg unsigned stage_counter_references[MESA_SHADER_STAGES]; 78b8e80941Smrg unsigned size; 79b8e80941Smrg }; 80b8e80941Smrg 81b8e80941Smrg int 82b8e80941Smrg cmp_actives(const void *a, const void *b) 83b8e80941Smrg { 84b8e80941Smrg const active_atomic_counter_uniform *const first = (active_atomic_counter_uniform *) a; 85b8e80941Smrg const active_atomic_counter_uniform *const second = (active_atomic_counter_uniform *) b; 86b8e80941Smrg 87b8e80941Smrg return int(first->var->data.offset) - int(second->var->data.offset); 88b8e80941Smrg } 89b8e80941Smrg 90b8e80941Smrg bool 91b8e80941Smrg check_atomic_counters_overlap(const ir_variable *x, const ir_variable *y) 92b8e80941Smrg { 93b8e80941Smrg return ((x->data.offset >= y->data.offset && 94b8e80941Smrg x->data.offset < y->data.offset + y->type->atomic_size()) || 95b8e80941Smrg (y->data.offset >= x->data.offset && 96b8e80941Smrg y->data.offset < x->data.offset + x->type->atomic_size())); 97b8e80941Smrg } 98b8e80941Smrg 99b8e80941Smrg void 100b8e80941Smrg process_atomic_variable(const glsl_type *t, struct gl_shader_program *prog, 101b8e80941Smrg unsigned *uniform_loc, ir_variable *var, 102b8e80941Smrg active_atomic_buffer *const buffers, 103b8e80941Smrg unsigned *num_buffers, int *offset, 104b8e80941Smrg const unsigned shader_stage) 105b8e80941Smrg { 106b8e80941Smrg /* FIXME: Arrays of arrays get counted separately. For example: 107b8e80941Smrg * x1[3][3][2] = 9 uniforms, 18 atomic counters 108b8e80941Smrg * x2[3][2] = 3 uniforms, 6 atomic counters 109b8e80941Smrg * x3[2] = 1 uniform, 2 atomic counters 110b8e80941Smrg * 111b8e80941Smrg * However this code marks all the counters as active even when they 112b8e80941Smrg * might not be used. 113b8e80941Smrg */ 114b8e80941Smrg if (t->is_array() && t->fields.array->is_array()) { 115b8e80941Smrg for (unsigned i = 0; i < t->length; i++) { 116b8e80941Smrg process_atomic_variable(t->fields.array, prog, uniform_loc, 117b8e80941Smrg var, buffers, num_buffers, offset, 118b8e80941Smrg shader_stage); 119b8e80941Smrg } 120b8e80941Smrg } else { 121b8e80941Smrg active_atomic_buffer *buf = &buffers[var->data.binding]; 122b8e80941Smrg gl_uniform_storage *const storage = 123b8e80941Smrg &prog->data->UniformStorage[*uniform_loc]; 124b8e80941Smrg 125b8e80941Smrg /* If this is the first time the buffer is used, increment 126b8e80941Smrg * the counter of buffers used. 127b8e80941Smrg */ 128b8e80941Smrg if (buf->size == 0) 129b8e80941Smrg (*num_buffers)++; 130b8e80941Smrg 131b8e80941Smrg buf->push_back(*uniform_loc, var); 132b8e80941Smrg 133b8e80941Smrg /* When checking for atomic counters we should count every member in 134b8e80941Smrg * an array as an atomic counter reference. 135b8e80941Smrg */ 136b8e80941Smrg if (t->is_array()) 137b8e80941Smrg buf->stage_counter_references[shader_stage] += t->length; 138b8e80941Smrg else 139b8e80941Smrg buf->stage_counter_references[shader_stage]++; 140b8e80941Smrg buf->size = MAX2(buf->size, *offset + t->atomic_size()); 141b8e80941Smrg 142b8e80941Smrg storage->offset = *offset; 143b8e80941Smrg *offset += t->atomic_size(); 144b8e80941Smrg 145b8e80941Smrg (*uniform_loc)++; 146b8e80941Smrg } 147b8e80941Smrg } 148b8e80941Smrg 149b8e80941Smrg active_atomic_buffer * 150b8e80941Smrg find_active_atomic_counters(struct gl_context *ctx, 151b8e80941Smrg struct gl_shader_program *prog, 152b8e80941Smrg unsigned *num_buffers) 153b8e80941Smrg { 154b8e80941Smrg active_atomic_buffer *const buffers = 155b8e80941Smrg new active_atomic_buffer[ctx->Const.MaxAtomicBufferBindings]; 156b8e80941Smrg 157b8e80941Smrg *num_buffers = 0; 158b8e80941Smrg 159b8e80941Smrg for (unsigned i = 0; i < MESA_SHADER_STAGES; ++i) { 160b8e80941Smrg struct gl_linked_shader *sh = prog->_LinkedShaders[i]; 161b8e80941Smrg if (sh == NULL) 162b8e80941Smrg continue; 163b8e80941Smrg 164b8e80941Smrg foreach_in_list(ir_instruction, node, sh->ir) { 165b8e80941Smrg ir_variable *var = node->as_variable(); 166b8e80941Smrg 167b8e80941Smrg if (var && var->type->contains_atomic()) { 168b8e80941Smrg int offset = var->data.offset; 169b8e80941Smrg unsigned uniform_loc = var->data.location; 170b8e80941Smrg process_atomic_variable(var->type, prog, &uniform_loc, 171b8e80941Smrg var, buffers, num_buffers, &offset, i); 172b8e80941Smrg } 173b8e80941Smrg } 174b8e80941Smrg } 175b8e80941Smrg 176b8e80941Smrg for (unsigned i = 0; i < ctx->Const.MaxAtomicBufferBindings; i++) { 177b8e80941Smrg if (buffers[i].size == 0) 178b8e80941Smrg continue; 179b8e80941Smrg 180b8e80941Smrg qsort(buffers[i].uniforms, buffers[i].num_uniforms, 181b8e80941Smrg sizeof(active_atomic_counter_uniform), 182b8e80941Smrg cmp_actives); 183b8e80941Smrg 184b8e80941Smrg for (unsigned j = 1; j < buffers[i].num_uniforms; j++) { 185b8e80941Smrg /* If an overlapping counter found, it must be a reference to the 186b8e80941Smrg * same counter from a different shader stage. 187b8e80941Smrg */ 188b8e80941Smrg if (check_atomic_counters_overlap(buffers[i].uniforms[j-1].var, 189b8e80941Smrg buffers[i].uniforms[j].var) 190b8e80941Smrg && strcmp(buffers[i].uniforms[j-1].var->name, 191b8e80941Smrg buffers[i].uniforms[j].var->name) != 0) { 192b8e80941Smrg linker_error(prog, "Atomic counter %s declared at offset %d " 193b8e80941Smrg "which is already in use.", 194b8e80941Smrg buffers[i].uniforms[j].var->name, 195b8e80941Smrg buffers[i].uniforms[j].var->data.offset); 196b8e80941Smrg } 197b8e80941Smrg } 198b8e80941Smrg } 199b8e80941Smrg return buffers; 200b8e80941Smrg } 201b8e80941Smrg} 202b8e80941Smrg 203b8e80941Smrgvoid 204b8e80941Smrglink_assign_atomic_counter_resources(struct gl_context *ctx, 205b8e80941Smrg struct gl_shader_program *prog) 206b8e80941Smrg{ 207b8e80941Smrg unsigned num_buffers; 208b8e80941Smrg unsigned num_atomic_buffers[MESA_SHADER_STAGES] = {}; 209b8e80941Smrg active_atomic_buffer *abs = 210b8e80941Smrg find_active_atomic_counters(ctx, prog, &num_buffers); 211b8e80941Smrg 212b8e80941Smrg prog->data->AtomicBuffers = rzalloc_array(prog->data, gl_active_atomic_buffer, 213b8e80941Smrg num_buffers); 214b8e80941Smrg prog->data->NumAtomicBuffers = num_buffers; 215b8e80941Smrg 216b8e80941Smrg unsigned i = 0; 217b8e80941Smrg for (unsigned binding = 0; 218b8e80941Smrg binding < ctx->Const.MaxAtomicBufferBindings; 219b8e80941Smrg binding++) { 220b8e80941Smrg 221b8e80941Smrg /* If the binding was not used, skip. 222b8e80941Smrg */ 223b8e80941Smrg if (abs[binding].size == 0) 224b8e80941Smrg continue; 225b8e80941Smrg 226b8e80941Smrg active_atomic_buffer &ab = abs[binding]; 227b8e80941Smrg gl_active_atomic_buffer &mab = prog->data->AtomicBuffers[i]; 228b8e80941Smrg 229b8e80941Smrg /* Assign buffer-specific fields. */ 230b8e80941Smrg mab.Binding = binding; 231b8e80941Smrg mab.MinimumSize = ab.size; 232b8e80941Smrg mab.Uniforms = rzalloc_array(prog->data->AtomicBuffers, GLuint, 233b8e80941Smrg ab.num_uniforms); 234b8e80941Smrg mab.NumUniforms = ab.num_uniforms; 235b8e80941Smrg 236b8e80941Smrg /* Assign counter-specific fields. */ 237b8e80941Smrg for (unsigned j = 0; j < ab.num_uniforms; j++) { 238b8e80941Smrg ir_variable *const var = ab.uniforms[j].var; 239b8e80941Smrg gl_uniform_storage *const storage = 240b8e80941Smrg &prog->data->UniformStorage[ab.uniforms[j].uniform_loc]; 241b8e80941Smrg 242b8e80941Smrg mab.Uniforms[j] = ab.uniforms[j].uniform_loc; 243b8e80941Smrg if (!var->data.explicit_binding) 244b8e80941Smrg var->data.binding = i; 245b8e80941Smrg 246b8e80941Smrg storage->atomic_buffer_index = i; 247b8e80941Smrg storage->offset = var->data.offset; 248b8e80941Smrg storage->array_stride = (var->type->is_array() ? 249b8e80941Smrg var->type->without_array()->atomic_size() : 0); 250b8e80941Smrg if (!var->type->is_matrix()) 251b8e80941Smrg storage->matrix_stride = 0; 252b8e80941Smrg } 253b8e80941Smrg 254b8e80941Smrg /* Assign stage-specific fields. */ 255b8e80941Smrg for (unsigned j = 0; j < MESA_SHADER_STAGES; ++j) { 256b8e80941Smrg if (ab.stage_counter_references[j]) { 257b8e80941Smrg mab.StageReferences[j] = GL_TRUE; 258b8e80941Smrg num_atomic_buffers[j]++; 259b8e80941Smrg } else { 260b8e80941Smrg mab.StageReferences[j] = GL_FALSE; 261b8e80941Smrg } 262b8e80941Smrg } 263b8e80941Smrg 264b8e80941Smrg i++; 265b8e80941Smrg } 266b8e80941Smrg 267b8e80941Smrg /* Store a list pointers to atomic buffers per stage and store the index 268b8e80941Smrg * to the intra-stage buffer list in uniform storage. 269b8e80941Smrg */ 270b8e80941Smrg for (unsigned j = 0; j < MESA_SHADER_STAGES; ++j) { 271b8e80941Smrg if (prog->_LinkedShaders[j] && num_atomic_buffers[j] > 0) { 272b8e80941Smrg struct gl_program *gl_prog = prog->_LinkedShaders[j]->Program; 273b8e80941Smrg gl_prog->info.num_abos = num_atomic_buffers[j]; 274b8e80941Smrg gl_prog->sh.AtomicBuffers = 275b8e80941Smrg rzalloc_array(gl_prog, gl_active_atomic_buffer *, 276b8e80941Smrg num_atomic_buffers[j]); 277b8e80941Smrg 278b8e80941Smrg unsigned intra_stage_idx = 0; 279b8e80941Smrg for (unsigned i = 0; i < num_buffers; i++) { 280b8e80941Smrg struct gl_active_atomic_buffer *atomic_buffer = 281b8e80941Smrg &prog->data->AtomicBuffers[i]; 282b8e80941Smrg if (atomic_buffer->StageReferences[j]) { 283b8e80941Smrg gl_prog->sh.AtomicBuffers[intra_stage_idx] = atomic_buffer; 284b8e80941Smrg 285b8e80941Smrg for (unsigned u = 0; u < atomic_buffer->NumUniforms; u++) { 286b8e80941Smrg prog->data->UniformStorage[atomic_buffer->Uniforms[u]].opaque[j].index = 287b8e80941Smrg intra_stage_idx; 288b8e80941Smrg prog->data->UniformStorage[atomic_buffer->Uniforms[u]].opaque[j].active = 289b8e80941Smrg true; 290b8e80941Smrg } 291b8e80941Smrg 292b8e80941Smrg intra_stage_idx++; 293b8e80941Smrg } 294b8e80941Smrg } 295b8e80941Smrg } 296b8e80941Smrg } 297b8e80941Smrg 298b8e80941Smrg delete [] abs; 299b8e80941Smrg assert(i == num_buffers); 300b8e80941Smrg} 301b8e80941Smrg 302b8e80941Smrgvoid 303b8e80941Smrglink_check_atomic_counter_resources(struct gl_context *ctx, 304b8e80941Smrg struct gl_shader_program *prog) 305b8e80941Smrg{ 306b8e80941Smrg unsigned num_buffers; 307b8e80941Smrg active_atomic_buffer *const abs = 308b8e80941Smrg find_active_atomic_counters(ctx, prog, &num_buffers); 309b8e80941Smrg unsigned atomic_counters[MESA_SHADER_STAGES] = {}; 310b8e80941Smrg unsigned atomic_buffers[MESA_SHADER_STAGES] = {}; 311b8e80941Smrg unsigned total_atomic_counters = 0; 312b8e80941Smrg unsigned total_atomic_buffers = 0; 313b8e80941Smrg 314b8e80941Smrg /* Sum the required resources. Note that this counts buffers and 315b8e80941Smrg * counters referenced by several shader stages multiple times 316b8e80941Smrg * against the combined limit -- That's the behavior the spec 317b8e80941Smrg * requires. 318b8e80941Smrg */ 319b8e80941Smrg for (unsigned i = 0; i < ctx->Const.MaxAtomicBufferBindings; i++) { 320b8e80941Smrg if (abs[i].size == 0) 321b8e80941Smrg continue; 322b8e80941Smrg 323b8e80941Smrg for (unsigned j = 0; j < MESA_SHADER_STAGES; ++j) { 324b8e80941Smrg const unsigned n = abs[i].stage_counter_references[j]; 325b8e80941Smrg 326b8e80941Smrg if (n) { 327b8e80941Smrg atomic_counters[j] += n; 328b8e80941Smrg total_atomic_counters += n; 329b8e80941Smrg atomic_buffers[j]++; 330b8e80941Smrg total_atomic_buffers++; 331b8e80941Smrg } 332b8e80941Smrg } 333b8e80941Smrg } 334b8e80941Smrg 335b8e80941Smrg /* Check that they are within the supported limits. */ 336b8e80941Smrg for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { 337b8e80941Smrg if (atomic_counters[i] > ctx->Const.Program[i].MaxAtomicCounters) 338b8e80941Smrg linker_error(prog, "Too many %s shader atomic counters", 339b8e80941Smrg _mesa_shader_stage_to_string(i)); 340b8e80941Smrg 341b8e80941Smrg if (atomic_buffers[i] > ctx->Const.Program[i].MaxAtomicBuffers) 342b8e80941Smrg linker_error(prog, "Too many %s shader atomic counter buffers", 343b8e80941Smrg _mesa_shader_stage_to_string(i)); 344b8e80941Smrg } 345b8e80941Smrg 346b8e80941Smrg if (total_atomic_counters > ctx->Const.MaxCombinedAtomicCounters) 347b8e80941Smrg linker_error(prog, "Too many combined atomic counters"); 348b8e80941Smrg 349b8e80941Smrg if (total_atomic_buffers > ctx->Const.MaxCombinedAtomicBuffers) 350b8e80941Smrg linker_error(prog, "Too many combined atomic buffers"); 351b8e80941Smrg 352b8e80941Smrg delete [] abs; 353b8e80941Smrg} 354