Discussion:
[Opensg-users] OpenSG2: Compute Shader...
Johannes Brunen
2017-03-29 14:42:49 UTC
Permalink
Hello Carsten and Gerrit,

I have some need for a compute shader and therefore I have learned its usage in OpenSG land. As a result I have some examples that I would like to see in OpenSG and some patches to the code base.

Let me first give you some information about the patches:

1. Main CMakeLists.txt file:
I have added a statement that allows you to bring boilerplate examples into the Examples/Advanced folder. I have added five examples into this folder because IMHO these are not simple anymore.

2. Source/Base/Base/OSGPolygon.cpp
Removed a compiler warning.

3. Source/Contrib/ComputeBase/ComputeShader/OSGComputeShaderAlgorithm.fcd
3.0. Added some documentation
3.1. Added a ChunkMaterial attribute that allows the use of ShaderStorageBufferObjs and UniformBufferObjs in conjunction to the TextureImageChunk. This allows you to bring multiple of these chunks into the compute shader.
3.2. Added the possible use of a glMemoryBarrier at the end of the computation.
3.3. Added the possible use of a variable work group size.

For 3.2 and 3.3 the following ARB must be available: GL_ARB_shader_image_load_store and GL_ARB_compute_variable_group_size
These provide the glMemoryBarrier and the glDispatchComputeGroupSizeARB APIs that are used.

ATTENTION: I have not added these to the OSGGLEXT.h and OSGGLFuncProtos.h files, because I do not work with them. I hope that this is Ok, and not too much of a burden to you.

4. Source/System/NodeCores/Drawables/Geometry/Properties/OSGGeoIntegralBufferRefProperty.cpp and
Source/System/NodeCores/Drawables/Geometry/Properties/OSGGeoVectorBufferRefProperty.cpp
At first, I was going to use these but decided otherwise. However, I think that their implementation is not correct with respect to the GL id.

5. Source/System/State/Base/OSGShaderStorageBufferObjChunk.cpp
Source/System/State/Base/OSGShaderStorageBufferObjStdLayoutChunk.cpp
Source/System/State/Shader/Variables/OSGShaderVariables.inl
I have changed the usage of calls like
hasExtOrVersion(_extUniformBufferObject, 0x0310);
getExtIdGPUShader4(), 0x0330, 0x0200))

to

hasExtOrVersion(_extUniformBufferObject, 0x0301);
getExtIdGPUShader4(), 0x0303, 0x0200))

That is the form found elsewhere in the code base. Could you confirm that this is the correct usage pattern?

6. Source/System/State/Base/OSGShaderStorageBufferObjRefChunk.fcd
This one is new and it allows you to bind a shader storage buffer object from an ordinary array buffer provided by the geo properties. This works fine if the array layout is compatible to the std430 layout format. That is the case for Pnt4f, Vec4f and Vec1f vector properties.

The compute shader examples I have written are numbers 1 to 5 and are of growing complexity. The first three build on the CSM compute shader example. Especially the first one is just a plain translation into C++ world. The second one is slight variation and uses a ShaderProgram instead of providing the source code directly to the ComputeShaderChunk. The third uses a ShaderStorageBufferObjChunk to provide some coloring into the compute shader. The fourth is a variation of the well known cylinder/torus example, but uses a compute shader to modify the material database which is a ShaderStorageBufferObjChunk. The fifth example uses the new ShaderStorageBufferObjRelChunk. It is a simple particle simulation, that does allows me to run as much as 6.000.000 particles in the simulation.

This contribution builds up on the last one I have send to the list (cc. to Carsten; mail still pending on the list, awaits moderation), e.g. it uses the MultiPropertySSBOChunk. However, the diff is against my last clone of the OpenSG master.

Best regards,
Johannes
Johannes
2017-03-31 04:59:15 UTC
Permalink
Hi,

I have a small addition. I have added the necessary extensions to the
OSGGLExt.h and OSGGLFuncProtos.h headers. The
GL_ARB_image_shader_load_store was already present, so I have only added
the GL_ARB_compute_variable_group_size extension.

Best,
Johannes
Johannes
2017-05-04 06:56:36 UTC
Permalink
Hello Carsten,

is this still in the pipeline?

Best,
Johannes
Carsten Neumann
2017-05-10 16:11:30 UTC
Permalink
Hello Johannes,
Post by Johannes
is this still in the pipeline?
yes, thank you for the reminder though. Since this modifies existing
code (as opposed to mostly adding new classes) I wanted to take a little
closer look.
- For OSGComputeShaderAlgorithm is it possible to combine the
useMemoryBarrier and memoryBarrier fields, i.e. if memoryBarrier is
GL_NONE that means no memory barrier? That would allow controlling the
barrier with a single field instead of requiring the setting of two.
- Can you imagine a situation where a barrier is needed/useful before
the compute shader? If so, should we have
preMemoryBarrier/postMemoryBarrier fields instead?
- In OSGGeo{Integral/Vector}BufferRefProperty you add getOpenGLId helper
functions, but then they appear to not be used. Did I miss something?

Other than these small things this is great and if the above triggers
changes they can be done as follow-ups; I'll commit the current state
now. Thank you for the additions!

Cheers,
Carsten
Gerrit Voß
2017-05-10 18:22:36 UTC
Permalink
Hi,

sorry for being mostly silent, I'm chasing one deadline after another
since beginning of the year.
Post by Carsten Neumann
Hello Johannes,
Post by Johannes
is this still in the pipeline?
yes, thank you for the reminder though. Since this modifies existing
code (as opposed to mostly adding new classes) I wanted to take a little
closer look.
- For OSGComputeShaderAlgorithm is it possible to combine the
useMemoryBarrier and memoryBarrier fields, i.e. if memoryBarrier is
GL_NONE that means no memory barrier? That would allow controlling the
barrier with a single field instead of requiring the setting of two.
- Can you imagine a situation where a barrier is needed/useful before
the compute shader? If so, should we have
preMemoryBarrier/postMemoryBarrier fields instead?
- In OSGGeo{Integral/Vector}BufferRefProperty you add getOpenGLId helper
functions, but then they appear to not be used. Did I miss something?
small comment, the *Ref* classes are meant to refer to/reference OpenSG
external OpenGL objects, so validating them through OpenSG and
translating them to an OpenSG managed OpenGL Id is not the intended
behavior.

So the changes to OSGGeo{Integral/Vector}BufferRefProperty will break
existing code and kind of duplicate what the normal properties do.

What was the reason behind these changes ?

kind regards
gerrit
Carsten Neumann
2017-05-10 18:43:05 UTC
Permalink
Hi Gerrit,
Post by Gerrit Voß
sorry for being mostly silent, I'm chasing one deadline after another
since beginning of the year.
not worries, good to hear it's still you doing the chasing instead of
the deadlines hunting you ;)
Post by Gerrit Voß
Post by Carsten Neumann
Post by Johannes
is this still in the pipeline?
yes, thank you for the reminder though. Since this modifies existing
code (as opposed to mostly adding new classes) I wanted to take a little
closer look.
- For OSGComputeShaderAlgorithm is it possible to combine the
useMemoryBarrier and memoryBarrier fields, i.e. if memoryBarrier is
GL_NONE that means no memory barrier? That would allow controlling the
barrier with a single field instead of requiring the setting of two.
- Can you imagine a situation where a barrier is needed/useful before
the compute shader? If so, should we have
preMemoryBarrier/postMemoryBarrier fields instead?
- In OSGGeo{Integral/Vector}BufferRefProperty you add getOpenGLId helper
functions, but then they appear to not be used. Did I miss something?
small comment, the *Ref* classes are meant to refer to/reference OpenSG
external OpenGL objects, so validating them through OpenSG and
translating them to an OpenSG managed OpenGL Id is not the intended
behavior.
So the changes to OSGGeo{Integral/Vector}BufferRefProperty will break
existing code and kind of duplicate what the normal properties do.
What was the reason behind these changes ?
Oh right, I missed the part about this being external GL ids that do not
need mapping. I'll revert that part right away. If Johannes has a
scenario where the previous behavior is not doing the right thing we can
figure out a correct change with more calm. Sorry about the (potential)
breakage.

Cheers,
Carsten
Gerrit Voß
2017-05-10 19:07:03 UTC
Permalink
Hi,
Post by Carsten Neumann
Hi Gerrit,
Post by Gerrit Voß
sorry for being mostly silent, I'm chasing one deadline after another
since beginning of the year.
not worries, good to hear it's still you doing the chasing instead of
the deadlines hunting you ;)
Post by Gerrit Voß
Post by Carsten Neumann
Post by Johannes
is this still in the pipeline?
yes, thank you for the reminder though. Since this modifies existing
code (as opposed to mostly adding new classes) I wanted to take a little
closer look.
- For OSGComputeShaderAlgorithm is it possible to combine the
useMemoryBarrier and memoryBarrier fields, i.e. if memoryBarrier is
GL_NONE that means no memory barrier? That would allow controlling the
barrier with a single field instead of requiring the setting of two.
- Can you imagine a situation where a barrier is needed/useful before
the compute shader? If so, should we have
preMemoryBarrier/postMemoryBarrier fields instead?
- In OSGGeo{Integral/Vector}BufferRefProperty you add getOpenGLId helper
functions, but then they appear to not be used. Did I miss something?
small comment, the *Ref* classes are meant to refer to/reference OpenSG
external OpenGL objects, so validating them through OpenSG and
translating them to an OpenSG managed OpenGL Id is not the intended
behavior.
So the changes to OSGGeo{Integral/Vector}BufferRefProperty will break
existing code and kind of duplicate what the normal properties do.
What was the reason behind these changes ?
Oh right, I missed the part about this being external GL ids that do not
need mapping. I'll revert that part right away. If Johannes has a
scenario where the previous behavior is not doing the right thing we can
figure out a correct change with more calm. Sorry about the (potential)
breakage.
There is one example actually using 2 ids, OSGTextureObjRefChunk.

This one has a oglGlId and an osgGlId if the OSG id is set the normal
OSG validation/mapping is done. If the oglGlId is set only the GL calls
are made. If both are set, the OpenSG id wins ;)

If there is a need to reference OpenSG internal properties this might be
the way to go.

kind regards
gerrit
Johannes
2017-05-11 06:23:05 UTC
Permalink
Hello Carsten and Gerrit,

I'm really happy to hear from you again :-)

Allow me to answer all the questions and remarks in this answer.
Post by Carsten Neumann
- For OSGComputeShaderAlgorithm is it possible to combine the
useMemoryBarrier and memoryBarrier fields, i.e. if memoryBarrier
is GL_NONE that means no memory barrier? That would allow
controlling the barrier with a single field instead of requiring
the setting of two.
Hmm, I don't think so. GL_NONE is not a valid (better listed of allowed)
parameters to the glMemoryBarrier API. I wouldn't try this.
Post by Carsten Neumann
- Can you imagine a situation where a barrier is needed/useful
before the compute shader? If so, should we have
preMemoryBarrier/postMemoryBarrier fields instead?
I can't come up with a good scenario. Maybe if you would like to do some
post processing of the buffer/image written by the fragment shader. I
would wait until someone has a real need for that.
Post by Carsten Neumann
- In OSGGeo{Integral/Vector}BufferRefProperty you add getOpenGLId
helper functions, but then they appear to not be used. Did I
miss something?
Let me explain how I came up with this modification first.

I was writing example 'computeshader5.cpp' and have had the need to
transport data from the compute shader to the fragment shader. In the
compute shader I can modify either a shader storage buffer object or a
texture image.
In this particular example, however, I have the need to use the written
data from the compute shader in form of an array buffer in order to use
them as input data into the vertex/fragment pipeline. I did see two
possibilities for that scenario. Either setup a geo property and tell
the compute shader that this buffer is basically a shader storage buffer
object or the other way around, that is, to setup a shader storage
buffer object and to tell the pipeline shaders that it is basically an
array buffer.
Firstly, I did go with the second approach and I was positively
surprised to find the GeoVectorBufferRefProperty that seemed to be
invented for my scenario. That is, setup the shader storage buffer
object and to provide the GL id to the GeoVectorBufferRefProperty
object. Then I discovered that the Id provided to the property interface
is taken directly instead of going the route over the
pWin->getGLObjectId(getGLId()). At this point I thought that this is
probably an implementation error or that it is simply not finished yet.
So I changed it and went on with the example. It worked well this way.
Then I thought about the first approach, that is to setup the geo
property in the first place and to reference that buffer as a shader
storage buffer object. So I wrote the ShaderStorageBufferObjRefChunk and
adapted the example accordingly. That also worked well and I leaved it
in this final state.
Post by Carsten Neumann
small comment, the *Ref* classes are meant to refer to/reference
OpenSG external OpenGL objects, so validating them through OpenSG
and translating them to an OpenSG managed OpenGL Id is not the
intended behavior.
So I misinterpreted the idea of these guys. My scenario is referencing
within OpenSG.
Post by Carsten Neumann
I'll revert that part right away. If Johannes has a
scenario where the previous behavior is not doing the right thing
we can figure out a correct change with more calm.
As the example currently works not with the GeoVectorBufferRefProperty
but with the ShaderStorageBufferObjRefChunk the revert is not hurting.
But I think that the scenario that I describe above is a valid and
important one. So we should support it. Additionally, now we have a
semantically interface break between the 'Ref' classes. We should find a
solution that supports both scenarios equally.
Post by Carsten Neumann
There is one example actually using 2 ids, OSGTextureObjRefChunk.
I do not know this one and have to look it up.
Post by Carsten Neumann
This one has a oglGlId and an osgGlId if the OSG id is set the
normal OSG validation/mapping is done. If the oglGlId is set
only the GL calls are made. If both are set, the OpenSG id wins
If there is a need to reference OpenSG internal properties this
might be the way to go.
This sounds promising. But I we would transfer that into the geo
property ref classes we would still break backward compatibility because
of API naming.

It is good that you have still interest in OpenSG. I have worked a lot
recently on OpenSG. The last thing that I have finished is to write an
ClusterShading example in the line of:

Ola Olsson, Markus Billeter, and Ulf Assarsson
High Performance Graphics (2012), pp. 1–10
C. Dachsbacher, J. Munkberg, and J. Pantaleoni (Editors)
http://efficientshading.com/wp-content/uploads/clustered_shading_preprint.pdf
http://efficientshading.com/2013/08/01/practical-clustered-deferred-and-forward-shading/

This example works quite well and I will send it to the list in the near
future. I have to do some polishing to get it upload ready. The next
step that I plan is to write a Stage class that wraps the implementation
of this example so that the user only has to add this stage to its scene
in order to take credit from the clustered light arrangement in the
fragment shader in a simple way.
What I have learned with this example is that you can do modern OpenGL
with OpenSG quite well.

So please stay tuned,

Best,
Johannes
Gerrit Voß
2017-05-11 06:45:13 UTC
Permalink
Hi,
Post by Johannes Brunen
Hello Carsten and Gerrit,
I'm really happy to hear from you again :-)
Post by Gerrit Voß
small comment, the *Ref* classes are meant to refer to/reference
OpenSG external OpenGL objects, so validating them through OpenSG
and translating them to an OpenSG managed OpenGL Id is not the
intended behavior.
So I misinterpreted the idea of these guys. My scenario is referencing
within OpenSG.
Post by Gerrit Voß
I'll revert that part right away. If Johannes has a
scenario where the previous behavior is not doing the right thing
we can figure out a correct change with more calm.
As the example currently works not with the GeoVectorBufferRefProperty
but with the ShaderStorageBufferObjRefChunk the revert is not hurting.
But I think that the scenario that I describe above is a valid and
important one. So we should support it. Additionally, now we have a
semantically interface break between the 'Ref' classes. We should find a
solution that supports both scenarios equally.
Post by Gerrit Voß
There is one example actually using 2 ids, OSGTextureObjRefChunk.
I do not know this one and have to look it up.
Post by Gerrit Voß
This one has a oglGlId and an osgGlId if the OSG id is set the
normal OSG validation/mapping is done. If the oglGlId is set
only the GL calls are made. If both are set, the OpenSG id wins
If there is a need to reference OpenSG internal properties this
might be the way to go.
This sounds promising. But I we would transfer that into the geo
property ref classes we would still break backward compatibility because
of API naming.
I'm actually ok with this as it won't compile (which is a pretty
obvious hint that something changed ;)). The original commit
unfortunately silently broke stuff as only the inner workings changed.

kind regards
gerrit
Johannes
2017-05-11 07:01:01 UTC
Permalink
Hi Gerrit,
Post by Gerrit Voß
Post by Johannes
This sounds promising. But I we would transfer that into the geo
property ref classes we would still break backward compatibility because
of API naming.
I'm actually ok with this as it won't compile (which is a pretty
obvious hint that something changed ;)). The original commit
unfortunately silently broke stuff as only the inner workings changed.
Ok I will give it a try.

I have one additional remark wrspt. to the ComputeShader stuff.
Currently it is housed in the Contrib\ComputeBase library. Since many
techniques are going to work with compute shaders nowadays, they are all
doomed to live outside of the core libraries probably in their own
techniques library that would be dependent on the Contrib\ComputeBase
library. I was thinking along the line that it might be preferable to
have to compute shader stuff as first class citizens like the other
shader code. What do you think?

Best,
Johannes
Johannes
2017-05-11 10:26:15 UTC
Permalink
Hi Carsten and Gerrit,
Post by Johannes
Ok I will give it a try.
Attached you can find a first version of the changes. I have added a
osgGLId field to the ref property classes. I still use the inherited
GLId field, but I have added an getOglGLId/setOglGLId API. I have still
an issue with the implementation since in the former cpp-files you can
find a few statements with getGLId() != 0 and I'm unsure how to handle
these correctly. I have replace these calls by (getOsgGLId() != 0 ||
getOglGLId() != 0). Can I safely use this->getOpenGLId(pEnv) != 0 instead.
Especially, in the integral ref property implementation of the
changeFrom function, their is a call to a GeoIntegralProperty::getGLId()
(line 165) that can not be replaced with my schema since
getOsgGLId()/getOglGLId() are unknown here.

Do you have an idea how I should implement this reasonably?

Best,
Johannes

P.S.: I also have the ShaderStorageBufferObjRef finished. This does not
have any unclear issues. But since I was recently forced to introduce a
common base class for the ShaderStorageBufferObj chunk classes and one
for the UniformBufferObj chunk classes, I will send them separately.
This ssbo/ubo patch exceeds the 200kB limit of the mailing list and
therefore I allow me to send this patch directly to Carsten. Hope that
this is fine for you.
Johannes
2017-05-23 05:46:18 UTC
Permalink
ping...

Carsten Neumann
2017-05-16 19:53:57 UTC
Permalink
Hello Johannes,
Post by Johannes
Post by Carsten Neumann
- For OSGComputeShaderAlgorithm is it possible to combine the
useMemoryBarrier and memoryBarrier fields, i.e. if memoryBarrier
is GL_NONE that means no memory barrier? That would allow
controlling the barrier with a single field instead of requiring
the setting of two.
Hmm, I don't think so. GL_NONE is not a valid (better listed of allowed)
parameters to the glMemoryBarrier API. I wouldn't try this.
sorry, I did not explain this in enough detail. I meant to use GL_NONE
as a special value that guards the call to glMemoryBarrier, i.e.

if(_sfMemoryBarrier.getValue() != GL_NONE)
glMemoryBarrier(_sfMemoryBarrier.getValue());

Please see the attached patch for details.

This also matches what we do for the face culling mode where GL requires
a glEnable(GL_CULL_FACE) call and glCullFace(GL_BACK) call, but there is
only a single field. If it has a value that is valid for glCullFace() we
issue the glEnable and glCullFace calls otherwise we call glDisable (see
PolygonChunk).

Cheers,
Carsten
Johannes
2017-05-17 04:28:04 UTC
Permalink
Hello Carsten,
Post by Carsten Neumann
sorry, I did not explain this in enough detail. I meant to use GL_NONE
as a special value that guards the call to glMemoryBarrier, i.e.
if(_sfMemoryBarrier.getValue() != GL_NONE)
glMemoryBarrier(_sfMemoryBarrier.getValue());
Please see the attached patch for details.
Yes, your are right, I did not pay enough attention. I'm fine with your
suggestion. We should do it that way.

Thank you.

Best
Johannes
Loading...