2

I'm trying to send an array of glm::uvec4 to my SSBO. Is it possible or I should use another method ?

I'm using instanced drawing and I tell OpenGL to draw X instances (Depend on glm::uvec4 size that can varry)

Data stored:

std::vector<glm::uvec4> m_blocksToRender;

SSBO setup:

// SSBO
glGenBuffers(1, &m_ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(m_blocksToRender), m_blocksToRender.data(), GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);

Shader:

layout(std430, binding = 0) buffer blocksData
{
    uvec4 data[/* ??? can varry, depends on gl_InstanceID size */];
};
genpfault
  • 51,148
  • 11
  • 85
  • 139
Adrien Givry
  • 956
  • 7
  • 18
  • "*I'm trying to send an array of glm::vec4 to my SSBO.*" So why is the `vector` defining this array a `uvec4`? Are you using `vec4` (floats) or `uvec4` (unsigned ints)? – Nicol Bolas May 24 '18 at 19:18
  • That's an error, thanks for noticing me – Adrien Givry May 24 '18 at 19:19
  • 2
    SSBOs can have variable storage, up to whatever buffer range was bound for that particular buffer; UBOs must have a specific, fixed storage size. This means that you can have an array of arbitrary length in an SSBO (at the end, rather). The actual size of the array, based on the range of the buffer bound, can be queried at runtime in the shader using the length function on the unbounded array variable. www.khronos.org/opengl/wiki/Shader_Storage_Buffer_Object – Paritosh Kulkarni May 24 '18 at 19:39

1 Answers1

1

You definitely can. The straight way to do it is to bind the buffer as you have done, set the data prior to render call (if you wish to modify it) and then read it on your shader.

Depending on your use you also need to sotre the size of the arrya either in the SSBO directly or on a uniform.

So the the full solution would be:

C++

//Create SSBO
glGenBuffers(1, &m_ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(m_blocksToRender), m_blocksToRender.data(), GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);

void render()
{
  /* additional code */

  //Only needed if another buffer has been bound to the binding point 0
  glBindBuffer(GL_SHADER_STORAGE_BUFFER, m_ssbo);
  glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, m_ssbo);
  //Only needed if the buffer data needs to be changed
  glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(m_blocksToRender)

  //If you use the uniform option
  glUniform1i(glGetUniformLocation(programID, "size"), m_blocksToRender.size());
}

Fragment

If you use the uniform method:

uniform int size;
layout(std430, binding = 0) buffer blocksData
{
    uvec4 data[];
};

If you use the metadata version:

layout(std430, binding = 0) buffer blocksData
{
    uint size;
    uvec4 data[];
};

If you choose the second option you need to be carfeul about alignment problems, and you also need to implement a way to append the data size to the beggining of the buffer you send to the SSBO.

Edit: To disable the driver warning (which btw is NVIDIA specific, AMD cards seem to not throw this error)

Add the following line somwhere in your code before binding your buffer:

GLuint copy_warning = 0x20072;
glDebugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_PERFORMANCE,
    GL_DONT_CARE, 1, &copy_warning, GL_FALSE);
Makogan
  • 8,208
  • 7
  • 44
  • 112
  • Thanks for your answer ! However I don't need to get the array size from the shader because I'm using gl_InstanceID as the index. gl_InstanceID can't be out of the array range. The problem I have now is that the m_blockToRender array (m_blockToRender is now a vector) can varry, so I have to update my SSBO size using glBufferData. The problem is that I sometines get OpenGL warning : Buffer performance warning: Buffer object 174 (bound to GL_SHADER_STORAGE_BUFFER, and GL_SHADER_STORAGE_BUFFER (0), usage hint is GL_DYNAMIC_DRAW) is being copied/moved from VIDEO memory to SYSTEM HEAP memory. – Adrien Givry May 27 '18 at 15:24
  • What a small world, I was getting that warning as well. Do you want to know how to disable it? – Makogan May 27 '18 at 19:18
  • Try it out and let me know – Makogan May 27 '18 at 19:49
  • Well, so it's the only way... I don't like having a warning and just hide it, but if it's necessary I'll. Thank you ! – Adrien Givry May 27 '18 at 23:06
  • 1
    The thing is, this is just a Nvidia warning (AMD does not create that warning), I was in the same boat as you like a week ago. The truth is, it's an optimization warning not an error warning. Nothing will go wrong, but you need to be careful when doing this as it can slow down your program significantly if yourt data is large – Makogan May 28 '18 at 22:41
  • @Makogan, Hello, does this also work for vector of struct of glm::vec3 values? Im trying to pass to the compute shader the mesh of an object as triangles (so 3 glm::vec3 for the vertices and 3 for the normals). For example: struct TriangleSSBO{ glm::vec3 v1,v2,v3,n1,n2,n3 } and then vector triangles; – PeGiannOS Aug 31 '19 at 12:26
  • It works for any kind of data but you need to be careful with alignment – Makogan Aug 31 '19 at 20:54