Blender  V3.3
gl_shader_interface.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2016 by Mike Erwin. All rights reserved. */
3 
10 #include "BLI_bitmap.h"
11 
12 #include "gl_batch.hh"
13 #include "gl_context.hh"
14 
15 #include "gl_shader_interface.hh"
16 
17 #include "GPU_capabilities.h"
18 
19 namespace blender::gpu {
20 
21 /* -------------------------------------------------------------------- */
28 static inline int block_binding(int32_t program, uint32_t block_index)
29 {
30  /* For now just assign a consecutive index. In the future, we should set it in
31  * the shader using layout(binding = i) and query its value. */
32  glUniformBlockBinding(program, block_index, block_index);
33  return block_index;
34 }
35 
36 static inline int sampler_binding(int32_t program,
37  uint32_t uniform_index,
38  int32_t uniform_location,
39  int *sampler_len)
40 {
41  /* Identify sampler uniforms and assign sampler units to them. */
42  GLint type;
43  glGetActiveUniformsiv(program, 1, &uniform_index, GL_UNIFORM_TYPE, &type);
44 
45  switch (type) {
46  case GL_SAMPLER_1D:
47  case GL_SAMPLER_2D:
48  case GL_SAMPLER_3D:
49  case GL_SAMPLER_CUBE:
50  case GL_SAMPLER_CUBE_MAP_ARRAY_ARB: /* OpenGL 4.0 */
51  case GL_SAMPLER_1D_SHADOW:
52  case GL_SAMPLER_2D_SHADOW:
53  case GL_SAMPLER_1D_ARRAY:
54  case GL_SAMPLER_2D_ARRAY:
55  case GL_SAMPLER_1D_ARRAY_SHADOW:
56  case GL_SAMPLER_2D_ARRAY_SHADOW:
57  case GL_SAMPLER_2D_MULTISAMPLE:
58  case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
59  case GL_SAMPLER_CUBE_SHADOW:
60  case GL_SAMPLER_BUFFER:
61  case GL_INT_SAMPLER_1D:
62  case GL_INT_SAMPLER_2D:
63  case GL_INT_SAMPLER_3D:
64  case GL_INT_SAMPLER_CUBE:
65  case GL_INT_SAMPLER_1D_ARRAY:
66  case GL_INT_SAMPLER_2D_ARRAY:
67  case GL_INT_SAMPLER_2D_MULTISAMPLE:
68  case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
69  case GL_INT_SAMPLER_BUFFER:
70  case GL_UNSIGNED_INT_SAMPLER_1D:
71  case GL_UNSIGNED_INT_SAMPLER_2D:
72  case GL_UNSIGNED_INT_SAMPLER_3D:
73  case GL_UNSIGNED_INT_SAMPLER_CUBE:
74  case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
75  case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
76  case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
77  case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
78  case GL_UNSIGNED_INT_SAMPLER_BUFFER: {
79  /* For now just assign a consecutive index. In the future, we should set it in
80  * the shader using layout(binding = i) and query its value. */
81  int binding = *sampler_len;
82  glUniform1i(uniform_location, binding);
83  (*sampler_len)++;
84  return binding;
85  }
86  default:
87  return -1;
88  }
89 }
90 
91 static inline int image_binding(int32_t program,
92  uint32_t uniform_index,
93  int32_t uniform_location,
94  int *image_len)
95 {
96  /* Identify image uniforms and assign image units to them. */
97  GLint type;
98  glGetActiveUniformsiv(program, 1, &uniform_index, GL_UNIFORM_TYPE, &type);
99 
100  switch (type) {
101  case GL_IMAGE_1D:
102  case GL_IMAGE_2D:
103  case GL_IMAGE_3D:
104  case GL_IMAGE_CUBE:
105  case GL_IMAGE_BUFFER:
106  case GL_IMAGE_1D_ARRAY:
107  case GL_IMAGE_2D_ARRAY:
108  case GL_IMAGE_CUBE_MAP_ARRAY:
109  case GL_INT_IMAGE_1D:
110  case GL_INT_IMAGE_2D:
111  case GL_INT_IMAGE_3D:
112  case GL_INT_IMAGE_CUBE:
113  case GL_INT_IMAGE_BUFFER:
114  case GL_INT_IMAGE_1D_ARRAY:
115  case GL_INT_IMAGE_2D_ARRAY:
116  case GL_INT_IMAGE_CUBE_MAP_ARRAY:
117  case GL_UNSIGNED_INT_IMAGE_1D:
118  case GL_UNSIGNED_INT_IMAGE_2D:
119  case GL_UNSIGNED_INT_IMAGE_3D:
120  case GL_UNSIGNED_INT_IMAGE_CUBE:
121  case GL_UNSIGNED_INT_IMAGE_BUFFER:
122  case GL_UNSIGNED_INT_IMAGE_1D_ARRAY:
123  case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
124  case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY: {
125  /* For now just assign a consecutive index. In the future, we should set it in
126  * the shader using layout(binding = i) and query its value. */
127  int binding = *image_len;
128  glUniform1i(uniform_location, binding);
129  (*image_len)++;
130  return binding;
131  }
132  default:
133  return -1;
134  }
135 }
136 
137 static inline int ssbo_binding(int32_t program, uint32_t ssbo_index)
138 {
139  GLint binding = -1;
140  GLenum property = GL_BUFFER_BINDING;
141  GLint values_written = 0;
142  glGetProgramResourceiv(
143  program, GL_SHADER_STORAGE_BLOCK, ssbo_index, 1, &property, 1, &values_written, &binding);
144 
145  return binding;
146 }
147 
150 /* -------------------------------------------------------------------- */
155 {
156  /* Necessary to make #glUniform works. */
157  glUseProgram(program);
158 
159  GLint max_attr_name_len = 0, attr_len = 0;
160  glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_attr_name_len);
161  glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &attr_len);
162 
163  GLint max_ubo_name_len = 0, ubo_len = 0;
164  glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &max_ubo_name_len);
165  glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &ubo_len);
166 
167  GLint max_uniform_name_len = 0, active_uniform_len = 0, uniform_len = 0;
168  glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_uniform_name_len);
169  glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &active_uniform_len);
170  uniform_len = active_uniform_len;
171 
172  GLint max_ssbo_name_len = 0, ssbo_len = 0;
174  glGetProgramInterfaceiv(program, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &ssbo_len);
175  glGetProgramInterfaceiv(
176  program, GL_SHADER_STORAGE_BLOCK, GL_MAX_NAME_LENGTH, &max_ssbo_name_len);
177  }
178 
179  BLI_assert_msg(ubo_len <= 16, "enabled_ubo_mask_ is uint16_t");
180 
181  /* Work around driver bug with Intel HD 4600 on Windows 7/8, where
182  * GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH does not work. */
183  if (attr_len > 0 && max_attr_name_len == 0) {
184  max_attr_name_len = 256;
185  }
186  if (ubo_len > 0 && max_ubo_name_len == 0) {
187  max_ubo_name_len = 256;
188  }
189  if (uniform_len > 0 && max_uniform_name_len == 0) {
190  max_uniform_name_len = 256;
191  }
192  if (ssbo_len > 0 && max_ssbo_name_len == 0) {
193  max_ssbo_name_len = 256;
194  }
195 
196  /* GL_ACTIVE_UNIFORMS lied to us! Remove the UBO uniforms from the total before
197  * allocating the uniform array. */
198  GLint max_ubo_uni_len = 0;
199  for (int i = 0; i < ubo_len; i++) {
200  GLint ubo_uni_len;
201  glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &ubo_uni_len);
202  max_ubo_uni_len = max_ii(max_ubo_uni_len, ubo_uni_len);
203  uniform_len -= ubo_uni_len;
204  }
205  /* Bit set to true if uniform comes from a uniform block. */
206  BLI_bitmap *uniforms_from_blocks = BLI_BITMAP_NEW(active_uniform_len, __func__);
207  /* Set uniforms from block for exclusion. */
208  GLint *ubo_uni_ids = (GLint *)MEM_mallocN(sizeof(GLint) * max_ubo_uni_len, __func__);
209  for (int i = 0; i < ubo_len; i++) {
210  GLint ubo_uni_len;
211  glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &ubo_uni_len);
212  glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, ubo_uni_ids);
213  for (int u = 0; u < ubo_uni_len; u++) {
214  BLI_BITMAP_ENABLE(uniforms_from_blocks, ubo_uni_ids[u]);
215  }
216  }
217  MEM_freeN(ubo_uni_ids);
218 
219  int input_tot_len = attr_len + ubo_len + uniform_len + ssbo_len;
220  inputs_ = (ShaderInput *)MEM_callocN(sizeof(ShaderInput) * input_tot_len, __func__);
221 
222  const uint32_t name_buffer_len = attr_len * max_attr_name_len + ubo_len * max_ubo_name_len +
223  uniform_len * max_uniform_name_len +
224  ssbo_len * max_ssbo_name_len;
225  name_buffer_ = (char *)MEM_mallocN(name_buffer_len, "name_buffer");
226  uint32_t name_buffer_offset = 0;
227 
228  /* Attributes */
229  enabled_attr_mask_ = 0;
230  for (int i = 0; i < attr_len; i++) {
231  char *name = name_buffer_ + name_buffer_offset;
232  GLsizei remaining_buffer = name_buffer_len - name_buffer_offset;
233  GLsizei name_len = 0;
234  GLenum type;
235  GLint size;
236 
237  glGetActiveAttrib(program, i, remaining_buffer, &name_len, &size, &type, name);
238  GLint location = glGetAttribLocation(program, name);
239  /* Ignore OpenGL names like `gl_BaseInstanceARB`, `gl_InstanceID` and `gl_VertexID`. */
240  if (location == -1) {
241  continue;
242  }
243 
245  input->location = input->binding = location;
246 
247  name_buffer_offset += set_input_name(input, name, name_len);
248  enabled_attr_mask_ |= (1 << input->location);
249  }
250 
251  /* Uniform Blocks */
252  for (int i = 0; i < ubo_len; i++) {
253  char *name = name_buffer_ + name_buffer_offset;
254  GLsizei remaining_buffer = name_buffer_len - name_buffer_offset;
255  GLsizei name_len = 0;
256 
257  glGetActiveUniformBlockName(program, i, remaining_buffer, &name_len, name);
258 
260  input->binding = input->location = block_binding(program, i);
261 
262  name_buffer_offset += this->set_input_name(input, name, name_len);
263  enabled_ubo_mask_ |= (1 << input->binding);
264  }
265 
266  /* Uniforms & samplers & images */
267  for (int i = 0, sampler = 0, image = 0; i < active_uniform_len; i++) {
268  if (BLI_BITMAP_TEST(uniforms_from_blocks, i)) {
269  continue;
270  }
271  char *name = name_buffer_ + name_buffer_offset;
272  GLsizei remaining_buffer = name_buffer_len - name_buffer_offset;
273  GLsizei name_len = 0;
274 
275  glGetActiveUniformName(program, i, remaining_buffer, &name_len, name);
276 
278  input->location = glGetUniformLocation(program, name);
279  input->binding = sampler_binding(program, i, input->location, &sampler);
280 
281  name_buffer_offset += this->set_input_name(input, name, name_len);
282  enabled_tex_mask_ |= (input->binding != -1) ? (1lu << input->binding) : 0lu;
283 
284  if (input->binding == -1) {
285  input->binding = image_binding(program, i, input->location, &image);
286 
287  enabled_ima_mask_ |= (input->binding != -1) ? (1lu << input->binding) : 0lu;
288  }
289  }
290 
291  /* SSBOs */
292  for (int i = 0; i < ssbo_len; i++) {
293  char *name = name_buffer_ + name_buffer_offset;
294  GLsizei remaining_buffer = name_buffer_len - name_buffer_offset;
295  GLsizei name_len = 0;
296  glGetProgramResourceName(
297  program, GL_SHADER_STORAGE_BLOCK, i, remaining_buffer, &name_len, name);
298 
299  const GLint binding = ssbo_binding(program, i);
300 
302  input->binding = input->location = binding;
303 
304  name_buffer_offset += this->set_input_name(input, name, name_len);
305  enabled_ssbo_mask_ |= (input->binding != -1) ? (1lu << input->binding) : 0lu;
306  }
307 
308  /* Builtin Uniforms */
309  for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORMS; u_int++) {
310  GPUUniformBuiltin u = static_cast<GPUUniformBuiltin>(u_int);
311  builtins_[u] = glGetUniformLocation(program, builtin_uniform_name(u));
312  }
313 
314  /* Builtin Uniforms Blocks */
315  for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORM_BLOCKS; u_int++) {
316  GPUUniformBlockBuiltin u = static_cast<GPUUniformBlockBuiltin>(u_int);
317  const ShaderInput *block = this->ubo_get(builtin_uniform_block_name(u));
318  builtin_blocks_[u] = (block != nullptr) ? block->binding : -1;
319  }
320 
321  MEM_freeN(uniforms_from_blocks);
322 
323  /* Resize name buffer to save some memory. */
324  if (name_buffer_offset < name_buffer_len) {
325  name_buffer_ = (char *)MEM_reallocN(name_buffer_, name_buffer_offset);
326  }
327 
328  // this->debug_print();
329 
330  this->sort_inputs();
331 }
332 
334 {
335  using namespace blender::gpu::shader;
336 
337  attr_len_ = info.vertex_inputs_.size();
338  uniform_len_ = info.push_constants_.size();
339  ubo_len_ = 0;
340  ssbo_len_ = 0;
341 
343  all_resources.extend(info.pass_resources_);
344  all_resources.extend(info.batch_resources_);
345 
346  for (ShaderCreateInfo::Resource &res : all_resources) {
347  switch (res.bind_type) {
348  case ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER:
349  ubo_len_++;
350  break;
351  case ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER:
352  ssbo_len_++;
353  break;
354  case ShaderCreateInfo::Resource::BindType::SAMPLER:
355  uniform_len_++;
356  break;
357  case ShaderCreateInfo::Resource::BindType::IMAGE:
358  uniform_len_++;
359  break;
360  }
361  }
362 
363  size_t workaround_names_size = 0;
364  Vector<StringRefNull> workaround_uniform_names;
365  auto check_enabled_uniform = [&](const char *uniform_name) {
366  if (glGetUniformLocation(program, uniform_name) != -1) {
367  workaround_uniform_names.append(uniform_name);
368  workaround_names_size += StringRefNull(uniform_name).size() + 1;
369  uniform_len_++;
370  }
371  };
372 
374  check_enabled_uniform("gpu_BaseInstance");
375  }
376 
377  BLI_assert_msg(ubo_len_ <= 16, "enabled_ubo_mask_ is uint16_t");
378 
379  int input_tot_len = attr_len_ + ubo_len_ + uniform_len_ + ssbo_len_;
380  inputs_ = (ShaderInput *)MEM_callocN(sizeof(ShaderInput) * input_tot_len, __func__);
382 
383  name_buffer_ = (char *)MEM_mallocN(info.interface_names_size_ + workaround_names_size,
384  "name_buffer");
385  uint32_t name_buffer_offset = 0;
386 
387  /* Necessary to make #glUniform works. TODO(fclem) Remove. */
388  glUseProgram(program);
389 
390  /* Attributes */
391  for (const ShaderCreateInfo::VertIn &attr : info.vertex_inputs_) {
392  copy_input_name(input, attr.name, name_buffer_, name_buffer_offset);
394  input->location = input->binding = glGetAttribLocation(program, attr.name.c_str());
395  }
396  else {
397  input->location = input->binding = attr.index;
398  }
399  if (input->location != -1) {
400  enabled_attr_mask_ |= (1 << input->location);
401  }
402  input++;
403  }
404 
405  /* Uniform Blocks */
406  for (const ShaderCreateInfo::Resource &res : all_resources) {
407  if (res.bind_type == ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER) {
408  copy_input_name(input, res.uniformbuf.name, name_buffer_, name_buffer_offset);
410  input->location = glGetUniformBlockIndex(program, name_buffer_ + input->name_offset);
411  glUniformBlockBinding(program, input->location, res.slot);
412  }
413  input->binding = res.slot;
414  enabled_ubo_mask_ |= (1 << input->binding);
415  input++;
416  }
417  }
418 
419  /* Uniforms & samplers & images */
420  for (const ShaderCreateInfo::Resource &res : all_resources) {
421  if (res.bind_type == ShaderCreateInfo::Resource::BindType::SAMPLER) {
422  copy_input_name(input, res.sampler.name, name_buffer_, name_buffer_offset);
423  /* Until we make use of explicit uniform location or eliminate all
424  * sampler manually changing. */
426  input->location = glGetUniformLocation(program, res.sampler.name.c_str());
427  glUniform1i(input->location, res.slot);
428  }
429  input->binding = res.slot;
430  enabled_tex_mask_ |= (1ull << input->binding);
431  input++;
432  }
433  else if (res.bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) {
434  copy_input_name(input, res.image.name, name_buffer_, name_buffer_offset);
435  /* Until we make use of explicit uniform location. */
437  input->location = glGetUniformLocation(program, res.image.name.c_str());
438  glUniform1i(input->location, res.slot);
439  }
440  input->binding = res.slot;
441  enabled_ima_mask_ |= (1 << input->binding);
442  input++;
443  }
444  }
445  for (const ShaderCreateInfo::PushConst &uni : info.push_constants_) {
446  copy_input_name(input, uni.name, name_buffer_, name_buffer_offset);
447  input->location = glGetUniformLocation(program, name_buffer_ + input->name_offset);
448  input->binding = -1;
449  input++;
450  }
451 
452  /* Compatibility uniforms. */
453  for (auto &name : workaround_uniform_names) {
454  copy_input_name(input, name, name_buffer_, name_buffer_offset);
455  input->location = glGetUniformLocation(program, name_buffer_ + input->name_offset);
456  input->binding = -1;
457  input++;
458  }
459 
460  /* SSBOs */
461  for (const ShaderCreateInfo::Resource &res : all_resources) {
462  if (res.bind_type == ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER) {
463  copy_input_name(input, res.storagebuf.name, name_buffer_, name_buffer_offset);
464  input->location = input->binding = res.slot;
465  enabled_ssbo_mask_ |= (1 << input->binding);
466  input++;
467  }
468  }
469 
470  /* Builtin Uniforms */
471  for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORMS; u_int++) {
472  GPUUniformBuiltin u = static_cast<GPUUniformBuiltin>(u_int);
473  const ShaderInput *uni = this->uniform_get(builtin_uniform_name(u));
474  builtins_[u] = (uni != nullptr) ? uni->location : -1;
475  }
476 
477  /* Builtin Uniforms Blocks */
478  for (int32_t u_int = 0; u_int < GPU_NUM_UNIFORM_BLOCKS; u_int++) {
479  GPUUniformBlockBuiltin u = static_cast<GPUUniformBlockBuiltin>(u_int);
480  const ShaderInput *block = this->ubo_get(builtin_uniform_block_name(u));
481  builtin_blocks_[u] = (block != nullptr) ? block->binding : -1;
482  }
483 
484  this->sort_inputs();
485 
486  // this->debug_print();
487 }
488 
490 {
491  for (auto *ref : refs_) {
492  if (ref != nullptr) {
493  ref->remove(this);
494  }
495  }
496 }
497 
500 /* -------------------------------------------------------------------- */
505 {
506  for (int i = 0; i < refs_.size(); i++) {
507  if (refs_[i] == nullptr) {
508  refs_[i] = ref;
509  return;
510  }
511  }
512  refs_.append(ref);
513 }
514 
516 {
517  for (int i = 0; i < refs_.size(); i++) {
518  if (refs_[i] == ref) {
519  refs_[i] = nullptr;
520  break; /* cannot have duplicates */
521  }
522  }
523 }
524 
527 /* -------------------------------------------------------------------- */
534 } // namespace blender::gpu
#define BLI_assert_msg(a, msg)
Definition: BLI_assert.h:53
#define BLI_BITMAP_NEW(_num, _alloc_string)
Definition: BLI_bitmap.h:40
#define BLI_BITMAP_TEST(_bitmap, _index)
Definition: BLI_bitmap.h:64
#define BLI_BITMAP_ENABLE(_bitmap, _index)
Definition: BLI_bitmap.h:81
unsigned int BLI_bitmap
Definition: BLI_bitmap.h:16
MINLINE int max_ii(int a, int b)
bool GPU_shader_storage_buffer_objects_support(void)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
GPUUniformBuiltin
Definition: GPU_shader.h:111
@ GPU_NUM_UNIFORMS
Definition: GPU_shader.h:135
GPUUniformBlockBuiltin
Definition: GPU_shader.h:138
@ GPU_NUM_UNIFORM_BLOCKS
Definition: GPU_shader.h:148
#define MEM_reallocN(vmemh, len)
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
constexpr int64_t size() const
constexpr const char * c_str() const
void append(const T &value)
Definition: BLI_vector.hh:433
void extend(Span< T > array)
Definition: BLI_vector.hh:530
static bool shader_draw_parameters_support
Definition: gl_context.hh:65
static bool explicit_location_support
Definition: gl_context.hh:58
GLShaderInterface(GLuint program, const shader::ShaderCreateInfo &info)
void copy_input_name(ShaderInput *input, const StringRefNull &name, char *name_buffer, uint32_t &name_buffer_offset) const
const ShaderInput * ubo_get(const char *name) const
uint32_t set_input_name(ShaderInput *input, char *name, uint32_t name_len) const
static const char * builtin_uniform_block_name(GPUUniformBlockBuiltin u)
int32_t builtin_blocks_[GPU_NUM_UNIFORM_BLOCKS]
const ShaderInput * uniform_get(const char *name) const
int32_t builtins_[GPU_NUM_UNIFORMS]
static const char * builtin_uniform_name(GPUUniformBuiltin u)
depth_tx sampler(1, ImageType::FLOAT_2D, "combined_tx") .sampler(2
depth_tx normal_tx diffuse_light_tx specular_light_tx volume_light_tx environment_tx ambient_occlusion_tx aov_value_tx in_weight_img image(1, GPU_R32F, Qualifier::WRITE, ImageType::FLOAT_2D_ARRAY, "out_weight_img") .image(3
ccl_global KernelShaderEvalInput * input
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
static int block_binding(int32_t program, uint32_t block_index)
static int sampler_binding(int32_t program, uint32_t uniform_index, int32_t uniform_location, int *sampler_len)
static int ssbo_binding(int32_t program, uint32_t ssbo_index)
static int image_binding(int32_t program, uint32_t uniform_index, int32_t uniform_location, int *image_len)
unsigned int uint32_t
Definition: stdint.h:80
signed int int32_t
Definition: stdint.h:77
Describe inputs & outputs, stage interfaces, resources and sources of a shader. If all data is correc...