From eb6b1ced86fa4c658aa9447986c8de40f0f7a3ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20Petter=20Sk=C3=A5lerud?= <np_skalerud@hotmail.com> Date: Wed, 27 Mar 2019 12:44:49 +0100 Subject: [PATCH] Added support for OpenGL's debug output feature. New version now requires OpenGL 4.3. Debugging the renderer now relies on a error message callback rather than <iostream> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nils Petter Skålerud <np_skalerud@hotmail.com> --- src/Engine/Application.cpp | 3 +- src/Engine/Engine.cpp | 11 +++-- src/Engine/Renderer/OpenGL.cpp | 70 +++++++++++++++------------- src/Engine/Renderer/Renderer.cpp | 60 ++++++++---------------- src/Engine/Renderer/Renderer.hpp | 15 ++++-- src/Engine/Renderer/RendererData.hpp | 50 ++++++++++++++++++++ src/Engine/Renderer/Typedefs.hpp | 1 + 7 files changed, 128 insertions(+), 82 deletions(-) create mode 100644 src/Engine/Renderer/RendererData.hpp diff --git a/src/Engine/Application.cpp b/src/Engine/Application.cpp index a30f9e5..81a463a 100644 --- a/src/Engine/Application.cpp +++ b/src/Engine/Application.cpp @@ -52,7 +52,8 @@ namespace Engine data->isRunning = true; glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GL_TRUE); GLFWwindow* window = glfwCreateWindow(defaultWindowSize.width, defaultWindowSize.height, "My Title", NULL, NULL); if (!window) { diff --git a/src/Engine/Engine.cpp b/src/Engine/Engine.cpp index 27a9e38..38ccf4f 100644 --- a/src/Engine/Engine.cpp +++ b/src/Engine/Engine.cpp @@ -47,6 +47,11 @@ protected: } }; +void rendererDebugCallback(std::string_view message) +{ + std::cout << "Renderer log: " << message << std::endl; +} + std::vector<std::unique_ptr<Engine::Scene>> Engine::Core::scenes; void Engine::Core::Run() @@ -56,16 +61,16 @@ void Engine::Core::Run() Input::Core::Initialize(); Physics2D::Core::Initialize(); - + // Initialize renderer Renderer::CreateInfo rendererCreateInfo; rendererCreateInfo.preferredAPI = Renderer::API::OpenGL; rendererCreateInfo.surfaceDimensions = Application::GetWindowSize(); rendererCreateInfo.surfaceHandle = Application::Core::GetMainWindowHandle(); - + rendererCreateInfo.debugCreateInfo.errorMessageCallback = rendererDebugCallback; rendererCreateInfo.openGLCreateInfo.glSwapBuffers = Application::Core::GL_SwapWindow; - Renderer::Core::Initialize(std::move(rendererCreateInfo)); + // Create scene and make viewport 0 point to scene 0. Scene& scene1 = Engine::NewScene(); Renderer::GetViewport(0).SetSceneRef(&scene1); diff --git a/src/Engine/Renderer/OpenGL.cpp b/src/Engine/Renderer/OpenGL.cpp index 13e5bcd..b9fb42d 100644 --- a/src/Engine/Renderer/OpenGL.cpp +++ b/src/Engine/Renderer/OpenGL.cpp @@ -1,4 +1,5 @@ #include "Renderer.hpp" +#include "RendererData.hpp" #include "OpenGL.hpp" #include "../Asset.hpp" @@ -9,7 +10,6 @@ #include <memory> #include <unordered_map> #include <fstream> -#include <iostream> #include <array> #include <optional> @@ -39,7 +39,7 @@ namespace Engine std::optional<VBO> VBOFromPath(const std::string& path); void UpdateIBODatabase(Data& data, const std::vector<SpriteID>& loadQueue); - Data& GetData(); + Data& GetAPIData(); void Draw_SpritePass(const Data& data, const std::vector<SpriteID>& sprites, const std::vector<Math::Matrix4x4>& transforms); void Draw_MeshPass(const Data& data, const std::vector<MeshID>& meshes, const std::vector<Math::Matrix4x4>& transforms); @@ -48,7 +48,7 @@ namespace Engine void LoadSpriteShader(Data& data); void LoadMeshShader(Data& data); - inline void PrintGLError(const char* string = ""); + void GLDebugOutputCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam); } } } @@ -115,7 +115,7 @@ struct Engine::Renderer::OpenGL::Data GLint meshModelUniform; }; -Engine::Renderer::OpenGL::Data& Engine::Renderer::OpenGL::GetData() { return std::any_cast<Data&>(Core::GetAPIData()); } +Engine::Renderer::OpenGL::Data& Engine::Renderer::OpenGL::GetAPIData() { return std::any_cast<Data&>(Core::GetAPIData()); } static std::string LoadShader(const std::string& fileName) { @@ -135,7 +135,9 @@ static std::string LoadShader(const std::string& fileName) } else { - std::cerr << "Unable to load shader: " << fileName << std::endl; + if (Engine::Renderer::Core::GetData().debugData.errorMessageCallback) + Engine::Renderer::Core::GetData().debugData.errorMessageCallback("Unable to load shader : " + fileName); + } return output; @@ -158,7 +160,8 @@ static void CheckShaderError(GLuint shader, GLuint flag, bool isProgram, const s else glGetShaderInfoLog(shader, sizeof(error), NULL, error); - std::cerr << errorMessage << ": '" << error << "'" << std::endl; + if (Engine::Renderer::Core::GetData().debugData.errorMessageCallback) + Engine::Renderer::Core::GetData().debugData.errorMessageCallback(errorMessage + ": '" + error); } } @@ -167,7 +170,10 @@ static GLuint CreateShader(const std::string& text, GLuint type) GLuint shader = glCreateShader(type); if (shader == 0) - std::cerr << "Error compiling shader type " << type << std::endl; + { + if (Engine::Renderer::Core::GetData().debugData.errorMessageCallback) + Engine::Renderer::Core::GetData().debugData.errorMessageCallback("Error compiling shader type " + type); + } const GLchar* p[1]; p[0] = text.c_str(); @@ -242,26 +248,11 @@ void Engine::Renderer::OpenGL::LoadMeshShader(Engine::Renderer::OpenGL::Data &da glUniformBlockBinding(data.meshProgram, 1, 1); } -inline void Engine::Renderer::OpenGL::PrintGLError(const char* string) -{ - if constexpr (enableDebug) - { - auto errorEnum = glGetError(); - if (errorEnum != 0) - { - auto errorString = glewGetErrorString(errorEnum); - std::cout << string << errorString << std::endl; - } - } -} - void Engine::Renderer::OpenGL::CreateStandardUBOs(Data& data) { std::array<GLuint, 2> buffers; glGenBuffers(2, buffers.data()); - PrintGLError("Making buffers for standard UBOs: "); - data.cameraDataUBO = buffers[0]; data.lightDataUBO = buffers[1]; @@ -269,13 +260,16 @@ void Engine::Renderer::OpenGL::CreateStandardUBOs(Data& data) glBindBuffer(GL_UNIFORM_BUFFER, data.cameraDataUBO); glNamedBufferData(data.cameraDataUBO, sizeof(CameraDataUBO), nullptr, GL_DYNAMIC_DRAW); glBindBufferRange(GL_UNIFORM_BUFFER, 0, data.cameraDataUBO, 0, sizeof(CameraDataUBO)); - PrintGLError("Making Camera UBO: "); // Make light ubo glBindBuffer(GL_UNIFORM_BUFFER, data.lightDataUBO); glNamedBufferData(data.lightDataUBO, sizeof(LightDataUBO), nullptr, GL_DYNAMIC_DRAW); glBindBufferRange(GL_UNIFORM_BUFFER, 1, data.lightDataUBO, 0, sizeof(LightDataUBO)); - PrintGLError("Making LightData UBO: "); +} + +void Engine::Renderer::OpenGL::GLDebugOutputCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam) +{ + Core::GetData().debugData.errorMessageCallback(message); } void Engine::Renderer::OpenGL::Initialize(std::any& apiData, CreateInfo&& createInfo) @@ -288,6 +282,23 @@ void Engine::Renderer::OpenGL::Initialize(std::any& apiData, CreateInfo&& create data.glSwapBuffers = std::move(createInfo.glSwapBuffers); + // Initialize debug stuff + if (Core::GetData().debugData.errorMessageCallback) + { + GLint flags; + glGetIntegerv(GL_CONTEXT_FLAGS, &flags); + if (flags & GL_CONTEXT_FLAG_DEBUG_BIT) + { + glEnable(GL_DEBUG_OUTPUT); + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); + glDebugMessageCallback(&GLDebugOutputCallback, nullptr); + glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE); + } + else + Core::GetData().debugData.errorMessageCallback("Error. Couldn't make GL Debug Output"); + } + + CreateStandardUBOs(data); // Gen sampler @@ -315,8 +326,6 @@ void Engine::Renderer::OpenGL::Initialize(std::any& apiData, CreateInfo&& create //LoadSpriteShader(data); LoadMeshShader(data); - - PrintGLError("End of GL init: "); } void Engine::Renderer::OpenGL::Terminate(std::any& apiData) @@ -339,7 +348,7 @@ void Engine::Renderer::OpenGL::Terminate(std::any& apiData) void Engine::Renderer::OpenGL::PrepareRenderingEarly(const std::vector<SpriteID>& spriteLoadQueue, const std::vector<MeshID>& meshLoadQueue) { - Data& data = GetData(); + Data& data = GetAPIData(); UpdateIBODatabase(data, spriteLoadQueue); UpdateVBODatabase(data, meshLoadQueue); @@ -365,10 +374,9 @@ void Engine::Renderer::OpenGL::PrepareRenderingEarly(const std::vector<SpriteID> glNamedBufferSubData(data.lightDataUBO, pointLightIntensityOffset, byteLength, intensityData.data()); } -bool testing = false; void Engine::Renderer::OpenGL::PrepareRenderingLate() { - Data& data = GetData(); + Data& data = GetAPIData(); const auto& renderGraphTransform = Core::GetRenderGraphTransform(); @@ -397,7 +405,7 @@ void Engine::Renderer::OpenGL::PrepareRenderingLate() void Engine::Renderer::OpenGL::Draw() { - Data& data = GetData(); + Data& data = GetAPIData(); glClearColor(0.25f, 0.f, 0.f, 1.f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -409,8 +417,6 @@ void Engine::Renderer::OpenGL::Draw() Draw_SpritePass(data, renderGraph.sprites, renderGraphTransform.sprites); Draw_MeshPass(data, renderGraph.meshes, renderGraphTransform.meshes); - PrintGLError("End of GL tick: "); - auto& viewport = Renderer::GetViewport(0); data.glSwapBuffers(viewport.GetSurfaceHandle()); diff --git a/src/Engine/Renderer/Renderer.cpp b/src/Engine/Renderer/Renderer.cpp index d2fc6ef..8cdecf0 100644 --- a/src/Engine/Renderer/Renderer.cpp +++ b/src/Engine/Renderer/Renderer.cpp @@ -1,15 +1,11 @@ #include "Renderer.hpp" -#include "OpenGL.hpp" +#include "RendererData.hpp" -#include "../Scene.hpp" -#include "../Components/SpriteRenderer.hpp" -#include "../Components/MeshRenderer.hpp" -#include "../Components/Camera.hpp" +#include "OpenGL.hpp" #include "DMath/LinearTransform3D.hpp" #include <functional> -#include <iostream> namespace Engine { @@ -17,33 +13,6 @@ namespace Engine { namespace Core { - struct Data - { - RenderGraph renderGraph; - RenderGraphTransform renderGraphTransform; - CameraInfo cameraInfo; - - size_t sceneIDCounter = 0; - - API activeAPI = API::None; - - std::unordered_map<MeshID, size_t> meshReferences; - std::unordered_map<SpriteID, size_t> spriteReferences; - - std::vector<MeshID> loadMeshQueue; - std::vector<MeshID> unloadMeshQueue; - std::vector<SpriteID> loadSpriteQueue; - std::vector<SpriteID> unloadSpriteQueue; - - std::vector<std::unique_ptr<Viewport>> viewports; - - std::function<void(void)> Draw; - std::function<void(const std::vector<SpriteID>&, const std::vector<MeshID>&)> PrepareRenderingEarly; - std::function<void(void)> PrepareRenderingLate; - - std::any apiData = nullptr; - }; - static std::unique_ptr<Data> data; void UpdateAssetReferences(Data& data, const RenderGraph& oldRG, const RenderGraph* newRG); @@ -51,6 +20,11 @@ namespace Engine } } +const Engine::Renderer::Core::Data& Engine::Renderer::Core::GetData() +{ + return *data; +} + Engine::Renderer::Viewport& Engine::Renderer::NewViewport(Utility::ImgDim dimensions, void* surfaceHandle) { Core::data->viewports.emplace_back(std::make_unique<Viewport>(dimensions, surfaceHandle)); @@ -73,18 +47,22 @@ std::any& Engine::Renderer::Core::GetAPIData() { return data->apiData; } bool Engine::Renderer::Core::Initialize(CreateInfo&& createInfo) { - data = std::make_unique<Data>(); - data->activeAPI = createInfo.preferredAPI; + Core::data = std::make_unique<Data>(); + Data& data = *Core::data; + + data.activeAPI = createInfo.preferredAPI; + + data.debugData = std::move(createInfo.debugCreateInfo); NewViewport(createInfo.surfaceDimensions, createInfo.surfaceHandle); - switch (data->activeAPI) + switch (data.activeAPI) { case API::OpenGL: - OpenGL::Initialize(data->apiData, std::move(createInfo.openGLCreateInfo)); - data->Draw = OpenGL::Draw; - data->PrepareRenderingEarly = OpenGL::PrepareRenderingEarly; - data->PrepareRenderingLate = OpenGL::PrepareRenderingLate; + OpenGL::Initialize(data.apiData, std::move(createInfo.openGLCreateInfo)); + data.Draw = OpenGL::Draw; + data.PrepareRenderingEarly = OpenGL::PrepareRenderingEarly; + data.PrepareRenderingLate = OpenGL::PrepareRenderingLate; break; default: break; @@ -118,7 +96,7 @@ void Engine::Renderer::Core::PrepareRenderingEarly(RenderGraph& renderGraphInput std::swap(renderGraph, renderGraphInput); if (!data.loadSpriteQueue.empty() || !data.loadMeshQueue.empty()) - std::cout << "Loading sprite/mesh resource(s)..." << std::endl; + data.debugData.errorMessageCallback("Loading sprite/mesh resource(s)..."); data.PrepareRenderingEarly(data.loadSpriteQueue, data.loadMeshQueue); data.loadSpriteQueue.clear(); diff --git a/src/Engine/Renderer/Renderer.hpp b/src/Engine/Renderer/Renderer.hpp index 98987a3..cdfcf97 100644 --- a/src/Engine/Renderer/Renderer.hpp +++ b/src/Engine/Renderer/Renderer.hpp @@ -37,8 +37,6 @@ namespace Engine void Draw(); void Terminate(); - std::any& GetAPIData(); - const RenderGraph& GetRenderGraph(); const RenderGraphTransform& GetRenderGraphTransform(); const CameraInfo& GetCameraInfo(); @@ -53,13 +51,20 @@ namespace Engine Vulkan }; + struct Renderer::DebugCreateInfo + { + std::function<void(std::string_view)> errorMessageCallback; + }; + struct Renderer::CreateInfo { API preferredAPI = API::None; - Utility::ImgDim surfaceDimensions{}; + Utility::ImgDim surfaceDimensions; void* surfaceHandle = nullptr; - std::function<void(std::string_view)> errorMessageCallback; - OpenGL::CreateInfo openGLCreateInfo{}; + + DebugCreateInfo debugCreateInfo; + + OpenGL::CreateInfo openGLCreateInfo; }; struct Renderer::RenderGraph diff --git a/src/Engine/Renderer/RendererData.hpp b/src/Engine/Renderer/RendererData.hpp new file mode 100644 index 0000000..37d25cd --- /dev/null +++ b/src/Engine/Renderer/RendererData.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include "Renderer.hpp" + +#include <vector> +#include <functional> +#include <any> +#include <unordered_map> + +namespace Engine +{ + namespace Renderer + { + namespace Core + { + struct Data + { + RenderGraph renderGraph; + RenderGraphTransform renderGraphTransform; + CameraInfo cameraInfo; + + size_t sceneIDCounter = 0; + + API activeAPI = API::None; + + std::unordered_map<MeshID, size_t> meshReferences; + std::unordered_map<SpriteID, size_t> spriteReferences; + + std::vector<MeshID> loadMeshQueue; + std::vector<MeshID> unloadMeshQueue; + std::vector<SpriteID> loadSpriteQueue; + std::vector<SpriteID> unloadSpriteQueue; + + std::vector<std::unique_ptr<Viewport>> viewports; + + std::function<void(void)> Draw; + std::function<void(const std::vector<SpriteID>&, const std::vector<MeshID>&)> PrepareRenderingEarly; + std::function<void(void)> PrepareRenderingLate; + + DebugCreateInfo debugData; + + std::any apiData = nullptr; + }; + + const Data& GetData(); + + std::any& GetAPIData(); + } + } +} \ No newline at end of file diff --git a/src/Engine/Renderer/Typedefs.hpp b/src/Engine/Renderer/Typedefs.hpp index ee6ab58..9410bd0 100644 --- a/src/Engine/Renderer/Typedefs.hpp +++ b/src/Engine/Renderer/Typedefs.hpp @@ -15,6 +15,7 @@ namespace Engine enum class MeshID : Core::AssetIntegerType {}; + struct DebugCreateInfo; struct CreateInfo; enum class API; class Viewport; -- GitLab