blob: 998343fcc04d91221ceffa332dc2f9eec4c0aeef [file] [log] [blame]
// Copyright 2016 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 THIRD_PARTY_BLINK_RENDERER_MODULES_VR_VR_DISPLAY_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_VR_VR_DISPLAY_H_
#include "device/vr/public/mojom/vr_service.mojom-blink.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "third_party/blink/public/platform/web_graphics_context_3d_provider.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_frame_request_callback.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/events/event_target.h"
#include "third_party/blink/renderer/core/execution_context/pausable_object.h"
#include "third_party/blink/renderer/modules/vr/vr_display_capabilities.h"
#include "third_party/blink/renderer/modules/vr/vr_layer_init.h"
#include "third_party/blink/renderer/platform/graphics/gpu/xr_frame_transport.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/timer.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
#include "third_party/blink/renderer/platform/wtf/functional.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace gpu {
namespace gles2 {
class GLES2Interface;
}
}
namespace blink {
class PLATFORM_EXPORT Image;
class NavigatorVR;
class VRController;
class VREyeParameters;
class VRFrameData;
class VRStageParameters;
class VRDisplay;
class WebGLRenderingContextBase;
// Wrapper class to allow the VRDisplay to distinguish between immersive and
// non-immersive XRSession events.
class SessionClientBinding
: public GarbageCollectedFinalized<SessionClientBinding>,
public device::mojom::blink::XRSessionClient {
public:
enum class SessionBindingType {
kImmersive = 0,
kNonImmersive = 1,
};
SessionClientBinding(VRDisplay* display,
SessionBindingType immersive,
device::mojom::blink::XRSessionClientRequest request);
~SessionClientBinding() override;
void Close();
void Trace(blink::Visitor*);
private:
void OnChanged(device::mojom::blink::VRDisplayInfoPtr) override;
void OnExitPresent() override;
void OnBlur() override;
void OnFocus() override;
// VRDisplay keeps all references to SessionClientBinding, so as soon as
// VRDisplay is destroyed, so is the SessionClientBinding.
Member<VRDisplay> display_;
bool is_immersive_;
mojo::Binding<device::mojom::blink::XRSessionClient> client_binding_;
};
enum VREye { kVREyeNone, kVREyeLeft, kVREyeRight };
class VRDisplay final : public EventTargetWithInlineData,
public ActiveScriptWrappable<VRDisplay>,
public PausableObject,
public device::mojom::blink::VRDisplayClient {
DEFINE_WRAPPERTYPEINFO();
USING_GARBAGE_COLLECTED_MIXIN(VRDisplay);
USING_PRE_FINALIZER(VRDisplay, Dispose);
public:
VRDisplay(NavigatorVR*, device::mojom::blink::XRDevicePtr);
~VRDisplay() override;
// We hand out at most one VRDisplay, so hardcode displayId to 1.
unsigned displayId() const { return 1; }
const String& displayName() const { return display_name_; }
VRDisplayCapabilities* capabilities() const { return capabilities_; }
VRStageParameters* stageParameters() const { return stage_parameters_; }
device::mojom::blink::XRDevice* device() { return device_ptr_.get(); }
bool isPresenting() const { return is_presenting_; }
bool canPresent() const { return capabilities_->canPresent(); }
bool getFrameData(VRFrameData*);
double depthNear() const { return depth_near_; }
double depthFar() const { return depth_far_; }
void setDepthNear(double value) { depth_near_ = value; }
void setDepthFar(double value) { depth_far_ = value; }
VREyeParameters* getEyeParameters(const String&);
int requestAnimationFrame(V8FrameRequestCallback*);
void cancelAnimationFrame(int id);
ScriptPromise requestPresent(ScriptState*,
const HeapVector<Member<VRLayerInit>>& layers);
ScriptPromise exitPresent(ScriptState*);
HeapVector<Member<VRLayerInit>> getLayers();
void submitFrame();
Document* GetDocument();
device::mojom::blink::VRDisplayClientPtr GetDisplayClient();
// EventTarget overrides:
ExecutionContext* GetExecutionContext() const override;
const AtomicString& InterfaceName() const override;
// ContextLifecycleObserver implementation.
void ContextDestroyed(ExecutionContext*) override;
// ScriptWrappable implementation.
bool HasPendingActivity() const final;
// PausableObject:
void ContextUnpaused() override;
void OnChanged(device::mojom::blink::VRDisplayInfoPtr, bool is_immersive);
void OnExitPresent(bool is_immersive);
void OnBlur(bool is_immersive);
void OnFocus(bool is_immersive);
void FocusChanged();
void OnNonImmersiveVSync(TimeTicks timestamp);
int PendingNonImmersiveVSyncId() { return pending_non_immersive_vsync_id_; }
void Trace(blink::Visitor*) override;
protected:
friend class VRController;
void Update(const device::mojom::blink::VRDisplayInfoPtr&);
void UpdatePose();
void BeginPresent();
void ForceExitPresent();
void UpdateLayerBounds();
VRController* Controller();
private:
void OnRequestImmersiveSessionReturned(
device::mojom::blink::XRSessionPtr session);
void OnNonImmersiveSessionRequestReturned(
device::mojom::blink::XRSessionPtr session);
void OnConnected();
void OnDisconnected();
void StopPresenting();
void OnPresentChange();
// VRDisplayClient
void OnActivate(device::mojom::blink::VRDisplayEventReason,
OnActivateCallback on_handled) override;
void OnDeactivate(device::mojom::blink::VRDisplayEventReason) override;
void OnPresentingVSync(device::mojom::blink::XRFrameDataPtr);
void OnPresentationProviderConnectionError();
void OnNonImmersiveFrameData(device::mojom::blink::XRFrameDataPtr);
bool FocusedOrPresenting();
ScriptedAnimationController& EnsureScriptedAnimationController(Document*);
void ProcessScheduledAnimations(TimeTicks timestamp);
void ProcessScheduledWindowAnimations(TimeTicks timestamp);
// Request delivery of a VSync event for either magic window mode or
// presenting mode as applicable. May be called more than once per frame, it
// ensures that there's at most one VSync request active at a time.
// Does nothing if the web application hasn't requested a rAF callback.
void RequestVSync();
scoped_refptr<Image> GetFrameImage(
std::unique_ptr<viz::SingleReleaseCallback>* out_release_callback);
Member<NavigatorVR> navigator_vr_;
String display_name_;
bool is_connected_ = false;
bool is_presenting_ = false;
bool is_valid_device_for_presenting_ = true;
Member<VRDisplayCapabilities> capabilities_;
Member<VRStageParameters> stage_parameters_;
Member<VREyeParameters> eye_parameters_left_;
Member<VREyeParameters> eye_parameters_right_;
device::mojom::blink::VRPosePtr frame_pose_;
device::mojom::blink::VRPosePtr pending_pose_;
// Set to true between OnActivate and requestPresent to indicate that we're in
// a display activation state.
bool in_display_activate_ = false;
// This frame ID is vr-specific and is used to track when frames arrive at the
// VR compositor so that it knows which poses to use, when to apply bounds
// updates, etc.
int16_t vr_frame_id_ = -1;
Member<VRLayerInit> layer_;
double depth_near_ = 0.01;
double depth_far_ = 10000.0;
// Current dimensions of the WebVR source canvas. May be different from
// the recommended renderWidth/Height if the client overrides dimensions.
int source_width_ = 0;
int source_height_ = 0;
void Dispose();
gpu::gles2::GLES2Interface* context_gl_ = nullptr;
Member<WebGLRenderingContextBase> rendering_context_;
Member<XRFrameTransport> frame_transport_;
TraceWrapperMember<ScriptedAnimationController>
scripted_animation_controller_;
bool pending_vrdisplay_raf_ = false;
bool pending_presenting_vsync_ = false;
bool pending_non_immersive_vsync_ = false;
int pending_non_immersive_vsync_id_ = -1;
base::OnceClosure non_immersive_vsync_waiting_for_pose_;
WTF::TimeTicks non_immersive_pose_request_time_;
WTF::TimeTicks non_immersive_pose_received_time_;
bool in_animation_frame_ = false;
bool did_submit_this_frame_ = false;
bool display_blurred_ = false;
bool pending_present_request_ = false;
// Metrics data - indicates whether we've already measured this data so we
// don't do it every frame.
bool did_log_getFrameData_ = false;
bool did_log_requestPresent_ = false;
device::mojom::blink::XRFrameDataProviderPtr non_immersive_provider_;
device::mojom::blink::XRDevicePtr device_ptr_;
bool present_image_needs_copy_ = false;
Member<SessionClientBinding> non_immersive_client_binding_;
Member<SessionClientBinding> immersive_client_binding_;
mojo::Binding<device::mojom::blink::VRDisplayClient> display_client_binding_;
device::mojom::blink::XRFrameDataProviderPtr vr_presentation_data_provider_;
device::mojom::blink::XRPresentationProviderPtr vr_presentation_provider_;
HeapDeque<Member<ScriptPromiseResolver>> pending_present_resolvers_;
};
using VRDisplayVector = HeapVector<Member<VRDisplay>>;
// When adding values, insert them before Max and add them to
// VRPresentationResult in enums.xml. Do not reuse values.
// Also, remove kPlaceholderForPreviousHighValue.
// When values become obsolete, comment them out here and mark them deprecated
// in enums.xml.
enum class PresentationResult {
kRequested = 0,
kSuccess = 1,
kSuccessAlreadyPresenting = 2,
kVRDisplayCannotPresent = 3,
kPresentationNotSupportedByDisplay = 4,
// kVRDisplayNotFound = 5,
kNotInitiatedByUserGesture = 6,
kInvalidNumberOfLayers = 7,
kInvalidLayerSource = 8,
kLayerSourceMissingWebGLContext = 9,
kInvalidLayerBounds = 10,
// kServiceInactive = 11,
// kRequestDenied = 12,
// kFullscreenNotEnabled = 13,
// TODO(ddorwin): Remove this placeholder when adding a new value.
kPlaceholderForPreviousHighValue = 13,
kPresentationResultMax, // Must be last member of enum.
};
void ReportPresentationResult(PresentationResult);
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_VR_VR_DISPLAY_H_