2

I have an UBO that looks like this:

#version 450
#extension GL_ARB_separate_shader_objects : enable

const uint InstanceCount = 64;

layout(std140, align = 16, binding = 0) uniform UBO
{
    vec4 array_indices[InstanceCount];
    mat4 proj;
    mat4 model;
    mat4 models[InstanceCount];
    uint selection[128];
} ubo;

and each vertex shader instance accesses one bit from uint selection[128] like this:

layout(location = 1) out uint is_selected;

void main() {
    uint id = gl_InstanceIndex;
    uint num_index = id / 32;
    uint bit_index = id % uint(32);
    uint n = ubo.selection[num_index];
    is_selected = n & (1u << bit_index);
...
}

The problem is that whenever id is greater than 31 (that is when num_index is 1 or greater) n is always zero. But RenderDoc shows that the first 2 uints of ubo.selection[128] are F0000380 and 0000000F (which means the 2nd uint is not zero), so I'm guessing the shader has problems indexing into the array, so any ideas why n is zero unless I'm indexing into the first elem of the array?

AMD Polaris10 video card.

The C++ structure which feeds this UBO is:

static const u32 InstanceCount = 64;

struct UBO
{
    vkm::vec4 array_indices[InstanceCount];
    vkm::mat4 proj;
    vkm::mat4 model;
    vkm::mat4 models[InstanceCount];
    u32 selection[128];
};

vkm::mat4 is a class with a single member float arr[16].

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
nicknorton
  • 63
  • 5
  • 1
    How are you uploading data to the shader? That is, what is the C or C++ structure which you *think* is equivalent to the GLSL definition? – Nicol Bolas Jan 20 '20 at 20:14
  • I appended the C++ structure, a padding issue is the only problem I can think of but I don't know how to fix/detect it. – nicknorton Jan 20 '20 at 21:23
  • If you have an answer to your question, write it as an *answer* using the Add an Answer button; don't edit it into your question. – Nicol Bolas Jan 21 '20 at 14:37

2 Answers2

3

In std140 layout, all arrays have an element-to-element array stride rounded up to the nearest sizeof(vec4), which is 16 bytes. So unless u32 is actually a 16-byte structure, u32 selection[128]; doesn't match with your definition.

What your GLSL needs to do is to take a uvec4 array 4 times smaller than its actual size, and index the array like this:

const int num_selection_elements = 128;
const int num_selection_words = num_selection_elements / 4
layout(std140, align = 16, binding = 0) uniform UBO
{
    ...
    uvec4 selection[num_selection_words];
} ubo;

void main() {
    uint id = gl_InstanceIndex;
    uint bit_index = id % 32;
    uint word_index = (id / 32) % 4;
    uint vec_index = id / (num_selection_words * 32 * 4);
    uint n = ubo.selection[vec_index][word_index];
    is_selected = n & (1u << bit_index);
...
}
Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • Thanks, though I tested it and the selection doesn't work at all now, though RenderDoc now says that the UBO occupies less space. I just woke up so if I have new ideas I'll share later. It's a small app (works only on Linux), should I post it somewhere so people can try compiling it? – nicknorton Jan 21 '20 at 09:47
  • RenderDoc says the selection array isn't empty, so could be the indexing into the array.. or some other misterios cause. – nicknorton Jan 21 '20 at 10:02
  • Thank you! Your answer is right except for the vec array indexing which by trial and error I eventually figured out and edited my original post. – nicknorton Jan 21 '20 at 14:16
0

After more testing this is the final correct indexing into the array of uvec4:

uint index = gl_InstanceIndex;
const uint vec_index = index / 128; // 128 = 32 * 4 = vec size
index %= 128;
uint num_index = index / 32;
const uint bit_index = index % 32;
const uint n = ubo.selection[vec_index][num_index];
is_selected = n & (1u << bit_index);

That is, when indexing past the first uvec4 num_index becomes wrong without index %= 128;.

nicknorton
  • 63
  • 5