Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 12 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
cmake_minimum_required(VERSION 3.20)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_VISIBILITY_PRESET hidden)

if(APPLE AND NOT CMAKE_OSX_DEPLOYMENT_TARGET)
# 10.15 because of our use of supportsFamily()
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum macOS deployment target")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

realized we'd never set one, best to set one

endif()

project(plume)

if(APPLE)
Expand Down Expand Up @@ -94,7 +100,7 @@ if(PLUME_D3D12_AGILITY_SDK_ENABLED)
target_link_libraries(plume PRIVATE Microsoft::DirectX-Headers Microsoft::DirectX-Guids Microsoft::DirectX12-Agility)
endif()

# Platform-specific includes
# Platform-specific includes and shader compilation
if(APPLE)
if(PLUME_APPLE_RETINA_ENABLED)
target_compile_definitions(plume PRIVATE PLUME_APPLE_RETINA_ENABLED)
Expand All @@ -103,9 +109,13 @@ if(APPLE)
target_include_directories(plume PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/contrib/metal-cpp
)

# Compile and embed internal Metal shaders
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/PlumeInternalShaders.cmake)
plume_compile_metal_shaders(plume)
endif()

# Add examples if requested
if(PLUME_BUILD_EXAMPLES)
add_subdirectory(examples)
endif()
endif()
92 changes: 92 additions & 0 deletions cmake/PlumeInternalShaders.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# PlumeInternalShaders.cmake
# Internal shader compilation for Plume's built-in shaders (clear, resolve)

# Build the file_to_c tool for the host system
function(plume_build_file_to_c)
if(TARGET plume_file_to_c)
return()
endif()

set(FILE_TO_C_SOURCE "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/tools/file_to_c.cpp")

add_executable(plume_file_to_c ${FILE_TO_C_SOURCE})
set_target_properties(plume_file_to_c PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/plume_tools"
)

if(APPLE)
set_target_properties(plume_file_to_c PROPERTIES
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "-"
)
endif()
endfunction()

# Compile Metal shaders to embedded C headers
function(plume_compile_metal_shaders TARGET_NAME)
if(NOT APPLE)
return()
endif()

# Build the file_to_c tool
plume_build_file_to_c()

# Get the shader source directory
set(SHADER_DIR "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/../shaders")
set(OUTPUT_DIR "${CMAKE_BINARY_DIR}/plume_shaders")

# Create output directory
file(MAKE_DIRECTORY "${OUTPUT_DIR}")

# List of shaders to compile
set(PLUME_METAL_SHADERS
plume_clear
plume_resolve
)

set(GENERATED_SOURCES "")
set(GENERATED_HEADERS "")

foreach(SHADER_NAME ${PLUME_METAL_SHADERS})
set(SHADER_SOURCE "${SHADER_DIR}/${SHADER_NAME}.metal")
set(IR_OUTPUT "${OUTPUT_DIR}/${SHADER_NAME}.ir")
set(METALLIB_OUTPUT "${OUTPUT_DIR}/${SHADER_NAME}.metallib")
set(C_OUTPUT "${OUTPUT_DIR}/${SHADER_NAME}.metallib.c")
set(H_OUTPUT "${OUTPUT_DIR}/${SHADER_NAME}.metallib.h")

# Compile Metal to IR
add_custom_command(
OUTPUT ${IR_OUTPUT}
COMMAND xcrun -sdk macosx metal -mmacosx-version-min=${CMAKE_OSX_DEPLOYMENT_TARGET} -o ${IR_OUTPUT} -c ${SHADER_SOURCE}
DEPENDS ${SHADER_SOURCE}
COMMENT "Compiling ${SHADER_NAME}.metal to IR"
VERBATIM
)

# Link IR to metallib
add_custom_command(
OUTPUT ${METALLIB_OUTPUT}
COMMAND xcrun -sdk macosx metallib ${IR_OUTPUT} -o ${METALLIB_OUTPUT}
DEPENDS ${IR_OUTPUT}
COMMENT "Linking ${SHADER_NAME} to metallib"
VERBATIM
)

# Generate C header with embedded data
add_custom_command(
OUTPUT ${C_OUTPUT} ${H_OUTPUT}
COMMAND plume_file_to_c ${METALLIB_OUTPUT} "${SHADER_NAME}_metallib" ${C_OUTPUT} ${H_OUTPUT}
DEPENDS ${METALLIB_OUTPUT} plume_file_to_c
COMMENT "Generating embedded header for ${SHADER_NAME}"
VERBATIM
)

list(APPEND GENERATED_SOURCES ${C_OUTPUT})
list(APPEND GENERATED_HEADERS ${H_OUTPUT})
endforeach()

# Add generated sources to the target
target_sources(${TARGET_NAME} PRIVATE ${GENERATED_SOURCES})

# Add include directory for generated headers
target_include_directories(${TARGET_NAME} PRIVATE "${OUTPUT_DIR}")
endfunction()
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
//
// plume
//
// Copyright (c) 2024 renderbag and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file for details.
//

#include <filesystem>
#include <fstream>
#include <cstdio>
Expand All @@ -14,7 +21,7 @@ std::vector<char> read_file(const char* path) {
// Get the length of the file
input_file.seekg(0, std::ios::end);
ret.resize(input_file.tellg());

// Read the file contents into the vector
input_file.seekg(0, std::ios::beg);
input_file.read(ret.data(), ret.size());
Expand Down Expand Up @@ -52,29 +59,43 @@ int main(int argc, const char** argv) {
create_parent_if_needed(output_c_path);
create_parent_if_needed(output_h_path);

// Write the C file with the array
// Write the C file with the array and size
{
std::ofstream output_c_file{output_c_path};
output_c_file << "extern const char " << array_name << "[" << contents.size() << "];\n";
output_c_file << "const char " << array_name << "[" << contents.size() << "] = {";
output_c_file << "// Auto-generated by plume file_to_c - do not edit\n\n";
output_c_file << "#include <stddef.h>\n\n";
output_c_file << "const unsigned char " << array_name << "[" << contents.size() << "] = {";

for (char x : contents) {
output_c_file << (int)x << ", ";
for (size_t i = 0; i < contents.size(); ++i) {
if (i % 16 == 0) {
output_c_file << "\n ";
}
output_c_file << (int)(unsigned char)contents[i] << ",";
if (i % 16 != 15 && i != contents.size() - 1) {
output_c_file << " ";
}
}

output_c_file << "};\n";
output_c_file << "\n};\n\n";
output_c_file << "const size_t " << array_name << "_size = " << contents.size() << ";\n";
}

// Write the header file with the extern array
// Write the header file with the extern declarations
{
std::ofstream output_h_file{output_h_path};
output_h_file << "// Auto-generated by plume file_to_c - do not edit\n\n";
output_h_file << "#pragma once\n\n";
output_h_file << "#include <stddef.h>\n\n";
output_h_file <<
"#ifdef __cplusplus\n"
" extern \"C\" {\n"
"#endif\n"
"extern const char " << array_name << "[" << contents.size() << "];\n"
"extern \"C\" {\n"
"#endif\n\n"
"extern const unsigned char " << array_name << "[" << contents.size() << "];\n"
"extern const size_t " << array_name << "_size;\n\n"
"#ifdef __cplusplus\n"
" }\n"
"}\n"
"#endif\n";
}
}

return EXIT_SUCCESS;
}
3 changes: 0 additions & 3 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@ set(PLUME_SDL_VULKAN_ENABLED ON CACHE BOOL "Enable SDL Vulkan integration" FORCE
# Find SDL2 (required for examples)
find_package(SDL2 REQUIRED)

# Add tools directory first (needed for shader compilation)
add_subdirectory(tools)

# Include custom ShaderCompilation module
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
include(ShaderCompilation)
Expand Down
54 changes: 29 additions & 25 deletions examples/cmake/ShaderCompilation.cmake
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Shader compilation functions for Plume
# Using DXC for HLSL to SPIR-V compilation and Metal for macOS

# Build file_to_c tool (shared with plume core)
Copy link
Contributor

@squidbus squidbus Dec 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason not to just unify this whole shader compilation utility with the new one? May be useful for consumers.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't want to make this PR too big, this one just aims to precompile and embed the shaders Metal uses -- but yes, I think I'll right after make a follow up PR that provides some primitives for shader compilation

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, sounds good.

include(${CMAKE_SOURCE_DIR}/cmake/PlumeInternalShaders.cmake)
plume_build_file_to_c()

# Fetch DXC for shader compilation
include(FetchContent)
FetchContent_Declare(
Expand All @@ -13,7 +17,7 @@ FetchContent_MakeAvailable(dxc)
# Set up DXC paths based on platform
if(WIN32)
set(DXC "${dxc_SOURCE_DIR}/bin/x64/dxc.exe")

# Dependencies that must be next to the DLL if on Windows
if(EXISTS "${dxc_SOURCE_DIR}/bin/x64/dxcompiler.dll")
configure_file("${dxc_SOURCE_DIR}/bin/x64/dxcompiler.dll" "${CMAKE_BINARY_DIR}/bin/dxcompiler.dll" COPYONLY)
Expand All @@ -30,12 +34,12 @@ elseif(APPLE)
set(DXC_EXECUTABLE "${dxc_SOURCE_DIR}/bin/arm64/dxc-macos")
set(DXC_LIB_DIR "${dxc_SOURCE_DIR}/lib/arm64")
endif()

# Make sure the executable is accessible and has execute permissions
if(EXISTS "${DXC_EXECUTABLE}")
# Set executable permission if needed
execute_process(COMMAND chmod +x "${DXC_EXECUTABLE}")

# Set DXC command with DYLD_LIBRARY_PATH
set(DXC "DYLD_LIBRARY_PATH=${DXC_LIB_DIR}" "${DXC_EXECUTABLE}")
else()
Expand All @@ -50,7 +54,7 @@ else()
set(DXC_EXECUTABLE "${dxc_SOURCE_DIR}/bin/arm64/dxc-linux")
set(DXC_LIB_DIR "${dxc_SOURCE_DIR}/lib/arm64")
endif()

# Make sure the executable is accessible and has execute permissions
if(EXISTS "${DXC_EXECUTABLE}")
# Set executable permission if needed
Expand Down Expand Up @@ -85,10 +89,10 @@ function(build_shader_dxc_impl TARGET_NAME SHADER_SOURCE SHADER_TYPE OUTPUT_NAME
set(SHADER_OUTPUT "${CMAKE_BINARY_DIR}/shaders/${OUTPUT_NAME}.hlsl.${OUTPUT_EXT}")
set(C_OUTPUT "${CMAKE_BINARY_DIR}/shaders/${OUTPUT_NAME}.hlsl.${OUTPUT_FORMAT}.c")
set(H_OUTPUT "${CMAKE_BINARY_DIR}/shaders/${OUTPUT_NAME}.hlsl.${OUTPUT_FORMAT}.h")

# Create output directory
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/shaders")

# Determine the shader options based on type
if(SHADER_TYPE STREQUAL "vertex")
set(SHADER_PROFILE "vs_6_0")
Expand All @@ -107,7 +111,7 @@ function(build_shader_dxc_impl TARGET_NAME SHADER_SOURCE SHADER_TYPE OUTPUT_NAME
endif()

set(BLOB_NAME "${OUTPUT_NAME}Blob${BLOB_SUFFIX}")

# Compile using DXC
add_custom_command(
OUTPUT ${SHADER_OUTPUT}
Expand All @@ -116,18 +120,18 @@ function(build_shader_dxc_impl TARGET_NAME SHADER_SOURCE SHADER_TYPE OUTPUT_NAME
DEPENDS ${SHADER_SOURCE}
COMMENT "Compiling ${SHADER_TYPE} shader ${SHADER_SOURCE} to ${OUTPUT_FORMAT} using DXC"
)

# Generate C header
add_custom_command(
OUTPUT "${C_OUTPUT}" "${H_OUTPUT}"
COMMAND file_to_c ${SHADER_OUTPUT} "${BLOB_NAME}" "${C_OUTPUT}" "${H_OUTPUT}"
DEPENDS ${SHADER_OUTPUT} file_to_c
COMMAND plume_file_to_c ${SHADER_OUTPUT} "${BLOB_NAME}" "${C_OUTPUT}" "${H_OUTPUT}"
DEPENDS ${SHADER_OUTPUT} plume_file_to_c
COMMENT "Generating C header for ${OUTPUT_FORMAT} shader ${OUTPUT_NAME}"
)

# Add the generated source file to the target
target_sources(${TARGET_NAME} PRIVATE "${C_OUTPUT}")

# Make sure the target can find the generated header
target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}")
endfunction()
Expand All @@ -149,37 +153,37 @@ function(build_shader_metal_impl TARGET_NAME SHADER_SOURCE OUTPUT_NAME)
set(IR_OUTPUT "${CMAKE_BINARY_DIR}/shaders/${OUTPUT_NAME}.ir")
set(METAL_C_OUTPUT "${CMAKE_BINARY_DIR}/shaders/${OUTPUT_NAME}.metal.c")
set(METAL_H_OUTPUT "${CMAKE_BINARY_DIR}/shaders/${OUTPUT_NAME}.metal.h")

# Create output directory
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/shaders")

# Compile Metal to IR
add_custom_command(
OUTPUT ${IR_OUTPUT}
COMMAND xcrun -sdk macosx metal -o ${IR_OUTPUT} -c ${SHADER_SOURCE}
DEPENDS ${SHADER_SOURCE}
COMMENT "Compiling Metal shader to IR"
)

# Compile IR to metallib
add_custom_command(
OUTPUT ${METALLIB_OUTPUT}
COMMAND xcrun -sdk macosx metallib ${IR_OUTPUT} -o ${METALLIB_OUTPUT}
DEPENDS ${IR_OUTPUT}
COMMENT "Compiling Metal IR to metallib"
)

# Generate C header
add_custom_command(
OUTPUT "${METAL_C_OUTPUT}" "${METAL_H_OUTPUT}"
COMMAND file_to_c ${METALLIB_OUTPUT} "${OUTPUT_NAME}BlobMSL" "${METAL_C_OUTPUT}" "${METAL_H_OUTPUT}"
DEPENDS ${METALLIB_OUTPUT} file_to_c
COMMAND plume_file_to_c ${METALLIB_OUTPUT} "${OUTPUT_NAME}BlobMSL" "${METAL_C_OUTPUT}" "${METAL_H_OUTPUT}"
DEPENDS ${METALLIB_OUTPUT} plume_file_to_c
COMMENT "Generating C header for Metal shader ${OUTPUT_NAME}"
)

# Add the generated source file to the target
target_sources(${TARGET_NAME} PRIVATE "${METAL_C_OUTPUT}")

# Make sure the target can find the generated header
target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}")
endfunction()
Expand All @@ -188,7 +192,7 @@ endfunction()
function(compile_shader TARGET_NAME SHADER_SOURCE SHADER_TYPE OUTPUT_NAME ENTRY_POINT)
# Get the file extension to determine the shader language
get_filename_component(SHADER_EXT ${SHADER_SOURCE} EXT)

# Compile based on extension
if(SHADER_EXT MATCHES ".*\\.metal$")
# Compile Metal shader
Expand All @@ -198,7 +202,7 @@ function(compile_shader TARGET_NAME SHADER_SOURCE SHADER_TYPE OUTPUT_NAME ENTRY_
elseif(SHADER_SOURCE MATCHES ".*\\.hlsl$")
# Compile HLSL shader to SPIR-V using DXC
build_shader_spirv_impl(${TARGET_NAME} ${SHADER_SOURCE} ${SHADER_TYPE} ${OUTPUT_NAME} ${ENTRY_POINT})

# Also compile to DXIL on Windows
if(WIN32)
build_shader_dxil_impl(${TARGET_NAME} ${SHADER_SOURCE} ${SHADER_TYPE} ${OUTPUT_NAME} ${ENTRY_POINT})
Expand All @@ -212,8 +216,8 @@ function(file_to_c_header INPUT_FILE OUTPUT_FILE VARIABLE_NAME)
add_custom_command(
OUTPUT ${OUTPUT_FILE}
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/shaders
COMMAND ${CMAKE_BINARY_DIR}/bin/file_to_c ${INPUT_FILE} ${OUTPUT_FILE} ${VARIABLE_NAME} ${VARIABLE_NAME}Size
DEPENDS ${INPUT_FILE} file_to_c
COMMAND plume_file_to_c ${INPUT_FILE} ${VARIABLE_NAME} ${OUTPUT_FILE} ${OUTPUT_FILE}
DEPENDS ${INPUT_FILE} plume_file_to_c
COMMENT "Converting ${INPUT_FILE} to C header"
)
endfunction()
endfunction()
1 change: 0 additions & 1 deletion examples/tools/CMakeLists.txt

This file was deleted.

14 changes: 0 additions & 14 deletions examples/tools/file_to_c/CMakeLists.txt

This file was deleted.

Loading
Loading