Diff
Modified: trunk/LayoutTests/ChangeLog (274694 => 274695)
--- trunk/LayoutTests/ChangeLog 2021-03-19 01:15:22 UTC (rev 274694)
+++ trunk/LayoutTests/ChangeLog 2021-03-19 01:27:38 UTC (rev 274695)
@@ -1,3 +1,14 @@
+2021-03-18 Imanol Fernandez <[email protected]>
+
+ 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 Diego Pino Garcia <[email protected]>
[GLIB] REGRESSION(r274273): fast/canvas/webgl/gl-teximage-imagebitmap.html is failing
Modified: trunk/LayoutTests/imported/w3c/ChangeLog (274694 => 274695)
--- trunk/LayoutTests/imported/w3c/ChangeLog 2021-03-19 01:15:22 UTC (rev 274694)
+++ trunk/LayoutTests/imported/w3c/ChangeLog 2021-03-19 01:27:38 UTC (rev 274695)
@@ -1,3 +1,15 @@
+2021-03-18 Imanol Fernandez <[email protected]>
+
+ 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 Truitt Savell <[email protected]>
Unreviewed, reverting r274644.
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/xrWebGLLayer_framebuffer_draw.https-expected.txt (0 => 274695)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/xrWebGLLayer_framebuffer_draw.https-expected.txt (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/xrWebGLLayer_framebuffer_draw.https-expected.txt 2021-03-19 01:27:38 UTC (rev 274695)
@@ -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
+
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/xrWebGLLayer_opaque_framebuffer.https-expected.txt (0 => 274695)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/xrWebGLLayer_opaque_framebuffer.https-expected.txt (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/webxr/xrWebGLLayer_opaque_framebuffer.https-expected.txt 2021-03-19 01:27:38 UTC (rev 274695)
@@ -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
+
Modified: trunk/LayoutTests/platform/wpe/TestExpectations (274694 => 274695)
--- trunk/LayoutTests/platform/wpe/TestExpectations 2021-03-19 01:15:22 UTC (rev 274694)
+++ trunk/LayoutTests/platform/wpe/TestExpectations 2021-03-19 01:27:38 UTC (rev 274695)
@@ -654,7 +654,9 @@
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 ]
Modified: trunk/Source/WebCore/ChangeLog (274694 => 274695)
--- trunk/Source/WebCore/ChangeLog 2021-03-19 01:15:22 UTC (rev 274694)
+++ trunk/Source/WebCore/ChangeLog 2021-03-19 01:27:38 UTC (rev 274695)
@@ -1,3 +1,116 @@
+2021-03-18 Imanol Fernandez <[email protected]>
+
+ 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 Wenson Hsieh <[email protected]>
Avoid copying item data when iterating in-process display lists
Modified: trunk/Source/WebCore/Modules/webxr/WebXRLayer.h (274694 => 274695)
--- trunk/Source/WebCore/Modules/webxr/WebXRLayer.h 2021-03-19 01:15:22 UTC (rev 274694)
+++ trunk/Source/WebCore/Modules/webxr/WebXRLayer.h 2021-03-19 01:27:38 UTC (rev 274695)
@@ -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 @@
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*);
Modified: trunk/Source/WebCore/Modules/webxr/WebXRSession.cpp (274694 => 274695)
--- trunk/Source/WebCore/Modules/webxr/WebXRSession.cpp 2021-03-19 01:15:22 UTC (rev 274694)
+++ trunk/Source/WebCore/Modules/webxr/WebXRSession.cpp 2021-03-19 01:27:38 UTC (rev 274695)
@@ -514,7 +514,11 @@
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 @@
// 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();
+
});
}
Modified: trunk/Source/WebCore/Modules/webxr/WebXRSession.h (274694 => 274695)
--- trunk/Source/WebCore/Modules/webxr/WebXRSession.h 2021-03-19 01:15:22 UTC (rev 274694)
+++ trunk/Source/WebCore/Modules/webxr/WebXRSession.h 2021-03-19 01:27:38 UTC (rev 274695)
@@ -73,6 +73,7 @@
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&&);
Modified: trunk/Source/WebCore/Modules/webxr/WebXRSystem.cpp (274694 => 274695)
--- trunk/Source/WebCore/Modules/webxr/WebXRSystem.cpp 2021-03-19 01:15:22 UTC (rev 274694)
+++ trunk/Source/WebCore/Modules/webxr/WebXRSystem.cpp 2021-03-19 01:27:38 UTC (rev 274695)
@@ -534,6 +534,7 @@
PlatformXR::Device::FrameData data;
data.isTrackingValid = true;
data.isPositionValid = true;
+ data.shouldRender = true;
data.views.append({ });
callback(WTFMove(data));
});
Modified: trunk/Source/WebCore/Modules/webxr/WebXRSystem.h (274694 => 274695)
--- trunk/Source/WebCore/Modules/webxr/WebXRSystem.h 2021-03-19 01:15:22 UTC (rev 274694)
+++ trunk/Source/WebCore/Modules/webxr/WebXRSystem.h 2021-03-19 01:27:38 UTC (rev 274695)
@@ -115,6 +115,8 @@
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;
Modified: trunk/Source/WebCore/Modules/webxr/WebXRViewport.h (274694 => 274695)
--- trunk/Source/WebCore/Modules/webxr/WebXRViewport.h 2021-03-19 01:15:22 UTC (rev 274694)
+++ trunk/Source/WebCore/Modules/webxr/WebXRViewport.h 2021-03-19 01:27:38 UTC (rev 274695)
@@ -43,6 +43,7 @@
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; }
Modified: trunk/Source/WebCore/Modules/webxr/WebXRWebGLLayer.cpp (274694 => 274695)
--- trunk/Source/WebCore/Modules/webxr/WebXRWebGLLayer.cpp 2021-03-19 01:15:22 UTC (rev 274694)
+++ trunk/Source/WebCore/Modules/webxr/WebXRWebGLLayer.cpp 2021-03-19 01:27:38 UTC (rev 274695)
@@ -28,9 +28,21 @@
#if ENABLE(WEBXR)
+#if !USE(ANGLE)
+#include "ExtensionsGLOpenGLCommon.h"
+#endif
+#if USE(OPENGL_ES)
+#include "ExtensionsGLOpenGLES.h"
+#endif
+#if !USE(ANGLE)
+#include "GraphicsContextGL.h"
+#endif
#include "HTMLCanvasElement.h"
#include "IntSize.h"
#include "OffscreenCanvas.h"
+#if !USE(ANGLE)
+#include "TemporaryOpenGLSetting.h"
+#endif
#include "WebGLFramebuffer.h"
#include "WebGLRenderingContext.h"
#if ENABLE(WEBGL2)
@@ -47,8 +59,52 @@
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)
{
@@ -55,7 +111,7 @@
// 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 +120,44 @@
[&](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));
+ // 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;
- 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.
+ // 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 +166,18 @@
);
}
-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 +185,11 @@
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 +202,15 @@
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 +219,8 @@
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 +287,39 @@
});
}
+
+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,11 +347,260 @@
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) {
+#if !USE(ANGLE)
+ // FIXME: These may be needed when using ANGLE, but it didn't compile in the initial implementation.
+ TemporaryOpenGLSetting scopedScissor(GL::SCISSOR_TEST, 0);
+ TemporaryOpenGLSetting scopedDither(GL::DITHER, 0);
+ TemporaryOpenGLSetting scopedDepth(GL::DEPTH_TEST, 0);
+ TemporaryOpenGLSetting scopedStencil(GL::STENCIL_TEST, 0);
+#endif
+
+ 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;
+#elif USE(ANGLE)
+ // FIXME: These values were chosen just to get this to compile successfully.
+ // Make sure they are correct.
+ bool supportsPackedDepthStencil = false;
+ auto depthFormat = supportsPackedDepthStencil ? GL::DEPTH24_STENCIL8 : GL::DEPTH_COMPONENT;
+ 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;
+#if USE(ANGLE)
+ // FIXME: This probably is not correct.
+ maxSampleCount = 0;
+#else
+ gl.getIntegerv(ExtensionsGL::MAX_SAMPLES, makeGCGLSpan(&maxSampleCount, 1));
+#endif
+ // 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
#endif // ENABLE(WEBXR)
Modified: trunk/Source/WebCore/Modules/webxr/WebXRWebGLLayer.h (274694 => 274695)
--- trunk/Source/WebCore/Modules/webxr/WebXRWebGLLayer.h 2021-03-19 01:15:22 UTC (rev 274694)
+++ trunk/Source/WebCore/Modules/webxr/WebXRWebGLLayer.h 2021-03-19 01:27:38 UTC (rev 274695)
@@ -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 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 @@
bool antialias() const;
bool ignoreDepthValues() const;
- WebGLFramebuffer* framebuffer() const;
+ const WebGLFramebuffer* framebuffer() const;
unsigned framebufferWidth() const;
unsigned framebufferHeight() const;
@@ -82,8 +86,12 @@
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 @@
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 @@
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 };
+};
- struct {
- RefPtr<WebGLFramebuffer> object;
- unsigned width { 0 };
- unsigned height { 0 };
- } m_framebuffer;
+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; }
+
+ 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
Modified: trunk/Source/WebCore/Sources.txt (274694 => 274695)
--- trunk/Source/WebCore/Sources.txt 2021-03-19 01:15:22 UTC (rev 274694)
+++ trunk/Source/WebCore/Sources.txt 2021-03-19 01:27:38 UTC (rev 274695)
@@ -2182,6 +2182,8 @@
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
Modified: trunk/Source/WebCore/html/canvas/WebGL2RenderingContext.cpp (274694 => 274695)
--- trunk/Source/WebCore/html/canvas/WebGL2RenderingContext.cpp 2021-03-19 01:15:22 UTC (rev 274694)
+++ trunk/Source/WebCore/html/canvas/WebGL2RenderingContext.cpp 2021-03-19 01:27:38 UTC (rev 274695)
@@ -2815,6 +2815,14 @@
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;
Modified: trunk/Source/WebCore/html/canvas/WebGLFramebuffer.cpp (274694 => 274695)
--- trunk/Source/WebCore/html/canvas/WebGLFramebuffer.cpp 2021-03-19 01:15:22 UTC (rev 274694)
+++ trunk/Source/WebCore/html/canvas/WebGLFramebuffer.cpp 2021-03-19 01:27:38 UTC (rev 274695)
@@ -309,6 +309,17 @@
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::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;
Modified: trunk/Source/WebCore/html/canvas/WebGLFramebuffer.h (274694 => 274695)
--- trunk/Source/WebCore/html/canvas/WebGLFramebuffer.h 2021-03-19 01:15:22 UTC (rev 274694)
+++ trunk/Source/WebCore/html/canvas/WebGLFramebuffer.h 2021-03-19 01:27:38 UTC (rev 274695)
@@ -74,6 +74,9 @@
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 @@
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,11 @@
Vector<GCGLenum> m_drawBuffers;
Vector<GCGLenum> m_filteredDrawBuffers;
+
+#if ENABLE(WEBXR)
+ bool m_opaque { false };
+ bool m_opaqueActive { false };
+#endif
};
} // namespace WebCore
Modified: trunk/Source/WebCore/html/canvas/WebGLRenderingContext.cpp (274694 => 274695)
--- trunk/Source/WebCore/html/canvas/WebGLRenderingContext.cpp 2021-03-19 01:15:22 UTC (rev 274694)
+++ trunk/Source/WebCore/html/canvas/WebGLRenderingContext.cpp 2021-03-19 01:27:38 UTC (rev 274695)
@@ -305,6 +305,13 @@
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)
Modified: trunk/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp (274694 => 274695)
--- trunk/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp 2021-03-19 01:15:22 UTC (rev 274694)
+++ trunk/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp 2021-03-19 01:27:38 UTC (rev 274695)
@@ -2054,6 +2054,13 @@
{
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 @@
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 @@
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();
}
Modified: trunk/Source/WebCore/platform/xr/PlatformXR.h (274694 => 274695)
--- trunk/Source/WebCore/platform/xr/PlatformXR.h 2021-03-19 01:15:22 UTC (rev 274694)
+++ trunk/Source/WebCore/platform/xr/PlatformXR.h 2021-03-19 01:27:38 UTC (rev 274695)
@@ -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 @@
Right,
};
+using LayerHandle = int;
+
#if ENABLE(WEBXR)
class TrackingAndRenderingClient : public CanMakeWeakPtr<TrackingAndRenderingClient> {
@@ -80,6 +84,15 @@
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 @@
// 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,16 +137,33 @@
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 {
bool active { false };
Eye eye { Eye::None };
@@ -141,6 +173,7 @@
using RequestFrameCallback = Function<void(FrameData&&)>;
virtual void requestFrame(RequestFrameCallback&&) = 0;
+ virtual void submitFrame(Vector<Layer>&&) { };
protected:
Device() = default;
Modified: trunk/Source/WebCore/platform/xr/cocoa/PlatformXRCocoa.h (274694 => 274695)
--- trunk/Source/WebCore/platform/xr/cocoa/PlatformXRCocoa.h 2021-03-19 01:15:22 UTC (rev 274694)
+++ trunk/Source/WebCore/platform/xr/cocoa/PlatformXRCocoa.h 2021-03-19 01:27:38 UTC (rev 274695)
@@ -37,6 +37,8 @@
void initializeReferenceSpace(ReferenceSpaceType) override { }
Vector<ViewData> views(SessionMode) const override { return { }; }
void requestFrame(RequestFrameCallback&&) override { }
+ Optional<LayerHandle> createLayerProjection(uint32_t, uint32_t, bool) override { return WTF::nullopt; };
+ void deleteLayer(LayerHandle) override { };
};
}
Added: trunk/Source/WebCore/platform/xr/openxr/OpenXRLayer.cpp (0 => 274695)
--- trunk/Source/WebCore/platform/xr/openxr/OpenXRLayer.cpp (rev 0)
+++ trunk/Source/WebCore/platform/xr/openxr/OpenXRLayer.cpp 2021-03-19 01:27:38 UTC (rev 274695)
@@ -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)
Added: trunk/Source/WebCore/platform/xr/openxr/OpenXRLayer.h (0 => 274695)
--- trunk/Source/WebCore/platform/xr/openxr/OpenXRLayer.h (rev 0)
+++ trunk/Source/WebCore/platform/xr/openxr/OpenXRLayer.h 2021-03-19 01:27:38 UTC (rev 274695)
@@ -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)
Added: trunk/Source/WebCore/platform/xr/openxr/OpenXRSwapchain.cpp (0 => 274695)
--- trunk/Source/WebCore/platform/xr/openxr/OpenXRSwapchain.cpp (rev 0)
+++ trunk/Source/WebCore/platform/xr/openxr/OpenXRSwapchain.cpp 2021-03-19 01:27:38 UTC (rev 274695)
@@ -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)
Added: trunk/Source/WebCore/platform/xr/openxr/OpenXRSwapchain.h (0 => 274695)
--- trunk/Source/WebCore/platform/xr/openxr/OpenXRSwapchain.h (rev 0)
+++ trunk/Source/WebCore/platform/xr/openxr/OpenXRSwapchain.h 2021-03-19 01:27:38 UTC (rev 274695)
@@ -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)
Modified: trunk/Source/WebCore/platform/xr/openxr/OpenXRUtils.h (274694 => 274695)
--- trunk/Source/WebCore/platform/xr/openxr/OpenXRUtils.h 2021-03-19 01:15:22 UTC (rev 274694)
+++ trunk/Source/WebCore/platform/xr/openxr/OpenXRUtils.h 2021-03-19 01:27:38 UTC (rev 274695)
@@ -70,6 +70,11 @@
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::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;
}
Modified: trunk/Source/WebCore/platform/xr/openxr/PlatformXROpenXR.cpp (274694 => 274695)
--- trunk/Source/WebCore/platform/xr/openxr/PlatformXROpenXR.cpp 2021-03-19 01:15:22 UTC (rev 274694)
+++ trunk/Source/WebCore/platform/xr/openxr/PlatformXROpenXR.cpp 2021-03-19 01:27:38 UTC (rev 274695)
@@ -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 @@
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 @@
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 @@
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,11 +176,10 @@
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);
@@ -181,7 +186,8 @@
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));
@@ -188,15 +194,12 @@
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;
@@ -203,17 +206,16 @@
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));
}
@@ -220,23 +222,62 @@
// 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));
});
+ });
+}
+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;
+ }
- Vector<const XrCompositionLayerBaseHeader*> layers;
+ 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,8 +297,39 @@
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;
// https://www.khronos.org/registry/OpenXR/specs/1.0/man/html/XrReferenceSpaceType.html
@@ -427,6 +499,7 @@
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 @@
m_stageParameters = { };
// deallocate graphic resources
+ m_gl = nullptr;
m_egl.reset();
}
Modified: trunk/Source/WebCore/platform/xr/openxr/PlatformXROpenXR.h (274694 => 274695)
--- trunk/Source/WebCore/platform/xr/openxr/PlatformXROpenXR.h 2021-03-19 01:15:22 UTC (rev 274694)
+++ trunk/Source/WebCore/platform/xr/openxr/PlatformXROpenXR.h 2021-03-19 01:27:38 UTC (rev 274695)
@@ -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 @@
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 @@
void handleSessionStateChange();
void waitUntilStopping();
void updateStageParameters();
+ LayerHandle generateLayerHandle() { return ++m_handleIndex; }
XrInstance m_instance;
XrSystemId m_systemId;
@@ -82,6 +88,11 @@
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;
Modified: trunk/Source/WebCore/testing/WebFakeXRDevice.cpp (274694 => 274695)
--- trunk/Source/WebCore/testing/WebFakeXRDevice.cpp 2021-03-19 01:15:22 UTC (rev 274694)
+++ trunk/Source/WebCore/testing/WebFakeXRDevice.cpp 2021-03-19 01:27:38 UTC (rev 274695)
@@ -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,15 +77,29 @@
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()
{
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 @@
update();
FrameData data;
+ data.shouldRender = true;
if (m_viewerOrigin) {
data.origin = *m_viewerOrigin;
data.isTrackingValid = true;
@@ -122,6 +139,9 @@
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 @@
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)
Modified: trunk/Source/WebCore/testing/WebFakeXRDevice.h (274694 => 274695)
--- trunk/Source/WebCore/testing/WebFakeXRDevice.h 2021-03-19 01:15:22 UTC (rev 274694)
+++ trunk/Source/WebCore/testing/WebFakeXRDevice.h 2021-03-19 01:27:38 UTC (rev 274695)
@@ -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 @@
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 @@
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> {