Advertisement

Generic buffer class

Started by February 04, 2015 04:18 PM
6 comments, last by Irlan Robson 9 years, 11 months ago

I'm making XNA-like OpenGL wrapper. And I have some problems with it's design. Should I come up with generic buffer class? What fields and methods should it have?

My first approach:


class Buffer
{

public:

 Buffer(/* possible parameters */);

 ~Buffer();

 unsigned char* map();

 void unmap();

 //possible getters

 (...)
 
private: 

 GLuint bindingPoint;
 GLuint capacity;
 GLuint actualSize;
 GLuint id;
 GLuint usage;
 
}

so, which fields would be preferable? Should I do generic buffer, or it would be correct to do single classes for vertex buffes/other possible buffers? Do I really need this overhead?

Sorry for my English.

What do you want this buffer to represent? That determines the answer to all of your questions, really, and you haven't provided that information.

Advertisement


My first approach:
class Buffer
{

public:

Buffer(/* possible parameters */);

~Buffer();

unsigned char* map();

void unmap();

//possible getters

(...)

private:

GLuint bindingPoint;
GLuint capacity;
GLuint actualSize;
GLuint id;
GLuint usage;

}
so, which fields would be preferable?
Looks like you're trying to wrap around a uniform/constant buffer (saw a binding point there). Rename it to UniformBuffer instead of buffer (a buffer is a vague term).
For this simple responsability you can try using a function such:
void Update( void* data, unsigned int size, unsigned int index )
and mapping/un-mapping (in the case of DirectX using ::memcpy(...) ).


Should I do generic buffer, or it would be correct to do single classes for vertex buffes/other possible buffers? Do I really need this overhead?
You should have classes for vertex buffers, index buffers, constant buffers, and whatever is considered a resource.
Each resource has one single responsability, and it doesn't make sense to abstract everything into a single buffer class.

What do you want this buffer to represent? That determines the answer to all of your questions, really, and you haven't provided that information.

well, nothing special. Likely I will need buffers for vertices, indexes, some per-instance data and transform feedback manipulations. I just want to hide such means as glGenBuffers,glBindBuffer,glBufferData and other. In fact, I dont need full Opengl's functionality in this thing as well. Just think if it possible to make such operations more simple and safe.

Sorry for my English.

You can generally consider vertex and index buffers the same "thing" and represent them by the same type (this is what D3D does). However you can also make them a distinct type to add an additional layer of type safety in your API (so you cannot ever "accidentally" set a vertex buffer resource where an index buffer resource is required) if you like. It's up to you. I prefer the first approach.


well, nothing special. Likely I will need buffers for vertices, indexes, some per-instance data and transform feedback manipulations. I just want to hide such means as glGenBuffers,glBindBuffer,glBufferData and other. In fact, I dont need full Opengl's functionality in this thing as well. Just think if it possible to make such operations more simple and safe.

Encapsulating resources using classes is what should be done. Every engine uses this method not only for good object-oriented practices but also cross platform support.

When doing cross-platform support you have then:

Using the top-down approach:

class CVertexBuffer

class CDirectX12VertexBuffer : CVertexBuffer

class COpenGlVertexBuffer : CVertexBuffer

Bottom-up approach (defining at compile-time what API you're using):

class CDirectX12VertexBuffer

class COpenGlVertexBuffer

class CVertexBuffer : #ifdef USE_DIRECTX CDirectX12VertexBuffer #elif USE_OPENGL COpenGlVertexBuffer

Since you're not concerned with cross-platform I would recommend at least using a COpenGlVertexBuffer.

Generally it doesn't make sense creating a abstract class called "Buffer" for more intuitive that looks like. The API already does this (OpenGL with BOs and DirectX with buffers), so your job it is only translate it to a manageable software-side interface.

Advertisement

Encapsulating resources using classes is what should be done. Every engine uses this method not only for good object-oriented practices but also cross platform support.

Not necessarily "every engine"... A thin wrapper like the one discussed here so far just puts some inconvenient things away and yes, it provides some type safety, at least for OpenGL. However, it does not help with the IMHO more relevant aspect of how to deal with the buffers. Buffer management within OpenGL 3.3 is different from OpenGL 4.4 and probably different from OpenGL 5.x, just to stay with OpenGL.

IMHO abstracted GPU resource management for cross platform support should give an API that is almost as generic as "reserve vertex memory for this array of groups of attributes with their respective usage pattern, with a capacity for 5000 vertexes", resulting in a handle for further use. When it comes to rendering a frame, an instance of (multi-buffered) GraphicFrameContext is granted. For vertex attribute groups with usage pattern "update frame-by-frame" the GraphicFrameContext holds an array of memory accessors (byte pointer, stride, size, you know that stuff) and the aforementioned handle is used to fetch the accessor of interest. Further, the GraphicFrameContext provides a pool of buffers that allow to transfer data of vertex attribute groups with usage patterns "changes seldom" and "changes virtually never". The accessors to such buffered memory are fetched from the pool and enqueued, together with the handle which denotes where the data should be copied to. When rendering (on this level) is done, the GraphicFrameContext instance is committed and rendering on the low-level starts.

So its totally up to the implementation how it realizes buffer management. An OpenGL 4.4 based implementation will use persistent mapping, one based on OpenGL 3.3 may use unsynchronized mapping (or glBufferSubData, or whatever). For a transfer buffer they may give a CPU memory block or an OpenGL buffered memory block.

In other words: I do not have a buffer class at all, at least no public one.

Just my 2 cents


Not necessarily "every engine"... A thin wrapper like the one discussed here so far just puts some inconvenient things away and yes, it provides some type safety, at least for OpenGL. However, it does not help with the IMHO more relevant aspect of how to deal with the buffers. Buffer management within OpenGL 3.3 is different from OpenGL 4.4 and probably different from OpenGL 5.x, just to stay with OpenGL.

IMHO abstracted GPU resource management for cross platform support should give an API that is almost as generic as "reserve vertex memory for this array of groups of attributes with their respective usage pattern, with a capacity for 5000 vertexes", resulting in a handle for further use. When it comes to rendering a frame, an instance of (multi-buffered) GraphicFrameContext is granted. For vertex attribute groups with usage pattern "update frame-by-frame" the GraphicFrameContext holds an array of memory accessors (byte pointer, stride, size, you know that stuff) and the aforementioned handle is used to fetch the accessor of interest. Further, the GraphicFrameContext provides a pool of buffers that allow to transfer data of vertex attribute groups with usage patterns "changes seldom" and "changes virtually never". The accessors to such buffered memory are fetched from the pool and enqueued, together with the handle which denotes where the data should be copied to. When rendering (on this level) is done, the GraphicFrameContext instance is committed and rendering on the low-level starts.

So its totally up to the implementation how it realizes buffer management. An OpenGL 4.4 based implementation will use persistent mapping, one based on OpenGL 3.3 may use unsynchronized mapping (or glBufferSubData, or whatever). For a transfer buffer they may give a CPU memory block or an OpenGL buffered memory block.

In other words: I do not have a buffer class at all, at least no public one.

Just my 2 cents

Yeah... he might consider it if it needs to meet more complex needs in newer versions of OpenGL.
For simple tasks such as abstraction of a resource buffer it may also want to consider only the encapsulation, so... the OP review your needs.

This topic is closed to new replies.

Advertisement