diff --git a/docs/FAQ.aml b/docs/FAQ.aml index 1493ae232..680cfaf2a 100644 --- a/docs/FAQ.aml +++ b/docs/FAQ.aml @@ -341,5 +341,27 @@ +
+ RenderDoc is complaining about my OpenGL app in the overlay - what gives? + + + The first thing to remember is that RenderDoc only supports Core 3.2 and above OpenGL. + If your app is using features from before 3.2 it almost certainly won't work as most functionality + is not supported. A couple of things like not creating a VAO (which are required in core profile) and + luminance textures (which don't exist in core profile) are allowed, but none of the fixed function + pipeline will work, etc etc. + + + If your app is not using the CreateContextAttribs API then RenderDoc will completely refuse to capture, + and will display overlay text to this effect using the simplest fixed-function pipeline code, so it will + run on any OpenGL app, even on a 1.4 context or similar. + + + If your app did use the CreateContextAttribs API, RenderDoc will allow you to capture, but compatibility + profiles will have a warning displayed in the overlay - this is because you could easily use old functionality + as it is all still available in the context. + + +
diff --git a/renderdoc/driver/d3d11/d3d11_device.cpp b/renderdoc/driver/d3d11/d3d11_device.cpp index a0a551f11..485c2eeef 100644 --- a/renderdoc/driver/d3d11/d3d11_device.cpp +++ b/renderdoc/driver/d3d11/d3d11_device.cpp @@ -3074,13 +3074,11 @@ HRESULT WrappedID3D11Device::Present(IDXGISwapChain *swap, UINT SyncInterval, UI if(overlay & eOverlay_FrameNumber) { - if(!overlayText.empty()) overlayText += " "; - overlayText += StringFormat::Fmt("Frame: %d.", m_FrameCounter); + overlayText += StringFormat::Fmt(" Frame: %d.", m_FrameCounter); } if(overlay & eOverlay_FrameRate) { - if(!overlayText.empty()) overlayText += " "; - overlayText += StringFormat::Fmt("%.2lf ms (%.2lf .. %.2lf) (%.0lf FPS)", + overlayText += StringFormat::Fmt(" %.2lf ms (%.2lf .. %.2lf) (%.0lf FPS)", m_AvgFrametime, m_MinFrametime, m_MaxFrametime, 1000.0f/m_AvgFrametime); } diff --git a/renderdoc/driver/gl/gl_common.h b/renderdoc/driver/gl/gl_common.h index 2ac62dfad..a1ae4aba5 100644 --- a/renderdoc/driver/gl/gl_common.h +++ b/renderdoc/driver/gl/gl_common.h @@ -71,6 +71,13 @@ struct GLWindowingData #define IMPLEMENT_FUNCTION_SERIALISED(ret, func) ret func; bool CONCAT(Serialise_, func); +// no longer in glcorearb.h or glext.h +const GLenum eGL_LUMINANCE = (GLenum)0x1909; +const GLenum eGL_LUMINANCE_ALPHA = (GLenum)0x190A; +const GLenum eGL_INTENSITY = (GLenum)0x8049; +const GLenum eGL_LIGHTING = (GLenum)0x0B50; +const GLenum eGL_ALPHA_TEST = (GLenum)0x0BC0; + class WrappedOpenGL; struct GLHookSet; diff --git a/renderdoc/driver/gl/gl_driver.cpp b/renderdoc/driver/gl/gl_driver.cpp index 8292bdc23..984ed2037 100644 --- a/renderdoc/driver/gl/gl_driver.cpp +++ b/renderdoc/driver/gl/gl_driver.cpp @@ -39,6 +39,13 @@ #include +const int firstChar = int(' ') + 1; +const int lastChar = 127; +const int numChars = lastChar-firstChar; +const float charPixelHeight = 20.0f; + +stbtt_bakedchar chardata[numChars]; + const char *GLChunkNames[] = { "WrappedOpenGL::Initialisation", @@ -915,6 +922,11 @@ WrappedOpenGL::ContextData &WrappedOpenGL::GetCtxData() // defined in gl__hooks.cpp void MakeContextCurrent(GLWindowingData data); +// for 'backwards compatible' overlay rendering +bool immediateBegin(GLenum mode, float width, float height); +void immediateVert(float x, float y, float u, float v); +void immediateEnd(); + //////////////////////////////////////////////////////////////// // Windowing/setup/etc //////////////////////////////////////////////////////////////// @@ -940,13 +952,14 @@ void WrappedOpenGL::DeleteContext(void *contextHandle) m_ContextData.erase(contextHandle); } -void WrappedOpenGL::CreateContext(GLWindowingData winData, void *shareContext, GLInitParams initParams, bool core) +void WrappedOpenGL::CreateContext(GLWindowingData winData, void *shareContext, GLInitParams initParams, bool core, bool attribsCreate) { // TODO: support multiple GL contexts more explicitly m_InitParams = initParams; ContextData &ctxdata = m_ContextData[winData.ctx]; ctxdata.isCore = core; + ctxdata.attribsCreate = attribsCreate; } void WrappedOpenGL::ActivateContext(GLWindowingData winData) @@ -1051,6 +1064,8 @@ void WrappedOpenGL::ActivateContext(GLWindowingData winData) int ver = mj*10 + mn; + ctxdata.version = ver; + if(ver > GLCoreVersion || (!GLIsCore && ctxdata.isCore)) { GLCoreVersion = ver; @@ -1059,37 +1074,20 @@ void WrappedOpenGL::ActivateContext(GLWindowingData winData) } } - if(gl.glGenTextures && gl.glTextureStorage2DEXT && gl.glTextureSubImage2DEXT && - gl.glGenVertexArrays && gl.glBindVertexArray && - gl.glGenBuffers && gl.glNamedBufferStorageEXT && - gl.glCreateShader && gl.glShaderSource && gl.glCompileShader && gl.glGetShaderiv && gl.glGetShaderInfoLog && gl.glDeleteShader && - gl.glCreateProgram && gl.glAttachShader && gl.glLinkProgram && gl.glGetProgramiv && gl.glGetProgramInfoLog) + // to let us display the overlay on old GL contexts, use as simple a subset of functionality as possible + // to upload the texture. VAO and shaders are used optionally on modern contexts, otherwise we fall back + // to immediate mode rendering by hand + if(gl.glGetIntegerv && gl.glGenTextures && gl.glBindTexture && gl.glTexImage2D && gl.glTexParameteri) { - gl.glGenTextures(1, &ctxdata.GlyphTexture); - gl.glTextureStorage2DEXT(ctxdata.GlyphTexture, eGL_TEXTURE_2D, 1, eGL_R8, FONT_TEX_WIDTH, FONT_TEX_HEIGHT); - - GLuint curvao = 0; - gl.glGetIntegerv(eGL_VERTEX_ARRAY_BINDING, (GLint *)&curvao); - - gl.glGenVertexArrays(1, &ctxdata.DummyVAO); - gl.glBindVertexArray(ctxdata.DummyVAO); - string ttfstring = GetEmbeddedResource(sourcecodepro_ttf); byte *ttfdata = (byte *)ttfstring.c_str(); - const int firstChar = int(' ') + 1; - const int lastChar = 127; - const int numChars = lastChar-firstChar; - byte *buf = new byte[FONT_TEX_WIDTH * FONT_TEX_HEIGHT]; - const float pixelHeight = 20.0f; + stbtt_BakeFontBitmap(ttfdata, 0, charPixelHeight, buf, FONT_TEX_WIDTH, FONT_TEX_HEIGHT, firstChar, numChars, chardata); - stbtt_bakedchar chardata[numChars]; - int ret = stbtt_BakeFontBitmap(ttfdata, 0, pixelHeight, buf, FONT_TEX_WIDTH, FONT_TEX_HEIGHT, firstChar, numChars, chardata); - - ctxdata.CharSize = pixelHeight; - ctxdata.CharAspect = chardata->xadvance / pixelHeight; + ctxdata.CharSize = charPixelHeight; + ctxdata.CharAspect = chardata->xadvance / charPixelHeight; stbtt_fontinfo f = {0}; stbtt_InitFont(&f, ttfdata, 0); @@ -1097,10 +1095,24 @@ void WrappedOpenGL::ActivateContext(GLWindowingData winData) int ascent = 0; stbtt_GetFontVMetrics(&f, &ascent, NULL, NULL); - float maxheight = float(ascent)*stbtt_ScaleForPixelHeight(&f, pixelHeight); + float maxheight = float(ascent)*stbtt_ScaleForPixelHeight(&f, charPixelHeight); - gl.glTextureSubImage2DEXT(ctxdata.GlyphTexture, eGL_TEXTURE_2D, 0, 0, 0, FONT_TEX_WIDTH, FONT_TEX_HEIGHT, - eGL_RED, eGL_UNSIGNED_BYTE, (void *)buf); + { + GLuint curtex = 0; + gl.glGetIntegerv(eGL_TEXTURE_BINDING_2D, (GLint *)&curtex); + + GLenum texFmt = eGL_R8; + if(ctxdata.Legacy()) + texFmt = eGL_LUMINANCE; + + gl.glGenTextures(1, &ctxdata.GlyphTexture); + gl.glBindTexture(eGL_TEXTURE_2D, ctxdata.GlyphTexture); + gl.glTexImage2D(eGL_TEXTURE_2D, 0, texFmt, FONT_TEX_WIDTH, FONT_TEX_HEIGHT, 0, eGL_RED, eGL_UNSIGNED_BYTE, buf); + gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_MAG_FILTER, eGL_LINEAR); + gl.glTexParameteri(eGL_TEXTURE_2D, eGL_TEXTURE_MIN_FILTER, eGL_LINEAR); + + gl.glBindTexture(eGL_TEXTURE_2D, curtex); + } delete[] buf; @@ -1113,72 +1125,97 @@ void WrappedOpenGL::ActivateContext(GLWindowingData winData) float x = b->xoff; float y = b->yoff + maxheight; - glyphData[(i+1)*2 + 0] = Vec4f(x/b->xadvance, y/pixelHeight, b->xadvance/float(b->x1 - b->x0), pixelHeight/float(b->y1 - b->y0)); + glyphData[(i+1)*2 + 0] = Vec4f(x/b->xadvance, y/charPixelHeight, b->xadvance/float(b->x1 - b->x0), charPixelHeight/float(b->y1 - b->y0)); glyphData[(i+1)*2 + 1] = Vec4f(b->x0, b->y0, b->x1, b->y1); } - gl.glGenBuffers(1, &ctxdata.GlyphUBO); - gl.glNamedBufferStorageEXT(ctxdata.GlyphUBO, sizeof(glyphData), glyphData, 0); - - gl.glGenBuffers(1, &ctxdata.GeneralUBO); - gl.glNamedBufferStorageEXT(ctxdata.GeneralUBO, sizeof(FontUniforms), NULL, GL_MAP_WRITE_BIT); - - gl.glGenBuffers(1, &ctxdata.StringUBO); - gl.glNamedBufferStorageEXT(ctxdata.StringUBO, sizeof(uint32_t)*4*FONT_MAX_CHARS, NULL, GL_MAP_WRITE_BIT); - - string textvs = "#version 420 core\n\n"; - textvs += GetEmbeddedResource(debuguniforms_h); - textvs += GetEmbeddedResource(text_vert); - string textfs = GetEmbeddedResource(text_frag); - - GLuint vs = gl.glCreateShader(eGL_VERTEX_SHADER); - GLuint fs = gl.glCreateShader(eGL_FRAGMENT_SHADER); - - const char *src = textvs.c_str(); - gl.glShaderSource(vs, 1, &src, NULL); - src = textfs.c_str(); - gl.glShaderSource(fs, 1, &src, NULL); - - gl.glCompileShader(vs); - gl.glCompileShader(fs); - - char buffer[1024] = {0}; - GLint status = 0; - - gl.glGetShaderiv(vs, eGL_COMPILE_STATUS, &status); - if(status == 0) + if(ctxdata.Modern() && gl.glGenVertexArrays && gl.glBindVertexArray) { - gl.glGetShaderInfoLog(vs, 1024, NULL, buffer); - RDCERR("Shader error: %s", buffer); + GLuint curvao = 0; + gl.glGetIntegerv(eGL_VERTEX_ARRAY_BINDING, (GLint *)&curvao); + + gl.glGenVertexArrays(1, &ctxdata.DummyVAO); + gl.glBindVertexArray(ctxdata.DummyVAO); + + gl.glBindVertexArray(curvao); } - gl.glGetShaderiv(fs, eGL_COMPILE_STATUS, &status); - if(status == 0) + if(ctxdata.Modern() && gl.glGenBuffers && gl.glBufferData && gl.glBindBuffer) { - gl.glGetShaderInfoLog(fs, 1024, NULL, buffer); - RDCERR("Shader error: %s", buffer); + GLuint curubo = 0; + gl.glGetIntegerv(eGL_UNIFORM_BUFFER_BINDING, (GLint *)&curubo); + + gl.glGenBuffers(1, &ctxdata.GlyphUBO); + gl.glBindBuffer(eGL_UNIFORM_BUFFER, ctxdata.GlyphUBO); + gl.glBufferData(eGL_UNIFORM_BUFFER, sizeof(glyphData), glyphData, eGL_STATIC_DRAW); + + gl.glGenBuffers(1, &ctxdata.GeneralUBO); + gl.glBindBuffer(eGL_UNIFORM_BUFFER, ctxdata.GeneralUBO); + gl.glBufferData(eGL_UNIFORM_BUFFER, sizeof(FontUniforms), NULL, eGL_DYNAMIC_DRAW); + + gl.glGenBuffers(1, &ctxdata.StringUBO); + gl.glBindBuffer(eGL_UNIFORM_BUFFER, ctxdata.StringUBO); + gl.glBufferData(eGL_UNIFORM_BUFFER, sizeof(uint32_t)*4*FONT_MAX_CHARS, NULL, eGL_DYNAMIC_DRAW); + + gl.glBindBuffer(eGL_UNIFORM_BUFFER, curubo); } - ctxdata.Program = gl.glCreateProgram(); - - gl.glAttachShader(ctxdata.Program, vs); - gl.glAttachShader(ctxdata.Program, fs); - - gl.glLinkProgram(ctxdata.Program); - - gl.glGetProgramiv(ctxdata.Program, eGL_LINK_STATUS, &status); - if(status == 0) + if(ctxdata.Modern() && + gl.glCreateShader && gl.glShaderSource && gl.glCompileShader && gl.glGetShaderiv && gl.glGetShaderInfoLog && gl.glDeleteShader && + gl.glCreateProgram && gl.glAttachShader && gl.glLinkProgram && gl.glGetProgramiv && gl.glGetProgramInfoLog) { - gl.glGetProgramInfoLog(ctxdata.Program, 1024, NULL, buffer); - RDCERR("Link error: %s", buffer); - } + string textvs = "#version 420 core\n\n"; + textvs += GetEmbeddedResource(debuguniforms_h); + textvs += GetEmbeddedResource(text_vert); + string textfs = GetEmbeddedResource(text_frag); - gl.glDeleteShader(vs); - gl.glDeleteShader(fs); + GLuint vs = gl.glCreateShader(eGL_VERTEX_SHADER); + GLuint fs = gl.glCreateShader(eGL_FRAGMENT_SHADER); + + const char *src = textvs.c_str(); + gl.glShaderSource(vs, 1, &src, NULL); + src = textfs.c_str(); + gl.glShaderSource(fs, 1, &src, NULL); + + gl.glCompileShader(vs); + gl.glCompileShader(fs); + + char buffer[1024] = {0}; + GLint status = 0; + + gl.glGetShaderiv(vs, eGL_COMPILE_STATUS, &status); + if(status == 0) + { + gl.glGetShaderInfoLog(vs, 1024, NULL, buffer); + RDCERR("Shader error: %s", buffer); + } + + gl.glGetShaderiv(fs, eGL_COMPILE_STATUS, &status); + if(status == 0) + { + gl.glGetShaderInfoLog(fs, 1024, NULL, buffer); + RDCERR("Shader error: %s", buffer); + } + + ctxdata.Program = gl.glCreateProgram(); + + gl.glAttachShader(ctxdata.Program, vs); + gl.glAttachShader(ctxdata.Program, fs); + + gl.glLinkProgram(ctxdata.Program); + + gl.glGetProgramiv(ctxdata.Program, eGL_LINK_STATUS, &status); + if(status == 0) + { + gl.glGetProgramInfoLog(ctxdata.Program, 1024, NULL, buffer); + RDCERR("Link error: %s", buffer); + } + + gl.glDeleteShader(vs); + gl.glDeleteShader(fs); + } ctxdata.ready = true; - - gl.glBindVertexArray(curvao); } } } @@ -1202,23 +1239,46 @@ struct RenderTextState GLenum SourceRGB, SourceAlpha; GLenum DestinationRGB, DestinationAlpha; GLenum PolygonMode; - GLfloat Viewport[4]; + GLfloat Viewportf[4]; + GLint Viewport[4]; GLenum ActiveTexture; GLuint tex0; GLuint ubo[3]; GLuint prog; + GLuint pipe; GLuint VAO; - void Push(const GLHookSet &gl) + // if this context wasn't created with CreateContextAttribs we + // do an immediate mode render, so fewer states are pushed/popped. + // note we don't assume a 1.0 context since that would be painful to + // handle. Instead we just skip bits of state we're not going to mess + // with. In some cases this might cause problems e.g. we don't use + // indexed enable states for blend and scissor test because we're + // assuming there's no separate blending. + // + // In the end, this is just a best-effort to keep going without + // crashing. Old GL versions aren't supported. + void Push(const GLHookSet &gl, bool modern) { - enableBits[0] = gl.glIsEnabledi(eGL_BLEND, 0) != 0; - enableBits[1] = gl.glIsEnabled(eGL_DEPTH_TEST) != 0; - enableBits[2] = gl.glIsEnabled(eGL_DEPTH_CLAMP) != 0; - enableBits[3] = gl.glIsEnabled(eGL_STENCIL_TEST) != 0; - enableBits[4] = gl.glIsEnabled(eGL_CULL_FACE) != 0; - enableBits[5] = gl.glIsEnabledi(eGL_SCISSOR_TEST, 0) != 0; - - if(GLCoreVersion >= 45 || ExtensionSupported[ExtensionSupported_ARB_clip_control]) + enableBits[0] = gl.glIsEnabled(eGL_DEPTH_TEST) != 0; + enableBits[1] = gl.glIsEnabled(eGL_STENCIL_TEST) != 0; + enableBits[2] = gl.glIsEnabled(eGL_CULL_FACE) != 0; + if(modern) + { + enableBits[3] = gl.glIsEnabled(eGL_DEPTH_CLAMP) != 0; + enableBits[4] = gl.glIsEnabledi(eGL_BLEND, 0) != 0; + enableBits[5] = gl.glIsEnabledi(eGL_SCISSOR_TEST, 0) != 0; + } + else + { + enableBits[3] = gl.glIsEnabled(eGL_BLEND) != 0; + enableBits[4] = gl.glIsEnabled(eGL_SCISSOR_TEST) != 0; + enableBits[5] = gl.glIsEnabled(eGL_TEXTURE_2D) != 0; + enableBits[6] = gl.glIsEnabled(eGL_LIGHTING) != 0; + enableBits[7] = gl.glIsEnabled(eGL_ALPHA_TEST) != 0; + } + + if(modern && (GLCoreVersion >= 45 || ExtensionSupported[ExtensionSupported_ARB_clip_control])) { gl.glGetIntegerv(eGL_CLIP_ORIGIN, (GLint *)&ClipOrigin); gl.glGetIntegerv(eGL_CLIP_DEPTH_MODE, (GLint *)&ClipDepth); @@ -1229,15 +1289,29 @@ struct RenderTextState ClipDepth = eGL_NEGATIVE_ONE_TO_ONE; } - gl.glGetIntegeri_v(eGL_BLEND_EQUATION_RGB, 0, (GLint*)&EquationRGB); - gl.glGetIntegeri_v(eGL_BLEND_EQUATION_ALPHA, 0, (GLint*)&EquationAlpha); + if(modern) + { + gl.glGetIntegeri_v(eGL_BLEND_EQUATION_RGB, 0, (GLint*)&EquationRGB); + gl.glGetIntegeri_v(eGL_BLEND_EQUATION_ALPHA, 0, (GLint*)&EquationAlpha); - gl.glGetIntegeri_v(eGL_BLEND_SRC_RGB, 0, (GLint*)&SourceRGB); - gl.glGetIntegeri_v(eGL_BLEND_SRC_ALPHA, 0, (GLint*)&SourceAlpha); + gl.glGetIntegeri_v(eGL_BLEND_SRC_RGB, 0, (GLint*)&SourceRGB); + gl.glGetIntegeri_v(eGL_BLEND_SRC_ALPHA, 0, (GLint*)&SourceAlpha); + + gl.glGetIntegeri_v(eGL_BLEND_DST_RGB, 0, (GLint*)&DestinationRGB); + gl.glGetIntegeri_v(eGL_BLEND_DST_ALPHA, 0, (GLint*)&DestinationAlpha); + } + else + { + gl.glGetIntegerv(eGL_BLEND_EQUATION_RGB, (GLint*)&EquationRGB); + gl.glGetIntegerv(eGL_BLEND_EQUATION_ALPHA, (GLint*)&EquationAlpha); + + gl.glGetIntegerv(eGL_BLEND_SRC_RGB, (GLint*)&SourceRGB); + gl.glGetIntegerv(eGL_BLEND_SRC_ALPHA, (GLint*)&SourceAlpha); + + gl.glGetIntegerv(eGL_BLEND_DST_RGB, (GLint*)&DestinationRGB); + gl.glGetIntegerv(eGL_BLEND_DST_ALPHA, (GLint*)&DestinationAlpha); + } - gl.glGetIntegeri_v(eGL_BLEND_DST_RGB, 0, (GLint*)&DestinationRGB); - gl.glGetIntegeri_v(eGL_BLEND_DST_ALPHA, 0, (GLint*)&DestinationAlpha); - if(!VendorCheck[VendorCheck_AMD_polygon_mode_query]) { GLenum dummy[2] = { eGL_FILL, eGL_FILL }; @@ -1250,52 +1324,99 @@ struct RenderTextState { PolygonMode = eGL_FILL; } - - gl.glGetFloati_v(eGL_VIEWPORT, 0, &Viewport[0]); + + if(modern) + gl.glGetFloati_v(eGL_VIEWPORT, 0, &Viewportf[0]); + else + gl.glGetIntegerv(eGL_VIEWPORT, &Viewport[0]); gl.glGetIntegerv(eGL_ACTIVE_TEXTURE, (GLint *)&ActiveTexture); gl.glActiveTexture(eGL_TEXTURE0); gl.glGetIntegerv(eGL_TEXTURE_BINDING_2D, (GLint*)&tex0); - gl.glGetIntegeri_v(eGL_UNIFORM_BUFFER_BINDING, 0, (GLint*)&ubo[0]); - gl.glGetIntegeri_v(eGL_UNIFORM_BUFFER_BINDING, 1, (GLint*)&ubo[1]); - gl.glGetIntegeri_v(eGL_UNIFORM_BUFFER_BINDING, 2, (GLint*)&ubo[2]); - + // we get the current program but only try to restore it if it's non-0 + prog = 0; gl.glGetIntegerv(eGL_CURRENT_PROGRAM, (GLint *)&prog); - - gl.glGetIntegerv(eGL_VERTEX_ARRAY_BINDING, (GLint *)&VAO); + + // since we will use the fixed function pipeline, also need to check for + // program pipeline bindings (if we weren't, our program would override) + pipe = 0; + gl.glGetIntegerv(eGL_PROGRAM_PIPELINE_BINDING, (GLint *)&pipe); + + if(modern) + { + gl.glGetIntegeri_v(eGL_UNIFORM_BUFFER_BINDING, 0, (GLint*)&ubo[0]); + gl.glGetIntegeri_v(eGL_UNIFORM_BUFFER_BINDING, 1, (GLint*)&ubo[1]); + gl.glGetIntegeri_v(eGL_UNIFORM_BUFFER_BINDING, 2, (GLint*)&ubo[2]); + + gl.glGetIntegerv(eGL_VERTEX_ARRAY_BINDING, (GLint *)&VAO); + } } - void Pop(const GLHookSet &gl) + void Pop(const GLHookSet &gl, bool modern) { - if(enableBits[0]) gl.glEnablei(eGL_BLEND, 0); else gl.glDisablei(eGL_BLEND, 0); - if(enableBits[1]) gl.glEnable(eGL_DEPTH_TEST); else gl.glDisable(eGL_DEPTH_TEST); - if(enableBits[2]) gl.glEnable(eGL_DEPTH_CLAMP); else gl.glDisable(eGL_DEPTH_CLAMP); - if(enableBits[3]) gl.glEnable(eGL_STENCIL_TEST); else gl.glDisable(eGL_STENCIL_TEST); - if(enableBits[4]) gl.glEnable(eGL_CULL_FACE); else gl.glDisable(eGL_CULL_FACE); - if(enableBits[5]) gl.glEnablei(eGL_SCISSOR_TEST, 0); else gl.glDisablei(eGL_SCISSOR_TEST, 0); + if(enableBits[0]) gl.glEnable(eGL_DEPTH_TEST); else gl.glDisable(eGL_DEPTH_TEST); + if(enableBits[1]) gl.glEnable(eGL_STENCIL_TEST); else gl.glDisable(eGL_STENCIL_TEST); + if(enableBits[2]) gl.glEnable(eGL_CULL_FACE); else gl.glDisable(eGL_CULL_FACE); - if(gl.glClipControl && (GLCoreVersion >= 45 || ExtensionSupported[ExtensionSupported_ARB_clip_control])) // only available in 4.5+ + if(modern) + { + if(enableBits[3]) gl.glEnable(eGL_DEPTH_CLAMP); else gl.glDisable(eGL_DEPTH_CLAMP); + if(enableBits[4]) gl.glEnablei(eGL_BLEND, 0); else gl.glDisablei(eGL_BLEND, 0); + if(enableBits[5]) gl.glEnablei(eGL_SCISSOR_TEST, 0); else gl.glDisablei(eGL_SCISSOR_TEST, 0); + } + else + { + if(enableBits[3]) gl.glEnable(eGL_BLEND); else gl.glDisable(eGL_BLEND); + if(enableBits[4]) gl.glEnable(eGL_SCISSOR_TEST); else gl.glDisable(eGL_SCISSOR_TEST); + if(enableBits[5]) gl.glEnable(eGL_TEXTURE_2D); else gl.glDisable(eGL_TEXTURE_2D); + if(enableBits[6]) gl.glEnable(eGL_LIGHTING); else gl.glDisable(eGL_LIGHTING); + if(enableBits[7]) gl.glEnable(eGL_ALPHA_TEST); else gl.glDisable(eGL_ALPHA_TEST); + } + + if(modern && gl.glClipControl && (GLCoreVersion >= 45 || ExtensionSupported[ExtensionSupported_ARB_clip_control])) // only available in 4.5+ gl.glClipControl(ClipOrigin, ClipDepth); - gl.glBlendFuncSeparatei(0, SourceRGB, DestinationRGB, SourceAlpha, DestinationAlpha); - gl.glBlendEquationSeparatei(0, EquationRGB, EquationAlpha); + if(modern) + { + gl.glBlendFuncSeparatei(0, SourceRGB, DestinationRGB, SourceAlpha, DestinationAlpha); + gl.glBlendEquationSeparatei(0, EquationRGB, EquationAlpha); + } + else + { + gl.glBlendFuncSeparate(SourceRGB, DestinationRGB, SourceAlpha, DestinationAlpha); + gl.glBlendEquationSeparate(EquationRGB, EquationAlpha); + } gl.glPolygonMode(eGL_FRONT_AND_BACK, PolygonMode); - gl.glViewportIndexedf(0, Viewport[0], Viewport[1], Viewport[2], Viewport[3]); + if(modern) + gl.glViewportIndexedf(0, Viewportf[0], Viewportf[1], Viewportf[2], Viewportf[3]); + else + gl.glViewport(Viewport[0], Viewport[1], (GLsizei)Viewport[2], (GLsizei)Viewport[3]); gl.glActiveTexture(eGL_TEXTURE0); gl.glBindTexture(eGL_TEXTURE_2D, tex0); gl.glActiveTexture(ActiveTexture); - - gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 0, ubo[0]); - gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 1, ubo[1]); - gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 2, ubo[2]); - gl.glUseProgram(prog); - - gl.glBindVertexArray(VAO); + if(modern) + { + gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 0, ubo[0]); + gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 1, ubo[1]); + gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 2, ubo[2]); + + gl.glUseProgram(prog); + + gl.glBindVertexArray(VAO); + } + else + { + // only restore these if there was a setting and the function pointer exists + if(gl.glUseProgram && prog != 0) + gl.glUseProgram(prog); + if(gl.glBindProgramPipeline && pipe != 0) + gl.glBindProgramPipeline(pipe); + } } }; @@ -1334,106 +1455,220 @@ void WrappedOpenGL::RenderOverlayStr(float x, float y, const char *text) if(!ctxdata.built || !ctxdata.ready) return; - gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 0, ctxdata.GeneralUBO); - - FontUniforms *ubo = (FontUniforms *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(FontUniforms), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); - ubo->TextPosition.x = x; - ubo->TextPosition.y = y; - - ubo->FontScreenAspect.x = 1.0f/float(m_InitParams.width); - ubo->FontScreenAspect.y = 1.0f/float(m_InitParams.height); - - ubo->TextSize = ctxdata.CharSize; - ubo->FontScreenAspect.x *= ctxdata.CharAspect; - - ubo->CharacterSize.x = 1.0f/float(FONT_TEX_WIDTH); - ubo->CharacterSize.y = 1.0f/float(FONT_TEX_HEIGHT); - - gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); - - size_t len = strlen(text); - - if((int)len > FONT_MAX_CHARS) + // if it's reasonably modern context, assume we can use buffers and UBOs + if(ctxdata.Modern()) { - static bool printedWarning = false; + gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 0, ctxdata.GeneralUBO); - // this could be called once a frame, don't want to spam the log - if(!printedWarning) + FontUniforms *ubo = (FontUniforms *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, sizeof(FontUniforms), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); + ubo->TextPosition.x = x; + ubo->TextPosition.y = y; + + ubo->FontScreenAspect.x = 1.0f/float(m_InitParams.width); + ubo->FontScreenAspect.y = 1.0f/float(m_InitParams.height); + + ubo->TextSize = ctxdata.CharSize; + ubo->FontScreenAspect.x *= ctxdata.CharAspect; + + ubo->CharacterSize.x = 1.0f/float(FONT_TEX_WIDTH); + ubo->CharacterSize.y = 1.0f/float(FONT_TEX_HEIGHT); + + gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); + + size_t len = strlen(text); + + if((int)len > FONT_MAX_CHARS) { - printedWarning = true; - RDCWARN("log string '%s' is too long", text, (int)len); + static bool printedWarning = false; + + // this could be called once a frame, don't want to spam the log + if(!printedWarning) + { + printedWarning = true; + RDCWARN("log string '%s' is too long", text, (int)len); + } + + len = FONT_MAX_CHARS; } - len = FONT_MAX_CHARS; - } + gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 0, ctxdata.StringUBO); + uint32_t *texs = (uint32_t *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, len*4*sizeof(uint32_t), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); - gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 0, ctxdata.StringUBO); - uint32_t *texs = (uint32_t *)gl.glMapBufferRange(eGL_UNIFORM_BUFFER, 0, len*4*sizeof(uint32_t), GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); - - if(texs) - { - for(size_t i=0; i < len; i++) + if(texs) { - texs[i*4+0] = text[i] - ' '; - texs[i*4+1] = text[i] - ' '; - texs[i*4+2] = text[i] - ' '; - texs[i*4+3] = text[i] - ' '; + for(size_t i=0; i < len; i++) + { + texs[i*4+0] = text[i] - ' '; + texs[i*4+1] = text[i] - ' '; + texs[i*4+2] = text[i] - ' '; + texs[i*4+3] = text[i] - ' '; + } } + else + { + static bool printedWarning = false; + + // this could be called once a frame, don't want to spam the log + if(!printedWarning) + { + printedWarning = true; + RDCWARN("failed to map %d characters for '%s' (%d)", (int)len, text, ctxdata.StringUBO); + } + } + + gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); + + ////////////////////////////////////////////////////////////////////////////////// + // Make sure if you change any other state in here, that you also update the push + // and pop functions above (RenderTextState) + + // set blend state + gl.glEnablei(eGL_BLEND, 0); + gl.glBlendFuncSeparatei(0, eGL_SRC_ALPHA, eGL_ONE_MINUS_SRC_ALPHA, eGL_SRC_ALPHA, eGL_SRC_ALPHA); + gl.glBlendEquationSeparatei(0, eGL_FUNC_ADD, eGL_FUNC_ADD); + + // set depth & stencil + gl.glDisable(eGL_DEPTH_TEST); + gl.glDisable(eGL_DEPTH_CLAMP); + gl.glDisable(eGL_STENCIL_TEST); + gl.glDisable(eGL_CULL_FACE); + + // set viewport & scissor + gl.glViewportIndexedf(0, 0.0f, 0.0f, (float)m_InitParams.width, (float)m_InitParams.height); + gl.glDisablei(eGL_SCISSOR_TEST, 0); + gl.glPolygonMode(eGL_FRONT_AND_BACK, eGL_FILL); + + if(gl.glClipControl && (GLCoreVersion >= 45 || ExtensionSupported[ExtensionSupported_ARB_clip_control])) // only available in 4.5+ + gl.glClipControl(eGL_LOWER_LEFT, eGL_NEGATIVE_ONE_TO_ONE); + + // bind UBOs + gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 0, ctxdata.GeneralUBO); + gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 1, ctxdata.GlyphUBO); + gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 2, ctxdata.StringUBO); + + // bind empty VAO just for valid rendering + gl.glBindVertexArray(ctxdata.DummyVAO); + + // bind textures + gl.glActiveTexture(eGL_TEXTURE0); + gl.glBindTexture(eGL_TEXTURE_2D, ctxdata.GlyphTexture); + + // bind program + gl.glUseProgram(ctxdata.Program); + + // draw string + gl.glDrawArraysInstanced(eGL_TRIANGLE_STRIP, 0, 4, (GLsizei)len); } else { - static bool printedWarning = false; + // if it wasn't created in modern fashion with createattribs, assume the worst + // and draw with immediate mode (since it's impossible that the context is core + // profile, this will always work) + // + // This isn't perfect since without a lot of fiddling we'd need to check if e.g. + // indexed blending should be used or not. Since we're not too worried about + // working in this situation, just doing something reasonable, we just assume + // roughly ~2.0 functionality + + ////////////////////////////////////////////////////////////////////////////////// + // Make sure if you change any other state in here, that you also update the push + // and pop functions above (RenderTextState) - // this could be called once a frame, don't want to spam the log - if(!printedWarning) + // disable blending and some old-style fixed function features + gl.glDisable(eGL_BLEND); + gl.glDisable(eGL_LIGHTING); + gl.glDisable(eGL_ALPHA_TEST); + + // set depth & stencil + gl.glDisable(eGL_DEPTH_TEST); + gl.glDisable(eGL_STENCIL_TEST); + gl.glDisable(eGL_CULL_FACE); + + // set viewport & scissor + gl.glViewport(0, 0, (GLsizei)m_InitParams.width, (GLsizei)m_InitParams.height); + gl.glDisable(eGL_SCISSOR_TEST); + gl.glPolygonMode(eGL_FRONT_AND_BACK, eGL_FILL); + + // bind textures + gl.glActiveTexture(eGL_TEXTURE0); + gl.glBindTexture(eGL_TEXTURE_2D, ctxdata.GlyphTexture); + gl.glEnable(eGL_TEXTURE_2D); + + // just in case, try to disable the programmable pipeline + if(gl.glUseProgram) + gl.glUseProgram(0); + if(gl.glBindProgramPipeline) + gl.glBindProgramPipeline(0); + + // draw string (based on sample code from stb_truetype.h) + if(immediateBegin(eGL_QUADS, (float)m_InitParams.width, (float)m_InitParams.height)) { - printedWarning = true; - RDCWARN("failed to map %d characters for '%s' (%d)", (int)len, text, ctxdata.StringUBO); + y += 1.0f; + y *= charPixelHeight; + + float startx = x; + float starty = y; + + float maxx = x, minx = x; + float maxy = y, miny = y - charPixelHeight; + + stbtt_aligned_quad q; + + const char *prepass = text; + while (*prepass) + { + char c = *prepass; + if (c >= firstChar && c <= lastChar) + { + stbtt_GetBakedQuad(chardata, FONT_TEX_WIDTH, FONT_TEX_HEIGHT, c-firstChar, &x, &y, &q, 1); + + maxx = RDCMAX(maxx, RDCMAX(q.x0, q.x1)); + maxy = RDCMAX(maxy, RDCMAX(q.y0, q.y1)); + + minx = RDCMIN(minx, RDCMIN(q.x0, q.x1)); + miny = RDCMIN(miny, RDCMIN(q.y0, q.y1)); + } + else + { + x += chardata[0].xadvance; + } + prepass++; + } + + x = startx; + y = starty; + + // draw black bar behind text + immediateVert(minx, maxy, 0.0f, 0.0f); + immediateVert(maxx, maxy, 0.0f, 0.0f); + immediateVert(maxx, miny, 0.0f, 0.0f); + immediateVert(minx, miny, 0.0f, 0.0f); + + while (*text) + { + char c = *text; + if (c >= firstChar && c <= lastChar) + { + stbtt_GetBakedQuad(chardata, FONT_TEX_WIDTH, FONT_TEX_HEIGHT, c-firstChar, &x, &y, &q, 1); + + immediateVert(q.x0, q.y0, q.s0, q.t0); + immediateVert(q.x1, q.y0, q.s1, q.t0); + immediateVert(q.x1, q.y1, q.s1, q.t1); + immediateVert(q.x0, q.y1, q.s0, q.t1); + + maxx = RDCMAX(maxx, RDCMAX(q.x0, q.x1)); + maxy = RDCMAX(maxy, RDCMAX(q.y0, q.y1)); + } + else + { + x += chardata[0].xadvance; + } + ++text; + } + + immediateEnd(); } } - - gl.glUnmapBuffer(eGL_UNIFORM_BUFFER); - - ////////////////////////////////////////////////////////////////////////////////// - // Make sure if you change any other state in here, that you also update the push - // and pop functions above (RenderTextState) - - // set blend state - gl.glEnablei(eGL_BLEND, 0); - gl.glBlendFuncSeparatei(0, eGL_SRC_ALPHA, eGL_ONE_MINUS_SRC_ALPHA, eGL_SRC_ALPHA, eGL_SRC_ALPHA); - gl.glBlendEquationSeparatei(0, eGL_FUNC_ADD, eGL_FUNC_ADD); - - // set depth & stencil - gl.glDisable(eGL_DEPTH_TEST); - gl.glDisable(eGL_DEPTH_CLAMP); - gl.glDisable(eGL_STENCIL_TEST); - gl.glDisable(eGL_CULL_FACE); - - // set viewport & scissor - gl.glViewportIndexedf(0, 0.0f, 0.0f, (float)m_InitParams.width, (float)m_InitParams.height); - gl.glDisablei(eGL_SCISSOR_TEST, 0); - gl.glPolygonMode(eGL_FRONT_AND_BACK, eGL_FILL); - - if(gl.glClipControl && (GLCoreVersion >= 45 || ExtensionSupported[ExtensionSupported_ARB_clip_control])) // only available in 4.5+ - gl.glClipControl(eGL_LOWER_LEFT, eGL_NEGATIVE_ONE_TO_ONE); - - // bind UBOs - gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 0, ctxdata.GeneralUBO); - gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 1, ctxdata.GlyphUBO); - gl.glBindBufferBase(eGL_UNIFORM_BUFFER, 2, ctxdata.StringUBO); - - // bind empty VAO just for valid rendering - gl.glBindVertexArray(ctxdata.DummyVAO); - - // bind textures - gl.glActiveTexture(eGL_TEXTURE0); - gl.glBindTexture(eGL_TEXTURE_2D, ctxdata.GlyphTexture); - - // bind program - gl.glUseProgram(ctxdata.Program); - - // draw string - gl.glDrawArraysInstanced(eGL_TRIANGLE_STRIP, 0, 4, (GLsizei)len); } struct ReplacementSearch @@ -1714,35 +1949,41 @@ void WrappedOpenGL::Present(void *windowHandle) { RenderTextState textState; - textState.Push(m_Real); + ContextData &ctxdata = GetCtxData(); + + textState.Push(m_Real, ctxdata.Modern()); // TODO: handle selecting active window amongst many { vector keys = RenderDoc::Inst().GetCaptureKeys(); - string overlayText = "OpenGL. "; + string overlayText = "OpenGL."; - for(size_t i=0; i < keys.size(); i++) + if(ctxdata.Modern()) { - if(i > 0) - overlayText += ", "; + overlayText += " "; - overlayText += ToStr::Get(keys[i]); + for(size_t i=0; i < keys.size(); i++) + { + if(i > 0) + overlayText += ", "; + + overlayText += ToStr::Get(keys[i]); + } + + if(!keys.empty()) + overlayText += " to capture."; } - if(!keys.empty()) - overlayText += " to capture."; - if(overlay & eOverlay_FrameNumber) { - if(!overlayText.empty()) overlayText += " "; - overlayText += StringFormat::Fmt("Frame: %d.", m_FrameCounter); + overlayText += StringFormat::Fmt(" Frame: %d.", m_FrameCounter); } if(overlay & eOverlay_FrameRate) { - if(!overlayText.empty()) overlayText += " "; - overlayText += StringFormat::Fmt("%.2lf ms (%.2lf .. %.2lf) (%.0lf FPS)", - m_AvgFrametime, m_MinFrametime, m_MaxFrametime, 1000.0f/m_AvgFrametime); + overlayText += StringFormat::Fmt(" %.2lf ms (%.2lf .. %.2lf) (%.0lf FPS)", + m_AvgFrametime, m_MinFrametime, m_MaxFrametime, + m_AvgFrametime <= 0.0f ? 0.0f : 1000.0f/m_AvgFrametime); } float y=0.0f; @@ -1753,7 +1994,23 @@ void WrappedOpenGL::Present(void *windowHandle) y += 1.0f; } - if(overlay & eOverlay_CaptureList) + if(ctxdata.Legacy()) + { + if(!ctxdata.attribsCreate) + { + RenderOverlayText(0.0f, y, "Context not created via CreateContextAttribs. Capturing disabled."); + y += 1.0f; + } + RenderOverlayText(0.0f, y, "Only OpenGL 3.2+ contexts are supported."); + y += 1.0f; + } + else if(!ctxdata.isCore) + { + RenderOverlayText(0.0f, y, "WARNING: Non-core context in use. Compatibility profile not supported."); + y += 1.0f; + } + + if(ctxdata.Modern() && (overlay & eOverlay_CaptureList)) { RenderOverlayText(0.0f, y, "%d Captures saved.\n", (uint32_t)m_FrameRecord.size()); y += 1.0f; @@ -1775,7 +2032,17 @@ void WrappedOpenGL::Present(void *windowHandle) #endif } - textState.Pop(m_Real); + textState.Pop(m_Real, ctxdata.Modern()); + + // swallow all errors we might have inadvertantly caused. This is + // better than letting an error propagate and maybe screw up the + // app (although it means we might swallow an error from before the + // SwapBuffers call, it can't be helped. + if(ctxdata.Legacy() && m_Real.glGetError) + { + GLenum err = m_Real.glGetError(); + while(err) err = m_Real.glGetError(); + } } } @@ -1936,7 +2203,8 @@ void WrappedOpenGL::Present(void *windowHandle) } } - if(RenderDoc::Inst().ShouldTriggerCapture(m_FrameCounter) && m_State == WRITING_IDLE && m_FrameRecord.empty()) + // only allow capturing on 'modern' created contexts + if(GetCtxData().Modern() && RenderDoc::Inst().ShouldTriggerCapture(m_FrameCounter) && m_State == WRITING_IDLE && m_FrameRecord.empty()) { m_State = WRITING_CAPFRAME; diff --git a/renderdoc/driver/gl/gl_driver.h b/renderdoc/driver/gl/gl_driver.h index 25ce517c2..c881b0a66 100644 --- a/renderdoc/driver/gl/gl_driver.h +++ b/renderdoc/driver/gl/gl_driver.h @@ -313,6 +313,8 @@ class WrappedOpenGL ContextData() { built = ready = false; + attribsCreate = false; + version = 0; isCore = false; Program = GeneralUBO = StringUBO = GlyphUBO = 0; GlyphTexture = DummyVAO = 0; @@ -329,8 +331,13 @@ class WrappedOpenGL bool built; bool ready; + int version; + bool attribsCreate; bool isCore; + bool Legacy() { return !attribsCreate || version < 32; } + bool Modern() { return !Legacy(); } + GLuint Program; GLuint GeneralUBO, StringUBO, GlyphUBO; GLuint GlyphTexture; @@ -427,7 +434,7 @@ class WrappedOpenGL const FetchDrawcall *GetDrawcall(uint32_t frameID, uint32_t eventID); - void CreateContext(GLWindowingData winData, void *shareContext, GLInitParams initParams, bool core); + void CreateContext(GLWindowingData winData, void *shareContext, GLInitParams initParams, bool core, bool attribsCreate); void DeleteContext(void *contextHandle); void ActivateContext(GLWindowingData winData); void WindowSize(void *windowHandle, uint32_t w, uint32_t h); diff --git a/renderdoc/driver/gl/gl_resources.h b/renderdoc/driver/gl/gl_resources.h index 6542be6b4..c72d7d81a 100644 --- a/renderdoc/driver/gl/gl_resources.h +++ b/renderdoc/driver/gl/gl_resources.h @@ -36,11 +36,6 @@ GLenum GetBaseFormat(GLenum internalFormat); GLenum GetDataType(GLenum internalFormat); GLenum GetSizedFormat(const GLHookSet &gl, GLenum target, GLenum internalFormat); -// no longer in glcorearb.h or glext.h -const GLenum eGL_LUMINANCE = (GLenum)0x1909; -const GLenum eGL_LUMINANCE_ALPHA = (GLenum)0x190A; -const GLenum eGL_INTENSITY = (GLenum)0x8049; - void EmulateLuminanceFormat(const GLHookSet &gl, GLuint tex, GLenum target, GLenum &internalFormat, GLenum &dataFormat); int GetNumMips(const GLHookSet &gl, GLenum target, GLuint tex, GLuint w, GLuint h, GLuint d); diff --git a/renderdoc/hooks/gl_linux_hooks.cpp b/renderdoc/hooks/gl_linux_hooks.cpp index 04ab1e334..1a7ae8f81 100644 --- a/renderdoc/hooks/gl_linux_hooks.cpp +++ b/renderdoc/hooks/gl_linux_hooks.cpp @@ -593,7 +593,7 @@ GLXContext glXCreateContext(Display *dpy, XVisualInfo *vis, GLXContext shareList data.wnd = (GLXDrawable)NULL; data.ctx = ret; - OpenGLHook::glhooks.GetDriver()->CreateContext(data, shareList, init, false); + OpenGLHook::glhooks.GetDriver()->CreateContext(data, shareList, init, false, false); return ret; } @@ -691,7 +691,7 @@ GLXContext glXCreateContextAttribsARB(Display *dpy, GLXFBConfig config, GLXConte data.wnd = (GLXDrawable)NULL; data.ctx = ret; - OpenGLHook::glhooks.GetDriver()->CreateContext(data, shareList, init, core); + OpenGLHook::glhooks.GetDriver()->CreateContext(data, shareList, init, core, true); return ret; } @@ -876,3 +876,90 @@ void DeleteContext(GLWindowingData context) OpenGLHook::glhooks.DeleteContext(context); } +// dirty immediate mode rendering functions for backwards compatible +// rendering of overlay text +typedef void (*GLGETINTEGERVPROC)(GLenum,GLint*); +typedef void (*GLPUSHMATRIXPROC)(); +typedef void (*GLLOADIDENTITYPROC)(); +typedef void (*GLMATRIXMODEPROC)(GLenum); +typedef void (*GLORTHOPROC)(GLdouble,GLdouble,GLdouble,GLdouble,GLdouble,GLdouble); +typedef void (*GLPOPMATRIXPROC)(); +typedef void (*GLBEGINPROC)(GLenum); +typedef void (*GLVERTEX2FPROC)(float,float); +typedef void (*GLTEXCOORD2FPROC)(float,float); +typedef void (*GLENDPROC)(); + +static GLGETINTEGERVPROC getInt = NULL; +static GLPUSHMATRIXPROC pushm = NULL; +static GLLOADIDENTITYPROC loadident = NULL; +static GLMATRIXMODEPROC matMode = NULL; +static GLORTHOPROC ortho = NULL; +static GLPOPMATRIXPROC popm = NULL; +static GLBEGINPROC begin = NULL; +static GLVERTEX2FPROC v2f = NULL; +static GLTEXCOORD2FPROC t2f = NULL; +static GLENDPROC end = NULL; + +const GLenum MAT_MODE = (GLenum)0x0BA0; +const GLenum MAT_MDVW = (GLenum)0x1700; +const GLenum MAT_PROJ = (GLenum)0x1701; + +static bool immediateInited = false; + +bool immediateBegin(GLenum mode, float width, float height) +{ + if(!immediateInited) + { + getInt = (GLGETINTEGERVPROC)dlsym(RTLD_NEXT, "glGetIntegerv"); if(!getInt) return false; + pushm = (GLPUSHMATRIXPROC)dlsym(RTLD_NEXT, "glPushMatrix"); if(!pushm) return false; + loadident = (GLLOADIDENTITYPROC)dlsym(RTLD_NEXT, "glLoadIdentity"); if(!loadident) return false; + matMode = (GLMATRIXMODEPROC)dlsym(RTLD_NEXT, "glMatrixMode"); if(!matMode) return false; + ortho = (GLORTHOPROC)dlsym(RTLD_NEXT, "glOrtho"); if(!ortho) return false; + popm = (GLPOPMATRIXPROC)dlsym(RTLD_NEXT, "glPopMatrix"); if(!popm) return false; + begin = (GLBEGINPROC)dlsym(RTLD_NEXT, "glBegin"); if(!begin) return false; + v2f = (GLVERTEX2FPROC)dlsym(RTLD_NEXT, "glVertex2f"); if(!v2f) return false; + t2f = (GLTEXCOORD2FPROC)dlsym(RTLD_NEXT, "glTexCoord2f"); if(!t2f) return false; + end = (GLENDPROC)dlsym(RTLD_NEXT, "glEnd"); if(!end) return false; + + immediateInited = true; + } + + GLenum prevMatMode = eGL_NONE; + getInt(MAT_MODE, (GLint *)&prevMatMode); + + matMode(MAT_PROJ); + pushm(); + loadident(); + ortho(0.0, width, height, 0.0, -1.0, 1.0); + + matMode(MAT_MDVW); + pushm(); + loadident(); + + matMode(prevMatMode); + + begin(mode); + + return true; +} + +void immediateVert(float x, float y, float u, float v) +{ + t2f(u,v); v2f(x,y); +} + +void immediateEnd() +{ + end(); + + GLenum prevMatMode = eGL_NONE; + getInt(MAT_MODE, (GLint *)&prevMatMode); + + matMode(MAT_PROJ); + popm(); + matMode(MAT_MDVW); + popm(); + + matMode(prevMatMode); +} + diff --git a/renderdoc/hooks/gl_win32_hooks.cpp b/renderdoc/hooks/gl_win32_hooks.cpp index 03f5f698c..6fd524a5f 100644 --- a/renderdoc/hooks/gl_win32_hooks.cpp +++ b/renderdoc/hooks/gl_win32_hooks.cpp @@ -379,7 +379,7 @@ class OpenGLHook : LibraryHook data.wnd = WindowFromDC(dc); data.ctx = ret; - glhooks.GetDriver()->CreateContext(data, NULL, GetInitParamsForDC(dc), false); + glhooks.GetDriver()->CreateContext(data, NULL, GetInitParamsForDC(dc), false, false); return ret; } @@ -400,7 +400,7 @@ class OpenGLHook : LibraryHook data.wnd = WindowFromDC(dc); data.ctx = ret; - glhooks.GetDriver()->CreateContext(data, NULL, GetInitParamsForDC(dc), false); + glhooks.GetDriver()->CreateContext(data, NULL, GetInitParamsForDC(dc), false, false); return ret; } @@ -468,7 +468,7 @@ class OpenGLHook : LibraryHook data.wnd = WindowFromDC(dc); data.ctx = ret; - glhooks.GetDriver()->CreateContext(data, hShareContext, GetInitParamsForDC(dc), core); + glhooks.GetDriver()->CreateContext(data, hShareContext, GetInitParamsForDC(dc), core, true); return ret; } @@ -865,3 +865,94 @@ void DeleteContext(GLWindowingData context) { OpenGLHook::glhooks.DeleteContext(context); } + +// dirty immediate mode rendering functions for backwards compatible +// rendering of overlay text +typedef void (WINAPI *GLGETINTEGERVPROC)(GLenum,GLint*); +typedef void (WINAPI *GLPUSHMATRIXPROC)(); +typedef void (WINAPI *GLLOADIDENTITYPROC)(); +typedef void (WINAPI *GLMATRIXMODEPROC)(GLenum); +typedef void (WINAPI *GLORTHOPROC)(GLdouble,GLdouble,GLdouble,GLdouble,GLdouble,GLdouble); +typedef void (WINAPI *GLPOPMATRIXPROC)(); +typedef void (WINAPI *GLBEGINPROC)(GLenum); +typedef void (WINAPI *GLVERTEX2FPROC)(float,float); +typedef void (WINAPI *GLTEXCOORD2FPROC)(float,float); +typedef void (WINAPI *GLENDPROC)(); + +static GLGETINTEGERVPROC getInt = NULL; +static GLPUSHMATRIXPROC pushm = NULL; +static GLLOADIDENTITYPROC loadident = NULL; +static GLMATRIXMODEPROC matMode = NULL; +static GLORTHOPROC ortho = NULL; +static GLPOPMATRIXPROC popm = NULL; +static GLBEGINPROC begin = NULL; +static GLVERTEX2FPROC v2f = NULL; +static GLTEXCOORD2FPROC t2f = NULL; +static GLENDPROC end = NULL; + +const GLenum MAT_MODE = (GLenum)0x0BA0; +const GLenum MAT_MDVW = (GLenum)0x1700; +const GLenum MAT_PROJ = (GLenum)0x1701; + +static bool immediateInited = false; + +bool immediateBegin(GLenum mode, float width, float height) +{ + if(!immediateInited) + { + HMODULE mod = GetModuleHandleA("opengl32.dll"); + + if(mod == NULL) return false; + + getInt = (GLGETINTEGERVPROC)GetProcAddress(mod, "glGetIntegerv"); if(!getInt) return false; + pushm = (GLPUSHMATRIXPROC)GetProcAddress(mod, "glPushMatrix"); if(!pushm) return false; + loadident = (GLLOADIDENTITYPROC)GetProcAddress(mod, "glLoadIdentity"); if(!loadident) return false; + matMode = (GLMATRIXMODEPROC)GetProcAddress(mod, "glMatrixMode"); if(!matMode) return false; + ortho = (GLORTHOPROC)GetProcAddress(mod, "glOrtho"); if(!ortho) return false; + popm = (GLPOPMATRIXPROC)GetProcAddress(mod, "glPopMatrix"); if(!popm) return false; + begin = (GLBEGINPROC)GetProcAddress(mod, "glBegin"); if(!begin) return false; + v2f = (GLVERTEX2FPROC)GetProcAddress(mod, "glVertex2f"); if(!v2f) return false; + t2f = (GLTEXCOORD2FPROC)GetProcAddress(mod, "glTexCoord2f"); if(!t2f) return false; + end = (GLENDPROC)GetProcAddress(mod, "glEnd"); if(!end) return false; + + immediateInited = true; + } + + GLenum prevMatMode = eGL_NONE; + getInt(MAT_MODE, (GLint *)&prevMatMode); + + matMode(MAT_PROJ); + pushm(); + loadident(); + ortho(0.0, width, height, 0.0, -1.0, 1.0); + + matMode(MAT_MDVW); + pushm(); + loadident(); + + matMode(prevMatMode); + + begin(mode); + + return true; +} + +void immediateVert(float x, float y, float u, float v) +{ + t2f(u,v); v2f(x,y); +} + +void immediateEnd() +{ + end(); + + GLenum prevMatMode = eGL_NONE; + getInt(MAT_MODE, (GLint *)&prevMatMode); + + matMode(MAT_PROJ); + popm(); + matMode(MAT_MDVW); + popm(); + + matMode(prevMatMode); +}