CMake: Simplify Metal shader build

Don't need multiple versions.
This commit is contained in:
Stenzek
2026-02-01 00:20:53 +10:00
parent 29241260a0
commit b330b3e7da
4 changed files with 51 additions and 70 deletions

View File

@@ -1,47 +1,32 @@
# Borrowed from PCSX2.
if(APPLE)
function(add_metal_sources target sources)
if(CMAKE_GENERATOR MATCHES "Xcode")
# If we're generating an xcode project, you can just add the shaders to the main pcsx2 target and xcode will deal with them properly
# This will make sure xcode supplies code completion, etc (if you use a custom command, it won't)
set_target_properties(${target} PROPERTIES
XCODE_ATTRIBUTE_MTL_ENABLE_DEBUG_INFO INCLUDE_SOURCE
function(add_metal_sources target sources library_name metal_std)
set(air_files)
set(compile_flags -std=${metal_std} -ffast-math)
foreach(source IN LISTS sources)
get_filename_component(source_name ${source} NAME)
set(air_file ${CMAKE_CURRENT_BINARY_DIR}/${library_name}/${source_name}.air)
list(APPEND air_files ${air_file})
add_custom_command(
OUTPUT ${air_file}
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/${library_name}
COMMAND xcrun metal ${compile_flags} -o ${air_file} -c ${source}
DEPENDS ${source}
COMMENT "Compiling Metal shader ${source_name}"
)
foreach(shader IN LISTS sources)
target_sources(${target} PRIVATE ${shader})
set_source_files_properties(${shader} PROPERTIES LANGUAGE METAL)
endforeach()
else()
function(generateMetallib std triple outputName)
set(MetalShaderOut)
set(flags
-ffast-math
$<$<NOT:$<CONFIG:Release,MinSizeRel>>:-gline-tables-only>
$<$<NOT:$<CONFIG:Release,MinSizeRel>>:-MO>
)
foreach(shader IN LISTS sources)
file(RELATIVE_PATH relativeShader "${CMAKE_SOURCE_DIR}" "${shader}")
set(shaderOut ${CMAKE_CURRENT_BINARY_DIR}/${outputName}/${relativeShader}.air)
list(APPEND MetalShaderOut ${shaderOut})
get_filename_component(shaderDir ${shaderOut} DIRECTORY)
add_custom_command(OUTPUT ${shaderOut}
COMMAND ${CMAKE_COMMAND} -E make_directory ${shaderDir}
COMMAND xcrun metal ${flags} -std=${std} -target ${triple} -o ${shaderOut} -c ${shader}
DEPENDS ${shader}
)
set(metallib ${CMAKE_CURRENT_BINARY_DIR}/${outputName}.metallib)
endforeach()
add_custom_command(OUTPUT ${metallib}
COMMAND xcrun metallib -o ${metallib} ${MetalShaderOut}
DEPENDS ${MetalShaderOut}
)
target_sources(${target} PRIVATE ${metallib})
set_source_files_properties(${metallib} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
endfunction()
generateMetallib(macos-metal2.0 air64-apple-macos10.13 default)
generateMetallib(macos-metal2.2 air64-apple-macos10.15 Metal22)
generateMetallib(macos-metal2.3 air64-apple-macos11.0 Metal23)
endif()
endforeach()
set(metallib_file ${CMAKE_CURRENT_BINARY_DIR}/${library_name}.metallib)
add_custom_command(
OUTPUT ${metallib_file}
COMMAND xcrun metallib -o ${metallib_file} ${air_files}
DEPENDS ${air_files}
COMMENT "Linking Metal library ${library_name}.metallib"
)
target_sources(${target} PRIVATE ${metallib_file})
set_source_files_properties(${metallib_file} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
endfunction()
endif()

View File

@@ -293,7 +293,7 @@ endif()
function(add_util_resources target)
if(APPLE)
get_property(UTIL_METAL_SOURCES GLOBAL PROPERTY UTIL_METAL_SOURCES)
add_metal_sources(${target} ${UTIL_METAL_SOURCES})
add_metal_sources(${target} ${UTIL_METAL_SOURCES} metal_shaders macos-metal2.3)
# Copy MoltenVK into the bundle
unset(MOLTENVK_PATH CACHE)

View File

@@ -374,7 +374,7 @@ private:
static_assert(sizeof(ClearPipelineConfig) == 8);
void SetFeatures(CreateFlags create_flags);
bool LoadShaders();
bool LoadShaders(Error* error);
std::unique_ptr<GPUShader> CreateShaderFromMSL(GPUShaderStage stage, std::string_view source,
std::string_view entry_point, Error* error);

View File

@@ -23,6 +23,11 @@
LOG_CHANNEL(GPUDevice);
// Can't include settings.h, nasty...
namespace EmuFolders {
extern std::string Resources;
}
// TODO: Disable hazard tracking and issue barriers explicitly.
// Used for shader "binaries".
@@ -356,11 +361,8 @@ bool MetalDevice::CreateDeviceAndMainSwapChain(std::string_view adapter, CreateF
RenderBlankFrame(static_cast<MetalSwapChain*>(m_main_swap_chain.get()));
}
if (!LoadShaders())
{
Error::SetStringView(error, "Failed to load shaders.");
if (!LoadShaders(error))
return false;
}
if (!CreateBuffers(error))
return false;
@@ -415,35 +417,29 @@ void MetalDevice::SetFeatures(CreateFlags create_flags)
!HasCreateFlag(create_flags, CreateFlags::DisableCompressedTextures) && m_device.supportsBCTextureCompression;
}
bool MetalDevice::LoadShaders()
bool MetalDevice::LoadShaders(Error* error)
{
@autoreleasepool
{
auto try_lib = [this](NSString* name) -> id<MTLLibrary> {
NSBundle* bundle = [NSBundle mainBundle];
NSString* path = [bundle pathForResource:name ofType:@"metallib"];
if (path == nil)
{
// Xcode places it alongside the binary.
path = [NSString stringWithFormat:@"%@/%@.metallib", [bundle bundlePath], name];
if (![[NSFileManager defaultManager] fileExistsAtPath:path])
return nil;
}
static constexpr const char* shader_lib_filename = "metal_shaders.metallib";
NSURL* url = [NSURL fileURLWithPath:path];
id<MTLLibrary> lib = [m_device newLibraryWithURL:url error:nil];
if (lib == nil)
return nil;
return [lib retain];
};
if (!(m_shaders = try_lib(@"Metal23")) && !(m_shaders = try_lib(@"Metal22")) &&
!(m_shaders = try_lib(@"Metal21")) && !(m_shaders = try_lib(@"default")))
std::string path = Path::Combine(EmuFolders::Resources, shader_lib_filename);
if (!FileSystem::FileExists(path.c_str()))
{
Error::SetStringFmt(error, "{} was not found", shader_lib_filename);
return false;
}
NSError* nserror = nil;
NSURL* url = [NSURL fileURLWithPath:CocoaTools::StringViewToNSString(path)];
id<MTLLibrary> lib = [m_device newLibraryWithURL:url error:&nserror];
if (lib == nil)
{
CocoaTools::NSErrorToErrorObject(error, "newLibraryWithURL failed: ", nserror);
return false;
}
m_shaders = [lib retain];
return true;
}
}