Add examples/gbm-egl-benchmark.c, a headless benchmark that compares
the display-path cost of uploading Cairo-rendered content to a GL
texture via two methods:
Image surface: glTexSubImage2D (CPU → GPU memcpy)
GBM surface: EGL DMA-BUF import (zero-copy)
The benchmark renders an animated Cairo scene at the requested
resolution, then measures only the upload/import step per frame.
It runs entirely on a DRM render node with no window system required.
Typical results on AMD Radeon RX 580:
1080p (7.9 MB/frame): ~24x faster with GBM (1.42 ms → 0.06 ms)
4K (31.6 MB/frame): ~80x faster with GBM (5.18 ms → 0.07 ms)
Built automatically when gbm, egl, and glesv2 are all available.
Add a new surface backend that allocates pixel buffers through GBM
(Generic Buffer Manager), allowing Cairo-rendered content to be
imported directly by GPU compositors via DMA-BUF file descriptors
without an intermediate memory copy.
The backend renders on the CPU via pixman (like the image backend)
but allocates its buffer through GBM with a linear modifier, making
it suitable for zero-copy handoff to GPU-based compositors such as
Mutter/Clutter (GNOME) or GSK (GTK 4).
New public API (cairo-gbm.h):
- cairo_gbm_surface_create() — allocate a new GBM-backed surface
- cairo_gbm_surface_create_for_bo() — wrap an existing gbm_bo
- cairo_gbm_surface_get_bo() — retrieve the underlying gbm_bo
- cairo_gbm_surface_get_dma_buf_fd() — export a DMA-BUF fd for the buffer
Build integration:
- New 'gbm' meson option (auto-detected via libgbm + libdrm)
- CAIRO_HAS_GBM_SURFACE feature flag
Test coverage:
- Dedicated API + error-path tests (test/gbm-surface.c)
- Surface-as-source pattern test (test/gbm-surface-source.c)
- GBM boilerplate target for the full test suite
- Entries in api-special-cases.c and error-setters.c
Make sure surface->object_stream.stream is cleaned up even if things
failed
In poppler oss-fuzz tests we are getting this leak reported
Direct leak of 64 byte(s) in 1 object(s) allocated from:
#0 0x5747417eabd9 in __interceptor_calloc /src/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:74:3
#1 0x574742706f5b in _cairo_memory_stream_create cairo/src/cairo-output-stream.c:741:14
#2 0x5747426757b8 in _cairo_pdf_surface_open_object_stream cairo/src/cairo-pdf-surface.c:2307:34
#3 0x57474266b880 in _cairo_pdf_surface_finish cairo/src/cairo-pdf-surface.c:2700:14
#4 0x57474261afc6 in _cairo_surface_finish cairo/src/cairo-surface.c:1043:11
#5 0x57474261afc6 in cairo_surface_finish cairo/src/cairo-surface.c:1092:5
#6 0x57474270808a in _cairo_paginated_surface_finish cairo/src/cairo-paginated-surface.c:215:2
#7 0x5747426175c2 in _cairo_surface_finish cairo/src/cairo-surface.c:1043:11
#8 0x5747426175c2 in cairo_surface_destroy cairo/src/cairo-surface.c:978:2
This fixes it.
_cairo_pdf_surface_finish was succeeding past
_cairo_pdf_surface_open_object_stream that allocates surface->object_stream.stream,
failing when calling _cairo_pdf_surface_emit_font_subsets
and that memory was never freed
Otherwise gitlab-runner prints a few warnings:
> Uploading artifacts...
> WARNING: Part of .git directory is on the list of files to archive
> WARNING: This may introduce unexpected problems
Both system() and popen() invoke the shell. Which shell is
invoked depends on the COMSPEC environment variable, but
usually it's CMD.exe.
CMD.exe doesn't quite like paths with forward slashes in its
command-line. Most of the times, the forward slash is mistaken
for a command line switch (the start of an option). For example:
cmd /c "dir C:\Windows" works
cmd /c "dir C:/Windows" doesn't work
Open the pipe in binary mode on Windows to get the expected
byte counts. Note that the 'b' mode for popen is not portable
and so is used only on Windows:
> The behavior of popen() is specified for values of mode of "r",
> "w", "re", and "we". Other modes such as "rb" and "wb" might be
> supported by specific implementations, but these would not be
> portable features.
https://pubs.opengroup.org/onlinepubs/9799919799/functions/popen.html
We now require at least Windows Vista. When dwrite is disabled, declare
WINVER accordingly so we get the defines we no longer carry ourselves.
The default dwrite-enabled path already has a new-enough WINVER.
Fixes: d0ee67a142 ("Win32: Remove unused code and defines for old toolchains")
If the import libraries are found, we can assume that headers are present
as well. All three headers were introduced many years ago in the Windows
SDK and mingw-w64 headers.