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