How to make 2D OpenGL rendering efficient in C++ [closed] - c++

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I am working on a little project in C++ using OpenGL. I want to be able to render multiple 2D rectangles either in some color or with texture as efficiently as possible.
However, I am doing this in modern C++, so I am writing many wrappers over OpenGL API so that I have better logical structure, RAII, ...
In this spirit I wanted to create a class Rectangle, which would have a method draw() and this method would activate corresponding OpenGL context and call glDrawArrays(). This works fine, but then I realized, that if I wanted to render more rectangles, I would have to cycle through many instances. They would each switch context and I don't think this is an effective solution.
After a bit of thinking my solution was to create a Renderer object, which would hold a single VAO for all Rectangles, associated program, and huge buffer in which I would hold all coordinates for my objects (Rectangle instance would then be like a smarter pointer to this buffer) and then draw them all at once. Of course it would add me a lot of work with managing the buffer itself (adding/removing rectangles). Would it be better?
Also, do you have any tips what else should I focus on?

In general you want to minimize the number of drawing calls. Placing a lot of geometry data in a single buffer object and batching it all up into a single glDraw… call is definitely the way to go. The best way to go about this is to not think things drawn using OpenGL being individual objects (there is no spoon) but just patches of colour, which by happenstance appear to be rectangles, boxes, spheres, spoons…
A way to implement this using C++ idioms is to have a buffer object class, which internally manages chunks of data contained inside a buffer object. Keep in mind that buffer objects by themself are pretty much formless, and only by using them as a source for vertex attributes they get meaning. Then your individual rectangles would each allocate from such a buffer object instance; the instance in return could deliver the rectangle attributes' indices relative to a certain internal offset (what's passed to glVertexAttribPointer); it actually kind of makes sense to have a buffer object class, a object attribute view class (which manages the attribute pointers) and the actual geometry classes which operate on attribute views.
In preparation of the actual drawing call the geometry instances would just emit the instances of their respective vertices; concatenate them up and use that for a glDrawElements call.

If your geometry is not changing then best way is to create VAO with one VBO for geometry of renctangle, one vbo with transformations for multiple rectangles you may draw and one vbo for texture coordinates and do instancing you remove lot of trafic from cpu to gpu by this.Also try to cache uniforms and dont set their value every rendering call if the values are not changing. Try to use tool like gltrace and see if you can reduce unnecessary state changes. Collect as much data as possible and then only do rendering call.

Related

How to optimize rendering of dynamic geomtry? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
As i know batching and instancing is used for decreasing draw-calls amount for static meshes.But what about dynamic meshes?How can i optimize amount of draw calls for them? Instancing and batching
create big overhead because you need to recalculate position with cpu every frame.Or it is better to draw dynamic meshes with separate draw calls?
There are a few performance considerations to keep in mind:
Every glDraw..() comes with some overhead, so you want to minimize those. That's one reason that instancing is such a performance boon. (Better cache behavior is another.)
Host-to-device data transfers (glBufferData()) are even slower than draw calls. So, we try to keep data on the GPU (vertex buffers, index buffers, textures) rather than transmitting it each frame.
In your case, there are a couple of ways to get performant dynamic meshes.
Fake it. Do you really need dynamic meshes - specifically, one where you must generate new mesh data? Or, can you achieve the same thing via transforms in your shaders?
Generate the mesh on the GPU. This could be done in a compute shader (for best performance) or in geometry and/or tessellation shaders. This comes with its own overhead, but, since everything happening on the GPU, you aren't hit with the much more expensive glDraw...() or host-GPU copies.
Note that geometry shaders are relatively slow, but they're still faster than copying a new vertex + index buffer from the CPU to the GPU. *
If your "dynamic" mesh has a finite number of states, just keep them all on the GPU and switch between them as necessary.
If this were another API such as Vulkan, you could potentially generate the mesh in a separate thread and transfer it to the GPU while drawing other things. That is a very complex topic, as is just about everything relating to the explicit graphics APIs.

Question about instancing, instanced arrays and buffer updating

In one of my previous questions (How to instance draw with different transformations for multiple objects) I asked how to instance draw with different transformations, one person answered that the proper way to do it is using instanced arrays.
This lead me to tutorials where they send transformation data through VAO, which is exactly what I was looking for.
But a new problem arose. Since my objects are dynamic (I want to move them) how do I update the buffer with their transformation?
Most of the tutorials Ive seen usually only render instanced objects once and thus they have no need to update the buffer. For a fact I wouldnt even know how to update a buffer to begin with, as I declare VAO with mesh at the beginning and it is not changed during the runtime of program.
What I think I should be doing: Store the transformations on CPU side in some array, when I do something which results in changing a specific transformation I will update this array and then update the transformation buffer.
Probably the actual question:
How do I update a buffer during the runtime of program?
Just use glBufferSubData to update the corresponding data on your GPU, from which your shaders get the transformations per instance (e.g. the vertex buffer for which the divisor is set to 1 with glVertexAttribDivisor(idx, 1)).
The other possibility would be to use glMapBuffer or glMapBufferRange to update that buffer.

Drawing multiple objects in Vulkan [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I've been working on creating a game with a Vulkan rendering backend and I therefore need to be able to draw multiple objects on the screen. I've worked with OpenGL before so I have a little experience in graphics programming.
I've gone through the tutorial at https://vulkan-tutorial.com/ and I more or less understand the basic ideas however there are so many moving parts I find it pretty difficult to wrap my head around it all. So far I'm able to draw a single object with essentially an arbitrary number of vertices with a UBO but no more than 1 since I don't know what to decouple from the main renderer object into a drawable object.
I don't really know what pieces need to live in a vulkan-context object and what parts are independent/live on each drawable object. I've tried doing some research and most of what I can find has to do with instancing which isn't really what I'm looking to do just yet.
There's many options for how to organize this, so there's no single answer. But generally speaking a drawable scene object will need
A VkPipeline describing the state and shaders to use when drawing the object.
One or more VkDescriptorSets that bind resource references in the shader to state and data in Vulkan API objects.
The actual data or data-containing-objects (images, buffers) to use for the drawable.
For the latter two, you don't necessarily have a distinct API objects for each drawable. Instead, your drawable might just have the data and you obtain an API object (like a descriptor set) and fill it in each time you draw, then recycle it. Or you might have a single VkBuffer shared by many drawables, with each drawable's geometry occupying a sub-range of the buffer.
Your "context", on the other hand, will have a VkDevice, VkQueue(s), and various pool objects like command buffer pools, descriptor pools. You'll also usually have some way of keeping track of things that should be recycled or destroyed when command buffers have completed (usually at frame granularity).

The best way to use VBOs [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 9 years ago.
What are the fastest and the most flexible (applicable in most situations) ways to use VBOs?
I am developing an openGL application and i want it to get to the best performance, so i need someone to answer these questions. I read many questions and anwers but i guess there's to much information that i don't need which messes up my brain...
How many vbos should i use?
How should i create vbos?
How should i update vbos data, if the data size is not fixed?
How should i render vbos?
How should i deal with data in vbos that i don't want to render anymore?
How many vbos should i use?
As few as possible. Switching VBOs comes with a small, but measureable cost. In general you'll try to group similar data into VBOs. For example in a FPS game all the different kinds of garbage lying on the street, small props, etc., will be usually located in the same or only a small number of VBOs.
It also comes down to drawing batch sizes. glDraw… calls which render less than about 100 primitives are suboptimal (this has always been the case, even 15 years ago). So you want to batch at least 100 primitives where possible. But if a single mesh has only, say 20 triangles (low polycount props for instancing or such), each in its own VBO you can no longer batch more.
How should i create vbos?
glGenBuffers → glBindBuffer → glBufferData
UPDATE You can pass a null pointer to the data parameter of glBufferData to initialize the buffer object without setting the data.
How should i update vbos data, if the data size is not fixed?
Create VBOs with a coarser size granularity than your data size is. Your operating system is doing this anyway for your host side data, it's called paging. Also if you want to use glMapBuffer making the buffer object a multiple of the host page size is very nice to the whole system.
The usual page size on current systems is 4kiB. So that's the VBO size granularity I'd choose. UPDATE: You can BTW ask your operating system which page size it is using. That's OS dependent though, I'd ask another question for that.
Update the data using glBufferSubData or map it with glMapBuffer modify in the host side mapped memory, then glUnmapBuffer.
If the data outgrows the buffer object, create a new, larger one and copy with glCopyBufferSubData. See the lase paragraph.
How should i render vbos?
glBindBuffer → glDraw…
How should i deal with data in vbos that i don't want to render anymore?
If the data consumes only a part of the VBO and shares it with other data and you're not running out of memory then, well, just don't access it. Ideally you keep around some index in which you keep track of which VBO has which parts of it available for what kind of task. This is very much like memory management, specifically a scheme known as object stacks (obstacks).
However eventually it may make sense to compactify an existing buffer object. For this you'd create a new buffer object, bind it as writing target, with the old buffer object being selected as reading target. Then use glCopyBufferSubData to copy the contents into a new, tightened buffer object. Of course you will then have to update all references to buffer object name (=OpenGL ID) and offsets.
For this reason it makes sense to write a thin abstraction layer on top of OpenGL buffer objects that keeps track of the actual typed data within the structureless blobs OpenGL buffer objects are.
How many vbo's should i use?
As many as you need, sounds silly but well, its that way
How should i update vbos data, if the data size is not fixed?
Overwrite and render the same VBO with different data and lengths.
How should i create vbos?
How should i render vbos?
see VBO tutorial
How should i deal with data in vbos that i don't want to render anymore?
create a new vbo and copy the data into it or render only parts of that vbo which is in memory.
To render only parts see glVertexBuffer glTexCoordPointer(just calculate the new pointer and new size based on the offset)
Edit 1:
Using a single VBO for everything feels wrong, because you have to manage the allcation of new vertex positions/texture coordinates yourself which gets really messy really fast.
It is better to group small props into VBO's and batch the drawing commands.
Can i add data to a buffer with glBufferSubData (adding 100 elements to a buffer with size x)?
No, its not possible because the description says updates a subset of a buffer object's data store and a subset is a smaller set inside a set.
Edit 2
A good tutorial is also Learning Modern 3D Graphics Programming but its not VBO specific.

How many VBOs do I use?

So I understand how to use a Vertex Buffer Object, and that it offers a large performance increase over immediate mode drawing. I will be drawing a lot of 2D quads (sprites), and I am wanting to know if I am supposed to create a VBO for each one, or create one VBO to hold all of the data?
You shouldn't use a new VBO for each sprite/quad. So putting them all in a single VBO would be the better solution in your case.
But in general i don't think this can be answered in one sentence.
Creating a new VBO for each Quad won't give you a real performance increase. If you do so, a lot of time will be wasted with glBindBuffer calls for switching the VBOs. However if you create VBOs that hold too much data you can run into other problems.
Small VBOs:
Are often easier to handle in your program code. You can use a new VBO for each Object you render. This way you can manage your objects very easy in your world
If VBOs are too small (only a few triangles) you don't gain much benefit. A lot of time will be lost with switching buffers (and maybe switching shaders/textures) between buffers
Large VBOs:
You can render tons of objects with a single drawArrays() call for best performance.
Depending on your data its possible that you create overhead for managing a lot of objects in a single VBO (what if you want to move one of these objects and rotate another object?).
If your VBOs are too large its possible that they can't be moved into VRAM
The following links can help you:
Vertex Specification Best Practices
Use one (or a small number of) VBO(s) to hold all/most of your geometry.
Generally the fewer API calls it takes to render your scene, the better.
It also depends what d you want to do with those sprites?
Are they dynamic? Do you want to change only the centre of quad or maybe modify all four points?
This is important because if your data are dynamic then, in the simplest way, you will have to transfer from cpu to gpu each frame. Maybe you could perform all computation on the GPU - for instance by using geometry shaders?
Also for very simple quads/sprites one can use GL_POINT_SPRITE. With that one need to send only one vertex for whole quad. But the drawback is that it is hard to rotate it...