From d9e2ceb0aed1188053c0dcd3ddb2a3427ac9ce14 Mon Sep 17 00:00:00 2001 From: fleroviux Date: Sat, 4 May 2024 22:21:26 +0200 Subject: [PATCH] Zephyr: Renderer: split OpenGL backend into multiple files --- zephyr/renderer/CMakeLists.txt | 3 + .../src/backend/opengl/render_backend.cpp | 329 ++++++------------ .../src/backend/opengl/render_backend.hpp | 48 +++ .../src/backend/opengl/render_geometry.cpp | 2 + .../src/backend/opengl/render_geometry.hpp | 108 ++++++ 5 files changed, 267 insertions(+), 223 deletions(-) create mode 100644 zephyr/renderer/src/backend/opengl/render_backend.hpp create mode 100644 zephyr/renderer/src/backend/opengl/render_geometry.cpp create mode 100644 zephyr/renderer/src/backend/opengl/render_geometry.hpp diff --git a/zephyr/renderer/CMakeLists.txt b/zephyr/renderer/CMakeLists.txt index f7a595a..2a3c1b9 100644 --- a/zephyr/renderer/CMakeLists.txt +++ b/zephyr/renderer/CMakeLists.txt @@ -4,6 +4,7 @@ set(SOURCES src/backend/opengl/render_backend.cpp + src/backend/opengl/render_geometry.cpp src/backend/vulkan/render_backend.cpp src/engine/geometry_cache.cpp src/vulkan/vulkan_instance.cpp @@ -11,6 +12,8 @@ set(SOURCES ) set(HEADERS + src/backend/opengl/render_geometry.hpp + src/backend/opengl/render_backend.hpp src/backend/vulkan/shader/triangle.frag.h src/backend/vulkan/shader/triangle.vert.h ) diff --git a/zephyr/renderer/src/backend/opengl/render_backend.cpp b/zephyr/renderer/src/backend/opengl/render_backend.cpp index 505ce72..671702f 100644 --- a/zephyr/renderer/src/backend/opengl/render_backend.cpp +++ b/zephyr/renderer/src/backend/opengl/render_backend.cpp @@ -1,265 +1,148 @@ -#include -#include -#include -#include -#include - -#include -#include -#include +#include "render_backend.hpp" namespace zephyr { - class OpenGLRenderGeometry final : public RenderGeometry { - public: - static OpenGLRenderGeometry* Build(RenderGeometryLayout layout, size_t number_of_vertices, size_t number_of_indices) { - GLuint gl_vao; - glCreateVertexArrays(1u, &gl_vao); - - std::optional maybe_gl_ibo{}; - - if(number_of_indices > 0) { - // @todo: use GL_STATIC_DRAW when possible. - GLuint gl_ibo; - glCreateBuffers(1u, &gl_ibo); - glNamedBufferData(gl_ibo, (GLsizeiptr)(sizeof(u32) * number_of_indices), nullptr, GL_DYNAMIC_DRAW); - glVertexArrayElementBuffer(gl_vao, gl_ibo); - maybe_gl_ibo = gl_ibo; - } - - size_t vbo_stride = 0u; - std::array vbo_attribute_offsets{}; - - const auto PackAttribute = [&](RenderGeometryAttribute attribute, int number_of_components) { - if(layout.HasAttribute(attribute)) { - glEnableVertexArrayAttrib(gl_vao, (int)attribute); - glVertexArrayAttribFormat(gl_vao, (int)attribute, number_of_components, GL_FLOAT, GL_FALSE, vbo_stride); - glVertexArrayAttribBinding(gl_vao, (int)attribute, 0u); - - vbo_attribute_offsets[(int)attribute] = vbo_stride; - vbo_stride += sizeof(f32) * number_of_components; - } - }; - - PackAttribute(RenderGeometryAttribute::Position, 3); - PackAttribute(RenderGeometryAttribute::Normal, 3); - PackAttribute(RenderGeometryAttribute::UV, 2); - PackAttribute(RenderGeometryAttribute::Color, 4); - - // @todo: use GL_STATIC_DRAW when possible. - GLuint gl_vbo; - glCreateBuffers(1u, &gl_vbo); - glNamedBufferData(gl_vbo, (GLsizeiptr)(vbo_stride * number_of_vertices), nullptr, GL_DYNAMIC_DRAW); - glVertexArrayVertexBuffer(gl_vao, 0u, gl_vbo, 0u, (GLsizei)vbo_stride); - - OpenGLRenderGeometry* render_geometry = new OpenGLRenderGeometry{}; - render_geometry->m_gl_vao = gl_vao; - render_geometry->m_gl_ibo = maybe_gl_ibo; - render_geometry->m_gl_vbo = gl_vbo; - render_geometry->m_vbo_stride = vbo_stride; - render_geometry->m_vbo_attribute_offsets = vbo_attribute_offsets; - render_geometry->m_number_of_indices = number_of_indices; - render_geometry->m_number_of_vertices = number_of_vertices; - return render_geometry; - } - - [[nodiscard]] size_t GetNumberOfVertices() const override { - return m_number_of_vertices; - } - - [[nodiscard]] size_t GetNumberOfIndices() const override { - return m_number_of_indices; - } - - void UpdateIndices(std::span data) { - // @todo: validation - glNamedBufferSubData(m_gl_ibo.value(), 0u, (GLsizeiptr)data.size_bytes(), data.data()); - } - - void UpdateVertices(std::span data) { - //@todo: validation - glNamedBufferSubData(m_gl_vbo, 0u, (GLsizeiptr)data.size_bytes(), data.data()); - } - - void Draw() { - glBindVertexArray(m_gl_vao); + OpenGLRenderBackend::OpenGLRenderBackend(SDL_Window* sdl2_window) : m_window{sdl2_window} { + } - if(m_gl_ibo.has_value()) { - glDrawElements(GL_TRIANGLES, (GLsizei)m_number_of_indices, GL_UNSIGNED_INT, nullptr); - } else { - glDrawArrays(GL_TRIANGLES, 0, (GLsizei)m_number_of_vertices); - } - } + void OpenGLRenderBackend::InitializeContext() { + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + m_gl_context = SDL_GL_CreateContext(m_window); + if(m_gl_context == nullptr) { + ZEPHYR_PANIC("Failed to create OpenGL context: {}", SDL_GetError()); + } + glewInit(); - private: - static_assert((int)RenderGeometryAttribute::Count <= 32); + CreateShaderProgram(); + glGenVertexArrays(1u, &m_gl_vao); - OpenGLRenderGeometry() = default; + glCreateBuffers(1u, &m_gl_ubo); + glNamedBufferData(m_gl_ubo, sizeof(Matrix4) * 2, nullptr, GL_DYNAMIC_DRAW); - GLuint m_gl_vao{}; - std::optional m_gl_ibo{}; - GLuint m_gl_vbo{}; - size_t m_vbo_stride{}; - std::array m_vbo_attribute_offsets{}; - size_t m_number_of_indices{}; - size_t m_number_of_vertices{}; - }; + glEnable(GL_DEPTH_TEST); + } - class OpenGLRenderBackend final : public RenderBackend { - public: - explicit OpenGLRenderBackend(SDL_Window* sdl2_window) : m_window{sdl2_window} { - } + void OpenGLRenderBackend::DestroyContext() { + glDeleteBuffers(1u, &m_gl_ubo); + glDeleteVertexArrays(1u, &m_gl_vao); + glDeleteProgram(m_gl_shader_program); - void InitializeContext() override { - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); - m_gl_context = SDL_GL_CreateContext(m_window); - if(m_gl_context == nullptr) { - ZEPHYR_PANIC("Failed to create OpenGL context: {}", SDL_GetError()); - } - glewInit(); + SDL_GL_DeleteContext(m_gl_context); + } - CreateShaderProgram(); - glGenVertexArrays(1u, &m_gl_vao); + RenderGeometry* OpenGLRenderBackend::CreateRenderGeometry(RenderGeometryLayout layout, size_t number_of_vertices, size_t number_of_indices) { + return OpenGLRenderGeometry::Build(layout, number_of_vertices, number_of_indices); + } - glCreateBuffers(1u, &m_gl_ubo); - glNamedBufferData(m_gl_ubo, sizeof(Matrix4) * 2, nullptr, GL_DYNAMIC_DRAW); + void OpenGLRenderBackend::UpdateRenderGeometryIndices(RenderGeometry* render_geometry, std::span data) { + dynamic_cast(render_geometry)->UpdateIndices(data); + } - glEnable(GL_DEPTH_TEST); - } + void OpenGLRenderBackend::UpdateRenderGeometryVertices(RenderGeometry* render_geometry, std::span data) { + dynamic_cast(render_geometry)->UpdateVertices(data); + } - void DestroyContext() override { - glDeleteBuffers(1u, &m_gl_ubo); - glDeleteVertexArrays(1u, &m_gl_vao); - glDeleteProgram(m_gl_shader_program); + void OpenGLRenderBackend::DestroyRenderGeometry(RenderGeometry* geometry) { + delete geometry; + } - SDL_GL_DeleteContext(m_gl_context); - } + void OpenGLRenderBackend::Render(const Matrix4& view_projection, std::span render_objects) { + glClearColor(0.1f, 0.1f, 0.1f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - RenderGeometry* CreateRenderGeometry(RenderGeometryLayout layout, size_t number_of_vertices, size_t number_of_indices) override { - return OpenGLRenderGeometry::Build(layout, number_of_vertices, number_of_indices); - } + glUseProgram(m_gl_shader_program); - void UpdateRenderGeometryIndices(RenderGeometry* render_geometry, std::span data) override { - dynamic_cast(render_geometry)->UpdateIndices(data); - } + glBindBufferBase(GL_UNIFORM_BUFFER, 0, m_gl_ubo); + glNamedBufferSubData(m_gl_ubo, 0, sizeof(Matrix4), &view_projection); - void UpdateRenderGeometryVertices(RenderGeometry* render_geometry, std::span data) override { - dynamic_cast(render_geometry)->UpdateVertices(data); - } + for(const RenderObject& render_object : render_objects) { + glNamedBufferSubData(m_gl_ubo, sizeof(Matrix4), sizeof(Matrix4), &render_object.local_to_world); + dynamic_cast(render_object.render_geometry)->Draw(); + } + } - void DestroyRenderGeometry(RenderGeometry* geometry) override { - delete geometry; - } + void OpenGLRenderBackend::SwapBuffers() { + SDL_GL_SwapWindow(m_window); + } - void Render(const Matrix4& view_projection, std::span render_objects) override { - glClearColor(0.1f, 0.1f, 0.1f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + void OpenGLRenderBackend::CreateShaderProgram() { + GLuint vert_shader = CreateShader(R"( + #version 450 core - glUseProgram(m_gl_shader_program); + layout(binding = 0, std140) uniform Transform { + mat4 projection; + mat4 local_to_world; + } u_transform; - glBindBufferBase(GL_UNIFORM_BUFFER, 0, m_gl_ubo); - glNamedBufferSubData(m_gl_ubo, 0, sizeof(Matrix4), &view_projection); + layout(location = 0) in vec3 a_position; + layout(location = 1) in vec3 a_normal; + layout(location = 2) in vec2 a_uv; + layout(location = 3) in vec3 a_color; - for(const RenderObject& render_object : render_objects) { - glNamedBufferSubData(m_gl_ubo, sizeof(Matrix4), sizeof(Matrix4), &render_object.local_to_world); - dynamic_cast(render_object.render_geometry)->Draw(); - } - } + out vec3 v_normal; + out vec3 v_color; - void SwapBuffers() override { - SDL_GL_SwapWindow(m_window); + void main() { + v_normal = a_normal; + v_color = a_color; + gl_Position = u_transform.projection * u_transform.local_to_world * vec4(a_position, 1.0); } + )", GL_VERTEX_SHADER); - private: - void CreateShaderProgram() { - GLuint vert_shader = CreateShader(R"( - #version 450 core - - layout(binding = 0, std140) uniform Transform { - mat4 projection; - mat4 local_to_world; - } u_transform; + GLuint frag_shader = CreateShader(R"( + #version 450 core - layout(location = 0) in vec3 a_position; - layout(location = 1) in vec3 a_normal; - layout(location = 2) in vec2 a_uv; - layout(location = 3) in vec3 a_color; + layout(location = 0) out vec4 f_frag_color; - out vec3 v_normal; - out vec3 v_color; + in vec3 v_normal; + in vec3 v_color; - void main() { - v_normal = a_normal; - v_color = a_color; - gl_Position = u_transform.projection * u_transform.local_to_world * vec4(a_position, 1.0); - } - )", GL_VERTEX_SHADER); - - GLuint frag_shader = CreateShader(R"( - #version 450 core - - layout(location = 0) out vec4 f_frag_color; - - in vec3 v_normal; - in vec3 v_color; - - void main() { - f_frag_color = vec4(v_normal * 0.5 + 0.5, 1.0); - } - )", GL_FRAGMENT_SHADER); - - m_gl_shader_program = CreateProgram({{vert_shader, frag_shader}}); - glDeleteShader(vert_shader); - glDeleteShader(frag_shader); + void main() { + f_frag_color = vec4(v_normal * 0.5 + 0.5, 1.0); } + )", GL_FRAGMENT_SHADER); - static GLuint CreateShader(const char* glsl_code, GLenum type) { - GLuint gl_shader = glCreateShader(type); - - const char* glsl_code_array[] = {glsl_code}; - glShaderSource(gl_shader, 1u, glsl_code_array, nullptr); - glCompileShader(gl_shader); + m_gl_shader_program = CreateProgram({{vert_shader, frag_shader}}); + glDeleteShader(vert_shader); + glDeleteShader(frag_shader); + } - GLint compile_succeeded; - glGetShaderiv(gl_shader, GL_COMPILE_STATUS, &compile_succeeded); - if(compile_succeeded == GL_FALSE) { - // TODO(fleroviux): let the caller decide how to deal with the error. - GLint info_log_length; - glGetShaderiv(gl_shader, GL_INFO_LOG_LENGTH, &info_log_length); + GLuint OpenGLRenderBackend::CreateShader(const char* glsl_code, GLenum type) { + GLuint gl_shader = glCreateShader(type); - GLchar* info_log = new GLchar[info_log_length]; - glGetShaderInfoLog(gl_shader, info_log_length, &info_log_length, info_log); - ZEPHYR_PANIC("OpenGL: failed to compile GLSL shader:\n{}", info_log); - delete[] info_log; - } + const char* glsl_code_array[] = {glsl_code}; + glShaderSource(gl_shader, 1u, glsl_code_array, nullptr); + glCompileShader(gl_shader); - return gl_shader; - } + GLint compile_succeeded; + glGetShaderiv(gl_shader, GL_COMPILE_STATUS, &compile_succeeded); + if(compile_succeeded == GL_FALSE) { + // TODO(fleroviux): let the caller decide how to deal with the error. + GLint info_log_length; + glGetShaderiv(gl_shader, GL_INFO_LOG_LENGTH, &info_log_length); - static GLuint CreateProgram(std::span shaders) { - GLuint gl_program = glCreateProgram(); + GLchar* info_log = new GLchar[info_log_length]; + glGetShaderInfoLog(gl_shader, info_log_length, &info_log_length, info_log); + ZEPHYR_PANIC("OpenGL: failed to compile GLSL shader:\n{}", info_log); + delete[] info_log; + } - for(auto shader_object : shaders) { - glAttachShader(gl_program, shader_object); - } - glLinkProgram(gl_program); + return gl_shader; + } - // TODO: handle program link error? - return gl_program; - } + GLuint OpenGLRenderBackend::CreateProgram(std::span shaders) { + GLuint gl_program = glCreateProgram(); - SDL_Window* m_window; - SDL_GLContext m_gl_context{}; - GLuint m_gl_shader_program{}; - GLuint m_gl_vao{}; - GLuint m_gl_ubo{}; - }; + for(auto shader_object : shaders) { + glAttachShader(gl_program, shader_object); + } + glLinkProgram(gl_program); - std::unique_ptr CreateOpenGLRenderBackendForSDL2(SDL_Window* sdl2_window) { - return std::make_unique(sdl2_window); + // TODO: handle program link error? + return gl_program; } } // namespace zephyr diff --git a/zephyr/renderer/src/backend/opengl/render_backend.hpp b/zephyr/renderer/src/backend/opengl/render_backend.hpp new file mode 100644 index 0000000..519b637 --- /dev/null +++ b/zephyr/renderer/src/backend/opengl/render_backend.hpp @@ -0,0 +1,48 @@ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "render_geometry.hpp" + +namespace zephyr { + + class OpenGLRenderBackend final : public RenderBackend { + public: + explicit OpenGLRenderBackend(SDL_Window* sdl2_window); + + void InitializeContext() override; + void DestroyContext() override; + + RenderGeometry* CreateRenderGeometry(RenderGeometryLayout layout, size_t number_of_vertices, size_t number_of_indices) override; + void UpdateRenderGeometryIndices(RenderGeometry* render_geometry, std::span data) override; + void UpdateRenderGeometryVertices(RenderGeometry* render_geometry, std::span data) override; + void DestroyRenderGeometry(RenderGeometry* geometry) override; + + void Render(const Matrix4& view_projection, std::span render_objects) override; + + void SwapBuffers() override; + + private: + void CreateShaderProgram(); + + static GLuint CreateShader(const char* glsl_code, GLenum type); + static GLuint CreateProgram(std::span shaders); + + SDL_Window* m_window; + SDL_GLContext m_gl_context{}; + GLuint m_gl_shader_program{}; + GLuint m_gl_vao{}; + GLuint m_gl_ubo{}; + }; + + std::unique_ptr CreateOpenGLRenderBackendForSDL2(SDL_Window* sdl2_window) { + return std::make_unique(sdl2_window); + } + +} // namespace zephyr diff --git a/zephyr/renderer/src/backend/opengl/render_geometry.cpp b/zephyr/renderer/src/backend/opengl/render_geometry.cpp new file mode 100644 index 0000000..9c07eb5 --- /dev/null +++ b/zephyr/renderer/src/backend/opengl/render_geometry.cpp @@ -0,0 +1,2 @@ + +#include "render_geometry.hpp" diff --git a/zephyr/renderer/src/backend/opengl/render_geometry.hpp b/zephyr/renderer/src/backend/opengl/render_geometry.hpp new file mode 100644 index 0000000..19264f6 --- /dev/null +++ b/zephyr/renderer/src/backend/opengl/render_geometry.hpp @@ -0,0 +1,108 @@ + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace zephyr { + + class OpenGLRenderGeometry final : public RenderGeometry { + public: + static OpenGLRenderGeometry* Build(RenderGeometryLayout layout, size_t number_of_vertices, size_t number_of_indices) { + GLuint gl_vao; + glCreateVertexArrays(1u, &gl_vao); + + std::optional maybe_gl_ibo{}; + + if(number_of_indices > 0) { + // @todo: use GL_STATIC_DRAW when possible. + GLuint gl_ibo; + glCreateBuffers(1u, &gl_ibo); + glNamedBufferData(gl_ibo, (GLsizeiptr)(sizeof(u32) * number_of_indices), nullptr, GL_DYNAMIC_DRAW); + glVertexArrayElementBuffer(gl_vao, gl_ibo); + maybe_gl_ibo = gl_ibo; + } + + size_t vbo_stride = 0u; + std::array vbo_attribute_offsets{}; + + const auto PackAttribute = [&](RenderGeometryAttribute attribute, int number_of_components) { + if(layout.HasAttribute(attribute)) { + glEnableVertexArrayAttrib(gl_vao, (int)attribute); + glVertexArrayAttribFormat(gl_vao, (int)attribute, number_of_components, GL_FLOAT, GL_FALSE, vbo_stride); + glVertexArrayAttribBinding(gl_vao, (int)attribute, 0u); + + vbo_attribute_offsets[(int)attribute] = vbo_stride; + vbo_stride += sizeof(f32) * number_of_components; + } + }; + + PackAttribute(RenderGeometryAttribute::Position, 3); + PackAttribute(RenderGeometryAttribute::Normal, 3); + PackAttribute(RenderGeometryAttribute::UV, 2); + PackAttribute(RenderGeometryAttribute::Color, 4); + + // @todo: use GL_STATIC_DRAW when possible. + GLuint gl_vbo; + glCreateBuffers(1u, &gl_vbo); + glNamedBufferData(gl_vbo, (GLsizeiptr)(vbo_stride * number_of_vertices), nullptr, GL_DYNAMIC_DRAW); + glVertexArrayVertexBuffer(gl_vao, 0u, gl_vbo, 0u, (GLsizei)vbo_stride); + + OpenGLRenderGeometry* render_geometry = new OpenGLRenderGeometry{}; + render_geometry->m_gl_vao = gl_vao; + render_geometry->m_gl_ibo = maybe_gl_ibo; + render_geometry->m_gl_vbo = gl_vbo; + render_geometry->m_vbo_stride = vbo_stride; + render_geometry->m_vbo_attribute_offsets = vbo_attribute_offsets; + render_geometry->m_number_of_indices = number_of_indices; + render_geometry->m_number_of_vertices = number_of_vertices; + return render_geometry; + } + + [[nodiscard]] size_t GetNumberOfVertices() const override { + return m_number_of_vertices; + } + + [[nodiscard]] size_t GetNumberOfIndices() const override { + return m_number_of_indices; + } + + void UpdateIndices(std::span data) { + // @todo: validation + glNamedBufferSubData(m_gl_ibo.value(), 0u, (GLsizeiptr)data.size_bytes(), data.data()); + } + + void UpdateVertices(std::span data) { + //@todo: validation + glNamedBufferSubData(m_gl_vbo, 0u, (GLsizeiptr)data.size_bytes(), data.data()); + } + + void Draw() { + glBindVertexArray(m_gl_vao); + + if(m_gl_ibo.has_value()) { + glDrawElements(GL_TRIANGLES, (GLsizei)m_number_of_indices, GL_UNSIGNED_INT, nullptr); + } else { + glDrawArrays(GL_TRIANGLES, 0, (GLsizei)m_number_of_vertices); + } + } + + private: + static_assert((int)RenderGeometryAttribute::Count <= 32); + + OpenGLRenderGeometry() = default; + + GLuint m_gl_vao{}; + std::optional m_gl_ibo{}; + GLuint m_gl_vbo{}; + size_t m_vbo_stride{}; + std::array m_vbo_attribute_offsets{}; + size_t m_number_of_indices{}; + size_t m_number_of_vertices{}; + }; + +} // namespace zephyr \ No newline at end of file