ovr_sdk

view LibOVR/Src/CAPI/GL/CAPI_GL_DistortionRenderer.cpp @ 0:1b39a1b46319

initial 0.4.4
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 14 Jan 2015 06:51:16 +0200
parents
children
line source
1 /************************************************************************************
3 Filename : CAPI_GL_DistortionRenderer.h
4 Content : Distortion renderer header for GL
5 Created : November 11, 2013
6 Authors : David Borel, Lee Cooper
8 Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
10 Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
11 you may not use the Oculus VR Rift SDK except in compliance with the License,
12 which is provided at the time of installation or download, or which
13 otherwise accompanies this software in either electronic or hard copy form.
15 You may obtain a copy of the License at
17 http://www.oculusvr.com/licenses/LICENSE-3.2
19 Unless required by applicable law or agreed to in writing, the Oculus VR SDK
20 distributed under the License is distributed on an "AS IS" BASIS,
21 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 See the License for the specific language governing permissions and
23 limitations under the License.
25 ************************************************************************************/
27 #include "CAPI_GL_DistortionRenderer.h"
29 #include "CAPI_GL_DistortionShaders.h"
31 #include "../../OVR_CAPI_GL.h"
32 #include "../../Kernel/OVR_Color.h"
34 #if defined(OVR_OS_LINUX)
35 #include "../../Displays/OVR_Linux_SDKWindow.h"
36 #elif defined(OVR_OS_MAC)
37 #include <CoreGraphics/CGDirectDisplay.h>
38 #include <OpenGL/OpenGL.h>
39 #endif
41 namespace OVR { namespace CAPI { namespace GL {
44 // Distortion pixel shader lookup.
45 // Bit 0: Chroma Correction
46 // Bit 1: Timewarp
48 enum {
49 DistortionVertexShaderBitMask = 3,
50 DistortionVertexShaderCount = DistortionVertexShaderBitMask + 1,
51 DistortionPixelShaderBitMask = 1,
52 DistortionPixelShaderCount = DistortionPixelShaderBitMask + 1
53 };
55 struct ShaderInfo
56 {
57 const char* ShaderData;
58 size_t ShaderSize;
59 const ShaderBase::Uniform* ReflectionData;
60 size_t ReflectionSize;
61 };
63 // Do add a new distortion shader use these macros (with or w/o reflection)
64 #define SI_NOREFL(shader) { shader, sizeof(shader), NULL, 0 }
65 #define SI_REFL__(shader) { shader, sizeof(shader), shader ## _refl, sizeof( shader ## _refl )/sizeof(*(shader ## _refl)) }
68 static ShaderInfo DistortionVertexShaderLookup[DistortionVertexShaderCount] =
69 {
70 SI_REFL__(Distortion_vs),
71 SI_REFL__(DistortionChroma_vs),
72 SI_REFL__(DistortionTimewarp_vs),
73 SI_REFL__(DistortionTimewarpChroma_vs)
74 };
76 static ShaderInfo DistortionPixelShaderLookup[DistortionPixelShaderCount] =
77 {
78 SI_NOREFL(Distortion_fs),
79 SI_NOREFL(DistortionChroma_fs)
80 };
82 void DistortionShaderBitIndexCheck()
83 {
84 OVR_COMPILER_ASSERT(ovrDistortionCap_Chromatic == 1);
85 OVR_COMPILER_ASSERT(ovrDistortionCap_TimeWarp == 2);
86 }
90 struct DistortionVertex
91 {
92 Vector2f ScreenPosNDC;
93 Vector2f TanEyeAnglesR;
94 Vector2f TanEyeAnglesG;
95 Vector2f TanEyeAnglesB;
96 Color Col;
97 };
100 // Vertex type; same format is used for all shapes for simplicity.
101 // Shapes are built by adding vertices to Model.
102 struct LatencyVertex
103 {
104 Vector3f Pos;
105 LatencyVertex (const Vector3f& p) : Pos(p) {}
106 };
109 //----------------------------------------------------------------------------
110 // ***** GL::DistortionRenderer
112 DistortionRenderer::DistortionRenderer(ovrHmd hmd, FrameTimeManager& timeManager,
113 const HMDRenderState& renderState)
114 : CAPI::DistortionRenderer(ovrRenderAPI_OpenGL, hmd, timeManager, renderState)
115 , RotateCCW90(false)
116 , LatencyVAO(0)
117 , OverdriveFbo(0)
118 {
119 DistortionMeshVAOs[0] = 0;
120 DistortionMeshVAOs[1] = 0;
122 // Initialize render params.
123 memset(&RParams, 0, sizeof(RParams));
124 }
126 DistortionRenderer::~DistortionRenderer()
127 {
128 destroy();
129 }
131 // static
132 CAPI::DistortionRenderer* DistortionRenderer::Create(ovrHmd hmd,
133 FrameTimeManager& timeManager,
134 const HMDRenderState& renderState)
135 {
136 InitGLExtensions();
138 return new DistortionRenderer(hmd, timeManager, renderState);
139 }
142 bool DistortionRenderer::Initialize(const ovrRenderAPIConfig* apiConfig)
143 {
144 const ovrGLConfig* config = (const ovrGLConfig*)apiConfig;
146 if (!config)
147 {
148 // Cleanup
149 pEyeTextures[0].Clear();
150 pEyeTextures[1].Clear();
151 memset(&RParams, 0, sizeof(RParams));
152 return true;
153 }
155 RParams.Multisample = config->OGL.Header.Multisample;
156 RParams.BackBufferSize = config->OGL.Header.BackBufferSize;
157 #if defined(OVR_OS_WIN32)
158 RParams.Window = (config->OGL.Window) ? config->OGL.Window : GetActiveWindow();
159 RParams.DC = config->OGL.DC;
160 #elif defined(OVR_OS_LINUX)
161 RotateCCW90 = false;
162 if ( RState.DistortionCaps & ovrDistortionCap_LinuxDevFullscreen
163 && SDKWindow::getRotation(HMD) == DistRotateCCW90)
164 {
165 RotateCCW90 = true;
166 }
167 if (config->OGL.Disp)
168 {
169 RParams.Disp = config->OGL.Disp;
170 }
171 if (!RParams.Disp)
172 {
173 RParams.Disp = glXGetCurrentDisplay();
174 }
175 if (!RParams.Disp)
176 {
177 OVR_DEBUG_LOG(("glXGetCurrentDisplay failed."));
178 return false;
179 }
180 #endif
182 DistortionMeshVAOs[0] = 0;
183 DistortionMeshVAOs[1] = 0;
185 LatencyVAO = 0;
187 GL::AutoContext autoGLContext(distortionContext); // Initializes distortionContext if not already, saves the current GL context, binds distortionContext, then at the end of scope re-binds the current GL context.
189 pEyeTextures[0] = *new Texture(&RParams, 0, 0);
190 pEyeTextures[1] = *new Texture(&RParams, 0, 0);
192 initBuffersAndShaders();
194 initOverdrive();
196 return true;
197 }
200 void DistortionRenderer::initOverdrive()
201 {
202 if(RState.DistortionCaps & ovrDistortionCap_Overdrive)
203 {
204 LastUsedOverdriveTextureIndex = 0;
206 glGenFramebuffers(1, &OverdriveFbo);
208 GLint internalFormat = (RState.DistortionCaps & ovrDistortionCap_SRGB) ? GL_SRGB_ALPHA : GL_RGBA;
210 for (int i = 0; i < NumOverdriveTextures ; i++)
211 {
212 pOverdriveTextures[i] = *new Texture(&RParams, RParams.BackBufferSize.w, RParams.BackBufferSize.h);
214 glBindTexture(GL_TEXTURE_2D, pOverdriveTextures[i]->TexId);
215 glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, RParams.BackBufferSize.w, RParams.BackBufferSize.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
216 OVR_ASSERT( glGetError() == GL_NO_ERROR );
218 pOverdriveTextures[i]->SetSampleMode(Sample_ClampBorder | Sample_Linear);
219 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
220 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
221 OVR_ASSERT(glGetError() == 0);
223 // clear the new buffer
224 glBindFramebuffer(GL_FRAMEBUFFER, OverdriveFbo );
225 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, pOverdriveTextures[i]->TexId, 0);
226 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
227 OVR_ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
228 GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0};
229 glDrawBuffers(OVR_ARRAY_COUNT(drawBuffers), drawBuffers);
230 glClearColor(0,0,0,1);
231 glClear(GL_COLOR_BUFFER_BIT);
232 }
234 {
235 OverdriveBackBufferTexture = *new Texture(&RParams, RParams.BackBufferSize.w, RParams.BackBufferSize.h);
237 glBindTexture(GL_TEXTURE_2D, OverdriveBackBufferTexture->TexId);
238 glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, RParams.BackBufferSize.w, RParams.BackBufferSize.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
239 OVR_ASSERT(glGetError() == 0);
241 OverdriveBackBufferTexture->SetSampleMode(Sample_ClampBorder | Sample_Linear);
242 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
243 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
244 OVR_ASSERT(glGetError() == 0);
246 // clear the new buffer
247 glBindFramebuffer(GL_FRAMEBUFFER, OverdriveFbo );
248 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, OverdriveBackBufferTexture->TexId, 0);
249 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
250 OVR_ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
251 GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0};
252 glDrawBuffers(OVR_ARRAY_COUNT(drawBuffers), drawBuffers);
253 glClearColor(0,0,0,1);
254 glClear(GL_COLOR_BUFFER_BIT);
255 }
257 glBindFramebuffer(GL_FRAMEBUFFER, 0);
258 }
259 else
260 {
261 LastUsedOverdriveTextureIndex = -1;
262 }
263 }
265 void DistortionRenderer::SubmitEye(int eyeId, const ovrTexture* eyeTexture)
266 {
267 // Doesn't do a lot in here??
268 const ovrGLTexture* tex = (const ovrGLTexture*)eyeTexture;
270 if (tex)
271 {
272 // Write in values
273 eachEye[eyeId].texture = tex->OGL.TexId;
275 // Its only at this point we discover what the viewport of the texture is.
276 // because presumably we allow users to realtime adjust the resolution.
277 eachEye[eyeId].TextureSize = tex->OGL.Header.TextureSize;
278 eachEye[eyeId].RenderViewport = tex->OGL.Header.RenderViewport;
280 const ovrEyeRenderDesc& erd = RState.EyeRenderDesc[eyeId];
282 ovrHmd_GetRenderScaleAndOffset( erd.Fov,
283 eachEye[eyeId].TextureSize, eachEye[eyeId].RenderViewport,
284 eachEye[eyeId].UVScaleOffset );
286 if (!(RState.DistortionCaps & ovrDistortionCap_FlipInput))
287 {
288 eachEye[eyeId].UVScaleOffset[0].y = -eachEye[eyeId].UVScaleOffset[0].y;
289 eachEye[eyeId].UVScaleOffset[1].y = 1.0f - eachEye[eyeId].UVScaleOffset[1].y;
290 }
292 pEyeTextures[eyeId]->UpdatePlaceholderTexture(tex->OGL.TexId,
293 tex->OGL.Header.TextureSize);
294 }
295 }
297 void DistortionRenderer::renderEndFrame()
298 {
299 renderDistortion(pEyeTextures[0], pEyeTextures[1]);
301 // TODO: Add rendering context to callback.
302 if(RegisteredPostDistortionCallback)
303 RegisteredPostDistortionCallback(NULL);
305 if(LatencyTest2Active)
306 {
307 renderLatencyPixel(LatencyTest2DrawColor);
308 }
309 }
311 void DistortionRenderer::EndFrame(bool swapBuffers)
312 {
313 Context currContext;
314 currContext.InitFromCurrent();
315 #if defined(OVR_OS_MAC)
316 distortionContext.SetSurface( currContext );
317 #endif
319 // Don't spin if we are explicitly asked not to
320 if ((RState.DistortionCaps & ovrDistortionCap_TimeWarp) &&
321 !(RState.DistortionCaps & ovrDistortionCap_ProfileNoTimewarpSpinWaits))
322 {
323 if (!TimeManager.NeedDistortionTimeMeasurement())
324 {
325 // Wait for timewarp distortion if it is time and Gpu idle
326 FlushGpuAndWaitTillTime(TimeManager.GetFrameTiming().TimewarpPointTime);
328 distortionContext.Bind();
329 renderEndFrame();
330 }
331 else
332 {
333 // If needed, measure distortion time so that TimeManager can better estimate
334 // latency-reducing time-warp wait timing.
335 WaitUntilGpuIdle();
336 double distortionStartTime = ovr_GetTimeInSeconds();
338 distortionContext.Bind();
339 renderEndFrame();
341 WaitUntilGpuIdle();
342 TimeManager.AddDistortionTimeMeasurement(ovr_GetTimeInSeconds() - distortionStartTime);
343 }
344 }
345 else
346 {
347 distortionContext.Bind();
348 renderEndFrame();
349 }
351 if(LatencyTestActive)
352 {
353 renderLatencyQuad(LatencyTestDrawColor);
354 }
356 if (swapBuffers)
357 {
358 bool useVsync = ((RState.EnabledHmdCaps & ovrHmdCap_NoVSync) == 0);
359 int ourSwapInterval = (useVsync) ? 1 : 0;
360 int originalSwapInterval;
362 #if defined(OVR_OS_WIN32)
363 originalSwapInterval = wglGetSwapIntervalEXT();
365 if (ourSwapInterval != originalSwapInterval)
366 wglSwapIntervalEXT(ourSwapInterval);
368 HDC dc = (RParams.DC != NULL) ? RParams.DC : GetDC(RParams.Window);
369 BOOL success = SwapBuffers(dc);
370 OVR_ASSERT_AND_UNUSED(success, success);
372 if (RParams.DC == NULL)
373 ReleaseDC(RParams.Window, dc);
375 #elif defined(OVR_OS_MAC)
376 originalSwapInterval = 0;
377 CGLContextObj context = CGLGetCurrentContext();
378 CGLError err = CGLGetParameter(context, kCGLCPSwapInterval, &originalSwapInterval);
379 OVR_ASSERT_AND_UNUSED(err == kCGLNoError, err);
381 if (ourSwapInterval != originalSwapInterval)
382 CGLSetParameter(context, kCGLCPSwapInterval, &ourSwapInterval);
384 CGLFlushDrawable(context);
386 #elif defined(OVR_OS_LINUX)
387 originalSwapInterval = 0;
388 GLXDrawable drawable = glXGetCurrentDrawable();
389 struct _XDisplay* x11Display = RParams.Disp;
391 if(GLE_GLX_EXT_swap_control)
392 {
393 static_assert(sizeof(GLuint) == sizeof(originalSwapInterval), "size mismatch");
394 glXQueryDrawable(x11Display, drawable, GLX_SWAP_INTERVAL_EXT, (GLuint*)&originalSwapInterval);
396 if (ourSwapInterval != originalSwapInterval)
397 glXSwapIntervalEXT(x11Display, drawable, ourSwapInterval);
398 }
399 else if (GLE_MESA_swap_control) // There is also GLX_SGI_swap_control
400 {
401 originalSwapInterval = glXGetSwapIntervalMESA();
403 if (ourSwapInterval != originalSwapInterval)
404 glXSwapIntervalMESA(ourSwapInterval);
405 }
407 glXSwapBuffers(x11Display, drawable);
408 #endif
410 // Force GPU to flush the scene, resulting in the lowest possible latency.
411 // It's critical that this flush is *after* present, because it results in the wait
412 // below completing after the vsync.
413 // With the display driver (direct mode) this flush is obsolete and theoretically
414 // should be a no-op and so doesn't need to be done if running in direct mode.
415 if (RState.OurHMDInfo.InCompatibilityMode &&
416 !(RState.DistortionCaps & ovrDistortionCap_ProfileNoTimewarpSpinWaits))
417 WaitUntilGpuIdle();
419 // Restore the original swap interval if we changed it above.
420 if (originalSwapInterval != ourSwapInterval)
421 {
422 #if defined(OVR_OS_WIN32)
423 wglSwapIntervalEXT(originalSwapInterval);
424 #elif defined(OVR_OS_MAC)
425 CGLSetParameter(context, kCGLCPSwapInterval, &originalSwapInterval);
426 #elif defined(OVR_OS_LINUX)
427 if(GLE_GLX_EXT_swap_control)
428 glXSwapIntervalEXT(x11Display, drawable, (GLuint)originalSwapInterval);
429 else if(GLE_MESA_swap_control)
430 glXSwapIntervalMESA(originalSwapInterval);
431 #endif
432 }
433 }
435 currContext.Bind();
436 }
438 void DistortionRenderer::WaitUntilGpuIdle()
439 {
440 glFinish(); // Block until current OpenGL commands (including swap) are complete.
441 }
443 double DistortionRenderer::FlushGpuAndWaitTillTime(double absTime)
444 {
445 // because glFlush() is not strict enough certain GL drivers
446 // we do a glFinish(), but before doing so, we make sure we're not
447 // running late
448 double initialTime = ovr_GetTimeInSeconds();
449 if (initialTime >= absTime)
450 return 0.0;
452 glFinish();
454 return WaitTillTime(absTime);
455 }
457 void DistortionRenderer::initBuffersAndShaders()
458 {
459 for ( int eyeNum = 0; eyeNum < 2; eyeNum++ )
460 {
461 // Allocate & generate distortion mesh vertices.
462 ovrDistortionMesh meshData;
464 if (!ovrHmd_CreateDistortionMesh( HMD,
465 RState.EyeRenderDesc[eyeNum].Eye,
466 RState.EyeRenderDesc[eyeNum].Fov,
467 RState.DistortionCaps,
468 &meshData) )
469 {
470 OVR_ASSERT(false);
471 continue;
472 }
474 // Now parse the vertex data and create a render ready vertex buffer from it
475 DistortionVertex * pVBVerts = (DistortionVertex*)OVR_ALLOC ( sizeof(DistortionVertex) * meshData.VertexCount );
476 DistortionVertex * pCurVBVert = pVBVerts;
477 ovrDistortionVertex* pCurOvrVert = meshData.pVertexData;
479 for ( unsigned vertNum = 0; vertNum < meshData.VertexCount; vertNum++ )
480 {
481 pCurVBVert->ScreenPosNDC.x = pCurOvrVert->ScreenPosNDC.x;
482 pCurVBVert->ScreenPosNDC.y = pCurOvrVert->ScreenPosNDC.y;
484 if (RotateCCW90)
485 {
486 OVR::Alg::Swap(pCurVBVert->ScreenPosNDC.x, pCurVBVert->ScreenPosNDC.y);
487 pCurVBVert->ScreenPosNDC.x = -pCurVBVert->ScreenPosNDC.x;
488 }
490 // Previous code here did this: pCurVBVert->TanEyeAnglesR = (*(Vector2f*)&pCurOvrVert->TanEyeAnglesR); However that's an usafe
491 // cast of unrelated types which can result in undefined behavior by a conforming compiler. A safe equivalent is simply memcpy.
492 static_assert(sizeof(OVR::Vector2f) == sizeof(ovrVector2f), "Mismatch of structs that are presumed binary equivalents.");
493 memcpy(&pCurVBVert->TanEyeAnglesR, &pCurOvrVert->TanEyeAnglesR, sizeof(pCurVBVert->TanEyeAnglesR));
494 memcpy(&pCurVBVert->TanEyeAnglesG, &pCurOvrVert->TanEyeAnglesG, sizeof(pCurVBVert->TanEyeAnglesG));
495 memcpy(&pCurVBVert->TanEyeAnglesB, &pCurOvrVert->TanEyeAnglesB, sizeof(pCurVBVert->TanEyeAnglesB));
497 // Convert [0.0f,1.0f] to [0,255]
498 if (RState.DistortionCaps & ovrDistortionCap_Vignette)
499 {
500 if(RState.DistortionCaps & ovrDistortionCap_SRGB)
501 pCurOvrVert->VignetteFactor = pow(pCurOvrVert->VignetteFactor, 2.1f);
503 pCurVBVert->Col.R = (uint8_t)( Alg::Max ( pCurOvrVert->VignetteFactor, 0.0f ) * 255.99f );
504 }
505 else
506 pCurVBVert->Col.R = 255;
508 pCurVBVert->Col.G = pCurVBVert->Col.R;
509 pCurVBVert->Col.B = pCurVBVert->Col.R;
510 pCurVBVert->Col.A = (uint8_t)( pCurOvrVert->TimeWarpFactor * 255.99f );;
511 pCurOvrVert++;
512 pCurVBVert++;
513 }
515 DistortionMeshVBs[eyeNum] = *new Buffer(&RParams);
516 DistortionMeshVBs[eyeNum]->Data ( Buffer_Vertex | Buffer_ReadOnly, pVBVerts, sizeof(DistortionVertex) * meshData.VertexCount );
517 DistortionMeshIBs[eyeNum] = *new Buffer(&RParams);
518 DistortionMeshIBs[eyeNum]->Data ( Buffer_Index | Buffer_ReadOnly, meshData.pIndexData, ( sizeof(int16_t) * meshData.IndexCount ) );
520 OVR_FREE ( pVBVerts );
521 ovrHmd_DestroyDistortionMesh( &meshData );
522 }
524 initShaders();
525 }
527 void DistortionRenderer::renderDistortion(Texture* leftEyeTexture, Texture* rightEyeTexture)
528 {
529 bool overdriveActive = IsOverdriveActive();
530 int currOverdriveTextureIndex = -1;
532 if(overdriveActive)
533 {
534 currOverdriveTextureIndex = (LastUsedOverdriveTextureIndex + 1) % NumOverdriveTextures;
536 //glBindFramebuffer(GL_FRAMEBUFFER, 0);
537 glBindFramebuffer(GL_FRAMEBUFFER, OverdriveFbo );
539 GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
540 glDrawBuffers(OVR_ARRAY_COUNT(drawBuffers), drawBuffers);
542 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, pOverdriveTextures[currOverdriveTextureIndex]->TexId, 0);
543 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, OverdriveBackBufferTexture->TexId, 0);
544 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
545 OVR_ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
546 }
547 else
548 {
549 glBindFramebuffer(GL_FRAMEBUFFER, 0);
550 }
552 setViewport( Recti(0,0, RParams.BackBufferSize.w, RParams.BackBufferSize.h) );
554 if (RState.DistortionCaps & ovrDistortionCap_SRGB)
555 glEnable(GL_FRAMEBUFFER_SRGB);
556 else
557 glDisable(GL_FRAMEBUFFER_SRGB);
559 glDisable(GL_CULL_FACE);
560 glDisable(GL_DEPTH_TEST);
562 if (GLE_EXT_draw_buffers2)
563 {
564 glDisablei(GL_BLEND, 0);
565 glColorMaski(0, GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
566 }
567 else
568 {
569 glDisable(GL_BLEND);
570 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
571 }
573 glDisable(GL_DITHER);
574 glDisable(GL_RASTERIZER_DISCARD);
575 if (GLEContext::GetCurrentContext()->WholeVersion >= 302)
576 {
577 glDisable(GL_SAMPLE_MASK);
578 }
580 glClearColor(
581 RState.ClearColor[0],
582 RState.ClearColor[1],
583 RState.ClearColor[2],
584 RState.ClearColor[3] );
586 glClear(GL_COLOR_BUFFER_BIT);
588 for (int eyeNum = 0; eyeNum < 2; eyeNum++)
589 {
590 ShaderFill distortionShaderFill(DistortionShader);
591 distortionShaderFill.SetTexture(0, eyeNum == 0 ? leftEyeTexture : rightEyeTexture);
593 if(overdriveActive)
594 {
595 distortionShaderFill.SetTexture(1, pOverdriveTextures[LastUsedOverdriveTextureIndex]);
597 float overdriveScaleRegularRise;
598 float overdriveScaleRegularFall;
599 GetOverdriveScales(overdriveScaleRegularRise, overdriveScaleRegularFall);
600 DistortionShader->SetUniform3f("OverdriveScales_IsSrgb", overdriveScaleRegularRise, overdriveScaleRegularFall,
601 (RState.DistortionCaps & ovrDistortionCap_SRGB) ? 1.0f : -1.0f);
602 }
603 else
604 {
605 // -1.0f disables PLO
606 DistortionShader->SetUniform3f("OverdriveScales_IsSrgb", -1.0f, -1.0f, -1.0f);
607 }
609 DistortionShader->SetUniform2f("EyeToSourceUVScale", eachEye[eyeNum].UVScaleOffset[0].x, eachEye[eyeNum].UVScaleOffset[0].y);
610 // Convert Y to 1-Y as OpenGL is inverse of D3D
611 DistortionShader->SetUniform2f("EyeToSourceUVOffset", eachEye[eyeNum].UVScaleOffset[1].x, 1.0f - eachEye[eyeNum].UVScaleOffset[1].y);
613 if (RState.DistortionCaps & ovrDistortionCap_TimeWarp)
614 {
615 ovrMatrix4f timeWarpMatrices[2];
616 ovrHmd_GetEyeTimewarpMatrices(HMD, (ovrEyeType)eyeNum,
617 RState.EyeRenderPoses[eyeNum], timeWarpMatrices);
619 // Feed identity like matrices in until we get proper timewarp calculation going on
620 DistortionShader->SetUniform4x4f("EyeRotationStart", Matrix4f(timeWarpMatrices[0]).Transposed());
621 DistortionShader->SetUniform4x4f("EyeRotationEnd", Matrix4f(timeWarpMatrices[1]).Transposed());
623 renderPrimitives(&distortionShaderFill, DistortionMeshVBs[eyeNum], DistortionMeshIBs[eyeNum],
624 0, (int)DistortionMeshIBs[eyeNum]->GetSize()/2, Prim_Triangles, &DistortionMeshVAOs[eyeNum], true);
625 }
626 else
627 {
628 renderPrimitives(&distortionShaderFill, DistortionMeshVBs[eyeNum], DistortionMeshIBs[eyeNum],
629 0, (int)DistortionMeshIBs[eyeNum]->GetSize()/2, Prim_Triangles, &DistortionMeshVAOs[eyeNum], true);
630 }
631 }
633 LastUsedOverdriveTextureIndex = currOverdriveTextureIndex;
635 // Re-activate to only draw on back buffer
636 if(overdriveActive)
637 {
638 GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0};
639 glDrawBuffers(OVR_ARRAY_COUNT(drawBuffers), drawBuffers);
641 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
642 //glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
643 //glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, 0, 0);
644 OVR_ASSERT(glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
646 glBindFramebuffer( GL_READ_FRAMEBUFFER, OverdriveFbo );
647 glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, OverdriveBackBufferTexture->TexId, 0);
648 glFramebufferRenderbuffer(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
649 OVR_ASSERT(glCheckFramebufferStatus(GL_READ_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
651 glBlitFramebuffer( 0, 0, OverdriveBackBufferTexture->GetWidth(), OverdriveBackBufferTexture->GetHeight(),
652 0, 0, OverdriveBackBufferTexture->GetWidth(), OverdriveBackBufferTexture->GetHeight(),
653 GL_COLOR_BUFFER_BIT, GL_NEAREST );
655 glBindFramebuffer( GL_FRAMEBUFFER, 0 );
656 GLint err = glGetError();
657 OVR_ASSERT(!err); OVR_UNUSED(err);
658 }
659 }
662 void DistortionRenderer::createDrawQuad()
663 {
664 const int numQuadVerts = 4;
665 LatencyTesterQuadVB = *new Buffer(&RParams);
666 if(!LatencyTesterQuadVB)
667 {
668 return;
669 }
671 LatencyTesterQuadVB->Data(Buffer_Vertex, NULL, numQuadVerts * sizeof(LatencyVertex));
672 LatencyVertex* vertices = (LatencyVertex*)LatencyTesterQuadVB->Map(0, numQuadVerts * sizeof(LatencyVertex), Map_Discard);
673 if(!vertices)
674 {
675 OVR_ASSERT(false); // failed to lock vertex buffer
676 return;
677 }
679 const float left = -1.0f;
680 const float top = -1.0f;
681 const float right = 1.0f;
682 const float bottom = 1.0f;
684 vertices[0] = LatencyVertex(Vector3f(left, top, 0.0f));
685 vertices[1] = LatencyVertex(Vector3f(left, bottom, 0.0f));
686 vertices[2] = LatencyVertex(Vector3f(right, top, 0.0f));
687 vertices[3] = LatencyVertex(Vector3f(right, bottom, 0.0f));
689 LatencyTesterQuadVB->Unmap(vertices);
690 }
692 void DistortionRenderer::renderLatencyQuad(unsigned char* latencyTesterDrawColor)
693 {
694 const int numQuadVerts = 4;
696 if(!LatencyTesterQuadVB)
697 {
698 createDrawQuad();
699 }
701 Ptr<ShaderSet> quadShader = (RState.DistortionCaps & ovrDistortionCap_SRGB) ? SimpleQuadGammaShader : SimpleQuadShader;
702 ShaderFill quadFill(quadShader);
703 //quadFill.SetInputLayout(SimpleQuadVertexIL);
705 setViewport(Recti(0,0, RParams.BackBufferSize.w, RParams.BackBufferSize.h));
707 quadShader->SetUniform2f("Scale", 0.3f, 0.3f);
708 quadShader->SetUniform4f("Color", (float)latencyTesterDrawColor[0] / 255.99f,
709 (float)latencyTesterDrawColor[0] / 255.99f,
710 (float)latencyTesterDrawColor[0] / 255.99f,
711 1.0f);
713 for(int eyeNum = 0; eyeNum < 2; eyeNum++)
714 {
715 quadShader->SetUniform2f("PositionOffset", eyeNum == 0 ? -0.5f : 0.5f, 0.0f);
716 renderPrimitives(&quadFill, LatencyTesterQuadVB, NULL, 0, numQuadVerts, Prim_TriangleStrip, &LatencyVAO, false);
717 }
718 }
720 void DistortionRenderer::renderLatencyPixel(unsigned char* latencyTesterPixelColor)
721 {
722 const int numQuadVerts = 4;
724 if(!LatencyTesterQuadVB)
725 {
726 createDrawQuad();
727 }
729 Ptr<ShaderSet> quadShader = (RState.DistortionCaps & ovrDistortionCap_SRGB) ? SimpleQuadGammaShader : SimpleQuadShader;
730 ShaderFill quadFill(quadShader);
732 setViewport(Recti(0,0, RParams.BackBufferSize.w, RParams.BackBufferSize.h));
734 #ifdef OVR_BUILD_DEBUG
735 quadShader->SetUniform4f("Color", (float)latencyTesterPixelColor[0] / 255.99f,
736 (float)latencyTesterPixelColor[1] / 255.99f,
737 (float)latencyTesterPixelColor[2] / 255.99f,
738 1.0f);
740 Vector2f scale(20.0f / RParams.BackBufferSize.w, 20.0f / RParams.BackBufferSize.h);
741 #else
742 quadShader->SetUniform4f("Color", (float)latencyTesterPixelColor[0] / 255.99f,
743 (float)latencyTesterPixelColor[0] / 255.99f,
744 (float)latencyTesterPixelColor[0] / 255.99f,
745 1.0f);
747 Vector2f scale(1.0f / RParams.BackBufferSize.w, 1.0f / RParams.BackBufferSize.h);
748 #endif
749 quadShader->SetUniform2f("Scale", scale.x, scale.y);
750 if (!RotateCCW90)
751 quadShader->SetUniform2f("PositionOffset", 1.0f-scale.x, 1.0f-scale.y);
752 else
753 quadShader->SetUniform2f("PositionOffset", -(1.0f-scale.x), 1.0f-scale.y);
754 renderPrimitives(&quadFill, LatencyTesterQuadVB, NULL, 0, numQuadVerts, Prim_TriangleStrip, &LatencyVAO, false);
755 }
757 void DistortionRenderer::renderPrimitives(
758 const ShaderFill* fill,
759 Buffer* vertices, Buffer* indices,
760 int offset, int count,
761 PrimitiveType rprim, GLuint* vao, bool isDistortionMesh)
762 {
763 GLenum prim;
764 switch (rprim)
765 {
766 case Prim_Triangles:
767 prim = GL_TRIANGLES;
768 break;
769 case Prim_Lines:
770 prim = GL_LINES;
771 break;
772 case Prim_TriangleStrip:
773 prim = GL_TRIANGLE_STRIP;
774 break;
775 default:
776 OVR_ASSERT(false);
777 return;
778 }
780 fill->Set();
782 GLuint prog = fill->GetShaders()->Prog;
784 if (vao != NULL)
785 {
786 if (*vao != 0)
787 {
788 glBindVertexArray(*vao);
790 if (isDistortionMesh)
791 glDrawElements(prim, count, GL_UNSIGNED_SHORT, NULL);
792 else
793 glDrawArrays(prim, 0, count);
795 glBindVertexArray(0);
796 }
797 else
798 {
799 if (GL_ARB_vertex_array_object)
800 {
801 glGenVertexArrays(1, vao);
802 glBindVertexArray(*vao);
803 }
805 int attributeCount = (isDistortionMesh) ? 5 : 1;
806 int* locs = new int[attributeCount];
808 glBindBuffer(GL_ARRAY_BUFFER, ((Buffer*)vertices)->GLBuffer);
810 if (isDistortionMesh)
811 {
812 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ((Buffer*)indices)->GLBuffer);
814 locs[0] = glGetAttribLocation(prog, "Position");
815 locs[1] = glGetAttribLocation(prog, "Color");
816 locs[2] = glGetAttribLocation(prog, "TexCoord0");
817 locs[3] = glGetAttribLocation(prog, "TexCoord1");
818 locs[4] = glGetAttribLocation(prog, "TexCoord2");
820 glVertexAttribPointer(locs[0], 2, GL_FLOAT, false, sizeof(DistortionVertex), reinterpret_cast<char*>(offset)+offsetof(DistortionVertex, ScreenPosNDC));
821 glVertexAttribPointer(locs[1], 4, GL_UNSIGNED_BYTE, true, sizeof(DistortionVertex), reinterpret_cast<char*>(offset)+offsetof(DistortionVertex, Col));
822 glVertexAttribPointer(locs[2], 2, GL_FLOAT, false, sizeof(DistortionVertex), reinterpret_cast<char*>(offset)+offsetof(DistortionVertex, TanEyeAnglesR));
823 glVertexAttribPointer(locs[3], 2, GL_FLOAT, false, sizeof(DistortionVertex), reinterpret_cast<char*>(offset)+offsetof(DistortionVertex, TanEyeAnglesG));
824 glVertexAttribPointer(locs[4], 2, GL_FLOAT, false, sizeof(DistortionVertex), reinterpret_cast<char*>(offset)+offsetof(DistortionVertex, TanEyeAnglesB));
825 }
826 else
827 {
828 locs[0] = glGetAttribLocation(prog, "Position");
830 glVertexAttribPointer(locs[0], 3, GL_FLOAT, false, sizeof(LatencyVertex), reinterpret_cast<char*>(offset)+offsetof(LatencyVertex, Pos));
831 }
833 for (int i = 0; i < attributeCount; ++i)
834 glEnableVertexAttribArray(locs[i]);
836 if (isDistortionMesh)
837 glDrawElements(prim, count, GL_UNSIGNED_SHORT, NULL);
838 else
839 glDrawArrays(prim, 0, count);
842 if (!GL_ARB_vertex_array_object)
843 {
844 for (int i = 0; i < attributeCount; ++i)
845 glDisableVertexAttribArray(locs[i]);
846 }
848 delete[] locs;
850 if (GL_ARB_vertex_array_object)
851 {
852 glBindVertexArray(0);
853 }
854 }
855 }
856 }
858 void DistortionRenderer::setViewport(const Recti& vp)
859 {
860 glViewport(vp.x, vp.y, vp.w, vp.h);
861 }
864 void DistortionRenderer::initShaders()
865 {
866 const char* shaderPrefix = (GLEContext::GetCurrentContext()->WholeVersion >= 302) ? glsl3Prefix : glsl2Prefix;
868 {
869 ShaderInfo vsInfo = DistortionVertexShaderLookup[DistortionVertexShaderBitMask & RState.DistortionCaps];
871 size_t vsSize = strlen(shaderPrefix)+vsInfo.ShaderSize;
872 char* vsSource = new char[vsSize];
873 OVR_strcpy(vsSource, vsSize, shaderPrefix);
874 OVR_strcat(vsSource, vsSize, vsInfo.ShaderData);
876 Ptr<GL::VertexShader> vs = *new GL::VertexShader(
877 &RParams,
878 (void*)vsSource, vsSize,
879 vsInfo.ReflectionData, vsInfo.ReflectionSize);
881 DistortionShader = *new ShaderSet;
882 DistortionShader->SetShader(vs);
884 delete[](vsSource);
886 ShaderInfo psInfo = DistortionPixelShaderLookup[DistortionPixelShaderBitMask & RState.DistortionCaps];
888 size_t psSize = strlen(shaderPrefix)+psInfo.ShaderSize;
889 char* psSource = new char[psSize];
890 OVR_strcpy(psSource, psSize, shaderPrefix);
891 OVR_strcat(psSource, psSize, psInfo.ShaderData);
893 Ptr<GL::FragmentShader> ps = *new GL::FragmentShader(
894 &RParams,
895 (void*)psSource, psSize,
896 psInfo.ReflectionData, psInfo.ReflectionSize);
898 DistortionShader->SetShader(ps);
900 delete[](psSource);
901 }
902 {
903 size_t vsSize = strlen(shaderPrefix)+sizeof(SimpleQuad_vs);
904 char* vsSource = new char[vsSize];
905 OVR_strcpy(vsSource, vsSize, shaderPrefix);
906 OVR_strcat(vsSource, vsSize, SimpleQuad_vs);
908 Ptr<GL::VertexShader> vs = *new GL::VertexShader(
909 &RParams,
910 (void*)vsSource, vsSize,
911 SimpleQuad_vs_refl, sizeof(SimpleQuad_vs_refl) / sizeof(SimpleQuad_vs_refl[0]));
913 SimpleQuadShader = *new ShaderSet;
914 SimpleQuadShader->SetShader(vs);
916 delete[](vsSource);
918 size_t psSize = strlen(shaderPrefix)+sizeof(SimpleQuad_fs);
919 char* psSource = new char[psSize];
920 OVR_strcpy(psSource, psSize, shaderPrefix);
921 OVR_strcat(psSource, psSize, SimpleQuad_fs);
923 Ptr<GL::FragmentShader> ps = *new GL::FragmentShader(
924 &RParams,
925 (void*)psSource, psSize,
926 SimpleQuad_fs_refl, sizeof(SimpleQuad_fs_refl) / sizeof(SimpleQuad_fs_refl[0]));
928 SimpleQuadShader->SetShader(ps);
930 delete[](psSource);
931 }
932 {
933 size_t vsSize = strlen(shaderPrefix)+sizeof(SimpleQuad_vs);
934 char* vsSource = new char[vsSize];
935 OVR_strcpy(vsSource, vsSize, shaderPrefix);
936 OVR_strcat(vsSource, vsSize, SimpleQuad_vs);
938 Ptr<GL::VertexShader> vs = *new GL::VertexShader(
939 &RParams,
940 (void*)vsSource, vsSize,
941 SimpleQuad_vs_refl, sizeof(SimpleQuad_vs_refl) / sizeof(SimpleQuad_vs_refl[0]));
943 SimpleQuadGammaShader = *new ShaderSet;
944 SimpleQuadGammaShader->SetShader(vs);
946 delete[](vsSource);
948 size_t psSize = strlen(shaderPrefix)+sizeof(SimpleQuadGamma_fs);
949 char* psSource = new char[psSize];
950 OVR_strcpy(psSource, psSize, shaderPrefix);
951 OVR_strcat(psSource, psSize, SimpleQuadGamma_fs);
953 Ptr<GL::FragmentShader> ps = *new GL::FragmentShader(
954 &RParams,
955 (void*)psSource, psSize,
956 SimpleQuadGamma_fs_refl, sizeof(SimpleQuadGamma_fs_refl) / sizeof(SimpleQuadGamma_fs_refl[0]));
958 SimpleQuadGammaShader->SetShader(ps);
960 delete[](psSource);
961 }
962 }
965 void DistortionRenderer::destroy()
966 {
967 Context currContext;
968 currContext.InitFromCurrent();
970 distortionContext.Bind();
972 for(int eyeNum = 0; eyeNum < 2; eyeNum++)
973 {
974 if (GL_ARB_vertex_array_object)
975 {
976 glDeleteVertexArrays(1, &DistortionMeshVAOs[eyeNum]);
977 }
979 DistortionMeshVAOs[eyeNum] = 0;
981 DistortionMeshVBs[eyeNum].Clear();
982 DistortionMeshIBs[eyeNum].Clear();
983 }
985 if (DistortionShader)
986 {
987 DistortionShader->UnsetShader(Shader_Vertex);
988 DistortionShader->UnsetShader(Shader_Pixel);
989 DistortionShader.Clear();
990 }
992 LatencyTesterQuadVB.Clear();
994 if(LatencyVAO != 0)
995 {
996 glDeleteVertexArrays(1, &LatencyVAO);
997 LatencyVAO = 0;
998 }
1000 if(OverdriveFbo != 0)
1002 glDeleteFramebuffers(1, &OverdriveFbo);
1005 currContext.Bind();
1006 distortionContext.Destroy();
1007 // Who is responsible for destroying the app's context?
1011 }}} // OVR::CAPI::GL