nuclear@0: /************************************************************************************ nuclear@0: nuclear@0: Filename : CAPI_GL_Util.cpp nuclear@0: Content : RenderDevice implementation for OpenGL nuclear@0: Created : September 10, 2012 nuclear@0: Authors : David Borel, Andrew Reisse nuclear@0: nuclear@0: Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. nuclear@0: nuclear@0: Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); nuclear@0: you may not use the Oculus VR Rift SDK except in compliance with the License, nuclear@0: which is provided at the time of installation or download, or which nuclear@0: otherwise accompanies this software in either electronic or hard copy form. nuclear@0: nuclear@0: You may obtain a copy of the License at nuclear@0: nuclear@0: http://www.oculusvr.com/licenses/LICENSE-3.2 nuclear@0: nuclear@0: Unless required by applicable law or agreed to in writing, the Oculus VR SDK nuclear@0: distributed under the License is distributed on an "AS IS" BASIS, nuclear@0: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. nuclear@0: See the License for the specific language governing permissions and nuclear@0: limitations under the License. nuclear@0: nuclear@0: ************************************************************************************/ nuclear@0: nuclear@0: #include "CAPI_GL_Util.h" nuclear@0: #include "../../Kernel/OVR_Log.h" nuclear@0: #include nuclear@0: nuclear@0: #if defined(OVR_OS_LINUX) nuclear@0: #include "../../Displays/OVR_Linux_SDKWindow.h" nuclear@0: #endif nuclear@0: nuclear@0: #if defined(OVR_OS_MAC) nuclear@0: #include nuclear@0: #include nuclear@0: nuclear@0: typedef void *CGSConnectionID; nuclear@0: typedef int32_t CGSWindowID; nuclear@0: typedef int32_t CGSSurfaceID; nuclear@0: nuclear@0: extern "C" CGLError CGLGetSurface(CGLContextObj ctx, CGSConnectionID *cid, CGSWindowID *wid, CGSSurfaceID *sid); nuclear@0: extern "C" CGLError CGLSetSurface(CGLContextObj ctx, CGSConnectionID cid, CGSWindowID wid, CGSSurfaceID sid); nuclear@0: #endif nuclear@0: nuclear@0: nuclear@0: nuclear@0: nuclear@0: namespace OVR { nuclear@0: nuclear@0: nuclear@0: OVR::GLEContext gleContext; nuclear@0: nuclear@0: nuclear@0: OVR::GLEContext* GetGLEContext() nuclear@0: { nuclear@0: return &gleContext; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: namespace CAPI { namespace GL { nuclear@0: nuclear@0: nuclear@0: void InitGLExtensions() nuclear@0: { nuclear@0: if(!gleContext.IsInitialized()) nuclear@0: { nuclear@0: gleContext.SetCurrentContext(&gleContext); nuclear@0: gleContext.Init(); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: nuclear@0: Buffer::Buffer(RenderParams* rp) : pParams(rp), Size(0), Use(0), GLBuffer(0) nuclear@0: { nuclear@0: } nuclear@0: nuclear@0: Buffer::~Buffer() nuclear@0: { nuclear@0: if (GLBuffer) nuclear@0: glDeleteBuffers(1, &GLBuffer); nuclear@0: } nuclear@0: nuclear@0: bool Buffer::Data(int use, const void* buffer, size_t size) nuclear@0: { nuclear@0: Size = size; nuclear@0: nuclear@0: switch (use & Buffer_TypeMask) nuclear@0: { nuclear@0: case Buffer_Index: Use = GL_ELEMENT_ARRAY_BUFFER; break; nuclear@0: default: Use = GL_ARRAY_BUFFER; break; nuclear@0: } nuclear@0: nuclear@0: if (!GLBuffer) nuclear@0: glGenBuffers(1, &GLBuffer); nuclear@0: nuclear@0: int mode = GL_DYNAMIC_DRAW; nuclear@0: if (use & Buffer_ReadOnly) nuclear@0: mode = GL_STATIC_DRAW; nuclear@0: nuclear@0: glBindBuffer(Use, GLBuffer); nuclear@0: glBufferData(Use, size, buffer, mode); nuclear@0: return 1; nuclear@0: } nuclear@0: nuclear@0: void* Buffer::Map(size_t, size_t, int) nuclear@0: { nuclear@0: int mode = GL_WRITE_ONLY; nuclear@0: //if (flags & Map_Unsynchronized) nuclear@0: // mode |= GL_MAP_UNSYNCHRONIZED; nuclear@0: nuclear@0: glBindBuffer(Use, GLBuffer); nuclear@0: void* v = glMapBuffer(Use, mode); nuclear@0: return v; nuclear@0: } nuclear@0: nuclear@0: bool Buffer::Unmap(void*) nuclear@0: { nuclear@0: glBindBuffer(Use, GLBuffer); nuclear@0: int r = glUnmapBuffer(Use); nuclear@0: return r != 0; nuclear@0: } nuclear@0: nuclear@0: ShaderSet::ShaderSet() : nuclear@0: //Shaders[], nuclear@0: UniformInfo(), nuclear@0: //Prog(0) nuclear@0: ProjLoc(0), nuclear@0: ViewLoc(0), nuclear@0: //TexLoc[], nuclear@0: UsesLighting(false), nuclear@0: LightingVer(0) nuclear@0: { nuclear@0: memset(TexLoc, 0, sizeof(TexLoc)); nuclear@0: Prog = glCreateProgram(); nuclear@0: } nuclear@0: ShaderSet::~ShaderSet() nuclear@0: { nuclear@0: glDeleteProgram(Prog); nuclear@0: } nuclear@0: nuclear@0: GLint ShaderSet::GetGLShader(Shader* s) nuclear@0: { nuclear@0: switch (s->Stage) nuclear@0: { nuclear@0: case Shader_Vertex: { nuclear@0: ShaderImpl* gls = (ShaderImpl*)s; nuclear@0: return gls->GLShader; nuclear@0: } break; nuclear@0: case Shader_Fragment: { nuclear@0: ShaderImpl* gls = (ShaderImpl*)s; nuclear@0: return gls->GLShader; nuclear@0: } break; nuclear@0: default: break; nuclear@0: } nuclear@0: nuclear@0: return -1; nuclear@0: } nuclear@0: nuclear@0: void ShaderSet::SetShader(Shader *s) nuclear@0: { nuclear@0: Shaders[s->Stage] = s; nuclear@0: GLint GLShader = GetGLShader(s); nuclear@0: glAttachShader(Prog, GLShader); nuclear@0: if (Shaders[Shader_Vertex] && Shaders[Shader_Fragment]) nuclear@0: Link(); nuclear@0: } nuclear@0: nuclear@0: void ShaderSet::UnsetShader(int stage) nuclear@0: { nuclear@0: if (Shaders[stage] == NULL) nuclear@0: return; nuclear@0: nuclear@0: GLint GLShader = GetGLShader(Shaders[stage]); nuclear@0: glDetachShader(Prog, GLShader); nuclear@0: nuclear@0: Shaders[stage] = NULL; nuclear@0: } nuclear@0: nuclear@0: bool ShaderSet::SetUniform(const char* name, int n, const float* v) nuclear@0: { nuclear@0: for (unsigned int i = 0; i < UniformInfo.GetSize(); i++) nuclear@0: if (!strcmp(UniformInfo[i].Name.ToCStr(), name)) nuclear@0: { nuclear@0: OVR_ASSERT(UniformInfo[i].Location >= 0); nuclear@0: glUseProgram(Prog); nuclear@0: switch (UniformInfo[i].Type) nuclear@0: { nuclear@0: case 1: glUniform1fv(UniformInfo[i].Location, n, v); break; nuclear@0: case 2: glUniform2fv(UniformInfo[i].Location, n/2, v); break; nuclear@0: case 3: glUniform3fv(UniformInfo[i].Location, n/3, v); break; nuclear@0: case 4: glUniform4fv(UniformInfo[i].Location, n/4, v); break; nuclear@0: case 12: glUniformMatrix3fv(UniformInfo[i].Location, 1, 1, v); break; nuclear@0: case 16: glUniformMatrix4fv(UniformInfo[i].Location, 1, 1, v); break; nuclear@0: default: OVR_ASSERT(0); nuclear@0: } nuclear@0: return 1; nuclear@0: } nuclear@0: nuclear@0: OVR_DEBUG_LOG(("Warning: uniform %s not present in selected shader", name)); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: bool ShaderSet::Link() nuclear@0: { nuclear@0: glLinkProgram(Prog); nuclear@0: GLint r; nuclear@0: glGetProgramiv(Prog, GL_LINK_STATUS, &r); nuclear@0: if (!r) nuclear@0: { nuclear@0: GLchar msg[1024]; nuclear@0: glGetProgramInfoLog(Prog, sizeof(msg), 0, msg); nuclear@0: OVR_DEBUG_LOG(("Linking shaders failed: %s\n", msg)); nuclear@0: if (!r) nuclear@0: return 0; nuclear@0: } nuclear@0: glUseProgram(Prog); nuclear@0: nuclear@0: UniformInfo.Clear(); nuclear@0: LightingVer = 0; nuclear@0: UsesLighting = 0; nuclear@0: nuclear@0: GLint uniformCount = 0; nuclear@0: glGetProgramiv(Prog, GL_ACTIVE_UNIFORMS, &uniformCount); nuclear@0: OVR_ASSERT(uniformCount >= 0); nuclear@0: nuclear@0: for(GLuint i = 0; i < (GLuint)uniformCount; i++) nuclear@0: { nuclear@0: GLsizei namelen; nuclear@0: GLint size = 0; nuclear@0: GLenum type; nuclear@0: GLchar name[32]; nuclear@0: glGetActiveUniform(Prog, i, sizeof(name), &namelen, &size, &type, name); nuclear@0: nuclear@0: if (size) nuclear@0: { nuclear@0: int l = glGetUniformLocation(Prog, name); nuclear@0: char *np = name; nuclear@0: while (*np) nuclear@0: { nuclear@0: if (*np == '[') nuclear@0: *np = 0; nuclear@0: np++; nuclear@0: } nuclear@0: Uniform u; nuclear@0: u.Name = name; nuclear@0: u.Location = l; nuclear@0: u.Size = size; nuclear@0: switch (type) nuclear@0: { nuclear@0: case GL_FLOAT: u.Type = 1; break; nuclear@0: case GL_FLOAT_VEC2: u.Type = 2; break; nuclear@0: case GL_FLOAT_VEC3: u.Type = 3; break; nuclear@0: case GL_FLOAT_VEC4: u.Type = 4; break; nuclear@0: case GL_FLOAT_MAT3: u.Type = 12; break; nuclear@0: case GL_FLOAT_MAT4: u.Type = 16; break; nuclear@0: default: nuclear@0: continue; nuclear@0: } nuclear@0: UniformInfo.PushBack(u); nuclear@0: if (!strcmp(name, "LightCount")) nuclear@0: UsesLighting = 1; nuclear@0: } nuclear@0: else nuclear@0: break; nuclear@0: } nuclear@0: nuclear@0: ProjLoc = glGetUniformLocation(Prog, "Proj"); nuclear@0: ViewLoc = glGetUniformLocation(Prog, "View"); nuclear@0: for (int i = 0; i < 8; i++) nuclear@0: { nuclear@0: char texv[32]; nuclear@0: OVR_sprintf(texv, 10, "Texture%d", i); nuclear@0: TexLoc[i] = glGetUniformLocation(Prog, texv); nuclear@0: if (TexLoc[i] < 0) nuclear@0: break; nuclear@0: nuclear@0: glUniform1i(TexLoc[i], i); nuclear@0: } nuclear@0: if (UsesLighting) nuclear@0: OVR_ASSERT(ProjLoc >= 0 && ViewLoc >= 0); nuclear@0: return 1; nuclear@0: } nuclear@0: nuclear@0: bool ShaderBase::SetUniform(const char* name, int n, const float* v) nuclear@0: { nuclear@0: for(unsigned i = 0; i < UniformReflSize; i++) nuclear@0: { nuclear@0: if (!strcmp(UniformRefl[i].Name, name)) nuclear@0: { nuclear@0: memcpy(UniformData + UniformRefl[i].Offset, v, n * sizeof(float)); nuclear@0: return 1; nuclear@0: } nuclear@0: } nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: bool ShaderBase::SetUniformBool(const char* name, int n, const bool* v) nuclear@0: { nuclear@0: OVR_UNUSED(n); nuclear@0: for(unsigned i = 0; i < UniformReflSize; i++) nuclear@0: { nuclear@0: if (!strcmp(UniformRefl[i].Name, name)) nuclear@0: { nuclear@0: memcpy(UniformData + UniformRefl[i].Offset, v, UniformRefl[i].Size); nuclear@0: return 1; nuclear@0: } nuclear@0: } nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: void ShaderBase::InitUniforms(const Uniform* refl, size_t reflSize) nuclear@0: { nuclear@0: if(!refl) nuclear@0: { nuclear@0: UniformRefl = NULL; nuclear@0: UniformReflSize = 0; nuclear@0: nuclear@0: UniformsSize = 0; nuclear@0: if (UniformData) nuclear@0: { nuclear@0: OVR_FREE(UniformData); nuclear@0: UniformData = 0; nuclear@0: } nuclear@0: return; // no reflection data nuclear@0: } nuclear@0: nuclear@0: UniformRefl = refl; nuclear@0: UniformReflSize = reflSize; nuclear@0: nuclear@0: UniformsSize = UniformRefl[UniformReflSize-1].Offset + UniformRefl[UniformReflSize-1].Size; nuclear@0: UniformData = (unsigned char*)OVR_ALLOC(UniformsSize); nuclear@0: } nuclear@0: nuclear@0: Texture::Texture(RenderParams* rp, int w, int h) : IsUserAllocated(false), pParams(rp), TexId(0), Width(w), Height(h) nuclear@0: { nuclear@0: if (w && h) nuclear@0: glGenTextures(1, &TexId); nuclear@0: } nuclear@0: nuclear@0: Texture::~Texture() nuclear@0: { nuclear@0: if (TexId && !IsUserAllocated) nuclear@0: glDeleteTextures(1, &TexId); nuclear@0: } nuclear@0: nuclear@0: void Texture::Set(int slot, ShaderStage) const nuclear@0: { nuclear@0: glActiveTexture(GL_TEXTURE0 + slot); nuclear@0: glBindTexture(GL_TEXTURE_2D, TexId); nuclear@0: } nuclear@0: nuclear@0: void Texture::SetSampleMode(int sm) nuclear@0: { nuclear@0: glBindTexture(GL_TEXTURE_2D, TexId); nuclear@0: switch (sm & Sample_FilterMask) nuclear@0: { nuclear@0: case Sample_Linear: nuclear@0: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); nuclear@0: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); nuclear@0: if(GLE_EXT_texture_filter_anisotropic) nuclear@0: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1); nuclear@0: break; nuclear@0: nuclear@0: case Sample_Anisotropic: nuclear@0: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); nuclear@0: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); nuclear@0: if(GLE_EXT_texture_filter_anisotropic) nuclear@0: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8); nuclear@0: break; nuclear@0: nuclear@0: case Sample_Nearest: nuclear@0: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); nuclear@0: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); nuclear@0: if(GLE_EXT_texture_filter_anisotropic) nuclear@0: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1); nuclear@0: break; nuclear@0: } nuclear@0: nuclear@0: switch (sm & Sample_AddressMask) nuclear@0: { nuclear@0: case Sample_Repeat: nuclear@0: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); nuclear@0: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); nuclear@0: break; nuclear@0: nuclear@0: case Sample_Clamp: nuclear@0: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); nuclear@0: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); nuclear@0: break; nuclear@0: nuclear@0: case Sample_ClampBorder: nuclear@0: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); nuclear@0: glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void Texture::UpdatePlaceholderTexture(GLuint texId, const Sizei& textureSize) nuclear@0: { nuclear@0: if (!IsUserAllocated && TexId && texId != TexId) nuclear@0: glDeleteTextures(1, &TexId); nuclear@0: nuclear@0: TexId = texId; nuclear@0: Width = textureSize.w; nuclear@0: Height = textureSize.h; nuclear@0: nuclear@0: IsUserAllocated = true; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: nuclear@0: nuclear@0: nuclear@0: Context::Context() : initialized(false), ownsContext(true), incarnation(0) nuclear@0: { nuclear@0: #if defined(OVR_OS_MAC) nuclear@0: systemContext = 0; nuclear@0: #elif defined(OVR_OS_WIN32) nuclear@0: hdc = 0; nuclear@0: systemContext = 0; nuclear@0: #elif defined(OVR_OS_LINUX) nuclear@0: x11Display = NULL; nuclear@0: x11Drawable = 0; nuclear@0: systemContext = 0; nuclear@0: memset(&x11Visual, 0, sizeof(x11Visual)); nuclear@0: #endif nuclear@0: nuclear@0: } nuclear@0: nuclear@0: void Context::InitFromCurrent() nuclear@0: { nuclear@0: Destroy(); nuclear@0: nuclear@0: initialized = true; nuclear@0: ownsContext = false; nuclear@0: incarnation++; nuclear@0: nuclear@0: #if defined(OVR_OS_MAC) nuclear@0: systemContext = CGLGetCurrentContext(); nuclear@0: { nuclear@0: CGSConnectionID cid; nuclear@0: CGSWindowID wid; nuclear@0: CGSSurfaceID sid; nuclear@0: CGLError e = kCGLNoError; nuclear@0: e = CGLGetSurface(systemContext, &cid, &wid, &sid); nuclear@0: OVR_ASSERT(e == kCGLNoError); OVR_UNUSED(e); nuclear@0: } nuclear@0: nuclear@0: #elif defined(OVR_OS_WIN32) nuclear@0: hdc = wglGetCurrentDC(); nuclear@0: systemContext = wglGetCurrentContext(); nuclear@0: #elif defined(OVR_OS_LINUX) nuclear@0: x11Display = glXGetCurrentDisplay(); nuclear@0: x11Drawable = glXGetCurrentDrawable(); nuclear@0: systemContext = glXGetCurrentContext(); nuclear@0: if (!SDKWindow::getVisualFromDrawable(x11Drawable, &x11Visual)) nuclear@0: { nuclear@0: OVR::LogError("[Context] Unable to obtain x11 visual from context"); nuclear@0: memset(&x11Visual, 0, sizeof(x11Visual)); nuclear@0: } nuclear@0: #endif nuclear@0: } nuclear@0: nuclear@0: nuclear@0: void Context::CreateShared( Context & ctx ) nuclear@0: { nuclear@0: Destroy(); nuclear@0: OVR_ASSERT( ctx.initialized == true ); nuclear@0: if( ctx.initialized == false ) nuclear@0: { nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: initialized = true; nuclear@0: ownsContext = true; nuclear@0: incarnation++; nuclear@0: nuclear@0: #if defined(OVR_OS_MAC) nuclear@0: CGLPixelFormatObj pixelFormat = CGLGetPixelFormat( ctx.systemContext ); nuclear@0: CGLError e = CGLCreateContext( pixelFormat, ctx.systemContext, &systemContext ); nuclear@0: OVR_ASSERT(e == kCGLNoError); OVR_UNUSED(e); nuclear@0: SetSurface(ctx); nuclear@0: #elif defined(OVR_OS_WIN32) nuclear@0: hdc = ctx.hdc; nuclear@0: systemContext = wglCreateContext( ctx.hdc ); nuclear@0: BOOL success = wglShareLists(ctx.systemContext, systemContext ); nuclear@0: OVR_ASSERT( success == TRUE ); nuclear@0: OVR_UNUSED(success); nuclear@0: #elif defined(OVR_OS_LINUX) nuclear@0: x11Display = ctx.x11Display; nuclear@0: x11Drawable = ctx.x11Drawable; nuclear@0: x11Visual = ctx.x11Visual; nuclear@0: systemContext = glXCreateContext( ctx.x11Display, &x11Visual, ctx.systemContext, True ); nuclear@0: OVR_ASSERT( systemContext != NULL ); nuclear@0: #endif nuclear@0: } nuclear@0: nuclear@0: #if defined(OVR_OS_MAC) nuclear@0: void Context::SetSurface( Context & ctx ) { nuclear@0: CGLError e = kCGLNoError; nuclear@0: CGSConnectionID cid, cid2; nuclear@0: CGSWindowID wid, wid2; nuclear@0: CGSSurfaceID sid, sid2; nuclear@0: nuclear@0: e = CGLGetSurface(ctx.systemContext, &cid, &wid, &sid); nuclear@0: OVR_ASSERT(e == kCGLNoError); OVR_UNUSED(e); nuclear@0: e = CGLGetSurface(systemContext, &cid2, &wid2, &sid2); nuclear@0: OVR_ASSERT(e == kCGLNoError); OVR_UNUSED(e); nuclear@0: if( sid && sid != sid2 ) { nuclear@0: e = CGLSetSurface(systemContext, cid, wid, sid); nuclear@0: OVR_ASSERT(e == kCGLNoError); OVR_UNUSED(e); nuclear@0: } nuclear@0: } nuclear@0: #endif nuclear@0: nuclear@0: void Context::Destroy() nuclear@0: { nuclear@0: if( initialized == false ) nuclear@0: { nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: if (systemContext) nuclear@0: { nuclear@0: #if defined(OVR_OS_MAC) nuclear@0: CGLDestroyContext( systemContext ); nuclear@0: #elif defined(OVR_OS_WIN32) nuclear@0: BOOL success = wglDeleteContext( systemContext ); nuclear@0: OVR_ASSERT( success == TRUE ); nuclear@0: OVR_UNUSED( success ); nuclear@0: #elif defined(OVR_OS_LINUX) nuclear@0: glXDestroyContext( x11Display, systemContext ); nuclear@0: #endif nuclear@0: nuclear@0: systemContext = NULL; nuclear@0: } nuclear@0: nuclear@0: initialized = false; nuclear@0: ownsContext = true; nuclear@0: } nuclear@0: nuclear@0: void Context::Bind() nuclear@0: { nuclear@0: if(systemContext) nuclear@0: { nuclear@0: #if defined(OVR_OS_MAC) nuclear@0: glFlush(); //Apple doesn't automatically flush within CGLSetCurrentContext, unlike other platforms. nuclear@0: CGLSetCurrentContext( systemContext ); nuclear@0: #elif defined(OVR_OS_WIN32) nuclear@0: wglMakeCurrent( hdc, systemContext ); nuclear@0: #elif defined(OVR_OS_LINUX) nuclear@0: glXMakeCurrent( x11Display, x11Drawable, systemContext ); nuclear@0: #endif nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void Context::Unbind() nuclear@0: { nuclear@0: #if defined(OVR_OS_MAC) nuclear@0: glFlush(); //Apple doesn't automatically flush within CGLSetCurrentContext, unlike other platforms. nuclear@0: CGLSetCurrentContext( NULL ); nuclear@0: #elif defined(OVR_OS_WIN32) nuclear@0: wglMakeCurrent( hdc, NULL ); nuclear@0: #elif defined(OVR_OS_LINUX) nuclear@0: glXMakeCurrent( x11Display, None, NULL ); nuclear@0: #endif nuclear@0: } nuclear@0: nuclear@0: }}} // namespace OVR::CAPI::GL