How to detect access violation on SSBO in OpenGL? - opengl

Suppose I have an SSBO in the glsl shader as follows.
layout(std430, binding = 10) buffer myData
{
uint64_t intArray[];
};
On the host, I will dynamically allocate the SSBO. In the shader, I will write data to this 'intArray' variable. How do I detect whether my shader code is accessing within the boundary of the array? Are there any tools to do the check (similar to valgrind, pageheap, -fsanitize, ... on CPU)?
Edit: In general, are there any ways to analyze the glsl code and figure out the memory issue?

The simplest way to figure out whether you're accessing within the array is to get the size of the array and check to see if the index you're about to use accesses past it or not. intArray.length() will give you the runtime length of the array, based on the size range of the buffer you have bound to that SSBO binding point.

Related

Shader storage buffer object slow – alternative?

I'm trying to make an array of vec3 available to a fragment shader. In the targeted application, there could be several hundred elements.
I tested transferring data in the form of a shader storage buffer object, declared as
layout(binding = 0) buffer voxels { vec3 xyz[]; }
and set using glBufferData, but I found that my fragment shader becomes very slow, even with only 33 elements.
Moreover, when I convert the same data into the GLSL code of a const vec3[] and include it in the shader code, the shader becomes noticeably faster.
Is there a better way – faster than an SSBO and more elegant than creating shader code?
As might already be apparent from the above, the array is only read from in the shader. It is constant within the shader as well as over shader invocations for different fragments, so effectively a uniform, and it is set only once or a few times over the runtime of the program.
I'd recommend using std430 layout specifier on the SSBO given that you are using vec3 data types, otherwise you'll be forced to pad the data, which isn't going to be great. In general, if the buffer is a fixed size, then prefer using glBufferSubData instead of glBufferData (the latter may reallocate memory on the GPU).
As yet another alternative, if you are able to target GL 4.4+, consider using glBufferStorage instead (or even better, if GL4.5 is available, use glCreateuffers, and glNamedBufferStorage). This let's you pass a few more hints to the GL driver about the way in which the buffer will be consumed. I'd try out a few options (e.g. mapping v.s. sub-data v.s. recreating each time).

Can interface block size be larger than underlying UBO in Opengl?

Let's declare a large interface block in a shader:
struct InstancingData
{
// whatever
};
#define LARGE_SIZE 1048576
layout(std140, row_major, binding = 0) uniform InstanceBlock
{
InstancingData data[LARGE_SIZE];
};
Then I want to bind a small UBO, containing less than LARGE_SIZE entries of InstancingData to this block. It may be either glBingBufferBase of a small array, or glBindBufferRange of a small range within a larger array.
Consequently, I will index data only with indices smaller than underlying buffer size allows, using an appropriate uniform or gl_VertexID. So formally it shouldn't lead to access violation.
Will these actions trigger an error or undefined behavior in any OpenGL version?
Another way to go:
I declared
InstancingData data[1];
Then I bound a buffer of 42 structures and indexed all of them (a 6x7 square bed of instanced models), and it worked fine on my machine. Is it guaranteed to work anywhere?
From ARB_uniform_buffer_object:
If any active uniform block is not backed by a sufficiently large
buffer object, the results of shader execution are undefined, and may
result in GL interruption or termination.
This is sufficient to say that backing InstancingData data[LARGE_SIZE]; with a small buffer is illegal.

OpenGL: How is MAX_SHADER_STORAGE_BLOCK_SIZE related to the real limit of SSBO size?

From skimming through the OpenGL documentation I kinda assumed that MAX_SHADER_STORAGE_BLOCK_SIZE is the actual limit on the size an SSBO might have. On my GPU this value is reported as 128 MB. However, it's working fine to create and use much larger buffers (Gigabytes), as long as they fit into video memory.
A few lines of code to clarify:
In my compute shader the buffer is accessed via
layout(std430, binding=2) buffer renderedDataRed
{
uint counts_SSBO[];
};
On the CPU side I'm creating the buffer with
glGenBuffers(1, &drawBuffer);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, drawBuffer);
glBufferData(GL_SHADER_STORAGE_BUFFER, 4 * pixelCount, nullptr, GL_DYNAMIC_COPY);
glClearBufferData(GL_SHADER_STORAGE_BUFFER,GL_R8,GL_RED,GL_UNSIGNED_INT,nullptr);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, drawBuffer);
As said, it's working fine to have pixelCounts leading to buffer sizes far beyond MAX_SHADER_STORAGE_BLOCK_SIZE...
So, is MAX_SHADER_STORAGE_BLOCK_SIZE supposed to be the actual SSBO size limit and my driver (mesa radeonsi) is just reporting wrong numbers, or did I misunderstand the documentation?
Can it be that arrays that aren't explicitly sized do not count towards MAX_SHADER_STORAGE_BLOCK_SIZE?
The maximum storage block size is the maximum size of a storage block: the thing you define in GLSL that you hook a buffer object to. Since your storage block us entirely composed of a variable sized array, it has no defined size.
There is otherwise no limit on the size of the bound range for a buffer object that is bound for use as an SSBO. So as far as the OpenGL specification is concerned, this should work.
That being said, I would not rely on it. The Vulkan equivalent explicitly limits the size used in buffer descriptors for storage buffers. So clearly, such limitations exist.

Dynamic size arrays in Uniform buffer in Vulkan

I recently re-wrote some code to use Shader Storage Buffer Object in OpenGL, to send in dynamic sized arrays into GLSL, vastly increasing performance when drawing many procedurally generated objects.
What I have is a couple of thousand points, and for each point I render a procedurally generated circular billboard. Each one can in turn have different colors and radius, as well as a few other characteristics (represented as bools or enums)
I fill a vector with these positions, packed together with the radius and color. Then I upload it as a Shader Storage Buffer Object with dynamic size. I create a dummy VAO, containing 0 vbos, but call the draw command with the same amount of points that I have.
Inside the shader, I then iterate through this array, using the gl_VertexID, and generate a quad (two triangles) with texture coordinates, for each point.
I'm looking for a way of doing the same in Vulkan. Is there some way in Vulkan, to pass a dynamic sized array into a shader? Reading about Shader Storage Buffer objects in Graham Seller's Vulkan book, it only mentions them being read-write, but not capable of dynamically sized arrays.
Edit: It seems that storage buffers are in fact capable of dynamic sized arrays, based on Sasha Willems particle example. Is there a way of doing the same thing via uniforms?
I may be misunderstanding your question. SSBOs have identical behavior and functionality between the two APIs. That's why they're named the same. An unbounded array at the end of a storage block will have its length defined at runtime, based on what data you provide.
The size of a buffer descriptor is not hard coded into the descriptor set layout; it's something you set with VkWriteDescriptorSet. Now unlike the offset, you cannot change a descriptor set's size without changing the descriptor itself. That is, you don't have an equivalent to vkCmdBindDescriptorSets's pDynamicOffsets field. So you have to actually update the descriptor in-situ to change the length.
But that just requires double-buffering your descriptor set; it shouldn't be a problem.
Is there a way of doing the same thing via uniforms?
Again, the answer is the same for Vulkan as for OpenGL: no.

OpenGL - glDrawElements vs Vertex Array Objects

I need help to see the trade-offs between them.
It looks to me that glDrawElements() needs to get the index-data "live" as a parameter.
On the other side if I use VAOs then during startup I buffer the data and the driver might decide to put it on the GPU, then during rendering I only bind the VAO and call glDrawArrays().
Is there no way to combine the advantages? Can we buffer the index-data too?
And how would that look in the vertex shader? Can it use the index and look it up in the vertex positions array?
This information is really a bit hard to find, but one can use glDrawElements also in combination with a VAO. The index data can then (but doesn't have to) be supplied by a ELEMENT_ARRAY_BUFFER. Indexing works then as usual, one does not have to do anything special in the vertex shader. OpenGL ensures already that the indices are used in the correct way during primitiv assembly.
The spec states to this in section 10.3.10:
DrawElements, DrawRangeElements, and DrawElementsInstanced source
their indices from the buffer object whose name is bound to ELEMENT_-
ARRAY_BUFFER, using their indices parameters as offsets into the buffer object
This basically means, that whenever a ELEMENT_ARRAY_BUFFER is bound, the indices parameter is used as an offset into this buffer (0 means start from the beginning). When no such buffer is bound, the indices pointer specifies the address of a index array.