WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
Patch for landing
bug-222607-20210318141222.patch (text/plain), 92.11 KB, created by
Imanol Fernandez
on 2021-03-18 06:12:23 PDT
(
hide
)
Description:
Patch for landing
Filename:
MIME Type:
Creator:
Imanol Fernandez
Created:
2021-03-18 06:12:23 PDT
Size:
92.11 KB
patch
obsolete
>Subversion Revision: 274641 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index ebbfeac00a536da5f9164d925d20ab5aa93222e5..38864227f14a0c39e6567ebb2fd6a73789d20d68 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,116 @@ >+2021-03-02 Imanol Fernandez <ifernandez@igalia.com> >+ >+ Implement WebXR Opaque Framebuffer >+ https://bugs.webkit.org/show_bug.cgi?id=222607 >+ >+ Reviewed by Youenn Fablet. >+ >+ This patch adds a base XR layers API which is initially used by WebXRWebGLLayer, but >+ with the goal of supporting more types of layers in the future (see WebXR Layers spec). >+ >+ Layers are connected to WebGL by using shared textures. In the case of WebXRWebGLLayer >+ it creates an Opaque Framebuffer that renders to the shared texture. XR runtimes supporting >+ double or triple buffering can send different shared textures each frame in the FrameData struct. >+ The texture for the current frame is attached in WebXRLayer::startFrame and prepared to send it back to the >+ VR compositor in WebXRLayer::endFrame(). >+ >+ Tested by the WebXR WPT tests. >+ >+ * Modules/webxr/WebXRLayer.h: add startFrame and endFrame pure virtual methods. >+ * Modules/webxr/WebXRSession.cpp: >+ (WebCore::WebXRSession::onFrame): do not call RAFs if frameData.shouldRender is false. >+ * Modules/webxr/WebXRSession.h: add device getter. >+ >+ * Modules/webxr/WebXRSystem.cpp: >+ (WebCore::WebXRSystem::DummyInlineDevice::requestFrame): always enable frameData.shouldRender flag. >+ * Modules/webxr/WebXRSystem.h: Override new virtual functions. >+ * Modules/webxr/WebXRViewport.h: >+ (WebCore::WebXRViewport::rect const): Add helper method. >+ >+ * Modules/webxr/WebXRWebGLLayer.cpp: Refactor resource initialization to create method. >+ (WebCore::WebXRWebGLLayer::create): >+ (WebCore::WebXRWebGLLayer::WebXRWebGLLayer): >+ (WebCore::m_isCompositionEnabled): >+ (WebCore::WebXRWebGLLayer::framebuffer const): >+ (WebCore::WebXRWebGLLayer::framebufferWidth const): >+ (WebCore::WebXRWebGLLayer::framebufferHeight const): >+ (WebCore::WebXRWebGLLayer::startFrame): Prepare Opaque Framebuffer for the start of next frame. >+ (WebCore::WebXRWebGLLayer::endFrame): Prepare Opaque Framebuffer for VR compositor submitFrame. >+ (WebCore::WebXRWebGLLayer::canvasResized): Move method >+ >+ (WebCore::WebXROpaqueFramebuffer::create): Implement class to manage WebXR Opaque framebuffer. >+ (WebCore::WebXROpaqueFramebuffer::WebXROpaqueFramebuffer): >+ (WebCore::WebXROpaqueFramebuffer::~WebXROpaqueFramebuffer): >+ (WebCore::WebXROpaqueFramebuffer::startFrame): Attach shared texture for the current frame. >+ (WebCore::WebXROpaqueFramebuffer::endFrame): Flush and resolve multisampling if required. >+ (WebCore::WebXROpaqueFramebuffer::setupFramebuffer): Allocate the Opaque framebuffer with requested attributes. >+ >+ * Modules/webxr/WebXRWebGLLayer.h: Add WebXROpaqueFramebuffer and handle members. >+ (WebCore::WebXROpaqueFramebuffer::handle const): >+ (WebCore::WebXROpaqueFramebuffer::framebuffer const): >+ (WebCore::WebXROpaqueFramebuffer::width const): >+ (WebCore::WebXROpaqueFramebuffer::height const): >+ >+ * Sources.txt: Add OpenXRLayer.cpp and OpenXRSwapchain.cpp. >+ >+ * html/canvas/WebGL2RenderingContext.cpp: >+ (WebCore::WebGL2RenderingContext::getFramebufferAttachmentParameter): handle Opaque Framebuffers. >+ >+ * html/canvas/WebGLFramebuffer.cpp: Add members and methods required for Opaque Framebuffers. >+ (WebCore::WebGLFramebuffer::createOpaque): >+ (WebCore::WebGLFramebuffer::checkStatus const): >+ * html/canvas/WebGLFramebuffer.h: >+ >+ * html/canvas/WebGLRenderingContext.cpp: >+ (WebCore::WebGLRenderingContext::getFramebufferAttachmentParameter): handle Opaque Framebuffers. >+ >+ * html/canvas/WebGLRenderingContextBase.cpp: handle Opaque Framebuffers. >+ (WebCore::WebGLRenderingContextBase::deleteFramebuffer): >+ (WebCore::WebGLRenderingContextBase::framebufferRenderbuffer): >+ (WebCore::WebGLRenderingContextBase::framebufferTexture2D): >+ >+ * platform/xr/PlatformXR.h: Add method to submitFrame. >+ (PlatformXR::Device::submitFrame): >+ >+ * platform/xr/openxr/OpenXRLayer.cpp: Add class to manage OpenXR layers. >+ (PlatformXR::OpenXRLayer::OpenXRLayer): >+ (PlatformXR::OpenXRLayerProjection::create): >+ (PlatformXR::OpenXRLayerProjection::OpenXRLayerProjection): >+ (PlatformXR::OpenXRLayerProjection::startFrame): >+ * platform/xr/openxr/OpenXRLayer.h: Added. >+ (PlatformXR::OpenXRLayer::handle): >+ >+ * platform/xr/openxr/OpenXRSwapchain.cpp: Add class to manage OpenXR swapchains >+ (PlatformXR::OpenXRSwapchain::create): >+ (PlatformXR::OpenXRSwapchain::OpenXRSwapchain): >+ (PlatformXR::OpenXRSwapchain::~OpenXRSwapchain): >+ (PlatformXR::OpenXRSwapchain::acquireImage): >+ (PlatformXR::OpenXRSwapchain::releaseImage): >+ * platform/xr/openxr/OpenXRSwapchain.h: Added. >+ >+ * platform/xr/openxr/OpenXRUtils.h: Add helper log function >+ (PlatformXR::xrViewToPose): Use fabs instead of negation >+ >+ * platform/xr/openxr/PlatformXROpenXR.cpp: >+ (PlatformXR::OpenXRDevice::initializeTrackingAndRendering): create GraphicsContextGL for texture sharing. >+ (PlatformXR::OpenXRDevice::requestFrame): Prepare and fill layers if shouldRender is true. >+ (PlatformXR::OpenXRDevice::submitFrame): Implement submit layers to OpenXR >+ (PlatformXR::OpenXRDevice::createLayerProjection): Implement layer creation method >+ (PlatformXR::OpenXRDevice::deleteLayer): Implement layer deallocation >+ (PlatformXR::OpenXRDevice::collectEnabledFeatures const): >+ (PlatformXR::OpenXRDevice::resetSession): Deallocate layers and graphics context. >+ >+ * platform/xr/openxr/PlatformXROpenXR.h: Add Layers API >+ >+ * testing/WebFakeXRDevice.cpp: >+ (WebCore::SimulatedXRDevice::recommendedResolution): Increase size to avoid platform minimum FBO size errors >+ (WebCore::SimulatedXRDevice::initializeTrackingAndRendering): Create graphics context >+ (WebCore::SimulatedXRDevice::shutDownTrackingAndRendering): Release graphics context >+ (WebCore::SimulatedXRDevice::frameTimerFired): set up layers in frame data >+ (WebCore::SimulatedXRDevice::createLayerProjection): creates a texture for a layer. >+ (WebCore::SimulatedXRDevice::deleteLayer): releases the associated texture to a layer >+ * testing/WebFakeXRDevice.h: >+ > 2021-03-18 Carlos Garcia Campos <cgarcia@igalia.com> > > [SOUP] SOUP3 crashes inside soup_message_set_request_body >diff --git a/Source/WebCore/Modules/webxr/WebXRLayer.h b/Source/WebCore/Modules/webxr/WebXRLayer.h >index 003f56c7d441e764ca63669526880f762953870d..dfc13830c3fc9ffe0960723348f1d7b81a82ec05 100644 >--- a/Source/WebCore/Modules/webxr/WebXRLayer.h >+++ b/Source/WebCore/Modules/webxr/WebXRLayer.h >@@ -29,6 +29,7 @@ > > #include "ContextDestructionObserver.h" > #include "EventTarget.h" >+#include "PlatformXR.h" > #include <wtf/IsoMalloc.h> > #include <wtf/RefCounted.h> > >@@ -44,6 +45,9 @@ public: > using RefCounted<WebXRLayer>::ref; > using RefCounted<WebXRLayer>::deref; > >+ virtual void startFrame(const PlatformXR::Device::FrameData&) = 0; >+ virtual PlatformXR::Device::Layer endFrame() = 0; >+ > protected: > explicit WebXRLayer(ScriptExecutionContext*); > >diff --git a/Source/WebCore/Modules/webxr/WebXRSession.cpp b/Source/WebCore/Modules/webxr/WebXRSession.cpp >index ff1eb1fa0fe67941f17fe34308acc426111c520f..deb4a590e79cd2b0d0f83043de704d14617e029b 100644 >--- a/Source/WebCore/Modules/webxr/WebXRSession.cpp >+++ b/Source/WebCore/Modules/webxr/WebXRSession.cpp >@@ -514,7 +514,11 @@ void WebXRSession::onFrame(PlatformXR::Device::FrameData&& frameData) > applyPendingRenderState(); > > // 6. If the frame should be rendered for session: >- if (frameShouldBeRendered()) { >+ if (frameShouldBeRendered() && m_frameData.shouldRender) { >+ // Prepare all layers for render >+ if (m_mode == XRSessionMode::ImmersiveVr && m_activeRenderState->baseLayer()) >+ m_activeRenderState->baseLayer()->startFrame(m_frameData); >+ > // 6.1.Set sessionâs list of currently running animation frame callbacks to be sessionâs list of animation frame callbacks. > // 6.2.Set sessionâs list of animation frame callbacks to the empty list. > auto callbacks = m_callbacks; >@@ -545,10 +549,18 @@ void WebXRSession::onFrame(PlatformXR::Device::FrameData&& frameData) > // If the session is ended, m_animationFrame->setActive false is set in shutdown(). > frame->setActive(false); > >- if (!m_callbacks.isEmpty()) >- requestFrame(); >+ >+ // Submit current frame layers to the device. >+ Vector<PlatformXR::Device::Layer> frameLayers; >+ if (m_mode == XRSessionMode::ImmersiveVr && m_activeRenderState->baseLayer()) >+ frameLayers.append(m_activeRenderState->baseLayer()->endFrame()); >+ >+ m_device->submitFrame(WTFMove(frameLayers)); > } > >+ if (!m_callbacks.isEmpty()) >+ requestFrame(); >+ > }); > } > >diff --git a/Source/WebCore/Modules/webxr/WebXRSession.h b/Source/WebCore/Modules/webxr/WebXRSession.h >index dc508acda1e024ef0afbfaeb6049e93c4b8482b3..313d8fc0e1569b829fe981e60885577cf366711e 100644 >--- a/Source/WebCore/Modules/webxr/WebXRSession.h >+++ b/Source/WebCore/Modules/webxr/WebXRSession.h >@@ -73,6 +73,7 @@ public: > XRVisibilityState visibilityState() const; > const WebXRRenderState& renderState() const; > const WebXRInputSourceArray& inputSources() const; >+ PlatformXR::Device* device() const { return m_device.get(); } > > ExceptionOr<void> updateRenderState(const XRRenderStateInit&); > void requestReferenceSpace(XRReferenceSpaceType, RequestReferenceSpacePromise&&); >diff --git a/Source/WebCore/Modules/webxr/WebXRSystem.cpp b/Source/WebCore/Modules/webxr/WebXRSystem.cpp >index 09bc8be562e6827345e341c5f11939b959025b17..d3d11a6b3c9a4c038c173e8bbb2b2167dc99982f 100644 >--- a/Source/WebCore/Modules/webxr/WebXRSystem.cpp >+++ b/Source/WebCore/Modules/webxr/WebXRSystem.cpp >@@ -534,6 +534,7 @@ void WebXRSystem::DummyInlineDevice::requestFrame(PlatformXR::Device::RequestFra > PlatformXR::Device::FrameData data; > data.isTrackingValid = true; > data.isPositionValid = true; >+ data.shouldRender = true; > data.views.append({ }); > callback(WTFMove(data)); > }); >diff --git a/Source/WebCore/Modules/webxr/WebXRSystem.h b/Source/WebCore/Modules/webxr/WebXRSystem.h >index 4008b3479229bb6e102335d2b7faf9b4a84c209e..0ac24b5c6ff510ec34ea48994324aefd3996298c 100644 >--- a/Source/WebCore/Modules/webxr/WebXRSystem.h >+++ b/Source/WebCore/Modules/webxr/WebXRSystem.h >@@ -115,6 +115,8 @@ private: > > void requestFrame(PlatformXR::Device::RequestFrameCallback&&) final; > Vector<Device::ViewData> views(XRSessionMode) const final; >+ Optional<PlatformXR::LayerHandle> createLayerProjection(uint32_t, uint32_t, bool) final { return WTF::nullopt; } >+ void deleteLayer(PlatformXR::LayerHandle) final { } > }; > DummyInlineDevice m_defaultInlineDevice; > >diff --git a/Source/WebCore/Modules/webxr/WebXRViewport.h b/Source/WebCore/Modules/webxr/WebXRViewport.h >index 0a5fecb2e359f2c41ece40a7b310a8d7108ef198..5627e96456bb79bfe1b8d2681413ab013f7b3d33 100644 >--- a/Source/WebCore/Modules/webxr/WebXRViewport.h >+++ b/Source/WebCore/Modules/webxr/WebXRViewport.h >@@ -43,6 +43,7 @@ public: > int y() const { return m_viewport.y(); } > int width() const { return m_viewport.width(); } > int height() const { return m_viewport.height(); } >+ IntRect rect() { return m_viewport; } > > void updateViewport(const IntRect& viewport) { m_viewport = viewport; } > >diff --git a/Source/WebCore/Modules/webxr/WebXRWebGLLayer.cpp b/Source/WebCore/Modules/webxr/WebXRWebGLLayer.cpp >index c8d42e54433acdf2cd23b6854f0550e1ab5c402a..91873c3d848ed73f1d64baf9b43bba106937bdd3 100644 >--- a/Source/WebCore/Modules/webxr/WebXRWebGLLayer.cpp >+++ b/Source/WebCore/Modules/webxr/WebXRWebGLLayer.cpp >@@ -28,9 +28,13 @@ > > #if ENABLE(WEBXR) > >+#include "ExtensionsGLOpenGLCommon.h" >+#include "ExtensionsGLOpenGLES.h" >+#include "GraphicsContextGL.h" > #include "HTMLCanvasElement.h" > #include "IntSize.h" > #include "OffscreenCanvas.h" >+#include "TemporaryOpenGLSetting.h" > #include "WebGLFramebuffer.h" > #include "WebGLRenderingContext.h" > #if ENABLE(WEBGL2) >@@ -47,15 +51,59 @@ > > namespace WebCore { > >+using GL = GraphicsContextGL; >+ > WTF_MAKE_ISO_ALLOCATED_IMPL(WebXRWebGLLayer); > >+// Arbitrary value for minimum framebuffer scaling. >+// Below this threshold the resulting framebuffer would be too small to see. >+constexpr double MinFramebufferScalingFactor = 0.2; >+ >+static ExceptionOr<std::unique_ptr<WebXROpaqueFramebuffer>> createOpaqueFramebuffer(WebXRSession& session, WebGLRenderingContextBase& context, const XRWebGLLayerInit& init) >+{ >+ auto device = session.device(); >+ if (!device) >+ return Exception { OperationError, "Cannot create an XRWebGLLayer with an XRSession that has ended." }; >+ >+ // 9.1. Initialize layerâs antialias to layerInitâs antialias value. >+ // 9.2. Let framebufferSize be the recommended WebGL framebuffer resolution multiplied by layerInit's framebufferScaleFactor. >+ >+ float scaleFactor = std::clamp(init.framebufferScaleFactor, MinFramebufferScalingFactor, device->maxFramebufferScalingFactor()); >+ >+ IntSize recommendedSize = session.recommendedWebGLFramebufferResolution(); >+ auto width = static_cast<uint32_t>(std::ceil(2 * recommendedSize.width() * scaleFactor)); >+ auto height = static_cast<uint32_t>(std::ceil(recommendedSize.height() * scaleFactor)); >+ >+ // 9.3. Initialize layerâs framebuffer to a new opaque framebuffer with the dimensions framebufferSize >+ // created with context, session initialized to session, and layerInitâs depth, stencil, and alpha values. >+ // 9.4. Allocate and initialize resources compatible with sessionâs XR device, including GPU accessible memory buffers, >+ // as required to support the compositing of layer. >+ // 9.5. If layerâs resources were unable to be created for any reason, throw an OperationError and abort these steps. >+ auto layerHandle = device->createLayerProjection(width, height, init.alpha); >+ if (!layerHandle) >+ return Exception { OperationError, "Unable to allocate XRWebGLLayer GPU resources."}; >+ >+ WebXROpaqueFramebuffer::Attributes attributes { >+ .alpha = init.alpha, >+ .antialias = init.antialias, >+ .depth = init.depth, >+ .stencil = init.stencil >+ }; >+ >+ auto framebuffer = WebXROpaqueFramebuffer::create(*layerHandle, context, WTFMove(attributes), width, height); >+ if (!framebuffer) >+ return Exception { OperationError, "Unable to create a framebuffer." }; >+ >+ return framebuffer; >+} >+ > // https://immersive-web.github.io/webxr/#dom-xrwebgllayer-xrwebgllayer > ExceptionOr<Ref<WebXRWebGLLayer>> WebXRWebGLLayer::create(Ref<WebXRSession>&& session, WebXRRenderingContext&& context, const XRWebGLLayerInit& init) > { > // 1. Let layer be a new XRWebGLLayer > // 2. If sessionâs ended value is true, throw an InvalidStateError and abort these steps. > if (session->ended()) >- return Exception { InvalidStateError }; >+ return Exception { InvalidStateError, "Cannot create an XRWebGLLayer with an XRSession that has ended." }; > > // 3. If context is lost, throw an InvalidStateError and abort these steps. > // 4. If session is an immersive session and contextâs XR compatible boolean is false, throw >@@ -64,29 +112,44 @@ ExceptionOr<Ref<WebXRWebGLLayer>> WebXRWebGLLayer::create(Ref<WebXRSession>&& se > [&](const RefPtr<WebGLRenderingContextBase>& baseContext) -> ExceptionOr<Ref<WebXRWebGLLayer>> > { > if (baseContext->isContextLost()) >- return Exception { InvalidStateError }; >+ return Exception { InvalidStateError, "Cannot create an XRWebGLLayer with a lost WebGL context." }; > > auto mode = session->mode(); > if ((mode == XRSessionMode::ImmersiveAr || mode == XRSessionMode::ImmersiveVr) && !baseContext->isXRCompatible()) >- return Exception { InvalidStateError }; >+ return Exception { InvalidStateError, "Cannot create an XRWebGLLayer with WebGL context not marked as XR compatible." }; > > > // 5. Initialize layerâs context to context. (see constructor) > // 6. Initialize layerâs session to session. (see constructor) > // 7. Initialize layerâs ignoreDepthValues as follows. (see constructor) >- // 8. Initialize layerâs composition disabled boolean as follows. (see constructor) >- // 9. (see constructor except for the resources initialization step which is handled in the if block below) >- auto layer = adoptRef(*new WebXRWebGLLayer(WTFMove(session), WTFMove(context), init)); >- >- if (layer->m_isCompositionEnabled) { >- // 9.4. Allocate and initialize resources compatible with sessionâs XR device, including GPU accessible memory buffers, >- // as required to support the compositing of layer. >- // 9.5. If layerâs resources were unable to be created for any reason, throw an OperationError and abort these steps. >- // TODO: Initialize layer's resources or issue an OperationError. >+ // 7.1 If layerInitâs ignoreDepthValues value is false and the XR Compositor will make use of depth values, >+ // Initialize layerâs ignoreDepthValues to false. >+ // 7.2. Else Initialize layerâs ignoreDepthValues to true >+ // TODO: ask XR compositor for depth value usages support >+ bool ignoreDepthValues = true; >+ // 8. Initialize layerâs composition disabled boolean as follows. >+ // If session is an inline session -> Initialize layer's composition disabled to true >+ // Otherwise -> Initialize layer's composition disabled boolean to false >+ bool isCompositionEnabled = session->mode() != XRSessionMode::Inline; >+ bool antialias = false; >+ std::unique_ptr<WebXROpaqueFramebuffer> framebuffer; >+ >+ // 9. If layer's composition enabled boolean is true: >+ if (isCompositionEnabled) { >+ auto createResult = createOpaqueFramebuffer(session.get(), *baseContext, init); >+ if (createResult.hasException()) >+ return createResult.releaseException(); >+ framebuffer = createResult.releaseReturnValue(); >+ } else { >+ // Otherwise >+ // 9.1. Initialize layerâs antialias to layerâs context's actual context parameters antialias value. >+ if (auto attributes = baseContext->getContextAttributes()) >+ antialias = attributes->antialias; >+ // 9.2 Initialize layer's framebuffer to null. > } > > // 10. Return layer. >- return layer; >+ return adoptRef(*new WebXRWebGLLayer(WTFMove(session), WTFMove(context), WTFMove(framebuffer), antialias, ignoreDepthValues, isCompositionEnabled)); > }, > [](WTF::Monostate) { > ASSERT_NOT_REACHED(); >@@ -95,63 +158,18 @@ ExceptionOr<Ref<WebXRWebGLLayer>> WebXRWebGLLayer::create(Ref<WebXRSession>&& se > ); > } > >-WebXRWebGLLayer::WebXRWebGLLayer(Ref<WebXRSession>&& session, WebXRRenderingContext&& context, const XRWebGLLayerInit& init) >+WebXRWebGLLayer::WebXRWebGLLayer(Ref<WebXRSession>&& session, WebXRRenderingContext&& context, std::unique_ptr<WebXROpaqueFramebuffer>&& framebuffer, >+ bool antialias, bool ignoreDepthValues, bool isCompositionEnabled) > : WebXRLayer(session->scriptExecutionContext()) > , m_session(WTFMove(session)) > , m_context(WTFMove(context)) > , m_leftViewportData({ WebXRViewport::create({ }) }) > , m_rightViewportData({ WebXRViewport::create({ }) }) >+ , m_framebuffer(WTFMove(framebuffer)) >+ , m_antialias(antialias) >+ , m_ignoreDepthValues(ignoreDepthValues) >+ , m_isCompositionEnabled(isCompositionEnabled) > { >- // 7. Initialize layerâs ignoreDepthValues as follows: >- // 7.1 If layerInitâs ignoreDepthValues value is false and the XR Compositor will make use of depth values, >- // Initialize layerâs ignoreDepthValues to false. >- // 7.2. Else Initialize layerâs ignoreDepthValues to true >- // TODO: ask XR compositor for depth value usages >- m_ignoreDepthValues = init.ignoreDepthValues; >- >- // 8. Initialize layer's composition disabled boolean as follows: >- // If session is an inline session -> Initialize layer's composition disabled to true >- // Otherwise -> Initialize layer's composition disabled boolean to false >- m_isCompositionEnabled = m_session->mode() != XRSessionMode::Inline; >- >- // 9. If layerâs composition disabled boolean is false: >- if (m_isCompositionEnabled) { >- // 1. Initialize layerâs antialias to layerInitâs antialias value. >- m_antialias = init.antialias; >- >- // 2. Let framebufferSize be the recommended WebGL framebuffer resolution multiplied by layerInit's framebufferScaleFactor. >- IntSize recommendedSize = m_session->recommendedWebGLFramebufferResolution(); >- m_framebuffer.width = recommendedSize.width() * init.framebufferScaleFactor; >- m_framebuffer.height = recommendedSize.height() * init.framebufferScaleFactor; >- >- // 3. Initialize layerâs framebuffer to a new opaque framebuffer with the dimensions framebufferSize >- // created with context, session initialized to session, and layerInitâs depth, stencil, and alpha values. >- // For steps 4 & 5 see the create() method as resources initialization is handled outside the constructor as it might trigger >- // an OperationError. >- // FIXME: create a proper opaque framebuffer. >- m_framebuffer.object = WTF::switchOn(m_context, >- [](const RefPtr<WebGLRenderingContextBase>& baseContext) >- { >- return WebGLFramebuffer::create(*baseContext); >- } >- ); >- } else { >- // 1. Initialize layerâs antialias to layerâs context's actual context parameters antialias value. >- m_antialias = WTF::switchOn(m_context, >- [](const RefPtr<WebGLRenderingContextBase>& context) >- { >- if (auto attributes = context->getContextAttributes()) >- return attributes.value().antialias; >- return false; >- } >- ); >- // 2. Initialize layerâs framebuffer to null. >- m_framebuffer.object = nullptr; >- } >- >- auto canvasElement = canvas(); >- if (canvasElement) >- canvasElement->addObserver(*this); > } > > WebXRWebGLLayer::~WebXRWebGLLayer() >@@ -159,6 +177,11 @@ WebXRWebGLLayer::~WebXRWebGLLayer() > auto canvasElement = canvas(); > if (canvasElement) > canvasElement->removeObserver(*this); >+ if (m_framebuffer) { >+ auto device = m_session->device(); >+ if (device) >+ device->deleteLayer(m_framebuffer->handle()); >+ } > } > > bool WebXRWebGLLayer::antialias() const >@@ -171,15 +194,15 @@ bool WebXRWebGLLayer::ignoreDepthValues() const > return m_ignoreDepthValues; > } > >-WebGLFramebuffer* WebXRWebGLLayer::framebuffer() const >+const WebGLFramebuffer* WebXRWebGLLayer::framebuffer() const > { >- return m_framebuffer.object.get(); >+ return m_framebuffer ? &m_framebuffer->framebuffer() : nullptr; > } > > unsigned WebXRWebGLLayer::framebufferWidth() const > { >- if (m_framebuffer.object) >- return m_framebuffer.width; >+ if (m_framebuffer) >+ return m_framebuffer->width(); > return WTF::switchOn(m_context, > [&](const RefPtr<WebGLRenderingContextBase>& baseContext) { > return baseContext->drawingBufferWidth(); >@@ -188,8 +211,8 @@ unsigned WebXRWebGLLayer::framebufferWidth() const > > unsigned WebXRWebGLLayer::framebufferHeight() const > { >- if (m_framebuffer.object) >- return m_framebuffer.height; >+ if (m_framebuffer) >+ return m_framebuffer->height(); > return WTF::switchOn(m_context, > [&](const RefPtr<WebGLRenderingContextBase>& baseContext) { > return baseContext->drawingBufferHeight(); >@@ -256,6 +279,39 @@ HTMLCanvasElement* WebXRWebGLLayer::canvas() const > }); > } > >+ >+void WebXRWebGLLayer::startFrame(const PlatformXR::Device::FrameData& data) >+{ >+ ASSERT(m_framebuffer); >+ >+ auto it = data.layers.find(m_framebuffer->handle()); >+ if (it == data.layers.end()) { >+ // For some reason the device didn't provide a texture for this frame. >+ // The frame is ignored and the device can recover the texture in future frames; >+ return; >+ } >+ >+ m_framebuffer->startFrame(it->value); >+} >+ >+PlatformXR::Device::Layer WebXRWebGLLayer::endFrame() >+{ >+ ASSERT(m_framebuffer); >+ m_framebuffer->endFrame(); >+ >+ Vector<PlatformXR::Device::LayerView> views { >+ { PlatformXR::Eye::Left, m_leftViewportData.viewport->rect() }, >+ { PlatformXR::Eye::Right, m_rightViewportData.viewport->rect() } >+ }; >+ >+ return PlatformXR::Device::Layer { .handle = m_framebuffer->handle(), .visible = true, .views = WTFMove(views) }; >+} >+ >+void WebXRWebGLLayer::canvasResized(CanvasBase&) >+{ >+ m_viewportsDirty = true; >+} >+ > // https://immersive-web.github.io/webxr/#xrview-obtain-a-scaled-viewport > void WebXRWebGLLayer::computeViewports() > { >@@ -283,9 +339,244 @@ void WebXRWebGLLayer::computeViewports() > m_viewportsDirty = false; > } > >-void WebXRWebGLLayer::canvasResized(CanvasBase&) >+// WebXROpaqueFramebuffer >+ >+std::unique_ptr<WebXROpaqueFramebuffer> WebXROpaqueFramebuffer::create(PlatformXR::LayerHandle handle, WebGLRenderingContextBase& context, Attributes&& attributes, uint32_t width, uint32_t height) > { >- m_viewportsDirty = true; >+ auto framebuffer = WebGLFramebuffer::createOpaque(context); >+ auto opaque = std::unique_ptr<WebXROpaqueFramebuffer>(new WebXROpaqueFramebuffer(handle, WTFMove(framebuffer), context, WTFMove(attributes), width, height)); >+ if (!opaque->setupFramebuffer()) >+ return nullptr; >+ return opaque; >+} >+ >+WebXROpaqueFramebuffer::WebXROpaqueFramebuffer(PlatformXR::LayerHandle handle, Ref<WebGLFramebuffer>&& framebuffer, WebGLRenderingContextBase& context, Attributes&& attributes, uint32_t width, uint32_t height) >+ : m_handle(handle) >+ , m_framebuffer(WTFMove(framebuffer)) >+ , m_context(context) >+ , m_attributes(WTFMove(attributes)) >+ , m_width(width) >+ , m_height(height) >+{ >+} >+ >+WebXROpaqueFramebuffer::~WebXROpaqueFramebuffer() >+{ >+ if (auto gl = m_context.graphicsContextGL()) { >+ if (m_stencilBuffer) >+ gl->deleteRenderbuffer(m_stencilBuffer); >+ if (m_depthStencilBuffer) >+ gl->deleteRenderbuffer(m_depthStencilBuffer); >+ if (m_multisampleColorBuffer) >+ gl->deleteRenderbuffer(m_multisampleColorBuffer); >+ if (m_resolvedFBO) >+ gl->deleteFramebuffer(m_resolvedFBO); >+ m_context.deleteFramebuffer(m_framebuffer.ptr()); >+ } >+} >+ >+void WebXROpaqueFramebuffer::startFrame(const PlatformXR::Device::FrameData::LayerData& data) >+{ >+ m_opaqueTexture = data.opaqueTexture; >+ if (!m_context.graphicsContextGL()) >+ return; >+ auto& gl = *m_context.graphicsContextGL(); >+ >+ m_framebuffer->setOpaqueActive(true); >+ >+ GCGLint boundFBO { 0 }; >+ >+ gl.getIntegerv(GL::FRAMEBUFFER_BINDING, makeGCGLSpan(&boundFBO, 1)); >+ auto scopedFBOs = makeScopeExit([&gl, boundFBO]() { >+ gl.bindFramebuffer(GL::FRAMEBUFFER, boundFBO); >+ }); >+ >+ gl.bindFramebuffer(GL::FRAMEBUFFER, m_framebuffer->object()); >+ // https://immersive-web.github.io/webxr/#opaque-framebuffer >+ // The buffers attached to an opaque framebuffer MUST be cleared to the values in the table below when first created, >+ // or prior to the processing of each XR animation frame. >+ std::array<const GCGLenum, 3> attachments = { GL::COLOR_ATTACHMENT0, GL::STENCIL_ATTACHMENT, GL::DEPTH_ATTACHMENT }; >+ gl.invalidateFramebuffer(GL::FRAMEBUFFER, makeGCGLSpan(attachments.data(), attachments.size())); >+ >+#if USE(OPENGL_ES) >+ auto& extensions = reinterpret_cast<ExtensionsGLOpenGLES&>(gl.getExtensions()); >+ if (m_attributes.antialias && extensions.isImagination()) { >+ extensions.framebufferTexture2DMultisampleIMG(GL::FRAMEBUFFER, GL::COLOR_ATTACHMENT0, GL::TEXTURE_2D, m_opaqueTexture, 0, m_sampleCount); >+ return; >+ } >+#endif >+ >+ if (!m_multisampleColorBuffer) >+ gl.framebufferTexture2D(GL::FRAMEBUFFER, GL::COLOR_ATTACHMENT0, GL::TEXTURE_2D, m_opaqueTexture, 0); >+} >+ >+void WebXROpaqueFramebuffer::endFrame() >+{ >+ m_framebuffer->setOpaqueActive(false); >+ >+ if (!m_context.graphicsContextGL()) >+ return; >+ auto& gl = *m_context.graphicsContextGL(); >+ >+ if (m_multisampleColorBuffer) { >+ TemporaryOpenGLSetting scopedScissor(GL::SCISSOR_TEST, 0); >+ TemporaryOpenGLSetting scopedDither(GL::DITHER, 0); >+ TemporaryOpenGLSetting scopedDepth(GL::DEPTH_TEST, 0); >+ TemporaryOpenGLSetting scopedStencil(GL::STENCIL_TEST, 0); >+ >+ GCGLint boundReadFBO { 0 }; >+ GCGLint boundDrawFBO { 0 }; >+ gl.getIntegerv(GL::READ_FRAMEBUFFER_BINDING, makeGCGLSpan(&boundReadFBO, 1)); >+ gl.getIntegerv(GL::DRAW_FRAMEBUFFER_BINDING, makeGCGLSpan(&boundDrawFBO, 1)); >+ >+ auto scopedFBOs = makeScopeExit([&gl, boundReadFBO, boundDrawFBO]() { >+ gl.bindFramebuffer(GL::READ_FRAMEBUFFER, boundReadFBO); >+ gl.bindFramebuffer(GL::DRAW_FRAMEBUFFER, boundDrawFBO); >+ }); >+ >+ gl.bindFramebuffer(GL::DRAW_FRAMEBUFFER, m_resolvedFBO); >+ gl.framebufferTexture2D(GL::FRAMEBUFFER, GL::COLOR_ATTACHMENT0, GL::TEXTURE_2D, m_opaqueTexture, 0); >+ >+ // Resolve multisample framebuffer >+ gl.bindFramebuffer(GL::READ_FRAMEBUFFER, m_framebuffer->object()); >+ gl.blitFramebuffer(0, 0, m_width, m_height, 0, 0, m_width, m_height, GL::COLOR_BUFFER_BIT, GL::LINEAR); >+ } >+ >+ gl.flush(); >+} >+ >+bool WebXROpaqueFramebuffer::setupFramebuffer() >+{ >+ if (!m_context.graphicsContextGL()) >+ return false; >+ auto& gl = *m_context.graphicsContextGL(); >+ >+ // Bind current FBOs when exiting the function >+ GCGLint boundFBO { 0 }; >+ GCGLint boundRenderbuffer { 0 }; >+ gl.getIntegerv(GL::FRAMEBUFFER_BINDING, makeGCGLSpan(&boundFBO, 1)); >+ gl.getIntegerv(GL::RENDERBUFFER_BINDING, makeGCGLSpan(&boundRenderbuffer, 1)); >+ auto scopedFBO = makeScopeExit([&gl, boundFBO, boundRenderbuffer]() { >+ gl.bindFramebuffer(GL::FRAMEBUFFER, boundFBO); >+ gl.bindRenderbuffer(GL::RENDERBUFFER, boundRenderbuffer); >+ }); >+ >+ // Set up color, depth and stencil formats >+ bool useDepthStencil = m_attributes.stencil || m_attributes.depth; >+ auto colorFormat = m_attributes.alpha ? GraphicsContextGL::RGBA8 : GraphicsContextGL::RGB8; >+#if USE(OPENGL_ES) >+ auto& extensions = reinterpret_cast<ExtensionsGLOpenGLES&>(gl.getExtensions()); >+ bool supportsPackedDepthStencil = useDepthStencil && extensions.supports("GL_OES_packed_depth_stencil"); >+ auto depthFormat = supportsPackedDepthStencil ? GL::DEPTH24_STENCIL8 : GL::DEPTH_COMPONENT16; >+ auto stencilFormat = GL::STENCIL_INDEX8; >+#else >+ auto& extensions = reinterpret_cast<ExtensionsGLOpenGLCommon&>(gl.getExtensions()); >+ bool supportsPackedDepthStencil = useDepthStencil && extensions.supports("GL_EXT_packed_depth_stencil"); >+ auto depthFormat = supportsPackedDepthStencil ? GL::DEPTH24_STENCIL8 : GL::DEPTH_COMPONENT; >+ auto stencilFormat = GL::STENCIL_COMPONENT; >+#endif >+ >+ // Set up recommended samples for WebXR. >+ // FIXME: check if we can get recommended values from each device platform. >+ if (m_attributes.antialias) { >+ GCGLint maxSampleCount; >+ gl.getIntegerv(ExtensionsGL::MAX_SAMPLES, makeGCGLSpan(&maxSampleCount, 1)); >+ // Using more than 4 samples might be overhead. >+ m_sampleCount = std::min(4, maxSampleCount); >+ } >+ >+#if USE(OPENGL_ES) >+ // Use multisampled_render_to_texture extension if available. >+ if (m_attributes.antialias && extensions.isImagination()) { >+ // framebufferTexture2DMultisampleIMG is set up in startFrame call. >+ if (!useDepthStencil) >+ return true; >+ >+ gl.bindFramebuffer(GL::FRAMEBUFFER, m_framebuffer->object()); >+ m_depthStencilBuffer = gl.createRenderbuffer(); >+ if (supportsPackedDepthStencil) { >+ gl.bindRenderbuffer(GL::RENDERBUFFER, m_depthStencilBuffer); >+ extensions.renderbufferStorageMultisampleANGLE(GL::RENDERBUFFER, m_sampleCount, depthFormat, m_width, m_height); >+ if (m_attributes.stencil) >+ gl.framebufferRenderbuffer(GL::FRAMEBUFFER, GL::STENCIL_ATTACHMENT, GL::RENDERBUFFER, m_depthStencilBuffer); >+ if (m_attributes.depth) >+ gl.framebufferRenderbuffer(GL::FRAMEBUFFER, GL::DEPTH_ATTACHMENT, GL::RENDERBUFFER, m_depthStencilBuffer); >+ } else { >+ if (m_attributes.stencil) { >+ m_stencilBuffer = gl.createRenderbuffer(); >+ gl.bindRenderbuffer(GL::RENDERBUFFER, m_stencilBuffer); >+ extensions.renderbufferStorageMultisampleANGLE(GL::RENDERBUFFER, m_sampleCount, stencilFormat, m_width, m_height); >+ gl.framebufferRenderbuffer(GL::FRAMEBUFFER, GL::STENCIL_ATTACHMENT, GL::RENDERBUFFER, m_stencilBuffer); >+ } >+ if (m_attributes.depth) { >+ gl.bindRenderbuffer(GL::RENDERBUFFER, m_depthStencilBuffer); >+ extensions.renderbufferStorageMultisampleANGLE(GL::RENDERBUFFER, m_sampleCount, depthFormat, m_width, m_height); >+ gl.framebufferRenderbuffer(GL::FRAMEBUFFER, GL::DEPTH_ATTACHMENT, GL::RENDERBUFFER, m_depthStencilBuffer); >+ } >+ } >+ return true; >+ } >+#endif // USE(OPENGL_ES) >+ >+ if (m_attributes.antialias && m_context.isWebGL2()) { >+ // Use an extra FBO for multisample if multisampled_render_to_texture is not supported. >+ m_resolvedFBO = gl.createFramebuffer(); >+ m_multisampleColorBuffer = gl.createRenderbuffer(); >+ gl.bindFramebuffer(GL::FRAMEBUFFER, m_framebuffer->object()); >+ gl.bindRenderbuffer(GL::RENDERBUFFER, m_multisampleColorBuffer); >+ gl.renderbufferStorageMultisample(GL::RENDERBUFFER, m_sampleCount, colorFormat, m_width, m_height); >+ gl.framebufferRenderbuffer(GL::FRAMEBUFFER, GL::COLOR_ATTACHMENT0, GL::RENDERBUFFER, m_multisampleColorBuffer); >+ if (useDepthStencil) { >+ m_depthStencilBuffer = gl.createRenderbuffer(); >+ if (supportsPackedDepthStencil) { >+ gl.bindRenderbuffer(GL::RENDERBUFFER, m_depthStencilBuffer); >+ gl.renderbufferStorageMultisample(GL::RENDERBUFFER, m_sampleCount, depthFormat, m_width, m_height); >+ if (m_attributes.stencil) >+ gl.framebufferRenderbuffer(GL::FRAMEBUFFER, GL::STENCIL_ATTACHMENT, GL::RENDERBUFFER, m_depthStencilBuffer); >+ if (m_attributes.depth) >+ gl.framebufferRenderbuffer(GL::FRAMEBUFFER, GL::DEPTH_ATTACHMENT, GL::RENDERBUFFER, m_depthStencilBuffer); >+ } else { >+ if (m_attributes.stencil) { >+ m_stencilBuffer = gl.createRenderbuffer(); >+ gl.bindRenderbuffer(GL::RENDERBUFFER, m_stencilBuffer); >+ gl.renderbufferStorageMultisample(GL::RENDERBUFFER, m_sampleCount, stencilFormat, m_width, m_height); >+ gl.framebufferRenderbuffer(GL::FRAMEBUFFER, GL::STENCIL_ATTACHMENT, GL::RENDERBUFFER, m_stencilBuffer); >+ } >+ if (m_attributes.depth) { >+ gl.bindRenderbuffer(GL::RENDERBUFFER, m_depthStencilBuffer); >+ gl.renderbufferStorageMultisample(GL::RENDERBUFFER, m_sampleCount, depthFormat, m_width, m_height); >+ gl.framebufferRenderbuffer(GL::FRAMEBUFFER, GL::DEPTH_ATTACHMENT, GL::RENDERBUFFER, m_depthStencilBuffer); >+ } >+ } >+ } >+ return gl.checkFramebufferStatus(GL::FRAMEBUFFER) == GL::FRAMEBUFFER_COMPLETE; >+ } >+ if (useDepthStencil) { >+ gl.bindFramebuffer(GL::FRAMEBUFFER, m_framebuffer->object()); >+ m_depthStencilBuffer = gl.createRenderbuffer(); >+ if (supportsPackedDepthStencil) { >+ gl.bindRenderbuffer(GL::RENDERBUFFER, m_depthStencilBuffer); >+ gl.renderbufferStorage(GL::RENDERBUFFER, depthFormat, m_width, m_height); >+ if (m_attributes.stencil) >+ gl.framebufferRenderbuffer(GL::FRAMEBUFFER, GL::STENCIL_ATTACHMENT, GL::RENDERBUFFER, m_depthStencilBuffer); >+ if (m_attributes.depth) >+ gl.framebufferRenderbuffer(GL::FRAMEBUFFER, GL::DEPTH_ATTACHMENT, GL::RENDERBUFFER, m_depthStencilBuffer); >+ } else { >+ if (m_attributes.stencil) { >+ m_stencilBuffer = gl.createRenderbuffer(); >+ gl.bindRenderbuffer(GL::RENDERBUFFER, m_stencilBuffer); >+ gl.renderbufferStorage(GL::RENDERBUFFER, stencilFormat, m_width, m_height); >+ gl.framebufferRenderbuffer(GL::FRAMEBUFFER, GL::STENCIL_ATTACHMENT, GL::RENDERBUFFER, m_stencilBuffer); >+ } >+ if (m_attributes.depth) { >+ gl.bindRenderbuffer(GL::RENDERBUFFER, m_depthStencilBuffer); >+ gl.renderbufferStorage(GL::RENDERBUFFER, depthFormat, m_width, m_height); >+ gl.framebufferRenderbuffer(GL::FRAMEBUFFER, GL::DEPTH_ATTACHMENT, GL::RENDERBUFFER, m_depthStencilBuffer); >+ } >+ } >+ } >+ >+ return true; > } > > } // namespace WebCore >diff --git a/Source/WebCore/Modules/webxr/WebXRWebGLLayer.h b/Source/WebCore/Modules/webxr/WebXRWebGLLayer.h >index 359535ed5d57095635d2686dda2985c09b310261..690c28a82e8bc2676df6b06369bac6b3258e8563 100644 >--- a/Source/WebCore/Modules/webxr/WebXRWebGLLayer.h >+++ b/Source/WebCore/Modules/webxr/WebXRWebGLLayer.h >@@ -30,6 +30,8 @@ > #include "CanvasBase.h" > #include "ExceptionOr.h" > #include "FloatRect.h" >+#include "GraphicsTypesGL.h" >+#include "PlatformXR.h" > #include "WebXRLayer.h" > #include <wtf/IsoMalloc.h> > #include <wtf/Optional.h> >@@ -43,9 +45,11 @@ class HTMLCanvasElement; > class IntSize; > class WebGLFramebuffer; > class WebGLRenderingContext; >+class WebGLRenderingContextBase; > #if ENABLE(WEBGL2) > class WebGL2RenderingContext; > #endif >+class WebXROpaqueFramebuffer; > class WebXRSession; > class WebXRView; > class WebXRViewport; >@@ -68,7 +72,7 @@ public: > bool antialias() const; > bool ignoreDepthValues() const; > >- WebGLFramebuffer* framebuffer() const; >+ const WebGLFramebuffer* framebuffer() const; > unsigned framebufferWidth() const; > unsigned framebufferHeight() const; > >@@ -82,8 +86,12 @@ public: > > HTMLCanvasElement* canvas() const; > >+ // WebXRLayer >+ void startFrame(const PlatformXR::Device::FrameData&) final; >+ PlatformXR::Device::Layer endFrame() final; >+ > private: >- WebXRWebGLLayer(Ref<WebXRSession>&&, WebXRRenderingContext&&, const XRWebGLLayerInit&); >+ WebXRWebGLLayer(Ref<WebXRSession>&&, WebXRRenderingContext&&, std::unique_ptr<WebXROpaqueFramebuffer>&&, bool antialias, bool ignoreDepthValues, bool isCompositionEnabled); > > void computeViewports(); > static IntSize computeNativeWebGLFramebufferResolution(); >@@ -92,7 +100,6 @@ private: > void canvasChanged(CanvasBase&, const Optional<FloatRect>&) final { }; > void canvasResized(CanvasBase&) final; > void canvasDestroyed(CanvasBase&) final { }; >- > Ref<WebXRSession> m_session; > WebXRRenderingContext m_context; > >@@ -103,16 +110,50 @@ private: > > ViewportData m_leftViewportData; > ViewportData m_rightViewportData; >+ std::unique_ptr<WebXROpaqueFramebuffer> m_framebuffer; > bool m_antialias { false }; > bool m_ignoreDepthValues { false }; > bool m_isCompositionEnabled { true }; > bool m_viewportsDirty { true }; >+}; >+ >+class WebXROpaqueFramebuffer { >+public: >+ struct Attributes { >+ bool alpha { true }; >+ bool antialias { true }; >+ bool depth { true }; >+ bool stencil { false }; >+ }; >+ >+ static std::unique_ptr<WebXROpaqueFramebuffer> create(PlatformXR::LayerHandle, WebGLRenderingContextBase&, Attributes&&, uint32_t width, uint32_t height); >+ ~WebXROpaqueFramebuffer(); >+ >+ PlatformXR::LayerHandle handle() const { return m_handle; } >+ const WebGLFramebuffer& framebuffer() const { return m_framebuffer.get(); } >+ uint32_t width() const { return m_width; } >+ uint32_t height() const { return m_height; } > >- struct { >- RefPtr<WebGLFramebuffer> object; >- unsigned width { 0 }; >- unsigned height { 0 }; >- } m_framebuffer; >+ void startFrame(const PlatformXR::Device::FrameData::LayerData&); >+ void endFrame(); >+ >+private: >+ WebXROpaqueFramebuffer(PlatformXR::LayerHandle, Ref<WebGLFramebuffer>&&, WebGLRenderingContextBase&, Attributes&&, uint32_t width, uint32_t height); >+ >+ bool setupFramebuffer(); >+ >+ PlatformXR::LayerHandle m_handle; >+ Ref<WebGLFramebuffer> m_framebuffer; >+ WebGLRenderingContextBase& m_context; >+ Attributes m_attributes; >+ uint32_t m_width { 0 }; >+ uint32_t m_height { 0 }; >+ PlatformGLObject m_depthStencilBuffer { 0 }; >+ PlatformGLObject m_stencilBuffer { 0 }; >+ PlatformGLObject m_multisampleColorBuffer { 0 }; >+ PlatformGLObject m_resolvedFBO { 0 }; >+ GCGLint m_sampleCount { 0 }; >+ PlatformGLObject m_opaqueTexture { 0 }; > }; > > } // namespace WebCore >diff --git a/Source/WebCore/Sources.txt b/Source/WebCore/Sources.txt >index ce9d448bf902b2f250191906d8a911de7a3d3565..e4fec798cb1f4a9d5fe332a9f64f9ab1ead62163 100644 >--- a/Source/WebCore/Sources.txt >+++ b/Source/WebCore/Sources.txt >@@ -2182,6 +2182,8 @@ platform/text/TextEncodingDetectorICU.cpp > platform/text/TextEncodingRegistry.cpp > platform/xr/openxr/OpenXRInstance.cpp @no-unify > platform/xr/openxr/OpenXRExtensions.cpp @no-unify >+platform/xr/openxr/OpenXRLayer.cpp @no-unify >+platform/xr/openxr/OpenXRSwapchain.cpp @no-unify > platform/xr/openxr/PlatformXROpenXR.cpp @no-unify > plugins/DOMMimeType.cpp > plugins/DOMMimeTypeArray.cpp >diff --git a/Source/WebCore/html/canvas/WebGL2RenderingContext.cpp b/Source/WebCore/html/canvas/WebGL2RenderingContext.cpp >index 9df3895a295ce0d92ef9baa65f58ab038c893644..21dea1f095e4fc031e628dcafd199b2928814eab 100644 >--- a/Source/WebCore/html/canvas/WebGL2RenderingContext.cpp >+++ b/Source/WebCore/html/canvas/WebGL2RenderingContext.cpp >@@ -2815,6 +2815,14 @@ WebGLAny WebGL2RenderingContext::getFramebufferAttachmentParameter(GCGLenum targ > return m_context->getFramebufferAttachmentParameteri(target, attachment, pname); > } > } >+ >+#if ENABLE(WEBXR) >+ if (targetFramebuffer->isOpaque()) { >+ synthesizeGLError(GraphicsContextGL::INVALID_OPERATION, "getFramebufferAttachmentParameter", "An opaque framebuffer's attachments cannot be inspected or changed"); >+ return nullptr; >+ } >+#endif >+ > if (!validateNonDefaultFramebufferAttachment(functionName, attachment)) > return nullptr; > >diff --git a/Source/WebCore/html/canvas/WebGLFramebuffer.cpp b/Source/WebCore/html/canvas/WebGLFramebuffer.cpp >index fd69fadf60eb605b1b8d42fd557624ff001fe63a..95abc033e2c6ed4fea25949433cd130d7f35fb57 100644 >--- a/Source/WebCore/html/canvas/WebGLFramebuffer.cpp >+++ b/Source/WebCore/html/canvas/WebGLFramebuffer.cpp >@@ -309,6 +309,17 @@ Ref<WebGLFramebuffer> WebGLFramebuffer::create(WebGLRenderingContextBase& ctx) > return adoptRef(*new WebGLFramebuffer(ctx)); > } > >+#if ENABLE(WEBXR) >+ >+Ref<WebGLFramebuffer> WebGLFramebuffer::createOpaque(WebGLRenderingContextBase& ctx) >+{ >+ auto framebuffer = adoptRef(*new WebGLFramebuffer(ctx)); >+ framebuffer->m_opaque = true; >+ return framebuffer; >+} >+ >+#endif >+ > WebGLFramebuffer::WebGLFramebuffer(WebGLRenderingContextBase& ctx) > : WebGLContextObject(ctx) > , m_hasEverBeenBound(false) >@@ -489,6 +500,16 @@ GCGLenum WebGLFramebuffer::getColorBufferFormat() const > > GCGLenum WebGLFramebuffer::checkStatus(const char** reason) const > { >+#if ENABLE(WEBXR) >+ // https://immersive-web.github.io/webxr/#opaque-framebuffer >+ if (m_opaque) { >+ if (m_opaqueActive) >+ return GL_FRAMEBUFFER_COMPLETE; >+ *reason = "An opaque framebuffer is considered incomplete outside of a requestAnimationFrame"; >+ return GL_FRAMEBUFFER_UNSUPPORTED; >+ } >+#endif >+ > unsigned int count = 0; > GCGLsizei width = 0, height = 0; > bool haveDepth = false; >diff --git a/Source/WebCore/html/canvas/WebGLFramebuffer.h b/Source/WebCore/html/canvas/WebGLFramebuffer.h >index 7b6df1f725748f89ccda46a84cd7c362498a2df2..314d51f699f4a70348aced53137ca1873379acf6 100644 >--- a/Source/WebCore/html/canvas/WebGLFramebuffer.h >+++ b/Source/WebCore/html/canvas/WebGLFramebuffer.h >@@ -74,6 +74,9 @@ public: > virtual ~WebGLFramebuffer(); > > static Ref<WebGLFramebuffer> create(WebGLRenderingContextBase&); >+#if ENABLE(WEBXR) >+ static Ref<WebGLFramebuffer> createOpaque(WebGLRenderingContextBase&); >+#endif > > void setAttachmentForBoundFramebuffer(GCGLenum target, GCGLenum attachment, GCGLenum texTarget, WebGLTexture*, GCGLint level, GCGLint layer); > void setAttachmentForBoundFramebuffer(GCGLenum target, GCGLenum attachment, WebGLRenderbuffer*); >@@ -116,6 +119,11 @@ public: > > void addMembersToOpaqueRoots(const WTF::AbstractLocker&, JSC::AbstractSlotVisitor&); > >+#if ENABLE(WEBXR) >+ bool isOpaque() const { return m_opaque; } >+ void setOpaqueActive(bool active) { m_opaqueActive = active; } >+#endif >+ > private: > WebGLFramebuffer(WebGLRenderingContextBase&); > >@@ -151,6 +159,12 @@ private: > > Vector<GCGLenum> m_drawBuffers; > Vector<GCGLenum> m_filteredDrawBuffers; >+ >+#if ENABLE(WEBXR) >+ bool m_opaque { false }; >+ bool m_opaqueActive { false }; >+ bool m_opaqueHasStencil { false }; >+#endif > }; > > } // namespace WebCore >diff --git a/Source/WebCore/html/canvas/WebGLRenderingContext.cpp b/Source/WebCore/html/canvas/WebGLRenderingContext.cpp >index a2960341b517830df66e567947a817e5bd73e26c..c9a944c6e1029f44d3d04f2733520a910ec48d24 100644 >--- a/Source/WebCore/html/canvas/WebGLRenderingContext.cpp >+++ b/Source/WebCore/html/canvas/WebGLRenderingContext.cpp >@@ -305,6 +305,13 @@ WebGLAny WebGLRenderingContext::getFramebufferAttachmentParameter(GCGLenum targe > return nullptr; > } > >+#if ENABLE(WEBXR) >+ if (m_framebufferBinding->isOpaque()) { >+ synthesizeGLError(GraphicsContextGL::INVALID_OPERATION, "getFramebufferAttachmentParameter", "An opaque framebuffer's attachments cannot be inspected or changed"); >+ return nullptr; >+ } >+#endif >+ > auto object = makeRefPtr(m_framebufferBinding->getAttachmentObject(attachment)); > if (!object) { > if (pname == GraphicsContextGL::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE) >diff --git a/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp b/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp >index 2facd12d284bca7e4543dd7b782bbcd92bcb6e74..2dd7071403765fd82aad92246cff9c28a7432b47 100644 >--- a/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp >+++ b/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp >@@ -2054,6 +2054,13 @@ void WebGLRenderingContextBase::deleteFramebuffer(WebGLFramebuffer* framebuffer) > { > auto locker = holdLock(objectGraphLock()); > >+#if ENABLE(WEBXR) >+ if (framebuffer && framebuffer->isOpaque()) { >+ synthesizeGLError(GraphicsContextGL::INVALID_OPERATION, "deleteFramebuffer", "An opaque framebuffer's attachments cannot be inspected or changed"); >+ return; >+ } >+#endif >+ > if (!deleteObject(locker, framebuffer)) > return; > >@@ -2734,6 +2741,14 @@ void WebGLRenderingContextBase::framebufferRenderbuffer(GCGLenum target, GCGLenu > synthesizeGLError(GraphicsContextGL::INVALID_OPERATION, "framebufferRenderbuffer", "no framebuffer bound"); > return; > } >+ >+#if ENABLE(WEBXR) >+ if (framebufferBinding->isOpaque()) { >+ synthesizeGLError(GraphicsContextGL::INVALID_OPERATION, "framebufferRenderbuffer", "An opaque framebuffer's attachments cannot be inspected or changed"); >+ return; >+ } >+#endif >+ > framebufferBinding->setAttachmentForBoundFramebuffer(target, attachment, buffer); > applyStencilTest(); > } >@@ -2757,6 +2772,13 @@ void WebGLRenderingContextBase::framebufferTexture2D(GCGLenum target, GCGLenum a > synthesizeGLError(GraphicsContextGL::INVALID_OPERATION, "framebufferTexture2D", "no framebuffer bound"); > return; > } >+#if ENABLE(WEBXR) >+ if (framebufferBinding->isOpaque()) { >+ synthesizeGLError(GraphicsContextGL::INVALID_OPERATION, "framebufferTexture2D", "An opaque framebuffer's attachments cannot be inspected or changed"); >+ return; >+ } >+#endif >+ > framebufferBinding->setAttachmentForBoundFramebuffer(target, attachment, textarget, texture, level, 0); > applyStencilTest(); > } >diff --git a/Source/WebCore/platform/xr/PlatformXR.h b/Source/WebCore/platform/xr/PlatformXR.h >index 56d8c6c8bda2d1b8683331d1d12e46aa13ec1f16..b66f0673e34238a86b08baaf10e4609bfa09d8d9 100644 >--- a/Source/WebCore/platform/xr/PlatformXR.h >+++ b/Source/WebCore/platform/xr/PlatformXR.h >@@ -19,6 +19,8 @@ > #pragma once > > #include "FloatPoint3D.h" >+#include "GraphicsTypesGL.h" >+#include "IntRect.h" > #include "IntSize.h" > #include <memory> > #include <wtf/CompletionHandler.h> >@@ -51,6 +53,8 @@ enum class Eye { > Right, > }; > >+using LayerHandle = int; >+ > #if ENABLE(WEBXR) > > class TrackingAndRenderingClient : public CanMakeWeakPtr<TrackingAndRenderingClient> { >@@ -80,6 +84,15 @@ public: > bool supportsOrientationTracking() const { return m_supportsOrientationTracking; } > bool supportsViewportScaling() const { return m_supportsViewportScaling; } > >+ // Returns the value that the device's recommended resolution must be multiplied by >+ // to yield the device's native framebuffer resolution. >+ virtual double nativeFramebufferScalingFactor() const { return 1.0; } >+ // Returns the value that the device's recommended resolution must be multiplied by >+ // to yield the device's max framebuffer resolution. This resolution can be larger than >+ // the native resolution if the device supports supersampling. >+ virtual double maxFramebufferScalingFactor() const { return nativeFramebufferScalingFactor(); } >+ >+ > virtual void initializeTrackingAndRendering(SessionMode) = 0; > virtual void shutDownTrackingAndRendering() = 0; > void setTrackingAndRenderingClient(WeakPtr<TrackingAndRenderingClient>&& client) { m_trackingAndRenderingClient = WTFMove(client); } >@@ -88,6 +101,8 @@ public: > // when the platform has completed all steps to shut down the XR session. > virtual bool supportsSessionShutdownNotification() const { return false; } > virtual void initializeReferenceSpace(ReferenceSpaceType) = 0; >+ virtual Optional<LayerHandle> createLayerProjection(uint32_t width, uint32_t height, bool alpha) = 0; >+ virtual void deleteLayer(LayerHandle) = 0; > > struct FrameData { > struct FloatQuaternion { >@@ -122,14 +137,31 @@ public: > Vector<WebCore::FloatPoint> bounds; > }; > >+ struct LayerData { >+ PlatformGLObject opaqueTexture { 0 }; >+ }; >+ > bool isTrackingValid { false }; > bool isPositionValid { false }; > bool isPositionEmulated { false }; >+ bool shouldRender { false }; > long predictedDisplayTime { 0 }; > Pose origin; > Optional<Pose> floorTransform; > StageParameters stageParameters; > Vector<View> views; >+ HashMap<LayerHandle, LayerData> layers; >+ }; >+ >+ struct LayerView { >+ Eye eye { Eye::None }; >+ WebCore::IntRect viewport; >+ }; >+ >+ struct Layer { >+ LayerHandle handle { 0 }; >+ bool visible { true }; >+ Vector<LayerView> views; > }; > > struct ViewData { >@@ -141,6 +173,7 @@ public: > > using RequestFrameCallback = Function<void(FrameData&&)>; > virtual void requestFrame(RequestFrameCallback&&) = 0; >+ virtual void submitFrame(Vector<Layer>&&) { }; > protected: > Device() = default; > >diff --git a/Source/WebCore/platform/xr/cocoa/PlatformXRCocoa.h b/Source/WebCore/platform/xr/cocoa/PlatformXRCocoa.h >index 902c2872e3db373888cce7ebf0d61c6c1a4c6972..fac38dafecbb075f1e6131e85c37f003da839c71 100644 >--- a/Source/WebCore/platform/xr/cocoa/PlatformXRCocoa.h >+++ b/Source/WebCore/platform/xr/cocoa/PlatformXRCocoa.h >@@ -37,6 +37,8 @@ public: > void initializeReferenceSpace(ReferenceSpaceType) override { } > Vector<ViewData> views(SessionMode) const override { return { }; } > void requestFrame(RequestFrameCallback&&) override { } >+ Optional<LayerHandle> createLayerProjection(uint32_t width, uint32_t height, bool alpha) override { return WTF::nullopt; }; >+ void deleteLayer(LayerHandle) override { }; > }; > > } >diff --git a/Source/WebCore/platform/xr/openxr/OpenXRLayer.cpp b/Source/WebCore/platform/xr/openxr/OpenXRLayer.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..783c337e2e01e1a209d5652d439c3001796293a2 >--- /dev/null >+++ b/Source/WebCore/platform/xr/openxr/OpenXRLayer.cpp >@@ -0,0 +1,99 @@ >+/* >+ * Copyright (C) 2021 Igalia, S.L. >+ * >+ * This library is free software; you can redistribute it and/or >+ * modify it under the terms of the GNU Library General Public >+ * License as published by the Free Software Foundation; either >+ * version 2 of the License, or (at your option) any later version. >+ * >+ * This library is distributed in the hope that it will be useful, >+ * but WITHOUT ANY WARRANTY; without even the implied warranty of >+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU >+ * Library General Public License for more details. >+ * >+ * You should have received a copy of the GNU Library General Public License >+ * aint with this library; see the file COPYING.LIB. If not, write to >+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, >+ * Boston, MA 02110-1301, USA. >+ */ >+ >+#include "config.h" >+#include "OpenXRLayer.h" >+ >+#if ENABLE(WEBXR) && USE(OPENXR) >+ >+using namespace WebCore; >+ >+namespace PlatformXR { >+ >+// OpenXRLayerProjection >+ >+std::unique_ptr<OpenXRLayerProjection> OpenXRLayerProjection::create(XrInstance instance, XrSession session, uint32_t width, uint32_t height, int64_t format, uint32_t sampleCount) >+{ >+ if (!width || !height || !sampleCount) >+ return nullptr; >+ >+ auto info = createStructure<XrSwapchainCreateInfo, XR_TYPE_SWAPCHAIN_CREATE_INFO>(); >+ info.arraySize = 1; >+ info.format = format; >+ info.width = width; >+ info.height = height; >+ info.mipCount = 1; >+ info.faceCount = 1; >+ info.arraySize = 1; >+ info.sampleCount = sampleCount; >+ info.usageFlags = XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT; >+ >+ auto swapchain = OpenXRSwapchain::create(instance, session, info); >+ if (!swapchain) >+ return nullptr; >+ >+ return std::unique_ptr<OpenXRLayerProjection>(new OpenXRLayerProjection(makeUniqueRefFromNonNullUniquePtr(WTFMove(swapchain)))); >+} >+ >+OpenXRLayerProjection::OpenXRLayerProjection(UniqueRef<OpenXRSwapchain>&& swapchain) >+ : m_swapchain(WTFMove(swapchain)) >+ , m_layerProjection(createStructure<XrCompositionLayerProjection, XR_TYPE_COMPOSITION_LAYER_PROJECTION>()) >+{ >+} >+ >+Optional<Device::FrameData::LayerData> OpenXRLayerProjection::startFrame() >+{ >+ auto texture = m_swapchain->acquireImage(); >+ if (!texture) >+ return WTF::nullopt; >+ >+ return Device::FrameData::LayerData { *texture }; >+} >+ >+XrCompositionLayerBaseHeader* OpenXRLayerProjection::endFrame(const Device::Layer& layer, XrSpace space, const Vector<XrView>& frameViews) >+{ >+ ASSERT(layer.views.size() == frameViews.size()); >+ >+ auto viewCount = frameViews.size(); >+ m_projectionViews.fill(createStructure<XrCompositionLayerProjectionView, XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW>(), viewCount); >+ m_layerProjection.layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT; >+ for (uint32_t i = 0; i < viewCount; ++i) { >+ m_projectionViews[i].pose = frameViews[i].pose; >+ m_projectionViews[i].fov = frameViews[i].fov; >+ m_projectionViews[i].subImage.swapchain = m_swapchain->swapchain(); >+ >+ auto& viewport = layer.views[i].viewport; >+ >+ m_projectionViews[i].subImage.imageRect.offset = { viewport.x(), viewport.y() }; >+ m_projectionViews[i].subImage.imageRect.extent = { viewport.width(), viewport.height() }; >+ } >+ >+ m_layerProjection.space = space; >+ m_layerProjection.viewCount = m_projectionViews.size(); >+ m_layerProjection.views = m_projectionViews.data(); >+ >+ m_swapchain->releaseImage(); >+ >+ return reinterpret_cast<XrCompositionLayerBaseHeader*>(&m_layerProjection); >+} >+ >+ >+} // namespace PlatformXR >+ >+#endif // ENABLE(WEBXR) && USE(OPENXR) >diff --git a/Source/WebCore/platform/xr/openxr/OpenXRLayer.h b/Source/WebCore/platform/xr/openxr/OpenXRLayer.h >new file mode 100644 >index 0000000000000000000000000000000000000000..885ea1e5c0a4e51637779c89690905899f1f6e9f >--- /dev/null >+++ b/Source/WebCore/platform/xr/openxr/OpenXRLayer.h >@@ -0,0 +1,65 @@ >+/* >+ * Copyright (C) 2021 Igalia, S.L. >+ * >+ * This library is free software; you can redistribute it and/or >+ * modify it under the terms of the GNU Library General Public >+ * License as published by the Free Software Foundation; either >+ * version 2 of the License, or (at your option) any later version. >+ * >+ * This library is distributed in the hope that it will be useful, >+ * but WITHOUT ANY WARRANTY; without even the implied warranty of >+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU >+ * Library General Public License for more details. >+ * >+ * You should have received a copy of the GNU Library General Public License >+ * aint with this library; see the file COPYING.LIB. If not, write to >+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, >+ * Boston, MA 02110-1301, USA. >+ */ >+ >+#pragma once >+ >+#if ENABLE(WEBXR) && USE(OPENXR) >+ >+#include "OpenXRSwapchain.h" >+#include "OpenXRUtils.h" >+#include "PlatformXR.h" >+ >+#include <wtf/Noncopyable.h> >+#include <wtf/UniqueRef.h> >+#include <wtf/Vector.h> >+ >+namespace PlatformXR { >+ >+class OpenXRLayer { >+ WTF_MAKE_FAST_ALLOCATED; >+ WTF_MAKE_NONCOPYABLE(OpenXRLayer); >+public: >+ virtual ~OpenXRLayer() = default; >+ >+ virtual Optional<Device::FrameData::LayerData> startFrame() = 0; >+ virtual XrCompositionLayerBaseHeader* endFrame(const Device::Layer&, XrSpace, const Vector<XrView>&) = 0; >+ >+protected: >+ OpenXRLayer() = default; >+}; >+ >+class OpenXRLayerProjection final: public OpenXRLayer { >+ WTF_MAKE_FAST_ALLOCATED; >+ WTF_MAKE_NONCOPYABLE(OpenXRLayerProjection); >+public: >+ static std::unique_ptr<OpenXRLayerProjection> create(XrInstance, XrSession, uint32_t width, uint32_t height, int64_t format, uint32_t sampleCount); >+private: >+ OpenXRLayerProjection(UniqueRef<OpenXRSwapchain>&&); >+ >+ Optional<Device::FrameData::LayerData> startFrame() final; >+ XrCompositionLayerBaseHeader* endFrame(const Device::Layer&, XrSpace, const Vector<XrView>&) final; >+ >+ UniqueRef<OpenXRSwapchain> m_swapchain; >+ XrCompositionLayerProjection m_layerProjection; >+ Vector<XrCompositionLayerProjectionView> m_projectionViews; >+}; >+ >+} // namespace PlatformXR >+ >+#endif // ENABLE(WEBXR) && USE(OPENXR) >diff --git a/Source/WebCore/platform/xr/openxr/OpenXRSwapchain.cpp b/Source/WebCore/platform/xr/openxr/OpenXRSwapchain.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..8e4adb6ed12a52721ed104b8a3e08ce69931b9fc >--- /dev/null >+++ b/Source/WebCore/platform/xr/openxr/OpenXRSwapchain.cpp >@@ -0,0 +1,113 @@ >+/* >+ * Copyright (C) 2020 Igalia, S.L. >+ * >+ * This library is free software; you can redistribute it and/or >+ * modify it under the terms of the GNU Library General Public >+ * License as published by the Free Software Foundation; either >+ * version 2 of the License, or (at your option) any later version. >+ * >+ * This library is distributed in the hope that it will be useful, >+ * but WITHOUT ANY WARRANTY; without even the implied warranty of >+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU >+ * Library General Public License for more details. >+ * >+ * You should have received a copy of the GNU Library General Public License >+ * aint with this library; see the file COPYING.LIB. If not, write to >+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, >+ * Boston, MA 02110-1301, USA. >+ */ >+ >+#include "config.h" >+ >+#if ENABLE(WEBXR) && USE(OPENXR) >+#include "OpenXRSwapchain.h" >+ >+using namespace WebCore; >+ >+namespace PlatformXR { >+ >+std::unique_ptr<OpenXRSwapchain> OpenXRSwapchain::create(XrInstance instance, XrSession session, const XrSwapchainCreateInfo& info) >+{ >+ ASSERT(session != XR_NULL_HANDLE); >+ ASSERT(info.faceCount == 1); >+ >+ XrSwapchain swapchain { XR_NULL_HANDLE }; >+ auto result = xrCreateSwapchain(session, &info, &swapchain); >+ RETURN_IF_FAILED(result, "xrEnumerateInstanceExtensionProperties", instance, nullptr); >+ ASSERT(swapchain != XR_NULL_HANDLE); >+ >+ uint32_t imageCount; >+ result = xrEnumerateSwapchainImages(swapchain, 0, &imageCount, nullptr); >+ RETURN_IF_FAILED(result, "xrEnumerateSwapchainImages", instance, nullptr); >+ if (!imageCount) { >+ LOG(XR, "xrEnumerateSwapchainImages(): no images\n"); >+ return nullptr; >+ } >+ >+ Vector<XrSwapchainImageOpenGLKHR> imageBuffers(imageCount, [] { >+ return createStructure<XrSwapchainImageOpenGLKHR, XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR>(); >+ }()); >+ >+ Vector<XrSwapchainImageBaseHeader*> imageHeaders = imageBuffers.map([](auto& image) mutable { >+ return (XrSwapchainImageBaseHeader*) ℑ >+ }); >+ >+ // Get images from an XrSwapchain >+ result = xrEnumerateSwapchainImages(swapchain, imageCount, &imageCount, imageHeaders[0]); >+ RETURN_IF_FAILED(result, "xrEnumerateSwapchainImages with imageCount", instance, nullptr); >+ >+ return std::unique_ptr<OpenXRSwapchain>(new OpenXRSwapchain(instance, session, swapchain, info, WTFMove(imageBuffers))); >+} >+ >+OpenXRSwapchain::OpenXRSwapchain(XrInstance instance, XrSession session, XrSwapchain swapchain, const XrSwapchainCreateInfo& info, Vector<XrSwapchainImageOpenGLKHR>&& imageBuffers) >+ : m_instance(instance) >+ , m_session(session) >+ , m_swapchain(swapchain) >+ , m_createInfo(info) >+ , m_imageBuffers(WTFMove(imageBuffers)) >+{ >+} >+ >+OpenXRSwapchain::~OpenXRSwapchain() >+{ >+ if (m_acquiredTexture) >+ releaseImage(); >+ if (m_swapchain != XR_NULL_HANDLE) >+ xrDestroySwapchain(m_swapchain); >+} >+ >+Optional<PlatformGLObject> OpenXRSwapchain::acquireImage() >+{ >+ RELEASE_ASSERT_WITH_MESSAGE(!m_acquiredTexture , "Expected no acquired images. ReleaseImage not called?"); >+ >+ auto acquireInfo = createStructure<XrSwapchainImageAcquireInfo, XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO>(); >+ uint32_t swapchainImageIndex = 0; >+ auto result = xrAcquireSwapchainImage(m_swapchain, &acquireInfo, &swapchainImageIndex); >+ RETURN_IF_FAILED(result, "xrAcquireSwapchainImage", m_instance, WTF::nullopt); >+ >+ RELEASE_ASSERT(swapchainImageIndex < m_imageBuffers.size()); >+ >+ auto waitInfo = createStructure<XrSwapchainImageWaitInfo, XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO>(); >+ waitInfo.timeout = XR_INFINITE_DURATION; >+ result = xrWaitSwapchainImage(m_swapchain, &waitInfo); >+ RETURN_IF_FAILED(result, "xrWaitSwapchainImage", m_instance, WTF::nullopt); >+ >+ m_acquiredTexture = m_imageBuffers[swapchainImageIndex].image; >+ >+ return m_acquiredTexture; >+} >+ >+void OpenXRSwapchain::releaseImage() >+{ >+ RELEASE_ASSERT_WITH_MESSAGE(m_acquiredTexture, "Expected a valid acquired image. AcquireImage not called?"); >+ >+ auto releaseInfo = createStructure<XrSwapchainImageReleaseInfo, XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO>(); >+ auto result = xrReleaseSwapchainImage(m_swapchain, &releaseInfo); >+ LOG_IF_FAILED(result, "xrReleaseSwapchainImage", m_instance); >+ >+ m_acquiredTexture = 0; >+} >+ >+} // namespace PlatformXR >+ >+#endif // ENABLE(WEBXR) && USE(OPENXR) >diff --git a/Source/WebCore/platform/xr/openxr/OpenXRSwapchain.h b/Source/WebCore/platform/xr/openxr/OpenXRSwapchain.h >new file mode 100644 >index 0000000000000000000000000000000000000000..bd8d3172e5d304ac44afbc6fa17a53d6d3bc17a3 >--- /dev/null >+++ b/Source/WebCore/platform/xr/openxr/OpenXRSwapchain.h >@@ -0,0 +1,59 @@ >+/* >+ * Copyright (C) 2021 Igalia, S.L. >+ * >+ * This library is free software; you can redistribute it and/or >+ * modify it under the terms of the GNU Library General Public >+ * License as published by the Free Software Foundation; either >+ * version 2 of the License, or (at your option) any later version. >+ * >+ * This library is distributed in the hope that it will be useful, >+ * but WITHOUT ANY WARRANTY; without even the implied warranty of >+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU >+ * Library General Public License for more details. >+ * >+ * You should have received a copy of the GNU Library General Public License >+ * aint with this library; see the file COPYING.LIB. If not, write to >+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, >+ * Boston, MA 02110-1301, USA. >+ */ >+ >+#pragma once >+ >+#if ENABLE(WEBXR) && USE(OPENXR) >+ >+#include "GraphicsContextGL.h" >+#include "OpenXRUtils.h" >+ >+#include <wtf/Noncopyable.h> >+#include <wtf/Vector.h> >+ >+namespace PlatformXR { >+ >+class OpenXRSwapchain { >+ WTF_MAKE_FAST_ALLOCATED; >+ WTF_MAKE_NONCOPYABLE(OpenXRSwapchain); >+public: >+ static std::unique_ptr<OpenXRSwapchain> create(XrInstance, XrSession, const XrSwapchainCreateInfo&); >+ ~OpenXRSwapchain(); >+ >+ Optional<PlatformGLObject> acquireImage(); >+ void releaseImage(); >+ XrSwapchain swapchain() const { return m_swapchain; } >+ int32_t width() const { return m_createInfo.width; } >+ int32_t height() const { return m_createInfo.height; } >+ >+private: >+ OpenXRSwapchain(XrInstance, XrSession, XrSwapchain, const XrSwapchainCreateInfo&, Vector<XrSwapchainImageOpenGLKHR>&&); >+ >+ XrInstance m_instance; >+ XrSession m_session; >+ XrSwapchain m_swapchain; >+ XrSwapchainCreateInfo m_createInfo; >+ Vector<XrSwapchainImageOpenGLKHR> m_imageBuffers; >+ PlatformGLObject m_acquiredTexture { 0 }; >+}; >+ >+ >+} // namespace PlatformXR >+ >+#endif // ENABLE(WEBXR) && USE(OPENXR) >diff --git a/Source/WebCore/platform/xr/openxr/OpenXRUtils.h b/Source/WebCore/platform/xr/openxr/OpenXRUtils.h >index 085814fd00ba88ade24b58bf79288bff18568c42..62c5cb1a6bd7f8ca441a6460bf7e8b66c890e67a 100644 >--- a/Source/WebCore/platform/xr/openxr/OpenXRUtils.h >+++ b/Source/WebCore/platform/xr/openxr/OpenXRUtils.h >@@ -70,6 +70,11 @@ inline String resultToString(XrResult value, XrInstance instance) > return __VA_ARGS__; \ > } > >+#define LOG_IF_FAILED(result, call, instance, ...) \ >+ if (XR_FAILED(result)) \ >+ LOG(XR, "%s %s: %s\n", __func__, call, resultToString(result, instance).utf8().data()); >+ >+ > inline Device::FrameData::Pose XrPosefToPose(XrPosef pose) > { > Device::FrameData::Pose result; >@@ -81,7 +86,7 @@ inline Device::FrameData::Pose XrPosefToPose(XrPosef pose) > inline Device::FrameData::View xrViewToPose(XrView view) > { > Device::FrameData::View pose; >- pose.projection = Device::FrameData::Fov { view.fov.angleUp, -view.fov.angleDown, -view.fov.angleLeft, view.fov.angleRight }; >+ pose.projection = Device::FrameData::Fov { fabs(view.fov.angleUp), fabs(view.fov.angleDown), fabs(view.fov.angleLeft), fabs(view.fov.angleRight) }; > pose.offset = XrPosefToPose(view.pose); > return pose; > } >diff --git a/Source/WebCore/platform/xr/openxr/PlatformXROpenXR.cpp b/Source/WebCore/platform/xr/openxr/PlatformXROpenXR.cpp >index a5ec9f18d90d9984bcee59db6239461543712823..24e934657de76ee08724c59b970ed4d271b7a291 100644 >--- a/Source/WebCore/platform/xr/openxr/PlatformXROpenXR.cpp >+++ b/Source/WebCore/platform/xr/openxr/PlatformXROpenXR.cpp >@@ -26,17 +26,12 @@ > > #include <wtf/NeverDestroyed.h> > #include <wtf/Optional.h> >+#include <wtf/threads/BinarySemaphore.h> > > using namespace WebCore; > > namespace PlatformXR { > >- >-static bool isSessionActive(XrSessionState state) >-{ >- return state == XR_SESSION_STATE_VISIBLE || state == XR_SESSION_STATE_FOCUSED; >-} >- > static bool isSessionReady(XrSessionState state) > { > return state >= XR_SESSION_STATE_READY && state < XR_SESSION_STATE_STOPPING; >@@ -52,7 +47,7 @@ Ref<OpenXRDevice> OpenXRDevice::create(XrInstance instance, XrSystemId system, R > OpenXRDevice::OpenXRDevice(XrInstance instance, XrSystemId system, Ref<WorkQueue>&& queue, const OpenXRExtensions& extensions) > : m_instance(instance) > , m_systemId(system) >- , m_queue(queue) >+ , m_queue(WTFMove(queue)) > , m_extensions(extensions) > { > } >@@ -113,6 +108,17 @@ void OpenXRDevice::initializeTrackingAndRendering(SessionMode mode) > auto& context = static_cast<GLContext&>(*m_egl); > context.makeContextCurrent(); > >+ GraphicsContextGLAttributes attributes; >+ attributes.depth = false; >+ attributes.stencil = false; >+ attributes.antialias = false; >+ >+ m_gl = GraphicsContextGL::create(attributes, nullptr); >+ if (!m_gl) { >+ LOG(XR, "Failed to create a valid GraphicsContextGL"); >+ return; >+ } >+ > m_graphicsBinding.display = PlatformDisplay::sharedDisplay().eglDisplay(); > m_graphicsBinding.context = context.platformContext(); > m_graphicsBinding.config = m_egl->config(); >@@ -124,7 +130,7 @@ void OpenXRDevice::initializeTrackingAndRendering(SessionMode mode) > sessionCreateInfo.next = &m_graphicsBinding; > > result = xrCreateSession(m_instance, &sessionCreateInfo, &m_session); >- RETURN_IF_FAILED(result, "xrEnumerateInstanceExtensionProperties", m_instance); >+ RETURN_IF_FAILED(result, "xrCreateSession", m_instance); > > // Create the default reference spaces > m_localSpace = createReferenceSpace(XR_REFERENCE_SPACE_TYPE_LOCAL); >@@ -170,73 +176,108 @@ void OpenXRDevice::requestFrame(RequestFrameCallback&& callback) > return; > } > >- auto frameState = createStructure<XrFrameState, XR_TYPE_FRAME_STATE>(); >+ m_frameState = createStructure<XrFrameState, XR_TYPE_FRAME_STATE>(); > auto frameWaitInfo = createStructure<XrFrameWaitInfo, XR_TYPE_FRAME_WAIT_INFO>(); >- auto result = xrWaitFrame(m_session, &frameWaitInfo, &frameState); >+ auto result = xrWaitFrame(m_session, &frameWaitInfo, &m_frameState); > RETURN_IF_FAILED(result, "xrWaitFrame", m_instance); >- XrTime predictedTime = frameState.predictedDisplayTime; > > auto frameBeginInfo = createStructure<XrFrameBeginInfo, XR_TYPE_FRAME_BEGIN_INFO>(); > result = xrBeginFrame(m_session, &frameBeginInfo); > RETURN_IF_FAILED(result, "xrBeginFrame", m_instance); > > Device::FrameData frameData; >- frameData.predictedDisplayTime = frameState.predictedDisplayTime; >+ frameData.predictedDisplayTime = m_frameState.predictedDisplayTime; >+ frameData.shouldRender = m_frameState.shouldRender; > frameData.stageParameters = m_stageParameters; > > ASSERT(m_configurationViews.contains(m_currentViewConfigurationType)); > const auto& configurationView = m_configurationViews.get(m_currentViewConfigurationType); > > uint32_t viewCount = configurationView.size(); >- Vector<XrView> views(viewCount, [] { >- return createStructure<XrView, XR_TYPE_VIEW>(); >- }()); >+ m_frameViews.fill(createStructure<XrView, XR_TYPE_VIEW>(), viewCount); > >- >- if (isSessionActive(m_sessionState)) { >+ if (m_frameState.shouldRender) { > // Query head location > auto location = createStructure<XrSpaceLocation, XR_TYPE_SPACE_LOCATION>(); >- xrLocateSpace(m_viewSpace, m_localSpace, frameState.predictedDisplayTime, &location); >+ xrLocateSpace(m_viewSpace, m_localSpace, m_frameState.predictedDisplayTime, &location); > frameData.isTrackingValid = location.locationFlags & XR_SPACE_LOCATION_ORIENTATION_VALID_BIT; > frameData.isPositionValid = location.locationFlags & XR_SPACE_LOCATION_POSITION_VALID_BIT; > frameData.isPositionEmulated = location.locationFlags & XR_SPACE_LOCATION_POSITION_TRACKED_BIT; > > if (frameData.isTrackingValid) > frameData.origin = XrPosefToPose(location.pose); >- > > auto viewLocateInfo = createStructure<XrViewLocateInfo, XR_TYPE_VIEW_LOCATE_INFO>(); >- viewLocateInfo.displayTime = predictedTime; >- viewLocateInfo.space = m_localSpace; >+ viewLocateInfo.displayTime = m_frameState.predictedDisplayTime; >+ viewLocateInfo.space = m_viewSpace; > > auto viewState = createStructure<XrViewState, XR_TYPE_VIEW_STATE>(); > uint32_t viewCountOutput; >- result = xrLocateViews(m_session, &viewLocateInfo, &viewState, viewCount, &viewCountOutput, views.data()); >+ result = xrLocateViews(m_session, &viewLocateInfo, &viewState, viewCount, &viewCountOutput, m_frameViews.data()); > if (!XR_FAILED(result)) { >- for (auto& view : views) >+ for (auto& view : m_frameViews) > frameData.views.append(xrViewToPose(view)); > } > > // Query floor transform > if (m_stageSpace != XR_NULL_HANDLE) { > auto floorLocation = createStructure<XrSpaceLocation, XR_TYPE_SPACE_LOCATION>(); >- xrLocateSpace(m_stageSpace, m_localSpace, frameState.predictedDisplayTime, &floorLocation); >+ xrLocateSpace(m_stageSpace, m_localSpace, m_frameState.predictedDisplayTime, &floorLocation); > frameData.floorTransform = { XrPosefToPose(floorLocation.pose) }; > } >+ >+ for (auto& layer : m_layers) { >+ auto layerData = layer.value->startFrame(); >+ if (layerData) >+ frameData.layers.add(layer.key, *layerData); >+ } >+ } else { >+ // https://www.khronos.org/registry/OpenXR/specs/1.0/man/html/XrFrameState.html >+ // When shouldRender is false the application should avoid heavy GPU work where possible, >+ // for example by skipping layer rendering and then omitting those layers when calling xrEndFrame. >+ // In this case we don't need to wait for OpenXRDevice::submitFrame to finish the frame. >+ auto frameEndInfo = createStructure<XrFrameEndInfo, XR_TYPE_FRAME_END_INFO>(); >+ frameEndInfo.displayTime = m_frameState.predictedDisplayTime; >+ frameEndInfo.environmentBlendMode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE; >+ frameEndInfo.layerCount = 0; >+ frameEndInfo.layers = nullptr; >+ LOG_IF_FAILED(xrEndFrame(m_session, &frameEndInfo), "xrEndFrame", m_instance); > } > > callOnMainThread([frameData = WTFMove(frameData), callback = WTFMove(callback)]() mutable { > callback(WTFMove(frameData)); > }); >+ }); >+} > >- >- Vector<const XrCompositionLayerBaseHeader*> layers; >+void OpenXRDevice::submitFrame(Vector<Device::Layer>&& layers) >+{ >+ m_queue.dispatch([this, protectedThis = makeRef(*this), layers = WTFMove(layers)]() mutable { >+ ASSERT(m_frameState.shouldRender); >+ Vector<const XrCompositionLayerBaseHeader*> frameEndLayers; >+ if (m_frameState.shouldRender) { >+ for (auto& layer : layers) { >+ auto it = m_layers.find(layer.handle); >+ if (it == m_layers.end()) { >+ LOG("Didn't find a OpenXRLayer with %d handle", layer.handle); >+ continue; >+ } >+ auto header = it->value->endFrame(layer, m_viewSpace, m_frameViews); >+ if (!header) { >+ LOG("endFrame() call failed in OpenXRLayer with %d handle", layer.handle()); >+ continue; >+ } >+ >+ frameEndLayers.append(header); >+ } >+ } > > auto frameEndInfo = createStructure<XrFrameEndInfo, XR_TYPE_FRAME_END_INFO>(); >- frameEndInfo.displayTime = predictedTime; >+ frameEndInfo.displayTime = m_frameState.predictedDisplayTime; > frameEndInfo.environmentBlendMode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE; >- frameEndInfo.layerCount = layers.size(); >- result = xrEndFrame(m_session, &frameEndInfo); >+ frameEndInfo.layerCount = frameEndLayers.size(); >+ frameEndInfo.layers = frameEndLayers.data(); >+ auto result = xrEndFrame(m_session, &frameEndInfo); > RETURN_IF_FAILED(result, "xrEndFrame", m_instance); > }); > } >@@ -256,7 +297,38 @@ Vector<Device::ViewData> OpenXRDevice::views(SessionMode mode) const > return views; > } > >-Device::FeatureList OpenXRDevice::collectSupportedFeatures() >+Optional<LayerHandle> OpenXRDevice::createLayerProjection(uint32_t width, uint32_t height, bool alpha) >+{ >+ Optional<LayerHandle> handle; >+ >+ BinarySemaphore semaphore; >+ m_queue.dispatch([this, width, height, alpha, &handle, &semaphore]() mutable { >+ auto format = alpha ? GL_RGBA8 : GL_RGB8; >+ int64_t sampleCount = 1; >+ >+ auto it = m_configurationViews.find(m_currentViewConfigurationType); >+ if (it != m_configurationViews.end()) >+ sampleCount = it->value[0].recommendedSwapchainSampleCount; >+ >+ auto layer = OpenXRLayerProjection::create(m_instance, m_session, width, height, format, sampleCount); >+ if (layer) { >+ handle = generateLayerHandle(); >+ m_layers.add(*handle, WTFMove(layer)); >+ } >+ >+ semaphore.signal(); >+ }); >+ semaphore.wait(); >+ >+ return handle; >+} >+ >+void OpenXRDevice::deleteLayer(LayerHandle handle) >+{ >+ m_layers.remove(handle); >+} >+ >+Device::FeatureList OpenXRDevice::collectSupportedFeatures() const > { > Device::FeatureList features; > >@@ -427,6 +499,7 @@ void OpenXRDevice::endSession() > void OpenXRDevice::resetSession() > { > ASSERT(&RunLoop::current() == &m_queue.runLoop()); >+ m_layers.clear(); > if (m_session != XR_NULL_HANDLE) { > xrDestroySession(m_session); > m_session = XR_NULL_HANDLE; >@@ -438,6 +511,7 @@ void OpenXRDevice::resetSession() > m_stageParameters = { }; > > // deallocate graphic resources >+ m_gl = nullptr; > m_egl.reset(); > } > >diff --git a/Source/WebCore/platform/xr/openxr/PlatformXROpenXR.h b/Source/WebCore/platform/xr/openxr/PlatformXROpenXR.h >index d4e26fce855a561e2dd33f0234a215c4befc4200..a86d5c949316a68680074a4756ad4c33aa79a9c9 100644 >--- a/Source/WebCore/platform/xr/openxr/PlatformXROpenXR.h >+++ b/Source/WebCore/platform/xr/openxr/PlatformXROpenXR.h >@@ -22,6 +22,8 @@ > #if ENABLE(WEBXR) && USE(OPENXR) > > #include "GLContextEGL.h" >+#include "GraphicsContextGL.h" >+#include "OpenXRLayer.h" > #include "OpenXRUtils.h" > #include "PlatformXR.h" > >@@ -59,10 +61,13 @@ private: > void initializeReferenceSpace(PlatformXR::ReferenceSpaceType) final; > bool supportsSessionShutdownNotification() const final { return true; } > void requestFrame(RequestFrameCallback&&) final; >+ void submitFrame(Vector<Device::Layer>&&) final; > Vector<ViewData> views(SessionMode) const final; >+ Optional<LayerHandle> createLayerProjection(uint32_t width, uint32_t height, bool alpha) final; >+ void deleteLayer(LayerHandle) final; > > // Custom methods >- FeatureList collectSupportedFeatures(); >+ FeatureList collectSupportedFeatures() const; > void collectSupportedSessionModes(); > void collectConfigurationViews(); > XrSpace createReferenceSpace(XrReferenceSpaceType); >@@ -73,6 +78,7 @@ private: > void handleSessionStateChange(); > void waitUntilStopping(); > void updateStageParameters(); >+ LayerHandle generateLayerHandle() { return ++m_handleIndex; } > > XrInstance m_instance; > XrSystemId m_systemId; >@@ -82,6 +88,11 @@ private: > XrSessionState m_sessionState { XR_SESSION_STATE_UNKNOWN }; > XrGraphicsBindingEGLMNDX m_graphicsBinding; > std::unique_ptr<WebCore::GLContextEGL> m_egl; >+ RefPtr<WebCore::GraphicsContextGL> m_gl; >+ XrFrameState m_frameState; >+ Vector<XrView> m_frameViews; >+ HashMap<LayerHandle, std::unique_ptr<OpenXRLayer>> m_layers; >+ LayerHandle m_handleIndex { 0 }; > > using ViewConfigurationPropertiesMap = HashMap<XrViewConfigurationType, XrViewConfigurationProperties, IntHash<XrViewConfigurationType>, WTF::StrongEnumHashTraits<XrViewConfigurationType>>; > ViewConfigurationPropertiesMap m_viewConfigurationProperties; >diff --git a/Source/WebCore/testing/WebFakeXRDevice.cpp b/Source/WebCore/testing/WebFakeXRDevice.cpp >index 33b5c2a305e7f213608e422eb6227c377071334a..1b77c95069c39dcc6050d78bd503c48a03189890 100644 >--- a/Source/WebCore/testing/WebFakeXRDevice.cpp >+++ b/Source/WebCore/testing/WebFakeXRDevice.cpp >@@ -29,6 +29,8 @@ > #if ENABLE(WEBXR) > > #include "DOMPointReadOnly.h" >+#include "GLContext.h" >+#include "GraphicsContextGL.h" > #include "JSDOMPromiseDeferred.h" > #include "WebFakeXRInputController.h" > #include <wtf/CompletionHandler.h> >@@ -75,8 +77,17 @@ void SimulatedXRDevice::simulateShutdownCompleted() > > WebCore::IntSize SimulatedXRDevice::recommendedResolution(PlatformXR::SessionMode) > { >- // Return at least a 2 pixel size so we can have different viewports for left and right eyes >- return IntSize(2, 2); >+ // Return at least a valid size for a framebuffer. >+ return IntSize(32, 32); >+} >+ >+void SimulatedXRDevice::initializeTrackingAndRendering(PlatformXR::SessionMode) >+{ >+ GraphicsContextGLAttributes attributes; >+ attributes.depth = false; >+ attributes.stencil = false; >+ attributes.antialias = false; >+ m_gl = GraphicsContextGL::create(attributes, nullptr); > } > > void SimulatedXRDevice::shutDownTrackingAndRendering() >@@ -84,6 +95,11 @@ void SimulatedXRDevice::shutDownTrackingAndRendering() > if (m_supportsShutdownNotification) > simulateShutdownCompleted(); > stopTimer(); >+ if (m_gl) { >+ for (auto layer : m_layers) >+ m_gl->deleteTexture(layer.value); >+ } >+ m_layers.clear(); > } > > void SimulatedXRDevice::stopTimer() >@@ -99,6 +115,7 @@ void SimulatedXRDevice::frameTimerFired() > update(); > > FrameData data; >+ data.shouldRender = true; > if (m_viewerOrigin) { > data.origin = *m_viewerOrigin; > data.isTrackingValid = true; >@@ -122,6 +139,9 @@ void SimulatedXRDevice::frameTimerFired() > data.views.append(view); > } > >+ for (auto& layer : m_layers) >+ data.layers.add(layer.key, FrameData::LayerData { .opaqueTexture = layer.value }); >+ > if (m_FrameCallback) > m_FrameCallback(WTFMove(data)); > } >@@ -133,6 +153,36 @@ void SimulatedXRDevice::requestFrame(RequestFrameCallback&& callback) > m_frameTimer.startOneShot(FakeXRFrameTime); > } > >+Optional<PlatformXR::LayerHandle> SimulatedXRDevice::createLayerProjection(uint32_t width, uint32_t height, bool alpha) >+{ >+ using GL = GraphicsContextGL; >+ if (!m_gl) >+ return WTF::nullopt; >+ PlatformXR::LayerHandle handle = ++m_layerIndex; >+ auto texture = m_gl->createTexture(); >+ auto colorFormat = alpha ? GL::RGBA8 : GL::RGB8; >+ >+ m_gl->bindTexture(GL::TEXTURE_2D, texture); >+ m_gl->texParameteri(GL::TEXTURE_2D, GL::TEXTURE_WRAP_S, GL::CLAMP_TO_EDGE); >+ m_gl->texParameteri(GL::TEXTURE_2D, GL::TEXTURE_WRAP_T, GL::CLAMP_TO_EDGE); >+ m_gl->texParameteri(GL::TEXTURE_2D, GL::TEXTURE_MIN_FILTER, GL::LINEAR); >+ m_gl->texParameteri(GL::TEXTURE_2D, GL::TEXTURE_MAG_FILTER, GL::LINEAR); >+ m_gl->texStorage2D(GL::TEXTURE_2D, 1, colorFormat, width, height); >+ >+ m_layers.add(handle, texture); >+ return handle; >+} >+ >+void SimulatedXRDevice::deleteLayer(PlatformXR::LayerHandle handle) >+{ >+ auto it = m_layers.find(handle); >+ if (it != m_layers.end()) { >+ if (m_gl) >+ m_gl->deleteTexture(it->value); >+ m_layers.remove(it); >+ } >+} >+ > Vector<PlatformXR::Device::ViewData> SimulatedXRDevice::views(PlatformXR::SessionMode mode) const > { > if (mode == PlatformXR::SessionMode::ImmersiveVr) >diff --git a/Source/WebCore/testing/WebFakeXRDevice.h b/Source/WebCore/testing/WebFakeXRDevice.h >index e127c059d31864b4c8d08263fd1d29fca4351c79..c73c0f39182295d82026a4d4ad449fbc69d532e3 100644 >--- a/Source/WebCore/testing/WebFakeXRDevice.h >+++ b/Source/WebCore/testing/WebFakeXRDevice.h >@@ -38,6 +38,9 @@ > #include <wtf/Vector.h> > > namespace WebCore { >+class GLContext; >+class GraphicsContextGL; >+ > class FakeXRView final : public RefCounted<FakeXRView> { > public: > static Ref<FakeXRView> create(XREye eye) { return adoptRef(*new FakeXRView(eye)); } >@@ -81,12 +84,14 @@ public: > void scheduleOnNextFrame(Function<void()>&&); > private: > WebCore::IntSize recommendedResolution(PlatformXR::SessionMode) final; >- void initializeTrackingAndRendering(PlatformXR::SessionMode) final { } >+ void initializeTrackingAndRendering(PlatformXR::SessionMode) final; > void shutDownTrackingAndRendering() final; > bool supportsSessionShutdownNotification() const final { return m_supportsShutdownNotification; } > void initializeReferenceSpace(PlatformXR::ReferenceSpaceType) final { } > Vector<PlatformXR::Device::ViewData> views(PlatformXR::SessionMode) const final; > void requestFrame(RequestFrameCallback&&) final; >+ Optional<PlatformXR::LayerHandle> createLayerProjection(uint32_t width, uint32_t height, bool alpha) final; >+ void deleteLayer(PlatformXR::LayerHandle) final; > > void stopTimer(); > void frameTimerFired(); >@@ -101,6 +106,9 @@ private: > RequestFrameCallback m_FrameCallback; > Vector<Function<void()>> m_pendingUpdates; > FrameData::StageParameters m_stageParameters; >+ RefPtr<WebCore::GraphicsContextGL> m_gl; >+ HashMap<PlatformXR::LayerHandle, PlatformGLObject> m_layers; >+ uint32_t m_layerIndex { 0 }; > }; > > class WebFakeXRDevice final : public RefCounted<WebFakeXRDevice> { >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index 44933b0291f55c51e98963ada823be57e03f4a46..a98fce781d078fe98e803dcf027536477fc0963e 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,14 @@ >+2021-03-02 Imanol Fernandez <ifernandez@igalia.com> >+ >+ Implement WebXR Opaque Framebuffer >+ https://bugs.webkit.org/show_bug.cgi?id=222607 >+ >+ Reviewed by Youenn Fablet. >+ >+ Update WebXR Opaque Framebuffer test expectations. >+ >+ * platform/wpe/TestExpectations: >+ > 2021-03-18 Youenn Fablet <youenn@apple.com> > > Geolocation API does not work in WKWebView with custom URL scheme handler >diff --git a/LayoutTests/imported/w3c/ChangeLog b/LayoutTests/imported/w3c/ChangeLog >index fa27f70868e1c3ca171d70be5fad6c7c7cf54ade..313f904e8b93a778b822daf9b12697b9e953761d 100644 >--- a/LayoutTests/imported/w3c/ChangeLog >+++ b/LayoutTests/imported/w3c/ChangeLog >@@ -1,3 +1,15 @@ >+2021-03-02 Imanol Fernandez <ifernandez@igalia.com> >+ >+ Implement WebXR Opaque Framebuffer >+ https://bugs.webkit.org/show_bug.cgi?id=222607 >+ >+ Reviewed by Youenn Fablet. >+ >+ Update WebXR Opaque Framebuffer test expectations. >+ >+ * web-platform-tests/webxr/xrWebGLLayer_framebuffer_draw.https-expected.txt: Added. >+ * web-platform-tests/webxr/xrWebGLLayer_opaque_framebuffer.https-expected.txt: Added. >+ > 2021-03-18 Cathie Chen <cathiechen@igalia.com> > > Import css/css-contain test from WPT >diff --git a/LayoutTests/imported/w3c/web-platform-tests/webxr/xrWebGLLayer_framebuffer_draw.https-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/webxr/xrWebGLLayer_framebuffer_draw.https-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..0f09dc9fdc2233ad4357bbb399a63a1aad003945 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/webxr/xrWebGLLayer_framebuffer_draw.https-expected.txt >@@ -0,0 +1,7 @@ >+CONSOLE MESSAGE: WebGL: INVALID_FRAMEBUFFER_OPERATION: clear: An opaque framebuffer is considered incomplete outside of a requestAnimationFrame >+CONSOLE MESSAGE: WebGL: INVALID_FRAMEBUFFER_OPERATION: clear: An opaque framebuffer is considered incomplete outside of a requestAnimationFrame >+CONSOLE MESSAGE: WebGL: INVALID_FRAMEBUFFER_OPERATION: drawArrays: An opaque framebuffer is considered incomplete outside of a requestAnimationFrame >+CONSOLE MESSAGE: WebGL: INVALID_FRAMEBUFFER_OPERATION: drawElements: An opaque framebuffer is considered incomplete outside of a requestAnimationFrame >+ >+PASS Ensure a WebGL layer's framebuffer can only be drawn to inside a XR frame >+ >diff --git a/LayoutTests/imported/w3c/web-platform-tests/webxr/xrWebGLLayer_opaque_framebuffer.https-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/webxr/xrWebGLLayer_opaque_framebuffer.https-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..c5cc76f5d96c7e90725f567e2c347e9fd0adcf10 >--- /dev/null >+++ b/LayoutTests/imported/w3c/web-platform-tests/webxr/xrWebGLLayer_opaque_framebuffer.https-expected.txt >@@ -0,0 +1,21 @@ >+CONSOLE MESSAGE: WebGL: INVALID_OPERATION: deleteFramebuffer: An opaque framebuffer's attachments cannot be inspected or changed >+CONSOLE MESSAGE: WebGL: INVALID_OPERATION: getFramebufferAttachmentParameter: An opaque framebuffer's attachments cannot be inspected or changed >+CONSOLE MESSAGE: WebGL: INVALID_OPERATION: getFramebufferAttachmentParameter: An opaque framebuffer's attachments cannot be inspected or changed >+CONSOLE MESSAGE: WebGL: INVALID_OPERATION: getFramebufferAttachmentParameter: An opaque framebuffer's attachments cannot be inspected or changed >+CONSOLE MESSAGE: WebGL: INVALID_OPERATION: getFramebufferAttachmentParameter: An opaque framebuffer's attachments cannot be inspected or changed >+CONSOLE MESSAGE: WebGL: INVALID_OPERATION: getFramebufferAttachmentParameter: An opaque framebuffer's attachments cannot be inspected or changed >+CONSOLE MESSAGE: WebGL: INVALID_OPERATION: getFramebufferAttachmentParameter: An opaque framebuffer's attachments cannot be inspected or changed >+CONSOLE MESSAGE: WebGL: INVALID_OPERATION: getFramebufferAttachmentParameter: An opaque framebuffer's attachments cannot be inspected or changed >+CONSOLE MESSAGE: WebGL: INVALID_OPERATION: getFramebufferAttachmentParameter: An opaque framebuffer's attachments cannot be inspected or changed >+CONSOLE MESSAGE: WebGL: INVALID_OPERATION: getFramebufferAttachmentParameter: An opaque framebuffer's attachments cannot be inspected or changed >+CONSOLE MESSAGE: WebGL: INVALID_OPERATION: getFramebufferAttachmentParameter: An opaque framebuffer's attachments cannot be inspected or changed >+CONSOLE MESSAGE: WebGL: INVALID_OPERATION: getFramebufferAttachmentParameter: An opaque framebuffer's attachments cannot be inspected or changed >+CONSOLE MESSAGE: WebGL: INVALID_OPERATION: getFramebufferAttachmentParameter: An opaque framebuffer's attachments cannot be inspected or changed >+CONSOLE MESSAGE: WebGL: INVALID_OPERATION: framebufferTexture2D: An opaque framebuffer's attachments cannot be inspected or changed >+CONSOLE MESSAGE: WebGL: INVALID_OPERATION: framebufferRenderbuffer: An opaque framebuffer's attachments cannot be inspected or changed >+CONSOLE MESSAGE: WebGL: INVALID_OPERATION: framebufferRenderbuffer: An opaque framebuffer's attachments cannot be inspected or changed >+CONSOLE MESSAGE: WebGL: checkFramebufferStatus:An opaque framebuffer is considered incomplete outside of a requestAnimationFrame >+ >+PASS Ensure that the framebuffer given by the WebGL layer is opaque for immersive >+PASS Ensure that the framebuffer given by the WebGL layer is opaque for non-immersive >+ >diff --git a/LayoutTests/platform/wpe/TestExpectations b/LayoutTests/platform/wpe/TestExpectations >index 67b190ee1c562eb67766efa4d4f54416310bffc7..0af58f3bca606801cc5acc210766d1263aa3d08f 100644 >--- a/LayoutTests/platform/wpe/TestExpectations >+++ b/LayoutTests/platform/wpe/TestExpectations >@@ -654,7 +654,9 @@ imported/w3c/web-platform-tests/webxr/xrSession_requestReferenceSpace_features.h > imported/w3c/web-platform-tests/webxr/xrSession_viewer_referenceSpace.https.html [ Pass ] > imported/w3c/web-platform-tests/webxr/xrViewport_valid.https.html [ Pass ] > imported/w3c/web-platform-tests/webxr/xrWebGLLayer_constructor.https.html [ Pass ] >+imported/w3c/web-platform-tests/webxr/xrWebGLLayer_framebuffer_draw.https.html [ Pass ] > imported/w3c/web-platform-tests/webxr/xrWebGLLayer_framebuffer_sameObject.https.html [ Pass ] >+imported/w3c/web-platform-tests/webxr/xrWebGLLayer_opaque_framebuffer.https.html [ Pass ] > imported/w3c/web-platform-tests/webxr/xrWebGLLayer_viewports.https.html [ Pass ] > imported/w3c/web-platform-tests/webxr/render_state_vertical_fov_immersive.https.html [ Pass ] > imported/w3c/web-platform-tests/webxr/render_state_update.https.html [ Pass ]
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 222607
:
421979
|
421982
|
422371
|
422562
|
422564
|
423181
|
423319
|
423590
|
423673