aboutsummaryrefslogtreecommitdiffstats
path: root/LibOVR/Src/CAPI/GL/CAPI_GL_DistortionRenderer.cpp
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2014-06-19 17:03:28 +0200
committerSven Gothel <[email protected]>2014-06-19 17:03:28 +0200
commitd9a584844a60542519d813b5dc1a62428f14a0ae (patch)
tree942c10a5ebcd0aab65e9d6facb59778468f39d3b /LibOVR/Src/CAPI/GL/CAPI_GL_DistortionRenderer.cpp
Add OculusSDK 0.3.2 Linux Source Code w/o Samples, docs or binaries (libs or tools)
Diffstat (limited to 'LibOVR/Src/CAPI/GL/CAPI_GL_DistortionRenderer.cpp')
-rw-r--r--LibOVR/Src/CAPI/GL/CAPI_GL_DistortionRenderer.cpp784
1 files changed, 784 insertions, 0 deletions
diff --git a/LibOVR/Src/CAPI/GL/CAPI_GL_DistortionRenderer.cpp b/LibOVR/Src/CAPI/GL/CAPI_GL_DistortionRenderer.cpp
new file mode 100644
index 0000000..21b6509
--- /dev/null
+++ b/LibOVR/Src/CAPI/GL/CAPI_GL_DistortionRenderer.cpp
@@ -0,0 +1,784 @@
+/************************************************************************************
+
+Filename : CAPI_GL_DistortionRenderer.h
+Content : Distortion renderer header for GL
+Created : November 11, 2013
+Authors : David Borel, Lee Cooper
+
+Copyright : Copyright 2013 Oculus VR, Inc. 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
+otherwise accompanies this software in either electronic or hard copy form.
+
+************************************************************************************/
+
+#include "CAPI_GL_DistortionRenderer.h"
+
+#include "CAPI_GL_DistortionShaders.h"
+
+#include "../../OVR_CAPI_GL.h"
+
+namespace OVR { namespace CAPI { namespace GL {
+
+// Distortion pixel shader lookup.
+// Bit 0: Chroma Correction
+// Bit 1: Timewarp
+
+enum {
+ DistortionVertexShaderBitMask = 3,
+ DistortionVertexShaderCount = DistortionVertexShaderBitMask + 1,
+ DistortionPixelShaderBitMask = 1,
+ DistortionPixelShaderCount = DistortionPixelShaderBitMask + 1
+};
+
+struct ShaderInfo
+{
+ const char* ShaderData;
+ size_t ShaderSize;
+ const ShaderBase::Uniform* ReflectionData;
+ size_t ReflectionSize;
+};
+
+// Do add a new distortion shader use these macros (with or w/o reflection)
+#define SI_NOREFL(shader) { shader, sizeof(shader), NULL, 0 }
+#define SI_REFL__(shader) { shader, sizeof(shader), shader ## _refl, sizeof( shader ## _refl )/sizeof(*(shader ## _refl)) }
+
+
+static ShaderInfo DistortionVertexShaderLookup[DistortionVertexShaderCount] =
+{
+ SI_REFL__(Distortion_vs),
+ SI_REFL__(DistortionChroma_vs),
+ SI_REFL__(DistortionTimewarp_vs),
+ SI_REFL__(DistortionTimewarpChroma_vs)
+};
+
+static ShaderInfo DistortionPixelShaderLookup[DistortionPixelShaderCount] =
+{
+ SI_NOREFL(Distortion_fs),
+ SI_NOREFL(DistortionChroma_fs)
+};
+
+void DistortionShaderBitIndexCheck()
+{
+ OVR_COMPILER_ASSERT(ovrDistortionCap_Chromatic == 1);
+ OVR_COMPILER_ASSERT(ovrDistortionCap_TimeWarp == 2);
+}
+
+
+
+struct DistortionVertex
+{
+ Vector2f Pos;
+ Vector2f TexR;
+ Vector2f TexG;
+ Vector2f TexB;
+ Color Col;
+};
+
+
+// Vertex type; same format is used for all shapes for simplicity.
+// Shapes are built by adding vertices to Model.
+struct LatencyVertex
+{
+ Vector3f Pos;
+ LatencyVertex (const Vector3f& p) : Pos(p) {}
+};
+
+
+//----------------------------------------------------------------------------
+// ***** GL::DistortionRenderer
+
+DistortionRenderer::DistortionRenderer(ovrHmd hmd, FrameTimeManager& timeManager,
+ const HMDRenderState& renderState)
+ : CAPI::DistortionRenderer(ovrRenderAPI_OpenGL, hmd, timeManager, renderState)
+ , LatencyVAO(0)
+{
+ DistortionMeshVAOs[0] = 0;
+ DistortionMeshVAOs[1] = 0;
+}
+
+DistortionRenderer::~DistortionRenderer()
+{
+ destroy();
+}
+
+// static
+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)
+{
+ GfxState = *new GraphicsState();
+
+ const ovrGLConfig* config = (const ovrGLConfig*)apiConfig;
+
+ if (!config)
+ {
+ // Cleanup
+ pEyeTextures[0].Clear();
+ pEyeTextures[1].Clear();
+ memset(&RParams, 0, sizeof(RParams));
+ return true;
+ }
+
+ RParams.Multisample = config->OGL.Header.Multisample;
+ RParams.RTSize = config->OGL.Header.RTSize;
+#if defined(OVR_OS_WIN32)
+ RParams.Window = (config->OGL.Window) ? config->OGL.Window : GetActiveWindow();
+#elif defined(OVR_OS_LINUX)
+ RParams.Disp = (config->OGL.Disp) ? config->OGL.Disp : XOpenDisplay(NULL);
+ RParams.Win = config->OGL.Win;
+ if (!RParams.Win)
+ {
+ int unused;
+ XGetInputFocus(RParams.Disp, &RParams.Win, &unused);
+ }
+#endif
+
+ DistortionCaps = distortionCaps;
+
+ //DistortionWarper.SetVsync((hmdCaps & ovrHmdCap_NoVSync) ? false : true);
+
+ pEyeTextures[0] = *new Texture(&RParams, 0, 0);
+ pEyeTextures[1] = *new Texture(&RParams, 0, 0);
+
+ initBuffersAndShaders();
+
+ return true;
+}
+
+
+void DistortionRenderer::SubmitEye(int eyeId, ovrTexture* eyeTexture)
+{
+ // Doesn't do a lot in here??
+ const ovrGLTexture* tex = (const ovrGLTexture*)eyeTexture;
+
+ // Write in values
+ eachEye[eyeId].texture = tex->OGL.TexId;
+
+ if (tex)
+ {
+ // 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;
+ eachEye[eyeId].RenderViewport = tex->OGL.Header.RenderViewport;
+
+ const ovrEyeRenderDesc& erd = RState.EyeRenderDesc[eyeId];
+
+ ovrHmd_GetRenderScaleAndOffset( erd.Fov,
+ eachEye[eyeId].TextureSize, eachEye[eyeId].RenderViewport,
+ eachEye[eyeId].UVScaleOffset );
+
+ pEyeTextures[eyeId]->UpdatePlaceholderTexture(tex->OGL.TexId,
+ tex->OGL.Header.TextureSize);
+ }
+}
+
+void DistortionRenderer::EndFrame(bool swapBuffers,
+ unsigned char* latencyTesterDrawColor, unsigned char* latencyTester2DrawColor)
+{
+ 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]);
+ }
+ else
+ {
+ // If needed, measure distortion time so that TimeManager can better estimate
+ // latency-reducing time-warp wait timing.
+ WaitUntilGpuIdle();
+ double distortionStartTime = ovr_GetTimeInSeconds();
+
+ renderDistortion(pEyeTextures[0], pEyeTextures[1]);
+
+ WaitUntilGpuIdle();
+ TimeManager.AddDistortionTimeMeasurement(ovr_GetTimeInSeconds() - distortionStartTime);
+ }
+
+ if(latencyTesterDrawColor)
+ {
+ renderLatencyQuad(latencyTesterDrawColor);
+ }
+ else if(latencyTester2DrawColor)
+ {
+ renderLatencyPixel(latencyTester2DrawColor);
+ }
+
+ if (swapBuffers)
+ {
+ bool useVsync = ((RState.EnabledHmdCaps & ovrHmdCap_NoVSync) == 0);
+ int swapInterval = (useVsync) ? 1 : 0;
+#if defined(OVR_OS_WIN32)
+ if (wglGetSwapIntervalEXT() != swapInterval)
+ wglSwapIntervalEXT(swapInterval);
+
+ HDC dc = GetDC(RParams.Window);
+ BOOL success = SwapBuffers(dc);
+ ReleaseDC(RParams.Window, dc);
+ OVR_ASSERT(success);
+ OVR_UNUSED(success);
+#elif defined(OVR_OS_MAC)
+ CGLContextObj context = CGLGetCurrentContext();
+ GLint currentSwapInterval = 0;
+ CGLGetParameter(context, kCGLCPSwapInterval, &currentSwapInterval);
+ if (currentSwapInterval != swapInterval)
+ CGLSetParameter(context, kCGLCPSwapInterval, &swapInterval);
+
+ 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();
+}
+
+double DistortionRenderer::FlushGpuAndWaitTillTime(double absTime)
+{
+ double initialTime = ovr_GetTimeInSeconds();
+ if (initialTime >= absTime)
+ return 0.0;
+
+ glFlush();
+ glFinish();
+
+ double newTime = initialTime;
+ volatile int i;
+
+ while (newTime < absTime)
+ {
+ for (int j = 0; j < 50; j++)
+ i = 0;
+
+ newTime = ovr_GetTimeInSeconds();
+ }
+
+ // 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)
+ {
+ GlMajorVersion = major;
+ GlMinorVersion = minor;
+ foundVersion = true;
+ break;
+ }
+ }
+
+ 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);
+}
+
+
+void DistortionRenderer::GraphicsState::Save()
+{
+ 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;
+}
+
+
+void DistortionRenderer::GraphicsState::Restore()
+{
+ // Don't allow restore-before-save.
+ if (!IsValid)
+ return;
+
+ 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);
+}
+
+
+void DistortionRenderer::initBuffersAndShaders()
+{
+ for ( int eyeNum = 0; eyeNum < 2; eyeNum++ )
+ {
+ // Allocate & generate distortion mesh vertices.
+ ovrDistortionMesh meshData;
+
+// double startT = ovr_GetTimeInSeconds();
+
+ if (!ovrHmd_CreateDistortionMesh( HMD,
+ RState.EyeRenderDesc[eyeNum].Eye,
+ RState.EyeRenderDesc[eyeNum].Fov,
+ RState.DistortionCaps,
+ &meshData) )
+ {
+ OVR_ASSERT(false);
+ continue;
+ }
+
+ // Now parse the vertex data and create a render ready vertex buffer from it
+ DistortionVertex * pVBVerts = (DistortionVertex*)OVR_ALLOC ( sizeof(DistortionVertex) * meshData.VertexCount );
+ DistortionVertex * pCurVBVert = pVBVerts;
+ ovrDistortionVertex* pCurOvrVert = meshData.pVertexData;
+
+ 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);
+ // Convert [0.0f,1.0f] to [0,255]
+ pCurVBVert->Col.R = (OVR::UByte)( pCurOvrVert->VignetteFactor * 255.99f );
+ pCurVBVert->Col.G = pCurVBVert->Col.R;
+ pCurVBVert->Col.B = pCurVBVert->Col.R;
+ pCurVBVert->Col.A = (OVR::UByte)( pCurOvrVert->TimeWarpFactor * 255.99f );;
+ pCurOvrVert++;
+ pCurVBVert++;
+ }
+
+ 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 ) );
+
+ OVR_FREE ( pVBVerts );
+ ovrHmd_DestroyDistortionMesh( &meshData );
+ }
+
+ initShaders();
+}
+
+void DistortionRenderer::renderDistortion(Texture* leftEyeTexture, Texture* rightEyeTexture)
+{
+ GraphicsState* glState = (GraphicsState*)GfxState.GetPtr();
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ setViewport( Recti(0,0, RParams.RTSize.w, RParams.RTSize.h) );
+
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_DEPTH_TEST);
+ 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)
+ glDisable(GL_SAMPLE_MASK);
+ glDisable(GL_SCISSOR_TEST);
+
+ glClearColor(
+ RState.ClearColor[0],
+ RState.ClearColor[1],
+ RState.ClearColor[2],
+ RState.ClearColor[3] );
+
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ for (int eyeNum = 0; eyeNum < 2; eyeNum++)
+ {
+ ShaderFill distortionShaderFill(DistortionShader);
+ distortionShaderFill.SetTexture(0, eyeNum == 0 ? leftEyeTexture : rightEyeTexture);
+
+ 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);
+
+ if (DistortionCaps & ovrDistortionCap_TimeWarp)
+ {
+ ovrMatrix4f timeWarpMatrices[2];
+ ovrHmd_GetEyeTimewarpMatrices(HMD, (ovrEyeType)eyeNum,
+ RState.EyeRenderPoses[eyeNum], timeWarpMatrices);
+
+ // Feed identity like matrices in until we get proper timewarp calculation going on
+ DistortionShader->SetUniform4x4f("EyeRotationStart", Matrix4f(timeWarpMatrices[0]).Transposed());
+ DistortionShader->SetUniform4x4f("EyeRotationEnd", Matrix4f(timeWarpMatrices[1]).Transposed());
+
+ renderPrimitives(&distortionShaderFill, DistortionMeshVBs[eyeNum], DistortionMeshIBs[eyeNum],
+ 0, (int)DistortionMeshIBs[eyeNum]->GetSize()/2, Prim_Triangles, &DistortionMeshVAOs[eyeNum], true);
+ }
+ else
+ {
+ renderPrimitives(&distortionShaderFill, DistortionMeshVBs[eyeNum], DistortionMeshIBs[eyeNum],
+ 0, (int)DistortionMeshIBs[eyeNum]->GetSize()/2, Prim_Triangles, &DistortionMeshVAOs[eyeNum], true);
+ }
+ }
+}
+
+void DistortionRenderer::createDrawQuad()
+{
+ const int numQuadVerts = 4;
+ LatencyTesterQuadVB = *new Buffer(&RParams);
+ if(!LatencyTesterQuadVB)
+ {
+ return;
+ }
+
+ LatencyTesterQuadVB->Data(Buffer_Vertex, NULL, numQuadVerts * sizeof(LatencyVertex));
+ LatencyVertex* vertices = (LatencyVertex*)LatencyTesterQuadVB->Map(0, numQuadVerts * sizeof(LatencyVertex), Map_Discard);
+ if(!vertices)
+ {
+ OVR_ASSERT(false); // failed to lock vertex buffer
+ return;
+ }
+
+ const float left = -1.0f;
+ const float top = -1.0f;
+ const float right = 1.0f;
+ const float bottom = 1.0f;
+
+ vertices[0] = LatencyVertex(Vector3f(left, top, 0.0f));
+ vertices[1] = LatencyVertex(Vector3f(left, bottom, 0.0f));
+ vertices[2] = LatencyVertex(Vector3f(right, top, 0.0f));
+ vertices[3] = LatencyVertex(Vector3f(right, bottom, 0.0f));
+
+ LatencyTesterQuadVB->Unmap(vertices);
+}
+
+void DistortionRenderer::renderLatencyQuad(unsigned char* latencyTesterDrawColor)
+{
+ const int numQuadVerts = 4;
+
+ if(!LatencyTesterQuadVB)
+ {
+ createDrawQuad();
+ }
+
+ ShaderFill quadFill(SimpleQuadShader);
+ //quadFill.SetInputLayout(SimpleQuadVertexIL);
+
+ setViewport(Recti(0,0, RParams.RTSize.w, RParams.RTSize.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);
+
+ for(int eyeNum = 0; eyeNum < 2; eyeNum++)
+ {
+ SimpleQuadShader->SetUniform2f("PositionOffset", eyeNum == 0 ? -0.4f : 0.4f, 0.0f);
+ renderPrimitives(&quadFill, LatencyTesterQuadVB, NULL, 0, numQuadVerts, Prim_TriangleStrip, &LatencyVAO, false);
+ }
+}
+
+void DistortionRenderer::renderLatencyPixel(unsigned char* latencyTesterPixelColor)
+{
+ const int numQuadVerts = 4;
+
+ if(!LatencyTesterQuadVB)
+ {
+ createDrawQuad();
+ }
+
+ ShaderFill quadFill(SimpleQuadShader);
+
+ setViewport(Recti(0,0, RParams.RTSize.w, RParams.RTSize.h));
+
+ SimpleQuadShader->SetUniform4f("Color", (float)latencyTesterPixelColor[0] / 255.99f,
+ (float)latencyTesterPixelColor[0] / 255.99f,
+ (float)latencyTesterPixelColor[0] / 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);
+ renderPrimitives(&quadFill, LatencyTesterQuadVB, NULL, 0, numQuadVerts, Prim_TriangleStrip, &LatencyVAO, false);
+}
+
+void DistortionRenderer::renderPrimitives(
+ const ShaderFill* fill,
+ Buffer* vertices, Buffer* indices,
+ int offset, int count,
+ PrimitiveType rprim, GLuint* vao, bool isDistortionMesh)
+{
+ GraphicsState* glState = (GraphicsState*)GfxState.GetPtr();
+
+ GLenum prim;
+ switch (rprim)
+ {
+ case Prim_Triangles:
+ prim = GL_TRIANGLES;
+ break;
+ case Prim_Lines:
+ prim = GL_LINES;
+ break;
+ case Prim_TriangleStrip:
+ prim = GL_TRIANGLE_STRIP;
+ break;
+ default:
+ OVR_ASSERT(false);
+ return;
+ }
+
+ fill->Set();
+
+ GLuint prog = fill->GetShaders()->Prog;
+
+ if (vao != NULL)
+ {
+ if (*vao != 0)
+ {
+ glBindVertexArray(*vao);
+
+ if (isDistortionMesh)
+ glDrawElements(prim, count, GL_UNSIGNED_SHORT, NULL);
+ else
+ glDrawArrays(prim, 0, count);
+ }
+ else
+ {
+ if (glState->SupportsVao)
+ {
+ glGenVertexArrays(1, vao);
+ glBindVertexArray(*vao);
+ }
+
+ int attributeCount = (isDistortionMesh) ? 5 : 1;
+ int* locs = new int[attributeCount];
+
+ glBindBuffer(GL_ARRAY_BUFFER, ((Buffer*)vertices)->GLBuffer);
+
+ if (isDistortionMesh)
+ {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ((Buffer*)indices)->GLBuffer);
+
+ locs[0] = glGetAttribLocation(prog, "Position");
+ locs[1] = glGetAttribLocation(prog, "Color");
+ locs[2] = glGetAttribLocation(prog, "TexCoord0");
+ 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[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));
+ }
+ else
+ {
+ locs[0] = glGetAttribLocation(prog, "Position");
+
+ glVertexAttribPointer(locs[0], 3, GL_FLOAT, false, sizeof(LatencyVertex), reinterpret_cast<char*>(offset)+offsetof(LatencyVertex, Pos));
+ }
+
+ for (int i = 0; i < attributeCount; ++i)
+ glEnableVertexAttribArray(locs[i]);
+
+ if (isDistortionMesh)
+ glDrawElements(prim, count, GL_UNSIGNED_SHORT, NULL);
+ else
+ glDrawArrays(prim, 0, count);
+
+
+ if (!glState->SupportsVao)
+ {
+ for (int i = 0; i < attributeCount; ++i)
+ glDisableVertexAttribArray(locs[i]);
+ }
+
+ delete[] locs;
+ }
+ }
+}
+
+void DistortionRenderer::setViewport(const Recti& vp)
+{
+ glViewport(vp.x, vp.y, vp.w, vp.h);
+}
+
+
+void DistortionRenderer::initShaders()
+{
+ GraphicsState* glState = (GraphicsState*)GfxState.GetPtr();
+
+ const char* shaderPrefix =
+ (glState->GlMajorVersion < 3 || (glState->GlMajorVersion == 3 && glState->GlMinorVersion < 2)) ?
+ glsl2Prefix : glsl3Prefix;
+
+ {
+ ShaderInfo vsInfo = DistortionVertexShaderLookup[DistortionVertexShaderBitMask & DistortionCaps];
+
+ size_t vsSize = strlen(shaderPrefix)+vsInfo.ShaderSize;
+ char* vsSource = new char[vsSize];
+ OVR_strcpy(vsSource, vsSize, shaderPrefix);
+ OVR_strcat(vsSource, vsSize, vsInfo.ShaderData);
+
+ Ptr<GL::VertexShader> vs = *new GL::VertexShader(
+ &RParams,
+ (void*)vsSource, vsSize,
+ vsInfo.ReflectionData, vsInfo.ReflectionSize);
+
+ DistortionShader = *new ShaderSet;
+ DistortionShader->SetShader(vs);
+
+ delete[](vsSource);
+
+ ShaderInfo psInfo = DistortionPixelShaderLookup[DistortionPixelShaderBitMask & DistortionCaps];
+
+ size_t psSize = strlen(shaderPrefix)+psInfo.ShaderSize;
+ char* psSource = new char[psSize];
+ OVR_strcpy(psSource, psSize, shaderPrefix);
+ OVR_strcat(psSource, psSize, psInfo.ShaderData);
+
+ Ptr<GL::FragmentShader> ps = *new GL::FragmentShader(
+ &RParams,
+ (void*)psSource, psSize,
+ psInfo.ReflectionData, psInfo.ReflectionSize);
+
+ DistortionShader->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]));
+
+ SimpleQuadShader = *new ShaderSet;
+ SimpleQuadShader->SetShader(vs);
+
+ delete[](vsSource);
+
+ size_t psSize = strlen(shaderPrefix)+sizeof(SimpleQuad_fs);
+ char* psSource = new char[psSize];
+ OVR_strcpy(psSource, psSize, shaderPrefix);
+ OVR_strcat(psSource, psSize, SimpleQuad_fs);
+
+ Ptr<GL::FragmentShader> ps = *new GL::FragmentShader(
+ &RParams,
+ (void*)psSource, psSize,
+ SimpleQuad_fs_refl, sizeof(SimpleQuad_fs_refl) / sizeof(SimpleQuad_fs_refl[0]));
+
+ SimpleQuadShader->SetShader(ps);
+
+ delete[](psSource);
+ }
+}
+
+
+void DistortionRenderer::destroy()
+{
+ GraphicsState* glState = (GraphicsState*)GfxState.GetPtr();
+
+ for(int eyeNum = 0; eyeNum < 2; eyeNum++)
+ {
+ if (glState->SupportsVao)
+ glDeleteVertexArrays(1, &DistortionMeshVAOs[eyeNum]);
+
+ DistortionMeshVAOs[eyeNum] = 0;
+
+ DistortionMeshVBs[eyeNum].Clear();
+ DistortionMeshIBs[eyeNum].Clear();
+ }
+
+ if (DistortionShader)
+ {
+ DistortionShader->UnsetShader(Shader_Vertex);
+ DistortionShader->UnsetShader(Shader_Pixel);
+ DistortionShader.Clear();
+ }
+
+ LatencyTesterQuadVB.Clear();
+ LatencyVAO = 0;
+}
+
+}}} // OVR::CAPI::GL