101e04c3fSmrg/* 201e04c3fSmrg * Copyright © 2013 Intel Corporation 301e04c3fSmrg * 401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 501e04c3fSmrg * copy of this software and associated documentation files (the "Software"), 601e04c3fSmrg * to deal in the Software without restriction, including without limitation 701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the 901e04c3fSmrg * Software is furnished to do so, subject to the following conditions: 1001e04c3fSmrg * 1101e04c3fSmrg * The above copyright notice and this permission notice (including the next 1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the 1301e04c3fSmrg * Software. 1401e04c3fSmrg * 1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2001e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 2101e04c3fSmrg * DEALINGS IN THE SOFTWARE. 2201e04c3fSmrg */ 2301e04c3fSmrg 2401e04c3fSmrg#include "glsl_parser_extras.h" 2501e04c3fSmrg#include "ir.h" 2601e04c3fSmrg#include "ir_uniform.h" 2701e04c3fSmrg#include "linker.h" 2801e04c3fSmrg#include "main/errors.h" 2901e04c3fSmrg#include "main/macros.h" 3001e04c3fSmrg#include "main/mtypes.h" 3101e04c3fSmrg 3201e04c3fSmrgnamespace { 3301e04c3fSmrg /* 3401e04c3fSmrg * Atomic counter uniform as seen by the program. 3501e04c3fSmrg */ 3601e04c3fSmrg struct active_atomic_counter_uniform { 3701e04c3fSmrg unsigned uniform_loc; 3801e04c3fSmrg ir_variable *var; 3901e04c3fSmrg }; 4001e04c3fSmrg 4101e04c3fSmrg /* 4201e04c3fSmrg * Atomic counter buffer referenced by the program. There is a one 4301e04c3fSmrg * to one correspondence between these and the objects that can be 4401e04c3fSmrg * queried using glGetActiveAtomicCounterBufferiv(). 4501e04c3fSmrg */ 4601e04c3fSmrg struct active_atomic_buffer { 4701e04c3fSmrg active_atomic_buffer() 4801e04c3fSmrg : uniforms(0), num_uniforms(0), stage_counter_references(), size(0) 4901e04c3fSmrg {} 5001e04c3fSmrg 5101e04c3fSmrg ~active_atomic_buffer() 5201e04c3fSmrg { 5301e04c3fSmrg free(uniforms); 5401e04c3fSmrg } 5501e04c3fSmrg 5601e04c3fSmrg void push_back(unsigned uniform_loc, ir_variable *var) 5701e04c3fSmrg { 5801e04c3fSmrg active_atomic_counter_uniform *new_uniforms; 5901e04c3fSmrg 6001e04c3fSmrg new_uniforms = (active_atomic_counter_uniform *) 6101e04c3fSmrg realloc(uniforms, sizeof(active_atomic_counter_uniform) * 6201e04c3fSmrg (num_uniforms + 1)); 6301e04c3fSmrg 6401e04c3fSmrg if (new_uniforms == NULL) { 6501e04c3fSmrg _mesa_error_no_memory(__func__); 6601e04c3fSmrg return; 6701e04c3fSmrg } 6801e04c3fSmrg 6901e04c3fSmrg uniforms = new_uniforms; 7001e04c3fSmrg uniforms[num_uniforms].uniform_loc = uniform_loc; 7101e04c3fSmrg uniforms[num_uniforms].var = var; 7201e04c3fSmrg num_uniforms++; 7301e04c3fSmrg } 7401e04c3fSmrg 7501e04c3fSmrg active_atomic_counter_uniform *uniforms; 7601e04c3fSmrg unsigned num_uniforms; 7701e04c3fSmrg unsigned stage_counter_references[MESA_SHADER_STAGES]; 7801e04c3fSmrg unsigned size; 7901e04c3fSmrg }; 8001e04c3fSmrg 8101e04c3fSmrg int 8201e04c3fSmrg cmp_actives(const void *a, const void *b) 8301e04c3fSmrg { 8401e04c3fSmrg const active_atomic_counter_uniform *const first = (active_atomic_counter_uniform *) a; 8501e04c3fSmrg const active_atomic_counter_uniform *const second = (active_atomic_counter_uniform *) b; 8601e04c3fSmrg 8701e04c3fSmrg return int(first->var->data.offset) - int(second->var->data.offset); 8801e04c3fSmrg } 8901e04c3fSmrg 9001e04c3fSmrg bool 9101e04c3fSmrg check_atomic_counters_overlap(const ir_variable *x, const ir_variable *y) 9201e04c3fSmrg { 9301e04c3fSmrg return ((x->data.offset >= y->data.offset && 9401e04c3fSmrg x->data.offset < y->data.offset + y->type->atomic_size()) || 9501e04c3fSmrg (y->data.offset >= x->data.offset && 9601e04c3fSmrg y->data.offset < x->data.offset + x->type->atomic_size())); 9701e04c3fSmrg } 9801e04c3fSmrg 9901e04c3fSmrg void 10001e04c3fSmrg process_atomic_variable(const glsl_type *t, struct gl_shader_program *prog, 10101e04c3fSmrg unsigned *uniform_loc, ir_variable *var, 10201e04c3fSmrg active_atomic_buffer *const buffers, 10301e04c3fSmrg unsigned *num_buffers, int *offset, 10401e04c3fSmrg const unsigned shader_stage) 10501e04c3fSmrg { 10601e04c3fSmrg /* FIXME: Arrays of arrays get counted separately. For example: 10701e04c3fSmrg * x1[3][3][2] = 9 uniforms, 18 atomic counters 10801e04c3fSmrg * x2[3][2] = 3 uniforms, 6 atomic counters 10901e04c3fSmrg * x3[2] = 1 uniform, 2 atomic counters 11001e04c3fSmrg * 11101e04c3fSmrg * However this code marks all the counters as active even when they 11201e04c3fSmrg * might not be used. 11301e04c3fSmrg */ 11401e04c3fSmrg if (t->is_array() && t->fields.array->is_array()) { 11501e04c3fSmrg for (unsigned i = 0; i < t->length; i++) { 11601e04c3fSmrg process_atomic_variable(t->fields.array, prog, uniform_loc, 11701e04c3fSmrg var, buffers, num_buffers, offset, 11801e04c3fSmrg shader_stage); 11901e04c3fSmrg } 12001e04c3fSmrg } else { 12101e04c3fSmrg active_atomic_buffer *buf = &buffers[var->data.binding]; 12201e04c3fSmrg gl_uniform_storage *const storage = 12301e04c3fSmrg &prog->data->UniformStorage[*uniform_loc]; 12401e04c3fSmrg 12501e04c3fSmrg /* If this is the first time the buffer is used, increment 12601e04c3fSmrg * the counter of buffers used. 12701e04c3fSmrg */ 12801e04c3fSmrg if (buf->size == 0) 12901e04c3fSmrg (*num_buffers)++; 13001e04c3fSmrg 13101e04c3fSmrg buf->push_back(*uniform_loc, var); 13201e04c3fSmrg 13301e04c3fSmrg /* When checking for atomic counters we should count every member in 13401e04c3fSmrg * an array as an atomic counter reference. 13501e04c3fSmrg */ 13601e04c3fSmrg if (t->is_array()) 13701e04c3fSmrg buf->stage_counter_references[shader_stage] += t->length; 13801e04c3fSmrg else 13901e04c3fSmrg buf->stage_counter_references[shader_stage]++; 14001e04c3fSmrg buf->size = MAX2(buf->size, *offset + t->atomic_size()); 14101e04c3fSmrg 14201e04c3fSmrg storage->offset = *offset; 14301e04c3fSmrg *offset += t->atomic_size(); 14401e04c3fSmrg 14501e04c3fSmrg (*uniform_loc)++; 14601e04c3fSmrg } 14701e04c3fSmrg } 14801e04c3fSmrg 14901e04c3fSmrg active_atomic_buffer * 15001e04c3fSmrg find_active_atomic_counters(struct gl_context *ctx, 15101e04c3fSmrg struct gl_shader_program *prog, 15201e04c3fSmrg unsigned *num_buffers) 15301e04c3fSmrg { 15401e04c3fSmrg active_atomic_buffer *const buffers = 15501e04c3fSmrg new active_atomic_buffer[ctx->Const.MaxAtomicBufferBindings]; 15601e04c3fSmrg 15701e04c3fSmrg *num_buffers = 0; 15801e04c3fSmrg 15901e04c3fSmrg for (unsigned i = 0; i < MESA_SHADER_STAGES; ++i) { 16001e04c3fSmrg struct gl_linked_shader *sh = prog->_LinkedShaders[i]; 16101e04c3fSmrg if (sh == NULL) 16201e04c3fSmrg continue; 16301e04c3fSmrg 16401e04c3fSmrg foreach_in_list(ir_instruction, node, sh->ir) { 16501e04c3fSmrg ir_variable *var = node->as_variable(); 16601e04c3fSmrg 16701e04c3fSmrg if (var && var->type->contains_atomic()) { 16801e04c3fSmrg int offset = var->data.offset; 16901e04c3fSmrg unsigned uniform_loc = var->data.location; 17001e04c3fSmrg process_atomic_variable(var->type, prog, &uniform_loc, 17101e04c3fSmrg var, buffers, num_buffers, &offset, i); 17201e04c3fSmrg } 17301e04c3fSmrg } 17401e04c3fSmrg } 17501e04c3fSmrg 17601e04c3fSmrg for (unsigned i = 0; i < ctx->Const.MaxAtomicBufferBindings; i++) { 17701e04c3fSmrg if (buffers[i].size == 0) 17801e04c3fSmrg continue; 17901e04c3fSmrg 18001e04c3fSmrg qsort(buffers[i].uniforms, buffers[i].num_uniforms, 18101e04c3fSmrg sizeof(active_atomic_counter_uniform), 18201e04c3fSmrg cmp_actives); 18301e04c3fSmrg 18401e04c3fSmrg for (unsigned j = 1; j < buffers[i].num_uniforms; j++) { 18501e04c3fSmrg /* If an overlapping counter found, it must be a reference to the 18601e04c3fSmrg * same counter from a different shader stage. 18701e04c3fSmrg */ 18801e04c3fSmrg if (check_atomic_counters_overlap(buffers[i].uniforms[j-1].var, 18901e04c3fSmrg buffers[i].uniforms[j].var) 19001e04c3fSmrg && strcmp(buffers[i].uniforms[j-1].var->name, 19101e04c3fSmrg buffers[i].uniforms[j].var->name) != 0) { 19201e04c3fSmrg linker_error(prog, "Atomic counter %s declared at offset %d " 19301e04c3fSmrg "which is already in use.", 19401e04c3fSmrg buffers[i].uniforms[j].var->name, 19501e04c3fSmrg buffers[i].uniforms[j].var->data.offset); 19601e04c3fSmrg } 19701e04c3fSmrg } 19801e04c3fSmrg } 19901e04c3fSmrg return buffers; 20001e04c3fSmrg } 20101e04c3fSmrg} 20201e04c3fSmrg 20301e04c3fSmrgvoid 20401e04c3fSmrglink_assign_atomic_counter_resources(struct gl_context *ctx, 20501e04c3fSmrg struct gl_shader_program *prog) 20601e04c3fSmrg{ 20701e04c3fSmrg unsigned num_buffers; 20801e04c3fSmrg unsigned num_atomic_buffers[MESA_SHADER_STAGES] = {}; 20901e04c3fSmrg active_atomic_buffer *abs = 21001e04c3fSmrg find_active_atomic_counters(ctx, prog, &num_buffers); 21101e04c3fSmrg 21201e04c3fSmrg prog->data->AtomicBuffers = rzalloc_array(prog->data, gl_active_atomic_buffer, 21301e04c3fSmrg num_buffers); 21401e04c3fSmrg prog->data->NumAtomicBuffers = num_buffers; 21501e04c3fSmrg 21601e04c3fSmrg unsigned i = 0; 21701e04c3fSmrg for (unsigned binding = 0; 21801e04c3fSmrg binding < ctx->Const.MaxAtomicBufferBindings; 21901e04c3fSmrg binding++) { 22001e04c3fSmrg 22101e04c3fSmrg /* If the binding was not used, skip. 22201e04c3fSmrg */ 22301e04c3fSmrg if (abs[binding].size == 0) 22401e04c3fSmrg continue; 22501e04c3fSmrg 22601e04c3fSmrg active_atomic_buffer &ab = abs[binding]; 22701e04c3fSmrg gl_active_atomic_buffer &mab = prog->data->AtomicBuffers[i]; 22801e04c3fSmrg 22901e04c3fSmrg /* Assign buffer-specific fields. */ 23001e04c3fSmrg mab.Binding = binding; 23101e04c3fSmrg mab.MinimumSize = ab.size; 23201e04c3fSmrg mab.Uniforms = rzalloc_array(prog->data->AtomicBuffers, GLuint, 23301e04c3fSmrg ab.num_uniforms); 23401e04c3fSmrg mab.NumUniforms = ab.num_uniforms; 23501e04c3fSmrg 23601e04c3fSmrg /* Assign counter-specific fields. */ 23701e04c3fSmrg for (unsigned j = 0; j < ab.num_uniforms; j++) { 23801e04c3fSmrg ir_variable *const var = ab.uniforms[j].var; 23901e04c3fSmrg gl_uniform_storage *const storage = 24001e04c3fSmrg &prog->data->UniformStorage[ab.uniforms[j].uniform_loc]; 24101e04c3fSmrg 24201e04c3fSmrg mab.Uniforms[j] = ab.uniforms[j].uniform_loc; 24301e04c3fSmrg if (!var->data.explicit_binding) 24401e04c3fSmrg var->data.binding = i; 24501e04c3fSmrg 24601e04c3fSmrg storage->atomic_buffer_index = i; 24701e04c3fSmrg storage->offset = var->data.offset; 24801e04c3fSmrg storage->array_stride = (var->type->is_array() ? 24901e04c3fSmrg var->type->without_array()->atomic_size() : 0); 25001e04c3fSmrg if (!var->type->is_matrix()) 25101e04c3fSmrg storage->matrix_stride = 0; 25201e04c3fSmrg } 25301e04c3fSmrg 25401e04c3fSmrg /* Assign stage-specific fields. */ 25501e04c3fSmrg for (unsigned j = 0; j < MESA_SHADER_STAGES; ++j) { 25601e04c3fSmrg if (ab.stage_counter_references[j]) { 25701e04c3fSmrg mab.StageReferences[j] = GL_TRUE; 25801e04c3fSmrg num_atomic_buffers[j]++; 25901e04c3fSmrg } else { 26001e04c3fSmrg mab.StageReferences[j] = GL_FALSE; 26101e04c3fSmrg } 26201e04c3fSmrg } 26301e04c3fSmrg 26401e04c3fSmrg i++; 26501e04c3fSmrg } 26601e04c3fSmrg 26701e04c3fSmrg /* Store a list pointers to atomic buffers per stage and store the index 26801e04c3fSmrg * to the intra-stage buffer list in uniform storage. 26901e04c3fSmrg */ 27001e04c3fSmrg for (unsigned j = 0; j < MESA_SHADER_STAGES; ++j) { 27101e04c3fSmrg if (prog->_LinkedShaders[j] && num_atomic_buffers[j] > 0) { 27201e04c3fSmrg struct gl_program *gl_prog = prog->_LinkedShaders[j]->Program; 27301e04c3fSmrg gl_prog->info.num_abos = num_atomic_buffers[j]; 27401e04c3fSmrg gl_prog->sh.AtomicBuffers = 27501e04c3fSmrg rzalloc_array(gl_prog, gl_active_atomic_buffer *, 27601e04c3fSmrg num_atomic_buffers[j]); 27701e04c3fSmrg 27801e04c3fSmrg unsigned intra_stage_idx = 0; 27901e04c3fSmrg for (unsigned i = 0; i < num_buffers; i++) { 28001e04c3fSmrg struct gl_active_atomic_buffer *atomic_buffer = 28101e04c3fSmrg &prog->data->AtomicBuffers[i]; 28201e04c3fSmrg if (atomic_buffer->StageReferences[j]) { 28301e04c3fSmrg gl_prog->sh.AtomicBuffers[intra_stage_idx] = atomic_buffer; 28401e04c3fSmrg 28501e04c3fSmrg for (unsigned u = 0; u < atomic_buffer->NumUniforms; u++) { 28601e04c3fSmrg prog->data->UniformStorage[atomic_buffer->Uniforms[u]].opaque[j].index = 28701e04c3fSmrg intra_stage_idx; 28801e04c3fSmrg prog->data->UniformStorage[atomic_buffer->Uniforms[u]].opaque[j].active = 28901e04c3fSmrg true; 29001e04c3fSmrg } 29101e04c3fSmrg 29201e04c3fSmrg intra_stage_idx++; 29301e04c3fSmrg } 29401e04c3fSmrg } 29501e04c3fSmrg } 29601e04c3fSmrg } 29701e04c3fSmrg 29801e04c3fSmrg delete [] abs; 29901e04c3fSmrg assert(i == num_buffers); 30001e04c3fSmrg} 30101e04c3fSmrg 30201e04c3fSmrgvoid 30301e04c3fSmrglink_check_atomic_counter_resources(struct gl_context *ctx, 30401e04c3fSmrg struct gl_shader_program *prog) 30501e04c3fSmrg{ 30601e04c3fSmrg unsigned num_buffers; 30701e04c3fSmrg active_atomic_buffer *const abs = 30801e04c3fSmrg find_active_atomic_counters(ctx, prog, &num_buffers); 30901e04c3fSmrg unsigned atomic_counters[MESA_SHADER_STAGES] = {}; 31001e04c3fSmrg unsigned atomic_buffers[MESA_SHADER_STAGES] = {}; 31101e04c3fSmrg unsigned total_atomic_counters = 0; 31201e04c3fSmrg unsigned total_atomic_buffers = 0; 31301e04c3fSmrg 31401e04c3fSmrg /* Sum the required resources. Note that this counts buffers and 31501e04c3fSmrg * counters referenced by several shader stages multiple times 31601e04c3fSmrg * against the combined limit -- That's the behavior the spec 31701e04c3fSmrg * requires. 31801e04c3fSmrg */ 31901e04c3fSmrg for (unsigned i = 0; i < ctx->Const.MaxAtomicBufferBindings; i++) { 32001e04c3fSmrg if (abs[i].size == 0) 32101e04c3fSmrg continue; 32201e04c3fSmrg 32301e04c3fSmrg for (unsigned j = 0; j < MESA_SHADER_STAGES; ++j) { 32401e04c3fSmrg const unsigned n = abs[i].stage_counter_references[j]; 32501e04c3fSmrg 32601e04c3fSmrg if (n) { 32701e04c3fSmrg atomic_counters[j] += n; 32801e04c3fSmrg total_atomic_counters += n; 32901e04c3fSmrg atomic_buffers[j]++; 33001e04c3fSmrg total_atomic_buffers++; 33101e04c3fSmrg } 33201e04c3fSmrg } 33301e04c3fSmrg } 33401e04c3fSmrg 33501e04c3fSmrg /* Check that they are within the supported limits. */ 33601e04c3fSmrg for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { 33701e04c3fSmrg if (atomic_counters[i] > ctx->Const.Program[i].MaxAtomicCounters) 33801e04c3fSmrg linker_error(prog, "Too many %s shader atomic counters", 33901e04c3fSmrg _mesa_shader_stage_to_string(i)); 34001e04c3fSmrg 34101e04c3fSmrg if (atomic_buffers[i] > ctx->Const.Program[i].MaxAtomicBuffers) 34201e04c3fSmrg linker_error(prog, "Too many %s shader atomic counter buffers", 34301e04c3fSmrg _mesa_shader_stage_to_string(i)); 34401e04c3fSmrg } 34501e04c3fSmrg 34601e04c3fSmrg if (total_atomic_counters > ctx->Const.MaxCombinedAtomicCounters) 34701e04c3fSmrg linker_error(prog, "Too many combined atomic counters"); 34801e04c3fSmrg 34901e04c3fSmrg if (total_atomic_buffers > ctx->Const.MaxCombinedAtomicBuffers) 35001e04c3fSmrg linker_error(prog, "Too many combined atomic buffers"); 35101e04c3fSmrg 35201e04c3fSmrg delete [] abs; 35301e04c3fSmrg} 354