Files
ivi-homescreen/cmake/drm_kms.cmake
T
Joel Winarske ec9cff4535 Add DRM/KMS Vulkan backend
Add a BUILD_BACKEND_DRM_KMS_VULKAN backend that drives the Flutter Vulkan
renderer for hardware KMS scanout, alongside the existing DRM/KMS EGL
backend.

At init the backend probes for zero-copy dma-buf scanout: a non-CPU
Vulkan device exposing VK_EXT_image_drm_format_modifier,
VK_EXT_external_memory_dma_buf, VK_KHR_external_memory_fd and
VK_EXT_queue_family_foreign, plus an openable DRM display node. When
those do not hold it refuses at init with a clear diagnostic instead of
failing later inside framebuffer import. Vulkan is resolved at runtime
through vulkan.hpp's dynamic dispatcher, so the binary links no EGL, GL,
Wayland or Vulkan loader library. The DRM session, display, seat and
cursor code is shared with the EGL backend. The backend probes and
refuses cleanly; it does not present frames yet.

To keep this and the software build free of EGL and Wayland, scope the
shared config header and the waypp subproject to the backends that use
them: config/common.h includes <EGL/egl.h> and the EGL config arrays
only for the EGL backends, and <waypp/waypp.h> only for the Wayland and
headless backends; waypp is built only for those backends.
platform_homescreen now takes the generated-config include directory
directly rather than inheriting it from wayland-gen. What the EGL,
software and Wayland builds link is unchanged.

Also:
- add the Backend::Type::DrmKmsVulkan enumerator and wire the backend
  through the backend-selection sites and the build
- add a BUILD_VULKAN_VALIDATION option
- add a drm_kms_vulkan_probe tool that reports the capability-gate
  result (exit 0 pass, 1 refuse)
- correct the sync note in scene_layer_source_vk.h: the embedder exposes
  no per-image render-complete fence, so producer/consumer synchronization
  is an open question rather than a settled one

Signed-off-by: Joel Winarske <joel.winarske@gmail.com>
2026-06-02 17:19:15 -07:00

103 lines
4.8 KiB
CMake

#
# DRM/KMS backend build wiring.
#
# drm-cxx is consumed as a git submodule under third_party/drm-cxx and built
# in-tree via add_subdirectory. System deps (libdrm, gbm, libinput, libudev)
# are resolved through pkg-config.
#
if (NOT BUILD_BACKEND_DRM_KMS_EGL AND NOT BUILD_BACKEND_DRM_KMS_VULKAN)
return()
endif ()
find_package(PkgConfig REQUIRED)
pkg_check_modules(DRM REQUIRED IMPORTED_TARGET libdrm)
pkg_check_modules(GBM REQUIRED IMPORTED_TARGET gbm)
pkg_check_modules(LIBINPUT REQUIRED IMPORTED_TARGET libinput)
pkg_check_modules(UDEV REQUIRED IMPORTED_TARGET libudev)
set(_drm_cxx_src "${CMAKE_SOURCE_DIR}/third_party/drm-cxx")
if (NOT EXISTS "${_drm_cxx_src}/CMakeLists.txt")
message(FATAL_ERROR
"third_party/drm-cxx/CMakeLists.txt is missing. Run:\n"
" git submodule update --init --recursive third_party/drm-cxx")
endif ()
# Suppress drm-cxx's tests, examples, install rules, and Vulkan display
# support. ivi-homescreen owns the integration test surface; drm-cxx's
# Vulkan path is orthogonal to the GL renderer this backend drives.
set(DRM_CXX_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(DRM_CXX_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
set(DRM_CXX_BUILD_BENCHMARKS OFF CACHE BOOL "" FORCE)
set(DRM_CXX_INSTALL OFF CACHE BOOL "" FORCE)
set(DRM_CXX_VULKAN OFF CACHE BOOL "" FORCE)
# Force-on the drm-cxx modules ivi-homescreen UNCONDITIONALLY depends on,
# so a missing system dep fails the configure step here rather than
# silently auto-disabling the module and producing a binary that crashes
# at first use. Today only DRM_CXX_SESSION qualifies: drm::session::Seat
# is consumed unconditionally in backend/drm_kms_egl/drm_session.cc.
set(DRM_CXX_SESSION ON CACHE BOOL "" FORCE)
# Leave AUTO (don't FORCE) on the drm-cxx modules whose ivi-homescreen
# consumers are themselves gated on the same system dep — shell/CMakeLists
# .txt probes libxcursor (gates drm_cursor.cc + sets HAVE_DRM_CURSOR=1) and
# blend2d (gates drm_capture.cc + sets HAVE_DRM_CAPTURE=1), silently
# dropping the source file when the dep is absent. Mirroring AUTO here
# matches that optionality: drm-cxx's cursor + capture modules build when
# libxcursor + blend2d are present, silently drop out together when not.
# Forcing ON here would break the configure for environments that don't
# have libxcursor / blend2d available (CI runners without libblend2d-dev,
# minimal embedded targets that don't want either feature).
# Force-off the optional drm-cxx modules ivi-homescreen does NOT use, so
# we don't transitively pull in their deps (e.g. csd needs Blend2D
# independently of capture; gstreamer support pulls in GStreamer dev
# packages we don't need on the DRM path; streams is a Tegra/L4T-only
# concern). Flip these to ON if/when a feature lands that consumes them.
set(DRM_CXX_CSD OFF CACHE BOOL "" FORCE)
set(DRM_CXX_GSTREAMER OFF CACHE BOOL "" FORCE)
set(DRM_CXX_STREAMS OFF CACHE BOOL "" FORCE)
# CMP0079 NEW lets us attach link libraries to a target created in a
# different directory (drm-cxx's own CMakeLists, processed below).
cmake_policy(SET CMP0079 NEW)
add_subdirectory(${_drm_cxx_src} ${CMAKE_BINARY_DIR}/third_party/drm-cxx EXCLUDE_FROM_ALL)
# Treat drm-cxx as a system library (vendored submodule we keep pristine):
# mark its interface headers SYSTEM so they're -isystem for consumers, and
# silence its own-source warnings (-Wsign-conversion, -Wc++20-extensions, …).
if (TARGET drm-cxx)
get_target_property(_drmcxx_inc drm-cxx INTERFACE_INCLUDE_DIRECTORIES)
if (_drmcxx_inc)
set_target_properties(drm-cxx PROPERTIES
INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${_drmcxx_inc}")
endif ()
target_compile_options(drm-cxx PRIVATE -w)
endif ()
# drm-cxx is built as a sub-project and doesn't automatically inherit the
# `toolchain` INTERFACE library that applies `-stdlib=libc++` on clang
# builds. Without this, drm-cxx compiles against libstdc++ and the main
# ivi-homescreen binary (libc++) fails to link its STL symbols.
if (TARGET toolchain)
target_link_libraries(drm-cxx PRIVATE toolchain::toolchain)
# drm-cxx transitively pulls in fmt via FetchContent when the toolchain
# lacks std::print. fmt builds with the default compiler stdlib
# (libstdc++), so its objects won't satisfy the libc++ symbols the main
# binary needs. Attaching `toolchain` as a link dep would drag it into
# fmt's install EXPORT set — fmt forces FMT_INSTALL=ON — so copy just
# the compile/link flags instead, leaving fmt's export set untouched.
if (TARGET fmt)
get_target_property(_tc_copts toolchain INTERFACE_COMPILE_OPTIONS)
get_target_property(_tc_lopts toolchain INTERFACE_LINK_OPTIONS)
if (_tc_copts)
target_compile_options(fmt PRIVATE ${_tc_copts})
endif ()
if (_tc_lopts)
target_link_options(fmt PRIVATE ${_tc_lopts})
endif ()
endif ()
endif ()