Bug 294223

Summary: WebGPU 1D texture sampling bug
Product: WebKit Reporter: Steven Wittens <steven>
Component: WebGPUAssignee: Mike Wyrzykowski <mwyrzykowski>
Status: RESOLVED FIXED    
Severity: Normal CC: mwyrzykowski, tzagallo, webkit-bug-importer
Priority: P2 Keywords: InRadar
Version: Safari Technology Preview   
Hardware: Mac (Apple Silicon)   
OS: macOS 15   
Attachments:
Description Flags
example misaligned palette texture (off by 4 texels).. there should be no green none

Steven Wittens
Reported 2025-06-09 14:37:09 PDT
Created attachment 475516 [details] example misaligned palette texture (off by 4 texels).. there should be no green In the following WebGPU demo from Use.GPU , a 1D texture is used to store and sample the palette for the voxels: https://usegpu.live/demo/geometry/voxel (format: rgba8unorm-srgb, texture_1d<f32>) In Safari Tech Preview, the palette is randomly corrupt on re-loading the page, though it remains constant during a particular run. You can also trigger this by pressing Next+Previous at the bottom (which does not reload the page, but reloads the texture). Tweaking the shader suggests that instead of accessing texel 'i' it is sometimes accessing texel 'i - 4', 'i - 8' or 'i - 12' and does so consistently for a given texture. i.e. It looks like a misalignment issue when uploading the texture to the GPU. There is also this 6 year old bug that suggests all non-2D textures are broken, however I am not sure it's true, given that the voxel data is a 3D texture (texture_3d(u32), r8uint) and it works fine. https://bugs.webkit.org/show_bug.cgi?id=201384
Attachments
example misaligned palette texture (off by 4 texels).. there should be no green (321.57 KB, image/png)
2025-06-09 14:37 PDT, Steven Wittens
no flags
Radar WebKit Bug Importer
Comment 1 2025-06-09 16:54:18 PDT
Mike Wyrzykowski
Comment 2 2025-06-11 10:45:38 PDT
https://bugs.webkit.org/show_bug.cgi?id=201384 is only applicable potentially on Tier1 devices, on macOS Sequoia no such devices exist is my understanding.
Mike Wyrzykowski
Comment 3 2025-06-11 10:50:45 PDT
Checking the gputrace, if you'd like to try as well here are the instructions: `````` (Launch Safari or Safari Technology Preview) __XPC_METAL_CAPTURE_ENABLED=1 open /Applications/Safari.app (Capture a trace) notifyutil -p com.apple.WebKit.WebGPU.CaptureFrame (Find where the trace was saved - I usually use Console.app and search for “gputrace") ```` By default it captures one MTLCommandBuffer, you can change it via: ``` (Set frame count to 10) notifyutil -s com.apple.WebKit.WebGPU.CaptureFrame 10 (Capture a trace) notifyutil -p com.apple.WebKit.WebGPU.CaptureFrame ```
Mike Wyrzykowski
Comment 4 2025-06-11 11:13:38 PDT
The issue seems to be in the blit command encoder path. Forcing the replaceRegion path: https://github.com/WebKit/WebKit/blob/66fc5e188133f37c2990801c5c665825dbe85243/Source/WebGPU/WebGPU/Queue.mm#L1006 and the issue is not reproducible. Presumably we have an issue around this line: https://github.com/WebKit/WebKit/blob/66fc5e188133f37c2990801c5c665825dbe85243/Source/WebGPU/WebGPU/Queue.mm#L1147
Mike Wyrzykowski
Comment 5 2025-06-11 11:16:54 PDT
Forcing the no copy path (set noCopy = true) and the issue is similarly not reproducible: https://github.com/WebKit/WebKit/blob/66fc5e188133f37c2990801c5c665825dbe85243/Source/WebGPU/WebGPU/Queue.mm#L1109
Mike Wyrzykowski
Comment 6 2025-06-11 11:23:37 PDT
Mike Wyrzykowski
Comment 7 2025-06-11 13:27:27 PDT
aligning to 64 bytes instead of 16 resolves the issue but I don't know if I'm just working around the issue
Mike Wyrzykowski
Comment 8 2025-06-11 13:29:22 PDT
diff --git a/Source/WebGPU/WebGPU/Queue.mm b/Source/WebGPU/WebGPU/Queue.mm index 228a7915f865..a7af1da907c7 100644 --- a/Source/WebGPU/WebGPU/Queue.mm +++ b/Source/WebGPU/WebGPU/Queue.mm @@ -600,7 +601,7 @@ std::pair<id<MTLBuffer>, uint64_t> Queue::newTemporaryBufferWithBytes(std::span< } auto priorOffset = m_temporaryBufferOffset; - m_temporaryBufferOffset += WTF::roundUpToMultipleOf(16, dataSize); + m_temporaryBufferOffset += WTF::roundUpToMultipleOf(64, dataSize); memcpySpan(span(m_temporaryBuffer).subspan(priorOffset), dataSpan); return std::make_pair(m_temporaryBuffer, priorOffset); }
Mike Wyrzykowski
Comment 10 2025-06-11 13:45:33 PDT
Mike Wyrzykowski
Comment 11 2025-06-11 14:03:07 PDT
I need to make a tiny test case in C++ to prove this is a Metal issue.
Mike Wyrzykowski
Comment 12 2025-06-15 21:34:56 PDT
So it appears passing 0 to sourceBytesPerRow is problematic.
Mike Wyrzykowski
Comment 13 2025-06-15 21:35:22 PDT
Passing the correct value for sourceBytesPerRow and we don't need to align to 64 bytes
Mike Wyrzykowski
Comment 14 2025-06-15 21:35:43 PDT
I would have expected a Metal validation error if this is a requirement, perhaps missing in the API validation layer
EWS
Comment 15 2025-06-16 00:54:17 PDT
Committed 296260@main (1b6e6ca8f0c2): <https://commits.webkit.org/296260@main> Reviewed commits have been landed. Closing PR #46615 and removing active labels.
Note You need to log in before you can comment on or make changes to this bug.