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/ui_elements.h" | 15 #include "chrome/browser/android/vr_shell/ui_elements.h" |
16 #include "chrome/browser/android/vr_shell/ui_scene.h" | 16 #include "chrome/browser/android/vr_shell/ui_scene.h" |
17 #include "chrome/browser/android/vr_shell/vr_controller.h" | 17 #include "chrome/browser/android/vr_shell/vr_controller.h" |
18 #include "chrome/browser/android/vr_shell/vr_gl_util.h" | 18 #include "chrome/browser/android/vr_shell/vr_gl_util.h" |
19 #include "chrome/browser/android/vr_shell/vr_math.h" | 19 #include "chrome/browser/android/vr_shell/vr_math.h" |
20 #include "chrome/browser/android/vr_shell/vr_shell.h" | 20 #include "chrome/browser/android/vr_shell/vr_shell.h" |
| 21 #include "chrome/browser/android/vr_shell/vr_shell_command_buffer_gl.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" |
25 #include "third_party/WebKit/public/platform/WebMouseEvent.h" | 26 #include "third_party/WebKit/public/platform/WebMouseEvent.h" |
26 #include "ui/gl/android/scoped_java_surface.h" | 27 #include "ui/gl/android/scoped_java_surface.h" |
27 #include "ui/gl/android/surface_texture.h" | 28 #include "ui/gl/android/surface_texture.h" |
28 #include "ui/gl/gl_bindings.h" | 29 #include "ui/gl/gl_bindings.h" |
29 #include "ui/gl/gl_context.h" | 30 #include "ui/gl/gl_context.h" |
30 #include "ui/gl/gl_surface.h" | 31 #include "ui/gl/gl_surface.h" |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
76 | 77 |
77 // The GVR viewport list has two entries (left eye and right eye) for each | 78 // The GVR viewport list has two entries (left eye and right eye) for each |
78 // GVR buffer. | 79 // GVR buffer. |
79 static constexpr int kViewportListPrimaryOffset = 0; | 80 static constexpr int kViewportListPrimaryOffset = 0; |
80 static constexpr int kViewportListHeadlockedOffset = 2; | 81 static constexpr int kViewportListHeadlockedOffset = 2; |
81 | 82 |
82 // Buffer size large enough to handle the current backlog of poses which is | 83 // Buffer size large enough to handle the current backlog of poses which is |
83 // 2-3 frames. | 84 // 2-3 frames. |
84 static constexpr unsigned kPoseRingBufferSize = 8; | 85 static constexpr unsigned kPoseRingBufferSize = 8; |
85 | 86 |
86 // Magic numbers used to mark valid pose index values encoded in frame | |
87 // data. Must match the magic numbers used in blink's VRDisplay.cpp. | |
88 static constexpr std::array<uint8_t, 2> kWebVrPosePixelMagicNumbers{{42, 142}}; | |
89 | |
90 float Distance(const gvr::Vec3f& vec1, const gvr::Vec3f& vec2) { | 87 float Distance(const gvr::Vec3f& vec1, const gvr::Vec3f& vec2) { |
91 float xdiff = (vec1.x - vec2.x); | 88 float xdiff = (vec1.x - vec2.x); |
92 float ydiff = (vec1.y - vec2.y); | 89 float ydiff = (vec1.y - vec2.y); |
93 float zdiff = (vec1.z - vec2.z); | 90 float zdiff = (vec1.z - vec2.z); |
94 float scale = xdiff * xdiff + ydiff * ydiff + zdiff * zdiff; | 91 float scale = xdiff * xdiff + ydiff * ydiff + zdiff * zdiff; |
95 return std::sqrt(scale); | 92 return std::sqrt(scale); |
96 } | 93 } |
97 | 94 |
98 // Generate a quaternion representing the rotation from the negative Z axis | 95 // Generate a quaternion representing the rotation from the negative Z axis |
99 // (0, 0, -1) to a specified vector. This is an optimized version of a more | 96 // (0, 0, -1) to a specified vector. This is an optimized version of a more |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
228 LOG(ERROR) << "gl::init::CreateGLContext failed"; | 225 LOG(ERROR) << "gl::init::CreateGLContext failed"; |
229 ForceExitVr(); | 226 ForceExitVr(); |
230 return; | 227 return; |
231 } | 228 } |
232 if (!context_->MakeCurrent(surface_.get())) { | 229 if (!context_->MakeCurrent(surface_.get())) { |
233 LOG(ERROR) << "gl::GLContext::MakeCurrent() failed"; | 230 LOG(ERROR) << "gl::GLContext::MakeCurrent() failed"; |
234 ForceExitVr(); | 231 ForceExitVr(); |
235 return; | 232 return; |
236 } | 233 } |
237 | 234 |
238 unsigned int textures[2]; | 235 unsigned int textures[3]; |
239 glGenTextures(2, textures); | 236 glGenTextures(3, textures); |
240 ui_texture_id_ = textures[0]; | 237 ui_texture_id_ = textures[0]; |
241 content_texture_id_ = textures[1]; | 238 content_texture_id_ = textures[1]; |
| 239 webvr_texture_id_ = textures[2]; |
242 ui_surface_texture_ = gl::SurfaceTexture::Create(ui_texture_id_); | 240 ui_surface_texture_ = gl::SurfaceTexture::Create(ui_texture_id_); |
243 content_surface_texture_ = gl::SurfaceTexture::Create(content_texture_id_); | 241 content_surface_texture_ = gl::SurfaceTexture::Create(content_texture_id_); |
| 242 webvr_surface_texture_ = gl::SurfaceTexture::Create(webvr_texture_id_); |
244 CreateUiSurface(); | 243 CreateUiSurface(); |
245 CreateContentSurface(); | 244 CreateContentSurface(); |
| 245 CreateWebVRSurface(); |
246 ui_surface_texture_->SetFrameAvailableCallback(base::Bind( | 246 ui_surface_texture_->SetFrameAvailableCallback(base::Bind( |
247 &VrShellGl::OnUIFrameAvailable, weak_ptr_factory_.GetWeakPtr())); | 247 &VrShellGl::OnUIFrameAvailable, weak_ptr_factory_.GetWeakPtr())); |
248 content_surface_texture_->SetFrameAvailableCallback(base::Bind( | 248 content_surface_texture_->SetFrameAvailableCallback(base::Bind( |
249 &VrShellGl::OnContentFrameAvailable, weak_ptr_factory_.GetWeakPtr())); | 249 &VrShellGl::OnContentFrameAvailable, weak_ptr_factory_.GetWeakPtr())); |
| 250 webvr_surface_texture_->SetFrameAvailableCallback(base::Bind( |
| 251 &VrShellGl::OnWebVRFrameAvailable, weak_ptr_factory_.GetWeakPtr())); |
| 252 ui_surface_texture_->SetDefaultBufferSize(ui_tex_physical_size_.width, |
| 253 ui_tex_physical_size_.height); |
250 content_surface_texture_->SetDefaultBufferSize( | 254 content_surface_texture_->SetDefaultBufferSize( |
251 content_tex_physical_size_.width, content_tex_physical_size_.height); | 255 content_tex_physical_size_.width, content_tex_physical_size_.height); |
252 ui_surface_texture_->SetDefaultBufferSize(ui_tex_physical_size_.width, | |
253 ui_tex_physical_size_.height); | |
254 InitializeRenderer(); | 256 InitializeRenderer(); |
255 | 257 |
256 vsync_task_.Reset(base::Bind(&VrShellGl::OnVSync, base::Unretained(this))); | 258 vsync_task_.Reset(base::Bind(&VrShellGl::OnVSync, base::Unretained(this))); |
257 OnVSync(); | 259 OnVSync(); |
258 | 260 |
259 ready_to_draw_ = true; | 261 ready_to_draw_ = true; |
260 } | 262 } |
261 | 263 |
| 264 |
262 void VrShellGl::CreateContentSurface() { | 265 void VrShellGl::CreateContentSurface() { |
263 content_surface_ = | 266 content_surface_ = |
264 base::MakeUnique<gl::ScopedJavaSurface>(content_surface_texture_.get()); | 267 base::MakeUnique<gl::ScopedJavaSurface>(content_surface_texture_.get()); |
265 main_thread_task_runner_->PostTask( | 268 main_thread_task_runner_->PostTask( |
266 FROM_HERE, base::Bind(&VrShell::ContentSurfaceChanged, weak_vr_shell_, | 269 FROM_HERE, base::Bind(&VrShell::ContentSurfaceChanged, weak_vr_shell_, |
267 content_surface_->j_surface().obj())); | 270 content_surface_->j_surface().obj())); |
268 } | 271 } |
269 | 272 |
270 void VrShellGl::CreateUiSurface() { | 273 void VrShellGl::CreateUiSurface() { |
271 ui_surface_ = | 274 ui_surface_ = |
272 base::MakeUnique<gl::ScopedJavaSurface>(ui_surface_texture_.get()); | 275 base::MakeUnique<gl::ScopedJavaSurface>(ui_surface_texture_.get()); |
273 main_thread_task_runner_->PostTask( | 276 main_thread_task_runner_->PostTask( |
274 FROM_HERE, base::Bind(&VrShell::UiSurfaceChanged, weak_vr_shell_, | 277 FROM_HERE, base::Bind(&VrShell::UiSurfaceChanged, weak_vr_shell_, |
275 ui_surface_->j_surface().obj())); | 278 ui_surface_->j_surface().obj())); |
276 } | 279 } |
277 | 280 |
| 281 void VrShellGl::CreateWebVRSurface() { |
| 282 VLOG(1) << __FUNCTION__ << ";;; content_tex_physical_size=" << |
| 283 content_tex_physical_size_.width << "x" << |
| 284 content_tex_physical_size_.height; |
| 285 VLOG(1) << __FUNCTION__ << ";;; render_size_primary=" << |
| 286 render_size_primary_.width << "x" << render_size_primary_.height; |
| 287 // FIXME: get correct sizes. Currently getting 0x0 from the |
| 288 // likely candidates. For now, hardcode Pixel XL resolution. |
| 289 // This will work on other devices too, though it's not the most |
| 290 // efficient. |
| 291 webvr_surface_texture_->SetDefaultBufferSize(2560, 1440); |
| 292 |
| 293 command_buffer_gl_ = base::MakeUnique<VrShellCommandBufferGl>(); |
| 294 command_buffer_gl_->CreateContext(webvr_surface_texture_); |
| 295 } |
| 296 |
| 297 void VrShellGl::SubmitWebVRFrame(int frame_index, const gpu::Mailbox& mailbox) { |
| 298 TRACE_EVENT0("gpu", "VrShellGl::SubmitWebVRFrame"); |
| 299 bool drawn = command_buffer_gl_->CopyFrameToSurface( |
| 300 frame_index, mailbox, !pending_frames_.empty()); |
| 301 // If we get here, we're committed to drawing and swapBuffers. |
| 302 // Continue after errors. |
| 303 if (drawn) { |
| 304 VLOG(1) << __FUNCTION__ << ";;; add frame=" << frame_index << |
| 305 " to pending_frames, size=" << pending_frames_.size(); |
| 306 main_thread_task_runner_->PostTask( |
| 307 FROM_HERE, base::Bind(&VrShell::OnSubmitWebVRFrameTransferred, |
| 308 weak_vr_shell_, frame_index)); |
| 309 pending_frames_.emplace(frame_index); |
| 310 } else { |
| 311 VLOG(1) << __FUNCTION__ << ";;; NOT DRAWN, FIXME!"; |
| 312 } |
| 313 } |
| 314 |
278 void VrShellGl::OnUIFrameAvailable() { | 315 void VrShellGl::OnUIFrameAvailable() { |
| 316 VLOG(1) << __FUNCTION__ << ";;; UI UpdateTexImage start"; |
279 ui_surface_texture_->UpdateTexImage(); | 317 ui_surface_texture_->UpdateTexImage(); |
| 318 VLOG(1) << __FUNCTION__ << ";;; UI UpdateTexImage end"; |
280 } | 319 } |
281 | 320 |
282 void VrShellGl::OnContentFrameAvailable() { | 321 void VrShellGl::OnContentFrameAvailable() { |
| 322 VLOG(1) << __FUNCTION__ << ";;; Content UpdateTexImage start"; |
283 content_surface_texture_->UpdateTexImage(); | 323 content_surface_texture_->UpdateTexImage(); |
284 received_frame_ = true; | 324 received_frame_ = true; |
| 325 VLOG(1) << __FUNCTION__ << ";;; Content UpdateTexImage end"; |
285 } | 326 } |
286 | 327 |
287 bool VrShellGl::GetPixelEncodedFrameIndex(uint16_t* frame_index) { | 328 void VrShellGl::OnWebVRFrameAvailable() { |
288 TRACE_EVENT0("gpu", "VrShellGl::GetPixelEncodedFrameIndex"); | 329 TRACE_EVENT0("gpu", "VrShellGl::OnWebVRFrameAvailable"); |
289 if (!received_frame_) { | 330 VLOG(1) << __FUNCTION__ << ";;; pending count=" << pending_frames_.size(); |
290 if (last_frame_index_ == (uint16_t)-1) | 331 // A "while" loop here is a bad idea. It's legal to call |
291 return false; | 332 // UpdateTexImage repeatedly even if no frames are available, but |
292 *frame_index = last_frame_index_; | 333 // that does *not* wait for a new frame, it just reuses the most |
293 return true; | 334 // recent one. That would mess up the count. |
| 335 if (pending_frames_.empty()) { |
| 336 VLOG(1) << __FUNCTION__ << ";;; no pending frames? Please retry! " << |
| 337 "premature_received_frames " << premature_received_frames_ << " => " << |
| 338 (premature_received_frames_ + 1); |
| 339 ++premature_received_frames_; |
| 340 return; |
294 } | 341 } |
295 received_frame_ = false; | |
296 | 342 |
297 // Read the pose index encoded in a bottom left pixel as color values. | 343 VLOG(1) << __FUNCTION__ << ";;; WebVR UpdateTexImage start"; |
298 // See also third_party/WebKit/Source/modules/vr/VRDisplay.cpp which | 344 webvr_surface_texture_->UpdateTexImage(); |
299 // encodes the pose index, and device/vr/android/gvr/gvr_device.cc | 345 int frame_index = pending_frames_.front(); |
300 // which tracks poses. Returns the low byte (0..255) if valid, or -1 | 346 pending_frames_.pop(); |
301 // if not valid due to bad magic number. | 347 VLOG(1) << __FUNCTION__ << ";;; WebVR UpdateTexImage end, got frame=" << |
302 uint8_t pixels[4]; | 348 frame_index; |
303 // Assume we're reading from the framebuffer we just wrote to. | 349 main_thread_task_runner_->PostTask( |
304 // That's true currently, we may need to use glReadBuffer(GL_BACK) | 350 FROM_HERE, base::Bind(&VrShell::OnSubmitWebVRFrameRendered, |
305 // or equivalent if the rendering setup changes in the future. | 351 weak_vr_shell_, frame_index)); |
306 glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels); | 352 DrawFrame(frame_index); |
307 | |
308 // Check for the magic number written by VRDevice.cpp on submit. | |
309 // This helps avoid glitches from garbage data in the render | |
310 // buffer that can appear during initialization or resizing. These | |
311 // often appear as flashes of all-black or all-white pixels. | |
312 if (pixels[1] == kWebVrPosePixelMagicNumbers[0] && | |
313 pixels[2] == kWebVrPosePixelMagicNumbers[1]) { | |
314 // Pose is good. | |
315 *frame_index = pixels[0]; | |
316 last_frame_index_ = pixels[0]; | |
317 return true; | |
318 } | |
319 VLOG(1) << "WebVR: reject decoded pose index " << static_cast<int>(pixels[0]) | |
320 << ", bad magic number " << static_cast<int>(pixels[1]) << ", " | |
321 << static_cast<int>(pixels[2]); | |
322 return false; | |
323 } | 353 } |
324 | 354 |
325 void VrShellGl::GvrInit(gvr_context* gvr_api) { | 355 void VrShellGl::GvrInit(gvr_context* gvr_api) { |
326 gvr_api_ = gvr::GvrApi::WrapNonOwned(gvr_api); | 356 gvr_api_ = gvr::GvrApi::WrapNonOwned(gvr_api); |
327 controller_.reset(new VrController(gvr_api)); | 357 controller_.reset(new VrController(gvr_api)); |
328 | 358 |
329 ViewerType viewerType; | 359 ViewerType viewerType; |
330 switch (gvr_api_->GetViewerType()) { | 360 switch (gvr_api_->GetViewerType()) { |
331 case gvr::ViewerType::GVR_VIEWER_TYPE_DAYDREAM: | 361 case gvr::ViewerType::GVR_VIEWER_TYPE_DAYDREAM: |
332 viewerType = ViewerType::DAYDREAM; | 362 viewerType = ViewerType::DAYDREAM; |
333 break; | 363 break; |
334 case gvr::ViewerType::GVR_VIEWER_TYPE_CARDBOARD: | 364 case gvr::ViewerType::GVR_VIEWER_TYPE_CARDBOARD: |
335 viewerType = ViewerType::CARDBOARD; | 365 viewerType = ViewerType::CARDBOARD; |
336 break; | 366 break; |
337 default: | 367 default: |
338 NOTREACHED(); | 368 NOTREACHED(); |
339 viewerType = ViewerType::UNKNOWN_TYPE; | 369 viewerType = ViewerType::UNKNOWN_TYPE; |
340 break; | 370 break; |
341 } | 371 } |
342 UMA_HISTOGRAM_ENUMERATION("VRViewerType", static_cast<int>(viewerType), | 372 UMA_HISTOGRAM_ENUMERATION("VRViewerType", static_cast<int>(viewerType), |
343 static_cast<int>(ViewerType::VIEWER_TYPE_MAX)); | 373 static_cast<int>(ViewerType::VIEWER_TYPE_MAX)); |
344 } | 374 } |
345 | 375 |
346 void VrShellGl::InitializeRenderer() { | 376 void VrShellGl::InitializeRenderer() { |
347 // While WebVR is going through the compositor path, it shares | |
348 // the same texture ID. This will change once it gets its own | |
349 // surface, but store it separately to avoid future confusion. | |
350 // TODO(klausw,crbug.com/655722): remove this. | |
351 webvr_texture_id_ = content_texture_id_; | |
352 | |
353 gvr_api_->InitializeGl(); | 377 gvr_api_->InitializeGl(); |
354 webvr_head_pose_.assign(kPoseRingBufferSize, | 378 webvr_head_pose_.assign(kPoseRingBufferSize, |
355 gvr_api_->GetHeadSpaceFromStartSpaceRotation( | 379 gvr_api_->GetHeadSpaceFromStartSpaceRotation( |
356 gvr::GvrApi::GetTimePointNow())); | 380 gvr::GvrApi::GetTimePointNow())); |
357 | 381 |
358 std::vector<gvr::BufferSpec> specs; | 382 std::vector<gvr::BufferSpec> specs; |
359 // For kFramePrimaryBuffer (primary VrShell and WebVR content) | 383 // For kFramePrimaryBuffer (primary VrShell and WebVR content) |
360 specs.push_back(gvr_api_->CreateBufferSpec()); | 384 specs.push_back(gvr_api_->CreateBufferSpec()); |
361 render_size_primary_ = specs[kFramePrimaryBuffer].GetSize(); | 385 render_size_primary_ = specs[kFramePrimaryBuffer].GetSize(); |
362 | 386 |
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
623 std::unique_ptr<blink::WebInputEvent> event) { | 647 std::unique_ptr<blink::WebInputEvent> event) { |
624 DCHECK(input_target != InputTarget::NONE); | 648 DCHECK(input_target != InputTarget::NONE); |
625 auto&& target = input_target == InputTarget::CONTENT | 649 auto&& target = input_target == InputTarget::CONTENT |
626 ? &VrShell::ProcessContentGesture | 650 ? &VrShell::ProcessContentGesture |
627 : &VrShell::ProcessUIGesture; | 651 : &VrShell::ProcessUIGesture; |
628 main_thread_task_runner_->PostTask( | 652 main_thread_task_runner_->PostTask( |
629 FROM_HERE, | 653 FROM_HERE, |
630 base::Bind(target, weak_vr_shell_, base::Passed(std::move(event)))); | 654 base::Bind(target, weak_vr_shell_, base::Passed(std::move(event)))); |
631 } | 655 } |
632 | 656 |
633 void VrShellGl::DrawFrame() { | 657 void VrShellGl::DrawFrame(int frame_index) { |
634 TRACE_EVENT0("gpu", "VrShellGl::DrawFrame"); | 658 TRACE_EVENT0("gpu", "VrShellGl::DrawFrame"); |
635 | 659 |
636 // Reset the viewport list to just the pair of viewports for the | 660 // Reset the viewport list to just the pair of viewports for the |
637 // primary buffer each frame. Head-locked viewports get added by | 661 // primary buffer each frame. Head-locked viewports get added by |
638 // DrawVrShell if needed. | 662 // DrawVrShell if needed. |
639 buffer_viewport_list_->SetToRecommendedBufferViewports(); | 663 buffer_viewport_list_->SetToRecommendedBufferViewports(); |
640 | 664 |
| 665 TRACE_EVENT_BEGIN0("gpu", "VrShellGl::AcquireFrame"); |
641 gvr::Frame frame = swap_chain_->AcquireFrame(); | 666 gvr::Frame frame = swap_chain_->AcquireFrame(); |
| 667 TRACE_EVENT_END0("gpu", "VrShellGl::AcquireFrame"); |
642 if (!frame.is_valid()) { | 668 if (!frame.is_valid()) { |
643 return; | 669 return; |
644 } | 670 } |
645 frame.BindBuffer(kFramePrimaryBuffer); | 671 frame.BindBuffer(kFramePrimaryBuffer); |
646 if (web_vr_mode_) { | 672 if (web_vr_mode_) { |
647 DrawWebVr(); | 673 DrawWebVr(); |
648 } | 674 } |
649 | 675 |
650 uint16_t frame_index; | |
651 gvr::Mat4f head_pose; | 676 gvr::Mat4f head_pose; |
652 | 677 |
653 // When using async reprojection, we need to know which pose was used in | 678 // When using async reprojection, we need to know which pose was used in |
654 // the WebVR app for drawing this frame. Due to unknown amounts of | 679 // the WebVR app for drawing this frame. Due to unknown amounts of |
655 // buffering in the compositor and SurfaceTexture, we read the pose number | 680 // buffering in the compositor and SurfaceTexture, we read the pose number |
656 // from a corner pixel. There's no point in doing this for legacy | 681 // from a corner pixel. There's no point in doing this for legacy |
657 // distortion rendering since that doesn't need a pose, and reading back | 682 // distortion rendering since that doesn't need a pose, and reading back |
658 // pixels is an expensive operation. TODO(klausw,crbug.com/655722): stop | 683 // pixels is an expensive operation. TODO(klausw,crbug.com/655722): stop |
659 // doing this once we have working no-compositor rendering for WebVR. | 684 // doing this once we have working no-compositor rendering for WebVR. |
660 if (web_vr_mode_ && gvr_api_->GetAsyncReprojectionEnabled() && | 685 if (web_vr_mode_ && gvr_api_->GetAsyncReprojectionEnabled()) { |
661 GetPixelEncodedFrameIndex(&frame_index)) { | |
662 static_assert(!((kPoseRingBufferSize - 1) & kPoseRingBufferSize), | 686 static_assert(!((kPoseRingBufferSize - 1) & kPoseRingBufferSize), |
663 "kPoseRingBufferSize must be a power of 2"); | 687 "kPoseRingBufferSize must be a power of 2"); |
664 head_pose = webvr_head_pose_[frame_index % kPoseRingBufferSize]; | 688 head_pose = webvr_head_pose_[frame_index % kPoseRingBufferSize]; |
665 // Process all pending_bounds_ changes targeted for before this frame, being | 689 // Process all pending_bounds_ changes targeted for before this frame, being |
666 // careful of wrapping frame indices. | 690 // careful of wrapping frame indices. |
667 static constexpr unsigned max = | 691 static constexpr unsigned max = |
668 std::numeric_limits<decltype(frame_index_)>::max(); | 692 std::numeric_limits<decltype(frame_index_)>::max(); |
669 static_assert(max > kPoseRingBufferSize * 2, | 693 static_assert(max > kPoseRingBufferSize * 2, |
670 "To detect wrapping, kPoseRingBufferSize must be smaller " | 694 "To detect wrapping, kPoseRingBufferSize must be smaller " |
671 "than half of frame_index_ range."); | 695 "than half of frame_index_ range."); |
672 while (!pending_bounds_.empty()) { | 696 while (!pending_bounds_.empty()) { |
673 uint16_t index = pending_bounds_.front().first; | 697 uint16_t index = pending_bounds_.front().first; |
| 698 VLOG(1) << __FUNCTION__ << ";;; new bounds, index=" << index; |
674 // If index is less than the frame_index it's possible we've wrapped, so | 699 // If index is less than the frame_index it's possible we've wrapped, so |
675 // we extend the range and 'un-wrap' to account for this. | 700 // we extend the range and 'un-wrap' to account for this. |
676 if (index < frame_index) | 701 if (index < frame_index) |
677 index += max; | 702 index += max; |
678 // If the pending bounds change is for an upcoming frame within our buffer | 703 // If the pending bounds change is for an upcoming frame within our buffer |
679 // size, wait to apply it. Otherwise, apply it immediately. This | 704 // size, wait to apply it. Otherwise, apply it immediately. This |
680 // guarantees that even if we miss many frames, the queue can't fill up | 705 // guarantees that even if we miss many frames, the queue can't fill up |
681 // with stale bounds. | 706 // with stale bounds. |
682 if (index > frame_index && index <= frame_index + kPoseRingBufferSize) | 707 if (index > frame_index && index <= frame_index + kPoseRingBufferSize) |
683 break; | 708 break; |
(...skipping 20 matching lines...) Expand all Loading... |
704 // object_from_reference_matrix, we're not updating position_external. | 729 // object_from_reference_matrix, we're not updating position_external. |
705 // TODO: Not sure what object_from_reference_matrix is. The new api removed | 730 // TODO: Not sure what object_from_reference_matrix is. The new api removed |
706 // it. For now, removing it seems working fine. | 731 // it. For now, removing it seems working fine. |
707 gvr_api_->ApplyNeckModel(head_pose, 1.0f); | 732 gvr_api_->ApplyNeckModel(head_pose, 1.0f); |
708 } | 733 } |
709 | 734 |
710 // Update the render position of all UI elements (including desktop). | 735 // Update the render position of all UI elements (including desktop). |
711 const float screen_tilt = kDesktopScreenTiltDefault * M_PI / 180.0f; | 736 const float screen_tilt = kDesktopScreenTiltDefault * M_PI / 180.0f; |
712 scene_->UpdateTransforms(screen_tilt, TimeInMicroseconds()); | 737 scene_->UpdateTransforms(screen_tilt, TimeInMicroseconds()); |
713 | 738 |
714 UpdateController(GetForwardVector(head_pose)); | 739 { |
| 740 TRACE_EVENT0("gpu", "VrShellGl::UpdateController"); |
| 741 UpdateController(GetForwardVector(head_pose)); |
| 742 } |
715 | 743 |
716 DrawVrShell(head_pose, frame); | 744 // Drawing VrShell causes GL error 0x501 GL_INVALID_VALUE while in |
| 745 // WebVR mode. FIXME. |
| 746 if (!web_vr_mode_) DrawVrShell(head_pose, frame); |
717 | 747 |
718 frame.Unbind(); | 748 { |
719 frame.Submit(*buffer_viewport_list_, head_pose); | 749 TRACE_EVENT0("gpu", "VrShellGl::Submit"); |
| 750 frame.Unbind(); |
| 751 frame.Submit(*buffer_viewport_list_, head_pose); |
| 752 } |
720 | 753 |
721 // No need to swap buffers for surfaceless rendering. | 754 // No need to swap buffers for surfaceless rendering. |
722 if (!surfaceless_rendering_) { | 755 if (!surfaceless_rendering_) { |
723 // TODO(mthiesse): Support asynchronous SwapBuffers. | 756 // TODO(mthiesse): Support asynchronous SwapBuffers. |
| 757 TRACE_EVENT0("gpu", "VrShellGl::SwapBuffers"); |
724 surface_->SwapBuffers(); | 758 surface_->SwapBuffers(); |
725 } | 759 } |
726 } | 760 } |
727 | 761 |
728 void VrShellGl::DrawVrShell(const gvr::Mat4f& head_pose, gvr::Frame& frame) { | 762 void VrShellGl::DrawVrShell(const gvr::Mat4f& head_pose, gvr::Frame& frame) { |
729 TRACE_EVENT0("gpu", "VrShellGl::DrawVrShell"); | 763 TRACE_EVENT0("gpu", "VrShellGl::DrawVrShell"); |
730 std::vector<const ContentRectangle*> head_locked_elements; | 764 std::vector<const ContentRectangle*> head_locked_elements; |
731 std::vector<const ContentRectangle*> world_elements; | 765 std::vector<const ContentRectangle*> world_elements; |
732 for (const auto& rect : scene_->GetUiElements()) { | 766 for (const auto& rect : scene_->GetUiElements()) { |
733 if (!rect->IsVisible()) | 767 if (!rect->IsVisible()) |
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
992 // Don't need face culling, depth testing, blending, etc. Turn it all off. | 1026 // Don't need face culling, depth testing, blending, etc. Turn it all off. |
993 glDisable(GL_CULL_FACE); | 1027 glDisable(GL_CULL_FACE); |
994 glDepthMask(GL_FALSE); | 1028 glDepthMask(GL_FALSE); |
995 glDisable(GL_DEPTH_TEST); | 1029 glDisable(GL_DEPTH_TEST); |
996 glDisable(GL_SCISSOR_TEST); | 1030 glDisable(GL_SCISSOR_TEST); |
997 glDisable(GL_BLEND); | 1031 glDisable(GL_BLEND); |
998 glDisable(GL_POLYGON_OFFSET_FILL); | 1032 glDisable(GL_POLYGON_OFFSET_FILL); |
999 | 1033 |
1000 glViewport(0, 0, render_size_primary_.width, render_size_primary_.height); | 1034 glViewport(0, 0, render_size_primary_.width, render_size_primary_.height); |
1001 vr_shell_renderer_->GetWebVrRenderer()->Draw(webvr_texture_id_); | 1035 vr_shell_renderer_->GetWebVrRenderer()->Draw(webvr_texture_id_); |
| 1036 VLOG(1) << __FUNCTION__ << ";;; WebVrRenderer done"; |
1002 } | 1037 } |
1003 | 1038 |
1004 void VrShellGl::OnTriggerEvent() { | 1039 void VrShellGl::OnTriggerEvent() { |
1005 // Set a flag to handle this on the render thread at the next frame. | 1040 // Set a flag to handle this on the render thread at the next frame. |
1006 touch_pending_ = true; | 1041 touch_pending_ = true; |
1007 } | 1042 } |
1008 | 1043 |
1009 void VrShellGl::OnPause() { | 1044 void VrShellGl::OnPause() { |
1010 vsync_task_.Cancel(); | 1045 vsync_task_.Cancel(); |
1011 controller_->OnPause(); | 1046 controller_->OnPause(); |
(...skipping 10 matching lines...) Expand all Loading... |
1022 } | 1057 } |
1023 } | 1058 } |
1024 | 1059 |
1025 void VrShellGl::SetWebVrMode(bool enabled) { | 1060 void VrShellGl::SetWebVrMode(bool enabled) { |
1026 web_vr_mode_ = enabled; | 1061 web_vr_mode_ = enabled; |
1027 } | 1062 } |
1028 | 1063 |
1029 void VrShellGl::UpdateWebVRTextureBounds(int16_t frame_index, | 1064 void VrShellGl::UpdateWebVRTextureBounds(int16_t frame_index, |
1030 const gvr::Rectf& left_bounds, | 1065 const gvr::Rectf& left_bounds, |
1031 const gvr::Rectf& right_bounds) { | 1066 const gvr::Rectf& right_bounds) { |
| 1067 VLOG(1) << __FUNCTION__ << ";;; frame_index=" << frame_index << |
| 1068 " left=" << left_bounds.left << "," << left_bounds.bottom << |
| 1069 "," << left_bounds.right << "," << left_bounds.top << |
| 1070 " right=" << right_bounds.left << "," << right_bounds.bottom << |
| 1071 "," << right_bounds.right << "," << right_bounds.top; |
1032 if (frame_index < 0) { | 1072 if (frame_index < 0) { |
1033 webvr_left_viewport_->SetSourceUv(left_bounds); | 1073 webvr_left_viewport_->SetSourceUv(left_bounds); |
1034 webvr_right_viewport_->SetSourceUv(right_bounds); | 1074 webvr_right_viewport_->SetSourceUv(right_bounds); |
1035 } else { | 1075 } else { |
1036 pending_bounds_.emplace( | 1076 pending_bounds_.emplace( |
1037 std::make_pair(frame_index, std::make_pair(left_bounds, right_bounds))); | 1077 std::make_pair(frame_index, std::make_pair(left_bounds, right_bounds))); |
1038 } | 1078 } |
1039 } | 1079 } |
1040 | 1080 |
1041 void VrShellGl::ContentBoundsChanged(int width, int height) { | 1081 void VrShellGl::ContentBoundsChanged(int width, int height) { |
(...skipping 19 matching lines...) Expand all Loading... |
1061 ui_surface_texture_->SetDefaultBufferSize(width, height); | 1101 ui_surface_texture_->SetDefaultBufferSize(width, height); |
1062 ui_tex_physical_size_.width = width; | 1102 ui_tex_physical_size_.width = width; |
1063 ui_tex_physical_size_.height = height; | 1103 ui_tex_physical_size_.height = height; |
1064 } | 1104 } |
1065 | 1105 |
1066 base::WeakPtr<VrShellGl> VrShellGl::GetWeakPtr() { | 1106 base::WeakPtr<VrShellGl> VrShellGl::GetWeakPtr() { |
1067 return weak_ptr_factory_.GetWeakPtr(); | 1107 return weak_ptr_factory_.GetWeakPtr(); |
1068 } | 1108 } |
1069 | 1109 |
1070 void VrShellGl::OnVSync() { | 1110 void VrShellGl::OnVSync() { |
| 1111 while (premature_received_frames_ > 0) { |
| 1112 VLOG(1) << __FUNCTION__ << ";;; Retrying premature received frame " << |
| 1113 premature_received_frames_ << " => " << |
| 1114 (premature_received_frames_ - 1); |
| 1115 --premature_received_frames_; |
| 1116 OnWebVRFrameAvailable(); |
| 1117 } |
| 1118 |
1071 base::TimeTicks now = base::TimeTicks::Now(); | 1119 base::TimeTicks now = base::TimeTicks::Now(); |
1072 base::TimeTicks target; | 1120 base::TimeTicks target; |
1073 | 1121 |
1074 // Don't send VSyncs until we have a timebase/interval. | 1122 // Don't send VSyncs until we have a timebase/interval. |
1075 if (vsync_interval_.is_zero()) | 1123 if (vsync_interval_.is_zero()) |
1076 return; | 1124 return; |
1077 target = now + vsync_interval_; | 1125 target = now + vsync_interval_; |
1078 int64_t intervals = (target - vsync_timebase_) / vsync_interval_; | 1126 int64_t intervals = (target - vsync_timebase_) / vsync_interval_; |
1079 target = vsync_timebase_ + intervals * vsync_interval_; | 1127 target = vsync_timebase_ + intervals * vsync_interval_; |
1080 task_runner_->PostDelayedTask(FROM_HERE, vsync_task_.callback(), | 1128 task_runner_->PostDelayedTask(FROM_HERE, vsync_task_.callback(), |
1081 target - now); | 1129 target - now); |
1082 | 1130 |
1083 base::TimeDelta time = intervals * vsync_interval_; | 1131 base::TimeDelta time = intervals * vsync_interval_; |
1084 if (!callback_.is_null()) { | 1132 if (!callback_.is_null()) { |
| 1133 VLOG(1) << __FUNCTION__ << ";;; vsync B, interval=" << vsync_interval_; |
1085 SendVSync(time, base::ResetAndReturn(&callback_)); | 1134 SendVSync(time, base::ResetAndReturn(&callback_)); |
1086 } else { | 1135 } else { |
1087 pending_vsync_ = true; | 1136 pending_vsync_ = true; |
1088 pending_time_ = time; | 1137 pending_time_ = time; |
1089 } | 1138 } |
1090 DrawFrame(); | 1139 if (!web_vr_mode_) { |
| 1140 DrawFrame(-1); |
| 1141 } |
1091 } | 1142 } |
1092 | 1143 |
1093 void VrShellGl::OnRequest(device::mojom::VRVSyncProviderRequest request) { | 1144 void VrShellGl::OnRequest(device::mojom::VRVSyncProviderRequest request) { |
1094 binding_.Close(); | 1145 binding_.Close(); |
1095 binding_.Bind(std::move(request)); | 1146 binding_.Bind(std::move(request)); |
1096 } | 1147 } |
1097 | 1148 |
1098 void VrShellGl::GetVSync(const GetVSyncCallback& callback) { | 1149 void VrShellGl::GetVSync(const GetVSyncCallback& callback) { |
1099 if (!pending_vsync_) { | 1150 if (!pending_vsync_) { |
1100 if (!callback_.is_null()) { | 1151 if (!callback_.is_null()) { |
1101 mojo::ReportBadMessage( | 1152 mojo::ReportBadMessage( |
1102 "Requested VSync before waiting for response to previous request."); | 1153 "Requested VSync before waiting for response to previous request."); |
1103 binding_.Close(); | 1154 binding_.Close(); |
1104 return; | 1155 return; |
1105 } | 1156 } |
1106 callback_ = callback; | 1157 callback_ = callback; |
1107 return; | 1158 return; |
1108 } | 1159 } |
1109 pending_vsync_ = false; | 1160 pending_vsync_ = false; |
| 1161 VLOG(1) << __FUNCTION__ << ";;; vsync A, pending time=" << pending_time_; |
1110 SendVSync(pending_time_, callback); | 1162 SendVSync(pending_time_, callback); |
| 1163 |
| 1164 // FIXME: A glFinish here triggers flickering? |
| 1165 // if (web_vr_mode_) glFinish(); |
1111 } | 1166 } |
1112 | 1167 |
1113 void VrShellGl::UpdateVSyncInterval(int64_t timebase_nanos, | 1168 void VrShellGl::UpdateVSyncInterval(int64_t timebase_nanos, |
1114 double interval_seconds) { | 1169 double interval_seconds) { |
1115 vsync_timebase_ = base::TimeTicks(); | 1170 vsync_timebase_ = base::TimeTicks(); |
1116 vsync_timebase_ += base::TimeDelta::FromMicroseconds(timebase_nanos / 1000); | 1171 vsync_timebase_ += base::TimeDelta::FromMicroseconds(timebase_nanos / 1000); |
1117 vsync_interval_ = base::TimeDelta::FromSecondsD(interval_seconds); | 1172 vsync_interval_ = base::TimeDelta::FromSecondsD(interval_seconds); |
1118 vsync_task_.Reset(base::Bind(&VrShellGl::OnVSync, base::Unretained(this))); | 1173 vsync_task_.Reset(base::Bind(&VrShellGl::OnVSync, base::Unretained(this))); |
| 1174 VLOG(1) << __FUNCTION__ << ";;; vsync_interval=" << vsync_interval_; |
1119 OnVSync(); | 1175 OnVSync(); |
1120 } | 1176 } |
1121 | 1177 |
1122 void VrShellGl::ForceExitVr() { | 1178 void VrShellGl::ForceExitVr() { |
1123 main_thread_task_runner_->PostTask( | 1179 main_thread_task_runner_->PostTask( |
1124 FROM_HERE, base::Bind(&VrShell::ForceExitVr, weak_vr_shell_)); | 1180 FROM_HERE, base::Bind(&VrShell::ForceExitVr, weak_vr_shell_)); |
1125 } | 1181 } |
1126 | 1182 |
1127 void VrShellGl::UpdateScene(std::unique_ptr<base::ListValue> commands) { | 1183 void VrShellGl::UpdateScene(std::unique_ptr<base::ListValue> commands) { |
1128 scene_->HandleCommands(std::move(commands), TimeInMicroseconds()); | 1184 scene_->HandleCommands(std::move(commands), TimeInMicroseconds()); |
1129 } | 1185 } |
1130 | 1186 |
1131 void VrShellGl::SendVSync(base::TimeDelta time, | 1187 void VrShellGl::SendVSync(base::TimeDelta time, |
1132 const GetVSyncCallback& callback) { | 1188 const GetVSyncCallback& callback) { |
1133 TRACE_EVENT0("input", "VrShellGl::SendVSync"); | 1189 TRACE_EVENT0("input", "VrShellGl::SendVSync"); |
1134 | 1190 |
1135 uint8_t frame_index = frame_index_++; | 1191 uint8_t frame_index = frame_index_++; |
| 1192 VLOG(1) << __FUNCTION__ << ";;; vsync for frame=" << |
| 1193 static_cast<int>(frame_index); |
1136 | 1194 |
1137 gvr::ClockTimePoint target_time = gvr::GvrApi::GetTimePointNow(); | 1195 gvr::ClockTimePoint target_time = gvr::GvrApi::GetTimePointNow(); |
1138 target_time.monotonic_system_time_nanos += kPredictionTimeWithoutVsyncNanos; | 1196 target_time.monotonic_system_time_nanos += kPredictionTimeWithoutVsyncNanos; |
1139 | 1197 |
1140 gvr::Mat4f head_mat = | 1198 gvr::Mat4f head_mat = |
1141 gvr_api_->GetHeadSpaceFromStartSpaceRotation(target_time); | 1199 gvr_api_->GetHeadSpaceFromStartSpaceRotation(target_time); |
1142 head_mat = gvr_api_->ApplyNeckModel(head_mat, 1.0f); | 1200 head_mat = gvr_api_->ApplyNeckModel(head_mat, 1.0f); |
1143 | 1201 |
1144 webvr_head_pose_[frame_index % kPoseRingBufferSize] = head_mat; | 1202 webvr_head_pose_[frame_index % kPoseRingBufferSize] = head_mat; |
1145 | 1203 |
(...skipping 12 matching lines...) Expand all Loading... |
1158 const base::Callback<void(device::mojom::VRDisplayInfoPtr)>& callback, | 1216 const base::Callback<void(device::mojom::VRDisplayInfoPtr)>& callback, |
1159 uint32_t device_id) { | 1217 uint32_t device_id) { |
1160 device::mojom::VRDisplayInfoPtr info = VrShell::CreateVRDisplayInfo( | 1218 device::mojom::VRDisplayInfoPtr info = VrShell::CreateVRDisplayInfo( |
1161 gvr_api_.get(), content_tex_physical_size_, device_id); | 1219 gvr_api_.get(), content_tex_physical_size_, device_id); |
1162 main_thread_task_runner_->PostTask( | 1220 main_thread_task_runner_->PostTask( |
1163 FROM_HERE, | 1221 FROM_HERE, |
1164 base::Bind(&RunVRDisplayInfoCallback, callback, base::Passed(&info))); | 1222 base::Bind(&RunVRDisplayInfoCallback, callback, base::Passed(&info))); |
1165 } | 1223 } |
1166 | 1224 |
1167 } // namespace vr_shell | 1225 } // namespace vr_shell |
OLD | NEW |