OpenGL -- How to deal with multiple image1D in OpenGL 4.5

Viewed 59

I need to transfer several variable length arrays to the shader. So I build up a rather complicated data structure in glsl, which contains multiple image1D. But I cannot successfully transfer the data to the shader now.

Fragment Shader:

struct HoleArea {
    bool clipping;
    int mesh_object_id;
    layout (rgba32f) image1D anchor_points;
    layout (rgba32f) image1D clip_planes;
};
layout (binding = 2) uniform HoleArea hole_area[10];

And the C++ code:

// set the anchor_points in hole_area[0]
glBindBuffer(GL_TEXTURE_BUFFER, m_anchorPointBuffer);
glBufferData(GL_TEXTURE_BUFFER, m_anchorPointPos.size() * sizeof(FLOAT4), &m_anchorPointPos[0], GL_STATIC_DRAW);
glBindBuffer(GL_TEXTURE_BUFFER, 0);

glBindTexture(GL_TEXTURE_BUFFER, m_anchorPointTexture);
glTextureBuffer(m_anchorPointTexture, GL_RGBA32F, m_anchorPointBuffer);
glBindTexture(GL_TEXTURE_BUFFER, 0);
glBindImageTexture(2, m_anchorPointTexture, 0, GL_TRUE, 0, GL_READ_ONLY, GL_RGBA32F);

So here is my question:

  1. What's the difference between image1D and imageBuffer? When I need to transfer a 1D glm::vec4 array into the shader, it seems that both image1D and imageBuffer can meet the requirement.

  2. As for an image format, there are r32f, rg32f and rgba32f. Why there isn't a rgb32f format to save the glm::vec3 data?

  3. For the code above, how should I set the anchor_points and clip_planes for each hole_area (hole_area[0], hole_area[1]...). In other words, how should I set the first variable (index of an image unit) in glBindImageTexture for each image1D.

I would be very thankful if somebody could answer my questions, thanks!

1 Answers

Unless you're using bindless texturing (and if you are, then you probably already know the answer), you cannot put opaque types like images inside of UBO/SSBO structures.

Opaque types can only be loose uniform variables; they can be arrayed, but they can't be part of a struct.

You could do this:

layout (binding = 0) uniform image1D hole_anchor_points[10];
layout (binding = 10) uniform image1D hole_clip_planes[10];

Each of those uniforms in the array has its own separate location, starting with the binding specified in the layout qualifier.

However, there are limits to the number of images you can access in a single shader stage. What you want tries to use 20 images in one stage, which probably exceeds your GPU's limits even if you correctly created such arrays.

If all you want to do is read some data from a buffer object, you should just use an SSBO. The last element in an SSBO can be unsized, thus allowing you to determine its size elsewhere. You can also specify where each array begins, thus allowing you to put multiple arrays into what the SSBO defines as a single array:

layout(binding = 0, std430) readonly buffer anchor_points
{
  int arrayIxs[10]; //Index offset to the start of each array.
  vec4 array[]; //Unsized. Determined by the size of the bound buffer range.
} hole_anchor_points;

vec4 anchor_point_ix(int arrayIx, int ix)
{
  return hole_anchor_points.array[ix + hole_anchor_points.arrayIxs[arrayIx]];
}


What's the difference between image1D and imageBuffer?

One is a 1D texture; the other is a buffer texture. One allows filtering, but has more strict limits; while the other always fetches exactly what is in the buffer and has far larger limits.

If your data is already in a buffer, and you just want to read from it without filtering, you should use a buffer texture.

Why there isn't a rgb32f format to save the glm::vec3 data?

Because hardware doesn't like misaligned data reads.

Related