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 <utility> |
| 8 |
7 #include "base/android/jni_android.h" | 9 #include "base/android/jni_android.h" |
8 #include "base/memory/ptr_util.h" | 10 #include "base/memory/ptr_util.h" |
9 #include "base/metrics/histogram_macros.h" | 11 #include "base/metrics/histogram_macros.h" |
10 #include "base/threading/thread_task_runner_handle.h" | 12 #include "base/threading/thread_task_runner_handle.h" |
11 #include "chrome/browser/android/vr_shell/ui_elements.h" | 13 #include "chrome/browser/android/vr_shell/ui_elements.h" |
12 #include "chrome/browser/android/vr_shell/ui_scene.h" | 14 #include "chrome/browser/android/vr_shell/ui_scene.h" |
13 #include "chrome/browser/android/vr_shell/vr_controller.h" | 15 #include "chrome/browser/android/vr_shell/vr_controller.h" |
14 #include "chrome/browser/android/vr_shell/vr_gl_util.h" | 16 #include "chrome/browser/android/vr_shell/vr_gl_util.h" |
15 #include "chrome/browser/android/vr_shell/vr_math.h" | 17 #include "chrome/browser/android/vr_shell/vr_math.h" |
16 #include "chrome/browser/android/vr_shell/vr_shell.h" | 18 #include "chrome/browser/android/vr_shell/vr_shell.h" |
| 19 #include "chrome/browser/android/vr_shell/vr_shell_delegate.h" |
17 #include "chrome/browser/android/vr_shell/vr_shell_renderer.h" | 20 #include "chrome/browser/android/vr_shell/vr_shell_renderer.h" |
| 21 #include "device/vr/android/gvr/gvr_device.h" |
18 #include "third_party/WebKit/public/platform/WebInputEvent.h" | 22 #include "third_party/WebKit/public/platform/WebInputEvent.h" |
19 #include "third_party/WebKit/public/platform/WebMouseEvent.h" | 23 #include "third_party/WebKit/public/platform/WebMouseEvent.h" |
20 #include "ui/gfx/vsync_provider.h" | |
21 #include "ui/gl/android/scoped_java_surface.h" | 24 #include "ui/gl/android/scoped_java_surface.h" |
22 #include "ui/gl/android/surface_texture.h" | 25 #include "ui/gl/android/surface_texture.h" |
23 #include "ui/gl/gl_bindings.h" | 26 #include "ui/gl/gl_bindings.h" |
24 #include "ui/gl/gl_context.h" | 27 #include "ui/gl/gl_context.h" |
25 #include "ui/gl/gl_surface.h" | 28 #include "ui/gl/gl_surface.h" |
26 #include "ui/gl/init/gl_factory.h" | 29 #include "ui/gl/init/gl_factory.h" |
27 | 30 |
28 namespace vr_shell { | 31 namespace vr_shell { |
29 | 32 |
30 namespace { | 33 namespace { |
31 // Constant taken from treasure_hunt demo. | 34 // TODO(mthiesse): If gvr::PlatformInfo().GetPosePredictionTime() is ever |
| 35 // exposed, use that instead (it defaults to 50ms on most platforms). |
32 static constexpr long kPredictionTimeWithoutVsyncNanos = 50000000; | 36 static constexpr long kPredictionTimeWithoutVsyncNanos = 50000000; |
33 | 37 |
34 static constexpr float kZNear = 0.1f; | 38 static constexpr float kZNear = 0.1f; |
35 static constexpr float kZFar = 1000.0f; | 39 static constexpr float kZFar = 1000.0f; |
36 | 40 |
37 // Screen angle in degrees. 0 = vertical, positive = top closer. | 41 // Screen angle in degrees. 0 = vertical, positive = top closer. |
38 static constexpr float kDesktopScreenTiltDefault = 0; | 42 static constexpr float kDesktopScreenTiltDefault = 0; |
39 | 43 |
40 static constexpr float kReticleWidth = 0.025f; | 44 static constexpr float kReticleWidth = 0.025f; |
41 static constexpr float kReticleHeight = 0.025f; | 45 static constexpr float kReticleHeight = 0.025f; |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
133 return mouse_event; | 137 return mouse_event; |
134 } | 138 } |
135 | 139 |
136 enum class ViewerType { | 140 enum class ViewerType { |
137 UNKNOWN_TYPE = 0, | 141 UNKNOWN_TYPE = 0, |
138 CARDBOARD = 1, | 142 CARDBOARD = 1, |
139 DAYDREAM = 2, | 143 DAYDREAM = 2, |
140 VIEWER_TYPE_MAX, | 144 VIEWER_TYPE_MAX, |
141 }; | 145 }; |
142 | 146 |
143 int GetPixelEncodedPoseIndexByte() { | |
144 TRACE_EVENT0("gpu", "VrShellGl::GetPixelEncodedPoseIndex"); | |
145 // Read the pose index encoded in a bottom left pixel as color values. | |
146 // See also third_party/WebKit/Source/modules/vr/VRDisplay.cpp which | |
147 // encodes the pose index, and device/vr/android/gvr/gvr_device.cc | |
148 // which tracks poses. Returns the low byte (0..255) if valid, or -1 | |
149 // if not valid due to bad magic number. | |
150 uint8_t pixels[4]; | |
151 // Assume we're reading from the framebuffer we just wrote to. | |
152 // That's true currently, we may need to use glReadBuffer(GL_BACK) | |
153 // or equivalent if the rendering setup changes in the future. | |
154 glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels); | |
155 | |
156 // Check for the magic number written by VRDevice.cpp on submit. | |
157 // This helps avoid glitches from garbage data in the render | |
158 // buffer that can appear during initialization or resizing. These | |
159 // often appear as flashes of all-black or all-white pixels. | |
160 if (pixels[1] == kWebVrPosePixelMagicNumbers[0] && | |
161 pixels[2] == kWebVrPosePixelMagicNumbers[1]) { | |
162 // Pose is good. | |
163 return pixels[0]; | |
164 } | |
165 VLOG(1) << "WebVR: reject decoded pose index " << (int)pixels[0] << | |
166 ", bad magic number " << (int)pixels[1] << ", " << (int)pixels[2]; | |
167 return -1; | |
168 } | |
169 | |
170 int64_t TimeInMicroseconds() { | 147 int64_t TimeInMicroseconds() { |
171 return std::chrono::duration_cast<std::chrono::microseconds>( | 148 return std::chrono::duration_cast<std::chrono::microseconds>( |
172 std::chrono::steady_clock::now().time_since_epoch()).count(); | 149 std::chrono::steady_clock::now().time_since_epoch()).count(); |
173 } | 150 } |
174 | 151 |
175 void WaitForSwapAck(const base::Closure& callback, gfx::SwapResult result) { | |
176 callback.Run(); | |
177 } | |
178 | |
179 } // namespace | 152 } // namespace |
180 | 153 |
181 VrShellGl::VrShellGl( | 154 VrShellGl::VrShellGl( |
182 const base::WeakPtr<VrShell>& weak_vr_shell, | 155 const base::WeakPtr<VrShell>& weak_vr_shell, |
| 156 const base::WeakPtr<VrShellDelegate>& delegate_provider, |
183 scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner, | 157 scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner, |
184 gvr_context* gvr_api, | 158 gvr_context* gvr_api, |
185 bool initially_web_vr, | 159 bool initially_web_vr, |
186 bool reprojected_rendering) | 160 bool reprojected_rendering) |
187 : web_vr_mode_(initially_web_vr), | 161 : web_vr_mode_(initially_web_vr), |
188 surfaceless_rendering_(reprojected_rendering), | 162 surfaceless_rendering_(reprojected_rendering), |
189 task_runner_(base::ThreadTaskRunnerHandle::Get()), | 163 task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| 164 binding_(this), |
190 weak_vr_shell_(weak_vr_shell), | 165 weak_vr_shell_(weak_vr_shell), |
| 166 delegate_provider_(delegate_provider), |
191 main_thread_task_runner_(std::move(main_thread_task_runner)), | 167 main_thread_task_runner_(std::move(main_thread_task_runner)), |
192 weak_ptr_factory_(this) { | 168 weak_ptr_factory_(this) { |
193 GvrInit(gvr_api); | 169 GvrInit(gvr_api); |
194 } | 170 } |
195 | 171 |
196 VrShellGl::~VrShellGl() { | 172 VrShellGl::~VrShellGl() { |
197 draw_task_.Cancel(); | 173 vsync_task_.Cancel(); |
| 174 if (!callback_.is_null()) |
| 175 callback_.Run(nullptr, base::TimeDelta()); |
| 176 if (binding_.is_bound()) { |
| 177 main_thread_task_runner_->PostTask(FROM_HERE, base::Bind( |
| 178 &VrShellDelegate::OnVRVsyncProviderRequest, delegate_provider_, |
| 179 base::Passed(binding_.Unbind()))); |
| 180 } |
198 } | 181 } |
199 | 182 |
200 void VrShellGl::Initialize() { | 183 void VrShellGl::Initialize() { |
201 gvr::Mat4f identity; | |
202 SetIdentityM(identity); | |
203 webvr_head_pose_.resize(kPoseRingBufferSize, identity); | |
204 webvr_head_pose_valid_.resize(kPoseRingBufferSize, false); | |
205 | |
206 scene_.reset(new UiScene); | 184 scene_.reset(new UiScene); |
207 | 185 |
208 if (surfaceless_rendering_) { | 186 if (surfaceless_rendering_) { |
209 // If we're rendering surfaceless, we'll never get a java surface to render | 187 // If we're rendering surfaceless, we'll never get a java surface to render |
210 // into, so we can initialize GL right away. | 188 // into, so we can initialize GL right away. |
211 InitializeGl(nullptr); | 189 InitializeGl(nullptr); |
212 } | 190 } |
213 } | 191 } |
214 | 192 |
215 void VrShellGl::InitializeGl(gfx::AcceleratedWidget window) { | 193 void VrShellGl::InitializeGl(gfx::AcceleratedWidget window) { |
(...skipping 22 matching lines...) Expand all Loading... |
238 LOG(ERROR) << "gl::init::CreateGLContext failed"; | 216 LOG(ERROR) << "gl::init::CreateGLContext failed"; |
239 ForceExitVr(); | 217 ForceExitVr(); |
240 return; | 218 return; |
241 } | 219 } |
242 if (!context_->MakeCurrent(surface_.get())) { | 220 if (!context_->MakeCurrent(surface_.get())) { |
243 LOG(ERROR) << "gl::GLContext::MakeCurrent() failed"; | 221 LOG(ERROR) << "gl::GLContext::MakeCurrent() failed"; |
244 ForceExitVr(); | 222 ForceExitVr(); |
245 return; | 223 return; |
246 } | 224 } |
247 | 225 |
248 // TODO(mthiesse): We don't appear to have a VSync provider ever here. This is | |
249 // sort of okay, because the GVR swap chain will block if we render too fast, | |
250 // but we should address this properly. | |
251 if (surface_->GetVSyncProvider()) { | |
252 surface_->GetVSyncProvider()->GetVSyncParameters(base::Bind( | |
253 &VrShellGl::UpdateVSyncParameters, weak_ptr_factory_.GetWeakPtr())); | |
254 } else { | |
255 LOG(ERROR) << "No VSync Provider"; | |
256 } | |
257 | |
258 unsigned int textures[2]; | 226 unsigned int textures[2]; |
259 glGenTextures(2, textures); | 227 glGenTextures(2, textures); |
260 ui_texture_id_ = textures[0]; | 228 ui_texture_id_ = textures[0]; |
261 content_texture_id_ = textures[1]; | 229 content_texture_id_ = textures[1]; |
262 ui_surface_texture_ = gl::SurfaceTexture::Create(ui_texture_id_); | 230 ui_surface_texture_ = gl::SurfaceTexture::Create(ui_texture_id_); |
263 content_surface_texture_ = gl::SurfaceTexture::Create(content_texture_id_); | 231 content_surface_texture_ = gl::SurfaceTexture::Create(content_texture_id_); |
264 ui_surface_.reset(new gl::ScopedJavaSurface(ui_surface_texture_.get())); | 232 ui_surface_.reset(new gl::ScopedJavaSurface(ui_surface_texture_.get())); |
265 content_surface_.reset(new gl::ScopedJavaSurface( | 233 content_surface_.reset(new gl::ScopedJavaSurface( |
266 content_surface_texture_.get())); | 234 content_surface_texture_.get())); |
267 ui_surface_texture_->SetFrameAvailableCallback(base::Bind( | 235 ui_surface_texture_->SetFrameAvailableCallback(base::Bind( |
268 &VrShellGl::OnUIFrameAvailable, weak_ptr_factory_.GetWeakPtr())); | 236 &VrShellGl::OnUIFrameAvailable, weak_ptr_factory_.GetWeakPtr())); |
269 content_surface_texture_->SetFrameAvailableCallback(base::Bind( | 237 content_surface_texture_->SetFrameAvailableCallback(base::Bind( |
270 &VrShellGl::OnContentFrameAvailable, weak_ptr_factory_.GetWeakPtr())); | 238 &VrShellGl::OnContentFrameAvailable, weak_ptr_factory_.GetWeakPtr())); |
271 | 239 |
272 content_surface_texture_->SetDefaultBufferSize( | 240 content_surface_texture_->SetDefaultBufferSize( |
273 content_tex_physical_size_.width, content_tex_physical_size_.height); | 241 content_tex_physical_size_.width, content_tex_physical_size_.height); |
274 ui_surface_texture_->SetDefaultBufferSize(ui_tex_physical_size_.width, | 242 ui_surface_texture_->SetDefaultBufferSize(ui_tex_physical_size_.width, |
275 ui_tex_physical_size_.height); | 243 ui_tex_physical_size_.height); |
276 | 244 |
277 main_thread_task_runner_->PostTask(FROM_HERE, base::Bind( | 245 main_thread_task_runner_->PostTask(FROM_HERE, base::Bind( |
278 &VrShell::SurfacesChanged, weak_vr_shell_, | 246 &VrShell::SurfacesChanged, weak_vr_shell_, |
279 content_surface_->j_surface().obj(), | 247 content_surface_->j_surface().obj(), |
280 ui_surface_->j_surface().obj())); | 248 ui_surface_->j_surface().obj())); |
281 | 249 |
282 InitializeRenderer(); | 250 InitializeRenderer(); |
283 | 251 |
284 draw_task_.Reset(base::Bind(&VrShellGl::DrawFrame, base::Unretained(this))); | 252 vsync_task_.Reset(base::Bind(&VrShellGl::OnVSync, base::Unretained(this))); |
285 ScheduleNextDrawFrame(); | 253 OnVSync(); |
286 | 254 |
287 ready_to_draw_ = true; | 255 ready_to_draw_ = true; |
288 } | 256 } |
289 | 257 |
290 void VrShellGl::OnUIFrameAvailable() { | 258 void VrShellGl::OnUIFrameAvailable() { |
291 ui_surface_texture_->UpdateTexImage(); | 259 ui_surface_texture_->UpdateTexImage(); |
292 } | 260 } |
293 | 261 |
294 void VrShellGl::OnContentFrameAvailable() { | 262 void VrShellGl::OnContentFrameAvailable() { |
295 content_surface_texture_->UpdateTexImage(); | 263 content_surface_texture_->UpdateTexImage(); |
| 264 received_frame_ = true; |
| 265 } |
| 266 |
| 267 bool VrShellGl::GetPixelEncodedPoseIndexByte(int* pose_index) { |
| 268 TRACE_EVENT0("gpu", "VrShellGl::GetPixelEncodedPoseIndex"); |
| 269 if (!received_frame_) { |
| 270 *pose_index = last_pose_; |
| 271 return true; |
| 272 } |
| 273 received_frame_ = false; |
| 274 |
| 275 // Read the pose index encoded in a bottom left pixel as color values. |
| 276 // See also third_party/WebKit/Source/modules/vr/VRDisplay.cpp which |
| 277 // encodes the pose index, and device/vr/android/gvr/gvr_device.cc |
| 278 // which tracks poses. Returns the low byte (0..255) if valid, or -1 |
| 279 // if not valid due to bad magic number. |
| 280 uint8_t pixels[4]; |
| 281 // Assume we're reading from the framebuffer we just wrote to. |
| 282 // That's true currently, we may need to use glReadBuffer(GL_BACK) |
| 283 // or equivalent if the rendering setup changes in the future. |
| 284 glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixels); |
| 285 |
| 286 // Check for the magic number written by VRDevice.cpp on submit. |
| 287 // This helps avoid glitches from garbage data in the render |
| 288 // buffer that can appear during initialization or resizing. These |
| 289 // often appear as flashes of all-black or all-white pixels. |
| 290 if (pixels[1] == kWebVrPosePixelMagicNumbers[0] && |
| 291 pixels[2] == kWebVrPosePixelMagicNumbers[1]) { |
| 292 // Pose is good. |
| 293 *pose_index = pixels[0]; |
| 294 last_pose_ = pixels[0]; |
| 295 return true; |
| 296 } |
| 297 VLOG(1) << "WebVR: reject decoded pose index " << (int)pixels[0] |
| 298 << ", bad magic number " << (int)pixels[1] << ", " |
| 299 << (int)pixels[2]; |
| 300 return false; |
296 } | 301 } |
297 | 302 |
298 void VrShellGl::GvrInit(gvr_context* gvr_api) { | 303 void VrShellGl::GvrInit(gvr_context* gvr_api) { |
299 gvr_api_ = gvr::GvrApi::WrapNonOwned(gvr_api); | 304 gvr_api_ = gvr::GvrApi::WrapNonOwned(gvr_api); |
300 controller_.reset(new VrController(gvr_api)); | 305 controller_.reset(new VrController(gvr_api)); |
301 | 306 |
302 ViewerType viewerType; | 307 ViewerType viewerType; |
303 switch (gvr_api_->GetViewerType()) { | 308 switch (gvr_api_->GetViewerType()) { |
304 case gvr::ViewerType::GVR_VIEWER_TYPE_DAYDREAM: | 309 case gvr::ViewerType::GVR_VIEWER_TYPE_DAYDREAM: |
305 viewerType = ViewerType::DAYDREAM; | 310 viewerType = ViewerType::DAYDREAM; |
306 break; | 311 break; |
307 case gvr::ViewerType::GVR_VIEWER_TYPE_CARDBOARD: | 312 case gvr::ViewerType::GVR_VIEWER_TYPE_CARDBOARD: |
308 viewerType = ViewerType::CARDBOARD; | 313 viewerType = ViewerType::CARDBOARD; |
309 break; | 314 break; |
310 default: | 315 default: |
311 NOTREACHED(); | 316 NOTREACHED(); |
312 viewerType = ViewerType::UNKNOWN_TYPE; | 317 viewerType = ViewerType::UNKNOWN_TYPE; |
313 break; | 318 break; |
314 } | 319 } |
315 UMA_HISTOGRAM_ENUMERATION("VRViewerType", static_cast<int>(viewerType), | 320 UMA_HISTOGRAM_ENUMERATION("VRViewerType", static_cast<int>(viewerType), |
316 static_cast<int>(ViewerType::VIEWER_TYPE_MAX)); | 321 static_cast<int>(ViewerType::VIEWER_TYPE_MAX)); |
317 } | 322 } |
318 | 323 |
319 void VrShellGl::InitializeRenderer() { | 324 void VrShellGl::InitializeRenderer() { |
320 // While WebVR is going through the compositor path, it shares | 325 // While WebVR is going through the compositor path, it shares |
321 // the same texture ID. This will change once it gets its own | 326 // the same texture ID. This will change once it gets its own |
322 // surface, but store it separately to avoid future confusion. | 327 // surface, but store it separately to avoid future confusion. |
323 // TODO(klausw,crbug.com/655722): remove this. | 328 // TODO(klausw,crbug.com/655722): remove this. |
324 webvr_texture_id_ = content_texture_id_; | 329 webvr_texture_id_ = content_texture_id_; |
325 // Out of paranoia, explicitly reset the "pose valid" flags to false | |
326 // from the GL thread. The constructor ran in the UI thread. | |
327 // TODO(klausw,crbug.com/655722): remove this. | |
328 webvr_head_pose_valid_.assign(kPoseRingBufferSize, false); | |
329 | 330 |
330 gvr_api_->InitializeGl(); | 331 gvr_api_->InitializeGl(); |
| 332 webvr_head_pose_.assign(kPoseRingBufferSize, |
| 333 gvr_api_->GetHeadSpaceFromStartSpaceRotation( |
| 334 gvr::GvrApi::GetTimePointNow())); |
| 335 |
331 std::vector<gvr::BufferSpec> specs; | 336 std::vector<gvr::BufferSpec> specs; |
332 // For kFramePrimaryBuffer (primary VrShell and WebVR content) | 337 // For kFramePrimaryBuffer (primary VrShell and WebVR content) |
333 specs.push_back(gvr_api_->CreateBufferSpec()); | 338 specs.push_back(gvr_api_->CreateBufferSpec()); |
334 render_size_primary_ = specs[kFramePrimaryBuffer].GetSize(); | 339 render_size_primary_ = specs[kFramePrimaryBuffer].GetSize(); |
335 | 340 |
336 // For kFrameHeadlockedBuffer (for WebVR insecure content warning). | 341 // For kFrameHeadlockedBuffer (for WebVR insecure content warning). |
337 // Set this up at fixed resolution, the (smaller) FOV gets set below. | 342 // Set this up at fixed resolution, the (smaller) FOV gets set below. |
338 specs.push_back(gvr_api_->CreateBufferSpec()); | 343 specs.push_back(gvr_api_->CreateBufferSpec()); |
339 specs.back().SetSize(kHeadlockedBufferDimensions); | 344 specs.back().SetSize(kHeadlockedBufferDimensions); |
340 render_size_headlocked_ = specs[kFrameHeadlockedBuffer].GetSize(); | 345 render_size_headlocked_ = specs[kFrameHeadlockedBuffer].GetSize(); |
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
577 std::unique_ptr<blink::WebInputEvent> event) { | 582 std::unique_ptr<blink::WebInputEvent> event) { |
578 DCHECK(input_target != InputTarget::NONE); | 583 DCHECK(input_target != InputTarget::NONE); |
579 auto&& target = input_target == InputTarget::CONTENT | 584 auto&& target = input_target == InputTarget::CONTENT |
580 ? &VrShell::ProcessContentGesture | 585 ? &VrShell::ProcessContentGesture |
581 : &VrShell::ProcessUIGesture; | 586 : &VrShell::ProcessUIGesture; |
582 main_thread_task_runner_->PostTask( | 587 main_thread_task_runner_->PostTask( |
583 FROM_HERE, | 588 FROM_HERE, |
584 base::Bind(target, weak_vr_shell_, base::Passed(std::move(event)))); | 589 base::Bind(target, weak_vr_shell_, base::Passed(std::move(event)))); |
585 } | 590 } |
586 | 591 |
587 void VrShellGl::SetGvrPoseForWebVr(const gvr::Mat4f& pose, uint32_t pose_num) { | |
588 webvr_head_pose_[pose_num % kPoseRingBufferSize] = pose; | |
589 webvr_head_pose_valid_[pose_num % kPoseRingBufferSize] = true; | |
590 } | |
591 | |
592 bool VrShellGl::WebVrPoseByteIsValid(int pose_index_byte) { | |
593 if (pose_index_byte < 0) { | |
594 return false; | |
595 } | |
596 if (!webvr_head_pose_valid_[pose_index_byte % kPoseRingBufferSize]) { | |
597 VLOG(1) << "WebVR: reject decoded pose index " << pose_index_byte << | |
598 ", not a valid pose"; | |
599 return false; | |
600 } | |
601 return true; | |
602 } | |
603 | |
604 void VrShellGl::DrawFrame() { | 592 void VrShellGl::DrawFrame() { |
605 TRACE_EVENT0("gpu", "VrShellGl::DrawFrame"); | 593 TRACE_EVENT0("gpu", "VrShellGl::DrawFrame"); |
| 594 |
606 // Reset the viewport list to just the pair of viewports for the | 595 // Reset the viewport list to just the pair of viewports for the |
607 // primary buffer each frame. Head-locked viewports get added by | 596 // primary buffer each frame. Head-locked viewports get added by |
608 // DrawVrShell if needed. | 597 // DrawVrShell if needed. |
609 buffer_viewport_list_->SetToRecommendedBufferViewports(); | 598 buffer_viewport_list_->SetToRecommendedBufferViewports(); |
610 | 599 |
611 gvr::Frame frame = swap_chain_->AcquireFrame(); | 600 gvr::Frame frame = swap_chain_->AcquireFrame(); |
612 gvr::ClockTimePoint target_time = gvr::GvrApi::GetTimePointNow(); | 601 if (!frame.is_valid()) { |
613 target_time.monotonic_system_time_nanos += kPredictionTimeWithoutVsyncNanos; | 602 return; |
| 603 } |
| 604 frame.BindBuffer(kFramePrimaryBuffer); |
| 605 if (web_vr_mode_) { |
| 606 DrawWebVr(); |
| 607 } |
614 | 608 |
615 gvr::Mat4f head_pose = | 609 int pose_index; |
616 gvr_api_->GetHeadSpaceFromStartSpaceRotation(target_time); | 610 gvr::Mat4f head_pose; |
| 611 |
| 612 // When using async reprojection, we need to know which pose was used in |
| 613 // the WebVR app for drawing this frame. Due to unknown amounts of |
| 614 // buffering in the compositor and SurfaceTexture, we read the pose number |
| 615 // from a corner pixel. There's no point in doing this for legacy |
| 616 // distortion rendering since that doesn't need a pose, and reading back |
| 617 // pixels is an expensive operation. TODO(klausw,crbug.com/655722): stop |
| 618 // doing this once we have working no-compositor rendering for WebVR. |
| 619 if (web_vr_mode_ && gvr_api_->GetAsyncReprojectionEnabled() && |
| 620 GetPixelEncodedPoseIndexByte(&pose_index)) { |
| 621 head_pose = webvr_head_pose_[pose_index % kPoseRingBufferSize]; |
| 622 } else { |
| 623 gvr::ClockTimePoint target_time = gvr::GvrApi::GetTimePointNow(); |
| 624 target_time.monotonic_system_time_nanos += kPredictionTimeWithoutVsyncNanos; |
| 625 head_pose = gvr_api_->GetHeadSpaceFromStartSpaceRotation(target_time); |
| 626 } |
617 | 627 |
618 gvr::Vec3f position = GetTranslation(head_pose); | 628 gvr::Vec3f position = GetTranslation(head_pose); |
619 if (position.x == 0.0f && position.y == 0.0f && position.z == 0.0f) { | 629 if (position.x == 0.0f && position.y == 0.0f && position.z == 0.0f) { |
620 // This appears to be a 3DOF pose without a neck model. Add one. | 630 // This appears to be a 3DOF pose without a neck model. Add one. |
621 // The head pose has redundant data. Assume we're only using the | 631 // The head pose has redundant data. Assume we're only using the |
622 // object_from_reference_matrix, we're not updating position_external. | 632 // object_from_reference_matrix, we're not updating position_external. |
623 // TODO: Not sure what object_from_reference_matrix is. The new api removed | 633 // TODO: Not sure what object_from_reference_matrix is. The new api removed |
624 // it. For now, removing it seems working fine. | 634 // it. For now, removing it seems working fine. |
625 gvr_api_->ApplyNeckModel(head_pose, 1.0f); | 635 gvr_api_->ApplyNeckModel(head_pose, 1.0f); |
626 } | 636 } |
627 | 637 |
628 frame.BindBuffer(kFramePrimaryBuffer); | |
629 | |
630 // Update the render position of all UI elements (including desktop). | 638 // Update the render position of all UI elements (including desktop). |
631 const float screen_tilt = kDesktopScreenTiltDefault * M_PI / 180.0f; | 639 const float screen_tilt = kDesktopScreenTiltDefault * M_PI / 180.0f; |
632 scene_->UpdateTransforms(screen_tilt, TimeInMicroseconds()); | 640 scene_->UpdateTransforms(screen_tilt, TimeInMicroseconds()); |
633 | 641 |
634 UpdateController(GetForwardVector(head_pose)); | 642 UpdateController(GetForwardVector(head_pose)); |
635 | 643 |
636 if (web_vr_mode_) { | |
637 DrawWebVr(); | |
638 | |
639 // When using async reprojection, we need to know which pose was used in | |
640 // the WebVR app for drawing this frame. Due to unknown amounts of | |
641 // buffering in the compositor and SurfaceTexture, we read the pose number | |
642 // from a corner pixel. There's no point in doing this for legacy | |
643 // distortion rendering since that doesn't need a pose, and reading back | |
644 // pixels is an expensive operation. TODO(klausw,crbug.com/655722): stop | |
645 // doing this once we have working no-compositor rendering for WebVR. | |
646 if (gvr_api_->GetAsyncReprojectionEnabled()) { | |
647 int pose_index_byte = GetPixelEncodedPoseIndexByte(); | |
648 if (WebVrPoseByteIsValid(pose_index_byte)) { | |
649 // We have a valid pose, use it for reprojection. | |
650 webvr_left_viewport_->SetReprojection(GVR_REPROJECTION_FULL); | |
651 webvr_right_viewport_->SetReprojection(GVR_REPROJECTION_FULL); | |
652 head_pose = webvr_head_pose_[pose_index_byte % kPoseRingBufferSize]; | |
653 // We can't mark the used pose as invalid since unfortunately | |
654 // we have to reuse them. The compositor will re-submit stale | |
655 // frames on vsync, and we can't tell that this has happened | |
656 // until we've read the pose index from it, and at that point | |
657 // it's too late to skip rendering. | |
658 } else { | |
659 // If we don't get a valid frame ID back we shouldn't attempt | |
660 // to reproject by an invalid matrix, so turn off reprojection | |
661 // instead. Invalid poses can permanently break reprojection | |
662 // for this GVR instance: http://crbug.com/667327 | |
663 webvr_left_viewport_->SetReprojection(GVR_REPROJECTION_NONE); | |
664 webvr_right_viewport_->SetReprojection(GVR_REPROJECTION_NONE); | |
665 } | |
666 } | |
667 } | |
668 | |
669 DrawVrShell(head_pose, frame); | 644 DrawVrShell(head_pose, frame); |
670 | 645 |
671 frame.Unbind(); | 646 frame.Unbind(); |
672 frame.Submit(*buffer_viewport_list_, head_pose); | 647 frame.Submit(*buffer_viewport_list_, head_pose); |
673 | 648 |
674 // No need to swap buffers for surfaceless rendering. | 649 // No need to swap buffers for surfaceless rendering. |
675 if (surfaceless_rendering_) { | 650 if (!surfaceless_rendering_) { |
676 ScheduleNextDrawFrame(); | 651 // TODO(mthiesse): Support asynchronous SwapBuffers. |
677 return; | |
678 } | |
679 | |
680 if (surface_->SupportsAsyncSwap()) { | |
681 surface_->SwapBuffersAsync(base::Bind(&WaitForSwapAck, base::Bind( | |
682 &VrShellGl::ScheduleNextDrawFrame, weak_ptr_factory_.GetWeakPtr()))); | |
683 } else { | |
684 surface_->SwapBuffers(); | 652 surface_->SwapBuffers(); |
685 ScheduleNextDrawFrame(); | |
686 } | 653 } |
687 } | 654 } |
688 | 655 |
689 void VrShellGl::DrawVrShell(const gvr::Mat4f& head_pose, | 656 void VrShellGl::DrawVrShell(const gvr::Mat4f& head_pose, |
690 gvr::Frame &frame) { | 657 gvr::Frame &frame) { |
691 TRACE_EVENT0("gpu", "VrShellGl::DrawVrShell"); | 658 TRACE_EVENT0("gpu", "VrShellGl::DrawVrShell"); |
692 std::vector<const ContentRectangle*> head_locked_elements; | 659 std::vector<const ContentRectangle*> head_locked_elements; |
693 std::vector<const ContentRectangle*> world_elements; | 660 std::vector<const ContentRectangle*> world_elements; |
694 for (const auto& rect : scene_->GetUiElements()) { | 661 for (const auto& rect : scene_->GetUiElements()) { |
695 if (!rect->IsVisible()) | 662 if (!rect->IsVisible()) |
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
908 void VrShellGl::DrawBackground(const gvr::Mat4f& render_matrix) { | 875 void VrShellGl::DrawBackground(const gvr::Mat4f& render_matrix) { |
909 vr_shell_renderer_->GetBackgroundRenderer()->Draw(render_matrix); | 876 vr_shell_renderer_->GetBackgroundRenderer()->Draw(render_matrix); |
910 } | 877 } |
911 | 878 |
912 void VrShellGl::OnTriggerEvent() { | 879 void VrShellGl::OnTriggerEvent() { |
913 // Set a flag to handle this on the render thread at the next frame. | 880 // Set a flag to handle this on the render thread at the next frame. |
914 touch_pending_ = true; | 881 touch_pending_ = true; |
915 } | 882 } |
916 | 883 |
917 void VrShellGl::OnPause() { | 884 void VrShellGl::OnPause() { |
918 draw_task_.Cancel(); | 885 vsync_task_.Cancel(); |
919 controller_->OnPause(); | 886 controller_->OnPause(); |
920 gvr_api_->PauseTracking(); | 887 gvr_api_->PauseTracking(); |
921 } | 888 } |
922 | 889 |
923 void VrShellGl::OnResume() { | 890 void VrShellGl::OnResume() { |
924 gvr_api_->RefreshViewerProfile(); | 891 gvr_api_->RefreshViewerProfile(); |
925 gvr_api_->ResumeTracking(); | 892 gvr_api_->ResumeTracking(); |
926 controller_->OnResume(); | 893 controller_->OnResume(); |
927 if (ready_to_draw_) { | 894 if (ready_to_draw_) { |
928 draw_task_.Reset(base::Bind(&VrShellGl::DrawFrame, base::Unretained(this))); | 895 vsync_task_.Reset(base::Bind(&VrShellGl::OnVSync, base::Unretained(this))); |
929 ScheduleNextDrawFrame(); | 896 OnVSync(); |
930 } | 897 } |
931 } | 898 } |
932 | 899 |
933 void VrShellGl::SetWebVrMode(bool enabled) { | 900 void VrShellGl::SetWebVrMode(bool enabled) { |
934 web_vr_mode_ = enabled; | 901 web_vr_mode_ = enabled; |
935 } | 902 } |
936 | 903 |
937 void VrShellGl::UpdateWebVRTextureBounds(const gvr::Rectf& left_bounds, | 904 void VrShellGl::UpdateWebVRTextureBounds(const gvr::Rectf& left_bounds, |
938 const gvr::Rectf& right_bounds) { | 905 const gvr::Rectf& right_bounds) { |
939 webvr_left_viewport_->SetSourceUv(left_bounds); | 906 webvr_left_viewport_->SetSourceUv(left_bounds); |
(...skipping 26 matching lines...) Expand all Loading... |
966 if (ui_surface_texture_.get()) | 933 if (ui_surface_texture_.get()) |
967 ui_surface_texture_->SetDefaultBufferSize(width, height); | 934 ui_surface_texture_->SetDefaultBufferSize(width, height); |
968 ui_tex_physical_size_.width = width; | 935 ui_tex_physical_size_.width = width; |
969 ui_tex_physical_size_.height = height; | 936 ui_tex_physical_size_.height = height; |
970 } | 937 } |
971 | 938 |
972 base::WeakPtr<VrShellGl> VrShellGl::GetWeakPtr() { | 939 base::WeakPtr<VrShellGl> VrShellGl::GetWeakPtr() { |
973 return weak_ptr_factory_.GetWeakPtr(); | 940 return weak_ptr_factory_.GetWeakPtr(); |
974 } | 941 } |
975 | 942 |
976 void VrShellGl::UpdateVSyncParameters(const base::TimeTicks timebase, | 943 void VrShellGl::OnVSync() { |
977 const base::TimeDelta interval) { | |
978 vsync_timebase_ = timebase; | |
979 vsync_interval_ = interval; | |
980 } | |
981 | |
982 void VrShellGl::ScheduleNextDrawFrame() { | |
983 base::TimeTicks now = base::TimeTicks::Now(); | 944 base::TimeTicks now = base::TimeTicks::Now(); |
984 base::TimeTicks target; | 945 base::TimeTicks target; |
985 | 946 |
986 if (vsync_interval_.is_zero()) { | 947 // Don't send VSyncs until we have a timebase/interval. |
987 target = now; | 948 if (vsync_interval_.is_zero()) |
| 949 return; |
| 950 target = now + vsync_interval_; |
| 951 int64_t intervals = (target - vsync_timebase_) / vsync_interval_; |
| 952 target = vsync_timebase_ + intervals * vsync_interval_; |
| 953 task_runner_->PostDelayedTask(FROM_HERE, vsync_task_.callback(), |
| 954 target - now); |
| 955 |
| 956 base::TimeDelta time = intervals * vsync_interval_; |
| 957 if (!callback_.is_null()) { |
| 958 callback_.Run(GetPose(), time); |
| 959 callback_.Reset(); |
988 } else { | 960 } else { |
989 target = now + vsync_interval_; | 961 pending_vsync_ = true; |
990 int64_t intervals = (target - vsync_timebase_) / vsync_interval_; | 962 pending_time_ = time; |
991 target = vsync_timebase_ + intervals * vsync_interval_; | |
992 } | 963 } |
| 964 DrawFrame(); |
| 965 } |
993 | 966 |
994 task_runner_->PostDelayedTask(FROM_HERE, draw_task_.callback(), target - now); | 967 void VrShellGl::OnRequest(device::mojom::VRVSyncProviderRequest request) { |
| 968 binding_.Close(); |
| 969 binding_.Bind(std::move(request)); |
| 970 } |
| 971 |
| 972 void VrShellGl::GetVSync(const GetVSyncCallback& callback) { |
| 973 if (!pending_vsync_) { |
| 974 if (!callback_.is_null()) { |
| 975 mojo::ReportBadMessage("Requested VSync before waiting for response to " |
| 976 "previous request."); |
| 977 return; |
| 978 } |
| 979 callback_ = callback; |
| 980 return; |
| 981 } |
| 982 pending_vsync_ = false; |
| 983 callback.Run(GetPose(), pending_time_); |
| 984 } |
| 985 |
| 986 void VrShellGl::UpdateVSyncInterval(long timebase_nanos, |
| 987 double interval_seconds) { |
| 988 vsync_timebase_ = base::TimeTicks(); |
| 989 vsync_timebase_ += base::TimeDelta::FromMicroseconds(timebase_nanos / 1000); |
| 990 vsync_interval_ = base::TimeDelta::FromSecondsD(interval_seconds); |
| 991 vsync_task_.Reset(base::Bind(&VrShellGl::OnVSync, base::Unretained(this))); |
| 992 OnVSync(); |
995 } | 993 } |
996 | 994 |
997 void VrShellGl::ForceExitVr() { | 995 void VrShellGl::ForceExitVr() { |
998 main_thread_task_runner_->PostTask( | 996 main_thread_task_runner_->PostTask( |
999 FROM_HERE, base::Bind(&VrShell::ForceExitVr, weak_vr_shell_)); | 997 FROM_HERE, base::Bind(&VrShell::ForceExitVr, weak_vr_shell_)); |
1000 } | 998 } |
1001 | 999 |
1002 void VrShellGl::UpdateScene(std::unique_ptr<base::ListValue> commands) { | 1000 void VrShellGl::UpdateScene(std::unique_ptr<base::ListValue> commands) { |
1003 scene_->HandleCommands(std::move(commands), TimeInMicroseconds()); | 1001 scene_->HandleCommands(std::move(commands), TimeInMicroseconds()); |
1004 } | 1002 } |
1005 | 1003 |
| 1004 device::mojom::VRPosePtr VrShellGl::GetPose() { |
| 1005 TRACE_EVENT0("input", "VrShellGl::GetPose"); |
| 1006 |
| 1007 gvr::ClockTimePoint target_time = gvr::GvrApi::GetTimePointNow(); |
| 1008 target_time.monotonic_system_time_nanos += kPredictionTimeWithoutVsyncNanos; |
| 1009 |
| 1010 gvr::Mat4f head_mat = |
| 1011 gvr_api_->GetHeadSpaceFromStartSpaceRotation(target_time); |
| 1012 head_mat = gvr_api_->ApplyNeckModel(head_mat, 1.0f); |
| 1013 |
| 1014 uint32_t pose_index = pose_index_++; |
| 1015 webvr_head_pose_[pose_index % kPoseRingBufferSize] = head_mat; |
| 1016 |
| 1017 return VrShell::VRPosePtrFromGvrPose(head_mat, pose_index); |
| 1018 } |
| 1019 |
1006 } // namespace vr_shell | 1020 } // namespace vr_shell |
OLD | NEW |