* DEALINGS IN THE SOFTWARE.
*/
+#include "glsl_parser_extras.h"
#include "ir.h"
#include "ir_uniform.h"
#include "linker.h"
* Atomic counter as seen by the program.
*/
struct active_atomic_counter {
- unsigned id;
+ unsigned uniform_loc;
ir_variable *var;
};
free(counters);
}
- void push_back(unsigned id, ir_variable *var)
+ void push_back(unsigned uniform_loc, ir_variable *var)
{
- counters = (active_atomic_counter *)
- realloc(counters, sizeof(active_atomic_counter) * (num_counters + 1));
+ active_atomic_counter *new_counters;
- counters[num_counters].id = id;
+ new_counters = (active_atomic_counter *)
+ realloc(counters, sizeof(active_atomic_counter) *
+ (num_counters + 1));
+
+ if (new_counters == NULL) {
+ _mesa_error_no_memory(__func__);
+ return;
+ }
+
+ counters = new_counters;
+ counters[num_counters].uniform_loc = uniform_loc;
counters[num_counters].var = var;
num_counters++;
}
active_atomic_counter *counters;
unsigned num_counters;
- unsigned stage_references[MESA_SHADER_TYPES];
+ unsigned stage_references[MESA_SHADER_STAGES];
unsigned size;
};
const active_atomic_counter *const first = (active_atomic_counter *) a;
const active_atomic_counter *const second = (active_atomic_counter *) b;
- return int(first->var->atomic.offset) - int(second->var->atomic.offset);
+ return int(first->var->data.atomic.offset) - int(second->var->data.atomic.offset);
}
bool
check_atomic_counters_overlap(const ir_variable *x, const ir_variable *y)
{
- return ((x->atomic.offset >= y->atomic.offset &&
- x->atomic.offset < y->atomic.offset + y->type->atomic_size()) ||
- (y->atomic.offset >= x->atomic.offset &&
- y->atomic.offset < x->atomic.offset + x->type->atomic_size()));
+ return ((x->data.atomic.offset >= y->data.atomic.offset &&
+ x->data.atomic.offset < y->data.atomic.offset + y->type->atomic_size()) ||
+ (y->data.atomic.offset >= x->data.atomic.offset &&
+ y->data.atomic.offset < x->data.atomic.offset + x->type->atomic_size()));
+ }
+
+ void
+ process_atomic_variable(const glsl_type *t, struct gl_shader_program *prog,
+ unsigned *uniform_loc, ir_variable *var,
+ active_atomic_buffer *const buffers,
+ unsigned *num_buffers, int *offset,
+ const unsigned shader_stage)
+ {
+ /* FIXME: Arrays of arrays get counted separately. For example:
+ * x1[3][3][2] = 9 counters
+ * x2[3][2] = 3 counters
+ * x3[2] = 1 counter
+ *
+ * However this code marks all the counters as active even when they
+ * might not be used.
+ */
+ if (t->is_array() && t->fields.array->is_array()) {
+ for (unsigned i = 0; i < t->length; i++) {
+ process_atomic_variable(t->fields.array, prog, uniform_loc,
+ var, buffers, num_buffers, offset,
+ shader_stage);
+ }
+ } else {
+ active_atomic_buffer *buf = &buffers[var->data.binding];
+ gl_uniform_storage *const storage =
+ &prog->UniformStorage[*uniform_loc];
+
+ /* If this is the first time the buffer is used, increment
+ * the counter of buffers used.
+ */
+ if (buf->size == 0)
+ (*num_buffers)++;
+
+ buf->push_back(*uniform_loc, var);
+
+ buf->stage_references[shader_stage]++;
+ buf->size = MAX2(buf->size, *offset + t->atomic_size());
+
+ storage->offset = *offset;
+ *offset += t->atomic_size();
+
+ (*uniform_loc)++;
+ }
}
active_atomic_buffer *
*num_buffers = 0;
- for (unsigned i = 0; i < MESA_SHADER_TYPES; ++i) {
+ for (unsigned i = 0; i < MESA_SHADER_STAGES; ++i) {
struct gl_shader *sh = prog->_LinkedShaders[i];
if (sh == NULL)
continue;
- foreach_list(node, sh->ir) {
- ir_variable *var = ((ir_instruction *)node)->as_variable();
+ foreach_in_list(ir_instruction, node, sh->ir) {
+ ir_variable *var = node->as_variable();
if (var && var->type->contains_atomic()) {
- unsigned id;
- bool found = prog->UniformHash->get(id, var->name);
- assert(found);
- active_atomic_buffer *buf = &buffers[var->binding];
-
- /* If this is the first time the buffer is used, increment
- * the counter of buffers used.
- */
- if (buf->size == 0)
- (*num_buffers)++;
-
- buf->push_back(id, var);
-
- buf->stage_references[i]++;
- buf->size = MAX2(buf->size, var->atomic.offset +
- var->type->atomic_size());
+ int offset = var->data.atomic.offset;
+ unsigned uniform_loc = var->data.location;
+ process_atomic_variable(var->type, prog, &uniform_loc,
+ var, buffers, num_buffers, &offset, i);
}
}
}
linker_error(prog, "Atomic counter %s declared at offset %d "
"which is already in use.",
buffers[i].counters[j].var->name,
- buffers[i].counters[j].var->atomic.offset);
+ buffers[i].counters[j].var->data.atomic.offset);
}
}
}
struct gl_shader_program *prog)
{
unsigned num_buffers;
+ unsigned num_atomic_buffers[MESA_SHADER_STAGES] = {};
active_atomic_buffer *abs =
find_active_atomic_counters(ctx, prog, &num_buffers);
/* Assign counter-specific fields. */
for (unsigned j = 0; j < ab.num_counters; j++) {
ir_variable *const var = ab.counters[j].var;
- const unsigned id = ab.counters[j].id;
- gl_uniform_storage *const storage = &prog->UniformStorage[id];
+ gl_uniform_storage *const storage =
+ &prog->UniformStorage[ab.counters[j].uniform_loc];
+
+ mab.Uniforms[j] = ab.counters[j].uniform_loc;
+ if (!var->data.explicit_binding)
+ var->data.binding = i;
- mab.Uniforms[j] = id;
- var->atomic.buffer_index = i;
storage->atomic_buffer_index = i;
- storage->offset = var->atomic.offset;
+ storage->offset = var->data.atomic.offset;
storage->array_stride = (var->type->is_array() ?
- var->type->element_type()->atomic_size() : 0);
+ var->type->without_array()->atomic_size() : 0);
+ if (!var->type->is_matrix())
+ storage->matrix_stride = 0;
}
/* Assign stage-specific fields. */
- for (unsigned j = 0; j < MESA_SHADER_TYPES; ++j)
- mab.StageReferences[j] =
- (ab.stage_references[j] ? GL_TRUE : GL_FALSE);
+ for (unsigned j = 0; j < MESA_SHADER_STAGES; ++j) {
+ if (ab.stage_references[j]) {
+ mab.StageReferences[j] = GL_TRUE;
+ num_atomic_buffers[j]++;
+ } else {
+ mab.StageReferences[j] = GL_FALSE;
+ }
+ }
i++;
}
+ /* Store a list pointers to atomic buffers per stage and store the index
+ * to the intra-stage buffer list in uniform storage.
+ */
+ for (unsigned j = 0; j < MESA_SHADER_STAGES; ++j) {
+ if (prog->_LinkedShaders[j] && num_atomic_buffers[j] > 0) {
+ prog->_LinkedShaders[j]->NumAtomicBuffers = num_atomic_buffers[j];
+ prog->_LinkedShaders[j]->AtomicBuffers =
+ rzalloc_array(prog, gl_active_atomic_buffer *,
+ num_atomic_buffers[j]);
+
+ unsigned intra_stage_idx = 0;
+ for (unsigned i = 0; i < num_buffers; i++) {
+ struct gl_active_atomic_buffer *atomic_buffer =
+ &prog->AtomicBuffers[i];
+ if (atomic_buffer->StageReferences[j]) {
+ prog->_LinkedShaders[j]->AtomicBuffers[intra_stage_idx] =
+ atomic_buffer;
+
+ for (unsigned u = 0; u < atomic_buffer->NumUniforms; u++) {
+ prog->UniformStorage[atomic_buffer->Uniforms[u]].opaque[j].index =
+ intra_stage_idx;
+ prog->UniformStorage[atomic_buffer->Uniforms[u]].opaque[j].active =
+ true;
+ }
+
+ intra_stage_idx++;
+ }
+ }
+ }
+ }
+
delete [] abs;
assert(i == num_buffers);
}
link_check_atomic_counter_resources(struct gl_context *ctx,
struct gl_shader_program *prog)
{
- STATIC_ASSERT(MESA_SHADER_TYPES == 3);
- static const char *shader_names[MESA_SHADER_TYPES] = {
- "vertex", "geometry", "fragment"
- };
- const unsigned max_atomic_counters[MESA_SHADER_TYPES] = {
- ctx->Const.VertexProgram.MaxAtomicCounters,
- ctx->Const.GeometryProgram.MaxAtomicCounters,
- ctx->Const.FragmentProgram.MaxAtomicCounters
- };
- const unsigned max_atomic_buffers[MESA_SHADER_TYPES] = {
- ctx->Const.VertexProgram.MaxAtomicBuffers,
- ctx->Const.GeometryProgram.MaxAtomicBuffers,
- ctx->Const.FragmentProgram.MaxAtomicBuffers
- };
unsigned num_buffers;
active_atomic_buffer *const abs =
find_active_atomic_counters(ctx, prog, &num_buffers);
- unsigned atomic_counters[MESA_SHADER_TYPES] = {};
- unsigned atomic_buffers[MESA_SHADER_TYPES] = {};
+ unsigned atomic_counters[MESA_SHADER_STAGES] = {};
+ unsigned atomic_buffers[MESA_SHADER_STAGES] = {};
unsigned total_atomic_counters = 0;
unsigned total_atomic_buffers = 0;
if (abs[i].size == 0)
continue;
- for (unsigned j = 0; j < MESA_SHADER_TYPES; ++j) {
+ for (unsigned j = 0; j < MESA_SHADER_STAGES; ++j) {
const unsigned n = abs[i].stage_references[j];
if (n) {
}
/* Check that they are within the supported limits. */
- for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
- if (atomic_counters[i] > max_atomic_counters[i])
+ for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) {
+ if (atomic_counters[i] > ctx->Const.Program[i].MaxAtomicCounters)
linker_error(prog, "Too many %s shader atomic counters",
- shader_names[i]);
+ _mesa_shader_stage_to_string(i));
- if (atomic_buffers[i] > max_atomic_buffers[i])
+ if (atomic_buffers[i] > ctx->Const.Program[i].MaxAtomicBuffers)
linker_error(prog, "Too many %s shader atomic counter buffers",
- shader_names[i]);
+ _mesa_shader_stage_to_string(i));
}
if (total_atomic_counters > ctx->Const.MaxCombinedAtomicCounters)