Files
marfrit-packages/arch/chromium-fourier/patches/nv12-external-oes-on-modifier-external-only.patch
T
marfrit 8756ce38be
build and publish packages / distcc-avahi-aarch64 (push) Successful in 46s
build and publish packages / lmcp-any (push) Successful in 9s
build and publish packages / lmcp-debian (push) Successful in 4s
build and publish packages / claude-his-any (push) Successful in 7s
build and publish packages / ffmpeg-v4l2-request-aarch64 (push) Successful in 12m8s
build and publish packages / claude-his-debian (push) Successful in 5s
chromium-fourier r2 + firefox-fourier 150.0.1 + KWIN_PIVOT.md
chromium-fourier:
- patch 3/3 nv12-external-oes-on-modifier-external-only.patch — adds
  NativePixmapEGLBinding::ModifierRequiresExternalOES helper, extends
  OzoneImageGLTexturesHolder::GetBinding to honor EGL external_only
  flag for NV12 dmabufs on panfrost / panthor. Validated on ohm
  (RK3566 hantro mainline 6.19.10): bbb_1080p30_h264.mp4 plays at
  34.7 % combined CPU vs ~131 % pre-patch baseline (~3.8x).
- PKGBUILD pkgrel 1->2, source array + sha256sums + prepare() hook for
  patch 4, patch numbering 1/2,2/2 -> 1/3,2/3,3/3.
- NEXT.md appended with 2026-04-28 section: patch 4 design, validation
  log, KWin GL_ALPHA bug pinpoint (preexisting since 2026-03-06,
  affects every wayland video client; unrelated to chromium-fourier),
  device-renumbering note (/dev/video1 = encoder post-reboot).
- KWIN_PIVOT.md: 4-phase plan to identify and patch KWin's
  glTexImage2D(internalFormat=GL_ALPHA) site, ohm-only test plan,
  scope discipline.
- patches/ now tracked (compiler-rt-adjust-paths, enable-v4l2,
  wayland-allow-direct-egl-gles2, nv12-external-oes); the dead-end
  chromeos-pipeline-bypass.patch removed.

firefox-fourier:
- 4 patches (gfxinfo v4l2 stateless fourccs, libwrapper hwdevice ctx,
  ffmpegvideo v4l2-request route, prefs v4l2-request default).
- PKGBUILD bumped to firefox 150.0.1, Arch toolchain glue patches
  layered in, mozconfig with --without-wasm-sandboxed-libraries for
  ALARM, package() launcher fix (rm -f symlink before cat > to avoid
  ENOENT through the dangling /usr/local symlink mach install drops).
- 150.0.1-1-aarch64.pkg.tar.zst built on boltzmann (95 MB), pending
  fresnel power-on for V4L2 stateless validation on RK3399.
2026-04-28 12:02:18 +00:00

188 lines
8.3 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
From: Markus Fritsche <mfritsche@reauktion.de>
Subject: [PATCH] gpu/ozone: pick GL_TEXTURE_EXTERNAL_OES for NV12 dmabufs whose
DRM modifier is advertised external_only by the EGL driver
Date: 2026-04-28
Background
----------
On mainline-Linux Mali GPUs (mesa panfrost / panthor on Bifrost / Valhall)
every NV12 modifier exposed by `eglQueryDmaBufModifiersEXT` is flagged
`external_only` — DRM_FORMAT_MOD_LINEAR + ARM AFBC × 2 + ARM AFRC. Mesa's
behavior is spec-correct: GLES sampling of multi-plane formats is
defined only via `samplerExternalOES`, never `sampler2D`. The chromium
NV12 import path at
`gpu/command_buffer/service/shared_image/ozone_image_gl_textures_holder.cc`
already chooses `GL_TEXTURE_EXTERNAL_OES` when the SharedImageFormat is
flagged `PrefersExternalSampler` — but that flag is only set for the
generic "multi-plane on Linux" case in
`media/gpu/chromeos/mailbox_video_frame_converter.cc`. Frames that
arrive with an `external_only`-flagged modifier from a producer that
didn't set the flag (V4L2 hantro NV12 with AFBC/AFRC capture format on
RK3588's rkvdec2, future NativePixmap producers, etc.) hit the
`GL_TEXTURE_2D` path; ANGLE's `validationES.cpp:4894` then rejects YUV
EGLImages on non-EXTERNAL_OES targets, and the import fails.
This patch closes the gap: the texture-target choice in
`OzoneImageGLTexturesHolder::GetBinding` now consults the EGL driver's
`external_only` annotation for the pixmap's actual modifier in addition
to `format.PrefersExternalSampler()`. If either says "external sampler
required", the target switches to `GL_TEXTURE_EXTERNAL_OES`. Skia
Ganesh handles `GL_TEXTURE_EXTERNAL_OES` natively via
`GrGLTextureInfo.fTarget`, so no shader changes are required. Same
infrastructure chromium already uses for Android camera / decoder
dmabufs, retargeted at the Linux ozone layer.
Result is cached per `(fourcc, modifier)` tuple via a function-local
static `base::flat_map`, so the EGL query is not on the per-frame hot
path — once per unique format+modifier combination, after which the
runtime cost is a hash lookup behind a base::Lock.
Bug crbug.com/1498703 is the closest existing tracker; framing this
upstream as "make Linux NV12 import path consistent with the
ChromeOS PrefersExternalSampler default" is the right angle.
diff --git a/gpu/command_buffer/service/shared_image/ozone_image_gl_textures_holder.cc b/gpu/command_buffer/service/shared_image/ozone_image_gl_textures_holder.cc
index 525bdcb0dc..43b0723326 100644
--- a/gpu/command_buffer/service/shared_image/ozone_image_gl_textures_holder.cc
+++ b/gpu/command_buffer/service/shared_image/ozone_image_gl_textures_holder.cc
@@ -16,6 +16,7 @@
#include "ui/gl/gl_bindings.h"
#include "ui/gl/scoped_binders.h"
#include "ui/ozone/public/gl_ozone.h"
+#include "ui/ozone/common/native_pixmap_egl_binding.h"
#include "ui/ozone/public/native_pixmap_gl_binding.h"
#include "ui/ozone/public/ozone_platform.h"
#include "ui/ozone/public/surface_factory_ozone.h"
@@ -82,7 +83,14 @@ std::unique_ptr<ui::NativePixmapGLBinding> GetBinding(
// being multiplanar (if using per-plane sampling of a multiplanar texture,
// the buffer format passed in here must be the single-planar format of the
// plane).
- if (format.PrefersExternalSampler()) {
+ // chromium-fourier: also pick GL_TEXTURE_EXTERNAL_OES whenever the
+ // pixmap's DRM modifier is advertised external_only by the EGL
+ // driver. Mesa panfrost / panthor mark every NV12 modifier
+ // external_only — the PrefersExternalSampler flag alone misses
+ // the AFBC / AFRC tiled paths.
+ if (format.PrefersExternalSampler() ||
+ ui::NativePixmapEGLBinding::ModifierRequiresExternalOES(
+ pixmap.get(), plane_format)) {
target = GL_TEXTURE_EXTERNAL_OES;
} else {
target = GL_TEXTURE_2D;
diff --git a/ui/ozone/common/native_pixmap_egl_binding.cc b/ui/ozone/common/native_pixmap_egl_binding.cc
index 31877f4459..6855c1093e 100644
--- a/ui/ozone/common/native_pixmap_egl_binding.cc
+++ b/ui/ozone/common/native_pixmap_egl_binding.cc
@@ -6,10 +6,13 @@
#include <array>
+#include "base/containers/flat_map.h"
#include "base/logging.h"
#include "base/memory/scoped_refptr.h"
+#include "base/no_destructor.h"
#include "base/notreached.h"
#include "base/numerics/safe_conversions.h"
+#include "base/synchronization/lock.h"
#include "ui/gfx/linux/drm_util_linux.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_surface_egl.h"
@@ -56,6 +59,75 @@ bool NativePixmapEGLBinding::IsSharedImageFormatSupported(
viz::SharedImageFormat format) {
return GetFourCCFormatFromSharedImageFormat(format) != DRM_FORMAT_INVALID;
}
+// static
+bool NativePixmapEGLBinding::ModifierRequiresExternalOES(
+ const gfx::NativePixmap* pixmap,
+ viz::SharedImageFormat format) {
+ // chromium-fourier: query the EGL driver for the (fourcc, modifier)
+ // tuple's external_only flag. Cache results — eglQueryDmaBufModifiersEXT
+ // is a synchronous round-trip into the driver and we want it off the
+ // per-frame hot path. The cache lives for the lifetime of the GPU
+ // process (modifier tables don't change after EGL init).
+ if (!pixmap) {
+ return false;
+ }
+ const uint64_t modifier = pixmap->GetFormatModifier();
+ if (modifier == gfx::NativePixmapHandle::kNoModifier) {
+ // Implicit linear — same answer the driver would give for the
+ // matching LINEAR entry, but cheaper not to query.
+ return false;
+ }
+ const uint32_t fourcc = GetFourCCFormatFromSharedImageFormat(format);
+ if (fourcc == DRM_FORMAT_INVALID) {
+ return false;
+ }
+
+ using Key = std::pair<uint32_t, uint64_t>;
+ static base::NoDestructor<base::Lock> cache_lock;
+ static base::NoDestructor<base::flat_map<Key, bool>> cache;
+ {
+ base::AutoLock lock(*cache_lock);
+ auto it = cache->find({fourcc, modifier});
+ if (it != cache->end()) {
+ return it->second;
+ }
+ }
+
+ bool external_only = false;
+ do {
+ auto* display = gl::GLSurfaceEGL::GetGLDisplayEGL();
+ if (!display || !display->ext->b_EGL_EXT_image_dma_buf_import_modifiers) {
+ break;
+ }
+ EGLDisplay egl_display = display->GetDisplay();
+ EGLint num_modifiers = 0;
+ if (!eglQueryDmaBufModifiersEXT(egl_display, fourcc, 0, nullptr, nullptr,
+ &num_modifiers) ||
+ num_modifiers <= 0) {
+ break;
+ }
+ std::vector<EGLuint64KHR> modifiers(num_modifiers);
+ std::vector<EGLBoolean> ext_only(num_modifiers);
+ if (!eglQueryDmaBufModifiersEXT(egl_display, fourcc, num_modifiers,
+ modifiers.data(), ext_only.data(),
+ &num_modifiers)) {
+ break;
+ }
+ for (EGLint i = 0; i < num_modifiers; ++i) {
+ if (modifiers[i] == modifier) {
+ external_only = (ext_only[i] == EGL_TRUE);
+ break;
+ }
+ }
+ } while (0);
+
+ {
+ base::AutoLock lock(*cache_lock);
+ cache->insert_or_assign({fourcc, modifier}, external_only);
+ }
+ return external_only;
+}
+
// static
std::unique_ptr<NativePixmapGLBinding> NativePixmapEGLBinding::Create(
diff --git a/ui/ozone/common/native_pixmap_egl_binding.h b/ui/ozone/common/native_pixmap_egl_binding.h
index 61fb0de77f..ad3ac9ced5 100644
--- a/ui/ozone/common/native_pixmap_egl_binding.h
+++ b/ui/ozone/common/native_pixmap_egl_binding.h
@@ -27,6 +27,17 @@ class NativePixmapEGLBinding : public NativePixmapGLBinding {
static bool IsSharedImageFormatSupported(viz::SharedImageFormat format);
+ // chromium-fourier: returns true when |pixmap|'s DRM format modifier
+ // is advertised by the EGL driver as `external_only` for the given
+ // SharedImage format. Used at SharedImage creation time to override
+ // the default GL_TEXTURE_2D target to GL_TEXTURE_EXTERNAL_OES so that
+ // mesa panfrost / panthor NV12 dmabufs (always external_only) import
+ // cleanly via glEGLImageTargetTexture2DOES + samplerExternalOES.
+ // Result is cached per (fourcc, modifier) tuple — the underlying
+ // eglQueryDmaBufModifiersEXT call is not on the per-frame hot path.
+ static bool ModifierRequiresExternalOES(const gfx::NativePixmap* pixmap,
+ viz::SharedImageFormat format);
+
// Create an EGLImage from a given NativePixmap and plane and bind
// |texture_id| to |target| followed by binding the image to |target|. The
// color space is for the external sampler: When we sample the YUV buffer as