Diff
Modified: trunk/Source/WebKit/ChangeLog (269808 => 269809)
--- trunk/Source/WebKit/ChangeLog 2020-11-14 01:09:38 UTC (rev 269808)
+++ trunk/Source/WebKit/ChangeLog 2020-11-14 02:11:30 UTC (rev 269809)
@@ -1,5 +1,35 @@
2020-11-13 Chris Dumez <[email protected]>
+ [GPUProcess] Add basic GPUProcess crash handling for canvas
+ https://bugs.webkit.org/show_bug.cgi?id=218924
+
+ Reviewed by Simon Fraser.
+
+ Update RemoteRenderingBackendProxy to be a GPUProcessConnection::Client so that it
+ gets notified when the IPC connection to the GPUProcess gets severed. When this
+ happens, RemoteRenderingBackendProxy clears all its SharedMemory handles and
+ sends IPC messages to the GPU process to recreate all the ImageBuffers we had.
+
+ * WebProcess/GPU/graphics/RemoteImageBufferProxy.h:
+ (WebKit::RemoteImageBufferProxy::create):
+ (WebKit::RemoteImageBufferProxy::clearBackend):
+ (WebKit::RemoteImageBufferProxy::size const):
+ (WebKit::RemoteImageBufferProxy::renderingMode const):
+ (WebKit::RemoteImageBufferProxy::colorSpace const):
+ (WebKit::RemoteImageBufferProxy::pixelFormat const):
+ (WebKit::RemoteImageBufferProxy::RemoteImageBufferProxy):
+ * WebProcess/GPU/graphics/RemoteRenderingBackendProxy.cpp:
+ (WebKit::RemoteRenderingBackendProxy::RemoteRenderingBackendProxy):
+ (WebKit::RemoteRenderingBackendProxy::connectToGPUProcess):
+ (WebKit::recreateImage):
+ (WebKit::RemoteRenderingBackendProxy::gpuProcessConnectionDidClose):
+ (WebKit::RemoteRenderingBackendProxy::createImageBuffer):
+ * WebProcess/GPU/graphics/RemoteRenderingBackendProxy.h:
+ * WebProcess/GPU/graphics/RemoteResourceCacheProxy.h:
+ (WebKit::RemoteResourceCacheProxy::imageBuffers const):
+
+2020-11-13 Chris Dumez <[email protected]>
+
[GPUProcess] Add basic low memory handling in the GPUProcess
https://bugs.webkit.org/show_bug.cgi?id=218926
<rdar://problem/70300888>
Modified: trunk/Source/WebKit/WebProcess/GPU/graphics/RemoteImageBufferProxy.h (269808 => 269809)
--- trunk/Source/WebKit/WebProcess/GPU/graphics/RemoteImageBufferProxy.h 2020-11-14 01:09:38 UTC (rev 269808)
+++ trunk/Source/WebKit/WebProcess/GPU/graphics/RemoteImageBufferProxy.h 2020-11-14 02:11:30 UTC (rev 269809)
@@ -48,12 +48,12 @@
using BaseDisplayListImageBuffer::m_renderingResourceIdentifier;
public:
- static RefPtr<RemoteImageBufferProxy> create(const WebCore::FloatSize& size, float resolutionScale, RemoteRenderingBackendProxy& remoteRenderingBackendProxy)
+ static RefPtr<RemoteImageBufferProxy> create(const WebCore::FloatSize& size, WebCore::RenderingMode renderingMode, float resolutionScale, WebCore::ColorSpace colorSpace, WebCore::PixelFormat pixelFormat, RemoteRenderingBackendProxy& remoteRenderingBackendProxy)
{
if (BackendType::calculateBackendSize(size, resolutionScale).isEmpty())
return nullptr;
- return adoptRef(new RemoteImageBufferProxy(size, remoteRenderingBackendProxy));
+ return adoptRef(new RemoteImageBufferProxy(size, renderingMode, resolutionScale, colorSpace, pixelFormat, remoteRenderingBackendProxy));
}
~RemoteImageBufferProxy()
@@ -65,6 +65,8 @@
m_remoteRenderingBackendProxy->releaseRemoteResource(m_renderingResourceIdentifier);
}
+ void clearBackend() { m_backend = nullptr; }
+
void createBackend(const WebCore::FloatSize& logicalSize, const WebCore::IntSize& backendSize, float resolutionScale, WebCore::ColorSpace colorSpace, WebCore::PixelFormat pixelFormat, ImageBufferBackendHandle handle)
{
ASSERT(!m_backend);
@@ -76,10 +78,21 @@
m_receivedFlushIdentifier = flushIdentifier;
}
+ const WebCore::FloatSize& size() const { return m_size; }
+ WebCore::RenderingMode renderingMode() const { return m_renderingMode; }
+ float resolutionScale() const final { return m_resolutionScale; }
+ WebCore::ColorSpace colorSpace() const { return m_colorSpace; }
+ WebCore::PixelFormat pixelFormat() const { return m_pixelFormat; }
+
protected:
- RemoteImageBufferProxy(const WebCore::FloatSize& size, RemoteRenderingBackendProxy& remoteRenderingBackendProxy)
+ RemoteImageBufferProxy(const WebCore::FloatSize& size, WebCore::RenderingMode renderingMode, float resolutionScale, WebCore::ColorSpace colorSpace, WebCore::PixelFormat pixelFormat, RemoteRenderingBackendProxy& remoteRenderingBackendProxy)
: BaseDisplayListImageBuffer(size, this)
, m_remoteRenderingBackendProxy(makeWeakPtr(remoteRenderingBackendProxy))
+ , m_size(size)
+ , m_renderingMode(renderingMode)
+ , m_resolutionScale(resolutionScale)
+ , m_colorSpace(colorSpace)
+ , m_pixelFormat(pixelFormat)
{
ASSERT(m_remoteRenderingBackendProxy);
m_remoteRenderingBackendProxy->remoteResourceCacheProxy().cacheImageBuffer(*this);
@@ -303,6 +316,11 @@
WebCore::DisplayList::FlushIdentifier m_receivedFlushIdentifier;
WeakPtr<RemoteRenderingBackendProxy> m_remoteRenderingBackendProxy;
size_t m_itemCountInCurrentDisplayList { 0 };
+ WebCore::FloatSize m_size;
+ WebCore::RenderingMode m_renderingMode;
+ float m_resolutionScale;
+ WebCore::ColorSpace m_colorSpace;
+ WebCore::PixelFormat m_pixelFormat;
};
} // namespace WebKit
Modified: trunk/Source/WebKit/WebProcess/GPU/graphics/RemoteRenderingBackendProxy.cpp (269808 => 269809)
--- trunk/Source/WebKit/WebProcess/GPU/graphics/RemoteRenderingBackendProxy.cpp 2020-11-14 01:09:38 UTC (rev 269808)
+++ trunk/Source/WebKit/WebProcess/GPU/graphics/RemoteRenderingBackendProxy.cpp 2020-11-14 02:11:30 UTC (rev 269809)
@@ -30,7 +30,6 @@
#include "DisplayListWriterHandle.h"
#include "GPUConnectionToWebProcess.h"
-#include "GPUProcessConnection.h"
#include "ImageDataReference.h"
#include "PlatformRemoteImageBufferProxy.h"
#include "RemoteRenderingBackendMessages.h"
@@ -49,12 +48,7 @@
RemoteRenderingBackendProxy::RemoteRenderingBackendProxy()
{
- // Register itself as a MessageReceiver in the GPUProcessConnection.
- IPC::MessageReceiverMap& messageReceiverMap = WebProcess::singleton().ensureGPUProcessConnection().messageReceiverMap();
- messageReceiverMap.addMessageReceiver(Messages::RemoteRenderingBackendProxy::messageReceiverName(), m_renderingBackendIdentifier.toUInt64(), *this);
-
- // Create the RemoteRenderingBackend
- send(Messages::GPUConnectionToWebProcess::CreateRenderingBackend(m_renderingBackendIdentifier), 0);
+ connectToGPUProcess();
}
RemoteRenderingBackendProxy::~RemoteRenderingBackendProxy()
@@ -67,6 +61,47 @@
send(Messages::GPUConnectionToWebProcess::ReleaseRenderingBackend(m_renderingBackendIdentifier), 0);
}
+void RemoteRenderingBackendProxy::connectToGPUProcess()
+{
+ auto& connection = WebProcess::singleton().ensureGPUProcessConnection();
+ connection.addClient(*this);
+ connection.messageReceiverMap().addMessageReceiver(Messages::RemoteRenderingBackendProxy::messageReceiverName(), m_renderingBackendIdentifier.toUInt64(), *this);
+
+ send(Messages::GPUConnectionToWebProcess::CreateRenderingBackend(m_renderingBackendIdentifier), 0);
+}
+
+template<typename T>
+static void recreateImageBuffer(RemoteRenderingBackendProxy& proxy, T& imageBuffer, RenderingResourceIdentifier resourceIdentifier, RenderingBackendIdentifier renderingBackendIdentifier)
+{
+ imageBuffer.clearBackend();
+ proxy.send(Messages::RemoteRenderingBackend::CreateImageBuffer(imageBuffer.size(), imageBuffer.renderingMode(), imageBuffer.resolutionScale(), imageBuffer.colorSpace(), imageBuffer.pixelFormat(), resourceIdentifier), renderingBackendIdentifier);
+}
+
+void RemoteRenderingBackendProxy::reestablishGPUProcessConnection()
+{
+ connectToGPUProcess();
+
+ for (auto& pair : m_remoteResourceCacheProxy.imageBuffers()) {
+ if (auto& baseImageBuffer = pair.value) {
+ if (is<AcceleratedRemoteImageBufferProxy>(*baseImageBuffer))
+ recreateImageBuffer(*this, downcast<AcceleratedRemoteImageBufferProxy>(*baseImageBuffer), pair.key, m_renderingBackendIdentifier);
+ else
+ recreateImageBuffer(*this, downcast<UnacceleratedRemoteImageBufferProxy>(*baseImageBuffer), pair.key, m_renderingBackendIdentifier);
+ }
+ }
+}
+
+void RemoteRenderingBackendProxy::gpuProcessConnectionDidClose(GPUProcessConnection& previousConnection)
+{
+ previousConnection.removeClient(*this);
+
+ m_identifiersOfReusableHandles.clear();
+ m_identifiersOfHandlesAvailableForWriting.clear();
+ m_sharedDisplayListHandles.clear();
+
+ reestablishGPUProcessConnection();
+}
+
IPC::Connection* RemoteRenderingBackendProxy::messageSenderConnection() const
{
return &WebProcess::singleton().ensureGPUProcessConnection().connection();
@@ -94,10 +129,10 @@
RefPtr<ImageBuffer> imageBuffer;
if (renderingMode == RenderingMode::Accelerated)
- imageBuffer = AcceleratedRemoteImageBufferProxy::create(size, resolutionScale, *this);
+ imageBuffer = AcceleratedRemoteImageBufferProxy::create(size, renderingMode, resolutionScale, colorSpace, pixelFormat, *this);
if (!imageBuffer)
- imageBuffer = UnacceleratedRemoteImageBufferProxy::create(size, resolutionScale, *this);
+ imageBuffer = UnacceleratedRemoteImageBufferProxy::create(size, renderingMode, resolutionScale, colorSpace, pixelFormat, *this);
if (imageBuffer) {
send(Messages::RemoteRenderingBackend::CreateImageBuffer(size, renderingMode, resolutionScale, colorSpace, pixelFormat, imageBuffer->renderingResourceIdentifier()), m_renderingBackendIdentifier);
Modified: trunk/Source/WebKit/WebProcess/GPU/graphics/RemoteRenderingBackendProxy.h (269808 => 269809)
--- trunk/Source/WebKit/WebProcess/GPU/graphics/RemoteRenderingBackendProxy.h 2020-11-14 01:09:38 UTC (rev 269808)
+++ trunk/Source/WebKit/WebProcess/GPU/graphics/RemoteRenderingBackendProxy.h 2020-11-14 02:11:30 UTC (rev 269809)
@@ -27,6 +27,7 @@
#if ENABLE(GPU_PROCESS)
+#include "GPUProcessConnection.h"
#include "ImageBufferBackendHandle.h"
#include "MessageReceiver.h"
#include "MessageSender.h"
@@ -56,7 +57,7 @@
class RemoteRenderingBackendProxy
: public IPC::MessageSender
, private IPC::MessageReceiver
- , public CanMakeWeakPtr<RemoteRenderingBackendProxy> {
+ , public GPUProcessConnection::Client {
public:
static std::unique_ptr<RemoteRenderingBackendProxy> create();
@@ -86,6 +87,11 @@
private:
RemoteRenderingBackendProxy();
+ // GPUProcessConnection::Client
+ void gpuProcessConnectionDidClose(GPUProcessConnection&) final;
+
+ void connectToGPUProcess();
+ void reestablishGPUProcessConnection();
void updateReusableHandles();
// Messages to be received.
Modified: trunk/Source/WebKit/WebProcess/GPU/graphics/RemoteResourceCacheProxy.h (269808 => 269809)
--- trunk/Source/WebKit/WebProcess/GPU/graphics/RemoteResourceCacheProxy.h 2020-11-14 01:09:38 UTC (rev 269808)
+++ trunk/Source/WebKit/WebProcess/GPU/graphics/RemoteResourceCacheProxy.h 2020-11-14 02:11:30 UTC (rev 269809)
@@ -49,8 +49,10 @@
void cacheNativeImage(WebCore::NativeImage&);
+ using ImageBufferHashMap = HashMap<WebCore::RenderingResourceIdentifier, WeakPtr<WebCore::ImageBuffer>>;
+ const ImageBufferHashMap& imageBuffers() const { return m_imageBuffers; }
+
private:
- using ImageBufferHashMap = HashMap<WebCore::RenderingResourceIdentifier, WeakPtr<WebCore::ImageBuffer>>;
using NativeImageHashMap = HashMap<WebCore::RenderingResourceIdentifier, WeakPtr<WebCore::NativeImage>>;
void releaseNativeImage(WebCore::RenderingResourceIdentifier) override;
Modified: trunk/Tools/ChangeLog (269808 => 269809)
--- trunk/Tools/ChangeLog 2020-11-14 01:09:38 UTC (rev 269808)
+++ trunk/Tools/ChangeLog 2020-11-14 02:11:30 UTC (rev 269809)
@@ -1,3 +1,17 @@
+2020-11-13 Chris Dumez <[email protected]>
+
+ [GPUProcess] Add basic GPUProcess crash handling for canvas
+ https://bugs.webkit.org/show_bug.cgi?id=218924
+
+ Reviewed by Simon Fraser.
+
+ Add API test coverage.
+
+ * TestWebKitAPI/Tests/WebKitCocoa/GPUProcess.mm:
+ (convertToCGImage):
+ (getPixelIndex):
+ (TEST):
+
2020-11-13 Aakash Jain <[email protected]>
[build.webkit.org] Update CompileWebKit step for new buildbot
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/GPUProcess.mm (269808 => 269809)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/GPUProcess.mm 2020-11-14 01:09:38 UTC (rev 269808)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/GPUProcess.mm 2020-11-14 02:11:30 UTC (rev 269809)
@@ -35,6 +35,30 @@
#import <WebKit/_WKInternalDebugFeature.h>
#import <wtf/RetainPtr.h>
+#if PLATFORM(MAC)
+typedef NSImage *PlatformImage;
+typedef NSWindow *PlatformWindow;
+
+static RetainPtr<CGImageRef> convertToCGImage(NSImage *image)
+{
+ return [image CGImageForProposedRect:nil context:nil hints:nil];
+}
+
+#else
+typedef UIImage *PlatformImage;
+typedef UIWindow *PlatformWindow;
+
+static RetainPtr<CGImageRef> convertToCGImage(UIImage *image)
+{
+ return image.CGImage;
+}
+#endif
+
+static NSInteger getPixelIndex(NSInteger x, NSInteger y, NSInteger width)
+{
+ return (y * width + x) * 4;
+}
+
TEST(GPUProcess, RelaunchOnCrash)
{
auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
@@ -260,3 +284,151 @@
EXPECT_EQ(gpuProcessPID, [processPool _gpuProcessIdentifier]);
EXPECT_EQ(webViewPID, [webView _webProcessIdentifier]);
}
+
+static NSString *testCanvasPage = @"<body> \n"
+ "<canvas id='myCanvas' width='400px' height='400px'>\n"
+ "<script> \n"
+ "var context = document.getElementById('myCanvas').getContext('2d'); \n"
+ "</script> \n"
+ "</body>";
+
+TEST(GPUProcess, CanvasBasicCrashHandling)
+{
+ auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+ for (_WKInternalDebugFeature *feature in [WKPreferences _internalDebugFeatures]) {
+ if ([feature.key isEqualToString:@"UseGPUProcessForCanvasRenderingEnabled"]) {
+ [[configuration preferences] _setEnabled:YES forInternalDebugFeature:feature];
+ break;
+ }
+ }
+
+ NSInteger viewWidth = 400;
+ NSInteger viewHeight = 400;
+ auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:CGRectMake(0, 0, viewWidth, viewHeight) configuration:configuration.get() addToWindow:NO]);
+
+ RetainPtr<PlatformWindow> window;
+ CGFloat backingScaleFactor;
+
+#if PLATFORM(MAC)
+ window = adoptNS([[NSWindow alloc] initWithContentRect:[webView frame] styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]);
+ [[window contentView] addSubview:webView.get()];
+ backingScaleFactor = [window backingScaleFactor];
+#elif PLATFORM(IOS_FAMILY)
+ window = adoptNS([[UIWindow alloc] initWithFrame:[webView frame]]);
+ [window addSubview:webView.get()];
+ backingScaleFactor = [[window screen] scale];
+#endif
+
+ [webView synchronouslyLoadHTMLString:testCanvasPage];
+
+ auto webViewPID = [webView _webProcessIdentifier];
+
+ // Try painting the canvas red.
+ __block bool done = false;
+ [webView evaluateJavaScript:@"context.fillStyle = '#FF0000'; context.fillRect(0, 0, 400, 400);" completionHandler:^(id result, NSError *error) {
+ EXPECT_TRUE(!error);
+ done = true;
+ }];
+ TestWebKitAPI::Util::run(&done);
+
+ [webView waitForNextPresentationUpdate];
+
+ // The GPU process should have been launched.
+ auto* processPool = configuration.get().processPool;
+ unsigned timeout = 0;
+ while (![processPool _gpuProcessIdentifier] && timeout++ < 100)
+ TestWebKitAPI::Util::sleep(0.1);
+ auto gpuProcessPID = [processPool _gpuProcessIdentifier];
+ EXPECT_NE(0, gpuProcessPID);
+
+ auto snapshotConfiguration = adoptNS([[WKSnapshotConfiguration alloc] init]);
+ [snapshotConfiguration setRect:NSMakeRect(0, 0, 150, 150)];
+ [snapshotConfiguration setSnapshotWidth:@(150)];
+ [snapshotConfiguration setAfterScreenUpdates:YES];
+
+ // Make sure a red square is painted.
+ done = false;
+ [webView takeSnapshotWithConfiguration:snapshotConfiguration.get() completionHandler:^(PlatformImage snapshotImage, NSError *error) {
+ EXPECT_TRUE(!error);
+
+ RetainPtr<CGImageRef> cgImage = convertToCGImage(snapshotImage);
+ RetainPtr<CGColorSpaceRef> colorSpace = adoptCF(CGColorSpaceCreateDeviceRGB());
+
+ NSInteger viewWidthInPixels = viewWidth * backingScaleFactor;
+ NSInteger viewHeightInPixels = viewHeight * backingScaleFactor;
+
+ uint8_t *rgba = (unsigned char *)calloc(viewWidthInPixels * viewHeightInPixels * 4, sizeof(unsigned char));
+ RetainPtr<CGContextRef> context = CGBitmapContextCreate(rgba, viewWidthInPixels, viewHeightInPixels, 8, 4 * viewWidthInPixels, colorSpace.get(), kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
+ CGContextDrawImage(context.get(), CGRectMake(0, 0, viewWidthInPixels, viewHeightInPixels), cgImage.get());
+
+ NSInteger pixelIndex = getPixelIndex(50, 50, viewWidthInPixels);
+ EXPECT_EQ(255, rgba[pixelIndex]);
+ EXPECT_EQ(0, rgba[pixelIndex + 1]);
+ EXPECT_EQ(0, rgba[pixelIndex + 2]);
+
+ pixelIndex = getPixelIndex(100, 100, viewWidthInPixels);
+ EXPECT_EQ(255, rgba[pixelIndex]);
+ EXPECT_EQ(0, rgba[pixelIndex + 1]);
+ EXPECT_EQ(0, rgba[pixelIndex + 2]);
+
+ free(rgba);
+
+ done = true;
+ }];
+ TestWebKitAPI::Util::run(&done);
+
+ // Kill the GPUProcess.
+ kill(gpuProcessPID, 9);
+
+ // GPU Process should get relaunched.
+ timeout = 0;
+ while ((![processPool _gpuProcessIdentifier] || [processPool _gpuProcessIdentifier] == gpuProcessPID) && timeout++ < 100)
+ TestWebKitAPI::Util::sleep(0.1);
+ EXPECT_NE([processPool _gpuProcessIdentifier], 0);
+ EXPECT_NE([processPool _gpuProcessIdentifier], gpuProcessPID);
+ gpuProcessPID = [processPool _gpuProcessIdentifier];
+
+ // WebProcess should not have crashed.
+ EXPECT_EQ(webViewPID, [webView _webProcessIdentifier]);
+
+ // Try painting the canvas green.
+ done = false;
+ [webView evaluateJavaScript:@"context.fillStyle = '#00FF00'; context.fillRect(0, 0, 400, 400);" completionHandler:^(id result, NSError *error) {
+ EXPECT_TRUE(!error);
+ done = true;
+ }];
+ TestWebKitAPI::Util::run(&done);
+
+ [webView waitForNextPresentationUpdate];
+
+ // Make sure a green square is painted.
+ done = false;
+ [webView takeSnapshotWithConfiguration:snapshotConfiguration.get() completionHandler:^(PlatformImage snapshotImage, NSError *error) {
+ EXPECT_TRUE(!error);
+
+ RetainPtr<CGImageRef> cgImage = convertToCGImage(snapshotImage);
+ RetainPtr<CGColorSpaceRef> colorSpace = adoptCF(CGColorSpaceCreateDeviceRGB());
+
+ NSInteger viewWidthInPixels = viewWidth * backingScaleFactor;
+ NSInteger viewHeightInPixels = viewHeight * backingScaleFactor;
+
+ uint8_t *rgba = (unsigned char *)calloc(viewWidthInPixels * viewHeightInPixels * 4, sizeof(unsigned char));
+ RetainPtr<CGContextRef> context = CGBitmapContextCreate(rgba, viewWidthInPixels, viewHeightInPixels, 8, 4 * viewWidthInPixels, colorSpace.get(), kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
+ CGContextDrawImage(context.get(), CGRectMake(0, 0, viewWidthInPixels, viewHeightInPixels), cgImage.get());
+
+ NSInteger pixelIndex = getPixelIndex(50, 50, viewWidthInPixels);
+ EXPECT_EQ(0, rgba[pixelIndex]);
+ EXPECT_EQ(255, rgba[pixelIndex + 1]);
+ EXPECT_EQ(0, rgba[pixelIndex + 2]);
+
+ pixelIndex = getPixelIndex(100, 100, viewWidthInPixels);
+ EXPECT_EQ(0, rgba[pixelIndex]);
+ EXPECT_EQ(255, rgba[pixelIndex + 1]);
+ EXPECT_EQ(0, rgba[pixelIndex + 2]);
+
+ free(rgba);
+
+ done = true;
+ }];
+ TestWebKitAPI::Util::run(&done);
+}