From 072875c464114edd2d64c3bf0af81e4b01f36cd4 Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Mon, 20 Apr 2026 12:33:52 +0200 Subject: [PATCH 01/10] Switch to std::format, remove fmtlib and wis::format Replaced all uses of wis::format and fmtlib with C++20 std::format and related functions. Removed the custom format.hpp header and all references to it. Updated CMake and Conan configuration to drop fmtlib dependency. Codebase now requires a C++20 compiler with std::format support. Minor code cleanups and function signature formatting improvements included. --- CMakeLists.txt | 12 --- cmake/deps.cmake | 14 --- conanfile.py | 11 -- generator/bitmask.cpp | 56 +++++------ generator/constant.cpp | 14 +-- generator/entry_main.cpp | 3 +- generator/enum.cpp | 46 ++++----- generator/function.cpp | 106 ++++++++++---------- generator/generator.cpp | 128 ++++++++++++------------ generator/generator.hpp | 46 ++++----- generator/handle.cpp | 42 ++++---- generator/pch.hpp | 2 +- generator/struct.cpp | 24 ++--- generator/validation.cpp | 6 +- generator/variant.cpp | 18 ++-- src/include/wisdom/bridge/format.hpp | 22 ---- src/include/wisdom/dx12/dx12_device.cpp | 102 ++++++++++++------- 17 files changed, 311 insertions(+), 341 deletions(-) delete mode 100644 src/include/wisdom/bridge/format.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c0979886..6d8fc77b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,16 +11,6 @@ include(GenerateExportHeader) include(cmake/functions.cmake) wisdom_detect_platform() -# Determine which options to use by default -if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" - AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "13" - OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang" - AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "16") - set(LOCAL_USE_FMTLIB TRUE) -else() - set(LOCAL_USE_FMTLIB FALSE) -endif() - if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) set(WTOP ON) else() @@ -28,7 +18,6 @@ else() endif() # Options -option(WISDOM_USE_FMT "Build Wisdom with fmtlib" ${LOCAL_USE_FMTLIB}) option(WISDOM_FORCE_VULKAN "Force Vulkan support" OFF) option(WISDOM_BUILD_EXAMPLES "Build the example project." ${WTOP}) option(WISDOM_BUILD_TESTS "Build the tests." ${WTOP}) @@ -55,7 +44,6 @@ message( WISDOM_VULKAN: ${WISDOM_VULKAN} WISDOM_VULKAN_VERSION: ${WISDOM_VULKAN_VERSION} WISDOM_DX12: ${WISDOM_DX12} - WISDOM_USE_FMT: ${WISDOM_USE_FMT} WISDOM_VERSION: ${WISDOM_VERSION} WISDOM_PLATFORM: ${WISDOM_PLATFORM} diff --git a/cmake/deps.cmake b/cmake/deps.cmake index 082239a8c..917174cb9 100644 --- a/cmake/deps.cmake +++ b/cmake/deps.cmake @@ -22,20 +22,6 @@ if (WISDOM_WINDOWS) include(${CMAKE_CURRENT_LIST_DIR}/deps/deps_win.cmake) endif () -# Use fmtlib -if (WISDOM_USE_FMT) - find_package(fmt CONFIG QUIET) - if (fmt_FOUND) - message("fmtlib found, skipping download.") - else () - message("Loading latest fmtlib...") - CPMAddPackage( - NAME fmt - GITHUB_REPOSITORY fmtlib/fmt - GIT_TAG 12.1.0) - endif () -endif () - # DXCompiler for HLSL compilation include(${CMAKE_CURRENT_LIST_DIR}/deps/dxc.cmake) diff --git a/conanfile.py b/conanfile.py index 8937bfdf0..53ad7320b 100644 --- a/conanfile.py +++ b/conanfile.py @@ -7,8 +7,6 @@ class WisdomConan(ConanFile): - """ """ - name = "wisdom" version = "0.7.0" package_type = "library" @@ -31,7 +29,6 @@ class WisdomConan(ConanFile): } def export_sources(self): - """ """ copy( self, "*", @@ -53,28 +50,23 @@ def export_sources(self): ) def config_options(self): - """ """ if self.settings.os == "Windows": self.options.rm_safe("fPIC") def configure(self): - """ """ if self.options.shared: self.options.rm_safe("fPIC") def layout(self): - """ """ cmake_layout(self) def generate(self): - """ """ self.output.warning( "This recipe currently relies on the project's CPM/NuGet dependency loading during CMake configure. " "For Conan Center, those dependencies should be provided as Conan requirements or vendored sources." ) tc = CMakeToolchain(self) - tc.generator = "Ninja" tc.variables["WISDOM_BUILD_EXAMPLES"] = False tc.variables["WISDOM_BUILD_TESTS"] = False tc.variables["WISDOM_BUILD_DOCS"] = False @@ -84,18 +76,15 @@ def generate(self): tc.generate() def build(self): - """ """ cmake = CMake(self) cmake.configure() cmake.build() def package(self): - """ """ cmake = CMake(self) cmake.install() def package_info(self): - """ """ self.cpp_info.set_property("cmake_file_name", "wisdom") self.cpp_info.builddirs.append("lib/cmake/wisdom") diff --git a/generator/bitmask.cpp b/generator/bitmask.cpp index 28de84e6e..be375c20b 100644 --- a/generator/bitmask.cpp +++ b/generator/bitmask.cpp @@ -49,7 +49,7 @@ void Generator::ParseBitmask(tinyxml2::XMLElement* type) if (auto* size = type->FindAttribute("version")) { ref.version = size->Value(); } else { - throw std::runtime_error(wis::format("Enum {} is missing version attribute.", name)); + throw std::runtime_error(std::format("Enum {} is missing version attribute.", name)); } for (auto* impl_type = type->FirstChildElement("impl_type"); impl_type; @@ -104,11 +104,11 @@ void Generator::ParseBitmask(tinyxml2::XMLElement* type) std::string Generator::MakeCBitmask(const WisBitmask& s, DocKind kind) { auto full_name = GetCFullTypename(s.name, Backend::Any); - std::string st_decl = wis::format("typedef enum {} {{\n", full_name); + std::string st_decl = std::format("typedef enum {} {{\n", full_name); if (!s.doc.empty()) { std::string xdoc = MakeTypeDocumentation(s, kind); - st_decl = wis::format("{}\n{}", xdoc, st_decl); + st_decl = std::format("{}\n{}", xdoc, st_decl); } for (auto& m : s.values) { @@ -116,44 +116,44 @@ std::string Generator::MakeCBitmask(const WisBitmask& s, DocKind kind) st_decl += MakeValueDocumentation( s, m, - wis::format(" Wis{}{} = (1u << {}),", s.name, m.name, m.value_or_bit), + std::format(" Wis{}{} = (1u << {}),", s.name, m.name, m.value_or_bit), kind ); continue; } - st_decl += MakeValueDocumentation(s, m, wis::format(" Wis{}{} = {},", s.name, m.name, m.value_or_bit), kind); + st_decl += MakeValueDocumentation(s, m, std::format(" Wis{}{} = {},", s.name, m.name, m.value_or_bit), kind); } - st_decl += wis::format("}} {};\n", full_name); + st_decl += std::format("}} {};\n", full_name); return st_decl; } //---------------------------------------------------------------------------------------------------------------------- std::string Generator::MakeCPPBitmask(const WisBitmask& s, DocKind kind) { - std::string st_decl = wis::format("enum class {} : uint32_t {{\n", s.name); + std::string st_decl = std::format("enum class {} : uint32_t {{\n", s.name); if (!s.doc.empty()) { std::string xdoc = MakeTypeDocumentation(s, kind); - st_decl = wis::format("{}\n{}", xdoc, st_decl); + st_decl = std::format("{}\n{}", xdoc, st_decl); } for (auto& m : s.values) { if (m.is_bit) { st_decl += MakeValueDocumentation( s, m, - wis::format(" {} = (1u << {}),", m.name, m.value_or_bit), + std::format(" {} = (1u << {}),", m.name, m.value_or_bit), kind ); continue; } - st_decl += MakeValueDocumentation(s, m, wis::format(" {} = {},", m.name, m.value_or_bit), kind); + st_decl += MakeValueDocumentation(s, m, std::format(" {} = {},", m.name, m.value_or_bit), kind); } st_decl += "};\n"; if (kind == DocKind::VersionOnly) { return st_decl; } - st_decl += wis::format("WISDOM_DEFINE_ENUM_OPERATORS({})\n\n", s.name); + st_decl += std::format("WISDOM_DEFINE_ENUM_OPERATORS({})\n\n", s.name); return st_decl; } @@ -179,7 +179,7 @@ std::string Generator::MakeBitmaskDescription(const WisBitmask& s) if (has_translate) { translates += ", "; } - translates += wis::format("{} as {}", impl_names[i], cvt.value); + translates += std::format("{} as {}", impl_names[i], cvt.value); has_translate = true; } if (has_translate) { @@ -188,10 +188,10 @@ std::string Generator::MakeBitmaskDescription(const WisBitmask& s) description += "Values:\n"; for (auto& m : s.values) { if (m.is_bit) { - description += wis::format("- `Wis{}{} = (1 << {})`: {}\n", s.name, m.name, m.value_or_bit, m.doc); + description += std::format("- `Wis{}{} = (1 << {})`: {}\n", s.name, m.name, m.value_or_bit, m.doc); continue; } - description += wis::format("- `Wis{}{} = {}`: {}\n", s.name, m.name, m.value_or_bit, m.doc); + description += std::format("- `Wis{}{} = {}`: {}\n", s.name, m.name, m.value_or_bit, m.doc); } return description; } @@ -209,7 +209,7 @@ std::string Generator::MakeBitmaskConverter(const WisBitmask& s, Backend backend auto wisdom_type = GetCFullTypename(s.name, Backend::Any); if (cvt.direct) { - converters = wis::format( + converters = std::format( "constexpr inline {} {}Convert({} value) noexcept {{\n return static_cast<{}>(value);\n}}\n\n", cvt.value, backend_tag, @@ -217,7 +217,7 @@ std::string Generator::MakeBitmaskConverter(const WisBitmask& s, Backend backend cvt.value ); } else { - converters = wis::format( + converters = std::format( "constexpr inline {} {}Convert({} value) noexcept {{\n", cvt.value, backend_tag, @@ -225,14 +225,14 @@ std::string Generator::MakeBitmaskConverter(const WisBitmask& s, Backend backend ); // Start with default value - converters += wis::format(" {} result = static_cast<{}>(0);\n", cvt.value, cvt.value); + converters += std::format(" {} result = static_cast<{}>(0);\n", cvt.value, cvt.value); if (auto nam = cvt.value.find("::"); nam != std::string::npos) { for (auto& m : s.values) { auto convert_value = m.converts[static_cast(backend)]; if (convert_value.empty()) { continue; } - converters += wis::format( + converters += std::format( " if (value & {}{}) {{ result = static_cast<{}>(result | {}); }}\n", GetCFullTypename(s.name, backend), m.name, @@ -246,7 +246,7 @@ std::string Generator::MakeBitmaskConverter(const WisBitmask& s, Backend backend if (convert_value.empty()) { continue; } - converters += wis::format( + converters += std::format( " if (value & {}{}) {{ result |= {}; }}\n", GetCFullTypename(s.name, backend), m.name, @@ -255,12 +255,12 @@ std::string Generator::MakeBitmaskConverter(const WisBitmask& s, Backend backend } } - converters += wis::format(" return result;\n}}\n\n"); + converters += std::format(" return result;\n}}\n\n"); } if (cvt.convert_back) { if (cvt.direct) { - converters += wis::format( + converters += std::format( "constexpr inline {} {}Convert({} value) noexcept {{\n return static_cast<{}>(value);\n}}\n\n", wisdom_type, backend_tag, @@ -268,20 +268,20 @@ std::string Generator::MakeBitmaskConverter(const WisBitmask& s, Backend backend wisdom_type ); } else { - converters += wis::format( + converters += std::format( "constexpr inline {} {}Convert({} value) noexcept {{\n", wisdom_type, backend_tag, cvt.value ); - converters += wis::format(" {} result = static_cast<{}>(0);\n", wisdom_type, wisdom_type); + converters += std::format(" {} result = static_cast<{}>(0);\n", wisdom_type, wisdom_type); for (auto& m : s.values) { auto convert_value = m.converts[static_cast(backend)]; if (convert_value.empty()) { continue; } - converters += wis::format( + converters += std::format( " if (value & {}) {{ result = static_cast<{}>(result | {}{}); }}\n", convert_value, wisdom_type, @@ -290,7 +290,7 @@ std::string Generator::MakeBitmaskConverter(const WisBitmask& s, Backend backend ); } - converters += wis::format(" return result;\n}}\n\n"); + converters += std::format(" return result;\n}}\n\n"); } } @@ -304,16 +304,16 @@ void Generator::WriteBitmaskDocumentation(std::filesystem::path enum_output_path auto& bitmask_names = module_map.at(active_module_name).bitmasks_in_order; for (auto& enum_name : bitmask_names) { // Make a folder for enums starting with this letter - std::filesystem::path enum_file_path = enum_output_path / wis::format("{}_enum.h", MakeSnakeCase(enum_name)); + std::filesystem::path enum_file_path = enum_output_path / std::format("{}_enum.h", MakeSnakeCase(enum_name)); auto& enum_ref = bitmask_map[enum_name]; - std::string enum_template_content = wis::format( + std::string enum_template_content = std::format( " * C version:\n```c\n{}```\n" "C++ version:\n```cpp\nnamespace wis{{\n{}}}\n```\n", MakeCBitmask(enum_ref, DocKind::VersionOnly), MakeCPPBitmask(enum_ref, DocKind::VersionOnly) ); - std::string enum_description = wis::format(" * {}", MakeBitmaskDescription(enum_ref)); + std::string enum_description = std::format(" * {}", MakeBitmaskDescription(enum_ref)); std::string enum_refs = GetRefs(enum_name); ReplaceAll(enum_template_content, "\n", "\n * "); ReplaceAll(enum_description, "\n", "\n * "); diff --git a/generator/constant.cpp b/generator/constant.cpp index 4ac171184..81877478a 100644 --- a/generator/constant.cpp +++ b/generator/constant.cpp @@ -58,11 +58,11 @@ std::string Generator::MakeCConstant(const WisConstant& c, DocKind kind) } std::string define_name = "WIS_" + MakeUpperSnakeCase(c.name); - std::string st_decl = wis::format("#define {} (({}{}){})\n", define_name, type_str, mod_str, c.value); + std::string st_decl = std::format("#define {} (({}{}){})\n", define_name, type_str, mod_str, c.value); if (!c.doc.empty() && kind == DocKind::Full) { std::string version_info = MakeVersionString(c.version); - std::string documentation = wis::format("/// @brief {}{}\n", version_info, c.doc); + std::string documentation = std::format("/// @brief {}{}\n", version_info, c.doc); documentation = FinalizeCDocumentation(documentation, c.name); st_decl = documentation + st_decl; } @@ -81,11 +81,11 @@ std::string Generator::MakeCPPConstant(const WisConstant& c, DocKind kind) type_str = "const " + type_str; } - std::string st_decl = wis::format("static constexpr {}{} {} = {};\n", type_str, mod_str, c.name, c.value); + std::string st_decl = std::format("static constexpr {}{} {} = {};\n", type_str, mod_str, c.name, c.value); if (!c.doc.empty() && kind == DocKind::Full) { std::string version_info = MakeVersionString(c.version); - std::string documentation = wis::format("/// @brief {}{}\n", version_info, c.doc); + std::string documentation = std::format("/// @brief {}{}\n", version_info, c.doc); documentation = FinalizeCPPDocumentation(documentation, c.name); st_decl = documentation + st_decl; } @@ -101,8 +101,8 @@ std::string Generator::MakeConstantDescription(const WisConstant& c) } std::string type_str = GetCFullTypename(c.type, Backend::Any); - description += wis::format("Type: `{}`\n", type_str); - description += wis::format("Value: `{}`\n", c.value); + description += std::format("Type: `{}`\n", type_str); + description += std::format("Value: `{}`\n", c.value); return description; } @@ -146,7 +146,7 @@ void Generator::WriteConstantDocumentation(std::filesystem::path const_output_pa WriteDocumentation( const_file_path, template_constant, - wis::format("{}Constants", active_module_name), + std::format("{}Constants", active_module_name), const_template_content, empty_doc, empty_doc, diff --git a/generator/entry_main.cpp b/generator/entry_main.cpp index 210dbf8b8..8a3a73f67 100644 --- a/generator/entry_main.cpp +++ b/generator/entry_main.cpp @@ -1,5 +1,4 @@ #include -#include "../src/include/wisdom/bridge/format.hpp" #include "generator.hpp" constexpr inline std::string_view clang_format_exe = CLANG_FORMAT_EXECUTABLE; @@ -17,7 +16,7 @@ void FormatFiles(std::span files) cmd += ' '; } std::cout << "Wisdom Vk Utils: Formatting:\n" << cmd << '\n'; - std::string command = wis::format("\"{}\" -i --style=file {}", clang_format_exe, cmd); + std::string command = std::format("\"{}\" -i --style=file {}", clang_format_exe, cmd); int ret = 0; for (uint32_t i = 0; (ret = std::system(command.c_str())) != 0 && i < repeats; ++i) diff --git a/generator/enum.cpp b/generator/enum.cpp index 4f5bd4191..91b42e5da 100644 --- a/generator/enum.cpp +++ b/generator/enum.cpp @@ -49,7 +49,7 @@ void Generator::ParseEnum(tinyxml2::XMLElement* type) if (auto* size = type->FindAttribute("version")) { ref.version = size->Value(); } else { - throw std::runtime_error(wis::format("Enum {} is missing version attribute.", name)); + throw std::runtime_error(std::format("Enum {} is missing version attribute.", name)); } for (auto* impl_type = type->FirstChildElement("impl_type"); impl_type; @@ -99,33 +99,33 @@ void Generator::ParseEnum(tinyxml2::XMLElement* type) std::string Generator::MakeCEnum(const WisEnum& s, DocKind kind) { auto full_name = GetCFullTypename(s.name, Backend::Any); - std::string st_decl = wis::format("typedef enum {} {{\n", full_name); + std::string st_decl = std::format("typedef enum {} {{\n", full_name); if (!s.doc.empty()) { std::string xdoc = MakeTypeDocumentation(s, kind); - st_decl = wis::format("{}\n{}", xdoc, st_decl); + st_decl = std::format("{}\n{}", xdoc, st_decl); } for (auto& m : s.values) { - st_decl += MakeValueDocumentation(s, m, wis::format(" Wis{}{} = {},", s.name, m.name, m.value), kind); + st_decl += MakeValueDocumentation(s, m, std::format(" Wis{}{} = {},", s.name, m.name, m.value), kind); } - st_decl += wis::format("}} {};\n", full_name); + st_decl += std::format("}} {};\n", full_name); return st_decl; } //---------------------------------------------------------------------------------------------------------------------- std::string Generator::MakeCPPEnum(const WisEnum& s, DocKind kind) { - std::string st_decl = wis::format("enum class {} {{\n", s.name); + std::string st_decl = std::format("enum class {} {{\n", s.name); if (!s.doc.empty()) { std::string xdoc = MakeTypeDocumentation(s, kind); - st_decl = wis::format("{}\n{}", xdoc, st_decl); + st_decl = std::format("{}\n{}", xdoc, st_decl); } for (auto& m : s.values) { - st_decl += MakeValueDocumentation(s, m, wis::format(" {} = {},", m.name, m.value), kind); + st_decl += MakeValueDocumentation(s, m, std::format(" {} = {},", m.name, m.value), kind); } st_decl += "};\n"; @@ -139,16 +139,16 @@ void Generator::WriteEnumDocumentation(std::filesystem::path enum_output_path) auto& enum_names = module_map.at(active_module_name).enums_in_order; for (auto& enum_name : enum_names) { // Make a folder for enums starting with this letter - std::filesystem::path enum_file_path = enum_output_path / wis::format("{}_enum.h", MakeSnakeCase(enum_name)); + std::filesystem::path enum_file_path = enum_output_path / std::format("{}_enum.h", MakeSnakeCase(enum_name)); auto& enum_ref = enum_map[enum_name]; - std::string enum_template_content = wis::format( + std::string enum_template_content = std::format( " * C version:\n```c\n{}```\n" "C++ version:\n```cpp\nnamespace wis{{\n{}}}\n```\n", MakeCEnum(enum_ref, DocKind::VersionOnly), MakeCPPEnum(enum_ref, DocKind::VersionOnly) ); - std::string enum_description = wis::format(" * {}", MakeEnumDescription(enum_ref)); + std::string enum_description = std::format(" * {}", MakeEnumDescription(enum_ref)); std::string enum_refs = GetRefs(enum_name); ReplaceAll(enum_template_content, "\n", "\n * "); ReplaceAll(enum_description, "\n", "\n * "); @@ -189,7 +189,7 @@ std::string Generator::MakeEnumDescription(const WisEnum& s) continue; } - translates += wis::format( + translates += std::format( "{} `{}` for {} implementation", has_translate ? ", and" : "", cvt.value, @@ -203,7 +203,7 @@ std::string Generator::MakeEnumDescription(const WisEnum& s) description += "Values:\n"; for (auto& m : s.values) { - description += wis::format("- `Wis{}{} = {}`: {}\n", s.name, m.name, m.value, m.doc); + description += std::format("- `Wis{}{} = {}`: {}\n", s.name, m.name, m.value, m.doc); } return description; } @@ -220,7 +220,7 @@ std::string Generator::MakeEnumConverter(const WisEnum& s, Backend backend) auto wisdom_type = GetCFullTypename(s.name, Backend::Any); if (cvt.direct) { - converters = wis::format( + converters = std::format( "constexpr inline {} {}Convert({} value) noexcept {{\n return static_cast<{}>(value);\n}}\n\n", cvt.value, backend_tag, @@ -228,7 +228,7 @@ std::string Generator::MakeEnumConverter(const WisEnum& s, Backend backend) cvt.value ); } else { - converters = wis::format( + converters = std::format( "constexpr inline {} {}Convert({} value) noexcept {{\n switch(value) {{\n", cvt.value, backend_tag, @@ -239,23 +239,23 @@ std::string Generator::MakeEnumConverter(const WisEnum& s, Backend backend) if (convert_value.empty()) { continue; } - converters += wis::format( + converters += std::format( " case {}: return {};\n", - wis::format("{}{}", GetCFullTypename(s.name, backend), m.name), + std::format("{}{}", GetCFullTypename(s.name, backend), m.name), convert_value ); } if (!cvt.default_value.empty()) { - converters += wis::format(" default: return {};\n }}\n}}\n\n", cvt.default_value); + converters += std::format(" default: return {};\n }}\n}}\n\n", cvt.default_value); } else { - converters += wis::format(" default: return static_cast<{}>(0);\n }}\n}}\n\n", cvt.value); + converters += std::format(" default: return static_cast<{}>(0);\n }}\n}}\n\n", cvt.value); } } if (cvt.convert_back) { if (cvt.direct) { - converters += wis::format( + converters += std::format( "constexpr inline {} {}Convert({} value) noexcept {{\n return static_cast<{}>(value);\n}}\n\n", wisdom_type, backend_tag, @@ -263,7 +263,7 @@ std::string Generator::MakeEnumConverter(const WisEnum& s, Backend backend) wisdom_type ); } else { - converters += wis::format( + converters += std::format( "constexpr inline {} {}Convert({} value) noexcept {{\n", wisdom_type, backend_tag, @@ -275,7 +275,7 @@ std::string Generator::MakeEnumConverter(const WisEnum& s, Backend backend) if (convert_value.empty()) { continue; } - converters += wis::format( + converters += std::format( " if (value == {}) {{ return {}{}; }}\n", convert_value, wisdom_type, @@ -283,7 +283,7 @@ std::string Generator::MakeEnumConverter(const WisEnum& s, Backend backend) ); } - converters += wis::format(" return static_cast<{}>(0);\n}}\n\n", wisdom_type); + converters += std::format(" return static_cast<{}>(0);\n}}\n\n", wisdom_type); } } diff --git a/generator/function.cpp b/generator/function.cpp index 0c15a172b..9b68e89b3 100644 --- a/generator/function.cpp +++ b/generator/function.cpp @@ -50,7 +50,7 @@ void Generator::ParseFunctions(tinyxml2::XMLElement* type) if (auto* version = func->FindAttribute("version")) { ref.version = version->Value(); } else { - throw std::runtime_error(wis::format("Function {} is missing version attribute.", name)); + throw std::runtime_error(std::format("Function {} is missing version attribute.", name)); } if (this_type) { @@ -110,7 +110,7 @@ void Generator::ParseFunctions(tinyxml2::XMLElement* type) if (auto* name_attr = param->FindAttribute("name")) { p.name = name_attr->Value(); } else { - throw std::runtime_error(wis::format("Function {} has a parameter with no name.", name)); + throw std::runtime_error(std::format("Function {} has a parameter with no name.", name)); } if (auto* def = param->FindAttribute("default")) { p.default_value = def->Value(); @@ -139,7 +139,7 @@ void Generator::ParseDelegate(tinyxml2::XMLElement* func) if (auto* version = func->FindAttribute("version")) { ref.version = version->Value(); } else { - throw std::runtime_error(wis::format("Delegate {} is missing version attribute.", name)); + throw std::runtime_error(std::format("Delegate {} is missing version attribute.", name)); } if (auto* doc = func->FindAttribute("doc")) { @@ -159,7 +159,7 @@ void Generator::ParseDelegate(tinyxml2::XMLElement* func) if (auto* name_attr = param->FindAttribute("name")) { p.name = name_attr->Value(); } else { - throw std::runtime_error(wis::format("Function {} has a parameter with no name.", name)); + throw std::runtime_error(std::format("Function {} has a parameter with no name.", name)); } if (auto* def = param->FindAttribute("default")) { p.default_value = def->Value(); @@ -186,7 +186,7 @@ std::string Generator::MakeCFunctionProto( std::string full_return_type; std::string post_return; - std::string function_full_name = wis::format("wis{}{}{}", re_impl, func.IsCD() ? "" : func.this_type, func.name); + std::string function_full_name = std::format("wis{}{}{}", re_impl, func.IsCD() ? "" : func.this_type, func.name); size_t post_return_length = 0; if (func.return_type.IsVoid()) { @@ -196,7 +196,7 @@ std::string Generator::MakeCFunctionProto( } else if (func.return_type.has_result) { full_return_type = GetCFullTypename("Result", Backend::Any); std::string arg_name = func.return_type.opt_name.empty() - ? wis::format("out_{}", MakeSnakeCase(func.return_type.type)) + ? std::format("out_{}", MakeSnakeCase(func.return_type.type)) : std::string(func.return_type.opt_name); std::string prefix = ""; @@ -207,7 +207,7 @@ std::string Generator::MakeCFunctionProto( } std::string type_str = GetMemberTypeString(func.return_type, backend); - post_return = wis::format("{}{}*{{}}{}", prefix, type_str, arg_name); + post_return = std::format("{}{}*{{}}{}", prefix, type_str, arg_name); post_return_length = type_str.size(); } else { full_return_type = GetMemberTypeString(func.return_type, backend); @@ -223,7 +223,7 @@ std::string Generator::MakeCFunctionProto( this_param.modifier = Modifier(Modifier::Pointer | func.modifier & Modifier::Const); auto full_this_type = GetMemberTypeString(this_param, backend); - this_arg = wis::format("{} {}", full_this_type, this_param.name); + this_arg = std::format("{} {}", full_this_type, this_param.name); if (func.parameters.size() > 0) { this_arg += ",\n"; } @@ -254,14 +254,14 @@ std::string Generator::MakeCFunctionProto( size_t pad_length = max_arg_length > type_str.length() ? max_arg_length - type_str.length() : 0; padding = std::string(pad_length, ' '); - params += wis::format("{}{}{} {}", prefix_spaces, type_str, padding, p.name); + params += std::format("{}{}{} {}", prefix_spaces, type_str, padding, p.name); if (i < func.parameters.size() - 1) { params += ",\n"; } max_arg_length = std::max(max_arg_length, type_str.length()); } - return wis::format( + return std::format( "{}{} {}({}{}{});\n", pre_decl, full_return_type, @@ -290,7 +290,7 @@ std::string Generator::MakeCPPFunctionProto( auto func_prefix = type != ProtoType::Prefixed ? "" : re_impl; std::string xclass_code; if (!func.this_type.empty() && kind != DocKind::Full) { - xclass_code = wis::format("{}::", func.this_type); + xclass_code = std::format("{}::", func.this_type); } std::string full_return_type; @@ -327,7 +327,7 @@ std::string Generator::MakeCPPFunctionProto( } std::string type_str = "wis::Result&"; std::string arg_name = "out_result"; - post_return = wis::format("{}{} {{}}{}", prefix, type_str, arg_name); + post_return = std::format("{}{} {{}}{}", prefix, type_str, arg_name); post_return_length = type_str.size(); } break; @@ -377,7 +377,7 @@ std::string Generator::MakeCPPFunctionProto( size_t pad_length = max_arg_length > type_str.length() ? max_arg_length - type_str.length() : 0; padding = std::string(pad_length, ' '); - params += wis::format("{}{}{} {}", prefix_spaces, type_str, padding, p.name); + params += std::format("{}{}{} {}", prefix_spaces, type_str, padding, p.name); // edge case for spans - if last argument was a span, skip the next one (the size) // That means we need to check if i(func, kind); - func_decl = wis::format("{}\n{}", xdoc, func_decl); + func_decl = std::format("{}\n{}", xdoc, func_decl); } if (kind != DocKind::Full) { return func_decl; } auto re_impl = GetBackendSuffix(backend); - auto c_name = wis::format("wis{}{}{}", re_impl, func.IsCD() ? "" : func.this_type, func.name); + auto c_name = std::format("wis{}{}{}", re_impl, func.IsCD() ? "" : func.this_type, func.name); // Convert args and call C function std::string body = "{\n"; @@ -473,7 +473,7 @@ std::string Generator::MakeCPPFunctionImpl( auto& p = func.parameters[i]; if (p.modifier & Modifier::Span) { - body += wis::format( + body += std::format( "reinterpret_cast<{}>({}.data()), {}.size()", GetMemberTypeString(p, backend), p.name, @@ -489,7 +489,7 @@ std::string Generator::MakeCPPFunctionImpl( switch (GetType(p.type)) { case TypeKind::Enum: case TypeKind::Bitmask: - body += wis::format("static_cast<{}>({})", GetMemberTypeString(p, backend), p.name); + body += std::format("static_cast<{}>({})", GetMemberTypeString(p, backend), p.name); break; case TypeKind::None: case TypeKind::View: @@ -498,10 +498,10 @@ std::string Generator::MakeCPPFunctionImpl( break; default: if (p.modifier & Modifier::Reference) { - body += wis::format("reinterpret_cast<{}>(&{})", GetMemberTypeString(p, backend), p.name); + body += std::format("reinterpret_cast<{}>(&{})", GetMemberTypeString(p, backend), p.name); break; } - body += wis::format("reinterpret_cast<{}>({})", GetMemberTypeString(p, backend), p.name); + body += std::format("reinterpret_cast<{}>({})", GetMemberTypeString(p, backend), p.name); break; } @@ -514,13 +514,13 @@ std::string Generator::MakeCPPFunctionImpl( switch (func.return_type.GetKind()) { case ReturnTypeKind::ResultAndValue: { auto ret_value_name = func.return_type.opt_name.empty() - ? wis::format("out_{}", MakeSnakeCase(func.return_type.type)) + ? std::format("out_{}", MakeSnakeCase(func.return_type.type)) : std::string(func.return_type.opt_name); // Prepare out parameter - body += wis::format(" {} {};\n", GetMemberTypeString(func.return_type, backend), ret_value_name); + body += std::format(" {} {};\n", GetMemberTypeString(func.return_type, backend), ret_value_name); - body += wis::format( + body += std::format( " const WisResult wis_result = ::{}({}", c_name, func.this_type.empty() ? "" : "&_impl_storage" @@ -535,9 +535,9 @@ std::string Generator::MakeCPPFunctionImpl( auto ret_type = GetType(func.return_type.type); if (ret_type == TypeKind::Handle) { - body += wis::format(", {}.GetStorage());\n", ret_value_name); + body += std::format(", {}.GetStorage());\n", ret_value_name); } else { - body += wis::format( + body += std::format( ", reinterpret_cast<{}*>(&{}));\n", GetMemberTypeString(func.return_type, backend), ret_value_name @@ -545,10 +545,10 @@ std::string Generator::MakeCPPFunctionImpl( } body += " out_result = wis::Result{ static_cast(wis_result.status), wis_result.platform_code, " "wis_result.error };\n"; - body += wis::format(" return {};\n", ret_value_name); + body += std::format(" return {};\n", ret_value_name); } break; case ReturnTypeKind::ResultOnly: { - body += wis::format( + body += std::format( " const WisResult wis_result = ::{}({}", c_name, func.this_type.empty() ? "" : "&_impl_storage" @@ -570,22 +570,22 @@ std::string Generator::MakeCPPFunctionImpl( break; case TypeKind::Enum: case TypeKind::Bitmask: - return_cast = wis::format("static_cast<{}>", GetMemberTypeString(func.return_type, backend)); + return_cast = std::format("static_cast<{}>", GetMemberTypeString(func.return_type, backend)); break; case TypeKind::Handle: throw std::runtime_error( - wis::format("Function {} return type cannot be a handle in direct return.", func.name) + std::format("Function {} return type cannot be a handle in direct return.", func.name) ); break; default: - return_cast = wis::format( + return_cast = std::format( "reinterpret_cast<{}>", GetMemberTypeString(func.return_type, backend) ); break; } - body += wis::format( + body += std::format( " return {}(::{}({}", return_cast, c_name, @@ -599,7 +599,7 @@ std::string Generator::MakeCPPFunctionImpl( body += "));\n"; } break; case ReturnTypeKind::Void: { - body += wis::format(" ::{}({}", c_name, func.this_type.empty() ? "" : "&_impl_storage"); + body += std::format(" ::{}({}", c_name, func.this_type.empty() ? "" : "&_impl_storage"); constexpr static std::string_view arg_prefix = ",\n "; if (func.parameters.size() > 0 && !func.this_type.empty()) { body += arg_prefix; @@ -627,15 +627,15 @@ std::string Generator::MakeCPPDelegate(const WisFunction& func, DocKind kind) for (size_t i = 0; i < func.parameters.size(); ++i) { const auto& p = func.parameters[i]; std::string type_str = GetMemberTypeString(p, Backend::Any); - params += wis::format("{} {}", type_str, p.name); + params += std::format("{} {}", type_str, p.name); if (i < func.parameters.size() - 1) { params += ", "; } } - std::string delegate_decl = wis::format("using {} = void (*)({});\n", func.name, params); + std::string delegate_decl = std::format("using {} = void (*)({});\n", func.name, params); if (!func.doc.empty()) { std::string xdoc = MakeTypeDocumentation(func, kind); - delegate_decl = wis::format("{}\n{}", xdoc, delegate_decl); + delegate_decl = std::format("{}\n{}", xdoc, delegate_decl); } return delegate_decl; } @@ -646,16 +646,16 @@ std::string Generator::MakeFunctionDescription(const WisFunction& s) std::string description = " * "; if (!s.this_type.empty()) { if (s.modifier & Modifier::Construct) { - description += wis::format( + description += std::format( "- **this** `self` is a pointer to uninitialized {{{}::}} instance memory. It will be initialized by " "this function.\n", s.this_type ); // There must also be a note about the destroy function in the description - description += wis::format("**note** The corresponding destroy function is `wisDestroy{}`.\n", s.this_type); + description += std::format("**note** The corresponding destroy function is `wisDestroy{}`.\n", s.this_type); } else { - description += wis::format( + description += std::format( "- **this** `self` self is a pointer to the valid {{{}::}} instance.\n", s.this_type ); @@ -663,28 +663,28 @@ std::string Generator::MakeFunctionDescription(const WisFunction& s) } for (auto& p : s.parameters) { - description += wis::format("- `{}` {}\n", p.name, p.doc.empty() ? "No description." : p.doc); + description += std::format("- `{}` {}\n", p.name, p.doc.empty() ? "No description." : p.doc); } switch (s.return_type.GetKind()) { case ReturnTypeKind::Direct: - description += wis::format( + description += std::format( "\n- **return** {}\n", s.return_type.doc.empty() ? "No description." : s.return_type.doc ); break; case ReturnTypeKind::ResultOnly: - description += wis::format("\n- **return** denoting the outcome of operation.\n"); + description += std::format("\n- **return** denoting the outcome of operation.\n"); break; case ReturnTypeKind::ResultAndValue: { - std::string arg_name = s.return_type.opt_name.empty() ? wis::format("out_{}", MakeSnakeCase(s.return_type.type)) + std::string arg_name = s.return_type.opt_name.empty() ? std::format("out_{}", MakeSnakeCase(s.return_type.type)) : std::string(s.return_type.opt_name); - description += wis::format( + description += std::format( "- `{}` {}\n", s.return_type.opt_name.empty() ? "value" : s.return_type.opt_name, s.return_type.doc.empty() ? "No description." : s.return_type.doc ); - description += wis::format("\n- **return** denoting the outcome of operation.\n"); + description += std::format("\n- **return** denoting the outcome of operation.\n"); break; } default: @@ -699,7 +699,7 @@ std::string Generator::MakeDelegateDescription(const WisFunction& s) { std::string description = " * "; for (auto& p : s.parameters) { - description += wis::format("- `{}` {}\n", p.name, p.doc.empty() ? "No description." : p.doc); + description += std::format("- `{}` {}\n", p.name, p.doc.empty() ? "No description." : p.doc); } return description; } @@ -711,12 +711,12 @@ void Generator::WriteFunctionDocumentation(std::filesystem::path func_output_pat auto& function_names = module_map.at(active_module_name).functions_in_order; for (auto& func_name : function_names) { auto& func_def = function_map[func_name]; - std::string full_func_name = wis::format( + std::string full_func_name = std::format( "wis{}{}", func_def.modifier & (Destroy | Construct) ? "" : func_def.this_type, func_def.name ); - auto func_doc_path = func_output_path / wis::format("{}_function.h", MakeSnakeCase(full_func_name.substr(3))); + auto func_doc_path = func_output_path / std::format("{}_function.h", MakeSnakeCase(full_func_name.substr(3))); auto supports_vk = has(func_def.backend, Backend::Vulkan); auto supports_dx = has(func_def.backend, Backend::DX12); @@ -775,7 +775,7 @@ void Generator::WriteDelegateDocumentation(std::filesystem::path func_output_pat for (auto& delegate_name : module_map.at(active_module_name).delegates_in_order) { auto full_delegate_name = GetCFullTypename(delegate_name, Backend::Any); auto delegate_doc_path = func_output_path - / wis::format("{}_delegate.h", MakeSnakeCase(full_delegate_name.substr(3))); + / std::format("{}_delegate.h", MakeSnakeCase(full_delegate_name.substr(3))); auto& delegate_def = delegate_map[delegate_name]; std::string regular_code = MakeCDelegate(delegate_def, DocKind::VersionOnly); diff --git a/generator/generator.cpp b/generator/generator.cpp index 0d6bac37b..172c0fd38 100644 --- a/generator/generator.cpp +++ b/generator/generator.cpp @@ -211,11 +211,11 @@ void Generator::WriteCAPI(std::filesystem::path dir) #include "wisdom_exports.h" )"; - auto api_macro = module.name == "Core" ? "WISDOM_API " : wis::format("WISDOM_{}_API ", header_guard); + auto api_macro = module.name == "Core" ? "WISDOM_API " : std::format("WISDOM_{}_API ", header_guard); // Write header // clang-format off - file << wis::format(R"(// This file is generated. Do not edit directly. + file << std::format(R"(// This file is generated. Do not edit directly. #ifndef WISDOM_{0}_C_API_H #define WISDOM_{0}_C_API_H {1} @@ -354,7 +354,7 @@ extern "C" {{ // Write footer // clang-format off - file << wis::format(R"( + file << std::format(R"( #ifdef __cplusplus }} #endif // __cplusplus @@ -396,7 +396,7 @@ void Generator::WriteCPPAPI(std::filesystem::path dir) // Write header // clang-format off - file << wis::format(R"(// This file is generated. Do not edit directly. + file << std::format(R"(// This file is generated. Do not edit directly. #ifndef WISDOM_{0}_CPP_API_HPP #define WISDOM_{0}_CPP_API_HPP #ifndef __cplusplus @@ -465,7 +465,7 @@ namespace wis {{ } } - file << wis::format( + file << std::format( R"( }} // namespace wis @@ -515,7 +515,7 @@ namespace wis {{ } } - file << wis::format( + file << std::format( R"( }} // namespace wis #endif // WISDOM_DX12 @@ -568,7 +568,7 @@ namespace wis {{ // Write footer // clang-format off - file << wis::format(R"( + file << std::format(R"( }} // namespace wis #endif // WISDOM_VULKAN @@ -584,15 +584,15 @@ void Generator::WriteCIndependentAPI(std::filesystem::path dir) auto& module = module_map.at(active_module_name); auto independent_name = module.name == "Core" ? std::string("wisdom") - : wis::format("wisdom_{}", MakeSnakeCase(module.name)); + : std::format("wisdom_{}", MakeSnakeCase(module.name)); auto module_folder = std::filesystem::path(module.gen_path).filename().generic_string(); if (module_folder.empty()) { module_folder = std::filesystem::path(module.gen_path).parent_path().filename().generic_string(); } auto backend_include = module_folder == "wisdom" ? std::string("generated/c_api.h") - : wis::format("../{}/generated/c_api.h", module_folder); - auto header_guard = wis::format("WISDOM_{}_H", MakeUpperSnakeCase(module.name)); + : std::format("../{}/generated/c_api.h", module_folder); + auto header_guard = std::format("WISDOM_{}_H", MakeUpperSnakeCase(module.name)); std::filesystem::path path_w = dir / (independent_name + ".h"); files.push_back(path_w); @@ -603,7 +603,7 @@ void Generator::WriteCIndependentAPI(std::filesystem::path dir) } // Write header - file_w << wis::format( + file_w << std::format( R"(// This file is generated. Do not edit directly. #ifndef {0} #define {0} @@ -667,7 +667,7 @@ static_assert(WISDOM_UWP && _WIN32, "Platform error"); for (auto& handle_name : module.handles_in_order) { auto& handle_def = handle_map[handle_name]; if (has(handle_def.GetBackend(), Backend::DX12)) { - file_w << wis::format( + file_w << std::format( "typedef struct {} {};\n", GetCFullTypename(handle_def.name, Backend::DX12), GetCFullTypename(handle_def.name) @@ -679,7 +679,7 @@ static_assert(WISDOM_UWP && _WIN32, "Platform error"); for (auto& handle_name : module.views_in_order) { auto& handle_def = handle_map[handle_name]; if (handle_def.GetViewSize(Backend::DX12) > 0) { - file_w << wis::format( + file_w << std::format( "typedef struct {}View {}View;\n", GetCFullTypename(handle_def.name, Backend::DX12), GetCFullTypename(handle_def.name) @@ -697,7 +697,7 @@ static_assert(WISDOM_UWP && _WIN32, "Platform error"); for (auto& variant_name : module.variants_in_order) { auto& variant_def = variant_map[variant_name]; if (has(variant_def.backend, Backend::DX12)) { - file_w << wis::format( + file_w << std::format( "typedef struct {} {};\n", GetCFullTypename(variant_def.name, Backend::DX12), GetCFullTypename(variant_def.name) @@ -714,7 +714,7 @@ static_assert(WISDOM_UWP && _WIN32, "Platform error"); for (auto& handle_name : module.handles_in_order) { auto& handle_def = handle_map[handle_name]; if (has(handle_def.GetBackend(), Backend::DX12) && handle_def.GetViewSize(Backend::DX12) > 0) { - file_w << wis::format( + file_w << std::format( "#define wisGet{}View wisGet{}{}View\n", handle_def.name, GetBackendSuffix(Backend::DX12), @@ -727,7 +727,7 @@ static_assert(WISDOM_UWP && _WIN32, "Platform error"); for (auto& func_name : module.functions_in_order) { auto& func_def = function_map[func_name]; if (has(func_def.backend, Backend::DX12)) { - file_w << wis::format( + file_w << std::format( "#define {} {}\n", GetCFullFunctionName(func_name), GetCFullFunctionName(func_name, Backend::DX12) @@ -776,7 +776,7 @@ static_assert(WISDOM_UWP && _WIN32, "Platform error"); for (auto& handle_name : module.handles_in_order) { auto& handle_def = handle_map[handle_name]; if (has(handle_def.GetBackend(), Backend::Vulkan)) { - file_w << wis::format( + file_w << std::format( "typedef struct {} {};\n", GetCFullTypename(handle_def.name, Backend::Vulkan), GetCFullTypename(handle_def.name) @@ -788,7 +788,7 @@ static_assert(WISDOM_UWP && _WIN32, "Platform error"); for (auto& handle_name : module.views_in_order) { auto& handle_def = handle_map[handle_name]; if (handle_def.GetViewSize(Backend::Vulkan) > 0) { - file_w << wis::format( + file_w << std::format( "typedef struct {}View {}View;\n", GetCFullTypename(handle_def.name, Backend::Vulkan), GetCFullTypename(handle_def.name) @@ -806,7 +806,7 @@ static_assert(WISDOM_UWP && _WIN32, "Platform error"); for (auto& variant_name : module.variants_in_order) { auto& variant_def = variant_map[variant_name]; if (has(variant_def.backend, Backend::Vulkan)) { - file_w << wis::format( + file_w << std::format( "typedef struct {} {};\n", GetCFullTypename(variant_def.name, Backend::Vulkan), GetCFullTypename(variant_def.name) @@ -823,7 +823,7 @@ static_assert(WISDOM_UWP && _WIN32, "Platform error"); for (auto& handle_name : module.handles_in_order) { auto& handle_def = handle_map[handle_name]; if (has(handle_def.GetBackend(), Backend::Vulkan) && handle_def.GetViewSize(Backend::Vulkan) > 0) { - file_w << wis::format( + file_w << std::format( "#define wisGet{}View wisGet{}{}View\n", handle_def.name, GetBackendSuffix(Backend::Vulkan), @@ -836,7 +836,7 @@ static_assert(WISDOM_UWP && _WIN32, "Platform error"); for (auto& func_name : module.functions_in_order) { auto& func_def = function_map[func_name]; if (has(func_def.backend, Backend::Vulkan)) { - file_w << wis::format( + file_w << std::format( "#define {} {}\n", GetCFullFunctionName(func_name), GetCFullFunctionName(func_name, Backend::Vulkan) @@ -859,7 +859,7 @@ static inline bool wisHandleValid(const void* handle) { #endif // WISDOM_HANDLE_VALID_DEFINED )"; - file_w << wis::format("#endif // {}\n", header_guard); + file_w << std::format("#endif // {}\n", header_guard); } //---------------------------------------------------------------------------------------------------------------------- @@ -868,15 +868,15 @@ void Generator::WriteCPPIndependentAPI(std::filesystem::path dir) auto& module = module_map.at(active_module_name); auto independent_name = module.name == "Core" ? std::string("wisdom") - : wis::format("wisdom_{}", MakeSnakeCase(module.name)); + : std::format("wisdom_{}", MakeSnakeCase(module.name)); auto module_folder = std::filesystem::path(module.gen_path).filename().generic_string(); if (module_folder.empty()) { module_folder = std::filesystem::path(module.gen_path).parent_path().filename().generic_string(); } auto backend_include = module_folder == "wisdom" ? std::string("generated/cpp_api.hpp") - : wis::format("../{}/generated/cpp_api.hpp", module_folder); - auto header_guard = wis::format("WISDOM_{}_HPP", MakeUpperSnakeCase(module.name)); + : std::format("../{}/generated/cpp_api.hpp", module_folder); + auto header_guard = std::format("WISDOM_{}_HPP", MakeUpperSnakeCase(module.name)); std::filesystem::path path_w = dir / (independent_name + ".hpp"); files.push_back(path_w); @@ -887,7 +887,7 @@ void Generator::WriteCPPIndependentAPI(std::filesystem::path dir) } // Write header - file_w << wis::format( + file_w << std::format( R"(// This file is generated. Do not edit directly. #ifndef {0} #define {0} @@ -960,7 +960,7 @@ namespace wis {{ for (auto& handle_name : module.handles_in_order) { auto& handle_def = handle_map[handle_name]; if (has(handle_def.GetBackend(), Backend::DX12)) { - file_w << wis::format( + file_w << std::format( "using {} = {};\n", handle_def.name, GetCPPFullTypename(handle_def.name, Backend::DX12) @@ -972,7 +972,7 @@ namespace wis {{ for (auto& handle_name : module.views_in_order) { auto& handle_def = handle_map[handle_name]; if (handle_def.GetViewSize(Backend::DX12) > 0) { - file_w << wis::format( + file_w << std::format( "using {}View = {};\n", handle_def.name, GetCPPFullTypename(handle_def.name, Backend::DX12) + "View" @@ -990,7 +990,7 @@ namespace wis {{ for (auto& variant_name : module.variants_in_order) { auto& variant_def = variant_map[variant_name]; if (has(variant_def.backend, Backend::DX12)) { - file_w << wis::format( + file_w << std::format( "using {} = {};\n", variant_def.name, GetCPPFullTypename(variant_def.name, Backend::DX12) @@ -1069,7 +1069,7 @@ namespace wis { for (auto& handle_name : module.handles_in_order) { auto& handle_def = handle_map[handle_name]; if (has(handle_def.GetBackend(), Backend::Vulkan)) { - file_w << wis::format( + file_w << std::format( "using {} = {};\n", handle_def.name, GetCPPFullTypename(handle_def.name, Backend::Vulkan) @@ -1081,7 +1081,7 @@ namespace wis { for (auto& handle_name : module.views_in_order) { auto& handle_def = handle_map[handle_name]; if (handle_def.GetViewSize(Backend::Vulkan) > 0) { - file_w << wis::format( + file_w << std::format( "using {}View = {};\n", handle_def.name, GetCPPFullTypename(handle_def.name, Backend::Vulkan) + "View" @@ -1099,7 +1099,7 @@ namespace wis { for (auto& variant_name : module.variants_in_order) { auto& variant_def = variant_map[variant_name]; if (has(variant_def.backend, Backend::Vulkan)) { - file_w << wis::format( + file_w << std::format( "using {} = {};\n", variant_def.name, GetCPPFullTypename(variant_def.name, Backend::Vulkan) @@ -1131,7 +1131,7 @@ namespace wis { #error "No API selected for Wisdom. Define WISDOM_DX12 or WISDOM_VULKAN." #endif // API selection )"; - file_w << wis::format("#endif // {}\n", header_guard); + file_w << std::format("#endif // {}\n", header_guard); } void Generator::WriteConversions(std::filesystem::path dir) @@ -1159,7 +1159,7 @@ void Generator::WriteConversions(std::filesystem::path dir) auto header_guard = MakeUpperSnakeCase(module.name); // Write header - file_dx << wis::format( + file_dx << std::format( R"(// This file is generated. Do not edit directly. #ifndef WISDOM_{0}_CPP_DX12_CONVERT_HPP #define WISDOM_{0}_CPP_DX12_CONVERT_HPP @@ -1176,7 +1176,7 @@ namespace wis{{ namespace detail {{ )", header_guard ); - file_vk << wis::format( + file_vk << std::format( R"(// This file is generated. Do not edit directly. #ifndef WISDOM_{0}_CPP_VK_CONVERT_HPP #define WISDOM_{0}_CPP_VK_CONVERT_HPP @@ -1210,14 +1210,14 @@ namespace wis{{ namespace detail {{ } // Write footer - file_dx << wis::format( + file_dx << std::format( R"( }}}} #endif // WISDOM_{}_CPP_DX12_CONVERT_HPP )", header_guard ); - file_vk << wis::format( + file_vk << std::format( R"( }}}} #endif // WISDOM_{}_CPP_VK_CONVERT_HPP @@ -1245,9 +1245,9 @@ void Generator::WriteDocumentation( std::fstream enum_file{doc_output_path, file_exists ? std::ios::in | std::ios::out : std::ios::out}; if (!file_exists) { - std::string xenum = wis::vformat( + std::string xenum = std::vformat( doc_template, - wis::make_format_args(object_name, code, desc, active_module_name) + std::make_format_args(object_name, code, desc, active_module_name) ); enum_file << FinalizeCDocumentation(xenum, object_name); @@ -1374,12 +1374,12 @@ std::string Generator::GetCFullTypename(std::string_view type, Backend backend) case TypeKind::Bitmask: case TypeKind::FuncPointer: case TypeKind::Struct: - return wis::format("Wis{}", type); + return std::format("Wis{}", type); case TypeKind::Handle: case TypeKind::View: case TypeKind::Function: case TypeKind::Variant: - return wis::format("Wis{}{}", suffix, type); + return std::format("Wis{}{}", suffix, type); } return ""; } @@ -1387,9 +1387,9 @@ std::string Generator::GetCFullFunctionName(FunctionKey type, Backend backend) { auto& func_def = function_map[type]; if (func_def.IsCD()) { - return wis::format("wis{}{}", GetBackendSuffix(backend), func_def.name); + return std::format("wis{}{}", GetBackendSuffix(backend), func_def.name); } else { - return wis::format("wis{}{}{}", GetBackendSuffix(backend), func_def.this_type, func_def.name); + return std::format("wis{}{}{}", GetBackendSuffix(backend), func_def.this_type, func_def.name); } } std::string Generator::GetCPPFullTypename(std::string_view type, Backend backend) @@ -1405,12 +1405,12 @@ std::string Generator::GetCPPFullTypename(std::string_view type, Backend backend case TypeKind::Bitmask: case TypeKind::Struct: case TypeKind::Enum: - return wis::format("wis::{}", type); + return std::format("wis::{}", type); case TypeKind::Variant: case TypeKind::Handle: case TypeKind::View: case TypeKind::Function: - return wis::format("wis::{}{}", suffix, type); + return std::format("wis::{}{}", suffix, type); case TypeKind::Union: break; case TypeKind::Alias: @@ -1422,9 +1422,9 @@ std::string Generator::GetCPPFullFunctionName(FunctionKey type, Backend backend) { auto& func_def = function_map[type]; if (func_def.IsCD()) { - return wis::format("wis::{}{}", GetBackendSuffix(backend), func_def.name); + return std::format("wis::{}{}", GetBackendSuffix(backend), func_def.name); } else { - return wis::format("wis::{}{}::{}", GetBackendSuffix(backend), func_def.this_type, func_def.name); + return std::format("wis::{}{}::{}", GetBackendSuffix(backend), func_def.this_type, func_def.name); } } std::string Generator::FinalizeCDocumentation(std::string doc, std::string_view this_type, Backend backend) @@ -1457,35 +1457,35 @@ std::string Generator::FinalizeCDocumentation(std::string doc, std::string_view case TypeKind::Enum: { auto& x = enum_map.at(this_type_view); auto evalue = x.HasValue(value); - replacement = evalue ? wis::format("`{}{}`", GetCFullTypename(x.name, backend), evalue->name) + replacement = evalue ? std::format("`{}{}`", GetCFullTypename(x.name, backend), evalue->name) : GetCFullTypename(x.name, backend); break; } case TypeKind::Bitmask: { auto& b = bitmask_map.at(this_type_view); auto evalue = b.HasValue(value); - replacement = evalue ? wis::format("`{}{}`", GetCFullTypename(b.name, backend), evalue->name) + replacement = evalue ? std::format("`{}{}`", GetCFullTypename(b.name, backend), evalue->name) : GetCFullTypename(b.name, backend); break; } case TypeKind::Struct: { auto& s = struct_map.at(this_type_view); auto member = s.HasValue(value); - replacement = member ? wis::format("`{}::{}`", GetCFullTypename(s.name, backend), member->name) + replacement = member ? std::format("`{}::{}`", GetCFullTypename(s.name, backend), member->name) : GetCFullTypename(s.name, backend); break; } case TypeKind::Variant: { auto& v = variant_map.at(this_type_view); auto m = v.HasValue(value); - replacement = m ? wis::format("`{}::{}`", GetCFullTypename(v.name, backend), m->name) + replacement = m ? std::format("`{}::{}`", GetCFullTypename(v.name, backend), m->name) : GetCFullTypename(v.name, backend); break; } case TypeKind::FuncPointer: { auto& d = delegate_map.at(this_type_view); auto m = d.HasValue(value); - replacement = m ? wis::format("`{}::{}`", GetCFullTypename(d.name, backend), m->name) + replacement = m ? std::format("`{}::{}`", GetCFullTypename(d.name, backend), m->name) : GetCFullTypename(d.name, backend); break; } @@ -1574,35 +1574,35 @@ std::string Generator::FinalizeCPPDocumentation(std::string doc, std::string_vie case TypeKind::Enum: { auto& x = enum_map.at(this_type_view); auto evalue = x.HasValue(value); - replacement = evalue ? wis::format("`{}::{}`", GetCPPFullTypename(x.name, backend), evalue->name) + replacement = evalue ? std::format("`{}::{}`", GetCPPFullTypename(x.name, backend), evalue->name) : GetCPPFullTypename(x.name, backend); break; } case TypeKind::Bitmask: { auto& b = bitmask_map.at(this_type_view); auto evalue = b.HasValue(value); - replacement = evalue ? wis::format("`{}::{}`", GetCPPFullTypename(b.name, backend), evalue->name) + replacement = evalue ? std::format("`{}::{}`", GetCPPFullTypename(b.name, backend), evalue->name) : GetCPPFullTypename(b.name, backend); break; } case TypeKind::Struct: { auto& s = struct_map.at(this_type_view); auto member = s.HasValue(value); - replacement = member ? wis::format("`{}::{}`", GetCPPFullTypename(s.name, backend), member->name) + replacement = member ? std::format("`{}::{}`", GetCPPFullTypename(s.name, backend), member->name) : GetCPPFullTypename(s.name, backend); break; } case TypeKind::Variant: { auto& v = variant_map.at(this_type_view); auto m = v.HasValue(value); - replacement = m ? wis::format("`{}::{}`", GetCPPFullTypename(v.name, backend), m->name) + replacement = m ? std::format("`{}::{}`", GetCPPFullTypename(v.name, backend), m->name) : GetCPPFullTypename(v.name, backend); break; } case TypeKind::FuncPointer: { auto& d = delegate_map.at(this_type_view); auto m = d.HasValue(value); - replacement = m ? wis::format("`{}::{}`", GetCPPFullTypename(d.name, backend), m->name) + replacement = m ? std::format("`{}::{}`", GetCPPFullTypename(d.name, backend), m->name) : GetCPPFullTypename(d.name, backend); break; } @@ -1671,10 +1671,10 @@ std::string Generator::GetSpecificationCode( { std::string template_content_c; if (!c_code.empty()) { - template_content_c = wis::format(" C Version:\n```c\n{}```\n", c_code); + template_content_c = std::format(" C Version:\n```c\n{}```\n", c_code); if (!c_impl_code.empty()) { // append a details section - template_content_c += wis::format( + template_content_c += std::format( "
\nC Implementation Specific Version:\n```c\n{}```\n
\n", c_impl_code ); @@ -1683,10 +1683,10 @@ std::string Generator::GetSpecificationCode( std::string template_content_cpp; if (!cpp_code.empty()) { - template_content_cpp = wis::format("C++ Version:\n```cpp\nnamespace wis{{\n{}}}\n```\n", cpp_code); + template_content_cpp = std::format("C++ Version:\n```cpp\nnamespace wis{{\n{}}}\n```\n", cpp_code); if (!cpp_impl_code.empty()) { // append a details section - template_content_cpp += wis::format( + template_content_cpp += std::format( "
\nC++ Implementation Specific Version:\n```cpp\nnamespace " "wis{{\n{}}}\n```\n
\n", cpp_impl_code @@ -1694,7 +1694,7 @@ std::string Generator::GetSpecificationCode( } } - std::string output = wis::format(" * {}\n{}", template_content_c, template_content_cpp); + std::string output = std::format(" * {}\n{}", template_content_c, template_content_cpp); ReplaceAll(output, "\n", "\n * "); return output; } @@ -1778,7 +1778,7 @@ InlineTypeInfo Generator::FindInlineType(std::string_view str) std::string Generator::MakeVersionString(std::string_view version, bool newline) { - return version.empty() ? "" : wis::format("Provided by Wisdom {}.{}", version, newline ? "\n" : " "); + return version.empty() ? "" : std::format("Provided by Wisdom {}.{}", version, newline ? "\n" : " "); } std::string Generator::MakeSnakeCase(std::string_view str) @@ -1927,7 +1927,7 @@ std::string Generator::GetRefs(std::string_view for_type) } if (!refs.empty()) { - refs = wis::format(" * @see {}\n", refs); + refs = std::format(" * @see {}\n", refs); } return refs; } diff --git a/generator/generator.hpp b/generator/generator.hpp index 0a1e5f693..077328f24 100644 --- a/generator/generator.hpp +++ b/generator/generator.hpp @@ -8,8 +8,8 @@ #include #include #include +#include -#include "../src/include/wisdom/bridge/format.hpp" #include "types.hpp" class Generator @@ -214,11 +214,11 @@ class Generator if (kind == DocKind::VersionOnly) { if constexpr (requires { value.version; }) { if (value.version.empty()) { - return wis::format("{}\n", value_decl); + return std::format("{}\n", value_decl); } - return wis::format("// {}{}\n", version_info, value_decl); + return std::format("// {}{}\n", version_info, value_decl); } - return wis::format("{}\n", value_decl); + return std::format("{}\n", value_decl); } auto doc = value.doc; @@ -237,22 +237,22 @@ class Generator if (doc.find('\n') != std::string_view::npos) { pre_doc = true; - documentation = wis::format("/**\n@brief {}\n{}\n*/", version_info, doc); + documentation = std::format("/**\n@brief {}\n{}\n*/", version_info, doc); ReplaceAll(documentation, "\n", "\n * "); } else { - documentation = wis::format(" ///< {}{}", version_info, doc); + documentation = std::format(" ///< {}{}", version_info, doc); } documentation = finalize_doc(std::move(documentation)); if (!pre_doc && value_decl.length() + documentation.length() > value_comment_column_limit) { pre_doc = true; - documentation = wis::format("/**\n@brief {}{}\n*/", version_info, doc); + documentation = std::format("/**\n@brief {}{}\n*/", version_info, doc); ReplaceAll(documentation, "\n", "\n * "); documentation = finalize_doc(std::move(documentation)); } } - return pre_doc ? wis::format(" {}\n {}\n", documentation, value_decl) - : wis::format("{}{}\n", value_decl, documentation); + return pre_doc ? std::format(" {}\n {}\n", documentation, value_decl) + : std::format("{}{}\n", value_decl, documentation); } template @@ -265,7 +265,7 @@ class Generator if constexpr (lang == Lang::C) { // This arg if (!type.this_type.empty()) { - args += wis::format( + args += std::format( "@param self is a pointer to the valid {{{}::}} instance.\n", type.this_type ); @@ -273,16 +273,16 @@ class Generator // Function arguments for (auto& param : type.parameters) { - args += wis::format("@param {} {}\n", param.name, param.doc); + args += std::format("@param {} {}\n", param.name, param.doc); } if (type.return_type.IsRV()) { - args += wis::format("@param {} {}\n", type.return_type.opt_name, type.return_type.doc); - args += wis::format("@return {} {}\n", "Result", "denoting the outcome of operation."); + args += std::format("@param {} {}\n", type.return_type.opt_name, type.return_type.doc); + args += std::format("@return {} {}\n", "Result", "denoting the outcome of operation."); } else if (type.return_type.IsDirect()) { - args += wis::format("@return {} {}\n", type.return_type.type, type.return_type.doc); + args += std::format("@return {} {}\n", type.return_type.type, type.return_type.doc); } else if (type.return_type.IsResultOnly()) { - args += wis::format("@return {} {}\n", "Result", "denoting the outcome of operation."); + args += std::format("@return {} {}\n", "Result", "denoting the outcome of operation."); } } else { // Function arguments, beware of spans @@ -295,20 +295,20 @@ class Generator if (param.modifier & Modifier::Span) { last_was_span = true; } - args += wis::format("@param {} {}\n", param.name, param.doc); + args += std::format("@param {} {}\n", param.name, param.doc); } auto kind = type.return_type.GetKind(); switch (kind) { case ReturnTypeKind::Direct: - args += wis::format("@return {} {}\n", type.return_type.type, type.return_type.doc); + args += std::format("@return {} {}\n", type.return_type.type, type.return_type.doc); break; case ReturnTypeKind::ResultOnly: - args += wis::format("@return {} {}\n", "Result", "denoting the outcome of operation."); + args += std::format("@return {} {}\n", "Result", "denoting the outcome of operation."); break; case ReturnTypeKind::ResultAndValue: - args += wis::format("@param {} {}\n", "out_result", "denoting the outcome of operation."); - args += wis::format("@return {} {}\n", type.return_type.opt_name, type.return_type.doc); + args += std::format("@param {} {}\n", "out_result", "denoting the outcome of operation."); + args += std::format("@return {} {}\n", type.return_type.opt_name, type.return_type.doc); break; default: break; @@ -316,7 +316,7 @@ class Generator } } - std::string documentation = wis::format("/**\n@brief {}{}\n{}\n", version_info, type.doc, args); + std::string documentation = std::format("/**\n@brief {}{}\n{}\n", version_info, type.doc, args); if constexpr (requires { type.doc_translates; }) { documentation += type.doc_translates; } @@ -330,7 +330,7 @@ class Generator return FinalizeCDocumentation(documentation, type.name); } } - return wis::format("// {}", version_info); + return std::format("// {}", version_info); } template @@ -352,7 +352,7 @@ class Generator attributes_inter += "&"; } if (member.modifier & Modifier::Span) { - return wis::format( + return std::format( "wis::span<{}>", attributes_pre + GetCPPFullTypename(member.type, backend) + attributes_inter ); diff --git a/generator/handle.cpp b/generator/handle.cpp index d19725385..6a27ef232 100644 --- a/generator/handle.cpp +++ b/generator/handle.cpp @@ -132,31 +132,31 @@ std::string Generator::MakeCHandle(const WisHandle& s, Backend backend, DocKind auto extends_macro = s.extends == Extends::None ? std::string("WIS_DEFINE_HANDLE") : (s.extends == Extends::Instance - ? wis::format("WIS_DEFINE_{}_INSTANCE_EXT_HANDLE", impl_string) - : wis::format("WIS_DEFINE_{}_DEVICE_EXT_HANDLE", impl_string)); + ? std::format("WIS_DEFINE_{}_INSTANCE_EXT_HANDLE", impl_string) + : std::format("WIS_DEFINE_{}_DEVICE_EXT_HANDLE", impl_string)); auto full_name = GetCFullTypename(s.name, backend); - std::string st_decl = wis::format("{}({},{});\n", extends_macro, full_name, s.GetSize(backend)); + std::string st_decl = std::format("{}({},{});\n", extends_macro, full_name, s.GetSize(backend)); if (!s.doc.empty()) { std::string xdoc = MakeTypeDocumentation(s, kind); - st_decl = wis::format("{}\n{}", xdoc, st_decl); + st_decl = std::format("{}\n{}", xdoc, st_decl); } if (s.GetViewSize(backend) > 0) { - std::string view_decl = wis::format("WIS_DEFINE_HANDLE_VIEW({},{});\n", full_name, s.GetViewSize(backend)); + std::string view_decl = std::format("WIS_DEFINE_HANDLE_VIEW({},{});\n", full_name, s.GetViewSize(backend)); st_decl += view_decl; } if (kind == DocKind::Full && s.GetViewSize(backend) > 0) { // Add view extraction function - st_decl += wis::format( + st_decl += std::format( "\nstatic inline {}View wisGet{}{}View(const {}* handle){{\n", full_name, impl_string, s.name, full_name ); - st_decl += wis::format(" {}View v;\n", full_name); + st_decl += std::format(" {}View v;\n", full_name); st_decl += " memcpy(&v, handle, sizeof(v));\n" " return v;\n}\n"; } @@ -170,7 +170,7 @@ std::string Generator::MakeCPPHandle(const WisHandle& s, Backend backend, DocKin auto impl_string = GetBackendSuffix(backend); auto full_name = GetCFullTypename(s.name, backend); - std::string deleter = wis::format( + std::string deleter = std::format( "struct {}{}Deleter {{\n " "void operator()({}* handle) noexcept {{\n ", impl_string, @@ -178,7 +178,7 @@ std::string Generator::MakeCPPHandle(const WisHandle& s, Backend backend, DocKin full_name ); - std::string st_decl = wis::format( + std::string st_decl = std::format( "class {}{} : public wis::impl::Implements{{\npublic:\n", impl_string, s.name, @@ -191,13 +191,13 @@ std::string Generator::MakeCPPHandle(const WisHandle& s, Backend backend, DocKin if (!s.doc.empty()) { std::string xdoc = MakeTypeDocumentation(s, kind); - st_decl = wis::format("{}\n{}", xdoc, st_decl); + st_decl = std::format("{}\n{}", xdoc, st_decl); } std::string ctor_decl; // Use constructor from base if (s.extends != Extends::None) { - ctor_decl += wis::format("{}{}() noexcept\n:ImplType(std::in_place)\n{{\n ", impl_string, s.name); + ctor_decl += std::format("{}{}() noexcept\n:ImplType(std::in_place)\n{{\n ", impl_string, s.name); } else { ctor_decl += " using ImplType::ImplType;\n"; } @@ -205,7 +205,7 @@ std::string Generator::MakeCPPHandle(const WisHandle& s, Backend backend, DocKin if (s.GetViewSize(backend) > 0) { // Strict aliasing rules prevent us from doing a simple cast, so we have to memcpy the data to a new view struct - st_decl2 += wis::format( + st_decl2 += std::format( " WIS_NODISCARD {}{}View GetView() const noexcept {{\n" " {}{}View v;\n" " std::memcpy(&v, &_impl_storage, sizeof(v));\n" @@ -218,7 +218,7 @@ std::string Generator::MakeCPPHandle(const WisHandle& s, Backend backend, DocKin ); // add conversion operator to view - st_decl2 += wis::format( + st_decl2 += std::format( " WIS_NODISCARD operator {}{}View() const noexcept {{\n" " return GetView();\n" " }}\n", @@ -231,18 +231,18 @@ std::string Generator::MakeCPPHandle(const WisHandle& s, Backend backend, DocKin for (const auto& func_name : s.functions) { FunctionKey func_key{s.name, func_name}; auto& func_ref = function_map[func_key]; - auto c_name = wis::format( + auto c_name = std::format( "wis{}{}{}", impl_string, func_ref.modifier & (Destroy | Construct) ? "" : func_ref.this_type, func_ref.name ); if (func_ref.modifier & Modifier::Destroy) { - deleter += wis::format(" ::{}(handle);\n", c_name); + deleter += std::format(" ::{}(handle);\n", c_name); continue; } if (func_ref.modifier & Modifier::Construct) { - ctor_decl += wis::format(" ::{}(GetStorage());\n }}\n", c_name); + ctor_decl += std::format(" ::{}(GetStorage());\n }}\n", c_name); continue; } @@ -252,7 +252,7 @@ std::string Generator::MakeCPPHandle(const WisHandle& s, Backend backend, DocKin if (s.extends != Extends::None) { auto header = s.extends == Extends::Instance ? GetCPPFullTypename("InstanceExtensionHeader", backend) : GetCPPFullTypename("DeviceExtensionHeader", backend); - ctor_decl += wis::format( + ctor_decl += std::format( " // Operator & overload\n" "{}* operator&() noexcept {{\n" " return &GetMutableInternal().header;\n" @@ -274,7 +274,7 @@ std::string Generator::MakeCPPView(const WisHandle& s, Backend backend, DocKind std::string view_decl; if (s.GetViewSize(backend) > 0) { - view_decl = wis::format("using {}{}View = {}View;\n", impl_string, s.name, full_name); + view_decl = std::format("using {}{}View = {}View;\n", impl_string, s.name, full_name); } return view_decl; } @@ -289,18 +289,18 @@ void Generator::WriteHandleDocumentation(std::filesystem::path handle_output_pat // Make a folder for enums starting with this letter std::filesystem::create_directories(handle_output_path); std::filesystem::path handle_file_path = handle_output_path - / wis::format("{}_handle.h", MakeSnakeCase(handle_name)); + / std::format("{}_handle.h", MakeSnakeCase(handle_name)); auto& handle_ref = handle_map[handle_name]; std::string vk_code; std::string dx_code; if (has(backend, Backend::Vulkan)) { vk_code = MakeCHandle(handle_ref, Backend::Vulkan, DocKind::VersionOnly); - vk_code = wis::format(" Vulkan Version:\n```c\n{}```\n", vk_code); + vk_code = std::format(" Vulkan Version:\n```c\n{}```\n", vk_code); } if (has(backend, Backend::DX12)) { dx_code = MakeCHandle(handle_ref, Backend::DX12, DocKind::VersionOnly); - dx_code = wis::format(" DX12 Version:\n```c\n{}```\n", dx_code); + dx_code = std::format(" DX12 Version:\n```c\n{}```\n", dx_code); } std::string handle_template_content = " * " + vk_code + dx_code; diff --git a/generator/pch.hpp b/generator/pch.hpp index 555286ef7..60de69698 100644 --- a/generator/pch.hpp +++ b/generator/pch.hpp @@ -8,4 +8,4 @@ #include #include #include -#include "../src/include/wisdom/bridge/format.hpp" +#include diff --git a/generator/struct.cpp b/generator/struct.cpp index 7f4fd75ca..b81c22f49 100644 --- a/generator/struct.cpp +++ b/generator/struct.cpp @@ -48,7 +48,7 @@ void Generator::ParseStruct(tinyxml2::XMLElement* type) if (auto* size = type->FindAttribute("version")) { ref.version = size->Value(); } else { - throw std::runtime_error(wis::format("Struct {} is missing version attribute.", name)); + throw std::runtime_error(std::format("Struct {} is missing version attribute.", name)); } if (auto* mod = type->FindAttribute("mod")) { @@ -87,14 +87,14 @@ void Generator::ParseStruct(tinyxml2::XMLElement* type) std::string Generator::MakeCStruct(const WisStruct& s, DocKind kind) { auto full_name = GetCFullTypename(s.name, Backend::Any); - std::string st_decl = wis::format( + std::string st_decl = std::format( "typedef struct {} {} {{\n", s.modifier & Modifier::Nodiscard ? "WIS_NODISCARD" : "", full_name ); if (!s.doc.empty()) { std::string xdoc = MakeTypeDocumentation(s, kind); - st_decl = wis::format("{}\n{}", xdoc, st_decl); + st_decl = std::format("{}\n{}", xdoc, st_decl); } // Calculate maximum type length for alignment @@ -107,21 +107,21 @@ std::string Generator::MakeCStruct(const WisStruct& s, DocKind kind) for (auto& m : s.members) { st_decl += MakeValueDocumentation(s, m, MakeCMemberDeclaration(m, max_type_length), kind); } - st_decl += wis::format("}} {};\n\n", full_name); + st_decl += std::format("}} {};\n\n", full_name); return st_decl; } //---------------------------------------------------------------------------------------------------------------------- std::string Generator::MakeCPPStruct(const WisStruct& s, DocKind kind) { - std::string st_decl = wis::format( + std::string st_decl = std::format( "struct {} {} {{\n", s.modifier & Modifier::Nodiscard ? "WIS_NODISCARD" : "", s.name ); if (!s.doc.empty()) { std::string xdoc = MakeTypeDocumentation(s, kind); - st_decl = wis::format("{}\n{}", xdoc, st_decl); + st_decl = std::format("{}\n{}", xdoc, st_decl); } // Calculate maximum type length for alignment @@ -157,7 +157,7 @@ std::string Generator::MakeCMemberDeclaration(const WisStructMember& member, siz std::string array_modifier; if (!member.array_size.empty()) { - array_modifier = wis::format("[{}]", member.array_size); + array_modifier = std::format("[{}]", member.array_size); } // Pad the type string to align_width @@ -173,7 +173,7 @@ std::string Generator::MakeCPPMemberDeclaration(const WisStructMember& member, s std::string type_string = GetMemberTypeString(member, backend); if (!member.array_size.empty()) { - type_string = wis::format("std::array<{}, {}>", type_string, member.array_size); + type_string = std::format("std::array<{}, {}>", type_string, member.array_size); } // Pad the type string to align_width @@ -188,7 +188,7 @@ std::string Generator::MakeStructDescription(const WisStruct& s) { std::string description; for (auto& m : s.members) { - description += wis::format("- `{}` {}\n", m.name, m.doc.empty() ? "No description." : m.doc); + description += std::format("- `{}` {}\n", m.name, m.doc.empty() ? "No description." : m.doc); } return description; } @@ -201,17 +201,17 @@ void Generator::WriteStructDocumentation(std::filesystem::path struct_output_pat for (const auto& struct_name : struct_names) { // Make a folder for enums starting with this letter std::filesystem::path struct_file_path = struct_output_path - / wis::format("{}_struct.h", MakeSnakeCase(struct_name)); + / std::format("{}_struct.h", MakeSnakeCase(struct_name)); auto& struct_ref = struct_map[struct_name]; - std::string struct_template_content = wis::format( + std::string struct_template_content = std::format( " * C version:\n```c\n{}```\n" "C++ version:\n```cpp\nnamespace wis{{\n{}}}\n```\n", MakeCStruct(struct_ref, DocKind::VersionOnly), MakeCPPStruct(struct_ref, DocKind::VersionOnly) ); - std::string struct_description = wis::format(" * {}", MakeStructDescription(struct_ref)); + std::string struct_description = std::format(" * {}", MakeStructDescription(struct_ref)); std::string struct_refs = GetRefs(struct_name); std::string vuids = MakeValidationForType(struct_name); diff --git a/generator/validation.cpp b/generator/validation.cpp index 3723fffe5..33388eed5 100644 --- a/generator/validation.cpp +++ b/generator/validation.cpp @@ -24,14 +24,14 @@ void Generator::ParseValidations(tinyxml2::XMLElement* validations) if (auto* id_attr = check->FindAttribute("id")) { vcheck.id = id_attr->Value(); } else { - throw std::runtime_error(wis::format("Validation for {} is missing id attribute.", name)); + throw std::runtime_error(std::format("Validation for {} is missing id attribute.", name)); } // Message if (auto* msg = check->FindAttribute("msg")) { vcheck.message = msg->Value(); } else { - throw std::runtime_error(wis::format("Validation for {} is missing message attribute.", name)); + throw std::runtime_error(std::format("Validation for {} is missing message attribute.", name)); } ref.push_back(vcheck); @@ -43,7 +43,7 @@ void Generator::ParseValidations(tinyxml2::XMLElement* validations) std::string Generator::MakeValidationDescription(const Validation& v) { auto doc = FinalizeCDocumentation(std::string(v.message), v.type_name); - return wis::format(" * @vuid_begin{{WIS-{}-{}}} {} @vuid_end\n", GetCFullTypename(v.type_name), v.id, doc); + return std::format(" * @vuid_begin{{WIS-{}-{}}} {} @vuid_end\n", GetCFullTypename(v.type_name), v.id, doc); } //---------------------------------------------------------------------------------------------------------------------- diff --git a/generator/variant.cpp b/generator/variant.cpp index 7b1be3d5e..37b49e552 100644 --- a/generator/variant.cpp +++ b/generator/variant.cpp @@ -48,7 +48,7 @@ void Generator::ParseVariant(tinyxml2::XMLElement* type) if (auto* size = type->FindAttribute("version")) { ref.version = size->Value(); } else { - throw std::runtime_error(wis::format("Struct {} is missing version attribute.", name)); + throw std::runtime_error(std::format("Struct {} is missing version attribute.", name)); } if (auto* mod = type->FindAttribute("mod")) { @@ -90,14 +90,14 @@ std::string Generator::MakeCVariant(const WisStruct& s, Backend backend, DocKind { auto impl_suffix = GetBackendSuffix(backend); auto full_name = GetCFullTypename(s.name, backend); - std::string st_decl = wis::format( + std::string st_decl = std::format( "typedef struct {}{} {{\n", s.modifier & Modifier::Nodiscard ? "WIS_NODISCARD " : "", full_name ); if (!s.doc.empty()) { std::string xdoc = MakeTypeDocumentation(s, kind); - st_decl = wis::format("{}\n{}", xdoc, st_decl); + st_decl = std::format("{}\n{}", xdoc, st_decl); } // Calculate maximum type length for alignment @@ -110,7 +110,7 @@ std::string Generator::MakeCVariant(const WisStruct& s, Backend backend, DocKind for (auto& m : s.members) { st_decl += MakeValueDocumentation(s, m, MakeCMemberDeclaration(m, max_type_length, backend), kind); } - st_decl += wis::format("}} {};\n", full_name); + st_decl += std::format("}} {};\n", full_name); return st_decl; } @@ -122,7 +122,7 @@ std::string Generator::MakeCPPVariant(const WisStruct& s, Backend backend, DocKi } auto impl_suffix = GetBackendSuffix(backend); - std::string st_decl = wis::format( + std::string st_decl = std::format( "struct {}{}{} {{\n", s.modifier & Modifier::Nodiscard ? "WIS_NODISCARD " : "", impl_suffix, @@ -130,7 +130,7 @@ std::string Generator::MakeCPPVariant(const WisStruct& s, Backend backend, DocKi ); if (!s.doc.empty()) { std::string xdoc = MakeTypeDocumentation(s, kind); - st_decl = wis::format("{}\n{}", xdoc, st_decl); + st_decl = std::format("{}\n{}", xdoc, st_decl); } // Calculate maximum type length for alignment @@ -158,7 +158,7 @@ std::string Generator::MakeVariantDescription(const WisStruct& s) { std::string description; for (auto& m : s.members) { - description += wis::format("- `{}` {}\n", m.name, m.doc.empty() ? "No description." : m.doc); + description += std::format("- `{}` {}\n", m.name, m.doc.empty() ? "No description." : m.doc); } return description; } @@ -171,7 +171,7 @@ void Generator::WriteVariantDocumentation(std::filesystem::path struct_output_pa for (const auto& variant_name : variant_names) { // Make a folder for enums starting with this letter std::filesystem::path variant_file_path = struct_output_path - / wis::format("{}_struct.h", MakeSnakeCase(variant_name)); + / std::format("{}_struct.h", MakeSnakeCase(variant_name)); auto& variant_ref = variant_map[variant_name]; auto supports_vk = has(variant_ref.backend, Backend::Vulkan); @@ -208,7 +208,7 @@ void Generator::WriteVariantDocumentation(std::filesystem::path struct_output_pa std::string variant_template_content = GetSpecificationCode(c_code, cimpl_code, cpp_code, cimpl_code_cpp); - std::string variant_description = wis::format(" * {}", MakeVariantDescription(variant_ref)); + std::string variant_description = std::format(" * {}", MakeVariantDescription(variant_ref)); std::string variant_refs = GetRefs(variant_name); std::string vuids = MakeValidationForType(variant_name); diff --git a/src/include/wisdom/bridge/format.hpp b/src/include/wisdom/bridge/format.hpp deleted file mode 100644 index e68cad3a4..000000000 --- a/src/include/wisdom/bridge/format.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef WIS_BRIDGE_FORMAT_H -#define WIS_BRIDGE_FORMAT_H -#if defined(WISDOM_USE_FMT) -# include -namespace wis { -using fmt::format; // NOLINT -using fmt::format_to; // NOLINT -using fmt::make_format_args; // NOLINT -using fmt::vformat; // NOLINT -} // namespace wis -#elif __has_include() -# include -namespace wis { -using std::format; -using std::format_to; -using std::make_format_args; -using std::vformat; -} // namespace wis -#else -# error "wisdom requires fmt or std::format" -#endif -#endif // WISDOM_BRIDGE_FORMAT_H diff --git a/src/include/wisdom/dx12/dx12_device.cpp b/src/include/wisdom/dx12/dx12_device.cpp index 9a23fc6a1..3bc2a06b8 100644 --- a/src/include/wisdom/dx12/dx12_device.cpp +++ b/src/include/wisdom/dx12/dx12_device.cpp @@ -1,7 +1,6 @@ #ifndef WIS_DX12_DEVICE_CPP #define WIS_DX12_DEVICE_CPP -#include #include #include #include @@ -31,8 +30,11 @@ WIS_EXTERN_C WISDOM_API void wisDX12DestroyDevice(WisDX12Device* self) } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisDX12DeviceCreateCommandQueue(const WisDX12Device* self, WisCommandQueueType type, WisDX12CommandQueue* queue) +WIS_EXTERN_C WISDOM_API WisResult wisDX12DeviceCreateCommandQueue( + const WisDX12Device* self, + WisCommandQueueType type, + WisDX12CommandQueue* queue +) { auto& device = wis::from_handle_ref(self); @@ -64,8 +66,11 @@ wisDX12DeviceCreateCommandQueue(const WisDX12Device* self, WisCommandQueueType t } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisDX12DeviceCreateCommandAllocator(const WisDX12Device* self, WisCommandQueueType type, WisDX12CommandAllocator* list) +WIS_EXTERN_C WISDOM_API WisResult wisDX12DeviceCreateCommandAllocator( + const WisDX12Device* self, + WisCommandQueueType type, + WisDX12CommandAllocator* list +) { WisResult result = wis::detail::dx_success; auto& device = wis::from_handle_ref(self); @@ -90,8 +95,11 @@ wisDX12DeviceCreateCommandAllocator(const WisDX12Device* self, WisCommandQueueTy } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisDX12DeviceCreateFence(const WisDX12Device* self, uint64_t initial_value, WisDX12Fence* fence) +WIS_EXTERN_C WISDOM_API WisResult wisDX12DeviceCreateFence( + const WisDX12Device* self, + uint64_t initial_value, + WisDX12Fence* fence +) { WisResult result = wis::detail::dx_success; auto& device = wis::from_handle_ref(self); @@ -120,8 +128,10 @@ wisDX12DeviceCreateFence(const WisDX12Device* self, uint64_t initial_value, WisD } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisDX12DeviceGetResourceAllocator(const WisDX12Device* self, WisDX12ResourceAllocator* allocator) +WIS_EXTERN_C WISDOM_API WisResult wisDX12DeviceGetResourceAllocator( + const WisDX12Device* self, + WisDX12ResourceAllocator* allocator +) { auto& device = wis::from_handle_ref(self); @@ -257,7 +267,8 @@ WIS_EXTERN_C WISDOM_API WisResult wisDX12DeviceCreateRootSignature( // Check limits if (push_constant_size + 2 * desc->push_descriptor_count + desc->descriptor_table_count > max_root_parameters) { - return wis::detail::make_result(E_INVALIDARG + return wis::detail::make_result( + E_INVALIDARG ); } @@ -287,9 +298,9 @@ WIS_EXTERN_C WISDOM_API WisResult wisDX12DeviceCreateRootSignature( auto& src = desc->push_descriptors[i]; if (!wis::detail::DX12IsPushable(src.type)) { - return wis::detail:: - make_result(E_INVALIDARG - ); + return wis::detail::make_result< + wis::detail::Func(), + "Descriptor type is not pushable to DX12 root signature">(E_INVALIDARG); } root_parameters_span[i] = { @@ -357,14 +368,13 @@ WIS_EXTERN_C WISDOM_API WisResult wisDX12DeviceCreateRootSignature( D3D12_VERSIONED_ROOT_SIGNATURE_DESC rsig_desc{ .Version = D3D_ROOT_SIGNATURE_VERSION_1_2, - .Desc_1_2 = - { - .NumParameters = static_cast(num_root_parameters), - .pParameters = root_parameters, - .NumStaticSamplers = 0, - .pStaticSamplers = nullptr, - .Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT, - }, + .Desc_1_2 = { + .NumParameters = static_cast(num_root_parameters), + .pParameters = root_parameters, + .NumStaticSamplers = 0, + .pStaticSamplers = nullptr, + .Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT, + }, }; wis::com_ptr signature; @@ -568,8 +578,12 @@ WIS_EXTERN_C WISDOM_API WisResult wisDX12DeviceCreatePipelineCache( } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisDX12DeviceCreateShader(const WisDX12Device* self, const uint8_t* data, size_t size, WisDX12Shader* shader) +WIS_EXTERN_C WISDOM_API WisResult wisDX12DeviceCreateShader( + const WisDX12Device* self, + const uint8_t* data, + size_t size, + WisDX12Shader* shader +) { if (!data || size == 0) { return wis::detail::make_result(E_INVALIDARG); @@ -581,7 +595,8 @@ wisDX12DeviceCreateShader(const WisDX12Device* self, const uint8_t* data, size_t operator new(wis::aligned_size(size, 8ull) + sizeof(wis::detail::DX12ShaderHeader), std::nothrow) )}; if (!shader_header) { - return wis::detail::make_result(E_OUTOFMEMORY + return wis::detail::make_result( + E_OUTOFMEMORY ); } @@ -650,7 +665,8 @@ WIS_EXTERN_C WISDOM_API WisResult wisDX12DeviceCreateComputePipeline( wis::com_ptr pipeline_state; // Calculate hash of pipeline state description for caching purposes - wchar_t name_buffer[256] = {}; + static constexpr std::size_t hash_input_size = 256; + wchar_t name_buffer[hash_input_size] = {}; if (cache) { // Get root signature hash @@ -670,7 +686,7 @@ WIS_EXTERN_C WISDOM_API WisResult wisDX12DeviceCreateComputePipeline( XXH128_hash_t pso_hash = XXH3_128bits(rehash_input, sizeof(rehash_input)); // convert hash to hex string for use as pipeline cache key - wis::format_to(name_buffer, L"CPSO_{:016x}{:016x}", pso_hash.low64, pso_hash.high64); + std::swprintf(name_buffer, hash_input_size, L"CPSO_%016llx%016llx", pso_hash.low64, pso_hash.high64); // Try to load pipeline from cache first if available HRESULT hr = cache->LoadPipeline( @@ -979,7 +995,8 @@ WIS_EXTERN_C WISDOM_API WisResult wisDX12DeviceCreateGraphicsPipeline( }; wis::com_ptr pipeline_state; - wchar_t name_buffer[128] = {}; + static constexpr std::size_t hash_input_size = 256; + wchar_t name_buffer[hash_input_size] = {}; if (cache) { uint32_t name_offset = 0; // max 7 struct RehashInput { @@ -1011,10 +1028,11 @@ WIS_EXTERN_C WISDOM_API WisResult wisDX12DeviceCreateGraphicsPipeline( rehash_input.multiview_mask = desc->render_attachments.view_mask; // Hash pso stream - wis::span pso_stream_bytes{// start after bytecodes - reinterpret_cast(&stream.flags), - // end at the end of the struct - reinterpret_cast(&stream + 1) + wis::span pso_stream_bytes{ + // start after bytecodes + reinterpret_cast(&stream.flags), + // end at the end of the struct + reinterpret_cast(&stream + 1) }; XXH128_hash_t stream_hash = XXH3_128bits(pso_stream_bytes.data(), pso_stream_bytes.size()); rehash_input.pso_hash[0] = stream_hash.low64; @@ -1024,7 +1042,13 @@ WIS_EXTERN_C WISDOM_API WisResult wisDX12DeviceCreateGraphicsPipeline( XXH128_hash_t pso_hash = XXH3_128bits(&rehash_input, sizeof(rehash_input)); // convert hash to hex string for use as pipeline cache key - wis::format_to(name_buffer + name_offset, L"PSO_{:016x}{:016x}", pso_hash.low64, pso_hash.high64); + std::swprintf( + name_buffer + name_offset, + hash_input_size - name_offset, + L"PSO_%016llx%016llx", + pso_hash.low64, + pso_hash.high64 + ); // Try to load pipeline from cache first if available HRESULT hr = cache->LoadPipeline( @@ -1087,8 +1111,11 @@ WIS_EXTERN_C WISDOM_API bool wisDX12DeviceGetFormatPresentationSupport( } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisDX12DeviceGetSurfaceParameters(const WisDX12Device* self, WisDX12SurfaceView surface, WisSurfaceParameters* params) +WIS_EXTERN_C WISDOM_API WisResult wisDX12DeviceGetSurfaceParameters( + const WisDX12Device* self, + WisDX12SurfaceView surface, + WisSurfaceParameters* params +) { auto& impl = wis::from_handle_ref(self); *params = { @@ -1196,8 +1223,11 @@ WIS_EXTERN_C WISDOM_API WisResult wisDX12DeviceCreateSwapchain( } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisDX12DeviceGetFormatProperties(const WisDX12Device* self, WisDataFormat format, WisFormatProperties* properties) +WIS_EXTERN_C WISDOM_API WisResult wisDX12DeviceGetFormatProperties( + const WisDX12Device* self, + WisDataFormat format, + WisFormatProperties* properties +) { auto& impl = wis::from_handle_ref(self); D3D12_FEATURE_DATA_FORMAT_SUPPORT formatSupport = {.Format = wis::detail::DX12Convert(format)}; From 3d24f2abb0f57f878fbe3045d1f225e15b1eb38c Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Mon, 20 Apr 2026 21:33:09 +0200 Subject: [PATCH 02/10] Add optional DirectX 12 Agility SDK support via CMake Introduce WISDOM_USE_AGILITY_SDK CMake option to enable building with the DirectX 12 Agility SDK for access to newer DX12 features on older Windows versions. Refactor dependency logic to conditionally fetch and deploy Agility SDK or DirectX-Headers as needed. Update DX12Allocator linkage and macro definitions accordingly. Replace legacy Agility deployment functions with a unified install function. Update documentation and source includes to reflect these changes. --- CMakeLists.txt | 2 + README.md | 5 +- cmake/deps/deps_win.cmake | 175 ++++++++++-------- cmake/functions.cmake | 97 ++-------- cmake/install/nuget.cmake | 7 +- cmake/install/wisdom.targets | 2 +- docs/wisdom/getting_started.h | 1 + examples/compute_particles_c/CMakeLists.txt | 4 +- examples/hello_triangle/CMakeLists.txt | 6 +- examples/multisampling/CMakeLists.txt | 4 +- generator/generator.cpp | 1 - src/include/CMakeLists.txt | 3 +- .../wisdom/dx12/detail/dx12_detail.hpp | 2 - src/include/wisdom/dx12/dx12_device.cpp | 6 +- src/include/wisdom/dx12/dx12_impl.cpp | 4 + src/include/wisdom/dx12/dx12_types.hpp | 4 +- src/include/wisdom/generated/dx12_convert.hpp | 1 - src/include/wisdom/global/definitions.h | 9 + 18 files changed, 155 insertions(+), 178 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6d8fc77b7..d84bfd139 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,8 @@ option(WISDOM_BUILD_STATIC "Build the static lib." ON) option(WISDOM_BUILD_SHARED "Build the dynamic lib." ON) option(WISDOM_BUILD_PLATFORM "Build unified platform extension library." ON) option(WISDOM_BUILD_DOCS "Build the documentation." OFF) +option(WISDOM_USE_AGILITY_SDK "Download and use DirectX 12 Agility SDK." OFF) + # DXC deployment options set(WISDOM_DXC_PATH diff --git a/README.md b/README.md index 31b58801e..4ea711622 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,7 @@ Vulkan library is loaded dynamically, so it is not required to have Vulkan SDK i - `WISDOM_BUILD_STATIC=ON` build static library version. - `WISDOM_BUILD_SHARED=ON` build shared/dynamic library version. - `WISDOM_BUILD_PLATFORM=ON` build unified platform extension library. +- `WISDOM_USE_AGILITY_SDK=OFF` download and build with Agility SDK instead of Windows SDK, this allows using latest DirectX 12 features on older Windows versions, but requires additional setup and dependencies. Default is `OFF`, which uses Windows SDK that comes with the system and DirectX-Headers. - `WISDOM_BUILD_DOCS=OFF` build documentation with Doxygen, default is dependent on whether you are building the library as a top project (ON) or as a part/dep for other (OFF) - `WISDOM_DXC_PATH="Path/to/dxc"` use system DXC compiler instead of the one provided with the library (default uses the one provided) @@ -115,8 +116,8 @@ To link library simply use `target_link_libraries(${YOUR_TARGET} PUBLIC wis::wis Available targets are: -- `wis::wisdom | wis::wisdom-headers` - functional library -- `wis::platform | wis::wisdom-platform-headers` - platform specific extensions (Surface) +- `wis::wisdom | wis::wisdom-headers | wis::wisdom-shared` - functional library +- `wis::platform | wis::wisdom-platform-headers | wis::wisdom-platform-shared` - platform specific extensions (Surface) There is also Conan package available for consumption, it can't be loaded to Conan Center yet, but you can add it manually by downloading the repo and executing `conan create .` command in the root of the repository. diff --git a/cmake/deps/deps_win.cmake b/cmake/deps/deps_win.cmake index e56cd8bed..9bba023b1 100644 --- a/cmake/deps/deps_win.cmake +++ b/cmake/deps/deps_win.cmake @@ -1,81 +1,101 @@ -include(${CMAKE_CURRENT_LIST_DIR}/nuget.cmake) - -_ww_find_nuget() - -# DirectX 12 Agility SDK -message("Setting up DirectX 12 Agility...") -_ww_load_nuget_dependency(${NUGET_EXE} "Microsoft.Direct3D.D3D12" DXA - ${CMAKE_CURRENT_BINARY_DIR}) - -string(REGEX MATCH "([0-9]+)\\.([0-9]+)\\.([0-9]+)$" VERSION_MATCH ${DXA_DIR}) - -message("Agility version: ${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}") -set(DXA_VERSION - ${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3} - CACHE INTERNAL "") -set(VERSION_MINOR - ${CMAKE_MATCH_2} - CACHE INTERNAL "") - -set(DXA_HEADERS ${DXA_DIR}/build/native/include) -set(DXA_SRC ${DXA_DIR}/build/native/src) -set(DXA_BIN ${DXA_DIR}/build/native/bin/x64) -set(DXAGILITY_DLL - ${DXA_BIN}/D3D12Core.dll - CACHE INTERNAL "") -set(DXAGILITY_DEBUG_DLL - ${DXA_BIN}/d3d12SDKLayers.dll - CACHE INTERNAL "") - -add_library(DX12AgilityCore MODULE IMPORTED GLOBAL) -set_property(TARGET DX12AgilityCore PROPERTY IMPORTED_LOCATION - ${DXAGILITY_DLL}) - -add_library(DX12AgilitySDKLayers MODULE IMPORTED GLOBAL) -set_property(TARGET DX12AgilitySDKLayers PROPERTY IMPORTED_LOCATION - ${DXAGILITY_DEBUG_DLL}) - -# Header interface library -add_library(DX12Agility STATIC) -add_library(wis::DX12Agility ALIAS DX12Agility) - -target_include_directories( - DX12Agility SYSTEM BEFORE - PUBLIC $ $ - PRIVATE $) -target_sources(DX12Agility - PRIVATE ${DXA_SRC}/d3dx12/d3dx12_property_format_table.cpp) - -install( - TARGETS DX12Agility - EXPORT wisdom-targets - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) - -install( - IMPORTED_RUNTIME_ARTIFACTS - DX12AgilityCore - DX12AgilitySDKLayers - RUNTIME - DESTINATION - ${CMAKE_INSTALL_BINDIR} - LIBRARY - DESTINATION - ${CMAKE_INSTALL_BINDIR}) +if (WISDOM_USE_AGILITY_SDK) + include(${CMAKE_CURRENT_LIST_DIR}/nuget.cmake) + + _ww_find_nuget() + + # DirectX 12 Agility SDK + message("Setting up DirectX 12 Agility...") + _ww_load_nuget_dependency(${NUGET_EXE} "Microsoft.Direct3D.D3D12" DXA + ${CMAKE_CURRENT_BINARY_DIR}) + + string(REGEX MATCH "([0-9]+)\\.([0-9]+)\\.([0-9]+)$" VERSION_MATCH ${DXA_DIR}) + + message("Agility version: ${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}") + set(DXA_VERSION + ${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3} + CACHE INTERNAL "") + set(VERSION_MINOR + ${CMAKE_MATCH_2} + CACHE INTERNAL "") + + set(DXA_HEADERS ${DXA_DIR}/build/native/include) + set(DXA_SRC ${DXA_DIR}/build/native/src) + set(DXA_BIN ${DXA_DIR}/build/native/bin/x64) + set(DXAGILITY_DLL + ${DXA_BIN}/D3D12Core.dll + CACHE INTERNAL "") + set(DXAGILITY_DEBUG_DLL + ${DXA_BIN}/d3d12SDKLayers.dll + CACHE INTERNAL "") + + add_library(DX12AgilityCore MODULE IMPORTED GLOBAL) + set_property(TARGET DX12AgilityCore PROPERTY IMPORTED_LOCATION + ${DXAGILITY_DLL}) + + add_library(DX12AgilitySDKLayers MODULE IMPORTED GLOBAL) + set_property(TARGET DX12AgilitySDKLayers PROPERTY IMPORTED_LOCATION + ${DXAGILITY_DEBUG_DLL}) + + # Header interface library + add_library(DX12Helpers STATIC) + add_library(wis::DX12Helpers ALIAS DX12Helpers) + + target_include_directories( + DX12Helpers SYSTEM BEFORE + PUBLIC $ $ + PRIVATE $) + target_sources(DX12Helpers + PRIVATE ${DXA_SRC}/d3dx12/d3dx12_property_format_table.cpp) + target_compile_definitions(DX12Helpers PUBLIC + DX12SDKVER=${VERSION_MINOR} + ) + install( + TARGETS DX12Helpers + EXPORT wisdom-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + + install( + IMPORTED_RUNTIME_ARTIFACTS + DX12AgilityCore + DX12AgilitySDKLayers + RUNTIME + DESTINATION + ${CMAKE_INSTALL_BINDIR} + LIBRARY + DESTINATION + ${CMAKE_INSTALL_BINDIR}) + + install(DIRECTORY ${DXA_HEADERS}/ DESTINATION include/d3dx12) + + set_target_properties(DX12Helpers PROPERTIES + DEBUG_POSTFIX d + ) +else() + message("DirectX 12 Agility SDK not enabled. Using Headers instead.") -install(DIRECTORY ${DXA_HEADERS}/ DESTINATION include/d3dx12) + # Guaranteed backwards compatibility. + # Using origin/main to ensure we get the latest headers, + # which are compatible with the latest SDKs. + CPMAddPackage( + NAME dxheaders + GITHUB_REPOSITORY microsoft/DirectX-Headers + GIT_TAG origin/main + ) -set_target_properties(DX12Agility PROPERTIES - DX12SDKVER ${VERSION_MINOR} - DEBUG_POSTFIX d -) + # Create helpers library + add_library(DX12Helpers INTERFACE) + add_library(wis::DX12Helpers ALIAS DX12Helpers) -set_property( - TARGET DX12Agility - APPEND - PROPERTY EXPORT_PROPERTIES DX12SDKVER) + target_link_libraries(DX12Helpers INTERFACE + DirectX-Headers + DirectX-Guids) + target_compile_definitions(DX12Helpers INTERFACE + D3D12MA_USING_DIRECTX_HEADERS=1 + ) +endif() # DirectX 12 Memory Allocator @@ -96,11 +116,12 @@ endif () add_library(DX12Allocator STATIC ${dxma_SOURCE_DIR}/include/D3D12MemAlloc.h) target_sources(DX12Allocator PRIVATE ${dxma_SOURCE_DIR}/src/D3D12MemAlloc.cpp) -target_link_libraries(DX12Allocator PRIVATE DX12Agility) -target_compile_definitions(DX12Allocator PRIVATE D3D12MA_OPTIONS16_SUPPORTED) +target_link_libraries(DX12Allocator PUBLIC DX12Helpers) + target_include_directories( DX12Allocator PUBLIC $ $) + set_target_properties(DX12Allocator PROPERTIES CXX_STANDARD 20 DEBUG_POSTFIX d diff --git a/cmake/functions.cmake b/cmake/functions.cmake index df9fe88e9..2a65958ef 100644 --- a/cmake/functions.cmake +++ b/cmake/functions.cmake @@ -75,87 +75,30 @@ function(wisdom_detect_platform) endif () endfunction() - -# Function for installing DirectX SDK for UWP -function(wis_export_agility_file) - set(options) - set(oneValueArgs PATH) - set(multiValueArgs) - - cmake_parse_arguments(wis_export_agility_file - "${options}" "${oneValueArgs}" "${multiValueArgs}" - ${ARGN}) - - get_property(DX12SDKVER TARGET wis::DX12Agility PROPERTY DX12SDKVER) - - set(EXPORT_AGILITY "_declspec(dllexport) const unsigned D3D12SDKVersion = ${DX12SDKVER}; - _declspec(dllexport) const char* D3D12SDKPath = \".\\\\D3D12\\\\\";" - ) - file(WRITE ${wis_export_agility_file_PATH} "${EXPORT_AGILITY}") -endfunction() - -function(wis_make_exports_dx PROJECT) - wis_export_agility_file(PATH ${CMAKE_CURRENT_BINARY_DIR}/exports.c) - - target_sources(${PROJECT} PRIVATE - ${CMAKE_CURRENT_BINARY_DIR}/exports.c - ) -endfunction() - -function(wis_install_dx_uwp PROJECT) - message("Installing DirectX Agility SDK Dependency") - wis_export_agility_file(PATH "${CMAKE_CURRENT_BINARY_DIR}/exports.c") - - target_sources(${PROJECT} PRIVATE - ${CMAKE_CURRENT_BINARY_DIR}/exports.c - ) - - message("DX12AgilityCore: ${DXAGILITY_DLL}") - set_property(SOURCE ${DXAGILITY_DLL} PROPERTY VS_DEPLOYMENT_CONTENT 1) - set_property(SOURCE ${DXAGILITY_DLL} PROPERTY VS_DEPLOYMENT_LOCATION "D3D12") - target_sources(${PROJECT} PRIVATE ${DXAGILITY_DLL}) - - message("DX12AgilitySDKLayers: ${DXAGILITY_DEBUG_DLL}") - set_property(SOURCE ${DXAGILITY_DEBUG_DLL} PROPERTY VS_DEPLOYMENT_CONTENT 1) - set_property(SOURCE ${DXAGILITY_DEBUG_DLL} PROPERTY VS_DEPLOYMENT_LOCATION "D3D12") - target_sources(${PROJECT} PRIVATE ${DXAGILITY_DEBUG_DLL}) -endfunction() - # Function for installing DirectX SDK -function(wis_install_dx_win32 PROJECT) +function(wis_install_agility_win32 PROJECT DXAGILITY_DLL DXAGILITY_DEBUG_DLL) message("Installing DirectX Agility SDK Dependency") - wis_export_agility_file(PATH "${CMAKE_CURRENT_BINARY_DIR}/exports.c") - - target_sources(${PROJECT} PRIVATE - ${CMAKE_CURRENT_BINARY_DIR}/exports.c - ) - - get_filename_component(DXAGILITY_DLL_NAME ${DXAGILITY_DLL} NAME) - add_custom_command(TARGET ${PROJECT} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${DXAGILITY_DLL} $/D3D12/${DXAGILITY_DLL_NAME} - COMMAND_EXPAND_LISTS - COMMENT "Copying DX12 Agility Core..." - ) - - - get_filename_component(DXAGILITY_DEBUG_DLL_NAME ${DXAGILITY_DEBUG_DLL} NAME) - add_custom_command(TARGET ${PROJECT} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy ${DXAGILITY_DEBUG_DLL} $/D3D12/${DXAGILITY_DEBUG_DLL_NAME} - COMMAND_EXPAND_LISTS - COMMENT "Copying DX12 Agility SDKLayers..." - ) -endfunction() - -# Function for installing Wisdom Dependencies -function(wis_install_deps PROJECT) - if (WIN32 AND NOT WINDOWS_STORE) - wis_install_dx_win32(${PROJECT}) - elseif (WINDOWS_STORE) - wis_install_dx_uwp(${PROJECT}) - endif (WIN32 AND NOT WINDOWS_STORE) + if (EXISTS ${DXAGILITY_DLL}) + message("DX12 Agility Core found: ${DXAGILITY_DLL}") + get_filename_component(DXAGILITY_DLL_NAME ${DXAGILITY_DLL} NAME) + add_custom_command(TARGET ${PROJECT} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${DXAGILITY_DLL} $/D3D12/${DXAGILITY_DLL_NAME} + COMMAND_EXPAND_LISTS + COMMENT "Copying DX12 Agility Core..." + ) + endif() + + if (EXISTS ${DXAGILITY_DEBUG_DLL}) + message("DX12 Agility SDKLayers found: ${DXAGILITY_DEBUG_DLL}") + get_filename_component(DXAGILITY_DEBUG_DLL_NAME ${DXAGILITY_DEBUG_DLL} NAME) + add_custom_command(TARGET ${PROJECT} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${DXAGILITY_DEBUG_DLL} $/D3D12/${DXAGILITY_DEBUG_DLL_NAME} + COMMAND_EXPAND_LISTS + COMMENT "Copying DX12 Agility SDKLayers..." + ) + endif() endfunction() - # Function for compiling shaders # Arguments: # DXC: Path to the DXC executable (default: stored in ${DXC_EXECUTABLE} then in PATH) diff --git a/cmake/install/nuget.cmake b/cmake/install/nuget.cmake index 7727ebbf3..5fdb224a8 100644 --- a/cmake/install/nuget.cmake +++ b/cmake/install/nuget.cmake @@ -2,7 +2,7 @@ set(CPACK_GENERATOR NuGet) # Set up package metadata set(CPACK_PACKAGE_NAME ${PROJECT_NAME}) set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}") -set(CPACK_PACKAGE_VENDOR "Arcom Inc.") +set(CPACK_PACKAGE_VENDOR "Agrael") set(CPACK_NUGET_PACKAGE_AUTHORS "Agrael") set(CPACK_PACKAGE_DESCRIPTION "A Low-level thin multiplatform and extensible Graphics API layer over Vulkan and DX12") set(CPACK_PACKAGE_HOMEPAGE_URL "https://agrael1.github.io/Wisdom/") @@ -13,8 +13,7 @@ set(CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION "MIT") set(CPACK_NUGET_PACKAGE_README "README.md") # pulled from installed files set(CPACK_INSTALL_SCRIPTS "${CMAKE_CURRENT_LIST_DIR}/gen-targets.cmake") -# NuGet dependencies - D3D12 Agility SDK is required, DXC is optional for runtime shader compilation -set(CPACK_NUGET_PACKAGE_DEPENDENCIES "Microsoft.Direct3D.D3D12;Microsoft.Direct3D.DXC") -set("CPACK_NUGET_PACKAGE_DEPENDENCIES_Microsoft.Direct3D.D3D12_VERSION" "${DXA_VERSION}") +# NuGet dependencies - DXC is optional for runtime shader compilation +set(CPACK_NUGET_PACKAGE_DEPENDENCIES "Microsoft.Direct3D.DXC") set("CPACK_NUGET_PACKAGE_DEPENDENCIES_Microsoft.Direct3D.DXC_VERSION" "[1.8,)") include(CPack) diff --git a/cmake/install/wisdom.targets b/cmake/install/wisdom.targets index 8d25ef4a0..945df9a54 100644 --- a/cmake/install/wisdom.targets +++ b/cmake/install/wisdom.targets @@ -25,7 +25,7 @@ $(MSBuildThisFileDirectory)..\..\lib\wisdom-platform$(LP).lib;%(AdditionalDependencies) $(MSBuildThisFileDirectory)..\..\lib\wisdom-platform-shared$(LP).lib;%(AdditionalDependencies) $(MSBuildThisFileDirectory)..\..\lib\vkma$(LP).lib;%(AdditionalDependencies) - $(MSBuildThisFileDirectory)..\..\lib\DX12Allocator$(LP).lib;$(MSBuildThisFileDirectory)..\..\lib\DX12Agility$(LP).lib;dxguid.lib;DXGI.lib;%(AdditionalDependencies) + $(MSBuildThisFileDirectory)..\..\lib\DX12Allocator$(LP).lib;$(MSBuildThisFileDirectory)..\..\lib\DX12Helpers$(LP).lib;dxguid.lib;DXGI.lib;%(AdditionalDependencies) diff --git a/docs/wisdom/getting_started.h b/docs/wisdom/getting_started.h index ccc31266d..f8cf5a607 100644 --- a/docs/wisdom/getting_started.h +++ b/docs/wisdom/getting_started.h @@ -126,6 +126,7 @@ * - `WISDOM_BUILD_TESTS=ON/OFF` build tests * - `WISDOM_BUILD_DOCS=ON/OFF` build Doxygen documentation * - `WISDOM_DXC_PATH=` custom DXC location + * - `WISDOM_USE_AGILITY_SDK=OFF` download and build with Agility SDK instead of Windows SDK, this allows using latest DirectX 12 features on older Windows versions, but requires additional setup and dependencies. Default is `OFF`, which uses Windows SDK that comes with the system and DirectX-Headers. * - `WISDOM_VULKAN_HEADER_PATH=` custom Vulkan-Headers location * * @section nuget NuGet Package diff --git a/examples/compute_particles_c/CMakeLists.txt b/examples/compute_particles_c/CMakeLists.txt index e82ea80fa..f18e92d4c 100644 --- a/examples/compute_particles_c/CMakeLists.txt +++ b/examples/compute_particles_c/CMakeLists.txt @@ -33,6 +33,6 @@ if(WISDOM_BUILD_SHARED) wis_test_compile_shaders) endif() -if(POSTFIX STREQUAL "dx12") - wis_install_deps(${PROJECT_NAME}) +if(POSTFIX STREQUAL "dx12" AND WISDOM_USE_AGILITY_SDK) + wis_install_agility_win32(${PROJECT_NAME} ${DXAGILITY_DLL} ${DXAGILITY_DEBUG_DLL}) endif() diff --git a/examples/hello_triangle/CMakeLists.txt b/examples/hello_triangle/CMakeLists.txt index 04521da8f..1c8462a34 100644 --- a/examples/hello_triangle/CMakeLists.txt +++ b/examples/hello_triangle/CMakeLists.txt @@ -64,7 +64,7 @@ target_compile_definitions(${PROJECT_NAME}-cpp-headers PUBLIC ${ADD_DEFINITIONS}) add_dependencies(${PROJECT_NAME}-cpp-headers copy_sdl wis_test_compile_shaders) -if(POSTFIX STREQUAL "dx12" AND WISDOM_BUILD_STATIC) - wis_install_deps(${PROJECT_NAME}-c) - wis_install_deps(${PROJECT_NAME}-cpp) +if(POSTFIX STREQUAL "dx12" AND WISDOM_BUILD_STATIC AND WISDOM_USE_AGILITY_SDK) + wis_install_agility_win32(${PROJECT_NAME}-c ${DXAGILITY_DLL} ${DXAGILITY_DEBUG_DLL}) + wis_install_agility_win32(${PROJECT_NAME}-cpp ${DXAGILITY_DLL} ${DXAGILITY_DEBUG_DLL}) endif() diff --git a/examples/multisampling/CMakeLists.txt b/examples/multisampling/CMakeLists.txt index 73476f808..c850de455 100644 --- a/examples/multisampling/CMakeLists.txt +++ b/examples/multisampling/CMakeLists.txt @@ -13,6 +13,6 @@ set_target_properties( target_compile_definitions(${PROJECT_NAME}-cpp PUBLIC ${ADD_DEFINITIONS}) add_dependencies(${PROJECT_NAME}-cpp copy_sdl wis_test_compile_shaders) -if(POSTFIX STREQUAL "dx12") - wis_install_deps(${PROJECT_NAME}-cpp) +if(POSTFIX STREQUAL "dx12" AND WISDOM_USE_AGILITY_SDK) + wis_install_agility_win32(${PROJECT_NAME}-cpp ${DXAGILITY_DLL} ${DXAGILITY_DEBUG_DLL}) endif() diff --git a/generator/generator.cpp b/generator/generator.cpp index 172c0fd38..f3cca7168 100644 --- a/generator/generator.cpp +++ b/generator/generator.cpp @@ -1169,7 +1169,6 @@ void Generator::WriteConversions(std::filesystem::path dir) #include "c_api.h" #include -#include #include namespace wis{{ namespace detail {{ diff --git a/src/include/CMakeLists.txt b/src/include/CMakeLists.txt index 208071b4f..2b38082ae 100644 --- a/src/include/CMakeLists.txt +++ b/src/include/CMakeLists.txt @@ -14,8 +14,7 @@ if(WISDOM_DX12) DXGI DXGUID d3d12 - DX12Allocator - DX12Agility) + DX12Allocator) list( APPEND diff --git a/src/include/wisdom/dx12/detail/dx12_detail.hpp b/src/include/wisdom/dx12/detail/dx12_detail.hpp index 53db8267e..8972d0efb 100644 --- a/src/include/wisdom/dx12/detail/dx12_detail.hpp +++ b/src/include/wisdom/dx12/detail/dx12_detail.hpp @@ -9,8 +9,6 @@ #include #include -#include - #include #include diff --git a/src/include/wisdom/dx12/dx12_device.cpp b/src/include/wisdom/dx12/dx12_device.cpp index 3bc2a06b8..d12395ad0 100644 --- a/src/include/wisdom/dx12/dx12_device.cpp +++ b/src/include/wisdom/dx12/dx12_device.cpp @@ -9,7 +9,11 @@ #include #include -#include +#ifdef DX12SDKVER +# include +#else +# include +#endif #include #include diff --git a/src/include/wisdom/dx12/dx12_impl.cpp b/src/include/wisdom/dx12/dx12_impl.cpp index 44edcbc7d..dc1d68c6e 100644 --- a/src/include/wisdom/dx12/dx12_impl.cpp +++ b/src/include/wisdom/dx12/dx12_impl.cpp @@ -6,7 +6,11 @@ #include #include +#ifdef DX12SDKVER #include +#else +#include +#endif //---------------------------------------------------------------------------------------------------------------------- WIS_EXTERN_C WISDOM_API void wisDX12DestroyRootSignature(WisDX12RootSignature* self) diff --git a/src/include/wisdom/dx12/dx12_types.hpp b/src/include/wisdom/dx12/dx12_types.hpp index aa742d984..fef3ff542 100644 --- a/src/include/wisdom/dx12/dx12_types.hpp +++ b/src/include/wisdom/dx12/dx12_types.hpp @@ -5,10 +5,8 @@ #endif // __cplusplus #include - -#include -#include #include +#include namespace wis { //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/include/wisdom/generated/dx12_convert.hpp b/src/include/wisdom/generated/dx12_convert.hpp index 9e277dc50..6c94f62dd 100644 --- a/src/include/wisdom/generated/dx12_convert.hpp +++ b/src/include/wisdom/generated/dx12_convert.hpp @@ -5,7 +5,6 @@ # error "This is a C++ only header" #endif // __cplusplus -#include #include #include #include "c_api.h" diff --git a/src/include/wisdom/global/definitions.h b/src/include/wisdom/global/definitions.h index 36955fdda..a08d1933d 100644 --- a/src/include/wisdom/global/definitions.h +++ b/src/include/wisdom/global/definitions.h @@ -192,4 +192,13 @@ # define WISDOM_USES_VULKAN 1 #endif // API selection +#if defined(WISDOM_DX12) && defined(DX12SDKVER) +// That means we are using D3D12Agility SDK +# define WISDOM_EXPORT_AGILITY_SYMBOLS() \ + _declspec(dllexport) const unsigned D3D12SDKVersion = DX12SDKVER; \ + _declspec(dllexport) const char* D3D12SDKPath = ".\\D3D12\\" +#else // We are using regular D3D12 headers, so we don't need to export these symbols +# define WISDOM_EXPORT_AGILITY_SYMBOLS() while (0) +#endif // WISDOM_DX12 && !D3D12MA_USING_DIRECTX_HEADERS + #endif // !WIS_GLOBAL_DEFINITIONS_H From 2b05c642eecc173fe7aa92c521e0734c9dc06353 Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Tue, 21 Apr 2026 21:58:42 +0200 Subject: [PATCH 03/10] Split NuGet/ZIP packaging; add Agility SDK validation Refactored packaging to produce separate NuGet (without Agility SDK) and ZIP (with Agility SDK) artifacts using distinct build/install roots. Updated CI to validate package contents, ensuring correct inclusion/exclusion of Agility SDK files. Improved CMake install logic for headers, clarified multi-config scripts, and refactored Agility SDK export macros. Enabled unity builds for Linux and made minor CMake target property adjustments. --- .github/workflows/package.yml | 45 ++++++++- .github/workflows/release.yml | 44 ++++++++- cmake/deps/deps_win.cmake | 8 ++ cmake/install/multi-config-nuget.cmake | 7 +- cmake/install/multi-config.cmake | 8 +- docs/wisdom/contributing.h | 69 +++++++++++++ docs/wisdom/main_page.h | 2 + examples/compute_particles_c/entry_main.c | 4 + examples/hello_triangle/entry_main.c | 4 + examples/hello_triangle/entry_main.cpp | 4 + examples/multisampling/entry_main.cpp | 4 + package.ps1 | 112 ++++++++++++++++++---- src/include/CMakeLists.txt | 1 - src/include/wisdom/global/definitions.h | 18 +++- src/platform/CMakeLists.txt | 3 +- 15 files changed, 295 insertions(+), 38 deletions(-) diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index 0f005e884..c90fcb0b9 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -53,7 +53,50 @@ jobs: shell: pwsh run: | $format = '${{ github.event.inputs.format }}' - .\package.ps1 -Format $format -Clean -OutputDir './artifacts' + .\package.ps1 -Format $format -Configuration both -Clean -OutputDir './artifacts' + + - name: Validate package contents + shell: pwsh + run: | + Add-Type -AssemblyName System.IO.Compression.FileSystem + $format = '${{ github.event.inputs.format }}' + + if ($format -in @('nuget', 'all')) { + $nugetPackage = Get-ChildItem -Path artifacts/*.nupkg | Select-Object -First 1 + if (-not $nugetPackage) { + throw "NuGet package was not generated." + } + + $nugetArchive = [System.IO.Compression.ZipFile]::OpenRead($nugetPackage.FullName) + try { + $hasAgility = $nugetArchive.Entries | Where-Object { $_.FullName -match '(?i)D3D12Core\.dll|d3d12SDKLayers\.dll|d3dx12/' } + if ($hasAgility) { + throw "NuGet package must not include Agility SDK files." + } + } + finally { + $nugetArchive.Dispose() + } + } + + if ($format -in @('zip', 'all')) { + $zipPackage = Get-ChildItem -Path artifacts/*.zip | Select-Object -First 1 + if (-not $zipPackage) { + throw "ZIP package was not generated." + } + + $zipArchive = [System.IO.Compression.ZipFile]::OpenRead($zipPackage.FullName) + try { + $hasCore = $zipArchive.Entries | Where-Object { $_.FullName -match '(?i)D3D12Core\.dll' } + $hasLayers = $zipArchive.Entries | Where-Object { $_.FullName -match '(?i)d3d12SDKLayers\.dll' } + if (-not $hasCore -or -not $hasLayers) { + throw "ZIP package must include Agility SDK runtime files (D3D12Core.dll and d3d12SDKLayers.dll)." + } + } + finally { + $zipArchive.Dispose() + } + } - name: Upload NuGet Package uses: actions/upload-artifact@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b8f3bccb9..c31144c78 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -220,7 +220,45 @@ jobs: - name: Build and Package shell: pwsh run: | - .\package.ps1 -Format all -Clean -OutputDir './artifacts' + .\package.ps1 -Format all -Configuration both -Clean -OutputDir './artifacts' + + - name: Validate package contents + shell: pwsh + run: | + Add-Type -AssemblyName System.IO.Compression.FileSystem + + $nugetPackage = Get-ChildItem -Path artifacts/*.nupkg | Select-Object -First 1 + if (-not $nugetPackage) { + throw "NuGet package was not generated." + } + + $nugetArchive = [System.IO.Compression.ZipFile]::OpenRead($nugetPackage.FullName) + try { + $nugetHasAgility = $nugetArchive.Entries | Where-Object { $_.FullName -match '(?i)D3D12Core\.dll|d3d12SDKLayers\.dll|d3dx12/' } + if ($nugetHasAgility) { + throw "NuGet package must not include Agility SDK files." + } + } + finally { + $nugetArchive.Dispose() + } + + $zipPackage = Get-ChildItem -Path artifacts/*.zip | Select-Object -First 1 + if (-not $zipPackage) { + throw "ZIP package was not generated." + } + + $zipArchive = [System.IO.Compression.ZipFile]::OpenRead($zipPackage.FullName) + try { + $zipHasCore = $zipArchive.Entries | Where-Object { $_.FullName -match '(?i)D3D12Core\.dll' } + $zipHasLayers = $zipArchive.Entries | Where-Object { $_.FullName -match '(?i)d3d12SDKLayers\.dll' } + if (-not $zipHasCore -or -not $zipHasLayers) { + throw "ZIP package must include Agility SDK runtime files (D3D12Core.dll and d3d12SDKLayers.dll)." + } + } + finally { + $zipArchive.Dispose() + } - name: Upload NuGet Package uses: actions/upload-artifact@v4 @@ -262,13 +300,13 @@ jobs: uses: lukka/get-cmake@latest - name: Configure CMake (Debug) - run: cmake --preset linux-gcc-debug-lib -DWISDOM_VULKAN_HEADER_PATH=${{ github.workspace }}/vulkan-headers/include + run: cmake --preset linux-gcc-debug-lib -DWISDOM_VULKAN_HEADER_PATH=${{ github.workspace }}/vulkan-headers/include -DCMAKE_UNITY_BUILD=ON - name: Build (Debug) run: cmake --build --preset linux-gcc-debug-lib - name: Configure CMake (Release) - run: cmake --preset linux-gcc-lib -DWISDOM_VULKAN_HEADER_PATH=${{ github.workspace }}/vulkan-headers/include + run: cmake --preset linux-gcc-lib -DWISDOM_VULKAN_HEADER_PATH=${{ github.workspace }}/vulkan-headers/include -DCMAKE_UNITY_BUILD=ON - name: Build (Release) run: cmake --build --preset linux-gcc-lib diff --git a/cmake/deps/deps_win.cmake b/cmake/deps/deps_win.cmake index 9bba023b1..c6d50390b 100644 --- a/cmake/deps/deps_win.cmake +++ b/cmake/deps/deps_win.cmake @@ -95,6 +95,14 @@ else() target_compile_definitions(DX12Helpers INTERFACE D3D12MA_USING_DIRECTX_HEADERS=1 ) + install(DIRECTORY ${dxheaders_SOURCE_DIR}/include/directx DESTINATION include) + install( + TARGETS DirectX-Headers DirectX-Guids DX12Helpers + EXPORT wisdom-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) endif() diff --git a/cmake/install/multi-config-nuget.cmake b/cmake/install/multi-config-nuget.cmake index be8ea9d03..b10708050 100644 --- a/cmake/install/multi-config-nuget.cmake +++ b/cmake/install/multi-config-nuget.cmake @@ -1,14 +1,15 @@ # NuGet-specific multi-config - excludes DXC component # Users should install Microsoft.Direct3D.DXC NuGet package separately +# NuGet package is built without Agility SDK # Include the release config as base (contains package metadata) -include("${CMAKE_CURRENT_LIST_DIR}/../../build/msvc-release/CPackConfig.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/../../build/msvc-release-nuget/CPackConfig.cmake") # Only include the default component, excluding 'dxc' component set(CPACK_COMPONENTS_ALL Unspecified) # Install from both Debug and Release builds (Unspecified component only) set(CPACK_INSTALL_CMAKE_PROJECTS - "${CMAKE_CURRENT_LIST_DIR}/../../build/msvc-debug;wisdom;Unspecified;/" - "${CMAKE_CURRENT_LIST_DIR}/../../build/msvc-release;wisdom;Unspecified;/" + "${CMAKE_CURRENT_LIST_DIR}/../../build/msvc-debug-nuget;wisdom;Unspecified;/" + "${CMAKE_CURRENT_LIST_DIR}/../../build/msvc-release-nuget;wisdom;Unspecified;/" ) diff --git a/cmake/install/multi-config.cmake b/cmake/install/multi-config.cmake index b7c44cbdf..f6b9232ac 100644 --- a/cmake/install/multi-config.cmake +++ b/cmake/install/multi-config.cmake @@ -1,8 +1,8 @@ # Include the release config as base (contains package metadata) -include("${CMAKE_CURRENT_LIST_DIR}/../../build/msvc-release/CPackConfig.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/../../build/msvc-release-zip/CPackConfig.cmake") -# Install from both Debug and Release builds +# Install from both Debug and Release builds (ZIP includes Agility SDK) set(CPACK_INSTALL_CMAKE_PROJECTS - "${CMAKE_CURRENT_LIST_DIR}/../../build/msvc-debug;wisdom;ALL;/" - "${CMAKE_CURRENT_LIST_DIR}/../../build/msvc-release;wisdom;ALL;/" + "${CMAKE_CURRENT_LIST_DIR}/../../build/msvc-debug-zip;wisdom;ALL;/" + "${CMAKE_CURRENT_LIST_DIR}/../../build/msvc-release-zip;wisdom;ALL;/" ) diff --git a/docs/wisdom/contributing.h b/docs/wisdom/contributing.h index cbeb06583..cd40ed84a 100644 --- a/docs/wisdom/contributing.h +++ b/docs/wisdom/contributing.h @@ -259,3 +259,72 @@ * @note Thank you for your interest in contributing to Wisdom! Your contributions help make this library better for * everyone. */ + +/** + * @page agility_page Agility SDK + * This page is dedicated to providing information about using the Agility SDK with Wisdom for DirectX 12 development on + * Windows. The Agility SDK allows developers to access the latest DirectX 12 features on older Windows versions, but it + * requires additional setup and dependencies compared to using the Windows SDK. + * + * @section what_happened_sec What Happened to the Agility SDK? + * + * If you have used Wisdom before, you may have noticed that the Agility SDK is no longer included as a default option + * for DirectX 12 development. This change was made to simplify the build process and reduce the number of dependencies. + * This in turn was done for a few reasons: + * - The Agility SDK breaks the Conan package, because it is not available as a Conan package and it requires manual + * installation and setup. This makes it difficult to maintain and use in a consistent way across different + * environments. + * - The Agility SDK is not required for most users, as the Windows SDK provides access to the latest DirectX 12 + * features on Windows 11 and Windows 10 (with the latest updates). For users who need to support older Windows + * versions, the Agility SDK can still be used by enabling the `WISDOM_USE_AGILITY_SDK` CMake option and following the + * setup instructions below. + * - The Agility SDK break transparency of the library, because it requires additional setup and exports were hidden + * behind a CMake command. This makes it difficult to use the library in a consistent way across different environments + * and platforms. + * + * @section using_agility_sec Using the Agility SDK with Wisdom + * + * If you need to use the Agility SDK for your DirectX 12 development on Windows, you can enable it by following these + * steps: + * + * - Install the Agility SDK from the official Microsoft website: + * https://devblogs.microsoft.com/directx/directx12agility/ + * - *OR* If you are using CMake and sources, define `WISDOM_USE_AGILITY_SDK=ON` before including the library. This will + * enable the use of the Agility SDK in your project and allow you to access the latest DirectX 12 features. + * - *OR* If you use distributed binaries, Agility SDK is included in the package. + * + * On NuGet, the Agility SDK comes under `Microsoft.Direct3D.D3D12` package, so you need to install it in your project + * to use the Agility SDK with Wisdom. + * + * Next, you need to ensure, that you copy the Agility SDK DLLs (`D3D12Core.dll` and `D3DSDKLayers.dll`) to your output + * directory under `/D3D12/` folder. You can do this manually, or you can add a post-build step in your project settings + * to copy the DLLs automatically. NuGet package should do this for you, but if you are using CMake and sources, you + * need to set this up yourself. You can use provided CMake function `wis_install_agility_win32` to copy the DLLs to your + * output directory. + * + * And finally, you need to export the symbols for the Agility SDK in your code. This is required when linking against + * the Agility SDK on Windows, as it uses a different set of symbols than the Windows SDK. You can do this by adding the + * following line to your code: + * + * ```c + * WISDOM_EXPORT_AGILITY_SYMBOLS(); + * ``` + * + * `WISDOM_EXPORT_AGILITY_SYMBOLS` requires defined `DX12SDKVER`. This macro is defined from sources/.zip distribution when + * `WISDOM_USE_AGILITY_SDK` is enabled, but if you are using custom SDK or NuGet you will need another macro. + * + * `WISDOM_EXPORT_AGILITY_CUSTOM(SDK_VER)` is a helper macro that allows you to use custom SDK version. + * Otherwise you can directly export symbols in your executable the way Agility SDK documentation describes: + * https://devblogs.microsoft.com/directx/gettingstarted-dx12agility/ + * + * @section agility_conclusion_sec Conclusion + * Wisdom Library automatically uses the Agility SDK, when it is enabled. + * .zip distribution includes the Agility SDK, so you don't have to worry about it if you are using that. If you are + * using CMake and sources, you can enable it with a single CMake option, but you need to set up the DLL copying + * yourself. On NuGet, you need to install the `Microsoft.Direct3D.D3D12` package and ensure the DLLs are copied to your + * output directory. + * + * It is not easy to set up, but sometimes it is necessary to support older Windows versions, so we provide the option + * to use it. If you don't need to, you can just ignore it and use the Windows SDK that comes with your system, which + * should work fine for most users. + */ diff --git a/docs/wisdom/main_page.h b/docs/wisdom/main_page.h index bb57be33e..81202a4f1 100644 --- a/docs/wisdom/main_page.h +++ b/docs/wisdom/main_page.h @@ -48,6 +48,8 @@ * Some additional pages: * - @ref contributing_page "Contributing" - Contribution guidelines and how to get involved * - @ref why_page "Why Wisdom?" - Explanation of the motivation and goals behind the project + * - @ref agility_page "Agility SDK" - Information about using the Agility SDK for DirectX 12 features on older Windows + * versions * * @section features_sec Key Features * diff --git a/examples/compute_particles_c/entry_main.c b/examples/compute_particles_c/entry_main.c index becbe2eca..e2f7e8cb3 100644 --- a/examples/compute_particles_c/entry_main.c +++ b/examples/compute_particles_c/entry_main.c @@ -4,6 +4,10 @@ #include +// Export the symbols for the Agility SDK. +// This is required when linking against the Agility SDK on Windows. +WISDOM_EXPORT_AGILITY_SYMBOLS(); + #define FRAMES_IN_FLIGHT 2 #define SWAPCHAIN_FRAMES 3 #define PARTICLE_COUNT 256 diff --git a/examples/hello_triangle/entry_main.c b/examples/hello_triangle/entry_main.c index 0f6f88b3d..0bb39ee2b 100644 --- a/examples/hello_triangle/entry_main.c +++ b/examples/hello_triangle/entry_main.c @@ -10,6 +10,10 @@ #include +// Export the symbols for the Agility SDK. +// This is required when linking against the Agility SDK on Windows. +WISDOM_EXPORT_AGILITY_SYMBOLS(); + #define FRAMES_IN_FLIGHT 2 #define SWAPCHAIN_FRAMES 3 diff --git a/examples/hello_triangle/entry_main.cpp b/examples/hello_triangle/entry_main.cpp index 1aeb490a2..1f03d8e7f 100644 --- a/examples/hello_triangle/entry_main.cpp +++ b/examples/hello_triangle/entry_main.cpp @@ -13,6 +13,10 @@ #include +// Export the symbols for the Agility SDK. +// This is required when linking against the Agility SDK on Windows. +WISDOM_EXPORT_AGILITY_SYMBOLS(); + #define FRAMES_IN_FLIGHT 2 #define SWAPCHAIN_FRAMES 3 diff --git a/examples/multisampling/entry_main.cpp b/examples/multisampling/entry_main.cpp index 2c7ea8b3b..59b11b5d9 100644 --- a/examples/multisampling/entry_main.cpp +++ b/examples/multisampling/entry_main.cpp @@ -14,6 +14,10 @@ #include +// Export the symbols for the Agility SDK. +// This is required when linking against the Agility SDK on Windows. +WISDOM_EXPORT_AGILITY_SYMBOLS(); + #define FRAMES_IN_FLIGHT 2 #define SWAPCHAIN_FRAMES 3 diff --git a/package.ps1 b/package.ps1 index c8259ea37..d7d2b02dd 100644 --- a/package.ps1 +++ b/package.ps1 @@ -61,6 +61,18 @@ $generateZip = $Format -in @('zip', 'all') $buildDebug = $Configuration -in @('both', 'debug') $buildRelease = $Configuration -in @('both', 'release') +# Package-specific build roots +$nugetDebugBuildDir = 'build/msvc-debug-nuget' +$nugetReleaseBuildDir = 'build/msvc-release-nuget' +$zipDebugBuildDir = 'build/msvc-debug-zip' +$zipReleaseBuildDir = 'build/msvc-release-zip' + +# Package-specific install roots +$nugetDebugInstallDir = 'install/msvc-debug-nuget' +$nugetReleaseInstallDir = 'install/msvc-release-nuget' +$zipDebugInstallDir = 'install/msvc-debug-zip' +$zipReleaseInstallDir = 'install/msvc-release-zip' + function Initialize-VSEnvironment { Write-Host "Initializing Visual Studio environment..." -ForegroundColor Cyan @@ -102,6 +114,10 @@ function Resolve-NuGetExecutable { } $candidatePaths = @( + 'build/msvc-release-nuget/NuGet/NuGet.exe', + 'build/msvc-debug-nuget/NuGet/NuGet.exe', + 'build/msvc-release-zip/NuGet/NuGet.exe', + 'build/msvc-debug-zip/NuGet/NuGet.exe', 'build/msvc-release/NuGet/NuGet.exe', 'build/msvc-debug/NuGet/NuGet.exe', 'build/NuGet/NuGet.exe' @@ -151,19 +167,40 @@ function Invoke-CMake { function Build-Configuration { param( - [string]$Preset, [string]$BuildDir, - [string]$Config + [string]$Config, + [bool]$UseAgility, + [string]$InstallDir + ) + + $agilityValue = if ($UseAgility) { 'ON' } else { 'OFF' } + + Write-Host " Configuring $Config (WISDOM_USE_AGILITY_SDK=$agilityValue)..." -ForegroundColor Gray + + $configureArgs = @( + '-S', '.', + '-B', $BuildDir, + '-G', 'Ninja', + "-DCMAKE_BUILD_TYPE=$Config", + "-DCMAKE_INSTALL_PREFIX=$InstallDir", + '-DWISDOM_BUILD_EXAMPLES=OFF', + '-DWISDOM_BUILD_TESTS=OFF', + '-DCMAKE_UNITY_BUILD=ON', + "-DWISDOM_USE_AGILITY_SDK=$agilityValue", + '-DCPM_SOURCE_CACHE=build/_deps_cache' ) - Write-Host " Configuring $Config..." -ForegroundColor Gray - Invoke-CMake @('--preset', $Preset) + if ($Config -eq 'Release') { + $configureArgs += '-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON' + } + + Invoke-CMake $configureArgs Write-Host " Building $Config..." -ForegroundColor Gray - Invoke-CMake @('--build', $BuildDir, '--config', $Config) + Invoke-CMake @('--build', $BuildDir) Write-Host " Installing $Config..." -ForegroundColor Gray - Invoke-CMake @('--install', $BuildDir, '--config', $Config) + Invoke-CMake @('--install', $BuildDir) } function New-Package { @@ -172,7 +209,15 @@ function New-Package { [string]$OutputPath ) - $buildDir = "build/msvc-release" + $buildDir = switch ($Generator) { + 'NuGet' { $nugetReleaseBuildDir } + 'ZIP' { $zipReleaseBuildDir } + } + + if (-not (Test-Path $buildDir)) { + throw "$Generator build directory not found at '$buildDir'. Run without -SkipBuild or build required artifacts first." + } + $cpackDir = Join-Path $buildDir "_CPack_Packages" # Clean CPack staging directory to prevent cross-contamination between formats @@ -189,7 +234,7 @@ function New-Package { # Select the appropriate config file based on generator # NuGet: excludes DXC (users get it from Microsoft.Direct3D.DXC package) - # ZIP: includes everything for standalone usage + # ZIP: includes DXC and Agility SDK for standalone usage $configFile = switch ($Generator) { 'NuGet' { '../../cmake/install/multi-config-nuget.cmake' } 'ZIP' { '../../cmake/install/multi-config.cmake' } @@ -229,8 +274,14 @@ function New-Package { $totalSteps = 0 if (-not $SkipBuild) { - if ($buildDebug) { $totalSteps++ } - if ($buildRelease) { $totalSteps++ } + if ($generateNuGet) { + if ($buildDebug) { $totalSteps++ } + if ($buildRelease) { $totalSteps++ } + } + if ($generateZip) { + if ($buildDebug) { $totalSteps++ } + if ($buildRelease) { $totalSteps++ } + } } if ($generateNuGet) { $totalSteps++ } if ($generateZip) { $totalSteps++ } @@ -258,23 +309,46 @@ $OutputDir = Resolve-Path $OutputDir # Clean if requested if ($Clean) { Write-Host "Cleaning build directories..." -ForegroundColor Yellow - @('build/msvc-debug', 'build/msvc-release') | ForEach-Object { + @( + $nugetDebugBuildDir, + $nugetReleaseBuildDir, + $zipDebugBuildDir, + $zipReleaseBuildDir, + 'build/msvc-debug', + 'build/msvc-release' + ) | ForEach-Object { if (Test-Path $_) { Remove-Item -Recurse -Force $_ } } } # Build if (-not $SkipBuild) { - if ($buildDebug) { - $currentStep++ - Write-Host "`n[$currentStep/$totalSteps] Building Debug configuration..." -ForegroundColor Yellow - Build-Configuration -Preset 'win-msvc-debug-lib' -BuildDir 'build/msvc-debug' -Config 'Debug' + if ($generateNuGet) { + if ($buildDebug) { + $currentStep++ + Write-Host "`n[$currentStep/$totalSteps] Building Debug configuration for NuGet (without Agility SDK)..." -ForegroundColor Yellow + Build-Configuration -BuildDir $nugetDebugBuildDir -Config 'Debug' -UseAgility $false -InstallDir $nugetDebugInstallDir + } + + if ($buildRelease) { + $currentStep++ + Write-Host "`n[$currentStep/$totalSteps] Building Release configuration for NuGet (without Agility SDK)..." -ForegroundColor Yellow + Build-Configuration -BuildDir $nugetReleaseBuildDir -Config 'Release' -UseAgility $false -InstallDir $nugetReleaseInstallDir + } } - if ($buildRelease) { - $currentStep++ - Write-Host "`n[$currentStep/$totalSteps] Building Release configuration..." -ForegroundColor Yellow - Build-Configuration -Preset 'win-msvc-lib' -BuildDir 'build/msvc-release' -Config 'Release' + if ($generateZip) { + if ($buildDebug) { + $currentStep++ + Write-Host "`n[$currentStep/$totalSteps] Building Debug configuration for ZIP (with Agility SDK)..." -ForegroundColor Yellow + Build-Configuration -BuildDir $zipDebugBuildDir -Config 'Debug' -UseAgility $true -InstallDir $zipDebugInstallDir + } + + if ($buildRelease) { + $currentStep++ + Write-Host "`n[$currentStep/$totalSteps] Building Release configuration for ZIP (with Agility SDK)..." -ForegroundColor Yellow + Build-Configuration -BuildDir $zipReleaseBuildDir -Config 'Release' -UseAgility $true -InstallDir $zipReleaseInstallDir + } } } diff --git a/src/include/CMakeLists.txt b/src/include/CMakeLists.txt index 2b38082ae..856038dd8 100644 --- a/src/include/CMakeLists.txt +++ b/src/include/CMakeLists.txt @@ -116,7 +116,6 @@ if(WISDOM_BUILD_SHARED) wisdom-shared PROPERTIES CXX_STANDARD 20 POSITION_INDEPENDENT_CODE ON - # UNITY_BUILD ON DEBUG_POSTFIX d) include(GenerateExportHeader) diff --git a/src/include/wisdom/global/definitions.h b/src/include/wisdom/global/definitions.h index a08d1933d..b3bb1c8b5 100644 --- a/src/include/wisdom/global/definitions.h +++ b/src/include/wisdom/global/definitions.h @@ -192,13 +192,21 @@ # define WISDOM_USES_VULKAN 1 #endif // API selection -#if defined(WISDOM_DX12) && defined(DX12SDKVER) -// That means we are using D3D12Agility SDK -# define WISDOM_EXPORT_AGILITY_SYMBOLS() \ - _declspec(dllexport) const unsigned D3D12SDKVersion = DX12SDKVER; \ +#if defined(WISDOM_DX12) +# define WISDOM_EXPORT_AGILITY_CUSTOM(SDK_VER) \ + _declspec(dllexport) const unsigned D3D12SDKVersion = SDK_VER; \ _declspec(dllexport) const char* D3D12SDKPath = ".\\D3D12\\" + +# if defined(DX12SDKVER) +// That means we are using D3D12Agility SDK +# define WISDOM_EXPORT_AGILITY_SYMBOLS() WISDOM_EXPORT_AGILITY_CUSTOM(DX12SDKVER) +# else +# define WISDOM_EXPORT_AGILITY_SYMBOLS() +# endif + #else // We are using regular D3D12 headers, so we don't need to export these symbols -# define WISDOM_EXPORT_AGILITY_SYMBOLS() while (0) +# define WISDOM_EXPORT_AGILITY_CUSTOM(SDK_VER) +# define WISDOM_EXPORT_AGILITY_SYMBOLS() #endif // WISDOM_DX12 && !D3D12MA_USING_DIRECTX_HEADERS #endif // !WIS_GLOBAL_DEFINITIONS_H diff --git a/src/platform/CMakeLists.txt b/src/platform/CMakeLists.txt index bee29494d..82170c5ea 100644 --- a/src/platform/CMakeLists.txt +++ b/src/platform/CMakeLists.txt @@ -50,7 +50,7 @@ if(WISDOM_BUILD_STATIC) $) set_target_properties( - wisdom-platform PROPERTIES CXX_STANDARD 20 # UNITY_BUILD ON + wisdom-platform PROPERTIES CXX_STANDARD 20 DEBUG_POSTFIX d) install( @@ -80,7 +80,6 @@ if(WISDOM_BUILD_SHARED) set_target_properties( wisdom-platform-shared PROPERTIES CXX_STANDARD 20 - # UNITY_BUILD ON POSITION_INDEPENDENT_CODE ON DEBUG_POSTFIX d) From 39737e06054baab5073cc1163ad56557e4c3d41a Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Wed, 22 Apr 2026 10:47:07 +0200 Subject: [PATCH 04/10] Refactor Agility SDK integration and CMake helpers - Move NuGet/CMake Agility helpers to functions.cmake (Windows only) - Add wis_load_agility_sdk(), wis_patch_agility_executable(), and wis_install_agility_win32() for automated Agility SDK setup and symbol export - Update CMakeLists.txt to use new helpers and add WISDOM_DOWNLOAD_DXC option - Improve Conan packaging: version from file, header_only option, better component handling - Update documentation for new Agility SDK usage paths and helpers - Remove manual WISDOM_EXPORT_AGILITY_SYMBOLS() macro from entry_main.cpp - General cleanup and modernization of Agility SDK handling for all build systems --- CMakeLists.txt | 2 + cmake/deps/deps_win.cmake | 83 +----- cmake/deps/nuget.cmake | 79 ------ cmake/functions.cmake | 272 ++++++++++++++++++-- conanfile.py | 111 +++++--- docs/wisdom/contributing.h | 97 ++++--- examples/compute_particles_c/CMakeLists.txt | 2 +- examples/hello_triangle/CMakeLists.txt | 4 +- examples/multisampling/CMakeLists.txt | 3 +- examples/multisampling/entry_main.cpp | 4 - 10 files changed, 400 insertions(+), 257 deletions(-) delete mode 100644 cmake/deps/nuget.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index d84bfd139..df019b0c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,7 @@ option(WISDOM_BUILD_SHARED "Build the dynamic lib." ON) option(WISDOM_BUILD_PLATFORM "Build unified platform extension library." ON) option(WISDOM_BUILD_DOCS "Build the documentation." OFF) option(WISDOM_USE_AGILITY_SDK "Download and use DirectX 12 Agility SDK." OFF) +option(WISDOM_DOWNLOAD_DXC "Download and use DXC for shader compilation. OFF means use one provided with Vulkan SDK." OFF) # DXC deployment options @@ -55,6 +56,7 @@ message( WISDOM_BUILD_STATIC: ${WISDOM_BUILD_STATIC} WISDOM_BUILD_SHARED: ${WISDOM_BUILD_SHARED} WISDOM_BUILD_PLATFORM: ${WISDOM_BUILD_PLATFORM} + WISDOM_USE_AGILITY_SDK: ${WISDOM_USE_AGILITY_SDK} WISDOM_VULKAN_HEADER_PATH: ${WISDOM_VULKAN_HEADER_PATH} diff --git a/cmake/deps/deps_win.cmake b/cmake/deps/deps_win.cmake index c6d50390b..d34af036a 100644 --- a/cmake/deps/deps_win.cmake +++ b/cmake/deps/deps_win.cmake @@ -1,78 +1,19 @@ if (WISDOM_USE_AGILITY_SDK) - include(${CMAKE_CURRENT_LIST_DIR}/nuget.cmake) + wis_load_agility_sdk() - _ww_find_nuget() - - # DirectX 12 Agility SDK - message("Setting up DirectX 12 Agility...") - _ww_load_nuget_dependency(${NUGET_EXE} "Microsoft.Direct3D.D3D12" DXA - ${CMAKE_CURRENT_BINARY_DIR}) - - string(REGEX MATCH "([0-9]+)\\.([0-9]+)\\.([0-9]+)$" VERSION_MATCH ${DXA_DIR}) - - message("Agility version: ${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}") - set(DXA_VERSION - ${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3} - CACHE INTERNAL "") - set(VERSION_MINOR - ${CMAKE_MATCH_2} - CACHE INTERNAL "") - - set(DXA_HEADERS ${DXA_DIR}/build/native/include) - set(DXA_SRC ${DXA_DIR}/build/native/src) - set(DXA_BIN ${DXA_DIR}/build/native/bin/x64) - set(DXAGILITY_DLL - ${DXA_BIN}/D3D12Core.dll - CACHE INTERNAL "") - set(DXAGILITY_DEBUG_DLL - ${DXA_BIN}/d3d12SDKLayers.dll - CACHE INTERNAL "") - - add_library(DX12AgilityCore MODULE IMPORTED GLOBAL) - set_property(TARGET DX12AgilityCore PROPERTY IMPORTED_LOCATION - ${DXAGILITY_DLL}) - - add_library(DX12AgilitySDKLayers MODULE IMPORTED GLOBAL) - set_property(TARGET DX12AgilitySDKLayers PROPERTY IMPORTED_LOCATION - ${DXAGILITY_DEBUG_DLL}) - - # Header interface library - add_library(DX12Helpers STATIC) + # Create helpers library + add_library(DX12Helpers INTERFACE) add_library(wis::DX12Helpers ALIAS DX12Helpers) - - target_include_directories( - DX12Helpers SYSTEM BEFORE - PUBLIC $ $ - PRIVATE $) - target_sources(DX12Helpers - PRIVATE ${DXA_SRC}/d3dx12/d3dx12_property_format_table.cpp) - target_compile_definitions(DX12Helpers PUBLIC - DX12SDKVER=${VERSION_MINOR} - ) - install( - TARGETS DX12Helpers - EXPORT wisdom-targets - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) - + + target_link_libraries(DX12Helpers INTERFACE + DX12Agility) install( - IMPORTED_RUNTIME_ARTIFACTS - DX12AgilityCore - DX12AgilitySDKLayers - RUNTIME - DESTINATION - ${CMAKE_INSTALL_BINDIR} - LIBRARY - DESTINATION - ${CMAKE_INSTALL_BINDIR}) - - install(DIRECTORY ${DXA_HEADERS}/ DESTINATION include/d3dx12) - - set_target_properties(DX12Helpers PROPERTIES - DEBUG_POSTFIX d - ) + TARGETS DX12Helpers + EXPORT wisdom-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) else() message("DirectX 12 Agility SDK not enabled. Using Headers instead.") diff --git a/cmake/deps/nuget.cmake b/cmake/deps/nuget.cmake deleted file mode 100644 index 5592ea301..000000000 --- a/cmake/deps/nuget.cmake +++ /dev/null @@ -1,79 +0,0 @@ -# Load NuGet.exe for Windows builds -function(_ww_load_nuget) - # Latest NuGet is at https://dist.nuget.org/win-x86-commandline/latest/nuget.exe - # Secure download with hash verification - set(FILE_URL "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe") - set(FILE_PATH "${CMAKE_CURRENT_BINARY_DIR}/NuGet/NuGet.exe") - file(DOWNLOAD - ${FILE_URL} - ${FILE_PATH} - STATUS download_status - LOG download_log - TIMEOUT 300 - TLS_VERIFY ON - TLS_VERSION 1.2 - ) - - # Check download status - list(GET download_status 0 status_code) - if (NOT status_code EQUAL 0) - list(GET download_status 1 status_string) - message(FATAL_ERROR "Download failed: ${status_string}") - else () - message(STATUS "File downloaded successfully to ${FILE_PATH}") - endif () -endfunction(_ww_load_nuget) - -# Find NuGet executable -function(_ww_find_nuget) - if (NOT WISDOM_WINDOWS) - return() - endif () - - find_program( - NUGET_EXE - NAMES nuget) - - if (NOT NUGET_EXE) - message("NUGET.EXE not found. Downloading...") - find_program( - NUGET_EXE - NAMES nuget - PATHS ${CMAKE_CURRENT_BINARY_DIR}/NuGet) - - if (NOT NUGET_EXE) - _ww_load_nuget() - set(NUGET_EXE "${CMAKE_CURRENT_BINARY_DIR}/NuGet/NuGet.exe" CACHE INTERNAL "Path to NuGet.exe") - endif () - else () - message("NUGET.EXE found: ${NUGET_EXE}") - endif () -endfunction(_ww_find_nuget) - -# Load a NuGet dependency -function(_ww_load_nuget_dependency NUGET PLUGIN_NAME ALIAS OUT_DIR) - if (${ALIAS}_DIR) - message("${ALIAS}_DIR already set, skipping download.") - return() - endif () - - execute_process(COMMAND ${NUGET} install "${PLUGIN_NAME}" -OutputDirectory ${OUT_DIR}) - file(GLOB PLUGIN_DIRS ${OUT_DIR}/${PLUGIN_NAME}.*) - list(LENGTH PLUGIN_DIRS PLUGIN_DIRS_L) - if (${PLUGIN_DIRS_L} GREATER 1) - #Sort directories by version in descending order, so the first dir is top version - list(SORT PLUGIN_DIRS COMPARE NATURAL ORDER DESCENDING) - list(GET PLUGIN_DIRS 0 PLUGIN_DIRX) - - #Remove older version - MATH(EXPR PLUGIN_DIRS_L "${PLUGIN_DIRS_L}-1") - foreach (I RANGE 1 ${PLUGIN_DIRS_L}) - list(GET PLUGIN_DIRS ${I} OLD) - file(REMOVE_RECURSE ${OLD}) - endforeach () - else () - list(GET PLUGIN_DIRS 0 PLUGIN_DIRX) - endif () - - set(${ALIAS}_DIR ${PLUGIN_DIRX} CACHE STRING "${PLUGIN_NAME} PATH" FORCE) -endfunction(_ww_load_nuget_dependency) diff --git a/cmake/functions.cmake b/cmake/functions.cmake index 2a65958ef..216f9acbb 100644 --- a/cmake/functions.cmake +++ b/cmake/functions.cmake @@ -1,3 +1,86 @@ +if (WIN32) + # Load NuGet.exe for Windows builds + function(_ww_load_nuget) + # Latest NuGet is at https://dist.nuget.org/win-x86-commandline/latest/nuget.exe + # Secure download with hash verification + set(FILE_URL "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe") + set(FILE_PATH "${CMAKE_CURRENT_BINARY_DIR}/NuGet/NuGet.exe") + file(DOWNLOAD + ${FILE_URL} + ${FILE_PATH} + STATUS download_status + LOG download_log + TIMEOUT 300 + TLS_VERIFY ON + TLS_VERSION 1.2 + ) + + # Check download status + list(GET download_status 0 status_code) + if (NOT status_code EQUAL 0) + list(GET download_status 1 status_string) + message(FATAL_ERROR "Download failed: ${status_string}") + else () + message(STATUS "File downloaded successfully to ${FILE_PATH}") + endif () + endfunction(_ww_load_nuget) + + # Find NuGet executable + function(_ww_find_nuget) + if (NOT WISDOM_WINDOWS) + return() + endif () + + find_program( + NUGET_EXE + NAMES nuget) + + if (NOT NUGET_EXE) + message("NUGET.EXE not found. Downloading...") + find_program( + NUGET_EXE + NAMES nuget + PATHS ${CMAKE_CURRENT_BINARY_DIR}/NuGet) + + if (NOT NUGET_EXE) + _ww_load_nuget() + set(NUGET_EXE "${CMAKE_CURRENT_BINARY_DIR}/NuGet/NuGet.exe" CACHE INTERNAL "Path to NuGet.exe") + endif () + else () + message("NUGET.EXE found: ${NUGET_EXE}") + endif () + endfunction(_ww_find_nuget) + + # Load a NuGet dependency + function(_ww_load_nuget_dependency NUGET PLUGIN_NAME ALIAS OUT_DIR) + if (${ALIAS}_DIR) + message("${ALIAS}_DIR already set, skipping download.") + return() + endif () + + execute_process(COMMAND ${NUGET} install "${PLUGIN_NAME}" -OutputDirectory ${OUT_DIR}) + file(GLOB PLUGIN_DIRS ${OUT_DIR}/${PLUGIN_NAME}.*) + list(LENGTH PLUGIN_DIRS PLUGIN_DIRS_L) + if (${PLUGIN_DIRS_L} GREATER 1) + #Sort directories by version in descending order, so the first dir is top version + list(SORT PLUGIN_DIRS COMPARE NATURAL ORDER DESCENDING) + list(GET PLUGIN_DIRS 0 PLUGIN_DIRX) + + #Remove older version + MATH(EXPR PLUGIN_DIRS_L "${PLUGIN_DIRS_L}-1") + foreach (I RANGE 1 ${PLUGIN_DIRS_L}) + list(GET PLUGIN_DIRS ${I} OLD) + file(REMOVE_RECURSE ${OLD}) + endforeach () + else () + list(GET PLUGIN_DIRS 0 PLUGIN_DIRX) + endif () + + set(${ALIAS}_DIR ${PLUGIN_DIRX} CACHE STRING "${PLUGIN_NAME} PATH" FORCE) + endfunction(_ww_load_nuget_dependency) +endif() + + # Function to detect platform and set relevant variables function(wisdom_detect_platform) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_LIST_DIR}/ecm") @@ -75,30 +158,6 @@ function(wisdom_detect_platform) endif () endfunction() -# Function for installing DirectX SDK -function(wis_install_agility_win32 PROJECT DXAGILITY_DLL DXAGILITY_DEBUG_DLL) - message("Installing DirectX Agility SDK Dependency") - if (EXISTS ${DXAGILITY_DLL}) - message("DX12 Agility Core found: ${DXAGILITY_DLL}") - get_filename_component(DXAGILITY_DLL_NAME ${DXAGILITY_DLL} NAME) - add_custom_command(TARGET ${PROJECT} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${DXAGILITY_DLL} $/D3D12/${DXAGILITY_DLL_NAME} - COMMAND_EXPAND_LISTS - COMMENT "Copying DX12 Agility Core..." - ) - endif() - - if (EXISTS ${DXAGILITY_DEBUG_DLL}) - message("DX12 Agility SDKLayers found: ${DXAGILITY_DEBUG_DLL}") - get_filename_component(DXAGILITY_DEBUG_DLL_NAME ${DXAGILITY_DEBUG_DLL} NAME) - add_custom_command(TARGET ${PROJECT} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy ${DXAGILITY_DEBUG_DLL} $/D3D12/${DXAGILITY_DEBUG_DLL_NAME} - COMMAND_EXPAND_LISTS - COMMENT "Copying DX12 Agility SDKLayers..." - ) - endif() -endfunction() - # Function for compiling shaders # Arguments: # DXC: Path to the DXC executable (default: stored in ${DXC_EXECUTABLE} then in PATH) @@ -223,3 +282,168 @@ function(wis_compile_shader) WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} VERBATIM) endfunction() + +# Function to load DirectX 12 Agility SDK using NuGet +# Creates 3 targets: +# - DX12AgilityCore: The core Agility DLL (D3D12Core.dll) +# - DX12AgilitySDKLayers: The SDK Layers DLL (d3d12SDKLayers.dll) +# - DX12Agility: A helper static library that includes the Agility headers, for easy consumption by users. This is the main target that users should link against. +function(wis_load_agility_sdk) + if (NOT WISDOM_WINDOWS) + return() + endif () + + _ww_find_nuget() + + # DirectX 12 Agility SDK + message("Setting up DirectX 12 Agility...") + _ww_load_nuget_dependency(${NUGET_EXE} "Microsoft.Direct3D.D3D12" DXA + ${CMAKE_CURRENT_BINARY_DIR}) + + string(REGEX MATCH "([0-9]+)\\.([0-9]+)\\.([0-9]+)$" VERSION_MATCH ${DXA_DIR}) + + message("Agility version: ${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}") + set(DXA_VERSION + ${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3} + CACHE INTERNAL "") + set(VERSION_MINOR + ${CMAKE_MATCH_2} + CACHE INTERNAL "") + + set(DXA_HEADERS ${DXA_DIR}/build/native/include) + set(DXA_SRC ${DXA_DIR}/build/native/src) + set(DXA_BIN ${DXA_DIR}/build/native/bin/x64) + set(DXAGILITY_DLL + ${DXA_BIN}/D3D12Core.dll + CACHE INTERNAL "") + set(DXAGILITY_DEBUG_DLL + ${DXA_BIN}/d3d12SDKLayers.dll + CACHE INTERNAL "") + + add_library(DX12AgilityCore MODULE IMPORTED GLOBAL) + set_property(TARGET DX12AgilityCore PROPERTY IMPORTED_LOCATION + ${DXAGILITY_DLL}) + + add_library(DX12AgilitySDKLayers MODULE IMPORTED GLOBAL) + set_property(TARGET DX12AgilitySDKLayers PROPERTY IMPORTED_LOCATION + ${DXAGILITY_DEBUG_DLL}) + + # Header interface library + add_library(DX12Agility STATIC) + add_library(wis::DX12Agility ALIAS DX12Agility) + + target_include_directories( + DX12Agility SYSTEM BEFORE + PUBLIC $ $ + PRIVATE $) + target_sources(DX12Agility + PRIVATE ${DXA_SRC}/d3dx12/d3dx12_property_format_table.cpp) + target_compile_definitions(DX12Agility PUBLIC + DX12SDKVER=${VERSION_MINOR} + ) + install( + TARGETS DX12Agility + EXPORT wisdom-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + + install( + IMPORTED_RUNTIME_ARTIFACTS + DX12AgilityCore + DX12AgilitySDKLayers + RUNTIME + DESTINATION + ${CMAKE_INSTALL_BINDIR} + LIBRARY + DESTINATION + ${CMAKE_INSTALL_BINDIR}) + + install(DIRECTORY ${DXA_HEADERS}/ DESTINATION include/d3dx12) + + set_target_properties(DX12Agility PROPERTIES + DX12SDKVER ${VERSION_MINOR} + DEBUG_POSTFIX d + ) + + set_property( + TARGET DX12Agility + APPEND + PROPERTY EXPORT_PROPERTIES DX12SDKVER) + +endfunction() + +# Function for patching executable to export DX12 Agility symbols on Windows +function(wis_patch_agility_executable TARGET) + if (NOT WISDOM_WINDOWS) + return() + endif() + + get_target_property(target_type ${TARGET_NAME} TYPE) + + if(target_type NOT STREQUAL "EXECUTABLE") + message(FATAL_ERROR "Target ${TARGET_NAME} is not an executable. DX12 Agility patching can only be applied to executables.") + endif() + + # Check if the DX12Agility target is available + if (NOT TARGET DX12Agility) + message(FATAL_ERROR "DX12Agility target not found. Make sure to call wis_load_agility_sdk() before patching the executable.") + endif() + + # Generate a source file that exports the required symbols for the DX12 Agility SDK. This is necessary to ensure that the application can load the Agility DLLs at runtime. + get_property(DX12SDKVER TARGET DX12Agility PROPERTY DX12SDKVER) + set(EXPORT_AGILITY "_declspec(dllexport) const unsigned D3D12SDKVersion = ${DX12SDKVER}; + _declspec(dllexport) const char* D3D12SDKPath = \".\\\\D3D12\\\\\";" + ) + file(WRITE ${wis_export_agility_file_PATH} "${EXPORT_AGILITY}") + + # Add the generated file to the target sources to ensure it's compiled and linked into the executable + target_sources(${TARGET} PRIVATE ${wis_export_agility_file_PATH}) +endfunction() + +# Function for installing DirectX SDK +# Arguments: +# TARGET: Target to copy the DLLs to +# PATCH_EXE: Whether to patch the executable to export the DX12 Agility symbols (default: OFF) +function(wis_install_agility_win32) + cmake_parse_arguments(wis_install_agility_win32 "PATCH_EXE" "TARGET" + "" ${ARGN}) + + # Check if project is an executable + if (NOT TARGET ${wis_install_agility_win32_TARGET}) + message(FATAL_ERROR "Target ${PROJECT} not found") + endif() + + get_target_property(target_type ${TARGET_NAME} TYPE) + + if(target_type NOT STREQUAL "EXECUTABLE") + message(FATAL_ERROR "Target ${TARGET_NAME} is not an executable. DX12 Agility patching can only be applied to executables.") + endif() + + message("Installing DirectX Agility SDK Dependency") + if (EXISTS ${DXAGILITY_DLL}) + message("DX12 Agility Core found: ${DXAGILITY_DLL}") + get_filename_component(DXAGILITY_DLL_NAME ${DXAGILITY_DLL} NAME) + add_custom_command(TARGET ${PROJECT} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${DXAGILITY_DLL} $/D3D12/${DXAGILITY_DLL_NAME} + COMMAND_EXPAND_LISTS + COMMENT "Copying DX12 Agility Core..." + ) + endif() + + if (EXISTS ${DXAGILITY_DEBUG_DLL}) + message("DX12 Agility SDKLayers found: ${DXAGILITY_DEBUG_DLL}") + get_filename_component(DXAGILITY_DEBUG_DLL_NAME ${DXAGILITY_DEBUG_DLL} NAME) + add_custom_command(TARGET ${PROJECT} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${DXAGILITY_DEBUG_DLL} $/D3D12/${DXAGILITY_DEBUG_DLL_NAME} + COMMAND_EXPAND_LISTS + COMMENT "Copying DX12 Agility SDKLayers..." + ) + endif() + + if (wis_install_agility_win32_PATCH_EXE) + wis_patch_agility_executable(${wis_install_agility_win32_TARGET}) + endif() +endfunction() + diff --git a/conanfile.py b/conanfile.py index 53ad7320b..67949729b 100644 --- a/conanfile.py +++ b/conanfile.py @@ -1,14 +1,14 @@ +import os from conan import ConanFile from conan.tools.cmake import CMake from conan.tools.cmake import cmake_layout from conan.tools.cmake import CMakeToolchain from conan.tools.files import collect_libs -from conan.tools.files import copy +from conan.tools.files import copy, load class WisdomConan(ConanFile): name = "wisdom" - version = "0.7.0" package_type = "library" license = "MIT" @@ -21,13 +21,27 @@ class WisdomConan(ConanFile): "shared": [True, False], "fPIC": [True, False], "build_platform": [True, False], + "header_only": [True, False], } default_options = { "shared": False, "fPIC": True, "build_platform": True, + "header_only": False, } + def set_version(self): + version_file_path = os.path.join(self.recipe_folder, "version/VERSION") + + try: + # Read the file and strip any whitespace/newlines + self.version = load(self, version_file_path).strip() + except Exception as e: + # It is highly recommended to provide a fallback or clear error + # so the recipe doesn't cryptically crash if the file is missing + self.output.warning(f"Could not read version file: {e}") + self.version = "0.0.0" + def export_sources(self): copy( self, @@ -54,9 +68,12 @@ def config_options(self): self.options.rm_safe("fPIC") def configure(self): - if self.options.shared: + if self.options.shared or self.options.header_only: self.options.rm_safe("fPIC") + if self.options.header_only: + self.options.rm_safe("shared") + def layout(self): cmake_layout(self) @@ -66,13 +83,17 @@ def generate(self): "For Conan Center, those dependencies should be provided as Conan requirements or vendored sources." ) + is_header_only = self.options.get_safe("header_only") + tc = CMakeToolchain(self) tc.variables["WISDOM_BUILD_EXAMPLES"] = False tc.variables["WISDOM_BUILD_TESTS"] = False tc.variables["WISDOM_BUILD_DOCS"] = False - tc.variables["WISDOM_BUILD_STATIC"] = not self.options.shared - tc.variables["WISDOM_BUILD_SHARED"] = self.options.shared + tc.variables["WISDOM_BUILD_STATIC"] = not self.options.get_safe("shared") and not is_header_only + tc.variables["WISDOM_BUILD_SHARED"] = self.options.get_safe("shared") and not is_header_only tc.variables["WISDOM_BUILD_PLATFORM"] = self.options.build_platform + tc.variables["WISDOM_USE_AGILITY_SDK"] = False + tc.variables["CMAKE_UNITY_BUILD"] = True tc.generate() def build(self): @@ -85,33 +106,55 @@ def package(self): cmake.install() def package_info(self): + # The overarching file namespace (find_package(wisdom)) self.cpp_info.set_property("cmake_file_name", "wisdom") - self.cpp_info.builddirs.append("lib/cmake/wisdom") - - all_libs = collect_libs(self) - - core_target = "wis::wisdom-shared" if self.options.shared else "wis::wisdom" - core_lib_hints = {"wisdom-shared", "wisdom"} - core_libs = [ - lib for lib in all_libs if any(h in lib for h in core_lib_hints) - ] - platform_libs = [lib for lib in all_libs if "platform" in lib] - - self.cpp_info.components["headers"].set_property( - "cmake_target_name", "wis::wisdom-headers") - - self.cpp_info.components["core"].set_property("cmake_target_name", - core_target) - self.cpp_info.components["core"].requires = ["headers"] - self.cpp_info.components["core"].libs = core_libs - - self.cpp_info.components["platform_headers"].set_property( - "cmake_target_name", "wis::wisdom-platform-headers") - self.cpp_info.components["platform_headers"].requires = ["headers"] - - self.cpp_info.components["platform"].set_property( - "cmake_target_name", "wis::wisdom-platform") - self.cpp_info.components["platform"].requires = [ - "core", "platform_headers" - ] - self.cpp_info.components["platform"].libs = platform_libs + + build_modules = ["lib/cmake/wisdom/functions.cmake"] + self.cpp_info.set_property("cmake_build_modules", build_modules) + + # --------------------------------------------------------- + # 1. HEADER-ONLY TARGETS (Always Available) + # --------------------------------------------------------- + + # Core Headers (wis::wisdom-headers) + self.cpp_info.components["headers"].set_property("cmake_target_name", "wis::wisdom-headers") + self.cpp_info.components["headers"].bindirs = [] + self.cpp_info.components["headers"].libdirs = [] + + # Platform Headers (wis::wisdom-platform-headers) + if self.options.build_platform: + self.cpp_info.components["platform_headers"].set_property("cmake_target_name", "wis::wisdom-platform-headers") + self.cpp_info.components["platform_headers"].requires = ["headers"] + self.cpp_info.components["platform_headers"].bindirs = [] + self.cpp_info.components["platform_headers"].libdirs = [] + + # If header_only is True, we stop here. No compiled libs are added. + if self.options.get_safe("header_only"): + return + + # --------------------------------------------------------- + # 2. COMPILED TARGETS (Static OR Shared) + # --------------------------------------------------------- + suffix = "d" if self.settings.build_type == "Debug" else "" + if self.options.get_safe("shared"): + # Core Shared + self.cpp_info.components["core"].set_property("cmake_target_name", "wis::wisdom-shared") + self.cpp_info.components["core"].requires = ["headers"] + self.cpp_info.components["core"].libs = [f"wisdom-shared{suffix}"] + + # Platform Shared + if self.options.build_platform: + self.cpp_info.components["platform"].set_property("cmake_target_name", "wis::wisdom-platform-shared") + self.cpp_info.components["platform"].requires = ["core", "platform_headers"] + self.cpp_info.components["platform"].libs = [f"wisdom-platform-shared{suffix}"] + else: + # Core Static + self.cpp_info.components["core"].set_property("cmake_target_name", "wis::wisdom") + self.cpp_info.components["core"].requires = ["headers"] + self.cpp_info.components["core"].libs = [f"wisdom{suffix}"] + + # Platform Static + if self.options.build_platform: + self.cpp_info.components["platform"].set_property("cmake_target_name", "wis::wisdom-platform") + self.cpp_info.components["platform"].requires = ["core", "platform_headers"] + self.cpp_info.components["platform"].libs = [f"wisdom-platform{suffix}"] \ No newline at end of file diff --git a/docs/wisdom/contributing.h b/docs/wisdom/contributing.h index cd40ed84a..5212ec66b 100644 --- a/docs/wisdom/contributing.h +++ b/docs/wisdom/contributing.h @@ -274,7 +274,7 @@ * - The Agility SDK breaks the Conan package, because it is not available as a Conan package and it requires manual * installation and setup. This makes it difficult to maintain and use in a consistent way across different * environments. - * - The Agility SDK is not required for most users, as the Windows SDK provides access to the latest DirectX 12 + * - The Agility SDK is not required for the build, as the Windows SDK provides access to the latest DirectX 12 * features on Windows 11 and Windows 10 (with the latest updates). For users who need to support older Windows * versions, the Agility SDK can still be used by enabling the `WISDOM_USE_AGILITY_SDK` CMake option and following the * setup instructions below. @@ -284,47 +284,62 @@ * * @section using_agility_sec Using the Agility SDK with Wisdom * - * If you need to use the Agility SDK for your DirectX 12 development on Windows, you can enable it by following these - * steps: - * - * - Install the Agility SDK from the official Microsoft website: - * https://devblogs.microsoft.com/directx/directx12agility/ - * - *OR* If you are using CMake and sources, define `WISDOM_USE_AGILITY_SDK=ON` before including the library. This will - * enable the use of the Agility SDK in your project and allow you to access the latest DirectX 12 features. - * - *OR* If you use distributed binaries, Agility SDK is included in the package. - * - * On NuGet, the Agility SDK comes under `Microsoft.Direct3D.D3D12` package, so you need to install it in your project - * to use the Agility SDK with Wisdom. - * - * Next, you need to ensure, that you copy the Agility SDK DLLs (`D3D12Core.dll` and `D3DSDKLayers.dll`) to your output - * directory under `/D3D12/` folder. You can do this manually, or you can add a post-build step in your project settings - * to copy the DLLs automatically. NuGet package should do this for you, but if you are using CMake and sources, you - * need to set this up yourself. You can use provided CMake function `wis_install_agility_win32` to copy the DLLs to your - * output directory. - * - * And finally, you need to export the symbols for the Agility SDK in your code. This is required when linking against - * the Agility SDK on Windows, as it uses a different set of symbols than the Windows SDK. You can do this by adding the - * following line to your code: - * - * ```c + * Because the Agility SDK can be tricky to set up (requiring specific DLL placement and symbol exports), Wisdom + * provides different usage paths depending on how you consume the library. + * + * @subsection path_nuget NuGet + * If you are consuming Wisdom via NuGet, install the `Microsoft.Direct3D.D3D12` package to use the Agility SDK. Wisdom + * does not bundle it for NuGet to avoid issues with UWP builds (Windows App Certification Kit). The NuGet package + * should handle copying the required DLLs to the output directory. + * + * @subsection path_cmake CMake + * If you are using CMake, Wisdom provides several helpers depending on your integration method: + * + * - **Sources (FetchContent / CPM)**: Set the CMake option `WISDOM_USE_AGILITY_SDK=ON` before integrating the library. + * Wisdom will handle the SDK download and link it automatically. + * - **.ZIP Distribution**: The Agility SDK is included automatically. + * - **Conan Package (Future)**: You will need to explicitly call the CMake function `wis_load_agility_sdk()` provided + * by Wisdom, or handle it yourself. + * + * **Installing the DLLs & Exporting Symbols in CMake**: + * To run your application, the Agility SDK DLLs (`D3D12Core.dll` and `D3DSDKLayers.dll`) must be copied to your output + * directory. Wisdom provides a CMake helper for this: + * ```cmake + * wis_install_agility_win32(YOUR_TARGET_NAME PATCH_EXE) + * ``` + * If you pass the `PATCH_EXE` argument, Wisdom will automatically call `wis_patch_agility_executable()` to export the + * required Agility SDK symbols directly in the compiled binary. **If you do this, you do not need to use any C++ + * macros.** + * + * @subsection path_manual Non-CMake / Manual Integration + * If you are using Conan with a build system other than CMake, or integrating manually: + * 1. Ensure the Agility SDK is downloaded. + * 2. Copy the DLLs to your output directory. + * 3. Export the symbols using the C++ macros described below. + * + * @section exporting_symbols_sec Exporting Symbols (C++ Macros) + * + * If you did **not** use the CMake `PATCH_EXE` method to automatically export symbols, you must export them in your + * source code (usually in `main.cpp`). + * + * - **When Wisdom loads Agility via CMake** (`WISDOM_USE_AGILITY_SDK=ON` or `.zip`): Use the standard macro. + * ```cpp * WISDOM_EXPORT_AGILITY_SYMBOLS(); * ``` - * - * `WISDOM_EXPORT_AGILITY_SYMBOLS` requires defined `DX12SDKVER`. This macro is defined from sources/.zip distribution when - * `WISDOM_USE_AGILITY_SDK` is enabled, but if you are using custom SDK or NuGet you will need another macro. - * - * `WISDOM_EXPORT_AGILITY_CUSTOM(SDK_VER)` is a helper macro that allows you to use custom SDK version. - * Otherwise you can directly export symbols in your executable the way Agility SDK documentation describes: - * https://devblogs.microsoft.com/directx/gettingstarted-dx12agility/ - * + * + * - **When integrating manually** (or using NuGet / Conan without CMake): Use the custom macro with your specific SDK + * version. + * ```cpp + * WISDOM_EXPORT_AGILITY_CUSTOM(619); // Replace 619 with your Agility SDK version + * ``` + * + * Alternatively, you can directly export the symbols using the `extern "C" __declspec(dllexport)` approach as + * documented by Microsoft. + * * @section agility_conclusion_sec Conclusion - * Wisdom Library automatically uses the Agility SDK, when it is enabled. - * .zip distribution includes the Agility SDK, so you don't have to worry about it if you are using that. If you are - * using CMake and sources, you can enable it with a single CMake option, but you need to set up the DLL copying - * yourself. On NuGet, you need to install the `Microsoft.Direct3D.D3D12` package and ensure the DLLs are copied to your - * output directory. - * - * It is not easy to set up, but sometimes it is necessary to support older Windows versions, so we provide the option - * to use it. If you don't need to, you can just ignore it and use the Windows SDK that comes with your system, which - * should work fine for most users. + * + * Providing these helpers drastically simplifies the setup compared to the manual Agility SDK installation process. + * While the multiple paths may seem complex at a glance, formatting them by package manager/method ensures that whether + * you use FetchContent, Conan, NuGet, or manual integration, there is a clear and accessible route to access modern + * DirectX 12 features. */ diff --git a/examples/compute_particles_c/CMakeLists.txt b/examples/compute_particles_c/CMakeLists.txt index f18e92d4c..892c30313 100644 --- a/examples/compute_particles_c/CMakeLists.txt +++ b/examples/compute_particles_c/CMakeLists.txt @@ -34,5 +34,5 @@ if(WISDOM_BUILD_SHARED) endif() if(POSTFIX STREQUAL "dx12" AND WISDOM_USE_AGILITY_SDK) - wis_install_agility_win32(${PROJECT_NAME} ${DXAGILITY_DLL} ${DXAGILITY_DEBUG_DLL}) + wis_install_agility_win32(TARGET ${PROJECT_NAME}) endif() diff --git a/examples/hello_triangle/CMakeLists.txt b/examples/hello_triangle/CMakeLists.txt index 1c8462a34..83b1dc304 100644 --- a/examples/hello_triangle/CMakeLists.txt +++ b/examples/hello_triangle/CMakeLists.txt @@ -65,6 +65,6 @@ target_compile_definitions(${PROJECT_NAME}-cpp-headers add_dependencies(${PROJECT_NAME}-cpp-headers copy_sdl wis_test_compile_shaders) if(POSTFIX STREQUAL "dx12" AND WISDOM_BUILD_STATIC AND WISDOM_USE_AGILITY_SDK) - wis_install_agility_win32(${PROJECT_NAME}-c ${DXAGILITY_DLL} ${DXAGILITY_DEBUG_DLL}) - wis_install_agility_win32(${PROJECT_NAME}-cpp ${DXAGILITY_DLL} ${DXAGILITY_DEBUG_DLL}) + wis_install_agility_win32(TARGET ${PROJECT_NAME}-cpp) + wis_install_agility_win32(TARGET ${PROJECT_NAME}-c) endif() diff --git a/examples/multisampling/CMakeLists.txt b/examples/multisampling/CMakeLists.txt index c850de455..6ad82bcb0 100644 --- a/examples/multisampling/CMakeLists.txt +++ b/examples/multisampling/CMakeLists.txt @@ -14,5 +14,6 @@ target_compile_definitions(${PROJECT_NAME}-cpp PUBLIC ${ADD_DEFINITIONS}) add_dependencies(${PROJECT_NAME}-cpp copy_sdl wis_test_compile_shaders) if(POSTFIX STREQUAL "dx12" AND WISDOM_USE_AGILITY_SDK) - wis_install_agility_win32(${PROJECT_NAME}-cpp ${DXAGILITY_DLL} ${DXAGILITY_DEBUG_DLL}) + wis_install_agility_win32(TARGET ${PROJECT_NAME}-cpp + PATCH_EXE ON) endif() diff --git a/examples/multisampling/entry_main.cpp b/examples/multisampling/entry_main.cpp index 59b11b5d9..2c7ea8b3b 100644 --- a/examples/multisampling/entry_main.cpp +++ b/examples/multisampling/entry_main.cpp @@ -14,10 +14,6 @@ #include -// Export the symbols for the Agility SDK. -// This is required when linking against the Agility SDK on Windows. -WISDOM_EXPORT_AGILITY_SYMBOLS(); - #define FRAMES_IN_FLIGHT 2 #define SWAPCHAIN_FRAMES 3 From 9d4c11fd9966caf65eb5c61d5a1e2bdb14a2b7d1 Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Wed, 22 Apr 2026 17:55:29 +0200 Subject: [PATCH 05/10] Overhaul packaging: CPack, NuGet, ZIP, DXC, integration tests Major refactor of packaging and deployment: - Switch to CPack for both NuGet and ZIP generation, with generator-specific logic and improved metadata. - Remove legacy nuget.cmake; add scripts for NuGet layout and DLL placement. - Refactor DXC handling: new CMake functions for DXC download/discovery, only included in ZIP; NuGet depends on Microsoft.Direct3D.DXC. - Update CI to build, package, and integration-test both formats. - Add PowerShell scripts and sample projects for automated ZIP/NuGet integration testing. - Update wisdom.targets and add nuget.config for correct MSBuild/NuGet integration. - Introduce wis::in_place for in-place construction, update C++ API. - Modernize packaging scripts and update .gitignore for new artifacts and tests. --- .github/workflows/ci.yml | 2 +- .gitignore | 1 + CMakeLists.txt | 30 ++-- cmake/deps.cmake | 3 - cmake/deps/deps_win.cmake | 1 + cmake/deps/dxc.cmake | 120 --------------- cmake/functions.cmake | 138 +++++++++++++++++- cmake/install/cpack-options.cmake | 8 + cmake/install/nuget-prepare.cmake | 28 ++++ cmake/install/nuget.cmake | 19 --- cmake/install/wisdom.targets | 51 +++---- conanfile.py | 1 + examples/CMakeLists.txt | 1 + examples/multisampling/CMakeLists.txt | 3 +- generator/handle.cpp | 2 +- package.ps1 => scripts/package.ps1 | 70 ++++----- scripts/test-cmake.ps1 | 64 ++++++++ scripts/test-nuget.ps1 | 63 ++++++++ src/include/wisdom/global/internal.hpp | 9 +- .../wisdom_platform/generated/cpp_api.hpp | 12 +- tests/integration/cmake/CMakeLists.txt | 16 ++ tests/integration/cmake/entry_main.cpp | 10 ++ tests/integration/nuget/entry_main.cpp | 10 ++ tests/integration/nuget/nuget.config | 7 + tests/integration/nuget/test.vcxproj | 48 ++++++ 25 files changed, 482 insertions(+), 235 deletions(-) delete mode 100644 cmake/deps/dxc.cmake create mode 100644 cmake/install/cpack-options.cmake create mode 100644 cmake/install/nuget-prepare.cmake delete mode 100644 cmake/install/nuget.cmake rename package.ps1 => scripts/package.ps1 (85%) create mode 100644 scripts/test-cmake.ps1 create mode 100644 scripts/test-nuget.ps1 create mode 100644 tests/integration/cmake/CMakeLists.txt create mode 100644 tests/integration/cmake/entry_main.cpp create mode 100644 tests/integration/nuget/entry_main.cpp create mode 100644 tests/integration/nuget/nuget.config create mode 100644 tests/integration/nuget/test.vcxproj diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1ece5ad56..b377a4136 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,7 +34,7 @@ jobs: - name: Configure CMake run: cmake --preset win-msvc-release - + - name: Build run: cmake --build --preset win-msvc-release diff --git a/.gitignore b/.gitignore index 123b20c4c..ad66106db 100644 --- a/.gitignore +++ b/.gitignore @@ -376,3 +376,4 @@ FodyWeavers.xsd # Package artifacts /artifacts/ +/tests/integration/cmake/extracted/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index df019b0c5..83a2877c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,14 +25,10 @@ option(WISDOM_BUILD_STATIC "Build the static lib." ON) option(WISDOM_BUILD_SHARED "Build the dynamic lib." ON) option(WISDOM_BUILD_PLATFORM "Build unified platform extension library." ON) option(WISDOM_BUILD_DOCS "Build the documentation." OFF) -option(WISDOM_USE_AGILITY_SDK "Download and use DirectX 12 Agility SDK." OFF) -option(WISDOM_DOWNLOAD_DXC "Download and use DXC for shader compilation. OFF means use one provided with Vulkan SDK." OFF) +option(WISDOM_USE_AGILITY_SDK "Download and use DirectX 12 Agility SDK." OFF) # TODO: ON # DXC deployment options -set(WISDOM_DXC_PATH - "" - CACHE PATH "Path to custom DXC installation (optional)") set(WISDOM_VULKAN_HEADER_PATH "" CACHE PATH "Path to custom Vulkan Headers (optional)") @@ -58,12 +54,7 @@ message( WISDOM_BUILD_PLATFORM: ${WISDOM_BUILD_PLATFORM} WISDOM_USE_AGILITY_SDK: ${WISDOM_USE_AGILITY_SDK} - WISDOM_VULKAN_HEADER_PATH: ${WISDOM_VULKAN_HEADER_PATH} - - DXC Configuration: - Custom Path: ${WISDOM_DXC_PATH} - Executable: ${DXC_EXECUTABLE} - ") + WISDOM_VULKAN_HEADER_PATH: ${WISDOM_VULKAN_HEADER_PATH}") if(WISDOM_BUILD_EXAMPLES AND WISDOM_BUILD_TESTS) add_subdirectory(generator) @@ -97,4 +88,19 @@ configure_package_config_file( install(FILES ${CMAKE_CURRENT_BINARY_DIR}/wisdom-config-version.cmake ${CMAKE_CURRENT_BINARY_DIR}/wisdom-config.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/wisdom) -include(cmake/install/nuget.cmake) + +# Set up package metadata +set(CPACK_PACKAGE_NAME ${PROJECT_NAME}) +set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}") +set(CPACK_PACKAGE_VENDOR "Agrael") +set(CPACK_NUGET_PACKAGE_AUTHORS "Agrael") +set(CPACK_PACKAGE_DESCRIPTION "A Low-level thin multiplatform and extensible Graphics API layer over Vulkan and DX12") +set(CPACK_PACKAGE_HOMEPAGE_URL "https://agrael1.github.io/Wisdom/") +set(CPACK_NUGET_PACKAGE_REPOSITORY_URL "https://github.com/Agrael1/Wisdom.git") +set(CPACK_NUGET_PACKAGE_ICON "favicon.png") # pulled from installed files +set(CPACK_NUGET_PACKAGE_REPOSITORY_TYPE git) +set(CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION "MIT") +set(CPACK_NUGET_PACKAGE_README "README.md") # pulled from installed files +set(CPACK_PROJECT_CONFIG_FILE "${CMAKE_CURRENT_LIST_DIR}/cmake/install/cpack-options.cmake") + +include(CPack) \ No newline at end of file diff --git a/cmake/deps.cmake b/cmake/deps.cmake index 917174cb9..74914f7fd 100644 --- a/cmake/deps.cmake +++ b/cmake/deps.cmake @@ -22,9 +22,6 @@ if (WISDOM_WINDOWS) include(${CMAKE_CURRENT_LIST_DIR}/deps/deps_win.cmake) endif () -# DXCompiler for HLSL compilation -include(${CMAKE_CURRENT_LIST_DIR}/deps/dxc.cmake) - # Vulkan dependencies if (WISDOM_VULKAN) include(${CMAKE_CURRENT_LIST_DIR}/deps/deps_vulkan.cmake) diff --git a/cmake/deps/deps_win.cmake b/cmake/deps/deps_win.cmake index d34af036a..d7ee32ab1 100644 --- a/cmake/deps/deps_win.cmake +++ b/cmake/deps/deps_win.cmake @@ -37,6 +37,7 @@ else() D3D12MA_USING_DIRECTX_HEADERS=1 ) install(DIRECTORY ${dxheaders_SOURCE_DIR}/include/directx DESTINATION include) + install(DIRECTORY ${dxheaders_SOURCE_DIR}/include/dxguids DESTINATION include) install( TARGETS DirectX-Headers DirectX-Guids DX12Helpers EXPORT wisdom-targets diff --git a/cmake/deps/dxc.cmake b/cmake/deps/dxc.cmake deleted file mode 100644 index 1eadd22b9..000000000 --- a/cmake/deps/dxc.cmake +++ /dev/null @@ -1,120 +0,0 @@ -# DXC Deployment Options -# Priority: 1. Custom path -> 2. Vulkan SDK -> 3. Auto-download - -# Option 1: Custom DXC path (highest priority) -# Users can specify WISDOM_DXC_PATH to use their own DXC installation -# Example: cmake -DWISDOM_DXC_PATH="C:/custom/dxc" .. -if (WISDOM_DXC_PATH) - message(STATUS "Using custom DXC path: ${WISDOM_DXC_PATH}") - - if (WIN32) - set(DXC_EXECUTABLE "${WISDOM_DXC_PATH}/bin/dxc.exe" CACHE INTERNAL "") - set(DXC_DLLS - "${WISDOM_DXC_PATH}/bin/dxcompiler.dll" - "${WISDOM_DXC_PATH}/bin/dxil.dll") - else () - set(DXC_EXECUTABLE "${WISDOM_DXC_PATH}/bin/dxc" CACHE INTERNAL "") - set(DXC_DLLS - "${WISDOM_DXC_PATH}/lib/libdxcompiler.so" - "${WISDOM_DXC_PATH}/lib/libdxil.so") - endif () - - # Verify that the executable exists - if (NOT EXISTS ${DXC_EXECUTABLE}) - message(WARNING "Custom DXC executable not found at: ${DXC_EXECUTABLE}") - message(WARNING "Please verify WISDOM_DXC_PATH is correct") - else () - message(STATUS "Found custom DXC executable: ${DXC_EXECUTABLE}") - endif () - - # Option 2: Try to use Vulkan SDK's DXC (if WISDOM_VULKAN is enabled and no custom path) -elseif (WISDOM_VULKAN AND Vulkan_dxc_EXECUTABLE) - message(STATUS "Using DXC from Vulkan SDK") - - # Use Vulkan SDK's DXC - find_program(DXCOMPILER dxc HINTS ${Vulkan_dxc_EXECUTABLE} ENV VULKAN_SDK PATH_SUFFIXES bin) - - if (DXCOMPILER) - message(STATUS "Found Vulkan SDK DXC: ${DXCOMPILER}") - set(DXC_EXECUTABLE ${DXCOMPILER} CACHE INTERNAL "") - - # Try to find DLLs alongside the executable for deployment - get_filename_component(DXC_BIN_DIR ${DXCOMPILER} DIRECTORY) - - if (WIN32) - set(DXC_DLLS - "${DXC_BIN_DIR}/dxcompiler.dll" - "${DXC_BIN_DIR}/dxil.dll") - else () - # On Linux, libraries might be in ../lib relative to bin - get_filename_component(DXC_SDK_DIR ${DXC_BIN_DIR} DIRECTORY) - set(DXC_DLLS - "${DXC_SDK_DIR}/lib/libdxcompiler.so" - "${DXC_SDK_DIR}/lib/libdxil.so") - endif () - else () - message(STATUS "Vulkan SDK DXC not found, falling back to download") - set(WISDOM_DOWNLOAD_DXC ON) - endif () - - # Option 3: Auto-download latest DXC (fallback) -else () - message(STATUS "Auto-downloading DXC...") - set(WISDOM_DOWNLOAD_DXC ON) -endif () - -# Download DXC if needed -if (WISDOM_DOWNLOAD_DXC) - if (NOT dxc_SOURCE_DIR) - if (WISDOM_WINDOWS) - set(DXC_FILE - https://github.com/microsoft/DirectXShaderCompiler/releases/download/v1.9.2602/dxc_2026_02_20.zip - ) - else () - set(DXC_FILE - https://github.com/microsoft/DirectXShaderCompiler/releases/download/v1.9.2602/linux_dxc_2026_02_20.x86_64.tar.gz - ) - endif () - - # Download DXC using CPM - CPMAddPackage( - NAME dxc - URL ${DXC_FILE} - ) - set(dxc_SOURCE_DIR ${dxc_SOURCE_DIR} CACHE INTERNAL "") - else () - message(STATUS "DXC already downloaded, skipping.") - endif () - - if (WIN32) - set(DXC_EXECUTABLE - ${dxc_SOURCE_DIR}/bin/x64/dxc.exe - CACHE INTERNAL "") - set(DXC_DLLS - ${dxc_SOURCE_DIR}/bin/x64/dxcompiler.dll - ${dxc_SOURCE_DIR}/bin/x64/dxil.dll) - else () - set(DXC_EXECUTABLE - ${dxc_SOURCE_DIR}/bin/dxc - CACHE INTERNAL "") - set(DXC_DLLS - ${dxc_SOURCE_DIR}/lib/libdxcompiler.so - ${dxc_SOURCE_DIR}/lib/libdxil.so) - endif () -endif () - -# Install DXC for deployment -if (WIN32) - install(PROGRAMS ${DXC_EXECUTABLE} DESTINATION bin COMPONENT dxc) - install(FILES ${DXC_DLLS} DESTINATION bin COMPONENT dxc) -else () - install(PROGRAMS ${DXC_EXECUTABLE} DESTINATION bin COMPONENT dxc) - install(FILES ${DXC_DLLS} DESTINATION lib COMPONENT dxc) -endif () - -# Verify DLLs exist (warning only) -foreach (dll ${DXC_DLLS}) - if (NOT EXISTS ${dll}) - message(WARNING "DXC library not found: ${dll}") - endif () -endforeach () diff --git a/cmake/functions.cmake b/cmake/functions.cmake index 216f9acbb..34f77e078 100644 --- a/cmake/functions.cmake +++ b/cmake/functions.cmake @@ -80,6 +80,70 @@ if (WIN32) endfunction(_ww_load_nuget_dependency) endif() +# Function to download the latest DXC release from GitHub API +function(_ww_load_latest_dxc) + if (dxc_SOURCE_DIR) + message(STATUS "DXC already downloaded, skipping.") + return() + endif () + + set(DXC_API_FILE "${CMAKE_CURRENT_BINARY_DIR}/dxc_latest_api.json") + file(DOWNLOAD + "https://api.github.com/repos/microsoft/DirectXShaderCompiler/releases/latest" + "${DXC_API_FILE}" + STATUS api_status + ) + + list(GET api_status 0 api_err) + if(api_err) + message(WARNING "Wisdom: Failed to query DXC latest release from GitHub API: ${api_status}") + endif() + + file(READ "${DXC_API_FILE}" DXC_JSON) + + # Take the first URL that ends with .zip (Windows release) from the JSON response + if(DXC_JSON AND DXC_JSON MATCHES "\"browser_download_url\":[ \t\r\n]*\"([^\"]+\\.zip)\"") + set(DXC_WINDOWS_LINK "${CMAKE_MATCH_1}") + else() + message(WARNING "Wisdom: Could not parse DXC zip URL from GitHub API response.") + set(DXC_WINDOWS_LINK "https://github.com/microsoft/DirectXShaderCompiler/releases/download/v1.9.2602/dxc_2026_02_20.zip") + endif() + + # Take the first URL that ends with .tar.gz (Linux release) from the JSON response + if(DXC_JSON AND DXC_JSON MATCHES "\"browser_download_url\":[ \t\r\n]*\"([^\"]+\\.tar\\.gz)\"") + set(DXC_LINUX_LINK "${CMAKE_MATCH_1}") + else() + message(WARNING "Wisdom: Could not parse DXC tar.gz URL from GitHub API response.") + set(DXC_LINUX_LINK "https://github.com/microsoft/DirectXShaderCompiler/releases/download/v1.9.2602/linux_dxc_2026_02_20.x86_64.tar.gz") + endif() + + if (WISDOM_WINDOWS) + set(DXC_LINK ${DXC_WINDOWS_LINK}) + else () + set(DXC_LINK ${DXC_LINUX_LINK}) + endif () + + + # Download DXC using CPM + include(FetchContent) + FetchContent_Declare( + dxc + URL "${DXC_LINK}" + ) + FetchContent_MakeAvailable(dxc) + set(dxc_SOURCE_DIR ${dxc_SOURCE_DIR} CACHE INTERNAL "") + + if (WIN32) + set(DXC_EXECUTABLE + ${dxc_SOURCE_DIR}/bin/x64/dxc.exe + CACHE INTERNAL "") + else () + set(DXC_EXECUTABLE + ${dxc_SOURCE_DIR}/bin/dxc + CACHE INTERNAL "") + endif () +endfunction() + # Function to detect platform and set relevant variables function(wisdom_detect_platform) @@ -158,6 +222,69 @@ function(wisdom_detect_platform) endif () endfunction() + + +# Function to load DXC +# Arguments: +# DOWNLOAD_LATEST: Download the latest DXC from GitHub +# DXC_PATH: Custom path to DXC installation (should contain bin/dxc.exe or bin/dxc) +function(wis_load_dxc) + set(options DOWNLOAD_LATEST) + set(oneValueArgs DXC_PATH) + set(multiValueArgs) + cmake_parse_arguments(wis_load_dxc "${options}" "${oneValueArgs}" + "${multiValueArgs}" ${ARGN}) + + # If DXC is already configured, skip loading + if (DXC_EXECUTABLE) + return() + endif() + + # Error if none of the above are available + + # Option 1: DOWNLOAD_LATEST (highest priority) + if (wis_load_dxc_DOWNLOAD_LATEST) + message(STATUS "DOWNLOAD_LATEST option enabled, downloading latest DXC from GitHub") + _ww_load_latest_dxc() + return() + endif() + + # Option 2: Custom DXC path (DXC_PATH) + if (WISDOM_DXC_PATH) + # Verify that the executable exists + if (NOT EXISTS ${DXC_EXECUTABLE}) + message(WARNING "Custom DXC executable not found at: ${DXC_EXECUTABLE}") + message(FATAL_ERROR "Please verify WISDOM_DXC_PATH is correct") + else () + message(STATUS "Found custom DXC executable: ${DXC_EXECUTABLE}") + endif () + + message(STATUS "Using custom DXC path: ${WISDOM_DXC_PATH}") + if (WIN32) + set(DXC_EXECUTABLE "${WISDOM_DXC_PATH}/bin/dxc.exe" CACHE INTERNAL "") + else () + set(DXC_EXECUTABLE "${WISDOM_DXC_PATH}/bin/dxc" CACHE INTERNAL "") + endif () + return() + endif() + + # Option 3: Try to use Vulkan SDK's DXC (if WISDOM_VULKAN is enabled and no custom path) + if (WISDOM_VULKAN AND Vulkan_dxc_EXECUTABLE) + # Use Vulkan SDK's DXC + find_program(DXCOMPILER dxc HINTS ${Vulkan_dxc_EXECUTABLE} ENV VULKAN_SDK PATH_SUFFIXES bin) + + if (DXCOMPILER) + message(STATUS "Found Vulkan SDK DXC: ${DXCOMPILER}") + set(DXC_EXECUTABLE ${DXCOMPILER} CACHE INTERNAL "") + else () + message(FATAL_ERROR "Vulkan SDK DXC not found in Vulkan SDK") + endif () + endif() + + # Error if DXC_EXECUTABLE is still not set + message(FATAL_ERROR "DXC executable not found. Please configure DXC using wis_load_dxc() with either DOWNLOAD_LATEST or DXC_PATH options, or ensure that the Vulkan SDK is installed and contains DXC.") +endfunction() + # Function for compiling shaders # Arguments: # DXC: Path to the DXC executable (default: stored in ${DXC_EXECUTABLE} then in PATH) @@ -176,12 +303,13 @@ function(wis_compile_shader) cmake_parse_arguments(wis_compile_shader "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - if (NOT wis_compile_shader_DXC) - if (NOT DXC_EXECUTABLE) - find_program(wis_compile_shader_DXC dxc) + if (NOT wis_compile_shader_DXC OR NOT EXISTS ${wis_compile_shader_DXC}) + if (DXC_EXECUTABLE) + set (wis_compile_shader_DXC ${DXC_EXECUTABLE}) else () - set(wis_compile_shader_DXC ${DXC_EXECUTABLE}) - endif () + message(FATAL_ERROR "wis_compile_shader: DXC not found. " + "Please configure DXC using wis_load_dxc(), or provide a valid DXC path via DXC argument.") + endif() endif () if (NOT wis_compile_shader_TARGET) diff --git a/cmake/install/cpack-options.cmake b/cmake/install/cpack-options.cmake new file mode 100644 index 000000000..56c78d626 --- /dev/null +++ b/cmake/install/cpack-options.cmake @@ -0,0 +1,8 @@ +if(CPACK_GENERATOR MATCHES "NuGet") + message(STATUS "Wisdom CPack: NuGet generator detected. Injecting pre-build script.") + set(CPACK_PRE_BUILD_SCRIPTS "${CMAKE_CURRENT_LIST_DIR}/nuget-prepare.cmake") + set(CPACK_INSTALL_SCRIPTS "${CMAKE_CURRENT_LIST_DIR}/gen-targets.cmake") +elseif(CPACK_GENERATOR MATCHES "ZIP") + message(STATUS "Wisdom CPack: ZIP generator detected. Proceeding with standard layout.") + # No pre-build script needed! The CMake folders stay intact. +endif() \ No newline at end of file diff --git a/cmake/install/nuget-prepare.cmake b/cmake/install/nuget-prepare.cmake new file mode 100644 index 000000000..47de9f26f --- /dev/null +++ b/cmake/install/nuget-prepare.cmake @@ -0,0 +1,28 @@ +# CPack sets this variable to the root of the staging directory right before packaging. +set(STAGING_DIR "${CPACK_TEMPORARY_INSTALL_DIRECTORY}") +set(NUGET_NATIVE_LIB_DIR "${STAGING_DIR}/lib/native/x64") +file(MAKE_DIRECTORY "${NUGET_NATIVE_LIB_DIR}") + +message(STATUS "Wisdom CPack: Reorganizing staging directory at ${STAGING_DIR}") + +# 1. Strip out the CMake configs +if(EXISTS "${STAGING_DIR}/lib/cmake") + file(REMOVE_RECURSE "${STAGING_DIR}/lib/cmake") +endif() + +# 2. Ensure /lib exists +file(MAKE_DIRECTORY "${STAGING_DIR}/lib") + +# 3. Move the DLLs from /bin to /lib +file(GLOB _wisdom_native_dlls "${STAGING_DIR}/bin/*.dll") +foreach(_dll IN LISTS _wisdom_native_dlls) + get_filename_component(_dll_name "${_dll}" NAME) + file(RENAME "${_dll}" "${NUGET_NATIVE_LIB_DIR}/${_dll_name}") +endforeach() + +# 3. (Optional but recommended) Move your static .libs / import .libs there too! +file(GLOB _wisdom_static_libs "${STAGING_DIR}/lib/*.lib") +foreach(_lib IN LISTS _wisdom_static_libs) + get_filename_component(_lib_name "${_lib}" NAME) + file(RENAME "${_lib}" "${NUGET_NATIVE_LIB_DIR}/${_lib_name}") +endforeach() \ No newline at end of file diff --git a/cmake/install/nuget.cmake b/cmake/install/nuget.cmake deleted file mode 100644 index 5fdb224a8..000000000 --- a/cmake/install/nuget.cmake +++ /dev/null @@ -1,19 +0,0 @@ -set(CPACK_GENERATOR NuGet) -# Set up package metadata -set(CPACK_PACKAGE_NAME ${PROJECT_NAME}) -set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}") -set(CPACK_PACKAGE_VENDOR "Agrael") -set(CPACK_NUGET_PACKAGE_AUTHORS "Agrael") -set(CPACK_PACKAGE_DESCRIPTION "A Low-level thin multiplatform and extensible Graphics API layer over Vulkan and DX12") -set(CPACK_PACKAGE_HOMEPAGE_URL "https://agrael1.github.io/Wisdom/") -set(CPACK_NUGET_PACKAGE_REPOSITORY_URL "https://github.com/Agrael1/Wisdom.git") -set(CPACK_NUGET_PACKAGE_ICON "favicon.png") # pulled from installed files -set(CPACK_NUGET_PACKAGE_REPOSITORY_TYPE git) -set(CPACK_NUGET_PACKAGE_LICENSE_EXPRESSION "MIT") -set(CPACK_NUGET_PACKAGE_README "README.md") # pulled from installed files -set(CPACK_INSTALL_SCRIPTS "${CMAKE_CURRENT_LIST_DIR}/gen-targets.cmake") - -# NuGet dependencies - DXC is optional for runtime shader compilation -set(CPACK_NUGET_PACKAGE_DEPENDENCIES "Microsoft.Direct3D.DXC") -set("CPACK_NUGET_PACKAGE_DEPENDENCIES_Microsoft.Direct3D.DXC_VERSION" "[1.8,)") -include(CPack) diff --git a/cmake/install/wisdom.targets b/cmake/install/wisdom.targets index 945df9a54..af87e23fd 100644 --- a/cmake/install/wisdom.targets +++ b/cmake/install/wisdom.targets @@ -5,12 +5,13 @@ - $(MSBuildThisFileDirectory)..\..\include\;$(MSBuildThisFileDirectory)..\..\include\dxma;$(MSBuildThisFileDirectory)..\..\include\d3dx12;%(AdditionalIncludeDirectories) + $(MSBuildThisFileDirectory)..\..\include\;$(MSBuildThisFileDirectory)..\..\include\dxma;%(AdditionalIncludeDirectories) $(MSBuildThisFileDirectory)..\..\include\vkma;%(AdditionalIncludeDirectories) $(WisdomVulkanSDKPath);%(AdditionalIncludeDirectories) - WISDOM_VULKAN=1;%(PreprocessorDefinitions) - WISDOM_DX12=1;WISDOM_WINDOWS=1;%(PreprocessorDefinitions) + + WISDOM_VULKAN=1;VK_USE_PLATFORM_WIN32_KHR=1;VMA_EXTERNAL_MEMORY_WIN32=1;%(PreprocessorDefinitions) + WISDOM_DX12=1;WISDOM_WINDOWS=1;D3D12MA_USING_DIRECTX_HEADERS=1;NOMINMAX=1;%(PreprocessorDefinitions) WISDOM_FORCE_VULKAN=1;%(PreprocessorDefinitions) WISDOM_SHARED_LIBRARY=1;%(PreprocessorDefinitions) @@ -20,29 +21,29 @@ - $(MSBuildThisFileDirectory)..\..\lib\wisdom$(LP).lib;%(AdditionalDependencies) - $(MSBuildThisFileDirectory)..\..\lib\wisdom-shared$(LP).lib;%(AdditionalDependencies) - $(MSBuildThisFileDirectory)..\..\lib\wisdom-platform$(LP).lib;%(AdditionalDependencies) - $(MSBuildThisFileDirectory)..\..\lib\wisdom-platform-shared$(LP).lib;%(AdditionalDependencies) - $(MSBuildThisFileDirectory)..\..\lib\vkma$(LP).lib;%(AdditionalDependencies) - $(MSBuildThisFileDirectory)..\..\lib\DX12Allocator$(LP).lib;$(MSBuildThisFileDirectory)..\..\lib\DX12Helpers$(LP).lib;dxguid.lib;DXGI.lib;%(AdditionalDependencies) + $(MSBuildThisFileDirectory)..\..\lib\native\x64\wisdom$(LP).lib;%(AdditionalDependencies) + $(MSBuildThisFileDirectory)..\..\lib\native\x64\wisdom-shared$(LP).lib;%(AdditionalDependencies) + $(MSBuildThisFileDirectory)..\..\lib\native\x64\wisdom-platform$(LP).lib;%(AdditionalDependencies) + $(MSBuildThisFileDirectory)..\..\lib\native\x64\wisdom-platform-shared$(LP).lib;%(AdditionalDependencies) + $(MSBuildThisFileDirectory)..\..\lib\native\x64\vkma$(LP).lib;%(AdditionalDependencies) + $(MSBuildThisFileDirectory)..\..\lib\native\x64\DX12Allocator$(LP).lib;$(MSBuildThisFileDirectory)..\..\lib\native\x64\DirectX-Headers$(LP).lib;$(MSBuildThisFileDirectory)..\..\lib\native\x64\DirectX-Guids$(LP).lib;dxguid.lib;DXGI.lib;d3d12.lib;%(AdditionalDependencies) + - - - - wisdom-shared$(LP).dll - PreserveNewest - - true - - - wisdom-platform-shared$(LP).dll - PreserveNewest - - true - - + + + + wisdom-shared$(LP).dll + PreserveNewest + + true + + + wisdom-platform-shared$(LP).dll + PreserveNewest + + true + + - diff --git a/conanfile.py b/conanfile.py index 67949729b..dc5cc1418 100644 --- a/conanfile.py +++ b/conanfile.py @@ -93,6 +93,7 @@ def generate(self): tc.variables["WISDOM_BUILD_SHARED"] = self.options.get_safe("shared") and not is_header_only tc.variables["WISDOM_BUILD_PLATFORM"] = self.options.build_platform tc.variables["WISDOM_USE_AGILITY_SDK"] = False + tc.variables["WISDOM_DOWNLOAD_DXC"] = False tc.variables["CMAKE_UNITY_BUILD"] = True tc.generate() diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index d8314746c..b6ed90c5f 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -29,6 +29,7 @@ endif() # compile shaders from folder shaders and put them in the binary output # directory +wis_load_dxc(DOWNLOAD_LATEST) add_custom_target(wis_test_compile_shaders) file(GLOB SHADERS ${CMAKE_CURRENT_SOURCE_DIR}/shaders/*) diff --git a/examples/multisampling/CMakeLists.txt b/examples/multisampling/CMakeLists.txt index 6ad82bcb0..3c18978ba 100644 --- a/examples/multisampling/CMakeLists.txt +++ b/examples/multisampling/CMakeLists.txt @@ -14,6 +14,5 @@ target_compile_definitions(${PROJECT_NAME}-cpp PUBLIC ${ADD_DEFINITIONS}) add_dependencies(${PROJECT_NAME}-cpp copy_sdl wis_test_compile_shaders) if(POSTFIX STREQUAL "dx12" AND WISDOM_USE_AGILITY_SDK) - wis_install_agility_win32(TARGET ${PROJECT_NAME}-cpp - PATCH_EXE ON) + wis_install_agility_win32(TARGET ${PROJECT_NAME}-cpp PATCH_EXE) endif() diff --git a/generator/handle.cpp b/generator/handle.cpp index 6a27ef232..b3ce360e0 100644 --- a/generator/handle.cpp +++ b/generator/handle.cpp @@ -197,7 +197,7 @@ std::string Generator::MakeCPPHandle(const WisHandle& s, Backend backend, DocKin std::string ctor_decl; // Use constructor from base if (s.extends != Extends::None) { - ctor_decl += std::format("{}{}() noexcept\n:ImplType(std::in_place)\n{{\n ", impl_string, s.name); + ctor_decl += std::format("{}{}() noexcept\n:ImplType(wis::in_place)\n{{\n ", impl_string, s.name); } else { ctor_decl += " using ImplType::ImplType;\n"; } diff --git a/package.ps1 b/scripts/package.ps1 similarity index 85% rename from package.ps1 rename to scripts/package.ps1 index d7d2b02dd..e60a5c5fc 100644 --- a/package.ps1 +++ b/scripts/package.ps1 @@ -17,7 +17,7 @@ Skip the build step (use existing build artifacts). Default: $false .PARAMETER OutputDir - Directory for output packages. Default: './artifacts' + Directory for output packages. Default: '../artifacts' .PARAMETER Configuration Build configuration: 'both', 'debug', or 'release'. Default: 'both' @@ -31,8 +31,8 @@ Clean build and create NuGet package only. .EXAMPLE - .\package.ps1 -Format zip -SkipBuild -OutputDir "./release" - Create ZIP from existing build, output to ./release folder. + .\package.ps1 -Format zip -SkipBuild -OutputDir "../release" + Create ZIP from existing build, output to ../release folder. #> [CmdletBinding()] @@ -44,7 +44,7 @@ param( [switch]$SkipBuild, - [string]$OutputDir = './artifacts', + [string]$OutputDir = $null, [ValidateSet('both', 'debug', 'release')] [string]$Configuration = 'both' @@ -57,21 +57,23 @@ $ErrorActionPreference = "Stop" $generateNuGet = $Format -in @('nuget', 'all') $generateZip = $Format -in @('zip', 'all') +$WorkspaceRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path + # Build configurations to process $buildDebug = $Configuration -in @('both', 'debug') $buildRelease = $Configuration -in @('both', 'release') # Package-specific build roots -$nugetDebugBuildDir = 'build/msvc-debug-nuget' -$nugetReleaseBuildDir = 'build/msvc-release-nuget' -$zipDebugBuildDir = 'build/msvc-debug-zip' -$zipReleaseBuildDir = 'build/msvc-release-zip' +$nugetDebugBuildDir = Join-Path $WorkspaceRoot 'build/msvc-debug-nuget' +$nugetReleaseBuildDir = Join-Path $WorkspaceRoot 'build/msvc-release-nuget' +$zipDebugBuildDir = Join-Path $WorkspaceRoot 'build/msvc-debug-zip' +$zipReleaseBuildDir = Join-Path $WorkspaceRoot 'build/msvc-release-zip' # Package-specific install roots -$nugetDebugInstallDir = 'install/msvc-debug-nuget' -$nugetReleaseInstallDir = 'install/msvc-release-nuget' -$zipDebugInstallDir = 'install/msvc-debug-zip' -$zipReleaseInstallDir = 'install/msvc-release-zip' +$nugetDebugInstallDir = Join-Path $WorkspaceRoot 'install/msvc-debug-nuget' +$nugetReleaseInstallDir = Join-Path $WorkspaceRoot 'install/msvc-release-nuget' +$zipDebugInstallDir = Join-Path $WorkspaceRoot 'install/msvc-debug-zip' +$zipReleaseInstallDir = Join-Path $WorkspaceRoot 'install/msvc-release-zip' function Initialize-VSEnvironment { Write-Host "Initializing Visual Studio environment..." -ForegroundColor Cyan @@ -114,13 +116,13 @@ function Resolve-NuGetExecutable { } $candidatePaths = @( - 'build/msvc-release-nuget/NuGet/NuGet.exe', - 'build/msvc-debug-nuget/NuGet/NuGet.exe', - 'build/msvc-release-zip/NuGet/NuGet.exe', - 'build/msvc-debug-zip/NuGet/NuGet.exe', - 'build/msvc-release/NuGet/NuGet.exe', - 'build/msvc-debug/NuGet/NuGet.exe', - 'build/NuGet/NuGet.exe' + "$WorkspaceRoot/build/msvc-release-nuget/NuGet/NuGet.exe", + "$WorkspaceRoot/build/msvc-debug-nuget/NuGet/NuGet.exe", + "$WorkspaceRoot/build/msvc-release-zip/NuGet/NuGet.exe", + "$WorkspaceRoot/build/msvc-debug-zip/NuGet/NuGet.exe", + "$WorkspaceRoot/build/msvc-release/NuGet/NuGet.exe", + "$WorkspaceRoot/build/msvc-debug/NuGet/NuGet.exe", + "$WorkspaceRoot/build/NuGet/NuGet.exe" ) $vsWhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" @@ -178,7 +180,7 @@ function Build-Configuration { Write-Host " Configuring $Config (WISDOM_USE_AGILITY_SDK=$agilityValue)..." -ForegroundColor Gray $configureArgs = @( - '-S', '.', + '-S', $WorkspaceRoot, '-B', $BuildDir, '-G', 'Ninja', "-DCMAKE_BUILD_TYPE=$Config", @@ -187,13 +189,9 @@ function Build-Configuration { '-DWISDOM_BUILD_TESTS=OFF', '-DCMAKE_UNITY_BUILD=ON', "-DWISDOM_USE_AGILITY_SDK=$agilityValue", - '-DCPM_SOURCE_CACHE=build/_deps_cache' + "-DCPM_SOURCE_CACHE=$WorkspaceRoot/build/_deps_cache" ) - if ($Config -eq 'Release') { - $configureArgs += '-DCMAKE_INTERPROCEDURAL_OPTIMIZATION=ON' - } - Invoke-CMake $configureArgs Write-Host " Building $Config..." -ForegroundColor Gray @@ -218,14 +216,6 @@ function New-Package { throw "$Generator build directory not found at '$buildDir'. Run without -SkipBuild or build required artifacts first." } - $cpackDir = Join-Path $buildDir "_CPack_Packages" - - # Clean CPack staging directory to prevent cross-contamination between formats - if (Test-Path $cpackDir) { - Write-Host " Cleaning CPack staging directory..." -ForegroundColor Gray - Remove-Item -Recurse -Force $cpackDir - } - # Also clean any existing packages in the build directory $existingPackages = Get-ChildItem -Path $buildDir -Include @('*.nupkg', '*.zip') -ErrorAction SilentlyContinue foreach ($pkg in $existingPackages) { @@ -233,8 +223,6 @@ function New-Package { } # Select the appropriate config file based on generator - # NuGet: excludes DXC (users get it from Microsoft.Direct3D.DXC package) - # ZIP: includes DXC and Agility SDK for standalone usage $configFile = switch ($Generator) { 'NuGet' { '../../cmake/install/multi-config-nuget.cmake' } 'ZIP' { '../../cmake/install/multi-config.cmake' } @@ -292,11 +280,15 @@ Write-Host " Wisdom Package Builder" -ForegroundColor Cyan Write-Host "========================================" -ForegroundColor Cyan Write-Host " Format: $Format" Write-Host " Configuration: $Configuration" -Write-Host " Output: $OutputDir" +Write-Host " Output: $(if ($OutputDir) { $OutputDir } else { Join-Path $WorkspaceRoot 'artifacts' })" Write-Host " Clean: $Clean" Write-Host " Skip Build: $SkipBuild" Write-Host "========================================`n" -ForegroundColor Cyan +if (-not $OutputDir) { + $OutputDir = Join-Path $WorkspaceRoot "artifacts" +} + # Initialize VS environment Initialize-VSEnvironment @@ -314,8 +306,8 @@ if ($Clean) { $nugetReleaseBuildDir, $zipDebugBuildDir, $zipReleaseBuildDir, - 'build/msvc-debug', - 'build/msvc-release' + "$WorkspaceRoot/build/msvc-debug", + "$WorkspaceRoot/build/msvc-release" ) | ForEach-Object { if (Test-Path $_) { Remove-Item -Recurse -Force $_ } } @@ -356,14 +348,12 @@ if (-not $SkipBuild) { if ($generateNuGet) { $currentStep++ Write-Host "`n[$currentStep/$totalSteps] Generating NuGet package..." -ForegroundColor Yellow - Write-Host " (DXC excluded - use Microsoft.Direct3D.DXC NuGet package)" -ForegroundColor Gray New-Package -Generator 'NuGet' -OutputPath $OutputDir } if ($generateZip) { $currentStep++ Write-Host "`n[$currentStep/$totalSteps] Generating ZIP archive..." -ForegroundColor Yellow - Write-Host " (Includes DXC for standalone usage)" -ForegroundColor Gray New-Package -Generator 'ZIP' -OutputPath $OutputDir } diff --git a/scripts/test-cmake.ps1 b/scripts/test-cmake.ps1 new file mode 100644 index 000000000..dccde17fa --- /dev/null +++ b/scripts/test-cmake.ps1 @@ -0,0 +1,64 @@ +param ( + [switch]$NoRun # Optional flag to disable running the application at the end +) + +# 0. Get the script's directory +$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path + +# 1. Read the version +$VersionFilePath = Join-Path $ScriptDir "..\version\VERSION" +$WisdomVersion = (Get-Content $VersionFilePath).Trim() +Write-Host "Automated testing for Wisdom ZIP Package v$WisdomVersion" -ForegroundColor Cyan + +# 2. Find the generated ZIP file +$ArtifactsDir = Join-Path $ScriptDir "..\artifacts" +$ZipFile = Get-ChildItem -Path $ArtifactsDir -Filter "wisdom-*$WisdomVersion*.zip" | Select-Object -First 1 +if (-Not $ZipFile) { + Write-Error "Could not find the generated .zip package in $ArtifactsDir" + exit 1 +} + +# 3. Unzip the package +$ExtractDir = Join-Path $ScriptDir "..\tests\integration\cmake\extracted" +if (Test-Path $ExtractDir) { Remove-Item -Recurse -Force $ExtractDir } +Write-Host "Extracting $($ZipFile.Name) to $ExtractDir..." +Expand-Archive -Path $ZipFile.FullName -DestinationPath $ExtractDir + +# CPack usually puts everything inside a subfolder inside the ZIP (e.g., wisdom-0.7.0-win64) +$ExtractedRoot = Get-ChildItem -Path $ExtractDir | Select-Object -First 1 + +# 4. Configure the test project using CMake +Write-Host "Configuring Test App via CMake..." +# We pass CMAKE_PREFIX_PATH so find_package() knows exactly where to look +$CmakeInputDir = Join-Path $ScriptDir "..\tests\integration\cmake" +$CmakeBuildDir = Join-Path $ScriptDir "..\tests\integration\cmake\build" +cmake -S $CmakeInputDir -B $CmakeBuildDir -DCMAKE_PREFIX_PATH="$($ExtractedRoot.FullName)" + +# 5. Build the test project +Write-Host "Building Test App..." +cmake --build $CmakeBuildDir --config Release + +if ($LASTEXITCODE -ne 0) { + Write-Error "ZIP integration test failed to compile!" + exit 1 +} + + +if ($NoRun) { + Write-Host "Skipping execution of Test App due to -NoRun flag..." -ForegroundColor Cyan +} else { + # 6. Run the compiled executable + # NOTE: Because it's a dynamic build, Windows needs to find wisdom-shared.dll. + # We temporarily add the extracted /bin folder to the environment PATH just for this run. + $env:PATH = "$($ExtractedRoot.FullName)\bin;$env:PATH" + + Write-Host "Running Test App..." + & (Join-Path $CmakeBuildDir "Release\TestApp.exe") + Write-Host "Running Test App..." + & (Join-Path $CmakeBuildDir "Release\TestAppShared.exe") + Write-Host "Running Test App..." + & (Join-Path $CmakeBuildDir "Release\TestAppHeaders.exe") +} + + +Write-Host "ZIP packaging completely validated!" -ForegroundColor Green \ No newline at end of file diff --git a/scripts/test-nuget.ps1 b/scripts/test-nuget.ps1 new file mode 100644 index 000000000..8f37591bf --- /dev/null +++ b/scripts/test-nuget.ps1 @@ -0,0 +1,63 @@ +param ( + [switch]$NoRun # Optional flag to disable running the application at the end +) + +# 0. Get the script's directory +$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path + +# 1. Read the version dynamically from your repository's VERSION file +$VersionFilePath = Join-Path $ScriptDir "..\version\VERSION" +if (-Not (Test-Path $VersionFilePath)) { + Write-Error "Could not find VERSION file at $VersionFilePath" + exit 1 +} + +$WisdomVersion = (Get-Content $VersionFilePath).Trim() +Write-Host "Automated testing for Wisdom NuGet Package v$WisdomVersion" -ForegroundColor Cyan + +# 1.5 Clear the output directory before building +$GlobalCachePath = "$env:USERPROFILE\.nuget\packages\wisdom\$WisdomVersion" +if (Test-Path $GlobalCachePath) { + Write-Host "Purging outdated v$WisdomVersion from global NuGet cache..." -ForegroundColor Yellow + Remove-Item -Path $GlobalCachePath -Recurse -Force +} + +# 2. Restore the NuGet package from your local feed, passing the version variable +Write-Host "Restoring NuGet packages..." +$VcxprojPath = Join-Path $ScriptDir "..\tests\integration\nuget\test.vcxproj" +msbuild $VcxprojPath -t:restore -p:RestorePackagesConfig=true /p:WisdomPackageVersion=$WisdomVersion + +$Linkages = @("dynamic", "static", "headers") + +foreach ($Linkage in $Linkages) { + Write-Host "`n--- Testing Linkage: $Linkage ---" -ForegroundColor Cyan + + # 3. Build the project using MSBuild + Write-Host "Building Test App ($Linkage)..." + msbuild $VcxprojPath /p:Configuration=Release /p:Platform=x64 /p:WisdomPackageVersion=$WisdomVersion /p:WisdomLinkage=$Linkage + + # 4. Verify the build succeeded + if ($LASTEXITCODE -ne 0) { + Write-Error "Integration test failed to compile for $Linkage linkage!" + exit 1 + } + + # 5. Verify your .targets file successfully copied the DLL (only for shared linkage) + if ($Linkage -eq "shared") { + $DllPath = Join-Path $ScriptDir "..\tests\integration\nuget\x64\Release\wisdom-shared.dll" + if (-Not (Test-Path $DllPath)) { + Write-Error "DLL was not copied to the output directory! Check your .targets DeploymentContent." + exit 1 + } + } + + # 6. Run the compiled executable + if ($NoRun) { + Write-Host "Skipping execution of Test App due to -NoRun flag..." -ForegroundColor Cyan + } else { + Write-Host "Running Test App ($Linkage)..." + & (Join-Path $ScriptDir "..\tests\integration\nuget\x64\Release\test.exe") + } +} + +Write-Host "`nNuGet packaging completely validated for v$WisdomVersion!" -ForegroundColor Green \ No newline at end of file diff --git a/src/include/wisdom/global/internal.hpp b/src/include/wisdom/global/internal.hpp index 78167e9a2..8e5d47d6e 100644 --- a/src/include/wisdom/global/internal.hpp +++ b/src/include/wisdom/global/internal.hpp @@ -7,6 +7,13 @@ # include namespace wis { +/// @brief Tag type for in-place construction (for C++11 and later) +struct in_place_t { +}; + +/// @brief Constant for in-place construction (for C++11 and later) +static constexpr in_place_t in_place{}; + namespace impl { /// @brief Implements class for querying the internal implementation @@ -27,7 +34,7 @@ struct Implements { /// @brief Default constructor, zeros the storage template - Implements(std::in_place_t in_place, Args&&... args) noexcept + Implements(wis::in_place_t in_place, Args&&... args) noexcept { (void)in_place; // explicitly start life of Impl in our storage diff --git a/src/platform/wisdom_platform/generated/cpp_api.hpp b/src/platform/wisdom_platform/generated/cpp_api.hpp index 6a0b50f0a..de48acd77 100644 --- a/src/platform/wisdom_platform/generated/cpp_api.hpp +++ b/src/platform/wisdom_platform/generated/cpp_api.hpp @@ -82,7 +82,7 @@ class DX12Win32Extension { public: DX12Win32Extension() noexcept - : ImplType(std::in_place) + : ImplType(wis::in_place) { ::wisDX12InitWin32Extension(GetStorage()); } @@ -136,7 +136,7 @@ class DX12UWPExtension { public: DX12UWPExtension() noexcept - : ImplType(std::in_place) + : ImplType(wis::in_place) { ::wisDX12InitUWPExtension(GetStorage()); } @@ -190,7 +190,7 @@ class VKXlibExtension { public: VKXlibExtension() noexcept - : ImplType(std::in_place) + : ImplType(wis::in_place) { ::wisVKInitXlibExtension(GetStorage()); } @@ -240,7 +240,7 @@ class VKXCBExtension { public: VKXCBExtension() noexcept - : ImplType(std::in_place) + : ImplType(wis::in_place) { ::wisVKInitXCBExtension(GetStorage()); } @@ -291,7 +291,7 @@ class VKWaylandExtension { public: VKWaylandExtension() noexcept - : ImplType(std::in_place) + : ImplType(wis::in_place) { ::wisVKInitWaylandExtension(GetStorage()); } @@ -344,7 +344,7 @@ class VKWin32Extension { public: VKWin32Extension() noexcept - : ImplType(std::in_place) + : ImplType(wis::in_place) { ::wisVKInitWin32Extension(GetStorage()); } diff --git a/tests/integration/cmake/CMakeLists.txt b/tests/integration/cmake/CMakeLists.txt new file mode 100644 index 000000000..d91a906f9 --- /dev/null +++ b/tests/integration/cmake/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.20) +project(WisdomZipIntegrationTest) + +# This is what a standard user does after extracting your ZIP +find_package(wisdom REQUIRED) + +add_executable(TestAppShared entry_main.cpp) +add_executable(TestApp entry_main.cpp) +add_executable(TestAppHeaders entry_main.cpp) + +# Test dynamic linkage to ensure the DLLs load correctly +target_link_libraries(TestAppShared PRIVATE wis::wisdom-shared) +target_link_libraries(TestApp PRIVATE wis::wisdom) +target_link_libraries(TestAppHeaders PRIVATE wis::wisdom-headers) + +set_target_properties(TestAppHeaders PROPERTIES CXX_STANDARD 20) \ No newline at end of file diff --git a/tests/integration/cmake/entry_main.cpp b/tests/integration/cmake/entry_main.cpp new file mode 100644 index 000000000..e9bb31ef6 --- /dev/null +++ b/tests/integration/cmake/entry_main.cpp @@ -0,0 +1,10 @@ +#include +#include + +int main() +{ + wis::Result result; + wis::Instance instance = wis::CreateInstance(nullptr, {}, result); + std::cout << "Wisdom NuGet package successfully linked!" << std::endl; + return 0; +} diff --git a/tests/integration/nuget/entry_main.cpp b/tests/integration/nuget/entry_main.cpp new file mode 100644 index 000000000..e9bb31ef6 --- /dev/null +++ b/tests/integration/nuget/entry_main.cpp @@ -0,0 +1,10 @@ +#include +#include + +int main() +{ + wis::Result result; + wis::Instance instance = wis::CreateInstance(nullptr, {}, result); + std::cout << "Wisdom NuGet package successfully linked!" << std::endl; + return 0; +} diff --git a/tests/integration/nuget/nuget.config b/tests/integration/nuget/nuget.config new file mode 100644 index 000000000..0b8ca7620 --- /dev/null +++ b/tests/integration/nuget/nuget.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/tests/integration/nuget/test.vcxproj b/tests/integration/nuget/test.vcxproj new file mode 100644 index 000000000..e55040989 --- /dev/null +++ b/tests/integration/nuget/test.vcxproj @@ -0,0 +1,48 @@ + + + + + Debug + x64 + + + Release + x64 + + + + native + {12345678-ABCD-EFGH-IJKL-1234567890AB} + Win32Proj + 10.0 + + + + Application + v143 + Unicode + + + + + + + + + $(WisdomLinkage) + + + + + + stdcpp20 + + + + + + $(WisdomPackageVersion) + + + + \ No newline at end of file From fc2219c8a6ab249d3ae5ffef78cf77fe29b3a055 Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Thu, 23 Apr 2026 21:45:40 +0200 Subject: [PATCH 06/10] Refactor API, add Conan support, improve docs & scripts - Reformatted C/C++ API functions for consistency and readability - Replaced `supported_initial_transitions` with `gpu_upload_heap_budget` in `WisDeviceMemoryProperties` (API change) - Added Conan integration and option to manage dependencies via CMake - Introduced PowerShell scripts for automated build and test on Windows - Improved code formatting and generator logic for large file sets - Fixed and clarified documentation comments throughout the codebase - Miscellaneous bug fixes, error handling, and style improvements --- .clang-format-ignore | 1 - .github/workflows/release.yml | 2 +- CMakeLists.txt | 9 +- cmake/conan.cmake | 117 +++++++++++++++ cmake/deps/deps_win.cmake | 20 ++- conanfile.py | 13 +- docs/wisdom/enum/adapter_preference_enum.h | 3 +- docs/wisdom/enum/barrier_flags_enum.h | 3 +- .../wisdom/enum/command_queue_priority_enum.h | 3 +- docs/wisdom/enum/composite_alpha_enum.h | 3 +- docs/wisdom/enum/data_format_enum.h | 3 +- docs/wisdom/enum/depth_stencil_flags_enum.h | 3 +- docs/wisdom/enum/descriptor_heap_flags_enum.h | 3 +- .../wisdom/enum/descriptor_memory_type_enum.h | 3 +- docs/wisdom/enum/pipeline_flags_enum.h | 3 +- docs/wisdom/enum/present_flags_enum.h | 3 +- docs/wisdom/enum/query_property_type_enum.h | 6 +- docs/wisdom/enum/render_pass_flags_enum.h | 3 +- docs/wisdom/enum/swapchain_flags_enum.h | 3 +- docs/wisdom/enum/swapchain_scaling_enum.h | 3 +- docs/wisdom/enum/texture_binding_flags_enum.h | 3 +- docs/wisdom/enum/texture_layout_enum.h | 3 +- docs/wisdom/enum/view_heap_flags_enum.h | 3 +- .../command_list_set_index_buffer2_function.h | 3 +- .../command_list_set_index_buffer_function.h | 3 +- docs/wisdom/handle/adapter_query_handle.h | 3 +- docs/wisdom/handle/command_allocator_handle.h | 3 +- docs/wisdom/handle/command_list_handle.h | 3 +- docs/wisdom/handle/command_queue_handle.h | 3 +- docs/wisdom/handle/descriptor_heap_handle.h | 3 +- docs/wisdom/handle/device_handle.h | 3 +- .../wisdom/handle/resource_allocator_handle.h | 3 +- docs/wisdom/handle/swapchain_handle.h | 3 +- docs/wisdom/handle/texture_handle.h | 3 +- docs/wisdom/handle/view_heap_handle.h | 3 +- docs/wisdom/struct/buffer_barrier_struct.h | 3 +- .../descriptor_table_data_desc_struct.h | 3 +- .../struct/descriptor_table_entry_struct.h | 3 +- .../struct/device_binding_properties_struct.h | 3 +- .../device_command_queue_properties_struct.h | 3 +- ...device_descriptor_heap_properties_struct.h | 3 +- .../struct/device_memory_properties_struct.h | 28 +++- .../struct/device_requirements_struct.h | 3 +- docs/wisdom/struct/format_properties_struct.h | 3 +- .../struct/push_constant_data_desc_struct.h | 3 +- docs/wisdom/struct/rasterizer_desc_struct.h | 3 +- .../struct/render_attachments_desc_struct.h | 3 +- docs/wisdom/struct/render_pass_desc_struct.h | 3 +- .../struct/root_signature_desc_struct.h | 3 +- docs/wisdom/struct/subresource_range_struct.h | 3 +- .../wisdom/struct/surface_parameters_struct.h | 3 +- docs/wisdom/struct/swapchain_desc_struct.h | 3 +- .../struct/swapchain_update_desc_struct.h | 3 +- docs/wisdom/struct/texture_barrier_struct.h | 3 +- examples/backend/sdl_backend_c.c | 8 +- examples/compute_particles_c/entry_main.c | 17 ++- generator/bitmask.cpp | 2 + generator/constant.cpp | 1 + generator/entry_main.cpp | 30 ++-- generator/enum.cpp | 2 + generator/function.cpp | 3 + generator/handle.cpp | 1 + generator/struct.cpp | 1 + generator/variant.cpp | 1 + scripts/test-all.ps1 | 74 +++++++++ scripts/test-unit.ps1 | 108 ++++++++++++++ src/include/wisdom/bridge/span.hpp | 9 +- .../wisdom/dx12/dx12_adapter_query.cpp | 7 +- .../wisdom/dx12/dx12_command_allocator.cpp | 6 +- src/include/wisdom/dx12/dx12_command_list.cpp | 71 +++++---- .../wisdom/dx12/dx12_command_queue.cpp | 21 ++- .../wisdom/dx12/dx12_descriptor_heap.cpp | 40 ++--- src/include/wisdom/dx12/dx12_device.cpp | 7 +- src/include/wisdom/dx12/dx12_impl.cpp | 4 +- src/include/wisdom/dx12/dx12_instance.cpp | 7 +- .../wisdom/dx12/dx12_pipeline_cache.cpp | 7 +- src/include/wisdom/dx12/dx12_swapchain.cpp | 21 ++- src/include/wisdom/dx12/dx12_types.hpp | 2 +- src/include/wisdom/generated/c_api.h | 7 +- src/include/wisdom/generated/cpp_api.hpp | 7 +- src/include/wisdom/global/internal.hpp | 3 +- .../wisdom/vulkan/detail/vk_detail.hpp | 2 +- src/include/wisdom/vulkan/detail/vk_ext1.hpp | 43 +----- .../wisdom/vulkan/vk_adapter_query.cpp | 22 ++- .../wisdom/vulkan/vk_command_allocator.cpp | 6 +- .../wisdom/vulkan/vk_command_queue.cpp | 21 ++- .../wisdom/vulkan/vk_descriptor_heap.cpp | 27 ++-- src/include/wisdom/vulkan/vk_device.cpp | 141 ++++++++++++------ src/include/wisdom/vulkan/vk_extensions.cpp | 3 +- src/include/wisdom/vulkan/vk_impl.cpp | 7 +- src/include/wisdom/vulkan/vk_instance.cpp | 7 +- .../wisdom/vulkan/vk_pipeline_cache.cpp | 7 +- .../wisdom/vulkan/vk_resource_allocator.cpp | 22 +-- src/include/wisdom/vulkan/vk_swapchain.cpp | 25 +++- .../dx12/dx12_platform_uwp.cpp | 7 +- .../dx12/dx12_platform_win32.cpp | 7 +- .../vulkan/vk_platform_wayland.cpp | 7 +- xml/structs.xml | 2 +- 98 files changed, 825 insertions(+), 332 deletions(-) create mode 100644 cmake/conan.cmake create mode 100644 scripts/test-all.ps1 create mode 100644 scripts/test-unit.ps1 diff --git a/.clang-format-ignore b/.clang-format-ignore index 57ece50d7..160b1067e 100644 --- a/.clang-format-ignore +++ b/.clang-format-ignore @@ -1,3 +1,2 @@ # Ignore third-party headers that crash the parser src/include/wisdom/util/xxhash.h -docs/* diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c31144c78..a7286758c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -220,7 +220,7 @@ jobs: - name: Build and Package shell: pwsh run: | - .\package.ps1 -Format all -Configuration both -Clean -OutputDir './artifacts' + .\scripts\package.ps1 -Format all -Configuration both -Clean -OutputDir './artifacts' - name: Validate package contents shell: pwsh diff --git a/CMakeLists.txt b/CMakeLists.txt index 83a2877c5..1f5649ef5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,13 @@ option(WISDOM_BUILD_STATIC "Build the static lib." ON) option(WISDOM_BUILD_SHARED "Build the dynamic lib." ON) option(WISDOM_BUILD_PLATFORM "Build unified platform extension library." ON) option(WISDOM_BUILD_DOCS "Build the documentation." OFF) -option(WISDOM_USE_AGILITY_SDK "Download and use DirectX 12 Agility SDK." OFF) # TODO: ON +option(WISDOM_USE_AGILITY_SDK "Download and use DirectX 12 Agility SDK." OFF) +option(WISDOM_USE_CONAN "Use Conan to manage dependencies. Only for library builds." OFF) + +if (WISDOM_USE_CONAN) + set(CONAN_CXX_STANDARD 20) + include(cmake/conan.cmake) +endif() # DXC deployment options @@ -53,6 +59,7 @@ message( WISDOM_BUILD_SHARED: ${WISDOM_BUILD_SHARED} WISDOM_BUILD_PLATFORM: ${WISDOM_BUILD_PLATFORM} WISDOM_USE_AGILITY_SDK: ${WISDOM_USE_AGILITY_SDK} + WISDOM_USE_CONAN: ${WISDOM_USE_CONAN} WISDOM_VULKAN_HEADER_PATH: ${WISDOM_VULKAN_HEADER_PATH}") diff --git a/cmake/conan.cmake b/cmake/conan.cmake new file mode 100644 index 000000000..3fe1fa835 --- /dev/null +++ b/cmake/conan.cmake @@ -0,0 +1,117 @@ +# Determine the Conan compiler name based on the CMake compiler ID +if (NOT CONAN_COMPILER) + if(CMAKE_CXX_COMPILER_ID MATCHES "AppleClang") + set(CONAN_COMPILER "apple-clang") + elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(CONAN_COMPILER "clang") + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + set(CONAN_COMPILER "msvc") + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(CONAN_COMPILER "gcc") + endif() +endif() + +# Extract the major version number from the CMake compiler version +if (NOT CONAN_COMPILER_VERSION) + if (CONAN_COMPILER STREQUAL "msvc") + message (STATUS "Detected MSVC version: ${CMAKE_CXX_COMPILER_VERSION}") + + # special handling for msvc to extract the major version (e.g., 143 from 14.3.0) + string (REGEX MATCH "^[0-9]+\\.[0-9]" MSVC_VERSION_MATCH ${CMAKE_CXX_COMPILER_VERSION}) + + # remove the dot to get the major version (e.g., 143 from 14.3) + string (REPLACE "." "" CONAN_COMPILER_VERSION ${MSVC_VERSION_MATCH}) + else() + string(REGEX MATCH "^[0-9]+" CONAN_COMPILER_VERSION ${CMAKE_CXX_COMPILER_VERSION}) + endif() +endif() + +# Map Architectures to Conan's expected values +if (NOT CONAN_ARCH) + if (CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64|AMD64") + set(CONAN_ARCH "x86_64") + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i386|i686") + set(CONAN_ARCH "x86") + else () + message(WARNING "Unknown architecture ${CMAKE_SYSTEM_PROCESSOR}, using it directly for Conan") + set(CONAN_ARCH ${CMAKE_SYSTEM_PROCESSOR}) + endif() +endif() + +# Map CXX_STANDARD to Conan's expected value +if (NOT CONAN_CXX_STANDARD) + if (CMAKE_CXX_STANDARD) + set(CONAN_CXX_STANDARD ${CMAKE_CXX_STANDARD}) + else() + message(WARNING "CMAKE_CXX_STANDARD is not set, defaulting to C++20 for Conan profile") + set(CONAN_CXX_STANDARD 20) # Default to C++17 if not specified + endif() +endif() + +# Determine OS-specific Conan settings +if(WIN32) + # Append runtime version for Clang-cl + if(MSVC_TOOLSET_VERSION) + set(CONAN_OS_SPECIFIC "compiler.runtime=dynamic\ncompiler.runtime_type=${CMAKE_BUILD_TYPE}") + + if(NOT CONAN_COMPILER STREQUAL "msvc") + set(CONAN_OS_SPECIFIC "${CONAN_OS_SPECIFIC}\ncompiler.runtime_version=v${MSVC_TOOLSET_VERSION}") + endif() + endif() + +elseif(APPLE) + # macOS always uses LLVM's libc++ + set(CONAN_OS_SPECIFIC "compiler.libcxx=libc++") + +elseif(UNIX) + # On Linux, determine if Clang was forced to use libc++, otherwise default to libstdc++11 + set(CONAN_LIBCXX "libstdc++11") + + if(CONAN_COMPILER STREQUAL "clang") + # Check if the developer passed -stdlib=libc++ in the CMake cache or env + if(CMAKE_CXX_FLAGS MATCHES "-stdlib=libc\\+\\+") + set(CONAN_LIBCXX "libc++") + endif() + endif() + + set(CONAN_OS_SPECIFIC "compiler.libcxx=${CONAN_LIBCXX}") +endif() + +# Set the Conan profile content +set(CONAN_PROFILE_PATH "${CMAKE_BINARY_DIR}/conan_profile.txt") +set(CONAN_PROFILE "[settings] +os=${CMAKE_SYSTEM_NAME} +arch=${CONAN_ARCH} +build_type=${CMAKE_BUILD_TYPE} +compiler=${CONAN_COMPILER} +compiler.version=${CONAN_COMPILER_VERSION} +compiler.cppstd=${CONAN_CXX_STANDARD} +${CONAN_OS_SPECIFIC} + +[conf] +tools.cmake.cmaketoolchain:generator=${CMAKE_GENERATOR} +") + +# Make a message with file contents +message(STATUS "Generating Conan profile at ${CONAN_PROFILE_PATH}...") +message(STATUS "Conan profile content:\n${CONAN_PROFILE}") + +file(WRITE ${CONAN_PROFILE_PATH} ${CONAN_PROFILE}) + +# Call Conan to install dependencies using the generated profile +message(STATUS "Running Conan install...") +execute_process( + COMMAND conan install ${CMAKE_SOURCE_DIR} + --profile:all=${CONAN_PROFILE_PATH} + --build=missing + -cc core.graph:compatibility_mode=optimized + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + RESULT_VARIABLE conan_result +) + +if(NOT conan_result EQUAL "0") + message(FATAL_ERROR "Conan install failed!") +endif() + +# 5. Link the dependencies +list(APPEND CMAKE_PREFIX_PATH "${CMAKE_SOURCE_DIR}/build/${CMAKE_BUILD_TYPE}/generators") \ No newline at end of file diff --git a/cmake/deps/deps_win.cmake b/cmake/deps/deps_win.cmake index d7ee32ab1..2e06d4741 100644 --- a/cmake/deps/deps_win.cmake +++ b/cmake/deps/deps_win.cmake @@ -17,6 +17,14 @@ if (WISDOM_USE_AGILITY_SDK) else() message("DirectX 12 Agility SDK not enabled. Using Headers instead.") + # Create helpers library + add_library(DX12Helpers INTERFACE) + add_library(wis::DX12Helpers ALIAS DX12Helpers) + + target_compile_definitions(DX12Helpers INTERFACE + D3D12MA_USING_DIRECTX_HEADERS=1 + ) + # Guaranteed backwards compatibility. # Using origin/main to ensure we get the latest headers, # which are compatible with the latest SDKs. @@ -26,25 +34,21 @@ else() GIT_TAG origin/main ) - # Create helpers library - add_library(DX12Helpers INTERFACE) - add_library(wis::DX12Helpers ALIAS DX12Helpers) - target_link_libraries(DX12Helpers INTERFACE DirectX-Headers DirectX-Guids) - target_compile_definitions(DX12Helpers INTERFACE - D3D12MA_USING_DIRECTX_HEADERS=1 - ) + install(DIRECTORY ${dxheaders_SOURCE_DIR}/include/directx DESTINATION include) install(DIRECTORY ${dxheaders_SOURCE_DIR}/include/dxguids DESTINATION include) install( - TARGETS DirectX-Headers DirectX-Guids DX12Helpers + TARGETS DirectX-Headers DirectX-Guids EXPORT wisdom-targets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + + install(TARGETS DX12Helpers EXPORT wisdom-targets) endif() diff --git a/conanfile.py b/conanfile.py index dc5cc1418..4921525e9 100644 --- a/conanfile.py +++ b/conanfile.py @@ -1,9 +1,6 @@ import os from conan import ConanFile -from conan.tools.cmake import CMake -from conan.tools.cmake import cmake_layout -from conan.tools.cmake import CMakeToolchain -from conan.tools.files import collect_libs +from conan.tools.cmake import CMake, cmake_layout, CMakeToolchain, CMakeDeps from conan.tools.files import copy, load @@ -42,6 +39,10 @@ def set_version(self): self.output.warning(f"Could not read version file: {e}") self.version = "0.0.0" + def requirements(self): + #self.requires("d3d12-memory-allocator/3.0.1", transitive_headers=True) + pass + def export_sources(self): copy( self, @@ -78,6 +79,9 @@ def layout(self): cmake_layout(self) def generate(self): + deps = CMakeDeps(self) + deps.generate() + self.output.warning( "This recipe currently relies on the project's CPM/NuGet dependency loading during CMake configure. " "For Conan Center, those dependencies should be provided as Conan requirements or vendored sources." @@ -95,6 +99,7 @@ def generate(self): tc.variables["WISDOM_USE_AGILITY_SDK"] = False tc.variables["WISDOM_DOWNLOAD_DXC"] = False tc.variables["CMAKE_UNITY_BUILD"] = True + tc.user_presets_path = "" tc.generate() def build(self): diff --git a/docs/wisdom/enum/adapter_preference_enum.h b/docs/wisdom/enum/adapter_preference_enum.h index 66a658980..ee3e18d9b 100644 --- a/docs/wisdom/enum/adapter_preference_enum.h +++ b/docs/wisdom/enum/adapter_preference_enum.h @@ -43,7 +43,8 @@ * - `WisAdapterPreferenceMinConsumption = 1`: List the adapters from low power consumption to high. DirectX 12: * Integrated, Discrete, External, Software. Vulkan: Integrated GPU, Discrete GPU, Virtual GPU, CPU. * - `WisAdapterPreferencePerformance = 2`: List the adapters from high performance to low. DirectX 12: External, - * Discrete, Integrated, Software. Vulkan: Discrete GPU, Integrated GPU, Virtual GPU, CPU. \endcond + * Discrete, Integrated, Software. Vulkan: Discrete GPU, Integrated GPU, Virtual GPU, CPU. + * \endcond * * GPU order @wis_may vary between the implementations due to differing heuristics. * diff --git a/docs/wisdom/enum/barrier_flags_enum.h b/docs/wisdom/enum/barrier_flags_enum.h index 5ea6891b3..d6afc1a46 100644 --- a/docs/wisdom/enum/barrier_flags_enum.h +++ b/docs/wisdom/enum/barrier_flags_enum.h @@ -47,7 +47,8 @@ * the specified subresource range. If set, the subresource range is ignored and the transition is applied to all * subresources of the resource. * - `WisBarrierFlagsPlanarImage = (1 << 3)`: Resource is a planar image. If the flag is not set, plane slices in - * WisSubresourceRange are ignored. \endcond + * WisSubresourceRange are ignored. + * \endcond * * * @section WisBarrierFlags_see_also See Also diff --git a/docs/wisdom/enum/command_queue_priority_enum.h b/docs/wisdom/enum/command_queue_priority_enum.h index 3b28f056b..f68ffae45 100644 --- a/docs/wisdom/enum/command_queue_priority_enum.h +++ b/docs/wisdom/enum/command_queue_priority_enum.h @@ -40,7 +40,8 @@ * - `WisCommandQueuePriorityNormal = 0`: Normal queue priority. * - `WisCommandQueuePriorityHigh = 1`: High queue priority. * - `WisCommandQueuePriorityRealtime = 2`: Global realtime queue priority. Requires special GPU support and @wis_may - * cause performance issues if used on unsupported hardware. \endcond + * cause performance issues if used on unsupported hardware. + * \endcond * * * @section WisCommandQueuePriority_see_also See Also diff --git a/docs/wisdom/enum/composite_alpha_enum.h b/docs/wisdom/enum/composite_alpha_enum.h index 8edc0a73d..ed55b6cde 100644 --- a/docs/wisdom/enum/composite_alpha_enum.h +++ b/docs/wisdom/enum/composite_alpha_enum.h @@ -45,7 +45,8 @@ * - `WisCompositeAlphaPostMultiplied = 2`: The alpha channel, if it exists, is respected and used in compositing. The * postmultiplied alpha format is expected. * - `WisCompositeAlphaInherit = 3`: The alpha channel, if it exists, is respected and used in compositing based on the - * platform's default behavior. \endcond + * platform's default behavior. + * \endcond * * * @section WisCompositeAlpha_see_also See Also diff --git a/docs/wisdom/enum/data_format_enum.h b/docs/wisdom/enum/data_format_enum.h index 1d355601e..cba9e183e 100644 --- a/docs/wisdom/enum/data_format_enum.h +++ b/docs/wisdom/enum/data_format_enum.h @@ -482,5 +482,6 @@ * @see Structs: * WisTextureDesc, WisTextureBinding, WisInputAttributeDesc, WisRenderAttachmentsDesc, WisRenderTargetDesc, * WisSwapchainDesc, WisSwapchainUpdateDesc Functions: wisDeviceGetFormatPresentationSupport, - * wisDeviceGetFormatProperties \endcond + * wisDeviceGetFormatProperties + * \endcond */ diff --git a/docs/wisdom/enum/depth_stencil_flags_enum.h b/docs/wisdom/enum/depth_stencil_flags_enum.h index 85bc4ada1..30d64e856 100644 --- a/docs/wisdom/enum/depth_stencil_flags_enum.h +++ b/docs/wisdom/enum/depth_stencil_flags_enum.h @@ -45,7 +45,8 @@ * - `WisDepthStencilFlagsReadOnlyDepth = (1 << 2)`: Depth part is read only. Texture @wis_must be in either read state, * depending on the format. * - `WisDepthStencilFlagsReadOnlyStencil = (1 << 3)`: Stencil part is read only. Texture @wis_must be in either read - * state, depending on the format. \endcond + * state, depending on the format. + * \endcond * * * @section WisDepthStencilFlags_see_also See Also diff --git a/docs/wisdom/enum/descriptor_heap_flags_enum.h b/docs/wisdom/enum/descriptor_heap_flags_enum.h index 5a6caf9ab..48298814f 100644 --- a/docs/wisdom/enum/descriptor_heap_flags_enum.h +++ b/docs/wisdom/enum/descriptor_heap_flags_enum.h @@ -35,7 +35,8 @@ * - `WisDescriptorHeapFlagsNone = 0`: No flags set. * - `WisDescriptorHeapFlagsDisallowEmbeddedSamplers = (1 << 1)`: Heap is used in full for dynamic samplers. There * @wis_mustnot be any shader that use embedded samplers that uses that heap. User @wis_may allocate more samplers in - * the heap than it would normally be. \endcond + * the heap than it would normally be. + * \endcond * * * @section WisDescriptorHeapFlags_see_also See Also diff --git a/docs/wisdom/enum/descriptor_memory_type_enum.h b/docs/wisdom/enum/descriptor_memory_type_enum.h index fee0601ac..12c4dfd59 100644 --- a/docs/wisdom/enum/descriptor_memory_type_enum.h +++ b/docs/wisdom/enum/descriptor_memory_type_enum.h @@ -37,7 +37,8 @@ * - `WisDescriptorMemoryTypeCpuOnly = 0`: Descriptors are only visible to CPU. May be used for copying descriptors to * the GPU visible pool. * - `WisDescriptorMemoryTypeShaderVisible = 1`: Descriptors are visible to GPU. Descriptors can be bound to the GPU - * pipeline directly, but can't be copied from. \endcond + * pipeline directly, but can't be copied from. + * \endcond * * * @section WisDescriptorMemoryType_see_also See Also diff --git a/docs/wisdom/enum/pipeline_flags_enum.h b/docs/wisdom/enum/pipeline_flags_enum.h index fcc2ff347..7fd53c7ae 100644 --- a/docs/wisdom/enum/pipeline_flags_enum.h +++ b/docs/wisdom/enum/pipeline_flags_enum.h @@ -43,7 +43,8 @@ * - `WisPipelineFlagsEnablePrimitiveRestart = (1 << 1)`: Enable primitive restart for graphics pipelines. If not set, * primitive restart is disabled and the implementation @wis_may choose to ignore restart indices in draw calls. * - `WisPipelineFlagsDynamicDepthBias = (1 << 2)`: Enable dynamic depth bias for graphics pipelines. If not set, depth - * bias is static and @wis_must be specified at pipeline creation time. \endcond + * bias is static and @wis_must be specified at pipeline creation time. + * \endcond * * * @section WisPipelineFlags_see_also See Also diff --git a/docs/wisdom/enum/present_flags_enum.h b/docs/wisdom/enum/present_flags_enum.h index 2ffee517d..fa0b0247c 100644 --- a/docs/wisdom/enum/present_flags_enum.h +++ b/docs/wisdom/enum/present_flags_enum.h @@ -36,7 +36,8 @@ * Values: * - `WisPresentFlagsNone = 0`: No flags set. Swapchain is regular. * - `WisPresentFlagsTimeoutOnBlock = (1 << 0)`: Fail present if the presentation engine is busy. If not set, the - * implementation @wis_may choose to block until the presentation engine is available. \endcond + * implementation @wis_may choose to block until the presentation engine is available. + * \endcond * * * @section WisPresentFlags_see_also See Also diff --git a/docs/wisdom/enum/query_property_type_enum.h b/docs/wisdom/enum/query_property_type_enum.h index a6fade280..a66619811 100644 --- a/docs/wisdom/enum/query_property_type_enum.h +++ b/docs/wisdom/enum/query_property_type_enum.h @@ -43,7 +43,8 @@ * - `WisQueryPropertyTypeDeviceMemoryProperties = 2`: Properties of the device descriptor heap. Expects a * WisDeviceMemoryProperties struct. * - `WisQueryPropertyTypeDeviceBindingProperties = 3`: Properties of the device resource binding. Expects a - * WisDeviceBindingProperties struct. \endcond + * WisDeviceBindingProperties struct. + * \endcond * * * @section WisQueryPropertyType_see_also See Also @@ -52,5 +53,6 @@ * \cond WIS_GEN_REFS * @see Structs: * WisQueryStructHeader, WisDeviceBindingProperties, WisDeviceDescriptorHeapProperties, WisDeviceCommandQueueProperties, - * WisDeviceMemoryProperties \endcond + * WisDeviceMemoryProperties + * \endcond */ diff --git a/docs/wisdom/enum/render_pass_flags_enum.h b/docs/wisdom/enum/render_pass_flags_enum.h index c02cda66a..9b6104a84 100644 --- a/docs/wisdom/enum/render_pass_flags_enum.h +++ b/docs/wisdom/enum/render_pass_flags_enum.h @@ -45,7 +45,8 @@ * - `WisRenderPassFlagsResuming = (1 << 2)`: Render pass is resuming. * - `WisRenderPassFlagsAllowUAVWrites = (1 << 3)`: Allow UAV writes. If set, unordered access view (UAV) writes are * allowed during the render pass. If not set, UAV writes are not allowed and @wis_may result in undefined behavior if - * attempted. \endcond + * attempted. + * \endcond * * * @section WisRenderPassFlags_see_also See Also diff --git a/docs/wisdom/enum/swapchain_flags_enum.h b/docs/wisdom/enum/swapchain_flags_enum.h index da0a9a5f5..246e8b4d7 100644 --- a/docs/wisdom/enum/swapchain_flags_enum.h +++ b/docs/wisdom/enum/swapchain_flags_enum.h @@ -41,7 +41,8 @@ * - `WisSwapchainFlagsVSync = (1 << 1)`: Present with vertical sync. If set, the swapchain is presented with vertical * sync pulse. * - `WisSwapchainFlagsStereo = (1 << 2)`: Stereo swapchain. If set, the swapchain is created for stereo rendering. If - * not set, the swapchain is created for mono rendering. \endcond + * not set, the swapchain is created for mono rendering. + * \endcond * * * @section WisSwapchainFlags_see_also See Also diff --git a/docs/wisdom/enum/swapchain_scaling_enum.h b/docs/wisdom/enum/swapchain_scaling_enum.h index 6de51d63e..d2ad922a2 100644 --- a/docs/wisdom/enum/swapchain_scaling_enum.h +++ b/docs/wisdom/enum/swapchain_scaling_enum.h @@ -40,7 +40,8 @@ * - `WisSwapchainScalingNone = 0`: No scaling. The swapchain size is equal to the window size. * - `WisSwapchainScalingStretch = 1`: Stretch scaling. The swapchain size is stretched to the window size. * - `WisSwapchainScalingAspect = 2`: Aspect scaling. The swapchain size is scaled to the window size with aspect ratio - * preserved. \endcond + * preserved. + * \endcond * * * @section WisSwapchainScaling_see_also See Also diff --git a/docs/wisdom/enum/texture_binding_flags_enum.h b/docs/wisdom/enum/texture_binding_flags_enum.h index 899eda74c..31819a8bf 100644 --- a/docs/wisdom/enum/texture_binding_flags_enum.h +++ b/docs/wisdom/enum/texture_binding_flags_enum.h @@ -39,7 +39,8 @@ * feature depth and stencil. The bound texture @wis_must be in TODO: specific layout before being used by shader. * - `WisTextureBindingFlagsStencilView = (1 << 1)`: Texture view is used to read stencil. Used for special formats that * feature depth and stencil. The bound texture @wis_must be in TODO: specific layout before being used by shader. - * Cannot be combined with `WisTextureBindingFlagsDepthView`. \endcond + * Cannot be combined with `WisTextureBindingFlagsDepthView`. + * \endcond * * * @section WisTextureBindingFlags_see_also See Also diff --git a/docs/wisdom/enum/texture_layout_enum.h b/docs/wisdom/enum/texture_layout_enum.h index fc7ff226b..58fb43e08 100644 --- a/docs/wisdom/enum/texture_layout_enum.h +++ b/docs/wisdom/enum/texture_layout_enum.h @@ -55,7 +55,8 @@ * - `WisTextureLayoutTexture3D = 8`: Texture is 3D volume. * - `WisTextureLayoutTextureCube = 9`: Texture is a cube map. Behaves similarly to Texture2DArray with 6 layers. * - `WisTextureLayoutTextureCubeArray = 10`: Texture is an array of cube maps. Behaves similarly to Texture2DArray with - * 6 layers per cube map. \endcond + * 6 layers per cube map. + * \endcond * * * @section WisTextureLayout_see_also See Also diff --git a/docs/wisdom/enum/view_heap_flags_enum.h b/docs/wisdom/enum/view_heap_flags_enum.h index 354de29a4..2714ce0ae 100644 --- a/docs/wisdom/enum/view_heap_flags_enum.h +++ b/docs/wisdom/enum/view_heap_flags_enum.h @@ -36,7 +36,8 @@ * Values: * - `WisViewHeapFlagsNone = 0`: No flags set. View heap is regular. * - `WisViewHeapFlagsAllowMultisample = (1 << 0)`: Allows the view heap to be used with multisampled resources. If not - * set, the view heap does not enable multisample-related usage. \endcond + * set, the view heap does not enable multisample-related usage. + * \endcond * * * @section WisViewHeapFlags_see_also See Also diff --git a/docs/wisdom/func/command_list_set_index_buffer2_function.h b/docs/wisdom/func/command_list_set_index_buffer2_function.h index 57ab8b3ef..dc75e0572 100644 --- a/docs/wisdom/func/command_list_set_index_buffer2_function.h +++ b/docs/wisdom/func/command_list_set_index_buffer2_function.h @@ -59,7 +59,8 @@ * - **this** `self` self is a pointer to the valid WisCommandList instance. * - `buffer` The index buffer to set. * - `index_type` Defines index type. Used to determine the size of each index in the buffer. Must be either - * `WisIndexTypeUInt16` or `WisIndexTypeUInt32`. \endcond + * `WisIndexTypeUInt16` or `WisIndexTypeUInt32`. + * \endcond * * @section wisCommandListSetIndexBuffer2_descr Description *
diff --git a/docs/wisdom/func/command_list_set_index_buffer_function.h b/docs/wisdom/func/command_list_set_index_buffer_function.h index d55a4ed19..05dc126ba 100644 --- a/docs/wisdom/func/command_list_set_index_buffer_function.h +++ b/docs/wisdom/func/command_list_set_index_buffer_function.h @@ -59,7 +59,8 @@ * - **this** `self` self is a pointer to the valid WisCommandList instance. * - `buffer` The index buffer to set. * - `index_type` Defines index type. Used to determine the size of each index in the buffer. Must be either - * `WisIndexTypeUInt16` or `WisIndexTypeUInt32`. \endcond + * `WisIndexTypeUInt16` or `WisIndexTypeUInt32`. + * \endcond * * @section wisCommandListSetIndexBuffer_descr Description *
diff --git a/docs/wisdom/handle/adapter_query_handle.h b/docs/wisdom/handle/adapter_query_handle.h index d914f9a21..1829feba8 100644 --- a/docs/wisdom/handle/adapter_query_handle.h +++ b/docs/wisdom/handle/adapter_query_handle.h @@ -28,5 +28,6 @@ * \cond WIS_GEN_REFS * @see Functions: * wisDestroyAdapterQuery, wisInstanceQueryAdapters, wisAdapterQueryGetAdapterCount, wisAdapterQueryGetAdapterDesc, - * wisAdapterQueryGetSurfaceSupport, wisAdapterQueryCreateDevice \endcond + * wisAdapterQueryGetSurfaceSupport, wisAdapterQueryCreateDevice + * \endcond */ diff --git a/docs/wisdom/handle/command_allocator_handle.h b/docs/wisdom/handle/command_allocator_handle.h index 3c89e47bf..fc0eb0475 100644 --- a/docs/wisdom/handle/command_allocator_handle.h +++ b/docs/wisdom/handle/command_allocator_handle.h @@ -24,5 +24,6 @@ * \cond WIS_GEN_REFS * @see Functions: * wisDestroyCommandAllocator, wisDeviceCreateCommandAllocator, wisCommandAllocatorReset, - * wisCommandAllocatorCreateCommandList \endcond + * wisCommandAllocatorCreateCommandList + * \endcond */ diff --git a/docs/wisdom/handle/command_list_handle.h b/docs/wisdom/handle/command_list_handle.h index 898d74576..7e0e59bfd 100644 --- a/docs/wisdom/handle/command_list_handle.h +++ b/docs/wisdom/handle/command_list_handle.h @@ -33,5 +33,6 @@ * wisCommandListDrawIndexed, wisCommandListBeginRenderPass, wisCommandListEndRenderPass, wisCommandListCopyBuffer, * wisCommandListCopyBufferToTexture, wisCommandListCopyTextureToBuffer, wisCommandListCopyTexture, * wisCommandListSetVertexBuffers, wisCommandListSetVertexBuffers2, wisCommandListSetIndexBuffer, - * wisCommandListSetIndexBuffer2, wisCommandListSetBlendFactors \endcond + * wisCommandListSetIndexBuffer2, wisCommandListSetBlendFactors + * \endcond */ diff --git a/docs/wisdom/handle/command_queue_handle.h b/docs/wisdom/handle/command_queue_handle.h index aef26a747..1c93793ef 100644 --- a/docs/wisdom/handle/command_queue_handle.h +++ b/docs/wisdom/handle/command_queue_handle.h @@ -24,5 +24,6 @@ * \cond WIS_GEN_REFS * @see Functions: * wisDestroyCommandQueue, wisDeviceCreateCommandQueue, wisDeviceCreateSwapchain, wisCommandQueueSubmit, - * wisCommandQueueSignalFence, wisCommandQueueWaitFence \endcond + * wisCommandQueueSignalFence, wisCommandQueueWaitFence + * \endcond */ diff --git a/docs/wisdom/handle/descriptor_heap_handle.h b/docs/wisdom/handle/descriptor_heap_handle.h index b1aa9edb1..9ae0e1a8c 100644 --- a/docs/wisdom/handle/descriptor_heap_handle.h +++ b/docs/wisdom/handle/descriptor_heap_handle.h @@ -27,5 +27,6 @@ * wisDescriptorHeapWriteConstantBuffer, wisDescriptorHeapWriteStructuredBuffer, * wisDescriptorHeapWriteRWStructuredBuffer, wisDescriptorHeapWriteSampler, wisDescriptorHeapWriteTexture, * wisDescriptorHeapWriteRWTexture, wisDescriptorHeapWriteAccelerationStructure, wisDescriptorHeapCopyDescriptors, - * wisCommandListSetDescriptorHeaps \endcond + * wisCommandListSetDescriptorHeaps + * \endcond */ diff --git a/docs/wisdom/handle/device_handle.h b/docs/wisdom/handle/device_handle.h index c5fd337b7..4e5f6ece9 100644 --- a/docs/wisdom/handle/device_handle.h +++ b/docs/wisdom/handle/device_handle.h @@ -28,5 +28,6 @@ * wisDeviceCreateViewHeap, wisDeviceQueryProperties, wisDeviceWaitForMultipleFences, wisDeviceCreatePipelineCache, * wisDeviceCreateShader, wisDeviceCreateComputePipeline, wisDeviceCreateGraphicsPipeline, * wisDeviceGetFormatPresentationSupport, wisDeviceGetSurfaceParameters, wisDeviceCreateSwapchain, - * wisDeviceGetFormatProperties \endcond + * wisDeviceGetFormatProperties + * \endcond */ diff --git a/docs/wisdom/handle/resource_allocator_handle.h b/docs/wisdom/handle/resource_allocator_handle.h index 82519d944..3102dbfa5 100644 --- a/docs/wisdom/handle/resource_allocator_handle.h +++ b/docs/wisdom/handle/resource_allocator_handle.h @@ -24,5 +24,6 @@ * \cond WIS_GEN_REFS * @see Functions: * wisDestroyResourceAllocator, wisDeviceGetResourceAllocator, wisResourceAllocatorCreateBuffer, - * wisResourceAllocatorCreateTexture \endcond + * wisResourceAllocatorCreateTexture + * \endcond */ diff --git a/docs/wisdom/handle/swapchain_handle.h b/docs/wisdom/handle/swapchain_handle.h index 5ce4788aa..fcf57ec18 100644 --- a/docs/wisdom/handle/swapchain_handle.h +++ b/docs/wisdom/handle/swapchain_handle.h @@ -24,5 +24,6 @@ * \cond WIS_GEN_REFS * @see Functions: * wisDestroySwapchain, wisDeviceCreateSwapchain, wisSwapchainPresent, wisSwapchainGetCurrentIndex, wisSwapchainUpdate, - * wisSwapchainGetTextures \endcond + * wisSwapchainGetTextures + * \endcond */ diff --git a/docs/wisdom/handle/texture_handle.h b/docs/wisdom/handle/texture_handle.h index 34e5e355e..e3c7fbc5f 100644 --- a/docs/wisdom/handle/texture_handle.h +++ b/docs/wisdom/handle/texture_handle.h @@ -26,5 +26,6 @@ * \cond WIS_GEN_REFS * @see Functions: * wisDestroyTexture, wisResourceAllocatorCreateTexture, wisTextureWriteSubresource, wisViewHeapWriteRenderTarget, - * wisViewHeapWriteDepthStencil, wisSwapchainGetTextures \endcond + * wisViewHeapWriteDepthStencil, wisSwapchainGetTextures + * \endcond */ diff --git a/docs/wisdom/handle/view_heap_handle.h b/docs/wisdom/handle/view_heap_handle.h index 21d92c9f8..052edb0cb 100644 --- a/docs/wisdom/handle/view_heap_handle.h +++ b/docs/wisdom/handle/view_heap_handle.h @@ -24,5 +24,6 @@ * \cond WIS_GEN_REFS * @see Functions: * wisDestroyViewHeap, wisDeviceCreateViewHeap, wisViewHeapWriteRenderTarget, wisViewHeapWriteDepthStencil, - * wisViewHeapGetViewAddress, wisViewHeapCopyViews, wisViewHeapGetCPUHandle \endcond + * wisViewHeapGetViewAddress, wisViewHeapCopyViews, wisViewHeapGetCPUHandle + * \endcond */ diff --git a/docs/wisdom/struct/buffer_barrier_struct.h b/docs/wisdom/struct/buffer_barrier_struct.h index 8549ef5e3..d7ef640f7 100644 --- a/docs/wisdom/struct/buffer_barrier_struct.h +++ b/docs/wisdom/struct/buffer_barrier_struct.h @@ -117,7 +117,8 @@ * - `queue_type_before` defines type of the queue the barrier is executed on before the synchronization point. Used for * cross-queue barriers. * - `queue_type_after` indicates type of the queue the barrier is executed on after the synchronization point. Used for - * cross-queue barriers. \endcond + * cross-queue barriers. + * \endcond * * @section WisBufferBarrier_descr Description *
diff --git a/docs/wisdom/struct/descriptor_table_data_desc_struct.h b/docs/wisdom/struct/descriptor_table_data_desc_struct.h index 7197587d7..6a0d979f8 100644 --- a/docs/wisdom/struct/descriptor_table_data_desc_struct.h +++ b/docs/wisdom/struct/descriptor_table_data_desc_struct.h @@ -39,7 +39,8 @@ * - `root_index` indicates the root index in the root signature to set the push descriptors for. * - `heap_type` indicates the type of the descriptor heap to bind. * - `heap_offset` defines the offset in descriptors from the start of the heap to set the descriptor table to. Used for - * calculating descriptor indices when binding descriptor tables. \endcond + * calculating descriptor indices when binding descriptor tables. + * \endcond * * @section WisDescriptorTableDataDesc_descr Description *
diff --git a/docs/wisdom/struct/descriptor_table_entry_struct.h b/docs/wisdom/struct/descriptor_table_entry_struct.h index 1cb45e6f5..eb02560be 100644 --- a/docs/wisdom/struct/descriptor_table_entry_struct.h +++ b/docs/wisdom/struct/descriptor_table_entry_struct.h @@ -43,7 +43,8 @@ * - `count` describes descriptor count for Array descriptors. UINT32_MAX means unbounded array. 0 means single * register, same as 1. * - `descriptor_offset` describes offset in descriptors from the heap start. Used for calculating descriptor indices - * when binding descriptor tables. \endcond + * when binding descriptor tables. + * \endcond * * @section WisDescriptorTableEntry_descr Description *
diff --git a/docs/wisdom/struct/device_binding_properties_struct.h b/docs/wisdom/struct/device_binding_properties_struct.h index b3b92e47c..a0a60d310 100644 --- a/docs/wisdom/struct/device_binding_properties_struct.h +++ b/docs/wisdom/struct/device_binding_properties_struct.h @@ -49,7 +49,8 @@ * - `multiple_viewports_supported` indicates if multiple viewports are supported. If true, the device supports up to 16 * viewports and scissor rectangles. If false, only one viewport and scissor rectangle is supported. * - `address_commands_supported` indicates if commands with buffer addresses are supported. If true, the device - * supports commands that take buffer addresses directly, such as wisCommandListSetVertexBuffers2. \endcond + * supports commands that take buffer addresses directly, such as wisCommandListSetVertexBuffers2. + * \endcond * * @section WisDeviceBindingProperties_descr Description *
diff --git a/docs/wisdom/struct/device_command_queue_properties_struct.h b/docs/wisdom/struct/device_command_queue_properties_struct.h index c24324544..99dbadc1a 100644 --- a/docs/wisdom/struct/device_command_queue_properties_struct.h +++ b/docs/wisdom/struct/device_command_queue_properties_struct.h @@ -46,7 +46,8 @@ * buffers is used on a different queue type. It is supported on Windows 10 22H2 and later with WDDM 3.0 or later. On * Vulkan it requires `VK_KHR_maintenance9` extension. * - `max_queue_priority` indicates an array of maximum supported priorities for each queue type. If a queue type is not - * supported, the value is `0`. Order of queue types is the same as in WisCommandQueueType enum. \endcond + * supported, the value is `0`. Order of queue types is the same as in WisCommandQueueType enum. + * \endcond * * @section WisDeviceCommandQueueProperties_descr Description *
diff --git a/docs/wisdom/struct/device_descriptor_heap_properties_struct.h b/docs/wisdom/struct/device_descriptor_heap_properties_struct.h index 8acfb6752..931d29ef0 100644 --- a/docs/wisdom/struct/device_descriptor_heap_properties_struct.h +++ b/docs/wisdom/struct/device_descriptor_heap_properties_struct.h @@ -67,7 +67,8 @@ * - `render_target_with_ms_increment_size` defines size of a single render target view descriptor in the descriptor * heap with multisample targets enabled. Used for calculating render target view descriptor offsets. * - `depth_stencil_with_ms_increment_size` defines size of a single depth stencil view descriptor in the descriptor - * heap with multisample targets enabled. Used for calculating depth stencil view descriptor offsets. \endcond + * heap with multisample targets enabled. Used for calculating depth stencil view descriptor offsets. + * \endcond * * @section WisDeviceDescriptorHeapProperties_descr Description *
diff --git a/docs/wisdom/struct/device_memory_properties_struct.h b/docs/wisdom/struct/device_memory_properties_struct.h index 1f4dbd491..42ee64934 100644 --- a/docs/wisdom/struct/device_memory_properties_struct.h +++ b/docs/wisdom/struct/device_memory_properties_struct.h @@ -2,6 +2,8 @@ * @struct WisDeviceMemoryProperties * @ingroup Structures Core * + * Structure describing memory properties of the device. + * Pass it to `wisDeviceQueryProperties` either directly or chained to another query structure for it to be filled. * * @section WisDeviceMemoryProperties_spec Specification *
@@ -15,7 +17,7 @@ * void* next_in_chain; * bool gpu_upload_supported; * bool host_image_copy_supported; - * uint32_t supported_initial_transitions; + * uint64_t gpu_upload_heap_budget; * } WisDeviceMemoryProperties; * * ``` @@ -28,7 +30,7 @@ * void* next_in_chain; * bool gpu_upload_supported; * bool host_image_copy_supported; - * std::uint32_t supported_initial_transitions; + * std::uint64_t gpu_upload_heap_budget; * }; * } * ``` @@ -47,13 +49,29 @@ * from CPU memory to optimal tiled image layout on GPU, without the need for an intermediate staging buffer. It is * supported on Windows 10 22H2 and later with WDDM 3.0 or later. On Vulkan it requires `VK_EXT_host_image_copy` * extension. - * - `supported_initial_transitions` defines bitfield of supported initial resource state transitions for buffers and - * textures. If a transition is supported, the corresponding bit is set to `1`, otherwise `0`. Bit positions are the - * same as in WisTextureState enum. `WisTextureStateUndefined` is always supported. \endcond + * - `gpu_upload_heap_budget` specifies heap budget for GPU upload memory type in bytes. This is an approximate value of + * how much memory of this type can be allocated, and it can change over time depending on the system state. + * \endcond * * @section WisDeviceMemoryProperties_descr Description *
* + * `gpu_upload_heap_budget` is a metric of how much memory of the GPU upload type can be allocated, but it is not a hard + * limit. It is possible that allocations of this type may fail even if the total allocated memory is below this budget, + * due to fragmentation or other factors. Conversely, it may be possible to allocate more memory than this budget in + * some cases. This value should be used as a guideline for how much memory of this type to allocate, rather than a + * strict limit. + * + * `gpu_upload_heap_budget` has 3 possible states: + * - If the device does not support GPU upload memory type, this value will be 0. + * - If the device supports GPU upload memory, but the ReBAR is not enabled, this value will be 0 on DirectX 12 and a + * small value on Vulkan (e.g., 256MB), representing the portion of shared system memory that is accessible to the GPU. + * The value is exposed even if ReBAR is not enabled, because in some cases allocation such a small amount may be + * beneficial, because it may be faster to access than regular Upload Heap. + * - If the device supports GPU upload memory and ReBAR is enabled, this value will be either equal to the size of + * dedicated video memory or a nearby value, depending on how the system allocates memory for the GPU upload type. This + * means that whole video memory is accessible by CPU and uploads can be done without staging buffers. + * * \cond WIS_GEN_WIS_IDS * \endcond * diff --git a/docs/wisdom/struct/device_requirements_struct.h b/docs/wisdom/struct/device_requirements_struct.h index 0a1d1ef01..3ca6b5372 100644 --- a/docs/wisdom/struct/device_requirements_struct.h +++ b/docs/wisdom/struct/device_requirements_struct.h @@ -76,7 +76,8 @@ * queue_descs array. * - `extensions` points to an array of extensions that are to be initialized with pointers to WisDeviceExtensionHeader. * - `extension_count` describes the number of the number of extensions in the wisAdapterQueryCreateDevice extensions - * array. \endcond + * array. + * \endcond * * @section WisDeviceRequirements_descr Description *
diff --git a/docs/wisdom/struct/format_properties_struct.h b/docs/wisdom/struct/format_properties_struct.h index 0c1a6f2ca..4a8733707 100644 --- a/docs/wisdom/struct/format_properties_struct.h +++ b/docs/wisdom/struct/format_properties_struct.h @@ -33,7 +33,8 @@ * \cond WIS_GEN_DESC * - `format_support_flags` specifies bitmask of supported features for the format. * - `max_sample_count` defines maximum supported sample count for the format. If the format does not support - * multisampling, the value is `S1`. \endcond + * multisampling, the value is `S1`. + * \endcond * * @section WisFormatProperties_descr Description *
diff --git a/docs/wisdom/struct/push_constant_data_desc_struct.h b/docs/wisdom/struct/push_constant_data_desc_struct.h index 0c935dbee..4e6a26cda 100644 --- a/docs/wisdom/struct/push_constant_data_desc_struct.h +++ b/docs/wisdom/struct/push_constant_data_desc_struct.h @@ -43,7 +43,8 @@ * - `data_size` defines the size of the data in bytes. It @wis_must be less than or equal to the maximum push constant * size defined by the device and 4-byte aligned. * - `push_offset` specifies the offset in bytes from the start of the push constant root parameter to set the data to. - * It @wis_must be less than the maximum push constant size defined by the device and 4-byte aligned. \endcond + * It @wis_must be less than the maximum push constant size defined by the device and 4-byte aligned. + * \endcond * * @section WisPushConstantDataDesc_descr Description *
diff --git a/docs/wisdom/struct/rasterizer_desc_struct.h b/docs/wisdom/struct/rasterizer_desc_struct.h index 54aa2485a..10a1abb71 100644 --- a/docs/wisdom/struct/rasterizer_desc_struct.h +++ b/docs/wisdom/struct/rasterizer_desc_struct.h @@ -58,7 +58,8 @@ * - `depth_clip_enable` specifies depth clip enable. Default is true. * - `line_rasterization` specifies line rasterization mode. Default is `WisLineRasterizationDefault`. * - `conservative_rasterization` indicates conservative rasterization mode. Default is - * `WisConservativeRasterizationOff`. \endcond + * `WisConservativeRasterizationOff`. + * \endcond * * @section WisRasterizerDesc_descr Description *
diff --git a/docs/wisdom/struct/render_attachments_desc_struct.h b/docs/wisdom/struct/render_attachments_desc_struct.h index 589576b9f..23ec76c20 100644 --- a/docs/wisdom/struct/render_attachments_desc_struct.h +++ b/docs/wisdom/struct/render_attachments_desc_struct.h @@ -39,7 +39,8 @@ * - `attachments_count` defines attachment formats count. Max is 8. * - `depth_attachment` describes depth attachment format. Describes the format of the depth buffer. * - `view_mask` specifies view mask for multiview rendering. Each bit represents a view that can be rendered to with - * the pipeline. Default is 0, meaning no multiview support. \endcond + * the pipeline. Default is 0, meaning no multiview support. + * \endcond * * @section WisRenderAttachmentsDesc_descr Description *
diff --git a/docs/wisdom/struct/render_pass_desc_struct.h b/docs/wisdom/struct/render_pass_desc_struct.h index 7e02bcf2b..2b12085d7 100644 --- a/docs/wisdom/struct/render_pass_desc_struct.h +++ b/docs/wisdom/struct/render_pass_desc_struct.h @@ -43,7 +43,8 @@ * - `view_mask` specifies view mask for multiview rendering. Each bit represents a view that can be rendered to with * the render pass. Default is 0, meaning no multiview support. * - `depth_stencil` specifies depth stencil description; if depth stencil is not used, the target field @wis_must be - * set to 0. \endcond + * set to 0. + * \endcond * * @section WisRenderPassDesc_descr Description *
diff --git a/docs/wisdom/struct/root_signature_desc_struct.h b/docs/wisdom/struct/root_signature_desc_struct.h index 865002b06..462840076 100644 --- a/docs/wisdom/struct/root_signature_desc_struct.h +++ b/docs/wisdom/struct/root_signature_desc_struct.h @@ -44,7 +44,8 @@ * `WisRootSignatureDesc::push_descriptors` array. * - `descriptor_tables` points to an array of WisDescriptorTable. * - `descriptor_table_count` specifies the number of the number of descriptor tables in the - * `WisRootSignatureDesc::descriptor_tables` array. \endcond + * `WisRootSignatureDesc::descriptor_tables` array. + * \endcond * * @section WisRootSignatureDesc_descr Description *
diff --git a/docs/wisdom/struct/subresource_range_struct.h b/docs/wisdom/struct/subresource_range_struct.h index 71ab9a57d..43ce2dbe3 100644 --- a/docs/wisdom/struct/subresource_range_struct.h +++ b/docs/wisdom/struct/subresource_range_struct.h @@ -46,7 +46,8 @@ * of depth slices. * - `plane_slice` indicates base depth slice of the subresource. Used only for 2D textures (YUV). * - `plane_slice_count` indicates number of depth slices in the subresource. Used only for 2D textures (YUV). Max value - * is 3. \endcond + * is 3. + * \endcond * * @section WisSubresourceRange_descr Description *
diff --git a/docs/wisdom/struct/surface_parameters_struct.h b/docs/wisdom/struct/surface_parameters_struct.h index e8b0d425d..a7541441d 100644 --- a/docs/wisdom/struct/surface_parameters_struct.h +++ b/docs/wisdom/struct/surface_parameters_struct.h @@ -43,7 +43,8 @@ * different alpha mode. Used to determine the supported alpha modes for the swapchain. * - `texture_usage_flags_supported` specifies bitmask of supported texture usage flags for the swapchain images. * - `stereo_supported` indicates if stereo rendering is supported. If true, the surface can be used to create a - * swapchain with stereo support. \endcond + * swapchain with stereo support. + * \endcond * * @section WisSurfaceParameters_descr Description *
diff --git a/docs/wisdom/struct/swapchain_desc_struct.h b/docs/wisdom/struct/swapchain_desc_struct.h index e52e7067b..ca9141955 100644 --- a/docs/wisdom/struct/swapchain_desc_struct.h +++ b/docs/wisdom/struct/swapchain_desc_struct.h @@ -52,7 +52,8 @@ * - `scaling` describes swapchain scaling mode. * - `flags` describes swapchain flags. Describe additional options for the swapchain. * - `composite_alpha` defines composite alpha mode. Describe how the alpha channel of the swapchain images is treated - * during compositing. \endcond + * during compositing. + * \endcond * * @section WisSwapchainDesc_descr Description *
diff --git a/docs/wisdom/struct/swapchain_update_desc_struct.h b/docs/wisdom/struct/swapchain_update_desc_struct.h index cba0dd45d..c030504b2 100644 --- a/docs/wisdom/struct/swapchain_update_desc_struct.h +++ b/docs/wisdom/struct/swapchain_update_desc_struct.h @@ -42,7 +42,8 @@ * - `image_count` indicates number of images in the swapchain. * - `format` describes swapchain image format. * - `vsync` indicates controls vsync; when true, presentation is synchronized to the vertical blanking interval to - * reduce tearing, whereas false can improve frame rate but can introduce tearing. \endcond + * reduce tearing, whereas false can improve frame rate but can introduce tearing. + * \endcond * * @section WisSwapchainUpdateDesc_descr Description *
diff --git a/docs/wisdom/struct/texture_barrier_struct.h b/docs/wisdom/struct/texture_barrier_struct.h index 07ec81949..e25dadab0 100644 --- a/docs/wisdom/struct/texture_barrier_struct.h +++ b/docs/wisdom/struct/texture_barrier_struct.h @@ -131,7 +131,8 @@ * - `queue_type_before` defines type of the queue the barrier is executed on before the synchronization point. Used for * cross-queue barriers. * - `queue_type_after` indicates type of the queue the barrier is executed on after the synchronization point. Used for - * cross-queue barriers. \endcond + * cross-queue barriers. + * \endcond * * @section WisTextureBarrier_descr Description *
diff --git a/examples/backend/sdl_backend_c.c b/examples/backend/sdl_backend_c.c index 451e673ff..fe878967e 100644 --- a/examples/backend/sdl_backend_c.c +++ b/examples/backend/sdl_backend_c.c @@ -52,8 +52,8 @@ WisSurface CreateSurface(const SDLPlatform* platform, SDL_Window* window) #if defined(SDL_PLATFORM_WIN32) case SDL_PLATFORM_EXTENSION_WIN32: { WisWin32Extension* win32_extension = (WisWin32Extension*)platform->platform_extension; - HWND hwnd = (HWND - )SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL); + HWND hwnd = (HWND) + SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL); if (hwnd) { WisWin32WindowDesc desc = { .hinstance = GetModuleHandle(NULL), @@ -69,8 +69,8 @@ WisSurface CreateSurface(const SDLPlatform* platform, SDL_Window* window) case SDL_PLATFORM_EXTENSION_X11: { void* xdisplay = (void*) SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_X11_DISPLAY_POINTER, NULL); - uint64_t xwindow = (uint64_t - )SDL_GetNumberProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0); + uint64_t xwindow = (uint64_t) + SDL_GetNumberProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0); if (xdisplay && xwindow) { WisXlibWindowDesc desc = { .display = xdisplay, diff --git a/examples/compute_particles_c/entry_main.c b/examples/compute_particles_c/entry_main.c index e2f7e8cb3..e59925581 100644 --- a/examples/compute_particles_c/entry_main.c +++ b/examples/compute_particles_c/entry_main.c @@ -1014,14 +1014,15 @@ void Render(BasicRenderer* renderer, const ResourceContainer* resources, const B .store_op = WisStoreOpStore, .clear_value = {0.5f, 1.0f, 1.0f, 1.0f}}}, .render_target_count = 1, - .depth_stencil = - {.target = wisViewHeapGetViewAddress(&renderer->dsv_heap, renderer->frame_index), - .load_op_depth = WisLoadOpClear, - .load_op_stencil = WisLoadOpDontCare, - .store_op_depth = WisStoreOpStore, - .store_op_stencil = WisStoreOpDontCare, - .flags = WisDepthStencilFlagsIgnoreStencil, - .clear_depth = 1.0f}, + .depth_stencil = { + .target = wisViewHeapGetViewAddress(&renderer->dsv_heap, renderer->frame_index), + .load_op_depth = WisLoadOpClear, + .load_op_stencil = WisLoadOpDontCare, + .store_op_depth = WisStoreOpStore, + .store_op_stencil = WisStoreOpDontCare, + .flags = WisDepthStencilFlagsIgnoreStencil, + .clear_depth = 1.0f + }, }; result = wisCommandListBegin(&frame->command_list); diff --git a/generator/bitmask.cpp b/generator/bitmask.cpp index be375c20b..2692c5cac 100644 --- a/generator/bitmask.cpp +++ b/generator/bitmask.cpp @@ -307,6 +307,8 @@ void Generator::WriteBitmaskDocumentation(std::filesystem::path enum_output_path std::filesystem::path enum_file_path = enum_output_path / std::format("{}_enum.h", MakeSnakeCase(enum_name)); auto& enum_ref = bitmask_map[enum_name]; + files.push_back(enum_file_path); + std::string enum_template_content = std::format( " * C version:\n```c\n{}```\n" "C++ version:\n```cpp\nnamespace wis{{\n{}}}\n```\n", diff --git a/generator/constant.cpp b/generator/constant.cpp index 81877478a..7ea110eea 100644 --- a/generator/constant.cpp +++ b/generator/constant.cpp @@ -126,6 +126,7 @@ void Generator::WriteConstantDocumentation(std::filesystem::path const_output_pa { std::filesystem::create_directories(const_output_path); std::filesystem::path const_file_path = const_output_path / "constants.h"; + files.push_back(const_file_path); std::string all_c_code; std::string all_cpp_code; diff --git a/generator/entry_main.cpp b/generator/entry_main.cpp index 8a3a73f67..5e0c425b5 100644 --- a/generator/entry_main.cpp +++ b/generator/entry_main.cpp @@ -10,19 +10,25 @@ void FormatFiles(std::span files) if (clang_format_exe.empty()) { return; } - std::string cmd; - for (auto f : files) { - cmd += f.string(); - cmd += ' '; - } - std::cout << "Wisdom Vk Utils: Formatting:\n" << cmd << '\n'; - std::string command = std::format("\"{}\" -i --style=file {}", clang_format_exe, cmd); - int ret = 0; - for (uint32_t i = 0; (ret = std::system(command.c_str())) != 0 && i < repeats; ++i) - ; - if (ret != 0) { - std::cout << "Wisdom Vk Utils: failed to format files with error <" << ret << ">\n"; + // break into chunks of 16 files to avoid command line length limits on some platforms + for (size_t i = 0; i < files.size(); i += 16) { + auto chunk_end = std::min(16ull, files.size() - i); + + std::string cmd; + for (auto f : files.subspan(i, chunk_end)) { + cmd += f.string(); + cmd += ' '; + } + std::cout << "Wisdom Vk Utils: Formatting:\n" << cmd << '\n'; + std::string command = std::format("\"{}\" -i --style=file {}", clang_format_exe, cmd); + + int ret = 0; + for (uint32_t i = 0; (ret = std::system(command.c_str())) != 0 && i < repeats; ++i) + ; + if (ret != 0) { + std::cout << "Wisdom Vk Utils: failed to format files with error <" << ret << ">\n"; + } } } diff --git a/generator/enum.cpp b/generator/enum.cpp index 91b42e5da..44ed3abdb 100644 --- a/generator/enum.cpp +++ b/generator/enum.cpp @@ -142,6 +142,8 @@ void Generator::WriteEnumDocumentation(std::filesystem::path enum_output_path) std::filesystem::path enum_file_path = enum_output_path / std::format("{}_enum.h", MakeSnakeCase(enum_name)); auto& enum_ref = enum_map[enum_name]; + files.push_back(enum_file_path); + std::string enum_template_content = std::format( " * C version:\n```c\n{}```\n" "C++ version:\n```cpp\nnamespace wis{{\n{}}}\n```\n", diff --git a/generator/function.cpp b/generator/function.cpp index 9b68e89b3..236204eb2 100644 --- a/generator/function.cpp +++ b/generator/function.cpp @@ -718,6 +718,8 @@ void Generator::WriteFunctionDocumentation(std::filesystem::path func_output_pat ); auto func_doc_path = func_output_path / std::format("{}_function.h", MakeSnakeCase(full_func_name.substr(3))); + files.push_back(func_doc_path); + auto supports_vk = has(func_def.backend, Backend::Vulkan); auto supports_dx = has(func_def.backend, Backend::DX12); @@ -777,6 +779,7 @@ void Generator::WriteDelegateDocumentation(std::filesystem::path func_output_pat auto delegate_doc_path = func_output_path / std::format("{}_delegate.h", MakeSnakeCase(full_delegate_name.substr(3))); auto& delegate_def = delegate_map[delegate_name]; + files.push_back(delegate_doc_path); std::string regular_code = MakeCDelegate(delegate_def, DocKind::VersionOnly); std::string regular_code_cpp = MakeCPPDelegate(delegate_def, DocKind::VersionOnly); diff --git a/generator/handle.cpp b/generator/handle.cpp index b3ce360e0..337050a28 100644 --- a/generator/handle.cpp +++ b/generator/handle.cpp @@ -291,6 +291,7 @@ void Generator::WriteHandleDocumentation(std::filesystem::path handle_output_pat std::filesystem::path handle_file_path = handle_output_path / std::format("{}_handle.h", MakeSnakeCase(handle_name)); auto& handle_ref = handle_map[handle_name]; + files.push_back(handle_file_path); std::string vk_code; std::string dx_code; diff --git a/generator/struct.cpp b/generator/struct.cpp index b81c22f49..d367e0d59 100644 --- a/generator/struct.cpp +++ b/generator/struct.cpp @@ -203,6 +203,7 @@ void Generator::WriteStructDocumentation(std::filesystem::path struct_output_pat std::filesystem::path struct_file_path = struct_output_path / std::format("{}_struct.h", MakeSnakeCase(struct_name)); auto& struct_ref = struct_map[struct_name]; + files.push_back(struct_file_path); std::string struct_template_content = std::format( " * C version:\n```c\n{}```\n" diff --git a/generator/variant.cpp b/generator/variant.cpp index 37b49e552..2b7deb445 100644 --- a/generator/variant.cpp +++ b/generator/variant.cpp @@ -173,6 +173,7 @@ void Generator::WriteVariantDocumentation(std::filesystem::path struct_output_pa std::filesystem::path variant_file_path = struct_output_path / std::format("{}_struct.h", MakeSnakeCase(variant_name)); auto& variant_ref = variant_map[variant_name]; + files.push_back(variant_file_path); auto supports_vk = has(variant_ref.backend, Backend::Vulkan); auto supports_dx = has(variant_ref.backend, Backend::DX12); diff --git a/scripts/test-all.ps1 b/scripts/test-all.ps1 new file mode 100644 index 000000000..7f07796a0 --- /dev/null +++ b/scripts/test-all.ps1 @@ -0,0 +1,74 @@ +[CmdletBinding()] +param() + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +$scriptRoot = $PSScriptRoot + +$steps = @( + @{ Name = 'Build and package artifacts'; Script = Join-Path $scriptRoot 'package.ps1' }, + @{ Name = 'Build and run unit tests'; Script = Join-Path $scriptRoot 'test-unit.ps1' }, + @{ Name = 'Run ZIP (CMake) integration test'; Script = Join-Path $scriptRoot 'test-cmake.ps1' }, + @{ Name = 'Run NuGet integration test'; Script = Join-Path $scriptRoot 'test-nuget.ps1' } +) + +function Invoke-TestStep { + param( + [Parameter(Mandatory = $true)] + [int]$Index, + + [Parameter(Mandatory = $true)] + [int]$Total, + + [Parameter(Mandatory = $true)] + [hashtable]$Step + ) + + Write-Host ("[{0}/{1}] {2}" -f $Index, $Total, $Step.Name) -ForegroundColor Cyan + + if ($VerbosePreference -eq 'Continue') { + & $Step.Script + if ($LASTEXITCODE -ne 0) { + throw "Step failed with exit code ${LASTEXITCODE}: $($Step.Name)" + } + + Write-Host ' OK' -ForegroundColor Green + return + } + + $output = @(& $Step.Script *>&1) + $exitCode = $LASTEXITCODE + + if ($exitCode -ne 0) { + $messages = @( + $output | + ForEach-Object { $_.ToString() } | + Where-Object { $_ -match '(?i)error|failed|exception|fatal' } + ) + + Write-Host ' FAILED' -ForegroundColor Red + if ($messages.Count -gt 0) { + $messages | Select-Object -Unique | ForEach-Object { Write-Host " $_" -ForegroundColor Red } + } + else { + $output | + ForEach-Object { $_.ToString() } | + Select-Object -Last 10 | + ForEach-Object { Write-Host " $_" -ForegroundColor Red } + } + + throw "Step failed with exit code ${exitCode}: $($Step.Name). Re-run with -Verbose for full logs." + } + + Write-Host ' OK' -ForegroundColor Green +} + +Write-Host "Starting local validation..." -ForegroundColor Yellow +Write-Host "Use -Verbose to show full command output." -ForegroundColor DarkGray + +for ($i = 0; $i -lt $steps.Count; $i++) { + Invoke-TestStep -Index ($i + 1) -Total $steps.Count -Step $steps[$i] +} + +Write-Host "All steps completed successfully." -ForegroundColor Green diff --git a/scripts/test-unit.ps1 b/scripts/test-unit.ps1 new file mode 100644 index 000000000..8d6a969c5 --- /dev/null +++ b/scripts/test-unit.ps1 @@ -0,0 +1,108 @@ +[CmdletBinding()] +param() + +Set-StrictMode -Version Latest +$ErrorActionPreference = 'Stop' + +$workspaceRoot = (Resolve-Path (Join-Path $PSScriptRoot '..')).Path +$buildDir = Join-Path $workspaceRoot 'build/msvc-debug-tests' + +function Initialize-VSEnvironment { + Write-Host 'Initializing Visual Studio environment...' -ForegroundColor Cyan + + $vsWhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" + if (-not (Test-Path $vsWhere)) { + throw 'Visual Studio not found. Please install Visual Studio with C++ workload.' + } + + $vsPath = & $vsWhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath + if (-not $vsPath) { + throw 'Visual Studio with C++ tools not found.' + } + + $vcvarsPath = Join-Path $vsPath 'VC\Auxiliary\Build\vcvars64.bat' + if (-not (Test-Path $vcvarsPath)) { + throw "vcvars64.bat not found at: $vcvarsPath" + } + + $env:PATH = ($env:PATH -split ';' | Where-Object { $_ -notmatch 'Strawberry' }) -join ';' + + $envBlock = cmd /c "`"$vcvarsPath`" >nul 2>&1 && set" + foreach ($line in $envBlock) { + if ($line -match '^([^=]+)=(.*)$') { + [Environment]::SetEnvironmentVariable($matches[1], $matches[2], 'Process') + } + } +} + +function Invoke-ExternalCommand { + param( + [Parameter(Mandatory = $true)] + [string]$FilePath, + + [Parameter(Mandatory = $true)] + [string[]]$Arguments, + + [Parameter(Mandatory = $true)] + [string]$ActionName + ) + + if ($VerbosePreference -eq 'Continue') { + & $FilePath @Arguments + $exitCode = $LASTEXITCODE + if ($exitCode -ne 0) { + throw "$ActionName failed with exit code $exitCode" + } + + return + } + + $output = @(& $FilePath @Arguments *>&1) + $exitCode = $LASTEXITCODE + + if ($exitCode -ne 0) { + $messages = @( + $output | + ForEach-Object { $_.ToString() } | + Where-Object { $_ -match '(?i)error|failed|exception|fatal' } + ) + + if ($messages.Count -gt 0) { + $messages | Select-Object -Unique | ForEach-Object { Write-Host " $_" -ForegroundColor Red } + } + else { + $output | + ForEach-Object { $_.ToString() } | + Select-Object -Last 10 | + ForEach-Object { Write-Host " $_" -ForegroundColor Red } + } + + throw "$ActionName failed with exit code $exitCode. Re-run with -Verbose for full logs." + } +} + +Write-Host 'Starting unit tests...' -ForegroundColor Yellow +Write-Host 'Use -Verbose to show full command output.' -ForegroundColor DarkGray + +Initialize-VSEnvironment + +Write-Host '[1/3] Configure unit test build' -ForegroundColor Cyan +Invoke-ExternalCommand -FilePath 'cmake' -Arguments @( + '-S', $workspaceRoot, + '-B', $buildDir, + '-G', 'Ninja', + '-DCMAKE_BUILD_TYPE=Debug', + '-DWISDOM_BUILD_TESTS=ON', + '-DWISDOM_BUILD_EXAMPLES=OFF' +) -ActionName 'CMake configure' +Write-Host ' OK' -ForegroundColor Green + +Write-Host '[2/3] Build unit tests' -ForegroundColor Cyan +Invoke-ExternalCommand -FilePath 'cmake' -Arguments @('--build', $buildDir) -ActionName 'CMake build' +Write-Host ' OK' -ForegroundColor Green + +Write-Host '[3/3] Run unit tests' -ForegroundColor Cyan +Invoke-ExternalCommand -FilePath 'ctest' -Arguments @('--test-dir', $buildDir, '--output-on-failure') -ActionName 'CTest run' +Write-Host ' OK' -ForegroundColor Green + +Write-Host 'Unit tests completed successfully.' -ForegroundColor Green diff --git a/src/include/wisdom/bridge/span.hpp b/src/include/wisdom/bridge/span.hpp index 12771f1dc..71587b128 100644 --- a/src/include/wisdom/bridge/span.hpp +++ b/src/include/wisdom/bridge/span.hpp @@ -76,7 +76,8 @@ struct contract_violation_error : std::logic_error { inline void contract_violation(const char* msg) { throw contract_violation_error(msg); } #elif defined(TCB_SPAN_TERMINATE_ON_CONTRACT_VIOLATION) -[[noreturn]] inline void contract_violation(const char* /*unused*/ +[[noreturn]] inline void contract_violation( + const char* /*unused*/ ) { std::terminate(); @@ -446,8 +447,10 @@ class span return {data() + (size() - count), count}; } - TCB_SPAN_CONSTEXPR11 span subspan(size_type offset, size_type count = dynamic_extent) - const + TCB_SPAN_CONSTEXPR11 span subspan( + size_type offset, + size_type count = dynamic_extent + ) const { TCB_SPAN_EXPECT(offset <= size() && (count == dynamic_extent || offset + count <= size())); return {data() + offset, count == dynamic_extent ? size() - offset : count}; diff --git a/src/include/wisdom/dx12/dx12_adapter_query.cpp b/src/include/wisdom/dx12/dx12_adapter_query.cpp index 7af53a063..c3724275e 100644 --- a/src/include/wisdom/dx12/dx12_adapter_query.cpp +++ b/src/include/wisdom/dx12/dx12_adapter_query.cpp @@ -39,8 +39,11 @@ WIS_EXTERN_C WISDOM_API size_t wisDX12AdapterQueryGetAdapterCount(const WisDX12A } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisDX12AdapterQueryGetAdapterDesc(const WisDX12AdapterQuery* self, size_t index, WisAdapterDesc* desc) +WIS_EXTERN_C WISDOM_API WisResult wisDX12AdapterQueryGetAdapterDesc( + const WisDX12AdapterQuery* self, + size_t index, + WisAdapterDesc* desc +) { WisResult res = wis::detail::dx_success; auto& impl = wis::from_handle_ref(self); diff --git a/src/include/wisdom/dx12/dx12_command_allocator.cpp b/src/include/wisdom/dx12/dx12_command_allocator.cpp index d147a7859..1651629f8 100644 --- a/src/include/wisdom/dx12/dx12_command_allocator.cpp +++ b/src/include/wisdom/dx12/dx12_command_allocator.cpp @@ -30,8 +30,10 @@ WIS_EXTERN_C WISDOM_API WisResult wisDX12CommandAllocatorReset(const WisDX12Comm } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisDX12CommandAllocatorCreateCommandList(const WisDX12CommandAllocator* self, WisDX12CommandList* list) +WIS_EXTERN_C WISDOM_API WisResult wisDX12CommandAllocatorCreateCommandList( + const WisDX12CommandAllocator* self, + WisDX12CommandList* list +) { auto& [allocator, device, type] = wis::from_handle_ref(self); diff --git a/src/include/wisdom/dx12/dx12_command_list.cpp b/src/include/wisdom/dx12/dx12_command_list.cpp index 20838baf3..e687551e9 100644 --- a/src/include/wisdom/dx12/dx12_command_list.cpp +++ b/src/include/wisdom/dx12/dx12_command_list.cpp @@ -616,11 +616,10 @@ WIS_EXTERN_C WISDOM_API void wisDX12CommandListBeginRenderPass( { .Type = wis::detail::DX12Convert(src.load_op), }, - .EndingAccess = - { - .Type = src.resolve_desc ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_RESOLVE - : wis::detail::DX12Convert(src.store_op), - }, + .EndingAccess = { + .Type = src.resolve_desc ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_RESOLVE + : wis::detail::DX12Convert(src.store_op), + }, }; if (src.load_op == WisLoadOpClear) { render_targets[i].BeginningAccess.Clear.ClearValue = { @@ -647,7 +646,8 @@ WIS_EXTERN_C WISDOM_API void wisDX12CommandListBeginRenderPass( // Encode the other parameters .pSubresourceParameters = static_cast< - const D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_SUBRESOURCE_PARAMETERS*>(static_cast(dst) + const D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_SUBRESOURCE_PARAMETERS*>( + static_cast(dst) ), .Format = static_cast(dst->format), .ResolveMode = wis::detail::DX12Convert(resolve.mode), @@ -689,12 +689,11 @@ WIS_EXTERN_C WISDOM_API void wisDX12CommandListBeginRenderPass( : src.resolve_depth_desc ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_RESOLVE : wis::detail::DX12Convert(src.store_op_depth), }, - .StencilEndingAccess = - { - .Type = ignore_stencil ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS - : src.resolve_stencil_desc ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_RESOLVE - : wis::detail::DX12Convert(src.store_op_stencil), - }, + .StencilEndingAccess = { + .Type = ignore_stencil ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_NO_ACCESS + : src.resolve_stencil_desc ? D3D12_RENDER_PASS_ENDING_ACCESS_TYPE_RESOLVE + : wis::detail::DX12Convert(src.store_op_stencil), + }, }; if (src.resolve_depth_desc) { @@ -716,7 +715,8 @@ WIS_EXTERN_C WISDOM_API void wisDX12CommandListBeginRenderPass( // Encode the other parameters .pSubresourceParameters = static_cast< - const D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_SUBRESOURCE_PARAMETERS*>(static_cast(dst) + const D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_SUBRESOURCE_PARAMETERS*>( + static_cast(dst) ), .Format = static_cast(dst->format), .ResolveMode = wis::detail::DX12Convert(resolve.mode), @@ -742,7 +742,8 @@ WIS_EXTERN_C WISDOM_API void wisDX12CommandListBeginRenderPass( .SubresourceCount = layer_count, // Encode the other parameters .pSubresourceParameters = static_cast< - const D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_SUBRESOURCE_PARAMETERS*>(static_cast(dst) + const D3D12_RENDER_PASS_ENDING_ACCESS_RESOLVE_SUBRESOURCE_PARAMETERS*>( + static_cast(dst) ), .Format = static_cast(dst->format), .ResolveMode = wis::detail::DX12Convert(resolve.mode), @@ -766,7 +767,8 @@ WIS_EXTERN_C WISDOM_API void wisDX12CommandListBeginRenderPass( auto& dst = render_targets[i].EndingAccess.Resolve; auto* src_aux = wis::detail::DX12DecodeViewAddress(src.target); - auto* dst_aux = reinterpret_cast(dst.pSubresourceParameters + auto* dst_aux = reinterpret_cast( + dst.pSubresourceParameters ); wis::span subresource_params{ @@ -778,13 +780,12 @@ WIS_EXTERN_C WISDOM_API void wisDX12CommandListBeginRenderPass( subresource_params[j] = { .SrcSubresource = src_aux->base_subresource + j * src_aux->subresource_stride, .DstSubresource = dst_aux->base_subresource + j * dst_aux->subresource_stride, - .SrcRect = - { - .left = 0, - .top = 0, - .right = static_cast(width), - .bottom = static_cast(height), - }, + .SrcRect = { + .left = 0, + .top = 0, + .right = static_cast(width), + .bottom = static_cast(height), + }, }; } dst.pSubresourceParameters = subresource_params.data(); @@ -817,13 +818,12 @@ WIS_EXTERN_C WISDOM_API void wisDX12CommandListBeginRenderPass( .SrcSubresource = aux->base_subresource + j * aux->subresource_stride, .DstSubresource = (dst_depth_aux ? dst_depth_aux->base_subresource : 0) + j * (dst_depth_aux ? dst_depth_aux->subresource_stride : 0), - .SrcRect = - { - .left = 0, - .top = 0, - .right = static_cast(width), - .bottom = static_cast(height), - }, + .SrcRect = { + .left = 0, + .top = 0, + .right = static_cast(width), + .bottom = static_cast(height), + }, }; } depth_stencil.DepthEndingAccess.Resolve.pSubresourceParameters = subresource_params.data(); @@ -850,13 +850,12 @@ WIS_EXTERN_C WISDOM_API void wisDX12CommandListBeginRenderPass( .SrcSubresource = aux->base_stencil_subresource + j * aux->subresource_stride, .DstSubresource = (dst_stencil_aux ? dst_stencil_aux->base_stencil_subresource : 0) + j * (dst_stencil_aux ? dst_stencil_aux->subresource_stride : 0), - .SrcRect = - { - .left = 0, - .top = 0, - .right = static_cast(width), - .bottom = static_cast(height), - }, + .SrcRect = { + .left = 0, + .top = 0, + .right = static_cast(width), + .bottom = static_cast(height), + }, }; } depth_stencil.StencilEndingAccess.Resolve.pSubresourceParameters = subresource_params.data(); diff --git a/src/include/wisdom/dx12/dx12_command_queue.cpp b/src/include/wisdom/dx12/dx12_command_queue.cpp index b5f7d6876..d8912c6eb 100644 --- a/src/include/wisdom/dx12/dx12_command_queue.cpp +++ b/src/include/wisdom/dx12/dx12_command_queue.cpp @@ -20,8 +20,11 @@ WIS_EXTERN_C WISDOM_API void wisDX12DestroyCommandQueue(WisDX12CommandQueue* sel } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisDX12CommandQueueSubmit(const WisDX12CommandQueue* self, const WisDX12CommandListView* lists, size_t count) +WIS_EXTERN_C WISDOM_API WisResult wisDX12CommandQueueSubmit( + const WisDX12CommandQueue* self, + const WisDX12CommandListView* lists, + size_t count +) { auto& [queue] = wis::from_handle_ref(self); queue->ExecuteCommandLists(static_cast(count), reinterpret_cast(lists)); @@ -29,8 +32,11 @@ wisDX12CommandQueueSubmit(const WisDX12CommandQueue* self, const WisDX12CommandL } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisDX12CommandQueueSignalFence(const WisDX12CommandQueue* self, WisDX12FenceView fence, uint64_t value) +WIS_EXTERN_C WISDOM_API WisResult wisDX12CommandQueueSignalFence( + const WisDX12CommandQueue* self, + WisDX12FenceView fence, + uint64_t value +) { auto& [queue] = wis::from_handle_ref(self); auto hr = queue->Signal(std::bit_cast(fence), value); @@ -42,8 +48,11 @@ wisDX12CommandQueueSignalFence(const WisDX12CommandQueue* self, WisDX12FenceView } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisDX12CommandQueueWaitFence(const WisDX12CommandQueue* self, WisDX12FenceView fence, uint64_t value) +WIS_EXTERN_C WISDOM_API WisResult wisDX12CommandQueueWaitFence( + const WisDX12CommandQueue* self, + WisDX12FenceView fence, + uint64_t value +) { auto& [queue] = wis::from_handle_ref(self); auto hr = queue->Wait(std::bit_cast(fence), value); diff --git a/src/include/wisdom/dx12/dx12_descriptor_heap.cpp b/src/include/wisdom/dx12/dx12_descriptor_heap.cpp index 14870eaae..362ae7b17 100644 --- a/src/include/wisdom/dx12/dx12_descriptor_heap.cpp +++ b/src/include/wisdom/dx12/dx12_descriptor_heap.cpp @@ -304,13 +304,12 @@ WIS_EXTERN_C WISDOM_API WisResult wisDX12DescriptorHeapWriteStructuredBuffer( .Format = DXGI_FORMAT_UNKNOWN, // must be UNKNOWN for structured buffers .ViewDimension = D3D12_SRV_DIMENSION_BUFFER, .Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, - .Buffer = - { - .FirstElement = data->array_offset, - .NumElements = data->structure_count, - .StructureByteStride = data->stride_bytes, - .Flags = D3D12_BUFFER_SRV_FLAG_NONE, - }, + .Buffer = { + .FirstElement = data->array_offset, + .NumElements = data->structure_count, + .StructureByteStride = data->stride_bytes, + .Flags = D3D12_BUFFER_SRV_FLAG_NONE, + }, }; heap.device->CreateShaderResourceView( resource, @@ -334,13 +333,12 @@ WIS_EXTERN_C WISDOM_API WisResult wisDX12DescriptorHeapWriteRWStructuredBuffer( D3D12_UNORDERED_ACCESS_VIEW_DESC uav_desc{ .Format = DXGI_FORMAT_UNKNOWN, // must be UNKNOWN for structured buffers .ViewDimension = D3D12_UAV_DIMENSION_BUFFER, - .Buffer = - { - .FirstElement = data->array_offset, - .NumElements = data->structure_count, - .StructureByteStride = data->stride_bytes, - .Flags = D3D12_BUFFER_UAV_FLAG_NONE, - }, + .Buffer = { + .FirstElement = data->array_offset, + .NumElements = data->structure_count, + .StructureByteStride = data->stride_bytes, + .Flags = D3D12_BUFFER_UAV_FLAG_NONE, + }, }; heap.device->CreateUnorderedAccessView( resource, @@ -352,8 +350,11 @@ WIS_EXTERN_C WISDOM_API WisResult wisDX12DescriptorHeapWriteRWStructuredBuffer( } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisDX12DescriptorHeapWriteSampler(const WisDX12DescriptorHeap* self, const WisSamplerDesc* sampler, uint32_t index) +WIS_EXTERN_C WISDOM_API WisResult wisDX12DescriptorHeapWriteSampler( + const WisDX12DescriptorHeap* self, + const WisSamplerDesc* sampler, + uint32_t index +) { auto& heap = wis::from_handle_ref(self); @@ -439,8 +440,11 @@ WIS_EXTERN_C WISDOM_API WisResult wisDX12DescriptorHeapWriteRWTexture( } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisDX12DescriptorHeapWriteAccelerationStructure(const WisDX12DescriptorHeap* self, uint64_t address, uint32_t index) +WIS_EXTERN_C WISDOM_API WisResult wisDX12DescriptorHeapWriteAccelerationStructure( + const WisDX12DescriptorHeap* self, + uint64_t address, + uint32_t index +) { auto& heap = wis::from_handle_ref(self); D3D12_SHADER_RESOURCE_VIEW_DESC desc{ diff --git a/src/include/wisdom/dx12/dx12_device.cpp b/src/include/wisdom/dx12/dx12_device.cpp index d12395ad0..14cc46e79 100644 --- a/src/include/wisdom/dx12/dx12_device.cpp +++ b/src/include/wisdom/dx12/dx12_device.cpp @@ -485,9 +485,14 @@ WIS_EXTERN_C WISDOM_API void wisDX12DeviceQueryProperties(const WisDX12Device* s if (wis::detail::succeeded( device.device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS16, &options16, sizeof(options16)) )) { + + D3D12MA::Budget local_budget = {}; + D3D12MA::Budget non_local_budget = {}; + device.allocator->GetBudget(&local_budget, &non_local_budget); + props->gpu_upload_supported = options16.GPUUploadHeapSupported; props->host_image_copy_supported = options16.GPUUploadHeapSupported; - props->supported_initial_transitions = 0b0001'1111'1111'1111; // All thansitions are supported + props->gpu_upload_heap_budget = options16.GPUUploadHeapSupported ? local_budget.BudgetBytes : 0ull; } } break; case WisQueryPropertyTypeDeviceBindingProperties: { diff --git a/src/include/wisdom/dx12/dx12_impl.cpp b/src/include/wisdom/dx12/dx12_impl.cpp index dc1d68c6e..43b6cfeca 100644 --- a/src/include/wisdom/dx12/dx12_impl.cpp +++ b/src/include/wisdom/dx12/dx12_impl.cpp @@ -7,9 +7,9 @@ #include #ifdef DX12SDKVER -#include +# include #else -#include +# include #endif //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/include/wisdom/dx12/dx12_instance.cpp b/src/include/wisdom/dx12/dx12_instance.cpp index 1e2df1bda..8b456940a 100644 --- a/src/include/wisdom/dx12/dx12_instance.cpp +++ b/src/include/wisdom/dx12/dx12_instance.cpp @@ -80,8 +80,11 @@ WIS_EXTERN_C WISDOM_API void wisDX12DestroyInstance(WisDX12Instance* self) } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisDX12InstanceQueryAdapters(const WisDX12Instance* self, WisAdapterPreference preference, WisDX12AdapterQuery* query) +WIS_EXTERN_C WISDOM_API WisResult wisDX12InstanceQueryAdapters( + const WisDX12Instance* self, + WisAdapterPreference preference, + WisDX12AdapterQuery* query +) { const auto& instance_impl = wis::from_handle_ref(self); wis::com_ptr factory_ref{instance_impl.factory}; // hold a reference diff --git a/src/include/wisdom/dx12/dx12_pipeline_cache.cpp b/src/include/wisdom/dx12/dx12_pipeline_cache.cpp index 06abe6c55..2ceab33ed 100644 --- a/src/include/wisdom/dx12/dx12_pipeline_cache.cpp +++ b/src/include/wisdom/dx12/dx12_pipeline_cache.cpp @@ -20,8 +20,11 @@ WIS_EXTERN_C WISDOM_API void wisDX12DestroyPipelineCache(WisDX12PipelineCache* s } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisDX12PipelineCacheSerialize(const WisDX12PipelineCache* self, uint8_t* data, size_t data_size) +WIS_EXTERN_C WISDOM_API WisResult wisDX12PipelineCacheSerialize( + const WisDX12PipelineCache* self, + uint8_t* data, + size_t data_size +) { auto& [cache, xx] = wis::from_handle_ref(self); auto hr = cache->Serialize(data, data_size); diff --git a/src/include/wisdom/dx12/dx12_swapchain.cpp b/src/include/wisdom/dx12/dx12_swapchain.cpp index 4fdd87cc3..b865487d1 100644 --- a/src/include/wisdom/dx12/dx12_swapchain.cpp +++ b/src/include/wisdom/dx12/dx12_swapchain.cpp @@ -16,8 +16,12 @@ WIS_EXTERN_C WISDOM_API void wisDX12DestroySwapchain(WisDX12Swapchain* self) } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisDX12SwapchainPresent(const WisDX12Swapchain* self, WisPresentFlags flags, const WisRect* rects, size_t rect_count) +WIS_EXTERN_C WISDOM_API WisResult wisDX12SwapchainPresent( + const WisDX12Swapchain* self, + WisPresentFlags flags, + const WisRect* rects, + size_t rect_count +) { auto& swapchain = wis::from_handle_ref(self); UINT dx_flags = swapchain.vsync ? 0 : swapchain.flags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; @@ -64,8 +68,10 @@ WIS_EXTERN_C WISDOM_API WisResult wisDX12SwapchainGetCurrentIndex(const WisDX12S } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisDX12SwapchainUpdate(const WisDX12Swapchain* self, const WisSwapchainUpdateDesc* desc) +WIS_EXTERN_C WISDOM_API WisResult wisDX12SwapchainUpdate( + const WisDX12Swapchain* self, + const WisSwapchainUpdateDesc* desc +) { auto& swapchain = wis::from_handle_ref(self); @@ -98,8 +104,11 @@ wisDX12SwapchainUpdate(const WisDX12Swapchain* self, const WisSwapchainUpdateDes } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisDX12SwapchainGetTextures(const WisDX12Swapchain* self, WisDX12Texture* buffers, size_t buffer_count) +WIS_EXTERN_C WISDOM_API WisResult wisDX12SwapchainGetTextures( + const WisDX12Swapchain* self, + WisDX12Texture* buffers, + size_t buffer_count +) { auto& impl = wis::from_handle_ref(self); if (buffer_count < impl.backbuffer_count) { diff --git a/src/include/wisdom/dx12/dx12_types.hpp b/src/include/wisdom/dx12/dx12_types.hpp index fef3ff542..4e3739a7b 100644 --- a/src/include/wisdom/dx12/dx12_types.hpp +++ b/src/include/wisdom/dx12/dx12_types.hpp @@ -5,8 +5,8 @@ #endif // __cplusplus #include -#include #include +#include namespace wis { //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/include/wisdom/generated/c_api.h b/src/include/wisdom/generated/c_api.h index 252179e92..7dcf8312b 100644 --- a/src/include/wisdom/generated/c_api.h +++ b/src/include/wisdom/generated/c_api.h @@ -2514,11 +2514,10 @@ typedef struct WisDeviceMemoryProperties { * */ bool host_image_copy_supported; /** - * @brief defines bitfield of supported initial resource state transitions for buffers and textures. If a transition - * is supported, the corresponding bit is set to `1`, otherwise `0`. Bit positions are the same as in - * WisTextureState enum. `WisTextureStateUndefined` is always supported. + * @brief specifies heap budget for GPU upload memory type in bytes. This is an approximate value of how much memory + * of this type can be allocated, and it can change over time depending on the system state. * */ - uint32_t supported_initial_transitions; + uint64_t gpu_upload_heap_budget; } WisDeviceMemoryProperties; /** diff --git a/src/include/wisdom/generated/cpp_api.hpp b/src/include/wisdom/generated/cpp_api.hpp index bba2d4a48..1ab8bbd0d 100644 --- a/src/include/wisdom/generated/cpp_api.hpp +++ b/src/include/wisdom/generated/cpp_api.hpp @@ -2534,11 +2534,10 @@ struct DeviceMemoryProperties { * */ bool host_image_copy_supported; /** - * @brief defines bitfield of supported initial resource state transitions for buffers and textures. If a transition - * is supported, the corresponding bit is set to `1`, otherwise `0`. Bit positions are the same as in - * wis::TextureState enum. `wis::TextureState::Undefined` is always supported. + * @brief specifies heap budget for GPU upload memory type in bytes. This is an approximate value of how much memory + * of this type can be allocated, and it can change over time depending on the system state. * */ - std::uint32_t supported_initial_transitions; + std::uint64_t gpu_upload_heap_budget; }; /** diff --git a/src/include/wisdom/global/internal.hpp b/src/include/wisdom/global/internal.hpp index 8e5d47d6e..c1ac2ff2b 100644 --- a/src/include/wisdom/global/internal.hpp +++ b/src/include/wisdom/global/internal.hpp @@ -8,8 +8,7 @@ namespace wis { /// @brief Tag type for in-place construction (for C++11 and later) -struct in_place_t { -}; +struct in_place_t {}; /// @brief Constant for in-place construction (for C++11 and later) static constexpr in_place_t in_place{}; diff --git a/src/include/wisdom/vulkan/detail/vk_detail.hpp b/src/include/wisdom/vulkan/detail/vk_detail.hpp index 52472b846..157f26a1e 100644 --- a/src/include/wisdom/vulkan/detail/vk_detail.hpp +++ b/src/include/wisdom/vulkan/detail/vk_detail.hpp @@ -165,7 +165,7 @@ struct VKDeviceFeatures { uint16_t resource_desc_size = 0; uint16_t sampler_desc_size = 0; uint16_t max_root_space = 0; - uint16_t supported_image_layout_transitions = 0; // bitmask of supported image layout transitions, indexed by + // WisImageLayout. A bit value of 1 indicates support for the // transition. uint32_t descriptor_heap_reserved_size = 0; diff --git a/src/include/wisdom/vulkan/detail/vk_ext1.hpp b/src/include/wisdom/vulkan/detail/vk_ext1.hpp index 4c30590e6..1eb64ad5c 100644 --- a/src/include/wisdom/vulkan/detail/vk_ext1.hpp +++ b/src/include/wisdom/vulkan/detail/vk_ext1.hpp @@ -190,7 +190,8 @@ struct DeviceExtension1 : VKDeviceExtensionImpl { static_cast(descriptor_heap_properties.minSamplerHeapReservedRangeWithEmbedded), features.sampler_desc_size ); - features.descriptor_heap_alignment = static_cast(descriptor_heap_properties.resourceHeapAlignment + features.descriptor_heap_alignment = static_cast( + descriptor_heap_properties.resourceHeapAlignment ); features.sampler_heap_alignment = static_cast(descriptor_heap_properties.samplerHeapAlignment); features.max_descriptor_heap_size = descriptor_heap_properties.maxResourceHeapSize; @@ -207,46 +208,6 @@ struct DeviceExtension1 : VKDeviceExtensionImpl { features.max_vertex_bindings = static_cast(device_properties.properties.limits.maxVertexInputBindings); features.multiple_viewports = device_properties.properties.limits.maxViewports > 1 ? 1 : 0; - if (features.host_image_copy) { - // Host image copy support - auto& host_image_copy_properties = *collector.GetEnabledPropertyStruct< - VkPhysicalDeviceHostImageCopyPropertiesEXT>( - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_IMAGE_COPY_PROPERTIES_EXT - ); - - static constexpr std::size_t reasonable_layout_count = 32; - VkImageLayout dst_layouts[reasonable_layout_count]{}; - std::unique_ptr dynamic_dst_layouts; - wis::span dst_layout_span; - - if (host_image_copy_properties.copyDstLayoutCount > reasonable_layout_count) { - dynamic_dst_layouts = std::make_unique(host_image_copy_properties.copyDstLayoutCount); - dst_layout_span = wis::span{ - dynamic_dst_layouts.get(), - host_image_copy_properties.copyDstLayoutCount - }; - } else { - dst_layout_span = wis::span{dst_layouts, host_image_copy_properties.copyDstLayoutCount}; - } - - // We are not interested in src layouts. - host_image_copy_properties.pCopyDstLayouts = dst_layout_span.data(); - device_properties.pNext = &host_image_copy_properties; - - auto& atable = device_impl.device_header->header.shared_header->header.adapter_table; - auto adapter = device_impl.physical_device; - - atable.vkGetPhysicalDeviceProperties2(adapter, &device_properties); - - for (uint32_t i = 0; i < host_image_copy_properties.copyDstLayoutCount; ++i) { - WisTextureState dst_layout = VKConvertToTextureState(dst_layout_span[i]); - if (dst_layout == WisTextureStateUndefined) { - continue; // Unsupported layout, skip - } - features.supported_image_layout_transitions |= (1 << static_cast(dst_layout_span[i])); - } - } - // Nothing to initialize for now return wis::detail::vk_success; } diff --git a/src/include/wisdom/vulkan/vk_adapter_query.cpp b/src/include/wisdom/vulkan/vk_adapter_query.cpp index 829e96ef3..45c1877cd 100644 --- a/src/include/wisdom/vulkan/vk_adapter_query.cpp +++ b/src/include/wisdom/vulkan/vk_adapter_query.cpp @@ -132,15 +132,19 @@ inline std::array VKGetSortedQueueFamilies( // Scenario B: We found a shared G+C queue, but now we found a DISTINCT Compute queue. // Overwrite the previous choice! This is how you get Async Compute. - else if ((props_span[current].queueFamilyProperties.queueFlags & VK_QUEUE_GRAPHICS_BIT) - && !(flags & VK_QUEUE_GRAPHICS_BIT)) { + else if ( + (props_span[current].queueFamilyProperties.queueFlags & VK_QUEUE_GRAPHICS_BIT) + && !(flags & VK_QUEUE_GRAPHICS_BIT) + ) { qcom[WisCommandQueueTypeCompute] = i; } // Scenario C: We have found another G+C, but it is different from WisCommandQueueTypeGraphics (probably // impossible) - else if ((props_span[current].queueFamilyProperties.queueFlags & VK_QUEUE_GRAPHICS_BIT) - && qcom[WisCommandQueueTypeGraphics] != i) { + else if ( + (props_span[current].queueFamilyProperties.queueFlags & VK_QUEUE_GRAPHICS_BIT) + && qcom[WisCommandQueueTypeGraphics] != i + ) { qcom[WisCommandQueueTypeCompute] = i; } } @@ -458,8 +462,11 @@ WIS_EXTERN_C WISDOM_API size_t wisVKAdapterQueryGetAdapterCount(const WisVKAdapt } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisVKAdapterQueryGetAdapterDesc(const WisVKAdapterQuery* self, size_t index, WisAdapterDesc* desc) +WIS_EXTERN_C WISDOM_API WisResult wisVKAdapterQueryGetAdapterDesc( + const WisVKAdapterQuery* self, + size_t index, + WisAdapterDesc* desc +) { const auto& impl = *wis::from_handle(self); if (index >= impl.adapter_count) { @@ -700,7 +707,8 @@ WIS_EXTERN_C WISDOM_API WisResult wisVKAdapterQueryCreateDevice( } control_block_size += sizeof(std::binary_semaphore) * semaphore_count; - std::unique_ptr header_storage{static_cast(operator new(control_block_size, std::nothrow)) + std::unique_ptr header_storage{ + static_cast(operator new(control_block_size, std::nothrow)) }; if (!header_storage) { return wis::detail::make_result( diff --git a/src/include/wisdom/vulkan/vk_command_allocator.cpp b/src/include/wisdom/vulkan/vk_command_allocator.cpp index 593164f5a..bac742b32 100644 --- a/src/include/wisdom/vulkan/vk_command_allocator.cpp +++ b/src/include/wisdom/vulkan/vk_command_allocator.cpp @@ -35,8 +35,10 @@ WIS_EXTERN_C WISDOM_API WisResult wisVKCommandAllocatorReset(const WisVKCommandA } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisVKCommandAllocatorCreateCommandList(const WisVKCommandAllocator* self, WisVKCommandList* list) +WIS_EXTERN_C WISDOM_API WisResult wisVKCommandAllocatorCreateCommandList( + const WisVKCommandAllocator* self, + WisVKCommandList* list +) { auto& impl = wis::from_handle_ref(self); auto& header = impl.command_pool_header->header; diff --git a/src/include/wisdom/vulkan/vk_command_queue.cpp b/src/include/wisdom/vulkan/vk_command_queue.cpp index f071115e7..1e34aa161 100644 --- a/src/include/wisdom/vulkan/vk_command_queue.cpp +++ b/src/include/wisdom/vulkan/vk_command_queue.cpp @@ -21,8 +21,11 @@ WIS_EXTERN_C WISDOM_API void wisVKDestroyCommandQueue(WisVKCommandQueue* self) } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisVKCommandQueueSubmit(const WisVKCommandQueue* self, const WisVKCommandListView* lists, size_t count) +WIS_EXTERN_C WISDOM_API WisResult wisVKCommandQueueSubmit( + const WisVKCommandQueue* self, + const WisVKCommandListView* lists, + size_t count +) { auto& impl = wis::from_handle_ref(self); @@ -43,8 +46,11 @@ wisVKCommandQueueSubmit(const WisVKCommandQueue* self, const WisVKCommandListVie } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisVKCommandQueueSignalFence(const WisVKCommandQueue* self, WisVKFenceView fence, uint64_t value) +WIS_EXTERN_C WISDOM_API WisResult wisVKCommandQueueSignalFence( + const WisVKCommandQueue* self, + WisVKFenceView fence, + uint64_t value +) { auto& impl = wis::from_handle_ref(self); VkQueue queue = impl.queue; @@ -69,8 +75,11 @@ wisVKCommandQueueSignalFence(const WisVKCommandQueue* self, WisVKFenceView fence } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisVKCommandQueueWaitFence(const WisVKCommandQueue* self, WisVKFenceView fence, uint64_t value) +WIS_EXTERN_C WISDOM_API WisResult wisVKCommandQueueWaitFence( + const WisVKCommandQueue* self, + WisVKFenceView fence, + uint64_t value +) { auto& impl = wis::from_handle_ref(self); VkQueue queue = impl.queue; diff --git a/src/include/wisdom/vulkan/vk_descriptor_heap.cpp b/src/include/wisdom/vulkan/vk_descriptor_heap.cpp index aabfbe937..2114ca5ce 100644 --- a/src/include/wisdom/vulkan/vk_descriptor_heap.cpp +++ b/src/include/wisdom/vulkan/vk_descriptor_heap.cpp @@ -33,13 +33,12 @@ inline VkImageViewCreateInfo VKGetSRVDesc(const WisTextureBinding& binding) noex .pNext = nullptr, .flags = 0, .format = wis::detail::VKConvert(binding.format), - .components = - { - .r = wis::detail::VKConvert(binding.component_mapping.r), - .g = wis::detail::VKConvert(binding.component_mapping.g), - .b = wis::detail::VKConvert(binding.component_mapping.b), - .a = wis::detail::VKConvert(binding.component_mapping.a), - }, + .components = { + .r = wis::detail::VKConvert(binding.component_mapping.r), + .g = wis::detail::VKConvert(binding.component_mapping.g), + .b = wis::detail::VKConvert(binding.component_mapping.b), + .a = wis::detail::VKConvert(binding.component_mapping.a), + }, }; auto aspect_flags = VKGetAspectFlags(binding); @@ -352,8 +351,11 @@ WIS_EXTERN_C WISDOM_API WisResult wisVKDescriptorHeapWriteRWStructuredBuffer( } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisVKDescriptorHeapWriteSampler(const WisVKDescriptorHeap* self, const WisSamplerDesc* sampler, uint32_t index) +WIS_EXTERN_C WISDOM_API WisResult wisVKDescriptorHeapWriteSampler( + const WisVKDescriptorHeap* self, + const WisSamplerDesc* sampler, + uint32_t index +) { auto& heap = wis::from_handle_ref(self); auto& table = heap.device_header->header.device_table; @@ -477,8 +479,11 @@ WISDOM_API WisResult wisVKDescriptorHeapWriteRWTexture( } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisVKDescriptorHeapWriteAccelerationStructure(const WisVKDescriptorHeap* self, uint64_t address, uint32_t index) +WIS_EXTERN_C WISDOM_API WisResult wisVKDescriptorHeapWriteAccelerationStructure( + const WisVKDescriptorHeap* self, + uint64_t address, + uint32_t index +) { auto& heap = wis::from_handle_ref(self); auto& table = heap.device_header->header.device_table; diff --git a/src/include/wisdom/vulkan/vk_device.cpp b/src/include/wisdom/vulkan/vk_device.cpp index f025a44d4..27966b6ef 100644 --- a/src/include/wisdom/vulkan/vk_device.cpp +++ b/src/include/wisdom/vulkan/vk_device.cpp @@ -37,7 +37,8 @@ constexpr VkSpirvResourceTypeFlagsEXT GetResourceTypeFlags(const WisDescriptorTy } } -inline std::array GetMapCountPerShaderType(const WisRootSignatureDesc& desc +inline std::array GetMapCountPerShaderType( + const WisRootSignatureDesc& desc ) noexcept { std::array counts{}; @@ -117,8 +118,11 @@ WIS_EXTERN_C WISDOM_API void wisVKDestroyDevice(WisVKDevice* self) } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisVKDeviceCreateCommandQueue(const WisVKDevice* self, WisCommandQueueType type, WisVKCommandQueue* queue) +WIS_EXTERN_C WISDOM_API WisResult wisVKDeviceCreateCommandQueue( + const WisVKDevice* self, + WisCommandQueueType type, + WisVKCommandQueue* queue +) { WisResult res = wis::detail::vk_success; auto& device = *wis::from_handle(self); @@ -166,8 +170,11 @@ wisVKDeviceCreateCommandQueue(const WisVKDevice* self, WisCommandQueueType type, } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisVKDeviceCreateCommandAllocator(const WisVKDevice* self, WisCommandQueueType type, WisVKCommandAllocator* allocator) +WIS_EXTERN_C WISDOM_API WisResult wisVKDeviceCreateCommandAllocator( + const WisVKDevice* self, + WisCommandQueueType type, + WisVKCommandAllocator* allocator +) { auto& device = *wis::from_handle(self); auto& table = device.device_header->header.device_table; @@ -224,8 +231,11 @@ wisVKDeviceCreateCommandAllocator(const WisVKDevice* self, WisCommandQueueType t return wis::detail::vk_success; } -WIS_EXTERN_C WISDOM_API WisResult -wisVKDeviceCreateFence(const WisVKDevice* self, uint64_t initial_value, WisVKFence* fence) +WIS_EXTERN_C WISDOM_API WisResult wisVKDeviceCreateFence( + const WisVKDevice* self, + uint64_t initial_value, + WisVKFence* fence +) { WisResult res = wis::detail::vk_success; auto& device = *wis::from_handle(self); @@ -259,8 +269,10 @@ wisVKDeviceCreateFence(const WisVKDevice* self, uint64_t initial_value, WisVKFen } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisVKDeviceGetResourceAllocator(const WisVKDevice* self, WisVKResourceAllocator* allocator) +WIS_EXTERN_C WISDOM_API WisResult wisVKDeviceGetResourceAllocator( + const WisVKDevice* self, + WisVKResourceAllocator* allocator +) { auto& device = *wis::from_handle(self); @@ -275,8 +287,11 @@ wisVKDeviceGetResourceAllocator(const WisVKDevice* self, WisVKResourceAllocator* } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisVKDeviceCreateDescriptorHeap(const WisVKDevice* self, const WisDescriptorHeapDesc* desc, WisVKDescriptorHeap* heap) +WIS_EXTERN_C WISDOM_API WisResult wisVKDeviceCreateDescriptorHeap( + const WisVKDevice* self, + const WisDescriptorHeapDesc* desc, + WisVKDescriptorHeap* heap +) { auto& device = *wis::from_handle(self); auto& header = device.device_header->header; @@ -434,8 +449,11 @@ WIS_EXTERN_C WISDOM_API WisResult wisVKDeviceCreateViewHeap( } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisVKDeviceCreateRootSignature(const WisVKDevice* self, const WisRootSignatureDesc* desc, WisVKRootSignature* layout) +WIS_EXTERN_C WISDOM_API WisResult wisVKDeviceCreateRootSignature( + const WisVKDevice* self, + const WisRootSignatureDesc* desc, + WisVKRootSignature* layout +) { auto& device = *wis::from_handle(self); auto& header = device.device_header->header; @@ -476,7 +494,8 @@ wisVKDeviceCreateRootSignature(const WisVKDevice* self, const WisRootSignatureDe // 2. Count the number of VkDescriptorSetAndBindingMappingEXT structures // Hard part is to pack the tables into a contiguous arrays for each shader type uint32_t total_table_count = 0; - std::array table_counts_per_shader = wis::detail::GetMapCountPerShaderType(*desc + std::array table_counts_per_shader = wis::detail::GetMapCountPerShaderType( + *desc ); std::array local_offsets_per_shader = wis::detail::GetMappingOffsetPerShaderType( @@ -513,14 +532,17 @@ wisVKDeviceCreateRootSignature(const WisVKDevice* self, const WisRootSignatureDe } rootsig_header->shader_mapping_offset[i] = local_offsets_per_shader[i].offset - - (local_offsets_per_shader[i].even ? 0 : table_counts_per_shader[0] - ); // If even, "all" maps are after + - (local_offsets_per_shader[i].even + ? 0 + : table_counts_per_shader[0]); // If even, "all" maps are after // this stage, if odd, "all" maps // are before this stage - rootsig_header->shader_mapping_sizes[i] = table_counts_per_shader[i] - + (local_offsets_per_shader[i].even ? 0 : table_counts_per_shader[0] - ); // If even, this stage maps + "all" + rootsig_header + ->shader_mapping_sizes[i] = table_counts_per_shader[i] + + (local_offsets_per_shader[i].even + ? 0 + : table_counts_per_shader[0]); // If even, this stage maps + "all" // maps, if odd, only this stage maps if (!all_offset) { @@ -606,21 +628,23 @@ wisVKDeviceCreateRootSignature(const WisVKDevice* self, const WisRootSignatureDe } heap_byte_offset = local_offset + local_count * heap_stride; - auto& mapping = mappings[local_offsets_per_shader[visibility].offset++] = - {.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_AND_BINDING_MAPPING_EXT, - .pNext = nullptr, - .descriptorSet = entry.bind_space, - .firstBinding = entry.bind_register, - .bindingCount = local_count, - .resourceMask = wis::detail::GetResourceTypeFlags(entry.type), - .source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_PUSH_INDEX_EXT, - .sourceData = - {.pushIndex = { - .heapOffset = local_offset, - .pushOffset = push_address_offset, - .heapIndexStride = 1, - .heapArrayStride = heap_stride, - }}}; + auto& mapping = mappings[local_offsets_per_shader[visibility].offset++] = { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_AND_BINDING_MAPPING_EXT, + .pNext = nullptr, + .descriptorSet = entry.bind_space, + .firstBinding = entry.bind_register, + .bindingCount = local_count, + .resourceMask = wis::detail::GetResourceTypeFlags(entry.type), + .source = VK_DESCRIPTOR_MAPPING_SOURCE_HEAP_WITH_PUSH_INDEX_EXT, + .sourceData = { + .pushIndex = { + .heapOffset = local_offset, + .pushOffset = push_address_offset, + .heapIndexStride = 1, + .heapArrayStride = heap_stride, + } + } + }; } root_param_offsets[root_param_index++] = push_address_offset; @@ -706,7 +730,6 @@ WIS_EXTERN_C WISDOM_API void wisVKDeviceQueryProperties(const WisVKDevice* self, case WisQueryPropertyTypeDeviceMemoryProperties: { auto* props = static_cast(next); props->host_image_copy_supported = header.features.host_image_copy; - props->supported_initial_transitions = header.features.supported_image_layout_transitions; const VkPhysicalDeviceMemoryProperties* mem_props; vmaGetMemoryProperties(header.allocator, &mem_props); @@ -716,9 +739,11 @@ WIS_EXTERN_C WISDOM_API void wisVKDeviceQueryProperties(const WisVKDevice* self, if ((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && (flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) && (flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) { props->gpu_upload_supported = true; + props->gpu_upload_heap_budget = mem_props->memoryHeaps[mem_props->memoryTypes[i].heapIndex].size; break; } } + } break; case WisQueryPropertyTypeDeviceBindingProperties: { auto* props = static_cast(next); @@ -826,8 +851,12 @@ WIS_EXTERN_C WISDOM_API WisResult wisVKDeviceCreatePipelineCache( } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisVKDeviceCreateShader(const WisVKDevice* self, const uint8_t* data, size_t size, WisVKShader* shader) +WIS_EXTERN_C WISDOM_API WisResult wisVKDeviceCreateShader( + const WisVKDevice* self, + const uint8_t* data, + size_t size, + WisVKShader* shader +) { auto& device = *wis::from_handle(self); auto& table = device.device_header->header.device_table; @@ -846,15 +875,19 @@ wisVKDeviceCreateShader(const WisVKDevice* self, const uint8_t* data, size_t siz return wis::detail::make_result(vr); } - auto& shader_impl = *new (shader + auto& shader_impl = *new ( + shader ) wis::impl::VKShaderImpl{.shader_module = shader_handle, .device_header = device.device_header}; device.device_header->AddRef(); return wis::detail::vk_success; } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisVKDeviceCreateComputePipeline(const WisVKDevice* self, const WisVKComputePipelineDesc* desc, WisVKPipeline* pipeline) +WIS_EXTERN_C WISDOM_API WisResult wisVKDeviceCreateComputePipeline( + const WisVKDevice* self, + const WisVKComputePipelineDesc* desc, + WisVKPipeline* pipeline +) { auto& device = *wis::from_handle(self); auto& table = device.device_header->header.device_table; @@ -901,7 +934,8 @@ wisVKDeviceCreateComputePipeline(const WisVKDevice* self, const WisVKComputePipe return wis::detail::make_result(vr); } - auto& pipeline_impl = *new (pipeline + auto& pipeline_impl = *new ( + pipeline ) wis::impl::VKPipelineImpl{.pipeline = pipeline_handle, .device_header = device.device_header}; pipeline_impl.device_header->AddRef(); return wis::detail::vk_success; @@ -1358,7 +1392,8 @@ WIS_EXTERN_C WISDOM_API WisResult wisVKDeviceCreateGraphicsPipeline( return wis::detail::make_result(vr); } - auto& pipeline_impl = *new (pipeline + auto& pipeline_impl = *new ( + pipeline ) wis::impl::VKPipelineImpl{.pipeline = pipeline_handle, .device_header = device.device_header}; device.device_header->AddRef(); @@ -1366,8 +1401,11 @@ WIS_EXTERN_C WISDOM_API WisResult wisVKDeviceCreateGraphicsPipeline( } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisVKDeviceGetSurfaceParameters(const WisVKDevice* self, WisVKSurfaceView surface, WisSurfaceParameters* params) +WIS_EXTERN_C WISDOM_API WisResult wisVKDeviceGetSurfaceParameters( + const WisVKDevice* self, + WisVKSurfaceView surface, + WisSurfaceParameters* params +) { auto& device = wis::from_handle_ref(self); auto atable = device.device_header->header.shared_header->header.adapter_table; @@ -1520,7 +1558,8 @@ WIS_EXTERN_C WISDOM_API WisResult wisVKDeviceCreateSwapchain( if (format_it == format_span.end()) { return wis::detail::make_result< wis::detail::Func(), - "The requested format is not supported for presentation on the given surface">(VK_ERROR_FORMAT_NOT_SUPPORTED + "The requested format is not supported for presentation on the given surface">( + VK_ERROR_FORMAT_NOT_SUPPORTED ); } @@ -1582,8 +1621,9 @@ WIS_EXTERN_C WISDOM_API WisResult wisVKDeviceCreateSwapchain( } else if ((tearing = std::ranges::count(modes, VK_PRESENT_MODE_FIFO_RELAXED_KHR) > 0)) { present_mode = VK_PRESENT_MODE_FIFO_RELAXED_KHR; } - } else if (std::ranges::count(modes, VK_PRESENT_MODE_MAILBOX_KHR) > 0 - && !(desc->flags & WisSwapchainFlagsStereo)) { + } else if ( + std::ranges::count(modes, VK_PRESENT_MODE_MAILBOX_KHR) > 0 && !(desc->flags & WisSwapchainFlagsStereo) + ) { present_mode = VK_PRESENT_MODE_MAILBOX_KHR; } } @@ -1789,8 +1829,11 @@ WIS_EXTERN_C WISDOM_API WisResult wisVKDeviceCreateSwapchain( } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisVKDeviceGetFormatProperties(const WisVKDevice* self, WisDataFormat format, WisFormatProperties* properties) +WIS_EXTERN_C WISDOM_API WisResult wisVKDeviceGetFormatProperties( + const WisVKDevice* self, + WisDataFormat format, + WisFormatProperties* properties +) { auto& device = wis::from_handle_ref(self); auto atable = device.device_header->header.shared_header->header.adapter_table; diff --git a/src/include/wisdom/vulkan/vk_extensions.cpp b/src/include/wisdom/vulkan/vk_extensions.cpp index 240f1bb3f..804636661 100644 --- a/src/include/wisdom/vulkan/vk_extensions.cpp +++ b/src/include/wisdom/vulkan/vk_extensions.cpp @@ -246,7 +246,8 @@ const VkExtensionProperties* wis::VKDeviceExtensionCollector::GetExtensionProper return nullptr; } -wis::VKDeviceExtensionCollector::InitBuffer wis::VKDeviceExtensionCollector::GetInitBuffer(WisResult& out_res +wis::VKDeviceExtensionCollector::InitBuffer wis::VKDeviceExtensionCollector::GetInitBuffer( + WisResult& out_res ) const noexcept { InitBuffer result; diff --git a/src/include/wisdom/vulkan/vk_impl.cpp b/src/include/wisdom/vulkan/vk_impl.cpp index 261c0533e..7c9c405d7 100644 --- a/src/include/wisdom/vulkan/vk_impl.cpp +++ b/src/include/wisdom/vulkan/vk_impl.cpp @@ -75,8 +75,11 @@ WIS_EXTERN_C WISDOM_API void wisVKDestroyTexture(WisVKTexture* self) } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisVKTextureWriteSubresource(const WisVKTexture* self, const void* source_data, const WisTextureRegion* target_region) +WIS_EXTERN_C WISDOM_API WisResult wisVKTextureWriteSubresource( + const WisVKTexture* self, + const void* source_data, + const WisTextureRegion* target_region +) { auto& impl = wis::from_handle_ref(self); auto& header = impl.device_header->header; diff --git a/src/include/wisdom/vulkan/vk_instance.cpp b/src/include/wisdom/vulkan/vk_instance.cpp index 0d5ffc356..47c1c4951 100644 --- a/src/include/wisdom/vulkan/vk_instance.cpp +++ b/src/include/wisdom/vulkan/vk_instance.cpp @@ -244,8 +244,11 @@ WIS_EXTERN_C WISDOM_API void wisVKDestroyInstance(WisVKInstance* self) } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisVKInstanceQueryAdapters(const WisVKInstance* self, WisAdapterPreference preference, WisVKAdapterQuery* query) +WIS_EXTERN_C WISDOM_API WisResult wisVKInstanceQueryAdapters( + const WisVKInstance* self, + WisAdapterPreference preference, + WisVKAdapterQuery* query +) { // Query can come as partially constructed from C side auto& instance_impl = wis::from_handle_ref(self); diff --git a/src/include/wisdom/vulkan/vk_pipeline_cache.cpp b/src/include/wisdom/vulkan/vk_pipeline_cache.cpp index 29c09cfb0..1366545a2 100644 --- a/src/include/wisdom/vulkan/vk_pipeline_cache.cpp +++ b/src/include/wisdom/vulkan/vk_pipeline_cache.cpp @@ -23,8 +23,11 @@ WIS_EXTERN_C WISDOM_API void wisVKDestroyPipelineCache(WisVKPipelineCache* self) } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisVKPipelineCacheSerialize(const WisVKPipelineCache* self, uint8_t* data, size_t data_size) +WIS_EXTERN_C WISDOM_API WisResult wisVKPipelineCacheSerialize( + const WisVKPipelineCache* self, + uint8_t* data, + size_t data_size +) { auto& impl = wis::from_handle_ref(self); auto& table = impl.device_header->header.device_table; diff --git a/src/include/wisdom/vulkan/vk_resource_allocator.cpp b/src/include/wisdom/vulkan/vk_resource_allocator.cpp index 615acaa20..155a5654b 100644 --- a/src/include/wisdom/vulkan/vk_resource_allocator.cpp +++ b/src/include/wisdom/vulkan/vk_resource_allocator.cpp @@ -97,8 +97,11 @@ WIS_EXTERN_C WISDOM_API void wisVKDestroyResourceAllocator(WisVKResourceAllocato } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisVKResourceAllocatorCreateBuffer(const WisVKResourceAllocator* self, const WisBufferDesc* desc, WisVKBuffer* buffer) +WIS_EXTERN_C WISDOM_API WisResult wisVKResourceAllocatorCreateBuffer( + const WisVKResourceAllocator* self, + const WisBufferDesc* desc, + WisVKBuffer* buffer +) { auto& allocator = wis::from_handle_ref(self); @@ -209,14 +212,13 @@ WIS_EXTERN_C WISDOM_API WisResult wisVKResourceAllocatorCreateTexture( .image = image_handle, .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, .newLayout = VK_IMAGE_LAYOUT_GENERAL, - .subresourceRange = - { - .aspectMask = wis::detail::VKAspectFlags(image_info.format), - .baseMipLevel = 0, - .levelCount = image_info.mipLevels, - .baseArrayLayer = 0, - .layerCount = image_info.arrayLayers, - }, + .subresourceRange = { + .aspectMask = wis::detail::VKAspectFlags(image_info.format), + .baseMipLevel = 0, + .levelCount = image_info.mipLevels, + .baseArrayLayer = 0, + .layerCount = image_info.arrayLayers, + }, }; vr = table.vkTransitionImageLayoutEXT(header.device, 1, &transition_info); diff --git a/src/include/wisdom/vulkan/vk_swapchain.cpp b/src/include/wisdom/vulkan/vk_swapchain.cpp index c1d0816e2..9a8e99fab 100644 --- a/src/include/wisdom/vulkan/vk_swapchain.cpp +++ b/src/include/wisdom/vulkan/vk_swapchain.cpp @@ -79,8 +79,12 @@ WIS_EXTERN_C WISDOM_API void wisVKDestroySwapchain(WisVKSwapchain* self) } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisVKSwapchainPresent(const WisVKSwapchain* self, WisPresentFlags flags, const WisRect* rects, size_t rect_count) +WIS_EXTERN_C WISDOM_API WisResult wisVKSwapchainPresent( + const WisVKSwapchain* self, + WisPresentFlags flags, + const WisRect* rects, + size_t rect_count +) { auto& impl = wis::from_handle_ref(self); @@ -158,8 +162,8 @@ WIS_EXTERN_C WISDOM_API WisResult wisVKSwapchainUpdate(const WisVKSwapchain* sel VkFormat new_format = wis::detail::VKConvert(desc->format); bool size_changed = desc->width != 0 && desc->height != 0 - && (desc->width != create_info.imageExtent.width || desc->height != create_info.imageExtent.height - ); + && (desc->width != create_info.imageExtent.width + || desc->height != create_info.imageExtent.height); bool format_changed = desc->format != WisDataFormatUnknown && new_format != create_info.imageFormat; bool count_changed = desc->image_count != 0 && desc->image_count != create_info.minImageCount; bool vsync_changed = desc->vsync != (create_info.presentMode == VK_PRESENT_MODE_FIFO_KHR); @@ -173,8 +177,10 @@ WIS_EXTERN_C WISDOM_API WisResult wisVKSwapchainUpdate(const WisVKSwapchain* sel } else if (std::ranges::find(modes, VK_PRESENT_MODE_FIFO_RELAXED_KHR) != std::end(modes)) { present_mode = VK_PRESENT_MODE_FIFO_RELAXED_KHR; } - } else if (std::ranges::find(modes, VK_PRESENT_MODE_MAILBOX_KHR) != std::end(modes) - && (create_info.imageArrayLayers == 1)) { + } else if ( + std::ranges::find(modes, VK_PRESENT_MODE_MAILBOX_KHR) != std::end(modes) + && (create_info.imageArrayLayers == 1) + ) { present_mode = VK_PRESENT_MODE_MAILBOX_KHR; } } @@ -295,8 +301,11 @@ WIS_EXTERN_C WISDOM_API WisResult wisVKSwapchainUpdate(const WisVKSwapchain* sel } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult -wisVKSwapchainGetTextures(const WisVKSwapchain* self, WisVKTexture* buffers, size_t buffer_count) +WIS_EXTERN_C WISDOM_API WisResult wisVKSwapchainGetTextures( + const WisVKSwapchain* self, + WisVKTexture* buffers, + size_t buffer_count +) { auto& impl = wis::from_handle_ref(self); diff --git a/src/platform/wisdom_platform/dx12/dx12_platform_uwp.cpp b/src/platform/wisdom_platform/dx12/dx12_platform_uwp.cpp index c8166bd96..d38e59373 100644 --- a/src/platform/wisdom_platform/dx12/dx12_platform_uwp.cpp +++ b/src/platform/wisdom_platform/dx12/dx12_platform_uwp.cpp @@ -38,8 +38,11 @@ WIS_EXTERN_C WISDOM_PLATFORM_API void wisDX12DestroyUWPExtension(WisDX12UWPExten } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_PLATFORM_API WisResult -wisDX12UWPExtensionCreateSurface(WisDX12UWPExtension* self, const WisUWPWindowDesc* info, WisDX12Surface* surface) +WIS_EXTERN_C WISDOM_PLATFORM_API WisResult wisDX12UWPExtensionCreateSurface( + WisDX12UWPExtension* self, + const WisUWPWindowDesc* info, + WisDX12Surface* surface +) { new (surface) wis::impl::DX12SurfaceImpl{ .surface = info->core_window, diff --git a/src/platform/wisdom_platform/dx12/dx12_platform_win32.cpp b/src/platform/wisdom_platform/dx12/dx12_platform_win32.cpp index 680dab073..d7bfd3555 100644 --- a/src/platform/wisdom_platform/dx12/dx12_platform_win32.cpp +++ b/src/platform/wisdom_platform/dx12/dx12_platform_win32.cpp @@ -38,8 +38,11 @@ WIS_EXTERN_C WISDOM_PLATFORM_API void wisDX12DestroyWin32Extension(WisDX12Win32E } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_PLATFORM_API WisResult -wisDX12Win32ExtensionCreateSurface(WisDX12Win32Extension* self, const WisWin32WindowDesc* info, WisDX12Surface* surface) +WIS_EXTERN_C WISDOM_PLATFORM_API WisResult wisDX12Win32ExtensionCreateSurface( + WisDX12Win32Extension* self, + const WisWin32WindowDesc* info, + WisDX12Surface* surface +) { new (surface) wis::impl::DX12SurfaceImpl{ .surface = info->hwnd, diff --git a/src/platform/wisdom_platform/vulkan/vk_platform_wayland.cpp b/src/platform/wisdom_platform/vulkan/vk_platform_wayland.cpp index 4478add10..04c8890d6 100644 --- a/src/platform/wisdom_platform/vulkan/vk_platform_wayland.cpp +++ b/src/platform/wisdom_platform/vulkan/vk_platform_wayland.cpp @@ -53,8 +53,11 @@ WIS_EXTERN_C WISDOM_PLATFORM_API void wisVKDestroyWaylandExtension(WisVKWaylandE } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_PLATFORM_API WisResult -wisVKWaylandExtensionCreateSurface(WisVKWaylandExtension* self, const WisWaylandWindowDesc* info, WisVKSurface* surface) +WIS_EXTERN_C WISDOM_PLATFORM_API WisResult wisVKWaylandExtensionCreateSurface( + WisVKWaylandExtension* self, + const WisWaylandWindowDesc* info, + WisVKSurface* surface +) { auto& impl = wis::from_handle_ref(self); auto vkCreateWaylandSurfaceKHR = reinterpret_cast(impl.vkCreateWaylandSurfaceKHR); diff --git a/xml/structs.xml b/xml/structs.xml index 349baf4d2..d9b679e98 100644 --- a/xml/structs.xml +++ b/xml/structs.xml @@ -464,7 +464,7 @@ Viewport is considered from Top Left corner."> - + From 4eec5f12361c3aa45e0ac3accc7a84c4fecb8894 Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Thu, 23 Apr 2026 23:59:15 +0200 Subject: [PATCH 07/10] Remove gpu_upload_heap_budget from device properties Removed gpu_upload_heap_budget from WisDeviceMemoryProperties and DeviceMemoryProperties in both C and C++ APIs. Updated all related code, documentation, and XML definitions to eliminate references to this field. Clarified documentation for gpu_upload_supported and host_image_copy_supported. Made minor code formatting improvements. --- .../struct/device_memory_properties_struct.h | 35 +++++++++---------- src/include/wisdom/dx12/dx12_device.cpp | 5 --- src/include/wisdom/generated/c_api.h | 5 --- src/include/wisdom/generated/cpp_api.hpp | 5 --- src/include/wisdom/vulkan/vk_device.cpp | 26 +++++++++++--- xml/structs.xml | 1 - 6 files changed, 38 insertions(+), 39 deletions(-) diff --git a/docs/wisdom/struct/device_memory_properties_struct.h b/docs/wisdom/struct/device_memory_properties_struct.h index 42ee64934..793cb9b07 100644 --- a/docs/wisdom/struct/device_memory_properties_struct.h +++ b/docs/wisdom/struct/device_memory_properties_struct.h @@ -17,7 +17,6 @@ * void* next_in_chain; * bool gpu_upload_supported; * bool host_image_copy_supported; - * uint64_t gpu_upload_heap_budget; * } WisDeviceMemoryProperties; * * ``` @@ -30,7 +29,6 @@ * void* next_in_chain; * bool gpu_upload_supported; * bool host_image_copy_supported; - * std::uint64_t gpu_upload_heap_budget; * }; * } * ``` @@ -49,28 +47,27 @@ * from CPU memory to optimal tiled image layout on GPU, without the need for an intermediate staging buffer. It is * supported on Windows 10 22H2 and later with WDDM 3.0 or later. On Vulkan it requires `VK_EXT_host_image_copy` * extension. - * - `gpu_upload_heap_budget` specifies heap budget for GPU upload memory type in bytes. This is an approximate value of - * how much memory of this type can be allocated, and it can change over time depending on the system state. * \endcond * * @section WisDeviceMemoryProperties_descr Description *
* - * `gpu_upload_heap_budget` is a metric of how much memory of the GPU upload type can be allocated, but it is not a hard - * limit. It is possible that allocations of this type may fail even if the total allocated memory is below this budget, - * due to fragmentation or other factors. Conversely, it may be possible to allocate more memory than this budget in - * some cases. This value should be used as a guideline for how much memory of this type to allocate, rather than a - * strict limit. - * - * `gpu_upload_heap_budget` has 3 possible states: - * - If the device does not support GPU upload memory type, this value will be 0. - * - If the device supports GPU upload memory, but the ReBAR is not enabled, this value will be 0 on DirectX 12 and a - * small value on Vulkan (e.g., 256MB), representing the portion of shared system memory that is accessible to the GPU. - * The value is exposed even if ReBAR is not enabled, because in some cases allocation such a small amount may be - * beneficial, because it may be faster to access than regular Upload Heap. - * - If the device supports GPU upload memory and ReBAR is enabled, this value will be either equal to the size of - * dedicated video memory or a nearby value, depending on how the system allocates memory for the GPU upload type. This - * means that whole video memory is accessible by CPU and uploads can be done without staging buffers. + * `gpu_upload_supported` means that the device has a memory type that is both HOST_VISIBLE and DEVICE_LOCAL. That + * allows writes to memory directly using CPU mapping. + * `host_image_copy_supported` means that the device supports copying data directly from CPU memory to optimal tiled + * image layout on GPU, without the need for an intermediate staging buffer. This can improve performance and reduce + * memory usage when uploading textures from CPU to GPU. + * + * DirectX 12 supports both of these feature simultaneusly. That means that on DirectX 12, if `gpu_upload_supported` is + * true, then `host_image_copy_supported` will also be true. On Vulkan, these features are independent and may be + * supported separately. On Vulkan, `host_image_copy_supported` requires the `VK_EXT_host_image_copy` extension, while + * `gpu_upload_supported` depends on the presence of a memory type that is both HOST_VISIBLE and DEVICE_LOCAL. + * + * If `gpu_upload_supported` is true, `WisMemoryTypeGPUUpload` memory type can be used for resource allocation. This + * memory type allows mapping the memory and writing to it from CPU, while being accessible from GPU. + * + * If `host_image_copy_supported` is true, `wisTextureWriteSubresource` function can be used to write texture data + * directly from CPU memory to optimal tiled image layout on GPU. * * \cond WIS_GEN_WIS_IDS * \endcond diff --git a/src/include/wisdom/dx12/dx12_device.cpp b/src/include/wisdom/dx12/dx12_device.cpp index 14cc46e79..8a190fb0e 100644 --- a/src/include/wisdom/dx12/dx12_device.cpp +++ b/src/include/wisdom/dx12/dx12_device.cpp @@ -486,13 +486,8 @@ WIS_EXTERN_C WISDOM_API void wisDX12DeviceQueryProperties(const WisDX12Device* s device.device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS16, &options16, sizeof(options16)) )) { - D3D12MA::Budget local_budget = {}; - D3D12MA::Budget non_local_budget = {}; - device.allocator->GetBudget(&local_budget, &non_local_budget); - props->gpu_upload_supported = options16.GPUUploadHeapSupported; props->host_image_copy_supported = options16.GPUUploadHeapSupported; - props->gpu_upload_heap_budget = options16.GPUUploadHeapSupported ? local_budget.BudgetBytes : 0ull; } } break; case WisQueryPropertyTypeDeviceBindingProperties: { diff --git a/src/include/wisdom/generated/c_api.h b/src/include/wisdom/generated/c_api.h index 7dcf8312b..b1ddcd6c3 100644 --- a/src/include/wisdom/generated/c_api.h +++ b/src/include/wisdom/generated/c_api.h @@ -2513,11 +2513,6 @@ typedef struct WisDeviceMemoryProperties { * Windows 10 22H2 and later with WDDM 3.0 or later. On Vulkan it requires `VK_EXT_host_image_copy` extension. * */ bool host_image_copy_supported; - /** - * @brief specifies heap budget for GPU upload memory type in bytes. This is an approximate value of how much memory - * of this type can be allocated, and it can change over time depending on the system state. - * */ - uint64_t gpu_upload_heap_budget; } WisDeviceMemoryProperties; /** diff --git a/src/include/wisdom/generated/cpp_api.hpp b/src/include/wisdom/generated/cpp_api.hpp index 1ab8bbd0d..51e1d9082 100644 --- a/src/include/wisdom/generated/cpp_api.hpp +++ b/src/include/wisdom/generated/cpp_api.hpp @@ -2533,11 +2533,6 @@ struct DeviceMemoryProperties { * Windows 10 22H2 and later with WDDM 3.0 or later. On Vulkan it requires `VK_EXT_host_image_copy` extension. * */ bool host_image_copy_supported; - /** - * @brief specifies heap budget for GPU upload memory type in bytes. This is an approximate value of how much memory - * of this type can be allocated, and it can change over time depending on the system state. - * */ - std::uint64_t gpu_upload_heap_budget; }; /** diff --git a/src/include/wisdom/vulkan/vk_device.cpp b/src/include/wisdom/vulkan/vk_device.cpp index 27966b6ef..28467f4ab 100644 --- a/src/include/wisdom/vulkan/vk_device.cpp +++ b/src/include/wisdom/vulkan/vk_device.cpp @@ -734,12 +734,31 @@ WIS_EXTERN_C WISDOM_API void wisVKDeviceQueryProperties(const WisVKDevice* self, const VkPhysicalDeviceMemoryProperties* mem_props; vmaGetMemoryProperties(header.allocator, &mem_props); + // Find largest VRAM heap. + uint64_t largest_vram_heap_size = 0; + uint32_t largest_vram_heap_index = 0; + for (uint32_t i = 0; i < mem_props->memoryHeapCount; ++i) { + if (mem_props->memoryHeaps[i].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) { + auto heap_size = mem_props->memoryHeaps[i].size; + if (heap_size > largest_vram_heap_size) { + largest_vram_heap_size = heap_size; + largest_vram_heap_index = i; + } + } + } + + // Scan memory types to find one that is HOST_VISIBLE, HOST_COHERENT and DEVICE_LOCAL, and belongs to the + // largest VRAM heap. + props->gpu_upload_supported = false; for (uint32_t i = 0; i < mem_props->memoryTypeCount; ++i) { + if ((mem_props->memoryTypes[i].heapIndex != largest_vram_heap_index)) { + continue; + } + const VkMemoryPropertyFlags flags = mem_props->memoryTypes[i].propertyFlags; if ((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) && (flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) && (flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) { props->gpu_upload_supported = true; - props->gpu_upload_heap_budget = mem_props->memoryHeaps[mem_props->memoryTypes[i].heapIndex].size; break; } } @@ -1621,9 +1640,8 @@ WIS_EXTERN_C WISDOM_API WisResult wisVKDeviceCreateSwapchain( } else if ((tearing = std::ranges::count(modes, VK_PRESENT_MODE_FIFO_RELAXED_KHR) > 0)) { present_mode = VK_PRESENT_MODE_FIFO_RELAXED_KHR; } - } else if ( - std::ranges::count(modes, VK_PRESENT_MODE_MAILBOX_KHR) > 0 && !(desc->flags & WisSwapchainFlagsStereo) - ) { + } else if (std::ranges::count(modes, VK_PRESENT_MODE_MAILBOX_KHR) > 0 + && !(desc->flags & WisSwapchainFlagsStereo)) { present_mode = VK_PRESENT_MODE_MAILBOX_KHR; } } diff --git a/xml/structs.xml b/xml/structs.xml index d9b679e98..5a91b5269 100644 --- a/xml/structs.xml +++ b/xml/structs.xml @@ -464,7 +464,6 @@ Viewport is considered from Top Left corner."> -
From 93b619721270cded6659dbe7bcaf1d791a1b51e1 Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Fri, 24 Apr 2026 09:58:14 +0200 Subject: [PATCH 08/10] Refactor dependency management: add Conan/CPM toggle Refactor CMake dependency management to support toggling between Conan and CPM via WISDOM_USE_CONAN. Move Conan logic from CMakeLists.txt to deps.cmake and update Vulkan/DirectX 12 memory allocator targets to match Conan package names. Improve find_package integration and error handling for missing dependencies. Update conanfile.py to always require Vulkan Memory Allocator. --- CMakeLists.txt | 6 -- cmake/conan.cmake | 117 ----------------------------------- cmake/deps.cmake | 46 ++++++++------ cmake/deps/deps_vulkan.cmake | 47 +++++++++----- cmake/deps/deps_win.cmake | 13 ++-- conanfile.py | 8 ++- src/include/CMakeLists.txt | 2 +- 7 files changed, 72 insertions(+), 167 deletions(-) delete mode 100644 cmake/conan.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f5649ef5..3e1ef968b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,12 +28,6 @@ option(WISDOM_BUILD_DOCS "Build the documentation." OFF) option(WISDOM_USE_AGILITY_SDK "Download and use DirectX 12 Agility SDK." OFF) option(WISDOM_USE_CONAN "Use Conan to manage dependencies. Only for library builds." OFF) -if (WISDOM_USE_CONAN) - set(CONAN_CXX_STANDARD 20) - include(cmake/conan.cmake) -endif() - - # DXC deployment options set(WISDOM_VULKAN_HEADER_PATH "" diff --git a/cmake/conan.cmake b/cmake/conan.cmake deleted file mode 100644 index 3fe1fa835..000000000 --- a/cmake/conan.cmake +++ /dev/null @@ -1,117 +0,0 @@ -# Determine the Conan compiler name based on the CMake compiler ID -if (NOT CONAN_COMPILER) - if(CMAKE_CXX_COMPILER_ID MATCHES "AppleClang") - set(CONAN_COMPILER "apple-clang") - elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(CONAN_COMPILER "clang") - elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") - set(CONAN_COMPILER "msvc") - elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - set(CONAN_COMPILER "gcc") - endif() -endif() - -# Extract the major version number from the CMake compiler version -if (NOT CONAN_COMPILER_VERSION) - if (CONAN_COMPILER STREQUAL "msvc") - message (STATUS "Detected MSVC version: ${CMAKE_CXX_COMPILER_VERSION}") - - # special handling for msvc to extract the major version (e.g., 143 from 14.3.0) - string (REGEX MATCH "^[0-9]+\\.[0-9]" MSVC_VERSION_MATCH ${CMAKE_CXX_COMPILER_VERSION}) - - # remove the dot to get the major version (e.g., 143 from 14.3) - string (REPLACE "." "" CONAN_COMPILER_VERSION ${MSVC_VERSION_MATCH}) - else() - string(REGEX MATCH "^[0-9]+" CONAN_COMPILER_VERSION ${CMAKE_CXX_COMPILER_VERSION}) - endif() -endif() - -# Map Architectures to Conan's expected values -if (NOT CONAN_ARCH) - if (CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64|AMD64") - set(CONAN_ARCH "x86_64") - elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i386|i686") - set(CONAN_ARCH "x86") - else () - message(WARNING "Unknown architecture ${CMAKE_SYSTEM_PROCESSOR}, using it directly for Conan") - set(CONAN_ARCH ${CMAKE_SYSTEM_PROCESSOR}) - endif() -endif() - -# Map CXX_STANDARD to Conan's expected value -if (NOT CONAN_CXX_STANDARD) - if (CMAKE_CXX_STANDARD) - set(CONAN_CXX_STANDARD ${CMAKE_CXX_STANDARD}) - else() - message(WARNING "CMAKE_CXX_STANDARD is not set, defaulting to C++20 for Conan profile") - set(CONAN_CXX_STANDARD 20) # Default to C++17 if not specified - endif() -endif() - -# Determine OS-specific Conan settings -if(WIN32) - # Append runtime version for Clang-cl - if(MSVC_TOOLSET_VERSION) - set(CONAN_OS_SPECIFIC "compiler.runtime=dynamic\ncompiler.runtime_type=${CMAKE_BUILD_TYPE}") - - if(NOT CONAN_COMPILER STREQUAL "msvc") - set(CONAN_OS_SPECIFIC "${CONAN_OS_SPECIFIC}\ncompiler.runtime_version=v${MSVC_TOOLSET_VERSION}") - endif() - endif() - -elseif(APPLE) - # macOS always uses LLVM's libc++ - set(CONAN_OS_SPECIFIC "compiler.libcxx=libc++") - -elseif(UNIX) - # On Linux, determine if Clang was forced to use libc++, otherwise default to libstdc++11 - set(CONAN_LIBCXX "libstdc++11") - - if(CONAN_COMPILER STREQUAL "clang") - # Check if the developer passed -stdlib=libc++ in the CMake cache or env - if(CMAKE_CXX_FLAGS MATCHES "-stdlib=libc\\+\\+") - set(CONAN_LIBCXX "libc++") - endif() - endif() - - set(CONAN_OS_SPECIFIC "compiler.libcxx=${CONAN_LIBCXX}") -endif() - -# Set the Conan profile content -set(CONAN_PROFILE_PATH "${CMAKE_BINARY_DIR}/conan_profile.txt") -set(CONAN_PROFILE "[settings] -os=${CMAKE_SYSTEM_NAME} -arch=${CONAN_ARCH} -build_type=${CMAKE_BUILD_TYPE} -compiler=${CONAN_COMPILER} -compiler.version=${CONAN_COMPILER_VERSION} -compiler.cppstd=${CONAN_CXX_STANDARD} -${CONAN_OS_SPECIFIC} - -[conf] -tools.cmake.cmaketoolchain:generator=${CMAKE_GENERATOR} -") - -# Make a message with file contents -message(STATUS "Generating Conan profile at ${CONAN_PROFILE_PATH}...") -message(STATUS "Conan profile content:\n${CONAN_PROFILE}") - -file(WRITE ${CONAN_PROFILE_PATH} ${CONAN_PROFILE}) - -# Call Conan to install dependencies using the generated profile -message(STATUS "Running Conan install...") -execute_process( - COMMAND conan install ${CMAKE_SOURCE_DIR} - --profile:all=${CONAN_PROFILE_PATH} - --build=missing - -cc core.graph:compatibility_mode=optimized - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - RESULT_VARIABLE conan_result -) - -if(NOT conan_result EQUAL "0") - message(FATAL_ERROR "Conan install failed!") -endif() - -# 5. Link the dependencies -list(APPEND CMAKE_PREFIX_PATH "${CMAKE_SOURCE_DIR}/build/${CMAKE_BUILD_TYPE}/generators") \ No newline at end of file diff --git a/cmake/deps.cmake b/cmake/deps.cmake index 74914f7fd..ddad3b00e 100644 --- a/cmake/deps.cmake +++ b/cmake/deps.cmake @@ -1,25 +1,35 @@ -include(FetchContent) -set(FETCHCONTENT_UPDATES_DISCONNECTED ON) -set(CPM_DONT_UPDATE_MODULE_PATH ON) -set(GET_CPM_FILE "${CMAKE_CURRENT_LIST_DIR}/deps/get_cpm.cmake") -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) - -# Set CPM source cache -if (NOT CPM_SOURCE_CACHE) - set(CPM_SOURCE_CACHE "${CMAKE_CURRENT_BINARY_DIR}/_deps_cache") -endif () +# Block CPM if already using Conan, otherwise fetch dependencies using CPM +if(NOT WISDOM_USE_CONAN) + include(FetchContent) + set(FETCHCONTENT_UPDATES_DISCONNECTED ON) + set(CPM_DONT_UPDATE_MODULE_PATH ON) + set(GET_CPM_FILE "${CMAKE_CURRENT_LIST_DIR}/deps/get_cpm.cmake") + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) + + # Set CPM source cache + if (NOT CPM_SOURCE_CACHE) + set(CPM_SOURCE_CACHE "${CMAKE_CURRENT_BINARY_DIR}/_deps_cache") + endif () -if (NOT EXISTS ${GET_CPM_FILE}) - file(DOWNLOAD - https://github.com/cpm-cmake/CPM.cmake/releases/latest/download/get_cpm.cmake - "${GET_CPM_FILE}" - ) -endif () -include(${GET_CPM_FILE}) + if (NOT EXISTS ${GET_CPM_FILE}) + file(DOWNLOAD + https://github.com/cpm-cmake/CPM.cmake/releases/latest/download/get_cpm.cmake + "${GET_CPM_FILE}" + ) + endif () + include(${GET_CPM_FILE}) +endif() if (WISDOM_WINDOWS) - include(${CMAKE_CURRENT_LIST_DIR}/deps/deps_win.cmake) + if (WISDOM_USE_CONAN) # This prevents accidental blockade of Agility SDK + find_package(D3D12MemoryAllocator CONFIG QUIET) + if (NOT D3D12MemoryAllocator_FOUND) + message(FATAL_ERROR "D3D12MemoryAllocator not found. Please install it using Conan or disable WISDOM_USE_CONAN.") + endif() + else() + include(${CMAKE_CURRENT_LIST_DIR}/deps/deps_win.cmake) + endif() endif () # Vulkan dependencies diff --git a/cmake/deps/deps_vulkan.cmake b/cmake/deps/deps_vulkan.cmake index 5a79db4be..164731525 100644 --- a/cmake/deps/deps_vulkan.cmake +++ b/cmake/deps/deps_vulkan.cmake @@ -1,14 +1,21 @@ -if (NOT vkma_SOURCE_DIR) - CPMAddPackage( - NAME vkma - GITHUB_REPOSITORY GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator - GIT_TAG v3.3.0 - DOWNLOAD_ONLY TRUE - ) - set(vkma_SOURCE_DIR ${vkma_SOURCE_DIR} CACHE INTERNAL "") -else () - message("Vulkan Memory Allocator found, skipping download.") -endif () +if (WISDOM_USE_CONAN) + find_package(VulkanMemoryAllocator CONFIG QUIET) + if (NOT VulkanMemoryAllocator_FOUND) + message(FATAL_ERROR "Vulkan Memory Allocator not found. Please install it using Conan or disable WISDOM_USE_CONAN.") + endif() +else() + if (NOT vkma_SOURCE_DIR) + CPMAddPackage( + NAME vkma + GITHUB_REPOSITORY GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator + GIT_TAG v3.3.0 + DOWNLOAD_ONLY TRUE + ) + set(vkma_SOURCE_DIR ${vkma_SOURCE_DIR} CACHE INTERNAL "") + else () + message("Vulkan Memory Allocator found, skipping download.") + endif () +endif() # Generate a cpp file that includes the implementation if (NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/vma.cpp) @@ -16,19 +23,16 @@ if (NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/vma.cpp) "#define VMA_IMPLEMENTATION\n#include \"vk_mem_alloc.h\"\n") endif () -add_library(vkma STATIC ${vkma_SOURCE_DIR}/include/vk_mem_alloc.h ${CMAKE_CURRENT_BINARY_DIR}/vma.cpp) -target_link_libraries(vkma PUBLIC Vulkan::Headers) +add_library(vkma STATIC ${CMAKE_CURRENT_BINARY_DIR}/vma.cpp) target_compile_definitions( vkma PRIVATE VK_NO_PROTOTYPES VMA_STATIC_VULKAN_FUNCTIONS=0 VMA_DYNAMIC_VULKAN_FUNCTIONS=0) + if (WISDOM_WINDOWS) target_compile_definitions(vkma PUBLIC VK_USE_PLATFORM_WIN32_KHR VMA_EXTERNAL_MEMORY_WIN32) endif (WISDOM_WINDOWS) -target_include_directories( - vkma PUBLIC $ - $) set_target_properties(vkma PROPERTIES CXX_STANDARD 20 DEBUG_POSTFIX d @@ -44,5 +48,14 @@ install( LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) -install(DIRECTORY ${vkma_SOURCE_DIR}/include/ +if (WISDOM_USE_CONAN) + # Conan already links Vulkan::Headers + target_link_libraries(vkma PUBLIC GPUOpen::VulkanMemoryAllocator) +else() + target_link_libraries(vkma PUBLIC Vulkan::Headers) + target_include_directories( + vkma PUBLIC $ + $) + install(DIRECTORY ${vkma_SOURCE_DIR}/include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/vkma) +endif() diff --git a/cmake/deps/deps_win.cmake b/cmake/deps/deps_win.cmake index 2e06d4741..f051a0e5d 100644 --- a/cmake/deps/deps_win.cmake +++ b/cmake/deps/deps_win.cmake @@ -68,20 +68,21 @@ else () endif () -add_library(DX12Allocator STATIC ${dxma_SOURCE_DIR}/include/D3D12MemAlloc.h) -target_sources(DX12Allocator PRIVATE ${dxma_SOURCE_DIR}/src/D3D12MemAlloc.cpp) -target_link_libraries(DX12Allocator PUBLIC DX12Helpers) +add_library(D3D12MemoryAllocator STATIC ${dxma_SOURCE_DIR}/include/D3D12MemAlloc.h) +add_library(GPUOpen::D3D12MemoryAllocator ALIAS D3D12MemoryAllocator) +target_sources(D3D12MemoryAllocator PRIVATE ${dxma_SOURCE_DIR}/src/D3D12MemAlloc.cpp) +target_link_libraries(D3D12MemoryAllocator PUBLIC DX12Helpers) target_include_directories( - DX12Allocator PUBLIC $ + D3D12MemoryAllocator PUBLIC $ $) -set_target_properties(DX12Allocator PROPERTIES +set_target_properties(D3D12MemoryAllocator PROPERTIES CXX_STANDARD 20 DEBUG_POSTFIX d ) install( - TARGETS DX12Allocator + TARGETS D3D12MemoryAllocator EXPORT wisdom-targets LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/conanfile.py b/conanfile.py index 4921525e9..1511d0396 100644 --- a/conanfile.py +++ b/conanfile.py @@ -40,8 +40,11 @@ def set_version(self): self.version = "0.0.0" def requirements(self): - #self.requires("d3d12-memory-allocator/3.0.1", transitive_headers=True) - pass + # If windows platform support is enabled, we need to require the D3D12 Memory Allocator + # Uncomment once #30026 is merged + #if self.settings.os == "Windows": + #self.requires("d3d12-memory-allocator/3.1.0", transitive_headers=True) + self.requires("vulkan-memory-allocator/3.3.0", transitive_headers=True) def export_sources(self): copy( @@ -97,6 +100,7 @@ def generate(self): tc.variables["WISDOM_BUILD_SHARED"] = self.options.get_safe("shared") and not is_header_only tc.variables["WISDOM_BUILD_PLATFORM"] = self.options.build_platform tc.variables["WISDOM_USE_AGILITY_SDK"] = False + # tc.variables["WISDOM_USE_CONAN"] = True tc.variables["WISDOM_DOWNLOAD_DXC"] = False tc.variables["CMAKE_UNITY_BUILD"] = True tc.user_presets_path = "" diff --git a/src/include/CMakeLists.txt b/src/include/CMakeLists.txt index 856038dd8..dd653b214 100644 --- a/src/include/CMakeLists.txt +++ b/src/include/CMakeLists.txt @@ -14,7 +14,7 @@ if(WISDOM_DX12) DXGI DXGUID d3d12 - DX12Allocator) + GPUOpen::D3D12MemoryAllocator) list( APPEND From 432ab16ccf84faf1fab213819964155e2a1a59f8 Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Fri, 24 Apr 2026 23:02:41 +0200 Subject: [PATCH 09/10] Improve Conan/CMake integration and dependency handling - Enhance NuGet discovery and fallback in functions.cmake - Rename DX12Allocator to D3D12MemoryAllocator in wisdom.targets - Remove header_only option; default to shared build in conanfile.py - Add d3d12-memory-allocator as a Windows dependency - Always enable WISDOM_USE_CONAN in CMake toolchain - Refactor package_info for correct targets and dependencies - Add Conan integration test scripts and minimal test project - Add CMakeUserPresets.json for Conan/CMake workflows - Improve documentation in address_mode_enum.h - Fix wisdom-platform-shared linkage for shared builds --- cmake/functions.cmake | 38 +++++++++----- cmake/install/wisdom.targets | 2 +- conanfile.py | 76 +++++++++++----------------- docs/wisdom/enum/address_mode_enum.h | 3 ++ scripts/test-all.ps1 | 1 + scripts/test-conan.ps1 | 10 ++++ src/platform/CMakeLists.txt | 2 +- test_package/CMakeLists.txt | 11 ++++ test_package/CMakeUserPresets.json | 9 ++++ test_package/conanfile.py | 32 ++++++++++++ test_package/main.cpp | 9 ++++ 11 files changed, 132 insertions(+), 61 deletions(-) create mode 100644 scripts/test-conan.ps1 create mode 100644 test_package/CMakeLists.txt create mode 100644 test_package/CMakeUserPresets.json create mode 100644 test_package/conanfile.py create mode 100644 test_package/main.cpp diff --git a/cmake/functions.cmake b/cmake/functions.cmake index 34f77e078..5e52e55a4 100644 --- a/cmake/functions.cmake +++ b/cmake/functions.cmake @@ -30,24 +30,36 @@ if (WIN32) if (NOT WISDOM_WINDOWS) return() endif () - - find_program( - NUGET_EXE - NAMES nuget) - - if (NOT NUGET_EXE) - message("NUGET.EXE not found. Downloading...") + + # Check provided with WISDOM_NUGET_PATH + if (WISDOM_NUGET_PATH) find_program( NUGET_EXE NAMES nuget - PATHS ${CMAKE_CURRENT_BINARY_DIR}/NuGet) - - if (NOT NUGET_EXE) - _ww_load_nuget() - set(NUGET_EXE "${CMAKE_CURRENT_BINARY_DIR}/NuGet/NuGet.exe" CACHE INTERNAL "Path to NuGet.exe") + PATHS ${WISDOM_NUGET_PATH}) + if (NUGET_EXE) + message("NUGET.EXE found at WISDOM_NUGET_PATH: ${NUGET_EXE}") + return() endif () - else () + endif() + + find_program( + NUGET_EXE + NAMES nuget) + if (NUGET_EXE) message("NUGET.EXE found: ${NUGET_EXE}") + return() + endif() + + message("NUGET.EXE not found. Downloading...") + find_program( + NUGET_EXE + NAMES nuget + PATHS ${CMAKE_CURRENT_BINARY_DIR}/NuGet) + + if (NOT NUGET_EXE) + _ww_load_nuget() + set(NUGET_EXE "${CMAKE_CURRENT_BINARY_DIR}/NuGet/NuGet.exe" CACHE INTERNAL "Path to NuGet.exe") endif () endfunction(_ww_find_nuget) diff --git a/cmake/install/wisdom.targets b/cmake/install/wisdom.targets index af87e23fd..60f98027c 100644 --- a/cmake/install/wisdom.targets +++ b/cmake/install/wisdom.targets @@ -26,7 +26,7 @@ $(MSBuildThisFileDirectory)..\..\lib\native\x64\wisdom-platform$(LP).lib;%(AdditionalDependencies) $(MSBuildThisFileDirectory)..\..\lib\native\x64\wisdom-platform-shared$(LP).lib;%(AdditionalDependencies) $(MSBuildThisFileDirectory)..\..\lib\native\x64\vkma$(LP).lib;%(AdditionalDependencies) - $(MSBuildThisFileDirectory)..\..\lib\native\x64\DX12Allocator$(LP).lib;$(MSBuildThisFileDirectory)..\..\lib\native\x64\DirectX-Headers$(LP).lib;$(MSBuildThisFileDirectory)..\..\lib\native\x64\DirectX-Guids$(LP).lib;dxguid.lib;DXGI.lib;d3d12.lib;%(AdditionalDependencies) + $(MSBuildThisFileDirectory)..\..\lib\native\x64\D3D12MemoryAllocator$(LP).lib;$(MSBuildThisFileDirectory)..\..\lib\native\x64\DirectX-Headers$(LP).lib;$(MSBuildThisFileDirectory)..\..\lib\native\x64\DirectX-Guids$(LP).lib;dxguid.lib;DXGI.lib;d3d12.lib;%(AdditionalDependencies) diff --git a/conanfile.py b/conanfile.py index 1511d0396..e7cb27c20 100644 --- a/conanfile.py +++ b/conanfile.py @@ -18,15 +18,14 @@ class WisdomConan(ConanFile): "shared": [True, False], "fPIC": [True, False], "build_platform": [True, False], - "header_only": [True, False], } default_options = { - "shared": False, + "shared": True, "fPIC": True, "build_platform": True, - "header_only": False, } + # keep it for now, but remove when we are at CCI def set_version(self): version_file_path = os.path.join(self.recipe_folder, "version/VERSION") @@ -41,9 +40,8 @@ def set_version(self): def requirements(self): # If windows platform support is enabled, we need to require the D3D12 Memory Allocator - # Uncomment once #30026 is merged - #if self.settings.os == "Windows": - #self.requires("d3d12-memory-allocator/3.1.0", transitive_headers=True) + if self.settings.os == "Windows": + self.requires("d3d12-memory-allocator/[>=3.0.1 <4]", transitive_headers=True) self.requires("vulkan-memory-allocator/3.3.0", transitive_headers=True) def export_sources(self): @@ -72,12 +70,9 @@ def config_options(self): self.options.rm_safe("fPIC") def configure(self): - if self.options.shared or self.options.header_only: + if self.options.shared: self.options.rm_safe("fPIC") - if self.options.header_only: - self.options.rm_safe("shared") - def layout(self): cmake_layout(self) @@ -90,20 +85,21 @@ def generate(self): "For Conan Center, those dependencies should be provided as Conan requirements or vendored sources." ) - is_header_only = self.options.get_safe("header_only") - tc = CMakeToolchain(self) tc.variables["WISDOM_BUILD_EXAMPLES"] = False tc.variables["WISDOM_BUILD_TESTS"] = False tc.variables["WISDOM_BUILD_DOCS"] = False - tc.variables["WISDOM_BUILD_STATIC"] = not self.options.get_safe("shared") and not is_header_only - tc.variables["WISDOM_BUILD_SHARED"] = self.options.get_safe("shared") and not is_header_only + tc.variables["WISDOM_BUILD_STATIC"] = not self.options.get_safe("shared") + tc.variables["WISDOM_BUILD_SHARED"] = self.options.get_safe("shared") tc.variables["WISDOM_BUILD_PLATFORM"] = self.options.build_platform tc.variables["WISDOM_USE_AGILITY_SDK"] = False - # tc.variables["WISDOM_USE_CONAN"] = True + tc.variables["WISDOM_USE_CONAN"] = True tc.variables["WISDOM_DOWNLOAD_DXC"] = False tc.variables["CMAKE_UNITY_BUILD"] = True - tc.user_presets_path = "" + + if self.settings.os == "Windows": + tc.preprocessor_definitions["VK_USE_PLATFORM_WIN32_KHR"] = "1" + tc.generate() def build(self): @@ -117,54 +113,42 @@ def package(self): def package_info(self): # The overarching file namespace (find_package(wisdom)) - self.cpp_info.set_property("cmake_file_name", "wisdom") + self.cpp_info.set_property("cmake_file_name", "Wisdom") build_modules = ["lib/cmake/wisdom/functions.cmake"] self.cpp_info.set_property("cmake_build_modules", build_modules) - # --------------------------------------------------------- - # 1. HEADER-ONLY TARGETS (Always Available) - # --------------------------------------------------------- - - # Core Headers (wis::wisdom-headers) - self.cpp_info.components["headers"].set_property("cmake_target_name", "wis::wisdom-headers") - self.cpp_info.components["headers"].bindirs = [] - self.cpp_info.components["headers"].libdirs = [] - - # Platform Headers (wis::wisdom-platform-headers) - if self.options.build_platform: - self.cpp_info.components["platform_headers"].set_property("cmake_target_name", "wis::wisdom-platform-headers") - self.cpp_info.components["platform_headers"].requires = ["headers"] - self.cpp_info.components["platform_headers"].bindirs = [] - self.cpp_info.components["platform_headers"].libdirs = [] - - # If header_only is True, we stop here. No compiled libs are added. - if self.options.get_safe("header_only"): - return - - # --------------------------------------------------------- - # 2. COMPILED TARGETS (Static OR Shared) - # --------------------------------------------------------- + + # Targets: suffix = "d" if self.settings.build_type == "Debug" else "" if self.options.get_safe("shared"): # Core Shared self.cpp_info.components["core"].set_property("cmake_target_name", "wis::wisdom-shared") - self.cpp_info.components["core"].requires = ["headers"] self.cpp_info.components["core"].libs = [f"wisdom-shared{suffix}"] # Platform Shared if self.options.build_platform: self.cpp_info.components["platform"].set_property("cmake_target_name", "wis::wisdom-platform-shared") - self.cpp_info.components["platform"].requires = ["core", "platform_headers"] + self.cpp_info.components["platform"].requires = ["core"] self.cpp_info.components["platform"].libs = [f"wisdom-platform-shared{suffix}"] else: # Core Static self.cpp_info.components["core"].set_property("cmake_target_name", "wis::wisdom") - self.cpp_info.components["core"].requires = ["headers"] - self.cpp_info.components["core"].libs = [f"wisdom{suffix}"] + self.cpp_info.components["core"].libs = [f"wisdom{suffix}", f"vkma{suffix}"] # Platform Static if self.options.build_platform: self.cpp_info.components["platform"].set_property("cmake_target_name", "wis::wisdom-platform") - self.cpp_info.components["platform"].requires = ["core", "platform_headers"] - self.cpp_info.components["platform"].libs = [f"wisdom-platform{suffix}"] \ No newline at end of file + self.cpp_info.components["platform"].requires = ["core"] + self.cpp_info.components["platform"].libs = [f"wisdom-platform{suffix}"] + + self.cpp_info.components["core"].requires = ["vulkan-memory-allocator::vulkan-memory-allocator"] + if self.settings.os == "Windows": + self.cpp_info.components["core"].defines.extend([ + "D3D12MA_USING_DIRECTX_HEADERS=1", + "VK_USE_PLATFORM_WIN32_KHR=1", + ]) + self.cpp_info.components["core"].requires.extend([ + "d3d12-memory-allocator::d3d12-memory-allocator" + ]) + self.cpp_info.components["core"].system_libs.extend(["dxgi", "DXGUID"]) \ No newline at end of file diff --git a/docs/wisdom/enum/address_mode_enum.h b/docs/wisdom/enum/address_mode_enum.h index e205c7443..126d1f03e 100644 --- a/docs/wisdom/enum/address_mode_enum.h +++ b/docs/wisdom/enum/address_mode_enum.h @@ -4,6 +4,9 @@ * * @section WisAddressMode_spec Specification *
+ * + * Possible values for texture address mode. Used in `WisSamplerDesc` to specify how texture coordinates outside the [0, + * 1] range are handled. * * \cond WIS_GEN_CODE * C version: diff --git a/scripts/test-all.ps1 b/scripts/test-all.ps1 index 7f07796a0..4d52f5ce2 100644 --- a/scripts/test-all.ps1 +++ b/scripts/test-all.ps1 @@ -11,6 +11,7 @@ $steps = @( @{ Name = 'Build and run unit tests'; Script = Join-Path $scriptRoot 'test-unit.ps1' }, @{ Name = 'Run ZIP (CMake) integration test'; Script = Join-Path $scriptRoot 'test-cmake.ps1' }, @{ Name = 'Run NuGet integration test'; Script = Join-Path $scriptRoot 'test-nuget.ps1' } + @{ Name = 'Run Conan integration test'; Script = Join-Path $scriptRoot 'test-conan.ps1' } ) function Invoke-TestStep { diff --git a/scripts/test-conan.ps1 b/scripts/test-conan.ps1 new file mode 100644 index 000000000..214be91fe --- /dev/null +++ b/scripts/test-conan.ps1 @@ -0,0 +1,10 @@ +# 0. Get the script's directory +$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$TestDir = Join-Path $ScriptDir "..\tests\integration\conan" +$BaseDir = Join-Path $ScriptDir "\.." + +# 1. Test Static +conan create $BaseDir --build=missing + +# 2. Test Shared +conan create $BaseDir -o "wisdom/*:shared=True" \ No newline at end of file diff --git a/src/platform/CMakeLists.txt b/src/platform/CMakeLists.txt index 82170c5ea..c42171aaa 100644 --- a/src/platform/CMakeLists.txt +++ b/src/platform/CMakeLists.txt @@ -67,7 +67,7 @@ if(WISDOM_BUILD_SHARED) add_library(wisdom-platform-shared SHARED ${WISDOM_PLATFORM_SOURCES}) add_library(wis::wisdom-platform-shared ALIAS wisdom-platform-shared) - target_link_libraries(wisdom-platform-shared PRIVATE wisdom) + target_link_libraries(wisdom-platform-shared PRIVATE wisdom-shared) target_include_directories( wisdom-platform-shared PUBLIC $ diff --git a/test_package/CMakeLists.txt b/test_package/CMakeLists.txt new file mode 100644 index 000000000..96bbfd8d0 --- /dev/null +++ b/test_package/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.22) + +project(TestApp) +find_package(Wisdom REQUIRED) + +add_executable(test_app main.cpp) +if(WISDOM_IS_SHARED) + target_link_libraries(test_app PRIVATE wis::wisdom-shared) +else() + target_link_libraries(test_app PRIVATE wis::wisdom) +endif() diff --git a/test_package/CMakeUserPresets.json b/test_package/CMakeUserPresets.json new file mode 100644 index 000000000..eafe17862 --- /dev/null +++ b/test_package/CMakeUserPresets.json @@ -0,0 +1,9 @@ +{ + "version": 4, + "vendor": { + "conan": {} + }, + "include": [ + "build/msvc-195-x86_64-20-release/generators/CMakePresets.json" + ] +} \ No newline at end of file diff --git a/test_package/conanfile.py b/test_package/conanfile.py new file mode 100644 index 000000000..9cf9befcc --- /dev/null +++ b/test_package/conanfile.py @@ -0,0 +1,32 @@ +import os +from conan import ConanFile +from conan.tools.cmake import CMake, cmake_layout, CMakeToolchain +from conan.tools.build import can_run + +class WisdomTestConan(ConanFile): + settings = "os", "compiler", "build_type", "arch" + generators = "CMakeDeps" + + def requirements(self): + self.requires(self.tested_reference_str) + + def layout(self): + cmake_layout(self) + + def generate(self): + tc = CMakeToolchain(self) + # Check if the wisdom package we are testing was built as shared + is_shared = self.dependencies["wisdom"].options.shared + # Pass that info to CMake! + tc.variables["WISDOM_IS_SHARED"] = is_shared + tc.generate() + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + def test(self): + if can_run(self): + cmd = os.path.join(self.cpp.build.bindir, "test_app") + self.run(cmd, env="conanrun") \ No newline at end of file diff --git a/test_package/main.cpp b/test_package/main.cpp new file mode 100644 index 000000000..a15ed5c95 --- /dev/null +++ b/test_package/main.cpp @@ -0,0 +1,9 @@ +#include + +int main() +{ + wis::Result result{}; + wis::DebugDesc debug_desc{true}; + wis::Instance instance = wis::CreateInstance(&debug_desc, {}, result); + return 0; +} \ No newline at end of file From 3efd3521bbf3a8ae25b921bcdadb012f526bb6b4 Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Sun, 13 Sep 2026 15:55:51 +0200 Subject: [PATCH 10/10] Preparation for new dev strategy --- src/include/wisdom/vulkan/vk_swapchain.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/include/wisdom/vulkan/vk_swapchain.cpp b/src/include/wisdom/vulkan/vk_swapchain.cpp index 9a8e99fab..551d5b72a 100644 --- a/src/include/wisdom/vulkan/vk_swapchain.cpp +++ b/src/include/wisdom/vulkan/vk_swapchain.cpp @@ -344,6 +344,9 @@ WIS_EXTERN_C WISDOM_API WisResult wisVKSwapchainGetTextures( new (&tex) wis::impl::VKTextureImpl{ .image = image, + .width = static_cast(impl.swapchain_header->header.create_info.imageExtent.width), + .height = static_cast(impl.swapchain_header->header.create_info.imageExtent.height), + .depth_or_array_size = static_cast(impl.swapchain_header->header.create_info.imageArrayLayers), .owned_by_swapchain = true, }; }