From 2ec80a78adcbf13b354a3547502951224ffa5e09 Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Mon, 20 Apr 2026 12:33:52 +0200 Subject: [PATCH 01/49] 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 5329c00146d367efa39dcb633a80cca97e1c6da3 Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Mon, 20 Apr 2026 21:33:09 +0200 Subject: [PATCH 02/49] 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 b2c352ddcb9af80a9cb7f26924d6ca80e1bfbdcb Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Tue, 21 Apr 2026 21:58:42 +0200 Subject: [PATCH 03/49] 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 a7bd138e042cca3d1c17f21fa41df5b96c4f1379 Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Wed, 22 Apr 2026 10:47:07 +0200 Subject: [PATCH 04/49] 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 d6ea1d3e886fb6ebe2c930b3d5d4b2b1b76132ff Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Wed, 22 Apr 2026 17:55:29 +0200 Subject: [PATCH 05/49] 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 2ff8d65ba1065a95f3d7b77adbb84a6fb2f91cc4 Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Thu, 23 Apr 2026 21:45:40 +0200 Subject: [PATCH 06/49] 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 a189ce32b87463e170727886315275d862f4e3fc Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Thu, 23 Apr 2026 23:59:15 +0200 Subject: [PATCH 07/49] 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 222d07074e79925f1740ffba0c23d83765d931ea Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Fri, 24 Apr 2026 09:58:14 +0200 Subject: [PATCH 08/49] 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 c7a557476a8c4e449ea2c19759e75bde674dd725 Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Fri, 24 Apr 2026 23:02:41 +0200 Subject: [PATCH 09/49] 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 52c2cc5b6115df33bf78eccb989412db7a2c95f2 Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Sat, 25 Apr 2026 13:18:42 +0200 Subject: [PATCH 10/49] Add Raytracing extension with DX12/Vulkan support Introduced a new Raytracing extension for Wisdom, providing C and C++ APIs for both DirectX 12 and Vulkan backends. Added CMake options and build logic for static/shared/header-only builds. Implemented platform-specific initialization, destruction, and support-checking functions. Generated and documented new API headers. Added tests for extension lifecycle and support detection. Updated build scripts and XML registry to integrate the new extension. Ensured proper resource management and handle validity. --- CMakeLists.txt | 5 + .../destroy_raytracing_extension_function.h | 49 ++++++++ .../func/init_raytracing_extension_function.h | 74 +++++++++++ .../raytracing_extension_supported_function.h | 66 ++++++++++ .../handle/raytracing_extension_handle.h | 30 +++++ generator/constant.cpp | 3 +- generator/generator.cpp | 4 +- src/CMakeLists.txt | 2 + src/extensions/CMakeLists.txt | 9 ++ src/extensions/raytracing/CMakeLists.txt | 116 ++++++++++++++++++ .../raytracing/dx12/dx12_raytracing.cpp | 51 ++++++++ .../raytracing/raytracing/dx12/dx12_types.hpp | 27 ++++ .../raytracing/raytracing/generated/c_api.h | 76 ++++++++++++ .../raytracing/generated/cpp_api.hpp | 87 +++++++++++++ .../raytracing/vulkan/vk_raytracing.cpp | 107 ++++++++++++++++ .../raytracing/vulkan/vk_tables.hpp | 40 ++++++ .../raytracing/raytracing/vulkan/vk_types.hpp | 30 +++++ .../raytracing/wisdom/wisdom_raytracing.h | 65 ++++++++++ .../raytracing/wisdom/wisdom_raytracing.hpp | 45 +++++++ .../dx12/dx12_platform_uwp.cpp | 1 + .../dx12/dx12_platform_win32.cpp | 1 + .../vulkan/vk_platform_wayland.cpp | 1 + .../vulkan/vk_platform_win32.cpp | 1 + .../vulkan/vk_platform_xcb.cpp | 1 + .../vulkan/vk_platform_xlib.cpp | 1 + tests/CMakeLists.txt | 4 +- tests/basic/CMakeLists.txt | 10 +- tests/basic/platform_check.cpp | 13 ++ tests/basic/rt_basic.cpp | 55 +++++++++ xml/raytracing.xml | 19 +++ 30 files changed, 986 insertions(+), 7 deletions(-) create mode 100644 docs/raytracing/func/destroy_raytracing_extension_function.h create mode 100644 docs/raytracing/func/init_raytracing_extension_function.h create mode 100644 docs/raytracing/func/raytracing_extension_supported_function.h create mode 100644 docs/raytracing/handle/raytracing_extension_handle.h create mode 100644 src/extensions/CMakeLists.txt create mode 100644 src/extensions/raytracing/CMakeLists.txt create mode 100644 src/extensions/raytracing/raytracing/dx12/dx12_raytracing.cpp create mode 100644 src/extensions/raytracing/raytracing/dx12/dx12_types.hpp create mode 100644 src/extensions/raytracing/raytracing/generated/c_api.h create mode 100644 src/extensions/raytracing/raytracing/generated/cpp_api.hpp create mode 100644 src/extensions/raytracing/raytracing/vulkan/vk_raytracing.cpp create mode 100644 src/extensions/raytracing/raytracing/vulkan/vk_tables.hpp create mode 100644 src/extensions/raytracing/raytracing/vulkan/vk_types.hpp create mode 100644 src/extensions/raytracing/wisdom/wisdom_raytracing.h create mode 100644 src/extensions/raytracing/wisdom/wisdom_raytracing.hpp create mode 100644 tests/basic/rt_basic.cpp create mode 100644 xml/raytracing.xml diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e1ef968b..7c05fc8bc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,11 @@ set(WISDOM_VULKAN_HEADER_PATH "" CACHE PATH "Path to custom Vulkan Headers (optional)") +# Conan includes Vulkan Headers. +if (WISDOM_USE_CONAN) + set(WISDOM_VULKAN ON) +endif() + # Load all dependencies include(cmake/deps.cmake) include(cmake/doc.cmake) diff --git a/docs/raytracing/func/destroy_raytracing_extension_function.h b/docs/raytracing/func/destroy_raytracing_extension_function.h new file mode 100644 index 000000000..5071aa82b --- /dev/null +++ b/docs/raytracing/func/destroy_raytracing_extension_function.h @@ -0,0 +1,49 @@ +/** + * @struct wisDestroyRaytracingExtension + * @ingroup Functions Raytracing + * + * Destroys a WisRaytracingExtension handle. This function should be called to clean up any resources associated with + * the raytracing extension when it is no longer needed. + * + * @section wisDestroyRaytracingExtension_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C Version: + * ```c + * // Provided by Wisdom 0.7.1. + * void wisDestroyRaytracingExtension(WisRaytracingExtension* self); + * ``` + *
+ * C Implementation Specific Version: + * ```c + * // Provided by Wisdom 0.7.1. + * void wisVKDestroyRaytracingExtension(WisVKRaytracingExtension* self); + * + * // Provided by Wisdom 0.7.1. + * void wisDX12DestroyRaytracingExtension(WisDX12RaytracingExtension* self); + * ``` + *
+ * + * \endcond + * + * @section wisDestroyRaytracingExtension_memb Parameters + *
+ * \cond WIS_GEN_DESC + * - **this** `self` self is a pointer to the valid WisRaytracingExtension instance. + * \endcond + * + * @section wisDestroyRaytracingExtension_descr Description + *
+ * + * \note WisRaytracingExtension references device. That means the device resources will not be released until the + * extension is destroyed. + * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section wisDestroyRaytracingExtension_see_also See Also + *
+ * \cond WIS_GEN_REFS + * \endcond + */ diff --git a/docs/raytracing/func/init_raytracing_extension_function.h b/docs/raytracing/func/init_raytracing_extension_function.h new file mode 100644 index 000000000..0b62c3976 --- /dev/null +++ b/docs/raytracing/func/init_raytracing_extension_function.h @@ -0,0 +1,74 @@ +/** + * @struct wisInitRaytracingExtension + * @ingroup Functions Raytracing + * + * Initializes a WisRaytracingExtension handle. This function must be called before passing the handle to the + * `WisDeviceRequirements` when creating a device. It sets up the necessary state for the raytracing extension to be + * used on a device. + * + * @section wisInitRaytracingExtension_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C Version: + * ```c + * // Provided by Wisdom 0.7.1. + * void wisInitRaytracingExtension(WisRaytracingExtension* self); + * ``` + *
+ * C Implementation Specific Version: + * ```c + * // Provided by Wisdom 0.7.1. + * void wisVKInitRaytracingExtension(WisVKRaytracingExtension* self); + * + * // Provided by Wisdom 0.7.1. + * void wisDX12InitRaytracingExtension(WisDX12RaytracingExtension* self); + * ``` + *
+ * + * C++ Version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * void RaytracingExtension::InitRaytracingExtension() noexcept; + * } + * ``` + *
+ * C++ Implementation Specific Version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * void VKRaytracingExtension::InitRaytracingExtension() noexcept; + * + * // Provided by Wisdom 0.7.1. + * void DX12RaytracingExtension::InitRaytracingExtension() noexcept; + * } + * ``` + *
+ * \endcond + * + * @section wisInitRaytracingExtension_memb Parameters + *
+ * \cond WIS_GEN_DESC + * - **this** `self` is a pointer to uninitialized WisRaytracingExtension instance memory. It will be initialized by + * this function. + * **note** The corresponding destroy function is `wisDestroyRaytracingExtension`. + * \endcond + * + * @section wisInitRaytracingExtension_descr Description + *
+ * + * Passing an uninitialized handle to `WisDeviceRequirements` when creating a device will not enable raytracing features + * on the device. + * + * \note WisRaytracingExtension references device. That means the device resources will not be released until the + * extension is destroyed. + * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section wisInitRaytracingExtension_see_also See Also + *
+ * \cond WIS_GEN_REFS + * \endcond + */ diff --git a/docs/raytracing/func/raytracing_extension_supported_function.h b/docs/raytracing/func/raytracing_extension_supported_function.h new file mode 100644 index 000000000..d25a86bfe --- /dev/null +++ b/docs/raytracing/func/raytracing_extension_supported_function.h @@ -0,0 +1,66 @@ +/** + * @struct wisRaytracingExtensionSupported + * @ingroup Functions Raytracing + * + * To check if raytracing is supported on a device, you can use the `wisRaytracingExtensionSupported` function. + * + * @section wisRaytracingExtensionSupported_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * * C Version: + * ```c + * // Provided by Wisdom 0.7.1. + * bool wisRaytracingExtensionSupported(WisRaytracingExtension* self); + * ``` + *
+ * C Implementation Specific Version: + * ```c + * // Provided by Wisdom 0.7.1. + * bool wisVKRaytracingExtensionSupported(WisVKRaytracingExtension* self); + * + * // Provided by Wisdom 0.7.1. + * bool wisDX12RaytracingExtensionSupported(WisDX12RaytracingExtension* self); + * ``` + *
+ * + * C++ Version: + * ```cpp + * namespace wis + * ``` + *
+ * C++ Implementation Specific Version: + * ```cpp + * namespace wis + * ``` + *
+ * + * \endcond + * + * @section wisRaytracingExtensionSupported_memb Parameters + *
+ * \cond WIS_GEN_DESC + * * - **this** `self` self is a pointer to the valid WisRaytracingExtension instance. + * + * - **return** true if raytracing is supported, false otherwise. + * + * \endcond + * + * @section wisRaytracingExtensionSupported_descr Description + *
+ * + * This function must be called after device creation, where the handle is passed to the `WisDeviceRequirements` when + * creating the device. It checks if raytracing is supported on the current device and returns a boolean value indicating the + * result. + * + * The result is not cached, so the call may be expensive. It is recommended to call this function once and cache the + * result if you need to check for raytracing support multiple times. + * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section wisRaytracingExtensionSupported_see_also See Also + *
+ * \cond WIS_GEN_REFS + * \endcond + */ diff --git a/docs/raytracing/handle/raytracing_extension_handle.h b/docs/raytracing/handle/raytracing_extension_handle.h new file mode 100644 index 000000000..4f297865f --- /dev/null +++ b/docs/raytracing/handle/raytracing_extension_handle.h @@ -0,0 +1,30 @@ +/** + * @struct WisRaytracingExtension + * @ingroup Handles Raytracing + * + * Represents the raytracing extension for a graphics API. This handle is used to check for raytracing support and to + * initialize raytracing features on a device. + * + * @section WisRaytracingExtension_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * Vulkan Version: + * ```c + * // Provided by Wisdom 0.7.1. + * WIS_DEFINE_VK_DEVICE_EXT_HANDLE(WisVKRaytracingExtension,5); + * ``` + * DX12 Version: + * ```c + * // Provided by Wisdom 0.7.1. + * WIS_DEFINE_DX12_DEVICE_EXT_HANDLE(WisDX12RaytracingExtension,2); + * ``` + * \endcond + * + * @section WisRaytracingExtension_see_also See Also + *
+ * \cond WIS_GEN_REFS + * @see Functions: + * wisDestroyRaytracingExtension, wisInitRaytracingExtension, wisRaytracingExtensionSupported + * \endcond + */ diff --git a/generator/constant.cpp b/generator/constant.cpp index 7ea110eea..5272582ae 100644 --- a/generator/constant.cpp +++ b/generator/constant.cpp @@ -126,7 +126,6 @@ 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; @@ -136,6 +135,8 @@ void Generator::WriteConstantDocumentation(std::filesystem::path const_output_pa return; } + files.push_back(const_file_path); + for (auto& const_name : constant_names) { auto& const_ref = constant_map[const_name]; all_c_code += MakeCConstant(const_ref, DocKind::VersionOnly); diff --git a/generator/generator.cpp b/generator/generator.cpp index f3cca7168..09d726e9a 100644 --- a/generator/generator.cpp +++ b/generator/generator.cpp @@ -186,7 +186,7 @@ void Generator::WriteCAPI(std::filesystem::path dir) bool has_independent_api = !module.enums_in_order.empty() || !module.bitmasks_in_order.empty() || !module.structs_in_order.empty() || !module.constants_in_order.empty() - || !module.delegates_in_order.empty(); + || !module.delegates_in_order.empty() || !module.functions_in_order.empty(); auto path = dir / "c_api.h"; if (!has_independent_api) { @@ -368,7 +368,7 @@ void Generator::WriteCPPAPI(std::filesystem::path dir) auto& module = module_map.at(active_module_name); bool has_independent_api = !module.enums_in_order.empty() || !module.bitmasks_in_order.empty() || !module.structs_in_order.empty() || !module.constants_in_order.empty() - || !module.delegates_in_order.empty(); + || !module.delegates_in_order.empty() || !module.functions_in_order.empty(); auto path = dir / "cpp_api.hpp"; if (!has_independent_api) { diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c1248abfa..0db81f93f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,3 +4,5 @@ add_subdirectory(include) if(WISDOM_BUILD_PLATFORM) add_subdirectory(platform) endif() + +add_subdirectory(extensions) diff --git a/src/extensions/CMakeLists.txt b/src/extensions/CMakeLists.txt new file mode 100644 index 000000000..5362f05f5 --- /dev/null +++ b/src/extensions/CMakeLists.txt @@ -0,0 +1,9 @@ +# Each extension will provide an option to build it + +# Extensions + +# Ray Tracing +option(WISDOM_BUILD_RAYTRACING "Build the Ray Tracing extension." ON) +if (WISDOM_BUILD_RAYTRACING) + add_subdirectory(raytracing) +endif() \ No newline at end of file diff --git a/src/extensions/raytracing/CMakeLists.txt b/src/extensions/raytracing/CMakeLists.txt new file mode 100644 index 000000000..59d7ee773 --- /dev/null +++ b/src/extensions/raytracing/CMakeLists.txt @@ -0,0 +1,116 @@ +set(WISDOM_RAYTRACING_SOURCES) + +if(WISDOM_DX12) + list(APPEND WISDOM_RAYTRACING_SOURCES + "raytracing/dx12/dx12_raytracing.cpp") +endif() + +if(WISDOM_VULKAN) + list( + APPEND + WISDOM_RAYTRACING_SOURCES + "raytracing/vulkan/vk_raytracing.cpp") +endif() + +# Platform header target +add_library(wisdom-raytracing-headers INTERFACE) +add_library(wis::wisdom-raytracing-headers ALIAS wisdom-raytracing-headers) + +target_include_directories( + wisdom-raytracing-headers + INTERFACE $ + $) + +target_link_libraries(wisdom-raytracing-headers INTERFACE wis::wisdom-headers) +target_compile_definitions( + wisdom-raytracing-headers INTERFACE WISDOM_RAYTRACING_STATIC=1) + +install( + TARGETS wisdom-raytracing-headers + EXPORT wisdom-raytracing-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + INCLUDES + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + +# Platform library target +if(WISDOM_BUILD_STATIC) + add_library(wisdom-raytracing STATIC ${WISDOM_RAYTRACING_SOURCES}) + add_library(wis::wisdom-raytracing ALIAS wisdom-raytracing) + + target_link_libraries(wisdom-raytracing PRIVATE wisdom) + target_compile_definitions(wisdom-raytracing PUBLIC WISDOM_RAYTRACING_STATIC=1) + target_include_directories( + wisdom-raytracing PUBLIC $ + $) + + set_target_properties( + wisdom-raytracing PROPERTIES CXX_STANDARD 20 + DEBUG_POSTFIX d) + + install( + TARGETS wisdom-raytracing + EXPORT wisdom-raytracing-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + INCLUDES + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +endif() + +if(WISDOM_BUILD_SHARED) + add_library(wisdom-raytracing-shared SHARED ${WISDOM_RAYTRACING_SOURCES}) + add_library(wis::wisdom-raytracing-shared ALIAS wisdom-raytracing-shared) + + target_link_libraries(wisdom-raytracing-shared PRIVATE wisdom-shared) + target_include_directories( + wisdom-raytracing-shared + PUBLIC $ + $) + target_compile_definitions( + wisdom-raytracing-shared + PUBLIC WISDOM_RAYTRACING_SHARED_LIBRARY=1 + PRIVATE raytracing_shared_EXPORTS=1) + + set_target_properties( + wisdom-raytracing-shared + PROPERTIES CXX_STANDARD 20 + POSITION_INDEPENDENT_CODE ON + DEBUG_POSTFIX d) + + include(GenerateExportHeader) + generate_export_header( + wisdom-raytracing-shared + BASE_NAME + WISDOM_RAYTRACING + EXPORT_MACRO_NAME + WISDOM_RAYTRACING_API + EXPORT_FILE_NAME + ${CMAKE_CURRENT_SOURCE_DIR}/raytracing/generated/wisdom_exports.h + STATIC_DEFINE + WISDOM_RAYTRACING_STATIC + INCLUDE_GUARD_NAME + WISDOM_RAYTRACING_EXPORTS_H) + + install( + TARGETS wisdom-raytracing-shared + EXPORT wisdom-raytracing-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + INCLUDES + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +endif() + +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/raytracing/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/raytracing) + +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/wisdom/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/wisdom) + +install( + EXPORT wisdom-raytracing-targets + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/wisdom + NAMESPACE wis:: + FILE wisdom-raytracing-targets.cmake) diff --git a/src/extensions/raytracing/raytracing/dx12/dx12_raytracing.cpp b/src/extensions/raytracing/raytracing/dx12/dx12_raytracing.cpp new file mode 100644 index 000000000..9aabd8432 --- /dev/null +++ b/src/extensions/raytracing/raytracing/dx12/dx12_raytracing.cpp @@ -0,0 +1,51 @@ +#ifndef WIS_DX12_RAYTRACING_CPP +#define WIS_DX12_RAYTRACING_CPP + +#include +#include + +namespace wis::detail { +inline WisResult DX12RaytracingExtensionInit( + wis::DX12DeviceExtensionHeader* self, + const wis::impl::DX12DeviceImpl& device +) noexcept +{ + auto& impl = wis::from_handle_ref(self); + impl.device = device.device; + impl.device->AddRef(); // AddRef factory to ensure it lives as long as the extension + return wis::detail::dx_success; +} +} // namespace wis::detail + +WIS_EXTERN_C WISDOM_RAYTRACING_API void wisDX12InitRaytracingExtension(WisDX12RaytracingExtension* self) +{ + new (self) wis::impl::DX12RaytracingExtensionImpl{ + .header = {&wis::detail::DX12RaytracingExtensionInit}, + }; +} + +WIS_EXTERN_C WISDOM_RAYTRACING_API void wisDX12DestroyRaytracingExtension(WisDX12RaytracingExtension* self) +{ + auto& impl = wis::from_handle_ref(self); + if (impl.device) { + impl.device->Release(); + impl.device = nullptr; + } + impl.header = {nullptr}; +} + +WIS_EXTERN_C WISDOM_RAYTRACING_API bool wisDX12RaytracingExtensionSupported(WisDX12RaytracingExtension* self) +{ + auto& impl = wis::from_handle_ref(self); + if (!impl.device) { + return false; + } + D3D12_FEATURE_DATA_D3D12_OPTIONS5 options5{}; + HRESULT hr = impl.device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS5, &options5, sizeof(options5)); + if (FAILED(hr)) { + return false; + } + return options5.RaytracingTier != D3D12_RAYTRACING_TIER_NOT_SUPPORTED; +} + +#endif diff --git a/src/extensions/raytracing/raytracing/dx12/dx12_types.hpp b/src/extensions/raytracing/raytracing/dx12/dx12_types.hpp new file mode 100644 index 000000000..24214c25a --- /dev/null +++ b/src/extensions/raytracing/raytracing/dx12/dx12_types.hpp @@ -0,0 +1,27 @@ +#ifndef WIS_DX12_RAYTRACING_TYPES_HPP +#define WIS_DX12_RAYTRACING_TYPES_HPP +#ifndef __cplusplus +# error "This header requires C++" +#endif // __cplusplus + +namespace wis { +//---------------------------------------------------------------------------------------------------------------------- +namespace detail {} // namespace detail + +namespace impl { +struct DX12RaytracingExtensionImpl { + DX12DeviceExtensionHeader header; + ID3D12Device* device; +}; +} // namespace impl +} // namespace wis + +// Include implementation for header-only mode +#ifdef WISDOM_HEADER_ONLY +# if !WIS_HAS_CPP20 && !defined(WISDOM_LANG_DISABLE_CHECK) +# error "C++20 is required to build wisdom as header-only library" +# endif // !WIS_HAS_CPP20 +# include "dx12_raytracing.cpp" + +#endif // WISDOM_HEADER_ONLY +#endif // WIS_DX12_PLATFORM_TYPES_HPP diff --git a/src/extensions/raytracing/raytracing/generated/c_api.h b/src/extensions/raytracing/raytracing/generated/c_api.h new file mode 100644 index 000000000..586daccc9 --- /dev/null +++ b/src/extensions/raytracing/raytracing/generated/c_api.h @@ -0,0 +1,76 @@ +// This file is generated. Do not edit directly. +#ifndef WISDOM_RAYTRACING_C_API_H +#define WISDOM_RAYTRACING_C_API_H +#include +#include "wisdom_exports.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#ifdef WISDOM_DX12 +/** + * @brief Provided by Wisdom 0.7.1. Extension handle for raytracing. + * + * */ +WIS_DEFINE_DX12_DEVICE_EXT_HANDLE(WisDX12RaytracingExtension, 2); + +/** + * @brief Provided by Wisdom 0.7.1. Destroys a WisRaytracingExtension handle. + * @param self is a pointer to the valid WisRaytracingExtension instance. + * + * */ +WISDOM_RAYTRACING_API void wisDX12DestroyRaytracingExtension(WisDX12RaytracingExtension* self); + +/** + * @brief Provided by Wisdom 0.7.1. Initializes a WisRaytracingExtension handle. + * @param self is a pointer to the valid WisRaytracingExtension instance. + * + * */ +WISDOM_RAYTRACING_API void wisDX12InitRaytracingExtension(WisDX12RaytracingExtension* self); + +/** + * @brief Provided by Wisdom 0.7.1. Checks if raytracing is supported on the current device. + * @param self is a pointer to the valid WisRaytracingExtension instance. + * @return bool true if raytracing is supported, false otherwise. + * + * */ +WISDOM_RAYTRACING_API bool wisDX12RaytracingExtensionSupported(WisDX12RaytracingExtension* self); + +#endif // WISDOM_DX12 + +#ifdef WISDOM_VULKAN +/** + * @brief Provided by Wisdom 0.7.1. Extension handle for raytracing. + * + * */ +WIS_DEFINE_VK_DEVICE_EXT_HANDLE(WisVKRaytracingExtension, 5); + +/** + * @brief Provided by Wisdom 0.7.1. Destroys a WisRaytracingExtension handle. + * @param self is a pointer to the valid WisRaytracingExtension instance. + * + * */ +WISDOM_RAYTRACING_API void wisVKDestroyRaytracingExtension(WisVKRaytracingExtension* self); + +/** + * @brief Provided by Wisdom 0.7.1. Initializes a WisRaytracingExtension handle. + * @param self is a pointer to the valid WisRaytracingExtension instance. + * + * */ +WISDOM_RAYTRACING_API void wisVKInitRaytracingExtension(WisVKRaytracingExtension* self); + +/** + * @brief Provided by Wisdom 0.7.1. Checks if raytracing is supported on the current device. + * @param self is a pointer to the valid WisRaytracingExtension instance. + * @return bool true if raytracing is supported, false otherwise. + * + * */ +WISDOM_RAYTRACING_API bool wisVKRaytracingExtensionSupported(WisVKRaytracingExtension* self); + +#endif // WISDOM_VULKAN + +#ifdef __cplusplus +} +#endif // __cplusplus +#endif // WISDOM_RAYTRACING_C_API_H diff --git a/src/extensions/raytracing/raytracing/generated/cpp_api.hpp b/src/extensions/raytracing/raytracing/generated/cpp_api.hpp new file mode 100644 index 000000000..4928087f7 --- /dev/null +++ b/src/extensions/raytracing/raytracing/generated/cpp_api.hpp @@ -0,0 +1,87 @@ +// This file is generated. Do not edit directly. +#ifndef WISDOM_RAYTRACING_CPP_API_HPP +#define WISDOM_RAYTRACING_CPP_API_HPP +#ifndef __cplusplus +# error C++ is required to include this header. +#endif // __cplusplus + +#include +#include "c_api.h" +#include "wisdom_exports.h" + +namespace wis {} // namespace wis + +#ifdef WISDOM_DX12 +# include + +namespace wis { +struct DX12RaytracingExtensionDeleter { + void operator()(WisDX12RaytracingExtension* handle) noexcept { ::wisDX12DestroyRaytracingExtension(handle); } +}; +/** + * @brief Provided by Wisdom 0.7.1. Extension handle for raytracing. + * + * */ +class DX12RaytracingExtension : public wis::impl::Implements< + wis::impl::DX12RaytracingExtensionImpl, + WisDX12RaytracingExtension, + wis::DX12RaytracingExtensionDeleter> +{ +public: + DX12RaytracingExtension() noexcept + : ImplType(wis::in_place) + { + ::wisDX12InitRaytracingExtension(GetStorage()); + } + // Operator & overload + wis::DX12DeviceExtensionHeader* operator&() noexcept { return &GetMutableInternal().header; } + +public: + /** + * @brief Provided by Wisdom 0.7.1. Checks if raytracing is supported on the current device. + * @return bool true if raytracing is supported, false otherwise. + * + * */ + WIS_NODISCARD inline bool Supported() noexcept { return (::wisDX12RaytracingExtensionSupported(&_impl_storage)); } +}; + +} // namespace wis +#endif // WISDOM_DX12 + +#ifdef WISDOM_VULKAN +# include + +namespace wis { +struct VKRaytracingExtensionDeleter { + void operator()(WisVKRaytracingExtension* handle) noexcept { ::wisVKDestroyRaytracingExtension(handle); } +}; +/** + * @brief Provided by Wisdom 0.7.1. Extension handle for raytracing. + * + * */ +class VKRaytracingExtension + : public wis::impl:: + Implements +{ +public: + VKRaytracingExtension() noexcept + : ImplType(wis::in_place) + { + ::wisVKInitRaytracingExtension(GetStorage()); + } + // Operator & overload + wis::VKDeviceExtensionHeader* operator&() noexcept { return &GetMutableInternal().header; } + +public: + /** + * @brief Provided by Wisdom 0.7.1. Checks if raytracing is supported on the current device. + * @return bool true if raytracing is supported, false otherwise. + * + * */ + WIS_NODISCARD inline bool Supported() noexcept { return (::wisVKRaytracingExtensionSupported(&_impl_storage)); } +}; + +} // namespace wis +#endif // WISDOM_VULKAN + +#endif // WISDOM_RAYTRACING_CPP_API_HPP diff --git a/src/extensions/raytracing/raytracing/vulkan/vk_raytracing.cpp b/src/extensions/raytracing/raytracing/vulkan/vk_raytracing.cpp new file mode 100644 index 000000000..14519ef54 --- /dev/null +++ b/src/extensions/raytracing/raytracing/vulkan/vk_raytracing.cpp @@ -0,0 +1,107 @@ +#ifndef WIS_VK_RAYTRACING_CPP +#define WIS_VK_RAYTRACING_CPP + +#include +#include +#include +#include + +namespace wis::detail { +inline WisResult VKRaytracingExtensionInit( + VKDeviceExtensionHeader* self, + impl::VKDeviceImpl* device_impl, + VKDeviceExtensionCollector* collector +) noexcept +{ + auto& impl = wis::from_handle_ref(self); + + if (!device_impl) { + auto& coll = *collector; + if (!coll.IsExtensionPresent(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME) + || !coll.IsExtensionPresent(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME) + || !coll.IsExtensionPresent(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME) + || !coll.IsExtensionPresent(VK_KHR_RAY_QUERY_EXTENSION_NAME)) { + return {}; // Required extension not present + } + + coll.EnableExtension({ + .name = VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME, + }); + + // Ray tracing pipeline + coll.EnableExtension( + {.name = VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, + .feature_struct = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR, + .feature_struct_size = sizeof(VkPhysicalDeviceRayTracingPipelineFeaturesKHR), + .property_struct = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR, + .property_struct_size = sizeof(VkPhysicalDeviceRayTracingPipelinePropertiesKHR)} + ); + + // Acceleration structure + coll.EnableExtension( + {.name = VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, + .feature_struct = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR, + .feature_struct_size = sizeof(VkPhysicalDeviceAccelerationStructureFeaturesKHR), + .property_struct = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR, + .property_struct_size = sizeof(VkPhysicalDeviceAccelerationStructurePropertiesKHR)} + ); + + // Ray query + coll.EnableExtension( + {.name = VK_KHR_RAY_QUERY_EXTENSION_NAME, + .feature_struct = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_QUERY_FEATURES_KHR, + .feature_struct_size = sizeof(VkPhysicalDeviceRayTracingPipelineFeaturesKHR)} + ); + + } else { + // Create table and pass + std::unique_ptr rt_table{new (std::nothrow) impl::VKRaytracingPipelineTable}; + if (!rt_table) { + return wis::detail::make_result( + VK_ERROR_OUT_OF_HOST_MEMORY + ); + } + + if (!rt_table->Init( + device_impl->device, + device_impl->device_header->header.shared_header->header.global_table.vkGetDeviceProcAddr + )) { + return wis::detail::make_result( + VK_ERROR_INITIALIZATION_FAILED + ); + } + + impl.device = device_impl->device; + impl.device_control_block = device_impl->device_header; + impl.device_control_block->AddRef(); // extension holds a reference to the device control block + impl.rt_table = rt_table.release(); // ownership transferred to extension, will be freed in destructor + } + + return wis::detail::vk_success; +} +} // namespace wis::detail + +WIS_EXTERN_C WISDOM_RAYTRACING_API void wisVKInitRaytracingExtension(WisVKRaytracingExtension* self) +{ + new (self) wis::impl::VKRaytracingExtensionImpl{ + .header = {&wis::detail::VKRaytracingExtensionInit}, + }; +} + +WIS_EXTERN_C WISDOM_RAYTRACING_API void wisVKDestroyRaytracingExtension(WisVKRaytracingExtension* self) +{ + auto& impl = wis::from_handle_ref(self); + if (impl.device_control_block) { + delete impl.rt_table; + wis::detail::VKReleaseDevice(impl.device_control_block); + } + impl.header = {}; // Clear header to prevent accidental use after destruction +} + +WIS_EXTERN_C WISDOM_RAYTRACING_API bool wisVKRaytracingExtensionSupported(WisVKRaytracingExtension* self) +{ + auto& impl = wis::from_handle_ref(self); + return impl.device_control_block != nullptr; // Supported if the extension was successfully initialized +} + +#endif diff --git a/src/extensions/raytracing/raytracing/vulkan/vk_tables.hpp b/src/extensions/raytracing/raytracing/vulkan/vk_tables.hpp new file mode 100644 index 000000000..ad56508af --- /dev/null +++ b/src/extensions/raytracing/raytracing/vulkan/vk_tables.hpp @@ -0,0 +1,40 @@ +#ifndef WIS_VK_RAYTRACING_TABLES_HPP +#define WIS_VK_RAYTRACING_TABLES_HPP +#ifndef __cplusplus +# error "This header requires C++" +#endif // __cplusplus +#include + +#include + +namespace wis { +namespace impl { +struct VKRaytracingPipelineTable { + PFN_vkCreateAccelerationStructureKHR vkCreateAccelerationStructureKHR; + PFN_vkGetAccelerationStructureBuildSizesKHR vkGetAccelerationStructureBuildSizesKHR; + PFN_vkDestroyAccelerationStructureKHR vkDestroyAccelerationStructureKHR; + PFN_vkCmdCopyAccelerationStructureKHR vkCmdCopyAccelerationStructureKHR; + PFN_vkCmdBuildAccelerationStructuresKHR vkCmdBuildAccelerationStructuresKHR; + PFN_vkGetAccelerationStructureDeviceAddressKHR vkGetAccelerationStructureDeviceAddressKHR; + PFN_vkGetRayTracingShaderGroupHandlesKHR vkGetRayTracingShaderGroupHandlesKHR; + PFN_vkCmdTraceRaysKHR vkCmdTraceRaysKHR; + PFN_vkCreateRayTracingPipelinesKHR vkCreateRayTracingPipelinesKHR; + + bool Init(VkDevice device, PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr) noexcept + { + ASSIGN_DEVICE_PROC_ADDR_CHECK(device, vkCreateAccelerationStructureKHR); + ASSIGN_DEVICE_PROC_ADDR_CHECK(device, vkGetAccelerationStructureBuildSizesKHR); + ASSIGN_DEVICE_PROC_ADDR_CHECK(device, vkDestroyAccelerationStructureKHR); + ASSIGN_DEVICE_PROC_ADDR_CHECK(device, vkCmdCopyAccelerationStructureKHR); + ASSIGN_DEVICE_PROC_ADDR_CHECK(device, vkCmdBuildAccelerationStructuresKHR); + ASSIGN_DEVICE_PROC_ADDR_CHECK(device, vkGetAccelerationStructureDeviceAddressKHR); + ASSIGN_DEVICE_PROC_ADDR_CHECK(device, vkGetRayTracingShaderGroupHandlesKHR); + ASSIGN_DEVICE_PROC_ADDR_CHECK(device, vkCmdTraceRaysKHR); + ASSIGN_DEVICE_PROC_ADDR_CHECK(device, vkCreateRayTracingPipelinesKHR); + return true; + } +}; +} // namespace impl +} // namespace wis + +#endif // !WIS_VK_RAYTRACING_TABLES_HPP diff --git a/src/extensions/raytracing/raytracing/vulkan/vk_types.hpp b/src/extensions/raytracing/raytracing/vulkan/vk_types.hpp new file mode 100644 index 000000000..a3fbc0d92 --- /dev/null +++ b/src/extensions/raytracing/raytracing/vulkan/vk_types.hpp @@ -0,0 +1,30 @@ +#ifndef WIS_VK_RAYTRACING_TYPES_HPP +#define WIS_VK_RAYTRACING_TYPES_HPP +#ifndef __cplusplus +# error "This header requires C++" +#endif // __cplusplus + +#include + +namespace wis { +//---------------------------------------------------------------------------------------------------------------------- +namespace impl { +struct VKRaytracingExtensionImpl { + VKDeviceExtensionHeader header; + VkDevice device; + detail::VKDeviceControlBlock* device_control_block; + impl::VKRaytracingPipelineTable* rt_table; +}; + +} // namespace impl +} // namespace wis + +// Include implementation for header-only mode +#ifdef WISDOM_HEADER_ONLY +# if !WIS_HAS_CPP20 && !defined(WISDOM_LANG_DISABLE_CHECK) +# error "C++20 is required to build wisdom as header-only library" +# endif // !WIS_HAS_CPP20 +# include "vk_raytracing.cpp" + +#endif // WISDOM_HEADER_ONLY +#endif // WIS_VK_PLATFORM_TYPES_HPP diff --git a/src/extensions/raytracing/wisdom/wisdom_raytracing.h b/src/extensions/raytracing/wisdom/wisdom_raytracing.h new file mode 100644 index 000000000..485bc83c0 --- /dev/null +++ b/src/extensions/raytracing/wisdom/wisdom_raytracing.h @@ -0,0 +1,65 @@ +// This file is generated. Do not edit directly. +#ifndef WISDOM_RAYTRACING_H +#define WISDOM_RAYTRACING_H + +#ifdef WISDOM_UWP +static_assert(WISDOM_UWP && _WIN32, "Platform error"); +#endif // WISDOM_UWP + +#ifndef FORCEVK_SWITCH +# if defined(WISDOM_VULKAN) && defined(WISDOM_FORCE_VULKAN) +# define FORCEVK_SWITCH 1 +# else +# define FORCEVK_SWITCH 0 +# endif // WISDOM_VULKAN_FOUND +#endif // FORCEVK_SWITCH + +#include "../raytracing/generated/c_api.h" + +#if defined(WISDOM_DX12) && !FORCEVK_SWITCH + +//============================================================== +// Handles +//============================================================== + +typedef struct WisDX12RaytracingExtension WisRaytracingExtension; + +//============================================================== +// Functions +//============================================================== + +# define wisDestroyRaytracingExtension wisDX12DestroyRaytracingExtension +# define wisInitRaytracingExtension wisDX12InitRaytracingExtension +# define wisRaytracingExtensionSupported wisDX12RaytracingExtensionSupported + +#elif defined(WISDOM_VULKAN) + +//============================================================== +// Handles +//============================================================== + +typedef struct WisVKRaytracingExtension WisRaytracingExtension; + +//============================================================== +// Functions +//============================================================== + +# define wisDestroyRaytracingExtension wisVKDestroyRaytracingExtension +# define wisInitRaytracingExtension wisVKInitRaytracingExtension +# define wisRaytracingExtensionSupported wisVKRaytracingExtensionSupported + +#else +# error "No API selected for Wisdom. Define WISDOM_DX12 or WISDOM_VULKAN." +#endif // API selection + +#ifndef WISDOM_HANDLE_VALID_DEFINED +# define WISDOM_HANDLE_VALID_DEFINED +static inline bool wisHandleValid(const void* handle) +{ + const uint64_t zero = 0; + return memcmp(handle, &zero, sizeof(uint64_t)) != 0; +} + +#endif // WISDOM_HANDLE_VALID_DEFINED + +#endif // WISDOM_RAYTRACING_H diff --git a/src/extensions/raytracing/wisdom/wisdom_raytracing.hpp b/src/extensions/raytracing/wisdom/wisdom_raytracing.hpp new file mode 100644 index 000000000..1838aa2ae --- /dev/null +++ b/src/extensions/raytracing/wisdom/wisdom_raytracing.hpp @@ -0,0 +1,45 @@ +// This file is generated. Do not edit directly. +#ifndef WISDOM_RAYTRACING_HPP +#define WISDOM_RAYTRACING_HPP + +#ifndef __cplusplus +# error "This is a C++ only header" +#endif // __cplusplus + +#ifndef FORCEVK_SWITCH +# if defined(WISDOM_VULKAN) && defined(WISDOM_FORCE_VULKAN) +# define FORCEVK_SWITCH 1 +# else +# define FORCEVK_SWITCH 0 +# endif // WISDOM_VULKAN_FOUND +#endif // FORCEVK_SWITCH + +#include "../raytracing/generated/cpp_api.hpp" + +#if defined(WISDOM_DX12) && !FORCEVK_SWITCH + +namespace wis { + +//============================================================== +// Handles +//============================================================== + +using RaytracingExtension = wis::DX12RaytracingExtension; + +} // namespace wis + +#elif defined(WISDOM_VULKAN) + +namespace wis { + +//============================================================== +// Handles +//============================================================== + +using RaytracingExtension = wis::VKRaytracingExtension; + +} // namespace wis +#else +# error "No API selected for Wisdom. Define WISDOM_DX12 or WISDOM_VULKAN." +#endif // API selection +#endif // WISDOM_RAYTRACING_HPP diff --git a/src/platform/wisdom_platform/dx12/dx12_platform_uwp.cpp b/src/platform/wisdom_platform/dx12/dx12_platform_uwp.cpp index d38e59373..e62fadd0c 100644 --- a/src/platform/wisdom_platform/dx12/dx12_platform_uwp.cpp +++ b/src/platform/wisdom_platform/dx12/dx12_platform_uwp.cpp @@ -35,6 +35,7 @@ WIS_EXTERN_C WISDOM_PLATFORM_API void wisDX12DestroyUWPExtension(WisDX12UWPExten impl.factory->Release(); impl.factory = nullptr; } + impl.header.init_fptr = nullptr; } //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/platform/wisdom_platform/dx12/dx12_platform_win32.cpp b/src/platform/wisdom_platform/dx12/dx12_platform_win32.cpp index d7bfd3555..4491fbd87 100644 --- a/src/platform/wisdom_platform/dx12/dx12_platform_win32.cpp +++ b/src/platform/wisdom_platform/dx12/dx12_platform_win32.cpp @@ -35,6 +35,7 @@ WIS_EXTERN_C WISDOM_PLATFORM_API void wisDX12DestroyWin32Extension(WisDX12Win32E impl.factory->Release(); impl.factory = nullptr; } + impl.header.init_fptr = nullptr; } //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/platform/wisdom_platform/vulkan/vk_platform_wayland.cpp b/src/platform/wisdom_platform/vulkan/vk_platform_wayland.cpp index 04c8890d6..a2db30fad 100644 --- a/src/platform/wisdom_platform/vulkan/vk_platform_wayland.cpp +++ b/src/platform/wisdom_platform/vulkan/vk_platform_wayland.cpp @@ -50,6 +50,7 @@ WIS_EXTERN_C WISDOM_PLATFORM_API void wisVKDestroyWaylandExtension(WisVKWaylandE if (impl.instance_control_block) { wis::detail::VKReleaseInstance(impl.instance_control_block); } + impl.header.init_fptr = nullptr; } //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/platform/wisdom_platform/vulkan/vk_platform_win32.cpp b/src/platform/wisdom_platform/vulkan/vk_platform_win32.cpp index 6a8467f28..c1f3b0595 100644 --- a/src/platform/wisdom_platform/vulkan/vk_platform_win32.cpp +++ b/src/platform/wisdom_platform/vulkan/vk_platform_win32.cpp @@ -76,6 +76,7 @@ WIS_EXTERN_C WISDOM_PLATFORM_API void wisVKDestroyWin32Extension(WisVKWin32Exten if (impl.instance_control_block) { wis::detail::VKReleaseInstance(impl.instance_control_block); } + impl.header.init_fptr = nullptr; } //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/platform/wisdom_platform/vulkan/vk_platform_xcb.cpp b/src/platform/wisdom_platform/vulkan/vk_platform_xcb.cpp index fc8db47b5..f8080746c 100644 --- a/src/platform/wisdom_platform/vulkan/vk_platform_xcb.cpp +++ b/src/platform/wisdom_platform/vulkan/vk_platform_xcb.cpp @@ -54,6 +54,7 @@ WIS_EXTERN_C WISDOM_PLATFORM_API void wisVKDestroyXCBExtension(WisVKXCBExtension if (impl.instance_control_block) { wis::detail::VKReleaseInstance(impl.instance_control_block); } + impl.header.init_fptr = nullptr; } //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/platform/wisdom_platform/vulkan/vk_platform_xlib.cpp b/src/platform/wisdom_platform/vulkan/vk_platform_xlib.cpp index b0e933729..c896e8ffb 100644 --- a/src/platform/wisdom_platform/vulkan/vk_platform_xlib.cpp +++ b/src/platform/wisdom_platform/vulkan/vk_platform_xlib.cpp @@ -55,6 +55,7 @@ WIS_EXTERN_C WISDOM_PLATFORM_API void wisVKDestroyXlibExtension(WisVKXlibExtensi if (impl.instance_control_block) { wis::detail::VKReleaseInstance(impl.instance_control_block); } + impl.header.init_fptr = nullptr; } //---------------------------------------------------------------------------------------------------------------------- diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 735273d9a..23b4204f2 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -6,10 +6,10 @@ function(wis_add_test TARGET SOURCES IMPL) add_executable(${TEST_TARGET} ${SOURCES}) if(WISDOM_BUILD_STATIC) # Link against static library if built - target_link_libraries(${TEST_TARGET} PUBLIC wis::wisdom wis::wisdom-platform + target_link_libraries(${TEST_TARGET} PUBLIC wis::wisdom wis::wisdom-platform wis::wisdom-raytracing Catch2::Catch2WithMain) else() - target_link_libraries(${TEST_TARGET} PUBLIC wis::wisdom-headers wis::wisdom-platform-headers + target_link_libraries(${TEST_TARGET} PUBLIC wis::wisdom-headers wis::wisdom-platform-headers wis::wisdom-raytracing-headers Catch2::Catch2WithMain) endif() diff --git a/tests/basic/CMakeLists.txt b/tests/basic/CMakeLists.txt index f3d7d49d8..14735d023 100644 --- a/tests/basic/CMakeLists.txt +++ b/tests/basic/CMakeLists.txt @@ -1,5 +1,11 @@ -set(TEST_SOURCES "relaxed_destruction_order.cpp") +set(TEST_SOURCES "relaxed_destruction_order.cpp" "rt_basic.cpp") -wis_add_test_suite("test-basic" ${TEST_SOURCES}) +if(WISDOM_DX12) + wis_add_test(test-basic "${TEST_SOURCES}" "dx12") +endif() + +if(WISDOM_VULKAN) + wis_add_test(test-basic "${TEST_SOURCES}" "vk") +endif() target_sources(test-basic-vk PRIVATE "platform_check.cpp") \ No newline at end of file diff --git a/tests/basic/platform_check.cpp b/tests/basic/platform_check.cpp index 52d6d38f2..03ea33250 100644 --- a/tests/basic/platform_check.cpp +++ b/tests/basic/platform_check.cpp @@ -52,4 +52,17 @@ TEST_CASE("check_platform_support") // At least one of the Linux surface extensions should be supported REQUIRE(xcb_supported || xlib_supported || wayland_supported); #endif + + wisDestroyInstance(&instance); + REQUIRE(!wisHandleValid(&instance)); + + wisDestroyXCBExtension(&xcb_extension); + wisDestroyXlibExtension(&xlib_extension); + wisDestroyWaylandExtension(&wayland_extension); + wisDestroyWin32Extension(&win32_extension); + + REQUIRE(!wisHandleValid(&xcb_extension)); + REQUIRE(!wisHandleValid(&xlib_extension)); + REQUIRE(!wisHandleValid(&wayland_extension)); + REQUIRE(!wisHandleValid(&win32_extension)); } diff --git a/tests/basic/rt_basic.cpp b/tests/basic/rt_basic.cpp new file mode 100644 index 000000000..b27f701a5 --- /dev/null +++ b/tests/basic/rt_basic.cpp @@ -0,0 +1,55 @@ +#include +#include +#include + +TEST_CASE("check_rt") +{ + WisRaytracingExtension ext{0}; + REQUIRE(!wisHandleValid(&ext)); + + wisInitRaytracingExtension(&ext); + REQUIRE(wisHandleValid(&ext)); + + wisDestroyRaytracingExtension(&ext); + REQUIRE(!wisHandleValid(&ext)); +} + +TEST_CASE("check_rt_support") +{ + WisRaytracingExtension ext{0}; + wisInitRaytracingExtension(&ext); + + WisInstance instance = {0}; + wisCreateInstance(NULL, NULL, 0, &instance); + + WisAdapterQuery adapter_query = {0}; + wisInstanceQueryAdapters(&instance, WisAdapterPreferencePerformance, &adapter_query); + + WisDeviceExtensionHeader* extensions[] = { + &ext.header, + }; + WisDevice device = {0}; + WisCommandQueueDesc queue_descs[] = { + {WisCommandQueueTypeGraphics, WisCommandQueuePriorityHigh}, + }; + WisDeviceRequirements requirements = { + .queue_descs = queue_descs, + .queue_desc_count = sizeof(queue_descs) / sizeof(queue_descs[0]), + .extensions = extensions, + .extension_count = sizeof(extensions) / sizeof(extensions[0]), + }; + bool supported = false; + for (size_t i = 0; i < wisAdapterQueryGetAdapterCount(&adapter_query); ++i) { + WisResult res = wisAdapterQueryCreateDevice(&adapter_query, i, &requirements, &device); + if (res.status == WisStatusOk) { + supported = wisRaytracingExtensionSupported(&ext); + wisDestroyDevice(&device); + break; + } + } + + printf("Raytracing supported: %s\n", supported ? "Yes" : "No"); + wisDestroyRaytracingExtension(&ext); + wisDestroyAdapterQuery(&adapter_query); + wisDestroyInstance(&instance); +} diff --git a/xml/raytracing.xml b/xml/raytracing.xml new file mode 100644 index 000000000..94e574141 --- /dev/null +++ b/xml/raytracing.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + From f201854d154305226ec2744ee72ff90fde624746 Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Sun, 26 Apr 2026 12:52:35 +0200 Subject: [PATCH 11/49] Add acceleration structure API for DX12 and Vulkan Introduce AccelerationStructure handle, descriptor, and level types for raytracing. Implement creation, destruction, and GPU address query functions for both DX12 and Vulkan backends. Update buffer and pipeline handle sizes, add resource management logic, and extend codegen XML and documentation. Provide C++ wrappers and a new test for acceleration structure creation and address retrieval. --- .../enum/acceleration_structure_level_enum.h | 53 ++++++ ...ion_structure_get_g_p_u_address_function.h | 64 ++++++++ .../destroy_acceleration_structure_function.h | 47 ++++++ .../destroy_raytracing_extension_function.h | 2 +- .../func/init_raytracing_extension_function.h | 4 +- ...n_create_acceleration_structure_function.h | 86 ++++++++++ .../raytracing_extension_supported_function.h | 27 ++-- .../handle/acceleration_structure_handle.h | 29 ++++ .../handle/raytracing_extension_handle.h | 3 +- .../acceleration_structure_desc_struct.h | 91 +++++++++++ docs/wisdom/enum/address_mode_enum.h | 2 +- docs/wisdom/handle/buffer_handle.h | 2 +- docs/wisdom/handle/pipeline_handle.h | 4 +- .../struct/device_memory_properties_struct.h | 6 +- .../raytracing/dx12/dx12_raytracing.cpp | 49 ++++++ .../raytracing/raytracing/dx12/dx12_types.hpp | 6 + .../raytracing/raytracing/generated/c_api.h | 119 ++++++++++++++ .../raytracing/generated/cpp_api.hpp | 153 +++++++++++++++++- .../raytracing/generated/dx12_convert.hpp | 15 ++ .../raytracing/generated/vk_convert.hpp | 27 ++++ .../raytracing/vulkan/vk_raytracing.cpp | 83 +++++++++- .../raytracing/raytracing/vulkan/vk_types.hpp | 6 + .../raytracing/wisdom/wisdom_raytracing.h | 32 +++- .../raytracing/wisdom/wisdom_raytracing.hpp | 14 ++ src/include/wisdom/generated/c_api.h | 6 +- .../wisdom/vulkan/detail/vk_detail.hpp | 34 ++++ src/include/wisdom/vulkan/vk_impl.cpp | 7 + .../wisdom/vulkan/vk_resource_allocator.cpp | 25 +++ src/include/wisdom/vulkan/vk_tables.hpp | 3 + src/include/wisdom/vulkan/vk_types.hpp | 2 + tests/basic/CMakeLists.txt | 2 +- tests/basic/rt_basic.cpp | 1 + tests/basic/rt_primitives.cpp | 116 +++++++++++++ xml/raytracing.xml | 34 +++- xml/wis.xml | 4 +- 35 files changed, 1122 insertions(+), 36 deletions(-) create mode 100644 docs/raytracing/enum/acceleration_structure_level_enum.h create mode 100644 docs/raytracing/func/acceleration_structure_get_g_p_u_address_function.h create mode 100644 docs/raytracing/func/destroy_acceleration_structure_function.h create mode 100644 docs/raytracing/func/raytracing_extension_create_acceleration_structure_function.h create mode 100644 docs/raytracing/handle/acceleration_structure_handle.h create mode 100644 docs/raytracing/struct/acceleration_structure_desc_struct.h create mode 100644 src/extensions/raytracing/raytracing/generated/dx12_convert.hpp create mode 100644 src/extensions/raytracing/raytracing/generated/vk_convert.hpp create mode 100644 tests/basic/rt_primitives.cpp diff --git a/docs/raytracing/enum/acceleration_structure_level_enum.h b/docs/raytracing/enum/acceleration_structure_level_enum.h new file mode 100644 index 000000000..9d62b483f --- /dev/null +++ b/docs/raytracing/enum/acceleration_structure_level_enum.h @@ -0,0 +1,53 @@ +/** + * @struct WisAccelerationStructureLevel WisAccelerationStructureLevel + * @ingroup Enumerations Raytracing + * + * Acceleration structure level enumeration for raytracing. + * + * @section WisAccelerationStructureLevel_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef enum WisAccelerationStructureLevel { + * WisAccelerationStructureLevelTopLevel = 0, + * WisAccelerationStructureLevelBottomLevel = 1, + * } WisAccelerationStructureLevel; + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * enum class AccelerationStructureLevel { + * TopLevel = 0, + * BottomLevel = 1, + * }; + * } + * ``` + * \endcond + * + * @section WisAccelerationStructureLevel_descr Description + *
+ * \cond WIS_GEN_DESC + * Enumeration for the level of an acceleration structure in raytracing. + * + * \note Translates to `VkAccelerationStructureTypeKHR` for Vulkan implementation. + * + * Values: + * - `WisAccelerationStructureLevelTopLevel = 0`: Top-level acceleration structure, which contains instances of + * bottom-level structures. + * - `WisAccelerationStructureLevelBottomLevel = 1`: Bottom-level acceleration structure, which contains geometry data + * such as triangles or AABBs. + * \endcond + * + * + * @section WisAccelerationStructureLevel_see_also See Also + *
+ * + * \cond WIS_GEN_REFS + * @see Structs: + * WisAccelerationStructureDesc + * \endcond + */ diff --git a/docs/raytracing/func/acceleration_structure_get_g_p_u_address_function.h b/docs/raytracing/func/acceleration_structure_get_g_p_u_address_function.h new file mode 100644 index 000000000..7a678c80b --- /dev/null +++ b/docs/raytracing/func/acceleration_structure_get_g_p_u_address_function.h @@ -0,0 +1,64 @@ +/** + * @struct wisAccelerationStructureGetGPUAddress + * @ingroup Functions Raytracing + * + * @section wisAccelerationStructureGetGPUAddress_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C Version: + * ```c + * // Provided by Wisdom 0.7.1. + * uint64_t wisAccelerationStructureGetGPUAddress(WisAccelerationStructure* self); + * ``` + *
+ * C Implementation Specific Version: + * ```c + * // Provided by Wisdom 0.7.1. + * uint64_t wisVKAccelerationStructureGetGPUAddress(WisVKAccelerationStructure* self); + * + * // Provided by Wisdom 0.7.1. + * uint64_t wisDX12AccelerationStructureGetGPUAddress(WisDX12AccelerationStructure* self); + * ``` + *
+ * + * C++ Version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * WIS_NODISCARD std::uint64_t AccelerationStructure::GetGPUAddress() noexcept; + * } + * ``` + *
+ * C++ Implementation Specific Version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * WIS_NODISCARD std::uint64_t VKAccelerationStructure::GetGPUAddress() noexcept; + * + * // Provided by Wisdom 0.7.1. + * WIS_NODISCARD std::uint64_t DX12AccelerationStructure::GetGPUAddress() noexcept; + * } + * ``` + *
+ * \endcond + * + * @section wisAccelerationStructureGetGPUAddress_memb Parameters + *
+ * \cond WIS_GEN_DESC + * - **this** `self` self is a pointer to the valid WisAccelerationStructure instance. + * + * - **return** The GPU address of the acceleration structure. + * \endcond + * + * @section wisAccelerationStructureGetGPUAddress_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section wisAccelerationStructureGetGPUAddress_see_also See Also + *
+ * \cond WIS_GEN_REFS + * \endcond + */ diff --git a/docs/raytracing/func/destroy_acceleration_structure_function.h b/docs/raytracing/func/destroy_acceleration_structure_function.h new file mode 100644 index 000000000..d9407b402 --- /dev/null +++ b/docs/raytracing/func/destroy_acceleration_structure_function.h @@ -0,0 +1,47 @@ +/** + * @struct wisDestroyAccelerationStructure + * @ingroup Functions Raytracing + * + * + * @section wisDestroyAccelerationStructure_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C Version: + * ```c + * // Provided by Wisdom 0.7.1. + * void wisDestroyAccelerationStructure(WisAccelerationStructure* self); + * ``` + *
+ * C Implementation Specific Version: + * ```c + * // Provided by Wisdom 0.7.1. + * void wisVKDestroyAccelerationStructure(WisVKAccelerationStructure* self); + * + * // Provided by Wisdom 0.7.1. + * void wisDX12DestroyAccelerationStructure(WisDX12AccelerationStructure* self); + * ``` + *
+ * + * \endcond + * + * @section wisDestroyAccelerationStructure_memb Parameters + *
+ * \cond WIS_GEN_DESC + * - **this** `self` self is a pointer to the valid WisAccelerationStructure instance. + * \endcond + * + * @section wisDestroyAccelerationStructure_descr Description + *
+ * + * Destroys the given acceleration structure, releasing any associated resources. After this call, the acceleration + * structure handle will no longer be valid and should not be used. + * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section wisDestroyAccelerationStructure_see_also See Also + *
+ * \cond WIS_GEN_REFS + * \endcond + */ diff --git a/docs/raytracing/func/destroy_raytracing_extension_function.h b/docs/raytracing/func/destroy_raytracing_extension_function.h index 5071aa82b..969119c10 100644 --- a/docs/raytracing/func/destroy_raytracing_extension_function.h +++ b/docs/raytracing/func/destroy_raytracing_extension_function.h @@ -35,7 +35,7 @@ * * @section wisDestroyRaytracingExtension_descr Description *
- * + * * \note WisRaytracingExtension references device. That means the device resources will not be released until the * extension is destroyed. * diff --git a/docs/raytracing/func/init_raytracing_extension_function.h b/docs/raytracing/func/init_raytracing_extension_function.h index 0b62c3976..166604818 100644 --- a/docs/raytracing/func/init_raytracing_extension_function.h +++ b/docs/raytracing/func/init_raytracing_extension_function.h @@ -57,10 +57,10 @@ * * @section wisInitRaytracingExtension_descr Description *
- * + * * Passing an uninitialized handle to `WisDeviceRequirements` when creating a device will not enable raytracing features * on the device. - * + * * \note WisRaytracingExtension references device. That means the device resources will not be released until the * extension is destroyed. * diff --git a/docs/raytracing/func/raytracing_extension_create_acceleration_structure_function.h b/docs/raytracing/func/raytracing_extension_create_acceleration_structure_function.h new file mode 100644 index 000000000..348d28c1d --- /dev/null +++ b/docs/raytracing/func/raytracing_extension_create_acceleration_structure_function.h @@ -0,0 +1,86 @@ +/** + * @struct wisRaytracingExtensionCreateAccelerationStructure + * @ingroup Functions Raytracing + * + * + * @section wisRaytracingExtensionCreateAccelerationStructure_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C Version: + * ```c + * // Provided by Wisdom 0.7.1. + * WisResult wisRaytracingExtensionCreateAccelerationStructure(WisRaytracingExtension* self, + * WisBuffer* buffer, + * const WisAccelerationStructureDesc* desc, + * WisAccelerationStructure* acceleration_structure); + * ``` + *
+ * C Implementation Specific Version: + * ```c + * // Provided by Wisdom 0.7.1. + * WisResult wisVKRaytracingExtensionCreateAccelerationStructure(WisVKRaytracingExtension* self, + * WisVKBuffer* buffer, + * const WisVKAccelerationStructureDesc* desc, + * WisVKAccelerationStructure* acceleration_structure); + * + * // Provided by Wisdom 0.7.1. + * WisResult wisDX12RaytracingExtensionCreateAccelerationStructure(WisDX12RaytracingExtension* self, + * WisDX12Buffer* buffer, + * const WisDX12AccelerationStructureDesc* desc, + * WisDX12AccelerationStructure* + * acceleration_structure); + * ``` + *
+ * + * C++ Version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * WIS_NODISCARD wis::AccelerationStructure RaytracingExtension::CreateAccelerationStructure(wis::Buffer& buffer, const + * wis::AccelerationStructureDesc& desc, wis::Result& out_result) noexcept; + * } + * ``` + *
+ * C++ Implementation Specific Version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * WIS_NODISCARD wis::VKAccelerationStructure VKRaytracingExtension::CreateAccelerationStructure(wis::VKBuffer& buffer, + * const + * wis::VKAccelerationStructureDesc& desc, wis::Result& out_result) noexcept; + * + * // Provided by Wisdom 0.7.1. + * WIS_NODISCARD wis::DX12AccelerationStructure DX12RaytracingExtension::CreateAccelerationStructure(wis::DX12Buffer& + * buffer, const wis::DX12AccelerationStructureDesc& desc, wis::Result& out_result) + * noexcept; + * } + * ``` + *
+ * \endcond + * + * @section wisRaytracingExtensionCreateAccelerationStructure_memb Parameters + *
+ * \cond WIS_GEN_DESC + * - **this** `self` self is a pointer to the valid WisRaytracingExtension instance. + * - `buffer` The buffer to write the acceleration structure data to. + * - `desc` The description of the acceleration structure to create. + * - `acceleration_structure` The created acceleration structure handle. + * + * - **return** denoting the outcome of operation. + * \endcond + * + * @section wisRaytracingExtensionCreateAccelerationStructure_descr Description + *
+ * + * The resulting acceleration structure stores reference to provided buffer, extending its lifetime to that of the + * acceleration structure. The buffer @wis_must be created with `WisBufferUsageFlagsAccelerationStructureBuffer` usage flag. + * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section wisRaytracingExtensionCreateAccelerationStructure_see_also See Also + *
+ * \cond WIS_GEN_REFS + * \endcond + */ diff --git a/docs/raytracing/func/raytracing_extension_supported_function.h b/docs/raytracing/func/raytracing_extension_supported_function.h index d25a86bfe..2f290c0ff 100644 --- a/docs/raytracing/func/raytracing_extension_supported_function.h +++ b/docs/raytracing/func/raytracing_extension_supported_function.h @@ -8,7 +8,7 @@ *
* * \cond WIS_GEN_CODE - * * C Version: + * C Version: * ```c * // Provided by Wisdom 0.7.1. * bool wisRaytracingExtensionSupported(WisRaytracingExtension* self); @@ -26,33 +26,40 @@ * * C++ Version: * ```cpp - * namespace wis + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * WIS_NODISCARD bool RaytracingExtension::Supported() noexcept; + * } * ``` *
* C++ Implementation Specific Version: * ```cpp - * namespace wis + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * WIS_NODISCARD bool VKRaytracingExtension::Supported() noexcept; + * + * // Provided by Wisdom 0.7.1. + * WIS_NODISCARD bool DX12RaytracingExtension::Supported() noexcept; + * } * ``` *
- * * \endcond * * @section wisRaytracingExtensionSupported_memb Parameters *
* \cond WIS_GEN_DESC - * * - **this** `self` self is a pointer to the valid WisRaytracingExtension instance. + * - **this** `self` self is a pointer to the valid WisRaytracingExtension instance. * * - **return** true if raytracing is supported, false otherwise. - * * \endcond * * @section wisRaytracingExtensionSupported_descr Description *
- * + * * This function must be called after device creation, where the handle is passed to the `WisDeviceRequirements` when - * creating the device. It checks if raytracing is supported on the current device and returns a boolean value indicating the - * result. - * + * creating the device. It checks if raytracing is supported on the current device and returns a boolean value + * indicating the result. + * * The result is not cached, so the call may be expensive. It is recommended to call this function once and cache the * result if you need to check for raytracing support multiple times. * diff --git a/docs/raytracing/handle/acceleration_structure_handle.h b/docs/raytracing/handle/acceleration_structure_handle.h new file mode 100644 index 000000000..61bbd76b1 --- /dev/null +++ b/docs/raytracing/handle/acceleration_structure_handle.h @@ -0,0 +1,29 @@ +/** + * @struct WisAccelerationStructure + * @ingroup Handles Raytracing + * + * + * @section WisAccelerationStructure_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * Vulkan Version: + * ```c + * // Provided by Wisdom 0.7.1. + * WIS_DEFINE_HANDLE(WisVKAccelerationStructure,4); + * ``` + * DX12 Version: + * ```c + * // Provided by Wisdom 0.7.1. + * WIS_DEFINE_HANDLE(WisDX12AccelerationStructure,2); + * ``` + * \endcond + * + * @section WisAccelerationStructure_see_also See Also + *
+ * \cond WIS_GEN_REFS + * @see Functions: + * wisDestroyAccelerationStructure, wisRaytracingExtensionCreateAccelerationStructure, + * wisAccelerationStructureGetGPUAddress + * \endcond + */ diff --git a/docs/raytracing/handle/raytracing_extension_handle.h b/docs/raytracing/handle/raytracing_extension_handle.h index 4f297865f..95264634a 100644 --- a/docs/raytracing/handle/raytracing_extension_handle.h +++ b/docs/raytracing/handle/raytracing_extension_handle.h @@ -25,6 +25,7 @@ *
* \cond WIS_GEN_REFS * @see Functions: - * wisDestroyRaytracingExtension, wisInitRaytracingExtension, wisRaytracingExtensionSupported + * wisDestroyRaytracingExtension, wisInitRaytracingExtension, wisRaytracingExtensionSupported, + * wisRaytracingExtensionCreateAccelerationStructure * \endcond */ diff --git a/docs/raytracing/struct/acceleration_structure_desc_struct.h b/docs/raytracing/struct/acceleration_structure_desc_struct.h new file mode 100644 index 000000000..b496ad4e7 --- /dev/null +++ b/docs/raytracing/struct/acceleration_structure_desc_struct.h @@ -0,0 +1,91 @@ +/** + * @struct WisAccelerationStructureDesc + * @ingroup Structures Raytracing + * + * + * @section WisAccelerationStructureDesc_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C Version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef struct WisAccelerationStructureDesc { + * WisAccelerationStructureLevel level; + * uint64_t offset; + * uint64_t size; + * } WisAccelerationStructureDesc; + * ``` + *
+ * C Implementation Specific Version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef struct WisVKAccelerationStructureDesc { + * WisAccelerationStructureLevel level; + * uint64_t offset; + * uint64_t size; + * } WisVKAccelerationStructureDesc; + * + * // Provided by Wisdom 0.7.1. + * typedef struct WisDX12AccelerationStructureDesc { + * WisAccelerationStructureLevel level; + * uint64_t offset; + * uint64_t size; + * } WisDX12AccelerationStructureDesc; + * ``` + *
+ * + * C++ Version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * struct AccelerationStructureDesc { + * wis::AccelerationStructureLevel level; + * std::uint64_t offset; + * std::uint64_t size; + * }; + * } + * ``` + *
+ * C++ Implementation Specific Version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * struct VKAccelerationStructureDesc { + * wis::AccelerationStructureLevel level; + * std::uint64_t offset; + * std::uint64_t size; + * }; + * + * // Provided by Wisdom 0.7.1. + * struct DX12AccelerationStructureDesc { + * wis::AccelerationStructureLevel level; + * std::uint64_t offset; + * std::uint64_t size; + * }; + * } + * ``` + *
+ * \endcond + * + * @section WisAccelerationStructureDesc_memb Members + *
+ * \cond WIS_GEN_DESC + * - `level` The level of the acceleration structure (top-level or bottom-level). + * - `offset` The offset in bytes from the start of the buffer where the acceleration structure is located. + * - `size` The size of the acceleration structure in bytes. + * \endcond + * + * @section WisAccelerationStructureDesc_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section WisAccelerationStructureDesc_see_also See Also + *
+ * \cond WIS_GEN_REFS + * @see Functions: + * wisRaytracingExtensionCreateAccelerationStructure + * \endcond + */ diff --git a/docs/wisdom/enum/address_mode_enum.h b/docs/wisdom/enum/address_mode_enum.h index 126d1f03e..e6e718724 100644 --- a/docs/wisdom/enum/address_mode_enum.h +++ b/docs/wisdom/enum/address_mode_enum.h @@ -4,7 +4,7 @@ * * @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. * diff --git a/docs/wisdom/handle/buffer_handle.h b/docs/wisdom/handle/buffer_handle.h index c656c74d5..5ae95a618 100644 --- a/docs/wisdom/handle/buffer_handle.h +++ b/docs/wisdom/handle/buffer_handle.h @@ -10,7 +10,7 @@ * Vulkan Version: * ```c * // Provided by Wisdom 0.7.0. - * WIS_DEFINE_HANDLE(WisVKBuffer,4); + * WIS_DEFINE_HANDLE(WisVKBuffer,5); * WIS_DEFINE_HANDLE_VIEW(WisVKBuffer,1); * ``` * DX12 Version: diff --git a/docs/wisdom/handle/pipeline_handle.h b/docs/wisdom/handle/pipeline_handle.h index a56d29a73..50d0b4881 100644 --- a/docs/wisdom/handle/pipeline_handle.h +++ b/docs/wisdom/handle/pipeline_handle.h @@ -10,8 +10,8 @@ * Vulkan Version: * ```c * // Provided by Wisdom 0.7.0. - * WIS_DEFINE_HANDLE(WisVKPipeline,2); - * WIS_DEFINE_HANDLE_VIEW(WisVKPipeline,1); + * WIS_DEFINE_HANDLE(WisVKPipeline,3); + * WIS_DEFINE_HANDLE_VIEW(WisVKPipeline,2); * ``` * DX12 Version: * ```c diff --git a/docs/wisdom/struct/device_memory_properties_struct.h b/docs/wisdom/struct/device_memory_properties_struct.h index 793cb9b07..2c3d2e831 100644 --- a/docs/wisdom/struct/device_memory_properties_struct.h +++ b/docs/wisdom/struct/device_memory_properties_struct.h @@ -57,15 +57,15 @@ * `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. * diff --git a/src/extensions/raytracing/raytracing/dx12/dx12_raytracing.cpp b/src/extensions/raytracing/raytracing/dx12/dx12_raytracing.cpp index 9aabd8432..f849d9d26 100644 --- a/src/extensions/raytracing/raytracing/dx12/dx12_raytracing.cpp +++ b/src/extensions/raytracing/raytracing/dx12/dx12_raytracing.cpp @@ -3,6 +3,7 @@ #include #include +#include namespace wis::detail { inline WisResult DX12RaytracingExtensionInit( @@ -11,12 +12,18 @@ inline WisResult DX12RaytracingExtensionInit( ) noexcept { auto& impl = wis::from_handle_ref(self); + + if (impl.device) { + impl.device->Release(); + } + impl.device = device.device; impl.device->AddRef(); // AddRef factory to ensure it lives as long as the extension return wis::detail::dx_success; } } // namespace wis::detail +//---------------------------------------------------------------------------------------------------------------------- WIS_EXTERN_C WISDOM_RAYTRACING_API void wisDX12InitRaytracingExtension(WisDX12RaytracingExtension* self) { new (self) wis::impl::DX12RaytracingExtensionImpl{ @@ -24,6 +31,7 @@ WIS_EXTERN_C WISDOM_RAYTRACING_API void wisDX12InitRaytracingExtension(WisDX12Ra }; } +//---------------------------------------------------------------------------------------------------------------------- WIS_EXTERN_C WISDOM_RAYTRACING_API void wisDX12DestroyRaytracingExtension(WisDX12RaytracingExtension* self) { auto& impl = wis::from_handle_ref(self); @@ -34,6 +42,7 @@ WIS_EXTERN_C WISDOM_RAYTRACING_API void wisDX12DestroyRaytracingExtension(WisDX1 impl.header = {nullptr}; } +//---------------------------------------------------------------------------------------------------------------------- WIS_EXTERN_C WISDOM_RAYTRACING_API bool wisDX12RaytracingExtensionSupported(WisDX12RaytracingExtension* self) { auto& impl = wis::from_handle_ref(self); @@ -48,4 +57,44 @@ WIS_EXTERN_C WISDOM_RAYTRACING_API bool wisDX12RaytracingExtensionSupported(WisD return options5.RaytracingTier != D3D12_RAYTRACING_TIER_NOT_SUPPORTED; } +//---------------------------------------------------------------------------------------------------------------------- +WIS_EXTERN_C WISDOM_RAYTRACING_API WisResult wisDX12RaytracingExtensionCreateAccelerationStructure( + WisDX12RaytracingExtension* self, + WisDX12Buffer* buffer, + const WisDX12AccelerationStructureDesc* desc, + WisDX12AccelerationStructure* acceleration_structure +) +{ + auto& buffer_impl = wis::from_handle_ref(buffer); + auto address = buffer_impl.resource->GetGPUVirtualAddress(); // AddRef buffer to ensure it lives as long as the acceleration + // structure + if (address == 0) { + return wis::detail::make_result(E_FAIL); + } + + new (acceleration_structure) wis::impl::DX12AccelerationStructureImpl{ + .gpu_address = address + desc->offset, + .resource = buffer_impl.resource, + }; + buffer_impl.resource->AddRef(); + return wis::detail::dx_success; +} + +//---------------------------------------------------------------------------------------------------------------------- +WIS_EXTERN_C WISDOM_RAYTRACING_API void wisDX12DestroyAccelerationStructure(WisDX12AccelerationStructure* self) +{ + auto& impl = wis::from_handle_ref(self); + if (impl.resource) { + impl.resource->Release(); + impl.resource = nullptr; + } + impl.gpu_address = 0; +} + +//---------------------------------------------------------------------------------------------------------------------- +WIS_EXTERN_C WISDOM_RAYTRACING_API uint64_t wisDX12AccelerationStructureGetGPUAddress(WisDX12AccelerationStructure* self) +{ + return wis::from_handle_ref(self).gpu_address; +} + #endif diff --git a/src/extensions/raytracing/raytracing/dx12/dx12_types.hpp b/src/extensions/raytracing/raytracing/dx12/dx12_types.hpp index 24214c25a..7b9cf15a5 100644 --- a/src/extensions/raytracing/raytracing/dx12/dx12_types.hpp +++ b/src/extensions/raytracing/raytracing/dx12/dx12_types.hpp @@ -13,6 +13,12 @@ struct DX12RaytracingExtensionImpl { DX12DeviceExtensionHeader header; ID3D12Device* device; }; + +struct DX12AccelerationStructureImpl { + D3D12_GPU_VIRTUAL_ADDRESS gpu_address; + ID3D12Resource* resource; +}; + } // namespace impl } // namespace wis diff --git a/src/extensions/raytracing/raytracing/generated/c_api.h b/src/extensions/raytracing/raytracing/generated/c_api.h index 586daccc9..9564ff14a 100644 --- a/src/extensions/raytracing/raytracing/generated/c_api.h +++ b/src/extensions/raytracing/raytracing/generated/c_api.h @@ -8,13 +8,58 @@ extern "C" { #endif // __cplusplus +//============================================================== +// Enums +//============================================================== + +/** + * @brief Provided by Wisdom 0.7.1. Enumeration for the level of an acceleration structure in raytracing. + * + * */ +typedef enum WisAccelerationStructureLevel { + /** + * @brief Top-level acceleration structure, which contains instances of bottom-level structures. + * */ + WisAccelerationStructureLevelTopLevel = 0, + /** + * @brief Bottom-level acceleration structure, which contains geometry data such as triangles or AABBs. + * */ + WisAccelerationStructureLevelBottomLevel = 1, +} WisAccelerationStructureLevel; + #ifdef WISDOM_DX12 +/** + * @brief Provided by Wisdom 0.7.1. Handle for an acceleration structure used in raytracing. + * + * */ +WIS_DEFINE_HANDLE(WisDX12AccelerationStructure, 2); + /** * @brief Provided by Wisdom 0.7.1. Extension handle for raytracing. * * */ WIS_DEFINE_DX12_DEVICE_EXT_HANDLE(WisDX12RaytracingExtension, 2); +/** + * @brief Provided by Wisdom 0.7.1. Structure describing the properties of an acceleration structure. + * + * */ +typedef struct WisDX12AccelerationStructureDesc { + WisAccelerationStructureLevel level; ///< The level of the acceleration structure (top-level or bottom-level). + /** + * @brief The offset in bytes from the start of the buffer where the acceleration structure is located. + * */ + uint64_t offset; + uint64_t size; ///< The size of the acceleration structure in bytes. +} WisDX12AccelerationStructureDesc; + +/** + * @brief Provided by Wisdom 0.7.1. Destroys a WisAccelerationStructure handle. + * @param self is a pointer to the valid WisAccelerationStructure instance. + * + * */ +WISDOM_RAYTRACING_API void wisDX12DestroyAccelerationStructure(WisDX12AccelerationStructure* self); + /** * @brief Provided by Wisdom 0.7.1. Destroys a WisRaytracingExtension handle. * @param self is a pointer to the valid WisRaytracingExtension instance. @@ -37,15 +82,65 @@ WISDOM_RAYTRACING_API void wisDX12InitRaytracingExtension(WisDX12RaytracingExten * */ WISDOM_RAYTRACING_API bool wisDX12RaytracingExtensionSupported(WisDX12RaytracingExtension* self); +/** + * @brief Provided by Wisdom 0.7.1. Creates an acceleration structure based on the provided description. + * @param self is a pointer to the valid WisRaytracingExtension instance. + * @param buffer The buffer to write the acceleration structure data to. + * @param desc The description of the acceleration structure to create. + * @param acceleration_structure The created acceleration structure handle. + * @return Result denoting the outcome of operation. + * + * */ +WISDOM_RAYTRACING_API WisResult wisDX12RaytracingExtensionCreateAccelerationStructure( + WisDX12RaytracingExtension* self, + WisDX12Buffer* buffer, + const WisDX12AccelerationStructureDesc* desc, + WisDX12AccelerationStructure* acceleration_structure +); + +/** + * @brief Provided by Wisdom 0.7.1. Retrieves the GPU address of the acceleration structure. + * @param self is a pointer to the valid WisAccelerationStructure instance. + * @return u64 The GPU address of the acceleration structure. + * + * */ +WISDOM_RAYTRACING_API uint64_t wisDX12AccelerationStructureGetGPUAddress(WisDX12AccelerationStructure* self); + #endif // WISDOM_DX12 #ifdef WISDOM_VULKAN +/** + * @brief Provided by Wisdom 0.7.1. Handle for an acceleration structure used in raytracing. + * + * */ +WIS_DEFINE_HANDLE(WisVKAccelerationStructure, 4); + /** * @brief Provided by Wisdom 0.7.1. Extension handle for raytracing. * * */ WIS_DEFINE_VK_DEVICE_EXT_HANDLE(WisVKRaytracingExtension, 5); +/** + * @brief Provided by Wisdom 0.7.1. Structure describing the properties of an acceleration structure. + * + * */ +typedef struct WisVKAccelerationStructureDesc { + WisAccelerationStructureLevel level; ///< The level of the acceleration structure (top-level or bottom-level). + /** + * @brief The offset in bytes from the start of the buffer where the acceleration structure is located. + * */ + uint64_t offset; + uint64_t size; ///< The size of the acceleration structure in bytes. +} WisVKAccelerationStructureDesc; + +/** + * @brief Provided by Wisdom 0.7.1. Destroys a WisAccelerationStructure handle. + * @param self is a pointer to the valid WisAccelerationStructure instance. + * + * */ +WISDOM_RAYTRACING_API void wisVKDestroyAccelerationStructure(WisVKAccelerationStructure* self); + /** * @brief Provided by Wisdom 0.7.1. Destroys a WisRaytracingExtension handle. * @param self is a pointer to the valid WisRaytracingExtension instance. @@ -68,6 +163,30 @@ WISDOM_RAYTRACING_API void wisVKInitRaytracingExtension(WisVKRaytracingExtension * */ WISDOM_RAYTRACING_API bool wisVKRaytracingExtensionSupported(WisVKRaytracingExtension* self); +/** + * @brief Provided by Wisdom 0.7.1. Creates an acceleration structure based on the provided description. + * @param self is a pointer to the valid WisRaytracingExtension instance. + * @param buffer The buffer to write the acceleration structure data to. + * @param desc The description of the acceleration structure to create. + * @param acceleration_structure The created acceleration structure handle. + * @return Result denoting the outcome of operation. + * + * */ +WISDOM_RAYTRACING_API WisResult wisVKRaytracingExtensionCreateAccelerationStructure( + WisVKRaytracingExtension* self, + WisVKBuffer* buffer, + const WisVKAccelerationStructureDesc* desc, + WisVKAccelerationStructure* acceleration_structure +); + +/** + * @brief Provided by Wisdom 0.7.1. Retrieves the GPU address of the acceleration structure. + * @param self is a pointer to the valid WisAccelerationStructure instance. + * @return u64 The GPU address of the acceleration structure. + * + * */ +WISDOM_RAYTRACING_API uint64_t wisVKAccelerationStructureGetGPUAddress(WisVKAccelerationStructure* self); + #endif // WISDOM_VULKAN #ifdef __cplusplus diff --git a/src/extensions/raytracing/raytracing/generated/cpp_api.hpp b/src/extensions/raytracing/raytracing/generated/cpp_api.hpp index 4928087f7..8feb90b71 100644 --- a/src/extensions/raytracing/raytracing/generated/cpp_api.hpp +++ b/src/extensions/raytracing/raytracing/generated/cpp_api.hpp @@ -9,12 +9,67 @@ #include "c_api.h" #include "wisdom_exports.h" -namespace wis {} // namespace wis +namespace wis { + +//============================================================== +// Enums +//============================================================== + +/** + * @brief Provided by Wisdom 0.7.1. Enumeration for the level of an acceleration structure in raytracing. + * + * */ +enum class AccelerationStructureLevel { + TopLevel = 0, ///< Top-level acceleration structure, which contains instances of bottom-level structures. + BottomLevel = 1, ///< Bottom-level acceleration structure, which contains geometry data such as triangles or AABBs. +}; + +} // namespace wis #ifdef WISDOM_DX12 # include namespace wis { +/** + * @brief Provided by Wisdom 0.7.1. Structure describing the properties of an acceleration structure. + * + * */ +struct DX12AccelerationStructureDesc { + wis::AccelerationStructureLevel level; ///< The level of the acceleration structure (top-level or bottom-level). + /** + * @brief The offset in bytes from the start of the buffer where the acceleration structure is located. + * */ + std::uint64_t offset; + std::uint64_t size; ///< The size of the acceleration structure in bytes. +}; + +struct DX12AccelerationStructureDeleter { + void operator()(WisDX12AccelerationStructure* handle) noexcept { ::wisDX12DestroyAccelerationStructure(handle); } +}; +/** + * @brief Provided by Wisdom 0.7.1. Handle for an acceleration structure used in raytracing. + * + * */ +class DX12AccelerationStructure : public wis::impl::Implements< + wis::impl::DX12AccelerationStructureImpl, + WisDX12AccelerationStructure, + wis::DX12AccelerationStructureDeleter> +{ +public: + using ImplType::ImplType; + +public: + /** + * @brief Provided by Wisdom 0.7.1. Retrieves the GPU address of the acceleration structure. + * @return u64 The GPU address of the acceleration structure. + * + * */ + WIS_NODISCARD inline std::uint64_t GetGPUAddress() noexcept + { + return (::wisDX12AccelerationStructureGetGPUAddress(&_impl_storage)); + } +}; + struct DX12RaytracingExtensionDeleter { void operator()(WisDX12RaytracingExtension* handle) noexcept { ::wisDX12DestroyRaytracingExtension(handle); } }; @@ -43,6 +98,34 @@ class DX12RaytracingExtension : public wis::impl::Implements< * * */ WIS_NODISCARD inline bool Supported() noexcept { return (::wisDX12RaytracingExtensionSupported(&_impl_storage)); } + /** + * @brief Provided by Wisdom 0.7.1. Creates an acceleration structure based on the provided description. + * @param buffer The buffer to write the acceleration structure data to. + * @param desc The description of the acceleration structure to create. + * @param out_result denoting the outcome of operation. + * @return acceleration_structure The created acceleration structure handle. + * + * */ + WIS_NODISCARD inline wis::DX12AccelerationStructure CreateAccelerationStructure( + wis::DX12Buffer& buffer, + const wis::DX12AccelerationStructureDesc& desc, + wis::Result& out_result + ) noexcept + { + wis::DX12AccelerationStructure acceleration_structure; + const WisResult wis_result = ::wisDX12RaytracingExtensionCreateAccelerationStructure( + &_impl_storage, + reinterpret_cast(&buffer), + reinterpret_cast(&desc), + acceleration_structure.GetStorage() + ); + out_result = wis::Result{ + static_cast(wis_result.status), + wis_result.platform_code, + wis_result.error + }; + return acceleration_structure; + } }; } // namespace wis @@ -52,6 +135,46 @@ class DX12RaytracingExtension : public wis::impl::Implements< # include namespace wis { +/** + * @brief Provided by Wisdom 0.7.1. Structure describing the properties of an acceleration structure. + * + * */ +struct VKAccelerationStructureDesc { + wis::AccelerationStructureLevel level; ///< The level of the acceleration structure (top-level or bottom-level). + /** + * @brief The offset in bytes from the start of the buffer where the acceleration structure is located. + * */ + std::uint64_t offset; + std::uint64_t size; ///< The size of the acceleration structure in bytes. +}; + +struct VKAccelerationStructureDeleter { + void operator()(WisVKAccelerationStructure* handle) noexcept { ::wisVKDestroyAccelerationStructure(handle); } +}; +/** + * @brief Provided by Wisdom 0.7.1. Handle for an acceleration structure used in raytracing. + * + * */ +class VKAccelerationStructure : public wis::impl::Implements< + wis::impl::VKAccelerationStructureImpl, + WisVKAccelerationStructure, + wis::VKAccelerationStructureDeleter> +{ +public: + using ImplType::ImplType; + +public: + /** + * @brief Provided by Wisdom 0.7.1. Retrieves the GPU address of the acceleration structure. + * @return u64 The GPU address of the acceleration structure. + * + * */ + WIS_NODISCARD inline std::uint64_t GetGPUAddress() noexcept + { + return (::wisVKAccelerationStructureGetGPUAddress(&_impl_storage)); + } +}; + struct VKRaytracingExtensionDeleter { void operator()(WisVKRaytracingExtension* handle) noexcept { ::wisVKDestroyRaytracingExtension(handle); } }; @@ -79,6 +202,34 @@ class VKRaytracingExtension * * */ WIS_NODISCARD inline bool Supported() noexcept { return (::wisVKRaytracingExtensionSupported(&_impl_storage)); } + /** + * @brief Provided by Wisdom 0.7.1. Creates an acceleration structure based on the provided description. + * @param buffer The buffer to write the acceleration structure data to. + * @param desc The description of the acceleration structure to create. + * @param out_result denoting the outcome of operation. + * @return acceleration_structure The created acceleration structure handle. + * + * */ + WIS_NODISCARD inline wis::VKAccelerationStructure CreateAccelerationStructure( + wis::VKBuffer& buffer, + const wis::VKAccelerationStructureDesc& desc, + wis::Result& out_result + ) noexcept + { + wis::VKAccelerationStructure acceleration_structure; + const WisResult wis_result = ::wisVKRaytracingExtensionCreateAccelerationStructure( + &_impl_storage, + reinterpret_cast(&buffer), + reinterpret_cast(&desc), + acceleration_structure.GetStorage() + ); + out_result = wis::Result{ + static_cast(wis_result.status), + wis_result.platform_code, + wis_result.error + }; + return acceleration_structure; + } }; } // namespace wis diff --git a/src/extensions/raytracing/raytracing/generated/dx12_convert.hpp b/src/extensions/raytracing/raytracing/generated/dx12_convert.hpp new file mode 100644 index 000000000..a3acae89e --- /dev/null +++ b/src/extensions/raytracing/raytracing/generated/dx12_convert.hpp @@ -0,0 +1,15 @@ +// This file is generated. Do not edit directly. +#ifndef WISDOM_RAYTRACING_CPP_DX12_CONVERT_HPP +#define WISDOM_RAYTRACING_CPP_DX12_CONVERT_HPP +#ifndef __cplusplus +# error "This is a C++ only header" +#endif // __cplusplus + +#include +#include +#include "c_api.h" + +namespace wis { +namespace detail {} +} // namespace wis +#endif // WISDOM_RAYTRACING_CPP_DX12_CONVERT_HPP diff --git a/src/extensions/raytracing/raytracing/generated/vk_convert.hpp b/src/extensions/raytracing/raytracing/generated/vk_convert.hpp new file mode 100644 index 000000000..2ebeec15e --- /dev/null +++ b/src/extensions/raytracing/raytracing/generated/vk_convert.hpp @@ -0,0 +1,27 @@ +// This file is generated. Do not edit directly. +#ifndef WISDOM_RAYTRACING_CPP_VK_CONVERT_HPP +#define WISDOM_RAYTRACING_CPP_VK_CONVERT_HPP +#ifndef __cplusplus +# error "This is a C++ only header" +#endif // __cplusplus + +#include +#include "c_api.h" + +namespace wis { +namespace detail { +constexpr inline VkAccelerationStructureTypeKHR VKConvert(WisAccelerationStructureLevel value) noexcept +{ + switch (value) { + case WisAccelerationStructureLevelTopLevel: + return VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; + case WisAccelerationStructureLevelBottomLevel: + return VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; + default: + return static_cast(0); + } +} + +} // namespace detail +} // namespace wis +#endif // WISDOM_RAYTRACING_CPP_VK_CONVERT_HPP diff --git a/src/extensions/raytracing/raytracing/vulkan/vk_raytracing.cpp b/src/extensions/raytracing/raytracing/vulkan/vk_raytracing.cpp index 14519ef54..97ca62467 100644 --- a/src/extensions/raytracing/raytracing/vulkan/vk_raytracing.cpp +++ b/src/extensions/raytracing/raytracing/vulkan/vk_raytracing.cpp @@ -5,6 +5,8 @@ #include #include #include +#include +#include namespace wis::detail { inline WisResult VKRaytracingExtensionInit( @@ -54,6 +56,11 @@ inline WisResult VKRaytracingExtensionInit( ); } else { + if (impl.device_control_block) { + delete impl.rt_table; + wis::detail::VKReleaseDevice(impl.device_control_block); + } + // Create table and pass std::unique_ptr rt_table{new (std::nothrow) impl::VKRaytracingPipelineTable}; if (!rt_table) { @@ -81,6 +88,7 @@ inline WisResult VKRaytracingExtensionInit( } } // namespace wis::detail +//---------------------------------------------------------------------------------------------------------------------- WIS_EXTERN_C WISDOM_RAYTRACING_API void wisVKInitRaytracingExtension(WisVKRaytracingExtension* self) { new (self) wis::impl::VKRaytracingExtensionImpl{ @@ -88,6 +96,7 @@ WIS_EXTERN_C WISDOM_RAYTRACING_API void wisVKInitRaytracingExtension(WisVKRaytra }; } +//---------------------------------------------------------------------------------------------------------------------- WIS_EXTERN_C WISDOM_RAYTRACING_API void wisVKDestroyRaytracingExtension(WisVKRaytracingExtension* self) { auto& impl = wis::from_handle_ref(self); @@ -98,10 +107,82 @@ WIS_EXTERN_C WISDOM_RAYTRACING_API void wisVKDestroyRaytracingExtension(WisVKRay impl.header = {}; // Clear header to prevent accidental use after destruction } -WIS_EXTERN_C WISDOM_RAYTRACING_API bool wisVKRaytracingExtensionSupported(WisVKRaytracingExtension* self) +//---------------------------------------------------------------------------------------------------------------------- +WIS_EXTERN_C WISDOM_RAYTRACING_API bool wisVKRaytracingExtensionSupported(WisVKRaytracingExtension* self) { auto& impl = wis::from_handle_ref(self); return impl.device_control_block != nullptr; // Supported if the extension was successfully initialized } +//---------------------------------------------------------------------------------------------------------------------- +WIS_EXTERN_C WISDOM_RAYTRACING_API WisResult wisVKRaytracingExtensionCreateAccelerationStructure( + WisVKRaytracingExtension* self, + WisVKBuffer* buffer, + const WisVKAccelerationStructureDesc* desc, + WisVKAccelerationStructure* acceleration_structure +) +{ + auto& impl = wis::from_handle_ref(self); + auto& buffer_impl = wis::from_handle_ref(buffer); + + if (!buffer_impl.buffer_header) { + return wis::detail::make_result< + wis::detail::Func(), + "Provided buffer is not suitable for acceleration structure creation, did you forget to add " + "WisBufferUsageFlagsAccelerationStructureBuffer?">(VK_ERROR_UNKNOWN); + } + + // Build acceleration structure using the provided description + // This is a simplified example, actual implementation would involve more detailed handling of the description + VkAccelerationStructureCreateInfoKHR create_info{ + .sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR, + .pNext = nullptr, + .createFlags = 0, + .buffer = buffer_impl.buffer, + .offset = desc->offset, + .size = desc->size, + .type = wis::detail::VKConvert(desc->level), + }; + VkAccelerationStructureKHR as_handle = VK_NULL_HANDLE; + VkResult vr = impl.rt_table->vkCreateAccelerationStructureKHR(impl.device, &create_info, nullptr, &as_handle); + if (!wis::detail::succeeded(vr)) { + return wis::detail::make_result(vr); + } + + VkAccelerationStructureDeviceAddressInfoKHR info{ + .sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR, + .accelerationStructure = as_handle + }; + + auto& as_impl = *new (acceleration_structure) wis::impl::VKAccelerationStructureImpl{ + .acceleration_structure = as_handle, + .device_address = impl.rt_table->vkGetAccelerationStructureDeviceAddressKHR(impl.device, &info), + .buffer_control_block = buffer_impl.buffer_header, + }; + buffer_impl.buffer_header->AddRef(); // Hold reference to device control block for acceleration structure + return wis::detail::vk_success; +} + +//---------------------------------------------------------------------------------------------------------------------- +WIS_EXTERN_C WISDOM_RAYTRACING_API void wisVKDestroyAccelerationStructure(WisVKAccelerationStructure* self) +{ + auto& impl = wis::from_handle_ref(self); + if (impl.acceleration_structure != VK_NULL_HANDLE) { + impl.buffer_control_block->header.device_table->vkDestroyAccelerationStructureKHR( + impl.buffer_control_block->header.device, + impl.acceleration_structure, + nullptr + ); + impl.acceleration_structure = VK_NULL_HANDLE; + + wis::detail::VKReleaseBuffer(impl.buffer_control_block); // Release reference to device control block + } +} + +//---------------------------------------------------------------------------------------------------------------------- +WIS_EXTERN_C WISDOM_RAYTRACING_API uint64_t wisVKAccelerationStructureGetGPUAddress(WisVKAccelerationStructure* self) +{ + return wis::from_handle_ref(self).device_address; +} + #endif diff --git a/src/extensions/raytracing/raytracing/vulkan/vk_types.hpp b/src/extensions/raytracing/raytracing/vulkan/vk_types.hpp index a3fbc0d92..393c7cf8b 100644 --- a/src/extensions/raytracing/raytracing/vulkan/vk_types.hpp +++ b/src/extensions/raytracing/raytracing/vulkan/vk_types.hpp @@ -16,6 +16,12 @@ struct VKRaytracingExtensionImpl { impl::VKRaytracingPipelineTable* rt_table; }; +struct VKAccelerationStructureImpl { + VkAccelerationStructureKHR acceleration_structure; + VkDeviceAddress device_address; + detail::VKBufferControlBlock* buffer_control_block; +}; + } // namespace impl } // namespace wis diff --git a/src/extensions/raytracing/wisdom/wisdom_raytracing.h b/src/extensions/raytracing/wisdom/wisdom_raytracing.h index 485bc83c0..0d0806b10 100644 --- a/src/extensions/raytracing/wisdom/wisdom_raytracing.h +++ b/src/extensions/raytracing/wisdom/wisdom_raytracing.h @@ -22,15 +22,25 @@ static_assert(WISDOM_UWP && _WIN32, "Platform error"); // Handles //============================================================== +typedef struct WisDX12AccelerationStructure WisAccelerationStructure; typedef struct WisDX12RaytracingExtension WisRaytracingExtension; +//============================================================== +// Variants +//============================================================== + +typedef struct WisDX12AccelerationStructureDesc WisAccelerationStructureDesc; + //============================================================== // Functions //============================================================== -# define wisDestroyRaytracingExtension wisDX12DestroyRaytracingExtension -# define wisInitRaytracingExtension wisDX12InitRaytracingExtension -# define wisRaytracingExtensionSupported wisDX12RaytracingExtensionSupported +# define wisDestroyAccelerationStructure wisDX12DestroyAccelerationStructure +# define wisDestroyRaytracingExtension wisDX12DestroyRaytracingExtension +# define wisInitRaytracingExtension wisDX12InitRaytracingExtension +# define wisRaytracingExtensionSupported wisDX12RaytracingExtensionSupported +# define wisRaytracingExtensionCreateAccelerationStructure wisDX12RaytracingExtensionCreateAccelerationStructure +# define wisAccelerationStructureGetGPUAddress wisDX12AccelerationStructureGetGPUAddress #elif defined(WISDOM_VULKAN) @@ -38,15 +48,25 @@ typedef struct WisDX12RaytracingExtension WisRaytracingExtension; // Handles //============================================================== +typedef struct WisVKAccelerationStructure WisAccelerationStructure; typedef struct WisVKRaytracingExtension WisRaytracingExtension; +//============================================================== +// Variants +//============================================================== + +typedef struct WisVKAccelerationStructureDesc WisAccelerationStructureDesc; + //============================================================== // Functions //============================================================== -# define wisDestroyRaytracingExtension wisVKDestroyRaytracingExtension -# define wisInitRaytracingExtension wisVKInitRaytracingExtension -# define wisRaytracingExtensionSupported wisVKRaytracingExtensionSupported +# define wisDestroyAccelerationStructure wisVKDestroyAccelerationStructure +# define wisDestroyRaytracingExtension wisVKDestroyRaytracingExtension +# define wisInitRaytracingExtension wisVKInitRaytracingExtension +# define wisRaytracingExtensionSupported wisVKRaytracingExtensionSupported +# define wisRaytracingExtensionCreateAccelerationStructure wisVKRaytracingExtensionCreateAccelerationStructure +# define wisAccelerationStructureGetGPUAddress wisVKAccelerationStructureGetGPUAddress #else # error "No API selected for Wisdom. Define WISDOM_DX12 or WISDOM_VULKAN." diff --git a/src/extensions/raytracing/wisdom/wisdom_raytracing.hpp b/src/extensions/raytracing/wisdom/wisdom_raytracing.hpp index 1838aa2ae..4f08c5cbe 100644 --- a/src/extensions/raytracing/wisdom/wisdom_raytracing.hpp +++ b/src/extensions/raytracing/wisdom/wisdom_raytracing.hpp @@ -24,8 +24,15 @@ namespace wis { // Handles //============================================================== +using AccelerationStructure = wis::DX12AccelerationStructure; using RaytracingExtension = wis::DX12RaytracingExtension; +//============================================================== +// Variants +//============================================================== + +using AccelerationStructureDesc = wis::DX12AccelerationStructureDesc; + } // namespace wis #elif defined(WISDOM_VULKAN) @@ -36,8 +43,15 @@ namespace wis { // Handles //============================================================== +using AccelerationStructure = wis::VKAccelerationStructure; using RaytracingExtension = wis::VKRaytracingExtension; +//============================================================== +// Variants +//============================================================== + +using AccelerationStructureDesc = wis::VKAccelerationStructureDesc; + } // namespace wis #else # error "No API selected for Wisdom. Define WISDOM_DX12 or WISDOM_VULKAN." diff --git a/src/include/wisdom/generated/c_api.h b/src/include/wisdom/generated/c_api.h index b1ddcd6c3..1fc10c7e2 100644 --- a/src/include/wisdom/generated/c_api.h +++ b/src/include/wisdom/generated/c_api.h @@ -2643,7 +2643,7 @@ WIS_DEFINE_HANDLE(WisDX12ViewHeap, 6); * GPU pipeline and allows to execute draw and dispatch calls with it. * * */ -WIS_DEFINE_HANDLE(WisDX12Pipeline, 1); +WIS_DEFINE_HANDLE(WisDX12Pipeline, 2); WIS_DEFINE_HANDLE_VIEW(WisDX12Pipeline, 1); static inline WisDX12PipelineView wisGetDX12PipelineView(const WisDX12Pipeline* handle) @@ -4264,7 +4264,7 @@ static inline WisVKTextureView wisGetVKTextureView(const WisVKTexture* handle) * @brief Provided by Wisdom 0.7.0. Class representing a GPU buffer resource. * * */ -WIS_DEFINE_HANDLE(WisVKBuffer, 4); +WIS_DEFINE_HANDLE(WisVKBuffer, 5); WIS_DEFINE_HANDLE_VIEW(WisVKBuffer, 1); static inline WisVKBufferView wisGetVKBufferView(const WisVKBuffer* handle) @@ -4307,7 +4307,7 @@ WIS_DEFINE_HANDLE(WisVKViewHeap, 3); * GPU pipeline and allows to execute draw and dispatch calls with it. * * */ -WIS_DEFINE_HANDLE(WisVKPipeline, 2); +WIS_DEFINE_HANDLE(WisVKPipeline, 3); WIS_DEFINE_HANDLE_VIEW(WisVKPipeline, 1); static inline WisVKPipelineView wisGetVKPipelineView(const WisVKPipeline* handle) diff --git a/src/include/wisdom/vulkan/detail/vk_detail.hpp b/src/include/wisdom/vulkan/detail/vk_detail.hpp index 157f26a1e..882f66820 100644 --- a/src/include/wisdom/vulkan/detail/vk_detail.hpp +++ b/src/include/wisdom/vulkan/detail/vk_detail.hpp @@ -386,6 +386,19 @@ struct alignas(void*) VKRootSignatureControlBlock { } }; +//---------------------------------------------------------------------------------------------------------------------- +struct VKBufferHeader { + VkBuffer buffer; + VmaAllocation allocation; + void* mapped_ptr; + VkDevice device; + detail::VKDeviceControlBlock* device_header; + impl::VKMainDevice* device_table; +}; + +//---------------------------------------------------------------------------------------------------------------------- +struct VKBufferControlBlock : public VKControlBlock {}; + //---------------------------------------------------------------------------------------------------------------------- struct VKRenderTargetView { VkImageView view = VK_NULL_HANDLE; @@ -554,6 +567,27 @@ inline void VKReleaseSwapchain(VkSwapchainKHR swap, VKSwapchainControlBlock* hea } } +//---------------------------------------------------------------------------------------------------------------------- +inline void VKReleaseBuffer(VKBufferControlBlock* header) noexcept +{ + if (header && header->Release() == 1) { + auto& header_ref = header->header; + + // get allocator + VmaAllocator allocator = header_ref.device_header->header.allocator; + + if (header_ref.mapped_ptr) { + vmaUnmapMemory(allocator, header_ref.allocation); + } + vmaDestroyBuffer(allocator, header_ref.buffer, header_ref.allocation); + + header_ref.buffer = VK_NULL_HANDLE; + + wis::detail::VKReleaseDevice(header_ref.device_header); + delete header; + } +} + } // namespace wis::detail #endif // WIS_VK_DETAIL_HPP diff --git a/src/include/wisdom/vulkan/vk_impl.cpp b/src/include/wisdom/vulkan/vk_impl.cpp index 7c9c405d7..1cc6abbbb 100644 --- a/src/include/wisdom/vulkan/vk_impl.cpp +++ b/src/include/wisdom/vulkan/vk_impl.cpp @@ -10,6 +10,13 @@ WIS_EXTERN_C WISDOM_API void wisVKDestroyBuffer(WisVKBuffer* self) { auto& impl = wis::from_handle_ref(self); if (impl.buffer != VK_NULL_HANDLE) { + + if (impl.buffer_header) { + wis::detail::VKReleaseBuffer(impl.buffer_header); + impl.buffer = VK_NULL_HANDLE; + return; + } + // get allocator VmaAllocator allocator = impl.device_header->header.allocator; diff --git a/src/include/wisdom/vulkan/vk_resource_allocator.cpp b/src/include/wisdom/vulkan/vk_resource_allocator.cpp index 155a5654b..b3457c91e 100644 --- a/src/include/wisdom/vulkan/vk_resource_allocator.cpp +++ b/src/include/wisdom/vulkan/vk_resource_allocator.cpp @@ -155,11 +155,36 @@ WIS_EXTERN_C WISDOM_API WisResult wisVKResourceAllocatorCreateBuffer( } } + wis::detail::VKBufferControlBlock* buffer_header = nullptr; + if (desc->usage_flags & WisBufferUsageFlagsAccelerationStructureBuffer) { + // Shared buffer for AS needs to be tracked separately + buffer_header = new (std::nothrow) wis::detail::VKBufferControlBlock{}; + if (!buffer_header) { + if (mapped_ptr) { + vmaUnmapMemory(allocator.allocator, allocation_handle); + } + vmaDestroyBuffer(allocator.allocator, buffer_handle, allocation_handle); + return wis::detail::make_result( + VK_ERROR_OUT_OF_HOST_MEMORY + ); + } + + buffer_header->header = { + .buffer = buffer_handle, + .allocation = allocation_handle, + .mapped_ptr = mapped_ptr, + .device = allocator.device_header->header.device, + .device_header = allocator.device_header, + .device_table = &allocator.device_header->header.device_table, + }; + } + auto& impl = *new (buffer) wis::impl::VKBufferImpl{ .buffer = buffer_handle, .allocation = allocation_handle, .mapped_ptr = mapped_ptr, .device_header = allocator.device_header, + .buffer_header = buffer_header, }; impl.device_header->AddRef(); diff --git a/src/include/wisdom/vulkan/vk_tables.hpp b/src/include/wisdom/vulkan/vk_tables.hpp index 2a65e6967..874768c81 100644 --- a/src/include/wisdom/vulkan/vk_tables.hpp +++ b/src/include/wisdom/vulkan/vk_tables.hpp @@ -324,6 +324,8 @@ struct VKMainDevice { PFN_vkGetMemoryWin32HandleKHR vkGetMemoryWin32HandleKHR; #endif //_WIN32 + PFN_vkDestroyAccelerationStructureKHR vkDestroyAccelerationStructureKHR; + public: bool Init(VkDevice device, PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr) noexcept { @@ -408,6 +410,7 @@ struct VKMainDevice { #ifdef _WIN32 ASSIGN_DEVICE_PROC_ADDR_OPTIONAL(device, vkGetMemoryWin32HandleKHR); #endif //_WIN32 + ASSIGN_DEVICE_PROC_ADDR_OPTIONAL(device, vkDestroyAccelerationStructureKHR); return true; } }; diff --git a/src/include/wisdom/vulkan/vk_types.hpp b/src/include/wisdom/vulkan/vk_types.hpp index 59b3fa4d6..7bcdbe6c8 100644 --- a/src/include/wisdom/vulkan/vk_types.hpp +++ b/src/include/wisdom/vulkan/vk_types.hpp @@ -26,6 +26,7 @@ struct VKSurfaceControlBlock; struct VKQueueFamilyExtras; struct VKSwapchainControlBlock; struct VKRenderTargetView; +struct VKBufferControlBlock; } // namespace detail namespace impl { @@ -116,6 +117,7 @@ struct VKBufferImpl { VmaAllocation allocation; void* mapped_ptr; detail::VKDeviceControlBlock* device_header; + detail::VKBufferControlBlock* buffer_header; // only for buffers for AS }; struct VKTextureImpl { diff --git a/tests/basic/CMakeLists.txt b/tests/basic/CMakeLists.txt index 14735d023..c8e460b9a 100644 --- a/tests/basic/CMakeLists.txt +++ b/tests/basic/CMakeLists.txt @@ -1,4 +1,4 @@ -set(TEST_SOURCES "relaxed_destruction_order.cpp" "rt_basic.cpp") +set(TEST_SOURCES "relaxed_destruction_order.cpp" "rt_basic.cpp" "rt_primitives.cpp") if(WISDOM_DX12) wis_add_test(test-basic "${TEST_SOURCES}" "dx12") diff --git a/tests/basic/rt_basic.cpp b/tests/basic/rt_basic.cpp index b27f701a5..9abe5bc49 100644 --- a/tests/basic/rt_basic.cpp +++ b/tests/basic/rt_basic.cpp @@ -46,6 +46,7 @@ TEST_CASE("check_rt_support") wisDestroyDevice(&device); break; } + wisDestroyDevice(&device); } printf("Raytracing supported: %s\n", supported ? "Yes" : "No"); diff --git a/tests/basic/rt_primitives.cpp b/tests/basic/rt_primitives.cpp new file mode 100644 index 000000000..32730643b --- /dev/null +++ b/tests/basic/rt_primitives.cpp @@ -0,0 +1,116 @@ +#include +#include +#include + +void log_callback_rt(wis::Severity severity, const char* message, uint64_t device, void* user_data) +{ + const char* severity_str = ""; + switch (severity) { + case wis::Severity::Verbose: + severity_str = "VERBOSE"; + break; + case wis::Severity::Info: + severity_str = "INFO"; + break; + case wis::Severity::Warning: + severity_str = "WARNING"; + break; + case wis::Severity::Error: + severity_str = "ERROR"; + printf("[%s] %s\n", severity_str, message); + break; + case wis::Severity::Fatal: + severity_str = "FATAL"; + printf("[%s] %s\n", severity_str, message); + FAIL(); + break; + default: + severity_str = "UNKNOWN"; + break; + } + printf("[%s] %s\n", severity_str, message); +} + +TEST_CASE("check_rt_acceleration_structure") +{ + wis::Result result{}; + wis::DebugDesc debug{ + .enable_debug_layer = true, + .callback = log_callback_rt, + .user_data = nullptr, + }; + + wis::Instance instance = wis::CreateInstance(&debug, {}, result); + REQUIRE(result.status == wis::Status::Ok); + + wis::AdapterQuery adapter_query = instance.QueryAdapters(wis::AdapterPreference::Performance, result); + REQUIRE(result.status == wis::Status::Ok); + + wis::RaytracingExtension rt_extension{}; + + wis::CommandQueueDesc queue_descs[] = { + {wis::CommandQueueType::Graphics, wis::CommandQueuePriority::Normal}, + }; + wis::DeviceExtensionHeader* extensions[] = { + &rt_extension, + }; + wis::DeviceRequirements device_requirements{ + .queue_descs = queue_descs, + .extensions = extensions, + }; + wis::Device device{}; + for (size_t i = 0; i < adapter_query.GetAdapterCount(); ++i) { + device = adapter_query.CreateDevice(i, device_requirements, result); + if (result.status == wis::Status::Ok) { + break; + } + } + + // If we don't have RT support -> skip the test. + if (result.status != wis::Status::Ok) { + printf( + "Failed to create device for raytracing test: %d, platform_code: %d, error: %s\n", + result.status, + result.platform_code, + result.error ? result.error : "None" + ); + return; + } + + wis::ResourceAllocator allocator = device.GetResourceAllocator(result); + REQUIRE(result.status == wis::Status::Ok); + + wis::Buffer rtas_buffer = allocator.CreateBuffer( + { + .size_bytes = 1024, + .usage_flags = wis::BufferUsageFlags::AccelerationStructureBuffer, + }, + result + ); + REQUIRE(result.status == wis::Status::Ok); + + wis::Buffer scratch_buffer = allocator.CreateBuffer( + { + .size_bytes = 1024, + .usage_flags = wis::BufferUsageFlags::StorageBuffer, + }, + result + ); + REQUIRE(result.status == wis::Status::Ok); + + // we won't update the as + wis::AccelerationStructure blas = rt_extension.CreateAccelerationStructure( + rtas_buffer, + { + .level = wis::AccelerationStructureLevel::BottomLevel, + .offset = 0, + .size = 1024, + }, + result + ); + REQUIRE(result.status == wis::Status::Ok); + + uint64_t gpu_address = blas.GetGPUAddress(); + REQUIRE(gpu_address != 0); +} + diff --git a/xml/raytracing.xml b/xml/raytracing.xml index 94e574141..22e976afa 100644 --- a/xml/raytracing.xml +++ b/xml/raytracing.xml @@ -1,8 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + @@ -13,7 +35,17 @@ + + + + + + + + + + - + diff --git a/xml/wis.xml b/xml/wis.xml index a1ee0248f..2216ba0e6 100644 --- a/xml/wis.xml +++ b/xml/wis.xml @@ -14,7 +14,7 @@ - + @@ -32,7 +32,7 @@ - + From e1d49a96d306f29a669577878ef11b2afd430c93 Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Sun, 26 Apr 2026 15:01:11 +0200 Subject: [PATCH 12/49] Add cross-API query for BLAS memory requirements Introduced enums and structs for geometry and allocation description. Added wisRaytracingExtensionGetBottomLevelStructureInfo to query acceleration structure and scratch buffer sizes for DX12 and Vulkan. Updated C/C++ APIs, backend implementations, and tests to use the new mechanism. Improved documentation and defined alignment constants. Updated XML registry and codegen for new API. --- docs/raytracing/constants.h | 27 +++ .../enum/acceleration_structure_flags_enum.h | 66 +++++++ docs/raytracing/enum/geometry_flags_enum.h | 52 ++++++ docs/raytracing/enum/geometry_type_enum.h | 50 ++++++ ...n_create_acceleration_structure_function.h | 5 +- ...get_bottom_level_structure_info_function.h | 79 ++++++++ .../handle/raytracing_extension_handle.h | 2 +- .../struct/accelerated_geometry_desc_struct.h | 81 +++++++++ .../acceleration_structure_desc_struct.h | 5 + ...bottom_level_structure_build_desc_struct.h | 61 +++++++ .../struct/structure_allocation_info_struct.h | 53 ++++++ docs/wisdom/handle/pipeline_handle.h | 4 +- generator/generator.cpp | 1 + .../raytracing/dx12/dx12_raytracing.cpp | 102 +++++++++++ .../raytracing/raytracing/dx12/dx12_types.hpp | 2 +- .../raytracing/raytracing/generated/c_api.h | 150 ++++++++++++++++ .../raytracing/generated/cpp_api.hpp | 168 ++++++++++++++++++ .../raytracing/generated/dx12_convert.hpp | 52 +++++- .../raytracing/generated/vk_convert.hpp | 46 +++++ .../raytracing/vulkan/vk_raytracing.cpp | 115 ++++++++++++ .../raytracing/wisdom/wisdom_raytracing.h | 2 + src/include/wisdom/generated/vk_convert.hpp | 1 + tests/basic/rt_primitives.cpp | 49 ++++- xml/raytracing.xml | 92 +++++++++- xml/wis.xml | 2 +- 25 files changed, 1256 insertions(+), 11 deletions(-) create mode 100644 docs/raytracing/constants.h create mode 100644 docs/raytracing/enum/acceleration_structure_flags_enum.h create mode 100644 docs/raytracing/enum/geometry_flags_enum.h create mode 100644 docs/raytracing/enum/geometry_type_enum.h create mode 100644 docs/raytracing/func/raytracing_extension_get_bottom_level_structure_info_function.h create mode 100644 docs/raytracing/struct/accelerated_geometry_desc_struct.h create mode 100644 docs/raytracing/struct/bottom_level_structure_build_desc_struct.h create mode 100644 docs/raytracing/struct/structure_allocation_info_struct.h diff --git a/docs/raytracing/constants.h b/docs/raytracing/constants.h new file mode 100644 index 000000000..caeeeb862 --- /dev/null +++ b/docs/raytracing/constants.h @@ -0,0 +1,27 @@ +/** + * @page RaytracingConstants + * @ingroup Constants Raytracing + * + * + * @section RaytracingConstants_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C Version: + * ```c + * #define WIS_ACCELERATION_STRUCTURE_ALIGNMENT ((uint32_t)256) + * ``` + * + * C++ Version: + * ```cpp + * namespace wis{ + * static constexpr std::uint32_t AccelerationStructureAlignment = 256; + * } + * ``` + * \endcond + * + * @section RaytracingConstants_see_also See Also + *
+ * \cond WIS_GEN_REFS + * \endcond + */ diff --git a/docs/raytracing/enum/acceleration_structure_flags_enum.h b/docs/raytracing/enum/acceleration_structure_flags_enum.h new file mode 100644 index 000000000..eba383f5d --- /dev/null +++ b/docs/raytracing/enum/acceleration_structure_flags_enum.h @@ -0,0 +1,66 @@ +/** + * @struct WisAccelerationStructureFlags WisAccelerationStructureFlags + * @ingroup Enumerations Raytracing + * + * @section WisAccelerationStructureFlags_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef enum WisAccelerationStructureFlags { + * WisAccelerationStructureFlagsNone = 0, + * WisAccelerationStructureFlagsAllowUpdate = (1u << 0), + * WisAccelerationStructureFlagsAllowCompaction = (1u << 1), + * WisAccelerationStructureFlagsPreferFastTrace = (1u << 2), + * WisAccelerationStructureFlagsPreferFastBuild = (1u << 3), + * WisAccelerationStructureFlagsMinimizeMemory = (1u << 4), + * WisAccelerationStructureFlagsPerformUpdate = (1u << 5), + * } WisAccelerationStructureFlags; + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * enum class AccelerationStructureFlags : uint32_t { + * None = 0, + * AllowUpdate = (1u << 0), + * AllowCompaction = (1u << 1), + * PreferFastTrace = (1u << 2), + * PreferFastBuild = (1u << 3), + * MinimizeMemory = (1u << 4), + * PerformUpdate = (1u << 5), + * }; + * } + * ``` + * \endcond + * + * @section WisAccelerationStructureFlags_descr Description + *
+ * \cond WIS_GEN_DESC + * Acceleration structure flags for additional acceleration structure features + * + * \note Translates to DirectX 12 as D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS, Vulkan as + * VkBuildAccelerationStructureFlagsKHR. + * + * Values: + * - `WisAccelerationStructureFlagsNone = 0`: No flags set. Acceleration structure is regular. + * - `WisAccelerationStructureFlagsAllowUpdate = (1 << 0)`: Acceleration structure is allowed to be updated. + * - `WisAccelerationStructureFlagsAllowCompaction = (1 << 1)`: Acceleration structure is allowed to be compacted. + * - `WisAccelerationStructureFlagsPreferFastTrace = (1 << 2)`: Acceleration structure is preferred to be fast traced. + * - `WisAccelerationStructureFlagsPreferFastBuild = (1 << 3)`: Acceleration structure is preferred to be fast built. + * - `WisAccelerationStructureFlagsMinimizeMemory = (1 << 4)`: Acceleration structure is minimized for memory usage. + * - `WisAccelerationStructureFlagsPerformUpdate = (1 << 5)`: Acceleration structure build is performed as an update. + * Only used for update builds. + * \endcond + * + * + * @section WisAccelerationStructureFlags_see_also See Also + *
+ * + * \cond WIS_GEN_REFS + * @see Structs: + * WisBottomLevelStructureBuildDesc + * \endcond + */ diff --git a/docs/raytracing/enum/geometry_flags_enum.h b/docs/raytracing/enum/geometry_flags_enum.h new file mode 100644 index 000000000..af3f953df --- /dev/null +++ b/docs/raytracing/enum/geometry_flags_enum.h @@ -0,0 +1,52 @@ +/** + * @struct WisGeometryFlags WisGeometryFlags + * @ingroup Enumerations Raytracing + * + * @section WisGeometryFlags_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef enum WisGeometryFlags { + * WisGeometryFlagsNone = 0, + * WisGeometryFlagsOpaque = (1u << 0), + * WisGeometryFlagsNoDuplicateAnyHitInvocation = (1u << 1), + * } WisGeometryFlags; + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * enum class GeometryFlags : uint32_t { + * None = 0, + * Opaque = (1u << 0), + * NoDuplicateAnyHitInvocation = (1u << 1), + * }; + * } + * ``` + * \endcond + * + * @section WisGeometryFlags_descr Description + *
+ * \cond WIS_GEN_DESC + * Bitmask for geometry flags in raytracing. + * + * \note Translates to DirectX 12 as D3D12_RAYTRACING_GEOMETRY_FLAGS, Vulkan as VkGeometryFlagsKHR. + * + * Values: + * - `WisGeometryFlagsNone = 0`: No flags set. Geometry is regular. + * - `WisGeometryFlagsOpaque = (1 << 0)`: Geometry is opaque. Used for opaque geometry. + * - `WisGeometryFlagsNoDuplicateAnyHitInvocation = (1 << 1)`: Geometry has no duplicate any hit invocation. + * \endcond + * + * + * @section WisGeometryFlags_see_also See Also + *
+ * + * \cond WIS_GEN_REFS + * @see Structs: + * WisAcceleratedGeometryDesc + * \endcond + */ diff --git a/docs/raytracing/enum/geometry_type_enum.h b/docs/raytracing/enum/geometry_type_enum.h new file mode 100644 index 000000000..bceec0863 --- /dev/null +++ b/docs/raytracing/enum/geometry_type_enum.h @@ -0,0 +1,50 @@ +/** + * @struct WisGeometryType WisGeometryType + * @ingroup Enumerations Raytracing + * + * @section WisGeometryType_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef enum WisGeometryType { + * WisGeometryTypeTriangles = 0, + * WisGeometryTypeAABBs = 1, + * } WisGeometryType; + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * enum class GeometryType { + * Triangles = 0, + * AABBs = 1, + * }; + * } + * ``` + * \endcond + * + * @section WisGeometryType_descr Description + *
+ * \cond WIS_GEN_DESC + * Enumeration for the type of geometry in a bottom-level acceleration structure. + * + * \note Translates to `D3D12_RAYTRACING_GEOMETRY_TYPE` for DirectX 12 implementation, and `VkGeometryTypeKHR` for + * Vulkan implementation. + * + * Values: + * - `WisGeometryTypeTriangles = 0`: Triangles geometry type. Used for triangle meshes. + * - `WisGeometryTypeAABBs = 1`: Axis Aligned Bounding Boxes geometry type. Used for bounding volume hierarchies. + * \endcond + * + * + * @section WisGeometryType_see_also See Also + *
+ * + * \cond WIS_GEN_REFS + * @see Structs: + * WisAcceleratedGeometryDesc + * \endcond + */ diff --git a/docs/raytracing/func/raytracing_extension_create_acceleration_structure_function.h b/docs/raytracing/func/raytracing_extension_create_acceleration_structure_function.h index 348d28c1d..1dd9bce18 100644 --- a/docs/raytracing/func/raytracing_extension_create_acceleration_structure_function.h +++ b/docs/raytracing/func/raytracing_extension_create_acceleration_structure_function.h @@ -72,9 +72,10 @@ * * @section wisRaytracingExtensionCreateAccelerationStructure_descr Description *
- * + * * The resulting acceleration structure stores reference to provided buffer, extending its lifetime to that of the - * acceleration structure. The buffer @wis_must be created with `WisBufferUsageFlagsAccelerationStructureBuffer` usage flag. + * acceleration structure. The buffer @wis_must be created with `WisBufferUsageFlagsAccelerationStructureBuffer` usage + * flag. * * \cond WIS_GEN_WIS_IDS * \endcond diff --git a/docs/raytracing/func/raytracing_extension_get_bottom_level_structure_info_function.h b/docs/raytracing/func/raytracing_extension_get_bottom_level_structure_info_function.h new file mode 100644 index 000000000..da94e93d4 --- /dev/null +++ b/docs/raytracing/func/raytracing_extension_get_bottom_level_structure_info_function.h @@ -0,0 +1,79 @@ +/** + * @struct wisRaytracingExtensionGetBottomLevelStructureInfo + * @ingroup Functions Raytracing + * + * + * @section wisRaytracingExtensionGetBottomLevelStructureInfo_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C Version: + * ```c + * // Provided by Wisdom 0.7.1. + * WisResult wisRaytracingExtensionGetBottomLevelStructureInfo(WisRaytracingExtension* self, + * const WisBottomLevelStructureBuildDesc* build_desc, + * WisStructureAllocationInfo* info); + * ``` + *
+ * C Implementation Specific Version: + * ```c + * // Provided by Wisdom 0.7.1. + * WisResult wisVKRaytracingExtensionGetBottomLevelStructureInfo(WisVKRaytracingExtension* self, + * const WisBottomLevelStructureBuildDesc* build_desc, + * WisStructureAllocationInfo* info); + * + * // Provided by Wisdom 0.7.1. + * WisResult wisDX12RaytracingExtensionGetBottomLevelStructureInfo(WisDX12RaytracingExtension* self, + * const WisBottomLevelStructureBuildDesc* build_desc, + * WisStructureAllocationInfo* info); + * ``` + *
+ * + * C++ Version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * WIS_NODISCARD wis::StructureAllocationInfo RaytracingExtension::GetBottomLevelStructureInfo(const + * wis::BottomLevelStructureBuildDesc& build_desc, wis::Result& out_result) noexcept; + * } + * ``` + *
+ * C++ Implementation Specific Version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * WIS_NODISCARD wis::StructureAllocationInfo VKRaytracingExtension::GetBottomLevelStructureInfo(const + * wis::BottomLevelStructureBuildDesc& build_desc, wis::Result& out_result) noexcept; + * + * // Provided by Wisdom 0.7.1. + * WIS_NODISCARD wis::StructureAllocationInfo DX12RaytracingExtension::GetBottomLevelStructureInfo(const + * wis::BottomLevelStructureBuildDesc& build_desc, wis::Result& out_result) noexcept; + * } + * ``` + *
+ * \endcond + * + * @section wisRaytracingExtensionGetBottomLevelStructureInfo_memb Parameters + *
+ * \cond WIS_GEN_DESC + * - **this** `self` self is a pointer to the valid WisRaytracingExtension instance. + * - `build_desc` The build description for the bottom-level acceleration structure. + * - `info` The allocation information for the bottom-level acceleration structure. + * + * - **return** denoting the outcome of operation. + * \endcond + * + * @section wisRaytracingExtensionGetBottomLevelStructureInfo_descr Description + *
+ * + * The function does not dereference the GPU addresses. It @wis_may only do null checks on the GPU addresses, while all + * the CPU parameters in the build description are used to determine the allocation sizes. + * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section wisRaytracingExtensionGetBottomLevelStructureInfo_see_also See Also + *
+ * \cond WIS_GEN_REFS + * \endcond + */ diff --git a/docs/raytracing/handle/raytracing_extension_handle.h b/docs/raytracing/handle/raytracing_extension_handle.h index 95264634a..37499b48b 100644 --- a/docs/raytracing/handle/raytracing_extension_handle.h +++ b/docs/raytracing/handle/raytracing_extension_handle.h @@ -26,6 +26,6 @@ * \cond WIS_GEN_REFS * @see Functions: * wisDestroyRaytracingExtension, wisInitRaytracingExtension, wisRaytracingExtensionSupported, - * wisRaytracingExtensionCreateAccelerationStructure + * wisRaytracingExtensionGetBottomLevelStructureInfo, wisRaytracingExtensionCreateAccelerationStructure * \endcond */ diff --git a/docs/raytracing/struct/accelerated_geometry_desc_struct.h b/docs/raytracing/struct/accelerated_geometry_desc_struct.h new file mode 100644 index 000000000..650dac455 --- /dev/null +++ b/docs/raytracing/struct/accelerated_geometry_desc_struct.h @@ -0,0 +1,81 @@ +/** + * @struct WisAcceleratedGeometryDesc + * @ingroup Structures Raytracing + * + * + * @section WisAcceleratedGeometryDesc_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef struct WisAcceleratedGeometryDesc { + * WisGeometryType type; + * WisGeometryFlags flags; + * uint64_t vertex_or_aabb_buffer_address; + * uint64_t index_buffer_address; + * uint64_t transform_matrix_address; + * uint32_t vertex_or_aabb_stride; + * uint32_t vertex_count; + * uint32_t triangle_or_aabb_count; + * WisDataFormat vertex_format; + * WisIndexType index_format; + * } WisAcceleratedGeometryDesc; + * + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * struct AcceleratedGeometryDesc { + * wis::GeometryType type; + * wis::GeometryFlags flags; + * std::uint64_t vertex_or_aabb_buffer_address; + * std::uint64_t index_buffer_address; + * std::uint64_t transform_matrix_address; + * std::uint32_t vertex_or_aabb_stride; + * std::uint32_t vertex_count; + * std::uint32_t triangle_or_aabb_count; + * wis::DataFormat vertex_format; + * wis::IndexType index_format; + * }; + * } + * ``` + * \endcond + * + * @section WisAcceleratedGeometryDesc_memb Members + *
+ * \cond WIS_GEN_DESC + * - `type` The type of geometry (triangles or AABBs). + * - `flags` The geometry flags for this geometry instance. + * - `vertex_or_aabb_buffer_address` The GPU address of the vertex buffer for this geometry instance. + * - `index_buffer_address` The GPU address of the index buffer for this geometry instance. Only used for triangles + * geometry type. + * - `transform_matrix_address` The GPU address of the transform matrix (float [3][4]) for this geometry instance. Only + * used for triangles geometry type. + * - `vertex_or_aabb_stride` The stride in bytes between vertices or AABBs in the buffer. + * - `vertex_count` The number of vertices in the vertex buffer. Only used for triangles geometry type. + * - `triangle_or_aabb_count` For triangles it is equal to (index_count/3) and count for AABBs. + * - `vertex_format` The format of the vertex data in the vertex buffer. Only used for triangles geometry type. + * - `index_format` The format of the index data in the index buffer. Only used for triangles geometry type. + * \endcond + * + * @section WisAcceleratedGeometryDesc_descr Description + *
+ * + * If the geometry type is `WisGeometryType::Triangles`, the geometry instance represents a triangle mesh. + * If the `index_buffer_address` is 0, the geometry is non-indexed and `vertex_count` is used to determine the number of + * triangles (vertex_count/3). + * + * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section WisAcceleratedGeometryDesc_see_also See Also + *
+ * \cond WIS_GEN_REFS + * @see Structs: + * WisBottomLevelStructureBuildDesc + * \endcond + */ diff --git a/docs/raytracing/struct/acceleration_structure_desc_struct.h b/docs/raytracing/struct/acceleration_structure_desc_struct.h index b496ad4e7..148414260 100644 --- a/docs/raytracing/struct/acceleration_structure_desc_struct.h +++ b/docs/raytracing/struct/acceleration_structure_desc_struct.h @@ -79,6 +79,11 @@ * @section WisAccelerationStructureDesc_descr Description *
* + * `size` of the acceleration structure can be queried using `wisRaytracingExtensionGetBottomLevelStructureInfo` + * function, which provides the necessary size based on the build description of the acceleration structure. + * + * `offset` allows for creating multiple acceleration structures within the same buffer by specifying different offsets + * for each structure. It @wis_must be aligned to `AccelerationStructureAlignment`. * \cond WIS_GEN_WIS_IDS * \endcond * diff --git a/docs/raytracing/struct/bottom_level_structure_build_desc_struct.h b/docs/raytracing/struct/bottom_level_structure_build_desc_struct.h new file mode 100644 index 000000000..b1f8e4a5e --- /dev/null +++ b/docs/raytracing/struct/bottom_level_structure_build_desc_struct.h @@ -0,0 +1,61 @@ +/** + * @struct WisBottomLevelStructureBuildDesc + * @ingroup Structures Raytracing + * + * + * @section WisBottomLevelStructureBuildDesc_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef struct WisBottomLevelStructureBuildDesc { + * WisAccelerationStructureFlags flags; + * uint32_t geometry_count; + * const WisAcceleratedGeometryDesc* geometries; + * const WisAcceleratedGeometryDesc** indirect_geometries; + * } WisBottomLevelStructureBuildDesc; + * + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * struct BottomLevelStructureBuildDesc { + * wis::AccelerationStructureFlags flags; + * std::uint32_t geometry_count; + * const wis::AcceleratedGeometryDesc* geometries; + * const wis::AcceleratedGeometryDesc** indirect_geometries; + * }; + * } + * ``` + * \endcond + * + * @section WisBottomLevelStructureBuildDesc_memb Members + *
+ * \cond WIS_GEN_DESC + * - `flags` The build flags for the acceleration structure build. + * - `geometry_count` The number of geometry instances in the bottom-level acceleration structure. + * - `geometries` The array of geometry descriptions for the bottom-level acceleration structure. Has higher precedence + * over `WisBottomLevelStructureBuildDesc::indirect_geometries`. + * - `indirect_geometries` The array of geometry descriptions for indirect build of the bottom-level acceleration + * structure. + * \endcond + * + * @section WisBottomLevelStructureBuildDesc_descr Description + *
+ * + * `geometries` and `indirect_geometries` are mutually exclusive. If both are provided, `geometries` will be used and + * `indirect_geometries` will be ignored. + * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section WisBottomLevelStructureBuildDesc_see_also See Also + *
+ * \cond WIS_GEN_REFS + * @see Functions: + * wisRaytracingExtensionGetBottomLevelStructureInfo + * \endcond + */ diff --git a/docs/raytracing/struct/structure_allocation_info_struct.h b/docs/raytracing/struct/structure_allocation_info_struct.h new file mode 100644 index 000000000..4e9779d94 --- /dev/null +++ b/docs/raytracing/struct/structure_allocation_info_struct.h @@ -0,0 +1,53 @@ +/** + * @struct WisStructureAllocationInfo + * @ingroup Structures Raytracing + * + * + * @section WisStructureAllocationInfo_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef struct WisStructureAllocationInfo { + * uint64_t structure_size; + * uint64_t scratch_size; + * uint64_t update_size; + * } WisStructureAllocationInfo; + * + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * struct StructureAllocationInfo { + * std::uint64_t structure_size; + * std::uint64_t scratch_size; + * std::uint64_t update_size; + * }; + * } + * ``` + * \endcond + * + * @section WisStructureAllocationInfo_memb Members + *
+ * \cond WIS_GEN_DESC + * - `structure_size` The size of the acceleration structure in bytes. + * - `scratch_size` The size of the scratch buffer needed to build the acceleration structure in bytes. + * - `update_size` The size of the scratch buffer needed to update the acceleration structure in bytes. + * \endcond + * + * @section WisStructureAllocationInfo_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section WisStructureAllocationInfo_see_also See Also + *
+ * \cond WIS_GEN_REFS + * @see Functions: + * wisRaytracingExtensionGetBottomLevelStructureInfo + * \endcond + */ diff --git a/docs/wisdom/handle/pipeline_handle.h b/docs/wisdom/handle/pipeline_handle.h index 50d0b4881..d94883998 100644 --- a/docs/wisdom/handle/pipeline_handle.h +++ b/docs/wisdom/handle/pipeline_handle.h @@ -11,12 +11,12 @@ * ```c * // Provided by Wisdom 0.7.0. * WIS_DEFINE_HANDLE(WisVKPipeline,3); - * WIS_DEFINE_HANDLE_VIEW(WisVKPipeline,2); + * WIS_DEFINE_HANDLE_VIEW(WisVKPipeline,1); * ``` * DX12 Version: * ```c * // Provided by Wisdom 0.7.0. - * WIS_DEFINE_HANDLE(WisDX12Pipeline,1); + * WIS_DEFINE_HANDLE(WisDX12Pipeline,2); * WIS_DEFINE_HANDLE_VIEW(WisDX12Pipeline,1); * ``` * \endcond diff --git a/generator/generator.cpp b/generator/generator.cpp index 09d726e9a..885075a38 100644 --- a/generator/generator.cpp +++ b/generator/generator.cpp @@ -1185,6 +1185,7 @@ namespace wis{{ namespace detail {{ #include "c_api.h" #include +#include namespace wis{{ namespace detail {{ )", diff --git a/src/extensions/raytracing/raytracing/dx12/dx12_raytracing.cpp b/src/extensions/raytracing/raytracing/dx12/dx12_raytracing.cpp index f849d9d26..279e63787 100644 --- a/src/extensions/raytracing/raytracing/dx12/dx12_raytracing.cpp +++ b/src/extensions/raytracing/raytracing/dx12/dx12_raytracing.cpp @@ -2,7 +2,9 @@ #define WIS_DX12_RAYTRACING_CPP #include +#include #include +#include #include namespace wis::detail { @@ -21,6 +23,44 @@ inline WisResult DX12RaytracingExtensionInit( impl.device->AddRef(); // AddRef factory to ensure it lives as long as the extension return wis::detail::dx_success; } + +[[nodiscard]] inline constexpr D3D12_RAYTRACING_GEOMETRY_DESC DX12CreateGeometryDesc( + const WisAcceleratedGeometryDesc& desc +) noexcept +{ + D3D12_RAYTRACING_GEOMETRY_DESC geometry{ + .Type = wis::detail::DX12Convert(desc.type), + .Flags = wis::detail::DX12Convert(desc.flags), + }; + switch (desc.type) { + case WisGeometryTypeTriangles: + geometry.Triangles = { + .Transform3x4 = desc.transform_matrix_address, + .IndexFormat = wis::detail::DX12Convert(desc.index_format), + .VertexFormat = wis::detail::DX12Convert(desc.vertex_format), + .IndexCount = desc.triangle_or_aabb_count * 3, + .VertexCount = desc.vertex_count, + .IndexBuffer = desc.index_buffer_address, + .VertexBuffer = { + .StartAddress = desc.vertex_or_aabb_buffer_address, + .StrideInBytes = desc.vertex_or_aabb_stride + } + }; + break; + case WisGeometryTypeAABBs: + geometry.AABBs = { + .AABBCount = desc.triangle_or_aabb_count, + .AABBs = { + .StartAddress = desc.vertex_or_aabb_buffer_address, + .StrideInBytes = desc.vertex_or_aabb_stride + } + }; + break; + default: + break; + } + return geometry; +} } // namespace wis::detail //---------------------------------------------------------------------------------------------------------------------- @@ -97,4 +137,66 @@ WIS_EXTERN_C WISDOM_RAYTRACING_API uint64_t wisDX12AccelerationStructureGetGPUAd return wis::from_handle_ref(self).gpu_address; } +//---------------------------------------------------------------------------------------------------------------------- +WIS_EXTERN_C WISDOM_RAYTRACING_API WisResult wisDX12RaytracingExtensionGetBottomLevelStructureInfo( + WisDX12RaytracingExtension* self, + const WisBottomLevelStructureBuildDesc* build_desc, + WisStructureAllocationInfo* info +) +{ + auto& impl = wis::from_handle_ref(self); + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS inputs{ + .Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL, + .Flags = wis::detail::DX12Convert(build_desc->flags), + .NumDescs = build_desc->geometry_count, + .DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY, + }; + + // Allocate temporary array for geometry descriptions if needed + static constexpr size_t max_preallocated_descs = 32; + D3D12_RAYTRACING_GEOMETRY_DESC preallocted_descs[max_preallocated_descs]; + std::unique_ptr dynamic_descs; + wis::span geometry_descs; + if (build_desc->geometry_count > max_preallocated_descs) { + dynamic_descs = wis::make_unique(build_desc->geometry_count); + if (!dynamic_descs) { + return wis::detail::make_result( + E_OUTOFMEMORY + ); + } + geometry_descs = {dynamic_descs.get(), build_desc->geometry_count}; + } else { + geometry_descs = {preallocted_descs, build_desc->geometry_count}; + } + + // Convert geometry descriptions + if (build_desc->geometries) { + for (uint32_t i = 0; i < build_desc->geometry_count; ++i) { + geometry_descs[i] = wis::detail::DX12CreateGeometryDesc(build_desc->geometries[i]); + } + } else if (build_desc->indirect_geometries) { + for (uint32_t i = 0; i < build_desc->geometry_count; ++i) { + geometry_descs[i] = wis::detail::DX12CreateGeometryDesc(*build_desc->indirect_geometries[i]); + } + } + + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO prebuild_info = {}; + impl.device->GetRaytracingAccelerationStructurePrebuildInfo(&inputs, &prebuild_info); + *info = { + wis::aligned_size( + uint64_t(prebuild_info.ScratchDataSizeInBytes), + uint64_t(D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BYTE_ALIGNMENT) + ), + wis::aligned_size( + uint64_t(prebuild_info.ResultDataMaxSizeInBytes), + uint64_t(D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BYTE_ALIGNMENT) + ), + wis::aligned_size( + uint64_t(prebuild_info.UpdateScratchDataSizeInBytes), + uint64_t(D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BYTE_ALIGNMENT) + ) + }; + return wis::detail::dx_success; +} + #endif diff --git a/src/extensions/raytracing/raytracing/dx12/dx12_types.hpp b/src/extensions/raytracing/raytracing/dx12/dx12_types.hpp index 7b9cf15a5..a4810dc4e 100644 --- a/src/extensions/raytracing/raytracing/dx12/dx12_types.hpp +++ b/src/extensions/raytracing/raytracing/dx12/dx12_types.hpp @@ -11,7 +11,7 @@ namespace detail {} // namespace detail namespace impl { struct DX12RaytracingExtensionImpl { DX12DeviceExtensionHeader header; - ID3D12Device* device; + ID3D12Device10* device; }; struct DX12AccelerationStructureImpl { diff --git a/src/extensions/raytracing/raytracing/generated/c_api.h b/src/extensions/raytracing/raytracing/generated/c_api.h index 9564ff14a..33ad8b273 100644 --- a/src/extensions/raytracing/raytracing/generated/c_api.h +++ b/src/extensions/raytracing/raytracing/generated/c_api.h @@ -27,6 +27,126 @@ typedef enum WisAccelerationStructureLevel { WisAccelerationStructureLevelBottomLevel = 1, } WisAccelerationStructureLevel; +/** + * @brief Provided by Wisdom 0.7.1. Enumeration for the type of geometry in a bottom-level acceleration structure. + * + * */ +typedef enum WisGeometryType { + WisGeometryTypeTriangles = 0, ///< Triangles geometry type. Used for triangle meshes. + WisGeometryTypeAABBs = 1, ///< Axis Aligned Bounding Boxes geometry type. Used for bounding volume hierarchies. +} WisGeometryType; + +/** + * @brief Provided by Wisdom 0.7.1. Bitmask for geometry flags in raytracing. + * + * */ +typedef enum WisGeometryFlags { + WisGeometryFlagsNone = 0, ///< No flags set. Geometry is regular. + WisGeometryFlagsOpaque = (1u << 0), ///< Geometry is opaque. Used for opaque geometry. + WisGeometryFlagsNoDuplicateAnyHitInvocation = (1u << 1), ///< Geometry has no duplicate any hit invocation. +} WisGeometryFlags; + +/** + * @brief Provided by Wisdom 0.7.1. Acceleration structure flags for additional acceleration structure features + * + * */ +typedef enum WisAccelerationStructureFlags { + WisAccelerationStructureFlagsNone = 0, ///< No flags set. Acceleration structure is regular. + WisAccelerationStructureFlagsAllowUpdate = (1u << 0), ///< Acceleration structure is allowed to be updated. + WisAccelerationStructureFlagsAllowCompaction = (1u << 1), ///< Acceleration structure is allowed to be compacted. + /** + * @brief Acceleration structure is preferred to be fast traced. + * */ + WisAccelerationStructureFlagsPreferFastTrace = (1u << 2), + WisAccelerationStructureFlagsPreferFastBuild = (1u << 3), ///< Acceleration structure is preferred to be fast built. + WisAccelerationStructureFlagsMinimizeMemory = (1u << 4), ///< Acceleration structure is minimized for memory usage. + /** + * @brief Acceleration structure build is performed as an update. Only used for update builds. + * */ + WisAccelerationStructureFlagsPerformUpdate = (1u << 5), +} WisAccelerationStructureFlags; + +//============================================================== +// Structs +//============================================================== + +/** + * @brief Provided by Wisdom 0.7.1. Structure describing the single geometry instance. + * + * */ +typedef struct WisAcceleratedGeometryDesc { + WisGeometryType type; ///< The type of geometry (triangles or AABBs). + WisGeometryFlags flags; ///< The geometry flags for this geometry instance. + /** + * @brief The GPU address of the vertex buffer for this geometry instance. + * */ + uint64_t vertex_or_aabb_buffer_address; + /** + * @brief The GPU address of the index buffer for this geometry instance. Only used for triangles geometry type. + * */ + uint64_t index_buffer_address; + /** + * @brief The GPU address of the transform matrix (float [3][4]) for this geometry instance. Only used for triangles + * geometry type. + * */ + uint64_t transform_matrix_address; + uint32_t vertex_or_aabb_stride; ///< The stride in bytes between vertices or AABBs in the buffer. + /** + * @brief The number of vertices in the vertex buffer. Only used for triangles geometry type. + * */ + uint32_t vertex_count; + uint32_t triangle_or_aabb_count; ///< For triangles it is equal to (index_count/3) and count for AABBs. + /** + * @brief The format of the vertex data in the vertex buffer. Only used for triangles geometry type. + * */ + WisDataFormat vertex_format; + /** + * @brief The format of the index data in the index buffer. Only used for triangles geometry type. + * */ + WisIndexType index_format; +} WisAcceleratedGeometryDesc; + +/** + * @brief Provided by Wisdom 0.7.1. Structure describing the allocation information for an acceleration structure. + * + * */ +typedef struct WisStructureAllocationInfo { + uint64_t structure_size; ///< The size of the acceleration structure in bytes. + uint64_t scratch_size; ///< The size of the scratch buffer needed to build the acceleration structure in bytes. + uint64_t update_size; ///< The size of the scratch buffer needed to update the acceleration structure in bytes. +} WisStructureAllocationInfo; + +/** + * @brief Provided by Wisdom 0.7.1. Structure describing the build description for a bottom-level acceleration + * structure. + * + * */ +typedef struct WisBottomLevelStructureBuildDesc { + WisAccelerationStructureFlags flags; ///< The build flags for the acceleration structure build. + /** + * @brief The number of geometry instances in the bottom-level acceleration structure. + * */ + uint32_t geometry_count; + /** + * @brief The array of geometry descriptions for the bottom-level acceleration structure. Has higher precedence over + * `WisBottomLevelStructureBuildDesc::indirect_geometries`. + * */ + const WisAcceleratedGeometryDesc* geometries; + /** + * @brief The array of geometry descriptions for indirect build of the bottom-level acceleration structure. + * */ + const WisAcceleratedGeometryDesc** indirect_geometries; +} WisBottomLevelStructureBuildDesc; + +//============================================================== +// Constants +//============================================================== + +/// @brief Provided by Wisdom 0.7.1. Alignment in bytes for acceleration structure buffers. Acceleration structures must +/// be allocated with this alignment and offset of the acceleration structure within the buffer must also be aligned to +/// this value. +#define WIS_ACCELERATION_STRUCTURE_ALIGNMENT ((uint32_t)256) + #ifdef WISDOM_DX12 /** * @brief Provided by Wisdom 0.7.1. Handle for an acceleration structure used in raytracing. @@ -82,6 +202,21 @@ WISDOM_RAYTRACING_API void wisDX12InitRaytracingExtension(WisDX12RaytracingExten * */ WISDOM_RAYTRACING_API bool wisDX12RaytracingExtensionSupported(WisDX12RaytracingExtension* self); +/** + * @brief Provided by Wisdom 0.7.1. Retrieves the allocation information for a bottom-level acceleration structure based + * on the provided build description. + * @param self is a pointer to the valid WisRaytracingExtension instance. + * @param build_desc The build description for the bottom-level acceleration structure. + * @param info The allocation information for the bottom-level acceleration structure. + * @return Result denoting the outcome of operation. + * + * */ +WISDOM_RAYTRACING_API WisResult wisDX12RaytracingExtensionGetBottomLevelStructureInfo( + WisDX12RaytracingExtension* self, + const WisBottomLevelStructureBuildDesc* build_desc, + WisStructureAllocationInfo* info +); + /** * @brief Provided by Wisdom 0.7.1. Creates an acceleration structure based on the provided description. * @param self is a pointer to the valid WisRaytracingExtension instance. @@ -163,6 +298,21 @@ WISDOM_RAYTRACING_API void wisVKInitRaytracingExtension(WisVKRaytracingExtension * */ WISDOM_RAYTRACING_API bool wisVKRaytracingExtensionSupported(WisVKRaytracingExtension* self); +/** + * @brief Provided by Wisdom 0.7.1. Retrieves the allocation information for a bottom-level acceleration structure based + * on the provided build description. + * @param self is a pointer to the valid WisRaytracingExtension instance. + * @param build_desc The build description for the bottom-level acceleration structure. + * @param info The allocation information for the bottom-level acceleration structure. + * @return Result denoting the outcome of operation. + * + * */ +WISDOM_RAYTRACING_API WisResult wisVKRaytracingExtensionGetBottomLevelStructureInfo( + WisVKRaytracingExtension* self, + const WisBottomLevelStructureBuildDesc* build_desc, + WisStructureAllocationInfo* info +); + /** * @brief Provided by Wisdom 0.7.1. Creates an acceleration structure based on the provided description. * @param self is a pointer to the valid WisRaytracingExtension instance. diff --git a/src/extensions/raytracing/raytracing/generated/cpp_api.hpp b/src/extensions/raytracing/raytracing/generated/cpp_api.hpp index 8feb90b71..b34f9d522 100644 --- a/src/extensions/raytracing/raytracing/generated/cpp_api.hpp +++ b/src/extensions/raytracing/raytracing/generated/cpp_api.hpp @@ -24,6 +24,122 @@ enum class AccelerationStructureLevel { BottomLevel = 1, ///< Bottom-level acceleration structure, which contains geometry data such as triangles or AABBs. }; +/** + * @brief Provided by Wisdom 0.7.1. Enumeration for the type of geometry in a bottom-level acceleration structure. + * + * */ +enum class GeometryType { + Triangles = 0, ///< Triangles geometry type. Used for triangle meshes. + AABBs = 1, ///< Axis Aligned Bounding Boxes geometry type. Used for bounding volume hierarchies. +}; + +/** + * @brief Provided by Wisdom 0.7.1. Bitmask for geometry flags in raytracing. + * + * */ +enum class GeometryFlags : uint32_t { + None = 0, ///< No flags set. Geometry is regular. + Opaque = (1u << 0), ///< Geometry is opaque. Used for opaque geometry. + NoDuplicateAnyHitInvocation = (1u << 1), ///< Geometry has no duplicate any hit invocation. +}; +WISDOM_DEFINE_ENUM_OPERATORS(GeometryFlags) + +/** + * @brief Provided by Wisdom 0.7.1. Acceleration structure flags for additional acceleration structure features + * + * */ +enum class AccelerationStructureFlags : uint32_t { + None = 0, ///< No flags set. Acceleration structure is regular. + AllowUpdate = (1u << 0), ///< Acceleration structure is allowed to be updated. + AllowCompaction = (1u << 1), ///< Acceleration structure is allowed to be compacted. + PreferFastTrace = (1u << 2), ///< Acceleration structure is preferred to be fast traced. + PreferFastBuild = (1u << 3), ///< Acceleration structure is preferred to be fast built. + MinimizeMemory = (1u << 4), ///< Acceleration structure is minimized for memory usage. + PerformUpdate = (1u << 5), ///< Acceleration structure build is performed as an update. Only used for update builds. +}; +WISDOM_DEFINE_ENUM_OPERATORS(AccelerationStructureFlags) + +//============================================================== +// Structs +//============================================================== + +/** + * @brief Provided by Wisdom 0.7.1. Structure describing the single geometry instance. + * + * */ +struct AcceleratedGeometryDesc { + wis::GeometryType type; ///< The type of geometry (triangles or AABBs). + wis::GeometryFlags flags; ///< The geometry flags for this geometry instance. + /** + * @brief The GPU address of the vertex buffer for this geometry instance. + * */ + std::uint64_t vertex_or_aabb_buffer_address; + /** + * @brief The GPU address of the index buffer for this geometry instance. Only used for triangles geometry type. + * */ + std::uint64_t index_buffer_address; + /** + * @brief The GPU address of the transform matrix (float [3][4]) for this geometry instance. Only used for triangles + * geometry type. + * */ + std::uint64_t transform_matrix_address; + std::uint32_t vertex_or_aabb_stride; ///< The stride in bytes between vertices or AABBs in the buffer. + /** + * @brief The number of vertices in the vertex buffer. Only used for triangles geometry type. + * */ + std::uint32_t vertex_count; + std::uint32_t triangle_or_aabb_count; ///< For triangles it is equal to (index_count/3) and count for AABBs. + /** + * @brief The format of the vertex data in the vertex buffer. Only used for triangles geometry type. + * */ + wis::DataFormat vertex_format; + /** + * @brief The format of the index data in the index buffer. Only used for triangles geometry type. + * */ + wis::IndexType index_format; +}; + +/** + * @brief Provided by Wisdom 0.7.1. Structure describing the allocation information for an acceleration structure. + * + * */ +struct StructureAllocationInfo { + std::uint64_t structure_size; ///< The size of the acceleration structure in bytes. + std::uint64_t scratch_size; ///< The size of the scratch buffer needed to build the acceleration structure in bytes. + std::uint64_t update_size; ///< The size of the scratch buffer needed to update the acceleration structure in bytes. +}; + +/** + * @brief Provided by Wisdom 0.7.1. Structure describing the build description for a bottom-level acceleration + * structure. + * + * */ +struct BottomLevelStructureBuildDesc { + wis::AccelerationStructureFlags flags; ///< The build flags for the acceleration structure build. + /** + * @brief The number of geometry instances in the bottom-level acceleration structure. + * */ + std::uint32_t geometry_count; + /** + * @brief The array of geometry descriptions for the bottom-level acceleration structure. Has higher precedence over + * `wis::BottomLevelStructureBuildDesc::indirect_geometries`. + * */ + const wis::AcceleratedGeometryDesc* geometries; + /** + * @brief The array of geometry descriptions for indirect build of the bottom-level acceleration structure. + * */ + const wis::AcceleratedGeometryDesc** indirect_geometries; +}; + +//============================================================== +// Constants +//============================================================== + +/// @brief Provided by Wisdom 0.7.1. Alignment in bytes for acceleration structure buffers. Acceleration structures must +/// be allocated with this alignment and offset of the acceleration structure within the buffer must also be aligned to +/// this value. +static constexpr std::uint32_t AccelerationStructureAlignment = 256; + } // namespace wis #ifdef WISDOM_DX12 @@ -98,6 +214,32 @@ class DX12RaytracingExtension : public wis::impl::Implements< * * */ WIS_NODISCARD inline bool Supported() noexcept { return (::wisDX12RaytracingExtensionSupported(&_impl_storage)); } + /** + * @brief Provided by Wisdom 0.7.1. Retrieves the allocation information for a bottom-level acceleration structure + * based on the provided build description. + * @param build_desc The build description for the bottom-level acceleration structure. + * @param out_result denoting the outcome of operation. + * @return info The allocation information for the bottom-level acceleration structure. + * + * */ + WIS_NODISCARD inline wis::StructureAllocationInfo GetBottomLevelStructureInfo( + const wis::BottomLevelStructureBuildDesc& build_desc, + wis::Result& out_result + ) noexcept + { + wis::StructureAllocationInfo info; + const WisResult wis_result = ::wisDX12RaytracingExtensionGetBottomLevelStructureInfo( + &_impl_storage, + reinterpret_cast(&build_desc), + reinterpret_cast(&info) + ); + out_result = wis::Result{ + static_cast(wis_result.status), + wis_result.platform_code, + wis_result.error + }; + return info; + } /** * @brief Provided by Wisdom 0.7.1. Creates an acceleration structure based on the provided description. * @param buffer The buffer to write the acceleration structure data to. @@ -202,6 +344,32 @@ class VKRaytracingExtension * * */ WIS_NODISCARD inline bool Supported() noexcept { return (::wisVKRaytracingExtensionSupported(&_impl_storage)); } + /** + * @brief Provided by Wisdom 0.7.1. Retrieves the allocation information for a bottom-level acceleration structure + * based on the provided build description. + * @param build_desc The build description for the bottom-level acceleration structure. + * @param out_result denoting the outcome of operation. + * @return info The allocation information for the bottom-level acceleration structure. + * + * */ + WIS_NODISCARD inline wis::StructureAllocationInfo GetBottomLevelStructureInfo( + const wis::BottomLevelStructureBuildDesc& build_desc, + wis::Result& out_result + ) noexcept + { + wis::StructureAllocationInfo info; + const WisResult wis_result = ::wisVKRaytracingExtensionGetBottomLevelStructureInfo( + &_impl_storage, + reinterpret_cast(&build_desc), + reinterpret_cast(&info) + ); + out_result = wis::Result{ + static_cast(wis_result.status), + wis_result.platform_code, + wis_result.error + }; + return info; + } /** * @brief Provided by Wisdom 0.7.1. Creates an acceleration structure based on the provided description. * @param buffer The buffer to write the acceleration structure data to. diff --git a/src/extensions/raytracing/raytracing/generated/dx12_convert.hpp b/src/extensions/raytracing/raytracing/generated/dx12_convert.hpp index a3acae89e..b74546ff3 100644 --- a/src/extensions/raytracing/raytracing/generated/dx12_convert.hpp +++ b/src/extensions/raytracing/raytracing/generated/dx12_convert.hpp @@ -10,6 +10,56 @@ #include "c_api.h" namespace wis { -namespace detail {} +namespace detail { + +constexpr inline D3D12_RAYTRACING_GEOMETRY_TYPE DX12Convert(WisGeometryType value) noexcept +{ + switch (value) { + case WisGeometryTypeTriangles: + return D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES; + case WisGeometryTypeAABBs: + return D3D12_RAYTRACING_GEOMETRY_TYPE_PROCEDURAL_PRIMITIVE_AABBS; + default: + return static_cast(0); + } +} + +constexpr inline D3D12_RAYTRACING_GEOMETRY_FLAGS DX12Convert(WisGeometryFlags value) noexcept +{ + D3D12_RAYTRACING_GEOMETRY_FLAGS result = static_cast(0); + if (value & WisGeometryFlagsOpaque) { + result |= D3D12_RAYTRACING_GEOMETRY_FLAG_OPAQUE; + } + if (value & WisGeometryFlagsNoDuplicateAnyHitInvocation) { + result |= D3D12_RAYTRACING_GEOMETRY_FLAG_NO_DUPLICATE_ANYHIT_INVOCATION; + } + return result; +} + +constexpr inline D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS DX12Convert( + WisAccelerationStructureFlags value +) noexcept +{ + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS + result = static_cast(0); + if (value & WisAccelerationStructureFlagsAllowUpdate) { + result |= D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_ALLOW_UPDATE; + } + if (value & WisAccelerationStructureFlagsAllowCompaction) { + result |= D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_ALLOW_COMPACTION; + } + if (value & WisAccelerationStructureFlagsPreferFastTrace) { + result |= D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_TRACE; + } + if (value & WisAccelerationStructureFlagsPreferFastBuild) { + result |= D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_BUILD; + } + if (value & WisAccelerationStructureFlagsMinimizeMemory) { + result |= D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_MINIMIZE_MEMORY; + } + return result; +} + +} // namespace detail } // namespace wis #endif // WISDOM_RAYTRACING_CPP_DX12_CONVERT_HPP diff --git a/src/extensions/raytracing/raytracing/generated/vk_convert.hpp b/src/extensions/raytracing/raytracing/generated/vk_convert.hpp index 2ebeec15e..8badf736c 100644 --- a/src/extensions/raytracing/raytracing/generated/vk_convert.hpp +++ b/src/extensions/raytracing/raytracing/generated/vk_convert.hpp @@ -5,6 +5,7 @@ # error "This is a C++ only header" #endif // __cplusplus +#include #include #include "c_api.h" @@ -22,6 +23,51 @@ constexpr inline VkAccelerationStructureTypeKHR VKConvert(WisAccelerationStructu } } +constexpr inline VkGeometryTypeKHR VKConvert(WisGeometryType value) noexcept +{ + switch (value) { + case WisGeometryTypeTriangles: + return VK_GEOMETRY_TYPE_TRIANGLES_KHR; + case WisGeometryTypeAABBs: + return VK_GEOMETRY_TYPE_AABBS_KHR; + default: + return static_cast(0); + } +} + +constexpr inline VkGeometryFlagsKHR VKConvert(WisGeometryFlags value) noexcept +{ + VkGeometryFlagsKHR result = static_cast(0); + if (value & WisGeometryFlagsOpaque) { + result |= VK_GEOMETRY_OPAQUE_BIT_KHR; + } + if (value & WisGeometryFlagsNoDuplicateAnyHitInvocation) { + result |= VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR; + } + return result; +} + +constexpr inline VkBuildAccelerationStructureFlagsKHR VKConvert(WisAccelerationStructureFlags value) noexcept +{ + VkBuildAccelerationStructureFlagsKHR result = static_cast(0); + if (value & WisAccelerationStructureFlagsAllowUpdate) { + result |= VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_KHR; + } + if (value & WisAccelerationStructureFlagsAllowCompaction) { + result |= VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_KHR; + } + if (value & WisAccelerationStructureFlagsPreferFastTrace) { + result |= VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; + } + if (value & WisAccelerationStructureFlagsPreferFastBuild) { + result |= VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_KHR; + } + if (value & WisAccelerationStructureFlagsMinimizeMemory) { + result |= VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_KHR; + } + return result; +} + } // namespace detail } // namespace wis #endif // WISDOM_RAYTRACING_CPP_VK_CONVERT_HPP diff --git a/src/extensions/raytracing/raytracing/vulkan/vk_raytracing.cpp b/src/extensions/raytracing/raytracing/vulkan/vk_raytracing.cpp index 97ca62467..c40bedca9 100644 --- a/src/extensions/raytracing/raytracing/vulkan/vk_raytracing.cpp +++ b/src/extensions/raytracing/raytracing/vulkan/vk_raytracing.cpp @@ -1,6 +1,7 @@ #ifndef WIS_VK_RAYTRACING_CPP #define WIS_VK_RAYTRACING_CPP +#include #include #include #include @@ -86,6 +87,41 @@ inline WisResult VKRaytracingExtensionInit( return wis::detail::vk_success; } + +[[nodiscard]] inline constexpr VkAccelerationStructureGeometryKHR VKCreateGeometryDesc( + const WisAcceleratedGeometryDesc& desc +) noexcept +{ + VkAccelerationStructureGeometryKHR out{ + .sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR, + .geometryType = VKConvert(desc.type), + .flags = VKConvert(desc.flags) + }; + switch (desc.type) { + case WisGeometryTypeTriangles: + out.geometry.triangles = { + .sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR, + .vertexFormat = VKConvert(desc.vertex_format), + .vertexData = {.deviceAddress = desc.vertex_or_aabb_buffer_address}, + .vertexStride = desc.vertex_or_aabb_stride, + .maxVertex = desc.vertex_count, + .indexType = VKConvert(desc.index_format), + .indexData = {.deviceAddress = desc.index_buffer_address}, + .transformData = {.deviceAddress = desc.transform_matrix_address} + }; + break; + case WisGeometryTypeAABBs: + out.geometry.aabbs = { + .sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_AABBS_DATA_KHR, + .data = {.deviceAddress = desc.vertex_or_aabb_buffer_address}, + .stride = desc.vertex_or_aabb_stride + }; + break; + default: + break; + } + return out; +} } // namespace wis::detail //---------------------------------------------------------------------------------------------------------------------- @@ -185,4 +221,83 @@ WIS_EXTERN_C WISDOM_RAYTRACING_API uint64_t wisVKAccelerationStructureGetGPUAddr return wis::from_handle_ref(self).device_address; } +//---------------------------------------------------------------------------------------------------------------------- +WIS_EXTERN_C WISDOM_RAYTRACING_API WisResult wisVKRaytracingExtensionGetBottomLevelStructureInfo( + WisVKRaytracingExtension* self, + const WisBottomLevelStructureBuildDesc* build_desc, + WisStructureAllocationInfo* info +) +{ + static constexpr size_t max_preallocated_descs = 32; + VkAccelerationStructureGeometryKHR geometry_descs[max_preallocated_descs]; + uint32_t primitive_counts[max_preallocated_descs]; + std::unique_ptr dynamic_descs; + wis::span geometry_desc_span; + wis::span primitive_counts_span; + if (build_desc->geometry_count > max_preallocated_descs) { + dynamic_descs = std::unique_ptr{ + static_cast(::operator new( + sizeof(VkAccelerationStructureGeometryKHR) * build_desc->geometry_count + + sizeof(uint32_t) * build_desc->geometry_count, + std::nothrow + )) + }; + if (!dynamic_descs) { + return wis::detail::make_result( + VK_ERROR_OUT_OF_HOST_MEMORY + ); + } + geometry_desc_span = {dynamic_descs.get(), build_desc->geometry_count}; + primitive_counts_span = { + reinterpret_cast(dynamic_descs.get() + build_desc->geometry_count), + build_desc->geometry_count + }; + } else { + geometry_desc_span = {geometry_descs, build_desc->geometry_count}; + primitive_counts_span = {primitive_counts, build_desc->geometry_count}; + } + + // Fill geometry descriptions + if (build_desc->geometries) { + for (uint32_t i = 0; i < build_desc->geometry_count; ++i) { + geometry_desc_span[i] = wis::detail::VKCreateGeometryDesc(build_desc->geometries[i]); + primitive_counts_span[i] = build_desc->geometries[i].triangle_or_aabb_count; + } + } else if (build_desc->indirect_geometries) { + for (uint32_t i = 0; i < build_desc->geometry_count; ++i) { + geometry_desc_span[i] = wis::detail::VKCreateGeometryDesc(*build_desc->indirect_geometries[i]); + primitive_counts_span[i] = build_desc->indirect_geometries[i]->triangle_or_aabb_count; + } + } + + VkAccelerationStructureBuildGeometryInfoKHR build_info{ + .sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR, + .type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR, + .flags = wis::detail::VKConvert(build_desc->flags), + .mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR, + .geometryCount = build_desc->geometry_count, + .pGeometries = geometry_desc_span.data(), + }; + VkAccelerationStructureBuildSizesInfoKHR build_sizes_info{ + .sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR, + }; + + auto& impl = wis::from_handle_ref(self); + impl.rt_table->vkGetAccelerationStructureBuildSizesKHR( + impl.device, + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, + &build_info, + primitive_counts_span.data(), + &build_sizes_info + ); + + constexpr static size_t alignment = 256; // 256 is a common alignment requirement for acceleration structures + *info = { + wis::aligned_size(build_sizes_info.buildScratchSize, alignment), + wis::aligned_size(build_sizes_info.accelerationStructureSize, alignment), + wis::aligned_size(build_sizes_info.updateScratchSize, alignment) + }; + return wis::detail::vk_success; +} + #endif diff --git a/src/extensions/raytracing/wisdom/wisdom_raytracing.h b/src/extensions/raytracing/wisdom/wisdom_raytracing.h index 0d0806b10..1c531199f 100644 --- a/src/extensions/raytracing/wisdom/wisdom_raytracing.h +++ b/src/extensions/raytracing/wisdom/wisdom_raytracing.h @@ -39,6 +39,7 @@ typedef struct WisDX12AccelerationStructureDesc WisAccelerationStructureDesc; # define wisDestroyRaytracingExtension wisDX12DestroyRaytracingExtension # define wisInitRaytracingExtension wisDX12InitRaytracingExtension # define wisRaytracingExtensionSupported wisDX12RaytracingExtensionSupported +# define wisRaytracingExtensionGetBottomLevelStructureInfo wisDX12RaytracingExtensionGetBottomLevelStructureInfo # define wisRaytracingExtensionCreateAccelerationStructure wisDX12RaytracingExtensionCreateAccelerationStructure # define wisAccelerationStructureGetGPUAddress wisDX12AccelerationStructureGetGPUAddress @@ -65,6 +66,7 @@ typedef struct WisVKAccelerationStructureDesc WisAccelerationStructureDesc; # define wisDestroyRaytracingExtension wisVKDestroyRaytracingExtension # define wisInitRaytracingExtension wisVKInitRaytracingExtension # define wisRaytracingExtensionSupported wisVKRaytracingExtensionSupported +# define wisRaytracingExtensionGetBottomLevelStructureInfo wisVKRaytracingExtensionGetBottomLevelStructureInfo # define wisRaytracingExtensionCreateAccelerationStructure wisVKRaytracingExtensionCreateAccelerationStructure # define wisAccelerationStructureGetGPUAddress wisVKAccelerationStructureGetGPUAddress diff --git a/src/include/wisdom/generated/vk_convert.hpp b/src/include/wisdom/generated/vk_convert.hpp index aff8b0dc9..e0c2199dd 100644 --- a/src/include/wisdom/generated/vk_convert.hpp +++ b/src/include/wisdom/generated/vk_convert.hpp @@ -5,6 +5,7 @@ # error "This is a C++ only header" #endif // __cplusplus +#include #include #include "c_api.h" diff --git a/tests/basic/rt_primitives.cpp b/tests/basic/rt_primitives.cpp index 32730643b..f585b2593 100644 --- a/tests/basic/rt_primitives.cpp +++ b/tests/basic/rt_primitives.cpp @@ -80,9 +80,54 @@ TEST_CASE("check_rt_acceleration_structure") wis::ResourceAllocator allocator = device.GetResourceAllocator(result); REQUIRE(result.status == wis::Status::Ok); + wis::Buffer vertex_buffer = allocator.CreateBuffer( + { + .size_bytes = 3 * sizeof(float) * 3, + .usage_flags = wis::BufferUsageFlags::VertexBuffer, + .memory_type = wis::MemoryType::Upload, + .memory_flags = wis::MemoryFlags::Mapped, + }, + result + ); + REQUIRE(result.status == wis::Status::Ok); + + float* vertex_data = static_cast(vertex_buffer.Map()); + REQUIRE(vertex_data != nullptr); + + // fill in standard triangle vertices + vertex_data[0] = 0.0f; + vertex_data[1] = 0.0f; + vertex_data[2] = 0.0f; + + vertex_data[3] = 1.0f; + vertex_data[4] = 0.0f; + vertex_data[5] = 0.0f; + + vertex_data[6] = 0.0f; + vertex_data[7] = 1.0f; + vertex_data[8] = 0.0f; + + wis::AcceleratedGeometryDesc geometry_desc{ + .type = wis::GeometryType::Triangles, + .flags = wis::GeometryFlags::Opaque, + .vertex_or_aabb_buffer_address = vertex_buffer.GetGPUAddress(), + .vertex_or_aabb_stride = 3 * sizeof(float), + .vertex_count = 3, + .triangle_or_aabb_count = 1, + .vertex_format = wis::DataFormat::RGB32Float, + }; + wis::BottomLevelStructureBuildDesc blas_build_desc{ + .flags = wis::AccelerationStructureFlags::None, + .geometry_count = 1, + .geometries = &geometry_desc, + }; + wis::StructureAllocationInfo alloc_info = rt_extension.GetBottomLevelStructureInfo(blas_build_desc, result); + REQUIRE(result.status == wis::Status::Ok); + REQUIRE(alloc_info.structure_size > 0); + wis::Buffer rtas_buffer = allocator.CreateBuffer( { - .size_bytes = 1024, + .size_bytes = alloc_info.structure_size, .usage_flags = wis::BufferUsageFlags::AccelerationStructureBuffer, }, result @@ -91,7 +136,7 @@ TEST_CASE("check_rt_acceleration_structure") wis::Buffer scratch_buffer = allocator.CreateBuffer( { - .size_bytes = 1024, + .size_bytes = alloc_info.scratch_size, .usage_flags = wis::BufferUsageFlags::StorageBuffer, }, result diff --git a/xml/raytracing.xml b/xml/raytracing.xml index 22e976afa..07c581a78 100644 --- a/xml/raytracing.xml +++ b/xml/raytracing.xml @@ -13,11 +13,93 @@
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -36,6 +118,11 @@ + + + + + @@ -46,6 +133,9 @@ - + + + + diff --git a/xml/wis.xml b/xml/wis.xml index 2216ba0e6..3d64233aa 100644 --- a/xml/wis.xml +++ b/xml/wis.xml @@ -33,7 +33,7 @@ - + From 14939381303b5f0f957f767ee201d78113692fea Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Mon, 27 Apr 2026 00:07:04 +0200 Subject: [PATCH 13/49] Refactor AS ownership: caller manages buffer/device lifetime Update DX12 and Vulkan acceleration structure ownership model: - Acceleration structures no longer hold references to buffers/devices. - Remove resource/buffer control block fields and ref counting. - Update docs to clarify caller's responsibility for resource lifetime. - Adjust XML handle sizes for Vulkan buffer. - Simplify destruction logic and resource management. --- .../destroy_acceleration_structure_function.h | 6 ++-- ...n_create_acceleration_structure_function.h | 8 +++-- .../handle/acceleration_structure_handle.h | 1 + .../raytracing/dx12/dx12_raytracing.cpp | 6 ---- .../raytracing/raytracing/dx12/dx12_types.hpp | 1 - .../raytracing/vulkan/vk_raytracing.cpp | 20 +++-------- .../raytracing/raytracing/vulkan/vk_types.hpp | 3 +- .../wisdom/vulkan/detail/vk_detail.hpp | 34 ------------------- src/include/wisdom/vulkan/vk_impl.cpp | 6 ---- .../wisdom/vulkan/vk_resource_allocator.cpp | 25 -------------- src/include/wisdom/vulkan/vk_types.hpp | 2 -- xml/wis.xml | 2 +- 12 files changed, 17 insertions(+), 97 deletions(-) diff --git a/docs/raytracing/func/destroy_acceleration_structure_function.h b/docs/raytracing/func/destroy_acceleration_structure_function.h index d9407b402..ffc7ded6f 100644 --- a/docs/raytracing/func/destroy_acceleration_structure_function.h +++ b/docs/raytracing/func/destroy_acceleration_structure_function.h @@ -34,8 +34,10 @@ * @section wisDestroyAccelerationStructure_descr Description *
* - * Destroys the given acceleration structure, releasing any associated resources. After this call, the acceleration - * structure handle will no longer be valid and should not be used. + * @warning The handle does not reference the underlying buffer or device. + * The caller is responsible for ensuring that the buffer and device remain valid until the acceleration structure is + * destroyed. For Top Level Acceleration Structures, the caller @wis_must ensure that the acceleration structure is not + * in use by any command. * * \cond WIS_GEN_WIS_IDS * \endcond diff --git a/docs/raytracing/func/raytracing_extension_create_acceleration_structure_function.h b/docs/raytracing/func/raytracing_extension_create_acceleration_structure_function.h index 1dd9bce18..1ba2699a1 100644 --- a/docs/raytracing/func/raytracing_extension_create_acceleration_structure_function.h +++ b/docs/raytracing/func/raytracing_extension_create_acceleration_structure_function.h @@ -73,9 +73,11 @@ * @section wisRaytracingExtensionCreateAccelerationStructure_descr Description *
* - * The resulting acceleration structure stores reference to provided buffer, extending its lifetime to that of the - * acceleration structure. The buffer @wis_must be created with `WisBufferUsageFlagsAccelerationStructureBuffer` usage - * flag. + * The resulting acceleration structure does not reference the provided buffer. The buffer @wis_must be created with + * `WisBufferUsageFlagsAccelerationStructureBuffer` usage flag. + * + * @warning The resulting acceleration structure does not hold a reference to a device or buffer. The caller is + * responsible for ensuring that the buffer and device remain valid until the acceleration structure is destroyed. * * \cond WIS_GEN_WIS_IDS * \endcond diff --git a/docs/raytracing/handle/acceleration_structure_handle.h b/docs/raytracing/handle/acceleration_structure_handle.h index 61bbd76b1..8b62764d7 100644 --- a/docs/raytracing/handle/acceleration_structure_handle.h +++ b/docs/raytracing/handle/acceleration_structure_handle.h @@ -2,6 +2,7 @@ * @struct WisAccelerationStructure * @ingroup Handles Raytracing * + * The view type handle for an acceleration structure. * * @section WisAccelerationStructure_spec Specification *
diff --git a/src/extensions/raytracing/raytracing/dx12/dx12_raytracing.cpp b/src/extensions/raytracing/raytracing/dx12/dx12_raytracing.cpp index 279e63787..d22de1136 100644 --- a/src/extensions/raytracing/raytracing/dx12/dx12_raytracing.cpp +++ b/src/extensions/raytracing/raytracing/dx12/dx12_raytracing.cpp @@ -114,9 +114,7 @@ WIS_EXTERN_C WISDOM_RAYTRACING_API WisResult wisDX12RaytracingExtensionCreateAcc new (acceleration_structure) wis::impl::DX12AccelerationStructureImpl{ .gpu_address = address + desc->offset, - .resource = buffer_impl.resource, }; - buffer_impl.resource->AddRef(); return wis::detail::dx_success; } @@ -124,10 +122,6 @@ WIS_EXTERN_C WISDOM_RAYTRACING_API WisResult wisDX12RaytracingExtensionCreateAcc WIS_EXTERN_C WISDOM_RAYTRACING_API void wisDX12DestroyAccelerationStructure(WisDX12AccelerationStructure* self) { auto& impl = wis::from_handle_ref(self); - if (impl.resource) { - impl.resource->Release(); - impl.resource = nullptr; - } impl.gpu_address = 0; } diff --git a/src/extensions/raytracing/raytracing/dx12/dx12_types.hpp b/src/extensions/raytracing/raytracing/dx12/dx12_types.hpp index a4810dc4e..b0468d1d1 100644 --- a/src/extensions/raytracing/raytracing/dx12/dx12_types.hpp +++ b/src/extensions/raytracing/raytracing/dx12/dx12_types.hpp @@ -16,7 +16,6 @@ struct DX12RaytracingExtensionImpl { struct DX12AccelerationStructureImpl { D3D12_GPU_VIRTUAL_ADDRESS gpu_address; - ID3D12Resource* resource; }; } // namespace impl diff --git a/src/extensions/raytracing/raytracing/vulkan/vk_raytracing.cpp b/src/extensions/raytracing/raytracing/vulkan/vk_raytracing.cpp index c40bedca9..45032a93f 100644 --- a/src/extensions/raytracing/raytracing/vulkan/vk_raytracing.cpp +++ b/src/extensions/raytracing/raytracing/vulkan/vk_raytracing.cpp @@ -161,13 +161,6 @@ WIS_EXTERN_C WISDOM_RAYTRACING_API WisResult wisVKRaytracingExtensionCreateAccel auto& impl = wis::from_handle_ref(self); auto& buffer_impl = wis::from_handle_ref(buffer); - if (!buffer_impl.buffer_header) { - return wis::detail::make_result< - wis::detail::Func(), - "Provided buffer is not suitable for acceleration structure creation, did you forget to add " - "WisBufferUsageFlagsAccelerationStructureBuffer?">(VK_ERROR_UNKNOWN); - } - // Build acceleration structure using the provided description // This is a simplified example, actual implementation would involve more detailed handling of the description VkAccelerationStructureCreateInfoKHR create_info{ @@ -193,9 +186,10 @@ WIS_EXTERN_C WISDOM_RAYTRACING_API WisResult wisVKRaytracingExtensionCreateAccel auto& as_impl = *new (acceleration_structure) wis::impl::VKAccelerationStructureImpl{ .acceleration_structure = as_handle, .device_address = impl.rt_table->vkGetAccelerationStructureDeviceAddressKHR(impl.device, &info), - .buffer_control_block = buffer_impl.buffer_header, + .device = impl.device, + .vkDestroyAccelerationStructureKHR = impl.rt_table->vkDestroyAccelerationStructureKHR }; - buffer_impl.buffer_header->AddRef(); // Hold reference to device control block for acceleration structure + // Don't ref return wis::detail::vk_success; } @@ -204,14 +198,8 @@ WIS_EXTERN_C WISDOM_RAYTRACING_API void wisVKDestroyAccelerationStructure(WisVKA { auto& impl = wis::from_handle_ref(self); if (impl.acceleration_structure != VK_NULL_HANDLE) { - impl.buffer_control_block->header.device_table->vkDestroyAccelerationStructureKHR( - impl.buffer_control_block->header.device, - impl.acceleration_structure, - nullptr - ); + impl.vkDestroyAccelerationStructureKHR(impl.device, impl.acceleration_structure, nullptr); impl.acceleration_structure = VK_NULL_HANDLE; - - wis::detail::VKReleaseBuffer(impl.buffer_control_block); // Release reference to device control block } } diff --git a/src/extensions/raytracing/raytracing/vulkan/vk_types.hpp b/src/extensions/raytracing/raytracing/vulkan/vk_types.hpp index 393c7cf8b..171eb714b 100644 --- a/src/extensions/raytracing/raytracing/vulkan/vk_types.hpp +++ b/src/extensions/raytracing/raytracing/vulkan/vk_types.hpp @@ -19,7 +19,8 @@ struct VKRaytracingExtensionImpl { struct VKAccelerationStructureImpl { VkAccelerationStructureKHR acceleration_structure; VkDeviceAddress device_address; - detail::VKBufferControlBlock* buffer_control_block; + VkDevice device; + PFN_vkDestroyAccelerationStructureKHR vkDestroyAccelerationStructureKHR; }; } // namespace impl diff --git a/src/include/wisdom/vulkan/detail/vk_detail.hpp b/src/include/wisdom/vulkan/detail/vk_detail.hpp index 882f66820..157f26a1e 100644 --- a/src/include/wisdom/vulkan/detail/vk_detail.hpp +++ b/src/include/wisdom/vulkan/detail/vk_detail.hpp @@ -386,19 +386,6 @@ struct alignas(void*) VKRootSignatureControlBlock { } }; -//---------------------------------------------------------------------------------------------------------------------- -struct VKBufferHeader { - VkBuffer buffer; - VmaAllocation allocation; - void* mapped_ptr; - VkDevice device; - detail::VKDeviceControlBlock* device_header; - impl::VKMainDevice* device_table; -}; - -//---------------------------------------------------------------------------------------------------------------------- -struct VKBufferControlBlock : public VKControlBlock {}; - //---------------------------------------------------------------------------------------------------------------------- struct VKRenderTargetView { VkImageView view = VK_NULL_HANDLE; @@ -567,27 +554,6 @@ inline void VKReleaseSwapchain(VkSwapchainKHR swap, VKSwapchainControlBlock* hea } } -//---------------------------------------------------------------------------------------------------------------------- -inline void VKReleaseBuffer(VKBufferControlBlock* header) noexcept -{ - if (header && header->Release() == 1) { - auto& header_ref = header->header; - - // get allocator - VmaAllocator allocator = header_ref.device_header->header.allocator; - - if (header_ref.mapped_ptr) { - vmaUnmapMemory(allocator, header_ref.allocation); - } - vmaDestroyBuffer(allocator, header_ref.buffer, header_ref.allocation); - - header_ref.buffer = VK_NULL_HANDLE; - - wis::detail::VKReleaseDevice(header_ref.device_header); - delete header; - } -} - } // namespace wis::detail #endif // WIS_VK_DETAIL_HPP diff --git a/src/include/wisdom/vulkan/vk_impl.cpp b/src/include/wisdom/vulkan/vk_impl.cpp index 1cc6abbbb..02d259158 100644 --- a/src/include/wisdom/vulkan/vk_impl.cpp +++ b/src/include/wisdom/vulkan/vk_impl.cpp @@ -11,12 +11,6 @@ WIS_EXTERN_C WISDOM_API void wisVKDestroyBuffer(WisVKBuffer* self) auto& impl = wis::from_handle_ref(self); if (impl.buffer != VK_NULL_HANDLE) { - if (impl.buffer_header) { - wis::detail::VKReleaseBuffer(impl.buffer_header); - impl.buffer = VK_NULL_HANDLE; - return; - } - // get allocator VmaAllocator allocator = impl.device_header->header.allocator; diff --git a/src/include/wisdom/vulkan/vk_resource_allocator.cpp b/src/include/wisdom/vulkan/vk_resource_allocator.cpp index b3457c91e..155a5654b 100644 --- a/src/include/wisdom/vulkan/vk_resource_allocator.cpp +++ b/src/include/wisdom/vulkan/vk_resource_allocator.cpp @@ -155,36 +155,11 @@ WIS_EXTERN_C WISDOM_API WisResult wisVKResourceAllocatorCreateBuffer( } } - wis::detail::VKBufferControlBlock* buffer_header = nullptr; - if (desc->usage_flags & WisBufferUsageFlagsAccelerationStructureBuffer) { - // Shared buffer for AS needs to be tracked separately - buffer_header = new (std::nothrow) wis::detail::VKBufferControlBlock{}; - if (!buffer_header) { - if (mapped_ptr) { - vmaUnmapMemory(allocator.allocator, allocation_handle); - } - vmaDestroyBuffer(allocator.allocator, buffer_handle, allocation_handle); - return wis::detail::make_result( - VK_ERROR_OUT_OF_HOST_MEMORY - ); - } - - buffer_header->header = { - .buffer = buffer_handle, - .allocation = allocation_handle, - .mapped_ptr = mapped_ptr, - .device = allocator.device_header->header.device, - .device_header = allocator.device_header, - .device_table = &allocator.device_header->header.device_table, - }; - } - auto& impl = *new (buffer) wis::impl::VKBufferImpl{ .buffer = buffer_handle, .allocation = allocation_handle, .mapped_ptr = mapped_ptr, .device_header = allocator.device_header, - .buffer_header = buffer_header, }; impl.device_header->AddRef(); diff --git a/src/include/wisdom/vulkan/vk_types.hpp b/src/include/wisdom/vulkan/vk_types.hpp index 7bcdbe6c8..59b3fa4d6 100644 --- a/src/include/wisdom/vulkan/vk_types.hpp +++ b/src/include/wisdom/vulkan/vk_types.hpp @@ -26,7 +26,6 @@ struct VKSurfaceControlBlock; struct VKQueueFamilyExtras; struct VKSwapchainControlBlock; struct VKRenderTargetView; -struct VKBufferControlBlock; } // namespace detail namespace impl { @@ -117,7 +116,6 @@ struct VKBufferImpl { VmaAllocation allocation; void* mapped_ptr; detail::VKDeviceControlBlock* device_header; - detail::VKBufferControlBlock* buffer_header; // only for buffers for AS }; struct VKTextureImpl { diff --git a/xml/wis.xml b/xml/wis.xml index 3d64233aa..1d0c7c22b 100644 --- a/xml/wis.xml +++ b/xml/wis.xml @@ -14,7 +14,7 @@
- + From 3be76e90b256a8f6acf502e24eeef29a5121815b Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Mon, 27 Apr 2026 11:54:35 +0200 Subject: [PATCH 14/49] Add top-level AS allocation info query to API Introduce WisTopLevelStructureBuildDesc and the IndirectInput flag. Implement wisRaytracingExtensionGetTopLevelStructureInfo for DX12 and Vulkan backends. Update docs, XML, and tests to support querying allocation info for top-level acceleration structures. Adjust bottom-level build logic for indirect input and ensure C/C++ API consistency. --- .../enum/acceleration_structure_flags_enum.h | 5 +- ...n_create_acceleration_structure_function.h | 2 +- ...on_get_top_level_structure_info_function.h | 66 ++++++++++++++++ .../handle/raytracing_extension_handle.h | 3 +- ...bottom_level_structure_build_desc_struct.h | 5 +- .../struct/structure_allocation_info_struct.h | 2 +- .../top_level_structure_build_desc_struct.h | 53 +++++++++++++ .../raytracing/dx12/dx12_raytracing.cpp | 67 +++++++++++++---- .../raytracing/raytracing/generated/c_api.h | 50 ++++++++++++- .../raytracing/generated/cpp_api.hpp | 75 ++++++++++++++++++- .../raytracing/vulkan/vk_raytracing.cpp | 60 +++++++++++++-- .../raytracing/wisdom/wisdom_raytracing.h | 2 + tests/basic/rt_primitives.cpp | 33 ++++++-- xml/raytracing.xml | 16 +++- 14 files changed, 398 insertions(+), 41 deletions(-) create mode 100644 docs/raytracing/func/raytracing_extension_get_top_level_structure_info_function.h create mode 100644 docs/raytracing/struct/top_level_structure_build_desc_struct.h diff --git a/docs/raytracing/enum/acceleration_structure_flags_enum.h b/docs/raytracing/enum/acceleration_structure_flags_enum.h index eba383f5d..5ad79c122 100644 --- a/docs/raytracing/enum/acceleration_structure_flags_enum.h +++ b/docs/raytracing/enum/acceleration_structure_flags_enum.h @@ -17,6 +17,7 @@ * WisAccelerationStructureFlagsPreferFastBuild = (1u << 3), * WisAccelerationStructureFlagsMinimizeMemory = (1u << 4), * WisAccelerationStructureFlagsPerformUpdate = (1u << 5), + * WisAccelerationStructureFlagsIndirectInput = (1u << 6), * } WisAccelerationStructureFlags; * ``` * C++ version: @@ -31,6 +32,7 @@ * PreferFastBuild = (1u << 3), * MinimizeMemory = (1u << 4), * PerformUpdate = (1u << 5), + * IndirectInput = (1u << 6), * }; * } * ``` @@ -53,6 +55,7 @@ * - `WisAccelerationStructureFlagsMinimizeMemory = (1 << 4)`: Acceleration structure is minimized for memory usage. * - `WisAccelerationStructureFlagsPerformUpdate = (1 << 5)`: Acceleration structure build is performed as an update. * Only used for update builds. + * - `WisAccelerationStructureFlagsIndirectInput = (1 << 6)`: Acceleration structure build uses indirect input. * \endcond * * @@ -61,6 +64,6 @@ * * \cond WIS_GEN_REFS * @see Structs: - * WisBottomLevelStructureBuildDesc + * WisBottomLevelStructureBuildDesc, WisTopLevelStructureBuildDesc * \endcond */ diff --git a/docs/raytracing/func/raytracing_extension_create_acceleration_structure_function.h b/docs/raytracing/func/raytracing_extension_create_acceleration_structure_function.h index 1ba2699a1..ad80bf77b 100644 --- a/docs/raytracing/func/raytracing_extension_create_acceleration_structure_function.h +++ b/docs/raytracing/func/raytracing_extension_create_acceleration_structure_function.h @@ -75,7 +75,7 @@ * * The resulting acceleration structure does not reference the provided buffer. The buffer @wis_must be created with * `WisBufferUsageFlagsAccelerationStructureBuffer` usage flag. - * + * * @warning The resulting acceleration structure does not hold a reference to a device or buffer. The caller is * responsible for ensuring that the buffer and device remain valid until the acceleration structure is destroyed. * diff --git a/docs/raytracing/func/raytracing_extension_get_top_level_structure_info_function.h b/docs/raytracing/func/raytracing_extension_get_top_level_structure_info_function.h new file mode 100644 index 000000000..8c212361b --- /dev/null +++ b/docs/raytracing/func/raytracing_extension_get_top_level_structure_info_function.h @@ -0,0 +1,66 @@ +/** + * @struct wisRaytracingExtensionGetTopLevelStructureInfo + * @ingroup Functions Raytracing + * + * + * @section wisRaytracingExtensionGetTopLevelStructureInfo_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * * C Version: + * ```c + * // Provided by Wisdom 0.7.1. + * WisResult wisRaytracingExtensionGetTopLevelStructureInfo(WisRaytracingExtension* self, + * const WisTopLevelStructureBuildDesc* build_desc, + * WisStructureAllocationInfo* info); + * ``` + *
+ * C Implementation Specific Version: + * ```c + * // Provided by Wisdom 0.7.1. + * WisResult wisVKRaytracingExtensionGetTopLevelStructureInfo(WisVKRaytracingExtension* self, + * const WisTopLevelStructureBuildDesc* build_desc, + * WisStructureAllocationInfo* info); + * + * // Provided by Wisdom 0.7.1. + * WisResult wisDX12RaytracingExtensionGetTopLevelStructureInfo(WisDX12RaytracingExtension* self, + * const WisTopLevelStructureBuildDesc* build_desc, + * WisStructureAllocationInfo* info); + * ``` + *
+ * + * C++ Version: + * ```cpp + * namespace wis + * ``` + *
+ * C++ Implementation Specific Version: + * ```cpp + * namespace wis + * ``` + *
+ * + * \endcond + * + * @section wisRaytracingExtensionGetTopLevelStructureInfo_memb Parameters + *
+ * \cond WIS_GEN_DESC + * * - **this** `self` self is a pointer to the valid WisRaytracingExtension instance. + * - `build_desc` The build description for the bottom-level acceleration structure. + * - `info` The allocation information for the bottom-level acceleration structure. + * + * - **return** denoting the outcome of operation. + * + * \endcond + * + * @section wisRaytracingExtensionGetTopLevelStructureInfo_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section wisRaytracingExtensionGetTopLevelStructureInfo_see_also See Also + *
+ * \cond WIS_GEN_REFS + * \endcond + */ diff --git a/docs/raytracing/handle/raytracing_extension_handle.h b/docs/raytracing/handle/raytracing_extension_handle.h index 37499b48b..324e8abfd 100644 --- a/docs/raytracing/handle/raytracing_extension_handle.h +++ b/docs/raytracing/handle/raytracing_extension_handle.h @@ -26,6 +26,7 @@ * \cond WIS_GEN_REFS * @see Functions: * wisDestroyRaytracingExtension, wisInitRaytracingExtension, wisRaytracingExtensionSupported, - * wisRaytracingExtensionGetBottomLevelStructureInfo, wisRaytracingExtensionCreateAccelerationStructure + * wisRaytracingExtensionGetBottomLevelStructureInfo, wisRaytracingExtensionGetTopLevelStructureInfo, + * wisRaytracingExtensionCreateAccelerationStructure * \endcond */ diff --git a/docs/raytracing/struct/bottom_level_structure_build_desc_struct.h b/docs/raytracing/struct/bottom_level_structure_build_desc_struct.h index b1f8e4a5e..73583b28c 100644 --- a/docs/raytracing/struct/bottom_level_structure_build_desc_struct.h +++ b/docs/raytracing/struct/bottom_level_structure_build_desc_struct.h @@ -37,10 +37,9 @@ * \cond WIS_GEN_DESC * - `flags` The build flags for the acceleration structure build. * - `geometry_count` The number of geometry instances in the bottom-level acceleration structure. - * - `geometries` The array of geometry descriptions for the bottom-level acceleration structure. Has higher precedence - * over `WisBottomLevelStructureBuildDesc::indirect_geometries`. + * - `geometries` The array of geometry descriptions for the bottom-level acceleration structure. * - `indirect_geometries` The array of geometry descriptions for indirect build of the bottom-level acceleration - * structure. + * structure. This input is ignored unless `WisAccelerationStructureFlagsIndirectInput` is specified. * \endcond * * @section WisBottomLevelStructureBuildDesc_descr Description diff --git a/docs/raytracing/struct/structure_allocation_info_struct.h b/docs/raytracing/struct/structure_allocation_info_struct.h index 4e9779d94..e64088532 100644 --- a/docs/raytracing/struct/structure_allocation_info_struct.h +++ b/docs/raytracing/struct/structure_allocation_info_struct.h @@ -48,6 +48,6 @@ *
* \cond WIS_GEN_REFS * @see Functions: - * wisRaytracingExtensionGetBottomLevelStructureInfo + * wisRaytracingExtensionGetBottomLevelStructureInfo, wisRaytracingExtensionGetTopLevelStructureInfo * \endcond */ diff --git a/docs/raytracing/struct/top_level_structure_build_desc_struct.h b/docs/raytracing/struct/top_level_structure_build_desc_struct.h new file mode 100644 index 000000000..a2f9cbc54 --- /dev/null +++ b/docs/raytracing/struct/top_level_structure_build_desc_struct.h @@ -0,0 +1,53 @@ +/** + * @struct WisTopLevelStructureBuildDesc + * @ingroup Structures Raytracing + * + * + * @section WisTopLevelStructureBuildDesc_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef struct WisTopLevelStructureBuildDesc { + * WisAccelerationStructureFlags flags; + * uint32_t instance_count; + * uint64_t instance_buffer_address; + * } WisTopLevelStructureBuildDesc; + * + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * struct TopLevelStructureBuildDesc { + * wis::AccelerationStructureFlags flags; + * std::uint32_t instance_count; + * std::uint64_t instance_buffer_address; + * }; + * } + * ``` + * \endcond + * + * @section WisTopLevelStructureBuildDesc_memb Members + *
+ * \cond WIS_GEN_DESC + * - `flags` The build flags for the acceleration structure build. + * - `instance_count` The number of instances in the top-level acceleration structure. + * - `instance_buffer_address` The GPU address of the instance buffer for the top-level acceleration structure. + * \endcond + * + * @section WisTopLevelStructureBuildDesc_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section WisTopLevelStructureBuildDesc_see_also See Also + *
+ * \cond WIS_GEN_REFS + * @see Functions: + * wisRaytracingExtensionGetTopLevelStructureInfo + * \endcond + */ diff --git a/src/extensions/raytracing/raytracing/dx12/dx12_raytracing.cpp b/src/extensions/raytracing/raytracing/dx12/dx12_raytracing.cpp index d22de1136..076c01a78 100644 --- a/src/extensions/raytracing/raytracing/dx12/dx12_raytracing.cpp +++ b/src/extensions/raytracing/raytracing/dx12/dx12_raytracing.cpp @@ -50,10 +50,7 @@ inline WisResult DX12RaytracingExtensionInit( case WisGeometryTypeAABBs: geometry.AABBs = { .AABBCount = desc.triangle_or_aabb_count, - .AABBs = { - .StartAddress = desc.vertex_or_aabb_buffer_address, - .StrideInBytes = desc.vertex_or_aabb_stride - } + .AABBs = {.StartAddress = desc.vertex_or_aabb_buffer_address, .StrideInBytes = desc.vertex_or_aabb_stride} }; break; default: @@ -106,12 +103,12 @@ WIS_EXTERN_C WISDOM_RAYTRACING_API WisResult wisDX12RaytracingExtensionCreateAcc ) { auto& buffer_impl = wis::from_handle_ref(buffer); - auto address = buffer_impl.resource->GetGPUVirtualAddress(); // AddRef buffer to ensure it lives as long as the acceleration - // structure + auto address = buffer_impl.resource->GetGPUVirtualAddress(); // AddRef buffer to ensure it lives as long as the + // acceleration structure if (address == 0) { return wis::detail::make_result(E_FAIL); } - + new (acceleration_structure) wis::impl::DX12AccelerationStructureImpl{ .gpu_address = address + desc->offset, }; @@ -126,7 +123,8 @@ WIS_EXTERN_C WISDOM_RAYTRACING_API void wisDX12DestroyAccelerationStructure(WisD } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_RAYTRACING_API uint64_t wisDX12AccelerationStructureGetGPUAddress(WisDX12AccelerationStructure* self) +WIS_EXTERN_C WISDOM_RAYTRACING_API uint64_t +wisDX12AccelerationStructureGetGPUAddress(WisDX12AccelerationStructure* self) { return wis::from_handle_ref(self).gpu_address; } @@ -164,11 +162,11 @@ WIS_EXTERN_C WISDOM_RAYTRACING_API WisResult wisDX12RaytracingExtensionGetBottom } // Convert geometry descriptions - if (build_desc->geometries) { + if (!(build_desc->flags & WisAccelerationStructureFlagsIndirectInput)) { for (uint32_t i = 0; i < build_desc->geometry_count; ++i) { - geometry_descs[i] = wis::detail::DX12CreateGeometryDesc(build_desc->geometries[i]); + geometry_descs[i] = wis::detail::DX12CreateGeometryDesc(build_desc->geometries[i]); } - } else if (build_desc->indirect_geometries) { + } else { for (uint32_t i = 0; i < build_desc->geometry_count; ++i) { geometry_descs[i] = wis::detail::DX12CreateGeometryDesc(*build_desc->indirect_geometries[i]); } @@ -179,18 +177,59 @@ WIS_EXTERN_C WISDOM_RAYTRACING_API WisResult wisDX12RaytracingExtensionGetBottom *info = { wis::aligned_size( uint64_t(prebuild_info.ScratchDataSizeInBytes), - uint64_t(D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BYTE_ALIGNMENT) + uint64_t(wis::AccelerationStructureAlignment) ), wis::aligned_size( uint64_t(prebuild_info.ResultDataMaxSizeInBytes), - uint64_t(D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BYTE_ALIGNMENT) + uint64_t(wis::AccelerationStructureAlignment) ), wis::aligned_size( uint64_t(prebuild_info.UpdateScratchDataSizeInBytes), - uint64_t(D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BYTE_ALIGNMENT) + uint64_t(wis::AccelerationStructureAlignment) ) }; return wis::detail::dx_success; } +//---------------------------------------------------------------------------------------------------------------------- +WIS_EXTERN_C WISDOM_RAYTRACING_API WisResult wisDX12RaytracingExtensionGetTopLevelStructureInfo( + WisDX12RaytracingExtension* self, + const WisTopLevelStructureBuildDesc* build_desc, + WisStructureAllocationInfo* info +) +{ + auto& impl = wis::from_handle_ref(self); + D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS inputs{ + .Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL, + .Flags = wis::detail::DX12Convert(build_desc->flags), + .NumDescs = build_desc->instance_count, + .DescsLayout = build_desc->flags & WisAccelerationStructureFlagsIndirectInput ? D3D12_ELEMENTS_LAYOUT_ARRAY_OF_POINTERS + : D3D12_ELEMENTS_LAYOUT_ARRAY, + .InstanceDescs = build_desc->instance_buffer_address + }; + D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO prebuild_info = {}; + impl.device->GetRaytracingAccelerationStructurePrebuildInfo(&inputs, &prebuild_info); + + static_assert( + wis::AccelerationStructureAlignment >= D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BYTE_ALIGNMENT, + "DX12 requires at least 256-byte alignment for acceleration structures" + ); + *info = { + wis::aligned_size( + uint32_t(prebuild_info.ScratchDataSizeInBytes), + uint32_t(wis::AccelerationStructureAlignment) + ), + wis::aligned_size( + uint32_t(prebuild_info.ResultDataMaxSizeInBytes), + uint32_t(wis::AccelerationStructureAlignment) + ), + wis::aligned_size( + uint32_t(prebuild_info.UpdateScratchDataSizeInBytes), + uint32_t(wis::AccelerationStructureAlignment) + ) + }; + + return wis::detail::dx_success; +} + #endif diff --git a/src/extensions/raytracing/raytracing/generated/c_api.h b/src/extensions/raytracing/raytracing/generated/c_api.h index 33ad8b273..9b48ab856 100644 --- a/src/extensions/raytracing/raytracing/generated/c_api.h +++ b/src/extensions/raytracing/raytracing/generated/c_api.h @@ -64,6 +64,7 @@ typedef enum WisAccelerationStructureFlags { * @brief Acceleration structure build is performed as an update. Only used for update builds. * */ WisAccelerationStructureFlagsPerformUpdate = (1u << 5), + WisAccelerationStructureFlagsIndirectInput = (1u << 6), ///< Acceleration structure build uses indirect input. } WisAccelerationStructureFlags; //============================================================== @@ -128,16 +129,29 @@ typedef struct WisBottomLevelStructureBuildDesc { * */ uint32_t geometry_count; /** - * @brief The array of geometry descriptions for the bottom-level acceleration structure. Has higher precedence over - * `WisBottomLevelStructureBuildDesc::indirect_geometries`. + * @brief The array of geometry descriptions for the bottom-level acceleration structure. * */ const WisAcceleratedGeometryDesc* geometries; /** - * @brief The array of geometry descriptions for indirect build of the bottom-level acceleration structure. + * @brief The array of geometry descriptions for indirect build of the bottom-level acceleration structure. This + * input is ignored unless `WisAccelerationStructureFlagsIndirectInput` is specified. * */ const WisAcceleratedGeometryDesc** indirect_geometries; } WisBottomLevelStructureBuildDesc; +/** + * @brief Provided by Wisdom 0.7.1. Structure describing the build description for a top-level acceleration structure. + * + * */ +typedef struct WisTopLevelStructureBuildDesc { + WisAccelerationStructureFlags flags; ///< The build flags for the acceleration structure build. + uint32_t instance_count; ///< The number of instances in the top-level acceleration structure. + /** + * @brief The GPU address of the instance buffer for the top-level acceleration structure. + * */ + uint64_t instance_buffer_address; +} WisTopLevelStructureBuildDesc; + //============================================================== // Constants //============================================================== @@ -217,6 +231,21 @@ WISDOM_RAYTRACING_API WisResult wisDX12RaytracingExtensionGetBottomLevelStructur WisStructureAllocationInfo* info ); +/** + * @brief Provided by Wisdom 0.7.1. Retrieves the allocation information for a top-level acceleration structure based on + * the provided build description. + * @param self is a pointer to the valid WisRaytracingExtension instance. + * @param build_desc The build description for the bottom-level acceleration structure. + * @param info The allocation information for the bottom-level acceleration structure. + * @return Result denoting the outcome of operation. + * + * */ +WISDOM_RAYTRACING_API WisResult wisDX12RaytracingExtensionGetTopLevelStructureInfo( + WisDX12RaytracingExtension* self, + const WisTopLevelStructureBuildDesc* build_desc, + WisStructureAllocationInfo* info +); + /** * @brief Provided by Wisdom 0.7.1. Creates an acceleration structure based on the provided description. * @param self is a pointer to the valid WisRaytracingExtension instance. @@ -313,6 +342,21 @@ WISDOM_RAYTRACING_API WisResult wisVKRaytracingExtensionGetBottomLevelStructureI WisStructureAllocationInfo* info ); +/** + * @brief Provided by Wisdom 0.7.1. Retrieves the allocation information for a top-level acceleration structure based on + * the provided build description. + * @param self is a pointer to the valid WisRaytracingExtension instance. + * @param build_desc The build description for the bottom-level acceleration structure. + * @param info The allocation information for the bottom-level acceleration structure. + * @return Result denoting the outcome of operation. + * + * */ +WISDOM_RAYTRACING_API WisResult wisVKRaytracingExtensionGetTopLevelStructureInfo( + WisVKRaytracingExtension* self, + const WisTopLevelStructureBuildDesc* build_desc, + WisStructureAllocationInfo* info +); + /** * @brief Provided by Wisdom 0.7.1. Creates an acceleration structure based on the provided description. * @param self is a pointer to the valid WisRaytracingExtension instance. diff --git a/src/extensions/raytracing/raytracing/generated/cpp_api.hpp b/src/extensions/raytracing/raytracing/generated/cpp_api.hpp index b34f9d522..7645b93e5 100644 --- a/src/extensions/raytracing/raytracing/generated/cpp_api.hpp +++ b/src/extensions/raytracing/raytracing/generated/cpp_api.hpp @@ -56,6 +56,7 @@ enum class AccelerationStructureFlags : uint32_t { PreferFastBuild = (1u << 3), ///< Acceleration structure is preferred to be fast built. MinimizeMemory = (1u << 4), ///< Acceleration structure is minimized for memory usage. PerformUpdate = (1u << 5), ///< Acceleration structure build is performed as an update. Only used for update builds. + IndirectInput = (1u << 6), ///< Acceleration structure build uses indirect input. }; WISDOM_DEFINE_ENUM_OPERATORS(AccelerationStructureFlags) @@ -121,16 +122,32 @@ struct BottomLevelStructureBuildDesc { * */ std::uint32_t geometry_count; /** - * @brief The array of geometry descriptions for the bottom-level acceleration structure. Has higher precedence over - * `wis::BottomLevelStructureBuildDesc::indirect_geometries`. + * @brief The array of geometry descriptions for the bottom-level acceleration structure. * */ const wis::AcceleratedGeometryDesc* geometries; /** - * @brief The array of geometry descriptions for indirect build of the bottom-level acceleration structure. + * @brief The array of geometry descriptions for indirect build of the bottom-level acceleration structure. This + * input is ignored unless `wis::AccelerationStructureFlags::IndirectInput` is specified. * */ const wis::AcceleratedGeometryDesc** indirect_geometries; }; +/** + * @brief Provided by Wisdom 0.7.1. Structure describing the build description for a top-level acceleration structure. + * + * */ +struct TopLevelStructureBuildDesc { + wis::AccelerationStructureFlags flags; ///< The build flags for the acceleration structure build. + /** + * @brief The number of instances in the top-level acceleration structure. + * */ + std::uint32_t instance_count; + /** + * @brief The GPU address of the instance buffer for the top-level acceleration structure. + * */ + std::uint64_t instance_buffer_address; +}; + //============================================================== // Constants //============================================================== @@ -240,6 +257,32 @@ class DX12RaytracingExtension : public wis::impl::Implements< }; return info; } + /** + * @brief Provided by Wisdom 0.7.1. Retrieves the allocation information for a top-level acceleration structure + * based on the provided build description. + * @param build_desc The build description for the bottom-level acceleration structure. + * @param out_result denoting the outcome of operation. + * @return info The allocation information for the bottom-level acceleration structure. + * + * */ + WIS_NODISCARD inline wis::StructureAllocationInfo GetTopLevelStructureInfo( + const wis::TopLevelStructureBuildDesc& build_desc, + wis::Result& out_result + ) noexcept + { + wis::StructureAllocationInfo info; + const WisResult wis_result = ::wisDX12RaytracingExtensionGetTopLevelStructureInfo( + &_impl_storage, + reinterpret_cast(&build_desc), + reinterpret_cast(&info) + ); + out_result = wis::Result{ + static_cast(wis_result.status), + wis_result.platform_code, + wis_result.error + }; + return info; + } /** * @brief Provided by Wisdom 0.7.1. Creates an acceleration structure based on the provided description. * @param buffer The buffer to write the acceleration structure data to. @@ -370,6 +413,32 @@ class VKRaytracingExtension }; return info; } + /** + * @brief Provided by Wisdom 0.7.1. Retrieves the allocation information for a top-level acceleration structure + * based on the provided build description. + * @param build_desc The build description for the bottom-level acceleration structure. + * @param out_result denoting the outcome of operation. + * @return info The allocation information for the bottom-level acceleration structure. + * + * */ + WIS_NODISCARD inline wis::StructureAllocationInfo GetTopLevelStructureInfo( + const wis::TopLevelStructureBuildDesc& build_desc, + wis::Result& out_result + ) noexcept + { + wis::StructureAllocationInfo info; + const WisResult wis_result = ::wisVKRaytracingExtensionGetTopLevelStructureInfo( + &_impl_storage, + reinterpret_cast(&build_desc), + reinterpret_cast(&info) + ); + out_result = wis::Result{ + static_cast(wis_result.status), + wis_result.platform_code, + wis_result.error + }; + return info; + } /** * @brief Provided by Wisdom 0.7.1. Creates an acceleration structure based on the provided description. * @param buffer The buffer to write the acceleration structure data to. diff --git a/src/extensions/raytracing/raytracing/vulkan/vk_raytracing.cpp b/src/extensions/raytracing/raytracing/vulkan/vk_raytracing.cpp index 45032a93f..f3e44c8b9 100644 --- a/src/extensions/raytracing/raytracing/vulkan/vk_raytracing.cpp +++ b/src/extensions/raytracing/raytracing/vulkan/vk_raytracing.cpp @@ -189,7 +189,6 @@ WIS_EXTERN_C WISDOM_RAYTRACING_API WisResult wisVKRaytracingExtensionCreateAccel .device = impl.device, .vkDestroyAccelerationStructureKHR = impl.rt_table->vkDestroyAccelerationStructureKHR }; - // Don't ref return wis::detail::vk_success; } @@ -246,12 +245,12 @@ WIS_EXTERN_C WISDOM_RAYTRACING_API WisResult wisVKRaytracingExtensionGetBottomLe } // Fill geometry descriptions - if (build_desc->geometries) { + if (!(build_desc->flags & WisAccelerationStructureFlagsIndirectInput)) { for (uint32_t i = 0; i < build_desc->geometry_count; ++i) { geometry_desc_span[i] = wis::detail::VKCreateGeometryDesc(build_desc->geometries[i]); primitive_counts_span[i] = build_desc->geometries[i].triangle_or_aabb_count; } - } else if (build_desc->indirect_geometries) { + } else { for (uint32_t i = 0; i < build_desc->geometry_count; ++i) { geometry_desc_span[i] = wis::detail::VKCreateGeometryDesc(*build_desc->indirect_geometries[i]); primitive_counts_span[i] = build_desc->indirect_geometries[i]->triangle_or_aabb_count; @@ -279,11 +278,58 @@ WIS_EXTERN_C WISDOM_RAYTRACING_API WisResult wisVKRaytracingExtensionGetBottomLe &build_sizes_info ); - constexpr static size_t alignment = 256; // 256 is a common alignment requirement for acceleration structures *info = { - wis::aligned_size(build_sizes_info.buildScratchSize, alignment), - wis::aligned_size(build_sizes_info.accelerationStructureSize, alignment), - wis::aligned_size(build_sizes_info.updateScratchSize, alignment) + wis::aligned_size(build_sizes_info.buildScratchSize, wis::AccelerationStructureAlignment), + wis::aligned_size(build_sizes_info.accelerationStructureSize, wis::AccelerationStructureAlignment), + wis::aligned_size(build_sizes_info.updateScratchSize, wis::AccelerationStructureAlignment) + }; + return wis::detail::vk_success; +} + +//---------------------------------------------------------------------------------------------------------------------- +WIS_EXTERN_C WISDOM_RAYTRACING_API WisResult wisVKRaytracingExtensionGetTopLevelStructureInfo( + WisVKRaytracingExtension* self, + const WisTopLevelStructureBuildDesc* build_desc, + WisStructureAllocationInfo* info +) +{ + auto& impl = wis::from_handle_ref(self); + VkAccelerationStructureGeometryKHR geometry{ + .sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR, + .geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR, + .geometry = { + .instances = { + .sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR, + .arrayOfPointers = VkBool32(build_desc->flags & WisAccelerationStructureFlagsIndirectInput > 0), + .data = {.deviceAddress = build_desc->instance_buffer_address} + } + }, + }; + VkAccelerationStructureBuildGeometryInfoKHR build_info{ + .sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR, + .type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR, + .flags = wis::detail::VKConvert(build_desc->flags), + .mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR, + .geometryCount = 1u, + .pGeometries = &geometry, + }; + VkAccelerationStructureBuildSizesInfoKHR build_sizes_info{ + .sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR, + }; + + uint32_t max_instance_count = build_desc->instance_count; + impl.rt_table->vkGetAccelerationStructureBuildSizesKHR( + impl.device, + VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, + &build_info, + &max_instance_count, + &build_sizes_info + ); + + *info = { + wis::aligned_size(build_sizes_info.buildScratchSize, wis::AccelerationStructureAlignment), + wis::aligned_size(build_sizes_info.accelerationStructureSize, wis::AccelerationStructureAlignment), + wis::aligned_size(build_sizes_info.updateScratchSize, wis::AccelerationStructureAlignment) }; return wis::detail::vk_success; } diff --git a/src/extensions/raytracing/wisdom/wisdom_raytracing.h b/src/extensions/raytracing/wisdom/wisdom_raytracing.h index 1c531199f..d0e7d8846 100644 --- a/src/extensions/raytracing/wisdom/wisdom_raytracing.h +++ b/src/extensions/raytracing/wisdom/wisdom_raytracing.h @@ -40,6 +40,7 @@ typedef struct WisDX12AccelerationStructureDesc WisAccelerationStructureDesc; # define wisInitRaytracingExtension wisDX12InitRaytracingExtension # define wisRaytracingExtensionSupported wisDX12RaytracingExtensionSupported # define wisRaytracingExtensionGetBottomLevelStructureInfo wisDX12RaytracingExtensionGetBottomLevelStructureInfo +# define wisRaytracingExtensionGetTopLevelStructureInfo wisDX12RaytracingExtensionGetTopLevelStructureInfo # define wisRaytracingExtensionCreateAccelerationStructure wisDX12RaytracingExtensionCreateAccelerationStructure # define wisAccelerationStructureGetGPUAddress wisDX12AccelerationStructureGetGPUAddress @@ -67,6 +68,7 @@ typedef struct WisVKAccelerationStructureDesc WisAccelerationStructureDesc; # define wisInitRaytracingExtension wisVKInitRaytracingExtension # define wisRaytracingExtensionSupported wisVKRaytracingExtensionSupported # define wisRaytracingExtensionGetBottomLevelStructureInfo wisVKRaytracingExtensionGetBottomLevelStructureInfo +# define wisRaytracingExtensionGetTopLevelStructureInfo wisVKRaytracingExtensionGetTopLevelStructureInfo # define wisRaytracingExtensionCreateAccelerationStructure wisVKRaytracingExtensionCreateAccelerationStructure # define wisAccelerationStructureGetGPUAddress wisVKAccelerationStructureGetGPUAddress diff --git a/tests/basic/rt_primitives.cpp b/tests/basic/rt_primitives.cpp index f585b2593..27f2d179e 100644 --- a/tests/basic/rt_primitives.cpp +++ b/tests/basic/rt_primitives.cpp @@ -121,13 +121,23 @@ TEST_CASE("check_rt_acceleration_structure") .geometry_count = 1, .geometries = &geometry_desc, }; + wis::TopLevelStructureBuildDesc tlas_build_desc{ + .flags = wis::AccelerationStructureFlags::AllowUpdate, + .instance_count = 1, + }; + wis::StructureAllocationInfo alloc_info = rt_extension.GetBottomLevelStructureInfo(blas_build_desc, result); REQUIRE(result.status == wis::Status::Ok); REQUIRE(alloc_info.structure_size > 0); + wis::StructureAllocationInfo tlas_alloc_info = rt_extension.GetTopLevelStructureInfo(tlas_build_desc, result); + REQUIRE(result.status == wis::Status::Ok); + REQUIRE(tlas_alloc_info.structure_size > 0); + REQUIRE(tlas_alloc_info.update_size > 0); + wis::Buffer rtas_buffer = allocator.CreateBuffer( { - .size_bytes = alloc_info.structure_size, + .size_bytes = alloc_info.structure_size + tlas_alloc_info.structure_size, .usage_flags = wis::BufferUsageFlags::AccelerationStructureBuffer, }, result @@ -136,7 +146,7 @@ TEST_CASE("check_rt_acceleration_structure") wis::Buffer scratch_buffer = allocator.CreateBuffer( { - .size_bytes = alloc_info.scratch_size, + .size_bytes = alloc_info.scratch_size + tlas_alloc_info.scratch_size, .usage_flags = wis::BufferUsageFlags::StorageBuffer, }, result @@ -149,13 +159,26 @@ TEST_CASE("check_rt_acceleration_structure") { .level = wis::AccelerationStructureLevel::BottomLevel, .offset = 0, - .size = 1024, + .size = alloc_info.structure_size, + }, + result + ); + REQUIRE(result.status == wis::Status::Ok); + + wis::AccelerationStructure tlas = rt_extension.CreateAccelerationStructure( + rtas_buffer, + { + .level = wis::AccelerationStructureLevel::TopLevel, + .offset = alloc_info.structure_size, + .size = tlas_alloc_info.structure_size, }, result ); REQUIRE(result.status == wis::Status::Ok); - uint64_t gpu_address = blas.GetGPUAddress(); - REQUIRE(gpu_address != 0); + uint64_t blas_gpu_address = blas.GetGPUAddress(); + REQUIRE(blas_gpu_address != 0); + uint64_t tlas_gpu_address = tlas.GetGPUAddress(); + REQUIRE(tlas_gpu_address != 0); } diff --git a/xml/raytracing.xml b/xml/raytracing.xml index 07c581a78..8e1e63e3c 100644 --- a/xml/raytracing.xml +++ b/xml/raytracing.xml @@ -66,6 +66,7 @@ + @@ -97,8 +98,14 @@ - - + + + + + + + + @@ -122,6 +129,11 @@ + + + + + From 1601d158d57c32f15e5db052418fe2a361c4cf59 Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Wed, 29 Apr 2026 08:59:20 +0200 Subject: [PATCH 15/49] swapchain rt --- 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, }; } From 763151a96b7cd13a5e0d0040befdaaedd9589e2a Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Fri, 1 May 2026 00:13:46 +0200 Subject: [PATCH 16/49] Add Video extension with DX12/Vulkan support and codegen Introduced a new Video extension with CMake integration, C/C++ API headers, and backend implementations for DirectX 12 and Vulkan. Updated the code generator to support handle constructors with custom parameters from XML, enabling automatic generation of extension handle constructors. Added XML spec files for the Video extension, new headers for enums and handles, and backend-specific implementation files. Improved code generation for function parameters and enhanced parsing of blocks in handle definitions. Comprehensive documentation was added for all new types and functions. --- docs/video/enum/video_codec_enum.h | 54 ++++++++ docs/video/enum/video_codec_flags_enum.h | 56 ++++++++ ...estroy_video_decoding_extension_function.h | 44 +++++++ .../init_video_decoding_extension_function.h | 70 ++++++++++ ...eo_decoding_extension_supported_function.h | 58 +++++++++ .../handle/video_decoding_extension_handle.h | 28 ++++ examples/CMakeLists.txt | 1 + examples/video/CMakeLists.txt | 17 +++ examples/video/entry_main.cpp | 120 ++++++++++++++++++ generator/function.cpp | 64 +++------- generator/generator.cpp | 46 +++++++ generator/generator.hpp | 1 + generator/handle.cpp | 82 +++++++++++- src/CMakeLists.txt | 2 +- src/extensions/CMakeLists.txt | 6 + src/extensions/video/CMakeLists.txt | 116 +++++++++++++++++ .../video/video/dx12/dx12_types.hpp | 30 +++++ .../video/video/dx12/dx12_video.cpp | 84 ++++++++++++ src/extensions/video/video/generated/c_api.h | 104 +++++++++++++++ .../video/video/generated/cpp_api.hpp | 112 ++++++++++++++++ .../video/video/generated/dx12_convert.hpp | 15 +++ .../video/video/generated/vk_convert.hpp | 15 +++ .../video/video/vulkan/vk_types.hpp | 30 +++++ .../video/video/vulkan/vk_video.cpp | 102 +++++++++++++++ src/extensions/video/wisdom/wisdom_video.h | 65 ++++++++++ src/extensions/video/wisdom/wisdom_video.hpp | 45 +++++++ xml/spec_template.xml | 26 ++++ xml/video.xml | 37 ++++++ 28 files changed, 1377 insertions(+), 53 deletions(-) create mode 100644 docs/video/enum/video_codec_enum.h create mode 100644 docs/video/enum/video_codec_flags_enum.h create mode 100644 docs/video/func/destroy_video_decoding_extension_function.h create mode 100644 docs/video/func/init_video_decoding_extension_function.h create mode 100644 docs/video/func/video_decoding_extension_supported_function.h create mode 100644 docs/video/handle/video_decoding_extension_handle.h create mode 100644 examples/video/CMakeLists.txt create mode 100644 examples/video/entry_main.cpp create mode 100644 src/extensions/video/CMakeLists.txt create mode 100644 src/extensions/video/video/dx12/dx12_types.hpp create mode 100644 src/extensions/video/video/dx12/dx12_video.cpp create mode 100644 src/extensions/video/video/generated/c_api.h create mode 100644 src/extensions/video/video/generated/cpp_api.hpp create mode 100644 src/extensions/video/video/generated/dx12_convert.hpp create mode 100644 src/extensions/video/video/generated/vk_convert.hpp create mode 100644 src/extensions/video/video/vulkan/vk_types.hpp create mode 100644 src/extensions/video/video/vulkan/vk_video.cpp create mode 100644 src/extensions/video/wisdom/wisdom_video.h create mode 100644 src/extensions/video/wisdom/wisdom_video.hpp create mode 100644 xml/spec_template.xml create mode 100644 xml/video.xml diff --git a/docs/video/enum/video_codec_enum.h b/docs/video/enum/video_codec_enum.h new file mode 100644 index 000000000..66badfb1a --- /dev/null +++ b/docs/video/enum/video_codec_enum.h @@ -0,0 +1,54 @@ +/** + * @struct WisVideoCodec WisVideoCodec + * @ingroup Enumerations Video + * + * @section WisVideoCodec_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef enum WisVideoCodec { + * WisVideoCodecNone = 0, + * WisVideoCodecH264 = (1u << 0), + * WisVideoCodecH265 = (1u << 1), + * WisVideoCodecAV1 = (1u << 2), + * WisVideoCodecVP9 = (1u << 3), + * } WisVideoCodec; + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * enum class VideoCodec : uint32_t { + * None = 0, + * H264 = (1u << 0), + * H265 = (1u << 1), + * AV1 = (1u << 2), + * VP9 = (1u << 3), + * }; + * } + * ``` + * \endcond + * + * @section WisVideoCodec_descr Description + *
+ * \cond WIS_GEN_DESC + * Video codec flags. Used to request and check supported codecs. + * + * Values: + * - `WisVideoCodecNone = 0`: No video is requested. The extension will not initialize. + * - `WisVideoCodecH264 = (1 << 0)`: H.264 video codec. + * - `WisVideoCodecH265 = (1 << 1)`: H.265 video codec. + * - `WisVideoCodecAV1 = (1 << 2)`: AV1 video codec. + * - `WisVideoCodecVP9 = (1 << 3)`: VP9 video codec. + * \endcond + * + * + * @section WisVideoCodec_see_also See Also + *
+ * + * \cond WIS_GEN_REFS + * \endcond + */ diff --git a/docs/video/enum/video_codec_flags_enum.h b/docs/video/enum/video_codec_flags_enum.h new file mode 100644 index 000000000..b879d707f --- /dev/null +++ b/docs/video/enum/video_codec_flags_enum.h @@ -0,0 +1,56 @@ +/** + * @struct WisVideoCodecFlags WisVideoCodecFlags + * @ingroup Enumerations Video + * + * @section WisVideoCodecFlags_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef enum WisVideoCodecFlags { + * WisVideoCodecFlagsNone = 0, + * WisVideoCodecFlagsH264 = (1u << 0), + * WisVideoCodecFlagsH265 = (1u << 1), + * WisVideoCodecFlagsAV1 = (1u << 2), + * WisVideoCodecFlagsVP9 = (1u << 3), + * } WisVideoCodecFlags; + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * enum class VideoCodecFlags : uint32_t { + * None = 0, + * H264 = (1u << 0), + * H265 = (1u << 1), + * AV1 = (1u << 2), + * VP9 = (1u << 3), + * }; + * } + * ``` + * \endcond + * + * @section WisVideoCodecFlags_descr Description + *
+ * \cond WIS_GEN_DESC + * Video codec flags. Used to request and check supported codecs. + * + * Values: + * - `WisVideoCodecFlagsNone = 0`: No video is requested. The extension will not initialize. + * - `WisVideoCodecFlagsH264 = (1 << 0)`: H.264 video codec. + * - `WisVideoCodecFlagsH265 = (1 << 1)`: H.265 video codec. + * - `WisVideoCodecFlagsAV1 = (1 << 2)`: AV1 video codec. + * - `WisVideoCodecFlagsVP9 = (1 << 3)`: VP9 video codec. + * \endcond + * + * + * @section WisVideoCodecFlags_see_also See Also + *
+ * + * \cond WIS_GEN_REFS + * @see Functions: + * wisInitVideoDecodingExtension + * \endcond + */ diff --git a/docs/video/func/destroy_video_decoding_extension_function.h b/docs/video/func/destroy_video_decoding_extension_function.h new file mode 100644 index 000000000..c4787aebd --- /dev/null +++ b/docs/video/func/destroy_video_decoding_extension_function.h @@ -0,0 +1,44 @@ +/** + * @struct wisDestroyVideoDecodingExtension + * @ingroup Functions Video + * + * + * @section wisDestroyVideoDecodingExtension_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C Version: + * ```c + * // Provided by Wisdom 0.7.1. + * void wisDestroyVideoDecodingExtension(WisVideoDecodingExtension* self); + * ``` + *
+ * C Implementation Specific Version: + * ```c + * // Provided by Wisdom 0.7.1. + * void wisVKDestroyVideoDecodingExtension(WisVKVideoDecodingExtension* self); + * + * // Provided by Wisdom 0.7.1. + * void wisDX12DestroyVideoDecodingExtension(WisDX12VideoDecodingExtension* self); + * ``` + *
+ * + * \endcond + * + * @section wisDestroyVideoDecodingExtension_memb Parameters + *
+ * \cond WIS_GEN_DESC + * - **this** `self` self is a pointer to the valid WisVideoDecodingExtension instance. + * \endcond + * + * @section wisDestroyVideoDecodingExtension_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section wisDestroyVideoDecodingExtension_see_also See Also + *
+ * \cond WIS_GEN_REFS + * \endcond + */ diff --git a/docs/video/func/init_video_decoding_extension_function.h b/docs/video/func/init_video_decoding_extension_function.h new file mode 100644 index 000000000..ff3c96724 --- /dev/null +++ b/docs/video/func/init_video_decoding_extension_function.h @@ -0,0 +1,70 @@ +/** + * @struct wisInitVideoDecodingExtension + * @ingroup Functions Video + * + * + * @section wisInitVideoDecodingExtension_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C Version: + * ```c + * // Provided by Wisdom 0.7.1. + * void wisInitVideoDecodingExtension(WisVideoDecodingExtension* self, + * WisVideoCodecFlags request_codecs); + * ``` + *
+ * C Implementation Specific Version: + * ```c + * // Provided by Wisdom 0.7.1. + * void wisVKInitVideoDecodingExtension(WisVKVideoDecodingExtension* self, + * WisVideoCodecFlags request_codecs); + * + * // Provided by Wisdom 0.7.1. + * void wisDX12InitVideoDecodingExtension(WisDX12VideoDecodingExtension* self, + * WisVideoCodecFlags request_codecs); + * ``` + *
+ * + * C++ Version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * VideoDecodingExtension::VideoDecodingExtension(wis::VideoCodecFlags request_codecs) noexcept; + * } + * ``` + *
+ * C++ Implementation Specific Version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * VKVideoDecodingExtension::VKVideoDecodingExtension(wis::VideoCodecFlags request_codecs) noexcept; + * + * // Provided by Wisdom 0.7.1. + * DX12VideoDecodingExtension::DX12VideoDecodingExtension(wis::VideoCodecFlags request_codecs) noexcept; + * } + * ``` + *
+ * \endcond + * + * @section wisInitVideoDecodingExtension_memb Parameters + *
+ * \cond WIS_GEN_DESC + * - **this** `self` is a pointer to uninitialized WisVideoDecodingExtension instance memory. It will be initialized by + * this function. + * **note** The corresponding destroy function is `wisDestroyVideoDecodingExtension`. + * - `request_codecs` Bitmask of requested video codecs. The extension will attempt to initialize with support for these + * codecs. + * \endcond + * + * @section wisInitVideoDecodingExtension_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section wisInitVideoDecodingExtension_see_also See Also + *
+ * \cond WIS_GEN_REFS + * \endcond + */ diff --git a/docs/video/func/video_decoding_extension_supported_function.h b/docs/video/func/video_decoding_extension_supported_function.h new file mode 100644 index 000000000..d86aafb4c --- /dev/null +++ b/docs/video/func/video_decoding_extension_supported_function.h @@ -0,0 +1,58 @@ +/** + * @struct wisVideoDecodingExtensionSupported + * @ingroup Functions Video + * + * + * @section wisVideoDecodingExtensionSupported_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * * C Version: + * ```c + * // Provided by Wisdom 0.7.1. + * bool wisVideoDecodingExtensionSupported(WisVideoDecodingExtension* self); + * ``` + *
+ * C Implementation Specific Version: + * ```c + * // Provided by Wisdom 0.7.1. + * bool wisVKVideoDecodingExtensionSupported(WisVKVideoDecodingExtension* self); + * + * // Provided by Wisdom 0.7.1. + * bool wisDX12VideoDecodingExtensionSupported(WisDX12VideoDecodingExtension* self); + * ``` + *
+ * + * C++ Version: + * ```cpp + * namespace wis + * ``` + *
+ * C++ Implementation Specific Version: + * ```cpp + * namespace wis + * ``` + *
+ * + * \endcond + * + * @section wisVideoDecodingExtensionSupported_memb Parameters + *
+ * \cond WIS_GEN_DESC + * * - **this** `self` self is a pointer to the valid WisVideoDecodingExtension instance. + * + * - **return** true if raytracing is supported, false otherwise. + * + * \endcond + * + * @section wisVideoDecodingExtensionSupported_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section wisVideoDecodingExtensionSupported_see_also See Also + *
+ * \cond WIS_GEN_REFS + * \endcond + */ diff --git a/docs/video/handle/video_decoding_extension_handle.h b/docs/video/handle/video_decoding_extension_handle.h new file mode 100644 index 000000000..4320c425b --- /dev/null +++ b/docs/video/handle/video_decoding_extension_handle.h @@ -0,0 +1,28 @@ +/** + * @struct WisVideoDecodingExtension + * @ingroup Handles Video + * + * + * @section WisVideoDecodingExtension_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * Vulkan Version: + * ```c + * // Provided by Wisdom 0.7.1. + * WIS_DEFINE_VK_DEVICE_EXT_HANDLE(WisVKVideoDecodingExtension,4); + * ``` + * DX12 Version: + * ```c + * // Provided by Wisdom 0.7.1. + * WIS_DEFINE_DX12_DEVICE_EXT_HANDLE(WisDX12VideoDecodingExtension,2); + * ``` + * \endcond + * + * @section WisVideoDecodingExtension_see_also See Also + *
+ * \cond WIS_GEN_REFS + * @see Functions: + * wisDestroyVideoDecodingExtension, wisInitVideoDecodingExtension, wisVideoDecodingExtensionSupported + * \endcond + */ diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index b6ed90c5f..153c85d80 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -52,3 +52,4 @@ add_example_suite(backend) add_example_suite(compute_particles_c) add_example_suite(hello_triangle) add_example_suite(multisampling) +add_example_suite(video) diff --git a/examples/video/CMakeLists.txt b/examples/video/CMakeLists.txt new file mode 100644 index 000000000..e083ade8d --- /dev/null +++ b/examples/video/CMakeLists.txt @@ -0,0 +1,17 @@ +project(video-${POSTFIX}) + +set(CPP_SOURCES entry_main.cpp) + +add_executable(${PROJECT_NAME}-cpp ${CPP_SOURCES}) +target_link_libraries( + ${PROJECT_NAME}-cpp PUBLIC wis::wisdom-headers wis::wisdom-platform-headers wis::wisdom-video-headers + SDL3::SDL3 example_backend_cpp-${POSTFIX}) +set_target_properties( + ${PROJECT_NAME}-cpp PROPERTIES CXX_STANDARD 23 RUNTIME_OUTPUT_DIRECTORY + ${EXAMPLE_BIN_OUTPUT}) +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) +endif() diff --git a/examples/video/entry_main.cpp b/examples/video/entry_main.cpp new file mode 100644 index 000000000..34e10b846 --- /dev/null +++ b/examples/video/entry_main.cpp @@ -0,0 +1,120 @@ +#include +#include + +static bool check_result(wis::Result result, const char* where) +{ + if (result.status == wis::Status::Ok) { + return true; + } + + std::printf( + "%s failed: %d, platform_code: %d, error: %s\n", + where, + static_cast(result.status), + result.platform_code, + result.error ? result.error : "None" + ); + return false; +} + +class Application +{ + static void log_callback(wis::Severity severity, const char* message, uint64_t, void*) + { + const char* severity_str = "UNKNOWN"; + switch (severity) { + case wis::Severity::Verbose: + severity_str = "VERBOSE"; + break; + case wis::Severity::Info: + severity_str = "INFO"; + break; + case wis::Severity::Warning: + severity_str = "WARNING"; + break; + case wis::Severity::Error: + severity_str = "ERROR"; + break; + case wis::Severity::Fatal: + severity_str = "FATAL"; + break; + default: + break; + } + + std::printf("[%s] %s\n", severity_str, message ? message : ""); + } + +public: + Application() + : video_extension{wis::VideoCodecFlags::AV1} + , device{CreateDevice()} + {} + +private: + wis::Device CreateDevice() + { + wis::Device device{}; + wis::Result result{}; + + wis::DebugDesc debug_desc = { + .enable_debug_layer = false, + .callback = log_callback, + }; + + wis::Instance instance = wis::CreateInstance(&debug_desc, {}, result); + if (!check_result(result, "CreateInstance")) { + return device; + } + + // Query adapters + wis::AdapterQuery adapters = instance.QueryAdapters(wis::AdapterPreference::Performance, result); + if (!check_result(result, "QueryAdapters")) { + return device; + } + + // Cycle through adapters and create device + wis::DeviceExtensionHeader* extensions[] = {&video_extension}; + wis::CommandQueueDesc queue_descs[] = { + {wis::CommandQueueType::VideoDecode, wis::CommandQueuePriority::Normal}, + }; + wis::DeviceRequirements requirements{ + .queue_descs = {queue_descs}, + .extensions = {extensions}, + }; + + for (size_t i = 0; i < adapters.GetAdapterCount(); ++i) { + device = adapters.CreateDevice(i, requirements, result); + if (result.status == wis::Status::Ok) { + // Get adapter description for logging purposes + wis::AdapterDesc adapter_desc = adapters.GetAdapterDesc(i, result); + std::printf( + "Successfully created device for adapter: %s, vendor_id: %u, device_id: %u\n", + adapter_desc.description.data(), + adapter_desc.vendor_id, + adapter_desc.device_id + ); + + break; + } + } + + if (video_extension.Supported()) { + std::printf("Video decoding is supported on this device.\n"); + } else { + std::printf("Video decoding is not supported on this device.\n"); + } + + return device; + } + +private: + wis::VideoDecodingExtension video_extension; + wis::Device device; +}; + +int main() +{ + Application app; + return 0; +} diff --git a/generator/function.cpp b/generator/function.cpp index 236204eb2..b8a4f6512 100644 --- a/generator/function.cpp +++ b/generator/function.cpp @@ -388,7 +388,18 @@ std::string Generator::MakeCPPFunctionProto( } max_arg_length = std::max(max_arg_length, type_str.length()); } - + if ((func.modifier & Modifier::Construct) != 0) { + return std::format( + "{}{}{}{}({}{}){} noexcept;\n", + func_prefix, + xclass_code, + func_prefix, + std::string_view(xclass_code.begin(), xclass_code.end() - 2), + params, + post_return, + func.modifier & Modifier::Const ? " const" : "" + ); + } return std::format( "{}{} {}{}{}({}{}){} noexcept;\n", pre_decl, @@ -468,49 +479,6 @@ std::string Generator::MakeCPPFunctionImpl( std::string body = "{\n"; constexpr static std::string_view arg_prefix = ",\n "; - auto set_params = [&]() { - for (size_t i = 0; i < func.parameters.size(); ++i) { - auto& p = func.parameters[i]; - - if (p.modifier & Modifier::Span) { - body += std::format( - "reinterpret_cast<{}>({}.data()), {}.size()", - GetMemberTypeString(p, backend), - p.name, - p.name - ); - i++; // skip next parameter (the size) - if (i < func.parameters.size() - 1) { - body += arg_prefix; - } - continue; - } - - switch (GetType(p.type)) { - case TypeKind::Enum: - case TypeKind::Bitmask: - body += std::format("static_cast<{}>({})", GetMemberTypeString(p, backend), p.name); - break; - case TypeKind::None: - case TypeKind::View: - case TypeKind::Base: - body += p.name; - break; - default: - if (p.modifier & Modifier::Reference) { - body += std::format("reinterpret_cast<{}>(&{})", GetMemberTypeString(p, backend), p.name); - break; - } - body += std::format("reinterpret_cast<{}>({})", GetMemberTypeString(p, backend), p.name); - break; - } - - if (i < func.parameters.size() - 1) { - body += arg_prefix; - } - } - }; - switch (func.return_type.GetKind()) { case ReturnTypeKind::ResultAndValue: { auto ret_value_name = func.return_type.opt_name.empty() @@ -530,7 +498,7 @@ std::string Generator::MakeCPPFunctionImpl( body += arg_prefix; } - set_params(); + body += GetFunctionCallParameters(func, backend); auto ret_type = GetType(func.return_type.type); @@ -557,7 +525,7 @@ std::string Generator::MakeCPPFunctionImpl( if (func.parameters.size() > 0 && !func.this_type.empty()) { body += arg_prefix; } - set_params(); + body += GetFunctionCallParameters(func, backend); body += ");\n"; body += " return wis::Result{ static_cast(wis_result.status), wis_result.platform_code, " "wis_result.error };\n"; @@ -595,7 +563,7 @@ std::string Generator::MakeCPPFunctionImpl( if (func.parameters.size() > 0 && !func.this_type.empty()) { body += arg_prefix; } - set_params(); + body += GetFunctionCallParameters(func, backend); body += "));\n"; } break; case ReturnTypeKind::Void: { @@ -604,7 +572,7 @@ std::string Generator::MakeCPPFunctionImpl( if (func.parameters.size() > 0 && !func.this_type.empty()) { body += arg_prefix; } - set_params(); + body += GetFunctionCallParameters(func, backend); body += ");\n"; } break; default: diff --git a/generator/generator.cpp b/generator/generator.cpp index 885075a38..09f04530d 100644 --- a/generator/generator.cpp +++ b/generator/generator.cpp @@ -1931,3 +1931,49 @@ std::string Generator::GetRefs(std::string_view for_type) } return refs; } + +std::string Generator::GetFunctionCallParameters(const WisFunction& func, Backend backend) { + constexpr static std::string_view arg_prefix = ",\n "; + std::string body; + for (size_t i = 0; i < func.parameters.size(); ++i) { + auto& p = func.parameters[i]; + + if (p.modifier & Modifier::Span) { + body += std::format( + "reinterpret_cast<{}>({}.data()), {}.size()", + GetMemberTypeString(p, backend), + p.name, + p.name + ); + i++; // skip next parameter (the size) + if (i < func.parameters.size() - 1) { + body += arg_prefix; + } + continue; + } + + switch (GetType(p.type)) { + case TypeKind::Enum: + case TypeKind::Bitmask: + body += std::format("static_cast<{}>({})", GetMemberTypeString(p, backend), p.name); + break; + case TypeKind::None: + case TypeKind::View: + case TypeKind::Base: + body += p.name; + break; + default: + if (p.modifier & Modifier::Reference) { + body += std::format("reinterpret_cast<{}>(&{})", GetMemberTypeString(p, backend), p.name); + break; + } + body += std::format("reinterpret_cast<{}>({})", GetMemberTypeString(p, backend), p.name); + break; + } + + if (i < func.parameters.size() - 1) { + body += arg_prefix; + } + } + return body; +} diff --git a/generator/generator.hpp b/generator/generator.hpp index 077328f24..ed81b818c 100644 --- a/generator/generator.hpp +++ b/generator/generator.hpp @@ -151,6 +151,7 @@ class Generator void TryMakeRef(std::string_view type, std::string_view from); void TryMakeRef(std::string_view type, FunctionKey from); std::string GetRefs(std::string_view for_type); + std::string GetFunctionCallParameters(const WisFunction& func, Backend backend); static Backend ParseBackend(std::string_view backend) noexcept; static ImplOs GetImplOs(std::string_view os) noexcept; diff --git a/generator/handle.cpp b/generator/handle.cpp index 337050a28..4214ad931 100644 --- a/generator/handle.cpp +++ b/generator/handle.cpp @@ -87,6 +87,40 @@ void Generator::ParseHandles(tinyxml2::XMLElement* types) create.modifier = Modifier::Construct; create.version = version; create.doc = create_doc; + + if (auto* init = type->FirstChildElement("init")) { + if (auto* vers = init->FindAttribute("version")) { + create.version = vers->Value(); + } + + if (auto* doc = init->FindAttribute("doc")) { + create.doc = doc->Value(); + } + + // Parse parameters + for (auto* param = init->FirstChildElement("arg"); param; param = param->NextSiblingElement("arg")) { + auto& p = create.parameters.emplace_back(); + p.type = param->FindAttribute("type")->Value(); + + if (auto* name_attr = param->FindAttribute("name")) { + p.name = name_attr->Value(); + } else { + throw std::runtime_error(std::format("Function {} has a parameter with no name.", create_name)); + } + if (auto* def = param->FindAttribute("default")) { + p.default_value = def->Value(); + } + if (auto* mod = param->FindAttribute("mod")) { + p.modifier = GetModifiers(mod->Value()); + } + if (auto* doc = param->FindAttribute("doc")) { + p.doc = doc->Value(); + } + create.FilterBackend(GetTypeBackendSupport(p.type)); + TryMakeRef(p.type, create_key); + } + } + create.FilterBackend(ref.GetBackend()); type_map[iref] = TypeKind::Function; module_map[active_module_name].functions_in_order.emplace_back(create_key); @@ -196,9 +230,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(wis::in_place)\n{{\n ", impl_string, s.name); - } else { + if (s.extends == Extends::None) { ctor_decl += " using ImplType::ImplType;\n"; } std::string st_decl2 = "public:\n"; @@ -242,7 +274,49 @@ std::string Generator::MakeCPPHandle(const WisHandle& s, Backend backend, DocKin continue; } if (func_ref.modifier & Modifier::Construct) { - ctor_decl += std::format(" ::{}(GetStorage());\n }}\n", c_name); + // Build the init function parameter list for the constructor + std::string params; + std::string args = "GetStorage(), " + GetFunctionCallParameters(func_ref, backend); + bool last_was_span = false; + for (size_t i = 0; i < func_ref.parameters.size(); ++i) { + if (last_was_span) { + last_was_span = false; + continue; + } + + const auto& p = func_ref.parameters[i]; + if (p.modifier & Modifier::Span) { + last_was_span = true; + } + + std::string type_str = GetMemberTypeString(p, backend); + params += std::format("{} {}", type_str, 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 + $) + +target_link_libraries(wisdom-video-headers INTERFACE wis::wisdom-headers) +target_compile_definitions( + wisdom-video-headers INTERFACE WISDOM_VIDEO_STATIC=1) + +install( + TARGETS wisdom-video-headers + EXPORT wisdom-video-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + INCLUDES + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + +# Platform library target +if(WISDOM_BUILD_STATIC) + add_library(wisdom-video STATIC ${WISDOM_VIDEO_SOURCES}) + add_library(wis::wisdom-video ALIAS wisdom-video) + + target_link_libraries(wisdom-video PRIVATE wisdom) + target_compile_definitions(wisdom-video PUBLIC WISDOM_VIDEO_STATIC=1) + target_include_directories( + wisdom-video PUBLIC $ + $) + + set_target_properties( + wisdom-video PROPERTIES CXX_STANDARD 20 + DEBUG_POSTFIX d) + + install( + TARGETS wisdom-video + EXPORT wisdom-video-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + INCLUDES + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +endif() + +if(WISDOM_BUILD_SHARED) + add_library(wisdom-video-shared SHARED ${WISDOM_VIDEO_SOURCES}) + add_library(wis::wisdom-video-shared ALIAS wisdom-video-shared) + + target_link_libraries(wisdom-video-shared PRIVATE wisdom-shared) + target_include_directories( + wisdom-video-shared + PUBLIC $ + $) + target_compile_definitions( + wisdom-video-shared + PUBLIC WISDOM_VIDEO_SHARED_LIBRARY=1 + PRIVATE video_shared_EXPORTS=1) + + set_target_properties( + wisdom-video-shared + PROPERTIES CXX_STANDARD 20 + POSITION_INDEPENDENT_CODE ON + DEBUG_POSTFIX d) + + include(GenerateExportHeader) + generate_export_header( + wisdom-video-shared + BASE_NAME + WISDOM_VIDEO + EXPORT_MACRO_NAME + WISDOM_VIDEO_API + EXPORT_FILE_NAME + ${CMAKE_CURRENT_SOURCE_DIR}/video/generated/wisdom_exports.h + STATIC_DEFINE + WISDOM_VIDEO_STATIC + INCLUDE_GUARD_NAME + WISDOM_VIDEO_EXPORTS_H) + + install( + TARGETS wisdom-video-shared + EXPORT wisdom-video-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + INCLUDES + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +endif() + +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/video/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/video) + +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/wisdom/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/wisdom) + +install( + EXPORT wisdom-video-targets + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/wisdom + NAMESPACE wis:: + FILE wisdom-video-targets.cmake) \ No newline at end of file diff --git a/src/extensions/video/video/dx12/dx12_types.hpp b/src/extensions/video/video/dx12/dx12_types.hpp new file mode 100644 index 000000000..d29b54d0b --- /dev/null +++ b/src/extensions/video/video/dx12/dx12_types.hpp @@ -0,0 +1,30 @@ +#ifndef WIS_DX12_VIDEO_TYPES_HPP +#define WIS_DX12_VIDEO_TYPES_HPP +#ifndef __cplusplus +# error "This header requires C++" +#endif // __cplusplus + +namespace wis { +//---------------------------------------------------------------------------------------------------------------------- +namespace detail {} // namespace detail + +namespace impl { +struct DX12VideoDecodingExtensionImpl { + DX12DeviceExtensionHeader header; + WisVideoCodecFlags supported_codecs; + ID3D12Device10* device; +}; + + +} // namespace impl +} // namespace wis + +// Include implementation for header-only mode +#ifdef WISDOM_HEADER_ONLY +# if !WIS_HAS_CPP20 && !defined(WISDOM_LANG_DISABLE_CHECK) +# error "C++20 is required to build wisdom as header-only library" +# endif // !WIS_HAS_CPP20 +# include "dx12_video.cpp" + +#endif // WISDOM_HEADER_ONLY +#endif // WIS_DX12_VIDEO_TYPES_HPP diff --git a/src/extensions/video/video/dx12/dx12_video.cpp b/src/extensions/video/video/dx12/dx12_video.cpp new file mode 100644 index 000000000..35b636ee6 --- /dev/null +++ b/src/extensions/video/video/dx12/dx12_video.cpp @@ -0,0 +1,84 @@ +#ifndef WIS_DX12_VIDEO_CPP +#define WIS_DX12_VIDEO_CPP + +#include +#include
+ + + + + + + + + + + + + + From d195af83ecf1711968e120a9485382a160f983e5 Mon Sep 17 00:00:00 2001 From: Ilya Doroshenko Date: Tue, 12 May 2026 13:00:35 +0200 Subject: [PATCH 25/49] - Introduce AV1 enums and structs for profiles, levels, frame types, color config, loop filter, quantization, segmentation, tile info, CDEF, restoration, global motion, film grain, sequence header, and decode info - Add std_video_av1.xml registry and integrate into video.xml - Add VideoDecodeInputDesc variant for bitstream input - Implement DecodeFrame method for VideoDecodeCommandList (DX12/Vulkan) - Update C/C++ API headers to expose new AV1 types and functions - Implement backend support for DecodeFrame (DX12: DecodeFrame1, Vulkan: vkCmdDecodeVideoKHR) - Integrate libavif for AVIF sample handling in examples - Add AVIF demuxer and sample loading to example app - Enhance codegen for bitfields and string enums - Update documentation and references for new AV1 features --- ...d_video_a_v1_chroma_sample_position_enum.h | 56 ++ .../std_video_a_v1_color_primaries_enum.h | 80 ++ ...d_video_a_v1_frame_restoration_type_enum.h | 56 ++ .../enum/std_video_a_v1_frame_type_enum.h | 58 ++ ...std_video_a_v1_interpolation_filter_enum.h | 59 ++ docs/video/enum/std_video_a_v1_level_enum.h | 114 +++ .../std_video_a_v1_matrix_coefficients_enum.h | 89 ++ docs/video/enum/std_video_a_v1_profile_enum.h | 53 ++ .../enum/std_video_a_v1_reference_name_enum.h | 66 ++ ...video_a_v1_transfer_characteristics_enum.h | 102 +++ docs/video/enum/std_video_a_v1_tx_mode_enum.h | 53 ++ ...ecode_command_list_decode_frame_function.h | 75 ++ ...g_extension_create_command_list_function.h | 78 ++ .../handle/video_decode_command_list_handle.h | 2 +- docs/video/handle/video_decoder_handle.h | 2 +- .../struct/std_video_a_v1_c_d_e_f_struct.h | 62 ++ ...std_video_a_v1_color_config_flags_struct.h | 59 ++ .../std_video_a_v1_color_config_struct.h | 71 ++ .../std_video_a_v1_film_grain_flags_struct.h | 59 ++ .../struct/std_video_a_v1_film_grain_struct.h | 119 +++ .../std_video_a_v1_global_motion_struct.h | 50 ++ .../std_video_a_v1_loop_filter_flags_struct.h | 55 ++ .../std_video_a_v1_loop_filter_struct.h | 65 ++ .../std_video_a_v1_loop_restoration_struct.h | 50 ++ ...std_video_a_v1_quantization_flags_struct.h | 53 ++ .../std_video_a_v1_quantization_struct.h | 74 ++ .../std_video_a_v1_segmentation_struct.h | 50 ++ ..._video_a_v1_sequence_header_flags_struct.h | 104 +++ .../std_video_a_v1_sequence_header_struct.h | 84 ++ .../std_video_a_v1_tile_info_flags_struct.h | 50 ++ .../struct/std_video_a_v1_tile_info_struct.h | 74 ++ .../std_video_a_v1_timing_info_flags_struct.h | 50 ++ .../std_video_a_v1_timing_info_struct.h | 56 ++ ...eo_decode_a_v1_picture_info_flags_struct.h | 134 +++ ...td_video_decode_a_v1_picture_info_struct.h | 115 +++ ..._decode_a_v1_reference_info_flags_struct.h | 53 ++ ..._video_decode_a_v1_reference_info_struct.h | 58 ++ .../struct/video_decode_input_desc_struct.h | 92 ++ examples/CMakeLists.txt | 7 + examples/assets/avif_sample.avif | Bin 0 -> 110925 bytes examples/cmake/deps.cmake | 25 +- examples/video/CMakeLists.txt | 4 +- examples/video/avif_demux.hpp | 49 ++ examples/video/entry_main.cpp | 32 +- generator/enum.cpp | 2 +- generator/struct.cpp | 12 + generator/types.hpp | 3 +- .../video/video/dx12/dx12_video_list.cpp | 44 +- src/extensions/video/video/generated/c_api.h | 729 ++++++++++++++- .../video/video/generated/cpp_api.hpp | 830 ++++++++++++++++-- .../video/video/vulkan/vk_video_list.cpp | 48 +- src/extensions/video/wisdom/wisdom_video.h | 22 +- src/extensions/video/wisdom/wisdom_video.hpp | 16 +- src/include/wisdom/vulkan/vk_tables.hpp | 10 + xml/video.xml | 36 +- xml/video/std_video_av1.xml | 411 +++++++++ 56 files changed, 4739 insertions(+), 121 deletions(-) create mode 100644 docs/video/enum/std_video_a_v1_chroma_sample_position_enum.h create mode 100644 docs/video/enum/std_video_a_v1_color_primaries_enum.h create mode 100644 docs/video/enum/std_video_a_v1_frame_restoration_type_enum.h create mode 100644 docs/video/enum/std_video_a_v1_frame_type_enum.h create mode 100644 docs/video/enum/std_video_a_v1_interpolation_filter_enum.h create mode 100644 docs/video/enum/std_video_a_v1_level_enum.h create mode 100644 docs/video/enum/std_video_a_v1_matrix_coefficients_enum.h create mode 100644 docs/video/enum/std_video_a_v1_profile_enum.h create mode 100644 docs/video/enum/std_video_a_v1_reference_name_enum.h create mode 100644 docs/video/enum/std_video_a_v1_transfer_characteristics_enum.h create mode 100644 docs/video/enum/std_video_a_v1_tx_mode_enum.h create mode 100644 docs/video/func/video_decode_command_list_decode_frame_function.h create mode 100644 docs/video/func/video_decoding_extension_create_command_list_function.h create mode 100644 docs/video/struct/std_video_a_v1_c_d_e_f_struct.h create mode 100644 docs/video/struct/std_video_a_v1_color_config_flags_struct.h create mode 100644 docs/video/struct/std_video_a_v1_color_config_struct.h create mode 100644 docs/video/struct/std_video_a_v1_film_grain_flags_struct.h create mode 100644 docs/video/struct/std_video_a_v1_film_grain_struct.h create mode 100644 docs/video/struct/std_video_a_v1_global_motion_struct.h create mode 100644 docs/video/struct/std_video_a_v1_loop_filter_flags_struct.h create mode 100644 docs/video/struct/std_video_a_v1_loop_filter_struct.h create mode 100644 docs/video/struct/std_video_a_v1_loop_restoration_struct.h create mode 100644 docs/video/struct/std_video_a_v1_quantization_flags_struct.h create mode 100644 docs/video/struct/std_video_a_v1_quantization_struct.h create mode 100644 docs/video/struct/std_video_a_v1_segmentation_struct.h create mode 100644 docs/video/struct/std_video_a_v1_sequence_header_flags_struct.h create mode 100644 docs/video/struct/std_video_a_v1_sequence_header_struct.h create mode 100644 docs/video/struct/std_video_a_v1_tile_info_flags_struct.h create mode 100644 docs/video/struct/std_video_a_v1_tile_info_struct.h create mode 100644 docs/video/struct/std_video_a_v1_timing_info_flags_struct.h create mode 100644 docs/video/struct/std_video_a_v1_timing_info_struct.h create mode 100644 docs/video/struct/std_video_decode_a_v1_picture_info_flags_struct.h create mode 100644 docs/video/struct/std_video_decode_a_v1_picture_info_struct.h create mode 100644 docs/video/struct/std_video_decode_a_v1_reference_info_flags_struct.h create mode 100644 docs/video/struct/std_video_decode_a_v1_reference_info_struct.h create mode 100644 docs/video/struct/video_decode_input_desc_struct.h create mode 100644 examples/assets/avif_sample.avif create mode 100644 examples/video/avif_demux.hpp create mode 100644 xml/video/std_video_av1.xml diff --git a/docs/video/enum/std_video_a_v1_chroma_sample_position_enum.h b/docs/video/enum/std_video_a_v1_chroma_sample_position_enum.h new file mode 100644 index 000000000..a028ecdbf --- /dev/null +++ b/docs/video/enum/std_video_a_v1_chroma_sample_position_enum.h @@ -0,0 +1,56 @@ +/** + * @struct WisStdVideoAV1ChromaSamplePosition WisStdVideoAV1ChromaSamplePosition + * @ingroup Enumerations Video + * + * @section WisStdVideoAV1ChromaSamplePosition_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef enum WisStdVideoAV1ChromaSamplePosition { + * WisStdVideoAV1ChromaSamplePositionUnknown = 0, + * WisStdVideoAV1ChromaSamplePositionVertical = 1, + * WisStdVideoAV1ChromaSamplePositionColocated = 2, + * WisStdVideoAV1ChromaSamplePositionReserved = 3, + * WisStdVideoAV1ChromaSamplePositionInvalid = 0x7FFFFFFF, + * } WisStdVideoAV1ChromaSamplePosition; + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * enum class StdVideoAV1ChromaSamplePosition { + * Unknown = 0, + * Vertical = 1, + * Colocated = 2, + * Reserved = 3, + * Invalid = 0x7FFFFFFF, + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoAV1ChromaSamplePosition_descr Description + *
+ * \cond WIS_GEN_DESC + * AV1 chroma sample position (AV1 Bitstream Specification Section 6.4.2). + * + * Values: + * - `WisStdVideoAV1ChromaSamplePositionUnknown = 0`: Unknown chroma sample position. + * - `WisStdVideoAV1ChromaSamplePositionVertical = 1`: Horizontally co-located with luma, vertically shifted by 0.5. + * - `WisStdVideoAV1ChromaSamplePositionColocated = 2`: Co-located with luma. + * - `WisStdVideoAV1ChromaSamplePositionReserved = 3`: + * - `WisStdVideoAV1ChromaSamplePositionInvalid = 0x7FFFFFFF`: + * \endcond + * + * + * @section WisStdVideoAV1ChromaSamplePosition_see_also See Also + *
+ * + * \cond WIS_GEN_REFS + * @see Structs: + * WisStdVideoAV1ColorConfig + * \endcond + */ diff --git a/docs/video/enum/std_video_a_v1_color_primaries_enum.h b/docs/video/enum/std_video_a_v1_color_primaries_enum.h new file mode 100644 index 000000000..0bdabbae6 --- /dev/null +++ b/docs/video/enum/std_video_a_v1_color_primaries_enum.h @@ -0,0 +1,80 @@ +/** + * @struct WisStdVideoAV1ColorPrimaries WisStdVideoAV1ColorPrimaries + * @ingroup Enumerations Video + * + * @section WisStdVideoAV1ColorPrimaries_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef enum WisStdVideoAV1ColorPrimaries { + * WisStdVideoAV1ColorPrimariesBt709 = 1, + * WisStdVideoAV1ColorPrimariesUnspecified = 2, + * WisStdVideoAV1ColorPrimariesBt470M = 4, + * WisStdVideoAV1ColorPrimariesBt470BG = 5, + * WisStdVideoAV1ColorPrimariesBt601 = 6, + * WisStdVideoAV1ColorPrimariesSmpte240 = 7, + * WisStdVideoAV1ColorPrimariesGenericFilm = 8, + * WisStdVideoAV1ColorPrimariesBt2020 = 9, + * WisStdVideoAV1ColorPrimariesXyz = 10, + * WisStdVideoAV1ColorPrimariesSmpte431 = 11, + * WisStdVideoAV1ColorPrimariesSmpte432 = 12, + * WisStdVideoAV1ColorPrimariesEbu3213 = 22, + * WisStdVideoAV1ColorPrimariesInvalid = 0x7FFFFFFF, + * } WisStdVideoAV1ColorPrimaries; + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * enum class StdVideoAV1ColorPrimaries { + * Bt709 = 1, + * Unspecified = 2, + * Bt470M = 4, + * Bt470BG = 5, + * Bt601 = 6, + * Smpte240 = 7, + * GenericFilm = 8, + * Bt2020 = 9, + * Xyz = 10, + * Smpte431 = 11, + * Smpte432 = 12, + * Ebu3213 = 22, + * Invalid = 0x7FFFFFFF, + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoAV1ColorPrimaries_descr Description + *
+ * \cond WIS_GEN_DESC + * AV1 color primaries mapping to ISO/IEC 23000-2 / CICP. + * + * Values: + * - `WisStdVideoAV1ColorPrimariesBt709 = 1`: Rec. ITU-R BT.709-6. + * - `WisStdVideoAV1ColorPrimariesUnspecified = 2`: Image characteristics are unknown or unspecified. + * - `WisStdVideoAV1ColorPrimariesBt470M = 4`: Rec. ITU-R BT.470-6 System M (historical). + * - `WisStdVideoAV1ColorPrimariesBt470BG = 5`: Rec. ITU-R BT.470-6 System B, G (historical). + * - `WisStdVideoAV1ColorPrimariesBt601 = 6`: Rec. ITU-R BT.601-7 525. + * - `WisStdVideoAV1ColorPrimariesSmpte240 = 7`: SMPTE 240M. + * - `WisStdVideoAV1ColorPrimariesGenericFilm = 8`: Generic film (color filters using Illuminant C). + * - `WisStdVideoAV1ColorPrimariesBt2020 = 9`: Rec. ITU-R BT.2020-2. + * - `WisStdVideoAV1ColorPrimariesXyz = 10`: SMPTE ST 428-1. + * - `WisStdVideoAV1ColorPrimariesSmpte431 = 11`: SMPTE RP 431-2. + * - `WisStdVideoAV1ColorPrimariesSmpte432 = 12`: SMPTE EG 432-1. + * - `WisStdVideoAV1ColorPrimariesEbu3213 = 22`: EBU Tech. 3213-E. + * - `WisStdVideoAV1ColorPrimariesInvalid = 0x7FFFFFFF`: Invalid. + * \endcond + * + * + * @section WisStdVideoAV1ColorPrimaries_see_also See Also + *
+ * + * \cond WIS_GEN_REFS + * @see Structs: + * WisStdVideoAV1ColorConfig + * \endcond + */ diff --git a/docs/video/enum/std_video_a_v1_frame_restoration_type_enum.h b/docs/video/enum/std_video_a_v1_frame_restoration_type_enum.h new file mode 100644 index 000000000..cd222c0fb --- /dev/null +++ b/docs/video/enum/std_video_a_v1_frame_restoration_type_enum.h @@ -0,0 +1,56 @@ +/** + * @struct WisStdVideoAV1FrameRestorationType WisStdVideoAV1FrameRestorationType + * @ingroup Enumerations Video + * + * @section WisStdVideoAV1FrameRestorationType_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef enum WisStdVideoAV1FrameRestorationType { + * WisStdVideoAV1FrameRestorationTypeNone = 0, + * WisStdVideoAV1FrameRestorationTypeWiener = 1, + * WisStdVideoAV1FrameRestorationTypeSgrproj = 2, + * WisStdVideoAV1FrameRestorationTypeSwitchable = 3, + * WisStdVideoAV1FrameRestorationTypeInvalid = 0x7FFFFFFF, + * } WisStdVideoAV1FrameRestorationType; + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * enum class StdVideoAV1FrameRestorationType { + * None = 0, + * Wiener = 1, + * Sgrproj = 2, + * Switchable = 3, + * Invalid = 0x7FFFFFFF, + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoAV1FrameRestorationType_descr Description + *
+ * \cond WIS_GEN_DESC + * Loop restoration types (AV1 Bitstream Specification Section 6.10.15). + * + * Values: + * - `WisStdVideoAV1FrameRestorationTypeNone = 0`: No loop restoration. + * - `WisStdVideoAV1FrameRestorationTypeWiener = 1`: Wiener filter loop restoration. + * - `WisStdVideoAV1FrameRestorationTypeSgrproj = 2`: Self-guided filter loop restoration. + * - `WisStdVideoAV1FrameRestorationTypeSwitchable = 3`: Switchable between Wiener and Sgrproj. + * - `WisStdVideoAV1FrameRestorationTypeInvalid = 0x7FFFFFFF`: Invalid restoration type. + * \endcond + * + * + * @section WisStdVideoAV1FrameRestorationType_see_also See Also + *
+ * + * \cond WIS_GEN_REFS + * @see Structs: + * WisStdVideoAV1LoopRestoration + * \endcond + */ diff --git a/docs/video/enum/std_video_a_v1_frame_type_enum.h b/docs/video/enum/std_video_a_v1_frame_type_enum.h new file mode 100644 index 000000000..984cce70a --- /dev/null +++ b/docs/video/enum/std_video_a_v1_frame_type_enum.h @@ -0,0 +1,58 @@ +/** + * @struct WisStdVideoAV1FrameType WisStdVideoAV1FrameType + * @ingroup Enumerations Video + * + * @section WisStdVideoAV1FrameType_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef enum WisStdVideoAV1FrameType { + * WisStdVideoAV1FrameTypeKey = 0, + * WisStdVideoAV1FrameTypeInter = 1, + * WisStdVideoAV1FrameTypeIntraOnly = 2, + * WisStdVideoAV1FrameTypeSwitch = 3, + * WisStdVideoAV1FrameTypeInvalid = 0x7FFFFFFF, + * } WisStdVideoAV1FrameType; + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * enum class StdVideoAV1FrameType { + * Key = 0, + * Inter = 1, + * IntraOnly = 2, + * Switch = 3, + * Invalid = 0x7FFFFFFF, + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoAV1FrameType_descr Description + *
+ * \cond WIS_GEN_DESC + * Specifies the AV1 frame type (AV1 Bitstream Specification Section 6.8.2). + * + * Values: + * - `WisStdVideoAV1FrameTypeKey = 0`: A key frame contains only intra-coded blocks and is fully decipherable. + * - `WisStdVideoAV1FrameTypeInter = 1`: An inter frame @wis_may contain intra-coded blocks and inter-coded blocks. + * - `WisStdVideoAV1FrameTypeIntraOnly = 2`: An intra-only frame contains only intra-coded blocks but acts otherwise as + * an inter frame. + * - `WisStdVideoAV1FrameTypeSwitch = 3`: A switch frame is an inter frame that can be used as a switching point for + * adaptive streaming. + * - `WisStdVideoAV1FrameTypeInvalid = 0x7FFFFFFF`: Invalid frame type. + * \endcond + * + * + * @section WisStdVideoAV1FrameType_see_also See Also + *
+ * + * \cond WIS_GEN_REFS + * @see Structs: + * WisStdVideoDecodeAV1PictureInfo + * \endcond + */ diff --git a/docs/video/enum/std_video_a_v1_interpolation_filter_enum.h b/docs/video/enum/std_video_a_v1_interpolation_filter_enum.h new file mode 100644 index 000000000..3efb282e3 --- /dev/null +++ b/docs/video/enum/std_video_a_v1_interpolation_filter_enum.h @@ -0,0 +1,59 @@ +/** + * @struct WisStdVideoAV1InterpolationFilter WisStdVideoAV1InterpolationFilter + * @ingroup Enumerations Video + * + * @section WisStdVideoAV1InterpolationFilter_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef enum WisStdVideoAV1InterpolationFilter { + * WisStdVideoAV1InterpolationFilterEighttap = 0, + * WisStdVideoAV1InterpolationFilterEighttapSmooth = 1, + * WisStdVideoAV1InterpolationFilterEighttapSharp = 2, + * WisStdVideoAV1InterpolationFilterBilinear = 3, + * WisStdVideoAV1InterpolationFilterSwitchable = 4, + * WisStdVideoAV1InterpolationFilterInvalid = 0x7FFFFFFF, + * } WisStdVideoAV1InterpolationFilter; + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * enum class StdVideoAV1InterpolationFilter { + * Eighttap = 0, + * EighttapSmooth = 1, + * EighttapSharp = 2, + * Bilinear = 3, + * Switchable = 4, + * Invalid = 0x7FFFFFFF, + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoAV1InterpolationFilter_descr Description + *
+ * \cond WIS_GEN_DESC + * Interpolation filter types (AV1 Bitstream Specification Section 6.8.9). + * + * Values: + * - `WisStdVideoAV1InterpolationFilterEighttap = 0`: Eight-tap filter. + * - `WisStdVideoAV1InterpolationFilterEighttapSmooth = 1`: Eight-tap smooth filter. + * - `WisStdVideoAV1InterpolationFilterEighttapSharp = 2`: Eight-tap sharp filter. + * - `WisStdVideoAV1InterpolationFilterBilinear = 3`: Bilinear filter. + * - `WisStdVideoAV1InterpolationFilterSwitchable = 4`: Switchable interpolation filter at the block level. + * - `WisStdVideoAV1InterpolationFilterInvalid = 0x7FFFFFFF`: Invalid filter. + * \endcond + * + * + * @section WisStdVideoAV1InterpolationFilter_see_also See Also + *
+ * + * \cond WIS_GEN_REFS + * @see Structs: + * WisStdVideoDecodeAV1PictureInfo + * \endcond + */ diff --git a/docs/video/enum/std_video_a_v1_level_enum.h b/docs/video/enum/std_video_a_v1_level_enum.h new file mode 100644 index 000000000..392dee36a --- /dev/null +++ b/docs/video/enum/std_video_a_v1_level_enum.h @@ -0,0 +1,114 @@ +/** + * @struct WisStdVideoAV1Level WisStdVideoAV1Level + * @ingroup Enumerations Video + * + * @section WisStdVideoAV1Level_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef enum WisStdVideoAV1Level { + * WisStdVideoAV1LevelLevel2_0 = 0, + * WisStdVideoAV1LevelLevel2_1 = 1, + * WisStdVideoAV1LevelLevel2_2 = 2, + * WisStdVideoAV1LevelLevel2_3 = 3, + * WisStdVideoAV1LevelLevel3_0 = 4, + * WisStdVideoAV1LevelLevel3_1 = 5, + * WisStdVideoAV1LevelLevel3_2 = 6, + * WisStdVideoAV1LevelLevel3_3 = 7, + * WisStdVideoAV1LevelLevel4_0 = 8, + * WisStdVideoAV1LevelLevel4_1 = 9, + * WisStdVideoAV1LevelLevel4_2 = 10, + * WisStdVideoAV1LevelLevel4_3 = 11, + * WisStdVideoAV1LevelLevel5_0 = 12, + * WisStdVideoAV1LevelLevel5_1 = 13, + * WisStdVideoAV1LevelLevel5_2 = 14, + * WisStdVideoAV1LevelLevel5_3 = 15, + * WisStdVideoAV1LevelLevel6_0 = 16, + * WisStdVideoAV1LevelLevel6_1 = 17, + * WisStdVideoAV1LevelLevel6_2 = 18, + * WisStdVideoAV1LevelLevel6_3 = 19, + * WisStdVideoAV1LevelLevel7_0 = 20, + * WisStdVideoAV1LevelLevel7_1 = 21, + * WisStdVideoAV1LevelLevel7_2 = 22, + * WisStdVideoAV1LevelLevel7_3 = 23, + * WisStdVideoAV1LevelInvalid = 0x7FFFFFFF, + * } WisStdVideoAV1Level; + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * enum class StdVideoAV1Level { + * Level2_0 = 0, + * Level2_1 = 1, + * Level2_2 = 2, + * Level2_3 = 3, + * Level3_0 = 4, + * Level3_1 = 5, + * Level3_2 = 6, + * Level3_3 = 7, + * Level4_0 = 8, + * Level4_1 = 9, + * Level4_2 = 10, + * Level4_3 = 11, + * Level5_0 = 12, + * Level5_1 = 13, + * Level5_2 = 14, + * Level5_3 = 15, + * Level6_0 = 16, + * Level6_1 = 17, + * Level6_2 = 18, + * Level6_3 = 19, + * Level7_0 = 20, + * Level7_1 = 21, + * Level7_2 = 22, + * Level7_3 = 23, + * Invalid = 0x7FFFFFFF, + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoAV1Level_descr Description + *
+ * \cond WIS_GEN_DESC + * AV1 levels as defined in the AV1 Bitstream Specification Annex A.3. + * + * Values: + * - `WisStdVideoAV1LevelLevel2_0 = 0`: Level 2.0 + * - `WisStdVideoAV1LevelLevel2_1 = 1`: Level 2.1 + * - `WisStdVideoAV1LevelLevel2_2 = 2`: Level 2.2 + * - `WisStdVideoAV1LevelLevel2_3 = 3`: Level 2.3 + * - `WisStdVideoAV1LevelLevel3_0 = 4`: Level 3.0 + * - `WisStdVideoAV1LevelLevel3_1 = 5`: Level 3.1 + * - `WisStdVideoAV1LevelLevel3_2 = 6`: Level 3.2 + * - `WisStdVideoAV1LevelLevel3_3 = 7`: Level 3.3 + * - `WisStdVideoAV1LevelLevel4_0 = 8`: Level 4.0 + * - `WisStdVideoAV1LevelLevel4_1 = 9`: Level 4.1 + * - `WisStdVideoAV1LevelLevel4_2 = 10`: Level 4.2 + * - `WisStdVideoAV1LevelLevel4_3 = 11`: Level 4.3 + * - `WisStdVideoAV1LevelLevel5_0 = 12`: Level 5.0 + * - `WisStdVideoAV1LevelLevel5_1 = 13`: Level 5.1 + * - `WisStdVideoAV1LevelLevel5_2 = 14`: Level 5.2 + * - `WisStdVideoAV1LevelLevel5_3 = 15`: Level 5.3 + * - `WisStdVideoAV1LevelLevel6_0 = 16`: Level 6.0 + * - `WisStdVideoAV1LevelLevel6_1 = 17`: Level 6.1 + * - `WisStdVideoAV1LevelLevel6_2 = 18`: Level 6.2 + * - `WisStdVideoAV1LevelLevel6_3 = 19`: Level 6.3 + * - `WisStdVideoAV1LevelLevel7_0 = 20`: Level 7.0 + * - `WisStdVideoAV1LevelLevel7_1 = 21`: Level 7.1 + * - `WisStdVideoAV1LevelLevel7_2 = 22`: Level 7.2 + * - `WisStdVideoAV1LevelLevel7_3 = 23`: Level 7.3 + * - `WisStdVideoAV1LevelInvalid = 0x7FFFFFFF`: Invalid level. + * \endcond + * + * + * @section WisStdVideoAV1Level_see_also See Also + *
+ * + * \cond WIS_GEN_REFS + * \endcond + */ diff --git a/docs/video/enum/std_video_a_v1_matrix_coefficients_enum.h b/docs/video/enum/std_video_a_v1_matrix_coefficients_enum.h new file mode 100644 index 000000000..bdcc0b151 --- /dev/null +++ b/docs/video/enum/std_video_a_v1_matrix_coefficients_enum.h @@ -0,0 +1,89 @@ +/** + * @struct WisStdVideoAV1MatrixCoefficients WisStdVideoAV1MatrixCoefficients + * @ingroup Enumerations Video + * + * @section WisStdVideoAV1MatrixCoefficients_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef enum WisStdVideoAV1MatrixCoefficients { + * WisStdVideoAV1MatrixCoefficientsIdentity = 0, + * WisStdVideoAV1MatrixCoefficientsBt709 = 1, + * WisStdVideoAV1MatrixCoefficientsUnspecified = 2, + * WisStdVideoAV1MatrixCoefficientsReserved3 = 3, + * WisStdVideoAV1MatrixCoefficientsFcc = 4, + * WisStdVideoAV1MatrixCoefficientsBt470BG = 5, + * WisStdVideoAV1MatrixCoefficientsBt601 = 6, + * WisStdVideoAV1MatrixCoefficientsSmpte240 = 7, + * WisStdVideoAV1MatrixCoefficientsSmpteYcgco = 8, + * WisStdVideoAV1MatrixCoefficientsBt2020Ncl = 9, + * WisStdVideoAV1MatrixCoefficientsBt2020Cl = 10, + * WisStdVideoAV1MatrixCoefficientsSmpte2085 = 11, + * WisStdVideoAV1MatrixCoefficientsChromatNcl = 12, + * WisStdVideoAV1MatrixCoefficientsChromatCl = 13, + * WisStdVideoAV1MatrixCoefficientsIctcp = 14, + * WisStdVideoAV1MatrixCoefficientsInvalid = 0x7FFFFFFF, + * } WisStdVideoAV1MatrixCoefficients; + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * enum class StdVideoAV1MatrixCoefficients { + * Identity = 0, + * Bt709 = 1, + * Unspecified = 2, + * Reserved3 = 3, + * Fcc = 4, + * Bt470BG = 5, + * Bt601 = 6, + * Smpte240 = 7, + * SmpteYcgco = 8, + * Bt2020Ncl = 9, + * Bt2020Cl = 10, + * Smpte2085 = 11, + * ChromatNcl = 12, + * ChromatCl = 13, + * Ictcp = 14, + * Invalid = 0x7FFFFFFF, + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoAV1MatrixCoefficients_descr Description + *
+ * \cond WIS_GEN_DESC + * AV1 matrix coefficients mapping to CICP. + * + * Values: + * - `WisStdVideoAV1MatrixCoefficientsIdentity = 0`: Identity matrix. + * - `WisStdVideoAV1MatrixCoefficientsBt709 = 1`: Rec. ITU-R BT.709-6. + * - `WisStdVideoAV1MatrixCoefficientsUnspecified = 2`: Matrix characteristics are unspecified. + * - `WisStdVideoAV1MatrixCoefficientsReserved3 = 3`: + * - `WisStdVideoAV1MatrixCoefficientsFcc = 4`: FCC Title 47 Code of Federal Regulations. + * - `WisStdVideoAV1MatrixCoefficientsBt470BG = 5`: Rec. ITU-R BT.470-6 System B, G (historical). + * - `WisStdVideoAV1MatrixCoefficientsBt601 = 6`: Rec. ITU-R BT.601-7. + * - `WisStdVideoAV1MatrixCoefficientsSmpte240 = 7`: SMPTE 240M. + * - `WisStdVideoAV1MatrixCoefficientsSmpteYcgco = 8`: YCgCo. + * - `WisStdVideoAV1MatrixCoefficientsBt2020Ncl = 9`: Bt2020 non-constant luminance. + * - `WisStdVideoAV1MatrixCoefficientsBt2020Cl = 10`: Bt2020 constant luminance. + * - `WisStdVideoAV1MatrixCoefficientsSmpte2085 = 11`: SMPTE ST 2085. + * - `WisStdVideoAV1MatrixCoefficientsChromatNcl = 12`: Chromaticity-derived non-constant luminance. + * - `WisStdVideoAV1MatrixCoefficientsChromatCl = 13`: Chromaticity-derived constant luminance. + * - `WisStdVideoAV1MatrixCoefficientsIctcp = 14`: Rec. ITU-R BT.2100-0 ICtCp. + * - `WisStdVideoAV1MatrixCoefficientsInvalid = 0x7FFFFFFF`: + * \endcond + * + * + * @section WisStdVideoAV1MatrixCoefficients_see_also See Also + *
+ * + * \cond WIS_GEN_REFS + * @see Structs: + * WisStdVideoAV1ColorConfig + * \endcond + */ diff --git a/docs/video/enum/std_video_a_v1_profile_enum.h b/docs/video/enum/std_video_a_v1_profile_enum.h new file mode 100644 index 000000000..bc60e6109 --- /dev/null +++ b/docs/video/enum/std_video_a_v1_profile_enum.h @@ -0,0 +1,53 @@ +/** + * @struct WisStdVideoAV1Profile WisStdVideoAV1Profile + * @ingroup Enumerations Video + * + * @section WisStdVideoAV1Profile_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef enum WisStdVideoAV1Profile { + * WisStdVideoAV1ProfileMain = 0, + * WisStdVideoAV1ProfileHigh = 1, + * WisStdVideoAV1ProfileProfessional = 2, + * WisStdVideoAV1ProfileInvalid = 0x7FFFFFFF, + * } WisStdVideoAV1Profile; + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * enum class StdVideoAV1Profile { + * Main = 0, + * High = 1, + * Professional = 2, + * Invalid = 0x7FFFFFFF, + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoAV1Profile_descr Description + *
+ * \cond WIS_GEN_DESC + * AV1 profiles as defined in the AV1 Bitstream Specification section 6.4.1. + * + * Values: + * - `WisStdVideoAV1ProfileMain = 0`: Main profile (8-bit or 10-bit color, 4:0:0 or 4:2:0). + * - `WisStdVideoAV1ProfileHigh = 1`: High profile (adds 8-bit or 10-bit 4:4:4). + * - `WisStdVideoAV1ProfileProfessional = 2`: Professional profile (adds 12-bit color, and 4:2:2). + * - `WisStdVideoAV1ProfileInvalid = 0x7FFFFFFF`: Invalid profile. + * \endcond + * + * + * @section WisStdVideoAV1Profile_see_also See Also + *
+ * + * \cond WIS_GEN_REFS + * @see Structs: + * WisStdVideoAV1SequenceHeader + * \endcond + */ diff --git a/docs/video/enum/std_video_a_v1_reference_name_enum.h b/docs/video/enum/std_video_a_v1_reference_name_enum.h new file mode 100644 index 000000000..c7663af61 --- /dev/null +++ b/docs/video/enum/std_video_a_v1_reference_name_enum.h @@ -0,0 +1,66 @@ +/** + * @struct WisStdVideoAV1ReferenceName WisStdVideoAV1ReferenceName + * @ingroup Enumerations Video + * + * @section WisStdVideoAV1ReferenceName_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef enum WisStdVideoAV1ReferenceName { + * WisStdVideoAV1ReferenceNameIntraFrame = 0, + * WisStdVideoAV1ReferenceNameLastFrame = 1, + * WisStdVideoAV1ReferenceNameLast2Frame = 2, + * WisStdVideoAV1ReferenceNameLast3Frame = 3, + * WisStdVideoAV1ReferenceNameGoldenFrame = 4, + * WisStdVideoAV1ReferenceNameBwdrefFrame = 5, + * WisStdVideoAV1ReferenceNameAltref2Frame = 6, + * WisStdVideoAV1ReferenceNameAltrefFrame = 7, + * WisStdVideoAV1ReferenceNameInvalid = 0x7FFFFFFF, + * } WisStdVideoAV1ReferenceName; + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * enum class StdVideoAV1ReferenceName { + * IntraFrame = 0, + * LastFrame = 1, + * Last2Frame = 2, + * Last3Frame = 3, + * GoldenFrame = 4, + * BwdrefFrame = 5, + * Altref2Frame = 6, + * AltrefFrame = 7, + * Invalid = 0x7FFFFFFF, + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoAV1ReferenceName_descr Description + *
+ * \cond WIS_GEN_DESC + * Names of the reference frames used in AV1 (AV1 Bitstream Specification Section 6.1). + * + * Values: + * - `WisStdVideoAV1ReferenceNameIntraFrame = 0`: Intra frame reference. + * - `WisStdVideoAV1ReferenceNameLastFrame = 1`: LAST_FRAME (1). + * - `WisStdVideoAV1ReferenceNameLast2Frame = 2`: LAST2_FRAME (2). + * - `WisStdVideoAV1ReferenceNameLast3Frame = 3`: LAST3_FRAME (3). + * - `WisStdVideoAV1ReferenceNameGoldenFrame = 4`: GOLDEN_FRAME (4). + * - `WisStdVideoAV1ReferenceNameBwdrefFrame = 5`: BWDREF_FRAME (5). + * - `WisStdVideoAV1ReferenceNameAltref2Frame = 6`: ALTREF2_FRAME (6). + * - `WisStdVideoAV1ReferenceNameAltrefFrame = 7`: ALTREF_FRAME (7). + * - `WisStdVideoAV1ReferenceNameInvalid = 0x7FFFFFFF`: Invalid reference name. + * \endcond + * + * + * @section WisStdVideoAV1ReferenceName_see_also See Also + *
+ * + * \cond WIS_GEN_REFS + * \endcond + */ diff --git a/docs/video/enum/std_video_a_v1_transfer_characteristics_enum.h b/docs/video/enum/std_video_a_v1_transfer_characteristics_enum.h new file mode 100644 index 000000000..d8ba510c5 --- /dev/null +++ b/docs/video/enum/std_video_a_v1_transfer_characteristics_enum.h @@ -0,0 +1,102 @@ +/** + * @struct WisStdVideoAV1TransferCharacteristics WisStdVideoAV1TransferCharacteristics + * @ingroup Enumerations Video + * + * @section WisStdVideoAV1TransferCharacteristics_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef enum WisStdVideoAV1TransferCharacteristics { + * WisStdVideoAV1TransferCharacteristicsReserved0 = 0, + * WisStdVideoAV1TransferCharacteristicsBt709 = 1, + * WisStdVideoAV1TransferCharacteristicsUnspecified = 2, + * WisStdVideoAV1TransferCharacteristicsReserved3 = 3, + * WisStdVideoAV1TransferCharacteristicsBt470M = 4, + * WisStdVideoAV1TransferCharacteristicsBt470BG = 5, + * WisStdVideoAV1TransferCharacteristicsBt601 = 6, + * WisStdVideoAV1TransferCharacteristicsSmpte240 = 7, + * WisStdVideoAV1TransferCharacteristicsLinear = 8, + * WisStdVideoAV1TransferCharacteristicsLog100 = 9, + * WisStdVideoAV1TransferCharacteristicsLog100Sqrt10 = 10, + * WisStdVideoAV1TransferCharacteristicsIec61966 = 11, + * WisStdVideoAV1TransferCharacteristicsBt1361 = 12, + * WisStdVideoAV1TransferCharacteristicsSrgb = 13, + * WisStdVideoAV1TransferCharacteristicsBt2020_10Bit = 14, + * WisStdVideoAV1TransferCharacteristicsBt2020_12Bit = 15, + * WisStdVideoAV1TransferCharacteristicsSmpte2084 = 16, + * WisStdVideoAV1TransferCharacteristicsSmpte428 = 17, + * WisStdVideoAV1TransferCharacteristicsHlg = 18, + * WisStdVideoAV1TransferCharacteristicsInvalid = 0x7FFFFFFF, + * } WisStdVideoAV1TransferCharacteristics; + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * enum class StdVideoAV1TransferCharacteristics { + * Reserved0 = 0, + * Bt709 = 1, + * Unspecified = 2, + * Reserved3 = 3, + * Bt470M = 4, + * Bt470BG = 5, + * Bt601 = 6, + * Smpte240 = 7, + * Linear = 8, + * Log100 = 9, + * Log100Sqrt10 = 10, + * Iec61966 = 11, + * Bt1361 = 12, + * Srgb = 13, + * Bt2020_10Bit = 14, + * Bt2020_12Bit = 15, + * Smpte2084 = 16, + * Smpte428 = 17, + * Hlg = 18, + * Invalid = 0x7FFFFFFF, + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoAV1TransferCharacteristics_descr Description + *
+ * \cond WIS_GEN_DESC + * Transfer characteristics for AV1. + * + * Values: + * - `WisStdVideoAV1TransferCharacteristicsReserved0 = 0`: + * - `WisStdVideoAV1TransferCharacteristicsBt709 = 1`: Rec. ITU-R BT.709-6. + * - `WisStdVideoAV1TransferCharacteristicsUnspecified = 2`: Unspecified. + * - `WisStdVideoAV1TransferCharacteristicsReserved3 = 3`: + * - `WisStdVideoAV1TransferCharacteristicsBt470M = 4`: Rec. ITU-R BT.470-6 System M (historical). + * - `WisStdVideoAV1TransferCharacteristicsBt470BG = 5`: Rec. ITU-R BT.470-6 System B, G (historical). + * - `WisStdVideoAV1TransferCharacteristicsBt601 = 6`: Rec. ITU-R BT.601-7. + * - `WisStdVideoAV1TransferCharacteristicsSmpte240 = 7`: SMPTE 240M. + * - `WisStdVideoAV1TransferCharacteristicsLinear = 8`: Linear transfer characteristics. + * - `WisStdVideoAV1TransferCharacteristicsLog100 = 9`: Logarithmic transfer characteristic (100:1 range). + * - `WisStdVideoAV1TransferCharacteristicsLog100Sqrt10 = 10`: Logarithmic transfer characteristic (100 * Sqrt(10) : 1 + * range). + * - `WisStdVideoAV1TransferCharacteristicsIec61966 = 11`: IEC 61966-2-4. + * - `WisStdVideoAV1TransferCharacteristicsBt1361 = 12`: Rec. ITU-R BT.1361-0 extended colour gamut system (historical). + * - `WisStdVideoAV1TransferCharacteristicsSrgb = 13`: IEC 61966-2-1 sRGB. + * - `WisStdVideoAV1TransferCharacteristicsBt2020_10Bit = 14`: Rec. ITU-R BT.2020-2 (10-bit system). + * - `WisStdVideoAV1TransferCharacteristicsBt2020_12Bit = 15`: Rec. ITU-R BT.2020-2 (12-bit system). + * - `WisStdVideoAV1TransferCharacteristicsSmpte2084 = 16`: SMPTE ST 2084 (PQ). + * - `WisStdVideoAV1TransferCharacteristicsSmpte428 = 17`: SMPTE ST 428-1. + * - `WisStdVideoAV1TransferCharacteristicsHlg = 18`: ARIB STD-B67 (HLG). + * - `WisStdVideoAV1TransferCharacteristicsInvalid = 0x7FFFFFFF`: + * \endcond + * + * + * @section WisStdVideoAV1TransferCharacteristics_see_also See Also + *
+ * + * \cond WIS_GEN_REFS + * @see Structs: + * WisStdVideoAV1ColorConfig + * \endcond + */ diff --git a/docs/video/enum/std_video_a_v1_tx_mode_enum.h b/docs/video/enum/std_video_a_v1_tx_mode_enum.h new file mode 100644 index 000000000..0c7830efe --- /dev/null +++ b/docs/video/enum/std_video_a_v1_tx_mode_enum.h @@ -0,0 +1,53 @@ +/** + * @struct WisStdVideoAV1TxMode WisStdVideoAV1TxMode + * @ingroup Enumerations Video + * + * @section WisStdVideoAV1TxMode_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef enum WisStdVideoAV1TxMode { + * WisStdVideoAV1TxModeOnly4x4 = 0, + * WisStdVideoAV1TxModeLargest = 1, + * WisStdVideoAV1TxModeSelect = 2, + * WisStdVideoAV1TxModeInvalid = 0x7FFFFFFF, + * } WisStdVideoAV1TxMode; + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * enum class StdVideoAV1TxMode { + * Only4x4 = 0, + * Largest = 1, + * Select = 2, + * Invalid = 0x7FFFFFFF, + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoAV1TxMode_descr Description + *
+ * \cond WIS_GEN_DESC + * Transform mode (AV1 Bitstream Specification Section 6.8.21). + * + * Values: + * - `WisStdVideoAV1TxModeOnly4x4 = 0`: Only 4x4 transforms. + * - `WisStdVideoAV1TxModeLargest = 1`: Largest allowed transform for the partition. + * - `WisStdVideoAV1TxModeSelect = 2`: Select the transform mode. + * - `WisStdVideoAV1TxModeInvalid = 0x7FFFFFFF`: Invalid TxMode. + * \endcond + * + * + * @section WisStdVideoAV1TxMode_see_also See Also + *
+ * + * \cond WIS_GEN_REFS + * @see Structs: + * WisStdVideoDecodeAV1PictureInfo + * \endcond + */ diff --git a/docs/video/func/video_decode_command_list_decode_frame_function.h b/docs/video/func/video_decode_command_list_decode_frame_function.h new file mode 100644 index 000000000..36a5e6724 --- /dev/null +++ b/docs/video/func/video_decode_command_list_decode_frame_function.h @@ -0,0 +1,75 @@ +/** + * @struct wisVideoDecodeCommandListDecodeFrame + * @ingroup Functions Video + * + * + * @section wisVideoDecodeCommandListDecodeFrame_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C Version: + * ```c + * // Provided by Wisdom 0.7.0. + * void wisVideoDecodeCommandListDecodeFrame(const WisVideoDecodeCommandList* self, + * const WisVideoDecoder* decoder, + * const WisVideoDecodeInputDesc* input_desc); + * ``` + *
+ * C Implementation Specific Version: + * ```c + * // Provided by Wisdom 0.7.0. + * void wisVKVideoDecodeCommandListDecodeFrame(const WisVKVideoDecodeCommandList* self, + * const WisVKVideoDecoder* decoder, + * const WisVKVideoDecodeInputDesc* input_desc); + * + * // Provided by Wisdom 0.7.0. + * void wisDX12VideoDecodeCommandListDecodeFrame(const WisDX12VideoDecodeCommandList* self, + * const WisDX12VideoDecoder* decoder, + * const WisDX12VideoDecodeInputDesc* input_desc); + * ``` + *
+ * + * C++ Version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.0. + * void VideoDecodeCommandList::DecodeFrame(const wis::VideoDecoder& decoder, + * const wis::VideoDecodeInputDesc& input_desc) const noexcept; + * } + * ``` + *
+ * C++ Implementation Specific Version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.0. + * void VKVideoDecodeCommandList::DecodeFrame(const wis::VKVideoDecoder& decoder, + * const wis::VKVideoDecodeInputDesc& input_desc) const noexcept; + * + * // Provided by Wisdom 0.7.0. + * void DX12VideoDecodeCommandList::DecodeFrame(const wis::DX12VideoDecoder& decoder, + * const wis::DX12VideoDecodeInputDesc& input_desc) const noexcept; + * } + * ``` + *
+ * \endcond + * + * @section wisVideoDecodeCommandListDecodeFrame_memb Parameters + *
+ * \cond WIS_GEN_DESC + * - **this** `self` self is a pointer to the valid WisVideoDecodeCommandList instance. + * - `decoder` The video decoder that will be used for decoding the video frame. + * - `input_desc` Description of the input data for the video decode operation. This field specifies the type and + * location of the input data that will be used for decoding the video frame. + * \endcond + * + * @section wisVideoDecodeCommandListDecodeFrame_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section wisVideoDecodeCommandListDecodeFrame_see_also See Also + *
+ * \cond WIS_GEN_REFS + * \endcond + */ diff --git a/docs/video/func/video_decoding_extension_create_command_list_function.h b/docs/video/func/video_decoding_extension_create_command_list_function.h new file mode 100644 index 000000000..67b5292c3 --- /dev/null +++ b/docs/video/func/video_decoding_extension_create_command_list_function.h @@ -0,0 +1,78 @@ +/** + * @struct wisVideoDecodingExtensionCreateCommandList + * @ingroup Functions Video + * + * + * @section wisVideoDecodingExtensionCreateCommandList_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C Version: + * ```c + * // Provided by Wisdom 0.7.1. + * WisResult wisVideoDecodingExtensionCreateCommandList(WisVideoDecodingExtension* self, + * const WisCommandAllocator* command_allocator, + * WisVideoDecodeCommandList* command_list); + * ``` + *
+ * C Implementation Specific Version: + * ```c + * // Provided by Wisdom 0.7.1. + * WisResult wisVKVideoDecodingExtensionCreateCommandList(WisVKVideoDecodingExtension* self, + * const WisVKCommandAllocator* command_allocator, + * WisVKVideoDecodeCommandList* command_list); + * + * // Provided by Wisdom 0.7.1. + * WisResult wisDX12VideoDecodingExtensionCreateCommandList(WisDX12VideoDecodingExtension* self, + * const WisDX12CommandAllocator* command_allocator, + * WisDX12VideoDecodeCommandList* command_list); + * ``` + *
+ * + * C++ Version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * WIS_NODISCARD wis::VideoDecodeCommandList VideoDecodingExtension::CreateCommandList(const wis::CommandAllocator& + * command_allocator, wis::Result& out_result) noexcept; + * } + * ``` + *
+ * C++ Implementation Specific Version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * WIS_NODISCARD wis::VKVideoDecodeCommandList VKVideoDecodingExtension::CreateCommandList(const + * wis::VKCommandAllocator& command_allocator, wis::Result& out_result) noexcept; + * + * // Provided by Wisdom 0.7.1. + * WIS_NODISCARD wis::DX12VideoDecodeCommandList DX12VideoDecodingExtension::CreateCommandList(const + * wis::DX12CommandAllocator& command_allocator, wis::Result& out_result) noexcept; + * } + * ``` + *
+ * \endcond + * + * @section wisVideoDecodingExtensionCreateCommandList_memb Parameters + *
+ * \cond WIS_GEN_DESC + * - **this** `self` self is a pointer to the valid WisVideoDecodingExtension instance. + * - `command_allocator` The command allocator that the command list will use for memory management of command buffers. + * It @wis_must be created with the same WisDevice as the extension and have `WisCommandQueueTypeVideoDecode` or + * `WisCommandQueueTypeVideoEncode` specified. + * - `command_list` Output parameter that holds the created video command list handle if the operation is successful. + * + * - **return** denoting the outcome of operation. + * \endcond + * + * @section wisVideoDecodingExtensionCreateCommandList_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section wisVideoDecodingExtensionCreateCommandList_see_also See Also + *
+ * \cond WIS_GEN_REFS + * \endcond + */ diff --git a/docs/video/handle/video_decode_command_list_handle.h b/docs/video/handle/video_decode_command_list_handle.h index cfb8ea1d3..771666e5d 100644 --- a/docs/video/handle/video_decode_command_list_handle.h +++ b/docs/video/handle/video_decode_command_list_handle.h @@ -24,6 +24,6 @@ * \cond WIS_GEN_REFS * @see Functions: * wisDestroyVideoDecodeCommandList, wisVideoDecodingExtensionCreateCommandList, wisVideoDecodeCommandListBegin, - * wisVideoDecodeCommandListEnd + * wisVideoDecodeCommandListEnd, wisVideoDecodeCommandListDecodeFrame * \endcond */ diff --git a/docs/video/handle/video_decoder_handle.h b/docs/video/handle/video_decoder_handle.h index 149d7a407..7edb32fdf 100644 --- a/docs/video/handle/video_decoder_handle.h +++ b/docs/video/handle/video_decoder_handle.h @@ -23,6 +23,6 @@ *
* \cond WIS_GEN_REFS * @see Functions: - * wisDestroyVideoDecoder, wisVideoDecodingExtensionCreateDecoder + * wisDestroyVideoDecoder, wisVideoDecodingExtensionCreateDecoder, wisVideoDecodeCommandListDecodeFrame * \endcond */ diff --git a/docs/video/struct/std_video_a_v1_c_d_e_f_struct.h b/docs/video/struct/std_video_a_v1_c_d_e_f_struct.h new file mode 100644 index 000000000..157910d9b --- /dev/null +++ b/docs/video/struct/std_video_a_v1_c_d_e_f_struct.h @@ -0,0 +1,62 @@ +/** + * @struct WisStdVideoAV1CDEF + * @ingroup Structures Video + * + * + * @section WisStdVideoAV1CDEF_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef struct WisStdVideoAV1CDEF { + * uint8_t cdef_damping_minus_3; + * uint8_t cdef_bits; + * uint8_t cdef_y_pri_strength[8]; + * uint8_t cdef_y_sec_strength[8]; + * uint8_t cdef_uv_pri_strength[8]; + * uint8_t cdef_uv_sec_strength[8]; + * } WisStdVideoAV1CDEF; + * + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * struct StdVideoAV1CDEF { + * std::uint8_t cdef_damping_minus_3; + * std::uint8_t cdef_bits; + * std::array cdef_y_pri_strength; + * std::array cdef_y_sec_strength; + * std::array cdef_uv_pri_strength; + * std::array cdef_uv_sec_strength; + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoAV1CDEF_memb Members + *
+ * \cond WIS_GEN_DESC + * - `cdef_damping_minus_3` Controls the amount of damping in the deringing filter. + * - `cdef_bits` Specifies the number of bits needed to specify the CDEF filter strength. + * - `cdef_y_pri_strength` Primary filter strength for Y. + * - `cdef_y_sec_strength` Secondary filter strength for Y. + * - `cdef_uv_pri_strength` Primary filter strength for UV. + * - `cdef_uv_sec_strength` Secondary filter strength for UV. + * \endcond + * + * @section WisStdVideoAV1CDEF_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section WisStdVideoAV1CDEF_see_also See Also + *
+ * \cond WIS_GEN_REFS + * @see Structs: + * WisStdVideoDecodeAV1PictureInfo + * \endcond + */ diff --git a/docs/video/struct/std_video_a_v1_color_config_flags_struct.h b/docs/video/struct/std_video_a_v1_color_config_flags_struct.h new file mode 100644 index 000000000..fdab89fca --- /dev/null +++ b/docs/video/struct/std_video_a_v1_color_config_flags_struct.h @@ -0,0 +1,59 @@ +/** + * @struct WisStdVideoAV1ColorConfigFlags + * @ingroup Structures Video + * + * + * @section WisStdVideoAV1ColorConfigFlags_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef struct WisStdVideoAV1ColorConfigFlags { + * uint32_t mono_chrome : 1; + * uint32_t color_range : 1; + * uint32_t separate_uv_delta_q : 1; + * uint32_t color_description_present_flag : 1; + * uint32_t reserved : 28; + * } WisStdVideoAV1ColorConfigFlags; + * + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * struct StdVideoAV1ColorConfigFlags { + * std::uint32_t mono_chrome : 1; + * std::uint32_t color_range : 1; + * std::uint32_t separate_uv_delta_q : 1; + * std::uint32_t color_description_present_flag : 1; + * std::uint32_t reserved : 28; + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoAV1ColorConfigFlags_memb Members + *
+ * \cond WIS_GEN_DESC + * - `mono_chrome` Indicates if the video does not contain U and V color planes. + * - `color_range` Flag indicating if full color range is used. + * - `separate_uv_delta_q` Flag indicating U and V planes have separate delta quantization. + * - `color_description_present_flag` Indicates if color description is present. + * - `reserved` No description. + * \endcond + * + * @section WisStdVideoAV1ColorConfigFlags_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section WisStdVideoAV1ColorConfigFlags_see_also See Also + *
+ * \cond WIS_GEN_REFS + * @see Structs: + * WisStdVideoAV1ColorConfig + * \endcond + */ diff --git a/docs/video/struct/std_video_a_v1_color_config_struct.h b/docs/video/struct/std_video_a_v1_color_config_struct.h new file mode 100644 index 000000000..9f522029a --- /dev/null +++ b/docs/video/struct/std_video_a_v1_color_config_struct.h @@ -0,0 +1,71 @@ +/** + * @struct WisStdVideoAV1ColorConfig + * @ingroup Structures Video + * + * + * @section WisStdVideoAV1ColorConfig_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef struct WisStdVideoAV1ColorConfig { + * WisStdVideoAV1ColorConfigFlags flags; + * uint8_t BitDepth; + * uint8_t subsampling_x; + * uint8_t subsampling_y; + * uint8_t reserved1; + * WisStdVideoAV1ColorPrimaries color_primaries; + * WisStdVideoAV1TransferCharacteristics transfer_characteristics; + * WisStdVideoAV1MatrixCoefficients matrix_coefficients; + * WisStdVideoAV1ChromaSamplePosition chroma_sample_position; + * } WisStdVideoAV1ColorConfig; + * + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * struct StdVideoAV1ColorConfig { + * wis::StdVideoAV1ColorConfigFlags flags; + * std::uint8_t BitDepth; + * std::uint8_t subsampling_x; + * std::uint8_t subsampling_y; + * std::uint8_t reserved1; + * wis::StdVideoAV1ColorPrimaries color_primaries; + * wis::StdVideoAV1TransferCharacteristics transfer_characteristics; + * wis::StdVideoAV1MatrixCoefficients matrix_coefficients; + * wis::StdVideoAV1ChromaSamplePosition chroma_sample_position; + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoAV1ColorConfig_memb Members + *
+ * \cond WIS_GEN_DESC + * - `flags` Color configuration flags. + * - `BitDepth` Bit depth of the color samples (8, 10, or 12). + * - `subsampling_x` Chroma subsampling x. + * - `subsampling_y` Chroma subsampling y. + * - `reserved1` No description. + * - `color_primaries` Color primaries. + * - `transfer_characteristics` Transfer characteristics. + * - `matrix_coefficients` Matrix coefficients. + * - `chroma_sample_position` Chroma sample position. + * \endcond + * + * @section WisStdVideoAV1ColorConfig_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section WisStdVideoAV1ColorConfig_see_also See Also + *
+ * \cond WIS_GEN_REFS + * @see Structs: + * WisStdVideoAV1SequenceHeader + * \endcond + */ diff --git a/docs/video/struct/std_video_a_v1_film_grain_flags_struct.h b/docs/video/struct/std_video_a_v1_film_grain_flags_struct.h new file mode 100644 index 000000000..7272bdcdd --- /dev/null +++ b/docs/video/struct/std_video_a_v1_film_grain_flags_struct.h @@ -0,0 +1,59 @@ +/** + * @struct WisStdVideoAV1FilmGrainFlags + * @ingroup Structures Video + * + * + * @section WisStdVideoAV1FilmGrainFlags_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef struct WisStdVideoAV1FilmGrainFlags { + * uint32_t chroma_scaling_from_luma : 1; + * uint32_t overlap_flag : 1; + * uint32_t clip_to_restricted_range : 1; + * uint32_t update_grain : 1; + * uint32_t reserved : 28; + * } WisStdVideoAV1FilmGrainFlags; + * + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * struct StdVideoAV1FilmGrainFlags { + * std::uint32_t chroma_scaling_from_luma : 1; + * std::uint32_t overlap_flag : 1; + * std::uint32_t clip_to_restricted_range : 1; + * std::uint32_t update_grain : 1; + * std::uint32_t reserved : 28; + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoAV1FilmGrainFlags_memb Members + *
+ * \cond WIS_GEN_DESC + * - `chroma_scaling_from_luma` Flag indicating that chroma scaling is derived from luma. + * - `overlap_flag` Flag indicating overlapping film grain blocks. + * - `clip_to_restricted_range` Flag indicating clipping to restricted range. + * - `update_grain` Flag indicating the film grain parameters are updated in this frame. + * - `reserved` No description. + * \endcond + * + * @section WisStdVideoAV1FilmGrainFlags_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section WisStdVideoAV1FilmGrainFlags_see_also See Also + *
+ * \cond WIS_GEN_REFS + * @see Structs: + * WisStdVideoAV1FilmGrain + * \endcond + */ diff --git a/docs/video/struct/std_video_a_v1_film_grain_struct.h b/docs/video/struct/std_video_a_v1_film_grain_struct.h new file mode 100644 index 000000000..e75dee79b --- /dev/null +++ b/docs/video/struct/std_video_a_v1_film_grain_struct.h @@ -0,0 +1,119 @@ +/** + * @struct WisStdVideoAV1FilmGrain + * @ingroup Structures Video + * + * + * @section WisStdVideoAV1FilmGrain_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef struct WisStdVideoAV1FilmGrain { + * WisStdVideoAV1FilmGrainFlags flags; + * uint8_t grain_scaling_minus_8; + * uint8_t ar_coeff_lag; + * uint8_t ar_coeff_shift_minus_6; + * uint8_t grain_scale_shift; + * uint16_t grain_seed; + * uint8_t film_grain_params_ref_idx; + * uint8_t num_y_points; + * uint8_t point_y_value[14]; + * uint8_t point_y_scaling[14]; + * uint8_t num_cb_points; + * uint8_t point_cb_value[10]; + * uint8_t point_cb_scaling[10]; + * uint8_t num_cr_points; + * uint8_t point_cr_value[10]; + * uint8_t point_cr_scaling[10]; + * int8_t ar_coeffs_y_plus_128[24]; + * int8_t ar_coeffs_cb_plus_128[25]; + * int8_t ar_coeffs_cr_plus_128[25]; + * uint8_t cb_mult; + * uint8_t cb_luma_mult; + * uint16_t cb_offset; + * uint8_t cr_mult; + * uint8_t cr_luma_mult; + * uint16_t cr_offset; + * } WisStdVideoAV1FilmGrain; + * + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * struct StdVideoAV1FilmGrain { + * wis::StdVideoAV1FilmGrainFlags flags; + * std::uint8_t grain_scaling_minus_8; + * std::uint8_t ar_coeff_lag; + * std::uint8_t ar_coeff_shift_minus_6; + * std::uint8_t grain_scale_shift; + * std::uint16_t grain_seed; + * std::uint8_t film_grain_params_ref_idx; + * std::uint8_t num_y_points; + * std::array point_y_value; + * std::array point_y_scaling; + * std::uint8_t num_cb_points; + * std::array point_cb_value; + * std::array point_cb_scaling; + * std::uint8_t num_cr_points; + * std::array point_cr_value; + * std::array point_cr_scaling; + * std::array ar_coeffs_y_plus_128; + * std::array ar_coeffs_cb_plus_128; + * std::array ar_coeffs_cr_plus_128; + * std::uint8_t cb_mult; + * std::uint8_t cb_luma_mult; + * std::uint16_t cb_offset; + * std::uint8_t cr_mult; + * std::uint8_t cr_luma_mult; + * std::uint16_t cr_offset; + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoAV1FilmGrain_memb Members + *
+ * \cond WIS_GEN_DESC + * - `flags` Film grain flags. + * - `grain_scaling_minus_8` Shift value for the film grain scale calculation. + * - `ar_coeff_lag` Number of auto-regressive coefficients. + * - `ar_coeff_shift_minus_6` Shift value for auto-regressive coefficients. + * - `grain_scale_shift` Specifies how much the Gaussian random numbers @wis_should be scaled down. + * - `grain_seed` Specifies the seed for the pseudo-random number generator. + * - `film_grain_params_ref_idx` Specifies the reference frame index to obtain the film grain parameters from. + * - `num_y_points` Number of points for luma scaling. + * - `point_y_value` Luma point values. + * - `point_y_scaling` Luma point scaling. + * - `num_cb_points` Number of points for Cb scaling. + * - `point_cb_value` Cb point values. + * - `point_cb_scaling` Cb point scaling. + * - `num_cr_points` Number of points for Cr scaling. + * - `point_cr_value` Cr point values. + * - `point_cr_scaling` Cr point scaling. + * - `ar_coeffs_y_plus_128` Auto-regressive coefficients for Y. + * - `ar_coeffs_cb_plus_128` Auto-regressive coefficients for Cb. + * - `ar_coeffs_cr_plus_128` Auto-regressive coefficients for Cr. + * - `cb_mult` Cb multiplier for chroma scaling from luma. + * - `cb_luma_mult` Cb luma multiplier for chroma scaling from luma. + * - `cb_offset` Cb offset for chroma scaling from luma. + * - `cr_mult` Cr multiplier for chroma scaling from luma. + * - `cr_luma_mult` Cr luma multiplier for chroma scaling from luma. + * - `cr_offset` Cr offset for chroma scaling from luma. + * \endcond + * + * @section WisStdVideoAV1FilmGrain_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section WisStdVideoAV1FilmGrain_see_also See Also + *
+ * \cond WIS_GEN_REFS + * @see Structs: + * WisStdVideoDecodeAV1PictureInfo + * \endcond + */ diff --git a/docs/video/struct/std_video_a_v1_global_motion_struct.h b/docs/video/struct/std_video_a_v1_global_motion_struct.h new file mode 100644 index 000000000..3f817495b --- /dev/null +++ b/docs/video/struct/std_video_a_v1_global_motion_struct.h @@ -0,0 +1,50 @@ +/** + * @struct WisStdVideoAV1GlobalMotion + * @ingroup Structures Video + * + * + * @section WisStdVideoAV1GlobalMotion_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef struct WisStdVideoAV1GlobalMotion { + * uint8_t GmType[8]; + * int32_t gm_params[8*6]; + * } WisStdVideoAV1GlobalMotion; + * + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * struct StdVideoAV1GlobalMotion { + * std::array GmType; + * std::array gm_params; + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoAV1GlobalMotion_memb Members + *
+ * \cond WIS_GEN_DESC + * - `GmType` Array specifying the global motion type for each reference frame. + * - `gm_params` Array of global motion parameters. + * \endcond + * + * @section WisStdVideoAV1GlobalMotion_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section WisStdVideoAV1GlobalMotion_see_also See Also + *
+ * \cond WIS_GEN_REFS + * @see Structs: + * WisStdVideoDecodeAV1PictureInfo + * \endcond + */ diff --git a/docs/video/struct/std_video_a_v1_loop_filter_flags_struct.h b/docs/video/struct/std_video_a_v1_loop_filter_flags_struct.h new file mode 100644 index 000000000..7830d19dd --- /dev/null +++ b/docs/video/struct/std_video_a_v1_loop_filter_flags_struct.h @@ -0,0 +1,55 @@ +/** + * @struct WisStdVideoAV1LoopFilterFlags + * @ingroup Structures Video + * + * + * @section WisStdVideoAV1LoopFilterFlags_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef struct WisStdVideoAV1LoopFilterFlags { + * uint32_t loop_filter_delta_enabled : 1; + * uint32_t loop_filter_delta_update : 1; + * uint32_t reserved : 30; + * } WisStdVideoAV1LoopFilterFlags; + * + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * struct StdVideoAV1LoopFilterFlags { + * std::uint32_t loop_filter_delta_enabled : 1; + * std::uint32_t loop_filter_delta_update : 1; + * std::uint32_t reserved : 30; + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoAV1LoopFilterFlags_memb Members + *
+ * \cond WIS_GEN_DESC + * - `loop_filter_delta_enabled` Indicates whether the filter level depends on the mode and reference frame used to + * predict a block. + * - `loop_filter_delta_update` Indicates whether additional syntax elements are present that specify which mode and + * reference frame deltas are to be updated. + * - `reserved` No description. + * \endcond + * + * @section WisStdVideoAV1LoopFilterFlags_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section WisStdVideoAV1LoopFilterFlags_see_also See Also + *
+ * \cond WIS_GEN_REFS + * @see Structs: + * WisStdVideoAV1LoopFilter + * \endcond + */ diff --git a/docs/video/struct/std_video_a_v1_loop_filter_struct.h b/docs/video/struct/std_video_a_v1_loop_filter_struct.h new file mode 100644 index 000000000..1b73d23cb --- /dev/null +++ b/docs/video/struct/std_video_a_v1_loop_filter_struct.h @@ -0,0 +1,65 @@ +/** + * @struct WisStdVideoAV1LoopFilter + * @ingroup Structures Video + * + * + * @section WisStdVideoAV1LoopFilter_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef struct WisStdVideoAV1LoopFilter { + * WisStdVideoAV1LoopFilterFlags flags; + * uint8_t loop_filter_level[4]; + * uint8_t loop_filter_sharpness; + * uint8_t update_ref_delta; + * int8_t loop_filter_ref_deltas[8]; + * uint8_t update_mode_delta; + * int8_t loop_filter_mode_deltas[2]; + * } WisStdVideoAV1LoopFilter; + * + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * struct StdVideoAV1LoopFilter { + * wis::StdVideoAV1LoopFilterFlags flags; + * std::array loop_filter_level; + * std::uint8_t loop_filter_sharpness; + * std::uint8_t update_ref_delta; + * std::array loop_filter_ref_deltas; + * std::uint8_t update_mode_delta; + * std::array loop_filter_mode_deltas; + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoAV1LoopFilter_memb Members + *
+ * \cond WIS_GEN_DESC + * - `flags` Loop filter flags. + * - `loop_filter_level` Array containing loop filter strength values. + * - `loop_filter_sharpness` Loop filter sharpness. + * - `update_ref_delta` Indicates that the loop filter ref deltas are to be updated. + * - `loop_filter_ref_deltas` Loop filter reference deltas. + * - `update_mode_delta` Indicates that the loop filter mode deltas are to be updated. + * - `loop_filter_mode_deltas` Loop filter mode deltas. + * \endcond + * + * @section WisStdVideoAV1LoopFilter_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section WisStdVideoAV1LoopFilter_see_also See Also + *
+ * \cond WIS_GEN_REFS + * @see Structs: + * WisStdVideoDecodeAV1PictureInfo + * \endcond + */ diff --git a/docs/video/struct/std_video_a_v1_loop_restoration_struct.h b/docs/video/struct/std_video_a_v1_loop_restoration_struct.h new file mode 100644 index 000000000..e75cb75b6 --- /dev/null +++ b/docs/video/struct/std_video_a_v1_loop_restoration_struct.h @@ -0,0 +1,50 @@ +/** + * @struct WisStdVideoAV1LoopRestoration + * @ingroup Structures Video + * + * + * @section WisStdVideoAV1LoopRestoration_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef struct WisStdVideoAV1LoopRestoration { + * WisStdVideoAV1FrameRestorationType FrameRestorationType[3]; + * uint16_t LoopRestorationSize[3]; + * } WisStdVideoAV1LoopRestoration; + * + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * struct StdVideoAV1LoopRestoration { + * std::array FrameRestorationType; + * std::array LoopRestorationSize; + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoAV1LoopRestoration_memb Members + *
+ * \cond WIS_GEN_DESC + * - `FrameRestorationType` Array specifying the loop restoration type for each plane (Y, U, V). + * - `LoopRestorationSize` Array specifying the size of loop restoration units for each plane. + * \endcond + * + * @section WisStdVideoAV1LoopRestoration_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section WisStdVideoAV1LoopRestoration_see_also See Also + *
+ * \cond WIS_GEN_REFS + * @see Structs: + * WisStdVideoDecodeAV1PictureInfo + * \endcond + */ diff --git a/docs/video/struct/std_video_a_v1_quantization_flags_struct.h b/docs/video/struct/std_video_a_v1_quantization_flags_struct.h new file mode 100644 index 000000000..aadfd37d2 --- /dev/null +++ b/docs/video/struct/std_video_a_v1_quantization_flags_struct.h @@ -0,0 +1,53 @@ +/** + * @struct WisStdVideoAV1QuantizationFlags + * @ingroup Structures Video + * + * + * @section WisStdVideoAV1QuantizationFlags_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef struct WisStdVideoAV1QuantizationFlags { + * uint32_t using_qmatrix : 1; + * uint32_t diff_uv_delta : 1; + * uint32_t reserved : 30; + * } WisStdVideoAV1QuantizationFlags; + * + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * struct StdVideoAV1QuantizationFlags { + * std::uint32_t using_qmatrix : 1; + * std::uint32_t diff_uv_delta : 1; + * std::uint32_t reserved : 30; + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoAV1QuantizationFlags_memb Members + *
+ * \cond WIS_GEN_DESC + * - `using_qmatrix` Specifies whether the quantizer matrix @wis_should be used. + * - `diff_uv_delta` Specifies whether the U and V delta quantizer values are transmitted separately. + * - `reserved` No description. + * \endcond + * + * @section WisStdVideoAV1QuantizationFlags_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section WisStdVideoAV1QuantizationFlags_see_also See Also + *
+ * \cond WIS_GEN_REFS + * @see Structs: + * WisStdVideoAV1Quantization + * \endcond + */ diff --git a/docs/video/struct/std_video_a_v1_quantization_struct.h b/docs/video/struct/std_video_a_v1_quantization_struct.h new file mode 100644 index 000000000..e9c459a31 --- /dev/null +++ b/docs/video/struct/std_video_a_v1_quantization_struct.h @@ -0,0 +1,74 @@ +/** + * @struct WisStdVideoAV1Quantization + * @ingroup Structures Video + * + * + * @section WisStdVideoAV1Quantization_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef struct WisStdVideoAV1Quantization { + * WisStdVideoAV1QuantizationFlags flags; + * uint8_t base_q_idx; + * int8_t DeltaQYDc; + * int8_t DeltaQUDc; + * int8_t DeltaQUAc; + * int8_t DeltaQVDc; + * int8_t DeltaQVAc; + * uint8_t qm_y; + * uint8_t qm_u; + * uint8_t qm_v; + * } WisStdVideoAV1Quantization; + * + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * struct StdVideoAV1Quantization { + * wis::StdVideoAV1QuantizationFlags flags; + * std::uint8_t base_q_idx; + * std::int8_t DeltaQYDc; + * std::int8_t DeltaQUDc; + * std::int8_t DeltaQUAc; + * std::int8_t DeltaQVDc; + * std::int8_t DeltaQVAc; + * std::uint8_t qm_y; + * std::uint8_t qm_u; + * std::uint8_t qm_v; + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoAV1Quantization_memb Members + *
+ * \cond WIS_GEN_DESC + * - `flags` Quantization flags. + * - `base_q_idx` Indicates the base frame qindex. + * - `DeltaQYDc` Y DC quantizer relative to base_q_idx. + * - `DeltaQUDc` U DC quantizer relative to base_q_idx. + * - `DeltaQUAc` U AC quantizer relative to base_q_idx. + * - `DeltaQVDc` V DC quantizer relative to base_q_idx. + * - `DeltaQVAc` V AC quantizer relative to base_q_idx. + * - `qm_y` Specifies the level in the quantizer matrix that @wis_should be used for luma plane decoding. + * - `qm_u` Specifies the level in the quantizer matrix that @wis_should be used for chroma U plane decoding. + * - `qm_v` Specifies the level in the quantizer matrix that @wis_should be used for chroma V plane decoding. + * \endcond + * + * @section WisStdVideoAV1Quantization_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section WisStdVideoAV1Quantization_see_also See Also + *
+ * \cond WIS_GEN_REFS + * @see Structs: + * WisStdVideoDecodeAV1PictureInfo + * \endcond + */ diff --git a/docs/video/struct/std_video_a_v1_segmentation_struct.h b/docs/video/struct/std_video_a_v1_segmentation_struct.h new file mode 100644 index 000000000..13826d8f8 --- /dev/null +++ b/docs/video/struct/std_video_a_v1_segmentation_struct.h @@ -0,0 +1,50 @@ +/** + * @struct WisStdVideoAV1Segmentation + * @ingroup Structures Video + * + * + * @section WisStdVideoAV1Segmentation_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef struct WisStdVideoAV1Segmentation { + * uint8_t FeatureEnabled[8]; + * int16_t FeatureData[8*8]; + * } WisStdVideoAV1Segmentation; + * + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * struct StdVideoAV1Segmentation { + * std::array FeatureEnabled; + * std::array FeatureData; + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoAV1Segmentation_memb Members + *
+ * \cond WIS_GEN_DESC + * - `FeatureEnabled` Array specifying whether the feature is enabled for a segment. + * - `FeatureData` Array specifying the feature data for a segment feature. + * \endcond + * + * @section WisStdVideoAV1Segmentation_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section WisStdVideoAV1Segmentation_see_also See Also + *
+ * \cond WIS_GEN_REFS + * @see Structs: + * WisStdVideoDecodeAV1PictureInfo + * \endcond + */ diff --git a/docs/video/struct/std_video_a_v1_sequence_header_flags_struct.h b/docs/video/struct/std_video_a_v1_sequence_header_flags_struct.h new file mode 100644 index 000000000..759623153 --- /dev/null +++ b/docs/video/struct/std_video_a_v1_sequence_header_flags_struct.h @@ -0,0 +1,104 @@ +/** + * @struct WisStdVideoAV1SequenceHeaderFlags + * @ingroup Structures Video + * + * + * @section WisStdVideoAV1SequenceHeaderFlags_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef struct WisStdVideoAV1SequenceHeaderFlags { + * uint32_t still_picture : 1; + * uint32_t reduced_still_picture_header : 1; + * uint32_t use_128x128_superblock : 1; + * uint32_t enable_filter_intra : 1; + * uint32_t enable_intra_edge_filter : 1; + * uint32_t enable_interintra_compound : 1; + * uint32_t enable_masked_compound : 1; + * uint32_t enable_warped_motion : 1; + * uint32_t enable_dual_filter : 1; + * uint32_t enable_order_hint : 1; + * uint32_t enable_jnt_comp : 1; + * uint32_t enable_ref_frame_mvs : 1; + * uint32_t frame_id_numbers_present_flag : 1; + * uint32_t enable_superres : 1; + * uint32_t enable_cdef : 1; + * uint32_t enable_restoration : 1; + * uint32_t film_grain_params_present : 1; + * uint32_t timing_info_present_flag : 1; + * uint32_t initial_display_delay_present_flag : 1; + * uint32_t reserved : 13; + * } WisStdVideoAV1SequenceHeaderFlags; + * + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * struct StdVideoAV1SequenceHeaderFlags { + * std::uint32_t still_picture : 1; + * std::uint32_t reduced_still_picture_header : 1; + * std::uint32_t use_128x128_superblock : 1; + * std::uint32_t enable_filter_intra : 1; + * std::uint32_t enable_intra_edge_filter : 1; + * std::uint32_t enable_interintra_compound : 1; + * std::uint32_t enable_masked_compound : 1; + * std::uint32_t enable_warped_motion : 1; + * std::uint32_t enable_dual_filter : 1; + * std::uint32_t enable_order_hint : 1; + * std::uint32_t enable_jnt_comp : 1; + * std::uint32_t enable_ref_frame_mvs : 1; + * std::uint32_t frame_id_numbers_present_flag : 1; + * std::uint32_t enable_superres : 1; + * std::uint32_t enable_cdef : 1; + * std::uint32_t enable_restoration : 1; + * std::uint32_t film_grain_params_present : 1; + * std::uint32_t timing_info_present_flag : 1; + * std::uint32_t initial_display_delay_present_flag : 1; + * std::uint32_t reserved : 13; + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoAV1SequenceHeaderFlags_memb Members + *
+ * \cond WIS_GEN_DESC + * - `still_picture` Specifies if the video sequence contains a single still picture. + * - `reduced_still_picture_header` Specifies if reduced header parameters are used for a still picture. + * - `use_128x128_superblock` Specifies if superblocks are 128x128 or 64x64. + * - `enable_filter_intra` Specifies if the filter intra predictor can be used. + * - `enable_intra_edge_filter` Specifies if intra edge filtering can be used. + * - `enable_interintra_compound` Specifies if inter-intra compound prediction can be used. + * - `enable_masked_compound` Specifies if masked compound prediction can be used. + * - `enable_warped_motion` Specifies if warped motion can be used. + * - `enable_dual_filter` Specifies if dual interpolation filters can be used. + * - `enable_order_hint` Specifies if order hints are used. + * - `enable_jnt_comp` Specifies if the distance weights process is used for compound prediction. + * - `enable_ref_frame_mvs` Specifies if reference frame motion vectors are present. + * - `frame_id_numbers_present_flag` Specifies if frame ID numbers are present. + * - `enable_superres` Specifies if the superresolution feature can be used. + * - `enable_cdef` Specifies if the CDEF filtering process can be used. + * - `enable_restoration` Specifies if loop restoration can be used. + * - `film_grain_params_present` Specifies if film grain parameters are present. + * - `timing_info_present_flag` Specifies if timing info is present. + * - `initial_display_delay_present_flag` Specifies if the initial display delay info is present. + * - `reserved` No description. + * \endcond + * + * @section WisStdVideoAV1SequenceHeaderFlags_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section WisStdVideoAV1SequenceHeaderFlags_see_also See Also + *
+ * \cond WIS_GEN_REFS + * @see Structs: + * WisStdVideoAV1SequenceHeader + * \endcond + */ diff --git a/docs/video/struct/std_video_a_v1_sequence_header_struct.h b/docs/video/struct/std_video_a_v1_sequence_header_struct.h new file mode 100644 index 000000000..02685929f --- /dev/null +++ b/docs/video/struct/std_video_a_v1_sequence_header_struct.h @@ -0,0 +1,84 @@ +/** + * @struct WisStdVideoAV1SequenceHeader + * @ingroup Structures Video + * + * + * @section WisStdVideoAV1SequenceHeader_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef struct WisStdVideoAV1SequenceHeader { + * WisStdVideoAV1SequenceHeaderFlags flags; + * WisStdVideoAV1Profile seq_profile; + * uint8_t frame_width_bits_minus_1; + * uint8_t frame_height_bits_minus_1; + * uint16_t max_frame_width_minus_1; + * uint16_t max_frame_height_minus_1; + * uint8_t delta_frame_id_length_minus_2; + * uint8_t additional_frame_id_length_minus_1; + * uint8_t order_hint_bits_minus_1; + * uint8_t seq_force_integer_mv; + * uint8_t seq_force_screen_content_tools; + * uint8_t reserved1[5]; + * const WisStdVideoAV1ColorConfig* pColorConfig; + * const WisStdVideoAV1TimingInfo* pTimingInfo; + * } WisStdVideoAV1SequenceHeader; + * + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * struct StdVideoAV1SequenceHeader { + * wis::StdVideoAV1SequenceHeaderFlags flags; + * wis::StdVideoAV1Profile seq_profile; + * std::uint8_t frame_width_bits_minus_1; + * std::uint8_t frame_height_bits_minus_1; + * std::uint16_t max_frame_width_minus_1; + * std::uint16_t max_frame_height_minus_1; + * std::uint8_t delta_frame_id_length_minus_2; + * std::uint8_t additional_frame_id_length_minus_1; + * std::uint8_t order_hint_bits_minus_1; + * std::uint8_t seq_force_integer_mv; + * std::uint8_t seq_force_screen_content_tools; + * std::array reserved1; + * const wis::StdVideoAV1ColorConfig* pColorConfig; + * const wis::StdVideoAV1TimingInfo* pTimingInfo; + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoAV1SequenceHeader_memb Members + *
+ * \cond WIS_GEN_DESC + * - `flags` Sequence header flags. + * - `seq_profile` AV1 profile. + * - `frame_width_bits_minus_1` Number of bits used to specify the frame width minus 1. + * - `frame_height_bits_minus_1` Number of bits used to specify the frame height minus 1. + * - `max_frame_width_minus_1` Maximum frame width minus 1. + * - `max_frame_height_minus_1` Maximum frame height minus 1. + * - `delta_frame_id_length_minus_2` Specifies the number of bits used to encode delta_frame_id. + * - `additional_frame_id_length_minus_1` Used to calculate the number of bits used to encode frame_id. + * - `order_hint_bits_minus_1` Used to compute OrderHintBits. + * - `seq_force_integer_mv` Equal to 1: motion vectors will always be integers. + * - `seq_force_screen_content_tools` Screen content tools setting. + * - `reserved1` No description. + * - `pColorConfig` Pointer to color configuration parameters. + * - `pTimingInfo` Pointer to timing info parameters. + * \endcond + * + * @section WisStdVideoAV1SequenceHeader_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section WisStdVideoAV1SequenceHeader_see_also See Also + *
+ * \cond WIS_GEN_REFS + * \endcond + */ diff --git a/docs/video/struct/std_video_a_v1_tile_info_flags_struct.h b/docs/video/struct/std_video_a_v1_tile_info_flags_struct.h new file mode 100644 index 000000000..5cc810f6e --- /dev/null +++ b/docs/video/struct/std_video_a_v1_tile_info_flags_struct.h @@ -0,0 +1,50 @@ +/** + * @struct WisStdVideoAV1TileInfoFlags + * @ingroup Structures Video + * + * + * @section WisStdVideoAV1TileInfoFlags_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef struct WisStdVideoAV1TileInfoFlags { + * uint32_t uniform_tile_spacing_flag : 1; + * uint32_t reserved : 31; + * } WisStdVideoAV1TileInfoFlags; + * + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * struct StdVideoAV1TileInfoFlags { + * std::uint32_t uniform_tile_spacing_flag : 1; + * std::uint32_t reserved : 31; + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoAV1TileInfoFlags_memb Members + *
+ * \cond WIS_GEN_DESC + * - `uniform_tile_spacing_flag` Indicates that the tiles are uniformly spaced across the picture. + * - `reserved` No description. + * \endcond + * + * @section WisStdVideoAV1TileInfoFlags_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section WisStdVideoAV1TileInfoFlags_see_also See Also + *
+ * \cond WIS_GEN_REFS + * @see Structs: + * WisStdVideoAV1TileInfo + * \endcond + */ diff --git a/docs/video/struct/std_video_a_v1_tile_info_struct.h b/docs/video/struct/std_video_a_v1_tile_info_struct.h new file mode 100644 index 000000000..058eda81d --- /dev/null +++ b/docs/video/struct/std_video_a_v1_tile_info_struct.h @@ -0,0 +1,74 @@ +/** + * @struct WisStdVideoAV1TileInfo + * @ingroup Structures Video + * + * + * @section WisStdVideoAV1TileInfo_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef struct WisStdVideoAV1TileInfo { + * WisStdVideoAV1TileInfoFlags flags; + * uint8_t TileCols; + * uint8_t TileRows; + * uint16_t context_update_tile_id; + * uint8_t tile_size_bytes_minus_1; + * uint8_t reserved1[7]; + * const uint16_t* pMiColStarts; + * const uint16_t* pMiRowStarts; + * const uint16_t* pWidthInSbsMinus1; + * const uint16_t* pHeightInSbsMinus1; + * } WisStdVideoAV1TileInfo; + * + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * struct StdVideoAV1TileInfo { + * wis::StdVideoAV1TileInfoFlags flags; + * std::uint8_t TileCols; + * std::uint8_t TileRows; + * std::uint16_t context_update_tile_id; + * std::uint8_t tile_size_bytes_minus_1; + * std::array reserved1; + * const std::uint16_t* pMiColStarts; + * const std::uint16_t* pMiRowStarts; + * const std::uint16_t* pWidthInSbsMinus1; + * const std::uint16_t* pHeightInSbsMinus1; + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoAV1TileInfo_memb Members + *
+ * \cond WIS_GEN_DESC + * - `flags` Tile info flags. + * - `TileCols` Number of tiles across the picture. + * - `TileRows` Number of tiles down the picture. + * - `context_update_tile_id` Specifies which tile to use for the CDF update. + * - `tile_size_bytes_minus_1` Specifies the number of bytes needed to code each tile size. + * - `reserved1` No description. + * - `pMiColStarts` Pointer to an array specifying the start column (in MI units) for each tile column. + * - `pMiRowStarts` Pointer to an array specifying the start row (in MI units) for each tile row. + * - `pWidthInSbsMinus1` Pointer to an array of tile widths in superblocks minus 1. + * - `pHeightInSbsMinus1` Pointer to an array of tile heights in superblocks minus 1. + * \endcond + * + * @section WisStdVideoAV1TileInfo_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section WisStdVideoAV1TileInfo_see_also See Also + *
+ * \cond WIS_GEN_REFS + * @see Structs: + * WisStdVideoDecodeAV1PictureInfo + * \endcond + */ diff --git a/docs/video/struct/std_video_a_v1_timing_info_flags_struct.h b/docs/video/struct/std_video_a_v1_timing_info_flags_struct.h new file mode 100644 index 000000000..62caf49e0 --- /dev/null +++ b/docs/video/struct/std_video_a_v1_timing_info_flags_struct.h @@ -0,0 +1,50 @@ +/** + * @struct WisStdVideoAV1TimingInfoFlags + * @ingroup Structures Video + * + * + * @section WisStdVideoAV1TimingInfoFlags_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef struct WisStdVideoAV1TimingInfoFlags { + * uint32_t equal_picture_interval : 1; + * uint32_t reserved : 31; + * } WisStdVideoAV1TimingInfoFlags; + * + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * struct StdVideoAV1TimingInfoFlags { + * std::uint32_t equal_picture_interval : 1; + * std::uint32_t reserved : 31; + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoAV1TimingInfoFlags_memb Members + *
+ * \cond WIS_GEN_DESC + * - `equal_picture_interval` Indicates if pictures @wis_should be displayed with equal intervals. + * - `reserved` No description. + * \endcond + * + * @section WisStdVideoAV1TimingInfoFlags_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section WisStdVideoAV1TimingInfoFlags_see_also See Also + *
+ * \cond WIS_GEN_REFS + * @see Structs: + * WisStdVideoAV1TimingInfo + * \endcond + */ diff --git a/docs/video/struct/std_video_a_v1_timing_info_struct.h b/docs/video/struct/std_video_a_v1_timing_info_struct.h new file mode 100644 index 000000000..c14170efd --- /dev/null +++ b/docs/video/struct/std_video_a_v1_timing_info_struct.h @@ -0,0 +1,56 @@ +/** + * @struct WisStdVideoAV1TimingInfo + * @ingroup Structures Video + * + * + * @section WisStdVideoAV1TimingInfo_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef struct WisStdVideoAV1TimingInfo { + * WisStdVideoAV1TimingInfoFlags flags; + * uint32_t num_units_in_display_tick; + * uint32_t time_scale; + * uint32_t num_ticks_per_picture_minus_1; + * } WisStdVideoAV1TimingInfo; + * + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * struct StdVideoAV1TimingInfo { + * wis::StdVideoAV1TimingInfoFlags flags; + * std::uint32_t num_units_in_display_tick; + * std::uint32_t time_scale; + * std::uint32_t num_ticks_per_picture_minus_1; + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoAV1TimingInfo_memb Members + *
+ * \cond WIS_GEN_DESC + * - `flags` Timing flags. + * - `num_units_in_display_tick` Number of units in a display tick. + * - `time_scale` Time scale. + * - `num_ticks_per_picture_minus_1` Ticks per picture minus 1. + * \endcond + * + * @section WisStdVideoAV1TimingInfo_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section WisStdVideoAV1TimingInfo_see_also See Also + *
+ * \cond WIS_GEN_REFS + * @see Structs: + * WisStdVideoAV1SequenceHeader + * \endcond + */ diff --git a/docs/video/struct/std_video_decode_a_v1_picture_info_flags_struct.h b/docs/video/struct/std_video_decode_a_v1_picture_info_flags_struct.h new file mode 100644 index 000000000..9ebb29882 --- /dev/null +++ b/docs/video/struct/std_video_decode_a_v1_picture_info_flags_struct.h @@ -0,0 +1,134 @@ +/** + * @struct WisStdVideoDecodeAV1PictureInfoFlags + * @ingroup Structures Video + * + * + * @section WisStdVideoDecodeAV1PictureInfoFlags_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef struct WisStdVideoDecodeAV1PictureInfoFlags { + * uint32_t error_resilient_mode : 1; + * uint32_t disable_cdf_update : 1; + * uint32_t use_superres : 1; + * uint32_t render_and_frame_size_different : 1; + * uint32_t allow_screen_content_tools : 1; + * uint32_t is_filter_switchable : 1; + * uint32_t force_integer_mv : 1; + * uint32_t frame_size_override_flag : 1; + * uint32_t buffer_removal_time_present_flag : 1; + * uint32_t allow_intrabc : 1; + * uint32_t frame_refs_short_signaling : 1; + * uint32_t allow_high_precision_mv : 1; + * uint32_t is_motion_mode_switchable : 1; + * uint32_t use_ref_frame_mvs : 1; + * uint32_t disable_frame_end_update_cdf : 1; + * uint32_t allow_warped_motion : 1; + * uint32_t reduced_tx_set : 1; + * uint32_t reference_select : 1; + * uint32_t skip_mode_present : 1; + * uint32_t delta_q_present : 1; + * uint32_t delta_lf_present : 1; + * uint32_t delta_lf_multi : 1; + * uint32_t segmentation_enabled : 1; + * uint32_t segmentation_update_map : 1; + * uint32_t segmentation_temporal_update : 1; + * uint32_t segmentation_update_data : 1; + * uint32_t UsesLr : 1; + * uint32_t usesChromaLr : 1; + * uint32_t apply_grain : 1; + * uint32_t reserved : 3; + * } WisStdVideoDecodeAV1PictureInfoFlags; + * + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * struct StdVideoDecodeAV1PictureInfoFlags { + * std::uint32_t error_resilient_mode : 1; + * std::uint32_t disable_cdf_update : 1; + * std::uint32_t use_superres : 1; + * std::uint32_t render_and_frame_size_different : 1; + * std::uint32_t allow_screen_content_tools : 1; + * std::uint32_t is_filter_switchable : 1; + * std::uint32_t force_integer_mv : 1; + * std::uint32_t frame_size_override_flag : 1; + * std::uint32_t buffer_removal_time_present_flag : 1; + * std::uint32_t allow_intrabc : 1; + * std::uint32_t frame_refs_short_signaling : 1; + * std::uint32_t allow_high_precision_mv : 1; + * std::uint32_t is_motion_mode_switchable : 1; + * std::uint32_t use_ref_frame_mvs : 1; + * std::uint32_t disable_frame_end_update_cdf : 1; + * std::uint32_t allow_warped_motion : 1; + * std::uint32_t reduced_tx_set : 1; + * std::uint32_t reference_select : 1; + * std::uint32_t skip_mode_present : 1; + * std::uint32_t delta_q_present : 1; + * std::uint32_t delta_lf_present : 1; + * std::uint32_t delta_lf_multi : 1; + * std::uint32_t segmentation_enabled : 1; + * std::uint32_t segmentation_update_map : 1; + * std::uint32_t segmentation_temporal_update : 1; + * std::uint32_t segmentation_update_data : 1; + * std::uint32_t UsesLr : 1; + * std::uint32_t usesChromaLr : 1; + * std::uint32_t apply_grain : 1; + * std::uint32_t reserved : 3; + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoDecodeAV1PictureInfoFlags_memb Members + *
+ * \cond WIS_GEN_DESC + * - `error_resilient_mode` Indicates error resilient mode is enabled. + * - `disable_cdf_update` Indicates CDF update is disabled. + * - `use_superres` Indicates superresolution is enabled for this frame. + * - `render_and_frame_size_different` Indicates actual frame size and render frame size are different. + * - `allow_screen_content_tools` Indicates screen content tools are allowed. + * - `is_filter_switchable` Indicates whether interpolation filter is switchable. + * - `force_integer_mv` Indicates whether motion vectors @wis_must be forced to integer. + * - `frame_size_override_flag` Indicates if frame size override is set. + * - `buffer_removal_time_present_flag` Indicates whether buffer removal time is present. + * - `allow_intrabc` Indicates if intra block copy is allowed. + * - `frame_refs_short_signaling` Indicates if reference frames are completely decided by last_frame_idx. + * - `allow_high_precision_mv` Indicates whether high precision motion vectors are allowed. + * - `is_motion_mode_switchable` Indicates whether motion mode is switchable. + * - `use_ref_frame_mvs` Indicates whether reference frame MVs are used. + * - `disable_frame_end_update_cdf` Specifies whether the frame end CDF update is skipped. + * - `allow_warped_motion` Indicates whether warped motion is allowed for this frame. + * - `reduced_tx_set` Indicates whether the frame uses a reduced transform set. + * - `reference_select` Specifies that the mode info for inter blocks contains the syntax element comp_mode. + * - `skip_mode_present` Specifies whether skip mode is allowed. + * - `delta_q_present` Specifies whether a delta q index is present for the frame. + * - `delta_lf_present` Specifies whether delta loop filter values are present. + * - `delta_lf_multi` Specifies whether independent delta loop filter values are used. + * - `segmentation_enabled` Indicates if segmentation is enabled. + * - `segmentation_update_map` Indicates if segmentation map is updated. + * - `segmentation_temporal_update` Indicates if temporal segmentation is updated. + * - `segmentation_update_data` Indicates if segmentation feature data is updated. + * - `UsesLr` Indicates if loop restoration is used. + * - `usesChromaLr` Indicates if loop restoration is used for chroma. + * - `apply_grain` Indicates if film grain @wis_should be applied. + * - `reserved` No description. + * \endcond + * + * @section WisStdVideoDecodeAV1PictureInfoFlags_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section WisStdVideoDecodeAV1PictureInfoFlags_see_also See Also + *
+ * \cond WIS_GEN_REFS + * @see Structs: + * WisStdVideoDecodeAV1PictureInfo + * \endcond + */ diff --git a/docs/video/struct/std_video_decode_a_v1_picture_info_struct.h b/docs/video/struct/std_video_decode_a_v1_picture_info_struct.h new file mode 100644 index 000000000..4b714b13d --- /dev/null +++ b/docs/video/struct/std_video_decode_a_v1_picture_info_struct.h @@ -0,0 +1,115 @@ +/** + * @struct WisStdVideoDecodeAV1PictureInfo + * @ingroup Structures Video + * + * + * @section WisStdVideoDecodeAV1PictureInfo_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef struct WisStdVideoDecodeAV1PictureInfo { + * WisStdVideoDecodeAV1PictureInfoFlags flags; + * WisStdVideoAV1FrameType frame_type; + * uint32_t current_frame_id; + * uint8_t OrderHint; + * uint8_t primary_ref_frame; + * uint8_t refresh_frame_flags; + * uint8_t reserved1; + * WisStdVideoAV1InterpolationFilter interpolation_filter; + * WisStdVideoAV1TxMode TxMode; + * uint8_t delta_q_res; + * uint8_t delta_lf_res; + * uint8_t SkipModeFrame[2]; + * uint8_t coded_denom; + * uint8_t reserved2[3]; + * uint8_t OrderHints[8]; + * uint32_t expectedFrameId[8]; + * const WisStdVideoAV1TileInfo* pTileInfo; + * const WisStdVideoAV1Quantization* pQuantization; + * const WisStdVideoAV1Segmentation* pSegmentation; + * const WisStdVideoAV1LoopFilter* pLoopFilter; + * const WisStdVideoAV1CDEF* pCDEF; + * const WisStdVideoAV1LoopRestoration* pLoopRestoration; + * const WisStdVideoAV1GlobalMotion* pGlobalMotion; + * const WisStdVideoAV1FilmGrain* pFilmGrain; + * } WisStdVideoDecodeAV1PictureInfo; + * + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * struct StdVideoDecodeAV1PictureInfo { + * wis::StdVideoDecodeAV1PictureInfoFlags flags; + * wis::StdVideoAV1FrameType frame_type; + * std::uint32_t current_frame_id; + * std::uint8_t OrderHint; + * std::uint8_t primary_ref_frame; + * std::uint8_t refresh_frame_flags; + * std::uint8_t reserved1; + * wis::StdVideoAV1InterpolationFilter interpolation_filter; + * wis::StdVideoAV1TxMode TxMode; + * std::uint8_t delta_q_res; + * std::uint8_t delta_lf_res; + * std::array SkipModeFrame; + * std::uint8_t coded_denom; + * std::array reserved2; + * std::array OrderHints; + * std::array expectedFrameId; + * const wis::StdVideoAV1TileInfo* pTileInfo; + * const wis::StdVideoAV1Quantization* pQuantization; + * const wis::StdVideoAV1Segmentation* pSegmentation; + * const wis::StdVideoAV1LoopFilter* pLoopFilter; + * const wis::StdVideoAV1CDEF* pCDEF; + * const wis::StdVideoAV1LoopRestoration* pLoopRestoration; + * const wis::StdVideoAV1GlobalMotion* pGlobalMotion; + * const wis::StdVideoAV1FilmGrain* pFilmGrain; + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoDecodeAV1PictureInfo_memb Members + *
+ * \cond WIS_GEN_DESC + * - `flags` Decode picture info flags. + * - `frame_type` Frame type: Key, Inter, Intra-only, or Switch. + * - `current_frame_id` Specifies the frame ID for the current frame. + * - `OrderHint` Order hint of the current frame used for motion vector scaling. + * - `primary_ref_frame` Index of the reference frame containing the CDF values to be loaded at the start of the frame. + * - `refresh_frame_flags` An 8-bit mask that specifies which reference frame slots will be updated with the current + * frame. + * - `reserved1` No description. + * - `interpolation_filter` Specifies the filter selection used for performing inter prediction. + * - `TxMode` Specifies how the transform size is determined. + * - `delta_q_res` Specifies the left shift to be applied to decoded delta q values. + * - `delta_lf_res` Specifies the left shift to be applied to decoded delta loop filter values. + * - `SkipModeFrame` Specifies the indices of the reference frames to be used for skip mode. + * - `coded_denom` Denominator for frame size calculation if superres is enabled. + * - `reserved2` No description. + * - `OrderHints` Order hints of the decoded reference frames. + * - `expectedFrameId` Expected frame IDs for reference frames. + * - `pTileInfo` Pointer to AV1 tile information. + * - `pQuantization` Pointer to standard quantization matrices and values. + * - `pSegmentation` Pointer to segmentation parameter information. + * - `pLoopFilter` Pointer to loop filter parameters. + * - `pCDEF` Pointer to CDEF parameters. + * - `pLoopRestoration` Pointer to loop restoration parameters. + * - `pGlobalMotion` Pointer to global motion parameters. + * - `pFilmGrain` Pointer to film grain synthesis parameters. + * \endcond + * + * @section WisStdVideoDecodeAV1PictureInfo_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section WisStdVideoDecodeAV1PictureInfo_see_also See Also + *
+ * \cond WIS_GEN_REFS + * \endcond + */ diff --git a/docs/video/struct/std_video_decode_a_v1_reference_info_flags_struct.h b/docs/video/struct/std_video_decode_a_v1_reference_info_flags_struct.h new file mode 100644 index 000000000..f8f9fd781 --- /dev/null +++ b/docs/video/struct/std_video_decode_a_v1_reference_info_flags_struct.h @@ -0,0 +1,53 @@ +/** + * @struct WisStdVideoDecodeAV1ReferenceInfoFlags + * @ingroup Structures Video + * + * + * @section WisStdVideoDecodeAV1ReferenceInfoFlags_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef struct WisStdVideoDecodeAV1ReferenceInfoFlags { + * uint32_t disable_frame_end_update_cdf : 1; + * uint32_t segmentation_enabled : 1; + * uint32_t reserved : 30; + * } WisStdVideoDecodeAV1ReferenceInfoFlags; + * + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * struct StdVideoDecodeAV1ReferenceInfoFlags { + * std::uint32_t disable_frame_end_update_cdf : 1; + * std::uint32_t segmentation_enabled : 1; + * std::uint32_t reserved : 30; + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoDecodeAV1ReferenceInfoFlags_memb Members + *
+ * \cond WIS_GEN_DESC + * - `disable_frame_end_update_cdf` Reference originally had disabled frame end CDF update. + * - `segmentation_enabled` Reference originally had segmentation enabled. + * - `reserved` No description. + * \endcond + * + * @section WisStdVideoDecodeAV1ReferenceInfoFlags_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section WisStdVideoDecodeAV1ReferenceInfoFlags_see_also See Also + *
+ * \cond WIS_GEN_REFS + * @see Structs: + * WisStdVideoDecodeAV1ReferenceInfo + * \endcond + */ diff --git a/docs/video/struct/std_video_decode_a_v1_reference_info_struct.h b/docs/video/struct/std_video_decode_a_v1_reference_info_struct.h new file mode 100644 index 000000000..90a352d0a --- /dev/null +++ b/docs/video/struct/std_video_decode_a_v1_reference_info_struct.h @@ -0,0 +1,58 @@ +/** + * @struct WisStdVideoDecodeAV1ReferenceInfo + * @ingroup Structures Video + * + * + * @section WisStdVideoDecodeAV1ReferenceInfo_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef struct WisStdVideoDecodeAV1ReferenceInfo { + * WisStdVideoDecodeAV1ReferenceInfoFlags flags; + * uint8_t frame_type; + * uint8_t RefFrameSignBias; + * uint8_t OrderHint; + * uint8_t SavedOrderHints[8]; + * } WisStdVideoDecodeAV1ReferenceInfo; + * + * ``` + * C++ version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * struct StdVideoDecodeAV1ReferenceInfo { + * wis::StdVideoDecodeAV1ReferenceInfoFlags flags; + * std::uint8_t frame_type; + * std::uint8_t RefFrameSignBias; + * std::uint8_t OrderHint; + * std::array SavedOrderHints; + * }; + * } + * ``` + * \endcond + * + * @section WisStdVideoDecodeAV1ReferenceInfo_memb Members + *
+ * \cond WIS_GEN_DESC + * - `flags` Reference information flags. + * - `frame_type` Frame type of the reference frame. + * - `RefFrameSignBias` Specifies the direction of the reference frame relative to other references used in motion + * vector derivation. + * - `OrderHint` Order hint of the reference frame. + * - `SavedOrderHints` Saved order hints when this reference frame was decoded. + * \endcond + * + * @section WisStdVideoDecodeAV1ReferenceInfo_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section WisStdVideoDecodeAV1ReferenceInfo_see_also See Also + *
+ * \cond WIS_GEN_REFS + * \endcond + */ diff --git a/docs/video/struct/video_decode_input_desc_struct.h b/docs/video/struct/video_decode_input_desc_struct.h new file mode 100644 index 000000000..c05dd59ff --- /dev/null +++ b/docs/video/struct/video_decode_input_desc_struct.h @@ -0,0 +1,92 @@ +/** + * @struct WisVideoDecodeInputDesc + * @ingroup Structures Video + * + * + * @section WisVideoDecodeInputDesc_spec Specification + *
+ * + * \cond WIS_GEN_CODE + * C Version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef struct WisVideoDecodeInputDesc { + * WisBufferView bitstream_buffer; + * uint64_t offset; + * uint64_t size; + * } WisVideoDecodeInputDesc; + * ``` + *
+ * C Implementation Specific Version: + * ```c + * // Provided by Wisdom 0.7.1. + * typedef struct WisVKVideoDecodeInputDesc { + * WisVKBufferView bitstream_buffer; + * uint64_t offset; + * uint64_t size; + * } WisVKVideoDecodeInputDesc; + * + * // Provided by Wisdom 0.7.1. + * typedef struct WisDX12VideoDecodeInputDesc { + * WisDX12BufferView bitstream_buffer; + * uint64_t offset; + * uint64_t size; + * } WisDX12VideoDecodeInputDesc; + * ``` + *
+ * + * C++ Version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * struct VideoDecodeInputDesc { + * wis::BufferView bitstream_buffer; + * std::uint64_t offset; + * std::uint64_t size; + * }; + * } + * ``` + *
+ * C++ Implementation Specific Version: + * ```cpp + * namespace wis{ + * // Provided by Wisdom 0.7.1. + * struct VKVideoDecodeInputDesc { + * wis::VKBufferView bitstream_buffer; + * std::uint64_t offset; + * std::uint64_t size; + * }; + * + * // Provided by Wisdom 0.7.1. + * struct DX12VideoDecodeInputDesc { + * wis::DX12BufferView bitstream_buffer; + * std::uint64_t offset; + * std::uint64_t size; + * }; + * } + * ``` + *
+ * \endcond + * + * @section WisVideoDecodeInputDesc_memb Members + *
+ * \cond WIS_GEN_DESC + * - `bitstream_buffer` Input description for a video decode operation that uses a bitstream buffer as input. The buffer + * view @wis_should contain the compressed video data to be decoded. + * - `offset` Offset in the buffer where the bistream data is located. + * - `size` Size of the bitstream data in bytes. + * \endcond + * + * @section WisVideoDecodeInputDesc_descr Description + *
+ * + * \cond WIS_GEN_WIS_IDS + * \endcond + * + * @section WisVideoDecodeInputDesc_see_also See Also + *
+ * \cond WIS_GEN_REFS + * @see Functions: + * wisVideoDecodeCommandListDecodeFrame + * \endcond + */ diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 153c85d80..571c122ce 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -48,6 +48,13 @@ add_custom_target( include(cmake/deps.cmake) +# Copy assets folder +add_custom_target( + copy_assets + COMMAND ${CMAKE_COMMAND} -E echo "Copying assets to example binaries..." + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_CURRENT_SOURCE_DIR}/assets ${EXAMPLE_BIN_OUTPUT}/assets) + add_example_suite(backend) add_example_suite(compute_particles_c) add_example_suite(hello_triangle) diff --git a/examples/assets/avif_sample.avif b/examples/assets/avif_sample.avif new file mode 100644 index 0000000000000000000000000000000000000000..e8b52e125145816f81d6d02c38f9d9f3898f87d1 GIT binary patch literal 110925 zcmXteW2`Vd6XmsS+qP}nwr$(CZ9mtxZQHhe_x*OW({#=`(=^i`O`B#4004kt=HlsK z=w@jK@SoXQnlaj18vc(j+M2o;{x9~Q5n7noIQ>5g0N`M0?DGHl|3^3nOBdV!D**rV zc$PNy#{W|y004mhwf}hlfJXqpdhP#^*wWJO|0estQPls0DbRo6|0zQ^2FCwUHA@F4 zhyRen(!tpNKSZ%~b};?l0002^e;wq11jf*fQ8e*_o`3hF;VvvjaE z{Ga~M{#yVrU=Z+s$&GDI3|)`_prH6K-T!{|fUsZ-m?rkY%mr2A7Ny1h`sN`BK*;{z zB#xsv2!f~pfFCsQQ}s&(w6?RXrA+g3HCHb&2!taM!elQ1j=c;3wZxDWKnjazgl9QrU-fR1wH2}rZ4B0m^BUr(=noM)4NQMX7Jh~yvGUJl zj4rIp!qtq}BR#<|}qDtw_n>I*2#C86wkm{-xsrFClBgZFTuY`k0 z=QtBjiB0Vw#o3k^Ei@P;65&17Pbef{mWvy03!UphOsX$*8rj_kn{PrHxksNXimM9w zNPr(s*D6>LG3=50KgbJdvp!c`yMv&wBcvMyG z`u&d;cXDcpoFdhvQ_sZE^Tz>}6=e8egZc^Scv#G7>*AY+~!;&U;_Gdb0<3$ISeh(>5@&Hy1E)d zj?4CrVxa(G_~uSMDTw~*QE|gCMKcrOJ-x;$yf_vft9$p6zV^sKyx_KuUL2caaaH#o z9eaq`uj{EL)6o&yPF&m9kFu{VbF*YbCSr{Qikqd4db=4F{ zY+n8>V$cSEHDi8W~a zHo~awL+x`ZR;xS5bo(v=`xeRc;TeQw_;QcD#$8qVq66!yE8`ee$M`~ z=o&0I9OH?Isb}WDY9g}zC4{&~bNFF8fkbP!Vo+F?o^H=N%i@NA57LZ;p}a?^bb?%7 zj%DveAu{pzjxQEk%qOsBWDt(eG+|>m+N_9>y+C_X9iFPA-U8tiI^%ft+gv611_^Fk zF6U#3ha5(RLEF=eGprgo%~BCz=#Qwi7X@N&{1!IDClqPoV-k} z2cfkhX<4D<)FvNX+vq8ODZt4UD$m6*z-x=?m1px7uj?V(UzBdjQP0YcxK{RlLP-Ww z2myuv^4ntN2Dm)E227^5VIiZ?|JzMPCr=Sr#~N?ZojSB#yc2k1HL_3TIr5=#`M%?v z&jRk~nAO61BrdRv0${RpFy?&Sz)euF*rZ;Q%6I!yrL->wXt=N(+KmY-0NWC%ZT0(U zDwc5sxZF{P=%q*dJ98aP^7DkNSMB|WBjXYO`MBSy!2{v&Phzx1;^qS#`v>0PnFR?k zmezSL_VBgxv=S}M$8mH5J|@6De%LEg!MynPFU|e2RG`HJC(2EWpi*}LFo#Up3fGCm z48Ra=cKQS-(Ckuer*IptSWO)j`{z=H23{TWgA6(R*0tzJ(gW{GZ<@3@{X`^J4657Z z)>ZfKTM0ZIIb5VmNxsn$+8s*CxEF-oaO$RNM<*@|7uAO!A}!``u8iZsVm<&9cd8sz zbiVq}geM2p{4-)hD7Lz%X4RLdFt@R_6Dd|d;vqgVGj6J&N@IYHaAUtP17Hwa{OY1u zmGq}d<>k(<-}-9^o;7b)$!p(tB!(nvL<%^H2UbH@1ltGEce#~5d5MpAQPb&KOwWM_ ztX20pnNAb<%(`gs9#s>w<5{P>ZDl!X`mE-4n|21Nfh1{^ZYOTqt**@JW_GN#gklD8#-Dx6^`ib>z|> z=eO_1f07N}BOv8PV_CP|qXD>Zci)ttUU?~FkhXf-}Ha4P+FAA*wFCD_ZNz4LqXY1U{Zb@6e5>R?3XiI$k$^^Ci4RaoikYg;+wvJ|r zwM0%Hv|>&n-X}L+j66Wby0mA0D^A!3MLbkCi5#0~9Uq=$r*|E5i z&wYwhD;5u_sttgciX0N`#gZ9|=tH2R#(R2XEuZJ(N33@gALRsm5+Z$nF9*98U{ANQ zq`(dwy?Pl^XPb!I{ zc4(!;z8=FPG0+iFqJC7!``8RR4qG14=c3rYCslw#0cisjR^e4$Btyo)xP7UvGWEV= z*Kj6-^O9lo-#wHfPAiPx>=F$RO_Wh@p>Po+M4EZtaL4&bMaccN(QxJ8Un=gDC>5dB z=y3t6s6!=a%F?N_$*YB+z%TBsFK5#Qgs?NjL&9o<{PUS?u*65^l5rnlc@qEb|Q?d2JL=s z_M9Jv&+77C;Qd2a;}kbM(+(eMTLf+;)uY%_uwMps_rxM1AN;SGjkVv^yr91y`467U z>a^MZRB96}ah?U@B_ZiW(B6`sWcg)HX)S%;?oa_n10RVvgrhtNuppS{`o%Tf@4LS+UzF z!>Zd8c95C|>If=!ve zAH*YO*NRJ9ng<=1zD11B*0Cj>&bV(k+rl=4Qm+?!_(Iol_S*iz z+vv3>DQzf5s=C+S5D9cY=EKRJgX;w1mYhgPjO90)cj_-Nu?@+h2g+U(_Q?6u2~PO& zdld!0GIK+!4r!T?G{(p^e)XA~n6z$Pf7aNd>U!*| zZ#+Rs`(u+MGsUe5AbkfHJ>uCm?Z_+W*5|$5A-HZ+oLyB{njhmG`NQrur{cGJuqShI zh!5Iu7p6=7YmnK401?Zha?KBCO|#ACxaXyb@V?k9a0oNOP6`hd#va;wX_z&wEQhVS zg*rkj>cNAjU#gE<{{&@f;h>Rrr@&A2VHh|-rE_;>LoReu~o-j}-Fx3_@J6 zvp0=Grv}+g1*Nmt)8-(g&N%2{1j6 z@2&i)N;ln76pG(b^5*?O5dU2$1c4vyy*ll)Ln2>hmpDqdgnTS?;#XkRs>@VF z+BQLU&z65YwLGgK@qsX*%)-*$p|)++|>bqO(0fQrlg}v_r>cXoy*U8Z`vw7O##8m^ z<(xorXVP@8E=O-*7`%h#(6C3hwcy*1{$!8&5jheP^h1UXOV06MeJH9-Qh)@ESsky~ zufywSV833lw*tNAR#IihNi@M{YA$PgU(YFxjJMK`CxRIFg6oI@ewElL;u`{PPJeB(m<7;zP`B(y`%$g%{6X&Bjmxd&kuG<2viI;fmPh-+q71 zgiR!ccj{pgJvgxHp5lQv#bj6Q$!(tA+t&=Vu1Ju7FSXuVh?Dmzp-w+$r5ruXsbdiC z&tw?GuMWe$K3My(UEp`bwVfHBq1uRf@`!$~p09_K6jz0xb7d&CSQNV;HNlFSc24l` zAf3;TH^(_$UuC}FMY|BhqgI0e*ihYqagtNF9JA3^cwlg#+RBfc zyqAMsm~k>nKB|^J?nyLD*$`FM_ze!C21ENfufyb&S;zabg#7z5<*IJNwmyTLuyDF3 zFMcjSv4;ME$X%$yeo9@N`zjZX(z@N+pl|6snRDLui>+6Ug@iUg46$rkD3mPUxbE4? z1SXyRwDT9!v6z8NkqYE>p2XnV@9Mu_6gw^AHRv-w#JGLrjfr6;eP z6LAYy@u^X$T~&ZfWdsY;X5}U~yr+vv-p@d6a6Eg$Q`F#|!<@JD3Tu|4oyA-M+bu4aiqG+<< z<{y{V--79v=+$kA&>%xc_pu3gkNy#{%jrAoe;Uwikus6{K1oA$l$0o3A+O-wE~m@0 zSei`h(xDcerNUz#snfccPRaOPWolUoan9L9S;a}Er#j$2a)6-+U{SwD@U&0QXcX14 z$6_U~X#cw`y6@;TsbBUrSFkJv#Bt>e$0%`lW40Q2<& zW4&wl!XqbjuH6b!#5=4wamP!lNh`@>oM87MPo?s86uTzED9lD2c$XYe)^RzqRHpXA z0J4(vWZ8jo+*VxOBSX_t?t&9F5YUpe<{IulPsmTx>wQ9t>QNDO|7xRF5Ml;olCT3& z=rBXLjxyg)B4{zT!Ods!U5YFAc97m<>y+^cA_Ip{~|&IQXE#e1k1&n_^bPx6y3EfOM9_Np}^ae`-cu-y9C@OpZ` z{^j_RvGA44r8)}NfhZ^jL}>yM%wl2k1)dJ*Zw`_FHcnWQBv4243{>W*g}fEh%Q&PW z3uJI!=!deIe6hWCmJXkV$1X61NTI>^k<#7YN9l<+ zf4i6_B6Lt(sb&C!u@&b#jZz8PzW^h%`AmX6{>9@LuXUPM^=#B@Hu^k5C?wVFxSXJ1 z?(jB%pIn-T>ig?ozRc$!>78lj?FuWR&mfAF=ITVO_#r}X4v~)YWp<;G?5v)FQ7!T< zI@aDV!y1k}hoX&*7PB0~9G#nF+D?GYcE~*dwWH?YM0a~FH zIb-|m|4JNAt|%mz^3&}<-IJN{sd=85UJMC7I$+k*fNtEz_zB_#3JjSzX2KF*wG})F?RJ9Eyww68{)9W2(b!Mi zLyFIJ&8(W_@9h^l+|owdCPUE@E~JbDzYeVJTdM>oB~Bh}0niV|4>2K7vG~UvfY?go z8oWA?f-@^$*crdb@=+2u5!8O^kDzA;2l%O`P?SoRMi^>!7lzZE~2uRQorCXF%I( zsC4ijj_U(l+^%F2M3vEq#h(V)grC%i%E9Xnz*OwWA-Gp>* zo)??g`uO#QN^Of(xDJE))9|4sXI^O9%HlzSyRbNc)>2EDK#|Sp0v#>x8a2eiE+`j^ z%vTqJL(xsIJ28{{jZ%N`B;nGp_goRusD6a6FF%S}4bfrav@u0b9Xja;3e~DuiH+d= ziVo5DIOrS$&3Un+nMPM*x3OBGrAnTNSaVzx3W zlb?|{JfHPwkn0Rf2bQ6%%|Jq=ySF1-ePmKKMebm%;$`3u!?6o?Y{Uk^b|9mDmjM|; zH9e4Sz+=cl@QQ%)tIFl%Je;MjbuR8SKOj$~F@svFxQ<;2oX(^eHV-T4qf~XQ=w)= zNt=HsUjiXbW1~%6KruQ|4bxh&8=BbGlnWI2$n&jE@+27J?$D>GHtOtiZI}|8PjMI0 z{!V;F7S@b!A`}Ioua#_#eO}o+qAFgPa@lIem9t51hqytJWHxTbTL(2#+is!+|76oh znxJ=HX9zgK87QGILPri>msFfyG!0f7I{6?)cEcso`fLPz_UP39cfx#7TUK{#anL-% z;CP-9)MoeKJ$`Zl@tgQC8~m;EHQ&*RKt;!?vLMCMn2l`k-#Y_W5ASFvy%)yCTClA| zj`1dZJNnZzrFE09fF4_MNq#iD6Xr4wsQVhx&z>PmEiNbP*^DqL-on&5Ps^G2`@h+C zJW0Jv^&psUT$p5Na_ThA(7Oh94wEPdnfv>KmptQw!f1o3o&LH-`@)w$?{$<8rMwFo zgnIR_^QA}DP>Et^l_?ex5E(}=(|Tl5eW&(^tq(Pt;Z{b92U zjLAcqW1&t(KDGC44xo62acWd#*uc=QbimHR^`MaB0}*bGy0CCKO}E+QIvz>xpZ=(b`09G zYi|8Y?aN}X)?93K#|(T9Qxx9mnNRmS(o^-66t{FRE)oQUm}z$Xhn~!^QAi26vD~sB z6cv91Fw>yE3DVICBI830cg3EY&kK5(BNLN+6o{K0CT=*};?(?Kzcfv!sO7V%&#~V& zqi*TccF}_K^YE;LLdWsa_}eL~W-EJ9amQ4|B0*u>#qAjuM&CzxmGa@1YCSJPA%b`4 z>=T`JSitPz4Q!7WtPB)`f(=2golC+-u{Y(CpS!JWvviHbozFFTT!A!Ml<@3N^nIa;tT@>sU9q46lYblB zHPzB@>KNzAzpv5!0nu`+rfq51c)yiD47OpkTXReqWw@H6QKSc&-K)B7_$}W@l9`s( zxKGWhV%Q%pWK5G4xieDbe$ZOD2#?uHcN5ZB?zU@U9j9X3C{1MU_{@Qw{N2}GNh+n~ zlGJ)XGOAeLmzP?*wl?HP(#E8q*R>b^_(-@dYpj@o@}SM~f=?ii1)3GkxKls#0&q0u z3E4WXDJ(;<*HKRAUnV{$VafOf|B5#XoSFAPdOU8hInKK7z0i;5lAdV?z`;_t&JB>} zSN@K7E0UiRdwOY2>Q89-1*0}?ejb5nwOT1YF5BT9q%dd0v$tZXTMt}Tq7hf&zNDYl zMNYwUbBH;w`4`+o6iK*BIMT& zD%8PufqI;&G*^om%IO|}ngQ}c;1+8H?0px4vX2NQYf{vnJx%SRYoV=tlb)YvvUx?h zcGktHNcyHUqpVgzyWD5!F8L*JN^?V084vn{pwqJAn6c|GM=YVrPRdI)UDBMDbl#{J zB<3b3L33a*-sd3=fQn8hUvRn@yQKwislPxJn&fux|%y7+T@k@urQfXO7JX|bEQwp#<>KTP|NxoR@UV!JeQ(vqZRnw-H;vBunOn*ej7$R z;{J_gA=3raaL^;Z(}~+?A$P(j=X8?&2oe0zQZhgzW(~XLT=Uz_)?~UR`^vi(*1fhLc8&;6?jW2o_MTf+88a~`S_-3Xw{#wd7O$a9pMm< zMWiuS9uWEaOK7Ig8_yM8zLDd8dk?tlW3ha~> z!V=XVh(b%YyL`8n{qI7mytnmy1c$ev?RFs1P*;Z%qvz@^7r>9z>|l?wTvMp7@|E5`vdls73VG8^fIwd9}ZVv>p z*fKftLe}!C&|)eTfxXQ#)BMPFw@wikSVxy?H1UO^a(gEe;MO+K`woQ) zjL(&Oj3^(|Ip~{37~@ss%<=|~OMHRL*U0^_pV>ymp;`@aDt||A znmmfrxY1yejP@7a%Z4@ws7c6@o{@S{51HZ>5%kK~d~dJPc!$k%RARRqbit~-djL84 z!!P!A>&X@L@+LKre=|)_M_s29q<^{T?q(eeYwnftKtH8Jz3sR89RJ1~8xNR(R^>Ec z`(dnSJ|oV|^!1!Y4jI2DK5EJ8aisUfl;i8yNKbX^Np!ed@K4n7OlrS~dUq{NH(vNC zpH@+Q51;s_D9lboINdW7?>ORajq1EoRCIp#8r}4p=7a1o+l$>?0@3O!PlJoBI5MhD_?Lg|2Q{wh(=(3s{mZP}-gZ7lhzPU6 z4S~Ns)zmDqf~9qW(Bs1e0<&@v-LN}quluA<1G|on`BhN z0!me*AfUhmTr-bez4cD%%$4>Y*YH$N;yK9pab(lA9ZxTvjXJX}i=~IG9kj`r)1uUK z9*H%#zsEHiA(LsTDHP3qXX=wi^AC79A+~nKd-15D)re%|4{iXEO(MvwH^xE#HyY4Z z&n;}^$ZfK1wY7|3=QK%F%Y*v-1b5P5-_!(lUm?J()_O?qUsBl(Dvj&(d~T?fV`unG zzuJjnawE)}nYg(bOz4nWhYS1g01}?J4moruDhYrJ*F4dUyY-p~cyW&~G8!Q*2cNaQ zn0S&dOH8*W^U&HYdL-Fn#^Nd5GE_v;S`95=fS>}!eT`fah;~-lV&(6NoiM^@b8JvJ z+=q*shuQYW5V2TEDMCAAU!ZBlq<@&~-$T_p(PS znP^3=MsG^py;6s?#~pqrxo+Pr73Ug%<8S+7$<(%#F{Z^zkLoX@pZ?M?3~&~#Rp^;E zk%C!?jUwK_7haYos)D%AK_)NAaz%*Ob*sGb4yE-)UEtagZAJj^Hv$`Q*X30k>7L~! zx$Wg+%gS9`hT(Mo5QEJkR#V%qCcH4vMT!v(FZvjSaY_-jqafQ@u)*kS)L(MHz0*b2 zgqv|JO?f*rLP;UGITW|!B!Up37js7&4ZX_i4`x|gRbqqe&6}tlUoe!Hsk3G0eiC{c zrzuM%$+&{_iF7T;Qs#F2=DHb)a`-S`BY22xrNnpCd%n0gtq8ZS2VBi|c9CRp(G1%Q z75x!OPeb4yf1_GYg^02;Uzv*zMe1;=i+|BpnuOj^#D8aU^Cid8{jVsyAJEiU4Fc9U znEeLHLxioGejo=n|8KnuFL3?T5G;#zm<@3-bgeO7Rsa(Ef(OAHVpzrq#$S<0l0yCp zA093lkD7*UgH`iC6BbwF^S*`_9u8k1=S?jXSwu6L9a%>DzV8m9VD~bhj9w)ZR}TnV zFJ^Y=rjIG>m&HyxRNexx*AF9}3SpNvr-VWaBvtW9Sf)5grG13;pK@4=Tr_Zo2`4IJ zz2G=Dq0>J^Kf%{zAaav|`JshCa)9}>o0bt8=|i#-Y3ukVr0svPxNsLejbXG-eyrih z(saC(=dZA}tS9j+noLzL;{SwNd+UfMsd0Y|Uq91;+EtOuy1kZ23D{hZ6p8o}9*VA@ zeDZ$x9FvuZwUZhpHwY+wG?1t;t!b?YjBtna`m>#0@ie|#5D8>wXY_k1&v(%&1zDn* zPt7-sHmwKWPnKJ$DAOsOlN1FiRdr6>DIG74`jtINGK(kb6@!u>SmsLjbH-9f|LiBtNvS@V zH~oM<#!P8axkwwmk@Zx|=IPGl-fgc|~1%XYee2K@+bL(?YIZ{Ns;`KxGO1#=AbTY2n7e3rdaPh}%jnrVG}Ew3ISKfnfISySBW|SOPHz`y+wjC zZH{6bg;hX}YMu8^#f?(yZXUs?ixl)_fRb9p=5%iS-p(6c&-ctv>(Z;NEtuN00#Qs? z34Sb{dF)GmLX(}UX7+kCPV1>63jQQocwgm*H47xAX#fl1OuZAoVNLbi>qq+!UmrgF zv9|cj6ura}*a`yCYl=oW9aSRC(gkf4@<4qb%!@p z(g@}41d(5tHma8SE>^@yz<3lwbXx0xeucGr+#z)>9!ghWEUM%S{DNo6c{P6RK)`Jsi7TiMS$0X#g;ne8g&HPae32k243lkoNIjd&*`fb=vgc4`1GXcdqI_>GN z>l53Q#<}z=swT5DV9jRn9mke_iJ<*JR+)W8Y=+$JLi)Kq0^i%$TlfosgJrsAJiXMd zbINTj^LWq(KauR6eZv_dBe@+D!H$j?>*V*wz;F-EA_!f0lgFD&VPee0;w=6FJVaXE zWMR2Hw==%{#}tO~CzqzA*)CBvYYJ&WHhTpUvW$s-6Vp0OQ#H`@>oBoLUsu*dOsqQY z{P|BDbhZ#{7l|DMXVAkVgTUz%=b9(NpG`5uZ5<2*PJv8sjBw6=a>XArFW96c!R8%M zDKLCpzTKE!9ikX?uEkfT#qn3dyJAn*qf)2)K0-m-p{o6~)J8-ppWQH}HhZD}SmV+p zW;5^W8(^>$2%Jn$vLeEhoVx~6iD>^s#}g(T6eJi^UCxwXG91w8zS9@tejmw0_yCcz zhoo+b;5L*z<2$*j)N1#%UGPzG))BsgA^kL-2hl|hA!$H-oatLK?&dqX7(j6wXsO3b z0jOyBY0JbtWR#A&{laRB5=h==>!Nd#oXTbP$Ydo4iQSOL$0!-3nT};VQt`&N@!QRt z$Gxsq8To;c#g^h;&l>&1GRS!tmtK-@v>XZqhXK=r9(q0*9ezQx*AxN)P#PZY$L;y^ znVw5x;I~p6l}czsJ{6e0ZB#)aOW~L(ssH0Ti@lTP53HTNkp`GHLmB%QedrrXN>sI| zFolYfd{JGiP4kG@S>6*l0R|%QXVqvIZV8079cAu@3wQYJL3sOw8y5#6@X5$)y?Wv! zzO7ta#xq`ZqaAP8Z7>>gpRtOD1&K|QnV&0G;x#Fl-*@9z`UrFsXXt1=Gz<6f;#m#% zY58x_6AA7J;o}`1sLE<+(4$*wKL8?*96D`uxB-kq@+Tz!CMygR3smKFTk(|9xk&W8 z(ibR9q;KJ9i7t@QrUi%#=uUK)%-QacQMqBClq?0u`4=33B33Cqq$W@cHZn&q)!8Uq zaa65|fW9mooV@3De^^Rq=#Qhk#I<|rU*r>%RL=WT?lL9v&aKz>nMp#F>?FTT6T`&W z4x}z!bk%JV&oR)+;6($47inM#Xp~YcN`Uj%a-Tu|h<6(yj2L3N@duak`IeR1+hFqj zJ>PWHdfnaQ55ejLgzR|lM)oF|Z2M#G--SLtrdqfi1M!rUi*@!}A3`d_0xQ=-EiL5o z?1FGK^Pr9;1LpG)frtr0Dml;dD_zydTg-)9V+I`?^0Ma+T#=C@`_E|Ir-OF~s|H2Q z3XaT^o_~PGtU4hQH?0v1)%#k<0vVpwqp1^)O6WiDPT>3V8t%V}ROah64c74#>Sfnk zG?#E2L9~u!{T^+0`%7yWrmgNpx8HO-=7LAVmkAh-*Q=bUI|tKvkPgKWC!Ih2>$drLo#lZPR^v4+xkvw}g{xNXJK zp>nn_oDs3X3N5-(*`J#a6$)RG>ph%AMUsapjtuTLJ0D#w#@Abf08DijrcGPf#$im!`)7zd z?X`2S;=+FAysfcenqfeMm>2(#%g+KZdPm?*>7h5U{QFG)DJ#+vYo%%2ioQ1VL ze^whuTkSIO9Mo>BCPo{nYe_ss%Zcg&+Mt>l){j70&L&a5fJS;WdK@&|rMw5Adj+FU z-y?$_WQ04~2OP<+oG{c;y=S6HqU2f6jQ~4y*Hvw{+sJ zM}XvDZ#b)cUdz_AI`_D~n|QKr^i}UlIr7N##o>F|Vs7w0Pwo10^D?{i&O@n_$1??W zP#tK>46_R7=59)eDgz@0*DeFOhw$K#TcypY?FvQkumV{^^Xk3 zB!<0VQ~8H}fOc0&ob$Lw5|cz#3AIm)`nFe8K=Clf((kKD#O@mdg@5W{wxe{upBk%} z{Ru4~3iZoOfwC+6VCpZjg;g+&aeWg%TLM9CT}ocI%D|h`5Kbd>FF&*Ybit7CN+-@9 zc2|7}6z=k$$H`yOL5VIg8Crb*_Yo#M>>tcbSwyNoR&Ez~OH!NZzA2lJ>Lq@teej|x z2gL7hwdKPa)ytsr3NJvilPVb0aiB;=Y9ctjxcdWnXpr_u>56z$=)>0=C;rRbKUrsh`eKjX*ifLHUKgEO3|20m=Zn;7HvET*(_4=v?|zz!KwY> z6;!XeCYJ?-<2`(U-Vi=$RR$GrjB>M(FDGs1r#^DU4r*$zPPuzH+0kF^iyE*hEL>e7 z2+`UDN@fr8R`HPuodYrN9$JMj^u<13uKDe+MveL06B5j7RH`}{Y9Wzcw^9@8d zSkQPV=fBdOT5&wdtHlD7A)VPxB+Vxs0NX~r2bSEe8*}X`Q)$30s5@+W5?R|})eeY) z!*-4vOp<-~Xn@>|>!%9K-SpuKWa_YsI;$AQXHo_rJF5d*J;$;SJ4i%T;{(l7!`T9j z$xn0ddfCY{hLsEjo!;mH&waWKi%6|UEKI+)cN$K<*g9*#y#`{fwtb$dpK_rn3btEI zPlVbbhuonB#*c7L%)*_@JqET23c}Z=C|C?0;a4qO+_Gw&at>Jf@&6w1>lN_qF{RcJvO=iSL(31dT%GdZiU5$rpf-(s4KJXyB(nrhY?&t|Ltq;p?QX7|?wGulWlL_=*=p6%X z>j-qKOU8z2+L}I-P^3}8C;U2iGmREL3KP7E*?Lopw#y-glCE1vEmC;9GM{3+)7E+OHg1&S%OD7 zA;vJH55a00a%B0X*W`zvp!HwpO1rR$iWTYH!@Ji?eGj%q<=!WCcL4j=Xz_3knz^W$ zQ#QjF$E&cu7p`0y%BGW3i4+@61Sd8}iVsf5*YQ@Ey=fMO4&jQG{%}sR2k(5d+8+Qf zAD-C;j|`CM)i^JbH@{KCs^ix=<7YIw$4Ya2U6#G3SgaVI<+ai{<+ZPTiL2BBGp`$L zg|-nRMENX`imP!8YK~lYBLl#>&;|IL21-2$=byB7ZQ<#*<~4P&QwKp$xyn}cI90Zq zvyUxc_?u2<3X)Bm4XC0A&^xJ5NU~Cw#->IXh}x{u2f%{9XzjHEo9WAP_o_1FKB3Hs zF8`}wVuj;Q7^5>e?5+BVF>q!IWw2`IViFjtGbq71Lswk)BLBwVxhpH%c)7+SEYpP+ z^0H_tx*g0bjezu@8v7Tu5?&O3eR+NcDaV1rjOin$j9+l8uc){ok1WNsxrpmTSs$cg zu_>kZgrGg_+;y;XD>_Om=~*Gfk6u$XZ^+LFj)hO!vce3FEFrf#*>*J%ts z8^@%9xQY5MPbb(joK4%3{k z%n%Q&phAUwY8-CSdQHj?zY{~Qx-YG|{=Z($G8FyhoQ=u*{K=_3a>+&M65 zto5N+doK>z2()D0Vo$I?(D3K%j1gzpr9&cbwEH!{9SwN2KSUBLO;^Krk_MyS=Lj)_5289 zp5J*VpW-CT)4zxx&E^o|Vk5sq8!iGI+|6Ni-{e;%>v{BE1-45sLqBgS~ z3jzn$ET0XG@I}`ZxUF#B-si*=1Os^6BQCMJhHZ#o@#xuccY^X5m$hAkQ|}|6QJ(Da z&pHJu2%waR0aR+nm3r-Aq;NBn-LbHvnR?B9MY7`zfJH&$zv4PXidCT)40*U7zMYOc zx(k(dj~8Gabnt0}^%g>%xyknMy^n z%GF9Le4He@h3FmF{Ud@Uki2aTDlnCHfX4)1T&aaiU0Gi~rH}~XI4wL>{564J`>=N= zT6}!t8z=iRpxvSL6 z7|%)=FHYn}5CU-Fy%KQZ4p3jhFUD@Ft;S5euyGJ0;*|D1F4?fIZ-_a=3%Qnuzb<%~ zuu-3=DxFZu$>Y%&eMWU5;cUR1@KO=T0=Lr-I9Gc?!cuGMH}3j<`cz(;+I;RMAJ9+! zLBvG~VT8A2HW1C7TP=Ql60a9`l5#~S!nA5<&4!`}xgUyND96;9U_opq5(y}?C)D*F z^aN}(^GEOLwGQ0Cl)sn~-A0k<%PFo972f!OJ;at;S@$G3ou5ZgY z_C0w`4CEGMbdYZ{;?HtJ!J=)Hg+vP6DWk+U_(w*zjgs9ug@dq@GEP-92AsD257RP$-oxM^U%~lHw_}B?gPG8_!SO7DT#ze6|vFrz1NB76zPmllurP zvRn1me0Llb2aL&plp5?$leLFSee8b4!ZK+r<@AmW!>e!F>4y65ZGg-7Dy9}W@rBeH zC*Yq2O2TG7TZ*)5gd0q3J}MArKD}k?q&ec8x@`&(nMnV?#fM*wuSNnn+pj%ga%8t4>akoY6iH)M0o4tpV1V^+j{c5)iE6tq_I5t072yn5XD-s7~}68zu9ci%JNin z?4nR^h;#*iyaGXc?WMg%v<;Ib|@*9CyWT7AO7R+Rr8@x#cIFn&ymw?iSgU74=4^~VSsb{hq;OHf-&he;tcJtdia=|*IC}b zc4se&<@`jsAJ=S{7fqU?`8IM%V^|qE4a0nLAC?C@2u!T_ARcL7{YXzTI~)8GKyIA= z+YBZGff&Rn^iGsoD8SLpPFL{!B!N?A3*$YBP#N;_mJ)x=!?8sSXZ`oFO5j-YW#Yzt ziaka=oxz37r^C_TQZ63T!Oy~<*Ex9=|L9&ER6qY@3gFHy)~Us#&s$I&nq&v zLDS3yg`KW?^eu@HKiAO3Y^~}`*jDiNXYd}Geh43u8ob=#3l=HILfJT6m_mnsLb3LTj(HAIz`hE z5n*gN4gd^@{m#|3RMqe-9(-J^vHcz}j6-jWrMT1ADD~aLXwAyH1B+JlODEmR$+7~2 zf3{CAd4Q3@?!Cah*9V-E*(!Y3`ya&%it;lqHV*2@lfg|B@>Y~E86Y<^iM^U z1$xT)>f4hX3){mWy<9c=Boc%!w-4>>VeuNi4%BIX!SttaO!**1a%|X7KVvCX*VISTkc%!i12g@lRIquA!Rd6;C~Bw zA5t1*E^@CUszjW|80#Nze-7t*57kwt0=3b3D-N${FU4(%$LeO|ExfpwxKDjA3&x|I zFqQ0|H|i-uFd)BRG#_Z{$HA4rrevR}N!+BZuEnn)ampc@3`&@3lQadc?e<)WUIAI4 zI^$`W!dUmHOadlGA?Ld;!WCS;ED~VoBE+fD9 z*)GjH@jwckQ$ah90^Zc0W{N3ryBi}jxcgy&+K+rHQJI+YMes@yI12ZxWQ#?-wA0(1 z6)Ha#vZ)ZnTK)xg<^y|-cr6i%`Vb;Lfp7fZnMeoW$Jh>ccSO-(8{qtvJq9S&+_;Gv z!nj#g*EiG|-*dnT{bLDvoD!>kf{Tc)HwnaY`BwMU zF2qWPDkC7xsGxwtRc{+zNOT<|e4-*hS402ti;=(RjuOmP~`>M)p zNGT*Nhfv+d@AaZ-QJoUnTzz3r#=bI)jAA$Pw`KyQ>~&#D$`auHoNM(S%Uy=`X54cj zux;K0#_q+p)8+$!4ri=W$X?RM8^7_`7{#k?KcdzQA6f^a`a3?f>Rt}uM3=aIJ&T%W z;!-c@S781N9;+%zNZ}Msj%36nflX-Fu~#&S4n75oylXkJ;K4=TUHIpZC;C=xv;ljK zl@#q!$E8ziIn6+?)RoD2rUk`8;|4ES<7Y$VCa>t)vh3S>6Tx*v7d!q0A@TH@F7^Ca zfb-e`k1~C=J&r`#NpANwW7oLgGj!qtRvTu-#aDu{Y2||Y$|Vd$IE$XT`1+}n{L*9R z`e`*H0-*ln%>skPM&X>|t+kTc-wF_Xt*fEVZJxywMbnEbLMjIWpXSGRYisUg+a{}-k6fvP+q>w!;CTV>j)Bq z9?_M~Wq%xuC^j=#r87`5H@EMyI1TyqtHOUKRs(0{Mr4vT_9_~6T0vgH3rv0+`5IJ6 zV+$zL7=`+;@36f1F4;_e_TZ7Mllsdmk@6dL3VhZiY`=s|E<$!5hC&pz5bB}==;{Ap z%;#{M;JLK%u8)7#4DnNC%xvJaSLw~k>Ze;|i_VB?6J~*XA~<^#ediJ)JnCPBxSD<> z;dEw&Y?~F#3-UV8Gf3}CtugUNlM_f1*Q}xv*=_eyi%qrh?PRz(b_9oxZAk(M(sC_| zfM=kdDm_B4Aj7Mh5*Wpt| zXW;)W++vK&X>IQK7 zv%Xi(D0BAxD#`FuAJ?L4qvB+OYsnQ01b7lwnesLLd^t707&FHXcpx z{S_LWe#IbZNKwq%e%tX90^InWIx>qrwb5Qg2rmfHaPsm|ip;zN4^s^Zr#ctgx zLJI@hJEa+%4)BZ-E@qGnmVF8LL#r2wnnRz`sfpX=V=|!OB-B#e7J1)SY^WZSxv4bp zi;ncoPH;!xbCEO=Zms1eKrw2%&IA!JAGZ4*b5RJ}t7m-%=<|BxTcf0ql~9G5FknfL zoo1pM!>BsPZ}OaL-rOy@cOdWv_urhW(pNCY`sQnw&D@0rlg9GD&eFf)38?kOdKRup ztmE)PXE=vY*&0&nv+OAVh9cDCwI9~)zGC+2L;2VbY&0}nh?(qQhP5hp?IOF0?&IyN z$g9cK<{EKdX~~r^^LF@%1;jbGMc#9nURHW-11QIrT@#q!Dq}#t%0JnBtd6Wv*Q#bR zYF?!`N7&nbkwBa+@@POngOL=s+Z+`U^e$nEJ=-bHY~{mahhle}@laI9k5JHUO%rPC z=s2aKmd0>r%-uDVlB$d-^M#Wd_S%ialQFVnt~Dt9nas_MBBtCZSD4W*tcLd!wS=^0 zu9^jDJb>p0AmIqI0K{k;hAAIG5y1)PeMr_}l)@EH!F;cP>P_UX5P0-nvIfpP$80Ar zshJH8NTsGi6c&I6FHzi+LzOn+=_R1B_8c=&ztnp`aeHo7hYBS(J)2Fbl&sLnl)LSow||>fQIVy{yRh zMEW=qPs*Ud070Z?-A~2NVPeLoL|EPdQQ96b-VT^HGhem9p*4r&rLQAL4)S%bP(>)^ zx6(OM-0)@uf>%_7wY|aGOS5wNEJRgAI0r+fJSkj+fz*)o%##moICg&Am6rf`V-hck z8*L|IG;oW51fy8jvfF0<5tqKbcP0W!$)waS>23=Wbx4{}1{@jYdd7yM)#?L0z#`|S z!ZwE}K1^9bAu04vkg7`?FVqC126uk(fN0Mv_PnP|zAT#VYgYzcG`m9HQ>WrYK)Ikp z3$p}+^3B4K4@E&mBS^#uR!d}2LpC#|*#MA7#U}d_Mzs>0eDNp0h!Uq7$?XU?)myBPV<-2btV7?N#*ye=Z(VQyt`2r2bGaNJJWAj5aJU1TsT)9BDD#! z7)T(xC+=!SN-hXaw!qrEX3~;=FktdaU|%f${UX@{pt^4mDJD@36>V zDW(0~JTUKodO?9Vn`OReL=vpQvk$V~3H?NdEA?Q3-TPE$ghb{uNi+qG-Z9!TiNe)A zyr(oII9OXT(0fx3hX1B*FolPILD%(s0mFVZ+-%}Vu2m%m!t?XEifU!<=zj@KNDgA9 zX5*dF20Wk?RY=?~+|U*4?y)KCQ@K1e+`nuhf`a9}V(W0}>m=%9y_^2&| zoY*suZK%`!&!w1f6H0rBrWLMlMs;Q0u(P^&Dpxc-sc6ds*HzJ6D}X%!%}c|V=-?{x z#JJx~3)=2D$oqZefUBBT)FC|5+=~+w*XeV4{fJ#-*)Cx)Ue8Nm`AQSMTQ|o%NZXL=Jk~80N!%ONWX%sTfDARf7m83 zqeKgCF5rbT4YuX>`5SFDb~WptyMmRP*U^zXKQxqhf^84Y3AnLf)j?Gj(Y1^ts%z3* zvlP14oeW2C{Y3ht{qi?W)Z2PczTz+Ah=d%l>~FhL>wOMnA*dxCT+fL zzSNt*@0@k%AE|}xl1a-1xZf@${%-u zQuvnnb|PftFqO$L8x;9+;tc&4Z%Ey#Mhe8cM@hOZu!H@##L}~w{3oJ91=I0%tH1Oy@bH7_2@h$xkcWrt zy}hbQvfD#A;QGo21IbfBBsvG?Ssvyj0Y5{$R7tfBVHt=NCg|KzxGL8n#%p?zR$8%Q zAf)9=Z64ySYC9SQ{U_H(_%@@N@lyQq0lE5O7l$&&(Q~HX0PKV%=fD-i+~dq%ChLA{ zOcfZ>)3d~3G|!XEwuo!3u&Z)(lk>z1o2m$6JFiSYjV?Y00q(7Axu19CTudnmcao}w9oIj2)67V;PbE%=Co)(HI1IY~SgN6Hb!bvK$=$P5 zDWgo44E^G&mM1y-eRhO5I_TF*6p|j5#M#H& zqDWa_DpRR(xIpMHO9hk2zxvdCgGJ6cdf&=|OIz|Lfw*(^ONm6dL_KF4o6{Oo?YD>k zeGak3@u~Rf`^52OQH5L$SE5!%_MUYp5;6U~f{dqkX3=(zJ`C17{4A<;-8XI2U)ZcIfMBkpcYG;m#_tipzi6o7!T;vowZBnoHi-v(g0_&duOt_~>j5QR6)okbF zHPBcF3sLA|GA2h*7++aNttDLp?T;-pj!T1+GH8!OL1-5Z_v-R&52pyaTTb+W@Y{TC ziPyH)Y)7z3m#U$?*RI7AaL|8#Hc&9=|H&1G$o!I0te5fSY%FWfo{nQNTG1f;?N6Q0 z1r-Cre9bQF=pHnl-aDGfv;sVyjSWv=KJa{h8%jr9a+ukrA4XP_)oHe5NX|NNfve(l z0hntym)yi#Iq#0FQ&aoce<8ds=T4FqE{H)p(J0raI%k1X##QVkF2dv0O6RYUrfKn} zcqQSt!^OK%=jvXwhM@u^Ip&sob}WH7{~QC8Cbs-X zrh@c^bu9t-VD3(Ix!M7n$N>7SpDaZ2R@(D&e<+f{_;d4rl)hO!bB;tg@?rXOn%ErH zoat_`o8Ym6g>eV(@F#X-GFUCR5e2(B7Fv-)=cYHryD&Wk%MiNvRiDNH*yW(E30;X!uxMzdjMl>ywCSx!XZh)Ch zrHGO^+9{5W-YbpfvoZ65i`}us4;5WUWz7w#RO`zT$|YgQMWW|_9GWh4DnY6>j;#0! zuNmY&Sk}f~uvxhkhVXSFIj3$Qo4Nt$z`rts5(A8kyq-iA8yygWm51f59n$v|j$l@P z`rCz?0*+41mFVeY^Qdk?Yg_R0fm&D9@A$3iSyp$f)k%UXml43#{U&7SEnh7{DQ?8 zhNb393X-oZnipI`$QV_0SZ?YY3O^3{1OyU>KfKy9&WzkOVGpvgf%9Dni zUK?b3q!6Z=K8y+Q7ZDTw_EyVLY22Dku+)UmQ1FS4y11pNfW`F)^xP3{?#FGl!H`cm zyAvF@&?H;~xUkz=$#&As8JXX7{#S%1rUnFG$gMj8{8Z19tKP&+4uJpFN?0i_lL4=r z=BAZ6`aI{6PF0AA2`)?RzL8{Ru`$mXh2-^~4oP7IH4u9j!K9 zX5H?f$m~}nUj0plSzCUsI8M1LP{yuGeL~`f7pWl4cKMp@Ntz@x*LW$@ln>1|^(TA^ zT~zIRq<1|D0BT1x9^8_J@$>Q(=nP{wxGR4RM)&}n11%*XW7Iw9ocxKfWAV4(fg}f> z?ReurN{PJikZAKtCa)_nKtxm*N@G`C9Ui+rc&?qd1MzM3(o`Zl-78W&N~Nj?H4oh# zNVIdbV*;o9Qq}RJ9J%dicG(JZj<0mQ(IxBaoEr~YT=0C~b)Se}%2F-^4{S4;XqydIWR9&BqU}yvz-sKmfB`gp4ug_VGWWXHY<1IonJrX2V~{(Ms9hJ=ZdW*Y zCJz9ns;vJ!6dM`;a2IDe!EF6e0C`4FcuJbM-GQBGPOx7*IUhtS%2?L_o{=G4R~k>h z_E>mS*M5A+sYTp+Fo=?r8%+pIqOk)_;4BD<=@7vAo)ftw%tp&~VYv-rZ>Un5l^T&i zIuVh?JC6{ch~M}}l;7R*poug-=V|C?Fgc(ZV_i&u>W;;@mLu>3|M^=CO}e!yZ?wN% zAs~sy1kHJ@b|ocF_K2hiKsK#Vgxx(>?z4BAm51Jc?El#u_SQza?Lrw8_A7pUKnlw+ z+9~7#B`)>4ZCB2^;GS=LnOfMI-hrQDF=Z6G0^%youP&3TlGlOc>->XLV*w93i*<{W zHPi1l7bf;}y~sO~u2mPx+%?+ir>KtOkKEe35py($LxKl|zaC|d)iJO1w73rf**F?L zh{`NQSJp&Kr9nsD{BYxZpqwZHh^(_(&>qoW89!w8U!FZo?lFe`%EM0<^#gzXV>W*W zuCu6$IBu$8CxvmeiOCr0DL%5S)CZ3J@!XT6l8bMEdSHP<@*#bv#%lD^MPOh+8O7tQ zGvBcbcr_iNNa*^DJHLN5d5X?@sGs{s8TF_o$Z2O`8GJZD&AN6CF^n#pB`x=w5p~j2 zn0`&>_;{W9?ZfY~>W2Ducls0)_Ap9K1HwR6%GMA4R>;bIWOp{RB6fqpl7j)@zX%^% z(;cc4z%$A(Ul!iHW799!<9oT8T(`K`ZJ-nqZHCXLl_)g=;4y2vJmbs;3qErp+!w>) znk*~1Z>2bA2raK@E8GjJ{C?MrLmr;|KSzwyPI!FTlTg7os%@m`Su4farfqmOD-HC7 zrC3_NH3uhF-!)*c)NZ20zxuL^((LQ4%gsC5(n%cRpN&?rd(}$fvvk;)DL|5Qsg##F zf1qlK>PD!g`qv zP-hPd{3v@W19>NVsV?N^7v9l@VRvOF~pS8p(i8gF*5X=)iWrj*Zq& z%3m{~0$2KFLecfw$9IxowtU~1_w>VP%s}PyjP93wEl(J3R`u7dy7O%}#VO2IgzTFa z^r}=Tpm;D^mr$;Ma#BVkUL>n;pJPcVM@UNo6>i^tZvcve(Pga(wpb2`}el z^ZpOp%iKRL3P5=;i*+S|EizHKI1DfjHnzL3v$mm8-t~FO(GAGC#hIHNU-(^AsCdv?m_ax;KC*+ zZLwLkEu?YylJ*-u7z2d|&V*W1Cukq+sPag={O1U*=9+9G@<97HnN`*yzadY!D zB;gOi2Q}CKb0pcQ5Glfn%QHM&LBHQF-d3f=OFD<37%Q0YXThYA6x#8JOJqU04r{oQ zy#{0WvLgQNI>_*e=Kw(qLn$-U?iQoMZp3~iDo-0#7Nm!*k^xr8S2HM!Wb8Z$_c4p& zYkWx6A1k$tNU$qLVa_g56!{W^=BV**`1sXe6s!5DwZMYkYEcBZDg%ivGA4KZxOSS% zC1T&4y<*?s(dZClp0=_eWks7Q^&m{|;H#N7uWzC_N`;~|yl}^O8*a9`L63J|s}R3Rpt`^2 zIoUd1`F&;)xZ)s14+VCbe+O6oHvnD^Sbpa|uoz4yDecf}%4rSkWTozh{|`vJWPp}p zZhQ0WTRpQks1J}VB`s$KJhD8L?Uv zO@U=-ayXu=Sm`RF6D$*dOm62*q0BWK^tMx-KR>@=Uasf6Q_!6OSD3AepK&#rmx{NF zxZ*XhMXC&~!!k+>0WpBUaf!eZ-U%IuafM@Hxs!ez2d`QWCvEK2FukIaw1iNxvc#id z91rBj2y~ji@utQ4ie)ZDFO?}()6UnH%%b^ibD30dcsn>fJjmq(u zh%08KlMF|I(wEDR@AqAYG45!n%&ly~xG;;rt6p^Jz?N#I21DrW@-N?EWX07mQnLe$ z&SUY)ZA6VCk{l9YhHy3KUwBiE9t4F2^v8B3q7rfZY|11h{yF&$H^O0`EnKm_0Xct` z&Zlt1dW^#dsv4bsLrc0xyPp~m6S-ViL7oe3n$uF6-d zwbI&j-R=+1`feb^7&aN8-#nCw+(xX5ez3%l1#Gk!jD|ia@@Si$6w{ZGUAu=@{|PDB zv_k40x{=W_V{9snG*D|CX;kCCroa?G-IBQG4s?p~ky5M53HH)&tgAh6drbfBbonh~?yQ2aNR1)Q$noq)Qox~8Y zi@$;C(&Eq^Rzq_WscWPDTHt;FsR-R85!zy>(kx&@Fo0)9(4iVwanC@GOCBbi?_?Bb z$p|~NnzfKFmYp_jXCMP>DQCwFx2^%X*7p9y8@O~nT~u2%@e>| zEYvURYDo!uxJ`W`wiJ{@C{2BMYM-OAMMVZ&!k6zQa9-_TM_2 zh@YEe0neo3+*LelIT}RgTh?sd7c&|8;T%Q8(YS(o(m&jKYCiTq{XHUOtA`BTcMAxOe}nr({MI zu_CSjgB7X?e--lwXu!@|4}oUdAnFGilDtYI{guWzXY*<08=~r( z!WrI|9S-qvXMGw;_3^+5!Ht$T7)w`@Aa*~gMl%%zW|3((63*(sfy6}q%bm8y{cz2A zU=ssxpDC=dgvUtpi{rGHy^IPD-Qy&Bi6@j_iQmxcm~ zmGt#%+L(IFRyg`26Errq@d(_7YY7I#ur13F>n>yX^k_C}y^hw;T!(Zvhu%*fIZ8~% z!75Pimoj45S&7ZOa%tqj$>S3@&UWdiqK6!blS)f~?S9NKS{lMSv1= zi#vw7zQA9^cfOg+7A+ijM;c2LK|v*4H}OmAP=r9u3z{(%7JL-V7%s}`cFLE#Pf>2H zhR_+HS|LTf-LIH~eVeyFyxcn6Y}4%)?@dvhhjEF{O`+BqLe96j_1jbS_M&0a!kITC z4qTNa1v~Mp-Q{dG5`{bbAD(DnQ6V-ZnFr@tHpIf7k8}zH2me=zixQL^Rd4c{?Q^q9 zoQIEiJTh|v?cUek+hJ4|Aw&WyBSw}nxs`*II+wZne+F~}P6{3NxFMXz2Uav9M>~&W za+I0UCfH)lT^OSChTSn8ohxk5rk`)~LM*=Ya*YTi9wHS`remDo9lz*`eMl9?j3ZXD zbiO1jQt1_I-)S1yYbKZa3G}B85B)+WUt=dLSIl0F{Gons$4d|9ftT7viu@9!0?I*) zHP}3W%V7@#s#TrDIp`_QG7!RF-OTKYh@{jH4i5iTwx%K-svNt8JZLLIR5z>xBC^xz z{HBdI7X3LWu84;LtH{QGBMPUPPH~sc&t$Jvk-ZSnTQ#9(^r5axexSW$d;wiV9tiNE>%hvY{ zL@h*le`}r7W9fK$4%<3kQ3++(KO%tbJ!#S@x#&2K?Z<2{OjT*=0$HH1oB^j*6|iT- zBQG?R*=aYz1BV=>fJ0*Mq%oEnw-sAO;?ZsFP2(fN@qR^XzhoE3DQx3Z;ir#Q%PC+` zKUF4Pm6pg^$_~0Eorx0oFBg~na-shTjKN^)9Lo5c23sZi{2L5!lbcg^?~XUyl(&HB zCW(-#xu;RXbe*eHbvx{iWc<^`@MAfmDA0}Hbs0{>`LDJcAcZ9MC`7`)-uRJEjS8?f z5eV^d3Thc~2uDAxWC`IYS#o}!sr0pF$TpV`9v(P-KP#~(Tp>+vep%j2NV}9U#fd-% zuK@zFB2(@*ZY_*PqnzBEp7UWy+|+{|Cx& zI~sJ`4L;huW0L;6Gpk~Vt7*M5GzG}a%{Y}$3oj_cqHt!`a-9t$WMvCwcAFto$uofS zNITJ1ao$?)Ew$j6aK8ATu<2>=iN_E_bR>Pf-R%QT^xvqyb3TMZIZ?E8`*|%Hi+_p? z#70vmJQSHwO&F@fD}g6}$^3qk(yD9Ir|T(&XMF)ipY#sF8aQDz>^w6$S3%^GBBk&M z7NW0VlaV$-g*e4`13@Smx}B~>qmK@9c1x%QYovk^V33#GdnjUvzZ-@CO;Q%~=6wF# zEwLXvZvw3lKiem>+BoSy)oQDl{G)8y+kHkIG=Bt@r#n@UQ&XO)Ojs7wzqcbs0IU~x z7NDbEQljKO6Pq3~qWjkwRwU~nY_=6B&W8v6-!L>sTY5JE&pHELN2=)mZZj9_#%X{c z0dUqX+^vplWp$1EsE_ZYk;b4c^-~)`G{h;pt;XuWA+Mi>i*5rdhe>EHBoH-N3XF=V zcbhm;WrqY4L!ILRu(PRJmeOI2DF>~yw~|n5)j>!%$Yd#S%V){w=S;-lP4wfet9RdF zb)=VP=>Zd`KD#4tjQDZWW};!@;m6MwP!kVy^lFA>BVpLbYe4uzJ7fUj6xU=vwFAY9 z;fm7>MSCv~fHspzy=(j_m2=H6cWftgWv&9>)stlp_^E8Qy+z`CD)LibI=jE1B~H-u zfQ;=4Qv7ye*(Y;lISXXBgR5sZ34=uHpQTqt*JkW75Sq8dC1HHY!HCQZd0)ZuxZ~4} zf4QD(z)?JYe_4ZI+4zh1WN^hOc|em_Oi8JJ7~KXY23d_ zZ4u0NncUUo^V_Ll26;7NiT1xX&tr)58W!AQYqiIv1;ZSzI%P%LkI`)lIYJB3#Ni5h zQW6I_*jzb&9UXkIvcaK+--HpaKOdI9PlemB#sVl6?12{(WJ_6bBH0aAjG=( z`#MGe@+{fzuL54gN#enkeAS>cl*e`=A%4)YwP08FfWibT9w12u+{)e4o6R--3QgnD z^2T`V8B=Pc&yY&c4p(AZ(zjK{`R$fTz&c2$1t8e+_O)R>iDB(@{`Y-iu0i3w&SnkV z=J4SdtysHO7uW1-rmaGH9PHR&rVTwo(#g30FKlgvhzt zo_YDB5;NKy(XJah0y4;0q(b4{LDm+8Mu_FNuDNM54XHwWI9=TnECD1;tDf0yi009j za41^@GH@xg!OJ0T~ol2X&Jy<#BG zlg0SSbWLO&Xa9!E3i&dhyx$`_h&Npct4n<>ak|t54gKBkt&hj3d_X$()FKdqpt)ev|`X zv+Y0wCbAS8<_AjJ9TL_YadX4E8P^Er+6|aBB@@JdAs_qJ*L1d^p2hTdy_JLm<_54P zUHoVMccilaMxCICrTbhf$5P#?-Zw265a~YU)0TN@7Dda63?~(|gtKR#ACW@dLKGOV z_o7&xbbyqfqeChPA{3{A+{a7=4-~j-K}-E8cspr#=PV`A-7kT~dTVb_Qb^H0*U$%} zby=WjGqE-Du6gq8Qqc%;r3BCr7|!4GXHosA;E;2qg|Jps*)rB``+C%KsdTk5L`Q`9 zQ3&ouo(A3bUK}VH)zp6B>n@Ae8#SXS)R13P|8$6rDWU!V|Bo|n_=Riy3_;$gRh+T) z_a*!29G?!eX-P*6+KxbFQO7jO35h4!>%#EJ3nI5Nlu!5KD`lL(m)bPh+Q*k-{6vp5 zuuGQ+&YG=6S(K1FaGBg)|=jG_k@RDPh3{ujI+<){4m%0Rb1*T{K8qqD9sN^meL9%^Jcm#@Ts+DJuD{1XIbscp9;8OsD+ ztPn@WUXRLK3Bg}9^%RNBEj=oLQTY6XQ6D00&F+YF+wT`B-p4|_0+_JtXXU?)Etibp zl{$DJ69VbZt=gL+33yVc^X-LiRWEd-;&h^5NkPCVs`y*|^|3^cB;RK|drBpr zsN4Hb+V8d3?+}@rSkDA4$z9E+6K#uRd0PqyHwh3Kpn-3xIIBB0p_!jX4%G?g3{}X= z)SDNxxJcw~)`=xd?x>B}ZWn%qWWMIlV7nyp@p8H{Ye;gbih$D~JQ>+z1LiyjB2JS& zhefhG!u4PN+~ zc5cRmn5;M9Ny9U$){n0;!q6YIjH>F26EFP*eJP>kLgsZ3*Vd{{2sw7>QB>3#hn8xP z5dY7c+0z-d=?0P>j+ak=PxVhYU#o(DnY(gwA#X;N)fZq~xHLN{?W9=MIorTnK7ue4e9W~CRu>a_yT3zd-QsLy~##Scg z{GZfq`Zv_5%>=gy@-0Lh+a7odX;khU0XBXM&1ADfRDzjIo7H*SI$4-^?_i-|xH!83 z*aYP+F&VHo2nT*FCGO)9hl`iVe3YhCGZ{O_=B#~b4zJZ#tVG|wKeTNA`a9E&404zI zNl~cWHqCS)TBIQss)MfBQpCBvYeSxb*Dsb!>>Z70urk{V%wNCc%&`FKdA8OB6JkwW z7*X20a_I^M)QMJi-|({YKGX-q1}#gNb3M&dOwQ9!xov7;v|HXXOj}_qQ(vk#<#UYD z8itM-EwKdb+s1-7`4h%1QAs-O_rXL?xqaG2pW%2P+4+H~7yuX7{^qFJgpgBP?Beg< zTA7~#e6>HuuzPI{2_hX^==+QbcLQ7%c{!}twXCCStF8sk>7sQ1*c;l6zSuItz!5H3nM9o(r2(Hec z1hsVOBtl6m+`Eee412CZP&U#?~;BsM;LOP(2a`G5+>+M2|+O^;sQ*i zhh9;6O`~iw8nyy_e|Wnl9LKBOG!f&Q&3f(1FK4{YuY2f3R*V>(hv39+OfR@;Pc;?G z6j;lTT~&UOS8!$Sn*19T2b)%#Muge8ZP41XX<9prI_@ zNN5NF;jSdFJwD`l{rKRLEQ%gzZ4xq1V@}-ILyDDLMHBd1wupBF?F&`V9RcIN^ppxM zpDMRGWT6noyJ#23%(8mh3PBYi`riIi8FLs@WsB&)qCZ1$90$I6FHEsq#D~gZITxG z=VqQ{4sa2tGKlTGw|iB*xurALaM*(uxEL zd($mBb<8g00eSgZL>V>dO%+~J_fYU%k&g0wG-Hb5ls_UpAZBYC8_+|W{(v0O9!Dpljua5x z@d(0_(qdZxA^KV->-&6q=NhuUyQORPp)(mF^%O?`qY6&hub%NpIl3MQV-eWh7|(~f z$NN=MJDon_gCN7e`<;Rg^ z!8^Ri1&bzU1&m#y9;&z)GEO~uC#kA8CM0BNCStfCr*P_*P7eh83(E}acR$RKeDE{v zQf7M@y!<2gNIHt1eZ5E+VHi<3rIx9*u%EPAW|E=FwW7sXslr9B=a+Q057DB9CaH$N zcVGQFc@{_Nf})J=bh(5J|7>3^j$>@z_rS+}Yei?~w}ZU=&86ITwtim0{{T|?M4)6w zRw=2fyh7JD{<5Nt0g!4%ouXy#}l(weATTky98Lv1nfc*deUXc>JJe|p46dvy8Nb+Rl}rZEv|2Y!+kOcu}0k-G6o3VWThbIkN{OfKgI zWAi2RpL%iYbnQVW9p8)tpX#rj{e4)VECk4W2&8A>SM=X!+j~tZU5R|Bu^LY1j`)J{ z>V}rl>M~{uXARWx5mr*C1F^*81bI|~MrSQwbm|Gj>#-nVe;LjQH6pm!edFSbff71+ z@_N9ywu310nbt9zxU8Z(ihu}#v>1o>I=bMQ@7_^MrlHp2Xl0ulJkM`z&{H1xu55B& z_cPGqazwIX7jMNdx)Mb^Rtxnju|<{6%=V;@g^}61yUN=c@bx)@l!pr#tLi##V^a# z;cvUcpfUjyqq0Jv5}9e**Le-MDIvHeK?N7{3;NULgaD71$>uOabb#~v>uBXTCpcV` zPp+&y;_tGS`EDF~=j;DsoAoVj>E$Gwp;FNu%6~X^|D28Q32eZ%9|F_874NSf z9ZIC~X5kV_5Z-Z72GrE5^DA!0wsNu-;8FC#ZV$W-Rok(p)sPd=Qeax zWtx8k?voo1h!jFe7M}UiXMO+!Kb*c=EYO|STRec(4djFZ{ z!UL4CqTr)l^G>iy;Jwv&!EPdtTfTPzA?k#$IetR3{@?^j+bXx?;2dea5)0gA&rXGO z=U^TOrJlRtLTo&3;|X8b4Z1Z8fJ+%%i~80Y#^~kmGu0BDb%3Yu|Gx;RCJ2hn+&qyy z5awsDUXuJ}5t5a5o7P`w%h6Q4di_allPF{FtGWwkRp7Uw2eNEqNYttlS9d;-0>Ew^nXC4F)d*^h*?g`?oFH)29y% zD(S2hljs7rdD6p03RwU6{{KzL30j_0Y zD5GUDr0g>4X&VlYG`AY7gNzcbfM)m?$`;#LNmfi5A_l~K*VsA|J z>O!aGmUE5OE8KUD>Bq3%j}yJ6rdzmvli%I`G|IV8$h)2C9?~BFmk3Z{;EHsn*+1wW zA_ZDf($iY{#MpA2KRiRiS_32Uw=v_-P0<(j66A+R8^eOae62MMzm~S%`ME(Jpc)#O^j?He)xt*o*e|DDtdxJW$5}&;4~Y3AKpW(yhY;SUEvDpu7+dPXeXKTU(tPBd*TT+PzN8w zxL9-ph@$Uc6`)lO-_VTLwN*%45D3(6$yi4_;Ha!BUnVNo%NfH~fF0m21lKv-1B4q{ zjOwPmg8Q@yzZMZ#eKMc+ap(RO^WC1mj^k*%pA~{q&fqU{I}^+M?Ti2z6}Js$(%jjR zs>nI|*)Y^OU8Kh&cNK#buF;7rl-)h6F^4f2orW@;CI!mi2usT^;QgIk=t`6iFF(To z&!djb2q-QNMe9k5ESSKeg4I&p`GS;sO$m!L^Si3mx;h&33MgI*+&8O zbrz2+r|#{8F5M{E>#XB*>Z7&+&zq)MTBTOcrh?&O%*8vsAy}$Vqnw+W#7PAH`wht` zlY0Z5jn$Mq52K<#T($}hcqS~*2We@rB%w1ibl>Ih1)Gjg2I zBu`oSurc1wc1-!wrx0xoZ#X{(;tgX0eSSJVL7JTM^4BWD*9_r|Qb6V=p z(UfHu24)cI&j$3_|FzL&3byW8z_Rk!`c(|;{o&RHE`j|Y`o8Q)4|*zDjN{OoKX3*u zv%C~_z3zwIW>XwbYmY60(Fl^MiO*3VP=>3XDi4>1ilDn?o)66x$Sxp_`Hk-l89*!p zd7hRxLG7=bcTm~($8?&sym!uqj5E((IIp)3TH9(o2rB1rfMH>5?(o@|=D`pooAz3O zCwABnVg8b=>`4REJ2b)S5CB!fPXH`AsAh-E&_b8Pu8I-HG~OK z+Lm#KLN#V)Mcb0MI9aup!I0(<#5%>4H@^!H!is>FL)trKz-c{1(N@B-OMYB&9}pkI z?VlIX!EG>vWKf>5CO0^Pf-b>Mt|;K5zUGKvDWVaN86J zucJHJ0KneHnJY-x|6GsY0G$k&f`Hp`SG0F+N}oIAJw`sUC>*C|q#7o!!VRK~7IVhB zSxWXwmH#sxTSDc4k2_x{>SaR~Fkx4#^B$2gUtXC`3L**ZGKt}6zMxeY7*cA=hbG7n z5E`$~o~q=-M5w-VoKyP4h;@r z*@|Q30J%DCnnsuH7p?UFeKUCAKhNi6-WM43Ex>kaG2u2tRTgQ(u<>DLem^#s&W?Tv zpZPX1JzIw@9e(>Urty5(`zID@efsK1j*d_Yw}Bi~Vtz;oI+dp3MTi|Tt%$UEDrxn* zyszl9d1i%gGS(C^LtC^%Tg-VYpNG~8`Cjm{9uXp~W7e@7zI{D%iQ(K)qhwPPoqS^t zM4WBL$VGW9@0ZstQwf37j|(uo0=OyhT!F3>jh}~E=4iEz-sXdDrN$SGgB%f2!4E=9 z))vJxOLaXp=G zE0t1!v8eW_nqLM9lu6|m6$xI9;#~hKZFnd*WE~?`)h$qra(j=hcF1n(#;oLXj{UlR zB>X%_N0Dd;!-|+85-CATgrF2F-iM4xcCq%-Wm*gf4qXtD{U)#vQXh;F0AuFHxdH0V zqX+H;vN!;49YV?+2{ctBJ-z~wr(~CsuJKo}_Op!6T!v-AofLdx`D2lwv@eS~&W0IG zjX_|NSw0Aoj%~;j@SHCA;Y?2bNsuOvb1HTppobrWkh^RKdP5M7OO@KAw5JRKDYV&W zORY<%r!R09#i}^bO1Hjlt4?2d*#;Eg)>j!3HQQbZWYR_F8n2m3tfKs%D4c4in#SP5 zP5vM54u%nqnx@{oW-5OW zTut!Q#{YORfRiH9;$W`Pud#q7`LHt)HBEdBf47- z`m_#Xs_?`1yX{9ue;=A;P)@Vj zm*Z3KbG2AQ&)p23@kMbv_?iKUbSF53%!}va+I-;AU=v_Z;Lb!Wx+T;0fvcxFU^hG1 zh5D@N(8JjahO*_Q3`j=5O-R9uI4a3;$UWd^{Oc2KX0j)oHWP%$kaQT%5t%%k=%3kr zTwWl4X$MKH82dTiPK&)Lxn;Q`>p8*Nn#d_DjDld25IY3Q;i%j2Ezdax%WJr2ZObovX_>^1W95w z*LkiNG$r~XaK+%EnoK5WJ3xwuZkjxj5p-@O=`t5rchm>wt1sFM@Uo*NA5`!-G)hgE zJN2hi3KA_O`s&!W!foYP*TSufQ8=&iWz4TR5B;oS_14|khBJ{gQ?Kh6<$`MsH$&(0 zg}qtEZrOpvEI%(_;m3{(}Nf)eWJ>9y4m*tH@5P;1M&wz@qLYrpGc8HqT<&U%{ySB@__?8YY#10#5}gw&*r$3 ztlo|Ax^vbaJ*Xs{C%JJnsh^Mvqa72sHB@8pG9fmeD;zw0H??iTN7k7kxAC^sEGY&= zM+v{;{roPVx^13_wxX3Rc+0P)OD0DnJ54}S5!{1848xkzXQ^Zq36&%QSdRpssG2Zc zIJE|GXmXJ%T^yb_1Kd7dMg)l9<6*s(k`RgCFir=dvhE*1zT`Z4OLq_}*D`n8LEfWwl}kyM zKv`+PeIqx5@4DIR=RXR#)<$2&hI8%$WJtMP{77e1^^x7ntn*fm%ok*hM%KF##2u*N zDG)@2>&*3g(?sAT%L`_MN$Ymu4XAO{LMgPxH;vH|OhYR;WopOPoJ;1YAGOh=6pGI(lx+|=bH7LGh{<L%c3MZvsNP`umznT7!Ec@&T>`5;kN|B zoeaa+{f_~>rKj!tbSiMD>~TifAV@@!6H_gYHO_vbk^|_yMWUPP@F5jufibhsN3Yni z#^!$+In?4c+91>UY<2n@pm?HKMq3k<+?ej2oc^e|F#IXuRHo``*b0rfc7SICwoyNt zr?U6z*Cg`Gx+3Um_&zslox|pP(gftg=JT6FTiWSfQ1aTF)1&{ROyJc=MqrN3PUqru_ggUSt?33QZyg1et1y1z;lp77xN@CczIg4lG&H zo_f1WLUvr*{V5+6r@CJ|R}C>SkJ1^Jz*7IDiU=!{`ZI8*HD(4@fbQi=|2|=M!OygE zBP5n{-OFpOk-xvM!O8DPke4eo7CqmkqrZRo?w`{y!sBlf4(N zj7j?P;KrIzRv;>)FM)MvRe{Ox996ucqkq7N>*DY~EOOkU@+13i)4GHkB^0P!EB^`F z`vdTF3W;Q*WY~e#hfZnP(Wg(H`;$gqngxaiUCR);(s#VCK_wXKplwM?1^n@))si1ZX}sDO0BgSP z>7L?uY<}gxz@qn*(wnU9{OOZE8OUsuk$?#RC#TM2xHByfKHXR2@GWmTxfIs&3BoP& zARQCCy1T$(K?npeZ#H{vza%)@HS}w6ZpbsDNuu*?STfNDhM-ZYln`B z$K&vdjRs-ny$M%XwKO*)`|JF4jMW%tK$E%B&pGY{R%`%6bl@^r(Fd57IGXd))6sly*S;qp$T*qLW@F5@OyU}6i%Ii3 zkpRY+1||_+I-sV2+Ic+J6vL^)dPRs$ga!*FNa|nmOWXVJn2ysG$&i5C0W$QvPGnIl zszpE+fU~1b)^%5vFJO1CDe78t^^ZmgMjtkbR0@^hw??ifz%Ji6&Wez*qX%FRfLB9y ziSeoHYQhKOt`jhH)C)%a%NhM0XM{;rj?QX-PSc%uQQ`(F3m*v=ZQ1c2kOZ!Ov5@-y z?%jkFK9d)wu4qIK4)&Be&V3&dd0pU82+aF?1%o{5NhG<)uG)^&NqVKdGDE5 zwmWS9+t1AE-M*F!uH1(ugzdl2tw?k^L8LJ*a4hgJu5DTQ-y1(02_6`B5cebRe8&M` za3p01Qg3PfA(oL!ZohTDbI8@dMx<;FQ=kZ8YMHjt`!+_Jl@0w=zbfYV#yVMFy;j6) zVVk6H`QU}H?GP>ftZmOzsy-6B_?xQ_$mR>8trmZJ?jj0f0KpzI}d_wuvTw|h|zbh)KDVOF8Hj6BjwzDVkZPf1RxDNo#GGF3nu-Cdkt zzhXhsrOt5z`1$5!<`|l|ni1$YJ*2iDPtn>#7rq?6?H>X2e$4dUf}C3av;n(aJX{JV zT@{|Pibc-J;Kri=EdNfYOerdeb&y>2N(KTN@&^Mrdi`#5GUM;L07?+{;yJR`tsJk! z{&lVgu6I6>3npB;%Y-P0Y&)jNya6LhWl?yJPtC+<`3R=lnlsH+)GwH4mb5q*rlG^UEez@97K7zhU&@DaF#iSn$pH6b`;FT-@!fM&A=& zx85#6GB{N4v)6{s#6K(-y*+QdLLT>K=quihI$_tu5Qhvu{Y{PbXxa?!uxw6DUGbQ8 zLYk2Efz4;>ER}DmJU1%o8OER66=N~$0`)G-WWX#=HVp7K0P-Q7L6LINt|T5?tv;JT zShzS8_Qtxy(Wj7KRhFO%D^w*Qse=gc>I@68z8h18YAP4AHWB(^=7-_+i?ouk#v$+P z9RD@o6tu&BPHR?~{qWdLHNL37Gd(a5$gFo4CvRaPJ9oV&@v^?d3>eN60kP8eKf2gEG-{ctYZ z3FtHB8(LG21lP+{d!5G+u)SX(se^RN(gf)o`+osfU0hWdPmCJik7bh9j__&ZSKY#R zpJQIyDF2hjZ&l*iJWIz4zt_J!T5u-*hW}C5?a)55;d`F@9d+uQ5U4^_Q1&ua9YZDh zEPB%(s^avDVrA*x@84Wi{<$?(g{xj6cnDt+hzO`|(gnA>b;LR#NE>zE-~CVT;I;iq zFe(20_y#Yz{ife8zC3syQ0iYmjsMDeT_a}mfj|*t3TXuNCgwxm3^Hc*Z*hQXCVa4O zIipV0GVn>ReUc4jZ~ z0xciM8YsE5qTHbpphF}Ir}L#Qb9?Z(Qo}SlR%zCR6Ipo-t)4+%7A!KINu_|tDtTLh&|D>+((G#C_5#o^UCtX^!)k8JS>zm?)?I+SuK?>nG-&Ad5mS zcZ=Pm1GOP7guDO6vxg5lbfHc}cKd`3`Trg?<#KX;pRZI!II%gx`7LzscUq<0JD)?4 zWvSM0Z~6%sqTonz*2UB4hNk?Rv&IIDmZ@hkwaoJI-(2!B35E1F#A*Zg8Z1%OK55M&+1?(@8gcQ zHl3=&4B822ah&kV`7pF+J@3I?qoi}0L^&nAHk5H#@k1G9Jfn+{Y0uYjSghn}FKIx5{6J(R>h_bhQF11gW5lq^K zK06Ocr?gY6baDTgbiJ*H>mzR$3Hk>f41Nax4{ZsGqV~2T2-(|@+s4X0z0cd3VTUx* zuX<<0)9)x#j`J=_v3%gX3N)f{68Se{Xdd_{o$3-_7Tza5RE}dMGKPYkexf*qny$GbD-RHxHk2MA# zDl5E4Kx_)&SG#(d%OQYC_@4l(ytG$^v23PL^eYm1uc+F1(XZ z@KbYu5|S(twY$3tbR99fDM!N3=2FCo7Mcev*k@{k;*i0a;K$%sc+()7z%BMfk7mE_ z%pm&6{^$P8#75Z1vR1Y1$hDJa1|ixyfspR5V|~X5Q05e0%wP)SymVm_eu+3WPunic zh?ylefu{W_3yk^X92G(B?_0cv8k*U*ZojsJsX0O-a)PeAaDQa$k;ZI$>;^v!fhiED z6(}_STrT(G(k|@ms}tJ_OaT9Rrw=95 zR=oWL$R1}6M7dt%xS36LI>&@nuQuv8`Vx?Ab2;JA@Hi&ok_Ns5 z2Z4{LA}!SXpE**#HeH{xm}jNYo4DXieoCCuh9BOC%(?FzT3~Q~w(VS`-~*g&{a25H zN6M1v)Y$;Px|FeVjtSG}>NbfCGh<8QiP*4&8%fxWnG6&@lp7j@>I}42IG6S3fXeMQ ztb1k4(4A8Q$?!!zc;MZuLPjgret$kp#EgVSF3@XsW7KX(YFKf8_k)B5Ec(|NwPyU`;Te&hqG+Z zn+c(L@dzTXVL2JjQ;ZA9I9tu0v$yRWPEiX!$6;d>AWty^;`0_Br&>Twbexasol@YMvV3VX|b z1599g^cUw=)?^=X!&;ykw9+me$nl2Cv|?@Ka0YFlp(K7be6x^b3DSL(?EN{Rh=^3? zc#bYi39|tZhh~?%>@B2+-#Ez8JmR6;N9m4YLzMQ74z7{M{N$U40_^I6J97i1%x6EX zR?Xgw7`yHB`o~(MD7>`oBo?WctM;d-JcRg!K{rk(83<})y)kPXE!JI3DcL^FHsd0s zkvSPMML+`?Wq+B@W|GcY((x5fSHX2D1fBg(&uzUGc^Dm;q5wpU`0gSM69MMF6EGt` zL3-54AqI z0bd+G=02MfkqF3*otS@^uRZe_*N2)Nq)c8KRHn?ISSGl);Y?IEOM+RMDt0eu97DX2u@r3h}Z*yn` zI3kGLG85+n&o6a78~!tIt&#su(8O(uUT2C^@xZ5iba1R)>PJch>KHel&x3JNMVPGc z<+U1^n{Wkw6t5HOqu!%~%f#j0qs;i|iw8+WPcc0B2~(TsFjAsDrpymzPid%m;r2Fz z$5e!E&kzpZqpM^ikwls24jE z=Z5Z^*hmQGZDL<8kC%$G zNt_<4MZjpT)3K>{Yya^MwJQ4WksVGu`$QIx{PhM4w1J#-1!$OeJC-C{770&JZ#7PbD{ZhpAg2))GMk&a6O&| z;hJrrmI0NEnApUG-L%zS>TGB`8swl|&}MXi&ur#{S0SV1@0Z>)P!D~wT6o^?X4ADn z_0XxlujXivw<<`1apF4!@Fg5mcJp^pYntsE}-M+Hzc={ zL}YCQOysuyj`j+H6JKOJFQI>} zSpQ=0U7TOhv`$*0V+pEPC1JLWj{8&Q6Rmaenj?fGzf$VX?1=1U(^AVEh5QCT&C$Z! zQH!0eY)QTKE5XUr1bgDx?jM<|fUBP{M6zj^85q>MZT7RWRc}57%WwIb_;k?1smz+; z0A5zt8jSS@6X@%Ypr&#rfV@H098WK*5qvjya`MPU3Vk2^q*T7cfGQXH>#{Xxgvz z@gbqzCf#F#P<|{Y$A2Xo(ojn_U0Tc|3M~JA!;?Zoj!YUO)=;ZvzF@Irlmh}4DK0M< z+U4vqf?eqz9001i=lO=MIQmmG*(kBI*_ZVRz69k~SxjVW!|LN{4G|`6n#0(|NNs~$ z!`;nI+Pv7^gK4S?5`{U;`tbDYZl-VLG?i-{zyN6H>M3B)aTUq(igtn&Tcj?nN6P3aS2<$Dr`#wld3+dpxM*@@3hUTyD23E1o zlr#;02kVUo_(-Ynt`i-#)yPTZffpNEJk&ipc2>#VzU)$|*b)pYkA_Xal(#lU9I04E zUUCG)iXNMhEqzEI1_cG3#G9qw?{tgdlhJ@!*rJF((+QB*oLp-RP_FFxYp9AddOOA;U_%51&tl zHZg~)`y=ht8qtd8Kh^)ue3{k!ARW7)I9;U>_Dpul>;bU*xB z*cu?e%daD6JTqG<@wegER$g5u;7p6!<^|18$aa8+Ih`9x*kKby8)W1KkNHog6B8AB zJfeHCxvFBG)W=3BJ;Ow(fWEcLXC}Q9hX^7w`8|rVOHE|`b)`4En+hQWs)ruVb%;An zu+5dXv6m@4iF&)-rT&eTHt+&IfeB}{XB|7A;T18d{md&#!OO@X6S!)0Fg+|ulV!mi zPQpOB>q+b;zTw44H|_ppZW=c=%5Xn1TAXmxM!J5z^KU>r26!wv36K()g>6iZ zpJ{jFg0BWAylGIUGbsR70fuQoE9l@~lD~;zbeoRv%*$T^T)i+?;4C#Zw&=R|vUUDYtVA!76@pX4$d#~Vk8wm3U zOIUXk9Zr5X9eu(+v59;YuWu1_4`%wI_&ovWcn=FOBcsjS(K!d8bJYj@Q!vUkv$l_mku(SEmbp<-%Rs|`Ti#0Jg!GCo zj5Tbdc|RnfgkT;ZYUPLlYG-HLU>Ay>9X>3aRhoVZz?Un`!JRRJUt%a0)X_)6>I;%wL_k(?yj3?%}`U#G=>b#{Sy+(V)Xo*Oe@l1 ziHtb*sTCQ7ApZRbtFfk4zJepK8`sdf$v~xt(l7T7dtudb+S^U(ZcQYnCB8#2;fq&3 zh?LSUqHF~O^qTMU+m+@;oSkX#@%B$Q#)!}H9|(g-MyHuZ_%9-3P`_XStVJM1GwE(Y#^X z^bHVwG7SNDI2DRESPXS?4KE14CvRa9|z=Rl)G{MSj^ z@!>t>OU8`0R%D`uk2gNU#90cQ`JTb3$@n~;T&>2wurG>@ zhHl~Ps*+V9WIoOcT0j5>OW6%+I!|aZbEihaM74j3ARb@JWhym{6n)vFoJN6od;w%x zV#S#3`R5;<11^jc2!NT4!w7Ip_2Fr)vk6@Qio6gqw9$=_KBmOUFfPPRWE2VFDusR> z!uB~}25Xa%At?Fzff>CoZ);{{>Q!8V69$cBX0&c*wBmMH#H(voN1a(5^If(6vBcia z{98*V1x1F1ldEPiCTA3rIJb`gYTwM2F(#X$C>I6Z^hXp~BlT*mhmxW-jPpj3qOy}Y zB#(EH?4->G7?PXnE;E-nf0dafNiXDNYd%&vBhP81eYZzN$sd~z%}>1pUbxVt74)n< zwi8rqcT~~hD2WFY5(D`RYVHtgK?a-nhb9@!YgYmpFKaz2T2;YzqTDUhVF&r}R)|gf zh5rqAzPy!Pb9I_&*8C1=28J?c>7~lt`Dxc@h1&cy>(5PG}c8(~P2>q-WtJR_s+)?- zg@mhfoEIPBR{SO{AiIbIT|8w%JX$PYxdvH#Vu`wzQ+G#O7=cww@6;LaZo!*J;<1iJ z8kgo<qjDG4f3lFb(0RIZFLZ7e=(ygo8rlK zWQwhOY#E7l8n<*IS)bcNTFKa)4!OC6&k#5DNC zdwT{c@A~9tmGSC~O7NNORJ1#hX;+)Hn~6{+-MgrWP=)~i4la8KG90$X6F&p(4HTIW z<_+j_u4d&m;6o|tB_nY`JVMFXaIk~OHwCWn&-%{O8XJBLk-AAw_3#k`oi#FGhHErS zMQgEsmU4^+DfHQb$b*zq*+2IM+w5O+9f~Vio8?uQhQ33ev^&Pod_B5|1%g_S$vJMY zD;(-Cb{6pbkV6f3Cjhzt#z||iBlF!;-yT$7hkfBf%y}y&(mA`m{oio4Lcb+AA zxs{3Sp4TQ70r{??MPoUqhf;fS<08LP0}tKE5*-!BuJ?F1&=NAi=RhP_qA>*}O9RbH z5T!QD#RR}>crpWWhYGkH+rXeKlhcJNYI|L$N}op$B@fvAl4y~E>UbgdRV-EcEj#?f znnI9yz8##jNDrz<5$>s7*{A6lC}OCqU|rhbOtjzqpH$b&H!C*^^T|*o#81P{foqSK?Y3J9`;UK%L z(oNt@y>36=LJg#kTpH3@Fr7+&s3d#X2Rz%%32nDbqXfaEk5d&&mqf%;|L4@jPO|T&}8N*KQ3wrS0z)IWwk6DOy-+*3DJ!TZ(gz zfyr?&hzp_Kl;fi2@#d(|W`UJH=h#A$_V6{O?H1$MH{|c*X?;irkEX!WC{1C?Bz4q> zmAW~J9WJ~O8SH}^z)HXlGSbYELeQpmLFf<)g&IX*ikFVHWnyR7Uh0U-U1s&6^itr| zk7jtN#XD#%N$!!M<)S@*mvkn!0(&nJr+`1P3tL|w?7g0f+?s81O5h*@+!YTns6E=(%R#6mkt zr_6a9Zs%B)|IbL=*d4$8B7fCGs{x z5YuSWkEgI=H9%l5N5JFC6=vcZ zSGRoi-gtyU%hF>C^>vbW)O25#nwvwsfPxOK8n3_$9PXoK7H5U~SGY#Rsp9yhnu~Ky zYBzMl<`Y@w*_2pe4Snu>rhecXBj``eZ~`5#4mWKbd?r`6df1iNA78q+?IDGy#FAzG z^6GStxm$!kU_znmv_>WK+54wDL_124Oo0$Ce=KiRtvYyfVoXqSMCbt0fXlB*K=4fo zD=JTC`cZm*=CT^qif+NpXYBBMlL#SD0j;bSdU77$+1+)c1-yFSw1o(wW8~ztMdmDr zBV9E`?k(7jszyT2IMlBYCEpxTDbHD9o8M})8?5zHnMrd<{QEX$UBmS~Wf1PQbrd}9 zaWZh*zz?$ zV3Ki{ZE-F2x1fh6clg4Bp|JgrbV(GgIE)+d$bR1zTyBqE^sjBTH}17xOxLWkbT+dA*mY&neFkCzr7oi@iRZccuP0FejgZ^W zFiyd_%}A-j_B<_t@ad`;pY$8{l9FrjiZ!2FwW*D~XC?!|S`nyI5Jk*>t=zj#)*#8b z08_D}u{*(~4Y!kzRr43`eWUc#(mI137J_hI8i(NIYJ^tsL8gNL2-2sRMrC<4v-QBM z$q%;ZHx+q zMg#6`XHhEGSLSq?&Ic!ASHt0xP-awOZqfiDXaW&=Qo47vyUd{Py(>q(H+~0U3XC`l zax(2dYkC5Vp4!@7hu?f{$&zqHg}1MZmP?Xl=3-DhYjWHdp@Z*B6r{Kkv_*sX)olB; zOgCaqMn#ze0M_wRZ^VDVl!?&_HLGM>Wd;j4*&Z>4^gc=lf_d2$;TA?rO_JO|oL(I6 zUJ#a*1u<^^As29%AagCJE;qbJ(P($h{P}e8td-!T@0DoeLA_vSw@iu5h+S&|$_mt| zL?fUe-I3vmn}6_*K_S%%s*106mg4DP)`!Mgp35NA-^ap?4UIU~rQh*f{KFjUL`5<< z-ZD1_%J3y2Nrc4pRxomohJw^B1rbLt2Q&h|Bl!7?>qpj}+-(3@=u@T{Gj_c?o2M4# zq*?|20iL<{wvHU6wwlrniFi0tueg#2NvKS7xQ+v3CMUI~|6M@7N#|~Tg1k-`p6H0^ zYAy(oaPdyyBct^FMsd#33X_#ohp@GXjlp4;vFGeI(nq^r9jA^pX?LfTiklRJ8q(_t z;fYb^1KC2(5|Jk+o;*3=<{rBrydyJRprFjKRRw*C^-Ul^Ru9h*x9xBNGiQx`b$Dvg z8b%->68cL2X$trX9H;c!C;P9l6rU&x%A#I?Cpr$s4hE*T+P0V6JCR}(;|D&IN`>g; zx7s^+&q)r>w!_E1D$_UIxAh5_>=Cj=d75%XhUtG+v{A_8kjAW94zGjU;4V`K69vac z`~-O3S6sRMf9oY7jo@v$Ao*MqwyEZkD1ik|zpEF2{Fe>iSL1n2Cz^ij#(vNX`}pWp zp6hz}MN3$qay_dFh;0zD2Km_qpG`NQq)Q5+*uiuIGcTO|tOH4=Y0UJMnjoqylKXwl z6_EH9-n4;AlpDyr)cbz<*7JMEi7sr9pjkyQrj!cg^=m2?jR5dLQN6q`S%5+v^ z+^RsoF~%)bmw#;#`;0M;jHwMODAX7&7I`Rs%!@Ws_AJqXkihj_qDMX+P|y9<$)cGO zm81;*+v=j>{Z9Yj6Uz_IE7+0br6+p_RtSFv$3maez8ZMXNxTpba#)h4J?G-o{>JWE zjJM}x`Yrl&TQE2OA6|ZxXhcCV8!M@ET)VdZ8)dE~U(uezE2H3Z`7^}3t_(wsNNSOG zZE%3O26k*xu03wTFv;KqGDk|TC?oz zz(l@eA+AwhvI>}5b)_8rJl44%kJGGr!Y7!4tdks@Y@O*<85&`Wa#f&m<<0I117Xw^ zx6YNDo7fatD|z41xBc1L?O$=w9lQgFKFXe^Twr^IJDftTahKa9jSF7Ajqs(Lv?9|E=dWZ+TSU zEnpc^9?|dQ>2$0$x^fh|pTgRtrGq5W5iCcjY;uzrXkld7)x!stLnr^p8ZT zayYlny$ud$1}rKB%?*O&-8XhQGKwMMEXuM;I9Xqol$k=BgQx-I$FgMn>|e_*Y|(uw zx-&5R+i45JS8Z^@52jNR$vmT=Bz)p~8{m$_Bd!Zi_@3S|ZINZ>X5KwvYWMM#qHjXN zy9=|$PuXs+QG7kA&r~^b86AZ(A|EGyiCtwMNs((i82K=1VAf2>(Rw*faPyhGe}Q$3 zrR`OF8HW{WKJd^XUmJ+nuG{7CNy`f5>Y2(}6fc`$Q6+oIc4w`y63_j8i@)k)#zA8; zCV_4i6hI1NZ*^W3=fj&2+d`74I>aDf#`#iE)$rb=!%pStYa9F@=07qCwCA3T;R04d z+Hd^#!ywRpl0g6d$%5K6mwrezjtJ6`9O4+M%nkVBo-GZ*@*$#ohM9tz1b4{2CO6|h z&pxQl8B3h@YZx~p{&q>CEv4Hu|NG9EK66VmFeFY$U-FylYN;RhZqmy1FE8@wxI4># zF;)*_zfr$?O7(bb&%M8XNB>$WUfEaUQl9SqbHv#f;0jlf&jkP(F`aamTs?bf#%wdayk@ zq%@Qpl*?yI6(T79sfj1A5QQCEzOz)n-b!4NUkYuy~U8W*IEUKo-#ily~Qo0?SQd%+MFFEIBpvL(gfqr z2-NzVY^30$vk{ESpiuFD;^T?Q?iJ-sWiEh6Pf&Iw3pT8a>s)DZvwC|MF8?corJp1) zQb`cP;}*(U@x>}z4h4JgA0Py$cKY?Be2D1ex~uUSJmD+37BFgCv=d;@pBd#H^fcOM z%9Ho^+A0t9nLyH=30WMKQZ16RKMnLEmL~FoSO@-{3Qmht{Vzpk3T0L{3be>Eb*&*C7bfAB={)zqkA%yWQ0q`0q-t zMuLsROvCcaI$P*KThmF`EXB}KHlcYt|9ustVMM3yydoaV*&#)glpR7&KLed-=7GZ@A8X z@-rM8>mATopp|y|@$?!o?`vSX5lUplEXcIP(0=~NfJkm77Vf8a&&8ASq z{ry^G5Hpp5pQ3Y3EZjt4btqvc2drX4+IWi9N;5Gd+~k18`vu8>d#&O6e=`0jA8dh{ zOO-qZopGDc?=0^EiZs&rRz?rWq=zgMRDCqzp{Mf>RXt?Mjm(%p zq|y@no%lSB0Mx9*%v5qf0dY`8czm>ATi23okXm|3~+f%6cDWqSo5Y=Eq;dk zAk%B}|KgNq0{nVB+F1O%1uY$nien`O%oF=I+zPnGwL#-t703;4QRA#JmVhj3E{KOc znjXSeS!#KAbQM_-X-O)D5TKF79oTGielCl&mZf5zs#A<~;t)^!34fH1sCXOeMZ&GK zfFjR_!g!&6C%H7(EguC1g2|W{pbapmFf?o|K5u~;72;g0&}*ug281S0jN2KuX-q?aDwJ8k-S`eOWgNl>+)h*T zDG!4_s#SW>sAJMk)`%qlzl>(Y@-cs3m6xWgKeUWeXt22?e{^BnZ~u)QmBV% zt(RCGxzzW-qvZ$X1LM>(mCW;7)5;`n>)OZEarl6`sR1))>;mjb-<)yD6Mm@GRzr;| z&OK?-+L7|Od)y^O;!KZrJ17JZI`mw8X3)UAV{!`ZmIj~`MzqCJ5h=7+k6^ngRrt(T z=-kqW7&ew6tS3iRFai(0Cnjsm40rJ> zsf%_^`|;3?^u@>urBO+law3Fl_;~;5V$dxmXkT`%VA;3^%h`}Xy{t|#C@U{NqXQ!) zSdEvbK*N5 z>d)}~Z1?T}l>QJN?)!R^rTyhBw%TK~fS*@y95Y&)1|C67;IgY^2E443*vs#^;`u}!*t!(ipj z_A7l|oJXchNTeA=!t#>#ZcV*Ch}SUEi-sU9`JI&KH!S>H?eOg1>@(d1Z*f2vuAzf{ z=o?l?^KSu76&Ed}%DWze!_dd?=0kBMNUOStDl1`3C_uQYOf0i%pDQ8l3 zyAP)jSi1vobK#j$7gU(E&-Kw1ZGkJ#<~UX+!E3g{k2|#`bv@CN3}1EDR2%d`ex4b8 z*E`FQy7~h1Q`}DN8sQK2cs`$oJv(N0RVUG{Q6X3>2v_5 z_jU+{0}iO9?*-lHAR;aZxcT8{T`75}h+&C`s(`Dx#JH9k2_6}nU`b+reD*AuumuP0 z(UhJr-PRIT=2bXWrZ(sTJ-76qs6}$L@*#Z9^lrIpiF-XiWzcr9y3@~}?*G++`x}UH zq+N)$DOIDnpr!jGnx3_p1P4*ydPZ0xqW3x4s5diK#^Ou$-LIT<++EQ;T@fIR{d+IUR+((3eO-YQ!Hxl{yOoGOE2S&-AdMA3`0}D{ZQaX?=4tX<&U)Ce($Yqh>s97`B_3MGCEsHr<)vcR2OX;6BlFuE=b=5TQ2V2!E}8U!juhc+0$j@R zd-E1J{e*L`USEhFBFE}cz%@Fu)(PZ}Pb*cOBawqq zjKS7yZl^#Pei8C^W zSFld@qvPEM_^ALwK)t_aq`tWAu`X=o8@^ zB`NQ{s^LT}ChL}2N?}yc>7W(eX!M1Y25u4YJ2TVm(q4lzw0VsFg%t0fe`d10yj8dW z6|WAW6mB<81Z>h&@M~RUL5lc}?t7+NKFo8NpO$G>IfAS<^ntbq@M|}d`@^)0^ z@vDi?iWV8dEfztqVSgCxT)*#lr{Ck8zAmL$%EZU})-}0OxgShE_22+y%tD953#UhF z86VwQYzit+edbQtNhCp6g49`8ml0c{f^Fu=KAtYk=Q1>9eA5>v37jk&)Oo1 zR6buLX`!&|fb%LNu3&uZcLo(5sv8{SJ`3&!){Lnh#iC-N=XXx7F(4|p!$_IFEj64? zakhw446|ygB0c}WfEswK1OyzI`_?HqQB}GSGy=~y3Vc!i2|rDQF74rsRK1>ocOFdZ zznnQ`wYgO2E9WSf;SgBr?{Yn2m}$tw70M9i`N%_CtB#tq9-yABZA+vwkhogj&bVRH zf|}adlW5%E$m+L4l_npOS>v5y4xnvzmXxMGm2r9G1DW&6L)XSmLB&WIJzc-h@O~@y z1c=HhihFy|#gMNs3AE-6X=%s33a{Ge2&%k@1$K=gbdFWfAoCttX~+*%=jIs?U3UL1 zn&Nc{qcIZDe@IXDcCyPUKrv{a#RCu_Qm2eZy-F3rt)- z*uBOK6AZlslaQc|!;Aa@nN&0lsC2wN2NqJvjAHJ7@Zsk%FN=#wO6$iOfwe!L7=<_x$E4x56v+Jn+6u4%7*q4X zD=P$x2K(LRDOoG?`Kwkqj8U7XFUSCgk9?29v7l3o-$S6w2nMdNfX*qB5%Pmq9Nw>WS+ zk_p{30K%Xl67GHmmFdR9Q9j8;GDW|kLSRP=h0%ySEPKTGUn`KqMce=ko>WUg!}g{$HO!+FIXv>6yM5AX%5bC>%mE=agl!5h!q@P{Z$FGLO z$`?cg+4nGq%3WbmY74U(g-`uTvK=k2G}3UR2f`MV^)dI017c#1cKFG9I07ot-&!zf z(L-sGP`i{1Hd%>M!8&sASv0$*tnR{x5WO5Db{DJw!#Q;F+rs3efaj`-PfVt_37$*v zl?1%DbXsc#M8?%p-ySb!zOz$Q6*|;kL8XUL2EXF& zZ@MFML(Qy%@Ye;oOkbh9fume?)20t1aAm zOExXCQa;9yU?-;EMApa5t>q0TlBUC(cT@wDA*}wFozc$Di+`02OD@A;%#)`=Po$e| znh|X9J=cW8Y~yT1`zXxg6~--@$iqcv&wcC4@YTq*S!AVmolM=T-r@t&Z+A<#r}tsm z|33NrnPF^t=gcU7y2vgFgtf#*W-V~I)2Zfu+=cW#9qR!E#s`I#3dnv=t0x}CbT=jV zisn5g!fwljvkU@L)iAyU(|3 zK-U(MMCQ1&aN4K8YdZ}1k0spS4{>R)L#DG=T~bxGT>;wb-L<7Z*7SOq3t$Pvms4N% z(jgav6DNbybsA+^#=mutVt-U7Fod=k1b-G8@U)UYFQfM#Vo-1fn9DKcxO04bjO;}e z2JA;4Db%z0)C`BNfQw;%UIYHd!02x+F;9XLnKnpzdV+C%u;I3C!0h{W|37{OR${Y( zB11`Ou~n95g~zfMOSQd`2#~_%G!|%Emj*bdCbW&bTRXe%Q@tFXsh0vX-x79O0r3zyCmrto*|OYL$}n~mf+)J$_fqHOI{Ni82`)GN z3524)nC0OIa`owU8dTM*aQ|;*$Hm;M%FN7jH3?lEK*ajTON(Dh`#54 z!HAttZ)HnCbRzR+Rb4w&F_QTRT_1rVs3TrUNW(&;<{ZwqU*pEm8fq&QYI}Y{voD)P z`1P6-wVEHQ!MlFBxvG2HrZG`Kmr_MN(p{zH2=1sphVh3-jVk-LWFhE3g9y-SJ%qn(0-R+W&r_7nh<+ zZUn32n2^e!8LPa`mA0y^pM)DuL5ul537BDGiz02Pd&-r<*wP@17@aXNq`_aoe*wr6 zfH6LVYK(MEwCXP4CXK&1;u9FZvWhdYmnub)h3xjtfQ?|hyCKiV7OzDvw0MD9cITn9 z>gz|j=Gz7w;3a8cQALO@4l`$+y3`*7=Rk`%Xm5Quo*9~hQm@iQ4~K*riXyj<<)W!7 zA{z;CEWAnq2IE5l;1)Jh5{!w!*N8#KUID7i09Ck&6ZGcV_ja%U`kb$T!-_zQJVvC% z!kL%%x|;HnK+MUrk#=4&!!4{fc#m;&OX~+7eRj9%lktp+z2 zxulA$2j4s5dLu3+Lk>ecdYE0d3a)hXw5Ok!FxMt!U@zaUySvx42d_1^7go@y^$^LE z2*J)2wdUoITCuI37LBn+8I@K%mn@q(!z@Iu{KWqUw9~U%7-guv&#Wszte1H&gc~r` zfpudK6xVkmVIHQa9v-6!WrlVFh_6^G@=z@f@g$4PoCGNaFMQeX5zM!>pV>YdjB4;Y z6OXkxKE!WRZW;`^<+K@&QtYsln@k^kpk5rLaw+PlWwj?%Otr;P3;0?>4=)m^3EQy2*c3l8S{W z{B+JJ&mH&Oaw<>`Ru3xQwV$P^;CW!fwSc-s%~}zS;0(6O+~o8fYW|X8>WGB|1W(*R zMjugXTz&gh35;70JkE{K|Eh zRwRH{DBYSbi|DXy>8k%T25a6N{aXtS2 z?_;1!vxMt|q6hxN$|iw5G%>Gnhj>4A(oo(;4kJ$kZyKws)Nhzm{=c6pEVJnHL|+?9 z)a|?p+iAUD+E%6mO4K)$K^=48#m#5JXmNw)I83V*>4Hw) zTFZ)ehDy~z7Q1&b!19aC1$+Ry0ZbL?hY&kGZ6kGfiYhwLf~>5?XOc{MP;27MMXe(D}Wp4W-#DzL>rVfHaN_O?zx+98(30cn!|@fy=7Js5R7 zR>s202nxys8!$->9epATD<5P-;0S?o(HbeId=A46^nN?SSts=^h{_T&d1+^X){1Tm z&ADe(=A#sAp`-8n&DDiu4vQbQR;zT20L^^BIQ{K9gQd1odS3K`j8D%&X5U?_2Gl~8 z35Vg2NX`0}wu6^Nu4Kaz_asS2pR@}um3}IteU|epQf?No>kJ*hIxv^XV{qHRkiqDF zXLZun!JtmDct(4MmSOz!hOtKSuA%z30Am*ZnltR-WVwjn@L4aiQgF2a>&G58jQ{%U z4b024=jodWuU3SHXJZvS4DW24x4eLI>cVYy)4keA+!Rf%Q)7mV?t*PV6Ca}%?t{7# z*Qi99EmV=^f8CpXEx8qyQA^0ye>yLd9H8n7$(}_WP3y7|MbID``UBC`nVA28w2EVI z*~IRoMvKoZR#E6iUU4JYD?yDH>2>DL`kCm>8;IXt)@wbYKf+2&@FS!j+lwYX?79)1 zT*0ATp>KL@%WuX{p6mWxQMV&4LNNIXni{qlQV3#QwkZ6ERW&P$A>bA{y9|2#A!@e< zB=FMogVm2p(VaZ%3IzkAF3R2)x+D(q!p6mSS(~=mQwr_^CjIn2F8{xMAUA)eyQNrQ zkD)>lYVxBf(U2sUUfybKu%ln}>c2vy9MxCi@#DRU(wbT*?>|~bY|}aa5)B+cr<3N? z(`&W7T7{6c6D5rY)Md~=u7Epof3M}*$e^nW?S-WboG64G=Y8zbr492XAWX(oym@4j zetyoY(SM~ypF4E{j-=D#6n<8`($fwd^#jy1^&{E9`zNYimWCZ=22{<7b$tJF;DZSV zTA7}~d6@K`UldSZdZX@`vaTgPTgqjRvHp21#hw;gkP#1i=vMojw=%0$mm*xrGAC#P zOt1{xz{BaZ@B0sxI*+#uKW{z!t$JRZwu#AnZ7MuvCn1*3^0%*1&cCPaU#gWezmuGnB#%o%BO1m8Ni>5;XOBIELAPeI{thoOOsHX}c%U@c`Gs@YdjADqM# zCdpi!f*hTuH!im5aHY=EYZ@sYH|=|-faXCL{%H~Cl7ms;^7<5)D%wphLO&Z{tJg(A z)IKniZBsY&PnVir6}90QL1!Ah73=OV+$7N3{KmkRu{r2g&8^gIfIhP{Ekicw=gXoD zGt@T4i|xYJwh(58y`8RAUUkAL=P})4DjQ?FolhdI<&!V0(@NmHc3}pM(?pV z9&wh*nl{QFTrAD8JR!E}pMK2gZOyChD7I5Z!{B1asNPf-nS`Fntu64Z;qNF-FNnqY zbHV-Fqd9N2*bp^YfV737s>9=gvQx7Um7M>GSS>p;&R$z(RgJG~FpFkZWs6Elmo+5N zUys_O=ZW9F0v~=j1X6F#pV>K-PAs4zQ~dL$WS}SW4_dV}gzx1<3wBW4q#RSYZ@(>T zZIAfNdS@rGGifb~Tz-3ECUa@p`0i$a<~Lu|+>#zL2D!-}fk#-$@zCUNtm&K|TKwO< z`VB(abg@F)ibjAUpi0K`5L%j53f5T1tU@EnSYYtDV?~^4K@TO9iGrMSk^ZObl`;gI z`2#C4##c&YmtJJLXofPa2Pb*P*8Pz?`?Yb!q0T8Pa}ohT{3duCilbB>aLR*M7W1N} zYfYw#{KQ{{Axo#0#T=nRx$!9#{-t$L!fQ=kfZhQne_R+{pL(UlewQuY3Iq^xDYI8& z9_J`q+%G?2iJ;w`%e9&?0=JBQ<&w=W$#5Udb&5l+f-7Qx+j}?@gxMc56~ykVCcHP@ zwPuTHV@3_~mvQRos}=UzbTdc|JOfj@&db4+EfcO}*$FW($ngT}5dyqIUYiqEYLwDs zf;XyC54Ki`aYL)!ifVCor4po&wHN@M_VmSJ{9sSk94%KSHiqPl3c1#2X1!LP;<;_t zpNVuC(Q^UGZz31qTdU?kzW>)- zD%N=EN3br1zFEkm*ku$K!@)#oRvtxNd5eKJgOi{&P-TQ-* zplTPlgTgi+vmuWUWs5*>PEwHMw}mF1zcu`s5Ti|E&ls+^r#lwr850~M>0 zJJRGMt`Xv=hd$h3ZeO3dYo5wBLM~<66|+)1@61iEb&NJMfP)KIp+yic%+^1`td2qp z%LZxdY&uK}`7jHB2mR#RnQ^Yt5IeEF~H9H-4;A4Cw`AQGk2e`a+!~2J&_6URw_vi;QOnL4tZKYe6l!d646Z~j` zBI&;PnSh0K6p%;+3sF{CfEara46@LV8gMJZCM!doZ`BRph>FmQD65(k;dwx=v>(}BsMF#4wXCsX*PTwRV<@6?J1jEYk#I+u|hAb~^5m>&-n2|W+z57u+UCz=gxE`B|UG+Z14BHUCJ-whq zo=tBFLC8|F#t3T=prd6;-=`0eieDUQX{IIM`*C2?&GeJsvN}*ikFE`#SVGGp-AcU8 zca)NNMDf8=&83e7!@qzpZeh`sXIAxp1Y?O(6vUVCsC`MxdM-?GQ;h47P^&6?&Ao&XLkN{cB2z)oY z;Eve2Euelh1iz}YP&Pbh8wba`N3b6Ju&UH$Epz$8osUvYOS!+Y?X-I1QkajL6;#JI z78Kw6gneQLo@E55>skl-_p)28GJq@TplbiRE_Qs?Q)>zh8awj>|5<62`GLCq1E{MJp@hYQ_;gqY zeaQC0&dY_@RrovRmhA!2r!Rb)sTyR*d9t=#Hh(hkp+a_oVi9^0f3(0|`3@mcc1Kjk z$*vW!J;bTwVsnc;M(}3wG@PC4w|QKtdeNg?89*$V^)G}!;RNe5N7_ss;MWgp(1|P* z?RO{Ydv;im8zKe-nLaklZ|c#=<=rUQ)i>bwKI4}%FzLi2zoEZ|G=eG2R0Yh;+wPUe7{ZYY0{N{k(LsuG zev@>YB6beg2Rar^;y+7m!iOIh8cUv{ef}1jgBux^REkhW%jAg9XLcW(d{Cl(pO%#` z&r9LoR+}VDU9U4wGR^H~o`HbYU45S2u?7@5^MVnAG(Yv*S>Z25`dRq^mvc#x4I{WlPGBaXO2paNPKQ^aGE(7K)YzLZa&Fb* zLAz_|T?cw(z=-Ml!A#1)Bh>cpml_ybwFM%7Z2TVGPL z_EH!Y7E5^5>mK7YyrZmYTvKrqKW*QoB6wsMyrP{EL*kC~ zX4vu|cXm(bfIw+9I?6fL43h~%BbL^aE_ulc`nQxI#0 z&%>vgLNAe4Cw%bsoMcs@N{BO`KY)rsqujt_Gx1q3LmM#&51E@!JragHBBmBwZC89V z^mlen*@@?lpHi6;jHqxcAr(~NBV8DE=HkrW!1#Ea4H1&)s=Zt=$aSa!u&wxqu! zP(D&G6{dXKlYT~nE6o+%O$i2YRly?#WqoYrHRNgw9zHcN`*$+U9%Y2|K3(7ZH#u#O zW^)wbvwpmYyI3(34qpf@AF@^R6VI1X-gGfb$icRApBR!BKqPpd;l^2HT7^11Wx+b= z!4TM#mO`(6JhyozLzfPSjzDd0>XIc@x~|&6YHAcZ2+u;N}UE6>S?RAUiI%~ z564e?Rd*~g8+0N4)dV8o({$7#^`BY`qLU+bZoR zpal>xIIV^|qAHkW2}bH|S=4O8Q+Za373UpJ&Zsd`=V+`_*)N z4to6S`KJv8oMTG!w+F%q_*51qu9tU6f$`A$d~**3Q~Z@{$D$*|_f?AUR7YShdiGwM zvMpRy@`#5}GFx~xr30Xc^!;ZEeThJbaZ&AfjsK&m&v2vIyIZ$Nlu;ZYg27}U{i5{w zUaxv)uJRU0n8^xWstJNrKN@<>O?;A)ToQS2mu)yw3-|`cGdl^te}MXf?@TGOAospY zuip*ad`6^y2%>=9VAOb2tuhRk{#7l4BEa~r`XsfKiqWjKw(?ha5A?affp}Vk6%WZ| zg~)TqppwJ(CDNhUWE$sHeO^qL_ifu|qv~6FLAhs=ENyGEk!(9rMOW0#uhUn{>G9JY z*obnaF$TMPpiIR8K1f>uBOB8{Nb^4B0v1r?&23yv=6lr%?tbz9O@3RCcW&^sLvn@_+v*; za8|j%7a)Vsh&W?(BPPNU&o&nVa8Yfg-x_S_as_1JV5!>(QiS=+_tEx(-~K+ev!pIhTF{tz3i3?5v~E2RCysRbiGEIjg98ZaPvMb z_5aEM%WK!nlD^sp3Su7_Ro)o?lWHZiNJCfvEb^<}Os_ag&Qb<9OSB-keN6#O7x})X zL3-%vsEG;v?#B5rnXSHQJ%kYI=mE%FLm1=bWsG44GSp(SWgHNEY>Qn{tlaO(BSlv_MOyF{ToM*NHrk{PSHKm~9>| z*3ijPX3>z^TK*CLldbs913;QC(&u?`ZAH0WCdjiVFJ&TW z>W_A8tKjKQ>HejloUM(L_K546Nn@pg3tk5-v>>w#yA)(3OM`hTXQ`|i7-{TVl0}hg zY*_PY^`w-Yu#YbbPY!_XCxC{oC36mxVxUBHec);Jd~VFLaEx!5uQ7zqz}qL4+~(k< z%HEgu_s(493)MpyIO&MIQ!-3Ti;K6AJ7MIr=G)?+yan{+HBJ#LhUvPxs9U30jaayY z;~{MmoC_Ez`5fDwsVvh8 zYv}ffd3jC7&YRvvPVU7bcz$uV?kK=y+dDbPxZd43*|v6$%@_a(a}PJWfak+L7ybT> zG_@!VRZ;)fUUEGiBg$1`PxuNjd0Li_g8tC5KNjydA5~s_ve-jD`zgmhtNTFCa*$HB zx0m`Z&j#uv4HC-pYuTR7w$m2h3!j|4EWE=c^?ZJyrg2P%KzC-pQGC63?^et7m^v^c z*4`nU^5PknMjU$wc{0bxdh+_5%Hf>3#;t<-ta`Ikyz)qQKr)SeB9uqAG?yG4nHw*r zg%MR7)6h}YQM;Rm9zDhuJ$sRSCS9pR3I%rzb@&wQLUoGsFXpyQm6#TYig#XbbkU1w;O1@ zuMf;`4h)JyGcJ2tetsi0Si6RdsiH!>jdrs06{JJ*x~AM7o6{(+rOif(D!R^h)}9(S zLlhW}q4S~`BV~X!q8dO7*3GNjYxd>Ueoc|FB-D#gv+zKZid9_P61dt&rNSk8APVRO zUM`u!6?5Nr3xaWk#d(}04(Ff)npN==AYon!6UDl5Kp~B!V8sA z_00Bpou+bA)d8Tx)I2^^u2L&z-0;TOBLJeAeSkX$0u=5zxvtk7r4yxy~hzw!#> zMSws{AD*u(fB{Zq2;B(-6oN&%JRR0Lg)_>S(TisB z2H5*c1~FsphUjb_KAm52T0~w#4a8cyhgI!_PqsrQY@)p1j;bCkh*C!D8ekeb6 zj?yig2`qTL5uB?5Zb-QZtE_B+|+ zLiY%5^99dl2#uB;qX{8_?KNX?u2S~CIQu+$9N%hd6QZ-~P#W495pvVp!ogooo}(i^ z+ssyJ7r3zqa9k4?kyA&uhVaHuupH^R$G5+*hTTCfE>d&C34ob<^@N!$CA~Q9ccJ?| zQMrA4L6LoLxgKkY#s>0F5tLkusRvUIM#Uw+p&0;(SoZ=XOyGT5svH9nXLJujSytbx8g)A7%m{O25i6)g%-Ao?9s&>iM(t(1Eb8Ibc? zJfdU(H(!Sw%1mVwu$M@ccbyL6&w7u#^!Wo(phaJH%%#n(6PCZdhC%fX+7{lB;&4}Y z>d&+26D3>e!y)ezG%l-`aPhDMfV9w&u632cg0xbRPtUTZ1q;pxa_{AZyGQLA%4b;P zju0Z|5kOAxgoKjxRb02>@;ewSDRe>I|D1#T7+ATCl(!o93xQAOZW(WG>a6zB_0MO^ z+lKd-DZ)G$!f*s_a_}(rg&lbB{WBOygo^Pr@Qzj>KD6RJY1Qqkaz{Q~{ZNnly07d( zRRA#|iFhC|FF>6;CmYNtE_@Oc_A${UGVV?;)^oc&JtLC3h>jvhDZRZd&2n(g%3aulO$7m84Rm#*(<9ue(WY@s8fe6MJvR#4%%okS zsDCU7rH1f*S;)~}bO@S$=|nInSfIVUx(?t4{ealpSd;&E5U(vAZM>7$zx89d-TEB&_;9!> zKzGOw%U6ZvIu6IuKJIF(S8hRu5`{-zmOBqSS>OB8ROTD`-rYRMdmM;GE!!s`9vQ$; zp%W^bq^G6vf6$+K{z*x75Q!f|;YHu2rE77M{L0dnA^><8ZlD}XX3%j7mA!>pQ*7Bb zUV`7@a1lBiy>jer_UPEUh3SFK1!^f6kc4)9+bSr@Ihsz`l&>7`h4*4ygeOU@QFxWk zK8y@HnaoVKS`1?C+GILCUbZlOS_;+Ck>#1}@*yH?boR5k@Xq&0sFDdwGP4O}GIOLW zpE3r8ghVAE?000?V0twxt$R0OhhIkKRi=JB5jqO%Ob{p$=_>jK63P&~IN8uh!*2WF zG_$DEP#$)8&EStzcw1qoEi=mvluicc0ry2UlU__8J3z0P0B;rus6#v;`!+>8ocmX%-tQe zUl>?<{h;DBhz+8hj@2O+fK{*6k|$W|O)Nv{D&DrADpuAg*V0bOpc+`~$s`+JBew>j z_IA6D^_~Re;>>}A5K@r&m=|vc0(-(4>1Fw&OarD)sla7TvE_in=Jw4!n7-fuH#~1Jhxn z-w60awUy;2U3l#rvQCDL3v~M@fN%wgd7#d`_;X^({T18e+Ian2vC7{AgW%S$t;{vjwZPE=&qaaQ6s$`i2ThjxKt50VJe|U-%q?DimVvq6SvAwOXKlkjC;m6pVFlQbhND^+sF^Mbx(v_ zUuPcY6j?Yj=Y$tbo#NQ*le#{-!I)7^qm^o0o*mV$x$Vm4Ibo`~wYMmy#>wY%jC*wj z_GxAfL7NN0Spp|T?0g#oV$gIYhO6R6*G%~Sgcc=2l&gc6ljS6rnLHYO0}&@VN?0Bw)9HFf9a5|unf9!(hS&FZ zM7F`vM3;iSRnJ@tj&&Hi>2I3Q4ZeQ8gdM01JJN$6hAjS7QL8qlu12srZE^q5uIF$) z+eI^%mqk@=n6!B&(0`5($39fF`#CKC=_+l2e4%Q}wjUnxB<$#LJIr;Q2oY*9eQ=cl zCxuXwp<-^4M<^oCijD@CxHb0+LB5RSVnAeeKRGC{t!v;cz=mbDzZQR_)98YexzsU0 z;e{BkR)<{<7EN=pc;^1xr);w_)9qSu%O^w+2ximuCmTBVBW1aWZVzqH_c^Syq6UG$ z_vfTTuQ%tH>^N^eh!2C37?4nAlo`So2kWwbO!~U@H>w&7ye?5z+D}CYP-Rnbx0Roh zhI9`aEdZXww|flTW3${kbK26T)e$B1mKrMEj>$;eIj zwTZI&34X?lni=B^nH}{>Vx<3KP6Zp~^*OTIi+ zjHzR~Tc@JE>)(xYx#S31%0TPovRd1M8)7pnk%coeGk84CMY1hRE4zpMtDh-|pf^EF zLPdV6KyNhH4uG=_DxBC7{A}m(BNY<#UsFy4p&Gx!-Vyc`-H=(NlV*blu)yH{BrdOXTq@ zcxd_HTpB&2%K)g2KdDq9e?4E{Yoj~Qu) zgnb!cN?D;uEE zB(`Mla^i?}+JKseD|Qrf!J_yAM)=E6zCVK4?tzo3jQ}Ose}{DC`m>Kv7modo+3q6W z;J9UtP5(1>iW+5En+yL^zw^zv7W^v*V_M1-3GJvQvt3$mBV1Kngr+rcTvz;Kjw<)O z)Dl`i(b%HCViLq@Vr zk=ff7-TtovEW&@ClKzw}?lwZ_HRu7tY|@#I>!hCrN~Ur8^MVplJBNI zd8RQUkE(j5U1kM(b59!9%gta&k}R|p%u)il~c1b&qJ%OckLOPZU0|)t!md45zBGM z&WcxeE{wS=%D*cBk>Dn6Nwqk9hf%&aIH_vHV9`J8R6Tk6sA2bDwgr`%ORn?0&rmd2 z@UZ0IhAXjxE{5>Tg~uqA5OV?NF}Qn>?(d3raSAX(o$&50{15_32EbR%75NqEjKS&& zPh4e^e2oz9o^SZhfr7Vj=fc%A^IT!O@J{HI#B)t*ETP}KRW6)a+gUAQpURZnt#=l2&()%ZO5W8RR`b3I+@c@Gvnl0wGaz^)JBxm(&r`*m$XV8tXfqyK+;XT* zJ>InzAtpf&Ar<8rv)I_5YNoj<07ikzrKwx|_QZJ)q=664pF1Ze3m)!%2|jX{-!!o0 zQkjk5Q~3uXBmGe=NgoESXO41@O!_;C%jRBER^x!uPfg6L+k7DLB4Nm8=a?;9xed%+ z12Obd?2Te)7$EKS5)u@&?_~rfBpOB=8JJ5QZoCf4G@#{a5%WfnFFk_ac8L8c7o`y< zUfp{kn08D1G=985?)n`pKa?rGt?5e$smX_WATJ;eI4=y8jNAMJXLAUuSVS4HXfLSCS zr0zlHSd7}^@qtM)$3wg;Ks@@Y3wZWXP}&ZvIN4C%U=K5of!x$_%LNS+#fJt2I z7#3!Pxv1lY``ZzL`K9Blc|XQgP>$X_|3lrp)dEbsD`NHks~ag=3lqtBZ}aE6wFDDVts}rpgVAn^1x3|(;DU%b8sK6&qr6kiDYnO)f?Nm}_Y-$byKsA1JaS;E+GoNXkKJk9*@{9G+y z6ritrFicbLrhQ8o{7an{bx860tnx2m3%rUOgwal08;9215p)((m-RI&;}cZ(A=?sz zLi!V6EwFhlS*@CJWL%U`q^z(54BcfGCZ=7feOyaNQ30Co;NO*!5TWTYw@KmQHC!JZ zk>4tvj4M7=hk>o%6@_WTnlfem>Y zZNL6LW+HJvaHcl8c>LJ;v5}w9Y!RWJSnw~v8a0s|bxV;xeJod|4M(7ZkO|`gN{)MK z-y`n=Fv2?{&SM)x9TLPbMt5RBn@U1L>_qU{8)euAp#`N(;pFzHTM{rp*g#{R@#VEV z%6ViIRc@iys}l%CAw6NvTJ)4FcKN5SBV2UP9fooP)9fR0v&J8^G~h%#?J*5+T$vo9 z6^iiNAjHv~=%-dkuqNZ)K(;3X@V9ba?*kq3?|d?dIu=Ojz7)wB6EU$8g>47X2AcwZ z_>E{%dT~pxg4-;Qx5_DJU}D;WcuN9yV1fWRijWBkh>q_~XxvA{>PLL=tYWm)QZUgN zGs`EU^lLl7WQ4hT1&h%*aIiTtzb&c2kYJotk?jG&+k*9lnd*pxjsG429InH?`W0Pj!v}1|pm=BS)_~H8RCQ^@*Mr0e5A(%5WN5vws zo4n4sweC?~xp1i~kqXwvHf5lCq+dy0e5?@U0b?07qomqUsmIlH>c=OZfThQa^M#v zbKNPQ9>wMPFIP;$IBT$c2M@UQHH6ah0`?~^*ur3>%+G8HW}-T_zjKRiJzo0w;0RXf zaVK7CbC<5^?aw=!AOjq`@WI}Li4-4X5yzrQa^6lw?51O z^p`X&5>Xk1Ees|a^6ujYbEY*UpP0mOAJ{Z?m(Jz8rC%-nLQ8X`y6hwuswo&B%9w@z zVIl&H2gHOoNz7^~EwE;n_%b(}(0$8B8pFxIvN|3kEN91hw~k?@ZU+XMdXBxhmv*Gt zpCclsSp3;{QTU|C=o6Uh-O`~^Vb11u-Zb+ET4ZY*32<(jF61o$Gt05%KvLAO|58AXk|0kK`68;_DcL}eE?lqSfaVqGT>BUSGO4aDwaW;It3 zRAh8;uU_*@%3qY%z*o2FXvRmRk-OWXwc*tdnM~&HH#JKc*AFwsumW@L+DY*y&T+lh8qtAQJ;39C9lwbH6@r>`Aer^00mm8bzar0v`HEW3M--?7 z+*gw8IVPc-xLtZn@}P&I$b*4BJ&n9&HT4833r$qUW~9Z7DXbp(tf?Phf8n7#VyvmU zWxN+gRE;hteuimwu+gbH1XOb^SWWP~AD6NT3Gp3mJMx2mrwkO;On@(b)Twrh*`+YH zNe3gB^V4K4+mSo~j#TJ<9R{^?gQB20PiZt2|HvoR=?v19sTR&vrj7J|k=H}f?6^;< zjoGrfTjSEFtQvN@uJqT7uD{j%L|)(<=(DSP*=yBfVF3$NNxT30m$eXGC}G=74C)t* zV0S#AD6{zC`+!8H!XxUsA1$MqW~sP8F(eW74TB)T(h#ZR!JgXu;ch0sD zb-0#$+dk-YeVo^RTIZ76+;RKJ7S0=5eQB>8GNM0Sz)EJ1JDKMB@jXtY5hy}7Tv8B2 z|6b#^GC7)DcIGD3b{SLr9e(UpE(@i5*tS%08uV_16Gk|$5>5R$rn9q%q^z1UGM==t z?YC_RM|tX1iwYssSt$V>31culX0-zko)QhfIe=&7kruneii-C@YuEbzQcV=PJb9J( zkKIEmDJ8GTELLDwolp!iFSYMCH7yTjx*Amb0EpftuLau)F_HcQ!pLob3=Q!vYoRyH zgQ{>($g0jP1F#dIy^<452X_NI-x@wkqr`&I$T4kjn>%qGlIpKeF zmU|D{3K9+Y(j-QtmA%5EJbRj1?3%mRN_Fb?(YUtxIYUhYu_HH3NGoOuz8sqBo*6{P zvI>;VW`{E)QSH+CJ@XY&e;$nl(ncw)-gyz6Y7b(xRWr3^p1)L%6HS}8GuLcdw%M`k zjh|@K=d4rFy?LBI|A4=^u{F#gdQJepeqX1fJ_}M-Tl4w{?!p-aYk+N>d=KZtbI5>C z<2k%Pz2{W}$=`kW+qB#Te0g(mxV?}@MXcvS7;D9NUp4ErM8xYh%R6=F?3mBG&$(Pp z>uJHgbied;MSX=KO6DzFX>@I)2!b8v>bDx@UhxhXfp+2uK+wP#5>Awe$uVjDcWanA z9(C}3Y#GP76F0VcfKQC+LZ%v4&Qr`MWUy^Aw2V>^?M<4nkPnT_o)Q$x3$Vj|*2L;E zK8x2p`m2Mcz9LX4$#KvDAsSPB%yQlLU}j4)oLNGH-kPYOTtfZjpOmq4xvm{`E*DD; z5s2(E8h*NV)k_?Cf$+tuN(igAqN^-<{h|Ya(5Vbb`HLW&Ly-Ktmo(@CV5BEkr8 z_)vSYhae(&#O93mH0afvYuU>|wl$I8gnSN*n`gP{XSpry6V7eBKcelbq!!gxhFj-gM@jt$5lpqH6`IcdEwmDf-+=E805{7hwz2r1W@f4>hBcb_Q zl474FU7T?hwXjSXzaUoR*<}$L0Zrx(`Q8sKU}!?uo|(3|FMG74!h!*z!VR5XGnZU+ zWzl1n(l?J&oL*T0#pV{eEaYo{VPj`y)~N6)bJYGjZ*J_-z_aHL@}LI8suHCQ#(*uz zI0@xX|4FD=SJdvV3qm6Hjr2xlQm1wZ61nv#p#qt^JlHUx(SSZS(qyp*PAi6jKe4)N z$tA>yn)^U);{QZN+PLkC%)4_QeLihfeOO$V$kb5e;z|MFs_vsoA!p780%{bx@Knhq zA2-aLILaY`2dMObkO>(SI8s2T|3nbGLh{v+>$;rX3R$$F^>}szu*zbjh7{T8Em>F+ zKA+OgS_|d-n^iHXR~;WG3j%D9cdX`1rJgvxmPn-d+D$%~2JKt+RCl3eLm)##Q6lcm zM{lh&Pm$7tyyfqt@8pCD0_xtt+6f$DI8*FAi0pSi^x`*s72;d0KswZ$zX~+RiBkVx z*m1!@G%O4~-4vZc^uPSZ2QNZL-3t$~t0yWW3*ctNlF5oxc%GtZW!HUJV^ky%Yv%==dk zg^deqbWpo%my%ZuCmAt>k>Q`eMDm4}h~|9@30?VdC1r>r#;8cfx+{rJB%n7GIV-Ka z5|Dlfwqyf>37ly1L?oPz_@We_5tQVNWC`jCfbxFH@!#N=B#^&u-WBFYvq?fpwVhme zNkc!WnApY|0FfCm{~736y4pvm-CI)ih+iUR7%bI$Y@sGiIZ)1@*Qjadsk(0Y0xh^1 zf=XUsv9zxF3XQu4L|ncH?L{{_6k58)X_7Xp=>nJeb{!kD@M~3!3dS8yN|sngv#!c? z50P^*;cGT7*wQ?Wu%F(^+s#oKL@%mhTn}n^goqP_0`4FI4Y!|WGc2<`X4<0`@xmHq z9qk_b>7Y=TQL5+c&7d-XkbWD;pme3{*pDA>VvLjd@!9fq0yLe|Y_a^@Xik}(m(~^2 z`*vb(r||*gMLJX3SIlNlqs+W`9hi{Fr5P)HOkLkLaxH$gNU>a$X2G5W*j}^VI1vM! zS3gAawNIj?+V`HGs+9ccO+hOedv6^63rKNz(j_Q!*#Jsto)H?S=EY|&Ol~uhf$~ro zns)@5+3$*ByToHN^_%l-{VX>5z;scrWJ#;SJx$;iGqAiO5^O&mwS9|fEPg!@tkmqr zYPmi<1e3k7uBMcP>L=*Zj2k@F;Ps*8FEuW#a%VyJl$)5CW0CerJVztoWJosuq0lUlmyfFw;#cIxS!asyB7XvgPAmji4E2dw7naXrWr7PcjjQb|lW zpSoj4IF(JY(n$0`(XL*RgUcb*-=U183y@VTY=(tJS3X7x&^n zXsV01rb(p_`iRHzL+)^zr{?peX{t$ZW4xT#M|6S#5LMJe9J|4T+52`G7yu!Bn+ zN(3$J*gX1#LKUkbw@mz^3WT}G5&OU$24>wvcmaSra=d0m-OFP9I=j@h9zl)(lQoE5 z!KIarB;}}F+t$X7^QU*~c^&eT2`P&@<+PtxFhYjXbR+IS?5s?q276R6`=Mn^;qJPB zS*)B03(N^Ty;!`tY;|rqJ1!*ljYa=Pj>^%cVlv4m|0MD}?!YO|7r zQCQvVBu)O*(7U(bIV6%rRn-n0{6^z%SkNQ}e*?uc!P5%V8j;1ZQw5?oscLo7DmTiN zV~o>i%9!lDSzs$#Hz10}TDTK)AkBKXoIGc(wW$OezdnuJVD2RJhV_y1M?hzd2Dya< zLPk#Tf{J^s`~1ucS+zF|GvzJXT}OHzP=OFI46p;S*1ch$u$|idS?ee>B2)g?3o);n z3~ZIXX$NM!nk?c5b1-wRb_Nqa?O;K8p1^bO>9}zE)V$T;_}}LTM7t>(L8fOv{)~xD zXYK%OzOw@KRKa{lvUue@J3G6b_*sDj5NiM&@#t$`?TOGX3G9RYU};z)ERW!+H73}) zing4}bA{%&k;cdh@aM25r4LLhhfM&fsxba$(6S~@6#*zT8g2W*y2uKmt4#@JZru%a zgYTAMc>>bpFx)u~xt}`xv#u9-|MCUXY|mLIFi9in`#9rh5@{1xl`u9|Gb|%~+V~nR z=6!)iR1s$(k*q|(JGMFY0U_@Tssqw7`HA!D99A$RBDx8v zGJMht5odksW%nxfS^WL08kVQrc9vdX_b%n|gs`4@bwgxvfp6n$gEf?|bD&=J&ao-X z19SF>D*4>suL@u%PFx~tls!M3<9!wBeZ((Y3GlP?)lF&^`PFj5zPvho^16KLjK2*S ztpi@xeFQJ>>5;R%IOFgJ$q+7Lq^N9g`+UQ1i%oVxe_;_tgQ z_*YWZA=J(dko=MYDXfL*I{%$Yf8VeEm<|5sJ4Sbpj~Knxe?~2wgc8~(_#~EDSS7_N zPRrnig|`e$*$BVn$PRh7OQJrmLvCEpK@u z{3Jxog~Y^wE>ah6AN*!c;ZM}$x;*%$Pi6~z2zbr8hFD)k_cMYd74*aYW;-B_mtVe&JO&v}MP&!-jOi-JYH48BJMH#0E=Uw%+4oCx z>|-!Kt(G|(gKuNEy)+yxn(1d`7t-Cuh>w5OA3J7_jd4IXn{`&J?ouno7F4X>&zYz* zu2R6^#n3^FK=x_&b7;_rk85Itr=;q?(}e%0Mlo%pKVex;RWtx;aSsN+rxOP_c57;z zmV%SUvhjT4I~E}dm4B($UkNtH3wyEKpQS_C*?)va>G;QJ_FaR_zkj2wE(cyS>y>Ki z2cw)YLRml^Iyu&TfZ?CSS36HnP(9PSqI_9Qn78tb!~uH!3BZ^*Svmv!nHpwK5=n;o z=!ZyhWMenZYU%A~FJwwUB7mUi=x!zGI`aUnIZsqBR+cni}%w*ls=s zXsk>jL?2lAy7k^H%uyHY)nNQ6>@T;^*m@HFn)bfsISTYyfJX_2cY$l{OYbJ}Y@_y zm)0v9yqelQEb45d@sH4OM8EaAyMSi1wkNfj>tDj;%g*Yp9a}5JzAF0X2$6FfDhQ~E z5Kh<($i?t@w>ap@pM-n}LvWmX6DUXGqS=#N$j@iLS;^-KT*-X z%nFMslcgMhh`TjQtvZYrL9_q)9jLc#yY#0*X;>DSl~zWJgK*Z^o;oI;B^lEApFdaWR6 zkGOTkDhU7@T=)8lzEifVjFD`dCwNK&+g>`ENJ7o0W_Je z7pu^?RZJIBY3R;`#+Ns?>Y*$$y=CT|z|zhYomFEA;uj67%;bb^{~Al5Tc%E^yz7CM z%ZMO%jBMHoZiBUgVYnx5=inVDu~6OS-5Q6YgR9lo@Gg7F&>2L9Dd^L^_}w+vABY-I z2*no!j^^DaD6|x5XM-K#nT-;q!C>py0GP4Y>+rS_{3tbiky*9p_sgx~bn;WQQnOuP z%puFz$6P{L3!e2EqdOT&VeFH0j+Ln1JDQPs(kq)E`{7(Y45ag6jFacIzpK7lO_>Zanf0A@ ze_Z_^z9G6~e?xzaX_8NH`o<+h#1iQ~Hl3JaHQ~Da>3}z?YlULCHQM;{7D@!M+fj6Uv3_I~gWMdHk5^yYbS)0hag6D*6NP3Iyj+JbfnN zgxv~}8C-c+Z7w$*)1sDb8$5%jS~mFKEptYZEgRt$p;VXt;GuY3pf<&B^H2?GobN#V z)_|_oYwyJ{O^Z=S1cz}_X3j88Psd5;7KozIU3lc8FiL_r(az(yO+hwAXtq@sg5Cr) zls(mH!p(GNQwn1ZN?PN1k32F2T2r!z(`#8+$6?9Ib3MP@()tN#5TvqrzNs-U+?Ep#g}3f172{GBQjp7Yp4eP#T8#eEPK!{TbfqL zMSjpipZump58-h2wm+vNJ%syHqmE@=_T#0&mbD`ku%l^|z9H%dVtT8b;`ar4uLOru zir1*<<{Ch9*qZgqLVpF!nj`3BdfFE#?#HwI>Sasa{{j|VLq1#2FgqlRuCTju$ zI|_Lnpd5vt2_aQz2r|YDF56lTg0;tn{Ch@y@omRJWKT$)t|~jn7IGT$2S7q8v*NfD zGo~(Ds5zArWxBQ(9h{t_B(NLMgUWH^K^(#8B+pud<_7uz)W31D)mGfY##(E2I!rNG z97 zQAGo$^_fbddLGRWyP3FT=$v>3j$l5<;$}$Zn?kyq)^6oUBY`DA^%F2XQS9knfwm(D7WQbjJ za!V-BW8DSYVecacS203pSLEWA9Yv(GFULPgQyUrp(bPJ$NDiDT9GtvpzRG{BrJpG*Fpk;9lihH%tJ22~N|ig5Z^F<=O*lCm3~i*}sv;eiuQfwFg~z z_B+C9d*{!2=;_a8uMrL9(N`aw2D(WYV|#LjWvVodWuCGOBfy zWD&5Qs-vy4McOm1pE*^6rXwXVB$?0oxwr2IY9X2=Rq`|&hYNd676UQW@9`p8_m*nW4vh%2jewnW#FYaW3D6B1c zQCu;8D(mOahG@j`EpDEhCEo6JnGKWy<;q@@9@sHTmC^7{g=g-lB}5~aNj4+X(7|=U zFO@>GS}R_HWBruaz&p*&>GuEKxSvP>^am!*(07#4Uf1}@Inlo)d@<4`S~D|b)(?^B zLuI4B{X?=35fpcL)Ve_TsmH1_PVaeI34Pn5#i)aPNEsEOHebk9@s$o6__N#bp<#bs zS#GakTsbAvlm`T>VgWP(2TkY{U#<-9>Gu9_3z&QovK)QNvTqn=B5CD-!&kGZ4--P~uKk;9!iMqQC-D8AjH2@$( z;(p@^Rlrwrq2aKS~U7vioPCnv* zC2&Eb{I%b5M=6+Lhvf6MlL@=~Ocd!KO!ojUkP9y%8VH4%qCG@0udx*A#wOt{f-NSD zWv8J|iG^roKFil}6QaG(tOe;Xla>p1XX>Z)x6Ve*E{DTYxZg!@bJahWc~T3lHf-z5 zqXJkszxdJm75#NOMJHN0ByN7mc(zF)b#V!oC&Bnl?v~r}{cj z-hMROC6n$m1g- zqsh4cg`O=fR@g3VR?9yIHupUTNO-GM(MdMPvHuy%z6WBpt1oQqmvI^ z8E}hX6Q?V*jE*vFTjV13Oq-UO-DwYI_2A!39b zSt#@r2vP0r^LIX416)!o-*4uiw}k(wd$irlDV=spth)l`t9aVhe&tP)*#7j2U0`m4gi8O!#%5489T9X)OFD42xlGNDd+DfZ2 zkL=mxsmPC~ii2NU>Ku9z^;ts|bf8tngsX#FB$fqct)m-b$;Du=&Cz# zH6uQt0FzXfiMmo@Vzx90i#0}~oJYu9#fN_*)4b0l!r?$$;(nhE@~pNl7}Ed|z{OTIMdM zOf<}z*x6{IN^AihdQ!NtbZxdmgQ^-;@s9w892XOwpq2yZge{Iuh#5GY9935qtwp+Z zXQ5;>a=&eiOk-ikG69t!JI2RO0U*o20SZVFEAB(iD{Nxu8DKUZi4B|*(ILBJZ)Eiu z6A-ylGd(R|2R(!&wft2%lk$qj`%c@$WzZv9KF&SCX=-5JeU`JaHxYUO5P(7dIYfl+ z|AxC5`g*DOQr=aaf-N`^_pWcM?5UIB$olQ#X0sO2po%BEIZg38>r5?JnNa>b5 zD}t)U9Bt`MJ}e-yMc)npXb?aU-`$FTOBo+=TYPC>q5^YkzKEMnS443c9p>g)mh3fZ zBl->mqoZQ0qaxCY8v_6h7gSlJJhj{d{Bkbhe7(g4=RXsy7aO=<#QzTTXP0zNoN7nO z!6L$5J|U;jrk@3LRgs|Bc?uK5N_>K-o9J$uzJJ=>-|ZUi72iDtTkTOJ$n(i2#o50S zp9NgoV3BaXma>v!eeb}RiuXQ#sUfBBG#I%vqY+_8!fOyhcX?a;Od9lk7uUqEMo=5H zO=!MC6#gwR~{^O2??Ztoi@q1at+jLj?p6E)J%}nI> zkqR&DDN2@gDF*HL?VGt3{236jJWw0-$7NEm{DE&pa&ivw+1wj(TboZAs-PC+oQn$OPVkLBD<<` zdGL5$@*M{t0hWFJ$FEZF;O0-*?CA)5k+&JSL+$fj=+2#L}MapjWjuy;wlT4%rxL&IUjuq^`%y`oH&PcQ-Z{#7Feo z*yKj;YIU`-KZ(E8g|!d(k-;i6oF*g4w`@jjH;BPH5H~;d!*-G0;xra zXFK4l513G@V|R&l^6kv!4ipmSGEl#Dr&zt<^gP>Ca&UVu(VD&f2OF0F8yRm%^Q+Ie zcD3{tc0+c}#E~bdZkjH*3!k+ksJ2qtX?5U52nyU!=d-bYAN(J|Qp^r4inC9q+2PPz z>eJP4BB=)RVP%+Ck_|3dV!X|~)bwLY2JgjBRpD?f3_cdU?x{eq(}L53j_v=|{CdkT zYG;n&h!k7r+@v!l#=E?vmaiu1k~=w6ex#_0_~zMxKH^!f^F)VfU*eF~-&B%W9v z`TkWB;#Q4d1t#zpMsKcK3UsZIO!UVk6|V4;7~SDDkzHD4EE{&1I9q`91Ocq-vdZm5 zX&&`GqNq{uvmNe~6iarwiKw0WTzsM4xtz-r-d4;bLQp2uS5gDB+W)AQc;VJ0@vY+j z{Uw-ws$SaEurNK%X)A$-YMTj*gm9z`2?wSyA=CClr=hfIY?Toc^ z+W-?wwuAe;Jpf68Wk|FAeNrA=j{dah z9URiBt6lAdtWB!Y=gp?w!jJp5$YWakqqilV1Mh1B<>sx|bdB#Zb@)kapG8%Tx_GOe zUewc_g2Cg5tZ@CHTfN9Ug`EiseJ)cc^biCktu2Ru=)a@}?-+=qUs|p?M%L0tLWQkF z4fVWYr0iHPq(7tzfp0Mo;E#i4&U8Dh3V3fKhIYqb$^3Pe?i1cOtVuBCcUrg54z^VVY+My(MJylU* zcGvCK&EVaTt%O%O<%HDsp6yJQF{Gc-x^0%4H)pN4U-+SN*eR~F(jHbHcwQpBk5~;N zZOWuY%iBK4<;{lE0a72S`9F`q$DBZbaGV{r=!Bwp_BTZOu@HjD-M%C(No<@|wt?1?jQ&V=#dhi=GY^;ob64HV049cT^lM zTIhJx7tvh;rCHNzI$64KIG}K~;1xbI_P}J{0T&W|Dgh#1-Uv={R zK7%PPd2w~1ZBt{Dfoi74-L5ZYr=ST4`(EVrl>&72I>t;gm!MG5<87c+tIW%Of5u!y zJhA5ke+l$Fn8YPpDdwEd$m81>gQFgaji-C`KqZ-@?z@f39d}8Bb}qI$yE9 z?)O_nw+UEIk6*z4tu|VJPq26SPmfJ%f>Q?6>-x?BY{J@zhiE})iqxY=wt<$38axD3 zoGATtD~a4(u?D2$y6CY|3i!qv^H#*H9+|Ii^#?>vR30Qt~?RcU~h#l2P(s!^X}f(mQzt5N=FMmOkpLkfGNlM|i@ z7HuRPBe%cQs5FXm2GbG-vG?jq*{Aze*XR4sIIBGnxhf1IFD+(#JWQ#L{^^Iz^%LE$ z_3WpBBMX^YTYB(NCpn}MT5oDx(aQm}f1vfuM%16xpVPtW z6eR*n+HF!lF-j_|h(Ew+Kf(-US53~6hJ$~QF$FL~S|L3lA9KL((@|vt zm@#=1FqPRx1p@Ip9Vg>9z8FVjsqs(VzsZ{%M^{2QDjdGU01bXS_UJ*U(g>~l`M|;E zq{DquqCsj%3u%Cy-0usNH*DHoA&SWgtOro2fWmxRvwE-id=2^+B@yq5vQd|Px-QQc z?{Iqib;w05j4`-I?+0)meAK#Z)`~-_S*I(Ptx*U0g#qMZg>CYwV#c*1z_)&#?!N?xt!(fO{>OLXhWUb#=4uNJCGiyJT#)*BC$s zIz$^s>+lr}oLukrs?gypmcF*JG+)6^(U9Y8b&?8!tJI31aAVN{;zxJ+zcERP@MY0Q zHQp+6s*-PpF8-t8T?HFTofF~FYb6jtSQ^S!I2y1V2;cl{j-xJfRfA#S1wJ6x!kl*C za_jqcwpu=xDU;wd6YObGwD6!Zpn$U7%81(=mb#BM-87tR;cL-wi8~3>rW>y%N z+;6T8RJz;vr9+#TBQ0V#)+2J?%nMR${}sb4-U^v!!&At=J#%l18uhKz@Dyt-^5&Ss zAmZq3mm+aT?N5qUyy_$nLRLn(eoZe~3|ZOv+<2G)oM=w5DK3>8S{6TsW62y%c26^;4KIT^b9A};wLEr7r_O%_gWQrE{2_Io!P600-+cCp9)UR_y zLBIwzUY-pfRA?oZCVdm-fw&sBTA?}5y4a}vS1-jivTDI#w+r*-hw`d%CNv%V=hk)A zQ7&qrE5L1(ErJx*c;&=Un3n4=Q{Esop+HhW4aDG(8!q5 zp0Ut1W9=JJ+~O@A+ixv8PX;hK5At%9O$IB0SBfT-q6isg?Z9{9wEG@Q^WsgrME`Xq z(kVvQ2O*L7xFwkx>f{)2FJEwX$D4VW+VT4a=LeOim(XC1D%Z3F1Fdk1hXjD+YNK=x z1-J)0z-1W9Z`Jwe<wPhsAB?tSj|M#=|TF^8IuXGcBSoz#ZgJ@P10c-5fK~6l4UL`DEEZ8I= zcV0R?C~?(q3=Ml^z=QRSIV>%oQ~VCtMrfm)!+ir)lEdT(AZw=~RMncM!#&u91_&ii z@vGHH!dts1NUMZp+M|{w$of7mqWliqNwSXcHpCkmywrnEijTEGa3W`__cee}P)PY- zxl}ZAHLNw|HQ>|N_4?en6%{3&DK=@4B~u*!QjE{fQd|V0p`*h?onYnF!Wv1xxZ>5ata<&8@njF8+-e?2&5x4WG)Hsg z!ocxWcB#zU`GXv;!12x)p02sHIGi?Mj__2*tST_I9Q7{Ic%Q%Ivc(i%Bh8Ppaxb(0|icY@~U}*$!#|oMX$1!;t9}qdVDdk-W?+Sojv0JaYQ^a+-c^ ziHZK_Gcm;}t-D*``Z$!%L95_L9c{g$N2q=UxiK?A_>d6)zq-aWTYJ-QwG0r!NJ%3-j!#&!kG0Q79&G&H&G#5_Y zQve8MlYo=uuiW2$cdVw~Q4YLXk%v!&338j)w#ZUGFAKx$S^f5P_Ej-r7*Vpl<=MOM z21SLTIq!||z%^tPjxthPRtmj+4Cns!0&$GvuRUOAUyNLxXln|xxc=H3RbUOgyqmE zI2}TcRJOL;05u)ik_e@9ghTeOocamie{Bv+qG!<>8kOZt#{{Y;5bA^!wp6<;ZN6r0 zSZ(~k&1p7XQCe0kpgMR5`M3`bKc2uOr}%g{pMn%=y6gg!%G0cyxL!9|#&F)C+Fq7= zUhyk#x}iQ8#EhYEet;pG$z)*ibOYL`nLNB)7`1_p%YWAoazFsf26q$C|2j&es~qAj z!c6^-HE>T~6>FbqDER3kUbXR0j<#=#EGaH^A{i!3Y%*R)7={m?{C$Xz)^{-Y{2Zav3QGEJ4e*z0k5v2YDR zyS%gv%xT%<8;^7Mt!TwJ!nWKb)Udn8Nf{@Y-PyugK7dKdpj03%MhIcqE!o-kp@-p3 zMc%h$1gWt)n9BD63lH29al)=PB8WuCvV z0nT=M=W=HgP7n@HH4Z1pbIRjwi;n(28o|%L1<~g?gbbei##uml2sc9N=1uK{||d ze*VWyw4;Vj@g=4%MPS*Ueb+ZmSO@v5I8BTIywEv|Bjk(eJX6`rSV|OeoFH{sea19? zb=IDxH+GDJoz2xo;E>Cx8}s6jilb)Kp|IPb}-Bdc;do3qK@=S+V|(bsnLT1 zr&NXm!n<~BJ(lq-#nqXNXnbzx`!pWeZ&Gb?xUbRnsxdx~(I`pCz*sb`1N=;4uvo48 z0YV{?!b{tvs&H{6u&R?;3kvmC+cliW&)+(LU`c7=h-Q;{smym*KO!mec+WEJ-v+Ra z$fxKzPgYNT^ZfRiD{z{yAFzYy$#QDHEq=&>4^DD}5O7t%WJ)WPMW9kyD}r?6o)jv6 z*IEU#?IiRBgIBZv0WcIek5Mmpu0$yLB~z@E^u{?&V$u}o={L9j2f9ei*xdqS&Hmbm z3YBWL&3}@8r?g_H=2yC5Cb@q_1G@J(L;_@s;~kt>KAIp#CMUtsaYENJ)5CKWZ%S_R z0xDu@n0m(Wh$l>%N{^uOf6A)%&o}8=pyi>TlVh^`t7nOuu&qh*7`GktX69kno?UI( z)KMQgur;bCV7{ZR{0o6$^R^isF_ig(Hhu_Buz$wE4E`Dr)NeF@ZkJToW*Gkypog7g z#F#F;C1H^ZX1fTbLa{%))6+z}KKwKz=N7f2FV!&g^K_)0;K&4CZ3ez6KkQSf1f{}d zcgX$q8icfCi@%wKgZfG^Q%8uuaIktPM-~I<+3ZiN9wM1!(`=q6Z~;xR1hV;<8$|l6)@nvme7cP zOUPV$S8@+h>VzW81T&wGF{0bi7E{n=@&Ga-$4ZT4|7c()1apD^PBsw6gtAV(ywlC% z^k(KuX|Pvc`iHJ)kZszZ-*Ri1mPn^-wJJj1@*_IY$v9 zzszZ9YWFb-1G#H3A6t|(bX&@PzhmUWgDdyFl(M1D4!~Z+t47!Y)QOLPUWROiXX4}U zOq#gnw-b?7V2ITEj=(7sF9G7FVKiBb1@pY2MTa{Q+!pGoLXxANanlN|>HhfU62=?q z8#f5(F{Y+p1R+AN%$mG0nI(N8>5`$x7!X)F&3qd9*0N%LX$tv5n_0bPwLDl=c$aZrv%qPfA)b5E{B0)?L%v|5a>$eu=u-Utc7#?IP%Y<{y;GnAFj5oh z!{2z&H;gA*>#_F%^;M>U`DGXQwVxA-4Ha(EN@YbAmU5xPzKm0Hz`?wOV>wW(^=uCR zWxcnF0fTNZkMKczxCaLt7!kSD1JQTu9D=?MgsEUArc3uITzZf@@{05Pa(D$4_}FES`KD(ejE#Np1T z)zY^&C0OJL{K>s+39&>;jwer!b|onr#WYpw*=+cAZmHS~;VJcIK>6C*EKOop%T0y9 zhZTvKk#s7qQ?px7%{+4M_x^exFD3_yjVnT))c5jKvwFO5FbDS%DkgReSft}zEuswc zBd-HvWq&AENU2D69uc_iMwrcG@AB6I^fNF=AGJORZRu02h&R!JXIPe58d¬(c)%^4Q|dMl|7R%tDusi@VcT#^&cd)IfGU3K8rR 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 literal 0 HcmV?d00001 diff --git a/examples/cmake/deps.cmake b/examples/cmake/deps.cmake index 4aca08d80..cad8cd61e 100644 --- a/examples/cmake/deps.cmake +++ b/examples/cmake/deps.cmake @@ -7,9 +7,22 @@ CPMAddPackage( "SDL_WERROR OFF" ) -# glm -CPMAddPackage( - NAME glm - GITHUB_REPOSITORY g-truc/glm - GIT_TAG origin/master -) +if (WISDOM_BUILD_VIDEO) + # libavif + CPMAddPackage( + NAME libavif + GITHUB_REPOSITORY AOMediaCodec/libavif + GIT_TAG v1.4.1 + OPTIONS + "AVIF_CODEC_AOM OFF" + "AVIF_CODEC_RAV1E OFF" + "AVIF_CODEC_SVT OFF" + "AVIF_CODEC_DAV1D OFF" + "AVIF_CODEC_LIBGAV1 OFF" + "AVIF_CODEC_AVM OFF" + "AVIF_BUILD_APPS OFF" + "AVIF_BUILD_TESTS OFF" + "AVIF_LIBYUV OFF" + "BUILD_SHARED_LIBS OFF" + ) +endif() diff --git a/examples/video/CMakeLists.txt b/examples/video/CMakeLists.txt index e083ade8d..b7398a915 100644 --- a/examples/video/CMakeLists.txt +++ b/examples/video/CMakeLists.txt @@ -5,12 +5,12 @@ set(CPP_SOURCES entry_main.cpp) add_executable(${PROJECT_NAME}-cpp ${CPP_SOURCES}) target_link_libraries( ${PROJECT_NAME}-cpp PUBLIC wis::wisdom-headers wis::wisdom-platform-headers wis::wisdom-video-headers - SDL3::SDL3 example_backend_cpp-${POSTFIX}) + SDL3::SDL3 avif example_backend_cpp-${POSTFIX}) set_target_properties( ${PROJECT_NAME}-cpp PROPERTIES CXX_STANDARD 23 RUNTIME_OUTPUT_DIRECTORY ${EXAMPLE_BIN_OUTPUT}) target_compile_definitions(${PROJECT_NAME}-cpp PUBLIC ${ADD_DEFINITIONS}) -add_dependencies(${PROJECT_NAME}-cpp copy_sdl wis_test_compile_shaders) +add_dependencies(${PROJECT_NAME}-cpp copy_sdl wis_test_compile_shaders copy_assets) if(POSTFIX STREQUAL "dx12" AND WISDOM_USE_AGILITY_SDK) wis_install_agility_win32(TARGET ${PROJECT_NAME}-cpp PATCH_EXE) diff --git a/examples/video/avif_demux.hpp b/examples/video/avif_demux.hpp new file mode 100644 index 000000000..8593d4e51 --- /dev/null +++ b/examples/video/avif_demux.hpp @@ -0,0 +1,49 @@ +#pragma once +#include +#include +#include +#include + +class AvifDemuxer +{ +public: + struct Deleter { + void operator()(avifDecoder* dec) const { avifDecoderDestroy(dec); } + }; + + AvifDemuxer() : decoder(avifDecoderCreate()) {} + + bool Load(std::span data) + { + avifResult res = avifDecoderSetIOMemory(decoder.get(), data.data(), data.size()); + if (res != AVIF_RESULT_OK) return false; + + res = avifDecoderParse(decoder.get()); + + if(res == AVIF_RESULT_OK) { + raw_data = data; + } + + return res == AVIF_RESULT_OK; + } + + uint32_t GetWidth() const { return decoder->image ? decoder->image->width : 0; } + uint32_t GetHeight() const { return decoder->image ? decoder->image->height : 0; } + uint32_t GetImageCount() const { return decoder->imageCount; } + + std::span GetFrameData(uint32_t frame_index) const + { + if (frame_index >= (uint32_t)decoder->imageCount) return {}; + + avifExtent extent; + avifResult res = avifDecoderNthImageMaxExtent(decoder.get(), frame_index, &extent); + if (res != AVIF_RESULT_OK) return {}; + if (extent.size == 0 || extent.offset + extent.size > raw_data.size()) return {}; + + return raw_data.subspan(extent.offset, extent.size); + } + +private: + std::unique_ptr decoder; + std::span raw_data; +}; diff --git a/examples/video/entry_main.cpp b/examples/video/entry_main.cpp index 0bebcf6b1..f01d7ecfb 100644 --- a/examples/video/entry_main.cpp +++ b/examples/video/entry_main.cpp @@ -1,6 +1,9 @@ #include #include +#include "avif_demux.hpp" #include +#include +#include static bool check_result(wis::Result result, const char* where) { @@ -27,7 +30,6 @@ class Application void log_callback(wis::Severity severity, const char* message, uint64_t) { if (!_device.IsValid()) { - // Avoid logging messages before instance creation return; } @@ -93,13 +95,11 @@ class Application return device; } - // Query adapters wis::AdapterQuery adapters = instance.QueryAdapters(wis::AdapterPreference::Performance, result); if (!check_result(result, "QueryAdapters")) { return device; } - // Cycle through adapters and create device wis::DeviceExtensionHeader* extensions[] = {&_video_extension}; wis::CommandQueueDesc queue_descs[] = { {wis::CommandQueueType::VideoDecode, wis::CommandQueuePriority::Normal}, @@ -112,7 +112,6 @@ class Application for (size_t i = 0; i < adapters.GetAdapterCount(); ++i) { device = adapters.CreateDevice(i, requirements, result); if (result.status == wis::Status::Ok) { - // Get adapter description for logging purposes wis::AdapterDesc adapter_desc = adapters.GetAdapterDesc(i, result); std::printf( "Successfully created device for adapter: %s, vendor_id: %u, device_id: %u\n", @@ -142,7 +141,6 @@ class Application if (!check_result(result, "CreateDecoder")) { return video_decoder; } - //assert(video_decoder.IsValid() && "Failed to create video decoder for AV1 Main profile with NV12 format"); return video_decoder; } void PrintCapability() @@ -175,5 +173,29 @@ class Application int main() { Application app; + + std::ifstream avif_file("assets/avif_sample.avif", std::ios::binary); + if (!avif_file) { + std::printf("Failed to open AVIF file\n"); + return -1; + } + + std::vector avif_data((std::istreambuf_iterator(avif_file)), std::istreambuf_iterator()); + + AvifDemuxer demuxer; + if (!demuxer.Load({avif_data.data(), avif_data.size()})) { + std::printf("Failed to load AVIF file\n"); + return -1; + } + + std::printf("AVIF image loaded. Width: %u, Height: %u, Frames: %u\n", demuxer.GetWidth(), demuxer.GetHeight(), demuxer.GetImageCount()); + + for (uint32_t i = 0; i < demuxer.GetImageCount(); ++i) { + auto frame_data = demuxer.GetFrameData(i); + std::printf("Frame %u size: %zu bytes\n", i, frame_data.size()); + + // TODO: Pass frame_data to VideoDecoder... + } + return 0; } diff --git a/generator/enum.cpp b/generator/enum.cpp index 44ed3abdb..a301b5cdd 100644 --- a/generator/enum.cpp +++ b/generator/enum.cpp @@ -76,7 +76,7 @@ void Generator::ParseEnum(tinyxml2::XMLElement* type) auto& m = ref.values.emplace_back(); m.name = member->FindAttribute("name")->Value(); - m.value = std::stoll(member->FindAttribute("value")->Value()); + m.value = member->FindAttribute("value")->Value(); if (auto* doc = member->FindAttribute("doc")) { m.doc = doc->Value(); } diff --git a/generator/struct.cpp b/generator/struct.cpp index d367e0d59..8a4cbd3f1 100644 --- a/generator/struct.cpp +++ b/generator/struct.cpp @@ -80,6 +80,9 @@ void Generator::ParseStruct(tinyxml2::XMLElement* type) if (auto* doc = member->FindAttribute("doc")) { m.doc = doc->Value(); } + if (auto* bits = member->FindAttribute("bits")) { + m.bits = std::stoul(bits->Value()); + } } } @@ -164,6 +167,10 @@ std::string Generator::MakeCMemberDeclaration(const WisStructMember& member, siz size_t padding = align_width > type_string.length() ? align_width - type_string.length() : 0; std::string padded_type = type_string + std::string(padding, ' '); + if (member.bits > 0) { + return std::format(" {} {} : {}{};", padded_type, member.name, member.bits, array_modifier); + } + return std::format(" {} {}{};", padded_type, member.name, array_modifier); } @@ -180,6 +187,11 @@ std::string Generator::MakeCPPMemberDeclaration(const WisStructMember& member, s size_t padding = align_width > type_string.length() ? align_width - type_string.length() : 0; std::string padded_type = type_string + std::string(padding, ' '); + // Bitfield + if (member.bits > 0) { + return std::format(" {} {} : {};", padded_type, member.name, member.bits); + } + return std::format(" {} {};", padded_type, member.name); } diff --git a/generator/types.hpp b/generator/types.hpp index 4f9d98a89..8774d8322 100644 --- a/generator/types.hpp +++ b/generator/types.hpp @@ -105,7 +105,7 @@ struct WisEnumValue { std::string_view doc; std::string_view version; std::array converts; - int64_t value = 0; + std::string_view value; }; struct WisEnum { std::string_view name; @@ -153,6 +153,7 @@ struct WisStructMember { std::string_view type; std::string_view array_size; Modifier modifier; + uint32_t bits; // for bitfield std::string_view default_value; std::string_view doc; }; diff --git a/src/extensions/video/video/dx12/dx12_video_list.cpp b/src/extensions/video/video/dx12/dx12_video_list.cpp index 2d5dbd958..a4eba847e 100644 --- a/src/extensions/video/video/dx12/dx12_video_list.cpp +++ b/src/extensions/video/video/dx12/dx12_video_list.cpp @@ -10,10 +10,11 @@ #else # include #endif // DX12SDKVER - +#include +#include //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult wisDX12VideoDecodeCommandListBegin(const WisDX12VideoDecodeCommandList* self) +WIS_EXTERN_C WISDOM_VIDEO_API WisResult wisDX12VideoDecodeCommandListBegin(const WisDX12VideoDecodeCommandList* self) { auto& impl = wis::from_handle_ref(self); auto hr = impl.command_list->Reset(impl.allocator); @@ -25,7 +26,7 @@ WIS_EXTERN_C WISDOM_API WisResult wisDX12VideoDecodeCommandListBegin(const WisDX } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_API WisResult wisDX12VideoDecodeCommandListEnd(const WisDX12VideoDecodeCommandList* self) +WIS_EXTERN_C WISDOM_VIDEO_API WisResult wisDX12VideoDecodeCommandListEnd(const WisDX12VideoDecodeCommandList* self) { auto& impl = wis::from_handle_ref(self); auto hr = impl.command_list->Close(); @@ -37,7 +38,8 @@ WIS_EXTERN_C WISDOM_API WisResult wisDX12VideoDecodeCommandListEnd(const WisDX12 } //---------------------------------------------------------------------------------------------------------------------- -WIS_EXTERN_C WISDOM_VIDEO_API void wisDX12DestroyVideoDecodeCommandList(WisDX12VideoDecodeCommandList* self) { +WIS_EXTERN_C WISDOM_VIDEO_API void wisDX12DestroyVideoDecodeCommandList(WisDX12VideoDecodeCommandList* self) +{ auto& impl = wis::from_handle_ref(self); if (impl.command_list) { impl.command_list->Release(); @@ -46,5 +48,39 @@ WIS_EXTERN_C WISDOM_VIDEO_API void wisDX12DestroyVideoDecodeCommandList(WisDX12V } } +//---------------------------------------------------------------------------------------------------------------------- +WIS_EXTERN_C WISDOM_VIDEO_API void wisDX12VideoDecodeCommandListDecodeFrame( + const WisDX12VideoDecodeCommandList* command_list, + const WisDX12VideoDecoder* decoder, + const WisDX12VideoDecodeInputDesc* input_desc +) +{ + auto& impl = wis::from_handle_ref(command_list); + auto& decoder_impl = wis::from_handle_ref(decoder); + + D3D12_VIDEO_DECODE_OUTPUT_STREAM_ARGUMENTS1 output_args{}; + D3D12_VIDEO_DECODE_INPUT_STREAM_ARGUMENTS input_args{ + .NumFrameArguments = 1, + .FrameArguments = + { + {} + }, + .ReferenceFrames = + { + .NumTexture2Ds = 0, + .ppTexture2Ds = nullptr, + .pSubresources = nullptr, + .ppHeaps = nullptr, + }, + .CompressedBitstream = + { + .pBuffer = std::bit_cast(input_desc->bitstream_buffer), + .Offset = input_desc->offset, + .Size = input_desc->size, + }, + .pHeap = decoder_impl.decoder_heap, + }; + impl.command_list->DecodeFrame1(decoder_impl.decoder, &output_args, &input_args); +} #endif // WIS_DX12_VIDEO_COMMAND_LIST_CPP diff --git a/src/extensions/video/video/generated/c_api.h b/src/extensions/video/video/generated/c_api.h index 511df9f49..a47fd16d9 100644 --- a/src/extensions/video/video/generated/c_api.h +++ b/src/extensions/video/video/generated/c_api.h @@ -12,6 +12,207 @@ extern "C" { // Enums //============================================================== +/** + * @brief Provided by Wisdom 0.7.1. AV1 profiles as defined in the AV1 Bitstream Specification section 6.4.1. + * + * */ +typedef enum WisStdVideoAV1Profile { + WisStdVideoAV1ProfileMain = 0, ///< Main profile (8-bit or 10-bit color, 4:0:0 or 4:2:0). + WisStdVideoAV1ProfileHigh = 1, ///< High profile (adds 8-bit or 10-bit 4:4:4). + WisStdVideoAV1ProfileProfessional = 2, ///< Professional profile (adds 12-bit color, and 4:2:2). + WisStdVideoAV1ProfileInvalid = 0x7FFFFFFF, ///< Invalid profile. +} WisStdVideoAV1Profile; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 levels as defined in the AV1 Bitstream Specification Annex A.3. + * + * */ +typedef enum WisStdVideoAV1Level { + WisStdVideoAV1LevelLevel2_0 = 0, ///< Level 2.0 + WisStdVideoAV1LevelLevel2_1 = 1, ///< Level 2.1 + WisStdVideoAV1LevelLevel2_2 = 2, ///< Level 2.2 + WisStdVideoAV1LevelLevel2_3 = 3, ///< Level 2.3 + WisStdVideoAV1LevelLevel3_0 = 4, ///< Level 3.0 + WisStdVideoAV1LevelLevel3_1 = 5, ///< Level 3.1 + WisStdVideoAV1LevelLevel3_2 = 6, ///< Level 3.2 + WisStdVideoAV1LevelLevel3_3 = 7, ///< Level 3.3 + WisStdVideoAV1LevelLevel4_0 = 8, ///< Level 4.0 + WisStdVideoAV1LevelLevel4_1 = 9, ///< Level 4.1 + WisStdVideoAV1LevelLevel4_2 = 10, ///< Level 4.2 + WisStdVideoAV1LevelLevel4_3 = 11, ///< Level 4.3 + WisStdVideoAV1LevelLevel5_0 = 12, ///< Level 5.0 + WisStdVideoAV1LevelLevel5_1 = 13, ///< Level 5.1 + WisStdVideoAV1LevelLevel5_2 = 14, ///< Level 5.2 + WisStdVideoAV1LevelLevel5_3 = 15, ///< Level 5.3 + WisStdVideoAV1LevelLevel6_0 = 16, ///< Level 6.0 + WisStdVideoAV1LevelLevel6_1 = 17, ///< Level 6.1 + WisStdVideoAV1LevelLevel6_2 = 18, ///< Level 6.2 + WisStdVideoAV1LevelLevel6_3 = 19, ///< Level 6.3 + WisStdVideoAV1LevelLevel7_0 = 20, ///< Level 7.0 + WisStdVideoAV1LevelLevel7_1 = 21, ///< Level 7.1 + WisStdVideoAV1LevelLevel7_2 = 22, ///< Level 7.2 + WisStdVideoAV1LevelLevel7_3 = 23, ///< Level 7.3 + WisStdVideoAV1LevelInvalid = 0x7FFFFFFF, ///< Invalid level. +} WisStdVideoAV1Level; + +/** + * @brief Provided by Wisdom 0.7.1. Specifies the AV1 frame type (AV1 Bitstream Specification Section 6.8.2). + * + * */ +typedef enum WisStdVideoAV1FrameType { + WisStdVideoAV1FrameTypeKey = 0, ///< A key frame contains only intra-coded blocks and is fully decipherable. + WisStdVideoAV1FrameTypeInter = 1, ///< An inter frame may contain intra-coded blocks and inter-coded blocks. + /** + * @brief An intra-only frame contains only intra-coded blocks but acts otherwise as an inter frame. + * */ + WisStdVideoAV1FrameTypeIntraOnly = 2, + /** + * @brief A switch frame is an inter frame that can be used as a switching point for adaptive streaming. + * */ + WisStdVideoAV1FrameTypeSwitch = 3, + WisStdVideoAV1FrameTypeInvalid = 0x7FFFFFFF, ///< Invalid frame type. +} WisStdVideoAV1FrameType; + +/** + * @brief Provided by Wisdom 0.7.1. Names of the reference frames used in AV1 (AV1 Bitstream Specification Section 6.1). + * + * */ +typedef enum WisStdVideoAV1ReferenceName { + WisStdVideoAV1ReferenceNameIntraFrame = 0, ///< Intra frame reference. + WisStdVideoAV1ReferenceNameLastFrame = 1, ///< LAST_FRAME (1). + WisStdVideoAV1ReferenceNameLast2Frame = 2, ///< LAST2_FRAME (2). + WisStdVideoAV1ReferenceNameLast3Frame = 3, ///< LAST3_FRAME (3). + WisStdVideoAV1ReferenceNameGoldenFrame = 4, ///< GOLDEN_FRAME (4). + WisStdVideoAV1ReferenceNameBwdrefFrame = 5, ///< BWDREF_FRAME (5). + WisStdVideoAV1ReferenceNameAltref2Frame = 6, ///< ALTREF2_FRAME (6). + WisStdVideoAV1ReferenceNameAltrefFrame = 7, ///< ALTREF_FRAME (7). + WisStdVideoAV1ReferenceNameInvalid = 0x7FFFFFFF, ///< Invalid reference name. +} WisStdVideoAV1ReferenceName; + +/** + * @brief Provided by Wisdom 0.7.1. Interpolation filter types (AV1 Bitstream Specification Section 6.8.9). + * + * */ +typedef enum WisStdVideoAV1InterpolationFilter { + WisStdVideoAV1InterpolationFilterEighttap = 0, ///< Eight-tap filter. + WisStdVideoAV1InterpolationFilterEighttapSmooth = 1, ///< Eight-tap smooth filter. + WisStdVideoAV1InterpolationFilterEighttapSharp = 2, ///< Eight-tap sharp filter. + WisStdVideoAV1InterpolationFilterBilinear = 3, ///< Bilinear filter. + WisStdVideoAV1InterpolationFilterSwitchable = 4, ///< Switchable interpolation filter at the block level. + WisStdVideoAV1InterpolationFilterInvalid = 0x7FFFFFFF, ///< Invalid filter. +} WisStdVideoAV1InterpolationFilter; + +/** + * @brief Provided by Wisdom 0.7.1. Transform mode (AV1 Bitstream Specification Section 6.8.21). + * + * */ +typedef enum WisStdVideoAV1TxMode { + WisStdVideoAV1TxModeOnly4x4 = 0, ///< Only 4x4 transforms. + WisStdVideoAV1TxModeLargest = 1, ///< Largest allowed transform for the partition. + WisStdVideoAV1TxModeSelect = 2, ///< Select the transform mode. + WisStdVideoAV1TxModeInvalid = 0x7FFFFFFF, ///< Invalid TxMode. +} WisStdVideoAV1TxMode; + +/** + * @brief Provided by Wisdom 0.7.1. Loop restoration types (AV1 Bitstream Specification Section 6.10.15). + * + * */ +typedef enum WisStdVideoAV1FrameRestorationType { + WisStdVideoAV1FrameRestorationTypeNone = 0, ///< No loop restoration. + WisStdVideoAV1FrameRestorationTypeWiener = 1, ///< Wiener filter loop restoration. + WisStdVideoAV1FrameRestorationTypeSgrproj = 2, ///< Self-guided filter loop restoration. + WisStdVideoAV1FrameRestorationTypeSwitchable = 3, ///< Switchable between Wiener and Sgrproj. + WisStdVideoAV1FrameRestorationTypeInvalid = 0x7FFFFFFF, ///< Invalid restoration type. +} WisStdVideoAV1FrameRestorationType; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 color primaries mapping to ISO/IEC 23000-2 / CICP. + * + * */ +typedef enum WisStdVideoAV1ColorPrimaries { + WisStdVideoAV1ColorPrimariesBt709 = 1, ///< Rec. ITU-R BT.709-6. + WisStdVideoAV1ColorPrimariesUnspecified = 2, ///< Image characteristics are unknown or unspecified. + WisStdVideoAV1ColorPrimariesBt470M = 4, ///< Rec. ITU-R BT.470-6 System M (historical). + WisStdVideoAV1ColorPrimariesBt470BG = 5, ///< Rec. ITU-R BT.470-6 System B, G (historical). + WisStdVideoAV1ColorPrimariesBt601 = 6, ///< Rec. ITU-R BT.601-7 525. + WisStdVideoAV1ColorPrimariesSmpte240 = 7, ///< SMPTE 240M. + WisStdVideoAV1ColorPrimariesGenericFilm = 8, ///< Generic film (color filters using Illuminant C). + WisStdVideoAV1ColorPrimariesBt2020 = 9, ///< Rec. ITU-R BT.2020-2. + WisStdVideoAV1ColorPrimariesXyz = 10, ///< SMPTE ST 428-1. + WisStdVideoAV1ColorPrimariesSmpte431 = 11, ///< SMPTE RP 431-2. + WisStdVideoAV1ColorPrimariesSmpte432 = 12, ///< SMPTE EG 432-1. + WisStdVideoAV1ColorPrimariesEbu3213 = 22, ///< EBU Tech. 3213-E. + WisStdVideoAV1ColorPrimariesInvalid = 0x7FFFFFFF, ///< Invalid. +} WisStdVideoAV1ColorPrimaries; + +/** + * @brief Provided by Wisdom 0.7.1. Transfer characteristics for AV1. + * + * */ +typedef enum WisStdVideoAV1TransferCharacteristics { + WisStdVideoAV1TransferCharacteristicsReserved0 = 0, + WisStdVideoAV1TransferCharacteristicsBt709 = 1, ///< Rec. ITU-R BT.709-6. + WisStdVideoAV1TransferCharacteristicsUnspecified = 2, ///< Unspecified. + WisStdVideoAV1TransferCharacteristicsReserved3 = 3, + WisStdVideoAV1TransferCharacteristicsBt470M = 4, ///< Rec. ITU-R BT.470-6 System M (historical). + WisStdVideoAV1TransferCharacteristicsBt470BG = 5, ///< Rec. ITU-R BT.470-6 System B, G (historical). + WisStdVideoAV1TransferCharacteristicsBt601 = 6, ///< Rec. ITU-R BT.601-7. + WisStdVideoAV1TransferCharacteristicsSmpte240 = 7, ///< SMPTE 240M. + WisStdVideoAV1TransferCharacteristicsLinear = 8, ///< Linear transfer characteristics. + WisStdVideoAV1TransferCharacteristicsLog100 = 9, ///< Logarithmic transfer characteristic (100:1 range). + /** + * @brief Logarithmic transfer characteristic (100 * Sqrt(10) : 1 range). + * */ + WisStdVideoAV1TransferCharacteristicsLog100Sqrt10 = 10, + WisStdVideoAV1TransferCharacteristicsIec61966 = 11, ///< IEC 61966-2-4. + /** + * @brief Rec. ITU-R BT.1361-0 extended colour gamut system (historical). + * */ + WisStdVideoAV1TransferCharacteristicsBt1361 = 12, + WisStdVideoAV1TransferCharacteristicsSrgb = 13, ///< IEC 61966-2-1 sRGB. + WisStdVideoAV1TransferCharacteristicsBt2020_10Bit = 14, ///< Rec. ITU-R BT.2020-2 (10-bit system). + WisStdVideoAV1TransferCharacteristicsBt2020_12Bit = 15, ///< Rec. ITU-R BT.2020-2 (12-bit system). + WisStdVideoAV1TransferCharacteristicsSmpte2084 = 16, ///< SMPTE ST 2084 (PQ). + WisStdVideoAV1TransferCharacteristicsSmpte428 = 17, ///< SMPTE ST 428-1. + WisStdVideoAV1TransferCharacteristicsHlg = 18, ///< ARIB STD-B67 (HLG). + WisStdVideoAV1TransferCharacteristicsInvalid = 0x7FFFFFFF, +} WisStdVideoAV1TransferCharacteristics; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 matrix coefficients mapping to CICP. + * + * */ +typedef enum WisStdVideoAV1MatrixCoefficients { + WisStdVideoAV1MatrixCoefficientsIdentity = 0, ///< Identity matrix. + WisStdVideoAV1MatrixCoefficientsBt709 = 1, ///< Rec. ITU-R BT.709-6. + WisStdVideoAV1MatrixCoefficientsUnspecified = 2, ///< Matrix characteristics are unspecified. + WisStdVideoAV1MatrixCoefficientsReserved3 = 3, + WisStdVideoAV1MatrixCoefficientsFcc = 4, ///< FCC Title 47 Code of Federal Regulations. + WisStdVideoAV1MatrixCoefficientsBt470BG = 5, ///< Rec. ITU-R BT.470-6 System B, G (historical). + WisStdVideoAV1MatrixCoefficientsBt601 = 6, ///< Rec. ITU-R BT.601-7. + WisStdVideoAV1MatrixCoefficientsSmpte240 = 7, ///< SMPTE 240M. + WisStdVideoAV1MatrixCoefficientsSmpteYcgco = 8, ///< YCgCo. + WisStdVideoAV1MatrixCoefficientsBt2020Ncl = 9, ///< Bt2020 non-constant luminance. + WisStdVideoAV1MatrixCoefficientsBt2020Cl = 10, ///< Bt2020 constant luminance. + WisStdVideoAV1MatrixCoefficientsSmpte2085 = 11, ///< SMPTE ST 2085. + WisStdVideoAV1MatrixCoefficientsChromatNcl = 12, ///< Chromaticity-derived non-constant luminance. + WisStdVideoAV1MatrixCoefficientsChromatCl = 13, ///< Chromaticity-derived constant luminance. + WisStdVideoAV1MatrixCoefficientsIctcp = 14, ///< Rec. ITU-R BT.2100-0 ICtCp. + WisStdVideoAV1MatrixCoefficientsInvalid = 0x7FFFFFFF, +} WisStdVideoAV1MatrixCoefficients; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 chroma sample position (AV1 Bitstream Specification Section 6.4.2). + * + * */ +typedef enum WisStdVideoAV1ChromaSamplePosition { + WisStdVideoAV1ChromaSamplePositionUnknown = 0, ///< Unknown chroma sample position. + WisStdVideoAV1ChromaSamplePositionVertical = 1, ///< Horizontally co-located with luma, vertically shifted by 0.5. + WisStdVideoAV1ChromaSamplePositionColocated = 2, ///< Co-located with luma. + WisStdVideoAV1ChromaSamplePositionReserved = 3, + WisStdVideoAV1ChromaSamplePositionInvalid = 0x7FFFFFFF, +} WisStdVideoAV1ChromaSamplePosition; + /** * @brief Provided by Wisdom 0.7.1. Standard codec profiles. Used to specify the profile of a video codec * implementation. @@ -139,6 +340,438 @@ typedef enum WisChromaSubsampling { // Structs //============================================================== +/** + * @brief Provided by Wisdom 0.7.1. Color configuration flags (AV1 Bitstream Specification 6.4.2). + * + * */ +typedef struct WisStdVideoAV1ColorConfigFlags { + uint32_t mono_chrome : 1; ///< Indicates if the video does not contain U and V color planes. + uint32_t color_range : 1; ///< Flag indicating if full color range is used. + uint32_t separate_uv_delta_q : 1; ///< Flag indicating U and V planes have separate delta quantization. + uint32_t color_description_present_flag : 1; ///< Indicates if color description is present. + uint32_t reserved : 28; +} WisStdVideoAV1ColorConfigFlags; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 Color Configuration (AV1 Bitstream Specification Section 6.4.2). + * + * */ +typedef struct WisStdVideoAV1ColorConfig { + WisStdVideoAV1ColorConfigFlags flags; ///< Color configuration flags. + uint8_t BitDepth; ///< Bit depth of the color samples (8, 10, or 12). + uint8_t subsampling_x; ///< Chroma subsampling x. + uint8_t subsampling_y; ///< Chroma subsampling y. + uint8_t reserved1; + WisStdVideoAV1ColorPrimaries color_primaries; ///< Color primaries. + WisStdVideoAV1TransferCharacteristics transfer_characteristics; ///< Transfer characteristics. + WisStdVideoAV1MatrixCoefficients matrix_coefficients; ///< Matrix coefficients. + WisStdVideoAV1ChromaSamplePosition chroma_sample_position; ///< Chroma sample position. +} WisStdVideoAV1ColorConfig; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 Timing Info flags. + * + * */ +typedef struct WisStdVideoAV1TimingInfoFlags { + uint32_t equal_picture_interval : 1; ///< Indicates if pictures should be displayed with equal intervals. + uint32_t reserved : 31; +} WisStdVideoAV1TimingInfoFlags; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 Timing Info (AV1 Bitstream Specification Section 6.4.3). + * + * */ +typedef struct WisStdVideoAV1TimingInfo { + WisStdVideoAV1TimingInfoFlags flags; ///< Timing flags. + uint32_t num_units_in_display_tick; ///< Number of units in a display tick. + uint32_t time_scale; ///< Time scale. + uint32_t num_ticks_per_picture_minus_1; ///< Ticks per picture minus 1. +} WisStdVideoAV1TimingInfo; + +/** + * @brief Provided by Wisdom 0.7.1. Loop filter flags (AV1 Bitstream Specification Section 6.8.10). + * + * */ +typedef struct WisStdVideoAV1LoopFilterFlags { + /** + * @brief Indicates whether the filter level depends on the mode and reference frame used to predict a block. + * */ + uint32_t loop_filter_delta_enabled : 1; + /** + * @brief Indicates whether additional syntax elements are present that specify which mode and reference frame + * deltas are to be updated. + * */ + uint32_t loop_filter_delta_update : 1; + uint32_t reserved : 30; +} WisStdVideoAV1LoopFilterFlags; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 Loop Filter Parameters (AV1 Bitstream Specification Section 6.8.10). + * + * */ +typedef struct WisStdVideoAV1LoopFilter { + WisStdVideoAV1LoopFilterFlags flags; ///< Loop filter flags. + uint8_t loop_filter_level[4]; ///< Array containing loop filter strength values. + uint8_t loop_filter_sharpness; ///< Loop filter sharpness. + uint8_t update_ref_delta; ///< Indicates that the loop filter ref deltas are to be updated. + int8_t loop_filter_ref_deltas[8]; ///< Loop filter reference deltas. + uint8_t update_mode_delta; ///< Indicates that the loop filter mode deltas are to be updated. + int8_t loop_filter_mode_deltas[2]; ///< Loop filter mode deltas. +} WisStdVideoAV1LoopFilter; + +/** + * @brief Provided by Wisdom 0.7.1. Quantization flags (AV1 Bitstream Specification Section 6.8.11). + * + * */ +typedef struct WisStdVideoAV1QuantizationFlags { + uint32_t using_qmatrix : 1; ///< Specifies whether the quantizer matrix should be used. + uint32_t diff_uv_delta : 1; ///< Specifies whether the U and V delta quantizer values are transmitted separately. + uint32_t reserved : 30; +} WisStdVideoAV1QuantizationFlags; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 Quantization Parameters (AV1 Bitstream Specification Section 6.8.11). + * + * */ +typedef struct WisStdVideoAV1Quantization { + WisStdVideoAV1QuantizationFlags flags; ///< Quantization flags. + uint8_t base_q_idx; ///< Indicates the base frame qindex. + int8_t DeltaQYDc; ///< Y DC quantizer relative to base_q_idx. + int8_t DeltaQUDc; ///< U DC quantizer relative to base_q_idx. + int8_t DeltaQUAc; ///< U AC quantizer relative to base_q_idx. + int8_t DeltaQVDc; ///< V DC quantizer relative to base_q_idx. + int8_t DeltaQVAc; ///< V AC quantizer relative to base_q_idx. + /** + * @brief Specifies the level in the quantizer matrix that should be used for luma plane decoding. + * */ + uint8_t qm_y; + /** + * @brief Specifies the level in the quantizer matrix that should be used for chroma U plane decoding. + * */ + uint8_t qm_u; + /** + * @brief Specifies the level in the quantizer matrix that should be used for chroma V plane decoding. + * */ + uint8_t qm_v; +} WisStdVideoAV1Quantization; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 Segmentation Parameters (AV1 Bitstream Specification Section 6.8.13). + * + * */ +typedef struct WisStdVideoAV1Segmentation { + uint8_t FeatureEnabled[8]; ///< Array specifying whether the feature is enabled for a segment. + int16_t FeatureData[8 * 8]; ///< Array specifying the feature data for a segment feature. +} WisStdVideoAV1Segmentation; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 Tile Info Flags (AV1 Bitstream Specification Section 6.8.14). + * + * */ +typedef struct WisStdVideoAV1TileInfoFlags { + uint32_t uniform_tile_spacing_flag : 1; ///< Indicates that the tiles are uniformly spaced across the picture. + uint32_t reserved : 31; +} WisStdVideoAV1TileInfoFlags; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 Tile Information (AV1 Bitstream Specification Section 6.8.14). + * + * */ +typedef struct WisStdVideoAV1TileInfo { + WisStdVideoAV1TileInfoFlags flags; ///< Tile info flags. + uint8_t TileCols; ///< Number of tiles across the picture. + uint8_t TileRows; ///< Number of tiles down the picture. + uint16_t context_update_tile_id; ///< Specifies which tile to use for the CDF update. + /** + * @brief Specifies the number of bytes needed to code each tile size. + * */ + uint8_t tile_size_bytes_minus_1; + uint8_t reserved1[7]; + /** + * @brief Pointer to an array specifying the start column (in MI units) for each tile column. + * */ + const uint16_t* pMiColStarts; + /** + * @brief Pointer to an array specifying the start row (in MI units) for each tile row. + * */ + const uint16_t* pMiRowStarts; + const uint16_t* pWidthInSbsMinus1; ///< Pointer to an array of tile widths in superblocks minus 1. + const uint16_t* pHeightInSbsMinus1; ///< Pointer to an array of tile heights in superblocks minus 1. +} WisStdVideoAV1TileInfo; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 Constrained Directional Enhancement Filter (CDEF) parameters (AV1 Bitstream + * Specification Section 6.8.19). + * + * */ +typedef struct WisStdVideoAV1CDEF { + uint8_t cdef_damping_minus_3; ///< Controls the amount of damping in the deringing filter. + uint8_t cdef_bits; ///< Specifies the number of bits needed to specify the CDEF filter strength. + uint8_t cdef_y_pri_strength[8]; ///< Primary filter strength for Y. + uint8_t cdef_y_sec_strength[8]; ///< Secondary filter strength for Y. + uint8_t cdef_uv_pri_strength[8]; ///< Primary filter strength for UV. + uint8_t cdef_uv_sec_strength[8]; ///< Secondary filter strength for UV. +} WisStdVideoAV1CDEF; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 Loop Restoration parameters (AV1 Bitstream Specification Section 6.8.20). + * + * */ +typedef struct WisStdVideoAV1LoopRestoration { + /** + * @brief Array specifying the loop restoration type for each plane (Y, U, V). + * */ + WisStdVideoAV1FrameRestorationType FrameRestorationType[3]; + /** + * @brief Array specifying the size of loop restoration units for each plane. + * */ + uint16_t LoopRestorationSize[3]; +} WisStdVideoAV1LoopRestoration; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 Global Motion parameters (AV1 Bitstream Specification Section 6.8.17). + * + * */ +typedef struct WisStdVideoAV1GlobalMotion { + uint8_t GmType[8]; ///< Array specifying the global motion type for each reference frame. + int32_t gm_params[8 * 6]; ///< Array of global motion parameters. +} WisStdVideoAV1GlobalMotion; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 Film Grain Flags (AV1 Bitstream Specification Section 6.8.24). + * + * */ +typedef struct WisStdVideoAV1FilmGrainFlags { + uint32_t chroma_scaling_from_luma : 1; ///< Flag indicating that chroma scaling is derived from luma. + uint32_t overlap_flag : 1; ///< Flag indicating overlapping film grain blocks. + uint32_t clip_to_restricted_range : 1; ///< Flag indicating clipping to restricted range. + uint32_t update_grain : 1; ///< Flag indicating the film grain parameters are updated in this frame. + uint32_t reserved : 28; +} WisStdVideoAV1FilmGrainFlags; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 Film Grain parameters (AV1 Bitstream Specification Section 6.8.24). + * + * */ +typedef struct WisStdVideoAV1FilmGrain { + WisStdVideoAV1FilmGrainFlags flags; ///< Film grain flags. + uint8_t grain_scaling_minus_8; ///< Shift value for the film grain scale calculation. + uint8_t ar_coeff_lag; ///< Number of auto-regressive coefficients. + uint8_t ar_coeff_shift_minus_6; ///< Shift value for auto-regressive coefficients. + /** + * @brief Specifies how much the Gaussian random numbers should be scaled down. + * */ + uint8_t grain_scale_shift; + uint16_t grain_seed; ///< Specifies the seed for the pseudo-random number generator. + /** + * @brief Specifies the reference frame index to obtain the film grain parameters from. + * */ + uint8_t film_grain_params_ref_idx; + uint8_t num_y_points; ///< Number of points for luma scaling. + uint8_t point_y_value[14]; ///< Luma point values. + uint8_t point_y_scaling[14]; ///< Luma point scaling. + uint8_t num_cb_points; ///< Number of points for Cb scaling. + uint8_t point_cb_value[10]; ///< Cb point values. + uint8_t point_cb_scaling[10]; ///< Cb point scaling. + uint8_t num_cr_points; ///< Number of points for Cr scaling. + uint8_t point_cr_value[10]; ///< Cr point values. + uint8_t point_cr_scaling[10]; ///< Cr point scaling. + int8_t ar_coeffs_y_plus_128[24]; ///< Auto-regressive coefficients for Y. + int8_t ar_coeffs_cb_plus_128[25]; ///< Auto-regressive coefficients for Cb. + int8_t ar_coeffs_cr_plus_128[25]; ///< Auto-regressive coefficients for Cr. + uint8_t cb_mult; ///< Cb multiplier for chroma scaling from luma. + uint8_t cb_luma_mult; ///< Cb luma multiplier for chroma scaling from luma. + uint16_t cb_offset; ///< Cb offset for chroma scaling from luma. + uint8_t cr_mult; ///< Cr multiplier for chroma scaling from luma. + uint8_t cr_luma_mult; ///< Cr luma multiplier for chroma scaling from luma. + uint16_t cr_offset; ///< Cr offset for chroma scaling from luma. +} WisStdVideoAV1FilmGrain; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 Sequence Header flags (AV1 Bitstream Specification Section 5.5). + * + * */ +typedef struct WisStdVideoAV1SequenceHeaderFlags { + uint32_t still_picture : 1; ///< Specifies if the video sequence contains a single still picture. + uint32_t reduced_still_picture_header : 1; ///< Specifies if reduced header parameters are used for a still picture. + uint32_t use_128x128_superblock : 1; ///< Specifies if superblocks are 128x128 or 64x64. + uint32_t enable_filter_intra : 1; ///< Specifies if the filter intra predictor can be used. + uint32_t enable_intra_edge_filter : 1; ///< Specifies if intra edge filtering can be used. + uint32_t enable_interintra_compound : 1; ///< Specifies if inter-intra compound prediction can be used. + uint32_t enable_masked_compound : 1; ///< Specifies if masked compound prediction can be used. + uint32_t enable_warped_motion : 1; ///< Specifies if warped motion can be used. + uint32_t enable_dual_filter : 1; ///< Specifies if dual interpolation filters can be used. + uint32_t enable_order_hint : 1; ///< Specifies if order hints are used. + uint32_t enable_jnt_comp : 1; ///< Specifies if the distance weights process is used for compound prediction. + uint32_t enable_ref_frame_mvs : 1; ///< Specifies if reference frame motion vectors are present. + uint32_t frame_id_numbers_present_flag : 1; ///< Specifies if frame ID numbers are present. + uint32_t enable_superres : 1; ///< Specifies if the superresolution feature can be used. + uint32_t enable_cdef : 1; ///< Specifies if the CDEF filtering process can be used. + uint32_t enable_restoration : 1; ///< Specifies if loop restoration can be used. + uint32_t film_grain_params_present : 1; ///< Specifies if film grain parameters are present. + uint32_t timing_info_present_flag : 1; ///< Specifies if timing info is present. + uint32_t initial_display_delay_present_flag : 1; ///< Specifies if the initial display delay info is present. + uint32_t reserved : 13; +} WisStdVideoAV1SequenceHeaderFlags; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 Sequence Header OBU parameters (AV1 Bitstream Specification Section 5.5). + * + * */ +typedef struct WisStdVideoAV1SequenceHeader { + WisStdVideoAV1SequenceHeaderFlags flags; ///< Sequence header flags. + WisStdVideoAV1Profile seq_profile; ///< AV1 profile. + /** + * @brief Number of bits used to specify the frame width minus 1. + * */ + uint8_t frame_width_bits_minus_1; + /** + * @brief Number of bits used to specify the frame height minus 1. + * */ + uint8_t frame_height_bits_minus_1; + uint16_t max_frame_width_minus_1; ///< Maximum frame width minus 1. + uint16_t max_frame_height_minus_1; ///< Maximum frame height minus 1. + /** + * @brief Specifies the number of bits used to encode delta_frame_id. + * */ + uint8_t delta_frame_id_length_minus_2; + /** + * @brief Used to calculate the number of bits used to encode frame_id. + * */ + uint8_t additional_frame_id_length_minus_1; + uint8_t order_hint_bits_minus_1; ///< Used to compute OrderHintBits. + uint8_t seq_force_integer_mv; ///< Equal to 1: motion vectors will always be integers. + uint8_t seq_force_screen_content_tools; ///< Screen content tools setting. + uint8_t reserved1[5]; + const WisStdVideoAV1ColorConfig* pColorConfig; ///< Pointer to color configuration parameters. + const WisStdVideoAV1TimingInfo* pTimingInfo; ///< Pointer to timing info parameters. +} WisStdVideoAV1SequenceHeader; + +/** + * @brief Provided by Wisdom 0.7.1. Flags for AV1 decode picture info (from Uncompressed Header). + * + * */ +typedef struct WisStdVideoDecodeAV1PictureInfoFlags { + uint32_t error_resilient_mode : 1; ///< Indicates error resilient mode is enabled. + uint32_t disable_cdf_update : 1; ///< Indicates CDF update is disabled. + uint32_t use_superres : 1; ///< Indicates superresolution is enabled for this frame. + uint32_t render_and_frame_size_different : 1; ///< Indicates actual frame size and render frame size are different. + uint32_t allow_screen_content_tools : 1; ///< Indicates screen content tools are allowed. + uint32_t is_filter_switchable : 1; ///< Indicates whether interpolation filter is switchable. + uint32_t force_integer_mv : 1; ///< Indicates whether motion vectors must be forced to integer. + uint32_t frame_size_override_flag : 1; ///< Indicates if frame size override is set. + uint32_t buffer_removal_time_present_flag : 1; ///< Indicates whether buffer removal time is present. + uint32_t allow_intrabc : 1; ///< Indicates if intra block copy is allowed. + /** + * @brief Indicates if reference frames are completely decided by last_frame_idx. + * */ + uint32_t frame_refs_short_signaling : 1; + uint32_t allow_high_precision_mv : 1; ///< Indicates whether high precision motion vectors are allowed. + uint32_t is_motion_mode_switchable : 1; ///< Indicates whether motion mode is switchable. + uint32_t use_ref_frame_mvs : 1; ///< Indicates whether reference frame MVs are used. + uint32_t disable_frame_end_update_cdf : 1; ///< Specifies whether the frame end CDF update is skipped. + uint32_t allow_warped_motion : 1; ///< Indicates whether warped motion is allowed for this frame. + uint32_t reduced_tx_set : 1; ///< Indicates whether the frame uses a reduced transform set. + /** + * @brief Specifies that the mode info for inter blocks contains the syntax element comp_mode. + * */ + uint32_t reference_select : 1; + uint32_t skip_mode_present : 1; ///< Specifies whether skip mode is allowed. + uint32_t delta_q_present : 1; ///< Specifies whether a delta q index is present for the frame. + uint32_t delta_lf_present : 1; ///< Specifies whether delta loop filter values are present. + uint32_t delta_lf_multi : 1; ///< Specifies whether independent delta loop filter values are used. + uint32_t segmentation_enabled : 1; ///< Indicates if segmentation is enabled. + uint32_t segmentation_update_map : 1; ///< Indicates if segmentation map is updated. + uint32_t segmentation_temporal_update : 1; ///< Indicates if temporal segmentation is updated. + uint32_t segmentation_update_data : 1; ///< Indicates if segmentation feature data is updated. + uint32_t UsesLr : 1; ///< Indicates if loop restoration is used. + uint32_t usesChromaLr : 1; ///< Indicates if loop restoration is used for chroma. + uint32_t apply_grain : 1; ///< Indicates if film grain should be applied. + uint32_t reserved : 3; +} WisStdVideoDecodeAV1PictureInfoFlags; + +/** + * @brief Provided by Wisdom 0.7.1. Information provided by the application to the video decoder for each AV1 picture + * (Khronos Video extensions). + * + * */ +typedef struct WisStdVideoDecodeAV1PictureInfo { + WisStdVideoDecodeAV1PictureInfoFlags flags; ///< Decode picture info flags. + WisStdVideoAV1FrameType frame_type; ///< Frame type: Key, Inter, Intra-only, or Switch. + uint32_t current_frame_id; ///< Specifies the frame ID for the current frame. + uint8_t OrderHint; ///< Order hint of the current frame used for motion vector scaling. + /** + * @brief Index of the reference frame containing the CDF values to be loaded at the start of the frame. + * */ + uint8_t primary_ref_frame; + /** + * @brief An 8-bit mask that specifies which reference frame slots will be updated with the current frame. + * */ + uint8_t refresh_frame_flags; + uint8_t reserved1; + /** + * @brief Specifies the filter selection used for performing inter prediction. + * */ + WisStdVideoAV1InterpolationFilter interpolation_filter; + WisStdVideoAV1TxMode TxMode; ///< Specifies how the transform size is determined. + /** + * @brief Specifies the left shift to be applied to decoded delta q values. + * */ + uint8_t delta_q_res; + /** + * @brief Specifies the left shift to be applied to decoded delta loop filter values. + * */ + uint8_t delta_lf_res; + /** + * @brief Specifies the indices of the reference frames to be used for skip mode. + * */ + uint8_t SkipModeFrame[2]; + /** + * @brief Denominator for frame size calculation if superres is enabled. + * */ + uint8_t coded_denom; + uint8_t reserved2[3]; + uint8_t OrderHints[8]; ///< Order hints of the decoded reference frames. + uint32_t expectedFrameId[8]; ///< Expected frame IDs for reference frames. + const WisStdVideoAV1TileInfo* pTileInfo; ///< Pointer to AV1 tile information. + const WisStdVideoAV1Quantization* pQuantization; ///< Pointer to standard quantization matrices and values. + const WisStdVideoAV1Segmentation* pSegmentation; ///< Pointer to segmentation parameter information. + const WisStdVideoAV1LoopFilter* pLoopFilter; ///< Pointer to loop filter parameters. + const WisStdVideoAV1CDEF* pCDEF; ///< Pointer to CDEF parameters. + const WisStdVideoAV1LoopRestoration* pLoopRestoration; ///< Pointer to loop restoration parameters. + const WisStdVideoAV1GlobalMotion* pGlobalMotion; ///< Pointer to global motion parameters. + const WisStdVideoAV1FilmGrain* pFilmGrain; ///< Pointer to film grain synthesis parameters. +} WisStdVideoDecodeAV1PictureInfo; + +/** + * @brief Provided by Wisdom 0.7.1. Flags for AV1 Decode Reference Information. + * + * */ +typedef struct WisStdVideoDecodeAV1ReferenceInfoFlags { + uint32_t disable_frame_end_update_cdf : 1; ///< Reference originally had disabled frame end CDF update. + uint32_t segmentation_enabled : 1; ///< Reference originally had segmentation enabled. + uint32_t reserved : 30; +} WisStdVideoDecodeAV1ReferenceInfoFlags; + +/** + * @brief Provided by Wisdom 0.7.1. Information provided by the application about an AV1 reference frame. + * + * */ +typedef struct WisStdVideoDecodeAV1ReferenceInfo { + WisStdVideoDecodeAV1ReferenceInfoFlags flags; ///< Reference information flags. + uint8_t frame_type; ///< Frame type of the reference frame. + /** + * @brief Specifies the direction of the reference frame relative to other references used in motion vector + * derivation. + * */ + uint8_t RefFrameSignBias; + uint8_t OrderHint; ///< Order hint of the reference frame. + /** + * @brief Saved order hints when this reference frame was decoded. + * */ + uint8_t SavedOrderHints[8]; +} WisStdVideoDecodeAV1ReferenceInfo; + /** * @brief Provided by Wisdom 0.7.1. Information about a supported video codec. * @@ -181,13 +814,6 @@ typedef struct WisVideoDecoderDesc { } WisVideoDecoderDesc; #ifdef WISDOM_DX12 -/** - * @brief Provided by Wisdom 0.7.1. Handle for a video command list. Represents a command list that can be used to - * record video decode commands. - * - * */ -WIS_DEFINE_HANDLE(WisDX12VideoDecodeCommandList, 2); - /** * @brief Provided by Wisdom 0.7.1. Handle for video decoder parameters. Represents the parameters and capabilities of a * video decoder, such as supported codecs, bit depths, and chroma subsampling formats. @@ -202,6 +828,13 @@ WIS_DEFINE_HANDLE(WisDX12VideoDecoderParameters, 2); * */ WIS_DEFINE_HANDLE(WisDX12VideoDecoder, 2); +/** + * @brief Provided by Wisdom 0.7.1. Handle for a video command list. Represents a command list that can be used to + * record video decode commands. + * + * */ +WIS_DEFINE_HANDLE(WisDX12VideoDecodeCommandList, 2); + /** * @brief Provided by Wisdom 0.7.1. Handle for the video decoding extension. Used to manage video decoding resources * and operations. @@ -210,11 +843,19 @@ WIS_DEFINE_HANDLE(WisDX12VideoDecoder, 2); WIS_DEFINE_DX12_DEVICE_EXT_HANDLE(WisDX12VideoDecodingExtension, 2); /** - * @brief Provided by Wisdom 0.7.1. Destroys a WisVideoDecodeCommandList handle. - * @param self is a pointer to the valid WisVideoDecodeCommandList instance. + * @brief Provided by Wisdom 0.7.1. Variant type for video decode input descriptions. Used to specify the type of input + * data for a video decode operation. * * */ -WISDOM_VIDEO_API void wisDX12DestroyVideoDecodeCommandList(WisDX12VideoDecodeCommandList* self); +typedef struct WisDX12VideoDecodeInputDesc { + /** + * @brief Input description for a video decode operation that uses a bitstream buffer as input. The buffer view + * should contain the compressed video data to be decoded. + * */ + WisDX12BufferView bitstream_buffer; + uint64_t offset; ///< Offset in the buffer where the bistream data is located. + uint64_t size; ///< Size of the bitstream data in bytes. +} WisDX12VideoDecodeInputDesc; /** * @brief Provided by Wisdom 0.7.1. Destroys a WisVideoDecoderParameters handle. @@ -230,6 +871,13 @@ WISDOM_VIDEO_API void wisDX12DestroyVideoDecoderParameters(WisDX12VideoDecoderPa * */ WISDOM_VIDEO_API void wisDX12DestroyVideoDecoder(WisDX12VideoDecoder* self); +/** + * @brief Provided by Wisdom 0.7.1. Destroys a WisVideoDecodeCommandList handle. + * @param self is a pointer to the valid WisVideoDecodeCommandList instance. + * + * */ +WISDOM_VIDEO_API void wisDX12DestroyVideoDecodeCommandList(WisDX12VideoDecodeCommandList* self); + /** * @brief Provided by Wisdom 0.7.1. Destroys a WisVideoDecodingExtension handle. * @param self is a pointer to the valid WisVideoDecodingExtension instance. @@ -306,16 +954,23 @@ WISDOM_VIDEO_API WisResult wisDX12VideoDecodeCommandListBegin(const WisDX12Video * */ WISDOM_VIDEO_API WisResult wisDX12VideoDecodeCommandListEnd(const WisDX12VideoDecodeCommandList* self); -#endif // WISDOM_DX12 - -#ifdef WISDOM_VULKAN /** - * @brief Provided by Wisdom 0.7.1. Handle for a video command list. Represents a command list that can be used to - * record video decode commands. + * @brief Provided by Wisdom 0.7.0. Records a video decode command to the command list. + * @param self is a pointer to the valid WisVideoDecodeCommandList instance. + * @param decoder The video decoder that will be used for decoding the video frame. + * @param input_desc Description of the input data for the video decode operation. This field specifies the type and + * location of the input data that will be used for decoding the video frame. * * */ -WIS_DEFINE_HANDLE(WisVKVideoDecodeCommandList, 7); +WISDOM_VIDEO_API void wisDX12VideoDecodeCommandListDecodeFrame( + const WisDX12VideoDecodeCommandList* self, + const WisDX12VideoDecoder* decoder, + const WisDX12VideoDecodeInputDesc* input_desc +); +#endif // WISDOM_DX12 + +#ifdef WISDOM_VULKAN /** * @brief Provided by Wisdom 0.7.1. Handle for video decoder parameters. Represents the parameters and capabilities of a * video decoder, such as supported codecs, bit depths, and chroma subsampling formats. @@ -330,6 +985,13 @@ WIS_DEFINE_HANDLE(WisVKVideoDecoderParameters, 4); * */ WIS_DEFINE_HANDLE(WisVKVideoDecoder, 4); +/** + * @brief Provided by Wisdom 0.7.1. Handle for a video command list. Represents a command list that can be used to + * record video decode commands. + * + * */ +WIS_DEFINE_HANDLE(WisVKVideoDecodeCommandList, 7); + /** * @brief Provided by Wisdom 0.7.1. Handle for the video decoding extension. Used to manage video decoding resources * and operations. @@ -338,11 +1000,19 @@ WIS_DEFINE_HANDLE(WisVKVideoDecoder, 4); WIS_DEFINE_VK_DEVICE_EXT_HANDLE(WisVKVideoDecodingExtension, 5); /** - * @brief Provided by Wisdom 0.7.1. Destroys a WisVideoDecodeCommandList handle. - * @param self is a pointer to the valid WisVideoDecodeCommandList instance. + * @brief Provided by Wisdom 0.7.1. Variant type for video decode input descriptions. Used to specify the type of input + * data for a video decode operation. * * */ -WISDOM_VIDEO_API void wisVKDestroyVideoDecodeCommandList(WisVKVideoDecodeCommandList* self); +typedef struct WisVKVideoDecodeInputDesc { + /** + * @brief Input description for a video decode operation that uses a bitstream buffer as input. The buffer view + * should contain the compressed video data to be decoded. + * */ + WisVKBufferView bitstream_buffer; + uint64_t offset; ///< Offset in the buffer where the bistream data is located. + uint64_t size; ///< Size of the bitstream data in bytes. +} WisVKVideoDecodeInputDesc; /** * @brief Provided by Wisdom 0.7.1. Destroys a WisVideoDecoderParameters handle. @@ -358,6 +1028,13 @@ WISDOM_VIDEO_API void wisVKDestroyVideoDecoderParameters(WisVKVideoDecoderParame * */ WISDOM_VIDEO_API void wisVKDestroyVideoDecoder(WisVKVideoDecoder* self); +/** + * @brief Provided by Wisdom 0.7.1. Destroys a WisVideoDecodeCommandList handle. + * @param self is a pointer to the valid WisVideoDecodeCommandList instance. + * + * */ +WISDOM_VIDEO_API void wisVKDestroyVideoDecodeCommandList(WisVKVideoDecodeCommandList* self); + /** * @brief Provided by Wisdom 0.7.1. Destroys a WisVideoDecodingExtension handle. * @param self is a pointer to the valid WisVideoDecodingExtension instance. @@ -434,6 +1111,20 @@ WISDOM_VIDEO_API WisResult wisVKVideoDecodeCommandListBegin(const WisVKVideoDeco * */ WISDOM_VIDEO_API WisResult wisVKVideoDecodeCommandListEnd(const WisVKVideoDecodeCommandList* self); +/** + * @brief Provided by Wisdom 0.7.0. Records a video decode command to the command list. + * @param self is a pointer to the valid WisVideoDecodeCommandList instance. + * @param decoder The video decoder that will be used for decoding the video frame. + * @param input_desc Description of the input data for the video decode operation. This field specifies the type and + * location of the input data that will be used for decoding the video frame. + * + * */ +WISDOM_VIDEO_API void wisVKVideoDecodeCommandListDecodeFrame( + const WisVKVideoDecodeCommandList* self, + const WisVKVideoDecoder* decoder, + const WisVKVideoDecodeInputDesc* input_desc +); + #endif // WISDOM_VULKAN #ifdef __cplusplus diff --git a/src/extensions/video/video/generated/cpp_api.hpp b/src/extensions/video/video/generated/cpp_api.hpp index 16b167811..a3d54b7e3 100644 --- a/src/extensions/video/video/generated/cpp_api.hpp +++ b/src/extensions/video/video/generated/cpp_api.hpp @@ -15,6 +15,195 @@ namespace wis { // Enums //============================================================== +/** + * @brief Provided by Wisdom 0.7.1. AV1 profiles as defined in the AV1 Bitstream Specification section 6.4.1. + * + * */ +enum class StdVideoAV1Profile { + Main = 0, ///< Main profile (8-bit or 10-bit color, 4:0:0 or 4:2:0). + High = 1, ///< High profile (adds 8-bit or 10-bit 4:4:4). + Professional = 2, ///< Professional profile (adds 12-bit color, and 4:2:2). + Invalid = 0x7FFFFFFF, ///< Invalid profile. +}; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 levels as defined in the AV1 Bitstream Specification Annex A.3. + * + * */ +enum class StdVideoAV1Level { + Level2_0 = 0, ///< Level 2.0 + Level2_1 = 1, ///< Level 2.1 + Level2_2 = 2, ///< Level 2.2 + Level2_3 = 3, ///< Level 2.3 + Level3_0 = 4, ///< Level 3.0 + Level3_1 = 5, ///< Level 3.1 + Level3_2 = 6, ///< Level 3.2 + Level3_3 = 7, ///< Level 3.3 + Level4_0 = 8, ///< Level 4.0 + Level4_1 = 9, ///< Level 4.1 + Level4_2 = 10, ///< Level 4.2 + Level4_3 = 11, ///< Level 4.3 + Level5_0 = 12, ///< Level 5.0 + Level5_1 = 13, ///< Level 5.1 + Level5_2 = 14, ///< Level 5.2 + Level5_3 = 15, ///< Level 5.3 + Level6_0 = 16, ///< Level 6.0 + Level6_1 = 17, ///< Level 6.1 + Level6_2 = 18, ///< Level 6.2 + Level6_3 = 19, ///< Level 6.3 + Level7_0 = 20, ///< Level 7.0 + Level7_1 = 21, ///< Level 7.1 + Level7_2 = 22, ///< Level 7.2 + Level7_3 = 23, ///< Level 7.3 + Invalid = 0x7FFFFFFF, ///< Invalid level. +}; + +/** + * @brief Provided by Wisdom 0.7.1. Specifies the AV1 frame type (AV1 Bitstream Specification Section 6.8.2). + * + * */ +enum class StdVideoAV1FrameType { + Key = 0, ///< A key frame contains only intra-coded blocks and is fully decipherable. + Inter = 1, ///< An inter frame may contain intra-coded blocks and inter-coded blocks. + IntraOnly = 2, ///< An intra-only frame contains only intra-coded blocks but acts otherwise as an inter frame. + Switch = 3, ///< A switch frame is an inter frame that can be used as a switching point for adaptive streaming. + Invalid = 0x7FFFFFFF, ///< Invalid frame type. +}; + +/** + * @brief Provided by Wisdom 0.7.1. Names of the reference frames used in AV1 (AV1 Bitstream Specification Section 6.1). + * + * */ +enum class StdVideoAV1ReferenceName { + IntraFrame = 0, ///< Intra frame reference. + LastFrame = 1, ///< LAST_FRAME (1). + Last2Frame = 2, ///< LAST2_FRAME (2). + Last3Frame = 3, ///< LAST3_FRAME (3). + GoldenFrame = 4, ///< GOLDEN_FRAME (4). + BwdrefFrame = 5, ///< BWDREF_FRAME (5). + Altref2Frame = 6, ///< ALTREF2_FRAME (6). + AltrefFrame = 7, ///< ALTREF_FRAME (7). + Invalid = 0x7FFFFFFF, ///< Invalid reference name. +}; + +/** + * @brief Provided by Wisdom 0.7.1. Interpolation filter types (AV1 Bitstream Specification Section 6.8.9). + * + * */ +enum class StdVideoAV1InterpolationFilter { + Eighttap = 0, ///< Eight-tap filter. + EighttapSmooth = 1, ///< Eight-tap smooth filter. + EighttapSharp = 2, ///< Eight-tap sharp filter. + Bilinear = 3, ///< Bilinear filter. + Switchable = 4, ///< Switchable interpolation filter at the block level. + Invalid = 0x7FFFFFFF, ///< Invalid filter. +}; + +/** + * @brief Provided by Wisdom 0.7.1. Transform mode (AV1 Bitstream Specification Section 6.8.21). + * + * */ +enum class StdVideoAV1TxMode { + Only4x4 = 0, ///< Only 4x4 transforms. + Largest = 1, ///< Largest allowed transform for the partition. + Select = 2, ///< Select the transform mode. + Invalid = 0x7FFFFFFF, ///< Invalid TxMode. +}; + +/** + * @brief Provided by Wisdom 0.7.1. Loop restoration types (AV1 Bitstream Specification Section 6.10.15). + * + * */ +enum class StdVideoAV1FrameRestorationType { + None = 0, ///< No loop restoration. + Wiener = 1, ///< Wiener filter loop restoration. + Sgrproj = 2, ///< Self-guided filter loop restoration. + Switchable = 3, ///< Switchable between Wiener and Sgrproj. + Invalid = 0x7FFFFFFF, ///< Invalid restoration type. +}; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 color primaries mapping to ISO/IEC 23000-2 / CICP. + * + * */ +enum class StdVideoAV1ColorPrimaries { + Bt709 = 1, ///< Rec. ITU-R BT.709-6. + Unspecified = 2, ///< Image characteristics are unknown or unspecified. + Bt470M = 4, ///< Rec. ITU-R BT.470-6 System M (historical). + Bt470BG = 5, ///< Rec. ITU-R BT.470-6 System B, G (historical). + Bt601 = 6, ///< Rec. ITU-R BT.601-7 525. + Smpte240 = 7, ///< SMPTE 240M. + GenericFilm = 8, ///< Generic film (color filters using Illuminant C). + Bt2020 = 9, ///< Rec. ITU-R BT.2020-2. + Xyz = 10, ///< SMPTE ST 428-1. + Smpte431 = 11, ///< SMPTE RP 431-2. + Smpte432 = 12, ///< SMPTE EG 432-1. + Ebu3213 = 22, ///< EBU Tech. 3213-E. + Invalid = 0x7FFFFFFF, ///< Invalid. +}; + +/** + * @brief Provided by Wisdom 0.7.1. Transfer characteristics for AV1. + * + * */ +enum class StdVideoAV1TransferCharacteristics { + Reserved0 = 0, + Bt709 = 1, ///< Rec. ITU-R BT.709-6. + Unspecified = 2, ///< Unspecified. + Reserved3 = 3, + Bt470M = 4, ///< Rec. ITU-R BT.470-6 System M (historical). + Bt470BG = 5, ///< Rec. ITU-R BT.470-6 System B, G (historical). + Bt601 = 6, ///< Rec. ITU-R BT.601-7. + Smpte240 = 7, ///< SMPTE 240M. + Linear = 8, ///< Linear transfer characteristics. + Log100 = 9, ///< Logarithmic transfer characteristic (100:1 range). + Log100Sqrt10 = 10, ///< Logarithmic transfer characteristic (100 * Sqrt(10) : 1 range). + Iec61966 = 11, ///< IEC 61966-2-4. + Bt1361 = 12, ///< Rec. ITU-R BT.1361-0 extended colour gamut system (historical). + Srgb = 13, ///< IEC 61966-2-1 sRGB. + Bt2020_10Bit = 14, ///< Rec. ITU-R BT.2020-2 (10-bit system). + Bt2020_12Bit = 15, ///< Rec. ITU-R BT.2020-2 (12-bit system). + Smpte2084 = 16, ///< SMPTE ST 2084 (PQ). + Smpte428 = 17, ///< SMPTE ST 428-1. + Hlg = 18, ///< ARIB STD-B67 (HLG). + Invalid = 0x7FFFFFFF, +}; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 matrix coefficients mapping to CICP. + * + * */ +enum class StdVideoAV1MatrixCoefficients { + Identity = 0, ///< Identity matrix. + Bt709 = 1, ///< Rec. ITU-R BT.709-6. + Unspecified = 2, ///< Matrix characteristics are unspecified. + Reserved3 = 3, + Fcc = 4, ///< FCC Title 47 Code of Federal Regulations. + Bt470BG = 5, ///< Rec. ITU-R BT.470-6 System B, G (historical). + Bt601 = 6, ///< Rec. ITU-R BT.601-7. + Smpte240 = 7, ///< SMPTE 240M. + SmpteYcgco = 8, ///< YCgCo. + Bt2020Ncl = 9, ///< Bt2020 non-constant luminance. + Bt2020Cl = 10, ///< Bt2020 constant luminance. + Smpte2085 = 11, ///< SMPTE ST 2085. + ChromatNcl = 12, ///< Chromaticity-derived non-constant luminance. + ChromatCl = 13, ///< Chromaticity-derived constant luminance. + Ictcp = 14, ///< Rec. ITU-R BT.2100-0 ICtCp. + Invalid = 0x7FFFFFFF, +}; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 chroma sample position (AV1 Bitstream Specification Section 6.4.2). + * + * */ +enum class StdVideoAV1ChromaSamplePosition { + Unknown = 0, ///< Unknown chroma sample position. + Vertical = 1, ///< Horizontally co-located with luma, vertically shifted by 0.5. + Colocated = 2, ///< Co-located with luma. + Reserved = 3, + Invalid = 0x7FFFFFFF, +}; + /** * @brief Provided by Wisdom 0.7.1. Standard codec profiles. Used to specify the profile of a video codec * implementation. @@ -139,6 +328,453 @@ WISDOM_DEFINE_ENUM_OPERATORS(ChromaSubsampling) // Structs //============================================================== +/** + * @brief Provided by Wisdom 0.7.1. Color configuration flags (AV1 Bitstream Specification 6.4.2). + * + * */ +struct StdVideoAV1ColorConfigFlags { + std::uint32_t mono_chrome : 1; ///< Indicates if the video does not contain U and V color planes. + std::uint32_t color_range : 1; ///< Flag indicating if full color range is used. + std::uint32_t separate_uv_delta_q : 1; ///< Flag indicating U and V planes have separate delta quantization. + std::uint32_t color_description_present_flag : 1; ///< Indicates if color description is present. + std::uint32_t reserved : 28; +}; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 Color Configuration (AV1 Bitstream Specification Section 6.4.2). + * + * */ +struct StdVideoAV1ColorConfig { + wis::StdVideoAV1ColorConfigFlags flags; ///< Color configuration flags. + std::uint8_t BitDepth; ///< Bit depth of the color samples (8, 10, or 12). + std::uint8_t subsampling_x; ///< Chroma subsampling x. + std::uint8_t subsampling_y; ///< Chroma subsampling y. + std::uint8_t reserved1; + wis::StdVideoAV1ColorPrimaries color_primaries; ///< Color primaries. + wis::StdVideoAV1TransferCharacteristics transfer_characteristics; ///< Transfer characteristics. + wis::StdVideoAV1MatrixCoefficients matrix_coefficients; ///< Matrix coefficients. + wis::StdVideoAV1ChromaSamplePosition chroma_sample_position; ///< Chroma sample position. +}; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 Timing Info flags. + * + * */ +struct StdVideoAV1TimingInfoFlags { + std::uint32_t equal_picture_interval : 1; ///< Indicates if pictures should be displayed with equal intervals. + std::uint32_t reserved : 31; +}; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 Timing Info (AV1 Bitstream Specification Section 6.4.3). + * + * */ +struct StdVideoAV1TimingInfo { + wis::StdVideoAV1TimingInfoFlags flags; ///< Timing flags. + std::uint32_t num_units_in_display_tick; ///< Number of units in a display tick. + std::uint32_t time_scale; ///< Time scale. + std::uint32_t num_ticks_per_picture_minus_1; ///< Ticks per picture minus 1. +}; + +/** + * @brief Provided by Wisdom 0.7.1. Loop filter flags (AV1 Bitstream Specification Section 6.8.10). + * + * */ +struct StdVideoAV1LoopFilterFlags { + /** + * @brief Indicates whether the filter level depends on the mode and reference frame used to predict a block. + * */ + std::uint32_t loop_filter_delta_enabled : 1; + /** + * @brief Indicates whether additional syntax elements are present that specify which mode and reference frame + * deltas are to be updated. + * */ + std::uint32_t loop_filter_delta_update : 1; + std::uint32_t reserved : 30; +}; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 Loop Filter Parameters (AV1 Bitstream Specification Section 6.8.10). + * + * */ +struct StdVideoAV1LoopFilter { + wis::StdVideoAV1LoopFilterFlags flags; ///< Loop filter flags. + std::array loop_filter_level; ///< Array containing loop filter strength values. + std::uint8_t loop_filter_sharpness; ///< Loop filter sharpness. + std::uint8_t update_ref_delta; ///< Indicates that the loop filter ref deltas are to be updated. + std::array loop_filter_ref_deltas; ///< Loop filter reference deltas. + /** + * @brief Indicates that the loop filter mode deltas are to be updated. + * */ + std::uint8_t update_mode_delta; + std::array loop_filter_mode_deltas; ///< Loop filter mode deltas. +}; + +/** + * @brief Provided by Wisdom 0.7.1. Quantization flags (AV1 Bitstream Specification Section 6.8.11). + * + * */ +struct StdVideoAV1QuantizationFlags { + std::uint32_t using_qmatrix : 1; ///< Specifies whether the quantizer matrix should be used. + /** + * @brief Specifies whether the U and V delta quantizer values are transmitted separately. + * */ + std::uint32_t diff_uv_delta : 1; + std::uint32_t reserved : 30; +}; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 Quantization Parameters (AV1 Bitstream Specification Section 6.8.11). + * + * */ +struct StdVideoAV1Quantization { + wis::StdVideoAV1QuantizationFlags flags; ///< Quantization flags. + std::uint8_t base_q_idx; ///< Indicates the base frame qindex. + std::int8_t DeltaQYDc; ///< Y DC quantizer relative to base_q_idx. + std::int8_t DeltaQUDc; ///< U DC quantizer relative to base_q_idx. + std::int8_t DeltaQUAc; ///< U AC quantizer relative to base_q_idx. + std::int8_t DeltaQVDc; ///< V DC quantizer relative to base_q_idx. + std::int8_t DeltaQVAc; ///< V AC quantizer relative to base_q_idx. + /** + * @brief Specifies the level in the quantizer matrix that should be used for luma plane decoding. + * */ + std::uint8_t qm_y; + /** + * @brief Specifies the level in the quantizer matrix that should be used for chroma U plane decoding. + * */ + std::uint8_t qm_u; + /** + * @brief Specifies the level in the quantizer matrix that should be used for chroma V plane decoding. + * */ + std::uint8_t qm_v; +}; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 Segmentation Parameters (AV1 Bitstream Specification Section 6.8.13). + * + * */ +struct StdVideoAV1Segmentation { + std::array FeatureEnabled; ///< Array specifying whether the feature is enabled for a segment. + std::array FeatureData; ///< Array specifying the feature data for a segment feature. +}; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 Tile Info Flags (AV1 Bitstream Specification Section 6.8.14). + * + * */ +struct StdVideoAV1TileInfoFlags { + std::uint32_t uniform_tile_spacing_flag : 1; ///< Indicates that the tiles are uniformly spaced across the picture. + std::uint32_t reserved : 31; +}; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 Tile Information (AV1 Bitstream Specification Section 6.8.14). + * + * */ +struct StdVideoAV1TileInfo { + wis::StdVideoAV1TileInfoFlags flags; ///< Tile info flags. + std::uint8_t TileCols; ///< Number of tiles across the picture. + std::uint8_t TileRows; ///< Number of tiles down the picture. + std::uint16_t context_update_tile_id; ///< Specifies which tile to use for the CDF update. + /** + * @brief Specifies the number of bytes needed to code each tile size. + * */ + std::uint8_t tile_size_bytes_minus_1; + std::array reserved1; + /** + * @brief Pointer to an array specifying the start column (in MI units) for each tile column. + * */ + const std::uint16_t* pMiColStarts; + /** + * @brief Pointer to an array specifying the start row (in MI units) for each tile row. + * */ + const std::uint16_t* pMiRowStarts; + const std::uint16_t* pWidthInSbsMinus1; ///< Pointer to an array of tile widths in superblocks minus 1. + const std::uint16_t* pHeightInSbsMinus1; ///< Pointer to an array of tile heights in superblocks minus 1. +}; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 Constrained Directional Enhancement Filter (CDEF) parameters (AV1 Bitstream + * Specification Section 6.8.19). + * + * */ +struct StdVideoAV1CDEF { + std::uint8_t cdef_damping_minus_3; ///< Controls the amount of damping in the deringing filter. + std::uint8_t cdef_bits; ///< Specifies the number of bits needed to specify the CDEF filter strength. + std::array cdef_y_pri_strength; ///< Primary filter strength for Y. + std::array cdef_y_sec_strength; ///< Secondary filter strength for Y. + std::array cdef_uv_pri_strength; ///< Primary filter strength for UV. + std::array cdef_uv_sec_strength; ///< Secondary filter strength for UV. +}; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 Loop Restoration parameters (AV1 Bitstream Specification Section 6.8.20). + * + * */ +struct StdVideoAV1LoopRestoration { + /** + * @brief Array specifying the loop restoration type for each plane (Y, U, V). + * */ + std::array FrameRestorationType; + /** + * @brief Array specifying the size of loop restoration units for each plane. + * */ + std::array LoopRestorationSize; +}; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 Global Motion parameters (AV1 Bitstream Specification Section 6.8.17). + * + * */ +struct StdVideoAV1GlobalMotion { + std::array GmType; ///< Array specifying the global motion type for each reference frame. + std::array gm_params; ///< Array of global motion parameters. +}; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 Film Grain Flags (AV1 Bitstream Specification Section 6.8.24). + * + * */ +struct StdVideoAV1FilmGrainFlags { + std::uint32_t chroma_scaling_from_luma : 1; ///< Flag indicating that chroma scaling is derived from luma. + std::uint32_t overlap_flag : 1; ///< Flag indicating overlapping film grain blocks. + std::uint32_t clip_to_restricted_range : 1; ///< Flag indicating clipping to restricted range. + std::uint32_t update_grain : 1; ///< Flag indicating the film grain parameters are updated in this frame. + std::uint32_t reserved : 28; +}; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 Film Grain parameters (AV1 Bitstream Specification Section 6.8.24). + * + * */ +struct StdVideoAV1FilmGrain { + wis::StdVideoAV1FilmGrainFlags flags; ///< Film grain flags. + std::uint8_t grain_scaling_minus_8; ///< Shift value for the film grain scale calculation. + std::uint8_t ar_coeff_lag; ///< Number of auto-regressive coefficients. + std::uint8_t ar_coeff_shift_minus_6; ///< Shift value for auto-regressive coefficients. + /** + * @brief Specifies how much the Gaussian random numbers should be scaled down. + * */ + std::uint8_t grain_scale_shift; + std::uint16_t grain_seed; ///< Specifies the seed for the pseudo-random number generator. + /** + * @brief Specifies the reference frame index to obtain the film grain parameters from. + * */ + std::uint8_t film_grain_params_ref_idx; + std::uint8_t num_y_points; ///< Number of points for luma scaling. + std::array point_y_value; ///< Luma point values. + std::array point_y_scaling; ///< Luma point scaling. + std::uint8_t num_cb_points; ///< Number of points for Cb scaling. + std::array point_cb_value; ///< Cb point values. + std::array point_cb_scaling; ///< Cb point scaling. + std::uint8_t num_cr_points; ///< Number of points for Cr scaling. + std::array point_cr_value; ///< Cr point values. + std::array point_cr_scaling; ///< Cr point scaling. + std::array ar_coeffs_y_plus_128; ///< Auto-regressive coefficients for Y. + std::array ar_coeffs_cb_plus_128; ///< Auto-regressive coefficients for Cb. + std::array ar_coeffs_cr_plus_128; ///< Auto-regressive coefficients for Cr. + std::uint8_t cb_mult; ///< Cb multiplier for chroma scaling from luma. + std::uint8_t cb_luma_mult; ///< Cb luma multiplier for chroma scaling from luma. + std::uint16_t cb_offset; ///< Cb offset for chroma scaling from luma. + std::uint8_t cr_mult; ///< Cr multiplier for chroma scaling from luma. + std::uint8_t cr_luma_mult; ///< Cr luma multiplier for chroma scaling from luma. + std::uint16_t cr_offset; ///< Cr offset for chroma scaling from luma. +}; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 Sequence Header flags (AV1 Bitstream Specification Section 5.5). + * + * */ +struct StdVideoAV1SequenceHeaderFlags { + std::uint32_t still_picture : 1; ///< Specifies if the video sequence contains a single still picture. + /** + * @brief Specifies if reduced header parameters are used for a still picture. + * */ + std::uint32_t reduced_still_picture_header : 1; + std::uint32_t use_128x128_superblock : 1; ///< Specifies if superblocks are 128x128 or 64x64. + std::uint32_t enable_filter_intra : 1; ///< Specifies if the filter intra predictor can be used. + std::uint32_t enable_intra_edge_filter : 1; ///< Specifies if intra edge filtering can be used. + std::uint32_t enable_interintra_compound : 1; ///< Specifies if inter-intra compound prediction can be used. + std::uint32_t enable_masked_compound : 1; ///< Specifies if masked compound prediction can be used. + std::uint32_t enable_warped_motion : 1; ///< Specifies if warped motion can be used. + std::uint32_t enable_dual_filter : 1; ///< Specifies if dual interpolation filters can be used. + std::uint32_t enable_order_hint : 1; ///< Specifies if order hints are used. + std::uint32_t enable_jnt_comp : 1; ///< Specifies if the distance weights process is used for compound prediction. + std::uint32_t enable_ref_frame_mvs : 1; ///< Specifies if reference frame motion vectors are present. + std::uint32_t frame_id_numbers_present_flag : 1; ///< Specifies if frame ID numbers are present. + std::uint32_t enable_superres : 1; ///< Specifies if the superresolution feature can be used. + std::uint32_t enable_cdef : 1; ///< Specifies if the CDEF filtering process can be used. + std::uint32_t enable_restoration : 1; ///< Specifies if loop restoration can be used. + std::uint32_t film_grain_params_present : 1; ///< Specifies if film grain parameters are present. + std::uint32_t timing_info_present_flag : 1; ///< Specifies if timing info is present. + std::uint32_t initial_display_delay_present_flag : 1; ///< Specifies if the initial display delay info is present. + std::uint32_t reserved : 13; +}; + +/** + * @brief Provided by Wisdom 0.7.1. AV1 Sequence Header OBU parameters (AV1 Bitstream Specification Section 5.5). + * + * */ +struct StdVideoAV1SequenceHeader { + wis::StdVideoAV1SequenceHeaderFlags flags; ///< Sequence header flags. + wis::StdVideoAV1Profile seq_profile; ///< AV1 profile. + /** + * @brief Number of bits used to specify the frame width minus 1. + * */ + std::uint8_t frame_width_bits_minus_1; + /** + * @brief Number of bits used to specify the frame height minus 1. + * */ + std::uint8_t frame_height_bits_minus_1; + std::uint16_t max_frame_width_minus_1; ///< Maximum frame width minus 1. + std::uint16_t max_frame_height_minus_1; ///< Maximum frame height minus 1. + /** + * @brief Specifies the number of bits used to encode delta_frame_id. + * */ + std::uint8_t delta_frame_id_length_minus_2; + /** + * @brief Used to calculate the number of bits used to encode frame_id. + * */ + std::uint8_t additional_frame_id_length_minus_1; + std::uint8_t order_hint_bits_minus_1; ///< Used to compute OrderHintBits. + std::uint8_t seq_force_integer_mv; ///< Equal to 1: motion vectors will always be integers. + std::uint8_t seq_force_screen_content_tools; ///< Screen content tools setting. + std::array reserved1; + const wis::StdVideoAV1ColorConfig* pColorConfig; ///< Pointer to color configuration parameters. + const wis::StdVideoAV1TimingInfo* pTimingInfo; ///< Pointer to timing info parameters. +}; + +/** + * @brief Provided by Wisdom 0.7.1. Flags for AV1 decode picture info (from Uncompressed Header). + * + * */ +struct StdVideoDecodeAV1PictureInfoFlags { + std::uint32_t error_resilient_mode : 1; ///< Indicates error resilient mode is enabled. + std::uint32_t disable_cdf_update : 1; ///< Indicates CDF update is disabled. + std::uint32_t use_superres : 1; ///< Indicates superresolution is enabled for this frame. + /** + * @brief Indicates actual frame size and render frame size are different. + * */ + std::uint32_t render_and_frame_size_different : 1; + std::uint32_t allow_screen_content_tools : 1; ///< Indicates screen content tools are allowed. + std::uint32_t is_filter_switchable : 1; ///< Indicates whether interpolation filter is switchable. + std::uint32_t force_integer_mv : 1; ///< Indicates whether motion vectors must be forced to integer. + std::uint32_t frame_size_override_flag : 1; ///< Indicates if frame size override is set. + std::uint32_t buffer_removal_time_present_flag : 1; ///< Indicates whether buffer removal time is present. + std::uint32_t allow_intrabc : 1; ///< Indicates if intra block copy is allowed. + /** + * @brief Indicates if reference frames are completely decided by last_frame_idx. + * */ + std::uint32_t frame_refs_short_signaling : 1; + std::uint32_t allow_high_precision_mv : 1; ///< Indicates whether high precision motion vectors are allowed. + std::uint32_t is_motion_mode_switchable : 1; ///< Indicates whether motion mode is switchable. + std::uint32_t use_ref_frame_mvs : 1; ///< Indicates whether reference frame MVs are used. + std::uint32_t disable_frame_end_update_cdf : 1; ///< Specifies whether the frame end CDF update is skipped. + std::uint32_t allow_warped_motion : 1; ///< Indicates whether warped motion is allowed for this frame. + std::uint32_t reduced_tx_set : 1; ///< Indicates whether the frame uses a reduced transform set. + /** + * @brief Specifies that the mode info for inter blocks contains the syntax element comp_mode. + * */ + std::uint32_t reference_select : 1; + std::uint32_t skip_mode_present : 1; ///< Specifies whether skip mode is allowed. + std::uint32_t delta_q_present : 1; ///< Specifies whether a delta q index is present for the frame. + std::uint32_t delta_lf_present : 1; ///< Specifies whether delta loop filter values are present. + std::uint32_t delta_lf_multi : 1; ///< Specifies whether independent delta loop filter values are used. + std::uint32_t segmentation_enabled : 1; ///< Indicates if segmentation is enabled. + std::uint32_t segmentation_update_map : 1; ///< Indicates if segmentation map is updated. + std::uint32_t segmentation_temporal_update : 1; ///< Indicates if temporal segmentation is updated. + std::uint32_t segmentation_update_data : 1; ///< Indicates if segmentation feature data is updated. + std::uint32_t UsesLr : 1; ///< Indicates if loop restoration is used. + std::uint32_t usesChromaLr : 1; ///< Indicates if loop restoration is used for chroma. + std::uint32_t apply_grain : 1; ///< Indicates if film grain should be applied. + std::uint32_t reserved : 3; +}; + +/** + * @brief Provided by Wisdom 0.7.1. Information provided by the application to the video decoder for each AV1 picture + * (Khronos Video extensions). + * + * */ +struct StdVideoDecodeAV1PictureInfo { + wis::StdVideoDecodeAV1PictureInfoFlags flags; ///< Decode picture info flags. + wis::StdVideoAV1FrameType frame_type; ///< Frame type: Key, Inter, Intra-only, or Switch. + std::uint32_t current_frame_id; ///< Specifies the frame ID for the current frame. + /** + * @brief Order hint of the current frame used for motion vector scaling. + * */ + std::uint8_t OrderHint; + /** + * @brief Index of the reference frame containing the CDF values to be loaded at the start of the frame. + * */ + std::uint8_t primary_ref_frame; + /** + * @brief An 8-bit mask that specifies which reference frame slots will be updated with the current frame. + * */ + std::uint8_t refresh_frame_flags; + std::uint8_t reserved1; + /** + * @brief Specifies the filter selection used for performing inter prediction. + * */ + wis::StdVideoAV1InterpolationFilter interpolation_filter; + wis::StdVideoAV1TxMode TxMode; ///< Specifies how the transform size is determined. + /** + * @brief Specifies the left shift to be applied to decoded delta q values. + * */ + std::uint8_t delta_q_res; + /** + * @brief Specifies the left shift to be applied to decoded delta loop filter values. + * */ + std::uint8_t delta_lf_res; + /** + * @brief Specifies the indices of the reference frames to be used for skip mode. + * */ + std::array SkipModeFrame; + /** + * @brief Denominator for frame size calculation if superres is enabled. + * */ + std::uint8_t coded_denom; + std::array reserved2; + std::array OrderHints; ///< Order hints of the decoded reference frames. + std::array expectedFrameId; ///< Expected frame IDs for reference frames. + const wis::StdVideoAV1TileInfo* pTileInfo; ///< Pointer to AV1 tile information. + const wis::StdVideoAV1Quantization* pQuantization; ///< Pointer to standard quantization matrices and values. + const wis::StdVideoAV1Segmentation* pSegmentation; ///< Pointer to segmentation parameter information. + const wis::StdVideoAV1LoopFilter* pLoopFilter; ///< Pointer to loop filter parameters. + const wis::StdVideoAV1CDEF* pCDEF; ///< Pointer to CDEF parameters. + const wis::StdVideoAV1LoopRestoration* pLoopRestoration; ///< Pointer to loop restoration parameters. + const wis::StdVideoAV1GlobalMotion* pGlobalMotion; ///< Pointer to global motion parameters. + const wis::StdVideoAV1FilmGrain* pFilmGrain; ///< Pointer to film grain synthesis parameters. +}; + +/** + * @brief Provided by Wisdom 0.7.1. Flags for AV1 Decode Reference Information. + * + * */ +struct StdVideoDecodeAV1ReferenceInfoFlags { + std::uint32_t disable_frame_end_update_cdf : 1; ///< Reference originally had disabled frame end CDF update. + std::uint32_t segmentation_enabled : 1; ///< Reference originally had segmentation enabled. + std::uint32_t reserved : 30; +}; + +/** + * @brief Provided by Wisdom 0.7.1. Information provided by the application about an AV1 reference frame. + * + * */ +struct StdVideoDecodeAV1ReferenceInfo { + wis::StdVideoDecodeAV1ReferenceInfoFlags flags; ///< Reference information flags. + std::uint8_t frame_type; ///< Frame type of the reference frame. + /** + * @brief Specifies the direction of the reference frame relative to other references used in motion vector + * derivation. + * */ + std::uint8_t RefFrameSignBias; + std::uint8_t OrderHint; ///< Order hint of the reference frame. + /** + * @brief Saved order hints when this reference frame was decoded. + * */ + std::array SavedOrderHints; +}; + /** * @brief Provided by Wisdom 0.7.1. Information about a supported video codec. * @@ -186,43 +822,19 @@ struct VideoDecoderDesc { # include