~mmach/netext73/mesa-haswell

« back to all changes in this revision

Viewing changes to src/imagination/rogue/rogue_build_data.c

  • Committer: mmach
  • Date: 2022-09-22 19:56:13 UTC
  • Revision ID: netbit73@gmail.com-20220922195613-wtik9mmy20tmor0i
2022-09-22 21:17:09

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright © 2022 Imagination Technologies Ltd.
3
 
 *
4
 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
5
 
 * of this software and associated documentation files (the "Software"), to deal
6
 
 * in the Software without restriction, including without limitation the rights
7
 
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
 
 * copies of the Software, and to permit persons to whom the Software is
9
 
 * 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 THE
18
 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
 
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
 
 * SOFTWARE.
22
 
 */
23
 
 
24
 
#include <assert.h>
25
 
#include <stdbool.h>
26
 
#include <stddef.h>
27
 
#include <stdint.h>
28
 
#include <stdlib.h>
29
 
 
30
 
#include "compiler/shader_enums.h"
31
 
#include "nir/nir.h"
32
 
#include "rogue_build_data.h"
33
 
#include "rogue_nir_helpers.h"
34
 
#include "rogue_operand.h"
35
 
#include "util/macros.h"
36
 
 
37
 
#define __pvr_address_type uint64_t
38
 
#define __pvr_get_address(pvr_dev_addr) (pvr_dev_addr)
39
 
 
40
 
#include "csbgen/rogue_pds.h"
41
 
 
42
 
#undef __pvr_get_address
43
 
#undef __pvr_address_type
44
 
 
45
 
/**
46
 
 * \brief Allocates the coefficient registers that will contain the iterator
47
 
 * data for the fragment shader input varyings.
48
 
 *
49
 
 * \param[in] args The iterator argument data.
50
 
 * \return The total number of coefficient registers required by the iterators.
51
 
 */
52
 
static size_t alloc_iterator_regs(struct rogue_iterator_args *args)
53
 
{
54
 
   size_t coeffs = 0;
55
 
 
56
 
   for (size_t u = 0; u < args->num_fpu_iterators; ++u) {
57
 
      /* Ensure there aren't any gaps. */
58
 
      assert(args->base[u] == ~0);
59
 
 
60
 
      args->base[u] = coeffs;
61
 
      coeffs += ROGUE_COEFF_ALIGN * args->components[u];
62
 
   }
63
 
 
64
 
   return coeffs;
65
 
}
66
 
 
67
 
/**
68
 
 * \brief Reserves an iterator for a fragment shader input varying,
69
 
 * and calculates its setup data.
70
 
 *
71
 
 * \param[in] args The iterator argument data.
72
 
 * \param[in] i The iterator index.
73
 
 * \param[in] type The interpolation type of the varying.
74
 
 * \param[in] f16 Whether the data type is F16 or F32.
75
 
 * \param[in] components The number of components in the varying.
76
 
 */
77
 
static void reserve_iterator(struct rogue_iterator_args *args,
78
 
                             size_t i,
79
 
                             enum glsl_interp_mode type,
80
 
                             bool f16,
81
 
                             size_t components)
82
 
{
83
 
   struct ROGUE_PDSINST_DOUT_FIELDS_DOUTI_SRC data = { 0 };
84
 
 
85
 
   assert(components >= 1 && components <= 4);
86
 
 
87
 
   /* The first iterator (W) *must* be INTERP_MODE_NOPERSPECTIVE. */
88
 
   assert(i > 0 || type == INTERP_MODE_NOPERSPECTIVE);
89
 
   assert(i < ARRAY_SIZE(args->fpu_iterators));
90
 
 
91
 
   switch (type) {
92
 
   /* Default interpolation is smooth. */
93
 
   case INTERP_MODE_NONE:
94
 
      data.shademodel = ROGUE_PDSINST_DOUTI_SHADEMODEL_GOURUAD;
95
 
      data.perspective = true;
96
 
      break;
97
 
 
98
 
   case INTERP_MODE_NOPERSPECTIVE:
99
 
      data.shademodel = ROGUE_PDSINST_DOUTI_SHADEMODEL_GOURUAD;
100
 
      data.perspective = false;
101
 
      break;
102
 
 
103
 
   default:
104
 
      unreachable("Unimplemented interpolation type.");
105
 
   }
106
 
 
107
 
   /* Number of components in this varying
108
 
    * (corresponds to ROGUE_PDSINST_DOUTI_SIZE_1..4D).
109
 
    */
110
 
   data.size = (components - 1);
111
 
 
112
 
   /* TODO: Investigate F16 support. */
113
 
   assert(!f16);
114
 
   data.f16 = f16;
115
 
 
116
 
   /* Offsets within the vertex. */
117
 
   data.f32_offset = 2 * i;
118
 
   data.f16_offset = data.f32_offset;
119
 
 
120
 
   ROGUE_PDSINST_DOUT_FIELDS_DOUTI_SRC_pack(&args->fpu_iterators[i], &data);
121
 
   args->destination[i] = i;
122
 
   args->base[i] = ~0;
123
 
   args->components[i] = components;
124
 
   ++args->num_fpu_iterators;
125
 
}
126
 
 
127
 
/**
128
 
 * \brief Collects the fragment shader I/O data to feed-back to the driver.
129
 
 *
130
 
 * \sa #collect_io_data()
131
 
 *
132
 
 * \param[in] common_data Common build data.
133
 
 * \param[in] fs_data Fragment-specific build data.
134
 
 * \param[in] nir NIR fragment shader.
135
 
 * \return true if successful, otherwise false.
136
 
 */
137
 
static bool collect_io_data_fs(struct rogue_common_build_data *common_data,
138
 
                               struct rogue_fs_build_data *fs_data,
139
 
                               nir_shader *nir)
140
 
{
141
 
   size_t num_inputs = nir_count_variables_with_modes(nir, nir_var_shader_in);
142
 
   assert(num_inputs < (ARRAY_SIZE(fs_data->iterator_args.fpu_iterators) - 1));
143
 
 
144
 
   /* Process inputs (if present). */
145
 
   if (num_inputs) {
146
 
      /* If the fragment shader has inputs, the first iterator
147
 
       * must be used for the W component.
148
 
       */
149
 
      reserve_iterator(&fs_data->iterator_args,
150
 
                       0,
151
 
                       INTERP_MODE_NOPERSPECTIVE,
152
 
                       false,
153
 
                       1);
154
 
 
155
 
      nir_foreach_shader_in_variable (var, nir) {
156
 
         size_t i = (var->data.location - VARYING_SLOT_VAR0) + 1;
157
 
         size_t components = glsl_get_components(var->type);
158
 
         enum glsl_interp_mode interp = var->data.interpolation;
159
 
         bool f16 = glsl_type_is_16bit(var->type);
160
 
 
161
 
         /* Check that arguments are either F16 or F32. */
162
 
         assert(glsl_get_base_type(var->type) == GLSL_TYPE_FLOAT);
163
 
         assert(f16 || glsl_type_is_32bit(var->type));
164
 
 
165
 
         /* Check input location. */
166
 
         assert(var->data.location >= VARYING_SLOT_VAR0 &&
167
 
                var->data.location <= VARYING_SLOT_VAR31);
168
 
 
169
 
         reserve_iterator(&fs_data->iterator_args, i, interp, f16, components);
170
 
      }
171
 
 
172
 
      common_data->coeffs = alloc_iterator_regs(&fs_data->iterator_args);
173
 
      assert(common_data->coeffs);
174
 
      assert(common_data->coeffs < ROGUE_MAX_REG_COEFF);
175
 
   }
176
 
 
177
 
   /* TODO: Process outputs. */
178
 
 
179
 
   return true;
180
 
}
181
 
 
182
 
/**
183
 
 * \brief Allocates the vertex shader input registers.
184
 
 *
185
 
 * \param[in] inputs The vertex shader input data.
186
 
 * \return The total number of vertex input registers required.
187
 
 */
188
 
static size_t alloc_vs_inputs(struct rogue_vertex_inputs *inputs)
189
 
{
190
 
   size_t vs_inputs = 0;
191
 
 
192
 
   for (size_t u = 0; u < inputs->num_input_vars; ++u) {
193
 
      /* Ensure there aren't any gaps. */
194
 
      assert(inputs->base[u] == ~0);
195
 
 
196
 
      inputs->base[u] = vs_inputs;
197
 
      vs_inputs += inputs->components[u];
198
 
   }
199
 
 
200
 
   return vs_inputs;
201
 
}
202
 
 
203
 
/**
204
 
 * \brief Allocates the vertex shader outputs.
205
 
 *
206
 
 * \param[in] outputs The vertex shader output data.
207
 
 * \return The total number of vertex outputs required.
208
 
 */
209
 
static size_t alloc_vs_outputs(struct rogue_vertex_outputs *outputs)
210
 
{
211
 
   size_t vs_outputs = 0;
212
 
 
213
 
   for (size_t u = 0; u < outputs->num_output_vars; ++u) {
214
 
      /* Ensure there aren't any gaps. */
215
 
      assert(outputs->base[u] == ~0);
216
 
 
217
 
      outputs->base[u] = vs_outputs;
218
 
      vs_outputs += outputs->components[u];
219
 
   }
220
 
 
221
 
   return vs_outputs;
222
 
}
223
 
 
224
 
/**
225
 
 * \brief Counts the varyings used by the vertex shader.
226
 
 *
227
 
 * \param[in] outputs The vertex shader output data.
228
 
 * \return The number of varyings used.
229
 
 */
230
 
static size_t count_vs_varyings(struct rogue_vertex_outputs *outputs)
231
 
{
232
 
   size_t varyings = 0;
233
 
 
234
 
   /* Skip the position. */
235
 
   for (size_t u = 1; u < outputs->num_output_vars; ++u)
236
 
      varyings += outputs->components[u];
237
 
 
238
 
   return varyings;
239
 
}
240
 
 
241
 
/**
242
 
 * \brief Reserves space for a vertex shader input.
243
 
 *
244
 
 * \param[in] inputs The vertex input data.
245
 
 * \param[in] i The vertex input index.
246
 
 * \param[in] components The number of components in the input.
247
 
 */
248
 
static void reserve_vs_input(struct rogue_vertex_inputs *inputs,
249
 
                             size_t i,
250
 
                             size_t components)
251
 
{
252
 
   assert(components >= 1 && components <= 4);
253
 
 
254
 
   assert(i < ARRAY_SIZE(inputs->base));
255
 
 
256
 
   inputs->base[i] = ~0;
257
 
   inputs->components[i] = components;
258
 
   ++inputs->num_input_vars;
259
 
}
260
 
 
261
 
/**
262
 
 * \brief Reserves space for a vertex shader output.
263
 
 *
264
 
 * \param[in] outputs The vertex output data.
265
 
 * \param[in] i The vertex output index.
266
 
 * \param[in] components The number of components in the output.
267
 
 */
268
 
static void reserve_vs_output(struct rogue_vertex_outputs *outputs,
269
 
                              size_t i,
270
 
                              size_t components)
271
 
{
272
 
   assert(components >= 1 && components <= 4);
273
 
 
274
 
   assert(i < ARRAY_SIZE(outputs->base));
275
 
 
276
 
   outputs->base[i] = ~0;
277
 
   outputs->components[i] = components;
278
 
   ++outputs->num_output_vars;
279
 
}
280
 
 
281
 
/**
282
 
 * \brief Collects the vertex shader I/O data to feed-back to the driver.
283
 
 *
284
 
 * \sa #collect_io_data()
285
 
 *
286
 
 * \param[in] common_data Common build data.
287
 
 * \param[in] vs_data Vertex-specific build data.
288
 
 * \param[in] nir NIR vertex shader.
289
 
 * \return true if successful, otherwise false.
290
 
 */
291
 
static bool collect_io_data_vs(struct rogue_common_build_data *common_data,
292
 
                               struct rogue_vs_build_data *vs_data,
293
 
                               nir_shader *nir)
294
 
{
295
 
   ASSERTED bool out_pos_present = false;
296
 
   ASSERTED size_t num_outputs =
297
 
      nir_count_variables_with_modes(nir, nir_var_shader_out);
298
 
 
299
 
   /* Process inputs. */
300
 
   nir_foreach_shader_in_variable (var, nir) {
301
 
      size_t components = glsl_get_components(var->type);
302
 
      size_t i = var->data.location - VERT_ATTRIB_GENERIC0;
303
 
 
304
 
      /* Check that inputs are F32. */
305
 
      /* TODO: Support other types. */
306
 
      assert(glsl_get_base_type(var->type) == GLSL_TYPE_FLOAT);
307
 
      assert(glsl_type_is_32bit(var->type));
308
 
 
309
 
      /* Check input location. */
310
 
      assert(var->data.location >= VERT_ATTRIB_GENERIC0 &&
311
 
             var->data.location <= VERT_ATTRIB_GENERIC15);
312
 
 
313
 
      reserve_vs_input(&vs_data->inputs, i, components);
314
 
   }
315
 
 
316
 
   vs_data->num_vertex_input_regs = alloc_vs_inputs(&vs_data->inputs);
317
 
   assert(vs_data->num_vertex_input_regs);
318
 
   assert(vs_data->num_vertex_input_regs < ROGUE_MAX_REG_VERTEX_IN);
319
 
 
320
 
   /* Process outputs. */
321
 
 
322
 
   /* We should always have at least a position variable. */
323
 
   assert(num_outputs > 0 && "Invalid number of vertex shader outputs.");
324
 
 
325
 
   nir_foreach_shader_out_variable (var, nir) {
326
 
      size_t components = glsl_get_components(var->type);
327
 
 
328
 
      /* Check that outputs are F32. */
329
 
      /* TODO: Support other types. */
330
 
      assert(glsl_get_base_type(var->type) == GLSL_TYPE_FLOAT);
331
 
      assert(glsl_type_is_32bit(var->type));
332
 
 
333
 
      if (var->data.location == VARYING_SLOT_POS) {
334
 
         assert(components == 4);
335
 
         out_pos_present = true;
336
 
 
337
 
         reserve_vs_output(&vs_data->outputs, 0, components);
338
 
      } else if ((var->data.location >= VARYING_SLOT_VAR0) &&
339
 
                 (var->data.location <= VARYING_SLOT_VAR31)) {
340
 
         size_t i = (var->data.location - VARYING_SLOT_VAR0) + 1;
341
 
         reserve_vs_output(&vs_data->outputs, i, components);
342
 
      } else {
343
 
         unreachable("Unsupported vertex output type.");
344
 
      }
345
 
   }
346
 
 
347
 
   /* Always need the output position to be present. */
348
 
   assert(out_pos_present);
349
 
 
350
 
   vs_data->num_vertex_outputs = alloc_vs_outputs(&vs_data->outputs);
351
 
   assert(vs_data->num_vertex_outputs);
352
 
   assert(vs_data->num_vertex_outputs < ROGUE_MAX_VERTEX_OUTPUTS);
353
 
 
354
 
   vs_data->num_varyings = count_vs_varyings(&vs_data->outputs);
355
 
 
356
 
   return true;
357
 
}
358
 
 
359
 
/**
360
 
 * \brief Allocates the shared registers that will contain the UBOs.
361
 
 *
362
 
 * \param[in] ubo_data The UBO data.
363
 
 * \return The total number of coefficient registers required by the iterators.
364
 
 */
365
 
static size_t alloc_ubos(struct rogue_ubo_data *ubo_data)
366
 
{
367
 
   size_t shareds = 0;
368
 
 
369
 
   for (size_t u = 0; u < ubo_data->num_ubo_entries; ++u) {
370
 
      /* Ensure there aren't any gaps. */
371
 
      assert(ubo_data->dest[u] == ~0);
372
 
 
373
 
      ubo_data->dest[u] = shareds;
374
 
      shareds += ubo_data->size[u];
375
 
   }
376
 
 
377
 
   return shareds;
378
 
}
379
 
 
380
 
/**
381
 
 * \brief Reserves a UBO and calculates its data.
382
 
 *
383
 
 * \param[in] ubo_data The UBO data.
384
 
 * \param[in] desc_set The UBO descriptor set.
385
 
 * \param[in] binding The UBO binding.
386
 
 * \param[in] size The size required by the UBO (in dwords).
387
 
 */
388
 
static void reserve_ubo(struct rogue_ubo_data *ubo_data,
389
 
                        size_t desc_set,
390
 
                        size_t binding,
391
 
                        size_t size)
392
 
{
393
 
   size_t i = ubo_data->num_ubo_entries;
394
 
   assert(i < ARRAY_SIZE(ubo_data->desc_set));
395
 
 
396
 
   ubo_data->desc_set[i] = desc_set;
397
 
   ubo_data->binding[i] = binding;
398
 
   ubo_data->dest[i] = ~0;
399
 
   ubo_data->size[i] = size;
400
 
   ++ubo_data->num_ubo_entries;
401
 
}
402
 
 
403
 
/**
404
 
 * \brief Collects UBO data to feed-back to the driver.
405
 
 *
406
 
 * \param[in] common_data Common build data.
407
 
 * \param[in] nir NIR shader.
408
 
 * \return true if successful, otherwise false.
409
 
 */
410
 
static bool collect_ubo_data(struct rogue_common_build_data *common_data,
411
 
                             nir_shader *nir)
412
 
{
413
 
   /* Iterate over each UBO. */
414
 
   nir_foreach_variable_with_modes (var, nir, nir_var_mem_ubo) {
415
 
      size_t desc_set = var->data.driver_location;
416
 
      size_t binding = var->data.binding;
417
 
      size_t ubo_size_regs = 0;
418
 
 
419
 
      nir_function_impl *entry = nir_shader_get_entrypoint(nir);
420
 
      /* Iterate over each load_ubo that uses this UBO. */
421
 
      nir_foreach_block (block, entry) {
422
 
         nir_foreach_instr (instr, block) {
423
 
            if (instr->type != nir_instr_type_intrinsic)
424
 
               continue;
425
 
 
426
 
            nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
427
 
            if (intr->intrinsic != nir_intrinsic_load_ubo)
428
 
               continue;
429
 
 
430
 
            assert(nir_src_num_components(intr->src[0]) == 2);
431
 
            assert(nir_intr_src_is_const(intr, 0));
432
 
 
433
 
            size_t load_desc_set = nir_intr_src_comp_const(intr, 0, 0);
434
 
            size_t load_binding = nir_intr_src_comp_const(intr, 0, 1);
435
 
 
436
 
            if (load_desc_set != desc_set || load_binding != binding)
437
 
               continue;
438
 
 
439
 
            ASSERTED size_t size_bytes = nir_intrinsic_range(intr);
440
 
            assert(size_bytes == ROGUE_REG_SIZE_BYTES);
441
 
 
442
 
            size_t offset_bytes = nir_intrinsic_range_base(intr);
443
 
            assert(!(offset_bytes % ROGUE_REG_SIZE_BYTES));
444
 
 
445
 
            size_t offset_regs = offset_bytes / ROGUE_REG_SIZE_BYTES;
446
 
 
447
 
            /* TODO: Put offsets in a BITSET_DECLARE and check for gaps. */
448
 
 
449
 
            /* Find the largest load offset. */
450
 
            ubo_size_regs = MAX2(ubo_size_regs, offset_regs);
451
 
         }
452
 
      }
453
 
 
454
 
      /* UBO size = largest offset + 1. */
455
 
      ++ubo_size_regs;
456
 
 
457
 
      reserve_ubo(&common_data->ubo_data, desc_set, binding, ubo_size_regs);
458
 
   }
459
 
 
460
 
   common_data->shareds = alloc_ubos(&common_data->ubo_data);
461
 
   assert(common_data->shareds < ROGUE_MAX_REG_SHARED);
462
 
 
463
 
   return true;
464
 
}
465
 
 
466
 
/**
467
 
 * \brief Collects I/O data to feed-back to the driver.
468
 
 *
469
 
 * Collects the inputs/outputs/memory required, and feeds that back to the
470
 
 * driver. Done at this stage rather than at the start of rogue_to_binary, so
471
 
 * that all the I/O of all the shader stages is known before backend
472
 
 * compilation, which would let us do things like cull unused inputs.
473
 
 *
474
 
 * \param[in] ctx Shared multi-stage build context.
475
 
 * \param[in] nir NIR shader.
476
 
 * \return true if successful, otherwise false.
477
 
 */
478
 
bool rogue_collect_io_data(struct rogue_build_ctx *ctx, nir_shader *nir)
479
 
{
480
 
   gl_shader_stage stage = nir->info.stage;
481
 
   struct rogue_common_build_data *common_data = &ctx->common_data[stage];
482
 
 
483
 
   /* Collect stage-agnostic data. */
484
 
   if (!collect_ubo_data(common_data, nir))
485
 
      return false;
486
 
 
487
 
   /* Collect stage-specific data. */
488
 
   switch (stage) {
489
 
   case MESA_SHADER_FRAGMENT:
490
 
      return collect_io_data_fs(common_data, &ctx->stage_data.fs, nir);
491
 
 
492
 
   case MESA_SHADER_VERTEX:
493
 
      return collect_io_data_vs(common_data, &ctx->stage_data.vs, nir);
494
 
 
495
 
   default:
496
 
      break;
497
 
   }
498
 
 
499
 
   return false;
500
 
}
501
 
 
502
 
/**
503
 
 * \brief Returns the allocated coefficient register index for a component of an
504
 
 * input varying location.
505
 
 *
506
 
 * \param[in] args The allocated iterator argument data.
507
 
 * \param[in] location The input varying location, or ~0 for the W coefficient.
508
 
 * \param[in] component The requested component.
509
 
 * \return The coefficient register index.
510
 
 */
511
 
size_t rogue_coeff_index_fs(struct rogue_iterator_args *args,
512
 
                            gl_varying_slot location,
513
 
                            size_t component)
514
 
{
515
 
   size_t i;
516
 
 
517
 
   /* Special case: W coefficient. */
518
 
   if (location == ~0) {
519
 
      /* The W component shouldn't be the only one. */
520
 
      assert(args->num_fpu_iterators > 1);
521
 
      assert(args->destination[0] == 0);
522
 
      return 0;
523
 
   }
524
 
 
525
 
   i = (location - VARYING_SLOT_VAR0) + 1;
526
 
   assert(location >= VARYING_SLOT_VAR0 && location <= VARYING_SLOT_VAR31);
527
 
   assert(i < args->num_fpu_iterators);
528
 
   assert(component < args->components[i]);
529
 
   assert(args->base[i] != ~0);
530
 
 
531
 
   return args->base[i] + (ROGUE_COEFF_ALIGN * component);
532
 
}
533
 
 
534
 
/**
535
 
 * \brief Returns the allocated vertex output index for a component of an input
536
 
 * varying location.
537
 
 *
538
 
 * \param[in] outputs The vertex output data.
539
 
 * \param[in] location The output varying location.
540
 
 * \param[in] component The requested component.
541
 
 * \return The vertex output index.
542
 
 */
543
 
size_t rogue_output_index_vs(struct rogue_vertex_outputs *outputs,
544
 
                             gl_varying_slot location,
545
 
                             size_t component)
546
 
{
547
 
   size_t i;
548
 
 
549
 
   if (location == VARYING_SLOT_POS) {
550
 
      /* Always at location 0. */
551
 
      assert(outputs->base[0] == 0);
552
 
      i = 0;
553
 
   } else if ((location >= VARYING_SLOT_VAR0) &&
554
 
              (location <= VARYING_SLOT_VAR31)) {
555
 
      i = (location - VARYING_SLOT_VAR0) + 1;
556
 
   } else {
557
 
      unreachable("Unsupported vertex output type.");
558
 
   }
559
 
 
560
 
   assert(i < outputs->num_output_vars);
561
 
   assert(component < outputs->components[i]);
562
 
   assert(outputs->base[i] != ~0);
563
 
 
564
 
   return outputs->base[i] + component;
565
 
}
566
 
 
567
 
/**
568
 
 * \brief Returns the allocated shared register index for a given UBO offset.
569
 
 *
570
 
 * \param[in] ubo_data The UBO data.
571
 
 * \param[in] desc_set The UBO descriptor set.
572
 
 * \param[in] binding The UBO binding.
573
 
 * \param[in] offset_bytes The UBO offset in bytes.
574
 
 * \return The UBO offset shared register index.
575
 
 */
576
 
size_t rogue_ubo_reg(struct rogue_ubo_data *ubo_data,
577
 
                     size_t desc_set,
578
 
                     size_t binding,
579
 
                     size_t offset_bytes)
580
 
{
581
 
   size_t ubo_index = ~0;
582
 
   size_t offset_regs;
583
 
 
584
 
   /* Find UBO located at (desc_set, binding). */
585
 
   for (size_t u = 0; u < ubo_data->num_ubo_entries; ++u) {
586
 
      if (ubo_data->dest[u] == ~0)
587
 
         continue;
588
 
 
589
 
      if (ubo_data->desc_set[u] != desc_set || ubo_data->binding[u] != binding)
590
 
         continue;
591
 
 
592
 
      ubo_index = u;
593
 
      break;
594
 
   }
595
 
 
596
 
   assert(ubo_index != ~0);
597
 
 
598
 
   assert(!(offset_bytes % ROGUE_REG_SIZE_BYTES));
599
 
   offset_regs = offset_bytes / ROGUE_REG_SIZE_BYTES;
600
 
 
601
 
   return ubo_data->dest[ubo_index] + offset_regs;
602
 
}