aboutsummaryrefslogtreecommitdiffstats
path: root/LibOVR/Src/CAPI/GL/CAPI_GL_DistortionRenderer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'LibOVR/Src/CAPI/GL/CAPI_GL_DistortionRenderer.cpp')
-rw-r--r--LibOVR/Src/CAPI/GL/CAPI_GL_DistortionRenderer.cpp729
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, &currentSwapInterval);
- 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, &currentSwapInterval);
- 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