Alright here we go… Not entirely
This is where I create my buffer objects. Channels represents the max amount of objects which can be drawn per batch. It used to be stored in one large allocated buffer, this is just an attempt to fix the issue.
struct Renderer
{
Renderer(std::vector<GLuint> channel_sizes, GLuint indices_size, std::vector<GLuint> attribute_sizes)
: current_material(nullptr), indices_size(indices_size), attribute_size(0), quad_count(0), first_quad(0)
{
for (auto att : attribute_sizes)
attribute_size += att;
vertex_size = attribute_size * indices_size;
max_sprites = 0;
for (auto size : channel_sizes)
{
channels.push_back(max_sprites * vertex_size);
max_sprites += size;
}
channels.push_back(max_sprites * vertex_size);
this->channels = channels;
this->curr_channel = this->channels.begin();
this->next_channel = this->curr_channel + 1;
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
// memory mapping flags
GLbitfield fMap = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
// buffer creation flags
GLbitfield fCreate = fMap | GL_DYNAMIC_STORAGE_BIT;
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
// initialize and allocate buffer object
glBufferStorage(GL_ARRAY_BUFFER, (GLsizeiptr)(max_sprites * vertex_size), nullptr, fCreate);
// map the VBO address
buffer = (float*)glMapBufferRange(GL_ARRAY_BUFFER, 0, (GLsizeiptr)(max_sprites * vertex_size), fMap);
buffer_curr = buffer;
auto stride = 0ull;
for (auto i = 0; i < attribute_sizes.size(); ++i)
{
glEnableVertexAttribArray(i);
glVertexAttribPointer(i, attribute_sizes[i], GL_FLOAT, GL_FALSE, attribute_size * sizeof(float), (GLvoid*)stride);
stride += attribute_sizes[i] * sizeof(float);
}
}
~PRenderer()
{
// delete allocated buffers
glDeleteBuffers(1, &vbo);
glDeleteBuffers(1, &vao);
}
GLuint max_sprites,
indices_size,
vertex_size,
attribute_size,
quad_count, first_quad;
std::vector<GLuint> channels;
std::vector<GLuint>::iterator curr_channel;
std::vector<GLuint>::iterator next_channel;
float* buffer;
float* buffer_curr;
GLuint vbo;
GLuint vao;
Material* current_material;
};
This is where I am drawing the quads. Src and Dest are both just glm::vec4s and Material is a holding class for my Shaders and Textures.
void draw(Renderer* renderer, Src* src, Dest* dest, Material* material)
{
if (renderer->next_channel == renderer->channels.end())
{
std::cerr << "not enough space to render batch: " << material->batch_id << std::endl;
return;
}
if ((renderer->quad_count * renderer->vertex_size >= *renderer->next_channel || !renderer->current_material) || material->hash != renderer->current_material->hash)
{
pflush(renderer);
renderer->current_material = material;
}
auto& buffer = renderer->buffer_curr;
// first triangle
*buffer++ = dest->dest.x;
*buffer++ = dest->dest.w;
*buffer++ = src->src.x;
*buffer++ = src->src.w;
*buffer++ = dest->dest.z;
*buffer++ = dest->dest.y;
*buffer++ = src->src.z;
*buffer++ = src->src.y;
*buffer++ = dest->dest.x;
*buffer++ = dest->dest.y;
*buffer++ = src->src.x;
*buffer++ = src->src.y;
// second triangle
*buffer++ = dest->dest.x;
*buffer++ = dest->dest.w;
*buffer++ = src->src.x;
*buffer++ = src->src.w;
*buffer++ = dest->dest.z;
*buffer++ = dest->dest.w;
*buffer++ = src->src.z;
*buffer++ = src->src.w;
*buffer++ = dest->dest.z;
*buffer++ = dest->dest.y;
*buffer++ = src->src.z;
*buffer++ = src->src.y;
// increment quad
++renderer->quad_count;
}
Lastly here is my flush function, where I call glDrawArrays. I don’t think I am using first properly, and I reckon that has something to do with the issue I am running into.
void flush(Renderer* renderer)
{
if (!renderer->quad_count) return;
if (!renderer->current_material)
{
renderer->quad_count = 0;
renderer->buffer_curr = renderer->buffer;
return;
}
// bind texture
renderer->current_material->mat->bind(renderer->current_material->texture);
// set uniforms and use shader
renderer->current_material->mat->compile(renderer->current_material->shader);
auto total_draws = (GLsizei)(renderer->quad_count * renderer->indices_size);
auto first = *renderer->curr_channel;
// draw triangles
glDrawArrays(GL_TRIANGLES, first, total_draws);
// increment chanel and buffer position
renderer->curr_channel++;
renderer->buffer_curr = &renderer->buffer[*renderer->curr_channel];
renderer->next_channel++;
renderer->first_quad += renderer->quad_count;
renderer->quad_count = 0;
}
Let me know what you see wrong here, I would be happy to provide more if need be. I have already successfully gotten one batch renderer working using glBufferData and glBufferSubData so I am fairly confident the problem is in these three files.
Thanks,
Wad