OLD | NEW |
---|---|
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/android/vr_shell/vr_shell_gl.h" | 5 #include "chrome/browser/android/vr_shell/vr_shell_gl.h" |
6 | 6 |
7 #include <limits> | 7 #include <limits> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/android/jni_android.h" | 10 #include "base/android/jni_android.h" |
11 #include "base/callback_helpers.h" | 11 #include "base/callback_helpers.h" |
12 #include "base/memory/ptr_util.h" | 12 #include "base/memory/ptr_util.h" |
13 #include "base/metrics/histogram_macros.h" | 13 #include "base/metrics/histogram_macros.h" |
14 #include "base/threading/thread_task_runner_handle.h" | 14 #include "base/threading/thread_task_runner_handle.h" |
15 #include "chrome/browser/android/vr_shell/mailbox_to_surface_bridge.h" | |
15 #include "chrome/browser/android/vr_shell/ui_elements.h" | 16 #include "chrome/browser/android/vr_shell/ui_elements.h" |
16 #include "chrome/browser/android/vr_shell/ui_scene.h" | 17 #include "chrome/browser/android/vr_shell/ui_scene.h" |
17 #include "chrome/browser/android/vr_shell/vr_controller.h" | 18 #include "chrome/browser/android/vr_shell/vr_controller.h" |
18 #include "chrome/browser/android/vr_shell/vr_gl_util.h" | 19 #include "chrome/browser/android/vr_shell/vr_gl_util.h" |
19 #include "chrome/browser/android/vr_shell/vr_math.h" | 20 #include "chrome/browser/android/vr_shell/vr_math.h" |
20 #include "chrome/browser/android/vr_shell/vr_shell.h" | 21 #include "chrome/browser/android/vr_shell/vr_shell.h" |
21 #include "chrome/browser/android/vr_shell/vr_shell_delegate.h" | 22 #include "chrome/browser/android/vr_shell/vr_shell_delegate.h" |
22 #include "chrome/browser/android/vr_shell/vr_shell_renderer.h" | 23 #include "chrome/browser/android/vr_shell/vr_shell_renderer.h" |
23 #include "device/vr/android/gvr/gvr_device.h" | 24 #include "device/vr/android/gvr/gvr_device.h" |
24 #include "third_party/WebKit/public/platform/WebInputEvent.h" | 25 #include "third_party/WebKit/public/platform/WebInputEvent.h" |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
73 | 74 |
74 // The GVR viewport list has two entries (left eye and right eye) for each | 75 // The GVR viewport list has two entries (left eye and right eye) for each |
75 // GVR buffer. | 76 // GVR buffer. |
76 static constexpr int kViewportListPrimaryOffset = 0; | 77 static constexpr int kViewportListPrimaryOffset = 0; |
77 static constexpr int kViewportListHeadlockedOffset = 2; | 78 static constexpr int kViewportListHeadlockedOffset = 2; |
78 | 79 |
79 // Buffer size large enough to handle the current backlog of poses which is | 80 // Buffer size large enough to handle the current backlog of poses which is |
80 // 2-3 frames. | 81 // 2-3 frames. |
81 static constexpr unsigned kPoseRingBufferSize = 8; | 82 static constexpr unsigned kPoseRingBufferSize = 8; |
82 | 83 |
83 // Magic numbers used to mark valid pose index values encoded in frame | 84 // Default downscale factor for computing the recommended WebVR |
84 // data. Must match the magic numbers used in blink's VRDisplay.cpp. | 85 // renderWidth/Height from the 1:1 pixel mapped size. Using a rather |
85 static constexpr std::array<uint8_t, 2> kWebVrPosePixelMagicNumbers{{42, 142}}; | 86 // aggressive downscale due to the high overhead of copying pixels |
87 // twice before handing off to GVR. For comparison, the polyfill | |
88 // uses approximately 0.55 on a Pixel XL. | |
89 static constexpr float kWebVrRecommendedResolutionScale = 0.5; | |
86 | 90 |
87 float Distance(const gvr::Vec3f& vec1, const gvr::Vec3f& vec2) { | 91 float Distance(const gvr::Vec3f& vec1, const gvr::Vec3f& vec2) { |
88 float xdiff = (vec1.x - vec2.x); | 92 float xdiff = (vec1.x - vec2.x); |
89 float ydiff = (vec1.y - vec2.y); | 93 float ydiff = (vec1.y - vec2.y); |
90 float zdiff = (vec1.z - vec2.z); | 94 float zdiff = (vec1.z - vec2.z); |
91 float scale = xdiff * xdiff + ydiff * ydiff + zdiff * zdiff; | 95 float scale = xdiff * xdiff + ydiff * ydiff + zdiff * zdiff; |
92 return std::sqrt(scale); | 96 return std::sqrt(scale); |
93 } | 97 } |
94 | 98 |
95 // Generate a quaternion representing the rotation from the negative Z axis | 99 // Generate a quaternion representing the rotation from the negative Z axis |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
165 binding_(this), | 169 binding_(this), |
166 weak_vr_shell_(weak_vr_shell), | 170 weak_vr_shell_(weak_vr_shell), |
167 delegate_provider_(delegate_provider), | 171 delegate_provider_(delegate_provider), |
168 main_thread_task_runner_(std::move(main_thread_task_runner)), | 172 main_thread_task_runner_(std::move(main_thread_task_runner)), |
169 weak_ptr_factory_(this) { | 173 weak_ptr_factory_(this) { |
170 GvrInit(gvr_api); | 174 GvrInit(gvr_api); |
171 } | 175 } |
172 | 176 |
173 VrShellGl::~VrShellGl() { | 177 VrShellGl::~VrShellGl() { |
174 vsync_task_.Cancel(); | 178 vsync_task_.Cancel(); |
179 binding_.Close(); | |
dcheng
2017/03/08 07:23:39
Please add a comment why it's necessary to explici
klausw
2017/03/08 08:11:09
Does the comment below the next line make it clear
mthiesse
2017/03/08 13:44:48
I wrote this - my concern was that it might be pos
klausw
2017/03/08 16:58:51
Added as a comment. Just to clarify, mthiesse@ con
dcheng
2017/03/08 23:08:05
OK, thanks. In the case of non-sync calls (which i
| |
175 if (!callback_.is_null()) { | 180 if (!callback_.is_null()) { |
176 // When this VSync provider is going away we have to respond to pending | 181 // When this VSync provider is going away we have to respond to pending |
177 // callbacks, so instead of providing a VSync, tell the requester to try | 182 // callbacks, so instead of providing a VSync, tell the requester to try |
178 // again. A VSyncProvider is guaranteed to exist, so the request in response | 183 // again. A VSyncProvider is guaranteed to exist, so the request in response |
179 // to this message will go through some other VSyncProvider. | 184 // to this message will go through some other VSyncProvider. |
180 base::ResetAndReturn(&callback_) | 185 base::ResetAndReturn(&callback_) |
181 .Run(nullptr, base::TimeDelta(), -1, | 186 .Run(nullptr, base::TimeDelta(), -1, |
182 device::mojom::VRVSyncProvider::Status::RETRY); | 187 device::mojom::VRVSyncProvider::Status::CLOSING); |
183 } | |
184 if (binding_.is_bound()) { | |
185 main_thread_task_runner_->PostTask( | |
186 FROM_HERE, | |
187 base::Bind(&VrShellDelegate::OnVRVsyncProviderRequest, | |
188 delegate_provider_, base::Passed(binding_.Unbind()))); | |
189 } | 188 } |
190 } | 189 } |
191 | 190 |
192 void VrShellGl::Initialize() { | 191 void VrShellGl::Initialize() { |
193 scene_.reset(new UiScene); | 192 scene_.reset(new UiScene); |
194 | 193 |
195 if (surfaceless_rendering_) { | 194 if (surfaceless_rendering_) { |
196 // If we're rendering surfaceless, we'll never get a java surface to render | 195 // If we're rendering surfaceless, we'll never get a java surface to render |
197 // into, so we can initialize GL right away. | 196 // into, so we can initialize GL right away. |
198 InitializeGl(nullptr); | 197 InitializeGl(nullptr); |
(...skipping 26 matching lines...) Expand all Loading... | |
225 LOG(ERROR) << "gl::init::CreateGLContext failed"; | 224 LOG(ERROR) << "gl::init::CreateGLContext failed"; |
226 ForceExitVr(); | 225 ForceExitVr(); |
227 return; | 226 return; |
228 } | 227 } |
229 if (!context_->MakeCurrent(surface_.get())) { | 228 if (!context_->MakeCurrent(surface_.get())) { |
230 LOG(ERROR) << "gl::GLContext::MakeCurrent() failed"; | 229 LOG(ERROR) << "gl::GLContext::MakeCurrent() failed"; |
231 ForceExitVr(); | 230 ForceExitVr(); |
232 return; | 231 return; |
233 } | 232 } |
234 | 233 |
235 unsigned int textures[2]; | 234 unsigned int textures[3]; |
236 glGenTextures(2, textures); | 235 glGenTextures(3, textures); |
237 ui_texture_id_ = textures[0]; | 236 ui_texture_id_ = textures[0]; |
238 content_texture_id_ = textures[1]; | 237 content_texture_id_ = textures[1]; |
238 webvr_texture_id_ = textures[2]; | |
239 ui_surface_texture_ = gl::SurfaceTexture::Create(ui_texture_id_); | 239 ui_surface_texture_ = gl::SurfaceTexture::Create(ui_texture_id_); |
240 content_surface_texture_ = gl::SurfaceTexture::Create(content_texture_id_); | 240 content_surface_texture_ = gl::SurfaceTexture::Create(content_texture_id_); |
241 webvr_surface_texture_ = gl::SurfaceTexture::Create(webvr_texture_id_); | |
241 CreateUiSurface(); | 242 CreateUiSurface(); |
242 CreateContentSurface(); | 243 CreateContentSurface(); |
243 ui_surface_texture_->SetFrameAvailableCallback(base::Bind( | 244 ui_surface_texture_->SetFrameAvailableCallback(base::Bind( |
244 &VrShellGl::OnUIFrameAvailable, weak_ptr_factory_.GetWeakPtr())); | 245 &VrShellGl::OnUIFrameAvailable, weak_ptr_factory_.GetWeakPtr())); |
245 content_surface_texture_->SetFrameAvailableCallback(base::Bind( | 246 content_surface_texture_->SetFrameAvailableCallback(base::Bind( |
246 &VrShellGl::OnContentFrameAvailable, weak_ptr_factory_.GetWeakPtr())); | 247 &VrShellGl::OnContentFrameAvailable, weak_ptr_factory_.GetWeakPtr())); |
248 webvr_surface_texture_->SetFrameAvailableCallback(base::Bind( | |
249 &VrShellGl::OnWebVRFrameAvailable, weak_ptr_factory_.GetWeakPtr())); | |
250 ui_surface_texture_->SetDefaultBufferSize(ui_tex_physical_size_.width, | |
251 ui_tex_physical_size_.height); | |
247 content_surface_texture_->SetDefaultBufferSize( | 252 content_surface_texture_->SetDefaultBufferSize( |
248 content_tex_physical_size_.width, content_tex_physical_size_.height); | 253 content_tex_physical_size_.width, content_tex_physical_size_.height); |
249 ui_surface_texture_->SetDefaultBufferSize(ui_tex_physical_size_.width, | |
250 ui_tex_physical_size_.height); | |
251 InitializeRenderer(); | 254 InitializeRenderer(); |
252 | 255 |
256 // Pick a reasonable default size for the WebVR transfer surface | |
257 // based on a downscaled 1:1 render resolution. This size will also | |
258 // be reported to the client via CreateVRDisplayInfo as the | |
259 // client-recommended renderWidth/renderHeight and for the GVR | |
260 // framebuffer. If the client chooses a different size or resizes it | |
261 // while presenting, we'll resize the transfer surface and GVR | |
262 // framebuffer to match. | |
263 auto render_target_size = gvr_api_->GetMaximumEffectiveRenderTargetSize(); | |
dcheng
2017/03/08 07:23:39
Can this be explicitly typed?
klausw
2017/03/08 08:11:09
Done.
| |
264 gvr::Sizei webvr_size = {static_cast<int>(render_target_size.width * | |
265 kWebVrRecommendedResolutionScale), | |
266 static_cast<int>(render_target_size.height * | |
267 kWebVrRecommendedResolutionScale)}; | |
268 | |
269 // TODO(klausw,crbug.com/699350): should we round the recommended | |
270 // size to a multiple of 2^N pixels to be friendlier to the GPU? The | |
271 // exact size doesn't matter. | |
272 | |
273 CreateOrResizeWebVRSurface(webvr_size); | |
274 | |
253 vsync_task_.Reset(base::Bind(&VrShellGl::OnVSync, base::Unretained(this))); | 275 vsync_task_.Reset(base::Bind(&VrShellGl::OnVSync, base::Unretained(this))); |
254 OnVSync(); | 276 OnVSync(); |
255 | 277 |
256 ready_to_draw_ = true; | 278 ready_to_draw_ = true; |
257 } | 279 } |
258 | 280 |
259 void VrShellGl::CreateContentSurface() { | 281 void VrShellGl::CreateContentSurface() { |
260 content_surface_ = | 282 content_surface_ = |
261 base::MakeUnique<gl::ScopedJavaSurface>(content_surface_texture_.get()); | 283 base::MakeUnique<gl::ScopedJavaSurface>(content_surface_texture_.get()); |
262 main_thread_task_runner_->PostTask( | 284 main_thread_task_runner_->PostTask( |
263 FROM_HERE, base::Bind(&VrShell::ContentSurfaceChanged, weak_vr_shell_, | 285 FROM_HERE, base::Bind(&VrShell::ContentSurfaceChanged, weak_vr_shell_, |
264 content_surface_->j_surface().obj())); | 286 content_surface_->j_surface().obj())); |
265 } | 287 } |
266 | 288 |
267 void VrShellGl::CreateUiSurface() { | 289 void VrShellGl::CreateUiSurface() { |
268 ui_surface_ = | 290 ui_surface_ = |
269 base::MakeUnique<gl::ScopedJavaSurface>(ui_surface_texture_.get()); | 291 base::MakeUnique<gl::ScopedJavaSurface>(ui_surface_texture_.get()); |
270 main_thread_task_runner_->PostTask( | 292 main_thread_task_runner_->PostTask( |
271 FROM_HERE, base::Bind(&VrShell::UiSurfaceChanged, weak_vr_shell_, | 293 FROM_HERE, base::Bind(&VrShell::UiSurfaceChanged, weak_vr_shell_, |
272 ui_surface_->j_surface().obj())); | 294 ui_surface_->j_surface().obj())); |
273 } | 295 } |
274 | 296 |
297 void VrShellGl::CreateOrResizeWebVRSurface(const gvr::Sizei& size) { | |
298 if (!webvr_surface_texture_) { | |
299 DLOG(ERROR) << "No WebVR surface texture available"; | |
300 return; | |
301 } | |
302 | |
303 // ContentPhysicalBoundsChanged is getting called twice with | |
304 // identical sizes? Avoid thrashing the existing context. | |
305 if (size == webvr_surface_size_) { | |
306 return; | |
307 } | |
308 | |
309 if (!size.width || !size.height) { | |
310 // Invalid size, defer until a new size arrives on a future bounds update. | |
311 return; | |
312 } | |
313 | |
314 webvr_surface_texture_->SetDefaultBufferSize(size.width, size.height); | |
315 webvr_surface_size_ = size; | |
316 | |
317 if (mailbox_bridge_) { | |
318 mailbox_bridge_->ResizeSurface(size.width, size.height); | |
319 } else { | |
320 mailbox_bridge_ = base::MakeUnique<MailboxToSurfaceBridge>(); | |
321 mailbox_bridge_->CreateSurface(webvr_surface_texture_); | |
322 } | |
323 } | |
324 | |
325 void VrShellGl::SubmitWebVRFrame(int16_t frame_index, | |
326 const gpu::MailboxHolder& mailbox) { | |
327 TRACE_EVENT0("gpu", "VrShellGl::SubmitWebVRFrame"); | |
328 | |
329 // Swapping twice on a Surface without calling updateTexImage in | |
330 // between can lose frames, so don't draw+swap if we already have | |
331 // a pending frame we haven't consumed yet. | |
332 bool swapped = false; | |
333 if (pending_frames_.empty()) { | |
334 swapped = mailbox_bridge_->CopyMailboxToSurfaceAndSwap(mailbox); | |
335 if (swapped) { | |
336 // Tell OnWebVRFrameAvailable to expect a new frame to arrive on | |
337 // the SurfaceTexture, and save the associated frame index. | |
338 pending_frames_.emplace(frame_index); | |
339 } | |
340 } | |
341 // Always notify the client that we're done with the mailbox even | |
342 // if we haven't drawn it, so that it's eligible for destruction. | |
343 submit_client_->OnSubmitFrameTransferred(); | |
344 if (!swapped) { | |
345 // We dropped without drawing, report this as completed rendering | |
346 // now to unblock the client. We're not going to receive it in | |
347 // OnWebVRFrameAvailable where we'd normally report that. | |
348 submit_client_->OnSubmitFrameRendered(); | |
349 } | |
350 | |
351 TRACE_EVENT0("gpu", "VrShellGl::glFinish"); | |
352 // This is a load-bearing glFinish, please don't remove it without | |
353 // before/after timing comparisons. Goal is to clear the GPU queue | |
354 // of the native GL context to avoid stalls later in GVR frame | |
355 // acquire/submit. | |
356 glFinish(); | |
357 } | |
358 | |
359 void VrShellGl::SetSubmitClient( | |
360 device::mojom::VRSubmitFrameClientPtrInfo submit_client_info) { | |
361 submit_client_.Bind(std::move(submit_client_info)); | |
362 } | |
363 | |
275 void VrShellGl::OnUIFrameAvailable() { | 364 void VrShellGl::OnUIFrameAvailable() { |
276 ui_surface_texture_->UpdateTexImage(); | 365 ui_surface_texture_->UpdateTexImage(); |
277 } | 366 } |
278 | 367 |
279 void VrShellGl::OnContentFrameAvailable() { | 368 void VrShellGl::OnContentFrameAvailable() { |
280 content_surface_texture_->UpdateTexImage(); | 369 content_surface_texture_->UpdateTexImage(); |
281 received_frame_ = true; | 370 received_frame_ = true; |
282 } | 371 } |
283 | 372 |
284 bool VrShellGl::GetPixelEncodedFrameIndex(uint16_t* frame_index) { | 373 void VrShellGl::OnWebVRFrameAvailable() { |
285 TRACE_EVENT0("gpu", "VrShellGl::GetPixelEncodedFrameIndex"); | 374 // A "while" loop here is a bad idea. It's legal to call |
286 if (!received_frame_) { | 375 // UpdateTexImage repeatedly even if no frames are available, but |
287 if (last_frame_index_ == (uint16_t)-1) | 376 // that does *not* wait for a new frame, it just reuses the most |
288 return false; | 377 // recent one. That would mess up the count. |
289 *frame_index = last_frame_index_; | 378 if (pending_frames_.empty()) { |
290 return true; | 379 // We're expecting a frame, but it's not here yet. Retry in OnVsync. |
380 ++premature_received_frames_; | |
381 return; | |
291 } | 382 } |
292 received_frame_ = false; | |
293 | 383 |
294 // Read the pose index encoded in a bottom left pixel as color values. | 384 webvr_surface_texture_->UpdateTexImage(); |
295 // See also third_party/WebKit/Source/modules/vr/VRDisplay.cpp which | 385 int frame_index = pending_frames_.front(); |
296 // encodes the pose index, and device/vr/android/gvr/gvr_device.cc | 386 TRACE_EVENT1("gpu", "VrShellGl::OnWebVRFrameAvailable", "frame", frame_index); |
297 // which tracks poses. Returns the low byte (0..255) if valid, or -1 | 387 pending_frames_.pop(); |
298 // if not valid due to bad magic number. | |
299 uint8_t pixels[4]; | |
300 // Assume we're reading from the framebuffer we just wrote to. | |
301 // That's true currently, we may need to use glReadBuffer(GL_BACK) | |
302 // or equivalent if the rendering setup changes in the future. | |
303 glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels); | |
304 | 388 |
305 // Check for the magic number written by VRDevice.cpp on submit. | 389 // It is legal for the WebVR client to submit a new frame now, since |
306 // This helps avoid glitches from garbage data in the render | 390 // we've consumed the image. TODO(klausw): would timing be better if |
307 // buffer that can appear during initialization or resizing. These | 391 // we move the "rendered" notification after draw, or suppress |
308 // often appear as flashes of all-black or all-white pixels. | 392 // the next vsync until that's done? |
309 if (pixels[1] == kWebVrPosePixelMagicNumbers[0] && | 393 |
310 pixels[2] == kWebVrPosePixelMagicNumbers[1]) { | 394 submit_client_->OnSubmitFrameRendered(); |
311 // Pose is good. | 395 |
312 *frame_index = pixels[0]; | 396 DrawFrame(frame_index); |
313 last_frame_index_ = pixels[0]; | |
314 return true; | |
315 } | |
316 VLOG(1) << "WebVR: reject decoded pose index " << static_cast<int>(pixels[0]) | |
317 << ", bad magic number " << static_cast<int>(pixels[1]) << ", " | |
318 << static_cast<int>(pixels[2]); | |
319 return false; | |
320 } | 397 } |
321 | 398 |
322 void VrShellGl::GvrInit(gvr_context* gvr_api) { | 399 void VrShellGl::GvrInit(gvr_context* gvr_api) { |
323 gvr_api_ = gvr::GvrApi::WrapNonOwned(gvr_api); | 400 gvr_api_ = gvr::GvrApi::WrapNonOwned(gvr_api); |
324 controller_.reset(new VrController(gvr_api)); | 401 controller_.reset(new VrController(gvr_api)); |
325 | 402 |
326 ViewerType viewerType; | 403 ViewerType viewerType; |
327 switch (gvr_api_->GetViewerType()) { | 404 switch (gvr_api_->GetViewerType()) { |
328 case gvr::ViewerType::GVR_VIEWER_TYPE_DAYDREAM: | 405 case gvr::ViewerType::GVR_VIEWER_TYPE_DAYDREAM: |
329 viewerType = ViewerType::DAYDREAM; | 406 viewerType = ViewerType::DAYDREAM; |
330 break; | 407 break; |
331 case gvr::ViewerType::GVR_VIEWER_TYPE_CARDBOARD: | 408 case gvr::ViewerType::GVR_VIEWER_TYPE_CARDBOARD: |
332 viewerType = ViewerType::CARDBOARD; | 409 viewerType = ViewerType::CARDBOARD; |
333 break; | 410 break; |
334 default: | 411 default: |
335 NOTREACHED(); | 412 NOTREACHED(); |
336 viewerType = ViewerType::UNKNOWN_TYPE; | 413 viewerType = ViewerType::UNKNOWN_TYPE; |
337 break; | 414 break; |
338 } | 415 } |
339 UMA_HISTOGRAM_ENUMERATION("VRViewerType", static_cast<int>(viewerType), | 416 UMA_HISTOGRAM_ENUMERATION("VRViewerType", static_cast<int>(viewerType), |
340 static_cast<int>(ViewerType::VIEWER_TYPE_MAX)); | 417 static_cast<int>(ViewerType::VIEWER_TYPE_MAX)); |
341 } | 418 } |
342 | 419 |
343 void VrShellGl::InitializeRenderer() { | 420 void VrShellGl::InitializeRenderer() { |
344 // While WebVR is going through the compositor path, it shares | |
345 // the same texture ID. This will change once it gets its own | |
346 // surface, but store it separately to avoid future confusion. | |
347 // TODO(klausw,crbug.com/655722): remove this. | |
348 webvr_texture_id_ = content_texture_id_; | |
349 | |
350 gvr_api_->InitializeGl(); | 421 gvr_api_->InitializeGl(); |
351 webvr_head_pose_.assign(kPoseRingBufferSize, | 422 webvr_head_pose_.assign(kPoseRingBufferSize, |
352 gvr_api_->GetHeadSpaceFromStartSpaceRotation( | 423 gvr_api_->GetHeadSpaceFromStartSpaceRotation( |
353 gvr::GvrApi::GetTimePointNow())); | 424 gvr::GvrApi::GetTimePointNow())); |
354 | 425 |
355 std::vector<gvr::BufferSpec> specs; | 426 std::vector<gvr::BufferSpec> specs; |
356 // For kFramePrimaryBuffer (primary VrShell and WebVR content) | 427 // For kFramePrimaryBuffer (primary VrShell and WebVR content) |
357 specs.push_back(gvr_api_->CreateBufferSpec()); | 428 specs.push_back(gvr_api_->CreateBufferSpec()); |
358 render_size_primary_ = specs[kFramePrimaryBuffer].GetSize(); | 429 render_size_primary_ = specs[kFramePrimaryBuffer].GetSize(); |
430 render_size_vrshell_ = render_size_primary_; | |
359 | 431 |
360 // For kFrameHeadlockedBuffer (for WebVR insecure content warning). | 432 // For kFrameHeadlockedBuffer (for WebVR insecure content warning). |
361 // Set this up at fixed resolution, the (smaller) FOV gets set below. | 433 // Set this up at fixed resolution, the (smaller) FOV gets set below. |
362 specs.push_back(gvr_api_->CreateBufferSpec()); | 434 specs.push_back(gvr_api_->CreateBufferSpec()); |
363 specs.back().SetSize(kHeadlockedBufferDimensions); | 435 specs.back().SetSize(kHeadlockedBufferDimensions); |
364 render_size_headlocked_ = specs[kFrameHeadlockedBuffer].GetSize(); | 436 render_size_headlocked_ = specs[kFrameHeadlockedBuffer].GetSize(); |
365 | 437 |
366 swap_chain_.reset(new gvr::SwapChain(gvr_api_->CreateSwapChain(specs))); | 438 swap_chain_.reset(new gvr::SwapChain(gvr_api_->CreateSwapChain(specs))); |
367 | 439 |
368 vr_shell_renderer_.reset(new VrShellRenderer()); | 440 vr_shell_renderer_.reset(new VrShellRenderer()); |
(...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
625 std::unique_ptr<blink::WebInputEvent> event) { | 697 std::unique_ptr<blink::WebInputEvent> event) { |
626 DCHECK(input_target != InputTarget::NONE); | 698 DCHECK(input_target != InputTarget::NONE); |
627 auto&& target = input_target == InputTarget::CONTENT | 699 auto&& target = input_target == InputTarget::CONTENT |
628 ? &VrShell::ProcessContentGesture | 700 ? &VrShell::ProcessContentGesture |
629 : &VrShell::ProcessUIGesture; | 701 : &VrShell::ProcessUIGesture; |
630 main_thread_task_runner_->PostTask( | 702 main_thread_task_runner_->PostTask( |
631 FROM_HERE, | 703 FROM_HERE, |
632 base::Bind(target, weak_vr_shell_, base::Passed(std::move(event)))); | 704 base::Bind(target, weak_vr_shell_, base::Passed(std::move(event)))); |
633 } | 705 } |
634 | 706 |
635 void VrShellGl::DrawFrame() { | 707 void VrShellGl::DrawFrame(int frame_index) { |
dcheng
2017/03/08 07:23:39
int16_t to match the other frame_index type?
klausw
2017/03/08 08:11:09
Done.
| |
636 TRACE_EVENT0("gpu", "VrShellGl::DrawFrame"); | 708 TRACE_EVENT1("gpu", "VrShellGl::DrawFrame", "frame", frame_index); |
637 | 709 |
638 // Reset the viewport list to just the pair of viewports for the | 710 // Reset the viewport list to just the pair of viewports for the |
639 // primary buffer each frame. Head-locked viewports get added by | 711 // primary buffer each frame. Head-locked viewports get added by |
640 // DrawVrShell if needed. | 712 // DrawVrShell if needed. |
641 buffer_viewport_list_->SetToRecommendedBufferViewports(); | 713 buffer_viewport_list_->SetToRecommendedBufferViewports(); |
642 | 714 |
715 // If needed, resize the primary buffer for use with WebVR. | |
716 if (web_vr_mode_) { | |
717 if (render_size_primary_ != webvr_surface_size_) { | |
718 if (!webvr_surface_size_.width) { | |
719 return; | |
720 } | |
721 render_size_primary_ = webvr_surface_size_; | |
722 swap_chain_->ResizeBuffer(kFramePrimaryBuffer, render_size_primary_); | |
723 } | |
724 } else { | |
725 if (render_size_primary_ != render_size_vrshell_) { | |
726 render_size_primary_ = render_size_vrshell_; | |
727 swap_chain_->ResizeBuffer(kFramePrimaryBuffer, render_size_primary_); | |
728 } | |
729 } | |
730 | |
731 TRACE_EVENT_BEGIN0("gpu", "VrShellGl::AcquireFrame"); | |
643 gvr::Frame frame = swap_chain_->AcquireFrame(); | 732 gvr::Frame frame = swap_chain_->AcquireFrame(); |
733 TRACE_EVENT_END0("gpu", "VrShellGl::AcquireFrame"); | |
644 if (!frame.is_valid()) { | 734 if (!frame.is_valid()) { |
645 return; | 735 return; |
646 } | 736 } |
647 frame.BindBuffer(kFramePrimaryBuffer); | 737 frame.BindBuffer(kFramePrimaryBuffer); |
648 if (web_vr_mode_) { | 738 if (web_vr_mode_) { |
649 DrawWebVr(); | 739 DrawWebVr(); |
650 } | 740 } |
651 | 741 |
652 uint16_t frame_index; | |
653 gvr::Mat4f head_pose; | 742 gvr::Mat4f head_pose; |
654 | 743 |
655 // When using async reprojection, we need to know which pose was used in | 744 // When using async reprojection, we need to know which pose was used in |
656 // the WebVR app for drawing this frame. Due to unknown amounts of | 745 // the WebVR app for drawing this frame. Only needed if reprojection is |
657 // buffering in the compositor and SurfaceTexture, we read the pose number | 746 // in use. |
658 // from a corner pixel. There's no point in doing this for legacy | 747 if (web_vr_mode_ && gvr_api_->GetAsyncReprojectionEnabled()) { |
659 // distortion rendering since that doesn't need a pose, and reading back | |
660 // pixels is an expensive operation. TODO(klausw,crbug.com/655722): stop | |
661 // doing this once we have working no-compositor rendering for WebVR. | |
662 if (web_vr_mode_ && gvr_api_->GetAsyncReprojectionEnabled() && | |
663 GetPixelEncodedFrameIndex(&frame_index)) { | |
664 static_assert(!((kPoseRingBufferSize - 1) & kPoseRingBufferSize), | 748 static_assert(!((kPoseRingBufferSize - 1) & kPoseRingBufferSize), |
665 "kPoseRingBufferSize must be a power of 2"); | 749 "kPoseRingBufferSize must be a power of 2"); |
666 head_pose = webvr_head_pose_[frame_index % kPoseRingBufferSize]; | 750 head_pose = webvr_head_pose_[frame_index % kPoseRingBufferSize]; |
667 // Process all pending_bounds_ changes targeted for before this frame, being | 751 // Process all pending_bounds_ changes targeted for before this frame, being |
668 // careful of wrapping frame indices. | 752 // careful of wrapping frame indices. |
669 static constexpr unsigned max = | 753 static constexpr unsigned max = |
670 std::numeric_limits<decltype(frame_index_)>::max(); | 754 std::numeric_limits<decltype(frame_index_)>::max(); |
671 static_assert(max > kPoseRingBufferSize * 2, | 755 static_assert(max > kPoseRingBufferSize * 2, |
672 "To detect wrapping, kPoseRingBufferSize must be smaller " | 756 "To detect wrapping, kPoseRingBufferSize must be smaller " |
673 "than half of frame_index_ range."); | 757 "than half of frame_index_ range."); |
674 while (!pending_bounds_.empty()) { | 758 while (!pending_bounds_.empty()) { |
675 uint16_t index = pending_bounds_.front().first; | 759 uint16_t index = pending_bounds_.front().first; |
676 // If index is less than the frame_index it's possible we've wrapped, so | 760 // If index is less than the frame_index it's possible we've wrapped, so |
677 // we extend the range and 'un-wrap' to account for this. | 761 // we extend the range and 'un-wrap' to account for this. |
678 if (index < frame_index) | 762 if (index < frame_index) |
679 index += max; | 763 index += max; |
680 // If the pending bounds change is for an upcoming frame within our buffer | 764 // If the pending bounds change is for an upcoming frame within our buffer |
681 // size, wait to apply it. Otherwise, apply it immediately. This | 765 // size, wait to apply it. Otherwise, apply it immediately. This |
682 // guarantees that even if we miss many frames, the queue can't fill up | 766 // guarantees that even if we miss many frames, the queue can't fill up |
683 // with stale bounds. | 767 // with stale bounds. |
684 if (index > frame_index && index <= frame_index + kPoseRingBufferSize) | 768 if (index > frame_index && index <= frame_index + kPoseRingBufferSize) |
685 break; | 769 break; |
686 | 770 |
687 const BoundsPair& bounds = pending_bounds_.front().second; | 771 const WebVrBounds& bounds = pending_bounds_.front().second; |
688 webvr_left_viewport_->SetSourceUv(bounds.first); | 772 webvr_left_viewport_->SetSourceUv(bounds.left_bounds); |
689 webvr_right_viewport_->SetSourceUv(bounds.second); | 773 webvr_right_viewport_->SetSourceUv(bounds.right_bounds); |
774 CreateOrResizeWebVRSurface(bounds.source_size); | |
690 pending_bounds_.pop(); | 775 pending_bounds_.pop(); |
691 } | 776 } |
692 buffer_viewport_list_->SetBufferViewport(GVR_LEFT_EYE, | 777 buffer_viewport_list_->SetBufferViewport(GVR_LEFT_EYE, |
693 *webvr_left_viewport_); | 778 *webvr_left_viewport_); |
694 buffer_viewport_list_->SetBufferViewport(GVR_RIGHT_EYE, | 779 buffer_viewport_list_->SetBufferViewport(GVR_RIGHT_EYE, |
695 *webvr_right_viewport_); | 780 *webvr_right_viewport_); |
696 } else { | 781 } else { |
697 gvr::ClockTimePoint target_time = gvr::GvrApi::GetTimePointNow(); | 782 gvr::ClockTimePoint target_time = gvr::GvrApi::GetTimePointNow(); |
698 target_time.monotonic_system_time_nanos += kPredictionTimeWithoutVsyncNanos; | 783 target_time.monotonic_system_time_nanos += kPredictionTimeWithoutVsyncNanos; |
699 head_pose = gvr_api_->GetHeadSpaceFromStartSpaceRotation(target_time); | 784 head_pose = gvr_api_->GetHeadSpaceFromStartSpaceRotation(target_time); |
700 } | 785 } |
701 | 786 |
702 gvr::Vec3f position = GetTranslation(head_pose); | 787 gvr::Vec3f position = GetTranslation(head_pose); |
703 if (position.x == 0.0f && position.y == 0.0f && position.z == 0.0f) { | 788 if (position.x == 0.0f && position.y == 0.0f && position.z == 0.0f) { |
704 // This appears to be a 3DOF pose without a neck model. Add one. | 789 // This appears to be a 3DOF pose without a neck model. Add one. |
705 // The head pose has redundant data. Assume we're only using the | 790 // The head pose has redundant data. Assume we're only using the |
706 // object_from_reference_matrix, we're not updating position_external. | 791 // object_from_reference_matrix, we're not updating position_external. |
707 // TODO: Not sure what object_from_reference_matrix is. The new api removed | 792 // TODO: Not sure what object_from_reference_matrix is. The new api removed |
708 // it. For now, removing it seems working fine. | 793 // it. For now, removing it seems working fine. |
709 gvr_api_->ApplyNeckModel(head_pose, 1.0f); | 794 gvr_api_->ApplyNeckModel(head_pose, 1.0f); |
710 } | 795 } |
711 | 796 |
712 // Update the render position of all UI elements (including desktop). | 797 // Update the render position of all UI elements (including desktop). |
713 scene_->UpdateTransforms(TimeInMicroseconds()); | 798 scene_->UpdateTransforms(TimeInMicroseconds()); |
714 | 799 |
715 UpdateController(GetForwardVector(head_pose)); | 800 { |
801 TRACE_EVENT0("gpu", "VrShellGl::UpdateController"); | |
802 UpdateController(GetForwardVector(head_pose)); | |
803 } | |
716 | 804 |
717 DrawVrShell(head_pose, frame); | 805 // Finish drawing in the primary buffer, and draw the headlocked buffer |
806 // if needed. This must be the last drawing call, this method will | |
807 // return with no frame being bound. | |
808 DrawVrShellAndUnbind(head_pose, frame); | |
718 | 809 |
719 frame.Unbind(); | 810 { |
720 frame.Submit(*buffer_viewport_list_, head_pose); | 811 TRACE_EVENT0("gpu", "VrShellGl::Submit"); |
812 frame.Submit(*buffer_viewport_list_, head_pose); | |
813 } | |
721 | 814 |
722 // No need to swap buffers for surfaceless rendering. | 815 // No need to swap buffers for surfaceless rendering. |
723 if (!surfaceless_rendering_) { | 816 if (!surfaceless_rendering_) { |
724 // TODO(mthiesse): Support asynchronous SwapBuffers. | 817 // TODO(mthiesse): Support asynchronous SwapBuffers. |
818 TRACE_EVENT0("gpu", "VrShellGl::SwapBuffers"); | |
725 surface_->SwapBuffers(); | 819 surface_->SwapBuffers(); |
726 } | 820 } |
727 } | 821 } |
728 | 822 |
729 void VrShellGl::DrawVrShell(const gvr::Mat4f& head_pose, gvr::Frame& frame) { | 823 void VrShellGl::DrawVrShellAndUnbind(const gvr::Mat4f& head_pose, |
824 gvr::Frame& frame) { | |
730 TRACE_EVENT0("gpu", "VrShellGl::DrawVrShell"); | 825 TRACE_EVENT0("gpu", "VrShellGl::DrawVrShell"); |
731 std::vector<const ContentRectangle*> head_locked_elements; | 826 std::vector<const ContentRectangle*> head_locked_elements; |
732 std::vector<const ContentRectangle*> world_elements; | 827 std::vector<const ContentRectangle*> world_elements; |
733 for (const auto& rect : scene_->GetUiElements()) { | 828 for (const auto& rect : scene_->GetUiElements()) { |
734 if (!rect->IsVisible()) | 829 if (!rect->IsVisible()) |
735 continue; | 830 continue; |
736 if (rect->lock_to_fov) { | 831 if (rect->lock_to_fov) { |
737 head_locked_elements.push_back(rect.get()); | 832 head_locked_elements.push_back(rect.get()); |
738 } else { | 833 } else { |
739 world_elements.push_back(rect.get()); | 834 world_elements.push_back(rect.get()); |
(...skipping 16 matching lines...) Expand all Loading... | |
756 | 851 |
757 const Colorf& backgroundColor = scene_->GetBackgroundColor(); | 852 const Colorf& backgroundColor = scene_->GetBackgroundColor(); |
758 glClearColor(backgroundColor.r, backgroundColor.g, backgroundColor.b, | 853 glClearColor(backgroundColor.r, backgroundColor.g, backgroundColor.b, |
759 backgroundColor.a); | 854 backgroundColor.a); |
760 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | 855 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
761 } | 856 } |
762 if (!world_elements.empty()) { | 857 if (!world_elements.empty()) { |
763 DrawUiView(&head_pose, world_elements, render_size_primary_, | 858 DrawUiView(&head_pose, world_elements, render_size_primary_, |
764 kViewportListPrimaryOffset); | 859 kViewportListPrimaryOffset); |
765 } | 860 } |
861 frame.Unbind(); // Done with the primary buffer. | |
766 | 862 |
767 if (!head_locked_elements.empty()) { | 863 if (!head_locked_elements.empty()) { |
768 // Add head-locked viewports. The list gets reset to just | 864 // Add head-locked viewports. The list gets reset to just |
769 // the recommended viewports (for the primary buffer) each frame. | 865 // the recommended viewports (for the primary buffer) each frame. |
770 buffer_viewport_list_->SetBufferViewport( | 866 buffer_viewport_list_->SetBufferViewport( |
771 kViewportListHeadlockedOffset + GVR_LEFT_EYE, | 867 kViewportListHeadlockedOffset + GVR_LEFT_EYE, |
772 *headlocked_left_viewport_); | 868 *headlocked_left_viewport_); |
773 buffer_viewport_list_->SetBufferViewport( | 869 buffer_viewport_list_->SetBufferViewport( |
774 kViewportListHeadlockedOffset + GVR_RIGHT_EYE, | 870 kViewportListHeadlockedOffset + GVR_RIGHT_EYE, |
775 *headlocked_right_viewport_); | 871 *headlocked_right_viewport_); |
776 | 872 |
777 // Bind the headlocked framebuffer. | 873 // Bind the headlocked framebuffer. |
778 // TODO(mthiesse): We don't unbind this? Maybe some cleanup is in order | |
779 // here. | |
780 frame.BindBuffer(kFrameHeadlockedBuffer); | 874 frame.BindBuffer(kFrameHeadlockedBuffer); |
781 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); | 875 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); |
782 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | 876 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
783 DrawUiView(nullptr, head_locked_elements, render_size_headlocked_, | 877 DrawUiView(nullptr, head_locked_elements, render_size_headlocked_, |
784 kViewportListHeadlockedOffset); | 878 kViewportListHeadlockedOffset); |
879 frame.Unbind(); // Done with the headlocked buffer. | |
785 } | 880 } |
786 } | 881 } |
787 | 882 |
788 gvr::Sizei VrShellGl::GetWebVRCompositorSurfaceSize() { | |
789 // This is a stopgap while we're using the WebVR compositor rendering path. | |
790 // TODO(klausw,crbug.com/655722): Remove this method and member once we're | |
791 // using a separate WebVR render surface. | |
792 return content_tex_physical_size_; | |
793 } | |
794 | |
795 void VrShellGl::DrawUiView(const gvr::Mat4f* head_pose, | 883 void VrShellGl::DrawUiView(const gvr::Mat4f* head_pose, |
796 const std::vector<const ContentRectangle*>& elements, | 884 const std::vector<const ContentRectangle*>& elements, |
797 const gvr::Sizei& render_size, | 885 const gvr::Sizei& render_size, |
798 int viewport_offset) { | 886 int viewport_offset) { |
799 TRACE_EVENT0("gpu", "VrShellGl::DrawUiView"); | 887 TRACE_EVENT0("gpu", "VrShellGl::DrawUiView"); |
800 | 888 |
801 gvr::Mat4f view_matrix; | 889 gvr::Mat4f view_matrix; |
802 if (head_pose) { | 890 if (head_pose) { |
803 view_matrix = *head_pose; | 891 view_matrix = *head_pose; |
804 } else { | 892 } else { |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
990 void VrShellGl::DrawWebVr() { | 1078 void VrShellGl::DrawWebVr() { |
991 TRACE_EVENT0("gpu", "VrShellGl::DrawWebVr"); | 1079 TRACE_EVENT0("gpu", "VrShellGl::DrawWebVr"); |
992 // Don't need face culling, depth testing, blending, etc. Turn it all off. | 1080 // Don't need face culling, depth testing, blending, etc. Turn it all off. |
993 glDisable(GL_CULL_FACE); | 1081 glDisable(GL_CULL_FACE); |
994 glDepthMask(GL_FALSE); | 1082 glDepthMask(GL_FALSE); |
995 glDisable(GL_DEPTH_TEST); | 1083 glDisable(GL_DEPTH_TEST); |
996 glDisable(GL_SCISSOR_TEST); | 1084 glDisable(GL_SCISSOR_TEST); |
997 glDisable(GL_BLEND); | 1085 glDisable(GL_BLEND); |
998 glDisable(GL_POLYGON_OFFSET_FILL); | 1086 glDisable(GL_POLYGON_OFFSET_FILL); |
999 | 1087 |
1000 glViewport(0, 0, render_size_primary_.width, render_size_primary_.height); | 1088 glViewport(0, 0, webvr_surface_size_.width, webvr_surface_size_.height); |
1001 vr_shell_renderer_->GetWebVrRenderer()->Draw(webvr_texture_id_); | 1089 vr_shell_renderer_->GetWebVrRenderer()->Draw(webvr_texture_id_); |
1002 } | 1090 } |
1003 | 1091 |
1004 void VrShellGl::OnTriggerEvent() { | 1092 void VrShellGl::OnTriggerEvent() { |
1005 // Set a flag to handle this on the render thread at the next frame. | 1093 // Set a flag to handle this on the render thread at the next frame. |
1006 touch_pending_ = true; | 1094 touch_pending_ = true; |
1007 } | 1095 } |
1008 | 1096 |
1009 void VrShellGl::OnPause() { | 1097 void VrShellGl::OnPause() { |
1010 vsync_task_.Cancel(); | 1098 vsync_task_.Cancel(); |
(...skipping 10 matching lines...) Expand all Loading... | |
1021 OnVSync(); | 1109 OnVSync(); |
1022 } | 1110 } |
1023 } | 1111 } |
1024 | 1112 |
1025 void VrShellGl::SetWebVrMode(bool enabled) { | 1113 void VrShellGl::SetWebVrMode(bool enabled) { |
1026 web_vr_mode_ = enabled; | 1114 web_vr_mode_ = enabled; |
1027 } | 1115 } |
1028 | 1116 |
1029 void VrShellGl::UpdateWebVRTextureBounds(int16_t frame_index, | 1117 void VrShellGl::UpdateWebVRTextureBounds(int16_t frame_index, |
1030 const gvr::Rectf& left_bounds, | 1118 const gvr::Rectf& left_bounds, |
1031 const gvr::Rectf& right_bounds) { | 1119 const gvr::Rectf& right_bounds, |
1120 const gvr::Sizei& source_size) { | |
1032 if (frame_index < 0) { | 1121 if (frame_index < 0) { |
1033 webvr_left_viewport_->SetSourceUv(left_bounds); | 1122 webvr_left_viewport_->SetSourceUv(left_bounds); |
1034 webvr_right_viewport_->SetSourceUv(right_bounds); | 1123 webvr_right_viewport_->SetSourceUv(right_bounds); |
1035 } else { | 1124 } else { |
1036 pending_bounds_.emplace( | 1125 pending_bounds_.emplace(std::make_pair( |
dcheng
2017/03/08 07:23:40
std::make_pair should be unnecessary with emplace
klausw
2017/03/08 08:11:09
Done.
| |
1037 std::make_pair(frame_index, std::make_pair(left_bounds, right_bounds))); | 1126 frame_index, WebVrBounds(left_bounds, right_bounds, source_size))); |
1038 } | 1127 } |
1039 } | 1128 } |
1040 | 1129 |
1041 void VrShellGl::ContentBoundsChanged(int width, int height) { | 1130 void VrShellGl::ContentBoundsChanged(int width, int height) { |
1042 TRACE_EVENT0("gpu", "VrShellGl::ContentBoundsChanged"); | 1131 TRACE_EVENT0("gpu", "VrShellGl::ContentBoundsChanged"); |
1043 content_tex_css_width_ = width; | 1132 content_tex_css_width_ = width; |
1044 content_tex_css_height_ = height; | 1133 content_tex_css_height_ = height; |
1045 } | 1134 } |
1046 | 1135 |
1047 void VrShellGl::ContentPhysicalBoundsChanged(int width, int height) { | 1136 void VrShellGl::ContentPhysicalBoundsChanged(int width, int height) { |
(...skipping 13 matching lines...) Expand all Loading... | |
1061 ui_surface_texture_->SetDefaultBufferSize(width, height); | 1150 ui_surface_texture_->SetDefaultBufferSize(width, height); |
1062 ui_tex_physical_size_.width = width; | 1151 ui_tex_physical_size_.width = width; |
1063 ui_tex_physical_size_.height = height; | 1152 ui_tex_physical_size_.height = height; |
1064 } | 1153 } |
1065 | 1154 |
1066 base::WeakPtr<VrShellGl> VrShellGl::GetWeakPtr() { | 1155 base::WeakPtr<VrShellGl> VrShellGl::GetWeakPtr() { |
1067 return weak_ptr_factory_.GetWeakPtr(); | 1156 return weak_ptr_factory_.GetWeakPtr(); |
1068 } | 1157 } |
1069 | 1158 |
1070 void VrShellGl::OnVSync() { | 1159 void VrShellGl::OnVSync() { |
1160 while (premature_received_frames_ > 0) { | |
1161 TRACE_EVENT0("gpu", "VrShellGl::OnWebVRFrameAvailableRetry"); | |
1162 --premature_received_frames_; | |
1163 OnWebVRFrameAvailable(); | |
1164 } | |
1165 | |
1071 base::TimeTicks now = base::TimeTicks::Now(); | 1166 base::TimeTicks now = base::TimeTicks::Now(); |
1072 base::TimeTicks target; | 1167 base::TimeTicks target; |
1073 | 1168 |
1074 // Don't send VSyncs until we have a timebase/interval. | 1169 // Don't send VSyncs until we have a timebase/interval. |
1075 if (vsync_interval_.is_zero()) | 1170 if (vsync_interval_.is_zero()) |
1076 return; | 1171 return; |
1077 target = now + vsync_interval_; | 1172 target = now + vsync_interval_; |
1078 int64_t intervals = (target - vsync_timebase_) / vsync_interval_; | 1173 int64_t intervals = (target - vsync_timebase_) / vsync_interval_; |
1079 target = vsync_timebase_ + intervals * vsync_interval_; | 1174 target = vsync_timebase_ + intervals * vsync_interval_; |
1080 task_runner_->PostDelayedTask(FROM_HERE, vsync_task_.callback(), | 1175 task_runner_->PostDelayedTask(FROM_HERE, vsync_task_.callback(), |
1081 target - now); | 1176 target - now); |
1082 | 1177 |
1083 base::TimeDelta time = intervals * vsync_interval_; | 1178 base::TimeDelta time = intervals * vsync_interval_; |
1084 if (!callback_.is_null()) { | 1179 if (!callback_.is_null()) { |
1085 SendVSync(time, base::ResetAndReturn(&callback_)); | 1180 SendVSync(time, base::ResetAndReturn(&callback_)); |
1086 } else { | 1181 } else { |
1087 pending_vsync_ = true; | 1182 pending_vsync_ = true; |
1088 pending_time_ = time; | 1183 pending_time_ = time; |
1089 } | 1184 } |
1090 DrawFrame(); | 1185 if (!web_vr_mode_) { |
1186 DrawFrame(-1); | |
1187 } | |
1091 } | 1188 } |
1092 | 1189 |
1093 void VrShellGl::OnRequest(device::mojom::VRVSyncProviderRequest request) { | 1190 void VrShellGl::OnRequest(device::mojom::VRVSyncProviderRequest request) { |
1094 binding_.Close(); | 1191 binding_.Close(); |
1095 binding_.Bind(std::move(request)); | 1192 binding_.Bind(std::move(request)); |
1096 } | 1193 } |
1097 | 1194 |
1098 void VrShellGl::GetVSync(const GetVSyncCallback& callback) { | 1195 void VrShellGl::GetVSync(const GetVSyncCallback& callback) { |
1099 if (!pending_vsync_) { | 1196 if (!pending_vsync_) { |
1100 if (!callback_.is_null()) { | 1197 if (!callback_.is_null()) { |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1150 void VrShellGl::ResetPose() { | 1247 void VrShellGl::ResetPose() { |
1151 // Should never call RecenterTracking when using with Daydream viewers. On | 1248 // Should never call RecenterTracking when using with Daydream viewers. On |
1152 // those devices recentering should only be done via the controller. | 1249 // those devices recentering should only be done via the controller. |
1153 if (gvr_api_ && gvr_api_->GetViewerType() == GVR_VIEWER_TYPE_CARDBOARD) | 1250 if (gvr_api_ && gvr_api_->GetViewerType() == GVR_VIEWER_TYPE_CARDBOARD) |
1154 gvr_api_->RecenterTracking(); | 1251 gvr_api_->RecenterTracking(); |
1155 } | 1252 } |
1156 | 1253 |
1157 void VrShellGl::CreateVRDisplayInfo( | 1254 void VrShellGl::CreateVRDisplayInfo( |
1158 const base::Callback<void(device::mojom::VRDisplayInfoPtr)>& callback, | 1255 const base::Callback<void(device::mojom::VRDisplayInfoPtr)>& callback, |
1159 uint32_t device_id) { | 1256 uint32_t device_id) { |
1257 // This assumes that the initial webvr_surface_size_ was set to the | |
1258 // appropriate recommended render resolution as the default size during | |
1259 // InitializeGl. Revisit if the initialization order changes. | |
1160 device::mojom::VRDisplayInfoPtr info = VrShell::CreateVRDisplayInfo( | 1260 device::mojom::VRDisplayInfoPtr info = VrShell::CreateVRDisplayInfo( |
1161 gvr_api_.get(), content_tex_physical_size_, device_id); | 1261 gvr_api_.get(), webvr_surface_size_, device_id); |
1162 main_thread_task_runner_->PostTask( | 1262 main_thread_task_runner_->PostTask( |
1163 FROM_HERE, | 1263 FROM_HERE, |
1164 base::Bind(&RunVRDisplayInfoCallback, callback, base::Passed(&info))); | 1264 base::Bind(&RunVRDisplayInfoCallback, callback, base::Passed(&info))); |
1165 } | 1265 } |
1166 | 1266 |
1167 } // namespace vr_shell | 1267 } // namespace vr_shell |
OLD | NEW |