Intro :
This thread is a branch from my GSoC project thread, because I think its a discussion that needs to happen regardless of my project's progress. If we do manage to agree on a solution soon enough, I will implement it as part of my SoC project.
Render to buffer is the (self-invented) name of the feature called Stream-Out in DirectX10 and Transform-Feedback in OpenGL. It essentially allows the user to run the vertex and geometry shading pipeline, saving the results back to a buffer instead of sending them to the rasterisation pipeline.
Many uses of geometry shaders use this feature as well, which is why I think its a good idea to add it to my SoC schedule.
How should this be implemented into ogre ?
Render-to-buffer API
The first thing I considered was to have a new subclass of Ogre::RenderTarget called Ogre::RenderBuffer. I quickly discarded this idea because the API has many irrelevant requirements and it is not really a render target (doesn't contain viewports and such).
In fact, there is pretty much a 1-to-1 relationship between a renderable (vertex+index buffer) to a render buffer target.
In a way, I can see this feature being someone parallel to the animation framework in a way - it updates the vertex & index data of an object every frame before the rendering takes place, and is often sequential.
There are two conceptual main modes of operation that we need to support :
1) Reset-every-frame mode. SrcBuffer + Shader = DstBuffer. SrcBuffer is used as the source next frame.
2) State-machine-ish mode. SrcBuffer + Shader = DstBuffer. DstBuffer is used as the source next frame.
The biggest question I'm asking myself is how generic should this be.
None-generic solution (but less obtrusive)
Theoretically, we can have a class that is a proxy Ogre::Renderable - it receives an Ogre::Renderable as input, and also implements Ogre::Renderable itself. When getRenderOperation is called, it will return the transformed buffers rather than the originals. It will have update() and reset() methods, which will update the destination buffers and return them to their original states, respectively.
These methods will either be triggered manually (by a framelistener in beginFrame, for example) or automatically (which will mean that a singleton that keeps track of all the render-buffers has to exist and called every frame). I believe that the animation framework in ogre operates in similar matter.
Of course, a boolean resetEveryFrame flag can be used to easily distinguish between the conceptual modes of operation that i stated earlier.
The problem with this mode is that you need to write quite a bit of code in order to use it. Who places the proxy renderable in the scene graph instead of the normal one? You will need to subclass MovableObject for object types (for example, ProceduralBillboardSet would be required for the ParticleGS sample) for each object type that uses this feature.
Generic solution (but more obtrusive)
This solution is similar to the first solution, but with a big difference.
Instead of the proxy Ogre::Renderable, one of the generic ogre classes (I'm thinking about Ogre::MovableObject, but Ogre::Renderable might also be a possibility) will handle the RenderBuffer functionality. Then, for every MovableObject (entity, billboard set, etc) you will be able to set a RenderBufferGeometry material (via a setRenderBufferGeometry call, along with setResetProceduralGeometryEveryFrame, resetRenderBufferGeometry, setRenderBufferGeometryAutoUpdates etc), and it will take care of the rest.
This will allow us to easily integrate geometry-generating materials without adding MovableObject-specific code (think of the wonders it can to do Ogre::ManualObject - lots of the math that generates the geometry can be shaderized).
However, it is very obtrusive (Ogre::MovableObject is a core class in Ogre) and raises some questions with some MovableObjects (ie, what happens to the render-to-buffer geometry when the MovableObject decides to internally regenerate its vertex & index buffers?)
I believe that the none-obtrusive solution is the better one, and MovableObject types that can use this feature (BillboardSet and ManualObject are the first two that come to mind for me) will implement related functionality.
What do you guys think?
Adding Render-To-Buffer support
-
- OGRE Retired Team Member
- Posts: 714
- Joined: Mon Jan 31, 2005 7:21 pm
- Location: Israel
- x 2
-
- OGRE Retired Team Member
- Posts: 714
- Joined: Mon Jan 31, 2005 7:21 pm
- Location: Israel
- x 2
(tuan's reply)
tuan kuranes wrote:DX10 sort of promoted a concept of 'casting' buffer type (called 'texture view'), GL does that with "Texture Buffer Object" I believe.In fact, there is pretty much a 1-to-1 relationship between a renderable (vertex+index buffer) to a render buffer target.
Idea being to prevent user having to copy results from one buffer to another 'pre-casted'.
So conceptually, Ogre should be able to reflect that somehow.
Perhaps current RenderTarget should be renamed more explicitly "FrameRenderTarget" and new one added would be "RenderBufferView", both referencing/using/encapsulating a RenderBuffer, which would reflect that 'typeless buffer' idea ?
Generic solution seems the way to go to me.Generic solution (but more obtrusive)
Could 'geometry_buffers on/off' or 'initial buffer on/off' be a parameter of material pass, so that user can specify things on a per-pass basis ?
Best would be to somewhat extend/copy/achieve something like the 'compositor' scripting flexibility. (could be renamed "Frame Compositor" and "Geometry Compositor")
Last edited by Noman on Mon Jun 30, 2008 5:28 pm, edited 1 time in total.
-
- OGRE Retired Team Member
- Posts: 714
- Joined: Mon Jan 31, 2005 7:21 pm
- Location: Israel
- x 2
I think you misunderstood part of my post. Buffer 'casting' is irrelevant here. The render-to-buffer technique outputs vertex and index buffers. No need to cast between different types of buffers.
I don't think we should go anywhere near these features in this SoC (Ogre in general can, just not here).
As for the two solutions. I'm not saying that I like the less generic solution because its an easier way out, I just think that the generic one has many pitfalls.
I understand why you compare this feature to the compositor framework, but I disagree. While API-wise this feature is something that you can add to any vertex+index buffer combination, logically speaking there is a tighter coupling between the shader and the vertex+index data that it will run on.
This is what differs between the RenderToBuffer feature and the compositor framework IMO. In most cases, compositors can be written regardless of the scenes they are compositing. Most of Ogre's sample compositors can be applied to everyday applications and work as expected out of the box. If I apply the vertex+geometry shader from the particleGS sample to an entity, I'll get garbage! I believe that this is the normal case in the render-to-buffer world.
This is the main reason that I think that RenderToBuffer shouldn't be part of Ogre::Renderable or Ogre::MovableObject, but a facility that the subclassers of those two classes can use if needed. Perhaps classes like Ogre::BillboardSet will have an out-of-the-box option to use a RenderToBuffer material (or perhaps a new, simpler object type that only contains a vertex and geometry shader), but should Ogre::Entity have this option? What will happen when software blending updates the vertex buffer?
I'm not making decisions yet, just debating...
I don't think we should go anywhere near these features in this SoC (Ogre in general can, just not here).
As for the two solutions. I'm not saying that I like the less generic solution because its an easier way out, I just think that the generic one has many pitfalls.
I understand why you compare this feature to the compositor framework, but I disagree. While API-wise this feature is something that you can add to any vertex+index buffer combination, logically speaking there is a tighter coupling between the shader and the vertex+index data that it will run on.
This is what differs between the RenderToBuffer feature and the compositor framework IMO. In most cases, compositors can be written regardless of the scenes they are compositing. Most of Ogre's sample compositors can be applied to everyday applications and work as expected out of the box. If I apply the vertex+geometry shader from the particleGS sample to an entity, I'll get garbage! I believe that this is the normal case in the render-to-buffer world.
This is the main reason that I think that RenderToBuffer shouldn't be part of Ogre::Renderable or Ogre::MovableObject, but a facility that the subclassers of those two classes can use if needed. Perhaps classes like Ogre::BillboardSet will have an out-of-the-box option to use a RenderToBuffer material (or perhaps a new, simpler object type that only contains a vertex and geometry shader), but should Ogre::Entity have this option? What will happen when software blending updates the vertex buffer?
I'm not making decisions yet, just debating...
-
- OGRE Retired Team Member
- Posts: 714
- Joined: Mon Jan 31, 2005 7:21 pm
- Location: Israel
- x 2
(tuan's second reply)
tuan kuranes wrote:The render-to-buffer technique outputs vertex and index buffers. No need to cast between different types of buffers.
Idea of my remarks was more about understanding the why of 'texture view', 'typeless buffer' and all... and therefore make sure to have that in mind when thinking of design.
Like ShadowGS or catmull-clarck mesh subdivision GS works for any mesh...compositors can be written regardless of the scenes
Same if you use compositor that does "deffered rendering" and waits for a "normal buffer" or a "depth buffer" as inputs...If I apply the vertex+geometry shader from the particleGS sample to an entity, I'll get garbage!
GS are at its early stage, we lack samples application...I believe that this is the normal case in the render-to-buffer world.
I even would go deeper and add that to 'VertexData' class, and using material current pass option (like I stated above), the renderer would choose at render time between "VertexData" internal Vertex Buffers. (initial or generated.)This is the main reason that I think that RenderToBuffer shouldn't be part of Ogre::Renderable or Ogre::MovableObject, but a facility that the subclassers of those two classes can use if needed.
-
- Ogre Magi
- Posts: 1137
- Joined: Mon May 07, 2007 3:43 am
- Location: Ossining, New York
- x 13
I vaguely understand why geometry shaders are useful, but this new thing eludes me somewhat. Please help me understand 
It seems there are two reasons for pulling out the result of the vert+geo pipeline. Either you want to use that data in software, or you want to avoid recomputing it. I'm not sure how resetting/accumulating i.e. basically recalculating every frame is going to help there. Recalculating every frame is surely the behaviour you get without render-to-buffer.
Maybe if you really want accumulation and the shader can't always compute "from zero" every time, then you'd want to cache those results and plug them as inputs the next time? How rare is this situation? It seems it might get unstable after a while, as errors build up and propogate.

It seems there are two reasons for pulling out the result of the vert+geo pipeline. Either you want to use that data in software, or you want to avoid recomputing it. I'm not sure how resetting/accumulating i.e. basically recalculating every frame is going to help there. Recalculating every frame is surely the behaviour you get without render-to-buffer.
Maybe if you really want accumulation and the shader can't always compute "from zero" every time, then you'd want to cache those results and plug them as inputs the next time? How rare is this situation? It seems it might get unstable after a while, as errors build up and propogate.
-
- Gnoll
- Posts: 677
- Joined: Tue Sep 19, 2006 6:09 pm
- x 5
I think that this feature is geometry shaders' most interesting one, at least from what i have understood.sparkprime wrote:I vaguely understand why geometry shaders are useful, but this new thing eludes me somewhat. Please help me understand
It seems there are two reasons for pulling out the result of the vert+geo pipeline. Either you want to use that data in software, or you want to avoid recomputing it. I'm not sure how resetting/accumulating i.e. basically recalculating every frame is going to help there. Recalculating every frame is surely the behaviour you get without render-to-buffer.
Maybe if you really want accumulation and the shader can't always compute "from zero" every time, then you'd want to cache those results and plug them as inputs the next time? How rare is this situation? It seems it might get unstable after a while, as errors build up and propogate.
Correct me if i'm wrong, but for example for a wall mesh, I can pass forces to a geometry shader, compute the break points, and build the fragment meshes...
Render To Buffer is useful at this point: you outstream the fragment meshes, so you can save them on host memory as normal meshes.
This would allow realtime destruction of any generic mesh, if i'm correct.

EDIT (i posted but i hadn't time to edit before

From an user standpoint I think that the general approach is the best one... for one because this way the RT can be "scripted", without per-entity C++ work.
Another reason is that we all know that when a feature is "attached" and is isolated from the rest of the architecture, it will never be used/supported extensively.
I can think to many examples:
-MultiRenderTarget, works very well but lacks in integration with the other render components;
-Vertex Texture Indexing, that is cross-platform incoherent because of Nvidia/Ati & DX/GL differences;
-ATI's tesselation units, that are so specifical that aren't even represented in Ogre...
Each one could be really useful, but the lack of integration with the other components and thus the difficult support, forces always to look for other methods.
Instead, if the render-to-buffer could be coherently integrated by ogre, just like render-to-texture, i think that it would be way easier to use, and would be much more widespread in applications.

Anyway it's true that now, no game uses even a Geometry Shader, to not speak of Stream-Out... and this makes really difficult to foresee the right general approach.
Last edited by _tommo_ on Tue Jul 01, 2008 7:31 pm, edited 2 times in total.
-
- OGRE Retired Team Member
- Posts: 19269
- Joined: Sun Oct 06, 2002 11:19 pm
- Location: Guernsey, Channel Islands
- x 66
I was wondering whether this was going to come up 
I agree with the non-obtrusive scenario initially. I think there will be potential for a more unified approach later on, but it's quite early days for this yet and an isolated utility class for the moment will be the best route to go. As more specific usage scenarios make themselves clearer, we could start integrating the functionality more but that would probably be premature right now.
I support tuan's thoughts on keeping in mind the more general cases, such as reinterpreting GPU buffers (of any kind). I've seen a couple of examples of this but they were extremely specific, and I couldn't really see how to make that kind of functionality generic at the time. I still think your non-obtrusive approach is right as a first step into this kind of functionality since it will enable a class of functionality we can't do right now, without getting it's tentacles too deep until we know more.

I agree with the non-obtrusive scenario initially. I think there will be potential for a more unified approach later on, but it's quite early days for this yet and an isolated utility class for the moment will be the best route to go. As more specific usage scenarios make themselves clearer, we could start integrating the functionality more but that would probably be premature right now.
I support tuan's thoughts on keeping in mind the more general cases, such as reinterpreting GPU buffers (of any kind). I've seen a couple of examples of this but they were extremely specific, and I couldn't really see how to make that kind of functionality generic at the time. I still think your non-obtrusive approach is right as a first step into this kind of functionality since it will enable a class of functionality we can't do right now, without getting it's tentacles too deep until we know more.
-
- OGRE Retired Team Member
- Posts: 714
- Joined: Mon Jan 31, 2005 7:21 pm
- Location: Israel
- x 2
I was away for a week (Rock Werchter 2008 festival!!!) so I didn't get a chance to reply.
I think I'll go for the none-obtrusive approach. It seems to be less dangerous.
I REALLY want to go for it in this summer of code, I personally think that its more important than the still-unimplemented extras (even more than the DX10 support) because geometry shaders are limited without this functionality.
I'll probably start designing this in-depth once I finish with the IsoSurf demo and midterm evaluation.
I think I'll go for the none-obtrusive approach. It seems to be less dangerous.
I REALLY want to go for it in this summer of code, I personally think that its more important than the still-unimplemented extras (even more than the DX10 support) because geometry shaders are limited without this functionality.
I'll probably start designing this in-depth once I finish with the IsoSurf demo and midterm evaluation.
-
- OGRE Retired Team Member
- Posts: 714
- Joined: Mon Jan 31, 2005 7:21 pm
- Location: Israel
- x 2
Alright.
I'm going for it. Decided to go for the none-obtrusive solution first (sorry quan) because we really don't know how people will use it from scripts.
I think the class will subclass Ogre::Renderable, and it will have a source renderable as well (thus, it serves as a sort of proxy)
The API I'm thinking of is :
Along with that, a manager will also need to be created, in order to do two tasks :
A) Render-system specific creation of RenderToBufferObjects (similar to GpuPrograms)
B) Keep track of all the created RenderToBufferObjects in order to be able to update the automatically updated onces when the scene manager requests it.
In order to use this class, a MovableObject will expose a setRenderToBufferMaterialName, and if its not empty, it will keep a RenderToBufferObject and will render to it, and when updateRenderQueue is called it will add that object instead of its normal renderable.
At this first stage this functionality will be added into specific MovableObjects. At a later stage, perhaps this will be generalized.
What do you guys think?
I'm going for it. Decided to go for the none-obtrusive solution first (sorry quan) because we really don't know how people will use it from scripts.
I think the class will subclass Ogre::Renderable, and it will have a source renderable as well (thus, it serves as a sort of proxy)
The API I'm thinking of is :
Code: Select all
class RenderToBufferObject : public Ogre::Renderable
{
public:
RenderToBufferObject(Ogre::Renderable* sourceRenderable);
getAutoUpdates();
setAutoUpdates(bool autoUpdates);
update();
getRenderToBufferMaterial();
setRenderToBufferMaterialName(const Ogre::String& materialName);
//Ogre::Renderable implementation...
}
A) Render-system specific creation of RenderToBufferObjects (similar to GpuPrograms)
B) Keep track of all the created RenderToBufferObjects in order to be able to update the automatically updated onces when the scene manager requests it.
In order to use this class, a MovableObject will expose a setRenderToBufferMaterialName, and if its not empty, it will keep a RenderToBufferObject and will render to it, and when updateRenderQueue is called it will add that object instead of its normal renderable.
At this first stage this functionality will be added into specific MovableObjects. At a later stage, perhaps this will be generalized.
What do you guys think?
-
- OGRE Retired Team Member
- Posts: 714
- Joined: Mon Jan 31, 2005 7:21 pm
- Location: Israel
- x 2
Since I decided to work on this feature, discussion about it has been moved back to the Geometry shader SoC thread. Flame away! =)