blob: efb8622e9f3c46bf253b8d5feeba306e465de60a [file] [log] [blame]
// 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 <utility>
#include "base/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();
void ProcessOrDefer(base::OnceClosure callback);
// Call this after state changes that could result in CanProcessFrame
// becoming true.
void TryDeferredProcessing();
bool HaveAnimatingFrame() const { return animating_frame_; }
WebXrFrame* GetAnimatingFrame();
bool HaveProcessingFrame() const { return processing_frame_; }
WebXrFrame* GetProcessingFrame();
bool HaveRenderingFrame() const { return rendering_frame_; }
WebXrFrame* GetRenderingFrame();
bool mailbox_bridge_ready() { return mailbox_bridge_ready_; }
void NotifyMailboxBridgeReady() { mailbox_bridge_ready_ = true; }
// 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;
private:
// Checks if we're in a valid state for processing the current animating
// frame. Invalid states include mailbox_bridge_ready_ being false, or an
// already existing processing frame that's not done yet.
bool CanProcessFrame() const;
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_;
bool mailbox_bridge_ready_ = false;
DISALLOW_COPY_AND_ASSIGN(WebXrPresentationState);
};
} // namespace vr
#endif // CHROME_BROWSER_ANDROID_VR_WEB_XR_PRESENTATION_STATE_H_