Skip to content

[GStreamer] Multiplanar YUV video shows no picture when a plane stride is not 64-byte aligned - #78212

Open
dangowrt wants to merge 1 commit into
WebKit:mainfrom
dangowrt:eng/gstreamer-yuv-aligned-plane-upload
Open

dangowrt wants to merge 1 commit into
WebKit:mainfrom
dangowrt:eng/gstreamer-yuv-aligned-plane-upload

Conversation

@dangowrt

@dangowrt dangowrt commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

12b2060

[GStreamer] Multiplanar YUV video shows no picture when a plane stride is not 64-byte aligned
https://bugs.webkit.org/show_bug.cgi?id=328398

Reviewed by NOBODY (OOPS!).

A hardware-decoded multiplanar YUV frame delivered as a DMABuf shows no
picture on panfrost/Mali even though decoding succeeds. importYUV()
splits the frame into one single-plane EGLImage per plane, each built
with that plane's own byte stride. A plane imported on its own is held to
the GPU's stricter standalone row alignment (64 bytes on Mali arch >= 7),
whereas a true multiplanar image needs only 16. When a plane's stride is
a multiple of 16 but not of 64 (an rk3588 AV1 luma stride of 592 at width
586, for example) the standalone import is rejected, importYUV() returns
null and nothing is painted. Widths that are multiples of 64 play. The
fault is a property of the plane byte stride, so it reaches every
multiplanar YUV format importYUV() handles, 10-bit P010 included.

Keep the per-plane path and WebKit's own YUV conversion as the single
colour path for every frame, and when a plane's zero-copy import is
rejected, repack that plane into an aligned-stride single-plane GBM buffer
object of the same per-plane format, read through a GstVideoFrame map so
the dma-buf cache is synchronised, then import the repacked plane through
the existing path and combine it with the zero-copy planes. The colour
result is byte-identical to the per-plane render used everywhere today;
the per-frame difference is a copy of the misaligned plane, invisible to
the picture, and 64-byte-aligned strides keep the zero-copy import. The
first rejected {format, modifier, plane, stride} is cached so later frames
of the stream repack directly and the GPU logs its alignment error once.

This covers the TextureMapper coordinated path. The Skia coordinated path
(DMABufBuffer::createPromiseImage) splits planes the same way and wants
the same treatment as a follow-up.

* Source/WebCore/platform/graphics/coordinated/CoordinatedPlatformLayerBufferDMABuf.h:
* Source/WebCore/platform/graphics/coordinated/CoordinatedPlatformLayerBufferVideo.h:
* Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedPlatformLayerBufferDMABufTextureMapper.cpp:
(WebCore::bytesPerSampleForPlaneFourcc):
(WebCore::importRepackedPlane):
(WebCore::importYUV):
(WebCore::CoordinatedPlatformLayerBufferDMABuf::importDMABuf const):
* Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedPlatformLayerBufferVideoTextureMapper.cpp:
(WebCore::CoordinatedPlatformLayerBufferVideo::createBufferFromDMABufMemory):

12b2060

Misc iOS, visionOS, tvOS & watchOS macOS Linux Windows
✅ 🧪 style ✅ 🛠 ios ✅ 🛠 mac ✅ 🛠 wpe ✅ 🛠 win
✅ 🧪 bindings ✅ 🛠 ios-sim ✅ 🛠 mac-cmake-debug ✅ 🧪 wpe-wk2 ✅ 🧪 win-tests
✅ 🧪 webkitperl ✅ 🧪 ios-wk2 ✅ 🧪 api-mac ✅ 🧪 api-wpe
✅ 🧪 ios-wk2-wpt ✅ 🧪 api-mac-cmake-debug
✅ 🧪 api-ios ✅ 🧪 mac-wk2 ✅ 🛠 gtk3-gcc
✅ 🛠 ios-safer-cpp ✅ 🧪 mac-cmake-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

…e is not 64-byte aligned

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

Reviewed by NOBODY (OOPS!).

A hardware-decoded multiplanar YUV frame delivered as a DMABuf shows no
picture on panfrost/Mali even though decoding succeeds. importYUV()
splits the frame into one single-plane EGLImage per plane, each built
with that plane's own byte stride. A plane imported on its own is held to
the GPU's stricter standalone row alignment (64 bytes on Mali arch >= 7),
whereas a true multiplanar image needs only 16. When a plane's stride is
a multiple of 16 but not of 64 (an rk3588 AV1 luma stride of 592 at width
586, for example) the standalone import is rejected, importYUV() returns
null and nothing is painted. Widths that are multiples of 64 play. The
fault is a property of the plane byte stride, so it reaches every
multiplanar YUV format importYUV() handles, 10-bit P010 included.

Keep the per-plane path and WebKit's own YUV conversion as the single
colour path for every frame, and when a plane's zero-copy import is
rejected, repack that plane into an aligned-stride single-plane GBM buffer
object of the same per-plane format, read through a GstVideoFrame map so
the dma-buf cache is synchronised, then import the repacked plane through
the existing path and combine it with the zero-copy planes. The colour
result is byte-identical to the per-plane render used everywhere today;
the per-frame difference is a copy of the misaligned plane, invisible to
the picture, and 64-byte-aligned strides keep the zero-copy import. The
first rejected {format, modifier, plane, stride} is cached so later frames
of the stream repack directly and the GPU logs its alignment error once.

This covers the TextureMapper coordinated path. The Skia coordinated path
(DMABufBuffer::createPromiseImage) splits planes the same way and wants
the same treatment as a follow-up.

* Source/WebCore/platform/graphics/coordinated/CoordinatedPlatformLayerBufferDMABuf.h:
* Source/WebCore/platform/graphics/coordinated/CoordinatedPlatformLayerBufferVideo.h:
* Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedPlatformLayerBufferDMABufTextureMapper.cpp:
(WebCore::bytesPerSampleForPlaneFourcc):
(WebCore::importRepackedPlane):
(WebCore::importYUV):
(WebCore::CoordinatedPlatformLayerBufferDMABuf::importDMABuf const):
* Source/WebCore/platform/graphics/texmap/coordinated/CoordinatedPlatformLayerBufferVideoTextureMapper.cpp:
(WebCore::CoordinatedPlatformLayerBufferVideo::createBufferFromDMABufMemory):
@dangowrt dangowrt changed the title [GStreamer] Multiplanar YUV video shows no picture when a plane stride is not 64-byte aligned https://bugs.webkit.org/show_bug.cgi?id=328398 [GStreamer] Multiplanar YUV video shows no picture when a plane stride is not 64-byte aligned Oct 25, 2026
@dangowrt
dangowrt marked this pull request as ready for review October 25, 2026 09:42
@dangowrt
dangowrt requested a review from magomez as a code owner October 25, 2026 09:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants