Skip to content
Permalink
Browse files
Add support for creating accelerated WebGL contexts in a worker
https://bugs.webkit.org/show_bug.cgi?id=247103

Reviewed by Dean Jackson.

* Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp:
(WebCore::getGraphicsClient):
(WebCore::WebGLRenderingContextBase::create):
(WebCore::WebGLRenderingContextBase::maybeRestoreContext):
* Source/WebCore/platform/GraphicsClient.h:
* Source/WebCore/platform/HostWindow.h:
* Source/WebKit/WebProcess/WebCoreSupport/WebWorkerClient.cpp:
(WebKit::WebWorkerClient::createGraphicsContextGL const):
* Source/WebKit/WebProcess/WebCoreSupport/WebWorkerClient.h:

Canonical link: https://commits.webkit.org/257541@main
  • Loading branch information
mattwoodrow committed Dec 8, 2022
1 parent 3c4cf6c commit cfc4f8094badecccd86eeaf81c072cb43cd6a41a
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 47 deletions.
@@ -115,6 +115,8 @@
#include "WebGLVertexArrayObject.h"
#include "WebGLVertexArrayObjectOES.h"
#include "WebXRSystem.h"
#include "WorkerClient.h"
#include "WorkerGlobalScope.h"
#include <JavaScriptCore/ConsoleMessage.h>
#include <JavaScriptCore/JSCInlines.h>
#include <JavaScriptCore/ScriptCallStack.h>
@@ -482,6 +484,22 @@ static void removeActiveContext(WebGLRenderingContextBase& context)
ASSERT_UNUSED(didContain, didContain);
}

static GraphicsClient* getGraphicsClient(CanvasBase& canvas)
{
if (auto* canvasElement = dynamicDowncast<HTMLCanvasElement>(canvas)) {
Document& document = canvasElement->document();
RefPtr<Frame> frame = document.frame();
if (!frame)
return nullptr;

return document.view()->root()->hostWindow();
}
if (is<WorkerGlobalScope>(canvas.scriptExecutionContext()))
return downcast<WorkerGlobalScope>(canvas.scriptExecutionContext())->workerClient();

return nullptr;
}

std::unique_ptr<WebGLRenderingContextBase> WebGLRenderingContextBase::create(CanvasBase& canvas, WebGLContextAttributes& attributes, WebGLVersion type)
{
auto scriptExecutionContext = canvas.scriptExecutionContext();
@@ -496,54 +514,53 @@ std::unique_ptr<WebGLRenderingContextBase> WebGLRenderingContextBase::create(Can
UNUSED_PARAM(type);
#endif

HostWindow* hostWindow = nullptr;
GraphicsClient* graphicsClient = getGraphicsClient(canvas);

auto* canvasElement = dynamicDowncast<HTMLCanvasElement>(canvas);

if (!scriptExecutionContext->settingsValues().webGLEnabled) {
canvasElement->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextcreationerrorEvent,
Event::CanBubble::No, Event::IsCancelable::Yes, "Web page was not allowed to create a WebGL context."_s));
return nullptr;
}

if (scriptExecutionContext->settingsValues().forceWebGLUsesLowPower) {
if (attributes.powerPreference == GraphicsContextGLPowerPreference::HighPerformance)
LOG(WebGL, "Overriding powerPreference from high-performance to low-power.");
attributes.powerPreference = GraphicsContextGLPowerPreference::LowPower;
}

if (canvasElement) {
Document& document = canvasElement->document();
RefPtr<Frame> frame = document.frame();
if (!frame)
return nullptr;

if (!frame->settings().webGLEnabled()) {
canvasElement->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextcreationerrorEvent,
Event::CanBubble::No, Event::IsCancelable::Yes, "Web page was not allowed to create a WebGL context."_s));
return nullptr;
}

Document& topDocument = document.topDocument();
Page* page = topDocument.page();
if (frame->settings().forceWebGLUsesLowPower()) {
if (attributes.powerPreference == GraphicsContextGLPowerPreference::HighPerformance)
LOG(WebGL, "Overriding powerPreference from high-performance to low-power.");
attributes.powerPreference = GraphicsContextGLPowerPreference::LowPower;
}

if (page)
attributes.devicePixelRatio = page->deviceScaleFactor();

hostWindow = document.view()->root()->hostWindow();
}

// FIXME: Should we try get the devicePixelRatio for workers for the page that created
// the worker? What if it's a shared worker, and there's multiple answers?

attributes.noExtensions = true;
attributes.shareResources = false;
attributes.initialPowerPreference = attributes.powerPreference;
attributes.webGLVersion = type;
#if PLATFORM(MAC)
// FIXME: Add MACCATALYST support for gpuIDForDisplay.
if (hostWindow)
attributes.windowGPUID = gpuIDForDisplay(hostWindow->displayID());
if (graphicsClient)
attributes.windowGPUID = gpuIDForDisplay(graphicsClient->displayID());
#endif
#if PLATFORM(COCOA)
attributes.useMetal = scriptExecutionContext->settingsValues().webGLUsingMetal;
#endif

RefPtr<GraphicsContextGL> context;
if (hostWindow)
context = hostWindow->createGraphicsContextGL(attributes);
// FIXME: OffscreenCanvas does not support GPU process and ANGLE does not support
// multi-threaded access so offscreen canvas is disabled.
if (graphicsClient)
context = graphicsClient->createGraphicsContextGL(attributes);
if (!context) {
if (canvasElement) {
canvasElement->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextcreationerrorEvent,
@@ -5506,28 +5523,18 @@ void WebGLRenderingContextBase::maybeRestoreContext()
return;
}

auto* canvas = htmlCanvas();
if (!canvas)
return;

RefPtr<Frame> frame = canvas->document().frame();
if (!frame)
auto scriptExecutionContext = canvasBase().scriptExecutionContext();
if (!scriptExecutionContext)
return;

if (!frame->settings().webGLEnabled())
if (!scriptExecutionContext->settingsValues().webGLEnabled)
return;

RefPtr<FrameView> view = frame->view();
if (!view)
return;
RefPtr<ScrollView> root = view->root();
if (!root)
return;
HostWindow* hostWindow = root->hostWindow();
if (!hostWindow)
GraphicsClient* graphicsClient = getGraphicsClient(canvasBase());
if (!graphicsClient)
return;

RefPtr<GraphicsContextGL> context = hostWindow->createGraphicsContextGL(m_attributes);
RefPtr<GraphicsContextGL> context = graphicsClient->createGraphicsContextGL(m_attributes);
if (!context) {
if (m_contextLostState->mode == RealLostContext)
m_restoreTimer.startOneShot(secondsBetweenRestoreAttempts);
@@ -5541,6 +5548,11 @@ void WebGLRenderingContextBase::maybeRestoreContext()
m_contextLostState = std::nullopt;
setupFlags();
initializeNewContext();

auto* canvas = htmlCanvas();
if (!canvas)
return;

if (!isContextLost())
canvas->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextrestoredEvent, Event::CanBubble::No, Event::IsCancelable::Yes, emptyString()));
}
@@ -30,8 +30,11 @@
namespace WebCore {

class DestinationColorSpace;
class GraphicsContextGL;
class ImageBuffer;

struct GraphicsContextGLAttributes;

enum class PixelFormat : uint8_t;
enum class RenderingMode : bool;
enum class RenderingPurpose : uint8_t;
@@ -45,6 +48,10 @@ class GraphicsClient {
virtual PlatformDisplayID displayID() const = 0;

virtual RefPtr<ImageBuffer> createImageBuffer(const FloatSize&, RenderingMode, RenderingPurpose, float resolutionScale, const DestinationColorSpace&, PixelFormat, bool avoidBackendSizeCheck = false) const = 0;
#if ENABLE(WEBGL)
virtual RefPtr<GraphicsContextGL> createGraphicsContextGL(const GraphicsContextGLAttributes&) const = 0;
#endif

};

} // namespace WebCore
@@ -31,9 +31,6 @@
namespace WebCore {

class Cursor;
class GraphicsContextGL;

struct GraphicsContextGLAttributes;

using FramesPerSecond = unsigned;

@@ -61,10 +58,6 @@ class HostWindow : public GraphicsClient {
virtual IntPoint accessibilityScreenToRootView(const IntPoint&) const = 0;
virtual IntRect rootViewToAccessibilityScreen(const IntRect&) const = 0;

#if ENABLE(WEBGL)
virtual RefPtr<GraphicsContextGL> createGraphicsContextGL(const GraphicsContextGLAttributes&) const = 0;
#endif

// Method for retrieving the native client of the page.
virtual PlatformPageClient platformPageClient() const = 0;

@@ -30,11 +30,22 @@
#include "RemoteImageBufferProxy.h"
#include "RemoteRenderingBackendProxy.h"

#if ENABLE(WEBGL) && ENABLE(GPU_PROCESS)
#include "RemoteGraphicsContextGLProxy.h"
#endif

#if ENABLE(WEBGL)
#include <WebCore/GraphicsContextGL.h>
#endif

namespace WebKit {
using namespace WebCore;

WebWorkerClient::WebWorkerClient(WebPage* page, SerialFunctionDispatcher& dispatcher)
: m_dispatcher(dispatcher)
#if ENABLE(GPU_PROCESS)
, m_connection(WebProcess::singleton().ensureGPUProcessConnection().connection())
#endif
{
ASSERT(isMainRunLoop());
#if ENABLE(GPU_PROCESS)
@@ -46,8 +57,9 @@ WebWorkerClient::WebWorkerClient(WebPage* page, SerialFunctionDispatcher& dispat
}

#if ENABLE(GPU_PROCESS)
WebWorkerClient::WebWorkerClient(SerialFunctionDispatcher& dispatcher, RemoteRenderingBackendCreationParameters& creationParameters, WebCore::PlatformDisplayID& displayID)
WebWorkerClient::WebWorkerClient(IPC::Connection& connection, SerialFunctionDispatcher& dispatcher, RemoteRenderingBackendCreationParameters& creationParameters, WebCore::PlatformDisplayID& displayID)
: m_dispatcher(dispatcher)
, m_connection(connection)
, m_creationParameters(creationParameters)
, m_displayID(displayID)
{ }
@@ -72,7 +84,7 @@ std::unique_ptr<WorkerClient> WebWorkerClient::clone(SerialFunctionDispatcher& d
{
assertIsCurrent(m_dispatcher);
#if ENABLE(GPU_PROCESS)
return makeUnique<WebWorkerClient>(dispatcher, m_creationParameters, m_displayID);
return makeUnique<WebWorkerClient>(m_connection, dispatcher, m_creationParameters, m_displayID);
#else
return makeUnique<WebWorkerClient>(dispatcher, m_displayID);
#endif
@@ -94,5 +106,16 @@ RefPtr<ImageBuffer> WebWorkerClient::createImageBuffer(const FloatSize& size, Re
return nullptr;
}

#if ENABLE(WEBGL)
RefPtr<GraphicsContextGL> WebWorkerClient::createGraphicsContextGL(const GraphicsContextGLAttributes& attributes) const
{
#if ENABLE(GPU_PROCESS)
if (WebProcess::singleton().shouldUseRemoteRenderingForWebGL())
return RemoteGraphicsContextGLProxy::create(m_connection, attributes, ensureRenderingBackend());
#endif
return WebCore::createWebProcessGraphicsContextGL(attributes);
}
#endif

}

@@ -25,6 +25,7 @@

#pragma once

#include "Connection.h"
#include "RemoteRenderingBackendCreationParameters.h"
#include <WebCore/WorkerClient.h>

@@ -47,7 +48,7 @@ class WebWorkerClient : public WebCore::WorkerClient {
// worker thread of the outer worker, and then transferred to the
// nested worker.
#if ENABLE(GPU_PROCESS)
WebWorkerClient(SerialFunctionDispatcher&, RemoteRenderingBackendCreationParameters&, WebCore::PlatformDisplayID&);
WebWorkerClient(IPC::Connection&, SerialFunctionDispatcher&, RemoteRenderingBackendCreationParameters&, WebCore::PlatformDisplayID&);
#else
WebWorkerClient(SerialFunctionDispatcher&, WebCore::PlatformDisplayID&);
#endif
@@ -57,6 +58,9 @@ class WebWorkerClient : public WebCore::WorkerClient {
WebCore::PlatformDisplayID displayID() const final;

RefPtr<WebCore::ImageBuffer> createImageBuffer(const WebCore::FloatSize&, WebCore::RenderingMode, WebCore::RenderingPurpose, float resolutionScale, const WebCore::DestinationColorSpace&, WebCore::PixelFormat, bool avoidBackendSizeCheck = false) const final;
#if ENABLE(WEBGL)
RefPtr<WebCore::GraphicsContextGL> createGraphicsContextGL(const WebCore::GraphicsContextGLAttributes&) const final;
#endif

private:
#if ENABLE(GPU_PROCESS)
@@ -65,6 +69,7 @@ class WebWorkerClient : public WebCore::WorkerClient {

SerialFunctionDispatcher& m_dispatcher;
#if ENABLE(GPU_PROCESS)
Ref<IPC::Connection> m_connection;
mutable std::unique_ptr<RemoteRenderingBackendProxy> m_remoteRenderingBackendProxy;
RemoteRenderingBackendCreationParameters m_creationParameters;
#endif

0 comments on commit cfc4f80

Please sign in to comment.