Skip to content
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
1db2685
refactor: extract platform-neutral view-abstraction base
cedrik-fuoco-adsk Jun 9, 2026
8c71bf5
feat(linux): add 10-bit Vulkan presentation backend
cedrik-fuoco-adsk Jun 9, 2026
c3d083e
pre-commit
cedrik-fuoco-adsk Jun 15, 2026
9bec27a
refactor: streamline view handling in RvDocument
cedrik-fuoco-adsk Jun 17, 2026
b38677c
feat(vulkan): introduce QTVulkanVideoDevice for GL-to-Vulkan interop
cedrik-fuoco-adsk Jun 17, 2026
8ad4f1b
fix(vulkan): enhance error handling and format validation in VulkanVi…
cedrik-fuoco-adsk Jun 19, 2026
558b628
–feat(vulkan): enhance Vulkan support for Windows and Linux
cedrik-fuoco-adsk Jun 26, 2026
d1dec5c
feat(vulkan): implement Vulkan to OpenGL fallback mechanism
cedrik-fuoco-adsk Jun 29, 2026
5af110c
–- Added detailed logging for GPU-related operations, providing bette…
cedrik-fuoco-adsk Jun 29, 2026
eab360c
pre commit
cedrik-fuoco-adsk Jun 29, 2026
4fc864b
windows build issue in debug
cedrik-fuoco-adsk Jun 30, 2026
907605c
Merge branch 'main' into vulkna-10bit-windows
cedrik-fuoco-adsk Jun 30, 2026
a44e303
feat(vulkan): introduce QTVulkanVideoDevice for GL-to-Vulkan bridging
cedrik-fuoco-adsk Jul 3, 2026
ef5d73d
On Linux and Windows, RV delivers the final 10-bit frame through a Vu…
cedrik-fuoco-adsk Jul 6, 2026
0be0c50
pre-commit
cedrik-fuoco-adsk Jul 6, 2026
d92df96
Bernard Laberge fixes for Nvidia adapted with my refactor
cedrik-fuoco-adsk Jul 6, 2026
095c13b
feat(vulkan): implement CPU fallback for Vulkan presentation
cedrik-fuoco-adsk Jul 6, 2026
6aa9dc3
remove redundant virtual and add curly braces
cedrik-fuoco-adsk Jul 17, 2026
06a3686
Merge branch 'main' into vulkna-10bit-windows
cedrik-fuoco-adsk Jul 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions cmake/defaults/CYCOMMON.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,21 @@ SET(RV_DEPS_GLEW_VERSION_LIB
"2.3.1"
)

# vulkan https://github.com/KhronosGroup/Vulkan-Headers + https://github.com/KhronosGroup/Vulkan-Loader
SET(RV_DEPS_VULKAN_VERSION
"1.4.350.0"
)
SET(RV_DEPS_VULKAN_HEADERS_DOWNLOAD_HASH
"74d68465ca2ef442397dc159edaa3b9c"
)
SET(RV_DEPS_VULKAN_LOADER_DOWNLOAD_HASH
"6ec91c673b48bbdffc923cce9d6a1a85"
)
# libvulkan.so SONAME major (libvulkan.so.1)
SET(RV_DEPS_VULKAN_VERSION_LIB
"1"
)

# imgui https://github.com/pthom/imgui
#
# Note this also depends on the following repositories: https://github.com/pthom/implot.git https://github.com/dpaulat/imgui-backend-qt.git
Expand Down
12 changes: 12 additions & 0 deletions cmake/dependencies/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,13 @@ IF(RV_TARGET_DARWIN
INCLUDE(gc)
INCLUDE(glew)
ENDIF()
# Vulkan (headers + loader) is fetched on Linux and Windows for the 10-bit presentation backend. On Linux the loader is libvulkan.so; on Windows it is
# vulkan-1.dll plus its import library.
IF(RV_TARGET_LINUX
OR RV_TARGET_WINDOWS
)
INCLUDE(vulkan)
ENDIF()
INCLUDE(imath)
INCLUDE(zlib)
INCLUDE(ffmpeg)
Expand Down Expand Up @@ -163,6 +170,11 @@ IF(RV_TARGET_DARWIN
MESSAGE(STATUS "Using GC: ${RV_DEPS_GC_VERSION}")
MESSAGE(STATUS "Using GLEW: ${RV_DEPS_GLEW_VERSION}")
ENDIF()
IF(RV_TARGET_LINUX
OR RV_TARGET_WINDOWS
)
MESSAGE(STATUS "Using Vulkan: ${RV_DEPS_VULKAN_VERSION}")
ENDIF()
MESSAGE(STATUS "Using Imath: ${RV_DEPS_IMATH_VERSION}")
MESSAGE(STATUS "Using JpegTurbo: ${RV_DEPS_JPEGTURBO_VERSION}")
MESSAGE(STATUS "Using OpenEXR: ${RV_DEPS_OPENEXR_VERSION}")
Expand Down
144 changes: 144 additions & 0 deletions cmake/dependencies/build/vulkan.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
#
# Copyright (C) 2026 Autodesk, Inc. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
# Build Vulkan-Headers (header-only install) + Vulkan-Loader (libvulkan.so / vulkan-1.dll) from hash-pinned Khronos GitHub tarballs. Both install into the
# shared ${_install_dir}. Included by cmake/dependencies/vulkan.cmake when no system Vulkan package is found.
#
# Expects these variables from the caller (set by RV_CREATE_STANDARD_DEPS_VARIABLES): _target, _version, _install_dir, _include_dir, _lib_dir, _bin_dir. And
# these dep-specific variables: _vulkan_lib, _vulkan_lib_name (and on Windows, _vulkan_implib, _vulkan_implib_name).
#
# The loader ships pre-generated sources and gates its Python codegen behind LOADER_CODEGEN (default OFF), so no Python is required at build time. It does
# require the Vulkan-Headers CMake package (find_package(VulkanHeaders CONFIG)), provided via CMAKE_PREFIX_PATH below.

SET(_headers_url
"https://github.com/KhronosGroup/Vulkan-Headers/archive/refs/tags/vulkan-sdk-${_version}.tar.gz"
)
SET(_loader_url
"https://github.com/KhronosGroup/Vulkan-Loader/archive/refs/tags/vulkan-sdk-${_version}.tar.gz"
)

# --- Vulkan-Headers: installs headers + the VulkanHeaders CMake config + the registry. ---
EXTERNALPROJECT_ADD(
${_target}_headers
URL ${_headers_url}
URL_MD5 ${RV_DEPS_VULKAN_HEADERS_DOWNLOAD_HASH}
DOWNLOAD_NAME vulkan-headers-${_version}.tar.gz
DOWNLOAD_DIR ${RV_DEPS_DOWNLOAD_DIR}
SOURCE_DIR ${RV_DEPS_BASE_DIR}/${_target}/headers-src
BINARY_DIR ${RV_DEPS_BASE_DIR}/${_target}/headers-build
INSTALL_DIR ${_install_dir}
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${_install_dir} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DVULKAN_HEADERS_ENABLE_MODULE=OFF -DVULKAN_HEADERS_ENABLE_TESTS=OFF
BUILD_ALWAYS FALSE
USES_TERMINAL_BUILD TRUE
)

# --- Vulkan-Loader: builds libvulkan.so / vulkan-1.dll against the installed headers. ---
# Linux WSI: enable Xlib/XCB (RV is an X11 client); leave Wayland off to avoid a wayland-client build dependency. Windows WSI: Vulkan-Loader defaults to WIN32
# WSI on WIN32 -- no explicit flags needed.
IF(RV_TARGET_WINDOWS)
SET(_vulkan_wsi_args
""
)
ELSE()
SET(_vulkan_wsi_args
-DBUILD_WSI_XLIB_SUPPORT=ON -DBUILD_WSI_XCB_SUPPORT=ON -DBUILD_WSI_WAYLAND_SUPPORT=OFF -DBUILD_WSI_XLIB_XRANDR_SUPPORT=OFF
)
ENDIF()

# Windows also emits the .lib import library; declare it as a byproduct so downstream link steps that depend on ${_vulkan_implib} don't race the build.
SET(_vulkan_byproducts
${_vulkan_lib}
)
IF(RV_TARGET_WINDOWS)
LIST(APPEND _vulkan_byproducts ${_vulkan_implib})
ENDIF()

EXTERNALPROJECT_ADD(
${_target}
DEPENDS ${_target}_headers
URL ${_loader_url}
URL_MD5 ${RV_DEPS_VULKAN_LOADER_DOWNLOAD_HASH}
DOWNLOAD_NAME vulkan-loader-${_version}.tar.gz
DOWNLOAD_DIR ${RV_DEPS_DOWNLOAD_DIR}
SOURCE_DIR ${RV_DEPS_BASE_DIR}/${_target}/loader-src
BINARY_DIR ${RV_DEPS_BASE_DIR}/${_target}/loader-build
INSTALL_DIR ${_install_dir}
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${_install_dir}
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DCMAKE_INSTALL_LIBDIR=lib
-DCMAKE_PREFIX_PATH=${_install_dir}
-DVULKAN_HEADERS_INSTALL_DIR=${_install_dir}
-DBUILD_TESTS=OFF
${_vulkan_wsi_args}
BUILD_BYPRODUCTS ${_vulkan_byproducts}
BUILD_ALWAYS FALSE
USES_TERMINAL_BUILD TRUE
)

IF(TARGET Vulkan::Vulkan)
# Qt's find_package(Qt6 Gui) -> WrapVulkanHeaders ran find_package(Vulkan) before us and created a global Vulkan::Vulkan pointing at the system loader. We
# can't redefine it (ADD_LIBRARY would error), so repoint it at our fetched build instead. This is invisible to Qt: it consumes only the Vulkan headers (via
# WrapVulkanHeaders) and dlopen()s the loader at runtime -- it never links Vulkan::Vulkan's IMPORTED_LOCATION.
MESSAGE(STATUS "Repointing existing Vulkan::Vulkan target at managed Vulkan ${_version}")
ADD_DEPENDENCIES(Vulkan::Vulkan ${_target})
FILE(MAKE_DIRECTORY ${_include_dir})
# On Windows, the target Qt creates via CMake's built-in FindVulkan is UNKNOWN IMPORTED. For that type the linker is fed IMPORTED_LOCATION directly and
# IMPORTED_IMPLIB is ignored -- so IMPORTED_LOCATION must be the .lib import library, not the .dll (otherwise LNK1107 "invalid or corrupt file"). We can't
# change a target's type after it's created, so detect the type and set properties accordingly.
GET_TARGET_PROPERTY(_vulkan_target_type Vulkan::Vulkan TYPE)
IF(RV_TARGET_WINDOWS
AND _vulkan_target_type STREQUAL "UNKNOWN_LIBRARY"
)
SET_TARGET_PROPERTIES(
Vulkan::Vulkan
PROPERTIES IMPORTED_LOCATION ${_vulkan_implib}
INTERFACE_INCLUDE_DIRECTORIES ${_include_dir}
)
ELSE()
SET_TARGET_PROPERTIES(
Vulkan::Vulkan
PROPERTIES IMPORTED_LOCATION ${_vulkan_lib}
IMPORTED_SONAME ${_vulkan_lib_name}
INTERFACE_INCLUDE_DIRECTORIES ${_include_dir}
)
IF(RV_TARGET_WINDOWS)
SET_PROPERTY(
TARGET Vulkan::Vulkan
PROPERTY IMPORTED_IMPLIB ${_vulkan_implib}
)
ENDIF()
ENDIF()
# Qt's find_package(Qt6 Gui) -> WrapVulkanHeaders created WrapVulkanHeaders::WrapVulkanHeaders pointing at the system Vulkan SDK include dir, and Qt6::Gui
# links it publicly. Overwrite its include dir with our managed headers so every consumer of Qt::Gui compiles against the managed Vulkan, not the system SDK.
# SET (not target_include_directories) to replace, not append, the system path.
IF(TARGET WrapVulkanHeaders::WrapVulkanHeaders)
MESSAGE(STATUS "Repointing WrapVulkanHeaders at managed Vulkan ${_version}")
SET_TARGET_PROPERTIES(
WrapVulkanHeaders::WrapVulkanHeaders
PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${_include_dir}
)
ENDIF()
SET(RV_DEPS_LIST
${RV_DEPS_LIST} Vulkan::Vulkan
)
ELSE()
RV_ADD_IMPORTED_LIBRARY(
NAME
Vulkan::Vulkan
TYPE
SHARED
LOCATION
${_vulkan_lib}
IMPLIB
"${_vulkan_implib}"
SONAME
${_vulkan_lib_name}
INCLUDE_DIRS
${_include_dir}
DEPENDS
${_target}
ADD_TO_DEPS_LIST
)
ENDIF()
93 changes: 93 additions & 0 deletions cmake/dependencies/vulkan.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#
# Copyright (C) 2026 Autodesk, Inc. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
# Vulkan = Vulkan-Headers + Vulkan-Loader (libvulkan.so), fetched from hash-pinned Khronos GitHub tarballs. RV consumes only the headers (<vulkan/vulkan.h>) and
# the loader (linked via Vulkan::Vulkan; all API calls go through vkGetInstanceProcAddr/vkGetDeviceProcAddr) -- no validation layers or shader tools. Modeled on
# glew.cmake.
#

# FORCE_LIB so _lib_dir is install/lib (we also pass -DCMAKE_INSTALL_LIBDIR=lib to the loader), giving a deterministic location across RHEL (lib64) and
# non-RHEL.
RV_CREATE_STANDARD_DEPS_VARIABLES("RV_DEPS_VULKAN" "${RV_DEPS_VULKAN_VERSION}" "" "" FORCE_LIB)

# --- Try to find an installed/system package first (only when RV_DEPS_PREFER_INSTALLED=ON). ---
# Vulkan ships no CMake config; it is located via the built-in FindVulkan module (ALLOW_MODULE) or the `vulkan` pkg-config module. Omit VERSION (FindVulkan
# version reporting is unreliable).
RV_FIND_DEPENDENCY(
TARGET
${_target}
PACKAGE
Vulkan
ALLOW_MODULE
PKG_CONFIG_NAME
vulkan
DEPS_LIST_TARGETS
Vulkan::Vulkan
)

# --- Library naming (shared between find and build paths), à la glew's _glew_lib_name. ---
# Linux: reference the SONAME symlink (libvulkan.so.1); the loader also installs the fully versioned real file (libvulkan.so.<version>) and the libvulkan.so dev
# symlink alongside it. Windows: loader produces vulkan-1.dll (in bin/) and the vulkan-1.lib import library (in lib/); the "-1" is RV_DEPS_VULKAN_VERSION_LIB.
IF(RV_TARGET_WINDOWS)
SET(_vulkan_lib_name
${CMAKE_SHARED_LIBRARY_PREFIX}vulkan-${RV_DEPS_VULKAN_VERSION_LIB}${CMAKE_SHARED_LIBRARY_SUFFIX}
)
SET(_vulkan_lib
${_bin_dir}/${_vulkan_lib_name}
)
SET(_vulkan_implib_name
${CMAKE_IMPORT_LIBRARY_PREFIX}vulkan-${RV_DEPS_VULKAN_VERSION_LIB}${CMAKE_IMPORT_LIBRARY_SUFFIX}
)
SET(_vulkan_implib
${_lib_dir}/${_vulkan_implib_name}
)
ELSE()
SET(_vulkan_lib_name
${CMAKE_SHARED_LIBRARY_PREFIX}vulkan${CMAKE_SHARED_LIBRARY_SUFFIX}.${RV_DEPS_VULKAN_VERSION_LIB}
)
SET(_vulkan_lib
${_lib_dir}/${_vulkan_lib_name}
)
ENDIF()

IF(${_target}_FOUND)
# Found via RV_FIND_DEPENDENCY (RV_DEPS_PREFER_INSTALLED=ON). FindVulkan/pkg-config usually provides the Vulkan::Vulkan target; create it only if the
# pkg-config path did not.
IF(NOT TARGET Vulkan::Vulkan)
RV_ADD_IMPORTED_LIBRARY(
NAME
Vulkan::Vulkan
TYPE
SHARED
LOCATION
${_vulkan_lib}
IMPLIB
"${_vulkan_implib}"
SONAME
${_vulkan_lib_name}
INCLUDE_DIRS
${_include_dir}
DEPENDS
${_target}
ADD_TO_DEPS_LIST
)
ENDIF()

# Found path: use TARGET_LIBS to resolve the actual library path at build time.
RV_STAGE_DEPENDENCY_LIBS(TARGET ${_target} TARGET_LIBS Vulkan::Vulkan)
ELSE()
# --- Default: fetch headers + loader from Khronos and build from source. ---
# We always build our own hash-pinned Vulkan (like every other managed dependency) unless RV_DEPS_PREFER_INSTALLED=ON. Note that a global Vulkan::Vulkan
# target may already exist here: INCLUDE(qt6) runs before us and Qt's find_package(Qt6 Gui) -> WrapVulkanHeaders runs find_package(Vulkan), which (with
# CMAKE_FIND_PACKAGE_TARGETS_GLOBAL) creates a global Vulkan::Vulkan from a discoverable *system* loader. build/vulkan.cmake takes ownership of that target
# name (repointing it at our fetched build) rather than reusing the system loader.
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/build/vulkan.cmake)

IF(RV_TARGET_WINDOWS)
RV_STAGE_DEPENDENCY_LIBS(TARGET ${_target} BIN_DIR ${_bin_dir} OUTPUTS ${RV_STAGE_BIN_DIR}/${_vulkan_lib_name})
ELSE()
RV_STAGE_DEPENDENCY_LIBS(TARGET ${_target} OUTPUTS ${RV_STAGE_LIB_DIR}/${_vulkan_lib_name})
ENDIF()
ENDIF()
9 changes: 9 additions & 0 deletions src/bin/apps/rv/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,15 @@ int utf8Main(int argc, char* argv[])
// (RV Preferences/Rendering/Multithread GPU Upload)
QApplication::setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity);

// Put every QOpenGLContext in one resource-sharing group. RV's GL contexts
// (GLView, video devices) already share manually via setShareContext, and
// shared resources like FTGL font-atlas textures rely on that invariant. On
// the Linux Vulkan presentation path there is no GLView to chain from, so
// the offscreen presentation context joins this global group instead (see
// QTVulkanVideoDevice::ensureGLContext). Otherwise, font glyph uploads land
// in a context where the atlas texture has no storage.
QApplication::setAttribute(Qt::AA_ShareOpenGLContexts);

TwkUtil::MemPool::initialize();

string altPrefsPath;
Expand Down
3 changes: 2 additions & 1 deletion src/lib/app/RvApp/Options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ namespace Rv
else if (name == "threads")
stl_ext::thread_group::debug_all(true);
else if (name == "gpu")
ImageRenderer::reportGL(true);
// Enables GLView format baseline, ImageRenderer GL reporting, and Vulkan presentation/interop diagnostics.
ImageRenderer::debugGpu(true);
else if (name == "audio")
{
AudioRenderer::setDebug(true);
Expand Down
46 changes: 46 additions & 0 deletions src/lib/app/RvCommon/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,25 @@ IF(RV_TARGET_LINUX
LIST(APPEND _sources ${_filename})
ENDIF()

IF(RV_TARGET_LINUX
OR RV_TARGET_WINDOWS
)
# Vulkan is fetched via cmake/dependencies/vulkan.cmake on Linux and Windows. No VULKAN_SDK environment variable or setup-env.sh is required.
IF(NOT TARGET Vulkan::Vulkan)
MESSAGE(FATAL_ERROR "Vulkan::Vulkan target is missing; cmake/dependencies/vulkan.cmake should provide it on Linux and Windows")
ENDIF()
MESSAGE(STATUS "Vulkan: using managed Vulkan ${RV_DEPS_VULKAN_VERSION}")
LIST(
APPEND
_sources
VulkanBuildProbe.cpp
VulkanView.cpp
QTVulkanVideoDevice.cpp
RvCommon/VulkanView.h
RvCommon/QTVulkanVideoDevice.h
)
ENDIF()

FILE(GLOB _ui_sources ui/*.ui)

IF(RV_VFX_PLATFORM STRGREATER_EQUAL CY2024)
Expand Down Expand Up @@ -148,6 +167,12 @@ FILE(
IF(NOT RV_TARGET_DARWIN)
LIST(REMOVE_ITEM _files_to_moc "RvCommon/DisplayLink.h" "RvCommon/CGDesktopVideoDevice.h")
ENDIF()
IF(NOT
(RV_TARGET_LINUX
OR RV_TARGET_WINDOWS)
)
LIST(REMOVE_ITEM _files_to_moc "RvCommon/VulkanView.h" "RvCommon/QTVulkanVideoDevice.h")
ENDIF()

FOREACH(
file_to_moc
Expand Down Expand Up @@ -452,6 +477,27 @@ IF(RV_TARGET_LINUX)
)
ENDIF()

IF(RV_TARGET_LINUX
OR RV_TARGET_WINDOWS
)
TARGET_LINK_LIBRARIES(
${_target}
PRIVATE Vulkan::Vulkan
)
# Activate the Win32-specific bits of <vulkan/vulkan.h>: VK_KHR_external_memory_win32 and VK_KHR_external_semaphore_win32 (struct types, enum values, and
# PFN_vkGet*Win32HandleKHR typedefs are gated behind this macro). Linux does not need an equivalent define because the FD external-handle symbols live in
# vulkan_core.h and are unconditionally exported.
IF(RV_TARGET_WINDOWS)
# WIN32_LEAN_AND_MEAN: vulkan_win32.h unconditionally includes <windows.h>; without WIN32_LEAN_AND_MEAN that drags in legacy winsock.h, which collides with
# the winsock2.h pulled in via Qt headers (ws2def.h struct redefinition errors). Promote the existing per-file convention to target scope so every RvCommon
# TU that transitively includes vulkan.h is safe.
TARGET_COMPILE_DEFINITIONS(
${_target}
PRIVATE VK_USE_PLATFORM_WIN32_KHR WIN32_LEAN_AND_MEAN
)
ENDIF()
ENDIF()

IF(RV_TARGET_WINDOWS)
TARGET_LINK_LIBRARIES(
${_target}
Expand Down
Loading
Loading