I have created a 2D sprite rendering engine in C++ and OpenGL. Each “Drawable” entity has a sprite attached to it and can be drawn at a different position, pivot point (origin), angle, scale and depth. A Sprite refers to a different texture page and texture coords in it, based on each sub-image.
I have avoided instancing since I have read that it’s not very efficient for drawing quads. Same for point sprites/geometry shaders.
So far the project has been a success! In order to maximize batching, each Drawable has a unique ID with the following setup in a 64-bit long long int:
First X bits represent the depth (the sign bit is left untouched)
Next Y bits represent the texture page ID
The last Z bits represent the drawable ID.
Therefore Drawables are sorted based on their Unique ID in Drawable Chunks and data from these chunks go to their respective VBO, EBO & VAO setup. Chunks and their respective buffer data are updated only when a drawable changes position, angle, depth etc. In this way, by using glMultiDrawElements(), the quads are being drawn in their proper order with the maximum amount of batching possible for the same texture page. Even if I acquire a subset of Drawable entities (say, by getting them form a Quadtree) and I sort them based on their unique ID, their order is the same as in their respective chunks since the sorting criterion is the same.
My question is the following:
I use glBindTexture to set up the proper texture page whenever a batch breaks due to the current drawable group belonging to a different texture page than the one being currently in use. Since Drawables can have different depths and can belong to different texture pages, despite their sorting/batching, a lot of texture swaps still occur.
Example: Drawing 25K sprites at random depths ranging from 0 to 1000, from 2 different texture pages, can result in 2K batches/texture swaps. Obviously, the larger the depth range, the more the batches: A depth range from 0 to 8 yields only ~60 different batches.
Is there a more efficient way to assign a texture page when a batch breaks? I tried binding a Texture to a different Texture Unit and then simply switching the active texture unit with glActiveTexture without calling glBindTexture, but this doesn’t seem to work. The fragment shader currently samples just from one texture unit (the default). Is there any other configuration I can look up (like texture arrays or setting up a lot of active textures and passing which sampler to use as a uniform)?
I would appreciate any info on this!
EDIT: In a realistic scenario there wouldn’t be so many different depths. Even in complex 2D games most drawable entities align to some grid and therefore many groups of entities share the same depth. My question is more on a technical level rather than a practical one. I am still learning about OpenGL and would like some pointers on what to look up next!