From 9be802082f93bbcb14a192bd80998ed500af2bf9 Mon Sep 17 00:00:00 2001 From: baldurk Date: Thu, 11 Dec 2014 20:30:34 +0000 Subject: [PATCH] Add a vendor check to detect if FBOs or VAOs are actually shared * This lets us detect if the FBO/VAO behaviour is different from the main spec, and so we won't miss deletes or other events if the context is different since we'll treat them as shared like any other object. --- renderdoc/driver/gl/gl_common.cpp | 80 +++++++++++++++++--------- renderdoc/driver/gl/gl_common.h | 8 ++- renderdoc/driver/gl/gl_driver.cpp | 2 +- renderdoc/driver/gl/gl_manager.cpp | 6 +- renderdoc/driver/gl/gl_renderstate.cpp | 2 +- renderdoc/driver/gl/gl_resources.h | 4 +- renderdoc/driver/gl/gl_shader_refl.cpp | 2 +- renderdoc/hooks/gl_linux_hooks.cpp | 50 ++++++++++++++++ renderdoc/hooks/gl_win32_hooks.cpp | 36 ++++++++++++ 9 files changed, 153 insertions(+), 37 deletions(-) diff --git a/renderdoc/driver/gl/gl_common.cpp b/renderdoc/driver/gl/gl_common.cpp index 30430883b..27ebbab2b 100644 --- a/renderdoc/driver/gl/gl_common.cpp +++ b/renderdoc/driver/gl/gl_common.cpp @@ -43,21 +43,24 @@ namespace TrackedResource } }; -namespace ExtensionSupport -{ - static bool extensions[ExtensionSupported_Count]; - static bool VendorChecks[VendorCheck_Count]; -}; +bool ExtensionSupported[ExtensionSupported_Count]; +bool VendorCheck[VendorCheck_Count]; int GLCoreVersion = 0; -void DoVendorChecks(const GLHookSet &gl) +// simple wrapper for OS functions to make/delete a context +GLWindowingData MakeContext(GLWindowingData share); +void DeleteContext(GLWindowingData context); + +void MakeContextCurrent(GLWindowingData data); + +void DoVendorChecks(const GLHookSet &gl, GLWindowingData context) { GLint numExts = 0; if(gl.glGetIntegerv) gl.glGetIntegerv(eGL_NUM_EXTENSIONS, &numExts); - RDCEraseEl(ExtensionSupport::extensions); - RDCEraseEl(ExtensionSupport::VendorChecks); + RDCEraseEl(ExtensionSupported); + RDCEraseEl(VendorCheck); if(gl.glGetStringi) { @@ -69,7 +72,7 @@ void DoVendorChecks(const GLHookSet &gl) ext += 3; -#define EXT_CHECK(extname) if(!strcmp(ext, STRINGIZE(extname))) ExtensionSupport::extensions[CONCAT(ExtensionSupported_, extname)] = true; +#define EXT_CHECK(extname) if(!strcmp(ext, STRINGIZE(extname))) ExtensionSupported[CONCAT(ExtensionSupported_, extname)] = true; EXT_CHECK(ARB_clip_control); EXT_CHECK(ARB_enhanced_layouts); @@ -106,7 +109,7 @@ void DoVendorChecks(const GLHookSet &gl) if(err != eGL_NONE) { // if we got an error trying to query that, we should enable this hack - ExtensionSupport::VendorChecks[VendorCheck_AMD_vertex_buffer_query] = true; + VendorCheck[VendorCheck_AMD_vertex_buffer_query] = true; RDCWARN("Using AMD hack to avoid GL_VERTEX_BINDING_BUFFER"); } @@ -142,11 +145,11 @@ void DoVendorChecks(const GLHookSet &gl) if(compSize == 8) { - ExtensionSupport::VendorChecks[VendorCheck_EXT_compressed_cube_size] = false; + VendorCheck[VendorCheck_EXT_compressed_cube_size] = false; } else if(compSize == 48) { - ExtensionSupport::VendorChecks[VendorCheck_EXT_compressed_cube_size] = true; + VendorCheck[VendorCheck_EXT_compressed_cube_size] = true; } else { @@ -156,20 +159,45 @@ void DoVendorChecks(const GLHookSet &gl) gl.glDeleteTextures(1, &dummy); } + // only do this when we have a proper context e.g. on windows where an old + // context is first created. Check to see if FBOs or VAOs are shared between + // contexts. + if(GLCoreVersion >= 32 && + gl.glGenVertexArrays && gl.glBindVertexArray && gl.glDeleteVertexArrays && + gl.glGenFramebuffers && gl.glBindFramebuffer && gl.glDeleteFramebuffers) + { + // gen & create an FBO and VAO + GLuint fbo = 0; + GLuint vao = 0; + gl.glGenFramebuffers(1, &fbo); + gl.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, fbo); + gl.glGenVertexArrays(1, &vao); + gl.glBindVertexArray(vao); + + // make a context that shares with the current one, and switch to it + GLWindowingData child = MakeContext(context); + + if(child.ctx) + { + // switch to child + MakeContextCurrent(child); + + // these shouldn't be visible + VendorCheck[VendorCheck_EXT_fbo_shared] = (gl.glIsFramebuffer(fbo) != GL_FALSE); + VendorCheck[VendorCheck_EXT_vao_shared] = (gl.glIsVertexArray(vao) != GL_FALSE); + + // switch back to context + MakeContextCurrent(context); + + DeleteContext(child); + } + + gl.glDeleteFramebuffers(1, &fbo); + gl.glDeleteVertexArrays(1, &vao); + } + // don't have a test for this, just have to enable it all the time, for now. - ExtensionSupport::VendorChecks[VendorCheck_NV_avoid_D32S8_copy] = true; -} - -bool ExtensionSupported(ExtensionCheckEnum ext) -{ - if(ext < 0 || ext >= ExtensionSupported_Count) return false; - return ExtensionSupport::extensions[ext]; -} - -bool VendorCheck(VendorCheckEnum vc) -{ - if(vc < 0 || vc >= VendorCheck_Count) return false; - return ExtensionSupport::VendorChecks[vc]; + VendorCheck[VendorCheck_NV_avoid_D32S8_copy] = true; } size_t BufferIdx(GLenum buf) @@ -311,7 +339,7 @@ GLuint GetBoundVertexBuffer(const GLHookSet &gl, GLuint i) { GLuint buffer = 0; - if(VendorCheck(VendorCheck_AMD_vertex_buffer_query)) + if(VendorCheck[VendorCheck_AMD_vertex_buffer_query]) gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, (GLint *)&buffer); else gl.glGetIntegeri_v(eGL_VERTEX_BINDING_BUFFER, i, (GLint *)&buffer); diff --git a/renderdoc/driver/gl/gl_common.h b/renderdoc/driver/gl/gl_common.h index 4e59af195..ad3a2527c 100644 --- a/renderdoc/driver/gl/gl_common.h +++ b/renderdoc/driver/gl/gl_common.h @@ -98,7 +98,7 @@ enum ExtensionCheckEnum ExtensionSupported_ARB_clip_control, ExtensionSupported_Count, }; -bool ExtensionSupported(ExtensionCheckEnum ext); +extern bool ExtensionSupported[ExtensionSupported_Count]; // for some things we need to know how a specific implementation behaves to work around it // or adjust things. We centralise that here (similar to extensions) @@ -107,12 +107,14 @@ enum VendorCheckEnum VendorCheck_AMD_vertex_buffer_query, VendorCheck_EXT_compressed_cube_size, VendorCheck_NV_avoid_D32S8_copy, + VendorCheck_EXT_fbo_shared, + VendorCheck_EXT_vao_shared, VendorCheck_Count, }; -bool VendorCheck(VendorCheckEnum ext); +extern bool VendorCheck[VendorCheck_Count]; // fills out the extension supported array and the version-specific checks above -void DoVendorChecks(const GLHookSet &gl); +void DoVendorChecks(const GLHookSet &gl, GLWindowingData context); #include "serialise/serialiser.h" #include "core/core.h" diff --git a/renderdoc/driver/gl/gl_driver.cpp b/renderdoc/driver/gl/gl_driver.cpp index 7b57461b1..f0841efca 100644 --- a/renderdoc/driver/gl/gl_driver.cpp +++ b/renderdoc/driver/gl/gl_driver.cpp @@ -735,7 +735,7 @@ void WrappedOpenGL::ActivateContext(GLWindowingData winData) if(ver > GLCoreVersion) { GLCoreVersion = ver; - DoVendorChecks(gl); + DoVendorChecks(gl, winData); } } diff --git a/renderdoc/driver/gl/gl_manager.cpp b/renderdoc/driver/gl/gl_manager.cpp index 3b5b47b7d..2f3752df3 100644 --- a/renderdoc/driver/gl/gl_manager.cpp +++ b/renderdoc/driver/gl/gl_manager.cpp @@ -286,7 +286,7 @@ bool GLResourceManager::Prepare_InitialState(GLResource res) // nvidia specific. // In most cases a program isn't going to rely on the contents of a depth-stencil buffer (shadow maps that it might // require would be depth-only formatted). - if(details.internalFormat == eGL_DEPTH32F_STENCIL8 && VendorCheck(VendorCheck_NV_avoid_D32S8_copy)) + if(details.internalFormat == eGL_DEPTH32F_STENCIL8 && VendorCheck[VendorCheck_NV_avoid_D32S8_copy]) RDCDEBUG("Not fetching initial contents of D32F_S8 texture"); else gl.glCopyImageSubData(res.name, details.curType, i, 0, 0, 0, tex, details.curType, i, 0, 0, 0, w, h, d); @@ -573,7 +573,7 @@ bool GLResourceManager::Serialise_InitialState(GLResource res) // sometimes cubemaps return the compressed image size for the whole texture, but we read it // face by face - if(VendorCheck(VendorCheck_EXT_compressed_cube_size) && t == eGL_TEXTURE_CUBE_MAP) + if(VendorCheck[VendorCheck_EXT_compressed_cube_size] && t == eGL_TEXTURE_CUBE_MAP) size /= 6; byte *buf = new byte[size]; @@ -969,7 +969,7 @@ void GLResourceManager::Apply_InitialState(GLResource live, InitialContentData i // nvidia specific. // In most cases a program isn't going to rely on the contents of a depth-stencil buffer (shadow maps that it might // require would be depth-only formatted). - if(details.internalFormat == eGL_DEPTH32F_STENCIL8 && VendorCheck(VendorCheck_NV_avoid_D32S8_copy)) + if(details.internalFormat == eGL_DEPTH32F_STENCIL8 && VendorCheck[VendorCheck_NV_avoid_D32S8_copy]) RDCDEBUG("Not fetching initial contents of D32F_S8 texture"); else gl.glCopyImageSubData(tex, details.curType, i, 0, 0, 0, live.name, details.curType, i, 0, 0, 0, w, h, d); diff --git a/renderdoc/driver/gl/gl_renderstate.cpp b/renderdoc/driver/gl/gl_renderstate.cpp index 2c9a52ad5..8f05bdc2a 100644 --- a/renderdoc/driver/gl/gl_renderstate.cpp +++ b/renderdoc/driver/gl/gl_renderstate.cpp @@ -115,7 +115,7 @@ void GLRenderState::FetchState(void *ctx, WrappedOpenGL *gl) m_Real->glGetFloatv(eGL_POINT_SIZE, &PointSize); m_Real->glGetIntegerv(eGL_PRIMITIVE_RESTART_INDEX, (GLint *)&PrimitiveRestartIndex); - if(GLCoreVersion >= 45 || ExtensionSupported(ExtensionSupported_ARB_clip_control)) + if(GLCoreVersion >= 45 || ExtensionSupported[ExtensionSupported_ARB_clip_control]) { m_Real->glGetIntegerv(eGL_CLIP_ORIGIN, (GLint *)&ClipOrigin); m_Real->glGetIntegerv(eGL_CLIP_DEPTH_MODE, (GLint *)&ClipDepth); diff --git a/renderdoc/driver/gl/gl_resources.h b/renderdoc/driver/gl/gl_resources.h index 6aed45f67..851633e61 100644 --- a/renderdoc/driver/gl/gl_resources.h +++ b/renderdoc/driver/gl/gl_resources.h @@ -108,10 +108,10 @@ struct GLResource // for objects in non-shared contexts inline GLResource TextureRes(void *ctx, GLuint i) { (void)ctx; return GLResource(NULL, eResTexture, i); } inline GLResource SamplerRes(void *ctx, GLuint i) { (void)ctx; return GLResource(NULL, eResSampler, i); } -inline GLResource FramebufferRes(void *ctx, GLuint i) { return GLResource(ctx, eResFramebuffer, i); } +inline GLResource FramebufferRes(void *ctx, GLuint i) { return GLResource(VendorCheck[VendorCheck_EXT_fbo_shared] ? NULL : ctx, eResFramebuffer, i); } inline GLResource RenderbufferRes(void *ctx, GLuint i) { (void)ctx; return GLResource(NULL, eResRenderbuffer, i); } inline GLResource BufferRes(void *ctx, GLuint i) { (void)ctx; return GLResource(NULL, eResBuffer, i); } -inline GLResource VertexArrayRes(void *ctx, GLuint i) { return GLResource(ctx, eResVertexArray, i); } +inline GLResource VertexArrayRes(void *ctx, GLuint i) { return GLResource(VendorCheck[VendorCheck_EXT_vao_shared] ? NULL : ctx, eResVertexArray, i); } inline GLResource ShaderRes(void *ctx, GLuint i) { (void)ctx; return GLResource(NULL, eResShader, i); } inline GLResource ProgramRes(void *ctx, GLuint i) { (void)ctx; return GLResource(NULL, eResProgram, i); } inline GLResource ProgramPipeRes(void *ctx, GLuint i) { return GLResource(ctx, eResProgramPipe, i); } diff --git a/renderdoc/driver/gl/gl_shader_refl.cpp b/renderdoc/driver/gl/gl_shader_refl.cpp index 5443624db..1c284e4f9 100644 --- a/renderdoc/driver/gl/gl_shader_refl.cpp +++ b/renderdoc/driver/gl/gl_shader_refl.cpp @@ -900,7 +900,7 @@ void MakeShaderReflection(const GLHookSet &gl, GLenum shadType, GLuint sepProg, GLsizei numProps = (GLsizei)ARRAY_COUNT(props); // GL_LOCATION_COMPONENT not supported on core <4.4 (or without GL_ARB_enhanced_layouts) - if(!ExtensionSupported(ExtensionSupported_ARB_enhanced_layouts) && GLCoreVersion < 44) + if(!ExtensionSupported[ExtensionSupported_ARB_enhanced_layouts] && GLCoreVersion < 44) numProps--; gl.glGetProgramResourceiv(sepProg, sigEnum, i, numProps, props, numProps, NULL, values); diff --git a/renderdoc/hooks/gl_linux_hooks.cpp b/renderdoc/hooks/gl_linux_hooks.cpp index 3dde8f0f7..66b434181 100644 --- a/renderdoc/hooks/gl_linux_hooks.cpp +++ b/renderdoc/hooks/gl_linux_hooks.cpp @@ -298,6 +298,46 @@ class OpenGLHook : LibraryHook if(glXMakeCurrent_real) glXMakeCurrent_real(data.dpy, data.wnd, data.ctx); } + + GLWindowingData MakeContext(GLWindowingData share) + { + GLWindowingData ret = {0}; + if(glXCreateContextAttribsARB_real) + { + const int attribs[] = { + GLX_CONTEXT_MAJOR_VERSION_ARB, + 3, + GLX_CONTEXT_MINOR_VERSION_ARB, + 2, + GLX_CONTEXT_FLAGS_ARB, + 0, + 0, 0, + }; + + PFNGLXCHOOSEFBCONFIGPROC glXChooseFBConfigProc = (PFNGLXCHOOSEFBCONFIGPROC)dlsym(RTLD_NEXT, "glXChooseFBConfig"); + + if(glXChooseFBConfigProc) + { + // don't need to care about the fb config as we won't be using the default framebuffer (backbuffer) + int visAttribs[] = { 0 }; + int numCfgs = 0; + GLXFBConfig *fbcfg = glXChooseFBConfigProc(dpy, DefaultScreen(dpy), visAttribs, &numCfgs); + + if(fbcfg) + { + ret.dpy = share.dpy; + ret.ctx = glXCreateContextAttribsARB_real(share.dpy, fbcfg[0], share.ctx, false, attribs); + } + } + } + return ret; + } + + void DeleteContext(GLWindowingData context) + { + if(context.ctx && glXDestroyContext_real) + glXDestroyContext_real(context.dpy, context.ctx); + } WrappedOpenGL *GetDriver() { @@ -628,3 +668,13 @@ void MakeContextCurrent(GLWindowingData data) OpenGLHook::glhooks.MakeContextCurrent(data); } +GLWindowingData MakeContext(GLWindowingData share) +{ + return OpenGLHook::glhooks.MakeContext(share); +} + +void DeleteContext(GLWindowingData context) +{ + OpenGLHook::glhooks.DeleteContext(context); +} + diff --git a/renderdoc/hooks/gl_win32_hooks.cpp b/renderdoc/hooks/gl_win32_hooks.cpp index bbc1d6f14..75e856bcd 100644 --- a/renderdoc/hooks/gl_win32_hooks.cpp +++ b/renderdoc/hooks/gl_win32_hooks.cpp @@ -258,6 +258,32 @@ class OpenGLHook : LibraryHook if(wglMakeCurrent_hook()) wglMakeCurrent_hook()(data.DC, data.ctx); } + + GLWindowingData MakeContext(GLWindowingData share) + { + GLWindowingData ret = {0}; + if(wglCreateContextAttribsARB_realfunc) + { + const int attribs[] = { + WGL_CONTEXT_MAJOR_VERSION_ARB, + 3, + WGL_CONTEXT_MINOR_VERSION_ARB, + 2, + WGL_CONTEXT_FLAGS_ARB, + 0, + 0, 0, + }; + ret.DC = share.DC; + ret.ctx = wglCreateContextAttribsARB_realfunc(share.DC, share.ctx, attribs); + } + return ret; + } + + void DeleteContext(GLWindowingData context) + { + if(context.ctx && wglDeleteContext_hook()) + wglDeleteContext_hook()(context.ctx); + } private: WrappedOpenGL *GetDriver() @@ -650,3 +676,13 @@ void MakeContextCurrent(GLWindowingData data) { OpenGLHook::glhooks.MakeContextCurrent(data); } + +GLWindowingData MakeContext(GLWindowingData share) +{ + return OpenGLHook::glhooks.MakeContext(share); +} + +void DeleteContext(GLWindowingData context) +{ + OpenGLHook::glhooks.DeleteContext(context); +}