aboutsummaryrefslogtreecommitdiffstats
path: root/LibOVR/Src/CAPI/GL
diff options
context:
space:
mode:
Diffstat (limited to 'LibOVR/Src/CAPI/GL')
-rw-r--r--LibOVR/Src/CAPI/GL/CAPI_GL_DistortionRenderer.cpp1006
-rw-r--r--LibOVR/Src/CAPI/GL/CAPI_GL_DistortionRenderer.h125
-rw-r--r--LibOVR/Src/CAPI/GL/CAPI_GL_Util.cpp516
-rw-r--r--LibOVR/Src/CAPI/GL/CAPI_GL_Util.h522
4 files changed, 2169 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..a953d73
--- /dev/null
+++ b/LibOVR/Src/CAPI/GL/CAPI_GL_DistortionRenderer.cpp
@@ -0,0 +1,1006 @@
+/************************************************************************************
+
+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 "../../OVR_CAPI_GL.h"
+
+namespace OVR { namespace CAPI { namespace GL {
+
+
+static const char SimpleQuad_vs[] =
+ "uniform vec2 PositionOffset;\n"
+ "uniform vec2 Scale;\n"
+
+ "attribute vec3 Position;\n"
+
+ "void main()\n"
+ "{\n"
+ " gl_Position = vec4(Position.xy * Scale + PositionOffset, 0.5, 1.0);\n"
+ "}\n";
+
+const OVR::CAPI::GL::ShaderBase::Uniform SimpleQuad_vs_refl[] =
+{
+ { "PositionOffset", OVR::CAPI::GL::ShaderBase::VARTYPE_FLOAT, 0, 8 },
+ { "Scale", OVR::CAPI::GL::ShaderBase::VARTYPE_FLOAT, 8, 8 },
+};
+
+static const char SimpleQuad_fs[] =
+ "uniform vec4 Color;\n"
+
+ "void main()\n"
+ "{\n"
+ " gl_FragColor = Color;\n"
+ "}\n";
+
+const OVR::CAPI::GL::ShaderBase::Uniform SimpleQuad_fs_refl[] =
+{
+ { "Color", OVR::CAPI::GL::ShaderBase::VARTYPE_FLOAT, 0, 16 },
+};
+
+
+static const char Distortion_vs[] =
+ "uniform vec2 EyeToSourceUVScale;\n"
+ "uniform vec2 EyeToSourceUVOffset;\n"
+
+ "attribute vec2 Position;\n"
+ "attribute vec4 Color;\n"
+ "attribute vec2 TexCoord0;\n"
+
+ "varying vec4 oColor;\n"
+ "varying vec2 oTexCoord0;\n"
+
+ "void main()\n"
+ "{\n"
+ " gl_Position.x = Position.x;\n"
+ " gl_Position.y = Position.y;\n"
+ " gl_Position.z = 0.5;\n"
+ " gl_Position.w = 1.0;\n"
+ // Vertex inputs are in TanEyeAngle space for the R,G,B channels (i.e. after chromatic aberration and distortion).
+ // Scale them into the correct [0-1],[0-1] UV lookup space (depending on eye)
+ " oTexCoord0 = TexCoord0 * EyeToSourceUVScale + EyeToSourceUVOffset;\n"
+ " oTexCoord0.y = 1-oTexCoord0.y;\n"
+ " oColor = Color;\n" // Used for vignette fade.
+ "}\n";
+
+const OVR::CAPI::GL::ShaderBase::Uniform Distortion_vs_refl[] =
+{
+ { "EyeToSourceUVScale", OVR::CAPI::GL::ShaderBase::VARTYPE_FLOAT, 0, 8 },
+ { "EyeToSourceUVOffset", OVR::CAPI::GL::ShaderBase::VARTYPE_FLOAT, 8, 8 },
+};
+
+static const char Distortion_fs[] =
+ "uniform sampler2D Texture0;\n"
+
+ "varying vec4 oColor;\n"
+ "varying vec2 oTexCoord0;\n"
+
+ "void main()\n"
+ "{\n"
+ " gl_FragColor = texture2D(Texture0, oTexCoord0);\n"
+ " gl_FragColor.a = 1.0;\n"
+ "}\n";
+
+
+static const char DistortionTimewarp_vs[] =
+ "uniform vec2 EyeToSourceUVScale;\n"
+ "uniform vec2 EyeToSourceUVOffset;\n"
+ "uniform mat4 EyeRotationStart;\n"
+ "uniform mat4 EyeRotationEnd;\n"
+
+ "attribute vec2 Position;\n"
+ "attribute vec4 Color;\n"
+ "attribute vec2 TexCoord0;\n"
+
+ "varying vec4 oColor;\n"
+ "varying vec2 oTexCoord0;\n"
+
+ "void main()\n"
+ "{\n"
+ " gl_Position.x = Position.x;\n"
+ " gl_Position.y = Position.y;\n"
+ " gl_Position.z = 0.0;\n"
+ " gl_Position.w = 1.0;\n"
+
+ // Vertex inputs are in TanEyeAngle space for the R,G,B channels (i.e. after chromatic aberration and distortion).
+ // These are now "real world" vectors in direction (x,y,1) relative to the eye of the HMD.
+ " vec3 TanEyeAngle = vec3 ( TexCoord0.x, TexCoord0.y, 1.0 );\n"
+
+ // Accurate time warp lerp vs. faster
+#if 1
+ // Apply the two 3x3 timewarp rotations to these vectors.
+ " vec3 TransformedStart = (EyeRotationStart * vec4(TanEyeAngle, 0)).xyz;\n"
+ " vec3 TransformedEnd = (EyeRotationEnd * vec4(TanEyeAngle, 0)).xyz;\n"
+ // And blend between them.
+ " vec3 Transformed = mix ( TransformedStart, TransformedEnd, Color.a );\n"
+#else
+ " mat3 EyeRotation = mix ( EyeRotationStart, EyeRotationEnd, Color.a );\n"
+ " vec3 Transformed = EyeRotation * TanEyeAngle;\n"
+#endif
+
+ // Project them back onto the Z=1 plane of the rendered images.
+ " float RecipZ = 1.0 / Transformed.z;\n"
+ " vec2 Flattened = vec2 ( Transformed.x * RecipZ, Transformed.y * RecipZ );\n"
+
+ // These are now still in TanEyeAngle space.
+ // Scale them into the correct [0-1],[0-1] UV lookup space (depending on eye)
+ " vec2 SrcCoord = Flattened * EyeToSourceUVScale + EyeToSourceUVOffset;\n"
+ " oTexCoord0 = SrcCoord;\n"
+ " oTexCoord0.y = 1-oTexCoord0.y;\n"
+ " oColor = Color.r;\n" // Used for vignette fade.
+ "}\n";
+
+const OVR::CAPI::GL::ShaderBase::Uniform DistortionTimewarp_vs_refl[] =
+{
+ { "EyeToSourceUVScale", OVR::CAPI::GL::ShaderBase::VARTYPE_FLOAT, 0, 8 },
+ { "EyeToSourceUVOffset", OVR::CAPI::GL::ShaderBase::VARTYPE_FLOAT, 8, 8 },
+};
+
+
+static const char DistortionPositionalTimewarp_vs[] =
+ "#version 150\n"
+
+ "uniform sampler2D Texture0;\n"
+ "uniform vec2 EyeToSourceUVScale;\n"
+ "uniform vec2 EyeToSourceUVOffset;\n"
+ "uniform vec2 DepthProjector;\n"
+ "uniform vec2 DepthDimSize;\n"
+ "uniform mat4 EyeRotationStart;\n"
+ "uniform mat4 EyeRotationEnd;\n"
+
+ "in vec2 Position;\n"
+ "in vec4 Color;\n"
+ "in vec2 TexCoord0;\n"
+ "in vec2 TexCoord1;\n"
+ "in vec2 TexCoord2;\n"
+
+ "out vec4 oColor;\n"
+ "out vec2 oTexCoord0;\n"
+
+ "vec4 PositionFromDepth(vec2 inTexCoord)\n"
+ "{\n"
+ " vec2 eyeToSourceTexCoord = inTexCoord * EyeToSourceUVScale + EyeToSourceUVOffset;\n"
+ " eyeToSourceTexCoord.y = 1 - eyeToSourceTexCoord.y;\n"
+ " float depth = texelFetch(Texture0, ivec2(eyeToSourceTexCoord * DepthDimSize), 0).x;\n"
+ " float linearDepth = DepthProjector.y / (depth - DepthProjector.x);\n"
+ " vec4 retVal = vec4(inTexCoord, 1, 1);\n"
+ " retVal.xyz *= linearDepth;\n"
+ " return retVal;\n"
+ "}\n"
+
+ "vec2 TimewarpTexCoordToWarpedPos(vec2 inTexCoord, float a)\n"
+ "{\n"
+ // Vertex inputs are in TanEyeAngle space for the R,G,B channels (i.e. after chromatic aberration and distortion).
+ // These are now "real world" vectors in direction (x,y,1) relative to the eye of the HMD.
+ // Apply the 4x4 timewarp rotation to these vectors.
+ " vec4 inputPos = PositionFromDepth(inTexCoord);\n"
+ " vec3 transformed = mix ( EyeRotationStart * inputPos, EyeRotationEnd * inputPos, a ).xyz;\n"
+ // Project them back onto the Z=1 plane of the rendered images.
+ " vec2 flattened = transformed.xy / transformed.z;\n"
+ // Scale them into ([0,0.5],[0,1]) or ([0.5,0],[0,1]) UV lookup space (depending on eye)
+ " vec2 noDepthUV = flattened * EyeToSourceUVScale + EyeToSourceUVOffset;\n"
+ //" float depth = texture2DLod(Texture0, noDepthUV, 0).r;\n"
+ " return noDepthUV.xy;\n"
+ "}\n"
+
+ "void main()\n"
+ "{\n"
+ " gl_Position.x = Position.x;\n"
+ " gl_Position.y = Position.y;\n"
+ " gl_Position.z = 0.0;\n"
+ " gl_Position.w = 1.0;\n"
+
+ // warped positions are a bit more involved, hence a separate function
+ " oTexCoord0 = TimewarpTexCoordToWarpedPos(TexCoord0, Color.a);\n"
+ " oTexCoord0.y = 1-oTexCoord0.y;\n"
+
+ " oColor = vec4(Color.r); // Used for vignette fade.\n"
+ "}\n";
+
+const OVR::CAPI::GL::ShaderBase::Uniform DistortionPositionalTimewarp_vs_refl[] =
+{
+ { "EyeToSourceUVScale", OVR::CAPI::GL::ShaderBase::VARTYPE_FLOAT, 0, 8 },
+ { "EyeToSourceUVOffset", OVR::CAPI::GL::ShaderBase::VARTYPE_FLOAT, 8, 8 },
+};
+
+
+static const char DistortionChroma_vs[] =
+ "uniform vec2 EyeToSourceUVScale;\n"
+ "uniform vec2 EyeToSourceUVOffset;\n"
+
+ "attribute vec2 Position;\n"
+ "attribute vec4 Color;\n"
+ "attribute vec2 TexCoord0;\n"
+ "attribute vec2 TexCoord1;\n"
+ "attribute vec2 TexCoord2;\n"
+
+ "varying vec4 oColor;\n"
+ "varying vec2 oTexCoord0;\n"
+ "varying vec2 oTexCoord1;\n"
+ "varying vec2 oTexCoord2;\n"
+
+ "void main()\n"
+ "{\n"
+ " gl_Position.x = Position.x;\n"
+ " gl_Position.y = Position.y;\n"
+ " gl_Position.z = 0.5;\n"
+ " gl_Position.w = 1.0;\n"
+
+ // Vertex inputs are in TanEyeAngle space for the R,G,B channels (i.e. after chromatic aberration and distortion).
+ // Scale them into the correct [0-1],[0-1] UV lookup space (depending on eye)
+ " oTexCoord0 = TexCoord0 * EyeToSourceUVScale + EyeToSourceUVOffset;\n"
+ " oTexCoord0.y = 1-oTexCoord0.y;\n"
+ " oTexCoord1 = TexCoord1 * EyeToSourceUVScale + EyeToSourceUVOffset;\n"
+ " oTexCoord1.y = 1-oTexCoord1.y;\n"
+ " oTexCoord2 = TexCoord2 * EyeToSourceUVScale + EyeToSourceUVOffset;\n"
+ " oTexCoord2.y = 1-oTexCoord2.y;\n"
+
+ " oColor = Color;\n" // Used for vignette fade.
+ "}\n";
+
+const OVR::CAPI::GL::ShaderBase::Uniform DistortionChroma_vs_refl[] =
+{
+ { "EyeToSourceUVScale", OVR::CAPI::GL::ShaderBase::VARTYPE_FLOAT, 0, 8 },
+ { "EyeToSourceUVOffset", OVR::CAPI::GL::ShaderBase::VARTYPE_FLOAT, 8, 8 },
+};
+
+static const char DistortionChroma_fs[] =
+ "uniform sampler2D Texture0;\n"
+
+ "varying vec4 oColor;\n"
+ "varying vec2 oTexCoord0;\n"
+ "varying vec2 oTexCoord1;\n"
+ "varying vec2 oTexCoord2;\n"
+
+ "void main()\n"
+ "{\n"
+ " float ResultR = texture2D(Texture0, oTexCoord0).r;\n"
+ " float ResultG = texture2D(Texture0, oTexCoord1).g;\n"
+ " float ResultB = texture2D(Texture0, oTexCoord2).b;\n"
+
+ " gl_FragColor = vec4(ResultR * oColor.r, ResultG * oColor.g, ResultB * oColor.b, 1.0);\n"
+ "}\n";
+
+
+static const char DistortionTimewarpChroma_vs[] =
+ "uniform vec2 EyeToSourceUVScale;\n"
+ "uniform vec2 EyeToSourceUVOffset;\n"
+ "uniform mat4 EyeRotationStart;\n"
+ "uniform mat4 EyeRotationEnd;\n"
+
+ "attribute vec2 Position;\n"
+ "attribute vec4 Color;\n"
+ "attribute vec2 TexCoord0;\n"
+ "attribute vec2 TexCoord1;\n"
+ "attribute vec2 TexCoord2;\n"
+
+ "varying vec4 oColor;\n"
+ "varying vec2 oTexCoord0;\n"
+ "varying vec2 oTexCoord1;\n"
+ "varying vec2 oTexCoord2;\n"
+
+ "void main()\n"
+ "{\n"
+ " gl_Position.x = Position.x;\n"
+ " gl_Position.y = Position.y;\n"
+ " gl_Position.z = 0.0;\n"
+ " gl_Position.w = 1.0;\n"
+
+ // Vertex inputs are in TanEyeAngle space for the R,G,B channels (i.e. after chromatic aberration and distortion).
+ // These are now "real world" vectors in direction (x,y,1) relative to the eye of the HMD.
+ " vec3 TanEyeAngleR = vec3 ( TexCoord0.x, TexCoord0.y, 1.0 );\n"
+ " vec3 TanEyeAngleG = vec3 ( TexCoord1.x, TexCoord1.y, 1.0 );\n"
+ " vec3 TanEyeAngleB = vec3 ( TexCoord2.x, TexCoord2.y, 1.0 );\n"
+
+ // Accurate time warp lerp vs. faster
+#if 1
+ // Apply the two 3x3 timewarp rotations to these vectors.
+ " vec3 TransformedRStart = (EyeRotationStart * vec4(TanEyeAngleR, 0)).xyz;\n"
+ " vec3 TransformedGStart = (EyeRotationStart * vec4(TanEyeAngleG, 0)).xyz;\n"
+ " vec3 TransformedBStart = (EyeRotationStart * vec4(TanEyeAngleB, 0)).xyz;\n"
+ " vec3 TransformedREnd = (EyeRotationEnd * vec4(TanEyeAngleR, 0)).xyz;\n"
+ " vec3 TransformedGEnd = (EyeRotationEnd * vec4(TanEyeAngleG, 0)).xyz;\n"
+ " vec3 TransformedBEnd = (EyeRotationEnd * vec4(TanEyeAngleB, 0)).xyz;\n"
+
+ // And blend between them.
+ " vec3 TransformedR = mix ( TransformedRStart, TransformedREnd, Color.a );\n"
+ " vec3 TransformedG = mix ( TransformedGStart, TransformedGEnd, Color.a );\n"
+ " vec3 TransformedB = mix ( TransformedBStart, TransformedBEnd, Color.a );\n"
+#else
+ " mat3 EyeRotation = mix ( EyeRotationStart, EyeRotationEnd, Color.a );\n"
+ " vec3 TransformedR = EyeRotation * TanEyeAngleR;\n"
+ " vec3 TransformedG = EyeRotation * TanEyeAngleG;\n"
+ " vec3 TransformedB = EyeRotation * TanEyeAngleB;\n"
+#endif
+
+ // Project them back onto the Z=1 plane of the rendered images.
+ " float RecipZR = 1.0 / TransformedR.z;\n"
+ " float RecipZG = 1.0 / TransformedG.z;\n"
+ " float RecipZB = 1.0 / TransformedB.z;\n"
+ " vec2 FlattenedR = vec2 ( TransformedR.x * RecipZR, TransformedR.y * RecipZR );\n"
+ " vec2 FlattenedG = vec2 ( TransformedG.x * RecipZG, TransformedG.y * RecipZG );\n"
+ " vec2 FlattenedB = vec2 ( TransformedB.x * RecipZB, TransformedB.y * RecipZB );\n"
+
+ // These are now still in TanEyeAngle space.
+ // Scale them into the correct [0-1],[0-1] UV lookup space (depending on eye)
+ " vec2 SrcCoordR = FlattenedR * EyeToSourceUVScale + EyeToSourceUVOffset;\n"
+ " vec2 SrcCoordG = FlattenedG * EyeToSourceUVScale + EyeToSourceUVOffset;\n"
+ " vec2 SrcCoordB = FlattenedB * EyeToSourceUVScale + EyeToSourceUVOffset;\n"
+
+ " oTexCoord0 = SrcCoordR;\n"
+ " oTexCoord0.y = 1-oTexCoord0.y;\n"
+ " oTexCoord1 = SrcCoordG;\n"
+ " oTexCoord1.y = 1-oTexCoord1.y;\n"
+ " oTexCoord2 = SrcCoordB;\n"
+ " oTexCoord2.y = 1-oTexCoord2.y;\n"
+
+ " oColor = Color.r;\n" // Used for vignette fade.
+ "}\n";
+
+const OVR::CAPI::GL::ShaderBase::Uniform DistortionTimewarpChroma_vs_refl[] =
+{
+ { "EyeToSourceUVScale", OVR::CAPI::GL::ShaderBase::VARTYPE_FLOAT, 0, 8 },
+ { "EyeToSourceUVOffset", OVR::CAPI::GL::ShaderBase::VARTYPE_FLOAT, 8, 8 },
+ { "EyeRotationStart", OVR::CAPI::GL::ShaderBase::VARTYPE_FLOAT, 16, 64 },
+ { "EyeRotationEnd", OVR::CAPI::GL::ShaderBase::VARTYPE_FLOAT, 80, 64 },
+};
+
+
+static const char DistortionPositionalTimewarpChroma_vs[] =
+ "#version 150\n"
+ "uniform sampler2D Texture0;\n"
+ "uniform sampler2D Texture1;\n"
+ "uniform vec2 EyeToSourceUVScale;\n"
+ "uniform vec2 EyeToSourceUVOffset;\n"
+ "uniform vec2 DepthProjector;\n"
+ "uniform vec2 DepthDimSize;\n"
+ "uniform mat4 EyeRotationStart;\n"
+ "uniform mat4 EyeRotationEnd;\n"
+
+ "in vec2 Position;\n"
+ "in vec4 Color;\n"
+ "in vec2 TexCoord0;\n"
+ "in vec2 TexCoord1;\n"
+ "in vec2 TexCoord2;\n"
+
+ "out vec4 oColor;\n"
+ "out vec2 oTexCoord0;\n"
+ "out vec2 oTexCoord1;\n"
+ "out vec2 oTexCoord2;\n"
+
+ "vec4 PositionFromDepth(vec2 inTexCoord)\n"
+ "{\n"
+ " vec2 eyeToSourceTexCoord = inTexCoord * EyeToSourceUVScale + EyeToSourceUVOffset;\n"
+ " eyeToSourceTexCoord.y = 1 - eyeToSourceTexCoord.y;\n"
+ " float depth = texelFetch(Texture1, ivec2(eyeToSourceTexCoord * DepthDimSize), 0).x;\n"
+ " float linearDepth = DepthProjector.y / (depth - DepthProjector.x);\n"
+ " vec4 retVal = vec4(inTexCoord, 1, 1);\n"
+ " retVal.xyz *= linearDepth;\n"
+ " return retVal;\n"
+ "}\n"
+
+ "vec2 TimewarpTexCoordToWarpedPos(vec2 inTexCoord, float a)\n"
+ "{\n"
+ // Vertex inputs are in TanEyeAngle space for the R,G,B channels (i.e. after chromatic aberration and distortion).
+ // These are now "real world" vectors in direction (x,y,1) relative to the eye of the HMD.
+ // Apply the 4x4 timewarp rotation to these vectors.
+ " vec4 inputPos = PositionFromDepth(inTexCoord);\n"
+ " vec3 transformed = mix ( EyeRotationStart * inputPos, EyeRotationEnd * inputPos, a ).xyz;\n"
+ // Project them back onto the Z=1 plane of the rendered images.
+ " vec2 flattened = transformed.xy / transformed.z;\n"
+ // Scale them into ([0,0.5],[0,1]) or ([0.5,0],[0,1]) UV lookup space (depending on eye)
+ " vec2 noDepthUV = flattened * EyeToSourceUVScale + EyeToSourceUVOffset;\n"
+ //" float depth = texture2DLod(Texture1, noDepthUV, 0).r;\n"
+ " return noDepthUV.xy;\n"
+ "}\n"
+
+ "void main()\n"
+ "{\n"
+ " gl_Position.x = Position.x;\n"
+ " gl_Position.y = Position.y;\n"
+ " gl_Position.z = 0.0;\n"
+ " gl_Position.w = 1.0;\n"
+
+ // warped positions are a bit more involved, hence a separate function
+ " oTexCoord0 = TimewarpTexCoordToWarpedPos(TexCoord0, Color.a);\n"
+ " oTexCoord0.y = 1-oTexCoord0.y;\n"
+ " oTexCoord1 = TimewarpTexCoordToWarpedPos(TexCoord1, Color.a);\n"
+ " oTexCoord1.y = 1-oTexCoord1.y;\n"
+ " oTexCoord2 = TimewarpTexCoordToWarpedPos(TexCoord2, Color.a);\n"
+ " oTexCoord2.y = 1-oTexCoord2.y;\n"
+
+ " oColor = vec4(Color.r); // Used for vignette fade.\n"
+ "}\n";
+
+const OVR::CAPI::GL::ShaderBase::Uniform DistortionPositionalTimewarpChroma_vs_refl[] =
+{
+ { "EyeToSourceUVScale", OVR::CAPI::GL::ShaderBase::VARTYPE_FLOAT, 0, 8 },
+ { "EyeToSourceUVOffset", OVR::CAPI::GL::ShaderBase::VARTYPE_FLOAT, 8, 8 },
+};
+
+
+// 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)
+ //SI_REFL__(DistortionPositionalTimewarp_vs),
+ //SI_REFL__(DistortionPositionalTimewarpChroma_vs)
+};
+
+static ShaderInfo DistortionPixelShaderLookup[DistortionPixelShaderCount] =
+{
+ SI_NOREFL(Distortion_fs),
+ SI_NOREFL(DistortionChroma_fs)
+};
+
+void DistortionShaderBitIndexCheck()
+{
+ OVR_COMPILER_ASSERT(ovrDistortion_Chromatic == 1);
+ OVR_COMPILER_ASSERT(ovrDistortion_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)
+{
+}
+
+DistortionRenderer::~DistortionRenderer()
+{
+ destroy();
+}
+
+// static
+CAPI::DistortionRenderer* DistortionRenderer::Create(ovrHmd hmd,
+ FrameTimeManager& timeManager,
+ const HMDRenderState& renderState)
+{
+ InitGLExtensions();
+
+ return new DistortionRenderer(hmd, timeManager, renderState);
+}
+
+
+bool DistortionRenderer::Initialize(const ovrRenderAPIConfig* apiConfig,
+ unsigned hmdCaps, unsigned distortionCaps)
+{
+ // TBD: Decide if hmdCaps are needed here or are a part of RenderState
+ OVR_UNUSED(hmdCaps);
+
+ const ovrGLConfig* config = (const ovrGLConfig*)apiConfig;
+
+ if (!config)
+ {
+ // Cleanup
+ pEyeTextures[0].Clear();
+ pEyeTextures[1].Clear();
+ memset(&RParams, 0, sizeof(RParams));
+ return true;
+ }
+
+ if (!config->OGL.WglContext || !config->OGL.GdiDc)
+ return false;
+
+ RParams.GdiDc = config->OGL.GdiDc;
+ RParams.Multisample = config->OGL.Header.Multisample;
+ RParams.RTSize = config->OGL.Header.RTSize;
+ RParams.WglContext = config->OGL.WglContext;
+ RParams.Window = config->OGL.Window;
+
+ 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.
+ //Which begs the question - why did we ask them what viewport they were
+ //using before, which gave them a set of UV offsets. In fact, our
+ //asking for eye mesh must be entirely independed of these viewports,
+ //presumably only to get the parameters.
+
+ ovrEyeDesc ed = RState.EyeRenderDesc[eyeId].Desc;
+ ed.TextureSize = tex->OGL.Header.TextureSize;
+ ed.RenderViewport = tex->OGL.Header.RenderViewport;
+
+ ovrHmd_GetRenderScaleAndOffset(HMD, ed, DistortionCaps, 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 & ovrDistortion_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.HMDCaps & ovrHmdCap_NoVSync) == 0);
+ BOOL success;
+ int swapInterval = (useVsync) ? 1 : 0;
+ if (wglGetSwapIntervalEXT() != swapInterval)
+ wglSwapIntervalEXT(swapInterval);
+
+ success = SwapBuffers(RParams.GdiDc);
+ OVR_ASSERT(success);
+
+ // Force GPU to flush the scene, resulting in the lowest possible latency.
+ // It's critical that this flush is *after* present.
+ WaitUntilGpuIdle();
+ }
+}
+
+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;
+}
+
+
+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].Desc,
+ RState.DistortionCaps,
+ UVScaleOffset[eyeNum], &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, pVBVerts, sizeof(DistortionVertex) * meshData.VertexCount );
+ DistortionMeshIBs[eyeNum] = *new Buffer(&RParams);
+ DistortionMeshIBs[eyeNum]->Data ( Buffer_Index, meshData.pIndexData, ( sizeof(INT16) * meshData.IndexCount ) );
+
+ OVR_FREE ( pVBVerts );
+ ovrHmd_DestroyDistortionMesh( &meshData );
+ }
+
+ initShaders();
+}
+
+void DistortionRenderer::renderDistortion(Texture* leftEyeTexture, Texture* rightEyeTexture)
+{
+ setViewport( Recti(0,0, RParams.RTSize.w, RParams.RTSize.h) );
+
+ glClearColor(
+ RState.ClearColor[0],
+ RState.ClearColor[1],
+ RState.ClearColor[2],
+ RState.ClearColor[3] );
+
+ glClearDepth(0);
+
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ for (int eyeNum = 0; eyeNum < 2; eyeNum++)
+ {
+ ShaderFill distortionShaderFill(DistortionShader);
+ distortionShaderFill.SetTexture(0, eyeNum == 0 ? leftEyeTexture : rightEyeTexture);
+
+ DistortionShader->SetUniform2f("EyeToSourceUVScale", UVScaleOffset[eyeNum][0].x, UVScaleOffset[eyeNum][0].y);
+ DistortionShader->SetUniform2f("EyeToSourceUVOffset", UVScaleOffset[eyeNum][1].x, UVScaleOffset[eyeNum][1].y);
+
+ if (DistortionCaps & ovrDistortion_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],
+ NULL, 0, (int)DistortionMeshVBs[eyeNum]->GetSize(), Prim_Triangles, true);
+ }
+ else
+ {
+ renderPrimitives(&distortionShaderFill, DistortionMeshVBs[eyeNum], DistortionMeshIBs[eyeNum],
+ NULL, 0, (int)DistortionMeshVBs[eyeNum]->GetSize(), Prim_Triangles, 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, NULL, 0, numQuadVerts, Prim_TriangleStrip, 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, NULL, 0, numQuadVerts, Prim_TriangleStrip, false);
+}
+
+void DistortionRenderer::renderPrimitives(
+ const ShaderFill* fill,
+ Buffer* vertices, Buffer* indices,
+ Matrix4f* viewMatrix, int offset, int count,
+ PrimitiveType rprim, bool useDistortionVertex)
+{
+ ShaderSet* shaders = (ShaderSet*) ((ShaderFill*)fill)->GetShaders();
+
+ 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:
+ assert(0);
+ return;
+ }
+
+ fill->Set();
+ if (shaders->ProjLoc >= 0)
+ glUniformMatrix4fv(shaders->ProjLoc, 1, 0, &StdUniforms.Proj.M[0][0]);
+ if (shaders->ViewLoc >= 0 && viewMatrix != NULL)
+ glUniformMatrix4fv(shaders->ViewLoc, 1, 0, &viewMatrix->Transposed().M[0][0]);
+
+ //if (shaders->UsesLighting && Lighting->Version != shaders->LightingVer)
+ //{
+ // shaders->LightingVer = Lighting->Version;
+ // Lighting->Set(shaders);
+ //}
+
+ glBindBuffer(GL_ARRAY_BUFFER, ((Buffer*)vertices)->GLBuffer);
+ for (int i = 0; i < 5; i++)
+ glEnableVertexAttribArray(i);
+
+ GLuint prog = fill->GetShaders()->Prog;
+
+ if (useDistortionVertex)
+ {
+ GLint posLoc = glGetAttribLocation(prog, "Position");
+ GLint colLoc = glGetAttribLocation(prog, "Color");
+ GLint tc0Loc = glGetAttribLocation(prog, "TexCoord0");
+ GLint tc1Loc = glGetAttribLocation(prog, "TexCoord1");
+ GLint tc2Loc = glGetAttribLocation(prog, "TexCoord2");
+
+ glVertexAttribPointer(posLoc, 2, GL_FLOAT, false, sizeof(DistortionVertex), (char*)offset + offsetof(DistortionVertex, Pos));
+ glVertexAttribPointer(colLoc, 4, GL_UNSIGNED_BYTE, true, sizeof(DistortionVertex), (char*)offset + offsetof(DistortionVertex, Col));
+ glVertexAttribPointer(tc0Loc, 2, GL_FLOAT, false, sizeof(DistortionVertex), (char*)offset + offsetof(DistortionVertex, TexR));
+ glVertexAttribPointer(tc1Loc, 2, GL_FLOAT, false, sizeof(DistortionVertex), (char*)offset + offsetof(DistortionVertex, TexG));
+ glVertexAttribPointer(tc2Loc, 2, GL_FLOAT, false, sizeof(DistortionVertex), (char*)offset + offsetof(DistortionVertex, TexB));
+ }
+ else
+ {
+ GLint posLoc = glGetAttribLocation(prog, "Position");
+
+ glVertexAttribPointer(posLoc, 3, GL_FLOAT, false, sizeof(LatencyVertex), (char*)offset + offsetof(LatencyVertex, Pos));
+ }
+
+ if (indices)
+ {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ((Buffer*)indices)->GLBuffer);
+ glDrawElements(prim, count, GL_UNSIGNED_SHORT, NULL);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+ else
+ {
+ glDrawArrays(prim, 0, count);
+ }
+
+ for (int i = 0; i < 5; i++)
+ glDisableVertexAttribArray(i);
+}
+
+void DistortionRenderer::setViewport(const Recti& vp)
+{
+ int wh;
+ if (CurRenderTarget)
+ wh = CurRenderTarget->Height;
+ else
+ {
+ RECT rect;
+ BOOL success = GetWindowRect(RParams.Window, &rect);
+ OVR_ASSERT(success);
+ OVR_UNUSED(success);
+ wh = rect.bottom - rect.top;
+ }
+ glViewport(vp.x, wh-vp.y-vp.h, vp.w, vp.h);
+
+ //glEnable(GL_SCISSOR_TEST);
+ //glScissor(vp.x, wh-vp.y-vp.h, vp.w, vp.h);
+}
+
+
+void DistortionRenderer::initShaders()
+{
+ {
+ ShaderInfo vsShaderByteCode = DistortionVertexShaderLookup[DistortionVertexShaderBitMask & DistortionCaps];
+ Ptr<GL::VertexShader> vtxShader = *new GL::VertexShader(
+ &RParams,
+ (void*)vsShaderByteCode.ShaderData, vsShaderByteCode.ShaderSize,
+ vsShaderByteCode.ReflectionData, vsShaderByteCode.ReflectionSize);
+
+ DistortionShader = *new ShaderSet;
+ DistortionShader->SetShader(vtxShader);
+
+ ShaderInfo psShaderByteCode = DistortionPixelShaderLookup[DistortionPixelShaderBitMask & DistortionCaps];
+
+ Ptr<GL::FragmentShader> ps = *new GL::FragmentShader(
+ &RParams,
+ (void*)psShaderByteCode.ShaderData, psShaderByteCode.ShaderSize,
+ psShaderByteCode.ReflectionData, psShaderByteCode.ReflectionSize);
+
+ DistortionShader->SetShader(ps);
+ }
+ {
+ Ptr<GL::VertexShader> vtxShader = *new GL::VertexShader(
+ &RParams,
+ (void*)SimpleQuad_vs, sizeof(SimpleQuad_vs),
+ SimpleQuad_vs_refl, sizeof(SimpleQuad_vs_refl) / sizeof(SimpleQuad_vs_refl[0]));
+
+ SimpleQuadShader = *new ShaderSet;
+ SimpleQuadShader->SetShader(vtxShader);
+
+ Ptr<GL::FragmentShader> ps = *new GL::FragmentShader(
+ &RParams,
+ (void*)SimpleQuad_fs, sizeof(SimpleQuad_fs),
+ SimpleQuad_fs_refl, sizeof(SimpleQuad_fs_refl) / sizeof(SimpleQuad_fs_refl[0]));
+
+ SimpleQuadShader->SetShader(ps);
+ }
+}
+
+
+void DistortionRenderer::destroy()
+{
+ for(int eyeNum = 0; eyeNum < 2; eyeNum++)
+ {
+ DistortionMeshVBs[eyeNum].Clear();
+ DistortionMeshIBs[eyeNum].Clear();
+ }
+
+ if (DistortionShader)
+ {
+ DistortionShader->UnsetShader(Shader_Vertex);
+ DistortionShader->UnsetShader(Shader_Pixel);
+ DistortionShader.Clear();
+ }
+
+ LatencyTesterQuadVB.Clear();
+}
+
+}}} // OVR::CAPI::GL
diff --git a/LibOVR/Src/CAPI/GL/CAPI_GL_DistortionRenderer.h b/LibOVR/Src/CAPI/GL/CAPI_GL_DistortionRenderer.h
new file mode 100644
index 0000000..8e0b72e
--- /dev/null
+++ b/LibOVR/Src/CAPI/GL/CAPI_GL_DistortionRenderer.h
@@ -0,0 +1,125 @@
+/************************************************************************************
+
+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.
+
+************************************************************************************/
+
+#ifndef OVR_CAPI_GL_DistortionRenderer_h
+#define OVR_CAPI_GL_DistortionRenderer_h
+
+#include "../CAPI_DistortionRenderer.h"
+
+#include "../../Kernel/OVR_Log.h"
+#include "CAPI_GL_Util.h"
+
+namespace OVR { namespace CAPI { namespace GL {
+
+// ***** GL::DistortionRenderer
+
+// Implementation of DistortionRenderer for GL.
+
+class DistortionRenderer : public CAPI::DistortionRenderer
+{
+public:
+ DistortionRenderer(ovrHmd hmd,
+ FrameTimeManager& timeManager,
+ const HMDRenderState& renderState);
+ ~DistortionRenderer();
+
+
+ // Creation function for the device.
+ static CAPI::DistortionRenderer* Create(ovrHmd hmd,
+ FrameTimeManager& timeManager,
+ const HMDRenderState& renderState);
+
+
+ // ***** Public DistortionRenderer interface
+
+ virtual bool Initialize(const ovrRenderAPIConfig* apiConfig,
+ unsigned hmdCaps, unsigned distortionCaps);
+
+ virtual void SubmitEye(int eyeId, ovrTexture* eyeTexture);
+
+ virtual void EndFrame(bool swapBuffers, unsigned char* latencyTesterDrawColor, unsigned char* latencyTester2DrawColor);
+
+ void WaitUntilGpuIdle();
+
+ // Similar to ovr_WaitTillTime but it also flushes GPU.
+ // Note, it exits when time expires, even if GPU is not in idle state yet.
+ double FlushGpuAndWaitTillTime(double absTime);
+
+private:
+ // TBD: Should we be using oe from RState instead?
+ unsigned DistortionCaps;
+
+ struct FOR_EACH_EYE
+ {
+#if 0
+ IDirect3DVertexBuffer9 * dxVerts;
+ IDirect3DIndexBuffer9 * dxIndices;
+#endif
+ int numVerts;
+ int numIndices;
+
+ GLuint texture;
+
+ ovrVector2f UVScaleOffset[2];
+ } eachEye[2];
+
+ // GL context and utility variables.
+ RenderParams RParams;
+
+ // Helpers
+ void initBuffersAndShaders();
+ void initShaders();
+ void initFullscreenQuad();
+ void destroy();
+
+ void setViewport(const Recti& vp);
+
+ void renderDistortion(Texture* leftEyeTexture, Texture* rightEyeTexture);
+
+ void renderPrimitives(const ShaderFill* fill, Buffer* vertices, Buffer* indices,
+ Matrix4f* viewMatrix, int offset, int count,
+ PrimitiveType rprim, bool useDistortionVertex);
+
+ void createDrawQuad();
+ void renderLatencyQuad(unsigned char* latencyTesterDrawColor);
+ void renderLatencyPixel(unsigned char* latencyTesterPixelColor);
+
+ Ptr<Texture> pEyeTextures[2];
+
+ // U,V scale and offset needed for timewarp.
+ ovrVector2f UVScaleOffset[2][2];
+
+ Ptr<Buffer> DistortionMeshVBs[2]; // one per-eye
+ Ptr<Buffer> DistortionMeshIBs[2]; // one per-eye
+
+ Ptr<ShaderSet> DistortionShader;
+
+ struct StandardUniformData
+ {
+ Matrix4f Proj;
+ Matrix4f View;
+ } StdUniforms;
+
+ Ptr<Buffer> LatencyTesterQuadVB;
+ Ptr<ShaderSet> SimpleQuadShader;
+
+ Ptr<Texture> CurRenderTarget;
+ Array<Ptr<Texture> > DepthBuffers;
+ GLuint CurrentFbo;
+};
+
+}}} // OVR::CAPI::GL
+
+#endif // OVR_CAPI_GL_DistortionRenderer_h \ No newline at end of file
diff --git a/LibOVR/Src/CAPI/GL/CAPI_GL_Util.cpp b/LibOVR/Src/CAPI/GL/CAPI_GL_Util.cpp
new file mode 100644
index 0000000..b82939a
--- /dev/null
+++ b/LibOVR/Src/CAPI/GL/CAPI_GL_Util.cpp
@@ -0,0 +1,516 @@
+/************************************************************************************
+
+Filename : Render_GL_Device.cpp
+Content : RenderDevice implementation for OpenGL
+Created : September 10, 2012
+Authors : David Borel, Andrew Reisse
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+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_Util.h"
+#include "../../Kernel/OVR_Log.h"
+
+namespace OVR { namespace CAPI { namespace GL {
+
+
+
+// GL Hooks for PC.
+#if defined(OVR_OS_WIN32)
+
+PFNWGLGETPROCADDRESS wglGetProcAddress;
+
+PFNGLCLEARPROC glClear;
+PFNGLCLEARCOLORPROC glClearColor;
+PFNGLCLEARDEPTHPROC glClearDepth;
+PFNGLVIEWPORTPROC glViewport;
+PFNGLDRAWELEMENTSPROC glDrawElements;
+PFNGLTEXPARAMETERIPROC glTexParameteri;
+PFNGLFLUSHPROC glFlush;
+PFNGLFINISHPROC glFinish;
+PFNGLDRAWARRAYSPROC glDrawArrays;
+PFNGLGENTEXTURESPROC glGenTextures;
+PFNGLDELETETEXTURESPROC glDeleteTextures;
+PFNGLBINDTEXTUREPROC glBindTexture;
+
+PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT;
+PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT;
+PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT;
+PFNGLDELETESHADERPROC glDeleteShader;
+PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT;
+PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT;
+PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT;
+PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT;
+PFNGLACTIVETEXTUREPROC glActiveTexture;
+PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray;
+PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer;
+PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray;
+PFNGLBINDBUFFERPROC glBindBuffer;
+PFNGLUNIFORMMATRIX3FVPROC glUniformMatrix3fv;
+PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv;
+PFNGLDELETEBUFFERSPROC glDeleteBuffers;
+PFNGLBUFFERDATAPROC glBufferData;
+PFNGLGENBUFFERSPROC glGenBuffers;
+PFNGLMAPBUFFERPROC glMapBuffer;
+PFNGLUNMAPBUFFERPROC glUnmapBuffer;
+PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
+PFNGLGETSHADERIVPROC glGetShaderiv;
+PFNGLCOMPILESHADERPROC glCompileShader;
+PFNGLSHADERSOURCEPROC glShaderSource;
+PFNGLCREATESHADERPROC glCreateShader;
+PFNGLCREATEPROGRAMPROC glCreateProgram;
+PFNGLATTACHSHADERPROC glAttachShader;
+PFNGLDETACHSHADERPROC glDetachShader;
+PFNGLDELETEPROGRAMPROC glDeleteProgram;
+PFNGLUNIFORM1IPROC glUniform1i;
+PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
+PFNGLGETACTIVEUNIFORMPROC glGetActiveUniform;
+PFNGLUSEPROGRAMPROC glUseProgram;
+PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
+PFNGLGETPROGRAMIVPROC glGetProgramiv;
+PFNGLLINKPROGRAMPROC glLinkProgram;
+PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation;
+PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation;
+PFNGLUNIFORM4FVPROC glUniform4fv;
+PFNGLUNIFORM3FVPROC glUniform3fv;
+PFNGLUNIFORM2FVPROC glUniform2fv;
+PFNGLUNIFORM1FVPROC glUniform1fv;
+PFNGLCOMPRESSEDTEXIMAGE2DPROC glCompressedTexImage2D;
+PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT;
+PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT;
+PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT;
+PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT;
+
+PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
+
+void InitGLExtensions()
+{
+ HINSTANCE hInst = LoadLibrary( L"Opengl32.dll" );
+ if (!hInst)
+ return;
+
+ glClear = (PFNGLCLEARPROC)GetProcAddress( hInst, "glClear" );
+ glClearColor = (PFNGLCLEARCOLORPROC)GetProcAddress( hInst, "glClearColor" );
+ glClearDepth = (PFNGLCLEARDEPTHPROC)GetProcAddress( hInst, "glClearDepth" );
+ glViewport = (PFNGLVIEWPORTPROC)GetProcAddress( hInst, "glViewport" );
+ glDrawElements = (PFNGLDRAWELEMENTSPROC)GetProcAddress( hInst, "glDrawElements" );
+ glTexParameteri = (PFNGLTEXPARAMETERIPROC)GetProcAddress( hInst, "glTexParameteri" );
+ glFlush = (PFNGLFLUSHPROC)GetProcAddress( hInst, "glFlush" );
+ glFinish = (PFNGLFINISHPROC)GetProcAddress( hInst, "glFinish" );
+ glDrawArrays = (PFNGLDRAWARRAYSPROC)GetProcAddress( hInst, "glDrawArrays" );
+ glGenTextures = (PFNGLGENTEXTURESPROC)GetProcAddress( hInst,"glGenTextures" );
+ glDeleteTextures = (PFNGLDELETETEXTURESPROC)GetProcAddress( hInst,"glDeleteTextures" );
+ glBindTexture = (PFNGLBINDTEXTUREPROC)GetProcAddress( hInst,"glBindTexture" );
+
+ wglGetProcAddress = (PFNWGLGETPROCADDRESS)GetProcAddress( hInst, "wglGetProcAddress" );
+
+ if (glGenFramebuffersEXT)
+ return;
+
+ wglGetSwapIntervalEXT = (PFNWGLGETSWAPINTERVALEXTPROC) wglGetProcAddress("wglGetSwapIntervalEXT");
+ wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC) wglGetProcAddress("wglSwapIntervalEXT");
+ glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC) wglGetProcAddress("glGenFramebuffersEXT");
+ glDeleteShader = (PFNGLDELETESHADERPROC) wglGetProcAddress("glDeleteShader");
+ glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) wglGetProcAddress("glCheckFramebufferStatusEXT");
+ glFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) wglGetProcAddress("glFramebufferRenderbufferEXT");
+ glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) wglGetProcAddress("glFramebufferTexture2DEXT");
+ glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC) wglGetProcAddress("glBindFramebufferEXT");
+ glActiveTexture = (PFNGLACTIVETEXTUREPROC) wglGetProcAddress("glActiveTexture");
+ glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC) wglGetProcAddress("glDisableVertexAttribArray");
+ glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC) wglGetProcAddress("glVertexAttribPointer");
+ glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC) wglGetProcAddress("glEnableVertexAttribArray");
+ glBindBuffer = (PFNGLBINDBUFFERPROC) wglGetProcAddress("glBindBuffer");
+ glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC) wglGetProcAddress("glUniformMatrix3fv");
+ glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC) wglGetProcAddress("glUniformMatrix4fv");
+ glDeleteBuffers = (PFNGLDELETEBUFFERSPROC) wglGetProcAddress("glDeleteBuffers");
+ glBufferData = (PFNGLBUFFERDATAPROC) wglGetProcAddress("glBufferData");
+ glGenBuffers = (PFNGLGENBUFFERSPROC) wglGetProcAddress("glGenBuffers");
+ glMapBuffer = (PFNGLMAPBUFFERPROC) wglGetProcAddress("glMapBuffer");
+ glUnmapBuffer = (PFNGLUNMAPBUFFERPROC) wglGetProcAddress("glUnmapBuffer");
+ glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) wglGetProcAddress("glGetShaderInfoLog");
+ glGetShaderiv = (PFNGLGETSHADERIVPROC) wglGetProcAddress("glGetShaderiv");
+ glCompileShader = (PFNGLCOMPILESHADERPROC) wglGetProcAddress("glCompileShader");
+ glShaderSource = (PFNGLSHADERSOURCEPROC) wglGetProcAddress("glShaderSource");
+ glCreateShader = (PFNGLCREATESHADERPROC) wglGetProcAddress("glCreateShader");
+ glCreateProgram = (PFNGLCREATEPROGRAMPROC) wglGetProcAddress("glCreateProgram");
+ glAttachShader = (PFNGLATTACHSHADERPROC) wglGetProcAddress("glAttachShader");
+ glDetachShader = (PFNGLDETACHSHADERPROC) wglGetProcAddress("glDetachShader");
+ glDeleteProgram = (PFNGLDELETEPROGRAMPROC) wglGetProcAddress("glDeleteProgram");
+ glUniform1i = (PFNGLUNIFORM1IPROC) wglGetProcAddress("glUniform1i");
+ glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) wglGetProcAddress("glGetUniformLocation");
+ glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC) wglGetProcAddress("glGetActiveUniform");
+ glUseProgram = (PFNGLUSEPROGRAMPROC) wglGetProcAddress("glUseProgram");
+ glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) wglGetProcAddress("glGetProgramInfoLog");
+ glGetProgramiv = (PFNGLGETPROGRAMIVPROC) wglGetProcAddress("glGetProgramiv");
+ glLinkProgram = (PFNGLLINKPROGRAMPROC) wglGetProcAddress("glLinkProgram");
+ glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC) wglGetProcAddress("glBindAttribLocation");
+ glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC) wglGetProcAddress("glGetAttribLocation");
+ glUniform4fv = (PFNGLUNIFORM4FVPROC) wglGetProcAddress("glUniform4fv");
+ glUniform3fv = (PFNGLUNIFORM3FVPROC) wglGetProcAddress("glUniform3fv");
+ glUniform2fv = (PFNGLUNIFORM2FVPROC) wglGetProcAddress("glUniform2fv");
+ glUniform1fv = (PFNGLUNIFORM1FVPROC) wglGetProcAddress("glUniform1fv");
+ glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC) wglGetProcAddress("glCompressedTexImage2D");
+ glRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC) wglGetProcAddress("glRenderbufferStorageEXT");
+ glBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC) wglGetProcAddress("glBindRenderbufferEXT");
+ glGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC) wglGetProcAddress("glGenRenderbuffersEXT");
+ glDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC) wglGetProcAddress("glDeleteRenderbuffersEXT");
+
+
+ glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC) wglGetProcAddress("glGenVertexArrays");
+}
+
+#endif
+
+Buffer::Buffer(RenderParams* rp) : pParams(rp), Size(0), Use(0), GLBuffer(0)
+{
+}
+
+Buffer::~Buffer()
+{
+ if (GLBuffer)
+ glDeleteBuffers(1, &GLBuffer);
+}
+
+bool Buffer::Data(int use, const void* buffer, size_t size)
+{
+ Size = size;
+
+ switch (use & Buffer_TypeMask)
+ {
+ case Buffer_Index: Use = GL_ELEMENT_ARRAY_BUFFER; break;
+ default: Use = GL_ARRAY_BUFFER; break;
+ }
+
+ if (!GLBuffer)
+ glGenBuffers(1, &GLBuffer);
+
+ int mode = GL_DYNAMIC_DRAW;
+ if (use & Buffer_ReadOnly)
+ mode = GL_STATIC_DRAW;
+
+ glBindBuffer(Use, GLBuffer);
+ glBufferData(Use, size, buffer, mode);
+ glBindBuffer(Use, 0);
+ return 1;
+}
+
+void* Buffer::Map(size_t, size_t, int)
+{
+ int mode = GL_WRITE_ONLY;
+ //if (flags & Map_Unsynchronized)
+ // mode |= GL_MAP_UNSYNCHRONIZED;
+
+ glBindBuffer(Use, GLBuffer);
+ void* v = glMapBuffer(Use, mode);
+ glBindBuffer(Use, 0);
+ return v;
+}
+
+bool Buffer::Unmap(void*)
+{
+ glBindBuffer(Use, GLBuffer);
+ int r = glUnmapBuffer(Use);
+ glBindBuffer(Use, 0);
+ return r != 0;
+}
+
+ShaderSet::ShaderSet()
+{
+ Prog = glCreateProgram();
+}
+ShaderSet::~ShaderSet()
+{
+ glDeleteProgram(Prog);
+}
+
+GLint ShaderSet::GetGLShader(Shader* s)
+{
+ switch (s->Stage)
+ {
+ case Shader_Vertex: {
+ ShaderImpl<Shader_Vertex, GL_VERTEX_SHADER>* gls = (ShaderImpl<Shader_Vertex, GL_VERTEX_SHADER>*)s;
+ return gls->GLShader;
+ } break;
+ case Shader_Fragment: {
+ ShaderImpl<Shader_Fragment, GL_FRAGMENT_SHADER>* gls = (ShaderImpl<Shader_Fragment, GL_FRAGMENT_SHADER>*)s;
+ return gls->GLShader;
+ } break;
+ }
+
+ return -1;
+}
+
+void ShaderSet::SetShader(Shader *s)
+{
+ Shaders[s->Stage] = s;
+ GLint GLShader = GetGLShader(s);
+ glAttachShader(Prog, GLShader);
+ if (Shaders[Shader_Vertex] && Shaders[Shader_Fragment])
+ Link();
+}
+
+void ShaderSet::UnsetShader(int stage)
+{
+ if (Shaders[stage] == NULL)
+ return;
+
+ GLint GLShader = GetGLShader(Shaders[stage]);
+ glDetachShader(Prog, GLShader);
+
+ Shaders[stage] = NULL;
+
+ //Link();
+}
+
+bool ShaderSet::SetUniform(const char* name, int n, const float* v)
+{
+ for (unsigned int i = 0; i < UniformInfo.GetSize(); i++)
+ if (!strcmp(UniformInfo[i].Name.ToCStr(), name))
+ {
+ OVR_ASSERT(UniformInfo[i].Location >= 0);
+ glUseProgram(Prog);
+ switch (UniformInfo[i].Type)
+ {
+ case 1: glUniform1fv(UniformInfo[i].Location, n, v); break;
+ case 2: glUniform2fv(UniformInfo[i].Location, n/2, v); break;
+ case 3: glUniform3fv(UniformInfo[i].Location, n/3, v); break;
+ case 4: glUniform4fv(UniformInfo[i].Location, n/4, v); break;
+ case 12: glUniformMatrix3fv(UniformInfo[i].Location, 1, 1, v); break;
+ case 16: glUniformMatrix4fv(UniformInfo[i].Location, 1, 1, v); break;
+ default: OVR_ASSERT(0);
+ }
+ return 1;
+ }
+
+ OVR_DEBUG_LOG(("Warning: uniform %s not present in selected shader", name));
+ return 0;
+}
+
+bool ShaderSet::Link()
+{
+ glLinkProgram(Prog);
+ GLint r;
+ glGetProgramiv(Prog, GL_LINK_STATUS, &r);
+ if (!r)
+ {
+ GLchar msg[1024];
+ glGetProgramInfoLog(Prog, sizeof(msg), 0, msg);
+ OVR_DEBUG_LOG(("Linking shaders failed: %s\n", msg));
+ if (!r)
+ return 0;
+ }
+ glUseProgram(Prog);
+
+ UniformInfo.Clear();
+ LightingVer = 0;
+ UsesLighting = 0;
+
+ GLint uniformCount = 0;
+ glGetProgramiv(Prog, GL_ACTIVE_UNIFORMS, &uniformCount);
+ OVR_ASSERT(uniformCount >= 0);
+
+ for(GLuint i = 0; i < (GLuint)uniformCount; i++)
+ {
+ GLsizei namelen;
+ GLint size = 0;
+ GLenum type;
+ GLchar name[32];
+ glGetActiveUniform(Prog, i, sizeof(name), &namelen, &size, &type, name);
+
+ if (size)
+ {
+ int l = glGetUniformLocation(Prog, name);
+ char *np = name;
+ while (*np)
+ {
+ if (*np == '[')
+ *np = 0;
+ np++;
+ }
+ Uniform u;
+ u.Name = name;
+ u.Location = l;
+ u.Size = size;
+ switch (type)
+ {
+ case GL_FLOAT: u.Type = 1; break;
+ case GL_FLOAT_VEC2: u.Type = 2; break;
+ case GL_FLOAT_VEC3: u.Type = 3; break;
+ case GL_FLOAT_VEC4: u.Type = 4; break;
+ case GL_FLOAT_MAT3: u.Type = 12; break;
+ case GL_FLOAT_MAT4: u.Type = 16; break;
+ default:
+ continue;
+ }
+ UniformInfo.PushBack(u);
+ if (!strcmp(name, "LightCount"))
+ UsesLighting = 1;
+ }
+ else
+ break;
+ }
+
+ ProjLoc = glGetUniformLocation(Prog, "Proj");
+ ViewLoc = glGetUniformLocation(Prog, "View");
+ for (int i = 0; i < 8; i++)
+ {
+ char texv[32];
+ OVR_sprintf(texv, 10, "Texture%d", i);
+ TexLoc[i] = glGetUniformLocation(Prog, texv);
+ if (TexLoc[i] < 0)
+ break;
+
+ glUniform1i(TexLoc[i], i);
+ }
+ if (UsesLighting)
+ OVR_ASSERT(ProjLoc >= 0 && ViewLoc >= 0);
+ return 1;
+}
+
+bool ShaderBase::SetUniform(const char* name, int n, const float* v)
+{
+ for(unsigned i = 0; i < UniformReflSize; i++)
+ {
+ if (!strcmp(UniformRefl[i].Name, name))
+ {
+ memcpy(UniformData + UniformRefl[i].Offset, v, n * sizeof(float));
+ return 1;
+ }
+ }
+ return 0;
+}
+
+bool ShaderBase::SetUniformBool(const char* name, int n, const bool* v)
+{
+ OVR_UNUSED(n);
+ for(unsigned i = 0; i < UniformReflSize; i++)
+ {
+ if (!strcmp(UniformRefl[i].Name, name))
+ {
+ memcpy(UniformData + UniformRefl[i].Offset, v, UniformRefl[i].Size);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void ShaderBase::InitUniforms(const Uniform* refl, size_t reflSize)
+{
+ if(!refl)
+ {
+ UniformRefl = NULL;
+ UniformReflSize = 0;
+
+ UniformsSize = 0;
+ if (UniformData)
+ {
+ OVR_FREE(UniformData);
+ UniformData = 0;
+ }
+ return; // no reflection data
+ }
+
+ UniformRefl = refl;
+ UniformReflSize = reflSize;
+
+ UniformsSize = UniformRefl[UniformReflSize-1].Offset + UniformRefl[UniformReflSize-1].Size;
+ UniformData = (unsigned char*)OVR_ALLOC(UniformsSize);
+}
+
+void ShaderBase::UpdateBuffer(Buffer* buf)
+{
+ if (UniformsSize)
+ {
+ buf->Data(Buffer_Uniform, UniformData, UniformsSize);
+ }
+}
+
+Texture::Texture(RenderParams* rp, int w, int h) : IsUserAllocated(true), pParams(rp), TexId(0), Width(w), Height(h)
+{
+ if (w && h)
+ glGenTextures(1, &TexId);
+}
+
+Texture::~Texture()
+{
+ if (TexId && !IsUserAllocated)
+ glDeleteTextures(1, &TexId);
+}
+
+void Texture::Set(int slot, ShaderStage) const
+{
+ glActiveTexture(GL_TEXTURE0 + slot);
+ glBindTexture(GL_TEXTURE_2D, TexId);
+ glActiveTexture(GL_TEXTURE0);
+}
+
+void Texture::SetSampleMode(int sm)
+{
+ glBindTexture(GL_TEXTURE_2D, TexId);
+ switch (sm & Sample_FilterMask)
+ {
+ case Sample_Linear:
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1);
+ break;
+
+ case Sample_Anisotropic:
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8);
+ break;
+
+ case Sample_Nearest:
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1);
+ break;
+ }
+
+ switch (sm & Sample_AddressMask)
+ {
+ case Sample_Repeat:
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ break;
+
+ case Sample_Clamp:
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ break;
+
+ case Sample_ClampBorder:
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+ break;
+ }
+ glBindTexture(GL_TEXTURE_2D, 0);
+}
+
+void Texture::UpdatePlaceholderTexture(GLuint texId, const Sizei& textureSize)
+{
+ if (!IsUserAllocated && TexId && texId != TexId)
+ glDeleteTextures(1, &TexId);
+
+ TexId = texId;
+ Width = textureSize.w;
+ Height = textureSize.h;
+
+ IsUserAllocated = true;
+}
+
+}}}
diff --git a/LibOVR/Src/CAPI/GL/CAPI_GL_Util.h b/LibOVR/Src/CAPI/GL/CAPI_GL_Util.h
new file mode 100644
index 0000000..5e694cc
--- /dev/null
+++ b/LibOVR/Src/CAPI/GL/CAPI_GL_Util.h
@@ -0,0 +1,522 @@
+/************************************************************************************
+
+Filename : CAPI_GL_Util.h
+Content : Utility header for OpenGL
+Created : March 27, 2014
+Authors : Andrew Reisse, David Borel
+
+Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+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.
+
+************************************************************************************/
+
+#ifndef INC_OVR_CAPI_GL_Util_h
+#define INC_OVR_CAPI_GL_Util_h
+
+#include "../../OVR_CAPI.h"
+#include "../../Kernel/OVR_Array.h"
+#include "../../Kernel/OVR_Math.h"
+#include "../../Kernel/OVR_RefCount.h"
+#include "../../Kernel/OVR_String.h"
+#include "../../Kernel/OVR_Types.h"
+
+#if defined(OVR_OS_WIN32)
+#include <Windows.h>
+#endif
+
+#if defined(OVR_OS_MAC)
+#include <OpenGL/gl.h>
+#include <OpenGL/glext.h>
+#else
+#ifndef GL_GLEXT_PROTOTYPES
+#define GL_GLEXT_PROTOTYPES
+#endif
+#include <GL/gl.h>
+#include <GL/glext.h>
+#if defined(OVR_OS_WIN32)
+#include <GL/wglext.h>
+#endif
+#endif
+
+namespace OVR { namespace CAPI { namespace GL {
+
+// GL extension Hooks for PC.
+#if defined(OVR_OS_WIN32)
+
+typedef PROC (__stdcall *PFNWGLGETPROCADDRESS) (LPCSTR);
+typedef void (__stdcall *PFNGLFLUSHPROC) ();
+typedef void (__stdcall *PFNGLFINISHPROC) ();
+typedef void (__stdcall *PFNGLDRAWARRAYSPROC) (GLenum mode, GLint first, GLsizei count);
+typedef void (__stdcall *PFNGLCLEARPROC) (GLbitfield);
+typedef void (__stdcall *PFNGLDRAWELEMENTSPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
+typedef void (__stdcall *PFNGLGENTEXTURESPROC) (GLsizei n, GLuint *textures);
+typedef void (__stdcall *PFNGLDELETETEXTURESPROC) (GLsizei n, GLuint *textures);
+typedef void (__stdcall *PFNGLBINDTEXTUREPROC) (GLenum target, GLuint texture);
+typedef void (__stdcall *PFNGLCLEARCOLORPROC) (GLfloat r, GLfloat g, GLfloat b, GLfloat a);
+typedef void (__stdcall *PFNGLCLEARDEPTHPROC) (GLclampd depth);
+typedef void (__stdcall *PFNGLTEXPARAMETERIPROC) (GLenum target, GLenum pname, GLint param);
+typedef void (__stdcall *PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
+
+extern PFNWGLGETPROCADDRESS wglGetProcAddress;
+extern PFNGLCLEARPROC glClear;
+extern PFNGLCLEARCOLORPROC glClearColor;
+extern PFNGLCLEARDEPTHPROC glClearDepth;
+extern PFNGLVIEWPORTPROC glViewport;
+extern PFNGLDRAWARRAYSPROC glDrawArrays;
+extern PFNGLDRAWELEMENTSPROC glDrawElements;
+extern PFNGLGENTEXTURESPROC glGenTextures;
+extern PFNGLDELETETEXTURESPROC glDeleteTextures;
+extern PFNGLBINDTEXTUREPROC glBindTexture;
+extern PFNGLTEXPARAMETERIPROC glTexParameteri;
+extern PFNGLFLUSHPROC glFlush;
+extern PFNGLFINISHPROC glFinish;
+
+extern PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT;
+extern PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT;
+extern PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT;
+extern PFNGLDELETESHADERPROC glDeleteShader;
+extern PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT;
+extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT;
+extern PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT;
+extern PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT;
+extern PFNGLACTIVETEXTUREPROC glActiveTexture;
+extern PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray;
+extern PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer;
+extern PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray;
+extern PFNGLBINDBUFFERPROC glBindBuffer;
+extern PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv;
+extern PFNGLDELETEBUFFERSPROC glDeleteBuffers;
+extern PFNGLBUFFERDATAPROC glBufferData;
+extern PFNGLGENBUFFERSPROC glGenBuffers;
+extern PFNGLMAPBUFFERPROC glMapBuffer;
+extern PFNGLUNMAPBUFFERPROC glUnmapBuffer;
+extern PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
+extern PFNGLGETSHADERIVPROC glGetShaderiv;
+extern PFNGLCOMPILESHADERPROC glCompileShader;
+extern PFNGLSHADERSOURCEPROC glShaderSource;
+extern PFNGLCREATESHADERPROC glCreateShader;
+extern PFNGLCREATEPROGRAMPROC glCreateProgram;
+extern PFNGLATTACHSHADERPROC glAttachShader;
+extern PFNGLDETACHSHADERPROC glDetachShader;
+extern PFNGLDELETEPROGRAMPROC glDeleteProgram;
+extern PFNGLUNIFORM1IPROC glUniform1i;
+extern PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
+extern PFNGLGETACTIVEUNIFORMPROC glGetActiveUniform;
+extern PFNGLUSEPROGRAMPROC glUseProgram;
+extern PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
+extern PFNGLGETPROGRAMIVPROC glGetProgramiv;
+extern PFNGLLINKPROGRAMPROC glLinkProgram;
+extern PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation;
+extern PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation;
+extern PFNGLUNIFORM4FVPROC glUniform4fv;
+extern PFNGLUNIFORM3FVPROC glUniform3fv;
+extern PFNGLUNIFORM2FVPROC glUniform2fv;
+extern PFNGLUNIFORM1FVPROC glUniform1fv;
+extern PFNGLCOMPRESSEDTEXIMAGE2DPROC glCompressedTexImage2D;
+extern PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT;
+extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT;
+extern PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT;
+extern PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT;
+
+// For testing
+extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
+
+extern void InitGLExtensions();
+
+#endif
+
+
+// Rendering primitive type used to render Model.
+enum PrimitiveType
+{
+ Prim_Triangles,
+ Prim_Lines,
+ Prim_TriangleStrip,
+ Prim_Unknown,
+ Prim_Count
+};
+
+// Types of shaders that can be stored together in a ShaderSet.
+enum ShaderStage
+{
+ Shader_Vertex = 0,
+ Shader_Fragment = 2,
+ Shader_Pixel = 2,
+ Shader_Count = 3,
+};
+
+enum MapFlags
+{
+ Map_Discard = 1,
+ Map_Read = 2, // do not use
+ Map_Unsynchronized = 4, // like D3D11_MAP_NO_OVERWRITE
+};
+
+
+// Buffer types used for uploading geometry & constants.
+enum BufferUsage
+{
+ Buffer_Unknown = 0,
+ Buffer_Vertex = 1,
+ Buffer_Index = 2,
+ Buffer_Uniform = 4,
+ Buffer_TypeMask = 0xff,
+ Buffer_ReadOnly = 0x100, // Buffer must be created with Data().
+};
+
+enum TextureFormat
+{
+ Texture_RGBA = 0x0100,
+ Texture_Depth = 0x8000,
+ Texture_TypeMask = 0xff00,
+ Texture_SamplesMask = 0x00ff,
+ Texture_RenderTarget = 0x10000,
+ Texture_GenMipmaps = 0x20000,
+};
+
+// Texture sampling modes.
+enum SampleMode
+{
+ Sample_Linear = 0,
+ Sample_Nearest = 1,
+ Sample_Anisotropic = 2,
+ Sample_FilterMask = 3,
+
+ Sample_Repeat = 0,
+ Sample_Clamp = 4,
+ Sample_ClampBorder = 8, // If unsupported Clamp is used instead.
+ Sample_AddressMask =12,
+
+ Sample_Count =13,
+};
+
+
+// Rendering parameters/pointers describing GL rendering setup.
+struct RenderParams
+{
+#ifdef OVR_OS_WIN32
+ HWND Window;
+ HGLRC WglContext;
+ HDC GdiDc;
+#endif
+
+ ovrSizei RTSize;
+ int Multisample;
+};
+
+
+class Buffer : public RefCountBase<Buffer>
+{
+public:
+ RenderParams* pParams;
+ size_t Size;
+ GLenum Use;
+ GLuint GLBuffer;
+
+public:
+ Buffer(RenderParams* r);
+ ~Buffer();
+
+ GLuint GetBuffer() { return GLBuffer; }
+
+ virtual size_t GetSize() { return Size; }
+ virtual void* Map(size_t start, size_t size, int flags = 0);
+ virtual bool Unmap(void *m);
+ virtual bool Data(int use, const void* buffer, size_t size);
+};
+
+class Texture : public RefCountBase<Texture>
+{
+ bool IsUserAllocated;
+
+public:
+ RenderParams* pParams;
+ GLuint TexId;
+ int Width, Height;
+
+ Texture(RenderParams* rp, int w, int h);
+ ~Texture();
+
+ virtual int GetWidth() const { return Width; }
+ virtual int GetHeight() const { return Height; }
+
+ virtual void SetSampleMode(int sm);
+
+ // Updates texture to point to specified resources
+ // - used for slave rendering.
+ void UpdatePlaceholderTexture(GLuint texId,
+ const Sizei& textureSize);
+
+ virtual void Set(int slot, ShaderStage stage = Shader_Fragment) const;
+};
+
+// Base class for vertex and pixel shaders. Stored in ShaderSet.
+class Shader : public RefCountBase<Shader>
+{
+ friend class ShaderSet;
+
+protected:
+ ShaderStage Stage;
+
+public:
+ Shader(ShaderStage s) : Stage(s) {}
+ virtual ~Shader() {}
+
+ ShaderStage GetStage() const { return Stage; }
+
+ virtual void Set(PrimitiveType) const { }
+ virtual void SetUniformBuffer(class Buffer* buffers, int i = 0) { OVR_UNUSED2(buffers, i); }
+
+protected:
+ virtual bool SetUniform(const char* name, int n, const float* v) { OVR_UNUSED3(name, n, v); return false; }
+ virtual bool SetUniformBool(const char* name, int n, const bool* v) { OVR_UNUSED3(name, n, v); return false; }
+};
+
+
+
+// A group of shaders, one per stage.
+// A ShaderSet is applied for rendering with a given fill.
+class ShaderSet : public RefCountBase<ShaderSet>
+{
+protected:
+ Ptr<Shader> Shaders[Shader_Count];
+
+ struct Uniform
+ {
+ String Name;
+ int Location, Size;
+ int Type; // currently number of floats in vector
+ };
+ Array<Uniform> UniformInfo;
+
+public:
+ GLuint Prog;
+ GLint ProjLoc, ViewLoc;
+ GLint TexLoc[8];
+ bool UsesLighting;
+ int LightingVer;
+
+ ShaderSet();
+ ~ShaderSet();
+
+ virtual void SetShader(Shader *s);
+ virtual void UnsetShader(int stage);
+ Shader* GetShader(int stage) { return Shaders[stage]; }
+
+ virtual void Set(PrimitiveType prim) const
+ {
+ glUseProgram(Prog);
+
+ for (int i = 0; i < Shader_Count; i++)
+ if (Shaders[i])
+ Shaders[i]->Set(prim);
+ }
+
+ // Set a uniform (other than the standard matrices). It is undefined whether the
+ // uniforms from one shader occupy the same space as those in other shaders
+ // (unless a buffer is used, then each buffer is independent).
+ virtual bool SetUniform(const char* name, int n, const float* v);
+ bool SetUniform1f(const char* name, float x)
+ {
+ const float v[] = {x};
+ return SetUniform(name, 1, v);
+ }
+ bool SetUniform2f(const char* name, float x, float y)
+ {
+ const float v[] = {x,y};
+ return SetUniform(name, 2, v);
+ }
+ bool SetUniform3f(const char* name, float x, float y, float z)
+ {
+ const float v[] = {x,y,z};
+ return SetUniform(name, 3, v);
+ }
+ bool SetUniform4f(const char* name, float x, float y, float z, float w = 1)
+ {
+ const float v[] = {x,y,z,w};
+ return SetUniform(name, 4, v);
+ }
+
+ bool SetUniformv(const char* name, const Vector3f& v)
+ {
+ const float a[] = {v.x,v.y,v.z,1};
+ return SetUniform(name, 4, a);
+ }
+
+ virtual bool SetUniform4x4f(const char* name, const Matrix4f& m)
+ {
+ Matrix4f mt = m.Transposed();
+ return SetUniform(name, 16, &mt.M[0][0]);
+ }
+
+protected:
+ GLint GetGLShader(Shader* s);
+ bool Link();
+};
+
+
+// Fill combines a ShaderSet (vertex, pixel) with textures, if any.
+// Every model has a fill.
+class ShaderFill : public RefCountBase<ShaderFill>
+{
+ Ptr<ShaderSet> Shaders;
+ Ptr<class Texture> Textures[8];
+ void* InputLayout; // HACK this should be abstracted
+
+public:
+ ShaderFill(ShaderSet* sh) : Shaders(sh) { InputLayout = NULL; }
+ ShaderFill(ShaderSet& sh) : Shaders(sh) { InputLayout = NULL; }
+
+ ShaderSet* GetShaders() const { return Shaders; }
+ void* GetInputLayout() const { return InputLayout; }
+
+ virtual void Set(PrimitiveType prim = Prim_Unknown) const {
+ Shaders->Set(prim);
+ for(int i = 0; i < 8; i++)
+ {
+ if(Textures[i])
+ {
+ Textures[i]->Set(i);
+ }
+ }
+ }
+
+ virtual void SetTexture(int i, class Texture* tex) { if (i < 8) Textures[i] = tex; }
+};
+
+
+struct DisplayId
+{
+ // Windows
+ String MonitorName; // Monitor name for fullscreen mode
+
+ // MacOS
+ long CgDisplayId; // CGDirectDisplayID
+
+ DisplayId() : CgDisplayId(0) {}
+ DisplayId(long id) : CgDisplayId(id) {}
+ DisplayId(String m, long id=0) : MonitorName(m), CgDisplayId(id) {}
+
+ operator bool () const
+ {
+ return MonitorName.GetLength() || CgDisplayId;
+ }
+
+ bool operator== (const DisplayId& b) const
+ {
+ return CgDisplayId == b.CgDisplayId &&
+ (strstr(MonitorName.ToCStr(), b.MonitorName.ToCStr()) ||
+ strstr(b.MonitorName.ToCStr(), MonitorName.ToCStr()));
+ }
+};
+
+
+class ShaderBase : public Shader
+{
+public:
+ RenderParams* pParams;
+ unsigned char* UniformData;
+ int UniformsSize;
+
+ enum VarType
+ {
+ VARTYPE_FLOAT,
+ VARTYPE_INT,
+ VARTYPE_BOOL,
+ };
+
+ struct Uniform
+ {
+ const char* Name;
+ VarType Type;
+ int Offset, Size;
+ };
+ const Uniform* UniformRefl;
+ size_t UniformReflSize;
+
+ ShaderBase(RenderParams* rp, ShaderStage stage) : Shader(stage), pParams(rp), UniformData(0), UniformsSize(0) {}
+ ~ShaderBase()
+ {
+ if (UniformData)
+ OVR_FREE(UniformData);
+ }
+
+ void InitUniforms(const Uniform* refl, size_t reflSize);
+ bool SetUniform(const char* name, int n, const float* v);
+ bool SetUniformBool(const char* name, int n, const bool* v);
+
+ void UpdateBuffer(Buffer* b);
+};
+
+
+template<ShaderStage SStage, GLenum SType>
+class ShaderImpl : public ShaderBase
+{
+ friend class ShaderSet;
+
+public:
+ ShaderImpl(RenderParams* rp, void* s, size_t size, const Uniform* refl, size_t reflSize)
+ : ShaderBase(rp, SStage)
+ , GLShader(0)
+ {
+ BOOL success;
+ OVR_UNUSED(size);
+ success = Compile((const char*) s);
+ OVR_ASSERT(success);
+ InitUniforms(refl, reflSize);
+ }
+ ~ShaderImpl()
+ {
+ if (GLShader)
+ {
+ glDeleteShader(GLShader);
+ GLShader = 0;
+ }
+ }
+ bool Compile(const char* src)
+ {
+ if (!GLShader)
+ GLShader = glCreateShader(GLStage());
+
+ glShaderSource(GLShader, 1, &src, 0);
+ glCompileShader(GLShader);
+ GLint r;
+ glGetShaderiv(GLShader, GL_COMPILE_STATUS, &r);
+ if (!r)
+ {
+ GLchar msg[1024];
+ glGetShaderInfoLog(GLShader, sizeof(msg), 0, msg);
+ if (msg[0])
+ OVR_DEBUG_LOG(("Compiling shader\n%s\nfailed: %s\n", src, msg));
+
+ return 0;
+ }
+ return 1;
+ }
+
+ GLenum GLStage() const
+ {
+ return SType;
+ }
+
+private:
+ GLuint GLShader;
+};
+
+typedef ShaderImpl<Shader_Vertex, GL_VERTEX_SHADER> VertexShader;
+typedef ShaderImpl<Shader_Fragment, GL_FRAGMENT_SHADER> FragmentShader;
+
+}}}
+
+#endif // INC_OVR_CAPI_GL_Util_h