| Differences between
and this patch
- a/Source/WebCore/ChangeLog +17 lines
Lines 1-3 a/Source/WebCore/ChangeLog_sec1
1
2021-11-05  Kimmo Kinnunen  <kkinnunen@apple.com>
2
3
        REGRESSION (iOS 15, GPU Process): Fails to load texture map
4
        https://bugs.webkit.org/show_bug.cgi?id=231471
5
        <rdar://problem/84328146>
6
7
        Reviewed by NOBODY (OOPS!).
8
9
        Clear the CGImage copy from the IOSurface CGContext after the IOSurface has
10
        been drawn to a bitmap CGContext. The CGImage stored in the IOSurface CGContext
11
        contains a malloc buffer of the data. This buffer is counted against GPU
12
        process memory consumption, causing GPU process jetsams.
13
14
        * platform/graphics/cg/ImageBufferIOSurfaceBackend.cpp:
15
        (WebCore::ImageBufferIOSurfaceBackend::draw):
16
        * platform/graphics/cg/ImageBufferIOSurfaceBackend.h:
17
1
2021-11-05  Carlos Garcia Campos  <cgarcia@igalia.com>
18
2021-11-05  Carlos Garcia Campos  <cgarcia@igalia.com>
2
19
3
        AX: rename actionVerb() as localizedActionVerb()
20
        AX: rename actionVerb() as localizedActionVerb()
- a/Source/WebKit/ChangeLog +19 lines
Lines 1-3 a/Source/WebKit/ChangeLog_sec1
1
2021-11-05  Kimmo Kinnunen  <kkinnunen@apple.com>
2
3
        REGRESSION (iOS 15, GPU Process): Fails to load texture map
4
        https://bugs.webkit.org/show_bug.cgi?id=231471
5
        <rdar://problem/84328146>
6
7
        Reviewed by NOBODY (OOPS!).
8
9
        Use the normal "draw image buffer" call to draw the image buffer
10
        to the shareble bitmap. Before, it was manually re-implementing this
11
        API call via the lower level calls.
12
        The drawImageBuffer call now fixes up the IOSurface -backed source
13
        ImageBuffers to not keep referencing to the CGImage that provided
14
        the data to the draw. Otherwise GPU process jetsams as the CGImage
15
        inside IOSurface is counted against GPU process memory limit.
16
17
        * GPUProcess/graphics/RemoteRenderingBackend.cpp:
18
        (WebKit::RemoteRenderingBackend::getShareableBitmapForImageBufferWithQualifiedIdentifier):
19
1
2021-11-04  Jean-Yves Avenard  <jya@apple.com>
20
2021-11-04  Jean-Yves Avenard  <jya@apple.com>
2
21
3
        Have RemoteMediaResource use SharedMemory
22
        Have RemoteMediaResource use SharedMemory
- a/Source/WebCore/platform/graphics/cg/ImageBufferIOSurfaceBackend.cpp +10 lines
Lines 175-180 RefPtr<NativeImage> ImageBufferIOSurfaceBackend::sinkIntoNativeImage() a/Source/WebCore/platform/graphics/cg/ImageBufferIOSurfaceBackend.cpp_sec1
175
    return NativeImage::create(IOSurface::sinkIntoImage(WTFMove(m_surface)));
175
    return NativeImage::create(IOSurface::sinkIntoImage(WTFMove(m_surface)));
176
}
176
}
177
177
178
void ImageBufferIOSurfaceBackend::draw(GraphicsContext& destContext, const FloatRect& destRect, const FloatRect& srcRect, const ImagePaintingOptions& options)
179
{
180
    ImageBufferCGBackend::draw(destContext, destRect, srcRect, options);
181
    // Accelerated to/from unaccelerated image buffers need complex caching. We trust that
182
    // this is a one-off draw, and as such we clear the caches after each draw.
183
    // This is important for example in GPUP operation, where caches of big IOSurfaces
184
    // would cause GPUP memory limits to be exceeded.
185
    if (destContext.renderingMode() != context().renderingMode())
186
        invalidateCachedNativeImage();
187
}
178
void ImageBufferIOSurfaceBackend::drawConsuming(GraphicsContext& destContext, const FloatRect& destRect, const FloatRect& srcRect, const ImagePaintingOptions& options)
188
void ImageBufferIOSurfaceBackend::drawConsuming(GraphicsContext& destContext, const FloatRect& destRect, const FloatRect& srcRect, const ImagePaintingOptions& options)
179
{
189
{
180
    prepareToDrawIntoContext(destContext);
190
    prepareToDrawIntoContext(destContext);
- a/Source/WebCore/platform/graphics/cg/ImageBufferIOSurfaceBackend.h +1 lines
Lines 58-63 public: a/Source/WebCore/platform/graphics/cg/ImageBufferIOSurfaceBackend.h_sec1
58
    RefPtr<NativeImage> copyNativeImage(BackingStoreCopy = CopyBackingStore) const override;
58
    RefPtr<NativeImage> copyNativeImage(BackingStoreCopy = CopyBackingStore) const override;
59
    RefPtr<NativeImage> sinkIntoNativeImage() override;
59
    RefPtr<NativeImage> sinkIntoNativeImage() override;
60
60
61
    void draw(GraphicsContext& destContext, const FloatRect& destRect, const FloatRect& srcRect, const ImagePaintingOptions&) override;
61
    void drawConsuming(GraphicsContext&, const FloatRect& destRect, const FloatRect& srcRect, const ImagePaintingOptions&) override;
62
    void drawConsuming(GraphicsContext&, const FloatRect& destRect, const FloatRect& srcRect, const ImagePaintingOptions&) override;
62
63
63
    std::optional<PixelBuffer> getPixelBuffer(const PixelBufferFormat& outputFormat, const IntRect&) const override;
64
    std::optional<PixelBuffer> getPixelBuffer(const PixelBufferFormat& outputFormat, const IntRect&) const override;
- a/Source/WebKit/GPUProcess/graphics/RemoteRenderingBackend.cpp -4 / +1 lines
Lines 304-312 void RemoteRenderingBackend::getShareableBitmapForImageBufferWithQualifiedIdenti a/Source/WebKit/GPUProcess/graphics/RemoteRenderingBackend.cpp_sec1
304
        auto imageBuffer = m_remoteResourceCache.cachedImageBuffer(identifier);
304
        auto imageBuffer = m_remoteResourceCache.cachedImageBuffer(identifier);
305
        if (!imageBuffer)
305
        if (!imageBuffer)
306
            return;
306
            return;
307
        auto image = imageBuffer->copyNativeImage(WebCore::BackingStoreCopy::DontCopyBackingStore);
308
        if (!image)
309
            return;
310
        auto backendSize = imageBuffer->backendSize();
307
        auto backendSize = imageBuffer->backendSize();
311
        auto resultSize = preserveResolution == WebCore::PreserveResolution::Yes ? backendSize : imageBuffer->truncatedLogicalSize();
308
        auto resultSize = preserveResolution == WebCore::PreserveResolution::Yes ? backendSize : imageBuffer->truncatedLogicalSize();
312
        auto bitmap = ShareableBitmap::createShareable(resultSize, { imageBuffer->colorSpace() });
309
        auto bitmap = ShareableBitmap::createShareable(resultSize, { imageBuffer->colorSpace() });
Lines 315-321 void RemoteRenderingBackend::getShareableBitmapForImageBufferWithQualifiedIdenti a/Source/WebKit/GPUProcess/graphics/RemoteRenderingBackend.cpp_sec2
315
        auto context = bitmap->createGraphicsContext();
312
        auto context = bitmap->createGraphicsContext();
316
        if (!context)
313
        if (!context)
317
            return;
314
            return;
318
        context->drawNativeImage(*image, resultSize, FloatRect { { }, resultSize }, FloatRect { { }, backendSize }, { WebCore::CompositeOperator::Copy });
315
        context->drawImageBuffer(*imageBuffer, FloatRect { { }, resultSize }, FloatRect { { }, backendSize }, { WebCore::CompositeOperator::Copy });
319
        bitmap->createHandle(handle);
316
        bitmap->createHandle(handle);
320
    }();
317
    }();
321
    completionHandler(WTFMove(handle));
318
    completionHandler(WTFMove(handle));
- a/Tools/ChangeLog +18 lines
Lines 1-3 a/Tools/ChangeLog_sec1
1
2021-11-05  Kimmo Kinnunen  <kkinnunen@apple.com>
2
3
        REGRESSION (iOS 15, GPU Process): Fails to load texture map
4
        https://bugs.webkit.org/show_bug.cgi?id=231471
5
        <rdar://problem/84328146>
6
7
        Reviewed by NOBODY (OOPS!).
8
9
        Add a test that tries to assert that GraphicsContext::drawImageBuffer() does not increase
10
        memory footprint of the process. However, leave the test disabled as currently
11
        it seems that the WTF::memoryFootprint() measurement does not see all the
12
        memory releases the CG does.
13
14
        * TestWebKitAPI/Tests/WebCore/ImageBufferTests.cpp:
15
        (TestWebKitAPI::memoryFootprintChangedBy):
16
        (TestWebKitAPI::imageBufferPixelIs):
17
        (TestWebKitAPI::TEST):
18
1
2021-11-05  Carlos Garcia Campos  <cgarcia@igalia.com>
19
2021-11-05  Carlos Garcia Campos  <cgarcia@igalia.com>
2
20
3
        [GTK][a11y] Embedded objects are not correctly handled by text interface with ATSPI
21
        [GTK][a11y] Embedded objects are not correctly handled by text interface with ATSPI
- a/Tools/TestWebKitAPI/Tests/WebCore/ImageBufferTests.cpp -20 / +90 lines
Lines 25-36 a/Tools/TestWebKitAPI/Tests/WebCore/ImageBufferTests.cpp_sec1
25
25
26
#include "config.h"
26
#include "config.h"
27
27
28
#include <WebCore/Color.h>
28
#include <WebCore/ImageBuffer.h>
29
#include <WebCore/ImageBuffer.h>
29
#include <WebCore/PlatformImageBuffer.h>
30
#include <WebCore/PlatformImageBuffer.h>
31
#include <cmath>
32
#include <wtf/MemoryFootprint.h>
30
33
31
namespace TestWebKitAPI {
34
namespace TestWebKitAPI {
32
using namespace WebCore;
35
using namespace WebCore;
33
36
37
static ::testing::AssertionResult memoryFootprintChangedBy(size_t& lastFootprint, double expectedChange, double error)
38
{
39
    WTF::releaseFastMallocFreeMemory();
40
    size_t newFootprint = memoryFootprint();
41
    size_t oldFootprint = std::exchange(lastFootprint, newFootprint);
42
    double change = static_cast<double>(newFootprint) - oldFootprint;
43
    if (change - expectedChange > error)
44
        return ::testing::AssertionFailure() << "Footprint changed by " << change << ". Expected at most " << expectedChange << "+-" << error;
45
    return ::testing::AssertionSuccess();
46
}
47
48
static ::testing::AssertionResult imageBufferPixelIs(Color expected, ImageBuffer& imageBuffer, int x, int y)
49
{
50
    PixelBufferFormat format { AlphaPremultiplication::Unpremultiplied, PixelFormat::RGBA8, DestinationColorSpace::SRGB() };
51
    auto frontPixelBuffer = imageBuffer.getPixelBuffer(format, { x, y, 1, 1 });
52
    auto& data = frontPixelBuffer->data();
53
    auto got = Color { SRGBA<uint8_t> { data.item(0), data.item(1), data.item(2), data.item(3) } };
54
    if (got != expected)
55
        return ::testing::AssertionFailure() << "color is not expected."; // FIXME: implement Color <<.
56
    return ::testing::AssertionSuccess();
57
}
58
34
// Tests that the specialized image buffer constructors construct the expected type of object.
59
// Tests that the specialized image buffer constructors construct the expected type of object.
35
// Test passes if the test compiles, there was a bug where the code wouldn't compile.
60
// Test passes if the test compiles, there was a bug where the code wouldn't compile.
36
TEST(ImageBufferTests, ImageBufferSubTypeCreateCreatesSubtypes)
61
TEST(ImageBufferTests, ImageBufferSubTypeCreateCreatesSubtypes)
Lines 79-104 TEST(ImageBufferTests, ImageBufferSubPixelDrawing) a/Tools/TestWebKitAPI/Tests/WebCore/ImageBufferTests.cpp_sec2
79
        frontContext.drawImageBuffer(*backImageBuffer, WebCore::FloatPoint { }, { WebCore::CompositeOperator::Copy });
104
        frontContext.drawImageBuffer(*backImageBuffer, WebCore::FloatPoint { }, { WebCore::CompositeOperator::Copy });
80
    }
105
    }
81
106
82
    auto checkGreenPixel = [&](ImageBuffer& imageBuffer, int x, int y) {
107
    EXPECT_TRUE(imageBufferPixelIs(Color::green, *frontImageBuffer, fillRect.x() + 1, fillRect.y() + 1));
83
        PixelBufferFormat format { AlphaPremultiplication::Unpremultiplied, PixelFormat::RGBA8, colorSpace };
108
    EXPECT_TRUE(imageBufferPixelIs(Color::green, *frontImageBuffer, fillRect.maxX() - 1, fillRect.y() + 1));
84
        auto frontPixelBuffer = imageBuffer.getPixelBuffer(format, { x, y, 1, 1 });
109
    EXPECT_TRUE(imageBufferPixelIs(Color::green, *frontImageBuffer, fillRect.x() + 1, fillRect.maxY() - 1));
85
        auto& data = frontPixelBuffer->data();
110
    EXPECT_TRUE(imageBufferPixelIs(Color::green, *frontImageBuffer, fillRect.maxX() - 1, fillRect.maxY() - 1));
86
111
87
        EXPECT_EQ(data.item(0), 0x00);
112
    EXPECT_TRUE(imageBufferPixelIs(Color::green, *backImageBuffer, fillRect.x() + 1, fillRect.y() + 1));
88
        EXPECT_EQ(data.item(1), 0xff);
113
    EXPECT_TRUE(imageBufferPixelIs(Color::green, *backImageBuffer, fillRect.maxX() - 1, fillRect.y() + 1));
89
        EXPECT_EQ(data.item(2), 0x00);
114
    EXPECT_TRUE(imageBufferPixelIs(Color::green, *backImageBuffer, fillRect.x() + 1, fillRect.maxY() - 1));
90
        EXPECT_EQ(data.item(3), 0xff);
115
    EXPECT_TRUE(imageBufferPixelIs(Color::green, *backImageBuffer, fillRect.maxX() - 1, fillRect.maxY() - 1));
91
    };
92
93
    checkGreenPixel(*frontImageBuffer, fillRect.x()    + 1, fillRect.y()    + 1);
94
    checkGreenPixel(*frontImageBuffer, fillRect.maxX() - 1, fillRect.y()    + 1);
95
    checkGreenPixel(*frontImageBuffer, fillRect.x()    + 1, fillRect.maxY() - 1);
96
    checkGreenPixel(*frontImageBuffer, fillRect.maxX() - 1, fillRect.maxY() - 1);
97
98
    checkGreenPixel(*backImageBuffer, fillRect.x()    + 1, fillRect.y()    + 1);
99
    checkGreenPixel(*backImageBuffer, fillRect.maxX() - 1, fillRect.y()    + 1);
100
    checkGreenPixel(*backImageBuffer, fillRect.x()    + 1, fillRect.maxY() - 1);
101
    checkGreenPixel(*backImageBuffer, fillRect.maxX() - 1, fillRect.maxY() - 1);
102
}
116
}
103
117
118
// Test that drawing an accelerated ImageBuffer to an unaccelerated does not store extra
119
// memory to the accelerated ImageBuffer.
120
// FIXME: The test is disabled as it appears that WTF::memoryFootprint() is not exact enough to
121
// test that GraphicsContext::drawImageBitmap() does not keep extra memory around.
122
// However, if the test is paused at the memory measurement location and the process is inspected
123
// manually with the memory tools, the footprint is as expected, e.g. drawBitmapImage does not
124
// persist additional memory.
125
TEST(ImageBufferTests, DISABLED_DrawImageBufferDoesNotReferenceExtraMemory)
126
{
127
    auto colorSpace = DestinationColorSpace::SRGB();
128
    auto pixelFormat = PixelFormat::BGRA8;
129
    FloatSize logicalSize { 4096, 4096 };
130
    float scale = 1;
131
    size_t footprintError = 1024 * 1024;
132
    size_t logicalSizeBytes = logicalSize.width() * logicalSize.height() * 4;
133
    // FIXME: Logically this fuzz amount  should not exist.
134
    // WTF::memoryFootprint() does not return the same amount of memory as
135
    // the `footprint` command or the leak tools.
136
    // At the time of writing, the bug case would report drawImageBitmap footprint
137
    // as ~130mb, and fixed case would report ~67mb.
138
    size_t drawImageBitmapUnaccountedFootprint = logicalSizeBytes + 3 * 1024 * 1024;
139
140
    {
141
        // Make potential accelerated drawing backend instantiate roughly the global structures needed for this test.
142
        auto accelerated = ImageBuffer::create(logicalSize, RenderingMode::Accelerated, scale, colorSpace, pixelFormat, nullptr);
143
        auto fillRect = FloatRect { { }, logicalSize };
144
        accelerated->context().fillRect(fillRect, Color::green);
145
        EXPECT_TRUE(imageBufferPixelIs(Color::green, *accelerated, fillRect.maxX() - 1, fillRect.maxY() - 1));
146
    }
147
    WTF::releaseFastMallocFreeMemory();
148
    auto initialFootprint = memoryFootprint();
149
    auto lastFootprint = initialFootprint;
150
    EXPECT_GT(lastFootprint, 0u);
151
152
    auto accelerated = ImageBuffer::create(logicalSize, RenderingMode::Accelerated, scale, colorSpace, pixelFormat, nullptr);
153
    auto fillRect = FloatRect { { }, logicalSize };
154
    accelerated->context().fillRect(fillRect, Color::green);
155
    accelerated->flushContext();
156
    EXPECT_TRUE(memoryFootprintChangedBy(lastFootprint, logicalSizeBytes, footprintError));
157
158
    auto unaccelerated = ImageBuffer::create(logicalSize, RenderingMode::Unaccelerated, scale, colorSpace, pixelFormat, nullptr);
159
    unaccelerated->context().fillRect(fillRect, Color::yellow);
160
    EXPECT_TRUE(imageBufferPixelIs(Color::yellow, *unaccelerated, fillRect.maxX() - 1, fillRect.maxY() - 1));
161
    EXPECT_TRUE(memoryFootprintChangedBy(lastFootprint, logicalSizeBytes, footprintError));
162
163
    // The purpose of the whole test is to test that drawImageBuffer does not increase
164
    // memory footprint.
165
    unaccelerated->context().drawImageBuffer(*accelerated, FloatRect { { }, logicalSize }, FloatRect { { }, logicalSize }, { WebCore::CompositeOperator::Copy });
166
    EXPECT_TRUE(imageBufferPixelIs(Color::green, *unaccelerated, fillRect.maxX() - 1, fillRect.maxY() - 1));
167
    EXPECT_TRUE(memoryFootprintChangedBy(lastFootprint, 0 + drawImageBitmapUnaccountedFootprint, footprintError));
168
    // sleep(10000); // Enable this to inspect the process manually.
169
    accelerated = nullptr;
170
    unaccelerated = nullptr;
171
    lastFootprint = initialFootprint;
172
    EXPECT_TRUE(memoryFootprintChangedBy(lastFootprint, 0, footprintError));
173
}
104
}
174
}

Return to Bug 231471