1/* 2 * Copyright © 2018 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 DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24#include "nir.h" 25#include "linker_util.h" 26#include "gl_nir_linker.h" 27#include "compiler/glsl/ir_uniform.h" /* for gl_uniform_storage */ 28#include "main/context.h" 29 30/* This file do the common link for GLSL atomic counter uniforms, using NIR, 31 * instead of IR as the counter-part glsl/link_uniforms.cpp 32 * 33 * Also note that this is tailored for ARB_gl_spirv needs and particularities 34 */ 35 36struct active_atomic_counter_uniform { 37 unsigned loc; 38 nir_variable *var; 39}; 40 41struct active_atomic_buffer { 42 struct active_atomic_counter_uniform *uniforms; 43 unsigned num_uniforms; 44 unsigned uniform_buffer_size; 45 unsigned stage_counter_references[MESA_SHADER_STAGES]; 46 unsigned size; 47}; 48 49static void 50add_atomic_counter(const void *ctx, 51 struct active_atomic_buffer *buffer, 52 unsigned uniform_loc, 53 nir_variable *var) 54{ 55 if (buffer->num_uniforms >= buffer->uniform_buffer_size) { 56 if (buffer->uniform_buffer_size == 0) 57 buffer->uniform_buffer_size = 1; 58 else 59 buffer->uniform_buffer_size *= 2; 60 buffer->uniforms = reralloc(ctx, 61 buffer->uniforms, 62 struct active_atomic_counter_uniform, 63 buffer->uniform_buffer_size); 64 } 65 66 struct active_atomic_counter_uniform *uniform = 67 buffer->uniforms + buffer->num_uniforms; 68 uniform->loc = uniform_loc; 69 uniform->var = var; 70 buffer->num_uniforms++; 71} 72 73static void 74process_atomic_variable(const struct glsl_type *t, 75 struct gl_shader_program *prog, 76 unsigned *uniform_loc, 77 nir_variable *var, 78 struct active_atomic_buffer *buffers, 79 unsigned *num_buffers, 80 int *offset, 81 unsigned shader_stage) 82{ 83 /* FIXME: Arrays of arrays get counted separately. For example: 84 * x1[3][3][2] = 9 uniforms, 18 atomic counters 85 * x2[3][2] = 3 uniforms, 6 atomic counters 86 * x3[2] = 1 uniform, 2 atomic counters 87 * 88 * However this code marks all the counters as active even when they 89 * might not be used. 90 */ 91 if (glsl_type_is_array(t) && 92 glsl_type_is_array(glsl_get_array_element(t))) { 93 for (unsigned i = 0; i < glsl_get_length(t); i++) { 94 process_atomic_variable(glsl_get_array_element(t), 95 prog, 96 uniform_loc, 97 var, 98 buffers, num_buffers, 99 offset, 100 shader_stage); 101 } 102 } else { 103 struct active_atomic_buffer *buf = buffers + var->data.binding; 104 struct gl_uniform_storage *const storage = 105 &prog->data->UniformStorage[*uniform_loc]; 106 107 /* If this is the first time the buffer is used, increment 108 * the counter of buffers used. 109 */ 110 if (buf->size == 0) 111 (*num_buffers)++; 112 113 add_atomic_counter(buffers, /* ctx */ 114 buf, 115 *uniform_loc, 116 var); 117 118 /* When checking for atomic counters we should count every member in 119 * an array as an atomic counter reference. 120 */ 121 if (glsl_type_is_array(t)) 122 buf->stage_counter_references[shader_stage] += glsl_get_length(t); 123 else 124 buf->stage_counter_references[shader_stage]++; 125 buf->size = MAX2(buf->size, *offset + glsl_atomic_size(t)); 126 127 storage->offset = *offset; 128 *offset += glsl_atomic_size(t); 129 130 (*uniform_loc)++; 131 } 132} 133 134static struct active_atomic_buffer * 135find_active_atomic_counters(struct gl_context *ctx, 136 struct gl_shader_program *prog, 137 unsigned *num_buffers) 138{ 139 struct active_atomic_buffer *buffers = 140 rzalloc_array(NULL, /* ctx */ 141 struct active_atomic_buffer, 142 ctx->Const.MaxAtomicBufferBindings); 143 *num_buffers = 0; 144 145 for (unsigned i = 0; i < MESA_SHADER_STAGES; ++i) { 146 struct gl_linked_shader *sh = prog->_LinkedShaders[i]; 147 if (sh == NULL) 148 continue; 149 150 nir_shader *nir = sh->Program->nir; 151 152 nir_foreach_variable(var, &nir->uniforms) { 153 if (!glsl_contains_atomic(var->type)) 154 continue; 155 156 int offset = var->data.offset; 157 unsigned uniform_loc = var->data.location; 158 159 process_atomic_variable(var->type, 160 prog, 161 &uniform_loc, 162 var, 163 buffers, 164 num_buffers, 165 &offset, 166 i); 167 } 168 } 169 170 return buffers; 171} 172 173void 174gl_nir_link_assign_atomic_counter_resources(struct gl_context *ctx, 175 struct gl_shader_program *prog) 176{ 177 unsigned num_buffers; 178 unsigned num_atomic_buffers[MESA_SHADER_STAGES] = {0}; 179 struct active_atomic_buffer *abs = 180 find_active_atomic_counters(ctx, prog, &num_buffers); 181 182 prog->data->AtomicBuffers = 183 rzalloc_array(prog->data, struct gl_active_atomic_buffer, num_buffers); 184 prog->data->NumAtomicBuffers = num_buffers; 185 186 unsigned buffer_idx = 0; 187 for (unsigned binding = 0; 188 binding < ctx->Const.MaxAtomicBufferBindings; 189 binding++) { 190 191 /* If the binding was not used, skip. 192 */ 193 if (abs[binding].size == 0) 194 continue; 195 196 struct active_atomic_buffer *ab = abs + binding; 197 struct gl_active_atomic_buffer *mab = 198 prog->data->AtomicBuffers + buffer_idx; 199 200 /* Assign buffer-specific fields. */ 201 mab->Binding = binding; 202 mab->MinimumSize = ab->size; 203 mab->Uniforms = rzalloc_array(prog->data->AtomicBuffers, GLuint, 204 ab->num_uniforms); 205 mab->NumUniforms = ab->num_uniforms; 206 207 /* Assign counter-specific fields. */ 208 for (unsigned j = 0; j < ab->num_uniforms; j++) { 209 nir_variable *var = ab->uniforms[j].var; 210 struct gl_uniform_storage *storage = 211 &prog->data->UniformStorage[ab->uniforms[j].loc]; 212 213 mab->Uniforms[j] = ab->uniforms[j].loc; 214 215 storage->atomic_buffer_index = buffer_idx; 216 storage->offset = var->data.offset; 217 if (glsl_type_is_array(var->type)) { 218 const struct glsl_type *without_array = 219 glsl_without_array(var->type); 220 storage->array_stride = glsl_atomic_size(without_array); 221 } else { 222 storage->array_stride = 0; 223 } 224 if (!glsl_type_is_matrix(var->type)) 225 storage->matrix_stride = 0; 226 } 227 228 /* Assign stage-specific fields. */ 229 for (unsigned stage = 0; stage < MESA_SHADER_STAGES; ++stage) { 230 if (ab->stage_counter_references[stage]) { 231 mab->StageReferences[stage] = GL_TRUE; 232 num_atomic_buffers[stage]++; 233 } else { 234 mab->StageReferences[stage] = GL_FALSE; 235 } 236 } 237 238 buffer_idx++; 239 } 240 241 /* Store a list pointers to atomic buffers per stage and store the index 242 * to the intra-stage buffer list in uniform storage. 243 */ 244 for (unsigned stage = 0; stage < MESA_SHADER_STAGES; ++stage) { 245 if (prog->_LinkedShaders[stage] == NULL || 246 num_atomic_buffers[stage] <= 0) 247 continue; 248 249 struct gl_program *gl_prog = prog->_LinkedShaders[stage]->Program; 250 gl_prog->info.num_abos = num_atomic_buffers[stage]; 251 gl_prog->sh.AtomicBuffers = 252 rzalloc_array(gl_prog, 253 struct gl_active_atomic_buffer *, 254 num_atomic_buffers[stage]); 255 256 gl_prog->nir->info.num_abos = num_atomic_buffers[stage]; 257 258 unsigned intra_stage_idx = 0; 259 for (unsigned i = 0; i < num_buffers; i++) { 260 struct gl_active_atomic_buffer *atomic_buffer = 261 &prog->data->AtomicBuffers[i]; 262 if (!atomic_buffer->StageReferences[stage]) 263 continue; 264 265 gl_prog->sh.AtomicBuffers[intra_stage_idx] = atomic_buffer; 266 267 for (unsigned u = 0; u < atomic_buffer->NumUniforms; u++) { 268 GLuint uniform_loc = atomic_buffer->Uniforms[u]; 269 struct gl_opaque_uniform_index *opaque = 270 prog->data->UniformStorage[uniform_loc].opaque + stage; 271 opaque->index = intra_stage_idx; 272 opaque->active = true; 273 } 274 275 intra_stage_idx++; 276 } 277 } 278 279 assert(buffer_idx == num_buffers); 280 281 ralloc_free(abs); 282} 283