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); +}