diff --git a/renderdoc/driver/gl/egl_dispatch_table.h b/renderdoc/driver/gl/egl_dispatch_table.h index 79039ab38..0d7a5b77b 100644 --- a/renderdoc/driver/gl/egl_dispatch_table.h +++ b/renderdoc/driver/gl/egl_dispatch_table.h @@ -51,6 +51,7 @@ typedef EGLSurface (*PFN_eglGetCurrentSurface)(EGLint readdraw); typedef EGLint (*PFN_eglGetError)(void); typedef EGLBoolean (*PFN_eglGetConfigAttrib)(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value); +typedef const char *(*PFN_eglQueryString)(EGLDisplay dpy, EGLint name); typedef PFNEGLPOSTSUBBUFFERNVPROC PFN_eglPostSubBufferNV; #define EGL_HOOKED_SYMBOLS(FUNC) \ @@ -74,6 +75,7 @@ typedef PFNEGLPOSTSUBBUFFERNVPROC PFN_eglPostSubBufferNV; FUNC(GetCurrentSurface, false); \ FUNC(GetError, false); \ FUNC(Initialize, false); \ + FUNC(QueryString, false); \ FUNC(QuerySurface, false); struct EGLDispatchTable diff --git a/renderdoc/driver/gl/egl_hooks.cpp b/renderdoc/driver/gl/egl_hooks.cpp index 2093d4f01..707b61c49 100644 --- a/renderdoc/driver/gl/egl_hooks.cpp +++ b/renderdoc/driver/gl/egl_hooks.cpp @@ -53,6 +53,24 @@ public: std::set contexts; std::map configs; std::map windows; + + bool IsYFlipped(EGLDisplay dpy, EGLSurface surface) + { + if(strstr(EGL.QueryString(dpy, EGL_EXTENSIONS), "ANGLE_surface_orientation")) + { +// https://github.com/google/angle/blob/master/extensions/EGL_ANGLE_surface_orientation.txt +#define EGL_SURFACE_ORIENTATION_ANGLE 0x33A8 +#define EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE 0x0002 + + int mask = 0; + EGL.QuerySurface(dpy, surface, EGL_SURFACE_ORIENTATION_ANGLE, &mask); + + return (mask & EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE) != 0; + } + + return false; + } + } eglhook; HOOK_EXPORT EGLDisplay EGLAPIENTRY eglGetDisplay(EGLNativeDisplayType display) @@ -302,6 +320,8 @@ HOOK_EXPORT EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface sur // GL_SRGB8_ALPHA8 is specified as color-renderable, unlike GL_SRGB8. init.isSRGB = init.colorBits == 32 && colorspace == EGL_GL_COLORSPACE_SRGB; + init.isYFlipped = eglhook.IsYFlipped(dpy, surface); + eglhook.driver.SetDriverType(RDCDriver::OpenGLES); eglhook.driver.WindowSize(surface, width, height); if(!eglhook.driver.UsesVRFrameMarkers()) @@ -333,10 +353,12 @@ HOOK_EXPORT EGLBoolean EGLAPIENTRY eglPostSubBufferNV(EGLDisplay dpy, EGLSurface // GL_SRGB8_ALPHA8 is specified as color-renderable, unlike GL_SRGB8. init.isSRGB = init.colorBits == 32 && colorspace == EGL_GL_COLORSPACE_SRGB; + init.isYFlipped = eglhook.IsYFlipped(dpy, surface); + eglhook.driver.SetDriverType(RDCDriver::OpenGLES); - eglhook.driver.WindowSize(surface, winwidth, winheight); + eglhook.driver.WindowSize(eglhook.windows[surface], winwidth, winheight); if(!eglhook.driver.UsesVRFrameMarkers()) - eglhook.driver.SwapBuffers(surface); + eglhook.driver.SwapBuffers(eglhook.windows[surface]); return EGL.PostSubBufferNV(dpy, surface, x, y, width, height); } diff --git a/renderdoc/driver/gl/gl_common.cpp b/renderdoc/driver/gl/gl_common.cpp index 284faf3e7..678016b88 100644 --- a/renderdoc/driver/gl/gl_common.cpp +++ b/renderdoc/driver/gl/gl_common.cpp @@ -1103,6 +1103,7 @@ GLInitParams::GLInitParams() multiSamples = 1; width = 32; height = 32; + isYFlipped = false; } bool GLInitParams::IsSupportedVersion(uint64_t ver) @@ -1120,6 +1121,10 @@ bool GLInitParams::IsSupportedVersion(uint64_t ver) if(ver == 0x1B) return true; + // 0x1C -> 0x1D - added isYFlipped init parameter for backbuffers on ANGLE. + if(ver == 0x1C) + return true; + return false; } @@ -1133,6 +1138,8 @@ void DoSerialise(SerialiserType &ser, GLInitParams &el) SERIALISE_MEMBER(multiSamples); SERIALISE_MEMBER(width); SERIALISE_MEMBER(height); + if(ser.VersionAtLeast(0x1D)) + SERIALISE_MEMBER(isYFlipped); } INSTANTIATE_SERIALISE_TYPE(GLInitParams); diff --git a/renderdoc/driver/gl/gl_driver.cpp b/renderdoc/driver/gl/gl_driver.cpp index 3ec7a9804..af18815a1 100644 --- a/renderdoc/driver/gl/gl_driver.cpp +++ b/renderdoc/driver/gl/gl_driver.cpp @@ -1636,7 +1636,7 @@ void WrappedOpenGL::SwapBuffers(void *windowHandle) } if(!overlayText.empty()) - RenderOverlayText(0.0f, 0.0f, overlayText.c_str()); + RenderOverlayText(0.0f, 0.0f, m_InitParams.isYFlipped, overlayText.c_str()); // swallow all errors we might have inadvertantly caused. This is // better than letting an error propagate and maybe screw up the @@ -1939,7 +1939,8 @@ bool WrappedOpenGL::EndFrameCapture(void *dev, void *wnd) { ContextData &ctxdata = GetCtxData(); - RenderOverlayText(0.0f, 0.0f, "Failed to capture frame %u: %s", m_FrameCounter, reasonString); + RenderOverlayText(0.0f, 0.0f, m_InitParams.isYFlipped, "Failed to capture frame %u: %s", + m_FrameCounter, reasonString); // swallow all errors we might have inadvertantly caused. This is // better than letting an error propagate and maybe screw up the @@ -2059,24 +2060,27 @@ WrappedOpenGL::BackbufferImage *WrappedOpenGL::SaveBackbufferImage() } // flip the image in-place - for(uint16_t y = 0; y <= thheight / 2; y++) + if(!m_InitParams.isYFlipped) { - uint16_t flipY = (thheight - 1 - y); - - for(uint16_t x = 0; x < thwidth; x++) + for(uint16_t y = 0; y <= thheight / 2; y++) { - byte save[3]; - save[0] = thpixels[(y * thwidth + x) * 3 + 0]; - save[1] = thpixels[(y * thwidth + x) * 3 + 1]; - save[2] = thpixels[(y * thwidth + x) * 3 + 2]; + uint16_t flipY = (thheight - 1 - y); - thpixels[(y * thwidth + x) * 3 + 0] = thpixels[(flipY * thwidth + x) * 3 + 0]; - thpixels[(y * thwidth + x) * 3 + 1] = thpixels[(flipY * thwidth + x) * 3 + 1]; - thpixels[(y * thwidth + x) * 3 + 2] = thpixels[(flipY * thwidth + x) * 3 + 2]; + for(uint16_t x = 0; x < thwidth; x++) + { + byte save[3]; + save[0] = thpixels[(y * thwidth + x) * 3 + 0]; + save[1] = thpixels[(y * thwidth + x) * 3 + 1]; + save[2] = thpixels[(y * thwidth + x) * 3 + 2]; - thpixels[(flipY * thwidth + x) * 3 + 0] = save[0]; - thpixels[(flipY * thwidth + x) * 3 + 1] = save[1]; - thpixels[(flipY * thwidth + x) * 3 + 2] = save[2]; + thpixels[(y * thwidth + x) * 3 + 0] = thpixels[(flipY * thwidth + x) * 3 + 0]; + thpixels[(y * thwidth + x) * 3 + 1] = thpixels[(flipY * thwidth + x) * 3 + 1]; + thpixels[(y * thwidth + x) * 3 + 2] = thpixels[(flipY * thwidth + x) * 3 + 2]; + + thpixels[(flipY * thwidth + x) * 3 + 0] = save[0]; + thpixels[(flipY * thwidth + x) * 3 + 1] = save[1]; + thpixels[(flipY * thwidth + x) * 3 + 2] = save[2]; + } } } diff --git a/renderdoc/driver/gl/gl_driver.h b/renderdoc/driver/gl/gl_driver.h index 198462f00..72b4c5d51 100644 --- a/renderdoc/driver/gl/gl_driver.h +++ b/renderdoc/driver/gl/gl_driver.h @@ -51,9 +51,10 @@ struct GLInitParams uint32_t multiSamples; uint32_t width; uint32_t height; + bool isYFlipped; // check if a frame capture section version is supported - static const uint64_t CurrentVersion = 0x1C; + static const uint64_t CurrentVersion = 0x1D; static bool IsSupportedVersion(uint64_t ver); }; @@ -440,8 +441,8 @@ private: static const int FONT_TEX_HEIGHT = 128; static const int FONT_MAX_CHARS = 256; - void RenderOverlayText(float x, float y, const char *fmt, ...); - void RenderOverlayStr(float x, float y, const char *str); + void RenderOverlayText(float x, float y, bool yflipped, const char *fmt, ...); + void RenderOverlayStr(float x, float y, bool yflipped, const char *str); struct BackbufferImage { diff --git a/renderdoc/driver/gl/gl_rendertext.cpp b/renderdoc/driver/gl/gl_rendertext.cpp index 8e87d2f56..b2089a59f 100644 --- a/renderdoc/driver/gl/gl_rendertext.cpp +++ b/renderdoc/driver/gl/gl_rendertext.cpp @@ -257,7 +257,7 @@ void WrappedOpenGL::ContextData::CreateDebugData() } } -void WrappedOpenGL::RenderOverlayText(float x, float y, const char *fmt, ...) +void WrappedOpenGL::RenderOverlayText(float x, float y, bool yflipped, const char *fmt, ...) { static char tmpBuf[4096]; @@ -273,18 +273,18 @@ void WrappedOpenGL::RenderOverlayText(float x, float y, const char *fmt, ...) textState.Push(ctxdata.Modern()); - RenderOverlayStr(x, y, tmpBuf); + RenderOverlayStr(x, y, yflipped, tmpBuf); textState.Pop(ctxdata.Modern()); } -void WrappedOpenGL::RenderOverlayStr(float x, float y, const char *text) +void WrappedOpenGL::RenderOverlayStr(float x, float y, bool yflipped, const char *text) { if(char *t = strchr((char *)text, '\n')) { *t = 0; - RenderOverlayStr(x, y, text); - RenderOverlayStr(x, y + 1.0f, t + 1); + RenderOverlayStr(x, y, yflipped, text); + RenderOverlayStr(x, y + 1.0f, yflipped, t + 1); *t = '\n'; return; } @@ -347,7 +347,7 @@ void WrappedOpenGL::RenderOverlayStr(float x, float y, const char *text) pos.y -= 1.0f; vertexData[(i * 6 + ch) * 5 + 0] = pos.x; - vertexData[(i * 6 + ch) * 5 + 1] = -pos.y; + vertexData[(i * 6 + ch) * 5 + 1] = yflipped ? pos.y : -pos.y; vertexData[(i * 6 + ch) * 5 + 2] = uv.x; vertexData[(i * 6 + ch) * 5 + 3] = uv.y; vertexData[(i * 6 + ch) * 5 + 4] = float(text[i] - FONT_FIRST_CHAR); @@ -529,6 +529,8 @@ void WrappedOpenGL::RenderOverlayStr(float x, float y, const char *text) vertices.push_back(Vec4f(maxx, miny, 0.0f, 0.0f)); vertices.push_back(Vec4f(minx, miny, 0.0f, 0.0f)); + float mul = yflipped ? -1.0f : 1.0f; + while(*text) { char c = *text; @@ -537,10 +539,10 @@ void WrappedOpenGL::RenderOverlayStr(float x, float y, const char *text) stbtt_GetBakedQuad(chardata, FONT_TEX_WIDTH, FONT_TEX_HEIGHT, c - FONT_FIRST_CHAR, &x, &y, &q, 1); - vertices.push_back(Vec4f(q.x0, q.y0, q.s0, q.t0)); - vertices.push_back(Vec4f(q.x1, q.y0, q.s1, q.t0)); - vertices.push_back(Vec4f(q.x1, q.y1, q.s1, q.t1)); - vertices.push_back(Vec4f(q.x0, q.y1, q.s0, q.t1)); + vertices.push_back(Vec4f(q.x0, q.y0 * mul, q.s0, q.t0)); + vertices.push_back(Vec4f(q.x1, q.y0 * mul, q.s1, q.t0)); + vertices.push_back(Vec4f(q.x1, q.y1 * mul, q.s1, q.t1)); + vertices.push_back(Vec4f(q.x0, q.y1 * mul, q.s0, q.t1)); maxx = RDCMAX(maxx, RDCMAX(q.x0, q.x1)); maxy = RDCMAX(maxy, RDCMAX(q.y0, q.y1)); diff --git a/renderdoc/driver/gl/gl_replay.cpp b/renderdoc/driver/gl/gl_replay.cpp index 4fc64424f..5de61ab50 100644 --- a/renderdoc/driver/gl/gl_replay.cpp +++ b/renderdoc/driver/gl/gl_replay.cpp @@ -3222,6 +3222,8 @@ ReplayStatus CreateReplayDevice(RDCFile *rdc, GLPlatform &platform, IReplayDrive ReadSerialiser ser(reader, Ownership::Stream); + ser.SetVersion(ver); + SystemChunk chunk = ser.ReadChunk(); if(chunk != SystemChunk::DriverInit)