Skip to content

Commit e8544b5

Browse files
committed
compute-infra: GPU compute shader infrastructure (Vulkan/Metal/GL interop)
Third-party additions: - vkmemalloc: Vulkan Memory Allocator (VMA) for device-local buffer allocation - vulkan_headers: Khronos Vulkan headers - find_dependencies.cmake: add Vulkan + vkmemalloc package discovery - cmake/Open3DAddComputeShaders.cmake: compile GLSL .comp -> SPIR-V (glslc) and cross-compile to MSL (spirv-cross) for Apple; installs to resources/ cpp/open3d/CMakeLists.txt: link OpenGL::EGL and X11 for the GL shared-context backend on Linux/Windows. New source files (wired into the build in the next PR): - ComputeGPU.h: ComputeProgramId enum, GaussianSplatGpuContext abstract base, GpuComputeFrame/GpuComputePass RAII helpers - ComputeGPUVulkan: headless Vulkan instance + device, SSBO/UBO binding, command buffer lifecycle, fence-based geometry sync - ComputeGPUMetal.mm: Metal GaussianSplatGpuContext implementation - GaussianSplatOpenGLContext: GLFW-owned GL 4.6 helper window for shared-context creation (GLX on Linux, WGL on Windows) before Engine::create() - GaussianSplatVulkanInteropContext: exports VkImage memory to OpenGL via GL_EXT_memory_object for zero-copy Filament-Vulkan texture sharing
1 parent 9053091 commit e8544b5

14 files changed

Lines changed: 23788 additions & 0 deletions

3rdparty/find_dependencies.cmake

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,24 @@ else()
608608
list(APPEND Open3D_3RDPARTY_PUBLIC_TARGETS_FROM_SYSTEM Open3D::3rdparty_eigen3)
609609
endif()
610610

611+
# Vulkan-Headers
612+
include(${Open3D_3RDPARTY_DIR}/vulkan_headers/vulkan_headers.cmake)
613+
open3d_import_3rdparty_library(3rdparty_vulkan_headers
614+
INCLUDE_DIRS ${VULKAN_HEADERS_INCLUDE_DIRS}
615+
INCLUDE_ALL
616+
DEPENDS ext_vulkan_headers
617+
)
618+
list(APPEND Open3D_3RDPARTY_PRIVATE_TARGETS_FROM_CUSTOM Open3D::3rdparty_vulkan_headers)
619+
620+
# Vulkan Memory Allocator
621+
include(${Open3D_3RDPARTY_DIR}/vkmemalloc/vkmemalloc.cmake)
622+
open3d_import_3rdparty_library(3rdparty_vkmemalloc
623+
INCLUDE_DIRS ${VMA_INCLUDE_DIRS}
624+
INCLUDE_ALL
625+
DEPENDS ext_vkmemalloc ext_vmahpp
626+
)
627+
list(APPEND Open3D_3RDPARTY_PRIVATE_TARGETS_FROM_CUSTOM Open3D::3rdparty_vkmemalloc)
628+
611629
# Nanoflann
612630
if(USE_SYSTEM_NANOFLANN)
613631
open3d_find_package_3rdparty_library(3rdparty_nanoflann

3rdparty/vkmemalloc/vk_mem_alloc.h

Lines changed: 19558 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
include(ExternalProject)
2+
3+
set(VMA_SOURCE_DIR "${OPEN3D_THIRD_PARTY_DOWNLOAD_DIR}/vkmemalloc")
4+
5+
ExternalProject_Add(
6+
ext_vkmemalloc
7+
PREFIX vkmemalloc
8+
URL https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator/raw/refs/tags/v3.3.0/include/vk_mem_alloc.h
9+
URL_HASH SHA256=90ce12fc4a2466235a09ae02905dd0c13aee80c1bbf11b331ab61230c2ceb112
10+
DOWNLOAD_NAME vk_mem_alloc.h
11+
DOWNLOAD_NO_EXTRACT TRUE
12+
SOURCE_DIR "${VMA_SOURCE_DIR}"
13+
DOWNLOAD_DIR "${OPEN3D_THIRD_PARTY_DOWNLOAD_DIR}/vkmemalloc"
14+
UPDATE_COMMAND ""
15+
CONFIGURE_COMMAND ""
16+
BUILD_COMMAND ""
17+
INSTALL_COMMAND ""
18+
)
19+
20+
# VulkanMemoryAllocator-Hpp: C++ bindings for VMA (header-only, CC0 license).
21+
# Provides vma::functionsFromDispatcher() and vma::raii:: RAII wrappers.
22+
# Pinned to v3.3.0+3, matching the VMA C header above.
23+
set(VMA_HPP_SOURCE_DIR "${OPEN3D_THIRD_PARTY_DOWNLOAD_DIR}/vkmemalloc_hpp")
24+
ExternalProject_Add(
25+
ext_vmahpp
26+
PREFIX vkmemalloc_hpp
27+
URL https://github.com/YaaZ/VulkanMemoryAllocator-Hpp/releases/download/v3.3.0%2B3/VulkanMemoryAllocator-Hpp-3.3.0.tar.gz
28+
URL_HASH SHA256=8c2a0573babe1f86f3241d12b4c9df40bb944649b7f4239c1c611797f8af6cd5
29+
DOWNLOAD_DIR "${OPEN3D_THIRD_PARTY_DOWNLOAD_DIR}/vkmemalloc_hpp"
30+
SOURCE_DIR "${VMA_HPP_SOURCE_DIR}/src"
31+
UPDATE_COMMAND ""
32+
CONFIGURE_COMMAND ""
33+
BUILD_COMMAND ""
34+
INSTALL_COMMAND ""
35+
DEPENDS ext_vkmemalloc
36+
)
37+
38+
set(VMA_INCLUDE_DIRS ${VMA_SOURCE_DIR}/ ${VMA_HPP_SOURCE_DIR}/src/) # "/" is critical.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
include(ExternalProject)
2+
3+
ExternalProject_Add(
4+
ext_vulkan_headers
5+
PREFIX vulkan_headers
6+
URL https://github.com/KhronosGroup/Vulkan-Headers/archive/refs/tags/v1.4.349.tar.gz
7+
URL_HASH SHA256=d7b84712f8469657baa37a436d1a23efbf0a6354fc8835b6758ef036e15dcc14
8+
DOWNLOAD_DIR "${OPEN3D_THIRD_PARTY_DOWNLOAD_DIR}/vulkan_headers"
9+
UPDATE_COMMAND ""
10+
CONFIGURE_COMMAND ""
11+
BUILD_COMMAND ""
12+
INSTALL_COMMAND ""
13+
)
14+
15+
ExternalProject_Get_Property(ext_vulkan_headers SOURCE_DIR)
16+
set(VULKAN_HEADERS_INCLUDE_DIRS ${SOURCE_DIR}/include/) # "/" is critical.
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# Capture the directory of this file at include-time. CMAKE_CURRENT_LIST_DIR
2+
# inside a function resolves to the caller's directory, not this file's directory,
3+
# so we must snapshot it here at file scope before the function definition.
4+
set(_Open3DAddComputeShaders_DIR "${CMAKE_CURRENT_LIST_DIR}" CACHE INTERNAL "")
5+
6+
# open3d_add_compute_shaders(<target>
7+
# OUTPUT_DIRECTORY <dir>
8+
# SOURCES <shader1> [<shader2>...]
9+
# )
10+
#
11+
# For each standalone Vulkan GLSL compute shader source, this function:
12+
# - stages the original .comp file into <dir>
13+
# - compiles it to SPIR-V (.spv) with glslangValidator
14+
# - [on Apple] transpiles the SPIR-V to Metal Shading Language (.metal) with spirv-cross
15+
# On Apple, the .metal files are bundled into a single .metallib file for runtime loading
16+
# (newLibraryWithFile / newLibraryWithData), avoiding newLibraryWithSource.
17+
function(open3d_add_compute_shaders target)
18+
cmake_parse_arguments(PARSE_ARGV 1 ARG "" "OUTPUT_DIRECTORY" "SOURCES")
19+
20+
if (ARG_UNPARSED_ARGUMENTS)
21+
message(FATAL_ERROR "Unknown arguments: ${ARG_UNPARSED_ARGUMENTS}")
22+
endif()
23+
24+
if (ARG_KEYWORDS_MISSING_VALUES)
25+
message(FATAL_ERROR "Missing values for arguments: ${ARG_KEYWORDS_MISSING_VALUES}")
26+
endif()
27+
28+
if (NOT ARG_OUTPUT_DIRECTORY)
29+
message(FATAL_ERROR "No output directory for compute shaders specified.")
30+
endif()
31+
32+
if (NOT ARG_SOURCES)
33+
message(FATAL_ERROR "No compute shader files specified.")
34+
endif()
35+
36+
get_filename_component(OUTPUT_DIRECTORY_FULL_PATH "${ARG_OUTPUT_DIRECTORY}" ABSOLUTE)
37+
file(MAKE_DIRECTORY ${OUTPUT_DIRECTORY_FULL_PATH})
38+
39+
find_program(OPEN3D_GLSLANG_VALIDATOR glslangValidator REQUIRED)
40+
if (APPLE)
41+
find_program(OPEN3D_SPIRV_CROSS spirv-cross REQUIRED)
42+
# The scatter pass uses subgroup arithmetic (gl_SubgroupSize, subgroupAdd, etc.).
43+
# Fixing the subgroup size to 32 (Apple Silicon SIMD width) lets the Metal compiler
44+
# treat gl_SubgroupSize as a compile-time constant for loop unrolling.
45+
set(SPIRV_CROSS_EXTRA_FLAGS_gaussian_radix_sort_scatter "--msl-fixed-subgroup-size 32")
46+
set(GAUSSIAN_METAL_BASENAMES "")
47+
endif()
48+
49+
# Default glslangValidator flags: Vulkan 1.3 SPIR-V + LTO.
50+
# Subgroup operations (gl_SubgroupSize, subgroupAdd, etc.) require Vulkan
51+
# SPIR-V (-V) because glslangValidator's OpenGL target (-G) does not support
52+
# them. Most compute shaders use subgroup ops and therefore need -V.
53+
set(GLSLANG_FLAGS -V --target-env vulkan1.3 -gVS)
54+
55+
foreach(shader IN LISTS ARG_SOURCES)
56+
get_filename_component(SHADER_FULL_PATH "${shader}" ABSOLUTE)
57+
get_filename_component(SHADER_NAME "${shader}" NAME)
58+
get_filename_component(SHADER_BASENAME "${shader}" NAME_WE)
59+
set(STAGED_SHADER_FULL_PATH "${OUTPUT_DIRECTORY_FULL_PATH}/${SHADER_NAME}")
60+
set(STAGED_SPIRV_FULL_PATH "${OUTPUT_DIRECTORY_FULL_PATH}/${SHADER_BASENAME}.spv")
61+
set(STAGED_METAL_FULL_PATH "${OUTPUT_DIRECTORY_FULL_PATH}/${SHADER_BASENAME}.metal")
62+
63+
file(RELATIVE_PATH STAGED_SHADER_RELATIVE_PATH
64+
"${CMAKE_CURRENT_BINARY_DIR}" "${STAGED_SHADER_FULL_PATH}")
65+
file(RELATIVE_PATH STAGED_SPIRV_RELATIVE_PATH
66+
"${CMAKE_CURRENT_BINARY_DIR}" "${STAGED_SPIRV_FULL_PATH}")
67+
file(RELATIVE_PATH STAGED_METAL_RELATIVE_PATH
68+
"${CMAKE_CURRENT_BINARY_DIR}" "${STAGED_METAL_FULL_PATH}")
69+
70+
add_custom_command(
71+
OUTPUT ${STAGED_SHADER_FULL_PATH} ${STAGED_SPIRV_FULL_PATH}
72+
COMMAND ${CMAKE_COMMAND} -E copy_if_different
73+
${SHADER_FULL_PATH} ${STAGED_SHADER_FULL_PATH}
74+
COMMAND ${OPEN3D_GLSLANG_VALIDATOR}
75+
${GLSLANG_FLAGS}
76+
${SHADER_FULL_PATH} -o ${STAGED_SPIRV_FULL_PATH}
77+
COMMENT "Compiling compute shader ${SHADER_NAME} to SPIR-V"
78+
MAIN_DEPENDENCY ${shader}
79+
VERBATIM
80+
)
81+
if (APPLE)
82+
set(SPIRV_CROSS_EXTRA_FLAGS ${SPIRV_CROSS_EXTRA_FLAGS_${SHADER_BASENAME}})
83+
file(GENERATE OUTPUT run_spirv_cross_${SHADER_BASENAME}.sh CONTENT
84+
"${OPEN3D_SPIRV_CROSS} \"${STAGED_SPIRV_FULL_PATH}\" --msl --msl-version 20400 --msl-decoration-binding ${SPIRV_CROSS_EXTRA_FLAGS} \
85+
--rename-entry-point main ${SHADER_BASENAME}_main comp --output \"${STAGED_METAL_FULL_PATH}\"
86+
sed -i '' 's/#include <metal_stdlib>/#include <metal_stdlib>\\n#include <metal_simdgroup>/g' \"${STAGED_METAL_FULL_PATH}\"")
87+
add_custom_command(
88+
OUTPUT ${STAGED_METAL_FULL_PATH}
89+
COMMAND sh run_spirv_cross_${SHADER_BASENAME}.sh
90+
DEPENDS ${STAGED_SPIRV_FULL_PATH} run_spirv_cross_${SHADER_BASENAME}.sh
91+
COMMENT "Transpiling compute shader ${SHADER_NAME} to Metal Shading Language and adding <metal_simdgroup>"
92+
VERBATIM
93+
)
94+
list(APPEND GAUSSIAN_METAL_BASENAMES "${SHADER_BASENAME}")
95+
endif()
96+
97+
list(APPEND STAGED_COMPUTE_SHADERS
98+
"${STAGED_SHADER_FULL_PATH}"
99+
"${STAGED_SPIRV_FULL_PATH}")
100+
if (APPLE)
101+
list(APPEND STAGED_COMPUTE_SHADERS "${STAGED_METAL_FULL_PATH}")
102+
endif()
103+
endforeach()
104+
105+
# Bundle SPIRV-Cross MSL into a single Metal library for runtime loading
106+
# (newLibraryWithFile / newLibraryWithData), avoiding newLibraryWithSource.
107+
if(APPLE AND GAUSSIAN_METAL_BASENAMES)
108+
set(METALLIB_OUTPUT "${OUTPUT_DIRECTORY_FULL_PATH}/gaussian_splat.metallib")
109+
set(METAL_AIR_FILES "")
110+
foreach(BASE IN LISTS GAUSSIAN_METAL_BASENAMES)
111+
set(STAGED_METAL_FULL_PATH "${OUTPUT_DIRECTORY_FULL_PATH}/${BASE}.metal")
112+
set(STAGED_AIR_FULL_PATH "${OUTPUT_DIRECTORY_FULL_PATH}/${BASE}.air")
113+
list(APPEND METAL_AIR_FILES "${STAGED_AIR_FULL_PATH}")
114+
add_custom_command(
115+
OUTPUT ${STAGED_AIR_FULL_PATH}
116+
COMMAND xcrun -sdk macosx metal
117+
-std=macos-metal2.4
118+
-Wno-sometimes-uninitialized
119+
-c ${STAGED_METAL_FULL_PATH}
120+
-o ${STAGED_AIR_FULL_PATH}
121+
DEPENDS ${STAGED_METAL_FULL_PATH}
122+
COMMENT "Metal AIR: ${BASE}.metal"
123+
VERBATIM
124+
)
125+
endforeach()
126+
# In Xcode 16+, the standalone 'metallib' tool was removed; the 'metal'
127+
# compiler now handles AIR -> metallib linking directly.
128+
add_custom_command(
129+
OUTPUT ${METALLIB_OUTPUT}
130+
COMMAND xcrun -sdk macosx metal ${METAL_AIR_FILES} -o ${METALLIB_OUTPUT}
131+
DEPENDS ${METAL_AIR_FILES}
132+
COMMENT "Linking gaussian_splat.metallib"
133+
VERBATIM
134+
)
135+
list(APPEND STAGED_COMPUTE_SHADERS "${METALLIB_OUTPUT}")
136+
endif()
137+
138+
add_custom_target(${target} ALL
139+
DEPENDS ${STAGED_COMPUTE_SHADERS}
140+
)
141+
142+
set_target_properties(${target} PROPERTIES
143+
COMPUTE_SHADER_FILES "${STAGED_COMPUTE_SHADERS}")
144+
endfunction()

cpp/open3d/CMakeLists.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,20 @@ open3d_set_global_properties(Open3D)
136136
open3d_set_open3d_lib_properties(Open3D)
137137
open3d_link_3rdparty_libraries(Open3D)
138138

139+
# GLX (X11) and EGL (Wayland) are needed by the OpenGL compute backend for
140+
# Gaussian splatting. The context class detects the display server at runtime
141+
# and uses GLX on X11, EGL on Wayland.
142+
if (NOT APPLE)
143+
find_package(OpenGL COMPONENTS EGL)
144+
if (OpenGL_EGL_FOUND)
145+
target_link_libraries(Open3D PRIVATE OpenGL::EGL)
146+
endif()
147+
find_package(X11 QUIET)
148+
if (X11_FOUND)
149+
target_link_libraries(Open3D PRIVATE X11::X11)
150+
endif()
151+
endif()
152+
139153

140154
# If we are building a STATIC_LIBRARY, hide symbols coming from 3rd party static
141155
# libraries that are not hidden during compilation. Don't propagate beyond

0 commit comments

Comments
 (0)