Bug 1700051: part 26) Correct typo in comment of `mozInlineSpellWordUtil::BuildSoftTe...
[gecko.git] / dom / canvas / XRWebGLLayer.cpp
blob2b23293a85fdb21dea4d7acd5521ec41c8efc064
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/dom/XRWebGLLayer.h"
8 #include "mozilla/dom/XRSession.h"
9 #include "mozilla/dom/XRView.h"
10 #include "mozilla/dom/XRViewport.h"
11 #include "mozilla/dom/WebGLRenderingContextBinding.h"
12 #include "mozilla/HoldDropJSObjects.h"
13 #include "WebGLFramebuffer.h"
14 #include "mozilla/StaticPrefs_dom.h"
15 #include "mozilla/StaticPrefs_webgl.h"
16 #include "GLContext.h"
17 #include "ScopedGLHelpers.h"
18 #include "MozFramebuffer.h"
19 #include "VRDisplayClient.h"
20 #include "ClientWebGLContext.h"
21 #include "nsContentUtils.h"
22 #include "nsIScriptError.h"
24 using namespace mozilla::gl;
26 namespace mozilla::dom {
28 static constexpr float XR_FRAMEBUFFER_MIN_SCALE = 0.2f;
30 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(XRWebGLLayer, mParent, mSession, mWebGL,
31 mFramebuffer, mLeftViewport,
32 mRightViewport)
33 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(XRWebGLLayer, AddRef)
34 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(XRWebGLLayer, Release)
36 XRWebGLLayer::XRWebGLLayer(
37 nsISupports* aParent, XRSession& aSession, bool aIgnoreDepthValues,
38 double aFramebufferScaleFactor,
39 RefPtr<mozilla::ClientWebGLContext> aWebGLContext,
40 RefPtr<WebGLFramebufferJS> aFramebuffer,
41 const Maybe<const webgl::OpaqueFramebufferOptions>& aOptions)
42 : mParent(aParent),
43 mSession(&aSession),
44 mWebGL(std::move(aWebGLContext)),
45 mFramebufferScaleFactor(aFramebufferScaleFactor),
46 mCompositionDisabled(!aSession.IsImmersive()),
47 mIgnoreDepthValues(aIgnoreDepthValues),
48 mFramebuffer(std::move(aFramebuffer)),
49 mFramebufferOptions(aOptions) {
50 mozilla::HoldJSObjects(this);
53 XRWebGLLayer::~XRWebGLLayer() {
54 DeleteFramebuffer();
55 mozilla::DropJSObjects(this);
58 void XRWebGLLayer::DeleteFramebuffer() {
59 if (mFramebuffer) {
60 mWebGL->DeleteFramebuffer(mFramebuffer.get(), true);
61 mFramebuffer = nullptr;
65 /* static */
66 already_AddRefed<XRWebGLLayer> XRWebGLLayer::Constructor(
67 const GlobalObject& aGlobal, XRSession& aSession,
68 const WebGLRenderingContextOrWebGL2RenderingContext& aXRWebGLContext,
69 const XRWebGLLayerInit& aXRWebGLLayerInitDict, ErrorResult& aRv) {
70 // https://immersive-web.github.io/webxr/#dom-xrwebgllayer-xrwebgllayer
72 // Depth not supported in XR Compositor yet.
73 const bool ignoreDepthValues = true;
75 // If session’s ended value is true, throw an InvalidStateError and abort
76 // these steps.
77 if (aSession.IsEnded()) {
78 aRv.ThrowInvalidStateError(
79 "Can not create an XRWebGLLayer with an XRSession that has ended.");
80 return nullptr;
82 gfx::VRDisplayClient* display = aSession.GetDisplayClient();
83 const gfx::VRDisplayInfo& displayInfo = display->GetDisplayInfo();
84 const gfx::VRDisplayState& displayState = displayInfo.mDisplayState;
86 RefPtr<ClientWebGLContext> gl;
87 if (aXRWebGLContext.IsWebGLRenderingContext()) {
88 gl = &aXRWebGLContext.GetAsWebGLRenderingContext();
89 } else {
90 gl = &aXRWebGLContext.GetAsWebGL2RenderingContext();
93 // If context is lost, throw an InvalidStateError and abort these steps.
94 if (gl->IsContextLost()) {
95 aRv.ThrowInvalidStateError(
96 "Could not create an XRWebGLLayer, as the WebGL context was lost.");
97 return nullptr;
100 RefPtr<mozilla::WebGLFramebufferJS> framebuffer;
101 Maybe<const webgl::OpaqueFramebufferOptions> framebufferOptions;
102 if (aSession.IsImmersive()) {
103 // If session is an immersive session and context’s XR compatible boolean
104 // is false, throw an InvalidStateError and abort these steps.
105 if (!gl->IsXRCompatible()) {
106 aRv.ThrowInvalidStateError(
107 "Can not create an XRWebGLLayer without first calling "
108 "makeXRCompatible "
109 "on the WebGLRenderingContext or WebGL2RenderingContext.");
110 return nullptr;
113 const auto document = gl->GetParentObject()->OwnerDoc();
114 if (aXRWebGLLayerInitDict.mAlpha) {
115 nsContentUtils::ReportToConsoleNonLocalized(
116 u"XRWebGLLayer doesn't support no alpha value. "
117 "Alpha will be enabled."_ns,
118 nsIScriptError::warningFlag, "DOM"_ns, document);
120 if (aXRWebGLLayerInitDict.mDepth != aXRWebGLLayerInitDict.mStencil) {
121 nsContentUtils::ReportToConsoleNonLocalized(
122 nsLiteralString(
123 u"XRWebGLLayer doesn't support separate "
124 "depth or stencil buffers. They will be enabled together."),
125 nsIScriptError::warningFlag, "DOM"_ns, document);
128 bool antialias = aXRWebGLLayerInitDict.mAntialias;
129 if (antialias && !StaticPrefs::webgl_msaa_force()) {
130 antialias = false;
131 nsContentUtils::ReportToConsoleNonLocalized(
132 u"XRWebGLLayer antialiasing is not supported."
133 "Antialiasing will be disabled."_ns,
134 nsIScriptError::warningFlag, "DOM"_ns, document);
137 webgl::OpaqueFramebufferOptions options;
138 options.antialias = antialias;
139 options.depthStencil =
140 aXRWebGLLayerInitDict.mDepth || aXRWebGLLayerInitDict.mStencil;
142 // Clamp the requested framebuffer size to ensure it's not too
143 // small to see or larger than the max native resolution.
144 const float maxScale =
145 std::max(displayState.nativeFramebufferScaleFactor, 1.0f);
146 const float scaleFactor =
147 std::max(XR_FRAMEBUFFER_MIN_SCALE,
148 std::min((float)aXRWebGLLayerInitDict.mFramebufferScaleFactor,
149 maxScale));
151 options.width =
152 (int32_t)ceilf(2.0f * displayState.eyeResolution.width * scaleFactor);
153 options.height =
154 (int32_t)ceilf(displayState.eyeResolution.height * scaleFactor);
155 framebuffer = gl->CreateOpaqueFramebuffer(options);
157 if (!framebuffer) {
158 aRv.ThrowOperationError(
159 "Could not create an XRWebGLLayer. XRFramebuffer creation failed.");
160 return nullptr;
162 framebufferOptions.emplace(options);
165 RefPtr<XRWebGLLayer> obj =
166 new XRWebGLLayer(aGlobal.GetAsSupports(), aSession, ignoreDepthValues,
167 aXRWebGLLayerInitDict.mFramebufferScaleFactor, gl,
168 framebuffer, framebufferOptions);
169 return obj.forget();
172 JSObject* XRWebGLLayer::WrapObject(JSContext* aCx,
173 JS::Handle<JSObject*> aGivenProto) {
174 return XRWebGLLayer_Binding::Wrap(aCx, this, aGivenProto);
177 nsISupports* XRWebGLLayer::GetParentObject() const { return mParent; }
179 bool XRWebGLLayer::Antialias() {
180 if (mFramebufferOptions) {
181 return mFramebufferOptions->antialias;
183 return mWebGL->ActualContextParameters().antialias;
186 bool XRWebGLLayer::Depth() {
187 if (mFramebufferOptions) {
188 return mFramebufferOptions->depthStencil;
190 return mWebGL->ActualContextParameters().depth;
193 bool XRWebGLLayer::Stencil() {
194 if (mFramebufferOptions) {
195 return mFramebufferOptions->depthStencil;
197 return mWebGL->ActualContextParameters().stencil;
200 bool XRWebGLLayer::Alpha() {
201 if (mFramebufferOptions) {
202 // Alpha is always true when using Opaque Framebuffers.
203 return true;
205 return mWebGL->ActualContextParameters().alpha;
208 bool XRWebGLLayer::IgnoreDepthValues() { return mIgnoreDepthValues; }
210 WebGLFramebufferJS* XRWebGLLayer::GetFramebuffer() {
211 return mFramebuffer.get();
214 uint32_t XRWebGLLayer::FramebufferWidth() {
215 if (mFramebufferOptions) {
216 return mFramebufferOptions->width;
218 return mWebGL->GetWidth();
221 uint32_t XRWebGLLayer::FramebufferHeight() {
222 if (mFramebufferOptions) {
223 return mFramebufferOptions->height;
225 return mWebGL->GetHeight();
228 already_AddRefed<XRViewport> XRWebGLLayer::GetViewport(const XRView& aView) {
229 const int32_t width = (aView.Eye() == XREye::None) ? FramebufferWidth()
230 : (FramebufferWidth() / 2);
231 gfx::IntRect rect(0, 0, width, FramebufferHeight());
232 if (aView.Eye() == XREye::Right) {
233 rect.x = width;
235 RefPtr<XRViewport>& viewport =
236 aView.Eye() == XREye::Right ? mRightViewport : mLeftViewport;
237 if (!viewport) {
238 viewport = new XRViewport(mParent, rect);
239 } else {
240 viewport->mRect = rect;
242 RefPtr<XRViewport> result = viewport;
243 return result.forget();
246 // https://www.w3.org/TR/webxr/#dom-xrwebgllayer-getnativeframebufferscalefactor
247 /* static */ double XRWebGLLayer::GetNativeFramebufferScaleFactor(
248 const GlobalObject& aGlobal, const XRSession& aSession) {
249 if (aSession.IsEnded()) {
250 return 0.0f;
252 if (!aSession.IsImmersive()) {
253 return 1.0f;
256 const gfx::VRDisplayInfo& displayInfo =
257 aSession.GetDisplayClient()->GetDisplayInfo();
258 return displayInfo.mDisplayState.nativeFramebufferScaleFactor;
261 void XRWebGLLayer::StartAnimationFrame() {
262 if (mFramebuffer) {
263 mWebGL->SetFramebufferIsInOpaqueRAF(mFramebuffer.get(), true);
267 void XRWebGLLayer::EndAnimationFrame() {
268 if (mFramebuffer) {
269 mWebGL->SetFramebufferIsInOpaqueRAF(mFramebuffer.get(), false);
273 HTMLCanvasElement* XRWebGLLayer::GetCanvas() {
274 return mWebGL->GetParentObject();
277 void XRWebGLLayer::SessionEnded() { DeleteFramebuffer(); }
279 } // namespace mozilla::dom