Skip to content

[CoordinatedGraphics] Use a swapchain of three buffers for WebGL - #75637

Open
carlosgcampos wants to merge 1 commit into
WebKit:mainfrom
carlosgcampos:webgl-swapchain
Open

carlosgcampos wants to merge 1 commit into
WebKit:mainfrom
carlosgcampos:webgl-swapchain

Conversation

@carlosgcampos

@carlosgcampos carlosgcampos commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

e2129ef

[CoordinatedGraphics] Use a swapchain of three buffers for WebGL
https://bugs.webkit.org/show_bug.cgi?id=325950

Reviewed by NOBODY (OOPS!).

We currently use two fixed buffers, but the compositor hasn't released
the previous one when we do the swap, so a third one is needed. Use a
swapchain based on a fixed size array of 3 buffers similar to the one
used by Cocoa implementation. If we need to bind a new buffer and next
one is still in used by the compositor, it's moved to an vector to be
released later when no longer in use and a new one is allocated. The
same happens when we release current buffers due to a reshape, buffers
still used by the compositor are moved to the obsolete buffers vector.
In the GBM implementation the drawing buffer keeps a reference of the
DMABufBuffer so that we know it's no longer in use by the compositor
when it only has one reference. For non-GBM implementation a thread safe
ref counted class is used to wrap the inner texture ID that is passed to
the compositor to keep a reference while the texture is in use.
This patch also moves the coordinated graphics implementation of
GraphicsContextGL to its own file and renames the API test.

Test: Tools/TestWebKitAPI/Tests/WebCore/glib/GraphicsContextGLCoordinated.cpp

* Source/WebCore/platform/CoordinatedGraphics.cmake:
* Source/WebCore/platform/graphics/coordinated/CoordinatedPlatformLayerBufferSkiaImage.cpp:
(WebCore::PromiseWebGLImageContext::PromiseWebGLImageContext):
(WebCore::PromiseWebGLImageContext::promiseImageTexture):
(WebCore::CoordinatedPlatformLayerBufferSkiaImage::create):
(): Deleted.
* Source/WebCore/platform/graphics/coordinated/CoordinatedPlatformLayerBufferSkiaImage.h:
* Source/WebCore/platform/graphics/coordinated/GraphicsContextGLCoordinated.cpp: Added.
(WebCore::GraphicsContextGLCoordinated::create):
(WebCore::GraphicsContextGLCoordinated::GraphicsContextGLCoordinated):
(WebCore::GraphicsContextGLCoordinated::~GraphicsContextGLCoordinated):
(WebCore::GraphicsContextGLCoordinated::platformInitialize):
(WebCore::GraphicsContextGLCoordinated::DrawingBuffer::DrawingBuffer):
(WebCore::GraphicsContextGLCoordinated::DrawingBuffer::operator=):
(WebCore::GraphicsContextGLCoordinated::DrawingBuffer::isInUse const):
(WebCore::GraphicsContextGLCoordinated::DrawingBuffer::release):
(WebCore::GraphicsContextGLCoordinated::createDrawingBuffer const):
(WebCore::GraphicsContextGLCoordinated::destroyDrawingBuffer const):
(WebCore::GraphicsContextGLCoordinated::freeDrawingBuffers):
(WebCore::GraphicsContextGLCoordinated::freeObsoleteDrawingBuffers):
(WebCore::GraphicsContextGLCoordinated::bindNextDrawingBuffer):
(WebCore::GraphicsContextGLCoordinated::reshapeDrawingBuffer):
(WebCore::GraphicsContextGLCoordinated::prepareForDisplay):
(WebCore::GraphicsContextGLCoordinated::readCompositedResults):
* Source/WebCore/platform/graphics/coordinated/GraphicsContextGLCoordinated.h: Added.
(WebCore::GraphicsContextGLCoordinated::DrawingBuffer::operator bool const):
(WebCore::GraphicsContextGLCoordinated::DrawingBuffer::texture const):
(WebCore::GraphicsContextGLCoordinated::drawingBuffer):
(WebCore::GraphicsContextGLCoordinated::displayBuffer):
* Source/WebCore/platform/graphics/coordinated/GraphicsContextGLCoordinatedEpoxy.cpp: Renamed from Source/WebCore/platform/graphics/coordinated/GraphicsContextGLEGLCoordinated.cpp.
(WebCore::GraphicsContextGLCoordinated::setupCurrentTexture const):
* Source/WebCore/platform/graphics/egl/GraphicsContextGLEGL.cpp:
(WebCore::createWebProcessGraphicsContextGL):
(WebCore::GraphicsContextGLEGL::~GraphicsContextGLEGL):
(WebCore::GraphicsContextGLEGL::platformInitialize):
(WebCore::GraphicsContextGLEGL::attachDrawingBufferTexture):
(WebCore::GraphicsContextGLEGL::reshapeDrawingBuffer):
(WebCore::GraphicsContextGLEGL::prepareForDisplay):
(WebCore::GraphicsContextGLEGL::swapCompositorTexture): Deleted.
* Source/WebCore/platform/graphics/egl/GraphicsContextGLEGL.h:
* Source/WebCore/platform/graphics/gbm/GraphicsContextGLGBM.cpp:
(WebCore::GraphicsContextGLGBM::~GraphicsContextGLGBM):
(WebCore::GraphicsContextGLGBM::DrawingBuffer::DrawingBuffer):
(WebCore::GraphicsContextGLGBM::DrawingBuffer::operator=):
(WebCore::GraphicsContextGLGBM::DrawingBuffer::isInUse const):
(WebCore::GraphicsContextGLGBM::DrawingBuffer::release):
(WebCore::GraphicsContextGLGBM::destroyDrawingBuffer const):
(WebCore::GraphicsContextGLGBM::freeDrawingBuffers):
(WebCore::GraphicsContextGLGBM::freeObsoleteDrawingBuffers):
(WebCore::GraphicsContextGLGBM::bindNextDrawingBuffer):
(WebCore::GraphicsContextGLGBM::prepareForDisplay):
(WebCore::GraphicsContextGLGBM::prepareForDisplayWithFinishedSignal):
(WebCore::GraphicsContextGLGBM::readCompositedResults):
* Source/WebCore/platform/graphics/gbm/GraphicsContextGLGBM.h:
* Source/WebKit/GPUProcess/graphics/RemoteGraphicsContextGLGBM.cpp:
(WebKit::RemoteGraphicsContextGLGBM::prepareForDisplay):
* Tools/TestWebKitAPI/PlatformGTK.cmake:
* Tools/TestWebKitAPI/PlatformWPE.cmake:
* Tools/TestWebKitAPI/Tests/WebCore/glib/GraphicsContextGLCoordinated.cpp: Renamed from Tools/TestWebKitAPI/Tests/WebCore/glib/GraphicsContextGLEGL.cpp.
(TestWebKitAPI::WebCore::createTestedGraphicsContextGL):
(TestWebKitAPI::WebCore::AnyContextAttributeTest::antialias const):
(TestWebKitAPI::WebCore::AnyContextAttributeTest::preserveDrawingBuffer const):
(TestWebKitAPI::WebCore::AnyContextAttributeTest::isWebGL2 const):
(TestWebKitAPI::WebCore::AnyContextAttributeTest::attributes):
(TestWebKitAPI::WebCore::AnyContextAttributeTest::createTestContext):
(TestWebKitAPI::checkReadPixel):
(TestWebKitAPI::TEST_F(GraphicsContextGLCoordinatedTest, ClearBufferIncorrectSizes)):
(TestWebKitAPI::TEST_F(GraphicsContextGLCoordinatedTest, DestroyWithoutMakingCurrent)):
(TestWebKitAPI::TEST_F(GraphicsContextGLCoordinatedTest, TwoLinks)):
(TestWebKitAPI::TEST_F(GraphicsContextGLCoordinatedTest, CopyNativeImageNoDrawingBufferReturnsNullptr)):
(TestWebKitAPI::TEST_F(GraphicsContextGLCoordinatedTest, CopyNativeImageIsNotYFlipped)):
(TestWebKitAPI::TEST_F(GraphicsContextGLCoordinatedTest, CopyImageAndMutateDrawingBuffer)):
(TestWebKitAPI::TEST_P):
(TestWebKitAPI::TEST_F(GraphicsContextGLCoordinatedReadPixelsTest, readPixelsSuccess)):
(TestWebKitAPI::TEST_F(GraphicsContextGLCoordinatedReadPixelsTest, readPixelsTooLargeRect)):
(TestWebKitAPI::TEST_F(GraphicsContextGLCoordinatedReadPixelsTest, readPixelsWithStatusSuccess)):
(TestWebKitAPI::TEST_F(GraphicsContextGLCoordinatedReadPixelsTest, readPixelsWithStatusTooLargeRect)):
(TestWebKitAPI::TEST_F(GraphicsContextGLCoordinatedReshapeTest, reshapeSuccess)):
(TestWebKitAPI::TEST_F(GraphicsContextGLCoordinatedReshapeTest, reshapeWidthTooLarge)):
(TestWebKitAPI::TEST_F(GraphicsContextGLCoordinatedReshapeTest, reshapeHeightTooLarge)):
* Source/WebCore/platform/graphics/android/GraphicsContextGLAndroid.h:

e2129ef

Misc iOS, visionOS, tvOS & watchOS macOS Linux Windows
✅ 🧪 style ✅ 🛠 ios ✅ 🛠 mac ✅ 🛠 wpe ⏳ 🛠 win
✅ 🧪 bindings ✅ 🛠 ios-sim ✅ 🛠 mac-AS-debug ✅ 🧪 wpe-wk2 ⏳ 🧪 win-tests
✅ 🧪 webkitperl ⏳ 🧪 ios-wk2 ⏳ 🧪 api-mac ⏳ 🧪 api-wpe
✅ 🧪 ios-wk2-wpt ⏳ 🧪 api-mac-debug
⏳ 🧪 api-ios loading-orange 🧪 mac-wk2 ✅ 🛠 gtk3-gcc
⏳ 🛠 ios-safer-cpp ⏳ 🧪 mac-AS-debug-wk2 ✅ 🛠 gtk
✅ 🛠 vision ⏳ 🧪 gtk-wk2
✅ 🛠 vision-sim ⏳ 🧪 mac-intel-wk2 ✅ 🧪 api-gtk
✅ 🧪 vision-wk2 ⏳ 🛠 mac-safer-cpp ✅ 🛠 playstation
✅ 🛠 tv ✅ 🧪 mac-site-isolation
✅ 🛠 tv-sim
✅ 🛠 watch
✅ 🛠 watch-sim

@carlosgcampos
carlosgcampos requested review from a team and magomez as code owners October 2, 2026 09:35
@carlosgcampos carlosgcampos self-assigned this Oct 2, 2026
@carlosgcampos carlosgcampos added the WebKitGTK Bugs related to the Gtk API layer. label Oct 2, 2026
Comment thread Source/WebCore/platform/graphics/egl/GraphicsContextGLEGL.cpp
if (!m_textureWrapper)
return false;

return !m_textureWrapper->hasOneRef();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the isInUse state is purely checked via the fact if a Ref() is hold.. ok, but that will break TextureMapper, no? There you only pass a raw ID to the compositor, not a Ref?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we answer this isInUse incorrectly, we could end up reusing the buffer too early, no? Are we sure that dropping the last ref (CPU-wise) means that the GPU is really finished with that buffer? I cannot see any guarantee for that...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't break texture mapper, it keeps it in its current state, no change in behavior.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we answer this isInUse incorrectly, we could end up reusing the buffer too early, no? Are we sure that dropping the last ref (CPU-wise) means that the GPU is really finished with that buffer? I cannot see any guarantee for that...

Exactly the situation we currently have without this patch.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding the last reference. It means skia has notified that the resource can be re-used/deleted. For GBM that's enough, for the non-GBM case we could use a release fence, but I'm not sure it's worth for a fallback code that it's only used for testing

m_layerContentsDisplayDelegate = GraphicsLayerContentsDisplayDelegateCoordinated::create();
}

GraphicsContextGLCoordinated::~GraphicsContextGLCoordinated()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here are no more isInUse() checks -- can we have the case where we still have pending/committed promise images in use by the compositor? that would then reference stale textures, that you just destroyed? Not sure about the dstruction order here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the context is destroyed we need to release the textures no matter what. So, yes, the compositor might still have a stale texture. There's no change in behavior here either.

@@ -77,7 +77,13 @@ GraphicsContextGLGBM::GraphicsContextGLGBM(GraphicsContextGLAttributes&& attribu

GraphicsContextGLGBM::~GraphicsContextGLGBM()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SAme question as in the GraphicsContextCoordinatedGL destructor: in GPUP mode, don't we need some kind of check if the remote side still uses the buffers?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GBM case is different, this is not a problem because CoordinatedPlatformLayerBufferDMABuf keeps a reference of the DMABufBuffer, GPU process imports the buffer, so it will be alive as long as it's references, like the DMABuf buffers we share with the UI process.

https://bugs.webkit.org/show_bug.cgi?id=325950

Reviewed by NOBODY (OOPS!).

We currently use two fixed buffers, but the compositor hasn't released
the previous one when we do the swap, so a third one is needed. Use a
swapchain based on a fixed size array of 3 buffers similar to the one
used by Cocoa implementation. If we need to bind a new buffer and next
one is still in used by the compositor, it's moved to an vector to be
released later when no longer in use and a new one is allocated. The
same happens when we release current buffers due to a reshape, buffers
still used by the compositor are moved to the obsolete buffers vector.
In the GBM implementation the drawing buffer keeps a reference of the
DMABufBuffer so that we know it's no longer in use by the compositor
when it only has one reference. For non-GBM implementation a thread safe
ref counted class is used to wrap the inner texture ID that is passed to
the compositor to keep a reference while the texture is in use.
This patch also moves the coordinated graphics implementation of
GraphicsContextGL to its own file and renames the API test.

Test: Tools/TestWebKitAPI/Tests/WebCore/glib/GraphicsContextGLCoordinated.cpp

* Source/WebCore/platform/CoordinatedGraphics.cmake:
* Source/WebCore/platform/graphics/coordinated/CoordinatedPlatformLayerBufferSkiaImage.cpp:
(WebCore::PromiseWebGLImageContext::PromiseWebGLImageContext):
(WebCore::PromiseWebGLImageContext::promiseImageTexture):
(WebCore::CoordinatedPlatformLayerBufferSkiaImage::create):
(): Deleted.
* Source/WebCore/platform/graphics/coordinated/CoordinatedPlatformLayerBufferSkiaImage.h:
* Source/WebCore/platform/graphics/coordinated/GraphicsContextGLCoordinated.cpp: Added.
(WebCore::GraphicsContextGLCoordinated::create):
(WebCore::GraphicsContextGLCoordinated::GraphicsContextGLCoordinated):
(WebCore::GraphicsContextGLCoordinated::~GraphicsContextGLCoordinated):
(WebCore::GraphicsContextGLCoordinated::platformInitialize):
(WebCore::GraphicsContextGLCoordinated::DrawingBuffer::DrawingBuffer):
(WebCore::GraphicsContextGLCoordinated::DrawingBuffer::operator=):
(WebCore::GraphicsContextGLCoordinated::DrawingBuffer::isInUse const):
(WebCore::GraphicsContextGLCoordinated::DrawingBuffer::release):
(WebCore::GraphicsContextGLCoordinated::createDrawingBuffer const):
(WebCore::GraphicsContextGLCoordinated::destroyDrawingBuffer const):
(WebCore::GraphicsContextGLCoordinated::freeDrawingBuffers):
(WebCore::GraphicsContextGLCoordinated::freeObsoleteDrawingBuffers):
(WebCore::GraphicsContextGLCoordinated::bindNextDrawingBuffer):
(WebCore::GraphicsContextGLCoordinated::reshapeDrawingBuffer):
(WebCore::GraphicsContextGLCoordinated::prepareForDisplay):
(WebCore::GraphicsContextGLCoordinated::readCompositedResults):
* Source/WebCore/platform/graphics/coordinated/GraphicsContextGLCoordinated.h: Added.
(WebCore::GraphicsContextGLCoordinated::DrawingBuffer::operator bool const):
(WebCore::GraphicsContextGLCoordinated::DrawingBuffer::texture const):
(WebCore::GraphicsContextGLCoordinated::drawingBuffer):
(WebCore::GraphicsContextGLCoordinated::displayBuffer):
* Source/WebCore/platform/graphics/coordinated/GraphicsContextGLCoordinatedEpoxy.cpp: Renamed from Source/WebCore/platform/graphics/coordinated/GraphicsContextGLEGLCoordinated.cpp.
(WebCore::GraphicsContextGLCoordinated::setupCurrentTexture const):
* Source/WebCore/platform/graphics/egl/GraphicsContextGLEGL.cpp:
(WebCore::createWebProcessGraphicsContextGL):
(WebCore::GraphicsContextGLEGL::~GraphicsContextGLEGL):
(WebCore::GraphicsContextGLEGL::platformInitialize):
(WebCore::GraphicsContextGLEGL::attachDrawingBufferTexture):
(WebCore::GraphicsContextGLEGL::reshapeDrawingBuffer):
(WebCore::GraphicsContextGLEGL::prepareForDisplay):
(WebCore::GraphicsContextGLEGL::swapCompositorTexture): Deleted.
* Source/WebCore/platform/graphics/egl/GraphicsContextGLEGL.h:
* Source/WebCore/platform/graphics/gbm/GraphicsContextGLGBM.cpp:
(WebCore::GraphicsContextGLGBM::~GraphicsContextGLGBM):
(WebCore::GraphicsContextGLGBM::DrawingBuffer::DrawingBuffer):
(WebCore::GraphicsContextGLGBM::DrawingBuffer::operator=):
(WebCore::GraphicsContextGLGBM::DrawingBuffer::isInUse const):
(WebCore::GraphicsContextGLGBM::DrawingBuffer::release):
(WebCore::GraphicsContextGLGBM::destroyDrawingBuffer const):
(WebCore::GraphicsContextGLGBM::freeDrawingBuffers):
(WebCore::GraphicsContextGLGBM::freeObsoleteDrawingBuffers):
(WebCore::GraphicsContextGLGBM::bindNextDrawingBuffer):
(WebCore::GraphicsContextGLGBM::prepareForDisplay):
(WebCore::GraphicsContextGLGBM::prepareForDisplayWithFinishedSignal):
(WebCore::GraphicsContextGLGBM::readCompositedResults):
* Source/WebCore/platform/graphics/gbm/GraphicsContextGLGBM.h:
* Source/WebKit/GPUProcess/graphics/RemoteGraphicsContextGLGBM.cpp:
(WebKit::RemoteGraphicsContextGLGBM::prepareForDisplay):
* Tools/TestWebKitAPI/PlatformGTK.cmake:
* Tools/TestWebKitAPI/PlatformWPE.cmake:
* Tools/TestWebKitAPI/Tests/WebCore/glib/GraphicsContextGLCoordinated.cpp: Renamed from Tools/TestWebKitAPI/Tests/WebCore/glib/GraphicsContextGLEGL.cpp.
(TestWebKitAPI::WebCore::createTestedGraphicsContextGL):
(TestWebKitAPI::WebCore::AnyContextAttributeTest::antialias const):
(TestWebKitAPI::WebCore::AnyContextAttributeTest::preserveDrawingBuffer const):
(TestWebKitAPI::WebCore::AnyContextAttributeTest::isWebGL2 const):
(TestWebKitAPI::WebCore::AnyContextAttributeTest::attributes):
(TestWebKitAPI::WebCore::AnyContextAttributeTest::createTestContext):
(TestWebKitAPI::checkReadPixel):
(TestWebKitAPI::TEST_F(GraphicsContextGLCoordinatedTest, ClearBufferIncorrectSizes)):
(TestWebKitAPI::TEST_F(GraphicsContextGLCoordinatedTest, DestroyWithoutMakingCurrent)):
(TestWebKitAPI::TEST_F(GraphicsContextGLCoordinatedTest, TwoLinks)):
(TestWebKitAPI::TEST_F(GraphicsContextGLCoordinatedTest, CopyNativeImageNoDrawingBufferReturnsNullptr)):
(TestWebKitAPI::TEST_F(GraphicsContextGLCoordinatedTest, CopyNativeImageIsNotYFlipped)):
(TestWebKitAPI::TEST_F(GraphicsContextGLCoordinatedTest, CopyImageAndMutateDrawingBuffer)):
(TestWebKitAPI::TEST_P):
(TestWebKitAPI::TEST_F(GraphicsContextGLCoordinatedReadPixelsTest, readPixelsSuccess)):
(TestWebKitAPI::TEST_F(GraphicsContextGLCoordinatedReadPixelsTest, readPixelsTooLargeRect)):
(TestWebKitAPI::TEST_F(GraphicsContextGLCoordinatedReadPixelsTest, readPixelsWithStatusSuccess)):
(TestWebKitAPI::TEST_F(GraphicsContextGLCoordinatedReadPixelsTest, readPixelsWithStatusTooLargeRect)):
(TestWebKitAPI::TEST_F(GraphicsContextGLCoordinatedReshapeTest, reshapeSuccess)):
(TestWebKitAPI::TEST_F(GraphicsContextGLCoordinatedReshapeTest, reshapeWidthTooLarge)):
(TestWebKitAPI::TEST_F(GraphicsContextGLCoordinatedReshapeTest, reshapeHeightTooLarge)):
* Source/WebCore/platform/graphics/android/GraphicsContextGLAndroid.h:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

WebKitGTK Bugs related to the Gtk API layer.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants