aboutsummaryrefslogtreecommitdiffstats
path: root/LibOVR/Src/CAPI/GL/CAPI_GL_HSWDisplay.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'LibOVR/Src/CAPI/GL/CAPI_GL_HSWDisplay.cpp')
-rw-r--r--LibOVR/Src/CAPI/GL/CAPI_GL_HSWDisplay.cpp507
1 files changed, 453 insertions, 54 deletions
diff --git a/LibOVR/Src/CAPI/GL/CAPI_GL_HSWDisplay.cpp b/LibOVR/Src/CAPI/GL/CAPI_GL_HSWDisplay.cpp
index 36830ca..6c0106d 100644
--- a/LibOVR/Src/CAPI/GL/CAPI_GL_HSWDisplay.cpp
+++ b/LibOVR/Src/CAPI/GL/CAPI_GL_HSWDisplay.cpp
@@ -33,7 +33,6 @@ limitations under the License.
#include "../../Kernel/OVR_Allocator.h"
#include "../../Kernel/OVR_Color.h"
-#include "../Textures/healthAndSafety.tga.h"
OVR_DISABLE_MSVC_WARNING(4996) // "This function or variable may be unsafe..."
@@ -46,8 +45,6 @@ namespace OVR { namespace CAPI {
uint8_t* LoadTextureTgaData(OVR::File* f, uint8_t alpha, int& width, int& height)
{
// See http://www.fileformat.info/format/tga/egff.htm for format details.
- // The TGA file must be exported with compression disabled and with the origin set to the top-left.
- // To do: Support at least RLE formats.
// TGA files are stored with little-endian data.
uint8_t* pRGBA = NULL;
@@ -67,9 +64,14 @@ uint8_t* LoadTextureTgaData(OVR::File* f, uint8_t alpha, int& width, int& height
int bpp = f->ReadUByte();
f->ReadUByte();
- OVR_ASSERT((imgtype == 2) && ((bpp == 24) || (bpp == 32)));
+ const int ImgTypeBGRAUncompressed = 2;
+ const int ImgTypeBGRARLECompressed = 10;
- if((imgtype == 2) && ((bpp == 24) || (bpp == 32)))
+ OVR_ASSERT(((imgtype == ImgTypeBGRAUncompressed) || (imgtype == ImgTypeBGRARLECompressed)) && ((bpp == 24) || (bpp == 32)));
+
+ // imgType 2 is uncompressed true-color image.
+ // imgType 10 is run-length encoded true-color image.
+ if(((imgtype == ImgTypeBGRAUncompressed) || (imgtype == ImgTypeBGRARLECompressed)) && ((bpp == 24) || (bpp == 32)))
{
int imgsize = width * height * 4;
pRGBA = (uint8_t*) OVR_ALLOC(imgsize);
@@ -77,37 +79,68 @@ uint8_t* LoadTextureTgaData(OVR::File* f, uint8_t alpha, int& width, int& height
f->Skip(palCount * (palSize + 7) >> 3);
int strideBytes = width * 4; // This is the number of bytes between successive rows.
-
- unsigned char buf[16];
+ unsigned char buf[4] = { 0, 0, 0, alpha }; // If bpp is 24 then this alpha will be unmodified below.
switch (imgtype)
{
- case 2: // uncompressed true-color image -- the only image type we support.
+ case ImgTypeBGRAUncompressed:
switch (bpp)
{
case 24:
+ case 32:
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
- f->Read(buf, 3); // Data is stored as B, G, R
+ f->Read(buf, bpp / 8); // Data is stored as B, G, R
pRGBA[y*strideBytes + x*4 + 0] = buf[2];
pRGBA[y*strideBytes + x*4 + 1] = buf[1];
pRGBA[y*strideBytes + x*4 + 2] = buf[0];
- pRGBA[y*strideBytes + x*4 + 3] = alpha;
+ pRGBA[y*strideBytes + x*4 + 3] = buf[3];
}
}
break;
+ }
+ break;
+
+ case ImgTypeBGRARLECompressed:
+ switch (bpp)
+ {
+ case 24:
case 32:
- for (int y = 0; y < height; y++)
+ for (int y = 0; y < height; y++) // RLE spans don't cross successive rows.
{
- for (int x = 0; x < width; x++)
+ int x = 0;
+
+ while(x < width)
{
- f->Read(buf, 4); // Data is stored as B, G, R, A
- pRGBA[y*strideBytes + x*4 + 0] = buf[2];
- pRGBA[y*strideBytes + x*4 + 1] = buf[1];
- pRGBA[y*strideBytes + x*4 + 2] = buf[0];
- pRGBA[y*strideBytes + x*4 + 3] = buf[3];
+ uint8_t rleByte;
+ f->Read(&rleByte, 1);
+
+ if(rleByte & 0x80) // If the high byte is set then what follows are RLE bytes.
+ {
+ size_t rleCount = ((rleByte & 0x7f) + 1);
+ f->Read(buf, bpp / 8); // Data is stored as B, G, R, A
+
+ for (; rleCount; --rleCount, ++x)
+ {
+ pRGBA[y*strideBytes + x*4 + 0] = buf[2];
+ pRGBA[y*strideBytes + x*4 + 1] = buf[1];
+ pRGBA[y*strideBytes + x*4 + 2] = buf[0];
+ pRGBA[y*strideBytes + x*4 + 3] = buf[3];
+ }
+ }
+ else // Else what follows are regular bytes of a count indicated by rleByte
+ {
+ for (size_t rleCount = (rleByte + 1); rleCount; --rleCount, ++x)
+ {
+ f->Read(buf, bpp / 8); // Data is stored as B, G, R, A
+ pRGBA[y*strideBytes + x*4 + 0] = buf[2];
+ pRGBA[y*strideBytes + x*4 + 1] = buf[1];
+ pRGBA[y*strideBytes + x*4 + 2] = buf[0];
+ pRGBA[y*strideBytes + x*4 + 3] = buf[3];
+ }
+ }
}
}
break;
@@ -165,6 +198,7 @@ Texture* LoadTextureTga(RenderParams& rParams, int samplerMode, OVR::File* f, ui
// We are intentionally not using mipmaps. We need to use this because Texture::SetSampleMode unilaterally uses GL_LINEAR_MIPMAP_LINEAR.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+ OVR_ASSERT(glGetError() == 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pRGBA);
OVR_ASSERT(glGetError() == 0);
@@ -196,12 +230,24 @@ Texture* LoadTextureTga(RenderParams& rParams, int samplerMode, const uint8_t* p
// simultaneously. As of this writing it's not clear if that can occur in practice.
HSWDisplay::HSWDisplay(ovrRenderAPIType api, ovrHmd hmd, const HMDRenderState& renderState)
- : OVR::CAPI::HSWDisplay(api, hmd, renderState),
- RenderParams(),
- FrameBuffer(0)
+ : OVR::CAPI::HSWDisplay(api, hmd, renderState)
+ , RenderParams()
+ , GLMajorVersion(0)
+ , GLMinorVersion(0)
+ , SupportsVao(false)
+ , FrameBuffer(0)
+ , pTexture()
+ , pShaderSet()
+ , pVertexShader()
+ , pFragmentShader()
+ , pVB()
+ , VAO(0)
+ , VAOInitialized(false)
+ , OrthoProjection()
{
}
-
+
+
bool HSWDisplay::Initialize(const ovrRenderAPIConfig* apiConfig)
{
const ovrGLConfig* config = (const ovrGLConfig*)apiConfig;
@@ -283,40 +329,68 @@ void HSWDisplay::UnloadGraphics()
pVertexShader.Clear();
pFragmentShader.Clear();
pVB.Clear();
+ if(VAO)
+ {
+ #ifdef OVR_OS_MAC
+ if(GLMajorVersion >= 3)
+ {
+ glDeleteVertexArrays(1, &VAO);
+ }
+ else
+ {
+ glDeleteVertexArraysAPPLE(1, &VAO);
+ }
+ #else
+ glDeleteVertexArrays(1, &VAO);
+ #endif
+ VAO = 0;
+ VAOInitialized = false;
+ }
// OrthoProjection: No need to clear.
}
void HSWDisplay::LoadGraphics()
{
- int glVersionMajor = 0;
- int glVersionMinor = 0;
const char* glVersionString = (const char*)glGetString(GL_VERSION);
OVR_ASSERT(glVersionString);
if (glVersionString)
{
- int fieldCount = sscanf(glVersionString, isdigit(*glVersionString) ? "%d.%d" : "%*[^0-9]%d.%d", &glVersionMajor, &glVersionMinor); // Skip all leading non-digits before reading %d. Example glVersionStrings: "1.5 ATI-1.4.18", "OpenGL ES-CM 3.2"
+ int fieldCount = sscanf(glVersionString, isdigit(*glVersionString) ? "%d.%d" : "%*[^0-9]%d.%d", &GLMajorVersion, &GLMinorVersion); // Skip all leading non-digits before reading %d. Example glVersionStrings: "1.5 ATI-1.4.18", "OpenGL ES-CM 3.2"
if(fieldCount != 2)
{
- static_assert(sizeof(glVersionMajor) == sizeof(GLint), "type mis-match");
- glGetIntegerv(GL_MAJOR_VERSION, &glVersionMajor);
+ static_assert(sizeof(GLMajorVersion) == sizeof(GLint), "type mis-match");
+ glGetIntegerv(GL_MAJOR_VERSION, &GLMajorVersion);
}
}
+ // SupportsVao
+ if(GLMajorVersion >= 3)
+ SupportsVao = true;
+ else
+ {
+ const char* extensions = (const char*)glGetString(GL_EXTENSIONS);
+ SupportsVao = (strstr(extensions, "GL_ARB_vertex_array_object") || strstr(extensions, "GL_APPLE_vertex_array_object"));
+ }
+
if (FrameBuffer == 0)
glGenFramebuffers(1, &FrameBuffer);
if (!pTexture) // To do: Add support for .dds files, which would be significantly smaller than the size of the tga.
- pTexture = *LoadTextureTga(RenderParams, Sample_Linear | Sample_Clamp, healthAndSafety_tga, (int)sizeof(healthAndSafety_tga), 255);
+ {
+ size_t textureSize;
+ const uint8_t* TextureData = GetDefaultTexture(textureSize);
+ pTexture = *LoadTextureTga(RenderParams, Sample_Linear | Sample_Clamp, TextureData, (int)textureSize, 255);
+ }
if(!pShaderSet)
pShaderSet = *new ShaderSet();
if(!pVertexShader)
{
- OVR::String strShader((glVersionMajor >= 3) ? glsl3Prefix : glsl2Prefix);
+ OVR::String strShader((GLMajorVersion >= 3) ? glsl3Prefix : glsl2Prefix);
strShader += SimpleTexturedQuad_vs;
pVertexShader = *new VertexShader(&RenderParams, const_cast<char*>(strShader.ToCStr()), strShader.GetLength(), SimpleTexturedQuad_vs_refl, OVR_ARRAY_COUNT(SimpleTexturedQuad_vs_refl));
@@ -325,7 +399,7 @@ void HSWDisplay::LoadGraphics()
if(!pFragmentShader)
{
- OVR::String strShader((glVersionMajor >= 3) ? glsl3Prefix : glsl2Prefix);
+ OVR::String strShader((GLMajorVersion >= 3) ? glsl3Prefix : glsl2Prefix);
strShader += SimpleTexturedQuad_ps;
pFragmentShader = *new FragmentShader(&RenderParams, const_cast<char*>(strShader.ToCStr()), strShader.GetLength(), SimpleTexturedQuad_ps_refl, OVR_ARRAY_COUNT(SimpleTexturedQuad_ps_refl));
@@ -348,7 +422,7 @@ void HSWDisplay::LoadGraphics()
const float right = 1.0f; // API abstraction we may move this draw to an overlay layer or to a more formal
const float bottom = 0.9f; // model/mesh scheme with a perspective projection.
- pVertices[0] = HASWVertex(left, top, 0.f, Color(255, 255, 255, 255), 0.f, flip ? 1.f : 0.f); // To do: Make this branchless
+ pVertices[0] = HASWVertex(left, top, 0.f, Color(255, 255, 255, 255), 0.f, flip ? 1.f : 0.f);
pVertices[1] = HASWVertex(left, bottom, 0.f, Color(255, 255, 255, 255), 0.f, flip ? 0.f : 1.f);
pVertices[2] = HASWVertex(right, top, 0.f, Color(255, 255, 255, 255), 1.f, flip ? 1.f : 0.f);
pVertices[3] = HASWVertex(right, bottom, 0.f, Color(255, 255, 255, 255), 1.f, flip ? 0.f : 1.f);
@@ -357,8 +431,23 @@ void HSWDisplay::LoadGraphics()
}
}
- // Calculate ortho projection.
- GetOrthoProjection(RenderState, OrthoProjection);
+ // We don't generate the vertex arrays here
+ if(!VAO && SupportsVao)
+ {
+ OVR_ASSERT(!VAOInitialized);
+ #ifdef OVR_OS_MAC
+ if(GLMajorVersion >= 3)
+ {
+ glGenVertexArrays(1, &VAO);
+ }
+ else
+ {
+ glGenVertexArraysAPPLE(1, &VAO);
+ }
+ #else
+ glGenVertexArrays(1, &VAO);
+ #endif
+ }
}
@@ -366,15 +455,158 @@ void HSWDisplay::RenderInternal(ovrEyeType eye, const ovrTexture* eyeTexture)
{
if(RenderEnabled && eyeTexture)
{
+ // Hack - Clear previous errors.
+ glGetError();
+
// We need to render to the eyeTexture with the texture viewport.
// Setup rendering to the texture.
ovrGLTexture* eyeTextureGL = const_cast<ovrGLTexture*>(reinterpret_cast<const ovrGLTexture*>(eyeTexture));
OVR_ASSERT(eyeTextureGL->Texture.Header.API == ovrRenderAPI_OpenGL);
+ const GLuint kVertexAttribCount = 3;
+ const GLuint kSavedVertexAttribCount = 8;
+
+ // Save state
+ // To do: Converge this with the state setting/restoring functionality present in the distortion renderer.
+ // Note that the glGet functions below will block until command buffer has completed.
+ // glPushAttrib is deprecated, so we use glGet* to save/restore fixed-function settings.
+ // https://www.opengl.org/sdk/docs/man/docbook4/xhtml/glGet.xml
+ //
+ GLint RenderModeSaved;
+ glGetIntegerv(GL_RENDER_MODE, &RenderModeSaved);
+ OVR_ASSERT(glGetError() == 0);
+ OVR_ASSERT(RenderModeSaved == GL_RENDER); // Make sure it's not GL_SELECT or GL_FEEDBACK.
+
+ GLint FrameBufferBindingSaved; // OpenGL renamed GL_FRAMEBUFFER_BINDING to GL_DRAW_FRAMEBUFFER_BINDING and adds GL_READ_FRAMEBUFFER_BINDING.
+ glGetIntegerv(GL_FRAMEBUFFER_BINDING, &FrameBufferBindingSaved);
+ OVR_ASSERT(glGetError() == 0);
+
+ GLint TextureBinding2DSaved;
+ glGetIntegerv(GL_TEXTURE_BINDING_2D, &TextureBinding2DSaved);
+ OVR_ASSERT(glGetError() == 0);
+
+ GLint ViewportSaved[4];
+ glGetIntegerv(GL_VIEWPORT, ViewportSaved);
+ OVR_ASSERT(glGetError() == 0);
+
+ GLint PolygonModeSaved[2]; // Will be two (e.g. GL_FILL) values, one for the front mode and one for the mode.
+ glGetIntegerv(GL_POLYGON_MODE, PolygonModeSaved);
+ OVR_ASSERT(glGetError() == 0);
+
+ GLdouble DepthRangeSaved[2];
+ #if defined(OVR_OS_MAC)
+ // Using glDepthRange as a conditional will always evaluate to true on Mac.
+ glGetDoublev(GL_DEPTH_RANGE, DepthRangeSaved);
+ #else
+ GLfloat DepthRangefSaved[2];
+ if(glDepthRange) // If we can use the double version (glDepthRangef may not be available)...
+ glGetDoublev(GL_DEPTH_RANGE, DepthRangeSaved);
+ else
+ glGetFloatv(GL_DEPTH_RANGE, DepthRangefSaved);
+ #endif
+ OVR_ASSERT(glGetError() == 0);
+
+ GLint DepthWriteMaskSaved;
+ glGetIntegerv(GL_DEPTH_WRITEMASK, &DepthWriteMaskSaved);
+ OVR_ASSERT(glGetError() == 0);
+
+ GLint DepthTestSaved;
+ glGetIntegerv(GL_DEPTH_TEST, &DepthTestSaved);
+ OVR_ASSERT(glGetError() == 0);
+
+ // No need to save/restore depth offset because we are neither testing nor writing depth.
+
+ GLint CullFaceSaved;
+ glGetIntegerv(GL_CULL_FACE, &CullFaceSaved);
+ OVR_ASSERT(glGetError() == 0);
+
+ GLint FrontFaceSaved;
+ glGetIntegerv(GL_FRONT_FACE, &FrontFaceSaved);
+ OVR_ASSERT(glGetError() == 0);
+
+ GLint BlendSaved;
+ glGetIntegerv(GL_BLEND, &BlendSaved);
+ OVR_ASSERT(glGetError() == 0);
+
+ GLint BlendSrcRGBSaved, BlendSrcAlphaSaved, BlendDstRGBSaved, BlendDstAlphaSaved;
+ glGetIntegerv(GL_BLEND_SRC_RGB, &BlendSrcRGBSaved);
+ glGetIntegerv(GL_BLEND_SRC_ALPHA, &BlendSrcAlphaSaved);
+ glGetIntegerv(GL_BLEND_DST_RGB, &BlendDstRGBSaved);
+ glGetIntegerv(GL_BLEND_DST_ALPHA, &BlendDstAlphaSaved);
+
+ GLint DitherSaved;
+ glGetIntegerv(GL_DITHER, &DitherSaved);
+ OVR_ASSERT(glGetError() == 0);
+
+ GLint RasterizerDiscardSaved;
+ glGetIntegerv(GL_RASTERIZER_DISCARD, &RasterizerDiscardSaved);
+ OVR_ASSERT(glGetError() == 0);
+
+ GLint ScissorTestSaved;
+ glGetIntegerv(GL_SCISSOR_TEST, &ScissorTestSaved);
+ OVR_ASSERT(glGetError() == 0);
+
+ GLint SampleMaskSaved = 0;
+ if(((GLMajorVersion * 100) + GLMinorVersion) >= 302) // OpenGL 3.2 or later
+ {
+ glGetIntegerv(GL_SAMPLE_MASK, &SampleMaskSaved);
+ OVR_ASSERT(glGetError() == 0);
+ }
+
+ GLint ColorWriteMaskSaved[4];
+ glGetIntegerv(GL_COLOR_WRITEMASK, ColorWriteMaskSaved);
+
+ GLint ArrayBufferBindingSaved;
+ glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &ArrayBufferBindingSaved);
+ OVR_ASSERT(glGetError() == 0);
+
+ GLint ProgramSaved;
+ glGetIntegerv(GL_CURRENT_PROGRAM, &ProgramSaved);
+ OVR_ASSERT(glGetError() == 0);
+
+ GLint ActiveTextureSaved;
+ glGetIntegerv(GL_ACTIVE_TEXTURE, &ActiveTextureSaved);
+ OVR_ASSERT(glGetError() == 0);
+
+ GLint TextureBindingSaved;
+ glGetIntegerv(GL_TEXTURE_BINDING_2D, &TextureBindingSaved);
+ OVR_ASSERT(glGetError() == 0);
+
+ // https://www.opengl.org/sdk/docs/man/docbook4/xhtml/glVertexAttribPointer.xml
+ GLint VertexAttribEnabledSaved[kSavedVertexAttribCount];
+ GLint VertexAttribSizeSaved[kSavedVertexAttribCount];
+ GLint VertexAttribTypeSaved[kSavedVertexAttribCount];
+ GLint VertexAttribNormalizedSaved[kSavedVertexAttribCount];
+ GLint VertexAttribStrideSaved[kSavedVertexAttribCount];
+ GLvoid* VertexAttribPointerSaved[kSavedVertexAttribCount];
+ for(GLuint i = 0; i < kSavedVertexAttribCount; i++)
+ {
+ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &VertexAttribEnabledSaved[i]);
+
+ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &VertexAttribSizeSaved[i]);
+ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_TYPE, &VertexAttribTypeSaved[i]);
+ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &VertexAttribNormalizedSaved[i]);
+ glGetVertexAttribiv(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &VertexAttribStrideSaved[i]);
+ glGetVertexAttribPointerv(i, GL_VERTEX_ATTRIB_ARRAY_POINTER, &VertexAttribPointerSaved[i]);
+
+ OVR_ASSERT(glGetError() == 0);
+ }
+
+ GLint VertexArrayBindingSaved = 0;
+ if (SupportsVao)
+ glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &VertexArrayBindingSaved);
+
+ //
+ // End of save state
+
+
// Load the graphics if not loaded already.
if (!pTexture)
LoadGraphics();
+ // Calculate ortho projection.
+ GetOrthoProjection(RenderState, OrthoProjection);
+
// Set the rendering to be to the eye texture.
glBindFramebuffer(GL_FRAMEBUFFER, FrameBuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, eyeTextureGL->OGL.TexId, 0);
@@ -383,6 +615,7 @@ void HSWDisplay::RenderInternal(ovrEyeType eye, const ovrTexture* eyeTexture)
// glDrawBuffers(OVR_ARRAY_COUNT(DrawBuffers), DrawBuffers);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
OVR_ASSERT(status == GL_FRAMEBUFFER_COMPLETE); OVR_UNUSED(status);
+ OVR_ASSERT(glGetError() == 0);
// Set up the viewport
const GLint x = (GLint)eyeTextureGL->Texture.Header.RenderViewport.Pos.x;
@@ -390,19 +623,34 @@ void HSWDisplay::RenderInternal(ovrEyeType eye, const ovrTexture* eyeTexture)
const GLsizei w = (GLsizei)eyeTextureGL->Texture.Header.RenderViewport.Size.w;
const GLsizei h = (GLsizei)eyeTextureGL->Texture.Header.RenderViewport.Size.h;
glViewport(x, y, w, h);
+ OVR_ASSERT(glGetError() == 0);
// Set fixed-function render states
- glDisable(GL_DEPTH_TEST);
- glEnable(GL_CULL_FACE); // Irrelevant to our case here.
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ OVR_ASSERT(glGetError() == 0);
+ #if defined(OVR_OS_MAC) // On Mac we are directly using OpenGL functions instead of function pointers.
+ glDepthRange(0.0, 1.0);
+ #else
+ if(glDepthRange) // If we can use the double version (glDepthRangef may not be available)...
+ glDepthRange(0.0, 1.0);
+ else
+ glDepthRangef(0.f, 1.f);
+ #endif
+ glDepthMask(GL_FALSE);
+ glDisable(GL_DEPTH_TEST); // Disabling depth test should also have the effect of glDepthMask(GL_FALSE).
+ glDisable(GL_CULL_FACE);
glFrontFace(GL_CW);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_DITHER);
+ glDisable(GL_RASTERIZER_DISCARD);
+ glDisable(GL_SCISSOR_TEST);
+ if(((GLMajorVersion * 100) + GLMinorVersion) >= 302) // OpenGL 3.2 or later
+ glDisable(GL_SAMPLE_MASK);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
OVR_ASSERT(glGetError() == 0);
// Enable the buffer and shaders we use.
- glBindBuffer(GL_ARRAY_BUFFER, pVB->GLBuffer);
- OVR_ASSERT(glGetError() == 0);
-
ShaderFill fill(pShaderSet);
if(pTexture)
{
@@ -417,26 +665,52 @@ void HSWDisplay::RenderInternal(ovrEyeType eye, const ovrTexture* eyeTexture)
OVR_ASSERT(glGetError() == 0);
// Set vertex attributes
- // To consider: We can use glGenVertexArrays + glBindVertexArray here to tell GL to store the attrib values below in
- // a vertex array object so later we can simply call glBindVertexArray(VertexArrayObject) to enable them instead
- // of doing all the calls below again. glBindVertexArray(0) to unbind, glDeleteVertexArrays to destory. Requires
- // OpenGL v3+ or the GL_ARB_vertex_array_object extension.
+ // To do: We must add support for vertext array objects (VAOs) here. When using an OpenGL 3.2+ core profile,
+ // the application is required to use vertex array objects and glVertexAttribPointer will fail otherwise.
- const GLuint shaderProgram = pShaderSet->Prog;
- int attributeLocationArray[3];
+ if(SupportsVao)
+ {
+ OVR_ASSERT(VAO != 0);
+ #ifdef OVR_OS_MAC
+ if(GLMajorVersion >= 3)
+ {
+ glBindVertexArray(VAO);
+ }
+ else
+ {
+ glBindVertexArrayAPPLE(VAO);
+ }
+ #else
+ glBindVertexArray(VAO);
+ #endif
+ }
- attributeLocationArray[0] = glGetAttribLocation(shaderProgram, "Position");
- glVertexAttribPointer(attributeLocationArray[0], sizeof(Vector3f)/sizeof(float), GL_FLOAT, false, sizeof(HASWVertex), reinterpret_cast<char*>(offsetof(HASWVertex, Pos)));
+ if(!VAOInitialized) // This executes for the case that VAO isn't supported.
+ {
+ glBindBuffer(GL_ARRAY_BUFFER, pVB->GLBuffer); // This must be called before glVertexAttribPointer is called below.
+ OVR_ASSERT(glGetError() == 0);
- attributeLocationArray[1] = glGetAttribLocation(shaderProgram, "Color");
- glVertexAttribPointer(attributeLocationArray[1], sizeof(Color)/sizeof(uint8_t), GL_UNSIGNED_BYTE, false, sizeof(HASWVertex), reinterpret_cast<char*>(offsetof(HASWVertex, C)));
+ const GLuint shaderProgram = pShaderSet->Prog;
+ GLint attributeLocationArray[kVertexAttribCount];
- attributeLocationArray[2] = glGetAttribLocation(shaderProgram, "TexCoord");
- glVertexAttribPointer(attributeLocationArray[2], sizeof(float[2])/sizeof(float), GL_FLOAT, false, sizeof(HASWVertex), reinterpret_cast<char*>(offsetof(HASWVertex, U)));
+ attributeLocationArray[0] = glGetAttribLocation(shaderProgram, "Position");
+ glVertexAttribPointer(attributeLocationArray[0], sizeof(Vector3f)/sizeof(float), GL_FLOAT, false, sizeof(HASWVertex), reinterpret_cast<char*>(offsetof(HASWVertex, Pos)));
- for (size_t i = 0; i < OVR_ARRAY_COUNT(attributeLocationArray); i++)
- glEnableVertexAttribArray((GLuint)i);
- OVR_ASSERT(glGetError() == 0);
+ attributeLocationArray[1] = glGetAttribLocation(shaderProgram, "Color");
+ glVertexAttribPointer(attributeLocationArray[1], sizeof(Color)/sizeof(uint8_t), GL_UNSIGNED_BYTE, true, sizeof(HASWVertex), reinterpret_cast<char*>(offsetof(HASWVertex, C))); // True because we want it to convert [0,255] to [0,1] for us.
+
+ attributeLocationArray[2] = glGetAttribLocation(shaderProgram, "TexCoord");
+ glVertexAttribPointer(attributeLocationArray[2], sizeof(float[2])/sizeof(float), GL_FLOAT, false, sizeof(HASWVertex), reinterpret_cast<char*>(offsetof(HASWVertex, U)));
+ OVR_ASSERT(glGetError() == 0);
+
+ for (size_t i = 0; i < kVertexAttribCount; i++)
+ glEnableVertexAttribArray((GLuint)i);
+ OVR_ASSERT(glGetError() == 0);
+
+ for (size_t i = kVertexAttribCount; i < kSavedVertexAttribCount; i++)
+ glDisableVertexAttribArray((GLuint)i);
+ OVR_ASSERT(glGetError() == 0);
+ }
fill.Set(Prim_TriangleStrip);
OVR_ASSERT(glGetError() == 0);
@@ -444,10 +718,135 @@ void HSWDisplay::RenderInternal(ovrEyeType eye, const ovrTexture* eyeTexture)
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
OVR_ASSERT(glGetError() == 0);
- for (size_t i = 0; i < OVR_ARRAY_COUNT(attributeLocationArray); i++)
- glDisableVertexAttribArray(i);
+ if(SupportsVao)
+ {
+ VAOInitialized = true;
+
+ #ifdef OVR_OS_MAC
+ if(GLMajorVersion >= 3)
+ {
+ glBindVertexArray(0);
+ }
+ else
+ {
+ glBindVertexArrayAPPLE(0);
+ }
+ #else
+ glBindVertexArray(0);
+ #endif
+ }
+
+ // Restore state
+ // We restore the state in the reverse order that we saved it.
+ // To do: Make the code below avoid changes that are effectively no-ops.
+ //
+ if (SupportsVao)
+ {
+#ifdef OVR_OS_MAC
+ if(GLMajorVersion >= 3)
+ {
+ glBindVertexArray(VertexArrayBindingSaved);
+ }
+ else
+ {
+ glBindVertexArrayAPPLE(VertexArrayBindingSaved);
+ }
+#else
+ glBindVertexArray(VertexArrayBindingSaved);
+#endif
+ }
+
+ for (GLuint i = 0; i < kSavedVertexAttribCount; i++)
+ {
+ // We have a problem here: if the GL context was initialized with a core profile version 3.x or later, calls to glVertexAttribPointer can fail when there is no Vertex Array Object
+ // in place. That case is possible here, and we don't have an easy means to detect that a core profile was specified and thus that the glVertexAttribPointer call below could fail.
+ // Our current solution is to call glVertexAttribPointer only if vertex array objects are not supported. We cannot simply decide based on whether the given vertex attrib was enabled
+ // or if there was a vertex array object installed. With our solution below a problem can occur when using OpenGL 3.x+ which supports VAOs, the user has vertex attrib pointers installed,
+ // the currently installed VAO is 0, and the user is somehow dependent on us returning to the user with those vertex attrib pointers reinstalled.
+
+ if (!SupportsVao || (VertexArrayBindingSaved != 0)) // If the OpenGL version is older or in core profile compatibility mode, or if there's a VAO currently installed...
+ {
+ glVertexAttribPointer(i, VertexAttribSizeSaved[i], VertexAttribTypeSaved[i], (GLboolean)VertexAttribNormalizedSaved[i], VertexAttribStrideSaved[i], VertexAttribPointerSaved[i]);
+
+ if(VertexAttribEnabledSaved[i])
+ glEnableVertexAttribArray(i);
+ else
+ glDisableVertexAttribArray(i);
+
+ OVR_ASSERT(glGetError() == 0);
+ }
+ }
+
+ glBindTexture(GL_TEXTURE_2D, TextureBindingSaved);
+ glActiveTexture(ActiveTextureSaved);
+ glUseProgram(ProgramSaved);
+ glBindBuffer(GL_ARRAY_BUFFER, ArrayBufferBindingSaved);
+ glColorMask((GLboolean)ColorWriteMaskSaved[0], (GLboolean)ColorWriteMaskSaved[1], (GLboolean)ColorWriteMaskSaved[2], (GLboolean)ColorWriteMaskSaved[3]);
+
+ if(((GLMajorVersion * 100) + GLMinorVersion) >= 302) // OpenGL 3.2 or later
+ {
+ if(SampleMaskSaved)
+ glEnable(GL_SAMPLE_MASK);
+ else
+ glDisable(GL_SAMPLE_MASK);
+ }
+
+ if(ScissorTestSaved)
+ glEnable(GL_SCISSOR_TEST);
+ else
+ glDisable(GL_SCISSOR_TEST);
+
+ if(RasterizerDiscardSaved)
+ glEnable(GL_RASTERIZER_DISCARD);
+ else
+ glDisable(GL_RASTERIZER_DISCARD);
+
+ if(DitherSaved)
+ glEnable(GL_DITHER);
+ else
+ glDisable(GL_DITHER);
+
+ glBlendFunc(BlendSrcRGBSaved, BlendDstRGBSaved); // What about BlendSrcAlphaSaved / BlendDstAlphaSaved?
+
+ if(BlendSaved)
+ glEnable(GL_BLEND);
+ else
+ glDisable(GL_BLEND);
+
+ glFrontFace(FrontFaceSaved);
+
+ if(CullFaceSaved)
+ glEnable(GL_CULL_FACE);
+ else
+ glDisable(GL_CULL_FACE);
+
+ if(DepthTestSaved)
+ glEnable(GL_DEPTH_TEST);
+ else
+ glDisable(GL_DEPTH_TEST);
+
+ glDepthMask(DepthWriteMaskSaved ? GL_TRUE : GL_FALSE);
+ #if defined(OVR_OS_MAC) // On Mac we are directly using OpenGL functions instead of function pointers.
+ glDepthRange(DepthRangeSaved[0], DepthRangeSaved[1]);
+ #else
+ if(glDepthRange) // If we can use the double version (glDepthRangef may not be available)...
+ glDepthRange(DepthRangeSaved[0], DepthRangeSaved[1]);
+ else
+ glDepthRangef(DepthRangefSaved[0], DepthRangefSaved[1]);
+ #endif
+ // For OpenGL 3.x+ core profile mode, glPolygonMode allows only GL_FRONT_AND_BACK and not separate GL_FRONT and GL_BACK.
+ glPolygonMode(GL_FRONT_AND_BACK, PolygonModeSaved[0]);
+ glViewport(ViewportSaved[0], ViewportSaved[1], ViewportSaved[2], ViewportSaved[3]);
+ glBindTexture(GL_TEXTURE_2D, TextureBinding2DSaved);
+ glBindFramebuffer(GL_FRAMEBUFFER, FrameBufferBindingSaved);
+ //glRenderMode(RenderModeSaved);
+
+ OVR_ASSERT(glGetError() == 0);
+ //
+ // End of restore state
}
}
+
}}} // namespace OVR::CAPI::GL