diff --git a/CMakeLists.txt b/CMakeLists.txt index e782ac5..337d4a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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") +endif() + project(plume) if(APPLE) @@ -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) @@ -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() diff --git a/cmake/PlumeInternalShaders.cmake b/cmake/PlumeInternalShaders.cmake new file mode 100644 index 0000000..3a60d26 --- /dev/null +++ b/cmake/PlumeInternalShaders.cmake @@ -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() diff --git a/examples/tools/file_to_c/file_to_c.cpp b/cmake/tools/file_to_c.cpp similarity index 55% rename from examples/tools/file_to_c/file_to_c.cpp rename to cmake/tools/file_to_c.cpp index 2da8158..174145e 100644 --- a/examples/tools/file_to_c/file_to_c.cpp +++ b/cmake/tools/file_to_c.cpp @@ -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 #include #include @@ -14,7 +21,7 @@ std::vector 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()); @@ -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 \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 \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"; } -} \ No newline at end of file + + return EXIT_SUCCESS; +} diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 91e96a8..69aca59 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -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) diff --git a/examples/cmake/ShaderCompilation.cmake b/examples/cmake/ShaderCompilation.cmake index 0104218..dcfd13e 100644 --- a/examples/cmake/ShaderCompilation.cmake +++ b/examples/cmake/ShaderCompilation.cmake @@ -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) +include(${CMAKE_SOURCE_DIR}/cmake/PlumeInternalShaders.cmake) +plume_build_file_to_c() + # Fetch DXC for shader compilation include(FetchContent) FetchContent_Declare( @@ -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) @@ -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() @@ -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 @@ -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") @@ -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} @@ -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() @@ -149,10 +153,10 @@ 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} @@ -160,7 +164,7 @@ function(build_shader_metal_impl TARGET_NAME SHADER_SOURCE OUTPUT_NAME) DEPENDS ${SHADER_SOURCE} COMMENT "Compiling Metal shader to IR" ) - + # Compile IR to metallib add_custom_command( OUTPUT ${METALLIB_OUTPUT} @@ -168,18 +172,18 @@ function(build_shader_metal_impl TARGET_NAME SHADER_SOURCE OUTPUT_NAME) 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() @@ -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 @@ -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}) @@ -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() diff --git a/examples/tools/CMakeLists.txt b/examples/tools/CMakeLists.txt deleted file mode 100644 index eb37de8..0000000 --- a/examples/tools/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -add_subdirectory(file_to_c) diff --git a/examples/tools/file_to_c/CMakeLists.txt b/examples/tools/file_to_c/CMakeLists.txt deleted file mode 100644 index e1db4ab..0000000 --- a/examples/tools/file_to_c/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -cmake_minimum_required(VERSION 3.20) -project(file_to_c) -set(CMAKE_CXX_STANDARD 17) - -add_executable(file_to_c file_to_c.cpp) - -if (APPLE) - set_target_properties(file_to_c PROPERTIES - XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "-" - XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS ${CMAKE_CURRENT_SOURCE_DIR}/../../plume.entitlements - ) -endif() - -target_link_libraries(file_to_c PRIVATE) diff --git a/plume_metal.cpp b/plume_metal.cpp index 8bbb865..a547850 100644 --- a/plume_metal.cpp +++ b/plume_metal.cpp @@ -18,6 +18,8 @@ #include #include "plume_metal.h" +#include "plume_clear.metallib.h" +#include "plume_resolve.metallib.h" namespace plume { // MARK: - Constants @@ -3992,37 +3994,22 @@ namespace plume { } void MetalDevice::createResolvePipelineState() { - const char* resolve_shader = R"( - #include - using namespace metal; - - struct ResolveParams { - uint2 dstOffset; - uint2 srcOffset; - uint2 resolveSize; - }; - - kernel void msaaResolve( - texture2d_ms source [[texture(0)]], - texture2d destination [[texture(1)]], - constant ResolveParams& params [[buffer(0)]], - uint2 gid [[thread_position_in_grid]]) - { - if (gid.x >= params.resolveSize.x || gid.y >= params.resolveSize.y) return; - uint2 dstPos = gid + params.dstOffset; - uint2 srcPos = gid + params.srcOffset; - float4 color = float4(0); - for (uint s = 0; s < source.get_num_samples(); s++) { - color += source.read(srcPos, s); - } - color /= float(source.get_num_samples()); - destination.write(color, dstPos); - } - )"; + // Load pre-compiled metallib from embedded data + dispatch_data_t dispatchData = dispatch_data_create( + plume_resolve_metallib, + plume_resolve_metallib_size, + nullptr, + DISPATCH_DATA_DESTRUCTOR_DEFAULT + ); NS::Error* error = nullptr; - MTL::Library *library = mtl->newLibrary(NS::String::string(resolve_shader, NS::UTF8StringEncoding), nullptr, &error); - assert(library != nullptr && "Failed to create library"); + MTL::Library *library = mtl->newLibrary(dispatchData, &error); + dispatch_release(dispatchData); + + if (error != nullptr) { + fprintf(stderr, "Failed to create resolve shader library: %s\n", error->localizedDescription()->utf8String()); + } + assert(library != nullptr && "Failed to create resolve shader library"); MTL::Function *resolveFunction = library->newFunction(NS::String::string("msaaResolve", NS::UTF8StringEncoding)); assert(resolveFunction != nullptr && "Failed to create resolve function"); @@ -4031,58 +4018,27 @@ namespace plume { resolveTexturePipelineState = mtl->newComputePipelineState(resolveFunction, &error); assert(resolveTexturePipelineState != nullptr && "Failed to create MSAA resolve pipeline state"); - // Destroy resolveFunction->release(); library->release(); } void MetalDevice::createClearShaderLibrary() { - const char* clear_shader = R"( - #include - using namespace metal; - - struct DepthClearFragmentOut { - float depth [[depth(any)]]; - }; - - struct VertexOutput { - float4 position [[position]]; - uint rect_index [[flat]]; - }; - - vertex VertexOutput clearVert(uint vid [[vertex_id]], - uint instance_id [[instance_id]], - constant float2* vertices [[buffer(0)]]) - { - VertexOutput out; - out.position = float4(vertices[vid], 0, 1); - out.rect_index = instance_id; - return out; - } - - // Color clear fragment shader - fragment float4 clearColorFrag(VertexOutput in [[stage_in]], - constant float4* clearColors [[buffer(0)]]) - { - return clearColors[in.rect_index]; - } - - // Depth clear fragment shader - fragment DepthClearFragmentOut clearDepthFrag(VertexOutput in [[stage_in]], - constant float* clearDepths [[buffer(0)]]) - { - DepthClearFragmentOut out; - out.depth = clearDepths[in.rect_index]; - return out; - } - )"; + // Load pre-compiled metallib from embedded data + dispatch_data_t dispatchData = dispatch_data_create( + plume_clear_metallib, + plume_clear_metallib_size, + nullptr, + DISPATCH_DATA_DESTRUCTOR_DEFAULT + ); NS::Error* error = nullptr; - MTL::Library *clearShaderLibrary = mtl->newLibrary(NS::String::string(clear_shader, NS::UTF8StringEncoding), nullptr, &error); + MTL::Library *clearShaderLibrary = mtl->newLibrary(dispatchData, &error); + dispatch_release(dispatchData); + if (error != nullptr) { - fprintf(stderr, "Error: %s\n", error->localizedDescription()->utf8String()); + fprintf(stderr, "Failed to create clear shader library: %s\n", error->localizedDescription()->utf8String()); } - assert(clearShaderLibrary != nullptr && "Failed to create clear color library"); + assert(clearShaderLibrary != nullptr && "Failed to create clear shader library"); // Create and cache the shader functions clearVertexFunction = clearShaderLibrary->newFunction(MTLSTR("clearVert")); diff --git a/shaders/plume_clear.metal b/shaders/plume_clear.metal new file mode 100644 index 0000000..12af163 --- /dev/null +++ b/shaders/plume_clear.metal @@ -0,0 +1,44 @@ +// +// plume +// +// Copyright (c) 2024 renderbag and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file for details. +// + +#include +using namespace metal; + +struct DepthClearFragmentOut { + float depth [[depth(any)]]; +}; + +struct VertexOutput { + float4 position [[position]]; + uint rect_index [[flat]]; +}; + +vertex VertexOutput clearVert(uint vid [[vertex_id]], + uint instance_id [[instance_id]], + constant float2* vertices [[buffer(0)]]) +{ + VertexOutput out; + out.position = float4(vertices[vid], 0, 1); + out.rect_index = instance_id; + return out; +} + +// Color clear fragment shader +fragment float4 clearColorFrag(VertexOutput in [[stage_in]], + constant float4* clearColors [[buffer(0)]]) +{ + return clearColors[in.rect_index]; +} + +// Depth clear fragment shader +fragment DepthClearFragmentOut clearDepthFrag(VertexOutput in [[stage_in]], + constant float* clearDepths [[buffer(0)]]) +{ + DepthClearFragmentOut out; + out.depth = clearDepths[in.rect_index]; + return out; +} diff --git a/shaders/plume_resolve.metal b/shaders/plume_resolve.metal new file mode 100644 index 0000000..92b8b97 --- /dev/null +++ b/shaders/plume_resolve.metal @@ -0,0 +1,35 @@ +// +// plume +// +// Copyright (c) 2024 renderbag and contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file for details. +// + +#include +using namespace metal; + +struct ResolveParams { + uint2 dstOffset; + uint2 srcOffset; + uint2 resolveSize; +}; + +kernel void msaaResolve( + texture2d_ms source [[texture(0)]], + texture2d destination [[texture(1)]], + constant ResolveParams& params [[buffer(0)]], + uint2 gid [[thread_position_in_grid]]) +{ + if (gid.x >= params.resolveSize.x || gid.y >= params.resolveSize.y) return; + + uint2 dstPos = gid + params.dstOffset; + uint2 srcPos = gid + params.srcOffset; + + float4 color = float4(0); + for (uint s = 0; s < source.get_num_samples(); s++) { + color += source.read(srcPos, s); + } + color /= float(source.get_num_samples()); + + destination.write(color, dstPos); +}