| 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" |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 #include "device/vr/android/gvr/gvr_device.h" | 23 #include "device/vr/android/gvr/gvr_device.h" |
| 24 #include "third_party/WebKit/public/platform/WebInputEvent.h" | 24 #include "third_party/WebKit/public/platform/WebInputEvent.h" |
| 25 #include "third_party/WebKit/public/platform/WebMouseEvent.h" | 25 #include "third_party/WebKit/public/platform/WebMouseEvent.h" |
| 26 #include "ui/gl/android/scoped_java_surface.h" | 26 #include "ui/gl/android/scoped_java_surface.h" |
| 27 #include "ui/gl/android/surface_texture.h" | 27 #include "ui/gl/android/surface_texture.h" |
| 28 #include "ui/gl/gl_bindings.h" | 28 #include "ui/gl/gl_bindings.h" |
| 29 #include "ui/gl/gl_context.h" | 29 #include "ui/gl/gl_context.h" |
| 30 #include "ui/gl/gl_surface.h" | 30 #include "ui/gl/gl_surface.h" |
| 31 #include "ui/gl/init/gl_factory.h" | 31 #include "ui/gl/init/gl_factory.h" |
| 32 | 32 |
| 33 #include "gpu/ipc/common/gpu_surface_tracker.h" |
| 34 |
| 33 namespace vr_shell { | 35 namespace vr_shell { |
| 34 | 36 |
| 35 namespace { | 37 namespace { |
| 36 // TODO(mthiesse): If gvr::PlatformInfo().GetPosePredictionTime() is ever | 38 // TODO(mthiesse): If gvr::PlatformInfo().GetPosePredictionTime() is ever |
| 37 // exposed, use that instead (it defaults to 50ms on most platforms). | 39 // exposed, use that instead (it defaults to 50ms on most platforms). |
| 38 static constexpr int64_t kPredictionTimeWithoutVsyncNanos = 50000000; | 40 static constexpr int64_t kPredictionTimeWithoutVsyncNanos = 50000000; |
| 39 | 41 |
| 40 static constexpr float kZNear = 0.1f; | 42 static constexpr float kZNear = 0.1f; |
| 41 static constexpr float kZFar = 1000.0f; | 43 static constexpr float kZFar = 1000.0f; |
| 42 | 44 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 76 | 78 |
| 77 // The GVR viewport list has two entries (left eye and right eye) for each | 79 // The GVR viewport list has two entries (left eye and right eye) for each |
| 78 // GVR buffer. | 80 // GVR buffer. |
| 79 static constexpr int kViewportListPrimaryOffset = 0; | 81 static constexpr int kViewportListPrimaryOffset = 0; |
| 80 static constexpr int kViewportListHeadlockedOffset = 2; | 82 static constexpr int kViewportListHeadlockedOffset = 2; |
| 81 | 83 |
| 82 // Buffer size large enough to handle the current backlog of poses which is | 84 // Buffer size large enough to handle the current backlog of poses which is |
| 83 // 2-3 frames. | 85 // 2-3 frames. |
| 84 static constexpr unsigned kPoseRingBufferSize = 8; | 86 static constexpr unsigned kPoseRingBufferSize = 8; |
| 85 | 87 |
| 88 #if 0 |
| 86 // Magic numbers used to mark valid pose index values encoded in frame | 89 // 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. | 90 // data. Must match the magic numbers used in blink's VRDisplay.cpp. |
| 88 static constexpr std::array<uint8_t, 2> kWebVrPosePixelMagicNumbers{{42, 142}}; | 91 static constexpr std::array<uint8_t, 2> kWebVrPosePixelMagicNumbers{{42, 142}}; |
| 92 #endif |
| 89 | 93 |
| 90 float Distance(const gvr::Vec3f& vec1, const gvr::Vec3f& vec2) { | 94 float Distance(const gvr::Vec3f& vec1, const gvr::Vec3f& vec2) { |
| 91 float xdiff = (vec1.x - vec2.x); | 95 float xdiff = (vec1.x - vec2.x); |
| 92 float ydiff = (vec1.y - vec2.y); | 96 float ydiff = (vec1.y - vec2.y); |
| 93 float zdiff = (vec1.z - vec2.z); | 97 float zdiff = (vec1.z - vec2.z); |
| 94 float scale = xdiff * xdiff + ydiff * ydiff + zdiff * zdiff; | 98 float scale = xdiff * xdiff + ydiff * ydiff + zdiff * zdiff; |
| 95 return std::sqrt(scale); | 99 return std::sqrt(scale); |
| 96 } | 100 } |
| 97 | 101 |
| 98 // Generate a quaternion representing the rotation from the negative Z axis | 102 // Generate a quaternion representing the rotation from the negative Z axis |
| (...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 228 LOG(ERROR) << "gl::init::CreateGLContext failed"; | 232 LOG(ERROR) << "gl::init::CreateGLContext failed"; |
| 229 ForceExitVr(); | 233 ForceExitVr(); |
| 230 return; | 234 return; |
| 231 } | 235 } |
| 232 if (!context_->MakeCurrent(surface_.get())) { | 236 if (!context_->MakeCurrent(surface_.get())) { |
| 233 LOG(ERROR) << "gl::GLContext::MakeCurrent() failed"; | 237 LOG(ERROR) << "gl::GLContext::MakeCurrent() failed"; |
| 234 ForceExitVr(); | 238 ForceExitVr(); |
| 235 return; | 239 return; |
| 236 } | 240 } |
| 237 | 241 |
| 238 unsigned int textures[2]; | 242 unsigned int textures[3]; |
| 239 glGenTextures(2, textures); | 243 glGenTextures(3, textures); |
| 240 ui_texture_id_ = textures[0]; | 244 ui_texture_id_ = textures[0]; |
| 241 content_texture_id_ = textures[1]; | 245 content_texture_id_ = textures[1]; |
| 246 webvr_texture_id_ = textures[2]; |
| 242 ui_surface_texture_ = gl::SurfaceTexture::Create(ui_texture_id_); | 247 ui_surface_texture_ = gl::SurfaceTexture::Create(ui_texture_id_); |
| 243 content_surface_texture_ = gl::SurfaceTexture::Create(content_texture_id_); | 248 content_surface_texture_ = gl::SurfaceTexture::Create(content_texture_id_); |
| 249 webvr_surface_texture_ = gl::SurfaceTexture::Create(webvr_texture_id_); |
| 244 CreateUiSurface(); | 250 CreateUiSurface(); |
| 245 CreateContentSurface(); | 251 CreateContentSurface(); |
| 252 CreateWebVRSurface(); |
| 246 ui_surface_texture_->SetFrameAvailableCallback(base::Bind( | 253 ui_surface_texture_->SetFrameAvailableCallback(base::Bind( |
| 247 &VrShellGl::OnUIFrameAvailable, weak_ptr_factory_.GetWeakPtr())); | 254 &VrShellGl::OnUIFrameAvailable, weak_ptr_factory_.GetWeakPtr())); |
| 248 content_surface_texture_->SetFrameAvailableCallback(base::Bind( | 255 content_surface_texture_->SetFrameAvailableCallback(base::Bind( |
| 249 &VrShellGl::OnContentFrameAvailable, weak_ptr_factory_.GetWeakPtr())); | 256 &VrShellGl::OnContentFrameAvailable, weak_ptr_factory_.GetWeakPtr())); |
| 257 webvr_surface_texture_->SetFrameAvailableCallback(base::Bind( |
| 258 &VrShellGl::OnWebVRFrameAvailable, weak_ptr_factory_.GetWeakPtr())); |
| 259 ui_surface_texture_->SetDefaultBufferSize(ui_tex_physical_size_.width, |
| 260 ui_tex_physical_size_.height); |
| 250 content_surface_texture_->SetDefaultBufferSize( | 261 content_surface_texture_->SetDefaultBufferSize( |
| 251 content_tex_physical_size_.width, content_tex_physical_size_.height); | 262 content_tex_physical_size_.width, content_tex_physical_size_.height); |
| 252 ui_surface_texture_->SetDefaultBufferSize(ui_tex_physical_size_.width, | 263 VLOG(1) << __FUNCTION__ << ";;; content_tex_physical_size=" << |
| 253 ui_tex_physical_size_.height); | 264 content_tex_physical_size_.width << "x" << |
| 265 content_tex_physical_size_.height; |
| 266 VLOG(1) << __FUNCTION__ << ";;; render_size_primary=" << |
| 267 render_size_primary_.width << "x" << render_size_primary_.height; |
| 268 webvr_surface_texture_->SetDefaultBufferSize( |
| 269 //content_tex_physical_size_.width, content_tex_physical_size_.height); |
| 270 2560, 1440); // FIXME! |
| 254 InitializeRenderer(); | 271 InitializeRenderer(); |
| 255 | 272 |
| 256 vsync_task_.Reset(base::Bind(&VrShellGl::OnVSync, base::Unretained(this))); | 273 vsync_task_.Reset(base::Bind(&VrShellGl::OnVSync, base::Unretained(this))); |
| 257 OnVSync(); | 274 OnVSync(); |
| 258 | 275 |
| 259 ready_to_draw_ = true; | 276 ready_to_draw_ = true; |
| 260 } | 277 } |
| 261 | 278 |
| 262 void VrShellGl::CreateContentSurface() { | 279 void VrShellGl::CreateContentSurface() { |
| 263 content_surface_ = | 280 content_surface_ = |
| 264 base::MakeUnique<gl::ScopedJavaSurface>(content_surface_texture_.get()); | 281 base::MakeUnique<gl::ScopedJavaSurface>(content_surface_texture_.get()); |
| 265 main_thread_task_runner_->PostTask( | 282 main_thread_task_runner_->PostTask( |
| 266 FROM_HERE, base::Bind(&VrShell::ContentSurfaceChanged, weak_vr_shell_, | 283 FROM_HERE, base::Bind(&VrShell::ContentSurfaceChanged, weak_vr_shell_, |
| 267 content_surface_->j_surface().obj())); | 284 content_surface_->j_surface().obj())); |
| 268 } | 285 } |
| 269 | 286 |
| 270 void VrShellGl::CreateUiSurface() { | 287 void VrShellGl::CreateUiSurface() { |
| 271 ui_surface_ = | 288 ui_surface_ = |
| 272 base::MakeUnique<gl::ScopedJavaSurface>(ui_surface_texture_.get()); | 289 base::MakeUnique<gl::ScopedJavaSurface>(ui_surface_texture_.get()); |
| 273 main_thread_task_runner_->PostTask( | 290 main_thread_task_runner_->PostTask( |
| 274 FROM_HERE, base::Bind(&VrShell::UiSurfaceChanged, weak_vr_shell_, | 291 FROM_HERE, base::Bind(&VrShell::UiSurfaceChanged, weak_vr_shell_, |
| 275 ui_surface_->j_surface().obj())); | 292 ui_surface_->j_surface().obj())); |
| 276 } | 293 } |
| 277 | 294 |
| 295 void VrShellGl::CreateWebVRSurface() { |
| 296 ANativeWindow* window = webvr_surface_texture_->CreateSurface(); |
| 297 gpu::GpuSurfaceTracker* tracker = gpu::GpuSurfaceTracker::Get(); |
| 298 ANativeWindow_acquire(window); |
| 299 // setBuffersGeometry seems optional, it uses the SurfaceTexture's |
| 300 // default size by default? |
| 301 // ANativeWindow_setBuffersGeometry( |
| 302 // window, 2048, 1024, WINDOW_FORMAT_RGBA_8888); // FIXME! |
| 303 webvr_surface_handle_ = tracker->AddSurfaceForNativeWidget(window); |
| 304 VLOG(1) << __FUNCTION__ << ";;;: webvr_surface_handle_=" << |
| 305 webvr_surface_handle_; |
| 306 |
| 307 webvr_surface_ = |
| 308 base::MakeUnique<gl::ScopedJavaSurface>(webvr_surface_texture_.get()); |
| 309 tracker->RegisterViewSurface( |
| 310 webvr_surface_handle_, webvr_surface_->j_surface().obj()); |
| 311 // When should this be released? Does registering it keep it alive? |
| 312 ANativeWindow_release(window); |
| 313 |
| 314 main_thread_task_runner_->PostTask( |
| 315 FROM_HERE, base::Bind(&VrShell::WebVRSurfaceChanged, weak_vr_shell_, |
| 316 webvr_surface_handle_)); |
| 317 } |
| 318 |
| 278 void VrShellGl::OnUIFrameAvailable() { | 319 void VrShellGl::OnUIFrameAvailable() { |
| 320 VLOG(1) << __FUNCTION__ << ";;; UI UpdateTexImage start"; |
| 279 ui_surface_texture_->UpdateTexImage(); | 321 ui_surface_texture_->UpdateTexImage(); |
| 322 VLOG(1) << __FUNCTION__ << ";;; UI UpdateTexImage end"; |
| 280 } | 323 } |
| 281 | 324 |
| 282 void VrShellGl::OnContentFrameAvailable() { | 325 void VrShellGl::OnContentFrameAvailable() { |
| 326 VLOG(1) << __FUNCTION__ << ";;; Content UpdateTexImage start"; |
| 283 content_surface_texture_->UpdateTexImage(); | 327 content_surface_texture_->UpdateTexImage(); |
| 284 received_frame_ = true; | 328 received_frame_ = true; |
| 329 VLOG(1) << __FUNCTION__ << ";;; Content UpdateTexImage end"; |
| 285 } | 330 } |
| 286 | 331 |
| 332 void VrShellGl::OnWebVRFrameAvailable() { |
| 333 VLOG(1) << __FUNCTION__ << ";;; pending count=" << pending_frames_.size(); |
| 334 // A "while" loop here is a bad idea. It's legal to call |
| 335 // UpdateTexImage repeatedly even if no frames are available, but |
| 336 // that does *not* wait for a new frame, it just reuses the most |
| 337 // recent one. That would mess up the count. |
| 338 if (pending_frames_.empty()) { |
| 339 VLOG(1) << __FUNCTION__ << ";;; no pending frames? Please retry! premature_r
eceived_frames " << premature_received_frames_ << " => " << (premature_received_
frames_ + 1); |
| 340 ++premature_received_frames_; |
| 341 return; |
| 342 } |
| 343 |
| 344 VLOG(1) << __FUNCTION__ << ";;; requested_frames " << requested_frames_ << " =
> " << (requested_frames_ - 1); |
| 345 --requested_frames_; |
| 346 VLOG(1) << __FUNCTION__ << ";;; WebVR UpdateTexImage start"; |
| 347 webvr_surface_texture_->UpdateTexImage(); |
| 348 int frame_index = pending_frames_.front(); |
| 349 pending_frames_.pop(); |
| 350 VLOG(1) << __FUNCTION__ << ";;; WebVR UpdateTexImage end, got frame=" << frame
_index; |
| 351 DrawFrame(frame_index); |
| 352 main_thread_task_runner_->PostTask( |
| 353 FROM_HERE, base::Bind(&VrShell::WebVRFrameCompleted, weak_vr_shell_, |
| 354 frame_index)); |
| 355 |
| 356 if (pending_frames_.empty() && requested_frames_ > 0) { |
| 357 // Heuristic got confused? TODO(klausw): do proper SubmitFrame callback? |
| 358 VLOG(1) << __FUNCTION__ << ";;; Resetting requested_frames " << requested_fr
ames_ << " => " << 0; |
| 359 requested_frames_ = 0; |
| 360 } |
| 361 } |
| 362 |
| 363 #if 0 |
| 287 bool VrShellGl::GetPixelEncodedFrameIndex(uint16_t* frame_index) { | 364 bool VrShellGl::GetPixelEncodedFrameIndex(uint16_t* frame_index) { |
| 365 //*frame_index = 1; |
| 366 //return true; |
| 288 TRACE_EVENT0("gpu", "VrShellGl::GetPixelEncodedFrameIndex"); | 367 TRACE_EVENT0("gpu", "VrShellGl::GetPixelEncodedFrameIndex"); |
| 289 if (!received_frame_) { | 368 if (!received_frame_) { |
| 290 if (last_frame_index_ == (uint16_t)-1) | 369 if (last_frame_index_ == (uint16_t)-1) |
| 291 return false; | 370 return false; |
| 292 *frame_index = last_frame_index_; | 371 *frame_index = last_frame_index_; |
| 293 return true; | 372 return true; |
| 294 } | 373 } |
| 295 received_frame_ = false; | 374 received_frame_ = false; |
| 296 | 375 |
| 297 // Read the pose index encoded in a bottom left pixel as color values. | 376 // Read the pose index encoded in a bottom left pixel as color values. |
| (...skipping 16 matching lines...) Expand all Loading... |
| 314 // Pose is good. | 393 // Pose is good. |
| 315 *frame_index = pixels[0]; | 394 *frame_index = pixels[0]; |
| 316 last_frame_index_ = pixels[0]; | 395 last_frame_index_ = pixels[0]; |
| 317 return true; | 396 return true; |
| 318 } | 397 } |
| 319 VLOG(1) << "WebVR: reject decoded pose index " << static_cast<int>(pixels[0]) | 398 VLOG(1) << "WebVR: reject decoded pose index " << static_cast<int>(pixels[0]) |
| 320 << ", bad magic number " << static_cast<int>(pixels[1]) << ", " | 399 << ", bad magic number " << static_cast<int>(pixels[1]) << ", " |
| 321 << static_cast<int>(pixels[2]); | 400 << static_cast<int>(pixels[2]); |
| 322 return false; | 401 return false; |
| 323 } | 402 } |
| 403 #endif |
| 324 | 404 |
| 325 void VrShellGl::GvrInit(gvr_context* gvr_api) { | 405 void VrShellGl::GvrInit(gvr_context* gvr_api) { |
| 326 gvr_api_ = gvr::GvrApi::WrapNonOwned(gvr_api); | 406 gvr_api_ = gvr::GvrApi::WrapNonOwned(gvr_api); |
| 327 controller_.reset(new VrController(gvr_api)); | 407 controller_.reset(new VrController(gvr_api)); |
| 328 | 408 |
| 329 ViewerType viewerType; | 409 ViewerType viewerType; |
| 330 switch (gvr_api_->GetViewerType()) { | 410 switch (gvr_api_->GetViewerType()) { |
| 331 case gvr::ViewerType::GVR_VIEWER_TYPE_DAYDREAM: | 411 case gvr::ViewerType::GVR_VIEWER_TYPE_DAYDREAM: |
| 332 viewerType = ViewerType::DAYDREAM; | 412 viewerType = ViewerType::DAYDREAM; |
| 333 break; | 413 break; |
| 334 case gvr::ViewerType::GVR_VIEWER_TYPE_CARDBOARD: | 414 case gvr::ViewerType::GVR_VIEWER_TYPE_CARDBOARD: |
| 335 viewerType = ViewerType::CARDBOARD; | 415 viewerType = ViewerType::CARDBOARD; |
| 336 break; | 416 break; |
| 337 default: | 417 default: |
| 338 NOTREACHED(); | 418 NOTREACHED(); |
| 339 viewerType = ViewerType::UNKNOWN_TYPE; | 419 viewerType = ViewerType::UNKNOWN_TYPE; |
| 340 break; | 420 break; |
| 341 } | 421 } |
| 342 UMA_HISTOGRAM_ENUMERATION("VRViewerType", static_cast<int>(viewerType), | 422 UMA_HISTOGRAM_ENUMERATION("VRViewerType", static_cast<int>(viewerType), |
| 343 static_cast<int>(ViewerType::VIEWER_TYPE_MAX)); | 423 static_cast<int>(ViewerType::VIEWER_TYPE_MAX)); |
| 344 } | 424 } |
| 345 | 425 |
| 346 void VrShellGl::InitializeRenderer() { | 426 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(); | 427 gvr_api_->InitializeGl(); |
| 354 webvr_head_pose_.assign(kPoseRingBufferSize, | 428 webvr_head_pose_.assign(kPoseRingBufferSize, |
| 355 gvr_api_->GetHeadSpaceFromStartSpaceRotation( | 429 gvr_api_->GetHeadSpaceFromStartSpaceRotation( |
| 356 gvr::GvrApi::GetTimePointNow())); | 430 gvr::GvrApi::GetTimePointNow())); |
| 357 | 431 |
| 358 std::vector<gvr::BufferSpec> specs; | 432 std::vector<gvr::BufferSpec> specs; |
| 359 // For kFramePrimaryBuffer (primary VrShell and WebVR content) | 433 // For kFramePrimaryBuffer (primary VrShell and WebVR content) |
| 360 specs.push_back(gvr_api_->CreateBufferSpec()); | 434 specs.push_back(gvr_api_->CreateBufferSpec()); |
| 361 render_size_primary_ = specs[kFramePrimaryBuffer].GetSize(); | 435 render_size_primary_ = specs[kFramePrimaryBuffer].GetSize(); |
| 362 | 436 |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 623 std::unique_ptr<blink::WebInputEvent> event) { | 697 std::unique_ptr<blink::WebInputEvent> event) { |
| 624 DCHECK(input_target != InputTarget::NONE); | 698 DCHECK(input_target != InputTarget::NONE); |
| 625 auto&& target = input_target == InputTarget::CONTENT | 699 auto&& target = input_target == InputTarget::CONTENT |
| 626 ? &VrShell::ProcessContentGesture | 700 ? &VrShell::ProcessContentGesture |
| 627 : &VrShell::ProcessUIGesture; | 701 : &VrShell::ProcessUIGesture; |
| 628 main_thread_task_runner_->PostTask( | 702 main_thread_task_runner_->PostTask( |
| 629 FROM_HERE, | 703 FROM_HERE, |
| 630 base::Bind(target, weak_vr_shell_, base::Passed(std::move(event)))); | 704 base::Bind(target, weak_vr_shell_, base::Passed(std::move(event)))); |
| 631 } | 705 } |
| 632 | 706 |
| 633 void VrShellGl::DrawFrame() { | 707 void VrShellGl::DrawFrame(int frame_index) { |
| 634 TRACE_EVENT0("gpu", "VrShellGl::DrawFrame"); | 708 TRACE_EVENT0("gpu", "VrShellGl::DrawFrame"); |
| 635 | 709 |
| 636 // 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 |
| 637 // primary buffer each frame. Head-locked viewports get added by | 711 // primary buffer each frame. Head-locked viewports get added by |
| 638 // DrawVrShell if needed. | 712 // DrawVrShell if needed. |
| 639 buffer_viewport_list_->SetToRecommendedBufferViewports(); | 713 buffer_viewport_list_->SetToRecommendedBufferViewports(); |
| 640 | 714 |
| 715 TRACE_EVENT_BEGIN0("gpu", "VrShellGl::AcquireFrame"); |
| 641 gvr::Frame frame = swap_chain_->AcquireFrame(); | 716 gvr::Frame frame = swap_chain_->AcquireFrame(); |
| 717 TRACE_EVENT_END0("gpu", "VrShellGl::AcquireFrame"); |
| 642 if (!frame.is_valid()) { | 718 if (!frame.is_valid()) { |
| 643 return; | 719 return; |
| 644 } | 720 } |
| 645 frame.BindBuffer(kFramePrimaryBuffer); | 721 frame.BindBuffer(kFramePrimaryBuffer); |
| 646 if (web_vr_mode_) { | 722 if (web_vr_mode_) { |
| 647 DrawWebVr(); | 723 DrawWebVr(); |
| 648 } | 724 } |
| 649 | 725 |
| 650 uint16_t frame_index; | |
| 651 gvr::Mat4f head_pose; | 726 gvr::Mat4f head_pose; |
| 652 | 727 |
| 653 // When using async reprojection, we need to know which pose was used in | 728 // 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 | 729 // the WebVR app for drawing this frame. Due to unknown amounts of |
| 655 // buffering in the compositor and SurfaceTexture, we read the pose number | 730 // 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 | 731 // 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 | 732 // distortion rendering since that doesn't need a pose, and reading back |
| 658 // pixels is an expensive operation. TODO(klausw,crbug.com/655722): stop | 733 // pixels is an expensive operation. TODO(klausw,crbug.com/655722): stop |
| 659 // doing this once we have working no-compositor rendering for WebVR. | 734 // doing this once we have working no-compositor rendering for WebVR. |
| 660 if (web_vr_mode_ && gvr_api_->GetAsyncReprojectionEnabled() && | 735 if (web_vr_mode_ && gvr_api_->GetAsyncReprojectionEnabled()) { |
| 661 GetPixelEncodedFrameIndex(&frame_index)) { | |
| 662 static_assert(!((kPoseRingBufferSize - 1) & kPoseRingBufferSize), | 736 static_assert(!((kPoseRingBufferSize - 1) & kPoseRingBufferSize), |
| 663 "kPoseRingBufferSize must be a power of 2"); | 737 "kPoseRingBufferSize must be a power of 2"); |
| 664 head_pose = webvr_head_pose_[frame_index % kPoseRingBufferSize]; | 738 head_pose = webvr_head_pose_[frame_index % kPoseRingBufferSize]; |
| 665 // Process all pending_bounds_ changes targeted for before this frame, being | 739 // Process all pending_bounds_ changes targeted for before this frame, being |
| 666 // careful of wrapping frame indices. | 740 // careful of wrapping frame indices. |
| 667 static constexpr unsigned max = | 741 static constexpr unsigned max = |
| 668 std::numeric_limits<decltype(frame_index_)>::max(); | 742 std::numeric_limits<decltype(frame_index_)>::max(); |
| 669 static_assert(max > kPoseRingBufferSize * 2, | 743 static_assert(max > kPoseRingBufferSize * 2, |
| 670 "To detect wrapping, kPoseRingBufferSize must be smaller " | 744 "To detect wrapping, kPoseRingBufferSize must be smaller " |
| 671 "than half of frame_index_ range."); | 745 "than half of frame_index_ range."); |
| 672 while (!pending_bounds_.empty()) { | 746 while (!pending_bounds_.empty()) { |
| 673 uint16_t index = pending_bounds_.front().first; | 747 uint16_t index = pending_bounds_.front().first; |
| 748 VLOG(1) << __FUNCTION__ << ";;; new bounds, index=" << index; |
| 674 // If index is less than the frame_index it's possible we've wrapped, so | 749 // 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. | 750 // we extend the range and 'un-wrap' to account for this. |
| 676 if (index < frame_index) | 751 if (index < frame_index) |
| 677 index += max; | 752 index += max; |
| 678 // If the pending bounds change is for an upcoming frame within our buffer | 753 // If the pending bounds change is for an upcoming frame within our buffer |
| 679 // size, wait to apply it. Otherwise, apply it immediately. This | 754 // 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 | 755 // guarantees that even if we miss many frames, the queue can't fill up |
| 681 // with stale bounds. | 756 // with stale bounds. |
| 682 if (index > frame_index && index <= frame_index + kPoseRingBufferSize) | 757 if (index > frame_index && index <= frame_index + kPoseRingBufferSize) |
| 683 break; | 758 break; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 706 // it. For now, removing it seems working fine. | 781 // it. For now, removing it seems working fine. |
| 707 gvr_api_->ApplyNeckModel(head_pose, 1.0f); | 782 gvr_api_->ApplyNeckModel(head_pose, 1.0f); |
| 708 } | 783 } |
| 709 | 784 |
| 710 // Update the render position of all UI elements (including desktop). | 785 // Update the render position of all UI elements (including desktop). |
| 711 const float screen_tilt = kDesktopScreenTiltDefault * M_PI / 180.0f; | 786 const float screen_tilt = kDesktopScreenTiltDefault * M_PI / 180.0f; |
| 712 scene_->UpdateTransforms(screen_tilt, TimeInMicroseconds()); | 787 scene_->UpdateTransforms(screen_tilt, TimeInMicroseconds()); |
| 713 | 788 |
| 714 UpdateController(GetForwardVector(head_pose)); | 789 UpdateController(GetForwardVector(head_pose)); |
| 715 | 790 |
| 716 DrawVrShell(head_pose, frame); | 791 // Drawing VrShell causes GL error 0x501 GL_INVALID_VALUE while in |
| 792 // WebVR mode. FIXME. |
| 793 if (!web_vr_mode_) DrawVrShell(head_pose, frame); |
| 717 | 794 |
| 718 frame.Unbind(); | 795 frame.Unbind(); |
| 719 frame.Submit(*buffer_viewport_list_, head_pose); | 796 frame.Submit(*buffer_viewport_list_, head_pose); |
| 720 | 797 |
| 721 // No need to swap buffers for surfaceless rendering. | 798 // No need to swap buffers for surfaceless rendering. |
| 722 if (!surfaceless_rendering_) { | 799 if (!surfaceless_rendering_) { |
| 723 // TODO(mthiesse): Support asynchronous SwapBuffers. | 800 // TODO(mthiesse): Support asynchronous SwapBuffers. |
| 724 surface_->SwapBuffers(); | 801 surface_->SwapBuffers(); |
| 725 } | 802 } |
| 726 } | 803 } |
| 727 | 804 |
| 805 void VrShellGl::ScheduleWebVRFrame(int frame_index) { |
| 806 VLOG(1) << __FUNCTION__ << ";;; schedule frame=" << frame_index; |
| 807 pending_frames_.emplace(frame_index); |
| 808 } |
| 809 |
| 810 void VrShellGl::DropWebVRFrame(int frame_index) { |
| 811 VLOG(1) << __FUNCTION__ << ";;; drop frame=" << frame_index; |
| 812 if (requested_frames_ > 0) { |
| 813 VLOG(1) << __FUNCTION__ << ";;; requested_frames " << requested_frames_ << |
| 814 " => " << (requested_frames_ - 1); |
| 815 --requested_frames_; |
| 816 } |
| 817 } |
| 818 |
| 728 void VrShellGl::DrawVrShell(const gvr::Mat4f& head_pose, gvr::Frame& frame) { | 819 void VrShellGl::DrawVrShell(const gvr::Mat4f& head_pose, gvr::Frame& frame) { |
| 729 TRACE_EVENT0("gpu", "VrShellGl::DrawVrShell"); | 820 TRACE_EVENT0("gpu", "VrShellGl::DrawVrShell"); |
| 730 std::vector<const ContentRectangle*> head_locked_elements; | 821 std::vector<const ContentRectangle*> head_locked_elements; |
| 731 std::vector<const ContentRectangle*> world_elements; | 822 std::vector<const ContentRectangle*> world_elements; |
| 732 for (const auto& rect : scene_->GetUiElements()) { | 823 for (const auto& rect : scene_->GetUiElements()) { |
| 733 if (!rect->IsVisible()) | 824 if (!rect->IsVisible()) |
| 734 continue; | 825 continue; |
| 735 if (rect->lock_to_fov) { | 826 if (rect->lock_to_fov) { |
| 736 head_locked_elements.push_back(rect.get()); | 827 head_locked_elements.push_back(rect.get()); |
| 737 } else { | 828 } else { |
| (...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1022 } | 1113 } |
| 1023 } | 1114 } |
| 1024 | 1115 |
| 1025 void VrShellGl::SetWebVrMode(bool enabled) { | 1116 void VrShellGl::SetWebVrMode(bool enabled) { |
| 1026 web_vr_mode_ = enabled; | 1117 web_vr_mode_ = enabled; |
| 1027 } | 1118 } |
| 1028 | 1119 |
| 1029 void VrShellGl::UpdateWebVRTextureBounds(int16_t frame_index, | 1120 void VrShellGl::UpdateWebVRTextureBounds(int16_t frame_index, |
| 1030 const gvr::Rectf& left_bounds, | 1121 const gvr::Rectf& left_bounds, |
| 1031 const gvr::Rectf& right_bounds) { | 1122 const gvr::Rectf& right_bounds) { |
| 1123 VLOG(1) << __FUNCTION__ << ";;; frame_index=" << frame_index << |
| 1124 " left=" << left_bounds.left << "," << left_bounds.bottom << |
| 1125 "," << left_bounds.right << "," << left_bounds.top << |
| 1126 " right=" << right_bounds.left << "," << right_bounds.bottom << |
| 1127 "," << right_bounds.right << "," << right_bounds.top; |
| 1032 if (frame_index < 0) { | 1128 if (frame_index < 0) { |
| 1033 webvr_left_viewport_->SetSourceUv(left_bounds); | 1129 webvr_left_viewport_->SetSourceUv(left_bounds); |
| 1034 webvr_right_viewport_->SetSourceUv(right_bounds); | 1130 webvr_right_viewport_->SetSourceUv(right_bounds); |
| 1035 } else { | 1131 } else { |
| 1036 pending_bounds_.emplace( | 1132 pending_bounds_.emplace( |
| 1037 std::make_pair(frame_index, std::make_pair(left_bounds, right_bounds))); | 1133 std::make_pair(frame_index, std::make_pair(left_bounds, right_bounds))); |
| 1038 } | 1134 } |
| 1039 } | 1135 } |
| 1040 | 1136 |
| 1041 void VrShellGl::ContentBoundsChanged(int width, int height) { | 1137 void VrShellGl::ContentBoundsChanged(int width, int height) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1061 ui_surface_texture_->SetDefaultBufferSize(width, height); | 1157 ui_surface_texture_->SetDefaultBufferSize(width, height); |
| 1062 ui_tex_physical_size_.width = width; | 1158 ui_tex_physical_size_.width = width; |
| 1063 ui_tex_physical_size_.height = height; | 1159 ui_tex_physical_size_.height = height; |
| 1064 } | 1160 } |
| 1065 | 1161 |
| 1066 base::WeakPtr<VrShellGl> VrShellGl::GetWeakPtr() { | 1162 base::WeakPtr<VrShellGl> VrShellGl::GetWeakPtr() { |
| 1067 return weak_ptr_factory_.GetWeakPtr(); | 1163 return weak_ptr_factory_.GetWeakPtr(); |
| 1068 } | 1164 } |
| 1069 | 1165 |
| 1070 void VrShellGl::OnVSync() { | 1166 void VrShellGl::OnVSync() { |
| 1167 while (premature_received_frames_ > 0) { |
| 1168 VLOG(1) << __FUNCTION__ << ";;; Retrying premature received frame " << |
| 1169 premature_received_frames_ << " => " << |
| 1170 (premature_received_frames_ - 1); |
| 1171 --premature_received_frames_; |
| 1172 OnWebVRFrameAvailable(); |
| 1173 } |
| 1174 |
| 1071 base::TimeTicks now = base::TimeTicks::Now(); | 1175 base::TimeTicks now = base::TimeTicks::Now(); |
| 1072 base::TimeTicks target; | 1176 base::TimeTicks target; |
| 1073 | 1177 |
| 1074 // Don't send VSyncs until we have a timebase/interval. | 1178 // Don't send VSyncs until we have a timebase/interval. |
| 1075 if (vsync_interval_.is_zero()) | 1179 if (vsync_interval_.is_zero()) |
| 1076 return; | 1180 return; |
| 1077 target = now + vsync_interval_; | 1181 target = now + vsync_interval_; |
| 1078 int64_t intervals = (target - vsync_timebase_) / vsync_interval_; | 1182 int64_t intervals = (target - vsync_timebase_) / vsync_interval_; |
| 1079 target = vsync_timebase_ + intervals * vsync_interval_; | 1183 target = vsync_timebase_ + intervals * vsync_interval_; |
| 1080 task_runner_->PostDelayedTask(FROM_HERE, vsync_task_.callback(), | 1184 task_runner_->PostDelayedTask(FROM_HERE, vsync_task_.callback(), |
| 1081 target - now); | 1185 target - now); |
| 1082 | 1186 |
| 1083 base::TimeDelta time = intervals * vsync_interval_; | 1187 base::TimeDelta time = intervals * vsync_interval_; |
| 1188 // Send a small rate of vsyncs even while backlogged to avoid |
| 1189 // locking up when the rAF loop doesn't submit a frame. |
| 1190 static int skip_counter = 0; |
| 1084 if (!callback_.is_null()) { | 1191 if (!callback_.is_null()) { |
| 1085 SendVSync(time, base::ResetAndReturn(&callback_)); | 1192 if (requested_frames_ < 1 || (++skip_counter % 30) == 0) { |
| 1193 VLOG(1) << __FUNCTION__ << ";;; vsync B, interval=" << vsync_interval_; |
| 1194 SendVSync(time, base::ResetAndReturn(&callback_)); |
| 1195 } else { |
| 1196 VLOG(1) << __FUNCTION__ << ";;; Skip vsync B, already have frame requested
"; |
| 1197 return; |
| 1198 } |
| 1086 } else { | 1199 } else { |
| 1087 pending_vsync_ = true; | 1200 pending_vsync_ = true; |
| 1088 pending_time_ = time; | 1201 pending_time_ = time; |
| 1089 } | 1202 } |
| 1090 DrawFrame(); | 1203 if (!web_vr_mode_) { |
| 1204 DrawFrame(-1); |
| 1205 } |
| 1091 } | 1206 } |
| 1092 | 1207 |
| 1093 void VrShellGl::OnRequest(device::mojom::VRVSyncProviderRequest request) { | 1208 void VrShellGl::OnRequest(device::mojom::VRVSyncProviderRequest request) { |
| 1094 binding_.Close(); | 1209 binding_.Close(); |
| 1095 binding_.Bind(std::move(request)); | 1210 binding_.Bind(std::move(request)); |
| 1096 } | 1211 } |
| 1097 | 1212 |
| 1098 void VrShellGl::GetVSync(const GetVSyncCallback& callback) { | 1213 void VrShellGl::GetVSync(const GetVSyncCallback& callback) { |
| 1099 if (!pending_vsync_) { | 1214 if (!pending_vsync_) { |
| 1100 if (!callback_.is_null()) { | 1215 if (!callback_.is_null()) { |
| 1101 mojo::ReportBadMessage( | 1216 mojo::ReportBadMessage( |
| 1102 "Requested VSync before waiting for response to previous request."); | 1217 "Requested VSync before waiting for response to previous request."); |
| 1103 binding_.Close(); | 1218 binding_.Close(); |
| 1104 return; | 1219 return; |
| 1105 } | 1220 } |
| 1106 callback_ = callback; | 1221 callback_ = callback; |
| 1107 return; | 1222 return; |
| 1108 } | 1223 } |
| 1109 pending_vsync_ = false; | 1224 pending_vsync_ = false; |
| 1225 VLOG(1) << __FUNCTION__ << ";;; vsync A, pending time=" << pending_time_; |
| 1110 SendVSync(pending_time_, callback); | 1226 SendVSync(pending_time_, callback); |
| 1111 } | 1227 } |
| 1112 | 1228 |
| 1113 void VrShellGl::UpdateVSyncInterval(int64_t timebase_nanos, | 1229 void VrShellGl::UpdateVSyncInterval(int64_t timebase_nanos, |
| 1114 double interval_seconds) { | 1230 double interval_seconds) { |
| 1115 vsync_timebase_ = base::TimeTicks(); | 1231 vsync_timebase_ = base::TimeTicks(); |
| 1116 vsync_timebase_ += base::TimeDelta::FromMicroseconds(timebase_nanos / 1000); | 1232 vsync_timebase_ += base::TimeDelta::FromMicroseconds(timebase_nanos / 1000); |
| 1117 vsync_interval_ = base::TimeDelta::FromSecondsD(interval_seconds); | 1233 vsync_interval_ = base::TimeDelta::FromSecondsD(interval_seconds); |
| 1118 vsync_task_.Reset(base::Bind(&VrShellGl::OnVSync, base::Unretained(this))); | 1234 vsync_task_.Reset(base::Bind(&VrShellGl::OnVSync, base::Unretained(this))); |
| 1235 VLOG(1) << __FUNCTION__ << ";;; vsync_interval=" << vsync_interval_; |
| 1119 OnVSync(); | 1236 OnVSync(); |
| 1120 } | 1237 } |
| 1121 | 1238 |
| 1122 void VrShellGl::ForceExitVr() { | 1239 void VrShellGl::ForceExitVr() { |
| 1123 main_thread_task_runner_->PostTask( | 1240 main_thread_task_runner_->PostTask( |
| 1124 FROM_HERE, base::Bind(&VrShell::ForceExitVr, weak_vr_shell_)); | 1241 FROM_HERE, base::Bind(&VrShell::ForceExitVr, weak_vr_shell_)); |
| 1125 } | 1242 } |
| 1126 | 1243 |
| 1127 void VrShellGl::UpdateScene(std::unique_ptr<base::ListValue> commands) { | 1244 void VrShellGl::UpdateScene(std::unique_ptr<base::ListValue> commands) { |
| 1128 scene_->HandleCommands(std::move(commands), TimeInMicroseconds()); | 1245 scene_->HandleCommands(std::move(commands), TimeInMicroseconds()); |
| 1129 } | 1246 } |
| 1130 | 1247 |
| 1131 void VrShellGl::SendVSync(base::TimeDelta time, | 1248 void VrShellGl::SendVSync(base::TimeDelta time, |
| 1132 const GetVSyncCallback& callback) { | 1249 const GetVSyncCallback& callback) { |
| 1133 TRACE_EVENT0("input", "VrShellGl::SendVSync"); | 1250 TRACE_EVENT0("input", "VrShellGl::SendVSync"); |
| 1134 | 1251 |
| 1252 VLOG(1) << __FUNCTION__ << ";;; requested_frames " << requested_frames_ << |
| 1253 " => " << (requested_frames_ + 1); |
| 1254 ++requested_frames_; |
| 1255 |
| 1135 uint8_t frame_index = frame_index_++; | 1256 uint8_t frame_index = frame_index_++; |
| 1257 VLOG(1) << __FUNCTION__ << ";;; vsync for frame=" << (int)frame_index; |
| 1136 | 1258 |
| 1137 gvr::ClockTimePoint target_time = gvr::GvrApi::GetTimePointNow(); | 1259 gvr::ClockTimePoint target_time = gvr::GvrApi::GetTimePointNow(); |
| 1138 target_time.monotonic_system_time_nanos += kPredictionTimeWithoutVsyncNanos; | 1260 target_time.monotonic_system_time_nanos += kPredictionTimeWithoutVsyncNanos; |
| 1139 | 1261 |
| 1140 gvr::Mat4f head_mat = | 1262 gvr::Mat4f head_mat = |
| 1141 gvr_api_->GetHeadSpaceFromStartSpaceRotation(target_time); | 1263 gvr_api_->GetHeadSpaceFromStartSpaceRotation(target_time); |
| 1142 head_mat = gvr_api_->ApplyNeckModel(head_mat, 1.0f); | 1264 head_mat = gvr_api_->ApplyNeckModel(head_mat, 1.0f); |
| 1143 | 1265 |
| 1144 webvr_head_pose_[frame_index % kPoseRingBufferSize] = head_mat; | 1266 webvr_head_pose_[frame_index % kPoseRingBufferSize] = head_mat; |
| 1145 | 1267 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1158 const base::Callback<void(device::mojom::VRDisplayInfoPtr)>& callback, | 1280 const base::Callback<void(device::mojom::VRDisplayInfoPtr)>& callback, |
| 1159 uint32_t device_id) { | 1281 uint32_t device_id) { |
| 1160 device::mojom::VRDisplayInfoPtr info = VrShell::CreateVRDisplayInfo( | 1282 device::mojom::VRDisplayInfoPtr info = VrShell::CreateVRDisplayInfo( |
| 1161 gvr_api_.get(), content_tex_physical_size_, device_id); | 1283 gvr_api_.get(), content_tex_physical_size_, device_id); |
| 1162 main_thread_task_runner_->PostTask( | 1284 main_thread_task_runner_->PostTask( |
| 1163 FROM_HERE, | 1285 FROM_HERE, |
| 1164 base::Bind(&RunVRDisplayInfoCallback, callback, base::Passed(&info))); | 1286 base::Bind(&RunVRDisplayInfoCallback, callback, base::Passed(&info))); |
| 1165 } | 1287 } |
| 1166 | 1288 |
| 1167 } // namespace vr_shell | 1289 } // namespace vr_shell |
| OLD | NEW |