Diff
Modified: trunk/Source/WebCore/ChangeLog (286159 => 286160)
--- trunk/Source/WebCore/ChangeLog 2021-11-25 06:59:55 UTC (rev 286159)
+++ trunk/Source/WebCore/ChangeLog 2021-11-25 09:17:45 UTC (rev 286160)
@@ -1,3 +1,25 @@
+2021-11-25 Kimmo Kinnunen <[email protected]>
+
+ ANGLE Metal: The memory backing IOSurfaces of former client buffer pbuffers is leaked
+ https://bugs.webkit.org/show_bug.cgi?id=233328
+ <rdar://problem/85563187>
+
+ Reviewed by Antti Koivisto.
+
+ Fix a bug where recycling GraphicsContextGLOpenGL display buffers would
+ leak the spare buffer pbuffer handle. This would happen if the
+ display buffer was marked as "in use", so that the IOSurface reference
+ would be dropped immediately in order to not use it as next drawing buffer.
+ However, the IOSurface is still bound in ANGLE and as such, the pbuffer handle
+ must be returned during `GraphicsContextGLIOSurfaceSwapChain::recycleBuffer``
+ call.
+
+ Adds API tests for testing the leak.
+
+ * platform/graphics/cocoa/GraphicsContextGLIOSurfaceSwapChain.cpp:
+ (WebCore::GraphicsContextGLIOSurfaceSwapChain::recycleBuffer):
+ (WebCore::GraphicsContextGLIOSurfaceSwapChain::present):
+
2021-11-24 David Kilzer <[email protected]>
Compiler should be able to check localized format strings for consistency
Modified: trunk/Source/WebCore/PAL/ChangeLog (286159 => 286160)
--- trunk/Source/WebCore/PAL/ChangeLog 2021-11-25 06:59:55 UTC (rev 286159)
+++ trunk/Source/WebCore/PAL/ChangeLog 2021-11-25 09:17:45 UTC (rev 286160)
@@ -1,3 +1,16 @@
+2021-11-25 Kimmo Kinnunen <[email protected]>
+
+ ANGLE Metal: The memory backing IOSurfaces of former client buffer pbuffers is leaked
+ https://bugs.webkit.org/show_bug.cgi?id=233328
+ <rdar://problem/85563187>
+
+ Reviewed by Antti Koivisto.
+
+ Add prototype for IOSurfaceIncrementUseCount.
+ Currently used for a test, in simulating CA behavior.
+
+ * pal/spi/cocoa/IOSurfaceSPI.h:
+
2021-11-22 Myles C. Maxfield <[email protected]>
[WebGPU] Use OptionSet where it makes sense to
Modified: trunk/Source/WebCore/PAL/pal/spi/cocoa/IOSurfaceSPI.h (286159 => 286160)
--- trunk/Source/WebCore/PAL/pal/spi/cocoa/IOSurfaceSPI.h 2021-11-25 06:59:55 UTC (rev 286159)
+++ trunk/Source/WebCore/PAL/pal/spi/cocoa/IOSurfaceSPI.h 2021-11-25 09:17:45 UTC (rev 286160)
@@ -71,6 +71,7 @@
size_t IOSurfaceGetPropertyMaximum(CFStringRef property);
size_t IOSurfaceGetWidth(IOSurfaceRef buffer);
OSType IOSurfaceGetPixelFormat(IOSurfaceRef buffer);
+void IOSurfaceIncrementUseCount(IOSurfaceRef buffer);
Boolean IOSurfaceIsInUse(IOSurfaceRef buffer);
IOReturn IOSurfaceLock(IOSurfaceRef buffer, uint32_t options, uint32_t *seed);
IOSurfaceRef IOSurfaceLookupFromMachPort(mach_port_t);
Modified: trunk/Source/WebCore/platform/graphics/cocoa/GraphicsContextGLIOSurfaceSwapChain.cpp (286159 => 286160)
--- trunk/Source/WebCore/platform/graphics/cocoa/GraphicsContextGLIOSurfaceSwapChain.cpp 2021-11-25 06:59:55 UTC (rev 286159)
+++ trunk/Source/WebCore/platform/graphics/cocoa/GraphicsContextGLIOSurfaceSwapChain.cpp 2021-11-25 09:17:45 UTC (rev 286160)
@@ -47,9 +47,8 @@
if (m_spareBuffer.surface) {
if (m_spareBuffer.surface->isInUse())
m_spareBuffer.surface.reset();
- return WTFMove(m_spareBuffer);
}
- return { };
+ return std::exchange(m_spareBuffer, { });
}
void* GraphicsContextGLIOSurfaceSwapChain::detachClient()
@@ -60,6 +59,8 @@
void GraphicsContextGLIOSurfaceSwapChain::present(Buffer&& buffer)
{
+ ASSERT(!m_spareBuffer.surface);
+ ASSERT(!m_spareBuffer.handle);
m_spareBuffer = std::exchange(m_displayBuffer, WTFMove(buffer));
if (m_displayBufferInUse) {
m_displayBufferInUse = false;
Modified: trunk/Tools/ChangeLog (286159 => 286160)
--- trunk/Tools/ChangeLog 2021-11-25 06:59:55 UTC (rev 286159)
+++ trunk/Tools/ChangeLog 2021-11-25 09:17:45 UTC (rev 286160)
@@ -1,3 +1,29 @@
+2021-11-25 Kimmo Kinnunen <[email protected]>
+
+ ANGLE Metal: The memory backing IOSurfaces of former client buffer pbuffers is leaked
+ https://bugs.webkit.org/show_bug.cgi?id=233328
+ <rdar://problem/85563187>
+
+ Reviewed by Antti Koivisto.
+
+ Add tests testing Cocoa GraphicsContextGLOpenGL drawing buffer
+ recycling behavior.
+
+ * TestWebKitAPI/Configurations/TestWebKitAPI.xcconfig:
+ * TestWebKitAPI/Sources.txt:
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/Tests/WebCore/ImageBufferTests.cpp:
+ (TestWebKitAPI::imageBufferPixelIs):
+ (TestWebKitAPI::memoryFootprintChangedBy): Deleted.
+ * TestWebKitAPI/Tests/WebCore/cocoa/TestGraphicsContextGLOpenGLCocoa.mm:
+ (TestWebKitAPI::createDefaultTestContext):
+ (TestWebKitAPI::changeContextContents):
+ (TestWebKitAPI::TEST):
+ * TestWebKitAPI/TestUtilities.h: Added.
+ * TestWebKitAPI/TestUtilities.cpp: Added.
+ Add few useful functions to TestUtilities.h so that different
+ tests can use them.
+
2021-11-23 Lauro Moura <[email protected]>
[GTK] GdkRGBA expects colors to be in the 0.0 to 1.0 range
Modified: trunk/Tools/TestWebKitAPI/Configurations/TestWebKitAPI.xcconfig (286159 => 286160)
--- trunk/Tools/TestWebKitAPI/Configurations/TestWebKitAPI.xcconfig 2021-11-25 06:59:55 UTC (rev 286159)
+++ trunk/Tools/TestWebKitAPI/Configurations/TestWebKitAPI.xcconfig 2021-11-25 09:17:45 UTC (rev 286160)
@@ -93,7 +93,7 @@
OTHER_CPLUSPLUSFLAGS = $(inherited) -isystem $(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders;
-OTHER_LDFLAGS = $(inherited) -lgtest -force_load $(BUILT_PRODUCTS_DIR)/libTestWebKitAPI.a -framework _javascript_Core -framework WebKit -lWebCoreTestSupport -framework Metal $(WK_APPSERVERSUPPORT_LDFLAGS) $(WK_AUTHKIT_LDFLAGS) -framework Network $(WK_HID_LDFLAGS) $(WK_OPENGL_LDFLAGS) $(WK_PDFKIT_LDFLAGS) $(WK_SYSTEM_LDFLAGS) $(WK_UIKITMACHELPER_LDFLAGS) $(WK_VISIONKITCORE_LDFLAGS) $(OTHER_LDFLAGS_PLATFORM_$(WK_COCOA_TOUCH));
+OTHER_LDFLAGS = $(inherited) -lgtest -force_load $(BUILT_PRODUCTS_DIR)/libTestWebKitAPI.a -framework _javascript_Core -framework WebKit -lWebCoreTestSupport -framework Metal -framework IOSurface $(WK_APPSERVERSUPPORT_LDFLAGS) $(WK_AUTHKIT_LDFLAGS) -framework Network $(WK_HID_LDFLAGS) $(WK_OPENGL_LDFLAGS) $(WK_PDFKIT_LDFLAGS) $(WK_SYSTEM_LDFLAGS) $(WK_UIKITMACHELPER_LDFLAGS) $(WK_VISIONKITCORE_LDFLAGS) $(OTHER_LDFLAGS_PLATFORM_$(WK_COCOA_TOUCH));
OTHER_LDFLAGS_PLATFORM_ = -framework Cocoa -framework Carbon;
// FIXME: This should not be built on iOS. Instead we should create and use a TestWebKitAPI application.
Modified: trunk/Tools/TestWebKitAPI/Sources.txt (286159 => 286160)
--- trunk/Tools/TestWebKitAPI/Sources.txt 2021-11-25 06:59:55 UTC (rev 286159)
+++ trunk/Tools/TestWebKitAPI/Sources.txt 2021-11-25 09:17:45 UTC (rev 286160)
@@ -25,4 +25,5 @@
_javascript_Test.cpp
PlatformUtilities.cpp
TestsController.cpp
+TestUtilities.cpp
Added: trunk/Tools/TestWebKitAPI/TestUtilities.cpp (0 => 286160)
--- trunk/Tools/TestWebKitAPI/TestUtilities.cpp (rev 0)
+++ trunk/Tools/TestWebKitAPI/TestUtilities.cpp 2021-11-25 09:17:45 UTC (rev 286160)
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2021 Apple Inc. 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 "TestUtilities.h"
+
+#import <wtf/MemoryFootprint.h>
+
+namespace TestWebKitAPI {
+
+::testing::AssertionResult memoryFootprintChangedBy(size_t& lastFootprint, double expectedChange, double error)
+{
+ WTF::releaseFastMallocFreeMemory();
+ size_t newFootprint = memoryFootprint();
+ size_t oldFootprint = std::exchange(lastFootprint, newFootprint);
+ double change = static_cast<double>(newFootprint) - oldFootprint;
+ if (change - expectedChange > error)
+ return ::testing::AssertionFailure() << "Footprint changed by " << change << ". Expected at most " << expectedChange << "+-" << error;
+ return ::testing::AssertionSuccess();
+}
+
+}
Added: trunk/Tools/TestWebKitAPI/TestUtilities.h (0 => 286160)
--- trunk/Tools/TestWebKitAPI/TestUtilities.h (rev 0)
+++ trunk/Tools/TestWebKitAPI/TestUtilities.h 2021-11-25 09:17:45 UTC (rev 286160)
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2021 Apple Inc. 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.
+ */
+
+#pragma once
+
+#include "Test.h"
+#include "WTFStringUtilities.h"
+#include <WebCore/Color.h>
+#include <wtf/text/TextStream.h>
+
+namespace TestWebKitAPI {
+
+// Caller should initialize lastFootprint with memoryFootprint() for the initial call.
+::testing::AssertionResult memoryFootprintChangedBy(size_t& lastFootprint, double expectedChange, double error);
+
+}
+
+namespace WebCore {
+
+inline std::ostream& operator<<(std::ostream& os, const WebCore::Color& value)
+{
+ TextStream s { TextStream::LineMode::SingleLine };
+ s << value;
+ return os << s.release();
+}
+
+}
Modified: trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (286159 => 286160)
--- trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2021-11-25 06:59:55 UTC (rev 286159)
+++ trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj 2021-11-25 09:17:45 UTC (rev 286160)
@@ -2372,6 +2372,8 @@
7B7D09692519F8F90017A078 /* WebGLNoCrashOnOtherThreadAccess.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = WebGLNoCrashOnOtherThreadAccess.mm; sourceTree = "<group>"; };
7BA3936B271EDFCA0015911C /* TestGraphicsContextGLOpenGLCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TestGraphicsContextGLOpenGLCocoa.mm; sourceTree = "<group>"; };
7BA3936D271EEC530015911C /* WebCoreUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebCoreUtilities.h; sourceTree = "<group>"; };
+ 7BB754AF274E39A100D00EC1 /* TestUtilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestUtilities.h; sourceTree = "<group>"; };
+ 7BB754B0274E39A100D00EC1 /* TestUtilities.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TestUtilities.cpp; sourceTree = "<group>"; };
7C1AF7931E8DCBAB002645B9 /* PrepareForMoveToWindow.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PrepareForMoveToWindow.mm; sourceTree = "<group>"; };
7C3965051CDD74F90094DBB8 /* ColorTests.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ColorTests.cpp; sourceTree = "<group>"; };
7C3DB8E21D12129B00AE8CC3 /* CommandBackForward.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CommandBackForward.mm; sourceTree = "<group>"; };
@@ -3181,6 +3183,8 @@
BCB9E7FA112359A300A137E0 /* Test.h */,
BC131AA8117131FC00B69727 /* TestsController.cpp */,
BCB9E7C711234E3A00A137E0 /* TestsController.h */,
+ 7BB754B0274E39A100D00EC1 /* TestUtilities.cpp */,
+ 7BB754AF274E39A100D00EC1 /* TestUtilities.h */,
7C83E0361D0A5F7000FEBCF3 /* Utilities.h */,
7BA3936D271EEC530015911C /* WebCoreUtilities.h */,
7CBD5A2222DE42A6004A9E32 /* WTFStringUtilities.cpp */,
Modified: trunk/Tools/TestWebKitAPI/Tests/WebCore/ImageBufferTests.cpp (286159 => 286160)
--- trunk/Tools/TestWebKitAPI/Tests/WebCore/ImageBufferTests.cpp 2021-11-25 06:59:55 UTC (rev 286159)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/ImageBufferTests.cpp 2021-11-25 09:17:45 UTC (rev 286160)
@@ -25,6 +25,7 @@
#include "config.h"
+#include "TestUtilities.h"
#include <WebCore/Color.h>
#include <WebCore/ImageBuffer.h>
#include <WebCore/PlatformImageBuffer.h>
@@ -34,17 +35,6 @@
namespace TestWebKitAPI {
using namespace WebCore;
-static ::testing::AssertionResult memoryFootprintChangedBy(size_t& lastFootprint, double expectedChange, double error)
-{
- WTF::releaseFastMallocFreeMemory();
- size_t newFootprint = memoryFootprint();
- size_t oldFootprint = std::exchange(lastFootprint, newFootprint);
- double change = static_cast<double>(newFootprint) - oldFootprint;
- if (change - expectedChange > error)
- return ::testing::AssertionFailure() << "Footprint changed by " << change << ". Expected at most " << expectedChange << "+-" << error;
- return ::testing::AssertionSuccess();
-}
-
static ::testing::AssertionResult imageBufferPixelIs(Color expected, ImageBuffer& imageBuffer, int x, int y)
{
PixelBufferFormat format { AlphaPremultiplication::Unpremultiplied, PixelFormat::RGBA8, DestinationColorSpace::SRGB() };
@@ -52,7 +42,7 @@
auto& data = ""
auto got = Color { SRGBA<uint8_t> { data.item(0), data.item(1), data.item(2), data.item(3) } };
if (got != expected)
- return ::testing::AssertionFailure() << "color is not expected."; // FIXME: implement Color <<.
+ return ::testing::AssertionFailure() << "color is not expected. Got: " << got << ", expected: " << expected << ".";
return ::testing::AssertionSuccess();
}
Modified: trunk/Tools/TestWebKitAPI/Tests/WebCore/cocoa/TestGraphicsContextGLOpenGLCocoa.mm (286159 => 286160)
--- trunk/Tools/TestWebKitAPI/Tests/WebCore/cocoa/TestGraphicsContextGLOpenGLCocoa.mm 2021-11-25 06:59:55 UTC (rev 286159)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/cocoa/TestGraphicsContextGLOpenGLCocoa.mm 2021-11-25 09:17:45 UTC (rev 286160)
@@ -27,29 +27,94 @@
#import "Test.h"
#if PLATFORM(COCOA) && ENABLE(WEBGL)
+#import "TestUtilities.h"
#import "WebCoreUtilities.h"
#import <Metal/Metal.h>
+#import <WebCore/Color.h>
#import <WebCore/GraphicsContextGLOpenGL.h>
+#import <optional>
+#import <wtf/HashSet.h>
+#import <wtf/MemoryFootprint.h>
namespace TestWebKitAPI {
-using namespace WebCore;
namespace {
-class TestedGraphicsContextGLOpenGL : public GraphicsContextGLOpenGL {
+
+class TestedGraphicsContextGLOpenGL : public WebCore::GraphicsContextGLOpenGL {
public:
- static RefPtr<TestedGraphicsContextGLOpenGL> create(GraphicsContextGLAttributes attributes)
+ static RefPtr<TestedGraphicsContextGLOpenGL> create(WebCore::GraphicsContextGLAttributes attributes)
{
auto context = adoptRef(*new TestedGraphicsContextGLOpenGL(WTFMove(attributes)));
return context;
}
+ WebCore::IOSurface* displayBuffer()
+ {
+ return m_swapChain.displayBuffer().surface.get();
+ }
+ void markDisplayBufferInUse()
+ {
+ m_swapChain.markDisplayBufferInUse();
+ }
private:
- TestedGraphicsContextGLOpenGL(GraphicsContextGLAttributes attributes)
- : GraphicsContextGLOpenGL(WTFMove(attributes))
+ TestedGraphicsContextGLOpenGL(WebCore::GraphicsContextGLAttributes attributes)
+ : WebCore::GraphicsContextGLOpenGL(WTFMove(attributes))
{
}
};
+
+class GraphicsContextGLOpenGLCocoaTest : public ::testing::Test {
+public:
+ void SetUp() override // NOLINT
+ {
+ m_scopedProcessType = ScopedSetAuxiliaryProcessTypeForTesting { WebCore::AuxiliaryProcessType::GPU };
+ }
+ void TearDown() override // NOLINT
+ {
+ m_scopedProcessType = std::nullopt;
+ }
+private:
+ std::optional<ScopedSetAuxiliaryProcessTypeForTesting> m_scopedProcessType;
+};
+
}
+static const int expectedDisplayBufferPoolSize = 3;
+
+static RefPtr<TestedGraphicsContextGLOpenGL> createDefaultTestContext(WebCore::IntSize contextSize)
+{
+ WebCore::GraphicsContextGLAttributes attributes;
+ attributes.useMetal = true;
+ attributes.antialias = false;
+ attributes.depth = false;
+ attributes.stencil = false;
+ attributes.alpha = true;
+ attributes.preserveDrawingBuffer = false;
+ auto context = TestedGraphicsContextGLOpenGL::create(attributes);
+ if (!context)
+ return nullptr;
+ context->reshape(contextSize.width(), contextSize.height());
+ return context;
+}
+
+static ::testing::AssertionResult changeContextContents(TestedGraphicsContextGLOpenGL& context, int iteration)
+{
+ context.markContextChanged();
+ WebCore::Color expected { iteration % 2 ? WebCore::Color::green : WebCore::Color::yellow };
+ auto [colorSpace, components] = expected.colorSpaceAndComponents();
+ UNUSED_VARIABLE(colorSpace);
+ context.clearColor(components[0], components[1], components[2], components[3]);
+ context.clear(WebCore::GraphicsContextGL::COLOR_BUFFER_BIT);
+ uint8_t gotValues[4] = { };
+ auto sampleAt = context.getInternalFramebufferSize();
+ sampleAt.contract(2, 3);
+ sampleAt.clampNegativeToZero();
+ context.readnPixels(sampleAt.width(), sampleAt.height(), 1, 1, WebCore::GraphicsContextGL::RGBA, WebCore::GraphicsContextGL::UNSIGNED_BYTE, gotValues);
+ WebCore::Color got { WebCore::SRGBA<uint8_t> { gotValues[0], gotValues[1], gotValues[2], gotValues[3] } };
+ if (got != expected)
+ return ::testing::AssertionFailure() << "Failed to verify draw to context. Got: " << got << ", expected: " << expected << ".";
+ return ::testing::AssertionSuccess();
+}
+
static bool hasMultipleGPUs()
{
#if (PLATFORM(MAC) || PLATFORM(MACCATALYST))
@@ -68,29 +133,121 @@
// Tests for a bug where high-performance context would use low-power GPU if low-power or default
// context was created first. Test is applicable only for Metal, since GPU selection for OpenGL is
// very different.
-TEST(GraphicsContextGLOpenGLCocoaTest, MAYBE_MultipleGPUsDifferentPowerPreferenceMetal)
+TEST_F(GraphicsContextGLOpenGLCocoaTest, MAYBE_MultipleGPUsDifferentPowerPreferenceMetal)
{
if (!hasMultipleGPUs())
return;
- ScopedSetAuxiliaryProcessTypeForTesting scopedProcessType { AuxiliaryProcessType::GPU };
- GraphicsContextGLAttributes attributes;
+ WebCore::GraphicsContextGLAttributes attributes;
attributes.useMetal = true;
- EXPECT_EQ(attributes.powerPreference, GraphicsContextGLPowerPreference::Default);
+ EXPECT_EQ(attributes.powerPreference, WebCore::GraphicsContextGLPowerPreference::Default);
auto defaultContext = TestedGraphicsContextGLOpenGL::create(attributes);
- EXPECT_NE(defaultContext, nullptr);
+ ASSERT_NE(defaultContext, nullptr);
- attributes.powerPreference = GraphicsContextGLPowerPreference::LowPower;
+ attributes.powerPreference = WebCore::GraphicsContextGLPowerPreference::LowPower;
auto lowPowerContext = TestedGraphicsContextGLOpenGL::create(attributes);
- EXPECT_NE(lowPowerContext, nullptr);
+ ASSERT_NE(lowPowerContext, nullptr);
- attributes.powerPreference = GraphicsContextGLPowerPreference::HighPerformance;
+ attributes.powerPreference = WebCore::GraphicsContextGLPowerPreference::HighPerformance;
auto highPerformanceContext = TestedGraphicsContextGLOpenGL::create(attributes);
- EXPECT_NE(highPerformanceContext, nullptr);
+ ASSERT_NE(highPerformanceContext, nullptr);
- EXPECT_NE(lowPowerContext->getString(GraphicsContextGL::RENDERER), highPerformanceContext->getString(GraphicsContextGL::RENDERER));
- EXPECT_EQ(defaultContext->getString(GraphicsContextGL::RENDERER), lowPowerContext->getString(GraphicsContextGL::RENDERER));
+ EXPECT_NE(lowPowerContext->getString(WebCore::GraphicsContextGL::RENDERER), highPerformanceContext->getString(WebCore::GraphicsContextGL::RENDERER));
+ EXPECT_EQ(defaultContext->getString(WebCore::GraphicsContextGL::RENDERER), lowPowerContext->getString(WebCore::GraphicsContextGL::RENDERER));
}
+TEST_F(GraphicsContextGLOpenGLCocoaTest, DisplayBuffersAreRecycled)
+{
+ auto context = createDefaultTestContext({ 20, 20 });
+ ASSERT_NE(context, nullptr);
+ RetainPtr<IOSurfaceRef> expectedDisplayBuffers[expectedDisplayBufferPoolSize];
+ for (int i = 0; i < 50; ++i) {
+ EXPECT_TRUE(changeContextContents(*context, i));
+ context->prepareForDisplay();
+ auto* surface = context->displayBuffer();
+ ASSERT_NE(surface, nullptr);
+ int slot = i % expectedDisplayBufferPoolSize;
+ if (!expectedDisplayBuffers[slot])
+ expectedDisplayBuffers[slot] = surface->surface();
+ EXPECT_EQ(expectedDisplayBuffers[slot].get(), surface->surface()) << "for i:" << i << " slot: " << slot;
+ }
+ for (int i = 0; i < expectedDisplayBufferPoolSize - 1; ++i) {
+ for (int j = i + 1; j < expectedDisplayBufferPoolSize; ++j)
+ EXPECT_NE(expectedDisplayBuffers[i].get(), expectedDisplayBuffers[j].get()) << "for i: " << i << " j:" << j;
+ }
}
+
+// Test that drawing buffers are not recycled if `GraphicsContextGLOpenGL::markDisplayBufferInUse()`
+// is called.
+TEST_F(GraphicsContextGLOpenGLCocoaTest, DisplayBuffersAreNotRecycledWhenMarkedInUse)
+{
+ auto context = createDefaultTestContext({ 20, 20 });
+ ASSERT_NE(context, nullptr);
+ HashSet<RetainPtr<IOSurfaceRef>> seenSurfaceRefs;
+ for (int i = 0; i < 50; ++i) {
+ EXPECT_TRUE(changeContextContents(*context, i));
+ context->prepareForDisplay();
+ WebCore::IOSurface* surface = context->displayBuffer();
+ ASSERT_NE(surface, nullptr);
+ IOSurfaceRef surfaceRef = surface->surface();
+ EXPECT_NE(surfaceRef, nullptr);
+ EXPECT_FALSE(seenSurfaceRefs.contains(surfaceRef));
+ seenSurfaceRefs.add(surfaceRef);
+
+ context->markDisplayBufferInUse();
+ }
+ ASSERT_EQ(seenSurfaceRefs.size(), 50u);
+}
+
+// Test that drawing buffers are not recycled if the use count of the underlying IOSurface
+// changes. Use count is modified for example by CoreAnimation when the IOSurface is attached
+// to the contents.
+TEST_F(GraphicsContextGLOpenGLCocoaTest, DisplayBuffersAreNotRecycledWhedInUse)
+{
+ auto context = createDefaultTestContext({ 20, 20 });
+ ASSERT_NE(context, nullptr);
+ HashSet<RetainPtr<IOSurfaceRef>> seenSurfaceRefs;
+ for (int i = 0; i < 50; ++i) {
+ EXPECT_TRUE(changeContextContents(*context, i));
+ context->prepareForDisplay();
+ WebCore::IOSurface* surface = context->displayBuffer();
+ ASSERT_NE(surface, nullptr);
+ IOSurfaceRef surfaceRef = surface->surface();
+ EXPECT_NE(surfaceRef, nullptr);
+ EXPECT_FALSE(seenSurfaceRefs.contains(surfaceRef));
+ seenSurfaceRefs.add(surfaceRef);
+
+ IOSurfaceIncrementUseCount(surfaceRef);
+ }
+ ASSERT_EQ(seenSurfaceRefs.size(), 50u);
+}
+
+// Test that drawing to GraphicsContextGL and marking the display buffer in use does not leak big
+// amounts of memory for each displayed buffer.
+TEST_F(GraphicsContextGLOpenGLCocoaTest, UnrecycledDisplayBuffersNoLeaks)
+{
+ // The test detects the leak by observing memory footprint. However, some of the freed IOSurface
+ // memory (130mb) stays resident, presumably by intention of IOKit. The test would originally leak
+ // 2.7gb so the intended bug would be detected with 150mb error range.
+ size_t footprintError = 150 * 1024 * 1024;
+ size_t footprintChange = 0;
+
+ auto context = createDefaultTestContext({ 2048, 2048 });
+ ASSERT_NE(context, nullptr);
+
+ WTF::releaseFastMallocFreeMemory();
+ auto lastFootprint = memoryFootprint();
+
+ for (int i = 0; i < 50; ++i) {
+ EXPECT_TRUE(changeContextContents(*context, i));
+ context->prepareForDisplay();
+ EXPECT_NE(context->displayBuffer(), nullptr);
+ context->markDisplayBufferInUse();
+ }
+
+ EXPECT_TRUE(memoryFootprintChangedBy(lastFootprint, footprintChange, footprintError));
+}
+
+}
+
#endif