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 "base/android/jni_android.h" | 7 #include "base/android/jni_android.h" |
8 #include "base/memory/ptr_util.h" | 8 #include "base/memory/ptr_util.h" |
9 #include "base/metrics/histogram_macros.h" | 9 #include "base/metrics/histogram_macros.h" |
10 #include "base/threading/thread_task_runner_handle.h" | 10 #include "base/threading/thread_task_runner_handle.h" |
11 #include "chrome/browser/android/vr_shell/ui_elements.h" | 11 #include "chrome/browser/android/vr_shell/ui_elements.h" |
12 #include "chrome/browser/android/vr_shell/ui_scene.h" | 12 #include "chrome/browser/android/vr_shell/ui_scene.h" |
13 #include "chrome/browser/android/vr_shell/vr_controller.h" | 13 #include "chrome/browser/android/vr_shell/vr_controller.h" |
14 #include "chrome/browser/android/vr_shell/vr_gl_util.h" | 14 #include "chrome/browser/android/vr_shell/vr_gl_util.h" |
15 #include "chrome/browser/android/vr_shell/vr_input_manager.h" | 15 #include "chrome/browser/android/vr_shell/vr_input_manager.h" |
16 #include "chrome/browser/android/vr_shell/vr_math.h" | 16 #include "chrome/browser/android/vr_shell/vr_math.h" |
17 #include "chrome/browser/android/vr_shell/vr_shell.h" | 17 #include "chrome/browser/android/vr_shell/vr_shell.h" |
18 #include "chrome/browser/android/vr_shell/vr_shell_renderer.h" | 18 #include "chrome/browser/android/vr_shell/vr_shell_renderer.h" |
19 #include "third_party/WebKit/public/platform/WebInputEvent.h" | 19 #include "third_party/WebKit/public/platform/WebInputEvent.h" |
| 20 #include "ui/gfx/transform.h" |
| 21 #include "ui/gfx/transform_util.h" |
20 #include "ui/gfx/vsync_provider.h" | 22 #include "ui/gfx/vsync_provider.h" |
21 #include "ui/gl/android/scoped_java_surface.h" | 23 #include "ui/gl/android/scoped_java_surface.h" |
22 #include "ui/gl/android/surface_texture.h" | 24 #include "ui/gl/android/surface_texture.h" |
23 #include "ui/gl/gl_bindings.h" | 25 #include "ui/gl/gl_bindings.h" |
24 #include "ui/gl/gl_context.h" | 26 #include "ui/gl/gl_context.h" |
25 #include "ui/gl/gl_surface.h" | 27 #include "ui/gl/gl_surface.h" |
26 #include "ui/gl/init/gl_factory.h" | 28 #include "ui/gl/init/gl_factory.h" |
27 | 29 |
28 namespace vr_shell { | 30 namespace vr_shell { |
29 | 31 |
30 namespace { | 32 namespace { |
31 // Constant taken from treasure_hunt demo. | 33 // TODO(mthiesse): If gvr::PlatformInfo().GetPosePredictionTime() is ever |
| 34 // exposed, use that instead (it defaults to 50ms on most platforms). |
32 static constexpr long kPredictionTimeWithoutVsyncNanos = 50000000; | 35 static constexpr long kPredictionTimeWithoutVsyncNanos = 50000000; |
33 | 36 |
34 static constexpr float kZNear = 0.1f; | 37 static constexpr float kZNear = 0.1f; |
35 static constexpr float kZFar = 1000.0f; | 38 static constexpr float kZFar = 1000.0f; |
36 | 39 |
37 // Screen angle in degrees. 0 = vertical, positive = top closer. | 40 // Screen angle in degrees. 0 = vertical, positive = top closer. |
38 static constexpr float kDesktopScreenTiltDefault = 0; | 41 static constexpr float kDesktopScreenTiltDefault = 0; |
39 | 42 |
40 static constexpr float kReticleWidth = 0.025f; | 43 static constexpr float kReticleWidth = 0.025f; |
41 static constexpr float kReticleHeight = 0.025f; | 44 static constexpr float kReticleHeight = 0.025f; |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
135 return mouse_event; | 138 return mouse_event; |
136 } | 139 } |
137 | 140 |
138 enum class ViewerType { | 141 enum class ViewerType { |
139 UNKNOWN_TYPE = 0, | 142 UNKNOWN_TYPE = 0, |
140 CARDBOARD = 1, | 143 CARDBOARD = 1, |
141 DAYDREAM = 2, | 144 DAYDREAM = 2, |
142 VIEWER_TYPE_MAX, | 145 VIEWER_TYPE_MAX, |
143 }; | 146 }; |
144 | 147 |
145 int GetPixelEncodedPoseIndexByte() { | 148 bool GetPixelEncodedPoseIndexByte(int* pose_index) { |
146 TRACE_EVENT0("gpu", "VrShellGl::GetPixelEncodedPoseIndex"); | 149 TRACE_EVENT0("gpu", "VrShellGl::GetPixelEncodedPoseIndex"); |
147 // Read the pose index encoded in a bottom left pixel as color values. | 150 // Read the pose index encoded in a bottom left pixel as color values. |
148 // See also third_party/WebKit/Source/modules/vr/VRDisplay.cpp which | 151 // See also third_party/WebKit/Source/modules/vr/VRDisplay.cpp which |
149 // encodes the pose index, and device/vr/android/gvr/gvr_device.cc | 152 // encodes the pose index, and device/vr/android/gvr/gvr_device.cc |
150 // which tracks poses. Returns the low byte (0..255) if valid, or -1 | 153 // which tracks poses. Returns the low byte (0..255) if valid, or -1 |
151 // if not valid due to bad magic number. | 154 // if not valid due to bad magic number. |
152 uint8_t pixels[4]; | 155 uint8_t pixels[4]; |
153 // Assume we're reading from the framebuffer we just wrote to. | 156 // Assume we're reading from the framebuffer we just wrote to. |
154 // That's true currently, we may need to use glReadBuffer(GL_BACK) | 157 // That's true currently, we may need to use glReadBuffer(GL_BACK) |
155 // or equivalent if the rendering setup changes in the future. | 158 // or equivalent if the rendering setup changes in the future. |
156 glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels); | 159 glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels); |
157 | 160 |
158 // Check for the magic number written by VRDevice.cpp on submit. | 161 // Check for the magic number written by VRDevice.cpp on submit. |
159 // This helps avoid glitches from garbage data in the render | 162 // This helps avoid glitches from garbage data in the render |
160 // buffer that can appear during initialization or resizing. These | 163 // buffer that can appear during initialization or resizing. These |
161 // often appear as flashes of all-black or all-white pixels. | 164 // often appear as flashes of all-black or all-white pixels. |
162 if (pixels[1] == kWebVrPosePixelMagicNumbers[0] && | 165 if (pixels[1] == kWebVrPosePixelMagicNumbers[0] && |
163 pixels[2] == kWebVrPosePixelMagicNumbers[1]) { | 166 pixels[2] == kWebVrPosePixelMagicNumbers[1]) { |
164 // Pose is good. | 167 // Pose is good. |
165 return pixels[0]; | 168 *pose_index = pixels[0]; |
| 169 return true; |
166 } | 170 } |
167 VLOG(1) << "WebVR: reject decoded pose index " << (int)pixels[0] << | 171 VLOG(1) << "WebVR: reject decoded pose index " << (int)pixels[0] |
168 ", bad magic number " << (int)pixels[1] << ", " << (int)pixels[2]; | 172 << ", bad magic number " << (int)pixels[1] << ", " |
169 return -1; | 173 << (int)pixels[2]; |
| 174 return false; |
170 } | 175 } |
171 | 176 |
172 int64_t TimeInMicroseconds() { | 177 int64_t TimeInMicroseconds() { |
173 return std::chrono::duration_cast<std::chrono::microseconds>( | 178 return std::chrono::duration_cast<std::chrono::microseconds>( |
174 std::chrono::steady_clock::now().time_since_epoch()).count(); | 179 std::chrono::steady_clock::now().time_since_epoch()).count(); |
175 } | 180 } |
176 | 181 |
177 void WaitForSwapAck(const base::Closure& callback, gfx::SwapResult result) { | 182 void WaitForSwapAck(const base::Closure& callback, gfx::SwapResult result) { |
178 callback.Run(); | 183 callback.Run(); |
179 } | 184 } |
(...skipping 17 matching lines...) Expand all Loading... |
197 main_thread_task_runner_(std::move(main_thread_task_runner)), | 202 main_thread_task_runner_(std::move(main_thread_task_runner)), |
198 weak_ptr_factory_(this) { | 203 weak_ptr_factory_(this) { |
199 GvrInit(gvr_api); | 204 GvrInit(gvr_api); |
200 } | 205 } |
201 | 206 |
202 VrShellGl::~VrShellGl() { | 207 VrShellGl::~VrShellGl() { |
203 draw_task_.Cancel(); | 208 draw_task_.Cancel(); |
204 } | 209 } |
205 | 210 |
206 void VrShellGl::Initialize() { | 211 void VrShellGl::Initialize() { |
207 gvr::Mat4f identity; | |
208 SetIdentityM(identity); | |
209 webvr_head_pose_.resize(kPoseRingBufferSize, identity); | |
210 webvr_head_pose_valid_.resize(kPoseRingBufferSize, false); | |
211 | |
212 scene_.reset(new UiScene); | 212 scene_.reset(new UiScene); |
213 | 213 |
214 if (surfaceless_rendering_) { | 214 if (surfaceless_rendering_) { |
215 // If we're rendering surfaceless, we'll never get a java surface to render | 215 // If we're rendering surfaceless, we'll never get a java surface to render |
216 // into, so we can initialize GL right away. | 216 // into, so we can initialize GL right away. |
217 InitializeGl(nullptr); | 217 InitializeGl(nullptr); |
218 } | 218 } |
219 } | 219 } |
220 | 220 |
221 void VrShellGl::InitializeGl(gfx::AcceleratedWidget window) { | 221 void VrShellGl::InitializeGl(gfx::AcceleratedWidget window) { |
(...skipping 22 matching lines...) Expand all Loading... |
244 LOG(ERROR) << "gl::init::CreateGLContext failed"; | 244 LOG(ERROR) << "gl::init::CreateGLContext failed"; |
245 ForceExitVr(); | 245 ForceExitVr(); |
246 return; | 246 return; |
247 } | 247 } |
248 if (!context_->MakeCurrent(surface_.get())) { | 248 if (!context_->MakeCurrent(surface_.get())) { |
249 LOG(ERROR) << "gl::GLContext::MakeCurrent() failed"; | 249 LOG(ERROR) << "gl::GLContext::MakeCurrent() failed"; |
250 ForceExitVr(); | 250 ForceExitVr(); |
251 return; | 251 return; |
252 } | 252 } |
253 | 253 |
254 // TODO(mthiesse): We don't appear to have a VSync provider ever here. This is | |
255 // sort of okay, because the GVR swap chain will block if we render too fast, | |
256 // but we should address this properly. | |
257 if (surface_->GetVSyncProvider()) { | |
258 surface_->GetVSyncProvider()->GetVSyncParameters(base::Bind( | |
259 &VrShellGl::UpdateVSyncParameters, weak_ptr_factory_.GetWeakPtr())); | |
260 } else { | |
261 LOG(ERROR) << "No VSync Provider"; | |
262 } | |
263 | |
264 unsigned int textures[2]; | 254 unsigned int textures[2]; |
265 glGenTextures(2, textures); | 255 glGenTextures(2, textures); |
266 ui_texture_id_ = textures[0]; | 256 ui_texture_id_ = textures[0]; |
267 content_texture_id_ = textures[1]; | 257 content_texture_id_ = textures[1]; |
268 ui_surface_texture_ = gl::SurfaceTexture::Create(ui_texture_id_); | 258 ui_surface_texture_ = gl::SurfaceTexture::Create(ui_texture_id_); |
269 content_surface_texture_ = gl::SurfaceTexture::Create(content_texture_id_); | 259 content_surface_texture_ = gl::SurfaceTexture::Create(content_texture_id_); |
270 ui_surface_.reset(new gl::ScopedJavaSurface(ui_surface_texture_.get())); | 260 ui_surface_.reset(new gl::ScopedJavaSurface(ui_surface_texture_.get())); |
271 content_surface_.reset(new gl::ScopedJavaSurface( | 261 content_surface_.reset(new gl::ScopedJavaSurface( |
272 content_surface_texture_.get())); | 262 content_surface_texture_.get())); |
273 ui_surface_texture_->SetFrameAvailableCallback(base::Bind( | 263 ui_surface_texture_->SetFrameAvailableCallback(base::Bind( |
274 &VrShellGl::OnUIFrameAvailable, weak_ptr_factory_.GetWeakPtr())); | 264 &VrShellGl::OnUIFrameAvailable, weak_ptr_factory_.GetWeakPtr())); |
275 content_surface_texture_->SetFrameAvailableCallback(base::Bind( | 265 content_surface_texture_->SetFrameAvailableCallback(base::Bind( |
276 &VrShellGl::OnContentFrameAvailable, weak_ptr_factory_.GetWeakPtr())); | 266 &VrShellGl::OnContentFrameAvailable, weak_ptr_factory_.GetWeakPtr())); |
277 | 267 |
278 content_surface_texture_->SetDefaultBufferSize( | 268 content_surface_texture_->SetDefaultBufferSize( |
279 content_tex_physical_size_.width, content_tex_physical_size_.height); | 269 content_tex_physical_size_.width, content_tex_physical_size_.height); |
280 ui_surface_texture_->SetDefaultBufferSize(ui_tex_physical_size_.width, | 270 ui_surface_texture_->SetDefaultBufferSize(ui_tex_physical_size_.width, |
281 ui_tex_physical_size_.height); | 271 ui_tex_physical_size_.height); |
282 | 272 |
283 main_thread_task_runner_->PostTask(FROM_HERE, base::Bind( | 273 main_thread_task_runner_->PostTask(FROM_HERE, base::Bind( |
284 &VrShell::SurfacesChanged, weak_vr_shell_, | 274 &VrShell::SurfacesChanged, weak_vr_shell_, |
285 content_surface_->j_surface().obj(), | 275 content_surface_->j_surface().obj(), |
286 ui_surface_->j_surface().obj())); | 276 ui_surface_->j_surface().obj())); |
287 | 277 |
288 InitializeRenderer(); | 278 InitializeRenderer(); |
289 | 279 |
290 draw_task_.Reset(base::Bind(&VrShellGl::DrawFrame, base::Unretained(this))); | 280 draw_task_.Reset(base::Bind(&VrShellGl::DrawFrame, base::Unretained(this))); |
291 ScheduleNextDrawFrame(); | 281 ScheduleNextDrawFrame(); |
292 | 282 |
| 283 main_thread_task_runner_->PostTask(FROM_HERE, base::Bind( |
| 284 &VrShell::OnVRVsyncProviderReady, weak_vr_shell_)); |
| 285 |
293 ready_to_draw_ = true; | 286 ready_to_draw_ = true; |
294 } | 287 } |
295 | 288 |
296 void VrShellGl::OnUIFrameAvailable() { | 289 void VrShellGl::OnUIFrameAvailable() { |
297 ui_surface_texture_->UpdateTexImage(); | 290 ui_surface_texture_->UpdateTexImage(); |
298 } | 291 } |
299 | 292 |
300 void VrShellGl::OnContentFrameAvailable() { | 293 void VrShellGl::OnContentFrameAvailable() { |
301 content_surface_texture_->UpdateTexImage(); | 294 content_surface_texture_->UpdateTexImage(); |
302 } | 295 } |
(...skipping 18 matching lines...) Expand all Loading... |
321 UMA_HISTOGRAM_ENUMERATION("VRViewerType", static_cast<int>(viewerType), | 314 UMA_HISTOGRAM_ENUMERATION("VRViewerType", static_cast<int>(viewerType), |
322 static_cast<int>(ViewerType::VIEWER_TYPE_MAX)); | 315 static_cast<int>(ViewerType::VIEWER_TYPE_MAX)); |
323 } | 316 } |
324 | 317 |
325 void VrShellGl::InitializeRenderer() { | 318 void VrShellGl::InitializeRenderer() { |
326 // While WebVR is going through the compositor path, it shares | 319 // While WebVR is going through the compositor path, it shares |
327 // the same texture ID. This will change once it gets its own | 320 // the same texture ID. This will change once it gets its own |
328 // surface, but store it separately to avoid future confusion. | 321 // surface, but store it separately to avoid future confusion. |
329 // TODO(klausw,crbug.com/655722): remove this. | 322 // TODO(klausw,crbug.com/655722): remove this. |
330 webvr_texture_id_ = content_texture_id_; | 323 webvr_texture_id_ = content_texture_id_; |
331 // Out of paranoia, explicitly reset the "pose valid" flags to false | |
332 // from the GL thread. The constructor ran in the UI thread. | |
333 // TODO(klausw,crbug.com/655722): remove this. | |
334 webvr_head_pose_valid_.assign(kPoseRingBufferSize, false); | |
335 | 324 |
336 gvr_api_->InitializeGl(); | 325 gvr_api_->InitializeGl(); |
| 326 webvr_head_pose_.assign(kPoseRingBufferSize, |
| 327 gvr_api_->GetHeadSpaceFromStartSpaceRotation( |
| 328 gvr::GvrApi::GetTimePointNow())); |
| 329 |
337 std::vector<gvr::BufferSpec> specs; | 330 std::vector<gvr::BufferSpec> specs; |
338 // For kFramePrimaryBuffer (primary VrShell and WebVR content) | 331 // For kFramePrimaryBuffer (primary VrShell and WebVR content) |
339 specs.push_back(gvr_api_->CreateBufferSpec()); | 332 specs.push_back(gvr_api_->CreateBufferSpec()); |
340 render_size_primary_ = specs[kFramePrimaryBuffer].GetSize(); | 333 render_size_primary_ = specs[kFramePrimaryBuffer].GetSize(); |
341 | 334 |
342 // For kFrameHeadlockedBuffer (for WebVR insecure content warning). | 335 // For kFrameHeadlockedBuffer (for WebVR insecure content warning). |
343 // Set this up at fixed resolution, the (smaller) FOV gets set below. | 336 // Set this up at fixed resolution, the (smaller) FOV gets set below. |
344 specs.push_back(gvr_api_->CreateBufferSpec()); | 337 specs.push_back(gvr_api_->CreateBufferSpec()); |
345 specs.back().SetSize(kHeadlockedBufferDimensions); | 338 specs.back().SetSize(kHeadlockedBufferDimensions); |
346 render_size_headlocked_ = specs[kFrameHeadlockedBuffer].GetSize(); | 339 render_size_headlocked_ = specs[kFrameHeadlockedBuffer].GetSize(); |
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
586 DCHECK(input_target != InputTarget::NONE); | 579 DCHECK(input_target != InputTarget::NONE); |
587 const base::WeakPtr<VrInputManager>& weak_ptr = | 580 const base::WeakPtr<VrInputManager>& weak_ptr = |
588 input_target == InputTarget::CONTENT ? content_input_manager_ | 581 input_target == InputTarget::CONTENT ? content_input_manager_ |
589 : ui_input_manager_; | 582 : ui_input_manager_; |
590 main_thread_task_runner_->PostTask( | 583 main_thread_task_runner_->PostTask( |
591 FROM_HERE, | 584 FROM_HERE, |
592 base::Bind(&VrInputManager::ProcessUpdatedGesture, weak_ptr, | 585 base::Bind(&VrInputManager::ProcessUpdatedGesture, weak_ptr, |
593 base::Passed(std::move(event)))); | 586 base::Passed(std::move(event)))); |
594 } | 587 } |
595 | 588 |
596 void VrShellGl::SetGvrPoseForWebVr(const gvr::Mat4f& pose, uint32_t pose_num) { | |
597 webvr_head_pose_[pose_num % kPoseRingBufferSize] = pose; | |
598 webvr_head_pose_valid_[pose_num % kPoseRingBufferSize] = true; | |
599 } | |
600 | |
601 bool VrShellGl::WebVrPoseByteIsValid(int pose_index_byte) { | |
602 if (pose_index_byte < 0) { | |
603 return false; | |
604 } | |
605 if (!webvr_head_pose_valid_[pose_index_byte % kPoseRingBufferSize]) { | |
606 VLOG(1) << "WebVR: reject decoded pose index " << pose_index_byte << | |
607 ", not a valid pose"; | |
608 return false; | |
609 } | |
610 return true; | |
611 } | |
612 | |
613 void VrShellGl::DrawFrame() { | 589 void VrShellGl::DrawFrame() { |
614 TRACE_EVENT0("gpu", "VrShellGl::DrawFrame"); | 590 TRACE_EVENT0("gpu", "VrShellGl::DrawFrame"); |
| 591 |
615 // Reset the viewport list to just the pair of viewports for the | 592 // Reset the viewport list to just the pair of viewports for the |
616 // primary buffer each frame. Head-locked viewports get added by | 593 // primary buffer each frame. Head-locked viewports get added by |
617 // DrawVrShell if needed. | 594 // DrawVrShell if needed. |
618 buffer_viewport_list_->SetToRecommendedBufferViewports(); | 595 buffer_viewport_list_->SetToRecommendedBufferViewports(); |
619 | 596 |
620 gvr::Frame frame = swap_chain_->AcquireFrame(); | 597 gvr::Frame frame = swap_chain_->AcquireFrame(); |
621 gvr::ClockTimePoint target_time = gvr::GvrApi::GetTimePointNow(); | |
622 target_time.monotonic_system_time_nanos += kPredictionTimeWithoutVsyncNanos; | |
623 | 598 |
624 gvr::Mat4f head_pose = | 599 frame.BindBuffer(kFramePrimaryBuffer); |
625 gvr_api_->GetHeadSpaceFromStartSpaceRotation(target_time); | 600 if (web_vr_mode_) { |
| 601 DrawWebVr(); |
| 602 } |
| 603 |
| 604 int pose_index; |
| 605 gvr::Mat4f head_pose; |
| 606 |
| 607 // When using async reprojection, we need to know which pose was used in |
| 608 // the WebVR app for drawing this frame. Due to unknown amounts of |
| 609 // buffering in the compositor and SurfaceTexture, we read the pose number |
| 610 // from a corner pixel. There's no point in doing this for legacy |
| 611 // distortion rendering since that doesn't need a pose, and reading back |
| 612 // pixels is an expensive operation. TODO(klausw,crbug.com/655722): stop |
| 613 // doing this once we have working no-compositor rendering for WebVR. |
| 614 if (web_vr_mode_ && gvr_api_->GetAsyncReprojectionEnabled() && |
| 615 GetPixelEncodedPoseIndexByte(&pose_index)) { |
| 616 head_pose = webvr_head_pose_[pose_index % kPoseRingBufferSize]; |
| 617 } else { |
| 618 gvr::ClockTimePoint target_time = gvr::GvrApi::GetTimePointNow(); |
| 619 target_time.monotonic_system_time_nanos += kPredictionTimeWithoutVsyncNanos; |
| 620 head_pose = gvr_api_->GetHeadSpaceFromStartSpaceRotation(target_time); |
| 621 } |
626 | 622 |
627 gvr::Vec3f position = GetTranslation(head_pose); | 623 gvr::Vec3f position = GetTranslation(head_pose); |
628 if (position.x == 0.0f && position.y == 0.0f && position.z == 0.0f) { | 624 if (position.x == 0.0f && position.y == 0.0f && position.z == 0.0f) { |
629 // This appears to be a 3DOF pose without a neck model. Add one. | 625 // This appears to be a 3DOF pose without a neck model. Add one. |
630 // The head pose has redundant data. Assume we're only using the | 626 // The head pose has redundant data. Assume we're only using the |
631 // object_from_reference_matrix, we're not updating position_external. | 627 // object_from_reference_matrix, we're not updating position_external. |
632 // TODO: Not sure what object_from_reference_matrix is. The new api removed | 628 // TODO: Not sure what object_from_reference_matrix is. The new api removed |
633 // it. For now, removing it seems working fine. | 629 // it. For now, removing it seems working fine. |
634 gvr_api_->ApplyNeckModel(head_pose, 1.0f); | 630 gvr_api_->ApplyNeckModel(head_pose, 1.0f); |
635 } | 631 } |
636 | 632 |
637 frame.BindBuffer(kFramePrimaryBuffer); | |
638 | |
639 // Update the render position of all UI elements (including desktop). | 633 // Update the render position of all UI elements (including desktop). |
640 const float screen_tilt = kDesktopScreenTiltDefault * M_PI / 180.0f; | 634 const float screen_tilt = kDesktopScreenTiltDefault * M_PI / 180.0f; |
641 scene_->UpdateTransforms(screen_tilt, TimeInMicroseconds()); | 635 scene_->UpdateTransforms(screen_tilt, TimeInMicroseconds()); |
642 | 636 |
643 UpdateController(GetForwardVector(head_pose)); | 637 UpdateController(GetForwardVector(head_pose)); |
644 | 638 |
645 if (web_vr_mode_) { | |
646 DrawWebVr(); | |
647 | |
648 // When using async reprojection, we need to know which pose was used in | |
649 // the WebVR app for drawing this frame. Due to unknown amounts of | |
650 // buffering in the compositor and SurfaceTexture, we read the pose number | |
651 // from a corner pixel. There's no point in doing this for legacy | |
652 // distortion rendering since that doesn't need a pose, and reading back | |
653 // pixels is an expensive operation. TODO(klausw,crbug.com/655722): stop | |
654 // doing this once we have working no-compositor rendering for WebVR. | |
655 if (gvr_api_->GetAsyncReprojectionEnabled()) { | |
656 int pose_index_byte = GetPixelEncodedPoseIndexByte(); | |
657 if (WebVrPoseByteIsValid(pose_index_byte)) { | |
658 // We have a valid pose, use it for reprojection. | |
659 webvr_left_viewport_->SetReprojection(GVR_REPROJECTION_FULL); | |
660 webvr_right_viewport_->SetReprojection(GVR_REPROJECTION_FULL); | |
661 head_pose = webvr_head_pose_[pose_index_byte % kPoseRingBufferSize]; | |
662 // We can't mark the used pose as invalid since unfortunately | |
663 // we have to reuse them. The compositor will re-submit stale | |
664 // frames on vsync, and we can't tell that this has happened | |
665 // until we've read the pose index from it, and at that point | |
666 // it's too late to skip rendering. | |
667 } else { | |
668 // If we don't get a valid frame ID back we shouldn't attempt | |
669 // to reproject by an invalid matrix, so turn off reprojection | |
670 // instead. Invalid poses can permanently break reprojection | |
671 // for this GVR instance: http://crbug.com/667327 | |
672 webvr_left_viewport_->SetReprojection(GVR_REPROJECTION_NONE); | |
673 webvr_right_viewport_->SetReprojection(GVR_REPROJECTION_NONE); | |
674 } | |
675 } | |
676 } | |
677 | |
678 DrawVrShell(head_pose, frame); | 639 DrawVrShell(head_pose, frame); |
679 | 640 |
680 frame.Unbind(); | 641 frame.Unbind(); |
681 frame.Submit(*buffer_viewport_list_, head_pose); | 642 frame.Submit(*buffer_viewport_list_, head_pose); |
682 | 643 |
683 // No need to swap buffers for surfaceless rendering. | 644 // No need to swap buffers for surfaceless rendering. |
684 if (surfaceless_rendering_) { | 645 if (surfaceless_rendering_) { |
685 ScheduleNextDrawFrame(); | 646 ScheduleNextDrawFrame(); |
686 return; | 647 return; |
687 } | 648 } |
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
966 if (ui_surface_texture_.get()) | 927 if (ui_surface_texture_.get()) |
967 ui_surface_texture_->SetDefaultBufferSize(width, height); | 928 ui_surface_texture_->SetDefaultBufferSize(width, height); |
968 ui_tex_physical_size_.width = width; | 929 ui_tex_physical_size_.width = width; |
969 ui_tex_physical_size_.height = height; | 930 ui_tex_physical_size_.height = height; |
970 } | 931 } |
971 | 932 |
972 base::WeakPtr<VrShellGl> VrShellGl::GetWeakPtr() { | 933 base::WeakPtr<VrShellGl> VrShellGl::GetWeakPtr() { |
973 return weak_ptr_factory_.GetWeakPtr(); | 934 return weak_ptr_factory_.GetWeakPtr(); |
974 } | 935 } |
975 | 936 |
976 void VrShellGl::UpdateVSyncParameters(const base::TimeTicks timebase, | |
977 const base::TimeDelta interval) { | |
978 vsync_timebase_ = timebase; | |
979 vsync_interval_ = interval; | |
980 } | |
981 | |
982 void VrShellGl::ScheduleNextDrawFrame() { | 937 void VrShellGl::ScheduleNextDrawFrame() { |
983 base::TimeTicks now = base::TimeTicks::Now(); | 938 base::TimeTicks now = base::TimeTicks::Now(); |
984 base::TimeTicks target; | 939 base::TimeTicks target; |
985 | 940 |
986 if (vsync_interval_.is_zero()) { | 941 if (vsync_interval_.is_zero()) { |
987 target = now; | 942 target = now; |
988 } else { | 943 } else { |
989 target = now + vsync_interval_; | 944 target = now + vsync_interval_; |
990 int64_t intervals = (target - vsync_timebase_) / vsync_interval_; | 945 int64_t intervals = (target - vsync_timebase_) / vsync_interval_; |
991 target = vsync_timebase_ + intervals * vsync_interval_; | 946 target = vsync_timebase_ + intervals * vsync_interval_; |
992 } | 947 } |
| 948 task_runner_->PostDelayedTask(FROM_HERE, draw_task_.callback(), target - now); |
993 | 949 |
994 task_runner_->PostDelayedTask(FROM_HERE, draw_task_.callback(), target - now); | 950 if (!client_.is_bound()) |
| 951 return; |
| 952 int64_t intervals = (target - vsync_timebase_) / vsync_interval_; |
| 953 double time = (intervals * vsync_interval_).InSecondsF(); |
| 954 if (!pending_ack_) { |
| 955 client_->OnVSync( |
| 956 GetPose(), time, |
| 957 base::Bind(&VrShellGl::OnVSyncAck, weak_ptr_factory_.GetWeakPtr())); |
| 958 pending_ack_ = true; |
| 959 } else { |
| 960 pending_vsync_ = true; |
| 961 pending_time_ = time; |
| 962 } |
995 } | 963 } |
996 | 964 |
997 void VrShellGl::ForceExitVr() { | 965 void VrShellGl::ForceExitVr() { |
998 main_thread_task_runner_->PostTask( | 966 main_thread_task_runner_->PostTask( |
999 FROM_HERE, base::Bind(&VrShell::ForceExitVr, weak_vr_shell_)); | 967 FROM_HERE, base::Bind(&VrShell::ForceExitVr, weak_vr_shell_)); |
1000 } | 968 } |
1001 | 969 |
| 970 void VrShellGl::OnVRVSyncProviderClientConnected( |
| 971 device::mojom::VRVSyncProviderClientPtr client) { |
| 972 client_.Bind(client.PassInterface()); |
| 973 } |
| 974 |
| 975 void VrShellGl::OnVSyncAck() { |
| 976 pending_ack_ = false; |
| 977 if (!pending_vsync_) { |
| 978 triggered_vsync_from_ack_ = false; |
| 979 return; |
| 980 } |
| 981 pending_vsync_ = false; |
| 982 if (triggered_vsync_from_ack_) |
| 983 return; |
| 984 if (!client_.is_bound()) |
| 985 return; |
| 986 |
| 987 // Allow VSyncAck to trigger a VSync in the case that we missed the previous |
| 988 // frame to make it less likely multiple frames are missed in a row. However, |
| 989 // we don't want to get into a state where VSync is only ever triggered from |
| 990 // VSyncAck so we make sure the next VSync is really from a VSync and not an |
| 991 // Ack. |
| 992 client_->OnVSync( |
| 993 GetPose(), pending_time_, |
| 994 base::Bind(&VrShellGl::OnVSyncAck, weak_ptr_factory_.GetWeakPtr())); |
| 995 pending_ack_ = true; |
| 996 triggered_vsync_from_ack_ = true; |
| 997 } |
| 998 |
| 999 void VrShellGl::UpdateVSyncInterval(long timebase_nanos, |
| 1000 double interval_seconds) { |
| 1001 vsync_timebase_ = base::TimeTicks(); |
| 1002 vsync_timebase_ += base::TimeDelta::FromMicroseconds(timebase_nanos / 1000); |
| 1003 vsync_interval_ = base::TimeDelta::FromSecondsD(interval_seconds); |
| 1004 } |
| 1005 |
1002 void VrShellGl::UpdateScene(std::unique_ptr<base::ListValue> commands) { | 1006 void VrShellGl::UpdateScene(std::unique_ptr<base::ListValue> commands) { |
1003 scene_->HandleCommands(std::move(commands), TimeInMicroseconds()); | 1007 scene_->HandleCommands(std::move(commands), TimeInMicroseconds()); |
1004 } | 1008 } |
1005 | 1009 |
| 1010 device::mojom::VRPosePtr VrShellGl::GetPose() { |
| 1011 TRACE_EVENT0("input", "GvrDevice::GetSensorState"); |
| 1012 |
| 1013 device::mojom::VRPosePtr pose = device::mojom::VRPose::New(); |
| 1014 |
| 1015 pose->timestamp = base::Time::Now().ToJsTime(); |
| 1016 |
| 1017 // Increment pose frame counter always, even if it's a faked pose. |
| 1018 pose->poseIndex = ++pose_index_; |
| 1019 |
| 1020 pose->orientation.emplace(4); |
| 1021 |
| 1022 gvr::ClockTimePoint target_time = gvr::GvrApi::GetTimePointNow(); |
| 1023 target_time.monotonic_system_time_nanos += kPredictionTimeWithoutVsyncNanos; |
| 1024 |
| 1025 gvr::Mat4f head_mat = |
| 1026 gvr_api_->GetHeadSpaceFromStartSpaceRotation(target_time); |
| 1027 head_mat = gvr_api_->ApplyNeckModel(head_mat, 1.0f); |
| 1028 |
| 1029 // Save the underlying GVR pose for use by rendering. It can't use a |
| 1030 // VRPosePtr since that's a different data type. |
| 1031 webvr_head_pose_[pose_index_ % kPoseRingBufferSize] = head_mat; |
| 1032 |
| 1033 gfx::Transform inv_transform( |
| 1034 head_mat.m[0][0], head_mat.m[0][1], head_mat.m[0][2], head_mat.m[0][3], |
| 1035 head_mat.m[1][0], head_mat.m[1][1], head_mat.m[1][2], head_mat.m[1][3], |
| 1036 head_mat.m[2][0], head_mat.m[2][1], head_mat.m[2][2], head_mat.m[2][3], |
| 1037 head_mat.m[3][0], head_mat.m[3][1], head_mat.m[3][2], head_mat.m[3][3]); |
| 1038 |
| 1039 gfx::Transform transform; |
| 1040 if (inv_transform.GetInverse(&transform)) { |
| 1041 gfx::DecomposedTransform decomposed_transform; |
| 1042 gfx::DecomposeTransform(&decomposed_transform, transform); |
| 1043 |
| 1044 pose->orientation.value()[0] = decomposed_transform.quaternion[0]; |
| 1045 pose->orientation.value()[1] = decomposed_transform.quaternion[1]; |
| 1046 pose->orientation.value()[2] = decomposed_transform.quaternion[2]; |
| 1047 pose->orientation.value()[3] = decomposed_transform.quaternion[3]; |
| 1048 |
| 1049 pose->position.emplace(3); |
| 1050 pose->position.value()[0] = decomposed_transform.translate[0]; |
| 1051 pose->position.value()[1] = decomposed_transform.translate[1]; |
| 1052 pose->position.value()[2] = decomposed_transform.translate[2]; |
| 1053 } |
| 1054 |
| 1055 return pose; |
| 1056 } |
| 1057 |
1006 } // namespace vr_shell | 1058 } // namespace vr_shell |
OLD | NEW |