blob: d92cf08abfd1cc5fba57b6d2fc6414b738dc662a [file] [log] [blame]
/*
* Copyright (C) 2020 Igalia S.L. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "WebXRWebGLLayer.h"
#if ENABLE(WEBXR)
#include "IntSize.h"
#include "WebGLFramebuffer.h"
#include "WebGLRenderingContext.h"
#if ENABLE(WEBGL2)
#include "WebGL2RenderingContext.h"
#endif
#include "WebGLRenderingContextBase.h"
#include "WebXRSession.h"
#include "WebXRViewport.h"
#include "XRWebGLLayerInit.h"
#include <wtf/IsoMallocInlines.h>
#include <wtf/Scope.h>
namespace WebCore {
WTF_MAKE_ISO_ALLOCATED_IMPL(WebXRWebGLLayer);
// 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 };
// 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
// an InvalidStateError and abort these steps.
return WTF::switchOn(context,
[&](const RefPtr<WebGLRenderingContextBase>& baseContext) -> ExceptionOr<Ref<WebXRWebGLLayer>>
{
if (baseContext->isContextLost())
return Exception { InvalidStateError };
auto mode = session->mode();
if ((mode == XRSessionMode::ImmersiveAr || mode == XRSessionMode::ImmersiveVr) && !baseContext->isXRCompatible())
return Exception { InvalidStateError };
// 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_isCompositionDisabled) {
// 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.
}
// 10. Return layer.
return layer;
},
[](WTF::Monostate) {
ASSERT_NOT_REACHED();
return Exception { InvalidStateError };
}
);
}
// https://immersive-web.github.io/webxr/#native-webgl-framebuffer-resolution
IntSize WebXRWebGLLayer::computeNativeWebGLFramebufferResolution()
{
// FIXME: implement this
return { 1, 1 };
}
// https://immersive-web.github.io/webxr/#recommended-webgl-framebuffer-resolution
IntSize WebXRWebGLLayer::computeRecommendedWebGLFramebufferResolution()
{
return computeNativeWebGLFramebufferResolution();
}
WebXRWebGLLayer::WebXRWebGLLayer(Ref<WebXRSession>&& session, WebXRRenderingContext&& context, const XRWebGLLayerInit& init)
: WebXRLayer(session->scriptExecutionContext())
, m_session(WTFMove(session))
, m_context(WTFMove(context))
{
// 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_isCompositionDisabled = m_session->mode() == XRSessionMode::Inline;
// 9. If layer’s composition disabled boolean is false:
if (m_isCompositionDisabled) {
// 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 = computeRecommendedWebGLFramebufferResolution();
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;
}
}
WebXRWebGLLayer::~WebXRWebGLLayer() = default;
bool WebXRWebGLLayer::antialias() const
{
return m_antialias;
}
bool WebXRWebGLLayer::ignoreDepthValues() const
{
return m_ignoreDepthValues;
}
WebGLFramebuffer* WebXRWebGLLayer::framebuffer() const
{
return m_framebuffer.object.get();
}
unsigned WebXRWebGLLayer::framebufferWidth() const
{
if (m_framebuffer.object)
return m_framebuffer.width;
return WTF::switchOn(m_context,
[&](const RefPtr<WebGLRenderingContextBase>& baseContext) {
return baseContext->drawingBufferWidth();
});
}
unsigned WebXRWebGLLayer::framebufferHeight() const
{
if (m_framebuffer.object)
return m_framebuffer.height;
return WTF::switchOn(m_context,
[&](const RefPtr<WebGLRenderingContextBase>& baseContext) {
return baseContext->drawingBufferHeight();
});
}
RefPtr<WebXRViewport> WebXRWebGLLayer::getViewport(const WebXRView&)
{
return { };
}
double WebXRWebGLLayer::getNativeFramebufferScaleFactor(const WebXRSession& session)
{
if (session.ended())
return 0.0;
IntSize nativeSize = computeNativeWebGLFramebufferResolution();
IntSize recommendedSize = computeRecommendedWebGLFramebufferResolution();
RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(!recommendedSize.isZero());
return (nativeSize / recommendedSize).width();
}
} // namespace WebCore
#endif // ENABLE(WEBXR)