diff --git a/CMakeModules/DuckStationDependencies.cmake b/CMakeModules/DuckStationDependencies.cmake index 71d1cb041..52c3831b9 100644 --- a/CMakeModules/DuckStationDependencies.cmake +++ b/CMakeModules/DuckStationDependencies.cmake @@ -138,7 +138,7 @@ if(NOT WIN32) endif() if(NOT WIN32) - find_package(FFMPEG 8.1.0 COMPONENTS avcodec avformat avutil swresample swscale) + find_package(FFMPEG 8.1.1 COMPONENTS avcodec avformat avutil swresample swscale) if(NOT FFMPEG_FOUND) message(WARNING "FFmpeg not found, using bundled headers.") endif() diff --git a/CMakeModules/DuckStationUtils.cmake b/CMakeModules/DuckStationUtils.cmake index 62de8921c..6d2c8c6d0 100644 --- a/CMakeModules/DuckStationUtils.cmake +++ b/CMakeModules/DuckStationUtils.cmake @@ -378,3 +378,38 @@ function(add_resources TARGET DEST_SUBDIR SOURCE_DIR) endif() endforeach() endfunction() + +function(bundle_libraries TARGET) + unset(LIBRARY_SOURCES) + foreach(NAME IN LISTS ARGN) + get_target_property(dyn_lib_path ${NAME} IMPORTED_LOCATION_RELEASE) + get_target_property(dyn_lib_soname ${NAME} IMPORTED_SONAME_RELEASE) + if(dyn_lib_soname) + string(REPLACE "@rpath/" "" dyn_lib_soname_filename "${dyn_lib_soname}") + get_filename_component(dyn_lib_dir "${dyn_lib_path}" DIRECTORY) + set(dyn_lib_major_path "${dyn_lib_dir}/${dyn_lib_soname_filename}") + if(EXISTS "${dyn_lib_major_path}") + set(dyn_lib_path "${dyn_lib_major_path}") + else() + message(WARNING "Could not find major-versioned symlink for ${NAME}.") + endif() + else() + message(FATAL_ERROR "Could not find ${NAME}.") + endif() + + message(STATUS "Bundling imported library ${dyn_lib_soname}") + + if(APPLE) + target_sources(${target} PRIVATE "${dyn_lib_path}") + set_source_files_properties("${dyn_lib_path}" PROPERTIES MACOSX_PACKAGE_LOCATION Frameworks) + else() + list(APPEND LIBRARY_SOURCES "${dyn_lib_path}") + endif() + endforeach() + + if(NOT APPLE) + add_custom_command(TARGET ${TARGET} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${LIBRARY_SOURCES} "$" + ) + endif() +endfunction() diff --git a/scripts/appimage/make-appimage.sh b/scripts/appimage/make-appimage.sh index 9ca5557dc..3a26d564b 100755 --- a/scripts/appimage/make-appimage.sh +++ b/scripts/appimage/make-appimage.sh @@ -39,11 +39,8 @@ declare -a MANUAL_LIBS=( "libavutil.so.60" "libswscale.so.9" "libswresample.so.6" - "libdiscord-rpc.so" "libharfbuzz.so" "libfreetype.so.6" - "libshaderc_shared.so" - "libspirv-cross-c-shared.so.0" ) set -e @@ -119,6 +116,7 @@ $LINUXDEPLOY --plugin qt --appdir="$OUTDIR" --executable="$BUILDDIR/bin/duckstat echo "Copying resources into AppDir..." cp -a "$BUILDDIR/bin/resources" "$OUTDIR/usr/bin" +cp "$BUILDDIR/bin/"*.so* "$OUTDIR/usr/bin" # Restore unstripped deps (for cache). rm -fr "$DEPSDIR" diff --git a/src/common/dynamic_library.cpp b/src/common/dynamic_library.cpp index 72410d215..33cd880dc 100644 --- a/src/common/dynamic_library.cpp +++ b/src/common/dynamic_library.cpp @@ -88,6 +88,26 @@ std::string DynamicLibrary::GetVersionedFilename(const char* libname, int major, #endif } +std::string DynamicLibrary::GetBundledLibraryPath(const char* libname, int major /*= -1*/, int minor /*= -1*/, + int patch /*= -1*/) +{ + Error error; + std::string program_path = FileSystem::GetProgramPath(&error); + if (program_path.empty()) [[unlikely]] + { + ERROR_LOG("Failed to get program path: {}", error.GetDescription()); + return {}; + } + +#ifdef __APPLE__ + program_path = Path::Combine(Path::GetDirectory(program_path), ".." FS_OSPATH_SEPARATOR_STR "Frameworks"); + Path::Canonicalize(&program_path); + return Path::Combine(program_path, GetVersionedFilename(libname, major, minor, patch)); +#else + return Path::Combine(Path::GetDirectory(program_path), GetVersionedFilename(libname, major, minor, patch)); +#endif +} + bool DynamicLibrary::Open(const char* filename, Error* error) { #ifdef _WIN32 @@ -179,7 +199,8 @@ bool DynamicLibrary::ResolveSymbols(const SymbolTable* symbols, size_t count, Er return true; } -bool DynamicLibrary::ResolveSymbols(const OptionalSymbolTable* symbols, size_t count, Error* error /* = nullptr */) const +bool DynamicLibrary::ResolveSymbols(const OptionalSymbolTable* symbols, size_t count, + Error* error /* = nullptr */) const { for (size_t i = 0; i < count; i++) { @@ -206,7 +227,8 @@ bool DynamicLibrary::ResolveSymbols(const std::span symbols, return ResolveSymbols(symbols.data(), symbols.size(), error); } -bool DynamicLibrary::ResolveSymbols(const std::span symbols, Error* error /*= nullptr*/) const +bool DynamicLibrary::ResolveSymbols(const std::span symbols, + Error* error /*= nullptr*/) const { return ResolveSymbols(symbols.data(), symbols.size(), error); } diff --git a/src/common/dynamic_library.h b/src/common/dynamic_library.h index 4566a4b5f..d500992f4 100644 --- a/src/common/dynamic_library.h +++ b/src/common/dynamic_library.h @@ -39,6 +39,9 @@ public: /// Mac: libLIBNAME.MAJOR.MINOR.PATCH.dylib static std::string GetVersionedFilename(const char* libname, int major = -1, int minor = -1, int patch = -1); + /// Returns the path to the specified library name, depending on the platform. + static std::string GetBundledLibraryPath(const char* libname, int major = -1, int minor = -1, int patch = -1); + /// Returns true if a module is loaded, otherwise false. bool IsOpen() const { return m_handle != nullptr; } diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index f3f8a32f8..ca5e678af 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -215,10 +215,6 @@ function(add_core_resources target) add_resources(${target} "resources" ${CMAKE_SOURCE_DIR}/data/resources) - if(APPLE) - # Copy discord-rpc into the bundle - get_target_property(DISCORD_RPC_LIBRARY DiscordRPC::discord-rpc IMPORTED_LOCATION_RELEASE) - target_sources(${target} PRIVATE "${DISCORD_RPC_LIBRARY}") - set_source_files_properties("${DISCORD_RPC_LIBRARY}" PROPERTIES MACOSX_PACKAGE_LOCATION Frameworks) - endif() + # Copy dynamically-loaded libraries into the bundle. + bundle_libraries(${target} DiscordRPC::discord-rpc) endfunction() diff --git a/src/core/discord_presence.cpp b/src/core/discord_presence.cpp index 8d2cd7684..b2b4e5059 100644 --- a/src/core/discord_presence.cpp +++ b/src/core/discord_presence.cpp @@ -58,8 +58,7 @@ bool DiscordPresence::OpenDiscordRPC(Error* error) if (s_locals.rpc_library.IsOpen()) return true; - const std::string libname = DynamicLibrary::GetVersionedFilename("discord-rpc"); - if (!s_locals.rpc_library.Open(libname.c_str(), error)) + if (!s_locals.rpc_library.Open(DynamicLibrary::GetBundledLibraryPath("discord-rpc").c_str(), error)) { Error::AddPrefix(error, "Failed to load discord-rpc: "); return false; diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt index d06043fd8..e82131a19 100644 --- a/src/util/CMakeLists.txt +++ b/src/util/CMakeLists.txt @@ -90,7 +90,9 @@ add_library(util target_precompile_headers(util PRIVATE "pch.h") target_include_directories(util PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/..") target_link_libraries(util PUBLIC common imgui) -target_link_libraries(util PRIVATE libchdr lzma libjpeg-turbo::jpeg PNG::PNG WebP::webp plutosvg::plutosvg ZLIB::ZLIB SoundTouch::SoundTouchDLL xxhash zstd::libzstd_shared reshadefx) +target_link_libraries(util PRIVATE libchdr lzma libjpeg-turbo::jpeg PNG::png_shared WebP::webp + plutosvg::plutosvg ZLIB::ZLIB SoundTouch::SoundTouchDLL xxhash + zstd::libzstd_shared reshadefx) if(ENABLE_X11) target_sources(util PRIVATE @@ -303,39 +305,18 @@ function(add_util_resources target) message(WARNING "MoltenVK not found in path, it will depend on the target system having it.") endif() - # Copy dynamically-loaded libraries (harfbuzz/shaderc/spirv-cross) into the bundle. - # Use IMPORTED_SONAME_RELEASE to get the major-versioned filename (stripping the @rpath/ prefix). - foreach(dyn_lib harfbuzz::harfbuzz spirv-cross-c-shared Shaderc::shaderc_shared) - get_target_property(dyn_lib_path ${dyn_lib} IMPORTED_LOCATION_RELEASE) - get_target_property(dyn_lib_soname ${dyn_lib} IMPORTED_SONAME_RELEASE) - if(dyn_lib_soname) - string(REPLACE "@rpath/" "" dyn_lib_soname_filename "${dyn_lib_soname}") - get_filename_component(dyn_lib_dir "${dyn_lib_path}" DIRECTORY) - set(dyn_lib_major_path "${dyn_lib_dir}/${dyn_lib_soname_filename}") - if(EXISTS "${dyn_lib_major_path}") - set(dyn_lib_path "${dyn_lib_major_path}") - else() - message(WARNING "Could not find major-versioned symlink for ${dyn_lib}.") - endif() - endif() - target_sources(${target} PRIVATE "${dyn_lib_path}") - set_source_files_properties("${dyn_lib_path}" PROPERTIES MACOSX_PACKAGE_LOCATION Frameworks) - endforeach() - - # Copy FFmpeg libraries into the bundle + # Copy ffmpeg into the bundle. foreach(component avcodec avformat avutil swresample swscale) string(REGEX REPLACE "\([0-9]+\)\.[0-9]+\.[0-9]+" "\\1" major "${FFMPEG_${component}_VERSION}") string(REPLACE "lib${component}.dylib" "lib${component}.${major}.dylib" version_lib "${FFMPEG_${component}_LIBRARIES}") target_sources(${target} PRIVATE ${version_lib}) set_source_files_properties(${target} PRIVATE ${version_lib} PROPERTIES MACOSX_PACKAGE_LOCATION Frameworks) endforeach() - elseif(NOT WIN32) - # We need to add the rpath for shaderc to the executable. - get_target_property(SHADERC_LIBRARY Shaderc::shaderc_shared IMPORTED_LOCATION) - get_filename_component(SHADERC_LIBRARY_DIRECTORY ${SHADERC_LIBRARY} DIRECTORY) - set_target_properties(${target} PROPERTIES BUILD_RPATH "${SHADERC_LIBRARY_DIRECTORY}") - get_target_property(SPIRV_CROSS_LIBRARY spirv-cross-c-shared IMPORTED_LOCATION) - get_filename_component(SPIRV_CROSS_LIBRARY_DIRECTORY ${SPIRV_CROSS_LIBRARY} DIRECTORY) - set_target_properties(${target} PROPERTIES BUILD_RPATH "${SPIRV_CROSS_LIBRARY_DIRECTORY}") + endif() + + # Copy dynamically-loaded libraries (harfbuzz/shaderc/spirv-cross) into the bundle. + bundle_libraries(${target} spirv-cross-c-shared Shaderc::shaderc_shared) + if(APPLE) + bundle_libraries(${target} harfbuzz::harfbuzz) endif() endfunction() diff --git a/src/util/dyn_shaderc.h b/src/util/dyn_shaderc.h index e146fc583..033984886 100644 --- a/src/util/dyn_shaderc.h +++ b/src/util/dyn_shaderc.h @@ -24,13 +24,15 @@ X(shaderc_result_get_error_message) \ X(shaderc_optimize_spv) -namespace dyn_libs { - -extern bool OpenShaderc(Error* error); -extern shaderc_compiler_t GetShadercCompiler(); - -#define ADD_FUNC(F) extern decltype(&::F) F; -DYN_SHADERC_FUNCTIONS(ADD_FUNC) +struct DynShaderc +{ +#define ADD_FUNC(F) decltype(&::F) F; + DYN_SHADERC_FUNCTIONS(ADD_FUNC) #undef ADD_FUNC -} // namespace dyn_libs + shaderc_compiler_t compiler; + + bool Open(Error* error); +}; + +extern DynShaderc g_dyn_shaderc; diff --git a/src/util/dyn_spirv_cross.h b/src/util/dyn_spirv_cross.h index 9ee801db3..af7f4f174 100644 --- a/src/util/dyn_spirv_cross.h +++ b/src/util/dyn_spirv_cross.h @@ -46,13 +46,15 @@ class Error; #define SPIRV_CROSS_MSL_FUNCTIONS(X) #endif -namespace dyn_libs { -extern bool OpenSpirvCross(Error* error); - -#define ADD_FUNC(F) extern decltype(&::F) F; -SPIRV_CROSS_FUNCTIONS(ADD_FUNC) -SPIRV_CROSS_HLSL_FUNCTIONS(ADD_FUNC) -SPIRV_CROSS_MSL_FUNCTIONS(ADD_FUNC) +struct DynSpirvCross +{ +#define ADD_FUNC(F) decltype(&::F) F; + SPIRV_CROSS_FUNCTIONS(ADD_FUNC) + SPIRV_CROSS_HLSL_FUNCTIONS(ADD_FUNC) + SPIRV_CROSS_MSL_FUNCTIONS(ADD_FUNC) #undef ADD_FUNC -} // namespace dyn_libs \ No newline at end of file + bool Open(Error* error); +}; + +extern DynSpirvCross g_dyn_spirv_cross; diff --git a/src/util/gpu_device.cpp b/src/util/gpu_device.cpp index a0fa023a7..4ed396ca0 100644 --- a/src/util/gpu_device.cpp +++ b/src/util/gpu_device.cpp @@ -59,7 +59,6 @@ struct Locals // Dynamic libraries DynamicLibrary shaderc_library; DynamicLibrary spirv_cross_library; - shaderc_compiler_t shaderc_compiler; std::once_flag shaderc_init_flag; std::once_flag spirv_cross_init_flag; }; @@ -67,6 +66,11 @@ struct Locals ALIGN_TO_CACHE_LINE static Locals s_locals; +static_assert(std::is_trivially_copyable_v && std::is_standard_layout_v); +static_assert(std::is_trivially_copyable_v && std::is_standard_layout_v); +DynShaderc g_dyn_shaderc; +DynSpirvCross g_dyn_spirv_cross; + size_t GPUDevice::s_total_vram_usage = 0; GPUDevice::Statistics GPUDevice::s_stats = {}; @@ -1384,148 +1388,85 @@ std::unique_ptr GPUDevice::CreateDeviceForAPI(RenderAPI api) } } -namespace dyn_libs { -static void InitializeShaderc(Error* error); -static void CloseShaderc(); -static void InitializeSpirvCross(Error* error); -static void CloseSpirvCross(); - -// TODO: Merge all of these into a struct? -#define ADD_FUNC(F) decltype(&::F) F; -DYN_SHADERC_FUNCTIONS(ADD_FUNC) -SPIRV_CROSS_FUNCTIONS(ADD_FUNC) -SPIRV_CROSS_HLSL_FUNCTIONS(ADD_FUNC) -SPIRV_CROSS_MSL_FUNCTIONS(ADD_FUNC) -#undef ADD_FUNC - -} // namespace dyn_libs - -bool dyn_libs::OpenShaderc(Error* error) +bool DynShaderc::Open(Error* error) { - if (s_locals.shaderc_library.IsOpen()) + if (compiler) return true; - std::call_once(s_locals.shaderc_init_flag, [&error]() { InitializeShaderc(error); }); - return s_locals.shaderc_library.IsOpen(); -} + std::call_once(s_locals.shaderc_init_flag, [&error]() { + Error lerror; + DynamicLibrary lib; + if (!lib.Open(DynamicLibrary::GetBundledLibraryPath("shaderc_shared").c_str(), error)) + { + ERROR_LOG("Failed to load shaderc: {}", (error ? error : &lerror)->GetDescription()); + Error::AddPrefix(error, "Failed to load shaderc: "); + return; + } -void dyn_libs::InitializeShaderc(Error* error) -{ - Error lerror; - DynamicLibrary lib; - const std::string libname = DynamicLibrary::GetVersionedFilename("shaderc_shared"); - if (!lib.Open(libname.c_str(), error)) - { - ERROR_LOG("Failed to load shaderc: {}", (error ? error : &lerror)->GetDescription()); - Error::AddPrefix(error, "Failed to load shaderc: "); - return; - } - - static const DynamicLibrary::SymbolTable shaderc_symbols[] = { -#define SHADERC_SYMBOL(F) {#F, (void**)&F}, - DYN_SHADERC_FUNCTIONS(SHADERC_SYMBOL) + static const DynamicLibrary::SymbolTable shaderc_symbols[] = { +#define SHADERC_SYMBOL(F) {#F, (void**)&g_dyn_shaderc.F}, + DYN_SHADERC_FUNCTIONS(SHADERC_SYMBOL) #undef SHADERC_SYMBOL - }; + }; - if (!lib.ResolveSymbols(shaderc_symbols, std::size(shaderc_symbols), error)) - { - CloseShaderc(); - return; - } + if (!lib.ResolveSymbols(shaderc_symbols, error)) + return; - s_locals.shaderc_compiler = shaderc_compiler_initialize(); - if (!s_locals.shaderc_compiler) - { - ERROR_LOG("shaderc_compiler_initialize() failed"); - Error::SetStringView(error, "shaderc_compiler_initialize() failed"); - CloseShaderc(); - return; - } + g_dyn_shaderc.compiler = g_dyn_shaderc.shaderc_compiler_initialize(); + if (!g_dyn_shaderc.compiler) + { + ERROR_LOG("shaderc_compiler_initialize() failed"); + Error::SetStringView(error, "shaderc_compiler_initialize() failed"); + DynamicLibrary::ClearSymbols(shaderc_symbols); + return; + } - s_locals.shaderc_library = std::move(lib); + s_locals.shaderc_library = std::move(lib); + }); + + return (compiler != nullptr); } -shaderc_compiler_t dyn_libs::GetShadercCompiler() -{ - return s_locals.shaderc_compiler; -} - -void dyn_libs::CloseShaderc() -{ - if (s_locals.shaderc_compiler) - { - shaderc_compiler_release(s_locals.shaderc_compiler); - s_locals.shaderc_compiler = nullptr; - } - -#define UNLOAD_FUNC(F) F = nullptr; - DYN_SHADERC_FUNCTIONS(UNLOAD_FUNC) -#undef UNLOAD_FUNC - - s_locals.shaderc_library.Close(); -} - -bool dyn_libs::OpenSpirvCross(Error* error) +bool DynSpirvCross::Open(Error* error) { if (s_locals.spirv_cross_library.IsOpen()) return true; - std::call_once(s_locals.spirv_cross_init_flag, [&error]() { InitializeSpirvCross(error); }); - return s_locals.spirv_cross_library.IsOpen(); -} - -void dyn_libs::InitializeSpirvCross(Error* error) -{ - Error lerror; - DynamicLibrary lib; + std::call_once(s_locals.spirv_cross_init_flag, [&error]() { + Error lerror; + DynamicLibrary lib; #if defined(_WIN32) || defined(__ANDROID__) - // SPVC's build on Windows doesn't spit out a versioned DLL. - const std::string libname = DynamicLibrary::GetVersionedFilename("spirv-cross-c-shared"); + // SPVC's build on Windows doesn't spit out a versioned DLL. + const std::string libpath = DynamicLibrary::GetBundledLibraryPath("spirv-cross-c-shared"); #else - const std::string libname = DynamicLibrary::GetVersionedFilename("spirv-cross-c-shared", SPVC_C_API_VERSION_MAJOR); + const std::string libpath = DynamicLibrary::GetBundledLibraryPath("spirv-cross-c-shared", SPVC_C_API_VERSION_MAJOR); #endif - if (!lib.Open(libname.c_str(), error ? error : &lerror)) - { - ERROR_LOG("Failed to load spirv-cross: {}", (error ? error : &lerror)->GetDescription()); - Error::AddPrefix(error, "Failed to load spirv-cross: "); - return; - } + if (!lib.Open(libpath.c_str(), error ? error : &lerror)) + { + ERROR_LOG("Failed to load spirv-cross: {}", (error ? error : &lerror)->GetDescription()); + Error::AddPrefix(error, "Failed to load spirv-cross: "); + return; + } - // clang-format off + // clang-format off static const DynamicLibrary::SymbolTable spirv_cross_symbols[] = { -#define SPIRV_CROSS_SYMBOL(F) {#F, (void**)&F}, +#define SPIRV_CROSS_SYMBOL(F) {#F, (void**)&g_dyn_spirv_cross.F}, SPIRV_CROSS_FUNCTIONS(SPIRV_CROSS_SYMBOL) SPIRV_CROSS_HLSL_FUNCTIONS(SPIRV_CROSS_SYMBOL) SPIRV_CROSS_MSL_FUNCTIONS(SPIRV_CROSS_SYMBOL) #undef SPIRV_CROSS_SYMBOL }; - // clang-format on + // clang-format on - if (!lib.ResolveSymbols(spirv_cross_symbols, std::size(spirv_cross_symbols), error)) - { - CloseShaderc(); - return; - } + if (!lib.ResolveSymbols(spirv_cross_symbols, std::size(spirv_cross_symbols), error)) + return; - s_locals.spirv_cross_library = std::move(lib); + s_locals.spirv_cross_library = std::move(lib); + }); + + return s_locals.spirv_cross_library.IsOpen(); } -void dyn_libs::CloseSpirvCross() -{ -#define UNLOAD_FUNC(F) F = nullptr; - SPIRV_CROSS_FUNCTIONS(UNLOAD_FUNC) - SPIRV_CROSS_HLSL_FUNCTIONS(UNLOAD_FUNC) - SPIRV_CROSS_MSL_FUNCTIONS(UNLOAD_FUNC) -#undef UNLOAD_FUNC - - s_locals.spirv_cross_library.Close(); -} - -#undef SPIRV_CROSS_HLSL_FUNCTIONS -#undef SPIRV_CROSS_MSL_FUNCTIONS -#undef SPIRV_CROSS_FUNCTIONS -#undef DYN_SHADERC_FUNCTIONS - std::optional> GPUDevice::OptimizeVulkanSpv(const std::span spirv, Error* error) { std::optional> ret; @@ -1552,34 +1493,35 @@ std::optional> GPUDevice::OptimizeVulkanSpv(const std::span else target_version = shaderc_env_version_vulkan_1_1; - if (!dyn_libs::OpenShaderc(error)) + if (!g_dyn_shaderc.Open(error)) return ret; - const shaderc_compile_options_t options = dyn_libs::shaderc_compile_options_initialize(); + const shaderc_compile_options_t options = g_dyn_shaderc.shaderc_compile_options_initialize(); AssertMsg(options, "shaderc_compile_options_initialize() failed"); - dyn_libs::shaderc_compile_options_set_target_env(options, target_env, target_version); - dyn_libs::shaderc_compile_options_set_optimization_level(options, shaderc_optimization_level_performance); + g_dyn_shaderc.shaderc_compile_options_set_target_env(options, target_env, target_version); + g_dyn_shaderc.shaderc_compile_options_set_optimization_level(options, shaderc_optimization_level_performance); const shaderc_compilation_result_t result = - dyn_libs::shaderc_optimize_spv(s_locals.shaderc_compiler, spirv.data(), spirv.size(), options); + g_dyn_shaderc.shaderc_optimize_spv(g_dyn_shaderc.compiler, spirv.data(), spirv.size(), options); const shaderc_compilation_status status = - result ? dyn_libs::shaderc_result_get_compilation_status(result) : shaderc_compilation_status_internal_error; + result ? g_dyn_shaderc.shaderc_result_get_compilation_status(result) : shaderc_compilation_status_internal_error; if (status != shaderc_compilation_status_success) { - const std::string_view errors(result ? dyn_libs::shaderc_result_get_error_message(result) : "null result object"); + const std::string_view errors(result ? g_dyn_shaderc.shaderc_result_get_error_message(result) : + "null result object"); Error::SetStringFmt(error, "Failed to optimize SPIR-V: {}\n{}", - dyn_libs::shaderc_compilation_status_to_string(status), errors); + g_dyn_shaderc.shaderc_compilation_status_to_string(status), errors); } else { - const size_t spirv_size = dyn_libs::shaderc_result_get_length(result); + const size_t spirv_size = g_dyn_shaderc.shaderc_result_get_length(result); DebugAssert(spirv_size > 0); ret = DynamicHeapArray(spirv_size); - std::memcpy(ret->data(), dyn_libs::shaderc_result_get_bytes(result), spirv_size); + std::memcpy(ret->data(), g_dyn_shaderc.shaderc_result_get_bytes(result), spirv_size); } - dyn_libs::shaderc_result_release(result); - dyn_libs::shaderc_compile_options_release(options); + g_dyn_shaderc.shaderc_result_release(result); + g_dyn_shaderc.shaderc_compile_options_release(options); return ret; } @@ -1602,47 +1544,48 @@ bool GPUDevice::CompileGLSLShaderToVulkanSpv(GPUShaderStage stage, GPUShaderLang return false; } - if (!dyn_libs::OpenShaderc(error)) + if (!g_dyn_shaderc.Open(error)) return false; - const shaderc_compile_options_t options = dyn_libs::shaderc_compile_options_initialize(); + const shaderc_compile_options_t options = g_dyn_shaderc.shaderc_compile_options_initialize(); AssertMsg(options, "shaderc_compile_options_initialize() failed"); - dyn_libs::shaderc_compile_options_set_source_language(options, shaderc_source_language_glsl); - dyn_libs::shaderc_compile_options_set_target_env(options, shaderc_target_env_vulkan, 0); - dyn_libs::shaderc_compile_options_set_generate_debug_info(options, m_debug_device, - m_debug_device && nonsemantic_debug_info); - dyn_libs::shaderc_compile_options_set_optimization_level( + g_dyn_shaderc.shaderc_compile_options_set_source_language(options, shaderc_source_language_glsl); + g_dyn_shaderc.shaderc_compile_options_set_target_env(options, shaderc_target_env_vulkan, 0); + g_dyn_shaderc.shaderc_compile_options_set_generate_debug_info(options, m_debug_device, + m_debug_device && nonsemantic_debug_info); + g_dyn_shaderc.shaderc_compile_options_set_optimization_level( options, optimization ? shaderc_optimization_level_performance : shaderc_optimization_level_zero); const shaderc_compilation_result_t result = - dyn_libs::shaderc_compile_into_spv(s_locals.shaderc_compiler, source.data(), source.length(), - stage_kinds[static_cast(stage)], "source", entry_point, options); + g_dyn_shaderc.shaderc_compile_into_spv(g_dyn_shaderc.compiler, source.data(), source.length(), + stage_kinds[static_cast(stage)], "source", entry_point, options); const shaderc_compilation_status status = - result ? dyn_libs::shaderc_result_get_compilation_status(result) : shaderc_compilation_status_internal_error; + result ? g_dyn_shaderc.shaderc_result_get_compilation_status(result) : shaderc_compilation_status_internal_error; if (status != shaderc_compilation_status_success) { - const std::string_view errors(result ? dyn_libs::shaderc_result_get_error_message(result) : "null result object"); + const std::string_view errors(result ? g_dyn_shaderc.shaderc_result_get_error_message(result) : + "null result object"); Error::SetStringFmt(error, "Failed to compile shader to SPIR-V: {}\n{}", - dyn_libs::shaderc_compilation_status_to_string(status), errors); - ERROR_LOG("Failed to compile shader to SPIR-V: {}\n{}", dyn_libs::shaderc_compilation_status_to_string(status), + g_dyn_shaderc.shaderc_compilation_status_to_string(status), errors); + ERROR_LOG("Failed to compile shader to SPIR-V: {}\n{}", g_dyn_shaderc.shaderc_compilation_status_to_string(status), errors); DumpBadShader(source, errors); } else { - const size_t num_warnings = dyn_libs::shaderc_result_get_num_warnings(result); + const size_t num_warnings = g_dyn_shaderc.shaderc_result_get_num_warnings(result); if (num_warnings > 0) - WARNING_LOG("Shader compiled with warnings:\n{}", dyn_libs::shaderc_result_get_error_message(result)); + WARNING_LOG("Shader compiled with warnings:\n{}", g_dyn_shaderc.shaderc_result_get_error_message(result)); - const size_t spirv_size = dyn_libs::shaderc_result_get_length(result); + const size_t spirv_size = g_dyn_shaderc.shaderc_result_get_length(result); DebugAssert(spirv_size > 0); out_binary->resize(spirv_size); - std::memcpy(out_binary->data(), dyn_libs::shaderc_result_get_bytes(result), spirv_size); + std::memcpy(out_binary->data(), g_dyn_shaderc.shaderc_result_get_bytes(result), spirv_size); } - dyn_libs::shaderc_result_release(result); - dyn_libs::shaderc_compile_options_release(options); + g_dyn_shaderc.shaderc_result_release(result); + g_dyn_shaderc.shaderc_compile_options_release(options); return (status == shaderc_compilation_status_success); } @@ -1650,20 +1593,20 @@ bool GPUDevice::TranslateVulkanSpvToLanguage(const std::span spirv, GP GPUShaderLanguage target_language, u32 target_version, std::string* output, Error* error) { - if (!dyn_libs::OpenSpirvCross(error)) + if (!g_dyn_spirv_cross.Open(error)) return false; spvc_context sctx; spvc_result sres; - if ((sres = dyn_libs::spvc_context_create(&sctx)) != SPVC_SUCCESS) + if ((sres = g_dyn_spirv_cross.spvc_context_create(&sctx)) != SPVC_SUCCESS) { Error::SetStringFmt(error, "spvc_context_create() failed: {}", static_cast(sres)); return false; } - const ScopedGuard sctx_guard = [&sctx]() { dyn_libs::spvc_context_destroy(sctx); }; + const ScopedGuard sctx_guard = [&sctx]() { g_dyn_spirv_cross.spvc_context_destroy(sctx); }; - dyn_libs::spvc_context_set_error_callback( + g_dyn_spirv_cross.spvc_context_set_error_callback( sctx, [](void* error, const char* errormsg) { ERROR_LOG("SPIRV-Cross reported an error: {}", errormsg); @@ -1672,8 +1615,8 @@ bool GPUDevice::TranslateVulkanSpvToLanguage(const std::span spirv, GP error); spvc_parsed_ir sir; - if ((sres = dyn_libs::spvc_context_parse_spirv(sctx, reinterpret_cast(spirv.data()), spirv.size() / 4, - &sir)) != SPVC_SUCCESS) + if ((sres = g_dyn_spirv_cross.spvc_context_parse_spirv(sctx, reinterpret_cast(spirv.data()), + spirv.size() / 4, &sir)) != SPVC_SUCCESS) { Error::SetStringFmt(error, "spvc_context_parse_spirv() failed: {}", static_cast(sres)); return {}; @@ -1684,22 +1627,23 @@ bool GPUDevice::TranslateVulkanSpvToLanguage(const std::span spirv, GP SPVC_BACKEND_NONE}}; spvc_compiler scompiler; - if ((sres = dyn_libs::spvc_context_create_compiler(sctx, backends[static_cast(target_language)], sir, - SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, &scompiler)) != SPVC_SUCCESS) + if ((sres = g_dyn_spirv_cross.spvc_context_create_compiler(sctx, backends[static_cast(target_language)], sir, + SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, &scompiler)) != + SPVC_SUCCESS) { Error::SetStringFmt(error, "spvc_context_create_compiler() failed: {}", static_cast(sres)); return {}; } spvc_compiler_options soptions; - if ((sres = dyn_libs::spvc_compiler_create_compiler_options(scompiler, &soptions)) != SPVC_SUCCESS) + if ((sres = g_dyn_spirv_cross.spvc_compiler_create_compiler_options(scompiler, &soptions)) != SPVC_SUCCESS) { Error::SetStringFmt(error, "spvc_compiler_create_compiler_options() failed: {}", static_cast(sres)); return {}; } spvc_resources resources; - if ((sres = dyn_libs::spvc_compiler_create_shader_resources(scompiler, &resources)) != SPVC_SUCCESS) + if ((sres = g_dyn_spirv_cross.spvc_compiler_create_shader_resources(scompiler, &resources)) != SPVC_SUCCESS) { Error::SetStringFmt(error, "spvc_compiler_create_shader_resources() failed: {}", static_cast(sres)); return {}; @@ -1708,20 +1652,20 @@ bool GPUDevice::TranslateVulkanSpvToLanguage(const std::span spirv, GP // Need to know if there's UBOs for mapping. const spvc_reflected_resource *ubos, *push_constants, *textures, *images; size_t ubos_count, push_constants_count, textures_count, images_count; - if ((sres = dyn_libs::spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_UNIFORM_BUFFER, &ubos, - &ubos_count)) != SPVC_SUCCESS || - (sres = dyn_libs::spvc_resources_get_resource_list_for_type( + if ((sres = g_dyn_spirv_cross.spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_UNIFORM_BUFFER, + &ubos, &ubos_count)) != SPVC_SUCCESS || + (sres = g_dyn_spirv_cross.spvc_resources_get_resource_list_for_type( resources, SPVC_RESOURCE_TYPE_PUSH_CONSTANT, &push_constants, &push_constants_count)) != SPVC_SUCCESS || - (sres = dyn_libs::spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_SAMPLED_IMAGE, - &textures, &textures_count)) != SPVC_SUCCESS || - (sres = dyn_libs::spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_STORAGE_IMAGE, &images, - &images_count)) != SPVC_SUCCESS) + (sres = g_dyn_spirv_cross.spvc_resources_get_resource_list_for_type( + resources, SPVC_RESOURCE_TYPE_SAMPLED_IMAGE, &textures, &textures_count)) != SPVC_SUCCESS || + (sres = g_dyn_spirv_cross.spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_STORAGE_IMAGE, + &images, &images_count)) != SPVC_SUCCESS) { Error::SetStringFmt(error, "spvc_resources_get_resource_list_for_type() failed: {}", static_cast(sres)); return {}; } - [[maybe_unused]] const SpvExecutionModel execmodel = dyn_libs::spvc_compiler_get_execution_model(scompiler); + [[maybe_unused]] const SpvExecutionModel execmodel = g_dyn_spirv_cross.spvc_compiler_get_execution_model(scompiler); [[maybe_unused]] static constexpr u32 UBO_DESCRIPTOR_SET = 0; [[maybe_unused]] static constexpr u32 TEXTURE_DESCRIPTOR_SET = 1; [[maybe_unused]] static constexpr u32 IMAGE_DESCRIPTOR_SET = 2; @@ -1735,8 +1679,8 @@ bool GPUDevice::TranslateVulkanSpvToLanguage(const std::span spirv, GP { const spvc_reflected_resource* inputs; size_t inputs_count; - if ((sres = dyn_libs::spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_STAGE_INPUT, - &inputs, &inputs_count)) != SPVC_SUCCESS) + if ((sres = g_dyn_spirv_cross.spvc_resources_get_resource_list_for_type( + resources, SPVC_RESOURCE_TYPE_STAGE_INPUT, &inputs, &inputs_count)) != SPVC_SUCCESS) { Error::SetStringFmt(error, "spvc_resources_get_resource_list_for_type() for vertex attributes failed: {}", static_cast(sres)); @@ -1745,10 +1689,12 @@ bool GPUDevice::TranslateVulkanSpvToLanguage(const std::span spirv, GP for (const spvc_reflected_resource& res : std::span(inputs, inputs_count)) { - const unsigned location = dyn_libs::spvc_compiler_get_decoration(scompiler, res.id, SpvDecorationLocation); + const unsigned location = + g_dyn_spirv_cross.spvc_compiler_get_decoration(scompiler, res.id, SpvDecorationLocation); const TinyString name = TinyString::from_format("ATTR{}", location); const spvc_hlsl_vertex_attribute_remap va = {.location = location, .semantic = name.c_str()}; - if ((sres = dyn_libs::spvc_compiler_hlsl_add_vertex_attribute_remap(scompiler, &va, 1)) != SPVC_SUCCESS) + if ((sres = g_dyn_spirv_cross.spvc_compiler_hlsl_add_vertex_attribute_remap(scompiler, &va, 1)) != + SPVC_SUCCESS) { Error::SetStringFmt(error, "spvc_compiler_hlsl_add_vertex_attribute_remap() failed: {}", static_cast(sres)); @@ -1757,15 +1703,15 @@ bool GPUDevice::TranslateVulkanSpvToLanguage(const std::span spirv, GP } } - if ((sres = dyn_libs::spvc_compiler_options_set_uint(soptions, SPVC_COMPILER_OPTION_HLSL_SHADER_MODEL, - target_version)) != SPVC_SUCCESS) + if ((sres = g_dyn_spirv_cross.spvc_compiler_options_set_uint(soptions, SPVC_COMPILER_OPTION_HLSL_SHADER_MODEL, + target_version)) != SPVC_SUCCESS) { Error::SetStringFmt(error, "spvc_compiler_options_set_uint(SPVC_COMPILER_OPTION_HLSL_SHADER_MODEL) failed: {}", static_cast(sres)); return {}; } - if ((sres = dyn_libs::spvc_compiler_options_set_bool( + if ((sres = g_dyn_spirv_cross.spvc_compiler_options_set_bool( soptions, SPVC_COMPILER_OPTION_HLSL_SUPPORT_NONZERO_BASE_VERTEX_BASE_INSTANCE, false)) != SPVC_SUCCESS) { Error::SetStringFmt(error, @@ -1775,8 +1721,8 @@ bool GPUDevice::TranslateVulkanSpvToLanguage(const std::span spirv, GP return {}; } - if ((sres = dyn_libs::spvc_compiler_options_set_bool(soptions, SPVC_COMPILER_OPTION_HLSL_POINT_SIZE_COMPAT, - true)) != SPVC_SUCCESS) + if ((sres = g_dyn_spirv_cross.spvc_compiler_options_set_bool( + soptions, SPVC_COMPILER_OPTION_HLSL_POINT_SIZE_COMPAT, true)) != SPVC_SUCCESS) { Error::SetStringFmt(error, "spvc_compiler_options_set_bool(SPVC_COMPILER_OPTION_HLSL_POINT_SIZE_COMPAT) failed: {}", @@ -1793,7 +1739,7 @@ bool GPUDevice::TranslateVulkanSpvToLanguage(const std::span spirv, GP .uav = {}, .srv = {}, .sampler = {}}; - if ((sres = dyn_libs::spvc_compiler_hlsl_add_resource_binding(scompiler, &rb)) != SPVC_SUCCESS) + if ((sres = g_dyn_spirv_cross.spvc_compiler_hlsl_add_resource_binding(scompiler, &rb)) != SPVC_SUCCESS) { Error::SetStringFmt(error, "spvc_compiler_hlsl_add_resource_binding() for UBO failed: {}", static_cast(sres)); @@ -1810,7 +1756,7 @@ bool GPUDevice::TranslateVulkanSpvToLanguage(const std::span spirv, GP .uav = {}, .srv = {}, .sampler = {}}; - if ((sres = dyn_libs::spvc_compiler_hlsl_add_resource_binding(scompiler, &rb)) != SPVC_SUCCESS) + if ((sres = g_dyn_spirv_cross.spvc_compiler_hlsl_add_resource_binding(scompiler, &rb)) != SPVC_SUCCESS) { Error::SetStringFmt(error, "spvc_compiler_hlsl_add_resource_binding() for push constant failed: {}", static_cast(sres)); @@ -1822,7 +1768,8 @@ bool GPUDevice::TranslateVulkanSpvToLanguage(const std::span spirv, GP { for (u32 i = 0; i < textures_count; i++) { - const u32 binding = dyn_libs::spvc_compiler_get_decoration(scompiler, textures[i].id, SpvDecorationBinding); + const u32 binding = + g_dyn_spirv_cross.spvc_compiler_get_decoration(scompiler, textures[i].id, SpvDecorationBinding); const spvc_hlsl_resource_binding rb = {.stage = execmodel, .desc_set = TEXTURE_DESCRIPTOR_SET, @@ -1831,7 +1778,7 @@ bool GPUDevice::TranslateVulkanSpvToLanguage(const std::span spirv, GP .uav = {}, .srv = {.register_space = 0, .register_binding = binding}, .sampler = {.register_space = 0, .register_binding = binding}}; - if ((sres = dyn_libs::spvc_compiler_hlsl_add_resource_binding(scompiler, &rb)) != SPVC_SUCCESS) + if ((sres = g_dyn_spirv_cross.spvc_compiler_hlsl_add_resource_binding(scompiler, &rb)) != SPVC_SUCCESS) { Error::SetStringFmt(error, "spvc_compiler_hlsl_add_resource_binding() for texture failed: {}", static_cast(sres)); @@ -1851,7 +1798,7 @@ bool GPUDevice::TranslateVulkanSpvToLanguage(const std::span spirv, GP .uav = {.register_space = 0, .register_binding = i}, .srv = {}, .sampler = {}}; - if ((sres = dyn_libs::spvc_compiler_hlsl_add_resource_binding(scompiler, &rb)) != SPVC_SUCCESS) + if ((sres = g_dyn_spirv_cross.spvc_compiler_hlsl_add_resource_binding(scompiler, &rb)) != SPVC_SUCCESS) { Error::SetStringFmt(error, "spvc_compiler_hlsl_add_resource_binding() for image failed: {}", static_cast(sres)); @@ -1867,8 +1814,8 @@ bool GPUDevice::TranslateVulkanSpvToLanguage(const std::span spirv, GP case GPUShaderLanguage::GLSL: case GPUShaderLanguage::GLSLES: { - if ((sres = dyn_libs::spvc_compiler_options_set_uint(soptions, SPVC_COMPILER_OPTION_GLSL_VERSION, - target_version)) != SPVC_SUCCESS) + if ((sres = g_dyn_spirv_cross.spvc_compiler_options_set_uint(soptions, SPVC_COMPILER_OPTION_GLSL_VERSION, + target_version)) != SPVC_SUCCESS) { Error::SetStringFmt(error, "spvc_compiler_options_set_uint(SPVC_COMPILER_OPTION_GLSL_VERSION) failed: {}", static_cast(sres)); @@ -1876,7 +1823,7 @@ bool GPUDevice::TranslateVulkanSpvToLanguage(const std::span spirv, GP } const bool is_gles = (target_language == GPUShaderLanguage::GLSLES); - if ((sres = dyn_libs::spvc_compiler_options_set_bool(soptions, SPVC_COMPILER_OPTION_GLSL_ES, is_gles)) != + if ((sres = g_dyn_spirv_cross.spvc_compiler_options_set_bool(soptions, SPVC_COMPILER_OPTION_GLSL_ES, is_gles)) != SPVC_SUCCESS) { Error::SetStringFmt(error, "spvc_compiler_options_set_bool(SPVC_COMPILER_OPTION_GLSL_ES) failed: {}", @@ -1885,8 +1832,8 @@ bool GPUDevice::TranslateVulkanSpvToLanguage(const std::span spirv, GP } const bool enable_420pack = (is_gles ? (target_version >= 310) : (target_version >= 420)); - if ((sres = dyn_libs::spvc_compiler_options_set_bool(soptions, SPVC_COMPILER_OPTION_GLSL_ENABLE_420PACK_EXTENSION, - enable_420pack)) != SPVC_SUCCESS) + if ((sres = g_dyn_spirv_cross.spvc_compiler_options_set_bool( + soptions, SPVC_COMPILER_OPTION_GLSL_ENABLE_420PACK_EXTENSION, enable_420pack)) != SPVC_SUCCESS) { Error::SetStringFmt( error, "spvc_compiler_options_set_bool(SPVC_COMPILER_OPTION_GLSL_ENABLE_420PACK_EXTENSION) failed: {}", @@ -1897,16 +1844,16 @@ bool GPUDevice::TranslateVulkanSpvToLanguage(const std::span spirv, GP if (ubos_count > 0) { // Set name of UBO block to match our shaders, so that drivers without binding info can still find it. - dyn_libs::spvc_compiler_set_name(scompiler, ubos[0].id, "UBOBlock"); + g_dyn_spirv_cross.spvc_compiler_set_name(scompiler, ubos[0].id, "UBOBlock"); } if (push_constants_count > 0) { // Set name of push constant block to match our shaders, so that drivers without binding info can still find it. - dyn_libs::spvc_compiler_set_name(scompiler, push_constants[0].id, "PushConstants"); - dyn_libs::spvc_compiler_set_decoration(scompiler, push_constants[0].id, SpvDecorationBinding, 1); + g_dyn_spirv_cross.spvc_compiler_set_name(scompiler, push_constants[0].id, "PushConstants"); + g_dyn_spirv_cross.spvc_compiler_set_decoration(scompiler, push_constants[0].id, SpvDecorationBinding, 1); - if ((sres = dyn_libs::spvc_compiler_options_set_bool( + if ((sres = g_dyn_spirv_cross.spvc_compiler_options_set_bool( soptions, SPVC_COMPILER_OPTION_GLSL_EMIT_PUSH_CONSTANT_AS_UNIFORM_BUFFER, SPVC_TRUE)) != SPVC_SUCCESS) { Error::SetStringFmt( @@ -1923,7 +1870,7 @@ bool GPUDevice::TranslateVulkanSpvToLanguage(const std::span spirv, GP #ifdef __APPLE__ case GPUShaderLanguage::MSL: { - if ((sres = dyn_libs::spvc_compiler_options_set_bool( + if ((sres = g_dyn_spirv_cross.spvc_compiler_options_set_bool( soptions, SPVC_COMPILER_OPTION_MSL_PAD_FRAGMENT_OUTPUT_COMPONENTS, true)) != SPVC_SUCCESS) { Error::SetStringFmt( @@ -1932,8 +1879,9 @@ bool GPUDevice::TranslateVulkanSpvToLanguage(const std::span spirv, GP return {}; } - if ((sres = dyn_libs::spvc_compiler_options_set_bool(soptions, SPVC_COMPILER_OPTION_MSL_FRAMEBUFFER_FETCH_SUBPASS, - m_features.framebuffer_fetch)) != SPVC_SUCCESS) + if ((sres = g_dyn_spirv_cross.spvc_compiler_options_set_bool(soptions, + SPVC_COMPILER_OPTION_MSL_FRAMEBUFFER_FETCH_SUBPASS, + m_features.framebuffer_fetch)) != SPVC_SUCCESS) { Error::SetStringFmt( error, "spvc_compiler_options_set_bool(SPVC_COMPILER_OPTION_MSL_FRAMEBUFFER_FETCH_SUBPASS) failed: {}", @@ -1942,8 +1890,8 @@ bool GPUDevice::TranslateVulkanSpvToLanguage(const std::span spirv, GP } if (m_features.framebuffer_fetch && - ((sres = dyn_libs::spvc_compiler_options_set_uint(soptions, SPVC_COMPILER_OPTION_MSL_VERSION, - target_version)) != SPVC_SUCCESS)) + ((sres = g_dyn_spirv_cross.spvc_compiler_options_set_uint(soptions, SPVC_COMPILER_OPTION_MSL_VERSION, + target_version)) != SPVC_SUCCESS)) { Error::SetStringFmt(error, "spvc_compiler_options_set_uint(SPVC_COMPILER_OPTION_MSL_VERSION) failed: {}", static_cast(sres)); @@ -1960,7 +1908,7 @@ bool GPUDevice::TranslateVulkanSpvToLanguage(const std::span spirv, GP .msl_texture = msl_texture, .msl_sampler = msl_sampler}; - const spvc_result sres = dyn_libs::spvc_compiler_msl_add_resource_binding(scompiler, &rb); + const spvc_result sres = g_dyn_spirv_cross.spvc_compiler_msl_add_resource_binding(scompiler, &rb); if (sres != SPVC_SUCCESS) { Error::SetStringFmt(error, "spvc_compiler_msl_add_resource_binding() failed: {}", static_cast(sres)); @@ -2007,14 +1955,14 @@ bool GPUDevice::TranslateVulkanSpvToLanguage(const std::span spirv, GP break; } - if ((sres = dyn_libs::spvc_compiler_install_compiler_options(scompiler, soptions)) != SPVC_SUCCESS) + if ((sres = g_dyn_spirv_cross.spvc_compiler_install_compiler_options(scompiler, soptions)) != SPVC_SUCCESS) { Error::SetStringFmt(error, "spvc_compiler_install_compiler_options() failed: {}", static_cast(sres)); return false; } const char* out_src; - if ((sres = dyn_libs::spvc_compiler_compile(scompiler, &out_src)) != SPVC_SUCCESS) + if ((sres = g_dyn_spirv_cross.spvc_compiler_compile(scompiler, &out_src)) != SPVC_SUCCESS) { Error::SetStringFmt(error, "spvc_compiler_compile() failed: {}", static_cast(sres)); return false; @@ -2105,8 +2053,13 @@ void GPUDevice::UnloadDynamicLibraries() { Assert(!g_gpu_device); - dyn_libs::CloseSpirvCross(); - dyn_libs::CloseShaderc(); + g_dyn_spirv_cross = {}; + s_locals.spirv_cross_library.Close(); + + if (g_dyn_shaderc.compiler) + g_dyn_shaderc.shaderc_compiler_release(g_dyn_shaderc.compiler); + g_dyn_shaderc = {}; + s_locals.shaderc_library.Close(); #ifdef ENABLE_VULKAN VulkanLoader::DestroyVulkanInstance(); diff --git a/src/util/postprocessing_shader_slang.cpp b/src/util/postprocessing_shader_slang.cpp index 176abfa96..743690d14 100644 --- a/src/util/postprocessing_shader_slang.cpp +++ b/src/util/postprocessing_shader_slang.cpp @@ -1219,46 +1219,47 @@ bool PostProcessing::SlangShader::ParsePresetPass(std::string_view preset_path, static std::optional> CompileToSPV(shaderc_shader_kind stage, std::string_view code, Error* error) { std::optional> ret; - if (!dyn_libs::OpenShaderc(error)) + if (!g_dyn_shaderc.Open(error)) return ret; const bool generate_debug_info = (g_gpu_device && g_gpu_device->IsDebugDevice()); - const shaderc_compile_options_t options = dyn_libs::shaderc_compile_options_initialize(); + const shaderc_compile_options_t options = g_dyn_shaderc.shaderc_compile_options_initialize(); AssertMsg(options, "shaderc_compile_options_initialize() failed"); - dyn_libs::shaderc_compile_options_set_source_language(options, shaderc_source_language_glsl); - dyn_libs::shaderc_compile_options_set_target_env(options, shaderc_target_env_vulkan, 0); - dyn_libs::shaderc_compile_options_set_generate_debug_info(options, generate_debug_info, false); - dyn_libs::shaderc_compile_options_set_optimization_level(options, shaderc_optimization_level_zero); + g_dyn_shaderc.shaderc_compile_options_set_source_language(options, shaderc_source_language_glsl); + g_dyn_shaderc.shaderc_compile_options_set_target_env(options, shaderc_target_env_vulkan, 0); + g_dyn_shaderc.shaderc_compile_options_set_generate_debug_info(options, generate_debug_info, false); + g_dyn_shaderc.shaderc_compile_options_set_optimization_level(options, shaderc_optimization_level_zero); - const shaderc_compilation_result_t result = dyn_libs::shaderc_compile_into_spv( - dyn_libs::GetShadercCompiler(), code.data(), code.length(), stage, "source", "main", options); + const shaderc_compilation_result_t result = g_dyn_shaderc.shaderc_compile_into_spv( + g_dyn_shaderc.compiler, code.data(), code.length(), stage, "source", "main", options); const shaderc_compilation_status status = - result ? dyn_libs::shaderc_result_get_compilation_status(result) : shaderc_compilation_status_internal_error; + result ? g_dyn_shaderc.shaderc_result_get_compilation_status(result) : shaderc_compilation_status_internal_error; if (status != shaderc_compilation_status_success) { - const std::string_view errors(result ? dyn_libs::shaderc_result_get_error_message(result) : "null result object"); + const std::string_view errors(result ? g_dyn_shaderc.shaderc_result_get_error_message(result) : + "null result object"); Error::SetStringFmt(error, "Failed to compile shader to SPIR-V: {}\n{}", - dyn_libs::shaderc_compilation_status_to_string(status), errors); - ERROR_LOG("Failed to compile shader to SPIR-V: {}\n{}", dyn_libs::shaderc_compilation_status_to_string(status), + g_dyn_shaderc.shaderc_compilation_status_to_string(status), errors); + ERROR_LOG("Failed to compile shader to SPIR-V: {}\n{}", g_dyn_shaderc.shaderc_compilation_status_to_string(status), errors); GPUDevice::DumpBadShader(code, errors); } else { - const size_t num_warnings = dyn_libs::shaderc_result_get_num_warnings(result); + const size_t num_warnings = g_dyn_shaderc.shaderc_result_get_num_warnings(result); if (num_warnings > 0) - WARNING_LOG("Shader compiled with warnings:\n{}", dyn_libs::shaderc_result_get_error_message(result)); + WARNING_LOG("Shader compiled with warnings:\n{}", g_dyn_shaderc.shaderc_result_get_error_message(result)); - const size_t spirv_size = dyn_libs::shaderc_result_get_length(result); + const size_t spirv_size = g_dyn_shaderc.shaderc_result_get_length(result); Assert(spirv_size > 0 && (spirv_size % sizeof(u32)) == 0); ret.emplace(); ret->resize(spirv_size / sizeof(u32)); - std::memcpy(ret->data(), dyn_libs::shaderc_result_get_bytes(result), spirv_size); + std::memcpy(ret->data(), g_dyn_shaderc.shaderc_result_get_bytes(result), spirv_size); } - dyn_libs::shaderc_result_release(result); - dyn_libs::shaderc_compile_options_release(options); + g_dyn_shaderc.shaderc_result_release(result); + g_dyn_shaderc.shaderc_compile_options_release(options); return ret; } @@ -1284,20 +1285,20 @@ bool PostProcessing::SlangShader::ReflectPass(Pass& pass, Error* error) bool PostProcessing::SlangShader::ReflectShader(Pass& pass, std::span spv, GPUShaderStage stage, Error* error) { - if (!dyn_libs::OpenSpirvCross(error)) + if (!g_dyn_spirv_cross.Open(error)) return false; spvc_context sctx; spvc_result sres; - if ((sres = dyn_libs::spvc_context_create(&sctx)) != SPVC_SUCCESS) + if ((sres = g_dyn_spirv_cross.spvc_context_create(&sctx)) != SPVC_SUCCESS) { Error::SetStringFmt(error, "spvc_context_create() failed: {}", static_cast(sres)); return false; } - const ScopedGuard sctx_guard = [&sctx]() { dyn_libs::spvc_context_destroy(sctx); }; + const ScopedGuard sctx_guard = [&sctx]() { g_dyn_spirv_cross.spvc_context_destroy(sctx); }; - dyn_libs::spvc_context_set_error_callback( + g_dyn_spirv_cross.spvc_context_set_error_callback( sctx, [](void* error, const char* errormsg) { ERROR_LOG("SPIRV-Cross reported an error: {}", errormsg); @@ -1306,30 +1307,31 @@ bool PostProcessing::SlangShader::ReflectShader(Pass& pass, std::span spv, error); spvc_parsed_ir sir; - if ((sres = dyn_libs::spvc_context_parse_spirv(sctx, reinterpret_cast(spv.data()), spv.size(), &sir)) != - SPVC_SUCCESS) + if ((sres = g_dyn_spirv_cross.spvc_context_parse_spirv(sctx, reinterpret_cast(spv.data()), spv.size(), + &sir)) != SPVC_SUCCESS) { Error::SetStringFmt(error, "spvc_context_parse_spirv() failed: {}", static_cast(sres)); return false; } spvc_compiler scompiler; - if ((sres = dyn_libs::spvc_context_create_compiler(sctx, SPVC_BACKEND_NONE /*SPVC_BACKEND_GLSL*/, sir, - SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, &scompiler)) != SPVC_SUCCESS) + if ((sres = g_dyn_spirv_cross.spvc_context_create_compiler(sctx, SPVC_BACKEND_NONE /*SPVC_BACKEND_GLSL*/, sir, + SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, &scompiler)) != + SPVC_SUCCESS) { Error::SetStringFmt(error, "spvc_context_create_compiler() failed: {}", static_cast(sres)); return false; } spvc_compiler_options soptions; - if ((sres = dyn_libs::spvc_compiler_create_compiler_options(scompiler, &soptions)) != SPVC_SUCCESS) + if ((sres = g_dyn_spirv_cross.spvc_compiler_create_compiler_options(scompiler, &soptions)) != SPVC_SUCCESS) { Error::SetStringFmt(error, "spvc_compiler_create_compiler_options() failed: {}", static_cast(sres)); return false; } spvc_resources resources; - if ((sres = dyn_libs::spvc_compiler_create_shader_resources(scompiler, &resources)) != SPVC_SUCCESS) + if ((sres = g_dyn_spirv_cross.spvc_compiler_create_shader_resources(scompiler, &resources)) != SPVC_SUCCESS) { Error::SetStringFmt(error, "spvc_compiler_create_shader_resources() failed: {}", static_cast(sres)); return false; @@ -1338,12 +1340,12 @@ bool PostProcessing::SlangShader::ReflectShader(Pass& pass, std::span spv, // Need to know if there's UBOs for mapping. const spvc_reflected_resource *ubos, *push_constants, *textures; size_t ubos_count, push_constants_count, textures_count; - if ((sres = dyn_libs::spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_UNIFORM_BUFFER, &ubos, - &ubos_count)) != SPVC_SUCCESS || - (sres = dyn_libs::spvc_resources_get_resource_list_for_type( + if ((sres = g_dyn_spirv_cross.spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_UNIFORM_BUFFER, + &ubos, &ubos_count)) != SPVC_SUCCESS || + (sres = g_dyn_spirv_cross.spvc_resources_get_resource_list_for_type( resources, SPVC_RESOURCE_TYPE_PUSH_CONSTANT, &push_constants, &push_constants_count)) != SPVC_SUCCESS || - (sres = dyn_libs::spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_SAMPLED_IMAGE, - &textures, &textures_count)) != SPVC_SUCCESS) + (sres = g_dyn_spirv_cross.spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_SAMPLED_IMAGE, + &textures, &textures_count)) != SPVC_SUCCESS) { Error::SetStringFmt(error, "spvc_resources_get_resource_list_for_type() failed: {}", static_cast(sres)); return false; @@ -1351,15 +1353,16 @@ bool PostProcessing::SlangShader::ReflectShader(Pass& pass, std::span spv, // Try to only allocate active textures. std::optional> active_textures; - if (spvc_set active_interface_variables; (sres = dyn_libs::spvc_compiler_get_active_interface_variables( + if (spvc_set active_interface_variables; (sres = g_dyn_spirv_cross.spvc_compiler_get_active_interface_variables( scompiler, &active_interface_variables)) == SPVC_SUCCESS) { - if (spvc_resources active_resources; (sres = dyn_libs::spvc_compiler_create_shader_resources_for_active_variables( - scompiler, &active_resources, active_interface_variables)) == SPVC_SUCCESS) + if (spvc_resources active_resources; + (sres = g_dyn_spirv_cross.spvc_compiler_create_shader_resources_for_active_variables( + scompiler, &active_resources, active_interface_variables)) == SPVC_SUCCESS) { const spvc_reflected_resource* active_textures_begin; size_t active_textures_count; - if ((sres = dyn_libs::spvc_resources_get_resource_list_for_type( + if ((sres = g_dyn_spirv_cross.spvc_resources_get_resource_list_for_type( active_resources, SPVC_RESOURCE_TYPE_SAMPLED_IMAGE, &active_textures_begin, &active_textures_count)) == SPVC_SUCCESS) { @@ -1419,8 +1422,9 @@ bool PostProcessing::SlangShader::ReflectShader(Pass& pass, std::span spv, } const unsigned orig_descriptor_set = - dyn_libs::spvc_compiler_get_decoration(scompiler, tex.id, SpvDecorationDescriptorSet); - const unsigned orig_binding = dyn_libs::spvc_compiler_get_decoration(scompiler, tex.id, SpvDecorationBinding); + g_dyn_spirv_cross.spvc_compiler_get_decoration(scompiler, tex.id, SpvDecorationDescriptorSet); + const unsigned orig_binding = + g_dyn_spirv_cross.spvc_compiler_get_decoration(scompiler, tex.id, SpvDecorationBinding); if (orig_descriptor_set != 0) { Error::SetStringFmt(error, "Texture '{}' is in descriptor set {}, only set 0 is supported", tex.name, @@ -1507,7 +1511,7 @@ bool PostProcessing::SlangShader::ReflectPassUniforms(const spvc_compiler& scomp const spvc_reflected_resource& resource, Pass& pass, bool push_constant, Error* error) { - const spvc_type type_handle = dyn_libs::spvc_compiler_get_type_handle(scompiler, resource.base_type_id); + const spvc_type type_handle = g_dyn_spirv_cross.spvc_compiler_get_type_handle(scompiler, resource.base_type_id); if (!type_handle) { Error::SetStringFmt(error, "spvc_compiler_get_type_handle() failed for resource '{}'", resource.name); @@ -1515,7 +1519,8 @@ bool PostProcessing::SlangShader::ReflectPassUniforms(const spvc_compiler& scomp } size_t struct_size = 0; - if (const spvc_result sres = dyn_libs::spvc_compiler_get_declared_struct_size(scompiler, type_handle, &struct_size); + if (const spvc_result sres = + g_dyn_spirv_cross.spvc_compiler_get_declared_struct_size(scompiler, type_handle, &struct_size); sres != SPVC_SUCCESS) { Error::SetStringFmt(error, "spvc_compiler_get_declared_struct_size() failed for resource '{}': {}", resource.name, @@ -1545,16 +1550,17 @@ bool PostProcessing::SlangShader::ReflectPassUniforms(const spvc_compiler& scomp for (unsigned member_idx = 0;; member_idx++) { - const char* member_name = dyn_libs::spvc_compiler_get_member_name(scompiler, resource.base_type_id, member_idx); + const char* member_name = + g_dyn_spirv_cross.spvc_compiler_get_member_name(scompiler, resource.base_type_id, member_idx); if (!member_name || member_name[0] == '\0') break; - const u32 offset = - dyn_libs::spvc_compiler_get_member_decoration(scompiler, resource.base_type_id, member_idx, SpvDecorationOffset); + const u32 offset = g_dyn_spirv_cross.spvc_compiler_get_member_decoration(scompiler, resource.base_type_id, + member_idx, SpvDecorationOffset); size_t member_size = 0; - if (const spvc_result sres = - dyn_libs::spvc_compiler_get_declared_struct_member_size(scompiler, type_handle, member_idx, &member_size); + if (const spvc_result sres = g_dyn_spirv_cross.spvc_compiler_get_declared_struct_member_size( + scompiler, type_handle, member_idx, &member_size); sres != SPVC_SUCCESS) { Error::SetStringFmt(error, "spvc_compiler_get_declared_struct_member_size() failed for member '{}' of '{}': {}",