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