Bug 311103

Summary: REGRESSION(308458@main): [GTK] white noise images
Product: WebKit Reporter: Fujii Hironori <fujii>
Component: WebKitGTKAssignee: Nobody <webkit-unassigned>
Status: NEW    
Severity: Normal CC: bugs-noreply, zimmermann
Priority: P2 Keywords: DoNotImportToRadar
Version: WebKit Nightly Build   
Hardware: Unspecified   
OS: Unspecified   
Attachments:
Description Flags
screenshot none

Fujii Hironori
Reported 2026-03-30 05:52:09 PDT
After 308458@main, images sometimes have white noise on my laptop. However, no such problem on my desktop.
Attachments
screenshot (1.16 MB, image/png)
2026-03-30 18:09 PDT, Fujii Hironori
no flags
Fujii Hironori
Comment 1 2026-03-30 18:09:52 PDT
Created attachment 478852 [details] screenshot
Fujii Hironori
Comment 2 2026-04-12 18:54:35 PDT
Adding sleep can work around the issue. However, it becomes slow. diff --git a/Source/WebCore/platform/graphics/skia/SkiaReplayCanvas.cpp b/Source/WebCore/platform/graphics/skia/SkiaReplayCanvas.cpp index 482ac8d7f28e..86dc824bc8c9 100644 --- a/Source/WebCore/platform/graphics/skia/SkiaReplayCanvas.cpp +++ b/Source/WebCore/platform/graphics/skia/SkiaReplayCanvas.cpp @@ -47,6 +47,7 @@ SkiaReplayCanvas::SkiaReplayCanvas(const IntSize& size, const RefPtr<SkiaRecordi m_recording->waitForUploadCondition(); m_recording->waitForUploadFence(); + sleep(500_ms); const auto& gpuAtlases = m_recording->gpuAtlases(); m_atlases.reserveInitialCapacity(gpuAtlases.size());
Fujii Hironori
Comment 3 2026-04-12 20:21:09 PDT
No. It still happens with the patch. Lower probability.
Fujii Hironori
Comment 4 2026-04-12 21:15:44 PDT
Setting WEBKIT_DISABLE_DMABUF_ATLAS=1 can work around the issue.
Nikolas Zimmermann
Comment 5 2026-04-13 02:30:52 PDT
I guess the problem is related to updating the dma-buf from another thread: ``` // DMA-buf path: create atlas without uploading, dispatch pixel writes to worker. if (!m_uploadWorkQueue) m_uploadWorkQueue = WorkQueue::create("AtlasUpload"_s); uploadCondition.addPending(); m_uploadWorkQueue->dispatch([atlas = Ref { *atlas }, condition = Ref { uploadCondition }]() mutable { atlas->uploadImages(); condition->signal(); }); return atlas; ```
Nikolas Zimmermann
Comment 6 2026-04-13 02:33:55 PDT
Maybe it is related to sharing the same write scope for multiple disjoint writes -- which should work in theory, but maybe there's a driver dependent issue. Can you create the writeScope inside the inner for loop instead of outside? ``` bool SkiaGPUAtlas::uploadImages() { ... #if USE(GBM) if (auto* gpuBuffer = m_atlasTexture->memoryMappedGPUBuffer()) { if (gpuBuffer->isLinear() || gpuBuffer->isVivanteSuperTiled()) { for (const auto& entry : m_layout->entries()) { auto writeScope = makeGPUBufferWriteScope(*gpuBuffer); if (!writeScope) return false; if (auto pixels = pixelDataInSRGB(entry.rasterImage)) gpuBuffer->updateContents(*writeScope, pixels->first, entry.atlasRect, pixels->second); } return true; } } #endif ```
Fujii Hironori
Comment 7 2026-04-13 03:41:08 PDT
Unfortunately, it has no effect. diff --git a/Source/WebCore/platform/graphics/skia/SkiaGPUAtlas.cpp b/Source/WebCore/platform/graphics/skia/SkiaGPUAtlas.cpp index 4d5a36f96e60..bb8375c96661 100644 --- a/Source/WebCore/platform/graphics/skia/SkiaGPUAtlas.cpp +++ b/Source/WebCore/platform/graphics/skia/SkiaGPUAtlas.cpp @@ -101,11 +101,10 @@ bool SkiaGPUAtlas::uploadImages() #if USE(GBM) if (auto* gpuBuffer = m_atlasTexture->memoryMappedGPUBuffer()) { if (gpuBuffer->isLinear() || gpuBuffer->isVivanteSuperTiled()) { - auto writeScope = makeGPUBufferWriteScope(*gpuBuffer); - if (!writeScope) - return false; - for (const auto& entry : m_layout->entries()) { + auto writeScope = makeGPUBufferWriteScope(*gpuBuffer); + if (!writeScope) + return false; if (auto pixels = pixelDataInSRGB(entry.rasterImage)) gpuBuffer->updateContents(*writeScope, pixels->first, entry.atlasRect, pixels->second); }
Nikolas Zimmermann
Comment 8 2026-04-13 04:04:44 PDT
Ok, one things less to check. Please test instead: Changing: ``` // DMA-buf path: create atlas without uploading, dispatch pixel writes to worker. if (!m_uploadWorkQueue) m_uploadWorkQueue = WorkQueue::create("AtlasUpload"_s); uploadCondition.addPending(); m_uploadWorkQueue->dispatch([atlas = Ref { *atlas }, condition = Ref { uploadCondition }]() mutable { atlas->uploadImages(); condition->signal(); }); return atlas; ``` To: ``` // DMA-buf path: create atlas without uploading, dispatch pixel writes to worker. atlas->uploadImages(); uploadCondition->signal(); return atlas; ``` That does the uploads on the main thread instead of a worker thread.
Nikolas Zimmermann
Comment 9 2026-04-13 04:05:23 PDT
(Not fully correct, you need the addPending()... - but you get the idea, just remove the work queue out of the condition)
Note You need to log in before you can comment on or make changes to this bug.