Skip to content

Commit

Permalink
Zephyr: Renderer: upload geometry draw parameters to a GPU buffer
Browse files Browse the repository at this point in the history
  • Loading branch information
fleroviux committed May 7, 2024
1 parent a276544 commit 2df5412
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 34 deletions.
6 changes: 6 additions & 0 deletions zephyr/renderer/src/backend/opengl/dynamic_gpu_array.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@

namespace zephyr {

/**
* TODO:
* - improve grow strategy (i.e. configurable grow factor)
* - implement shrinking
*/

class OpenGLDynamicGPUArray {
public:
struct BufferRange {
Expand Down
12 changes: 7 additions & 5 deletions zephyr/renderer/src/backend/opengl/render_backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,21 +62,23 @@ namespace zephyr {
glBindBufferBase(GL_UNIFORM_BUFFER, 0, m_gl_ubo);
glNamedBufferSubData(m_gl_ubo, 0, sizeof(Matrix4), &view_projection);

glBindBuffer(GL_DRAW_INDIRECT_BUFFER, m_render_geometry_manager->GetDrawCommandBuffer());

for(const RenderObject& render_object : render_objects) {
glNamedBufferSubData(m_gl_ubo, sizeof(Matrix4), sizeof(Matrix4), &render_object.local_to_world);
//dynamic_cast<OpenGLRenderGeometry*>(render_object.render_geometry)->Draw();

// TODO(fleroviux): avoid constant rebinding of VAO
auto render_geometry = dynamic_cast<OpenGLRenderGeometry*>(render_object.render_geometry);
auto indirect_buffer_offset = (const void*)(render_geometry->GetDrawCommandID() * sizeof(OpenGLDrawElementsIndirectCommand));
glBindVertexArray(m_render_geometry_manager->GetVAOFromLayout(render_geometry->GetLayout()));
if(render_geometry->GetNumberOfIndices() > 0) {
const auto command = render_geometry->GetDrawElementsIndirectCommand();
glDrawElementsInstancedBaseVertexBaseInstance(GL_TRIANGLES, command.count, GL_UNSIGNED_INT, (void*)(sizeof(u32) * command.first_index), command.instance_count, command.base_vertex, command.base_instance);
glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, indirect_buffer_offset);
} else {
const auto command = render_geometry->GetDrawArraysIndirectCommand();
glDrawArraysInstancedBaseInstance(GL_TRIANGLES, command.first, command.count, command.instance_count, command.base_instance);
glDrawArraysIndirect(GL_TRIANGLES, indirect_buffer_offset);
}
}

glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
}

void OpenGLRenderBackend::SwapBuffers() {
Expand Down
66 changes: 37 additions & 29 deletions zephyr/renderer/src/backend/opengl/render_geometry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,56 +29,58 @@ namespace zephyr {

class OpenGLRenderGeometry final : public RenderGeometry {
public:
OpenGLRenderGeometry(RenderGeometryLayout layout, size_t number_of_vertices, size_t number_of_indices, std::shared_ptr<OpenGLDynamicGPUArray> vbo, std::shared_ptr<OpenGLDynamicGPUArray> ibo)
OpenGLRenderGeometry(RenderGeometryLayout layout, size_t number_of_vertices, size_t number_of_indices, std::shared_ptr<OpenGLDynamicGPUArray> vbo, std::shared_ptr<OpenGLDynamicGPUArray> ibo, std::shared_ptr<OpenGLDynamicGPUArray> draw_command_buffer)
: m_layout{layout}
, m_number_of_vertices{number_of_vertices}
, m_number_of_indices{number_of_indices}
, m_vbo{std::move(vbo)} {
, m_vbo{std::move(vbo)}
, m_draw_command_buffer{std::move(draw_command_buffer)} {
m_vbo_allocation = m_vbo->AllocateRange(number_of_vertices);
m_draw_command_allocation = m_draw_command_buffer->AllocateRange(1u);

if(number_of_indices > 0u) {
m_ibo = std::move(ibo);
m_ibo_allocation = m_ibo->AllocateRange(number_of_indices);

const OpenGLDrawElementsIndirectCommand command = {
.count = (GLuint)number_of_indices,
.instance_count = 1u,
.first_index = (GLuint)m_ibo_allocation.base_element,
.base_vertex = (GLint)m_vbo_allocation.base_element,
.base_instance = 0u,
};
m_draw_command_buffer->Write({(const u8*)&command, sizeof(command)}, m_draw_command_allocation.base_element);
} else {
const OpenGLDrawArraysIndirectCommand command = {
.count = (GLuint)number_of_vertices,
.instance_count = 1u,
.first = (GLuint)m_vbo_allocation.base_element,
.base_instance = 0u,
};
m_draw_command_buffer->Write({(const u8*)&command, sizeof(command)}, m_draw_command_allocation.base_element);
}
}

~OpenGLRenderGeometry() override {
m_vbo->ReleaseRange(m_vbo_allocation);

if(m_ibo) {
m_ibo->ReleaseRange(m_ibo_allocation);
}
m_draw_command_buffer->ReleaseRange(m_draw_command_allocation);
}

[[nodiscard]] RenderGeometryLayout GetLayout() const {
return m_layout;
}

[[nodiscard]] size_t GetNumberOfVertices() const override {
return m_number_of_vertices;
}

[[nodiscard]] size_t GetNumberOfIndices() const override {
return m_number_of_indices;
[[nodiscard]] size_t GetDrawCommandID() const {
return m_draw_command_allocation.base_element;
}

[[nodiscard]] OpenGLDrawElementsIndirectCommand GetDrawElementsIndirectCommand() const {
return {
.count = (GLuint)m_number_of_indices,
.instance_count = 1u,
.first_index = (GLuint)m_ibo_allocation.base_element,
.base_vertex = (GLint)m_vbo_allocation.base_element,
.base_instance = 0u,
};
[[nodiscard]] size_t GetNumberOfVertices() const override {
return m_vbo_allocation.number_of_elements;
}

[[nodiscard]] OpenGLDrawArraysIndirectCommand GetDrawArraysIndirectCommand() const {
return {
.count = (GLuint)m_number_of_vertices,
.instance_count = 1u,
.first = (GLuint)m_vbo_allocation.base_element,
.base_instance = 0u,
};
[[nodiscard]] size_t GetNumberOfIndices() const override {
return m_ibo_allocation.number_of_elements;
}

void WriteVBO(std::span<const u8> data) {
Expand All @@ -96,18 +98,19 @@ namespace zephyr {

private:
RenderGeometryLayout m_layout;
size_t m_number_of_vertices;
size_t m_number_of_indices;
std::shared_ptr<OpenGLDynamicGPUArray> m_vbo;
std::shared_ptr<OpenGLDynamicGPUArray> m_ibo{};
std::shared_ptr<OpenGLDynamicGPUArray> m_draw_command_buffer{};
OpenGLDynamicGPUArray::BufferRange m_vbo_allocation{};
OpenGLDynamicGPUArray::BufferRange m_ibo_allocation{};
OpenGLDynamicGPUArray::BufferRange m_draw_command_allocation{};
};

class OpenGLRenderGeometryManager {
public:
OpenGLRenderGeometryManager() {
m_ibo = std::make_shared<OpenGLDynamicGPUArray>(sizeof(u32));
m_draw_command_buffer = std::make_shared<OpenGLDynamicGPUArray>(sizeof(OpenGLDrawElementsIndirectCommand));
}

GLuint GetVAOFromLayout(RenderGeometryLayout layout) {
Expand All @@ -119,9 +122,13 @@ namespace zephyr {
return bucket.vao;
}

GLuint GetDrawCommandBuffer() {
return m_draw_command_buffer->GetBufferHandle();
}

RenderGeometry* CreateRenderGeometry(RenderGeometryLayout layout, size_t number_of_vertices, size_t number_of_indices) {
const Bucket& bucket = GetBucketFromLayout(layout);
return new OpenGLRenderGeometry{layout, number_of_vertices, number_of_indices, bucket.vbo, m_ibo};
return new OpenGLRenderGeometry{layout, number_of_vertices, number_of_indices, bucket.vbo, m_ibo, m_draw_command_buffer};
}

void UpdateRenderGeometryIndices(RenderGeometry* render_geometry, std::span<const u8> data) {
Expand Down Expand Up @@ -182,6 +189,7 @@ namespace zephyr {
std::shared_ptr<OpenGLDynamicGPUArray> m_ibo{};
std::unordered_map<size_t, std::shared_ptr<OpenGLDynamicGPUArray>> m_byte_stride_to_vbo_table{};
std::unordered_map<decltype(RenderGeometryLayout::key), Bucket> m_layout_to_bucket_table{};
std::shared_ptr<OpenGLDynamicGPUArray> m_draw_command_buffer{};
};

} // namespace zephyr

0 comments on commit 2df5412

Please sign in to comment.