This is the reproducible developer procedure for the experimental
CNA_GRAPHICS_RENDERER=SKIA CPU-raster 2D renderer. The commands describe the only implemented Skia
execution mode. They do not build or silently select Ganesh, Graphite, OpenGL, Vulkan, Metal, or
Dawn. Read skia-renderer.md for the verified feature boundary before treating a
successful build as a capability claim.
The validated host shape is Linux x86-64, a GNU or Clang C++23 CNA build, Ninja, and ELF static linking against a Clang-built upstream Skia artifact. Ordinary CNA configuration is offline: CMake never downloads or rebuilds Skia. The source checkout and matching GN output are explicit inputs.
The Skia revision is exactly:
ebf50520d720a1ce9d842d942d04c6c39c3fbc7b
The current adapter requires these six files in one GN output directory:
libskia.a
libskcms.a
liballocator_base.a
liballocator_core.a
liballocator_shim.a
libraw_ptr.a
CMake rejects a missing source header or any missing archive. Do not point the source option at one Skia revision and the build option at another.
On Debian/Ubuntu, install the build/test tools and CNA's required FFmpeg development packages:
sudo apt-get update
sudo apt-get install -y \
git cmake ninja-build build-essential clang python3 pkg-config xvfb xauth libgl1-mesa-dri \
libavcodec-dev libavformat-dev libavutil-dev libswresample-devThe default CNA build compiles SDL3, SDL3_image, and SDL3_mixer from the repository submodules.
Optional SDL features may need additional packages listed in third_party/SDL/docs/README-linux.md,
but they are not part of the Skia adapter contract.
sharp-runtime is a separate sibling checkout rather than a submodule. Starting from the directory
that will contain both projects:
git clone https://github.com/openeggbert/sharp-runtime.git
git clone https://github.com/openeggbert/cna.git cnaskia
cd cnaskia
git submodule update --initAn existing CNA checkout only needs the last command and a ../sharp-runtime/CMakeLists.txt.
Choose absolute paths outside the CNA source tree. These task-specific variables are used by the remaining commands:
export CNA_SKIA_SRC=/absolute/path/to/skia
export CNA_SKIA_OUT=/absolute/path/to/skia-out/raster
export CMAKE_BUILD_PARALLEL_LEVEL=3The CMake environment limit also applies to the one-time vendored SDL builds that occur during the
first CNA configure; their internal cmake --build --parallel command would otherwise use the
native tool's unrestricted default.
Clone, detach at the pinned revision, fetch GN, generate the exact raster configuration, and build with at most three workers (this repository's own build-hygiene rule; see /rv/data/development/github.com/openeggbert/CLAUDE.md):
git clone https://skia.googlesource.com/skia.git "$CNA_SKIA_SRC"
git -C "$CNA_SKIA_SRC" checkout --detach ebf50520d720a1ce9d842d942d04c6c39c3fbc7b
"$CNA_SKIA_SRC/bin/fetch-gn"
"$CNA_SKIA_SRC/bin/gn" gen "$CNA_SKIA_OUT" --args='is_official_build=true is_debug=false cc="clang" cxx="clang++" skia_use_gl=false skia_enable_ganesh=false skia_use_vulkan=false skia_use_dawn=false skia_enable_graphite=false skia_enable_pdf=false skia_use_freetype=false skia_use_fontconfig=false skia_use_libpng_decode=false skia_use_libjpeg_turbo_decode=false skia_use_libwebp_decode=false skia_use_wuffs=false skia_use_icu=false skia_enable_tools=false'
ninja -C "$CNA_SKIA_OUT" -j3 skiaVerify the revision and complete archive set before configuring CNA:
test "$(git -C "$CNA_SKIA_SRC" rev-parse HEAD)" = \
ebf50520d720a1ce9d842d942d04c6c39c3fbc7b
for CNA_SKIA_ARCHIVE in \
libskia.a libskcms.a liballocator_base.a liballocator_core.a \
liballocator_shim.a libraw_ptr.a
do
test -f "$CNA_SKIA_OUT/$CNA_SKIA_ARCHIVE"
doneis_official_build=true produces the no-RTTI upstream ABI used by the validated archives. CNA's
sanitizer integration accounts for that boundary; do not change the GN ABI flags independently and
reuse the same output directory.
From the CNA repository root:
cmake -S . -B build-skia -G Ninja \
-DCMAKE_BUILD_TYPE=Debug \
-DCNA_GRAPHICS_RENDERER=SKIA \
-DCNA_SKIA_ROOT="$CNA_SKIA_SRC" \
-DCNA_SKIA_BUILD_DIR="$CNA_SKIA_OUT" \
-DCNA_BUILD_TESTS=ON \
-DCNA_BUILD_EXAMPLES=ON \
-DCNA_USE_CCACHE=OFF \
-DCNA_TEST_DISPLAY=:0
cmake --build build-skia --parallel 3Expected configure output includes CNA: Using SKIA raster graphics renderer. It must not mention
an EasyGL fallback. Wait for the build command to finish before starting CTest; a partially linked
executable is not a valid test artifact.
The suite is split by execution requirement:
Audit: display-free source/plan consistency;Raster: display-free Skia surface and feasibility tests;Display: SDL/X11 presentation and public pixel tests;Accelerated: reserved for a future real Skia GPU mode and currently empty.
The display-free gate works directly:
ctest --test-dir build-skia -L 'Audit|Raster' --parallel 3 --output-on-failureOn a headless Linux host, bake Xvfb's actual display number into the CTest environment and run all Skia labels in the same shell:
xvfb-run -a bash -c '
set -e
cmake -S . -B build-skia -DCNA_TEST_DISPLAY="$DISPLAY"
ctest --test-dir build-skia -L Skia --parallel 3 --output-on-failure
'On a real X11 desktop, configure the build with that session's display and run the same label:
cmake -S . -B build-skia -DCNA_TEST_DISPLAY="$DISPLAY"
ctest --test-dir build-skia -L Skia --parallel 3 --output-on-failureIf this is a persistent developer build, restore its conventional display after an Xvfb run:
cmake -S . -B build-skia -DCNA_TEST_DISPLAY=:0The exact test count can grow. At the SKIA-112 checkpoint the expected inventory is 132 tests: 16 Raster, 113 Display, and three Audit. This command must report zero tests until an accelerated Skia implementation is intentionally added:
ctest --test-dir build-skia -N -L AcceleratedUse the real display selected during configuration, or run through Xvfb for a three-frame smoke:
DISPLAY=:0 SDL_VIDEODRIVER=x11 CNA_SKIA_STATE_TRACE=1 \
cmake -E chdir build-skia ./cna_demo_2d
xvfb-run -a env SDL_VIDEODRIVER=x11 CNA_SKIA_STATE_TRACE=1 \
cmake -E chdir build-skia ./cna_demo_2d --smoke 3The working-directory change is required because the post-build step copies the demo's relative
Content/ tree next to the executable.
Every constructed renderer prints one immutable startup line containing the pinned revision,
surface=raster, colour=RGBA_8888/premultiplied, samples=0, and
anisotropic filtering=unsupported. CNA_SKIA_STATE_TRACE=1 additionally prints target identity,
size, blend, sampler, and scissor transitions; unset it (or set it to 0) for normal runs.
For ownership diagnostics that should exclude the host GLX presenter, use SDL's dummy/software
presentation path on a display-independent fixture, as documented in
skia-sanitizer-validation.md. The same document gives the
ASan+UBSan configure command and explains the narrow no-RTTI vptr exception.
This is not the release-gated configuration -- see
Accelerated prerequisites and raster fallback policy
below and skia-ganesh-artifact.md for the full contract. It exists to
build and exercise SkiaGaneshContext/SkiaGaneshSurface and their Skia_Ganesh_* tests; it does
not wire a presentable Ganesh backbuffer into SkiaRenderer/IGraphicsRenderer itself.
First build the separately pinned Ganesh GN artifact, reusing the exact same $CNA_SKIA_SRC
checkout from step 2 above (never re-clone Skia for this):
export CNA_SKIA_GANESH_OUT=/absolute/path/to/skia-out/ganesh
"$CNA_SKIA_SRC/bin/gn" gen "$CNA_SKIA_GANESH_OUT" --args='is_official_build=true is_debug=false cc="clang" cxx="clang++" skia_use_gl=true skia_enable_ganesh=true skia_use_vulkan=false skia_use_dawn=false skia_enable_graphite=false skia_enable_pdf=false skia_use_freetype=false skia_use_fontconfig=false skia_use_libpng_decode=false skia_use_libjpeg_turbo_decode=false skia_use_libwebp_decode=false skia_use_wuffs=false skia_use_icu=false skia_enable_tools=false'
ninja -C "$CNA_SKIA_GANESH_OUT" -j3 skiaThen configure a new, stable, reusable build directory -- cmake-build-skia-ganesh, following this
project's own cmake-build-<variant>/ convention, not a per-ticket one-off:
cmake -S . -B cmake-build-skia-ganesh -G Ninja \
-DCMAKE_BUILD_TYPE=Debug \
-DCNA_GRAPHICS_RENDERER=SKIA \
-DCNA_SKIA_MODE=GANESH \
-DCNA_SKIA_ROOT="$CNA_SKIA_SRC" \
-DCNA_SKIA_GANESH_BUILD_DIR="$CNA_SKIA_GANESH_OUT" \
-DCNA_BUILD_TESTS=ON \
-DCNA_BUILD_EXAMPLES=ON \
-DCNA_USE_CCACHE=ON \
-DCNA_TEST_DISPLAY=:99
cmake --build cmake-build-skia-ganesh -j3Expected configure output includes CNA: Using SKIA renderer in Ganesh/OpenGL mode (experimental, SKIA-159-161), distinct from step 3's CNA: Using SKIA raster graphics renderer. Unlike this
section's own earlier revision, -DCNA_TEST_DISPLAY does not need to be a real desktop display:
confirmed directly (SKIA-161) that Xvfb (:99/:101, the same displays step 4 already uses for the
raster suite) provides a real, if software-only (Mesa llvmpipe), GLX implementation, sufficient for
every Ganesh correctness check this renderer has -- prefer the existing Xvfb displays for this reason
(and to avoid disturbing a real desktop session); a real display also works if that is what is
available. Skia_Ganesh_ModeConstruction/Skia_Ganesh_Backbuffer and the 170+ raster-labeled tests
already present in this same build directory all run identically either way.
ctest --test-dir cmake-build-skia-ganesh -L Accelerated --output-on-failureFor ASan+UBSan coverage of the Ganesh path, configure a second stable directory the same way as
step 3's cmake-build-skia-asan, adding the same CNA_SKIA_MODE/CNA_SKIA_GANESH_BUILD_DIR
options as above:
cmake -S . -B cmake-build-skia-ganesh-asan -G Ninja \
-DCMAKE_BUILD_TYPE=Debug \
-DCNA_GRAPHICS_RENDERER=SKIA \
-DCNA_SKIA_MODE=GANESH \
-DCNA_SKIA_ROOT="$CNA_SKIA_SRC" \
-DCNA_SKIA_GANESH_BUILD_DIR="$CNA_SKIA_GANESH_OUT" \
-DCNA_BUILD_TESTS=ON \
-DCNA_BUILD_EXAMPLES=ON \
-DCNA_USE_CCACHE=ON \
-DCNA_SANITIZE=address,undefined \
-DCNA_TEST_DISPLAY=:99
cmake --build cmake-build-skia-ganesh-asan -j3
ASAN_OPTIONS=detect_leaks=0:halt_on_error=1 UBSAN_OPTIONS=halt_on_error=1:print_stacktrace=1 \
ctest --test-dir cmake-build-skia-ganesh-asan -R '^Skia_' --output-on-failureThe detect_leaks=0 matches skia-sanitizer-validation.md's
already-documented host libGLX_mesa.so.0 residual baseline -- not specific to Ganesh mode, the
same real GLX presenter every Display-labeled Skia test already opens in any build.
There is no accelerated Skia binary or runtime fallback wired into SkiaRenderer (the real
IGraphicsRenderer implementation) in this revision. The default CNA_SKIA_MODE=RASTER build's
pinned GN arguments disable every Skia GPU API, and SKIA construction always selects raster
regardless of what else is built. SDL may use a GPU only to upload/present the completed CPU image;
that does not change the Skia execution mode.
A separate, independently pinned Ganesh/OpenGL GN artifact and CMake target (CNA::SkiaGanesh,
SKIA-159) exist, selectable at CMake configure time via -DCNA_SKIA_MODE=GANESH (SKIA-160,
skia-ganesh-artifact.md), and a real, testable
SkiaGaneshContext proves a genuine GrDirectContext constructs (or fails transactionally) in that
mode. Neither is wired into SkiaRenderer itself, though -- there is still no presentable
Ganesh backbuffer, and ordinary CNA_GRAPHICS_RENDERER=SKIA builds default to RASTER and are
completely unaffected.
The accepted skia-surface-mode-adr.md selects raster for this release
and names Ganesh/OpenGL only as the first future candidate. Any successor accelerated plan must
reopen the SKIA-6 proof rather than treating its conditional current-release closure as GPU
evidence. Before such a path can be built or advertised it needs, at minimum:
- a separately named pinned GN artifact with the selected GPU API enabled, plus construction-time
mode selection and a mode-specific startup diagnostic (done -- SKIA-159/160;
CNA::SkiaGanesh,CNA_SKIA_MODE,SkiaGaneshContext); - explicit SDL/native context or device ownership and framebuffer/surface interop;
- a tested device-loss/reset and fallback contract; and
- the CPU/GPU parity corpus listed in
skia-verification-boundary.md.
Until those gates close, missing Skia headers/archives or presenter construction is a hard error, not permission to switch implementation. To choose a deliberate non-Skia fallback, use a separate build directory, for example:
cmake -S . -B build-sdl-renderer -G Ninja \
-DCNA_GRAPHICS_RENDERER=SDL_RENDERER \
-DCNA_BUILD_TESTS=ON
cmake --build build-sdl-renderer --parallel 3Never reuse one CMake build directory while comparing renderer selections.
| Symptom | Cause | Correction |
|---|---|---|
SKIA requires -DCNA_SKIA_ROOT=... |
Header root is unset or does not contain include/core/SkSurface.h. |
Pass the absolute pinned source checkout. |
SKIA requires -DCNA_SKIA_BUILD_DIR=... |
GN output is unset or lacks libskia.a. |
Pass the exact raster output directory, not its parent. |
build directory is incomplete; missing ... |
One of the six static archives was not produced or paths mix revisions. | Re-run the exact GN/Ninja commands and the archive loop above. |
| Link errors involving PartitionAlloc/SkSL | Incompatible Skia arguments/revision or archives copied incompletely. | Rebuild all six archives together; let CNA::Skia retain their CMake link group. |
Link errors containing typeinfo for SkCanvas under UBSan |
A no-RTTI Skia boundary was instrumented with vptr outside CNA's supported sanitizer targets. |
Use -DCNA_SANITIZE=address,undefined; CNA disables only vptr on the adapter/fixtures. |
| Display tests cannot open X11 | CNA_TEST_DISPLAY was configured for a different server. |
Reconfigure inside xvfb-run or with the real session's $DISPLAY, then rerun CTest. |
permission denied while CTest starts a just-built executable |
CTest was started before Ninja completed replacement/linking of all selected targets. | Let cmake --build return successfully, then rerun the test. |
Windowed LSan reports allocations rooted in libGLX_mesa.so.0 |
Known host presenter baseline, not automatically a CNA/Skia leak. | Compare the one-presenter control and dummy/software isolation exactly as in the sanitizer report; do not add a broad suppression. |