diff options
Diffstat (limited to 'LibOVR/Src/CAPI/GL')
-rw-r--r-- | LibOVR/Src/CAPI/GL/CAPI_GL_DistortionRenderer.cpp | 1006 | ||||
-rw-r--r-- | LibOVR/Src/CAPI/GL/CAPI_GL_DistortionRenderer.h | 125 | ||||
-rw-r--r-- | LibOVR/Src/CAPI/GL/CAPI_GL_Util.cpp | 516 | ||||
-rw-r--r-- | LibOVR/Src/CAPI/GL/CAPI_GL_Util.h | 522 |
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 |