From 00c2e824d1e9e05dec1d3d35caceeb4a705980d2 Mon Sep 17 00:00:00 2001 From: Lynix Date: Fri, 21 Jun 2013 01:28:11 +0200 Subject: [PATCH] The OpenGL wrapper now handles context change Fixed some bugs Thanks to Raakz Former-commit-id: f156ba7aa3307cccd83c9c02987dadad02cd8185 --- include/Nazara/Renderer/Context.hpp | 8 +- include/Nazara/Renderer/OpenGL.hpp | 7 + readme.txt | 2 +- readme_fr.txt | 2 +- src/Nazara/Renderer/Context.cpp | 20 ++- src/Nazara/Renderer/OpenGL.cpp | 244 ++++++++++++++++++++------- src/Nazara/Renderer/RenderWindow.cpp | 4 +- 7 files changed, 208 insertions(+), 79 deletions(-) diff --git a/include/Nazara/Renderer/Context.hpp b/include/Nazara/Renderer/Context.hpp index aee424a35..836a1f59e 100644 --- a/include/Nazara/Renderer/Context.hpp +++ b/include/Nazara/Renderer/Context.hpp @@ -32,13 +32,13 @@ class NAZARA_API NzContext : public NzResource const NzContextParameters& GetParameters() const; bool IsActive() const; - bool SetActive(bool active) const; + bool SetActive(bool active); void SwapBuffers(); static bool EnsureContext(); - static const NzContext* GetCurrent(); - static const NzContext* GetReference(); - static const NzContext* GetThreadContext(); + static NzContext* GetCurrent(); + static NzContext* GetReference(); + static NzContext* GetThreadContext(); static bool Initialize(); static void Uninitialize(); diff --git a/include/Nazara/Renderer/OpenGL.hpp b/include/Nazara/Renderer/OpenGL.hpp index 958499488..ff7db1f6e 100644 --- a/include/Nazara/Renderer/OpenGL.hpp +++ b/include/Nazara/Renderer/OpenGL.hpp @@ -44,10 +44,13 @@ enum nzOpenGLExtension nzOpenGLExtension_Max = nzOpenGLExtension_VertexArrayObjects }; +class NzContext; using NzOpenGLFunc = void (*)(); class NAZARA_API NzOpenGL { + friend NzContext; + public: enum FormatType { @@ -120,6 +123,10 @@ class NAZARA_API NzOpenGL static GLenum TextureTarget[nzImageType_Max+1]; static GLenum TextureTargetBinding[nzImageType_Max+1]; static GLenum TextureTargetProxy[nzImageType_Max+1]; + + private: + static void OnContextDestruction(NzContext* context); + static void OnContextChange(NzContext* newContext); }; NAZARA_API extern PFNGLACTIVETEXTUREPROC glActiveTexture; diff --git a/readme.txt b/readme.txt index 8c8dc495e..ef28b04bf 100644 --- a/readme.txt +++ b/readme.txt @@ -43,6 +43,6 @@ Wiki : http://wiki.digitalpulsesoftware.com/index.php?title=Nazara Forum : http://forum.digitalpulsesoftware.com Thanks to --RafBill: Finding bugs +-RafBill/Raakz: Finding bugs and/or testing -Fissal "DrFisher" Hannoun: Helped a lot in architecture design -Alexandre "Danman" Janniaux: Made the core POSIX port diff --git a/readme_fr.txt b/readme_fr.txt index a4d87ee8e..d82ea8c8d 100644 --- a/readme_fr.txt +++ b/readme_fr.txt @@ -43,6 +43,6 @@ Wiki : http://wiki.digitalpulsesoftware.com/index.php?title=Nazara Forum : http://forum.digitalpulsesoftware.com Merci à --RafBill: Recherche de bugs +-RafBill/Raakz: Recherche de bugs et/ou testeur -Fissal "DrFisher" Hannoun: Beaucoup d'aide dans la conception de l'architecture du moteur -Alexandre "Danman" Janniaux: À fait le port POSIX du noyau diff --git a/src/Nazara/Renderer/Context.cpp b/src/Nazara/Renderer/Context.cpp index e80dbb353..d4a988943 100644 --- a/src/Nazara/Renderer/Context.cpp +++ b/src/Nazara/Renderer/Context.cpp @@ -22,8 +22,8 @@ namespace { - thread_local const NzContext* currentContext = nullptr; - thread_local const NzContext* threadContext = nullptr; + thread_local NzContext* currentContext = nullptr; + thread_local NzContext* threadContext = nullptr; std::vector contexts; @@ -153,7 +153,7 @@ bool NzContext::Create(const NzContextParameters& parameters) return false; } - if (!m_impl->Activate()) + if (!SetActive(true)) { NazaraError("Failed to activate context"); @@ -186,9 +186,13 @@ void NzContext::Destroy() if (m_impl) { NotifyDestroy(); + NzOpenGL::OnContextDestruction(this); if (currentContext == this) + { NzContextImpl::Desactivate(); + currentContext = nullptr; + } m_impl->Destroy(); delete m_impl; @@ -219,7 +223,7 @@ bool NzContext::IsActive() const return currentContext == this; } -bool NzContext::SetActive(bool active) const +bool NzContext::SetActive(bool active) { #ifdef NAZARA_RENDERER_SAFE if (!m_impl) @@ -248,6 +252,8 @@ bool NzContext::SetActive(bool active) const currentContext = nullptr; } + NzOpenGL::OnContextChange(currentContext); + return true; } @@ -300,17 +306,17 @@ bool NzContext::EnsureContext() return true; } -const NzContext* NzContext::GetCurrent() +NzContext* NzContext::GetCurrent() { return currentContext; } -const NzContext* NzContext::GetReference() +NzContext* NzContext::GetReference() { return s_reference; } -const NzContext* NzContext::GetThreadContext() +NzContext* NzContext::GetThreadContext() { EnsureContext(); diff --git a/src/Nazara/Renderer/OpenGL.cpp b/src/Nazara/Renderer/OpenGL.cpp index cf954f6d1..1c8886edf 100644 --- a/src/Nazara/Renderer/OpenGL.cpp +++ b/src/Nazara/Renderer/OpenGL.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include namespace @@ -59,17 +60,23 @@ namespace #endif } + struct ContextStates + { + GLuint buffersBinding[nzBufferType_Max+1] = {0}; + GLuint currentProgram = 0; + GLuint texturesBinding[32] = {0}; // 32 est pour l'instant la plus haute limite (GL_TEXTURE31) + NzRenderStates renderStates; // Toujours synchronisé avec OpenGL + unsigned int textureUnit = 0; + }; + std::set s_openGLextensionSet; - GLuint s_buffersBinding[nzBufferType_Max+1]; - GLuint s_currentProgram; - GLuint s_texturesBinding[32]; // 32 est pour l'instant la plus haute limite (GL_TEXTURE31) - NzRenderStates s_states; // Toujours synchronisé avec OpenGL + std::unordered_map s_contexts; + ContextStates* s_contextStates = nullptr; const char* s_rendererName = nullptr; const char* s_vendorName = nullptr; bool s_initialized = false; bool s_openGLextensions[nzOpenGLExtension_Max+1] = {false}; unsigned int s_openglVersion = 0; - unsigned int s_textureUnit = 0; bool LoadExtensionsString(const NzString& extensionString) { @@ -118,191 +125,270 @@ namespace void NzOpenGL::ApplyStates(const NzRenderStates& states) { - if (s_states.dstBlend != states.dstBlend || s_states.srcBlend != states.srcBlend) + #ifdef NAZARA_DEBUG + if (!s_contextStates) + { + NazaraError("No context activated"); + return; + } + #endif + + NzRenderStates& currentRenderStates = s_contextStates->renderStates; + + if (currentRenderStates.dstBlend != states.dstBlend || + currentRenderStates.srcBlend != states.srcBlend) { glBlendFunc(BlendFunc[states.srcBlend], BlendFunc[states.dstBlend]); - s_states.dstBlend = states.dstBlend; - s_states.srcBlend = states.srcBlend; + currentRenderStates.dstBlend = states.dstBlend; + currentRenderStates.srcBlend = states.srcBlend; } - if (s_states.depthFunc != states.depthFunc) + if (currentRenderStates.depthFunc != states.depthFunc) { glDepthFunc(RendererComparison[states.depthFunc]); - s_states.depthFunc = states.depthFunc; + currentRenderStates.depthFunc = states.depthFunc; } - if (s_states.faceCulling != states.faceCulling) + if (currentRenderStates.faceCulling != states.faceCulling) { glCullFace(FaceCulling[states.faceCulling]); - s_states.faceCulling = states.faceCulling; + currentRenderStates.faceCulling = states.faceCulling; } - if (s_states.faceFilling != states.faceFilling) + if (currentRenderStates.faceFilling != states.faceFilling) { glPolygonMode(GL_FRONT_AND_BACK, FaceFilling[states.faceFilling]); - s_states.faceFilling = states.faceFilling; + currentRenderStates.faceFilling = states.faceFilling; } - if (s_states.stencilCompare != states.stencilCompare || s_states.stencilMask != states.stencilMask || s_states.stencilReference != states.stencilReference) + if (currentRenderStates.stencilCompare != states.stencilCompare || + currentRenderStates.stencilMask != states.stencilMask || + currentRenderStates.stencilReference != states.stencilReference) { glStencilFunc(RendererComparison[states.stencilCompare], states.stencilReference, states.stencilMask); - s_states.stencilCompare = states.stencilCompare; - s_states.stencilMask = states.stencilMask; - s_states.stencilReference = states.stencilReference; + currentRenderStates.stencilCompare = states.stencilCompare; + currentRenderStates.stencilMask = states.stencilMask; + currentRenderStates.stencilReference = states.stencilReference; } - if (s_states.stencilFail != states.stencilFail || s_states.stencilPass != states.stencilPass || s_states.stencilZFail != states.stencilZFail) + if (currentRenderStates.stencilFail != states.stencilFail || + currentRenderStates.stencilPass != states.stencilPass || + currentRenderStates.stencilZFail != states.stencilZFail) { glStencilOp(StencilOperation[states.stencilFail], StencilOperation[states.stencilZFail], StencilOperation[states.stencilPass]); - s_states.stencilFail = states.stencilFail; - s_states.stencilPass = states.stencilPass; - s_states.stencilZFail = states.stencilZFail; + currentRenderStates.stencilFail = states.stencilFail; + currentRenderStates.stencilPass = states.stencilPass; + currentRenderStates.stencilZFail = states.stencilZFail; } - if (!NzNumberEquals(s_states.lineWidth, states.lineWidth, 0.001f)) + if (!NzNumberEquals(currentRenderStates.lineWidth, states.lineWidth, 0.001f)) { glLineWidth(states.lineWidth); - s_states.lineWidth = states.lineWidth; + currentRenderStates.lineWidth = states.lineWidth; } - if (!NzNumberEquals(s_states.pointSize, states.pointSize, 0.001f)) + if (!NzNumberEquals(currentRenderStates.pointSize, states.pointSize, 0.001f)) { glPointSize(states.pointSize); - s_states.pointSize = states.pointSize; + currentRenderStates.pointSize = states.pointSize; } // Paramètres de rendu - if (s_states.parameters[nzRendererParameter_Blend] != states.parameters[nzRendererParameter_Blend]) + if (currentRenderStates.parameters[nzRendererParameter_Blend] != states.parameters[nzRendererParameter_Blend]) { if (states.parameters[nzRendererParameter_Blend]) glEnable(GL_BLEND); else glDisable(GL_BLEND); - s_states.parameters[nzRendererParameter_Blend] = states.parameters[nzRendererParameter_Blend]; + currentRenderStates.parameters[nzRendererParameter_Blend] = states.parameters[nzRendererParameter_Blend]; } - if (s_states.parameters[nzRendererParameter_ColorWrite] != states.parameters[nzRendererParameter_ColorWrite]) + if (currentRenderStates.parameters[nzRendererParameter_ColorWrite] != states.parameters[nzRendererParameter_ColorWrite]) { GLboolean param = (states.parameters[nzRendererParameter_ColorWrite]) ? GL_TRUE : GL_FALSE; glColorMask(param, param, param, param); - s_states.parameters[nzRendererParameter_ColorWrite] = states.parameters[nzRendererParameter_ColorWrite]; + currentRenderStates.parameters[nzRendererParameter_ColorWrite] = states.parameters[nzRendererParameter_ColorWrite]; } - if (s_states.parameters[nzRendererParameter_DepthBuffer] != states.parameters[nzRendererParameter_DepthBuffer]) + if (currentRenderStates.parameters[nzRendererParameter_DepthBuffer] != states.parameters[nzRendererParameter_DepthBuffer]) { if (states.parameters[nzRendererParameter_DepthBuffer]) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST); - s_states.parameters[nzRendererParameter_DepthBuffer] = states.parameters[nzRendererParameter_DepthBuffer]; + currentRenderStates.parameters[nzRendererParameter_DepthBuffer] = states.parameters[nzRendererParameter_DepthBuffer]; } - if (s_states.parameters[nzRendererParameter_DepthWrite] != states.parameters[nzRendererParameter_DepthWrite]) + if (currentRenderStates.parameters[nzRendererParameter_DepthWrite] != states.parameters[nzRendererParameter_DepthWrite]) { glDepthMask((states.parameters[nzRendererParameter_DepthWrite]) ? GL_TRUE : GL_FALSE); - s_states.parameters[nzRendererParameter_DepthWrite] = states.parameters[nzRendererParameter_DepthWrite]; + currentRenderStates.parameters[nzRendererParameter_DepthWrite] = states.parameters[nzRendererParameter_DepthWrite]; } - if (s_states.parameters[nzRendererParameter_FaceCulling] != states.parameters[nzRendererParameter_FaceCulling]) + if (currentRenderStates.parameters[nzRendererParameter_FaceCulling] != states.parameters[nzRendererParameter_FaceCulling]) { if (states.parameters[nzRendererParameter_FaceCulling]) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); - s_states.parameters[nzRendererParameter_FaceCulling] = states.parameters[nzRendererParameter_FaceCulling]; + currentRenderStates.parameters[nzRendererParameter_FaceCulling] = states.parameters[nzRendererParameter_FaceCulling]; } - if (s_states.parameters[nzRendererParameter_ScissorTest] != states.parameters[nzRendererParameter_ScissorTest]) + if (currentRenderStates.parameters[nzRendererParameter_ScissorTest] != states.parameters[nzRendererParameter_ScissorTest]) { if (states.parameters[nzRendererParameter_ScissorTest]) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST); - s_states.parameters[nzRendererParameter_ScissorTest] = states.parameters[nzRendererParameter_ScissorTest]; + currentRenderStates.parameters[nzRendererParameter_ScissorTest] = states.parameters[nzRendererParameter_ScissorTest]; } - if (s_states.parameters[nzRendererParameter_StencilTest] != states.parameters[nzRendererParameter_StencilTest]) + if (currentRenderStates.parameters[nzRendererParameter_StencilTest] != states.parameters[nzRendererParameter_StencilTest]) { if (states.parameters[nzRendererParameter_StencilTest]) glEnable(GL_STENCIL_TEST); else glDisable(GL_STENCIL_TEST); - s_states.parameters[nzRendererParameter_StencilTest] = states.parameters[nzRendererParameter_StencilTest]; + currentRenderStates.parameters[nzRendererParameter_StencilTest] = states.parameters[nzRendererParameter_StencilTest]; } } void NzOpenGL::BindBuffer(nzBufferType type, GLuint id) { - if (s_buffersBinding[type] != id) + #ifdef NAZARA_DEBUG + if (!s_contextStates) + { + NazaraError("No context activated"); + return; + } + #endif + + if (s_contextStates->buffersBinding[type] != id) { glBindBuffer(BufferTarget[type], id); - s_buffersBinding[type] = id; + s_contextStates->buffersBinding[type] = id; } } void NzOpenGL::BindProgram(GLuint id) { - if (s_currentProgram != id) + #ifdef NAZARA_DEBUG + if (!s_contextStates) + { + NazaraError("No context activated"); + return; + } + #endif + + if (s_contextStates->currentProgram != id) { glUseProgram(id); - s_currentProgram = id; + s_contextStates->currentProgram = id; } } void NzOpenGL::BindTexture(nzImageType type, GLuint id) { - if (s_texturesBinding[s_textureUnit] != id) + #ifdef NAZARA_DEBUG + if (!s_contextStates) + { + NazaraError("No context activated"); + return; + } + #endif + + if (s_contextStates->texturesBinding[s_contextStates->textureUnit] != id) { glBindTexture(TextureTarget[type], id); - s_texturesBinding[s_textureUnit] = id; + s_contextStates->texturesBinding[s_contextStates->textureUnit] = id; } } void NzOpenGL::BindTexture(unsigned int textureUnit, nzImageType type, GLuint id) { - if (s_texturesBinding[textureUnit] != id) + #ifdef NAZARA_DEBUG + if (!s_contextStates) + { + NazaraError("No context activated"); + return; + } + #endif + + if (s_contextStates->texturesBinding[textureUnit] != id) { SetTextureUnit(textureUnit); glBindTexture(TextureTarget[type], id); - s_texturesBinding[textureUnit] = id; + s_contextStates->texturesBinding[textureUnit] = id; } } void NzOpenGL::BindVertexArray(GLuint id) { + #ifdef NAZARA_DEBUG + if (!s_contextStates) + { + NazaraError("No context activated"); + return; + } + #endif + // Je ne pense pas que ça soit une bonne idée de le mettre en cache, c'est un objet "spécial" glBindVertexArray(id); // On invalide les bindings des buffers (Overridés par le VertexArray) - std::memset(s_buffersBinding, 0, (nzBufferType_Max+1)*sizeof(GLuint)); + std::memset(s_contextStates->buffersBinding, 0, (nzBufferType_Max+1)*sizeof(GLuint)); } void NzOpenGL::DeleteBuffer(nzBufferType type, GLuint id) { + #ifdef NAZARA_DEBUG + if (!s_contextStates) + { + NazaraError("No context activated"); + return; + } + #endif + glDeleteBuffers(1, &id); - if (s_buffersBinding[type] == id) - s_buffersBinding[type] = 0; + if (s_contextStates->buffersBinding[type] == id) + s_contextStates->buffersBinding[type] = 0; } void NzOpenGL::DeleteProgram(GLuint id) { + #ifdef NAZARA_DEBUG + if (!s_contextStates) + { + NazaraError("No context activated"); + return; + } + #endif + glDeleteProgram(id); - if (s_currentProgram == id) - s_currentProgram = 0; + if (s_contextStates->currentProgram == id) + s_contextStates->currentProgram = 0; } void NzOpenGL::DeleteTexture(GLuint id) { + #ifdef NAZARA_DEBUG + if (!s_contextStates) + { + NazaraError("No context activated"); + return; + } + #endif + glDeleteTextures(1, &id); - for (GLuint& binding : s_texturesBinding) + for (GLuint& binding : s_contextStates->texturesBinding) { if (binding == id) binding = 0; @@ -311,12 +397,28 @@ void NzOpenGL::DeleteTexture(GLuint id) GLuint NzOpenGL::GetCurrentBuffer(nzBufferType type) { - return s_buffersBinding[type]; + #ifdef NAZARA_DEBUG + if (!s_contextStates) + { + NazaraError("No context activated"); + return 0; + } + #endif + + return s_contextStates->buffersBinding[type]; } GLuint NzOpenGL::GetCurrentProgram() { - return s_currentProgram; + #ifdef NAZARA_DEBUG + if (!s_contextStates) + { + NazaraError("No context activated"); + return 0; + } + #endif + + return s_contextStates->currentProgram; } NzOpenGLFunc NzOpenGL::GetEntry(const NzString& entryPoint) @@ -331,7 +433,15 @@ NzString NzOpenGL::GetRendererName() unsigned int NzOpenGL::GetTextureUnit() { - return s_textureUnit; + #ifdef NAZARA_DEBUG + if (!s_contextStates) + { + NazaraError("No context activated"); + return 0; + } + #endif + + return s_contextStates->textureUnit; } NzString NzOpenGL::GetVendorName() @@ -844,12 +954,8 @@ bool NzOpenGL::Initialize() return false; } - std::memset(s_buffersBinding, 0, (nzBufferType_Max+1)*sizeof(GLuint)); - std::memset(s_texturesBinding, 0, 32*sizeof(GLuint)); - - s_currentProgram = 0; s_rendererName = reinterpret_cast(glGetString(GL_RENDERER)); - s_textureUnit = 0; + s_contextStates = nullptr; s_vendorName = reinterpret_cast(glGetString(GL_VENDOR)); return true; @@ -872,10 +978,10 @@ bool NzOpenGL::IsSupported(const NzString& string) void NzOpenGL::SetTextureUnit(unsigned int textureUnit) { - if (s_textureUnit != textureUnit) + if (s_contextStates->textureUnit != textureUnit) { glActiveTexture(GL_TEXTURE0 + textureUnit); - s_textureUnit = textureUnit; + s_contextStates->textureUnit = textureUnit; } } @@ -1036,6 +1142,16 @@ void NzOpenGL::Uninitialize() } } +void NzOpenGL::OnContextDestruction(NzContext* context) +{ + s_contexts.erase(context); +} + +void NzOpenGL::OnContextChange(NzContext* newContext) +{ + s_contextStates = (newContext) ? &s_contexts[newContext] : nullptr; +} + GLenum NzOpenGL::Attachment[nzAttachmentPoint_Max+1] = { GL_COLOR_ATTACHMENT0, // nzAttachmentPoint_Color diff --git a/src/Nazara/Renderer/RenderWindow.cpp b/src/Nazara/Renderer/RenderWindow.cpp index 1e5e7a1fb..247b63041 100644 --- a/src/Nazara/Renderer/RenderWindow.cpp +++ b/src/Nazara/Renderer/RenderWindow.cpp @@ -59,7 +59,7 @@ bool NzRenderWindow::CopyToImage(NzImage* image) const } #endif - const NzContext* currentContext = NzContext::GetCurrent(); + NzContext* currentContext = NzContext::GetCurrent(); if (m_context != currentContext) { if (!m_context->SetActive(true)) @@ -112,7 +112,7 @@ bool NzRenderWindow::CopyToTexture(NzTexture* texture) const } #endif - const NzContext* currentContext = NzContext::GetCurrent(); + NzContext* currentContext = NzContext::GetCurrent(); if (m_context != currentContext) { if (!m_context->SetActive(true))