Hi people, I’m new to the world of OpenGL shaders, and I’m looking for help with a problem I’ve come across.
I’m developing an application with OpenGL shaders and GLSL. Basically, I have one large loop that needs to be executed on each pixel. Because this loop should be executed on the pixels, I have put it in the fragment shader. The problem is that when I go to compile the fragment shader, I get an error because the number of elements in my loop exceeds the maximum possible size for a fragment shader.
Here’s the current code for my fragment shader, which compiles and outputs the right image:
So that compiles, but when I change the dimensions of redlogs[256] to something like [1024], the shader will not compile… I’m wondering what I should do instead? Is there a way to use larger arrays on the GPU?
You can move the data into textures such as TBOs or ordinary 2D textures, or into buffer objects accessed as SSBOs or UBOs.
With UBOs though, you might run into space constraints as IIRC the limit is ~64k on some GPUs. Whereas SSBOs, TBOs, and textures in general can be quite large. More on accessing those in shaders here: Interface Block (GLSL)
Given that you’re doing 2D access, you may just want to consider storing all this data in a 2D texture. Then you don’t need to do the array indexing in your shader and you can benefit from the texture cache.
All that said, from an efficiency standpoint, you probably should look at other formulations of your algorithm that don’t involve O(n^2) looping over all large images within each fragment. If your shaders take too long, you can trigger GPU driver resets, which will basically kill your program.
Thanks Dark_Photon, that sounds like the right direction. I’ll give it a try soon. I agree that it would make sense to reformulate the algorithm, but I’ve had some trouble understanding how I would do that…
In terms of OpenCL and kernels, the other option I see is having a 3D space of shape (Lx, Ly, DimN*DimM), where the third dimension spans those `logon’ images. In this formulation, a first kernel would operate on each point in the 3D space, calculating the the red, green, and blue component compressed from those 4 basis functions with associated amplitudes. After the first kernel finishes, a second kernel would come in and sum values over the 3rd dimension, creating the output 2d texture of shape (Lx, Ly) that could be passed to the fragment shader.
In your opinion, would the compute shader be a proper choice for this implementation? The pipeline would then be something like:
Compute shader 1: calculate sample values in 3d space (stored in an SSBO?) ->
Compute shader 2: compress the 3d buffers into 2d textures ->
Vertex shader: draw quad over viewport ->
Fragment shader: overlay 2d texture on the quad
Does this sound reasonable?
Thanks again, while this GLSL stuff can be challenging, it’s also very rewarding!