diff options
Diffstat (limited to 'LibOVR/Src/CAPI/GL/CAPI_GL_DistortionRenderer.cpp')
-rw-r--r-- | LibOVR/Src/CAPI/GL/CAPI_GL_DistortionRenderer.cpp | 729 |
1 files changed, 478 insertions, 251 deletions
diff --git a/LibOVR/Src/CAPI/GL/CAPI_GL_DistortionRenderer.cpp b/LibOVR/Src/CAPI/GL/CAPI_GL_DistortionRenderer.cpp index 21b6509..5ddbed2 100644 --- a/LibOVR/Src/CAPI/GL/CAPI_GL_DistortionRenderer.cpp +++ b/LibOVR/Src/CAPI/GL/CAPI_GL_DistortionRenderer.cpp @@ -5,12 +5,23 @@ Content : Distortion renderer header for GL Created : November 11, 2013 Authors : David Borel, Lee Cooper -Copyright : Copyright 2013 Oculus VR, Inc. All Rights reserved. +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. -Use of this software is subject to the terms of the Oculus Inc license -agreement provided at the time of installation or download, or which +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); +you may not use the Oculus VR Rift SDK except in compliance with the License, +which is provided at the time of installation or download, or which otherwise accompanies this software in either electronic or hard copy form. +You may obtain a copy of the License at + +http://www.oculusvr.com/licenses/LICENSE-3.2 + +Unless required by applicable law or agreed to in writing, the Oculus VR SDK +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + ************************************************************************************/ #include "CAPI_GL_DistortionRenderer.h" @@ -18,9 +29,18 @@ otherwise accompanies this software in either electronic or hard copy form. #include "CAPI_GL_DistortionShaders.h" #include "../../OVR_CAPI_GL.h" +#include "../../Kernel/OVR_Color.h" + +#if defined(OVR_OS_LINUX) + #include "../../Displays/OVR_Linux_SDKWindow.h" +#elif defined(OVR_OS_MAC) + #include <CoreGraphics/CGDirectDisplay.h> + #include <OpenGL/OpenGL.h> +#endif namespace OVR { namespace CAPI { namespace GL { + // Distortion pixel shader lookup. // Bit 0: Chroma Correction // Bit 1: Timewarp @@ -69,10 +89,10 @@ void DistortionShaderBitIndexCheck() struct DistortionVertex { - Vector2f Pos; - Vector2f TexR; - Vector2f TexG; - Vector2f TexB; + Vector2f ScreenPosNDC; + Vector2f TanEyeAnglesR; + Vector2f TanEyeAnglesG; + Vector2f TanEyeAnglesB; Color Col; }; @@ -92,10 +112,15 @@ struct LatencyVertex DistortionRenderer::DistortionRenderer(ovrHmd hmd, FrameTimeManager& timeManager, const HMDRenderState& renderState) : CAPI::DistortionRenderer(ovrRenderAPI_OpenGL, hmd, timeManager, renderState) + , RotateCCW90(false) , LatencyVAO(0) + , OverdriveFbo(0) { DistortionMeshVAOs[0] = 0; DistortionMeshVAOs[1] = 0; + + // Initialize render params. + memset(&RParams, 0, sizeof(RParams)); } DistortionRenderer::~DistortionRenderer() @@ -108,18 +133,14 @@ CAPI::DistortionRenderer* DistortionRenderer::Create(ovrHmd hmd, FrameTimeManager& timeManager, const HMDRenderState& renderState) { -#if !defined(OVR_OS_MAC) InitGLExtensions(); -#endif + return new DistortionRenderer(hmd, timeManager, renderState); } -bool DistortionRenderer::Initialize(const ovrRenderAPIConfig* apiConfig, - unsigned distortionCaps) +bool DistortionRenderer::Initialize(const ovrRenderAPIConfig* apiConfig) { - GfxState = *new GraphicsState(); - const ovrGLConfig* config = (const ovrGLConfig*)apiConfig; if (!config) @@ -132,42 +153,125 @@ bool DistortionRenderer::Initialize(const ovrRenderAPIConfig* apiConfig, } RParams.Multisample = config->OGL.Header.Multisample; - RParams.RTSize = config->OGL.Header.RTSize; + RParams.BackBufferSize = config->OGL.Header.BackBufferSize; #if defined(OVR_OS_WIN32) RParams.Window = (config->OGL.Window) ? config->OGL.Window : GetActiveWindow(); + RParams.DC = config->OGL.DC; #elif defined(OVR_OS_LINUX) - RParams.Disp = (config->OGL.Disp) ? config->OGL.Disp : XOpenDisplay(NULL); - RParams.Win = config->OGL.Win; - if (!RParams.Win) + RotateCCW90 = false; + if ( RState.DistortionCaps & ovrDistortionCap_LinuxDevFullscreen + && SDKWindow::getRotation(HMD) == DistRotateCCW90) { - int unused; - XGetInputFocus(RParams.Disp, &RParams.Win, &unused); + RotateCCW90 = true; + } + if (config->OGL.Disp) + { + RParams.Disp = config->OGL.Disp; + } + if (!RParams.Disp) + { + RParams.Disp = glXGetCurrentDisplay(); + } + if (!RParams.Disp) + { + OVR_DEBUG_LOG(("glXGetCurrentDisplay failed.")); + return false; } #endif - DistortionCaps = distortionCaps; - - //DistortionWarper.SetVsync((hmdCaps & ovrHmdCap_NoVSync) ? false : true); + DistortionMeshVAOs[0] = 0; + DistortionMeshVAOs[1] = 0; + + LatencyVAO = 0; + + GL::AutoContext autoGLContext(distortionContext); // Initializes distortionContext if not already, saves the current GL context, binds distortionContext, then at the end of scope re-binds the current GL context. pEyeTextures[0] = *new Texture(&RParams, 0, 0); pEyeTextures[1] = *new Texture(&RParams, 0, 0); initBuffersAndShaders(); + initOverdrive(); + return true; } -void DistortionRenderer::SubmitEye(int eyeId, ovrTexture* eyeTexture) +void DistortionRenderer::initOverdrive() { - // Doesn't do a lot in here?? - const ovrGLTexture* tex = (const ovrGLTexture*)eyeTexture; + if(RState.DistortionCaps & ovrDistortionCap_Overdrive) + { + LastUsedOverdriveTextureIndex = 0; + + glGenFramebuffers(1, &OverdriveFbo); + + GLint internalFormat = (RState.DistortionCaps & ovrDistortionCap_SRGB) ? GL_SRGB_ALPHA : GL_RGBA; + + for (int i = 0; i < NumOverdriveTextures ; i++) + { + pOverdriveTextures[i] = *new Texture(&RParams, RParams.BackBufferSize.w, RParams.BackBufferSize.h); + + glBindTexture(GL_TEXTURE_2D, pOverdriveTextures[i]->TexId); + glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, RParams.BackBufferSize.w, RParams.BackBufferSize.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + OVR_ASSERT( glGetError() == GL_NO_ERROR ); + + pOverdriveTextures[i]->SetSampleMode(Sample_ClampBorder | Sample_Linear); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); + OVR_ASSERT(glGetError() == 0); + + // clear the new buffer + glBindFramebuffer(GL_FRAMEBUFFER, OverdriveFbo ); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, pOverdriveTextures[i]->TexId, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); + OVR_ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0}; + glDrawBuffers(OVR_ARRAY_COUNT(drawBuffers), drawBuffers); + glClearColor(0,0,0,1); + glClear(GL_COLOR_BUFFER_BIT); + } - // Write in values - eachEye[eyeId].texture = tex->OGL.TexId; + { + OverdriveBackBufferTexture = *new Texture(&RParams, RParams.BackBufferSize.w, RParams.BackBufferSize.h); + + glBindTexture(GL_TEXTURE_2D, OverdriveBackBufferTexture->TexId); + glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, RParams.BackBufferSize.w, RParams.BackBufferSize.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + OVR_ASSERT(glGetError() == 0); + + OverdriveBackBufferTexture->SetSampleMode(Sample_ClampBorder | Sample_Linear); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); + OVR_ASSERT(glGetError() == 0); + + // clear the new buffer + glBindFramebuffer(GL_FRAMEBUFFER, OverdriveFbo ); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, OverdriveBackBufferTexture->TexId, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); + OVR_ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0}; + glDrawBuffers(OVR_ARRAY_COUNT(drawBuffers), drawBuffers); + glClearColor(0,0,0,1); + glClear(GL_COLOR_BUFFER_BIT); + } + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + else + { + LastUsedOverdriveTextureIndex = -1; + } +} + +void DistortionRenderer::SubmitEye(int eyeId, const ovrTexture* eyeTexture) +{ + // Doesn't do a lot in here?? + const ovrGLTexture* tex = (const ovrGLTexture*)eyeTexture; if (tex) { + // Write in values + eachEye[eyeId].texture = tex->OGL.TexId; + // Its only at this point we discover what the viewport of the texture is. // because presumably we allow users to realtime adjust the resolution. eachEye[eyeId].TextureSize = tex->OGL.Header.TextureSize; @@ -179,216 +283,176 @@ void DistortionRenderer::SubmitEye(int eyeId, ovrTexture* eyeTexture) eachEye[eyeId].TextureSize, eachEye[eyeId].RenderViewport, eachEye[eyeId].UVScaleOffset ); + if (!(RState.DistortionCaps & ovrDistortionCap_FlipInput)) + { + eachEye[eyeId].UVScaleOffset[0].y = -eachEye[eyeId].UVScaleOffset[0].y; + eachEye[eyeId].UVScaleOffset[1].y = 1.0f - eachEye[eyeId].UVScaleOffset[1].y; + } + pEyeTextures[eyeId]->UpdatePlaceholderTexture(tex->OGL.TexId, tex->OGL.Header.TextureSize); } } -void DistortionRenderer::EndFrame(bool swapBuffers, - unsigned char* latencyTesterDrawColor, unsigned char* latencyTester2DrawColor) +void DistortionRenderer::renderEndFrame() { - if (!TimeManager.NeedDistortionTimeMeasurement()) - { - if (RState.DistortionCaps & ovrDistortionCap_TimeWarp) - { - // Wait for timewarp distortion if it is time and Gpu idle - FlushGpuAndWaitTillTime(TimeManager.GetFrameTiming().TimewarpPointTime); - } + renderDistortion(pEyeTextures[0], pEyeTextures[1]); - renderDistortion(pEyeTextures[0], pEyeTextures[1]); + // TODO: Add rendering context to callback. + if(RegisteredPostDistortionCallback) + RegisteredPostDistortionCallback(NULL); + + if(LatencyTest2Active) + { + renderLatencyPixel(LatencyTest2DrawColor); } - else +} + +void DistortionRenderer::EndFrame(bool swapBuffers) +{ + Context currContext; + currContext.InitFromCurrent(); +#if defined(OVR_OS_MAC) + distortionContext.SetSurface( currContext ); +#endif + + // Don't spin if we are explicitly asked not to + if ((RState.DistortionCaps & ovrDistortionCap_TimeWarp) && + !(RState.DistortionCaps & ovrDistortionCap_ProfileNoTimewarpSpinWaits)) { - // If needed, measure distortion time so that TimeManager can better estimate - // latency-reducing time-warp wait timing. - WaitUntilGpuIdle(); - double distortionStartTime = ovr_GetTimeInSeconds(); + if (!TimeManager.NeedDistortionTimeMeasurement()) + { + // Wait for timewarp distortion if it is time and Gpu idle + FlushGpuAndWaitTillTime(TimeManager.GetFrameTiming().TimewarpPointTime); - renderDistortion(pEyeTextures[0], pEyeTextures[1]); + distortionContext.Bind(); + renderEndFrame(); + } + else + { + // If needed, measure distortion time so that TimeManager can better estimate + // latency-reducing time-warp wait timing. + WaitUntilGpuIdle(); + double distortionStartTime = ovr_GetTimeInSeconds(); - WaitUntilGpuIdle(); - TimeManager.AddDistortionTimeMeasurement(ovr_GetTimeInSeconds() - distortionStartTime); - } + distortionContext.Bind(); + renderEndFrame(); - if(latencyTesterDrawColor) + WaitUntilGpuIdle(); + TimeManager.AddDistortionTimeMeasurement(ovr_GetTimeInSeconds() - distortionStartTime); + } + } + else { - renderLatencyQuad(latencyTesterDrawColor); + distortionContext.Bind(); + renderEndFrame(); } - else if(latencyTester2DrawColor) + + if(LatencyTestActive) { - renderLatencyPixel(latencyTester2DrawColor); + renderLatencyQuad(LatencyTestDrawColor); } if (swapBuffers) { bool useVsync = ((RState.EnabledHmdCaps & ovrHmdCap_NoVSync) == 0); - int swapInterval = (useVsync) ? 1 : 0; + int ourSwapInterval = (useVsync) ? 1 : 0; + int originalSwapInterval; + #if defined(OVR_OS_WIN32) - if (wglGetSwapIntervalEXT() != swapInterval) - wglSwapIntervalEXT(swapInterval); + originalSwapInterval = wglGetSwapIntervalEXT(); + + if (ourSwapInterval != originalSwapInterval) + wglSwapIntervalEXT(ourSwapInterval); - HDC dc = GetDC(RParams.Window); + HDC dc = (RParams.DC != NULL) ? RParams.DC : GetDC(RParams.Window); BOOL success = SwapBuffers(dc); - ReleaseDC(RParams.Window, dc); - OVR_ASSERT(success); - OVR_UNUSED(success); + OVR_ASSERT_AND_UNUSED(success, success); + + if (RParams.DC == NULL) + ReleaseDC(RParams.Window, dc); + #elif defined(OVR_OS_MAC) + originalSwapInterval = 0; CGLContextObj context = CGLGetCurrentContext(); - GLint currentSwapInterval = 0; - CGLGetParameter(context, kCGLCPSwapInterval, ¤tSwapInterval); - if (currentSwapInterval != swapInterval) - CGLSetParameter(context, kCGLCPSwapInterval, &swapInterval); + CGLError err = CGLGetParameter(context, kCGLCPSwapInterval, &originalSwapInterval); + OVR_ASSERT_AND_UNUSED(err == kCGLNoError, err); + + if (ourSwapInterval != originalSwapInterval) + CGLSetParameter(context, kCGLCPSwapInterval, &ourSwapInterval); CGLFlushDrawable(context); + #elif defined(OVR_OS_LINUX) - static const char* extensions = glXQueryExtensionsString(RParams.Disp, 0); - static bool supportsVSync = (extensions != NULL && strstr(extensions, "GLX_EXT_swap_control")); - if (supportsVSync) - { - GLuint currentSwapInterval = 0; - glXQueryDrawable(RParams.Disp, RParams.Win, GLX_SWAP_INTERVAL_EXT, ¤tSwapInterval); - if (currentSwapInterval != swapInterval) - glXSwapIntervalEXT(RParams.Disp, RParams.Win, swapInterval); - } - - glXSwapBuffers(RParams.Disp, RParams.Win); -#endif - } -} - -void DistortionRenderer::WaitUntilGpuIdle() -{ - glFlush(); - glFinish(); -} + originalSwapInterval = 0; + GLXDrawable drawable = glXGetCurrentDrawable(); + struct _XDisplay* x11Display = RParams.Disp; -double DistortionRenderer::FlushGpuAndWaitTillTime(double absTime) -{ - double initialTime = ovr_GetTimeInSeconds(); - if (initialTime >= absTime) - return 0.0; - - glFlush(); - glFinish(); + if(GLE_GLX_EXT_swap_control) + { + static_assert(sizeof(GLuint) == sizeof(originalSwapInterval), "size mismatch"); + glXQueryDrawable(x11Display, drawable, GLX_SWAP_INTERVAL_EXT, (GLuint*)&originalSwapInterval); - double newTime = initialTime; - volatile int i; + if (ourSwapInterval != originalSwapInterval) + glXSwapIntervalEXT(x11Display, drawable, ourSwapInterval); + } + else if (GLE_MESA_swap_control) // There is also GLX_SGI_swap_control + { + originalSwapInterval = glXGetSwapIntervalMESA(); - while (newTime < absTime) - { - for (int j = 0; j < 50; j++) - i = 0; + if (ourSwapInterval != originalSwapInterval) + glXSwapIntervalMESA(ourSwapInterval); + } - newTime = ovr_GetTimeInSeconds(); - } + glXSwapBuffers(x11Display, drawable); +#endif - // How long we waited - return newTime - initialTime; -} - - -DistortionRenderer::GraphicsState::GraphicsState() -{ - const char* glVersionString = (const char*)glGetString(GL_VERSION); - OVR_DEBUG_LOG(("GL_VERSION STRING: %s", (const char*)glVersionString)); - char prefix[64]; - bool foundVersion = false; - - for (int i = 10; i < 30; ++i) - { - int major = i / 10; - int minor = i % 10; - OVR_sprintf(prefix, 64, "%d.%d", major, minor); - if (strstr(glVersionString, prefix) == glVersionString) + // Force GPU to flush the scene, resulting in the lowest possible latency. + // It's critical that this flush is *after* present, because it results in the wait + // below completing after the vsync. + // With the display driver (direct mode) this flush is obsolete and theoretically + // should be a no-op and so doesn't need to be done if running in direct mode. + if (RState.OurHMDInfo.InCompatibilityMode && + !(RState.DistortionCaps & ovrDistortionCap_ProfileNoTimewarpSpinWaits)) + WaitUntilGpuIdle(); + + // Restore the original swap interval if we changed it above. + if (originalSwapInterval != ourSwapInterval) { - GlMajorVersion = major; - GlMinorVersion = minor; - foundVersion = true; - break; +#if defined(OVR_OS_WIN32) + wglSwapIntervalEXT(originalSwapInterval); +#elif defined(OVR_OS_MAC) + CGLSetParameter(context, kCGLCPSwapInterval, &originalSwapInterval); +#elif defined(OVR_OS_LINUX) + if(GLE_GLX_EXT_swap_control) + glXSwapIntervalEXT(x11Display, drawable, (GLuint)originalSwapInterval); + else if(GLE_MESA_swap_control) + glXSwapIntervalMESA(originalSwapInterval); +#endif } } - - if (!foundVersion) - { - glGetIntegerv(GL_MAJOR_VERSION, &GlMajorVersion); - glGetIntegerv(GL_MAJOR_VERSION, &GlMinorVersion); - } - OVR_ASSERT(GlMajorVersion >= 2); - - if (GlMajorVersion >= 3) - { - SupportsVao = true; - } - else - { - const char* extensions = (const char*)glGetString(GL_EXTENSIONS); - SupportsVao = (strstr("GL_ARB_vertex_array_object", extensions) != NULL); - } -} - - -void DistortionRenderer::GraphicsState::ApplyBool(GLenum Name, GLint Value) -{ - if (Value != 0) - glEnable(Name); - else - glDisable(Name); + currContext.Bind(); } - - -void DistortionRenderer::GraphicsState::Save() + +void DistortionRenderer::WaitUntilGpuIdle() { - glGetIntegerv(GL_VIEWPORT, Viewport); - glGetFloatv(GL_COLOR_CLEAR_VALUE, ClearColor); - glGetIntegerv(GL_DEPTH_TEST, &DepthTest); - glGetIntegerv(GL_CULL_FACE, &CullFace); - glGetIntegerv(GL_CURRENT_PROGRAM, &Program); - glGetIntegerv(GL_ACTIVE_TEXTURE, &ActiveTexture); - glGetIntegerv(GL_TEXTURE_BINDING_2D, &TextureBinding); - glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &VertexArray); - glGetIntegerv(GL_FRAMEBUFFER_BINDING, &FrameBufferBinding); - glGetIntegerv(GL_BLEND, &Blend); - glGetIntegerv(GL_COLOR_WRITEMASK, ColorWritemask); - glGetIntegerv(GL_DITHER, &Dither); - glGetIntegerv(GL_RASTERIZER_DISCARD, &RasterizerDiscard); - if (GlMajorVersion >= 3 && GlMajorVersion >= 2) - glGetIntegerv(GL_SAMPLE_MASK, &SampleMask); - glGetIntegerv(GL_SCISSOR_TEST, &ScissorTest); - - IsValid = true; + glFinish(); // Block until current OpenGL commands (including swap) are complete. } - -void DistortionRenderer::GraphicsState::Restore() +double DistortionRenderer::FlushGpuAndWaitTillTime(double absTime) { - // Don't allow restore-before-save. - if (!IsValid) - return; + // because glFlush() is not strict enough certain GL drivers + // we do a glFinish(), but before doing so, we make sure we're not + // running late + double initialTime = ovr_GetTimeInSeconds(); + if (initialTime >= absTime) + return 0.0; - glViewport(Viewport[0], Viewport[1], Viewport[2], Viewport[3]); - glClearColor(ClearColor[0], ClearColor[1], ClearColor[2], ClearColor[3]); - - ApplyBool(GL_DEPTH_TEST, DepthTest); - ApplyBool(GL_CULL_FACE, CullFace); - - glUseProgram(Program); - glActiveTexture(ActiveTexture); - glBindTexture(GL_TEXTURE_2D, TextureBinding); - if (SupportsVao) - glBindVertexArray(VertexArray); - glBindFramebuffer(GL_FRAMEBUFFER, FrameBufferBinding); - - ApplyBool(GL_BLEND, Blend); - - glColorMask((GLboolean)ColorWritemask[0], (GLboolean)ColorWritemask[1], (GLboolean)ColorWritemask[2], (GLboolean)ColorWritemask[3]); - ApplyBool(GL_DITHER, Dither); - ApplyBool(GL_RASTERIZER_DISCARD, RasterizerDiscard); - if (GlMajorVersion >= 3 && GlMajorVersion >= 2) - ApplyBool(GL_SAMPLE_MASK, SampleMask); - ApplyBool(GL_SCISSOR_TEST, ScissorTest); -} + glFinish(); + return WaitTillTime(absTime); +} void DistortionRenderer::initBuffersAndShaders() { @@ -397,8 +461,6 @@ void DistortionRenderer::initBuffersAndShaders() // Allocate & generate distortion mesh vertices. ovrDistortionMesh meshData; -// double startT = ovr_GetTimeInSeconds(); - if (!ovrHmd_CreateDistortionMesh( HMD, RState.EyeRenderDesc[eyeNum].Eye, RState.EyeRenderDesc[eyeNum].Fov, @@ -416,16 +478,36 @@ void DistortionRenderer::initBuffersAndShaders() for ( unsigned vertNum = 0; vertNum < meshData.VertexCount; vertNum++ ) { - pCurVBVert->Pos.x = pCurOvrVert->Pos.x; - pCurVBVert->Pos.y = pCurOvrVert->Pos.y; - pCurVBVert->TexR = (*(Vector2f*)&pCurOvrVert->TexR); - pCurVBVert->TexG = (*(Vector2f*)&pCurOvrVert->TexG); - pCurVBVert->TexB = (*(Vector2f*)&pCurOvrVert->TexB); + pCurVBVert->ScreenPosNDC.x = pCurOvrVert->ScreenPosNDC.x; + pCurVBVert->ScreenPosNDC.y = pCurOvrVert->ScreenPosNDC.y; + + if (RotateCCW90) + { + OVR::Alg::Swap(pCurVBVert->ScreenPosNDC.x, pCurVBVert->ScreenPosNDC.y); + pCurVBVert->ScreenPosNDC.x = -pCurVBVert->ScreenPosNDC.x; + } + + // Previous code here did this: pCurVBVert->TanEyeAnglesR = (*(Vector2f*)&pCurOvrVert->TanEyeAnglesR); However that's an usafe + // cast of unrelated types which can result in undefined behavior by a conforming compiler. A safe equivalent is simply memcpy. + static_assert(sizeof(OVR::Vector2f) == sizeof(ovrVector2f), "Mismatch of structs that are presumed binary equivalents."); + memcpy(&pCurVBVert->TanEyeAnglesR, &pCurOvrVert->TanEyeAnglesR, sizeof(pCurVBVert->TanEyeAnglesR)); + memcpy(&pCurVBVert->TanEyeAnglesG, &pCurOvrVert->TanEyeAnglesG, sizeof(pCurVBVert->TanEyeAnglesG)); + memcpy(&pCurVBVert->TanEyeAnglesB, &pCurOvrVert->TanEyeAnglesB, sizeof(pCurVBVert->TanEyeAnglesB)); + // Convert [0.0f,1.0f] to [0,255] - pCurVBVert->Col.R = (OVR::UByte)( pCurOvrVert->VignetteFactor * 255.99f ); + if (RState.DistortionCaps & ovrDistortionCap_Vignette) + { + if(RState.DistortionCaps & ovrDistortionCap_SRGB) + pCurOvrVert->VignetteFactor = pow(pCurOvrVert->VignetteFactor, 2.1f); + + pCurVBVert->Col.R = (uint8_t)( Alg::Max ( pCurOvrVert->VignetteFactor, 0.0f ) * 255.99f ); + } + else + pCurVBVert->Col.R = 255; + pCurVBVert->Col.G = pCurVBVert->Col.R; pCurVBVert->Col.B = pCurVBVert->Col.R; - pCurVBVert->Col.A = (OVR::UByte)( pCurOvrVert->TimeWarpFactor * 255.99f );; + pCurVBVert->Col.A = (uint8_t)( pCurOvrVert->TimeWarpFactor * 255.99f );; pCurOvrVert++; pCurVBVert++; } @@ -433,7 +515,7 @@ void DistortionRenderer::initBuffersAndShaders() DistortionMeshVBs[eyeNum] = *new Buffer(&RParams); DistortionMeshVBs[eyeNum]->Data ( Buffer_Vertex | Buffer_ReadOnly, pVBVerts, sizeof(DistortionVertex) * meshData.VertexCount ); DistortionMeshIBs[eyeNum] = *new Buffer(&RParams); - DistortionMeshIBs[eyeNum]->Data ( Buffer_Index | Buffer_ReadOnly, meshData.pIndexData, ( sizeof(SInt16) * meshData.IndexCount ) ); + DistortionMeshIBs[eyeNum]->Data ( Buffer_Index | Buffer_ReadOnly, meshData.pIndexData, ( sizeof(int16_t) * meshData.IndexCount ) ); OVR_FREE ( pVBVerts ); ovrHmd_DestroyDistortionMesh( &meshData ); @@ -444,21 +526,56 @@ void DistortionRenderer::initBuffersAndShaders() void DistortionRenderer::renderDistortion(Texture* leftEyeTexture, Texture* rightEyeTexture) { - GraphicsState* glState = (GraphicsState*)GfxState.GetPtr(); + bool overdriveActive = IsOverdriveActive(); + int currOverdriveTextureIndex = -1; + + if(overdriveActive) + { + currOverdriveTextureIndex = (LastUsedOverdriveTextureIndex + 1) % NumOverdriveTextures; + + //glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindFramebuffer(GL_FRAMEBUFFER, OverdriveFbo ); + + GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}; + glDrawBuffers(OVR_ARRAY_COUNT(drawBuffers), drawBuffers); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, pOverdriveTextures[currOverdriveTextureIndex]->TexId, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, OverdriveBackBufferTexture->TexId, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); + OVR_ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + } + else + { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } - glBindFramebuffer(GL_FRAMEBUFFER, 0); - setViewport( Recti(0,0, RParams.RTSize.w, RParams.RTSize.h) ); + setViewport( Recti(0,0, RParams.BackBufferSize.w, RParams.BackBufferSize.h) ); + + if (RState.DistortionCaps & ovrDistortionCap_SRGB) + glEnable(GL_FRAMEBUFFER_SRGB); + else + glDisable(GL_FRAMEBUFFER_SRGB); glDisable(GL_CULL_FACE); glDisable(GL_DEPTH_TEST); - glDisable(GL_BLEND); - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); + if (GLE_EXT_draw_buffers2) + { + glDisablei(GL_BLEND, 0); + glColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); + } + else + { + glDisable(GL_BLEND); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); + } + glDisable(GL_DITHER); glDisable(GL_RASTERIZER_DISCARD); - if (glState->GlMajorVersion >= 3 && glState->GlMajorVersion >= 2) + if (GLEContext::GetCurrentContext()->WholeVersion >= 302) + { glDisable(GL_SAMPLE_MASK); - glDisable(GL_SCISSOR_TEST); + } glClearColor( RState.ClearColor[0], @@ -469,14 +586,31 @@ void DistortionRenderer::renderDistortion(Texture* leftEyeTexture, Texture* righ glClear(GL_COLOR_BUFFER_BIT); for (int eyeNum = 0; eyeNum < 2; eyeNum++) - { + { ShaderFill distortionShaderFill(DistortionShader); distortionShaderFill.SetTexture(0, eyeNum == 0 ? leftEyeTexture : rightEyeTexture); + if(overdriveActive) + { + distortionShaderFill.SetTexture(1, pOverdriveTextures[LastUsedOverdriveTextureIndex]); + + float overdriveScaleRegularRise; + float overdriveScaleRegularFall; + GetOverdriveScales(overdriveScaleRegularRise, overdriveScaleRegularFall); + DistortionShader->SetUniform3f("OverdriveScales_IsSrgb", overdriveScaleRegularRise, overdriveScaleRegularFall, + (RState.DistortionCaps & ovrDistortionCap_SRGB) ? 1.0f : -1.0f); + } + else + { + // -1.0f disables PLO + DistortionShader->SetUniform3f("OverdriveScales_IsSrgb", -1.0f, -1.0f, -1.0f); + } + DistortionShader->SetUniform2f("EyeToSourceUVScale", eachEye[eyeNum].UVScaleOffset[0].x, eachEye[eyeNum].UVScaleOffset[0].y); - DistortionShader->SetUniform2f("EyeToSourceUVOffset", eachEye[eyeNum].UVScaleOffset[1].x, eachEye[eyeNum].UVScaleOffset[1].y); + // Convert Y to 1-Y as OpenGL is inverse of D3D + DistortionShader->SetUniform2f("EyeToSourceUVOffset", eachEye[eyeNum].UVScaleOffset[1].x, 1.0f - eachEye[eyeNum].UVScaleOffset[1].y); - if (DistortionCaps & ovrDistortionCap_TimeWarp) + if (RState.DistortionCaps & ovrDistortionCap_TimeWarp) { ovrMatrix4f timeWarpMatrices[2]; ovrHmd_GetEyeTimewarpMatrices(HMD, (ovrEyeType)eyeNum, @@ -495,8 +629,36 @@ void DistortionRenderer::renderDistortion(Texture* leftEyeTexture, Texture* righ 0, (int)DistortionMeshIBs[eyeNum]->GetSize()/2, Prim_Triangles, &DistortionMeshVAOs[eyeNum], true); } } + + LastUsedOverdriveTextureIndex = currOverdriveTextureIndex; + + // Re-activate to only draw on back buffer + if(overdriveActive) + { + GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0}; + glDrawBuffers(OVR_ARRAY_COUNT(drawBuffers), drawBuffers); + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + //glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); + //glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, 0, 0); + OVR_ASSERT(glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + + glBindFramebuffer( GL_READ_FRAMEBUFFER, OverdriveFbo ); + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, OverdriveBackBufferTexture->TexId, 0); + glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); + OVR_ASSERT(glCheckFramebufferStatus(GL_READ_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); + + glBlitFramebuffer( 0, 0, OverdriveBackBufferTexture->GetWidth(), OverdriveBackBufferTexture->GetHeight(), + 0, 0, OverdriveBackBufferTexture->GetWidth(), OverdriveBackBufferTexture->GetHeight(), + GL_COLOR_BUFFER_BIT, GL_NEAREST ); + + glBindFramebuffer( GL_FRAMEBUFFER, 0 ); + GLint err = glGetError(); + OVR_ASSERT(!err); OVR_UNUSED(err); + } } + void DistortionRenderer::createDrawQuad() { const int numQuadVerts = 4; @@ -536,20 +698,21 @@ void DistortionRenderer::renderLatencyQuad(unsigned char* latencyTesterDrawColor createDrawQuad(); } - ShaderFill quadFill(SimpleQuadShader); + Ptr<ShaderSet> quadShader = (RState.DistortionCaps & ovrDistortionCap_SRGB) ? SimpleQuadGammaShader : SimpleQuadShader; + ShaderFill quadFill(quadShader); //quadFill.SetInputLayout(SimpleQuadVertexIL); - setViewport(Recti(0,0, RParams.RTSize.w, RParams.RTSize.h)); + setViewport(Recti(0,0, RParams.BackBufferSize.w, RParams.BackBufferSize.h)); - SimpleQuadShader->SetUniform2f("Scale", 0.2f, 0.2f); - SimpleQuadShader->SetUniform4f("Color", (float)latencyTesterDrawColor[0] / 255.99f, - (float)latencyTesterDrawColor[0] / 255.99f, - (float)latencyTesterDrawColor[0] / 255.99f, - 1.0f); + quadShader->SetUniform2f("Scale", 0.3f, 0.3f); + quadShader->SetUniform4f("Color", (float)latencyTesterDrawColor[0] / 255.99f, + (float)latencyTesterDrawColor[0] / 255.99f, + (float)latencyTesterDrawColor[0] / 255.99f, + 1.0f); for(int eyeNum = 0; eyeNum < 2; eyeNum++) { - SimpleQuadShader->SetUniform2f("PositionOffset", eyeNum == 0 ? -0.4f : 0.4f, 0.0f); + quadShader->SetUniform2f("PositionOffset", eyeNum == 0 ? -0.5f : 0.5f, 0.0f); renderPrimitives(&quadFill, LatencyTesterQuadVB, NULL, 0, numQuadVerts, Prim_TriangleStrip, &LatencyVAO, false); } } @@ -563,18 +726,31 @@ void DistortionRenderer::renderLatencyPixel(unsigned char* latencyTesterPixelCol createDrawQuad(); } - ShaderFill quadFill(SimpleQuadShader); + Ptr<ShaderSet> quadShader = (RState.DistortionCaps & ovrDistortionCap_SRGB) ? SimpleQuadGammaShader : SimpleQuadShader; + ShaderFill quadFill(quadShader); - setViewport(Recti(0,0, RParams.RTSize.w, RParams.RTSize.h)); + setViewport(Recti(0,0, RParams.BackBufferSize.w, RParams.BackBufferSize.h)); - SimpleQuadShader->SetUniform4f("Color", (float)latencyTesterPixelColor[0] / 255.99f, - (float)latencyTesterPixelColor[0] / 255.99f, - (float)latencyTesterPixelColor[0] / 255.99f, - 1.0f); +#ifdef OVR_BUILD_DEBUG + quadShader->SetUniform4f("Color", (float)latencyTesterPixelColor[0] / 255.99f, + (float)latencyTesterPixelColor[1] / 255.99f, + (float)latencyTesterPixelColor[2] / 255.99f, + 1.0f); - Vector2f scale(2.0f / RParams.RTSize.w, 2.0f / RParams.RTSize.h); - SimpleQuadShader->SetUniform2f("Scale", scale.x, scale.y); - SimpleQuadShader->SetUniform2f("PositionOffset", 1.0f, 1.0f); + Vector2f scale(20.0f / RParams.BackBufferSize.w, 20.0f / RParams.BackBufferSize.h); +#else + quadShader->SetUniform4f("Color", (float)latencyTesterPixelColor[0] / 255.99f, + (float)latencyTesterPixelColor[0] / 255.99f, + (float)latencyTesterPixelColor[0] / 255.99f, + 1.0f); + + Vector2f scale(1.0f / RParams.BackBufferSize.w, 1.0f / RParams.BackBufferSize.h); +#endif + quadShader->SetUniform2f("Scale", scale.x, scale.y); + if (!RotateCCW90) + quadShader->SetUniform2f("PositionOffset", 1.0f-scale.x, 1.0f-scale.y); + else + quadShader->SetUniform2f("PositionOffset", -(1.0f-scale.x), 1.0f-scale.y); renderPrimitives(&quadFill, LatencyTesterQuadVB, NULL, 0, numQuadVerts, Prim_TriangleStrip, &LatencyVAO, false); } @@ -584,8 +760,6 @@ void DistortionRenderer::renderPrimitives( int offset, int count, PrimitiveType rprim, GLuint* vao, bool isDistortionMesh) { - GraphicsState* glState = (GraphicsState*)GfxState.GetPtr(); - GLenum prim; switch (rprim) { @@ -611,20 +785,22 @@ void DistortionRenderer::renderPrimitives( { if (*vao != 0) { - glBindVertexArray(*vao); + glBindVertexArray(*vao); if (isDistortionMesh) glDrawElements(prim, count, GL_UNSIGNED_SHORT, NULL); else glDrawArrays(prim, 0, count); + + glBindVertexArray(0); } else { - if (glState->SupportsVao) + if (GL_ARB_vertex_array_object) { glGenVertexArrays(1, vao); glBindVertexArray(*vao); - } + } int attributeCount = (isDistortionMesh) ? 5 : 1; int* locs = new int[attributeCount]; @@ -641,11 +817,11 @@ void DistortionRenderer::renderPrimitives( locs[3] = glGetAttribLocation(prog, "TexCoord1"); locs[4] = glGetAttribLocation(prog, "TexCoord2"); - glVertexAttribPointer(locs[0], 2, GL_FLOAT, false, sizeof(DistortionVertex), reinterpret_cast<char*>(offset)+offsetof(DistortionVertex, Pos)); + glVertexAttribPointer(locs[0], 2, GL_FLOAT, false, sizeof(DistortionVertex), reinterpret_cast<char*>(offset)+offsetof(DistortionVertex, ScreenPosNDC)); glVertexAttribPointer(locs[1], 4, GL_UNSIGNED_BYTE, true, sizeof(DistortionVertex), reinterpret_cast<char*>(offset)+offsetof(DistortionVertex, Col)); - glVertexAttribPointer(locs[2], 2, GL_FLOAT, false, sizeof(DistortionVertex), reinterpret_cast<char*>(offset)+offsetof(DistortionVertex, TexR)); - glVertexAttribPointer(locs[3], 2, GL_FLOAT, false, sizeof(DistortionVertex), reinterpret_cast<char*>(offset)+offsetof(DistortionVertex, TexG)); - glVertexAttribPointer(locs[4], 2, GL_FLOAT, false, sizeof(DistortionVertex), reinterpret_cast<char*>(offset)+offsetof(DistortionVertex, TexB)); + glVertexAttribPointer(locs[2], 2, GL_FLOAT, false, sizeof(DistortionVertex), reinterpret_cast<char*>(offset)+offsetof(DistortionVertex, TanEyeAnglesR)); + glVertexAttribPointer(locs[3], 2, GL_FLOAT, false, sizeof(DistortionVertex), reinterpret_cast<char*>(offset)+offsetof(DistortionVertex, TanEyeAnglesG)); + glVertexAttribPointer(locs[4], 2, GL_FLOAT, false, sizeof(DistortionVertex), reinterpret_cast<char*>(offset)+offsetof(DistortionVertex, TanEyeAnglesB)); } else { @@ -663,13 +839,18 @@ void DistortionRenderer::renderPrimitives( glDrawArrays(prim, 0, count); - if (!glState->SupportsVao) + if (!GL_ARB_vertex_array_object) { for (int i = 0; i < attributeCount; ++i) glDisableVertexAttribArray(locs[i]); } delete[] locs; + + if (GL_ARB_vertex_array_object) + { + glBindVertexArray(0); + } } } } @@ -682,14 +863,10 @@ void DistortionRenderer::setViewport(const Recti& vp) void DistortionRenderer::initShaders() { - GraphicsState* glState = (GraphicsState*)GfxState.GetPtr(); - - const char* shaderPrefix = - (glState->GlMajorVersion < 3 || (glState->GlMajorVersion == 3 && glState->GlMinorVersion < 2)) ? - glsl2Prefix : glsl3Prefix; + const char* shaderPrefix = (GLEContext::GetCurrentContext()->WholeVersion >= 302) ? glsl3Prefix : glsl2Prefix; { - ShaderInfo vsInfo = DistortionVertexShaderLookup[DistortionVertexShaderBitMask & DistortionCaps]; + ShaderInfo vsInfo = DistortionVertexShaderLookup[DistortionVertexShaderBitMask & RState.DistortionCaps]; size_t vsSize = strlen(shaderPrefix)+vsInfo.ShaderSize; char* vsSource = new char[vsSize]; @@ -706,7 +883,7 @@ void DistortionRenderer::initShaders() delete[](vsSource); - ShaderInfo psInfo = DistortionPixelShaderLookup[DistortionPixelShaderBitMask & DistortionCaps]; + ShaderInfo psInfo = DistortionPixelShaderLookup[DistortionPixelShaderBitMask & RState.DistortionCaps]; size_t psSize = strlen(shaderPrefix)+psInfo.ShaderSize; char* psSource = new char[psSize]; @@ -751,18 +928,53 @@ void DistortionRenderer::initShaders() SimpleQuadShader->SetShader(ps); delete[](psSource); - } + } + { + size_t vsSize = strlen(shaderPrefix)+sizeof(SimpleQuad_vs); + char* vsSource = new char[vsSize]; + OVR_strcpy(vsSource, vsSize, shaderPrefix); + OVR_strcat(vsSource, vsSize, SimpleQuad_vs); + + Ptr<GL::VertexShader> vs = *new GL::VertexShader( + &RParams, + (void*)vsSource, vsSize, + SimpleQuad_vs_refl, sizeof(SimpleQuad_vs_refl) / sizeof(SimpleQuad_vs_refl[0])); + + SimpleQuadGammaShader = *new ShaderSet; + SimpleQuadGammaShader->SetShader(vs); + + delete[](vsSource); + + size_t psSize = strlen(shaderPrefix)+sizeof(SimpleQuadGamma_fs); + char* psSource = new char[psSize]; + OVR_strcpy(psSource, psSize, shaderPrefix); + OVR_strcat(psSource, psSize, SimpleQuadGamma_fs); + + Ptr<GL::FragmentShader> ps = *new GL::FragmentShader( + &RParams, + (void*)psSource, psSize, + SimpleQuadGamma_fs_refl, sizeof(SimpleQuadGamma_fs_refl) / sizeof(SimpleQuadGamma_fs_refl[0])); + + SimpleQuadGammaShader->SetShader(ps); + + delete[](psSource); + } } void DistortionRenderer::destroy() { - GraphicsState* glState = (GraphicsState*)GfxState.GetPtr(); + Context currContext; + currContext.InitFromCurrent(); + + distortionContext.Bind(); for(int eyeNum = 0; eyeNum < 2; eyeNum++) { - if (glState->SupportsVao) + if (GL_ARB_vertex_array_object) + { glDeleteVertexArrays(1, &DistortionMeshVAOs[eyeNum]); + } DistortionMeshVAOs[eyeNum] = 0; @@ -778,7 +990,22 @@ void DistortionRenderer::destroy() } LatencyTesterQuadVB.Clear(); - LatencyVAO = 0; + + if(LatencyVAO != 0) + { + glDeleteVertexArrays(1, &LatencyVAO); + LatencyVAO = 0; + } + + if(OverdriveFbo != 0) + { + glDeleteFramebuffers(1, &OverdriveFbo); + } + + currContext.Bind(); + distortionContext.Destroy(); + // Who is responsible for destroying the app's context? } + }}} // OVR::CAPI::GL |