Vertex buffers and other objects

Discuss about anything related to the Irrlicht Engine, or read announcements about any significant features or usage changes.
EmmanuelD
Posts: 25
Joined: Thu Aug 24, 2006 8:34 am
Location: Right in front of Dagoth Ur
Contact:

Post by EmmanuelD »

hybrid wrote: My plans for the next version are (besides FSAA and bugfixing) the additional geometry render methods (quads, triangle strips, lines, etc.) and thereby also rewriting the s3dvertex interface and integrating IIndexBuffer for 32bit indices from IrrSpintz. Though this is not for sure to be done until 1.2 :wink: Ah, and spot lights :!:

Any other requests or plans?
Speaking of IIndexBuffer, the team I work for really need them (as well as vertex buffer objects too). Initially, we planed an irrlicht fork but I don't think this is a very good idea, and I'd prefer to see them in the irrlicht base code. I wrote an proposal (draft) to see what should be needed to support this feature, and I was about to post it there in a few days. the proposal tries to limit the interface change to a minimum, and I believe I succeeded well since the resulting code should be source compatible with the current irrlicht version. I still have some work to do on it, but I'll post the current version of the proposal in this thread tomorrow (I just forgot to bring it with me today - damn USB stick, you are too small).

Regards,
-- Emmanuel D.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Yeah, sounds great. IIndexBuffers in their current state do not support hardware index buffers, though. So I'd really like to hear about your solution.
EmmanuelD
Posts: 25
Joined: Thu Aug 24, 2006 8:34 am
Location: Right in front of Dagoth Ur
Contact:

Post by EmmanuelD »

hybrid wrote:Yeah, sounds great. IIndexBuffers in their current state do not support hardware index buffers, though. So I'd really like to hear about your solution.
This is only a draft, and it lacks some specifications about the vertex buffers. Here is the pdf clicky linky: http://members.gamedev.net/emmanuel_del ... bjects.pdf. Note that this draft also lack information about how it should be done - it only present the interface changes.

The whole idea is quite logical: let the video driver create the index/vertex buffer objet, so that each video diver implements his specialized, hardware supported buffer object (I guess the version you are working on is using the same solution). Although it is not documented in the draft yet, the other idea is to implement a lock/unlock mechanism (just as it is done for textures - I tried to be consistent with the current API). The interface can be used to create 16 bit or 32 bits index buffers, and is only restricted by the underlying driver when it comes to vertex buffers (although this is not explained in the pdf yet - I implemented a similar mechanism in an older 3D engine, so redoing it will not be difficult). The capability enum (queryFeature()) have to be extended to support the new fonctionalities, and the driver might need to support more than 4 textures (we use more than 4 textures in our implementation). Also, not that I want to give to the programmer the responsability of chosing the right usage (in the opengl meaning) for the created buffer. This will allow him to optimize his buffer throughput by carefully chosing where to put the data (system memory, AGP, ...).

The vertex description being completely free, it is up to the driver to verify if it can be used (for example, DX8 might want to match the vertex descriptin to a FVF), meaning that irrlicht will no longer be limited to the current set of vertex types - a good thing IMHO since it will allow it to go one step further in the shader-based effects.

I'm planning the implementation - I will probably begin it in a few days, if I'm able to finish my current tasks.

There is an obvious error in the document - I stupidly states that DX8 only supports FVF vertex buffers, which is false. I simply didn't had all my mind when I wrote this (you know: tired, 80h per week and so on). There are also some typo (Word is still unable to underand everything, and my english is often quite approximative).

The main reason why I wanted to post this here is that I really want some feedback before I (we? not sure I wil do this, but if I don't then someone else at Winterdyne will) begin to implement this. Even if it is not completed, it still gives a good idea of what I'm planning to do (I have other planed irrlicht changes - mostly in the UI management: the infamous isVisible() problem in the menu is rally bugging me, and the lack of proper support for a window/dialog based event handling is quite embarrassing when you want to make something complex. I'll think to these problems later :)). I'll post a more complete document (with UML diagrams - I love them :)) when I'll begin to work on the subject.

Regards,
-- Emmanuel D.
EmmanuelD
Posts: 25
Joined: Thu Aug 24, 2006 8:34 am
Location: Right in front of Dagoth Ur
Contact:

Post by EmmanuelD »

Just to make sure: I will start the development of my buffer object solution next week, so if you have any comment, I welcome them (see the link to the pdf draft in my previous posts).

Regards,
-- Emmanuel D.
Saturn
Posts: 418
Joined: Mon Sep 25, 2006 5:58 pm

Post by Saturn »

EmmanuelD, I read your proposal and have a few comments.

The smallest of these: What's the name in the add-function for? I don't believe vertex/index buffers need to be handled by name in Irrlicht, this should be removed. If an application needs to track those by name, it can easily do the mapping itself.

You don't mention IUnknown, I take it the buffers are derived from it?

On to the beef:
E_VERTEX_TYPE should contain additional members: EVT_VB_FIXED,
EVT_VB_DESCRIPTOR.
I beg to differ. E_VERTEX_TYPE doesn't need yet more members, so that all the alway-the-same switch-statements are amended with yet two more cases. I believe that you should get rid of E_VERTEX_TYPE altogether. And instead of having now three, then five different mesh buffer interfaces, only one is needed and that should be flexible and comfortable enough.

The driver returns some IVertexBuffer/IIndexBuffer pointer. The client program doesn't need to care, whether this is really a hardware vertex buffer or not. Thus instead of failing, the function could fallback to a simple memory buffer. Then the drawVertexBuffer function would use the same way of rendering as done now by drawMeshBuffer()

The E_VERTEX_TYPE types can be used to create preconfigured vertex declarations maybe, but else they should be removed.

Also your proposal leaves the interesting part of how the vertex declaration shall look like out completely, and it doesn't tell anything about the interfaces of the newly introduced types. So commenting these is not really possible, eventhough this is an important part. It needs to be easy to use, but still flexible.

How do I write to the buffer and read from it? How do I access a certain element of vertex? How do I determine the size of a vertex, the size of an element? (2D/3D position, 1D/2D/3D texcoords, etc...) Is it allowed and possible to have gaps in between vertices, to maximize the usefulness of the vertex cache?

All this is not answered.

All in all, I don't believe a solution that would clutter the irrlicht interface is wanted, what I prefer is an integrating interface change, that smoothly encompasses what now is IMeshBuffer and the new hardware buffers. Ideally without forcing the client program *and* as far as possible irrlicht itself to distinguish between these two.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

(I have split these posting into a new thread to avoid messing the other thread too much)
I am a little short on time currently, but I've downloaded it already and will try to respond in the next days.
But the less changes to the API are necessary the better for the solution. Ease of use is the major target for Irrlicht. The vertex types are simply a trade-off between space requirements and speed which is both important for real-time rendering.
Also index buffers are really not that easy to assess. I just read the nvidia recommendations which propose to use 16bit buffers. So instead of adding the new IIndexBuffer I am currently thinking about fixing loaders and generators to better work with 16bit indices.
EmmanuelD
Posts: 25
Joined: Thu Aug 24, 2006 8:34 am
Location: Right in front of Dagoth Ur
Contact:

Post by EmmanuelD »

Saturn wrote:EmmanuelD, I read your proposal and have a few comments.

The smallest of these: What's the name in the add-function for? I don't believe vertex/index buffers need to be handled by name in Irrlicht, this should be removed. If an application needs to track those by name, it can easily do the mapping itself.
This was a late addition to the proposal. I mainly wanted to replicate the texture creation interface in order to make things consistent. If I remove the name then the buffer objects will be the only non-queryable resources in the software (as every other object can be fetched from its manager). But this is not a very important point, and in fact I don't see any problem in removing the name.
Saturn wrote: You don't mention IUnknown, I take it the buffers are derived from it?
Yep. IUnknown is the root of all Irrlicht, there's no reason why the new classes should nto inherit from this class.
Saturn wrote: On to the beef:
E_VERTEX_TYPE should contain additional members: EVT_VB_FIXED,
EVT_VB_DESCRIPTOR.
I beg to differ. E_VERTEX_TYPE doesn't need yet more members, so that all the alway-the-same switch-statements are amended with yet two more cases. I believe that you should get rid of E_VERTEX_TYPE altogether. And instead of having now three, then five different mesh buffer interfaces, only one is needed and that should be flexible and comfortable enough.
Problem is that we need to differentiate with the current vertex type. I'd also like to get rid of E_VERTEX_TYPE but this can't be done without changing the current Irrlicht interface (let's do that for 2.0 if it is really needed).
Saturn wrote: The driver returns some IVertexBuffer/IIndexBuffer pointer. The client program doesn't need to care, whether this is really a hardware vertex buffer or not. Thus instead of failing, the function could fallback to a simple memory buffer. Then the drawVertexBuffer function would use the same way of rendering as done now by drawMeshBuffer()
Here, we have different opinions on the subject. If I specify a default ussage then it probably mean that I don't care abouthow the buffer is managed. But if I specify any other usage then it means that I really want this buffer to be managed in a particular way? Silently changing the usage to application memoey simply don't fit the bill IMHO. Moreover, it can fail because the hardware is unable to do something with it. There is no point in creating a vertex buffer object that can't be supported by the driver at all (for example, putting two position vector in the same vertex buffer).
Saturn wrote: The E_VERTEX_TYPE types can be used to create preconfigured vertex declarations maybe, but else they should be removed.
I'd see what I can do with this in mind.
Saturn wrote: Also your proposal leaves the interesting part of how the vertex declaration shall look like out completely, and it doesn't tell anything about the interfaces of the newly introduced types. So commenting these is not really possible, eventhough this is an important part. It needs to be easy to use, but still flexible.
It can't be both, unfortunately, although some standard vertex descriptors can be built in Irrlicht to ease their creation.

Basically, the system works like the vertex declarators of DX9: a list of dword describes the vertex streams (yes, there's an 's' here). I'll postpone my implementation in order to write a v0.4 of the draft to explain all these (and to take your comments into account).
Saturn wrote: How do I write to the buffer and read from it? How do I access a certain element of vertex? How do I determine the size of a vertex, the size of an element? (2D/3D position, 1D/2D/3D texcoords, etc...) Is it allowed and possible to have gaps in between vertices, to maximize the usefulness of the vertex cache?
You typically access the BO data by using lock/unlock. Accessing a particular element of the vertex needs you to know its position. You can either cast the lock() result to a known vertex structure or use a more complex class that will be able to interpret the vertex descriptor and do the job for you. Unfortunately, this class can't be in the irrlicht dll for efficiency reason (if one of the function returns a position vector, the user have no way to know what is the offset to the next position vector, except by doing some nasty pointer math - this should be done by the proxy class, and it can't be done in a virtual function for obvious reasons).

Vertex and element size can be computed from the vertex descriptor itself.

The vertex descriptor can allow gaps, but it is up to the driver to allow them or not. Actually, in my idea, the vertex descriptor can be used to describe a vertex made of one or more vertex streams. It is flexible, but not that easy to handle (although it is not utterly difficult to understand IMHO).
Saturn wrote: All this is not answered.
I'll try to answer all these questions in the next draft.
Saturn wrote: All in all, I don't believe a solution that would clutter the irrlicht interface is wanted, what I prefer is an integrating interface change, that smoothly encompasses what now is IMeshBuffer and the new hardware buffers. Ideally without forcing the client program *and* as far as possible irrlicht itself to distinguish between these two.
If I understand this statement correctly, this would break the current irrlicht interface - something I wanted to avoid. I'll still try to see if something can be done with IMeshBuffer.

Thanks for your comments. They are noted, and I'll take them into account.
-- Emmanuel D.
EmmanuelD
Posts: 25
Joined: Thu Aug 24, 2006 8:34 am
Location: Right in front of Dagoth Ur
Contact:

Post by EmmanuelD »

hybrid wrote:(I have split these posting into a new thread to avoid messing the other thread too much)
I am a little short on time currently, but I've downloaded it already and will try to respond in the next days.
But the less changes to the API are necessary the better for the solution. Ease of use is the major target for Irrlicht.
This is also my opinion. I don't want to break anything in the current irrlicht interface, nor I want to create an improbable beast that even Knuth couldn't understand :).
hybrid wrote: The vertex types are simply a trade-off between space requirements and speed which is both important for real-time rendering.
The vertex buffer object serves different purpose - namely, they address the need of more complex construction as well as hardware storage of the buffer. It is important IMHO that the two cohabits - doing something simple have to be simple. Doing something complex have be as simple as possible, but I can't say that it will be as simple as the current interface.
hybrid wrote: Also index buffers are really not that easy to assess. I just read the nvidia recommendations which propose to use 16bit buffers. So instead of adding the new IIndexBuffer I am currently thinking about fixing loaders and generators to better work with 16bit indices.
I'll read the nvidia recommandation (and I'll try to see if either intel or ATI released some similar material). 16 bit indices are of course better than 32 bit indices (twice less data to transform, and carefully generated indices list can help to keep a good vertex locality) but both have their use.
Thanks for the info :) (and thanks for splitting the thread: it is far easier to manage now :))

Regards,
-- Emmanuel D.
Saturn
Posts: 418
Joined: Mon Sep 25, 2006 5:58 pm

Post by Saturn »

EmmanuelD, thank you for your answers. :)

Indeed, all I said has to be seen in the context, that I don't see preservation of the current interface as a value per se. Don't get me wrong: I do understand that some see the need to preserve it and that the chances are higher to get this into Irrlicht, if it doesn't meddle too much with the interface as it is now.

I hope it is clearer now, why I proposed the fallback, since it only, as you mentioned, makes sense, when there is a single interface for hardware buffers and simple memory buffers. Of course, one could add bool force_hardware_buffers = false, as a default param to the addVertexBuffer function.

The current E_VERTEX_TYPE distinction and how it is implemented is hideous, IMHO. From an OO perspective there is a missing encapsulation. The user of the IMeshBuffer-interface to a meshbuffer object has to handle it differently depending on the implemented type of this object. This is a classic example for a missing encapsulation, with the disadvatages that come with it. Mainly, that extension is difficult to pull off. Since, when you add a new vertex type, you basically have to sift through all the client code and append cases to the switch statements, with virtually duplicated code, since you just have to cast to the new SVertex version. Duplicated code is bad, copy/pasting it is bad. Both are error prone and tedious.
It is thus a violation of the principle of ease-of-use as mentioned earlier.

If I have the need to meddle with the meshes vertices / indices myself, then I gladly prefer a pointer to the memory and informations of start, offset, skip and count of each vertex element *for all vertex types* rather than have to do this anyway in case this is a E_VB_DESCRIPTOR and do the casting for everything else.

Alternatively the client code can go by unchanged, and the user can pretend, that no change happend and ignore the new vertex types. But then Irrlicht were more or less forbidden to use it internally for the nodes created by the SceneManager, since could break client code. But when the client wants to react to the change, with the current proposal he ends up with more, harder to maintain, client code.

EmmanuelD, I agree, that this is a 2.0 change, but what is the gain for a half-assed (IMHO, no offense :)) solution up-front, over doing it right from the beginning. With your proposal we have yet another special case for yet another different reason. Irrlicht already has enough special cases that hinder ease-of-use in my sense of the word.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

The problem with IVertex is simply the concern of lots of additional virtual mthod calls that are introduced. Vertices and indices are the major hotspot for 3d applications which is why they are currently not virtualized. But the current setup definitely limits Irrlicht. I've currently abandoned several features which would require 3d texture coords as this would introduce another vertex type. Maybe it's time to work out some new interfaces and streamline the methods such that the actual overhead can be minimized.
EmmanuelD
Posts: 25
Joined: Thu Aug 24, 2006 8:34 am
Location: Right in front of Dagoth Ur
Contact:

Post by EmmanuelD »

Hello y'all,

I updated my proposal to v0.4 (find it here).

The old proposal still lies here: http://members.gamedev.net/emmanuel_del ... s.v0.3.pdf.

Change includes:
* suppression of the name parameter for addXXX() methods
* addition of a method to create a vertex buffer place holder (ie it doesn't create the underlying streams)
*interfaces for IIndexBuffer, IVertexBuffer
* addition of a new class: IVertexStream
* other cleanup in the document

I think that the design is simple enough. Basic vertex manipulation can be quite simple, but of course more advanced handling will be less easy. However, this is an advanced irrlicht feature that cohabits with the simpler current vertices management. If one wants to make something simple, he can still use the current interface.

One might note that I didn't described exactly how to build a vertex descriptor, but I made a clear reference to both the DX8 SDK and the DX9 SDK. The idea is to have an array of u32 where each element describes either a vertex element or a control structure (end of a stream, gap; end of the buffer is implicit but may also be added). A vertex element can be a position vector, a normal a texture coordinate, and so on. Each vertex descriptor element also define the size of the corresponding element (2D texcoord, 3D texcoord, ..). For example, a simple vertex should be described as:

Code: Select all

u32 desc[] = { position_3_float, normal_3_float, tex_2_float };
(Of course, the correct naming scheme has to be different from this fake one).

I think it lacks some kind of bindBuffer() function (maybe more than one). Such function should be able to setup the driver with the provided buffers, and subsequent calls to a corresponding rendering function would use these buffers. This would be an alternative rendering option that could speed up the whole thing if the user have to render a lot of similar objects.

I hope this second document makes things clearer. If you have any question or remarks, don't hesitate :)

Regards,
-- Emmanuel D.
Spintz
Posts: 1688
Joined: Thu Nov 04, 2004 3:25 pm

Post by Spintz »

Hardware index buffers are already supported in IrrSpintz. The difference is the ID for the buffer is not stored in the IIndexBuffer but in the mesh. A simple design change if needed.

What's the problem with the VertexBuffer / IndexBuffer implementation in IrrSpintz?

This all seems like overdesign to me.
Image
EmmanuelD
Posts: 25
Joined: Thu Aug 24, 2006 8:34 am
Location: Right in front of Dagoth Ur
Contact:

Post by EmmanuelD »

Spintz wrote:Hardware index buffers are already supported in IrrSpintz. The difference is the ID for the buffer is not stored in the IIndexBuffer but in the mesh. A simple design change if needed.

What's the problem with the VertexBuffer / IndexBuffer implementation in IrrSpintz?

This all seems like overdesign to me.
To be fair, I still have to give a look to IrrSpintz. I will do this today - I promise.

However, this is not really the index buffer implementation that I want to have (although it is still interesting), it is really the vertex buffer implementation - one that is flexible enough to allow us to do what we need (at WS). We do need to be able to define arbitrary vertex formats.

However, I'll study your implementation - sounds interesting.

Regards,
-- Emmanuel D.
EmmanuelD
Posts: 25
Joined: Thu Aug 24, 2006 8:34 am
Location: Right in front of Dagoth Ur
Contact:

Post by EmmanuelD »

I just gave a quick look to IrrSpintz, so I may be wrong in these conclusions (please feel free to correct me).

As of today, only the IIndexBuffer class is exposed to the public. This class is a standalone class that is not related to hardware index buffer, although it can be used to backup the hw index buffer (and it seems it is used in that way). However, it is still a pure software thingy.

Hardware index/vertex buffers are handled in the IMeshBuffer class, but are not exposed to the public. There is still no way to create a hw vertex buffer in IrrSpintz, except by loading a mesh.

Vertex buffer are restricted to the current irrlicht vertex types (although you modified the default type to provide access to 8 textures coords) and are not exposed to the user. They duplicate the software vertex buffer in a somewhat dangerous way - the software vertex buffer might be modified, but the hw buffer is not aware of this modification. To reflect user changes, one have to call some uploadMeshData() that will create new index and vertex buffers.

I do believe that exposing the vertex buffer and the index buffer to the user will allow you to implement more interesting effects. Of course, this is more complex than using a set of predefined vertex format, but in the using them is
* optional
* way more flexible
* and (I hope) faster.

I don't think that my solution is over-engineered. From a user perspective, there is 3 new classes and a bunch of functionsand the client code is not required to change. From an irrlicht hacker perspective, one have to implement 3 classes by driver (and maybe some other helpers).

I also strongly suspect that ib and flexible vb are the way to go (maybe my solution is not the best but at the end, Irrlicht will have to implement something similar, or it will be doomed to either being limited or having too much different vertex types).

I'm eagerly waiting for your comments :)
-- Emmanuel D.
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Maybe the public interface should indeed just use some simple vertex array and buffer properties instead of giving access to the full-blown hardware buffer mess. Each driver can then create the internal representation necessary. I'm not sure if there is a chance to make this somewhat performant and portable, but just exposing the D3D or OpenGL interface in the Irrlicht namespace should definitely by avoided.
Post Reply