Commit 43e1c81e authored by Aldo Culquicondor's avatar Aldo Culquicondor Committed by Commit Bot

VR: Extract the WebXR presentation state in a separate file

Bug: 767282
Change-Id: Ie0a3951f454f8ee1d8df36d770b758d06d9a6826
Reviewed-on: https://chromium-review.googlesource.com/1157269Reviewed-by: default avatarKlaus Weidner <klausw@chromium.org>
Commit-Queue: Aldo Culquicondor <acondor@chromium.org>
Cr-Commit-Position: refs/heads/master@{#579791}
parent 96e64f1e
...@@ -47,6 +47,8 @@ static_library("vr_android") { ...@@ -47,6 +47,8 @@ static_library("vr_android") {
"vr_shell_gl.h", "vr_shell_gl.h",
"vr_web_contents_observer.cc", "vr_web_contents_observer.cc",
"vr_web_contents_observer.h", "vr_web_contents_observer.h",
"web_xr_presentation_state.cc",
"web_xr_presentation_state.h",
] ]
if (enable_arcore) { if (enable_arcore) {
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
#include "chrome/browser/android/vr/vr_shell_gl.h" #include "chrome/browser/android/vr/vr_shell_gl.h"
#include <algorithm> #include <algorithm>
#include <chrono>
#include <limits> #include <limits>
#include <utility> #include <utility>
...@@ -89,10 +88,6 @@ constexpr float kLowDpiDefaultRenderTargetSizeScale = 0.9f; ...@@ -89,10 +88,6 @@ constexpr float kLowDpiDefaultRenderTargetSizeScale = 0.9f;
// Use 2 for now, we can probably make the buffer even smaller. // Use 2 for now, we can probably make the buffer even smaller.
constexpr float kWebVrBrowserUiSizeFactor = 2.f; constexpr float kWebVrBrowserUiSizeFactor = 2.f;
// We have at most one frame animating, one frame being processed,
// and one frame tracked after submission to GVR.
constexpr int kWebXrFrameCount = 3;
// Number of frames to use for sliding averages for pose timings, // Number of frames to use for sliding averages for pose timings,
// as used for estimating prediction times. // as used for estimating prediction times.
constexpr unsigned kWebVRSlidingAverageSize = 5; constexpr unsigned kWebVRSlidingAverageSize = 5;
...@@ -198,131 +193,6 @@ gvr::Rectf GetMinimalFov(const gfx::Transform& view_matrix, ...@@ -198,131 +193,6 @@ gvr::Rectf GetMinimalFov(const gfx::Transform& view_matrix,
} // namespace } // namespace
WebXrSharedBuffer::WebXrSharedBuffer() = default;
WebXrSharedBuffer::~WebXrSharedBuffer() = default;
WebXrFrame::WebXrFrame() = default;
WebXrFrame::~WebXrFrame() = default;
bool WebXrFrame::IsValid() {
return index >= 0;
}
void WebXrFrame::Recycle() {
DCHECK(!state_locked);
index = -1;
deferred_start_processing.Reset();
recycle_once_unlocked = false;
gvr_handoff_fence.reset();
}
WebXrPresentationState::WebXrPresentationState() {
for (int i = 0; i < kWebXrFrameCount; ++i) {
// Create frames in "idle" state.
frames_storage_.push_back(std::make_unique<WebXrFrame>());
idle_frames_.push(frames_storage_[i].get());
}
}
WebXrPresentationState::~WebXrPresentationState() {}
WebXrFrame* WebXrPresentationState::GetAnimatingFrame() {
DCHECK(HaveAnimatingFrame());
DCHECK(animating_frame_->IsValid());
return animating_frame_;
}
WebXrFrame* WebXrPresentationState::GetProcessingFrame() {
DCHECK(HaveProcessingFrame());
DCHECK(processing_frame_->IsValid());
return processing_frame_;
}
WebXrFrame* WebXrPresentationState::GetRenderingFrame() {
DCHECK(HaveRenderingFrame());
DCHECK(rendering_frame_->IsValid());
return rendering_frame_;
}
WebXrPresentationState::FrameIndexType
WebXrPresentationState::StartFrameAnimating() {
DCHECK(!HaveAnimatingFrame());
DCHECK(idle_frames_.size() > 0);
animating_frame_ = idle_frames_.front();
idle_frames_.pop();
animating_frame_->index = next_frame_index_++;
return animating_frame_->index;
}
void WebXrPresentationState::TransitionFrameAnimatingToProcessing() {
DCHECK(HaveAnimatingFrame());
DCHECK(animating_frame_->IsValid());
DCHECK(!animating_frame_->state_locked);
DCHECK(!HaveProcessingFrame());
processing_frame_ = animating_frame_;
animating_frame_ = nullptr;
}
void WebXrPresentationState::RecycleUnusedAnimatingFrame() {
DCHECK(HaveAnimatingFrame());
animating_frame_->Recycle();
idle_frames_.push(animating_frame_);
animating_frame_ = nullptr;
}
void WebXrPresentationState::TransitionFrameProcessingToRendering() {
DCHECK(HaveProcessingFrame());
DCHECK(processing_frame_->IsValid());
DCHECK(!processing_frame_->state_locked);
DCHECK(!HaveRenderingFrame());
rendering_frame_ = processing_frame_;
processing_frame_ = nullptr;
}
void WebXrPresentationState::EndFrameRendering() {
DCHECK(HaveRenderingFrame());
DCHECK(rendering_frame_->IsValid());
rendering_frame_->Recycle();
idle_frames_.push(rendering_frame_);
rendering_frame_ = nullptr;
}
bool WebXrPresentationState::RecycleProcessingFrameIfPossible() {
DCHECK(HaveProcessingFrame());
bool can_cancel = !processing_frame_->state_locked;
if (can_cancel) {
processing_frame_->Recycle();
idle_frames_.push(processing_frame_);
processing_frame_ = nullptr;
} else {
processing_frame_->recycle_once_unlocked = true;
}
return can_cancel;
}
void WebXrPresentationState::EndPresentation() {
TRACE_EVENT0("gpu", __FUNCTION__);
if (end_presentation_callback) {
base::ResetAndReturn(&end_presentation_callback).Run();
}
if (HaveRenderingFrame()) {
rendering_frame_->Recycle();
idle_frames_.push(rendering_frame_);
rendering_frame_ = nullptr;
}
if (HaveProcessingFrame()) {
RecycleProcessingFrameIfPossible();
}
if (HaveAnimatingFrame()) {
RecycleUnusedAnimatingFrame();
}
last_ui_allows_sending_vsync = false;
}
VrShellGl::VrShellGl(GlBrowserInterface* browser_interface, VrShellGl::VrShellGl(GlBrowserInterface* browser_interface,
std::unique_ptr<UiInterface> ui, std::unique_ptr<UiInterface> ui,
gvr_context* gvr_api, gvr_context* gvr_api,
...@@ -1332,7 +1202,7 @@ bool VrShellGl::ResizeForWebVR(int16_t frame_index) { ...@@ -1332,7 +1202,7 @@ bool VrShellGl::ResizeForWebVR(int16_t frame_index) {
// careful of wrapping frame indices. // careful of wrapping frame indices.
static constexpr unsigned max = static constexpr unsigned max =
std::numeric_limits<WebXrPresentationState::FrameIndexType>::max(); std::numeric_limits<WebXrPresentationState::FrameIndexType>::max();
static_assert(max > kWebXrFrameCount * 2, static_assert(max > WebXrPresentationState::kWebXrFrameCount * 2,
"To detect wrapping, kPoseRingBufferSize must be smaller " "To detect wrapping, kPoseRingBufferSize must be smaller "
"than half of next_frame_index_ range."); "than half of next_frame_index_ range.");
while (!pending_bounds_.empty()) { while (!pending_bounds_.empty()) {
...@@ -1345,7 +1215,8 @@ bool VrShellGl::ResizeForWebVR(int16_t frame_index) { ...@@ -1345,7 +1215,8 @@ bool VrShellGl::ResizeForWebVR(int16_t frame_index) {
// size, wait to apply it. Otherwise, apply it immediately. This guarantees // size, wait to apply it. Otherwise, apply it immediately. This guarantees
// that even if we miss many frames, the queue can't fill up with stale // that even if we miss many frames, the queue can't fill up with stale
// bounds. // bounds.
if (index > frame_index && index <= frame_index + kWebXrFrameCount) if (index > frame_index &&
index <= frame_index + WebXrPresentationState::kWebXrFrameCount)
break; break;
const WebVrBounds& bounds = pending_bounds_.front().second; const WebVrBounds& bounds = pending_bounds_.front().second;
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "base/single_thread_task_runner.h" #include "base/single_thread_task_runner.h"
#include "chrome/browser/android/vr/android_vsync_helper.h" #include "chrome/browser/android/vr/android_vsync_helper.h"
#include "chrome/browser/android/vr/vr_controller.h" #include "chrome/browser/android/vr/vr_controller.h"
#include "chrome/browser/android/vr/web_xr_presentation_state.h"
#include "chrome/browser/vr/content_input_delegate.h" #include "chrome/browser/vr/content_input_delegate.h"
#include "chrome/browser/vr/fps_meter.h" #include "chrome/browser/vr/fps_meter.h"
#include "chrome/browser/vr/model/controller_model.h" #include "chrome/browser/vr/model/controller_model.h"
...@@ -32,7 +33,7 @@ ...@@ -32,7 +33,7 @@
#include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_types.h" #include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_types.h"
#include "ui/gfx/geometry/quaternion.h" #include "ui/gfx/geometry/quaternion.h"
#include "ui/gfx/geometry/rect_f.h" #include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/size_f.h" #include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_widget_types.h" #include "ui/gfx/native_widget_types.h"
namespace base { namespace base {
...@@ -40,10 +41,8 @@ class WaitableEvent; ...@@ -40,10 +41,8 @@ class WaitableEvent;
} }
namespace gl { namespace gl {
class GLFence;
class GLFenceAndroidNativeFenceSync; class GLFenceAndroidNativeFenceSync;
class GLFenceEGL; class GLFenceEGL;
class GLImageEGL;
class GLSurface; class GLSurface;
class ScopedJavaSurface; class ScopedJavaSurface;
class SurfaceTexture; class SurfaceTexture;
...@@ -56,7 +55,6 @@ class GpuFence; ...@@ -56,7 +55,6 @@ class GpuFence;
namespace gpu { namespace gpu {
struct MailboxHolder; struct MailboxHolder;
struct SyncToken; struct SyncToken;
class GpuMemoryBufferImplAndroidHardwareBuffer;
} // namespace gpu } // namespace gpu
namespace vr { namespace vr {
...@@ -82,110 +80,6 @@ struct WebVrBounds { ...@@ -82,110 +80,6 @@ struct WebVrBounds {
gfx::Size source_size; gfx::Size source_size;
}; };
// WebVR/WebXR frames go through a three-stage pipeline: Animating, Processing,
// and Rendering. There's also an Idle state used as the starting state before
// Animating and ending state after Rendering.
//
// The stages can overlap, but we enforce that there isn't more than one
// frame in a given non-Idle state at any one time.
//
// <- GetFrameData
// Idle
// SendVSync
// Animating
// <- UpdateLayerBounds (optional)
// <- GetFrameData
// <- SubmitFrame
// ProcessWebVrFrame
// Processing
// <- OnWebVrFrameAvailable
// DrawFrame
// DrawFrameSubmitWhenReady
// <= poll prev_frame_completion_fence_
// DrawFrameSubmitNow
// Rendering
// <= prev_frame_completion_fence_ signals
// DrawFrameSubmitNow (of next frame)
// Idle
//
// Note that the frame is considered to still be in "Animating" state until
// ProcessWebVrFrame is called. If the current processing frame isn't done yet
// at the time the incoming SubmitFrame arrives, we defer ProcessWebVrFrame
// until that finishes.
//
// The renderer may call SubmitFrameMissing instead of SubmitFrame. In that
// case, the frame transitions from Animating back to Idle.
//
// <- GetFrameData
// Idle
// SendVSync
// Animating
// <- UpdateLayerBounds (optional)
// <- GetFrameData
// <- SubmitFrameMissing
// Idle
struct WebXrSharedBuffer {
WebXrSharedBuffer();
~WebXrSharedBuffer();
gfx::Size size = {0, 0};
// Shared GpuMemoryBuffer
std::unique_ptr<gpu::GpuMemoryBufferImplAndroidHardwareBuffer> gmb;
// Resources in the remote GPU process command buffer context
std::unique_ptr<gpu::MailboxHolder> mailbox_holder;
uint32_t remote_texture = 0;
uint32_t remote_image = 0;
// Resources in the local GL context
uint32_t local_texture = 0;
// This refptr keeps the image alive while processing a frame. That's
// required because it owns underlying resources, and must still be
// alive when the mailbox texture backed by this image is used.
scoped_refptr<gl::GLImageEGL> local_glimage;
};
struct WebXrFrame {
WebXrFrame();
~WebXrFrame();
bool IsValid();
void Recycle();
// If true, this frame cannot change state until unlocked. Used to mark
// processing frames for the critical stage from drawing to Surface until
// they arrive in OnWebVRFrameAvailable. See also recycle_once_unlocked.
bool state_locked = false;
// Start of elements that need to be reset on Recycle
int16_t index = -1;
// Set on an animating frame if it is waiting for being able to transition
// to processing state.
base::OnceClosure deferred_start_processing;
// Set if a frame recycle failed due to being locked. The client should check
// this after unlocking it and retry recycling it at that time.
bool recycle_once_unlocked = false;
std::unique_ptr<gl::GLFence> gvr_handoff_fence;
// End of elements that need to be reset on Recycle
base::TimeTicks time_pose;
base::TimeTicks time_js_submit;
base::TimeTicks time_copied;
gfx::Transform head_pose;
// In SharedBuffer mode, keep a swap chain.
std::unique_ptr<WebXrSharedBuffer> shared_buffer;
DISALLOW_COPY_AND_ASSIGN(WebXrFrame);
};
struct Viewport { struct Viewport {
gvr::BufferViewport left; gvr::BufferViewport left;
gvr::BufferViewport right; gvr::BufferViewport right;
...@@ -201,67 +95,6 @@ struct Viewport { ...@@ -201,67 +95,6 @@ struct Viewport {
} }
}; };
class WebXrPresentationState {
public:
// WebXR frames use an arbitrary sequential ID to help catch logic errors
// involving out-of-order frames. We use an 8-bit unsigned counter, wrapping
// from 255 back to 0. Elsewhere we use -1 to indicate a non-WebXR frame, so
// most internal APIs use int16_t to ensure that they can store a full
// -1..255 value range.
using FrameIndexType = uint8_t;
WebXrPresentationState();
~WebXrPresentationState();
// State transitions for normal flow
FrameIndexType StartFrameAnimating();
void TransitionFrameAnimatingToProcessing();
void TransitionFrameProcessingToRendering();
void EndFrameRendering();
// Shuts down a presentation session. This will recycle any
// animating or rendering frame. A processing frame cannot be
// recycled if its state is locked, it will be recycled later
// once the state unlocks.
void EndPresentation();
// Variant transitions, if Renderer didn't call SubmitFrame,
// or if we want to discard an unwanted incoming frame.
void RecycleUnusedAnimatingFrame();
bool RecycleProcessingFrameIfPossible();
bool HaveAnimatingFrame() { return animating_frame_; }
WebXrFrame* GetAnimatingFrame();
bool HaveProcessingFrame() { return processing_frame_; }
WebXrFrame* GetProcessingFrame();
bool HaveRenderingFrame() { return rendering_frame_; }
WebXrFrame* GetRenderingFrame();
// Used by WebVrCanAnimateFrame() to detect when ui_->CanSendWebVrVSync()
// transitions from false to true, as part of starting the incoming frame
// timeout.
bool last_ui_allows_sending_vsync = false;
// GpuMemoryBuffer creation needs a buffer ID. We don't really care about
// this, but try to keep it unique to avoid confusion.
int next_memory_buffer_id = 0;
base::OnceClosure end_presentation_callback;
private:
std::vector<std::unique_ptr<WebXrFrame>> frames_storage_;
// Index of the next animating WebXR frame.
FrameIndexType next_frame_index_ = 0;
WebXrFrame* animating_frame_ = nullptr;
WebXrFrame* processing_frame_ = nullptr;
WebXrFrame* rendering_frame_ = nullptr;
base::queue<WebXrFrame*> idle_frames_;
DISALLOW_COPY_AND_ASSIGN(WebXrPresentationState);
};
// This class manages all GLThread owned objects and GL rendering for VrShell. // This class manages all GLThread owned objects and GL rendering for VrShell.
// It is not threadsafe and must only be used on the GL thread. // It is not threadsafe and must only be used on the GL thread.
class VrShellGl : public device::mojom::XRPresentationProvider, class VrShellGl : public device::mojom::XRPresentationProvider,
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/android/vr/web_xr_presentation_state.h"
#include "base/callback_helpers.h"
#include "base/trace_event/trace_event.h"
#include "gpu/command_buffer/common/mailbox_holder.h"
#include "gpu/ipc/common/gpu_memory_buffer_impl_android_hardware_buffer.h"
#include "ui/gl/gl_fence.h"
#include "ui/gl/gl_image_egl.h"
namespace vr {
WebXrSharedBuffer::WebXrSharedBuffer() = default;
WebXrSharedBuffer::~WebXrSharedBuffer() = default;
WebXrFrame::WebXrFrame() = default;
WebXrFrame::~WebXrFrame() = default;
bool WebXrFrame::IsValid() {
return index >= 0;
}
void WebXrFrame::Recycle() {
DCHECK(!state_locked);
index = -1;
deferred_start_processing.Reset();
recycle_once_unlocked = false;
gvr_handoff_fence.reset();
}
WebXrPresentationState::WebXrPresentationState() {
for (auto& frame : frames_storage_) {
// Create frames in "idle" state.
frame = std::make_unique<WebXrFrame>();
idle_frames_.push(frame.get());
}
}
WebXrPresentationState::~WebXrPresentationState() {}
WebXrFrame* WebXrPresentationState::GetAnimatingFrame() {
DCHECK(HaveAnimatingFrame());
DCHECK(animating_frame_->IsValid());
return animating_frame_;
}
WebXrFrame* WebXrPresentationState::GetProcessingFrame() {
DCHECK(HaveProcessingFrame());
DCHECK(processing_frame_->IsValid());
return processing_frame_;
}
WebXrFrame* WebXrPresentationState::GetRenderingFrame() {
DCHECK(HaveRenderingFrame());
DCHECK(rendering_frame_->IsValid());
return rendering_frame_;
}
WebXrPresentationState::FrameIndexType
WebXrPresentationState::StartFrameAnimating() {
DCHECK(!HaveAnimatingFrame());
DCHECK(!idle_frames_.empty());
animating_frame_ = idle_frames_.front();
idle_frames_.pop();
animating_frame_->index = next_frame_index_++;
return animating_frame_->index;
}
void WebXrPresentationState::TransitionFrameAnimatingToProcessing() {
DCHECK(HaveAnimatingFrame());
DCHECK(animating_frame_->IsValid());
DCHECK(!animating_frame_->state_locked);
DCHECK(!HaveProcessingFrame());
processing_frame_ = animating_frame_;
animating_frame_ = nullptr;
}
void WebXrPresentationState::RecycleUnusedAnimatingFrame() {
DCHECK(HaveAnimatingFrame());
animating_frame_->Recycle();
idle_frames_.push(animating_frame_);
animating_frame_ = nullptr;
}
void WebXrPresentationState::TransitionFrameProcessingToRendering() {
DCHECK(HaveProcessingFrame());
DCHECK(processing_frame_->IsValid());
DCHECK(!processing_frame_->state_locked);
DCHECK(!HaveRenderingFrame());
rendering_frame_ = processing_frame_;
processing_frame_ = nullptr;
}
void WebXrPresentationState::EndFrameRendering() {
DCHECK(HaveRenderingFrame());
DCHECK(rendering_frame_->IsValid());
rendering_frame_->Recycle();
idle_frames_.push(rendering_frame_);
rendering_frame_ = nullptr;
}
bool WebXrPresentationState::RecycleProcessingFrameIfPossible() {
DCHECK(HaveProcessingFrame());
bool can_cancel = !processing_frame_->state_locked;
if (can_cancel) {
processing_frame_->Recycle();
idle_frames_.push(processing_frame_);
processing_frame_ = nullptr;
} else {
processing_frame_->recycle_once_unlocked = true;
}
return can_cancel;
}
void WebXrPresentationState::EndPresentation() {
TRACE_EVENT0("gpu", __FUNCTION__);
if (end_presentation_callback) {
base::ResetAndReturn(&end_presentation_callback).Run();
}
if (HaveRenderingFrame()) {
rendering_frame_->Recycle();
idle_frames_.push(rendering_frame_);
rendering_frame_ = nullptr;
}
if (HaveProcessingFrame()) {
RecycleProcessingFrameIfPossible();
}
if (HaveAnimatingFrame()) {
RecycleUnusedAnimatingFrame();
}
last_ui_allows_sending_vsync = false;
}
} // namespace vr
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_ANDROID_VR_WEB_XR_PRESENTATION_STATE_H_
#define CHROME_BROWSER_ANDROID_VR_WEB_XR_PRESENTATION_STATE_H_
#include <memory>
#include "base/cancelable_callback.h"
#include "base/containers/queue.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/transform.h"
namespace gl {
class GLFence;
class GLImageEGL;
} // namespace gl
namespace gpu {
class GpuMemoryBufferImplAndroidHardwareBuffer;
struct MailboxHolder;
} // namespace gpu
namespace vr {
// WebVR/WebXR frames go through a three-stage pipeline: Animating, Processing,
// and Rendering. There's also an Idle state used as the starting state before
// Animating and ending state after Rendering.
//
// The stages can overlap, but we enforce that there isn't more than one
// frame in a given non-Idle state at any one time.
//
// <- GetFrameData
// Idle
// SendVSync
// Animating
// <- UpdateLayerBounds (optional)
// <- GetFrameData
// <- SubmitFrame
// ProcessWebVrFrame
// Processing
// <- OnWebVrFrameAvailable
// DrawFrame
// DrawFrameSubmitWhenReady
// <= poll prev_frame_completion_fence_
// DrawFrameSubmitNow
// Rendering
// <= prev_frame_completion_fence_ signals
// DrawFrameSubmitNow (of next frame)
// Idle
//
// Note that the frame is considered to still be in "Animating" state until
// ProcessWebVrFrame is called. If the current processing frame isn't done yet
// at the time the incoming SubmitFrame arrives, we defer ProcessWebVrFrame
// until that finishes.
//
// The renderer may call SubmitFrameMissing instead of SubmitFrame. In that
// case, the frame transitions from Animating back to Idle.
//
// <- GetFrameData
// Idle
// SendVSync
// Animating
// <- UpdateLayerBounds (optional)
// <- GetFrameData
// <- SubmitFrameMissing
// Idle
struct WebXrSharedBuffer {
WebXrSharedBuffer();
~WebXrSharedBuffer();
gfx::Size size = {0, 0};
// Shared GpuMemoryBuffer
std::unique_ptr<gpu::GpuMemoryBufferImplAndroidHardwareBuffer> gmb;
// Resources in the remote GPU process command buffer context
std::unique_ptr<gpu::MailboxHolder> mailbox_holder;
uint32_t remote_texture = 0;
uint32_t remote_image = 0;
// Resources in the local GL context
uint32_t local_texture = 0;
// This refptr keeps the image alive while processing a frame. That's
// required because it owns underlying resources, and must still be
// alive when the mailbox texture backed by this image is used.
scoped_refptr<gl::GLImageEGL> local_glimage;
};
struct WebXrFrame {
WebXrFrame();
~WebXrFrame();
bool IsValid();
void Recycle();
// If true, this frame cannot change state until unlocked. Used to mark
// processing frames for the critical stage from drawing to Surface until
// they arrive in OnWebVRFrameAvailable. See also recycle_once_unlocked.
bool state_locked = false;
// Start of elements that need to be reset on Recycle
int16_t index = -1;
// Set on an animating frame if it is waiting for being able to transition
// to processing state.
base::OnceClosure deferred_start_processing;
// Set if a frame recycle failed due to being locked. The client should check
// this after unlocking it and retry recycling it at that time.
bool recycle_once_unlocked = false;
std::unique_ptr<gl::GLFence> gvr_handoff_fence;
// End of elements that need to be reset on Recycle
base::TimeTicks time_pose;
base::TimeTicks time_js_submit;
base::TimeTicks time_copied;
gfx::Transform head_pose;
// In SharedBuffer mode, keep a swap chain.
std::unique_ptr<WebXrSharedBuffer> shared_buffer;
DISALLOW_COPY_AND_ASSIGN(WebXrFrame);
};
class WebXrPresentationState {
public:
// WebXR frames use an arbitrary sequential ID to help catch logic errors
// involving out-of-order frames. We use an 8-bit unsigned counter, wrapping
// from 255 back to 0. Elsewhere we use -1 to indicate a non-WebXR frame, so
// most internal APIs use int16_t to ensure that they can store a full
// -1..255 value range.
using FrameIndexType = uint8_t;
// We have at most one frame animating, one frame being processed,
// and one frame tracked after submission to GVR.
static constexpr int kWebXrFrameCount = 3;
WebXrPresentationState();
~WebXrPresentationState();
// State transitions for normal flow
FrameIndexType StartFrameAnimating();
void TransitionFrameAnimatingToProcessing();
void TransitionFrameProcessingToRendering();
void EndFrameRendering();
// Shuts down a presentation session. This will recycle any
// animating or rendering frame. A processing frame cannot be
// recycled if its state is locked, it will be recycled later
// once the state unlocks.
void EndPresentation();
// Variant transitions, if Renderer didn't call SubmitFrame,
// or if we want to discard an unwanted incoming frame.
void RecycleUnusedAnimatingFrame();
bool RecycleProcessingFrameIfPossible();
bool HaveAnimatingFrame() { return animating_frame_; }
WebXrFrame* GetAnimatingFrame();
bool HaveProcessingFrame() { return processing_frame_; }
WebXrFrame* GetProcessingFrame();
bool HaveRenderingFrame() { return rendering_frame_; }
WebXrFrame* GetRenderingFrame();
// Used by WebVrCanAnimateFrame() to detect when ui_->CanSendWebVrVSync()
// transitions from false to true, as part of starting the incoming frame
// timeout.
bool last_ui_allows_sending_vsync = false;
// GpuMemoryBuffer creation needs a buffer ID. We don't really care about
// this, but try to keep it unique to avoid confusion.
int next_memory_buffer_id = 0;
base::OnceClosure end_presentation_callback;
private:
std::unique_ptr<WebXrFrame> frames_storage_[kWebXrFrameCount];
// Index of the next animating WebXR frame.
FrameIndexType next_frame_index_ = 0;
WebXrFrame* animating_frame_ = nullptr;
WebXrFrame* processing_frame_ = nullptr;
WebXrFrame* rendering_frame_ = nullptr;
base::queue<WebXrFrame*> idle_frames_;
DISALLOW_COPY_AND_ASSIGN(WebXrPresentationState);
};
} // namespace vr
#endif // CHROME_BROWSER_ANDROID_VR_WEB_XR_PRESENTATION_STATE_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment