mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-10-07 21:01:27 +00:00
Refuse to capture on old contexts, warn on compat profiles. Closes #125
* If CreateContextAttribs is not used to create the context, the overlay will run in super-duper old mode using immediate mode calls and fixed function pipeline. This way it should display on (in theory) any GL app. Capturing will be prevented. * Compatibility profile contexts are still allowed, but a warning is displayed in the overlay. * If CreateContextAttribs is used to create a < 3.2 version context, we go down the same path as for legacy contexts, except with an accurate overlay message (just that the version isn't supported).
This commit is contained in:
1 parent
6fa7d47097
commit
35fa1ce2bf
8 files changed
+716
-241
No files matched your search
@@ -341,5 +341,27 @@
|
||||
</para>
|
||||
</content>
|
||||
</section>
|
||||
<section address="FAQ11">
|
||||
<title>RenderDoc is complaining about my OpenGL app in the overlay - what gives?</title>
|
||||
<content>
|
||||
<para>
|
||||
The first thing to remember is that <legacyBold>RenderDoc only supports Core 3.2 and above OpenGL</legacyBold>.
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
</content>
|
||||
</section>
|
||||
</developerConceptualDocument>
|
||||
</topic>
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
+494
-226
@@ -39,6 +39,13 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
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_<platform>_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<KeyButton> 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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
Reference in new issue
Block a user