20

First of all, re: "GPUs are simply giant SIMD processors and should operate in lock-step", it's a bit more complicated than that. The entire GPU does not run in lockstep. Shader threads are organized into groups of 32 called "warps" (on NVIDIA; on AMD they're groups of 64 called "wavefronts", but same concept). Within a warp, all the threads do run in ...


19

An architectural advantage of compute shaders for image processing is that they skip the ROP step. It's very likely that writes from pixel shaders go through all the regular blending hardware even if you don't use it. Generally speaking compute shaders go through a different (and often more direct) path to memory, so you may avoid a bottleneck that you would ...


12

No it is not guaranteed, since the OpenGL specification allows that two Compute Shader run concurrently or even in different order. You need to call glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT) before the second glDispatchCompute to ensure visibility of the writes from program_one. From the OpenGL.org wiki article on the memory model: [...] ...


8

John has already written a great answer so consider this answer an extension of his. I'm currently working a lot with compute shaders for different algorithms. In general, I've found that compute shaders can be much faster than their equivalent pixel shader or transform feedback based alternatives. Once you wrap your head around how compute shaders work, ...


7

If you have access to glsl 4.3+ (or glsl ES 3.1) you can use atomicAdd The next option is to use a barrier() after all vertices are generated in the compute and then multiplying the value in the counter: main(){ // generate vertices barrier(); if(gl_localInvocationID == vec3(0)){ indirectCount = atomicCounter(indirectIndexCount)*3; ...


7

It's not quite correct, today, to think of compute shaders as being "in the shader pipeline" in the same sense that your vertex and fragment shaders are literally hooked up into a pipeline. Compute shaders are not "hooked up" to anything currently, cannot drive rasterization, or directly consume the outputs of rasterization. What it allows you to do, ...


5

Yes, it's totally possible, and in fact it's preferable to keep buffers in memory if you will be accessing them over the life of your program, rather than deallocating and reallocating them again. I can't speak for Unity's way of allocating persistent buffers - I work with Unity and do a lot of shader writing in Cg, but most of our stuff is on mobile so ...


5

Not all threads will execute in lockstep but they are split into groups whose threads are locked to each other. This means that if only 1 thread out of all threads enters a branch then only 1 group will need to enter that branch while all the others will skip it. In that group that has to execute both branches it will actually execute both branches but ...


5

For an nVidia only solution you can use floating point atomic add intrinsics (like NvInterlockedAddFp32) Unlocking GPU Intrinsics in HLSL | NVIDIA Developer I tried this on 80.000 vertex mesh and it's quite fast (something like 1 or 2 ms on a GTX980M, if I remember correctly) Just beware of compiling your shaders in release for the intrinsics to work (due ...


5

The problem is actually in your fragment shader: color_out = texture(source_image, gl_FragCoord.xy); The texture() function accepts normalized coordinates which range from 0.0 to 1.0. The gl_FragCoord built in contains window coordinates which range from (0.0, 0.0) to (window width, window height). To fix this, change the fragment shader to this: ...


4

Working Towards an Exact solution Just some quick thought before I must run! Ok, let us turn the problem on its head. What if one does not calculate the area of the triangle cut by the circle. Instead let's calculate the inverse of this. The area of three segments cut out of the circle. The beauty of this approach is that we can make a single piece of code ...


4

Lowering register pressure doesn't necessarily give you any performance boost though. I recently went through this exercise myself on GCN architectures (for a simple ray tracer) and reduced register pressure so that it increased occupancy from 2 to 4, which had no impact on performance. It's generally a good idea to reduce the pressure if you need to hide ...


4

Core OpenGL has no mechanism for this. The ARB_compute_variable_group_size extension provides such a feature. It doesn't allow for indirect compute operations though. It doesn't seem to have much AMD support though (outside of open source Linux drivers). And Intel support is nil.


4

There shouldn't be any performance penalty inherent in using a 3D group over a 2D one, the dimensions are just an aid for programmers to map invocations on to memory locations (since you can read or write wherever you like). The group size affects which invocations can access the same block of groupshared memory, so it forces all warps from the same group ...


4

Work groups share resources. The most notable resources they share are barriers and LDS (Local Data Storage aka shared memory in GL lingo, aka Thread Group Shared Memory). See Efficient Compute Shader Programming for an example where LDS/TGSM is used to accelerate a simple gaussian blur. It is an interesting thought exercise of how a simple algorithm (...


3

The Opengl deals this problem automatically? How could it? At no point do you inform OpenGL that you only want 900 invocations. You have exactly 2 mechanisms to control the number of invocations: the work group size in the shader, and the work group count in the dispatch call. That determines how many invocations there are. If you want a variable number ...


3

In principle you avoid using scatter (casting) behavior with GPU. They have offered random output coordinate write out since only shader model 5 as a need for extreme situations. But you should as general rule write your GPU code in a "gather" fashion. The difference: the hardware threads are logically soft-locked to one output position in the render target....


3

Vulkan is not really suited to at least some of the task you're trying to accomplish. It has no mechanism to declare from within a shader that some additional work should be invoked. Or at least, not directly. The most effective way to execute this on the GPU would be to compute each level of all of the trees as a distinct dispatch operation. So you process ...


3

After looking into this for a while, I found out a couple of things: You cannot avoid a memcpy: You cannot write directly into texture storage allocated for a compressed texture using only OpenGL API calls. This means that you cannot avoid the call to glCompressedTexImage2D with a bound PBO. That being said, you may be able to use a 16-bit RGBA texture and ...


3

I stumbled on this blog: Compute Shader Optimizations for AMD Given what tricks can be done in compute shader (that are specific only to compute shaders) I was curious if parallel reduction on compute shader was faster than on pixel shader. I e-mail'ed the author, Wolf Engel, to ask if he had tried pixel shader. He replied that yes and back when he wrote ...


3

r a similar problem (a tree of combined noise functions, evaluated on the GPU), I found a good method is to generate a shader from the expression tree. Each predefined node corresponds to a single shader function, e.g. float simplexNode(vec3 pos) { // ... implementation of simplex noise } or float sumNode(float val1, float val2) { return val1 + val2; ...


2

I found it! The issue stems from a problem in the swap. When we swap buffers, the output buffer becomes the input and the input buffer becomes the output. However, the buffer that is now the output was not updated to match! To illustrate: Init: In Out 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 First Iteration (remove north corners): In Out 1 1 ...


2

Got help from someone over in the OpenGL subreddit. Apparently, as I trimmed the code for posting here and there, I changed the operation of the code. What I trimmed to this: void main() { uint index = gl_GlobalInvocationID.x; Particle p = AllParticles[index]; vec2 deltaPosition = p._velocity * uDeltaTimeSec; p._position = p._position + ...


2

So i searched a lot after this and I think it was my confusion on FrameBuffer Objects. I thought you could use FBO's just like a default FrameBuffer and display the texture image attached to it but you can't. It's only used for offscreen rendering. So while you can use rendering commands to draw something to a "texture image" attached to it, you can't "...


2

To first clear your confusion around the terms: GPGPU stands for General Purpose computing on GPUs CUDA is the specific NVIDIA API to perform GPGPU only on their hardware OpenGL is a graphics specific API and is vendor independent OpenCL is a parallel programming compute API and is vendor independent Compute Shaders are a way to perform general purpose ...


2

The float2 type in the Metal structure requires an alignment of 8 bytes. The stride of the struct then becomes 24 so every value is aligned properly if you use it in an array. Your Swift structure only uses float which requires an alignment of 4 bytes, and an overall stride of 20. This presentation by Apple goes into some detail (starting at 30:20 of the ...


2

You havent' set the mipFilter property for your samplerDescriptor. The default value for mipFilter is notMipped which means the sampler will never access anything other than level 0. Set it to nearest or linear.


2

I can see a few things wrong here. First, you're setting your GL buffer size to sizeof(vertices) * vertices.size() This looks wrong. What is vertices? A std::array of vec4? Then you want vertices.size() * sizeof(glm::vec4), or just sizeof(vertices) Second, as wandering-warrior said, you want to be binding to GL_ARRAY_BUFFER before calling ...


2

I won't be discussing the usefulness of workgroups here as you can find it pretty much anywhere. However I am going to touch up on GPU architecture to understand why do we have workgroups in the first place. Most GPUs are designed in such a way that the concept of workgroup is useful. I won't go into details but give a brief overview as to how the mainstream ...


1

In addition to the more direct existing answer, there is a way to work around this in unextended OpenGL to some degree, feeding from the fact that in contrast to CUDA OpenGL compute shaders are not pre-compiled with application build (well, they can nowadays, but aren't by default). Instead you usually compile your compute shaders at some point during ...


Only top voted, non community-wiki answers of a minimum length are eligible