From b19cff8a08a03b39653ea16ec5f51a2c80c5f2d1 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 3 Dec 2014 23:24:58 -0800 Subject: [PATCH 1/5] OGL: Use a fixed VAO for attributeless rendering. Instead of abusing whatever VAO is previously bound, which might have enabled arrays. Only used in one instance currently, which fixes a crash with older NVIDIA drivers. --- Source/Core/VideoBackends/OGL/GLUtil.cpp | 31 +++++++++++++++++++ Source/Core/VideoBackends/OGL/GLUtil.h | 5 +++ .../Core/VideoBackends/OGL/PostProcessing.cpp | 2 ++ Source/Core/VideoBackends/OGL/Render.cpp | 2 ++ 4 files changed, 40 insertions(+) diff --git a/Source/Core/VideoBackends/OGL/GLUtil.cpp b/Source/Core/VideoBackends/OGL/GLUtil.cpp index bfd6170839..f91b079c3b 100644 --- a/Source/Core/VideoBackends/OGL/GLUtil.cpp +++ b/Source/Core/VideoBackends/OGL/GLUtil.cpp @@ -16,6 +16,8 @@ #include "VideoCommon/VideoConfig.h" cInterfaceBase *GLInterface; +static GLuint attributelessVAO = 0; +static GLuint attributelessVBO = 0; namespace OGL { @@ -113,3 +115,32 @@ GLuint OpenGL_CompileProgram(const char* vertexShader, const char* fragmentShade return programID; } +static void CreateAttributelessVAO() +{ + glGenVertexArrays(1, &attributelessVAO); + + // In a compatibility context, we require a valid, bound array buffer. + glGenBuffers(1, &attributelessVBO); + + // Initialize the buffer with nothing. + glBindBuffer(GL_ARRAY_BUFFER, attributelessVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat), nullptr, GL_STATIC_DRAW); + + // We must also define vertex attribute 0. + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr); +} + +void OpenGL_BindAttributelessVAO() +{ + if (attributelessVAO == 0) + CreateAttributelessVAO(); + + glBindVertexArray(attributelessVAO); + glBindBuffer(GL_ARRAY_BUFFER, attributelessVBO); +} + +void OpenGL_DeleteAttributelessVAO() +{ + glDeleteVertexArrays(1, &attributelessVAO); + glDeleteBuffers(1, &attributelessVBO); +} diff --git a/Source/Core/VideoBackends/OGL/GLUtil.h b/Source/Core/VideoBackends/OGL/GLUtil.h index 8bcfb06886..3d7e562971 100644 --- a/Source/Core/VideoBackends/OGL/GLUtil.h +++ b/Source/Core/VideoBackends/OGL/GLUtil.h @@ -18,6 +18,11 @@ void InitInterface(); // Helpers GLuint OpenGL_CompileProgram(const char *vertexShader, const char *fragmentShader); +// Binds (and creates, if necessary) a VAO and VBO suitable for attributeless rendering. +void OpenGL_BindAttributelessVAO(); +// Deletes any existing VAO / VBO that has been created. +void OpenGL_DeleteAttributelessVAO(); + // this should be removed in future, but as long as glsl is unstable, we should really read this messages #if defined(_DEBUG) || defined(DEBUGFAST) #define DEBUG_GLSL 1 diff --git a/Source/Core/VideoBackends/OGL/PostProcessing.cpp b/Source/Core/VideoBackends/OGL/PostProcessing.cpp index 80bdf8eef4..74fd93147b 100644 --- a/Source/Core/VideoBackends/OGL/PostProcessing.cpp +++ b/Source/Core/VideoBackends/OGL/PostProcessing.cpp @@ -72,6 +72,8 @@ void OpenGLPostProcessing::BlitFromTexture(TargetRectangle src, TargetRectangle if (m_attribute_workaround) glBindVertexArray(m_attribute_vao); + else + OpenGL_BindAttributelessVAO(); m_shader.Bind(); diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index f33c59899c..c14753039d 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -686,6 +686,8 @@ void Renderer::Shutdown() delete m_post_processor; m_post_processor = nullptr; + + OpenGL_DeleteAttributelessVAO(); } void Renderer::Init() From 0861cb874460e16691f52bfa6e2f60505e7de39d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 10 Dec 2014 20:11:48 -0800 Subject: [PATCH 2/5] OGL: Properly reset the attributeless VAO. --- Source/Core/VideoBackends/OGL/GLUtil.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Source/Core/VideoBackends/OGL/GLUtil.cpp b/Source/Core/VideoBackends/OGL/GLUtil.cpp index f91b079c3b..f9b3ccb844 100644 --- a/Source/Core/VideoBackends/OGL/GLUtil.cpp +++ b/Source/Core/VideoBackends/OGL/GLUtil.cpp @@ -143,4 +143,7 @@ void OpenGL_DeleteAttributelessVAO() { glDeleteVertexArrays(1, &attributelessVAO); glDeleteBuffers(1, &attributelessVBO); + + attributelessVAO = 0; + attributelessVBO = 0; } From 290fd545e688639057c7657050335c3bf5729331 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 10 Dec 2014 23:19:18 -0800 Subject: [PATCH 3/5] OGL: Bind the attributeless VAO before EFB copies. Fixes crashes in Zack & Wiki using an older NVIDIA driver. --- Source/Core/VideoBackends/OGL/GLUtil.cpp | 11 +++++++---- Source/Core/VideoBackends/OGL/TextureCache.cpp | 2 ++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Source/Core/VideoBackends/OGL/GLUtil.cpp b/Source/Core/VideoBackends/OGL/GLUtil.cpp index f9b3ccb844..d367c370bf 100644 --- a/Source/Core/VideoBackends/OGL/GLUtil.cpp +++ b/Source/Core/VideoBackends/OGL/GLUtil.cpp @@ -141,9 +141,12 @@ void OpenGL_BindAttributelessVAO() void OpenGL_DeleteAttributelessVAO() { - glDeleteVertexArrays(1, &attributelessVAO); - glDeleteBuffers(1, &attributelessVBO); + if (attributelessVAO) + { + glDeleteVertexArrays(1, &attributelessVAO); + glDeleteBuffers(1, &attributelessVBO); - attributelessVAO = 0; - attributelessVBO = 0; + attributelessVAO = 0; + attributelessVBO = 0; + } } diff --git a/Source/Core/VideoBackends/OGL/TextureCache.cpp b/Source/Core/VideoBackends/OGL/TextureCache.cpp index 49bfc98a55..f697d51c73 100644 --- a/Source/Core/VideoBackends/OGL/TextureCache.cpp +++ b/Source/Core/VideoBackends/OGL/TextureCache.cpp @@ -249,6 +249,8 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo { FramebufferManager::SetFramebuffer(framebuffer); + OpenGL_BindAttributelessVAO(); + glActiveTexture(GL_TEXTURE0+9); glBindTexture(GL_TEXTURE_2D_ARRAY, read_texture); From de2abbed17fdb6521b5973cb7544cd21977051c9 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 11 Dec 2014 01:00:37 -0800 Subject: [PATCH 4/5] OGL: Move attributeless VAO creation to Init. This way we won't trash an existing bound VBO by mistake. --- Source/Core/VideoBackends/OGL/GLUtil.cpp | 12 ++++++------ Source/Core/VideoBackends/OGL/GLUtil.h | 9 ++++++--- Source/Core/VideoBackends/OGL/Render.cpp | 2 ++ 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/Source/Core/VideoBackends/OGL/GLUtil.cpp b/Source/Core/VideoBackends/OGL/GLUtil.cpp index d367c370bf..dddc299fb9 100644 --- a/Source/Core/VideoBackends/OGL/GLUtil.cpp +++ b/Source/Core/VideoBackends/OGL/GLUtil.cpp @@ -115,12 +115,14 @@ GLuint OpenGL_CompileProgram(const char* vertexShader, const char* fragmentShade return programID; } -static void CreateAttributelessVAO() +void OpenGL_CreateAttributelessVAO() { glGenVertexArrays(1, &attributelessVAO); + _dbg_assert_msg_(VIDEO, attributelessVAO != 0, "Attributeless VAO should have been created successfully.") // In a compatibility context, we require a valid, bound array buffer. glGenBuffers(1, &attributelessVBO); + _dbg_assert_msg_(VIDEO, attributelessVBO != 0, "Attributeless VBO should have been created successfully.") // Initialize the buffer with nothing. glBindBuffer(GL_ARRAY_BUFFER, attributelessVBO); @@ -132,16 +134,14 @@ static void CreateAttributelessVAO() void OpenGL_BindAttributelessVAO() { - if (attributelessVAO == 0) - CreateAttributelessVAO(); - + _dbg_assert_msg_(VIDEO, attributelessVAO != 0, "Attributeless VAO should have already been created.") glBindVertexArray(attributelessVAO); - glBindBuffer(GL_ARRAY_BUFFER, attributelessVBO); } void OpenGL_DeleteAttributelessVAO() { - if (attributelessVAO) + _dbg_assert_msg_(VIDEO, attributelessVAO != 0, "Attributeless VAO should have already been created.") + if (attributelessVAO != 0) { glDeleteVertexArrays(1, &attributelessVAO); glDeleteBuffers(1, &attributelessVBO); diff --git a/Source/Core/VideoBackends/OGL/GLUtil.h b/Source/Core/VideoBackends/OGL/GLUtil.h index 3d7e562971..13052be293 100644 --- a/Source/Core/VideoBackends/OGL/GLUtil.h +++ b/Source/Core/VideoBackends/OGL/GLUtil.h @@ -18,11 +18,14 @@ void InitInterface(); // Helpers GLuint OpenGL_CompileProgram(const char *vertexShader, const char *fragmentShader); -// Binds (and creates, if necessary) a VAO and VBO suitable for attributeless rendering. -void OpenGL_BindAttributelessVAO(); -// Deletes any existing VAO / VBO that has been created. +// Creates and deletes a VAO and VBO suitable for attributeless rendering. +// Called by the Renderer. +void OpenGL_CreateAttributelessVAO(); void OpenGL_DeleteAttributelessVAO(); +// Binds the VAO suitable for attributeless rendering. +void OpenGL_BindAttributelessVAO(); + // this should be removed in future, but as long as glsl is unstable, we should really read this messages #if defined(_DEBUG) || defined(DEBUGFAST) #define DEBUG_GLSL 1 diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index c14753039d..853711dc18 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -714,6 +714,8 @@ void Renderer::Init() " ocol0 = c;\n" "}\n"); + OpenGL_CreateAttributelessVAO(); + // creating buffers glGenBuffers(1, &s_ShowEFBCopyRegions_VBO); glGenVertexArrays(1, &s_ShowEFBCopyRegions_VAO); From 029f8c3c3f065de723a1a334f70d2882208b7cdf Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 11 Dec 2014 09:42:49 -0800 Subject: [PATCH 5/5] OGL: Ensure a VAO is bound for all attributeless. Unfortunately, some of these cases are not well tested, because I don't know how to reproduce them. --- Source/Core/VideoBackends/OGL/FramebufferManager.cpp | 2 ++ Source/Core/VideoBackends/OGL/TextureConverter.cpp | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/Source/Core/VideoBackends/OGL/FramebufferManager.cpp b/Source/Core/VideoBackends/OGL/FramebufferManager.cpp index c458b79dc6..1089884b96 100644 --- a/Source/Core/VideoBackends/OGL/FramebufferManager.cpp +++ b/Source/Core/VideoBackends/OGL/FramebufferManager.cpp @@ -373,6 +373,8 @@ void FramebufferManager::ReinterpretPixelData(unsigned int convtype) { g_renderer->ResetAPIState(); + OpenGL_BindAttributelessVAO(); + GLuint src_texture = 0; // We aren't allowed to render and sample the same texture in one draw call, diff --git a/Source/Core/VideoBackends/OGL/TextureConverter.cpp b/Source/Core/VideoBackends/OGL/TextureConverter.cpp index 8753b58e8a..6384991ceb 100644 --- a/Source/Core/VideoBackends/OGL/TextureConverter.cpp +++ b/Source/Core/VideoBackends/OGL/TextureConverter.cpp @@ -222,6 +222,8 @@ static void EncodeToRamUsingShader(GLuint srcTexture, // attach render buffer as color destination FramebufferManager::SetFramebuffer(s_texConvFrameBuffer[0]); + OpenGL_BindAttributelessVAO(); + // set source texture glActiveTexture(GL_TEXTURE0+9); glBindTexture(GL_TEXTURE_2D_ARRAY, srcTexture); @@ -362,6 +364,8 @@ void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTextur g_renderer->ResetAPIState(); // reset any game specific settings + OpenGL_BindAttributelessVAO(); + // switch to texture converter frame buffer // attach destTexture as color destination FramebufferManager::SetFramebuffer(s_texConvFrameBuffer[1]);