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