diff --git a/.clang-format b/.clang-format index 849cdca54..24420da65 100644 --- a/.clang-format +++ b/.clang-format @@ -4,31 +4,31 @@ BasedOnStyle: LLVM Language: Cpp AlignAfterOpenBracket: Align AlignArrayOfStructures: Left -AlignConsecutiveAssignments: 'true' -AlignConsecutiveDeclarations: 'true' +AlignConsecutiveAssignments: "true" +AlignConsecutiveDeclarations: "true" AlignEscapedNewlines: Left AlignOperands: Align -AlignTrailingComments: 'true' -AllowAllParametersOfDeclarationOnNextLine: 'false' -AllowAllArgumentsOnNextLine: 'false' -AllowShortBlocksOnASingleLine: 'true' -AllowShortCaseLabelsOnASingleLine: 'true' +AlignTrailingComments: "true" +AllowAllParametersOfDeclarationOnNextLine: "false" +AllowAllArgumentsOnNextLine: "false" +AllowShortBlocksOnASingleLine: "true" +AllowShortCaseLabelsOnASingleLine: "true" AllowShortFunctionsOnASingleLine: InlineOnly AllowShortIfStatementsOnASingleLine: Always -AllowShortLoopsOnASingleLine: 'true' -AllowShortLambdasOnASingleLine: 'true' -AllowShortEnumsOnASingleLine: 'false' +AllowShortLoopsOnASingleLine: "true" +AllowShortLambdasOnASingleLine: "true" +AllowShortEnumsOnASingleLine: "false" AlignConsecutiveMacros: Consecutive BitFieldColonSpacing: After -BreakBeforeConceptDeclarations: 'true' +BreakBeforeConceptDeclarations: "true" BreakBinaryOperations: RespectPrecedence EmptyLineBeforeAccessModifier: LogicalBlock EnumTrailingComma: Insert -FixNamespaceComments: 'true' +FixNamespaceComments: "true" IndentExternBlock: Indent -IndentGotoLabels: 'false' -IndentRequiresClause: 'true' -InsertBraces: 'false' +IndentGotoLabels: "false" +IndentRequiresClause: "true" +InsertBraces: "false" InsertTrailingCommas: Wrapped LambdaBodyIndentation: Signature PPIndentWidth: 4 @@ -36,20 +36,29 @@ PenaltyBreakAssignment: 1000 PenaltyReturnTypeOnItsOwnLine: 1000 PenaltyBreakBeforeFirstCallParameter: 1000 PenaltyBreakOpenParenthesis: 1000 -PenaltyBreakBeforeMemberAccess: 10 -PenaltyIndentedWhitespace: 1 +PenaltyBreakBeforeMemberAccess: 1000 +PenaltyIndentedWhitespace: 2 ContinuationIndentWidth: 2 ReferenceAlignment: Left # RemoveBracesLLVM: 'true' RequiresClausePosition: OwnLine SeparateDefinitionBlocks: Always -SpaceAfterLogicalNot: 'false' +SpaceAfterLogicalNot: "false" SpaceAroundPointerQualifiers: After -SpaceBeforeCaseColon: 'false' +SpaceBeforeCaseColon: "false" AlwaysBreakAfterDefinitionReturnType: None -SpaceBeforeSquareBrackets: 'false' -SpaceInEmptyBlock: 'false' -AttributeMacros: [STORMKIT_FORCE_INLINE, STORMKIT_API, STORMKIT_PRIVATE, STORMKIT_PUBLIC, STORMKIT_CONST, STORMKIT_PURE, STORMKIT_INTRINSIC] +SpaceBeforeSquareBrackets: "false" +SpaceInEmptyBlock: "false" +AttributeMacros: + [ + STORMKIT_FORCE_INLINE, + STORMKIT_API, + STORMKIT_PRIVATE, + STORMKIT_PUBLIC, + STORMKIT_CONST, + STORMKIT_PURE, + STORMKIT_INTRINSIC, + ] IfMacros: [CASE_DO, CASE_DO_RETURN, CASE, CASE_ARGS_DO] BreakAfterAttributes: Always Macros: @@ -60,120 +69,122 @@ Macros: - STORMKIT_CONST=[[maybe_unused]] - STORMKIT_PURE=[[maybe_unused]] - STORMKIT_INTRINSIC=[[maybe_unused]] - + QualifierAlignment: Custom QualifierOrder: [static, inline, volatile, restrict, constexpr, const, type] SpacesInLineCommentPrefix: - Minimum: '1' - Maximum: '4' + Minimum: "1" + Maximum: "4" AlwaysBreakAfterReturnType: None -AlwaysBreakBeforeMultilineStrings: 'false' -AlwaysBreakTemplateDeclarations: 'Yes' -BinPackArguments: 'false' -BinPackParameters: 'false' +AlwaysBreakBeforeMultilineStrings: "false" +AlwaysBreakTemplateDeclarations: "Yes" +BinPackArguments: "false" +BinPackParameters: "false" BreakBeforeBinaryOperators: All BreakBeforeBraces: Attach BreakConstructorInitializers: BeforeColon +BreakBeforeCloseBracketBracedList: "true" BreakInheritanceList: BeforeColon -BreakStringLiterals: 'true' -ColumnLimit: '130' -CompactNamespaces: 'true' -ConstructorInitializerAllOnOneLineOrOnePerLine: 'true' -ConstructorInitializerIndentWidth: '4' +BreakStringLiterals: "true" +ColumnLimit: "130" +CompactNamespaces: "true" +ConstructorInitializerAllOnOneLineOrOnePerLine: "true" +ConstructorInitializerIndentWidth: "4" IncludeBlocks: Preserve -IndentCaseLabels: 'true' -IndentWidth: '4' -IndentWrappedFunctionNames: 'true' +IndentCaseLabels: "true" +IndentWidth: "4" +IndentWrappedFunctionNames: "true" IndentPPDirectives: BeforeHash -KeepEmptyLinesAtTheStartOfBlocks: 'false' -Cpp11BracedListStyle: 'false' -MaxEmptyLinesToKeep: '1' +KeepEmptyLinesAtTheStartOfBlocks: "false" +Cpp11BracedListStyle: "Block" +MaxEmptyLinesToKeep: "1" NamespaceIndentation: All ObjCSpaceAfterProperty: true ObjCSpaceBeforeProtocolList: false PointerAlignment: Left -SortIncludes: 'true' -SortUsingDeclarations: 'true' -SpaceAfterTemplateKeyword: 'false' -SpaceBeforeAssignmentOperators: 'true' -SpaceBeforeCpp11BracedList: 'true' -SpaceBeforeCtorInitializerColon: 'true' -SpaceBeforeInheritanceColon: 'false' -SpaceBeforeRangeBasedForLoopColon: 'true' -SpaceInEmptyParentheses: 'false' -SpacesInAngles: 'false' +SortIncludes: "true" +SortUsingDeclarations: "true" +SpaceAfterTemplateKeyword: "false" +SpaceBeforeAssignmentOperators: "true" +SpaceBeforeCpp11BracedList: "true" +SpaceBeforeCtorInitializerColon: "true" +SpaceBeforeInheritanceColon: "false" +SpaceBeforeRangeBasedForLoopColon: "true" +SpaceInEmptyParentheses: "false" +SpacesInAngles: "false" Standard: c++20 -TabWidth: '4' +TabWidth: "4" UseTab: Never --- Language: ObjC AlignAfterOpenBracket: Align AlignArrayOfStructures: Left -AlignConsecutiveAssignments: 'true' -AlignConsecutiveDeclarations: 'false' +AlignConsecutiveAssignments: "true" +AlignConsecutiveDeclarations: "false" AlignEscapedNewlines: Left AlignOperands: Align -AlignTrailingComments: 'true' -AllowAllParametersOfDeclarationOnNextLine: 'false' -AllowAllArgumentsOnNextLine: 'false' -AllowShortBlocksOnASingleLine: 'true' -AllowShortCaseLabelsOnASingleLine: 'true' +AlignTrailingComments: "true" +AllowAllParametersOfDeclarationOnNextLine: "false" +AllowAllArgumentsOnNextLine: "false" +AllowShortBlocksOnASingleLine: "true" +AllowShortCaseLabelsOnASingleLine: "true" AllowShortFunctionsOnASingleLine: InlineOnly AllowShortIfStatementsOnASingleLine: Always -AllowShortLoopsOnASingleLine: 'true' -AllowShortLambdasOnASingleLine: 'true' +AllowShortLoopsOnASingleLine: "true" +AllowShortLambdasOnASingleLine: "true" AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None -AlwaysBreakBeforeMultilineStrings: 'false' -AlwaysBreakTemplateDeclarations: 'Yes' -BinPackArguments: 'false' -BinPackParameters: 'false' +AlwaysBreakBeforeMultilineStrings: "false" +AlwaysBreakTemplateDeclarations: "Yes" +BinPackArguments: "false" +BinPackParameters: "false" BreakBeforeBinaryOperators: All BreakBeforeBraces: Attach BreakBinaryOperations: OnePerLine BreakConstructorInitializers: BeforeColon BreakInheritanceList: BeforeColon -BreakStringLiterals: 'true' -ColumnLimit: '130' -CompactNamespaces: 'true' -ConstructorInitializerAllOnOneLineOrOnePerLine: 'false' -ConstructorInitializerIndentWidth: '4' -ContinuationIndentWidth: '4' +BreakStringLiterals: "true" +ColumnLimit: "130" +CompactNamespaces: "true" +ConstructorInitializerAllOnOneLineOrOnePerLine: "false" +ConstructorInitializerIndentWidth: "4" +ContinuationIndentWidth: "4" IncludeBlocks: Preserve -IndentCaseLabels: 'true' -IndentWidth: '4' -IndentWrappedFunctionNames: 'true' +IndentCaseLabels: "true" +IndentWidth: "4" +IndentWrappedFunctionNames: "true" IndentPPDirectives: BeforeHash -KeepEmptyLinesAtTheStartOfBlocks: 'false' -Cpp11BracedListStyle: 'false' -MaxEmptyLinesToKeep: '1' +KeepEmptyLinesAtTheStartOfBlocks: "false" +Cpp11BracedListStyle: "false" +MaxEmptyLinesToKeep: "1" NamespaceIndentation: All ObjCSpaceAfterProperty: true ObjCSpaceBeforeProtocolList: false PointerAlignment: Right -PenaltyBreakAssignment: 1000 -PenaltyReturnTypeOnItsOwnLine: 1000 -PenaltyBreakBeforeFirstCallParameter: 1000 -PenaltyBreakOpenParenthesis: 1000 -PenaltyBreakBeforeMemberAccess: 10 -SortIncludes: 'true' -SortUsingDeclarations: 'true' -SpaceAfterTemplateKeyword: 'false' -SpaceBeforeAssignmentOperators: 'true' -SpaceBeforeCpp11BracedList: 'true' -SpaceBeforeCtorInitializerColon: 'true' -SpaceBeforeInheritanceColon: 'false' -SpaceBeforeRangeBasedForLoopColon: 'true' -SpaceInEmptyParentheses: 'false' -SpacesInAngles: 'false' +PenaltyBreakAssignment: 300 +PenaltyReturnTypeOnItsOwnLine: 100 +PenaltyBreakBeforeFirstCallParameter: 500 +PenaltyBreakOpenParenthesis: 700 +PenaltyBreakBeforeMemberAccess: 700 +SortIncludes: "true" +SortUsingDeclarations: "true" +SpaceAfterTemplateKeyword: "false" +SpaceBeforeAssignmentOperators: "true" +SpaceBeforeCpp11BracedList: "true" +SpaceBeforeCtorInitializerColon: "true" +SpaceBeforeInheritanceColon: "false" +SpaceBeforeRangeBasedForLoopColon: "true" +SpaceInEmptyParentheses: "false" +SpacesInAngles: "false" Standard: c++20 -TabWidth: '4' +TabWidth: "4" UseTab: Never -PenaltyIndentedWhitespace: '1' +PenaltyIndentedWhitespace: "1" QualifierAlignment: Custom QualifierOrder: [static, inline, volatile, restrict, constexpr, const, type] -AttributeMacros: [STORMKIT_FORCE_INLINE, STORMKIT_API, STORMKIT_PRIVATE, STORMKIT_PUBLIC] +AttributeMacros: + [STORMKIT_FORCE_INLINE, STORMKIT_API, STORMKIT_PRIVATE, STORMKIT_PUBLIC] IfMacros: [CASE_DO, CASE_DO_RETURN, CASE, CASE_ARGS_DO] BreakAfterAttributes: Always diff --git a/examples/wsi/events/win32/manifest.manifest b/examples/common/Windows/manifest.manifest similarity index 100% rename from examples/wsi/events/win32/manifest.manifest rename to examples/common/Windows/manifest.manifest diff --git a/examples/log/file-logger/iOS/info.plist b/examples/common/macOS/info.plist similarity index 97% rename from examples/log/file-logger/iOS/info.plist rename to examples/common/macOS/info.plist index 83e13e582..6e96e13c8 100644 --- a/examples/log/file-logger/iOS/info.plist +++ b/examples/common/macOS/info.plist @@ -1,44 +1,44 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - ${MACOSX_BUNDLE_EXECUTABLE_NAME} - CFBundleGetInfoString - ${MACOSX_BUNDLE_INFO_STRING} - CFBundleIconFile - ${MACOSX_BUNDLE_ICON_FILE} - CFBundleIdentifier - ${MACOSX_BUNDLE_GUI_IDENTIFIER} - CFBundleInfoDictionaryVersion - 6.0 - CFBundleLongVersionString - ${MACOSX_BUNDLE_LONG_VERSION_STRING} - CFBundleName - ${MACOSX_BUNDLE_BUNDLE_NAME} - CFBundlePackageType - APPL - CFBundleShortVersionString - ${MACOSX_BUNDLE_SHORT_VERSION_STRING} - CFBundleSignature - ???? - CFBundleVersion - ${MACOSX_BUNDLE_BUNDLE_VERSION} - LSRequiresIPhoneOS - - UISupportedInterfaceOrientations - - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - NSHumanReadableCopyright - ${MACOSX_BUNDLE_COPYRIGHT} - - + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${MACOSX_BUNDLE_EXECUTABLE_NAME} + CFBundleGetInfoString + ${MACOSX_BUNDLE_INFO_STRING} + CFBundleIconFile + ${MACOSX_BUNDLE_ICON_FILE} + CFBundleIdentifier + ${MACOSX_BUNDLE_GUI_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleLongVersionString + ${MACOSX_BUNDLE_LONG_VERSION_STRING} + CFBundleName + ${MACOSX_BUNDLE_BUNDLE_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + ${MACOSX_BUNDLE_SHORT_VERSION_STRING} + CFBundleSignature + ???? + CFBundleVersion + ${MACOSX_BUNDLE_BUNDLE_VERSION} + LSRequiresIPhoneOS + + UISupportedInterfaceOrientations + + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + NSHumanReadableCopyright + ${MACOSX_BUNDLE_COPYRIGHT} + + diff --git a/examples/entities/gameoflife/src/App.cpp b/examples/entities/gameoflife/src/App.cpp index 97f47c4b6..d1545f474 100644 --- a/examples/entities/gameoflife/src/App.cpp +++ b/examples/entities/gameoflife/src/App.cpp @@ -25,7 +25,7 @@ App::~App() { ilog("Cleaning"); } -auto App::run([[maybe_unused]] const int argc, [[maybe_unused]] CZString argv[]) -> i32 { +auto App::run([[maybe_unused]] const int argc, [[maybe_unused]] czstring argv[]) -> i32 { using Clock = std::chrono::high_resolution_clock; using namespace stormkit::literals; @@ -83,7 +83,7 @@ auto App::run([[maybe_unused]] const int argc, [[maybe_unused]] CZString argv[]) auto App::do_initWindow() -> void { const auto window_style = wsi::WindowStyle::ALL; - m_window = allocate(WINDOW_TITLE, math::ExtentU { 800u, 600u }, window_style); + m_window = allocate(WINDOW_TITLE, math::uextent2 { 800u, 600u }, window_style); m_renderer = allocate(*m_window); } @@ -124,8 +124,8 @@ auto App::handleKeyboard(const stormkit::wsi::KeyReleasedEventData& event) -> vo m_is_on_edit_mode = !m_is_on_edit_mode; m_update_system->setEditModeEnabled(m_is_on_edit_mode); break; - case wsi::Key::ADD: m_update_system->incrementDelta(Secondf { 0.01f }); break; - case wsi::Key::SUBSTRACT: m_update_system->incrementDelta(Secondf { -0.01f }); break; + case wsi::Key::ADD: m_update_system->incrementDelta(fsecond { 0.01f }); break; + case wsi::Key::SUBSTRACT: m_update_system->incrementDelta(fsecond { -0.01f }); break; default: break; } } @@ -135,11 +135,11 @@ auto App::handleMouse(const stormkit::wsi::MouseButtonPushedEventData& event) -> return; if (event.button != wsi::MouseButton::LEFT) return; - const auto cell_width = as(m_window->size().width) / as(BOARD_SIZE); - const auto cell_height = as(m_window->size().height) / as(BOARD_SIZE); + const auto cell_width = as(m_window->size().width) / as(BOARD_SIZE); + const auto cell_height = as(m_window->size().height) / as(BOARD_SIZE); - const auto x = glm::floor(as(event.position.x) / cell_width); - const auto y = glm::floor(as(event.position.y) / cell_height); + const auto x = glm::floor(as(event.position.x) / cell_width); + const auto y = glm::floor(as(event.position.y) / cell_height); const auto cells = m_entities.entities_with_component(); const auto it = std::ranges::find_if(cells, [&](const auto e) { diff --git a/examples/entities/gameoflife/src/App.mpp b/examples/entities/gameoflife/src/App.cppm similarity index 90% rename from examples/entities/gameoflife/src/App.mpp rename to examples/entities/gameoflife/src/App.cppm index 0c76586fc..ef52d2ecd 100644 --- a/examples/entities/gameoflife/src/App.mpp +++ b/examples/entities/gameoflife/src/App.cppm @@ -1,59 +1,59 @@ - - -#ifdef STORMKIT_BUILD_MODULES -export module App; - -import std; - -import stormkit.core; -import stormkit.image; -import stormkit.wsi; -import stormkit.entities; - -import Renderer; - -export { -#else - #include - - #include - #include - #include - #include - - #include "Renderer.mpp" -#endif - - class UpdateBoardSystem; - - class App: public stormkit::App { - public: - App(); - ~App() override; - - auto run(const int argc, CZString argv[]) -> stormkit::i32 override; - - private: - auto do_initWindow() -> void; - - auto handleKeyboard(const stormkit::wsi::KeyReleasedEventData& event) -> void; - auto handleMouse(const stormkit::wsi::MouseButtonPushedEventData& event) -> void; - auto createCell(stormkit::u32 x, stormkit::u32 y) -> void; - - std::unique_ptr m_window; - - bool m_fullscreen_enabled = false; - bool m_is_on_edit_mode = true; - - std::unique_ptr m_renderer; - - stormkit::entities::EntityManager m_entities; - - stormkit::image::Image m_board; - - UpdateBoardSystem* m_update_system = nullptr; - }; - -#ifdef STORMKIT_BUILD_MODULES -} -#endif + + +#ifdef STORMKIT_BUILD_MODULES +export module App; + +import std; + +import stormkit.core; +import stormkit.image; +import stormkit.wsi; +import stormkit.entities; + +import Renderer; + +export { +#else + #include + + #include + #include + #include + #include + + #include "Renderer.mpp" +#endif + + class UpdateBoardSystem; + + class App: public stormkit::App { + public: + App(); + ~App() override; + + auto run(const int argc, czstring argv[]) -> stormkit::i32 override; + + private: + auto do_initWindow() -> void; + + auto handleKeyboard(const stormkit::wsi::KeyReleasedEventData& event) -> void; + auto handleMouse(const stormkit::wsi::MouseButtonPushedEventData& event) -> void; + auto createCell(stormkit::u32 x, stormkit::u32 y) -> void; + + std::unique_ptr m_window; + + bool m_fullscreen_enabled = false; + bool m_is_on_edit_mode = true; + + std::unique_ptr m_renderer; + + stormkit::entities::EntityManager m_entities; + + stormkit::image::Image m_board; + + UpdateBoardSystem* m_update_system = nullptr; + }; + +#ifdef STORMKIT_BUILD_MODULES +} +#endif diff --git a/examples/entities/gameoflife/src/Components.mpp b/examples/entities/gameoflife/src/Components.cppm similarity index 77% rename from examples/entities/gameoflife/src/Components.mpp rename to examples/entities/gameoflife/src/Components.cppm index 290615e1f..cfd9c7265 100644 --- a/examples/entities/gameoflife/src/Components.mpp +++ b/examples/entities/gameoflife/src/Components.cppm @@ -1,28 +1,28 @@ - - -#ifdef STORMKIT_BUILD_MODULES -export module Components; - -import std; - -import stormkit.core; -import stormkit.entities; - -export { -#else - #include - - #include - #include -#endif - - struct PositionComponent: public stormkit::entities::Component { - stormkit::u32 x; - stormkit::u32 y; - - static constexpr Type TYPE = stormkit::entities::component_hash("PositionComponent"); - }; - -#ifdef STORMKIT_BUILD_MODULES -} -#endif + + +#ifdef STORMKIT_BUILD_MODULES +export module Components; + +import std; + +import stormkit.core; +import stormkit.entities; + +export { +#else + #include + + #include + #include +#endif + + struct PositionComponent: public stormkit::entities::Component { + stormkit::u32 x; + stormkit::u32 y; + + static constexpr Type TYPE = stormkit::hash("PositionComponent"); + }; + +#ifdef STORMKIT_BUILD_MODULES +} +#endif diff --git a/examples/entities/gameoflife/src/Constants.mpp b/examples/entities/gameoflife/src/Constants.cppm similarity index 82% rename from examples/entities/gameoflife/src/Constants.mpp rename to examples/entities/gameoflife/src/Constants.cppm index 1b5a5fad4..ca6ac6433 100644 --- a/examples/entities/gameoflife/src/Constants.mpp +++ b/examples/entities/gameoflife/src/Constants.cppm @@ -1,54 +1,54 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -#ifdef STORMKIT_BUILD_MODULES -export module Constants; - -import std; - -import stormkit.core; -import stormkit.log; -import stormkit.gpu; - -export { -#else - #include - - #include - #include - #include -#endif - - inline constexpr auto VERTEX_SIZE - = sizeof(stormkit::math::vec2f) + sizeof(stormkit::vec3f); - inline constexpr auto WINDOW_TITLE = "StormKit GameOfLife Example"; - inline constexpr auto MESH_VERTEX_BUFFER_SIZE = VERTEX_SIZE * 3; - inline constexpr auto MESH_VERTEX_BINDING_DESCRIPTIONS = std::array { - stormkit::gpu::VertexBindingDescription { .binding = 0, .stride = VERTEX_SIZE } - }; - inline constexpr auto MESH_VERTEX_ATTRIBUTE_DESCRIPTIONS = std::array { - stormkit::gpu::VertexInputAttributeDescription { .location = 0, - .binding = 0, - .format = stormkit::gpu::format::f322, - .offset = 0 }, - stormkit::gpu::VertexInputAttributeDescription { .location = 1, - .binding = 0, - .format = stormkit::gpu::format::f322, - .offset - = sizeof(stormkit::math::vec2f) } - }; - - inline constexpr auto BOARD_SIZE = 100u; - inline constexpr auto BOARD_BUFFERING_COUNT = 3u; - inline constexpr auto REFRESH_BOARD_DELTA = stormkit::Secondf { 1 }; - - inline constexpr auto SHADER_DATA = stormkit::as_bytes( -#include - ); - - IN_MODULE_LOGGER("StormKit.GameOfLife"); - -#ifdef STORMKIT_BUILD_MODULES -} -#endif +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +#ifdef STORMKIT_BUILD_MODULES +export module Constants; + +import std; + +import stormkit.core; +import stormkit.log; +import stormkit.gpu; + +export { +#else + #include + + #include + #include + #include +#endif + + inline constexpr auto VERTEX_SIZE + = sizeof(stormkit::math::fvec2) + sizeof(stormkit::fvec3); + inline constexpr auto WINDOW_TITLE = "StormKit GameOfLife Example"; + inline constexpr auto MESH_VERTEX_BUFFER_SIZE = VERTEX_SIZE * 3; + inline constexpr auto MESH_VERTEX_BINDING_DESCRIPTIONS = array { + stormkit::gpu::VertexBindingDescription { .binding = 0, .stride = VERTEX_SIZE } + }; + inline constexpr auto MESH_VERTEX_ATTRIBUTE_DESCRIPTIONS = array { + stormkit::gpu::VertexInputAttributeDescription { .location = 0, + .binding = 0, + .format = stormkit::gpu::format::f322, + .offset = 0 }, + stormkit::gpu::VertexInputAttributeDescription { .location = 1, + .binding = 0, + .format = stormkit::gpu::format::f322, + .offset + = sizeof(stormkit::math::fvec2) } + }; + + inline constexpr auto BOARD_SIZE = 100u; + inline constexpr auto BOARD_BUFFERING_COUNT = 3u; + inline constexpr auto REFRESH_BOARD_DELTA = stormkit::fsecond { 1 }; + + inline constexpr auto SHADER_DATA = stormkit::as_bytes( +#include + ); + + IN_MODULE_LOGGER("StormKit.GameOfLife"); + +#ifdef STORMKIT_BUILD_MODULES +} +#endif diff --git a/examples/entities/gameoflife/src/Renderer.cpp b/examples/entities/gameoflife/src/Renderer.cpp index 27b849145..cc93afd5c 100644 --- a/examples/entities/gameoflife/src/Renderer.cpp +++ b/examples/entities/gameoflife/src/Renderer.cpp @@ -28,7 +28,7 @@ auto Renderer::operator=(Renderer&&) noexcept -> Renderer& = default; auto Renderer::renderFrame() -> void { const auto& surface_extent = m_surface->extent(); - const auto surface_extentf = math::ExtentF { surface_extent }; + const auto surface_extentf = math::fextent2 { surface_extent }; if (m_surface->needRecreate()) { m_surface->recreate(); @@ -36,17 +36,17 @@ auto Renderer::renderFrame() -> void { } const auto viewports = [&] { - auto v = std::vector {}; + auto v = dyn_array {}; v.emplace_back(gpu::Viewport { - .extent = surface_extentf, - .depth = { 0, 1 } + .extent = surface_extentf, + .depth = { 0, 1 } }); return v; }(); const auto scissors = [&] { - auto s = std::vector {}; + auto s = dyn_array {}; s.emplace_back(gpu::Scissor { .extent = surface_extent }); return s; @@ -88,14 +88,12 @@ auto Renderer::updateBoard(const stormkit::image::Image& board) -> void { if (m_current_fence) m_current_fence->wait(); - const auto descriptors = into_array(gpu::Descriptor { - gpu::ImageDescriptor { .type = gpu::DescriptorType::Combined_Image_Sampler, - .binding = 0, - .layout = gpu::ImageLayout::Shader_Read_Only_Optimal, - .image_view - = makeConstObserver(m_board.image_views[m_board.current_image]), - .sampler = makeConstObserver(m_board.sampler) } - }); + const auto descriptors = into_array_of(gpu::ImageDescriptor { + .type = gpu::DescriptorType::Combined_Image_Sampler, + .binding = 0, + .layout = gpu::ImageLayout::Shader_Read_Only_Optimal, + .image_view = makeConstObserver(m_board.image_views[m_board.current_image]), + .sampler = makeConstObserver(m_board.sampler) }); m_board.descriptor_set->update(descriptors); } @@ -122,9 +120,7 @@ auto Renderer::do_initBaseRenderObjects() -> void { const auto& physical_device_info = physical_device.info(); - ilog("Using physical device {} ({:#06x})", - physical_device_info.device_name, - physical_device_info.device_id); + ilog("Using physical device {} ({:#06x})", physical_device_info.device_name, physical_device_info.device_id); m_device = physical_device.allocateLogicalDevice(); @@ -136,49 +132,46 @@ auto Renderer::do_initBaseRenderObjects() -> void { auto Renderer::do_initMeshRenderObjects() -> void { const auto& surface_extent = m_surface->extent(); - const auto surface_extentf = math::ExtentF { surface_extent }; + const auto surface_extentf = math::fextent2 { surface_extent }; m_board.vertex_shader = m_device->allocateShader(SHADER_DATA, gpu::ShaderStageFlag::Vertex); m_board.fragment_shader = m_device->allocateShader(SHADER_DATA, gpu::ShaderStageFlag::Fragment); - const auto description - = gpu::RenderPassDescription { .attachments = { { .format = m_surface->pixelFormat() } }, - .subpasses - = { { .bind_point = gpu::PipelineBindPoint::Graphics, - .attachment_refs = { { .attachment_id = 0u } } } } }; + const auto description = gpu::RenderPassDescription { + .attachments = { { .format = m_surface->pixelFormat() } }, + .subpasses = { { .bind_point = gpu::PipelineBindPoint::Graphics, .attachment_refs = { { .attachment_id = 0u } } } } + }; m_descriptor_set_layout = m_device->allocateDescriptorSetLayout(); - m_descriptor_set_layout->addBinding({ .binding = 0, - .type = gpu::DescriptorType::Combined_Image_Sampler, - .stages = gpu::ShaderStageFlag::Fragment, - .descriptor_count = 1 }); + m_descriptor_set_layout + ->addBinding({ .binding = 0, + .type = gpu::DescriptorType::Combined_Image_Sampler, + .stages = gpu::ShaderStageFlag::Fragment, + .descriptor_count = 1 }); m_descriptor_set_layout->bake(); m_descriptor_pool = m_device->allocateDescriptorPool( - std::array { - gpu::DescriptorPool::Size { gpu::DescriptorType::Combined_Image_Sampler, 1 } + array { + gpu::DescriptorPool::Size { gpu::DescriptorType::Combined_Image_Sampler, 1 } }, - 1); + 1); m_render_pass = m_device->allocateRenderPass(description); m_board.pipeline = m_device->allocateRasterPipeline(); const auto state = gpu::RasterPipelineState { .input_assembly_state = { .topology = gpu::PrimitiveTopology::Triangle_Strip }, - .viewport_state - = { .viewports = { gpu::Viewport { .position = { 0.f, 0.f }, - .extent = surface_extentf, - .depth = { 0.f, 1.f } } }, + .viewport_state = { .viewports = { gpu::Viewport { .position = { 0.f, 0.f }, + .extent = surface_extentf, + .depth = { 0.f, 1.f } } }, .scissors = { gpu::Scissor { .offset = { 0, 0 }, .extent = surface_extent } } }, - .color_blend_state - = { .attachments = { { .blend_enable = true, - .src_color_blend_factor = gpu::BlendFactor::Src_Alpha, - .dst_color_blend_factor = gpu::BlendFactor::One_Minus_Src_Alpha, - .src_alpha_blend_factor = gpu::BlendFactor::Src_Alpha, - .dst_alpha_blend_factor = gpu::BlendFactor::One_Minus_Src_Alpha, - .alpha_blend_operation = gpu::BlendOperation::Add } } }, - .dynamic_state = { { gpu::DynamicState::Viewport, gpu::DynamicState::Scissor } }, - .shader_state - = { .shaders = makeConstObserverArray(m_board.vertex_shader, m_board.fragment_shader) }, + .color_blend_state = { .attachments = { { .blend_enable = true, + .src_color_blend_factor = gpu::BlendFactor::Src_Alpha, + .dst_color_blend_factor = gpu::BlendFactor::One_Minus_Src_Alpha, + .src_alpha_blend_factor = gpu::BlendFactor::Src_Alpha, + .dst_alpha_blend_factor = gpu::BlendFactor::One_Minus_Src_Alpha, + .alpha_blend_operation = gpu::BlendOperation::Add } } }, + .dynamic_state = { { gpu::DynamicState::Viewport, gpu::DynamicState::Scissor } }, + .shader_state = { .shaders = makeConstObserverArray(m_board.vertex_shader, m_board.fragment_shader) }, /*.vertex_input_state = { .binding_descriptions = to_dyn_array(MESH_VERTEX_BINDING_DESCRIPTIONS), .input_attribute_descriptions = @@ -193,17 +186,17 @@ auto Renderer::do_initMeshRenderObjects() -> void { for (auto i : range(BOARD_BUFFERING_COUNT)) { auto& img = m_board.images.emplace_back(*m_device, gpu::Image::CreateInfo { - .extent = { BOARD_SIZE, BOARD_SIZE } + .extent = { BOARD_SIZE, BOARD_SIZE } }); m_board.image_views.emplace_back(img.createView()); } - m_board.sampler = m_device->allocateSampler( - gpu::Sampler::Settings { .mag_filter = gpu::Filter::Nearest, - .min_filter = gpu::Filter::Nearest, - .address_mode_u = gpu::SamplerAddressMode::Clamp_To_Edge, - .address_mode_v = gpu::SamplerAddressMode::Clamp_To_Edge }); + m_board.sampler = m_device->allocateSampler(gpu::Sampler::Settings { + .mag_filter = gpu::Filter::Nearest, + .min_filter = gpu::Filter::Nearest, + .address_mode_u = gpu::SamplerAddressMode::Clamp_To_Edge, + .address_mode_v = gpu::SamplerAddressMode::Clamp_To_Edge }); m_board.descriptor_set = m_descriptor_pool->allocateDescriptorSet(*m_descriptor_set_layout); @@ -212,7 +205,7 @@ auto Renderer::do_initMeshRenderObjects() -> void { auto Renderer::do_initPerFrameObjects() -> void { const auto& surface_extent = m_surface->extent(); - const auto surface_extentf = math::ExtentF { surface_extent }; + const auto surface_extentf = math::fextent2 { surface_extent }; const auto buffering_count = m_surface->bufferingCount(); m_surface_views.clear(); diff --git a/examples/entities/gameoflife/src/Renderer.mpp b/examples/entities/gameoflife/src/Renderer.cppm similarity index 83% rename from examples/entities/gameoflife/src/Renderer.mpp rename to examples/entities/gameoflife/src/Renderer.cppm index 63f6aa419..a45a6437c 100644 --- a/examples/entities/gameoflife/src/Renderer.mpp +++ b/examples/entities/gameoflife/src/Renderer.cppm @@ -1,77 +1,77 @@ - - -#ifdef STORMKIT_BUILD_MODULES -export module Renderer; - -import std; - -import stormkit.core; -import stormkit.wsi; -import stormkit.gpu; - -export { -#else - #include - - #include - #include - #include -#endif - - class Renderer { - public: - Renderer(const stormkit::wsi::Window& window); - ~Renderer(); - - Renderer(const Renderer&) = delete; - auto operator=(const Renderer&) -> Renderer& = delete; - - Renderer(Renderer&&) noexcept; - auto operator=(Renderer&&) noexcept -> Renderer&; - - auto renderFrame() -> void; - - auto updateBoard(const stormkit::image::Image& board) -> void; - - private: - auto do_initBaseRenderObjects() -> void; - auto do_initMeshRenderObjects() -> void; - auto do_initPerFrameObjects() -> void; - - const stormkit::wsi::Window* m_window = nullptr; - - std::unique_ptr m_instance; - std::unique_ptr m_device; - std::unique_ptr m_surface; - stormkit::gpu::Fence* m_current_fence = nullptr; - - const stormkit::gpu::Queue* m_queue = nullptr; - std::vector m_surface_views; - - std::unique_ptr m_descriptor_set_layout; - std::unique_ptr m_descriptor_pool; - - std::unique_ptr m_render_pass; - - struct Board { - std::vector images; - std::vector image_views; - std::unique_ptr sampler; - - stormkit::u32 current_image = 0; - - std::unique_ptr vertex_shader; - std::unique_ptr fragment_shader; - - std::unique_ptr pipeline; - - std::unique_ptr descriptor_set; - } m_board; - - std::vector m_command_buffers; - std::vector m_framebuffers; - }; - -#ifdef STORMKIT_BUILD_MODULES -} -#endif + + +#ifdef STORMKIT_BUILD_MODULES +export module Renderer; + +import std; + +import stormkit.core; +import stormkit.wsi; +import stormkit.gpu; + +export { +#else + #include + + #include + #include + #include +#endif + + class Renderer { + public: + Renderer(const stormkit::wsi::Window& window); + ~Renderer(); + + Renderer(const Renderer&) = delete; + auto operator=(const Renderer&) -> Renderer& = delete; + + Renderer(Renderer&&) noexcept; + auto operator=(Renderer&&) noexcept -> Renderer&; + + auto renderFrame() -> void; + + auto updateBoard(const stormkit::image::Image& board) -> void; + + private: + auto do_initBaseRenderObjects() -> void; + auto do_initMeshRenderObjects() -> void; + auto do_initPerFrameObjects() -> void; + + const stormkit::wsi::Window* m_window = nullptr; + + std::unique_ptr m_instance; + std::unique_ptr m_device; + std::unique_ptr m_surface; + stormkit::gpu::Fence* m_current_fence = nullptr; + + const stormkit::gpu::Queue* m_queue = nullptr; + dyn_array m_surface_views; + + std::unique_ptr m_descriptor_set_layout; + std::unique_ptr m_descriptor_pool; + + std::unique_ptr m_render_pass; + + struct Board { + dyn_array images; + dyn_array image_views; + std::unique_ptr sampler; + + stormkit::u32 current_image = 0; + + std::unique_ptr vertex_shader; + std::unique_ptr fragment_shader; + + std::unique_ptr pipeline; + + std::unique_ptr descriptor_set; + } m_board; + + dyn_array m_command_buffers; + dyn_array m_framebuffers; + }; + +#ifdef STORMKIT_BUILD_MODULES +} +#endif diff --git a/examples/entities/gameoflife/src/Systems.cpp b/examples/entities/gameoflife/src/Systems.cpp index 8f621fd99..4f0fce0d4 100644 --- a/examples/entities/gameoflife/src/Systems.cpp +++ b/examples/entities/gameoflife/src/Systems.cpp @@ -24,7 +24,7 @@ UpdateBoardSystem::~UpdateBoardSystem() UpdateBoardSystem::UpdateBoardSystem(UpdateBoardSystem&&) noexcept = default; auto UpdateBoardSystem::operator=(UpdateBoardSystem&&) noexcept -> UpdateBoardSystem& = default; -auto UpdateBoardSystem::update(stormkit::Secondf delta) -> void { +auto UpdateBoardSystem::update(stormkit::fsecond delta) -> void { const auto now = Clock::now(); if (m_is_on_edit_mode) [[unlikely]] { diff --git a/examples/entities/gameoflife/src/Systems.mpp b/examples/entities/gameoflife/src/Systems.cppm similarity index 85% rename from examples/entities/gameoflife/src/Systems.mpp rename to examples/entities/gameoflife/src/Systems.cppm index 279e12c7e..e7c4d5cf6 100644 --- a/examples/entities/gameoflife/src/Systems.mpp +++ b/examples/entities/gameoflife/src/Systems.cppm @@ -1,62 +1,62 @@ - - -#ifdef STORMKIT_BUILD_MODULES -export module Systems; - -import std; - -import stormkit.core; -import stormkit.image; -import stormkit.entities; - -import Constants; -import Renderer; - -export { -#else - #include - - #include - #include - #include - - #include "Constants.mpp" - #include "Renderer.mpp" -#endif - - class UpdateBoardSystem final: public stormkit::entities::System { - public: - UpdateBoardSystem(stormkit::image::Image& board, - Renderer& renderer, - stormkit::entities::EntityManager& manager); - ~UpdateBoardSystem() override; - - UpdateBoardSystem(UpdateBoardSystem&&) noexcept; - auto operator=(UpdateBoardSystem&&) noexcept -> UpdateBoardSystem&; - - auto update(stormkit::Secondf delta) -> void override; - auto post_update() -> void override; - - auto setEditModeEnabled(bool enabled) noexcept { m_is_on_edit_mode = enabled; } - - auto incrementDelta(stormkit::Secondf delta) { m_refresh_board_delta += delta; } - - private: - using Clock = std::chrono::high_resolution_clock; - - auto on_message_received(const stormkit::entities::Message& message) -> void override {}; - - bool m_is_on_edit_mode = true; - stormkit::image::Image* m_board = nullptr; - Renderer* m_renderer = nullptr; - - Clock::time_point m_last_update; - - bool m_updated = true; - - stormkit::Secondf m_refresh_board_delta = REFRESH_BOARD_DELTA; - }; - -#ifdef STORMKIT_BUILD_MODULES -} -#endif + + +#ifdef STORMKIT_BUILD_MODULES +export module Systems; + +import std; + +import stormkit.core; +import stormkit.image; +import stormkit.entities; + +import Constants; +import Renderer; + +export { +#else + #include + + #include + #include + #include + + #include "Constants.mpp" + #include "Renderer.mpp" +#endif + + class UpdateBoardSystem final: public stormkit::entities::System { + public: + UpdateBoardSystem(stormkit::image::Image& board, + Renderer& renderer, + stormkit::entities::EntityManager& manager); + ~UpdateBoardSystem() override; + + UpdateBoardSystem(UpdateBoardSystem&&) noexcept; + auto operator=(UpdateBoardSystem&&) noexcept -> UpdateBoardSystem&; + + auto update(stormkit::fsecond delta) -> void override; + auto post_update() -> void override; + + auto setEditModeEnabled(bool enabled) noexcept { m_is_on_edit_mode = enabled; } + + auto incrementDelta(stormkit::fsecond delta) { m_refresh_board_delta += delta; } + + private: + using Clock = std::chrono::high_resolution_clock; + + auto on_message_received(const stormkit::entities::Message& message) -> void override {}; + + bool m_is_on_edit_mode = true; + stormkit::image::Image* m_board = nullptr; + Renderer* m_renderer = nullptr; + + Clock::time_point m_last_update; + + bool m_updated = true; + + stormkit::fsecond m_refresh_board_delta = REFRESH_BOARD_DELTA; + }; + +#ifdef STORMKIT_BUILD_MODULES +} +#endif diff --git a/examples/entities/gameoflife/src/main.cpp b/examples/entities/gameoflife/src/main.cpp index 13eee9992..4be3cea29 100644 --- a/examples/entities/gameoflife/src/main.cpp +++ b/examples/entities/gameoflife/src/main.cpp @@ -14,7 +14,7 @@ import App; #include "App.mpp" #endif -auto main([[maybe_unused]] std::span args) -> int { +auto main([[maybe_unused]] array_view args) -> int { using namespace stormkit; setup_signal_handler(); diff --git a/examples/entities/gameoflife/xmake.lua b/examples/entities/gameoflife/xmake.lua index 9e96e6baf..221d097be 100644 --- a/examples/entities/gameoflife/xmake.lua +++ b/examples/entities/gameoflife/xmake.lua @@ -1,29 +1,29 @@ -if has_config("enable_gpu") and has_config("enable_wsi") and has_config("enable-image") then - target("game_of_life") - do - set_kind("binary") - set_languages("cxxlatest", "clatest") +-- if has_config("enable_gpu") and has_config("enable_wsi") and has_config("enable-image") then +-- target("game_of_life") +-- do +-- set_kind("binary") +-- set_languages("cxxlatest", "clatest") - add_packages("nzsl") - add_deps("core", "main", "log", "wsi", "gpu", "image") +-- add_packages("nzsl") +-- add_deps("core", "main", "log", "wsi", "gpu", "image") - add_rules("stormkit.utils.nzsl2spv") +-- add_rules("stormkit.utils.nzsl2spv") - if is_mode("debug") then - add_defines("STORMKIT_BUILD_DEBUG") - add_defines("STORMKIT_ASSERT=1") - set_suffixname("-d") - else - add_defines("STORMKIT_ASSERT=0") - end +-- if is_mode("debug") then +-- add_defines("STORMKIT_BUILD_DEBUG") +-- add_defines("STORMKIT_ASSERT=1") +-- set_suffixname("-d") +-- else +-- add_defines("STORMKIT_ASSERT=0") +-- end - add_files("src/*.cpp") - add_files("src/*.mpp") - add_files("shaders/*.nzsl") - if is_plat("windows") then add_files("win32/*.manifest") end +-- add_files("src/*.cpp") +-- add_files("src/*.cppm") +-- add_files("shaders/*.nzsl") +-- if is_plat("windows") then add_files("win32/*.manifest") end - add_rules("platform.windows.subsystem.windows") +-- add_rules("platform.windows.subsystem.windows") - set_group("examples/stormkit-entities") - end -end +-- set_group("examples/stormkit-entities") +-- end +-- end diff --git a/src/wsi/linux/mouse.mpp b/examples/entities/xmake.lua similarity index 100% rename from src/wsi/linux/mouse.mpp rename to examples/entities/xmake.lua diff --git a/examples/gpu/common/app.cppm b/examples/gpu/common/app.cppm new file mode 100644 index 000000000..9fe4d8c3c --- /dev/null +++ b/examples/gpu/common/app.cppm @@ -0,0 +1,150 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include + +#include + +#include + +export module gpu_app; + +import std; +import stormkit; + +export import :logger; + +using namespace stormkit; + +namespace stdr = std::ranges; +namespace stdv = std::views; + +NAMED_LOGGER(vulkan_logger, "vulkan") + +extern "C" auto debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, + VkDebugUtilsMessageTypeFlagsEXT, + const VkDebugUtilsMessengerCallbackDataEXT* callback_data, + void*) noexcept -> u32 { + EXPECTS(callback_data); + auto message = std::format("{}", callback_data->pMessage); + + if (check_flag_bit(severity, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT)) vulkan_logger.ilog("{}", message); + else if (check_flag_bit(severity, VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT)) + vulkan_logger.dlog("{}", message); + else if (check_flag_bit(severity, VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)) + vulkan_logger.elog("{}", message); + else if (check_flag_bit(severity, VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT)) + vulkan_logger.wlog("{}", message); + + return 0; +} + +static constexpr auto ENABLE_VALIDATION_LAYERS = false; + +export namespace base { + class Application { + public: + auto run(this auto& self, array_view args) { + wsi::parse_args(args); + log::parse_args(args); + + const auto example_name = self.example_name(); + + auto logger_singleton = log::Logger::create_logger_instance(); + + self.init_window(example_name); + self.init_gpu(example_name); + + self.init_example(); + + self.m_window->event_loop([&self] noexcept { self.run_example(); }); + + TryDiscardAssert(self.m_raster_queue->wait_idle(), "Failed to wait for raster queue"); + self.m_device->wait_idle(); + + if constexpr (requires { self.deinit(); }) self.deinit(); + } + + protected: + DeferInit m_window; + DeferInit m_instance; + DeferInit m_debug_callback; + DeferInit m_surface; + DeferInit m_physical_device; + DeferInit m_device; + DeferInit m_swapchain; + DeferInit m_raster_queue; + DeferInit m_command_pool; + + private: + auto init_window(string_view example_name) noexcept -> void { + m_window = wsi::Window::open(std::format("Stormkit GPU {} example", example_name), + { 800_u32, 600_u32 }, + wsi::WindowFlag::DEFAULT | wsi::WindowFlag::EXTERNAL_CONTEXT); + m_window->on([this](u8 /*id*/, wsi::Key key, char /*c*/) mutable noexcept { + if (key == wsi::Key::ESCAPE) m_window->close(); + }); + } + + auto init_gpu(string_view example_name) noexcept -> void { + // initialize gpu backend (vulkan or webgpu depending the platform) + TryDiscardAssert(gpu::initialize_backend(), "Failed to initialize gpu backend"); + + // create gpu instance and attach surface to window + m_instance = TryAssert(gpu::Instance::create({ .application_name = string { example_name }, + .enable_validation_layers = ENABLE_VALIDATION_LAYERS }), + "Failed to initialize gpu instance"); + + if (ENABLE_VALIDATION_LAYERS) { + m_debug_callback = TryAssert(gpu::DebugCallback::create(m_instance, { .messenger_closure = debug_callback }), + "Failed to initialize gpu instance"); + } + + m_surface = TryAssert(gpu::Surface::create_from_window(m_instance, m_window), + "Failed to initialize window gpu surface"); + + // pick the best physical device + const auto& physical_devices = m_instance->physical_devices(); + if (stdr::empty(physical_devices)) { + elog("No render physical device found!"); + return; + } + ilog("Physical devices: {}", physical_devices); + + m_physical_device = physical_devices.front(); + auto score = gpu::score_physical_device(*m_physical_device); + for (auto i : range(1_u32, stdr::size(physical_devices))) { + const auto& d = physical_devices[i]; + const auto d_score = gpu::score_physical_device(d); + if (d_score > score) { + m_physical_device = d; + score = d_score; + } + } + + ilog("Picked gpu: {}", *m_physical_device); + + // create gpu device + m_device = TryAssert(gpu::Device::create(m_physical_device, {}), "Failed to initialize gpu device"); + + // create swapchain + const auto window_extent = m_window->extent(); + m_swapchain = TryAssert(gpu::SwapChain::create(m_device, { gpu::as_view(m_surface), window_extent }), + "Failed to create swapchain"); + + const auto queue_entries = m_device->queue_entries(); + const auto it = stdr::find_if(queue_entries, gpu::monadic::find_queue()); + ensures(it != stdr::cend(queue_entries), "No raster queue found!"); + + m_raster_queue = gpu::Queue::create(m_device, *it); + + m_command_pool = TryAssert(gpu::CommandPool::create(m_device, { .queue = m_raster_queue }), + "Failed to create command pool " + "command pool"); + } + }; +} // namespace base diff --git a/examples/gpu/common/app.mpp b/examples/gpu/common/app.mpp deleted file mode 100644 index caec4ac2a..000000000 --- a/examples/gpu/common/app.mpp +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -export module gpu_app; - -import std; -import stormkit; - -using namespace stormkit; - -namespace stdr = std::ranges; -namespace stdv = std::views; - -export namespace base { - class Application { - public: - auto run(this auto& self, std::span args) { - const auto example_name = self.example_name(); - - auto logger_singleton = log::Logger::create_logger_instance(); - - wsi::parse_args(args); - - self.init_window(example_name); - self.init_gpu(example_name); - - self.init_example(); - - self.m_window->event_loop([&self] noexcept { self.run_example(); }); - - self.m_raster_queue->wait_idle(); - self.m_device->wait_idle(); - - if constexpr (requires { self.deinit(); }) self.deinit(); - } - - protected: - DeferInit m_window; - DeferInit m_instance; - DeferInit m_surface; - OptionalRef m_physical_device; - DeferInit m_device; - DeferInit m_swapchain; - DeferInit m_raster_queue; - DeferInit m_command_pool; - - private: - auto init_window(std::string_view example_name) noexcept -> void { - m_window = wsi::Window::open(std::format("Stormkit GPU {} example", example_name), - { 800_u32, 600_u32 }, - wsi::WindowFlag::DEFAULT - | wsi::WindowFlag::EXTERNAL_CONTEXT); - m_window->on([this](u8 /*id*/, - wsi::Key key, - char /*c*/) mutable noexcept { - if (key == wsi::Key::ESCAPE) m_window->close(); - }); - } - - auto init_gpu(std::string_view example_name) noexcept -> void { - // initialize gpu backend (vulkan or webgpu depending the platform) - *gpu::initialize_backend() - .transform_error(monadic::assert("Failed to initialize gpu backend")); - - // create gpu instance and attach surface to window - m_instance = gpu::Instance::create(std::string { example_name }) - .transform_error(monadic::assert("Failed to initialize gpu instance")) - .value(); - - m_surface = gpu::Surface::create_from_window(m_instance, m_window) - .transform_error(monadic:: - assert("Failed to initialize window gpu surface")) - .value(); - // pick the best physical device - const auto& physical_devices = m_instance->physical_devices(); - if (stdr::empty(physical_devices)) { - log::Logger::elog("No render physical device found!"); - return; - } - log::Logger::ilog("Physical devices: {}", physical_devices); - - m_physical_device = as_opt_ref(physical_devices.front()); - auto score = gpu::score_physical_device(*m_physical_device); - for (auto i = 1u; i < stdr::size(physical_devices); ++i) { - const auto& d = physical_devices[i]; - const auto d_score = gpu::score_physical_device(d); - if (d_score > score) { - m_physical_device = as_opt_ref(d); - score = d_score; - } - } - - log::Logger::ilog("Picked gpu: {}", *m_physical_device); - - // create gpu device - m_device = gpu::Device::create(*m_physical_device, m_instance) - .transform_error(monadic::assert("Failed to initialize gpu device")) - .value(); - - // create swapchain - const auto window_extent = m_window->extent(); - m_swapchain = gpu::SwapChain::create(m_device, m_surface, window_extent) - .transform_error(monadic::assert("Failed to create swapchain")) - .value(); - - m_raster_queue = gpu::Queue::create(m_device, m_device->raster_queue_entry()); - - m_command_pool = gpu::CommandPool::create(m_device) - .transform_error(monadic::assert("Failed to create raster queue " - "command pool")) - .value(); - } - }; -} // namespace base diff --git a/examples/gpu/imgui/iOS/Info.plist b/examples/gpu/imgui/iOS/Info.plist deleted file mode 100644 index a62a3592d..000000000 --- a/examples/gpu/imgui/iOS/Info.plist +++ /dev/null @@ -1,46 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - ${MACOSX_BUNDLE_EXECUTABLE_NAME} - CFBundleGetInfoString - ${MACOSX_BUNDLE_INFO_STRING} - CFBundleIconFile - ${MACOSX_BUNDLE_ICON_FILE} - CFBundleIdentifier - ${MACOSX_BUNDLE_GUI_IDENTIFIER} - CFBundleInfoDictionaryVersion - 6.0 - CFBundleLongVersionString - ${MACOSX_BUNDLE_LONG_VERSION_STRING} - CFBundleName - ${MACOSX_BUNDLE_BUNDLE_NAME} - CFBundlePackageType - APPL - CFBundleShortVersionString - ${MACOSX_BUNDLE_SHORT_VERSION_STRING} - CFBundleSignature - ???? - CFBundleVersion - ${MACOSX_BUNDLE_BUNDLE_VERSION} - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UISupportedInterfaceOrientations - - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - NSHumanReadableCopyright - ${MACOSX_BUNDLE_COPYRIGHT} - - diff --git a/examples/gpu/imgui/iOS/LaunchScreen.storyboard b/examples/gpu/imgui/iOS/LaunchScreen.storyboard deleted file mode 100644 index 436820912..000000000 --- a/examples/gpu/imgui/iOS/LaunchScreen.storyboard +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/examples/gpu/imgui/macOS/Info.plist b/examples/gpu/imgui/macOS/Info.plist deleted file mode 100644 index f68f66070..000000000 --- a/examples/gpu/imgui/macOS/Info.plist +++ /dev/null @@ -1,36 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - ${MACOSX_BUNDLE_EXECUTABLE_NAME} - CFBundleGetInfoString - ${MACOSX_BUNDLE_INFO_STRING} - CFBundleIconFile - ${MACOSX_BUNDLE_ICON_FILE} - CFBundleIdentifier - ${MACOSX_BUNDLE_GUI_IDENTIFIER} - CFBundleInfoDictionaryVersion - 6.0 - CFBundleLongVersionString - ${MACOSX_BUNDLE_LONG_VERSION_STRING} - CFBundleName - ${MACOSX_BUNDLE_BUNDLE_NAME} - CFBundlePackageType - APPL - CFBundleShortVersionString - ${MACOSX_BUNDLE_SHORT_VERSION_STRING} - CFBundleSignature - ???? - CFBundleVersion - ${MACOSX_BUNDLE_BUNDLE_VERSION} - CSResourcesFileMapped - - NSHumanReadableCopyright - ${MACOSX_BUNDLE_COPYRIGHT} - NSHighResolutionCapable - - - diff --git a/examples/gpu/imgui/src/logger.cppm b/examples/gpu/imgui/src/logger.cppm new file mode 100644 index 000000000..ca004b433 --- /dev/null +++ b/examples/gpu/imgui/src/logger.cppm @@ -0,0 +1,15 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +export module gpu_app:logger; + +import std; + +import stormkit.log; + +export { IN_MODULE_LOGGER("Imgui"); } diff --git a/examples/gpu/imgui/src/main.cpp b/examples/gpu/imgui/src/main.cpp index ba751c442..018321dc2 100644 --- a/examples/gpu/imgui/src/main.cpp +++ b/examples/gpu/imgui/src/main.cpp @@ -7,6 +7,7 @@ import std; import stormkit; import gpu_app; +#include #include #include #include @@ -16,8 +17,6 @@ import gpu_app; #include #undef assert -LOGGER("stormkit.examples.gpu.imgui"); - namespace stdr = std::ranges; namespace stdfs = std::filesystem; @@ -31,13 +30,17 @@ struct SubmissionResource { }; struct SwapchainImageResource { - Ref image; - gpu::ImageView view; - gpu::FrameBuffer framebuffer; - gpu::Semaphore render_finished; + gpu::view::Image image; + gpu::ImageView view; + gpu::Semaphore render_finished; }; -static constexpr auto BUFFERING_COUNT = 2; +namespace { + constexpr auto BUFFERING_COUNT = 2_u32; + constexpr auto POOL_SIZES = array { + gpu::DescriptorPool::Size { .type = gpu::DescriptorType::COMBINED_IMAGE_SAMPLER, .descriptor_count = BUFFERING_COUNT } + }; +} // namespace class Application: public base::Application { public: @@ -48,44 +51,23 @@ class Application: public base::Application { auto init_resources() -> void { // initialilze descriptor pool - static constexpr auto POOL_SIZES = std::array { - gpu::DescriptorPool::Size { .type = gpu::DescriptorType::COMBINED_IMAGE_SAMPLER, - .descriptor_count = BUFFERING_COUNT } - }; - m_descriptor_pool = gpu::DescriptorPool::create(m_device, POOL_SIZES, BUFFERING_COUNT) - .transform_error(monadic::assert("Failed to create descriptor pool")) - .value(); - - // initialize render pass - m_render_pass - = gpu::RenderPass:: - create(m_device, - { .attachments = { { .format = m_swapchain->pixel_format() } }, - .subpasses = { { .bind_point = gpu::PipelineBindPoint::GRAPHICS, - .color_attachment_refs = { { .attachment_id = 0u } } } } }) - .transform_error(monadic::assert("Failed to create render pass")) - .value(); - - const auto window_extent = m_window->extent(); + m_descriptor_pool = TryAssert(gpu::DescriptorPool::create(m_device, POOL_SIZES, BUFFERING_COUNT), + "Failed to create descriptor pool!"); // create present engine resources - m_submission_resources = init_by>([&](auto& out) noexcept { + m_submission_resources = init_by>([&](auto& out) noexcept { out.reserve(BUFFERING_COUNT); for (auto _ : range(BUFFERING_COUNT)) { out.push_back({ - .in_flight = gpu::Fence::create_signaled(m_device) - .transform_error(monadic:: - assert("Failed to create swapchain image " - "in flight fence")) - .value(), - .image_available = gpu::Semaphore::create(m_device) - .transform_error(monadic::assert("Failed to create " - "present wait semaphore")) - .value(), - .render_cmb = m_command_pool->create_command_buffer() - .transform_error(monadic::assert("Failed to create transition " - "command buffers")) - .value(), + .in_flight = TryAssert(gpu::Fence::create_signaled(m_device), + "Failed to create swapchain image " + "in flight fence!"), + .image_available = TryAssert(gpu::Semaphore::create(m_device), + "Failed to create " + "present wait semaphore!"), + .render_cmb = TryAssert(m_command_pool->create_command_buffer(), + "Failed to create transition " + "command buffers!"), }); } }); @@ -93,64 +75,43 @@ class Application: public base::Application { // transition swapchain image to present image const auto& images = m_swapchain->images(); - const auto image_count = stdr::size(images); - auto transition_cmbs - = m_command_pool->create_command_buffers(image_count) - .transform_error(monadic::assert("Failed to create transition command buffers")) - .value(); + const auto image_count = stdr::size(images); + auto transition_cmbs = TryAssert(m_command_pool->create_command_buffers(image_count), + "Failed to create transition command buffers!"); m_image_resources.reserve(stdr::size(images)); auto image_index = 0u; for (const auto& swap_image : images) { - auto view = gpu::ImageView::create(m_device, swap_image) - .transform_error(core::monadic:: - assert("Failed to create swapchain image view")) - .value(); - auto framebuffer = m_render_pass - ->create_frame_buffer(m_device, window_extent, to_refs(view)) - .transform_error(core::monadic::assert( - std::format("Failed to create framebuffer for image {}", - image_index))) - .value(); - - m_image_resources.push_back({ - .image = as_ref(swap_image), - .view = std::move(view), - .framebuffer = std::move(framebuffer), - .render_finished = gpu::Semaphore::create(m_device) - .transform_error(core::monadic::assert("Failed to create render " - "signal semaphore")) - .value(), - }); + auto view = TryAssert(gpu::ImageView::create(m_device, { swap_image }), "Failed to create swapchain image view!"); + + m_image_resources.push_back({ .image = swap_image, + .view = std::move(view), + .render_finished = TryAssert(gpu::Semaphore::create(m_device), + "Failed to create render " + "signal semaphore!") }); auto& transition_cmb = transition_cmbs[image_index]; - *transition_cmb.begin(true) - .transform_error(monadic:: - assert("Failed to begin texture transition command buffer")) - .value() - ->begin_debug_region(std::format("transition image {}", image_index)) - .transition_image_layout(swap_image, - gpu::ImageLayout::UNDEFINED, - gpu::ImageLayout::PRESENT_SRC) - .end_debug_region() - .end() - .transform_error(monadic::assert("Failed to begin texture transition command " - "buffer")); + TryDiscardAssert((transition_cmb.record([&](auto cmb) noexcept { + cmb.begin_debug_region(std::format("Transition image {}", image_index)) + .transition_image_layout(swap_image, + gpu::ImageLayout::UNDEFINED, + gpu::ImageLayout::PRESENT_SRC) + .end_debug_region(); + })), + std::format("Failed to record transition cmb {}!", image_index)); ++image_index; } - const auto fence = gpu::Fence::create(m_device) - .transform_error(monadic::assert("Failed to create transition fence")) - .value(); - const auto cmbs = to_refs(transition_cmbs); + const auto fence = TryAssert(gpu::Fence::create(m_device), "Failed to create transition fence!"); - m_raster_queue->submit({ .command_buffers = cmbs }, as_ref(fence)) - .transform_error(monadic::assert("Failed to submit texture transition command buffers")) - .value(); + const auto cmbs = to_views(transition_cmbs); + + TryAssert(m_raster_queue->submit({ .command_buffers = cmbs }, fence), + "Failed to submit texture transition command buffers!"); // wait for transition to be done - fence.wait().transform_error(monadic::assert()); + TryAssert(fence.wait(), ""); } auto init_imgui() -> void { @@ -160,70 +121,81 @@ class Application: public base::Application { io.DisplaySize.x = m_window->extent().to().width; io.DisplaySize.y = m_window->extent().to().height; + const auto format = gpu::vk::to_vk(m_swapchain->pixel_format()); /*const*/ auto init_info = ImGui_ImplVulkan_InitInfo { - .ApiVersion = VK_API_VERSION_1_1, + .ApiVersion = VK_API_VERSION_1_3, .Instance = m_instance->native_handle(), .PhysicalDevice = m_physical_device->native_handle(), .Device = m_device->native_handle(), .QueueFamily = 0, .Queue = m_raster_queue->native_handle(), .DescriptorPool = m_descriptor_pool->native_handle(), - .RenderPass = m_render_pass->native_handle(), + .DescriptorPoolSize = 0, .MinImageCount = BUFFERING_COUNT, .ImageCount = BUFFERING_COUNT, - .MSAASamples = VK_SAMPLE_COUNT_1_BIT, .PipelineCache = nullptr, - .Subpass = 0, - .DescriptorPoolSize = 0, - .UseDynamicRendering = false, - .PipelineRenderingCreateInfo = {}, + .PipelineInfoMain = { + .RenderPass = nullptr, + .Subpass = {}, + .MSAASamples = {}, + .PipelineRenderingCreateInfo = { + .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, + .pNext = nullptr, + .viewMask = 0, + .colorAttachmentCount = 1, + .pColorAttachmentFormats = &format, + .depthAttachmentFormat = {}, + .stencilAttachmentFormat = {} + + }, + }, + .UseDynamicRendering = true, .Allocator = nullptr, .CheckVkResultFn = [](auto result) static noexcept { - if (result != VK_SUCCESS) elog("{}", gpu::from_vk(result)); + if (result != VK_SUCCESS) elog("{}", gpu::vk::from_vk(result)); }, .MinAllocationSize = 1024 * 1024, + .CustomShaderVertCreateInfo = {}, + .CustomShaderFragCreateInfo = {}, }; - ImGui_ImplVulkan_LoadFunctions(VK_API_VERSION_1_1, gpu::imgui_vk_loader, &*m_device); + ImGui_ImplVulkan_LoadFunctions(VK_API_VERSION_1_1, gpu::vk::imgui_vk_loader, &*m_device); ImGui_ImplVulkan_Init(&init_info); - m_window - ->on(wsi::KeyDownEventFunc { [this, - &io](u8 /*id*/, wsi::Key key, char c) mutable noexcept { - if (key == wsi::Key::ESCAPE) m_window->close(); - io.AddInputCharactersUTF8(&c); - } }, - wsi::MouseMovedEventFunc { - [&io](u8 /*id*/, const math::vec2i& position) mutable noexcept { - const auto _position = position.to(); - - io.AddMouseSourceEvent(ImGuiMouseSource_Mouse); - io.AddMousePosEvent(_position.x, _position.y); - } }, - wsi::MouseButtonDownEventFunc { - [&io](u8 /*id*/, wsi::MouseButton button, const math::vec2i&) mutable noexcept { - auto mouse_button = -1; - if (button == wsi::MouseButton::LEFT) mouse_button = 0; - if (button == wsi::MouseButton::RIGHT) mouse_button = 1; - if (button == wsi::MouseButton::MIDDLE) mouse_button = 2; - if (button == wsi::MouseButton::BUTTON_1) mouse_button = 3; - if (button == wsi::MouseButton::BUTTON_2) mouse_button = 4; - if (mouse_button == -1) return; - io.AddMouseSourceEvent(ImGuiMouseSource_Mouse); - io.AddMouseButtonEvent(mouse_button, true); - } }, - wsi::MouseButtonUpEventFunc { - [&io](u8 /*id*/, wsi::MouseButton button, const math::vec2i&) mutable noexcept { - auto mouse_button = -1; - if (button == wsi::MouseButton::LEFT) mouse_button = 0; - if (button == wsi::MouseButton::RIGHT) mouse_button = 1; - if (button == wsi::MouseButton::MIDDLE) mouse_button = 2; - if (button == wsi::MouseButton::BUTTON_1) mouse_button = 3; - if (button == wsi::MouseButton::BUTTON_2) mouse_button = 4; - if (mouse_button == -1) return; - io.AddMouseSourceEvent(ImGuiMouseSource_Mouse); - io.AddMouseButtonEvent(mouse_button, false); - } }); + m_window->on(wsi::KeyDownEventFunc { [this, &io](u8 /*id*/, wsi::Key key, char c) mutable noexcept { + if (key == wsi::Key::ESCAPE) m_window->close(); + io.AddInputCharactersUTF8(&c); + } }, + wsi::MouseMovedEventFunc { [&io](u8 /*id*/, const math::ivec2& position) mutable noexcept { + const auto _position = position.to(); + + io.AddMouseSourceEvent(ImGuiMouseSource_Mouse); + io.AddMousePosEvent(_position.x, _position.y); + } }, + wsi::MouseButtonDownEventFunc { + [&io](u8 /*id*/, wsi::MouseButton button, const math::ivec2&) mutable noexcept { + auto mouse_button = -1; + if (button == wsi::MouseButton::LEFT) mouse_button = 0; + if (button == wsi::MouseButton::RIGHT) mouse_button = 1; + if (button == wsi::MouseButton::MIDDLE) mouse_button = 2; + if (button == wsi::MouseButton::BUTTON_1) mouse_button = 3; + if (button == wsi::MouseButton::BUTTON_2) mouse_button = 4; + if (mouse_button == -1) return; + io.AddMouseSourceEvent(ImGuiMouseSource_Mouse); + io.AddMouseButtonEvent(mouse_button, true); + } }, + wsi::MouseButtonUpEventFunc { + [&io](u8 /*id*/, wsi::MouseButton button, const math::ivec2&) mutable noexcept { + auto mouse_button = -1; + if (button == wsi::MouseButton::LEFT) mouse_button = 0; + if (button == wsi::MouseButton::RIGHT) mouse_button = 1; + if (button == wsi::MouseButton::MIDDLE) mouse_button = 2; + if (button == wsi::MouseButton::BUTTON_1) mouse_button = 3; + if (button == wsi::MouseButton::BUTTON_2) mouse_button = 4; + if (mouse_button == -1) return; + io.AddMouseSourceEvent(ImGuiMouseSource_Mouse); + io.AddMouseButtonEvent(mouse_button, false); + } }); } auto run_example() { @@ -240,64 +212,55 @@ class Application: public base::Application { const auto& wait = submission_resource.image_available; auto& in_flight = submission_resource.in_flight; - const auto acquire_next_image = bind_front(&gpu::SwapChain::acquire_next_image, - &*m_swapchain, - 100ms, - std::cref(wait)); - const auto extract_index = [](auto&& _result) static noexcept { - auto&& [result, _image_index] = _result; - return _image_index; - }; + TryAssert(in_flight.wait(), "Failed to wait in_flight fence!"); + TryAssert(in_flight.reset(), "Failed to reset in_flight fence!"); - const auto image_index - = in_flight.wait() - .transform([&in_flight](auto&&) mutable noexcept { in_flight.reset(); }) - .and_then(acquire_next_image) - .transform(extract_index) - .transform_error(monadic::assert("Failed to acquire next swapchain image")) - .value(); + const auto&& [_, image_index] = TryAssert(m_swapchain->acquire_next_image(100ms, wait), + "Failed to acquire next swapchain image!"); const auto& swapchain_image_resource = m_image_resources[image_index]; - const auto& framebuffer = swapchain_image_resource.framebuffer; const auto& signal = swapchain_image_resource.render_finished; - static constexpr auto PIPELINE_FLAGS = std::array { - gpu::PipelineStageFlag::COLOR_ATTACHMENT_OUTPUT + static constexpr auto PIPELINE_FLAGS = array { gpu::PipelineStageFlag::COLOR_ATTACHMENT_OUTPUT }; + + const auto window_extent = m_window->extent().to(); + const auto rendering_info = gpu::RenderingInfo { + .render_area = { .x = 0, .y = 0, .width = window_extent.width, .height = window_extent.height }, + .color_attachments = { { .image_view = swapchain_image_resource.view, + .layout = gpu::ImageLayout::ATTACHMENT_OPTIMAL, + .clear_value = gpu::ClearColor { .color = colors::SILVER } } } }; // render in it auto& render_cmb = submission_resource.render_cmb; - render_cmb.reset() - .transform_error(monadic::assert("Failed to reset render command buffer")) - .value() - ->begin() - .transform_error(monadic::assert("Failed to begin render command buffer")) - .value() - ->begin_debug_region("Render imgui") - .begin_render_pass(m_render_pass, framebuffer); - - ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), render_cmb.native_handle()); - - *render_cmb.end_render_pass() - .end_debug_region() - .end() - .transform_error(monadic::assert("Failed to end render command buffer")) - .value() - ->submit(m_raster_queue, - as_refs(wait), - PIPELINE_FLAGS, - as_refs(signal), - as_ref(in_flight)) - .transform_error(monadic::assert("Failed to submit render command buffer")); + TryAssert(render_cmb.reset(), std::format("Failed to reset render cmb {}!", image_index)); + TryDiscardAssert((render_cmb.record([&](auto cmb) noexcept { + cmb + .transition_image_layout(swapchain_image_resource.image, + gpu::ImageLayout::PRESENT_SRC, + gpu::ImageLayout::ATTACHMENT_OPTIMAL) + .begin_debug_region("Render imgui") + .begin_rendering(rendering_info); + + ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmb); + + cmb + .end_rendering() // + .end_debug_region() + .transition_image_layout(swapchain_image_resource.image, + gpu::ImageLayout::ATTACHMENT_OPTIMAL, + gpu::ImageLayout::PRESENT_SRC); + })), + std::format("Failed to record render cmb {}!", image_index)); + + TryDiscardAssert(render_cmb.submit(m_raster_queue, gpu::as_views(wait), PIPELINE_FLAGS, gpu::as_views(signal), in_flight), + "Failed to submit render command buffer"); // present it - auto update_current_frame = [this](auto&&) mutable noexcept { - if (++m_current_frame >= BUFFERING_COUNT) m_current_frame = 0; - }; + TryDiscardAssert(m_raster_queue->present(gpu::as_views(m_swapchain), gpu::as_views(signal), as_view(image_index)), + "Failed to present swapchain image"); - m_raster_queue->present(as_refs(m_swapchain), as_refs(signal), as_view(image_index)) - .transform(update_current_frame) - .transform_error(monadic::assert("Failed to present swapchain image")); + if (++m_current_frame >= BUFFERING_COUNT) m_current_frame = 0; } auto deinit() { @@ -305,17 +268,16 @@ class Application: public base::Application { ImGui::DestroyContext(); } - constexpr auto example_name() const noexcept -> std::string_view { return "Imgui"; } + constexpr auto example_name() const noexcept -> string_view { return "Imgui"; } private: - DeferInit m_render_pass; - DeferInit m_descriptor_pool; - std::vector m_submission_resources; - std::vector m_image_resources; - usize m_current_frame = 0_usize; + DeferInit m_descriptor_pool; + dyn_array m_submission_resources; + dyn_array m_image_resources; + usize m_current_frame = 0_usize; }; -auto main(std::span args) -> int { +auto main(array_view args) -> int { auto app = Application {}; app.run(args); return 0; diff --git a/examples/gpu/imgui/win32/manifest.manifest b/examples/gpu/imgui/win32/manifest.manifest deleted file mode 100644 index 4a9b5f6a6..000000000 --- a/examples/gpu/imgui/win32/manifest.manifest +++ /dev/null @@ -1,9 +0,0 @@ - - - - - true - PerMonitorV2 - - - diff --git a/examples/gpu/imgui/xmake.lua b/examples/gpu/imgui/xmake.lua index b7cfa0a5b..7eca49909 100644 --- a/examples/gpu/imgui/xmake.lua +++ b/examples/gpu/imgui/xmake.lua @@ -3,31 +3,21 @@ add_requires("imgui", { system = false, debug = true, }) -target("imgui", function() - set_kind("binary") - set_languages("cxxlatest", "clatest") - - add_rules("stormkit.flags") - -- add_rules("platform.windows.subsystem.windows") - add_rules("platform.windows.subsystem.console") - add_deps("core", "main", "log", "wsi", "gpu", "stormkit") +target("imgui", function() + add_rules("stormkit::example") - add_packages("imgui") + add_files("src/*.cpp", "src/*.cppm", "../common/app.cppm") - if is_mode("debug") then - add_defines("STORMKIT_BUILD_DEBUG") - add_defines("STORMKIT_ASSERT=1") - set_suffixname("-d") - else - add_defines("STORMKIT_ASSERT=0") + if get_config("devmode") then + add_defines(format('RESOURCE_DIR="%s"', path.unix(path.join(os.projectdir(), "gpu/imgui")))) + add_defines(format('SHADER_DIR="%s"', path.unix("$(builddir)/shader"))) end - - add_files("../common/app.mpp") - add_files("src/*.cpp") - if is_plat("windows") then add_files("win32/*.manifest") end + add_embeddirs("$(builddir)/shaders") if get_config("devmode") then set_rundir("$(projectdir)") end + add_packages("imgui", "volk", "vulkan-headers") + set_group("examples/stormkit-gpu") end) diff --git a/examples/gpu/textured_cube/iOS/Info.plist b/examples/gpu/textured_cube/iOS/Info.plist deleted file mode 100644 index a62a3592d..000000000 --- a/examples/gpu/textured_cube/iOS/Info.plist +++ /dev/null @@ -1,46 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - ${MACOSX_BUNDLE_EXECUTABLE_NAME} - CFBundleGetInfoString - ${MACOSX_BUNDLE_INFO_STRING} - CFBundleIconFile - ${MACOSX_BUNDLE_ICON_FILE} - CFBundleIdentifier - ${MACOSX_BUNDLE_GUI_IDENTIFIER} - CFBundleInfoDictionaryVersion - 6.0 - CFBundleLongVersionString - ${MACOSX_BUNDLE_LONG_VERSION_STRING} - CFBundleName - ${MACOSX_BUNDLE_BUNDLE_NAME} - CFBundlePackageType - APPL - CFBundleShortVersionString - ${MACOSX_BUNDLE_SHORT_VERSION_STRING} - CFBundleSignature - ???? - CFBundleVersion - ${MACOSX_BUNDLE_BUNDLE_VERSION} - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UISupportedInterfaceOrientations - - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - NSHumanReadableCopyright - ${MACOSX_BUNDLE_COPYRIGHT} - - diff --git a/examples/gpu/textured_cube/iOS/LaunchScreen.storyboard b/examples/gpu/textured_cube/iOS/LaunchScreen.storyboard deleted file mode 100644 index 436820912..000000000 --- a/examples/gpu/textured_cube/iOS/LaunchScreen.storyboard +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/examples/gpu/textured_cube/macOS/Info.plist b/examples/gpu/textured_cube/macOS/Info.plist deleted file mode 100644 index f68f66070..000000000 --- a/examples/gpu/textured_cube/macOS/Info.plist +++ /dev/null @@ -1,36 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - ${MACOSX_BUNDLE_EXECUTABLE_NAME} - CFBundleGetInfoString - ${MACOSX_BUNDLE_INFO_STRING} - CFBundleIconFile - ${MACOSX_BUNDLE_ICON_FILE} - CFBundleIdentifier - ${MACOSX_BUNDLE_GUI_IDENTIFIER} - CFBundleInfoDictionaryVersion - 6.0 - CFBundleLongVersionString - ${MACOSX_BUNDLE_LONG_VERSION_STRING} - CFBundleName - ${MACOSX_BUNDLE_BUNDLE_NAME} - CFBundlePackageType - APPL - CFBundleShortVersionString - ${MACOSX_BUNDLE_SHORT_VERSION_STRING} - CFBundleSignature - ???? - CFBundleVersion - ${MACOSX_BUNDLE_BUNDLE_VERSION} - CSResourcesFileMapped - - NSHumanReadableCopyright - ${MACOSX_BUNDLE_COPYRIGHT} - NSHighResolutionCapable - - - diff --git a/examples/gpu/textured_cube/shaders/textured_cube.nzsl b/examples/gpu/textured_cube/shaders/textured_cube.nzsl index 8580764db..0c3dd2ac1 100644 --- a/examples/gpu/textured_cube/shaders/textured_cube.nzsl +++ b/examples/gpu/textured_cube/shaders/textured_cube.nzsl @@ -29,7 +29,7 @@ external { } [entry(vert)] -fn main(input: VertIn) -> VertOut { +fn vert_main(input: VertIn) -> VertOut { let output: VertOut; output.position = viewer.proj * viewer.view * viewer.model * vec4[f32](input.position, 1.); @@ -49,7 +49,7 @@ external { } [entry(frag)] -fn main(input: VertOut) -> FragOut { +fn frag_main(input: VertOut) -> FragOut { let output: FragOut; output.color = texture.Sample(input.uv); diff --git a/examples/gpu/textured_cube/src/logger.cppm b/examples/gpu/textured_cube/src/logger.cppm new file mode 100644 index 000000000..30e39ca8f --- /dev/null +++ b/examples/gpu/textured_cube/src/logger.cppm @@ -0,0 +1,15 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +export module gpu_app:logger; + +import std; + +import stormkit.log; + +export { IN_MODULE_LOGGER("Textured Cube"); } diff --git a/examples/gpu/textured_cube/src/main.cpp b/examples/gpu/textured_cube/src/main.cpp index 7b2566504..1f868809e 100644 --- a/examples/gpu/textured_cube/src/main.cpp +++ b/examples/gpu/textured_cube/src/main.cpp @@ -10,21 +10,21 @@ import stormkit; import gpu_app; #include +#include #include #include -LOGGER("stormkit.examples.gpu.textured_cube"); - #ifndef SHADER_DIR - #define SHADER_DIR "../share/shaders" +static constexpr auto SHADER_DIR "../share/stormkit/shaders/" #endif -#ifndef TEXTURE_DIR - #define TEXTURE_DIR "../share/textures" +#ifndef RESOURCE_DIR + static constexpr auto RESOURCE_DIR "../share/stormkit/" #endif -namespace stdc = std::chrono; -namespace stdr = std::ranges; + namespace stdc = std::chrono; +namespace stdr = std::ranges; +namespace stdfs = std::filesystem; using clock = stdc::high_resolution_clock; @@ -41,151 +41,145 @@ struct SubmissionResource { }; struct SwapchainImageResource { - Ref image; - gpu::ImageView view; - gpu::Image depth_image; - gpu::ImageView depth_view; - gpu::FrameBuffer framebuffer; - gpu::Semaphore render_finished; + gpu::view::Image image; + gpu::ImageView view; + gpu::Image depth_image; + gpu::ImageView depth_view; + gpu::Semaphore render_finished; }; struct Vertex { - math::vec3f position; - math::vec2f uv; - - static constexpr auto attribute_descriptions() noexcept - -> std::array { - return { - gpu::VertexInputAttributeDescription { - 0, 0, - gpu::PixelFormat::RGB32F, - offsetof(Vertex, position) }, - gpu::VertexInputAttributeDescription { - 1, 0, - gpu::PixelFormat::RG32F, - offsetof(Vertex, uv) }, - }; + math::fvec3 position; + math::fvec2 uv; + + static constexpr auto attribute_descriptions() noexcept -> array { + return to_array({ + { .location = 0, .binding = 0, .format = gpu::PixelFormat::RGB32F, .offset = offsetof(Vertex, position) }, + { .location = 1, .binding = 0, .format = gpu::PixelFormat::RG32F, .offset = offsetof(Vertex, uv) } + }); } static constexpr auto binding_description() noexcept -> gpu::VertexBindingDescription { - return { 0, sizeof(Vertex), gpu::VertexInputRate::VERTEX }; + return { .binding = 0, .stride = sizeof(Vertex), .input_rate = gpu::VertexInputRate::VERTEX }; } }; -static constexpr auto VERTICES = std::array { - Vertex { { -1.f, -1.f, -1.f }, { 2.f / 3.f, 3.f / 4.f } }, // -X side - { { -1.f, -1.f, 1.f }, { 1.f / 3.f, 3.f / 4.f } }, - { { -1.f, 1.f, 1.f }, { 1.f / 3.f, 1.f } }, - { { -1.f, 1.f, 1.f }, { 1.f / 3.f, 1.f } }, - { { -1.f, 1.f, -1.f }, { 2.f / 3.f, 1.f } }, - { { -1.f, -1.f, -1.f }, { 2.f / 3.f, 3.f / 4.f } }, - - { { -1.f, -1.f, -1.f }, { 1.f / 3.f, 2.f / 4.f } }, // -Z side - { { 1.f, 1.f, -1.f }, { 0.f, 1.f / 4.f } }, - { { 1.f, -1.f, -1.f }, { 0.f, 2.f / 4.f } }, - { { -1.f, -1.f, -1.f }, { 1.f / 3.f, 2.f / 4.f } }, - { { -1.f, 1.f, -1.f }, { 1.f / 3.f, 1.f / 4.f } }, - { { 1.f, 1.f, -1.f }, { 0.f, 1.f / 4.f } }, - - { { -1.f, -1.f, -1.f }, { 2.f / 3.f, 2.f / 4.f } }, // -Y side - { { 1.f, -1.f, -1.f }, { 2.f / 3.f, 3.f / 4.f } }, - { { 1.f, -1.f, 1.f }, { 1.f / 3.f, 3.f / 4.f } }, - { { -1.f, -1.f, -1.f }, { 2.f / 3.f, 2.f / 4.f } }, - { { 1.f, -1.f, 1.f }, { 1.f / 3.f, 3.f / 4.f } }, - { { -1.f, -1.f, 1.f }, { 1.f / 3.f, 2.f / 4.f } }, - - { { -1.f, 1.f, -1.f }, { 2.f / 3.f, 0.f } }, // +Y side - { { -1.f, 1.f, 1.f }, { 1.f / 3.f, 0.f } }, - { { 1.f, 1.f, 1.f }, { 1.f / 3.f, 1.f / 4.f } }, - { { -1.f, 1.f, -1.f }, { 2.f / 3.f, 0.f } }, - { { 1.f, 1.f, 1.f }, { 1.f / 3.f, 1.f / 4.f } }, - { { 1.f, 1.f, -1.f }, { 2.f / 3.f, 1.f / 4.f } }, - - { { 1.f, 1.f, -1.f }, { 2.f / 3.f, 1.f / 4.f } }, // +X side - { { 1.f, 1.f, 1.f }, { 1.f / 3.f, 1.f / 4.f } }, - { { 1.f, -1.f, 1.f }, { 1.f / 3.f, 2.f / 4.f } }, - { { 1.f, -1.f, 1.f }, { 1.f / 3.f, 2.f / 4.f } }, - { { 1.f, -1.f, -1.f }, { 2.f / 3.f, 2.f / 4.f } }, - { { 1.f, 1.f, -1.f }, { 2.f / 3.f, 1.f / 4.f } }, - - { { -1.f, 1.f, 1.f }, { 2.f / 3.f, 1.f / 4.f } }, // +Z side - { { -1.f, -1.f, 1.f }, { 2.f / 3.f, 2.f / 4.f } }, - { { 1.f, 1.f, 1.f }, { 1.f, 1.f / 4.f } }, - { { -1.f, -1.f, 1.f }, { 2.f / 3.f, 2.f / 4.f } }, - { { 1.f, -1.f, 1.f }, { 1.f, 2.f / 4.f } }, - { { 1.f, 1.f, 1.f }, { 1.f, 1.f / 4.f } }, -}; - struct ViewerData { - math::mat4f proj; - math::mat4f view; - math::mat4f model; + math::fmat4 proj; + math::fmat4 view; + math::fmat4 model; static constexpr auto layout_binding() -> gpu::DescriptorSetLayoutBinding { - return { 0, gpu::DescriptorType::UNIFORM_BUFFER, gpu::ShaderStageFlag::VERTEX, 1 }; + return { .binding = 0, + .type = gpu::DescriptorType::UNIFORM_BUFFER, + .stages = gpu::ShaderStageFlag::VERTEX, + .descriptor_count = 1 }; } }; -static constexpr auto VERTICES_SIZE = sizeof(Vertex) * stdr::size(VERTICES); +namespace { + const auto SHADER = stdfs::path { SHADER_DIR } / "textured_cube.spv"; + const auto TEXTURE = stdfs::path { RESOURCE_DIR } / "textures/cube.png"; + constexpr auto VERTICES = array { + Vertex { { -1.f, -1.f, -1.f }, { 2.f / 3.f, 3.f / 4.f } }, // -X side + { { -1.f, -1.f, 1.f }, { 1.f / 3.f, 3.f / 4.f } }, + { { -1.f, 1.f, 1.f }, { 1.f / 3.f, 1.f } }, + { { -1.f, 1.f, 1.f }, { 1.f / 3.f, 1.f } }, + { { -1.f, 1.f, -1.f }, { 2.f / 3.f, 1.f } }, + { { -1.f, -1.f, -1.f }, { 2.f / 3.f, 3.f / 4.f } }, + + { { -1.f, -1.f, -1.f }, { 1.f / 3.f, 2.f / 4.f } }, // -Z side + { { 1.f, 1.f, -1.f }, { 0.f, 1.f / 4.f } }, + { { 1.f, -1.f, -1.f }, { 0.f, 2.f / 4.f } }, + { { -1.f, -1.f, -1.f }, { 1.f / 3.f, 2.f / 4.f } }, + { { -1.f, 1.f, -1.f }, { 1.f / 3.f, 1.f / 4.f } }, + { { 1.f, 1.f, -1.f }, { 0.f, 1.f / 4.f } }, + + { { -1.f, -1.f, -1.f }, { 2.f / 3.f, 2.f / 4.f } }, // -Y side + { { 1.f, -1.f, -1.f }, { 2.f / 3.f, 3.f / 4.f } }, + { { 1.f, -1.f, 1.f }, { 1.f / 3.f, 3.f / 4.f } }, + { { -1.f, -1.f, -1.f }, { 2.f / 3.f, 2.f / 4.f } }, + { { 1.f, -1.f, 1.f }, { 1.f / 3.f, 3.f / 4.f } }, + { { -1.f, -1.f, 1.f }, { 1.f / 3.f, 2.f / 4.f } }, + + { { -1.f, 1.f, -1.f }, { 2.f / 3.f, 0.f } }, // +Y side + { { -1.f, 1.f, 1.f }, { 1.f / 3.f, 0.f } }, + { { 1.f, 1.f, 1.f }, { 1.f / 3.f, 1.f / 4.f } }, + { { -1.f, 1.f, -1.f }, { 2.f / 3.f, 0.f } }, + { { 1.f, 1.f, 1.f }, { 1.f / 3.f, 1.f / 4.f } }, + { { 1.f, 1.f, -1.f }, { 2.f / 3.f, 1.f / 4.f } }, + + { { 1.f, 1.f, -1.f }, { 2.f / 3.f, 1.f / 4.f } }, // +X side + { { 1.f, 1.f, 1.f }, { 1.f / 3.f, 1.f / 4.f } }, + { { 1.f, -1.f, 1.f }, { 1.f / 3.f, 2.f / 4.f } }, + { { 1.f, -1.f, 1.f }, { 1.f / 3.f, 2.f / 4.f } }, + { { 1.f, -1.f, -1.f }, { 2.f / 3.f, 2.f / 4.f } }, + { { 1.f, 1.f, -1.f }, { 2.f / 3.f, 1.f / 4.f } }, + + { { -1.f, 1.f, 1.f }, { 2.f / 3.f, 1.f / 4.f } }, // +Z side + { { -1.f, -1.f, 1.f }, { 2.f / 3.f, 2.f / 4.f } }, + { { 1.f, 1.f, 1.f }, { 1.f, 1.f / 4.f } }, + { { -1.f, -1.f, 1.f }, { 2.f / 3.f, 2.f / 4.f } }, + { { 1.f, -1.f, 1.f }, { 1.f, 2.f / 4.f } }, + { { 1.f, 1.f, 1.f }, { 1.f, 1.f / 4.f } }, + }; -static constexpr auto BUFFERING_COUNT = 2; + constexpr auto VERTICES_SIZE = sizeof(Vertex) * stdr::size(VERTICES); + constexpr auto BUFFERING_COUNT = 2_u32; + constexpr auto POOL_SIZES = to_array({ + { + .type = gpu::DescriptorType::UNIFORM_BUFFER, + .descriptor_count = BUFFERING_COUNT, + }, + { + .type = gpu::DescriptorType::COMBINED_IMAGE_SAMPLER, + .descriptor_count = BUFFERING_COUNT, + } + }); + + constexpr auto OFFSETS = array { 0_u64 }; + constexpr auto PIPELINE_FLAGS = array { gpu::PipelineStageFlag::COLOR_ATTACHMENT_OUTPUT }; +} // namespace class Application: public base::Application { public: auto init_example() { - static constexpr auto POOL_SIZES = std::array { - gpu::DescriptorPool::Size { - .type = gpu::DescriptorType::UNIFORM_BUFFER, - .descriptor_count = BUFFERING_COUNT, - }, - gpu::DescriptorPool::Size { .type = gpu::DescriptorType::COMBINED_IMAGE_SAMPLER, - .descriptor_count = BUFFERING_COUNT } - }; - m_descriptor_pool = gpu::DescriptorPool::create(m_device, POOL_SIZES, BUFFERING_COUNT * 2) - .transform_error(monadic::assert("Failed to create descriptor pool")) - .value(); + m_descriptor_pool = TryAssert(gpu::DescriptorPool::create(m_device, POOL_SIZES, BUFFERING_COUNT * 2), + "Failed to create descriptor pool!"); // load shaders - m_vertex_shader = gpu::Shader::load_from_file(m_device, - SHADER_DIR "/textured_cube.spv", - gpu::ShaderStageFlag::VERTEX) - .transform_error(monadic::assert("Failed to load vertex shader")) - .value(); - - m_fragment_shader = gpu::Shader::load_from_file(m_device, - SHADER_DIR "/textured_cube.spv", - gpu::ShaderStageFlag::FRAGMENT) - .transform_error(monadic::assert("Failed to load fragment shader")) - .value(); - - m_descriptor_set_layout - = gpu::DescriptorSetLayout:: - create(m_device, - into_dyn_array(ViewerData::layout_binding(), - gpu::DescriptorSetLayoutBinding { - 1, - gpu::DescriptorType::COMBINED_IMAGE_SAMPLER, - gpu::ShaderStageFlag::FRAGMENT, - 1 })) - .transform_error(monadic::assert("Failed to create descriptor set layout")) - .value(); - m_pipeline_layout = gpu::PipelineLayout::create( - m_device, - { .descriptor_set_layouts = to_refs(m_descriptor_set_layout) }) - .transform_error(monadic::assert("Failed to create pipeline layout")) - .value(); + m_vertex_shader = TryAssert(gpu::Shader::load_from_file(m_device, SHADER, gpu::ShaderStageFlag::VERTEX), + std::format("Failed to load vertex shader {}!", SHADER.string())); + + m_fragment_shader = TryAssert(gpu::Shader::load_from_file(m_device, SHADER, gpu::ShaderStageFlag::FRAGMENT), + std::format("Failed to load fragment shader {}!", SHADER.string())); + + m_descriptor_set_layout = TryAssert(gpu::DescriptorSetLayout:: + create(m_device, + into_dyn_array(ViewerData::layout_binding(), + gpu::DescriptorSetLayoutBinding { + 1, + gpu::DescriptorType::COMBINED_IMAGE_SAMPLER, + gpu::ShaderStageFlag::FRAGMENT, + 1 })), + "Failed to create descriptor set layout!"); + + m_pipeline_layout = TryAssert(gpu::PipelineLayout:: + create(m_device, + gpu::RasterPipelineLayout { + .descriptor_set_layouts = gpu::to_views(m_descriptor_set_layout) }), + "Failed to create pipeline layout!"); // initialize render pass const auto depth_format = [this] { const auto formats_properties = m_physical_device->formats_properties(); - const auto candidates = std::array { gpu::PixelFormat::DEPTH32F, - gpu::PixelFormat::DEPTH32F_STENCIL8U, - gpu::PixelFormat::DEPTH24_UNORM_STENCIL8U }; + const auto candidates = array { gpu::PixelFormat::DEPTH32F, + gpu::PixelFormat::DEPTH32F_STENCIL8U, + gpu::PixelFormat::DEPTH24_UNORM_STENCIL8U }; for (const auto format : candidates) { - const auto properties = stdr::find_if(formats_properties, - [format](const auto& pair) { - return pair.first == format; - }); + const auto properties = stdr::find_if(formats_properties, [format](const auto& pair) { + return pair.first == format; + }); ENSURES(properties != stdr::cend(formats_properties)); if (check_flag_bit(properties->second.optimal_tiling_features, gpu::FormatFeatureFlag::DEPTH_STENCIL_ATTACHMENT)) { @@ -193,7 +187,7 @@ class Application: public base::Application { } } - ensures(false, "No supported depth format found !"); + ensures(false, "No supported depth format found!"); std::unreachable(); }(); @@ -203,20 +197,6 @@ class Application: public base::Application { return flag; }(); - m_render_pass - = gpu::RenderPass:: - create(m_device, - { .attachments = { { - .format = m_swapchain->pixel_format(), - }, { - .format = depth_format, - .destination_layout = gpu::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL - }}, - .subpasses = { gpu::Subpass{ .bind_point = gpu::PipelineBindPoint::GRAPHICS, - .color_attachment_refs = { { .attachment_id = 0u }, }, .depth_attachment_ref = gpu::Subpass::Ref{.attachment_id = 1u, .layout = gpu::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL, }, }, }, }) - .transform_error(monadic::assert("Failed to create render pass")) - .value(); - // initialize render pipeline const auto window_extent = m_window->extent(); const auto window_viewport = gpu::Viewport { @@ -230,159 +210,125 @@ class Application: public base::Application { }; const auto state = gpu::RasterPipelineState { - .input_assembly_state = { .topology = gpu::PrimitiveTopology::TRIANGLE_LIST, }, - .viewport_state = { .viewports = { window_viewport }, - .scissors = { scissor }, }, - .rasterization_state = { - .cull_mode = gpu::CullModeFlag::BACK, - .front_face = gpu::FrontFace::CLOCKWISE, - }, - .color_blend_state - = { .attachments = { { .blend_enable = true, - .src_color_blend_factor = gpu::BlendFactor::SRC_ALPHA, - .dst_color_blend_factor = gpu::BlendFactor::ONE_MINUS_SRC_ALPHA, - .src_alpha_blend_factor = gpu::BlendFactor::SRC_ALPHA, - .dst_alpha_blend_factor = gpu::BlendFactor::ONE_MINUS_SRC_ALPHA, - .alpha_blend_operation = gpu::BlendOperation::ADD, }, }, }, - .shader_state = to_refs(m_vertex_shader, m_fragment_shader), - .vertex_input_state = { - .binding_descriptions = into_dyn_array(Vertex::binding_description()), - .input_attribute_descriptions = to_dyn_array(Vertex::attribute_descriptions()), - }, - .depth_stencil_state = { - .depth_test_enable = true, - .depth_write_enable = true - }, - }; + .input_assembly_state = { .topology = gpu::PrimitiveTopology::TRIANGLE_LIST, }, + .viewport_state = { .viewports = { window_viewport }, + .scissors = { scissor }, }, + .rasterization_state = { + .cull_mode = gpu::CullModeFlag::BACK, + .front_face = gpu::FrontFace::CLOCKWISE, + }, + .color_blend_state + = { .attachments = { { .blend_enable = true, + .src_color_blend_factor = gpu::BlendFactor::SRC_ALPHA, + .dst_color_blend_factor = gpu::BlendFactor::ONE_MINUS_SRC_ALPHA, + .src_alpha_blend_factor = gpu::BlendFactor::SRC_ALPHA, + .dst_alpha_blend_factor = gpu::BlendFactor::ONE_MINUS_SRC_ALPHA, + .alpha_blend_operation = gpu::BlendOperation::ADD, }, }, }, + .shader_state = to_views(m_vertex_shader, m_fragment_shader), + .vertex_input_state = { + .binding_descriptions = into_dyn_array(Vertex::binding_description()), + .input_attribute_descriptions = to_dyn_array(Vertex::attribute_descriptions()), + }, + .depth_stencil_state = { + .depth_test_enable = true, + .depth_write_enable = true + }, + }; + + const auto rendering_info = gpu::RasterPipelineRenderingInfo { + .color_attachment_formats = { m_swapchain->pixel_format() }, + .depth_attachment_format = depth_format, + }; - m_pipeline = gpu::Pipeline::create(m_device, state, m_pipeline_layout, m_render_pass) - .transform_error(monadic::assert("Failed to create raster pipeline")) - .value(); + m_pipeline = TryAssert(gpu::Pipeline::create(m_device, + gpu::Pipeline::RasterizationCreateInfo { .state = as_ref(state), + .layout = m_pipeline_layout, + .rendering_info = rendering_info }), + "Failed to create raster pipeline!"); // load texture auto image = image::Image {}; - image.load_from_file(TEXTURE_DIR "/cube.png").transform_error(monadic::assert()).value(); + TryAssert(image.load_from_file(TEXTURE), std::format("Failed to load texture file {}!", TEXTURE.string())); - m_texture = gpu::Image::create(m_device, - { .extent = image.extent(), - .format = gpu::PixelFormat::RGBA8_UNORM, - .usages = gpu::ImageUsageFlag::SAMPLED - | gpu::ImageUsageFlag::TRANSFER_DST, - .property = gpu::MemoryPropertyFlag::DEVICE_LOCAL }) - .transform_error(monadic::assert("Failed to allocate texture")) - .value(); + m_texture = TryAssert(gpu::Image::create(m_device, + { .extent = image.extent(), + .format = gpu::PixelFormat::RGBA8_UNORM, + .usages = gpu::ImageUsageFlag::SAMPLED | gpu::ImageUsageFlag::TRANSFER_DST, + .properties = gpu::MemoryPropertyFlag::DEVICE_LOCAL }), + "Failed to allocate texture!"); { - auto staging_buffer - = gpu::Buffer::create(m_device, - { .usages = gpu::BufferUsageFlag::TRANSFER_SRC, - .size = image.size() }) - .transform_error(monadic::assert("Failed to allocate gpu texture staging buffer")) - .value(); - - staging_buffer.upload(image.data()) - .transform_error(monadic::assert("Failed to upload texture data to staging buffer")) - .value(); - - auto - cpy_fence = gpu::Fence::create(m_device) - .transform_error(monadic:: - assert("Failed to create copy texture buffer fence")) - .value(); - - const auto copy = { - gpu::BufferImageCopy { - .buffer_offset = 0, - .buffer_row_length = 0, - .buffer_image_height = 0, - .subresource_layers = {}, - .offset = {}, - .extent = image.extent() } - }; - auto copy_cmb = m_command_pool->create_command_buffer() - .transform_error(monadic:: - assert("Failed to allocate copy texture buffer " - "commandbuffer")) - .value(); - - copy_cmb.begin() - .transform_error(monadic::assert("Failed to begin texture upload command buffer")) - .value() - ->begin_debug_region("Upload texture data") - .transition_image_layout(m_texture, - gpu::ImageLayout::UNDEFINED, - gpu::ImageLayout::TRANSFER_DST_OPTIMAL) - .copy_buffer_to_image(staging_buffer, m_texture, as_view(copy)) - .transition_image_layout(m_texture, - gpu::ImageLayout::TRANSFER_DST_OPTIMAL, - gpu::ImageLayout::SHADER_READ_ONLY_OPTIMAL) - .end_debug_region() - .end() - .transform_error(monadic::assert("Failed to end texture upload command buffer")) - .value() - ->submit(m_raster_queue, {}, {}, {}, as_ref(cpy_fence)) - .transform_error(monadic::assert("Failed to submit texture upload command buffer")) - .value(); - - *cpy_fence.wait().transform_error(monadic::assert()); + auto cpy_fence = TryAssert(gpu::Fence::create(m_device), "Failed to create copy texture buffer fence!"); + auto staging_buffer = TryAssert(gpu::Buffer::create(m_device, + { .usages = gpu::BufferUsageFlag::TRANSFER_SRC, + .size = image.size() }), + "Failed to allocate gpu texture staging buffer!"); + TryAssert(staging_buffer.upload(image.data()), "Failed to upload texture data to staging buffer!"); + + auto copy_cmb = TryAssert(m_command_pool->create_command_buffer(), "Failed to allocate copy texture buffer"); + TryDiscardAssert((copy_cmb.record([&](auto cmb) noexcept { + const auto copy = array { + gpu::BufferImageCopy { + .buffer_offset = 0, + .buffer_row_length = 0, + .buffer_image_height = 0, + .subresource_layers = {}, + .offset = {}, + .extent = image.extent() } + }; + + cmb.begin_debug_region("Upload texture data") + .transition_image_layout(m_texture, + gpu::ImageLayout::UNDEFINED, + gpu::ImageLayout::TRANSFER_DST_OPTIMAL) + .copy_buffer_to_image(staging_buffer, m_texture, copy) + .end_debug_region() + .begin_debug_region("Transition texture data") + .transition_image_layout(m_texture, + gpu::ImageLayout::TRANSFER_DST_OPTIMAL, + gpu::ImageLayout::SHADER_READ_ONLY_OPTIMAL) + .end_debug_region(); + })), + "Failed to record texture upload and transition cmb!"); + + TryDiscardAssert(copy_cmb.submit(m_raster_queue, {}, {}, {}, cpy_fence), + "Failed to submit texture upload command buffer!"); + + TryDiscardAssert(cpy_fence.wait(), "Failed to create texture view!"); } - m_texture_view = gpu::ImageView::create(m_device, m_texture) - .transform_error(monadic::assert("Failed to create texture view")) - .value(); - - m_sampler = gpu::Sampler::create(m_device, {}) - .transform_error(monadic::assert("Failed to create sampler")) - .value(); - - // create present engine resources - m_submission_resources = std::vector {}; + m_texture_view = TryAssert(gpu::ImageView::create(m_device, { m_texture }), "Failed to create texture view!"); + m_sampler = TryAssert(gpu::Sampler::create(m_device, {}), "Failed to create sampler!"); + m_submission_resources = dyn_array {}; m_submission_resources.reserve(BUFFERING_COUNT); for (auto _ : range(BUFFERING_COUNT)) { - m_submission_resources.push_back({ - .in_flight = gpu::Fence::create_signaled(m_device) - .transform_error(core::monadic:: - assert("Failed to create swapchain image " - "in flight fence")) - .value(), - .image_available = gpu::Semaphore::create(m_device) - .transform_error(core::monadic:: - assert("Failed to create present " - "wait semaphore")) - .value(), - .render_cmb = m_command_pool->create_command_buffer() - .transform_error(monadic::assert("Failed to create " - "transition command " - "buffers")) - .value(), - .viewer_buffer = gpu::Buffer::create(m_device, - { - .usages = gpu::BufferUsageFlag::UNIFORM, - .size = sizeof(ViewerData), - }, - true) - .transform_error(monadic:: - assert("Failed to allocate gpu viewer buffer")) - .value(), - .descriptor_set = m_descriptor_pool->create_descriptor_set(m_descriptor_set_layout) - .transform_error(monadic:: - assert("Failed to create descriptor set")) - .value(), - }); + m_submission_resources.push_back( + { .in_flight = TryAssert(gpu::Fence::create_signaled(m_device), "Failed to create swapchain image!"), + .image_available = TryAssert(gpu::Semaphore::create(m_device), "Failed to create present image!"), + .render_cmb = TryAssert(m_command_pool->create_command_buffer(), "Failed to create buffers!"), + .viewer_buffer = TryAssert(gpu::Buffer::create(m_device, + { + .usages = gpu::BufferUsageFlag::UNIFORM, + .size = sizeof(ViewerData), + .persistently_mapped = true, + }), + "Failed to allocate gpu viewer buffer!"), + .descriptor_set = TryAssert(m_descriptor_pool->create_descriptor_set(m_descriptor_set_layout), + "Failed to create descriptor set!") }); auto& res = m_submission_resources.back(); - const auto sets = std::array { + const auto sets = array { gpu::BufferDescriptor { .binding = 0, - .buffer = as_ref(res.viewer_buffer), + .buffer = res.viewer_buffer, .range = sizeof(ViewerData), .offset = 0, }, gpu::ImageDescriptor { .binding = 1, .layout = gpu::ImageLayout::SHADER_READ_ONLY_OPTIMAL, - .image_view = as_ref(m_texture_view), - .sampler = as_ref(m_sampler), + .image_view = m_texture_view, + .sampler = m_sampler, } }; res.descriptor_set.update(sets); @@ -390,163 +336,112 @@ class Application: public base::Application { const auto& images = m_swapchain->images(); - const auto image_count = stdr::size(images); - auto transition_cmbs - = m_command_pool->create_command_buffers(image_count) - .transform_error(monadic::assert("Failed to create transition command buffers")) - .value(); + const auto image_count = stdr::size(images); + auto transition_cmbs = TryAssert(m_command_pool->create_command_buffers(image_count), + "Failed to create transition command buffers!"); - m_image_resources = std::vector {}; + m_image_resources = dyn_array {}; m_image_resources.reserve(stdr::size(images)); auto image_index = 0u; for (const auto& swap_image : images) { - auto view = gpu::ImageView::create(m_device, swap_image) - .transform_error(core::monadic:: - assert("Failed to create swapchain image view")) - .value(); - - auto depth_image - = gpu::Image::create(m_device, - gpu::Image::CreateInfo { - .extent = swap_image.extent(), - .format = depth_format, - .usages = gpu::ImageUsageFlag::DEPTH_STENCIL_ATTACHMENT, - .property = gpu::MemoryPropertyFlag::DEVICE_LOCAL }) - .transform_error(core::monadic::assert("Failed to create depth image")) - .value(); - - auto depth_view = gpu::ImageView::create(m_device, - depth_image, - gpu::ImageViewType::T2D, - { .aspect_mask = depth_aspect_flag }) - .transform_error(core::monadic:: - assert("Failed to create depth image view")) - .value(); - - auto framebuffer = m_render_pass - ->create_frame_buffer(m_device, - window_extent, - to_refs(view, depth_view)) - .transform_error(core::monadic::assert( - std::format("Failed to create framebuffer for image {}", - image_index))) - .value(); - - m_image_resources.push_back({ - .image = as_ref(swap_image), - .view = std::move(view), - .depth_image = std::move(depth_image), - .depth_view = std::move(depth_view), - .framebuffer = std::move(framebuffer), - .render_finished = gpu::Semaphore::create(m_device) - .transform_error(core::monadic::assert("Failed to create render " - "signal semaphore")) - .value(), - }); + auto view = TryAssert(gpu::ImageView::create(m_device, { swap_image }), "Failed to create swapchain image view!"); + auto depth_image = TryAssert(gpu::Image::create(m_device, + { .extent = swap_image.extent(), + .format = depth_format, + .usages = gpu::ImageUsageFlag::DEPTH_STENCIL_ATTACHMENT, + .properties = gpu::MemoryPropertyFlag::DEVICE_LOCAL }), + "Failed to create depth image!"); + + auto depth_view = TryAssert(gpu::ImageView::create(m_device, + { .image = depth_image, + .subresource_range = gpu:: + ImageSubresourceRange { .aspect_mask = depth_aspect_flag } }), + "Failed to create depth image view!"); + + m_image_resources.push_back({ .image = swap_image, + .view = std::move(view), + .depth_image = std::move(depth_image), + .depth_view = std::move(depth_view), + .render_finished = TryAssert(gpu::Semaphore::create(m_device), + "Failed to create render!") }); const auto& resources = m_image_resources.back(); auto& transition_cmb = transition_cmbs[image_index]; - *transition_cmb.begin(true) - .transform_error(monadic:: - assert("Failed to begin texture transition command buffer")) - .value() - ->begin_debug_region(std::format("transition image {}", image_index)) - .transition_image_layout(swap_image, - gpu::ImageLayout::UNDEFINED, - gpu::ImageLayout::PRESENT_SRC) - .transition_image_layout(resources.depth_image, - gpu::ImageLayout::UNDEFINED, - gpu::ImageLayout::DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - { .aspect_mask = depth_aspect_flag }) - .end_debug_region() - .end() - .transform_error(monadic:: - assert("Failed to begin texture transition command buffer")) - .transform(monadic::discard()); + TryDiscardAssert((transition_cmb.record([&](auto cmb) noexcept { + cmb.begin_debug_region(std::format("Transition image {}", image_index)) + .transition_image_layout(swap_image, + gpu::ImageLayout::UNDEFINED, + gpu::ImageLayout::PRESENT_SRC) + .end_debug_region() + .begin_debug_region(std::format("Transition depth image {}", image_index)) + .transition_image_layout(resources.depth_image, + gpu::ImageLayout::UNDEFINED, + gpu::ImageLayout::ATTACHMENT_OPTIMAL, + { .aspect_mask = depth_aspect_flag }) + .end_debug_region(); + })), + std::format("Failed to record transition cmb {}!", image_index)); ++image_index; } - const auto fence = gpu::Fence::create(m_device) - .transform_error(monadic::assert("Failed to create transition fence")) - .value(); + const auto fence = TryAssert(gpu::Fence::create(m_device), "Failed to create transition fence!"); - const auto cmbs = to_refs(transition_cmbs); - m_raster_queue->submit({ .command_buffers = cmbs }, as_ref(fence)) - .transform_error(monadic::assert("Failed to submit texture transition command buffers")) - .value(); + const auto cmbs = to_views(transition_cmbs); + TryDiscardAssert(m_raster_queue->submit({ .command_buffers = cmbs }, fence), + "Failed to submit texture transition command buffers!"); // setup vertex buffer - m_vertex_buffer = gpu::Buffer::create(m_device, - { .usages = gpu::BufferUsageFlag::VERTEX - | gpu::BufferUsageFlag::TRANSFER_DST, - .size = VERTICES_SIZE, - .property = gpu::MemoryPropertyFlag::DEVICE_LOCAL }) - .transform_error(monadic:: - assert("Failed to allocate gpu vertex buffer")) - .value(); + m_vertex_buffer = TryAssert(gpu::Buffer::create(m_device, + { .usages = gpu::BufferUsageFlag::VERTEX + | gpu::BufferUsageFlag::TRANSFER_DST, + .size = VERTICES_SIZE, + .properties = gpu::MemoryPropertyFlag::DEVICE_LOCAL }), + "Failed to allocate gpu vertex buffer!"); { - auto staging_buffer - = gpu::Buffer::create(m_device, - { .usages = gpu::BufferUsageFlag::TRANSFER_SRC, - .size = VERTICES_SIZE }) - .transform_error(monadic::assert("Failed to allocate gpu vertex staging buffer")) - .value(); - - staging_buffer.upload(VERTICES) - .transform_error(monadic::assert("Failed to upload vertex data to staging buffer")) - .value(); - - auto - cpy_fence = gpu::Fence::create(m_device) - .transform_error(monadic:: - assert("Failed to create copy vertex buffer fence")) - .value(); - - auto - copy_cmb = m_command_pool->create_command_buffer() - .transform_error(monadic::assert("Failed to allocate copy vertex buffer " - "commandbuffer")) - .value(); - - copy_cmb.begin() - .transform_error(monadic::assert("Failed to begin vertices upload command buffer")) - .value() - ->begin_debug_region("Upload vertex data to vertex buffer") + auto staging_buffer = TryAssert(gpu::Buffer::create(m_device, + { .usages = gpu::BufferUsageFlag::TRANSFER_SRC, + .size = VERTICES_SIZE }), + "Failed to allocate gpu vertex staging buffer!"); + + TryAssert(staging_buffer.upload(VERTICES), "Failed to upload vertex data to staging buffer!"); + + auto cpy_fence = TryAssert(gpu::Fence::create(m_device), "Failed to create copy vertex buffer fence!"); + + auto copy_cmb = TryAssert(m_command_pool->create_command_buffer(), "Failed to allocate copy vertex buffer"); + TryAssert(copy_cmb.begin(), "Failed to begin vertices upload command buffer"); + + copy_cmb.begin_debug_region("Upload vertex data to vertex buffer") .copy_buffer(staging_buffer, m_vertex_buffer, VERTICES_SIZE) - .end_debug_region() - .end() - .transform_error(monadic::assert("Failed to begin vertices upload command buffer")) - .value() - ->submit(m_raster_queue, {}, {}, {}, as_ref(cpy_fence)); + .end_debug_region(); - cpy_fence.wait().transform_error(monadic::assert()); + TryDiscardAssert(copy_cmb.end(), "Failed to begin vertices upload command buffer"); + TryDiscardAssert(copy_cmb.submit(m_raster_queue, {}, {}, {}, cpy_fence), + "Failed to submit vertices upload command buffer!"); + TryAssert(cpy_fence.wait(), "Failed to acquire next swapchain image!"); } - // wait for transition to be done - fence.wait().transform_error(monadic::assert()); + TryAssert(fence.wait(), ""); } auto run_example() { - using SecondF = stdc::duration; + LOG_MODULE.flush(); + + const auto current_time = clock::now(); + const auto window_extent = m_window->extent(); const auto window_extent_f32 = window_extent.to(); auto viewer_data = ViewerData { - .proj = math::perspective(math::radians(45.f), + .proj = math::perspective(math::angle::radians(45.f), window_extent_f32.width / window_extent_f32.height, 0.1f, 100.f), - .view = math::look_at(math::vec3f { 0.f, 3.f, 5.f }, - { 0.f, 0.f, 0.f }, - { 0.f, 1.f, 0.f }), - .model = math::mat4f::identity(), + .view = math::look_at(math::fvec3 { 0.f, 3.f, 5.f }, { 0.f, 0.f, 0.f }, { 0.f, 1.f, 0.f }), + .model = math::fmat4::identity(), }; - LOG_MODULE.flush(); - - const auto current_time = clock::now(); // get next swapchain image auto& submission_resource = m_submission_resources[m_current_frame]; @@ -554,89 +449,68 @@ class Application: public base::Application { const auto& wait = submission_resource.image_available; auto& in_flight = submission_resource.in_flight; - const auto acquire_next_image = bind_front(&gpu::SwapChain::acquire_next_image, - &*m_swapchain, - 100ms, - std::cref(wait)); - const auto extract_index = [](auto&& _result) static noexcept { - auto&& [result, _image_index] = _result; - return _image_index; - }; + TryAssert(in_flight.wait(), "Failed to wait in_flight fence!"); + TryAssert(in_flight.reset(), "Failed to reset in_flight fence!"); - const auto - image_index = in_flight.wait() - .transform([&in_flight](auto&&) noexcept { in_flight.reset(); }) - .and_then(acquire_next_image) - .transform(extract_index) - .transform_error(monadic:: - assert("Failed to acquire next swapchain image")) - .value(); + const auto&& [_, image_index] = TryAssert(m_swapchain->acquire_next_image(100ms, wait), + "Failed to acquire next swapchain image!"); const auto& swapchain_image_resource = m_image_resources[image_index]; - const auto& framebuffer = swapchain_image_resource.framebuffer; const auto& signal = swapchain_image_resource.render_finished; // update viewer data and upload - const auto time = stdc::duration_cast(current_time - m_start_time).count(); - viewer_data.model = math::rotate(math::mat4f::identity(), - time * math::radians(90.f), - math::vec3f { 0.f, 1.f, 0.f }); + const auto time = stdc::duration_cast(current_time - m_start_time).count(); + viewer_data.model = math::transpose(math::rotate(math::fmat4::identity(), + time * math::angle::radians(90.f), + math::fvec3 { 0.f, 1.f, 0.f })); auto& viewer_buffer = submission_resource.viewer_buffer; - viewer_buffer.upload(viewer_data); + TryAssert(viewer_buffer.upload(viewer_data), "Failed to upload texture to gpu!"); + + const auto rendering_info = gpu::RenderingInfo { + .render_area = { .x = 0, .y = 0, .width = window_extent.to().width, .height = window_extent.to().height }, + .color_attachments = { { .image_view = swapchain_image_resource.view, + .layout = gpu::ImageLayout::ATTACHMENT_OPTIMAL, + .clear_value = gpu::ClearColor { .color = colors::SILVER } } }, + .depth_attachment = { { .image_view = swapchain_image_resource.depth_view, + .layout = gpu::ImageLayout::ATTACHMENT_OPTIMAL, + .clear_value = gpu::ClearDepthStencil {} } } + }; // render in it auto& render_cmb = submission_resource.render_cmb; const auto& descriptor_set = submission_resource.descriptor_set; - static constexpr auto CLEAR_VALUES = std::array { - gpu::ClearColor { .color = RGBColorDef::SILVER }, - gpu::ClearDepthStencil {} - }; - static constexpr auto OFFSETS = std::array { 0_u64 }; - static constexpr auto PIPELINE_FLAGS = std::array { - gpu::PipelineStageFlag::COLOR_ATTACHMENT_OUTPUT - }; - - render_cmb.reset() - .transform_error(monadic::assert("Failed to reset render command buffer")) - .value() - ->begin() - .transform_error(monadic::assert("Failed to begin render command buffer")) - .value() - ->begin_debug_region("Render textured cube") - .begin_render_pass(m_render_pass, framebuffer, CLEAR_VALUES) - .bind_pipeline(m_pipeline) - .bind_vertex_buffers(to_refs(m_vertex_buffer), OFFSETS) - .bind_descriptor_sets(m_pipeline, m_pipeline_layout, as_refs(descriptor_set), {}) - .draw(stdr::size(VERTICES)) - .end_render_pass() - .end_debug_region() - .end() - .transform_error(monadic::assert("Failed to end render command buffer")) - .value() - ->submit(m_raster_queue, - as_refs(wait), - PIPELINE_FLAGS, - as_refs(signal), - as_ref(in_flight)) - .transform_error(monadic::assert("Failed to submit render command buffer")) - .value(); + TryAssert(render_cmb.reset(), std::format("Failed to reset render cmb {}!", image_index)); + TryDiscardAssert((render_cmb.record([&](auto cmb) noexcept { + cmb + .transition_image_layout(swapchain_image_resource.image, + gpu::ImageLayout::PRESENT_SRC, + gpu::ImageLayout::ATTACHMENT_OPTIMAL) + .begin_debug_region("Render cube") + .begin_rendering(rendering_info) + .bind_pipeline(m_pipeline) + .bind_vertex_buffers(gpu::as_views(m_vertex_buffer), OFFSETS) + .bind_descriptor_sets(m_pipeline, m_pipeline_layout, gpu::as_views(descriptor_set), {}) + .draw(stdr::size(VERTICES)) + .end_rendering() + .end_debug_region() + .transition_image_layout(swapchain_image_resource.image, + gpu::ImageLayout::ATTACHMENT_OPTIMAL, + gpu::ImageLayout::PRESENT_SRC); + })), + std::format("Failed to record render cmb {}!", image_index)); + TryDiscardAssert(render_cmb.submit(m_raster_queue, gpu::as_views(wait), PIPELINE_FLAGS, gpu::as_views(signal), in_flight), + "Failed to submit render command buffer!"); // present it - auto update_current_frame = [this](auto&&) mutable noexcept { - if (++m_current_frame >= BUFFERING_COUNT) m_current_frame = 0; - }; - - m_raster_queue->present(as_refs(m_swapchain), as_refs(signal), as_view(image_index)) - .transform(update_current_frame) - .transform_error(monadic::assert("Failed to present swapchain image")); + TryAssert(m_raster_queue->present(gpu::as_views(m_swapchain), gpu::as_views(signal), as_view(image_index)), + "Failed to present swapchain image!"); - m_raster_queue->wait_idle(); - m_device->wait_idle(); + if (++m_current_frame >= BUFFERING_COUNT) m_current_frame = 0; } - constexpr auto example_name() const noexcept -> std::string_view { return "Textured Cube"; } + constexpr auto example_name() const noexcept -> string_view { return "Textured Cube"; } private: DeferInit m_descriptor_pool; @@ -645,19 +519,18 @@ class Application: public base::Application { DeferInit m_fragment_shader; DeferInit m_descriptor_set_layout; DeferInit m_pipeline_layout; - DeferInit m_render_pass; DeferInit m_pipeline; DeferInit m_texture; DeferInit m_texture_view; DeferInit m_sampler; - std::vector m_submission_resources; - std::vector m_image_resources; + dyn_array m_submission_resources; + dyn_array m_image_resources; DeferInit m_vertex_buffer; usize m_current_frame = 0_usize; decltype(clock::now()) m_start_time = clock::now(); }; -auto main(std::span args) -> int { +auto main(array_view args) -> int { auto app = Application {}; app.run(args); return 0; diff --git a/examples/gpu/textured_cube/win32/manifest.manifest b/examples/gpu/textured_cube/win32/manifest.manifest deleted file mode 100644 index 4a9b5f6a6..000000000 --- a/examples/gpu/textured_cube/win32/manifest.manifest +++ /dev/null @@ -1,9 +0,0 @@ - - - - - true - PerMonitorV2 - - - diff --git a/examples/gpu/textured_cube/xmake.lua b/examples/gpu/textured_cube/xmake.lua index f16e33fd1..748a76f2e 100644 --- a/examples/gpu/textured_cube/xmake.lua +++ b/examples/gpu/textured_cube/xmake.lua @@ -1,47 +1,28 @@ -if is_plat("linux") then - add_requires( - "nzsl", - { configs = { toolchains = "gcc", runtimes = "stdc++_shared", fs_watcher = false, link = {} } } - ) -elseif is_plat("windows") then - add_requires("nzsl", { configs = { toolchains = "msvc", runtimes = "MD", fs_watcher = false, links = {} } }) -else - add_requires("nzsl", { configs = { fs_watcher = false, links = {} } }) +local runtimes +local toolchain +if is_plat("windows") then + runtimes = "MD" + toolchain = "msvc" +elseif is_plat("linux") then + runtimes = "stdc++_shared" + toolchain = "gcc" end +add_requires("nzsl", { configs = { fs_watcher = false, kind = "binary", toolchains = toolchain, runtimes = runtimes } }) target("textured_cube", function() - set_kind("binary") - set_languages("cxxlatest", "clatest") + add_rules("stormkit::example", "compile.shaders") - add_rules("stormkit.flags") - add_rules("platform.windows.subsystem.console") - -- add_rules("platform.windows.subsystem.windows") - - add_rules("compile.shaders") - add_deps("core", "main", "log", "wsi", "gpu", "stormkit") - - if is_mode("debug") then - add_defines("STORMKIT_BUILD_DEBUG") - add_defines("STORMKIT_ASSERT=1") - set_suffixname("-d") - else - add_defines("STORMKIT_ASSERT=0") - end - - add_files("src/*.cpp", "../common/app.mpp") - add_files("shaders/*.nzsl") - if is_plat("windows") then add_files("win32/*.manifest") end - - add_includedirs("$(builddir)/shaders") + add_files("src/*.cpp", "src/*.cppm", "../common/app.cppm", "shaders/*.nzsl") if get_config("devmode") then - add_defines('SHADER_DIR="$(builddir)/shaders"') - add_defines('TEXTURE_DIR="$(builddir)/textures"') - set_rundir("$(projectdir)") + add_defines(format('RESOURCE_DIR="%s"', path.unix(path.join(os.projectdir(), "examples/gpu/textured_cube")))) + add_defines(format('SHADER_DIR="%s"', path.unix("$(builddir)/shaders"))) end + add_embeddirs("$(builddir)/shaders") + + if get_config("devmode") then set_rundir("$(projectdir)") end - -- add_cxflags("--embed-dir=$(builddir)/shaders", {tools = {"clang", "clangxx", "clang-cl", "gcc", "gxx"}}) - after_build(function(target) os.cp("examples/gpu/textured_cube/textures/", "$(builddir)") end) + add_packages("nzsl") set_group("examples/stormkit-gpu") end) diff --git a/examples/gpu/triangle/iOS/Info.plist b/examples/gpu/triangle/iOS/Info.plist deleted file mode 100644 index a62a3592d..000000000 --- a/examples/gpu/triangle/iOS/Info.plist +++ /dev/null @@ -1,46 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - ${MACOSX_BUNDLE_EXECUTABLE_NAME} - CFBundleGetInfoString - ${MACOSX_BUNDLE_INFO_STRING} - CFBundleIconFile - ${MACOSX_BUNDLE_ICON_FILE} - CFBundleIdentifier - ${MACOSX_BUNDLE_GUI_IDENTIFIER} - CFBundleInfoDictionaryVersion - 6.0 - CFBundleLongVersionString - ${MACOSX_BUNDLE_LONG_VERSION_STRING} - CFBundleName - ${MACOSX_BUNDLE_BUNDLE_NAME} - CFBundlePackageType - APPL - CFBundleShortVersionString - ${MACOSX_BUNDLE_SHORT_VERSION_STRING} - CFBundleSignature - ???? - CFBundleVersion - ${MACOSX_BUNDLE_BUNDLE_VERSION} - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UISupportedInterfaceOrientations - - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - NSHumanReadableCopyright - ${MACOSX_BUNDLE_COPYRIGHT} - - diff --git a/examples/gpu/triangle/iOS/LaunchScreen.storyboard b/examples/gpu/triangle/iOS/LaunchScreen.storyboard deleted file mode 100644 index 436820912..000000000 --- a/examples/gpu/triangle/iOS/LaunchScreen.storyboard +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/examples/gpu/triangle/macOS/Info.plist b/examples/gpu/triangle/macOS/Info.plist deleted file mode 100644 index f68f66070..000000000 --- a/examples/gpu/triangle/macOS/Info.plist +++ /dev/null @@ -1,36 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - ${MACOSX_BUNDLE_EXECUTABLE_NAME} - CFBundleGetInfoString - ${MACOSX_BUNDLE_INFO_STRING} - CFBundleIconFile - ${MACOSX_BUNDLE_ICON_FILE} - CFBundleIdentifier - ${MACOSX_BUNDLE_GUI_IDENTIFIER} - CFBundleInfoDictionaryVersion - 6.0 - CFBundleLongVersionString - ${MACOSX_BUNDLE_LONG_VERSION_STRING} - CFBundleName - ${MACOSX_BUNDLE_BUNDLE_NAME} - CFBundlePackageType - APPL - CFBundleShortVersionString - ${MACOSX_BUNDLE_SHORT_VERSION_STRING} - CFBundleSignature - ???? - CFBundleVersion - ${MACOSX_BUNDLE_BUNDLE_VERSION} - CSResourcesFileMapped - - NSHumanReadableCopyright - ${MACOSX_BUNDLE_COPYRIGHT} - NSHighResolutionCapable - - - diff --git a/examples/gpu/triangle/shaders/triangle.nzsl b/examples/gpu/triangle/shaders/triangle.nzsl index 5f88feefe..e6b6d6b57 100644 --- a/examples/gpu/triangle/shaders/triangle.nzsl +++ b/examples/gpu/triangle/shaders/triangle.nzsl @@ -15,7 +15,7 @@ struct VertOut { } [entry(vert)] -fn main(input: VertIn) -> VertOut { +fn vert_main(input: VertIn) -> VertOut { let output: VertOut; let position: vec2[f32]; @@ -44,7 +44,7 @@ struct FragOut { } [entry(frag)] -fn main(input: VertOut) -> FragOut { +fn frag_main(input: VertOut) -> FragOut { let output: FragOut; output.color = vec4[f32](input.color, 1.); diff --git a/examples/gpu/triangle/src/logger.cppm b/examples/gpu/triangle/src/logger.cppm new file mode 100644 index 000000000..7aa06a6b7 --- /dev/null +++ b/examples/gpu/triangle/src/logger.cppm @@ -0,0 +1,15 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +export module gpu_app:logger; + +import std; + +import stormkit.log; + +export { IN_MODULE_LOGGER("Triangle"); } diff --git a/examples/gpu/triangle/src/main.cpp b/examples/gpu/triangle/src/main.cpp index 4f8bdfac8..a1716f214 100644 --- a/examples/gpu/triangle/src/main.cpp +++ b/examples/gpu/triangle/src/main.cpp @@ -2,22 +2,22 @@ // This file is subject to the license terms in the LICENSE file // found in the top-level of this distribution +#include + import std; import stormkit; import gpu_app; -#include +#include #include -LOGGER("stormkit.examples.gpu.triangle"); - #ifndef SHADER_DIR - #define SHADER_DIR "../share/shaders" +static constexpr auto SHADER_DIR "../share/stormkit/shaders/" #endif -namespace stdr = std::ranges; -namespace stdfs = std::filesystem; + namespace stdr = std::ranges; +namespace stdfs = std::filesystem; using namespace std::literals; using namespace stormkit; @@ -29,43 +29,28 @@ struct SubmissionResource { }; struct SwapchainImageResource { - Ref image; - gpu::ImageView view; - gpu::FrameBuffer framebuffer; - gpu::Semaphore render_finished; + gpu::view::Image image; + gpu::ImageView view; + gpu::Semaphore render_finished; }; -static constexpr auto BUFFERING_COUNT = 2; +namespace { + constexpr auto BUFFERING_COUNT = 2_u32; + const auto SHADER = stdfs::path { SHADER_DIR } / "triangle.spv"; +} // namespace class Application: public base::Application { public: auto init_example() { // load shaders - m_vertex_shader = gpu::Shader::load_from_file(m_device, - SHADER_DIR "/triangle.spv", - gpu::ShaderStageFlag::VERTEX) - .transform_error(monadic::assert("Failed to load vertex shader")) - .value(); - - m_fragment_shader = gpu::Shader::load_from_file(m_device, - SHADER_DIR "/triangle.spv", - gpu::ShaderStageFlag::FRAGMENT) - .transform_error(monadic::assert("Failed to load fragment shader")) - .value(); - - m_pipeline_layout = gpu::PipelineLayout::create(m_device, {}) - .transform_error(monadic::assert("Failed to create pipeline layout")) - .value(); - - // initialize render pass - m_render_pass - = gpu::RenderPass:: - create(m_device, - { .attachments = { { .format = m_swapchain->pixel_format() } }, - .subpasses = { { .bind_point = gpu::PipelineBindPoint::GRAPHICS, - .color_attachment_refs = { { .attachment_id = 0u } } } } }) - .transform_error(monadic::assert("Failed to create render pass")) - .value(); + m_vertex_shader = TryAssert(gpu::Shader::load_from_file(m_device, SHADER, gpu::ShaderStageFlag::VERTEX), + std::format("Failed to load vertex shader {}!", SHADER.string())); + + m_fragment_shader = TryAssert(gpu::Shader::load_from_file(m_device, SHADER, gpu::ShaderStageFlag::FRAGMENT), + std::format("Failed to load fragment shader {}!", SHADER.string())); + + m_pipeline_layout = TryAssert(gpu::PipelineLayout::create(m_device, gpu::RasterPipelineLayout {}), + "Failed to create pipeline layoutu!"); const auto window_extent = m_window->extent(); @@ -81,41 +66,43 @@ class Application: public base::Application { }; const auto state = gpu::RasterPipelineState { - .input_assembly_state = { .topology = gpu::PrimitiveTopology::TRIANGLE_LIST, }, - .viewport_state = { .viewports = { window_viewport }, - .scissors = { scissor }, }, - .color_blend_state - = { .attachments = { { .blend_enable = true, - .src_color_blend_factor = gpu::BlendFactor::SRC_ALPHA, - .dst_color_blend_factor = gpu::BlendFactor::ONE_MINUS_SRC_ALPHA, - .src_alpha_blend_factor = gpu::BlendFactor::SRC_ALPHA, - .dst_alpha_blend_factor = gpu::BlendFactor::ONE_MINUS_SRC_ALPHA, - .alpha_blend_operation = gpu::BlendOperation::ADD, }, }, }, - .shader_state = to_refs(m_vertex_shader, m_fragment_shader), - }; - - m_pipeline = gpu::Pipeline::create(m_device, state, m_pipeline_layout, m_render_pass) - .transform_error(monadic::assert("Failed to create raster pipeline")) - .value(); + .input_assembly_state = { .topology = gpu::PrimitiveTopology::TRIANGLE_LIST, }, + .viewport_state = { .viewports = { window_viewport }, + .scissors = { scissor }, }, + .color_blend_state + = { .attachments = { { .blend_enable = true, + .src_color_blend_factor = gpu::BlendFactor::SRC_ALPHA, + .dst_color_blend_factor = gpu::BlendFactor::ONE_MINUS_SRC_ALPHA, + .src_alpha_blend_factor = gpu::BlendFactor::SRC_ALPHA, + .dst_alpha_blend_factor = gpu::BlendFactor::ONE_MINUS_SRC_ALPHA, + .alpha_blend_operation = gpu::BlendOperation::ADD, }, }, }, + .shader_state = gpu::to_views(m_vertex_shader, m_fragment_shader), + }; + + const auto rendering_info = gpu::RasterPipelineRenderingInfo { + .color_attachment_formats = { m_swapchain->pixel_format() } + }; + + m_pipeline = TryAssert(gpu::Pipeline::create(m_device, + gpu::Pipeline::RasterizationCreateInfo { .state = as_ref(state), + .layout = m_pipeline_layout, + .rendering_info = rendering_info }), + "Failed to create raster pipeline!"); // create present engine resources - m_submission_resources = init_by>([&](auto& out) noexcept { + m_submission_resources = init_by>([&](auto& out) noexcept { out.reserve(BUFFERING_COUNT); for (auto _ : range(BUFFERING_COUNT)) { out.push_back({ - .in_flight = gpu::Fence::create_signaled(m_device) - .transform_error(monadic:: - assert("Failed to create swapchain image " - "in flight fence")) - .value(), - .image_available = gpu::Semaphore::create(m_device) - .transform_error(monadic::assert("Failed to create " - "present wait semaphore")) - .value(), - .render_cmb = m_command_pool->create_command_buffer() - .transform_error(monadic::assert("Failed to create transition " - "command buffers")) - .value(), + .in_flight = TryAssert(gpu::Fence::create_signaled(m_device), + "Failed to create swapchain image " + "in flight fence!"), + .image_available = TryAssert(gpu::Semaphore::create(m_device), + "Failed to create " + "present wait semaphore!"), + .render_cmb = TryAssert(m_command_pool->create_command_buffer(), + "Failed to create transition " + "command buffers!"), }); } }); @@ -123,65 +110,43 @@ class Application: public base::Application { // transition swapchain image to present image const auto& images = m_swapchain->images(); - const auto image_count = stdr::size(images); - auto transition_cmbs - = m_command_pool->create_command_buffers(image_count) - .transform_error(monadic::assert("Failed to create transition command buffers")) - .value(); + const auto image_count = stdr::size(images); + auto transition_cmbs = TryAssert(m_command_pool->create_command_buffers(image_count), + "Failed to create transition command buffers!"); m_image_resources.reserve(stdr::size(images)); auto image_index = 0u; for (const auto& swap_image : images) { - auto view = gpu::ImageView::create(m_device, swap_image) - .transform_error(core::monadic:: - assert("Failed to create swapchain image view")) - .value(); - auto framebuffer = m_render_pass - ->create_frame_buffer(m_device, window_extent, to_refs(view)) - .transform_error(core::monadic::assert( - std::format("Failed to create framebuffer for image {}", - image_index))) - .value(); - - m_image_resources.push_back({ - .image = as_ref(swap_image), - .view = std::move(view), - .framebuffer = std::move(framebuffer), - .render_finished = gpu::Semaphore::create(m_device) - .transform_error(core::monadic::assert("Failed to create render " - "signal semaphore")) - .value(), - }); + auto view = TryAssert(gpu::ImageView::create(m_device, { swap_image }), "Failed to create swapchain image view!"); + + m_image_resources.push_back({ .image = swap_image, + .view = std::move(view), + .render_finished = TryAssert(gpu::Semaphore::create(m_device), + "Failed to create render " + "signal semaphore!") }); auto& transition_cmb = transition_cmbs[image_index]; - *transition_cmb.begin(true) - .transform_error(monadic:: - assert("Failed to begin texture transition command buffer")) - .value() - ->begin_debug_region(std::format("transition image {}", image_index)) - .transition_image_layout(swap_image, - gpu::ImageLayout::UNDEFINED, - gpu::ImageLayout::PRESENT_SRC) - .end_debug_region() - .end() - .transform_error(monadic::assert("Failed to begin texture transition command " - "buffer")); + TryDiscardAssert((transition_cmb.record([&](auto cmb) noexcept { + cmb.begin_debug_region(std::format("Transition image {}", image_index)) + .transition_image_layout(swap_image, + gpu::ImageLayout::UNDEFINED, + gpu::ImageLayout::PRESENT_SRC) + .end_debug_region(); + })), + std::format("Failed to record transition cmb {}!", image_index)); ++image_index; } - const auto fence = gpu::Fence::create(m_device) - .transform_error(monadic::assert("Failed to create transition fence")) - .value(); + const auto fence = TryAssert(gpu::Fence::create(m_device), "Failed to create transition fence!"); - const auto cmbs = to_refs(transition_cmbs); + const auto cmbs = gpu::to_views(transition_cmbs); - m_raster_queue->submit({ .command_buffers = cmbs }, as_ref(fence)) - .transform_error(monadic::assert("Failed to submit texture transition command buffers")) - .value(); + TryAssert(m_raster_queue->submit({ .command_buffers = cmbs }, fence), + "Failed to submit texture transition command buffers!"); // wait for transition to be done - fence.wait().transform_error(monadic::assert()); + TryAssert(fence.wait(), ""); } auto run_example() { @@ -193,80 +158,69 @@ class Application: public base::Application { const auto& wait = submission_resource.image_available; auto& in_flight = submission_resource.in_flight; - const auto acquire_next_image = bind_front(&gpu::SwapChain::acquire_next_image, - &*m_swapchain, - 100ms, - std::cref(wait)); - const auto extract_index = [](auto&& _result) static noexcept { - auto&& [result, _image_index] = _result; - return _image_index; - }; + TryAssert(in_flight.wait(), "Failed to wait in_flight fence!"); + TryAssert(in_flight.reset(), "Failed to reset in_flight fence!"); - const auto - image_index = in_flight.wait() - .transform([&in_flight](auto&&) mutable noexcept { in_flight.reset(); }) - .and_then(acquire_next_image) - .transform(extract_index) - .transform_error(monadic:: - assert("Failed to acquire next swapchain image")) - .value(); + const auto&& [_, image_index] = TryAssert(m_swapchain->acquire_next_image(100ms, wait), + "Failed to acquire next swapchain image!"); const auto& swapchain_image_resource = m_image_resources[image_index]; - const auto& framebuffer = swapchain_image_resource.framebuffer; const auto& signal = swapchain_image_resource.render_finished; - static constexpr auto PIPELINE_FLAGS = std::array { - gpu::PipelineStageFlag::COLOR_ATTACHMENT_OUTPUT + static constexpr auto PIPELINE_FLAGS = array { gpu::PipelineStageFlag::COLOR_ATTACHMENT_OUTPUT }; + + const auto window_extent = m_window->extent().to(); + const auto rendering_info = gpu::RenderingInfo { + .render_area = { .x = 0, .y = 0, .width = window_extent.width, .height = window_extent.height }, + .color_attachments = { { .image_view = swapchain_image_resource.view, + .layout = gpu::ImageLayout::ATTACHMENT_OPTIMAL, + .clear_value = gpu::ClearColor { .color = colors::SILVER } } } }; // render in it auto& render_cmb = submission_resource.render_cmb; - *render_cmb.reset() - .transform_error(monadic::assert("Failed to reset render command buffer")) - .value() - ->begin() - .transform_error(monadic::assert("Failed to begin render command buffer")) - .value() - ->begin_debug_region("Render triangle") - .begin_render_pass(m_render_pass, framebuffer) - .bind_pipeline(m_pipeline) - .draw(3) - .end_render_pass() - .end_debug_region() - .end() - .transform_error(monadic::assert("Failed to end render command buffer")) - .value() - ->submit(m_raster_queue, - as_refs(wait), - PIPELINE_FLAGS, - as_refs(signal), - as_ref(in_flight)) - .transform_error(monadic::assert("Failed to submit render command buffer")); + TryAssert(render_cmb.reset(), std::format("Failed to reset render cmb {}!", image_index)); + TryDiscardAssert((render_cmb.record([&](auto cmb) noexcept { + cmb + .transition_image_layout(swapchain_image_resource.image, + gpu::ImageLayout::PRESENT_SRC, + gpu::ImageLayout::ATTACHMENT_OPTIMAL) + .begin_debug_region("Render triangle") + .begin_rendering(rendering_info) + .bind_pipeline(m_pipeline) + .draw(3) + .end_rendering() + .end_debug_region() + .transition_image_layout(swapchain_image_resource.image, + gpu::ImageLayout::ATTACHMENT_OPTIMAL, + gpu::ImageLayout::PRESENT_SRC); + })), + std::format("Failed to record render cmb {}!", image_index)); + + TryDiscardAssert(render_cmb.submit(m_raster_queue, gpu::as_views(wait), PIPELINE_FLAGS, gpu::as_views(signal), in_flight), + "Failed to submit render command buffer"); // present it - auto update_current_frame = [this](auto&&) mutable noexcept { - if (++m_current_frame >= BUFFERING_COUNT) m_current_frame = 0; - }; + TryDiscardAssert(m_raster_queue->present(gpu::as_views(m_swapchain), gpu::as_views(signal), as_view(image_index)), + "Failed to present swapchain image!"); - m_raster_queue->present(as_refs(m_swapchain), as_refs(signal), as_view(image_index)) - .transform(update_current_frame) - .transform_error(monadic::assert("Failed to present swapchain image")); + if (++m_current_frame >= BUFFERING_COUNT) m_current_frame = 0; } - constexpr auto example_name() const noexcept -> std::string_view { return "Triangle"; } + constexpr auto example_name() const noexcept -> string_view { return "Triangle"; } private: - DeferInit m_vertex_shader; - DeferInit m_fragment_shader; - DeferInit m_pipeline_layout; - DeferInit m_render_pass; - DeferInit m_pipeline; - std::vector m_submission_resources; - std::vector m_image_resources; - usize m_current_frame = 0_usize; + DeferInit m_vertex_shader; + DeferInit m_fragment_shader; + DeferInit m_pipeline_layout; + DeferInit m_render_pass; + DeferInit m_pipeline; + dyn_array m_submission_resources; + dyn_array m_image_resources; + usize m_current_frame = 0_usize; }; -auto main(std::span args) -> int { +auto main(array_view args) -> int { auto app = Application {}; app.run(args); return 0; diff --git a/examples/gpu/triangle/win32/manifest.manifest b/examples/gpu/triangle/win32/manifest.manifest deleted file mode 100644 index 4a9b5f6a6..000000000 --- a/examples/gpu/triangle/win32/manifest.manifest +++ /dev/null @@ -1,9 +0,0 @@ - - - - - true - PerMonitorV2 - - - diff --git a/examples/gpu/triangle/xmake.lua b/examples/gpu/triangle/xmake.lua index 7069fe24b..762d686d0 100644 --- a/examples/gpu/triangle/xmake.lua +++ b/examples/gpu/triangle/xmake.lua @@ -1,46 +1,28 @@ -if is_plat("linux") then - add_requires( - "nzsl", - { configs = { toolchains = "gcc", runtimes = "stdc++_shared", fs_watcher = false, link = {} } } - ) -elseif is_plat("windows") then - add_requires("nzsl", { configs = { toolchains = "msvc", runtimes = "MD", fs_watcher = false, links = {} } }) -else - add_requires("nzsl", { configs = { fs_watcher = false, links = {} } }) +local runtimes +local toolchain +if is_plat("windows") then + runtimes = "MD" + toolchain = "msvc" +elseif is_plat("linux") then + runtimes = "stdc++_shared" + toolchain = "gcc" end +add_requires("nzsl", { configs = { fs_watcher = false, kind = "binary", toolchains = toolchain, runtimes = runtimes } }) target("triangle", function() - set_kind("binary") - set_languages("cxxlatest", "clatest") + add_rules("stormkit::example", "compile.shaders") - add_rules("stormkit.flags") - -- add_rules("platform.windows.subsystem.windows") - add_rules("platform.windows.subsystem.console") - - add_rules("compile.shaders") - add_deps("core", "main", "log", "wsi", "gpu", "stormkit") - - if is_mode("debug") then - add_defines("STORMKIT_BUILD_DEBUG") - add_defines("STORMKIT_ASSERT=1") - set_suffixname("-d") - else - add_defines("STORMKIT_ASSERT=0") - end - - add_files("../common/app.mpp") - add_files("src/*.cpp") - add_files("shaders/*.nzsl") - if is_plat("windows") then add_files("win32/*.manifest") end - - add_includedirs("$(builddir)/shaders") + add_files("src/*.cpp", "src/*.cppm", "../common/app.cppm", "shaders/*.nzsl") if get_config("devmode") then - add_defines('SHADER_DIR="$(builddir)/shaders"') - set_rundir("$(projectdir)") + add_defines(format('RESOURCE_DIR="%s"', path.unix(path.join(os.projectdir(), "gpu/triangle")))) + add_defines(format('SHADER_DIR="%s"', path.unix("$(builddir)/shaders"))) end - add_embeddirs("$(builddir)/shaders") + if get_config("devmode") then set_rundir("$(projectdir)") end + + add_packages("nzsl") + set_group("examples/stormkit-gpu") end) diff --git a/examples/log/console-logger/iOS/info.plist b/examples/log/console-logger/iOS/info.plist deleted file mode 100644 index 83e13e582..000000000 --- a/examples/log/console-logger/iOS/info.plist +++ /dev/null @@ -1,44 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - ${MACOSX_BUNDLE_EXECUTABLE_NAME} - CFBundleGetInfoString - ${MACOSX_BUNDLE_INFO_STRING} - CFBundleIconFile - ${MACOSX_BUNDLE_ICON_FILE} - CFBundleIdentifier - ${MACOSX_BUNDLE_GUI_IDENTIFIER} - CFBundleInfoDictionaryVersion - 6.0 - CFBundleLongVersionString - ${MACOSX_BUNDLE_LONG_VERSION_STRING} - CFBundleName - ${MACOSX_BUNDLE_BUNDLE_NAME} - CFBundlePackageType - APPL - CFBundleShortVersionString - ${MACOSX_BUNDLE_SHORT_VERSION_STRING} - CFBundleSignature - ???? - CFBundleVersion - ${MACOSX_BUNDLE_BUNDLE_VERSION} - LSRequiresIPhoneOS - - UISupportedInterfaceOrientations - - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - NSHumanReadableCopyright - ${MACOSX_BUNDLE_COPYRIGHT} - - diff --git a/examples/log/console-logger/macOS/info.plist b/examples/log/console-logger/macOS/info.plist deleted file mode 100644 index f68f66070..000000000 --- a/examples/log/console-logger/macOS/info.plist +++ /dev/null @@ -1,36 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - ${MACOSX_BUNDLE_EXECUTABLE_NAME} - CFBundleGetInfoString - ${MACOSX_BUNDLE_INFO_STRING} - CFBundleIconFile - ${MACOSX_BUNDLE_ICON_FILE} - CFBundleIdentifier - ${MACOSX_BUNDLE_GUI_IDENTIFIER} - CFBundleInfoDictionaryVersion - 6.0 - CFBundleLongVersionString - ${MACOSX_BUNDLE_LONG_VERSION_STRING} - CFBundleName - ${MACOSX_BUNDLE_BUNDLE_NAME} - CFBundlePackageType - APPL - CFBundleShortVersionString - ${MACOSX_BUNDLE_SHORT_VERSION_STRING} - CFBundleSignature - ???? - CFBundleVersion - ${MACOSX_BUNDLE_BUNDLE_VERSION} - CSResourcesFileMapped - - NSHumanReadableCopyright - ${MACOSX_BUNDLE_COPYRIGHT} - NSHighResolutionCapable - - - diff --git a/examples/log/console-logger/src/main.cpp b/examples/log/console-logger/src/main.cpp index 869b4f17f..f1a8be34f 100644 --- a/examples/log/console-logger/src/main.cpp +++ b/examples/log/console-logger/src/main.cpp @@ -4,15 +4,14 @@ import std; -import stormkit.core; -import stormkit.log; +import stormkit; #include using namespace stormkit; struct Bar { - std::string d = "FooBar"; + string d = "FooBar"; }; template @@ -20,30 +19,35 @@ struct std::formatter: std::formatter, Char template auto format(const Bar& data, FormatContext& ctx) const -> decltype(ctx.out()) { auto&& out = ctx.out(); - return format_to(out, "[Bar: d = {}]", data.d); + return format_to(out, "[Bar d: {}]", data.d); } }; struct Foo { - u32 a = 0u; - float b = 2.3f; - Bar c = Bar {}; + u32 a = 0u; + f32 b = 2.3f; + Bar c = Bar {}; }; -template -struct std::formatter: std::formatter, CharT> { - template - auto format(const Foo& data, FormatContext& ctx) const -> decltype(ctx.out()) { - auto&& out = ctx.out(); - return format_to(out, "[Foo: a = {}, b = {}, c = {}]", data.a, data.b, data.c); - } -}; +template +auto format_as(const Foo& data, FormatContext& ctx) -> decltype(ctx.out()) { + return std::format_to(ctx.out(), "[Foo a: {}, b: {}, c: {}]", data.a, data.b, data.c); +} + +namespace stdr = std::ranges; +namespace stdv = std::views; //////////////////////////////////////// //////////////////////////////////////// -auto main(std::span) -> int { +auto main(array_view args) -> int { using log::operator""_module; + // force debug + auto args2 = dyn_array { std::from_range, args }; + args2.emplace_back("--debug"); + + log::parse_args(args2); + auto logger = log::Logger::create_logger_instance(); log::Logger::ilog("This is an information"); diff --git a/examples/log/console-logger/xmake.lua b/examples/log/console-logger/xmake.lua index c7a024340..91bc43c2e 100644 --- a/examples/log/console-logger/xmake.lua +++ b/examples/log/console-logger/xmake.lua @@ -1,22 +1,7 @@ -target("console-logger") -do - set_kind("binary") - set_languages("cxxlatest", "clatest") +target("console-logger", function() + add_rules("stormkit::example") - add_rules("stormkit.flags") - add_rules("platform.windows.subsystem.console") - - add_deps("core", "main", "log") - - if is_mode("debug") then - add_defines("STORMKIT_BUILD_DEBUG") - add_defines("STORMKIT_ASSERT=1") - set_suffixname("-d") - else - add_defines("STORMKIT_ASSERT=0") - end - - add_files("src/main.cpp") + add_files("src/*.cpp") set_group("examples/stormkit-log") -end +end) diff --git a/examples/log/file-logger/macOS/info.plist b/examples/log/file-logger/macOS/info.plist deleted file mode 100644 index f68f66070..000000000 --- a/examples/log/file-logger/macOS/info.plist +++ /dev/null @@ -1,36 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - ${MACOSX_BUNDLE_EXECUTABLE_NAME} - CFBundleGetInfoString - ${MACOSX_BUNDLE_INFO_STRING} - CFBundleIconFile - ${MACOSX_BUNDLE_ICON_FILE} - CFBundleIdentifier - ${MACOSX_BUNDLE_GUI_IDENTIFIER} - CFBundleInfoDictionaryVersion - 6.0 - CFBundleLongVersionString - ${MACOSX_BUNDLE_LONG_VERSION_STRING} - CFBundleName - ${MACOSX_BUNDLE_BUNDLE_NAME} - CFBundlePackageType - APPL - CFBundleShortVersionString - ${MACOSX_BUNDLE_SHORT_VERSION_STRING} - CFBundleSignature - ???? - CFBundleVersion - ${MACOSX_BUNDLE_BUNDLE_VERSION} - CSResourcesFileMapped - - NSHumanReadableCopyright - ${MACOSX_BUNDLE_COPYRIGHT} - NSHighResolutionCapable - - - diff --git a/examples/log/file-logger/src/main.cpp b/examples/log/file-logger/src/main.cpp index 79586a346..7b033ab0c 100644 --- a/examples/log/file-logger/src/main.cpp +++ b/examples/log/file-logger/src/main.cpp @@ -4,8 +4,7 @@ import std; -import stormkit.core; -import stormkit.log; +import stormkit; #include @@ -14,32 +13,27 @@ import stormkit.log; using namespace stormkit; struct Bar { - std::string d = "FooBar"; + string d = "FooBar"; }; template struct std::formatter: std::formatter, CharT> { template auto format(const Bar& data, FormatContext& ctx) const -> decltype(ctx.out()) { - auto&& out = ctx.out(); - return format_to(out, "[Bar: d = {}]", data.d); + return format_to(ctx.out(), "[Bar d: {}]", data.d); } }; struct Foo { stormkit::u32 a = 0u; - float b = 2.3f; + f32 b = 2.3f; Bar c = Bar {}; }; -template -struct std::formatter: std::formatter, CharT> { - template - auto format(const Foo& data, FormatContext& ctx) const -> decltype(ctx.out()) { - auto&& out = ctx.out(); - return format_to(out, "[Foo: a = {}, b = {}, c = {}]", data.a, data.b, data.c); - } -}; +template +auto format_as(const Foo& data, FormatContext& ctx) -> decltype(ctx.out()) { + return std::format_to(ctx.out(), "[Foo a: {}, b: {}, c: {}]", data.a, data.b, data.c); +} #ifdef STORMKIT_COMPILER_MSVC static const auto LOG_DIR = std::filesystem::path { L"log/" }; @@ -49,10 +43,15 @@ static const auto LOG_DIR = std::filesystem::path { "log/" }; //////////////////////////////////////// //////////////////////////////////////// -auto main(std::span _) -> int { - using namespace stormkit; +auto main(array_view args) -> int { using log::operator""_module; + // force debug + auto args2 = dyn_array { std::from_range, args }; + args2.emplace_back("--debug"); + + log::parse_args(args2); + auto logger = log::Logger::create_logger_instance(LOG_DIR); log::Logger::ilog("This is an information"); diff --git a/examples/log/file-logger/xmake.lua b/examples/log/file-logger/xmake.lua index 44fd4c8f4..e5ef36883 100644 --- a/examples/log/file-logger/xmake.lua +++ b/examples/log/file-logger/xmake.lua @@ -1,22 +1,7 @@ -target("file-logger") -do - set_kind("binary") - set_languages("cxxlatest", "clatest") +target("file-logger", function() + add_rules("stormkit::example") - add_rules("stormkit.flags") - add_rules("platform.windows.subsystem.console") - - add_deps("core", "main", "log") - - if is_mode("debug") then - add_defines("STORMKIT_BUILD_DEBUG") - add_defines("STORMKIT_ASSERT=1") - set_suffixname("-d") - else - add_defines("STORMKIT_ASSERT=0") - end - - add_files("src/main.cpp") + add_files("src/*.cpp") set_group("examples/stormkit-log") -end +end) diff --git a/examples/lua/wsi/events/lua/events.luau b/examples/lua/wsi/events/lua/events.luau new file mode 100644 index 000000000..9f8ed39ef --- /dev/null +++ b/examples/lua/wsi/events/lua/events.luau @@ -0,0 +1,111 @@ +local function main() + local window = wsi.window.open("test", 800, 600, wsi.window_flag.RESIZEABLE) + + window:on_closed(function() + print("Close event!") + return true + end) + + window:on_resized(function(extent) + print("Resize event:\n {}", extent) + end) + + window:on_monitor_changed(function(monitor) + print("Monitor changed event:\n {}", monitor) + end) + + window:on_mouse_moved(function(_, position) + print("Mouse move event:\n {}", position) + end) + + window:on_mouse_button_down(function(_, button, position) + print("Mouse button down event:\n {}\n {}", button, position) + end) + + window:on_mouse_button_up(function(_, button, position) + print("Mouse button up event:\n {}\n {}", button, position) + end) + + window:on_restored(function() + print("Restored event!") + end) + + window:on_minimized(function() + print("Minimzed event!") + end) + + window:on_activated(function() + print("Activate event!") + end) + + window:on_deactivated(function() + print("Deactivate event!") + end) + + local foo = 0 + window:on_key_down(function(_, key, c) + print("Key down event: {} {}", key, c) + + local closures = { + [wsi.key.ESCAPE] = function() + print("Closing window!") + window:close() + end, + [wsi.key.W] = function() + local extent = window:extent() + extent.width = extent.width + 10 + window:set_extent(extent) + end, + [wsi.key.T] = function() + foo = foo + 1 + window:set_title(format("StormKit Lua Events Example | T pressed {} times", foo)) + end, + [wsi.key.H] = function() + local extent = window:extent() + extent.height = extent.height + 10 + window:set_extent(extent) + end, + [wsi.key.F11] = function() + window:toggle_fullscreen() + print("Toggling fullscreen to {}", window:fullscreen()) + end, + [wsi.key.F1] = function() + window:toggle_hidden_mouse() + print("Toggling hidden mouse to {}", window:is_mouse_hidden()) + end, + [wsi.key.F2] = function() + window:toggle_locked_mouse() + print("Toggling locked mouse to {}", window:is_mouse_locked()) + end, + [wsi.key.F3] = function() + window:toggle_confined_mouse() + print("Toggling confined mouse to {}", window:is_mouse_confined()) + end, + [wsi.key.F4] = function() + window:toggle_relative_mouse() + print("Toggling relative mouse to {}", window:is_mouse_relative()) + end, + [wsi.key.F5] = function() + window:toggle_key_repeat() + print("Toggling key repeat to {}", window:is_key_repeat_enabled()) + end, + } + + for k, closure in pairs(closures) do + if k == key then + closure() + break + end + end + end) + + window:on_key_up(function(_, key, c) + print("Key up event: {} {}", key, c) + end) + + window:event_loop(function() + window:clear() + end) +end + +main() diff --git a/examples/lua/wsi/events/src/main.cpp b/examples/lua/wsi/events/src/main.cpp new file mode 100644 index 000000000..642a3c72d --- /dev/null +++ b/examples/lua/wsi/events/src/main.cpp @@ -0,0 +1,38 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +#include + +#include + +#include + +import std; + +import stormkit; + +LOGGER("lua-Events"); + +#ifndef RESOURCE_DIR + #define RESOURCE_DIR "../share/stormkit" +#endif + +namespace stdfs = std::filesystem; + +static const auto LUA_FILE = stdfs::path { RESOURCE_DIR } / stdfs::path { "lua/events.luau" }; + +using namespace stormkit; + +//////////////////////////////////////// +//////////////////////////////////////// +auto main(array_view args) -> int { + wsi::parse_args(args); + log::parse_args(args); + + auto logger = log::Logger::create_logger_instance(); + + lua::Engine::run(LUA_FILE, { .wsi = true }); + + return 0; +} diff --git a/examples/lua/wsi/events/xmake.lua b/examples/lua/wsi/events/xmake.lua new file mode 100644 index 000000000..28f72c434 --- /dev/null +++ b/examples/lua/wsi/events/xmake.lua @@ -0,0 +1,16 @@ +namespace("lua", function() + target("events", function() + add_rules("stormkit::example", "compile.shaders") + + add_files("src/*.cpp") + + if get_config("devmode") then + add_defines(format('RESOURCE_DIR="%s"', path.unix(path.join(os.projectdir(), "examples/lua/wsi/events")))) + end + add_embeddirs("$(builddir)/shaders") + + if get_config("devmode") then set_rundir("$(projectdir)") end + + set_group("examples/stormkit-lua") + end) +end) diff --git a/examples/wsi/events/iOS/Info.plist b/examples/wsi/events/iOS/Info.plist deleted file mode 100644 index 823db4f45..000000000 --- a/examples/wsi/events/iOS/Info.plist +++ /dev/null @@ -1,46 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - ${MACOSX_BUNDLE_EXECUTABLE_NAME} - CFBundleGetInfoString - ${MACOSX_BUNDLE_INFO_STRING} - CFBundleIconFile - ${MACOSX_BUNDLE_ICON_FILE} - CFBundleIdentifier - ${MACOSX_BUNDLE_GUI_IDENTIFIER} - CFBundleInfoDictionaryVersion - 6.0 - CFBundleLongVersionString - ${MACOSX_BUNDLE_LONG_VERSION_STRING} - CFBundleName - ${MACOSX_BUNDLE_BUNDLE_NAME} - CFBundlePackageType - APPL - CFBundleShortVersionString - ${MACOSX_BUNDLE_SHORT_VERSION_STRING} - CFBundleSignature - ???? - CFBundleVersion - ${MACOSX_BUNDLE_BUNDLE_VERSION} - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UISupportedInterfaceOrientations - - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - NSHumanReadableCopyright - ${MACOSX_BUNDLE_COPYRIGHT} - - diff --git a/examples/wsi/events/iOS/LaunchScreen.storyboard b/examples/wsi/events/iOS/LaunchScreen.storyboard deleted file mode 100644 index 94d24c83b..000000000 --- a/examples/wsi/events/iOS/LaunchScreen.storyboard +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/examples/wsi/events/macOS/Info.plist b/examples/wsi/events/macOS/Info.plist deleted file mode 100644 index e8cc71539..000000000 --- a/examples/wsi/events/macOS/Info.plist +++ /dev/null @@ -1,36 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - ${MACOSX_BUNDLE_EXECUTABLE_NAME} - CFBundleGetInfoString - ${MACOSX_BUNDLE_INFO_STRING} - CFBundleIconFile - ${MACOSX_BUNDLE_ICON_FILE} - CFBundleIdentifier - ${MACOSX_BUNDLE_GUI_IDENTIFIER} - CFBundleInfoDictionaryVersion - 6.0 - CFBundleLongVersionString - ${MACOSX_BUNDLE_LONG_VERSION_STRING} - CFBundleName - ${MACOSX_BUNDLE_BUNDLE_NAME} - CFBundlePackageType - APPL - CFBundleShortVersionString - ${MACOSX_BUNDLE_SHORT_VERSION_STRING} - CFBundleSignature - ???? - CFBundleVersion - ${MACOSX_BUNDLE_BUNDLE_VERSION} - CSResourcesFileMapped - - NSHumanReadableCopyright - ${MACOSX_BUNDLE_COPYRIGHT} - NSHighResolutionCapable - - - diff --git a/examples/wsi/events/src/main.cpp b/examples/wsi/events/src/main.cpp index b43c56d2f..49cb38c3e 100644 --- a/examples/wsi/events/src/main.cpp +++ b/examples/wsi/events/src/main.cpp @@ -4,9 +4,7 @@ import std; -import stormkit.core; -import stormkit.log; -import stormkit.wsi; +import stormkit; #include #include @@ -20,8 +18,10 @@ namespace stdr = std::ranges; //////////////////////////////////////// //////////////////////////////////////// -auto main(std::span args) -> int { +auto main(array_view args) -> int { wsi::parse_args(args); + log::parse_args(args); + auto logger = log::Logger::create_logger_instance(); const auto monitors = wsi::get_monitors(); @@ -39,85 +39,72 @@ auto main(std::span args) -> int { }); auto foo = 0; - window - .on(wsi::ResizedEventFunc { [](const math::Extent2& extent) static noexcept { - ilog("Resize event: {}", extent); - } }, - wsi::MonitorChangedEventFunc { [](const wsi::Monitor& monitor) noexcept { - ilog("Monitor changed event: {}", monitor); - } }, - wsi::MouseMovedEventFunc { [](u8 /*id*/, const math::vec2i& position) noexcept { - ilog("Mouse move event: {}", position); - } }, - wsi::MouseButtonDownEventFunc { - [](u8 /*id*/, wsi::MouseButton button, const math::vec2i& position) noexcept { - ilog("Mouse button down event: {} {}", button, position); - } }, - wsi::MouseButtonUpEventFunc { - [](u8 /*id*/, wsi::MouseButton button, const math::vec2i& position) noexcept { - ilog("Mouse button up event: {} {}", button, position); - } }, - wsi::RestoredEventFunc { [] noexcept { ilog("Restored event"); } }, - wsi::MinimizedEventFunc { [] noexcept { ilog("Minimized event"); } }, - wsi::ActivateEventFunc { [] noexcept { ilog("Activate event"); } }, - wsi::DeactivateEventFunc { [] noexcept { ilog("Deactivate event"); } }, - wsi::KeyDownEventFunc { - [&window, &foo](u8 /*id*/, wsi::Key key, char c) mutable noexcept { - switch (key) { - case wsi::Key::ESCAPE: - window.close(); - ilog("Closing window"); - break; - case wsi::Key::W: { - auto extent = window.extent(); - extent.width += 10; - window.set_extent(extent); - } break; - case wsi::Key::T: { - window - .set_title(std::format("StormKit WSI Events Example | T pressed {} times", - ++foo)); - } break; - case wsi::Key::H: { - auto extent = window.extent(); - extent.height += 10; - window.set_extent(extent); - } break; - case wsi::Key::F11: - window.toggle_fullscreen(); - ilog("Toggling fullscreen to {}", window.fullscreen()); - break; - case wsi::Key::F1: - window.toggle_hidden_mouse(); - ilog("Toggling hidden mouse to {}", window.is_mouse_hidden()); - break; - case wsi::Key::F2: - window.toggle_locked_mouse(); - ilog("Toggling locked mouse to {}", window.is_mouse_locked()); - break; - case wsi::Key::F3: - window.toggle_confined_mouse(); - ilog("Toggling confined mouse to {}", window.is_mouse_confined()); - break; - case wsi::Key::F4: - window.toggle_relative_mouse(); - ilog("Toggling relative mouse to {}", window.is_mouse_relative()); - break; - case wsi::Key::F5: - window.toggle_key_repeat(); - ilog("Toggling key repeat to {}", window.is_key_repeat_enabled()); - break; - default: break; - } + window.on(wsi::ResizedEventFunc { [](const math::uextent2& extent) static noexcept { ilog("Resize event: {}", extent); } }, + wsi::MonitorChangedEventFunc { [](const wsi::Monitor& monitor) noexcept { + ilog("Monitor changed event: {}", monitor); + } }, + wsi::MouseMovedEventFunc { [](u8 /*id*/, const math::ivec2& position) noexcept { + ilog("Mouse move event: {}", position); + } }, + wsi::MouseButtonDownEventFunc { [](u8 /*id*/, wsi::MouseButton button, const math::ivec2& position) noexcept { + ilog("Mouse button down event: {} {}", button, position); + } }, + wsi::MouseButtonUpEventFunc { [](u8 /*id*/, wsi::MouseButton button, const math::ivec2& position) noexcept { + ilog("Mouse button up event: {} {}", button, position); + } }, + wsi::RestoredEventFunc { [] noexcept { ilog("Restored event"); } }, + wsi::MinimizedEventFunc { [] noexcept { ilog("Minimized event"); } }, + wsi::ActivateEventFunc { [] noexcept { ilog("Activate event"); } }, + wsi::DeactivateEventFunc { [] noexcept { ilog("Deactivate event"); } }, + wsi::KeyDownEventFunc { [&window, &foo](u8 /*id*/, wsi::Key key, char c) mutable noexcept { + switch (key) { + case wsi::Key::ESCAPE: + window.close(); + ilog("Closing window"); + break; + case wsi::Key::W: { + auto extent = window.extent(); + extent.width += 10; + window.set_extent(extent); + } break; + case wsi::Key::T: { + window.set_title(std::format("StormKit WSI Events Example | T pressed {} times", ++foo)); + } break; + case wsi::Key::H: { + auto extent = window.extent(); + extent.height += 10; + window.set_extent(extent); + } break; + case wsi::Key::F11: + window.toggle_fullscreen(); + ilog("Toggling fullscreen to {}", window.fullscreen()); + break; + case wsi::Key::F1: + window.toggle_hidden_mouse(); + ilog("Toggling hidden mouse to {}", window.is_mouse_hidden()); + break; + case wsi::Key::F2: + window.toggle_locked_mouse(); + ilog("Toggling locked mouse to {}", window.is_mouse_locked()); + break; + case wsi::Key::F3: + window.toggle_confined_mouse(); + ilog("Toggling confined mouse to {}", window.is_mouse_confined()); + break; + case wsi::Key::F4: + window.toggle_relative_mouse(); + ilog("Toggling relative mouse to {}", window.is_mouse_relative()); + break; + case wsi::Key::F5: + window.toggle_key_repeat(); + ilog("Toggling key repeat to {}", window.is_key_repeat_enabled()); + break; + default: break; + } - ilog("Key down --\n code: {}\n value: '{}'\n raw_value: 0x{:0x})", - key, - c, - c); - } }, - wsi::KeyUpEventFunc { [](u8 /*id*/, wsi::Key key, char /*c*/) noexcept { - ilog("Key up --\n code: {}", key); - } }); + ilog("Key down --\n code: {}\n value: '{}'\n raw_value: 0x{:0x})", key, c, c); + } }, + wsi::KeyUpEventFunc { [](u8 /*id*/, wsi::Key key, char /*c*/) noexcept { ilog("Key up --\n code: {}", key); } }); window.event_loop([&] mutable { window.clear(); }); diff --git a/examples/wsi/events/xmake.lua b/examples/wsi/events/xmake.lua index 6713719ad..0340337ff 100644 --- a/examples/wsi/events/xmake.lua +++ b/examples/wsi/events/xmake.lua @@ -1,22 +1,7 @@ target("events", function() - set_kind("binary") - set_languages("cxxlatest", "clatest") + add_rules("stormkit::example") - add_rules("stormkit.flags") - add_rules("platform.windows.subsystem.console") - - add_deps("core", "main", "log", "wsi") - - if is_mode("debug") then - add_defines("STORMKIT_BUILD_DEBUG") - add_defines("STORMKIT_ASSERT=1") - set_suffixname("-d") - else - add_defines("STORMKIT_ASSERT=0") - end - - add_files("src/main.cpp") - if is_plat("windows") then add_files("win32/*.manifest") end + add_files("src/*.cpp") set_group("examples/stormkit-wsi") end) diff --git a/examples/wsi/framebuffer/iOS/Info.plist b/examples/wsi/framebuffer/iOS/Info.plist deleted file mode 100644 index 823db4f45..000000000 --- a/examples/wsi/framebuffer/iOS/Info.plist +++ /dev/null @@ -1,46 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - ${MACOSX_BUNDLE_EXECUTABLE_NAME} - CFBundleGetInfoString - ${MACOSX_BUNDLE_INFO_STRING} - CFBundleIconFile - ${MACOSX_BUNDLE_ICON_FILE} - CFBundleIdentifier - ${MACOSX_BUNDLE_GUI_IDENTIFIER} - CFBundleInfoDictionaryVersion - 6.0 - CFBundleLongVersionString - ${MACOSX_BUNDLE_LONG_VERSION_STRING} - CFBundleName - ${MACOSX_BUNDLE_BUNDLE_NAME} - CFBundlePackageType - APPL - CFBundleShortVersionString - ${MACOSX_BUNDLE_SHORT_VERSION_STRING} - CFBundleSignature - ???? - CFBundleVersion - ${MACOSX_BUNDLE_BUNDLE_VERSION} - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UISupportedInterfaceOrientations - - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - NSHumanReadableCopyright - ${MACOSX_BUNDLE_COPYRIGHT} - - diff --git a/examples/wsi/framebuffer/iOS/LaunchScreen.storyboard b/examples/wsi/framebuffer/iOS/LaunchScreen.storyboard deleted file mode 100644 index 94d24c83b..000000000 --- a/examples/wsi/framebuffer/iOS/LaunchScreen.storyboard +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/examples/wsi/framebuffer/macOS/Info.plist b/examples/wsi/framebuffer/macOS/Info.plist deleted file mode 100644 index e8cc71539..000000000 --- a/examples/wsi/framebuffer/macOS/Info.plist +++ /dev/null @@ -1,36 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - ${MACOSX_BUNDLE_EXECUTABLE_NAME} - CFBundleGetInfoString - ${MACOSX_BUNDLE_INFO_STRING} - CFBundleIconFile - ${MACOSX_BUNDLE_ICON_FILE} - CFBundleIdentifier - ${MACOSX_BUNDLE_GUI_IDENTIFIER} - CFBundleInfoDictionaryVersion - 6.0 - CFBundleLongVersionString - ${MACOSX_BUNDLE_LONG_VERSION_STRING} - CFBundleName - ${MACOSX_BUNDLE_BUNDLE_NAME} - CFBundlePackageType - APPL - CFBundleShortVersionString - ${MACOSX_BUNDLE_SHORT_VERSION_STRING} - CFBundleSignature - ???? - CFBundleVersion - ${MACOSX_BUNDLE_BUNDLE_VERSION} - CSResourcesFileMapped - - NSHumanReadableCopyright - ${MACOSX_BUNDLE_COPYRIGHT} - NSHighResolutionCapable - - - diff --git a/examples/wsi/framebuffer/src/main.cpp b/examples/wsi/framebuffer/src/main.cpp index 0560211c6..d526d0f29 100644 --- a/examples/wsi/framebuffer/src/main.cpp +++ b/examples/wsi/framebuffer/src/main.cpp @@ -4,9 +4,7 @@ import std; -import stormkit.core; -import stormkit.log; -import stormkit.wsi; +import stormkit; #include #include @@ -18,9 +16,7 @@ using namespace std::literals; namespace stdr = std::ranges; -auto update_pixels(stormkit::ThreadPool& pool, - std::vector>& pixels, - const auto& extent) noexcept { +auto update_pixels(stormkit::ThreadPool& pool, dyn_array& pixels, const auto& extent) noexcept { const auto rect_width = extent.width / 5; const auto rect_height = extent.height / 5; @@ -33,32 +29,30 @@ auto update_pixels(stormkit::ThreadPool& pool, pixels.resize(extent.height * extent.width, colors::RED); - auto data = std::mdspan { stdr::data(pixels), extent.height, extent.width }; - parallel_for(pool, - range(extent.width * extent.height), - [&rect, data, &extent](auto x_y) mutable noexcept { - const auto x = as(x_y % extent.width); - const auto y = as(x_y / extent.width); - - if (math::AABB({ as(x), as(y) }, rect)) - data[y, x] = colors::BLACK; - else { - const auto color_id = as(x) / as(extent.width); - if (color_id >= 0.8) data[y, x] = colors::BLUE; - else if (color_id >= 0.6) - data[y, x] = colors::GREEN; - else if (color_id >= 0.4) - data[y, x] = colors::WHITE; - else if (color_id >= 0.2) - data[y, x] = colors::YELLOW; - else - data[y, x] = colors::RED; - } - }); + auto data = mdarray_view { stdr::data(pixels), extent.height, extent.width }; + parallel_for(pool, range(extent.width * extent.height), [&rect, data, &extent](auto x_y) mutable noexcept { + const auto x = as(x_y % extent.width); + const auto y = as(x_y / extent.width); + + if (math::AABB(math::uvec2 { as(x), as(y) }, rect)) data[y, x] = colors::BLACK; + else { + const auto color_id = as(x) / as(extent.width); + if (color_id >= 0.8) data[y, x] = colors::BLUE; + else if (color_id >= 0.6) + data[y, x] = colors::GREEN; + else if (color_id >= 0.4) + data[y, x] = colors::WHITE; + else if (color_id >= 0.2) + data[y, x] = colors::YELLOW; + else + data[y, x] = colors::RED; + } + }); } -auto main(std::span args) -> int { +auto main(array_view args) -> int { wsi::parse_args(args); + log::parse_args(args); auto logger = log::Logger::create_logger_instance(); @@ -66,25 +60,22 @@ auto main(std::span args) -> int { ilog("--- Monitors ---"); ilog("{}", monitors); - auto window = wsi::Window::open("Hello world", - { .width = 800_u32, .height = 600_u32 }, - wsi::WindowFlag::RESIZEABLE); + auto window = wsi::Window::open("Hello world", { .width = 800_u32, .height = 600_u32 }, wsi::WindowFlag::RESIZEABLE); ilog("wm: {}", window.wm()); auto pool = core::ThreadPool {}; - auto pixels = std::vector> {}; + auto pixels = dyn_array {}; update_pixels(pool, pixels, window.extent()); auto active = true; - window - .on(wsi::ResizedEventFunc { [&](const math::Extent2& extent) mutable noexcept { - update_pixels(pool, pixels, extent); - window.fill_framebuffer(pixels); - } }, - wsi::RestoredEventFunc { [&active] mutable noexcept { active = true; } }, - wsi::MinimizedEventFunc { [&active] mutable noexcept { active = false; } }, - wsi::KeyDownEventFunc { [&window](u8 /*id*/, wsi::Key key, char /*c*/) mutable noexcept { - if (key == wsi::Key::ESCAPE) window.close(); - } }); + window.on(wsi::ResizedEventFunc { [&](const math::uextent2& extent) mutable noexcept { + update_pixels(pool, pixels, extent); + window.fill_framebuffer(pixels); + } }, + wsi::RestoredEventFunc { [&active] mutable noexcept { active = true; } }, + wsi::MinimizedEventFunc { [&active] mutable noexcept { active = false; } }, + wsi::KeyDownEventFunc { [&window](u8 /*id*/, wsi::Key key, char /*c*/) mutable noexcept { + if (key == wsi::Key::ESCAPE) window.close(); + } }); window.event_loop([&] noexcept { if (not active) std::this_thread::yield(); diff --git a/examples/wsi/framebuffer/win32/manifest.manifest b/examples/wsi/framebuffer/win32/manifest.manifest deleted file mode 100644 index f2708ecb1..000000000 --- a/examples/wsi/framebuffer/win32/manifest.manifest +++ /dev/null @@ -1,9 +0,0 @@ - - - - - true - PerMonitorV2 - - - diff --git a/examples/wsi/framebuffer/xmake.lua b/examples/wsi/framebuffer/xmake.lua index 0d9bb9906..ecb3674f3 100644 --- a/examples/wsi/framebuffer/xmake.lua +++ b/examples/wsi/framebuffer/xmake.lua @@ -1,22 +1,7 @@ target("framebuffer", function() - set_kind("binary") - set_languages("cxxlatest", "clatest") + add_rules("stormkit::example") - add_rules("stormkit.flags") - add_rules("platform.windows.subsystem.console") - - add_deps("core", "main", "log", "wsi") - - if is_mode("debug") then - add_defines("STORMKIT_BUILD_DEBUG") - add_defines("STORMKIT_ASSERT=1") - set_suffixname("-d") - else - add_defines("STORMKIT_ASSERT=0") - end - - add_files("src/main.cpp") - if is_plat("windows") then add_files("win32/*.manifest") end + add_files("src/*.cpp") set_group("examples/stormkit-wsi") end) diff --git a/include/stormkit/core/api.hpp b/include/stormkit/core/api.hpp new file mode 100644 index 000000000..ef5e0d316 --- /dev/null +++ b/include/stormkit/core/api.hpp @@ -0,0 +1,16 @@ +// Copryright (C) 2022 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +#ifndef STORMKIT_CORE_API_HPP +#define STORMKIT_CORE_API_HPP + +#include + +#ifdef STORMKIT_CORE_BUILD + #define STORMKIT_CORE_API STORMKIT_EXPORT +#else + #define STORMKIT_CORE_API STORMKIT_IMPORT +#endif + +#endif diff --git a/include/stormkit/core/as_casts_macro.hpp b/include/stormkit/core/as_casts_macro.hpp index f9cab0eb2..616f42274 100644 --- a/include/stormkit/core/as_casts_macro.hpp +++ b/include/stormkit/core/as_casts_macro.hpp @@ -8,13 +8,13 @@ #include #define ASCASTER_STRICT_DECLARE(_To, _From) \ - template To, stormkit::meta::IsStrict<_From> From> \ + template To, stormkit::meta::SameAs<_From> From> \ struct stormkit::casts::AsCaster { \ static constexpr auto operator()(const From& from, const std::source_location& location) noexcept -> To; \ }; #define ASCASTER_STRICT_DEFINE(_To, _From) \ - template To, stormkit::meta::IsStrict<_From> From> \ + template To, stormkit::meta::SameAs<_From> From> \ STORMKIT_FORCE_INLINE constexpr auto \ stormkit::casts::AsCaster::operator()(const From& from, \ [[maybe_unused]] const std::source_location& location) noexcept -> To @@ -40,13 +40,13 @@ ASCASTER_DEFINE(_To, _From) #define NARROWCASTER_STRICT_DECLARE(_To, _From) \ - template To, stormkit::meta::IsStrict<_From> From> \ + template To, stormkit::meta::SameAs<_From> From> \ struct stormkit::casts::NarrowCaster { \ static constexpr auto operator()(const From& from, const std::source_location& location) noexcept -> To; \ }; #define NARROWCASTER_STRICT_DEFINE(_To, _From) \ - template To, stormkit::meta::IsStrict<_From> From> \ + template To, stormkit::meta::SameAs<_From> From> \ STORMKIT_FORCE_INLINE constexpr auto \ stormkit::casts::NarrowCaster::operator()(const From& from, \ [[maybe_unused]] const std::source_location& location) noexcept -> To diff --git a/include/stormkit/core/config.hpp.in b/include/stormkit/core/config.hpp.in index 2689f0ed1..0172e41b0 100644 --- a/include/stormkit/core/config.hpp.in +++ b/include/stormkit/core/config.hpp.in @@ -14,6 +14,7 @@ ${define STORMKIT_LIB_ENTITIES_ENABLED} ${define STORMKIT_LIB_IMAGE_ENABLED} ${define STORMKIT_LIB_WSI_ENABLED} ${define STORMKIT_LIB_GPU_ENABLED} +${define STORMKIT_LIB_LUA_ENABLED} #ifndef NO_CONSTANTS _STORMKIT_EXPORT namespace stormkit { inline namespace core { diff --git a/include/stormkit/core/format_macro.hpp b/include/stormkit/core/format_macro.hpp index 778dca433..1bc519bbb 100644 --- a/include/stormkit/core/format_macro.hpp +++ b/include/stormkit/core/format_macro.hpp @@ -14,7 +14,7 @@ constexpr auto parse(ParseContext& ctx) noexcept -> decltype(ctx.begin()); \ \ template \ - requires(stormkit::meta::IsStrict>) \ + requires(stormkit::meta::SameAs>) \ auto format(U&& data, FormatContext& ctx) const noexcept -> decltype(ctx.out()); \ }; @@ -26,26 +26,26 @@ #define FORMATTER_DEFINE_FORMAT(_From) \ template<_From T, typename CharT> \ template \ - requires(stormkit::meta::IsStrict>) \ + requires(stormkit::meta::SameAs>) \ inline auto std::formatter::format(U&& data, FormatContext& ctx) const noexcept -> decltype(ctx.out()) #define FORMATTER_INHERIT_DECLARE(_Parent, _From) \ template<_From T, typename CharT> \ struct std::formatter: std::formatter<_Parent, CharT> { \ template \ - requires(stormkit::meta::IsStrict>) \ + requires(stormkit::meta::SameAs>) \ auto format(U&& data, FormatContext& ctx) const noexcept -> decltype(ctx.out()); \ }; #define FORMATTER_INHERIT_DEFINE_FORMAT(_From) \ template<_From T, typename CharT> \ template \ - requires(stormkit::meta::IsStrict>) \ + requires(stormkit::meta::SameAs>) \ inline auto std::formatter::format(U&& data, FormatContext& ctx) const noexcept -> decltype(ctx.out()) #define FORMATTER_INHERIT_DEFINE_FORMAT_AS_STRING(_Parent, _From) \ FORMATTER_INHERIT_DEFINE_FORMAT(_From) { \ - return formatter<_Parent, CharT>::format(stormkit::as(std::forward(data)), ctx); \ + return formatter<_Parent, CharT>::format(stormkit::as(std::forward(data)), ctx); \ } #define FORMATTER_DEFINE_FORMAT_AS_STRING(_From) \ @@ -53,7 +53,7 @@ return ctx.begin(); \ } \ FORMATTER_DEFINE_FORMAT(_From) { \ - return std::format_to(ctx.out(), "{}", stormkit::as(std::forward(data))); \ + return std::format_to(ctx.out(), "{}", stormkit::as(std::forward(data))); \ } #define FORMATTER(_From) \ diff --git a/include/stormkit/core/hash_macro.hpp b/include/stormkit/core/hash_macro.hpp deleted file mode 100644 index 412e70df6..000000000 --- a/include/stormkit/core/hash_macro.hpp +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (C) 2022 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -#ifndef STORMKIT_HASH_MACRO_HPP -#define STORMKIT_HASH_MACRO_HPP - -#include - -/// \brief `HASH_FUNC` declare hash func and define an operator== for a given `x` type -#define HASH_FUNC(x, ...) \ - template<> \ - struct std::hash { \ - [[nodiscard]] \ - auto operator()(const x& value) const noexcept -> stormkit::hash64 { \ - auto hash = stormkit::hash64 { 0 }; \ - stormkit::hash_combine(hash, __VA_ARGS__); \ - return hash; \ - } \ - }; - -#define CONSTRAINED_HASH_FUNC(x, ...) \ - template \ - struct std::hash { \ - [[nodiscard]] \ - auto operator()(const T& value) const noexcept -> stormkit::hash64 { \ - auto hash = stormkit::hash64 { 0 }; \ - stormkit::hash_combine(hash, __VA_ARGS__); \ - return hash; \ - } \ - }; - -#define TEMPLATED_HASH_FUNC(x, z, y, ...) \ - template \ - struct std::hash> { \ - [[nodiscard]] \ - auto operator()(const x& value) const noexcept -> stormkit::hash64 { \ - auto hash = stormkit::hash64 { 0 }; \ - stormkit::hash_combine(hash, __VA_ARGS__); \ - return hash; \ - } \ - }; - -#define EQUAL_FUNC(x) \ - template<> \ - struct std::equal_to { \ - [[nodiscard]] \ - constexpr auto operator()(const x& first, const x& second) const noexcept -> bool { \ - const auto hasher = std::hash {}; \ - return hasher(first) == hasher(second); \ - } \ - }; - -#define CONSTRAINED_EQUAL_FUNC(x) \ - template \ - struct std::equal_to { \ - [[nodiscard]] \ - constexpr auto operator()(const T& first, const T& second) const noexcept -> bool { \ - const auto hasher = std::hash {}; \ - return hasher(first) == hasher(second); \ - } \ - }; - -#define TEMPLATED_EQUAL_FUNC(x, z, y) \ - template \ - struct std::equal_to> { \ - [[nodiscard]] \ - constexpr auto operator()(const x& first, const x& second) const noexcept -> bool { \ - const auto hasher = std::hash> {}; \ - return hasher(first) == hasher(second); \ - } \ - }; - -#define HASH_EQUAL_FUNC(x, ...) \ - HASH_FUNC(x, __VA_ARGS__) \ - EQUAL_FUNC(x) - -#define CONSTRAINED_HASH_EQUAL_FUNC(x, ...) \ - CONSTRAINED_HASH_FUNC(x, __VA_ARGS__) \ - CONSTRAINED_EQUAL_FUNC(x) - -#define TEMPLATED_HASH_EQUAL_FUNC(x, z, y, ...) \ - TEMPLATED_HASH_FUNC(x, z, y, __VA_ARGS__) \ - TEMPLATED_EQUAL_FUNC(x, z, y) -#endif diff --git a/include/stormkit/core/platform_macro.hpp b/include/stormkit/core/platform_macro.hpp index d9068d4cf..068042f00 100644 --- a/include/stormkit/core/platform_macro.hpp +++ b/include/stormkit/core/platform_macro.hpp @@ -17,8 +17,9 @@ #error "Stormkit need a c++ compiler" #endif -#define STORMKIT_STRINGIFY_DETAILS(x) #x -#define STORMKIT_STRINGIFY(x) STORMKIT_STRINGIFY_DETAILS(x) +#define STORMKIT_STRINGIFY_DETAILS(x) #x +#define STORMKIT_STRINGIFY(x) STORMKIT_STRINGIFY_DETAILS(x) +#define STORMKIT_PRAGMA_FROM_STRING(x) _Pragma(STORMKIT_STRINGIFY(x)) #if defined(_MSC_VER) and not defined(__clang__) #pragma warning(disable: 4251) @@ -30,12 +31,16 @@ #define STORMKIT_IMPORT __declspec(dllimport) #define STORMKIT_RESTRICT __restrict #define STORMKIT_PRIVATE - #define STORMKIT_FORCE_INLINE_IMPL [[msvc::forceinline]] - #define STORMKIT_INTRINSIC [[msvc::intrinsic]] - #define STORMKIT_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]] - #define STORMKIT_PUSH_WARNINGS _Pragma("warning(push)") - #define STORMKIT_POP_WARNINGS _Pragma("warning(pop))") - #define STORMKIT_ARRAY_IF_MSVC std::array + #define STORMKIT_FORCE_INLINE_IMPL [[msvc::forceinline]] + #define STORMKIT_INTRINSIC [[msvc::intrinsic]] + #define STORMKIT_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]] + #define STORMKIT_PUSH_WARNINGS _Pragma("warning(push)") + #define STORMKIT_WARNING_IGNORE_MSVC_IMPL(warning_) _Pragma(#warning_) + //clang-format off + #define STORMKIT_WARNING_IGNORE_MSVC(value) STORMKIT_WARNING_IGNORE_MSVC_IMPL(warning(disable : value)) + //clang-format on + #define STORMKIT_POP_WARNINGS _Pragma("warning(pop)") + #define STORMKIT_ARRAY_IF_MSVC array #elif defined(_MSC_VER) and defined(__clang__) #if defined(_LIBCPP_VERSION) #define STORMKIT_COMPILER_LIBCPP "libc++" @@ -44,13 +49,16 @@ #else #define STORMKIT_COMPILER_MSSTL "MSSTL" #define STORMKIT_COMPILER_CXXLIB STORMKIT_COMPILER_MSSTL - #define STORMKIT_ARRAY_IF_MSVC std::array + #define STORMKIT_ARRAY_IF_MSVC array #endif - #define STORMKIT_EXPORT __declspec(dllexport) - #define STORMKIT_IMPORT __declspec(dllimport) - #define STORMKIT_PRIVATE [[gnu::visibility("hidden")]] - #define STORMKIT_RESTRICT __restrict - #define STORMKIT_FORCE_INLINE_IMPL [[gnu::always_inline]] + #define STORMKIT_EXPORT __declspec(dllexport) + #define STORMKIT_IMPORT __declspec(dllimport) + #define STORMKIT_PRIVATE [[gnu::visibility("hidden")]] + #define STORMKIT_RESTRICT __restrict + //clang-format off + #define STORMKIT_WARNING_IGNORE_MSVC(value) STORMKIT_PRAGMA_FROM_STRING(warning(disable : value)) + //clang-format on + #define STORMKIT_FORCE_INLINE_IMPL [[gnu::always_inline]] #define STORMKIT_INTRINSIC #define STORMKIT_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]] #elif defined(__MINGW32__) @@ -97,32 +105,34 @@ #define STORMKIT_LIFETIMEBOUND #endif -#if not defined(STORMKIT_COMPILER_MSVC) - #if __has_cpp_attribute(gnu::pure) - #define STORMKIT_PURE [[gnu::pure]] - #else - #define STORMKIT_PURE - #endif +#if __has_cpp_attribute(clang::guarded_by) + #define STORMKIT_GUARDED_BY(x) [[clang::guarded_by(x)]] +#else + #define STORMKIT_GUARDED_BY(_) +#endif + +#if __has_cpp_attribute(gnu::pure) + #define STORMKIT_PURE [[gnu::pure]] #else #define STORMKIT_PURE #endif -#if not defined(STORMKIT_COMPILER_MSVC) - #if __has_cpp_attribute(gnu::const) - #define STORMKIT_CONST [[gnu::const]] - #else - #define STORMKIT_CONST - #endif +#if __has_cpp_attribute(gnu::const) + #define STORMKIT_CONST [[gnu::const]] #else #define STORMKIT_CONST #endif -#define STORMKIT_FORCE_INLINE STORMKIT_FORCE_INLINE_IMPL +// #if defined(STORMKIT_BUILD_DEBUG) +#define STORMKIT_FORCE_INLINE +// #else +// #define STORMKIT_FORCE_INLINE STORMKIT_FORCE_INLINE_IMPL +// #endif #if defined(__MINGW32__) #define STORMKIT_COMPILER STORMKIT_COMPILER_MINGW #if defined(__clang__) - #define STORMKIT_COMPILER_CLANG std::string { "MinGW Clang " } + __clang_version__ + #define STORMKIT_COMPILER_CLANG string { "MinGW Clang " } + __clang_version__ #define STORMKIT_COMPILER STORMKIT_COMPILER_CLANG #define STORMKIT_PUSH_WARNINGS _Pragma("clang diagnostic push") #define STORMKIT_POP_WARNINGS _Pragma("clang diagnostic pop") @@ -141,18 +151,28 @@ #endif #define STORMKIT_COMPILER_MINGW STORMKIT_COMPILER #elif defined(__clang__) - #define STORMKIT_COMPILER_CLANG std::string { "Clang " } + __clang_version__ + #define STORMKIT_COMPILER_CLANG string { "Clang " } + __clang_version__ #define STORMKIT_COMPILER STORMKIT_COMPILER_CLANG #define STORMKIT_PUSH_WARNINGS _Pragma("clang diagnostic push") - #define STORMKIT_POP_WARNINGS _Pragma("clang diagnostic pop") + #define STORMKIT_WARNING_IGNORE_GCC(_) + #define STORMKIT_WARNING_IGNORE_MSVC(_) + #define STORMKIT_WARNING_IGNORE_CLANG(warning) STORMKIT_PRAGMA_FROM_STRING(clang diagnostic ignore warning) + #define STORMKIT_POP_WARNINGS _Pragma("clang diagnostic pop") #elif defined(__GNUC__) or defined(__GNUG__) #define STORMKIT_COMPILER_GCC \ "GCC " + std::to_string(__GNUC__) + "." + std::to_string(__GNUC_MINOR__) + "." + "." + std::to_string(__GNUC_PATCHLEVEL__) #define STORMKIT_COMPILER STORMKIT_COMPILER_GCC #define STORMKIT_PUSH_WARNINGS _Pragma("GCC diagnostic push") - #define STORMKIT_POP_WARNINGS _Pragma("GCC diagnostic pop") + #define STORMKIT_WARNING_IGNORE_CLANG(_) + #define STORMKIT_WARNING_IGNORE_MSVC(_) + #define STORMKIT_WARNING_IGNORE_GCC(warning) STORMKIT_PRAGMA_FROM_STRING(GCC diagnostic ignored warning) + #define STORMKIT_POP_WARNINGS _Pragma("GCC diagnostic pop") #endif +#define STORMKIT_WARNING_IGNORE_GCC_CLANG(warning) \ + STORMKIT_WARNING_IGNORE_GCC(warning) \ + STORMKIT_WARNING_IGNORE_CLANG(warning) + #if defined(__SWITCH__) #define STORMKIT_OS_NX "Nintendo Switch" #define STORMKIT_BITS_64 diff --git a/include/stormkit/core/try_expected.hpp b/include/stormkit/core/try_expected.hpp index f1ab7250d..e2b83a4b2 100644 --- a/include/stormkit/core/try_expected.hpp +++ b/include/stormkit/core/try_expected.hpp @@ -5,20 +5,60 @@ #ifndef STORMKIT_TRY_EXPECTED_HPP #define STORMKIT_TRY_EXPECTED_HPP +#include + #if (defined(__clang__) or defined(__GNUC__)) - #define Try(m) \ - ({ \ - auto res = (m); \ - if (!res.has_value()) [[unlikely]] \ - return std::unexpected { res.error() }; \ - std::move(res).value(); \ + #define Try(m) \ + ({ \ + auto res = (m); \ + if (not res.has_value()) [[unlikely]] \ + return std::unexpected { std::move(res).error() }; \ + std::move(res).value(); \ + }) + #define TryOr(m, t) \ + ({ \ + auto res = (m); \ + if (not res.has_value()) [[unlikely]] \ + t(std::move(res).error()); \ + std::move(res).value(); \ + }) + #define TryTransformError(m, t) \ + ({ \ + auto res = (m); \ + if (not res.has_value()) [[unlikely]] \ + return std::unexpected { t(std::move(res).error()) }; \ + std::move(res).value(); \ + }) + + #define TryDiscard(m) \ + ({ \ + auto res = (m).transform(stormkit::core::monadic::discard()); \ + if (not res.has_value()) [[unlikely]] \ + return std::unexpected { std::move(res).error() }; \ }) - #define Ret(x) return x - #define RetErr(x) return std::unexpected { x }; + #define TryDiscardOr(m, t) \ + ({ \ + auto res = (m).transform(stormkit::core::monadic::discard()); \ + if (not res.has_value()) [[unlikely]] \ + t(std::move(res).error()); \ + }) + #define TryDiscardTransformError(m, t) \ + ({ \ + auto res = (m).transform(stormkit::core::monadic::discard()); \ + if (not res.has_value()) [[unlikely]] \ + return std::unexpected { t(std::move(res).error()) }; \ + }) + + #define Return return #else - #define Try(x) co_await x - #define Ret(x) co_return x - #define RetErr(x) co_return std::unexpected { x }; + #define Try(m) co_await m + #define TryOr(m, t) co_await m.transform_error(t) + #define TryTransformError(m, t) TryOr(m, t) + #define TryDiscard(m) co_await m.transform(stormkit::core::monadic::discard()) + #define TryDiscardOr(m, t) co_await m.transform(stormkit::core::monadic::discard()).transform_error(t) + #define TryDiscardTransformError(m, t) TryDiscardOr(m, t) + #define Return co_return #endif - +#define TryAssert(m, msg) TryOr(m, stormkit::core::monadic::assert(msg)) +#define TryDiscardAssert(m, msg) TryDiscardOr(m, stormkit::core::monadic::assert(msg)) #endif diff --git a/include/stormkit/entities/api.hpp b/include/stormkit/entities/api.hpp new file mode 100644 index 000000000..be8909415 --- /dev/null +++ b/include/stormkit/entities/api.hpp @@ -0,0 +1,16 @@ +// Copryright (C) 2022 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +#ifndef STORMKIT_ENTITIES_API_HPP +#define STORMKIT_ENTITIES_API_HPP + +#include + +#ifdef STORMKIT_ENTITIES_BUILD + #define STORMKIT_ENTITIES_API STORMKIT_EXPORT +#else + #define STORMKIT_ENTITIES_API STORMKIT_IMPORT +#endif + +#endif diff --git a/include/stormkit/gpu/api.hpp b/include/stormkit/gpu/api.hpp new file mode 100644 index 000000000..2c8e37bbe --- /dev/null +++ b/include/stormkit/gpu/api.hpp @@ -0,0 +1,16 @@ +// Copryright (C) 2022 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +#ifndef STORMKIT_GPU_API_HPP +#define STORMKIT_GPU_API_HPP + +#include + +#ifdef STORMKIT_GPU_BUILD + #define STORMKIT_GPU_API STORMKIT_EXPORT +#else + #define STORMKIT_GPU_API STORMKIT_IMPORT +#endif + +#endif diff --git a/include/stormkit/image/api.hpp b/include/stormkit/image/api.hpp new file mode 100644 index 000000000..fb762c298 --- /dev/null +++ b/include/stormkit/image/api.hpp @@ -0,0 +1,16 @@ +// Copryright (C) 2022 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +#ifndef STORMKIT_IMAGE_API_HPP +#define STORMKIT_IMAGE_API_HPP + +#include + +#ifdef STORMKIT_IMAGE_BUILD + #define STORMKIT_IMAGE_API STORMKIT_EXPORT +#else + #define STORMKIT_IMAGE_API STORMKIT_IMPORT +#endif + +#endif diff --git a/include/stormkit/log/api.hpp b/include/stormkit/log/api.hpp new file mode 100644 index 000000000..2977bbc8a --- /dev/null +++ b/include/stormkit/log/api.hpp @@ -0,0 +1,16 @@ +// Copryright (C) 2022 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +#ifndef STORMKIT_LOG_API_HPP +#define STORMKIT_LOG_API_HPP + +#include + +#ifdef STORMKIT_LOG_BUILD + #define STORMKIT_LOG_API STORMKIT_EXPORT +#else + #define STORMKIT_LOG_API STORMKIT_IMPORT +#endif + +#endif diff --git a/include/stormkit/log/log_macro.hpp b/include/stormkit/log/log_macro.hpp index 779efd554..83edcd346 100644 --- a/include/stormkit/log/log_macro.hpp +++ b/include/stormkit/log/log_macro.hpp @@ -9,55 +9,62 @@ #define NAMED_LOGGER(NAME, module_chars) \ namespace { \ + [[maybe_unused]] \ constexpr auto NAME = stormkit::log::Module { module_chars }; \ } -#define LOGGER(module) \ - NAMED_LOGGER(LOG_MODULE, module) \ - template \ - STORMKIT_FORCE_INLINE inline auto dlog(Args&&... args) noexcept -> void { \ - LOG_MODULE.dlog(std::forward(args)...); \ - } \ - template \ - STORMKIT_FORCE_INLINE inline auto ilog(Args&&... args) noexcept -> void { \ - LOG_MODULE.ilog(std::forward(args)...); \ - } \ - template \ - STORMKIT_FORCE_INLINE inline auto wlog(Args&&... args) noexcept -> void { \ - LOG_MODULE.wlog(std::forward(args)...); \ - } \ - template \ - STORMKIT_FORCE_INLINE inline auto elog(Args&&... args) noexcept -> void { \ - LOG_MODULE.elog(std::forward(args)...); \ - } \ - template \ - STORMKIT_FORCE_INLINE inline auto flog(Args&&... args) noexcept -> void { \ - LOG_MODULE.flog(std::forward(args)...); \ +#define LOGGER_FUNC(LOG_MODULE) \ + template \ + STORMKIT_FORCE_INLINE inline auto dlog(std::format_string format_string, Args&&... args) noexcept -> void { \ + LOG_MODULE.dlog(std::move(format_string), std::forward(args)...); \ + } \ + template \ + STORMKIT_FORCE_INLINE inline auto ilog(std::format_string format_string, Args&&... args) noexcept -> void { \ + LOG_MODULE.ilog(std::move(format_string), std::forward(args)...); \ + } \ + template \ + STORMKIT_FORCE_INLINE inline auto wlog(std::format_string format_string, Args&&... args) noexcept -> void { \ + LOG_MODULE.wlog(std::move(format_string), std::forward(args)...); \ + } \ + template \ + STORMKIT_FORCE_INLINE inline auto elog(std::format_string format_string, Args&&... args) noexcept -> void { \ + LOG_MODULE.elog(std::move(format_string), std::forward(args)...); \ + } \ + template \ + STORMKIT_FORCE_INLINE inline auto flog(std::format_string format_string, Args&&... args) noexcept -> void { \ + LOG_MODULE.flog(std::move(format_string), std::forward(args)...); \ + } \ + template \ + STORMKIT_FORCE_INLINE inline auto dlog_runtime(std::string_view format_string, Args&&... args) noexcept -> void { \ + LOG_MODULE.dlog_runtime(std::move(format_string), std::forward(args)...); \ + } \ + template \ + STORMKIT_FORCE_INLINE inline auto ilog_runtime(std::string_view format_string, Args&&... args) noexcept -> void { \ + LOG_MODULE.ilog_runtime(std::move(format_string), std::forward(args)...); \ + } \ + template \ + STORMKIT_FORCE_INLINE inline auto wlog_runtime(std::string_view format_string, Args&&... args) noexcept -> void { \ + LOG_MODULE.wlog_runtime(std::move(format_string), std::forward(args)...); \ + } \ + template \ + STORMKIT_FORCE_INLINE inline auto elog_runtime(std::string_view format_string, Args&&... args) noexcept -> void { \ + LOG_MODULE.elog_runtime(std::move(format_string), std::forward(args)...); \ + } \ + template \ + STORMKIT_FORCE_INLINE inline auto flog_runtime(std::string_view format_string, Args&&... args) noexcept -> void { \ + LOG_MODULE.flog_runtime(std::move(format_string), std::forward(args)...); \ } -#define IN_MODULE_NAMED_LOGGER(NAME, module_chars) inline constexpr auto NAME = stormkit::log::Module { module_chars }; - -#define IN_MODULE_LOGGER(module) \ - IN_MODULE_NAMED_LOGGER(LOG_MODULE, module) \ - template \ - STORMKIT_FORCE_INLINE inline auto dlog(Args&&... args) noexcept -> void { \ - LOG_MODULE.dlog(std::forward(args)...); \ - } \ - template \ - STORMKIT_FORCE_INLINE inline auto ilog(Args&&... args) noexcept -> void { \ - LOG_MODULE.ilog(std::forward(args)...); \ - } \ - template \ - STORMKIT_FORCE_INLINE inline auto wlog(Args&&... args) noexcept -> void { \ - LOG_MODULE.wlog(std::forward(args)...); \ - } \ - template \ - STORMKIT_FORCE_INLINE inline auto elog(Args&&... args) noexcept -> void { \ - LOG_MODULE.elog(std::forward(args)...); \ - } \ - template \ - STORMKIT_FORCE_INLINE inline auto flog(Args&&... args) noexcept -> void { \ - LOG_MODULE.flog(std::forward(args)...); \ - } +#define LOGGER(module) \ + NAMED_LOGGER(LOG_MODULE, module) \ + LOGGER_FUNC(LOG_MODULE) + +#define IN_MODULE_NAMED_LOGGER(NAME, module_chars) \ + [[maybe_unused]] \ + inline constexpr auto NAME = stormkit::log::Module { module_chars }; + +#define IN_MODULE_LOGGER(module) \ + IN_MODULE_NAMED_LOGGER(LOG_MODULE, module) \ + LOGGER_FUNC(LOG_MODULE) #endif diff --git a/include/stormkit/lua/api.hpp b/include/stormkit/lua/api.hpp new file mode 100644 index 000000000..aeb00feed --- /dev/null +++ b/include/stormkit/lua/api.hpp @@ -0,0 +1,16 @@ +// Copryright (C) 2022 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +#ifndef STORMKIT_LUA_API_HPP +#define STORMKIT_LUA_API_HPP + +#include + +#ifdef STORMKIT_LUA_BUILD + #define STORMKIT_LUA_API STORMKIT_EXPORT +#else + #define STORMKIT_LUA_API STORMKIT_IMPORT +#endif + +#endif diff --git a/include/stormkit/lua/lua.hpp b/include/stormkit/lua/lua.hpp new file mode 100644 index 000000000..7228ee045 --- /dev/null +++ b/include/stormkit/lua/lua.hpp @@ -0,0 +1,33 @@ +#ifndef STORMKIT_LUA_HPP +#define STORMKIT_LUA_HPP + +#include + +#include + +STORMKIT_PUSH_WARNINGS + +#define LUA_API extern "C" STORMKIT_LUA_API +#define LUACODE_API extern "C" STORMKIT_LUA_API +#define LUACODEGEN_API extern "C" STORMKIT_LUA_API + +extern "C" { +#include + +#include +#include +} + +// #pragma clang diagnostic ignored "-Wdeprecated-declarations" +#define SOL_USING_CXX_LUA 0 +#define SOL_NO_LUA_HPP 1 +#define SOL_USE_LUAU 1 +#define SOL_SAFE_STACK_CHECK 1 +#define SOL_LUA_BIT32_LIB 1 +#define LUA_VERSION_NUM 501 +#include +#undef assert + +STORMKIT_POP_WARNINGS + +#endif diff --git a/include/stormkit/wsi/api.hpp b/include/stormkit/wsi/api.hpp new file mode 100644 index 000000000..e9b56cf3d --- /dev/null +++ b/include/stormkit/wsi/api.hpp @@ -0,0 +1,16 @@ +// Copryright (C) 2022 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +#ifndef STORMKIT_WSI_API_HPP +#define STORMKIT_WSI_API_HPP + +#include + +#ifdef STORMKIT_WSI_BUILD + #define STORMKIT_WSI_API STORMKIT_EXPORT +#else + #define STORMKIT_WSI_API STORMKIT_IMPORT +#endif + +#endif diff --git a/modules/stormkit.mpp b/modules/stormkit.cppm similarity index 54% rename from modules/stormkit.mpp rename to modules/stormkit.cppm index 9eb2ba2d8..717b4c732 100644 --- a/modules/stormkit.mpp +++ b/modules/stormkit.cppm @@ -12,20 +12,22 @@ import std; export module stormkit; export import stormkit.core; -export import stormkit.main; -#ifdef STORMKIT_LIB_LOG_ENABLED +#if STORMKIT_LIB_LOG_ENABLED and defined(STORMKIT_IMPORT_LOG) export import stormkit.log; #endif -#ifdef STORMKIT_LIB_ENTITIES_ENABLED +#if STORMKIT_LIB_ENTITIES_ENABLED and defined(STORMKIT_IMPORT_ENTITIES) export import stormkit.entities; #endif -#ifdef STORMKIT_LIB_IMAGE_ENABLED +#if STORMKIT_LIB_IMAGE_ENABLED and defined(STORMKIT_IMPORT_IMAGE) export import stormkit.image; #endif -#ifdef STORMKIT_LIB_WSI_ENABLED +#if STORMKIT_LIB_WSI_ENABLED and defined(STORMKIT_IMPORT_WSI) export import stormkit.wsi; #endif -#ifdef STORMKIT_LIB_GPU_ENABLED +#if STORMKIT_LIB_GPU_ENABLED and defined(STORMKIT_IMPORT_GPU) export import stormkit.gpu; #endif +#if STORMKIT_LIB_LUA_ENABLED and defined(STORMKIT_IMPORT_LUA) +export import stormkit.lua; +#endif diff --git a/modules/stormkit/core.mpp b/modules/stormkit/core.cppm similarity index 93% rename from modules/stormkit/core.mpp rename to modules/stormkit/core.cppm index 00bbfad9b..22860b658 100644 --- a/modules/stormkit/core.mpp +++ b/modules/stormkit/core.cppm @@ -1,21 +1,22 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -export module stormkit.core; - -import std.compat; - -export import :config; -export import :containers; -export import :console; -export import :coroutines; -export import :functional; -export import :errors; -export import :hash; -export import :meta; -export import :math; -export import :parallelism; -export import :string; -export import :typesafe; -export import :utils; +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +export module stormkit.core; + +import std.compat; + +export import :config; +export import :containers; +export import :console; +export import :coroutines; +export import :functional; +export import :errors; +export import :hash; +export import :meta; +export import :named_constructors; +export import :math; +export import :parallelism; +export import :string; +export import :typesafe; +export import :utils; diff --git a/modules/stormkit/core/config.mpp b/modules/stormkit/core/config.cppm similarity index 96% rename from modules/stormkit/core/config.mpp rename to modules/stormkit/core/config.cppm index 9edb9fbae..cea2c8eaf 100644 --- a/modules/stormkit/core/config.mpp +++ b/modules/stormkit/core/config.cppm @@ -1,23 +1,23 @@ -// Copyright (C) 2021 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -export module stormkit.core:config; - -import std; - -#if defined(__clang__) - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Winclude-angled-in-module-purview" -#elif defined(_MSC_VER) - #pragma warning(push) - #pragma warning(disable: 5244) -#endif -#define _STORMKIT_EXPORT export -#include -#if defined(__clang__) - #pragma clang diagnostic push - #pragma clang diagnostic ignored "-Winclude-angled-in-module-purview" -#elif defined(_MSC_VER) - #pragma warning(pop) -#endif +// Copyright (C) 2021 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +export module stormkit.core:config; + +import std; + +#if defined(__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Winclude-angled-in-module-purview" +#elif defined(_MSC_VER) + #pragma warning(push) + #pragma warning(disable: 5244) +#endif +#define _STORMKIT_EXPORT export +#include +#if defined(__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Winclude-angled-in-module-purview" +#elif defined(_MSC_VER) + #pragma warning(pop) +#endif diff --git a/modules/stormkit/core/console.mpp b/modules/stormkit/core/console.cppm similarity index 100% rename from modules/stormkit/core/console.mpp rename to modules/stormkit/core/console.cppm diff --git a/modules/stormkit/core/console/io.mpp b/modules/stormkit/core/console/io.cppm similarity index 100% rename from modules/stormkit/core/console/io.mpp rename to modules/stormkit/core/console/io.cppm diff --git a/modules/stormkit/core/console/style.mpp b/modules/stormkit/core/console/style.cppm similarity index 52% rename from modules/stormkit/core/console/style.mpp rename to modules/stormkit/core/console/style.cppm index 5424cc3eb..4160b96cb 100644 --- a/modules/stormkit/core/console/style.mpp +++ b/modules/stormkit/core/console/style.cppm @@ -52,7 +52,7 @@ export { template struct Stylized { - constexpr auto render() const noexcept -> std::string; + constexpr auto render() const noexcept -> string; constexpr auto render_into(stdr::output_range auto& out) const noexcept -> void; T value; @@ -78,17 +78,65 @@ export { inline constexpr auto CYAN_TEXT_STYLE = ConsoleStyle { .fg = ConsoleColor::CYAN }; inline constexpr auto WHITE_TEXT_STYLE = ConsoleStyle { .fg = ConsoleColor::WHITE }; inline constexpr auto BLACK_TEXT_STYLE = ConsoleStyle { .fg = ConsoleColor::BLACK }; + + namespace ecma48 { + inline constexpr auto FOREGROUND = frozen::make_unordered_map({ + { ConsoleColor::BLACK, "\x1B[30m" }, + { ConsoleColor::RED, "\x1B[31m" }, + { ConsoleColor::GREEN, "\x1B[32m" }, + { ConsoleColor::YELLOW, "\x1B[33m" }, + { ConsoleColor::BLUE, "\x1B[34m" }, + { ConsoleColor::MAGENTA, "\x1B[35m" }, + { ConsoleColor::CYAN, "\x1B[36m" }, + { ConsoleColor::WHITE, "\x1B[37m" }, + { ConsoleColor::BRIGHT_BLACK, "\x1B[90m" }, + { ConsoleColor::BRIGHT_RED, "\x1B[91m" }, + { ConsoleColor::BRIGHT_GREEN, "\x1B[92m" }, + { ConsoleColor::BRIGHT_YELLOW, "\x1B[93m" }, + { ConsoleColor::BRIGHT_BLUE, "\x1B[94m" }, + { ConsoleColor::BRIGHT_MAGENTA, "\x1B[95m" }, + { ConsoleColor::BRIGHT_CYAN, "\x1B[96m" }, + { ConsoleColor::BRIGHT_WHITE, "\x1B[97m" }, + }); + + inline constexpr auto BACKGROUND = frozen::make_unordered_map({ + { ConsoleColor::BLACK, "\x1B[40m" }, + { ConsoleColor::RED, "\x1B[41m" }, + { ConsoleColor::GREEN, "\x1B[42m" }, + { ConsoleColor::YELLOW, "\x1B[43m" }, + { ConsoleColor::BLUE, "\x1B[44m" }, + { ConsoleColor::MAGENTA, "\x1B[45m" }, + { ConsoleColor::CYAN, "\x1B[46m" }, + { ConsoleColor::WHITE, "\x1B[47m" }, + { ConsoleColor::BRIGHT_BLACK, "\x1B[100m" }, + { ConsoleColor::BRIGHT_RED, "\x1B[101m" }, + { ConsoleColor::BRIGHT_GREEN, "\x1B[102m" }, + { ConsoleColor::BRIGHT_YELLOW, "\x1B[103m" }, + { ConsoleColor::BRIGHT_BLUE, "\x1B[104m" }, + { ConsoleColor::BRIGHT_MAGENTA, "\x1B[105m" }, + { ConsoleColor::BRIGHT_CYAN, "\x1B[106m" }, + { ConsoleColor::BRIGHT_WHITE, "\x1B[107m" }, + }); + + inline constexpr auto RESET = "\x1B[0m"sv; + inline constexpr auto BOLD = "\x1B[1m"sv; + inline constexpr auto FAINT = "\x1B[2m"sv; + inline constexpr auto ITALIC = "\x1B[3m"sv; + inline constexpr auto UNDERLINE = "\x1B[4m"sv; + inline constexpr auto INVERSE = "\x1B[7m"sv; + } // namespace ecma48 + + template + auto format_as(const ConsoleStyle& style, FormatContext& ctx) noexcept -> decltype(ctx.out()); }} // namespace stormkit::core FLAG_ENUM(stormkit::core::StyleModifier) namespace std { template - struct formatter, CharT> - : formatter, CharT> { + struct formatter, CharT>: formatter, CharT> { template - auto format(const stormkit::core::Stylized& stylized, - FormatContext& ctx) const noexcept -> decltype(ctx.out()); + auto format(const stormkit::core::Stylized& stylized, FormatContext& ctx) const noexcept -> decltype(ctx.out()); }; } // namespace std } @@ -100,53 +148,6 @@ export { using namespace std::literals; namespace stormkit { inline namespace core { - namespace { namespace ecma48 { - constexpr auto FOREGROUND = frozen::make_unordered_map({ - { ConsoleColor::BLACK, "\x1B[30m" }, - { ConsoleColor::RED, "\x1B[31m" }, - { ConsoleColor::GREEN, "\x1B[32m" }, - { ConsoleColor::YELLOW, "\x1B[33m" }, - { ConsoleColor::BLUE, "\x1B[34m" }, - { ConsoleColor::MAGENTA, "\x1B[35m" }, - { ConsoleColor::CYAN, "\x1B[36m" }, - { ConsoleColor::WHITE, "\x1B[37m" }, - { ConsoleColor::BRIGHT_BLACK, "\x1B[90m" }, - { ConsoleColor::BRIGHT_RED, "\x1B[91m" }, - { ConsoleColor::BRIGHT_GREEN, "\x1B[92m" }, - { ConsoleColor::BRIGHT_YELLOW, "\x1B[93m" }, - { ConsoleColor::BRIGHT_BLUE, "\x1B[94m" }, - { ConsoleColor::BRIGHT_MAGENTA, "\x1B[95m" }, - { ConsoleColor::BRIGHT_CYAN, "\x1B[96m" }, - { ConsoleColor::BRIGHT_WHITE, "\x1B[97m" }, - }); - - constexpr auto BACKGROUND = frozen::make_unordered_map({ - { ConsoleColor::BLACK, "\x1B[40m" }, - { ConsoleColor::RED, "\x1B[41m" }, - { ConsoleColor::GREEN, "\x1B[42m" }, - { ConsoleColor::YELLOW, "\x1B[43m" }, - { ConsoleColor::BLUE, "\x1B[44m" }, - { ConsoleColor::MAGENTA, "\x1B[45m" }, - { ConsoleColor::CYAN, "\x1B[46m" }, - { ConsoleColor::WHITE, "\x1B[47m" }, - { ConsoleColor::BRIGHT_BLACK, "\x1B[100m" }, - { ConsoleColor::BRIGHT_RED, "\x1B[101m" }, - { ConsoleColor::BRIGHT_GREEN, "\x1B[102m" }, - { ConsoleColor::BRIGHT_YELLOW, "\x1B[103m" }, - { ConsoleColor::BRIGHT_BLUE, "\x1B[104m" }, - { ConsoleColor::BRIGHT_MAGENTA, "\x1B[105m" }, - { ConsoleColor::BRIGHT_CYAN, "\x1B[106m" }, - { ConsoleColor::BRIGHT_WHITE, "\x1B[107m" }, - }); - - constexpr auto RESET = "\x1B[0m"sv; - constexpr auto BOLD = "\x1B[1m"sv; - constexpr auto FAINT = "\x1B[2m"sv; - constexpr auto ITALIC = "\x1B[3m"sv; - constexpr auto UNDERLINE = "\x1B[4m"sv; - constexpr auto INVERSE = "\x1B[7m"sv; - }} // namespace ::ecma48 - ///////////////////////////////////// ///////////////////////////////////// template @@ -158,13 +159,11 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// template - constexpr auto Stylized::render() const noexcept -> std::string { - auto out = std::string {}; + constexpr auto Stylized::render() const noexcept -> string { + auto out = string {}; const auto size = [this] noexcept { if constexpr (requires { stdr::size(value); }) return stdr::size(value); - else if constexpr (requires { - std::char_traits>::length(value); - }) + else if constexpr (requires { std::char_traits>::length(value); }) return std::char_traits>::length(value); else { (void)this; @@ -179,8 +178,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// template - constexpr auto Stylized::render_into(stdr::output_range auto& out) const noexcept - -> void { + constexpr auto Stylized::render_into(stdr::output_range auto& out) const noexcept -> void { if (fg) out.append_range(ecma48::FOREGROUND.at(*fg)); if (bg) out.append_range(ecma48::BACKGROUND.at(*bg)); if (check_flag_bit(modifiers, StyleModifier::BOLD)) out.append(ecma48::BOLD); @@ -188,12 +186,51 @@ namespace stormkit { inline namespace core { if (check_flag_bit(modifiers, StyleModifier::ITALIC)) out.append(ecma48::ITALIC); if (check_flag_bit(modifiers, StyleModifier::INVERSE)) out.append(ecma48::INVERSE); if (check_flag_bit(modifiers, StyleModifier::UNDERLINE)) out.append(ecma48::UNDERLINE); - if constexpr (meta::IsStringLike) out.append_range(std::string_view { value }); + if constexpr (meta::IsStringLike) out.append_range(string_view { value }); else out.append_range(std::format("{}", value)); out.append(ecma48::RESET); } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto format_as(const ConsoleStyle& style, FormatContext& ctx) noexcept -> decltype(ctx.out()) { + thread_local auto buf = array {}; + auto end = stdr::begin(buf); + + if (style.fg) { + auto [_, end_] = stdr::copy(ecma48::FOREGROUND.at(*style.fg), end); + end = end_; + } + if (style.bg) { + auto [_, end_] = stdr::copy(ecma48::BACKGROUND.at(*style.bg), end); + end = end_; + } + if (check_flag_bit(style.modifiers, StyleModifier::BOLD)) { + auto [_, end_] = stdr::copy(ecma48::BOLD, end); + end = end_; + } + if (check_flag_bit(style.modifiers, StyleModifier::FAINT)) { + auto [_, end_] = stdr::copy(ecma48::FAINT, end); + end = end_; + } + if (check_flag_bit(style.modifiers, StyleModifier::ITALIC)) { + auto [_, end_] = stdr::copy(ecma48::ITALIC, end); + end = end_; + } + if (check_flag_bit(style.modifiers, StyleModifier::INVERSE)) { + auto [_, end_] = stdr::copy(ecma48::INVERSE, end); + end = end_; + } + if (check_flag_bit(style.modifiers, StyleModifier::UNDERLINE)) { + auto [_, end_] = stdr::copy(ecma48::UNDERLINE, end); + end = end_; + } + + return std::format_to(ctx.out(), "{}", string_view { stdr::begin(buf), end }); + } }} // namespace stormkit::core using namespace stormkit; @@ -202,8 +239,7 @@ namespace std { template template STORMKIT_FORCE_INLINE - auto formatter, CharT>::format(const Stylized& stylized, - FormatContext& ctx) const noexcept + auto formatter, CharT>::format(const Stylized& stylized, FormatContext& ctx) const noexcept -> decltype(ctx.out()) { auto&& out = ctx.out(); return format_to(out, "{}", stylized.render()); diff --git a/modules/stormkit/core/containers.mpp b/modules/stormkit/core/containers.cppm similarity index 90% rename from modules/stormkit/core/containers.mpp rename to modules/stormkit/core/containers.cppm index 38bb4e972..4985b8133 100644 --- a/modules/stormkit/core/containers.mpp +++ b/modules/stormkit/core/containers.cppm @@ -7,7 +7,9 @@ export module stormkit.core:containers; export import :containers.multi_buffer; export import :containers.ringbuffer; export import :containers.tree; +export import :containers.dag; export import :containers.utils; +export import :containers.aliases; export import :containers.raii_capsule; export import :containers.shmbuffer; @@ -31,8 +33,7 @@ namespace std { //////////////////////////////////////// template template - constexpr auto formatter, CharT>::parse(ParseContext& ctx) noexcept - -> decltype(ctx.begin()) { + constexpr auto formatter, CharT>::parse(ParseContext& ctx) noexcept -> decltype(ctx.begin()) { return ctx.begin(); } @@ -40,8 +41,7 @@ namespace std { //////////////////////////////////////// template template - inline auto formatter, CharT>::format(const std::variant& variant, - FormatContext& ctx) const + inline auto formatter, CharT>::format(const std::variant& variant, FormatContext& ctx) const -> decltype(ctx.out()) { return std::visit( [&ctx](auto&& value) mutable noexcept { diff --git a/modules/stormkit/core/containers/aliases.cppm b/modules/stormkit/core/containers/aliases.cppm new file mode 100644 index 000000000..fbdfd2e16 --- /dev/null +++ b/modules/stormkit/core/containers/aliases.cppm @@ -0,0 +1,28 @@ +// Copyright (C) 2023 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +export module stormkit.core:containers.aliases; + +import std; + +namespace stdr = std::ranges; +namespace stdp = std::pmr; + +export namespace stormkit { inline namespace core { + using std::array; + + template> + using dyn_array = std::vector; + + template + using array_view = std::span; + + template> + using mdarray_view = std::mdspan; + + namespace pmr { + template + using dyn_array = std::vector>>; + } // namespace pmr +}} // namespace stormkit::core diff --git a/modules/stormkit/core/containers/dag.cppm b/modules/stormkit/core/containers/dag.cppm new file mode 100644 index 000000000..fd5acf7e2 --- /dev/null +++ b/modules/stormkit/core/containers/dag.cppm @@ -0,0 +1,608 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +#include + +#include + +export module stormkit.core:containers.dag; + +import std; + +import :typesafe.integer; +import :typesafe.byte; +import :typesafe.safecasts; +import :utils.handle; +import :utils.contract; +import :utils.std23_functional; +import :utils.filesystem; +import :string.format; + +namespace stdr = std::ranges; +namespace stdfs = std::filesystem; + +export namespace stormkit { inline namespace core { + namespace dag { + using VertexID = u32; + + struct Edge { + VertexID from; + VertexID to; + }; + + template + struct Vertex { + dag::VertexID id; + VertexValue value; + }; + } // namespace dag + + template + class DAG { + public: + using Vertex = dag::Vertex; + using ColorizeClosure = std23::function_ref; + using FormatValueClosure = std23::function_ref; + + using ValueType = Vertex; + + struct Closures { + std::optional colorize = std::nullopt; + std::optional format_value = []() static noexcept -> std::optional { + if constexpr (std::formattable) + return [](const auto& value) static noexcept { return std::format("{}", value); }; + else + return std::nullopt; + }(); + }; + + constexpr explicit DAG(std::optional reserve = std::nullopt) noexcept; + constexpr ~DAG() noexcept; + + constexpr DAG(DAG&&) noexcept; + constexpr DAG(const DAG&) noexcept = delete; + + constexpr auto operator=(DAG&&) noexcept -> DAG&; + constexpr auto operator=(const DAG&) noexcept -> DAG& = delete; + + constexpr auto directed() const noexcept -> bool; + + constexpr auto clear() noexcept -> void; + constexpr auto empty() const noexcept -> bool; + + constexpr auto add_vertex(const VertexValue& vertex) noexcept -> dag::VertexID + requires(meta::IsCopyConstructible); + constexpr auto add_vertex(VertexValue&& vertex) noexcept -> dag::VertexID + requires(meta::IsMoveConstructible); + template + constexpr auto emplace_vertex(Args&&... vertex) noexcept -> dag::VertexID + requires(meta::IsConstructible); + template + constexpr auto get_vertex_value(this Self&& self, dag::VertexID id) noexcept -> meta::ForwardLike; + constexpr auto has_vertex(const VertexValue& vertex) const noexcept -> bool + requires(meta::HasEqualityOperator); + constexpr auto has_vertex(dag::VertexID vertex) const noexcept -> bool; + constexpr auto remove_vertex(const VertexValue& vertex) noexcept -> void + requires(meta::HasEqualityOperator); + constexpr auto remove_vertex(dag::VertexID id) noexcept -> void; + + constexpr auto add_edge(dag::VertexID from, dag::VertexID to) noexcept -> void; + constexpr auto has_edge(dag::VertexID from, dag::VertexID to) const noexcept -> bool; + constexpr auto remove_edge(dag::VertexID from, dag::VertexID to) noexcept -> void; + constexpr auto adjacent_edges(dag::VertexID vertex) const noexcept -> const dyn_array&; + + constexpr auto vertices() const noexcept -> const dyn_array&; + constexpr auto vertices_count() const noexcept -> usize; + + constexpr auto edges() const noexcept -> const dyn_array&; + constexpr auto edges_count() const noexcept -> usize; + + constexpr auto topological_sort() const noexcept -> std::expected, dyn_array>; + constexpr auto find_cycle() const noexcept -> std::optional>; + + constexpr auto reverse_view() const noexcept -> DAG>; + constexpr auto reverse_clone() const noexcept -> DAG; + + constexpr auto dump(Closures closures = {}) const noexcept -> string; + + // FIXME find a way to make it not accessible to user + template + static constexpr auto reverse_from(dag::VertexID, + const dyn_array&, + const dyn_array&) noexcept -> DAG; + + private: + dag::VertexID m_next_id = 0; + + dyn_array m_vertices; + dyn_array m_edges; + dyn_array>> m_adjacent_edges; + }; + + namespace dag { + template + auto format_as(const Edge& edge, FormatContext&) noexcept -> FormatContext::iterator; + + template + auto format_as(const dag::Vertex& vertex, FormatContext&) noexcept -> FormatContext::iterator; + + [[nodiscard]] + constexpr auto to_string(const Edge& edge) noexcept -> string; + + template + [[nodiscard]] + constexpr auto to_string(const dag::Vertex& vertex) noexcept -> string; + } // namespace dag +}} // namespace stormkit::core + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit { inline namespace core { + //////////////////////////////////////// + //////////////////////////////////////// + template + constexpr DAG::DAG(std::optional reserve) noexcept { + if (reserve) m_vertices.reserve(*reserve); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + constexpr DAG::~DAG() noexcept = default; + + //////////////////////////////////////// + //////////////////////////////////////// + template + constexpr DAG::DAG(DAG&&) noexcept = default; + + //////////////////////////////////////// + //////////////////////////////////////// + template + constexpr auto DAG::operator=(DAG&&) noexcept -> DAG& = default; + + //////////////////////////////////////// + //////////////////////////////////////// + template + constexpr auto DAG::clear() noexcept -> void { + m_adjacent_edges.clear(); + m_edges.clear(); + m_vertices.clear(); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto DAG::empty() const noexcept -> bool { + return stdr::empty(m_vertices); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + constexpr auto DAG::add_vertex(const VertexValue& vertex) noexcept -> dag::VertexID + requires(meta::IsCopyConstructible) + { + const auto id = m_next_id++; + m_vertices.emplace_back(id, vertex); + m_adjacent_edges.emplace_back(id, dyn_array {}); + return id; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + constexpr auto DAG::add_vertex(VertexValue&& vertex) noexcept -> dag::VertexID + requires(meta::IsMoveConstructible) + { + const auto id = m_next_id++; + m_vertices.emplace_back(id, std::move(vertex)); + m_adjacent_edges.emplace_back(id, dyn_array {}); + return id; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template + constexpr auto DAG::emplace_vertex(Args&&... args) noexcept -> dag::VertexID + requires(meta::IsConstructible) + { + return add_vertex(VertexValue { std::forward(args)... }); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template + constexpr auto DAG::get_vertex_value(this Self&& self, dag::VertexID id) noexcept + -> meta::ForwardLike { + expects(self.has_vertex(id), std::format("Unknown DAG vertex id: {}!", id)); + + return std::forward_like(stdr::find_if(self.m_vertices, [id](const auto& other) noexcept { + return other.id == id; + })->value); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto DAG::has_vertex(const VertexValue& vertex) const noexcept -> bool + requires(meta::HasEqualityOperator) + { + return stdr::any_of(m_vertices, [&vertex](const auto& other) noexcept { return vertex == other.value; }); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto DAG::has_vertex(dag::VertexID id) const noexcept -> bool { + return stdr::any_of(m_vertices, [&id](const auto& vertex) noexcept { return vertex.id == id; }); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + constexpr auto DAG::remove_vertex(const VertexValue& vertex) noexcept -> void + requires(meta::HasEqualityOperator) + { + if constexpr (std::formattable) expects(has_vertex(vertex), "Unknown DAG vertex value: {}!", vertex); + else + expects(has_vertex(vertex), "Unknown DAG vertex value!"); + + auto it = stdr::find_if(m_vertices, [&value = vertex](const auto& vertex) noexcept { return vertex.value == value; }); + const auto id = it->id; + + remove_vertex(id); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + constexpr auto DAG::remove_vertex(dag::VertexID id) noexcept -> void { + expects(has_vertex(id), std::format("Unknown DAG vertex id: {}!", id)); + + auto touching = dyn_array {}; + for (auto&& edge : m_edges) + if (edge.from == id or edge.to == id) touching.emplace_back(edge); + + for (auto&& [from, to] : touching) remove_edge(from, to); + + auto&& [begin, end] = stdr::remove_if(m_vertices, [id](const auto& vertex) noexcept { return vertex.id == id; }); + auto&& [begin2, end2] = stdr::remove_if(m_adjacent_edges, [id](const auto& pair) noexcept { return pair.first == id; }); + + m_adjacent_edges.erase(begin2, end2); + m_vertices.erase(begin, end); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + constexpr auto DAG::add_edge(dag::VertexID from, dag::VertexID to) noexcept -> void { + expects(has_vertex(from), std::format("Unknown DAG vertex from: {}", from)); + expects(has_vertex(to), std::format("Unknown DAG vertex to: {}", to)); + if (has_edge(from, to)) return; + + const auto& edge = m_edges.emplace_back(from, to); + + auto& adjacent_edges = stdr::find_if(m_adjacent_edges, [id = from](const auto& pair) noexcept { + return pair.first == id; + })->second; + adjacent_edges.emplace_back(edge); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + constexpr auto DAG::has_edge(dag::VertexID from, dag::VertexID to) const noexcept -> bool { + if (not has_vertex(from) or not has_vertex(to)) return false; + + return stdr::any_of(m_edges, [from, to](auto&& edge) noexcept { return edge.from == from and edge.to == to; }); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + constexpr auto DAG::remove_edge(dag::VertexID from, dag::VertexID to) noexcept -> void { + expects(has_vertex(from), std::format("Unknown DAG vertex from: {}", from)); + expects(has_vertex(to), std::format("Unknown DAG vertex to: {}", to)); + + if (not has_edge(from, to)) return; + + { + auto&& [begin, end] = stdr::remove_if(m_edges, [from, to](auto&& edge) noexcept { + return edge.from == from and edge.to == to; + }); + + m_edges.erase(begin, end); + } + for (auto&& [_, edges] : m_adjacent_edges) { + auto&& [begin, end] = stdr::remove_if(edges, [from, to](auto&& edge) noexcept { + return edge.from == from and edge.to == to; + }); + edges.erase(begin, end); + } + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + constexpr auto DAG::adjacent_edges(dag::VertexID id) const noexcept -> const dyn_array& { + expects(has_vertex(id), std::format("Unknown DAG vertex id: {}!", id)); + + const auto& adjacent_edges = stdr::find_if(m_adjacent_edges, [id](const auto& pair) noexcept { + return pair.first == id; + })->second; + return adjacent_edges; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto DAG::vertices() const noexcept -> const dyn_array& { + return m_vertices; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto DAG::vertices_count() const noexcept -> usize { + return stdr::size(m_vertices); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto DAG::edges() const noexcept -> const dyn_array& { + return m_edges; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto DAG::edges_count() const noexcept -> usize { + return stdr::size(m_edges); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + constexpr auto DAG::topological_sort() const noexcept + -> std::expected, dyn_array> { + if (auto result = find_cycle(); result.has_value()) return std::unexpected { std::move(*result) }; + + struct Degree { + dag::VertexID id; + u32 d = 0; + }; + + auto in_degree = dyn_array {}; + in_degree.reserve(stdr::size(m_vertices)); + for (const auto& [id, _] : m_vertices) { in_degree.emplace_back(id, 0); } + + for (const auto& [id, _] : m_vertices) { + const auto& edges = adjacent_edges(id); + + if (not stdr::empty(edges)) { + for (auto&& [from, to] : edges) { + if (from != id) continue; + auto&& [_, d] = *stdr::find_if(in_degree, [to](auto&& other) noexcept { return other.id == to; }); + d += 1; + } + } + } + + auto queue = std::queue {}; + + for (const auto& [id, _] : m_vertices) { + auto&& [_, d] = *stdr::find_if(in_degree, [id](auto&& other) noexcept { return other.id == id; }); + if (d == 0) queue.push(id); + } + + auto ordered_vertices = dyn_array {}; + ordered_vertices.reserve(stdr::size(m_vertices)); + while (not stdr::empty(queue)) { + auto id = queue.front(); + queue.pop(); + + ordered_vertices.emplace_back(id); + + const auto& edges = adjacent_edges(id); + if (not stdr::empty(edges)) { + for (auto&& [from, to] : edges) { + if (from == id) { + auto&& [_, d] = *stdr::find_if(in_degree, [to](auto&& other) noexcept { return other.id == to; }); + if (d > 0) d -= 1; + if (d == 0) queue.push(to); + } + } + } + } + + return ordered_vertices; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + constexpr auto DAG::find_cycle() const noexcept -> std::optional> { + auto out = std::optional> { std::nullopt }; + + auto visited = dyn_array {}; + visited.reserve(stdr::size(m_vertices)); + auto stack = dyn_array {}; + + auto dfs = [&visited, &stack, &out, this](auto&& dfs, auto&& id) mutable noexcept -> bool { + visited.emplace_back(id); + + const auto& edges = adjacent_edges(id); + if (stdr::empty(edges)) return false; + + stack.emplace_back(id); + + for (const auto& [from, to] : edges) { + const auto w = (from == id) ? to : from; + if (not stdr::contains(visited, w)) { + if (dfs(dfs, w)) { + return true; + } else if (auto it = stdr::find(stack, w); it != stdr::cend(stack)) { + auto cycle = dyn_array(it, stdr::end(stack)); + cycle.emplace_back(w); + out = std::move(cycle); + return true; + } + } else if (auto it = stdr::find(stack, w); it != stdr::cend(stack)) { + auto cycle = dyn_array(it, stdr::end(stack)); + cycle.emplace_back(w); + out = std::move(cycle); + return true; + } + } + + auto [begin, end] = stdr::remove(stack, id); + stack.erase(begin, end); + return false; + }; + + for (auto&& [id, _] : m_vertices) { + if (stdr::contains(visited, id)) continue; + + if (dfs(dfs, id)) break; + } + + return out; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + constexpr auto DAG::reverse_view() const noexcept -> DAG> { + return DAG>::template reverse_from, true>(m_next_id, m_vertices, m_edges); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + constexpr auto DAG::reverse_clone() const noexcept -> DAG { + return reverse_from, false>(m_next_id, m_vertices, m_edges); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + constexpr auto DAG::dump(Closures closures) const noexcept -> string { + auto out = string { "digraph G {\n" + " rankdir = LR\n" + " bgcolor = black\n" + " node [shape=box, fontname=\"helvetica\", fontsize=12];\n\n" }; + + if (closures.format_value) + for (const auto& [id, value] : m_vertices) { + out += std::format(" \"node{}\" [label=\"id: {} value: {}\", style=filled,color=\"{}\"];\n", + id, + id, + closures.format_value.value()(value), + closures.colorize ? closures.colorize.value()(value) : "white"); + } + else + for (const auto& [id, value] : m_vertices) { + out += std::format(" \"node{}\" [label=\"id: {}\", style=filled,color=\"{}\"];\n", + id, + id, + closures.colorize ? closures.colorize.value()(value) : "white"); + } + + for (const auto& [from, to] : m_edges) out += std::format(" \"node{}\" -> \"node{}\" [color=seagreen];\n", from, to); + + out += "}"; + + return out; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template + constexpr auto DAG::reverse_from(dag::VertexID next_id, + const dyn_array& vertices, + const dyn_array& edges) noexcept -> DAG { + auto out = DAG {}; + out.m_next_id = next_id; + + out.m_adjacent_edges.reserve(stdr::size(vertices)); + if constexpr (AS_REF) { + for (const auto& [id, vertice] : vertices) { + out.m_vertices.emplace_back(id, as_ref(vertice)); + out.m_adjacent_edges.emplace_back(id, dyn_array {}); + } + } else { + for (const auto& [id, vertice] : vertices) { + out.m_vertices.emplace_back(id, auto(vertice)); + out.m_adjacent_edges.emplace_back(id, dyn_array {}); + } + } + + out.m_edges.reserve(stdr::size(edges)); + for (auto&& [from, to] : edges) { + const auto& edge = out.m_edges.emplace_back(to, from); + + auto& adjacent_edges = stdr::find_if(out.m_adjacent_edges, [id = to](const auto& pair) noexcept { + return pair.first == id; + })->second; + adjacent_edges.emplace_back(edge); + } + + return out; + } + + namespace dag { + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto format_as(const Edge& edge, FormatContext& ctx) noexcept -> FormatContext::iterator { + auto&& out = ctx.out(); + return std::format_to(out, "[dag_edge from: {}, to: {}]", edge.from, edge.to); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto format_as(const dag::Vertex& vertex, FormatContext& ctx) noexcept -> FormatContext::iterator { + auto&& out = ctx.out(); + if constexpr (std::formattable) + return std::format_to(out, "[dag_vertex id: {}, value: {}]", vertex.id, vertex.value); + else + return std::format_to(out, "[dag_vertex id: {}, value: ]", vertex.id); + } + + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_PURE + constexpr auto to_string(const dag::Edge& edge) noexcept -> string { + return std::format("{}", edge); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE STORMKIT_PURE + constexpr auto to_string(const dag::Vertex& vertex) noexcept -> string { + return std::format("{}", vertex); + } + } // namespace dag +}} // namespace stormkit::core diff --git a/modules/stormkit/core/containers/multi_buffer.mpp b/modules/stormkit/core/containers/multi_buffer.cppm similarity index 64% rename from modules/stormkit/core/containers/multi_buffer.mpp rename to modules/stormkit/core/containers/multi_buffer.cppm index 3b2e678cb..95cf0ede4 100644 --- a/modules/stormkit/core/containers/multi_buffer.mpp +++ b/modules/stormkit/core/containers/multi_buffer.cppm @@ -24,7 +24,7 @@ export namespace stormkit { inline namespace core { template class MultiBuffer { public: - explicit constexpr MultiBuffer(std::array sizes_in_bytes); + explicit constexpr MultiBuffer(array sizes_in_bytes); constexpr ~MultiBuffer(); constexpr MultiBuffer(const MultiBuffer&); @@ -37,27 +37,26 @@ export namespace stormkit { inline namespace core { constexpr auto size() const noexcept -> usize; template [[nodiscard]] - constexpr auto data(this Self& self) noexcept -> const meta::ForwardConst*; + constexpr auto data(this Self& self) noexcept -> const meta::ForwardConst*; template - constexpr auto init_range(V&& init_data) noexcept -> std::span; + constexpr auto init_range(V&& init_data) noexcept -> array_view; template - constexpr auto init_range(V&& init_data) noexcept -> std::span; + constexpr auto init_range(V&& init_data) noexcept -> array_view; template [[nodiscard]] - constexpr auto range(this Self& self) noexcept -> std::span>; + constexpr auto range(this Self& self) noexcept -> array_view>; template [[nodiscard]] - constexpr auto range(this Self& self) noexcept - -> std::span>; + constexpr auto range(this Self& self) noexcept -> array_view>; private: - std::array m_ranges_sizes; - std::array m_ranges_begin; - usize m_size = 0; - ByteDynArray m_data; + array m_ranges_sizes; + array m_ranges_begin; + usize m_size = 0; + byte_dyn_array m_data; }; }} // namespace stormkit::core @@ -70,7 +69,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_FORCE_INLINE - constexpr MultiBuffer::MultiBuffer(std::array sizes_in_bytes) + constexpr MultiBuffer::MultiBuffer(array sizes_in_bytes) : m_ranges_sizes { sizes_in_bytes } { auto i = 0uz; for (auto&& size : m_ranges_sizes) { @@ -83,7 +82,8 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr MultiBuffer::MultiBuffer(const MultiBuffer&) = default; + STORMKIT_FORCE_INLINE + constexpr MultiBuffer::MultiBuffer(const MultiBuffer&) = default; ///////////////////////////////////// ///////////////////////////////////// @@ -94,7 +94,8 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr MultiBuffer::MultiBuffer(MultiBuffer&&) noexcept = default; + STORMKIT_FORCE_INLINE + constexpr MultiBuffer::MultiBuffer(MultiBuffer&&) noexcept = default; ///////////////////////////////////// ///////////////////////////////////// @@ -105,7 +106,8 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr MultiBuffer::~MultiBuffer() = default; + STORMKIT_FORCE_INLINE + constexpr MultiBuffer::~MultiBuffer() = default; ///////////////////////////////////// ///////////////////////////////////// @@ -120,8 +122,7 @@ namespace stormkit { inline namespace core { template template STORMKIT_FORCE_INLINE - constexpr auto MultiBuffer::data(this Self& self) noexcept - -> const meta::ForwardConst* { + constexpr auto MultiBuffer::data(this Self& self) noexcept -> const meta::ForwardConst* { return stdr::data(self.m_data); } @@ -129,8 +130,8 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template template - constexpr auto MultiBuffer::init_range(V&& init_data) noexcept -> std::span { - static_assert(meta::IsOneOf, "U should be a type contained by MultiBuffer"); + constexpr auto MultiBuffer::init_range(V&& init_data) noexcept -> array_view { + static_assert(meta::IsAnyOf, "U should be a type contained by MultiBuffer"); static_assert(meta::Is>, "range V should be of type U"); static constexpr auto TYPE_INDEX = meta::find_type_index_of(); return init_range(std::forward(init_data)); @@ -140,29 +141,25 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template template - constexpr auto MultiBuffer::init_range(V&& init_data) noexcept - -> std::span { - static_assert(TYPE_INDEX < sizeof...(T), "Index is out of bounds"); - auto span = std::span { stdr::data(m_data) + m_ranges_begin[TYPE_INDEX], - m_ranges_sizes[TYPE_INDEX] }; - - auto begin = stdr::begin(span); - for (auto&& bytes : - std::forward(init_data) | stdv::transform(monadic::as_bytes(Force {}))) { - stdr::copy(bytes, begin); - begin += as(stdr::size(bytes)); - } + constexpr auto MultiBuffer::init_range(V&& init_data) noexcept -> array_view { + static_assert(TYPE_INDEX < sizeof...(T), "Index is out of bounds"); + auto span = byte_mut_view { stdr::data(m_data) + m_ranges_begin[TYPE_INDEX], m_ranges_sizes[TYPE_INDEX] }; + + auto begin = stdr::begin(span); + for (auto&& bytes : std::forward(init_data) | stdv::transform(monadic::as_bytes(Force {}))) { + stdr::copy(bytes, begin); + begin += as(stdr::size(bytes)); + } - return range(); - } + return range(); + } ///////////////////////////////////// ///////////////////////////////////// template template - constexpr auto MultiBuffer::range(this Self& self) noexcept - -> std::span> { - static_assert(meta::IsOneOf, "U should be a type contained by MultiBuffer"); + constexpr auto MultiBuffer::range(this Self& self) noexcept -> array_view> { + static_assert(meta::IsAnyOf, "U should be a type contained by MultiBuffer"); static constexpr auto TYPE_INDEX = meta::find_type_index_of(); return self.template range(); } @@ -171,20 +168,18 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template template - constexpr auto MultiBuffer::range(this Self& self) noexcept - -> std::span> { - static_assert(TYPE_INDEX < sizeof...(T), "Index is out of bounds"); - using U = T...[TYPE_INDEX]; - using OutType = meta::ForwardConst; - const auto ptr = stdr::begin(self.m_data) + as(self.m_ranges_begin[TYPE_INDEX]); - return std::span { + constexpr auto MultiBuffer::range(this Self& self) noexcept -> array_view> { + static_assert(TYPE_INDEX < sizeof...(T), "Index is out of bounds"); + using U = T...[TYPE_INDEX]; + using OutType = meta::ForwardConst; + const auto ptr = stdr::begin(self.m_data) + as(self.m_ranges_begin[TYPE_INDEX]); + return array_view { #if defined(__cpp_lib_start_lifetime_as) and __cpp_lib_start_lifetime_as >= 202207L - std::start_lifetime_as_array(ptr, - self.m_ranges_sizes[TYPE_INDEX] / sizeof(U)), + std::start_lifetime_as_array(ptr, self.m_ranges_sizes[TYPE_INDEX] / sizeof(U)), #else - std::launder(std::bit_cast(ptr)), + std::launder(std::bit_cast(ptr)), #endif - self.m_ranges_sizes[TYPE_INDEX] / sizeof(U) - }; - } + self.m_ranges_sizes[TYPE_INDEX] / sizeof(U) + }; + } }} // namespace stormkit::core diff --git a/modules/stormkit/core/containers/raii_capsule.mpp b/modules/stormkit/core/containers/raii_capsule.cppm similarity index 82% rename from modules/stormkit/core/containers/raii_capsule.mpp rename to modules/stormkit/core/containers/raii_capsule.cppm index efa14877c..5f4bcd816 100644 --- a/modules/stormkit/core/containers/raii_capsule.mpp +++ b/modules/stormkit/core/containers/raii_capsule.cppm @@ -19,17 +19,20 @@ export namespace stormkit { inline namespace core { template class RAIICapsule { public: - using value_type = T; + using ValueType = T; + using ReferenceType = ValueType&; + + using value_type = ValueType; + using reference = ReferenceType; template static constexpr auto create(Args&&... args) noexcept -> RAIICapsule - requires meta::Is, T>; + requires meta::Is, ValueType>; template static constexpr auto create(Args&&... args) noexcept -> decltype(auto) - requires meta::IsSpecializationOf, - std::expected>; + requires meta::IsSpecializationOf, std::expected>; - static constexpr auto take(T&& value) noexcept -> RAIICapsule; + static constexpr auto take(ValueType&& value) noexcept -> RAIICapsule; static constexpr auto empty() noexcept -> RAIICapsule; constexpr ~RAIICapsule() noexcept; @@ -40,19 +43,19 @@ export namespace stormkit { inline namespace core { constexpr RAIICapsule(RAIICapsule&& other) noexcept; constexpr auto operator=(RAIICapsule&& other) noexcept -> RAIICapsule&; - constexpr operator T() const noexcept; - constexpr auto handle() noexcept -> T&; - constexpr auto handle() const noexcept -> T; - constexpr auto release() noexcept -> T; + constexpr operator ValueType() const noexcept; + constexpr auto handle() noexcept -> ReferenceType; + constexpr auto handle() const noexcept -> ValueType; + constexpr auto release() noexcept -> ValueType; constexpr auto reset(T handle = RELEASE_VALUE) noexcept -> void; private: constexpr RAIICapsule() noexcept; - constexpr RAIICapsule(T handle) noexcept; + constexpr RAIICapsule(ValueType handle) noexcept; constexpr auto destroy() noexcept -> void; - T m_handle = RELEASE_VALUE; + ValueType m_handle = RELEASE_VALUE; }; }} // namespace stormkit::core @@ -65,9 +68,8 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template template - constexpr auto RAIICapsule:: - create(Args&&... args) noexcept -> RAIICapsule - requires meta::Is, T> + constexpr auto RAIICapsule::create(Args&&... args) noexcept -> RAIICapsule + requires meta::Is, ValueType> { return RAIICapsule { Constructor(std::forward(args)...) }; } @@ -76,10 +78,8 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template template - constexpr auto RAIICapsule:: - create(Args&&... args) noexcept -> decltype(auto) - requires meta::IsSpecializationOf, - std::expected> + constexpr auto RAIICapsule::create(Args&&... args) noexcept -> decltype(auto) + requires meta::IsSpecializationOf, std::expected> { return Constructor(std::forward(args)...).transform(monadic::init()); } @@ -88,9 +88,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_FORCE_INLINE - constexpr auto RAIICapsule::take(T&& - value) noexcept - -> RAIICapsule { + constexpr auto RAIICapsule::take(ValueType&& value) noexcept -> RAIICapsule { return RAIICapsule { std::move(value) }; } @@ -98,8 +96,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_FORCE_INLINE - constexpr auto RAIICapsule::empty() noexcept - -> RAIICapsule { + constexpr auto RAIICapsule::empty() noexcept -> RAIICapsule { return RAIICapsule { RELEASE_VALUE }; } @@ -115,8 +112,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_FORCE_INLINE - constexpr RAIICapsule:: - RAIICapsule(RAIICapsule&& other) noexcept { + constexpr RAIICapsule::RAIICapsule(RAIICapsule&& other) noexcept { m_handle = other.release(); } @@ -124,8 +120,8 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_FORCE_INLINE - constexpr auto RAIICapsule:: - operator=(RAIICapsule&& other) noexcept -> RAIICapsule& { + constexpr auto RAIICapsule::operator=(RAIICapsule&& other) noexcept + -> RAIICapsule& { m_handle = other.release(); return *this; } @@ -134,8 +130,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr RAIICapsule::operator T() - const noexcept { + constexpr RAIICapsule::operator ValueType() const noexcept { return m_handle; } @@ -143,8 +138,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto RAIICapsule::handle() noexcept - -> T& { + constexpr auto RAIICapsule::handle() noexcept -> ReferenceType { return m_handle; } @@ -152,8 +146,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto RAIICapsule::handle() const noexcept - -> T { + constexpr auto RAIICapsule::handle() const noexcept -> ValueType { return m_handle; } @@ -161,8 +154,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto RAIICapsule::release() noexcept - -> T { + constexpr auto RAIICapsule::release() noexcept -> ValueType { auto tmp = std::exchange(m_handle, RELEASE_VALUE); return tmp; } @@ -171,8 +163,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_FORCE_INLINE - constexpr auto RAIICapsule:: - reset(T handle) noexcept -> void { + constexpr auto RAIICapsule::reset(ValueType handle) noexcept -> void { destroy(); m_handle = handle; } @@ -181,8 +172,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_FORCE_INLINE - constexpr auto RAIICapsule::destroy() noexcept - -> void { + constexpr auto RAIICapsule::destroy() noexcept -> void { if (m_handle != RELEASE_VALUE) { Deleter(release()); } } @@ -190,8 +180,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_FORCE_INLINE - constexpr RAIICapsule:: - RAIICapsule(T handle) noexcept { + constexpr RAIICapsule::RAIICapsule(ValueType handle) noexcept { m_handle = handle; } @@ -199,6 +188,5 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_FORCE_INLINE - constexpr RAIICapsule:: - RAIICapsule() noexcept = default; + constexpr RAIICapsule::RAIICapsule() noexcept = default; }} // namespace stormkit::core diff --git a/modules/stormkit/core/containers/ringbuffer.mpp b/modules/stormkit/core/containers/ringbuffer.cppm similarity index 89% rename from modules/stormkit/core/containers/ringbuffer.mpp rename to modules/stormkit/core/containers/ringbuffer.cppm index 5e459f05d..af98e13f0 100644 --- a/modules/stormkit/core/containers/ringbuffer.mpp +++ b/modules/stormkit/core/containers/ringbuffer.cppm @@ -1,283 +1,279 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -#include - -export module stormkit.core:containers.ringbuffer; - -import std; - -import :utils.contract; -import :typesafe.integer; -import :typesafe.byte; -import :meta; - -export namespace stormkit { inline namespace core { - template - class RingBuffer { - public: - using ValueType = T; - using ExtentType = usize; - - using value_type = ValueType; - using size_type = ExtentType; - - RingBuffer(ExtentType capacity); - - RingBuffer(const RingBuffer& copy); - auto operator=(const RingBuffer& copy) -> RingBuffer&; - - RingBuffer(RingBuffer&& moved) noexcept; - auto operator=(RingBuffer&& moved) noexcept -> RingBuffer&; - - ~RingBuffer() noexcept; - - auto clear() noexcept -> void; - - [[nodiscard]] - auto empty() const noexcept -> bool; - [[nodiscard]] - auto full() const noexcept -> bool; - [[nodiscard]] - auto size() const noexcept -> ExtentType; - [[nodiscard]] - auto capacity() const noexcept -> ExtentType; - - template - requires meta::Is> - auto push(U&& value) noexcept(std::is_nothrow_constructible_v) -> void; - - template - auto emplace(Args&&... values) noexcept(std::is_nothrow_constructible_v) - -> void; - - auto next() noexcept -> void; - - auto pop() noexcept -> void; - - template - [[nodiscard]] - auto get(this Self& self) noexcept -> decltype(auto); - - [[nodiscard]] - auto data() const noexcept -> std::span; - - private: - template - [[nodiscard]] - auto get_ptr(this Self& self, ExtentType pos) noexcept -> decltype(auto); - - ExtentType m_capacity = 0; - ExtentType m_count = 0; - - std::vector m_buffer; - - ExtentType m_write = 0; - ExtentType m_read = 0; - }; -}} // namespace stormkit::core - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit { inline namespace core { - //////////////////////////////////////// - //////////////////////////////////////// - template - RingBuffer::RingBuffer(ExtentType capacity) : m_capacity { capacity } { - m_buffer.resize(m_capacity * sizeof(ValueType)); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - RingBuffer::RingBuffer(const RingBuffer& copy) { - m_capacity = copy.m_capacity; - m_count = copy.m_count; - m_write = copy.m_write; - m_read = copy.m_read; - - m_buffer.resize(m_capacity * sizeof(ValueType)); - if (not empty()) { - for (auto i = m_read; i < m_write;) { - new (&m_buffer[i * sizeof(ValueType)]) T { *copy.get_ptr(i) }; - - i += 1; - if (i >= m_capacity) i -= m_capacity; - } - } - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - auto RingBuffer::operator=(const RingBuffer& copy) -> RingBuffer& { - if (© == this) return *this; - - m_capacity = copy.m_capacity; - m_count = copy.m_count; - m_write = copy.m_write; - m_read = copy.m_read; - - m_buffer.resize(m_capacity * sizeof(ValueType)); - if (not empty()) - for (auto i = m_read; i < m_write;) { - new (&m_buffer[i * sizeof(ValueType)]) T { *copy.get_ptr(i) }; - - i += 1; - if (i >= m_capacity) i -= m_capacity; - } - - return *this; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - RingBuffer::RingBuffer(RingBuffer&& moved) noexcept { - m_buffer = std::exchange(moved.m_buffer, std::vector {}); - - m_capacity = std::exchange(moved.m_capacity, 0); - m_count = std::exchange(moved.m_count, 0); - m_write = std::exchange(moved.m_write, 0); - m_read = std::exchange(moved.m_read, 0); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - auto RingBuffer::operator=(RingBuffer&& moved) noexcept -> RingBuffer& { - if (&moved == this) return *this; - - m_buffer = std::exchange(moved.m_buffer, std::vector {}); - - m_capacity = std::exchange(moved.m_capacity, 0); - m_count = std::exchange(moved.m_count, 0); - m_write = std::exchange(moved.m_write, 0); - m_read = std::exchange(moved.m_read, 0); - - return *this; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - RingBuffer::~RingBuffer() noexcept { - clear(); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - auto RingBuffer::clear() noexcept -> void { - while (not empty()) pop(); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - auto RingBuffer::empty() const noexcept -> bool { - return m_count == 0; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - auto RingBuffer::full() const noexcept -> bool { - return m_count == m_capacity; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - auto RingBuffer::size() const noexcept -> ExtentType { - return m_count; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - auto RingBuffer::capacity() const noexcept -> ExtentType { - return m_capacity; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - template - requires meta::Is> - auto RingBuffer::push(U&& value) noexcept(std::is_nothrow_constructible_v) - -> void { - emplace(std::forward(value)); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - template - auto RingBuffer< - T>::emplace(Args&&... values) noexcept(std::is_nothrow_constructible_v) - -> void { - if (m_count == m_capacity) pop(); - - new (&m_buffer[m_write * sizeof(ValueType)]) ValueType { std::forward(values)... }; - - m_write += 1; - if (m_write >= m_capacity) m_write -= m_capacity; - - m_count++; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - auto RingBuffer::next() noexcept -> void { - m_read += 1; - if (m_read >= m_capacity) m_read -= m_capacity; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - auto RingBuffer::pop() noexcept -> void { - EXPECTS(not empty()); - - get_ptr(m_write)->~ValueType(); - - --m_count; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - template - auto RingBuffer::get(this Self& self) noexcept -> decltype(auto) { - EXPECTS(not self.empty()); - - return std::forward_like(self.get_ptr(self.m_read)); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - auto RingBuffer::data() const noexcept -> std::span { - return std::span { get_ptr(0), m_capacity }; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - template - auto RingBuffer::get_ptr(this Self& self, ExtentType pos) noexcept -> decltype(auto) { - using OutPtr = meta::ForwardConst; - auto addr = std::forward_like(&(self.m_buffer[pos * sizeof(ValueType)])); - - return std::launder(std::bit_cast(addr)); - } -}} // namespace stormkit::core +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +#include + +export module stormkit.core:containers.ringbuffer; + +import std; + +import :utils.contract; +import :typesafe.integer; +import :typesafe.byte; +import :meta; + +export namespace stormkit { inline namespace core { + template + class RingBuffer { + public: + using ValueType = T; + using ExtentType = usize; + + using value_type = ValueType; + using size_type = ExtentType; + + RingBuffer(ExtentType capacity); + + RingBuffer(const RingBuffer& copy); + auto operator=(const RingBuffer& copy) -> RingBuffer&; + + RingBuffer(RingBuffer&& moved) noexcept; + auto operator=(RingBuffer&& moved) noexcept -> RingBuffer&; + + ~RingBuffer() noexcept; + + auto clear() noexcept -> void; + + [[nodiscard]] + auto empty() const noexcept -> bool; + [[nodiscard]] + auto full() const noexcept -> bool; + [[nodiscard]] + auto size() const noexcept -> ExtentType; + [[nodiscard]] + auto capacity() const noexcept -> ExtentType; + + template + requires meta::Is> + auto push(U&& value) noexcept(std::is_nothrow_constructible_v) -> void; + + template + auto emplace(Args&&... values) noexcept(std::is_nothrow_constructible_v) -> void; + + auto next() noexcept -> void; + + auto pop() noexcept -> void; + + template + [[nodiscard]] + auto get(this Self& self) noexcept -> decltype(auto); + + [[nodiscard]] + auto data() const noexcept -> array_view; + + private: + template + [[nodiscard]] + auto get_ptr(this Self& self, ExtentType pos) noexcept -> decltype(auto); + + ExtentType m_capacity = 0; + ExtentType m_count = 0; + + byte_dyn_array m_buffer; + + ExtentType m_write = 0; + ExtentType m_read = 0; + }; +}} // namespace stormkit::core + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit { inline namespace core { + //////////////////////////////////////// + //////////////////////////////////////// + template + RingBuffer::RingBuffer(ExtentType capacity) : m_capacity { capacity } { + m_buffer.resize(m_capacity * sizeof(ValueType)); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + RingBuffer::RingBuffer(const RingBuffer& copy) { + m_capacity = copy.m_capacity; + m_count = copy.m_count; + m_write = copy.m_write; + m_read = copy.m_read; + + m_buffer.resize(m_capacity * sizeof(ValueType)); + if (not empty()) { + for (auto i = m_read; i < m_write;) { + new (&m_buffer[i * sizeof(ValueType)]) T { *copy.get_ptr(i) }; + + i += 1; + if (i >= m_capacity) i -= m_capacity; + } + } + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto RingBuffer::operator=(const RingBuffer& copy) -> RingBuffer& { + if (© == this) return *this; + + m_capacity = copy.m_capacity; + m_count = copy.m_count; + m_write = copy.m_write; + m_read = copy.m_read; + + m_buffer.resize(m_capacity * sizeof(ValueType)); + if (not empty()) + for (auto i = m_read; i < m_write;) { + new (&m_buffer[i * sizeof(ValueType)]) T { *copy.get_ptr(i) }; + + i += 1; + if (i >= m_capacity) i -= m_capacity; + } + + return *this; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + RingBuffer::RingBuffer(RingBuffer&& moved) noexcept { + m_buffer = std::exchange(moved.m_buffer, byte_dyn_array {}); + + m_capacity = std::exchange(moved.m_capacity, 0); + m_count = std::exchange(moved.m_count, 0); + m_write = std::exchange(moved.m_write, 0); + m_read = std::exchange(moved.m_read, 0); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto RingBuffer::operator=(RingBuffer&& moved) noexcept -> RingBuffer& { + if (&moved == this) return *this; + + m_buffer = std::exchange(moved.m_buffer, byte_dyn_array {}); + + m_capacity = std::exchange(moved.m_capacity, 0); + m_count = std::exchange(moved.m_count, 0); + m_write = std::exchange(moved.m_write, 0); + m_read = std::exchange(moved.m_read, 0); + + return *this; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + RingBuffer::~RingBuffer() noexcept { + clear(); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto RingBuffer::clear() noexcept -> void { + while (not empty()) pop(); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto RingBuffer::empty() const noexcept -> bool { + return m_count == 0; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto RingBuffer::full() const noexcept -> bool { + return m_count == m_capacity; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto RingBuffer::size() const noexcept -> ExtentType { + return m_count; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto RingBuffer::capacity() const noexcept -> ExtentType { + return m_capacity; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template + requires meta::Is> + auto RingBuffer::push(U&& value) noexcept(std::is_nothrow_constructible_v) -> void { + emplace(std::forward(value)); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template + auto RingBuffer::emplace(Args&&... values) noexcept(std::is_nothrow_constructible_v) -> void { + if (m_count == m_capacity) pop(); + + new (&m_buffer[m_write * sizeof(ValueType)]) ValueType { std::forward(values)... }; + + m_write += 1; + if (m_write >= m_capacity) m_write -= m_capacity; + + m_count++; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto RingBuffer::next() noexcept -> void { + m_read += 1; + if (m_read >= m_capacity) m_read -= m_capacity; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto RingBuffer::pop() noexcept -> void { + EXPECTS(not empty()); + + get_ptr(m_write)->~ValueType(); + + --m_count; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template + auto RingBuffer::get(this Self& self) noexcept -> decltype(auto) { + EXPECTS(not self.empty()); + + return std::forward_like(self.get_ptr(self.m_read)); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto RingBuffer::data() const noexcept -> array_view { + return array_view { get_ptr(0), m_capacity }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template + auto RingBuffer::get_ptr(this Self& self, ExtentType pos) noexcept -> decltype(auto) { + using OutPtr = meta::ForwardConst; + auto addr = std::forward_like(&(self.m_buffer[pos * sizeof(ValueType)])); + + return std::launder(std::bit_cast(addr)); + } +}} // namespace stormkit::core diff --git a/modules/stormkit/core/containers/shmbuffer.mpp b/modules/stormkit/core/containers/shmbuffer.cppm similarity index 57% rename from modules/stormkit/core/containers/shmbuffer.mpp rename to modules/stormkit/core/containers/shmbuffer.cppm index b226194d3..932bf2cc1 100644 --- a/modules/stormkit/core/containers/shmbuffer.mpp +++ b/modules/stormkit/core/containers/shmbuffer.cppm @@ -4,11 +4,10 @@ module; -#include - +#include #include - #include +#include export module stormkit.core:containers.shmbuffer; @@ -19,25 +18,26 @@ import :typesafe.integer; import :typesafe.byte; import :functional.monadic; import :utils.contract; +import :named_constructors; +import :utils.filesystem; export namespace stormkit { inline namespace core { - class STORMKIT_API SHMBuffer { - struct PrivateFuncTag {}; + class STORMKIT_CORE_API SHMBuffer final: public NamedConstructor> { + using Base = NamedConstructor>; public: - using value_type = Byte; - - enum class Access : u8 { - READ = 1, - WRITE = 2, - }; + using ValueType = byte; + template + using ExpectedType = std::expected; - static auto create(usize size, std::string name) noexcept - -> std::expected; + using value_type = ValueType; - static auto create_with_access(usize size, std::string name, Access access) noexcept - -> std::expected; + static auto create(usize size, string name, io::Access access = io::Access::READ | io::Access::WRITE) noexcept + -> ExpectedType; + static auto allocate(usize size, string name, io::Access access = io::Access::READ | io::Access::WRITE) noexcept + -> ExpectedType>; + explicit SHMBuffer(PrivateTag) noexcept; ~SHMBuffer(); SHMBuffer(const SHMBuffer&) = delete; @@ -55,67 +55,61 @@ export namespace stormkit { inline namespace core { auto cend() const noexcept -> decltype(auto); template - auto operator[](this Self&, usize index) noexcept -> meta::ForwardConst&; + auto operator[](this Self&, usize index) noexcept -> meta::ForwardConst&; template - auto at(this Self&, usize index) noexcept -> meta::ForwardConst&; + auto at(this Self&, usize index) noexcept -> meta::ForwardConst&; auto size() const noexcept -> usize; template - auto data(this Self&) noexcept -> meta::ForwardConst*; + auto data(this Self&) noexcept -> array_view>; template auto native_handle(this Self&) noexcept -> meta::ForwardConst*; - auto name() const noexcept -> const std::string&; - auto access() const noexcept -> Access; + auto name() const noexcept -> string_view; + auto access() const noexcept -> io::Access; - constexpr SHMBuffer(usize size, std::string name, Access access, PrivateFuncTag) noexcept; + auto do_init(PrivateTag, usize, string, io::Access) noexcept -> ExpectedType; private: - auto allocate_buffer() noexcept -> std::expected; - - Access m_access; - void* m_handle = nullptr; - usize m_size; - std::string m_name; - std::span m_data; + using Base::allocate; + using Base::create; + + io::Access m_access; + void* m_handle = nullptr; + usize m_size; + string m_name; + array_view m_data; }; - - FLAG_ENUM(SHMBuffer::Access); }} // namespace stormkit::core namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// STORMKIT_FORCE_INLINE - auto SHMBuffer::create(usize size, std::string name) noexcept - -> std::expected { - return create_with_access(size, std::move(name), Access::READ | Access::WRITE); + inline auto SHMBuffer::create(usize size, string name, io::Access access) noexcept -> ExpectedType { + return Base::create(size, std::move(name), access); } ///////////////////////////////////// ///////////////////////////////////// STORMKIT_FORCE_INLINE - auto SHMBuffer::create_with_access(usize size, std::string name, Access access) noexcept - -> std::expected { - auto buffer = SHMBuffer { size, std::move(name), access, PrivateFuncTag {} }; - return buffer.allocate_buffer().transform(core::monadic::consume(buffer)); + inline auto SHMBuffer::allocate(usize size, string name, io::Access access) noexcept -> ExpectedType> { + return Base::allocate(size, std::move(name), access); } ///////////////////////////////////// ///////////////////////////////////// STORMKIT_FORCE_INLINE - constexpr SHMBuffer::SHMBuffer(usize size, - std::string name, - Access access, - PrivateFuncTag) noexcept - : m_access { access }, m_size { size }, m_name { std::move(name) } { + inline SHMBuffer::SHMBuffer(PrivateTag) noexcept { } ///////////////////////////////////// ///////////////////////////////////// STORMKIT_FORCE_INLINE inline SHMBuffer::SHMBuffer(SHMBuffer&& other) noexcept - : m_access { other.access() }, m_handle { std::exchange(other.m_handle, nullptr) }, - m_size { std::exchange(other.m_size, 0u) }, m_name { std::exchange(other.m_name, {}) }, + : m_access { other.access() }, + m_handle { std::exchange(other.m_handle, nullptr) }, + m_size { std::exchange(other.m_size, 0u) }, + m_name { std::exchange(other.m_name, {}) }, m_data { std::exchange(other.m_data, {}) } { } @@ -138,16 +132,16 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_PURE STORMKIT_FORCE_INLINE - auto SHMBuffer::begin(this Self& self) noexcept -> decltype(auto) { + STORMKIT_FORCE_INLINE + inline auto SHMBuffer::begin(this Self& self) noexcept -> decltype(auto) { EXPECTS(self.m_handle); return stdr::begin(std::forward(self).m_data); } ///////////////////////////////////// ///////////////////////////////////// - STORMKIT_PURE STORMKIT_FORCE_INLINE - auto SHMBuffer::cbegin() const noexcept -> decltype(auto) { + STORMKIT_FORCE_INLINE + inline auto SHMBuffer::cbegin() const noexcept -> decltype(auto) { EXPECTS(m_handle); return stdr::cbegin(m_data); } @@ -155,16 +149,16 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_PURE STORMKIT_FORCE_INLINE - auto SHMBuffer::end(this Self& self) noexcept -> decltype(auto) { + STORMKIT_FORCE_INLINE + inline auto SHMBuffer::end(this Self& self) noexcept -> decltype(auto) { EXPECTS(self.m_handle); return stdr::end(std::forward(self).m_data); } ///////////////////////////////////// ///////////////////////////////////// - STORMKIT_PURE STORMKIT_FORCE_INLINE - auto SHMBuffer::cend() const noexcept -> decltype(auto) { + STORMKIT_FORCE_INLINE + inline auto SHMBuffer::cend() const noexcept -> decltype(auto) { EXPECTS(m_handle); return stdr::cend(m_data); } @@ -172,9 +166,8 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_PURE STORMKIT_FORCE_INLINE - auto SHMBuffer::operator[](this Self& self, usize index) noexcept - -> meta::ForwardConst& { + STORMKIT_FORCE_INLINE + inline auto SHMBuffer::operator[](this Self& self, usize index) noexcept -> meta::ForwardConst& { EXPECTS(self.m_handle); EXPECTS(index < self.m_size); return std::forward(self).m_data[index]; @@ -183,8 +176,8 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_PURE STORMKIT_FORCE_INLINE - auto SHMBuffer::at(this Self& self, usize index) noexcept -> meta::ForwardConst& { + STORMKIT_FORCE_INLINE + inline auto SHMBuffer::at(this Self& self, usize index) noexcept -> meta::ForwardConst& { EXPECTS(self.m_handle); EXPECTS(index < self.m_size); return std::forward(self).m_data.at(index); @@ -192,39 +185,39 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// - STORMKIT_PURE STORMKIT_FORCE_INLINE - auto SHMBuffer::size() const noexcept -> usize { + STORMKIT_FORCE_INLINE + inline auto SHMBuffer::size() const noexcept -> usize { return m_size; } ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_PURE STORMKIT_FORCE_INLINE - auto SHMBuffer::data(this Self& self) noexcept -> meta::ForwardConst* { + STORMKIT_FORCE_INLINE + inline auto SHMBuffer::data(this Self& self) noexcept -> array_view> { EXPECTS(self.m_handle); - return stdr::data(std::forward(self).m_data); + return std::forward(self).m_data; } ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_PURE STORMKIT_FORCE_INLINE - auto SHMBuffer::native_handle(this Self& self) noexcept -> meta::ForwardConst* { + STORMKIT_FORCE_INLINE + inline auto SHMBuffer::native_handle(this Self& self) noexcept -> meta::ForwardConst* { return std::forward(self).m_handle; } ///////////////////////////////////// ///////////////////////////////////// - STORMKIT_PURE STORMKIT_FORCE_INLINE - auto SHMBuffer::name() const noexcept -> const std::string& { + STORMKIT_FORCE_INLINE + inline auto SHMBuffer::name() const noexcept -> string_view { return m_name; } ///////////////////////////////////// ///////////////////////////////////// - STORMKIT_PURE STORMKIT_FORCE_INLINE - auto SHMBuffer::access() const noexcept -> Access { + STORMKIT_FORCE_INLINE + inline auto SHMBuffer::access() const noexcept -> io::Access { return m_access; } }} // namespace stormkit::core diff --git a/modules/stormkit/core/containers/tree.mpp b/modules/stormkit/core/containers/tree.cppm similarity index 68% rename from modules/stormkit/core/containers/tree.mpp rename to modules/stormkit/core/containers/tree.cppm index c627e40b0..c2237ca52 100644 --- a/modules/stormkit/core/containers/tree.mpp +++ b/modules/stormkit/core/containers/tree.cppm @@ -1,565 +1,530 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -#include - -#include - -export module stormkit.core:containers.tree; - -import std; - -import :typesafe.integer; -import :typesafe.safecasts; -import :utils.handle; -import :utils.contract; - -export namespace stormkit { inline namespace core { - class STORMKIT_API TreeNode { - public: - using IndexType = Handle32; - using DirtyBitType = u32; - - static constexpr auto INVALID_INDEX = IndexType { IndexType::INVALID_HANDLE_VALUE }; - - [[nodiscard]] - auto name() const noexcept -> const std::string&; - auto set_name(std::string name) noexcept -> void; - - [[nodiscard]] - auto parent() const noexcept -> IndexType; - auto set_parent(IndexType index) noexcept -> void; - - auto next_sibling() const noexcept -> IndexType; - auto set_next_sibling(IndexType index) noexcept -> void; - - auto first_child() const noexcept -> IndexType; - auto set_first_child(IndexType index) noexcept -> void; - - auto dirty_bits() const noexcept -> const DirtyBitType&; - auto set_dirty_bits(DirtyBitType bits) noexcept -> void; - - auto invalidate() noexcept -> void; - - private: - IndexType m_parent = INVALID_INDEX; - IndexType m_next_sibling = INVALID_INDEX; - IndexType m_first_child = INVALID_INDEX; - DirtyBitType m_dirty_bits = 0; - - std::string m_name; - }; - - template - class Tree { - public: - static constexpr auto DEFAULT_PREALLOCATED_TREE_SIZE = usize { 1000 }; - - using TreeNodeType = TreeNodeClass; - using TreeNodeIndexType = typename TreeNodeType::IndexType; - using TreeNodeDirtyBitType = typename TreeNodeType::DirtyBitType; - - Tree(); - ~Tree(); - - Tree(const Tree&); - auto operator=(const Tree&) -> Tree&; - - Tree(Tree&&); - auto operator=(Tree&&) -> Tree&; - - auto getFreeNode() -> TreeNodeIndexType; - - auto insert(TreeNodeType&& node, - TreeNodeIndexType parent_index, - TreeNodeIndexType previous_sibling) -> TreeNodeIndexType; - auto remove(TreeNodeIndexType index) -> void; - - auto markDirty(TreeNodeIndexType index, TreeNodeDirtyBitType bits) -> void; - - auto operator[](TreeNodeIndexType index) noexcept -> TreeNodeType&; - auto operator[](TreeNodeIndexType index) const noexcept -> const TreeNodeType&; - - [[nodiscard]] - auto size() const noexcept -> usize; - - [[nodiscard]] - auto begin() noexcept; - [[nodiscard]] - auto begin() const noexcept; - [[nodiscard]] - auto cbegin() const noexcept; - - [[nodiscard]] - auto end() noexcept; - [[nodiscard]] - auto end() const noexcept; - [[nodiscard]] - auto cend() const noexcept; - - auto clearDirties() noexcept -> void; - [[nodiscard]] - auto dirties() const noexcept -> std::span; - - auto genDotFile(std::filesystem::path filepath, - std::function colorize_node) const - -> void; - - auto genDotFile(std::filesystem::path filepath, - core::u32 highlight, - std::function colorize_node) const - -> void; - - private: - TreeNodeIndexType m_first_free_index = 0; - std::vector m_tree; - std::vector m_dirties; - }; -}} // namespace stormkit::core - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit { inline namespace core { - //////////////////////////////////////// - //////////////////////////////////////// - inline auto TreeNode::name() const noexcept -> const std::string& { - return m_name; - } - - //////////////////////////////////////// - //////////////////////////////////////// - inline auto TreeNode::set_name(std::string name) noexcept -> void { - m_name = std::move(name); - } - - //////////////////////////////////////// - //////////////////////////////////////// - inline auto TreeNode::parent() const noexcept -> TreeNode::IndexType { - return m_parent; - } - - //////////////////////////////////////// - //////////////////////////////////////// - inline auto TreeNode::set_parent(IndexType index) noexcept -> void { - m_parent = index; - } - - //////////////////////////////////////// - //////////////////////////////////////// - inline auto TreeNode::next_sibling() const noexcept -> TreeNode::IndexType { - return m_next_sibling; - } - - //////////////////////////////////////// - //////////////////////////////////////// - inline auto TreeNode::set_next_sibling(IndexType index) noexcept -> void { - m_next_sibling = index; - } - - //////////////////////////////////////// - //////////////////////////////////////// - inline auto TreeNode::first_child() const noexcept -> TreeNode::IndexType { - return m_first_child; - } - - //////////////////////////////////////// - //////////////////////////////////////// - inline auto TreeNode::set_first_child(IndexType index) noexcept -> void { - m_first_child = index; - } - - //////////////////////////////////////// - //////////////////////////////////////// - inline auto TreeNode::dirty_bits() const noexcept -> const TreeNode::DirtyBitType& { - return m_dirty_bits; - } - - //////////////////////////////////////// - //////////////////////////////////////// - inline auto TreeNode::set_dirty_bits(DirtyBitType bits) noexcept -> void { - m_dirty_bits = bits; - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto TreeNode::invalidate() noexcept -> void { - m_parent = { INVALID_INDEX }; - m_next_sibling = { INVALID_INDEX }; - m_first_child = { INVALID_INDEX }; - m_dirty_bits = 0; - m_name = ""; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - Tree::Tree() { - m_tree.resize(DEFAULT_PREALLOCATED_TREE_SIZE); - - for (auto i : range(std::size(m_tree) - 1u)) - m_tree[i].set_next_sibling(i + 1u); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - Tree::~Tree() = default; - - //////////////////////////////////////// - //////////////////////////////////////// - template - Tree::Tree(const Tree&) = default; - - //////////////////////////////////////// - //////////////////////////////////////// - template - Tree::Tree(Tree&&) = default; - - //////////////////////////////////////// - //////////////////////////////////////// - template - auto Tree::operator=(const Tree&) -> Tree& = default; - - //////////////////////////////////////// - //////////////////////////////////////// - template - auto Tree::operator=(Tree&&) -> Tree& = default; - - //////////////////////////////////////// - //////////////////////////////////////// - template - auto Tree::getFreeNode() -> TreeNodeIndexType { - if (m_tree[m_first_free_index].next_sibling() == TreeNode::INVALID_INDEX) { - const auto size = as(std::size(m_tree)); - const auto first_new = as(size); - - m_tree.resize(as(size * 1.5f)); - const auto new_size = std::size(m_tree); - - // generate a new chain of free objects, with the last one pointing to - // ~0 - m_tree[m_first_free_index].set_next_sibling(first_new); - for (auto i : range(first_new, new_size - 1u)) m_tree[i].set_next_sibling(i + 1u); - } - - auto index = m_first_free_index; - m_first_free_index = m_tree[m_first_free_index].next_sibling(); - - return index; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - auto Tree::insert(TreeNodeType&& node, - TreeNodeIndexType parent_index, - TreeNodeIndexType previous_sibling) -> TreeNodeIndexType { - const auto index = getFreeNode(); - - auto& _node = m_tree[index]; - _node = std::forward(node); - - _node.set_parent(parent_index); - - // check if parent is real node - if (parent_index != TreeNode::INVALID_INDEX) { - auto& parent_node = *(std::ranges::begin(m_tree) + parent_index); - - // new node is first child - if (parent_node.first_child() == TreeNode::INVALID_INDEX) - parent_node.set_first_child(index); - else if (previous_sibling == TreeNode::INVALID_INDEX) { // insert a beginning of childs - _node.set_next_sibling(parent_node.first_child()); - parent_node.set_first_child(index); - } else { // insert at the end - auto& prev_sibling_node = m_tree[previous_sibling]; - _node.set_next_sibling(prev_sibling_node.next_sibling()); - prev_sibling_node.set_next_sibling(index); - } - } - - return index; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - auto Tree::remove(TreeNodeIndexType index) -> void { - auto& node = m_tree[index]; - - if (node.parent() != TreeNode::INVALID_INDEX) { - auto& parent = m_tree[node.parent()]; - - // Remove sibling - auto current_index = parent.first_child(); - while (current_index != TreeNode::INVALID_INDEX) { - auto& current_node = m_tree[current_index]; - - if (current_node.next_sibling() == index) { - current_node.set_next_sibling(node.next_sibling()); - break; - } - current_index = current_node.next_sibling(); - } - - // remove parent - if (parent.first_child() == index) parent.set_first_child(node.next_sibling()); - - node.set_parent(TreeNode::INVALID_INDEX); - } - - auto last_index = TreeNode::INVALID_INDEX; - auto queue = std::deque {}; - queue.emplace_back(index); - while (not queue.empty()) { - auto current_index = queue.front(); - auto& current_node = m_tree[current_index]; - queue.pop_front(); - - auto child_index = current_node.first_child(); - while (child_index != TreeNode::INVALID_INDEX) { - queue.emplace_back(child_index); - child_index = m_tree[child_index].next_sibling(); - } - - node.invalidate(); - - if (last_index != TreeNode::INVALID_INDEX) - m_tree[last_index].set_next_sibling(current_index); - - last_index = current_index; - } - - m_tree[last_index].set_next_sibling(m_first_free_index); - m_first_free_index = index; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - auto Tree::markDirty(TreeNodeIndexType index, TreeNodeDirtyBitType bits) - -> void { - auto& node = m_tree[index]; - if (not node.dirty_bits()) { - m_dirties.emplace_back(index); - node.set_dirty_bits(bits); - return; - } - - node.set_dirty_bits(bits); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - auto Tree::operator[](TreeNodeIndexType index) noexcept -> TreeNodeType& { - EXPECTS(index < std::size(m_tree)); - - return m_tree[index]; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - auto Tree::operator[](TreeNodeIndexType index) const noexcept - -> const TreeNodeType& { - EXPECTS(index < std::size(m_tree)); - - return m_tree[index]; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - auto Tree::size() const noexcept -> usize { - return std::size(m_tree); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - auto Tree::begin() noexcept { - return std::ranges::begin(m_tree); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - auto Tree::begin() const noexcept { - return std::cbegin(m_tree); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - auto Tree::cbegin() const noexcept { - return std::cbegin(m_tree); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - auto Tree::end() noexcept { - return std::ranges::end(m_tree); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - auto Tree::end() const noexcept { - return std::cend(m_tree); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - auto Tree::cend() const noexcept { - return std::cend(m_tree); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - auto Tree::clearDirties() noexcept -> void { - if (std::empty(m_dirties)) return; - - for (auto i : m_dirties) { m_tree[i].set_dirty_bits(0); } - - m_dirties.clear(); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - auto Tree::dirties() const noexcept -> std::span { - return m_dirties; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - auto Tree::genDotFile(std::filesystem::path filepath, - std::function - colorize_node) const -> void { - auto stream = std::fstream(filepath, std::ios::out); - - stream - << "digraph G { \n" - << " rankdir = LR\n" - << " bgcolor = black\n\n" - << " node [shape=box, fontname=\"helvetica\", fontsize=12];\n\n"; - - for (auto i : range(m_first_free_index)) { - const auto name = operator[](i).name(); - const auto dirty = bool(operator[](i).dirty_bits()); - - stream - << " \"node" - << i - << "\" [label=\"id: " - << i - << " type: " - << name - << " dirty: " - << std::boolalpha - << dirty - << "\", style=filled,color=\"" - << colorize_node(name) - << "\"];\n"; - } - - for (auto i : range(m_first_free_index)) { - if (operator[](i).first_child() == TreeNodeClass::INVALID_INDEX) continue; - - for (auto current = operator[](i).first_child(); - current != TreeNodeClass::INVALID_INDEX; - current = operator[](current).next_sibling()) { - stream - << " \"node" - << i - << "\" -> \"node" - << current - << "\" [color=seagreen] ;\n"; - } - } - - stream << "}" << std::flush; - - stream.close(); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - auto Tree::genDotFile(std::filesystem::path filepath, - core::u32 highlight, - std::function - colorize_node) const -> void { - std::fstream stream(filepath.string(), std::ios::out); - - stream - << "digraph G { \n" - << " rankdir = LR\n" - << " bgcolor = black\n\n" - << " node [shape=box, fontname=\"helvetica\", fontsize=12];\n\n"; - - for (auto i : range(m_first_free_index)) { - const auto name = operator[](i).name(); - const auto dirty = bool(operator[](i).dirty_bits()); - if (i != highlight) - stream - << " \"node" - << i - << "\" [label=\"id: " - << i - << " type: " - << name - << " dirty: " - << std::boolalpha - << dirty - << "\", style=filled,color=\"" - << colorize_node(name) - << "\"];\n"; - else - stream - << " \"node" - << i - << "\" [shape=polygon,sides=5,peripheries=3, label=\"id: " - << i - << " type: " - << name - << " dirty: " - << std::boolalpha - << dirty - << "\", style=filled,color=\"" - << colorize_node(name) - << "\"];\n"; - } - - for (auto i : range(m_first_free_index)) { - if (operator[](i).first_child() == TreeNodeClass::INVALID_INDEX) continue; - - for (auto current = operator[](i).first_child(); - current != TreeNodeClass::INVALID_INDEX; - current = operator[](current).next_sibling()) { - stream - << " \"node" - << i - << "\" -> \"nodeNode" - << current - << "\" [color=seagreen] ;\n"; - } - } - - stream << "}" << std::flush; - - stream.close(); - } -}} // namespace stormkit::core +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include +#include +#include + +export module stormkit.core:containers.tree; + +import std; + +import :typesafe.integer; +import :typesafe.byte; +import :typesafe.safecasts; +import :utils.handle; +import :utils.contract; +import :utils.std23_functional; +import :utils.filesystem; + +namespace stdr = std::ranges; +namespace stdfs = std::filesystem; + +export namespace stormkit { inline namespace core { + class STORMKIT_CORE_API TreeNode { + public: + using IndexType = Handle32; + using DirtyBitType = u32; + + static constexpr auto INVALID_INDEX = IndexType { IndexType::INVALID_HANDLE_VALUE }; + + [[nodiscard]] + auto name() const noexcept -> const string&; + auto set_name(string name) noexcept -> void; + + [[nodiscard]] + auto parent() const noexcept -> IndexType; + auto set_parent(IndexType index) noexcept -> void; + + auto next_sibling() const noexcept -> IndexType; + auto set_next_sibling(IndexType index) noexcept -> void; + + auto first_child() const noexcept -> IndexType; + auto set_first_child(IndexType index) noexcept -> void; + + auto dirty_bits() const noexcept -> const DirtyBitType&; + auto set_dirty_bits(DirtyBitType bits) noexcept -> void; + + auto invalidate() noexcept -> void; + + private: + IndexType m_parent = INVALID_INDEX; + IndexType m_next_sibling = INVALID_INDEX; + IndexType m_first_child = INVALID_INDEX; + DirtyBitType m_dirty_bits = 0; + + string m_name; + }; + + template + class Tree { + public: + static constexpr auto DEFAULT_PREALLOCATED_TREE_SIZE = usize { 10 }; + + using TreeNodeType = TreeNodeClass; + using TreeNodeIndexType = typename TreeNodeType::IndexType; + using TreeNodeDirtyBitType = typename TreeNodeType::DirtyBitType; + + Tree(); + ~Tree(); + + Tree(const Tree&); + auto operator=(const Tree&) -> Tree&; + + Tree(Tree&&); + auto operator=(Tree&&) -> Tree&; + + auto get_free_node() -> TreeNodeIndexType; + + auto insert(TreeNodeType&& node, TreeNodeIndexType parent_index, TreeNodeIndexType previous_sibling) -> TreeNodeIndexType; + auto remove(TreeNodeIndexType index) -> void; + + auto mark_dirty(TreeNodeIndexType index, TreeNodeDirtyBitType bits) -> void; + + auto operator[](TreeNodeIndexType index) noexcept -> TreeNodeType&; + auto operator[](TreeNodeIndexType index) const noexcept -> const TreeNodeType&; + + [[nodiscard]] + auto size() const noexcept -> usize; + + [[nodiscard]] + auto begin() noexcept; + [[nodiscard]] + auto begin() const noexcept; + [[nodiscard]] + auto cbegin() const noexcept; + + [[nodiscard]] + auto end() noexcept; + [[nodiscard]] + auto end() const noexcept; + [[nodiscard]] + auto cend() const noexcept; + + auto clear_dirties() noexcept -> void; + [[nodiscard]] + auto dirties() const noexcept -> array_view; + + auto gen_dot_file(stdfs::path filepath, std23::function_ref colorize_node) const noexcept + -> io::Expected; + + auto gen_dot_file(stdfs::path filepath, + core::u32 highlight, + std23::function_ref colorize_node) const noexcept -> io::Expected; + + private: + TreeNodeIndexType m_first_free_index = 0; + dyn_array m_tree; + dyn_array m_dirties; + }; +}} // namespace stormkit::core + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit { inline namespace core { + //////////////////////////////////////// + //////////////////////////////////////// + inline auto TreeNode::name() const noexcept -> const string& { + return m_name; + } + + //////////////////////////////////////// + //////////////////////////////////////// + inline auto TreeNode::set_name(string name) noexcept -> void { + m_name = std::move(name); + } + + //////////////////////////////////////// + //////////////////////////////////////// + inline auto TreeNode::parent() const noexcept -> TreeNode::IndexType { + return m_parent; + } + + //////////////////////////////////////// + //////////////////////////////////////// + inline auto TreeNode::set_parent(IndexType index) noexcept -> void { + m_parent = index; + } + + //////////////////////////////////////// + //////////////////////////////////////// + inline auto TreeNode::next_sibling() const noexcept -> TreeNode::IndexType { + return m_next_sibling; + } + + //////////////////////////////////////// + //////////////////////////////////////// + inline auto TreeNode::set_next_sibling(IndexType index) noexcept -> void { + m_next_sibling = index; + } + + //////////////////////////////////////// + //////////////////////////////////////// + inline auto TreeNode::first_child() const noexcept -> TreeNode::IndexType { + return m_first_child; + } + + //////////////////////////////////////// + //////////////////////////////////////// + inline auto TreeNode::set_first_child(IndexType index) noexcept -> void { + m_first_child = index; + } + + //////////////////////////////////////// + //////////////////////////////////////// + inline auto TreeNode::dirty_bits() const noexcept -> const TreeNode::DirtyBitType& { + return m_dirty_bits; + } + + //////////////////////////////////////// + //////////////////////////////////////// + inline auto TreeNode::set_dirty_bits(DirtyBitType bits) noexcept -> void { + m_dirty_bits = bits; + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto TreeNode::invalidate() noexcept -> void { + m_parent = { INVALID_INDEX }; + m_next_sibling = { INVALID_INDEX }; + m_first_child = { INVALID_INDEX }; + m_dirty_bits = 0; + m_name = ""; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + Tree::Tree() { + m_tree.resize(DEFAULT_PREALLOCATED_TREE_SIZE); + + for (auto i : range(stdr::size(m_tree) - 1u)) m_tree[i].set_next_sibling(i + 1u); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + Tree::~Tree() = default; + + //////////////////////////////////////// + //////////////////////////////////////// + template + Tree::Tree(const Tree&) = default; + + //////////////////////////////////////// + //////////////////////////////////////// + template + Tree::Tree(Tree&&) = default; + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto Tree::operator=(const Tree&) -> Tree& = default; + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto Tree::operator=(Tree&&) -> Tree& = default; + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto Tree::get_free_node() -> TreeNodeIndexType { + if (m_tree[m_first_free_index].next_sibling() == TreeNode::INVALID_INDEX) { + const auto size = as(stdr::size(m_tree)); + const auto first_new = as(stdr::size(m_tree)); + + m_tree.resize(as(size * 1.5f)); + const auto new_size = stdr::size(m_tree); + + // generate a new chain of free objects, with the last one pointing to + // ~0 + m_tree[m_first_free_index].set_next_sibling(first_new); + for (auto i : range(first_new, new_size - 1u)) m_tree[i].set_next_sibling(i + 1u); + } + + auto index = m_first_free_index; + m_first_free_index = m_tree[m_first_free_index].next_sibling(); + + return index; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto Tree::insert(TreeNodeType&& node, TreeNodeIndexType parent_index, TreeNodeIndexType previous_sibling) + -> TreeNodeIndexType { + const auto index = get_free_node(); + + auto& _node = m_tree[index]; + _node = std::forward(node); + + _node.set_parent(parent_index); + + // check if parent is real node + if (parent_index != TreeNode::INVALID_INDEX) { + auto& parent_node = *(std::ranges::begin(m_tree) + parent_index); + + // new node is first child + if (parent_node.first_child() == TreeNode::INVALID_INDEX) parent_node.set_first_child(index); + else if (previous_sibling == TreeNode::INVALID_INDEX) { // insert a beginning of childs + _node.set_next_sibling(parent_node.first_child()); + parent_node.set_first_child(index); + } else { // insert at the end + auto& prev_sibling_node = m_tree[previous_sibling]; + _node.set_next_sibling(prev_sibling_node.next_sibling()); + prev_sibling_node.set_next_sibling(index); + } + } + + return index; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto Tree::remove(TreeNodeIndexType index) -> void { + auto& node = m_tree[index]; + + if (node.parent() != TreeNode::INVALID_INDEX) { + auto& parent = m_tree[node.parent()]; + + // Remove sibling + auto current_index = parent.first_child(); + while (current_index != TreeNode::INVALID_INDEX) { + auto& current_node = m_tree[current_index]; + + if (current_node.next_sibling() == index) { + current_node.set_next_sibling(node.next_sibling()); + break; + } + current_index = current_node.next_sibling(); + } + + // remove parent + if (parent.first_child() == index) parent.set_first_child(node.next_sibling()); + + node.set_parent(TreeNode::INVALID_INDEX); + } + + auto last_index = TreeNode::INVALID_INDEX; + auto queue = std::deque {}; + queue.emplace_back(index); + while (not queue.empty()) { + auto current_index = queue.front(); + auto& current_node = m_tree[current_index]; + queue.pop_front(); + + auto child_index = current_node.first_child(); + while (child_index != TreeNode::INVALID_INDEX) { + queue.emplace_back(child_index); + child_index = m_tree[child_index].next_sibling(); + } + + node.invalidate(); + + if (last_index != TreeNode::INVALID_INDEX) m_tree[last_index].set_next_sibling(current_index); + + last_index = current_index; + } + + m_tree[last_index].set_next_sibling(m_first_free_index); + m_first_free_index = index; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto Tree::mark_dirty(TreeNodeIndexType index, TreeNodeDirtyBitType bits) -> void { + auto& node = m_tree[index]; + if (not node.dirty_bits()) { + m_dirties.emplace_back(index); + node.set_dirty_bits(bits); + return; + } + + node.set_dirty_bits(bits); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto Tree::operator[](TreeNodeIndexType index) noexcept -> TreeNodeType& { + EXPECTS(index < stdr::size(m_tree)); + + return m_tree[index]; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto Tree::operator[](TreeNodeIndexType index) const noexcept -> const TreeNodeType& { + EXPECTS(index < stdr::size(m_tree)); + + return m_tree[index]; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto Tree::size() const noexcept -> usize { + return stdr::size(m_tree); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto Tree::begin() noexcept { + return std::ranges::begin(m_tree); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto Tree::begin() const noexcept { + return std::cbegin(m_tree); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto Tree::cbegin() const noexcept { + return std::cbegin(m_tree); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto Tree::end() noexcept { + return std::ranges::end(m_tree); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto Tree::end() const noexcept { + return std::cend(m_tree); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto Tree::cend() const noexcept { + return std::cend(m_tree); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto Tree::clear_dirties() noexcept -> void { + if (std::empty(m_dirties)) return; + + for (auto i : m_dirties) { m_tree[i].set_dirty_bits(0); } + + m_dirties.clear(); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto Tree::dirties() const noexcept -> array_view { + return m_dirties; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto Tree::gen_dot_file(stdfs::path filepath, + std23::function_ref colorize_node) const noexcept + -> io::Expected { + using namespace stormkit::literals; + auto out = string {}; + out.reserve(1_kb); + + out += "digraph G { \n" + " rankdir = LR\n" + " bgcolor = black\n\n" + " node [shape=box, fontname=\"helvetica\", fontsize=12];\n\n"; + + for (auto i : range(m_first_free_index)) { + const auto name = operator[](i).name(); + const auto dirty = bool(operator[](i).dirty_bits()); + + out += std::format(" \"node{}\" [label=\"id: {} type: {} dirty: {} \", style=filled,color=\"{}\"];\n", + i, + i, + name, + dirty, + colorize_node(name)); + } + + for (auto i : range(m_first_free_index)) { + if (operator[](i).first_child() == TreeNodeClass::INVALID_INDEX) continue; + + for (auto current = operator[](i).first_child(); current != TreeNodeClass::INVALID_INDEX; + current = operator[](current).next_sibling()) { + out += std::format(" \"node{}\" -> \"node{}\" [color=seagreen] ;\n", i, current); + } + } + + out += "}"; + + return io::write_text(filepath, out); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto Tree::gen_dot_file(stdfs::path filepath, + core::u32 highlight, + std23::function_ref colorize_node) const noexcept + -> io::Expected { + using namespace stormkit::literals; + auto out = string {}; + out.reserve(1_kb); + + out += "digraph G { \n" + " rankdir = LR\n" + " bgcolor = black\n\n" + " node [shape=box, fontname=\"helvetica\", fontsize=12];\n\n"; + + for (auto i : range(m_first_free_index)) { + const auto name = operator[](i).name(); + const auto dirty = bool(operator[](i).dirty_bits()); + if (i != highlight) + out += std::format(" \"node{}\" [label=\"id: {} type: {} dirty: {} \", style=filled,color=\"{}\"];\n", + i, + i, + name, + dirty, + colorize_node(name)); + else + out += std::format(" \"node{}\" [shape = polygon,sides=5,peripheries=3, label=\"id: {} type: {} dirty: {} \", " + "style=filled,color=\"{}\"];\n", + i, + i, + name, + dirty, + colorize_node(name)); + } + + for (auto i : range(m_first_free_index)) { + if (operator[](i).first_child() == TreeNodeClass::INVALID_INDEX) continue; + + for (auto current = operator[](i).first_child(); current != TreeNodeClass::INVALID_INDEX; + current = operator[](current).next_sibling()) { + out += std::format(" \"node{}\" -> \"node{}\" [color=seagreen] ;\n", i, current); + } + } + + out += "}"; + + return io::write_text(filepath, out); + } +}} // namespace stormkit::core diff --git a/modules/stormkit/core/containers/utils.mpp b/modules/stormkit/core/containers/utils.cppm similarity index 63% rename from modules/stormkit/core/containers/utils.mpp rename to modules/stormkit/core/containers/utils.cppm index 33920b6ac..92ca6b9da 100644 --- a/modules/stormkit/core/containers/utils.mpp +++ b/modules/stormkit/core/containers/utils.cppm @@ -18,63 +18,57 @@ namespace stdr = std::ranges; export namespace stormkit { inline namespace core { // template typename Container = std::inplace_vector, typename T> - template typename Container = std::vector, typename T> + template typename Container = dyn_array, typename T> constexpr auto filled_with(usize size, T value) noexcept -> Container; template - constexpr auto filled_with(T value) noexcept -> std::array; + constexpr auto filled_with(T value) noexcept -> array; template constexpr auto merge(Out& output, const Inputs&... ranges) noexcept -> void; - template typename Out = std::vector, stdr::input_range... Inputs> - constexpr auto concat(const Inputs&... inputs) noexcept - -> Out>>; + template typename Out = dyn_array, stdr::input_range... Inputs> + constexpr auto concat(const Inputs&... inputs) noexcept -> Out>>; template constexpr auto move_and_merge(Out& output, Inputs&&... ranges) noexcept -> void; - template typename Out = std::vector, stdr::input_range... Inputs> - constexpr auto move_and_concat(Inputs&&... inputs) noexcept - -> Out>>; + template typename Out = dyn_array, stdr::input_range... Inputs> + constexpr auto move_and_concat(Inputs&&... inputs) noexcept -> Out>>; using std::to_array; template - constexpr auto to_dyn_array(T&& range) noexcept -> std::vector>; + constexpr auto to_dyn_array(T&& range) noexcept -> dyn_array>; template requires(sizeof...(Args) > 0) - constexpr auto into_array(Args&&... args) noexcept - -> std::array, sizeof...(Args)>; + constexpr auto into_array(Args&&... args) noexcept -> array, sizeof...(Args)>; template requires(sizeof...(Args) > 0) - constexpr auto into_array_of(Args&&... args) noexcept -> std::array; + constexpr auto into_array_of(Args&&... args) noexcept -> array; template requires(sizeof...(Args) > 0) - constexpr auto into_dyn_array(Args&&... args) noexcept - -> std::vector>; + constexpr auto into_dyn_array(Args&&... args) noexcept -> dyn_array>; template requires(sizeof...(Args) > 0) - constexpr auto into_dyn_array_of(Args&&... args) noexcept -> std::vector; + constexpr auto into_dyn_array_of(Args&&... args) noexcept -> dyn_array; template - constexpr auto as_view(T& range) noexcept -> std::string_view; + constexpr auto as_view(T& range) noexcept -> string_view; template requires(not stdr::range) - constexpr auto as_view(T& value) noexcept -> std::span; + constexpr auto as_view(T& value) noexcept -> array_view; template - constexpr auto as_view(T& range) noexcept - -> std::span>>; + constexpr auto as_view(T& range) noexcept -> array_view>>; template - constexpr auto as_view(T& range, Force) noexcept - -> std::span>>; + constexpr auto as_view(T& range, Force) noexcept -> array_view>>; }} // namespace stormkit::core //////////////////////////////////////////////////////////////////// @@ -84,7 +78,7 @@ export namespace stormkit { inline namespace core { namespace stormkit { inline namespace core { //////////////////////////////////////// //////////////////////////////////////// - template typename Container = std::vector, typename T> + template typename Container, typename T> STORMKIT_FORCE_INLINE STORMKIT_PURE constexpr auto filled_with(usize size, T value) noexcept -> Container { auto out = Container {}; @@ -97,8 +91,8 @@ namespace stormkit { inline namespace core { //////////////////////////////////////// template STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto filled_with(T value) noexcept -> std::array { - auto out = std::array {}; + constexpr auto filled_with(T value) noexcept -> array { + auto out = array {}; std::ranges::fill(out, value); return out; } @@ -115,11 +109,10 @@ namespace stormkit { inline namespace core { //////////////////////////////////////// //////////////////////////////////////// - template typename Out = std::vector, stdr::input_range... Inputs> + template typename Out, stdr::input_range... Inputs> STORMKIT_FORCE_INLINE STORMKIT_PURE - constexpr auto concat(const Inputs&... inputs) noexcept - -> Out>> { + constexpr auto concat(const Inputs&... inputs) noexcept -> Out>> { auto output = Out>> {}; merge(output, inputs...); @@ -138,11 +131,10 @@ namespace stormkit { inline namespace core { //////////////////////////////////////// //////////////////////////////////////// - template typename Out = std::vector, stdr::input_range... Inputs> + template typename Out, stdr::input_range... Inputs> STORMKIT_FORCE_INLINE STORMKIT_PURE - constexpr auto move_and_concat(Inputs&&... inputs) noexcept - -> Out>> { + constexpr auto move_and_concat(Inputs&&... inputs) noexcept -> Out>> { auto output = Out>> {}; move_and_merge(output, std::forward(inputs)...); @@ -154,8 +146,8 @@ namespace stormkit { inline namespace core { template STORMKIT_FORCE_INLINE STORMKIT_PURE - constexpr auto to_dyn_array(T&& range) noexcept -> std::vector> { - return std::forward(range) | stdr::to(); + constexpr auto to_dyn_array(T&& range) noexcept -> dyn_array> { + return std::forward(range) | stdr::to>>(); } ///////////////////////////////////// @@ -164,12 +156,11 @@ namespace stormkit { inline namespace core { requires(sizeof...(Args) > 0) STORMKIT_FORCE_INLINE STORMKIT_PURE - constexpr auto into_array(Args&&... args) noexcept - -> std::array, sizeof...(Args)> { + constexpr auto into_array(Args&&... args) noexcept -> array, sizeof...(Args)> { static_assert((not meta::IsLValueReference and ...), "lvalue reference can't be passed to into_ functions as it take " "ownership"); - return std::array { std::move(args)... }; + return array { std::move(args)... }; } ///////////////////////////////////// @@ -178,11 +169,8 @@ namespace stormkit { inline namespace core { requires(sizeof...(Args) > 0) STORMKIT_FORCE_INLINE STORMKIT_PURE - constexpr auto into_array_of(Args&&... args) noexcept -> std::array { - static_assert((not meta::IsLValueReference and ...), - "lvalue reference can't be passed to into_ functions as it take " - "ownership"); - return std::array { std::move(args)... }; + constexpr auto into_array_of(Args&&... args) noexcept -> array { + return array { T { std::move(args) }... }; } ///////////////////////////////////// @@ -190,12 +178,11 @@ namespace stormkit { inline namespace core { template requires(sizeof...(Args) > 0) STORMKIT_FORCE_INLINE STORMKIT_PURE - constexpr auto into_dyn_array(Args&&... args) noexcept - -> std::vector> { + constexpr auto into_dyn_array(Args&&... args) noexcept -> dyn_array> { static_assert((not meta::IsLValueReference and ...), "lvalue reference can't be passed to into_ functions as it take " "ownership"); - return std::vector { std::move(args)... }; + return dyn_array { std::move(args)... }; } ///////////////////////////////////// @@ -203,11 +190,8 @@ namespace stormkit { inline namespace core { template requires(sizeof...(Args) > 0) STORMKIT_FORCE_INLINE STORMKIT_PURE - constexpr auto into_dyn_array_of(Args&&... args) noexcept -> std::vector { - static_assert((not meta::IsLValueReference and ...), - "lvalue reference can't be passed to into_ functions as it take " - "ownership"); - return std::vector { std::move(args)... }; + constexpr auto into_dyn_array_of(Args&&... args) noexcept -> dyn_array { + return dyn_array { T { std::move(args) }... }; } ///////////////////////////////////// @@ -215,8 +199,8 @@ namespace stormkit { inline namespace core { template STORMKIT_FORCE_INLINE STORMKIT_PURE - constexpr auto as_view(T& range) noexcept -> std::string_view { - return std::string_view { range }; + constexpr auto as_view(T& range) noexcept -> string_view { + return string_view { range }; } ///////////////////////////////////// @@ -224,7 +208,7 @@ namespace stormkit { inline namespace core { template requires(not stdr::range) STORMKIT_FORCE_INLINE STORMKIT_PURE - constexpr auto as_view(T& value) noexcept -> std::span { + constexpr auto as_view(T& value) noexcept -> array_view { return { &value, 1 }; } @@ -232,8 +216,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_FORCE_INLINE STORMKIT_PURE - constexpr auto as_view(T& range) noexcept - -> std::span>> { + constexpr auto as_view(T& range) noexcept -> array_view>> { return { range }; } @@ -241,8 +224,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_FORCE_INLINE STORMKIT_PURE - constexpr auto as_view(T& range, Force) noexcept - -> std::span>> { + constexpr auto as_view(T& range, Force) noexcept -> array_view>> { return { range }; } }} // namespace stormkit::core diff --git a/modules/stormkit/core/coroutines.mpp b/modules/stormkit/core/coroutines.cppm similarity index 60% rename from modules/stormkit/core/coroutines.mpp rename to modules/stormkit/core/coroutines.cppm index fa92ed69b..b62b5fd1b 100644 --- a/modules/stormkit/core/coroutines.mpp +++ b/modules/stormkit/core/coroutines.cppm @@ -1,645 +1,592 @@ -module; - -#include -#include - -#include - -export module stormkit.core:coroutines; - -export import std; - -#if not defined(__cpp_lib_generator) \ - or (defined(__cpp_lib_generator) and (__cpp_lib_generator < 202207L)) -export namespace std { - struct use_allocator_arg {}; - - template, - typename _Allocator = use_allocator_arg> - class generator; - - namespace ranges { - template - inline constexpr bool enable_view> = true; - - template - struct elements_of; - } // namespace ranges -} // namespace std - -namespace std { - template - class __manual_lifetime { - public: - __manual_lifetime() noexcept {} - - ~__manual_lifetime() {} - - template - _T& construct(_Args&&... __args) noexcept(std::is_nothrow_constructible_v<_T, _Args...>) { - return *::new (static_cast(std::addressof(__value_))) _T((_Args&&)__args...); - } - - void destruct() noexcept(std::is_nothrow_destructible_v<_T>) { __value_.~_T(); } - - _T& get() & noexcept { return __value_; } - - _T&& get() && noexcept { return static_cast<_T&&>(__value_); } - - const _T& get() const & noexcept { return __value_; } - - const _T&& get() const && noexcept { return static_cast(__value_); } - - private: - union { - std::remove_const_t<_T> __value_; - }; - }; - - template - class __manual_lifetime<_T&> { - public: - __manual_lifetime() noexcept : __value_(nullptr) {} - - ~__manual_lifetime() {} - - _T& construct(_T& __value) noexcept { - __value_ = std::addressof(__value); - return __value; - } - - void destruct() noexcept {} - - _T& get() const noexcept { return *__value_; } - - private: - _T* __value_; - }; - - template - class __manual_lifetime<_T&&> { - public: - __manual_lifetime() noexcept : __value_(nullptr) {} - - ~__manual_lifetime() {} - - _T&& construct(_T&& __value) noexcept { - __value_ = std::addressof(__value); - return static_cast<_T&&>(__value); - } - - void destruct() noexcept {} - - _T&& get() const noexcept { return static_cast<_T&&>(*__value_); } - - private: - _T* __value_; - }; - - namespace ranges { - template - struct elements_of { - explicit constexpr elements_of(_Rng&& __rng) noexcept - requires std::is_default_constructible_v<_Allocator> - : __range(static_cast<_Rng&&>(__rng)) {} - - constexpr elements_of(_Rng&& __rng, _Allocator&& __alloc) noexcept - : __range((_Rng&&)__rng), __alloc((_Allocator&&)__alloc) {} - - constexpr elements_of(elements_of&&) noexcept = default; - - constexpr elements_of(const elements_of&) = delete; - constexpr elements_of& operator=(const elements_of&) = delete; - constexpr elements_of& operator=(elements_of&&) = delete; - - constexpr _Rng&& get() noexcept { return static_cast<_Rng&&>(__range); } - - constexpr _Allocator get_allocator() const noexcept { return __alloc; } - - private: - STORMKIT_NO_UNIQUE_ADDRESS - _Allocator __alloc; // \expos - _Rng&& __range; // \expos - }; - - template - elements_of(_Rng&&) -> elements_of<_Rng>; - - template - elements_of(_Rng&&, Allocator&&) -> elements_of<_Rng, Allocator>; - } // namespace ranges - - template - static constexpr bool __allocator_needs_to_be_stored = !std::allocator_traits< - _Alloc>::is_always_equal::value - || !std::is_default_constructible_v< - _Alloc>; - - // Round s up to next multiple of a. - constexpr size_t __aligned_allocation_size(size_t s, size_t a) { - return (s + a - 1) & ~(a - 1); - } - - template - class __promise_base_alloc { - static constexpr std::size_t __offset_of_allocator(std::size_t __frameSize) noexcept { - return __aligned_allocation_size(__frameSize, alignof(_Alloc)); - } - - static constexpr std::size_t __padded_frame_size(std::size_t __frameSize) noexcept { - return __offset_of_allocator(__frameSize) + sizeof(_Alloc); - } - - static _Alloc& __get_allocator(void* __frame, std::size_t __frameSize) noexcept { - return *reinterpret_cast<_Alloc*>(static_cast(__frame) - + __offset_of_allocator(__frameSize)); - } - - public: - template - static void* operator new(std::size_t __frameSize, - std::allocator_arg_t, - _Alloc __alloc, - _Args&...) { - void* __frame = __alloc.allocate(__padded_frame_size(__frameSize)); - - // Store allocator at end of the coroutine frame. - // Assuming the allocator's move constructor is non-throwing (a requirement for - // allocators) - ::new (static_cast(std::addressof(__get_allocator(__frame, __frameSize)))) - _Alloc(std::move(__alloc)); - - return __frame; - } - - template - static void* operator new(std::size_t __frameSize, - _This&, - std::allocator_arg_t, - _Alloc __alloc, - _Args&...) { - return __promise_base_alloc::operator new(__frameSize, - std::allocator_arg, - std::move(__alloc)); - } - - static void operator delete(void* __ptr, std::size_t __frameSize) noexcept { - _Alloc& __alloc = __get_allocator(__ptr, __frameSize); - _Alloc __localAlloc(std::move(__alloc)); - __alloc.~Alloc(); - __localAlloc - .deallocate(static_cast(__ptr), __padded_frame_size(__frameSize)); - } - }; - - template - requires(!__allocator_needs_to_be_stored<_Alloc>) - class __promise_base_alloc<_Alloc> { - public: - static void* operator new(std::size_t __size) { - _Alloc __alloc; - return __alloc.allocate(__size); - } - - static void operator delete(void* __ptr, std::size_t __size) noexcept { - _Alloc __alloc; - __alloc.deallocate(static_cast(__ptr), __size); - } - }; - - template - struct __generator_promise_base { - template - friend class generator; - - __generator_promise_base* __root_; - std::coroutine_handle<> __parentOrLeaf_; - // Note: Using manual_lifetime here to avoid extra calls to exception_ptr - // constructor/destructor in cases where it is not needed (i.e. where this - // generator coroutine is not used as a nested coroutine). - // This member is lazily constructed by the __yield_sequence_awaiter::await_suspend() - // method if this generator is used as a nested generator. - __manual_lifetime __exception_; - __manual_lifetime<_Ref> __value_; - - explicit __generator_promise_base(std::coroutine_handle<> thisCoro) noexcept - : __root_(this), __parentOrLeaf_(thisCoro) {} - - ~__generator_promise_base() { - if (__root_ != this) { - // This coroutine was used as a nested generator and so will - // have constructed its __exception_ member which needs to be - // destroyed here. - __exception_.destruct(); - } - } - - std::suspend_always initial_suspend() noexcept { return {}; } - - void return_void() noexcept {} - - void unhandled_exception() { - if (__root_ != this) { - __exception_.get() = std::current_exception(); - } else { - throw; - } - } - - // Transfers control back to the parent of a nested coroutine - struct __final_awaiter { - bool await_ready() noexcept { return false; } - - template - std::coroutine_handle<> await_suspend(std::coroutine_handle<_Promise> __h) noexcept { - _Promise& __promise = __h.promise(); - __generator_promise_base& __root = *__promise.__root_; - if (&__root != &__promise) { - auto __parent = __promise.__parentOrLeaf_; - __root.__parentOrLeaf_ = __parent; - return __parent; - } - return std::noop_coroutine(); - } - - void await_resume() noexcept {} - }; - - __final_awaiter final_suspend() noexcept { return {}; } - - std::suspend_always yield_value(_Ref&& __x) noexcept(std::is_nothrow_move_constructible_v< - _Ref>) { - __root_->__value_.construct((_Ref&&)__x); - return {}; - } - - template - requires(!std::is_reference_v<_Ref>) && std::is_convertible_v<_T, _Ref> - std::suspend_always yield_value(_T&& - __x) noexcept(std::is_nothrow_constructible_v<_Ref, _T>) { - __root_->__value_.construct((_T&&)__x); - return {}; - } - - template - struct __yield_sequence_awaiter { - _Gen __gen_; - - __yield_sequence_awaiter(_Gen&& __g) noexcept - // Taking ownership of the generator ensures frame are destroyed - // in the reverse order of their execution. - : __gen_((_Gen&&)__g) {} - - bool await_ready() noexcept { return false; } - - // set the parent, root and exceptions pointer and - // resume the nested - template - std::coroutine_handle<> await_suspend(std::coroutine_handle<_Promise> __h) noexcept { - __generator_promise_base& __current = __h.promise(); - __generator_promise_base& __nested = *__gen_.__get_promise(); - __generator_promise_base& __root = *__current.__root_; - - __nested.__root_ = __current.__root_; - __nested.__parentOrLeaf_ = __h; - - // Lazily construct the __exception_ member here now that we - // know it will be used as a nested generator. This will be - // destroyed by the promise destructor. - __nested.__exception_.construct(); - __root.__parentOrLeaf_ = __gen_.__get_coro(); - - // Immediately resume the nested coroutine (nested generator) - return __gen_.__get_coro(); - } - - void await_resume() { - __generator_promise_base& __nestedPromise = *__gen_.__get_promise(); - if (__nestedPromise.__exception_.get()) { - std::rethrow_exception(std::move(__nestedPromise.__exception_.get())); - } - } - }; - - template - __yield_sequence_awaiter> - yield_value(std::ranges::elements_of> __g) noexcept { - return std::move(__g).get(); - } - - template - __yield_sequence_awaiter, _Allocator>> - yield_value(std::ranges::elements_of<_Rng, _Allocator>&& __x) { - return [](allocator_arg_t, - [[maybe_unused]] - _Allocator alloc, - auto&& __rng) -> generator<_Ref, std::remove_cvref_t<_Ref>, _Allocator> { - for (auto&& e : __rng) co_yield static_cast(e); - }(std::allocator_arg, __x.get_allocator(), std::forward<_Rng>(__x.get())); - } - - void resume() { __parentOrLeaf_.resume(); } - - // Disable use of co_await within this coroutine. - void await_transform() = delete; - }; - - template - struct __generator_promise; - - template - struct __generator_promise, _ByteAllocator, _ExplicitAllocator> - final: public __generator_promise_base<_Ref>, public __promise_base_alloc<_ByteAllocator> { - __generator_promise() noexcept - : __generator_promise_base< - _Ref>(std::coroutine_handle<__generator_promise>::from_promise(*this)) {} - - generator<_Ref, _Value, _Alloc> get_return_object() noexcept { - return generator<_Ref, _Value, _Alloc> { - std::coroutine_handle<__generator_promise>::from_promise(*this) - }; - } - - using __generator_promise_base<_Ref>::yield_value; - - template - typename __generator_promise_base<_Ref>::template __yield_sequence_awaiter< - generator<_Ref, _Value, _Alloc>> - yield_value(std::ranges::elements_of<_Rng>&& __x) { - static_assert(!_ExplicitAllocator, - "This coroutine has an explicit allocator specified with " - "std::allocator_arg so an allocator needs to be passed " - "explicitely to std::elements_of"); - return [](auto&& __rng) -> generator<_Ref, _Value, _Alloc> { - for (auto&& e : __rng) co_yield static_cast(e); - }(std::forward<_Rng>(__x.get())); - } - }; - - template - using __byte_allocator_t = typename std::allocator_traits< - std::remove_cvref_t<_Alloc>>::template rebind_alloc; - - // Type-erased allocator with default allocator behaviour. - template - struct coroutine_traits, _Args...> { - using promise_type = __generator_promise, - std::allocator>; - }; - - // Type-erased allocator with std::allocator_arg parameter - template - struct coroutine_traits, allocator_arg_t, _Alloc, _Args...> { - private: - using __byte_allocator = __byte_allocator_t<_Alloc>; - - public: - using promise_type = __generator_promise, - __byte_allocator, - true /*explicit Allocator*/>; - }; - - // Type-erased allocator with std::allocator_arg parameter (non-static member functions) - template - struct coroutine_traits, _This, allocator_arg_t, _Alloc, _Args...> { - private: - using __byte_allocator = __byte_allocator_t<_Alloc>; - - public: - using promise_type = __generator_promise, - __byte_allocator, - true /*explicit Allocator*/>; - }; - - // Generator with specified allocator type - template - struct coroutine_traits, _Args...> { - using __byte_allocator = __byte_allocator_t<_Alloc>; - - public: - using promise_type = __generator_promise, __byte_allocator>; - }; - - // TODO : make layout compatible promise casts possible - template - class generator { - using __byte_allocator = __byte_allocator_t<_Alloc>; - - public: - using promise_type = __generator_promise, __byte_allocator>; - friend promise_type; - - private: - using __coroutine_handle = std::coroutine_handle; - - public: - generator() noexcept = default; - - generator(generator&& __other) noexcept - : __coro_(std::exchange(__other.__coro_, {})), - __started_(std::exchange(__other.__started_, false)) {} - - ~generator() noexcept { - if (__coro_) { - if (__started_ && !__coro_.done()) { __coro_.promise().__value_.destruct(); } - __coro_.destroy(); - } - } - - generator& operator=(generator&& g) noexcept { - swap(g); - return *this; - } - - void swap(generator& __other) noexcept { - std::swap(__coro_, __other.__coro_); - std::swap(__started_, __other.__started_); - } - - struct sentinel {}; - - class iterator { - public: - using iterator_category = std::input_iterator_tag; - using difference_type = std::ptrdiff_t; - using value_type = _Value; - using reference = _Ref; - using pointer = std::add_pointer_t<_Ref>; - - iterator() noexcept = default; - iterator(const iterator&) = delete; - - iterator(iterator&& __other) noexcept : __coro_(std::exchange(__other.__coro_, {})) {} - - iterator& operator=(iterator&& __other) { - std::swap(__coro_, __other.__coro_); - return *this; - } - - ~iterator() {} - - friend bool operator==(const iterator& it, sentinel) noexcept { - return it.__coro_.done(); - } - - iterator& operator++() { - __coro_.promise().__value_.destruct(); - __coro_.promise().resume(); - return *this; - } - - void operator++(int) { (void)operator++(); } - - reference operator*() const noexcept { - return static_cast(__coro_.promise().__value_.get()); - } - - private: - friend generator; - - explicit iterator(__coroutine_handle __coro) noexcept : __coro_(__coro) {} - - __coroutine_handle __coro_; - }; - - iterator begin() { - assert(__coro_); - assert(!__started_); - __started_ = true; - __coro_.resume(); - return iterator { __coro_ }; - } - - sentinel end() noexcept { return {}; } - - private: - explicit generator(__coroutine_handle __coro) noexcept : __coro_(__coro) {} - - public: // to get around access restrictions for __yield_sequence_awaitable - std::coroutine_handle<> __get_coro() noexcept { return __coro_; } - - promise_type* __get_promise() noexcept { return std::addressof(__coro_.promise()); } - - private: - __coroutine_handle __coro_; - bool __started_ = false; - }; - - // Specialisation for type-erased allocator implementation. - template - class generator<_Ref, _Value, use_allocator_arg> { - using __promise_base = __generator_promise_base<_Ref>; - - public: - generator() noexcept : __promise_(nullptr), __coro_(), __started_(false) {} - - generator(generator&& __other) noexcept - : __promise_(std::exchange(__other.__promise_, nullptr)), - __coro_(std::exchange(__other.__coro_, {})), - __started_(std::exchange(__other.__started_, false)) {} - - ~generator() noexcept { - if (__coro_) { - if (__started_ && !__coro_.done()) { __promise_->__value_.destruct(); } - __coro_.destroy(); - } - } - - generator& operator=(generator g) noexcept { - swap(g); - return *this; - } - - void swap(generator& __other) noexcept { - std::swap(__promise_, __other.__promise_); - std::swap(__coro_, __other.__coro_); - std::swap(__started_, __other.__started_); - } - - struct sentinel {}; - - class iterator { - public: - using iterator_category = std::input_iterator_tag; - using difference_type = std::ptrdiff_t; - using value_type = _Value; - using reference = _Ref; - using pointer = std::add_pointer_t<_Ref>; - - iterator() noexcept = default; - iterator(const iterator&) = delete; - - iterator(iterator&& __other) noexcept - : __promise_(std::exchange(__other.__promise_, nullptr)), - __coro_(std::exchange(__other.__coro_, {})) {} - - iterator& operator=(iterator&& __other) { - __promise_ = std::exchange(__other.__promise_, nullptr); - __coro_ = std::exchange(__other.__coro_, {}); - return *this; - } - - ~iterator() = default; - - friend bool operator==(const iterator& it, sentinel) noexcept { - return it.__coro_.done(); - } - - iterator& operator++() { - __promise_->__value_.destruct(); - __promise_->resume(); - return *this; - } - - void operator++(int) { (void)operator++(); } - - reference operator*() const noexcept { - return static_cast(__promise_->__value_.get()); - } - - private: - friend generator; - - explicit iterator(__promise_base* __promise, std::coroutine_handle<> __coro) noexcept - : __promise_(__promise), __coro_(__coro) {} - - __promise_base* __promise_; - std::coroutine_handle<> __coro_; - }; - - iterator begin() { - assert(__coro_); - assert(!__started_); - __started_ = true; - __coro_.resume(); - return iterator { __promise_, __coro_ }; - } - - sentinel end() noexcept { return {}; } - - private: - template - friend struct __generator_promise; - - template - explicit generator(std::coroutine_handle<_Promise> __coro) noexcept - : __promise_(std::addressof(__coro.promise())), __coro_(__coro) {} - - public: // to get around access restrictions for __yield_sequence_awaitable - std::coroutine_handle<> __get_coro() noexcept { return __coro_; } - - __promise_base* __get_promise() noexcept { return __promise_; } - - private: - __promise_base* __promise_; - std::coroutine_handle<> __coro_; - bool __started_ = false; - }; - -} // namespace std -#endif +module; + +#include +#include + +#include + +export module stormkit.core:coroutines; + +export import std; + +#if not defined(__cpp_lib_generator) or __cpp_lib_generator < 202207L +export namespace std { + struct use_allocator_arg {}; + + template, typename _Alloc = use_allocator_arg> + class generator; + + template + class __manual_lifetime { + public: + __manual_lifetime() noexcept {} + + ~__manual_lifetime() {} + + template + _T& construct(_Args&&... __args) noexcept(is_nothrow_constructible_v<_T, _Args...>) { + return *::new (static_cast(addressof(__value_))) _T((_Args&&)__args...); + } + + void destruct() noexcept(is_nothrow_destructible_v<_T>) { __value_.~_T(); } + + _T& get() & noexcept { return __value_; } + + _T&& get() && noexcept { return static_cast<_T&&>(__value_); } + + const _T& get() const & noexcept { return __value_; } + + const _T&& get() const && noexcept { return static_cast(__value_); } + + private: + union { + remove_const_t<_T> __value_; + }; + }; + + template + class __manual_lifetime<_T&> { + public: + __manual_lifetime() noexcept : __value_(nullptr) {} + + ~__manual_lifetime() {} + + _T& construct(_T& __value) noexcept { + __value_ = addressof(__value); + return __value; + } + + void destruct() noexcept {} + + _T& get() const noexcept { return *__value_; } + + private: + _T* __value_; + }; + + template + class __manual_lifetime<_T&&> { + public: + __manual_lifetime() noexcept : __value_(nullptr) {} + + ~__manual_lifetime() {} + + _T&& construct(_T&& __value) noexcept { + __value_ = addressof(__value); + return static_cast<_T&&>(__value); + } + + void destruct() noexcept {} + + _T&& get() const noexcept { return static_cast<_T&&>(*__value_); } + + private: + _T* __value_; + }; + + #if defined(__clang__) and (__clang_major__ < 22) + namespace ranges { + template + struct elements_of { + explicit constexpr elements_of(_Rng&& __rng) noexcept + requires std::is_default_constructible_v<_Allocator> + : __range(static_cast<_Rng&&>(__rng)) {} + + constexpr elements_of(_Rng&& __rng, _Allocator&& __alloc) noexcept + : __range((_Rng&&)__rng), __alloc((_Allocator&&)__alloc) {} + + constexpr elements_of(elements_of&&) noexcept = default; + + constexpr elements_of(const elements_of&) = delete; + constexpr elements_of& operator=(const elements_of&) = delete; + constexpr elements_of& operator=(elements_of&&) = delete; + + constexpr _Rng&& get() noexcept { return static_cast<_Rng&&>(__range); } + + constexpr _Allocator get_allocator() const noexcept { return __alloc; } + + private: + [[no_unique_address]] + _Allocator __alloc; // \expos + _Rng&& __range; // \expos + }; + + template + elements_of(_Rng&&) -> elements_of<_Rng>; + + template + elements_of(_Rng&&, Allocator&&) -> elements_of<_Rng, Allocator>; + } // namespace ranges + #endif + + template + inline constexpr bool __allocator_needs_to_be_stored = !allocator_traits<_Alloc>::is_always_equal::value + || !is_default_constructible_v<_Alloc>; + + // Round s up to next multiple of a. + constexpr size_t __aligned_allocation_size(size_t s, size_t a) { + return (s + a - 1) & ~(a - 1); + } + + template + class __promise_base_alloc { + static constexpr size_t __offset_of_allocator(size_t __frameSize) noexcept { + return __aligned_allocation_size(__frameSize, alignof(_Alloc)); + } + + static constexpr size_t __padded_frame_size(size_t __frameSize) noexcept { + return __offset_of_allocator(__frameSize) + sizeof(_Alloc); + } + + static _Alloc& __get_allocator(void* __frame, size_t __frameSize) noexcept { + return *reinterpret_cast<_Alloc*>(static_cast(__frame) + __offset_of_allocator(__frameSize)); + } + + public: + template + static void* operator new(size_t __frameSize, allocator_arg_t, _Alloc __alloc, _Args&...) { + void* __frame = __alloc.allocate(__padded_frame_size(__frameSize)); + + // Store allocator at end of the coroutine frame. + // Assuming the allocator's move constructor is non-throwing (a requirement for + // allocators) + ::new (static_cast(addressof(__get_allocator(__frame, __frameSize)))) _Alloc(move(__alloc)); + + return __frame; + } + + template + static void* operator new(size_t __frameSize, _This&, allocator_arg_t, _Alloc __alloc, _Args&...) { + return __promise_base_alloc::operator new(__frameSize, allocator_arg, move(__alloc)); + } + + static void operator delete(void* __ptr, size_t __frameSize) noexcept { + _Alloc& __alloc = __get_allocator(__ptr, __frameSize); + _Alloc __localAlloc(move(__alloc)); + __alloc.~Alloc(); + __localAlloc.deallocate(static_cast(__ptr), __padded_frame_size(__frameSize)); + } + }; + + template + requires(!__allocator_needs_to_be_stored<_Alloc>) + class __promise_base_alloc<_Alloc> { + public: + static void* operator new(size_t __size) { + _Alloc __alloc; + return __alloc.allocate(__size); + } + + static void operator delete(void* __ptr, size_t __size) noexcept { + _Alloc __alloc; + __alloc.deallocate(static_cast(__ptr), __size); + } + }; + + template + struct __generator_promise_base { + template + friend class generator; + + __generator_promise_base* __root_; + coroutine_handle<> __parentOrLeaf_; + // Note: Using manual_lifetime here to avoid extra calls to exception_ptr + // constructor/destructor in cases where it is not needed (i.e. where this + // generator coroutine is not used as a nested coroutine). + // This member is lazily constructed by the __yield_sequence_awaiter::await_suspend() + // method if this generator is used as a nested generator. + __manual_lifetime __exception_; + __manual_lifetime<_Ref> __value_; + + explicit __generator_promise_base(coroutine_handle<> thisCoro) noexcept : __root_(this), __parentOrLeaf_(thisCoro) {} + + ~__generator_promise_base() { + if (__root_ != this) { + // This coroutine was used as a nested generator and so will + // have constructed its __exception_ member which needs to be + // destroyed here. + __exception_.destruct(); + } + } + + suspend_always initial_suspend() noexcept { return {}; } + + void return_void() noexcept {} + + void unhandled_exception() { + if (__root_ != this) { + __exception_.get() = current_exception(); + } else { + throw; + } + } + + // Transfers control back to the parent of a nested coroutine + struct __final_awaiter { + bool await_ready() noexcept { return false; } + + template + coroutine_handle<> await_suspend(coroutine_handle<_Promise> __h) noexcept { + _Promise& __promise = __h.promise(); + __generator_promise_base& __root = *__promise.__root_; + if (&__root != &__promise) { + auto __parent = __promise.__parentOrLeaf_; + __root.__parentOrLeaf_ = __parent; + return __parent; + } + return noop_coroutine(); + } + + void await_resume() noexcept {} + }; + + __final_awaiter final_suspend() noexcept { return {}; } + + suspend_always yield_value(_Ref&& __x) noexcept(is_nothrow_move_constructible_v<_Ref>) { + __root_->__value_.construct((_Ref&&)__x); + return {}; + } + + template + requires(!is_reference_v<_Ref>) && is_convertible_v<_T, _Ref> + suspend_always yield_value(_T&& __x) noexcept(is_nothrow_constructible_v<_Ref, _T>) { + __root_->__value_.construct((_T&&)__x); + return {}; + } + + template + struct __yield_sequence_awaiter { + _Gen __gen_; + + __yield_sequence_awaiter(_Gen&& __g) noexcept + // Taking ownership of the generator ensures frame are destroyed + // in the reverse order of their execution. + : __gen_((_Gen&&)__g) {} + + bool await_ready() noexcept { return false; } + + // set the parent, root and exceptions pointer and + // resume the nested + template + coroutine_handle<> await_suspend(coroutine_handle<_Promise> __h) noexcept { + __generator_promise_base& __current = __h.promise(); + __generator_promise_base& __nested = *__gen_.__get_promise(); + __generator_promise_base& __root = *__current.__root_; + + __nested.__root_ = __current.__root_; + __nested.__parentOrLeaf_ = __h; + + // Lazily construct the __exception_ member here now that we + // know it will be used as a nested generator. This will be + // destroyed by the promise destructor. + __nested.__exception_.construct(); + __root.__parentOrLeaf_ = __gen_.__get_coro(); + + // Immediately resume the nested coroutine (nested generator) + return __gen_.__get_coro(); + } + + void await_resume() { + __generator_promise_base& __nestedPromise = *__gen_.__get_promise(); + if (__nestedPromise.__exception_.get()) { rethrow_exception(std::move(__nestedPromise.__exception_.get())); } + } + }; + + template + __yield_sequence_awaiter> yield_value(ranges::elements_of< + generator<_Ref, _OValue, _OAlloc>> __g) noexcept { + return move(__g).get(); + } + + template + __yield_sequence_awaiter, _Allocator>> yield_value(ranges::elements_of<_Rng, + _Allocator>&& + __x) { + return [](allocator_arg_t, + [[maybe_unused]] + _Allocator alloc, + auto&& __rng) -> generator<_Ref, remove_cvref_t<_Ref>, _Allocator> { + for (auto&& e : __rng) co_yield static_cast(e); + }(allocator_arg, __x.get_allocator(), forward<_Rng>(__x.get())); + } + + void resume() { __parentOrLeaf_.resume(); } + + // Disable use of co_await within this coroutine. + void await_transform() = delete; + }; + + template + struct __generator_promise; + + template + struct __generator_promise, _byteAllocator, _ExplicitAllocator> final + : public __generator_promise_base<_Ref>, + public __promise_base_alloc<_byteAllocator> { + __generator_promise() noexcept + : __generator_promise_base<_Ref>(coroutine_handle<__generator_promise>::from_promise(*this)) {} + + generator<_Ref, _Value, _Alloc> get_return_object() noexcept { + return generator<_Ref, _Value, _Alloc> { coroutine_handle<__generator_promise>::from_promise(*this) }; + } + + using __generator_promise_base<_Ref>::yield_value; + + template + typename __generator_promise_base<_Ref>::template __yield_sequence_awaiter> + yield_value(ranges::elements_of<_Rng>&& __x) { + static_assert(!_ExplicitAllocator, + "This coroutine has an explicit allocator specified with " + "allocator_arg so an allocator needs to be passed " + "explicitely to elements_of"); + return [](auto&& __rng) -> generator<_Ref, _Value, _Alloc> { + for (auto&& e : __rng) co_yield static_cast(e); + }(forward<_Rng>(__x.get())); + } + }; + + template + using __byte_allocator_t = typename allocator_traits>::template rebind_alloc; + + // Type-erased allocator with default allocator behaviour. + template + struct coroutine_traits, _Args...> { + using promise_type = __generator_promise, allocator>; + }; + + // Type-erased allocator with allocator_arg parameter + template + struct coroutine_traits, allocator_arg_t, _Alloc, _Args...> { + private: + using __byte_allocator = __byte_allocator_t<_Alloc>; + + public: + using promise_type = __generator_promise, __byte_allocator, true /*explicit Allocator*/>; + }; + + // Type-erased allocator with allocator_arg parameter (non-static member functions) + template + struct coroutine_traits, _This, allocator_arg_t, _Alloc, _Args...> { + private: + using __byte_allocator = __byte_allocator_t<_Alloc>; + + public: + using promise_type = __generator_promise, __byte_allocator, true /*explicit Allocator*/>; + }; + + // Generator with specified allocator type + template + struct coroutine_traits, _Args...> { + using __byte_allocator = __byte_allocator_t<_Alloc>; + + public: + using promise_type = __generator_promise, __byte_allocator>; + }; + + // TODO : make layout compatible promise casts possible + template + class generator { + using __byte_allocator = __byte_allocator_t<_Alloc>; + + public: + using promise_type = __generator_promise, __byte_allocator>; + friend promise_type; + + private: + using __coroutine_handle = coroutine_handle; + + public: + generator() noexcept = default; + + generator(generator&& __other) noexcept + : __coro_(exchange(__other.__coro_, {})), __started_(exchange(__other.__started_, false)) {} + + ~generator() noexcept { + if (__coro_) { + if (__started_ && !__coro_.done()) { __coro_.promise().__value_.destruct(); } + __coro_.destroy(); + } + } + + generator& operator=(generator&& g) noexcept { + swap(g); + return *this; + } + + void swap(generator& __other) noexcept { + swap(__coro_, __other.__coro_); + swap(__started_, __other.__started_); + } + + struct sentinel {}; + + class iterator { + public: + using iterator_category = input_iterator_tag; + using difference_type = ptrdiff_t; + using value_type = _Value; + using reference = _Ref; + using pointer = add_pointer_t<_Ref>; + + iterator() noexcept = default; + iterator(const iterator&) = delete; + + iterator(iterator&& __other) noexcept : __coro_(exchange(__other.__coro_, {})) {} + + iterator& operator=(iterator&& __other) { + std::swap(__coro_, __other.__coro_); + return *this; + } + + ~iterator() {} + + friend bool operator==(const iterator& it, sentinel) noexcept { return it.__coro_.done(); } + + iterator& operator++() { + __coro_.promise().__value_.destruct(); + __coro_.promise().resume(); + return *this; + } + + void operator++(int) { (void)operator++(); } + + reference operator*() const noexcept { return static_cast(__coro_.promise().__value_.get()); } + + private: + friend generator; + + explicit iterator(__coroutine_handle __coro) noexcept : __coro_(__coro) {} + + __coroutine_handle __coro_; + }; + + iterator begin() { + assert(__coro_); + assert(!__started_); + __started_ = true; + __coro_.resume(); + return iterator { __coro_ }; + } + + sentinel end() noexcept { return {}; } + + private: + explicit generator(__coroutine_handle __coro) noexcept : __coro_(__coro) {} + + public: // to get around access restrictions for __yield_sequence_awaitable + coroutine_handle<> __get_coro() noexcept { return __coro_; } + + promise_type* __get_promise() noexcept { return addressof(__coro_.promise()); } + + private: + __coroutine_handle __coro_; + bool __started_ = false; + }; + + // Specialisation for type-erased allocator implementation. + template + class generator<_Ref, _Value, use_allocator_arg> { + using __promise_base = __generator_promise_base<_Ref>; + + public: + generator() noexcept : __promise_(nullptr), __coro_(), __started_(false) {} + + generator(generator&& __other) noexcept + : __promise_(exchange(__other.__promise_, nullptr)), + __coro_(exchange(__other.__coro_, {})), + __started_(exchange(__other.__started_, false)) {} + + ~generator() noexcept { + if (__coro_) { + if (__started_ && !__coro_.done()) { __promise_->__value_.destruct(); } + __coro_.destroy(); + } + } + + generator& operator=(generator g) noexcept { + swap(g); + return *this; + } + + void swap(generator& __other) noexcept { + swap(__promise_, __other.__promise_); + swap(__coro_, __other.__coro_); + swap(__started_, __other.__started_); + } + + struct sentinel {}; + + class iterator { + public: + using iterator_category = input_iterator_tag; + using difference_type = ptrdiff_t; + using value_type = _Value; + using reference = _Ref; + using pointer = add_pointer_t<_Ref>; + + iterator() noexcept = default; + iterator(const iterator&) = delete; + + iterator(iterator&& __other) noexcept + : __promise_(exchange(__other.__promise_, nullptr)), __coro_(exchange(__other.__coro_, {})) {} + + iterator& operator=(iterator&& __other) { + __promise_ = exchange(__other.__promise_, nullptr); + __coro_ = exchange(__other.__coro_, {}); + return *this; + } + + ~iterator() = default; + + friend bool operator==(const iterator& it, sentinel) noexcept { return it.__coro_.done(); } + + iterator& operator++() { + __promise_->__value_.destruct(); + __promise_->resume(); + return *this; + } + + void operator++(int) { (void)operator++(); } + + reference operator*() const noexcept { return static_cast(__promise_->__value_.get()); } + + private: + friend generator; + + explicit iterator(__promise_base* __promise, coroutine_handle<> __coro) noexcept + : __promise_(__promise), __coro_(__coro) {} + + __promise_base* __promise_; + coroutine_handle<> __coro_; + }; + + iterator begin() { + assert(__coro_); + assert(!__started_); + __started_ = true; + __coro_.resume(); + return iterator { __promise_, __coro_ }; + } + + sentinel end() noexcept { return {}; } + + private: + template + friend struct __generator_promise; + + template + explicit generator(coroutine_handle<_Promise> __coro) noexcept + : __promise_(addressof(__coro.promise())), __coro_(__coro) {} + + public: // to get around access restrictions for __yield_sequence_awaitable + coroutine_handle<> __get_coro() noexcept { return __coro_; } + + __promise_base* __get_promise() noexcept { return __promise_; } + + private: + __promise_base* __promise_; + coroutine_handle<> __coro_; + bool __started_ = false; + }; +} // namespace std +#endif diff --git a/modules/stormkit/core/errors.mpp b/modules/stormkit/core/errors.cppm similarity index 82% rename from modules/stormkit/core/errors.mpp rename to modules/stormkit/core/errors.cppm index ddd671a1f..93ad5d9f9 100644 --- a/modules/stormkit/core/errors.mpp +++ b/modules/stormkit/core/errors.cppm @@ -20,6 +20,8 @@ export module stormkit.core:errors; import std; +import :string.aliases; + export { namespace stormkit { inline namespace core { #if (defined(__clang__) or defined(__GNUC__)) @@ -36,9 +38,7 @@ export { constexpr auto final_suspend() const noexcept -> std::suspend_never { return {}; } - constexpr auto get_return_object() noexcept -> Expected { - return Expected { this }; - } + constexpr auto get_return_object() noexcept -> Expected { return Expected { this }; } template constexpr auto return_value(Args&&... args) noexcept { @@ -61,9 +61,7 @@ export { Expected* expected_ptr = nullptr; }; - constexpr Expected(promise_type* promise) noexcept : Expected {} { - promise->expected_ptr = this; - } + constexpr Expected(promise_type* promise) noexcept : Expected {} { promise->expected_ptr = this; } constexpr auto await_ready() const noexcept -> bool { return this->has_value(); } @@ -93,8 +91,8 @@ export { template struct DecoratedError { - Error error; - std::string message = ""; + Error error; + string message = ""; }; template<> @@ -102,18 +100,17 @@ export { explicit DecoratedError(Error _error) noexcept; Error error; - std::string message; + string message; }; - auto to_string(const SystemError& error) noexcept -> std::string; + auto to_string(const SystemError& error) noexcept -> string; }} // namespace stormkit::core namespace std { template struct formatter, CharT>: formatter { template - auto format(const stormkit::core::Error&, FormatContext& ctx) const - -> decltype(ctx.out()); + auto format(const stormkit::core::Error&, FormatContext& ctx) const -> decltype(ctx.out()); }; template @@ -122,8 +119,7 @@ export { constexpr auto parse(ParseContext& ctx) noexcept -> decltype(ctx.begin()); template - auto format(const stormkit::core::DecoratedError&, FormatContext& ctx) const - -> decltype(ctx.out()); + auto format(const stormkit::core::DecoratedError&, FormatContext& ctx) const -> decltype(ctx.out()); }; } // namespace std } @@ -152,12 +148,12 @@ namespace stormkit { inline namespace core { //////////////////////////////////////// //////////////////////////////////////// STORMKIT_FORCE_INLINE - inline auto to_string(const SystemError& error) noexcept -> std::string { + inline auto to_string(const SystemError& error) noexcept -> string { const auto code = static_cast(error.code); #ifdef STORMKIT_OS_WINDOWS - thread_local auto STRERROR_BUFFER = std::array {}; + thread_local auto STRERROR_BUFFER = array {}; strerror_s(stdr::data(STRERROR_BUFFER), stdr::size(STRERROR_BUFFER), code); - return std::string { stdr::data(STRERROR_BUFFER) }; + return string { stdr::data(STRERROR_BUFFER) }; #else return std::strerror(code); #endif @@ -170,9 +166,8 @@ namespace std { template template STORMKIT_FORCE_INLINE - inline auto formatter, - CharT>::format(const stormkit::core::Error& error, - FormatContext& ctx) const -> decltype(ctx.out()) { + inline auto formatter, CharT>::format(const stormkit::core::Error& error, FormatContext& ctx) + const -> decltype(ctx.out()) { return formatter::format(error.code, ctx); } @@ -181,8 +176,8 @@ namespace std { template template STORMKIT_FORCE_INLINE - constexpr auto formatter, - CharT>::parse(ParseContext& ctx) noexcept -> decltype(ctx.begin()) { + constexpr auto formatter, CharT>::parse(ParseContext& ctx) noexcept + -> decltype(ctx.begin()) { return ctx.begin(); } @@ -191,9 +186,8 @@ namespace std { template template STORMKIT_FORCE_INLINE - inline auto formatter, - CharT>::format(const stormkit::core::DecoratedError& error, - FormatContext& ctx) const -> decltype(ctx.out()) { + inline auto formatter, CharT>::format(const stormkit::core::DecoratedError& error, + FormatContext& ctx) const -> decltype(ctx.out()) { auto&& out = ctx.out(); return format_to("message: {}, code: {}", error.message, error.error.code); } diff --git a/modules/stormkit/core/functional.mpp b/modules/stormkit/core/functional.cppm similarity index 100% rename from modules/stormkit/core/functional.mpp rename to modules/stormkit/core/functional.cppm diff --git a/modules/stormkit/core/functional/error_handling.cppm b/modules/stormkit/core/functional/error_handling.cppm new file mode 100644 index 000000000..17f37ba97 --- /dev/null +++ b/modules/stormkit/core/functional/error_handling.cppm @@ -0,0 +1,93 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +export module stormkit.core:functional.error_handling; + +import std; + +import :meta; + +import :console; +import :utils.contract; + +export namespace stormkit { inline namespace core { namespace monadic { + [[nodiscard]] + constexpr auto assert(std::optional message = std::nullopt, + std::source_location location = std::source_location::current()) noexcept -> decltype(auto); + + template + [[nodiscard]] + constexpr auto assert(std::optional message = std::nullopt, + std::source_location location = std::source_location::current()) noexcept -> decltype(auto); + + [[nodiscard]] + constexpr auto log(std::invocable auto&& logger, string&& message) noexcept -> decltype(auto); + + [[nodiscard]] + constexpr auto throw_as_exception() noexcept -> decltype(auto); +}}} // namespace stormkit::core::monadic + +#ifdef STORMKIT_COMPILER_CLANG + #define NORETURN_LAMBDA [[noreturn]] +#else + #define NORETURN_LAMBDA +#endif + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit { inline namespace core { namespace monadic { + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto assert(std::optional message, std::source_location location) noexcept -> decltype(auto) { + return [message = std::move(message), location = std::move(location)] NORETURN_LAMBDA(const E& error) -> T { + if (message.has_value()) core::assert(false, std::format("{} ({})", *message, error), std::move(location)); + else + core::assert(false, std::move(location)); + + std::unreachable(); + }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto assert(std::optional message, std::source_location location) noexcept -> decltype(auto) { + return [message = std::move(message), location = std::move(location)] NORETURN_LAMBDA(const E& error) -> E { + if (message.has_value()) core::assert(false, std::format("{} ({})", *message, error), std::move(location)); + else + core::assert(false, std::format("{}", error), std::move(location)); + + std::unreachable(); + }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto log(std::invocable auto&& logger, string&& message) noexcept -> decltype(auto) { + return [logger = std::forward, + message = std::move(message)](auto&& error) -> std::expected> { + logger(message, error); + + return {}; + }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto throw_as_exception() noexcept -> decltype(auto) { + return [] NORETURN_LAMBDA(auto&& error) static -> std::expected> { + throw std::forward(error); + }; + } +}}} // namespace stormkit::core::monadic diff --git a/modules/stormkit/core/functional/error_handling.mpp b/modules/stormkit/core/functional/error_handling.mpp deleted file mode 100644 index add1958f7..000000000 --- a/modules/stormkit/core/functional/error_handling.mpp +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -export module stormkit.core:functional.error_handling; - -import std; - -import :meta; - -import :console; -import :utils.contract; - -export namespace stormkit { inline namespace core { namespace monadic { - [[nodiscard]] - constexpr auto assert(std::optional message = std::nullopt, - std::source_location location = std::source_location::current()) noexcept - -> decltype(auto); - - template - [[nodiscard]] - constexpr auto assert(std::optional message = std::nullopt, - std::source_location location = std::source_location::current()) noexcept - -> decltype(auto); - - [[nodiscard]] - constexpr auto log(std::invocable auto&& logger, std::string&& message) noexcept - -> decltype(auto); - - [[nodiscard]] - constexpr auto throw_as_exception() noexcept -> decltype(auto); -}}} // namespace stormkit::core::monadic - -#ifdef STORMKIT_COMPILER_CLANG - #define NORETURN_LAMBDA [[noreturn]] -#else - #define NORETURN_LAMBDA -#endif - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit { inline namespace core { namespace monadic { - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr auto assert(std::optional message, - std::source_location location) noexcept -> decltype(auto) { - return - [message = std::move(message), location = std::move(location)] NORETURN_LAMBDA() -> T { - if (message.has_value()) core::assert(false, *message, std::move(location)); - else - core::assert(false, std::move(location)); - - std::unreachable(); - }; - } - - //////////////////////////////////////// - //////////////////////////////////////// - STORMKIT_FORCE_INLINE - constexpr auto assert(std::optional message, - std::source_location location) noexcept -> decltype(auto) { - return - [message = std::move(message), location = std::move(location)] - NORETURN_LAMBDA(const E& error) -> E { - if (message.has_value()) - core::assert(false, std::format("{} ({})", *message, error), std::move(location)); - else - core::assert(false, std::format("{}", error), std::move(location)); - - std::unreachable(); - }; - } - - //////////////////////////////////////// - //////////////////////////////////////// - STORMKIT_FORCE_INLINE - constexpr auto log(std::invocable auto&& logger, std::string&& message) noexcept - -> decltype(auto) { - return [logger = std::forward, message = std::move(message)](auto&& error) - -> std::expected> { - logger(message, error); - - return {}; - }; - } - - //////////////////////////////////////// - //////////////////////////////////////// - STORMKIT_FORCE_INLINE - constexpr auto throw_as_exception() noexcept -> decltype(auto) { - return [] NORETURN_LAMBDA(auto&& error) static - -> std::expected> { - throw std::forward(error); - }; - } -}}} // namespace stormkit::core::monadic diff --git a/modules/stormkit/core/functional/monadic.mpp b/modules/stormkit/core/functional/monadic.cppm similarity index 81% rename from modules/stormkit/core/functional/monadic.mpp rename to modules/stormkit/core/functional/monadic.cppm index 71cb92e66..cb12bf6e4 100644 --- a/modules/stormkit/core/functional/monadic.mpp +++ b/modules/stormkit/core/functional/monadic.cppm @@ -36,8 +36,7 @@ export namespace stormkit { inline namespace core { namespace monadic { constexpr auto value() noexcept -> decltype(auto); template [[nodiscard]] - constexpr auto as(const std::source_location& - location = std::source_location::current()) noexcept -> decltype(auto); + constexpr auto as(const std::source_location& location = std::source_location::current()) noexcept -> decltype(auto); template [[nodiscard]] constexpr auto narrow() noexcept -> decltype(auto); @@ -75,9 +74,7 @@ export namespace stormkit { inline namespace core { namespace monadic { [[nodiscard]] constexpr auto noop() noexcept -> decltype(auto); - template First, - std::invocable> Second> + template First, std::invocable> Second> [[nodiscard]] constexpr auto map(First&& first, Second&& second) noexcept -> decltype(auto); @@ -85,8 +82,7 @@ export namespace stormkit { inline namespace core { namespace monadic { constexpr auto map(auto&& first, auto&& second) noexcept -> decltype(auto); [[nodiscard]] - constexpr auto either(std::regular_invocable auto&&... visitors) noexcept - -> decltype(auto); + constexpr auto either(std::regular_invocable auto&&... visitors) noexcept -> decltype(auto); template [[nodiscard]] @@ -146,18 +142,15 @@ namespace stormkit { inline namespace core { namespace monadic { [[nodiscard]] STORMKIT_FORCE_INLINE STORMKIT_PURE constexpr auto identity(T&& value) noexcept -> decltype(auto) { - return [value = std::forward(value)] mutable noexcept -> decltype(auto) { - return std::forward_like(value); - }; + return [value = std::forward(value)] mutable noexcept -> decltype(auto) { return std::forward_like(value); }; } ///////////////////////////////////// ///////////////////////////////////// - template [[nodiscard]] STORMKIT_FORCE_INLINE STORMKIT_PURE - constexpr auto consume(T&& value) noexcept -> decltype(auto) { - return [value = std::move(value)](auto&&...) mutable noexcept -> meta::CanonicalType { + constexpr auto consume(auto&& value) noexcept -> decltype(auto) { + return [value = std::move(value)](auto&&...) mutable noexcept -> meta::CanonicalType { return std::move(value); }; } @@ -166,9 +159,8 @@ namespace stormkit { inline namespace core { namespace monadic { ///////////////////////////////////// STORMKIT_FORCE_INLINE STORMKIT_CONST constexpr auto value() noexcept -> decltype(auto) { - return [](T&& value) static noexcept -> decltype(auto) { - return std::forward_like(value.get()); - }; + return + [](T&& value) static noexcept -> decltype(auto) { return std::forward_like(value.get()); }; } ///////////////////////////////////// @@ -177,9 +169,7 @@ namespace stormkit { inline namespace core { namespace monadic { STORMKIT_FORCE_INLINE STORMKIT_PURE constexpr auto as(const std::source_location& location) noexcept -> decltype(auto) { - return [location](U&& value) noexcept -> T { - return core::as(std::forward(value), location); - }; + return [location](U&& value) noexcept -> T { return core::as(std::forward(value), location); }; } ///////////////////////////////////// @@ -188,9 +178,7 @@ namespace stormkit { inline namespace core { namespace monadic { STORMKIT_FORCE_INLINE STORMKIT_CONST constexpr auto narrow() noexcept -> decltype(auto) { - return [](U&& value) static noexcept -> decltype(auto) { - return core::narrow(std::forward(value)); - }; + return [](U&& value) static noexcept -> decltype(auto) { return core::narrow(std::forward(value)); }; } //////////////////////////////////////// @@ -199,18 +187,14 @@ namespace stormkit { inline namespace core { namespace monadic { STORMKIT_FORCE_INLINE STORMKIT_PURE constexpr auto is_equal(T&& value) noexcept -> decltype(auto) { - return [value = std::forward(value)](U&& other) { - return core::is_equal(value, std::forward(other)); - }; + return [value = std::forward(value)](U&& other) { return core::is_equal(value, std::forward(other)); }; } //////////////////////////////////////// //////////////////////////////////////// STORMKIT_FORCE_INLINE STORMKIT_PURE constexpr auto append_to(std::ranges::range auto& range) noexcept -> decltype(auto) { - return [&range](T&& val) noexcept { - range.emplace(std::ranges::cend(range), std::forward(val)); - }; + return [&range](T&& val) noexcept { range.emplace(std::ranges::cend(range), std::forward(val)); }; } //////////////////////////////////////// @@ -219,8 +203,9 @@ namespace stormkit { inline namespace core { namespace monadic { STORMKIT_FORCE_INLINE STORMKIT_PURE constexpr auto wrap(T&& func) noexcept { - return [func = std::forward(func)](Args&&... args) noexcept - -> decltype(auto) { return std::invoke(func, std::forward(args)...); }; + return [func = std::forward(func)](Args&&... args) noexcept -> decltype(auto) { + return std::invoke(func, std::forward(args)...); + }; } //////////////////////////////////////// @@ -286,9 +271,7 @@ namespace stormkit { inline namespace core { namespace monadic { STORMKIT_FORCE_INLINE STORMKIT_PURE constexpr auto unpack_tuple_to(T&& func) noexcept -> decltype(auto) { - return [func = std::forward(func)](U&& arg) noexcept { - return std::apply(func, std::forward(arg)); - }; + return [func = std::forward(func)](U&& arg) noexcept { return std::apply(func, std::forward(arg)); }; } //////////////////////////////////////// @@ -309,30 +292,22 @@ namespace stormkit { inline namespace core { namespace monadic { ///////////////////////////////////// STORMKIT_FORCE_INLINE STORMKIT_PURE constexpr auto set(auto& output) noexcept -> decltype(auto) { - return [&output](T&& value) mutable noexcept -> void { - output = std::forward(value); - }; + return [&output](T&& value) mutable noexcept -> void { output = std::forward(value); }; } ///////////////////////////////////// ///////////////////////////////////// STORMKIT_FORCE_INLINE STORMKIT_PURE constexpr auto emplace_to(std::ranges::range auto& container) noexcept -> decltype(auto) { - return [&container](T&& value) noexcept -> void { - container.emplace_back(std::forward(value)); - }; + return [&container](T&& value) noexcept -> void { container.emplace_back(std::forward(value)); }; } template - constexpr auto - is_noexcept = noexcept(std::declval< - Second>()(std::declval()(std::declval()...))); + constexpr auto is_noexcept = noexcept(std::declval()(std::declval()(std::declval()...))); ///////////////////////////////////// ///////////////////////////////////// - template First, - std::invocable> Second> + template First, std::invocable> Second> STORMKIT_FORCE_INLINE STORMKIT_PURE constexpr auto map(First&& first, Second&& second) noexcept -> decltype(auto) { @@ -349,15 +324,15 @@ namespace stormkit { inline namespace core { namespace monadic { using SecondP = meta::CanonicalType; return [first = std::forward(first), second = std::forward(second)]< - typename... Args>(Args&&... args) noexcept(is_noexcept) - -> decltype(auto) { return second(first(std::forward(args)...)); }; + typename... Args>(Args&&... args) noexcept(is_noexcept) -> decltype(auto) { + return second(first(std::forward(args)...)); + }; } ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_FORCE_INLINE - STORMKIT_PURE + STORMKIT_FORCE_INLINE STORMKIT_PURE constexpr auto either(meta::IsUnaryPredicate auto&& predicate, std::invocable auto&& true_, std::invocable auto&& false_) noexcept -> decltype(auto) { @@ -375,9 +350,7 @@ namespace stormkit { inline namespace core { namespace monadic { STORMKIT_FORCE_INLINE STORMKIT_CONST constexpr auto get() noexcept -> decltype(auto) { - return [](U&& value) static noexcept -> decltype(auto) { - return std::get(std::forward(value)); - }; + return [](U&& value) static noexcept -> decltype(auto) { return std::get(std::forward(value)); }; } ///////////////////////////////////// @@ -395,8 +368,7 @@ namespace stormkit { inline namespace core { namespace monadic { STORMKIT_FORCE_INLINE STORMKIT_CONST constexpr auto is() noexcept -> decltype(auto) { - return - [](U&& value) static noexcept { return core::is(std::forward(value)); }; + return [](U&& value) static noexcept { return core::is(std::forward(value)); }; } ///////////////////////////////////// @@ -405,22 +377,17 @@ namespace stormkit { inline namespace core { namespace monadic { STORMKIT_FORCE_INLINE STORMKIT_PURE constexpr auto either(Args&&... visitors) noexcept -> decltype(auto) { - return - [... visitors = std::forward(visitors)](T&& variant) mutable noexcept - -> decltype(auto) { - return std::visit(core::Overloaded { std::forward(visitors)... }, - std::forward(variant)); - }; + return [... visitors = std::forward(visitors)](T&& variant) mutable noexcept -> decltype(auto) { + return std::visit(core::Overloaded { std::forward(visitors)... }, std::forward(variant)); + }; } ///////////////////////////////////// ///////////////////////////////////// STORMKIT_FORCE_INLINE STORMKIT_CONST constexpr auto clone() noexcept -> decltype(auto) { - return - [](T&& value) static noexcept(noexcept(std::is_nothrow_copy_constructible_v< - meta::CanonicalType>)) - -> decltype(auto) { return auto(std::forward(value)); }; + return [](T&& value) static noexcept(noexcept(std::is_nothrow_copy_constructible_v>)) + -> decltype(auto) { return auto(std::forward(value)); }; } ///////////////////////////////////// @@ -429,10 +396,8 @@ namespace stormkit { inline namespace core { namespace monadic { STORMKIT_FORCE_INLINE STORMKIT_CONST constexpr auto init() noexcept -> decltype(auto) { - return [](Args&&... args) static noexcept( - noexcept(std::is_nothrow_constructible_v)) -> decltype(auto) { - return T { std::forward(args)... }; - }; + return [](Args&&... args) static noexcept(noexcept(std::is_nothrow_constructible_v)) + -> decltype(auto) { return T { std::forward(args)... }; }; } ///////////////////////////////////// @@ -441,10 +406,8 @@ namespace stormkit { inline namespace core { namespace monadic { STORMKIT_FORCE_INLINE STORMKIT_PURE constexpr auto init(Args&&... args) noexcept -> decltype(auto) { - return - [... args = std::forward< - Args>(args)]() mutable noexcept(noexcept(std::is_nothrow_constructible_v)) - -> decltype(auto) { return T { std::forward(args)... }; }; + return [... args = std::forward(args)]() mutable noexcept(noexcept(std::is_nothrow_constructible_v)) + -> decltype(auto) { return T { std::forward(args)... }; }; } ///////////////////////////////////// @@ -462,35 +425,28 @@ namespace stormkit { inline namespace core { namespace monadic { ///////////////////////////////////// STORMKIT_FORCE_INLINE STORMKIT_CONST constexpr auto as_ref() noexcept -> decltype(auto) { - return [](T&& value) static noexcept -> decltype(auto) { - return core::as_ref(std::forward(value)); - }; + return [](T&& value) static noexcept -> decltype(auto) { return core::as_ref(std::forward(value)); }; } ///////////////////////////////////// ///////////////////////////////////// STORMKIT_FORCE_INLINE STORMKIT_CONST constexpr auto as_ref_mut() noexcept -> decltype(auto) { - return [](T&& value) static noexcept -> decltype(auto) { - return core::as_ref_mut(std::forward(value)); - }; + return [](T&& value) static noexcept -> decltype(auto) { return core::as_ref_mut(std::forward(value)); }; } ///////////////////////////////////// ///////////////////////////////////// STORMKIT_FORCE_INLINE STORMKIT_CONST constexpr auto unref() noexcept -> decltype(auto) { - return - [](const auto& value) static noexcept -> decltype(auto) { return core::unref(value); }; + return [](const auto& value) static noexcept -> decltype(auto) { return core::unref(value); }; } ///////////////////////////////////// ///////////////////////////////////// STORMKIT_FORCE_INLINE STORMKIT_CONST constexpr auto unref_mut() noexcept -> decltype(auto) { - return [](const auto& value) static noexcept -> decltype(auto) { - return core::unref_mut(value); - }; + return [](const auto& value) static noexcept -> decltype(auto) { return core::unref_mut(value); }; } ///////////////////////////////////// @@ -499,8 +455,6 @@ namespace stormkit { inline namespace core { namespace monadic { STORMKIT_FORCE_INLINE STORMKIT_CONST constexpr auto forward_like() noexcept -> decltype(auto) { - return [](auto&& value) static noexcept -> decltype(auto) { - return std::forward_like(value); - }; + return [](auto&& value) static noexcept -> decltype(auto) { return std::forward_like(value); }; } }}} // namespace stormkit::core::monadic diff --git a/modules/stormkit/core/functional/utils.mpp b/modules/stormkit/core/functional/utils.cppm similarity index 64% rename from modules/stormkit/core/functional/utils.mpp rename to modules/stormkit/core/functional/utils.cppm index 11cda0e43..fac519139 100644 --- a/modules/stormkit/core/functional/utils.mpp +++ b/modules/stormkit/core/functional/utils.cppm @@ -1,137 +1,122 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -export module stormkit.core:functional.utils; - -import std; - -import :meta; - -namespace stormkit { inline namespace core { namespace details { - struct EitherFunc { - [[nodiscard]] - static constexpr auto operator()(bool condition, - std::invocable auto&& true_, - std::invocable auto&& false_) noexcept - -> decltype(false_()); - - template - using ForwardArg = meta::ForwardLike>>; - - template - [[nodiscard]] - static constexpr auto operator()(T value, - std::invocable&> auto&& true_, - std::invocable auto&& false_) noexcept - -> decltype(false_()); - - template - requires(meta::IsConvertibleTo) - [[nodiscard]] - static constexpr auto operator()(T&& value, - std::invocable> auto&& true_, - std::invocable auto&& false_) noexcept - -> decltype(false_()); - }; -}}} // namespace stormkit::core::details - -export namespace stormkit { inline namespace core { - inline constexpr auto either = details::EitherFunc {}; - - using std::bind_back; - using std::bind_front; - - template - requires(std::invocable - and meta::Is, void>) - [[nodiscard]] - constexpr auto init_by(Func&& func, Args&&... args) noexcept -> T; -}} // namespace stormkit::core - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit { inline namespace core { - namespace details { - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - constexpr auto EitherFunc::operator()(bool condition, - std::invocable auto&& true_, - std::invocable auto&& false_) noexcept - -> decltype(false_()) { - if (condition) return true_(); - return false_(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr auto EitherFunc::operator()(T value, - std::invocable&> auto&& true_, - std::invocable auto&& false_) noexcept - -> decltype(false_()) { - if (static_cast(value)) return true_(*value); - return false_(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - requires(meta::IsConvertibleTo) - STORMKIT_FORCE_INLINE - constexpr auto EitherFunc::operator()(T&& value, - std::invocable> auto&& true_, - std::invocable auto&& false_) noexcept - -> decltype(false_()) { - if (static_cast(value)) return true_(std::forward_like(*value)); - return false_(); - } - } // namespace details - -#if not(defined(__cpp_lib_bind_back) and __cpp_lib_bind_back >= 202306L) - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr auto bind_back(Args&&... args) noexcept -> decltype(auto) { - return std::bind_back(std::forward(args)...); - using FuncType = decltype(Func); - if constexpr (meta::IsPointer or std::is_member_pointer_v) - static_assert(Func != nullptr); - return - [... bound_args(std::forward(args))]( - this Self&&, - CallArgs&&... call_args) noexcept(std:: - is_nothrow_invocable_v< - FuncType, - CallArgs..., - meta::ForwardLike>...>) - -> decltype(auto) { - return std::invoke(Func, - std::forward(call_args)..., - std::forward_like(bound_args)...); - }; - } -#endif - - ///////////////////////////////////// - ///////////////////////////////////// - template - requires(std::invocable - and meta::Is, void>) - STORMKIT_CONST STORMKIT_FORCE_INLINE - constexpr auto init_by(Func&& func, Args&&... args) noexcept -> T { - auto out = T {}; - std::invoke(std::forward(func), out, std::forward(args)...); - return out; - } -}} // namespace stormkit::core +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +export module stormkit.core:functional.utils; + +import std; + +import :meta; +import :typesafe.ref; + +namespace stormkit { inline namespace core { namespace details { + struct EitherFunc { + [[nodiscard]] + static constexpr auto operator()(bool condition, std::invocable auto&& true_, std::invocable auto&& false_) noexcept + -> decltype(false_()); + + template + using ForwardArg = meta::ForwardLike>>; + + template + [[nodiscard]] + static constexpr auto operator()(T value, + std::invocable&> auto&& true_, + std::invocable auto&& false_) noexcept -> decltype(false_()); + + template + requires(meta::IsConvertibleTo) + [[nodiscard]] + static constexpr auto operator()(T&& value, + std::invocable> auto&& true_, + std::invocable auto&& false_) noexcept -> decltype(false_()); + }; +}}} // namespace stormkit::core::details + +export namespace stormkit { inline namespace core { + inline constexpr auto either = details::EitherFunc {}; + + using std::bind_back; + using std::bind_front; + + template + requires(std::invocable and meta::Is, void>) + [[nodiscard]] + constexpr auto init_by(Func&& func, Args&&... args) noexcept -> T; +}} // namespace stormkit::core + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit { inline namespace core { + namespace details { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto EitherFunc::operator()(bool condition, std::invocable auto&& true_, std::invocable auto&& false_) noexcept + -> decltype(false_()) { + if (condition) return true_(); + return false_(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto EitherFunc::operator()(T value, + std::invocable&> auto&& true_, + std::invocable auto&& false_) noexcept -> decltype(false_()) { + if (static_cast(value)) return true_(unref(value)); + return false_(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(meta::IsConvertibleTo) + STORMKIT_FORCE_INLINE + constexpr auto EitherFunc::operator()(T&& value, + std::invocable> auto&& true_, + std::invocable auto&& false_) noexcept -> decltype(false_()) { + if (static_cast(value)) return true_(std::forward_like(unref(value))); + return false_(); + } + } // namespace details + +#if not(defined(__cpp_lib_bind_back) and __cpp_lib_bind_back >= 202306L) + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto bind_back(Args&&... args) noexcept -> decltype(auto) { + return std::bind_back(std::forward(args)...); + using FuncType = decltype(Func); + if constexpr (meta::IsPointer or std::is_member_pointer_v) static_assert(Func != nullptr); + return + [... bound_args(std::forward(args))]( + this Self&&, + CallArgs&&... call_args) noexcept(std::is_nothrow_invocable_v>...>) + -> decltype(auto) { + return std::invoke(Func, std::forward(call_args)..., std::forward_like(bound_args)...); + }; + } +#endif + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(std::invocable and meta::Is, void>) + STORMKIT_CONST STORMKIT_FORCE_INLINE + constexpr auto init_by(Func&& func, Args&&... args) noexcept -> T { + auto out = T {}; + std::invoke(std::forward(func), out, std::forward(args)...); + return out; + } +}} // namespace stormkit::core diff --git a/modules/stormkit/core/hash.mpp b/modules/stormkit/core/hash.cppm similarity index 96% rename from modules/stormkit/core/hash.mpp rename to modules/stormkit/core/hash.cppm index adb4875cb..665cf3dd3 100644 --- a/modules/stormkit/core/hash.mpp +++ b/modules/stormkit/core/hash.cppm @@ -1,13 +1,13 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -export module stormkit.core:hash; - -export import :hash.base; -export import :hash.map; -export import :hash.string; +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +export module stormkit.core:hash; + +export import :hash.base; +export import :hash.map; +export import :hash.string; diff --git a/modules/stormkit/core/hash/base.cppm b/modules/stormkit/core/hash/base.cppm new file mode 100644 index 000000000..8c6626ec7 --- /dev/null +++ b/modules/stormkit/core/hash/base.cppm @@ -0,0 +1,165 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +export module stormkit.core:hash.base; + +import std; + +import :meta; + +export namespace stormkit { inline namespace core { + using hash32 = std::uint32_t; + using hash64 = std::uint64_t; + + namespace meta { + template + concept HashType = meta::IsAnyOf; + } + + template + constexpr auto hasher(const T& value) noexcept -> Ret = delete; + + namespace meta { + template + concept HasHasher = requires(T&& value) { + { hasher(std::forward(value)) } -> meta::HashType; + }; + } // namespace meta + + template + requires(sizeof...(Args) >= 2) + constexpr auto hash(Args&&... values) noexcept -> Ret; + + template + constexpr auto hash(T&& value) noexcept -> Ret; + + template + requires(sizeof(T) <= sizeof(Ret)) + constexpr auto hasher(T value) noexcept -> Ret; + + template + requires(sizeof(T) <= sizeof(Ret)) + constexpr auto hasher(T value) noexcept -> Ret; + + template + constexpr auto hash_combine(Ret& hash, T&& value) noexcept -> void; + + template + requires(sizeof...(Args) >= 2) + constexpr auto hash_combine(Ret& hash, Args&&... args) noexcept -> void; + + namespace literals { + constexpr auto operator""_hash32(unsigned long long int) -> hash32; + constexpr auto operator""_hash32(long double) -> hash32; + constexpr auto operator""_hash64(unsigned long long int) -> hash64; + constexpr auto operator""_hash64(long double) -> hash64; + } // namespace literals +}} // namespace stormkit::core + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit { inline namespace core { + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(sizeof...(Args) >= 2) + STORMKIT_FORCE_INLINE STORMKIT_PURE + constexpr auto hash(Args&&... values) noexcept -> Ret { + auto out = Ret { 0 }; + stormkit::hash_combine(out, std::forward(values)...); + return out; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE STORMKIT_PURE + constexpr auto hash(T&& value) noexcept -> Ret { + static_assert(meta::HasHasher or meta::HasStdHashSpecialization, "No hasher or std::hash specialization!"); + + if constexpr (meta::HasHasher) return hasher(std::forward(value)); + else { + const auto _hasher = std::hash> {}; + return static_cast(_hasher(std::forward(value))); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(sizeof(T) <= sizeof(Ret)) + STORMKIT_FORCE_INLINE STORMKIT_PURE + constexpr auto hasher(T value) noexcept -> Ret { + return static_cast(value); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(sizeof(T) <= sizeof(Ret)) + STORMKIT_FORCE_INLINE STORMKIT_PURE + constexpr auto hasher(T value) noexcept -> Ret { + return static_cast(value); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto hash_combine(Ret& out, T&& value) noexcept -> void { + if constexpr (std::ranges::range) + for (auto&& elem : value) stormkit::hash_combine(out, elem); + else { out ^= hash(std::forward(value)) + 0x9e3779b9 + (out << 6) + (out >> 2); } + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(sizeof...(Args) >= 2) + STORMKIT_FORCE_INLINE + constexpr auto hash_combine(Ret& out, Args&&... args) noexcept -> void { +#if defined(__cpp_expansion_statements) and __cpp_expansion_statements >= 202500L + template for (constexpr auto elem : { std::forward(args)... }) + stormkit::hash_combine(out, std::forward(elem)); +#else + (stormkit::hash_combine(out, std::forward(args)), ...); +#endif + } + + namespace literals { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto operator""_hash32(unsigned long long int value) -> hash32 { + return hash(value); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto operator""_hash32(long double value) -> hash32 { + return hash(value); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto operator""_hash64(unsigned long long int value) -> hash64 { + return hash(value); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto operator""_hash64(long double value) -> hash64 { + return hash(value); + } + } // namespace literals +}} // namespace stormkit::core diff --git a/modules/stormkit/core/hash/base.mpp b/modules/stormkit/core/hash/base.mpp deleted file mode 100644 index c408a2cbe..000000000 --- a/modules/stormkit/core/hash/base.mpp +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -export module stormkit.core:hash.base; - -import std; - -import :meta; - -export namespace stormkit { inline namespace core { - using hash32 = std::uint32_t; - using hash64 = std::uint64_t; - - template - concept HashValue = meta::IsOneOf; - - template - constexpr auto hash_combine(auto&& value) -> OutputType; - - template - constexpr auto hash_combine(HashValue auto& hash, T&& range) noexcept; - - template - requires(sizeof...(Args) > 1) - constexpr auto hash_combine(HashValue auto& hash, Args&&... args) noexcept; -}} // namespace stormkit::core - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit { inline namespace core { - template - constexpr auto hash_combine(auto&& value) -> OutputType { - auto hash = OutputType { 0u }; - - hash_combine(hash, std::forward(value)); - - return hash; - } - - template - constexpr auto hash_combine(HashValue auto& hash, T&& value) noexcept { - if constexpr (std::ranges::range) - for (auto&& elem : value) hash_combine(hash, elem); - else { - const auto hasher = std::hash> {}; - hash ^= hasher(std::forward(value)) + 0x9e3779b9 + (hash << 6) + (hash >> 2); - } - } - - template - requires(sizeof...(Args) > 1) - constexpr auto hash_combine(HashValue auto& hash, Args&&... args) noexcept { -#if defined(__cpp_expansion_statements) and __cpp_expansion_statements >= 202500L - template for (constexpr auto elem : { std::forward(args)... }) - hash_combine(hash, std::forward(elem)); -#else - (hash_combine(hash, std::forward(args)), ...); -#endif - } -}} // namespace stormkit::core diff --git a/modules/stormkit/core/hash/map.mpp b/modules/stormkit/core/hash/map.cppm similarity index 79% rename from modules/stormkit/core/hash/map.mpp rename to modules/stormkit/core/hash/map.cppm index f610b9737..96895a9ed 100644 --- a/modules/stormkit/core/hash/map.mpp +++ b/modules/stormkit/core/hash/map.cppm @@ -1,24 +1,24 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -export module stormkit.core:hash.map; - -import std; - -import ankerl.unordered_dense; - -export namespace stormkit { inline namespace core { - template, - class KeyEqual = std::equal_to, - class AllocatorOrContainer = std::allocator>> - using HashMap = ankerl::unordered_dense::map; - - template, - class KeyEqual = std::equal_to, - class AllocatorOrContainer = std::allocator> - using HashSet = ankerl::unordered_dense::set; -}} // namespace stormkit::core +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +export module stormkit.core:hash.map; + +import std; + +import ankerl.unordered_dense; + +export namespace stormkit { inline namespace core { + template, + class KeyEqual = std::equal_to, + class AllocatorOrContainer = std::allocator>> + using hash_map = ankerl::unordered_dense::map; + + template, + class KeyEqual = std::equal_to, + class AllocatorOrContainer = std::allocator> + using hash_set = ankerl::unordered_dense::set; +}} // namespace stormkit::core diff --git a/modules/stormkit/core/hash/string.mpp b/modules/stormkit/core/hash/string.cppm similarity index 66% rename from modules/stormkit/core/hash/string.mpp rename to modules/stormkit/core/hash/string.cppm index 1d2ec0254..86799383e 100644 --- a/modules/stormkit/core/hash/string.mpp +++ b/modules/stormkit/core/hash/string.cppm @@ -8,7 +8,9 @@ module; export module stormkit.core:hash.string; -import :string.czstring; +import :hash.base; + +import :string.aliases; import :typesafe.integer; import :typesafe.safecasts; @@ -21,33 +23,31 @@ export namespace stormkit { inline namespace core { using is_transparent = void; using is_avalanching = void; -#ifdef STORMKIT_COMPILER_MSVC - [[nodiscard]] - auto operator()(std::string_view value, u64 seed = 0) const noexcept -> u64; -#else [[nodiscard]] - static auto operator()(std::string_view value, u64 seed = 0) noexcept -> u64; -#endif + static constexpr auto operator()(string_view value, u64 seed = 0) noexcept -> u64; }; - template - using StringHashMap = ankerl::unordered_dense:: + template + using string_hash_map = ankerl::unordered_dense:: map, std::remove_cvref_t, StringHash, std::equal_to<>>; - template - using FrozenStringHashMap = frozen::unordered_map, - std::remove_cvref_t, - Size, - StringHash, - std::equal_to<>>; + template + using Frozenstring_hash_map = frozen:: + unordered_map, std::remove_cvref_t, Size, StringHash, std::equal_to<>>; + + template + using string_hash_set = ankerl::unordered_dense::set, StringHash, std::equal_to<>>; - template - using StringHashSet = ankerl::unordered_dense:: - set, StringHash, std::equal_to<>>; + template + using frozen_string_hash_set = frozen::unordered_set, Size, StringHash, std::equal_to<>>; - template - using FrozenStringHashSet = frozen:: - unordered_set, Size, StringHash, std::equal_to<>>; + template + constexpr auto hasher(string_view value) noexcept -> Ret; + + namespace literals { + constexpr auto operator""_hash32(czstring str, usize size) -> hash32; + constexpr auto operator""_hash64(czstring str, usize size) -> hash64; + } // namespace literals }} // namespace stormkit::core //////////////////////////////////////////////////////////////////// @@ -62,16 +62,13 @@ namespace stormkit { inline namespace core { : m_hash { basis } {} STORMKIT_FORCE_INLINE - constexpr auto bytes(std::span bytes) noexcept -> void { + constexpr auto bytes(array_view bytes) noexcept -> void { bytes_4(bytes); } STORMKIT_FORCE_INLINE - constexpr auto bytes_4(std::span bytes) noexcept -> void { - const auto val = u64(bytes[0]) << 0 - | u64(bytes[1]) << 8 - | u64(bytes[2]) << 16 - | u64(bytes[3]) << 24; + constexpr auto bytes_4(array_view bytes) noexcept -> void { + const auto val = u64(bytes[0]) << 0 | u64(bytes[1]) << 8 | u64(bytes[2]) << 16 | u64(bytes[3]) << 24; dword(val); } @@ -101,10 +98,7 @@ namespace stormkit { inline namespace core { template STORMKIT_FORCE_INLINE - constexpr auto hash_selected_characters(u8 mask, - Hasher& hasher, - CZString s, - usize size) noexcept -> void { + constexpr auto hash_selected_characters(u8 mask, Hasher& hasher, czstring s, usize size) noexcept -> void { if (std::popcount(mask) == 4) { auto dword = u64 { 0 }; auto i = i32 { 0 }; @@ -170,8 +164,8 @@ namespace stormkit { inline namespace core { hasher.dword(dword); } else { - std::array bytes; - auto i = usize { 0 }; + array bytes; + auto i = usize { 0 }; if (mask & (1 << 0)) bytes[i++] = static_cast(s[0]); if (mask & (1 << 1)) bytes[i++] = static_cast(s[1]); @@ -181,22 +175,41 @@ namespace stormkit { inline namespace core { if (mask & (1 << 4)) bytes[i++] = static_cast(size); - hasher.bytes(std::span { std::data(bytes), i }); + hasher.bytes(array_view { std::data(bytes), i }); } } //////////////////////////////////////// //////////////////////////////////////// STORMKIT_FORCE_INLINE -#ifdef STORMKIT_COMPILER_MSVC - inline auto StringHash::operator()(std::string_view value, u64 seed) const noexcept -#else - inline auto StringHash::operator()(std::string_view value, u64 seed) noexcept -#endif - -> u64 { + constexpr auto StringHash::operator()(string_view value, u64 seed) noexcept -> u64 { auto mask = u8 { 0b01111 }; auto hasher = Lehmer128Hasher { seed }; hash_selected_characters(mask, hasher, std::data(value), std::size(value)); return hasher.hash(); } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto hasher(string_view value) noexcept -> Ret { + return StringHash::operator()(value); + } + + namespace literals { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto operator""_hash32(czstring str, usize size) -> hash32 { + return hash(string_view { str, size }); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto operator""_hash64(czstring str, usize size) -> hash64 { + return hash(string_view { str, size }); + } + } // namespace literals }} // namespace stormkit::core diff --git a/modules/stormkit/core/math.mpp b/modules/stormkit/core/math.cppm similarity index 100% rename from modules/stormkit/core/math.mpp rename to modules/stormkit/core/math.cppm diff --git a/modules/stormkit/core/math/arithmetic.mpp b/modules/stormkit/core/math/arithmetic.cppm similarity index 89% rename from modules/stormkit/core/math/arithmetic.mpp rename to modules/stormkit/core/math/arithmetic.cppm index 1d7a1c886..b0abde910 100644 --- a/modules/stormkit/core/math/arithmetic.mpp +++ b/modules/stormkit/core/math/arithmetic.cppm @@ -4,6 +4,7 @@ module; +#include #include export module stormkit.core:math.arithmetic; @@ -85,10 +86,10 @@ namespace stormkit { inline namespace core { namespace math { if constexpr (meta::IsIntegral) return as(std::log2(v)); else { auto val_i = as(v); - auto log_2 = std::bit_cast(((val_i >> 23) & 255) - 128); + auto log_2 = std::bit_cast(((val_i >> 23) & 255) - 128); val_i &= ~(255 << 23); val_i += 127 << 23; - const auto val_f = std::bit_cast(val_i); + const auto val_f = std::bit_cast(val_i); log_2 += ((-0.3358287811f) * val_f + 2.0f) * val_f - 0.65871759316667f; return as(log_2); } @@ -175,18 +176,18 @@ namespace stormkit { inline namespace core { namespace math { } #ifndef STORMKIT_OS_WINDOWS - #undef STORMKIT_API - #define STORMKIT_API + #undef STORMKIT_CORE_API + #define STORMKIT_CORE_API #endif -#define INSTANCIATE(t) \ - template STORMKIT_API auto is_positive(t) noexcept -> bool; \ - template STORMKIT_API auto is_negative(t) noexcept -> bool; \ - template STORMKIT_API auto abs(t) noexcept -> t; \ - template STORMKIT_API auto min(t, t) noexcept -> t; \ - template STORMKIT_API auto max(t, t) noexcept -> t; \ - template STORMKIT_API auto log2(t) noexcept -> t; \ - template STORMKIT_API auto floor(t) noexcept -> t; +#define INSTANCIATE(t) \ + template STORMKIT_CORE_API auto is_positive(t) noexcept -> bool; \ + template STORMKIT_CORE_API auto is_negative(t) noexcept -> bool; \ + template STORMKIT_CORE_API auto abs(t) noexcept -> t; \ + template STORMKIT_CORE_API auto min(t, t) noexcept -> t; \ + template STORMKIT_CORE_API auto max(t, t) noexcept -> t; \ + template STORMKIT_CORE_API auto log2(t) noexcept -> t; \ + template STORMKIT_CORE_API auto floor(t) noexcept -> t; INSTANCIATE(u8); INSTANCIATE(i8); diff --git a/modules/stormkit/core/math/combinatoric.mpp b/modules/stormkit/core/math/combinatoric.cppm similarity index 90% rename from modules/stormkit/core/math/combinatoric.mpp rename to modules/stormkit/core/math/combinatoric.cppm index b567cab6e..d8b2a6915 100644 --- a/modules/stormkit/core/math/combinatoric.mpp +++ b/modules/stormkit/core/math/combinatoric.cppm @@ -24,11 +24,9 @@ export namespace stormkit { inline namespace core { namespace math { //////////////////////////////////////////////////////////////////// namespace stormkit { inline namespace core { namespace math { - namespace { - constexpr auto FTABLE = std::array { - 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800 - }; - } + constexpr auto FTABLE = array { + 1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800 + }; ///////////////////////////////////// ///////////////////////////////////// diff --git a/modules/stormkit/core/math/extent.mpp b/modules/stormkit/core/math/extent.cppm similarity index 52% rename from modules/stormkit/core/math/extent.mpp rename to modules/stormkit/core/math/extent.cppm index 0ed62b9ff..76e02d86c 100644 --- a/modules/stormkit/core/math/extent.mpp +++ b/modules/stormkit/core/math/extent.cppm @@ -23,73 +23,79 @@ namespace stdr = std::ranges; export { namespace stormkit { inline namespace core { namespace math { template - struct Extent; + struct extent; template - struct alignas(std::array) Extent { + struct alignas(array) extent { static constexpr auto RANK = 2uz; - using ElementType = T; + using ValueType = T; using OrderingType = meta::ArithmeticOrderingType; template - constexpr auto narrow_to() const noexcept -> Extent; + constexpr auto narrow_to() const noexcept -> extent; template - constexpr auto to(const std::source_location& = std::source_location::current()) - const noexcept -> Extent; + constexpr auto to(const std::source_location& = std::source_location::current()) const noexcept -> extent; template - constexpr auto to() const noexcept -> Extent; + constexpr auto to() const noexcept -> extent; /// @brief The extent width - ElementType width = 0; + ValueType width = 0; /// @brief The extent height - ElementType height = 0; + ValueType height = 0; }; template - using Extent2 = Extent; + using extent2 = extent; + + using fextent2 = extent2; + using uextent2 = extent2; + using iextent2 = extent2; template - struct alignas(std::array) Extent { + struct alignas(array) extent { static constexpr auto RANK = 3uz; - using ElementType = T; + using ValueType = T; using OrderingType = meta::ArithmeticOrderingType; template - constexpr auto narrow_to() const noexcept -> Extent; + constexpr auto narrow_to() const noexcept -> extent; template - constexpr auto to(const std::source_location& = std::source_location::current()) - const noexcept -> Extent; + constexpr auto to(const std::source_location& = std::source_location::current()) const noexcept -> extent; template - constexpr auto to() const noexcept -> Extent; + constexpr auto to() const noexcept -> extent; /// @brief The extent width - ElementType width = 0; + ValueType width = 0; /// @brief The extent height - ElementType height = 0; + ValueType height = 0; /// @brief The extent depth - ElementType depth = 1; + ValueType depth = 1; }; template - using Extent3 = Extent; + using extent3 = extent; + + using fextent3 = extent3; + using uextent3 = extent3; + using iextent3 = extent3; template - Extent(T, T) -> Extent; + extent(T, T) -> extent; template - Extent(T, T, T) -> Extent; + extent(T, T, T) -> extent; namespace meta { template concept IsExtent = requires(T&&) { - typename T::ElementType; + typename T::ValueType; typename T::OrderingType; { T::RANK } -> core::meta::Is; }; @@ -107,8 +113,7 @@ export { /// @returns true if this extent is equal to `other`, otherwise returns false. template [[nodiscard]] - constexpr auto operator<=>(const Extent& first, const Extent& second) noexcept -> - typename Extent::OrderingType; + constexpr auto operator<=>(const Extent& first, const Extent& second) noexcept -> typename Extent::OrderingType; /// @output_section Publics operators members /// @brief ValueType the equality with an other extent. @@ -119,65 +124,54 @@ export { constexpr auto operator==(const Extent& first, const Extent& second) noexcept -> bool; /// @brief Multiply an extent with a factor. - /// @param factor ElementType factor to multiply + /// @param factor ValueType factor to multiply /// @returns A newly constructed extent equal to this extent multiplied with /// `factor` template [[nodiscard]] - constexpr auto operator*(Extent&& event, typename Extent::ElemenType factor) noexcept + constexpr auto operator*(Extent&& extent, typename Extent::ElemenType factor) noexcept -> core::meta::CanonicalType; /// @brief Divide an extent with a factor. - /// @param factor ElementType factor to divide + /// @param factor ValueType factor to divide /// @returns A newly constructed extent equal to this extent Divided with `factor` template [[nodiscard]] - constexpr auto operator/(Extent&& event, typename Extent::ElemenType factor) noexcept + constexpr auto operator/(Extent&& extent, typename Extent::ElemenType factor) noexcept -> core::meta::CanonicalType; /// @brief Multiply this extent with a factor. - /// @param factor ElementType factor to multiply + /// @param factor ValueType factor to multiply /// @returns A reference to this after the multiplication with `factor` template [[nodiscard]] - constexpr auto operator*=(Extent& extent, typename Extent::ElementType factor) noexcept - -> Extent&; + constexpr auto operator*=(Extent& extent, typename Extent::ValueType factor) noexcept -> Extent&; /// @brief Divide this extent with a factor. - /// @param factor ElementType factor to divide + /// @param factor ValueType factor to divide /// @returns A reference to this after the division with `factor` template [[nodiscard]] - constexpr auto operator/=(Extent& extent, typename Extent::ElementType factor) noexcept - -> Extent&; + constexpr auto operator/=(Extent& extent, typename Extent::ValueType factor) noexcept -> Extent&; template - auto to_string(Extent&& extent) noexcept -> std::string; - }}} // namespace stormkit::core::math + auto to_string(const Extent& extent) noexcept -> string; + + template + auto to_string(const Extent& extent) noexcept -> string; + + template + auto format_as(const extent& extent, FormatContext& ctx) noexcept -> decltype(ctx.out()); + + template + auto format_as(const extent& extent, FormatContext& ctx) noexcept -> decltype(ctx.out()); + + template + constexpr auto hasher(const extent& extent) noexcept -> Ret; - template - struct std::formatter>: std::formatter { - template - auto format(const math::Extent& extent, FormatContext& ctx) const noexcept - -> decltype(ctx.out()); - }; - - template - struct std::formatter>: std::formatter { - template - auto format(const math::Extent& extent, FormatContext& ctx) const noexcept - -> decltype(ctx.out()); - }; - - template - struct std::hash> { - static constexpr auto operator()(const math::Extent& extent) noexcept; - }; - - template - struct std::hash> { - static constexpr auto operator()(const math::Extent& extent) noexcept; - }; + template + constexpr auto hasher(const extent& extent) noexcept -> Ret; + }}} // namespace stormkit::core::math } //////////////////////////////////////////////////////////////////// @@ -190,7 +184,7 @@ namespace stormkit { inline namespace core { namespace math { template template STORMKIT_PURE - constexpr auto Extent::narrow_to() const noexcept -> Extent { + constexpr auto extent::narrow_to() const noexcept -> extent { return { .width = narrow(width), .height = narrow(height) }; } @@ -199,8 +193,7 @@ namespace stormkit { inline namespace core { namespace math { template template STORMKIT_PURE - constexpr auto Extent::to(const std::source_location& location) const noexcept - -> Extent { + constexpr auto extent::to(const std::source_location& location) const noexcept -> extent { return { .width = as(width, location), .height = as(height, location) }; } @@ -209,10 +202,10 @@ namespace stormkit { inline namespace core { namespace math { template template STORMKIT_PURE - constexpr auto Extent::to() const noexcept -> Extent { - using Out = Extent; - using Array = std::array; - using OtherArray = std::array; + constexpr auto extent::to() const noexcept -> extent { + using Out = extent; + using Array = array; + using OtherArray = array; auto out = Out {}; @@ -232,10 +225,8 @@ namespace stormkit { inline namespace core { namespace math { template template STORMKIT_PURE - constexpr auto Extent::narrow_to() const noexcept -> Extent { - return { .width = narrow(width), - .height = narrow(height), - .depth = narrow(depth) }; + constexpr auto extent::narrow_to() const noexcept -> extent { + return { .width = narrow(width), .height = narrow(height), .depth = narrow(depth) }; } ///////////////////////////////////// @@ -243,11 +234,8 @@ namespace stormkit { inline namespace core { namespace math { template template STORMKIT_PURE - constexpr auto Extent::to(const std::source_location& location) const noexcept - -> Extent { - return { .width = as(width, location), - .height = as(height, location), - .depth = as(depth, location) }; + constexpr auto extent::to(const std::source_location& location) const noexcept -> extent { + return { .width = as(width, location), .height = as(height, location), .depth = as(depth, location) }; } ///////////////////////////////////// @@ -255,10 +243,10 @@ namespace stormkit { inline namespace core { namespace math { template template STORMKIT_PURE - constexpr auto Extent::to() const noexcept -> Extent { - using Out = Extent; - using Array = std::array; - using OtherArray = std::array; + constexpr auto extent::to() const noexcept -> extent { + using Out = extent; + using Array = array; + using OtherArray = array; auto out = Out {}; @@ -277,9 +265,8 @@ namespace stormkit { inline namespace core { namespace math { ///////////////////////////////////// template STORMKIT_PURE - constexpr auto operator<=>(const Extent& first, const Extent& second) noexcept -> - typename Extent::OrderingType { - using Array = std::array; + constexpr auto operator<=>(const Extent& first, const Extent& second) noexcept -> typename Extent::OrderingType { + using Array = array; using OrderingType = typename Extent::OrderingType; static constexpr auto RANK = Extent::RANK; @@ -297,7 +284,7 @@ namespace stormkit { inline namespace core { namespace math { template STORMKIT_PURE constexpr auto operator==(const Extent& first, const Extent& second) noexcept -> bool { - using Array = std::array; + using Array = array; static constexpr auto RANK = Extent::RANK; const auto& values = *std::bit_cast(&first); @@ -313,29 +300,26 @@ namespace stormkit { inline namespace core { namespace math { ///////////////////////////////////// template STORMKIT_PURE - constexpr auto operator*(Extent&& event, typename Extent::ElemenType factor) noexcept - -> core::meta::CanonicalType { - return core::meta::CanonicalType { std::forward(event) } *= factor; + constexpr auto operator*(Extent&& extent, typename Extent::ElemenType factor) noexcept -> core::meta::CanonicalType { + return core::meta::CanonicalType { std::forward(extent) } *= factor; } ///////////////////////////////////// ///////////////////////////////////// template STORMKIT_PURE - constexpr auto operator/(Extent&& event, typename Extent::ElemenType factor) noexcept - -> core::meta::CanonicalType { - return core::meta::CanonicalType { std::forward(event) } /= factor; + constexpr auto operator/(Extent&& extent, typename Extent::ElemenType factor) noexcept -> core::meta::CanonicalType { + return core::meta::CanonicalType { std::forward(extent) } /= factor; } ///////////////////////////////////// ///////////////////////////////////// template STORMKIT_PURE - constexpr auto operator*=(Extent& extent, typename Extent::ElementType factor) noexcept - -> Extent& { - using ElementType = typename Extent::ElementType; + constexpr auto operator*=(Extent& extent, typename Extent::ValueType factor) noexcept -> Extent& { + using ValueType = typename Extent::ValueType; static constexpr auto RANK = Extent::RANK; - auto& values = *std::bit_cast>(&extent); + auto& values = *std::bit_cast>(&extent); for (auto&& val : values) val *= factor; return extent; } @@ -344,11 +328,10 @@ namespace stormkit { inline namespace core { namespace math { ///////////////////////////////////// template STORMKIT_PURE - constexpr auto operator/=(Extent& extent, typename Extent::ElementType factor) noexcept - -> Extent& { - using ElementType = typename Extent::ElementType; + constexpr auto operator/=(Extent& extent, typename Extent::ValueType factor) noexcept -> Extent& { + using ValueType = typename Extent::ValueType; static constexpr auto RANK = Extent::RANK; - auto& values = *std::bit_cast>(&extent); + auto& values = *std::bit_cast>(&extent); for (auto&& val : values) val /= factor; return extent; } @@ -356,93 +339,75 @@ namespace stormkit { inline namespace core { namespace math { ///////////////////////////////////// ///////////////////////////////////// template - auto to_string(Extent&& extent) noexcept -> std::string { + STORMKIT_FORCE_INLINE + inline auto to_string(const Extent& extent) noexcept -> string { return std::format("{}", extent); } ///////////////////////////////////// ///////////////////////////////////// template - auto to_string(Extent&& extent) noexcept -> std::string { + STORMKIT_FORCE_INLINE + inline auto to_string(const Extent& extent) noexcept -> string { return std::format("{}", extent); } -}}} // namespace stormkit::core::math -///////////////////////////////////// -///////////////////////////////////// -template -template -auto std::formatter>::format(const math::Extent& extent, - FormatContext& ctx) const noexcept - -> decltype(ctx.out()) { - auto&& out = ctx.out(); - format_to(out, "{{ .width = "); - formatter::format(extent.width, ctx); - format_to(out, ", .height = "); - formatter::format(extent.height, ctx); - return format_to(out, " }}"); -} + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto format_as(const extent& extent, FormatContext& ctx) noexcept -> decltype(ctx.out()) { + return std::format_to(ctx.out(), "[extent2 width: {}, height: {}]", extent.width, extent.height); + } -///////////////////////////////////// -///////////////////////////////////// -template -template -auto std::formatter>::format(const math::Extent& extent, - FormatContext& ctx) const noexcept - -> decltype(ctx.out()) { - auto&& out = ctx.out(); - format_to(out, "{{ .width = "); - formatter::format(extent.width, ctx); - format_to(out, ", .height = "); - formatter::format(extent.height, ctx); - format_to(out, ", .depth = "); - formatter::format(extent.depth, ctx); - return format_to(out, " }}"); -} + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto format_as(const extent& extent, FormatContext& ctx) noexcept -> decltype(ctx.out()) { + return std::format_to(ctx.out(), "[extent3 width: {}, height: {}, depth: {}]", extent.width, extent.height, extent.depth); + } -///////////////////////////////////// -///////////////////////////////////// -template -constexpr auto std::hash>::operator()(const math::Extent& - extent) noexcept { - auto hash = hash64 { 0 }; - hash_combine(hash, extent.width, extent.height); - return hash; -} + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto hasher(const extent& extent) noexcept -> Ret { + return hash(extent.width, extent.height); + } -///////////////////////////////////// -///////////////////////////////////// -template -constexpr auto std::hash>::operator()(const math::Extent& - extent) noexcept { - auto hash = hash64 { 0 }; - hash_combine(hash, extent.width, extent.height, extent.depth); - return hash; -} + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto hasher(const extent& extent) noexcept -> Ret { + return hash(extent.width, extent.height, extent.depth); + } +}}} // namespace stormkit::core::math -static_assert(sizeof(math::Extent2) == sizeof(std::array)); -static_assert(sizeof(math::Extent3) == sizeof(std::array)); +static_assert(sizeof(math::uextent2) == sizeof(array)); +static_assert(sizeof(math::uextent3) == sizeof(array)); -static_assert(sizeof(math::Extent2) == sizeof(std::array)); -static_assert(sizeof(math::Extent3) == sizeof(std::array)); +static_assert(sizeof(math::iextent2) == sizeof(array)); +static_assert(sizeof(math::iextent3) == sizeof(array)); -static_assert(sizeof(math::Extent2) == sizeof(std::array)); -static_assert(sizeof(math::Extent3) == sizeof(std::array)); +static_assert(sizeof(math::extent2) == sizeof(array)); +static_assert(sizeof(math::extent3) == sizeof(array)); -static_assert(sizeof(math::Extent2) == sizeof(std::array)); -static_assert(sizeof(math::Extent3) == sizeof(std::array)); +static_assert(sizeof(math::extent2) == sizeof(array)); +static_assert(sizeof(math::extent3) == sizeof(array)); -static_assert(sizeof(math::Extent2) == sizeof(std::array)); -static_assert(sizeof(math::Extent3) == sizeof(std::array)); +static_assert(sizeof(math::fextent2) == sizeof(array)); +static_assert(sizeof(math::fextent3) == sizeof(array)); -static_assert(math::Extent2::RANK == 2); -static_assert(math::Extent3::RANK == 3); -static_assert(math::Extent3::RANK != 2); -static_assert(math::Extent2::RANK != 3); +static_assert(math::fextent2::RANK == 2); +static_assert(math::fextent3::RANK == 3); +static_assert(math::fextent3::RANK != 2); +static_assert(math::fextent2::RANK != 3); -static_assert(math::meta::IsExtent>); -static_assert(math::meta::IsExtent>); -static_assert(math::meta::IsExtent2>); -static_assert(not math::meta::IsExtent2>); -static_assert(math::meta::IsExtent3>); -static_assert(not math::meta::IsExtent3>); +static_assert(math::meta::IsExtent); +static_assert(math::meta::IsExtent); +static_assert(math::meta::IsExtent2); +static_assert(not math::meta::IsExtent2); +static_assert(math::meta::IsExtent3); +static_assert(not math::meta::IsExtent3); diff --git a/modules/stormkit/core/math/geometry.mpp b/modules/stormkit/core/math/geometry.cppm similarity index 55% rename from modules/stormkit/core/math/geometry.mpp rename to modules/stormkit/core/math/geometry.cppm index 1dec7c854..244600a4f 100644 --- a/modules/stormkit/core/math/geometry.mpp +++ b/modules/stormkit/core/math/geometry.cppm @@ -20,51 +20,72 @@ import :math.linear.vector; export namespace stormkit { inline namespace core { namespace math { template struct rect { - T x; - T y; - Positive width; - Positive height; + using ValueType = T; + using value_type = T; - constexpr auto position() const noexcept -> vec2; - constexpr auto extent() const noexcept -> Extent2; + ValueType x = ValueType { 0 }; + ValueType y = ValueType { 0 }; + Positive width = ValueType { 0 }; + Positive height = ValueType { 0 }; + + constexpr auto position() const noexcept -> vec2; + constexpr auto extent() const noexcept -> extent2; template constexpr auto to() const noexcept -> rect; }; - using recti = rect; - using rectu = rect; - using rectf = rect; + using irect = rect; + using urect = rect; + using frect = rect; template rect(T, T, T, T) -> rect; - template - constexpr auto format_as(const rect& point, FormatContext& ctx) -> decltype(ctx.out()); - template struct bounding_rect { - T left; - T top; - T right; - T bottom; + using ValueType = T; + using value_type = T; - constexpr auto topleft() const noexcept -> vec2; - constexpr auto bottomright() const noexcept -> vec2; + ValueType left = ValueType { 0 }; + ValueType top = ValueType { 0 }; + ValueType right = ValueType { 0 }; + ValueType bottom = ValueType { 0 }; + + constexpr auto topleft() const noexcept -> vec2; + constexpr auto bottomright() const noexcept -> vec2; template constexpr auto to() const noexcept -> rect; }; - template - constexpr auto format_as(const bounding_rect& point, FormatContext& ctx) - -> decltype(ctx.out()); + using ibounding_rect = bounding_rect; + using ubounding_rect = bounding_rect; + using fbounding_rect = bounding_rect; + + template + auto to_string(const rect& value) noexcept -> string; + + template + auto to_string(const bounding_rect& value) noexcept -> string; + + template + constexpr auto hasher(const rect& value) noexcept -> Ret; + + template + constexpr auto hasher(const bounding_rect& value) noexcept -> Ret; + + template + auto format_as(const rect& value, FormatContext& ctx) -> decltype(ctx.out()); + + template + auto format_as(const bounding_rect& value, FormatContext& ctx) -> decltype(ctx.out()); template - constexpr auto to_bounding_rect(const rect& _rect) noexcept -> bounding_rect; + constexpr auto to_bounding_rect(const rect& value) noexcept -> bounding_rect; template - constexpr auto to_rect(const bounding_rect& _rect) noexcept -> rect; + constexpr auto to_rect(const bounding_rect& value) noexcept -> rect; template constexpr auto AABB(const rect& rect1, const rect& rect2) noexcept -> bool; @@ -89,8 +110,8 @@ namespace stormkit { inline namespace core { namespace math { //////////////////////////////////////// template STORMKIT_FORCE_INLINE STORMKIT_PURE - constexpr auto rect::extent() const noexcept -> Extent2 { - return { width, height }; + constexpr auto rect::extent() const noexcept -> extent2 { + return { width.value, height.value }; } //////////////////////////////////////// @@ -103,19 +124,6 @@ namespace stormkit { inline namespace core { namespace math { return { as(x), as(y), as(width), as(height) }; } - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr auto format_as(const rect& point, FormatContext& ctx) -> decltype(ctx.out()) { - return std::format_to(ctx.out(), - "{{ rect: .x = {}, .y = {}, .width = {}, .height = {} }}", - point.x, - point.y, - point.width, - point.height); - } - //////////////////////////////////////// //////////////////////////////////////// template @@ -144,17 +152,60 @@ namespace stormkit { inline namespace core { namespace math { //////////////////////////////////////// //////////////////////////////////////// - template + template + STORMKIT_FORCE_INLINE + inline auto to_string(const rect& value) noexcept -> string { + return std::format("{}", value); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto to_string(const bounding_rect& value) noexcept -> string { + return std::format("{}", value); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto hasher(const rect& value) noexcept -> Ret { + return hash(value.x, value.y, value.width, value.height); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template STORMKIT_FORCE_INLINE - constexpr auto format_as(const bounding_rect& point, FormatContext& ctx) - -> decltype(ctx.out()) { - return std:: - format_to(ctx.out(), - "{{ bounding_rect: .left = {}, .top = {}, .right = {}, .bottom = {} }}", - point.left, - point.top, - point.right, - point.bottom); + constexpr auto hasher(const bounding_rect& value) noexcept -> Ret { + return hash(value.left, value.top, value.right, value.bottom); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto format_as(const rect& point, FormatContext& ctx) -> decltype(ctx.out()) { + return std::format_to(ctx.out(), + "[rect x = {}, y = {}, width = {}, height = {}]", + point.x, + point.y, + point.width, + point.height); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto format_as(const bounding_rect& point, FormatContext& ctx) -> decltype(ctx.out()) { + return std::format_to(ctx.out(), + "[bounding_rect left = {}, top = {}, right = {}, bottom = {}]", + point.left, + point.top, + point.right, + point.bottom); } //////////////////////////////////////// @@ -177,12 +228,8 @@ namespace stormkit { inline namespace core { namespace math { //////////////////////////////////////// template STORMKIT_FORCE_INLINE STORMKIT_PURE - constexpr auto AABB(const bounding_rect& rect1, const bounding_rect& rect2) noexcept - -> bool { - return rect1.left < rect2.right - and rect1.right > rect2.left - and rect1.top < rect2.bottom - and rect1.bottom > rect2.top; + constexpr auto AABB(const bounding_rect& rect1, const bounding_rect& rect2) noexcept -> bool { + return rect1.left < rect2.right and rect1.right > rect2.left and rect1.top < rect2.bottom and rect1.bottom > rect2.top; } //////////////////////////////////////// @@ -198,10 +245,7 @@ namespace stormkit { inline namespace core { namespace math { template STORMKIT_FORCE_INLINE STORMKIT_PURE constexpr auto AABB(const vec2& pos, const bounding_rect& rect) noexcept -> bool { - return pos.x >= rect.left - and pos.x <= rect.right - and pos.y >= rect.top - and pos.y <= rect.bottom; + return pos.x >= rect.left and pos.x <= rect.right and pos.y >= rect.top and pos.y <= rect.bottom; } //////////////////////////////////////// diff --git a/modules/stormkit/core/math/hypercomplex.mpp b/modules/stormkit/core/math/hypercomplex.cppm similarity index 100% rename from modules/stormkit/core/math/hypercomplex.mpp rename to modules/stormkit/core/math/hypercomplex.cppm diff --git a/modules/stormkit/core/math/linear-matrix.cppm b/modules/stormkit/core/math/linear-matrix.cppm new file mode 100644 index 000000000..5870d3387 --- /dev/null +++ b/modules/stormkit/core/math/linear-matrix.cppm @@ -0,0 +1,918 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include + +export module stormkit.core:math.linear.matrix; + +import std; + +import :meta; + +import :typesafe.integer; +import :typesafe.floating_point; + +import :math.linear; +import :math.linear.vector; + +import :hash.base; + +import :string.format; + +import :utils.numeric_range; + +export { + namespace stormkit { inline namespace core { namespace math { + inline namespace matrix { + // M => rows + // N => columns + template + struct alignas(array) mat { + using ValueType = T; + using StorageType = array; + using SizeType = usize; + using ExtentType = u8; + + using value_type = ValueType; + using storage_type = StorageType; + using size_type = SizeType; + using extent_type = ExtentType; + + static constexpr auto EXTENTS = array { M, N }; + + StorageType values; + + template + [[nodiscard]] + constexpr auto operator[](this Self&& self, SizeType i) noexcept -> core::meta::ForwardLike&; + + template + [[nodiscard]] + constexpr auto operator[](this Self&& self, SizeType i, SizeType j) noexcept + -> core::meta::ForwardLike&; + + template + [[nodiscard]] + constexpr auto begin(this Self& self) noexcept -> decltype(auto); + [[nodiscard]] + constexpr auto cbegin() const noexcept -> decltype(auto); + + template + [[nodiscard]] + constexpr auto end(this Self& self) noexcept -> decltype(auto); + [[nodiscard]] + constexpr auto cend() const noexcept -> decltype(auto); + + template + [[nodiscard]] + constexpr auto data(this Self& self) noexcept -> core::meta::ForwardConst*; + + [[nodiscard]] + constexpr auto size() const noexcept -> SizeType; + [[nodiscard]] + static consteval auto max_size() noexcept -> SizeType; + + [[nodiscard]] + static constexpr auto identity() noexcept -> mat + requires(M == N); + }; + + template + using mat2x2 = mat; + template + using mat3x3 = mat; + template + using mat4x4 = mat; + template + using mat2x3 = mat; + template + using mat3x2 = mat; + template + using mat4x3 = mat; + template + using mat3x4 = mat; + template + using mat4x2 = mat; + template + using mat2x4 = mat; + + using fmat2 = mat2x2; + using imat2 = mat2x2; + using umat2 = mat2x2; + + using fmat3 = mat3x3; + using imat3 = mat3x3; + using umat3 = mat3x3; + + using fmat4 = mat4x4; + using imat4 = mat4x4; + using umat4 = mat4x4; + + using fmat2x3 = mat2x3; + using imat2x3 = mat2x3; + using umat2x3 = mat2x3; + + using fmat3x2 = mat3x2; + using imat3x2 = mat3x2; + using umat3x2 = mat3x2; + + using fmat4x3 = mat4x3; + using imat4x3 = mat4x3; + using umat4x3 = mat4x3; + + using fmat3x4 = mat3x4; + using imat3x4 = mat3x4; + using umat3x4 = mat3x4; + + using fmat4x2 = mat4x2; + using imat4x2 = mat4x2; + using umat4x2 = mat4x2; + + using fmat2x4 = mat2x4; + using imat2x4 = mat2x4; + using umat2x4 = mat2x4; + } // namespace matrix + + namespace meta { + template + concept IsMat2 = core::meta::IsSpecializationOf; + + template + concept IsMat3 = core::meta::IsSpecializationOf; + + template + concept IsMat4 = core::meta::IsSpecializationOf; + + template + concept IsMat = core::meta::IsSpecializationWithNTTPOf; + + template + concept IsSquareMat = IsMat and T::EXTENTS[0] == T::EXTENTS[1]; + + template + concept HasOneMatType = not(core::meta::IsStdMdspan and core::meta::IsStdMdspan) + or meta::IsMat + or meta::IsMat; + } // namespace meta + + inline namespace matrix { + template + [[nodiscard]] + constexpr auto determinant(const T& mat) noexcept -> typename T::ValueType; + + template + constexpr auto transpose(const T& mat) noexcept -> T; + + template + [[nodiscard]] + constexpr auto is_inversible(const T& mat) noexcept -> bool; + + template + constexpr auto inverse(const T& mat) noexcept -> T; + + template + [[nodiscard]] + constexpr auto is_orthogonal(const T& mat) noexcept -> bool; + + template + [[nodiscard]] + constexpr auto mul(const T& a, typename T::ValueType b) noexcept -> T; + + template + [[nodiscard]] + constexpr auto div(const T& a, typename T::ValueType b) noexcept -> T; + + template + [[nodiscard]] + constexpr auto mul(const T& a, const T& b) noexcept -> T; + + template + requires(core::meta::SameAs) + [[nodiscard]] + constexpr auto div(const T& a, const U& b) noexcept -> U; + + template + [[nodiscard]] + constexpr auto translate(const mat4x4& mat, const vec3& translation) noexcept -> mat4x4; + + template + [[nodiscard]] + constexpr auto scale(const mat4x4& mat, const vec3& scale) noexcept -> mat4x4; + + template + [[nodiscard]] + constexpr auto rotate(const mat4x4& mat, angle::radian angle, const vec3& axis) noexcept -> mat4x4; + + template + [[nodiscard]] + constexpr auto orthographique(T left, T right, T bottom, T top, T near, T far) noexcept -> mat4x4; + + template + [[nodiscard]] + constexpr auto orthographique(T left, T right, T bottom, T top) noexcept -> mat4x4; + + template + [[nodiscard]] + constexpr auto perspective(angle::radian fov_y, T aspect, T near, T far) noexcept -> mat4x4; + + template + [[nodiscard]] + constexpr auto look_at(const vec3& eye, const vec3& center, const vec3& up) noexcept -> mat4x4; + + template + [[nodiscard]] + constexpr auto as_view(const T& value) noexcept + -> array_view; + + template + [[nodiscard]] + constexpr auto as_view_mut(T& value) noexcept -> array_view; + + template + [[nodiscard]] + constexpr auto as_mdspan(const T& value) noexcept + -> MatrixSpan; + + template + requires(not core::meta::IsConst) + [[nodiscard]] + constexpr auto as_mdspan(T& value) noexcept -> MatrixSpan; + + template + auto to_string(const T& value) noexcept -> string; + + template + constexpr auto hasher(const T& value) noexcept -> Ret; + + template + auto format_as(const T& value, FormatContext& ctx) noexcept -> decltype(ctx.out()); + } // namespace matrix + }}} // namespace stormkit::core::math + + namespace std { + template + constexpr range_format format_kind = range_format::disabled; + } // namespace std +} + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stdr = std::ranges; +namespace stdv = std::views; + +namespace stormkit { inline namespace core { namespace math { inline namespace matrix { + static_assert(sizeof(mat2x2) == sizeof(i32) * 2 * 2); + static_assert(sizeof(mat2x2) == sizeof(i64) * 2 * 2); + static_assert(sizeof(mat2x2) == sizeof(u32) * 2 * 2); + static_assert(sizeof(mat2x2) == sizeof(u64) * 2 * 2); + static_assert(sizeof(mat2x2) == sizeof(f32) * 2 * 2); + static_assert(sizeof(mat2x2) == sizeof(f64) * 2 * 2); + + static_assert(sizeof(mat3x3) == sizeof(i32) * 3 * 3); + static_assert(sizeof(mat3x3) == sizeof(i64) * 3 * 3); + static_assert(sizeof(mat3x3) == sizeof(u32) * 3 * 3); + static_assert(sizeof(mat3x3) == sizeof(u64) * 3 * 3); + static_assert(sizeof(mat3x3) == sizeof(f32) * 3 * 3); + static_assert(sizeof(mat3x3) == sizeof(f64) * 3 * 3); + + static_assert(sizeof(mat4x4) == sizeof(i32) * 4 * 4); + static_assert(sizeof(mat4x4) == sizeof(i64) * 4 * 4); + static_assert(sizeof(mat4x4) == sizeof(u32) * 4 * 4); + static_assert(sizeof(mat4x4) == sizeof(u64) * 4 * 4); + static_assert(sizeof(mat4x4) == sizeof(f32) * 4 * 4); + static_assert(sizeof(mat4x4) == sizeof(f64) * 4 * 4); + + //////////////////////////////////////// + //////////////////////////////////////// + template + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto mat::operator[](this Self&& self, SizeType i) noexcept -> core::meta::ForwardLike& { + return std::forward_like(self.values[i]); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto mat::operator[](this Self&& self, SizeType i, SizeType j) noexcept + -> core::meta::ForwardLike& { + return std::forward_like(self.operator[](((i * EXTENTS[0]) + j))); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto mat::begin(this Self& self) noexcept -> decltype(auto) { + return stdr::begin(self.values); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto mat::cbegin() const noexcept -> decltype(auto) { + return stdr::cbegin(values); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto mat::end(this Self& self) noexcept -> decltype(auto) { + return stdr::end(self.values); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto mat::cend() const noexcept -> decltype(auto) { + return stdr::cend(values); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto mat::data(this Self& self) noexcept -> core::meta::ForwardConst* { + return stdr::data(self.values); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto mat::size() const noexcept -> SizeType { + return stdr::size(values); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + consteval auto mat::max_size() noexcept -> SizeType { + return M * N; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto mat::identity() noexcept -> mat + requires(M == N) + { + auto matrix = mat {}; + + for (auto i = 0u; i < M; ++i) { matrix[i, i] = T { 1 }; } + + return matrix; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto determinant(const T& mat) noexcept -> typename T::ValueType { + return math::determinant(as_mdspan(mat)); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto transpose(const T& mat) noexcept -> T { + auto out = T {}; + math::transpose(as_mdspan(mat), as_mdspan_mut(out)); + return out; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto is_inversible(const T& mat) noexcept -> bool { + return math::is_inversible(as_mdspan(mat)); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto inverse(const T& mat) noexcept -> T { + auto out = T {}; + math::inverse(as_mdspan(mat), as_mdspan_mut(out)); + return out; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto is_orthogonal(const T& mat) noexcept -> bool { + return math::is_orthogonal(as_mdspan(mat)); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto mul(const T& a, typename T::ValueType b) noexcept -> T { + auto out = T {}; + + math::mul(as_mdspan(a), b, as_mdspan_mut(out)); + + return out; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto div(const T& a, typename T::ValueType b) noexcept -> T { + auto out = T {}; + + math::div(as_mdspan(a), b, as_mdspan_mut(out)); + + return out; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto mul(const T& a, const T& b) noexcept -> T { + auto out = T {}; + + math::mul(as_mdspan(a), as_mdspan(b), as_mdspan_mut(out)); + + return out; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + requires(core::meta::SameAs) + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto div(const T& a, const U& b) noexcept -> U { + auto out = T {}; + + math::div(as_mdspan(a), as_mdspan(b), as_mdspan_mut(out)); + + return out; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto translate(const mat4x4& mat, const vec3& translation) noexcept -> mat4x4 { + auto out = auto(mat); + + math::translate(as_mdspan(mat), as_mdspan(translation), as_mdspan_mut(out)); + + return out; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto scale(const mat4x4& mat, const vec3& scale_factors) noexcept -> mat4x4 { + auto out = auto(mat); + + math::scale(as_mdspan(mat), as_mdspan(scale_factors), as_mdspan_mut(out)); + + return out; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto rotate(const mat4x4& mat, angle::radian angle, const vec3& axis) noexcept -> mat4x4 { + auto out = auto(mat); + + const auto cos = narrow(std::cos(angle.get())); + const auto sin = narrow(std::sin(angle.get())); + + const auto axis_norm = normalize(axis); + const auto temp = mul(axis_norm, T { 1 } - cos); + + auto rotation_matrix = mat4x4 {}; + rotation_matrix[0, 0] = cos + temp[0] * axis_norm[0]; + rotation_matrix[1, 0] = temp[0] * axis_norm[1] + sin * axis_norm[2]; + rotation_matrix[2, 0] = temp[0] * axis_norm[2] - sin * axis_norm[1]; + + rotation_matrix[0, 1] = temp[1] * axis_norm[0] - sin * axis_norm[2]; + rotation_matrix[1, 1] = cos + temp[1] * axis_norm[1]; + rotation_matrix[2, 1] = temp[1] * axis_norm[2] + sin * axis_norm[0]; + + rotation_matrix[0, 2] = temp[2] * axis_norm[0] + sin * axis_norm[1]; + rotation_matrix[1, 2] = temp[2] * axis_norm[1] - sin * axis_norm[0]; + rotation_matrix[2, 2] = cos + temp[2] * axis_norm[2]; + + out[0, 0] = mat[0, 0] * rotation_matrix[0, 0] + mat[1, 0] * rotation_matrix[1, 0] + mat[2, 0] * rotation_matrix[2, 0]; + out[0, 1] = mat[0, 1] * rotation_matrix[0, 0] + mat[1, 1] * rotation_matrix[1, 0] + mat[2, 1] * rotation_matrix[2, 0]; + out[0, 2] = mat[0, 2] * rotation_matrix[0, 0] + mat[1, 2] * rotation_matrix[1, 0] + mat[2, 2] * rotation_matrix[2, 0]; + + out[1, 0] = mat[0, 0] * rotation_matrix[0, 1] + mat[1, 0] * rotation_matrix[1, 1] + mat[2, 0] * rotation_matrix[2, 1]; + out[1, 1] = mat[0, 1] * rotation_matrix[0, 1] + mat[1, 1] * rotation_matrix[1, 1] + mat[2, 1] * rotation_matrix[2, 1]; + out[1, 2] = mat[0, 2] * rotation_matrix[0, 1] + mat[1, 2] * rotation_matrix[1, 1] + mat[2, 2] * rotation_matrix[2, 1]; + + out[2, 0] = mat[0, 0] * rotation_matrix[0, 2] + mat[1, 0] * rotation_matrix[1, 2] + mat[2, 0] * rotation_matrix[2, 2]; + out[2, 1] = mat[0, 1] * rotation_matrix[0, 2] + mat[1, 1] * rotation_matrix[1, 2] + mat[2, 1] * rotation_matrix[2, 2]; + out[2, 2] = mat[0, 2] * rotation_matrix[0, 2] + mat[1, 2] * rotation_matrix[1, 2] + mat[2, 2] * rotation_matrix[2, 2]; + + return out; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto orthographique(T left, T right, T bottom, T top, T near, T far) noexcept -> mat4x4 { + auto out = mat4x4::identity(); + + math::orthographique(left, right, top, bottom, near, far, as_mdspan_mut(out)); + + return out; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto orthographique(T left, T right, T bottom, T top) noexcept -> mat4x4 { + auto out = mat4x4::identity(); + + math::orthographique(left, right, bottom, top, as_mdspan_mut(out)); + + return out; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto perspective(angle::radian fov_y, T aspect, T near, T far) noexcept -> mat4x4 { + auto out = mat4x4 {}; + + math::perspective(fov_y, aspect, near, far, as_mdspan_mut(out)); + + return out; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto look_at(const vec3& eye, const vec3& center, const vec3& up) noexcept -> mat4x4 { + auto out = mat4x4 {}; + + math::look_at(as_mdspan(eye), as_mdspan(center), as_mdspan(up), as_mdspan_mut(out)); + + return out; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto as_view(const T& value) noexcept -> array_view { + return array_view { + stdr::data(value), + T::EXTENTS[0] * T::EXTENTS[1] + }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto as_view_mut(T& value) noexcept -> array_view { + return array_view { + stdr::data(value), + T::EXTENTS[0] * T::EXTENTS[1] + }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto as_mdspan(const T& value) noexcept -> MatrixSpan { + return MatrixSpan { stdr::data(value), T::EXTENTS }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + requires(not core::meta::IsConst) + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto as_mdspan_mut(T& value) noexcept -> MatrixSpan { + return MatrixSpan { stdr::data(value), T::EXTENTS }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + inline auto to_string(const T& value) noexcept -> string { + return std::format("{}", value); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto hasher(const T& value) noexcept -> Ret { + return hash(as_view(value)); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + inline auto format_as(const T& mat, FormatContext& ctx) noexcept -> decltype(ctx.out()) { + auto out = ctx.out(); + + auto max_digit = 0u; + if constexpr (stormkit::meta::IsSigned) + for (auto v : as_view(mat)) { + max_digit = std::max(max_digit, narrow(v) == 0 ? 2 : narrow(std::log10(v) + 2)); + if (v < 0) max_digit = max_digit + 1; + } + else + for (auto v : as_view(mat)) max_digit = std::max(max_digit, narrow(v) == 0 ? 2 : narrow(std::log10(v) + 2)); + + format_to(out, "[mat "); + + for (auto i : range(T::EXTENTS[0] * T::EXTENTS[1])) { + const auto row = i / T::EXTENTS[1]; + const auto col = i % T::EXTENTS[1]; + + if (row != 0 && col == 0) format_to(out, " "); + + if constexpr (stormkit::meta::IsIntegral) { + if (col < T::EXTENTS[1] - 1) format_to(out, "{:>{}}, ", mat[i], max_digit); + else { + if (row < T::EXTENTS[0] - 1) format_to(out, "{:>{}}\n", mat[i], max_digit); + else + format_to(out, "{:>{}}]", mat[i], max_digit); + } + } else { + if (col < T::EXTENTS[1] - 1) format_to(out, "{:>{}.5f}, ", mat[i], max_digit); + else { + if (row < T::EXTENTS[0] - 1) format_to(out, "{:>{}.5f}\n", mat[i], max_digit); + else + format_to(out, "{:>{}.5f}]", mat[i], max_digit); + } + } + } + + return out; + } + +#ifndef STORMKIT_OS_WINDOWS + #undef STORMKIT_CORE_API + #define STORMKIT_CORE_API +#endif + +#define DETERMINANT_INSTANCIATE(mat_type) \ + template STORMKIT_CORE_API auto determinant(const mat_type&) noexcept -> typename mat_type::ValueType + + DETERMINANT_INSTANCIATE(fmat2); + DETERMINANT_INSTANCIATE(fmat3); + DETERMINANT_INSTANCIATE(fmat4); + DETERMINANT_INSTANCIATE(umat2); + DETERMINANT_INSTANCIATE(umat3); + DETERMINANT_INSTANCIATE(umat4); + DETERMINANT_INSTANCIATE(imat2); + DETERMINANT_INSTANCIATE(imat3); + DETERMINANT_INSTANCIATE(imat4); + +#undef DETERMINANT_INSTANCIATE + +#define TRANSPOSE_INSTANCIATE(mat_type) template STORMKIT_CORE_API auto transpose(const mat_type&) noexcept -> mat_type + + TRANSPOSE_INSTANCIATE(fmat2); + TRANSPOSE_INSTANCIATE(fmat3); + TRANSPOSE_INSTANCIATE(fmat4); + TRANSPOSE_INSTANCIATE(umat2); + TRANSPOSE_INSTANCIATE(umat3); + TRANSPOSE_INSTANCIATE(umat4); + TRANSPOSE_INSTANCIATE(imat2); + TRANSPOSE_INSTANCIATE(imat3); + TRANSPOSE_INSTANCIATE(imat4); + +#undef TRANSPOSE_INSTANCIATE + +#define IS_INVERSIBLE_INSTANCIATE(mat_type) \ + template STORMKIT_CORE_API auto is_inversible(const mat_type&) noexcept -> bool + + IS_INVERSIBLE_INSTANCIATE(fmat2); + IS_INVERSIBLE_INSTANCIATE(fmat2x3); + IS_INVERSIBLE_INSTANCIATE(fmat2x4); + IS_INVERSIBLE_INSTANCIATE(fmat3); + IS_INVERSIBLE_INSTANCIATE(fmat3x2); + IS_INVERSIBLE_INSTANCIATE(fmat3x4); + IS_INVERSIBLE_INSTANCIATE(fmat4); + IS_INVERSIBLE_INSTANCIATE(fmat4x2); + IS_INVERSIBLE_INSTANCIATE(fmat4x3); + IS_INVERSIBLE_INSTANCIATE(umat2); + IS_INVERSIBLE_INSTANCIATE(umat2x3); + IS_INVERSIBLE_INSTANCIATE(umat2x4); + IS_INVERSIBLE_INSTANCIATE(umat3); + IS_INVERSIBLE_INSTANCIATE(umat3x2); + IS_INVERSIBLE_INSTANCIATE(umat3x4); + IS_INVERSIBLE_INSTANCIATE(umat4); + IS_INVERSIBLE_INSTANCIATE(umat4x2); + IS_INVERSIBLE_INSTANCIATE(umat4x3); + IS_INVERSIBLE_INSTANCIATE(imat2); + IS_INVERSIBLE_INSTANCIATE(imat2x3); + IS_INVERSIBLE_INSTANCIATE(imat2x4); + IS_INVERSIBLE_INSTANCIATE(imat3); + IS_INVERSIBLE_INSTANCIATE(imat3x2); + IS_INVERSIBLE_INSTANCIATE(imat3x4); + IS_INVERSIBLE_INSTANCIATE(imat4); + IS_INVERSIBLE_INSTANCIATE(imat4x2); + IS_INVERSIBLE_INSTANCIATE(imat4x3); + +#undef IS_INVERSIBLE_INSTANCIATE + +#define INVERSE_INSTANCIATE(mat_type) template STORMKIT_CORE_API auto inverse(const mat_type&) noexcept -> mat_type + + INVERSE_INSTANCIATE(fmat2); + INVERSE_INSTANCIATE(fmat3); + INVERSE_INSTANCIATE(fmat4); + INVERSE_INSTANCIATE(umat2); + INVERSE_INSTANCIATE(umat3); + INVERSE_INSTANCIATE(umat4); + INVERSE_INSTANCIATE(imat2); + INVERSE_INSTANCIATE(imat3); + INVERSE_INSTANCIATE(imat4); + +#undef INVERSE_INSTANCIATE + +#define IS_ORTHOGONAL_INSTANCIATE(mat_type) \ + template STORMKIT_CORE_API auto is_orthogonal(const mat_type&) noexcept -> bool + + IS_ORTHOGONAL_INSTANCIATE(fmat2); + IS_ORTHOGONAL_INSTANCIATE(fmat2x3); + IS_ORTHOGONAL_INSTANCIATE(fmat2x4); + IS_ORTHOGONAL_INSTANCIATE(fmat3); + IS_ORTHOGONAL_INSTANCIATE(fmat3x2); + IS_ORTHOGONAL_INSTANCIATE(fmat3x4); + IS_ORTHOGONAL_INSTANCIATE(fmat4); + IS_ORTHOGONAL_INSTANCIATE(fmat4x2); + IS_ORTHOGONAL_INSTANCIATE(fmat4x3); + IS_ORTHOGONAL_INSTANCIATE(umat2); + IS_ORTHOGONAL_INSTANCIATE(umat2x3); + IS_ORTHOGONAL_INSTANCIATE(umat2x4); + IS_ORTHOGONAL_INSTANCIATE(umat3); + IS_ORTHOGONAL_INSTANCIATE(umat3x2); + IS_ORTHOGONAL_INSTANCIATE(umat3x4); + IS_ORTHOGONAL_INSTANCIATE(umat4); + IS_ORTHOGONAL_INSTANCIATE(umat4x2); + IS_ORTHOGONAL_INSTANCIATE(umat4x3); + IS_ORTHOGONAL_INSTANCIATE(imat2); + IS_ORTHOGONAL_INSTANCIATE(imat2x3); + IS_ORTHOGONAL_INSTANCIATE(imat2x4); + IS_ORTHOGONAL_INSTANCIATE(imat3); + IS_ORTHOGONAL_INSTANCIATE(imat3x2); + IS_ORTHOGONAL_INSTANCIATE(imat3x4); + IS_ORTHOGONAL_INSTANCIATE(imat4); + IS_ORTHOGONAL_INSTANCIATE(imat4x2); + IS_ORTHOGONAL_INSTANCIATE(imat4x3); + +#undef IS_ORTHOGONAL_INSTANCIATE + +#define MUL_INSTANCIATE(mat_type) \ + template STORMKIT_CORE_API auto mul(const mat_type&, typename mat_type::ValueType) noexcept -> mat_type + + MUL_INSTANCIATE(fmat2); + MUL_INSTANCIATE(fmat2x3); + MUL_INSTANCIATE(fmat2x4); + MUL_INSTANCIATE(fmat3); + MUL_INSTANCIATE(fmat3x2); + MUL_INSTANCIATE(fmat3x4); + MUL_INSTANCIATE(fmat4); + MUL_INSTANCIATE(fmat4x2); + MUL_INSTANCIATE(fmat4x3); + MUL_INSTANCIATE(umat2); + MUL_INSTANCIATE(umat2x3); + MUL_INSTANCIATE(umat2x4); + MUL_INSTANCIATE(umat3); + MUL_INSTANCIATE(umat3x2); + MUL_INSTANCIATE(umat3x4); + MUL_INSTANCIATE(umat4); + MUL_INSTANCIATE(umat4x2); + MUL_INSTANCIATE(umat4x3); + MUL_INSTANCIATE(imat2); + MUL_INSTANCIATE(imat2x3); + MUL_INSTANCIATE(imat2x4); + MUL_INSTANCIATE(imat3); + MUL_INSTANCIATE(imat3x2); + MUL_INSTANCIATE(imat3x4); + MUL_INSTANCIATE(imat4); + MUL_INSTANCIATE(imat4x2); + MUL_INSTANCIATE(imat4x3); + +#undef MUL_INSTANCIATE + +#define DIV_INSTANCIATE(mat_type) \ + template STORMKIT_CORE_API auto div(const mat_type&, typename mat_type::ValueType) noexcept -> mat_type + + DIV_INSTANCIATE(fmat2); + DIV_INSTANCIATE(fmat2x3); + DIV_INSTANCIATE(fmat2x4); + DIV_INSTANCIATE(fmat3); + DIV_INSTANCIATE(fmat3x2); + DIV_INSTANCIATE(fmat3x4); + DIV_INSTANCIATE(fmat4); + DIV_INSTANCIATE(fmat4x2); + DIV_INSTANCIATE(fmat4x3); + DIV_INSTANCIATE(umat2); + DIV_INSTANCIATE(umat2x3); + DIV_INSTANCIATE(umat2x4); + DIV_INSTANCIATE(umat3); + DIV_INSTANCIATE(umat3x2); + DIV_INSTANCIATE(umat3x4); + DIV_INSTANCIATE(umat4); + DIV_INSTANCIATE(umat4x2); + DIV_INSTANCIATE(umat4x3); + DIV_INSTANCIATE(imat2); + DIV_INSTANCIATE(imat2x3); + DIV_INSTANCIATE(imat2x4); + DIV_INSTANCIATE(imat3); + DIV_INSTANCIATE(imat3x2); + DIV_INSTANCIATE(imat3x4); + DIV_INSTANCIATE(imat4); + DIV_INSTANCIATE(imat4x2); + DIV_INSTANCIATE(imat4x3); + +#undef DIV_INSTANCIATE + +#define TRANSLATE_INSTANCIATE(type) \ + template STORMKIT_CORE_API auto translate(const mat4x4&, const vec3&) noexcept -> mat4x4 + + TRANSLATE_INSTANCIATE(f32); + TRANSLATE_INSTANCIATE(u32); + TRANSLATE_INSTANCIATE(i32); + +#undef TRANSLATE_INSTANCIATE + +#define SCALE_INSTANCIATE(type) \ + template STORMKIT_CORE_API auto scale(const mat4x4&, const vec3&) noexcept -> mat4x4 + + SCALE_INSTANCIATE(f32); + SCALE_INSTANCIATE(u32); + SCALE_INSTANCIATE(i32); + +#undef SCALE_INSTANCIATE + +#define ROTATE_INSTANCIATE(type) \ + template STORMKIT_CORE_API auto rotate(const mat4x4&, angle::radian, const vec3&) noexcept \ + -> mat4x4 + + ROTATE_INSTANCIATE(f32); + // ROTATE_INSTANCIATE(i32); + +#undef ROTATE_INSTANCIATE + +#define ORTHOGRAPHIQUE_INSTANCIATE(type) \ + template STORMKIT_CORE_API auto orthographique(type, type, type, type) noexcept -> mat4x4; \ + template STORMKIT_CORE_API auto orthographique(type, type, type, type, type, type) noexcept -> mat4x4 + + ORTHOGRAPHIQUE_INSTANCIATE(f32); + ORTHOGRAPHIQUE_INSTANCIATE(i32); + +#undef ORTHOGRAPHIQUE_INSTANCIATE + +#define PERSPECTIVE_INSTANCIATE(type) \ + template STORMKIT_CORE_API auto perspective(angle::radian, type, type, type) noexcept -> mat4x4 + + PERSPECTIVE_INSTANCIATE(f32); + // PERSPECTIVE_INSTANCIATE(i32); + +#undef PERSPECTIVE_INSTANCIATE + +#define LOOK_AT_INSTANCIATE(type) \ + template STORMKIT_CORE_API auto look_at(const vec3&, const vec3&, const vec3&) noexcept \ + -> mat4x4 + + LOOK_AT_INSTANCIATE(f32); + LOOK_AT_INSTANCIATE(i32); + +#undef LOOK_AT_INSTANCIATE +}}}} // namespace stormkit::core::math::matrix diff --git a/modules/stormkit/core/math/linear-matrix.mpp b/modules/stormkit/core/math/linear-matrix.mpp deleted file mode 100644 index 2bb516572..000000000 --- a/modules/stormkit/core/math/linear-matrix.mpp +++ /dev/null @@ -1,755 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -export module stormkit.core:math.linear.matrix; - -import std; - -import :meta; - -import :typesafe.integer; -import :typesafe.floating_point; - -import :math.linear; -import :math.linear.vector; - -export { - namespace stormkit { inline namespace core { namespace math { - template - struct alignas(std::array) mat { - using value_type = T; - using storage_type = std::array; - using size_type = usize; - using extent_type = u8; - - static constexpr auto EXTENTS = std::array { M, N }; - - storage_type values; - - template - [[nodiscard]] - constexpr auto operator[](this Self&& self, size_type i) noexcept - -> core::meta::ForwardLike; - - template - [[nodiscard]] - constexpr auto operator[](this Self&& self, size_type i, size_type j) noexcept - -> core::meta::ForwardLike; - - template - [[nodiscard]] - constexpr auto begin(this Self& self) noexcept -> decltype(auto); - [[nodiscard]] - constexpr auto cbegin() const noexcept -> decltype(auto); - - template - [[nodiscard]] - constexpr auto end(this Self& self) noexcept -> decltype(auto); - [[nodiscard]] - constexpr auto cend() const noexcept -> decltype(auto); - - template - [[nodiscard]] - constexpr auto data(this Self& self) noexcept - -> core::meta::ForwardConst*; - - [[nodiscard]] - constexpr auto size() const noexcept -> size_type; - [[nodiscard]] - static consteval auto max_size() noexcept -> size_type; - - [[nodiscard]] - static consteval auto identity() noexcept -> mat - requires(M == N); - }; - - template - using mat2x2 = mat; - - using mat2x2f32 = mat2x2; - using mat2x2f64 = mat2x2; - using mat2x2f = mat2x2f32; - using mat2f = mat2x2f; - - using mat2x2i32 = mat2x2; - using mat2x2i64 = mat2x2; - using mat2x2i = mat2x2i32; - using mat2i = mat2x2i; - - using mat2x2u32 = mat2x2; - using mat2x2u64 = mat2x2; - using mat2x2u = mat2x2u32; - using mat2u = mat2x2u; - - template - using mat3x3 = mat; - - using mat3x3f32 = mat3x3; - using mat3x3f64 = mat3x3; - using mat3x3f = mat3x3f32; - using mat3f = mat3x3f; - - using mat3x3i32 = mat3x3; - using mat3x3i64 = mat3x3; - using mat3x3i = mat3x3i32; - using mat3i = mat3x3i; - - using mat3x3u32 = mat3x3; - using mat3x3u64 = mat3x3; - using mat3x3u = mat3x3u32; - using mat3u = mat3x3u; - - template - using mat4x4 = mat; - - using mat4x4f32 = mat4x4; - using mat4x4f64 = mat4x4; - using mat4x4f = mat4x4f32; - using mat4f = mat4x4f; - - using mat4x4i32 = mat4x4; - using mat4x4i64 = mat4x4; - using mat4x4i = mat4x4i32; - using mat4i = mat4x4i; - - using mat4x4u32 = mat4x4; - using mat4x4u64 = mat4x4; - using mat4x4u = mat4x4u32; - using mat4u = mat4x4u; - - template - using mat2x3 = mat; - - using mat2x3f32 = mat2x3; - using mat2x3f64 = mat2x3; - using mat2x3f = mat2x3f32; - - using mat2x3i32 = mat2x3; - using mat2x3i64 = mat2x3; - using mat2x3i = mat2x3i32; - - using mat2x3u32 = mat2x3; - using mat2x3u64 = mat2x3; - using mat2x3u = mat2x3u32; - - template - using mat3x2 = mat; - - using mat3x2f32 = mat3x2; - using mat3x2f64 = mat3x2; - using mat3x2f = mat3x2f32; - - using mat3x2i32 = mat3x2; - using mat3x2i64 = mat3x2; - using mat3x2i = mat3x2i32; - - using mat3x2u32 = mat3x2; - using mat3x2u64 = mat3x2; - using mat3x2u = mat3x2u32; - - template - using mat4x3 = mat; - - using mat4x3f32 = mat4x3; - using mat4x3f64 = mat4x3; - using mat4x3f = mat4x3f32; - - using mat4x3i32 = mat4x3; - using mat4x3i64 = mat4x3; - using mat4x3i = mat4x3i32; - - using mat4x3u32 = mat4x3; - using mat4x3u64 = mat4x3; - using mat4x3u = mat4x3u32; - - template - using mat3x4 = mat; - - using mat3x4f32 = mat3x4; - using mat3x4f64 = mat3x4; - using mat3x4f = mat3x4f32; - - using mat3x4i32 = mat3x4; - using mat3x4i64 = mat3x4; - using mat3x4i = mat3x4i32; - - using mat3x4u32 = mat3x4; - using mat3x4u64 = mat3x4; - using mat3x4u = mat3x4u32; - - template - using mat4x2 = mat; - - using mat4x2f32 = mat4x2; - using mat4x2f64 = mat4x2; - using mat4x2f = mat4x2f32; - - using mat4x2i32 = mat4x2; - using mat4x2i64 = mat4x2; - using mat4x2i = mat4x2i32; - - using mat4x2u32 = mat4x2; - using mat4x2u64 = mat4x2; - using mat4x2u = mat4x2u32; - - template - using mat2x4 = mat; - - using mat2x4f32 = mat2x4; - using mat2x4f64 = mat2x4; - using mat2x4f = mat2x4f32; - - using mat2x4i32 = mat2x4; - using mat2x4i64 = mat2x4; - using mat2x4i = mat2x4i32; - - using mat2x4u32 = mat2x4; - using mat2x4u64 = mat2x4; - using mat2x4u = mat2x4u32; - - namespace meta { - template - concept IsMat2 = core::meta::IsSpecializationOf; - - template - concept IsMat3 = core::meta::IsSpecializationOf; - - template - concept IsMat4 = core::meta::IsSpecializationOf; - - template - concept IsMat = core::meta::IsSpecializationWithNTTPOf; - - template - concept IsSquareMat = IsMat and T::EXTENTS[0] == T::EXTENTS[1]; - - template - concept HasOneMatType = not(core::meta::IsMdspanType and core::meta::IsMdspanType) - or meta::IsMat - or meta::IsMat; - } // namespace meta - - template - [[nodiscard]] - constexpr auto determinant(const T& mat) noexcept -> typename T::value_type; - - template - constexpr auto transpose(const T& mat) noexcept -> T; - - template - [[nodiscard]] - constexpr auto is_inversible(const T& mat) noexcept -> bool; - - template - constexpr auto inverse(const T& mat) noexcept -> T; - - template - [[nodiscard]] - constexpr auto is_orthogonal(const T& mat) noexcept -> bool; - - template - [[nodiscard]] - constexpr auto mul(const T& a, typename T::value_type b) noexcept -> T; - - template - [[nodiscard]] - constexpr auto div(const T& a, typename T::value_type b) noexcept -> T; - - template - [[nodiscard]] - constexpr auto mul(const T& a, const T& b) noexcept -> T; - - template - requires(core::meta::IsStrict) - [[nodiscard]] - constexpr auto div(const T& a, const U& b) noexcept -> U; - - template - [[nodiscard]] - constexpr auto translate(const mat4x4& mat, const vec3& translation) noexcept - -> mat4x4; - - template - [[nodiscard]] - constexpr auto scale(const mat4x4& mat, const vec3& scale) noexcept -> mat4x4; - - template - [[nodiscard]] - constexpr auto rotate(const mat4x4& mat, Radian angle, const vec3& axis) noexcept - -> mat4x4; - - template - [[nodiscard]] - constexpr auto orthographique(T left, T right, T bottom, T top, T near, T far) noexcept - -> mat4x4; - - template - [[nodiscard]] - constexpr auto orthographique(T left, T right, T bottom, T top) noexcept -> mat4x4; - - template - [[nodiscard]] - constexpr auto perspective(Radian fov_y, T aspect, T near, T far) noexcept -> mat4x4; - - template - [[nodiscard]] - constexpr auto look_at(const vec3& eye, - const vec3& center, - const vec3& up) noexcept -> mat4x4; - - template - [[nodiscard]] - constexpr auto as_span(T& value) noexcept - -> std::span, - T::EXTENTS[0] * T::EXTENTS[1]>; - - template - [[nodiscard]] - constexpr auto as_mdspan(const T& value) noexcept - -> MatrixSpan; - - template - requires(not core::meta::IsConst) - [[nodiscard]] - constexpr auto as_mdspan(T& value) noexcept - -> MatrixSpan; - }}} // namespace stormkit::core::math - - namespace std { - template - struct hash { - [[nodiscard]] - auto operator()(const T&) const noexcept -> stormkit::u64; - }; - - template - struct formatter { - template - constexpr auto parse(ParseContext& ctx) noexcept -> decltype(ctx.begin()); - - template - [[nodiscard]] - auto format(const T&, FormatContext& ctx) const -> decltype(ctx.out()); - }; - - template - constexpr range_format format_kind = range_format::disabled; - } // namespace std -} - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stdr = std::ranges; -namespace stdv = std::views; - -namespace stormkit { inline namespace core { namespace math { - static_assert(sizeof(mat2x2i32) == sizeof(i32) * 2 * 2); - static_assert(sizeof(mat2x2i64) == sizeof(i64) * 2 * 2); - static_assert(sizeof(mat2x2u32) == sizeof(u32) * 2 * 2); - static_assert(sizeof(mat2x2u64) == sizeof(u64) * 2 * 2); - static_assert(sizeof(mat2x2f32) == sizeof(f32) * 2 * 2); - static_assert(sizeof(mat2x2f64) == sizeof(f64) * 2 * 2); - - static_assert(sizeof(mat3x3i32) == sizeof(i32) * 3 * 3); - static_assert(sizeof(mat3x3i64) == sizeof(i64) * 3 * 3); - static_assert(sizeof(mat3x3u32) == sizeof(u32) * 3 * 3); - static_assert(sizeof(mat3x3u64) == sizeof(u64) * 3 * 3); - static_assert(sizeof(mat3x3f32) == sizeof(f32) * 3 * 3); - static_assert(sizeof(mat3x3f64) == sizeof(f64) * 3 * 3); - - static_assert(sizeof(mat4x4i32) == sizeof(i32) * 4 * 4); - static_assert(sizeof(mat4x4i64) == sizeof(i64) * 4 * 4); - static_assert(sizeof(mat4x4u32) == sizeof(u32) * 4 * 4); - static_assert(sizeof(mat4x4u64) == sizeof(u64) * 4 * 4); - static_assert(sizeof(mat4x4f32) == sizeof(f32) * 4 * 4); - static_assert(sizeof(mat4x4f64) == sizeof(f64) * 4 * 4); - - //////////////////////////////////////// - //////////////////////////////////////// - template - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto mat::operator[](this Self&& self, size_type i) noexcept - -> core::meta::ForwardLike { - return std::forward(self).values[i]; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto mat::operator[](this Self&& self, size_type i, size_type j) noexcept - -> core::meta::ForwardLike { - return std::forward_like(self.operator[](j + i * M)); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto mat::begin(this Self& self) noexcept -> decltype(auto) { - return stdr::begin(self.values); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto mat::cbegin() const noexcept -> decltype(auto) { - return stdr::cbegin(values); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto mat::end(this Self& self) noexcept -> decltype(auto) { - return stdr::end(self.values); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto mat::cend() const noexcept -> decltype(auto) { - return stdr::cend(values); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto mat::data(this Self& self) noexcept - -> core::meta::ForwardConst* { - return stdr::data(self.values); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto mat::size() const noexcept -> size_type { - return stdr::size(values); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - consteval auto mat::max_size() noexcept -> size_type { - return M * N; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - consteval auto mat::identity() noexcept -> mat - requires(M == N) - { - auto matrix = mat {}; - - for (auto i = 0u; i < M; ++i) { matrix[i, i] = T { 1 }; } - - return matrix; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto determinant(const T& mat) noexcept -> typename T::value_type { - return determinant(as_mdspan(mat)); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto transpose(const T& mat) noexcept -> T { - auto out = T {}; - transpose(as_mdspan(mat), as_mdspan_mut(out)); - return out; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto is_inversible(const T& mat) noexcept -> bool { - return is_inversible(as_mdspan(mat)); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto inverse(const T& mat) noexcept -> T { - auto out = T {}; - inverse(as_mdspan(mat), as_mdspan_mut(out)); - return out; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto is_orthogonal(const T& mat) noexcept -> bool { - return is_orthogonal(as_mdspan(mat)); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto mul(const T& a, typename T::value_type b) noexcept -> T { - auto out = T {}; - - mul(as_mdspan(a), b, as_mdspan_mut(out)); - - return out; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto div(const T& a, typename T::value_type b) noexcept -> T { - auto out = T {}; - - div(as_mdspan(a), b, as_mdspan_mut(out)); - - return out; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto mul(const T& a, const T& b) noexcept -> T { - auto out = T {}; - - mul(as_mdspan(a), as_mdspan(b), as_mdspan_mut(out)); - - return out; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - requires(core::meta::IsStrict) - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto div(const T& a, const U& b) noexcept -> U { - auto out = T {}; - - div(as_mdspan(a), as_mdspan(b), as_mdspan_mut(out)); - - return out; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto translate(const mat4x4& mat, const vec3& translation) noexcept - -> mat4x4 { - auto out = mat4x4 {}; - - translate(as_mdspan(mat), as_mdspan(translation), as_mdspan_mut(out)); - - return out; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto scale(const mat4x4& mat, const vec3& scale_factors) noexcept -> mat4x4 { - auto out = mat4x4 {}; - - scale(as_mdspan(mat), as_mdspan(scale_factors), as_mdspan_mut(out)); - - return out; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto rotate(const mat4x4& mat, Radian angle, const vec3& axis) noexcept - -> mat4x4 { - auto out = mat4x4 {}; - - rotate(as_mdspan(mat), angle, as_mdspan(axis), as_mdspan_mut(out)); - - return out; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto orthographique(T left, T right, T bottom, T top, T near, T far) noexcept - -> mat4x4 { - auto out = mat4x4 {}; - - orthographique(left, right, bottom, top, near, far, as_mdspan_mut(out)); - - return out; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto orthographique(T left, T right, T bottom, T top) noexcept -> mat4x4 { - auto out = mat4x4 {}; - - orthographique(left, right, bottom, top, as_mdspan_mut(out)); - - return out; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto perspective(Radian fov_y, T aspect, T near, T far) noexcept -> mat4x4 { - auto out = mat4x4 {}; - - perspective(fov_y, aspect, near, far, as_mdspan_mut(out)); - - return out; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto look_at(const vec3& eye, const vec3& center, const vec3& up) noexcept - -> mat4x4 { - auto out = mat4x4 {}; - - look_at(as_mdspan(eye), as_mdspan(center), as_mdspan(up), as_mdspan_mut(out)); - - return out; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto as_span(T& value) noexcept - -> std::span, - T::EXTENTS[0] * T::EXTENTS[1]> { - return std::span, - T::EXTENTS[0] * T::EXTENTS[1]> { stdr::data(value), - T::EXTENTS[0] * T::EXTENTS[1] }; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto as_mdspan(const T& value) noexcept - -> MatrixSpan { - return MatrixSpan { - stdr::data(value), - T::EXTENTS - }; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - requires(not core::meta::IsConst) - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto as_mdspan_mut(T& value) noexcept - -> MatrixSpan { - return MatrixSpan { stdr::data(value), - T::EXTENTS }; - } -}}} // namespace stormkit::core::math - -//////////////////////////////////////// -//////////////////////////////////////// -template - STORMKIT_PURE STORMKIT_FORCE_INLINE -auto std::hash::operator()(const T& mat) const noexcept -> stormkit::u64 { - const auto span = as_span(mat); - - auto hash = stormkit::u64 { 0 }; - for (const auto v : span) stormkit::hash_combine(hash, v); - - return hash; -} - -//////////////////////////////////////// -//////////////////////////////////////// -template -template -constexpr auto std::formatter::parse(ParseContext& ctx) noexcept - -> decltype(ctx.begin()) { - return ctx.begin(); -} - -//////////////////////////////////////// -//////////////////////////////////////// -template -template -inline auto std::formatter::format(const T& mat, FormatContext& ctx) const - -> decltype(ctx.out()) { - auto out = ctx.out(); - - auto i = 0; - auto check_by_extent = [&i](auto, auto) mutable { - const auto insert = i++ < (T::EXTENTS[0] - 1); - if (not insert) i = 0; - - return insert; - }; - - format_to(out, "{ mat:"); - auto l = 0u; - if constexpr (stormkit::meta::IsIntegral) { - auto max_digit = 0u; - for (auto v : as_span(mat)) - max_digit = std::max(max_digit, v == 0 ? 2 : narrow(std::log10(v) + 2)); - for (auto&& slice : mat | stdv::chunk_by(check_by_extent)) { - format_to(out, - "{}|{:n:>{}}|{}", - (l > 0) ? " "sv : " "sv, - slice, - max_digit, - (l != (T::EXTENTS[0] - 1)) ? "\n"sv : "}"sv); - ++l; - } - } else { - auto max_digit = 0u; - for (auto v : as_span(mat)) - max_digit = std::max(max_digit, - narrow(v) == 0 ? 2 : narrow(std::log10(v) + 2)); - for (auto&& slice : mat | stdv::chunk_by(check_by_extent)) { - format_to(out, - "{}| {:n:>{}.5f}|{}", - (l > 0) ? " "sv : " "sv, - slice, - max_digit, - (l != (T::EXTENTS[0] - 1)) ? "\n"sv : "}"sv); - ++l; - } - } - - return out; -} diff --git a/modules/stormkit/core/math/linear-vector.cppm b/modules/stormkit/core/math/linear-vector.cppm new file mode 100644 index 000000000..6511ca63e --- /dev/null +++ b/modules/stormkit/core/math/linear-vector.cppm @@ -0,0 +1,577 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include + +export module stormkit.core:math.linear.vector; + +import std; + +import :meta; + +import :typesafe.integer; +import :typesafe.floating_point; + +import :math.linear; + +import :hash.base; + +import :string.format; + +export namespace stormkit { inline namespace core { namespace math { + inline namespace vector { + template + struct alignas(array) vec2 { + using ValueType = T; + using SizeType = usize; + using ExtentType = u8; + + using value_type = ValueType; + using size_type = SizeType; + using extent_type = ExtentType; + + static constexpr auto EXTENT = array { 2uz }; + + ValueType x; + ValueType y; + + template + constexpr auto operator[](this Self& self, usize i) noexcept -> core::meta::ForwardConst&; + + template + constexpr auto to() const noexcept -> vec2; + }; + + using fvec2 = vec2; + using ivec2 = vec2; + using uvec2 = vec2; + + template + struct alignas(array) vec3 { + using ValueType = T; + using SizeType = usize; + using ExtentType = u8; + + using value_type = ValueType; + using size_type = SizeType; + using extent_type = ExtentType; + + static constexpr auto EXTENT = array { 3uz }; + + ValueType x; + ValueType y; + ValueType z; + + template + constexpr auto operator[](this Self& self, usize i) noexcept -> core::meta::ForwardConst&; + + template + constexpr auto to() const noexcept -> vec3; + }; + + using fvec3 = vec3; + using ivec3 = vec3; + using uvec3 = vec3; + + template + struct alignas(array) vec4 { + using ValueType = T; + using SizeType = usize; + using ExtentType = u8; + + using value_type = ValueType; + using size_type = SizeType; + using extent_type = ExtentType; + + static constexpr auto EXTENT = array { 4uz }; + + ValueType x; + ValueType y; + ValueType z; + ValueType w; + + template + constexpr auto operator[](this Self& self, usize i) noexcept -> core::meta::ForwardConst&; + + template + constexpr auto to() const noexcept -> vec4; + }; + + using fvec4 = vec4; + using ivec4 = vec4; + using uvec4 = vec4; + + } // namespace vector + + namespace meta { + template + concept IsVec2 = core::meta::IsSpecializationOf; + template + concept IsVec3 = core::meta::IsSpecializationOf; + template + concept IsVec4 = core::meta::IsSpecializationOf; + + template + concept IsVec = IsVec2 || IsVec3 || IsVec4; + + template + concept HasOneVecType = not(core::meta::IsStdMdspan and core::meta::IsStdMdspan) + or meta::IsVec + or meta::IsVec; + } // namespace meta + + inline namespace vector { + template + [[nodiscard]] + constexpr auto add(const T& a, const T& b) noexcept -> T; + + template + [[nodiscard]] + constexpr auto sub(const T& a, const T& b) noexcept -> T; + + template + [[nodiscard]] + constexpr auto mul(const T& a, typename T::ValueType b) noexcept -> T; + + template + [[nodiscard]] + constexpr auto div(const T& a, typename T::ValueType b) noexcept -> T; + + template + [[nodiscard]] + constexpr auto dot(const T& a, const T& b) noexcept -> typename T::ValueType; + + template + [[nodiscard]] + constexpr auto cross(const vec3& a, const vec3& b) noexcept -> vec3; + + template + [[nodiscard]] + constexpr auto normalize(const T& a) noexcept -> T; + + template + [[nodiscard]] + constexpr auto as_view(const T& value) noexcept -> array_view; + + template + [[nodiscard]] + constexpr auto as_view_mut(T& value) noexcept -> array_view; + + template + [[nodiscard]] + constexpr auto as_mdspan(const T& value) noexcept -> VectorSpan; + + template + requires(not core::meta::IsConst) + [[nodiscard]] + constexpr auto as_mdspan_mut(T& value) noexcept -> VectorSpan; + + template + auto to_string(const vec2& value) noexcept -> string; + + template + auto to_string(const vec3& value) noexcept -> string; + + template + auto to_string(const vec4& value) noexcept -> string; + + template + constexpr auto hasher(const vec2& value) noexcept -> Ret; + + template + constexpr auto hasher(const vec3& value) noexcept -> Ret; + + template + constexpr auto hasher(const vec4& value) noexcept -> Ret; + + template + auto format_as(const vec2& value, FormatContext& ctx) noexcept -> decltype(ctx.out()); + + template + auto format_as(const vec3& value, FormatContext& ctx) noexcept -> decltype(ctx.out()); + + template + auto format_as(const vec4& value, FormatContext& ctx) noexcept -> decltype(ctx.out()); + } // namespace vector +}}} // namespace stormkit::core::math + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stdr = std::ranges; + +namespace stormkit { inline namespace core { namespace math { inline namespace vector { + static_assert(sizeof(uvec2) == sizeof(u32) * 2); + static_assert(sizeof(vec2) == sizeof(u64) * 2); + static_assert(sizeof(ivec2) == sizeof(i32) * 2); + static_assert(sizeof(vec2) == sizeof(i64) * 2); + static_assert(sizeof(fvec2) == sizeof(f32) * 2); + static_assert(sizeof(vec2) == sizeof(f64) * 2); + + static_assert(sizeof(uvec3) == sizeof(u32) * 3); + static_assert(sizeof(vec3) == sizeof(u64) * 3); + static_assert(sizeof(ivec3) == sizeof(i32) * 3); + static_assert(sizeof(vec3) == sizeof(i64) * 3); + static_assert(sizeof(fvec3) == sizeof(f32) * 3); + static_assert(sizeof(vec3) == sizeof(f64) * 3); + + static_assert(sizeof(uvec4) == sizeof(u32) * 4); + static_assert(sizeof(vec4) == sizeof(u64) * 4); + static_assert(sizeof(ivec4) == sizeof(i32) * 4); + static_assert(sizeof(vec4) == sizeof(i64) * 4); + static_assert(sizeof(fvec4) == sizeof(f32) * 4); + static_assert(sizeof(vec4) == sizeof(f64) * 4); + + //////////////////////////////////////// + //////////////////////////////////////// + template + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto vec2::operator[](this Self& self, usize i) noexcept -> core::meta::ForwardConst& { + static constexpr auto members = array { &vec2::x, &vec2::y }; + + return std::forward_like(self.*members[i]); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto vec2::to() const noexcept -> vec2 { + return { core::as(x), core::as(y) }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto vec3::operator[](this Self& self, usize i) noexcept -> core::meta::ForwardConst& { + static constexpr auto members = array { &vec3::x, &vec3::y, &vec3::z }; + + return std::forward_like(self.*members[i]); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto vec3::to() const noexcept -> vec3 { + return { core::as(x), core::as(y), core::as(z) }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto vec4::operator[](this Self& self, usize i) noexcept -> core::meta::ForwardConst& { + static constexpr auto members = array { &vec4::x, &vec4::y, &vec4::z, &vec4::w }; + + return std::forward_like(self.*members[i]); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto vec4::to() const noexcept -> vec4 { + return { core::as(x), core::as(y), core::as(z), core::as(w) }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto normalize(const T& a) noexcept -> T { + auto out = T {}; + + math::normalize(as_mdspan(a), as_mdspan_mut(out)); + + return out; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto add(const T& a, const T& b) noexcept -> T { + auto out = T {}; + + math::add(as_mdspan(a), as_mdspan(b), as_mdspan_mut(out)); + + return out; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto sub(const T& a, const T& b) noexcept -> T { + auto out = T {}; + + math::sub(as_mdspan(a), as_mdspan(b), as_mdspan_mut(out)); + + return out; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto mul(const T& a, typename T::ValueType b) noexcept -> T { + auto out = T {}; + + math::mul(as_mdspan(a), b, as_mdspan_mut(out)); + + return out; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto div(const T& a, typename T::ValueType b) noexcept -> T { + auto out = T {}; + + math::div(as_mdspan(a), b, as_mdspan_mut(out)); + + return out; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto dot(const T& a, const T& b) noexcept -> typename T::ValueType { + return math::dot(as_mdspan(a), as_mdspan(b)); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto cross(const vec3& a, const vec3& b) noexcept -> vec3 { + auto out = vec3 {}; + + math::cross(as_mdspan(a), as_mdspan(b), as_mdspan_mut(out)); + + return out; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto as_view(const T& value) noexcept -> array_view { + return array_view { &value.x, T::EXTENT[0] }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto as_view_mut(T& value) noexcept -> array_view { + return array_view { &value.x, T::EXTENT[0] }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto as_mdspan(const T& value) noexcept -> VectorSpan { + return VectorSpan { &value.x, T::EXTENT }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + requires(not core::meta::IsConst) + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto as_mdspan_mut(T& value) noexcept -> VectorSpan { + return VectorSpan { &value.x, T::EXTENT }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + auto to_string(const vec2& value) noexcept -> string { + return std::format("{}", value); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + auto to_string(const vec3& value) noexcept -> string { + return std::format("{}", value); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + auto to_string(const vec4& value) noexcept -> string { + return std::format("{}", value); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto hasher(const vec2& value) noexcept -> Ret { + return hash(value.x, value.y); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto hasher(const vec3& value) noexcept -> Ret { + return hash(value.x, value.y, value.z); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto hasher(const vec4& value) noexcept -> Ret { + return hash(value.x, value.y, value.z, value.w); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto format_as(const vec2& value, FormatContext& ctx) noexcept -> decltype(ctx.out()) { + return std::format_to(ctx.out(), "[vec2 x: {}, y: {}]", value.x, value.y); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto format_as(const vec3& value, FormatContext& ctx) noexcept -> decltype(ctx.out()) { + return std::format_to(ctx.out(), "[vec3 x: {}, y: {}, z: {}]", value.x, value.y, value.z); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto format_as(const vec4& value, FormatContext& ctx) noexcept -> decltype(ctx.out()) { + return std::format_to(ctx.out(), "[vec4 x: {}, y: {}, z: {}, w: {}]", value.x, value.y, value.z, value.w); + } + +#ifndef STORMKIT_OS_WINDOWS + #undef STORMKIT_CORE_API + #define STORMKIT_CORE_API +#endif + +#define ADD_INSTANCIATE(vec_type) \ + template STORMKIT_CORE_API auto add(const vec_type&, const vec_type&) noexcept -> vec_type + + ADD_INSTANCIATE(fvec2); + ADD_INSTANCIATE(fvec3); + ADD_INSTANCIATE(fvec4); + ADD_INSTANCIATE(uvec2); + ADD_INSTANCIATE(uvec3); + ADD_INSTANCIATE(uvec4); + ADD_INSTANCIATE(ivec2); + ADD_INSTANCIATE(ivec3); + ADD_INSTANCIATE(ivec4); + +#undef ADD_INSTANCIATE + +#define SUB_INSTANCIATE(vec_type) \ + template STORMKIT_CORE_API auto sub(const vec_type&, const vec_type&) noexcept -> vec_type + + SUB_INSTANCIATE(fvec2); + SUB_INSTANCIATE(fvec3); + SUB_INSTANCIATE(fvec4); + SUB_INSTANCIATE(uvec2); + SUB_INSTANCIATE(uvec3); + SUB_INSTANCIATE(uvec4); + SUB_INSTANCIATE(ivec2); + SUB_INSTANCIATE(ivec3); + SUB_INSTANCIATE(ivec4); + +#undef SUB_INSTANCIATE + +#define MUL_INSTANCIATE(vec_type) \ + template STORMKIT_CORE_API auto mul(const vec_type&, typename vec_type::ValueType) noexcept -> vec_type + + MUL_INSTANCIATE(fvec2); + MUL_INSTANCIATE(fvec3); + MUL_INSTANCIATE(fvec4); + MUL_INSTANCIATE(uvec2); + MUL_INSTANCIATE(uvec3); + MUL_INSTANCIATE(uvec4); + MUL_INSTANCIATE(ivec2); + MUL_INSTANCIATE(ivec3); + MUL_INSTANCIATE(ivec4); + +#undef MUL_INSTANCIATE + +#define DIV_INSTANCIATE(vec_type) \ + template STORMKIT_CORE_API auto div(const vec_type&, typename vec_type::ValueType) noexcept -> vec_type + + DIV_INSTANCIATE(fvec2); + DIV_INSTANCIATE(fvec3); + DIV_INSTANCIATE(fvec4); + DIV_INSTANCIATE(uvec2); + DIV_INSTANCIATE(uvec3); + DIV_INSTANCIATE(uvec4); + DIV_INSTANCIATE(ivec2); + DIV_INSTANCIATE(ivec3); + DIV_INSTANCIATE(ivec4); + +#undef DIV_INSTANCIATE + +#define DOT_INSTANCIATE(vec_type) \ + template STORMKIT_CORE_API auto dot(const vec_type&, const vec_type&) noexcept -> typename vec_type::ValueType + + DOT_INSTANCIATE(fvec2); + DOT_INSTANCIATE(fvec3); + DOT_INSTANCIATE(fvec4); + DOT_INSTANCIATE(uvec2); + DOT_INSTANCIATE(uvec3); + DOT_INSTANCIATE(uvec4); + DOT_INSTANCIATE(ivec2); + DOT_INSTANCIATE(ivec3); + DOT_INSTANCIATE(ivec4); + +#undef DOT_INSTANCIATE + +#define CROSS_INSTANCIATE(type) \ + template STORMKIT_CORE_API auto cross(const vec3&, const vec3&) noexcept -> vec3 + + CROSS_INSTANCIATE(f32); + CROSS_INSTANCIATE(u32); + CROSS_INSTANCIATE(i32); + +#undef CROSS_INSTANCIATE + +#define NORMALIZE_INSTANCIATE(vec_type) template STORMKIT_CORE_API auto normalize(const vec_type&) noexcept -> vec_type + + NORMALIZE_INSTANCIATE(fvec2); + NORMALIZE_INSTANCIATE(fvec3); + NORMALIZE_INSTANCIATE(fvec4); + NORMALIZE_INSTANCIATE(uvec2); + NORMALIZE_INSTANCIATE(uvec3); + NORMALIZE_INSTANCIATE(uvec4); + NORMALIZE_INSTANCIATE(ivec2); + NORMALIZE_INSTANCIATE(ivec3); + NORMALIZE_INSTANCIATE(ivec4); + +#undef NORMALIZE_INSTANCIATE +}}}} // namespace stormkit::core::math::vector diff --git a/modules/stormkit/core/math/linear-vector.mpp b/modules/stormkit/core/math/linear-vector.mpp deleted file mode 100644 index dbf3b6b97..000000000 --- a/modules/stormkit/core/math/linear-vector.mpp +++ /dev/null @@ -1,493 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -export module stormkit.core:math.linear.vector; - -import std; - -import :meta; -import :typesafe; - -import :math.linear; - -import :hash.base; - -export { - namespace stormkit { inline namespace core { namespace math { - template - struct alignas(std::array) vec2 { - using value_type = T; - using size_type = usize; - using extent_type = u8; - - static constexpr auto EXTENT = std::array { 2uz }; - - T x; - T y; - - template - constexpr auto operator[](this Self& self, usize i) noexcept - -> core::meta::ForwardConst; - - template - constexpr auto to() const noexcept -> vec2; - }; - - using vec2f32 = vec2; - using vec2f64 = vec2; - using vec2f = vec2f32; - - using vec2i32 = vec2; - using vec2i64 = vec2; - using vec2i = vec2i32; - - using vec2u32 = vec2; - using vec2u64 = vec2; - using vec2u = vec2u32; - - template - struct alignas(std::array) vec3 { - using value_type = T; - using size_type = usize; - using extent_type = u8; - - static constexpr auto EXTENT = std::array { 3uz }; - - T x; - T y; - T z; - - template - constexpr auto operator[](this Self& self, usize i) noexcept - -> core::meta::ForwardConst; - - template - constexpr auto to() const noexcept -> vec3; - }; - - using vec3f32 = vec3; - using vec3f64 = vec3; - using vec3f = vec3f32; - - using vec3i32 = vec3; - using vec3i64 = vec3; - using vec3i = vec3i32; - - using vec3u32 = vec3; - using vec3u64 = vec3; - using vec3u = vec3u32; - - template - struct alignas(std::array) vec4 { - using value_type = T; - using size_type = usize; - using extent_type = u8; - - static constexpr auto EXTENT = std::array { 4uz }; - - T x; - T y; - T z; - T w; - - template - constexpr auto operator[](this Self& self, usize i) noexcept - -> core::meta::ForwardConst; - - template - constexpr auto to() const noexcept -> vec4; - }; - - using vec4f32 = vec4; - using vec4f64 = vec4; - using vec4f = vec4f32; - - using vec4i32 = vec4; - using vec4i64 = vec4; - using vec4i = vec4i32; - - using vec4u32 = vec4; - using vec4u64 = vec4; - using vec4u = vec4u32; - - namespace meta { - template - concept IsVec2 = core::meta::IsSpecializationOf; - template - concept IsVec3 = core::meta::IsSpecializationOf; - - template - concept IsVec = IsVec2 || IsVec3; - - template - concept HasOneVecType = not(core::meta::IsMdspanType and core::meta::IsMdspanType) - or meta::IsVec - or meta::IsVec; - } // namespace meta - - template - [[nodiscard]] - constexpr auto add(const T& a, const T& b) noexcept -> T; - - template - [[nodiscard]] - constexpr auto sub(const T& a, const T& b) noexcept -> T; - - template - [[nodiscard]] - constexpr auto mul(const T& a, typename T::value_type b) noexcept -> T; - - template - [[nodiscard]] - constexpr auto div(const T& a, typename T::value_type b) noexcept -> T; - - template - [[nodiscard]] - constexpr auto dot(const T& a, const T& b) noexcept -> typename T::value_type; - - template - [[nodiscard]] - constexpr auto cross(const vec3& a, const vec3& b) noexcept -> vec3; - - template - [[nodiscard]] - constexpr auto normalize(const T& a) noexcept -> T; - - template - [[nodiscard]] - constexpr auto as_mdspan(const T& value) noexcept - -> VectorSpan; - - template - requires(not core::meta::IsConst) - [[nodiscard]] - constexpr auto as_mdspan_mut(T& value) noexcept - -> VectorSpan; - }}} // namespace stormkit::core::math - - namespace std { - template - struct hash> { - [[nodiscard]] - auto operator()(const stormkit::math::vec2&) const noexcept -> stormkit::u64; - }; - - template - struct formatter, CharT>: formatter { - template - [[nodiscard]] - auto format(const stormkit::math::vec2&, FormatContext& ctx) const - -> decltype(ctx.out()); - }; - - template - struct hash> { - [[nodiscard]] - auto operator()(const stormkit::math::vec3&) const noexcept -> stormkit::u64; - }; - - template - struct formatter, CharT>: formatter { - template - [[nodiscard]] - auto format(const stormkit::math::vec3&, FormatContext& ctx) const - -> decltype(ctx.out()); - }; - - template - struct hash> { - [[nodiscard]] - auto operator()(const stormkit::math::vec4&) const noexcept -> stormkit::u64; - }; - - template - struct formatter, CharT>: formatter { - template - [[nodiscard]] - auto format(const stormkit::math::vec4&, FormatContext& ctx) const - -> decltype(ctx.out()); - }; - } // namespace std -} // namespace stormkit::core::math - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stdr = std::ranges; - -namespace stormkit { inline namespace core { namespace math { - static_assert(sizeof(vec2u32) == sizeof(u32) * 2); - static_assert(sizeof(vec2u64) == sizeof(u64) * 2); - static_assert(sizeof(vec2i32) == sizeof(i32) * 2); - static_assert(sizeof(vec2i64) == sizeof(i64) * 2); - static_assert(sizeof(vec2f32) == sizeof(f32) * 2); - static_assert(sizeof(vec2f64) == sizeof(f64) * 2); - - static_assert(sizeof(vec3u32) == sizeof(u32) * 3); - static_assert(sizeof(vec3u64) == sizeof(u64) * 3); - static_assert(sizeof(vec3i32) == sizeof(i32) * 3); - static_assert(sizeof(vec3i64) == sizeof(i64) * 3); - static_assert(sizeof(vec3f32) == sizeof(f32) * 3); - static_assert(sizeof(vec3f64) == sizeof(f64) * 3); - - static_assert(sizeof(vec4u32) == sizeof(u32) * 4); - static_assert(sizeof(vec4u64) == sizeof(u64) * 4); - static_assert(sizeof(vec4i32) == sizeof(i32) * 4); - static_assert(sizeof(vec4i64) == sizeof(i64) * 4); - static_assert(sizeof(vec4f32) == sizeof(f32) * 4); - static_assert(sizeof(vec4f64) == sizeof(f64) * 4); - - //////////////////////////////////////// - //////////////////////////////////////// - template - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto vec2::operator[](this Self& self, usize i) noexcept - -> core::meta::ForwardConst { - static constexpr auto* members = { &vec2::x, &vec2::y }; - - return std::forward_like(self->*members[i]); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto vec2::to() const noexcept -> vec2 { - return { core::as(x), core::as(y) }; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto vec3::operator[](this Self& self, usize i) noexcept - -> core::meta::ForwardConst { - static constexpr auto* members = { &vec3::x, &vec3::y, &vec3::z }; - - return std::forward_like(self->*members[i]); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto vec3::to() const noexcept -> vec3 { - return { core::as(x), core::as(y), core::as(z) }; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto vec4::operator[](this Self& self, usize i) noexcept - -> core::meta::ForwardConst { - static constexpr auto* members = { &vec4::x, &vec4::y, &vec4::z, &vec4::w }; - - return std::forward_like(self->*members[i]); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto vec4::to() const noexcept -> vec4 { - return { core::as(x), core::as(y), core::as(z), core::as(w) }; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto normalize(const T& a) noexcept -> T { - auto out = T {}; - - normalize(as_mdspan(a), as_mdspan_mut(out)); - - return out; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto add(const T& a, const T& b) noexcept -> T { - auto out = T {}; - - add(as_mdspan(a), as_mdspan(b), as_mdspan_mut(out)); - - return out; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto sub(const T& a, const T& b) noexcept -> T { - auto out = T {}; - - sub(as_mdspan(a), as_mdspan(b), as_mdspan_mut(out)); - - return out; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto mul(const T& a, typename T::value_type b) noexcept -> T { - auto out = T {}; - - mul(as_mdspan(a), b, as_mdspan_mut(out)); - - return out; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto div(const T& a, typename T::value_type b) noexcept -> T { - auto out = T {}; - - div(as_mdspan(a), b, as_mdspan_mut(out)); - - return out; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto dot(const T& a, const T& b) noexcept -> typename T::value_type { - return dot(as_mdspan(a), as_mdspan(b)); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto cross(const vec3& a, const vec3& b) noexcept -> vec3 { - auto out = vec3 {}; - - cross(as_mdspan(a), as_mdspan(b), as_mdspan_mut(out)); - - return out; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto as_mdspan(const T& value) noexcept - -> VectorSpan { - return VectorSpan { &value.x, T::EXTENT }; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - requires(not core::meta::IsConst) - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto as_mdspan_mut(T& value) noexcept - -> VectorSpan { - return VectorSpan { &value.x, T::EXTENT }; - } -}}} // namespace stormkit::core::math - -namespace std { - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - auto hash>::operator()(const stormkit::math::vec2& vec) - const noexcept -> stormkit::u64 { - auto hash = stormkit::hash64 { 0 }; - - stormkit::hash_combine(hash, vec.x); - stormkit::hash_combine(hash, vec.y); - - return hash; - } - - template - template - inline auto formatter, - CharT>::format(const stormkit::math::vec2& vec, - FormatContext& ctx) const -> decltype(ctx.out()) { - auto out = ctx.out(); - - stdr::copy("{ vec2: .x = "sv, out); - formatter::format(vec.x, ctx); - stdr::copy(" .y = "sv, out); - formatter::format(vec.y, ctx); - stdr::copy(" }"sv, out); - - return std::move(out); - } - - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - auto hash>::operator()(const stormkit::math::vec3& vec) - const noexcept -> stormkit::u64 { - auto hash = stormkit::hash64 { 0 }; - stormkit::hash_combine(hash, vec.x, vec.y, vec.z); - return hash; - } - - template - template - inline auto formatter, - CharT>::format(const stormkit::math::vec3& vec, - FormatContext& ctx) const -> decltype(ctx.out()) { - auto out = ctx.out(); - - stdr::copy("{ vec3: .x = "sv, out); - formatter::format(vec.x, ctx); - stdr::copy(" .y = "sv, out); - formatter::format(vec.y, ctx); - stdr::copy(" .z = "sv, out); - formatter::format(vec.z, ctx); - stdr::copy(" }"sv, out); - - return std::move(out); - } - - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - auto hash>::operator()(const stormkit::math::vec4& vec) - const noexcept -> stormkit::u64 { - auto hash = stormkit::hash64 { 0 }; - stormkit::hash_combine(hash, vec.x, vec.y, vec.z, vec.w); - return hash; - } - - template - template - inline auto formatter, - CharT>::format(const stormkit::math::vec4& vec, - FormatContext& ctx) const -> decltype(ctx.out()) { - auto out = ctx.out(); - - stdr::copy("{ vec4: .x = "sv, out); - formatter::format(vec.x, ctx); - stdr::copy(" .y = "sv, out); - formatter::format(vec.y, ctx); - stdr::copy(" .z = "sv, out); - formatter::format(vec.z, ctx); - stdr::copy(" .w = "sv, out); - formatter::format(vec.w, ctx); - stdr::copy(" }"sv, out); - - return std::move(out); - } -} // namespace std diff --git a/modules/stormkit/core/math/linear.mpp b/modules/stormkit/core/math/linear.cppm similarity index 69% rename from modules/stormkit/core/math/linear.mpp rename to modules/stormkit/core/math/linear.cppm index efb402d7d..9fb9fe63a 100644 --- a/modules/stormkit/core/math/linear.mpp +++ b/modules/stormkit/core/math/linear.cppm @@ -21,15 +21,21 @@ import :functional; // TODO improve template deduction export namespace stormkit { inline namespace core { namespace math { - template - using Euler = StrongType; + namespace angle { + template + using euler = StrongType; - template - using Radian = StrongType; + template + using radian = StrongType; + + template + [[nodiscard]] + constexpr auto radians(T degres) noexcept -> radian; + } // namespace angle template requires(sizeof...(Sizes) >= 1) - using TensorSpan = std::mdspan>; + using TensorSpan = mdarray_view>; template using VectorSpan = TensorSpan; @@ -47,41 +53,32 @@ export namespace stormkit { inline namespace core { namespace math { // template // [[nodiscard]] - // constexpr auto as_span(TensorSpan& tensor) noexcept -> std::span& tensor) noexcept -> array_view; template [[nodiscard]] - constexpr auto as_span(const TensorSpan& tensor) noexcept - -> std::span; + constexpr auto as_span(const TensorSpan& tensor) noexcept -> array_view; template requires(not core::meta::IsConst) [[nodiscard]] - constexpr auto as_span_mut(TensorSpan tensor) noexcept - -> std::span; + constexpr auto as_span_mut(TensorSpan tensor) noexcept -> array_view; template requires(core::meta::IsArithmetic>) [[nodiscard]] - constexpr auto as_mdspan(const T& data) noexcept - -> TensorSpan, Sizes...>; + constexpr auto as_mdspan(const T& data) noexcept -> TensorSpan, Sizes...>; template - requires(core::meta::IsArithmetic> - and not core::meta::IsConst>) + requires(core::meta::IsArithmetic> and not core::meta::IsConst>) [[nodiscard]] - constexpr auto as_mdspan_mut(T& data) noexcept - -> TensorSpan, Sizes...>; + constexpr auto as_mdspan_mut(T& data) noexcept -> TensorSpan, Sizes...>; template [[nodiscard]] constexpr auto as(const From& data) noexcept -> To; - template - [[nodiscard]] - constexpr auto radians(T degres) noexcept -> Radian; - template requires(not core::meta::IsConst) constexpr auto add(const TensorSpan& a, @@ -96,15 +93,11 @@ export namespace stormkit { inline namespace core { namespace math { template requires(not core::meta::IsConst) - constexpr auto mul(const TensorSpan& a, - T b, - TensorSpan out) noexcept -> void; + constexpr auto mul(const TensorSpan& a, T b, TensorSpan out) noexcept -> void; template requires(not core::meta::IsConst) - constexpr auto div(const TensorSpan& a, - T b, - TensorSpan out) noexcept -> void; + constexpr auto div(const TensorSpan& a, T b, TensorSpan out) noexcept -> void; // TODO WAIT FOR SUBMDSPAN // template // constexpr auto normalize(TensorSpan a, @@ -113,24 +106,19 @@ export namespace stormkit { inline namespace core { namespace math { /* vector */ template requires(not core::meta::IsConst) - constexpr auto normalize(const VectorSpan& a, VectorSpan out) noexcept - -> void; + constexpr auto normalize(const VectorSpan& a, VectorSpan out) noexcept -> void; template requires(not core::meta::IsConst) - constexpr auto transpose(const VectorSpan& a, VectorSpan out) noexcept - -> void; + constexpr auto transpose(const VectorSpan& a, VectorSpan out) noexcept -> void; template [[nodiscard]] - constexpr auto dot(const VectorSpan& a, const VectorSpan& b) noexcept - -> T; + constexpr auto dot(const VectorSpan& a, const VectorSpan& b) noexcept -> T; template requires(not core::meta::IsConst) - constexpr auto cross(const VectorSpan& a, - const VectorSpan& b, - VectorSpan out) noexcept -> void; + constexpr auto cross(const VectorSpan& a, const VectorSpan& b, VectorSpan out) noexcept -> void; /* matrix */ template @@ -140,8 +128,7 @@ export namespace stormkit { inline namespace core { namespace math { template requires(not core::meta::IsConst) - constexpr auto transpose(const SquareMatrixSpan& a, - SquareMatrixSpan out) noexcept -> void; + constexpr auto transpose(const SquareMatrixSpan& a, SquareMatrixSpan out) noexcept -> void; template [[nodiscard]] @@ -149,8 +136,7 @@ export namespace stormkit { inline namespace core { namespace math { template requires(not core::meta::IsConst) - constexpr auto inverse(const SquareMatrixSpan& a, - SquareMatrixSpan out) noexcept -> void; + constexpr auto inverse(const SquareMatrixSpan& a, SquareMatrixSpan out) noexcept -> void; template [[nodiscard]] @@ -158,9 +144,8 @@ export namespace stormkit { inline namespace core { namespace math { template requires(not core::meta::IsConst) - constexpr auto mul(const MatrixSpan& a, - const MatrixSpan& b, - MatrixSpan out) noexcept -> void; + constexpr auto mul(const MatrixSpan& a, const MatrixSpan& b, MatrixSpan out) noexcept + -> void; template requires(not core::meta::IsConst) @@ -188,29 +173,15 @@ export namespace stormkit { inline namespace core { namespace math { /* graphics */ template requires(std::is_signed_v and not core::meta::IsConst) - constexpr auto orthographique(T left, - T right, - T bottom, - T top, - T near, - T far, - SquareMatrixSpan out) noexcept -> void; + constexpr auto orthographique(T left, T right, T bottom, T top, T near, T far, SquareMatrixSpan out) noexcept -> void; template requires(std::is_signed_v and not core::meta::IsConst) - constexpr auto orthographique(T left, - T right, - T bottom, - T top, - SquareMatrixSpan out) noexcept -> void; + constexpr auto orthographique(T left, T right, T bottom, T top, SquareMatrixSpan out) noexcept -> void; template requires(std::is_signed_v and not core::meta::IsConst) - constexpr auto perspective(Radian fov_y, - T aspect, - T near, - T far, - SquareMatrixSpan out) noexcept -> void; + constexpr auto perspective(angle::radian fov_y, T aspect, T near, T far, SquareMatrixSpan out) noexcept -> void; template requires(std::is_signed_v and not core::meta::IsConst) @@ -227,39 +198,49 @@ export namespace stormkit { inline namespace core { namespace math { namespace stdr = std::ranges; namespace stormkit { inline namespace core { namespace math { + namespace angle { + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_PURE STORMKIT_FORCE_INLINE + constexpr auto radians(T degres) noexcept -> radian { + static constexpr auto one_rad = std::numbers::pi_v / T { 180 }; + return radian { degres * one_rad }; + } + } // namespace angle + template - using MatData = std::array; + using MatData = array; template using SMatData = MatData; template - using VecData = std::array; + using VecData = array; template - using Vec2Data = VecData; + using vec2data = VecData; template - using Vec3Data = VecData; + using vec3data = VecData; template - using Vec4Data = VecData; + using vec4data = VecData; // //////////////////////////////////////// // //////////////////////////////////////// // template // [[nodiscard]] // constexpr auto as_span(const TensorSpan& tensor) noexcept - // -> std::span { - // return std::span { tensor.data_handle(), (Sizes * ...) }; + // -> array_view { + // return array_view { tensor.data_handle(), (Sizes * ...) }; // } //////////////////////////////////////// //////////////////////////////////////// template [[nodiscard]] - constexpr auto as_span(const TensorSpan& tensor) noexcept - -> std::span { - return std::span { tensor.data_handle(), (Sizes * ...) }; + constexpr auto as_span(const TensorSpan& tensor) noexcept -> array_view { + return array_view { tensor.data_handle(), (Sizes * ...) }; } //////////////////////////////////////// @@ -267,9 +248,8 @@ namespace stormkit { inline namespace core { namespace math { template requires(not core::meta::IsConst) [[nodiscard]] - constexpr auto as_span_mut(TensorSpan tensor) noexcept - -> std::span { - return std::span { tensor.data_handle(), (Sizes * ...) }; + constexpr auto as_span_mut(TensorSpan tensor) noexcept -> array_view { + return array_view { tensor.data_handle(), (Sizes * ...) }; } //////////////////////////////////////// @@ -277,8 +257,7 @@ namespace stormkit { inline namespace core { namespace math { template requires(core::meta::IsArithmetic>) STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto as_mdspan(const T& data) noexcept - -> TensorSpan, Sizes...> { + constexpr auto as_mdspan(const T& data) noexcept -> TensorSpan, Sizes...> { EXPECTS(stdr::size(data) == (Sizes * ...)); return TensorSpan, Sizes...> { stdr::data(data), Sizes... }; } @@ -286,11 +265,9 @@ namespace stormkit { inline namespace core { namespace math { //////////////////////////////////////// //////////////////////////////////////// template - requires(core::meta::IsArithmetic> - and not core::meta::IsConst>) + requires(core::meta::IsArithmetic> and not core::meta::IsConst>) STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto as_mdspan_mut(T& data) noexcept - -> TensorSpan, Sizes...> { + constexpr auto as_mdspan_mut(T& data) noexcept -> TensorSpan, Sizes...> { EXPECTS(stdr::size(data) == (Sizes * ...)); return TensorSpan, Sizes...> { stdr::data(data), Sizes... }; } @@ -303,15 +280,6 @@ namespace stormkit { inline namespace core { namespace math { return To { data }; } - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto radians(T degres) noexcept -> Radian { - static constexpr auto one_rad = std::numbers::pi_v / T { 180 }; - return Radian { degres * one_rad }; - } - //////////////////////////////////////// //////////////////////////////////////// template @@ -349,9 +317,7 @@ namespace stormkit { inline namespace core { namespace math { template requires(not core::meta::IsConst) STORMKIT_FORCE_INLINE - constexpr auto mul(const TensorSpan& a, - T b, - TensorSpan out) noexcept -> void { + constexpr auto mul(const TensorSpan& a, T b, TensorSpan out) noexcept -> void { EXPECTS(a.data_handle() != out.data_handle()); const auto a_linear = as_span(a); auto out_linear = as_span_mut(out); @@ -363,9 +329,7 @@ namespace stormkit { inline namespace core { namespace math { template requires(not core::meta::IsConst) STORMKIT_FORCE_INLINE - constexpr auto div(const TensorSpan& a, - T b, - TensorSpan out) noexcept -> void { + constexpr auto div(const TensorSpan& a, T b, TensorSpan out) noexcept -> void { EXPECTS(a.data_handle() != out.data_handle()); const auto a_linear = as_span(a); auto out_linear = as_span_mut(out); @@ -377,8 +341,7 @@ namespace stormkit { inline namespace core { namespace math { template requires(not core::meta::IsConst) STORMKIT_FORCE_INLINE - constexpr auto normalize(const VectorSpan& a, VectorSpan out) noexcept - -> void { + constexpr auto normalize(const VectorSpan& a, VectorSpan out) noexcept -> void { EXPECTS(a.data_handle() != out.data_handle()); const auto sum = init_by([&a](auto& out) noexcept { for (auto i = 0u; i < N; ++i) out += (a[i] * a[i]); @@ -392,8 +355,7 @@ namespace stormkit { inline namespace core { namespace math { //////////////////////////////////////// template STORMKIT_PURE STORMKIT_FORCE_INLINE - constexpr auto dot(const VectorSpan& a, const VectorSpan& b) noexcept - -> T { + constexpr auto dot(const VectorSpan& a, const VectorSpan& b) noexcept -> T { auto out = T { 0 }; for (auto i = 0u; i < N; ++i) out += (a[i] * b[i]); return out; @@ -404,9 +366,8 @@ namespace stormkit { inline namespace core { namespace math { template requires(not core::meta::IsConst) STORMKIT_FORCE_INLINE - constexpr auto cross(const VectorSpan& a, - const VectorSpan& b, - VectorSpan out) noexcept -> void { + constexpr auto cross(const VectorSpan& a, const VectorSpan& b, VectorSpan out) noexcept + -> void { EXPECTS(a.data_handle() != out.data_handle()); EXPECTS(b.data_handle() != out.data_handle()); @@ -419,8 +380,7 @@ namespace stormkit { inline namespace core { namespace math { //////////////////////////////////////// template requires(not core::meta::IsConst) - constexpr auto cofactor(const SquareMatrixSpan& mat, - SquareMatrixSpan out) noexcept -> void { + constexpr auto cofactor(const SquareMatrixSpan& mat, SquareMatrixSpan out) noexcept -> void { static constexpr auto N = M - 1u; for (auto i = 0u; i < M; ++i) @@ -438,8 +398,7 @@ namespace stormkit { inline namespace core { namespace math { } }); - out[i, j] = narrow(std::pow(T { -1 }, i + j)) - * determinant(as_mdspan(submatrix)); + out[i, j] = narrow(std::pow(-1, i + j)) * determinant(as_mdspan(submatrix)); } } @@ -476,7 +435,7 @@ namespace stormkit { inline namespace core { namespace math { const auto det = determinant(as_mdspan(submatrix)); - result += mat[i, j] * narrow(std::pow(T { -1 }, i + j)) * det; + result += mat[i, j] * narrow(std::pow(-1, i + j)) * det; } return result; } @@ -487,8 +446,7 @@ namespace stormkit { inline namespace core { namespace math { template requires(not core::meta::IsConst) STORMKIT_FORCE_INLINE - constexpr auto transpose(const SquareMatrixSpan& a, - SquareMatrixSpan out) noexcept -> void { + constexpr auto transpose(const SquareMatrixSpan& a, SquareMatrixSpan out) noexcept -> void { EXPECTS(a.data_handle() != out.data_handle()); for (auto i = 0u; i < N; ++i) @@ -513,14 +471,11 @@ namespace stormkit { inline namespace core { namespace math { //////////////////////////////////////// template requires(not core::meta::IsConst) - constexpr auto inverse(const SquareMatrixSpan& a, - SquareMatrixSpan out) noexcept -> void { + constexpr auto inverse(const SquareMatrixSpan& a, SquareMatrixSpan out) noexcept -> void { EXPECTS(a.data_handle() != out.data_handle()); EXPECTS(is_inversible(a)); - const auto factor = init_by>([&a](auto& out) noexcept { - cofactor(a, as_mdspan_mut(out)); - }); + const auto factor = init_by>([&a](auto& out) noexcept { cofactor(a, as_mdspan_mut(out)); }); const auto transposed = init_by>([&factor](auto& out) noexcept { transpose(as_mdspan(factor), as_mdspan_mut(out)); @@ -531,9 +486,7 @@ namespace stormkit { inline namespace core { namespace math { const auto one_over_determinant = T { 1 } / determinant(a); for (auto i = 0u; i < N; ++i) - for (auto j = 0u; j < N; ++j) { - out[i, j] = transposed_mat[i, j] * one_over_determinant; - } + for (auto j = 0u; j < N; ++j) { out[i, j] = transposed_mat[i, j] * one_over_determinant; } } //////////////////////////////////////// @@ -571,13 +524,11 @@ namespace stormkit { inline namespace core { namespace math { template requires(not core::meta::IsConst) STORMKIT_FORCE_INLINE - constexpr auto mul(const MatrixSpan& a, - const MatrixSpan& b, - MatrixSpan out) noexcept -> void { - stdr::fill(as_span_mut(out), T { 0 }); + constexpr auto mul(const MatrixSpan& a, const MatrixSpan& b, MatrixSpan out) noexcept + -> void { for (auto i = 0u; i < M; ++i) for (auto j = 0u; j < K; ++j) - for (auto k = 0u; k < N; ++k) out[i, j] += a[i, k] * b[k, j]; + for (auto k = 0u; k < N; ++k) out[i, j] += a[i, k] * b[j, k]; } //////////////////////////////////////// @@ -591,9 +542,7 @@ namespace stormkit { inline namespace core { namespace math { EXPECTS(a.data_handle() != out.data_handle()); EXPECTS(b.data_handle() != out.data_handle()); - const auto inverted = init_by>([&b](auto& out) noexcept { - inverse(b, as_mdspan_mut(out)); - }); + const auto inverted = init_by>([&b](auto& out) noexcept { inverse(b, as_mdspan_mut(out)); }); mul(a, as_mdspan(inverted), out); } @@ -607,25 +556,13 @@ namespace stormkit { inline namespace core { namespace math { EXPECTS(a.data_handle() != out.data_handle()); EXPECTS(translation.data_handle() != out.data_handle()); - for (auto i = 0u; i < 3; ++i) - for (auto j = 0u; j < 3; ++j) out[i, j] = a[i, j]; - - out[3, 0] = a[0, 0] * translation[0] - + a[1, 0] * translation[1] - + a[2, 0] * translation[2] - + a[3, 0]; - out[3, 1] = a[0, 1] * translation[0] - + a[1, 1] * translation[1] - + a[2, 1] * translation[2] - + a[3, 1]; - out[3, 2] = a[0, 2] * translation[0] - + a[1, 2] * translation[1] - + a[2, 2] * translation[2] - + a[3, 2]; - out[3, 3] = a[0, 3] * translation[0] - + a[1, 3] * translation[1] - + a[2, 3] * translation[2] - + a[3, 3]; + out[0, 3] = a[0, 3] + + translation[0]; // a[0, 0] * translation[0] + a[1, 0] * translation[1] + a[2, 0] * translation[2] + a[3, 0]; + out[1, 3] = a[1, 3] + + translation[1]; // a[0, 1] * translation[0] + a[1, 1] * translation[1] + a[2, 1] * translation[2] + a[3, 1]; + out[2, 3] = a[2, 3] + + translation[2]; // a[0, 2] * translation[0] + a[1, 2] * translation[1] + a[2, 2] * translation[2] + a[3, 2]; + // out[3, 3] = a[0, 3] * translation[0] + a[1, 3] * translation[1] + a[2, 3] * translation[2] + a[3, 3]; } //////////////////////////////////////// @@ -638,23 +575,23 @@ namespace stormkit { inline namespace core { namespace math { EXPECTS(scale.data_handle() != out.data_handle()); out[0, 0] = a[0, 0] * scale[0]; - out[0, 1] = a[0, 1] * scale[0]; - out[0, 2] = a[0, 2] * scale[0]; - out[0, 3] = a[0, 3] * scale[0]; + out[1, 0] = a[1, 0] * scale[0]; + out[2, 0] = a[2, 0] * scale[0]; + out[3, 0] = a[3, 0] * scale[0]; - out[1, 0] = a[1, 0] * scale[1]; + out[0, 1] = a[0, 1] * scale[1]; out[1, 1] = a[1, 1] * scale[1]; - out[1, 2] = a[1, 2] * scale[1]; - out[1, 3] = a[1, 3] * scale[1]; + out[2, 1] = a[2, 1] * scale[1]; + out[3, 1] = a[3, 1] * scale[1]; - out[2, 0] = a[2, 0] * scale[2]; - out[2, 1] = a[2, 1] * scale[2]; + out[0, 2] = a[0, 2] * scale[2]; + out[1, 2] = a[1, 2] * scale[2]; out[2, 2] = a[2, 2] * scale[2]; - out[2, 3] = a[2, 3] * scale[2]; + out[3, 2] = a[3, 2] * scale[2]; - out[3, 0] = a[3, 0]; - out[3, 1] = a[3, 1]; - out[3, 2] = a[3, 2]; + out[0, 3] = a[0, 3]; + out[1, 3] = a[1, 3]; + out[2, 3] = a[2, 3]; out[3, 3] = a[3, 3]; } @@ -664,52 +601,49 @@ namespace stormkit { inline namespace core { namespace math { requires(std::is_signed_v and not core::meta::IsConst) STORMKIT_FORCE_INLINE constexpr auto rotate(const SquareMatrixSpan& a, - Radian angle, + angle::radian angle, const VectorSpan& axis, SquareMatrixSpan out) noexcept -> void { EXPECTS(a.data_handle() != out.data_handle()); EXPECTS(axis.data_handle() != out.data_handle()); - const auto cos = std::cos(angle.get()); - const auto sin = std::sin(angle.get()); + const auto cos = narrow(std::cos(angle.get())); + const auto sin = narrow(std::sin(angle.get())); const auto axis_norm = [&axis] noexcept { - auto axis_norm = Vec3Data {}; + auto axis_norm = vec3data {}; normalize(axis, as_mdspan_mut<3>(axis_norm)); return axis_norm; }(); - const auto temp = [&axis_norm, &cos] noexcept { - auto temp = Vec3Data {}; - mul(as_mdspan<3>(axis_norm), T { 1 } - cos, as_mdspan_mut<3>(temp)); - return temp; - }(); + const auto temp = + [&axis_norm, &cos] noexcept { + auto temp = vec3data {}; + mul(as_mdspan<3>(axis_norm), T { 1 } - cos, as_mdspan_mut<3>(temp)); + return temp; + } - auto rotation_matrix = SMatData {}; - stdr::fill(rotation_matrix, 0); + (); + + auto rotation_matrix = SMatData {}; auto rotation_matrix_ = as_mdspan_mut<4, 4>(rotation_matrix); rotation_matrix_[0, 0] = cos + temp[0] * axis_norm[0]; - rotation_matrix_[0, 1] = temp[0] * axis_norm[1] + sin * axis_norm[2]; - rotation_matrix_[0, 2] = temp[0] * axis_norm[2] - sin * axis_norm[1]; + rotation_matrix_[1, 0] = temp[0] * axis_norm[1] + sin * axis_norm[2]; + rotation_matrix_[2, 0] = temp[0] * axis_norm[2] - sin * axis_norm[1]; - rotation_matrix_[1, 0] = temp[1] * axis_norm[0] - sin * axis_norm[2]; + rotation_matrix_[0, 1] = temp[1] * axis_norm[0] - sin * axis_norm[2]; rotation_matrix_[1, 1] = cos + temp[1] * axis_norm[1]; - rotation_matrix_[1, 2] = temp[1] * axis_norm[2] + sin * axis_norm[0]; + rotation_matrix_[2, 1] = temp[1] * axis_norm[2] + sin * axis_norm[0]; - rotation_matrix_[2, 0] = temp[2] * axis_norm[0] + sin * axis_norm[1]; - rotation_matrix_[2, 1] = temp[2] * axis_norm[1] - sin * axis_norm[0]; + rotation_matrix_[0, 2] = temp[2] * axis_norm[0] + sin * axis_norm[1]; + rotation_matrix_[1, 2] = temp[2] * axis_norm[1] - sin * axis_norm[0]; rotation_matrix_[2, 2] = cos + temp[2] * axis_norm[2]; - // TODO replace by mul when submdspan is available + // // TODO replace by mul when submdspan is available for (auto i = 0u; i < 3; ++i) for (auto j = 0u; j < 3; ++j) - for (auto k = 0u; k < 3; ++k) out[i, j] += a[i, k] * rotation_matrix_[k, j]; - - out[3, 0] = a[3, 0]; - out[3, 1] = a[3, 1]; - out[3, 2] = a[3, 2]; - out[3, 3] = a[3, 3]; + for (auto k = 0u; k < 3; ++k) out[j, i] += a[k, i] * rotation_matrix_[j, k]; } //////////////////////////////////////// @@ -717,20 +651,14 @@ namespace stormkit { inline namespace core { namespace math { template requires(std::is_signed_v and not core::meta::IsConst) STORMKIT_FORCE_INLINE - constexpr auto orthographique(T left, - T right, - T bottom, - T top, - T near, - T far, - SquareMatrixSpan out) noexcept -> void { - (void)left; - (void)right; - (void)bottom; - (void)top; - (void)near; - (void)far; - (void)out; + constexpr auto orthographique(T left, T right, T bottom, T top, T near, T far, SquareMatrixSpan out) noexcept -> void { + out[0, 0] = core::as(2) / (right - left); + out[1, 1] = core::as(2) / (top - bottom); + out[2, 2] = core::as(1) / (far - near); + + out[0, 3] = -(right + left) / (right - left); + out[1, 3] = -(top + bottom) / (top - bottom); + out[2, 3] = -near / (far - near); } //////////////////////////////////////// @@ -738,16 +666,11 @@ namespace stormkit { inline namespace core { namespace math { template requires(std::is_signed_v and not core::meta::IsConst) STORMKIT_FORCE_INLINE - constexpr auto orthographique(T left, - T right, - T bottom, - T top, - SquareMatrixSpan out) noexcept -> void { - (void)left; - (void)right; - (void)bottom; - (void)top; - (void)out; + constexpr auto orthographique(T left, T right, T bottom, T top, SquareMatrixSpan out) noexcept -> void { + constexpr auto far = core::as(100); + constexpr auto near = core::narrow(0.1); + + return orthographique(left, right, bottom, top, near, far, out); } //////////////////////////////////////// @@ -755,15 +678,11 @@ namespace stormkit { inline namespace core { namespace math { template requires(std::is_signed_v and not core::meta::IsConst) STORMKIT_FORCE_INLINE - constexpr auto perspective(Radian fov_y, - T aspect, - T near, - T far, - SquareMatrixSpan out) noexcept -> void { + constexpr auto perspective(angle::radian fov_y, T aspect, T near, T far, SquareMatrixSpan out) noexcept -> void { EXPECTS(not is_equal(aspect, T { 0 })); EXPECTS(not is_equal(near, far)); - const auto half_fov_y = std::tan(fov_y.get() / T { 2 }); + const auto half_fov_y = narrow(std::tan(fov_y.get() / T { 2 })); stdr::fill(as_span_mut(out), T { 0 }); out[0, 0] = T { 1 } / (aspect * half_fov_y); @@ -786,24 +705,24 @@ namespace stormkit { inline namespace core { namespace math { EXPECTS(center.data_handle() != out.data_handle()); EXPECTS(up.data_handle() != out.data_handle()); - const auto z_temp = init_by>([&eye, ¢er](auto& out) noexcept { + const auto z_temp = init_by>([&eye, ¢er](auto& out) noexcept { sub(center, eye, as_mdspan_mut<3>(out)); }); - const auto z = init_by>([&z_temp](auto& out) noexcept { + const auto z = init_by>([&z_temp](auto& out) noexcept { normalize(as_mdspan<3>(z_temp), as_mdspan_mut<3>(out)); }); - const auto x_temp = init_by>([&up, &z](auto& out) noexcept { + const auto x_temp = init_by>([&up, &z](auto& out) noexcept { cross(up, as_mdspan<3>(z), as_mdspan_mut<3>(out)); }); - const auto x = init_by>([&x_temp](auto& out) noexcept { + const auto x = init_by>([&x_temp](auto& out) noexcept { normalize(as_mdspan<3>(x_temp), as_mdspan_mut<3>(out)); }); - const auto y_temp = init_by>([&z, &x](auto& out) noexcept { + const auto y_temp = init_by>([&z, &x](auto& out) noexcept { cross(as_mdspan<3>(z), as_mdspan<3>(x), as_mdspan_mut<3>(out)); }); - const auto y = init_by>([&y_temp](auto& out) noexcept { + const auto y = init_by>([&y_temp](auto& out) noexcept { normalize(as_mdspan<3>(y_temp), as_mdspan_mut<3>(out)); }); diff --git a/modules/stormkit/core/math/trigonometry.mpp b/modules/stormkit/core/math/trigonometry.cppm similarity index 100% rename from modules/stormkit/core/math/trigonometry.mpp rename to modules/stormkit/core/math/trigonometry.cppm diff --git a/modules/stormkit/core/meta.mpp b/modules/stormkit/core/meta.cppm similarity index 91% rename from modules/stormkit/core/meta.mpp rename to modules/stormkit/core/meta.cppm index 2d993429e..25353daf5 100644 --- a/modules/stormkit/core/meta.mpp +++ b/modules/stormkit/core/meta.cppm @@ -1,32 +1,32 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -export module stormkit.core:meta; - -export import :meta.algorithms; -export import :meta.concepts; -export import :meta.type_traits; -export import :meta.type_query; -export import :meta.type_manipulation; -export import :meta.priority_tag; - -export namespace stormkit { inline namespace core { - template - struct Overloaded: Ts... { - using Ts::operator()...; - }; - - template - Overloaded(Ts...) -> Overloaded; - - namespace meta { - template - consteval auto find_type_index_of() noexcept -> std::size_t { - static_assert(IsOneOf); - auto i = 0u; - ((not Is and ++i) and ...); - return i; - } - } // namespace meta -}} // namespace stormkit::core +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +export module stormkit.core:meta; + +export import :meta.algorithms; +export import :meta.concepts; +export import :meta.type_traits; +export import :meta.type_query; +export import :meta.type_manipulation; +export import :meta.priority_tag; + +export namespace stormkit { inline namespace core { + template + struct Overloaded: Ts... { + using Ts::operator()...; + }; + + template + Overloaded(Ts...) -> Overloaded; + + namespace meta { + template + consteval auto find_type_index_of() noexcept -> std::size_t { + static_assert(IsAnyOf); + auto i = 0u; + ((not Is and ++i) and ...); + return i; + } + } // namespace meta +}} // namespace stormkit::core diff --git a/modules/stormkit/core/meta/algorithms.cppm b/modules/stormkit/core/meta/algorithms.cppm new file mode 100644 index 000000000..8a3ef8848 --- /dev/null +++ b/modules/stormkit/core/meta/algorithms.cppm @@ -0,0 +1,93 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +export module stormkit.core:meta.algorithms; + +import std; + +import :meta.concepts; + +namespace stormkit { inline namespace core { namespace meta::details { + // template class Then, class Arg, class Else> + // struct LazyEvaluation final { + // using type = Else; + // }; + + // template class Then, class Arg, class Else> + // struct LazyEvaluation final { + // using type = Then; + // }; + + // /* + // LazyEvaluationType permet de choisir un type basé sur une condition sans instancier préventivement la branche 'Then'. + // Contrairement à std::conditional::type, qui force l'instanciation de A ET B même si Condition est + // fausse (pouvant causer des erreurs de compilation si une branche est invalide pour les types donnés), + // LazyEvaluationType n'instancie Then que si la condition est vraie. + // */ + // template class Then, class Arg, class Else> + // using LazyEvaluationType = typename LazyEvaluation::type; + + template + struct LazyType { + using Type = T; + }; + template typename, typename, typename> + struct If; + + template typename LazyType, typename Then, typename OrElse> + struct If { + using Type = LazyType::Type; + }; + + template typename LazyType, typename Then, typename OrElse> + struct If { + using Type = LazyType::Type; + }; +}}} // namespace stormkit::core::meta::details + +export namespace stormkit { inline namespace core { namespace meta { + template + using If = details::If::Type; + + template + using Select = std::conditional_t; + + template class Variant, typename... Ts> + constexpr auto variant_type_find_if(const Variant&, Predicate&& predicate) noexcept -> std::size_t; +}}} // namespace stormkit::core::meta + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit { inline namespace core { namespace meta { + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto variant_type_find_if_impl(Predicate&& predicate) noexcept -> std::size_t { + auto found = std::variant_npos; + [&](std::index_sequence) noexcept { + if constexpr ((requires { + { std::forward(predicate).template operator() } -> IsBooleanTestable; + } and ...)) + (((std::forward(predicate).template operator()()) and (found = Indices, true)) or ...); + else + static_assert(false, "Type not found"); + }(std::index_sequence_for()); + return found; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template class Variant, typename... Ts> + STORMKIT_FORCE_INLINE + constexpr auto variant_type_find_if(const Variant&, Predicate&& predicate) noexcept -> std::size_t { + return variant_type_find_if_impl(std::forward(predicate)); + } +}}} // namespace stormkit::core::meta diff --git a/modules/stormkit/core/meta/algorithms.mpp b/modules/stormkit/core/meta/algorithms.mpp deleted file mode 100644 index 46d5c9b19..000000000 --- a/modules/stormkit/core/meta/algorithms.mpp +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -export module stormkit.core:meta.algorithms; - -import std; - -import :meta.concepts; - -export namespace stormkit { inline namespace core { namespace meta { - template - using If = std::conditional_t; - - template - using Select = std::conditional_t; - - template class Variant, typename... Ts> - constexpr auto variant_type_find_if(const Variant&, Predicate&& predicate) noexcept - -> std::size_t; -}}} // namespace stormkit::core::meta - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit { inline namespace core { namespace meta { - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr auto variant_type_find_if_impl(Predicate&& predicate) noexcept -> std::size_t { - auto found = std::variant_npos; - [&](std::index_sequence) noexcept { - if constexpr ((requires { - { - std::forward(predicate) - .template operator() - } -> IsBooleanTestable; - } and ...)) - (((std::forward(predicate).template operator()()) - and (found = Indices, true)) - or ...); - else - static_assert(false, "Type not found"); - }(std::index_sequence_for()); - return found; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template class Variant, typename... Ts> - STORMKIT_FORCE_INLINE - constexpr auto variant_type_find_if(const Variant&, Predicate&& predicate) noexcept - -> std::size_t { - return variant_type_find_if_impl(std::forward(predicate)); - } -}}} // namespace stormkit::core::meta diff --git a/modules/stormkit/core/meta/concepts.mpp b/modules/stormkit/core/meta/concepts.cppm similarity index 64% rename from modules/stormkit/core/meta/concepts.mpp rename to modules/stormkit/core/meta/concepts.cppm index 7ea1f1dd7..667b3c38b 100644 --- a/modules/stormkit/core/meta/concepts.mpp +++ b/modules/stormkit/core/meta/concepts.cppm @@ -1,436 +1,449 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -export module stormkit.core:meta.concepts; - -import std; - -namespace stormkit { inline namespace core { namespace meta::details { - template - concept IsBooleanTestable = std::convertible_to; - - template class T, typename... Args> - constexpr auto is_specialization_of_helper(const T&) noexcept -> std::true_type { - return {}; - } - - template class T, typename T2, auto... Args> - constexpr auto is_specialization_of_with_nttp_helper(const T&) noexcept - -> std::true_type { - return {}; - } - - template class T, typename T1, auto... Args> - constexpr auto is_specialization_of_helper_nttp_tv(const T&) noexcept - -> std::true_type { - return {}; - } - - template typename T, typename T1, typename T2, auto... Args> - constexpr auto is_specialization_of_helper_nttp_ttv(const T&) noexcept - -> std::true_type { - return {}; - } -}}} // namespace stormkit::core::meta::details - -export namespace stormkit { inline namespace core { namespace meta { - template - concept IsStrict = std::same_as; - - template - concept Same = std::same_as; - - template - concept SameAs = std::same_as; - - template - concept DerivedFrom = std::derived_from; - - template - concept Is = SameAs or DerivedFrom; - - template - concept IsNot = not Is; - - // template concept C> - // concept Not = not C; - - // template concept... C> - // concept AllOf = (C and ...); - - // template concept... C> - // concept AnyOf = (C or ...); - - template - concept ConvertibleTo = std::convertible_to; - - template - concept IsConvertibleTo = std::convertible_to; - - template - concept IsHashable = requires(std::remove_cvref_t& a) { - std::hash> {}(a); - }; - - template - concept IsCanonical = IsStrict, std::remove_cvref_t>; - - template - concept PlainIs = Is, std::remove_cvref_t>; - - template - concept IsPlain = Is>; - - template - concept Are = (Is and ...); - - template - concept AnyOf = (Is or ...); - - template - concept IsOneOf = (Is or ...); - - template - concept SameAsOneOf = (SameAs or ...); - - template - concept IsByte = IsStrict; - - template - concept IsByteSized = sizeof(T) == sizeof(std::byte); - - template - concept IsNotByte = not IsByte; - - template - concept IsStringLike = std::convertible_to; - - template - concept IsRawPointer = std::is_pointer_v; - - template - concept IsNonOwningPointer = IsRawPointer or (requires { - typename T::element_type; - } and requires(T a) { - { a.operator->() } -> std::convertible_to; - { a.operator*() }; - { static_cast(a) }; - }); - - template - concept IsOwningPointer = IsNonOwningPointer and requires(T a) { - { a.reset() }; - }; - - template - concept IsPointer = IsNonOwningPointer or IsOwningPointer; - - template - concept IsNotPointer = not IsPointer; - - template - concept IsLValueReference = std::is_lvalue_reference_v; - - template - concept IsRValueReference = std::is_rvalue_reference_v; - - template - concept IsReference = IsLValueReference or IsRValueReference; - - template - concept IsNotReference = not IsReference; - - template - concept IsReferenceTo = IsReference and Is, U>; - - template - concept IsMovedOwningPointer = IsOwningPointer and IsRValueReference; - - template - concept IsViewPointer = (IsOwningPointer> - and not IsMovedOwningPointer) - or IsNonOwningPointer>; - - template - concept IsRawPointerOrLValueReference = IsRawPointer or IsLValueReference; - - template - concept IsIndirection = IsLValueReference or IsPointer; - - template - concept AreIndirections = ((IsLValueReference or IsPointer) && ...); - - template - concept IsPolymorphic = std::is_polymorphic_v; - - template - concept IsPolymorphicPointer = IsPointer - and IsPolymorphic::element_type>; - - template - concept IsPolymorphicReference = IsReference and IsPolymorphic>; - - template - concept IsPolymorphicIndirection = IsPolymorphicReference or IsPolymorphicPointer; - - template - concept IsRawIndirection = IsLValueReference or IsRawPointer; - - template - concept IsNotRawIndirection = not IsRawIndirection; - - template - concept IsNotIndirection = not IsIndirection; - - template - concept IsScopedEnumeration = std::is_scoped_enum_v and IsNotByte; - - template - concept IsPlainEnumeration = not IsScopedEnumeration and std::is_enum_v and IsNotByte; - - template - concept IsEnumeration = std::is_enum_v and IsNotByte; - - template - concept IsIntegral - = (std::integral and not IsStrict and not IsByte) - or Is>> - or Is>> -#if defined(STORMKIT_COMPILER_MSVC) - or Is - or Is; -#else - or Is - or Is; -#endif - - template - concept IsIntegralOrEnumeration = IsIntegral or IsEnumeration; - - template - concept IsFloatingPoint = std::floating_point; - - template - concept IsArithmetic = (IsIntegral or IsFloatingPoint) - and not IsPointer - and not IsEnumeration; - - template - concept IsScalar = IsArithmetic or IsPointer or IsEnumeration; - - template - concept IsPreIncrementable = requires(T& a) { a.operator--(); }; - - template - concept IsBooleanTestable = details::IsBooleanTestable && requires(T&& t) { - { not std::forward(t) } -> details::IsBooleanTestable; - }; - - template - concept IsContainedSemantics = requires(T& val) { - typename T::value_type; - { val.operator*() } -> IsReferenceTo; - }; - - template class T> - concept IsSpecializationOf = requires(S&& s) { - { details::is_specialization_of_helper(std::forward(s)) } -> IsStrict; - }; - - template typename T> - concept IsSpecializationOfNTTP_TV = requires(S&& s) { - { - details::is_specialization_of_helper_nttp_tv(std::forward(s)) - } -> IsStrict; - }; - - template typename T> - concept IsSpecializationOfNTTP_TTV = requires(S&& s) { - { - details::is_specialization_of_helper_nttp_ttv(std::forward(s)) - } -> IsStrict; - }; - - template class T> - concept IsSpecializationWithNTTPOf = requires(S&& s) { - { - details::is_specialization_of_with_nttp_helper(std::forward(s)) - } -> IsStrict; - }; - - template - concept IsOptionalType = IsSpecializationOf; - - template - concept IsExpectedType = IsSpecializationOf; - - template - concept IsVariantType = IsSpecializationOf; - - template - concept IsMdspanType = IsSpecializationOf; - - template - concept IsArrayType = IsSpecializationWithNTTPOf; - - template - concept IsPredicate = std::predicate; - - template - concept IsUnaryPredicate = IsPredicate; - - template - concept IsBinaryPredicate = IsPredicate; - - template - concept IsHashFunc = std::regular_invocable - and std::convertible_to, std::uint64_t>; - - // doesn't work atm - template - concept IsFormattable = true; // requires(std::formatter f, T val) { f.format("{}", - // val); }; - - template - concept IsCharacter - = IsOneOf; - - template - concept IsCharType = IsOneOf; - - template - concept IsColorComponent = Is or Is; - - template - concept IsConst = std::is_const_v; - - template - concept IsVolatile = std::is_volatile_v; - - template - concept IsNotConst = not IsConst; - - template - concept IsBraceInitializableTo = requires(From&& from) { To { std::forward(from) }; }; - - template - concept IsConvertibleToOneOf = (IsConvertibleTo or ...); - - template - concept IsExplicitConvertibleTo = IsConvertibleTo or requires(From&& from) { - { static_cast(std::forward(from)) } -> Is; - }; - - template - concept IsUnsigned = std::is_unsigned_v -#if defined(STORMKIT_COMPILER_MSVC) - or Is; -#else - or Is; -#endif - - template - concept IsSigned = std::is_signed_v -#if defined(STORMKIT_COMPILER_MSVC) - or Is; -#else - or Is; -#endif - - template - concept IsSameSigneness = (IsSigned and IsSigned) or (IsUnsigned and IsUnsigned); - - template - concept IsSignNarrowing = (IsSigned ? not IsSigned - : IsSigned and sizeof(From) == sizeof(To)); - - template - concept IsByteNarrowing = ((IsArithmetic and IsByte) - or (IsByte and IsArithmetic)) - and (IsByte and sizeof(To) != sizeof(From)); - - template - concept IsNarrowing = (IsFloatingPoint and IsIntegral) - or (IsFloatingPoint - and IsFloatingPoint - and sizeof(From) > sizeof(To)) - or (IsIntegralOrEnumeration and IsFloatingPoint) - or (IsIntegral - and IsIntegral - and (sizeof(From) > sizeof(To) or IsSignNarrowing)) - or (IsEnumeration - and IsIntegral - and (sizeof(From) > sizeof(To) - or IsSignNarrowing, From>)) - or (IsPointer and Is); - - template - concept IsUnsafePointerConvertion = IsPointer - and IsPointer - and not requires(To to, From from) { to = from; }; - - template - concept IsSafeNarrowing = IsArithmetic - and IsArithmetic - and not is_safe_narrowing(from); - - template - concept HasEqualityOperator = requires(const T1& first, const T2& second) { - { first == second } -> IsBooleanTestable; - }; - - static_assert(HasEqualityOperator); - - template - concept EnableCtor = sizeof...(Args) != 1 - || (sizeof...(Args) == 1 - && !Is::type>); - - template - concept IsNoexceptDefaultConstructible = std::is_nothrow_default_constructible_v; - - template - concept IsNoexceptConstructible = std::is_nothrow_constructible_v; - - template - concept IsNoexceptCopyConstructible = std::is_nothrow_copy_constructible_v; - - template - concept IsNoexceptMoveConstructible = std::is_nothrow_move_constructible_v; - - template - concept IsNoexceptCopyAssignable = std::is_nothrow_copy_assignable_v; - - template - concept IsNoexceptMoveAssignable = std::is_nothrow_move_assignable_v; - - template - concept IsNoexceptAssignable = std::is_nothrow_assignable_v; - - template - concept IsNoexceptDestructible = std::is_nothrow_destructible_v; - - template - concept IsDefaultConstructible = std::is_default_constructible_v; - - template - concept IsConstructible = std::is_constructible_v; - - template - concept IsCopyConstructible = std::is_copy_constructible_v; - - template - concept IsMoveConstructible = std::is_move_constructible_v; - - template - concept IsCopyAssignable = std::is_copy_assignable_v; - - template - concept IsMoveAssignable = std::is_move_assignable_v; - - template - concept IsAssignable = std::is_assignable_v; -}}} // namespace stormkit::core::meta +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +export module stormkit.core:meta.concepts; + +import std; + +#if defined(STORMKIT_COMPILER_MSVC) +using int128 = std::__Signed128; +using uint128 = std::__Unsigned128; +#else +__extension__ using int128 = __int128; +__extension__ using uint128 = unsigned __int128; +#endif + +namespace stormkit { inline namespace core { namespace meta::details { + template + concept IsBooleanTestable = std::convertible_to; + + template class T, typename... Args> + constexpr auto is_specialization_of_helper(const T&) noexcept -> std::true_type { + return {}; + } + + template class T, typename T2, auto... Args> + constexpr auto is_specialization_of_with_nttp_helper(const T&) noexcept -> std::true_type { + return {}; + } + + template class T, typename T1, auto... Args> + constexpr auto is_specialization_of_helper_nttp_tv(const T&) noexcept -> std::true_type { + return {}; + } + + template typename T, typename T1, typename T2, auto... Args> + constexpr auto is_specialization_of_helper_nttp_ttv(const T&) noexcept -> std::true_type { + return {}; + } + + template typename T, typename T1, typename T2, auto Arg, typename... Ts> + constexpr auto is_specialization_of_helper_nttp_ttvts(const T&) noexcept -> std::true_type { + return {}; + } +}}} // namespace stormkit::core::meta::details + +export namespace stormkit { inline namespace core { namespace meta { + template + concept SameAs = std::same_as; + + template + concept DerivedFrom = std::derived_from; + + template + concept Is = SameAs or DerivedFrom; + + template + concept IsNot = not Is; + + // template concept C> + // concept Not = not C; + + // template concept... C> + // concept AllOf = (C and ...); + + // template concept... C> + // concept AnyOf = (C or ...); + + template + concept IsBooleanTestable = details::IsBooleanTestable && requires(T&& t) { + { not std::forward(t) } -> details::IsBooleanTestable; + }; + + template class T> + concept IsSpecializationOf = requires(S&& s) { + { details::is_specialization_of_helper(std::forward(s)) } -> SameAs; + }; + + template typename T> + concept IsSpecializationOfNTTP_TV = requires(S&& s) { + { details::is_specialization_of_helper_nttp_tv(std::forward(s)) } -> SameAs; + }; + + template typename T> + concept IsSpecializationOfNTTP_TTV = requires(S&& s) { + { details::is_specialization_of_helper_nttp_ttv(std::forward(s)) } -> SameAs; + }; + + template typename T> + concept IsSpecializationOfNTTP_TTVTs = requires(S&& s) { + { details::is_specialization_of_helper_nttp_ttvts(std::forward(s)) } -> SameAs; + }; + + template class T> + concept IsSpecializationWithNTTPOf = requires(S&& s) { + { details::is_specialization_of_with_nttp_helper(std::forward(s)) } -> SameAs; + }; + + template + concept ConvertibleTo = std::convertible_to; + + template + concept IsConvertibleTo = std::convertible_to; + + template + concept HasStdHashSpecialization = requires(T&& a) { std::hash> {}(std::forward(a)); }; + + template + concept IsCanonical = SameAs, std::remove_cvref_t>; + + template + concept PlainIs = Is, std::remove_cvref_t>; + + template + concept IsPlain = Is>; + + template + concept Are = (Is and ...); + + template + concept IsAnyOf = (Is or ...); + + template + concept SameAsAnyOf = (SameAs or ...); + + template + concept Isbyte = SameAs; + + template + concept IsbyteSized = sizeof(T) == sizeof(std::byte); + + template + concept IsNotbyte = not Isbyte; + + template + concept IsStringLike = std::convertible_to; + + template + concept IsStdOptional = IsSpecializationOf; + + template + concept IsStdExpected = IsSpecializationOf; + + template + concept IsStdVariant = IsSpecializationOf; + + template + concept IsStdSpan = IsSpecializationOfNTTP_TV; + + template + concept IsStdMdspan = IsSpecializationOf; + + template + concept IsStdArray = IsSpecializationWithNTTPOf; + + template + concept IsStdReferenceWrapper = IsSpecializationOf; + + template + concept IsLValueReference = std::is_lvalue_reference_v; + + template + concept IsRValueReference = std::is_rvalue_reference_v; + + template + concept IsReference = IsLValueReference or IsRValueReference; + + template + concept IsNotReference = not IsReference; + + template + concept IsReferenceTo = IsReference and Is, U>; + + template + concept IsRawPointer = std::is_pointer_v; + + template + concept IsNonOwningPointer = IsRawPointer or (requires { + typename std::pointer_traits::element_type; + } and requires(T a) { + { a.operator->() } -> std::convertible_to; + { a.operator*() }; + { a == nullptr } -> IsBooleanTestable; + }) or IsStdReferenceWrapper; + + template + concept IsOwningPointer = IsNonOwningPointer and requires(T a) { + { a.reset() }; + }; + + template + concept IsPointer = IsNonOwningPointer or IsOwningPointer; + + template + concept IsNotPointer = not IsPointer; + + template + concept IsPointerOf = IsPointer and SameAs::element_type, U>; + + template + concept IsMovedOwningPointer = IsOwningPointer and IsRValueReference; + + template + concept IsViewPointer = (IsOwningPointer> and not IsMovedOwningPointer) + or IsNonOwningPointer>; + + template + concept IsRawPointerOrLValueReference = IsRawPointer or IsLValueReference; + + template + concept IsIndirection = IsLValueReference or IsPointer; + + template + concept IsIndirectionTo = IsIndirection and SameAs>, U>; + + template + concept AreIndirections = ((IsLValueReference or IsPointer) and ...); + + template + concept HasElementType = requires() { typename T::ElementType; } or requires() { typename T::element_type; }; + + template + concept HasValueType = requires() { typename T::ValueType; } or requires() { typename T::value_type; }; + + template + concept HasExpectedType = requires() { typename T::ExpectedType; } and IsStdExpected; + + template + concept IsContainer = HasValueType and requires(T& val) { + { val.operator*() } -> IsReferenceTo; + { val.operator->() } -> IsReferenceTo; + }; + + template + concept IsContainerOf = IsContainer and SameAs; + + template + concept IsContainerOrPointer = IsContainer or IsPointer; + + template + concept IsContainerOrPointerOf = IsContainerOf or IsPointerOf; + + template + concept IsContainerOrIndirection = IsContainer or IsIndirection; + + template + concept IsContainerOrIndirectionOf = IsContainerOf or IsIndirectionTo; + + template + concept IsPolymorphic = std::is_polymorphic_v; + + template + concept IsPolymorphicPointer = IsPointer and IsPolymorphic::element_type>; + + template + concept IsPolymorphicReference = IsReference and IsPolymorphic>; + + template + concept IsPolymorphicIndirection = IsPolymorphicReference or IsPolymorphicPointer; + + template + concept IsRawIndirection = IsLValueReference or IsRawPointer; + + template + concept IsNotRawIndirection = not IsRawIndirection; + + template + concept IsNotIndirection = not IsIndirection; + + template + concept IsScopedEnumeration = std::is_scoped_enum_v and IsNotbyte; + + template + concept IsPlainEnumeration = not IsScopedEnumeration and std::is_enum_v and IsNotbyte; + + template + concept IsEnumeration = std::is_enum_v and IsNotbyte; + + template + concept IsIntegral = (std::integral and not SameAs and not Isbyte) + or Is>> + or Is>> + or Is + or Is; + + template + concept IsIntegralOrEnumeration = IsIntegral or IsEnumeration; + + template + concept IsFloatingPoint = std::floating_point; + + template + concept IsArithmetic = (IsIntegral or IsFloatingPoint) and not IsPointer and not IsEnumeration; + + template + concept IsScalar = IsArithmetic or IsPointer or IsEnumeration; + + template + concept IsPreIncrementable = requires(T& a) { a.operator--(); }; + + template + concept IsPredicate = std::predicate; + + template + concept IsUnaryPredicate = IsPredicate; + + template + concept IsBinaryPredicate = IsPredicate; + + template + concept IsHashFunc = std::regular_invocable and std::convertible_to, std::uint64_t>; + + // doesn't work atm + template + concept IsFormattable = true; // requires(std::formatter f, T val) { f.format("{}", + // val); }; + + template + concept IsCharacter = IsAnyOf; + + template + concept IsCharType = IsAnyOf; + + template + concept IsColorComponent = IsAnyOf< + T, + float, + std::uint8_t +#ifdef __STDCPP_FLOAT32_T__ + , + std::float32_t +#endif +#ifdef __STDCPP_FLOAT64_T__ + , + std::float64_t +#endif + >; + + template + concept IsConst = std::is_const_v; + + template + concept IsNotConst = not IsConst; + + template + concept IsVolatile = std::is_volatile_v; + + template + concept IsBraceInitializableTo = requires(From&& from) { To { std::forward(from) }; }; + + template + concept IsConvertibleToOneOf = (IsConvertibleTo or ...); + + template + concept IsExplicitConvertibleTo = IsConvertibleTo or requires(From&& from) { + { static_cast(std::forward(from)) } -> Is; + }; + + template + concept IsUnsigned = std::is_unsigned_v or Is; + + template + concept IsSigned = std::is_signed_v or Is; + + template + concept IsSameSigneness = (IsSigned and IsSigned) or (IsUnsigned and IsUnsigned); + + template + concept IsSignNarrowing = (IsSigned ? not IsSigned : IsSigned and sizeof(From) == sizeof(To)); + + template + concept IsbyteNarrowing = ((IsArithmetic and Isbyte) or (Isbyte and IsArithmetic)) + and (Isbyte and sizeof(To) != sizeof(From)); + + template + concept IsNarrowing = (IsFloatingPoint and IsIntegral) + or (IsFloatingPoint and IsFloatingPoint and sizeof(From) > sizeof(To)) + or (IsIntegralOrEnumeration and IsFloatingPoint) + or (IsIntegral and IsIntegral and (sizeof(From) > sizeof(To) or IsSignNarrowing)) + or (IsEnumeration + and IsIntegral + and (sizeof(From) > sizeof(To) or IsSignNarrowing, From>)) + or (IsPointer and Is); + + template + concept IsUnsafePointerConvertion = IsPointer and IsPointer and not requires(To to, From from) { to = from; }; + + template + concept IsSafeNarrowing = IsArithmetic and IsArithmetic and not is_safe_narrowing(from); + + template + concept HasEqualityOperator = requires(const T1& first, const T2& second) { + { first == second } -> IsBooleanTestable; + }; + + static_assert(HasEqualityOperator); + + template + concept EnableCtor = sizeof...(Args) != 1 || (sizeof...(Args) == 1 && !Is::type>); + + template + concept IsNoexceptDefaultConstructible = std::is_nothrow_default_constructible_v; + + template + concept IsNoexceptConstructible = std::is_nothrow_constructible_v; + + template + concept IsNoexceptCopyConstructible = std::is_nothrow_copy_constructible_v; + + template + concept IsNoexceptMoveConstructible = std::is_nothrow_move_constructible_v; + + template + concept IsNoexceptCopyAssignable = std::is_nothrow_copy_assignable_v; + + template + concept IsNoexceptMoveAssignable = std::is_nothrow_move_assignable_v; + + template + concept IsNoexceptAssignable = std::is_nothrow_assignable_v; + + template + concept IsNoexceptDestructible = std::is_nothrow_destructible_v; + + template + concept IsDefaultConstructible = std::is_default_constructible_v; + + template + concept IsConstructible = std::is_constructible_v; + + template + concept IsCopyConstructible = std::is_copy_constructible_v; + + template + concept IsMoveConstructible = std::is_move_constructible_v; + + template + concept IsCopyAssignable = std::is_copy_assignable_v; + + template + concept IsMoveAssignable = std::is_move_assignable_v; + + template + concept IsAssignable = std::is_assignable_v; +}}} // namespace stormkit::core::meta diff --git a/modules/stormkit/core/meta/priority_tag.mpp b/modules/stormkit/core/meta/priority_tag.cppm similarity index 100% rename from modules/stormkit/core/meta/priority_tag.mpp rename to modules/stormkit/core/meta/priority_tag.cppm diff --git a/modules/stormkit/core/meta/type_manipulation.mpp b/modules/stormkit/core/meta/type_manipulation.cppm similarity index 96% rename from modules/stormkit/core/meta/type_manipulation.mpp rename to modules/stormkit/core/meta/type_manipulation.cppm index d5e0f0247..df561b105 100644 --- a/modules/stormkit/core/meta/type_manipulation.mpp +++ b/modules/stormkit/core/meta/type_manipulation.cppm @@ -32,6 +32,9 @@ namespace stormkit { inline namespace core { namespace meta { template using AddConst = std::add_const_t; + template + using AddConstIf = If, T>; + template using AddVolatile = std::add_volatile_t; diff --git a/modules/stormkit/core/meta/type_query.cppm b/modules/stormkit/core/meta/type_query.cppm new file mode 100644 index 000000000..3e706ec9b --- /dev/null +++ b/modules/stormkit/core/meta/type_query.cppm @@ -0,0 +1,293 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +export module stormkit.core:meta.type_query; + +import std; + +import :meta.concepts; +import :meta.type_manipulation; + +namespace stdr = std::ranges; + +namespace stormkit { inline namespace core { namespace meta { + namespace details { + template + struct AlwaysTrue: std::false_type {}; + + template + struct AlwaysFalse: std::false_type {}; + + template + struct UnderlyingType; + + template + struct PointerType; + + template + struct PointerType { + using Type = typename std::pointer_traits::pointer; + }; + + template + struct PointerType> { + using Type = std::reference_wrapper::type*; + }; + + template + struct PointedType; + + template + struct PointedType { + using Type = typename std::pointer_traits::element_type; + }; + + template + struct PointedType> { + using Type = std::reference_wrapper::type; + }; + + template + struct ContainedType; + + template + struct ContainedType { + using Type = typename T::value_type; + }; + + template + struct ContainedType { + using Type = typename T::value_type; + }; + + template + struct ContainedOrPointedOrTType { + using Type = T; + }; + + template + struct ContainedOrPointedOrTType: ContainedType {}; + + template + struct ContainedOrPointedOrTType: PointedType {}; + + template + struct ContainedOrPointedType; + + template + struct ContainedOrPointedType: ContainedType {}; + + template + struct ContainedOrPointedType: PointedType {}; + + template + struct CallableTrait; + + template + struct SignatureTrait { + using ReturnType = Return; + // using ArgumentsTypes = std::tuple; + }; + + template + struct CallableTrait: SignatureTrait {}; + + template + struct CallableTrait: SignatureTrait {}; + + template + struct CallableTrait: CallableTrait {}; + + template + struct CallableTrait: CallableTrait {}; + + template + struct CallableTrait: CallableTrait {}; + + template + struct CallableTrait: CallableTrait {}; + + template + struct CallableTrait: CallableTrait {}; + + template + struct CallableTrait: CallableTrait {}; + + template + struct CallableTrait: CallableTrait {}; + + template + struct CallableTrait: CallableTrait {}; + + template + struct CallableTrait: CallableTrait {}; + + template + struct CallableTrait: CallableTrait {}; + + template + struct CallableTrait: CallableTrait {}; + + template + struct CallableTrait: CallableTrait {}; + + template + struct CallableTrait: CallableTrait {}; + + template + struct CallableTrait: CallableTrait {}; + + template + concept HasStdValueType = requires() { typename T::value_type; }; + + template + concept HasValueType = requires() { typename T::ValueType; }; + + template + struct ValueType; + + template + struct ValueType { + using Type = typename T::ValueType; + }; + + template + requires(not HasValueType) + struct ValueType { + using Type = typename T::value_type; + }; + + template + concept HasStdElementType = requires() { typename T::element_type; }; + + template + concept HasElementType = requires() { typename T::ElementType; }; + + template + struct ElementType; + + template + struct ElementType { + using Type = typename T::ElementType; + }; + + template + requires(not HasElementType) + struct ElementType { + using Type = typename T::element_type; + }; + } // namespace details + + export { + template + using UnderlyingType = std::underlying_type_t; + + template + using PointerType = details::PointerType::Type; + + template + using PointedType = details::PointedType::Type; + + template + using ContainedType = details::ContainedType::Type; + + template + using ContainedOrPointedType = details::ContainedOrPointedType::Type; + + template + using ContainedOrPointedOrTType = details::ContainedOrPointedOrTType::Type; + + template + using ReturnType = details::CallableTrait::ReturnType; + + template + using ExpectedType = typename T::ExpectedType; + + template + using ElementType = details::ElementType::Type; + + template + using ValueType = details::ValueType::Type; + + template + using IteratorType = stdr::iterator_t; + + template + using SentinelType = stdr::sentinel_t; + + template + using RangeType = RemoveReferencesType>; + + template + constexpr auto is_greater() noexcept; + + template + using SafeNarrowHelperType = Select(), T, V>; + + template + using SafeNarrowHelperOtherType = Select(), V, T>; + + template + using ArithmeticOrderingType = Select, std::strong_ordering, std::partial_ordering>; + + template + constexpr auto enumerate() noexcept -> decltype(auto) = delete; + + template + consteval auto name_of() noexcept -> std::string_view; + } +}}} // namespace stormkit::core::meta + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit { inline namespace core { namespace meta { + //////////////////////////////////////// + //////////////////////////////////////// + template + constexpr auto is_greater() noexcept { + using Type = decltype(T {} + V {}); + + return static_cast(std::numeric_limits::max()) > static_cast(std::numeric_limits::max()); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + consteval auto name_of() noexcept -> std::string_view { +#if defined(STORMKIT_COMPILER_GCC) + constexpr auto prefix = std::string_view { " [with T = " }; + constexpr auto suffix = std::string_view { "]" }; + constexpr auto function = std::string_view { __PRETTY_FUNCTION__ }; +#elif defined(STORMKIT_COMPILER_CLANG) + constexpr auto prefix = std::string_view { " [T = " }; + constexpr auto suffix = std::string_view { "]" }; + constexpr auto function = std::string_view { __PRETTY_FUNCTION__ }; +#elif defined(STORMKIT_COMPILER_MSVC) + constexpr auto prefix = std::string_view { "<" }; + constexpr auto suffix = std::string_view { ">(void)" }; + constexpr auto function = std::string_view { __FUNCSIG__ }; +#else + #error Unsupported compiler +#endif + static_assert(not function.empty()); + + constexpr auto start = function.find(prefix) + prefix.size(); + constexpr auto end = function.rfind(suffix); + + static_assert(start < end); + + constexpr auto name = function.substr(start, (end - start)); + static constexpr auto res = [](std::string_view str, std::index_sequence) { + return std::array { str[Idxs]... }; + }(name, std::make_index_sequence {}); + + return std::string_view { res.data(), res.size() }; + } +}}} // namespace stormkit::core::meta diff --git a/modules/stormkit/core/meta/type_query.mpp b/modules/stormkit/core/meta/type_query.mpp deleted file mode 100644 index 8c8e3379a..000000000 --- a/modules/stormkit/core/meta/type_query.mpp +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -export module stormkit.core:meta.type_query; - -import std; - -import :meta.concepts; -import :meta.type_manipulation; - -namespace stdr = std::ranges; - -namespace stormkit { inline namespace core { namespace meta { - namespace details { - template - struct AlwaysTrue: std::false_type {}; - - template - struct AlwaysFalse: std::false_type {}; - - template - struct UnderlyingType; - - template - concept HasValueType = requires() { typename T::ValueType; }; - - template - concept HasStdValueType = requires() { typename T::value_type; }; - - template - struct UnderlyingType { - using Type = typename T::ValueType; - }; - - template - requires(not HasValueType) - struct UnderlyingType { - using Type = typename T::value_type; - }; - - template - struct UnderlyingType { - using Type = std::underlying_type_t; - }; - } // namespace details - - export { - template - using ElementType = typename std::pointer_traits::element_type; - - template - using PointerType = typename std::pointer_traits::pointer; - - template - using IteratorType = stdr::iterator_t; - - template - using SentinelType = stdr::sentinel_t; - - template - using RangeType = RemoveReferencesType>; - - template - constexpr auto is_greater() noexcept; - - template - using SafeNarrowHelperType = Select(), T, V>; - - template - using SafeNarrowHelperOtherType = Select(), V, T>; - - template - using UnderlyingType = details::UnderlyingType::Type; - - template - using ArithmeticOrderingType = Select, - std::strong_ordering, - std::weak_ordering>; - - template - constexpr auto enumerate() noexcept -> decltype(auto) = delete; - - template - consteval auto name_of() noexcept -> std::string_view; - } -}}} // namespace stormkit::core::meta - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit { inline namespace core { namespace meta { - //////////////////////////////////////// - //////////////////////////////////////// - template - constexpr auto is_greater() noexcept { - using Type = decltype(T {} + V {}); - - return static_cast(std::numeric_limits::max()) - > static_cast(std::numeric_limits::max()); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - consteval auto name_of() noexcept -> std::string_view { -#if defined(STORMKIT_COMPILER_GCC) - constexpr auto prefix = std::string_view { " [with T = " }; - constexpr auto suffix = std::string_view { "]" }; - constexpr auto function = std::string_view { __PRETTY_FUNCTION__ }; -#elif defined(STORMKIT_COMPILER_CLANG) - constexpr auto prefix = std::string_view { " [T = " }; - constexpr auto suffix = std::string_view { "]" }; - constexpr auto function = std::string_view { __PRETTY_FUNCTION__ }; -#elif defined(STORMKIT_COMPILER_MSVC) - constexpr auto prefix = std::string_view { "<" }; - constexpr auto suffix = std::string_view { ">(void)" }; - constexpr auto function = std::string_view { __FUNCSIG__ }; -#else - #error Unsupported compiler -#endif - static_assert(not function.empty()); - - constexpr auto start = function.find(prefix) + prefix.size(); - constexpr auto end = function.rfind(suffix); - - static_assert(start < end); - - constexpr auto name = function.substr(start, (end - start)); - static constexpr auto res = - [](std::string_view str, std::index_sequence) { - return std::array { str[Idxs]... }; - }(name, std::make_index_sequence {}); - - return std::string_view { res.data(), res.size() }; - } -}}} // namespace stormkit::core::meta diff --git a/modules/stormkit/core/meta/type_traits.mpp b/modules/stormkit/core/meta/type_traits.cppm similarity index 90% rename from modules/stormkit/core/meta/type_traits.mpp rename to modules/stormkit/core/meta/type_traits.cppm index 2fb10d879..5a46eabf5 100644 --- a/modules/stormkit/core/meta/type_traits.mpp +++ b/modules/stormkit/core/meta/type_traits.cppm @@ -26,42 +26,42 @@ import :meta.type_query; // struct ArithmeticTraitInterface { // template // static auto add(Ts...) noexcept -> decltype(auto) { -// static_assert(false, std::string { "add not implemented for " } + name_of()); +// static_assert(false, string { "add not implemented for " } + name_of()); // } // template // static auto add_eq(Ts...) noexcept -> decltype(auto) { -// static_assert(false, std::string { "add_eq not implemented for " } + name_of()); +// static_assert(false, string { "add_eq not implemented for " } + name_of()); // } // template // static auto sub(Ts...) noexcept -> decltype(auto) { -// static_assert(false, std::string { "sub not implemented for " } + name_of()); +// static_assert(false, string { "sub not implemented for " } + name_of()); // } // template // static auto sub_eq(Ts...) noexcept -> decltype(auto) { -// static_assert(false, std::string { "sub_eq not implemented for " } + name_of()); +// static_assert(false, string { "sub_eq not implemented for " } + name_of()); // } // template // static auto div(Ts...) noexcept -> decltype(auto) { -// static_assert(false, std::string { "div not implemented for " } + name_of()); +// static_assert(false, string { "div not implemented for " } + name_of()); // } // template // static auto div_eq(Ts...) noexcept -> decltype(auto) { -// static_assert(false, std::string { "div_eq not implemented for " } + name_of()); +// static_assert(false, string { "div_eq not implemented for " } + name_of()); // } // template // static auto mul(Ts...) noexcept -> decltype(auto) { -// static_assert(false, std::string { "mul not implemented for " } + name_of()); +// static_assert(false, string { "mul not implemented for " } + name_of()); // } // template // static auto mul_eq(Ts...) noexcept -> decltype(auto) { -// static_assert(false, std::string { "mul_eq not implemented for " } + name_of()); +// static_assert(false, string { "mul_eq not implemented for " } + name_of()); // } // }; diff --git a/modules/stormkit/core/named_constructors.cppm b/modules/stormkit/core/named_constructors.cppm new file mode 100644 index 000000000..f4efb627f --- /dev/null +++ b/modules/stormkit/core/named_constructors.cppm @@ -0,0 +1,296 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include + +export module stormkit.core:named_constructors; + +import std; + +import :meta; +import :utils.allocation; + +namespace stormkit { inline namespace core { + export { + namespace meta { + template + using TransformExpectedValueTo = std::expected; + } // namespace meta + } + + struct PrivateTagBase { + struct Tag { + private: + Tag() = default; + friend struct PrivateTagBase; + }; + + private: + static constexpr auto PRIVATE = Tag {}; + + template + friend class NamedConstructor; + }; + + export { + using PrivateTag = PrivateTagBase::Tag; + + template + struct ConstructorArgs {}; + + template + struct DoInitArgs {}; + + template + class NamedConstructor { + protected: + constexpr ~NamedConstructor() noexcept; + + constexpr NamedConstructor(const NamedConstructor&) noexcept; + constexpr auto operator=(const NamedConstructor&) noexcept -> NamedConstructor&; + + constexpr NamedConstructor(NamedConstructor&&) noexcept; + constexpr auto operator=(NamedConstructor&&) noexcept -> NamedConstructor&; + + static constexpr auto PRIVATE = PrivateTagBase::PRIVATE; + + constexpr NamedConstructor() noexcept; + }; + + template + class NamedConstructor>: public NamedConstructor<> { + using ValueType = T; + + public: + using NamedConstructor<>::NamedConstructor; + using NamedConstructor<>::operator=; + + [[nodiscard]] + static constexpr auto create(TConstructorArgs... c_args) noexcept -> ValueType; + + [[nodiscard]] + static constexpr auto allocate(TConstructorArgs... c_args) noexcept -> Heap; + }; + + template + class NamedConstructor: NamedConstructor> { + public: + using NamedConstructor>::NamedConstructor; + using NamedConstructor>::operator=; + }; + + template + class NamedConstructor, DoInitArgs>: public NamedConstructor<> { + using ValueType = T; + + public: + using NamedConstructor<>::NamedConstructor; + using NamedConstructor<>::operator=; + + [[nodiscard]] + static constexpr auto create(TConstructorArgs... c_args, TDoInitArgs... d_args) noexcept -> decltype(auto); + + [[nodiscard]] + static constexpr auto allocate(TConstructorArgs... c_args, TDoInitArgs... d_args) noexcept -> decltype(auto); + }; + + template + class NamedConstructor>: public NamedConstructor<> { + using ValueType = T; + + public: + using NamedConstructor<>::NamedConstructor; + using NamedConstructor<>::operator=; + [[nodiscard]] + static constexpr auto create(TDoInitArgs... args) noexcept -> decltype(auto); + + [[nodiscard]] + static constexpr auto allocate(TDoInitArgs... args) noexcept -> decltype(auto); + }; + } +}} // namespace stormkit::core + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit { inline namespace core { + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr NamedConstructor::NamedConstructor() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr NamedConstructor::~NamedConstructor() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto NamedConstructor::operator=(const NamedConstructor&) noexcept -> NamedConstructor& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr NamedConstructor::NamedConstructor(const NamedConstructor&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto NamedConstructor::operator=(NamedConstructor&&) noexcept -> NamedConstructor& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr NamedConstructor::NamedConstructor(NamedConstructor&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto NamedConstructor>::create(TConstructorArgs... args) noexcept + -> ValueType { + return ValueType { PrivateTagBase::PRIVATE, std::forward(args)... }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto NamedConstructor>::allocate(TConstructorArgs... args) noexcept + -> Heap { + return core::allocate_unsafe(PrivateTagBase::PRIVATE, std::forward(args)...); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + constexpr auto NamedConstructor, DoInitArgs>:: + create(TConstructorArgs... c_args, TDoInitArgs... d_args) noexcept -> decltype(auto) { + using DoInitReturnType = decltype(std::declval().do_init(PRIVATE, std::declval()...)); + if constexpr (not meta::IsStdExpected) { + auto out = ValueType { PrivateTagBase::PRIVATE, std::forward(c_args)... }; + out.do_init(PrivateTagBase::PRIVATE, std::forward(d_args)...); + return out; + } else { + using ReturnType = meta::TransformExpectedValueTo; + +#ifdef STORMKIT_COMPILER_CLANG + auto out = ValueType { PrivateTagBase::PRIVATE, std::forward(c_args)... }; + if (auto result = out.do_init(PrivateTagBase::PRIVATE, std::forward(d_args)...); not result) + return ReturnType { std::unexpect, std::move(result).error() }; + + return ReturnType { std::in_place, std::move(out) }; +#else + auto out_expected = ReturnType { std::in_place, PrivateTagBase::PRIVATE, std::forward(c_args)... }; + if (auto result = out_expected.value().do_init(PrivateTagBase::PRIVATE, std::forward(d_args)...); + not result) + out_expected = std::unexpected { std::move(result).error() }; + + return out_expected; +#endif + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + constexpr auto NamedConstructor, DoInitArgs>:: + allocate(TConstructorArgs... c_args, TDoInitArgs... d_args) noexcept -> decltype(auto) { + using DoInitReturnType = decltype(std::declval().do_init(PRIVATE, std::declval()...)); + if constexpr (not meta::IsStdExpected) { + auto out = core::allocate_unsafe(PrivateTagBase::PRIVATE, std::forward(c_args)...); + out->do_init(PrivateTagBase::PRIVATE, std::forward(d_args)...); + return out; + } else { + using ReturnType = meta::TransformExpectedValueTo, DoInitReturnType>; + +#ifdef STORMKIT_COMPILER_CLANG + auto out = core::allocate_unsafe(PrivateTagBase::PRIVATE, std::forward(c_args)...); + if (auto result = out->do_init(PrivateTagBase::PRIVATE, std::forward(d_args)...); not result) + return ReturnType { std::unexpect, std::move(result).error() }; + + return ReturnType { std::in_place, std::move(out) }; +#else + auto out_expected = ReturnType { + std::in_place, + core::allocate_unsafe(PrivateTagBase::PRIVATE, std::forward(c_args)...) + }; + if (auto result = out_expected.value()->do_init(PrivateTagBase::PRIVATE, std::forward(d_args)...); + not result) + out_expected = std::unexpected { std::move(result).error() }; + + return out_expected; +#endif + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + constexpr auto NamedConstructor>::create(TDoInitArgs... args) noexcept -> decltype(auto) { + using DoInitReturnType = decltype(std::declval().do_init(PRIVATE, std::declval()...)); + if constexpr (not meta::IsStdExpected) { + auto out = ValueType { PrivateTagBase::PRIVATE }; + out.do_init(PrivateTagBase::PRIVATE, std::forward(args)...); + return out; + } else { + using ReturnType = meta::TransformExpectedValueTo; + +#ifdef STORMKIT_COMPILER_CLANG + auto out = ValueType { PrivateTagBase::PRIVATE }; + if (auto result = out.do_init(PrivateTagBase::PRIVATE, std::forward(args)...); not result) + return ReturnType { std::unexpect, std::move(result).error() }; + + return ReturnType { std::in_place, std::move(out) }; +#else + auto out_expected = ReturnType { std::in_place, PrivateTagBase::PRIVATE }; + if (auto result = out_expected.value().do_init(PrivateTagBase::PRIVATE, std::forward(args)...); + not result) + out_expected = std::unexpected { std::move(result).error() }; + + return out_expected; +#endif + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + constexpr auto NamedConstructor>::allocate(TDoInitArgs... args) noexcept -> decltype(auto) { + using DoInitReturnType = decltype(std::declval().do_init(PRIVATE, std::declval()...)); + if constexpr (not meta::IsStdExpected) { + auto out = core::allocate_unsafe(PrivateTagBase::PRIVATE); + out->do_init(PrivateTagBase::PRIVATE, std::forward(args)...); + return out; + } else { + using ReturnType = meta::TransformExpectedValueTo, DoInitReturnType>; + +#ifdef STORMKIT_COMPILER_CLANG + auto out = core::allocate_unsafe(PrivateTagBase::PRIVATE); + if (auto result = out->do_init(PrivateTagBase::PRIVATE, std::forward(args)...); not result) + return ReturnType { std::unexpect, std::move(result).error() }; + + return ReturnType { std::in_place, std::move(out) }; +#else + auto out_expected = ReturnType { std::in_place, core::allocate_unsafe(PrivateTagBase::PRIVATE...) }; + if (auto result = out_expected.value()->do_init(PrivateTagBase::PRIVATE, std::forward(args)...); + not result) + out_expected = std::unexpected { std::move(result).error() }; + + return out_expected; +#endif + } + } +}} // namespace stormkit::core diff --git a/modules/stormkit/core/parallelism.mpp b/modules/stormkit/core/parallelism.cppm similarity index 97% rename from modules/stormkit/core/parallelism.mpp rename to modules/stormkit/core/parallelism.cppm index 8ab882df4..16ef24cea 100644 --- a/modules/stormkit/core/parallelism.mpp +++ b/modules/stormkit/core/parallelism.cppm @@ -1,9 +1,9 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -export module stormkit.core:parallelism; - -export import :parallelism.locked; -export import :parallelism.threadpool; -export import :parallelism.threadutils; +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +export module stormkit.core:parallelism; + +export import :parallelism.locked; +export import :parallelism.threadpool; +export import :parallelism.threadutils; diff --git a/modules/stormkit/core/parallelism/locked.cppm b/modules/stormkit/core/parallelism/locked.cppm new file mode 100644 index 000000000..640e7dd53 --- /dev/null +++ b/modules/stormkit/core/parallelism/locked.cppm @@ -0,0 +1,443 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include + +export module stormkit.core:parallelism.locked; + +import std; + +import :meta; +import :typesafe.integer; +import :typesafe.ref; + +namespace stormkit { inline namespace core { + export { + enum class LockAccessMode : core::u8 { + READ_ONLY, + READ_WRITE, + }; + } + + namespace meta { namespace details { + template + struct LockedValueType { + using Type = T; + }; + + template + struct LockedValueType { + using Type = meta::ContainedOrPointedType; + }; + + template + using AccessClosureInvokeParameter = meta::If; + }} // namespace meta::details + + namespace details { + using DefaultMutex = std::mutex; + template + using DefaultReadOnlyLock = std::unique_lock; + template + using DefaultReadWriteLock = std::unique_lock; + } // namespace details + + export { + template + class STORMKIT_CORE_API Locked { + public: + using ValueType = meta::details::LockedValueType::Type; + using ReferenceType = ValueType&; + using ConstReferenceType = const ValueType&; + using PointerType = ValueType*; + + /* stl compatible */ + using value_type = ValueType; + using reference_type = ReferenceType; + using pointer_type = PointerType; + + using MutexType = Mutex; + + private: + template class Lock, LockAccessMode Mode> + class Access; + + public: + template class Lock> + using ReadAccess = Access; + template class Lock> + using WriteAccess = Access; + + Locked() noexcept(noexcept(std::is_nothrow_default_constructible_v)); + + template + explicit(sizeof...(Args) == 1) + Locked(Args&&... args) noexcept(noexcept(std::is_nothrow_constructible_v)); + + Locked(const Locked&) = delete; + auto operator=(const Locked&) -> Locked& = delete; + + Locked(Locked&&) noexcept; + auto operator=(Locked&&) noexcept -> Locked&; + + ~Locked() noexcept; + + template class Lock, typename... LockArgs, class Self> + auto access(this Self& self, LockArgs&&... lock_args) noexcept -> Access; + + template< + LockAccessMode Mode, + std::invocable::Type&, Mode>> + Closure, + template class Lock, + typename... LockArgs, + class Self> + auto access(this Self& self, Closure&& closure, LockArgs&&... lock_args) noexcept + -> std::invoke_result_t>; + + template class Lock = details::DefaultReadOnlyLock, typename... LockArgs> + auto read(LockArgs&&... lock_args) const noexcept -> ReadAccess; + + template Closure, + template class Lock = details::DefaultReadOnlyLock, + typename... LockArgs> + auto read(Closure&& closure, LockArgs&&... lock_args) const noexcept + -> std::invoke_result_t; + + template class Lock = details::DefaultReadWriteLock, typename... LockArgs> + auto write(LockArgs&&... lock_args) noexcept -> WriteAccess; + + template Closure, + template class Lock = details::DefaultReadWriteLock, + typename... LockArgs> + auto write(Closure&& closure, LockArgs&&... lock_args) noexcept -> std::invoke_result_t; + + template class Lock = details::DefaultReadOnlyLock, typename... LockArgs> + auto copy(LockArgs&&... lock_args) const noexcept -> ValueType; + + template class Lock = details::DefaultReadWriteLock, typename... LockArgs> + auto assign(ConstReferenceType value, + LockArgs&&... lock_args) noexcept(noexcept(std::is_nothrow_assignable_v)) + -> void; + + template class Lock = details::DefaultReadWriteLock, typename... LockArgs> + auto assign(ValueType&& value, + LockArgs&&... lock_args) noexcept(noexcept(std::is_nothrow_assignable_v)) -> void; + + template + auto unsafe(this Self& self) noexcept -> meta::ForwardConst&; + + auto mutex() const noexcept -> const MutexType&; + + private: + template class Lock, LockAccessMode Mode> + class Access { + public: + using AccessValueType = std::conditional_t; + using RefContainerType = std:: + conditional_t, ref>; + + template + Access(ReferenceType value, MutexType& mutex, LockArgs&&... args) noexcept; + + template + Access(ConstReferenceType value, MutexType& mutex, LockArgs&&... args) noexcept; + + template + requires(not meta::IsContainerOrPointer) + explicit(sizeof...(LockArgs) == 0) Access(const Locked& locked, LockArgs&&... args) noexcept + requires(Mode == LockAccessMode::READ_ONLY); + + template + requires(not meta::IsContainerOrPointer) + explicit(sizeof...(LockArgs) == 0) Access(Locked& locked, LockArgs&&... args) noexcept; + + template + requires(meta::IsContainerOrPointer) + explicit(sizeof...(LockArgs) == 0) Access(const Locked& locked, LockArgs&&... args) noexcept + requires(Mode == LockAccessMode::READ_ONLY); + + template + requires(meta::IsContainerOrPointer) + explicit(sizeof...(LockArgs) == 0) Access(Locked& locked, LockArgs&&... args) noexcept; + + auto operator->() const noexcept -> AccessValueType*; + auto operator*() const noexcept -> AccessValueType&; + + mutable Lock lock; + + private: + RefContainerType m_value; + }; + + mutable Mutex m_mutex; + T m_value STORMKIT_GUARDED_BY(m_mutex); + }; + + template + Locked(T) -> Locked; + + template class Locked; + template class Locked>; + template class Locked>; + } +}} // namespace stormkit::core + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit { inline namespace core { + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + Locked::Locked() noexcept(noexcept(std::is_nothrow_default_constructible_v)) = default; + + //////////////////////////////////////// + //////////////////////////////////////// + template + template + STORMKIT_FORCE_INLINE + Locked::Locked(Args&&... args) noexcept(noexcept(std::is_nothrow_constructible_v)) + : m_value { std::forward(args)... } { + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + Locked::Locked(Locked&& other) noexcept { + auto _ = other.write(); + + m_value = std::move(other.m_value); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto Locked::operator=(Locked&& other) noexcept -> Locked& { + if (&other == this) [[unlikely]] + return *this; + + auto from = other.write(); + auto to = write(); + + *to = std::move(*from); + + return *this; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + Locked::~Locked() noexcept = default; + + //////////////////////////////////////// + //////////////////////////////////////// + template + template class Lock, typename... LockArgs, class Self> + STORMKIT_FORCE_INLINE + auto Locked::access(this Self& self, LockArgs&&... lock_args) noexcept -> Access { + static_assert(not(Mode == LockAccessMode::READ_ONLY and not std::is_const_v>), + "can't get read access on const Locked"); + using AccessType = Access; + return AccessType { std::forward(self), std::forward(lock_args)... }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template::Type&, Mode>> + Closure, + template class Lock, + typename... LockArgs, + class Self> STORMKIT_FORCE_INLINE + auto Locked::access(this Self& self, Closure&& closure, LockArgs&&... lock_args) noexcept + -> std::invoke_result_t> { + static_assert(not(Mode == LockAccessMode::READ_ONLY and not std::is_const_v>), + "can't get read access on const Locked"); + using AccessType = Access; + auto access_ = AccessType { std::forward(self), std::forward(lock_args)... }; + return std::invoke(std::forward(closure), *access_); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template class Lock, typename... LockArgs> + STORMKIT_FORCE_INLINE + auto Locked::read(LockArgs&&... lock_args) const noexcept -> ReadAccess { + return access(std::forward(lock_args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template::ConstReferenceType> Closure, + template class Lock, + typename... LockArgs> + STORMKIT_FORCE_INLINE + auto Locked::read(Closure&& closure, LockArgs&&... lock_args) const noexcept + -> std::invoke_result_t { + return access(std::forward(closure), + std::forward(lock_args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template class Lock, typename... LockArgs> + STORMKIT_FORCE_INLINE + auto Locked::write(LockArgs&&... lock_args) noexcept -> WriteAccess { + return access(std::forward(lock_args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template::ReferenceType> Closure, template class Lock, typename... LockArgs> + STORMKIT_FORCE_INLINE + auto Locked::write(Closure&& closure, LockArgs&&... lock_args) noexcept + -> std::invoke_result_t { + return access(std::forward(closure), + std::forward(lock_args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template class Lock, typename... LockArgs> + STORMKIT_FORCE_INLINE + auto Locked::copy(LockArgs&&... lock_args) const noexcept -> ValueType { + return *read(std::forward(lock_args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template class Lock, typename... LockArgs> + STORMKIT_FORCE_INLINE + auto Locked:: + assign(ConstReferenceType value, + LockArgs&&... lock_args) noexcept(noexcept(std::is_nothrow_assignable_v)) -> void { + *write(std::forward(lock_args)...) = value; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template class Lock, typename... LockArgs> + STORMKIT_FORCE_INLINE + auto Locked::assign(ValueType&& value, + LockArgs&&... lock_args) noexcept(noexcept(std::is_nothrow_assignable_v)) + -> void { + *write(std::forward(lock_args)...) = std::move(value); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template + STORMKIT_FORCE_INLINE + auto Locked::unsafe(this Self& self) noexcept -> meta::ForwardConst& { + return std::forward_like(self.m_value); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + auto Locked::mutex() const noexcept -> const MutexType& { + return m_mutex; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template class Lock, LockAccessMode Mode> + template + STORMKIT_FORCE_INLINE + Locked::Access::Access(ReferenceType value, MutexType& mutex, LockArgs&&... lock_args) noexcept + : lock { mutex, std::forward(lock_args)... }, m_value { as_ref_mut(value) } { + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template class Lock, LockAccessMode Mode> + template + STORMKIT_FORCE_INLINE + Locked::Access::Access(ConstReferenceType value, MutexType& mutex, LockArgs&&... lock_args) noexcept + : lock { mutex, std::forward(lock_args)... }, m_value { as_ref(value) } { + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template class Lock, LockAccessMode Mode> + template + requires(not meta::IsContainerOrPointer) + STORMKIT_FORCE_INLINE + Locked::Access::Access(const Locked& locked, LockArgs&&... lock_args) noexcept + requires(Mode == LockAccessMode::READ_ONLY) + : Access { locked.m_value, locked.m_mutex, std::forward(lock_args)... } { + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template class Lock, LockAccessMode Mode> + template + requires(not meta::IsContainerOrPointer) + STORMKIT_FORCE_INLINE + Locked::Access::Access(Locked& locked, LockArgs&&... lock_args) noexcept + : Access { locked.m_value, locked.m_mutex, std::forward(lock_args)... } { + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template class Lock, LockAccessMode Mode> + template + requires(meta::IsContainerOrPointer) + STORMKIT_FORCE_INLINE + Locked::Access::Access(const Locked& locked, LockArgs&&... lock_args) noexcept + requires(Mode == LockAccessMode::READ_ONLY) + : Access { *locked.m_value, locked.m_mutex, std::forward(lock_args)... } { + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template class Lock, LockAccessMode Mode> + template + requires(meta::IsContainerOrPointer) + STORMKIT_FORCE_INLINE + Locked::Access::Access(Locked& locked, LockArgs&&... lock_args) noexcept + : Access { *locked.m_value, locked.m_mutex, std::forward(lock_args)... } { + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template class Lock, LockAccessMode Mode> + STORMKIT_FORCE_INLINE + auto Locked::Access::operator->() const noexcept -> AccessValueType* { + return m_value.get(); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + template class Lock, LockAccessMode Mode> + STORMKIT_FORCE_INLINE + auto Locked::Access::operator*() const noexcept -> AccessValueType& { + return *m_value; + } +}} // namespace stormkit::core diff --git a/modules/stormkit/core/parallelism/locked.mpp b/modules/stormkit/core/parallelism/locked.mpp deleted file mode 100644 index 223a8f78c..000000000 --- a/modules/stormkit/core/parallelism/locked.mpp +++ /dev/null @@ -1,286 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -export module stormkit.core:parallelism.locked; - -import std; - -import :meta; -import :typesafe.integer; -import :typesafe.ref; - -namespace stormkit { inline namespace core { namespace details { - using DefaultMutex = std::mutex; - template - using DefaultReadOnlyLock = std::lock_guard; - template - using DefaultReadWriteLock = std::lock_guard; -}}} // namespace stormkit::core::details - -export namespace stormkit { inline namespace core { - enum class LockAccessMode : core::u8 { - Read_Only, - Read_Write - }; - - template - class STORMKIT_API Locked { - public: - using ValueType = T; - using ReferenceType = ValueType&; - using ConstReferenceType = const ValueType&; - using PointerType = ValueType*; - - /* stl compatible */ - using value_type = ValueType; - using reference_type = ReferenceType; - using pointer_type = PointerType; - - using MutexType = Mutex; - - private: - template class Lock, LockAccessMode Mode> - class Access; - - public: - template class Lock> - using ReadAccess = Access; - template class Lock> - using WriteAccess = Access; - - Locked() noexcept(noexcept(std::is_nothrow_default_constructible_v)); - - template - explicit Locked(Args&&... args) noexcept( - noexcept(std::is_nothrow_constructible_v)); - - Locked(const Locked&) = delete; - auto operator=(const Locked&) -> Locked& = delete; - - Locked(Locked&&) noexcept = delete; - auto operator=(Locked&&) noexcept -> Locked& = delete; - - template class Lock, typename... LockArgs, class Self> - auto access(this Self& self, LockArgs&&... lock_args) noexcept -> Access; - - template class Lock = details::DefaultReadOnlyLock, typename... LockArgs> - auto read(LockArgs&&... lock_args) const noexcept -> ReadAccess; - - template class Lock = details::DefaultReadWriteLock, typename... LockArgs> - auto write(LockArgs&&... lock_args) noexcept -> WriteAccess; - - template class Lock = details::DefaultReadOnlyLock, typename... LockArgs> - auto copy(LockArgs&&... lock_args) const noexcept -> ValueType; - - template class Lock = details::DefaultReadWriteLock, typename... LockArgs> - auto assign(ConstReferenceType value, LockArgs&&... lock_args) noexcept( - noexcept(std::is_nothrow_assignable_v)) -> void; - - template class Lock = details::DefaultReadWriteLock, typename... LockArgs> - auto assign(ValueType&& value, LockArgs&&... lock_args) noexcept( - noexcept(std::is_nothrow_assignable_v)) -> void; - - template - auto unsafe(this Self& self) noexcept -> meta::ForwardConst; - - auto mutex() const noexcept -> const MutexType&; - - private: - template class Lock, LockAccessMode Mode> - class Access { - public: - using ValueType - = std::conditional_t; - using RefContainerType = std::conditional_t, - Ref>; - using ReferenceType = ValueType&; - using PointerType = ValueType*; - - template - Access(ReferenceType value, MutexType& mutex, LockArgs&&... args) noexcept; - - template - explicit Access(const Locked& locked, LockArgs&&... args) noexcept; - - template - explicit Access(Locked& locked, LockArgs&&... args) noexcept; - - template - auto operator->(this Self&& self) noexcept -> meta::ForwardConst; - - template - auto operator*(this Self&& self) noexcept -> meta::ForwardConst; - - mutable Lock lock; - - private: - RefContainerType m_value; - }; - - Mutex m_mutex; - ValueType m_value; - }; - - template - Locked(T) -> Locked; -}} // namespace stormkit::core - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit { inline namespace core { - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_FORCE_INLINE Locked::Locked() noexcept( - noexcept(std::is_nothrow_default_constructible_v)) - = default; - - //////////////////////////////////////// - //////////////////////////////////////// - template - template - STORMKIT_FORCE_INLINE Locked::Locked(Args&&... args) noexcept( - noexcept(std::is_nothrow_constructible_v)) - : m_value { std::forward(args)... } { - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - template class Lock, typename... LockArgs, class Self> - STORMKIT_FORCE_INLINE auto Locked::access(this Self& self, - LockArgs&&... lock_args) noexcept - -> Access { - static_assert(not(Mode == LockAccessMode::Read_Only - and not std::is_const_v>), - "can't get read access on const Locked"); - using AccessType = Access; - return AccessType { self, std::forward(lock_args)... }; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - template class Lock, typename... LockArgs> - STORMKIT_FORCE_INLINE auto Locked::read(LockArgs&&... lock_args) const noexcept - -> ReadAccess { - return access(std::forward(lock_args)...); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - template class Lock, typename... LockArgs> - STORMKIT_FORCE_INLINE auto Locked::write(LockArgs&&... lock_args) noexcept - -> WriteAccess { - return access(std::forward(lock_args)...); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - template class Lock, typename... LockArgs> - STORMKIT_FORCE_INLINE auto Locked::copy(LockArgs&&... lock_args) const noexcept - -> ValueType { - return *read(std::forward(lock_args)...); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - template class Lock, typename... LockArgs> - STORMKIT_FORCE_INLINE auto - Locked::assign(ConstReferenceType value, LockArgs&&... lock_args) noexcept( - noexcept(std::is_nothrow_assignable_v)) -> void { - *write(std::forward(lock_args)...) = value; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - template class Lock, typename... LockArgs> - STORMKIT_FORCE_INLINE auto - Locked::assign(ValueType&& value, LockArgs&&... lock_args) noexcept( - noexcept(std::is_nothrow_assignable_v)) -> void { - *write(std::forward(lock_args)...) = std::move(value); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - template - STORMKIT_FORCE_INLINE auto Locked::unsafe(this Self& self) noexcept - -> meta::ForwardConst { - return self.m_value; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_FORCE_INLINE auto Locked::mutex() const noexcept -> const MutexType& { - return m_mutex; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - template class Lock, LockAccessMode Mode> - template - STORMKIT_FORCE_INLINE - Locked::Access::Access(ReferenceType value, - MutexType& mutex, - LockArgs&&... lock_args) noexcept - : lock { mutex, std::forward(lock_args)... }, m_value { as_ref_like(value) } { - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - template class Lock, LockAccessMode Mode> - template - STORMKIT_FORCE_INLINE - Locked::Access::Access(const Locked& locked, - LockArgs&&... lock_args) noexcept - : Access { locked.m_value, locked.m_mutex, std::forward(lock_args)... } { - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - template class Lock, LockAccessMode Mode> - template - STORMKIT_FORCE_INLINE - Locked::Access::Access(Locked& locked, LockArgs&&... lock_args) noexcept - : Access { locked.m_value, locked.m_mutex, std::forward(lock_args)... } { - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - template class Lock, LockAccessMode Mode> - template - STORMKIT_FORCE_INLINE auto - Locked::Access::operator->(this Self&& self) noexcept - -> meta::ForwardConst { - return self.m_value.get(); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - template class Lock, LockAccessMode Mode> - template - STORMKIT_FORCE_INLINE auto - Locked::Access::operator*(this Self&& self) noexcept - -> meta::ForwardConst { - return *self.m_value; - } -}} // namespace stormkit::core diff --git a/modules/stormkit/core/parallelism/threadpool.mpp b/modules/stormkit/core/parallelism/threadpool.cppm similarity index 64% rename from modules/stormkit/core/parallelism/threadpool.mpp rename to modules/stormkit/core/parallelism/threadpool.cppm index 2ff79ecd7..9cc0525cf 100644 --- a/modules/stormkit/core/parallelism/threadpool.mpp +++ b/modules/stormkit/core/parallelism/threadpool.cppm @@ -1,226 +1,228 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -export module stormkit.core:parallelism.threadpool; - -import std; - -import :parallelism.threadutils; - -import :meta; - -import :utils.numeric_range; -import :typesafe.integer; - -export namespace stormkit { inline namespace core { - class STORMKIT_API ThreadPool { - public: - static constexpr struct NoFutureType { - } NoFuture; - - template - using Callback = std::function; - - explicit ThreadPool(u32 worker_count = std::thread::hardware_concurrency() / 2); - ~ThreadPool(); - - ThreadPool(const ThreadPool&) = delete; - auto operator=(const ThreadPool&) -> ThreadPool& = delete; - - ThreadPool(ThreadPool&&) noexcept; - auto operator=(ThreadPool&&) noexcept -> ThreadPool&; - - auto worker_count() const noexcept; - - template - auto post_task(Callback callback); - - template - auto post_task(Callback callback, NoFutureType); - - auto join_all() -> void; - - auto set_name(std::string_view name) noexcept -> void; - - private: - struct Task { - enum class Type { - Standard, - Terminate, - }; - - Task() = default; - - inline Task(Type _type, std::function _work) - : type { _type }, work { std::move(_work) } {} - - Task(Task&&) noexcept = default; - auto operator=(Task&&) noexcept -> Task& = default; - - Type type; - std::function work; - }; - - template - auto post_task(Task::Type type, Callback callback); - - template - auto post_task(Task::Type type, Callback callback, NoFutureType); - - auto worker_main() noexcept -> void; - - u32 m_worker_count = 0; - - std::vector m_workers; - - mutable std::mutex m_mutex; - std::condition_variable m_work_signal; - std::queue m_tasks; - }; - - template&> F> - auto parallel_for(ThreadPool& pool, Range&& range, F&& f) noexcept -> void; - - template&> F> - auto parallel_for_async(ThreadPool& pool, Range& range, F&& f) noexcept - -> std::vector>; -}} // namespace stormkit::core - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stdr = std::ranges; -namespace stdv = std::views; - -namespace stormkit { inline namespace core { - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline ThreadPool::ThreadPool(u32 worker_count) - : m_worker_count { worker_count } { - m_workers.reserve(m_worker_count); - - for (auto i : range(m_worker_count)) { - auto& worker = m_workers.emplace_back([this] { worker_main(); }); - set_thread_name(worker, std::format("StormKit:WorkerThread:{}", i)); - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline ThreadPool::~ThreadPool() { - join_all(); - } - - //////////////////////////////////////// - //////////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto ThreadPool::worker_count() const noexcept { - return m_worker_count; - } - - //////////////////////////////////////// - //////////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto ThreadPool::set_name(std::string_view name) noexcept -> void { - // for (auto&& [i, worker] : stdv::enumerate(m_workers)) - for (auto i : range(m_worker_count)) - set_thread_name(m_workers[i], std::format("{}:{}", name, i)); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_FORCE_INLINE - inline auto ThreadPool::post_task(Callback callback) { - return post_task(Task::Type::Standard, std::move(callback)); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_FORCE_INLINE - inline auto ThreadPool::post_task(Callback callback, NoFutureType t) { - post_task(Task::Type::Standard, std::move(callback), t); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - inline auto ThreadPool::post_task(Task::Type type, Callback callback) { - auto packaged_task = std::make_shared>(std::move(callback)); - - auto future = packaged_task->get_future(); - - auto task = Task { type, [callback = std::move(packaged_task)]() { (*callback)(); } }; - - { - auto lock = std::unique_lock { m_mutex }; - - m_tasks.emplace(std::move(task)); - } - - m_work_signal.notify_one(); - - return future; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - inline auto ThreadPool::post_task(Task::Type type, Callback callback, NoFutureType) { - auto task = Task { type, [callback = std::move(callback)]() { callback(); } }; - - { - auto lock = std::unique_lock { m_mutex }; - - m_tasks.emplace(std::move(task)); - } - - m_work_signal.notify_one(); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template&> F> - inline auto parallel_for(ThreadPool& pool, Range&& range, F&& f) noexcept -> void { - auto futures = parallel_for_async(pool, range, std::forward(f)); - wait_all(futures); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template&> F> - inline auto parallel_for_async(ThreadPool& pool, Range& range, F&& f) noexcept - -> std::vector> { - const auto size = stdr::size(range); - const auto chunk_size = size / pool.worker_count(); - const auto chunk_count = size / chunk_size; - - auto out = std::vector> {}; - out.reserve(chunk_count); - - for (auto chunk : stormkit::range(chunk_count)) { - const auto start = chunk * chunk_size; - auto end = (chunk + 1u) * chunk_size; - if (end >= (chunk_count * size)) end = size; - - out.emplace_back(pool.post_task([&f, &range, start, end] mutable noexcept { - auto it = std::begin(range) + start; - for (auto _ : stormkit::range(start, end)) { - f(*it); - ++it; - } - })); - } - - return out; - } -}} // namespace stormkit::core +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include + +export module stormkit.core:parallelism.threadpool; + +import std; + +import :parallelism.threadutils; + +import :meta; +import :functional; + +import :utils.std23_functional; +import :utils.numeric_range; +import :typesafe.integer; + +export namespace stormkit { inline namespace core { + class STORMKIT_CORE_API ThreadPool { + public: + static constexpr struct NoFutureType { + } NO_FUTURE = {}; + + template + using Closure = std23::move_only_function; + + explicit ThreadPool(u32 worker_count = std::thread::hardware_concurrency() / 2); + ~ThreadPool(); + + ThreadPool(const ThreadPool&) = delete; + auto operator=(const ThreadPool&) -> ThreadPool& = delete; + + ThreadPool(ThreadPool&&) noexcept; + auto operator=(ThreadPool&&) noexcept -> ThreadPool&; + + [[nodiscard]] + auto worker_count() const noexcept -> u32; + + template + [[nodiscard]] + auto post_task(Closure task) noexcept -> decltype(auto); + + template + auto post_task(Closure task, NoFutureType) noexcept -> void; + + auto join_all() noexcept -> void; + + auto wait_idle(bool cancel_tasks = false) noexcept -> void; + + auto set_name(string_view name) noexcept -> void; + + private: + struct Task { + enum class Type { + Standard, + Terminate, + }; + + Task() = default; + + inline Task(Type _type, std23::move_only_function&& _work) : type { _type }, work { std::move(_work) } {} + + Task(Task&&) noexcept = default; + auto operator=(Task&&) noexcept -> Task& = default; + + Type type; + std23::move_only_function work; + }; + + template + auto post_task(Task::Type type, Closure task) noexcept -> decltype(auto); + + template + auto post_task(Task::Type type, Closure task, NoFutureType) noexcept -> void; + + auto worker_main(i32 id) noexcept -> void; + + auto spawn_workers() noexcept -> void; + + u32 m_worker_count = 0; + + dyn_array m_workers; + + mutable std::mutex m_mutex; + std::condition_variable m_work_signal; + std::counting_semaphore<64> m_running_task_counter; + std::queue m_tasks; + }; + + template&> F> + auto parallel_for(ThreadPool& pool, Range&& range, F&& f) noexcept -> void; + + template&> F> + auto parallel_for_async(ThreadPool& pool, Range& range, F&& f) noexcept -> dyn_array>; +}} // namespace stormkit::core + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stdr = std::ranges; +namespace stdv = std::views; + +namespace stormkit { inline namespace core { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline ThreadPool::ThreadPool(u32 worker_count) + : m_worker_count { worker_count }, m_running_task_counter { worker_count } { + spawn_workers(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline ThreadPool::~ThreadPool() { + wait_idle(); + join_all(); + } + + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto ThreadPool::worker_count() const noexcept -> u32 { + return m_worker_count; + } + + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto ThreadPool::set_name(string_view name) noexcept -> void { + // for (auto&& [i, worker] : stdv::enumerate(m_workers)) + for (auto i : range(m_worker_count)) set_thread_name(m_workers[i], std::format("{}:{}", name, i)); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto ThreadPool::post_task(Closure task) noexcept -> decltype(auto) { + return post_task(Task::Type::Standard, std::move(task)); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto ThreadPool::post_task(Closure task, NoFutureType t) noexcept -> void { + post_task(Task::Type::Standard, std::move(task), t); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + inline auto ThreadPool::post_task(Task::Type type, Closure closure) noexcept -> decltype(auto) { + auto packaged_task = std::make_shared>(std::move(closure)); + + auto future = packaged_task->get_future(); + + auto task = Task { type, [task = std::move(packaged_task)]() { (*task)(); } }; + + { + auto _ = std::unique_lock { m_mutex }; + + m_tasks.emplace(std::move(task)); + } + + m_work_signal.notify_one(); + + return future; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + inline auto ThreadPool::post_task(Task::Type type, Closure closure, NoFutureType) noexcept -> void { + auto task = Task { type, [task = std::move(closure)]() mutable noexcept { task(); } }; + + { + auto lock = std::unique_lock { m_mutex }; + + m_tasks.emplace(std::move(task)); + } + + m_work_signal.notify_one(); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template&> F> + inline auto parallel_for(ThreadPool& pool, Range&& range, F&& f) noexcept -> void { + auto futures = parallel_for_async(pool, range, std::forward(f)); + wait_all(futures); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template&> F> + inline auto parallel_for_async(ThreadPool& pool, Range& range, F&& f) noexcept -> dyn_array> { + const auto size = stdr::size(range); + const auto chunk_size = size / pool.worker_count(); + const auto chunk_count = size / chunk_size; + + auto out = dyn_array> {}; + out.reserve(chunk_count); + + for (auto chunk : stormkit::range(chunk_count)) { + const auto start = chunk * chunk_size; + auto end = (chunk + 1u) * chunk_size; + if (end >= (chunk_count * size)) end = size; + + out.emplace_back(pool.post_task([&f, &range, start, end] mutable noexcept { + auto it = std::begin(range) + as(start); + for (auto _ : stormkit::range(start, end)) { + f(*it); + ++it; + } + })); + } + + return out; + } +}} // namespace stormkit::core diff --git a/modules/stormkit/core/parallelism/threadutils.mpp b/modules/stormkit/core/parallelism/threadutils.cppm similarity index 61% rename from modules/stormkit/core/parallelism/threadutils.mpp rename to modules/stormkit/core/parallelism/threadutils.cppm index a55d1c978..0fd29b201 100644 --- a/modules/stormkit/core/parallelism/threadutils.mpp +++ b/modules/stormkit/core/parallelism/threadutils.cppm @@ -1,34 +1,36 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -export module stormkit.core:parallelism.threadutils; - -import std; - -import :meta; - -export namespace stormkit { inline namespace core { - STORMKIT_API - auto set_current_thread_name(std::string_view name) noexcept -> void; - STORMKIT_API - auto set_thread_name(std::thread& thread, std::string_view name) noexcept -> void; - STORMKIT_API - auto set_thread_name(std::jthread& thread, std::string_view name) noexcept -> void; - STORMKIT_API - auto get_current_thread_name() noexcept -> std::string; - STORMKIT_API - auto get_thread_name(const std::thread& thread) noexcept -> std::string; - STORMKIT_API - auto get_thread_name(const std::jthread& thread) noexcept -> std::string; - - template - requires(meta::IsSpecializationOf, std::future>) - inline auto wait_all(Range&& futures) noexcept { - for (auto&& future : std::forward(futures)) future.wait(); - } -}} // namespace stormkit::core +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include + +export module stormkit.core:parallelism.threadutils; + +import std; + +import :meta; +import :string.aliases; + +export namespace stormkit { inline namespace core { + STORMKIT_CORE_API + auto set_current_thread_name(string_view name) noexcept -> void; + STORMKIT_CORE_API + auto set_thread_name(std::thread& thread, string_view name) noexcept -> void; + STORMKIT_CORE_API + auto set_thread_name(std::jthread& thread, string_view name) noexcept -> void; + STORMKIT_CORE_API + auto get_current_thread_name() noexcept -> string; + STORMKIT_CORE_API + auto get_thread_name(const std::thread& thread) noexcept -> string; + STORMKIT_CORE_API + auto get_thread_name(const std::jthread& thread) noexcept -> string; + + template + requires(meta::IsSpecializationOf, std::future>) + inline auto wait_all(Range&& futures) noexcept { + for (auto&& future : std::forward(futures)) future.wait(); + } +}} // namespace stormkit::core diff --git a/modules/stormkit/core/string.mpp b/modules/stormkit/core/string.cppm similarity index 89% rename from modules/stormkit/core/string.mpp rename to modules/stormkit/core/string.cppm index e2c65a7d9..150a9e66c 100644 --- a/modules/stormkit/core/string.mpp +++ b/modules/stormkit/core/string.cppm @@ -1,11 +1,11 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -export module stormkit.core:string; - -export import :string.constexpr_string; -export import :string.czstring; -export import :string.encodings; -export import :string.format; -export import :string.operations; +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +export module stormkit.core:string; + +export import :string.constexpr_string; +export import :string.encodings; +export import :string.format; +export import :string.operations; +export import :string.aliases; diff --git a/modules/stormkit/core/string/aliases.cppm b/modules/stormkit/core/string/aliases.cppm new file mode 100644 index 000000000..6bb860ba3 --- /dev/null +++ b/modules/stormkit/core/string/aliases.cppm @@ -0,0 +1,35 @@ +// Copyright (C) 2023 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +export module stormkit.core:string.aliases; + +import std; + +namespace stdp = std::pmr; + +export namespace stormkit { inline namespace core { + using std::string; + using std::string_view; + using std::u16string; + using std::u16string_view; + using std::u32string; + using std::u32string_view; + using std::u8string; + using std::u8string_view; + using std::wstring; + using std::wstring_view; + + namespace pmr { + using stdp::string; + using stdp::u16string; + using stdp::u32string; + using stdp::u8string; + using stdp::wstring; + } // namespace pmr + + using czstring = const char*; + using zstring = char*; + using cwzstring = const wchar_t*; + using wzstring = wchar_t*; +}} // namespace stormkit::core diff --git a/modules/stormkit/core/string/constexpr_string.mpp b/modules/stormkit/core/string/constexpr_string.cppm similarity index 76% rename from modules/stormkit/core/string/constexpr_string.mpp rename to modules/stormkit/core/string/constexpr_string.cppm index 49a3aeedc..83346e843 100644 --- a/modules/stormkit/core/string/constexpr_string.mpp +++ b/modules/stormkit/core/string/constexpr_string.cppm @@ -10,10 +10,14 @@ export module stormkit.core:string.constexpr_string; import std; +import :containers.aliases; +import :string.aliases; +import :typesafe.integer; + namespace stdr = std::ranges; -export namespace stormkit { inline namespace core { - template +export namespace stormkit { inline namespace core { namespace meta { + template struct ConstexprString { consteval ConstexprString() noexcept = default; consteval ConstexprString(const char (&new_str)[N]) noexcept; @@ -23,31 +27,31 @@ export namespace stormkit { inline namespace core { [[nodiscard]] constexpr auto end(this auto& self) noexcept -> decltype(auto); [[nodiscard]] - constexpr auto size() const noexcept -> std::size_t; + constexpr auto size() const noexcept -> usize; [[nodiscard]] - constexpr auto view() const noexcept -> std::string_view; + constexpr auto view() const noexcept -> string_view; [[nodiscard]] - constexpr operator std::string_view() const noexcept; + constexpr operator string_view() const noexcept; constexpr auto update_size() noexcept -> void; static constexpr auto STATIC_SIZE = N - 1u; - std::array data = {}; - std::size_t m_size = 0; + array data = {}; + usize m_size = 0; }; -}} // namespace stormkit::core +}}} // namespace stormkit::core::meta //////////////////////////////////////////////////////////////////// /// IMPLEMENTATION /// //////////////////////////////////////////////////////////////////// -namespace stormkit { inline namespace core { +namespace stormkit { inline namespace core { namespace meta { ///////////////////////////////////// ///////////////////////////////////// - template + template STORMKIT_FORCE_INLINE consteval ConstexprString::ConstexprString(const char (&new_str)[N]) noexcept { std::copy_n(new_str, STATIC_SIZE, std::data(data)); @@ -56,7 +60,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// - template + template STORMKIT_FORCE_INLINE constexpr auto ConstexprString::begin(this auto& self) noexcept -> decltype(auto) { return stdr::begin(self.data); @@ -64,7 +68,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// - template + template STORMKIT_FORCE_INLINE constexpr auto ConstexprString::end(this auto& self) noexcept -> decltype(auto) { return stdr::begin(self.data) + static_cast(self.size()); @@ -72,33 +76,33 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// - template + template STORMKIT_FORCE_INLINE - constexpr auto ConstexprString::size() const noexcept -> std::size_t { + constexpr auto ConstexprString::size() const noexcept -> usize { return m_size; } ///////////////////////////////////// ///////////////////////////////////// - template + template STORMKIT_FORCE_INLINE - constexpr auto ConstexprString::view() const noexcept -> std::string_view { - return std::string_view { begin(), end() }; + constexpr auto ConstexprString::view() const noexcept -> string_view { + return string_view { begin(), end() }; } ///////////////////////////////////// ///////////////////////////////////// - template + template STORMKIT_FORCE_INLINE - constexpr ConstexprString::operator std::string_view() const noexcept { + constexpr ConstexprString::operator string_view() const noexcept { return view(); } ///////////////////////////////////// ///////////////////////////////////// - template + template STORMKIT_FORCE_INLINE constexpr auto ConstexprString::update_size() noexcept -> void { m_size = std::char_traits::length(stdr::data(data)); } -}} // namespace stormkit::core +}}} // namespace stormkit::core::meta diff --git a/modules/stormkit/core/string/czstring.mpp b/modules/stormkit/core/string/czstring.mpp deleted file mode 100644 index 173aaf483..000000000 --- a/modules/stormkit/core/string/czstring.mpp +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (C) 2023 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -export module stormkit.core:string.czstring; - -export namespace stormkit { inline namespace core { - using CZString = const char*; - using ZString = char*; - using CWZString = const wchar_t*; - using WZString = wchar_t*; -}} // namespace stormkit::core diff --git a/modules/stormkit/core/string/encodings.mpp b/modules/stormkit/core/string/encodings.cppm similarity index 68% rename from modules/stormkit/core/string/encodings.mpp rename to modules/stormkit/core/string/encodings.cppm index 77f63e4e0..09b1dfb97 100644 --- a/modules/stormkit/core/string/encodings.mpp +++ b/modules/stormkit/core/string/encodings.cppm @@ -18,19 +18,19 @@ import :typesafe.integer; import :typesafe.byte; export namespace stormkit { inline namespace core { - auto ascii_to_utf16(std::string_view) -> std::u16string; - auto utf16_to_ascii(std::u16string_view) -> std::string; + auto ascii_to_utf16(string_view) -> u16string; + auto utf16_to_ascii(u16string_view) -> string; - auto ascii_to_wide(std::string_view) -> std::wstring; - auto wide_to_ascii(std::wstring_view) -> std::string; + auto ascii_to_wide(string_view) -> wstring; + auto wide_to_ascii(wstring_view) -> string; - auto ascii_to_utf8(std::string_view) -> std::u8string; - auto utf8_to_ascii(std::u8string_view) -> std::string; + auto ascii_to_utf8(string_view) -> u8string; + auto utf8_to_ascii(u8string_view) -> string; #ifdef STORMKIT_COMPILER_MSVC - auto to_native_encoding(std::string_view) -> std::u16string; + auto to_native_encoding(string_view) -> u16string; #else - auto to_native_encoding(std::string_view) -> std::u8string; + auto to_native_encoding(string_view) -> u8string; #endif }} // namespace stormkit::core @@ -44,19 +44,15 @@ namespace stdr = std::ranges; namespace stormkit { inline namespace core { //////////////////////////////////////// //////////////////////////////////////// - inline auto ascii_to_utf16(std::string_view input) -> std::u16string { - auto output = std::u16string {}; + inline auto ascii_to_utf16(string_view input) -> u16string { + auto output = u16string {}; #if not defined(STORMKIT_COMPILER_CLANG) auto state = std::mbstate_t {}; output.resize(stdr::size(input)); auto len = 0ull; auto input_it = stdr::data(input); - while ((len = std::mbrtoc16(std::bit_cast(stdr::data(output)), - input_it, - MB_CUR_MAX, - &state)) - > 0ull) + while ((len = std::mbrtoc16(std::bit_cast(stdr::data(output)), input_it, MB_CUR_MAX, &state)) > 0ull) input_it += len; #else output = std::bit_cast(stdr::data(input)); @@ -67,14 +63,13 @@ namespace stormkit { inline namespace core { //////////////////////////////////////// //////////////////////////////////////// - inline auto utf16_to_ascii(std::u16string_view input) -> std::string { - auto output = std::string {}; + inline auto utf16_to_ascii(u16string_view input) -> string { + auto output = string {}; #if not defined(STORMKIT_COMPILER_CLANG) auto state = std::mbstate_t {}; output.resize(stdr::size(input)); - for (const auto& c : input) - std::c16rtomb(std::bit_cast(stdr::data(output)), c, &state); + for (const auto& c : input) std::c16rtomb(std::bit_cast(stdr::data(output)), c, &state); #else output = std::bit_cast(stdr::data(input)); #endif @@ -84,10 +79,10 @@ namespace stormkit { inline namespace core { //////////////////////////////////////// //////////////////////////////////////// - inline auto ascii_to_wide(std::string_view input) -> std::wstring { + inline auto ascii_to_wide(string_view input) -> wstring { [[maybe_unused]] auto state = std::mbstate_t {}; - auto output = std::wstring {}; + auto output = wstring {}; output.resize(stdr::size(input)); [[maybe_unused]] @@ -97,20 +92,12 @@ namespace stormkit { inline namespace core { [[maybe_unused]] auto i = 0; #if defined(STORMKIT_COMPILER_MSVC) - while ((len = std::mbrtoc16(std::bit_cast(stdr::data(output)) + i++, - input_it, - MB_CUR_MAX, - &state)) - > 0u) + while ((len = std::mbrtoc16(std::bit_cast(stdr::data(output)) + i++, input_it, MB_CUR_MAX, &state)) > 0u) input_it += len; #elif defined(STORMKIT_COMPILER_CLANG) output = std::bit_cast(stdr::data(input)); #else - while ((len = std::mbrtoc8(std::bit_cast(stdr::data(output)) + i++, - input_it, - MB_CUR_MAX, - &state)) - > 0ull) + while ((len = std::mbrtoc8(std::bit_cast(stdr::data(output)) + i++, input_it, MB_CUR_MAX, &state)) > 0ull) input_it += len; #endif @@ -119,11 +106,11 @@ namespace stormkit { inline namespace core { //////////////////////////////////////// //////////////////////////////////////// - inline auto wide_to_ascii(std::wstring_view input) -> std::string { + inline auto wide_to_ascii(wstring_view input) -> string { [[maybe_unused]] auto state = std::mbstate_t {}; [[maybe_unused]] - auto output = std::string {}; + auto output = string {}; output.resize(stdr::size(input)); #if defined(STORMKIT_COMPILER_MSVC) @@ -139,9 +126,9 @@ namespace stormkit { inline namespace core { //////////////////////////////////////// //////////////////////////////////////// - inline auto ascii_to_utf8(std::string_view input) -> std::u8string { + inline auto ascii_to_utf8(string_view input) -> u8string { [[maybe_unused]] - auto output = std::u8string {}; + auto output = u8string {}; output.resize(stdr::size(input) * narrow(MB_LEN_MAX)); #if defined(STORMKIT_COMPILER_MSVC) @@ -153,11 +140,7 @@ namespace stormkit { inline namespace core { auto len = 0ull; auto input_it = stdr::data(input); auto i = 0; - while ((len = std::mbrtoc8(std::bit_cast(stdr::data(output)) + i++, - input_it, - MB_CUR_MAX, - &state)) - > 0ull) + while ((len = std::mbrtoc8(std::bit_cast(stdr::data(output)) + i++, input_it, MB_CUR_MAX, &state)) > 0ull) input_it += len; #endif @@ -168,9 +151,9 @@ namespace stormkit { inline namespace core { //////////////////////////////////////// //////////////////////////////////////// - inline auto utf8_to_ascii(std::u8string_view input) -> std::string { + inline auto utf8_to_ascii(u8string_view input) -> string { [[maybe_unused]] - auto output = std::string {}; + auto output = string {}; output.resize(stdr::size(input)); #if defined(STORMKIT_COMPILER_MSVC) @@ -192,14 +175,14 @@ namespace stormkit { inline namespace core { //////////////////////////////////////// //////////////////////////////////////// STORMKIT_FORCE_INLINE - inline auto to_native_encoding(std::string_view input) -> std::u16string { + inline auto to_native_encoding(string_view input) -> u16string { return ascii_to_utf16(input); } #else //////////////////////////////////////// //////////////////////////////////////// STORMKIT_FORCE_INLINE - inline auto to_native_encoding(std::string_view input) -> std::u8string { + inline auto to_native_encoding(string_view input) -> u8string { return ascii_to_utf8(input); } #endif diff --git a/modules/stormkit/core/string/format.mpp b/modules/stormkit/core/string/format.cppm similarity index 71% rename from modules/stormkit/core/string/format.mpp rename to modules/stormkit/core/string/format.cppm index d8cdd09fe..ce29fdea0 100644 --- a/modules/stormkit/core/string/format.mpp +++ b/modules/stormkit/core/string/format.cppm @@ -1,200 +1,188 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -export module stormkit.core:string.format; - -import std; - -import :meta; -import :typesafe.integer; -import :typesafe.safecasts; -import :utils.time; -import :string.operations; - -export { - namespace stormkit { inline namespace core { - template - auto format_as(const T&, FormatContext&) noexcept -> FormatContext::iterator = delete; - - namespace meta { - template - inline constexpr auto DISABLE_DEFAULT_FORMATTER_FOR_ENUM = false; - - template - concept IsDefaultFormattedEnumeration = IsEnumeration - and not DISABLE_DEFAULT_FORMATTER_FOR_ENUM; - - template - concept HasFormatAs = requires(const T& val) { - { - format_as(val, std::declval()) - } -> Is; - }; - } // namespace meta - - inline constexpr struct { - template - static constexpr auto operator()(const T& value, FormatContext& ctx) noexcept - -> FormatContext::iterator { - return format_as(value, ctx); - } - } format_fn = {}; - - template - auto format_as(std::byte, FormatContext&) noexcept -> FormatContext::iterator; - - template - auto format_as(stormkit::Secondf, FormatContext&) noexcept -> FormatContext::iterator; - }} // namespace stormkit::core - - template - struct std::formatter { - template - [[nodiscard]] - constexpr auto parse(ParseContext&) noexcept -> ParseContext::iterator; - - template - [[nodiscard]] - auto format(const T&, FormatContext&) const noexcept -> FormatContext::iterator; - }; - - template - struct std::formatter { - template - [[nodiscard]] - constexpr auto parse(ParseContext&) noexcept -> ParseContext::iterator; - - template - [[nodiscard]] - auto format(const T&, FormatContext&) const -> FormatContext::iterator; - }; - - template - struct std::formatter: public formatter { - template - [[nodiscard]] - auto format(const T&, FormatContext&) const -> FormatContext::iterator; - }; - - template - struct std::formatter - : public formatter, CharT> { - template - [[nodiscard]] - auto format(const std::error_code&, FormatContext&) const -> FormatContext::iterator; - }; - - template - struct std::formatter: public formatter, CharT> { - template - [[nodiscard]] - auto format(const std::errc& code, FormatContext& ctx) const -> FormatContext::iterator; - }; -} - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit { inline namespace core { - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - inline auto format_as(std::byte value, FormatContext& ctx) noexcept -> FormatContext::iterator { - auto&& out = ctx.out(); - return std::format_to(out, "{}", narrow(value)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - inline auto format_as(Secondf value, FormatContext& ctx) noexcept -> FormatContext::iterator { - auto&& out = ctx.out(); - return std::format_to(out, "{}", value.count()); - } -}} // namespace stormkit::core - -using namespace stormkit; - -///////////////////////////////////// -///////////////////////////////////// -template -template -constexpr auto std::formatter::parse(ParseContext& ctx) noexcept - -> ParseContext::iterator { - return ctx.begin(); -} - -///////////////////////////////////// -///////////////////////////////////// -template -template -auto std::formatter::format(const T& value, FormatContext& ctx) const noexcept - -> FormatContext::iterator { - return core::format_fn(value, ctx); -} - -///////////////////////////////////// -///////////////////////////////////// -template -template -constexpr auto std::formatter::parse(ParseContext& ctx) noexcept - -> ParseContext::iterator { - return ctx.begin(); -} - -///////////////////////////////////// -///////////////////////////////////// -template -template -auto std::formatter::format(const T& value, FormatContext& ctx) const - -> FormatContext::iterator { - auto&& out = ctx.out(); - if constexpr (requires { - { as_string(value) } -> meta::Is; - }) { - const auto strvalue = as_string(value); - return format_to(out, "{}", strvalue); - } else - return format_to(out, "{}", as(value)); -} - -///////////////////////////////////// -///////////////////////////////////// -template -template -auto std::formatter::format(const T& value, FormatContext& ctx) const - -> FormatContext::iterator { - auto&& out = ctx.out(); - return format_to(out, "{:#0x}", std::bit_cast(std::to_address(value))); -} - -///////////////////////////////////// -///////////////////////////////////// -template -template -auto std::formatter::format(const std::error_code& code, - FormatContext& ctx) const - -> FormatContext::iterator { - auto&& out = ctx.out(); - const auto message = code.message(); - return format_to(out, "{}", message); -} - -///////////////////////////////////// -///////////////////////////////////// -template -template -auto std::formatter::format(const std::errc& code, FormatContext& ctx) const - -> FormatContext::iterator { - auto&& out = ctx.out(); - const auto message = make_error_code(code).message(); - return format_to(out, "{}", message); -} +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +export module stormkit.core:string.format; + +import std; + +import :meta; +import :typesafe.integer; +import :typesafe.safecasts; +import :utils.time; +import :string.operations; + +export { + namespace stormkit { inline namespace core { + template + auto format_as(const T&, FormatContext& ctx) noexcept -> decltype(ctx.out()) = delete; + + namespace meta { + template + inline constexpr auto DISABLE_DEFAULT_FORMATTER_FOR_ENUM = false; + + template + concept IsDefaultFormattedEnumeration = IsEnumeration and not DISABLE_DEFAULT_FORMATTER_FOR_ENUM; + + template + concept HasFormatAs = requires(const T& val) { + { format_as(val, std::declval()) } -> Is; + }; + } // namespace meta + + inline constexpr struct FormatFN { + template + static constexpr auto operator()(const T& value, FormatContext& ctx) noexcept -> decltype(ctx.out()) { + return format_as(value, ctx); + } + } format_fn = {}; + + template + auto format_as(std::byte, FormatContext& ctx) noexcept -> decltype(ctx.out()); + + template + auto format_as(stormkit::fsecond, FormatContext& ctx) noexcept -> decltype(ctx.out()); + }} // namespace stormkit::core + + template + struct std::formatter { + template + [[nodiscard]] + constexpr auto parse(ParseContext& ctx) noexcept -> decltype(ctx.begin()); + + template + [[nodiscard]] + auto format(const T&, FormatContext& ctx) const noexcept -> decltype(ctx.out()); + }; + + template + struct std::formatter { + template + [[nodiscard]] + constexpr auto parse(ParseContext& ctx) noexcept -> decltype(ctx.begin()); + + template + [[nodiscard]] + auto format(const T&, FormatContext& ctx) const -> decltype(ctx.out()); + }; + + template + struct std::formatter: public formatter { + template + [[nodiscard]] + auto format(const T&, FormatContext& ctx) const -> decltype(ctx.out()); + }; + + template + struct std::formatter: public formatter, CharT> { + template + [[nodiscard]] + auto format(const std::error_code&, FormatContext& ctx) const -> decltype(ctx.out()); + }; + + template + struct std::formatter: public formatter, CharT> { + template + [[nodiscard]] + auto format(const std::errc& code, FormatContext& ctx) const -> decltype(ctx.out()); + }; +} + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit { inline namespace core { + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto format_as(std::byte value, FormatContext& ctx) noexcept -> decltype(ctx.out()) { + auto&& out = ctx.out(); + return std::format_to(out, "{}", narrow(value)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto format_as(fsecond value, FormatContext& ctx) noexcept -> decltype(ctx.out()) { + auto&& out = ctx.out(); + return std::format_to(out, "{}", value.count()); + } +}} // namespace stormkit::core + +using namespace stormkit; + +///////////////////////////////////// +///////////////////////////////////// +template +template +constexpr auto std::formatter::parse(ParseContext& ctx) noexcept -> decltype(ctx.begin()) { + return ctx.begin(); +} + +///////////////////////////////////// +///////////////////////////////////// +template +template +auto std::formatter::format(const T& value, FormatContext& ctx) const noexcept -> decltype(ctx.out()) { + return core::format_fn(value, ctx); +} + +///////////////////////////////////// +///////////////////////////////////// +template +template +constexpr auto std::formatter::parse(ParseContext& ctx) noexcept -> decltype(ctx.begin()) { + return ctx.begin(); +} + +///////////////////////////////////// +///////////////////////////////////// +template +template +auto std::formatter::format(const T& value, FormatContext& ctx) const -> decltype(ctx.out()) { + auto&& out = ctx.out(); + if constexpr (requires { + { as_string(value) } -> meta::Is; + }) { + const auto strvalue = as_string(value); + return format_to(out, "{}", strvalue); + } else + return format_to(out, "{}", as(value)); +} + +///////////////////////////////////// +///////////////////////////////////// +template +template +auto std::formatter::format(const T& value, FormatContext& ctx) const -> decltype(ctx.out()) { + auto&& out = ctx.out(); + return format_to(out, "{:#0x}", std::bit_cast(std::to_address(value))); +} + +///////////////////////////////////// +///////////////////////////////////// +template +template +auto std::formatter::format(const std::error_code& code, FormatContext& ctx) const + -> decltype(ctx.out()) { + auto&& out = ctx.out(); + const auto message = code.message(); + return format_to(out, "{}", message); +} + +///////////////////////////////////// +///////////////////////////////////// +template +template +auto std::formatter::format(const std::errc& code, FormatContext& ctx) const -> decltype(ctx.out()) { + auto&& out = ctx.out(); + const auto message = make_error_code(code).message(); + return format_to(out, "{}", message); +} diff --git a/modules/stormkit/core/string/operations.mpp b/modules/stormkit/core/string/operations.cppm similarity index 56% rename from modules/stormkit/core/string/operations.mpp rename to modules/stormkit/core/string/operations.cppm index d19dc78c4..f79d08e3a 100644 --- a/modules/stormkit/core/string/operations.mpp +++ b/modules/stormkit/core/string/operations.cppm @@ -16,7 +16,7 @@ import :meta; import :typesafe.integer; -import :string.czstring; +import :string.aliases; import :typesafe.safecasts; @@ -25,67 +25,60 @@ namespace stdv = std::views; export namespace stormkit { inline namespace core { [[nodiscard]] - constexpr auto split(std::string_view string, std::string_view delim) noexcept - -> std::vector; + constexpr auto split(string_view str, string_view delim) noexcept -> dyn_array; [[nodiscard]] - constexpr auto to_lower(std::string_view string) noexcept -> std::string; + constexpr auto to_lower(string_view str) noexcept -> string; [[nodiscard]] - constexpr auto to_upper(std::string_view string) noexcept -> std::string; + constexpr auto to_upper(string_view str) noexcept -> string; [[nodiscard]] - auto to_lower(std::string_view string, const std::locale& locale) noexcept -> std::string; + auto to_lower(string_view str, const std::locale& locale) noexcept -> string; [[nodiscard]] - auto to_upper(std::string_view string, const std::locale& locale) noexcept -> std::string; + auto to_upper(string_view str, const std::locale& locale) noexcept -> string; [[nodiscard]] - constexpr auto replace(std::string_view in, - std::string_view pattern, - std::string_view replacement) noexcept -> std::string; + constexpr auto replace(string_view in, string_view pattern, string_view replacement) noexcept -> string; template [[nodiscard]] - constexpr auto as_string(T) noexcept -> std::string_view = delete; + constexpr auto as_string(T) noexcept -> string_view = delete; template [[nodiscard]] - constexpr auto to_string(T) noexcept -> std::string = delete; + constexpr auto to_string(T) noexcept -> string = delete; template [[nodiscard]] - constexpr auto from_string(std::string_view) noexcept -> T = delete; + constexpr auto from_string(string_view) noexcept -> T = delete; template requires(as_string(std::declval())) [[nodiscard]] - constexpr auto to_string(T&& value) noexcept -> std::string; + constexpr auto to_string(T&& value) noexcept -> string; template [[nodiscard]] - constexpr auto to_string(T value, i32 base = 10) noexcept - -> std::expected; + constexpr auto to_string(T value, i32 base = 10) noexcept -> std::expected; template [[nodiscard]] - auto to_string(T value, std::chars_format fmt = std::chars_format::general) noexcept - -> std::expected; + auto to_string(T value, std::chars_format fmt = std::chars_format::general) noexcept -> std::expected; template [[nodiscard]] - constexpr auto from_string(std::string_view data, i32 base = 10) noexcept - -> std::expected; + constexpr auto from_string(string_view data, i32 base = 10) noexcept -> std::expected; template [[nodiscard]] - auto from_string(std::string_view data, - std::chars_format fmt = std::chars_format::general) noexcept + auto from_string(string_view data, std::chars_format fmt = std::chars_format::general) noexcept -> std::expected; [[nodiscard]] - constexpr auto as_czstring(std::string_view value) noexcept -> CZString; + constexpr auto as_czstring(string_view value) noexcept -> czstring; template requires(as_string(std::declval())) [[nodiscard]] - constexpr auto as_czstring(T&& value) noexcept -> CZString; + constexpr auto as_czstring(T&& value) noexcept -> czstring; template constexpr auto is_text(T c) noexcept -> bool; @@ -114,31 +107,27 @@ namespace stormkit { inline namespace core { //////////////////////////////////////// //////////////////////////////////////// - constexpr auto split(std::string_view string, std::string_view delim) noexcept - -> std::vector { - return std::string_view { string } + constexpr auto split(string_view str, string_view delim) noexcept -> dyn_array { + return str | stdv::split(delim) - | stdv::transform([](auto&& subrange) { - return std::string_view { stdr::cbegin(subrange), stdr::cend(subrange) }; - }) - | stdr::to(); + | stdv::transform([](auto&& subrange) { return string_view { stdr::cbegin(subrange), stdr::cend(subrange) }; }) + | stdr::to>(); } //////////////////////////////////////// //////////////////////////////////////// STORMKIT_FORCE_INLINE - constexpr auto to_lower(std::string_view string) noexcept -> std::string { - auto result = std::string { string }; + constexpr auto to_lower(string_view str) noexcept -> string { + auto result = string { str }; for (auto& c : result) c = to_lower(c); return result; } //////////////////////////////////////// //////////////////////////////////////// - inline auto to_lower(std::string_view string, const std::locale& locale) noexcept - -> std::string { - auto result = std::string { string }; - auto& facet = std::use_facet>(locale); + inline auto to_lower(string_view str, const std::locale& locale) noexcept -> string { + auto result = string { str }; + auto& facet = std::use_facet>(locale); facet.tolower(&result[0], &result[0] + stdr::size(result)); return result; @@ -147,18 +136,17 @@ namespace stormkit { inline namespace core { //////////////////////////////////////// //////////////////////////////////////// STORMKIT_FORCE_INLINE - constexpr auto to_upper(std::string_view string) noexcept -> std::string { - auto result = std::string { string }; + constexpr auto to_upper(string_view str) noexcept -> string { + auto result = string { str }; for (auto& c : result) c = to_upper(c); return result; } //////////////////////////////////////// //////////////////////////////////////// - inline auto to_upper(std::string_view string, const std::locale& locale) noexcept - -> std::string { - auto result = std::string { string }; - auto& facet = std::use_facet>(locale); + inline auto to_upper(string_view str, const std::locale& locale) noexcept -> string { + auto result = string { str }; + auto& facet = std::use_facet>(locale); facet.toupper(&result[0], &result[0] + stdr::size(result)); return result; @@ -166,21 +154,19 @@ namespace stormkit { inline namespace core { //////////////////////////////////////// //////////////////////////////////////// - inline constexpr auto replace(std::string_view in, - std::string_view pattern, - std::string_view replacement) noexcept -> std::string { + inline constexpr auto replace(string_view in, string_view pattern, string_view replacement) noexcept -> string { return in | stdv::split(pattern) | stdv::transform([replacement](auto&& substr) noexcept { - auto out = std::string {}; + auto out = string {}; out.reserve(stdr::size(replacement) + stdr::size(substr)); out += replacement; - out += std::string_view { stdr::cbegin(substr), stdr::cend(substr) }; + out += string_view { stdr::cbegin(substr), stdr::cend(substr) }; return out; }) | stdv::join | stdv::drop(stdr::size(replacement)) - | stdr::to(); + | stdr::to(); } //////////////////////////////////////// @@ -188,20 +174,17 @@ namespace stormkit { inline namespace core { template requires(as_string(std::declval())) STORMKIT_FORCE_INLINE STORMKIT_PURE - constexpr auto to_string(T&& value) noexcept -> std::string { - return std::string { as_string(std::forward(value)) }; + constexpr auto to_string(T&& value) noexcept -> string { + return string { as_string(std::forward(value)) }; } //////////////////////////////////////// //////////////////////////////////////// template - constexpr auto to_string(T value, int base) noexcept -> std::expected { - auto out = std::expected { std::in_place }; + constexpr auto to_string(T value, int base) noexcept -> std::expected { + auto out = std::expected { std::in_place }; out->resize(16); - auto&& [ptr, errc] = std::to_chars(stdr::data(*out), - stdr::data(*out) + stdr::size(*out), - value, - base); + auto&& [ptr, errc] = std::to_chars(stdr::data(*out), stdr::data(*out) + stdr::size(*out), value, base); if (errc != std::errc {}) [[unlikely]] out = std::unexpected { std::in_place, std::move(errc) }; else { @@ -217,15 +200,11 @@ namespace stormkit { inline namespace core { // TODO add an argument to customize string buffer size template [[nodiscard]] - auto to_string(T value, std::chars_format fmt) noexcept - -> std::expected { - auto out = std::expected { std::in_place }; + auto to_string(T value, std::chars_format fmt) noexcept -> std::expected { + auto out = std::expected { std::in_place }; out->resize(16, '\0'); - auto&& [ptr, errc] = std::to_chars(stdr::data(*out), - stdr::data(*out) + stdr::size(*out), - value, - fmt); + auto&& [ptr, errc] = std::to_chars(stdr::data(*out), stdr::data(*out) + stdr::size(*out), value, fmt); if (errc != std::errc {}) [[unlikely]] out = std::unexpected { std::in_place, std::move(errc) }; else { @@ -239,13 +218,9 @@ namespace stormkit { inline namespace core { //////////////////////////////////////// //////////////////////////////////////// template - inline constexpr auto from_string(std::string_view data, i32 base) noexcept - -> std::expected { + inline constexpr auto from_string(string_view data, i32 base) noexcept -> std::expected { auto value = T {}; - auto&& [_, errc] = std::from_chars(stdr::data(data), - stdr::data(data) + stdr::size(data), - value, - base); + auto&& [_, errc] = std::from_chars(stdr::data(data), stdr::data(data) + stdr::size(data), value, base); if (errc != std::errc {}) [[unlikely]] return std::unexpected { std::in_place, std::move(errc) }; @@ -255,13 +230,9 @@ namespace stormkit { inline namespace core { //////////////////////////////////////// //////////////////////////////////////// template - inline auto from_string(std::string_view data, std::chars_format fmt) noexcept - -> std::expected { + inline auto from_string(string_view data, std::chars_format fmt) noexcept -> std::expected { auto value = T {}; - auto&& [_, errc] = std::from_chars(stdr::data(data), - stdr::data(data) + stdr::size(data), - value, - fmt); + auto&& [_, errc] = std::from_chars(stdr::data(data), stdr::data(data) + stdr::size(data), value, fmt); if (errc != std::errc {}) [[unlikely]] return std::unexpected { std::in_place, std::move(errc) }; @@ -271,7 +242,7 @@ namespace stormkit { inline namespace core { //////////////////////////////////////// //////////////////////////////////////// STORMKIT_FORCE_INLINE - constexpr auto as_czstring(std::string_view value) noexcept -> CZString { + constexpr auto as_czstring(string_view value) noexcept -> czstring { return stdr::data(value); } @@ -280,7 +251,7 @@ namespace stormkit { inline namespace core { template requires(as_string(std::declval())) STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto as_czstring(T value) noexcept -> CZString { + constexpr auto as_czstring(T value) noexcept -> czstring { return stdr::data(as_string(std::forward(value))); } diff --git a/modules/stormkit/core/typesafe.mpp b/modules/stormkit/core/typesafe.cppm similarity index 100% rename from modules/stormkit/core/typesafe.mpp rename to modules/stormkit/core/typesafe.cppm diff --git a/modules/stormkit/core/typesafe/boolean.mpp b/modules/stormkit/core/typesafe/boolean.cppm similarity index 95% rename from modules/stormkit/core/typesafe/boolean.mpp rename to modules/stormkit/core/typesafe/boolean.cppm index 81b51fe7e..051d421bb 100644 --- a/modules/stormkit/core/typesafe/boolean.mpp +++ b/modules/stormkit/core/typesafe/boolean.cppm @@ -41,7 +41,7 @@ export { }} // namespace stormkit::core - FORMATTER_INHERIT_DECLARE(bool, stormkit::meta::IsStrict) + FORMATTER_INHERIT_DECLARE(bool, stormkit::meta::SameAs) } //////////////////////////////////////////////////////////////////// @@ -106,6 +106,6 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// -FORMATTER_INHERIT_DEFINE_FORMAT(stormkit::meta::IsStrict) { +FORMATTER_INHERIT_DEFINE_FORMAT(stormkit::meta::SameAs) { return formatter::format(static_cast(data), ctx); } diff --git a/modules/stormkit/core/typesafe/byte.cppm b/modules/stormkit/core/typesafe/byte.cppm new file mode 100644 index 000000000..fc50adf93 --- /dev/null +++ b/modules/stormkit/core/typesafe/byte.cppm @@ -0,0 +1,380 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +#include + +export module stormkit.core:typesafe.byte; + +import std; + +import :meta; + +import :typesafe.integer; + +import :containers.aliases; + +import :utils.contract; +import :utils.tags; + +namespace stdr = std::ranges; +namespace stdp = std::pmr; + +template +consteval auto get_byte_extent_value_of() { + if constexpr (EXTENT == std::dynamic_extent) return EXTENT; + else if constexpr (stormkit::meta::Is, void>) + return EXTENT; + else + return EXTENT * sizeof(T); +} + +export namespace stormkit { inline namespace core { + using std::byte; + + template + using byte_view = array_view; + template + using byte_array = array; + using byte_dyn_array = dyn_array; + template + using byte_mut_view = array_view; + + namespace pmr { + using byte_dyn_array = dyn_array; + } // namespace pmr + + template + constexpr auto zero_bytes(T& value) noexcept -> void; + + template + constexpr auto zeroed() noexcept -> T; + + template + [[nodiscard]] + constexpr auto byte_swap(const T& value) noexcept -> T; + + // array_view + using std::as_bytes; + + template + [[nodiscard]] + constexpr auto as_bytes(const T* const ptr, usize size = 1) noexcept -> byte_view<>; + + template + [[nodiscard]] + constexpr auto as_bytes(const Range& range) noexcept -> byte_view<>; + + [[nodiscard]] + constexpr auto as_bytes(string_view string) noexcept -> byte_view<>; + + template + [[nodiscard]] + constexpr auto as_bytes(const T& value) noexcept -> byte_view; + + // array_view + template + [[nodiscard]] + constexpr auto as_bytes_mut(array_view container) noexcept -> byte_mut_view()>; + + template + [[nodiscard]] + constexpr auto as_bytes_mut(Range& range) noexcept -> byte_mut_view<>; + + template + [[nodiscard]] + constexpr auto as_bytes_mut(T* const ptr, usize size = 1) noexcept -> byte_mut_view<>; + + template + [[nodiscard]] + constexpr auto as_bytes_mut(T& value) noexcept -> byte_mut_view; + + template + [[nodiscard]] + constexpr auto bytes_as(byte_view bytes) noexcept -> const T&; + + template + requires(meta::SameAs>, byte>) + [[nodiscard]] + constexpr auto bytes_as_span(const Range& bytes) noexcept -> array_view; + + template + [[nodiscard]] + constexpr auto bytes_as_span(byte_view bytes) noexcept + -> array_view; + + template + [[nodiscard]] + constexpr auto bytes_mut_as(byte_mut_view bytes) noexcept -> T&; + + template + requires(meta::SameAs, byte> and not meta::IsConst) + [[nodiscard]] + constexpr auto bytes_mut_as_span(Range& range) noexcept -> array_view; + + template + [[nodiscard]] + constexpr auto bytes_mut_as_span(byte_mut_view bytes) noexcept + -> array_view; + + template + [[nodiscard]] + constexpr auto into_bytes(const T (&bytes)[N]) noexcept -> byte_array; + + namespace literals { + [[nodiscard]] + constexpr auto operator""_b(unsigned long long value) noexcept -> byte; + + [[nodiscard]] + constexpr auto operator""_kb(unsigned long long x) noexcept -> u64; + + [[nodiscard]] + constexpr auto operator""_mb(unsigned long long x) noexcept -> u64; + + [[nodiscard]] + constexpr auto operator""_gb(unsigned long long x) noexcept -> u64; + + [[nodiscard]] + constexpr auto operator""_kib(unsigned long long x) noexcept -> u64; + + [[nodiscard]] + constexpr auto operator""_mib(unsigned long long x) noexcept -> u64; + + [[nodiscard]] + constexpr auto operator""_gib(unsigned long long x) noexcept -> u64; + + } // namespace literals +}} // namespace stormkit::core + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit { inline namespace core { + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto zero_bytes(T& value) noexcept -> void { + auto bytes = as_bytes_mut(value); + stdr::fill(bytes, byte { 0 }); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto zeroed() noexcept -> T { + auto data = T {}; + zero_bytes(data); + return data; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto byte_swap(const T& value) noexcept -> T { + if constexpr (meta::IsIntegral) return std::byteswap(value); + else { + auto repr = std::bit_cast>(value); + + stdr::reverse(repr); + + return std::launder(std::bit_cast(repr)); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto as_bytes(const T* const ptr, usize size) noexcept -> byte_view<> { + return std::as_bytes(array_view { ptr, size }); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto as_bytes(const Range& range) noexcept -> byte_view<> { + return as_bytes(array_view { range }); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto as_bytes(string_view value) noexcept -> byte_view<> { + return std::as_bytes(array_view { stdr::data(value), stdr::size(value) }); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto as_bytes(const T& value) noexcept -> byte_view { + return std::as_bytes(array_view { &value, 1 }); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + constexpr auto as_bytes_mut(array_view container) noexcept + -> byte_mut_view()> { + return std::as_writable_bytes(container); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto as_bytes_mut(Range& range) noexcept -> byte_mut_view<> { + return as_bytes_mut(array_view { range }); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto as_bytes_mut(T* const ptr, usize size) noexcept -> byte_mut_view<> { + return std::as_writable_bytes(array_view { ptr, size }); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto as_bytes_mut(T& value) noexcept -> byte_mut_view { + return std::as_writable_bytes(array_view { &value, 1 }); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto bytes_as(byte_view bytes) noexcept -> const T& { + if constexpr (EXTENT != std::dynamic_extent) EXPECTS(EXTENT == sizeof(T)); + EXPECTS(stdr::size(bytes) == sizeof(T)); + return *std::launder(std::bit_cast(stdr::data(bytes))); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(meta::SameAs>, byte>) + STORMKIT_FORCE_INLINE + constexpr auto bytes_as_span(const Range& bytes) noexcept -> array_view { + return array_view { std::launder(std::bit_cast(stdr::data(bytes))), stdr::size(bytes) / sizeof(T) }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto bytes_as_span(byte_view bytes) noexcept + -> array_view { + if constexpr (EXTENT != std::dynamic_extent) + return array_view { std::bit_cast(stdr::data(bytes)), + EXTENT / sizeof(T) }; + else + return array_view { std::launder(std::bit_cast(stdr::data(bytes))), stdr::size(bytes) / sizeof(T) }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto bytes_mut_as(byte_mut_view bytes) noexcept -> T& { + if constexpr (EXTENT != std::dynamic_extent) EXPECTS(EXTENT == sizeof(T)); + EXPECTS(stdr::size(bytes) == sizeof(T)); + return *std::launder(std::bit_cast(stdr::data(bytes))); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(meta::SameAs, byte> and not meta::IsConst) + STORMKIT_FORCE_INLINE + constexpr auto bytes_mut_as_span(Range& bytes) noexcept -> array_view { + return array_view { std::launder(std::bit_cast(stdr::data(bytes))), stdr::size(bytes) / sizeof(T) }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto bytes_mut_as_span(byte_mut_view bytes) noexcept + -> array_view { + if constexpr (EXTENT != std::dynamic_extent) + return array_view { std::bit_cast(stdr::data(bytes)), EXTENT / sizeof(T) }; + else + return array_view { std::launder(std::bit_cast(stdr::data(bytes))), stdr::size(bytes) / sizeof(T) }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE STORMKIT_PURE + constexpr auto into_bytes(const T (&bytes)[N]) noexcept -> byte_array { + EXPECTS(static_cast(static_cast(bytes[0])) == bytes[0]); + auto out = byte_array {}; + auto i = 0_usize; + for (auto&& byte : bytes) out[i++] = static_cast(byte); + return out; + } + + namespace literals { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_CONST STORMKIT_INTRINSIC + constexpr auto operator""_b(unsigned long long value) noexcept -> byte { + return static_cast(value); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto operator""_kb(unsigned long long x) noexcept -> u64 { + return x * 1000ULL; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto operator""_mb(unsigned long long x) noexcept -> u64 { + return x * 1000_kb; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto operator""_gb(unsigned long long x) noexcept -> u64 { + return x * 1000_mb; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto operator""_kib(unsigned long long x) noexcept -> u64 { + return x * 1024; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto operator""_mib(unsigned long long x) noexcept -> u64 { + return x * 1024_kib; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto operator""_gib(unsigned long long x) noexcept -> u64 { + return x * 1024_mib; + } + } // namespace literals +}} // namespace stormkit::core diff --git a/modules/stormkit/core/typesafe/byte.mpp b/modules/stormkit/core/typesafe/byte.mpp deleted file mode 100644 index 7523b1545..000000000 --- a/modules/stormkit/core/typesafe/byte.mpp +++ /dev/null @@ -1,272 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -#include - -export module stormkit.core:typesafe.byte; - -import std; - -import :meta; - -import :typesafe.integer; - -import :utils.contract; -import :utils.tags; - -namespace stdr = std::ranges; - -export namespace stormkit { inline namespace core { - using Byte = std::byte; - using ByteView = std::span; - template - using ByteArray = std::array; - using ByteDynArray = std::vector; - using MutableByteView = std::span; - - template - constexpr auto zero_bytes(T& value) noexcept -> void; - - template - constexpr auto zeroed() noexcept -> T; - - template - [[nodiscard]] - constexpr auto byte_swap(const T& value) noexcept -> T; - - template - [[nodiscard]] - constexpr auto as_bytes(T& container) noexcept -> std::span>; - - template - [[nodiscard]] - constexpr auto as_bytes(T ptr, usize size = 1) noexcept - -> std::span, Byte>>; - - template - [[nodiscard]] - constexpr auto as_bytes(T& value) noexcept -> std::span>; - - template - [[nodiscard]] - constexpr auto as_bytes(T& value, Force) noexcept -> std::span>; - - template - requires(stdr::range and meta::IsOneOf) - [[nodiscard]] - constexpr auto bytes_as(Bytes& bytes) noexcept -> T; - - template - requires(meta::IsOneOf) - [[nodiscard]] - constexpr auto bytes_as(Bytes& bytes) noexcept - -> meta::ForwardConst; - - template - [[nodiscard]] - constexpr auto into_bytes(const T (&bytes)[N]) noexcept -> ByteArray; - - namespace literals { - [[nodiscard]] - constexpr auto operator""_b(unsigned long long value) noexcept -> Byte; - - [[nodiscard]] - constexpr auto operator""_kb(unsigned long long x) noexcept -> u64; - - [[nodiscard]] - constexpr auto operator""_mb(unsigned long long x) noexcept -> u64; - - [[nodiscard]] - constexpr auto operator""_gb(unsigned long long x) noexcept -> u64; - - [[nodiscard]] - constexpr auto operator""_kib(unsigned long long x) noexcept -> u64; - - [[nodiscard]] - constexpr auto operator""_mib(unsigned long long x) noexcept -> u64; - - [[nodiscard]] - constexpr auto operator""_gib(unsigned long long x) noexcept -> u64; - - } // namespace literals -}} // namespace stormkit::core - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit { inline namespace core { - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - inline constexpr auto zero_bytes(T& value) noexcept -> void { - auto bytes = as_bytes(value); - - std::memset(&bytes[0], 0, stdr::size(bytes)); - } - - template - STORMKIT_FORCE_INLINE - inline constexpr auto zeroed() noexcept -> T { - auto data = T {}; - zero_bytes(data); - return data; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_CONST - STORMKIT_FORCE_INLINE - inline constexpr auto byte_swap(const T& value) noexcept -> T { - auto repr = std::bit_cast>(value); - - stdr::reverse(repr); - - return std::bit_cast(repr); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - STORMKIT_PURE - inline constexpr auto as_bytes(T& container) noexcept - -> std::span> { - return as_bytes(stdr::data(container), stdr::size(container)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - STORMKIT_PURE - inline constexpr auto as_bytes(T ptr, usize size) noexcept - -> std::span, Byte>> { - auto raw_ptr = std::to_address(ptr); - - using PtrType = decltype(raw_ptr); - using ElementType = meta::ElementType; - using ByteType = meta::ForwardConst; - - constexpr auto byte_count = []() { - if constexpr (meta::Is) return 1; - else - return sizeof(ElementType); - }(); - - return std::span { std::bit_cast(raw_ptr), size * byte_count }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - STORMKIT_PURE - inline constexpr auto as_bytes(T& value) noexcept -> std::span> { - return as_bytes(&value, 1); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - STORMKIT_PURE - inline constexpr auto as_bytes(T& value, Force) noexcept - -> std::span> { - return as_bytes(&value, 1); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - requires(meta::IsOneOf) - STORMKIT_FORCE_INLINE - STORMKIT_PURE - inline constexpr auto bytes_as(Bytes& bytes) noexcept - -> meta::ForwardConst { - return *std::bit_cast< - meta::ForwardConst*>(stdr::data(bytes)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - requires(stdr::range and meta::IsOneOf) - STORMKIT_FORCE_INLINE - STORMKIT_PURE - inline constexpr auto bytes_as(Bytes& bytes) noexcept -> T { - using ElementType = typename T::element_type; - return T { std::bit_cast(stdr::data(bytes)), - stdr::size(bytes) * sizeof(ElementType) }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline constexpr auto into_bytes(const T (&bytes)[N]) noexcept -> ByteArray { - EXPECTS(static_cast(static_cast(bytes[0])) == bytes[0]); - auto out = ByteArray {}; - auto i = 0uz; - for (auto&& byte : bytes) out[i++] = static_cast(byte); - return out; - } - - namespace literals { - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE STORMKIT_INTRINSIC - inline constexpr auto operator""_b(unsigned long long value) noexcept -> Byte { - return static_cast(value); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline constexpr auto operator""_kb(unsigned long long x) noexcept -> u64 { - return x * 1000ULL; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline constexpr auto operator""_mb(unsigned long long x) noexcept -> u64 { - return x * 1000_kb; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline constexpr auto operator""_gb(unsigned long long x) noexcept -> u64 { - return x * 1000_mb; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline constexpr auto operator""_kib(unsigned long long x) noexcept -> u64 { - return x * 1024; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline constexpr auto operator""_mib(unsigned long long x) noexcept -> u64 { - return x * 1024_kib; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline constexpr auto operator""_gib(unsigned long long x) noexcept -> u64 { - return x * 1024_mib; - } - } // namespace literals -}} // namespace stormkit::core diff --git a/modules/stormkit/core/typesafe/character.mpp b/modules/stormkit/core/typesafe/character.cppm similarity index 100% rename from modules/stormkit/core/typesafe/character.mpp rename to modules/stormkit/core/typesafe/character.cppm diff --git a/modules/stormkit/core/typesafe/checked_value.mpp b/modules/stormkit/core/typesafe/checked_value.cppm similarity index 79% rename from modules/stormkit/core/typesafe/checked_value.mpp rename to modules/stormkit/core/typesafe/checked_value.cppm index 1a85ba89c..fdd44704a 100644 --- a/modules/stormkit/core/typesafe/checked_value.mpp +++ b/modules/stormkit/core/typesafe/checked_value.cppm @@ -4,6 +4,7 @@ module; +#include #include #include @@ -26,12 +27,10 @@ namespace stormkit { inline namespace core { namespace meta { template - concept IsCheckedValueArithmetic = meta::IsArithmetic< - meta::UnderlyingType>>; + concept IsCheckedValueArithmetic = meta::IsArithmetic>>; template - concept IsCheckedValueValueType = meta::PlainIs>>; + concept IsCheckedValueValueType = meta::PlainIs>>; } // namespace meta }} // namespace stormkit::core @@ -49,64 +48,52 @@ export namespace stormkit { inline namespace core { constexpr operator T() noexcept; - constexpr auto operator+(meta::PlainIs auto&& other) const noexcept - -> CheckedValue + constexpr auto operator+(meta::PlainIs auto&& other) const noexcept -> CheckedValue requires(meta::IsArithmetic); - constexpr auto operator+(meta::PlainIs auto&& other) const noexcept - -> CheckedValue + constexpr auto operator+(meta::PlainIs auto&& other) const noexcept -> CheckedValue requires(meta::IsArithmetic); constexpr auto operator+=(meta::PlainIs auto&& other) noexcept -> CheckedValue& requires(meta::IsArithmetic); - constexpr auto operator+=(meta::PlainIs auto&& other) noexcept - -> CheckedValue& + constexpr auto operator+=(meta::PlainIs auto&& other) noexcept -> CheckedValue& requires(meta::IsArithmetic); - constexpr auto operator-(meta::PlainIs auto&& other) const noexcept - -> CheckedValue + constexpr auto operator-(meta::PlainIs auto&& other) const noexcept -> CheckedValue requires(meta::IsArithmetic); - constexpr auto operator-(meta::PlainIs auto&& other) const noexcept - -> CheckedValue + constexpr auto operator-(meta::PlainIs auto&& other) const noexcept -> CheckedValue requires(meta::IsArithmetic); constexpr auto operator-=(meta::PlainIs auto&& other) noexcept -> CheckedValue& requires(meta::IsArithmetic); - constexpr auto operator-=(meta::PlainIs auto&& other) noexcept - -> CheckedValue& + constexpr auto operator-=(meta::PlainIs auto&& other) noexcept -> CheckedValue& requires(meta::IsArithmetic); - constexpr auto operator*(meta::PlainIs auto&& other) const noexcept - -> CheckedValue + constexpr auto operator*(meta::PlainIs auto&& other) const noexcept -> CheckedValue requires(meta::IsArithmetic); - constexpr auto operator*(meta::PlainIs auto&& other) const noexcept - -> CheckedValue + constexpr auto operator*(meta::PlainIs auto&& other) const noexcept -> CheckedValue requires(meta::IsArithmetic); constexpr auto operator*=(meta::PlainIs auto&& other) noexcept -> CheckedValue& requires(meta::IsArithmetic); - constexpr auto operator*=(meta::PlainIs auto&& other) noexcept - -> CheckedValue& + constexpr auto operator*=(meta::PlainIs auto&& other) noexcept -> CheckedValue& requires(meta::IsArithmetic); - constexpr auto operator/(meta::PlainIs auto&& other) const noexcept - -> CheckedValue + constexpr auto operator/(meta::PlainIs auto&& other) const noexcept -> CheckedValue requires(meta::IsArithmetic); - constexpr auto operator/(meta::PlainIs auto&& other) const noexcept - -> CheckedValue + constexpr auto operator/(meta::PlainIs auto&& other) const noexcept -> CheckedValue requires(meta::IsArithmetic); constexpr auto operator/=(meta::PlainIs auto&& other) noexcept -> CheckedValue& requires(meta::IsArithmetic); - constexpr auto operator/=(meta::PlainIs auto&& other) noexcept - -> CheckedValue& + constexpr auto operator/=(meta::PlainIs auto&& other) noexcept -> CheckedValue& requires(meta::IsArithmetic); T value; @@ -125,27 +112,22 @@ export namespace stormkit { inline namespace core { template requires(meta::IsCheckedValueArithmetic) - constexpr auto operator+(meta::IsCheckedValueValueType auto&& first, T&& second) noexcept - -> meta::ToPlainType; + constexpr auto operator+(meta::IsCheckedValueValueType auto&& first, T&& second) noexcept -> meta::ToPlainType; template requires(meta::IsCheckedValueArithmetic) - constexpr auto operator-(meta::IsCheckedValueValueType auto&& first, T&& second) noexcept - -> meta::ToPlainType; + constexpr auto operator-(meta::IsCheckedValueValueType auto&& first, T&& second) noexcept -> meta::ToPlainType; template requires(meta::IsCheckedValueArithmetic) - constexpr auto operator*(meta::IsCheckedValueValueType auto&& first, T&& second) noexcept - -> meta::ToPlainType; + constexpr auto operator*(meta::IsCheckedValueValueType auto&& first, T&& second) noexcept -> meta::ToPlainType; template requires(meta::IsCheckedValueArithmetic) - constexpr auto operator/(meta::IsCheckedValueValueType auto&& first, T&& second) noexcept - -> meta::ToPlainType; + constexpr auto operator/(meta::IsCheckedValueValueType auto&& first, T&& second) noexcept -> meta::ToPlainType; template - constexpr auto format_as(const CheckedValue& val, FormatContext& ctx) - -> decltype(ctx.out()); + constexpr auto format_as(const CheckedValue& val, FormatContext& ctx) -> decltype(ctx.out()); }} // namespace stormkit::core //////////////////////////////////////////////////////////////////// @@ -186,8 +168,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto CheckedValue::operator+(meta::PlainIs auto&& other) - const noexcept -> CheckedValue + constexpr auto CheckedValue::operator+(meta::PlainIs auto&& other) const noexcept -> CheckedValue requires(meta::IsArithmetic) { return { value + std::forward(other) }; @@ -197,8 +178,8 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto CheckedValue::operator+(meta::PlainIs auto&& - other) const noexcept -> CheckedValue + constexpr auto CheckedValue::operator+(meta::PlainIs auto&& other) const noexcept + -> CheckedValue requires(meta::IsArithmetic) { return operator+(std::forward_like(other.value)); @@ -208,8 +189,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_FORCE_INLINE - constexpr auto CheckedValue::operator+=(meta::PlainIs auto&& - other) noexcept -> CheckedValue& + constexpr auto CheckedValue::operator+=(meta::PlainIs auto&& other) noexcept -> CheckedValue& requires(meta::IsArithmetic) { value += std::forward(other); @@ -220,8 +200,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_FORCE_INLINE - constexpr auto CheckedValue::operator+=(meta::PlainIs auto&& - other) noexcept -> CheckedValue& + constexpr auto CheckedValue::operator+=(meta::PlainIs auto&& other) noexcept -> CheckedValue& requires(meta::IsArithmetic) { return operator+=(std::forward_like(other.value)); @@ -231,8 +210,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto CheckedValue::operator-(meta::PlainIs auto&& other) - const noexcept -> CheckedValue + constexpr auto CheckedValue::operator-(meta::PlainIs auto&& other) const noexcept -> CheckedValue requires(meta::IsArithmetic) { return { value - std::forward(other) }; @@ -242,8 +220,8 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto CheckedValue::operator-(meta::PlainIs auto&& - other) const noexcept -> CheckedValue + constexpr auto CheckedValue::operator-(meta::PlainIs auto&& other) const noexcept + -> CheckedValue requires(meta::IsArithmetic) { return operator-(std::forward_like(other.value)); @@ -253,8 +231,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_FORCE_INLINE - constexpr auto CheckedValue::operator-=(meta::PlainIs auto&& - other) noexcept -> CheckedValue& + constexpr auto CheckedValue::operator-=(meta::PlainIs auto&& other) noexcept -> CheckedValue& requires(meta::IsArithmetic) { value -= std::forward(other); @@ -265,8 +242,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_FORCE_INLINE - constexpr auto CheckedValue::operator-=(meta::PlainIs auto&& - other) noexcept -> CheckedValue& + constexpr auto CheckedValue::operator-=(meta::PlainIs auto&& other) noexcept -> CheckedValue& requires(meta::IsArithmetic) { return operator-=(std::forward_like(other.value)); @@ -276,8 +252,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto CheckedValue::operator*(meta::PlainIs auto&& other) - const noexcept -> CheckedValue + constexpr auto CheckedValue::operator*(meta::PlainIs auto&& other) const noexcept -> CheckedValue requires(meta::IsArithmetic) { return { value * std::forward(other) }; @@ -287,8 +262,8 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto CheckedValue::operator*(meta::PlainIs auto&& - other) const noexcept -> CheckedValue + constexpr auto CheckedValue::operator*(meta::PlainIs auto&& other) const noexcept + -> CheckedValue requires(meta::IsArithmetic) { return operator*(std::forward_like(other.value)); @@ -298,8 +273,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_FORCE_INLINE - constexpr auto CheckedValue::operator*=(meta::PlainIs auto&& - other) noexcept -> CheckedValue& + constexpr auto CheckedValue::operator*=(meta::PlainIs auto&& other) noexcept -> CheckedValue& requires(meta::IsArithmetic) { value *= std::forward(other); @@ -310,8 +284,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_FORCE_INLINE - constexpr auto CheckedValue::operator*=(meta::PlainIs auto&& - other) noexcept -> CheckedValue& + constexpr auto CheckedValue::operator*=(meta::PlainIs auto&& other) noexcept -> CheckedValue& requires(meta::IsArithmetic) { return operator*=(std::forward_like(other.value)); @@ -321,8 +294,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto CheckedValue::operator/(meta::PlainIs auto&& other) - const noexcept -> CheckedValue + constexpr auto CheckedValue::operator/(meta::PlainIs auto&& other) const noexcept -> CheckedValue requires(meta::IsArithmetic) { return { value / std::forward(other) }; @@ -332,8 +304,8 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto CheckedValue::operator/(meta::PlainIs auto&& - other) const noexcept -> CheckedValue + constexpr auto CheckedValue::operator/(meta::PlainIs auto&& other) const noexcept + -> CheckedValue requires(meta::IsArithmetic) { return operator/(std::forward_like(other.value)); @@ -343,8 +315,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_FORCE_INLINE - constexpr auto CheckedValue::operator/=(meta::PlainIs auto&& - other) noexcept -> CheckedValue& + constexpr auto CheckedValue::operator/=(meta::PlainIs auto&& other) noexcept -> CheckedValue& requires(meta::IsArithmetic) { value /= std::forward(other); @@ -355,8 +326,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_FORCE_INLINE - constexpr auto CheckedValue::operator/=(meta::PlainIs auto&& - other) noexcept -> CheckedValue& + constexpr auto CheckedValue::operator/=(meta::PlainIs auto&& other) noexcept -> CheckedValue& requires(meta::IsArithmetic) { return operator/=(std::forward_like(other.value)); @@ -367,8 +337,7 @@ namespace stormkit { inline namespace core { template requires(meta::IsCheckedValueArithmetic) STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto operator+(meta::IsCheckedValueValueType auto&& first, T&& second) noexcept - -> meta::ToPlainType { + constexpr auto operator+(meta::IsCheckedValueValueType auto&& first, T&& second) noexcept -> meta::ToPlainType { return std::forward(second).operator+(std::forward(first)); } @@ -377,8 +346,7 @@ namespace stormkit { inline namespace core { template requires(meta::IsCheckedValueArithmetic) STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto operator-(meta::IsCheckedValueValueType auto&& first, T&& second) noexcept - -> meta::ToPlainType { + constexpr auto operator-(meta::IsCheckedValueValueType auto&& first, T&& second) noexcept -> meta::ToPlainType { return std::forward(second).operator-(std::forward(first)); } @@ -387,8 +355,7 @@ namespace stormkit { inline namespace core { template requires(meta::IsCheckedValueArithmetic) STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto operator*(meta::IsCheckedValueValueType auto&& first, T&& second) noexcept - -> meta::ToPlainType { + constexpr auto operator*(meta::IsCheckedValueValueType auto&& first, T&& second) noexcept -> meta::ToPlainType { return std::forward(second).operator*(std::forward(first)); } @@ -397,8 +364,7 @@ namespace stormkit { inline namespace core { template requires(meta::IsCheckedValueArithmetic) STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto operator/(meta::IsCheckedValueValueType auto&& first, T&& second) noexcept - -> meta::ToPlainType { + constexpr auto operator/(meta::IsCheckedValueValueType auto&& first, T&& second) noexcept -> meta::ToPlainType { return std::forward(second).operator/(std::forward(first)); } @@ -406,20 +372,19 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_FORCE_INLINE - constexpr auto format_as(const CheckedValue& val, FormatContext& ctx) - -> decltype(ctx.out()) { + constexpr auto format_as(const CheckedValue& val, FormatContext& ctx) -> decltype(ctx.out()) { auto&& out = ctx.out(); return std::format_to(out, "{}", val.value); } #ifndef STORMKIT_OS_WINDOWS - #undef STORMKIT_API - #define STORMKIT_API + #undef STORMKIT_CORE_API + #define STORMKIT_CORE_API #endif -#define INSTANCIATE(t) \ - template struct STORMKIT_API CheckedValue>; \ - template struct STORMKIT_API CheckedValue> +#define INSTANCIATE(t) \ + template struct STORMKIT_CORE_API CheckedValue>; \ + template struct STORMKIT_CORE_API CheckedValue> INSTANCIATE(u8); INSTANCIATE(i8); diff --git a/modules/stormkit/core/typesafe/flags.mpp b/modules/stormkit/core/typesafe/flags.cppm similarity index 72% rename from modules/stormkit/core/typesafe/flags.mpp rename to modules/stormkit/core/typesafe/flags.cppm index f0269c1a0..ce0cccccb 100644 --- a/modules/stormkit/core/typesafe/flags.mpp +++ b/modules/stormkit/core/typesafe/flags.cppm @@ -1,319 +1,301 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -export module stormkit.core:typesafe.flags; - -import std; - -import :meta; - -import :string.constexpr_string; - -import :math.combinatoric; - -import :typesafe.integer; - -export { - namespace stormkit { inline namespace core { - namespace details { - template - struct EnableBitmaskOperators { - constexpr EnableBitmaskOperators() = default; - static constexpr auto enable = false; - }; - - template - inline constexpr auto BITMASK_OPERATORS_ENABLED = EnableBitmaskOperators::enable; - } // namespace details - - namespace meta { - template - concept IsFlag = (IsScopedEnumeration> - and core::details::BITMASK_OPERATORS_ENABLED) - or IsPlainEnumeration>; - } - - /// \brief Check if a flag bit is enabled - /// \requires `Enum` to be an enumeration promoted static_cast a flag with `FLAG_ENUM` - /// macro - /// \returns true if the flag big is set and false if not - template - [[nodiscard]] - constexpr auto check_flag_bit(const T& value, const T& flag) noexcept -> bool; - - /// \exclude - template - [[nodiscard]] - constexpr auto next_value(const T& value) noexcept -> T; - - template - consteval auto generate_substitutions_as_string_for(std::string_view prefix, - const std::array< - std::pair, - N>& mapping, - char separator = '|') noexcept - -> decltype(auto); - - template - consteval auto generate_substitutions_as_string_for(std::string_view prefix, - const std::array< - std::pair, - N>& mapping, - char separator = '|') noexcept - -> decltype(auto); - }} // namespace stormkit::core - - template - [[nodiscard]] - constexpr auto operator|(const T& lhs, const T& rhs) noexcept -> decltype(auto); - - template - [[nodiscard]] - constexpr auto operator&(const T& lhs, const T& rhs) noexcept -> decltype(auto); - - template - [[nodiscard]] - constexpr auto operator^(const T& lhs, const T& rhs) noexcept -> decltype(auto); - - template - [[nodiscard]] - constexpr auto operator~(const T& lhs) noexcept -> decltype(auto); - - template - constexpr auto operator|=(T& lhs, const T& rhs) noexcept -> decltype(auto); - - template - constexpr auto operator&=(T& lhs, const T& rhs) noexcept -> decltype(auto); - - template - constexpr auto operator^=(T& lhs, const T& rhs) noexcept -> decltype(auto); -} - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit { inline namespace core { - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr auto check_flag_bit(const T& value, const T& flag) noexcept -> bool { - return (value & flag) == flag; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr auto next_value(const T& value) noexcept -> T { - using Underlying = meta::UnderlyingType; - return static_cast(static_cast(value) << 1); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - consteval auto generate_substitutions_as_string_for(std::string_view prefix, - const std::array< - std::pair, - N>& mapping, - char separator) noexcept -> decltype(auto) { - constexpr auto OUT_SIZE = [] { - auto res = 0uz; - - constexpr auto n_fact = math::factoriel(N); - - if constexpr (static_cast(DEFAULT_VALUE) == 0) - for (auto R = 0uz; R < (N - 1); ++R) - res += n_fact / (math::factoriel(N - R) * math::factoriel(R)); - else - for (auto R = 0uz; R < N; ++R) - res += n_fact / (math::factoriel(N - R) * math::factoriel(R)); - - return res + 1; - }(); - - auto out = std::array>, OUT_SIZE> {}; - auto queue = std::vector> {}; - for (const auto& [k, v] : mapping) queue.emplace_back(k, std::string { v }, true); - - auto i = 0uz; - while (not stdr::empty(queue)) { - const auto [key, string, single_value] = queue.back(); - if (not stdr::any_of(out, [&key](auto& pair) noexcept { return pair.first == key; })) { - auto& [k, v] = out[i]; - k = key; - - auto out_string = std::string { prefix }; - if (single_value) out_string += string; - else { - out_string += "("; - out_string += string; - out_string += ")"; - } - - stdr::copy(out_string, stdr::begin(v)); - v.update_size(); - - i += 1; - } - if (key != DEFAULT_VALUE) { - for (const auto& [k, v] : mapping) { - const auto has_key = stdr::any_of(queue, - ([_k = k | key](auto&& tuple) noexcept { - const auto& [_key, _, _] = tuple; - return _key == _k; - })); - - if (not has_key) { - auto str = string; - if (k != DEFAULT_VALUE) { - str += " "; - str += separator; - str += " "; - str += v; - } - queue.emplace(stdr::begin(queue), key | k, str, false); - } - } - } - queue.pop_back(); - } - return out; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - consteval auto generate_substitutions_as_string_for(std::string_view prefix, - const std::array< - std::pair, - N>& mapping, - char separator) noexcept -> decltype(auto) { - constexpr auto OUT_SIZE = [] { - auto res = 0uz; - - constexpr auto n_fact = math::factoriel(N); - for (auto R = 0uz; R < N; ++R) - res += n_fact / (math::factoriel(N - R) * math::factoriel(R)); - - return res; - }(); - - auto out = std::array>, OUT_SIZE> {}; - auto queue = std::vector> {}; - for (const auto& [k, v] : mapping) queue.emplace_back(k, std::string { v }, true); - - auto i = 0uz; - while (not stdr::empty(queue)) { - const auto [key, string, single_value] = queue.back(); - if (not stdr::any_of(out, [&key](auto& pair) noexcept { return pair.first == key; })) { - auto& [k, v] = out[i]; - k = key; - - auto out_string = std::string { prefix }; - if (single_value) out_string += string; - else { - out_string += "("; - out_string += string; - out_string += ")"; - } - - stdr::copy(out_string, stdr::begin(v)); - v.update_size(); - - i += 1; - } - for (const auto& [k, v] : mapping) { - const auto has_key = stdr::any_of(queue, [_k = k | key](auto tuple) noexcept { - const auto& [_key, _, _] = tuple; - return _key == _k; - }); - - if (not has_key) - queue.emplace(stdr::begin(queue), - key | k, - string + " " + separator + " " + v, - false); - } - queue.pop_back(); - } - return out; - } -}} // namespace stormkit::core - -///////////////////////////////////// -///////////////////////////////////// -template -STORMKIT_FORCE_INLINE -constexpr auto operator|(const T& lhs, const T& rhs) noexcept -> decltype(auto) { - using namespace stormkit; - using Underlying = meta::UnderlyingType; - return static_cast(static_cast(lhs) | static_cast(rhs)); -} - -///////////////////////////////////// -///////////////////////////////////// -template -STORMKIT_FORCE_INLINE -constexpr auto operator&(const T& lhs, const T& rhs) noexcept -> decltype(auto) { - using namespace stormkit; - using Underlying = meta::UnderlyingType; - return static_cast(static_cast(lhs) & static_cast(rhs)); -} - -///////////////////////////////////// -///////////////////////////////////// -template -STORMKIT_FORCE_INLINE -constexpr auto operator^(const T& lhs, const T& rhs) noexcept -> decltype(auto) { - using namespace stormkit; - using Underlying = meta::UnderlyingType; - return static_cast(static_cast(lhs) ^ static_cast(rhs)); -} - -///////////////////////////////////// -///////////////////////////////////// -template -STORMKIT_FORCE_INLINE -constexpr auto operator~(const T& lhs) noexcept -> decltype(auto) { - using namespace stormkit; - using Underlying = meta::UnderlyingType; - return static_cast(~static_cast(lhs)); -} - -///////////////////////////////////// -///////////////////////////////////// -template -STORMKIT_FORCE_INLINE -constexpr auto operator|=(T& lhs, const T& rhs) noexcept -> decltype(auto) { - using namespace stormkit; - lhs = lhs | rhs; - return lhs; -} - -///////////////////////////////////// -///////////////////////////////////// -template -STORMKIT_FORCE_INLINE -constexpr auto operator&=(T& lhs, const T& rhs) noexcept -> decltype(auto) { - using namespace stormkit; - lhs = lhs & rhs; - return lhs; -} - -///////////////////////////////////// -///////////////////////////////////// -template -STORMKIT_FORCE_INLINE -constexpr auto operator^=(T& lhs, const T& rhs) noexcept -> decltype(auto) { - using namespace stormkit; - lhs = lhs ^ rhs; - return lhs; -} +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +export module stormkit.core:typesafe.flags; + +import std; + +import :meta; + +import :string.constexpr_string; +import :string.aliases; + +import :math.combinatoric; + +import :typesafe.integer; + +export { + namespace stormkit { inline namespace core { + namespace details { + template + struct EnableBitmaskOperators { + constexpr EnableBitmaskOperators() = default; + static constexpr auto enable = false; + }; + + template + inline constexpr auto BITMASK_OPERATORS_ENABLED = EnableBitmaskOperators::enable; + } // namespace details + + namespace meta { + template + concept IsFlag = (IsScopedEnumeration> and core::details::BITMASK_OPERATORS_ENABLED) + or IsPlainEnumeration>; + } + + /// \brief Check if a flag bit is enabled + /// \requires `Enum` to be an enumeration promoted static_cast a flag with `FLAG_ENUM` + /// macro + /// \returns true if the flag big is set and false if not + template + [[nodiscard]] + constexpr auto check_flag_bit(const T& value, const T& flag) noexcept -> bool; + + /// \exclude + template + [[nodiscard]] + constexpr auto next_value(const T& value) noexcept -> T; + + template + consteval auto generate_substitutions_as_string_for(string_view prefix, + const array, N>& mapping, + char separator = '|') noexcept -> decltype(auto); + + template + consteval auto generate_substitutions_as_string_for(string_view prefix, + const array, N>& mapping, + char separator = '|') noexcept -> decltype(auto); + }} // namespace stormkit::core + + template + [[nodiscard]] + constexpr auto operator|(const T& lhs, const T& rhs) noexcept -> decltype(auto); + + template + [[nodiscard]] + constexpr auto operator&(const T& lhs, const T& rhs) noexcept -> decltype(auto); + + template + [[nodiscard]] + constexpr auto operator^(const T& lhs, const T& rhs) noexcept -> decltype(auto); + + template + [[nodiscard]] + constexpr auto operator~(const T& lhs) noexcept -> decltype(auto); + + template + constexpr auto operator|=(T& lhs, const T& rhs) noexcept -> decltype(auto); + + template + constexpr auto operator&=(T& lhs, const T& rhs) noexcept -> decltype(auto); + + template + constexpr auto operator^=(T& lhs, const T& rhs) noexcept -> decltype(auto); +} + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit { inline namespace core { + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto check_flag_bit(const T& value, const T& flag) noexcept -> bool { + return (value & flag) == flag; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto next_value(const T& value) noexcept -> T { + using Underlying = meta::UnderlyingType; + return static_cast(static_cast(value) << 1); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + consteval auto generate_substitutions_as_string_for(string_view prefix, + const array, N>& mapping, + char separator) noexcept -> decltype(auto) { + constexpr auto OUT_SIZE = [] { + auto res = 0uz; + + constexpr auto n_fact = math::factoriel(N); + + if constexpr (static_cast(DEFAULT_VALUE) == 0) + for (auto R = 0uz; R < (N - 1); ++R) res += n_fact / (math::factoriel(N - R) * math::factoriel(R)); + else + for (auto R = 0uz; R < N; ++R) res += n_fact / (math::factoriel(N - R) * math::factoriel(R)); + + return res + 1; + }(); + + auto out = array>, OUT_SIZE> {}; + auto queue = dyn_array> {}; + for (const auto& [k, v] : mapping) queue.emplace_back(k, string { v }, true); + + auto i = 0uz; + while (not stdr::empty(queue)) { + const auto [key, str, single_value] = queue.back(); + if (not stdr::any_of(out, [&key](auto& pair) noexcept { return pair.first == key; })) { + auto& [k, v] = out[i]; + k = key; + + auto out_string = string { prefix }; + if (single_value) out_string += str; + else { + out_string += "("; + out_string += str; + out_string += ")"; + } + + stdr::copy(out_string, stdr::begin(v)); + v.update_size(); + + i += 1; + } + if (key != DEFAULT_VALUE) { + for (const auto& [k, v] : mapping) { + const auto has_key = stdr::any_of(queue, ([_k = k | key](auto&& tuple) noexcept { + const auto& [_key, _, _] = tuple; + return _key == _k; + })); + + if (not has_key) { + auto str2 = str; + if (k != DEFAULT_VALUE) { + str2 += " "; + str2 += separator; + str2 += " "; + str2 += v; + } + queue.emplace(stdr::begin(queue), key | k, str2, false); + } + } + } + queue.pop_back(); + } + return out; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + consteval auto generate_substitutions_as_string_for(string_view prefix, + const array, N>& mapping, + char separator) noexcept -> decltype(auto) { + constexpr auto OUT_SIZE = [] { + auto res = 0uz; + + constexpr auto n_fact = math::factoriel(N); + for (auto R = 0uz; R < N; ++R) res += n_fact / (math::factoriel(N - R) * math::factoriel(R)); + + return res; + }(); + + auto out = array>, OUT_SIZE> {}; + auto queue = dyn_array> {}; + for (const auto& [k, v] : mapping) queue.emplace_back(k, string { v }, true); + + auto i = 0uz; + while (not stdr::empty(queue)) { + const auto [key, str, single_value] = queue.back(); + if (not stdr::any_of(out, [&key](auto& pair) noexcept { return pair.first == key; })) { + auto& [k, v] = out[i]; + k = key; + + auto out_string = string { prefix }; + if (single_value) out_string += str; + else { + out_string += "("; + out_string += str; + out_string += ")"; + } + + stdr::copy(out_string, stdr::begin(v)); + v.update_size(); + + i += 1; + } + for (const auto& [k, v] : mapping) { + const auto has_key = stdr::any_of(queue, [_k = k | key](auto tuple) noexcept { + const auto& [_key, _, _] = tuple; + return _key == _k; + }); + + if (not has_key) queue.emplace(stdr::begin(queue), key | k, str + " " + separator + " " + v, false); + } + queue.pop_back(); + } + return out; + } +}} // namespace stormkit::core + +///////////////////////////////////// +///////////////////////////////////// +template +STORMKIT_FORCE_INLINE +constexpr auto operator|(const T& lhs, const T& rhs) noexcept -> decltype(auto) { + using namespace stormkit; + using Underlying = meta::UnderlyingType; + return static_cast(static_cast(lhs) | static_cast(rhs)); +} + +///////////////////////////////////// +///////////////////////////////////// +template +STORMKIT_FORCE_INLINE +constexpr auto operator&(const T& lhs, const T& rhs) noexcept -> decltype(auto) { + using namespace stormkit; + using Underlying = meta::UnderlyingType; + return static_cast(static_cast(lhs) & static_cast(rhs)); +} + +///////////////////////////////////// +///////////////////////////////////// +template +STORMKIT_FORCE_INLINE +constexpr auto operator^(const T& lhs, const T& rhs) noexcept -> decltype(auto) { + using namespace stormkit; + using Underlying = meta::UnderlyingType; + return static_cast(static_cast(lhs) ^ static_cast(rhs)); +} + +///////////////////////////////////// +///////////////////////////////////// +template +STORMKIT_FORCE_INLINE +constexpr auto operator~(const T& lhs) noexcept -> decltype(auto) { + using namespace stormkit; + using Underlying = meta::UnderlyingType; + return static_cast(~static_cast(lhs)); +} + +///////////////////////////////////// +///////////////////////////////////// +template +STORMKIT_FORCE_INLINE +constexpr auto operator|=(T& lhs, const T& rhs) noexcept -> decltype(auto) { + using namespace stormkit; + lhs = lhs | rhs; + return lhs; +} + +///////////////////////////////////// +///////////////////////////////////// +template +STORMKIT_FORCE_INLINE +constexpr auto operator&=(T& lhs, const T& rhs) noexcept -> decltype(auto) { + using namespace stormkit; + lhs = lhs & rhs; + return lhs; +} + +///////////////////////////////////// +///////////////////////////////////// +template +STORMKIT_FORCE_INLINE +constexpr auto operator^=(T& lhs, const T& rhs) noexcept -> decltype(auto) { + using namespace stormkit; + lhs = lhs ^ rhs; + return lhs; +} diff --git a/modules/stormkit/core/typesafe/float.mpp b/modules/stormkit/core/typesafe/float.cppm similarity index 91% rename from modules/stormkit/core/typesafe/float.mpp rename to modules/stormkit/core/typesafe/float.cppm index b221f5a7f..7260a6842 100644 --- a/modules/stormkit/core/typesafe/float.mpp +++ b/modules/stormkit/core/typesafe/float.cppm @@ -6,9 +6,7 @@ module; #include -#if not defined(__STDCPP_FLOAT32_T__) \ - or not defined(__STDCPP_FLOAT64_T__) \ - or not defined(__STDCPP_FLOAT128_T__) +#if not defined(__STDCPP_FLOAT32_T__) or not defined(__STDCPP_FLOAT64_T__) or not defined(__STDCPP_FLOAT128_T__) #ifdef STORMKIT_GLIBC #include #endif diff --git a/modules/stormkit/core/typesafe/integer.mpp b/modules/stormkit/core/typesafe/integer.cppm similarity index 98% rename from modules/stormkit/core/typesafe/integer.mpp rename to modules/stormkit/core/typesafe/integer.cppm index 8cf803372..fcc04e74a 100644 --- a/modules/stormkit/core/typesafe/integer.mpp +++ b/modules/stormkit/core/typesafe/integer.cppm @@ -41,7 +41,7 @@ export { using u32 = std::uint32_t; using u64 = std::uint64_t; #ifdef __SIZEOF_INT128__ - using u128 = unsigned __int128; + __extension__ using u128 = unsigned __int128; #elif defined(STORMKIT_COMPILER_MSVC) using u128 = std::_Unsigned128; #endif @@ -51,7 +51,7 @@ export { using i32 = std::int32_t; using i64 = std::int64_t; #ifdef __SIZEOF_INT128__ - using i128 = __int128; + __extension__ using i128 = __int128; #elif defined(STORMKIT_COMPILER_MSVC) using i128 = std::_Signed128; #else diff --git a/modules/stormkit/core/typesafe/ref.cppm b/modules/stormkit/core/typesafe/ref.cppm new file mode 100644 index 000000000..7a3bd59d9 --- /dev/null +++ b/modules/stormkit/core/typesafe/ref.cppm @@ -0,0 +1,1097 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +#include + +export module stormkit.core:typesafe.ref; + +import std; + +import :meta; + +import :utils.contract; + +import :typesafe.boolean; +import :typesafe.integer; + +import :hash; + +namespace stdr = std::ranges; +namespace stdv = std::views; + +export { + namespace stormkit { inline namespace core { + template + using ptr = T*; + template + using owned_ptr = T*; + + template + class ref; + + template + using optref = ref; + + inline constexpr struct Raw { + } RAW; + + template + class ref { + public: + using ElementType = T; + using referenceType = ElementType&; + using PointerType = ElementType*; + + // STL compatible + using element_type = ElementType; + using pointer = PointerType; + + constexpr ref(std::nullopt_t) noexcept + requires(Optional == true); + constexpr ref(std::nullptr_t) noexcept + requires(Optional == true); + constexpr ref() noexcept + requires(Optional == true); + constexpr ~ref() noexcept; + + template U, bool OptionalU> + requires(not(meta::IsConst and not meta::IsConst)) + constexpr ref(const ref&) noexcept; + template U, bool OptionalU> + requires(not(meta::IsConst and not meta::IsConst)) + constexpr ref(ref&&) noexcept; + + constexpr auto operator=(const ref&) noexcept -> ref& = delete; + + template U, bool OptionalU> + requires(not(meta::IsConst and not meta::IsConst)) + constexpr auto operator=(ref&& other) noexcept -> decltype(auto); + + [[nodiscard]] + constexpr auto get() const noexcept STORMKIT_LIFETIMEBOUND -> PointerType; + [[nodiscard]] + constexpr auto operator->() const noexcept STORMKIT_LIFETIMEBOUND->PointerType; + [[nodiscard]] + constexpr auto operator*() const noexcept STORMKIT_LIFETIMEBOUND->referenceType; + + constexpr explicit operator bool() const noexcept; + [[nodiscard]] + constexpr auto has_value() const noexcept -> Boolean; + + [[nodiscard]] + constexpr operator referenceType() const noexcept STORMKIT_LIFETIMEBOUND; + [[nodiscard]] + constexpr operator PointerType() const noexcept STORMKIT_LIFETIMEBOUND; + + [[nodiscard]] + constexpr auto operator==(std::nullptr_t) const noexcept -> bool; + [[nodiscard]] + constexpr auto operator<(std::nullptr_t) const noexcept -> bool; + [[nodiscard]] + constexpr auto operator<=(std::nullptr_t) const noexcept -> bool; + [[nodiscard]] + constexpr auto operator>(std::nullptr_t) const noexcept -> bool; + [[nodiscard]] + constexpr auto operator>=(std::nullptr_t) const noexcept -> bool; + [[nodiscard]] + constexpr auto operator<=>(std::nullptr_t) const noexcept + -> std::compare_three_way_result_t::PointerType, typename ref::PointerType> + requires std::three_way_comparable::PointerType, typename ref::PointerType> + ; + + [[nodiscard]] + constexpr auto operator==(std::nullopt_t) const noexcept -> bool + requires(Optional == true); + [[nodiscard]] + constexpr auto operator<(std::nullopt_t) const noexcept -> bool + requires(Optional == true); + [[nodiscard]] + constexpr auto operator<=(std::nullopt_t) const noexcept -> bool + requires(Optional == true); + [[nodiscard]] + constexpr auto operator>(std::nullopt_t) const noexcept -> bool + requires(Optional == true); + [[nodiscard]] + constexpr auto operator>=(std::nullopt_t) const noexcept -> bool + requires(Optional == true); + [[nodiscard]] + constexpr auto operator<=>(std::nullopt_t) const noexcept + -> std::compare_three_way_result_t::PointerType, typename ref::PointerType> + requires(std::three_way_comparable::PointerType, typename ref::PointerType> + and Optional == true); + + template + [[nodiscard]] + constexpr auto operator==(const ref&) const noexcept -> bool; + template + [[nodiscard]] + constexpr auto operator<(const ref&) const noexcept -> bool; + template + [[nodiscard]] + constexpr auto operator<=(const ref&) const noexcept -> bool; + template + [[nodiscard]] + constexpr auto operator>(const ref&) const noexcept -> bool; + template + [[nodiscard]] + constexpr auto operator>=(const ref&) const noexcept -> bool; + template + requires std::three_way_comparable::PointerType, + typename ref::PointerType> + [[nodiscard]] + constexpr auto operator<=>(const ref& other) const noexcept + -> std::compare_three_way_result_t::PointerType, typename ref::PointerType>; + + [[nodiscard]] + constexpr operator std::reference_wrapper() const noexcept; + + private: + constexpr ref(referenceType value STORMKIT_LIFETIMEBOUND) noexcept; + constexpr ref(PointerType value STORMKIT_LIFETIMEBOUND) noexcept; + + friend class ref; + friend class ref, T, const T>, not Optional>; + + PointerType m_value; + + template + friend constexpr auto as_ref_raw(const U&) noexcept -> ref; + + template + requires(not meta::IsConst) + friend constexpr auto as_ref_mut_raw(U&) noexcept -> ref; + + template + friend constexpr auto as_ref_like_raw(U&) noexcept -> ref; + + template + friend constexpr auto as_optref_raw(const U&) noexcept -> optref; + + template + requires(not meta::IsConst) + friend constexpr auto as_optref_mut_raw(U&) noexcept -> optref; + + template + friend constexpr auto as_optref_like_raw(U&) noexcept -> optref; + }; + + template + [[nodiscard]] + constexpr auto as_ref_raw(const T& value) noexcept -> ref; + + template + requires(not meta::IsContainerOrPointer) + [[nodiscard]] + constexpr auto as_ref(const T& value) noexcept -> ref; + + template + [[nodiscard]] + constexpr auto as_ref(const T& value) noexcept -> ref>; + + template + [[nodiscard]] + constexpr auto as_ref(const T& value) noexcept -> ref>; + + template + [[nodiscard]] + constexpr auto as_ref_mut_raw(const T& value) noexcept -> ref; + + template + requires(not meta::IsContainerOrPointer and not meta::IsConst) + [[nodiscard]] + constexpr auto as_ref_mut(T& value) noexcept -> ref; + + template + requires(not meta::IsConst>) + [[nodiscard]] + constexpr auto as_ref_mut(T& value) noexcept -> ref>; + + template + requires(not meta::IsConst>) + [[nodiscard]] + constexpr auto as_ref_mut(T& value) noexcept -> ref>; + + template + [[nodiscard]] + constexpr auto as_ref_mut_like(const T& value) noexcept -> ref; + + template + [[nodiscard]] + constexpr auto as_ref_like_raw(T& value) noexcept -> ref; + + template + requires(not meta::IsContainerOrPointer) + [[nodiscard]] + constexpr auto as_ref_like(T& value) noexcept -> ref; + + template + [[nodiscard]] + constexpr auto as_ref_like(T& value) noexcept -> ref>; + + template + [[nodiscard]] + constexpr auto as_ref_like(T& value) noexcept -> ref>; + + template + [[nodiscard]] + constexpr auto as_optref_raw(const T& value) noexcept -> optref; + + template + requires(not meta::IsContainerOrPointer) + [[nodiscard]] + constexpr auto as_optref(const T& value) noexcept -> optref; + + template + [[nodiscard]] + constexpr auto as_optref(const T& value) noexcept -> optref>; + + template + [[nodiscard]] + constexpr auto as_optref(const T& value) noexcept -> optref>; + + template + requires(not meta::IsConst) + [[nodiscard]] + constexpr auto as_optref_mut_raw(T& value) noexcept -> optref; + + template + requires(not meta::IsContainerOrPointer and not meta::IsConst) + [[nodiscard]] + constexpr auto as_optref_mut(T& value) noexcept -> optref; + + template + requires(not meta::IsConst>) + [[nodiscard]] + constexpr auto as_optref_mut(T& value) noexcept -> optref>; + + template + requires(not meta::IsConst>) + [[nodiscard]] + constexpr auto as_optref_mut(T& value) noexcept -> optref>; + + template + [[nodiscard]] + constexpr auto as_optref_like_raw(T& value) noexcept -> optref; + + template + requires(not meta::IsContainerOrPointer) + [[nodiscard]] + constexpr auto as_optref_like(T& value) noexcept -> optref; + + template + [[nodiscard]] + constexpr auto as_optref_like(T& value) noexcept -> optref>; + + template + [[nodiscard]] + constexpr auto as_optref_like(T& value) noexcept -> optref>; + + template + [[nodiscard]] + constexpr auto unref(const T& value) noexcept -> const meta::PointedType&; + + template + requires(not meta::IsConst>) + [[nodiscard]] + constexpr auto unref_mut(T& value) noexcept -> meta::PointedType&; + + template typename Out = array, typename... Args> + requires(not stdr::range and ...) + [[nodiscard]] + constexpr auto as_refs(Args&&... args) noexcept -> decltype(auto); + + template typename Out = dyn_array, typename... Args> + requires(not stdr::range and ...) + [[nodiscard]] + constexpr auto to_refs(Args&&... args) noexcept -> decltype(auto); + + template typename Out = array, typename... Args> + requires(not stdr::range and ...) + [[nodiscard]] + constexpr auto as_ref_muts(Args&&... args) noexcept -> decltype(auto); + + template typename Out = dyn_array, typename... Args> + requires(not stdr::range and ...) + [[nodiscard]] + constexpr auto to_ref_muts(Args&&... args) noexcept -> decltype(auto); + + template class Out = dyn_array, stdr::range T> + requires(stdr::range>) + [[nodiscard]] + constexpr auto to_refs(const T& range) noexcept -> decltype(auto); + + template class Out = dyn_array, stdr::range T> + requires(stdr::range>) + [[nodiscard]] + constexpr auto to_mut_refs(T& range) noexcept -> decltype(auto); + + template typename Out = array, typename... Args> + requires(not stdr::range and ...) + [[nodiscard]] + constexpr auto as_optrefs(Args&&... args) noexcept -> decltype(auto); + + template typename Out = dyn_array, typename... Args> + requires(not stdr::range and ...) + [[nodiscard]] + constexpr auto to_optrefs(Args&&... args) noexcept -> decltype(auto); + + template typename Out = array, typename... Args> + requires(not stdr::range and ...) + [[nodiscard]] + constexpr auto as_optref_muts(Args&&... args) noexcept -> decltype(auto); + + template typename Out = dyn_array, typename... Args> + requires(not stdr::range and ...) + [[nodiscard]] + constexpr auto to_optref_muts(Args&&... args) noexcept -> decltype(auto); + + template class Out = dyn_array, stdr::range T> + requires(stdr::range>) + [[nodiscard]] + constexpr auto to_optrefs(const T& range) noexcept -> decltype(auto); + + template class Out = dyn_array, stdr::range T> + requires(stdr::range>) + [[nodiscard]] + constexpr auto to_mut_optrefs(T& range) noexcept -> decltype(auto); + + template + constexpr auto hasher(const ref& value) noexcept -> Ret; + + template + auto format_as(const ref& value, FormatContext& ctx) noexcept -> decltype(ctx.out()); + }} // namespace stormkit::core + + template + struct std::pointer_traits> { + using pointer = typename stormkit::ref::PointerType; + using element_type = typename stormkit::ref::ElementType; + using difference_type = std::ptrdiff_t; + }; +} + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit { inline namespace core { + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr ref::ref() noexcept + requires(Optional == true) + : m_value { nullptr } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr ref::ref(std::nullopt_t) noexcept + requires(Optional == true) + : m_value { nullptr } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr ref::ref(std::nullptr_t) noexcept + requires(Optional == true) + : m_value { nullptr } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr ref::ref(referenceType value) noexcept + : m_value { &value } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr ref::ref(PointerType value) noexcept + : m_value { value } { + EXPECTS(m_value != nullptr); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr ref::~ref() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + template U, bool OptionalU> + requires(not(meta::IsConst and not meta::IsConst)) + STORMKIT_FORCE_INLINE + constexpr ref::ref(const ref& other) noexcept + : m_value { other.m_value } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + template U, bool OptionalU> + requires(not(meta::IsConst and not meta::IsConst)) + STORMKIT_FORCE_INLINE + constexpr ref::ref(ref&& other) noexcept + : m_value { std::exchange(other.m_value, nullptr) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + template U, bool OptionalU> + requires(not(meta::IsConst and not meta::IsConst)) + constexpr auto ref::operator=(ref&& other) noexcept -> decltype(auto) { + if constexpr (meta::SameAs and Optional == OptionalU) + if (&other == this) return *this; + + m_value = std::exchange(other.m_value, nullptr); + + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto ref::get() const noexcept -> PointerType { + return m_value; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto ref::operator->() const noexcept -> PointerType { + EXPECTS(m_value != nullptr); + return get(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto ref::operator*() const noexcept -> referenceType { + EXPECTS(m_value != nullptr); + return *get(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr ref::operator bool() const noexcept { + return m_value != nullptr; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto ref::has_value() const noexcept -> Boolean { + return operator bool(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr ref::operator referenceType() const noexcept { + EXPECTS(m_value != nullptr); + return *m_value; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr ref::operator PointerType() const noexcept { + return m_value; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto ref::operator==(std::nullptr_t) const noexcept -> bool { + return !m_value; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto ref::operator<(std::nullptr_t) const noexcept -> bool { + return std::less::pointer> {}(m_value, nullptr); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto ref::operator<=(std::nullptr_t) const noexcept -> bool { + return !(nullptr < *this); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto ref::operator>(std::nullptr_t) const noexcept -> bool { + return nullptr < *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto ref::operator>=(std::nullptr_t) const noexcept -> bool { + return !(*this < nullptr); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto ref::operator<=>(std::nullptr_t) const noexcept + -> std::compare_three_way_result_t::PointerType, typename ref::PointerType> + requires std::three_way_comparable::PointerType, typename ref::PointerType> + + { + return std::compare_three_way {}(m_value, static_cast::pointer>(nullptr)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto ref::operator==(std::nullopt_t) const noexcept -> bool + requires(Optional == true) + { + return !m_value; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto ref::operator<(std::nullopt_t) const noexcept -> bool + requires(Optional == true) + { + return std::less::pointer> {}(m_value, std::nullopt); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto ref::operator<=(std::nullopt_t) const noexcept -> bool + requires(Optional == true) + { + return !(std::nullopt < *this); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto ref::operator>(std::nullopt_t) const noexcept -> bool + requires(Optional == true) + { + return std::nullopt < *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto ref::operator>=(std::nullopt_t) const noexcept -> bool + requires(Optional == true) + { + return !(*this < std::nullopt); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto ref::operator<=>(std::nullopt_t) const noexcept + -> std::compare_three_way_result_t::PointerType, typename ref::PointerType> + requires(std::three_way_comparable::PointerType, typename ref::PointerType> + and Optional == true) + { + return std::compare_three_way {}(m_value, static_cast::pointer>(std::nullopt)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + template + STORMKIT_FORCE_INLINE + constexpr auto ref::operator==(const ref& other) const noexcept -> bool { + return m_value == other.m_value; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + template + STORMKIT_FORCE_INLINE + constexpr auto ref::operator<(const ref& other) const noexcept -> bool { + return std::less< + std::common_type_t::PointerType, typename ref::PointerType>> {}(m_value, other.m_value); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + template + STORMKIT_FORCE_INLINE + constexpr auto ref::operator<=(const ref& other) const noexcept -> bool { + return !(other < *this); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + template + STORMKIT_FORCE_INLINE + constexpr auto ref::operator>(const ref& other) const noexcept -> bool { + return other < *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + template + STORMKIT_FORCE_INLINE + constexpr auto ref::operator>=(const ref& other) const noexcept -> bool { + return !(*this < other); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + template + requires std::three_way_comparable::PointerType, typename ref::PointerType> + STORMKIT_FORCE_INLINE + constexpr auto ref::operator<=>(const ref& other) const noexcept + -> std::compare_three_way_result_t::PointerType, typename ref::PointerType> { + return m_value <=> other.m_value; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr ref::operator std::reference_wrapper() const noexcept { + if constexpr (meta::IsConst) return std::cref(*m_value); + else + return std::ref(*m_value); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto as_ref_raw(const T& value) noexcept -> ref { + return { std::addressof(value) }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(not meta::IsContainerOrPointer) + STORMKIT_FORCE_INLINE + constexpr auto as_ref(const T& value) noexcept -> ref { + return as_ref_raw(value); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto as_ref(const T& value) noexcept -> ref> { + EXPECTS(value != nullptr); + return as_ref(unref(value)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto as_ref(const T& value) noexcept -> ref> { + EXPECTS(value.operator bool()); + return as_ref(value.value()); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(not meta::IsConst) + STORMKIT_FORCE_INLINE + constexpr auto as_ref_mut_raw(T& value) noexcept -> ref { + return { std::addressof(value) }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(not meta::IsContainerOrPointer and not meta::IsConst) + STORMKIT_FORCE_INLINE + constexpr auto as_ref_mut(T& value) noexcept -> ref { + return as_ref_mut_raw(value); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(not meta::IsConst>) + STORMKIT_FORCE_INLINE + constexpr auto as_ref_mut(T& value) noexcept -> ref> { + EXPECTS(value != nullptr); + return as_ref_mut(unref_mut(value)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(not meta::IsConst>) + STORMKIT_FORCE_INLINE + constexpr auto as_ref_mut(T& value) noexcept -> ref> { + if constexpr (requires { value.has_value(); }) EXPECTS(value.has_value()); + return as_ref_mut(value.value()); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto as_ref_like_raw(T& value) noexcept -> ref { + return { std::addressof(value) }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(not meta::IsContainerOrPointer) + STORMKIT_FORCE_INLINE + constexpr auto as_ref_like(T& value, Raw) noexcept -> ref { + return as_ref_like_raw(value); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto as_ref_like(T& value) noexcept -> ref> { + EXPECTS(value != nullptr); + if (meta::IsConst>) return as_ref_like(unref(value)); + else + return as_ref_like(unref_mut(value)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto as_ref_like(T& value) noexcept -> ref> { + if constexpr (requires { value.has_value(); }) EXPECTS(value.has_value()); + return as_ref_like(value.value()); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto as_optref_raw(const T& value) noexcept -> optref { + return { std::addressof(value) }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(not meta::IsContainerOrPointer) + STORMKIT_FORCE_INLINE + constexpr auto as_optref(const T& value) noexcept -> optref { + return as_optref_raw(value); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto as_optref(const T& value) noexcept -> optref> { + EXPECTS(value != nullptr); + return as_optref(unref(value)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto as_optref(const T& value) noexcept -> optref> { + EXPECTS(value.operator bool()); + return as_optref(value.value()); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(not meta::IsConst) + STORMKIT_FORCE_INLINE + constexpr auto as_optref_mut_raw(T& value) noexcept -> optref { + return { std::addressof(value) }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(not meta::IsContainerOrPointer and not meta::IsConst) + STORMKIT_FORCE_INLINE + constexpr auto as_optref_mut(T& value) noexcept -> optref { + return as_optref_mut(value); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(not meta::IsConst>) + STORMKIT_FORCE_INLINE + constexpr auto as_optref_mut(T& value) noexcept -> optref> { + EXPECTS(value != nullptr); + return as_optref_mut(unref_mut(value)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(not meta::IsConst>) + STORMKIT_FORCE_INLINE + constexpr auto as_optref_mut(T& value) noexcept -> optref> { + if constexpr (requires { value.has_value(); }) EXPECTS(value.has_value()); + return as_optref_mut(value.value()); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto as_optref_like_raw(T& value) noexcept -> optref { + return { std::addressof(value) }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(not meta::IsContainerOrPointer) + STORMKIT_FORCE_INLINE + constexpr auto as_optref_like(T& value) noexcept -> optref { + return as_optref_like_raw(value); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto as_optref_like(T& value) noexcept -> optref> { + EXPECTS(value != nullptr); + if (meta::IsConst>) return as_optref_like(unref(value)); + else + return as_optref_like(unref_mut(value)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto as_optref_like(T& value) noexcept -> optref> { + if constexpr (requires { value.has_value(); }) EXPECTS(value.has_value()); + return as_optref_like(value.value()); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto unref(const T& value) noexcept -> const meta::PointedType& { + return *value; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(not meta::IsConst>) + STORMKIT_FORCE_INLINE + constexpr auto unref_mut(T& value) noexcept -> meta::PointedType& { + return *value; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template typename Out, typename... Args> + requires(not stdr::range and ...) + STORMKIT_FORCE_INLINE + constexpr auto as_refs(Args&&... args) noexcept -> decltype(auto) { + using ValueType = std::common_type_t>...>; + return Out, sizeof...(args)> { as_ref(std::forward(args))... }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template typename Out, typename... Args> + requires(not stdr::range and ...) + STORMKIT_FORCE_INLINE + constexpr auto to_refs(Args&&... args) noexcept -> decltype(auto) { + using ValueType = std::common_type_t>...>; + return Out> { as_ref(std::forward(args))... }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template typename Out, typename... Args> + requires(not stdr::range and ...) + STORMKIT_FORCE_INLINE + constexpr auto as_ref_muts(Args&&... args) noexcept -> decltype(auto) { + using ValueType = std::common_type_t>...>; + return Out, sizeof...(args)> { as_ref_mut(std::forward(args))... }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template typename Out, typename... Args> + requires(not stdr::range and ...) + STORMKIT_FORCE_INLINE + constexpr auto to_ref_muts(Args&&... args) noexcept -> decltype(auto) { + using ValueType = std::common_type_t>...>; + return Out> { as_ref_mut(std::forward(args))... }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template class Out, stdr::range T> + requires(stdr::range>) + STORMKIT_FORCE_INLINE + constexpr auto to_refs(const T& range) noexcept -> decltype(auto) { + using ValueType = stdr::range_value_t; + return range + | stdv::transform([](U&& val) static noexcept -> decltype(auto) { return as_ref(std::forward(val)); }) + | stdr::to>>(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template class Out, stdr::range T> + requires(stdr::range>) + STORMKIT_FORCE_INLINE + constexpr auto to_mut_refs(T& range) noexcept -> decltype(auto) { + using ValueType = stdr::range_value_t; + return range + | stdv::transform([](U&& val) static noexcept -> decltype(auto) { + return as_ref_mut(std::forward(val)); + }) + | stdr::to>>(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template typename Out, typename... Args> + requires(not stdr::range and ...) + STORMKIT_FORCE_INLINE + constexpr auto as_optrefs(Args&&... args) noexcept -> decltype(auto) { + using ValueType = std::common_type_t>...>; + return Out, sizeof...(args)> { as_optref(std::forward(args))... }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template typename Out, typename... Args> + requires(not stdr::range and ...) + STORMKIT_FORCE_INLINE + constexpr auto to_optrefs(Args&&... args) noexcept -> decltype(auto) { + using ValueType = std::common_type_t>...>; + return Out> { optas_ref(std::forward(args))... }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template typename Out, typename... Args> + requires(not stdr::range and ...) + STORMKIT_FORCE_INLINE + constexpr auto as_optref_muts(Args&&... args) noexcept -> decltype(auto) { + using ValueType = std::common_type_t>...>; + return Out, sizeof...(args)> { as_optref_mut(std::forward(args))... }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template typename Out, typename... Args> + requires(not stdr::range and ...) + STORMKIT_FORCE_INLINE + constexpr auto to_optref_muts(Args&&... args) noexcept -> decltype(auto) { + using ValueType = std::common_type_t>...>; + return Out> { as_optref_mut(std::forward(args))... }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template class Out, stdr::range T> + requires(stdr::range>) + STORMKIT_FORCE_INLINE + constexpr auto to_optrefs(const T& range) noexcept -> decltype(auto) { + using ValueType = stdr::range_value_t; + return range + | stdv::transform([](U&& val) static noexcept -> decltype(auto) { + return as_optref(std::forward(val)); + }) + | stdr::to>>(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template class Out, stdr::range T> + requires(stdr::range>) + STORMKIT_FORCE_INLINE + constexpr auto to_mut_optrefs(T& range) noexcept -> decltype(auto) { + using ValueType = stdr::range_value_t; + return range + | stdv::transform([](U&& val) static noexcept -> decltype(auto) { + return as_optref_mut(std::forward(val)); + }) + | stdr::to>>(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto hasher(const ref& value) noexcept -> Ret { + return hash(value.get()); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + inline auto format_as(const ref& value, FormatContext& ctx) noexcept -> decltype(ctx.out()) { + if constexpr (Optional) { + if (value == nullptr) return std::format_to(ctx.out(), "[ref value: null]"); + else + return std::format_to(ctx.out(), "[ref value: {}]", *value); + } else + return std::format_to(ctx.out(), "[ref value: {}]", *value); + } +}} // namespace stormkit::core diff --git a/modules/stormkit/core/typesafe/ref.mpp b/modules/stormkit/core/typesafe/ref.mpp deleted file mode 100644 index b3512d0e5..000000000 --- a/modules/stormkit/core/typesafe/ref.mpp +++ /dev/null @@ -1,826 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -#include - -#include - -export module stormkit.core:typesafe.ref; - -import std; - -import :meta; - -import :utils.contract; - -import :typesafe.boolean; -import :typesafe.integer; - -import :hash; - -export { - namespace stormkit { inline namespace core { - template - using ptr = T*; - - template - class [[nodiscard, gsl::Pointer]] - Ref { - public: - using ElementType = T; - using ReferenceType = ElementType&; - using PointerType = ElementType*; - - // STL compatible - using element_type = ElementType; - using pointer = PointerType; - - constexpr Ref(std::nullopt_t) noexcept - requires(Optional == true); - constexpr Ref(std::nullptr_t) noexcept - requires(Optional == true); - constexpr Ref() noexcept - requires(Optional == true); - constexpr ~Ref() noexcept; - - template U, bool OptionalU> - requires(not(meta::IsConst and not meta::IsConst)) - constexpr Ref(const Ref&) noexcept; - template U, bool OptionalU> - requires(not(meta::IsConst and not meta::IsConst)) - constexpr Ref(Ref&&) noexcept; - - constexpr auto operator=(const Ref&) noexcept -> Ref& = delete; - - template U, bool OptionalU> - requires(not(meta::IsConst and not meta::IsConst)) - constexpr auto operator=(Ref&& other) noexcept -> decltype(auto); - - [[nodiscard]] - constexpr auto get() const noexcept STORMKIT_LIFETIMEBOUND -> PointerType; - [[nodiscard]] - constexpr auto operator->() const noexcept STORMKIT_LIFETIMEBOUND->PointerType; - [[nodiscard]] - constexpr auto operator*() const noexcept STORMKIT_LIFETIMEBOUND->ReferenceType; - - constexpr explicit operator bool() const noexcept; - [[nodiscard]] - constexpr auto has_value() const noexcept -> Boolean; - - [[nodiscard]] - constexpr operator ReferenceType() const noexcept STORMKIT_LIFETIMEBOUND; - [[nodiscard]] - constexpr operator PointerType() const noexcept STORMKIT_LIFETIMEBOUND; - - [[nodiscard]] - constexpr auto operator==(std::nullptr_t) const noexcept -> bool; - [[nodiscard]] - constexpr auto operator<(std::nullptr_t) const noexcept -> bool; - [[nodiscard]] - constexpr auto operator<=(std::nullptr_t) const noexcept -> bool; - [[nodiscard]] - constexpr auto operator>(std::nullptr_t) const noexcept -> bool; - [[nodiscard]] - constexpr auto operator>=(std::nullptr_t) const noexcept -> bool; - [[nodiscard]] - constexpr auto operator<=>(std::nullptr_t) const noexcept - -> std::compare_three_way_result_t::PointerType, - typename Ref::PointerType> - requires std::three_way_comparable::PointerType, - typename Ref::PointerType>; - - [[nodiscard]] - constexpr auto operator==(std::nullopt_t) const noexcept -> bool - requires(Optional == true); - [[nodiscard]] - constexpr auto operator<(std::nullopt_t) const noexcept -> bool - requires(Optional == true); - [[nodiscard]] - constexpr auto operator<=(std::nullopt_t) const noexcept -> bool - requires(Optional == true); - [[nodiscard]] - constexpr auto operator>(std::nullopt_t) const noexcept -> bool - requires(Optional == true); - [[nodiscard]] - constexpr auto operator>=(std::nullopt_t) const noexcept -> bool - requires(Optional == true); - [[nodiscard]] - constexpr auto operator<=>(std::nullopt_t) const noexcept - -> std::compare_three_way_result_t::PointerType, - typename Ref::PointerType> - requires(std::three_way_comparable::PointerType, - typename Ref::PointerType> - and Optional == true); - - template - [[nodiscard]] - constexpr auto operator==(const Ref&) const noexcept -> bool; - template - [[nodiscard]] - constexpr auto operator<(const Ref&) const noexcept -> bool; - template - [[nodiscard]] - constexpr auto operator<=(const Ref&) const noexcept -> bool; - template - [[nodiscard]] - constexpr auto operator>(const Ref&) const noexcept -> bool; - template - [[nodiscard]] - constexpr auto operator>=(const Ref&) const noexcept -> bool; - template - requires std::three_way_comparable::PointerType, - typename Ref::PointerType> - [[nodiscard]] - constexpr auto operator<=>(const Ref& other) const noexcept - -> std::compare_three_way_result_t::PointerType, - typename Ref::PointerType>; - - [[nodiscard]] - constexpr operator std::reference_wrapper() const noexcept; - - private: - constexpr Ref(ReferenceType value STORMKIT_LIFETIMEBOUND) noexcept; - constexpr Ref(PointerType value STORMKIT_LIFETIMEBOUND) noexcept; - - friend class Ref; - friend class Ref, T, const T>, not Optional>; - - PointerType m_value; - - template - friend constexpr auto as_ref(U&& value) noexcept -> decltype(auto); - - template - friend constexpr auto as_ref_mut(U&& value) noexcept -> decltype(auto); - - template - friend constexpr auto as_ref_like(U&& value) noexcept -> decltype(auto); - - template - friend constexpr auto as_opt_ref(U&& value) noexcept -> decltype(auto); - - template - friend constexpr auto as_opt_ref_mut(U&& value) noexcept -> decltype(auto); - - template - friend constexpr auto as_opt_ref_like(U&& value) noexcept -> decltype(auto); - }; - - template - using OptionalRef = Ref; - - template - [[nodiscard]] - constexpr auto as_ref(T&& value STORMKIT_LIFETIMEBOUND) noexcept -> decltype(auto); - - template - [[nodiscard]] - constexpr auto as_ref_mut(T&& value STORMKIT_LIFETIMEBOUND) noexcept -> decltype(auto); - - template - [[nodiscard]] - constexpr auto as_ref_like(T&& value STORMKIT_LIFETIMEBOUND) noexcept -> decltype(auto); - - template - [[nodiscard]] - constexpr auto as_opt_ref(T&& value STORMKIT_LIFETIMEBOUND) noexcept -> decltype(auto); - - template - [[nodiscard]] - constexpr auto as_opt_ref_mut(T&& value STORMKIT_LIFETIMEBOUND) noexcept -> decltype(auto); - - template - [[nodiscard]] - constexpr auto as_opt_ref_like(T&& value STORMKIT_LIFETIMEBOUND) noexcept -> decltype(auto); - - template - [[nodiscard]] - constexpr auto unref(const Ref& value STORMKIT_LIFETIMEBOUND) noexcept -> const T&; - - template - [[nodiscard]] - constexpr auto unref_mut(const Ref& value STORMKIT_LIFETIMEBOUND) noexcept -> T&; - - template typename Out = std::array, typename... Args> - requires(not std::ranges::range and ...) - [[nodiscard]] - constexpr auto as_refs(Args&&... args) noexcept -> decltype(auto); - - template typename Out = std::vector, typename... Args> - requires(not std::ranges::range and ...) - [[nodiscard]] - constexpr auto to_refs(Args&&... args) noexcept -> decltype(auto); - - template typename Out = std::array, typename... Args> - requires(not std::ranges::range and ...) - [[nodiscard]] - constexpr auto as_ref_muts(Args&&... args) noexcept -> decltype(auto); - - template typename Out = std::vector, typename... Args> - requires(not std::ranges::range and ...) - [[nodiscard]] - constexpr auto to_ref_muts(Args&&... args) noexcept -> decltype(auto); - - template class Out = std::vector, std::ranges::range T> - requires(std::ranges::range>) - [[nodiscard]] - constexpr auto to_refs(const T& range) noexcept -> decltype(auto); - - template class Out = std::vector, std::ranges::range T> - requires(std::ranges::range>) - [[nodiscard]] - constexpr auto to_mut_refs(T& range) noexcept -> decltype(auto); - template typename Out = std::array, typename... Args> - requires(not std::ranges::range and ...) - - [[nodiscard]] - constexpr auto as_opt_refs(Args&&... args) noexcept -> decltype(auto); - - template typename Out = std::vector, typename... Args> - requires(not std::ranges::range and ...) - [[nodiscard]] - constexpr auto to_opt_refs(Args&&... args) noexcept -> decltype(auto); - - template typename Out = std::array, typename... Args> - requires(not std::ranges::range and ...) - [[nodiscard]] - constexpr auto as_opt_ref_muts(Args&&... args) noexcept -> decltype(auto); - - template typename Out = std::vector, typename... Args> - requires(not std::ranges::range and ...) - [[nodiscard]] - constexpr auto to_opt_ref_muts(Args&&... args) noexcept -> decltype(auto); - - template class Out = std::vector, std::ranges::range T> - requires(std::ranges::range>) - [[nodiscard]] - constexpr auto to_opt_refs(const T& range) noexcept -> decltype(auto); - - template class Out = std::vector, std::ranges::range T> - requires(std::ranges::range>) - [[nodiscard]] - constexpr auto to_mut_opt_refs(T& range) noexcept -> decltype(auto); - }} // namespace stormkit::core - - namespace std { - template - struct pointer_traits> { - using pointer = typename stormkit::Ref::PointerType; - using element_type = typename stormkit::Ref::ElementType; - using difference_type = std::ptrdiff_t; - }; - - template - struct hash> { - [[nodiscard]] - auto operator()(const stormkit::Ref& ref) const noexcept -> stormkit::u64; - }; - } // namespace std -} - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit { inline namespace core { - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr Ref::Ref() noexcept - requires(Optional == true) - : m_value { nullptr } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr Ref::Ref(std::nullopt_t) noexcept - requires(Optional == true) - : m_value { nullptr } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr Ref::Ref(std::nullptr_t) noexcept - requires(Optional == true) - : m_value { nullptr } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr Ref::Ref(ReferenceType value) noexcept - : m_value { &value } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr Ref::Ref(PointerType value) noexcept - : m_value { value } { - EXPECTS(m_value != nullptr); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr Ref::~Ref() noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - template - template U, bool OptionalU> - requires(not(meta::IsConst and not meta::IsConst)) - STORMKIT_FORCE_INLINE - constexpr Ref::Ref(const Ref& other) noexcept - : m_value { other.m_value } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - template U, bool OptionalU> - requires(not(meta::IsConst and not meta::IsConst)) - STORMKIT_FORCE_INLINE - constexpr Ref::Ref(Ref&& other) noexcept - : m_value { std::exchange(other.m_value, nullptr) } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - template U, bool OptionalU> - requires(not(meta::IsConst and not meta::IsConst)) - constexpr auto Ref::operator=(Ref&& other) noexcept - -> decltype(auto) { - if constexpr (meta::IsStrict) - if (&other == this) return *this; - - m_value = std::exchange(other.m_value, nullptr); - - return *this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr auto Ref::get() const noexcept -> PointerType { - return m_value; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr auto Ref::operator->() const noexcept -> PointerType { - EXPECTS(m_value != nullptr); - return get(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr auto Ref::operator*() const noexcept -> ReferenceType { - EXPECTS(m_value != nullptr); - return *get(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr Ref::operator bool() const noexcept { - return m_value != nullptr; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr auto Ref::has_value() const noexcept -> Boolean { - return operator bool(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr Ref::operator ReferenceType() const noexcept { - EXPECTS(m_value != nullptr); - return *m_value; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr Ref::operator PointerType() const noexcept { - return m_value; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr auto Ref::operator==(std::nullptr_t) const noexcept -> bool { - return !m_value; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr auto Ref::operator<(std::nullptr_t) const noexcept -> bool { - return std::less::pointer> {}(m_value, nullptr); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr auto Ref::operator<=(std::nullptr_t) const noexcept -> bool { - return !(nullptr < *this); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr auto Ref::operator>(std::nullptr_t) const noexcept -> bool { - return nullptr < *this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr auto Ref::operator>=(std::nullptr_t) const noexcept -> bool { - return !(*this < nullptr); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr auto Ref::operator<=>(std::nullptr_t) const noexcept - -> std::compare_three_way_result_t::PointerType, - typename Ref::PointerType> - requires std::three_way_comparable::PointerType, - typename Ref::PointerType> - - { - return std::compare_three_way {}(m_value, - static_cast::pointer>(nullptr)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - template - STORMKIT_FORCE_INLINE - constexpr auto Ref::operator==(const Ref& other) const noexcept - -> bool { - return m_value == other.value(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - template - STORMKIT_FORCE_INLINE - constexpr auto Ref::operator<(const Ref& other) const noexcept - -> bool { - return std::less< - std::common_type_t::PointerType, - typename Ref::PointerType>> {}(m_value, other.m_value); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - template - STORMKIT_FORCE_INLINE - constexpr auto Ref::operator<=(const Ref& other) const noexcept - -> bool { - return !(other < *this); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - template - STORMKIT_FORCE_INLINE - constexpr auto Ref::operator>(const Ref& other) const noexcept - -> bool { - return other < *this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - template - STORMKIT_FORCE_INLINE - constexpr auto Ref::operator>=(const Ref& other) const noexcept - -> bool { - return !(*this < other); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - template - requires std::three_way_comparable::PointerType, - typename Ref::PointerType> - STORMKIT_FORCE_INLINE - constexpr auto Ref::operator<=>(const Ref& other) const noexcept - -> std::compare_three_way_result_t::PointerType, - typename Ref::PointerType> { - return m_value <=> other.m_value; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr Ref::operator std::reference_wrapper() const noexcept { - if constexpr (meta::IsConst) return std::cref(*m_value); - else - return std::ref(*m_value); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr auto as_ref(T&& value) noexcept -> decltype(auto) { - using TValue = meta::CanonicalType; - if constexpr (meta::IsPointer) { - EXPECTS(value != nullptr); - return Ref> { std::to_address(value) }; - } else if constexpr (meta::IsContainedSemantics) { - EXPECTS(value.operator bool()); - return Ref> { &(value.operator*()) }; - } else { - return Ref { &value }; - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - // template - template - STORMKIT_FORCE_INLINE - constexpr auto as_ref_mut(T&& value) noexcept -> decltype(auto) { - using TValue = std::remove_reference_t; - static constexpr auto error_msg = "as_ref_mut can't take a reference of a const object"sv; - if constexpr (meta::IsPointer) { - using PointedType = meta::ElementType; - static_assert(meta::IsNotConst, error_msg); - EXPECTS(value != nullptr); - return Ref> { std::to_address(value) }; - } else if constexpr (meta::IsContainedSemantics) { - using UnderlyingType = meta::UnderlyingType; - static_assert(meta::IsNotConst, error_msg); - EXPECTS(value.operator bool()); - return Ref { &(value.operator*()) }; - } else { - static_assert(meta::IsNotConst, error_msg); - return Ref { &value }; - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - // template - template - STORMKIT_FORCE_INLINE - constexpr auto as_ref_like(T&& value) noexcept -> decltype(auto) { - using TValue = meta::CanonicalType; - if constexpr (meta::IsPointer) { - EXPECTS(value != nullptr); - return Ref> { std::to_address(value) }; - } else if constexpr (meta::IsContainedSemantics) { - EXPECTS(value.operator bool()); - return Ref> { &(value.operator*()) }; - } else { - return Ref { &value }; - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - // template - template - STORMKIT_FORCE_INLINE - constexpr auto as_opt_ref(T&& value) noexcept -> decltype(auto) { - using TValue = meta::CanonicalType; - if constexpr (meta::IsPointer) { - return OptionalRef> { std::to_address(value) }; - } else if constexpr (meta::IsContainedSemantics) { - return OptionalRef> { &(value.operator*()) }; - } else { - return OptionalRef { &value }; - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - // template - template - STORMKIT_FORCE_INLINE - constexpr auto as_opt_ref_mut(T&& value) noexcept -> decltype(auto) { - using TValue = std::remove_reference_t; - static constexpr auto error_msg = "as_ref_mut can't take a reference of a const object"sv; - if constexpr (meta::IsPointer) { - using PointedType = meta::ElementType; - static_assert(meta::IsNotConst, error_msg); - return OptionalRef> { std::to_address(value) }; - } else if constexpr (meta::IsContainedSemantics) { - using UnderlyingType = meta::UnderlyingType; - static_assert(meta::IsNotConst, error_msg); - return OptionalRef { &(value.operator*()) }; - } else { - static_assert(meta::IsNotConst, error_msg); - return OptionalRef { &value }; - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - // template - template - STORMKIT_FORCE_INLINE - constexpr auto as_opt_ref_like(T&& value) noexcept -> decltype(auto) { - using TValue = meta::CanonicalType; - if constexpr (meta::IsPointer) { - return OptionalRef> { std::to_address(value) }; - } else if constexpr (meta::IsContainedSemantics) { - return OptionalRef> { &(value.get()) }; - } else { - return OptionalRef { &value }; - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE STORMKIT_PURE - constexpr auto unref(const Ref& value) noexcept -> const T& { - return *value; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE STORMKIT_PURE - constexpr auto unref_mut(const Ref& value) noexcept -> T& { - return *value; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template typename Out = std::array, typename... Args> - requires(not std::ranges::range and ...) - STORMKIT_FORCE_INLINE - constexpr auto as_refs(Args&&... args) noexcept -> decltype(auto) { - return Out { as_ref(std::forward(args))... }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template typename Out, typename... Args> - requires(not std::ranges::range and ...) - STORMKIT_FORCE_INLINE - constexpr auto to_refs(Args&&... args) noexcept -> decltype(auto) { - return Out { { as_ref(std::forward(args))... } }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template typename Out = std::array, typename... Args> - requires(not std::ranges::range and ...) - STORMKIT_FORCE_INLINE - constexpr auto as_ref_muts(Args&&... args) noexcept -> decltype(auto) { - return Out { { as_ref_mut(std::forward(args))... } }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template typename Out, typename... Args> - requires(not std::ranges::range and ...) - STORMKIT_FORCE_INLINE - constexpr auto to_ref_muts(Args&&... args) noexcept -> decltype(auto) { - return Out { { as_ref_mut(std::forward(args))... } }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template class Out = std::vector, std::ranges::range T> - requires(std::ranges::range>) - STORMKIT_FORCE_INLINE - constexpr auto to_refs(const T& range) noexcept -> decltype(auto) { - return range - | std::views::transform([](U&& val) static noexcept -> decltype(auto) { - return as_ref(std::forward(val)); - }) - | std::ranges::to(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template class Out = std::vector, std::ranges::range T> - requires(std::ranges::range>) - STORMKIT_FORCE_INLINE - constexpr auto to_mut_refs(T& range) noexcept -> decltype(auto) { - return range - | std::views::transform([](U&& val) static noexcept -> decltype(auto) { - return as_ref_mut(std::forward(val)); - }) - | std::ranges::to(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template typename Out = std::array, typename... Args> - requires(not std::ranges::range and ...) - STORMKIT_FORCE_INLINE - constexpr auto as_opt_refs(Args&&... args) noexcept -> decltype(auto) { - return Out { as_opt_ref(std::forward(args))... }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template typename Out, typename... Args> - requires(not std::ranges::range and ...) - STORMKIT_FORCE_INLINE - constexpr auto to_opt_refs(Args&&... args) noexcept -> decltype(auto) { - return Out { { as_opt_ref(std::forward(args))... } }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template typename Out = std::array, typename... Args> - requires(not std::ranges::range and ...) - STORMKIT_FORCE_INLINE - constexpr auto as_opt_ref_muts(Args&&... args) noexcept -> decltype(auto) { - return Out { { as_opt_ref_mut(std::forward(args))... } }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template typename Out, typename... Args> - requires(not std::ranges::range and ...) - STORMKIT_FORCE_INLINE - constexpr auto to_opt_ref_muts(Args&&... args) noexcept -> decltype(auto) { - return Out { { as_opt_ref_mut(std::forward(args))... } }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template class Out = std::vector, std::ranges::range T> - requires(std::ranges::range>) - STORMKIT_FORCE_INLINE - constexpr auto to_opt_refs(const T& range) noexcept -> decltype(auto) { - return range - | std::views::transform([](U&& val) static noexcept -> decltype(auto) { - return as_opt_ref(std::forward(val)); - }) - | std::ranges::to(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template class Out = std::vector, std::ranges::range T> - requires(std::ranges::range>) - STORMKIT_FORCE_INLINE - constexpr auto to_mut_opt_refs(T& range) noexcept -> decltype(auto) { - return range - | std::views::transform([](U&& val) static noexcept -> decltype(auto) { - return as_opt_ref_mut(std::forward(val)); - }) - | std::ranges::to(); - } -}} // namespace stormkit::core - -using namespace stormkit; - -template -inline auto std::hash>::operator()(const Ref& ref) const noexcept -> u64 { - auto hash = u64 { 0 }; - hash_combine(hash, ref.get()); - return hash; -} diff --git a/modules/stormkit/core/typesafe/safecasts.mpp b/modules/stormkit/core/typesafe/safecasts.cppm similarity index 90% rename from modules/stormkit/core/typesafe/safecasts.mpp rename to modules/stormkit/core/typesafe/safecasts.cppm index 51c02926e..3203d9833 100644 --- a/modules/stormkit/core/typesafe/safecasts.mpp +++ b/modules/stormkit/core/typesafe/safecasts.cppm @@ -4,6 +4,7 @@ module; +#include #include export module stormkit.core:typesafe.safecasts; @@ -67,8 +68,8 @@ export { }; template - concept HasIsTypeQueryier = requires(U&& value) { - { is_impl(std::forward(value)) } -> IsBooleanTestable; + concept HasIsTypeQueryier = requires(const U& value) { + { is_impl(value) } -> IsBooleanTestable; }; template @@ -109,9 +110,8 @@ export { struct AsFn final { template [[nodiscard]] - static constexpr auto operator()(U&& value, - const std::source_location& - location = std::source_location::current()) noexcept + static constexpr auto operator()(U&& value, + const std::source_location& location = std::source_location::current()) noexcept -> decltype(auto); }; @@ -155,7 +155,7 @@ export { [[nodiscard]] constexpr auto is_equal_impl(T first, T second) noexcept -> bool; - template T, meta::ConvertibleTo U> + template T, meta::ConvertibleTo U> [[nodiscard]] constexpr auto is_equal_impl(T&& first, U&& second) noexcept -> bool; @@ -170,23 +170,23 @@ export { //////////////////////////////////////////////////////////////////// /// BYTES /// //////////////////////////////////////////////////////////////////// - template + template [[nodiscard]] constexpr auto is_impl(T first, T second) noexcept -> bool; - template + template [[nodiscard]] constexpr auto as_impl(U value, const std::source_location&) noexcept -> T; - template + template [[nodiscard]] constexpr auto as_impl(U value, const std::source_location&) noexcept -> T; - template + template [[nodiscard]] constexpr auto narrow_impl(U value) noexcept -> T; - template + template [[nodiscard]] constexpr auto narrow_impl(U value) noexcept -> T; @@ -194,23 +194,22 @@ export { /// ENUMERATION /// //////////////////////////////////////////////////////////////////// template - requires(meta::Same) + requires(meta::SameAs) [[nodiscard]] constexpr auto is_impl(T first, U second) noexcept -> bool; template - requires(meta::Same) + requires(meta::SameAs) [[nodiscard]] - constexpr auto as_impl(U value, const std::source_location&) noexcept - -> meta::UnderlyingType; + constexpr auto as_impl(U value, const std::source_location&) noexcept -> meta::UnderlyingType; template - requires(meta::Same, U>) + requires(meta::SameAs, U>) [[nodiscard]] constexpr auto as_impl(U value, const std::source_location&) noexcept -> T; template - requires(meta::Same>) + requires(meta::SameAs>) [[nodiscard]] constexpr auto as_impl(U value, const std::source_location&) noexcept -> T; @@ -229,14 +228,13 @@ export { //////////////////////////////////////////////////////////////////// /// STL /// //////////////////////////////////////////////////////////////////// - template + template [[nodiscard]] constexpr auto is_impl(const U& value) noexcept -> bool; - template + template [[nodiscard]] - constexpr auto as_impl(U&& value, const std::source_location&) noexcept - -> meta::ForwardLike; + constexpr auto as_impl(U&& value, const std::source_location&) noexcept -> meta::ForwardLike; }} // namespace stormkit::core } @@ -248,16 +246,13 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// template - requires((meta::IsArithmetic or meta::IsByte) - and (meta::IsArithmetic or meta::IsByte)) + requires((meta::IsArithmetic or meta::Isbyte) and (meta::IsArithmetic or meta::Isbyte)) constexpr auto isSafeNarrowing(const From& from) noexcept -> Boolean { - if constexpr ((meta::IsArithmetic and meta::IsByte) - or (meta::IsByte and meta::IsArithmetic)) + if constexpr ((meta::IsArithmetic and meta::Isbyte) or (meta::Isbyte and meta::IsArithmetic)) return (static_cast(static_cast(from)) == from); else if constexpr (meta::IsArithmetic and meta::IsArithmetic) return (static_cast(static_cast(from)) == from) - or (meta::IsSigned != meta::IsUnsigned - and ((static_cast(from) < To {}) == (from < From {}))); + or (meta::IsSigned != meta::IsUnsigned and ((static_cast(from) < To {}) == (from < From {}))); std::unreachable(); } @@ -291,8 +286,7 @@ namespace stormkit { inline namespace core { template template STORMKIT_FORCE_INLINE - constexpr auto AsFn::operator()(U&& value, const std::source_location& location) noexcept - -> decltype(auto) { + constexpr auto AsFn::operator()(U&& value, const std::source_location& location) noexcept -> decltype(auto) { return as_impl(std::forward(value), location); } @@ -372,11 +366,10 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// - template T, meta::ConvertibleTo U> + template T, meta::ConvertibleTo U> STORMKIT_FORCE_INLINE STORMKIT_CONST constexpr auto is_equal_impl(T&& first, U&& second) noexcept -> bool { - return std::string_view { std::forward(first) } - == std::string_view { std::forward(second) }; + return string_view { std::forward(first) } == string_view { std::forward(second) }; } ///////////////////////////////////// @@ -406,7 +399,7 @@ namespace stormkit { inline namespace core { //////////////////////////////////////////////////////////////////// ///////////////////////////////////// ///////////////////////////////////// - template + template STORMKIT_FORCE_INLINE STORMKIT_CONST constexpr auto as_impl(U value, const std::source_location& location) noexcept -> T { if constexpr (meta::IsNarrowing>) @@ -420,7 +413,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// - template + template STORMKIT_FORCE_INLINE STORMKIT_CONST constexpr auto as_impl(U value, const std::source_location& location) noexcept -> T { if constexpr (meta::IsNarrowing>) @@ -434,7 +427,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// - template + template STORMKIT_FORCE_INLINE STORMKIT_CONST STORMKIT_INTRINSIC constexpr auto narrow_impl(U value) noexcept -> T { return static_cast(value); @@ -442,7 +435,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// - template + template STORMKIT_FORCE_INLINE STORMKIT_CONST STORMKIT_INTRINSIC constexpr auto narrow_impl(U value) noexcept -> T { return static_cast(value); @@ -454,7 +447,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// template - requires(meta::Same) + requires(meta::SameAs) STORMKIT_FORCE_INLINE STORMKIT_CONST constexpr auto is_impl(T first, U second) noexcept -> bool { return first == second; @@ -463,10 +456,9 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// template - requires(meta::Same) + requires(meta::SameAs) STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto as_impl(U value, const std::source_location&) noexcept - -> meta::UnderlyingType { + constexpr auto as_impl(U value, const std::source_location&) noexcept -> meta::UnderlyingType { // TODO WHEN REFLEXION IS IMPLEMENTED, CHECK IF `value` IS A VALID ENUMERATION VALUE return as>(value); } @@ -474,7 +466,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// template - requires(meta::Same, U>) + requires(meta::SameAs, U>) STORMKIT_FORCE_INLINE STORMKIT_CONST constexpr auto as_impl(U value, const std::source_location&) noexcept -> T { // TODO WHEN REFLEXION IS IMPLEMENTED, CHECK IF `value` IS A VALID ENUMERATION VALUE @@ -484,7 +476,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// template - requires(meta::Same>) + requires(meta::SameAs>) STORMKIT_FORCE_INLINE STORMKIT_CONST constexpr auto as_impl(U value, const std::source_location&) noexcept -> T { return narrow>(value); @@ -519,7 +511,7 @@ namespace stormkit { inline namespace core { //////////////////////////////////////////////////////////////////// ///////////////////////////////////// ///////////////////////////////////// - template + template STORMKIT_FORCE_INLINE constexpr auto is_impl(const U& value) noexcept -> bool { return std::holds_alternative(value); @@ -527,24 +519,20 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// - template + template STORMKIT_FORCE_INLINE - constexpr auto as_impl(U&& value, const std::source_location&) noexcept - -> meta::ForwardLike { + constexpr auto as_impl(U&& value, const std::source_location&) noexcept -> meta::ForwardLike { return std::forward_like(std::get(value)); } #ifndef STORMKIT_OS_WINDOWS - #undef STORMKIT_API - #define STORMKIT_API + #undef STORMKIT_CORE_API + #define STORMKIT_CORE_API #endif -#define IS_EQUAL_INSTANCIATE(t1, t2) \ - template STORMKIT_API auto is_equal_impl(t1, t2) noexcept -> bool; -#define IS_EQUAL_INSTANCIATE_F1(t1, t2) \ - template STORMKIT_API auto is_equal_impl(t1, t2, t1) noexcept -> bool; -#define IS_EQUAL_INSTANCIATE_F2(t1, t2) \ - template STORMKIT_API auto is_equal_impl(t1, t2, t2) noexcept -> bool +#define IS_EQUAL_INSTANCIATE(t1, t2) template STORMKIT_CORE_API auto is_equal_impl(t1, t2) noexcept -> bool; +#define IS_EQUAL_INSTANCIATE_F1(t1, t2) template STORMKIT_CORE_API auto is_equal_impl(t1, t2, t1) noexcept -> bool; +#define IS_EQUAL_INSTANCIATE_F2(t1, t2) template STORMKIT_CORE_API auto is_equal_impl(t1, t2, t2) noexcept -> bool IS_EQUAL_INSTANCIATE(u8, u8); IS_EQUAL_INSTANCIATE(u8, i8); @@ -718,10 +706,9 @@ namespace stormkit { inline namespace core { #undef IS_EQUAL_INSTANCIATE_F1 #undef IS_EQUAL_INSTANCIATE_F2 -#define AS_NARROW_INSTANCIATE(t1, t2) \ - template STORMKIT_API auto stormkit::as_impl(t2, const std::source_location&) noexcept \ - -> t1; \ - template STORMKIT_API auto stormkit::narrow_impl(t2) noexcept -> t1 +#define AS_NARROW_INSTANCIATE(t1, t2) \ + template STORMKIT_CORE_API auto as_impl(t2, const std::source_location&) noexcept -> t1; \ + template STORMKIT_CORE_API auto narrow_impl(t2) noexcept -> t1 AS_NARROW_INSTANCIATE(u8, u8); AS_NARROW_INSTANCIATE(u8, i8); diff --git a/modules/stormkit/core/typesafe/strong_type.mpp b/modules/stormkit/core/typesafe/strong_type.cppm similarity index 56% rename from modules/stormkit/core/typesafe/strong_type.mpp rename to modules/stormkit/core/typesafe/strong_type.cppm index a36071fe8..99b4dae21 100644 --- a/modules/stormkit/core/typesafe/strong_type.mpp +++ b/modules/stormkit/core/typesafe/strong_type.cppm @@ -11,69 +11,59 @@ export module stormkit.core:typesafe.strong_type; import std; import :meta; +import :string.constexpr_string; +import :hash; export { namespace stormkit { inline namespace core { struct ArithmeticTag { template - using Type = meta::UnderlyingType>; + using Type = meta::ValueType>; template - constexpr auto operator+(this Self&& self, - meta::PlainIs> auto&& other) noexcept + constexpr auto operator+(this Self&& self, meta::PlainIs> auto&& other) noexcept -> meta::ToPlainType { - return meta::ToPlainType { std::forward(self).get() - + std::forward(other) }; + return meta::ToPlainType { std::forward(self).get() + std::forward(other) }; } template - constexpr auto operator+=(this Self& self, - meta::PlainIs> auto&& other) noexcept -> Self& { + constexpr auto operator+=(this Self& self, meta::PlainIs> auto&& other) noexcept -> Self& { self.get() += std::forward(other); return self; } template - constexpr auto operator-(this Self&& self, - meta::PlainIs> auto&& other) noexcept + constexpr auto operator-(this Self&& self, meta::PlainIs> auto&& other) noexcept -> meta::ToPlainType { - return meta::ToPlainType { std::forward(self).get() - - std::forward(other) }; + return meta::ToPlainType { std::forward(self).get() - std::forward(other) }; } template - constexpr auto operator-=(this Self& self, - meta::PlainIs> auto&& other) noexcept -> Self& { + constexpr auto operator-=(this Self& self, meta::PlainIs> auto&& other) noexcept -> Self& { self.get() -= std::forward(other); return self; } template - constexpr auto operator*(this Self&& self, - meta::PlainIs> auto&& other) noexcept + constexpr auto operator*(this Self&& self, meta::PlainIs> auto&& other) noexcept -> meta::ToPlainType { - return meta::ToPlainType { std::forward(self).get() - * std::forward(other) }; + return meta::ToPlainType { std::forward(self).get() * std::forward(other) }; } template - constexpr auto operator*=(this Self& self, - meta::PlainIs> auto&& other) noexcept -> Self& { + constexpr auto operator*=(this Self& self, meta::PlainIs> auto&& other) noexcept -> Self& { self.get() *= std::forward(other); return self; } template - constexpr auto operator/(this Self&& self, - meta::PlainIs> auto&& other) noexcept + constexpr auto operator/(this Self&& self, meta::PlainIs> auto&& other) noexcept -> meta::ToPlainType { - return meta::ToPlainType { std::forward(self).get() - / std::forward(other) }; + return meta::ToPlainType { std::forward(self).get() / std::forward(other) }; } template - constexpr auto operator/=(this Self& self, - meta::PlainIs> auto&& other) noexcept -> Self& { + constexpr auto operator/=(this Self& self, meta::PlainIs> auto&& other) noexcept -> Self& { self.get() /= std::forward(other); return self; } @@ -81,95 +71,81 @@ export { struct ImplicitConvertionTag {}; - template + template class StrongType; namespace meta { template - concept IsStrongType = IsSpecializationOf; + concept IsStrongType = IsSpecializationOfNTTP_TTVTs; template concept HasCapability = DerivedFrom; template - concept HasArithmeticCapability = AnyOf; + concept HasArithmeticCapability = IsAnyOf; template - concept HasImplicitConvertionCapability = AnyOf; + concept HasImplicitConvertionCapability = IsAnyOf; } // namespace meta template requires(meta::IsStrongType>) - constexpr auto operator+(meta::PlainIs> auto&& first, - T&& second) noexcept -> meta::ToPlainType { - return meta::ToPlainType { std::forward(second).get() - + std::forward(first) }; + constexpr auto operator+(meta::PlainIs> auto&& first, T&& second) noexcept + -> meta::ToPlainType { + return meta::ToPlainType { std::forward(second).get() + std::forward(first) }; } template requires(meta::IsStrongType>) - constexpr auto operator-(meta::PlainIs> auto&& first, - T&& second) noexcept -> meta::ToPlainType { - return meta::ToPlainType { std::forward(second).get() - - std::forward(first) }; + constexpr auto operator-(meta::PlainIs> auto&& first, T&& second) noexcept + -> meta::ToPlainType { + return meta::ToPlainType { std::forward(second).get() - std::forward(first) }; } template requires(meta::IsStrongType>) - constexpr auto operator*(meta::PlainIs> auto&& first, - T&& second) noexcept -> meta::ToPlainType { - return meta::ToPlainType { std::forward(second).get() - * std::forward(first) }; + constexpr auto operator*(meta::PlainIs> auto&& first, T&& second) noexcept + -> meta::ToPlainType { + return meta::ToPlainType { std::forward(second).get() * std::forward(first) }; } template requires(meta::IsStrongType>) - constexpr auto operator/(meta::PlainIs> auto&& first, - T&& second) noexcept -> meta::ToPlainType { - return meta::ToPlainType { std::forward(second).get() - / std::forward(first) }; + constexpr auto operator/(meta::PlainIs> auto&& first, T&& second) noexcept + -> meta::ToPlainType { + return meta::ToPlainType { std::forward(second).get() / std::forward(first) }; } - template - class StrongType { + template + class StrongType: public Capabilities... { public: using ValueType = T; - constexpr explicit StrongType(ValueType value) noexcept(meta::IsNoexceptConstructible< - ValueType, - ValueType>); + constexpr explicit StrongType(ValueType value) noexcept(meta::IsNoexceptConstructible); template constexpr explicit(sizeof...(Args) == 1) - StrongType(std::in_place_t, - Args&&... args) noexcept(meta::IsNoexceptConstructible) + StrongType(std::in_place_t, Args&&... args) noexcept(meta::IsNoexceptConstructible) requires(meta::IsConstructible); constexpr ~StrongType() noexcept(meta::IsNoexceptDestructible); - constexpr StrongType(const StrongType&) noexcept(meta::IsNoexceptCopyConstructible< - ValueType>) + constexpr StrongType(const StrongType&) noexcept(meta::IsNoexceptCopyConstructible) requires(meta::IsCopyConstructible); - constexpr auto operator=(const StrongType&) noexcept(meta::IsNoexceptCopyAssignable< - ValueType>) -> StrongType& + constexpr auto operator=(const StrongType&) noexcept(meta::IsNoexceptCopyAssignable) -> StrongType& requires(meta::IsCopyAssignable); - constexpr StrongType(StrongType&&) noexcept(meta::IsNoexceptMoveConstructible< - ValueType>) + constexpr StrongType(StrongType&&) noexcept(meta::IsNoexceptMoveConstructible) requires(meta::IsMoveConstructible); - constexpr auto operator=(StrongType&&) noexcept(meta::IsNoexceptMoveAssignable< - ValueType>) -> StrongType& + constexpr auto operator=(StrongType&&) noexcept(meta::IsNoexceptMoveAssignable) -> StrongType& requires(meta::IsMoveAssignable); template [[nodiscard]] - constexpr explicit(not meta::HasImplicitConvertionCapability< - Capabilities...>) operator T(this Self&& self) noexcept; + constexpr explicit(not meta::HasImplicitConvertionCapability) operator T(this Self&& self) noexcept; [[nodiscard]] - constexpr explicit(not meta::HasImplicitConvertionCapability< - Capabilities...>) operator T&() & noexcept; + constexpr explicit(not meta::HasImplicitConvertionCapability) operator T&() & noexcept; [[nodiscard]] - constexpr explicit(not meta::HasImplicitConvertionCapability< - Capabilities...>) operator const T&() const & noexcept; + constexpr explicit(not meta::HasImplicitConvertionCapability) operator const T&() const & noexcept; [[nodiscard]] constexpr auto get(this auto&& self) noexcept -> decltype(auto); @@ -208,19 +184,14 @@ export { // constexpr auto operator+=(First& first, Second&& second) { // first.get() += std::forward(second).get(); // } - }} // namespace stormkit::core - template - struct std::hash { - [[nodiscard]] - auto operator()(const T& value) const noexcept -> std::uint64_t; - }; - - template - struct std::formatter: std::formatter { - template - auto format(const T& data, FormatContext& ctx) const noexcept -> decltype(ctx.out()); - }; + template + constexpr auto hasher(const T& value) noexcept -> Ret; + + template + auto format_as(const StrongType& value, FormatContext& ctx) noexcept + -> decltype(ctx.out()); + }} // namespace stormkit::core } //////////////////////////////////////////////////////////////////// @@ -230,100 +201,97 @@ export { namespace stormkit { inline namespace core { //////////////////////////////////////// //////////////////////////////////////// - template + template STORMKIT_FORCE_INLINE - constexpr StrongType:: + constexpr StrongType:: StrongType(ValueType value) noexcept(meta::IsNoexceptConstructible) : m_value { value } { } //////////////////////////////////////// //////////////////////////////////////// - template + template template STORMKIT_FORCE_INLINE - constexpr StrongType:: - StrongType(std::in_place_t, - Args&&... args) noexcept(meta::IsNoexceptConstructible) + constexpr StrongType:: + StrongType(std::in_place_t, Args&&... args) noexcept(meta::IsNoexceptConstructible) requires(meta::IsConstructible) : m_value { std::forward(args)... } { } //////////////////////////////////////// //////////////////////////////////////// - template + template STORMKIT_FORCE_INLINE - constexpr StrongType:: + constexpr StrongType:: ~StrongType() noexcept(meta::IsNoexceptDestructible) = default; //////////////////////////////////////// //////////////////////////////////////// - template + template STORMKIT_FORCE_INLINE - constexpr StrongType:: + constexpr StrongType:: StrongType(const StrongType&) noexcept(meta::IsNoexceptCopyConstructible) requires(meta::IsCopyConstructible) = default; //////////////////////////////////////// //////////////////////////////////////// - template + template STORMKIT_FORCE_INLINE - constexpr auto StrongType:: - operator=(const StrongType&) noexcept(meta::IsNoexceptCopyAssignable) - -> StrongType& + constexpr auto StrongType:: + operator=(const StrongType&) noexcept(meta::IsNoexceptCopyAssignable) -> StrongType& requires(meta::IsCopyAssignable) = default; //////////////////////////////////////// //////////////////////////////////////// - template + template STORMKIT_FORCE_INLINE - constexpr StrongType:: + constexpr StrongType:: StrongType(StrongType&&) noexcept(meta::IsNoexceptMoveConstructible) requires(meta::IsMoveConstructible) = default; //////////////////////////////////////// //////////////////////////////////////// - template + template STORMKIT_FORCE_INLINE - constexpr auto StrongType:: + constexpr auto StrongType:: operator=(StrongType&&) noexcept(meta::IsNoexceptMoveAssignable) -> StrongType& requires(meta::IsMoveAssignable) = default; //////////////////////////////////////// //////////////////////////////////////// - template + template template STORMKIT_FORCE_INLINE STORMKIT_PURE - constexpr StrongType::operator T(this Self&& self) noexcept { + constexpr StrongType::operator T(this Self&& self) noexcept { return std::forward_like(self.m_value); } //////////////////////////////////////// //////////////////////////////////////// - template + template STORMKIT_FORCE_INLINE STORMKIT_PURE - constexpr StrongType::operator T&() & noexcept { + constexpr StrongType::operator T&() & noexcept { return get(); } //////////////////////////////////////// //////////////////////////////////////// - template + template STORMKIT_FORCE_INLINE STORMKIT_PURE - constexpr StrongType::operator const T&() const & noexcept { + constexpr StrongType::operator const T&() const & noexcept { return get(); } //////////////////////////////////////// //////////////////////////////////////// - template + template STORMKIT_FORCE_INLINE STORMKIT_PURE - constexpr auto StrongType::get(this auto&& self) noexcept - -> decltype(auto) { + constexpr auto StrongType::get(this auto&& self) noexcept -> decltype(auto) { return std::forward_like(self.m_value); } @@ -336,25 +304,21 @@ namespace stormkit { inline namespace core { else return std::forward(value); } -}} // namespace stormkit::core -using namespace stormkit; - -//////////////////////////////////////// -//////////////////////////////////////// -template -STORMKIT_FORCE_INLINE -inline auto std::hash::operator()(const T& value) const noexcept -> std::uint64_t { - return std::hash {}(value.get()); -} + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto hasher(const T& value) noexcept -> Ret { + return hash(value.get()); + } -//////////////////////////////////////// -//////////////////////////////////////// -template -template -STORMKIT_FORCE_INLINE -auto std::formatter::format(const T& data, FormatContext& ctx) const noexcept - -> decltype(ctx.out()) { - auto&& out = ctx.out(); - return std::format_to(out, "{}", data.get()); -} + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto format_as(const StrongType& value, FormatContext& ctx) noexcept + -> decltype(ctx.out()) { + return std::format_to(ctx.out(), "[{} value: {}]", Name, value.get()); + } +}} // namespace stormkit::core diff --git a/modules/stormkit/core/utils.mpp b/modules/stormkit/core/utils.cppm similarity index 92% rename from modules/stormkit/core/utils.mpp rename to modules/stormkit/core/utils.cppm index c809d8ce7..511f19881 100644 --- a/modules/stormkit/core/utils.mpp +++ b/modules/stormkit/core/utils.cppm @@ -1,24 +1,24 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -export module stormkit.core:utils; - -export import :utils.algorithms; -export import :utils.allocation; -export import :utils.app; -export import :utils.contract; -export import :utils.color; -export import :utils.deferinit; -export import :utils.dynamic_loader; -export import :utils.filesystem; -export import :utils.function_ref; -export import :utils.handle; -export import :utils.numeric_range; -export import :utils.pimpl; -export import :utils.random; -export import :utils.singleton; -export import :utils.stracktrace; -export import :utils.signal_handler; -export import :utils.tags; -export import :utils.time; +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +export module stormkit.core:utils; + +export import :utils.algorithms; +export import :utils.allocation; +export import :utils.app; +export import :utils.contract; +export import :utils.color; +export import :utils.deferinit; +export import :utils.dynamic_loader; +export import :utils.filesystem; +export import :utils.std23_functional; +export import :utils.handle; +export import :utils.numeric_range; +export import :utils.pimpl; +export import :utils.random; +export import :utils.singleton; +export import :utils.stracktrace; +export import :utils.signal_handler; +export import :utils.tags; +export import :utils.time; diff --git a/modules/stormkit/core/utils/algorithms.cppm b/modules/stormkit/core/utils/algorithms.cppm new file mode 100644 index 000000000..889d5a604 --- /dev/null +++ b/modules/stormkit/core/utils/algorithms.cppm @@ -0,0 +1,83 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +export module stormkit.core:utils.algorithms; + +import std; + +import :meta; +import :containers.aliases; + +namespace stdr = std::ranges; +namespace stdv = std::views; + +export namespace stormkit { inline namespace core { + template::value_type> Predicate> + [[nodiscard]] + constexpr auto copy_if(Range&& input, Predicate&& predicate) noexcept -> decltype(auto); + + template::value_type&> Lambda> + [[nodiscard]] + constexpr auto transform(Range&& input, Lambda&& lambda) noexcept -> decltype(auto); + + template::value_type> Predicate, + std::invocable::value_type&> Lambda> + [[nodiscard]] + constexpr auto transform_if(Range&& input, Predicate&& predicate, Lambda&& lambda) noexcept -> decltype(auto); + + template::value_type> Predicate, + std::invocable::value_type&> Lambda, + std::output_iterator::value_type&>> Iterator> + constexpr auto transform_if(Range&& input, Iterator&& it, Predicate&& predicate, Lambda&& lambda) noexcept -> void; +}} // namespace stormkit::core + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit { inline namespace core { + ///////////////////////////////////// + ///////////////////////////////////// + template::value_type> Predicate> + constexpr auto copy_if(Range&& input, Predicate&& predicate) noexcept -> decltype(auto) { + return std::forward(input) + | stdv::filter(std::forward(predicate)) + | stdr::to>(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template::value_type&> Lambda> + constexpr auto transform(Range&& input, Lambda&& lambda) noexcept -> decltype(auto) { + return std::forward(input) + | stdv::transform(lambda) + | stdr::to::value_type>>>(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template::value_type> Predicate, + std::invocable::value_type&> Lambda> + constexpr auto transform_if(Range&& input, Predicate&& predicate, Lambda&& lambda) noexcept -> decltype(auto) { + return std::forward(input) + | stdv::filter(std::forward(predicate)) + | stdv::transform(std::forward(lambda)) + | stdr::to::value_type>>>(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template::value_type> Predicate, + std::invocable::value_type&> Lambda, + std::output_iterator::value_type&>> Iterator> + constexpr auto transform_if(Range&& input, Iterator&& it, Predicate&& predicate, Lambda&& lambda) noexcept -> void { + stdr::for_each(std::forward(input), [&it, &predicate, &lambda](auto&& elem) { + if (predicate(elem)) *it++ = lambda(elem); + }); + } +}} // namespace stormkit::core diff --git a/modules/stormkit/core/utils/algorithms.mpp b/modules/stormkit/core/utils/algorithms.mpp deleted file mode 100644 index 572842982..000000000 --- a/modules/stormkit/core/utils/algorithms.mpp +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -export module stormkit.core:utils.algorithms; - -import std; - -import :meta; - -export namespace stormkit { inline namespace core { - template::value_type> Predicate> - [[nodiscard]] - constexpr auto copy_if(Range&& input, Predicate&& predicate) noexcept; - - template::value_type&> Lambda> - [[nodiscard]] - constexpr auto transform(Range&& input, Lambda&& lambda) noexcept; - - template::value_type> Predicate, - std::invocable::value_type&> Lambda> - [[nodiscard]] - constexpr auto transform_if(Range&& input, Predicate&& predicate, Lambda&& lambda) noexcept; - - template< - std::ranges::input_range Range, - meta::IsUnaryPredicate::value_type> Predicate, - std::invocable::value_type&> Lambda, - std::output_iterator< - std::invoke_result_t::value_type&>> - Iterator> - constexpr auto - transform_if(Range&& input, Iterator&& it, Predicate&& predicate, Lambda&& lambda) noexcept - -> void; -}} // namespace stormkit::core - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit { inline namespace core { - ///////////////////////////////////// - ///////////////////////////////////// - template::value_type> Predicate> - constexpr auto copy_if(Range&& input, Predicate&& predicate) noexcept { - auto output = std::vector::value_type> {}; - - output.reserve(std::size(input)); - - std::ranges::copy_if(input, std::back_inserter(output), std::forward(predicate)); - - return output; - - } - - ///////////////////////////////////// - ///////////////////////////////////// - template::value_type&> Lambda> - constexpr auto transform(Range&& input, Lambda&& lambda) noexcept { - auto output = std::vector< - std::invoke_result_t, - const typename std::remove_cvref_t::value_type&>> {}; - output.reserve(std::size(input)); - - std::ranges::transform(input, std::back_inserter(output), lambda); - - return output; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template::value_type> Predicate, - std::invocable::value_type&> Lambda> - constexpr auto transform_if(Range&& input, Predicate&& predicate, Lambda&& lambda) noexcept { - auto output = std::vector< - std::invoke_result_t, - const typename std::remove_cvref_t::value_type&>> {}; - output.reserve(std::size(input)); - - std::ranges::for_each(input, [&](auto& elem) { - if (predicate(elem)) output.emplace_back(lambda(elem)); - }); - - return output; - - } - - ///////////////////////////////////// - ///////////////////////////////////// - template< - std::ranges::input_range Range, - meta::IsUnaryPredicate::value_type> Predicate, - std::invocable::value_type&> Lambda, - std::output_iterator< - std::invoke_result_t::value_type&>> - Iterator> - constexpr auto - transform_if(Range&& input, Iterator&& it, Predicate&& predicate, Lambda&& lambda) noexcept - -> void { - std::ranges::for_each(input, [&](auto& elem) { - if (predicate(elem)) *it++ = lambda(elem); - }); - } -}} // namespace stormkit::core diff --git a/modules/stormkit/core/utils/allocation.mpp b/modules/stormkit/core/utils/allocation.cppm similarity index 84% rename from modules/stormkit/core/utils/allocation.mpp rename to modules/stormkit/core/utils/allocation.cppm index 80632bae4..e0dcd5f39 100644 --- a/modules/stormkit/core/utils/allocation.mpp +++ b/modules/stormkit/core/utils/allocation.cppm @@ -18,13 +18,12 @@ import :typesafe.integer; export namespace stormkit { inline namespace core { struct MemoryAllocationError { - std::string_view type; - usize size; + string_view type; + usize size; }; template - auto format_as(const MemoryAllocationError&, FormatContext&) noexcept - -> FormatContext::iterator; + auto format_as(const MemoryAllocationError&, FormatContext&) noexcept -> FormatContext::iterator; template using Heap = std::unique_ptr; @@ -36,16 +35,14 @@ export namespace stormkit { inline namespace core { -> std::expected, MemoryAllocationError>; template - auto allocate_unsafe(Args&&... args) noexcept(noexcept(T(std::forward(args)...))) - -> Heap; + auto allocate_unsafe(Args&&... args) noexcept(noexcept(T(std::forward(args)...))) -> Heap; template auto allocate_counted(Args&&... args) noexcept(noexcept(T(std::forward(args)...))) -> std::expected, MemoryAllocationError>; template - auto allocate_counted_unsafe(Args&&... args) noexcept(noexcept(T(std::forward(args)...))) - -> HeapCounted; + auto allocate_counted_unsafe(Args&&... args) noexcept(noexcept(T(std::forward(args)...))) -> HeapCounted; }} // namespace stormkit::core //////////////////////////////////////////////////////////////////// @@ -56,8 +53,7 @@ namespace stormkit { inline namespace core { //////////////////////////////////////// //////////////////////////////////////// template - auto format_as(const MemoryAllocationError& error, FormatContext& ctx) noexcept - -> FormatContext::iterator { + auto format_as(const MemoryAllocationError& error, FormatContext& ctx) noexcept -> FormatContext::iterator { auto&& out = ctx.out(); return std::format_to(out, "Failed to allocate type {} of {} byte{}", @@ -74,8 +70,7 @@ namespace stormkit { inline namespace core { -> std::expected, MemoryAllocationError> { auto value = Heap { new (std::nothrow) T(std::forward(args)...) }; if (not value) [[unlikely]] - return std::unexpected(MemoryAllocationError { .type = typeid(T).name(), - .size = sizeof(T) }); + return std::unexpected(MemoryAllocationError { .type = typeid(T).name(), .size = sizeof(T) }); return std::expected, MemoryAllocationError> { std::in_place, std::move(value) }; } @@ -83,8 +78,7 @@ namespace stormkit { inline namespace core { //////////////////////////////////////// template STORMKIT_FORCE_INLINE - auto allocate_unsafe(Args&&... args) noexcept(noexcept(T(std::forward(args)...))) - -> Heap { + auto allocate_unsafe(Args&&... args) noexcept(noexcept(T(std::forward(args)...))) -> Heap { return Heap { new (std::nothrow) T(std::forward(args)...) }; } @@ -96,18 +90,15 @@ namespace stormkit { inline namespace core { -> std::expected, MemoryAllocationError> { auto value = HeapCounted { new (std::nothrow) T(std::forward(args)...) }; if (not value) [[unlikely]] - return std::unexpected(MemoryAllocationError { .type = typeid(T).name(), - .size = sizeof(T) }); - return std::expected, MemoryAllocationError> { std::in_place, - std::move(value) }; + return std::unexpected(MemoryAllocationError { .type = typeid(T).name(), .size = sizeof(T) }); + return std::expected, MemoryAllocationError> { std::in_place, std::move(value) }; } //////////////////////////////////////// //////////////////////////////////////// template STORMKIT_FORCE_INLINE - auto allocate_counted_unsafe(Args&&... args) noexcept(noexcept(T(std::forward(args)...))) - -> HeapCounted { + auto allocate_counted_unsafe(Args&&... args) noexcept(noexcept(T(std::forward(args)...))) -> HeapCounted { return HeapCounted { new (std::nothrow) T(std::forward(args)...) }; } }} // namespace stormkit::core diff --git a/modules/stormkit/core/utils/app.mpp b/modules/stormkit/core/utils/app.cppm similarity index 80% rename from modules/stormkit/core/utils/app.mpp rename to modules/stormkit/core/utils/app.cppm index aecb718dc..c251ab075 100644 --- a/modules/stormkit/core/utils/app.mpp +++ b/modules/stormkit/core/utils/app.cppm @@ -1,31 +1,33 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -#include - -export module stormkit.core:utils.app; - -import std; - -import :typesafe.integer; - -export namespace stormkit { inline namespace core { - class STORMKIT_API App { - public: - App() noexcept = default; - virtual ~App() noexcept = default; - - App(App&&) noexcept = delete; - auto operator=(App&&) noexcept -> App& = delete; - - App(const App&) noexcept = delete; - auto operator=(const App&) noexcept -> App& = delete; - - virtual auto run(std::span args) -> i32 = 0; - }; -}} // namespace stormkit::core +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include +#include + +export module stormkit.core:utils.app; + +import std; + +import :typesafe.integer; +import :containers.aliases; +import :string.aliases; + +export namespace stormkit { inline namespace core { + class STORMKIT_CORE_API App { + public: + App() noexcept = default; + virtual ~App() noexcept = default; + + App(App&&) noexcept = delete; + auto operator=(App&&) noexcept -> App& = delete; + + App(const App&) noexcept = delete; + auto operator=(const App&) noexcept -> App& = delete; + + virtual auto run(array_view args) -> i32 = 0; + }; +}} // namespace stormkit::core diff --git a/modules/stormkit/core/utils/color.cppm b/modules/stormkit/core/utils/color.cppm new file mode 100644 index 000000000..a4a65a280 --- /dev/null +++ b/modules/stormkit/core/utils/color.cppm @@ -0,0 +1,605 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include + +export module stormkit.core:utils.color; + +import std; + +import :hash; +import :typesafe.integer; +import :math.linear.vector; +import :meta; + +export namespace stormkit { inline namespace core { + namespace meta { + template + concept ColorComponentStorageType = SameAs or SameAs; + } + + enum class ColorLayout { + R, + RG, + RGB, + BGR, + RGBA, + ARGB, + BGRA, + ABGR, + }; + + template + struct ColorComponent { + static constexpr auto max() noexcept -> T; + }; + + template + constexpr auto as_impl(ColorComponent component) noexcept -> ColorComponent; + + template + struct color; + + template + constexpr auto to_layout(const color& color) noexcept -> stormkit::color; + + template + constexpr auto to_storage(const color& color) noexcept -> stormkit::color; + + template + struct color { + static constexpr auto LAYOUT = ColorLayout::R; + using Storage = T; + + static constexpr auto COMPONENTS_COUNT = 1; + T r; + + constexpr auto operator==(const color& other) const noexcept -> bool; + }; + + template + struct color { + static constexpr auto LAYOUT = ColorLayout::RG; + using Storage = T; + + static constexpr auto COMPONENTS_COUNT = 2; + T r; + T g; + + constexpr auto operator==(const color& other) const noexcept -> bool; + }; + + template + struct color { + static constexpr auto LAYOUT = ColorLayout::RGB; + using Storage = T; + + static constexpr auto COMPONENTS_COUNT = 3; + T r; + T g; + T b; + + constexpr auto operator==(const color& other) const noexcept -> bool; + }; + + template + struct color { + static constexpr auto LAYOUT = ColorLayout::RGBA; + using Storage = T; + + static constexpr auto COMPONENTS_COUNT = 4; + T r; + T g; + T b; + T a; + + constexpr auto operator==(const color& other) const noexcept -> bool; + }; + + template + struct color { + static constexpr auto LAYOUT = ColorLayout::ARGB; + using Storage = T; + + static constexpr auto COMPONENTS_COUNT = 4; + T a; + T r; + T g; + T b; + + constexpr auto operator==(const color& other) const noexcept -> bool; + }; + + template + struct color { + static constexpr auto LAYOUT = ColorLayout::BGR; + using Storage = T; + + static constexpr auto COMPONENTS_COUNT = 3; + T b; + T g; + T r; + + constexpr auto operator==(const color& other) const noexcept -> bool; + }; + + template + struct color { + static constexpr auto LAYOUT = ColorLayout::BGRA; + using Storage = T; + + static constexpr auto COMPONENTS_COUNT = 4; + T b; + T g; + T r; + T a; + + constexpr auto operator==(const color& other) const noexcept -> bool; + }; + + template + struct color { + static constexpr auto LAYOUT = ColorLayout::ABGR; + using Storage = T; + + static constexpr auto COMPONENTS_COUNT = 4; + T a; + T b; + T g; + T r; + + constexpr auto operator==(const color& other) const noexcept -> bool; + }; + + template + using color_r = color; + template + using color_rg = color; + template + using color_rgb = color; + template + using color_rgba = color; + template + using color_argb = color; + template + using color_bgr = color; + template + using color_bgra = color; + template + using color_abgr = color; + + using fcolor_r = color_r; + using fcolor_rg = color_rg; + using fcolor_rgb = color_rgb; + using fcolor_rgba = color_rgba; + using fcolor_argb = color_argb; + using fcolor_bgr = color_bgr; + using fcolor_bgra = color_bgra; + using fcolor_abgr = color_abgr; + + using ucolor_r = color_r; + using ucolor_rg = color_rg; + using ucolor_rgb = color_rgb; + using ucolor_rgba = color_rgba; + using ucolor_argb = color_argb; + using ucolor_bgr = color_bgr; + using ucolor_bgra = color_bgra; + using ucolor_abgr = color_abgr; + + constexpr auto as_string(ColorLayout layout) noexcept -> string_view; + constexpr auto to_string(ColorLayout layout) noexcept -> string; + + template + constexpr auto to_string(const color& color) noexcept -> string; + + template + auto format_as(const color& color, FormatContext& ctx) noexcept -> decltype(ctx.out()); + + template + constexpr auto hasher(const color& color) noexcept -> Ret; +}} // namespace stormkit::core + +namespace stormkit { inline namespace core { namespace details { + template + struct ImplicitConverter { + template + constexpr operator color() const noexcept; + + color c; + }; +}}} // namespace stormkit::core::details + +export namespace stormkit { inline namespace core { + /// This namespace contain preset colors, these colors are defined from [HTML 4.01 + /// colors](https://en.wikipedia.org/wiki/Web_colors#HTML_color_names). + ///``` + /// | name | red |green|blue |alpha| + /// |-------------|-----|-----|-----|-----| + /// | BLACK | 0 | 0 | 0 | 255 | + /// | Gray | 127 | 127 | 127 | 255 | + /// | SILVER | 190 | 190 | 190 | 255 | + /// | WHITE | 255 | 255 | 255 | 255 | + /// | Maroon | 127 | 0 | 0 | 255 | + /// | RED | 255 | 0 | 0 | 255 | + /// | Olive | 127 | 127 | 0 | 255 | + /// | YELLOW | 255 | 255 | 0 | 255 | + /// | GREEN | 0 | 127 | 0 | 255 | + /// | LIME | 0 | 255 | 0 | 255 | + /// | TEAL | 0 | 127 | 127 | 255 | + /// | AQUA | 0 | 255 | 255 | 255 | + /// | NAVY | 0 | 0 | 127 | 255 | + /// | BLUE | 0 | 0 | 255 | 255 | + /// | PURPLE | 127 | 0 | 127 | 255 | + /// | FUSCHIA | 255 | 0 | 255 | 255 | + /// | TRANSPARENT | 0 | 0 | 0 | 0 | + ///``` + + namespace colors { + template + inline constexpr auto BLACK = details::ImplicitConverter { + .c = { .r = 0, .g = 0, .b = 0, .a = ColorComponent::max() } + }; + + template + inline constexpr auto GRAY = details::ImplicitConverter { + .c = { .r = ColorComponent::max() / T { 2 }, + .g = ColorComponent::max() / T { 2 }, + .b = ColorComponent::max() / T { 2 }, + .a = ColorComponent::max() } + }; + + template + inline constexpr auto SILVER = details::ImplicitConverter { + .c = { .r = ColorComponent::max() / T { 2 } + ColorComponent::max() / T { 4 }, + .g = ColorComponent::max() / T { 2 } + ColorComponent::max() / T { 4 }, + .b = ColorComponent::max() / T { 2 } + ColorComponent::max() / T { 4 }, + .a = ColorComponent::max() } + }; + + template + inline constexpr auto WHITE = details::ImplicitConverter { + .c = { .r = ColorComponent::max(), + .g = ColorComponent::max(), + .b = ColorComponent::max(), + .a = ColorComponent::max() } + }; + + template + inline constexpr auto MAROON = details::ImplicitConverter { + .c = { .r = ColorComponent::max() / T { 2 }, .g = T { 0 }, .b = T { 0 }, .a = ColorComponent::max() } + }; + + template + inline constexpr auto RED = details::ImplicitConverter { + .c = { .r = ColorComponent::max(), .g = 0, .b = 0, .a = ColorComponent::max() } + }; + + template + inline constexpr auto OLIVE = details::ImplicitConverter { + .c = { .r = ColorComponent::max() / T { 2 }, + .g = ColorComponent::max() / T { 2 }, + .b = T { 0 }, + .a = ColorComponent::max() } + }; + + template + inline constexpr auto YELLOW = details::ImplicitConverter { + .c = { .r = ColorComponent::max(), .g = ColorComponent::max(), .b = T { 0 }, .a = ColorComponent::max() } + }; + + template + inline constexpr auto GREEN = details::ImplicitConverter { + .c = { .r = 0, .g = ColorComponent::max() / T { 2 }, .b = 0, .a = ColorComponent::max() } + }; + + template + inline constexpr auto LIME = details::ImplicitConverter { + .c = { .r = 0, .g = ColorComponent::max(), .b = 0, .a = ColorComponent::max() } + }; + + template + inline constexpr auto TEAL = details::ImplicitConverter { + .c = { .r = 0, + .g = ColorComponent::max() / T { 2 }, + .b = ColorComponent::max() / T { 2 }, + .a = ColorComponent::max() } + }; + + template + inline constexpr auto AQUA = details::ImplicitConverter { + .c = { .r = 0, .g = ColorComponent::max(), .b = ColorComponent::max(), .a = ColorComponent::max() } + }; + + template + inline constexpr auto NAVY = details::ImplicitConverter { + .c = { .r = 0, .g = 0, .b = ColorComponent::max() / T { 2 }, .a = ColorComponent::max() } + }; + + template + inline constexpr auto BLUE = details::ImplicitConverter { + .c = { .r = 0, .g = 0, .b = ColorComponent::max(), .a = ColorComponent::max() } + }; + + template + inline constexpr auto PURPLE = details::ImplicitConverter { + .c = { .r = ColorComponent::max() / T { 2 }, + .g = 0, + .b = ColorComponent::max() / T { 2 }, + .a = ColorComponent::max() } + }; + + template + inline constexpr auto FUSCHIA = details::ImplicitConverter { + .c = { .r = ColorComponent::max(), .g = 0, .b = ColorComponent::max(), .a = ColorComponent::max() } + }; + + template + inline constexpr auto TRANSPARENT = details::ImplicitConverter { + .c = { .r = 0, .g = 0, .b = 0, .a = 0 } + }; + } // namespace colors +}} // namespace stormkit::core + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit { inline namespace core { + ///////////////////////////////////// + ///////////////////////////////////// + template + constexpr auto to_layout(const color& in) noexcept -> stormkit::color { + if constexpr (LAYOUT == LAYOUT_T) return in; + else { + using InColor = color; + using OutColor = color; + auto out = OutColor {}; + out.r = in.r; + + if constexpr (OutColor::COMPONENTS_COUNT > 1 and InColor::COMPONENTS_COUNT > 1) { + out.g = in.g; + if constexpr (OutColor::COMPONENTS_COUNT > 2 and InColor::COMPONENTS_COUNT > 2) { + out.b = in.b; + if constexpr (OutColor::COMPONENTS_COUNT > 3 and InColor::COMPONENTS_COUNT > 3) out.a = in.a; + } + } + + return out; + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + constexpr auto to_storage(const color& in) noexcept -> stormkit::color { + if constexpr (meta::SameAs) return in; + else { + using OutColor = color; + auto out = OutColor {}; + out.r = as(in.r); + + if constexpr (OutColor::COMPONENTS_COUNT > 1) { + out.g = as(in.g); + if constexpr (OutColor::COMPONENTS_COUNT > 2) { + out.b = as(in.b); + if constexpr (OutColor::COMPONENTS_COUNT > 3) out.a = as(in.a); + } + } + + return out; + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + constexpr auto color_component_as(u8 component) noexcept -> f32 { + return as(component) / 255.f; + } + + ///////////////////////////////////// + ///////////////////////////////////// + constexpr auto color_component_as(f32 component) noexcept -> u8 { + EXPECTS(component <= 1.f); + return as(component * 255u); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + constexpr auto max_color_component_value() noexcept -> T { + if constexpr (std::is_same_v) return 1.f; + + return 255u; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + constexpr auto ColorComponent::max() noexcept -> T { + if constexpr (meta::SameAs) return 1.f; + else + return 255u; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + constexpr auto as_impl(ColorComponent component) noexcept -> ColorComponent { + if constexpr (meta::SameAs) return ColorComponent { as(component.value) / 255.f }; + else + return ColorComponent { as(component.value) * 255.f }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + template + constexpr details::ImplicitConverter::operator color() const noexcept { + return to_storage(to_layout(c)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto color::operator==(const color& other) const noexcept -> bool { + return r == other.r; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto color::operator==(const color& other) const noexcept -> bool { + return r == other.r and g == other.g; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto color::operator==(const color& other) const noexcept -> bool { + return r == other.r and g == other.g and b == other.b; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto color::operator==(const color& other) const noexcept -> bool { + return r == other.r and g == other.g and b == other.b and a == other.a; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto color::operator==(const color& other) const noexcept -> bool { + return r == other.r and g == other.g and b == other.b and a == other.a; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto color::operator==(const color& other) const noexcept -> bool { + return r == other.r and g == other.g and b == other.b; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto color::operator==(const color& other) const noexcept -> bool { + return r == other.r and g == other.g and b == other.b and a == other.a; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto color::operator==(const color& other) const noexcept -> bool { + return r == other.r and g == other.g and b == other.b and a == other.a; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto as_string(ColorLayout layout) noexcept -> string_view { + switch (layout) { + case ColorLayout::R: return "R"; + case ColorLayout::RG: return "RG"; + case ColorLayout::RGB: return "RGB"; + case ColorLayout::BGR: return "BGR"; + case ColorLayout::RGBA: return "RGBA"; + case ColorLayout::ARGB: return "ARGB"; + case ColorLayout::BGRA: return "BGRA"; + case ColorLayout::ABGR: return "ABGR"; + default: break; + } + std::unreachable(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto to_string(ColorLayout layout) noexcept -> string { + return string { as_string(layout) }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto to_string(const color& color) noexcept -> string { + return std::format("{}", color); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto format_as(const color& color, FormatContext& ctx) noexcept -> decltype(ctx.out()) { + if constexpr (LAYOUT == ColorLayout::R) return std::format_to(ctx.out(), "[color layout: R, red: {}]", color.r); + else if constexpr (LAYOUT == ColorLayout::RG) + return std::format_to(ctx.out(), "[color layout: RG, red: {}, green: {}]", color.r, color.g); + else if constexpr (LAYOUT == ColorLayout::RGB) + return std::format_to(ctx.out(), "[color layout: RGB, red: {}, green: {}, blue: {}]", color.r, color.g, color.b); + else if constexpr (LAYOUT == ColorLayout::BGR) + return std::format_to(ctx.out(), "[color layout: BGR, blue: {}, green: {}, red: {}]", color.r, color.g); + else if constexpr (LAYOUT == ColorLayout::RGBA) + return std::format_to(ctx.out(), + "[color layout: RGBA, red: {}, green: {}, blue: {}, alpha: {}]", + color.r, + color.g, + color.b, + color.a); + else if constexpr (LAYOUT == ColorLayout::ARGB) + return std::format_to(ctx.out(), + "[color layout: ARGB, alpha: {}, red: {}, green: {}, blue: {}]", + color.a, + color.r, + color.g, + color.b); + else if constexpr (LAYOUT == ColorLayout::BGRA) + return std::format_to(ctx.out(), + "[color layout: BGRA, bue: {}, green: {}, red: {}, alpha: {}]", + color.b, + color.g, + color.r, + color.a); + else if constexpr (LAYOUT == ColorLayout::ABGR) + return std::format_to(ctx.out(), + "[color layout: ABGR, alpha: {}, blue: {}, green: {}, red: {}]", + color.a, + color.b, + color.g, + color.r); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto hasher(const color& color) noexcept -> Ret { + if constexpr (LAYOUT == ColorLayout::R) return hash(color.r); + else if constexpr (LAYOUT == ColorLayout::RG) + return hash(color.r, color.g); + else if constexpr (LAYOUT == ColorLayout::RGB) + return hash(color.r, color.g, color.b); + else if constexpr (LAYOUT == ColorLayout::BGR) + return hash(color.b, color.g, color.r); + else if constexpr (LAYOUT == ColorLayout::RGBA) + return hash(color.r, color.g, color.b, color.a); + else if constexpr (LAYOUT == ColorLayout::ARGB) + return hash(color.a, color.r, color.g, color.b); + else if constexpr (LAYOUT == ColorLayout::BGRA) + return hash(color.b, color.g, color.r, color.a); + else if constexpr (LAYOUT == ColorLayout::ABGR) + return hash(color.a, color.b, color.g, color.r); + } +}} // namespace stormkit::core diff --git a/modules/stormkit/core/utils/color.mpp b/modules/stormkit/core/utils/color.mpp deleted file mode 100644 index 039774593..000000000 --- a/modules/stormkit/core/utils/color.mpp +++ /dev/null @@ -1,622 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -#include - -#include - -export module stormkit.core:utils.color; - -import std; - -import :hash; -import :typesafe.integer; -import :math.linear.vector; -import :meta; - -export namespace stormkit { inline namespace core { - namespace meta { - template - concept ColorComponentStorageType = IsStrict or IsStrict; - } - - enum class ColorLayout { - R, - RG, - RGB, - BGR, - RGBA, - ARGB, - BGRA, - ABGR, - }; - - template - struct ColorComponent { - static constexpr auto max() noexcept -> T; - }; - - template - constexpr auto as_impl(ColorComponent component) noexcept -> ColorComponent; - - template - struct color; - - template - constexpr auto to_layout(const color& color) noexcept - -> stormkit::color; - - template - constexpr auto to_storage(const color& color) noexcept - -> stormkit::color; - - template - struct color { - static constexpr auto COMPONENTS_COUNT = 1; - T r; - }; - - template - struct color { - static constexpr auto COMPONENTS_COUNT = 2; - T r; - T g; - }; - - template - struct color { - static constexpr auto COMPONENTS_COUNT = 3; - T r; - T g; - T b; - }; - - template - struct color { - static constexpr auto COMPONENTS_COUNT = 4; - T r; - T g; - T b; - T a; - }; - - template - struct color { - static constexpr auto COMPONENTS_COUNT = 4; - T a; - T r; - T g; - T b; - }; - - template - struct color { - static constexpr auto COMPONENTS_COUNT = 3; - T b; - T g; - T r; - }; - - template - struct color { - static constexpr auto COMPONENTS_COUNT = 4; - T b; - T g; - T r; - T a; - }; - - template - struct color { - static constexpr auto COMPONENTS_COUNT = 4; - T a; - T b; - T g; - T r; - }; - - template - using rcolor = color; - template - using rgcolor = color; - template - using rgbcolor = color; - template - using rgbacolor = color; - template - using argbcolor = color; - template - using bgrcolor = color; - template - using bgracolor = color; - template - using abgrcolor = color; - - constexpr auto color_component_as(u8 component) noexcept -> f32; - - constexpr auto color_component_as(f32 component) noexcept -> u8; - - template - constexpr auto max_color_component_value() noexcept -> T; - - template - struct RGBColor { - using ValueType = T; - using value_type = ValueType; - - constexpr RGBColor(ValueType red, - ValueType green, - ValueType blue, - ValueType alpha = max_color_component_value()) noexcept; - - constexpr explicit RGBColor(const math::vec3& vector) noexcept; - - constexpr explicit RGBColor(const math::vec4& vector) noexcept; - - constexpr RGBColor(const RGBColor& other) noexcept; - constexpr auto operator=(const RGBColor& other) noexcept -> RGBColor&; - - constexpr RGBColor(RGBColor&& other) noexcept; - constexpr auto operator=(RGBColor&& other) noexcept -> RGBColor&; - - template - constexpr RGBColor(const RGBColor& other) noexcept; - - template - constexpr auto operator=(const RGBColor& other) noexcept -> RGBColor&; - - constexpr auto to_vec3() const noexcept -> math::vec3; - constexpr auto to_vec4() const noexcept -> math::vec4; - - constexpr operator math::vec3() const noexcept; - constexpr operator math::vec4() const noexcept; - constexpr operator std::array() const noexcept; - - ValueType red; - ValueType green; - ValueType blue; - ValueType alpha; - }; - - using RGBColorU = RGBColor; - using RGBColorF = RGBColor; -}} // namespace stormkit::core - -namespace stormkit { inline namespace core { namespace details { - template - struct ImplicitConverter { - template - constexpr operator color() const noexcept; - - color c; - }; -}}} // namespace stormkit::core::details - -export namespace stormkit { inline namespace core { - /// This namespace contain preset colors, these colors are defined from [HTML 4.01 - /// colors](https://en.wikipedia.org/wiki/Web_colors#HTML_color_names). - ///``` - /// | name | red |green|blue |alpha| - /// |-------------|-----|-----|-----|-----| - /// | BLACK | 0 | 0 | 0 | 255 | - /// | Gray | 127 | 127 | 127 | 255 | - /// | SILVER | 190 | 190 | 190 | 255 | - /// | WHITE | 255 | 255 | 255 | 255 | - /// | Maroon | 127 | 0 | 0 | 255 | - /// | RED | 255 | 0 | 0 | 255 | - /// | Olive | 127 | 127 | 0 | 255 | - /// | YELLOW | 255 | 255 | 0 | 255 | - /// | GREEN | 0 | 127 | 0 | 255 | - /// | LIME | 0 | 255 | 0 | 255 | - /// | TEAL | 0 | 127 | 127 | 255 | - /// | AQUA | 0 | 255 | 255 | 255 | - /// | NAVY | 0 | 0 | 127 | 255 | - /// | BLUE | 0 | 0 | 255 | 255 | - /// | PURPLE | 127 | 0 | 127 | 255 | - /// | FUSCHIA | 255 | 0 | 255 | 255 | - /// | TRANSPARENT | 0 | 0 | 0 | 0 | - ///``` - - namespace colors { - template - inline constexpr auto BLACK = details::ImplicitConverter { - .c = { .r = 0, .g = 0, .b = 0, .a = ColorComponent::max() } - }; - - template - inline constexpr auto WHITE = details::ImplicitConverter { - .c = { .r = ColorComponent::max(), - .g = ColorComponent::max(), - .b = ColorComponent::max(), - .a = ColorComponent::max() } - }; - - template - inline constexpr auto RED = details::ImplicitConverter { - .c = { .r = ColorComponent::max(), .g = 0, .b = 0, .a = ColorComponent::max() } - }; - - template - inline constexpr auto GREEN = details::ImplicitConverter { - .c = { .r = 0, .g = ColorComponent::max(), .b = 0, .a = ColorComponent::max() } - }; - - template - inline constexpr auto BLUE = details::ImplicitConverter { - .c = { .r = 0, .g = 0, .b = ColorComponent::max(), .a = ColorComponent::max() } - }; - - template - inline constexpr auto YELLOW = details::ImplicitConverter { - .c = { .r = ColorComponent::max(), - .g = ColorComponent::max(), - .b = 0, - .a = ColorComponent::max() } - }; - } // namespace colors - - namespace RGBColorDef { - template - inline constexpr auto - BLACK = RGBColor { T { 0 }, T { 0 }, T { 0 }, max_color_component_value() }; - - template - inline constexpr auto Gray = RGBColor { max_color_component_value() / T { 2 }, - max_color_component_value() / T { 2 }, - max_color_component_value() / T { 2 }, - max_color_component_value() }; - - template - inline constexpr auto SILVER = RGBColor { - (max_color_component_value() / T { 2 }) + (max_color_component_value() / T { 4 }), - (max_color_component_value() / T { 2 }) + (max_color_component_value() / T { 4 }), - (max_color_component_value() / T { 2 }) + (max_color_component_value() / T { 4 }), - max_color_component_value() - }; - - template - inline constexpr auto WHITE = RGBColor { - max_color_component_value(), - max_color_component_value(), - max_color_component_value(), - max_color_component_value() - }; - - template - inline constexpr auto Maroon = RGBColor { - max_color_component_value() / T { 2 }, - T { 0 }, - T { 0 }, - max_color_component_value() - }; - - template - inline constexpr auto RED = RGBColor { max_color_component_value(), - T { 0 }, - T { 0 }, - max_color_component_value() }; - - template - inline constexpr auto Olive = RGBColor { - max_color_component_value() / T { 2 }, - max_color_component_value() / T { 2 }, - T { 0 }, - max_color_component_value() - }; - - template - inline constexpr auto YELLOW = RGBColor { - max_color_component_value(), - max_color_component_value(), - T { 0 }, - max_color_component_value() - }; - template - inline constexpr auto GREEN = RGBColor { - T { 0 }, - max_color_component_value() / T { 2 }, - T { 0 }, - max_color_component_value() - }; - - template - inline constexpr auto LIME = RGBColor { T { 0 }, - max_color_component_value(), - T { 0 }, - max_color_component_value() }; - - template - inline constexpr auto TEAL = RGBColor { T { 0 }, - max_color_component_value() / T { 2 }, - max_color_component_value() / T { 2 }, - max_color_component_value() }; - - template - inline constexpr auto AQUA = RGBColor { T { 0 }, - max_color_component_value(), - max_color_component_value(), - max_color_component_value() }; - - template - inline constexpr auto NAVY = RGBColor { T { 0 }, - T { 0 }, - max_color_component_value() / T { 2 }, - max_color_component_value() }; - - template - inline constexpr auto BLUE = RGBColor { T { 0 }, - T { 0 }, - max_color_component_value(), - max_color_component_value() }; - - template - inline constexpr auto PURPLE = RGBColor { - max_color_component_value() / T { 2 }, - T { 0 }, - max_color_component_value() / T { 2 }, - max_color_component_value() - }; - - template - inline constexpr auto Fuchsia = RGBColor { - max_color_component_value(), - T { 0 }, - max_color_component_value(), - max_color_component_value() - }; - - template - inline constexpr auto TRANSPARENT = RGBColor { T { 0 }, T { 0 }, T { 0 }, T { 0 } }; - } // namespace RGBColorDef - - template - constexpr auto format_as(const RGBColor&, FormatContext& ctx) noexcept - -> decltype(ctx.out()); -}} // namespace stormkit::core - -export { - TEMPLATED_HASH_EQUAL_FUNC(stormkit::core::RGBColor, - stormkit::meta::IsColorComponent, - T, - value.r, - value.g, - value.b, - value.a) -} - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit { inline namespace core { - ///////////////////////////////////// - ///////////////////////////////////// - template - constexpr auto to_layout(const color& in) noexcept -> stormkit::color { - if constexpr (LAYOUT == LAYOUT_T) return in; - else { - using InColor = color; - using OutColor = color; - auto out = OutColor {}; - out.r = in.r; - - if constexpr (OutColor::COMPONENTS_COUNT > 1 and InColor::COMPONENTS_COUNT > 1) { - out.g = in.g; - if constexpr (OutColor::COMPONENTS_COUNT > 2 and InColor::COMPONENTS_COUNT > 2) { - out.b = in.b; - if constexpr (OutColor::COMPONENTS_COUNT > 3 and InColor::COMPONENTS_COUNT > 3) - out.a = in.a; - } - } - - return out; - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - constexpr auto to_storage(const color& in) noexcept - -> stormkit::color { - if constexpr (meta::IsStrict) return in; - else { - using OutColor = color; - auto out = OutColor {}; - out.r = as(in.r); - - if constexpr (OutColor::COMPONENTS_COUNT > 1) { - out.g = as(in.g); - if constexpr (OutColor::COMPONENTS_COUNT > 2) { - out.b = as(in.b); - if constexpr (OutColor::COMPONENTS_COUNT > 3) out.a = as(in.a); - } - } - - return out; - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - constexpr auto color_component_as(u8 component) noexcept -> f32 { - return as(component) / 255.f; - } - - ///////////////////////////////////// - ///////////////////////////////////// - constexpr auto color_component_as(f32 component) noexcept -> u8 { - EXPECTS(component <= 1.f); - return as(component * 255u); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - constexpr auto max_color_component_value() noexcept -> T { - if constexpr (std::is_same_v) return 1.f; - - return 255u; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - constexpr auto ColorComponent::max() noexcept -> T { - if constexpr (meta::IsStrict) return 1.f; - else - return 255u; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - constexpr auto as_impl(ColorComponent component) noexcept -> ColorComponent { - if constexpr (meta::IsStrict) - return ColorComponent { as(component.value) / 255.f }; - else - return ColorComponent { as(component.value) * 255.f }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - template - constexpr details::ImplicitConverter::operator color() const noexcept { - return to_storage(to_layout(c)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - constexpr RGBColor::RGBColor(ValueType _red, - ValueType _green, - ValueType _blue, - ValueType _alpha) noexcept - : red { _red }, green { _green }, blue { _blue }, alpha { _alpha } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - constexpr RGBColor::RGBColor(const math::vec3& vector) noexcept - : red { vector.r }, green { vector.g }, blue { vector.b }, - alpha(max_color_component_value()) { - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - constexpr RGBColor::RGBColor(const math::vec4& vector) noexcept - : red { vector.r }, green { vector.g }, blue { vector.b }, alpha { vector.a } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - constexpr RGBColor::RGBColor(const RGBColor& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - template - constexpr auto RGBColor::operator=(const RGBColor& other) noexcept - -> RGBColor& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - template - constexpr RGBColor::RGBColor(RGBColor&& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - template - constexpr auto RGBColor::operator=(RGBColor&& other) noexcept - -> RGBColor& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - template - template - constexpr RGBColor::RGBColor(const RGBColor& other) noexcept - : red { color_component_as(other.red) }, green { color_component_as(other.green) }, - blue { color_component_as(other.blue) }, alpha { color_component_as(other.alpha) } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - template - constexpr auto RGBColor::operator=(const RGBColor& other) noexcept -> RGBColor& { - red = color_component_as(other.red); - green = color_component_as(other.green); - blue = color_component_as(other.blue); - alpha = color_component_as(other.alpha); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - constexpr auto RGBColor::to_vec3() const noexcept -> math::vec3 { - return { red, green, blue }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - constexpr auto RGBColor::to_vec4() const noexcept -> math::vec4 { - return { red, green, blue, alpha }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - constexpr RGBColor::operator math::vec3() const noexcept { - return to_vec3(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - constexpr RGBColor::operator math::vec4() const noexcept { - return to_vec4(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - constexpr RGBColor::operator std::array() const noexcept { - return { red, green, blue, alpha }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr auto format_as(const RGBColor& color, FormatContext& ctx) noexcept - -> decltype(ctx.out()) { - if constexpr (meta::Is) - return std::format_to(ctx.out(), - "{{red: {}, green: {}, blue: {}, alpha: {}}}", - color.red, - color.green, - color.blue, - color.alpha); - else { - const auto color_u8 = RGBColorU { color }; - return std::format_to(ctx.out(), - "{{red: {}, green: {}, blue: {}, alpha: {}}}", - color_u8.red, - color_u8.green, - color_u8.blue, - color_u8.alpha); - } - } -}} // namespace stormkit::core diff --git a/modules/stormkit/core/utils/contract.mpp b/modules/stormkit/core/utils/contract.cppm similarity index 52% rename from modules/stormkit/core/utils/contract.mpp rename to modules/stormkit/core/utils/contract.cppm index 7a3cb8949..6b8cfe08b 100644 --- a/modules/stormkit/core/utils/contract.mpp +++ b/modules/stormkit/core/utils/contract.cppm @@ -1,213 +1,195 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -#ifndef STORMKIT_ASSERT - #define STORMKIT_ASSERT 1 -#endif - -export module stormkit.core:utils.contract; - -import std; -import frozen; - -import :utils.stracktrace; - -import :meta; - -namespace stdr = std::ranges; - -export namespace stormkit { inline namespace core { - enum class AssertType { - Assertion, - PreCondition, - PostCondition, - }; - - constexpr auto as_string(AssertType type) noexcept -> std::string_view; - constexpr auto to_string(AssertType type) noexcept -> std::string; - - STORMKIT_API - auto assert_base(bool cond, - AssertType type, - std::string_view message, - const std::source_location& - location = std::source_location::current()) noexcept -> void; - - consteval auto consteval_assert_base(bool cond, - AssertType type, - std::string_view message) noexcept -> void; - - constexpr auto assert(bool cond, - std::string_view message, - const std::source_location& - location = std::source_location::current()) noexcept -> void; - - constexpr auto assert(bool cond, - const std::source_location& - location = std::source_location::current()) noexcept -> void; - - constexpr auto expects(bool cond, - std::string_view message, - const std::source_location& - location = std::source_location::current()) noexcept -> void; - - constexpr auto expects(bool cond, - const std::source_location& - location = std::source_location::current()) noexcept -> void; - - constexpr auto ensures(bool cond, - std::string_view message, - const std::source_location& - location = std::source_location::current()) noexcept -> void; - - constexpr auto ensures(bool cond, - const std::source_location& - location = std::source_location::current()) noexcept -> void; - - namespace casts::core { - template To> - [[nodiscard]] - constexpr auto as(AssertType t) noexcept -> To; - } -}} // namespace stormkit::core - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -using namespace std::literals; -using namespace frozen::string_literals; - -namespace stormkit { inline namespace core { - namespace casts::core { namespace { - constexpr auto - AssertTypeToContractName = frozen::make_unordered_map({ - { AssertType::Assertion, "Contract check"_s }, - { AssertType::PreCondition, "Pre condition check"_s }, - { AssertType::PostCondition, "Post condition check"_s }, - }); - - }} // namespace casts::core - - struct StringLiteral { - std::array buff; - std::size_t size; - - consteval auto view() noexcept -> std::string_view { return { std::data(buff), size }; } - }; - - auto constevalFailure(StringLiteral) -> void; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto as_string(AssertType type) noexcept -> std::string_view { - const auto t = casts::core::AssertTypeToContractName.at(type); - return { stdr::data(t), stdr::size(t) }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto to_string(AssertType type) noexcept -> std::string { - const auto t = casts::core::AssertTypeToContractName.at(type); - return { stdr::data(t), stdr::size(t) }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - consteval auto generateConstevalMessage(AssertType type, std::string_view message) noexcept - -> StringLiteral { - auto result = StringLiteral {}; - const auto str = "[Assertion]"s + to_string(type) + ": " + std::string { message }; - std::ranges::copy(str, std::begin(result.buff)); - result.size = std::size(str); - return result; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - consteval auto consteval_assert_base(bool cond, - AssertType type, - std::string_view message) noexcept -> void { - if (not cond) [[unlikely]] { constevalFailure(generateConstevalMessage(type, message)); } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - constexpr auto assert(bool cond, - std::string_view message, - [[maybe_unused]] const std::source_location& location) noexcept -> void { -#ifdef STORMKIT_COMPILER_MSVC - if constexpr (std::is_constant_evaluated()) { -#else - if consteval { -#endif - consteval_assert_base(cond, AssertType::Assertion, message); - } else { - assert_base(cond, AssertType::Assertion, message, location); - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - constexpr auto assert(bool cond, const std::source_location& location) noexcept -> void { - assert(cond, "", location); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - constexpr auto expects(bool cond, - std::string_view message, - const std::source_location& location) noexcept -> void { -#ifdef STORMKIT_COMPILER_MSVC - if constexpr (std::is_constant_evaluated()) { -#else - if consteval { -#endif - consteval_assert_base(cond, AssertType::PreCondition, message); - } else { - assert_base(cond, AssertType::PreCondition, message, location); - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - constexpr auto expects(bool cond, const std::source_location& location) noexcept -> void { - expects(cond, "", location); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - constexpr auto ensures(bool cond, - std::string_view message, - const std::source_location& location) noexcept -> void { -#ifdef STORMKIT_COMPILER_MSVC - if constexpr (std::is_constant_evaluated()) { -#else - if consteval { -#endif - consteval_assert_base(cond, AssertType::PostCondition, message); - } else { - assert_base(cond, AssertType::PostCondition, message, location); - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - constexpr auto ensures(bool cond, const std::source_location& location) noexcept -> void { - ensures(cond, "", location); - } -}} // namespace stormkit::core +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include + +#ifndef STORMKIT_ASSERT + #define STORMKIT_ASSERT 1 +#endif + +export module stormkit.core:utils.contract; + +import std; +import frozen; + +import :utils.stracktrace; +import :containers.aliases; +import :string.aliases; + +import :meta; + +namespace stdr = std::ranges; + +export namespace stormkit { inline namespace core { + enum class AssertType { + Assertion, + PreCondition, + PostCondition, + }; + + constexpr auto as_string(AssertType type) noexcept -> string_view; + constexpr auto to_string(AssertType type) noexcept -> string; + + STORMKIT_CORE_API + auto assert_base(bool cond, + AssertType type, + string_view message, + const std::source_location& location = std::source_location::current()) noexcept -> void; + + consteval auto consteval_assert_base(bool cond, AssertType type, string_view message) noexcept -> void; + + constexpr auto assert(bool cond, + string_view message, + const std::source_location& location = std::source_location::current()) noexcept -> void; + + constexpr auto assert(bool cond, const std::source_location& location = std::source_location::current()) noexcept -> void; + + constexpr auto expects(bool cond, + string_view message, + const std::source_location& location = std::source_location::current()) noexcept -> void; + + constexpr auto expects(bool cond, const std::source_location& location = std::source_location::current()) noexcept -> void; + + constexpr auto ensures(bool cond, + string_view message, + const std::source_location& location = std::source_location::current()) noexcept -> void; + + constexpr auto ensures(bool cond, const std::source_location& location = std::source_location::current()) noexcept -> void; + + namespace casts::core { + template To> + [[nodiscard]] + constexpr auto as(AssertType t) noexcept -> To; + } +}} // namespace stormkit::core + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +using namespace std::literals; +using namespace frozen::string_literals; + +namespace stormkit { inline namespace core { + namespace casts::core { + constexpr auto AssertTypeToContractName = frozen::make_unordered_map({ + { AssertType::Assertion, "Contract check"_s }, + { AssertType::PreCondition, "Pre condition check"_s }, + { AssertType::PostCondition, "Post condition check"_s }, + }); + + } // namespace casts::core + + struct StringLiteral { + array buff; + std::size_t size; + + consteval auto view() noexcept -> string_view { return { std::data(buff), size }; } + }; + + auto constevalFailure(StringLiteral) -> void; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto as_string(AssertType type) noexcept -> string_view { + const auto t = casts::core::AssertTypeToContractName.at(type); + return { stdr::data(t), stdr::size(t) }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto to_string(AssertType type) noexcept -> string { + const auto t = casts::core::AssertTypeToContractName.at(type); + return { stdr::data(t), stdr::size(t) }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + consteval auto generateConstevalMessage(AssertType type, string_view message) noexcept -> StringLiteral { + auto result = StringLiteral {}; + const auto str = "[Assertion]"s + to_string(type) + ": " + string { message }; + std::ranges::copy(str, std::begin(result.buff)); + result.size = std::size(str); + return result; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + consteval auto consteval_assert_base(bool cond, AssertType type, string_view message) noexcept -> void { + if (not cond) [[unlikely]] { constevalFailure(generateConstevalMessage(type, message)); } + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto assert(bool cond, string_view message, [[maybe_unused]] const std::source_location& location) noexcept + -> void { +#ifdef STORMKIT_COMPILER_MSVC + if constexpr (std::is_constant_evaluated()) { +#else + if consteval { +#endif + consteval_assert_base(cond, AssertType::Assertion, message); + } else { + assert_base(cond, AssertType::Assertion, message, location); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto assert(bool cond, const std::source_location& location) noexcept -> void { + assert(cond, "", location); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto expects(bool cond, string_view message, const std::source_location& location) noexcept -> void { +#ifdef STORMKIT_COMPILER_MSVC + if constexpr (std::is_constant_evaluated()) { +#else + if consteval { +#endif + consteval_assert_base(cond, AssertType::PreCondition, message); + } else { + assert_base(cond, AssertType::PreCondition, message, location); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto expects(bool cond, const std::source_location& location) noexcept -> void { + expects(cond, "", location); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto ensures(bool cond, string_view message, const std::source_location& location) noexcept -> void { +#ifdef STORMKIT_COMPILER_MSVC + if constexpr (std::is_constant_evaluated()) { +#else + if consteval { +#endif + consteval_assert_base(cond, AssertType::PostCondition, message); + } else { + assert_base(cond, AssertType::PostCondition, message, location); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto ensures(bool cond, const std::source_location& location) noexcept -> void { + ensures(cond, "", location); + } +}} // namespace stormkit::core diff --git a/modules/stormkit/core/utils/deferinit.mpp b/modules/stormkit/core/utils/deferinit.cppm similarity index 69% rename from modules/stormkit/core/utils/deferinit.mpp rename to modules/stormkit/core/utils/deferinit.cppm index 5a3b7de28..a207197df 100644 --- a/modules/stormkit/core/utils/deferinit.mpp +++ b/modules/stormkit/core/utils/deferinit.cppm @@ -16,7 +16,7 @@ import :utils.contract; export namespace stormkit { inline namespace core { template - using DeferInitDefaultStorage = std::array; + using DeferInitDefaultStorage = array; template> class [[nodiscard]] DeferInit { @@ -26,9 +26,8 @@ export namespace stormkit { inline namespace core { using ReferenceType = ValueType&; // STL compatible - using value_type = ValueType; - using pointer_type = PointerType; - using reference_type = ReferenceType; + using value_type = ValueType; + using pointer = PointerType; constexpr DeferInit(); constexpr ~DeferInit(); @@ -36,25 +35,19 @@ export namespace stormkit { inline namespace core { DeferInit(const DeferInit& other) = delete; auto operator=(const DeferInit& other) -> DeferInit& = delete; - constexpr DeferInit(DeferInit&& - other) noexcept(noexcept(std::is_nothrow_move_constructible_v)); - constexpr auto operator=(DeferInit&& - other) noexcept(noexcept(std::is_nothrow_move_assignable_v)) - -> DeferInit&; + constexpr DeferInit(DeferInit&& other) noexcept(noexcept(std::is_nothrow_move_constructible_v)); + constexpr auto operator=(DeferInit&& other) noexcept(noexcept(std::is_nothrow_move_assignable_v)) -> DeferInit&; template - constexpr auto construct(Args&&... args) noexcept(noexcept(std::is_nothrow_constructible_v< - T, - Args...>)) -> void; + constexpr auto construct(Args&&... args) noexcept(noexcept(std::is_nothrow_constructible_v)) -> void; template - constexpr auto construct_with_narrowing(Args&&... args) noexcept( - noexcept(std::is_nothrow_constructible_v)) -> void; + constexpr auto construct_with_narrowing(Args&&... args) noexcept(noexcept(std::is_nothrow_constructible_v)) + -> void; - constexpr auto operator=(T&& value) noexcept(noexcept(std::is_nothrow_move_constructible_v< - T>)) -> void; + constexpr auto operator=(T&& value) noexcept(noexcept(std::is_nothrow_move_constructible_v)) -> void; - constexpr auto get(this auto&& self) noexcept -> decltype(auto); + constexpr auto value(this auto&& self) noexcept -> decltype(auto); constexpr auto operator->(this auto& self) noexcept -> decltype(auto); constexpr auto operator*(this auto&& self) noexcept -> decltype(auto); @@ -62,7 +55,7 @@ export namespace stormkit { inline namespace core { constexpr operator const T&() const noexcept; constexpr explicit operator bool() const noexcept; - constexpr auto initialized() const noexcept -> bool; + constexpr auto has_value() const noexcept -> bool; private: constexpr auto reset() noexcept -> void; @@ -80,12 +73,14 @@ namespace stormkit { inline namespace core { //////////////////////////////////////// //////////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr DeferInit::DeferInit() = default; + STORMKIT_FORCE_INLINE + constexpr DeferInit::DeferInit() = default; //////////////////////////////////////// //////////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr DeferInit::~DeferInit() { + STORMKIT_FORCE_INLINE + constexpr DeferInit::~DeferInit() { reset(); } @@ -93,12 +88,11 @@ namespace stormkit { inline namespace core { //////////////////////////////////////// template STORMKIT_FORCE_INLINE - constexpr DeferInit:: - DeferInit(DeferInit&& other) noexcept(noexcept(std::is_nothrow_move_constructible_v)) { + constexpr DeferInit::DeferInit(DeferInit&& other) noexcept(noexcept(std::is_nothrow_move_constructible_v)) { reset(); - if (other.initialized()) [[likely]] { - m_pointer = new (std::data(m_data)) T { std::move(other.get()) }; + if (other.has_value()) [[likely]] { + m_pointer = new (std::data(m_data)) T { std::move(other.value()) }; other.reset(); } @@ -108,16 +102,15 @@ namespace stormkit { inline namespace core { //////////////////////////////////////// template STORMKIT_FORCE_INLINE - constexpr auto DeferInit:: - operator=(DeferInit&& other) noexcept(noexcept(std::is_nothrow_move_assignable_v)) - -> DeferInit& { + constexpr auto DeferInit::operator=(DeferInit&& other) noexcept(noexcept(std::is_nothrow_move_assignable_v)) + -> DeferInit& { if (&other == this) [[unlikely]] return *this; reset(); - if (other.initialized()) [[likely]] { - m_pointer = new (std::data(m_data)) T { std::move(other.get()) }; + if (other.has_value()) [[likely]] { + m_pointer = new (std::data(m_data)) T { std::move(other.value()) }; other.reset(); } @@ -130,9 +123,9 @@ namespace stormkit { inline namespace core { template template STORMKIT_FORCE_INLINE - constexpr auto DeferInit:: - construct(Args&&... args) noexcept(noexcept(std::is_nothrow_constructible_v)) - -> void { + constexpr auto DeferInit::construct(Args&&... args) noexcept(noexcept(std::is_nothrow_constructible_v)) + -> void { reset(); m_pointer = new (std::data(m_data)) T { std::forward(args)... }; @@ -143,8 +136,8 @@ namespace stormkit { inline namespace core { template template STORMKIT_FORCE_INLINE - constexpr auto DeferInit::construct_with_narrowing(Args&&... args) noexcept( - noexcept(std::is_nothrow_constructible_v)) -> void { + constexpr auto DeferInit:: + construct_with_narrowing(Args&&... args) noexcept(noexcept(std::is_nothrow_constructible_v)) -> void { reset(); m_pointer = new (std::data(m_data)) T(std::forward(args)...); @@ -154,8 +147,8 @@ namespace stormkit { inline namespace core { //////////////////////////////////////// template STORMKIT_FORCE_INLINE - constexpr auto DeferInit:: - operator=(T&& value) noexcept(noexcept(std::is_nothrow_move_constructible_v)) -> void { + constexpr auto DeferInit::operator=(T&& value) noexcept(noexcept(std::is_nothrow_move_constructible_v)) + -> void { reset(); m_pointer = new (std::data(m_data)) T { std::move(value) }; @@ -166,14 +159,14 @@ namespace stormkit { inline namespace core { template STORMKIT_FORCE_INLINE constexpr DeferInit::operator bool() const noexcept { - return initialized(); + return has_value(); } //////////////////////////////////////// //////////////////////////////////////// template STORMKIT_FORCE_INLINE - constexpr auto DeferInit::initialized() const noexcept -> bool { + constexpr auto DeferInit::has_value() const noexcept -> bool { return m_pointer != nullptr; } @@ -183,7 +176,7 @@ namespace stormkit { inline namespace core { STORMKIT_FORCE_INLINE constexpr auto DeferInit::reset() noexcept -> void { if (m_pointer) [[likely]] { - get().~T(); + value().~T(); m_pointer = nullptr; } } @@ -192,8 +185,8 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template STORMKIT_FORCE_INLINE - constexpr auto DeferInit::get(this auto&& self) noexcept -> decltype(auto) { - expects(self.initialized(), "Underlying object is not initialized"); + constexpr auto DeferInit::value(this auto&& self) noexcept -> decltype(auto) { + expects(self.has_value(), "Underlying object is not has_value"); return std::forward_like(*self.m_pointer); } @@ -203,7 +196,7 @@ namespace stormkit { inline namespace core { template STORMKIT_FORCE_INLINE constexpr auto DeferInit::operator->(this auto& self) noexcept -> decltype(auto) { - expects(self.initialized(), "Underlying object is not initialized"); + expects(self.has_value(), "Underlying object is not has_value"); return std::forward_like(self.m_pointer); } @@ -213,7 +206,7 @@ namespace stormkit { inline namespace core { template STORMKIT_FORCE_INLINE constexpr auto DeferInit::operator*(this auto&& self) noexcept -> decltype(auto) { - return std::forward_like(self.get()); + return std::forward_like(self.value()); } ///////////////////////////////////// @@ -221,7 +214,7 @@ namespace stormkit { inline namespace core { template STORMKIT_FORCE_INLINE constexpr DeferInit::operator T&() noexcept { - return get(); + return value(); } ///////////////////////////////////// @@ -229,8 +222,8 @@ namespace stormkit { inline namespace core { template STORMKIT_FORCE_INLINE constexpr DeferInit::operator const T&() const noexcept { - return get(); + return value(); } }} // namespace stormkit::core -static_assert(stormkit::meta::IsContainedSemantics>); +static_assert(stormkit::meta::IsContainer>); diff --git a/modules/stormkit/core/utils/dynamic_loader.mpp b/modules/stormkit/core/utils/dynamic_loader.cppm similarity index 77% rename from modules/stormkit/core/utils/dynamic_loader.mpp rename to modules/stormkit/core/utils/dynamic_loader.cppm index 50ccbb802..8fc61fe5d 100644 --- a/modules/stormkit/core/utils/dynamic_loader.mpp +++ b/modules/stormkit/core/utils/dynamic_loader.cppm @@ -1,139 +1,134 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -#include - -#include - -export module stormkit.core:utils.dynamic_loader; - -import std; - -import :utils.contract; -import :utils.pimpl; - -export namespace stormkit { inline namespace core { - class STORMKIT_API DynamicLoader { - public: - template - using Expected = std::expected; - - ~DynamicLoader(); - - DynamicLoader(const DynamicLoader&) = delete; - auto operator=(const DynamicLoader&) -> DynamicLoader& = delete; - - DynamicLoader(DynamicLoader&&) noexcept; - auto operator=(DynamicLoader&&) noexcept -> DynamicLoader&; - - [[nodiscard]] - static auto load(std::filesystem::path filepath) noexcept -> Expected; - - [[nodiscard]] - static auto allocate_and_load(std::filesystem::path filepath) noexcept - -> Expected>; - - template - [[nodiscard]] - auto func(std::string_view name) const noexcept -> Expected>; - - template - [[nodiscard]] - auto c_func(std::string_view name) const noexcept -> Expected; - - [[nodiscard]] - auto filepath() const noexcept -> const std::filesystem::path&; - - private: - DynamicLoader() noexcept; - - auto do_load(std::filesystem::path filepath) -> Expected; - auto do_get_func(std::string_view name) const -> Expected; - - std::filesystem::path m_filepath; - void* m_library_handle = nullptr; - }; -}} // namespace stormkit::core - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit { inline namespace core { - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - DynamicLoader::DynamicLoader() noexcept - = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - DynamicLoader::DynamicLoader(DynamicLoader&& other) noexcept - : m_filepath { std::move(other.m_filepath) }, - m_library_handle { std::exchange(other.m_library_handle, nullptr) } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - auto DynamicLoader::operator=(DynamicLoader&& other) noexcept -> DynamicLoader& { - if (&other == this) [[unlikely]] - return *this; - - m_filepath = std::move(other.m_filepath); - m_library_handle = std::exchange(other.m_library_handle, nullptr); - - return *this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto DynamicLoader::load(std::filesystem::path filepath) noexcept - -> Expected { - auto loader = DynamicLoader {}; - - return loader.do_load(std::move(filepath)).transform([&]() { return std::move(loader); }); - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto DynamicLoader::allocate_and_load(std::filesystem::path filepath) noexcept - -> Expected> { - return load(std::move(filepath)).transform([](auto&& loader) { - return std::make_unique(std::move(loader)); - }); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - auto DynamicLoader::func(std::string_view name) const noexcept - -> Expected> { - return c_func(name).transform([](T&& value) { - return std::function { std::forward(value) }; - }); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - auto DynamicLoader::c_func(std::string_view name) const noexcept -> Expected { - EXPECTS(not std::empty(name)); - - return do_get_func(name).transform([](T&& value) { - return std::bit_cast(std::forward(value)); - }); - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto DynamicLoader::filepath() const noexcept -> const std::filesystem::path& { - return m_filepath; - } -}} // namespace stormkit::core +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include +#include +#include + +export module stormkit.core:utils.dynamic_loader; + +import std; + +import :utils.contract; +import :utils.pimpl; + +export namespace stormkit { inline namespace core { + class STORMKIT_CORE_API DynamicLoader { + public: + template + using Expected = std::expected; + + ~DynamicLoader(); + + DynamicLoader(const DynamicLoader&) = delete; + auto operator=(const DynamicLoader&) -> DynamicLoader& = delete; + + DynamicLoader(DynamicLoader&&) noexcept; + auto operator=(DynamicLoader&&) noexcept -> DynamicLoader&; + + [[nodiscard]] + static auto load(std::filesystem::path filepath) noexcept -> Expected; + + [[nodiscard]] + static auto allocate_and_load(std::filesystem::path filepath) noexcept -> Expected>; + + template + [[nodiscard]] + auto func(string_view name) const noexcept -> Expected>; + + template + [[nodiscard]] + auto c_func(string_view name) const noexcept -> Expected; + + [[nodiscard]] + auto filepath() const noexcept -> const std::filesystem::path&; + + private: + DynamicLoader() noexcept; + + auto do_load(std::filesystem::path filepath) -> Expected; + auto do_get_func(string_view name) const -> Expected; + + std::filesystem::path m_filepath; + void* m_library_handle = nullptr; + }; +}} // namespace stormkit::core + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit { inline namespace core { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline DynamicLoader::DynamicLoader() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline DynamicLoader::DynamicLoader(DynamicLoader&& other) noexcept + : m_filepath { std::move(other.m_filepath) }, m_library_handle { std::exchange(other.m_library_handle, nullptr) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto DynamicLoader::operator=(DynamicLoader&& other) noexcept -> DynamicLoader& { + if (&other == this) [[unlikely]] + return *this; + + m_filepath = std::move(other.m_filepath); + m_library_handle = std::exchange(other.m_library_handle, nullptr); + + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto DynamicLoader::load(std::filesystem::path filepath) noexcept -> Expected { + auto loader = DynamicLoader {}; + + return loader.do_load(std::move(filepath)).transform([&]() { return std::move(loader); }); + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto DynamicLoader::allocate_and_load(std::filesystem::path filepath) noexcept + -> Expected> { + return load(std::move(filepath)).transform([](auto&& loader) { + return std::make_unique(std::move(loader)); + }); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + inline auto DynamicLoader::func(string_view name) const noexcept -> Expected> { + return c_func(name).transform([](T&& value) { + return std::function { std::forward(value) }; + }); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + inline auto DynamicLoader::c_func(string_view name) const noexcept -> Expected { + EXPECTS(not std::empty(name)); + + return do_get_func(name).transform([](T&& value) { + return std::bit_cast(std::forward(value)); + }); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto DynamicLoader::filepath() const noexcept -> const std::filesystem::path& { + return m_filepath; + } +}} // namespace stormkit::core diff --git a/modules/stormkit/core/utils/filesystem.mpp b/modules/stormkit/core/utils/filesystem.cppm similarity index 54% rename from modules/stormkit/core/utils/filesystem.mpp rename to modules/stormkit/core/utils/filesystem.cppm index a213fd5b4..57196d042 100644 --- a/modules/stormkit/core/utils/filesystem.mpp +++ b/modules/stormkit/core/utils/filesystem.cppm @@ -9,7 +9,11 @@ module; #include #include +#include + #ifdef STORMKIT_OS_WINDOWS + #include + #include #include #include @@ -33,7 +37,8 @@ import :utils.contract; import :typesafe; import :functional; import :meta; -import :containers; +import :named_constructors; +// import :containers; namespace stdfs = std::filesystem; @@ -55,80 +60,89 @@ namespace stormkit { inline namespace core { namespace io::meta { }}} // namespace stormkit::core::io::meta export { - namespace stormkit { inline namespace core { namespace io { - template - using Expected = std::expected; + namespace stormkit { inline namespace core { + namespace io { + template + using Expected = std::expected; + + enum class Access { + READ, + WRITE, + }; - enum class Access { - READ, - WRITE, - }; + template + class Descriptor; + } // namespace io - template - class Descriptor { - struct PrivateFuncTag {}; + namespace io { + template + class Descriptor final: public NamedConstructor, DoInitArgs> { + using Base = NamedConstructor, DoInitArgs>; - public: - static auto open(const stdfs::path& path, Access access) noexcept - -> Expected; - auto close() noexcept; + public: + explicit Descriptor(PrivateTag) noexcept; + ~Descriptor() noexcept; - ~Descriptor() noexcept; + Descriptor(Descriptor&) = delete; + auto operator=(Descriptor&) -> Descriptor& = delete; - Descriptor(Descriptor&) = delete; - auto operator=(Descriptor&) -> Descriptor& = delete; + Descriptor(Descriptor&&) noexcept; + auto operator=(Descriptor&&) noexcept -> Descriptor&; - Descriptor(Descriptor&&) noexcept; - auto operator=(Descriptor&&) noexcept -> Descriptor&; + static auto open(const stdfs::path& path, Access access) noexcept -> Expected; + static auto allocate_and_open(const stdfs::path& path, Access access) noexcept -> Expected; - auto read_to(std::span out) noexcept -> Expected; - auto read_to(std::span out) noexcept -> Expected - requires(mode == Mode::UTF8 or mode == Mode::AINSI); - auto read_to(std::span out) noexcept -> Expected - requires(mode == Mode::WIDE); + auto close() noexcept; - auto write(std::span bytes) noexcept -> Expected; - auto write(std::span bytes) noexcept -> Expected - requires(mode == Mode::UTF8 or mode == Mode::AINSI); - auto write(std::span bytes) noexcept -> Expected - requires(mode == Mode::WIDE); + auto read_to(byte_mut_view<> out) noexcept -> Expected; + auto read_to(array_view out) noexcept -> Expected + requires(mode == Mode::UTF8 or mode == Mode::AINSI); + auto read_to(array_view out) noexcept -> Expected + requires(mode == Mode::WIDE); - auto flush() noexcept -> void; + auto write(byte_view<> bytes) noexcept -> Expected; + auto write(array_view bytes) noexcept -> Expected + requires(mode == Mode::UTF8 or mode == Mode::AINSI); + auto write(array_view bytes) noexcept -> Expected + requires(mode == Mode::WIDE); - auto position() const noexcept -> usize; - auto size() const noexcept -> usize; + auto flush() noexcept -> void; - auto native_descriptor() const noexcept -> int; + auto position() const noexcept -> usize; + auto size() const noexcept -> usize; - Descriptor(PrivateFuncTag, int descriptor) noexcept; + auto native_descriptor() const noexcept -> int; - private: - int m_descriptor = 0; + auto do_init(PrivateTag, const stdfs::path&, Access) noexcept -> Expected; - mutable std::atomic m_size = 0; - }; + private: + using Base::allocate; + using Base::create; - using File = Descriptor; - template - requires(mode != Mode::BINARY) - using TextFile = Descriptor; - - template - auto read_text_to(const stdfs::path& path, - std::span> output) noexcept -> Expected; - template - auto read_text(const stdfs::path& path) noexcept - -> Expected>>; - - auto read_to(const stdfs::path& path, std::span output) noexcept -> Expected; - auto read(const stdfs::path& path) noexcept -> Expected>; - - template - auto write_text(const stdfs::path& path, - std::span> data) noexcept - -> Expected; - auto write(const stdfs::path& path, std::span data) noexcept -> Expected; - }}} // namespace stormkit::core::io + int m_descriptor = 0; + + mutable std::atomic m_size = 0; + }; + + using File = Descriptor; + template + requires(mode != Mode::BINARY) + using TextFile = Descriptor; + + template + auto read_text_to(const stdfs::path& path, array_view> output) noexcept -> Expected; + template + auto read_text(const stdfs::path& path) noexcept -> Expected>>; + + auto read_to(const stdfs::path& path, byte_mut_view<> output) noexcept -> Expected; + auto read(const stdfs::path& path) noexcept -> Expected; + + template + auto write_text(const stdfs::path& path, array_view> data) noexcept + -> Expected; + auto write(const stdfs::path& path, byte_view<> data) noexcept -> Expected; + } // namespace io + }} // namespace stormkit::core FLAG_ENUM(stormkit::core::io::Access); } // namespace stormkit::core::io @@ -140,75 +154,11 @@ export { namespace stdr = std::ranges; namespace stormkit { inline namespace core { namespace io { - //////////////////////////////////////// - //////////////////////////////////////// - template - inline auto Descriptor::open(const stdfs::path& path, Access access) noexcept - -> Expected> { - const auto p = path.string(); - const auto posix_access = [&access]() noexcept { - if (access == Access::READ) return O_RDONLY; - else if (access == Access::WRITE) - return O_WRONLY; - else - return O_RDWR; - std::unreachable(); - }(); - -#ifdef STORMKIT_OS_WINDOWS - const auto text_mode = []() noexcept { - switch (mode) { - case Mode::BINARY: return 0; - #ifdef STORMKIT_OS_WINDOWS - case Mode::UTF8: return _O_U8TEXT; - case Mode::WIDE: return _O_WTEXT; - default: break; - #else - default: return 0; - #endif - }; - std::unreachable(); - }(); - - const auto win32_access = [&access]() noexcept { - if (access == Access::READ) return _S_IREAD; - else if (access == Access::WRITE) - return _S_IWRITE; - else - return _S_IREAD | _S_IWRITE; - std::unreachable(); - }(); - - auto ret = 0; - const auto - // err = _sopen_s(&ret, stdr::data(p), posix_access | text_mode, _SH_DENYNO, - // win32_access); - err - = _sopen_s(&ret, stdr::data(p), posix_access | text_mode, _SH_SECURE, win32_access); - if (err != 0) return std::unexpected { SystemError::from_errno() }; -#else - const auto ret = ::open(stdr::data(p), posix_access); - if (ret == -1) return std::unexpected { SystemError::from_errno() }; -#endif - return Expected> { std::in_place, PrivateFuncTag {}, ret }; - } - //////////////////////////////////////// //////////////////////////////////////// template STORMKIT_FORCE_INLINE - inline auto Descriptor::close() noexcept { - if (m_descriptor != 0) { - flush(); -#ifdef STORMKIT_OS_WINDOWS - _close -#else - ::close -#endif - (m_descriptor); - m_descriptor = 0; - m_size = 0; - } + inline Descriptor::Descriptor(PrivateTag) noexcept { } //////////////////////////////////////// @@ -240,13 +190,50 @@ namespace stormkit { inline namespace core { namespace io { m_descriptor = std::exchange(other.m_descriptor, 0); m_size = other.m_size.load(); other.m_size.store(0); + + return *this; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Descriptor::open(const stdfs::path& path, Access access) noexcept -> Expected> { + return Descriptor::create(path, access); } //////////////////////////////////////// //////////////////////////////////////// template STORMKIT_FORCE_INLINE - inline auto Descriptor::read_to(std::span out) noexcept -> Expected { + inline auto Descriptor::allocate_and_open(const stdfs::path& path, Access access) noexcept + -> Expected> { + return Descriptor::allocate(path, access); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Descriptor::close() noexcept { + if (m_descriptor != 0) { + flush(); +#ifdef STORMKIT_OS_WINDOWS + _close +#else + ::close +#endif + (m_descriptor); + m_descriptor = 0; + m_size = 0; + } + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Descriptor::read_to(byte_mut_view<> out) noexcept -> Expected { EXPECTS(m_descriptor != 0); const auto ret = #ifdef STORMKIT_OS_WINDOWS @@ -264,27 +251,27 @@ namespace stormkit { inline namespace core { namespace io { //////////////////////////////////////// template STORMKIT_FORCE_INLINE - inline auto Descriptor::read_to(std::span out) noexcept -> Expected + inline auto Descriptor::read_to(array_view out) noexcept -> Expected requires(mode == Mode::UTF8 or mode == Mode::AINSI) { - return read_to(as_bytes(out)); + return read_to(as_bytes_mut(out)); } //////////////////////////////////////// //////////////////////////////////////// template STORMKIT_FORCE_INLINE - inline auto Descriptor::read_to(std::span out) noexcept -> Expected + inline auto Descriptor::read_to(array_view out) noexcept -> Expected requires(mode == Mode::WIDE) { - return read_to(as_bytes(out)); + return read_to(as_bytes_mut(out)); } //////////////////////////////////////// //////////////////////////////////////// template STORMKIT_FORCE_INLINE - inline auto Descriptor::write(std::span data) noexcept -> Expected { + inline auto Descriptor::write(byte_view<> data) noexcept -> Expected { EXPECTS(m_descriptor != 0); const auto ret = #ifdef STORMKIT_OS_WINDOWS @@ -302,7 +289,7 @@ namespace stormkit { inline namespace core { namespace io { //////////////////////////////////////// template STORMKIT_FORCE_INLINE - inline auto Descriptor::write(std::span data) noexcept -> Expected + inline auto Descriptor::write(array_view data) noexcept -> Expected requires(mode == Mode::UTF8 or mode == Mode::AINSI) { return write(as_bytes(data)); @@ -312,7 +299,7 @@ namespace stormkit { inline namespace core { namespace io { //////////////////////////////////////// template STORMKIT_FORCE_INLINE - inline auto Descriptor::write(std::span data) noexcept -> Expected + inline auto Descriptor::write(array_view data) noexcept -> Expected requires(mode == Mode::WIDE) { return write(as_bytes(data)); @@ -325,13 +312,15 @@ namespace stormkit { inline namespace core { namespace io { inline auto Descriptor::flush() noexcept -> void { EXPECTS(m_descriptor != 0); #ifdef STORMKIT_OS_WINDOWS - _commit -#elifdef STORMKIT_OS_LINUX - fdatasync + FlushFileBuffers(reinterpret_cast(m_descriptor)); #else + #ifdef STORMKIT_OS_LINUX + fdatasync + #else fsync -#endif + #endif (m_descriptor); +#endif } //////////////////////////////////////// @@ -352,7 +341,6 @@ namespace stormkit { inline namespace core { namespace io { //////////////////////////////////////// //////////////////////////////////////// template - STORMKIT_FORCE_INLINE inline auto Descriptor::size() const noexcept -> usize { EXPECTS(m_descriptor != 0); if (m_size == 0) { @@ -383,80 +371,115 @@ namespace stormkit { inline namespace core { namespace io { //////////////////////////////////////// //////////////////////////////////////// template - STORMKIT_FORCE_INLINE - inline Descriptor::Descriptor(PrivateFuncTag, int descriptor) noexcept - : m_descriptor { descriptor } { + inline auto Descriptor::do_init(PrivateTag, const stdfs::path& path, Access access) noexcept -> Expected { + if (access == Access::READ and not stdfs::exists(path)) + return std::unexpected { SystemError { .code = std::errc::no_such_file_or_directory } }; + if (stdfs::is_directory(path)) return std::unexpected { SystemError { .code = std::errc::is_a_directory } }; + + const auto posix_access = [&access]() noexcept { +#ifdef STORMKIT_OS_WINDOWS + if (access == Access::READ) return _O_RDONLY; + else if (access == Access::WRITE) + return (_O_WRONLY | _O_CREAT); + else + return _O_RDWR; +#else + if (access == Access::READ) return O_RDONLY; + else if (access == Access::WRITE) + return O_WRONLY | O_CREAT; + else + return O_RDWR; +#endif + std::unreachable(); + }(); + +#ifdef STORMKIT_OS_WINDOWS + const auto text_mode = []() noexcept { + switch (mode) { + #ifdef STORMKIT_OS_WINDOWS + case Mode::BINARY: return _O_BINARY; + case Mode::AINSI: [[fallthrough]]; + case Mode::UTF8: return _O_TEXT; + case Mode::WIDE: return _O_WTEXT; + default: break; + #else + default: return 0; + #endif + }; + std::unreachable(); + }(); + + auto ret = 0; + auto str = path.string(); + const auto // + err = _sopen_s(&ret, str.c_str(), posix_access | text_mode, _SH_DENYNO, _S_IREAD); + if (err != 0) return std::unexpected { SystemError::from_errno() }; +#else + const auto ret = ::open(path.c_str(), posix_access); + if (ret == -1) return std::unexpected { SystemError::from_errno() }; +#endif + m_descriptor = ret; + return {}; } //////////////////////////////////////// //////////////////////////////////////// - template + template STORMKIT_FORCE_INLINE - inline auto read_text_to(const stdfs::path& path, - std::span> out) noexcept - -> Expected { - return TextFile::open(path, Access::READ) - .and_then([&out](auto&& file) mutable noexcept { - EXPECTS(file.size() >= stdr::size(out)); - return file.read_to(out); - }); + inline auto read_text_to(const stdfs::path& path, array_view> out) noexcept -> Expected { + auto file = Try((TextFile::open(path, Access::READ))); + ENSURES(stdr::size(out) >= file.size()); + Return Try(file.read_to(out)); } //////////////////////////////////////// //////////////////////////////////////// - template + template STORMKIT_FORCE_INLINE - inline auto read_text(const stdfs::path& path) noexcept - -> Expected>> { - auto out = std::vector> {}; - return TextFile::open(path, Access::READ) - .and_then([&out](auto&& file) mutable noexcept { - out.resize(file.size()); - return file.read_to(out); - }) - .transform(monadic::discard()) - .transform(monadic::consume(out)); + inline auto read_text(const stdfs::path& path) noexcept -> Expected>> { + auto file = Try((TextFile::open(path, Access::READ))); + auto out = dyn_array> {}; + out.resize(file.size()); + auto readed = Try(file.read_to(out)); + out.resize(readed); + Return out; } //////////////////////////////////////// //////////////////////////////////////// STORMKIT_FORCE_INLINE - inline auto read_to(const stdfs::path& path, std::span out) noexcept -> Expected { - return File::open(path, Access::READ).and_then([&out](auto&& file) mutable noexcept { - EXPECTS(file.size() >= stdr::size(out)); - return file.read_to(out); - }); + inline auto read_to(const stdfs::path& path, byte_mut_view<> out) noexcept -> Expected { + auto file = Try((File::open(path, Access::READ))); + Return Try(file.read_to(out)); } //////////////////////////////////////// //////////////////////////////////////// STORMKIT_FORCE_INLINE - inline auto read(const stdfs::path& path) noexcept -> Expected> { - auto out = std::vector {}; - return File::open(path, Access::READ) - .and_then([&out](auto&& file) mutable noexcept { - out.resize(file.size()); - return file.read_to(out); - }) - .transform(monadic::discard()) - .transform(monadic::consume(out)); + inline auto read(const stdfs::path& path) noexcept -> Expected { + auto file = Try((File::open(path, Access::READ))); + auto out = byte_dyn_array {}; + out.resize(file.size()); + auto readed = Try(file.read_to(out)); + out.resize(readed); + Return out; } //////////////////////////////////////// //////////////////////////////////////// - template + template STORMKIT_FORCE_INLINE - inline auto write_text(const stdfs::path& path, - std::span> data) noexcept + inline auto write_text(const stdfs::path& path, array_view> data) noexcept -> Expected { - return TextFile::open(path, Access::WRITE).and_then(bind_back(&File::write, data)); + auto file = Try((TextFile::open(path, Access::WRITE))); + Return Try(file.write(data)); } //////////////////////////////////////// //////////////////////////////////////// STORMKIT_FORCE_INLINE - inline auto write(const stdfs::path& path, std::span data) noexcept - -> Expected { - return File::open(path, Access::WRITE).and_then(std::bind_back(&File::write, data)); + inline auto write(const stdfs::path& path, byte_view<> data) noexcept -> Expected { + auto file = Try((File::open(path, Access::WRITE))); + Return Try(file.write(data)); } }}} // namespace stormkit::core::io diff --git a/modules/stormkit/core/utils/function_ref.cppm b/modules/stormkit/core/utils/function_ref.cppm new file mode 100644 index 000000000..3410b409e --- /dev/null +++ b/modules/stormkit/core/utils/function_ref.cppm @@ -0,0 +1,8 @@ +export module stormkit.core:utils.std23_functional; + +export import nontype_functional; + +export namespace std23 { + using std23::function_ref; + using std23::move_only_function; +} // namespace std23 diff --git a/modules/stormkit/core/utils/function_ref.mpp b/modules/stormkit/core/utils/function_ref.mpp deleted file mode 100644 index cb48aa41b..000000000 --- a/modules/stormkit/core/utils/function_ref.mpp +++ /dev/null @@ -1,12 +0,0 @@ -module; - -#include - -export module stormkit.core:utils.function_ref; - -export namespace stormkit { inline namespace core { - using tl::swap; - - template - using FunctionRef = tl::function_ref; -}} // namespace stormkit::core diff --git a/modules/stormkit/core/utils/handle.cppm b/modules/stormkit/core/utils/handle.cppm new file mode 100644 index 000000000..3486bd948 --- /dev/null +++ b/modules/stormkit/core/utils/handle.cppm @@ -0,0 +1,136 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +#include + +export module stormkit.core:utils.handle; + +import std; + +import :hash; +import :typesafe.safecasts; +import :typesafe.integer; +import :meta; + +export namespace stormkit { inline namespace core { + template + struct Handle { + using ID = _ID; + + static constexpr auto INVALID_HANDLE_VALUE = std::numeric_limits::max(); + + [[nodiscard]] + constexpr auto operator<=>(const Handle&) const noexcept -> std::strong_ordering = default; + + template U> + constexpr operator Handle() const noexcept; + + constexpr auto& operator++() noexcept; + + constexpr auto operator++(int) noexcept; + + constexpr auto& operator--() noexcept; + + constexpr auto operator--(int) noexcept; + + constexpr operator ID() const noexcept; + + [[nodiscard]] + static constexpr auto invalid_handle() noexcept -> Handle; + + ID id = INVALID_HANDLE_VALUE; + }; + + template + using Handle32 = Handle; + + template + using Handle64 = Handle; + + template + constexpr auto hasher(const Handle& value) noexcept -> Ret; + + template + auto format_as(const Handle& value, FormatContext& ctx) noexcept -> decltype(ctx.out()); +}} // namespace stormkit::core + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit { inline namespace core { + ///////////////////////////////////// + ///////////////////////////////////// + template + template U> + constexpr Handle::operator Handle() const noexcept { + return Handle { id }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + constexpr auto& Handle::operator++() noexcept { + ++id; + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + constexpr auto Handle::operator++(int) noexcept { + auto old = *this; + operator++(); + return old; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + constexpr auto& Handle::operator--() noexcept { + --id; + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + constexpr auto Handle::operator--(int) noexcept { + auto old = *this; + operator--(); + return old; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + constexpr Handle::operator ID() const noexcept { + return id; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + constexpr auto Handle::invalid_handle() noexcept -> Handle { + return Handle {}; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + constexpr auto hasher(const Handle& value) noexcept -> Ret { + return hash(value.id); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto format_as(const Handle& value, FormatContext& ctx) noexcept -> decltype(ctx.out()) { + return std::format_to(ctx.out(), "[handle id: {}]", value.id); + } +}} // namespace stormkit::core diff --git a/modules/stormkit/core/utils/handle.mpp b/modules/stormkit/core/utils/handle.mpp deleted file mode 100644 index d2f81c4e8..000000000 --- a/modules/stormkit/core/utils/handle.mpp +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -#include - -export module stormkit.core:utils.handle; - -import std; - -import :hash; -import :typesafe.safecasts; -import :typesafe.integer; -import :meta; - -export { - namespace stormkit { inline namespace core { - template - struct Handle { - using ID = _ID; - - static constexpr auto INVALID_HANDLE_VALUE = std::numeric_limits::max(); - - [[nodiscard]] - constexpr auto operator<=>(const Handle&) const noexcept -> std::strong_ordering - = default; - - template U> - constexpr operator Handle() const noexcept; - - constexpr auto& operator++() noexcept; - - constexpr auto operator++(int) noexcept; - - constexpr auto& operator--() noexcept; - - constexpr auto operator--(int) noexcept; - - constexpr operator ID() const noexcept; - - [[nodiscard]] - static constexpr auto invalid_handle() noexcept -> Handle; - - ID id = INVALID_HANDLE_VALUE; - }; - - template - using Handle32 = Handle; - - template - using Handle64 = Handle; - }} // namespace stormkit::core - - template - struct std::hash> { - [[nodiscard]] - constexpr auto operator()(stormkit::core::Handle handle) const noexcept - -> stormkit::core::hash64; - }; -} - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit { inline namespace core { - ///////////////////////////////////// - ///////////////////////////////////// - template - template U> - constexpr Handle::operator Handle() const noexcept { - return Handle { id }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - constexpr auto& Handle::operator++() noexcept { - ++id; - return *this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - constexpr auto Handle::operator++(int) noexcept { - auto old = *this; - operator++(); - return old; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - constexpr auto& Handle::operator--() noexcept { - --id; - return *this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - constexpr auto Handle::operator--(int) noexcept { - auto old = *this; - operator--(); - return old; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - constexpr Handle::operator ID() const noexcept { - return id; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - constexpr auto Handle::invalid_handle() noexcept -> Handle { - return Handle {}; - } -}} // namespace stormkit::core - -///////////////////////////////////// -///////////////////////////////////// -template -constexpr stormkit::core::hash64 std::hash>::operator()( - stormkit::core::Handle handle) const noexcept { - return stormkit::core::as(handle.id); -} diff --git a/modules/stormkit/core/utils/numeric_range.mpp b/modules/stormkit/core/utils/numeric_range.cppm similarity index 83% rename from modules/stormkit/core/utils/numeric_range.mpp rename to modules/stormkit/core/utils/numeric_range.cppm index 88add312f..3a5e57ff6 100644 --- a/modules/stormkit/core/utils/numeric_range.mpp +++ b/modules/stormkit/core/utils/numeric_range.cppm @@ -1,329 +1,308 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -export module stormkit.core:utils.numeric_range; - -import std; - -import :meta; - -import :typesafe; - -import :coroutines; - -export namespace stormkit { inline namespace core { - template - struct NumericsRange { - using RangeType = T; - T begin; - T end; - T step = T { 1 }; - }; - - namespace meta { - template - concept IsNumericsRange = requires(const T& t) { - t.begin; - t.end; - t.step; - typename T::RangeType; - }; - - template - concept IsNumericsRangePure = IsNumericsRange>; - } // namespace meta - - template - [[nodiscard]] - constexpr auto range(const T& end) noexcept -> decltype(auto); - - template - [[nodiscard]] - constexpr auto range(const T& begin, const U& end) noexcept -> decltype(auto); - - template - [[nodiscard]] - constexpr auto range(const T& begin, const U& end, const V& step) noexcept -> decltype(auto); - - [[nodiscard]] - constexpr auto range(meta::IsNumericsRangePure auto&& range) noexcept -> decltype(auto); - - template - [[nodiscard]] - constexpr auto multi_range(const Args&... args) noexcept -> decltype(auto); - - template - [[nodiscard]] - constexpr auto multi_range(Args&&... args) noexcept -> decltype(auto); -}} // namespace stormkit::core - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stdr = std::ranges; -namespace stdv = std::views; - -namespace stormkit { inline namespace core { -#define FOR(a, b) for (auto a = b.begin; a < b.end; a += b.step) -#define YIELD(...) co_yield { __VA_ARGS__ }; - - ///////////////////////////////////// - ///////////////////////////////////// - template - auto range_implementation(T a, U b) noexcept - -> std::generator> { - FOR(i, a) - FOR(j, b) - YIELD(i, j) - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - auto range_implementation(T a, U b, V c) noexcept - -> std::generator> { - FOR(i, a) - FOR(j, b) - FOR(k, c) - YIELD(i, j, k) - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - auto range_implementation(T a, U b, V c, W d) noexcept -> std::generator< - std::tuple> { - FOR(i, a) - FOR(j, b) - FOR(k, c) - FOR(l, d) - YIELD(i, j, k, l) - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - auto range_implementation(T a, U b, V c, W d, X e) noexcept - -> std::generator> { - FOR(i, a) - FOR(j, b) - FOR(k, c) - FOR(l, d) - FOR(m, e) - YIELD(i, j, k, l, m) - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - auto range_implementation(T a, U b, V c, W d, X e, Y f) noexcept - -> std::generator> { - FOR(i, a) - FOR(j, b) - FOR(k, c) - FOR(l, d) - FOR(m, e) - FOR(n, f) - YIELD(i, j, k, l, m, n) - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - auto range_implementation(T a, U b, V c, W d, X e, Y f, Z g) noexcept - -> std::generator> { - FOR(i, a) - FOR(j, b) - FOR(k, c) - FOR(l, d) - FOR(m, e) - FOR(n, f) - FOR(o, g) - YIELD(i, j, k, l, m, n, g) - } - -#undef FOR -#undef YIELD - - template - struct Range { - using Type = typename T::RangeType; - - struct Sentinel { - Type val; - }; - - struct Iterator { - using value_type = T; - using difference_type = isize; - - constexpr Iterator(Type val, Type step) noexcept : m_val { val }, m_step { step } {} - - constexpr Iterator(const Iterator&) noexcept = default; - constexpr Iterator(Iterator&&) noexcept = default; - constexpr ~Iterator() noexcept = default; - - constexpr auto operator=(const Iterator&) noexcept -> Iterator& = default; - constexpr auto operator=(Iterator&&) noexcept -> Iterator& = default; - - constexpr auto operator=(const Sentinel& end) noexcept -> Iterator& { - m_val = end.val; - - return *this; - } - - constexpr auto operator+(std::size_t index) noexcept -> decltype(auto) { - auto cpy = clone(*this); - for (auto i = 0u; i < index; ++i) ++cpy; - return cpy; - } - - constexpr auto operator++() noexcept -> decltype(auto) { - m_val += m_step; - return *this; - } - - constexpr auto operator++(int) noexcept -> decltype(auto) { - auto old = clone(*this); - m_val += m_step; - return old; - } - - constexpr auto operator--() noexcept -> decltype(auto) { - m_val -= m_step; - return *this; - } - - constexpr auto operator--(int) noexcept -> decltype(auto) { - auto old = clone(*this); - m_val -= m_step; - return old; - } - - constexpr auto operator==(const Iterator& other) const noexcept { - return m_val == other.m_val; - } - - constexpr auto operator==(const Sentinel& end) const noexcept -> bool { - if (m_step > 0) return m_val >= end.val; - - return m_val <= end.val; - } - - constexpr auto operator!=(const Iterator& other) const noexcept { - return m_val != other.m_val; - } - - constexpr auto operator*() const noexcept -> const Type& { return m_val; } - - private: - Type m_val; - Type m_step; - }; - - constexpr explicit Range(meta::IsStrict auto&& range) - : m_range { std::forward(range) } {} - - constexpr auto begin() const noexcept -> Iterator { - return { m_range.begin, m_range.step }; - } - - constexpr auto cbegin() const noexcept -> Iterator { return begin(); } - - constexpr auto end() const noexcept -> Sentinel { return { m_range.end }; } - - constexpr auto cend() const noexcept -> Sentinel { return end(); } - - private: - T m_range; - }; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - constexpr auto range(meta::IsNumericsRangePure auto&& range) noexcept -> decltype(auto) { - return Range> { std::forward(range) }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr auto range(const T& begin, const U& end, const V& step) noexcept -> decltype(auto) { - using Type = meta::SafeNarrowHelperType, V>; - return range(NumericsRange { .begin = as(begin), - .end = as(end), - .step = as(step) }); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr auto range(const T& begin, const U& end) noexcept -> decltype(auto) { - return stdv::iota(begin, end); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr auto range(const T& end) noexcept -> decltype(auto) { - return range(T { 0 }, end); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr auto multi_range(const Args&... args) noexcept -> decltype(auto) { - return range_implementation(NumericsRange { .begin = 0, .end = args }...); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - constexpr auto multi_range(Args&&... args) noexcept -> decltype(auto) { - return range_implementation(std::forward(args)...); - } -}} // namespace stormkit::core +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +export module stormkit.core:utils.numeric_range; + +import std; + +import :meta; + +import :typesafe; + +import :coroutines; + +export namespace stormkit { inline namespace core { + template + struct NumericsRange { + using RangeType = T; + T begin; + T end; + T step = T { 1 }; + }; + + namespace meta { + template + concept IsNumericsRange = requires(const T& t) { + t.begin; + t.end; + t.step; + typename T::RangeType; + }; + + template + concept IsNumericsRangePure = IsNumericsRange>; + } // namespace meta + + template + [[nodiscard]] + constexpr auto range(const T& end) noexcept -> decltype(auto); + + template + [[nodiscard]] + constexpr auto range(const T& begin, const U& end) noexcept -> decltype(auto); + + template + [[nodiscard]] + constexpr auto range(const T& begin, const U& end, const V& step) noexcept -> decltype(auto); + + [[nodiscard]] + constexpr auto range(meta::IsNumericsRangePure auto&& range) noexcept -> decltype(auto); + + template + [[nodiscard]] + constexpr auto multi_range(const Args&... args) noexcept -> decltype(auto); + + template + [[nodiscard]] + constexpr auto multi_range(Args&&... args) noexcept -> decltype(auto); +}} // namespace stormkit::core + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stdr = std::ranges; +namespace stdv = std::views; + +namespace stormkit { inline namespace core { +#define FOR(a, b) for (auto a = b.begin; a < b.end; a += b.step) +#define YIELD(...) co_yield { __VA_ARGS__ }; + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto range_implementation(T a, U b) noexcept -> std::generator> { + FOR(i, a) + FOR(j, b) + YIELD(i, j) + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto range_implementation(T a, U b, V c) noexcept + -> std::generator> { + FOR(i, a) + FOR(j, b) + FOR(k, c) + YIELD(i, j, k) + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto range_implementation(T a, U b, V c, W d) noexcept + -> std::generator> { + FOR(i, a) + FOR(j, b) + FOR(k, c) + FOR(l, d) + YIELD(i, j, k, l) + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto range_implementation(T a, U b, V c, W d, X e) noexcept -> std::generator< + std::tuple> { + FOR(i, a) + FOR(j, b) + FOR(k, c) + FOR(l, d) + FOR(m, e) + YIELD(i, j, k, l, m) + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto range_implementation(T a, U b, V c, W d, X e, Y f) noexcept -> std::generator< + std:: + tuple> { + FOR(i, a) + FOR(j, b) + FOR(k, c) + FOR(l, d) + FOR(m, e) + FOR(n, f) + YIELD(i, j, k, l, m, n) + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto range_implementation(T a, U b, V c, W d, X e, Y f, Z g) noexcept + -> std::generator> { + FOR(i, a) + FOR(j, b) + FOR(k, c) + FOR(l, d) + FOR(m, e) + FOR(n, f) + FOR(o, g) + YIELD(i, j, k, l, m, n, g) + } + +#undef FOR +#undef YIELD + + template + struct Range { + using Type = typename T::RangeType; + + struct Sentinel { + Type val; + }; + + struct Iterator { + using value_type = T; + using difference_type = isize; + + constexpr Iterator(Type val, Type step) noexcept : m_val { val }, m_step { step } {} + + constexpr Iterator(const Iterator&) noexcept = default; + constexpr Iterator(Iterator&&) noexcept = default; + constexpr ~Iterator() noexcept = default; + + constexpr auto operator=(const Iterator&) noexcept -> Iterator& = default; + constexpr auto operator=(Iterator&&) noexcept -> Iterator& = default; + + constexpr auto operator=(const Sentinel& end) noexcept -> Iterator& { + m_val = end.val; + + return *this; + } + + constexpr auto operator+(std::size_t index) noexcept -> decltype(auto) { + auto cpy = clone(*this); + for (auto i = 0u; i < index; ++i) ++cpy; + return cpy; + } + + constexpr auto operator++() noexcept -> decltype(auto) { + m_val += m_step; + return *this; + } + + constexpr auto operator++(int) noexcept -> decltype(auto) { + auto old = clone(*this); + m_val += m_step; + return old; + } + + constexpr auto operator--() noexcept -> decltype(auto) { + m_val -= m_step; + return *this; + } + + constexpr auto operator--(int) noexcept -> decltype(auto) { + auto old = clone(*this); + m_val -= m_step; + return old; + } + + constexpr auto operator==(const Iterator& other) const noexcept { return m_val == other.m_val; } + + constexpr auto operator==(const Sentinel& end) const noexcept -> bool { + if (m_step > 0) return m_val >= end.val; + + return m_val <= end.val; + } + + constexpr auto operator!=(const Iterator& other) const noexcept { return m_val != other.m_val; } + + constexpr auto operator*() const noexcept -> const Type& { return m_val; } + + private: + Type m_val; + Type m_step; + }; + + constexpr explicit Range(meta::SameAs auto&& range) : m_range { std::forward(range) } {} + + constexpr auto begin() const noexcept -> Iterator { return { m_range.begin, m_range.step }; } + + constexpr auto cbegin() const noexcept -> Iterator { return begin(); } + + constexpr auto end() const noexcept -> Sentinel { return { m_range.end }; } + + constexpr auto cend() const noexcept -> Sentinel { return end(); } + + private: + T m_range; + }; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto range(meta::IsNumericsRangePure auto&& range) noexcept -> decltype(auto) { + return Range> { std::forward(range) }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto range(const T& begin, const U& end, const V& step) noexcept -> decltype(auto) { + using Type = meta::SafeNarrowHelperType, V>; + return range(NumericsRange { .begin = as(begin), .end = as(end), .step = as(step) }); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto range(const T& begin, const U& end) noexcept -> decltype(auto) { + return stdv::iota(begin, end); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto range(const T& end) noexcept -> decltype(auto) { + return range(T { 0 }, end); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto multi_range(const Args&... args) noexcept -> decltype(auto) { + return range_implementation(NumericsRange { .begin = 0, .end = args }...); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto multi_range(Args&&... args) noexcept -> decltype(auto) { + return range_implementation(std::forward(args)...); + } +}} // namespace stormkit::core diff --git a/modules/stormkit/core/utils/pimpl.mpp b/modules/stormkit/core/utils/pimpl.cppm similarity index 82% rename from modules/stormkit/core/utils/pimpl.mpp rename to modules/stormkit/core/utils/pimpl.cppm index b13abce03..6305c7c9a 100644 --- a/modules/stormkit/core/utils/pimpl.mpp +++ b/modules/stormkit/core/utils/pimpl.cppm @@ -1,166 +1,164 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -#include - -export module stormkit.core:utils.pimpl; - -import std; - -import :meta; -import :utils.contract; - -export namespace stormkit { inline namespace core { - template - class Pimpl { - public: - Pimpl() noexcept(not Defer); - ~Pimpl(); - -#if defined(STORMKIT_COMPILER_CLANG) and __clang_major__ < 21 - template - requires(meta::EnableCtor, Args...>) - Pimpl(Args&&... args); -#else - template - requires(meta::EnableCtor, Args...>) - explicit(sizeof...(Args) == 1) Pimpl(Args&&... args); -#endif - - Pimpl(Pimpl&&) noexcept; - auto operator=(Pimpl&&) noexcept -> Pimpl&; - - template - auto init(Args&&... args) -> void; - - auto operator->() noexcept -> T*; - auto operator->() const noexcept -> const T*; - - auto operator*() noexcept -> T&; - auto operator*() const noexcept -> const T&; - - auto get() noexcept -> T&; - auto get() const noexcept -> const T&; - - explicit operator bool() const noexcept; - - private: - std::unique_ptr m_data; - }; -}} // namespace stormkit::core - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit { inline namespace core { - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - Pimpl::Pimpl() noexcept(not Defer) { - if constexpr (not Defer) init(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - Pimpl::~Pimpl() - = default; - - ///////////////////////////////////// - ///////////////////////////////////// - template - template - requires(meta::EnableCtor, Args...>) - STORMKIT_FORCE_INLINE - Pimpl::Pimpl(Args&&... args) { - init(std::forward(args)...); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - Pimpl::Pimpl(Pimpl&&) noexcept - = default; - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - auto Pimpl::operator=(Pimpl&&) noexcept -> Pimpl& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - template - template - STORMKIT_FORCE_INLINE - auto Pimpl::init(Args&&... args) -> void { - m_data = std::make_unique(std::forward(args)...); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - auto Pimpl::operator->() noexcept -> T* { - return &get(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - auto Pimpl::operator->() const noexcept -> const T* { - return &get(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - auto Pimpl::operator*() noexcept -> T& { - return get(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - auto Pimpl::operator*() const noexcept -> const T& { - return get(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - auto Pimpl::get() noexcept -> T& { - EXPECTS(m_data != nullptr); - return *m_data; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - auto Pimpl::get() const noexcept -> const T& { - EXPECTS(m_data != nullptr); - return *m_data; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - Pimpl::operator bool() const noexcept { - return m_data != nullptr; - } -}} // namespace stormkit::core +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +#include + +export module stormkit.core:utils.pimpl; + +import std; + +import :meta; +import :utils.contract; + +export namespace stormkit { inline namespace core { + template + class Pimpl { + public: + Pimpl() noexcept(not Defer); + ~Pimpl(); + +#if defined(STORMKIT_COMPILER_CLANG) and __clang_major__ < 21 + template + requires(meta::EnableCtor, Args...>) + Pimpl(Args&&... args); +#else + template + requires(meta::EnableCtor, Args...>) + explicit(sizeof...(Args) == 1) Pimpl(Args&&... args); +#endif + + Pimpl(Pimpl&&) noexcept; + auto operator=(Pimpl&&) noexcept -> Pimpl&; + + template + auto init(Args&&... args) -> void; + + auto operator->() noexcept -> T*; + auto operator->() const noexcept -> const T*; + + auto operator*() noexcept -> T&; + auto operator*() const noexcept -> const T&; + + auto get() noexcept -> T&; + auto get() const noexcept -> const T&; + + explicit operator bool() const noexcept; + + private: + std::unique_ptr m_data; + }; +}} // namespace stormkit::core + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit { inline namespace core { + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline Pimpl::Pimpl() noexcept(not Defer) { + if constexpr (not Defer) init(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline Pimpl::~Pimpl() = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + template + requires(meta::EnableCtor, Args...>) + STORMKIT_FORCE_INLINE + inline Pimpl::Pimpl(Args&&... args) { + init(std::forward(args)...); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline Pimpl::Pimpl(Pimpl&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Pimpl::operator=(Pimpl&&) noexcept -> Pimpl& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + template + STORMKIT_FORCE_INLINE + inline auto Pimpl::init(Args&&... args) -> void { + m_data = std::make_unique(std::forward(args)...); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Pimpl::operator->() noexcept -> T* { + return &get(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Pimpl::operator->() const noexcept -> const T* { + return &get(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Pimpl::operator*() noexcept -> T& { + return get(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Pimpl::operator*() const noexcept -> const T& { + return get(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Pimpl::get() noexcept -> T& { + EXPECTS(m_data != nullptr); + return *m_data; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Pimpl::get() const noexcept -> const T& { + EXPECTS(m_data != nullptr); + return *m_data; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline Pimpl::operator bool() const noexcept { + return m_data != nullptr; + } +}} // namespace stormkit::core diff --git a/modules/stormkit/core/utils/random.mpp b/modules/stormkit/core/utils/random.cppm similarity index 83% rename from modules/stormkit/core/utils/random.mpp rename to modules/stormkit/core/utils/random.cppm index 367949115..8e2bba117 100644 --- a/modules/stormkit/core/utils/random.mpp +++ b/modules/stormkit/core/utils/random.cppm @@ -1,69 +1,66 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -export module stormkit.core:utils.random; - -import std; - -import :typesafe; - -import :meta; - -export namespace stormkit { inline namespace core { - auto seed(u32 seed) noexcept -> void; - - template - [[nodiscard]] - auto rand(T min, T max) noexcept -> T; - - template - [[nodiscard]] - auto rand(T min, T max) noexcept -> T; -}} // namespace stormkit::core - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit { inline namespace core { - namespace { - std::default_random_engine generator {}; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - auto random_generator() noexcept -> std::default_random_engine& { - return generator; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - auto seed(u32 seed) noexcept -> void { - random_generator().seed(seed); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - auto rand(T min, T max) noexcept -> T { - std::uniform_real_distribution dis(min, max); - return dis(random_generator()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - auto rand(T min, T max) noexcept -> T { - std::uniform_int_distribution dis(min, max); - return dis(random_generator()); - } -}} // namespace stormkit::core +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +export module stormkit.core:utils.random; + +import std; + +import :typesafe; + +import :meta; + +export namespace stormkit { inline namespace core { + auto seed(u32 seed) noexcept -> void; + + template + [[nodiscard]] + auto rand(T min, T max) noexcept -> T; + + template + [[nodiscard]] + auto rand(T min, T max) noexcept -> T; +}} // namespace stormkit::core + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit { inline namespace core { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto random_generator() noexcept -> std::default_random_engine& { + static auto generator = std::default_random_engine {}; + return generator; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto seed(u32 seed) noexcept -> void { + random_generator().seed(seed); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto rand(T min, T max) noexcept -> T { + std::uniform_real_distribution dis(min, max); + return dis(random_generator()); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto rand(T min, T max) noexcept -> T { + std::uniform_int_distribution dis(min, max); + return dis(random_generator()); + } +}} // namespace stormkit::core diff --git a/modules/stormkit/core/utils/signal_handler.cppm b/modules/stormkit/core/utils/signal_handler.cppm new file mode 100644 index 000000000..46701b71c --- /dev/null +++ b/modules/stormkit/core/utils/signal_handler.cppm @@ -0,0 +1,10 @@ +module; + +#include + +export module stormkit.core:utils.signal_handler; + +export namespace stormkit { inline namespace core { + STORMKIT_CORE_API + auto setup_signal_handler() noexcept -> void; +}} // namespace stormkit::core diff --git a/modules/stormkit/core/utils/singleton.mpp b/modules/stormkit/core/utils/singleton.cppm similarity index 90% rename from modules/stormkit/core/utils/singleton.mpp rename to modules/stormkit/core/utils/singleton.cppm index 9bf1307cc..387b3e8a0 100644 --- a/modules/stormkit/core/utils/singleton.mpp +++ b/modules/stormkit/core/utils/singleton.cppm @@ -1,59 +1,57 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -export module stormkit.core:utils.singleton; - -import std; - -export namespace stormkit { inline namespace core { - template - class Singleton { - public: - template - static auto instance(Args&&... args) noexcept(std::is_nothrow_constructible_v) -> T&; - - Singleton(Singleton&&) = delete; - Singleton(const Singleton&) = delete; - - auto operator=(Singleton&&) -> Singleton& = delete; - auto operator=(const Singleton&) -> Singleton& = delete; - - protected: - Singleton() noexcept = default; - ~Singleton() noexcept = default; - - private: - static auto once_flag() noexcept -> std::once_flag&; - - static inline std::unique_ptr m_instance = nullptr; - }; -}} // namespace stormkit::core - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit { inline namespace core { - ///////////////////////////////////// - ///////////////////////////////////// - template - template - auto Singleton::instance(Args&&... args) noexcept(std::is_nothrow_constructible_v) -> T& { - auto lambdas = [](Args&&... args) mutable { - m_instance = std::make_unique(std::forward(args)...); - }; - - std::call_once(once_flag(), lambdas, std::forward(args)...); - - return *m_instance; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - auto Singleton::once_flag() noexcept -> std::once_flag& { - static auto once_flag = std::once_flag {}; - return once_flag; - } -}} // namespace stormkit::core +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +export module stormkit.core:utils.singleton; + +import std; + +export namespace stormkit { inline namespace core { + template + class Singleton { + public: + template + static auto instance(Args&&... args) noexcept(std::is_nothrow_constructible_v) -> T&; + + Singleton(Singleton&&) = delete; + Singleton(const Singleton&) = delete; + + auto operator=(Singleton&&) -> Singleton& = delete; + auto operator=(const Singleton&) -> Singleton& = delete; + + protected: + Singleton() noexcept = default; + ~Singleton() noexcept = default; + + private: + static auto once_flag() noexcept -> std::once_flag&; + + static inline std::unique_ptr m_instance = nullptr; + }; +}} // namespace stormkit::core + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit { inline namespace core { + ///////////////////////////////////// + ///////////////////////////////////// + template + template + auto Singleton::instance(Args&&... args) noexcept(std::is_nothrow_constructible_v) -> T& { + auto lambdas = [](Args&&... args) mutable { m_instance = std::make_unique(std::forward(args)...); }; + + std::call_once(once_flag(), lambdas, std::forward(args)...); + + return *m_instance; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto Singleton::once_flag() noexcept -> std::once_flag& { + static auto once_flag = std::once_flag {}; + return once_flag; + } +}} // namespace stormkit::core diff --git a/modules/stormkit/core/utils/stacktrace.mpp b/modules/stormkit/core/utils/stacktrace.cppm similarity index 65% rename from modules/stormkit/core/utils/stacktrace.mpp rename to modules/stormkit/core/utils/stacktrace.cppm index 04568b5df..014631f59 100644 --- a/modules/stormkit/core/utils/stacktrace.mpp +++ b/modules/stormkit/core/utils/stacktrace.cppm @@ -1,5 +1,6 @@ module; +#include #include export module stormkit.core:utils.stracktrace; @@ -9,5 +10,6 @@ import std; import :parallelism.threadutils; export namespace stormkit { inline namespace core { - STORMKIT_API auto print_stacktrace(int ignore_count = 0) noexcept -> void; + STORMKIT_CORE_API + auto print_stacktrace(int ignore_count = 0) noexcept -> void; }} // namespace stormkit::core diff --git a/modules/stormkit/core/utils/tags.mpp b/modules/stormkit/core/utils/tags.cppm similarity index 100% rename from modules/stormkit/core/utils/tags.mpp rename to modules/stormkit/core/utils/tags.cppm diff --git a/modules/stormkit/core/utils/time.mpp b/modules/stormkit/core/utils/time.cppm similarity index 73% rename from modules/stormkit/core/utils/time.mpp rename to modules/stormkit/core/utils/time.cppm index 6b75d54f5..ef1b07fda 100644 --- a/modules/stormkit/core/utils/time.mpp +++ b/modules/stormkit/core/utils/time.cppm @@ -6,6 +6,8 @@ export module stormkit.core:utils.time; import std; +import :typesafe.floating_point; + export namespace stormkit { inline namespace core { - using Secondf = std::chrono::duration; + using fsecond = std::chrono::duration; }} // namespace stormkit::core diff --git a/modules/stormkit/entities.cppm b/modules/stormkit/entities.cppm new file mode 100644 index 000000000..9a0bb38eb --- /dev/null +++ b/modules/stormkit/entities.cppm @@ -0,0 +1,580 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include +#include + +#include + +#include + +#include +#ifdef STORMKIT_LIB_LUA_ENABLED + #include +#endif + +export module stormkit.entities; + +import std; + +import stormkit.core; + +namespace stdr = std::ranges; +namespace stdv = std::views; + +namespace cmeta = stormkit::core::meta; + +export namespace stormkit::entities { + using ComponentType = u32; + +#ifdef STORMKIT_LIB_LUA_ENABLED + namespace lua { + struct LuaComponent { + sol::table data; + ComponentType _type; + + STORMKIT_FORCE_INLINE + inline auto type() const noexcept -> ComponentType { + return _type; + } + }; + } // namespace lua +#endif + + using Entity = u32; + using Entities = dyn_array; + + inline constexpr auto INVALID_ENTITY = Entity { 0 }; + class System; + + struct EntityHashFunc { +#ifdef STORMKIT_COMPILER_MSVC + [[nodiscard]] + auto operator()(Entity k) const noexcept -> hash64; +#else + [[nodiscard]] + static auto operator()(Entity k) noexcept -> hash64; +#endif + }; + + namespace meta { + template + concept IsComponentType = requires(T&& component) { + { component.type() } -> cmeta::Is; + }; + + template + concept ComponentWithStaticType = IsComponentType and requires(T) { + { T::type() } -> cmeta::SameAs; + }; + + } // namespace meta + + struct Message { + u32 id; + Entities entities; + }; + + class STORMKIT_ENTITIES_API MessageBus { + public: + MessageBus(); + ~MessageBus(); + + MessageBus(const MessageBus&) = delete; + auto operator=(const MessageBus&) -> MessageBus& = delete; + + MessageBus(MessageBus&&); + auto operator=(MessageBus&&) -> MessageBus&; + + auto push(Message&& message) -> void; + [[nodiscard]] + auto top() const -> const Message&; + auto pop() -> void; + + [[nodiscard]] + auto empty() const noexcept -> bool; + + private: + std::queue m_messages; + }; + + class EntityManager; + + class STORMKIT_ENTITIES_API System { + public: + using ComponentTypes = dyn_array; + + using PreUpdateClosure = std::function; + using UpdateClosure = std::function; + using PostUpdateClosure = std::function; + using OnMessageReceived = std::function; + + struct Closures { + PreUpdateClosure pre_update = monadic::noop(); + UpdateClosure update; + PostUpdateClosure post_update = monadic::noop(); + OnMessageReceived on_message_received = monadic::noop(); + }; + + System(string name, ComponentTypes types, Closures&& closures) noexcept; + + System(const System&) = delete; + auto operator=(const System&) -> System& = delete; + + System(System&&) noexcept; + auto operator=(System&&) noexcept -> System&; + + ~System() noexcept; + + [[nodiscard]] + auto name() const noexcept -> const string&; + [[nodiscard]] + auto components_used() const noexcept -> const ComponentTypes&; + + private: + auto add_entity(Entity e) noexcept -> void; + auto remove_entity(Entity e) noexcept -> void; + + auto pre_update(EntityManager&) noexcept -> void; + auto update(EntityManager&, fsecond) noexcept -> void; + auto post_update(EntityManager&) noexcept -> void; + + auto on_message_received(EntityManager&, const Message&) noexcept -> void; + + string m_name; + + ComponentTypes m_types; + + Closures m_closures; + + Entities m_entities; + + friend class EntityManager; + }; + + namespace meta { + template + concept IsUsableAsSystem = requires(T& value) { + value.update(std::declval(), std::declval(), std::declval()); + }; + } // namespace meta + + struct ComponentStore {}; + + class STORMKIT_ENTITIES_API EntityManager { + public: + using DeleteFunc = std::function; + static constexpr auto ADDED_ENTITY_MESSAGE_ID = 1; + static constexpr auto REMOVED_ENTITY_MESSAGE_ID = 2; + + EntityManager() noexcept; + ~EntityManager() noexcept; + + EntityManager(const EntityManager&) = delete; + auto operator=(const EntityManager&) -> EntityManager& = delete; + + EntityManager(EntityManager&&) noexcept; + auto operator=(EntityManager&&) noexcept -> EntityManager&; + + auto make_entity() noexcept -> Entity; + auto destroy_entity(Entity entity) noexcept -> void; + auto destroy_all_entities() noexcept -> void; + auto has_entity(Entity entity) const noexcept -> bool; + + template + auto add_component(Entity entity, T&& component) noexcept -> cmeta::ToPlainType&; + + auto destroy_component(Entity entity, string_view name) noexcept -> void; + auto destroy_component(Entity entity, ComponentType type) noexcept -> void; + + template + auto has_component(Entity entity) const noexcept -> bool; + auto has_component(Entity entity, string_view name) const noexcept -> bool; + auto has_component(Entity entity, ComponentType type) const noexcept -> bool; + + auto entities() const noexcept -> const Entities&; + + auto entities_with_component(ComponentType type) const noexcept -> Entities; + auto entities_with_component(string_view name) const noexcept -> Entities; + + template + auto get_component(this Self& self, Entity entity) noexcept -> cmeta::ForwardConst&; + template + auto get_component(this Self& self, Entity entity, ComponentType) noexcept -> cmeta::ForwardConst&; + template + auto get_component(this Self& self, Entity entity, string_view) noexcept -> cmeta::ForwardConst&; + + template + auto components_of_type(this Self& self) noexcept -> dyn_array>>; + template + auto components_of_type(this Self& self, ComponentType type) noexcept -> dyn_array>>; + template + auto components_of_type(this Self& self, string_view name) noexcept -> dyn_array>>; + + auto components_types_of(Entity entity) const noexcept -> dyn_array; + + template + auto add_system(string name, System::ComponentTypes types, T& system) noexcept -> System&; + auto add_system(string name, System::ComponentTypes types, System::Closures&& closures) noexcept -> System&; + auto has_system(string_view name) const noexcept -> bool; + auto remove_system(string_view name) noexcept -> void; + + template + auto systems(this Self& self) noexcept -> dyn_array>>; + + template + auto get_system(this Self& self, string_view name) noexcept -> cmeta::ForwardConst; + + auto flush() noexcept -> void; + auto step(fsecond delta) noexcept -> void; + + auto entity_count() const noexcept -> usize; + + auto add_raw_component(Entity entity, ComponentType type, byte_view<> component, DeleteFunc delete_func) noexcept + -> byte_mut_view<>; + + template + auto get_raw_component(this Self& self, Entity entity, ComponentType type) noexcept + -> array_view>; + + private: + using ComponentKey = u64; + + struct Store { + ComponentType type; + usize size; + Entities entities; + byte_dyn_array data; + DeleteFunc delete_func; + }; + + using ComponentStore = dyn_array; + + auto purpose_to_systems(Entity e) noexcept -> void; + auto remove_from_systems(Entity e) noexcept -> void; + auto get_needed_entities(System& system) noexcept -> void; + + Entity m_next_valid_entity = 1; + + Entities m_entities; + + Entities m_free_entities; + + hash_set m_added_entities; + hash_set m_updated_entities; + hash_set m_removed_entities; + + dyn_array m_systems; + + ComponentStore m_components; + + MessageBus m_message_bus; + }; +} // namespace stormkit::entities + +namespace stormkit::entities { + ///////////////////////////////////// + ///////////////////////////////////// +#ifdef STORMKIT_COMPILER_MSVC + inline auto EntityHashFunc::operator()(Entity k) const noexcept -> hash64 { +#else + inline auto EntityHashFunc::operator()(Entity k) noexcept -> hash64 { +#endif + return as(k); + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto MessageBus::empty() const noexcept -> bool { + return std::empty(m_messages); + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto System::name() const noexcept -> const string& { + return m_name; + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto System::components_used() const noexcept -> const ComponentTypes& { + return m_types; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto EntityManager::add_component(Entity entity, T&& component) noexcept -> cmeta::ToPlainType& { + using PureT = cmeta::ToPlainType; + + auto _component = add_raw_component(entity, + component.type(), + as_bytes(std::forward(component)), + [](auto ptr) static noexcept { std::launder(std::bit_cast(ptr))->~PureT(); }); + + return bytes_mut_as(_component); + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto EntityManager::destroy_component(Entity entity, string_view name) noexcept -> void { + destroy_component(entity, hash(name)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + inline auto EntityManager::has_component(Entity entity) const noexcept -> bool { + return has_component(entity, T::type()); + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto EntityManager::has_component(Entity entity, string_view name) const noexcept -> bool { + return has_component(entity, hash(name)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto EntityManager::entities() const noexcept -> const Entities& { + return m_entities; + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto EntityManager::entities_with_component(ComponentType type) const noexcept -> Entities { + // clang-format off + return entities() + | stdv::filter([this, type](auto entity) noexcept { return has_component(entity, type); }) + | stdr::to(); + // clang-format on + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto EntityManager::entities_with_component(string_view name) const noexcept -> Entities { + return entities_with_component(hash(name)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto EntityManager::get_component(this Self& self, Entity entity) noexcept -> cmeta::ForwardConst& { + return self.template get_component(entity, T::type()); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto EntityManager::get_component(this Self& self, Entity entity, ComponentType type) noexcept + -> cmeta::ForwardConst& { + if constexpr (cmeta::IsConst) return bytes_as(self.get_raw_component(entity, type)); + else + return bytes_mut_as(self.get_raw_component(entity, type)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto EntityManager::get_component(this Self& self, Entity entity, string_view name) noexcept + -> cmeta::ForwardConst& { + return self.template get_component(entity, hash(name)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto EntityManager::components_of_type(this Self& self) noexcept -> dyn_array>> { + return self.template components_of_type(T::type()); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto EntityManager::components_of_type(this Self& self, ComponentType type) noexcept + -> dyn_array>> { + // clang-format off + return self.m_entities + | stdv::filter([&self, type](auto entity) noexcept { return self.has_component(entity, type); }) + | stdv::transform([&self, type](auto entity) noexcept { return self.template get_component(entity, type); }) + // | stdv::transform(monadic::forward_like()) + | stdv::transform(monadic::as_ref()) + | stdr::to(); + // clang-format on + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto EntityManager::components_of_type(this Self& self, string_view name) noexcept + -> dyn_array>> { + return self.template components_of_type(hash(name)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto EntityManager::components_types_of(Entity entity) const noexcept -> dyn_array { + EXPECTS(has_entity(entity)); + + auto out = dyn_array {}; + for (auto&& [type, _, entities, _, _] : m_components) { + for (auto e : entities) + if (e == entity) { + out.emplace_back(type); + break; + } + } + return out; + } + + namespace meta { + template + concept HasPreUpdate = requires(T& value) { value.pre_update(std::declval()); }; + + template + concept HasPostUpdate = requires(T& value) { value.post_update(std::declval()); }; + + template + concept HasOnMessageReceived = requires(T& value) { + value.on_message_received(std::declval(), + std::declval(), + std::declval()); + }; + } // namespace meta + + ///////////////////////////////////// + ///////////////////////////////////// + template + inline auto EntityManager::add_system(string name, System::ComponentTypes types, T& system) noexcept -> System& { + auto closures = System::Closures { + .update = bind_front(&T::update, &system), + }; + + if constexpr (meta::HasPreUpdate) closures.pre_update = bind_front(&T::pre_update, &system); + if constexpr (meta::HasPostUpdate) closures.post_update = bind_front(&T::post_update, &system); + if constexpr (meta::HasOnMessageReceived) closures.on_message_received = bind_front(&T::on_message_received, &system); + + return add_system(std::move(name), std::move(types), std::move(closures)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto EntityManager::add_system(string name, System::ComponentTypes types, System::Closures&& closures) noexcept + -> System& { + auto& system = m_systems.emplace_back(std::move(name), std::move(types), std::move(closures)); + + get_needed_entities(system); + + return system; + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto EntityManager::has_system(string_view name) const noexcept -> bool { + return stdr::any_of(m_systems, [name](const auto& system) noexcept { return system.name() == name; }); + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto EntityManager::remove_system(string_view name) noexcept -> void { + auto&& [begin, end] = stdr::remove_if(m_systems, [&name](const auto& system) { return name == system.name(); }); + m_systems.erase(begin, end); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto EntityManager::systems(this Self& self) noexcept -> dyn_array>> { + constexpr auto as_refer = [] { + if constexpr (cmeta::IsConst) return monadic::as_ref(); + else + return monadic::as_ref_mut(); + }(); + + return self.m_systems | stdv::transform(as_refer) | stdr::to>>>(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto EntityManager::get_system(this Self& self, string_view name) noexcept -> cmeta::ForwardConst { + EXPECTS(self.has_system(name)); + + const auto it = stdr::find_if(self.m_systems, [name](const auto& system) noexcept { return system.name() == name; }); + return std::forward_like(*it->get()); + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto EntityManager::entity_count() const noexcept -> usize { + return std::size(m_entities); + } + + ///////////////////////////////////// + ///////////////////////////////////// + auto EntityManager::add_raw_component(Entity entity, + ComponentType type, + byte_view<> component, + DeleteFunc delete_func) noexcept -> byte_mut_view<> { + EXPECTS(has_entity(entity)); + EXPECTS(not has_component(entity, type)); + + const auto _size = stdr::size(component); + + auto it = stdr::find_if(m_components, [type = type](const auto& pair) noexcept { return pair.type == type; }); + if (it == stdr::cend(m_components)) + it = m_components.emplace(stdr::cend(m_components), + Store { type, stdr::size(component), {}, {}, std::move(delete_func) }); + + ENSURES(it != stdr::cend(m_components)); + + auto& [_, size, entities, components, _] = *it; + ENSURES(size == _size); + + const auto old_size = stdr::size(components); + components.resize(old_size + sizeof(Entity) + size); + + new (stdr::data(components) + old_size) Entity { entity }; + auto _component = array_view { stdr::data(components) + old_size + sizeof(Entity), _size }; + stdr::copy(component, stdr::begin(_component)); + + entities.emplace_back(entity); + + m_updated_entities.emplace(entity); + + return _component; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto EntityManager::get_raw_component(this Self& self, Entity entity, ComponentType type) noexcept + -> array_view> { + EXPECTS(self.has_entity(entity)); + EXPECTS(self.has_component(entity, type)); + + auto it = stdr::find_if(self.m_components, [&type](const auto& pair) noexcept { return pair.type == type; }); + ENSURES(it != stdr::cend(self.m_components)); + + auto& [_, size, _, components, _] = *it; + + auto component_it = stdr::data(components); + for (;;) { + auto e = *std::launder(std::bit_cast(component_it)); + if (e != entity) { + component_it += sizeof(Entity) + size; + continue; + } + + component_it += sizeof(Entity); + + break; + } + + return { component_it, size }; + } +} // namespace stormkit::entities diff --git a/modules/stormkit/entities.mpp b/modules/stormkit/entities.mpp deleted file mode 100644 index 1a06e70f1..000000000 --- a/modules/stormkit/entities.mpp +++ /dev/null @@ -1,474 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -#include - -#include - -export module stormkit.entities; - -import std; - -import stormkit.core; - -namespace stdr = std::ranges; -namespace stdv = std::views; - -export namespace stormkit::entities { - using Entity = u32; - inline constexpr auto INVALID_ENTITY = Entity { 0 }; - class System; - - struct EntityHashFunc { -#ifdef STORMKIT_COMPILER_MSVC - [[nodiscard]] - auto operator()(Entity k) const noexcept -> hash64; -#else - [[nodiscard]] - static auto operator()(Entity k) noexcept -> hash64; -#endif - }; - - struct Component { - using Type = u64; - - static constexpr Type INVALID_TYPE = 0; - static constexpr Type TYPE = INVALID_TYPE; - }; - - namespace meta { - template - concept IsComponentType = core::meta::Is and requires(T&& component) { - T::TYPE; - }; - - template - concept IsSystem = core::meta::Is; - } // namespace meta - - template - constexpr auto component_hash(std::string_view str) noexcept -> Result; - - constexpr auto component_hash(CZString str, usize size) noexcept -> Component::Type; - - constexpr auto component_hash(std::string_view str) noexcept -> Component::Type; - - namespace literals { - constexpr auto operator""_component_type(CZString str, usize size) -> Component::Type; - } // namespace literals - - struct Message { - u32 id; - std::vector entities; - }; - - class STORMKIT_API MessageBus { - public: - MessageBus(); - ~MessageBus(); - - MessageBus(const MessageBus&) = delete; - auto operator=(const MessageBus&) -> MessageBus& = delete; - - MessageBus(MessageBus&&); - auto operator=(MessageBus&&) -> MessageBus&; - - auto push(Message&& message) -> void; - [[nodiscard]] - auto top() const -> const Message&; - auto pop() -> void; - - [[nodiscard]] - auto empty() const noexcept -> bool; - - private: - std::queue m_messages; - }; - - class EntityManager; - - class STORMKIT_API System { - public: - using ComponentTypes = HashSet; - - System(EntityManager& manager, u32 priority, ComponentTypes types); - - System(const System&) = delete; - auto operator=(const System&) -> System& = delete; - - System(System&&) noexcept; - auto operator=(System&&) noexcept -> System&; - - virtual ~System(); - - virtual auto pre_update() -> void; - virtual auto update(Secondf delta) -> void = 0; - virtual auto post_update() -> void; - - [[nodiscard]] - auto priority() const noexcept -> u32; - [[nodiscard]] - auto components_used() const noexcept -> const ComponentTypes&; - - auto add_entity(Entity e) -> void; - auto remove_entity(Entity e) -> void; - - struct Predicate { -#ifdef STORMKIT_COMPILER_MSVC - [[nodiscard]] - auto operator()(const std::unique_ptr& s1, - const std::unique_ptr& s2) const noexcept -#else - [[nodiscard]] - static auto operator()(const std::unique_ptr& s1, - const std::unique_ptr& s2) noexcept -#endif - -> bool { - return s1->priority() < s2->priority(); - } - }; - - protected: - virtual auto on_message_received(const Message& message) -> void = 0; - - Ref m_manager; - HashSet m_entities; - - friend class EntityManager; - - private: - u32 m_priority; - ComponentTypes m_types; - }; - - class STORMKIT_API EntityManager { - public: - static constexpr auto ADDED_ENTITY_MESSAGE_ID = 1; - static constexpr auto REMOVED_ENTITY_MESSAGE_ID = 2; - - explicit EntityManager(); - ~EntityManager(); - - EntityManager(const EntityManager&) = delete; - auto operator=(const EntityManager&) -> EntityManager& = delete; - - EntityManager(EntityManager&&); - auto operator=(EntityManager&&) -> EntityManager&; - - auto make_entity() -> Entity; - auto destroy_entity(Entity entity) -> void; - auto destroy_all_entities() -> void; - auto has_entity(Entity entity) const -> bool; - - template - auto add_component(Entity entity, Args&&... args) -> T&; - - template - auto destroy_component(Entity entity) -> void; - - template - auto has_component(Entity entity) const -> bool; - - auto has_component(Entity entity, Component::Type type) const -> bool; - - auto entities() const noexcept -> const std::vector&; - - template - auto entities_with_component() const -> std::vector; - - template - auto getComponent(this Self& self, Entity entity) -> core::meta::ForwardConst; - - template - auto components(this Self& self, Entity entity) - -> std::vector>>; - - template - auto components_of_type(this Self& self) noexcept - -> std::vector>>; - - template - auto add_system(Args&&... args) -> T&; - - template - auto has_system() const noexcept -> bool; - - template - auto systems(this Self& self) noexcept - -> std::vector>>; - - template - auto get_system(this Self& self) noexcept -> core::meta::ForwardConst; - - auto step(Secondf delta) -> void; - - auto entity_count() const noexcept -> usize; - - // void commit(Entity e); - - private: - using ComponentKey = u64; - - static constexpr auto component_key_for(Entity e, Component::Type type) noexcept - -> ComponentKey; - static constexpr auto is_key_entity(Entity e, ComponentKey key) noexcept -> bool; - - auto purpose_to_systems(Entity e) -> void; - auto remove_from_systems(Entity e) -> void; - auto get_needed_entities(System& system) -> void; - - Entity m_next_valid_entity = 1; - std::queue m_free_entities; - - HashSet m_entities; - - HashSet m_added_entities; - HashSet m_updated_entities; - HashSet m_removed_entities; - - HashMap> m_registered_components_for_entities; - std::set, System::Predicate> m_systems; - HashMap> m_components; - - MessageBus m_message_bus; - }; -} // namespace stormkit::entities - -namespace stormkit::entities { - ///////////////////////////////////// - ///////////////////////////////////// -#ifdef STORMKIT_COMPILER_MSVC - inline auto EntityHashFunc::operator()(Entity k) const noexcept -> hash64 { -#else - inline auto EntityHashFunc::operator()(Entity k) noexcept -> hash64 { -#endif - return as(k); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - constexpr auto component_hash(std::string_view str) noexcept -> Result { - return std::empty(str) - ? 0xcbf29ce484222325UL - : (as(str[0]) ^ component_hash(str.substr(1, std::size(str) - 1))) - * 0x100000001b3UL; - } - - ///////////////////////////////////// - ///////////////////////////////////// - constexpr auto component_hash(CZString str, usize size) noexcept -> Component::Type { - return size == 0 - ? 0xcbf29ce484222325UL - : (as(str[0]) ^ component_hash(std::string_view { str + 1, size - 1 })) - * 0x100000001b3UL; - } - - ///////////////////////////////////// - ///////////////////////////////////// - constexpr auto component_hash(std::string_view str) noexcept -> Component::Type { - return component_hash(std::data(str), std::size(str)); - } - - namespace literals { - ///////////////////////////////////// - ///////////////////////////////////// - constexpr auto operator""_component_type(CZString str, usize size) -> Component::Type { - return stormkit::entities::component_hash(str, size); - } - } // namespace literals - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto MessageBus::empty() const noexcept -> bool { - return std::empty(m_messages); - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto System::priority() const noexcept -> u32 { - return m_priority; - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto System::components_used() const noexcept -> const ComponentTypes& { - return m_types; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - auto EntityManager::add_component(Entity entity, Args&&... args) -> T& { - static_assert(T::TYPE != Component::INVALID_TYPE, "T must have T::type defined"); - - EXPECTS(has_entity(entity)); - EXPECTS(not has_component(entity)); - - auto component = std::make_unique(std::forward(args)...); - - auto type = T::TYPE; - m_components[component_key_for(entity, type)] = std::move(component); - m_registered_components_for_entities.at(entity).emplace_back(type); - - m_updated_entities.emplace(entity); - - return getComponent(entity); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - auto EntityManager::destroy_component(Entity entity) -> void { - static_assert(T::TYPE != Component::INVALID_TYPE, "T must have T::type defined"); - - EXPECTS(has_entity(entity)); - EXPECTS(has_component(entity)); - - const auto key = component_key_for(entity, T::TYPE); - - if (m_components.find(key) != stdr::cend(m_components)) m_components.erase(key); - - m_updated_entities.emplace(entity); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - auto EntityManager::has_component(Entity entity) const -> bool { - static_assert(T::TYPE != Component::INVALID_TYPE, "T must have T::type defined"); - - return has_component(entity, T::TYPE); - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto EntityManager::entities() const noexcept -> const std::vector& { - return m_entities.values(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - auto EntityManager::entities_with_component() const -> std::vector { - // clang-format off - return entities() - | stdv::filter([](auto&& entity) static noexcept { return stdr::any_of(entity, T::TYPE); }) - | stdr::to(); - // clang-format on - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - auto EntityManager::getComponent(this Self& self, Entity entity) - -> core::meta::ForwardConst { - EXPECTS(self.template has_component(entity)); - EXPECTS(self.has_entity(entity)); - - const auto key = component_key_for(entity, T::TYPE); - return *std::bit_cast(self.m_components.at(key).get()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - auto EntityManager::components(this Self& self, Entity entity) - -> std::vector>> { - if (not self.has_entity(entity)) [[unlikely]] - return {}; - // clang-format off - return self.m_components - | stdv::filter([entity](auto&& pair) noexcept { - return EntityManager::is_key_entity(entity, pair.first); - }) - | stdv::values - | stdv::transform(monadic::as_ref()) - | stdr::to(); - // clang-format on - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - auto EntityManager::components_of_type(this Self& self) noexcept - -> std::vector>> { - // clang-format off - return self.m_entities - | stdv::filter(bind_front(&EntityManager::has_component, &self)) - | stdv::transform(bind_front(&EntityManager::getComponent, &self)) - | stdv::transform(monadic::forward_like()) - | stdv::transform(monadic::as_ref()) - | stdr::to(); - // clang-format on - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - auto EntityManager::add_system(Args&&... args) -> T& { - m_systems.emplace(std::make_unique(std::forward(args)..., *this)); - - auto& system = get_system(); - - get_needed_entities(system); - - return system; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - auto EntityManager::has_system() const noexcept -> bool { - return stdr::any_of(m_systems, monadic::is()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - auto EntityManager::systems(this Self& self) noexcept - -> std::vector>> { - constexpr auto as_refer = [] { - if constexpr (core::meta::IsConst) return monadic::as_ref(); - else - return monadic::as_ref_mut(); - }(); - - return self.m_systems | stdv::transform(as_refer) | stdr::to(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - auto EntityManager::get_system(this Self& self) noexcept -> core::meta::ForwardConst { - EXPECTS(self.template has_system()); - - auto it = stdr::find_if(self.m_systems, monadic::is()); - - return as>(*it->get()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto EntityManager::entity_count() const noexcept -> usize { - return std::size(m_entities); - } - - ///////////////////////////////////// - ///////////////////////////////////// - constexpr auto EntityManager::component_key_for(Entity e, Component::Type type) noexcept - -> ComponentKey { - return (static_cast(e) << 32) | static_cast(type); - } - - ///////////////////////////////////// - ///////////////////////////////////// - constexpr auto EntityManager::is_key_entity(Entity e, ComponentKey type) noexcept -> bool { - return static_cast(e) == (type >> 32); - } -} // namespace stormkit::entities diff --git a/modules/stormkit/gpu.mpp b/modules/stormkit/gpu.cppm similarity index 94% rename from modules/stormkit/gpu.mpp rename to modules/stormkit/gpu.cppm index 019a4b993..56f5892b7 100644 --- a/modules/stormkit/gpu.mpp +++ b/modules/stormkit/gpu.cppm @@ -1,11 +1,10 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -export module stormkit.gpu; - -// export import stormkit.gpu:Core.Compute; -export import stormkit.gpu.core; -export import stormkit.gpu.execution; -export import stormkit.gpu.resource; -export ; +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +export module stormkit.gpu; + +// export import stormkit.gpu:Core.Compute; +export import stormkit.gpu.core; +export import stormkit.gpu.execution; +export import stormkit.gpu.resource; diff --git a/modules/stormkit/gpu/core.mpp b/modules/stormkit/gpu/core.cppm similarity index 74% rename from modules/stormkit/gpu/core.mpp rename to modules/stormkit/gpu/core.cppm index dda5cd765..54f568fee 100644 --- a/modules/stormkit/gpu/core.mpp +++ b/modules/stormkit/gpu/core.cppm @@ -1,12 +1,17 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -export module stormkit.gpu.core; - -export import :loader; -export import :device; -export import :instance; -export import :structs; -export import :sync; -export import :vulkan; +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +export module stormkit.gpu.core; + +export import :meta; +export import :base; +export import :loader; +export import :objects; +export import :instance; +export import :debug_callback; +export import :surface; +export import :device; +export import :structs; +export import :sync; +export import :vulkan; diff --git a/modules/stormkit/gpu/core/base.cppm b/modules/stormkit/gpu/core/base.cppm new file mode 100644 index 000000000..a8ab5c1e6 --- /dev/null +++ b/modules/stormkit/gpu/core/base.cppm @@ -0,0 +1,730 @@ +// Copyright (C) 2023 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include + +#include +#include + +export module stormkit.gpu.core:base; + +import std; + +import stormkit.core; + +import :meta; +import :structs; +import :vulkan; + +namespace stdr = std::ranges; +namespace stdv = std::views; + +namespace cmeta = stormkit::core::meta; + +export namespace stormkit::gpu { + STORMKIT_GPU_API + auto initialize_backend() -> Expected; + + template + class GpuObjectViewImplementation; + + template + class GpuObjectBase { + public: + using TagType = Tag; + using TraitType = trait::GpuObject; + using ValueType = TraitType::ValueType; + using ObjectType = TraitType::ObjectType; + using ViewType = TraitType::ViewType; + + ~GpuObjectBase() noexcept; + + GpuObjectBase(const GpuObjectBase&) noexcept; + auto operator=(const GpuObjectBase&) noexcept -> GpuObjectBase&; + + GpuObjectBase(GpuObjectBase&&) noexcept; + auto operator=(GpuObjectBase&&) noexcept -> GpuObjectBase&; + + [[nodiscard]] + auto native_handle() const noexcept -> ValueType; + + [[nodiscard]] + operator ValueType() const noexcept; + + protected: + GpuObjectBase() noexcept; + + ValueType m_vk_handle = VK_NULL_HANDLE; + + friend class GpuObjectViewImplementation; + }; + + template + requires(meta::HasOwnerType) + class GpuObjectBase { + public: + using TagType = Tag; + using TraitType = trait::GpuObject; + using ValueType = TraitType::ValueType; + using ObjectType = TraitType::ObjectType; + using ViewType = TraitType::ViewType; + using OwnerType = TraitType::OwnerType; + using OwnerViewType = typename OwnerType::ViewType; + + ~GpuObjectBase() noexcept; + + GpuObjectBase(const GpuObjectBase&) noexcept; + auto operator=(const GpuObjectBase&) noexcept -> GpuObjectBase&; + + GpuObjectBase(GpuObjectBase&&) noexcept; + auto operator=(GpuObjectBase&&) noexcept -> GpuObjectBase&; + + [[nodiscard]] + auto native_handle() const noexcept -> ValueType; + + [[nodiscard]] + operator ValueType() const noexcept; + + [[nodiscard]] + auto owner() const noexcept -> OwnerViewType; + + protected: + GpuObjectBase(OwnerViewType&&) noexcept; + + ValueType m_vk_handle = VK_NULL_HANDLE; + OwnerViewType m_owner; + + friend class GpuObjectViewImplementation; + }; + + template + class GpuObjectImplementation; + + template + class GpuObjectViewImplementation: public GpuObjectBase { + using Base = GpuObjectBase; + + public: + using TagType = Base::TagType; + using TraitType = Base::TraitType; + using ValueType = Base::ValueType; + using ObjectType = Base::ObjectType; + using ViewType = Base::ViewType; + + GpuObjectViewImplementation(const cmeta::IsSpecializationOf auto&) noexcept; + template + GpuObjectViewImplementation(const TContainerOrPointer&) noexcept; + ~GpuObjectViewImplementation() noexcept; + + GpuObjectViewImplementation(const GpuObjectViewImplementation&) noexcept; + auto operator=(const GpuObjectViewImplementation&) noexcept -> GpuObjectViewImplementation&; + + GpuObjectViewImplementation(GpuObjectViewImplementation&&) noexcept; + auto operator=(GpuObjectViewImplementation&&) noexcept -> GpuObjectViewImplementation&; + }; + + template + requires(meta::HasOwnerType) + class GpuObjectViewImplementation: public GpuObjectBase { + using Base = GpuObjectBase; + + public: + using TagType = Base::TagType; + using TraitType = Base::TraitType; + using ValueType = Base::ValueType; + using ObjectType = Base::ObjectType; + using ViewType = Base::ViewType; + using OwnerType = Base::OwnerType; + using OwnerViewType = Base::OwnerViewType; + + GpuObjectViewImplementation(const cmeta::IsSpecializationOf auto&) noexcept; + template + GpuObjectViewImplementation(const TContainerOrPointer&) noexcept; + ~GpuObjectViewImplementation() noexcept; + + GpuObjectViewImplementation(const GpuObjectViewImplementation&) noexcept; + auto operator=(const GpuObjectViewImplementation&) noexcept -> GpuObjectViewImplementation&; + + GpuObjectViewImplementation(GpuObjectViewImplementation&&) noexcept; + auto operator=(GpuObjectViewImplementation&&) noexcept -> GpuObjectViewImplementation&; + }; + + template + requires(meta::GpuObjectHasTraitDefined) + class GpuObjectImplementation + : public GpuObjectBase, + public core::NamedConstructor::ObjectType, DoInitArgs> { + using Base = GpuObjectBase; + + protected: + using NamedConstructorBase = core::NamedConstructor::ObjectType, + DoInitArgs>; + + public: + using TagType = Base::TagType; + using TraitType = Base::TraitType; + using ValueType = Base::ValueType; + using ObjectType = Base::ObjectType; + using ViewType = Base::ViewType; + using DeleterType = TraitType::DeleterType; + + GpuObjectImplementation(DeleterType&&) noexcept; + ~GpuObjectImplementation() noexcept; + + GpuObjectImplementation(const GpuObjectImplementation&) noexcept = delete; + auto operator=(const GpuObjectImplementation&) noexcept -> GpuObjectImplementation& = delete; + + GpuObjectImplementation(GpuObjectImplementation&&) noexcept; + auto operator=(GpuObjectImplementation&&) noexcept -> GpuObjectImplementation&; + + using NamedConstructorBase::allocate; + using NamedConstructorBase::create; + + protected: + DeleterType m_deleter_ptr; + }; + + template + requires(meta::GpuObjectHasTraitDefined and meta::HasOwnerType) + class GpuObjectImplementation + : public GpuObjectBase, + public core::NamedConstructor::ObjectType, + ConstructorArgs::OwnerType::ViewType>, + DoInitArgs> { + using Base = GpuObjectBase; + + protected: + using NamedConstructorBase = core::NamedConstructor::ObjectType, + ConstructorArgs::OwnerType::ViewType>, + DoInitArgs>; + + public: + using TagType = Base::TagType; + using TraitType = Base::TraitType; + using ValueType = Base::ValueType; + using ObjectType = Base::ObjectType; + using ViewType = Base::ViewType; + using DeleterType = TraitType::DeleterType; + using OwnerType = Base::OwnerType; + using OwnerViewType = Base::OwnerViewType; + + GpuObjectImplementation(OwnerViewType&&, DeleterType&&) noexcept; + ~GpuObjectImplementation() noexcept; + + GpuObjectImplementation(const GpuObjectImplementation&) noexcept = delete; + auto operator=(const GpuObjectImplementation&) noexcept -> GpuObjectImplementation& = delete; + + GpuObjectImplementation(GpuObjectImplementation&&) noexcept; + auto operator=(GpuObjectImplementation&&) noexcept -> GpuObjectImplementation&; + + using NamedConstructorBase::allocate; + using NamedConstructorBase::create; + + protected: + DeleterType m_deleter_ptr; + }; + + template + requires(meta::IsGpuView>) + auto as_view(T&& value) noexcept -> decltype(auto); + + template + auto as_view(const T& value) noexcept -> trait::GpuObject::ViewType; + + template + auto as_view(const T& value) noexcept + -> trait::GpuObject>::TagType>::ViewType; + + template + auto as_view(const T& value) noexcept + -> trait::GpuObject>::TagType>::ViewType; + + template class Out = array, typename... Args> + requires(not stdr::range and ...) + auto as_views(Args&&... args) noexcept -> decltype(auto); + + template class Out = dyn_array, typename... Args> + requires(not stdr::range and ...) + auto to_views(Args&&... args) noexcept -> decltype(auto); + + template class Out = dyn_array, stdr::range Range> + auto to_views(const Range& range) noexcept -> decltype(auto); + + template + auto format_as(const T& object, FormatContext& ctx) noexcept -> decltype(ctx.out()); +} // namespace stormkit::gpu + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit::gpu { + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline GpuObjectBase::GpuObjectBase() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline GpuObjectBase::~GpuObjectBase() noexcept { + m_vk_handle = VK_NULL_HANDLE; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline GpuObjectBase::GpuObjectBase(const GpuObjectBase&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto GpuObjectBase::operator=(const GpuObjectBase&) noexcept -> GpuObjectBase& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline GpuObjectBase::GpuObjectBase(GpuObjectBase&& other) noexcept + : m_vk_handle { std::exchange(other.m_vk_handle, VK_NULL_HANDLE) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto GpuObjectBase::operator=(GpuObjectBase&& other) noexcept -> GpuObjectBase& { + if (&other == this) [[unlikely]] + return *this; + + m_vk_handle = std::exchange(other.m_vk_handle, VK_NULL_HANDLE); + + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto GpuObjectBase::native_handle() const noexcept -> ValueType { + EXPECTS(m_vk_handle != VK_NULL_HANDLE); + return m_vk_handle; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline GpuObjectBase::operator ValueType() const noexcept { + return native_handle(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(meta::HasOwnerType) + STORMKIT_FORCE_INLINE + inline GpuObjectBase::GpuObjectBase(OwnerViewType&& owner) noexcept + : m_owner { std::move(owner) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(meta::HasOwnerType) + STORMKIT_FORCE_INLINE + inline GpuObjectBase::~GpuObjectBase() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(meta::HasOwnerType) + STORMKIT_FORCE_INLINE + inline GpuObjectBase::GpuObjectBase(const GpuObjectBase&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(meta::HasOwnerType) + STORMKIT_FORCE_INLINE + inline auto GpuObjectBase::operator=(const GpuObjectBase&) noexcept -> GpuObjectBase& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(meta::HasOwnerType) + STORMKIT_FORCE_INLINE + inline GpuObjectBase::GpuObjectBase(GpuObjectBase&& other) noexcept + : m_vk_handle { std::exchange(other.m_vk_handle, VK_NULL_HANDLE) }, m_owner { std::move(other.m_owner) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(meta::HasOwnerType) + STORMKIT_FORCE_INLINE + inline auto GpuObjectBase::operator=(GpuObjectBase&& other) noexcept -> GpuObjectBase& { + if (&other == this) [[unlikely]] + return *this; + + m_vk_handle = std::exchange(other.m_vk_handle, VK_NULL_HANDLE); + m_owner = std::move(other.m_owner); + + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(meta::HasOwnerType) + STORMKIT_FORCE_INLINE + inline auto GpuObjectBase::native_handle() const noexcept -> ValueType { + EXPECTS(m_vk_handle != VK_NULL_HANDLE); + return m_vk_handle; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(meta::HasOwnerType) + STORMKIT_FORCE_INLINE + inline GpuObjectBase::operator ValueType() const noexcept { + return native_handle(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(meta::HasOwnerType) + STORMKIT_FORCE_INLINE + inline auto GpuObjectBase::owner() const noexcept -> OwnerViewType { + return m_owner; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline GpuObjectViewImplementation< + Tag>::GpuObjectViewImplementation(const cmeta::IsSpecializationOf auto& object) noexcept + : GpuObjectBase {} { + GpuObjectBase::m_vk_handle = object.m_vk_handle; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + template + STORMKIT_FORCE_INLINE + inline GpuObjectViewImplementation::GpuObjectViewImplementation(const TContainerOrPointer& object) noexcept + : GpuObjectBase {} { + GpuObjectBase::m_vk_handle = (*object).m_vk_handle; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline GpuObjectViewImplementation::~GpuObjectViewImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline GpuObjectViewImplementation::GpuObjectViewImplementation(const GpuObjectViewImplementation&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto GpuObjectViewImplementation::operator=(const GpuObjectViewImplementation&) noexcept + -> GpuObjectViewImplementation& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline GpuObjectViewImplementation::GpuObjectViewImplementation(GpuObjectViewImplementation&& other) noexcept + : GpuObjectBase {} { + GpuObjectBase::m_vk_handle = other.m_vk_handle; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto GpuObjectViewImplementation::operator=(GpuObjectViewImplementation&& other) noexcept + -> GpuObjectViewImplementation& { + if (this == &other) [[unlikely]] + return *this; + + GpuObjectBase::m_vk_handle = other.m_vk_handle; + + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(meta::HasOwnerType) + STORMKIT_FORCE_INLINE + inline GpuObjectViewImplementation< + Tag>::GpuObjectViewImplementation(const cmeta::IsSpecializationOf auto& object) noexcept + : GpuObjectBase { object.owner() } { + GpuObjectBase::m_vk_handle = object.m_vk_handle; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(meta::HasOwnerType) + template + STORMKIT_FORCE_INLINE + inline GpuObjectViewImplementation::GpuObjectViewImplementation(const TContainerOrPointer& object) noexcept + : GpuObjectBase { (*object).owner() } { + GpuObjectBase::m_vk_handle = (*object).m_vk_handle; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(meta::HasOwnerType) + STORMKIT_FORCE_INLINE + inline GpuObjectViewImplementation::~GpuObjectViewImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(meta::HasOwnerType) + STORMKIT_FORCE_INLINE + inline GpuObjectViewImplementation< + Tag>::GpuObjectViewImplementation(const GpuObjectViewImplementation& other) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(meta::HasOwnerType) + STORMKIT_FORCE_INLINE + inline auto GpuObjectViewImplementation::operator=(const GpuObjectViewImplementation&) noexcept + -> GpuObjectViewImplementation& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(meta::HasOwnerType) + STORMKIT_FORCE_INLINE + inline GpuObjectViewImplementation::GpuObjectViewImplementation(GpuObjectViewImplementation&& other) noexcept + : GpuObjectBase { other.owner() } { + GpuObjectBase::m_vk_handle = other.m_vk_handle; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(meta::HasOwnerType) + STORMKIT_FORCE_INLINE + inline auto GpuObjectViewImplementation::operator=(GpuObjectViewImplementation&& other) noexcept + -> GpuObjectViewImplementation& { + if (this == &other) [[unlikely]] + return *this; + + GpuObjectBase::m_vk_handle = other.m_vk_handle; + GpuObjectBase::m_owner = other.m_owner; + + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(meta::GpuObjectHasTraitDefined) + STORMKIT_FORCE_INLINE + inline GpuObjectImplementation::GpuObjectImplementation(DeleterType&& deleter_ptr) noexcept + : GpuObjectBase {}, m_deleter_ptr { std::move(deleter_ptr) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(meta::GpuObjectHasTraitDefined) + STORMKIT_FORCE_INLINE inline GpuObjectImplementation::~GpuObjectImplementation() noexcept { + if constexpr (cmeta::SameAs) { + if (m_deleter_ptr != nullptr and Base::m_vk_handle != VK_NULL_HANDLE) + vk::call(m_deleter_ptr, Base::m_vk_handle, nullptr); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(meta::GpuObjectHasTraitDefined) + STORMKIT_FORCE_INLINE + inline GpuObjectImplementation::GpuObjectImplementation(GpuObjectImplementation&& other) noexcept + : GpuObjectBase { std::move(other) }, m_deleter_ptr { std::exchange(other.m_deleter_ptr, {}) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(meta::GpuObjectHasTraitDefined) + STORMKIT_FORCE_INLINE + inline auto GpuObjectImplementation::operator=(GpuObjectImplementation&& other) noexcept + -> GpuObjectImplementation& { + if (&other == this) [[unlikely]] + return *this; + + GpuObjectBase::operator=(std::move(other)); + + m_deleter_ptr = std::exchange(other.m_deleter_ptr, {}); + + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(meta::GpuObjectHasTraitDefined and meta::HasOwnerType) + STORMKIT_FORCE_INLINE + inline GpuObjectImplementation::GpuObjectImplementation(OwnerViewType&& owner, + DeleterType&& deleter_ptr) noexcept + : GpuObjectBase { std::move(owner) }, m_deleter_ptr { std::move(deleter_ptr) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(meta::GpuObjectHasTraitDefined and meta::HasOwnerType) + STORMKIT_FORCE_INLINE inline GpuObjectImplementation::~GpuObjectImplementation() noexcept { + using OwnerValueType = OwnerType::ValueType; + + if constexpr (cmeta::SameAs) { + if constexpr (cmeta::SameAs) { + if (m_deleter_ptr != nullptr and Base::m_vk_handle != VK_NULL_HANDLE) + vk::call(m_deleter_ptr, Base::m_owner, Base::m_vk_handle, nullptr); + } else { + const auto& device = this->device(); + const auto& device_table = device.device_table(); + if (m_deleter_ptr != nullptr and Base::m_vk_handle != VK_NULL_HANDLE) + vk::call(device_table.*m_deleter_ptr, device, Base::m_vk_handle, nullptr); + } + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(meta::GpuObjectHasTraitDefined and meta::HasOwnerType) + STORMKIT_FORCE_INLINE + inline GpuObjectImplementation::GpuObjectImplementation(GpuObjectImplementation&& other) noexcept + : GpuObjectBase { std::move(other) }, m_deleter_ptr { std::exchange(other.m_deleter_ptr, {}) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(meta::GpuObjectHasTraitDefined and meta::HasOwnerType) + STORMKIT_FORCE_INLINE + inline auto GpuObjectImplementation::operator=(GpuObjectImplementation&& other) noexcept + -> GpuObjectImplementation& { + if (&other == this) [[unlikely]] + return *this; + + GpuObjectBase::operator=(std::move(other)); + + m_deleter_ptr = std::exchange(other.m_deleter_ptr, {}); + + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(meta::IsGpuView>) + STORMKIT_FORCE_INLINE + inline auto as_view(T&& value) noexcept -> decltype(auto) { + return std::forward(value); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto as_view(const T& value) noexcept -> trait::GpuObject::ViewType { + using Out = trait::GpuObject::ViewType; + return Out { value }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto as_view(const T& value) noexcept + -> trait::GpuObject>::TagType>::ViewType { + return as_view(unref(value)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto as_view(const T& value) noexcept + -> trait::GpuObject>::TagType>::ViewType { + return as_view(value.value()); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template class Out, typename... Args> + requires(not stdr::range and ...) + STORMKIT_FORCE_INLINE + inline auto as_views(Args&&... args) noexcept -> decltype(auto) { + using ValueType = std::common_type_t>...>; + using TagType = typename ValueType::TagType; + using ViewType = trait::GpuObject::ViewType; + + return Out { gpu::as_view(std::forward(args))... }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template class Out, typename... Args> + requires(not stdr::range and ...) + STORMKIT_FORCE_INLINE + inline auto to_views(Args&&... args) noexcept -> decltype(auto) { + using ValueType = std::common_type_t>...>; + using TagType = typename ValueType::TagType; + using ViewType = trait::GpuObject::ViewType; + + return Out { gpu::as_view(std::forward(args))... }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template class Out, stdr::range Range> + STORMKIT_FORCE_INLINE + inline auto to_views(const Range& range) noexcept -> decltype(auto) { + using ValueType = stdr::range_value_t; + using TagType = typename ValueType::TagType; + using ViewType = trait::GpuObject::ViewType; + + return range + | stdv::transform([](T&& val) static noexcept { return gpu::as_view(std::forward(val)); }) + | stdr::to>(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto format_as(const T& object, FormatContext& ctx) noexcept -> decltype(ctx.out()) { + return format_as(as_view(object), ctx); + } +} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/core/debug_callback.cppm b/modules/stormkit/gpu/core/debug_callback.cppm new file mode 100644 index 000000000..0a17d6035 --- /dev/null +++ b/modules/stormkit/gpu/core/debug_callback.cppm @@ -0,0 +1,97 @@ +// Copyright (C) 2023 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +#include +#include + +export module stormkit.gpu.core:debug_callback; + +import std; + +import stormkit.core; + +import :base; +import :vulkan; +import :structs; +import :objects; +import :instance; + +namespace stormkit::gpu { + export { + struct DebugCallbackInterfaceBase { + struct CreateInfo { + using Closure = PFN_vkDebugUtilsMessengerCallbackEXT; + + Closure messenger_closure; + ptr user_data = nullptr; + }; + }; + + template + class DebugCallbackInterface final: public InstanceObject, public DebugCallbackInterfaceBase { + public: + using InstanceObject::InstanceObject; + using InstanceObject::operator=; + using TagType = DebugCallbackTag; + }; + } + + class STORMKIT_GPU_API DebugCallbackImplementation + : public GpuObjectImplementation { + public: + using CreateInfo = DebugCallbackInterfaceBase::CreateInfo; + + DebugCallbackImplementation(PrivateTag, view::Instance&&) noexcept; + ~DebugCallbackImplementation() noexcept; + + DebugCallbackImplementation(const DebugCallbackImplementation&) noexcept = delete; + auto operator=(const DebugCallbackImplementation&) noexcept -> DebugCallbackImplementation& = delete; + + DebugCallbackImplementation(DebugCallbackImplementation&&) noexcept; + auto operator=(DebugCallbackImplementation&&) noexcept -> DebugCallbackImplementation&; + + auto do_init(PrivateTag, const CreateInfo&) noexcept -> Expected; + }; + + namespace view { + class DebugCallbackImplementation: public GpuObjectViewImplementation { + public: + using GpuObjectViewImplementation::GpuObjectViewImplementation; + using GpuObjectViewImplementation::operator=; + }; + } // namespace view +} // namespace stormkit::gpu + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit::gpu { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline DebugCallbackImplementation::DebugCallbackImplementation(PrivateTag, view::Instance&& instance) noexcept + : GpuObjectImplementation { std::move(instance), auto(vkDestroyDebugUtilsMessengerEXT) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline DebugCallbackImplementation::~DebugCallbackImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline DebugCallbackImplementation::DebugCallbackImplementation(DebugCallbackImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto DebugCallbackImplementation::operator=(DebugCallbackImplementation&&) noexcept + -> DebugCallbackImplementation& = default; +} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/core/device.cppm b/modules/stormkit/gpu/core/device.cppm new file mode 100644 index 000000000..0caeeae26 --- /dev/null +++ b/modules/stormkit/gpu/core/device.cppm @@ -0,0 +1,287 @@ +// Copyright (C) 2023 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include +#include + +#include +#include + +export module stormkit.gpu.core:device; + +import std; + +import stormkit.core; + +import :vulkan; +import :base; + +import :structs; +import :objects; + +import :instance; + +namespace cmeta = stormkit::core::meta; + +using namespace stormkit; + +namespace stormkit::gpu { + export { + struct QueueEntry { + u32 id; + u32 count; + QueueFlag flags = QueueFlag {}; + }; + + struct DeviceInterfaceBase { + struct CreateInfo { + bool enable_swapchain = true; + bool enable_raytracing = false; + }; + }; + + template + class STORMKIT_GPU_API DeviceInterface final: public PhysicalDeviceObject, public DeviceInterfaceBase { + public: + using PhysicalDeviceObject::PhysicalDeviceObject; + using PhysicalDeviceObject::operator=; + using TagType = DeviceTag; + + auto wait_idle() const noexcept -> Expected; + + auto wait_for_fences(array_view fences, + bool wait_all = true, + const std::chrono::milliseconds& timeout = std::chrono::milliseconds::max()) const noexcept + -> Expected; + auto wait_for_fence(view::Fence fence, + const std::chrono::milliseconds& timeout = std::chrono::milliseconds::max()) const noexcept + -> Expected; + + auto reset_fences(array_view fences) const noexcept -> Expected; + auto reset_fence(view::Fence fence) const noexcept -> Expected; + + template + auto set_object_name(const T& object, string_view name) const noexcept -> Expected; + + auto set_object_name(u64 object, DebugObjectType type, string_view name) const noexcept -> Expected; + + [[nodiscard]] + auto queue_entries() const noexcept -> array_view; + + [[nodiscard]] + auto device_table() const noexcept -> const VolkDeviceTable&; + + [[nodiscard]] + auto allocator() const noexcept -> vk::Observer; + }; + + namespace vk { + STORMKIT_GPU_API auto imgui_vk_loader(const char* func_name, void*) noexcept -> PFN_vkVoidFunction; + } + + namespace monadic { + template + constexpr auto find_queue() noexcept -> decltype(auto); + } // namespace monadic + } + + class STORMKIT_GPU_API + DeviceImplementation: public GpuObjectImplementation { + public: + using CreateInfo = DeviceInterfaceBase::CreateInfo; + + DeviceImplementation(PrivateTag, view::PhysicalDevice&&) noexcept; + ~DeviceImplementation() noexcept; + + DeviceImplementation(const DeviceImplementation&) noexcept = delete; + auto operator=(const DeviceImplementation&) noexcept -> DeviceImplementation& = delete; + + DeviceImplementation(DeviceImplementation&&) noexcept; + auto operator=(DeviceImplementation&&) noexcept -> DeviceImplementation&; + + auto do_init(PrivateTag, const CreateInfo&) noexcept -> Expected; + + protected: + dyn_array m_queue_entries; + + VolkDeviceTable m_vk_device_table = {}; + VmaVulkanFunctions m_vma_function_table = {}; + vk::Owned m_vma_allocator = { vmaDestroyAllocator }; + }; + + namespace view { + class DeviceImplementation: public GpuObjectViewImplementation { + public: + DeviceImplementation(const gpu::Device& of) noexcept; + template TContainerOrPointer> + DeviceImplementation(const TContainerOrPointer&) noexcept; + ~DeviceImplementation() noexcept; + + DeviceImplementation(const DeviceImplementation&) noexcept; + auto operator=(const DeviceImplementation&) noexcept -> DeviceImplementation&; + + DeviceImplementation(DeviceImplementation&&) noexcept; + auto operator=(DeviceImplementation&&) noexcept -> DeviceImplementation&; + + protected: + array_view m_queue_entries; + + VolkDeviceTable m_vk_device_table; + vk::Observer m_vma_allocator; + }; + } // namespace view +} // namespace stormkit::gpu + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit::gpu { + ///////////////////////////////////// + ///////////////////////////////////// + template + template + STORMKIT_FORCE_INLINE + inline auto DeviceInterface::set_object_name(const T& object, string_view name) const noexcept -> Expected { + if (not vkSetDebugUtilsObjectNameEXT) return {}; + + const auto vk_object = vk::to_vk(object); + return set_object_name(as(std::bit_cast(vk_object)), + trait::GpuObject::DEBUG_TYPE, + std::move(name)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto DeviceInterface::queue_entries() const noexcept -> array_view { + return Base::m_queue_entries; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto DeviceInterface::device_table() const noexcept -> const VolkDeviceTable& { + return Base::m_vk_device_table; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto DeviceInterface::allocator() const noexcept -> vk::Observer { + return Base::m_vma_allocator; + } + + namespace monadic { + ///////////////////////////////////// + ///////////////////////////////////// + template + constexpr auto find_queue() noexcept -> decltype(auto) { + return [](const auto& family) static noexcept { + return core::check_flag_bit(family.flags, flag) and (not core::check_flag_bit(family.flags, no_flag) and ...); + }; + } + } // namespace monadic + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline DeviceImplementation::DeviceImplementation(PrivateTag, view::PhysicalDevice&& physical_device) noexcept + : GpuObjectImplementation { std::move(physical_device), &VolkDeviceTable::vkDestroyDevice } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline DeviceImplementation::~DeviceImplementation() noexcept { + if (m_deleter_ptr != nullptr and m_vk_handle != VK_NULL_HANDLE) + vk::call(m_vk_device_table.*m_deleter_ptr, m_vk_handle, nullptr); + m_vk_handle = VK_NULL_HANDLE; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline DeviceImplementation::DeviceImplementation(DeviceImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto DeviceImplementation::operator=(DeviceImplementation&&) noexcept -> DeviceImplementation& = default; + + namespace view { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline DeviceImplementation::DeviceImplementation(const gpu::Device& of) noexcept + : GpuObjectViewImplementation { of }, + m_queue_entries { of.queue_entries() }, + m_vk_device_table { of.device_table() }, + m_vma_allocator { of.allocator() } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template TContainerOrPointer> + STORMKIT_FORCE_INLINE + inline DeviceImplementation::DeviceImplementation(const TContainerOrPointer& of) noexcept + : DeviceImplementation { *of } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline DeviceImplementation::~DeviceImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline DeviceImplementation::DeviceImplementation(const DeviceImplementation&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto DeviceImplementation::operator=(const DeviceImplementation&) noexcept -> DeviceImplementation& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline DeviceImplementation::DeviceImplementation(DeviceImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto DeviceImplementation::operator=(DeviceImplementation&&) noexcept -> DeviceImplementation& = default; + } // namespace view + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto DeviceObject::instance() const noexcept -> view::Instance { + return Interface::owner().instance(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto DeviceObject::physical_device() const noexcept -> view::PhysicalDevice { + return Interface::owner().physical_device(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto DeviceObject::device() const noexcept -> view::Device { + return Interface::owner(); + } +} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/core/device.mpp b/modules/stormkit/gpu/core/device.mpp deleted file mode 100644 index 878aafaff..000000000 --- a/modules/stormkit/gpu/core/device.mpp +++ /dev/null @@ -1,317 +0,0 @@ -// Copyright (C) 2023 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include -#include - -#include - -export module stormkit.gpu.core:device; - -import std; - -import stormkit.core; -import :vulkan; - -import :structs; - -using namespace stormkit; - -export { - namespace stormkit::gpu { - class PhysicalDevice; - class Instance; - class Fence; - class Semaphore; - - class STORMKIT_API Device { - struct PrivateFuncTag {}; - - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::DEVICE; - - struct QueueEntry { - u32 id; - u32 count; - QueueFlag flags = QueueFlag {}; - }; - - struct Info { - bool enable_swapchain = true; - bool enable_raytracing = false; - }; - - static auto create(const PhysicalDevice& physical_device, - const Instance& instance, - const Info& info = { true, false }) noexcept -> Expected; - static auto allocate(const PhysicalDevice& physical_device, - const Instance& instance, - const Info& info = { true, false }) noexcept - -> Expected>; - ~Device() noexcept; - - Device(const Device&) = delete; - auto operator=(const Device&) -> Device& = delete; - - Device(Device&&) noexcept; - auto operator=(Device&&) noexcept -> Device&; - - auto wait_idle() const noexcept -> void; - - auto wait_for_fences(std::span> fences, - bool wait_all = true, - const std::chrono::milliseconds& - timeout = std::chrono::milliseconds::max()) const noexcept - -> Expected; - auto wait_for_fence(const Fence& fence, - const std::chrono::milliseconds& - timeout = std::chrono::milliseconds::max()) const noexcept - -> Expected; - - auto reset_fences(std::span> fences) const noexcept - -> Expected; - auto reset_fence(const Fence& fence) const noexcept -> Expected; - - [[nodiscard]] - auto raster_queue_entry() const noexcept -> const QueueEntry&; - [[nodiscard]] - auto async_transfer_queue_entry() const noexcept -> const QueueEntry&; - [[nodiscard]] - auto async_compute_queue_entry() const noexcept -> const QueueEntry&; - - [[nodiscard]] - auto has_async_transfer_queue() const noexcept -> bool; - [[nodiscard]] - auto has_async_compute_queue() const noexcept -> bool; - - [[nodiscard]] - auto physical_device() const noexcept -> const PhysicalDevice&; - - template - auto set_object_name(const T& object, std::string_view name) const -> Expected; - - auto set_object_name(u64 object, DebugObjectType type, std::string_view name) const - -> Expected; - - [[nodiscard]] - auto native_handle() const noexcept -> VkDevice; - - [[nodiscard]] - auto device_table() const noexcept -> const VolkDeviceTable&; - - [[nodiscard]] - auto allocator() const noexcept -> VmaAllocator; - - Device(const PhysicalDevice&, PrivateFuncTag) noexcept; - - private: - auto do_init(const Instance&, const Info&) noexcept -> Expected; - - Ref m_physical_device; - - QueueEntry m_raster_queue; - std::optional m_async_transfert_queue; - std::optional m_async_compute_queue; - - VolkDeviceTable m_vk_device_table = zeroed(); - VkRAIIHandle m_vk_handle = { [](auto) static noexcept {} }; - VmaVulkanFunctions m_vma_function_table = zeroed(); - VkRAIIHandle m_vma_allocator = { [](auto handle) static noexcept { - vmaDestroyAllocator(handle); - } }; - }; - - STORMKIT_API - auto imgui_vk_loader(const char* func_name, void*) noexcept -> PFN_vkVoidFunction; - } // namespace stormkit::gpu - - template - struct std::formatter { - template - [[nodiscard]] - constexpr auto parse(ParseContext& ctx) noexcept -> ParseContext::iterator; - - template - [[nodiscard]] - auto format(const gpu::Device::QueueEntry& queue, FormatContext& ctx) const noexcept - -> decltype(ctx.out()); - }; -} - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::gpu { - ///////////////////////////////////// - ///////////////////////////////////// - - inline Device::Device(const PhysicalDevice& physical_device, PrivateFuncTag) noexcept - : m_physical_device { as_ref(physical_device) } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - - inline Device::~Device() noexcept { - if (m_vk_handle) wait_idle(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - - inline auto Device::create(const PhysicalDevice& physical_device, - const Instance& instance, - const Info& info) noexcept -> Expected { - auto device = Device { physical_device, PrivateFuncTag {} }; - return device.do_init(instance, info).transform(core::monadic::consume(device)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - - inline auto Device::allocate(const PhysicalDevice& physical_device, - const Instance& instance, - const Info& info) noexcept -> Expected> { - auto device = core::allocate_unsafe(physical_device, PrivateFuncTag {}); - return device->do_init(instance, info).transform(core::monadic::consume(device)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - - inline Device::Device(Device&&) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - - inline auto Device::operator=(Device&&) noexcept -> Device& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - - inline auto Device::wait_idle() const noexcept -> void { - // native_handle().wait_idle(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - - inline auto Device::wait_for_fence(const Fence& fence, - const std::chrono::milliseconds& timeout) const noexcept - -> Expected { - return wait_for_fences(as_refs(fence), true, timeout); - } - - ///////////////////////////////////// - ///////////////////////////////////// - - inline auto Device::reset_fence(const Fence& fence) const noexcept -> Expected { - return reset_fences(as_refs(fence)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - - inline auto Device::raster_queue_entry() const noexcept -> const QueueEntry& { - return m_raster_queue; - } - - ///////////////////////////////////// - ///////////////////////////////////// - - inline auto Device::async_transfer_queue_entry() const noexcept -> const QueueEntry& { - EXPECTS(m_async_transfert_queue != std::nullopt); - - return *m_async_transfert_queue; - } - - ///////////////////////////////////// - ///////////////////////////////////// - - inline auto Device::async_compute_queue_entry() const noexcept -> const QueueEntry& { - EXPECTS(m_async_compute_queue != std::nullopt); - - return *m_async_compute_queue; - } - - ///////////////////////////////////// - ///////////////////////////////////// - - inline auto Device::has_async_transfer_queue() const noexcept -> bool { - return m_async_transfert_queue != std::nullopt; - } - - ///////////////////////////////////// - ///////////////////////////////////// - - inline auto Device::has_async_compute_queue() const noexcept -> bool { - return m_async_compute_queue != std::nullopt; - } - - ///////////////////////////////////// - ///////////////////////////////////// - - inline auto Device::physical_device() const noexcept -> const PhysicalDevice& { - return m_physical_device; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - - inline auto Device::set_object_name(const T& object, std::string_view name) const - -> Expected { - if (not vkSetDebugUtilsObjectNameEXT) return {}; - - auto&& vk_object = to_vk(object); - return set_object_name(std::bit_cast(static_cast(vk_object)), - T::DEBUG_TYPE, - name); - } - - ///////////////////////////////////// - ///////////////////////////////////// - - inline auto Device::native_handle() const noexcept -> VkDevice { - EXPECTS(m_vk_handle.value() != nullptr); - return m_vk_handle.value(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - - inline auto Device::device_table() const noexcept -> const VolkDeviceTable& { - return m_vk_device_table; - } - - ///////////////////////////////////// - ///////////////////////////////////// - - inline auto Device::allocator() const noexcept -> VmaAllocator { - return m_vma_allocator; - } -} // namespace stormkit::gpu - -template -template -constexpr auto std::formatter::parse(ParseContext& ctx) noexcept - -> ParseContext::iterator { - return ctx.begin(); -} - -template -template -auto std::formatter::format(const gpu::Device::QueueEntry& queue, - FormatContext& ctx) const noexcept - -> decltype(ctx.out()) { - auto&& out = ctx.out(); - return format_to(out, - "[Device::QueueEntry: .id = {}, .count = {}, .flags = {}]", - queue.id, - queue.count, - queue.flags); -} diff --git a/modules/stormkit/gpu/core/instance.cppm b/modules/stormkit/gpu/core/instance.cppm new file mode 100644 index 000000000..38b5c59a2 --- /dev/null +++ b/modules/stormkit/gpu/core/instance.cppm @@ -0,0 +1,493 @@ +// Copyright (C) 2023 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include +#include + +#include +#include + +export module stormkit.gpu.core:instance; + +import std; + +import stormkit.core; +import stormkit.wsi; + +import :vulkan; +import :base; + +import :structs; +import :objects; + +namespace cmonadic = stormkit::core::monadic; + +namespace stormkit::gpu { + export { + template + class STORMKIT_GPU_API PhysicalDeviceInterface final: public InstanceObject { + public: + using InstanceObject::InstanceObject; + using InstanceObject::operator=; + using TagType = PhysicalDeviceTag; + + [[nodiscard]] + auto check_extension_support(string_view extension) const noexcept -> bool; + [[nodiscard]] + auto check_extension_support(array_view extensions) const noexcept + -> std::optional>; + [[nodiscard]] + auto check_extension_support(array_view extensions) const noexcept + -> std::optional>; + + [[nodiscard]] + auto info() const noexcept -> const PhysicalDeviceInfo&; + [[nodiscard]] + auto capabilities() const noexcept -> const RenderCapabilities&; + [[nodiscard]] + auto memory_types() const noexcept -> array_view; + [[nodiscard]] + auto queue_families() const noexcept -> array_view; + [[nodiscard]] + auto extensions() const noexcept -> array_view; + [[nodiscard]] + auto formats_properties() const noexcept -> array_view>; + }; + + struct InstanceInterfaceBase { + struct CreateInfo { + string_view application_name; + u32 application_version = vk::make_version(0, 0, 0); + bool enable_validation_layers = (STORMKIT_BUILD_TYPE == "DEBUG"); + }; + }; + + template + class InstanceInterface final: public Base, public InstanceInterfaceBase { + public: + using Base::Base; + using Base::operator=; + using TagType = InstanceTag; + + [[nodiscard]] + auto extensions() const noexcept -> array_view; + + [[nodiscard]] + auto physical_devices() const noexcept -> array_view; + }; + } + + class STORMKIT_GPU_API + InstanceImplementation: public GpuObjectImplementation { + public: + using CreateInfo = InstanceInterfaceBase::CreateInfo; + + explicit InstanceImplementation(PrivateTag) noexcept; + ~InstanceImplementation() noexcept; + + InstanceImplementation(const InstanceImplementation&) noexcept = delete; + auto operator=(const InstanceImplementation&) noexcept -> InstanceImplementation& = delete; + + InstanceImplementation(InstanceImplementation&&) noexcept; + auto operator=(InstanceImplementation&&) noexcept -> InstanceImplementation&; + + auto do_init(PrivateTag, const CreateInfo&) noexcept -> Expected; + + protected: + dyn_array m_extensions; + dyn_array m_physical_devices; + + friend class view::InstanceImplementation; + + private: + auto do_load_instance() noexcept -> Expected; + auto do_retrieve_physical_devices() noexcept -> Expected; + }; + + namespace view { + class InstanceImplementation: public GpuObjectViewImplementation { + public: + InstanceImplementation(const gpu::Instance&) noexcept; + template TContainerOrPointer> + InstanceImplementation(const TContainerOrPointer&) noexcept; + InstanceImplementation(const gpu::InstanceImplementation&) noexcept; + ~InstanceImplementation() noexcept; + + InstanceImplementation(const InstanceImplementation&) noexcept; + auto operator=(const InstanceImplementation&) noexcept -> InstanceImplementation&; + + InstanceImplementation(InstanceImplementation&&) noexcept; + auto operator=(InstanceImplementation&&) noexcept -> InstanceImplementation&; + + protected: + array_view m_extensions; + array_view m_physical_devices; + }; + } // namespace view + + class STORMKIT_GPU_API PhysicalDeviceImplementation: public GpuObjectImplementation { + public: + struct Data { + PhysicalDeviceInfo device_info; + RenderCapabilities capabilities; + }; + + PhysicalDeviceImplementation(PrivateTag, view::Instance&&) noexcept; + ~PhysicalDeviceImplementation() noexcept; + + PhysicalDeviceImplementation(const PhysicalDeviceImplementation&) noexcept = delete; + auto operator=(const PhysicalDeviceImplementation&) noexcept -> PhysicalDeviceImplementation& = delete; + + PhysicalDeviceImplementation(PhysicalDeviceImplementation&&) noexcept; + auto operator=(PhysicalDeviceImplementation&&) noexcept -> PhysicalDeviceImplementation&; + + auto do_init(PrivateTag, VkPhysicalDevice&&) noexcept -> void; + + protected: + Heap m_data; + dyn_array m_memory_types; + dyn_array m_queue_families; + dyn_array m_extensions; + dyn_array> m_format_properties; + + friend class InstanceInterface; + friend class view::PhysicalDeviceImplementation; + }; + + namespace view { + class PhysicalDeviceImplementation: public GpuObjectViewImplementation { + public: + PhysicalDeviceImplementation(const gpu::PhysicalDevice&) noexcept; + template TContainerOrPointer> + PhysicalDeviceImplementation(const TContainerOrPointer&) noexcept; + ~PhysicalDeviceImplementation() noexcept; + + PhysicalDeviceImplementation(const PhysicalDeviceImplementation&) noexcept; + auto operator=(const PhysicalDeviceImplementation&) noexcept -> PhysicalDeviceImplementation&; + + PhysicalDeviceImplementation(PhysicalDeviceImplementation&&) noexcept; + auto operator=(PhysicalDeviceImplementation&&) noexcept -> PhysicalDeviceImplementation&; + + protected: + ref m_data; + array_view m_memory_types; + array_view m_queue_families; + array_view m_extensions; + array_view> m_format_properties; + }; + } // namespace view + + export { + [[nodiscard]] + STORMKIT_GPU_API auto score_physical_device(view::PhysicalDevice physical_device) noexcept -> u64; + + template + auto format_as(view::PhysicalDevice physical_device, FormatContext& ctx) noexcept -> decltype(ctx.out()); + } +} // namespace stormkit::gpu + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit::gpu { + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto InstanceObject::instance() const noexcept -> view::Instance { + return Interface::owner(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto PhysicalDeviceInterface::check_extension_support(string_view extension) const noexcept -> bool { + return stdr::any_of(extensions(), [extension](const auto& e) { return e == extension; }); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + inline auto PhysicalDeviceInterface::check_extension_support(array_view extensions) const noexcept + -> std::optional> { + auto required_extensions = hash_set { stdr::begin(extensions), stdr::end(extensions) }; + + for (const auto& extension : this->extensions()) required_extensions.erase(extension); + + if (not required_extensions.empty()) return required_extensions; + + return std::nullopt; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + inline auto PhysicalDeviceInterface::check_extension_support(array_view extensions) const noexcept + -> std::optional> { + const auto ext = transform(extensions, cmonadic::init()); + return check_extension_support(ext); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto PhysicalDeviceInterface::info() const noexcept -> const PhysicalDeviceInfo& { + return Base::m_data->device_info; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto PhysicalDeviceInterface::capabilities() const noexcept -> const RenderCapabilities& { + return Base::m_data->capabilities; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto PhysicalDeviceInterface::memory_types() const noexcept -> array_view { + return Base::m_memory_types; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto PhysicalDeviceInterface::queue_families() const noexcept -> array_view { + return Base::m_queue_families; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto PhysicalDeviceInterface::extensions() const noexcept -> array_view { + return Base::m_extensions; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto PhysicalDeviceInterface::formats_properties() const noexcept + -> array_view> { + return Base::m_format_properties; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto InstanceInterface::extensions() const noexcept -> array_view { + return Base::m_extensions; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto InstanceInterface::physical_devices() const noexcept -> array_view { + return Base::m_physical_devices; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline InstanceImplementation::InstanceImplementation(PrivateTag) noexcept + : GpuObjectImplementation { auto(vkDestroyInstance) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline InstanceImplementation::~InstanceImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline InstanceImplementation::InstanceImplementation(InstanceImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto InstanceImplementation::operator=(InstanceImplementation&&) noexcept -> InstanceImplementation& = default; + + namespace view { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline InstanceImplementation::InstanceImplementation(const gpu::Instance& of) noexcept + : GpuObjectViewImplementation { of }, m_extensions { of.extensions() }, m_physical_devices { of.physical_devices() } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template TContainerOrPointer> + STORMKIT_FORCE_INLINE + inline InstanceImplementation::InstanceImplementation(const TContainerOrPointer& of) noexcept + : InstanceImplementation { *of } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline InstanceImplementation::InstanceImplementation(const gpu::InstanceImplementation& of) noexcept + : GpuObjectViewImplementation { of }, m_extensions { of.m_extensions }, m_physical_devices { of.m_physical_devices } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline InstanceImplementation::~InstanceImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline InstanceImplementation::InstanceImplementation(const InstanceImplementation&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto InstanceImplementation::operator=(const InstanceImplementation&) noexcept + -> InstanceImplementation& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline InstanceImplementation::InstanceImplementation(InstanceImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto InstanceImplementation::operator=(InstanceImplementation&&) noexcept -> InstanceImplementation& = default; + } // namespace view + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline PhysicalDeviceImplementation::PhysicalDeviceImplementation(PrivateTag, view::Instance&& instance) noexcept + : GpuObjectImplementation { std::move(instance), monadic::noop() } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline PhysicalDeviceImplementation::~PhysicalDeviceImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline PhysicalDeviceImplementation::PhysicalDeviceImplementation(PhysicalDeviceImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto PhysicalDeviceImplementation::operator=(PhysicalDeviceImplementation&&) noexcept + -> PhysicalDeviceImplementation& = default; + + namespace view { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline PhysicalDeviceImplementation::PhysicalDeviceImplementation(const gpu::PhysicalDevice& of) noexcept + : GpuObjectViewImplementation { of }, + m_data { as_ref(of.m_data) }, + m_memory_types { of.m_memory_types }, + m_queue_families { of.m_queue_families }, + m_extensions { of.m_extensions }, + m_format_properties { of.m_format_properties } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template TContainerOrPointer> + STORMKIT_FORCE_INLINE + inline PhysicalDeviceImplementation::PhysicalDeviceImplementation(const TContainerOrPointer& of) noexcept + : PhysicalDeviceImplementation { *of } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline PhysicalDeviceImplementation::~PhysicalDeviceImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline PhysicalDeviceImplementation::PhysicalDeviceImplementation(const PhysicalDeviceImplementation&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto PhysicalDeviceImplementation::operator=(const PhysicalDeviceImplementation& other) noexcept + -> PhysicalDeviceImplementation& { + if (&other == this) [[unlikely]] + return *this; + + GpuObjectViewImplementation::operator=(other); + + m_data = as_ref(other.m_data); + m_memory_types = other.m_memory_types; + m_queue_families = other.m_queue_families; + m_extensions = other.m_extensions; + m_format_properties = other.m_format_properties; + + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline PhysicalDeviceImplementation::PhysicalDeviceImplementation(PhysicalDeviceImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto PhysicalDeviceImplementation::operator=(PhysicalDeviceImplementation&&) noexcept + -> PhysicalDeviceImplementation& = default; + } // namespace view + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto PhysicalDeviceObject::instance() const noexcept -> view::Instance { + return Interface::owner().instance(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto PhysicalDeviceObject::physical_device() const noexcept -> view::PhysicalDevice { + return Interface::owner(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + inline auto format_as(view::PhysicalDevice physical_device, FormatContext& ctx) noexcept -> decltype(ctx.out()) { + const auto& info = physical_device.info(); + return std::format_to(ctx.out(), + "PhysicalDevice[name: {}, vendor: {}, id: {}, vulkan: {}.{}.{}, driver version: " + "{}.{}.{}]", + info.device_name, + info.vendor_name, + info.device_id, + info.api_major_version, + info.api_minor_version, + info.api_patch_version, + info.driver_major_version, + info.driver_minor_version, + info.driver_patch_version); + } +} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/core/instance.mpp b/modules/stormkit/gpu/core/instance.mpp deleted file mode 100644 index 4e63674a8..000000000 --- a/modules/stormkit/gpu/core/instance.mpp +++ /dev/null @@ -1,398 +0,0 @@ -// Copyright (C) 2023 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include -#include - -#include - -export module stormkit.gpu.core:instance; - -import std; - -import stormkit.core; -import stormkit.wsi; - -import :vulkan; -import :structs; -import :device; - -export { - namespace stormkit::gpu { - class PhysicalDevice; - - class STORMKIT_API Instance { - struct PrivateFuncTag {}; - - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::INSTANCE; - - [[nodiscard]] - static auto create(std::string app_name = "", - bool verbose = (STORMKIT_BUILD_TYPE == "DEBUG")) noexcept - -> Expected; - [[nodiscard]] - static auto allocate(std::string app_name = "", - bool verbose = (STORMKIT_BUILD_TYPE == "DEBUG")) noexcept - -> Expected>; - ~Instance(); - - Instance(const Instance&) = delete; - auto operator=(const Instance&) -> Instance& = delete; - - Instance(Instance&&) noexcept; - auto operator=(Instance&&) noexcept -> Instance&; - - [[nodiscard]] - auto physical_devices() const noexcept -> const std::vector&; - - [[nodiscard]] - auto native_handle() const noexcept -> VkInstance; - - constexpr Instance(std::string app_name, bool verbose, PrivateFuncTag) noexcept; - - private: - auto do_init() noexcept -> Expected; - auto do_load_instance() noexcept -> VulkanExpected; - auto do_init_debug_report_callback() noexcept -> VulkanExpected; - auto do_retrieve_physical_devices() noexcept -> VulkanExpected; - - std::string m_app_name; - bool m_validation_layers_enabled; - - std::vector m_extensions; - std::vector m_physical_devices; - - VkRAIIHandle m_vk_handle = { [](auto handle) static noexcept { - vkDestroyInstance(handle, nullptr); - } }; - VkRAIIHandle m_vk_debug_utils_handle = { - [](auto) static noexcept {} - }; - }; - - [[nodiscard]] - STORMKIT_API - auto score_physical_device(const PhysicalDevice& physical_device) noexcept -> u64; - - class STORMKIT_API PhysicalDevice { - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::PHYSICAL_DEVICE; - - ~PhysicalDevice(); - - PhysicalDevice(const PhysicalDevice&) = delete; - auto operator=(const PhysicalDevice&) -> PhysicalDevice& = delete; - - PhysicalDevice(PhysicalDevice&&) noexcept; - auto operator=(PhysicalDevice&&) noexcept -> PhysicalDevice&; - - [[nodiscard]] - auto check_extension_support(std::string_view extension) const noexcept -> bool; - [[nodiscard]] - auto check_extension_support(std::span extensions) - const noexcept -> bool; - [[nodiscard]] - auto check_extension_support(std::span extensions) const noexcept - -> bool; - - [[nodiscard]] - auto info() const noexcept -> const PhysicalDeviceInfo&; - [[nodiscard]] - auto capabilities() const noexcept -> const RenderCapabilities&; - [[nodiscard]] - auto memory_types() const noexcept -> const std::vector&; - - [[nodiscard]] - auto queue_families() const noexcept -> const std::vector&; - - [[nodiscard]] - auto extensions() const noexcept -> const std::vector&; - - [[nodiscard]] - auto formats_properties() const noexcept - -> const std::vector>&; - - [[nodiscard]] - auto native_handle() const noexcept -> VkPhysicalDevice; - - private: - explicit PhysicalDevice(VkPhysicalDevice physical_device) noexcept; - - PhysicalDeviceInfo m_device_info; - RenderCapabilities m_capabilities; - std::vector m_memory_types; - - std::vector m_queue_families; - std::vector m_extensions; - std::vector> m_format_properties; - - VkPhysicalDevice m_vk_handle = nullptr; - friend class Instance; - }; - - class STORMKIT_API Surface { - struct PrivateFuncTag {}; - - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::SURFACE; - - ~Surface(); - - Surface(const Surface&) = delete; - auto operator=(const Surface&) -> Surface& = delete; - - Surface(Surface&&) noexcept; - auto operator=(Surface&&) noexcept -> Surface&; - -#if false - [[nodiscard]] - static auto create_offscreen(const Instance& instance) noexcept -> Expected; - [[nodiscard]] - static auto allocate_offscreen(const Instance& instance) noexcept - -> Expected>; -#endif - - [[nodiscard]] - static auto create_from_window(const Instance& instance, - const wsi::Window& window) noexcept -> Expected; - [[nodiscard]] - static auto allocate_from_window(const Instance& instance, - const wsi::Window& window) noexcept - -> Expected>; - - [[nodiscard]] - auto native_handle() const noexcept -> VkSurfaceKHR; - - constexpr explicit Surface(PrivateFuncTag) noexcept; - - private: - auto do_init_offscreen(const Instance&) noexcept -> Expected; - auto do_init_from_window(const Instance&, const wsi::Window&) noexcept - -> Expected; - - VkInstance m_vk_instance = nullptr; - VkRAIIHandle m_vk_handle = { [](auto) static noexcept {} }; - }; - } // namespace stormkit::gpu - - namespace std { - template - struct formatter { - template - STORMKIT_FORCE_INLINE - constexpr auto parse(ParseContext& ctx) -> decltype(auto) { - return ctx.begin(); - } - - template - STORMKIT_FORCE_INLINE - auto format(const stormkit::gpu::PhysicalDevice& device, FormatContext& ctx) const - -> decltype(auto) { - auto&& out = ctx.out(); - const auto& info = device.info(); - return format_to(out, - "[name: {}, vendor: {}, id: {}, vulkan: {}.{}.{}, driver version: " - "{}.{}.{}]", - info.device_name, - info.vendor_name, - info.device_id, - info.api_major_version, - info.api_minor_version, - info.api_patch_version, - info.driver_major_version, - info.driver_minor_version, - info.driver_patch_version); - } - }; - } // namespace std -} - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::gpu { - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - constexpr Instance::Instance(std::string app_name, - bool enable_validation, - PrivateFuncTag) noexcept - : m_app_name { std::move(app_name) }, m_validation_layers_enabled { enable_validation } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Instance::create(std::string app_name, bool enable_validation) noexcept - -> Expected { - auto instance = Instance { std::move(app_name), enable_validation, PrivateFuncTag {} }; - return instance.do_init().transform(core::monadic::consume(instance)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Instance::allocate(std::string app_name, bool enable_validation) noexcept - -> Expected> { - auto instance = core::allocate_unsafe(std::move(app_name), - enable_validation, - PrivateFuncTag {}); - return instance->do_init().transform(core::monadic::consume(instance)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Instance::~Instance() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Instance::Instance(Instance&&) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Instance::operator=(Instance&&) noexcept -> Instance& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Instance::physical_devices() const noexcept -> const std::vector& { - return m_physical_devices; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Instance::native_handle() const noexcept -> VkInstance { - EXPECTS(m_vk_handle); - return m_vk_handle; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto PhysicalDevice::info() const noexcept -> const PhysicalDeviceInfo& { - return m_device_info; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto PhysicalDevice::capabilities() const noexcept -> const RenderCapabilities& { - return m_capabilities; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto PhysicalDevice::memory_types() const noexcept - -> const std::vector& { - return m_memory_types; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto PhysicalDevice::queue_families() const noexcept -> const std::vector& { - return m_queue_families; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto PhysicalDevice::extensions() const noexcept -> const std::vector& { - return m_extensions; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto PhysicalDevice::formats_properties() const noexcept - -> const std::vector>& { - return m_format_properties; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto PhysicalDevice::native_handle() const noexcept -> VkPhysicalDevice { - EXPECTS(m_vk_handle); - return m_vk_handle; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline constexpr Surface::Surface(PrivateFuncTag) noexcept { - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Surface::~Surface() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Surface::Surface(Surface&&) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Surface::operator=(Surface&&) noexcept -> Surface& = default; - -#if false - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Surface::create_offscreen(const Instance& instance) noexcept - -> Expected { - auto surface = Surface { PrivateFuncTag {} }; - return surface.do_init_offscreen(instance).transform(core::monadic::consume(instance)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Surface::allocate_offscreen(const Instance& instance) noexcept - -> Expected> { - auto surface = core::allocate_unsafe(PrivateFuncTag {}); - return surface->do_init_offscreen(instance).transform(core::monadic::consume(instance)); - } -#endif - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Surface::create_from_window(const Instance& instance, - const wsi::Window& window) noexcept - -> Expected { - auto surface = Surface { PrivateFuncTag {} }; - return surface.do_init_from_window(instance, window) - .transform(core::monadic::consume(surface)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Surface::allocate_from_window(const Instance& instance, - const wsi::Window& window) noexcept - -> Expected> { - auto surface = core::allocate_unsafe(PrivateFuncTag {}); - return surface->do_init_from_window(instance, window) - .transform(core::monadic::consume(surface)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Surface::native_handle() const noexcept -> VkSurfaceKHR { - EXPECTS(m_vk_handle); - return m_vk_handle; - } -} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/core/loader.mpp b/modules/stormkit/gpu/core/loader.cppm similarity index 64% rename from modules/stormkit/gpu/core/loader.mpp rename to modules/stormkit/gpu/core/loader.cppm index 3ade381d4..352f76930 100644 --- a/modules/stormkit/gpu/core/loader.mpp +++ b/modules/stormkit/gpu/core/loader.cppm @@ -1,12 +1,12 @@ module; -#include +#include export module stormkit.gpu.core:loader; import :structs; export namespace stormkit::gpu { - STORMKIT_API + STORMKIT_GPU_API auto initialize_backend() -> Expected; -} +} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/core/meta.cppm b/modules/stormkit/gpu/core/meta.cppm new file mode 100644 index 000000000..b306371e6 --- /dev/null +++ b/modules/stormkit/gpu/core/meta.cppm @@ -0,0 +1,78 @@ +// Copyright (C) 2023 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +export module stormkit.gpu.core:meta; + +import std; + +import stormkit.core; + +import :vulkan; + +namespace cmeta = stormkit::core::meta; + +namespace stormkit::gpu { + export namespace trait { + template + struct GpuObject; + }; + + namespace meta { + export { + template + concept GpuObjectHasTraitDefined = requires() { + trait::GpuObject {}; + typename trait::GpuObject::ValueType; + typename trait::GpuObject::DeleterType; + typename trait::GpuObject::ObjectType; + typename trait::GpuObject::ViewType; + + { trait::GpuObject::DEBUG_TYPE } -> cmeta::SameAs; + }; + + template + concept HasDoInitReturnType = GpuObjectHasTraitDefined and requires() { + typename trait::GpuObject::DoInitReturnType; + }; + + template + concept HasOwnerType = GpuObjectHasTraitDefined and requires() { typename trait::GpuObject::OwnerType; }; + + template + concept HasTagType = requires() { typename T::TagType; }; + } + + namespace details { + template + struct GpuObjectDoInitReturnType { + using Type = Expected; + }; + + template + struct GpuObjectDoInitReturnType { + using Type = typename trait::GpuObject>::DoInitReturnType; + }; + } // namespace details + + export { + template + using GpuObjectDoInitReturnType = details::GpuObjectDoInitReturnType::Type; + + template + concept IsGpuObject = HasTagType + and GpuObjectHasTraitDefined + and cmeta::SameAs::ObjectType>; + + template + concept IsGpuView = HasTagType + and GpuObjectHasTraitDefined + and cmeta::SameAs::ViewType>; + + template + concept IsGpuObjectOrView = IsGpuObject or IsGpuView; + } + } // namespace meta +} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/core/objects.cppm b/modules/stormkit/gpu/core/objects.cppm new file mode 100644 index 000000000..a80393cb4 --- /dev/null +++ b/modules/stormkit/gpu/core/objects.cppm @@ -0,0 +1,208 @@ +// Copyright (C) 2023 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +export module stormkit.gpu.core:objects; + +import std; + +import stormkit.core; + +import :vulkan; +import :base; + +namespace stormkit::gpu { + class InstanceImplementation; + class DebugCallbackImplementation; + class SurfaceImplementation; + class PhysicalDeviceImplementation; + class DeviceImplementation; + class FenceImplementation; + class SemaphoreImplementation; + + namespace view { + class InstanceImplementation; + class DebugCallbackImplementation; + class SurfaceImplementation; + class PhysicalDeviceImplementation; + class DeviceImplementation; + class FenceImplementation; + class SemaphoreImplementation; + } // namespace view + + export { + class InstanceTag; + template + class InstanceInterface; + + class DebugCallbackTag; + template + class DebugCallbackInterface; + + class SurfaceTag; + template + class SurfaceInterface; + + class PhysicalDeviceTag; + template + class PhysicalDeviceInterface; + + class DeviceTag; + template + class DeviceInterface; + + class FenceTag; + template + class FenceInterface; + + class SemaphoreTag; + template + class SemaphoreInterface; + + using Instance = InstanceInterface; + + namespace view { + using Instance = InstanceInterface; + } + + template + class InstanceObject: public Interface { + public: + using Interface::Interface; + using Interface::operator=; + using TagType = Interface::TagType; + + auto instance() const noexcept -> view::Instance; + }; + + using DebugCallback = DebugCallbackInterface; + using Surface = SurfaceInterface; + using PhysicalDevice = PhysicalDeviceInterface; + + namespace view { + using PhysicalDevice = PhysicalDeviceInterface; + using Surface = SurfaceInterface; + using DebugCallback = DebugCallbackInterface; + } // namespace view + + template + class PhysicalDeviceObject: public Interface { + public: + using Interface::Interface; + using Interface::operator=; + using TagType = Interface::TagType; + + auto instance() const noexcept -> view::Instance; + auto physical_device() const noexcept -> view::PhysicalDevice; + }; + + using Device = DeviceInterface; + + namespace view { + using Device = DeviceInterface; + } + + template + class DeviceObject: public Interface { + public: + using Interface::Interface; + using Interface::operator=; + using TagType = Interface::TagType; + + auto instance() const noexcept -> view::Instance; + auto physical_device() const noexcept -> view::PhysicalDevice; + auto device() const noexcept -> view::Device; + }; + + using Fence = FenceInterface; + using Semaphore = SemaphoreInterface; + + namespace view { + using Fence = FenceInterface; + using Semaphore = SemaphoreInterface; + } // namespace view + + namespace trait { + template<> + struct GpuObject { + using ValueType = VkInstance; + using DeleterType = PFN_vkDestroyInstance; + using ObjectType = Instance; + using ViewType = view::Instance; + + static constexpr auto DEBUG_TYPE = DebugObjectType::INSTANCE; + }; + + template<> + struct GpuObject { + using ValueType = VkDebugUtilsMessengerEXT; + using DeleterType = PFN_vkDestroyDebugUtilsMessengerEXT; + using ObjectType = DebugCallback; + using ViewType = view::DebugCallback; + using OwnerType = Instance; + + static constexpr auto DEBUG_TYPE = DebugObjectType::DEBUG_UTILS_MESSENGER; + }; + + template<> + struct GpuObject { + using ValueType = VkSurfaceKHR; + using DeleterType = PFN_vkDestroySurfaceKHR; + using ObjectType = Surface; + using ViewType = view::Surface; + using OwnerType = Instance; + + static constexpr auto DEBUG_TYPE = DebugObjectType::SURFACE; + }; + + template<> + struct GpuObject { + using ValueType = VkPhysicalDevice; + using DeleterType = decltype(monadic::noop()); + using DoInitReturnType = void; + using ObjectType = PhysicalDevice; + using ViewType = view::PhysicalDevice; + using OwnerType = Instance; + + static constexpr auto DEBUG_TYPE = DebugObjectType::PHYSICAL_DEVICE; + }; + + template<> + struct GpuObject { + using ValueType = VkDevice; + using DeleterType = PFN_vkDestroyDevice VolkDeviceTable::*; + using ObjectType = Device; + using ViewType = view::Device; + using OwnerType = PhysicalDevice; + + static constexpr auto DEBUG_TYPE = DebugObjectType::DEVICE; + }; + + template<> + struct GpuObject { + using ValueType = VkFence; + using DeleterType = PFN_vkDestroyFence VolkDeviceTable::*; + using ObjectType = Fence; + using ViewType = view::Fence; + using OwnerType = Device; + + static constexpr auto DEBUG_TYPE = DebugObjectType::FENCE; + }; + + template<> + struct GpuObject { + using ValueType = VkSemaphore; + using DeleterType = PFN_vkDestroySemaphore VolkDeviceTable::*; + using ObjectType = Semaphore; + using ViewType = view::Semaphore; + using OwnerType = Device; + + static constexpr auto DEBUG_TYPE = DebugObjectType::SEMAPHORE; + }; + } // namespace trait + } +} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/core/structs.mpp b/modules/stormkit/gpu/core/structs.cppm similarity index 74% rename from modules/stormkit/gpu/core/structs.mpp rename to modules/stormkit/gpu/core/structs.cppm index 1cbeaaf40..9fb9114fe 100644 --- a/modules/stormkit/gpu/core/structs.mpp +++ b/modules/stormkit/gpu/core/structs.cppm @@ -4,9 +4,7 @@ module; -#include #include -#include #include #include @@ -145,19 +143,19 @@ export { u32 max_fragment_dual_src_attachments; u32 max_fragment_combined_output_resources; u32 max_compute_shared_memory_size; - std::array max_compute_work_group_count; + array max_compute_work_group_count; u32 max_compute_work_group_invocations; - std::array max_compute_work_group_size; + array max_compute_work_group_size; std::optional sub_pixel_precision_bits; std::optional sub_texel_precision_bits; std::optional mipmap_precision_bits; u32 max_draw_indexed_index_value; std::optional max_draw_indirect_count; - float max_sampler_lod_bias; - float max_sampler_anisotropy; + f32 max_sampler_lod_bias; + f32 max_sampler_anisotropy; u32 max_viewports; - std::array max_viewport_dimensions; - std::array viewport_bounds_range; + array max_viewport_dimensions; + array viewport_bounds_range; std::optional viewport_sub_pixel_bits; std::optional min_memory_map_alignment; std::optional min_texel_buffer_offset_alignment; @@ -167,8 +165,8 @@ export { u32 max_texel_offset; i32 min_texel_gather_offset; u32 max_texel_gather_offset; - float min_interpolation_offset; - float max_interpolation_offset; + f32 min_interpolation_offset; + f32 max_interpolation_offset; std::optional sub_pixel_interpolation_offset_bits; u32 max_framebuffer_width; u32 max_framebuffer_height; @@ -185,15 +183,15 @@ export { SampleCountFlag storage_image_sample_counts; u32 max_sample_mask_words; bool timestamp_compute_and_engine; - float timestamp_period; + f32 timestamp_period; u32 max_clip_distances; u32 max_cull_distances; u32 max_combined_clip_and_cull_distances; u32 discrete_queue_priorities; - std::array point_size_range; - std::array line_width_range; - float point_size_granularity; - float line_width_granularity; + array point_size_range; + array line_width_range; + f32 point_size_granularity; + f32 line_width_granularity; bool strict_lines; bool standard_sample_locations; std::optional optimal_buffer_copy_offset_alignment; @@ -226,23 +224,34 @@ export { }; struct Viewport { - math::vec2f position; - math::Extent2 extent; - math::vec2f depth; + math::fvec2 position; + math::extent2 extent; + math::fvec2 depth; }; struct Scissor { - math::vec2i offset; - math::Extent2 extent; + math::ivec2 offset; + math::uextent2 extent; }; struct ClearColor { - RGBColorF color = stormkit::RGBColorDef::SILVER; + fcolor_rgba color = stormkit::colors::SILVER; + + constexpr auto operator==(const ClearColor& other) const noexcept -> bool; + }; + + struct ClearDepth { + f32 depth = 1.f; + constexpr auto operator==(const ClearDepth& other) const noexcept -> bool; }; - struct ClearDepthStencil { - float depth = 1.f; - u32 stencil = 0; + struct ClearStencil { + u32 stencil = 0u; + constexpr auto operator==(const ClearStencil& other) const noexcept -> bool; + }; + + struct ClearDepthStencil: ClearDepth, ClearStencil { + constexpr auto operator==(const ClearDepthStencil& other) const noexcept -> bool; }; using ClearValue = std::variant; @@ -254,16 +263,23 @@ export { ImageSubresourceLayers subresource_layers; - math::vec3i offset; - math::Extent3 extent; + math::ivec3 offset; + math::uextent3 extent; }; struct BlitRegion { ImageSubresourceLayers src; ImageSubresourceLayers dst; - std::array src_offset; - std::array dst_offset; + struct { + math::ivec3 position; + math::iextent3 extent; + } src_offset; + + struct { + math::ivec3 position; + math::iextent3 extent; + } dst_offset; }; struct PushConstantRange { @@ -273,10 +289,10 @@ export { }; struct PhysicalDeviceInfo { - u64 device_id; - std::string device_name; - u64 vendor_id; - std::string vendor_name; + u64 device_id; + string device_name; + u64 vendor_id; + string vendor_name; u32 api_major_version; u32 api_minor_version; @@ -286,7 +302,7 @@ export { u32 driver_minor_version; u32 driver_patch_version; - std::array pipeline_cache_uuid; + array pipeline_cache_uuid; PhysicalDeviceType type; }; @@ -303,18 +319,25 @@ export { using Expected = std::expected; [[nodiscard]] - constexpr auto compute_mip_level(const math::Extent2& extent) noexcept -> u32; + constexpr auto compute_mip_level(const math::uextent2& extent) noexcept -> u32; [[nodiscard]] - constexpr auto compute_uniform_buffer_offset_align(usize size, - const RenderCapabilities& - capabilities) noexcept -> usize; + constexpr auto compute_uniform_buffer_offset_align(usize size, const RenderCapabilities& capabilities) noexcept -> usize; [[nodiscard]] auto to_string(const PhysicalDeviceInfo& data) noexcept; - } // namespace stormkit::gpu - HASH_FUNC(stormkit::gpu::Viewport, value.position, value.extent, value.depth) - HASH_FUNC(stormkit::gpu::Scissor, value.offset, value.extent) + template + constexpr auto hasher(const Viewport& value) noexcept -> Ret; + + template + constexpr auto hasher(const Scissor& value) noexcept -> Ret; + + template + constexpr auto hasher(const ClearColor& value) noexcept -> Ret; + + template + constexpr auto hasher(const ClearDepthStencil& value) noexcept -> Ret; + } // namespace stormkit::gpu } //////////////////////////////////////////////////////////////////// @@ -325,7 +348,35 @@ namespace stormkit::gpu { ///////////////////////////////////// ///////////////////////////////////// STORMKIT_FORCE_INLINE - constexpr auto compute_mip_level(const math::Extent2& extent) noexcept -> u32 { + constexpr auto ClearColor::operator==(const ClearColor& other) const noexcept -> bool { + return color == other.color; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto ClearDepth::operator==(const ClearDepth& other) const noexcept -> bool { + return depth == other.depth; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto ClearStencil::operator==(const ClearStencil& other) const noexcept -> bool { + return stencil == other.stencil; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto ClearDepthStencil::operator==(const ClearDepthStencil& other) const noexcept -> bool { + return depth == other.depth and stencil == other.stencil; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto compute_mip_level(const math::uextent2& extent) noexcept -> u32 { const auto as_float = extent.to(); return as(math::floor(math::log2(math::max(as_float.width, as_float.height)))) + 1; } @@ -333,9 +384,7 @@ namespace stormkit::gpu { ///////////////////////////////////// ///////////////////////////////////// STORMKIT_FORCE_INLINE - constexpr auto compute_uniform_buffer_offset_align(usize size, - const RenderCapabilities& - capabilities) noexcept -> usize { + constexpr auto compute_uniform_buffer_offset_align(usize size, const RenderCapabilities& capabilities) noexcept -> usize { const auto min_ubo_align = capabilities.limits.min_uniform_buffer_offset_alignment; if (min_ubo_align > 0) size = (size + min_ubo_align - 1) & ~(min_ubo_align - 1); @@ -366,4 +415,33 @@ namespace stormkit::gpu { data.driver_patch_version, data.type); } + + ///////////////////////////////////// + ///////////////////////////////////// + template + constexpr auto hasher(const Viewport& value) noexcept -> Ret { + return hash(value.position, value.extent, value.depth); + } + + ///////////////////////////////////// + ///////////////////////////////////// + + template + constexpr auto hasher(const Scissor& value) noexcept -> Ret { + return hash(value.offset, value.extent); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + constexpr auto hasher(const ClearColor& value) noexcept -> Ret { + return hash(value.color); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + constexpr auto hasher(const ClearDepthStencil& value) noexcept -> Ret { + return hash(value.depth, value.stencil); + } } // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/core/surface.cppm b/modules/stormkit/gpu/core/surface.cppm new file mode 100644 index 000000000..bad263622 --- /dev/null +++ b/modules/stormkit/gpu/core/surface.cppm @@ -0,0 +1,156 @@ +// Copyright (C) 2023 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include +#include + +#include +#include + +export module stormkit.gpu.core:surface; + +import std; + +import stormkit.core; +import stormkit.wsi; + +import :vulkan; +import :base; + +import :structs; +import :objects; + +import :instance; + +namespace stormkit::gpu { + export { + struct SurfaceInterfaceBase { + struct OffscreenCreateInfo {}; + + struct CreateInfo { + ref window; + }; + }; + + template + class SurfaceInterface final: public InstanceObject { + public: + using InstanceObject::InstanceObject; + using InstanceObject::operator=; + using TagType = SurfaceTag; + }; + } + + class STORMKIT_GPU_API SurfaceImplementation + : public GpuObjectImplementation, + public core::NamedConstructor, + DoInitArgs> { + public: + using CreateInfo = SurfaceInterfaceBase::CreateInfo; + using OffscreenCreateInfo = SurfaceInterfaceBase::OffscreenCreateInfo; + using OffscreenNamedConstructor = core:: + NamedConstructor, DoInitArgs>; + + using OffscreenNamedConstructor::allocate; + using OffscreenNamedConstructor::create; + + SurfaceImplementation(PrivateTag, view::Instance&&) noexcept; + ~SurfaceImplementation() noexcept; + + SurfaceImplementation(const SurfaceImplementation&) noexcept = delete; + auto operator=(const SurfaceImplementation&) noexcept -> SurfaceImplementation& = delete; + + SurfaceImplementation(SurfaceImplementation&&) noexcept; + auto operator=(SurfaceImplementation&&) noexcept -> SurfaceImplementation&; + +#if false + [[nodiscard]] + static auto create_offscreen(view::Instance instance) noexcept + -> Expected; + [[nodiscard]] + static auto allocate_offscreen(view::Instance instance) noexcept + -> Expected>; +#endif + + [[nodiscard]] + static auto create_from_window(view::Instance instance, const wsi::Window& window) noexcept -> Expected; + [[nodiscard]] + static auto allocate_from_window(view::Instance instance, const wsi::Window& window) noexcept -> Expected>; + + auto do_init(PrivateTag, const CreateInfo&) noexcept -> Expected; + auto do_init(PrivateTag, const OffscreenCreateInfo&) noexcept -> Expected; + }; + + namespace view { + class SurfaceImplementation: public GpuObjectViewImplementation { + public: + using GpuObjectViewImplementation::GpuObjectViewImplementation; + using GpuObjectViewImplementation::operator=; + }; + } // namespace view +} // namespace stormkit::gpu + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit::gpu { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline SurfaceImplementation::SurfaceImplementation(PrivateTag, view::Instance&& instance) noexcept + : GpuObjectImplementation { std::move(instance), auto(vkDestroySurfaceKHR) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline SurfaceImplementation::~SurfaceImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline SurfaceImplementation::SurfaceImplementation(SurfaceImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto SurfaceImplementation::operator=(SurfaceImplementation&&) noexcept -> SurfaceImplementation& = default; + +#if false + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE inline auto SurfaceImplementation::create_offscreen(view::Instance instance) noexcept + -> Expected { + return OffScreenNamedConstructor::create(std::move(instance), OffscreenCreateInfo{}); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE inline auto SurfaceImplementation::allocate_offscreen(view::Instance instance) noexcept + -> Expected> { + return OffScreenNamedConstructor::allocate(std::move(instance), OffscreenCreateInfo{}); + } +#endif + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto SurfaceImplementation::create_from_window(view::Instance instance, const wsi::Window& window) noexcept + -> Expected { + return GpuObjectImplementation::create(std::move(instance), CreateInfo { as_ref(window) }); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto SurfaceImplementation::allocate_from_window(view::Instance instance, const wsi::Window& window) noexcept + -> Expected> { + return GpuObjectImplementation::allocate(std::move(instance), CreateInfo { as_ref(window) }); + } +} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/core/sync.cppm b/modules/stormkit/gpu/core/sync.cppm new file mode 100644 index 000000000..812f8e37b --- /dev/null +++ b/modules/stormkit/gpu/core/sync.cppm @@ -0,0 +1,167 @@ +// Copyright (C) 2023 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include +#include + +#include +#include + +export module stormkit.gpu.core:sync; + +import std; + +import stormkit.core; + +import :vulkan; +import :base; + +import :structs; +import :objects; + +import :instance; +import :device; + +namespace stormkit::gpu { + export { + struct FenceInterfaceBase { + struct CreateInfo { + bool signaled = false; + }; + + enum class Status { + SIGNALED, + UNSIGNALED, + }; + }; + + template + class STORMKIT_GPU_API FenceInterface final: public FenceInterfaceBase, public DeviceObject { + public: + using DeviceObject::DeviceObject; + using DeviceObject::operator=; + using TagType = FenceTag; + + using Status = FenceInterfaceBase::Status; + + auto status() const noexcept -> Expected; + auto wait(const std::chrono::milliseconds& wait_for = std::chrono::milliseconds::max()) const noexcept + -> Expected; + auto reset() const noexcept -> Expected; + }; + + template + class SemaphoreInterface final: public DeviceObject { + public: + using DeviceObject::DeviceObject; + using DeviceObject::operator=; + using TagType = SemaphoreTag; + }; + } + + class STORMKIT_GPU_API FenceImplementation: public GpuObjectImplementation { + public: + using CreateInfo = FenceInterfaceBase::CreateInfo; + + static auto create(view::Device device) noexcept -> Expected; + static auto allocate(view::Device device) noexcept -> Expected>; + static auto create_signaled(view::Device device) noexcept -> Expected; + static auto allocate_signaled(view::Device device) noexcept -> Expected>; + + FenceImplementation(PrivateTag, view::Device&&) noexcept; + + auto do_init(PrivateTag, const CreateInfo&) noexcept -> Expected; + }; + + namespace view { + class FenceImplementation: public GpuObjectViewImplementation { + public: + using GpuObjectViewImplementation::GpuObjectViewImplementation; + using GpuObjectViewImplementation::operator=; + }; + } // namespace view + + class STORMKIT_GPU_API SemaphoreImplementation: public GpuObjectImplementation { + public: + SemaphoreImplementation(PrivateTag, view::Device&&) noexcept; + + auto do_init(PrivateTag) noexcept -> Expected; + }; + + namespace view { + class SemaphoreImplementation: public GpuObjectViewImplementation { + public: + using GpuObjectViewImplementation::GpuObjectViewImplementation; + using GpuObjectViewImplementation::operator=; + }; + } // namespace view +} // namespace stormkit::gpu + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit::gpu { + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto DeviceInterface::wait_for_fence(view::Fence fence, const std::chrono::milliseconds& timeout) const noexcept + -> Expected { + return wait_for_fences(as_views(std::move(fence)), true, timeout); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto DeviceInterface::reset_fence(view::Fence fence) const noexcept -> Expected { + return reset_fences(as_views(std::move(fence))); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline FenceImplementation::FenceImplementation(PrivateTag, view::Device&& device) noexcept + : GpuObjectImplementation { std::move(device), &VolkDeviceTable::vkDestroyFence } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto FenceImplementation::create(view::Device device) noexcept -> Expected { + return NamedConstructor::create(std::move(device), {}); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto FenceImplementation::allocate(view::Device device) noexcept -> Expected> { + return NamedConstructor::allocate(std::move(device), {}); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto FenceImplementation::create_signaled(view::Device device) noexcept -> Expected { + return NamedConstructor::create(std::move(device), { true }); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto FenceImplementation::allocate_signaled(view::Device device) noexcept -> Expected> { + return NamedConstructor::allocate(std::move(device), { true }); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline SemaphoreImplementation::SemaphoreImplementation(PrivateTag, view::Device&& device) noexcept + : GpuObjectImplementation { std::move(device), &VolkDeviceTable::vkDestroySemaphore } { + } +} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/core/sync.mpp b/modules/stormkit/gpu/core/sync.mpp deleted file mode 100644 index 4ff9f5b92..000000000 --- a/modules/stormkit/gpu/core/sync.mpp +++ /dev/null @@ -1,305 +0,0 @@ -// Copyright (C) 2023 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include -#include - -#include - -export module stormkit.gpu.core:sync; - -import std; - -import stormkit.core; - -import :vulkan; -import :structs; -import :device; - -export namespace stormkit::gpu { - class Device; - - class STORMKIT_API Fence { - struct PrivateFuncTag {}; - - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::FENCE; - - enum class Status { - SIGNALED, - UNSIGNALED, - }; - - [[nodiscard]] - static auto create(const Device& device, bool signaled = false) noexcept -> Expected; - [[nodiscard]] - static auto create_signaled(const Device& device) noexcept -> Expected; - [[nodiscard]] - static auto allocate(const Device& device, bool signaled = false) noexcept - -> Expected>; - [[nodiscard]] - static auto allocate_signaled(const Device& device) noexcept -> Expected>; - ~Fence(); - - Fence(const Fence&) = delete; - auto operator=(const Fence&) -> Fence& = delete; - - Fence(Fence&&) noexcept; - auto operator=(Fence&&) noexcept -> Fence&; - - [[nodiscard]] - auto wait(const std::chrono::milliseconds& wait_for = std::chrono::milliseconds::max()) - const -> Expected; - auto reset() -> Expected; - - [[nodiscard]] - auto status() const noexcept -> Expected; - - [[nodiscard]] - auto native_handle() const noexcept -> VkFence; - - Fence(const Device&, PrivateFuncTag) noexcept; - - private: - auto do_init(bool) noexcept -> Expected; - - VkDevice m_vk_device = nullptr; - Ref m_vk_device_table; - VkRAIIHandle m_vk_handle; - }; - - class STORMKIT_API Semaphore { - struct PrivateFuncTag {}; - - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::SEMAPHORE; - - [[nodiscard]] - static auto create(const Device& device) noexcept -> Expected; - [[nodiscard]] - static auto allocate(const Device& device) noexcept -> Expected>; - ~Semaphore(); - - Semaphore(const Semaphore&) = delete; - auto operator=(const Semaphore&) -> Semaphore& = delete; - - Semaphore(Semaphore&&) noexcept; - auto operator=(Semaphore&&) noexcept -> Semaphore&; - - [[nodiscard]] - auto native_handle() const noexcept -> VkSemaphore; - - Semaphore(const Device&, PrivateFuncTag) noexcept; - - private: - auto do_init() noexcept -> Expected; - - VkDevice m_vk_device = nullptr; - Ref m_vk_device_table; - VkRAIIHandle m_vk_handle; - }; -} // namespace stormkit::gpu - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::gpu { - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Fence::Fence(const Device& device, PrivateFuncTag) noexcept - : m_vk_device { device.native_handle() }, - m_vk_device_table { as_ref(device.device_table()) }, - m_vk_handle { [vk_device_table = *m_vk_device_table, - vk_device = m_vk_device](auto handle) noexcept { - vk_device_table.vkDestroyFence(vk_device, handle, nullptr); - } } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Fence::create(const Device& device, bool signaled) noexcept -> Expected { - auto fence = Fence { device, PrivateFuncTag {} }; - return fence.do_init(signaled).transform(core::monadic::consume(fence)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Fence::create_signaled(const Device& device) noexcept -> Expected { - return create(device, true); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Fence::allocate(const Device& device, bool signaled) noexcept - -> Expected> { - auto fence = core::allocate_unsafe(device, PrivateFuncTag {}); - return fence->do_init(signaled).transform(core::monadic::consume(fence)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Fence::allocate_signaled(const Device& device) noexcept -> Expected> { - return allocate(device, true); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Fence::~Fence() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Fence::Fence(Fence&&) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Fence::operator=(Fence&&) noexcept -> Fence& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Fence::status() const noexcept -> Expected { - static constexpr auto POSSIBLE_RESULTS = std::array { VK_SUCCESS, VK_NOT_READY }; - return vk_call(m_vk_device_table->vkGetFenceStatus, - as_view(POSSIBLE_RESULTS), - m_vk_device, - m_vk_handle) - .transform([](auto&& result) static noexcept { - if (result == VK_NOT_READY) return Status::UNSIGNALED; - return Status::SIGNALED; - }) - .transform_error(monadic::from_vk()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Fence::wait(const std::chrono::milliseconds& wait_for) const -> Expected { - static constexpr auto POSSIBLE_RESULTS = std::array { VK_SUCCESS, VK_NOT_READY }; - return vk_call(m_vk_device_table->vkWaitForFences, - as_view(POSSIBLE_RESULTS), - m_vk_device, - 1u, - &m_vk_handle.value(), - true, - std::chrono::duration_cast(wait_for) - .count()) - .transform(monadic::from_vk()) - .transform_error(monadic::from_vk()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Fence::reset() -> Expected { - return vk_call(m_vk_device_table->vkResetFences, m_vk_device, 1u, &m_vk_handle.value()) - .transform_error(monadic::from_vk()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Fence::native_handle() const noexcept -> VkFence { - EXPECTS(m_vk_handle); - return m_vk_handle; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Fence::do_init(bool signaled) noexcept -> Expected { - const auto flags = (signaled) ? VkFenceCreateFlags { VK_FENCE_CREATE_SIGNALED_BIT } - : VkFenceCreateFlags {}; - - const auto create_info = VkFenceCreateInfo { .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, - .pNext = nullptr, - .flags = flags }; - - return vk_call(m_vk_device_table->vkCreateFence, - m_vk_device, - &create_info, - nullptr) - .transform(core::monadic::set(m_vk_handle)) - .transform_error(monadic::from_vk()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Semaphore::Semaphore(const Device& device, PrivateFuncTag) noexcept - : m_vk_device { device.native_handle() }, - m_vk_device_table { as_ref(device.device_table()) }, - m_vk_handle { [vk_device_table = *m_vk_device_table, - vk_device = m_vk_device](auto handle) noexcept { - vk_device_table.vkDestroySemaphore(vk_device, handle, nullptr); - } } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Semaphore::create(const Device& device) noexcept -> Expected { - auto semaphore = Semaphore { device, PrivateFuncTag {} }; - return semaphore.do_init().transform(core::monadic::consume(semaphore)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Semaphore::allocate(const Device& device) noexcept -> Expected> { - auto semaphore = core::allocate_unsafe(device, PrivateFuncTag {}); - return semaphore->do_init().transform(core::monadic::consume(semaphore)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Semaphore::~Semaphore() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Semaphore::Semaphore(Semaphore&&) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Semaphore::operator=(Semaphore&&) noexcept -> Semaphore& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Semaphore::native_handle() const noexcept -> VkSemaphore { - EXPECTS(m_vk_handle); - return m_vk_handle; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Semaphore::do_init() noexcept -> Expected { - const auto create_info = VkSemaphoreCreateInfo { - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - }; - - return vk_call(m_vk_device_table->vkCreateSemaphore, - m_vk_device, - &create_info, - nullptr) - .transform(core::monadic::set(m_vk_handle)) - .transform_error(monadic::from_vk()); - } -} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/core/vulkan.mpp b/modules/stormkit/gpu/core/vulkan.cppm similarity index 100% rename from modules/stormkit/gpu/core/vulkan.mpp rename to modules/stormkit/gpu/core/vulkan.cppm diff --git a/modules/stormkit/gpu/core/vulkan/enums.mpp b/modules/stormkit/gpu/core/vulkan/enums.cppm similarity index 66% rename from modules/stormkit/gpu/core/vulkan/enums.mpp rename to modules/stormkit/gpu/core/vulkan/enums.cppm index 79348add0..03a28278c 100644 --- a/modules/stormkit/gpu/core/vulkan/enums.mpp +++ b/modules/stormkit/gpu/core/vulkan/enums.cppm @@ -7,12 +7,14 @@ module; #include #include +#include #include export module stormkit.gpu.core:vulkan.enums; import std; import stormkit.core; +import stormkit.image; import :vulkan.volk; @@ -25,8 +27,7 @@ export { namespace meta { template - concept IsVulkanEnumeration = core::meta::IsEnumeration - and details::IS_VULKAN_ENUMERATION; + concept IsVulkanEnumeration = core::meta::IsEnumeration and details::IS_VULKAN_ENUMERATION; } inline constexpr auto QUEUE_FAMILY_IGNORED = std::numeric_limits::max(); @@ -208,6 +209,7 @@ export { COMMAND_BUFFER = VK_OBJECT_TYPE_COMMAND_BUFFER, COMMAND_POOL = VK_OBJECT_TYPE_COMMAND_POOL, DEBUG_REPORT_CALLBACK = VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT, + DEBUG_UTILS_MESSENGER = VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT, DESCRIPTOR_POOL = VK_OBJECT_TYPE_DESCRIPTOR_POOL, DESCRIPTOR_SET = VK_OBJECT_TYPE_DESCRIPTOR_SET, DESCRIPTOR_SET_LAYOUT = VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, @@ -305,8 +307,7 @@ export { = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT, SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT, - SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER - = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT, + SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT, SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER = VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT, STORAGE_IMAGE = VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT, @@ -377,21 +378,20 @@ export { inline constexpr auto details::IS_VULKAN_ENUMERATION = true; enum class ImageLayout : u32 { - COLOR_ATTACHMENT_OPTIMAL = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL - = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, - DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL - = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, - DEPTH_STENCIL_ATTACHMENT_OPTIMAL = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - DEPTH_STENCIL_READ_ONLY_OPTIMAL = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, - GENERAL = VK_IMAGE_LAYOUT_GENERAL, - PREINITIALIZED = VK_IMAGE_LAYOUT_PREINITIALIZED, - PRESENT_SRC = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, - SHADER_READ_ONLY_OPTIMAL = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - SHARED_PRESENT = VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR, - TRANSFER_DST_OPTIMAL = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - TRANSFER_SRC_OPTIMAL = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - UNDEFINED = VK_IMAGE_LAYOUT_UNDEFINED, + ATTACHMENT_OPTIMAL = VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, + COLOR_ATTACHMENT_OPTIMAL = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, + DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, + DEPTH_STENCIL_ATTACHMENT_OPTIMAL = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + DEPTH_STENCIL_READ_ONLY_OPTIMAL = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, + GENERAL = VK_IMAGE_LAYOUT_GENERAL, + PREINITIALIZED = VK_IMAGE_LAYOUT_PREINITIALIZED, + PRESENT_SRC = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + SHADER_READ_ONLY_OPTIMAL = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + SHARED_PRESENT = VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR, + TRANSFER_DST_OPTIMAL = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + TRANSFER_SRC_OPTIMAL = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + UNDEFINED = VK_IMAGE_LAYOUT_UNDEFINED, }; template<> @@ -580,6 +580,7 @@ export { RGBA8_SNORM = VK_FORMAT_R8G8B8A8_SNORM, RGBA8U = VK_FORMAT_R8G8B8A8_UINT, RGBA8_UNORM = VK_FORMAT_R8G8B8A8_UNORM, + S8U = VK_FORMAT_S8_UINT, SBGR8 = VK_FORMAT_B8G8R8_SRGB, SBGRA8 = VK_FORMAT_B8G8R8A8_SRGB, SR8 = VK_FORMAT_R8_SRGB, @@ -637,6 +638,18 @@ export { template<> inline constexpr auto details::IS_VULKAN_ENUMERATION = true; + enum class ResolveModeFlag : u8 { + AVERAGE = VK_RESOLVE_MODE_AVERAGE_BIT, + EXTERNAL_FORMAT_DOWNSAMPLE_ANDROID = VK_RESOLVE_MODE_EXTERNAL_FORMAT_DOWNSAMPLE_ANDROID, + MAX = VK_RESOLVE_MODE_MAX_BIT, + MIN = VK_RESOLVE_MODE_MIN_BIT, + NONE = VK_RESOLVE_MODE_NONE, + SAMPLE_ZERO = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT, + }; + + template<> + inline constexpr auto details::IS_VULKAN_ENUMERATION = true; + enum class Result : i32 { ERROR_DEVICE_LOST = VK_ERROR_DEVICE_LOST, ERROR_EXTENSION_NOT_PRESENT = VK_ERROR_EXTENSION_NOT_PRESENT, @@ -739,22 +752,31 @@ export { template<> inline constexpr auto details::IS_VULKAN_ENUMERATION = true; - template - requires(core::meta::IsPlainEnumeration or core::meta::Is) - [[nodiscard]] - constexpr auto to_vk(U value) noexcept -> T; + namespace vk { + template + requires(core::meta::IsPlainEnumeration or core::meta::Is) + [[nodiscard]] + constexpr auto to_vk(U value) noexcept -> T; + + template + requires(core::meta::IsPlainEnumeration or core::meta::Is) + [[nodiscard]] + constexpr auto from_vk(U value) noexcept -> T; + } // namespace vk - template - requires(core::meta::IsPlainEnumeration or core::meta::Is) [[nodiscard]] - constexpr auto from_vk(U value) noexcept -> T; + constexpr auto from_image(image::Image::Format format) -> PixelFormat; [[nodiscard]] constexpr auto is_depth_only_format(PixelFormat format) noexcept -> bool; [[nodiscard]] + constexpr auto is_stencil_only_format(PixelFormat format) noexcept -> bool; + [[nodiscard]] constexpr auto is_depth_stencil_format(PixelFormat format) noexcept -> bool; [[nodiscard]] constexpr auto is_depth_format(PixelFormat format) noexcept -> bool; + [[nodiscard]] + constexpr auto is_stencil_format(PixelFormat format) noexcept -> bool; [[nodiscard]] constexpr auto get_format_channel_count(PixelFormat format) noexcept -> u8; @@ -766,9 +788,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::AccessFlag::COLOR_ATTACHMENT_READ, stormkit::gpu::AccessFlag::COLOR_ATTACHMENT_WRITE, stormkit::gpu::AccessFlag::DEPTH_STENCIL_ATTACHMENT_READ, @@ -793,24 +814,16 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string(stormkit::gpu::AccessFlag - value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::AccessFlag value) noexcept -> string_view { switch (value) { - case stormkit::gpu::AccessFlag::COLOR_ATTACHMENT_READ: - return "AccessFlag::COLOR_ATTACHMENT_READ"; - case stormkit::gpu::AccessFlag::COLOR_ATTACHMENT_WRITE: - return "AccessFlag::COLOR_ATTACHMENT_WRITE"; - case stormkit::gpu::AccessFlag::DEPTH_STENCIL_ATTACHMENT_READ: - return "AccessFlag::DEPTH_STENCIL_ATTACHMENT_READ"; - case stormkit::gpu::AccessFlag::DEPTH_STENCIL_ATTACHMENT_WRITE: - return "AccessFlag::DEPTH_STENCIL_ATTACHMENT_WRITE"; + case stormkit::gpu::AccessFlag::COLOR_ATTACHMENT_READ: return "AccessFlag::COLOR_ATTACHMENT_READ"; + case stormkit::gpu::AccessFlag::COLOR_ATTACHMENT_WRITE: return "AccessFlag::COLOR_ATTACHMENT_WRITE"; + case stormkit::gpu::AccessFlag::DEPTH_STENCIL_ATTACHMENT_READ: return "AccessFlag::DEPTH_STENCIL_ATTACHMENT_READ"; + case stormkit::gpu::AccessFlag::DEPTH_STENCIL_ATTACHMENT_WRITE: return "AccessFlag::DEPTH_STENCIL_ATTACHMENT_WRITE"; case stormkit::gpu::AccessFlag::HOST_READ: return "AccessFlag::HOST_READ"; case stormkit::gpu::AccessFlag::HOST_WRITE: return "AccessFlag::HOST_WRITE"; - case stormkit::gpu::AccessFlag::INDIRECT_COMMAND_READ: - return "AccessFlag::INDIRECT_COMMAND_READ"; - case stormkit::gpu::AccessFlag::INPUT_ATTACHMENT_READ: - return "AccessFlag::INPUT_ATTACHMENT_READ"; + case stormkit::gpu::AccessFlag::INDIRECT_COMMAND_READ: return "AccessFlag::INDIRECT_COMMAND_READ"; + case stormkit::gpu::AccessFlag::INPUT_ATTACHMENT_READ: return "AccessFlag::INPUT_ATTACHMENT_READ"; case stormkit::gpu::AccessFlag::MEMORY_READ: return "AccessFlag::MEMORY_READ"; case stormkit::gpu::AccessFlag::MEMORY_WRITE: return "AccessFlag::MEMORY_WRITE"; case stormkit::gpu::AccessFlag::NONE: return "AccessFlag::NONE"; @@ -819,33 +832,23 @@ export { case stormkit::gpu::AccessFlag::TRANSFER_READ: return "AccessFlag::TRANSFER_READ"; case stormkit::gpu::AccessFlag::TRANSFER_WRITE: return "AccessFlag::TRANSFER_WRITE"; case stormkit::gpu::AccessFlag::UNIFORM_READ: return "AccessFlag::UNIFORM_READ"; - case stormkit::gpu::AccessFlag::VERTEX_ATTRIBUTE_READ: - return "AccessFlag::VERTEX_ATTRIBUTE_READ"; + case stormkit::gpu::AccessFlag::VERTEX_ATTRIBUTE_READ: return "AccessFlag::VERTEX_ATTRIBUTE_READ"; } std::unreachable(); } template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string(stormkit::gpu::AccessFlag - value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::AccessFlag value) noexcept -> string { switch (value) { - case stormkit::gpu::AccessFlag::COLOR_ATTACHMENT_READ: - return "AccessFlag::COLOR_ATTACHMENT_READ"; - case stormkit::gpu::AccessFlag::COLOR_ATTACHMENT_WRITE: - return "AccessFlag::COLOR_ATTACHMENT_WRITE"; - case stormkit::gpu::AccessFlag::DEPTH_STENCIL_ATTACHMENT_READ: - return "AccessFlag::DEPTH_STENCIL_ATTACHMENT_READ"; - case stormkit::gpu::AccessFlag::DEPTH_STENCIL_ATTACHMENT_WRITE: - return "AccessFlag::DEPTH_STENCIL_ATTACHMENT_WRITE"; + case stormkit::gpu::AccessFlag::COLOR_ATTACHMENT_READ: return "AccessFlag::COLOR_ATTACHMENT_READ"; + case stormkit::gpu::AccessFlag::COLOR_ATTACHMENT_WRITE: return "AccessFlag::COLOR_ATTACHMENT_WRITE"; + case stormkit::gpu::AccessFlag::DEPTH_STENCIL_ATTACHMENT_READ: return "AccessFlag::DEPTH_STENCIL_ATTACHMENT_READ"; + case stormkit::gpu::AccessFlag::DEPTH_STENCIL_ATTACHMENT_WRITE: return "AccessFlag::DEPTH_STENCIL_ATTACHMENT_WRITE"; case stormkit::gpu::AccessFlag::HOST_READ: return "AccessFlag::HOST_READ"; case stormkit::gpu::AccessFlag::HOST_WRITE: return "AccessFlag::HOST_WRITE"; - case stormkit::gpu::AccessFlag::INDIRECT_COMMAND_READ: - return "AccessFlag::INDIRECT_COMMAND_READ"; - case stormkit::gpu::AccessFlag::INPUT_ATTACHMENT_READ: - return "AccessFlag::INPUT_ATTACHMENT_READ"; + case stormkit::gpu::AccessFlag::INDIRECT_COMMAND_READ: return "AccessFlag::INDIRECT_COMMAND_READ"; + case stormkit::gpu::AccessFlag::INPUT_ATTACHMENT_READ: return "AccessFlag::INPUT_ATTACHMENT_READ"; case stormkit::gpu::AccessFlag::MEMORY_READ: return "AccessFlag::MEMORY_READ"; case stormkit::gpu::AccessFlag::MEMORY_WRITE: return "AccessFlag::MEMORY_WRITE"; case stormkit::gpu::AccessFlag::NONE: return "AccessFlag::NONE"; @@ -854,8 +857,7 @@ export { case stormkit::gpu::AccessFlag::TRANSFER_READ: return "AccessFlag::TRANSFER_READ"; case stormkit::gpu::AccessFlag::TRANSFER_WRITE: return "AccessFlag::TRANSFER_WRITE"; case stormkit::gpu::AccessFlag::UNIFORM_READ: return "AccessFlag::UNIFORM_READ"; - case stormkit::gpu::AccessFlag::VERTEX_ATTRIBUTE_READ: - return "AccessFlag::VERTEX_ATTRIBUTE_READ"; + case stormkit::gpu::AccessFlag::VERTEX_ATTRIBUTE_READ: return "AccessFlag::VERTEX_ATTRIBUTE_READ"; } std::unreachable(); } @@ -864,9 +866,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate< - stormkit::gpu::AttachmentLoadOperation>() noexcept -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::AttachmentLoadOperation::CLEAR, stormkit::gpu::AttachmentLoadOperation::DONT_CARE, stormkit::gpu::AttachmentLoadOperation::LOAD, @@ -875,35 +876,25 @@ export { } template<> - STORMKIT_FORCE_INLINE - STORMKIT_CONST + STORMKIT_FORCE_INLINE STORMKIT_CONST constexpr auto stormkit::core::as_string< - stormkit::gpu::AttachmentLoadOperation>(stormkit::gpu::AttachmentLoadOperation value) noexcept - -> std::string_view { + stormkit::gpu::AttachmentLoadOperation>(stormkit::gpu::AttachmentLoadOperation value) noexcept -> string_view { switch (value) { - case stormkit::gpu::AttachmentLoadOperation::CLEAR: - return "AttachmentLoadOperation::CLEAR"; - case stormkit::gpu::AttachmentLoadOperation::DONT_CARE: - return "AttachmentLoadOperation::DONT_CARE"; - case stormkit::gpu::AttachmentLoadOperation::LOAD: - return "AttachmentLoadOperation::LOAD"; + case stormkit::gpu::AttachmentLoadOperation::CLEAR: return "AttachmentLoadOperation::CLEAR"; + case stormkit::gpu::AttachmentLoadOperation::DONT_CARE: return "AttachmentLoadOperation::DONT_CARE"; + case stormkit::gpu::AttachmentLoadOperation::LOAD: return "AttachmentLoadOperation::LOAD"; } std::unreachable(); } template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST constexpr auto stormkit::core::to_string< - stormkit::gpu::AttachmentLoadOperation>(stormkit::gpu::AttachmentLoadOperation value) noexcept - -> std::string { + stormkit::gpu::AttachmentLoadOperation>(stormkit::gpu::AttachmentLoadOperation value) noexcept -> string { switch (value) { - case stormkit::gpu::AttachmentLoadOperation::CLEAR: - return "AttachmentLoadOperation::CLEAR"; - case stormkit::gpu::AttachmentLoadOperation::DONT_CARE: - return "AttachmentLoadOperation::DONT_CARE"; - case stormkit::gpu::AttachmentLoadOperation::LOAD: - return "AttachmentLoadOperation::LOAD"; + case stormkit::gpu::AttachmentLoadOperation::CLEAR: return "AttachmentLoadOperation::CLEAR"; + case stormkit::gpu::AttachmentLoadOperation::DONT_CARE: return "AttachmentLoadOperation::DONT_CARE"; + case stormkit::gpu::AttachmentLoadOperation::LOAD: return "AttachmentLoadOperation::LOAD"; } std::unreachable(); } @@ -912,9 +903,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate< - stormkit::gpu::AttachmentStoreOperation>() noexcept -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::AttachmentStoreOperation::DONT_CARE, stormkit::gpu::AttachmentStoreOperation::STORE, @@ -922,31 +912,23 @@ export { } template<> - STORMKIT_FORCE_INLINE - STORMKIT_CONST + STORMKIT_FORCE_INLINE STORMKIT_CONST constexpr auto stormkit::core::as_string< - stormkit::gpu::AttachmentStoreOperation>(stormkit::gpu::AttachmentStoreOperation - value) noexcept -> std::string_view { + stormkit::gpu::AttachmentStoreOperation>(stormkit::gpu::AttachmentStoreOperation value) noexcept -> string_view { switch (value) { - case stormkit::gpu::AttachmentStoreOperation::DONT_CARE: - return "AttachmentStoreOperation::DONT_CARE"; - case stormkit::gpu::AttachmentStoreOperation::STORE: - return "AttachmentStoreOperation::STORE"; + case stormkit::gpu::AttachmentStoreOperation::DONT_CARE: return "AttachmentStoreOperation::DONT_CARE"; + case stormkit::gpu::AttachmentStoreOperation::STORE: return "AttachmentStoreOperation::STORE"; } std::unreachable(); } template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST constexpr auto stormkit::core::to_string< - stormkit::gpu::AttachmentStoreOperation>(stormkit::gpu::AttachmentStoreOperation - value) noexcept -> std::string { + stormkit::gpu::AttachmentStoreOperation>(stormkit::gpu::AttachmentStoreOperation value) noexcept -> string { switch (value) { - case stormkit::gpu::AttachmentStoreOperation::DONT_CARE: - return "AttachmentStoreOperation::DONT_CARE"; - case stormkit::gpu::AttachmentStoreOperation::STORE: - return "AttachmentStoreOperation::STORE"; + case stormkit::gpu::AttachmentStoreOperation::DONT_CARE: return "AttachmentStoreOperation::DONT_CARE"; + case stormkit::gpu::AttachmentStoreOperation::STORE: return "AttachmentStoreOperation::STORE"; } std::unreachable(); } @@ -955,9 +937,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::BlendFactor::CONSTANT_ALPHA, stormkit::gpu::BlendFactor::CONSTANT_COLOR, stormkit::gpu::BlendFactor::DST_ALPHA, @@ -984,36 +965,26 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string(stormkit::gpu::BlendFactor - value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::BlendFactor value) noexcept + -> string_view { switch (value) { case stormkit::gpu::BlendFactor::CONSTANT_ALPHA: return "BlendFactor::CONSTANT_ALPHA"; case stormkit::gpu::BlendFactor::CONSTANT_COLOR: return "BlendFactor::CONSTANT_COLOR"; case stormkit::gpu::BlendFactor::DST_ALPHA: return "BlendFactor::DST_ALPHA"; case stormkit::gpu::BlendFactor::DST_COLOR: return "BlendFactor::DST_COLOR"; case stormkit::gpu::BlendFactor::ONE: return "BlendFactor::ONE"; - case stormkit::gpu::BlendFactor::ONE_MINUS_CONSTANT_ALPHA: - return "BlendFactor::ONE_MINUS_CONSTANT_ALPHA"; - case stormkit::gpu::BlendFactor::ONE_MINUS_CONSTANT_COLOR: - return "BlendFactor::ONE_MINUS_CONSTANT_COLOR"; - case stormkit::gpu::BlendFactor::ONE_MINUS_DST_ALPHA: - return "BlendFactor::ONE_MINUS_DST_ALPHA"; - case stormkit::gpu::BlendFactor::ONE_MINUS_DST_COLOR: - return "BlendFactor::ONE_MINUS_DST_COLOR"; - case stormkit::gpu::BlendFactor::ONE_MINUS_SRC1_ALPHA: - return "BlendFactor::ONE_MINUS_SRC1_ALPHA"; - case stormkit::gpu::BlendFactor::ONE_MINUS_SRC1_COLOR: - return "BlendFactor::ONE_MINUS_SRC1_COLOR"; - case stormkit::gpu::BlendFactor::ONE_MINUS_SRC_ALPHA: - return "BlendFactor::ONE_MINUS_SRC_ALPHA"; - case stormkit::gpu::BlendFactor::ONE_MINUS_SRC_COLOR: - return "BlendFactor::ONE_MINUS_SRC_COLOR"; + case stormkit::gpu::BlendFactor::ONE_MINUS_CONSTANT_ALPHA: return "BlendFactor::ONE_MINUS_CONSTANT_ALPHA"; + case stormkit::gpu::BlendFactor::ONE_MINUS_CONSTANT_COLOR: return "BlendFactor::ONE_MINUS_CONSTANT_COLOR"; + case stormkit::gpu::BlendFactor::ONE_MINUS_DST_ALPHA: return "BlendFactor::ONE_MINUS_DST_ALPHA"; + case stormkit::gpu::BlendFactor::ONE_MINUS_DST_COLOR: return "BlendFactor::ONE_MINUS_DST_COLOR"; + case stormkit::gpu::BlendFactor::ONE_MINUS_SRC1_ALPHA: return "BlendFactor::ONE_MINUS_SRC1_ALPHA"; + case stormkit::gpu::BlendFactor::ONE_MINUS_SRC1_COLOR: return "BlendFactor::ONE_MINUS_SRC1_COLOR"; + case stormkit::gpu::BlendFactor::ONE_MINUS_SRC_ALPHA: return "BlendFactor::ONE_MINUS_SRC_ALPHA"; + case stormkit::gpu::BlendFactor::ONE_MINUS_SRC_COLOR: return "BlendFactor::ONE_MINUS_SRC_COLOR"; case stormkit::gpu::BlendFactor::SRC1_ALPHA: return "BlendFactor::SRC1_ALPHA"; case stormkit::gpu::BlendFactor::SRC1_COLOR: return "BlendFactor::SRC1_COLOR"; case stormkit::gpu::BlendFactor::SRC_ALPHA: return "BlendFactor::SRC_ALPHA"; - case stormkit::gpu::BlendFactor::SRC_ALPHA_SATURATE: - return "BlendFactor::SRC_ALPHA_SATURATE"; + case stormkit::gpu::BlendFactor::SRC_ALPHA_SATURATE: return "BlendFactor::SRC_ALPHA_SATURATE"; case stormkit::gpu::BlendFactor::SRC_COLOR: return "BlendFactor::SRC_COLOR"; case stormkit::gpu::BlendFactor::ZERO: return "BlendFactor::ZERO"; } @@ -1022,37 +993,25 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string(stormkit::gpu::BlendFactor - value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::BlendFactor value) noexcept -> string { switch (value) { case stormkit::gpu::BlendFactor::CONSTANT_ALPHA: return "BlendFactor::CONSTANT_ALPHA"; case stormkit::gpu::BlendFactor::CONSTANT_COLOR: return "BlendFactor::CONSTANT_COLOR"; case stormkit::gpu::BlendFactor::DST_ALPHA: return "BlendFactor::DST_ALPHA"; case stormkit::gpu::BlendFactor::DST_COLOR: return "BlendFactor::DST_COLOR"; case stormkit::gpu::BlendFactor::ONE: return "BlendFactor::ONE"; - case stormkit::gpu::BlendFactor::ONE_MINUS_CONSTANT_ALPHA: - return "BlendFactor::ONE_MINUS_CONSTANT_ALPHA"; - case stormkit::gpu::BlendFactor::ONE_MINUS_CONSTANT_COLOR: - return "BlendFactor::ONE_MINUS_CONSTANT_COLOR"; - case stormkit::gpu::BlendFactor::ONE_MINUS_DST_ALPHA: - return "BlendFactor::ONE_MINUS_DST_ALPHA"; - case stormkit::gpu::BlendFactor::ONE_MINUS_DST_COLOR: - return "BlendFactor::ONE_MINUS_DST_COLOR"; - case stormkit::gpu::BlendFactor::ONE_MINUS_SRC1_ALPHA: - return "BlendFactor::ONE_MINUS_SRC1_ALPHA"; - case stormkit::gpu::BlendFactor::ONE_MINUS_SRC1_COLOR: - return "BlendFactor::ONE_MINUS_SRC1_COLOR"; - case stormkit::gpu::BlendFactor::ONE_MINUS_SRC_ALPHA: - return "BlendFactor::ONE_MINUS_SRC_ALPHA"; - case stormkit::gpu::BlendFactor::ONE_MINUS_SRC_COLOR: - return "BlendFactor::ONE_MINUS_SRC_COLOR"; + case stormkit::gpu::BlendFactor::ONE_MINUS_CONSTANT_ALPHA: return "BlendFactor::ONE_MINUS_CONSTANT_ALPHA"; + case stormkit::gpu::BlendFactor::ONE_MINUS_CONSTANT_COLOR: return "BlendFactor::ONE_MINUS_CONSTANT_COLOR"; + case stormkit::gpu::BlendFactor::ONE_MINUS_DST_ALPHA: return "BlendFactor::ONE_MINUS_DST_ALPHA"; + case stormkit::gpu::BlendFactor::ONE_MINUS_DST_COLOR: return "BlendFactor::ONE_MINUS_DST_COLOR"; + case stormkit::gpu::BlendFactor::ONE_MINUS_SRC1_ALPHA: return "BlendFactor::ONE_MINUS_SRC1_ALPHA"; + case stormkit::gpu::BlendFactor::ONE_MINUS_SRC1_COLOR: return "BlendFactor::ONE_MINUS_SRC1_COLOR"; + case stormkit::gpu::BlendFactor::ONE_MINUS_SRC_ALPHA: return "BlendFactor::ONE_MINUS_SRC_ALPHA"; + case stormkit::gpu::BlendFactor::ONE_MINUS_SRC_COLOR: return "BlendFactor::ONE_MINUS_SRC_COLOR"; case stormkit::gpu::BlendFactor::SRC1_ALPHA: return "BlendFactor::SRC1_ALPHA"; case stormkit::gpu::BlendFactor::SRC1_COLOR: return "BlendFactor::SRC1_COLOR"; case stormkit::gpu::BlendFactor::SRC_ALPHA: return "BlendFactor::SRC_ALPHA"; - case stormkit::gpu::BlendFactor::SRC_ALPHA_SATURATE: - return "BlendFactor::SRC_ALPHA_SATURATE"; + case stormkit::gpu::BlendFactor::SRC_ALPHA_SATURATE: return "BlendFactor::SRC_ALPHA_SATURATE"; case stormkit::gpu::BlendFactor::SRC_COLOR: return "BlendFactor::SRC_COLOR"; case stormkit::gpu::BlendFactor::ZERO: return "BlendFactor::ZERO"; } @@ -1063,13 +1022,10 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { - stormkit::gpu::BlendOperation::ADD, - stormkit::gpu::BlendOperation::MAX, - stormkit::gpu::BlendOperation::MIN, - stormkit::gpu::BlendOperation::REVERSE_SUBTRACT, + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { + stormkit::gpu::BlendOperation::ADD, stormkit::gpu::BlendOperation::MAX, + stormkit::gpu::BlendOperation::MIN, stormkit::gpu::BlendOperation::REVERSE_SUBTRACT, stormkit::gpu::BlendOperation::SUBTRACT, }; @@ -1078,15 +1034,13 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string< - stormkit::gpu::BlendOperation>(stormkit::gpu::BlendOperation value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::BlendOperation value) noexcept + -> string_view { switch (value) { case stormkit::gpu::BlendOperation::ADD: return "BlendOperation::ADD"; case stormkit::gpu::BlendOperation::MAX: return "BlendOperation::MAX"; case stormkit::gpu::BlendOperation::MIN: return "BlendOperation::MIN"; - case stormkit::gpu::BlendOperation::REVERSE_SUBTRACT: - return "BlendOperation::REVERSE_SUBTRACT"; + case stormkit::gpu::BlendOperation::REVERSE_SUBTRACT: return "BlendOperation::REVERSE_SUBTRACT"; case stormkit::gpu::BlendOperation::SUBTRACT: return "BlendOperation::SUBTRACT"; } std::unreachable(); @@ -1094,15 +1048,13 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string< - stormkit::gpu::BlendOperation>(stormkit::gpu::BlendOperation value) noexcept -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::BlendOperation value) noexcept + -> string { switch (value) { case stormkit::gpu::BlendOperation::ADD: return "BlendOperation::ADD"; case stormkit::gpu::BlendOperation::MAX: return "BlendOperation::MAX"; case stormkit::gpu::BlendOperation::MIN: return "BlendOperation::MIN"; - case stormkit::gpu::BlendOperation::REVERSE_SUBTRACT: - return "BlendOperation::REVERSE_SUBTRACT"; + case stormkit::gpu::BlendOperation::REVERSE_SUBTRACT: return "BlendOperation::REVERSE_SUBTRACT"; case stormkit::gpu::BlendOperation::SUBTRACT: return "BlendOperation::SUBTRACT"; } std::unreachable(); @@ -1112,15 +1064,11 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { - stormkit::gpu::BorderColor::FLOAT_OPAQUE_BLACK, - stormkit::gpu::BorderColor::FLOAT_OPAQUE_WHITE, - stormkit::gpu::BorderColor::FLOAT_TRANSPARENT_BLACK, - stormkit::gpu::BorderColor::INT_OPAQUE_BLACK, - stormkit::gpu::BorderColor::INT_OPAQUE_WHITE, - stormkit::gpu::BorderColor::INT_TRANSPARENT_BLACK, + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { + stormkit::gpu::BorderColor::FLOAT_OPAQUE_BLACK, stormkit::gpu::BorderColor::FLOAT_OPAQUE_WHITE, + stormkit::gpu::BorderColor::FLOAT_TRANSPARENT_BLACK, stormkit::gpu::BorderColor::INT_OPAQUE_BLACK, + stormkit::gpu::BorderColor::INT_OPAQUE_WHITE, stormkit::gpu::BorderColor::INT_TRANSPARENT_BLACK, }; } @@ -1128,45 +1076,29 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string(stormkit::gpu::BorderColor - value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::BorderColor value) noexcept + -> string_view { switch (value) { - case stormkit::gpu::BorderColor::FLOAT_OPAQUE_BLACK: - return "BorderColor::FLOAT_OPAQUE_BLACK"; - case stormkit::gpu::BorderColor::FLOAT_OPAQUE_WHITE: - return "BorderColor::FLOAT_OPAQUE_WHITE"; - case stormkit::gpu::BorderColor::FLOAT_TRANSPARENT_BLACK: - return "BorderColor::FLOAT_TRANSPARENT_BLACK"; - case stormkit::gpu::BorderColor::INT_OPAQUE_BLACK: - return "BorderColor::INT_OPAQUE_BLACK"; - case stormkit::gpu::BorderColor::INT_OPAQUE_WHITE: - return "BorderColor::INT_OPAQUE_WHITE"; - case stormkit::gpu::BorderColor::INT_TRANSPARENT_BLACK: - return "BorderColor::INT_TRANSPARENT_BLACK"; + case stormkit::gpu::BorderColor::FLOAT_OPAQUE_BLACK: return "BorderColor::FLOAT_OPAQUE_BLACK"; + case stormkit::gpu::BorderColor::FLOAT_OPAQUE_WHITE: return "BorderColor::FLOAT_OPAQUE_WHITE"; + case stormkit::gpu::BorderColor::FLOAT_TRANSPARENT_BLACK: return "BorderColor::FLOAT_TRANSPARENT_BLACK"; + case stormkit::gpu::BorderColor::INT_OPAQUE_BLACK: return "BorderColor::INT_OPAQUE_BLACK"; + case stormkit::gpu::BorderColor::INT_OPAQUE_WHITE: return "BorderColor::INT_OPAQUE_WHITE"; + case stormkit::gpu::BorderColor::INT_TRANSPARENT_BLACK: return "BorderColor::INT_TRANSPARENT_BLACK"; } std::unreachable(); } template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string(stormkit::gpu::BorderColor - value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::BorderColor value) noexcept -> string { switch (value) { - case stormkit::gpu::BorderColor::FLOAT_OPAQUE_BLACK: - return "BorderColor::FLOAT_OPAQUE_BLACK"; - case stormkit::gpu::BorderColor::FLOAT_OPAQUE_WHITE: - return "BorderColor::FLOAT_OPAQUE_WHITE"; - case stormkit::gpu::BorderColor::FLOAT_TRANSPARENT_BLACK: - return "BorderColor::FLOAT_TRANSPARENT_BLACK"; - case stormkit::gpu::BorderColor::INT_OPAQUE_BLACK: - return "BorderColor::INT_OPAQUE_BLACK"; - case stormkit::gpu::BorderColor::INT_OPAQUE_WHITE: - return "BorderColor::INT_OPAQUE_WHITE"; - case stormkit::gpu::BorderColor::INT_TRANSPARENT_BLACK: - return "BorderColor::INT_TRANSPARENT_BLACK"; + case stormkit::gpu::BorderColor::FLOAT_OPAQUE_BLACK: return "BorderColor::FLOAT_OPAQUE_BLACK"; + case stormkit::gpu::BorderColor::FLOAT_OPAQUE_WHITE: return "BorderColor::FLOAT_OPAQUE_WHITE"; + case stormkit::gpu::BorderColor::FLOAT_TRANSPARENT_BLACK: return "BorderColor::FLOAT_TRANSPARENT_BLACK"; + case stormkit::gpu::BorderColor::INT_OPAQUE_BLACK: return "BorderColor::INT_OPAQUE_BLACK"; + case stormkit::gpu::BorderColor::INT_OPAQUE_WHITE: return "BorderColor::INT_OPAQUE_WHITE"; + case stormkit::gpu::BorderColor::INT_TRANSPARENT_BLACK: return "BorderColor::INT_TRANSPARENT_BLACK"; } std::unreachable(); } @@ -1175,17 +1107,12 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { - stormkit::gpu::BufferUsageFlag::INDEX, - stormkit::gpu::BufferUsageFlag::INDIRECT, - stormkit::gpu::BufferUsageFlag::STORAGE, - stormkit::gpu::BufferUsageFlag::STORAGE_TEXEL, - stormkit::gpu::BufferUsageFlag::TRANSFER_DST, - stormkit::gpu::BufferUsageFlag::TRANSFER_SRC, - stormkit::gpu::BufferUsageFlag::UNIFORM, - stormkit::gpu::BufferUsageFlag::UNIFORM_TEXEL, + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { + stormkit::gpu::BufferUsageFlag::INDEX, stormkit::gpu::BufferUsageFlag::INDIRECT, + stormkit::gpu::BufferUsageFlag::STORAGE, stormkit::gpu::BufferUsageFlag::STORAGE_TEXEL, + stormkit::gpu::BufferUsageFlag::TRANSFER_DST, stormkit::gpu::BufferUsageFlag::TRANSFER_SRC, + stormkit::gpu::BufferUsageFlag::UNIFORM, stormkit::gpu::BufferUsageFlag::UNIFORM_TEXEL, stormkit::gpu::BufferUsageFlag::VERTEX, }; @@ -1194,22 +1121,17 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string< - stormkit::gpu::BufferUsageFlag>(stormkit::gpu::BufferUsageFlag value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::BufferUsageFlag value) noexcept + -> string_view { switch (value) { case stormkit::gpu::BufferUsageFlag::INDEX: return "BufferUsageFlag::INDEX"; case stormkit::gpu::BufferUsageFlag::INDIRECT: return "BufferUsageFlag::INDIRECT"; case stormkit::gpu::BufferUsageFlag::STORAGE: return "BufferUsageFlag::STORAGE"; - case stormkit::gpu::BufferUsageFlag::STORAGE_TEXEL: - return "BufferUsageFlag::STORAGE_TEXEL"; - case stormkit::gpu::BufferUsageFlag::TRANSFER_DST: - return "BufferUsageFlag::TRANSFER_DST"; - case stormkit::gpu::BufferUsageFlag::TRANSFER_SRC: - return "BufferUsageFlag::TRANSFER_SRC"; + case stormkit::gpu::BufferUsageFlag::STORAGE_TEXEL: return "BufferUsageFlag::STORAGE_TEXEL"; + case stormkit::gpu::BufferUsageFlag::TRANSFER_DST: return "BufferUsageFlag::TRANSFER_DST"; + case stormkit::gpu::BufferUsageFlag::TRANSFER_SRC: return "BufferUsageFlag::TRANSFER_SRC"; case stormkit::gpu::BufferUsageFlag::UNIFORM: return "BufferUsageFlag::UNIFORM"; - case stormkit::gpu::BufferUsageFlag::UNIFORM_TEXEL: - return "BufferUsageFlag::UNIFORM_TEXEL"; + case stormkit::gpu::BufferUsageFlag::UNIFORM_TEXEL: return "BufferUsageFlag::UNIFORM_TEXEL"; case stormkit::gpu::BufferUsageFlag::VERTEX: return "BufferUsageFlag::VERTEX"; } std::unreachable(); @@ -1217,23 +1139,17 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string< - stormkit::gpu::BufferUsageFlag>(stormkit::gpu::BufferUsageFlag value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::BufferUsageFlag value) noexcept + -> string { switch (value) { case stormkit::gpu::BufferUsageFlag::INDEX: return "BufferUsageFlag::INDEX"; case stormkit::gpu::BufferUsageFlag::INDIRECT: return "BufferUsageFlag::INDIRECT"; case stormkit::gpu::BufferUsageFlag::STORAGE: return "BufferUsageFlag::STORAGE"; - case stormkit::gpu::BufferUsageFlag::STORAGE_TEXEL: - return "BufferUsageFlag::STORAGE_TEXEL"; - case stormkit::gpu::BufferUsageFlag::TRANSFER_DST: - return "BufferUsageFlag::TRANSFER_DST"; - case stormkit::gpu::BufferUsageFlag::TRANSFER_SRC: - return "BufferUsageFlag::TRANSFER_SRC"; + case stormkit::gpu::BufferUsageFlag::STORAGE_TEXEL: return "BufferUsageFlag::STORAGE_TEXEL"; + case stormkit::gpu::BufferUsageFlag::TRANSFER_DST: return "BufferUsageFlag::TRANSFER_DST"; + case stormkit::gpu::BufferUsageFlag::TRANSFER_SRC: return "BufferUsageFlag::TRANSFER_SRC"; case stormkit::gpu::BufferUsageFlag::UNIFORM: return "BufferUsageFlag::UNIFORM"; - case stormkit::gpu::BufferUsageFlag::UNIFORM_TEXEL: - return "BufferUsageFlag::UNIFORM_TEXEL"; + case stormkit::gpu::BufferUsageFlag::UNIFORM_TEXEL: return "BufferUsageFlag::UNIFORM_TEXEL"; case stormkit::gpu::BufferUsageFlag::VERTEX: return "BufferUsageFlag::VERTEX"; } std::unreachable(); @@ -1243,9 +1159,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::ColorComponentFlag::A, stormkit::gpu::ColorComponentFlag::B, stormkit::gpu::ColorComponentFlag::G, stormkit::gpu::ColorComponentFlag::NONE, stormkit::gpu::ColorComponentFlag::R, stormkit::gpu::ColorComponentFlag::RG, @@ -1257,9 +1172,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string< - stormkit::gpu::ColorComponentFlag>(stormkit::gpu::ColorComponentFlag value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::ColorComponentFlag value) noexcept + -> string_view { switch (value) { case stormkit::gpu::ColorComponentFlag::A: return "ColorComponentFlag::A"; case stormkit::gpu::ColorComponentFlag::B: return "ColorComponentFlag::B"; @@ -1275,10 +1189,8 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string< - stormkit::gpu::ColorComponentFlag>(stormkit::gpu::ColorComponentFlag value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::ColorComponentFlag value) noexcept + -> string { switch (value) { case stormkit::gpu::ColorComponentFlag::A: return "ColorComponentFlag::A"; case stormkit::gpu::ColorComponentFlag::B: return "ColorComponentFlag::B"; @@ -1296,9 +1208,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::ColorSpace::ADOBERGB_LINEAR, stormkit::gpu::ColorSpace::ADOBERGB_NONLINEAR, stormkit::gpu::ColorSpace::BT2020_LINEAR, @@ -1322,28 +1233,20 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string(stormkit::gpu::ColorSpace - value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::ColorSpace value) noexcept -> string_view { switch (value) { case stormkit::gpu::ColorSpace::ADOBERGB_LINEAR: return "ColorSpace::ADOBERGB_LINEAR"; - case stormkit::gpu::ColorSpace::ADOBERGB_NONLINEAR: - return "ColorSpace::ADOBERGB_NONLINEAR"; + case stormkit::gpu::ColorSpace::ADOBERGB_NONLINEAR: return "ColorSpace::ADOBERGB_NONLINEAR"; case stormkit::gpu::ColorSpace::BT2020_LINEAR: return "ColorSpace::BT2020_LINEAR"; case stormkit::gpu::ColorSpace::BT709_LINEAR: return "ColorSpace::BT709_LINEAR"; case stormkit::gpu::ColorSpace::BT709_NONLINEAR: return "ColorSpace::BT709_NONLINEAR"; case stormkit::gpu::ColorSpace::DCI_P3_NONLINEAR: return "ColorSpace::DCI_P3_NONLINEAR"; - case stormkit::gpu::ColorSpace::DISPLAY_NATIVE_AMD: - return "ColorSpace::DISPLAY_NATIVE_AMD"; - case stormkit::gpu::ColorSpace::DISPLAY_P3_LINEAR: - return "ColorSpace::DISPLAY_P3_LINEAR"; - case stormkit::gpu::ColorSpace::DISPLAY_P3_NONLINEAR: - return "ColorSpace::DISPLAY_P3_NONLINEAR"; + case stormkit::gpu::ColorSpace::DISPLAY_NATIVE_AMD: return "ColorSpace::DISPLAY_NATIVE_AMD"; + case stormkit::gpu::ColorSpace::DISPLAY_P3_LINEAR: return "ColorSpace::DISPLAY_P3_LINEAR"; + case stormkit::gpu::ColorSpace::DISPLAY_P3_NONLINEAR: return "ColorSpace::DISPLAY_P3_NONLINEAR"; case stormkit::gpu::ColorSpace::DOLBYVISION: return "ColorSpace::DOLBYVISION"; - case stormkit::gpu::ColorSpace::EXTENDED_SRGB_LINEAR: - return "ColorSpace::EXTENDED_SRGB_LINEAR"; - case stormkit::gpu::ColorSpace::EXTENDED_SRGB_NONLINEAR: - return "ColorSpace::EXTENDED_SRGB_NONLINEAR"; + case stormkit::gpu::ColorSpace::EXTENDED_SRGB_LINEAR: return "ColorSpace::EXTENDED_SRGB_LINEAR"; + case stormkit::gpu::ColorSpace::EXTENDED_SRGB_NONLINEAR: return "ColorSpace::EXTENDED_SRGB_NONLINEAR"; case stormkit::gpu::ColorSpace::HDR10_HLG: return "ColorSpace::HDR10_HLG"; case stormkit::gpu::ColorSpace::HDR10_ST2084: return "ColorSpace::HDR10_ST2084"; case stormkit::gpu::ColorSpace::PASS_THROUGH: return "ColorSpace::PASS_THROUGH"; @@ -1354,29 +1257,20 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string(stormkit::gpu::ColorSpace - value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::ColorSpace value) noexcept -> string { switch (value) { case stormkit::gpu::ColorSpace::ADOBERGB_LINEAR: return "ColorSpace::ADOBERGB_LINEAR"; - case stormkit::gpu::ColorSpace::ADOBERGB_NONLINEAR: - return "ColorSpace::ADOBERGB_NONLINEAR"; + case stormkit::gpu::ColorSpace::ADOBERGB_NONLINEAR: return "ColorSpace::ADOBERGB_NONLINEAR"; case stormkit::gpu::ColorSpace::BT2020_LINEAR: return "ColorSpace::BT2020_LINEAR"; case stormkit::gpu::ColorSpace::BT709_LINEAR: return "ColorSpace::BT709_LINEAR"; case stormkit::gpu::ColorSpace::BT709_NONLINEAR: return "ColorSpace::BT709_NONLINEAR"; case stormkit::gpu::ColorSpace::DCI_P3_NONLINEAR: return "ColorSpace::DCI_P3_NONLINEAR"; - case stormkit::gpu::ColorSpace::DISPLAY_NATIVE_AMD: - return "ColorSpace::DISPLAY_NATIVE_AMD"; - case stormkit::gpu::ColorSpace::DISPLAY_P3_LINEAR: - return "ColorSpace::DISPLAY_P3_LINEAR"; - case stormkit::gpu::ColorSpace::DISPLAY_P3_NONLINEAR: - return "ColorSpace::DISPLAY_P3_NONLINEAR"; + case stormkit::gpu::ColorSpace::DISPLAY_NATIVE_AMD: return "ColorSpace::DISPLAY_NATIVE_AMD"; + case stormkit::gpu::ColorSpace::DISPLAY_P3_LINEAR: return "ColorSpace::DISPLAY_P3_LINEAR"; + case stormkit::gpu::ColorSpace::DISPLAY_P3_NONLINEAR: return "ColorSpace::DISPLAY_P3_NONLINEAR"; case stormkit::gpu::ColorSpace::DOLBYVISION: return "ColorSpace::DOLBYVISION"; - case stormkit::gpu::ColorSpace::EXTENDED_SRGB_LINEAR: - return "ColorSpace::EXTENDED_SRGB_LINEAR"; - case stormkit::gpu::ColorSpace::EXTENDED_SRGB_NONLINEAR: - return "ColorSpace::EXTENDED_SRGB_NONLINEAR"; + case stormkit::gpu::ColorSpace::EXTENDED_SRGB_LINEAR: return "ColorSpace::EXTENDED_SRGB_LINEAR"; + case stormkit::gpu::ColorSpace::EXTENDED_SRGB_NONLINEAR: return "ColorSpace::EXTENDED_SRGB_NONLINEAR"; case stormkit::gpu::ColorSpace::HDR10_HLG: return "ColorSpace::HDR10_HLG"; case stormkit::gpu::ColorSpace::HDR10_ST2084: return "ColorSpace::HDR10_ST2084"; case stormkit::gpu::ColorSpace::PASS_THROUGH: return "ColorSpace::PASS_THROUGH"; @@ -1389,9 +1283,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::CommandBufferLevel::PRIMARY, stormkit::gpu::CommandBufferLevel::SECONDARY, @@ -1401,27 +1294,22 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string< - stormkit::gpu::CommandBufferLevel>(stormkit::gpu::CommandBufferLevel value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::CommandBufferLevel value) noexcept + -> string_view { switch (value) { case stormkit::gpu::CommandBufferLevel::PRIMARY: return "CommandBufferLevel::PRIMARY"; - case stormkit::gpu::CommandBufferLevel::SECONDARY: - return "CommandBufferLevel::SECONDARY"; + case stormkit::gpu::CommandBufferLevel::SECONDARY: return "CommandBufferLevel::SECONDARY"; } std::unreachable(); } template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string< - stormkit::gpu::CommandBufferLevel>(stormkit::gpu::CommandBufferLevel value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::CommandBufferLevel value) noexcept + -> string { switch (value) { case stormkit::gpu::CommandBufferLevel::PRIMARY: return "CommandBufferLevel::PRIMARY"; - case stormkit::gpu::CommandBufferLevel::SECONDARY: - return "CommandBufferLevel::SECONDARY"; + case stormkit::gpu::CommandBufferLevel::SECONDARY: return "CommandBufferLevel::SECONDARY"; } std::unreachable(); } @@ -1430,17 +1318,12 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { - stormkit::gpu::CompareOperation::ALWAYS, - stormkit::gpu::CompareOperation::EQUAL, - stormkit::gpu::CompareOperation::GREATER, - stormkit::gpu::CompareOperation::GREATER_OR_EQUAL, - stormkit::gpu::CompareOperation::LESS, - stormkit::gpu::CompareOperation::LESS_OR_EQUAL, - stormkit::gpu::CompareOperation::NEVER, - stormkit::gpu::CompareOperation::NOT_EQUAL, + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { + stormkit::gpu::CompareOperation::ALWAYS, stormkit::gpu::CompareOperation::EQUAL, + stormkit::gpu::CompareOperation::GREATER, stormkit::gpu::CompareOperation::GREATER_OR_EQUAL, + stormkit::gpu::CompareOperation::LESS, stormkit::gpu::CompareOperation::LESS_OR_EQUAL, + stormkit::gpu::CompareOperation::NEVER, stormkit::gpu::CompareOperation::NOT_EQUAL, }; } @@ -1448,18 +1331,15 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string< - stormkit::gpu::CompareOperation>(stormkit::gpu::CompareOperation value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::CompareOperation value) noexcept + -> string_view { switch (value) { case stormkit::gpu::CompareOperation::ALWAYS: return "CompareOperation::ALWAYS"; case stormkit::gpu::CompareOperation::EQUAL: return "CompareOperation::EQUAL"; case stormkit::gpu::CompareOperation::GREATER: return "CompareOperation::GREATER"; - case stormkit::gpu::CompareOperation::GREATER_OR_EQUAL: - return "CompareOperation::GREATER_OR_EQUAL"; + case stormkit::gpu::CompareOperation::GREATER_OR_EQUAL: return "CompareOperation::GREATER_OR_EQUAL"; case stormkit::gpu::CompareOperation::LESS: return "CompareOperation::LESS"; - case stormkit::gpu::CompareOperation::LESS_OR_EQUAL: - return "CompareOperation::LESS_OR_EQUAL"; + case stormkit::gpu::CompareOperation::LESS_OR_EQUAL: return "CompareOperation::LESS_OR_EQUAL"; case stormkit::gpu::CompareOperation::NEVER: return "CompareOperation::NEVER"; case stormkit::gpu::CompareOperation::NOT_EQUAL: return "CompareOperation::NOT_EQUAL"; } @@ -1468,19 +1348,15 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string< - stormkit::gpu::CompareOperation>(stormkit::gpu::CompareOperation value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::CompareOperation value) noexcept + -> string { switch (value) { case stormkit::gpu::CompareOperation::ALWAYS: return "CompareOperation::ALWAYS"; case stormkit::gpu::CompareOperation::EQUAL: return "CompareOperation::EQUAL"; case stormkit::gpu::CompareOperation::GREATER: return "CompareOperation::GREATER"; - case stormkit::gpu::CompareOperation::GREATER_OR_EQUAL: - return "CompareOperation::GREATER_OR_EQUAL"; + case stormkit::gpu::CompareOperation::GREATER_OR_EQUAL: return "CompareOperation::GREATER_OR_EQUAL"; case stormkit::gpu::CompareOperation::LESS: return "CompareOperation::LESS"; - case stormkit::gpu::CompareOperation::LESS_OR_EQUAL: - return "CompareOperation::LESS_OR_EQUAL"; + case stormkit::gpu::CompareOperation::LESS_OR_EQUAL: return "CompareOperation::LESS_OR_EQUAL"; case stormkit::gpu::CompareOperation::NEVER: return "CompareOperation::NEVER"; case stormkit::gpu::CompareOperation::NOT_EQUAL: return "CompareOperation::NOT_EQUAL"; } @@ -1491,9 +1367,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::CullModeFlag::BACK, stormkit::gpu::CullModeFlag::FRONT, stormkit::gpu::CullModeFlag::FRONT_BACK, @@ -1505,8 +1380,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string< - stormkit::gpu::CullModeFlag>(stormkit::gpu::CullModeFlag value) noexcept -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::CullModeFlag value) noexcept + -> string_view { switch (value) { case stormkit::gpu::CullModeFlag::BACK: return "CullModeFlag::BACK"; case stormkit::gpu::CullModeFlag::FRONT: return "CullModeFlag::FRONT"; @@ -1518,9 +1393,7 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string< - stormkit::gpu::CullModeFlag>(stormkit::gpu::CullModeFlag value) noexcept -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::CullModeFlag value) noexcept -> string { switch (value) { case stormkit::gpu::CullModeFlag::BACK: return "CullModeFlag::BACK"; case stormkit::gpu::CullModeFlag::FRONT: return "CullModeFlag::FRONT"; @@ -1534,14 +1407,14 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::DebugObjectType::BUFFER, stormkit::gpu::DebugObjectType::BUFFER_VIEW, stormkit::gpu::DebugObjectType::COMMAND_BUFFER, stormkit::gpu::DebugObjectType::COMMAND_POOL, stormkit::gpu::DebugObjectType::DEBUG_REPORT_CALLBACK, + stormkit::gpu::DebugObjectType::DEBUG_UTILS_MESSENGER, stormkit::gpu::DebugObjectType::DESCRIPTOR_POOL, stormkit::gpu::DebugObjectType::DESCRIPTOR_SET, stormkit::gpu::DebugObjectType::DESCRIPTOR_SET_LAYOUT, @@ -1574,27 +1447,20 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string< - stormkit::gpu::DebugObjectType>(stormkit::gpu::DebugObjectType value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::DebugObjectType value) noexcept + -> string_view { switch (value) { case stormkit::gpu::DebugObjectType::BUFFER: return "DebugObjectType::BUFFER"; case stormkit::gpu::DebugObjectType::BUFFER_VIEW: return "DebugObjectType::BUFFER_VIEW"; - case stormkit::gpu::DebugObjectType::COMMAND_BUFFER: - return "DebugObjectType::COMMAND_BUFFER"; - case stormkit::gpu::DebugObjectType::COMMAND_POOL: - return "DebugObjectType::COMMAND_POOL"; - case stormkit::gpu::DebugObjectType::DEBUG_REPORT_CALLBACK: - return "DebugObjectType::DEBUG_REPORT_CALLBACK"; - case stormkit::gpu::DebugObjectType::DESCRIPTOR_POOL: - return "DebugObjectType::DESCRIPTOR_POOL"; - case stormkit::gpu::DebugObjectType::DESCRIPTOR_SET: - return "DebugObjectType::DESCRIPTOR_SET"; - case stormkit::gpu::DebugObjectType::DESCRIPTOR_SET_LAYOUT: - return "DebugObjectType::DESCRIPTOR_SET_LAYOUT"; + case stormkit::gpu::DebugObjectType::COMMAND_BUFFER: return "DebugObjectType::COMMAND_BUFFER"; + case stormkit::gpu::DebugObjectType::COMMAND_POOL: return "DebugObjectType::COMMAND_POOL"; + case stormkit::gpu::DebugObjectType::DEBUG_REPORT_CALLBACK: return "DebugObjectType::DEBUG_REPORT_CALLBACK"; + case stormkit::gpu::DebugObjectType::DEBUG_UTILS_MESSENGER: return "DebugObjectType::DEBUG_UTILS_MESSENGER"; + case stormkit::gpu::DebugObjectType::DESCRIPTOR_POOL: return "DebugObjectType::DESCRIPTOR_POOL"; + case stormkit::gpu::DebugObjectType::DESCRIPTOR_SET: return "DebugObjectType::DESCRIPTOR_SET"; + case stormkit::gpu::DebugObjectType::DESCRIPTOR_SET_LAYOUT: return "DebugObjectType::DESCRIPTOR_SET_LAYOUT"; case stormkit::gpu::DebugObjectType::DEVICE: return "DebugObjectType::DEVICE"; - case stormkit::gpu::DebugObjectType::DEVICE_MEMORY: - return "DebugObjectType::DEVICE_MEMORY"; + case stormkit::gpu::DebugObjectType::DEVICE_MEMORY: return "DebugObjectType::DEVICE_MEMORY"; case stormkit::gpu::DebugObjectType::DISPLAY: return "DebugObjectType::DISPLAY"; case stormkit::gpu::DebugObjectType::EVENT: return "DebugObjectType::EVENT"; case stormkit::gpu::DebugObjectType::FENCE: return "DebugObjectType::FENCE"; @@ -1602,20 +1468,16 @@ export { case stormkit::gpu::DebugObjectType::IMAGE: return "DebugObjectType::IMAGE"; case stormkit::gpu::DebugObjectType::IMAGE_VIEW: return "DebugObjectType::IMAGE_VIEW"; case stormkit::gpu::DebugObjectType::INSTANCE: return "DebugObjectType::INSTANCE"; - case stormkit::gpu::DebugObjectType::PHYSICAL_DEVICE: - return "DebugObjectType::PHYSICAL_DEVICE"; + case stormkit::gpu::DebugObjectType::PHYSICAL_DEVICE: return "DebugObjectType::PHYSICAL_DEVICE"; case stormkit::gpu::DebugObjectType::PIPELINE: return "DebugObjectType::PIPELINE"; - case stormkit::gpu::DebugObjectType::PIPELINE_CACHE: - return "DebugObjectType::PIPELINE_CACHE"; - case stormkit::gpu::DebugObjectType::PIPELINE_LAYOUT: - return "DebugObjectType::PIPELINE_LAYOUT"; + case stormkit::gpu::DebugObjectType::PIPELINE_CACHE: return "DebugObjectType::PIPELINE_CACHE"; + case stormkit::gpu::DebugObjectType::PIPELINE_LAYOUT: return "DebugObjectType::PIPELINE_LAYOUT"; case stormkit::gpu::DebugObjectType::QUERY_POOL: return "DebugObjectType::QUERY_POOL"; case stormkit::gpu::DebugObjectType::QUEUE: return "DebugObjectType::QUEUE"; case stormkit::gpu::DebugObjectType::RENDER_PASS: return "DebugObjectType::RENDER_PASS"; case stormkit::gpu::DebugObjectType::SAMPLER: return "DebugObjectType::SAMPLER"; case stormkit::gpu::DebugObjectType::SEMAPHORE: return "DebugObjectType::SEMAPHORE"; - case stormkit::gpu::DebugObjectType::SHADER_MODULE: - return "DebugObjectType::SHADER_MODULE"; + case stormkit::gpu::DebugObjectType::SHADER_MODULE: return "DebugObjectType::SHADER_MODULE"; case stormkit::gpu::DebugObjectType::SURFACE: return "DebugObjectType::SURFACE"; case stormkit::gpu::DebugObjectType::SWAPCHAIN: return "DebugObjectType::SWAPCHAIN"; case stormkit::gpu::DebugObjectType::UNKNOWN: return "DebugObjectType::UNKNOWN"; @@ -1625,28 +1487,20 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string< - stormkit::gpu::DebugObjectType>(stormkit::gpu::DebugObjectType value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::DebugObjectType value) noexcept + -> string { switch (value) { case stormkit::gpu::DebugObjectType::BUFFER: return "DebugObjectType::BUFFER"; case stormkit::gpu::DebugObjectType::BUFFER_VIEW: return "DebugObjectType::BUFFER_VIEW"; - case stormkit::gpu::DebugObjectType::COMMAND_BUFFER: - return "DebugObjectType::COMMAND_BUFFER"; - case stormkit::gpu::DebugObjectType::COMMAND_POOL: - return "DebugObjectType::COMMAND_POOL"; - case stormkit::gpu::DebugObjectType::DEBUG_REPORT_CALLBACK: - return "DebugObjectType::DEBUG_REPORT_CALLBACK"; - case stormkit::gpu::DebugObjectType::DESCRIPTOR_POOL: - return "DebugObjectType::DESCRIPTOR_POOL"; - case stormkit::gpu::DebugObjectType::DESCRIPTOR_SET: - return "DebugObjectType::DESCRIPTOR_SET"; - case stormkit::gpu::DebugObjectType::DESCRIPTOR_SET_LAYOUT: - return "DebugObjectType::DESCRIPTOR_SET_LAYOUT"; + case stormkit::gpu::DebugObjectType::COMMAND_BUFFER: return "DebugObjectType::COMMAND_BUFFER"; + case stormkit::gpu::DebugObjectType::COMMAND_POOL: return "DebugObjectType::COMMAND_POOL"; + case stormkit::gpu::DebugObjectType::DEBUG_REPORT_CALLBACK: return "DebugObjectType::DEBUG_REPORT_CALLBACK"; + case stormkit::gpu::DebugObjectType::DEBUG_UTILS_MESSENGER: return "DebugObjectType::DEBUG_UTILS_MESSENGER"; + case stormkit::gpu::DebugObjectType::DESCRIPTOR_POOL: return "DebugObjectType::DESCRIPTOR_POOL"; + case stormkit::gpu::DebugObjectType::DESCRIPTOR_SET: return "DebugObjectType::DESCRIPTOR_SET"; + case stormkit::gpu::DebugObjectType::DESCRIPTOR_SET_LAYOUT: return "DebugObjectType::DESCRIPTOR_SET_LAYOUT"; case stormkit::gpu::DebugObjectType::DEVICE: return "DebugObjectType::DEVICE"; - case stormkit::gpu::DebugObjectType::DEVICE_MEMORY: - return "DebugObjectType::DEVICE_MEMORY"; + case stormkit::gpu::DebugObjectType::DEVICE_MEMORY: return "DebugObjectType::DEVICE_MEMORY"; case stormkit::gpu::DebugObjectType::DISPLAY: return "DebugObjectType::DISPLAY"; case stormkit::gpu::DebugObjectType::EVENT: return "DebugObjectType::EVENT"; case stormkit::gpu::DebugObjectType::FENCE: return "DebugObjectType::FENCE"; @@ -1654,20 +1508,16 @@ export { case stormkit::gpu::DebugObjectType::IMAGE: return "DebugObjectType::IMAGE"; case stormkit::gpu::DebugObjectType::IMAGE_VIEW: return "DebugObjectType::IMAGE_VIEW"; case stormkit::gpu::DebugObjectType::INSTANCE: return "DebugObjectType::INSTANCE"; - case stormkit::gpu::DebugObjectType::PHYSICAL_DEVICE: - return "DebugObjectType::PHYSICAL_DEVICE"; + case stormkit::gpu::DebugObjectType::PHYSICAL_DEVICE: return "DebugObjectType::PHYSICAL_DEVICE"; case stormkit::gpu::DebugObjectType::PIPELINE: return "DebugObjectType::PIPELINE"; - case stormkit::gpu::DebugObjectType::PIPELINE_CACHE: - return "DebugObjectType::PIPELINE_CACHE"; - case stormkit::gpu::DebugObjectType::PIPELINE_LAYOUT: - return "DebugObjectType::PIPELINE_LAYOUT"; + case stormkit::gpu::DebugObjectType::PIPELINE_CACHE: return "DebugObjectType::PIPELINE_CACHE"; + case stormkit::gpu::DebugObjectType::PIPELINE_LAYOUT: return "DebugObjectType::PIPELINE_LAYOUT"; case stormkit::gpu::DebugObjectType::QUERY_POOL: return "DebugObjectType::QUERY_POOL"; case stormkit::gpu::DebugObjectType::QUEUE: return "DebugObjectType::QUEUE"; case stormkit::gpu::DebugObjectType::RENDER_PASS: return "DebugObjectType::RENDER_PASS"; case stormkit::gpu::DebugObjectType::SAMPLER: return "DebugObjectType::SAMPLER"; case stormkit::gpu::DebugObjectType::SEMAPHORE: return "DebugObjectType::SEMAPHORE"; - case stormkit::gpu::DebugObjectType::SHADER_MODULE: - return "DebugObjectType::SHADER_MODULE"; + case stormkit::gpu::DebugObjectType::SHADER_MODULE: return "DebugObjectType::SHADER_MODULE"; case stormkit::gpu::DebugObjectType::SURFACE: return "DebugObjectType::SURFACE"; case stormkit::gpu::DebugObjectType::SWAPCHAIN: return "DebugObjectType::SWAPCHAIN"; case stormkit::gpu::DebugObjectType::UNKNOWN: return "DebugObjectType::UNKNOWN"; @@ -1679,9 +1529,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::DependencyFlag::BY_REGION, stormkit::gpu::DependencyFlag::DEVICE_GROUP, stormkit::gpu::DependencyFlag::NONE, @@ -1693,9 +1542,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string< - stormkit::gpu::DependencyFlag>(stormkit::gpu::DependencyFlag value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::DependencyFlag value) noexcept + -> string_view { switch (value) { case stormkit::gpu::DependencyFlag::BY_REGION: return "DependencyFlag::BY_REGION"; case stormkit::gpu::DependencyFlag::DEVICE_GROUP: return "DependencyFlag::DEVICE_GROUP"; @@ -1707,9 +1555,8 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string< - stormkit::gpu::DependencyFlag>(stormkit::gpu::DependencyFlag value) noexcept -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::DependencyFlag value) noexcept + -> string { switch (value) { case stormkit::gpu::DependencyFlag::BY_REGION: return "DependencyFlag::BY_REGION"; case stormkit::gpu::DependencyFlag::DEVICE_GROUP: return "DependencyFlag::DEVICE_GROUP"; @@ -1723,19 +1570,13 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { - stormkit::gpu::DescriptorType::COMBINED_IMAGE_SAMPLER, - stormkit::gpu::DescriptorType::INPUT_ATTACHMENT, - stormkit::gpu::DescriptorType::SAMPLED_IMAGE, - stormkit::gpu::DescriptorType::SAMPLER, - stormkit::gpu::DescriptorType::STORAGE_BUFFER, - stormkit::gpu::DescriptorType::STORAGE_BUFFER_DYNAMIC, - stormkit::gpu::DescriptorType::STORAGE_IMAGE, - stormkit::gpu::DescriptorType::STORAGE_TEXEL_BUFFER, - stormkit::gpu::DescriptorType::UNIFORM_BUFFER, - stormkit::gpu::DescriptorType::UNIFORM_BUFFER_DYNAMIC, + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { + stormkit::gpu::DescriptorType::COMBINED_IMAGE_SAMPLER, stormkit::gpu::DescriptorType::INPUT_ATTACHMENT, + stormkit::gpu::DescriptorType::SAMPLED_IMAGE, stormkit::gpu::DescriptorType::SAMPLER, + stormkit::gpu::DescriptorType::STORAGE_BUFFER, stormkit::gpu::DescriptorType::STORAGE_BUFFER_DYNAMIC, + stormkit::gpu::DescriptorType::STORAGE_IMAGE, stormkit::gpu::DescriptorType::STORAGE_TEXEL_BUFFER, + stormkit::gpu::DescriptorType::UNIFORM_BUFFER, stormkit::gpu::DescriptorType::UNIFORM_BUFFER_DYNAMIC, stormkit::gpu::DescriptorType::UNIFORM_TEXEL_BUFFER, }; @@ -1744,62 +1585,40 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string< - stormkit::gpu::DescriptorType>(stormkit::gpu::DescriptorType value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::DescriptorType value) noexcept + -> string_view { switch (value) { - case stormkit::gpu::DescriptorType::COMBINED_IMAGE_SAMPLER: - return "DescriptorType::COMBINED_IMAGE_SAMPLER"; - case stormkit::gpu::DescriptorType::INPUT_ATTACHMENT: - return "DescriptorType::INPUT_ATTACHMENT"; - case stormkit::gpu::DescriptorType::SAMPLED_IMAGE: - return "DescriptorType::SAMPLED_IMAGE"; + case stormkit::gpu::DescriptorType::COMBINED_IMAGE_SAMPLER: return "DescriptorType::COMBINED_IMAGE_SAMPLER"; + case stormkit::gpu::DescriptorType::INPUT_ATTACHMENT: return "DescriptorType::INPUT_ATTACHMENT"; + case stormkit::gpu::DescriptorType::SAMPLED_IMAGE: return "DescriptorType::SAMPLED_IMAGE"; case stormkit::gpu::DescriptorType::SAMPLER: return "DescriptorType::SAMPLER"; - case stormkit::gpu::DescriptorType::STORAGE_BUFFER: - return "DescriptorType::STORAGE_BUFFER"; - case stormkit::gpu::DescriptorType::STORAGE_BUFFER_DYNAMIC: - return "DescriptorType::STORAGE_BUFFER_DYNAMIC"; - case stormkit::gpu::DescriptorType::STORAGE_IMAGE: - return "DescriptorType::STORAGE_IMAGE"; - case stormkit::gpu::DescriptorType::STORAGE_TEXEL_BUFFER: - return "DescriptorType::STORAGE_TEXEL_BUFFER"; - case stormkit::gpu::DescriptorType::UNIFORM_BUFFER: - return "DescriptorType::UNIFORM_BUFFER"; - case stormkit::gpu::DescriptorType::UNIFORM_BUFFER_DYNAMIC: - return "DescriptorType::UNIFORM_BUFFER_DYNAMIC"; - case stormkit::gpu::DescriptorType::UNIFORM_TEXEL_BUFFER: - return "DescriptorType::UNIFORM_TEXEL_BUFFER"; + case stormkit::gpu::DescriptorType::STORAGE_BUFFER: return "DescriptorType::STORAGE_BUFFER"; + case stormkit::gpu::DescriptorType::STORAGE_BUFFER_DYNAMIC: return "DescriptorType::STORAGE_BUFFER_DYNAMIC"; + case stormkit::gpu::DescriptorType::STORAGE_IMAGE: return "DescriptorType::STORAGE_IMAGE"; + case stormkit::gpu::DescriptorType::STORAGE_TEXEL_BUFFER: return "DescriptorType::STORAGE_TEXEL_BUFFER"; + case stormkit::gpu::DescriptorType::UNIFORM_BUFFER: return "DescriptorType::UNIFORM_BUFFER"; + case stormkit::gpu::DescriptorType::UNIFORM_BUFFER_DYNAMIC: return "DescriptorType::UNIFORM_BUFFER_DYNAMIC"; + case stormkit::gpu::DescriptorType::UNIFORM_TEXEL_BUFFER: return "DescriptorType::UNIFORM_TEXEL_BUFFER"; } std::unreachable(); } template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string< - stormkit::gpu::DescriptorType>(stormkit::gpu::DescriptorType value) noexcept -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::DescriptorType value) noexcept + -> string { switch (value) { - case stormkit::gpu::DescriptorType::COMBINED_IMAGE_SAMPLER: - return "DescriptorType::COMBINED_IMAGE_SAMPLER"; - case stormkit::gpu::DescriptorType::INPUT_ATTACHMENT: - return "DescriptorType::INPUT_ATTACHMENT"; - case stormkit::gpu::DescriptorType::SAMPLED_IMAGE: - return "DescriptorType::SAMPLED_IMAGE"; + case stormkit::gpu::DescriptorType::COMBINED_IMAGE_SAMPLER: return "DescriptorType::COMBINED_IMAGE_SAMPLER"; + case stormkit::gpu::DescriptorType::INPUT_ATTACHMENT: return "DescriptorType::INPUT_ATTACHMENT"; + case stormkit::gpu::DescriptorType::SAMPLED_IMAGE: return "DescriptorType::SAMPLED_IMAGE"; case stormkit::gpu::DescriptorType::SAMPLER: return "DescriptorType::SAMPLER"; - case stormkit::gpu::DescriptorType::STORAGE_BUFFER: - return "DescriptorType::STORAGE_BUFFER"; - case stormkit::gpu::DescriptorType::STORAGE_BUFFER_DYNAMIC: - return "DescriptorType::STORAGE_BUFFER_DYNAMIC"; - case stormkit::gpu::DescriptorType::STORAGE_IMAGE: - return "DescriptorType::STORAGE_IMAGE"; - case stormkit::gpu::DescriptorType::STORAGE_TEXEL_BUFFER: - return "DescriptorType::STORAGE_TEXEL_BUFFER"; - case stormkit::gpu::DescriptorType::UNIFORM_BUFFER: - return "DescriptorType::UNIFORM_BUFFER"; - case stormkit::gpu::DescriptorType::UNIFORM_BUFFER_DYNAMIC: - return "DescriptorType::UNIFORM_BUFFER_DYNAMIC"; - case stormkit::gpu::DescriptorType::UNIFORM_TEXEL_BUFFER: - return "DescriptorType::UNIFORM_TEXEL_BUFFER"; + case stormkit::gpu::DescriptorType::STORAGE_BUFFER: return "DescriptorType::STORAGE_BUFFER"; + case stormkit::gpu::DescriptorType::STORAGE_BUFFER_DYNAMIC: return "DescriptorType::STORAGE_BUFFER_DYNAMIC"; + case stormkit::gpu::DescriptorType::STORAGE_IMAGE: return "DescriptorType::STORAGE_IMAGE"; + case stormkit::gpu::DescriptorType::STORAGE_TEXEL_BUFFER: return "DescriptorType::STORAGE_TEXEL_BUFFER"; + case stormkit::gpu::DescriptorType::UNIFORM_BUFFER: return "DescriptorType::UNIFORM_BUFFER"; + case stormkit::gpu::DescriptorType::UNIFORM_BUFFER_DYNAMIC: return "DescriptorType::UNIFORM_BUFFER_DYNAMIC"; + case stormkit::gpu::DescriptorType::UNIFORM_TEXEL_BUFFER: return "DescriptorType::UNIFORM_TEXEL_BUFFER"; } std::unreachable(); } @@ -1808,17 +1627,12 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { - stormkit::gpu::DynamicState::BLEND_CONSTANTS, - stormkit::gpu::DynamicState::DEPTH_BIAS, - stormkit::gpu::DynamicState::DEPTH_BOUNDS, - stormkit::gpu::DynamicState::LINE_WIDTH, - stormkit::gpu::DynamicState::SCISSOR, - stormkit::gpu::DynamicState::STENCIL_COMPARE_MASK, - stormkit::gpu::DynamicState::STENCIL_REFERENCE, - stormkit::gpu::DynamicState::STENCIL_WRITE_MASK, + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { + stormkit::gpu::DynamicState::BLEND_CONSTANTS, stormkit::gpu::DynamicState::DEPTH_BIAS, + stormkit::gpu::DynamicState::DEPTH_BOUNDS, stormkit::gpu::DynamicState::LINE_WIDTH, + stormkit::gpu::DynamicState::SCISSOR, stormkit::gpu::DynamicState::STENCIL_COMPARE_MASK, + stormkit::gpu::DynamicState::STENCIL_REFERENCE, stormkit::gpu::DynamicState::STENCIL_WRITE_MASK, stormkit::gpu::DynamicState::VIEWPORT, }; @@ -1827,21 +1641,17 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string< - stormkit::gpu::DynamicState>(stormkit::gpu::DynamicState value) noexcept -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::DynamicState value) noexcept + -> string_view { switch (value) { - case stormkit::gpu::DynamicState::BLEND_CONSTANTS: - return "DynamicState::BLEND_CONSTANTS"; + case stormkit::gpu::DynamicState::BLEND_CONSTANTS: return "DynamicState::BLEND_CONSTANTS"; case stormkit::gpu::DynamicState::DEPTH_BIAS: return "DynamicState::DEPTH_BIAS"; case stormkit::gpu::DynamicState::DEPTH_BOUNDS: return "DynamicState::DEPTH_BOUNDS"; case stormkit::gpu::DynamicState::LINE_WIDTH: return "DynamicState::LINE_WIDTH"; case stormkit::gpu::DynamicState::SCISSOR: return "DynamicState::SCISSOR"; - case stormkit::gpu::DynamicState::STENCIL_COMPARE_MASK: - return "DynamicState::STENCIL_COMPARE_MASK"; - case stormkit::gpu::DynamicState::STENCIL_REFERENCE: - return "DynamicState::STENCIL_REFERENCE"; - case stormkit::gpu::DynamicState::STENCIL_WRITE_MASK: - return "DynamicState::STENCIL_WRITE_MASK"; + case stormkit::gpu::DynamicState::STENCIL_COMPARE_MASK: return "DynamicState::STENCIL_COMPARE_MASK"; + case stormkit::gpu::DynamicState::STENCIL_REFERENCE: return "DynamicState::STENCIL_REFERENCE"; + case stormkit::gpu::DynamicState::STENCIL_WRITE_MASK: return "DynamicState::STENCIL_WRITE_MASK"; case stormkit::gpu::DynamicState::VIEWPORT: return "DynamicState::VIEWPORT"; } std::unreachable(); @@ -1849,22 +1659,16 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string< - stormkit::gpu::DynamicState>(stormkit::gpu::DynamicState value) noexcept -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::DynamicState value) noexcept -> string { switch (value) { - case stormkit::gpu::DynamicState::BLEND_CONSTANTS: - return "DynamicState::BLEND_CONSTANTS"; + case stormkit::gpu::DynamicState::BLEND_CONSTANTS: return "DynamicState::BLEND_CONSTANTS"; case stormkit::gpu::DynamicState::DEPTH_BIAS: return "DynamicState::DEPTH_BIAS"; case stormkit::gpu::DynamicState::DEPTH_BOUNDS: return "DynamicState::DEPTH_BOUNDS"; case stormkit::gpu::DynamicState::LINE_WIDTH: return "DynamicState::LINE_WIDTH"; case stormkit::gpu::DynamicState::SCISSOR: return "DynamicState::SCISSOR"; - case stormkit::gpu::DynamicState::STENCIL_COMPARE_MASK: - return "DynamicState::STENCIL_COMPARE_MASK"; - case stormkit::gpu::DynamicState::STENCIL_REFERENCE: - return "DynamicState::STENCIL_REFERENCE"; - case stormkit::gpu::DynamicState::STENCIL_WRITE_MASK: - return "DynamicState::STENCIL_WRITE_MASK"; + case stormkit::gpu::DynamicState::STENCIL_COMPARE_MASK: return "DynamicState::STENCIL_COMPARE_MASK"; + case stormkit::gpu::DynamicState::STENCIL_REFERENCE: return "DynamicState::STENCIL_REFERENCE"; + case stormkit::gpu::DynamicState::STENCIL_WRITE_MASK: return "DynamicState::STENCIL_WRITE_MASK"; case stormkit::gpu::DynamicState::VIEWPORT: return "DynamicState::VIEWPORT"; } std::unreachable(); @@ -1874,9 +1678,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::Filter::CUBIC_IMG, stormkit::gpu::Filter::LINEAR, stormkit::gpu::Filter::NEAREST, @@ -1887,9 +1690,7 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string(stormkit::gpu::Filter - value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::Filter value) noexcept -> string_view { switch (value) { case stormkit::gpu::Filter::CUBIC_IMG: return "Filter::CUBIC_IMG"; case stormkit::gpu::Filter::LINEAR: return "Filter::LINEAR"; @@ -1900,10 +1701,7 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string(stormkit::gpu::Filter - value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::Filter value) noexcept -> string { switch (value) { case stormkit::gpu::Filter::CUBIC_IMG: return "Filter::CUBIC_IMG"; case stormkit::gpu::Filter::LINEAR: return "Filter::LINEAR"; @@ -1916,9 +1714,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::FormatFeatureFlag::BLIT_DST, stormkit::gpu::FormatFeatureFlag::BLIT_SRC, stormkit::gpu::FormatFeatureFlag::COLOR_ATTACHMENT, @@ -1930,13 +1727,10 @@ export { stormkit::gpu::FormatFeatureFlag::SAMPLED_IMAGE, stormkit::gpu::FormatFeatureFlag::SAMPLED_IMAGE_FILTER_LINEAR, stormkit::gpu::FormatFeatureFlag::SAMPLED_IMAGE_FILTER_MINMAX, - stormkit::gpu::FormatFeatureFlag:: - SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT, - stormkit::gpu::FormatFeatureFlag:: - SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE, + stormkit::gpu::FormatFeatureFlag::SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT, + stormkit::gpu::FormatFeatureFlag::SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE, stormkit::gpu::FormatFeatureFlag::SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER, - stormkit::gpu::FormatFeatureFlag:: - SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER, + stormkit::gpu::FormatFeatureFlag::SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER, stormkit::gpu::FormatFeatureFlag::STORAGE_IMAGE, stormkit::gpu::FormatFeatureFlag::STORAGE_IMAGE_ATOMIC, stormkit::gpu::FormatFeatureFlag::STORAGE_TEXEL_BUFFER, @@ -1952,119 +1746,78 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string< - stormkit::gpu::FormatFeatureFlag>(stormkit::gpu::FormatFeatureFlag value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::FormatFeatureFlag value) noexcept + -> string_view { switch (value) { case stormkit::gpu::FormatFeatureFlag::BLIT_DST: return "FormatFeatureFlag::BLIT_DST"; case stormkit::gpu::FormatFeatureFlag::BLIT_SRC: return "FormatFeatureFlag::BLIT_SRC"; - case stormkit::gpu::FormatFeatureFlag::COLOR_ATTACHMENT: - return "FormatFeatureFlag::COLOR_ATTACHMENT"; - case stormkit::gpu::FormatFeatureFlag::COLOR_ATTACHMENT_BLEND: - return "FormatFeatureFlag::COLOR_ATTACHMENT_BLEND"; - case stormkit::gpu::FormatFeatureFlag::COSITED_CHROMA_SAMPLES: - return "FormatFeatureFlag::COSITED_CHROMA_SAMPLES"; - case stormkit::gpu::FormatFeatureFlag::DEPTH_STENCIL_ATTACHMENT: - return "FormatFeatureFlag::DEPTH_STENCIL_ATTACHMENT"; + case stormkit::gpu::FormatFeatureFlag::COLOR_ATTACHMENT: return "FormatFeatureFlag::COLOR_ATTACHMENT"; + case stormkit::gpu::FormatFeatureFlag::COLOR_ATTACHMENT_BLEND: return "FormatFeatureFlag::COLOR_ATTACHMENT_BLEND"; + case stormkit::gpu::FormatFeatureFlag::COSITED_CHROMA_SAMPLES: return "FormatFeatureFlag::COSITED_CHROMA_SAMPLES"; + case stormkit::gpu::FormatFeatureFlag::DEPTH_STENCIL_ATTACHMENT: return "FormatFeatureFlag::DEPTH_STENCIL_ATTACHMENT"; case stormkit::gpu::FormatFeatureFlag::DISJOINT: return "FormatFeatureFlag::DISJOINT"; - case stormkit::gpu::FormatFeatureFlag::MIDPOINT_CHROMA_SAMPLES: - return "FormatFeatureFlag::MIDPOINT_CHROMA_SAMPLES"; - case stormkit::gpu::FormatFeatureFlag::SAMPLED_IMAGE: - return "FormatFeatureFlag::SAMPLED_IMAGE"; + case stormkit::gpu::FormatFeatureFlag::MIDPOINT_CHROMA_SAMPLES: return "FormatFeatureFlag::MIDPOINT_CHROMA_SAMPLES"; + case stormkit::gpu::FormatFeatureFlag::SAMPLED_IMAGE: return "FormatFeatureFlag::SAMPLED_IMAGE"; case stormkit::gpu::FormatFeatureFlag::SAMPLED_IMAGE_FILTER_LINEAR: return "FormatFeatureFlag::SAMPLED_IMAGE_FILTER_LINEAR"; case stormkit::gpu::FormatFeatureFlag::SAMPLED_IMAGE_FILTER_MINMAX: return "FormatFeatureFlag::SAMPLED_IMAGE_FILTER_MINMAX"; - case stormkit::gpu::FormatFeatureFlag:: - SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT: - return "FormatFeatureFlag::SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_" - "EXPLICIT"; - case stormkit::gpu::FormatFeatureFlag:: - SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE: - return "FormatFeatureFlag::SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_" - "EXPLICIT_FORCEABLE"; + case stormkit::gpu::FormatFeatureFlag::SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT: + return "FormatFeatureFlag::SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT"; + case stormkit::gpu::FormatFeatureFlag::SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE: + return "FormatFeatureFlag::SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE"; case stormkit::gpu::FormatFeatureFlag::SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER: return "FormatFeatureFlag::SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER"; - case stormkit::gpu::FormatFeatureFlag:: - SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER: - return "FormatFeatureFlag::SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_" - "FILTER"; - case stormkit::gpu::FormatFeatureFlag::STORAGE_IMAGE: - return "FormatFeatureFlag::STORAGE_IMAGE"; - case stormkit::gpu::FormatFeatureFlag::STORAGE_IMAGE_ATOMIC: - return "FormatFeatureFlag::STORAGE_IMAGE_ATOMIC"; - case stormkit::gpu::FormatFeatureFlag::STORAGE_TEXEL_BUFFER: - return "FormatFeatureFlag::STORAGE_TEXEL_BUFFER"; + case stormkit::gpu::FormatFeatureFlag::SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER: + return "FormatFeatureFlag::SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER"; + case stormkit::gpu::FormatFeatureFlag::STORAGE_IMAGE: return "FormatFeatureFlag::STORAGE_IMAGE"; + case stormkit::gpu::FormatFeatureFlag::STORAGE_IMAGE_ATOMIC: return "FormatFeatureFlag::STORAGE_IMAGE_ATOMIC"; + case stormkit::gpu::FormatFeatureFlag::STORAGE_TEXEL_BUFFER: return "FormatFeatureFlag::STORAGE_TEXEL_BUFFER"; case stormkit::gpu::FormatFeatureFlag::STORAGE_TEXEL_BUFFER_ATOMIC: return "FormatFeatureFlag::STORAGE_TEXEL_BUFFER_ATOMIC"; - case stormkit::gpu::FormatFeatureFlag::TRANSFER_DST: - return "FormatFeatureFlag::TRANSFER_DST"; - case stormkit::gpu::FormatFeatureFlag::TRANSFER_SRC: - return "FormatFeatureFlag::TRANSFER_SRC"; - case stormkit::gpu::FormatFeatureFlag::UNIFORM_TEXEL_BUFFER: - return "FormatFeatureFlag::UNIFORM_TEXEL_BUFFER"; - case stormkit::gpu::FormatFeatureFlag::VERTEX_BUFFER: - return "FormatFeatureFlag::VERTEX_BUFFER"; + case stormkit::gpu::FormatFeatureFlag::TRANSFER_DST: return "FormatFeatureFlag::TRANSFER_DST"; + case stormkit::gpu::FormatFeatureFlag::TRANSFER_SRC: return "FormatFeatureFlag::TRANSFER_SRC"; + case stormkit::gpu::FormatFeatureFlag::UNIFORM_TEXEL_BUFFER: return "FormatFeatureFlag::UNIFORM_TEXEL_BUFFER"; + case stormkit::gpu::FormatFeatureFlag::VERTEX_BUFFER: return "FormatFeatureFlag::VERTEX_BUFFER"; } std::unreachable(); } template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string< - stormkit::gpu::FormatFeatureFlag>(stormkit::gpu::FormatFeatureFlag value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::FormatFeatureFlag value) noexcept + -> string { switch (value) { case stormkit::gpu::FormatFeatureFlag::BLIT_DST: return "FormatFeatureFlag::BLIT_DST"; case stormkit::gpu::FormatFeatureFlag::BLIT_SRC: return "FormatFeatureFlag::BLIT_SRC"; - case stormkit::gpu::FormatFeatureFlag::COLOR_ATTACHMENT: - return "FormatFeatureFlag::COLOR_ATTACHMENT"; - case stormkit::gpu::FormatFeatureFlag::COLOR_ATTACHMENT_BLEND: - return "FormatFeatureFlag::COLOR_ATTACHMENT_BLEND"; - case stormkit::gpu::FormatFeatureFlag::COSITED_CHROMA_SAMPLES: - return "FormatFeatureFlag::COSITED_CHROMA_SAMPLES"; - case stormkit::gpu::FormatFeatureFlag::DEPTH_STENCIL_ATTACHMENT: - return "FormatFeatureFlag::DEPTH_STENCIL_ATTACHMENT"; + case stormkit::gpu::FormatFeatureFlag::COLOR_ATTACHMENT: return "FormatFeatureFlag::COLOR_ATTACHMENT"; + case stormkit::gpu::FormatFeatureFlag::COLOR_ATTACHMENT_BLEND: return "FormatFeatureFlag::COLOR_ATTACHMENT_BLEND"; + case stormkit::gpu::FormatFeatureFlag::COSITED_CHROMA_SAMPLES: return "FormatFeatureFlag::COSITED_CHROMA_SAMPLES"; + case stormkit::gpu::FormatFeatureFlag::DEPTH_STENCIL_ATTACHMENT: return "FormatFeatureFlag::DEPTH_STENCIL_ATTACHMENT"; case stormkit::gpu::FormatFeatureFlag::DISJOINT: return "FormatFeatureFlag::DISJOINT"; - case stormkit::gpu::FormatFeatureFlag::MIDPOINT_CHROMA_SAMPLES: - return "FormatFeatureFlag::MIDPOINT_CHROMA_SAMPLES"; - case stormkit::gpu::FormatFeatureFlag::SAMPLED_IMAGE: - return "FormatFeatureFlag::SAMPLED_IMAGE"; + case stormkit::gpu::FormatFeatureFlag::MIDPOINT_CHROMA_SAMPLES: return "FormatFeatureFlag::MIDPOINT_CHROMA_SAMPLES"; + case stormkit::gpu::FormatFeatureFlag::SAMPLED_IMAGE: return "FormatFeatureFlag::SAMPLED_IMAGE"; case stormkit::gpu::FormatFeatureFlag::SAMPLED_IMAGE_FILTER_LINEAR: return "FormatFeatureFlag::SAMPLED_IMAGE_FILTER_LINEAR"; case stormkit::gpu::FormatFeatureFlag::SAMPLED_IMAGE_FILTER_MINMAX: return "FormatFeatureFlag::SAMPLED_IMAGE_FILTER_MINMAX"; - case stormkit::gpu::FormatFeatureFlag:: - SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT: - return "FormatFeatureFlag::SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_" - "EXPLICIT"; - case stormkit::gpu::FormatFeatureFlag:: - SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE: - return "FormatFeatureFlag::SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_" - "EXPLICIT_FORCEABLE"; + case stormkit::gpu::FormatFeatureFlag::SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT: + return "FormatFeatureFlag::SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT"; + case stormkit::gpu::FormatFeatureFlag::SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE: + return "FormatFeatureFlag::SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE"; case stormkit::gpu::FormatFeatureFlag::SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER: return "FormatFeatureFlag::SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER"; - case stormkit::gpu::FormatFeatureFlag:: - SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER: - return "FormatFeatureFlag::SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_" - "FILTER"; - case stormkit::gpu::FormatFeatureFlag::STORAGE_IMAGE: - return "FormatFeatureFlag::STORAGE_IMAGE"; - case stormkit::gpu::FormatFeatureFlag::STORAGE_IMAGE_ATOMIC: - return "FormatFeatureFlag::STORAGE_IMAGE_ATOMIC"; - case stormkit::gpu::FormatFeatureFlag::STORAGE_TEXEL_BUFFER: - return "FormatFeatureFlag::STORAGE_TEXEL_BUFFER"; + case stormkit::gpu::FormatFeatureFlag::SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER: + return "FormatFeatureFlag::SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER"; + case stormkit::gpu::FormatFeatureFlag::STORAGE_IMAGE: return "FormatFeatureFlag::STORAGE_IMAGE"; + case stormkit::gpu::FormatFeatureFlag::STORAGE_IMAGE_ATOMIC: return "FormatFeatureFlag::STORAGE_IMAGE_ATOMIC"; + case stormkit::gpu::FormatFeatureFlag::STORAGE_TEXEL_BUFFER: return "FormatFeatureFlag::STORAGE_TEXEL_BUFFER"; case stormkit::gpu::FormatFeatureFlag::STORAGE_TEXEL_BUFFER_ATOMIC: return "FormatFeatureFlag::STORAGE_TEXEL_BUFFER_ATOMIC"; - case stormkit::gpu::FormatFeatureFlag::TRANSFER_DST: - return "FormatFeatureFlag::TRANSFER_DST"; - case stormkit::gpu::FormatFeatureFlag::TRANSFER_SRC: - return "FormatFeatureFlag::TRANSFER_SRC"; - case stormkit::gpu::FormatFeatureFlag::UNIFORM_TEXEL_BUFFER: - return "FormatFeatureFlag::UNIFORM_TEXEL_BUFFER"; - case stormkit::gpu::FormatFeatureFlag::VERTEX_BUFFER: - return "FormatFeatureFlag::VERTEX_BUFFER"; + case stormkit::gpu::FormatFeatureFlag::TRANSFER_DST: return "FormatFeatureFlag::TRANSFER_DST"; + case stormkit::gpu::FormatFeatureFlag::TRANSFER_SRC: return "FormatFeatureFlag::TRANSFER_SRC"; + case stormkit::gpu::FormatFeatureFlag::UNIFORM_TEXEL_BUFFER: return "FormatFeatureFlag::UNIFORM_TEXEL_BUFFER"; + case stormkit::gpu::FormatFeatureFlag::VERTEX_BUFFER: return "FormatFeatureFlag::VERTEX_BUFFER"; } std::unreachable(); } @@ -2073,9 +1826,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::FrontFace::CLOCKWISE, stormkit::gpu::FrontFace::COUNTER_CLOCKWISE, @@ -2085,9 +1837,7 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string(stormkit::gpu::FrontFace - value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::FrontFace value) noexcept -> string_view { switch (value) { case stormkit::gpu::FrontFace::CLOCKWISE: return "FrontFace::CLOCKWISE"; case stormkit::gpu::FrontFace::COUNTER_CLOCKWISE: return "FrontFace::COUNTER_CLOCKWISE"; @@ -2097,10 +1847,7 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string(stormkit::gpu::FrontFace - value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::FrontFace value) noexcept -> string { switch (value) { case stormkit::gpu::FrontFace::CLOCKWISE: return "FrontFace::CLOCKWISE"; case stormkit::gpu::FrontFace::COUNTER_CLOCKWISE: return "FrontFace::COUNTER_CLOCKWISE"; @@ -2112,9 +1859,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::GeometryFlag::NO_DUPLICATE_ANY_HIT_INVOCATION, stormkit::gpu::GeometryFlag::OPAQUE, @@ -2124,8 +1870,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string< - stormkit::gpu::GeometryFlag>(stormkit::gpu::GeometryFlag value) noexcept -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::GeometryFlag value) noexcept + -> string_view { switch (value) { case stormkit::gpu::GeometryFlag::NO_DUPLICATE_ANY_HIT_INVOCATION: return "GeometryFlag::NO_DUPLICATE_ANY_HIT_INVOCATION"; @@ -2136,9 +1882,7 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string< - stormkit::gpu::GeometryFlag>(stormkit::gpu::GeometryFlag value) noexcept -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::GeometryFlag value) noexcept -> string { switch (value) { case stormkit::gpu::GeometryFlag::NO_DUPLICATE_ANY_HIT_INVOCATION: return "GeometryFlag::NO_DUPLICATE_ANY_HIT_INVOCATION"; @@ -2151,9 +1895,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::GeometryType::AABBS, stormkit::gpu::GeometryType::INSTANCES, stormkit::gpu::GeometryType::TRIANGLES, @@ -2164,8 +1907,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string< - stormkit::gpu::GeometryType>(stormkit::gpu::GeometryType value) noexcept -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::GeometryType value) noexcept + -> string_view { switch (value) { case stormkit::gpu::GeometryType::AABBS: return "GeometryType::AABBS"; case stormkit::gpu::GeometryType::INSTANCES: return "GeometryType::INSTANCES"; @@ -2176,9 +1919,7 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string< - stormkit::gpu::GeometryType>(stormkit::gpu::GeometryType value) noexcept -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::GeometryType value) noexcept -> string { switch (value) { case stormkit::gpu::GeometryType::AABBS: return "GeometryType::AABBS"; case stormkit::gpu::GeometryType::INSTANCES: return "GeometryType::INSTANCES"; @@ -2191,9 +1932,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::ImageAspectFlag::COLOR, stormkit::gpu::ImageAspectFlag::DEPTH, stormkit::gpu::ImageAspectFlag::NONE, @@ -2205,9 +1945,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string< - stormkit::gpu::ImageAspectFlag>(stormkit::gpu::ImageAspectFlag value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::ImageAspectFlag value) noexcept + -> string_view { switch (value) { case stormkit::gpu::ImageAspectFlag::COLOR: return "ImageAspectFlag::COLOR"; case stormkit::gpu::ImageAspectFlag::DEPTH: return "ImageAspectFlag::DEPTH"; @@ -2219,10 +1958,8 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string< - stormkit::gpu::ImageAspectFlag>(stormkit::gpu::ImageAspectFlag value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::ImageAspectFlag value) noexcept + -> string { switch (value) { case stormkit::gpu::ImageAspectFlag::COLOR: return "ImageAspectFlag::COLOR"; case stormkit::gpu::ImageAspectFlag::DEPTH: return "ImageAspectFlag::DEPTH"; @@ -2236,9 +1973,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::ImageCreateFlag::ALIAS, stormkit::gpu::ImageCreateFlag::ARRAY_2D_COMPATIBLE, stormkit::gpu::ImageCreateFlag::BLOCK_TEXEL_VIEW_COMPATIBLE, @@ -2259,30 +1995,22 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string< - stormkit::gpu::ImageCreateFlag>(stormkit::gpu::ImageCreateFlag value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::ImageCreateFlag value) noexcept + -> string_view { switch (value) { case stormkit::gpu::ImageCreateFlag::ALIAS: return "ImageCreateFlag::ALIAS"; - case stormkit::gpu::ImageCreateFlag::ARRAY_2D_COMPATIBLE: - return "ImageCreateFlag::ARRAY_2D_COMPATIBLE"; + case stormkit::gpu::ImageCreateFlag::ARRAY_2D_COMPATIBLE: return "ImageCreateFlag::ARRAY_2D_COMPATIBLE"; case stormkit::gpu::ImageCreateFlag::BLOCK_TEXEL_VIEW_COMPATIBLE: return "ImageCreateFlag::BLOCK_TEXEL_VIEW_COMPATIBLE"; - case stormkit::gpu::ImageCreateFlag::CUBE_COMPATIBLE: - return "ImageCreateFlag::CUBE_COMPATIBLE"; + case stormkit::gpu::ImageCreateFlag::CUBE_COMPATIBLE: return "ImageCreateFlag::CUBE_COMPATIBLE"; case stormkit::gpu::ImageCreateFlag::DISJOINT: return "ImageCreateFlag::DISJOINT"; - case stormkit::gpu::ImageCreateFlag::EXTENDED_USAGE: - return "ImageCreateFlag::EXTENDED_USAGE"; - case stormkit::gpu::ImageCreateFlag::MUTABLE_FORMAT: - return "ImageCreateFlag::MUTABLE_FORMAT"; + case stormkit::gpu::ImageCreateFlag::EXTENDED_USAGE: return "ImageCreateFlag::EXTENDED_USAGE"; + case stormkit::gpu::ImageCreateFlag::MUTABLE_FORMAT: return "ImageCreateFlag::MUTABLE_FORMAT"; case stormkit::gpu::ImageCreateFlag::NONE: return "ImageCreateFlag::NONE"; case stormkit::gpu::ImageCreateFlag::PROTECTED: return "ImageCreateFlag::PROTECTED"; - case stormkit::gpu::ImageCreateFlag::SPARSE_ALIASED: - return "ImageCreateFlag::SPARSE_ALIASED"; - case stormkit::gpu::ImageCreateFlag::SPARSE_BINDING: - return "ImageCreateFlag::SPARSE_BINDING"; - case stormkit::gpu::ImageCreateFlag::SPARSE_RESIDENCY: - return "ImageCreateFlag::SPARSE_RESIDENCY"; + case stormkit::gpu::ImageCreateFlag::SPARSE_ALIASED: return "ImageCreateFlag::SPARSE_ALIASED"; + case stormkit::gpu::ImageCreateFlag::SPARSE_BINDING: return "ImageCreateFlag::SPARSE_BINDING"; + case stormkit::gpu::ImageCreateFlag::SPARSE_RESIDENCY: return "ImageCreateFlag::SPARSE_RESIDENCY"; case stormkit::gpu::ImageCreateFlag::SPLIT_INSTANCE_BIND_REGIONS: return "ImageCreateFlag::SPLIT_INSTANCE_BIND_REGIONS"; } @@ -2291,31 +2019,22 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string< - stormkit::gpu::ImageCreateFlag>(stormkit::gpu::ImageCreateFlag value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::ImageCreateFlag value) noexcept + -> string { switch (value) { case stormkit::gpu::ImageCreateFlag::ALIAS: return "ImageCreateFlag::ALIAS"; - case stormkit::gpu::ImageCreateFlag::ARRAY_2D_COMPATIBLE: - return "ImageCreateFlag::ARRAY_2D_COMPATIBLE"; + case stormkit::gpu::ImageCreateFlag::ARRAY_2D_COMPATIBLE: return "ImageCreateFlag::ARRAY_2D_COMPATIBLE"; case stormkit::gpu::ImageCreateFlag::BLOCK_TEXEL_VIEW_COMPATIBLE: return "ImageCreateFlag::BLOCK_TEXEL_VIEW_COMPATIBLE"; - case stormkit::gpu::ImageCreateFlag::CUBE_COMPATIBLE: - return "ImageCreateFlag::CUBE_COMPATIBLE"; + case stormkit::gpu::ImageCreateFlag::CUBE_COMPATIBLE: return "ImageCreateFlag::CUBE_COMPATIBLE"; case stormkit::gpu::ImageCreateFlag::DISJOINT: return "ImageCreateFlag::DISJOINT"; - case stormkit::gpu::ImageCreateFlag::EXTENDED_USAGE: - return "ImageCreateFlag::EXTENDED_USAGE"; - case stormkit::gpu::ImageCreateFlag::MUTABLE_FORMAT: - return "ImageCreateFlag::MUTABLE_FORMAT"; + case stormkit::gpu::ImageCreateFlag::EXTENDED_USAGE: return "ImageCreateFlag::EXTENDED_USAGE"; + case stormkit::gpu::ImageCreateFlag::MUTABLE_FORMAT: return "ImageCreateFlag::MUTABLE_FORMAT"; case stormkit::gpu::ImageCreateFlag::NONE: return "ImageCreateFlag::NONE"; case stormkit::gpu::ImageCreateFlag::PROTECTED: return "ImageCreateFlag::PROTECTED"; - case stormkit::gpu::ImageCreateFlag::SPARSE_ALIASED: - return "ImageCreateFlag::SPARSE_ALIASED"; - case stormkit::gpu::ImageCreateFlag::SPARSE_BINDING: - return "ImageCreateFlag::SPARSE_BINDING"; - case stormkit::gpu::ImageCreateFlag::SPARSE_RESIDENCY: - return "ImageCreateFlag::SPARSE_RESIDENCY"; + case stormkit::gpu::ImageCreateFlag::SPARSE_ALIASED: return "ImageCreateFlag::SPARSE_ALIASED"; + case stormkit::gpu::ImageCreateFlag::SPARSE_BINDING: return "ImageCreateFlag::SPARSE_BINDING"; + case stormkit::gpu::ImageCreateFlag::SPARSE_RESIDENCY: return "ImageCreateFlag::SPARSE_RESIDENCY"; case stormkit::gpu::ImageCreateFlag::SPLIT_INSTANCE_BIND_REGIONS: return "ImageCreateFlag::SPLIT_INSTANCE_BIND_REGIONS"; } @@ -2326,9 +2045,9 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { + stormkit::gpu::ImageLayout::ATTACHMENT_OPTIMAL, stormkit::gpu::ImageLayout::COLOR_ATTACHMENT_OPTIMAL, stormkit::gpu::ImageLayout::DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, stormkit::gpu::ImageLayout::DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, @@ -2349,12 +2068,11 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string(stormkit::gpu::ImageLayout - value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::ImageLayout value) noexcept + -> string_view { switch (value) { - case stormkit::gpu::ImageLayout::COLOR_ATTACHMENT_OPTIMAL: - return "ImageLayout::COLOR_ATTACHMENT_OPTIMAL"; + case stormkit::gpu::ImageLayout::ATTACHMENT_OPTIMAL: return "ImageLayout::ATTACHMENT_OPTIMAL"; + case stormkit::gpu::ImageLayout::COLOR_ATTACHMENT_OPTIMAL: return "ImageLayout::COLOR_ATTACHMENT_OPTIMAL"; case stormkit::gpu::ImageLayout::DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL: return "ImageLayout::DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL"; case stormkit::gpu::ImageLayout::DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL: @@ -2366,13 +2084,10 @@ export { case stormkit::gpu::ImageLayout::GENERAL: return "ImageLayout::GENERAL"; case stormkit::gpu::ImageLayout::PREINITIALIZED: return "ImageLayout::PREINITIALIZED"; case stormkit::gpu::ImageLayout::PRESENT_SRC: return "ImageLayout::PRESENT_SRC"; - case stormkit::gpu::ImageLayout::SHADER_READ_ONLY_OPTIMAL: - return "ImageLayout::SHADER_READ_ONLY_OPTIMAL"; + case stormkit::gpu::ImageLayout::SHADER_READ_ONLY_OPTIMAL: return "ImageLayout::SHADER_READ_ONLY_OPTIMAL"; case stormkit::gpu::ImageLayout::SHARED_PRESENT: return "ImageLayout::SHARED_PRESENT"; - case stormkit::gpu::ImageLayout::TRANSFER_DST_OPTIMAL: - return "ImageLayout::TRANSFER_DST_OPTIMAL"; - case stormkit::gpu::ImageLayout::TRANSFER_SRC_OPTIMAL: - return "ImageLayout::TRANSFER_SRC_OPTIMAL"; + case stormkit::gpu::ImageLayout::TRANSFER_DST_OPTIMAL: return "ImageLayout::TRANSFER_DST_OPTIMAL"; + case stormkit::gpu::ImageLayout::TRANSFER_SRC_OPTIMAL: return "ImageLayout::TRANSFER_SRC_OPTIMAL"; case stormkit::gpu::ImageLayout::UNDEFINED: return "ImageLayout::UNDEFINED"; } std::unreachable(); @@ -2380,13 +2095,10 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string(stormkit::gpu::ImageLayout - value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::ImageLayout value) noexcept -> string { switch (value) { - case stormkit::gpu::ImageLayout::COLOR_ATTACHMENT_OPTIMAL: - return "ImageLayout::COLOR_ATTACHMENT_OPTIMAL"; + case stormkit::gpu::ImageLayout::ATTACHMENT_OPTIMAL: return "ImageLayout::ATTACHMENT_OPTIMAL"; + case stormkit::gpu::ImageLayout::COLOR_ATTACHMENT_OPTIMAL: return "ImageLayout::COLOR_ATTACHMENT_OPTIMAL"; case stormkit::gpu::ImageLayout::DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL: return "ImageLayout::DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL"; case stormkit::gpu::ImageLayout::DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL: @@ -2398,13 +2110,10 @@ export { case stormkit::gpu::ImageLayout::GENERAL: return "ImageLayout::GENERAL"; case stormkit::gpu::ImageLayout::PREINITIALIZED: return "ImageLayout::PREINITIALIZED"; case stormkit::gpu::ImageLayout::PRESENT_SRC: return "ImageLayout::PRESENT_SRC"; - case stormkit::gpu::ImageLayout::SHADER_READ_ONLY_OPTIMAL: - return "ImageLayout::SHADER_READ_ONLY_OPTIMAL"; + case stormkit::gpu::ImageLayout::SHADER_READ_ONLY_OPTIMAL: return "ImageLayout::SHADER_READ_ONLY_OPTIMAL"; case stormkit::gpu::ImageLayout::SHARED_PRESENT: return "ImageLayout::SHARED_PRESENT"; - case stormkit::gpu::ImageLayout::TRANSFER_DST_OPTIMAL: - return "ImageLayout::TRANSFER_DST_OPTIMAL"; - case stormkit::gpu::ImageLayout::TRANSFER_SRC_OPTIMAL: - return "ImageLayout::TRANSFER_SRC_OPTIMAL"; + case stormkit::gpu::ImageLayout::TRANSFER_DST_OPTIMAL: return "ImageLayout::TRANSFER_DST_OPTIMAL"; + case stormkit::gpu::ImageLayout::TRANSFER_SRC_OPTIMAL: return "ImageLayout::TRANSFER_SRC_OPTIMAL"; case stormkit::gpu::ImageLayout::UNDEFINED: return "ImageLayout::UNDEFINED"; } std::unreachable(); @@ -2414,9 +2123,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::ImageTiling::LINEAR, stormkit::gpu::ImageTiling::OPTIMAL, @@ -2426,9 +2134,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string(stormkit::gpu::ImageTiling - value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::ImageTiling value) noexcept + -> string_view { switch (value) { case stormkit::gpu::ImageTiling::LINEAR: return "ImageTiling::LINEAR"; case stormkit::gpu::ImageTiling::OPTIMAL: return "ImageTiling::OPTIMAL"; @@ -2438,10 +2145,7 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string(stormkit::gpu::ImageTiling - value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::ImageTiling value) noexcept -> string { switch (value) { case stormkit::gpu::ImageTiling::LINEAR: return "ImageTiling::LINEAR"; case stormkit::gpu::ImageTiling::OPTIMAL: return "ImageTiling::OPTIMAL"; @@ -2453,9 +2157,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::ImageType::T1D, stormkit::gpu::ImageType::T2D, stormkit::gpu::ImageType::T3D, @@ -2466,9 +2169,7 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string(stormkit::gpu::ImageType - value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::ImageType value) noexcept -> string_view { switch (value) { case stormkit::gpu::ImageType::T1D: return "ImageType::T1D"; case stormkit::gpu::ImageType::T2D: return "ImageType::T2D"; @@ -2479,10 +2180,7 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string(stormkit::gpu::ImageType - value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::ImageType value) noexcept -> string { switch (value) { case stormkit::gpu::ImageType::T1D: return "ImageType::T1D"; case stormkit::gpu::ImageType::T2D: return "ImageType::T2D"; @@ -2495,17 +2193,12 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { - stormkit::gpu::ImageUsageFlag::COLOR_ATTACHMENT, - stormkit::gpu::ImageUsageFlag::DEPTH_STENCIL_ATTACHMENT, - stormkit::gpu::ImageUsageFlag::INPUT_ATTACHMENT, - stormkit::gpu::ImageUsageFlag::SAMPLED, - stormkit::gpu::ImageUsageFlag::STORAGE, - stormkit::gpu::ImageUsageFlag::TRANSFER_DST, - stormkit::gpu::ImageUsageFlag::TRANSFER_SRC, - stormkit::gpu::ImageUsageFlag::TRANSIENT_ATTACHMENT, + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { + stormkit::gpu::ImageUsageFlag::COLOR_ATTACHMENT, stormkit::gpu::ImageUsageFlag::DEPTH_STENCIL_ATTACHMENT, + stormkit::gpu::ImageUsageFlag::INPUT_ATTACHMENT, stormkit::gpu::ImageUsageFlag::SAMPLED, + stormkit::gpu::ImageUsageFlag::STORAGE, stormkit::gpu::ImageUsageFlag::TRANSFER_DST, + stormkit::gpu::ImageUsageFlag::TRANSFER_SRC, stormkit::gpu::ImageUsageFlag::TRANSIENT_ATTACHMENT, }; } @@ -2513,44 +2206,34 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string< - stormkit::gpu::ImageUsageFlag>(stormkit::gpu::ImageUsageFlag value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::ImageUsageFlag value) noexcept + -> string_view { switch (value) { - case stormkit::gpu::ImageUsageFlag::COLOR_ATTACHMENT: - return "ImageUsageFlag::COLOR_ATTACHMENT"; - case stormkit::gpu::ImageUsageFlag::DEPTH_STENCIL_ATTACHMENT: - return "ImageUsageFlag::DEPTH_STENCIL_ATTACHMENT"; - case stormkit::gpu::ImageUsageFlag::INPUT_ATTACHMENT: - return "ImageUsageFlag::INPUT_ATTACHMENT"; + case stormkit::gpu::ImageUsageFlag::COLOR_ATTACHMENT: return "ImageUsageFlag::COLOR_ATTACHMENT"; + case stormkit::gpu::ImageUsageFlag::DEPTH_STENCIL_ATTACHMENT: return "ImageUsageFlag::DEPTH_STENCIL_ATTACHMENT"; + case stormkit::gpu::ImageUsageFlag::INPUT_ATTACHMENT: return "ImageUsageFlag::INPUT_ATTACHMENT"; case stormkit::gpu::ImageUsageFlag::SAMPLED: return "ImageUsageFlag::SAMPLED"; case stormkit::gpu::ImageUsageFlag::STORAGE: return "ImageUsageFlag::STORAGE"; case stormkit::gpu::ImageUsageFlag::TRANSFER_DST: return "ImageUsageFlag::TRANSFER_DST"; case stormkit::gpu::ImageUsageFlag::TRANSFER_SRC: return "ImageUsageFlag::TRANSFER_SRC"; - case stormkit::gpu::ImageUsageFlag::TRANSIENT_ATTACHMENT: - return "ImageUsageFlag::TRANSIENT_ATTACHMENT"; + case stormkit::gpu::ImageUsageFlag::TRANSIENT_ATTACHMENT: return "ImageUsageFlag::TRANSIENT_ATTACHMENT"; } std::unreachable(); } template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string< - stormkit::gpu::ImageUsageFlag>(stormkit::gpu::ImageUsageFlag value) noexcept -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::ImageUsageFlag value) noexcept + -> string { switch (value) { - case stormkit::gpu::ImageUsageFlag::COLOR_ATTACHMENT: - return "ImageUsageFlag::COLOR_ATTACHMENT"; - case stormkit::gpu::ImageUsageFlag::DEPTH_STENCIL_ATTACHMENT: - return "ImageUsageFlag::DEPTH_STENCIL_ATTACHMENT"; - case stormkit::gpu::ImageUsageFlag::INPUT_ATTACHMENT: - return "ImageUsageFlag::INPUT_ATTACHMENT"; + case stormkit::gpu::ImageUsageFlag::COLOR_ATTACHMENT: return "ImageUsageFlag::COLOR_ATTACHMENT"; + case stormkit::gpu::ImageUsageFlag::DEPTH_STENCIL_ATTACHMENT: return "ImageUsageFlag::DEPTH_STENCIL_ATTACHMENT"; + case stormkit::gpu::ImageUsageFlag::INPUT_ATTACHMENT: return "ImageUsageFlag::INPUT_ATTACHMENT"; case stormkit::gpu::ImageUsageFlag::SAMPLED: return "ImageUsageFlag::SAMPLED"; case stormkit::gpu::ImageUsageFlag::STORAGE: return "ImageUsageFlag::STORAGE"; case stormkit::gpu::ImageUsageFlag::TRANSFER_DST: return "ImageUsageFlag::TRANSFER_DST"; case stormkit::gpu::ImageUsageFlag::TRANSFER_SRC: return "ImageUsageFlag::TRANSFER_SRC"; - case stormkit::gpu::ImageUsageFlag::TRANSIENT_ATTACHMENT: - return "ImageUsageFlag::TRANSIENT_ATTACHMENT"; + case stormkit::gpu::ImageUsageFlag::TRANSIENT_ATTACHMENT: return "ImageUsageFlag::TRANSIENT_ATTACHMENT"; } std::unreachable(); } @@ -2559,9 +2242,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::ImageViewType::CUBE, stormkit::gpu::ImageViewType::CUBE_ARRAY, stormkit::gpu::ImageViewType::T1D, stormkit::gpu::ImageViewType::T1D_ARRAY, stormkit::gpu::ImageViewType::T2D, stormkit::gpu::ImageViewType::T2D_ARRAY, @@ -2573,9 +2255,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string< - stormkit::gpu::ImageViewType>(stormkit::gpu::ImageViewType value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::ImageViewType value) noexcept + -> string_view { switch (value) { case stormkit::gpu::ImageViewType::CUBE: return "ImageViewType::CUBE"; case stormkit::gpu::ImageViewType::CUBE_ARRAY: return "ImageViewType::CUBE_ARRAY"; @@ -2590,9 +2271,8 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string< - stormkit::gpu::ImageViewType>(stormkit::gpu::ImageViewType value) noexcept -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::ImageViewType value) noexcept + -> string { switch (value) { case stormkit::gpu::ImageViewType::CUBE: return "ImageViewType::CUBE"; case stormkit::gpu::ImageViewType::CUBE_ARRAY: return "ImageViewType::CUBE_ARRAY"; @@ -2609,25 +2289,16 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { - stormkit::gpu::LogicOperation::AND, - stormkit::gpu::LogicOperation::AND_INVERTED, - stormkit::gpu::LogicOperation::AND_REVERSE, - stormkit::gpu::LogicOperation::CLEAR, - stormkit::gpu::LogicOperation::COPY, - stormkit::gpu::LogicOperation::COPY_INVERTED, - stormkit::gpu::LogicOperation::EQUIVALENT, - stormkit::gpu::LogicOperation::INVERT, - stormkit::gpu::LogicOperation::NAND, - stormkit::gpu::LogicOperation::NO_OP, - stormkit::gpu::LogicOperation::NOR, - stormkit::gpu::LogicOperation::OR, - stormkit::gpu::LogicOperation::OR_INVERTED, - stormkit::gpu::LogicOperation::OR_REVERSE, - stormkit::gpu::LogicOperation::SET, - stormkit::gpu::LogicOperation::XOR, + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { + stormkit::gpu::LogicOperation::AND, stormkit::gpu::LogicOperation::AND_INVERTED, + stormkit::gpu::LogicOperation::AND_REVERSE, stormkit::gpu::LogicOperation::CLEAR, + stormkit::gpu::LogicOperation::COPY, stormkit::gpu::LogicOperation::COPY_INVERTED, + stormkit::gpu::LogicOperation::EQUIVALENT, stormkit::gpu::LogicOperation::INVERT, + stormkit::gpu::LogicOperation::NAND, stormkit::gpu::LogicOperation::NO_OP, + stormkit::gpu::LogicOperation::NOR, stormkit::gpu::LogicOperation::OR, + stormkit::gpu::LogicOperation::OR_INVERTED, stormkit::gpu::LogicOperation::OR_REVERSE, + stormkit::gpu::LogicOperation::SET, stormkit::gpu::LogicOperation::XOR, }; } @@ -2635,17 +2306,15 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string< - stormkit::gpu::LogicOperation>(stormkit::gpu::LogicOperation value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::LogicOperation value) noexcept + -> string_view { switch (value) { case stormkit::gpu::LogicOperation::AND: return "LogicOperation::AND"; case stormkit::gpu::LogicOperation::AND_INVERTED: return "LogicOperation::AND_INVERTED"; case stormkit::gpu::LogicOperation::AND_REVERSE: return "LogicOperation::AND_REVERSE"; case stormkit::gpu::LogicOperation::CLEAR: return "LogicOperation::CLEAR"; case stormkit::gpu::LogicOperation::COPY: return "LogicOperation::COPY"; - case stormkit::gpu::LogicOperation::COPY_INVERTED: - return "LogicOperation::COPY_INVERTED"; + case stormkit::gpu::LogicOperation::COPY_INVERTED: return "LogicOperation::COPY_INVERTED"; case stormkit::gpu::LogicOperation::EQUIVALENT: return "LogicOperation::EQUIVALENT"; case stormkit::gpu::LogicOperation::INVERT: return "LogicOperation::INVERT"; case stormkit::gpu::LogicOperation::NAND: return "LogicOperation::NAND"; @@ -2662,17 +2331,15 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string< - stormkit::gpu::LogicOperation>(stormkit::gpu::LogicOperation value) noexcept -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::LogicOperation value) noexcept + -> string { switch (value) { case stormkit::gpu::LogicOperation::AND: return "LogicOperation::AND"; case stormkit::gpu::LogicOperation::AND_INVERTED: return "LogicOperation::AND_INVERTED"; case stormkit::gpu::LogicOperation::AND_REVERSE: return "LogicOperation::AND_REVERSE"; case stormkit::gpu::LogicOperation::CLEAR: return "LogicOperation::CLEAR"; case stormkit::gpu::LogicOperation::COPY: return "LogicOperation::COPY"; - case stormkit::gpu::LogicOperation::COPY_INVERTED: - return "LogicOperation::COPY_INVERTED"; + case stormkit::gpu::LogicOperation::COPY_INVERTED: return "LogicOperation::COPY_INVERTED"; case stormkit::gpu::LogicOperation::EQUIVALENT: return "LogicOperation::EQUIVALENT"; case stormkit::gpu::LogicOperation::INVERT: return "LogicOperation::INVERT"; case stormkit::gpu::LogicOperation::NAND: return "LogicOperation::NAND"; @@ -2691,9 +2358,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::MemoryPropertyFlag::DEVICE_LOCAL, stormkit::gpu::MemoryPropertyFlag::HOST_CACHED, stormkit::gpu::MemoryPropertyFlag::HOST_COHERENT, @@ -2705,37 +2371,26 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string< - stormkit::gpu::MemoryPropertyFlag>(stormkit::gpu::MemoryPropertyFlag value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::MemoryPropertyFlag value) noexcept + -> string_view { switch (value) { - case stormkit::gpu::MemoryPropertyFlag::DEVICE_LOCAL: - return "MemoryPropertyFlag::DEVICE_LOCAL"; - case stormkit::gpu::MemoryPropertyFlag::HOST_CACHED: - return "MemoryPropertyFlag::HOST_CACHED"; - case stormkit::gpu::MemoryPropertyFlag::HOST_COHERENT: - return "MemoryPropertyFlag::HOST_COHERENT"; - case stormkit::gpu::MemoryPropertyFlag::HOST_VISIBLE: - return "MemoryPropertyFlag::HOST_VISIBLE"; + case stormkit::gpu::MemoryPropertyFlag::DEVICE_LOCAL: return "MemoryPropertyFlag::DEVICE_LOCAL"; + case stormkit::gpu::MemoryPropertyFlag::HOST_CACHED: return "MemoryPropertyFlag::HOST_CACHED"; + case stormkit::gpu::MemoryPropertyFlag::HOST_COHERENT: return "MemoryPropertyFlag::HOST_COHERENT"; + case stormkit::gpu::MemoryPropertyFlag::HOST_VISIBLE: return "MemoryPropertyFlag::HOST_VISIBLE"; } std::unreachable(); } template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string< - stormkit::gpu::MemoryPropertyFlag>(stormkit::gpu::MemoryPropertyFlag value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::MemoryPropertyFlag value) noexcept + -> string { switch (value) { - case stormkit::gpu::MemoryPropertyFlag::DEVICE_LOCAL: - return "MemoryPropertyFlag::DEVICE_LOCAL"; - case stormkit::gpu::MemoryPropertyFlag::HOST_CACHED: - return "MemoryPropertyFlag::HOST_CACHED"; - case stormkit::gpu::MemoryPropertyFlag::HOST_COHERENT: - return "MemoryPropertyFlag::HOST_COHERENT"; - case stormkit::gpu::MemoryPropertyFlag::HOST_VISIBLE: - return "MemoryPropertyFlag::HOST_VISIBLE"; + case stormkit::gpu::MemoryPropertyFlag::DEVICE_LOCAL: return "MemoryPropertyFlag::DEVICE_LOCAL"; + case stormkit::gpu::MemoryPropertyFlag::HOST_CACHED: return "MemoryPropertyFlag::HOST_CACHED"; + case stormkit::gpu::MemoryPropertyFlag::HOST_COHERENT: return "MemoryPropertyFlag::HOST_COHERENT"; + case stormkit::gpu::MemoryPropertyFlag::HOST_VISIBLE: return "MemoryPropertyFlag::HOST_VISIBLE"; } std::unreachable(); } @@ -2744,9 +2399,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::PhysicalDeviceType::CPU, stormkit::gpu::PhysicalDeviceType::DISCRETE_GPU, stormkit::gpu::PhysicalDeviceType::INTEGRATED_GPU, @@ -2759,37 +2413,28 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string< - stormkit::gpu::PhysicalDeviceType>(stormkit::gpu::PhysicalDeviceType value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::PhysicalDeviceType value) noexcept + -> string_view { switch (value) { case stormkit::gpu::PhysicalDeviceType::CPU: return "PhysicalDeviceType::CPU"; - case stormkit::gpu::PhysicalDeviceType::DISCRETE_GPU: - return "PhysicalDeviceType::DISCRETE_GPU"; - case stormkit::gpu::PhysicalDeviceType::INTEGRATED_GPU: - return "PhysicalDeviceType::INTEGRATED_GPU"; + case stormkit::gpu::PhysicalDeviceType::DISCRETE_GPU: return "PhysicalDeviceType::DISCRETE_GPU"; + case stormkit::gpu::PhysicalDeviceType::INTEGRATED_GPU: return "PhysicalDeviceType::INTEGRATED_GPU"; case stormkit::gpu::PhysicalDeviceType::OTHER: return "PhysicalDeviceType::OTHER"; - case stormkit::gpu::PhysicalDeviceType::VIRTUAL_GPU: - return "PhysicalDeviceType::VIRTUAL_GPU"; + case stormkit::gpu::PhysicalDeviceType::VIRTUAL_GPU: return "PhysicalDeviceType::VIRTUAL_GPU"; } std::unreachable(); } template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string< - stormkit::gpu::PhysicalDeviceType>(stormkit::gpu::PhysicalDeviceType value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::PhysicalDeviceType value) noexcept + -> string { switch (value) { case stormkit::gpu::PhysicalDeviceType::CPU: return "PhysicalDeviceType::CPU"; - case stormkit::gpu::PhysicalDeviceType::DISCRETE_GPU: - return "PhysicalDeviceType::DISCRETE_GPU"; - case stormkit::gpu::PhysicalDeviceType::INTEGRATED_GPU: - return "PhysicalDeviceType::INTEGRATED_GPU"; + case stormkit::gpu::PhysicalDeviceType::DISCRETE_GPU: return "PhysicalDeviceType::DISCRETE_GPU"; + case stormkit::gpu::PhysicalDeviceType::INTEGRATED_GPU: return "PhysicalDeviceType::INTEGRATED_GPU"; case stormkit::gpu::PhysicalDeviceType::OTHER: return "PhysicalDeviceType::OTHER"; - case stormkit::gpu::PhysicalDeviceType::VIRTUAL_GPU: - return "PhysicalDeviceType::VIRTUAL_GPU"; + case stormkit::gpu::PhysicalDeviceType::VIRTUAL_GPU: return "PhysicalDeviceType::VIRTUAL_GPU"; } std::unreachable(); } @@ -2798,9 +2443,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::PipelineBindPoint::COMPUTE, stormkit::gpu::PipelineBindPoint::GRAPHICS, @@ -2810,9 +2454,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string< - stormkit::gpu::PipelineBindPoint>(stormkit::gpu::PipelineBindPoint value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::PipelineBindPoint value) noexcept + -> string_view { switch (value) { case stormkit::gpu::PipelineBindPoint::COMPUTE: return "PipelineBindPoint::COMPUTE"; case stormkit::gpu::PipelineBindPoint::GRAPHICS: return "PipelineBindPoint::GRAPHICS"; @@ -2822,10 +2465,8 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string< - stormkit::gpu::PipelineBindPoint>(stormkit::gpu::PipelineBindPoint value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::PipelineBindPoint value) noexcept + -> string { switch (value) { case stormkit::gpu::PipelineBindPoint::COMPUTE: return "PipelineBindPoint::COMPUTE"; case stormkit::gpu::PipelineBindPoint::GRAPHICS: return "PipelineBindPoint::GRAPHICS"; @@ -2837,9 +2478,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::PipelineStageFlag::ALL_COMMANDS, stormkit::gpu::PipelineStageFlag::ALL_GRAPHICS, stormkit::gpu::PipelineStageFlag::BOTTOM_OF_PIPE, @@ -2864,85 +2504,56 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string< - stormkit::gpu::PipelineStageFlag>(stormkit::gpu::PipelineStageFlag value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::PipelineStageFlag value) noexcept + -> string_view { switch (value) { - case stormkit::gpu::PipelineStageFlag::ALL_COMMANDS: - return "PipelineStageFlag::ALL_COMMANDS"; - case stormkit::gpu::PipelineStageFlag::ALL_GRAPHICS: - return "PipelineStageFlag::ALL_GRAPHICS"; - case stormkit::gpu::PipelineStageFlag::BOTTOM_OF_PIPE: - return "PipelineStageFlag::BOTTOM_OF_PIPE"; - case stormkit::gpu::PipelineStageFlag::COLOR_ATTACHMENT_OUTPUT: - return "PipelineStageFlag::COLOR_ATTACHMENT_OUTPUT"; - case stormkit::gpu::PipelineStageFlag::COMPUTE_SHADER: - return "PipelineStageFlag::COMPUTE_SHADER"; - case stormkit::gpu::PipelineStageFlag::DRAW_INDIRECT: - return "PipelineStageFlag::DRAW_INDIRECT"; - case stormkit::gpu::PipelineStageFlag::EARLY_FRAGMENT_TESTS: - return "PipelineStageFlag::EARLY_FRAGMENT_TESTS"; - case stormkit::gpu::PipelineStageFlag::FRAGMENT_SHADER: - return "PipelineStageFlag::FRAGMENT_SHADER"; - case stormkit::gpu::PipelineStageFlag::GEOMETRY_SHADER: - return "PipelineStageFlag::GEOMETRY_SHADER"; + case stormkit::gpu::PipelineStageFlag::ALL_COMMANDS: return "PipelineStageFlag::ALL_COMMANDS"; + case stormkit::gpu::PipelineStageFlag::ALL_GRAPHICS: return "PipelineStageFlag::ALL_GRAPHICS"; + case stormkit::gpu::PipelineStageFlag::BOTTOM_OF_PIPE: return "PipelineStageFlag::BOTTOM_OF_PIPE"; + case stormkit::gpu::PipelineStageFlag::COLOR_ATTACHMENT_OUTPUT: return "PipelineStageFlag::COLOR_ATTACHMENT_OUTPUT"; + case stormkit::gpu::PipelineStageFlag::COMPUTE_SHADER: return "PipelineStageFlag::COMPUTE_SHADER"; + case stormkit::gpu::PipelineStageFlag::DRAW_INDIRECT: return "PipelineStageFlag::DRAW_INDIRECT"; + case stormkit::gpu::PipelineStageFlag::EARLY_FRAGMENT_TESTS: return "PipelineStageFlag::EARLY_FRAGMENT_TESTS"; + case stormkit::gpu::PipelineStageFlag::FRAGMENT_SHADER: return "PipelineStageFlag::FRAGMENT_SHADER"; + case stormkit::gpu::PipelineStageFlag::GEOMETRY_SHADER: return "PipelineStageFlag::GEOMETRY_SHADER"; case stormkit::gpu::PipelineStageFlag::HOST: return "PipelineStageFlag::HOST"; - case stormkit::gpu::PipelineStageFlag::LATE_FRAGMENT_TESTS: - return "PipelineStageFlag::LATE_FRAGMENT_TESTS"; + case stormkit::gpu::PipelineStageFlag::LATE_FRAGMENT_TESTS: return "PipelineStageFlag::LATE_FRAGMENT_TESTS"; case stormkit::gpu::PipelineStageFlag::TESSELLATION_CONTROL_SHADER: return "PipelineStageFlag::TESSELLATION_CONTROL_SHADER"; case stormkit::gpu::PipelineStageFlag::TESSELLATION_EVALUATION_SHADER: return "PipelineStageFlag::TESSELLATION_EVALUATION_SHADER"; - case stormkit::gpu::PipelineStageFlag::TOP_OF_PIPE: - return "PipelineStageFlag::TOP_OF_PIPE"; + case stormkit::gpu::PipelineStageFlag::TOP_OF_PIPE: return "PipelineStageFlag::TOP_OF_PIPE"; case stormkit::gpu::PipelineStageFlag::TRANSFER: return "PipelineStageFlag::TRANSFER"; - case stormkit::gpu::PipelineStageFlag::VERTEX_INPUT: - return "PipelineStageFlag::VERTEX_INPUT"; - case stormkit::gpu::PipelineStageFlag::VERTEX_SHADER: - return "PipelineStageFlag::VERTEX_SHADER"; + case stormkit::gpu::PipelineStageFlag::VERTEX_INPUT: return "PipelineStageFlag::VERTEX_INPUT"; + case stormkit::gpu::PipelineStageFlag::VERTEX_SHADER: return "PipelineStageFlag::VERTEX_SHADER"; } std::unreachable(); } template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string< - stormkit::gpu::PipelineStageFlag>(stormkit::gpu::PipelineStageFlag value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::PipelineStageFlag value) noexcept + -> string { switch (value) { - case stormkit::gpu::PipelineStageFlag::ALL_COMMANDS: - return "PipelineStageFlag::ALL_COMMANDS"; - case stormkit::gpu::PipelineStageFlag::ALL_GRAPHICS: - return "PipelineStageFlag::ALL_GRAPHICS"; - case stormkit::gpu::PipelineStageFlag::BOTTOM_OF_PIPE: - return "PipelineStageFlag::BOTTOM_OF_PIPE"; - case stormkit::gpu::PipelineStageFlag::COLOR_ATTACHMENT_OUTPUT: - return "PipelineStageFlag::COLOR_ATTACHMENT_OUTPUT"; - case stormkit::gpu::PipelineStageFlag::COMPUTE_SHADER: - return "PipelineStageFlag::COMPUTE_SHADER"; - case stormkit::gpu::PipelineStageFlag::DRAW_INDIRECT: - return "PipelineStageFlag::DRAW_INDIRECT"; - case stormkit::gpu::PipelineStageFlag::EARLY_FRAGMENT_TESTS: - return "PipelineStageFlag::EARLY_FRAGMENT_TESTS"; - case stormkit::gpu::PipelineStageFlag::FRAGMENT_SHADER: - return "PipelineStageFlag::FRAGMENT_SHADER"; - case stormkit::gpu::PipelineStageFlag::GEOMETRY_SHADER: - return "PipelineStageFlag::GEOMETRY_SHADER"; + case stormkit::gpu::PipelineStageFlag::ALL_COMMANDS: return "PipelineStageFlag::ALL_COMMANDS"; + case stormkit::gpu::PipelineStageFlag::ALL_GRAPHICS: return "PipelineStageFlag::ALL_GRAPHICS"; + case stormkit::gpu::PipelineStageFlag::BOTTOM_OF_PIPE: return "PipelineStageFlag::BOTTOM_OF_PIPE"; + case stormkit::gpu::PipelineStageFlag::COLOR_ATTACHMENT_OUTPUT: return "PipelineStageFlag::COLOR_ATTACHMENT_OUTPUT"; + case stormkit::gpu::PipelineStageFlag::COMPUTE_SHADER: return "PipelineStageFlag::COMPUTE_SHADER"; + case stormkit::gpu::PipelineStageFlag::DRAW_INDIRECT: return "PipelineStageFlag::DRAW_INDIRECT"; + case stormkit::gpu::PipelineStageFlag::EARLY_FRAGMENT_TESTS: return "PipelineStageFlag::EARLY_FRAGMENT_TESTS"; + case stormkit::gpu::PipelineStageFlag::FRAGMENT_SHADER: return "PipelineStageFlag::FRAGMENT_SHADER"; + case stormkit::gpu::PipelineStageFlag::GEOMETRY_SHADER: return "PipelineStageFlag::GEOMETRY_SHADER"; case stormkit::gpu::PipelineStageFlag::HOST: return "PipelineStageFlag::HOST"; - case stormkit::gpu::PipelineStageFlag::LATE_FRAGMENT_TESTS: - return "PipelineStageFlag::LATE_FRAGMENT_TESTS"; + case stormkit::gpu::PipelineStageFlag::LATE_FRAGMENT_TESTS: return "PipelineStageFlag::LATE_FRAGMENT_TESTS"; case stormkit::gpu::PipelineStageFlag::TESSELLATION_CONTROL_SHADER: return "PipelineStageFlag::TESSELLATION_CONTROL_SHADER"; case stormkit::gpu::PipelineStageFlag::TESSELLATION_EVALUATION_SHADER: return "PipelineStageFlag::TESSELLATION_EVALUATION_SHADER"; - case stormkit::gpu::PipelineStageFlag::TOP_OF_PIPE: - return "PipelineStageFlag::TOP_OF_PIPE"; + case stormkit::gpu::PipelineStageFlag::TOP_OF_PIPE: return "PipelineStageFlag::TOP_OF_PIPE"; case stormkit::gpu::PipelineStageFlag::TRANSFER: return "PipelineStageFlag::TRANSFER"; - case stormkit::gpu::PipelineStageFlag::VERTEX_INPUT: - return "PipelineStageFlag::VERTEX_INPUT"; - case stormkit::gpu::PipelineStageFlag::VERTEX_SHADER: - return "PipelineStageFlag::VERTEX_SHADER"; + case stormkit::gpu::PipelineStageFlag::VERTEX_INPUT: return "PipelineStageFlag::VERTEX_INPUT"; + case stormkit::gpu::PipelineStageFlag::VERTEX_SHADER: return "PipelineStageFlag::VERTEX_SHADER"; } std::unreachable(); } @@ -2951,9 +2562,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::PixelFormat::A1_RGB5_UNORM_PACK16, stormkit::gpu::PixelFormat::A2_RGB10I_PACK32, stormkit::gpu::PixelFormat::A2_RGB10_SNORM_PACK32, @@ -3018,6 +2628,7 @@ export { stormkit::gpu::PixelFormat::RGBA8_SNORM, stormkit::gpu::PixelFormat::RGBA8U, stormkit::gpu::PixelFormat::RGBA8_UNORM, + stormkit::gpu::PixelFormat::S8U, stormkit::gpu::PixelFormat::SBGR8, stormkit::gpu::PixelFormat::SBGRA8, stormkit::gpu::PixelFormat::SR8, @@ -3032,34 +2643,23 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string(stormkit::gpu::PixelFormat - value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::PixelFormat value) noexcept + -> string_view { switch (value) { - case stormkit::gpu::PixelFormat::A1_RGB5_UNORM_PACK16: - return "PixelFormat::A1_RGB5_UNORM_PACK16"; - case stormkit::gpu::PixelFormat::A2_RGB10I_PACK32: - return "PixelFormat::A2_RGB10I_PACK32"; - case stormkit::gpu::PixelFormat::A2_RGB10_SNORM_PACK32: - return "PixelFormat::A2_RGB10_SNORM_PACK32"; - case stormkit::gpu::PixelFormat::A2_RGB10_UNORM_PACK32: - return "PixelFormat::A2_RGB10_UNORM_PACK32"; - case stormkit::gpu::PixelFormat::A2_RGB10U_PACK32: - return "PixelFormat::A2_RGB10U_PACK32"; - case stormkit::gpu::PixelFormat::B10_GR11UF_PACK32: - return "PixelFormat::B10_GR11UF_PACK32"; + case stormkit::gpu::PixelFormat::A1_RGB5_UNORM_PACK16: return "PixelFormat::A1_RGB5_UNORM_PACK16"; + case stormkit::gpu::PixelFormat::A2_RGB10I_PACK32: return "PixelFormat::A2_RGB10I_PACK32"; + case stormkit::gpu::PixelFormat::A2_RGB10_SNORM_PACK32: return "PixelFormat::A2_RGB10_SNORM_PACK32"; + case stormkit::gpu::PixelFormat::A2_RGB10_UNORM_PACK32: return "PixelFormat::A2_RGB10_UNORM_PACK32"; + case stormkit::gpu::PixelFormat::A2_RGB10U_PACK32: return "PixelFormat::A2_RGB10U_PACK32"; + case stormkit::gpu::PixelFormat::B10_GR11UF_PACK32: return "PixelFormat::B10_GR11UF_PACK32"; case stormkit::gpu::PixelFormat::BGR8_UNORM: return "PixelFormat::BGR8_UNORM"; case stormkit::gpu::PixelFormat::BGRA8_UNORM: return "PixelFormat::BGRA8_UNORM"; case stormkit::gpu::PixelFormat::DEPTH16_UNORM: return "PixelFormat::DEPTH16_UNORM"; - case stormkit::gpu::PixelFormat::DEPTH16_UNORM_STENCIL8U: - return "PixelFormat::DEPTH16_UNORM_STENCIL8U"; - case stormkit::gpu::PixelFormat::DEPTH24_UNORM_PACK32: - return "PixelFormat::DEPTH24_UNORM_PACK32"; - case stormkit::gpu::PixelFormat::DEPTH24_UNORM_STENCIL8U: - return "PixelFormat::DEPTH24_UNORM_STENCIL8U"; + case stormkit::gpu::PixelFormat::DEPTH16_UNORM_STENCIL8U: return "PixelFormat::DEPTH16_UNORM_STENCIL8U"; + case stormkit::gpu::PixelFormat::DEPTH24_UNORM_PACK32: return "PixelFormat::DEPTH24_UNORM_PACK32"; + case stormkit::gpu::PixelFormat::DEPTH24_UNORM_STENCIL8U: return "PixelFormat::DEPTH24_UNORM_STENCIL8U"; case stormkit::gpu::PixelFormat::DEPTH32F: return "PixelFormat::DEPTH32F"; - case stormkit::gpu::PixelFormat::DEPTH32F_STENCIL8U: - return "PixelFormat::DEPTH32F_STENCIL8U"; + case stormkit::gpu::PixelFormat::DEPTH32F_STENCIL8U: return "PixelFormat::DEPTH32F_STENCIL8U"; case stormkit::gpu::PixelFormat::R16F: return "PixelFormat::R16F"; case stormkit::gpu::PixelFormat::R16I: return "PixelFormat::R16I"; case stormkit::gpu::PixelFormat::R16_SNORM: return "PixelFormat::R16_SNORM"; @@ -3068,8 +2668,7 @@ export { case stormkit::gpu::PixelFormat::R32F: return "PixelFormat::R32F"; case stormkit::gpu::PixelFormat::R32I: return "PixelFormat::R32I"; case stormkit::gpu::PixelFormat::R32U: return "PixelFormat::R32U"; - case stormkit::gpu::PixelFormat::R5_G6_B5_UNORM_PACK16: - return "PixelFormat::R5_G6_B5_UNORM_PACK16"; + case stormkit::gpu::PixelFormat::R5_G6_B5_UNORM_PACK16: return "PixelFormat::R5_G6_B5_UNORM_PACK16"; case stormkit::gpu::PixelFormat::R8I: return "PixelFormat::R8I"; case stormkit::gpu::PixelFormat::R8_SNORM: return "PixelFormat::R8_SNORM"; case stormkit::gpu::PixelFormat::R8U: return "PixelFormat::R8U"; @@ -3106,12 +2705,12 @@ export { case stormkit::gpu::PixelFormat::RGBA32F: return "PixelFormat::RGBA32F"; case stormkit::gpu::PixelFormat::RGBA32I: return "PixelFormat::RGBA32I"; case stormkit::gpu::PixelFormat::RGBA32U: return "PixelFormat::RGBA32U"; - case stormkit::gpu::PixelFormat::RGBA4_UNORM_PACK16: - return "PixelFormat::RGBA4_UNORM_PACK16"; + case stormkit::gpu::PixelFormat::RGBA4_UNORM_PACK16: return "PixelFormat::RGBA4_UNORM_PACK16"; case stormkit::gpu::PixelFormat::RGBA8I: return "PixelFormat::RGBA8I"; case stormkit::gpu::PixelFormat::RGBA8_SNORM: return "PixelFormat::RGBA8_SNORM"; case stormkit::gpu::PixelFormat::RGBA8U: return "PixelFormat::RGBA8U"; case stormkit::gpu::PixelFormat::RGBA8_UNORM: return "PixelFormat::RGBA8_UNORM"; + case stormkit::gpu::PixelFormat::S8U: return "PixelFormat::S8U"; case stormkit::gpu::PixelFormat::SBGR8: return "PixelFormat::SBGR8"; case stormkit::gpu::PixelFormat::SBGRA8: return "PixelFormat::SBGRA8"; case stormkit::gpu::PixelFormat::SR8: return "PixelFormat::SR8"; @@ -3125,35 +2724,22 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string(stormkit::gpu::PixelFormat - value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::PixelFormat value) noexcept -> string { switch (value) { - case stormkit::gpu::PixelFormat::A1_RGB5_UNORM_PACK16: - return "PixelFormat::A1_RGB5_UNORM_PACK16"; - case stormkit::gpu::PixelFormat::A2_RGB10I_PACK32: - return "PixelFormat::A2_RGB10I_PACK32"; - case stormkit::gpu::PixelFormat::A2_RGB10_SNORM_PACK32: - return "PixelFormat::A2_RGB10_SNORM_PACK32"; - case stormkit::gpu::PixelFormat::A2_RGB10_UNORM_PACK32: - return "PixelFormat::A2_RGB10_UNORM_PACK32"; - case stormkit::gpu::PixelFormat::A2_RGB10U_PACK32: - return "PixelFormat::A2_RGB10U_PACK32"; - case stormkit::gpu::PixelFormat::B10_GR11UF_PACK32: - return "PixelFormat::B10_GR11UF_PACK32"; + case stormkit::gpu::PixelFormat::A1_RGB5_UNORM_PACK16: return "PixelFormat::A1_RGB5_UNORM_PACK16"; + case stormkit::gpu::PixelFormat::A2_RGB10I_PACK32: return "PixelFormat::A2_RGB10I_PACK32"; + case stormkit::gpu::PixelFormat::A2_RGB10_SNORM_PACK32: return "PixelFormat::A2_RGB10_SNORM_PACK32"; + case stormkit::gpu::PixelFormat::A2_RGB10_UNORM_PACK32: return "PixelFormat::A2_RGB10_UNORM_PACK32"; + case stormkit::gpu::PixelFormat::A2_RGB10U_PACK32: return "PixelFormat::A2_RGB10U_PACK32"; + case stormkit::gpu::PixelFormat::B10_GR11UF_PACK32: return "PixelFormat::B10_GR11UF_PACK32"; case stormkit::gpu::PixelFormat::BGR8_UNORM: return "PixelFormat::BGR8_UNORM"; case stormkit::gpu::PixelFormat::BGRA8_UNORM: return "PixelFormat::BGRA8_UNORM"; case stormkit::gpu::PixelFormat::DEPTH16_UNORM: return "PixelFormat::DEPTH16_UNORM"; - case stormkit::gpu::PixelFormat::DEPTH16_UNORM_STENCIL8U: - return "PixelFormat::DEPTH16_UNORM_STENCIL8U"; - case stormkit::gpu::PixelFormat::DEPTH24_UNORM_PACK32: - return "PixelFormat::DEPTH24_UNORM_PACK32"; - case stormkit::gpu::PixelFormat::DEPTH24_UNORM_STENCIL8U: - return "PixelFormat::DEPTH24_UNORM_STENCIL8U"; + case stormkit::gpu::PixelFormat::DEPTH16_UNORM_STENCIL8U: return "PixelFormat::DEPTH16_UNORM_STENCIL8U"; + case stormkit::gpu::PixelFormat::DEPTH24_UNORM_PACK32: return "PixelFormat::DEPTH24_UNORM_PACK32"; + case stormkit::gpu::PixelFormat::DEPTH24_UNORM_STENCIL8U: return "PixelFormat::DEPTH24_UNORM_STENCIL8U"; case stormkit::gpu::PixelFormat::DEPTH32F: return "PixelFormat::DEPTH32F"; - case stormkit::gpu::PixelFormat::DEPTH32F_STENCIL8U: - return "PixelFormat::DEPTH32F_STENCIL8U"; + case stormkit::gpu::PixelFormat::DEPTH32F_STENCIL8U: return "PixelFormat::DEPTH32F_STENCIL8U"; case stormkit::gpu::PixelFormat::R16F: return "PixelFormat::R16F"; case stormkit::gpu::PixelFormat::R16I: return "PixelFormat::R16I"; case stormkit::gpu::PixelFormat::R16_SNORM: return "PixelFormat::R16_SNORM"; @@ -3162,8 +2748,7 @@ export { case stormkit::gpu::PixelFormat::R32F: return "PixelFormat::R32F"; case stormkit::gpu::PixelFormat::R32I: return "PixelFormat::R32I"; case stormkit::gpu::PixelFormat::R32U: return "PixelFormat::R32U"; - case stormkit::gpu::PixelFormat::R5_G6_B5_UNORM_PACK16: - return "PixelFormat::R5_G6_B5_UNORM_PACK16"; + case stormkit::gpu::PixelFormat::R5_G6_B5_UNORM_PACK16: return "PixelFormat::R5_G6_B5_UNORM_PACK16"; case stormkit::gpu::PixelFormat::R8I: return "PixelFormat::R8I"; case stormkit::gpu::PixelFormat::R8_SNORM: return "PixelFormat::R8_SNORM"; case stormkit::gpu::PixelFormat::R8U: return "PixelFormat::R8U"; @@ -3200,12 +2785,12 @@ export { case stormkit::gpu::PixelFormat::RGBA32F: return "PixelFormat::RGBA32F"; case stormkit::gpu::PixelFormat::RGBA32I: return "PixelFormat::RGBA32I"; case stormkit::gpu::PixelFormat::RGBA32U: return "PixelFormat::RGBA32U"; - case stormkit::gpu::PixelFormat::RGBA4_UNORM_PACK16: - return "PixelFormat::RGBA4_UNORM_PACK16"; + case stormkit::gpu::PixelFormat::RGBA4_UNORM_PACK16: return "PixelFormat::RGBA4_UNORM_PACK16"; case stormkit::gpu::PixelFormat::RGBA8I: return "PixelFormat::RGBA8I"; case stormkit::gpu::PixelFormat::RGBA8_SNORM: return "PixelFormat::RGBA8_SNORM"; case stormkit::gpu::PixelFormat::RGBA8U: return "PixelFormat::RGBA8U"; case stormkit::gpu::PixelFormat::RGBA8_UNORM: return "PixelFormat::RGBA8_UNORM"; + case stormkit::gpu::PixelFormat::S8U: return "PixelFormat::S8U"; case stormkit::gpu::PixelFormat::SBGR8: return "PixelFormat::SBGR8"; case stormkit::gpu::PixelFormat::SBGRA8: return "PixelFormat::SBGRA8"; case stormkit::gpu::PixelFormat::SR8: return "PixelFormat::SR8"; @@ -3221,9 +2806,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::PolygonMode::FILL, stormkit::gpu::PolygonMode::LINE, stormkit::gpu::PolygonMode::POINT, @@ -3234,9 +2818,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string(stormkit::gpu::PolygonMode - value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::PolygonMode value) noexcept + -> string_view { switch (value) { case stormkit::gpu::PolygonMode::FILL: return "PolygonMode::FILL"; case stormkit::gpu::PolygonMode::LINE: return "PolygonMode::LINE"; @@ -3247,10 +2830,7 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string(stormkit::gpu::PolygonMode - value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::PolygonMode value) noexcept -> string { switch (value) { case stormkit::gpu::PolygonMode::FILL: return "PolygonMode::FILL"; case stormkit::gpu::PolygonMode::LINE: return "PolygonMode::LINE"; @@ -3263,9 +2843,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::PresentMode::FIFO, stormkit::gpu::PresentMode::FIFO_RELAXED, stormkit::gpu::PresentMode::IMMEDIATE, @@ -3279,37 +2858,29 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string(stormkit::gpu::PresentMode - value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::PresentMode value) noexcept + -> string_view { switch (value) { case stormkit::gpu::PresentMode::FIFO: return "PresentMode::FIFO"; case stormkit::gpu::PresentMode::FIFO_RELAXED: return "PresentMode::FIFO_RELAXED"; case stormkit::gpu::PresentMode::IMMEDIATE: return "PresentMode::IMMEDIATE"; case stormkit::gpu::PresentMode::MAILBOX: return "PresentMode::MAILBOX"; - case stormkit::gpu::PresentMode::SHARED_CONTINUOUS_REFRESH: - return "PresentMode::SHARED_CONTINUOUS_REFRESH"; - case stormkit::gpu::PresentMode::SHARED_DEMAND_REFRESH: - return "PresentMode::SHARED_DEMAND_REFRESH"; + case stormkit::gpu::PresentMode::SHARED_CONTINUOUS_REFRESH: return "PresentMode::SHARED_CONTINUOUS_REFRESH"; + case stormkit::gpu::PresentMode::SHARED_DEMAND_REFRESH: return "PresentMode::SHARED_DEMAND_REFRESH"; } std::unreachable(); } template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string(stormkit::gpu::PresentMode - value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::PresentMode value) noexcept -> string { switch (value) { case stormkit::gpu::PresentMode::FIFO: return "PresentMode::FIFO"; case stormkit::gpu::PresentMode::FIFO_RELAXED: return "PresentMode::FIFO_RELAXED"; case stormkit::gpu::PresentMode::IMMEDIATE: return "PresentMode::IMMEDIATE"; case stormkit::gpu::PresentMode::MAILBOX: return "PresentMode::MAILBOX"; - case stormkit::gpu::PresentMode::SHARED_CONTINUOUS_REFRESH: - return "PresentMode::SHARED_CONTINUOUS_REFRESH"; - case stormkit::gpu::PresentMode::SHARED_DEMAND_REFRESH: - return "PresentMode::SHARED_DEMAND_REFRESH"; + case stormkit::gpu::PresentMode::SHARED_CONTINUOUS_REFRESH: return "PresentMode::SHARED_CONTINUOUS_REFRESH"; + case stormkit::gpu::PresentMode::SHARED_DEMAND_REFRESH: return "PresentMode::SHARED_DEMAND_REFRESH"; } std::unreachable(); } @@ -3318,15 +2889,11 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { - stormkit::gpu::PrimitiveTopology::LINE_LIST, - stormkit::gpu::PrimitiveTopology::LINE_STRIP, - stormkit::gpu::PrimitiveTopology::POINT_LIST, - stormkit::gpu::PrimitiveTopology::TRIANGLE_FAN, - stormkit::gpu::PrimitiveTopology::TRIANGLE_LIST, - stormkit::gpu::PrimitiveTopology::TRIANGLE_STRIP, + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { + stormkit::gpu::PrimitiveTopology::LINE_LIST, stormkit::gpu::PrimitiveTopology::LINE_STRIP, + stormkit::gpu::PrimitiveTopology::POINT_LIST, stormkit::gpu::PrimitiveTopology::TRIANGLE_FAN, + stormkit::gpu::PrimitiveTopology::TRIANGLE_LIST, stormkit::gpu::PrimitiveTopology::TRIANGLE_STRIP, }; } @@ -3334,43 +2901,30 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string< - stormkit::gpu::PrimitiveTopology>(stormkit::gpu::PrimitiveTopology value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::PrimitiveTopology value) noexcept + -> string_view { switch (value) { case stormkit::gpu::PrimitiveTopology::LINE_LIST: return "PrimitiveTopology::LINE_LIST"; - case stormkit::gpu::PrimitiveTopology::LINE_STRIP: - return "PrimitiveTopology::LINE_STRIP"; - case stormkit::gpu::PrimitiveTopology::POINT_LIST: - return "PrimitiveTopology::POINT_LIST"; - case stormkit::gpu::PrimitiveTopology::TRIANGLE_FAN: - return "PrimitiveTopology::TRIANGLE_FAN"; - case stormkit::gpu::PrimitiveTopology::TRIANGLE_LIST: - return "PrimitiveTopology::TRIANGLE_LIST"; - case stormkit::gpu::PrimitiveTopology::TRIANGLE_STRIP: - return "PrimitiveTopology::TRIANGLE_STRIP"; + case stormkit::gpu::PrimitiveTopology::LINE_STRIP: return "PrimitiveTopology::LINE_STRIP"; + case stormkit::gpu::PrimitiveTopology::POINT_LIST: return "PrimitiveTopology::POINT_LIST"; + case stormkit::gpu::PrimitiveTopology::TRIANGLE_FAN: return "PrimitiveTopology::TRIANGLE_FAN"; + case stormkit::gpu::PrimitiveTopology::TRIANGLE_LIST: return "PrimitiveTopology::TRIANGLE_LIST"; + case stormkit::gpu::PrimitiveTopology::TRIANGLE_STRIP: return "PrimitiveTopology::TRIANGLE_STRIP"; } std::unreachable(); } template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string< - stormkit::gpu::PrimitiveTopology>(stormkit::gpu::PrimitiveTopology value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::PrimitiveTopology value) noexcept + -> string { switch (value) { case stormkit::gpu::PrimitiveTopology::LINE_LIST: return "PrimitiveTopology::LINE_LIST"; - case stormkit::gpu::PrimitiveTopology::LINE_STRIP: - return "PrimitiveTopology::LINE_STRIP"; - case stormkit::gpu::PrimitiveTopology::POINT_LIST: - return "PrimitiveTopology::POINT_LIST"; - case stormkit::gpu::PrimitiveTopology::TRIANGLE_FAN: - return "PrimitiveTopology::TRIANGLE_FAN"; - case stormkit::gpu::PrimitiveTopology::TRIANGLE_LIST: - return "PrimitiveTopology::TRIANGLE_LIST"; - case stormkit::gpu::PrimitiveTopology::TRIANGLE_STRIP: - return "PrimitiveTopology::TRIANGLE_STRIP"; + case stormkit::gpu::PrimitiveTopology::LINE_STRIP: return "PrimitiveTopology::LINE_STRIP"; + case stormkit::gpu::PrimitiveTopology::POINT_LIST: return "PrimitiveTopology::POINT_LIST"; + case stormkit::gpu::PrimitiveTopology::TRIANGLE_FAN: return "PrimitiveTopology::TRIANGLE_FAN"; + case stormkit::gpu::PrimitiveTopology::TRIANGLE_LIST: return "PrimitiveTopology::TRIANGLE_LIST"; + case stormkit::gpu::PrimitiveTopology::TRIANGLE_STRIP: return "PrimitiveTopology::TRIANGLE_STRIP"; } std::unreachable(); } @@ -3379,12 +2933,10 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { - stormkit::gpu::QueueFlag::COMPUTE, stormkit::gpu::QueueFlag::GRAPHICS, - stormkit::gpu::QueueFlag::NONE, stormkit::gpu::QueueFlag::PROTECTED, - stormkit::gpu::QueueFlag::SPARSE_BINDING, stormkit::gpu::QueueFlag::TRANSFER, + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { + stormkit::gpu::QueueFlag::COMPUTE, stormkit::gpu::QueueFlag::GRAPHICS, stormkit::gpu::QueueFlag::NONE, + stormkit::gpu::QueueFlag::PROTECTED, stormkit::gpu::QueueFlag::SPARSE_BINDING, stormkit::gpu::QueueFlag::TRANSFER, }; } @@ -3392,9 +2944,7 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string(stormkit::gpu::QueueFlag - value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::QueueFlag value) noexcept -> string_view { switch (value) { case stormkit::gpu::QueueFlag::COMPUTE: return "QueueFlag::COMPUTE"; case stormkit::gpu::QueueFlag::GRAPHICS: return "QueueFlag::GRAPHICS"; @@ -3408,10 +2958,7 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string(stormkit::gpu::QueueFlag - value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::QueueFlag value) noexcept -> string { switch (value) { case stormkit::gpu::QueueFlag::COMPUTE: return "QueueFlag::COMPUTE"; case stormkit::gpu::QueueFlag::GRAPHICS: return "QueueFlag::GRAPHICS"; @@ -3422,14 +2969,59 @@ export { } std::unreachable(); } + FLAG_ENUM(stormkit::gpu::ResolveModeFlag) + + template<> + STORMKIT_FORCE_INLINE + STORMKIT_CONST + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { + stormkit::gpu::ResolveModeFlag::AVERAGE, stormkit::gpu::ResolveModeFlag::EXTERNAL_FORMAT_DOWNSAMPLE_ANDROID, + stormkit::gpu::ResolveModeFlag::MAX, stormkit::gpu::ResolveModeFlag::MIN, + stormkit::gpu::ResolveModeFlag::NONE, stormkit::gpu::ResolveModeFlag::SAMPLE_ZERO, + + }; + } + + template<> + STORMKIT_FORCE_INLINE + STORMKIT_CONST + constexpr auto stormkit::core::as_string(stormkit::gpu::ResolveModeFlag value) noexcept + -> string_view { + switch (value) { + case stormkit::gpu::ResolveModeFlag::AVERAGE: return "ResolveModeFlag::AVERAGE"; + case stormkit::gpu::ResolveModeFlag::EXTERNAL_FORMAT_DOWNSAMPLE_ANDROID: + return "ResolveModeFlag::EXTERNAL_FORMAT_DOWNSAMPLE_ANDROID"; + case stormkit::gpu::ResolveModeFlag::MAX: return "ResolveModeFlag::MAX"; + case stormkit::gpu::ResolveModeFlag::MIN: return "ResolveModeFlag::MIN"; + case stormkit::gpu::ResolveModeFlag::NONE: return "ResolveModeFlag::NONE"; + case stormkit::gpu::ResolveModeFlag::SAMPLE_ZERO: return "ResolveModeFlag::SAMPLE_ZERO"; + } + std::unreachable(); + } + + template<> + STORMKIT_FORCE_INLINE + constexpr auto stormkit::core::to_string(stormkit::gpu::ResolveModeFlag value) noexcept + -> string { + switch (value) { + case stormkit::gpu::ResolveModeFlag::AVERAGE: return "ResolveModeFlag::AVERAGE"; + case stormkit::gpu::ResolveModeFlag::EXTERNAL_FORMAT_DOWNSAMPLE_ANDROID: + return "ResolveModeFlag::EXTERNAL_FORMAT_DOWNSAMPLE_ANDROID"; + case stormkit::gpu::ResolveModeFlag::MAX: return "ResolveModeFlag::MAX"; + case stormkit::gpu::ResolveModeFlag::MIN: return "ResolveModeFlag::MIN"; + case stormkit::gpu::ResolveModeFlag::NONE: return "ResolveModeFlag::NONE"; + case stormkit::gpu::ResolveModeFlag::SAMPLE_ZERO: return "ResolveModeFlag::SAMPLE_ZERO"; + } + std::unreachable(); + } FLAG_ENUM(stormkit::gpu::Result) template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::Result::ERROR_DEVICE_LOST, stormkit::gpu::Result::ERROR_EXTENSION_NOT_PRESENT, stormkit::gpu::Result::ERROR_FEATURE_NOT_PRESENT, @@ -3473,61 +3065,41 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string(stormkit::gpu::Result - value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::Result value) noexcept -> string_view { switch (value) { case stormkit::gpu::Result::ERROR_DEVICE_LOST: return "Result::ERROR_DEVICE_LOST"; - case stormkit::gpu::Result::ERROR_EXTENSION_NOT_PRESENT: - return "Result::ERROR_EXTENSION_NOT_PRESENT"; - case stormkit::gpu::Result::ERROR_FEATURE_NOT_PRESENT: - return "Result::ERROR_FEATURE_NOT_PRESENT"; - case stormkit::gpu::Result::ERROR_FORMAT_NOT_SUPPORTED: - return "Result::ERROR_FORMAT_NOT_SUPPORTED"; + case stormkit::gpu::Result::ERROR_EXTENSION_NOT_PRESENT: return "Result::ERROR_EXTENSION_NOT_PRESENT"; + case stormkit::gpu::Result::ERROR_FEATURE_NOT_PRESENT: return "Result::ERROR_FEATURE_NOT_PRESENT"; + case stormkit::gpu::Result::ERROR_FORMAT_NOT_SUPPORTED: return "Result::ERROR_FORMAT_NOT_SUPPORTED"; case stormkit::gpu::Result::ERROR_FRAGMENTATION: return "Result::ERROR_FRAGMENTATION"; - case stormkit::gpu::Result::ERROR_FRAGMENTED_POOL: - return "Result::ERROR_FRAGMENTED_POOL"; + case stormkit::gpu::Result::ERROR_FRAGMENTED_POOL: return "Result::ERROR_FRAGMENTED_POOL"; case stormkit::gpu::Result::ERROR_FULLSCREEN_EXCLUSIVE_MODE_LOST: return "Result::ERROR_FULLSCREEN_EXCLUSIVE_MODE_LOST"; - case stormkit::gpu::Result::ERROR_INCOMPATIBLE_DISPLAY: - return "Result::ERROR_INCOMPATIBLE_DISPLAY"; - case stormkit::gpu::Result::ERROR_INCOMPATIBLE_DRIVER: - return "Result::ERROR_INCOMPATIBLE_DRIVER"; - case stormkit::gpu::Result::ERROR_INITIALIZATION_FAILED: - return "Result::ERROR_INITIALIZATION_FAILED"; - case stormkit::gpu::Result::ERROR_INVALID_EXTERNAL_HANDLE: - return "Result::ERROR_INVALID_EXTERNAL_HANDLE"; + case stormkit::gpu::Result::ERROR_INCOMPATIBLE_DISPLAY: return "Result::ERROR_INCOMPATIBLE_DISPLAY"; + case stormkit::gpu::Result::ERROR_INCOMPATIBLE_DRIVER: return "Result::ERROR_INCOMPATIBLE_DRIVER"; + case stormkit::gpu::Result::ERROR_INITIALIZATION_FAILED: return "Result::ERROR_INITIALIZATION_FAILED"; + case stormkit::gpu::Result::ERROR_INVALID_EXTERNAL_HANDLE: return "Result::ERROR_INVALID_EXTERNAL_HANDLE"; case stormkit::gpu::Result::ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS: return "Result::ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS"; - case stormkit::gpu::Result::ERROR_LAYER_NOT_PRESENT: - return "Result::ERROR_LAYER_NOT_PRESENT"; - case stormkit::gpu::Result::ERROR_MEMORY_MAP_FAILED: - return "Result::ERROR_MEMORY_MAP_FAILED"; - case stormkit::gpu::Result::ERROR_NATIVE_WINDOW_IN_USE: - return "Result::ERROR_NATIVE_WINDOW_IN_USE"; + case stormkit::gpu::Result::ERROR_LAYER_NOT_PRESENT: return "Result::ERROR_LAYER_NOT_PRESENT"; + case stormkit::gpu::Result::ERROR_MEMORY_MAP_FAILED: return "Result::ERROR_MEMORY_MAP_FAILED"; + case stormkit::gpu::Result::ERROR_NATIVE_WINDOW_IN_USE: return "Result::ERROR_NATIVE_WINDOW_IN_USE"; case stormkit::gpu::Result::ERROR_NOT_PERMITTED: return "Result::ERROR_NOT_PERMITTED"; case stormkit::gpu::Result::ERROR_OUT_OF_DATE: return "Result::ERROR_OUT_OF_DATE"; - case stormkit::gpu::Result::ERROR_OUT_OF_DEVICE_MEMORY: - return "Result::ERROR_OUT_OF_DEVICE_MEMORY"; - case stormkit::gpu::Result::ERROR_OUT_OF_HOST_MEMORY: - return "Result::ERROR_OUT_OF_HOST_MEMORY"; - case stormkit::gpu::Result::ERROR_OUT_OF_POOL_MEMORY: - return "Result::ERROR_OUT_OF_POOL_MEMORY"; + case stormkit::gpu::Result::ERROR_OUT_OF_DEVICE_MEMORY: return "Result::ERROR_OUT_OF_DEVICE_MEMORY"; + case stormkit::gpu::Result::ERROR_OUT_OF_HOST_MEMORY: return "Result::ERROR_OUT_OF_HOST_MEMORY"; + case stormkit::gpu::Result::ERROR_OUT_OF_POOL_MEMORY: return "Result::ERROR_OUT_OF_POOL_MEMORY"; case stormkit::gpu::Result::ERROR_SURFACE_LOST: return "Result::ERROR_SURFACE_LOST"; - case stormkit::gpu::Result::ERROR_TOO_MANY_OBJECTS: - return "Result::ERROR_TOO_MANY_OBJECTS"; + case stormkit::gpu::Result::ERROR_TOO_MANY_OBJECTS: return "Result::ERROR_TOO_MANY_OBJECTS"; case stormkit::gpu::Result::ERROR_UNKNOWN: return "Result::ERROR_UNKNOWN"; - case stormkit::gpu::Result::ERROR_VALIDATION_FAILED: - return "Result::ERROR_VALIDATION_FAILED"; + case stormkit::gpu::Result::ERROR_VALIDATION_FAILED: return "Result::ERROR_VALIDATION_FAILED"; case stormkit::gpu::Result::EVENT_RESET: return "Result::EVENT_RESET"; case stormkit::gpu::Result::EVENT_SET: return "Result::EVENT_SET"; case stormkit::gpu::Result::INCOMPLETE: return "Result::INCOMPLETE"; case stormkit::gpu::Result::NOT_READY: return "Result::NOT_READY"; case stormkit::gpu::Result::OPERATION_DEFERRED: return "Result::OPERATION_DEFERRED"; - case stormkit::gpu::Result::OPERATION_NOT_DEFERRED: - return "Result::OPERATION_NOT_DEFERRED"; - case stormkit::gpu::Result::PIPELINE_COMPILE_REQUIRED: - return "Result::PIPELINE_COMPILE_REQUIRED"; + case stormkit::gpu::Result::OPERATION_NOT_DEFERRED: return "Result::OPERATION_NOT_DEFERRED"; + case stormkit::gpu::Result::PIPELINE_COMPILE_REQUIRED: return "Result::PIPELINE_COMPILE_REQUIRED"; case stormkit::gpu::Result::SUBOPTIMAL: return "Result::SUBOPTIMAL"; case stormkit::gpu::Result::SUCCESS: return "Result::SUCCESS"; case stormkit::gpu::Result::THREAD_DONE: return "Result::THREAD_DONE"; @@ -3539,62 +3111,41 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string(stormkit::gpu::Result - value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::Result value) noexcept -> string { switch (value) { case stormkit::gpu::Result::ERROR_DEVICE_LOST: return "Result::ERROR_DEVICE_LOST"; - case stormkit::gpu::Result::ERROR_EXTENSION_NOT_PRESENT: - return "Result::ERROR_EXTENSION_NOT_PRESENT"; - case stormkit::gpu::Result::ERROR_FEATURE_NOT_PRESENT: - return "Result::ERROR_FEATURE_NOT_PRESENT"; - case stormkit::gpu::Result::ERROR_FORMAT_NOT_SUPPORTED: - return "Result::ERROR_FORMAT_NOT_SUPPORTED"; + case stormkit::gpu::Result::ERROR_EXTENSION_NOT_PRESENT: return "Result::ERROR_EXTENSION_NOT_PRESENT"; + case stormkit::gpu::Result::ERROR_FEATURE_NOT_PRESENT: return "Result::ERROR_FEATURE_NOT_PRESENT"; + case stormkit::gpu::Result::ERROR_FORMAT_NOT_SUPPORTED: return "Result::ERROR_FORMAT_NOT_SUPPORTED"; case stormkit::gpu::Result::ERROR_FRAGMENTATION: return "Result::ERROR_FRAGMENTATION"; - case stormkit::gpu::Result::ERROR_FRAGMENTED_POOL: - return "Result::ERROR_FRAGMENTED_POOL"; + case stormkit::gpu::Result::ERROR_FRAGMENTED_POOL: return "Result::ERROR_FRAGMENTED_POOL"; case stormkit::gpu::Result::ERROR_FULLSCREEN_EXCLUSIVE_MODE_LOST: return "Result::ERROR_FULLSCREEN_EXCLUSIVE_MODE_LOST"; - case stormkit::gpu::Result::ERROR_INCOMPATIBLE_DISPLAY: - return "Result::ERROR_INCOMPATIBLE_DISPLAY"; - case stormkit::gpu::Result::ERROR_INCOMPATIBLE_DRIVER: - return "Result::ERROR_INCOMPATIBLE_DRIVER"; - case stormkit::gpu::Result::ERROR_INITIALIZATION_FAILED: - return "Result::ERROR_INITIALIZATION_FAILED"; - case stormkit::gpu::Result::ERROR_INVALID_EXTERNAL_HANDLE: - return "Result::ERROR_INVALID_EXTERNAL_HANDLE"; + case stormkit::gpu::Result::ERROR_INCOMPATIBLE_DISPLAY: return "Result::ERROR_INCOMPATIBLE_DISPLAY"; + case stormkit::gpu::Result::ERROR_INCOMPATIBLE_DRIVER: return "Result::ERROR_INCOMPATIBLE_DRIVER"; + case stormkit::gpu::Result::ERROR_INITIALIZATION_FAILED: return "Result::ERROR_INITIALIZATION_FAILED"; + case stormkit::gpu::Result::ERROR_INVALID_EXTERNAL_HANDLE: return "Result::ERROR_INVALID_EXTERNAL_HANDLE"; case stormkit::gpu::Result::ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS: return "Result::ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS"; - case stormkit::gpu::Result::ERROR_LAYER_NOT_PRESENT: - return "Result::ERROR_LAYER_NOT_PRESENT"; - case stormkit::gpu::Result::ERROR_MEMORY_MAP_FAILED: - return "Result::ERROR_MEMORY_MAP_FAILED"; - case stormkit::gpu::Result::ERROR_NATIVE_WINDOW_IN_USE: - return "Result::ERROR_NATIVE_WINDOW_IN_USE"; + case stormkit::gpu::Result::ERROR_LAYER_NOT_PRESENT: return "Result::ERROR_LAYER_NOT_PRESENT"; + case stormkit::gpu::Result::ERROR_MEMORY_MAP_FAILED: return "Result::ERROR_MEMORY_MAP_FAILED"; + case stormkit::gpu::Result::ERROR_NATIVE_WINDOW_IN_USE: return "Result::ERROR_NATIVE_WINDOW_IN_USE"; case stormkit::gpu::Result::ERROR_NOT_PERMITTED: return "Result::ERROR_NOT_PERMITTED"; case stormkit::gpu::Result::ERROR_OUT_OF_DATE: return "Result::ERROR_OUT_OF_DATE"; - case stormkit::gpu::Result::ERROR_OUT_OF_DEVICE_MEMORY: - return "Result::ERROR_OUT_OF_DEVICE_MEMORY"; - case stormkit::gpu::Result::ERROR_OUT_OF_HOST_MEMORY: - return "Result::ERROR_OUT_OF_HOST_MEMORY"; - case stormkit::gpu::Result::ERROR_OUT_OF_POOL_MEMORY: - return "Result::ERROR_OUT_OF_POOL_MEMORY"; + case stormkit::gpu::Result::ERROR_OUT_OF_DEVICE_MEMORY: return "Result::ERROR_OUT_OF_DEVICE_MEMORY"; + case stormkit::gpu::Result::ERROR_OUT_OF_HOST_MEMORY: return "Result::ERROR_OUT_OF_HOST_MEMORY"; + case stormkit::gpu::Result::ERROR_OUT_OF_POOL_MEMORY: return "Result::ERROR_OUT_OF_POOL_MEMORY"; case stormkit::gpu::Result::ERROR_SURFACE_LOST: return "Result::ERROR_SURFACE_LOST"; - case stormkit::gpu::Result::ERROR_TOO_MANY_OBJECTS: - return "Result::ERROR_TOO_MANY_OBJECTS"; + case stormkit::gpu::Result::ERROR_TOO_MANY_OBJECTS: return "Result::ERROR_TOO_MANY_OBJECTS"; case stormkit::gpu::Result::ERROR_UNKNOWN: return "Result::ERROR_UNKNOWN"; - case stormkit::gpu::Result::ERROR_VALIDATION_FAILED: - return "Result::ERROR_VALIDATION_FAILED"; + case stormkit::gpu::Result::ERROR_VALIDATION_FAILED: return "Result::ERROR_VALIDATION_FAILED"; case stormkit::gpu::Result::EVENT_RESET: return "Result::EVENT_RESET"; case stormkit::gpu::Result::EVENT_SET: return "Result::EVENT_SET"; case stormkit::gpu::Result::INCOMPLETE: return "Result::INCOMPLETE"; case stormkit::gpu::Result::NOT_READY: return "Result::NOT_READY"; case stormkit::gpu::Result::OPERATION_DEFERRED: return "Result::OPERATION_DEFERRED"; - case stormkit::gpu::Result::OPERATION_NOT_DEFERRED: - return "Result::OPERATION_NOT_DEFERRED"; - case stormkit::gpu::Result::PIPELINE_COMPILE_REQUIRED: - return "Result::PIPELINE_COMPILE_REQUIRED"; + case stormkit::gpu::Result::OPERATION_NOT_DEFERRED: return "Result::OPERATION_NOT_DEFERRED"; + case stormkit::gpu::Result::PIPELINE_COMPILE_REQUIRED: return "Result::PIPELINE_COMPILE_REQUIRED"; case stormkit::gpu::Result::SUBOPTIMAL: return "Result::SUBOPTIMAL"; case stormkit::gpu::Result::SUCCESS: return "Result::SUCCESS"; case stormkit::gpu::Result::THREAD_DONE: return "Result::THREAD_DONE"; @@ -3608,12 +3159,10 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { - stormkit::gpu::SampleCountFlag::C1, stormkit::gpu::SampleCountFlag::C16, - stormkit::gpu::SampleCountFlag::C2, stormkit::gpu::SampleCountFlag::C32, - stormkit::gpu::SampleCountFlag::C4, stormkit::gpu::SampleCountFlag::C64, + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { + stormkit::gpu::SampleCountFlag::C1, stormkit::gpu::SampleCountFlag::C16, stormkit::gpu::SampleCountFlag::C2, + stormkit::gpu::SampleCountFlag::C32, stormkit::gpu::SampleCountFlag::C4, stormkit::gpu::SampleCountFlag::C64, stormkit::gpu::SampleCountFlag::C8, }; @@ -3622,9 +3171,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string< - stormkit::gpu::SampleCountFlag>(stormkit::gpu::SampleCountFlag value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::SampleCountFlag value) noexcept + -> string_view { switch (value) { case stormkit::gpu::SampleCountFlag::C1: return "SampleCountFlag::C1"; case stormkit::gpu::SampleCountFlag::C16: return "SampleCountFlag::C16"; @@ -3639,10 +3187,8 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string< - stormkit::gpu::SampleCountFlag>(stormkit::gpu::SampleCountFlag value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::SampleCountFlag value) noexcept + -> string { switch (value) { case stormkit::gpu::SampleCountFlag::C1: return "SampleCountFlag::C1"; case stormkit::gpu::SampleCountFlag::C16: return "SampleCountFlag::C16"; @@ -3659,9 +3205,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::SamplerAddressMode::CLAMP_TO_BORDER, stormkit::gpu::SamplerAddressMode::CLAMP_TO_EDGE, stormkit::gpu::SamplerAddressMode::MIRROR_CLAMP_TO_EDGE, @@ -3674,18 +3219,13 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string< - stormkit::gpu::SamplerAddressMode>(stormkit::gpu::SamplerAddressMode value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::SamplerAddressMode value) noexcept + -> string_view { switch (value) { - case stormkit::gpu::SamplerAddressMode::CLAMP_TO_BORDER: - return "SamplerAddressMode::CLAMP_TO_BORDER"; - case stormkit::gpu::SamplerAddressMode::CLAMP_TO_EDGE: - return "SamplerAddressMode::CLAMP_TO_EDGE"; - case stormkit::gpu::SamplerAddressMode::MIRROR_CLAMP_TO_EDGE: - return "SamplerAddressMode::MIRROR_CLAMP_TO_EDGE"; - case stormkit::gpu::SamplerAddressMode::MIRRORED_REPEAT: - return "SamplerAddressMode::MIRRORED_REPEAT"; + case stormkit::gpu::SamplerAddressMode::CLAMP_TO_BORDER: return "SamplerAddressMode::CLAMP_TO_BORDER"; + case stormkit::gpu::SamplerAddressMode::CLAMP_TO_EDGE: return "SamplerAddressMode::CLAMP_TO_EDGE"; + case stormkit::gpu::SamplerAddressMode::MIRROR_CLAMP_TO_EDGE: return "SamplerAddressMode::MIRROR_CLAMP_TO_EDGE"; + case stormkit::gpu::SamplerAddressMode::MIRRORED_REPEAT: return "SamplerAddressMode::MIRRORED_REPEAT"; case stormkit::gpu::SamplerAddressMode::REPEAT: return "SamplerAddressMode::REPEAT"; } std::unreachable(); @@ -3693,19 +3233,13 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string< - stormkit::gpu::SamplerAddressMode>(stormkit::gpu::SamplerAddressMode value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::SamplerAddressMode value) noexcept + -> string { switch (value) { - case stormkit::gpu::SamplerAddressMode::CLAMP_TO_BORDER: - return "SamplerAddressMode::CLAMP_TO_BORDER"; - case stormkit::gpu::SamplerAddressMode::CLAMP_TO_EDGE: - return "SamplerAddressMode::CLAMP_TO_EDGE"; - case stormkit::gpu::SamplerAddressMode::MIRROR_CLAMP_TO_EDGE: - return "SamplerAddressMode::MIRROR_CLAMP_TO_EDGE"; - case stormkit::gpu::SamplerAddressMode::MIRRORED_REPEAT: - return "SamplerAddressMode::MIRRORED_REPEAT"; + case stormkit::gpu::SamplerAddressMode::CLAMP_TO_BORDER: return "SamplerAddressMode::CLAMP_TO_BORDER"; + case stormkit::gpu::SamplerAddressMode::CLAMP_TO_EDGE: return "SamplerAddressMode::CLAMP_TO_EDGE"; + case stormkit::gpu::SamplerAddressMode::MIRROR_CLAMP_TO_EDGE: return "SamplerAddressMode::MIRROR_CLAMP_TO_EDGE"; + case stormkit::gpu::SamplerAddressMode::MIRRORED_REPEAT: return "SamplerAddressMode::MIRRORED_REPEAT"; case stormkit::gpu::SamplerAddressMode::REPEAT: return "SamplerAddressMode::REPEAT"; } std::unreachable(); @@ -3715,9 +3249,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::SamplerMipmapMode::LINEAR, stormkit::gpu::SamplerMipmapMode::NEAREST, @@ -3727,9 +3260,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string< - stormkit::gpu::SamplerMipmapMode>(stormkit::gpu::SamplerMipmapMode value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::SamplerMipmapMode value) noexcept + -> string_view { switch (value) { case stormkit::gpu::SamplerMipmapMode::LINEAR: return "SamplerMipmapMode::LINEAR"; case stormkit::gpu::SamplerMipmapMode::NEAREST: return "SamplerMipmapMode::NEAREST"; @@ -3739,10 +3271,8 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string< - stormkit::gpu::SamplerMipmapMode>(stormkit::gpu::SamplerMipmapMode value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::SamplerMipmapMode value) noexcept + -> string { switch (value) { case stormkit::gpu::SamplerMipmapMode::LINEAR: return "SamplerMipmapMode::LINEAR"; case stormkit::gpu::SamplerMipmapMode::NEAREST: return "SamplerMipmapMode::NEAREST"; @@ -3754,9 +3284,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::ShaderStageFlag::COMPUTE, stormkit::gpu::ShaderStageFlag::FRAGMENT, stormkit::gpu::ShaderStageFlag::GEOMETRY, stormkit::gpu::ShaderStageFlag::NONE, stormkit::gpu::ShaderStageFlag::VERTEX, @@ -3767,9 +3296,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string< - stormkit::gpu::ShaderStageFlag>(stormkit::gpu::ShaderStageFlag value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::ShaderStageFlag value) noexcept + -> string_view { switch (value) { case stormkit::gpu::ShaderStageFlag::COMPUTE: return "ShaderStageFlag::COMPUTE"; case stormkit::gpu::ShaderStageFlag::FRAGMENT: return "ShaderStageFlag::FRAGMENT"; @@ -3782,10 +3310,8 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string< - stormkit::gpu::ShaderStageFlag>(stormkit::gpu::ShaderStageFlag value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::ShaderStageFlag value) noexcept + -> string { switch (value) { case stormkit::gpu::ShaderStageFlag::COMPUTE: return "ShaderStageFlag::COMPUTE"; case stormkit::gpu::ShaderStageFlag::FRAGMENT: return "ShaderStageFlag::FRAGMENT"; @@ -3800,9 +3326,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::StencilFaceFlag::BACK, stormkit::gpu::StencilFaceFlag::FRONT, stormkit::gpu::StencilFaceFlag::FRONT_AND_BACK, @@ -3813,29 +3338,24 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string< - stormkit::gpu::StencilFaceFlag>(stormkit::gpu::StencilFaceFlag value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::StencilFaceFlag value) noexcept + -> string_view { switch (value) { case stormkit::gpu::StencilFaceFlag::BACK: return "StencilFaceFlag::BACK"; case stormkit::gpu::StencilFaceFlag::FRONT: return "StencilFaceFlag::FRONT"; - case stormkit::gpu::StencilFaceFlag::FRONT_AND_BACK: - return "StencilFaceFlag::FRONT_AND_BACK"; + case stormkit::gpu::StencilFaceFlag::FRONT_AND_BACK: return "StencilFaceFlag::FRONT_AND_BACK"; } std::unreachable(); } template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string< - stormkit::gpu::StencilFaceFlag>(stormkit::gpu::StencilFaceFlag value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::StencilFaceFlag value) noexcept + -> string { switch (value) { case stormkit::gpu::StencilFaceFlag::BACK: return "StencilFaceFlag::BACK"; case stormkit::gpu::StencilFaceFlag::FRONT: return "StencilFaceFlag::FRONT"; - case stormkit::gpu::StencilFaceFlag::FRONT_AND_BACK: - return "StencilFaceFlag::FRONT_AND_BACK"; + case stormkit::gpu::StencilFaceFlag::FRONT_AND_BACK: return "StencilFaceFlag::FRONT_AND_BACK"; } std::unreachable(); } @@ -3844,9 +3364,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::meta::enumerate() noexcept - -> decltype(auto) { - return std::array { + constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { + return array { stormkit::gpu::VertexInputRate::INSTANCE, stormkit::gpu::VertexInputRate::VERTEX, @@ -3856,9 +3375,8 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string< - stormkit::gpu::VertexInputRate>(stormkit::gpu::VertexInputRate value) noexcept - -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::VertexInputRate value) noexcept + -> string_view { switch (value) { case stormkit::gpu::VertexInputRate::INSTANCE: return "VertexInputRate::INSTANCE"; case stormkit::gpu::VertexInputRate::VERTEX: return "VertexInputRate::VERTEX"; @@ -3868,110 +3386,14 @@ export { template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string< - stormkit::gpu::VertexInputRate>(stormkit::gpu::VertexInputRate value) noexcept - -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::VertexInputRate value) noexcept + -> string { switch (value) { case stormkit::gpu::VertexInputRate::INSTANCE: return "VertexInputRate::INSTANCE"; case stormkit::gpu::VertexInputRate::VERTEX: return "VertexInputRate::VERTEX"; } std::unreachable(); } - - // enum class Format : u8 { - // BYTE, - // BYTE2, - // BYTE3, - // BYTE4, - - // BYTE_NORM, - // BYTE2_NORM, - // BYTE3_NORM, - // BYTE4_NORM, - - // BYTE_SCALED, - // BYTE2_SCALED, - // BYTE3_SCALED, - // BYTE4_SCALED, - - // UBYTE, - // UBYTE2, - // UBYTE3, - // UBYTE4, - - // UBYTE_NORM, - // UBYTE2_NORM, - // UBYTE3_NORM, - // UBYTE4_NORM, - - // UBYTE_UCALED, - // UBYTE2_UCALED, - // UBYTE3_UCALED, - // UBYTE4_UCALED, - - // SHORT, - // SHORT2, - // SHORT3, - // SHORT4, - - // SHORT_NORM, - // SHORT2_NORM, - // SHORT3_NORM, - // SHORT4_NORM, - - // SHORT_SCALED, - // SHORT2_SCALED, - // SHORT3_SCALED, - // SHORT4_SCALED, - - // USHORT, - // USHORT2, - // USHORT3, - // USHORT4, - - // USHORT_NORM, - // USHORT2_NORM, - // USHORT3_NORM, - // USHORT4_NORM, - - // USHORT_UCALED, - // USHORT2_UCALED, - // USHORT3_UCALED, - // USHORT4_UCALED, - - // INT, - // INT2, - // INT3, - // INT4, - - // UINT, - // UINT2, - // UINT3, - // UINT4, - - // LONG, - // LONG2, - // LONG3, - // LONG4, - - // ULONG, - // ULONG2, - // ULONG3, - // ULONG4, - - // FLOAT, - // FLOAT2, - // FLOAT3, - // FLOAT4, - - // DOUBLE, - // DOUBLE2, - // DOUBLE3, - // DOUBLE4, - - // UNDEFINED, - // }; } //////////////////////////////////////////////////////////////////// @@ -3981,7 +3403,7 @@ export { namespace stormkit::gpu { ///////////////////////////////////// ///////////////////////////////////// - STORMKIT_FORCE_INLINE + STORMKIT_FORCE_INLINE STORMKIT_CONST constexpr auto is_depth_only_format(PixelFormat format) noexcept -> bool { return format == PixelFormat::DEPTH16_UNORM or format == PixelFormat::DEPTH24_UNORM_PACK32 @@ -3990,7 +3412,14 @@ namespace stormkit::gpu { ///////////////////////////////////// ///////////////////////////////////// - STORMKIT_FORCE_INLINE + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto is_stencil_only_format(PixelFormat format) noexcept -> bool { + return format == PixelFormat::S8U; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_CONST constexpr auto is_depth_stencil_format(PixelFormat format) noexcept -> bool { return format == PixelFormat::DEPTH16_UNORM_STENCIL8U or format == PixelFormat::DEPTH24_UNORM_STENCIL8U @@ -3999,14 +3428,21 @@ namespace stormkit::gpu { ///////////////////////////////////// ///////////////////////////////////// - STORMKIT_FORCE_INLINE + STORMKIT_FORCE_INLINE STORMKIT_CONST constexpr auto is_depth_format(PixelFormat format) noexcept -> bool { return is_depth_only_format(format) or is_depth_stencil_format(format); } ///////////////////////////////////// ///////////////////////////////////// - STORMKIT_FORCE_INLINE + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto is_stencil_format(PixelFormat format) noexcept -> bool { + return is_stencil_only_format(format) or is_depth_stencil_format(format); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_CONST constexpr auto get_format_channel_count(PixelFormat format) noexcept -> u8 { switch (format) { case PixelFormat::R8_SNORM: @@ -4083,7 +3519,7 @@ namespace stormkit::gpu { ///////////////////////////////////// ///////////////////////////////////// - STORMKIT_FORCE_INLINE + STORMKIT_FORCE_INLINE STORMKIT_CONST constexpr auto get_format_element_count(PixelFormat format) noexcept -> u8 { switch (format) { case PixelFormat::R8_SNORM: @@ -4147,355 +3583,404 @@ namespace stormkit::gpu { return 0u; } - ///////////////////////////////////// - ///////////////////////////////////// - template - requires(core::meta::IsPlainEnumeration or core::meta::Is) - STORMKIT_FORCE_INLINE - STORMKIT_INTRINSIC - constexpr auto to_vk(U value) noexcept -> T { - return narrow(value); - } + namespace vk { + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(core::meta::IsPlainEnumeration or core::meta::Is) + STORMKIT_FORCE_INLINE + STORMKIT_CONST + STORMKIT_INTRINSIC + constexpr auto to_vk(U value) noexcept -> T { + return narrow(value); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(core::meta::IsPlainEnumeration or core::meta::Is) + STORMKIT_FORCE_INLINE + STORMKIT_CONST + STORMKIT_INTRINSIC + constexpr auto from_vk(U value) noexcept -> T { + return narrow(value); + } + } // namespace vk ///////////////////////////////////// ///////////////////////////////////// - template - requires(core::meta::IsPlainEnumeration or core::meta::Is) STORMKIT_FORCE_INLINE - STORMKIT_INTRINSIC - constexpr auto from_vk(U value) noexcept -> T { - return narrow(value); + STORMKIT_CONST + constexpr auto from_image(image::Image::Format format) -> PixelFormat { + switch (format) { + case image::Image::Format::R8_SNORM: return PixelFormat::R8_SNORM; + case image::Image::Format::RG8_SNORM: return PixelFormat::RG8_SNORM; + case image::Image::Format::RGB8_SNORM: return PixelFormat::RGB8_SNORM; + case image::Image::Format::RGBA8_SNORM: return PixelFormat::RGBA8_SNORM; + case image::Image::Format::R8_UNORM: return PixelFormat::R8_UNORM; + case image::Image::Format::RG8_UNORM: return PixelFormat::RG8_UNORM; + case image::Image::Format::RGB8_UNORM: return PixelFormat::RGB8_UNORM; + case image::Image::Format::RGBA8_UNORM: return PixelFormat::RGBA8_UNORM; + case image::Image::Format::R16_SNORM: return PixelFormat::R16_SNORM; + case image::Image::Format::RG16_SNORM: return PixelFormat::RG16_SNORM; + case image::Image::Format::RGB16_SNORM: return PixelFormat::RGB16_SNORM; + case image::Image::Format::RGBA16_SNORM: return PixelFormat::RGBA16_SNORM; + case image::Image::Format::R16_UNORM: return PixelFormat::R16_UNORM; + case image::Image::Format::RG16_UNORM: return PixelFormat::RG16_UNORM; + case image::Image::Format::RGB16_UNORM: return PixelFormat::RGB16_UNORM; + case image::Image::Format::RGBA16_UNORM: return PixelFormat::RGBA16_UNORM; + case image::Image::Format::RGBA4_UNORM: return PixelFormat::RGBA4_UNORM_PACK16; + case image::Image::Format::BGR8_UNORM: return PixelFormat::BGR8_UNORM; + case image::Image::Format::BGRA8_UNORM: return PixelFormat::BGRA8_UNORM; + case image::Image::Format::R8I: return PixelFormat::R8I; + case image::Image::Format::RG8I: return PixelFormat::RG8I; + case image::Image::Format::RGB8I: return PixelFormat::RGB8I; + case image::Image::Format::RGBA8I: return PixelFormat::RGBA8I; + case image::Image::Format::R8U: return PixelFormat::R8U; + case image::Image::Format::RG8U: return PixelFormat::RG8U; + case image::Image::Format::RGB8U: return PixelFormat::RGB8U; + case image::Image::Format::RGBA8U: return PixelFormat::RGBA8U; + case image::Image::Format::R16I: return PixelFormat::R16I; + case image::Image::Format::RG16I: return PixelFormat::RG16I; + case image::Image::Format::RGB16I: return PixelFormat::RGB16I; + case image::Image::Format::RGBA16I: return PixelFormat::RGBA16I; + case image::Image::Format::R16U: return PixelFormat::R16U; + case image::Image::Format::RG16U: return PixelFormat::RG16U; + case image::Image::Format::RGB16U: return PixelFormat::RGB16U; + case image::Image::Format::RGBA16U: return PixelFormat::RGBA16U; + case image::Image::Format::R32I: return PixelFormat::R32I; + case image::Image::Format::RG32I: return PixelFormat::RG32I; + case image::Image::Format::RGB32I: return PixelFormat::RGB32I; + case image::Image::Format::RGBA32I: return PixelFormat::RGBA32I; + case image::Image::Format::R32U: return PixelFormat::R32U; + case image::Image::Format::RG32U: return PixelFormat::RG32U; + case image::Image::Format::RGB32U: return PixelFormat::RGB32U; + case image::Image::Format::RGBA32U: return PixelFormat::RGBA32U; + case image::Image::Format::R16F: return PixelFormat::R16F; + case image::Image::Format::RG16F: return PixelFormat::RG16F; + case image::Image::Format::RGB16F: return PixelFormat::RGB16F; + case image::Image::Format::RGBA16F: return PixelFormat::RGBA16F; + case image::Image::Format::R32F: return PixelFormat::R32F; + case image::Image::Format::RG32F: return PixelFormat::RG32F; + case image::Image::Format::RGB32F: return PixelFormat::RGB32F; + case image::Image::Format::RGBA32F: return PixelFormat::RGBA32F; + case image::Image::Format::SRGB8: return PixelFormat::SRGB8; + case image::Image::Format::SRGBA8: return PixelFormat::SRGBA8; + case image::Image::Format::SBGR8: return PixelFormat::SBGR8; + case image::Image::Format::SBGRA8: return PixelFormat::SBGRA8; + case image::Image::Format::UNDEFINED: return PixelFormat::UNDEFINED; + + default: break; + } + + std::unreachable(); } } // namespace stormkit::gpu -template stormkit::gpu::AccessFlag stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::AccessFlag stormkit::gpu::from_vk(VkAccessFlagBits); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::AccessFlag); -template VkAccessFlagBits stormkit::gpu::to_vk(stormkit::gpu::AccessFlag); - -template stormkit::gpu::AttachmentLoadOperation stormkit::gpu:: - from_vk(VkFlags); -template stormkit::gpu::AttachmentLoadOperation stormkit::gpu:: - from_vk(VkAttachmentLoadOp); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::AttachmentLoadOperation); -template VkAttachmentLoadOp stormkit::gpu::to_vk< - VkAttachmentLoadOp>(stormkit::gpu::AttachmentLoadOperation); - -template stormkit::gpu::AttachmentStoreOperation stormkit::gpu:: - from_vk(VkFlags); -template stormkit::gpu::AttachmentStoreOperation stormkit::gpu:: - from_vk(VkAttachmentStoreOp); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::AttachmentStoreOperation); -template VkAttachmentStoreOp stormkit::gpu::to_vk< - VkAttachmentStoreOp>(stormkit::gpu::AttachmentStoreOperation); - -template stormkit::gpu::BlendFactor stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::BlendFactor stormkit::gpu::from_vk(VkBlendFactor); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::BlendFactor); -template VkBlendFactor stormkit::gpu::to_vk(stormkit::gpu::BlendFactor); - -template stormkit::gpu::BlendOperation stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::BlendOperation stormkit::gpu::from_vk(VkBlendOp); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::BlendOperation); -template VkBlendOp stormkit::gpu::to_vk(stormkit::gpu::BlendOperation); - -template stormkit::gpu::BorderColor stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::BorderColor stormkit::gpu::from_vk(VkBorderColor); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::BorderColor); -template VkBorderColor stormkit::gpu::to_vk(stormkit::gpu::BorderColor); - -template stormkit::gpu::BufferUsageFlag stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::BufferUsageFlag stormkit::gpu:: - from_vk(VkBufferUsageFlagBits); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::BufferUsageFlag); -template VkBufferUsageFlagBits stormkit::gpu::to_vk< - VkBufferUsageFlagBits>(stormkit::gpu::BufferUsageFlag); - -template stormkit::gpu::ColorComponentFlag stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::ColorComponentFlag stormkit::gpu:: - from_vk(VkColorComponentFlagBits); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::ColorComponentFlag); -template VkColorComponentFlagBits stormkit::gpu::to_vk< - VkColorComponentFlagBits>(stormkit::gpu::ColorComponentFlag); - -template stormkit::gpu::ColorSpace stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::ColorSpace stormkit::gpu::from_vk(VkColorSpaceKHR); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::ColorSpace); -template VkColorSpaceKHR stormkit::gpu::to_vk(stormkit::gpu::ColorSpace); - -template stormkit::gpu::CommandBufferLevel stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::CommandBufferLevel stormkit::gpu:: - from_vk(VkCommandBufferLevel); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::CommandBufferLevel); -template VkCommandBufferLevel stormkit::gpu::to_vk< - VkCommandBufferLevel>(stormkit::gpu::CommandBufferLevel); - -template stormkit::gpu::CompareOperation stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::CompareOperation stormkit::gpu::from_vk(VkCompareOp); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::CompareOperation); -template VkCompareOp stormkit::gpu::to_vk(stormkit::gpu::CompareOperation); - -template stormkit::gpu::CullModeFlag stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::CullModeFlag stormkit::gpu::from_vk(VkCullModeFlagBits); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::CullModeFlag); -template VkCullModeFlagBits stormkit::gpu::to_vk(stormkit::gpu::CullModeFlag); - -template stormkit::gpu::DebugObjectType stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::DebugObjectType stormkit::gpu::from_vk(VkObjectType); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::DebugObjectType); -template VkObjectType stormkit::gpu::to_vk(stormkit::gpu::DebugObjectType); - -template stormkit::gpu::DependencyFlag stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::DependencyFlag stormkit::gpu:: - from_vk(VkDependencyFlagBits); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::DependencyFlag); -template VkDependencyFlagBits stormkit::gpu::to_vk< - VkDependencyFlagBits>(stormkit::gpu::DependencyFlag); - -template stormkit::gpu::DescriptorType stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::DescriptorType stormkit::gpu::from_vk(VkDescriptorType); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::DescriptorType); -template VkDescriptorType stormkit::gpu::to_vk(stormkit::gpu::DescriptorType); - -template stormkit::gpu::DynamicState stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::DynamicState stormkit::gpu::from_vk(VkDynamicState); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::DynamicState); -template VkDynamicState stormkit::gpu::to_vk(stormkit::gpu::DynamicState); - -template stormkit::gpu::Filter stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::Filter stormkit::gpu::from_vk(VkFilter); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::Filter); -template VkFilter stormkit::gpu::to_vk(stormkit::gpu::Filter); - -template stormkit::gpu::FormatFeatureFlag stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::FormatFeatureFlag stormkit::gpu:: - from_vk(VkFormatFeatureFlagBits); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::FormatFeatureFlag); -template VkFormatFeatureFlagBits stormkit::gpu::to_vk< - VkFormatFeatureFlagBits>(stormkit::gpu::FormatFeatureFlag); - -template stormkit::gpu::FrontFace stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::FrontFace stormkit::gpu::from_vk(VkFrontFace); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::FrontFace); -template VkFrontFace stormkit::gpu::to_vk(stormkit::gpu::FrontFace); - -template stormkit::gpu::GeometryFlag stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::GeometryFlag stormkit::gpu:: - from_vk(VkGeometryFlagBitsKHR); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::GeometryFlag); -template VkGeometryFlagBitsKHR stormkit::gpu::to_vk< - VkGeometryFlagBitsKHR>(stormkit::gpu::GeometryFlag); - -template stormkit::gpu::GeometryType stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::GeometryType stormkit::gpu::from_vk(VkGeometryTypeKHR); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::GeometryType); -template VkGeometryTypeKHR stormkit::gpu::to_vk(stormkit::gpu::GeometryType); - -template stormkit::gpu::ImageAspectFlag stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::ImageAspectFlag stormkit::gpu:: - from_vk(VkImageAspectFlagBits); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::ImageAspectFlag); -template VkImageAspectFlagBits stormkit::gpu::to_vk< - VkImageAspectFlagBits>(stormkit::gpu::ImageAspectFlag); - -template stormkit::gpu::ImageCreateFlag stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::ImageCreateFlag stormkit::gpu:: - from_vk(VkImageCreateFlagBits); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::ImageCreateFlag); -template VkImageCreateFlagBits stormkit::gpu::to_vk< - VkImageCreateFlagBits>(stormkit::gpu::ImageCreateFlag); - -template stormkit::gpu::ImageLayout stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::ImageLayout stormkit::gpu::from_vk(VkImageLayout); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::ImageLayout); -template VkImageLayout stormkit::gpu::to_vk(stormkit::gpu::ImageLayout); - -template stormkit::gpu::ImageTiling stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::ImageTiling stormkit::gpu::from_vk(VkImageTiling); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::ImageTiling); -template VkImageTiling stormkit::gpu::to_vk(stormkit::gpu::ImageTiling); - -template stormkit::gpu::ImageType stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::ImageType stormkit::gpu::from_vk(VkImageType); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::ImageType); -template VkImageType stormkit::gpu::to_vk(stormkit::gpu::ImageType); - -template stormkit::gpu::ImageUsageFlag stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::ImageUsageFlag stormkit::gpu:: - from_vk(VkImageUsageFlagBits); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::ImageUsageFlag); -template VkImageUsageFlagBits stormkit::gpu::to_vk< - VkImageUsageFlagBits>(stormkit::gpu::ImageUsageFlag); - -template stormkit::gpu::ImageViewType stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::ImageViewType stormkit::gpu::from_vk(VkImageViewType); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::ImageViewType); -template VkImageViewType stormkit::gpu::to_vk(stormkit::gpu::ImageViewType); - -template stormkit::gpu::LogicOperation stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::LogicOperation stormkit::gpu::from_vk(VkLogicOp); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::LogicOperation); -template VkLogicOp stormkit::gpu::to_vk(stormkit::gpu::LogicOperation); - -template stormkit::gpu::MemoryPropertyFlag stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::MemoryPropertyFlag stormkit::gpu:: - from_vk(VkMemoryPropertyFlagBits); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::MemoryPropertyFlag); -template VkMemoryPropertyFlagBits stormkit::gpu::to_vk< - VkMemoryPropertyFlagBits>(stormkit::gpu::MemoryPropertyFlag); - -template stormkit::gpu::PhysicalDeviceType stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::PhysicalDeviceType stormkit::gpu:: - from_vk(VkPhysicalDeviceType); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::PhysicalDeviceType); -template VkPhysicalDeviceType stormkit::gpu::to_vk< - VkPhysicalDeviceType>(stormkit::gpu::PhysicalDeviceType); - -template stormkit::gpu::PipelineBindPoint stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::PipelineBindPoint stormkit::gpu:: - from_vk(VkPipelineBindPoint); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::PipelineBindPoint); -template VkPipelineBindPoint stormkit::gpu::to_vk< - VkPipelineBindPoint>(stormkit::gpu::PipelineBindPoint); - -template stormkit::gpu::PipelineStageFlag stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::PipelineStageFlag stormkit::gpu:: - from_vk(VkPipelineStageFlagBits); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::PipelineStageFlag); -template VkPipelineStageFlagBits stormkit::gpu::to_vk< - VkPipelineStageFlagBits>(stormkit::gpu::PipelineStageFlag); - -template stormkit::gpu::PixelFormat stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::PixelFormat stormkit::gpu::from_vk(VkFormat); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::PixelFormat); -template VkFormat stormkit::gpu::to_vk(stormkit::gpu::PixelFormat); - -template stormkit::gpu::PolygonMode stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::PolygonMode stormkit::gpu::from_vk(VkPolygonMode); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::PolygonMode); -template VkPolygonMode stormkit::gpu::to_vk(stormkit::gpu::PolygonMode); - -template stormkit::gpu::PresentMode stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::PresentMode stormkit::gpu::from_vk(VkPresentModeKHR); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::PresentMode); -template VkPresentModeKHR stormkit::gpu::to_vk(stormkit::gpu::PresentMode); - -template stormkit::gpu::PrimitiveTopology stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::PrimitiveTopology stormkit::gpu:: - from_vk(VkPrimitiveTopology); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::PrimitiveTopology); -template VkPrimitiveTopology stormkit::gpu::to_vk< - VkPrimitiveTopology>(stormkit::gpu::PrimitiveTopology); - -template stormkit::gpu::QueueFlag stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::QueueFlag stormkit::gpu::from_vk(VkQueueFlagBits); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::QueueFlag); -template VkQueueFlagBits stormkit::gpu::to_vk(stormkit::gpu::QueueFlag); - -template stormkit::gpu::Result stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::Result stormkit::gpu::from_vk(VkResult); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::Result); -template VkResult stormkit::gpu::to_vk(stormkit::gpu::Result); - -template stormkit::gpu::SampleCountFlag stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::SampleCountFlag stormkit::gpu:: - from_vk(VkSampleCountFlagBits); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::SampleCountFlag); -template VkSampleCountFlagBits stormkit::gpu::to_vk< - VkSampleCountFlagBits>(stormkit::gpu::SampleCountFlag); - -template stormkit::gpu::SamplerAddressMode stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::SamplerAddressMode stormkit::gpu:: - from_vk(VkSamplerAddressMode); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::SamplerAddressMode); -template VkSamplerAddressMode stormkit::gpu::to_vk< - VkSamplerAddressMode>(stormkit::gpu::SamplerAddressMode); - -template stormkit::gpu::SamplerMipmapMode stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::SamplerMipmapMode stormkit::gpu:: - from_vk(VkSamplerMipmapMode); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::SamplerMipmapMode); -template VkSamplerMipmapMode stormkit::gpu::to_vk< - VkSamplerMipmapMode>(stormkit::gpu::SamplerMipmapMode); - -template stormkit::gpu::ShaderStageFlag stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::ShaderStageFlag stormkit::gpu:: - from_vk(VkShaderStageFlagBits); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::ShaderStageFlag); -template VkShaderStageFlagBits stormkit::gpu::to_vk< - VkShaderStageFlagBits>(stormkit::gpu::ShaderStageFlag); - -template stormkit::gpu::StencilFaceFlag stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::StencilFaceFlag stormkit::gpu:: - from_vk(VkStencilFaceFlagBits); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::StencilFaceFlag); -template VkStencilFaceFlagBits stormkit::gpu::to_vk< - VkStencilFaceFlagBits>(stormkit::gpu::StencilFaceFlag); - -template stormkit::gpu::VertexInputRate stormkit::gpu::from_vk(VkFlags); -template stormkit::gpu::VertexInputRate stormkit::gpu:: - from_vk(VkVertexInputRate); -template VkFlags stormkit::gpu::to_vk(stormkit::gpu::VertexInputRate); -template VkVertexInputRate stormkit::gpu::to_vk(stormkit::gpu::VertexInputRate); +#ifndef STORMKIT_OS_WINDOWS + #undef STORMKIT_GPU_API + #define STORMKIT_GPU_API +#endif + +template stormkit::gpu::AccessFlag STORMKIT_GPU_API stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::AccessFlag STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkAccessFlagBits); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::AccessFlag); +template VkAccessFlagBits STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::AccessFlag); + +template stormkit::gpu::AttachmentLoadOperation STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::AttachmentLoadOperation STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkAttachmentLoadOp); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::AttachmentLoadOperation); +template VkAttachmentLoadOp STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::AttachmentLoadOperation); + +template stormkit::gpu::AttachmentStoreOperation STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::AttachmentStoreOperation STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkAttachmentStoreOp); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::AttachmentStoreOperation); +template VkAttachmentStoreOp STORMKIT_GPU_API + stormkit::gpu::vk::to_vk(stormkit::gpu::AttachmentStoreOperation); + +template stormkit::gpu::BlendFactor STORMKIT_GPU_API stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::BlendFactor STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkBlendFactor); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::BlendFactor); +template VkBlendFactor STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::BlendFactor); + +template stormkit::gpu::BlendOperation STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::BlendOperation STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkBlendOp); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::BlendOperation); +template VkBlendOp STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::BlendOperation); + +template stormkit::gpu::BorderColor STORMKIT_GPU_API stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::BorderColor STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkBorderColor); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::BorderColor); +template VkBorderColor STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::BorderColor); + +template stormkit::gpu::BufferUsageFlag STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::BufferUsageFlag STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkBufferUsageFlagBits); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::BufferUsageFlag); +template VkBufferUsageFlagBits STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::BufferUsageFlag); + +template stormkit::gpu::ColorComponentFlag STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::ColorComponentFlag STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkColorComponentFlagBits); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::ColorComponentFlag); +template VkColorComponentFlagBits STORMKIT_GPU_API + stormkit::gpu::vk::to_vk(stormkit::gpu::ColorComponentFlag); + +template stormkit::gpu::ColorSpace STORMKIT_GPU_API stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::ColorSpace STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkColorSpaceKHR); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::ColorSpace); +template VkColorSpaceKHR STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::ColorSpace); + +template stormkit::gpu::CommandBufferLevel STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::CommandBufferLevel STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkCommandBufferLevel); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::CommandBufferLevel); +template VkCommandBufferLevel STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::CommandBufferLevel); + +template stormkit::gpu::CompareOperation STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::CompareOperation STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkCompareOp); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::CompareOperation); +template VkCompareOp STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::CompareOperation); + +template stormkit::gpu::CullModeFlag STORMKIT_GPU_API stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::CullModeFlag STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkCullModeFlagBits); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::CullModeFlag); +template VkCullModeFlagBits STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::CullModeFlag); + +template stormkit::gpu::DebugObjectType STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::DebugObjectType STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkObjectType); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::DebugObjectType); +template VkObjectType STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::DebugObjectType); + +template stormkit::gpu::DependencyFlag STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::DependencyFlag STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkDependencyFlagBits); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::DependencyFlag); +template VkDependencyFlagBits STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::DependencyFlag); + +template stormkit::gpu::DescriptorType STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::DescriptorType STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkDescriptorType); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::DescriptorType); +template VkDescriptorType STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::DescriptorType); + +template stormkit::gpu::DynamicState STORMKIT_GPU_API stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::DynamicState STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkDynamicState); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::DynamicState); +template VkDynamicState STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::DynamicState); + +template stormkit::gpu::Filter STORMKIT_GPU_API stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::Filter STORMKIT_GPU_API stormkit::gpu::vk::from_vk(VkFilter); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::Filter); +template VkFilter STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::Filter); + +template stormkit::gpu::FormatFeatureFlag STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::FormatFeatureFlag STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkFormatFeatureFlagBits); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::FormatFeatureFlag); +template VkFormatFeatureFlagBits STORMKIT_GPU_API + stormkit::gpu::vk::to_vk(stormkit::gpu::FormatFeatureFlag); + +template stormkit::gpu::FrontFace STORMKIT_GPU_API stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::FrontFace STORMKIT_GPU_API stormkit::gpu::vk::from_vk(VkFrontFace); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::FrontFace); +template VkFrontFace STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::FrontFace); + +template stormkit::gpu::GeometryFlag STORMKIT_GPU_API stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::GeometryFlag STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkGeometryFlagBitsKHR); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::GeometryFlag); +template VkGeometryFlagBitsKHR STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::GeometryFlag); + +template stormkit::gpu::GeometryType STORMKIT_GPU_API stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::GeometryType STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkGeometryTypeKHR); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::GeometryType); +template VkGeometryTypeKHR STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::GeometryType); + +template stormkit::gpu::ImageAspectFlag STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::ImageAspectFlag STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkImageAspectFlagBits); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::ImageAspectFlag); +template VkImageAspectFlagBits STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::ImageAspectFlag); + +template stormkit::gpu::ImageCreateFlag STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::ImageCreateFlag STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkImageCreateFlagBits); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::ImageCreateFlag); +template VkImageCreateFlagBits STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::ImageCreateFlag); + +template stormkit::gpu::ImageLayout STORMKIT_GPU_API stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::ImageLayout STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkImageLayout); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::ImageLayout); +template VkImageLayout STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::ImageLayout); + +template stormkit::gpu::ImageTiling STORMKIT_GPU_API stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::ImageTiling STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkImageTiling); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::ImageTiling); +template VkImageTiling STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::ImageTiling); + +template stormkit::gpu::ImageType STORMKIT_GPU_API stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::ImageType STORMKIT_GPU_API stormkit::gpu::vk::from_vk(VkImageType); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::ImageType); +template VkImageType STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::ImageType); + +template stormkit::gpu::ImageUsageFlag STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::ImageUsageFlag STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkImageUsageFlagBits); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::ImageUsageFlag); +template VkImageUsageFlagBits STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::ImageUsageFlag); + +template stormkit::gpu::ImageViewType STORMKIT_GPU_API stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::ImageViewType STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkImageViewType); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::ImageViewType); +template VkImageViewType STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::ImageViewType); + +template stormkit::gpu::LogicOperation STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::LogicOperation STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkLogicOp); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::LogicOperation); +template VkLogicOp STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::LogicOperation); + +template stormkit::gpu::MemoryPropertyFlag STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::MemoryPropertyFlag STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkMemoryPropertyFlagBits); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::MemoryPropertyFlag); +template VkMemoryPropertyFlagBits STORMKIT_GPU_API + stormkit::gpu::vk::to_vk(stormkit::gpu::MemoryPropertyFlag); + +template stormkit::gpu::PhysicalDeviceType STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::PhysicalDeviceType STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkPhysicalDeviceType); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::PhysicalDeviceType); +template VkPhysicalDeviceType STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::PhysicalDeviceType); + +template stormkit::gpu::PipelineBindPoint STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::PipelineBindPoint STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkPipelineBindPoint); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::PipelineBindPoint); +template VkPipelineBindPoint STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::PipelineBindPoint); + +template stormkit::gpu::PipelineStageFlag STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::PipelineStageFlag STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkPipelineStageFlagBits); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::PipelineStageFlag); +template VkPipelineStageFlagBits STORMKIT_GPU_API + stormkit::gpu::vk::to_vk(stormkit::gpu::PipelineStageFlag); + +template stormkit::gpu::PixelFormat STORMKIT_GPU_API stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::PixelFormat STORMKIT_GPU_API stormkit::gpu::vk::from_vk(VkFormat); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::PixelFormat); +template VkFormat STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::PixelFormat); + +template stormkit::gpu::PolygonMode STORMKIT_GPU_API stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::PolygonMode STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkPolygonMode); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::PolygonMode); +template VkPolygonMode STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::PolygonMode); + +template stormkit::gpu::PresentMode STORMKIT_GPU_API stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::PresentMode STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkPresentModeKHR); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::PresentMode); +template VkPresentModeKHR STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::PresentMode); + +template stormkit::gpu::PrimitiveTopology STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::PrimitiveTopology STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkPrimitiveTopology); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::PrimitiveTopology); +template VkPrimitiveTopology STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::PrimitiveTopology); + +template stormkit::gpu::QueueFlag STORMKIT_GPU_API stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::QueueFlag STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkQueueFlagBits); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::QueueFlag); +template VkQueueFlagBits STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::QueueFlag); + +template stormkit::gpu::ResolveModeFlag STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::ResolveModeFlag STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkResolveModeFlagBits); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::ResolveModeFlag); +template VkResolveModeFlagBits STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::ResolveModeFlag); + +template stormkit::gpu::Result STORMKIT_GPU_API stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::Result STORMKIT_GPU_API stormkit::gpu::vk::from_vk(VkResult); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::Result); +template VkResult STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::Result); + +template stormkit::gpu::SampleCountFlag STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::SampleCountFlag STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkSampleCountFlagBits); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::SampleCountFlag); +template VkSampleCountFlagBits STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::SampleCountFlag); + +template stormkit::gpu::SamplerAddressMode STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::SamplerAddressMode STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkSamplerAddressMode); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::SamplerAddressMode); +template VkSamplerAddressMode STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::SamplerAddressMode); + +template stormkit::gpu::SamplerMipmapMode STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::SamplerMipmapMode STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkSamplerMipmapMode); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::SamplerMipmapMode); +template VkSamplerMipmapMode STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::SamplerMipmapMode); + +template stormkit::gpu::ShaderStageFlag STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::ShaderStageFlag STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkShaderStageFlagBits); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::ShaderStageFlag); +template VkShaderStageFlagBits STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::ShaderStageFlag); + +template stormkit::gpu::StencilFaceFlag STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::StencilFaceFlag STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkStencilFaceFlagBits); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::StencilFaceFlag); +template VkStencilFaceFlagBits STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::StencilFaceFlag); + +template stormkit::gpu::VertexInputRate STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkFlags); +template stormkit::gpu::VertexInputRate STORMKIT_GPU_API + stormkit::gpu::vk::from_vk(VkVertexInputRate); +template VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::VertexInputRate); +template VkVertexInputRate STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::VertexInputRate); diff --git a/modules/stormkit/gpu/core/vulkan/enums.mpp.tpl b/modules/stormkit/gpu/core/vulkan/enums.cppm.tpl similarity index 56% rename from modules/stormkit/gpu/core/vulkan/enums.mpp.tpl rename to modules/stormkit/gpu/core/vulkan/enums.cppm.tpl index 92a42adc2..8fabedda1 100644 --- a/modules/stormkit/gpu/core/vulkan/enums.mpp.tpl +++ b/modules/stormkit/gpu/core/vulkan/enums.cppm.tpl @@ -7,17 +7,19 @@ module; #include #include +#include #include export module stormkit.gpu.core:vulkan.enums; import std; import stormkit.core; +import stormkit.image; import :vulkan.volk; {% - import("core.base.json") - local json_data = json.loadfile("modules/stormkit/gpu/core/vulkan/mapping.json") +import("core.base.json") +local json_data = json.loadfile("modules/stormkit/gpu/core/vulkan/mapping.json") %} export { @@ -43,22 +45,31 @@ export { inline constexpr auto details::IS_VULKAN_ENUMERATION<{% outfile:write(name) %}> = true; {% end %} - template - requires(core::meta::IsPlainEnumeration or core::meta::Is) - [[nodiscard]] - constexpr auto to_vk(U value) noexcept -> T; + namespace vk { + template + requires(core::meta::IsPlainEnumeration or core::meta::Is) + [[nodiscard]] + constexpr auto to_vk(U value) noexcept -> T; - template - requires(core::meta::IsPlainEnumeration or core::meta::Is) - [[nodiscard]] - constexpr auto from_vk(U value) noexcept -> T; + template + requires(core::meta::IsPlainEnumeration or core::meta::Is) + [[nodiscard]] + constexpr auto from_vk(U value) noexcept -> T; + } + [[nodiscard]] + constexpr auto from_image(image::Image::Format format) -> PixelFormat; + [[nodiscard]] constexpr auto is_depth_only_format(PixelFormat format) noexcept -> bool; [[nodiscard]] + constexpr auto is_stencil_only_format(PixelFormat format) noexcept -> bool; + [[nodiscard]] constexpr auto is_depth_stencil_format(PixelFormat format) noexcept -> bool; [[nodiscard]] constexpr auto is_depth_format(PixelFormat format) noexcept -> bool; + [[nodiscard]] + constexpr auto is_stencil_format(PixelFormat format) noexcept -> bool; [[nodiscard]] constexpr auto get_format_channel_count(PixelFormat format) noexcept -> u8; @@ -70,7 +81,7 @@ export { STORMKIT_FORCE_INLINE STORMKIT_CONST constexpr auto stormkit::core::meta::enumerate() noexcept -> decltype(auto) { - return std::array { + return array { {% for val_name, value in table.orderpairs(enumeration["values"]) do %}stormkit::gpu::{% outfile:write(name) %}::{% outfile:write(val_name) %}, {% end %} }; @@ -78,7 +89,7 @@ export { template<> STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto stormkit::core::as_string(stormkit::gpu::{% outfile:write(name) %} value) noexcept -> std::string_view { + constexpr auto stormkit::core::as_string(stormkit::gpu::{% outfile:write(name) %} value) noexcept -> string_view { switch(value) { {% for val_name, value in table.orderpairs(enumeration["values"]) do %}case stormkit::gpu::{% outfile:write(name) %}::{% outfile:write(val_name) %}: return "{% outfile:write(name) %}::{% outfile:write(val_name) %}"; {% end %} @@ -87,8 +98,7 @@ export { } template<> STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto stormkit::core::to_string(stormkit::gpu::{% outfile:write(name) %} value) noexcept -> std::string { + constexpr auto stormkit::core::to_string(stormkit::gpu::{% outfile:write(name) %} value) noexcept -> string { switch(value) { {% for val_name, value in table.orderpairs(enumeration["values"]) do %}case stormkit::gpu::{% outfile:write(name) %}::{% outfile:write(val_name) %}: return "{% outfile:write(name) %}::{% outfile:write(val_name) %}"; {% end %} @@ -96,99 +106,6 @@ export { std::unreachable(); } {% end %} - // enum class Format : u8 { - // BYTE, - // BYTE2, - // BYTE3, - // BYTE4, - - // BYTE_NORM, - // BYTE2_NORM, - // BYTE3_NORM, - // BYTE4_NORM, - - // BYTE_SCALED, - // BYTE2_SCALED, - // BYTE3_SCALED, - // BYTE4_SCALED, - - // UBYTE, - // UBYTE2, - // UBYTE3, - // UBYTE4, - - // UBYTE_NORM, - // UBYTE2_NORM, - // UBYTE3_NORM, - // UBYTE4_NORM, - - // UBYTE_UCALED, - // UBYTE2_UCALED, - // UBYTE3_UCALED, - // UBYTE4_UCALED, - - // SHORT, - // SHORT2, - // SHORT3, - // SHORT4, - - // SHORT_NORM, - // SHORT2_NORM, - // SHORT3_NORM, - // SHORT4_NORM, - - // SHORT_SCALED, - // SHORT2_SCALED, - // SHORT3_SCALED, - // SHORT4_SCALED, - - // USHORT, - // USHORT2, - // USHORT3, - // USHORT4, - - // USHORT_NORM, - // USHORT2_NORM, - // USHORT3_NORM, - // USHORT4_NORM, - - // USHORT_UCALED, - // USHORT2_UCALED, - // USHORT3_UCALED, - // USHORT4_UCALED, - - // INT, - // INT2, - // INT3, - // INT4, - - // UINT, - // UINT2, - // UINT3, - // UINT4, - - // LONG, - // LONG2, - // LONG3, - // LONG4, - - // ULONG, - // ULONG2, - // ULONG3, - // ULONG4, - - // FLOAT, - // FLOAT2, - // FLOAT3, - // FLOAT4, - - // DOUBLE, - // DOUBLE2, - // DOUBLE3, - // DOUBLE4, - - // UNDEFINED, - // }; } //////////////////////////////////////////////////////////////////// @@ -199,6 +116,7 @@ namespace stormkit::gpu { ///////////////////////////////////// ///////////////////////////////////// STORMKIT_FORCE_INLINE + STORMKIT_CONST constexpr auto is_depth_only_format(PixelFormat format) noexcept -> bool { return format == PixelFormat::DEPTH16_UNORM or format == PixelFormat::DEPTH24_UNORM_PACK32 @@ -208,6 +126,15 @@ namespace stormkit::gpu { ///////////////////////////////////// ///////////////////////////////////// STORMKIT_FORCE_INLINE + STORMKIT_CONST + constexpr auto is_stencil_only_format(PixelFormat format) noexcept -> bool { + return format == PixelFormat::S8U; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + STORMKIT_CONST constexpr auto is_depth_stencil_format(PixelFormat format) noexcept -> bool { return format == PixelFormat::DEPTH16_UNORM_STENCIL8U or format == PixelFormat::DEPTH24_UNORM_STENCIL8U @@ -217,6 +144,7 @@ namespace stormkit::gpu { ///////////////////////////////////// ///////////////////////////////////// STORMKIT_FORCE_INLINE + STORMKIT_CONST constexpr auto is_depth_format(PixelFormat format) noexcept -> bool { return is_depth_only_format(format) or is_depth_stencil_format(format); } @@ -224,6 +152,15 @@ namespace stormkit::gpu { ///////////////////////////////////// ///////////////////////////////////// STORMKIT_FORCE_INLINE + STORMKIT_CONST + constexpr auto is_stencil_format(PixelFormat format) noexcept -> bool { + return is_stencil_only_format(format) or is_depth_stencil_format(format); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + STORMKIT_CONST constexpr auto get_format_channel_count(PixelFormat format) noexcept -> u8 { switch (format) { case PixelFormat::R8_SNORM: @@ -301,6 +238,7 @@ namespace stormkit::gpu { ///////////////////////////////////// ///////////////////////////////////// STORMKIT_FORCE_INLINE + STORMKIT_CONST constexpr auto get_format_element_count(PixelFormat format) noexcept -> u8 { switch (format) { case PixelFormat::R8_SNORM: @@ -364,31 +302,112 @@ namespace stormkit::gpu { return 0u; } - ///////////////////////////////////// - ///////////////////////////////////// - template - requires(core::meta::IsPlainEnumeration or core::meta::Is) - STORMKIT_FORCE_INLINE - STORMKIT_INTRINSIC - constexpr auto to_vk(U value) noexcept -> T{ - return narrow(value); + namespace vk { + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(core::meta::IsPlainEnumeration or core::meta::Is) + STORMKIT_FORCE_INLINE + STORMKIT_CONST + STORMKIT_INTRINSIC + constexpr auto to_vk(U value) noexcept -> T{ + return narrow(value); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(core::meta::IsPlainEnumeration or core::meta::Is) + STORMKIT_FORCE_INLINE + STORMKIT_CONST + STORMKIT_INTRINSIC + constexpr auto from_vk(U value) noexcept -> T { + return narrow(value); + } } ///////////////////////////////////// ///////////////////////////////////// - template - requires(core::meta::IsPlainEnumeration or core::meta::Is) STORMKIT_FORCE_INLINE - STORMKIT_INTRINSIC - constexpr auto from_vk(U value) noexcept -> T { - return narrow(value); + STORMKIT_CONST + constexpr auto from_image(image::Image::Format format) -> PixelFormat { + switch(format) { + case image::Image::Format::R8_SNORM : return PixelFormat::R8_SNORM ; + case image::Image::Format::RG8_SNORM : return PixelFormat::RG8_SNORM ; + case image::Image::Format::RGB8_SNORM : return PixelFormat::RGB8_SNORM ; + case image::Image::Format::RGBA8_SNORM : return PixelFormat::RGBA8_SNORM ; + case image::Image::Format::R8_UNORM : return PixelFormat::R8_UNORM ; + case image::Image::Format::RG8_UNORM : return PixelFormat::RG8_UNORM ; + case image::Image::Format::RGB8_UNORM : return PixelFormat::RGB8_UNORM ; + case image::Image::Format::RGBA8_UNORM : return PixelFormat::RGBA8_UNORM ; + case image::Image::Format::R16_SNORM : return PixelFormat::R16_SNORM ; + case image::Image::Format::RG16_SNORM : return PixelFormat::RG16_SNORM ; + case image::Image::Format::RGB16_SNORM : return PixelFormat::RGB16_SNORM ; + case image::Image::Format::RGBA16_SNORM : return PixelFormat::RGBA16_SNORM ; + case image::Image::Format::R16_UNORM : return PixelFormat::R16_UNORM ; + case image::Image::Format::RG16_UNORM : return PixelFormat::RG16_UNORM ; + case image::Image::Format::RGB16_UNORM : return PixelFormat::RGB16_UNORM ; + case image::Image::Format::RGBA16_UNORM : return PixelFormat::RGBA16_UNORM ; + case image::Image::Format::RGBA4_UNORM : return PixelFormat::RGBA4_UNORM_PACK16 ; + case image::Image::Format::BGR8_UNORM : return PixelFormat::BGR8_UNORM ; + case image::Image::Format::BGRA8_UNORM : return PixelFormat::BGRA8_UNORM ; + case image::Image::Format::R8I : return PixelFormat::R8I ; + case image::Image::Format::RG8I : return PixelFormat::RG8I ; + case image::Image::Format::RGB8I : return PixelFormat::RGB8I ; + case image::Image::Format::RGBA8I : return PixelFormat::RGBA8I ; + case image::Image::Format::R8U : return PixelFormat::R8U ; + case image::Image::Format::RG8U : return PixelFormat::RG8U ; + case image::Image::Format::RGB8U : return PixelFormat::RGB8U ; + case image::Image::Format::RGBA8U : return PixelFormat::RGBA8U ; + case image::Image::Format::R16I : return PixelFormat::R16I ; + case image::Image::Format::RG16I : return PixelFormat::RG16I ; + case image::Image::Format::RGB16I : return PixelFormat::RGB16I ; + case image::Image::Format::RGBA16I : return PixelFormat::RGBA16I ; + case image::Image::Format::R16U : return PixelFormat::R16U ; + case image::Image::Format::RG16U : return PixelFormat::RG16U ; + case image::Image::Format::RGB16U : return PixelFormat::RGB16U ; + case image::Image::Format::RGBA16U : return PixelFormat::RGBA16U ; + case image::Image::Format::R32I : return PixelFormat::R32I ; + case image::Image::Format::RG32I : return PixelFormat::RG32I ; + case image::Image::Format::RGB32I : return PixelFormat::RGB32I ; + case image::Image::Format::RGBA32I : return PixelFormat::RGBA32I ; + case image::Image::Format::R32U : return PixelFormat::R32U ; + case image::Image::Format::RG32U : return PixelFormat::RG32U ; + case image::Image::Format::RGB32U : return PixelFormat::RGB32U ; + case image::Image::Format::RGBA32U : return PixelFormat::RGBA32U ; + case image::Image::Format::R16F : return PixelFormat::R16F ; + case image::Image::Format::RG16F : return PixelFormat::RG16F ; + case image::Image::Format::RGB16F : return PixelFormat::RGB16F ; + case image::Image::Format::RGBA16F : return PixelFormat::RGBA16F ; + case image::Image::Format::R32F : return PixelFormat::R32F ; + case image::Image::Format::RG32F : return PixelFormat::RG32F ; + case image::Image::Format::RGB32F : return PixelFormat::RGB32F ; + case image::Image::Format::RGBA32F : return PixelFormat::RGBA32F ; + case image::Image::Format::SRGB8 : return PixelFormat::SRGB8 ; + case image::Image::Format::SRGBA8 : return PixelFormat::SRGBA8 ; + case image::Image::Format::SBGR8 : return PixelFormat::SBGR8 ; + case image::Image::Format::SBGRA8 : return PixelFormat::SBGRA8 ; + case image::Image::Format::UNDEFINED : return PixelFormat::UNDEFINED ; + + default: break; + } + + std::unreachable(); } } +#ifndef STORMKIT_OS_WINDOWS + #undef STORMKIT_GPU_API + #define STORMKIT_GPU_API +#endif + {% for name, enumeration in table.orderpairs(json_data) do %} - template stormkit::gpu::{% outfile:write(name) %} stormkit::gpu::from_vk(VkFlags); - template stormkit::gpu::{% outfile:write(name) %} stormkit::gpu::from_vk({% outfile:write(enumeration.vktype) %}); - template VkFlags stormkit::gpu::to_vk(stormkit::gpu::{% outfile:write(name) %}); - template {% outfile:write(enumeration.vktype) %} stormkit::gpu::to_vk<{% outfile:write(enumeration.vktype) %}>(stormkit::gpu::{% outfile:write(name) %}); + template + stormkit::gpu::{% outfile:write(name) %} STORMKIT_GPU_API stormkit::gpu::vk::from_vk(VkFlags); + template + stormkit::gpu::{% outfile:write(name) %} STORMKIT_GPU_API stormkit::gpu::vk::from_vk({% outfile:write(enumeration.vktype) %}); + template + VkFlags STORMKIT_GPU_API stormkit::gpu::vk::to_vk(stormkit::gpu::{% outfile:write(name) %}); + template + {% outfile:write(enumeration.vktype) %} STORMKIT_GPU_API stormkit::gpu::vk::to_vk<{% outfile:write(enumeration.vktype) %}>(stormkit::gpu::{% outfile:write(name) %}); {% end %} - diff --git a/modules/stormkit/gpu/core/vulkan/mapping.json b/modules/stormkit/gpu/core/vulkan/mapping.json index 657643eda..81b3b7de6 100644 --- a/modules/stormkit/gpu/core/vulkan/mapping.json +++ b/modules/stormkit/gpu/core/vulkan/mapping.json @@ -16,7 +16,7 @@ "type": "u8", "vktype": "VkQueueFlagBits", "values": { - "NONE": { "vulkan": "0", "webgpu": "" }, + "NONE": { "vulkan": "0", "webgpu": "" }, "GRAPHICS": { "vulkan": "VK_QUEUE_GRAPHICS_BIT", "webgpu": "" }, "COMPUTE": { "vulkan": "VK_QUEUE_COMPUTE_BIT", "webgpu": "" }, "TRANSFER": { "vulkan": "VK_QUEUE_TRANSFER_BIT", "webgpu": "" }, @@ -151,22 +151,22 @@ "type": "u8", "vktype": "VkLogicOp", "values": { - "CLEAR": { "vulkan": "VK_LOGIC_OP_CLEAR", "webgpu": ""}, - "AND": { "vulkan": "VK_LOGIC_OP_AND", "webgpu": ""}, - "AND_REVERSE": { "vulkan": "VK_LOGIC_OP_AND_REVERSE", "webgpu": ""}, - "COPY": { "vulkan": "VK_LOGIC_OP_COPY", "webgpu": ""}, - "AND_INVERTED": { "vulkan": "VK_LOGIC_OP_AND_INVERTED", "webgpu": ""}, - "NO_OP": { "vulkan": "VK_LOGIC_OP_NO_OP", "webgpu": ""}, - "XOR": { "vulkan": "VK_LOGIC_OP_XOR", "webgpu": ""}, - "OR": { "vulkan": "VK_LOGIC_OP_OR", "webgpu": ""}, - "NOR": { "vulkan": "VK_LOGIC_OP_NOR", "webgpu": ""}, - "EQUIVALENT": { "vulkan": "VK_LOGIC_OP_EQUIVALENT", "webgpu": ""}, - "INVERT": { "vulkan": "VK_LOGIC_OP_INVERT", "webgpu": ""}, - "OR_REVERSE": { "vulkan": "VK_LOGIC_OP_OR_REVERSE", "webgpu": ""}, - "COPY_INVERTED": { "vulkan": "VK_LOGIC_OP_COPY_INVERTED","webgpu": ""}, - "OR_INVERTED": { "vulkan": "VK_LOGIC_OP_OR_INVERTED", "webgpu": ""}, - "NAND": { "vulkan": "VK_LOGIC_OP_NAND", "webgpu": ""}, - "SET": { "vulkan": "VK_LOGIC_OP_SET", "webgpu": ""} + "CLEAR": { "vulkan": "VK_LOGIC_OP_CLEAR", "webgpu": "" }, + "AND": { "vulkan": "VK_LOGIC_OP_AND", "webgpu": "" }, + "AND_REVERSE": { "vulkan": "VK_LOGIC_OP_AND_REVERSE", "webgpu": "" }, + "COPY": { "vulkan": "VK_LOGIC_OP_COPY", "webgpu": "" }, + "AND_INVERTED": { "vulkan": "VK_LOGIC_OP_AND_INVERTED", "webgpu": "" }, + "NO_OP": { "vulkan": "VK_LOGIC_OP_NO_OP", "webgpu": "" }, + "XOR": { "vulkan": "VK_LOGIC_OP_XOR", "webgpu": "" }, + "OR": { "vulkan": "VK_LOGIC_OP_OR", "webgpu": "" }, + "NOR": { "vulkan": "VK_LOGIC_OP_NOR", "webgpu": "" }, + "EQUIVALENT": { "vulkan": "VK_LOGIC_OP_EQUIVALENT", "webgpu": "" }, + "INVERT": { "vulkan": "VK_LOGIC_OP_INVERT", "webgpu": "" }, + "OR_REVERSE": { "vulkan": "VK_LOGIC_OP_OR_REVERSE", "webgpu": "" }, + "COPY_INVERTED": { "vulkan": "VK_LOGIC_OP_COPY_INVERTED","webgpu": "" }, + "OR_INVERTED": { "vulkan": "VK_LOGIC_OP_OR_INVERTED", "webgpu": "" }, + "NAND": { "vulkan": "VK_LOGIC_OP_NAND", "webgpu": "" }, + "SET": { "vulkan": "VK_LOGIC_OP_SET", "webgpu": "" } } }, "PixelFormat": { @@ -174,77 +174,78 @@ "type": "u32", "vktype": "VkFormat", "values": { - "UNDEFINED": { "vulkan": "VK_FORMAT_UNDEFINED", "webgpu": ""}, - "R8_SNORM": { "vulkan": "VK_FORMAT_R8_SNORM", "webgpu": ""}, - "RG8_SNORM": { "vulkan": "VK_FORMAT_R8G8_SNORM", "webgpu": ""}, - "RGB8_SNORM": { "vulkan": "VK_FORMAT_R8G8B8_SNORM", "webgpu": ""}, - "RGBA8_SNORM": { "vulkan": "VK_FORMAT_R8G8B8A8_SNORM", "webgpu": ""}, - "R8_UNORM": { "vulkan": "VK_FORMAT_R8_UNORM", "webgpu": ""}, - "RG8_UNORM": { "vulkan": "VK_FORMAT_R8G8_UNORM", "webgpu": ""}, - "RGB8_UNORM": { "vulkan": "VK_FORMAT_R8G8B8_UNORM", "webgpu": ""}, - "RGBA8_UNORM": { "vulkan": "VK_FORMAT_R8G8B8A8_UNORM", "webgpu": ""}, - "R16_SNORM": { "vulkan": "VK_FORMAT_R16_SNORM", "webgpu": ""}, - "RG16_SNORM": { "vulkan": "VK_FORMAT_R16G16_SNORM", "webgpu": ""}, - "RGB16_SNORM": { "vulkan": "VK_FORMAT_R16G16B16_SNORM", "webgpu": ""}, - "RGBA16_SNORM": { "vulkan": "VK_FORMAT_R16G16B16A16_SNORM", "webgpu": ""}, - "R16_UNORM": { "vulkan": "VK_FORMAT_R16_UNORM", "webgpu": ""}, - "RG16_UNORM": { "vulkan": "VK_FORMAT_R16G16_UNORM", "webgpu": ""}, - "RGB16_UNORM": { "vulkan": "VK_FORMAT_R16G16B16_UNORM", "webgpu": ""}, - "RGBA16_UNORM": { "vulkan": "VK_FORMAT_R16G16B16A16_UNORM", "webgpu": ""}, - "A2_RGB10_UNORM_PACK32": { "vulkan": "VK_FORMAT_A2R10G10B10_UNORM_PACK32", "webgpu": ""}, - "A2_RGB10_SNORM_PACK32": { "vulkan": "VK_FORMAT_A2R10G10B10_SNORM_PACK32", "webgpu": ""}, - "A2_RGB10U_PACK32": { "vulkan": "VK_FORMAT_A2R10G10B10_UINT_PACK32", "webgpu": ""}, - "A2_RGB10I_PACK32": { "vulkan": "VK_FORMAT_A2R10G10B10_SINT_PACK32", "webgpu": ""}, - "RGBA4_UNORM_PACK16": { "vulkan": "VK_FORMAT_R4G4B4A4_UNORM_PACK16", "webgpu": ""}, - "A1_RGB5_UNORM_PACK16": { "vulkan": "VK_FORMAT_A1R5G5B5_UNORM_PACK16", "webgpu": ""}, - "R5_G6_B5_UNORM_PACK16": { "vulkan": "VK_FORMAT_R5G6B5_UNORM_PACK16", "webgpu": ""}, - "BGR8_UNORM": { "vulkan": "VK_FORMAT_B8G8R8_UNORM", "webgpu": ""}, - "BGRA8_UNORM": { "vulkan": "VK_FORMAT_B8G8R8A8_UNORM", "webgpu": ""}, - "R8I": { "vulkan": "VK_FORMAT_R8_SINT", "webgpu": ""}, - "RG8I": { "vulkan": "VK_FORMAT_R8G8_SINT", "webgpu": ""}, - "RGB8I": { "vulkan": "VK_FORMAT_R8G8B8_SINT", "webgpu": ""}, - "RGBA8I": { "vulkan": "VK_FORMAT_R8G8B8A8_SINT", "webgpu": ""}, - "R8U": { "vulkan": "VK_FORMAT_R8_UINT", "webgpu": ""}, - "RG8U": { "vulkan": "VK_FORMAT_R8G8_UINT", "webgpu": ""}, - "RGB8U": { "vulkan": "VK_FORMAT_R8G8B8_UINT", "webgpu": ""}, - "RGBA8U": { "vulkan": "VK_FORMAT_R8G8B8A8_UINT", "webgpu": ""}, - "R16I": { "vulkan": "VK_FORMAT_R16_SINT", "webgpu": ""}, - "RG16I": { "vulkan": "VK_FORMAT_R16G16_SINT", "webgpu": ""}, - "RGB16I": { "vulkan": "VK_FORMAT_R16G16B16_SINT", "webgpu": ""}, - "RGBA16I": { "vulkan": "VK_FORMAT_R16G16B16A16_SINT", "webgpu": ""}, - "R16U": { "vulkan": "VK_FORMAT_R16_UINT", "webgpu": ""}, - "RG16U": { "vulkan": "VK_FORMAT_R16G16_UINT", "webgpu": ""}, - "RGB16U": { "vulkan": "VK_FORMAT_R16G16B16_UINT", "webgpu": ""}, - "RGBA16U": { "vulkan": "VK_FORMAT_R16G16B16A16_UINT", "webgpu": ""}, - "R32I": { "vulkan": "VK_FORMAT_R32_SINT", "webgpu": ""}, - "RG32I": { "vulkan": "VK_FORMAT_R32G32_SINT", "webgpu": ""}, - "RGB32I": { "vulkan": "VK_FORMAT_R32G32B32_SINT", "webgpu": ""}, - "RGBA32I": { "vulkan": "VK_FORMAT_R32G32B32A32_SINT", "webgpu": ""}, - "R32U": { "vulkan": "VK_FORMAT_R32_UINT", "webgpu": ""}, - "RG32U": { "vulkan": "VK_FORMAT_R32G32_UINT", "webgpu": ""}, - "RGB32U": { "vulkan": "VK_FORMAT_R32G32B32_UINT", "webgpu": ""}, - "RGBA32U": { "vulkan": "VK_FORMAT_R32G32B32A32_UINT", "webgpu": ""}, - "R16F": { "vulkan": "VK_FORMAT_R16_SFLOAT", "webgpu": ""}, - "RG16F": { "vulkan": "VK_FORMAT_R16G16_SFLOAT", "webgpu": ""}, - "RGB16F": { "vulkan": "VK_FORMAT_R16G16B16_SFLOAT", "webgpu": ""}, - "RGBA16F": { "vulkan": "VK_FORMAT_R16G16B16A16_SFLOAT", "webgpu": ""}, - "R32F": { "vulkan": "VK_FORMAT_R32_SFLOAT", "webgpu": ""}, - "RG32F": { "vulkan": "VK_FORMAT_R32G32_SFLOAT", "webgpu": ""}, - "RGB32F": { "vulkan": "VK_FORMAT_R32G32B32_SFLOAT", "webgpu": ""}, - "RGBA32F": { "vulkan": "VK_FORMAT_R32G32B32A32_SFLOAT", "webgpu": ""}, - "B10_GR11UF_PACK32": { "vulkan": "VK_FORMAT_B10G11R11_UFLOAT_PACK32", "webgpu": ""}, - "SR8": { "vulkan": "VK_FORMAT_R8_SRGB", "webgpu": ""}, - "SRG8": { "vulkan": "VK_FORMAT_R8G8_SRGB", "webgpu": ""}, - "SRGB8": { "vulkan": "VK_FORMAT_R8G8B8_SRGB", "webgpu": ""}, - "SRGBA8": { "vulkan": "VK_FORMAT_R8G8B8A8_SRGB", "webgpu": ""}, - "SBGR8": { "vulkan": "VK_FORMAT_B8G8R8_SRGB", "webgpu": ""}, - "SBGRA8": { "vulkan": "VK_FORMAT_B8G8R8A8_SRGB", "webgpu": ""}, - "DEPTH16_UNORM": { "vulkan": "VK_FORMAT_D16_UNORM", "webgpu": ""}, - "DEPTH24_UNORM_PACK32": { "vulkan": "VK_FORMAT_X8_D24_UNORM_PACK32", "webgpu": ""}, - "DEPTH32F": { "vulkan": "VK_FORMAT_D32_SFLOAT", "webgpu": ""}, - "DEPTH16_UNORM_STENCIL8U": { "vulkan": "VK_FORMAT_D16_UNORM_S8_UINT", "webgpu": ""}, - "DEPTH24_UNORM_STENCIL8U": { "vulkan": "VK_FORMAT_D24_UNORM_S8_UINT", "webgpu": ""}, - "DEPTH32F_STENCIL8U": { "vulkan": "VK_FORMAT_D32_SFLOAT_S8_UINT", "webgpu": ""} + "UNDEFINED": { "vulkan": "VK_FORMAT_UNDEFINED", "webgpu": "" }, + "R8_SNORM": { "vulkan": "VK_FORMAT_R8_SNORM", "webgpu": "" }, + "RG8_SNORM": { "vulkan": "VK_FORMAT_R8G8_SNORM", "webgpu": "" }, + "RGB8_SNORM": { "vulkan": "VK_FORMAT_R8G8B8_SNORM", "webgpu": "" }, + "RGBA8_SNORM": { "vulkan": "VK_FORMAT_R8G8B8A8_SNORM", "webgpu": "" }, + "R8_UNORM": { "vulkan": "VK_FORMAT_R8_UNORM", "webgpu": "" }, + "RG8_UNORM": { "vulkan": "VK_FORMAT_R8G8_UNORM", "webgpu": "" }, + "RGB8_UNORM": { "vulkan": "VK_FORMAT_R8G8B8_UNORM", "webgpu": "" }, + "RGBA8_UNORM": { "vulkan": "VK_FORMAT_R8G8B8A8_UNORM", "webgpu": "" }, + "R16_SNORM": { "vulkan": "VK_FORMAT_R16_SNORM", "webgpu": "" }, + "RG16_SNORM": { "vulkan": "VK_FORMAT_R16G16_SNORM", "webgpu": "" }, + "RGB16_SNORM": { "vulkan": "VK_FORMAT_R16G16B16_SNORM", "webgpu": "" }, + "RGBA16_SNORM": { "vulkan": "VK_FORMAT_R16G16B16A16_SNORM", "webgpu": "" }, + "R16_UNORM": { "vulkan": "VK_FORMAT_R16_UNORM", "webgpu": "" }, + "RG16_UNORM": { "vulkan": "VK_FORMAT_R16G16_UNORM", "webgpu": "" }, + "RGB16_UNORM": { "vulkan": "VK_FORMAT_R16G16B16_UNORM", "webgpu": "" }, + "RGBA16_UNORM": { "vulkan": "VK_FORMAT_R16G16B16A16_UNORM", "webgpu": "" }, + "A2_RGB10_UNORM_PACK32": { "vulkan": "VK_FORMAT_A2R10G10B10_UNORM_PACK32", "webgpu": "" }, + "A2_RGB10_SNORM_PACK32": { "vulkan": "VK_FORMAT_A2R10G10B10_SNORM_PACK32", "webgpu": "" }, + "A2_RGB10U_PACK32": { "vulkan": "VK_FORMAT_A2R10G10B10_UINT_PACK32", "webgpu": "" }, + "A2_RGB10I_PACK32": { "vulkan": "VK_FORMAT_A2R10G10B10_SINT_PACK32", "webgpu": "" }, + "RGBA4_UNORM_PACK16": { "vulkan": "VK_FORMAT_R4G4B4A4_UNORM_PACK16", "webgpu": "" }, + "A1_RGB5_UNORM_PACK16": { "vulkan": "VK_FORMAT_A1R5G5B5_UNORM_PACK16", "webgpu": "" }, + "R5_G6_B5_UNORM_PACK16": { "vulkan": "VK_FORMAT_R5G6B5_UNORM_PACK16", "webgpu": "" }, + "BGR8_UNORM": { "vulkan": "VK_FORMAT_B8G8R8_UNORM", "webgpu": "" }, + "BGRA8_UNORM": { "vulkan": "VK_FORMAT_B8G8R8A8_UNORM", "webgpu": "" }, + "R8I": { "vulkan": "VK_FORMAT_R8_SINT", "webgpu": "" }, + "RG8I": { "vulkan": "VK_FORMAT_R8G8_SINT", "webgpu": "" }, + "RGB8I": { "vulkan": "VK_FORMAT_R8G8B8_SINT", "webgpu": "" }, + "RGBA8I": { "vulkan": "VK_FORMAT_R8G8B8A8_SINT", "webgpu": "" }, + "R8U": { "vulkan": "VK_FORMAT_R8_UINT", "webgpu": "" }, + "RG8U": { "vulkan": "VK_FORMAT_R8G8_UINT", "webgpu": "" }, + "RGB8U": { "vulkan": "VK_FORMAT_R8G8B8_UINT", "webgpu": "" }, + "RGBA8U": { "vulkan": "VK_FORMAT_R8G8B8A8_UINT", "webgpu": "" }, + "R16I": { "vulkan": "VK_FORMAT_R16_SINT", "webgpu": "" }, + "RG16I": { "vulkan": "VK_FORMAT_R16G16_SINT", "webgpu": "" }, + "RGB16I": { "vulkan": "VK_FORMAT_R16G16B16_SINT", "webgpu": "" }, + "RGBA16I": { "vulkan": "VK_FORMAT_R16G16B16A16_SINT", "webgpu": "" }, + "R16U": { "vulkan": "VK_FORMAT_R16_UINT", "webgpu": "" }, + "RG16U": { "vulkan": "VK_FORMAT_R16G16_UINT", "webgpu": "" }, + "RGB16U": { "vulkan": "VK_FORMAT_R16G16B16_UINT", "webgpu": "" }, + "RGBA16U": { "vulkan": "VK_FORMAT_R16G16B16A16_UINT", "webgpu": "" }, + "R32I": { "vulkan": "VK_FORMAT_R32_SINT", "webgpu": "" }, + "RG32I": { "vulkan": "VK_FORMAT_R32G32_SINT", "webgpu": "" }, + "RGB32I": { "vulkan": "VK_FORMAT_R32G32B32_SINT", "webgpu": "" }, + "RGBA32I": { "vulkan": "VK_FORMAT_R32G32B32A32_SINT", "webgpu": "" }, + "R32U": { "vulkan": "VK_FORMAT_R32_UINT", "webgpu": "" }, + "RG32U": { "vulkan": "VK_FORMAT_R32G32_UINT", "webgpu": "" }, + "RGB32U": { "vulkan": "VK_FORMAT_R32G32B32_UINT", "webgpu": "" }, + "RGBA32U": { "vulkan": "VK_FORMAT_R32G32B32A32_UINT", "webgpu": "" }, + "R16F": { "vulkan": "VK_FORMAT_R16_SFLOAT", "webgpu": "" }, + "RG16F": { "vulkan": "VK_FORMAT_R16G16_SFLOAT", "webgpu": "" }, + "RGB16F": { "vulkan": "VK_FORMAT_R16G16B16_SFLOAT", "webgpu": "" }, + "RGBA16F": { "vulkan": "VK_FORMAT_R16G16B16A16_SFLOAT", "webgpu": "" }, + "R32F": { "vulkan": "VK_FORMAT_R32_SFLOAT", "webgpu": "" }, + "RG32F": { "vulkan": "VK_FORMAT_R32G32_SFLOAT", "webgpu": "" }, + "RGB32F": { "vulkan": "VK_FORMAT_R32G32B32_SFLOAT", "webgpu": "" }, + "RGBA32F": { "vulkan": "VK_FORMAT_R32G32B32A32_SFLOAT", "webgpu": "" }, + "B10_GR11UF_PACK32": { "vulkan": "VK_FORMAT_B10G11R11_UFLOAT_PACK32", "webgpu": "" }, + "SR8": { "vulkan": "VK_FORMAT_R8_SRGB", "webgpu": "" }, + "SRG8": { "vulkan": "VK_FORMAT_R8G8_SRGB", "webgpu": "" }, + "SRGB8": { "vulkan": "VK_FORMAT_R8G8B8_SRGB", "webgpu": "" }, + "SRGBA8": { "vulkan": "VK_FORMAT_R8G8B8A8_SRGB", "webgpu": "" }, + "SBGR8": { "vulkan": "VK_FORMAT_B8G8R8_SRGB", "webgpu": "" }, + "SBGRA8": { "vulkan": "VK_FORMAT_B8G8R8A8_SRGB", "webgpu": "" }, + "DEPTH16_UNORM": { "vulkan": "VK_FORMAT_D16_UNORM", "webgpu": "" }, + "DEPTH24_UNORM_PACK32": { "vulkan": "VK_FORMAT_X8_D24_UNORM_PACK32", "webgpu": "" }, + "DEPTH32F": { "vulkan": "VK_FORMAT_D32_SFLOAT", "webgpu": "" }, + "DEPTH16_UNORM_STENCIL8U": { "vulkan": "VK_FORMAT_D16_UNORM_S8_UINT", "webgpu": "" }, + "DEPTH24_UNORM_STENCIL8U": { "vulkan": "VK_FORMAT_D24_UNORM_S8_UINT", "webgpu": "" }, + "DEPTH32F_STENCIL8U": { "vulkan": "VK_FORMAT_D32_SFLOAT_S8_UINT", "webgpu": "" }, + "S8U": { "vulkan": "VK_FORMAT_S8_UINT", "webgpu": "" } } }, "AttachmentLoadOperation": { @@ -252,9 +253,9 @@ "type": "u8", "vktype": "VkAttachmentLoadOp", "values": { - "LOAD": { "vulkan": "VK_ATTACHMENT_LOAD_OP_LOAD", "webgpu": ""}, - "CLEAR": { "vulkan": "VK_ATTACHMENT_LOAD_OP_CLEAR", "webgpu": ""}, - "DONT_CARE": { "vulkan": "VK_ATTACHMENT_LOAD_OP_DONT_CARE", "webgpu": ""} + "LOAD": { "vulkan": "VK_ATTACHMENT_LOAD_OP_LOAD", "webgpu": "" }, + "CLEAR": { "vulkan": "VK_ATTACHMENT_LOAD_OP_CLEAR", "webgpu": "" }, + "DONT_CARE": { "vulkan": "VK_ATTACHMENT_LOAD_OP_DONT_CARE", "webgpu": "" } } }, "AttachmentStoreOperation": { @@ -262,8 +263,8 @@ "type": "u8", "vktype": "VkAttachmentStoreOp", "values": { - "STORE": { "vulkan": "VK_ATTACHMENT_STORE_OP_STORE", "webgpu": ""}, - "DONT_CARE": { "vulkan": "VK_ATTACHMENT_STORE_OP_DONT_CARE", "webgpu": ""} + "STORE": { "vulkan": "VK_ATTACHMENT_STORE_OP_STORE", "webgpu": "" }, + "DONT_CARE": { "vulkan": "VK_ATTACHMENT_STORE_OP_DONT_CARE", "webgpu": "" } } }, "PipelineBindPoint": { @@ -271,8 +272,8 @@ "type": "u8", "vktype": "VkPipelineBindPoint", "values": { - "GRAPHICS": { "vulkan": "VK_PIPELINE_BIND_POINT_GRAPHICS", "webgpu": ""}, - "COMPUTE": { "vulkan": "VK_PIPELINE_BIND_POINT_COMPUTE", "webgpu": ""} + "GRAPHICS": { "vulkan": "VK_PIPELINE_BIND_POINT_GRAPHICS", "webgpu": "" }, + "COMPUTE": { "vulkan": "VK_PIPELINE_BIND_POINT_COMPUTE", "webgpu": "" } } }, "ImageLayout": { @@ -280,19 +281,20 @@ "type": "u32", "vktype": "VkImageLayout", "values": { - "UNDEFINED": { "vulkan": "VK_IMAGE_LAYOUT_UNDEFINED", "webgpu": "" }, - "GENERAL": { "vulkan": "VK_IMAGE_LAYOUT_GENERAL", "webgpu": "" }, - "COLOR_ATTACHMENT_OPTIMAL": { "vulkan": "VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL", "webgpu": "" }, - "DEPTH_STENCIL_ATTACHMENT_OPTIMAL": { "vulkan": "VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL", "webgpu": "" }, - "DEPTH_STENCIL_READ_ONLY_OPTIMAL": { "vulkan": "VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL", "webgpu": "" }, - "SHADER_READ_ONLY_OPTIMAL": { "vulkan": "VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL", "webgpu": "" }, - "TRANSFER_SRC_OPTIMAL": { "vulkan": "VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL", "webgpu": "" }, - "TRANSFER_DST_OPTIMAL": { "vulkan": "VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL", "webgpu": "" }, - "PREINITIALIZED": { "vulkan": "VK_IMAGE_LAYOUT_PREINITIALIZED", "webgpu": "" }, + "UNDEFINED": { "vulkan": "VK_IMAGE_LAYOUT_UNDEFINED", "webgpu": "" }, + "GENERAL": { "vulkan": "VK_IMAGE_LAYOUT_GENERAL", "webgpu": "" }, + "ATTACHMENT_OPTIMAL": { "vulkan": "VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL", "webgpu": "" }, + "COLOR_ATTACHMENT_OPTIMAL": { "vulkan": "VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL", "webgpu": "" }, + "DEPTH_STENCIL_ATTACHMENT_OPTIMAL": { "vulkan": "VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL", "webgpu": "" }, + "DEPTH_STENCIL_READ_ONLY_OPTIMAL": { "vulkan": "VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL", "webgpu": "" }, + "SHADER_READ_ONLY_OPTIMAL": { "vulkan": "VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL", "webgpu": "" }, + "TRANSFER_SRC_OPTIMAL": { "vulkan": "VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL", "webgpu": "" }, + "TRANSFER_DST_OPTIMAL": { "vulkan": "VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL", "webgpu": "" }, + "PREINITIALIZED": { "vulkan": "VK_IMAGE_LAYOUT_PREINITIALIZED", "webgpu": "" }, "DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL": { "vulkan": "VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL", "webgpu": "" }, "DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL": { "vulkan": "VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL", "webgpu": "" }, - "PRESENT_SRC": { "vulkan": "VK_IMAGE_LAYOUT_PRESENT_SRC_KHR", "webgpu": "" }, - "SHARED_PRESENT": { "vulkan": "VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR", "webgpu": "" } + "PRESENT_SRC": { "vulkan": "VK_IMAGE_LAYOUT_PRESENT_SRC_KHR", "webgpu": "" }, + "SHARED_PRESENT": { "vulkan": "VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR", "webgpu": "" } } }, "ImageAspectFlag": { @@ -300,10 +302,10 @@ "type": "u8", "vktype": "VkImageAspectFlagBits", "values": { - "NONE": { "vulkan": "VK_IMAGE_ASPECT_NONE_KHR", "webgpu": ""}, - "COLOR": { "vulkan": "VK_IMAGE_ASPECT_COLOR_BIT", "webgpu": ""}, - "DEPTH": { "vulkan": "VK_IMAGE_ASPECT_DEPTH_BIT", "webgpu": ""}, - "STENCIL": { "vulkan": "VK_IMAGE_ASPECT_STENCIL_BIT", "webgpu": ""} + "NONE": { "vulkan": "VK_IMAGE_ASPECT_NONE_KHR", "webgpu": "" }, + "COLOR": { "vulkan": "VK_IMAGE_ASPECT_COLOR_BIT", "webgpu": "" }, + "DEPTH": { "vulkan": "VK_IMAGE_ASPECT_DEPTH_BIT", "webgpu": "" }, + "STENCIL": { "vulkan": "VK_IMAGE_ASPECT_STENCIL_BIT", "webgpu": "" } } }, "VertexInputRate": { @@ -311,8 +313,8 @@ "type": "u8", "vktype": "VkVertexInputRate", "values": { - "VERTEX": { "vulkan": "VK_VERTEX_INPUT_RATE_VERTEX", "webgpu": ""}, - "INSTANCE": { "vulkan": "VK_VERTEX_INPUT_RATE_INSTANCE", "webgpu": ""} + "VERTEX": { "vulkan": "VK_VERTEX_INPUT_RATE_VERTEX", "webgpu": "" }, + "INSTANCE": { "vulkan": "VK_VERTEX_INPUT_RATE_INSTANCE", "webgpu": "" } } }, "ImageCreateFlag": { @@ -320,19 +322,19 @@ "type": "u16", "vktype": "VkImageCreateFlagBits", "values": { - "NONE": { "vulkan": "0", "webgpu": "" }, - "SPARSE_BINDING": { "vulkan": "VK_IMAGE_CREATE_SPARSE_BINDING_BIT", "webgpu": ""}, - "SPARSE_RESIDENCY": { "vulkan": "VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT", "webgpu": ""}, - "SPARSE_ALIASED": { "vulkan": "VK_IMAGE_CREATE_SPARSE_ALIASED_BIT", "webgpu": ""}, - "MUTABLE_FORMAT": { "vulkan": "VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT", "webgpu": ""}, - "CUBE_COMPATIBLE": { "vulkan": "VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT", "webgpu": ""}, - "ALIAS": { "vulkan": "VK_IMAGE_CREATE_ALIAS_BIT", "webgpu": ""}, + "NONE": { "vulkan": "0", "webgpu": "" }, + "SPARSE_BINDING": { "vulkan": "VK_IMAGE_CREATE_SPARSE_BINDING_BIT", "webgpu": ""}, + "SPARSE_RESIDENCY": { "vulkan": "VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT", "webgpu": ""}, + "SPARSE_ALIASED": { "vulkan": "VK_IMAGE_CREATE_SPARSE_ALIASED_BIT", "webgpu": ""}, + "MUTABLE_FORMAT": { "vulkan": "VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT", "webgpu": ""}, + "CUBE_COMPATIBLE": { "vulkan": "VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT", "webgpu": ""}, + "ALIAS": { "vulkan": "VK_IMAGE_CREATE_ALIAS_BIT", "webgpu": ""}, "SPLIT_INSTANCE_BIND_REGIONS": { "vulkan": "VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT", "webgpu": ""}, - "ARRAY_2D_COMPATIBLE": { "vulkan": "VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT", "webgpu": ""}, + "ARRAY_2D_COMPATIBLE": { "vulkan": "VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT", "webgpu": ""}, "BLOCK_TEXEL_VIEW_COMPATIBLE": { "vulkan": "VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT", "webgpu": ""}, - "EXTENDED_USAGE": { "vulkan": "VK_IMAGE_CREATE_EXTENDED_USAGE_BIT", "webgpu": ""}, - "PROTECTED": { "vulkan": "VK_IMAGE_CREATE_PROTECTED_BIT", "webgpu": ""}, - "DISJOINT": { "vulkan": "VK_IMAGE_CREATE_DISJOINT_BIT", "webgpu": ""} + "EXTENDED_USAGE": { "vulkan": "VK_IMAGE_CREATE_EXTENDED_USAGE_BIT", "webgpu": ""}, + "PROTECTED": { "vulkan": "VK_IMAGE_CREATE_PROTECTED_BIT", "webgpu": ""}, + "DISJOINT": { "vulkan": "VK_IMAGE_CREATE_DISJOINT_BIT", "webgpu": ""} } }, "BufferUsageFlag": { @@ -340,15 +342,15 @@ "type": "u16", "vktype": "VkBufferUsageFlagBits", "values": { - "VERTEX": { "vulkan": "VK_BUFFER_USAGE_VERTEX_BUFFER_BIT", "webgpu": ""}, - "INDEX": { "vulkan": "VK_BUFFER_USAGE_INDEX_BUFFER_BIT", "webgpu": ""}, - "TRANSFER_SRC": { "vulkan": "VK_BUFFER_USAGE_TRANSFER_SRC_BIT", "webgpu": ""}, - "TRANSFER_DST": { "vulkan": "VK_BUFFER_USAGE_TRANSFER_DST_BIT", "webgpu": ""}, - "UNIFORM": { "vulkan": "VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT", "webgpu": ""}, - "STORAGE": { "vulkan": "VK_BUFFER_USAGE_STORAGE_BUFFER_BIT", "webgpu": ""}, + "VERTEX": { "vulkan": "VK_BUFFER_USAGE_VERTEX_BUFFER_BIT", "webgpu": ""}, + "INDEX": { "vulkan": "VK_BUFFER_USAGE_INDEX_BUFFER_BIT", "webgpu": ""}, + "TRANSFER_SRC": { "vulkan": "VK_BUFFER_USAGE_TRANSFER_SRC_BIT", "webgpu": ""}, + "TRANSFER_DST": { "vulkan": "VK_BUFFER_USAGE_TRANSFER_DST_BIT", "webgpu": ""}, + "UNIFORM": { "vulkan": "VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT", "webgpu": ""}, + "STORAGE": { "vulkan": "VK_BUFFER_USAGE_STORAGE_BUFFER_BIT", "webgpu": ""}, "UNIFORM_TEXEL": { "vulkan": "VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT", "webgpu": ""}, "STORAGE_TEXEL": { "vulkan": "VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT", "webgpu": ""}, - "INDIRECT": { "vulkan": "VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT", "webgpu": ""} + "INDIRECT": { "vulkan": "VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT", "webgpu": ""} } }, "ImageUsageFlag": { @@ -356,14 +358,14 @@ "type": "u16", "vktype": "VkImageUsageFlagBits", "values": { - "TRANSFER_SRC": { "vulkan": "VK_IMAGE_USAGE_TRANSFER_SRC_BIT", "webgpu": "" }, - "TRANSFER_DST": { "vulkan": "VK_IMAGE_USAGE_TRANSFER_DST_BIT", "webgpu": "" }, - "SAMPLED": { "vulkan": "VK_IMAGE_USAGE_SAMPLED_BIT", "webgpu": "" }, - "STORAGE": { "vulkan": "VK_IMAGE_USAGE_STORAGE_BIT", "webgpu": "" }, - "COLOR_ATTACHMENT": { "vulkan": "VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT", "webgpu": "" }, + "TRANSFER_SRC": { "vulkan": "VK_IMAGE_USAGE_TRANSFER_SRC_BIT", "webgpu": "" }, + "TRANSFER_DST": { "vulkan": "VK_IMAGE_USAGE_TRANSFER_DST_BIT", "webgpu": "" }, + "SAMPLED": { "vulkan": "VK_IMAGE_USAGE_SAMPLED_BIT", "webgpu": "" }, + "STORAGE": { "vulkan": "VK_IMAGE_USAGE_STORAGE_BIT", "webgpu": "" }, + "COLOR_ATTACHMENT": { "vulkan": "VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT", "webgpu": "" }, "DEPTH_STENCIL_ATTACHMENT": { "vulkan": "VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT", "webgpu": "" }, - "TRANSIENT_ATTACHMENT": { "vulkan": "VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT", "webgpu": "" }, - "INPUT_ATTACHMENT": { "vulkan": "VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT", "webgpu": "" } + "TRANSIENT_ATTACHMENT": { "vulkan": "VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT", "webgpu": "" }, + "INPUT_ATTACHMENT": { "vulkan": "VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT", "webgpu": "" } } }, "MemoryPropertyFlag": { @@ -371,10 +373,10 @@ "type": "u8", "vktype": "VkMemoryPropertyFlagBits", "values": { - "DEVICE_LOCAL": { "vulkan": "VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT", "webgpu": ""}, - "HOST_VISIBLE": { "vulkan": "VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT", "webgpu": ""}, + "DEVICE_LOCAL": { "vulkan": "VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT", "webgpu": ""}, + "HOST_VISIBLE": { "vulkan": "VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT", "webgpu": ""}, "HOST_COHERENT": { "vulkan": "VK_MEMORY_PROPERTY_HOST_COHERENT_BIT", "webgpu": ""}, - "HOST_CACHED": { "vulkan": "VK_MEMORY_PROPERTY_HOST_CACHED_BIT", "webgpu": ""} + "HOST_CACHED": { "vulkan": "VK_MEMORY_PROPERTY_HOST_CACHED_BIT", "webgpu": ""} } }, "CommandBufferLevel": { @@ -382,7 +384,7 @@ "type": "u8", "vktype": "VkCommandBufferLevel", "values": { - "PRIMARY": { "vulkan": "VK_COMMAND_BUFFER_LEVEL_PRIMARY", "webgpu": "" }, + "PRIMARY": { "vulkan": "VK_COMMAND_BUFFER_LEVEL_PRIMARY", "webgpu": "" }, "SECONDARY": { "vulkan": "VK_COMMAND_BUFFER_LEVEL_SECONDARY", "webgpu": "" } } }, @@ -391,17 +393,17 @@ "type": "u8", "vktype": "VkDescriptorType", "values": { - "SAMPLER": { "vulkan": "VK_DESCRIPTOR_TYPE_SAMPLER", "webgpu": "" }, + "SAMPLER": { "vulkan": "VK_DESCRIPTOR_TYPE_SAMPLER", "webgpu": "" }, "COMBINED_IMAGE_SAMPLER": { "vulkan": "VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER", "webgpu": "" }, - "SAMPLED_IMAGE": { "vulkan": "VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE", "webgpu": "" }, - "STORAGE_IMAGE": { "vulkan": "VK_DESCRIPTOR_TYPE_STORAGE_IMAGE", "webgpu": "" }, - "UNIFORM_TEXEL_BUFFER": { "vulkan": "VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER", "webgpu": "" }, - "STORAGE_TEXEL_BUFFER": { "vulkan": "VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER", "webgpu": "" }, - "UNIFORM_BUFFER": { "vulkan": "VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER", "webgpu": "" }, - "STORAGE_BUFFER": { "vulkan": "VK_DESCRIPTOR_TYPE_STORAGE_BUFFER", "webgpu": "" }, + "SAMPLED_IMAGE": { "vulkan": "VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE", "webgpu": "" }, + "STORAGE_IMAGE": { "vulkan": "VK_DESCRIPTOR_TYPE_STORAGE_IMAGE", "webgpu": "" }, + "UNIFORM_TEXEL_BUFFER": { "vulkan": "VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER", "webgpu": "" }, + "STORAGE_TEXEL_BUFFER": { "vulkan": "VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER", "webgpu": "" }, + "UNIFORM_BUFFER": { "vulkan": "VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER", "webgpu": "" }, + "STORAGE_BUFFER": { "vulkan": "VK_DESCRIPTOR_TYPE_STORAGE_BUFFER", "webgpu": "" }, "UNIFORM_BUFFER_DYNAMIC": { "vulkan": "VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC", "webgpu": "" }, "STORAGE_BUFFER_DYNAMIC": { "vulkan": "VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC", "webgpu": "" }, - "INPUT_ATTACHMENT": { "vulkan": "VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT", "webgpu": "" } + "INPUT_ATTACHMENT": { "vulkan": "VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT", "webgpu": "" } } }, "CompareOperation": { @@ -409,14 +411,14 @@ "type": "u8", "vktype": "VkCompareOp", "values": { - "NEVER": { "vulkan": "VK_COMPARE_OP_NEVER", "webgpu": "" }, - "LESS": { "vulkan": "VK_COMPARE_OP_LESS", "webgpu": "" }, - "EQUAL": { "vulkan": "VK_COMPARE_OP_EQUAL", "webgpu": "" }, - "LESS_OR_EQUAL": { "vulkan": "VK_COMPARE_OP_LESS_OR_EQUAL", "webgpu": "" }, - "GREATER": { "vulkan": "VK_COMPARE_OP_GREATER", "webgpu": "" }, - "NOT_EQUAL": { "vulkan": "VK_COMPARE_OP_NOT_EQUAL", "webgpu": "" }, + "NEVER": { "vulkan": "VK_COMPARE_OP_NEVER", "webgpu": "" }, + "LESS": { "vulkan": "VK_COMPARE_OP_LESS", "webgpu": "" }, + "EQUAL": { "vulkan": "VK_COMPARE_OP_EQUAL", "webgpu": "" }, + "LESS_OR_EQUAL": { "vulkan": "VK_COMPARE_OP_LESS_OR_EQUAL", "webgpu": "" }, + "GREATER": { "vulkan": "VK_COMPARE_OP_GREATER", "webgpu": "" }, + "NOT_EQUAL": { "vulkan": "VK_COMPARE_OP_NOT_EQUAL", "webgpu": "" }, "GREATER_OR_EQUAL": { "vulkan": "VK_COMPARE_OP_GREATER_OR_EQUAL", "webgpu": "" }, - "ALWAYS": { "vulkan": "VK_COMPARE_OP_ALWAYS", "webgpu": "" } + "ALWAYS": { "vulkan": "VK_COMPARE_OP_ALWAYS", "webgpu": "" } } }, "Filter": { @@ -424,8 +426,8 @@ "type": "u32", "vktype": "VkFilter", "values": { - "NEAREST": { "vulkan": "VK_FILTER_NEAREST", "webgpu": "" }, - "LINEAR": { "vulkan": "VK_FILTER_LINEAR", "webgpu": "" }, + "NEAREST": { "vulkan": "VK_FILTER_NEAREST", "webgpu": "" }, + "LINEAR": { "vulkan": "VK_FILTER_LINEAR", "webgpu": "" }, "CUBIC_IMG": { "vulkan": "VK_FILTER_CUBIC_IMG", "webgpu": "" } } }, @@ -434,10 +436,10 @@ "type": "u8", "vktype": "VkSamplerAddressMode", "values": { - "REPEAT": { "vulkan": "VK_SAMPLER_ADDRESS_MODE_REPEAT", "webgpu": "" }, - "MIRRORED_REPEAT": { "vulkan": "VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT", "webgpu": "" }, - "CLAMP_TO_EDGE": { "vulkan": "VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE", "webgpu": "" }, - "CLAMP_TO_BORDER": { "vulkan": "VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER", "webgpu": "" }, + "REPEAT": { "vulkan": "VK_SAMPLER_ADDRESS_MODE_REPEAT", "webgpu": "" }, + "MIRRORED_REPEAT": { "vulkan": "VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT", "webgpu": "" }, + "CLAMP_TO_EDGE": { "vulkan": "VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE", "webgpu": "" }, + "CLAMP_TO_BORDER": { "vulkan": "VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER", "webgpu": "" }, "MIRROR_CLAMP_TO_EDGE": { "vulkan": "VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE", "webgpu": "" } } }, @@ -447,11 +449,11 @@ "vktype": "VkBorderColor", "values": { "FLOAT_TRANSPARENT_BLACK": { "vulkan": "VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK", "webgpu": "" }, - "INT_TRANSPARENT_BLACK": { "vulkan": "VK_BORDER_COLOR_INT_TRANSPARENT_BLACK", "webgpu": "" }, - "FLOAT_OPAQUE_BLACK": { "vulkan": "VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK", "webgpu": "" }, - "INT_OPAQUE_BLACK": { "vulkan": "VK_BORDER_COLOR_INT_OPAQUE_BLACK", "webgpu": "" }, - "FLOAT_OPAQUE_WHITE": { "vulkan": "VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE", "webgpu": "" }, - "INT_OPAQUE_WHITE": { "vulkan": "VK_BORDER_COLOR_INT_OPAQUE_WHITE", "webgpu": "" } + "INT_TRANSPARENT_BLACK": { "vulkan": "VK_BORDER_COLOR_INT_TRANSPARENT_BLACK", "webgpu": "" }, + "FLOAT_OPAQUE_BLACK": { "vulkan": "VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK", "webgpu": "" }, + "INT_OPAQUE_BLACK": { "vulkan": "VK_BORDER_COLOR_INT_OPAQUE_BLACK", "webgpu": "" }, + "FLOAT_OPAQUE_WHITE": { "vulkan": "VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE", "webgpu": "" }, + "INT_OPAQUE_WHITE": { "vulkan": "VK_BORDER_COLOR_INT_OPAQUE_WHITE", "webgpu": "" } } }, "SamplerMipmapMode": { @@ -460,7 +462,7 @@ "vktype": "VkSamplerMipmapMode", "values": { "NEAREST": { "vulkan": "VK_SAMPLER_MIPMAP_MODE_NEAREST", "webgpu": "" }, - "LINEAR": { "vulkan": "VK_SAMPLER_MIPMAP_MODE_LINEAR", "webgpu": "" } + "LINEAR": { "vulkan": "VK_SAMPLER_MIPMAP_MODE_LINEAR", "webgpu": "" } } }, "Result": { @@ -468,42 +470,42 @@ "type": "i32", "vktype": "VkResult", "values": { - "SUCCESS": { "vulkan": "VK_SUCCESS", "webgpu": "" }, - "NOT_READY": { "vulkan": "VK_NOT_READY", "webgpu": "" }, - "TIMEOUT": { "vulkan": "VK_TIMEOUT", "webgpu": "" }, - "EVENT_SET": { "vulkan": "VK_EVENT_SET", "webgpu": "" }, - "EVENT_RESET": { "vulkan": "VK_EVENT_RESET", "webgpu": "" }, - "INCOMPLETE": { "vulkan": "VK_INCOMPLETE", "webgpu": "" }, - "ERROR_OUT_OF_HOST_MEMORY": { "vulkan": "VK_ERROR_OUT_OF_HOST_MEMORY", "webgpu": "" }, - "ERROR_OUT_OF_DEVICE_MEMORY": { "vulkan": "VK_ERROR_OUT_OF_DEVICE_MEMORY", "webgpu": "" }, - "ERROR_INITIALIZATION_FAILED": { "vulkan": "VK_ERROR_INITIALIZATION_FAILED", "webgpu": "" }, - "ERROR_DEVICE_LOST": { "vulkan": "VK_ERROR_DEVICE_LOST", "webgpu": "" }, - "ERROR_MEMORY_MAP_FAILED": { "vulkan": "VK_ERROR_MEMORY_MAP_FAILED", "webgpu": "" }, - "ERROR_LAYER_NOT_PRESENT": { "vulkan": "VK_ERROR_LAYER_NOT_PRESENT", "webgpu": "" }, - "ERROR_EXTENSION_NOT_PRESENT": { "vulkan": "VK_ERROR_EXTENSION_NOT_PRESENT", "webgpu": "" }, - "ERROR_FEATURE_NOT_PRESENT": { "vulkan": "VK_ERROR_FEATURE_NOT_PRESENT", "webgpu": "" }, - "ERROR_INCOMPATIBLE_DRIVER": { "vulkan": "VK_ERROR_INCOMPATIBLE_DRIVER", "webgpu": "" }, - "ERROR_TOO_MANY_OBJECTS": { "vulkan": "VK_ERROR_TOO_MANY_OBJECTS", "webgpu": "" }, - "ERROR_FORMAT_NOT_SUPPORTED": { "vulkan": "VK_ERROR_FORMAT_NOT_SUPPORTED", "webgpu": "" }, - "ERROR_FRAGMENTED_POOL": { "vulkan": "VK_ERROR_FRAGMENTED_POOL", "webgpu": "" }, - "ERROR_UNKNOWN": { "vulkan": "VK_ERROR_UNKNOWN", "webgpu": "" }, - "ERROR_OUT_OF_POOL_MEMORY": { "vulkan": "VK_ERROR_OUT_OF_POOL_MEMORY", "webgpu": "" }, - "ERROR_INVALID_EXTERNAL_HANDLE": { "vulkan": "VK_ERROR_INVALID_EXTERNAL_HANDLE", "webgpu": "" }, - "ERROR_FRAGMENTATION": { "vulkan": "VK_ERROR_FRAGMENTATION", "webgpu": "" }, - "ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS": { "vulkan": "VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS", "webgpu": "" }, - "ERROR_SURFACE_LOST": { "vulkan": "VK_ERROR_SURFACE_LOST_KHR", "webgpu": "" }, - "ERROR_NATIVE_WINDOW_IN_USE": { "vulkan": "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR", "webgpu": "" }, - "SUBOPTIMAL": { "vulkan": "VK_SUBOPTIMAL_KHR", "webgpu": "" }, - "ERROR_OUT_OF_DATE": { "vulkan": "VK_ERROR_OUT_OF_DATE_KHR", "webgpu": "" }, - "ERROR_INCOMPATIBLE_DISPLAY": { "vulkan": "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR", "webgpu": "" }, - "ERROR_VALIDATION_FAILED": { "vulkan": "VK_ERROR_VALIDATION_FAILED_EXT", "webgpu": "" }, - "ERROR_NOT_PERMITTED": { "vulkan": "VK_ERROR_NOT_PERMITTED", "webgpu": "" }, + "SUCCESS": { "vulkan": "VK_SUCCESS", "webgpu": "" }, + "NOT_READY": { "vulkan": "VK_NOT_READY", "webgpu": "" }, + "TIMEOUT": { "vulkan": "VK_TIMEOUT", "webgpu": "" }, + "EVENT_SET": { "vulkan": "VK_EVENT_SET", "webgpu": "" }, + "EVENT_RESET": { "vulkan": "VK_EVENT_RESET", "webgpu": "" }, + "INCOMPLETE": { "vulkan": "VK_INCOMPLETE", "webgpu": "" }, + "ERROR_OUT_OF_HOST_MEMORY": { "vulkan": "VK_ERROR_OUT_OF_HOST_MEMORY", "webgpu": "" }, + "ERROR_OUT_OF_DEVICE_MEMORY": { "vulkan": "VK_ERROR_OUT_OF_DEVICE_MEMORY", "webgpu": "" }, + "ERROR_INITIALIZATION_FAILED": { "vulkan": "VK_ERROR_INITIALIZATION_FAILED", "webgpu": "" }, + "ERROR_DEVICE_LOST": { "vulkan": "VK_ERROR_DEVICE_LOST", "webgpu": "" }, + "ERROR_MEMORY_MAP_FAILED": { "vulkan": "VK_ERROR_MEMORY_MAP_FAILED", "webgpu": "" }, + "ERROR_LAYER_NOT_PRESENT": { "vulkan": "VK_ERROR_LAYER_NOT_PRESENT", "webgpu": "" }, + "ERROR_EXTENSION_NOT_PRESENT": { "vulkan": "VK_ERROR_EXTENSION_NOT_PRESENT", "webgpu": "" }, + "ERROR_FEATURE_NOT_PRESENT": { "vulkan": "VK_ERROR_FEATURE_NOT_PRESENT", "webgpu": "" }, + "ERROR_INCOMPATIBLE_DRIVER": { "vulkan": "VK_ERROR_INCOMPATIBLE_DRIVER", "webgpu": "" }, + "ERROR_TOO_MANY_OBJECTS": { "vulkan": "VK_ERROR_TOO_MANY_OBJECTS", "webgpu": "" }, + "ERROR_FORMAT_NOT_SUPPORTED": { "vulkan": "VK_ERROR_FORMAT_NOT_SUPPORTED", "webgpu": "" }, + "ERROR_FRAGMENTED_POOL": { "vulkan": "VK_ERROR_FRAGMENTED_POOL", "webgpu": "" }, + "ERROR_UNKNOWN": { "vulkan": "VK_ERROR_UNKNOWN", "webgpu": "" }, + "ERROR_OUT_OF_POOL_MEMORY": { "vulkan": "VK_ERROR_OUT_OF_POOL_MEMORY", "webgpu": "" }, + "ERROR_INVALID_EXTERNAL_HANDLE": { "vulkan": "VK_ERROR_INVALID_EXTERNAL_HANDLE", "webgpu": "" }, + "ERROR_FRAGMENTATION": { "vulkan": "VK_ERROR_FRAGMENTATION", "webgpu": "" }, + "ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS": { "vulkan": "VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS", "webgpu": "" }, + "ERROR_SURFACE_LOST": { "vulkan": "VK_ERROR_SURFACE_LOST_KHR", "webgpu": "" }, + "ERROR_NATIVE_WINDOW_IN_USE": { "vulkan": "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR", "webgpu": "" }, + "SUBOPTIMAL": { "vulkan": "VK_SUBOPTIMAL_KHR", "webgpu": "" }, + "ERROR_OUT_OF_DATE": { "vulkan": "VK_ERROR_OUT_OF_DATE_KHR", "webgpu": "" }, + "ERROR_INCOMPATIBLE_DISPLAY": { "vulkan": "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR", "webgpu": "" }, + "ERROR_VALIDATION_FAILED": { "vulkan": "VK_ERROR_VALIDATION_FAILED_EXT", "webgpu": "" }, + "ERROR_NOT_PERMITTED": { "vulkan": "VK_ERROR_NOT_PERMITTED", "webgpu": "" }, "ERROR_FULLSCREEN_EXCLUSIVE_MODE_LOST": { "vulkan": "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT", "webgpu": "" }, - "THREAD_IDLE": { "vulkan": "VK_THREAD_IDLE_KHR", "webgpu": "" }, - "THREAD_DONE": { "vulkan": "VK_THREAD_DONE_KHR", "webgpu": "" }, - "OPERATION_DEFERRED": { "vulkan": "VK_OPERATION_DEFERRED_KHR", "webgpu": "" }, - "OPERATION_NOT_DEFERRED": { "vulkan": "VK_OPERATION_NOT_DEFERRED_KHR", "webgpu": "" }, - "PIPELINE_COMPILE_REQUIRED": { "vulkan": "VK_PIPELINE_COMPILE_REQUIRED", "webgpu": "" } + "THREAD_IDLE": { "vulkan": "VK_THREAD_IDLE_KHR", "webgpu": "" }, + "THREAD_DONE": { "vulkan": "VK_THREAD_DONE_KHR", "webgpu": "" }, + "OPERATION_DEFERRED": { "vulkan": "VK_OPERATION_DEFERRED_KHR", "webgpu": "" }, + "OPERATION_NOT_DEFERRED": { "vulkan": "VK_OPERATION_NOT_DEFERRED_KHR", "webgpu": "" }, + "PIPELINE_COMPILE_REQUIRED": { "vulkan": "VK_PIPELINE_COMPILE_REQUIRED", "webgpu": "" } } }, "ImageType": { @@ -511,9 +513,9 @@ "type": "u8", "vktype": "VkImageType", "values": { - "T1D": { "vulkan": "VK_IMAGE_TYPE_1D", "webgpu": ""}, - "T2D": { "vulkan": "VK_IMAGE_TYPE_2D", "webgpu": ""}, - "T3D": { "vulkan": "VK_IMAGE_TYPE_3D", "webgpu": ""} + "T1D": { "vulkan": "VK_IMAGE_TYPE_1D", "webgpu": "" }, + "T2D": { "vulkan": "VK_IMAGE_TYPE_2D", "webgpu": "" }, + "T3D": { "vulkan": "VK_IMAGE_TYPE_3D", "webgpu": "" } } }, "ImageViewType": { @@ -521,12 +523,12 @@ "type": "u8", "vktype": "VkImageViewType", "values": { - "T1D": { "vulkan": "VK_IMAGE_VIEW_TYPE_1D", "webgpu": "" }, - "T2D": { "vulkan": "VK_IMAGE_VIEW_TYPE_2D", "webgpu": "" }, - "T3D": { "vulkan": "VK_IMAGE_VIEW_TYPE_3D", "webgpu": "" }, - "CUBE": { "vulkan": "VK_IMAGE_VIEW_TYPE_CUBE", "webgpu": "" }, - "T1D_ARRAY": { "vulkan": "VK_IMAGE_VIEW_TYPE_1D_ARRAY", "webgpu": "" }, - "T2D_ARRAY": { "vulkan": "VK_IMAGE_VIEW_TYPE_2D_ARRAY", "webgpu": "" }, + "T1D": { "vulkan": "VK_IMAGE_VIEW_TYPE_1D", "webgpu": "" }, + "T2D": { "vulkan": "VK_IMAGE_VIEW_TYPE_2D", "webgpu": "" }, + "T3D": { "vulkan": "VK_IMAGE_VIEW_TYPE_3D", "webgpu": "" }, + "CUBE": { "vulkan": "VK_IMAGE_VIEW_TYPE_CUBE", "webgpu": "" }, + "T1D_ARRAY": { "vulkan": "VK_IMAGE_VIEW_TYPE_1D_ARRAY", "webgpu": "" }, + "T2D_ARRAY": { "vulkan": "VK_IMAGE_VIEW_TYPE_2D_ARRAY", "webgpu": "" }, "CUBE_ARRAY": { "vulkan": "VK_IMAGE_VIEW_TYPE_CUBE_ARRAY", "webgpu": "" } } }, @@ -535,36 +537,37 @@ "type": "u32", "vktype": "VkObjectType", "values": { - "UNKNOWN": { "vulkan": "VK_OBJECT_TYPE_UNKNOWN", "webgpu": "" }, - "INSTANCE": { "vulkan": "VK_OBJECT_TYPE_INSTANCE", "webgpu": "" }, - "PHYSICAL_DEVICE": { "vulkan": "VK_OBJECT_TYPE_PHYSICAL_DEVICE", "webgpu": "" }, - "DEVICE": { "vulkan": "VK_OBJECT_TYPE_DEVICE", "webgpu": "" }, - "QUEUE": { "vulkan": "VK_OBJECT_TYPE_QUEUE", "webgpu": "" }, - "SEMAPHORE": { "vulkan": "VK_OBJECT_TYPE_SEMAPHORE", "webgpu": "" }, - "COMMAND_BUFFER": { "vulkan": "VK_OBJECT_TYPE_COMMAND_BUFFER", "webgpu": "" }, - "FENCE": { "vulkan": "VK_OBJECT_TYPE_FENCE", "webgpu": "" }, - "DEVICE_MEMORY": { "vulkan": "VK_OBJECT_TYPE_DEVICE_MEMORY", "webgpu": "" }, - "BUFFER": { "vulkan": "VK_OBJECT_TYPE_BUFFER", "webgpu": "" }, - "IMAGE": { "vulkan": "VK_OBJECT_TYPE_IMAGE", "webgpu": "" }, - "EVENT": { "vulkan": "VK_OBJECT_TYPE_EVENT", "webgpu": "" }, - "QUERY_POOL": { "vulkan": "VK_OBJECT_TYPE_QUERY_POOL", "webgpu": "" }, - "BUFFER_VIEW": { "vulkan": "VK_OBJECT_TYPE_BUFFER_VIEW", "webgpu": "" }, - "IMAGE_VIEW": { "vulkan": "VK_OBJECT_TYPE_IMAGE_VIEW", "webgpu": "" }, - "SHADER_MODULE": { "vulkan": "VK_OBJECT_TYPE_SHADER_MODULE", "webgpu": "" }, - "PIPELINE_CACHE": { "vulkan": "VK_OBJECT_TYPE_PIPELINE_CACHE", "webgpu": "" }, - "PIPELINE_LAYOUT": { "vulkan": "VK_OBJECT_TYPE_PIPELINE_LAYOUT", "webgpu": "" }, - "RENDER_PASS": { "vulkan": "VK_OBJECT_TYPE_RENDER_PASS", "webgpu": "" }, - "PIPELINE": { "vulkan": "VK_OBJECT_TYPE_PIPELINE", "webgpu": "" }, - "DESCRIPTOR_SET_LAYOUT": { "vulkan": "VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT", "webgpu": "" }, - "SAMPLER": { "vulkan": "VK_OBJECT_TYPE_SAMPLER", "webgpu": "" }, - "DESCRIPTOR_POOL": { "vulkan": "VK_OBJECT_TYPE_DESCRIPTOR_POOL", "webgpu": "" }, - "DESCRIPTOR_SET": { "vulkan": "VK_OBJECT_TYPE_DESCRIPTOR_SET", "webgpu": "" }, - "FRAMEBUFFER": { "vulkan": "VK_OBJECT_TYPE_FRAMEBUFFER", "webgpu": "" }, - "COMMAND_POOL": { "vulkan": "VK_OBJECT_TYPE_COMMAND_POOL", "webgpu": "" }, - "SURFACE": { "vulkan": "VK_OBJECT_TYPE_SURFACE_KHR", "webgpu": "" }, - "SWAPCHAIN": { "vulkan": "VK_OBJECT_TYPE_SWAPCHAIN_KHR", "webgpu": "" }, + "UNKNOWN": { "vulkan": "VK_OBJECT_TYPE_UNKNOWN", "webgpu": "" }, + "INSTANCE": { "vulkan": "VK_OBJECT_TYPE_INSTANCE", "webgpu": "" }, + "PHYSICAL_DEVICE": { "vulkan": "VK_OBJECT_TYPE_PHYSICAL_DEVICE", "webgpu": "" }, + "DEVICE": { "vulkan": "VK_OBJECT_TYPE_DEVICE", "webgpu": "" }, + "QUEUE": { "vulkan": "VK_OBJECT_TYPE_QUEUE", "webgpu": "" }, + "SEMAPHORE": { "vulkan": "VK_OBJECT_TYPE_SEMAPHORE", "webgpu": "" }, + "COMMAND_BUFFER": { "vulkan": "VK_OBJECT_TYPE_COMMAND_BUFFER", "webgpu": "" }, + "FENCE": { "vulkan": "VK_OBJECT_TYPE_FENCE", "webgpu": "" }, + "DEVICE_MEMORY": { "vulkan": "VK_OBJECT_TYPE_DEVICE_MEMORY", "webgpu": "" }, + "BUFFER": { "vulkan": "VK_OBJECT_TYPE_BUFFER", "webgpu": "" }, + "IMAGE": { "vulkan": "VK_OBJECT_TYPE_IMAGE", "webgpu": "" }, + "EVENT": { "vulkan": "VK_OBJECT_TYPE_EVENT", "webgpu": "" }, + "QUERY_POOL": { "vulkan": "VK_OBJECT_TYPE_QUERY_POOL", "webgpu": "" }, + "BUFFER_VIEW": { "vulkan": "VK_OBJECT_TYPE_BUFFER_VIEW", "webgpu": "" }, + "IMAGE_VIEW": { "vulkan": "VK_OBJECT_TYPE_IMAGE_VIEW", "webgpu": "" }, + "SHADER_MODULE": { "vulkan": "VK_OBJECT_TYPE_SHADER_MODULE", "webgpu": "" }, + "PIPELINE_CACHE": { "vulkan": "VK_OBJECT_TYPE_PIPELINE_CACHE", "webgpu": "" }, + "PIPELINE_LAYOUT": { "vulkan": "VK_OBJECT_TYPE_PIPELINE_LAYOUT", "webgpu": "" }, + "RENDER_PASS": { "vulkan": "VK_OBJECT_TYPE_RENDER_PASS", "webgpu": "" }, + "PIPELINE": { "vulkan": "VK_OBJECT_TYPE_PIPELINE", "webgpu": "" }, + "DESCRIPTOR_SET_LAYOUT": { "vulkan": "VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT", "webgpu": "" }, + "SAMPLER": { "vulkan": "VK_OBJECT_TYPE_SAMPLER", "webgpu": "" }, + "DESCRIPTOR_POOL": { "vulkan": "VK_OBJECT_TYPE_DESCRIPTOR_POOL", "webgpu": "" }, + "DESCRIPTOR_SET": { "vulkan": "VK_OBJECT_TYPE_DESCRIPTOR_SET", "webgpu": "" }, + "FRAMEBUFFER": { "vulkan": "VK_OBJECT_TYPE_FRAMEBUFFER", "webgpu": "" }, + "COMMAND_POOL": { "vulkan": "VK_OBJECT_TYPE_COMMAND_POOL", "webgpu": "" }, + "SURFACE": { "vulkan": "VK_OBJECT_TYPE_SURFACE_KHR", "webgpu": "" }, + "SWAPCHAIN": { "vulkan": "VK_OBJECT_TYPE_SWAPCHAIN_KHR", "webgpu": "" }, + "DISPLAY": { "vulkan": "VK_OBJECT_TYPE_DISPLAY_KHR", "webgpu": "" }, "DEBUG_REPORT_CALLBACK": { "vulkan": "VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT", "webgpu": "" }, - "DISPLAY": { "vulkan": "VK_OBJECT_TYPE_DISPLAY_KHR", "webgpu": "" } + "DEBUG_UTILS_MESSENGER": { "vulkan": "VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT", "webgpu": "" } } }, "AccessFlag": { @@ -573,22 +576,22 @@ "vktype": "VkAccessFlagBits", "values": { "NONE": {"vulkan": "0", "webgpu": "" }, - "INDIRECT_COMMAND_READ": { "vulkan": "VK_ACCESS_INDIRECT_COMMAND_READ_BIT", "webgpu": "" }, - "VERTEX_ATTRIBUTE_READ": { "vulkan": "VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT", "webgpu": "" }, - "UNIFORM_READ": { "vulkan": "VK_ACCESS_UNIFORM_READ_BIT", "webgpu": "" }, - "INPUT_ATTACHMENT_READ": { "vulkan": "VK_ACCESS_INPUT_ATTACHMENT_READ_BIT", "webgpu": "" }, - "SHADER_READ": { "vulkan": "VK_ACCESS_SHADER_READ_BIT", "webgpu": "" }, - "SHADER_WRITE": { "vulkan": "VK_ACCESS_SHADER_WRITE_BIT", "webgpu": "" }, - "COLOR_ATTACHMENT_READ": { "vulkan": "VK_ACCESS_COLOR_ATTACHMENT_READ_BIT", "webgpu": "" }, - "COLOR_ATTACHMENT_WRITE": { "vulkan": "VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT", "webgpu": "" }, - "DEPTH_STENCIL_ATTACHMENT_READ": { "vulkan": "VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT", "webgpu": "" }, + "INDIRECT_COMMAND_READ": { "vulkan": "VK_ACCESS_INDIRECT_COMMAND_READ_BIT", "webgpu": "" }, + "VERTEX_ATTRIBUTE_READ": { "vulkan": "VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT", "webgpu": "" }, + "UNIFORM_READ": { "vulkan": "VK_ACCESS_UNIFORM_READ_BIT", "webgpu": "" }, + "INPUT_ATTACHMENT_READ": { "vulkan": "VK_ACCESS_INPUT_ATTACHMENT_READ_BIT", "webgpu": "" }, + "SHADER_READ": { "vulkan": "VK_ACCESS_SHADER_READ_BIT", "webgpu": "" }, + "SHADER_WRITE": { "vulkan": "VK_ACCESS_SHADER_WRITE_BIT", "webgpu": "" }, + "COLOR_ATTACHMENT_READ": { "vulkan": "VK_ACCESS_COLOR_ATTACHMENT_READ_BIT", "webgpu": "" }, + "COLOR_ATTACHMENT_WRITE": { "vulkan": "VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT", "webgpu": "" }, + "DEPTH_STENCIL_ATTACHMENT_READ": { "vulkan": "VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT", "webgpu": "" }, "DEPTH_STENCIL_ATTACHMENT_WRITE": { "vulkan": "VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT", "webgpu": "" }, - "TRANSFER_READ": { "vulkan": "VK_ACCESS_TRANSFER_READ_BIT", "webgpu": "" }, - "TRANSFER_WRITE": { "vulkan": "VK_ACCESS_TRANSFER_WRITE_BIT", "webgpu": "" }, - "HOST_READ": { "vulkan": "VK_ACCESS_HOST_READ_BIT", "webgpu": "" }, - "HOST_WRITE": { "vulkan": "VK_ACCESS_HOST_WRITE_BIT", "webgpu": "" }, - "MEMORY_READ": { "vulkan": "VK_ACCESS_MEMORY_READ_BIT", "webgpu": "" }, - "MEMORY_WRITE": { "vulkan": "VK_ACCESS_MEMORY_WRITE_BIT", "webgpu": "" } + "TRANSFER_READ": { "vulkan": "VK_ACCESS_TRANSFER_READ_BIT", "webgpu": "" }, + "TRANSFER_WRITE": { "vulkan": "VK_ACCESS_TRANSFER_WRITE_BIT", "webgpu": "" }, + "HOST_READ": { "vulkan": "VK_ACCESS_HOST_READ_BIT", "webgpu": "" }, + "HOST_WRITE": { "vulkan": "VK_ACCESS_HOST_WRITE_BIT", "webgpu": "" }, + "MEMORY_READ": { "vulkan": "VK_ACCESS_MEMORY_READ_BIT", "webgpu": "" }, + "MEMORY_WRITE": { "vulkan": "VK_ACCESS_MEMORY_WRITE_BIT", "webgpu": "" } } }, "PipelineStageFlag": { @@ -596,23 +599,23 @@ "type": "u32", "vktype": "VkPipelineStageFlagBits", "values": { - "TOP_OF_PIPE": { "vulkan": "VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT", "webgpu": ""}, - "DRAW_INDIRECT": { "vulkan": "VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT", "webgpu": ""}, - "VERTEX_INPUT": { "vulkan": "VK_PIPELINE_STAGE_VERTEX_INPUT_BIT", "webgpu": ""}, - "VERTEX_SHADER": { "vulkan": "VK_PIPELINE_STAGE_VERTEX_SHADER_BIT", "webgpu": ""}, - "TESSELLATION_CONTROL_SHADER": { "vulkan": "VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT", "webgpu": ""}, - "TESSELLATION_EVALUATION_SHADER": { "vulkan": "VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT", "webgpu": ""}, - "GEOMETRY_SHADER": { "vulkan": "VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT", "webgpu": ""}, - "FRAGMENT_SHADER": { "vulkan": "VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT", "webgpu": ""}, - "EARLY_FRAGMENT_TESTS": { "vulkan": "VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT", "webgpu": ""}, - "LATE_FRAGMENT_TESTS": { "vulkan": "VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT", "webgpu": ""}, - "COLOR_ATTACHMENT_OUTPUT": { "vulkan": "VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT", "webgpu": ""}, - "COMPUTE_SHADER": { "vulkan": "VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT", "webgpu": ""}, - "TRANSFER": { "vulkan": "VK_PIPELINE_STAGE_TRANSFER_BIT", "webgpu": ""}, - "BOTTOM_OF_PIPE": { "vulkan": "VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT", "webgpu": ""}, - "HOST": { "vulkan": "VK_PIPELINE_STAGE_HOST_BIT", "webgpu": ""}, - "ALL_GRAPHICS": { "vulkan": "VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT", "webgpu": ""}, - "ALL_COMMANDS": { "vulkan": "VK_PIPELINE_STAGE_ALL_COMMANDS_BIT", "webgpu": ""} + "TOP_OF_PIPE": { "vulkan": "VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT", "webgpu": "" }, + "DRAW_INDIRECT": { "vulkan": "VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT", "webgpu": "" }, + "VERTEX_INPUT": { "vulkan": "VK_PIPELINE_STAGE_VERTEX_INPUT_BIT", "webgpu": "" }, + "VERTEX_SHADER": { "vulkan": "VK_PIPELINE_STAGE_VERTEX_SHADER_BIT", "webgpu": "" }, + "TESSELLATION_CONTROL_SHADER": { "vulkan": "VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT", "webgpu": "" }, + "TESSELLATION_EVALUATION_SHADER": { "vulkan": "VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT", "webgpu": "" }, + "GEOMETRY_SHADER": { "vulkan": "VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT", "webgpu": "" }, + "FRAGMENT_SHADER": { "vulkan": "VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT", "webgpu": "" }, + "EARLY_FRAGMENT_TESTS": { "vulkan": "VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT", "webgpu": "" }, + "LATE_FRAGMENT_TESTS": { "vulkan": "VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT", "webgpu": "" }, + "COLOR_ATTACHMENT_OUTPUT": { "vulkan": "VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT", "webgpu": "" }, + "COMPUTE_SHADER": { "vulkan": "VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT", "webgpu": "" }, + "TRANSFER": { "vulkan": "VK_PIPELINE_STAGE_TRANSFER_BIT", "webgpu": "" }, + "BOTTOM_OF_PIPE": { "vulkan": "VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT", "webgpu": "" }, + "HOST": { "vulkan": "VK_PIPELINE_STAGE_HOST_BIT", "webgpu": "" }, + "ALL_GRAPHICS": { "vulkan": "VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT", "webgpu": "" }, + "ALL_COMMANDS": { "vulkan": "VK_PIPELINE_STAGE_ALL_COMMANDS_BIT", "webgpu": "" } } }, "DependencyFlag": { @@ -620,10 +623,10 @@ "type": "u8", "vktype": "VkDependencyFlagBits", "values": { - "NONE": { "vulkan": "0", "webgpu": "" }, - "BY_REGION": { "vulkan": "VK_DEPENDENCY_BY_REGION_BIT", "webgpu": "" }, + "NONE": { "vulkan": "0", "webgpu": "" }, + "BY_REGION": { "vulkan": "VK_DEPENDENCY_BY_REGION_BIT", "webgpu": "" }, "DEVICE_GROUP": { "vulkan": "VK_DEPENDENCY_DEVICE_GROUP_BIT", "webgpu": "" }, - "VIEW_LOCAL": { "vulkan": "VK_DEPENDENCY_VIEW_LOCAL_BIT", "webgpu": "" } + "VIEW_LOCAL": { "vulkan": "VK_DEPENDENCY_VIEW_LOCAL_BIT", "webgpu": "" } } }, "DynamicState": { @@ -631,15 +634,15 @@ "type": "u8", "vktype": "VkDynamicState", "values": { - "VIEWPORT": { "vulkan": "VK_DYNAMIC_STATE_VIEWPORT", "webgpu": "" }, - "SCISSOR": { "vulkan": "VK_DYNAMIC_STATE_SCISSOR", "webgpu": "" }, - "LINE_WIDTH": { "vulkan": "VK_DYNAMIC_STATE_LINE_WIDTH", "webgpu": "" }, - "DEPTH_BIAS": { "vulkan": "VK_DYNAMIC_STATE_DEPTH_BIAS", "webgpu": "" }, - "BLEND_CONSTANTS": { "vulkan": "VK_DYNAMIC_STATE_BLEND_CONSTANTS", "webgpu": "" }, - "DEPTH_BOUNDS": { "vulkan": "VK_DYNAMIC_STATE_DEPTH_BOUNDS", "webgpu": "" }, + "VIEWPORT": { "vulkan": "VK_DYNAMIC_STATE_VIEWPORT", "webgpu": "" }, + "SCISSOR": { "vulkan": "VK_DYNAMIC_STATE_SCISSOR", "webgpu": "" }, + "LINE_WIDTH": { "vulkan": "VK_DYNAMIC_STATE_LINE_WIDTH", "webgpu": "" }, + "DEPTH_BIAS": { "vulkan": "VK_DYNAMIC_STATE_DEPTH_BIAS", "webgpu": "" }, + "BLEND_CONSTANTS": { "vulkan": "VK_DYNAMIC_STATE_BLEND_CONSTANTS", "webgpu": "" }, + "DEPTH_BOUNDS": { "vulkan": "VK_DYNAMIC_STATE_DEPTH_BOUNDS", "webgpu": "" }, "STENCIL_COMPARE_MASK": { "vulkan": "VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK", "webgpu": "" }, - "STENCIL_WRITE_MASK": { "vulkan": "VK_DYNAMIC_STATE_STENCIL_WRITE_MASK", "webgpu": "" }, - "STENCIL_REFERENCE": { "vulkan": "VK_DYNAMIC_STATE_STENCIL_REFERENCE", "webgpu": "" } + "STENCIL_WRITE_MASK": { "vulkan": "VK_DYNAMIC_STATE_STENCIL_WRITE_MASK", "webgpu": "" }, + "STENCIL_REFERENCE": { "vulkan": "VK_DYNAMIC_STATE_STENCIL_REFERENCE", "webgpu": "" } } }, "ImageTiling": { @@ -648,7 +651,7 @@ "vktype": "VkImageTiling", "values": { "OPTIMAL": { "vulkan": "VK_IMAGE_TILING_OPTIMAL", "webgpu": "" }, - "LINEAR": { "vulkan": "VK_IMAGE_TILING_LINEAR", "webgpu": "" } + "LINEAR": { "vulkan": "VK_IMAGE_TILING_LINEAR", "webgpu": "" } } }, "StencilFaceFlag": { @@ -657,8 +660,8 @@ "vktype": "VkStencilFaceFlagBits", "values": { "FRONT": { "vulkan": "VK_STENCIL_FACE_FRONT_BIT", "webgpu": "" }, - "BACK": { "vulkan": "VK_STENCIL_FACE_BACK_BIT", "webgpu": "" }, - "FRONT_AND_BACK": { "vulkan": "FRONT | BACK", "webgpu": "" } + "BACK": { "vulkan": "VK_STENCIL_FACE_BACK_BIT", "webgpu": "" }, + "FRONT_AND_BACK": { "vulkan": "FRONT | BACK", "webgpu": "" } } }, "GeometryType": { @@ -667,7 +670,7 @@ "vktype": "VkGeometryTypeKHR", "values": { "TRIANGLES": { "vulkan": "VK_GEOMETRY_TYPE_TRIANGLES_KHR", "webgpu": "" }, - "AABBS": { "vulkan": "VK_GEOMETRY_TYPE_AABBS_KHR", "webgpu": "" }, + "AABBS": { "vulkan": "VK_GEOMETRY_TYPE_AABBS_KHR", "webgpu": "" }, "INSTANCES": { "vulkan": "VK_GEOMETRY_TYPE_INSTANCES_KHR", "webgpu": "" } } }, @@ -676,7 +679,7 @@ "type": "u8", "vktype": "VkGeometryFlagBitsKHR", "values": { - "OPAQUE": { "vulkan": "VK_GEOMETRY_OPAQUE_BIT_KHR", "webgpu": "" }, + "OPAQUE": { "vulkan": "VK_GEOMETRY_OPAQUE_BIT_KHR", "webgpu": "" }, "NO_DUPLICATE_ANY_HIT_INVOCATION": { "vulkan": "VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_KHR", "webgpu": "" } } }, @@ -685,22 +688,22 @@ "type": "u32", "vktype": "VkColorSpaceKHR", "values": { - "SRGB_NONLINEAR": { "vulkan": "VK_COLOR_SPACE_SRGB_NONLINEAR_KHR", "webgpu": "" }, - "DISPLAY_P3_NONLINEAR": { "vulkan": "VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT", "webgpu": "" }, - "EXTENDED_SRGB_LINEAR": { "vulkan": "VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT", "webgpu": "" }, - "DCI_P3_NONLINEAR": { "vulkan": "VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT", "webgpu": "" }, - "BT709_LINEAR": { "vulkan": "VK_COLOR_SPACE_BT709_LINEAR_EXT", "webgpu": "" }, - "BT709_NONLINEAR": { "vulkan": "VK_COLOR_SPACE_BT709_NONLINEAR_EXT", "webgpu": "" }, - "BT2020_LINEAR": { "vulkan": "VK_COLOR_SPACE_BT2020_LINEAR_EXT", "webgpu": "" }, - "HDR10_ST2084": { "vulkan": "VK_COLOR_SPACE_HDR10_ST2084_EXT", "webgpu": "" }, - "DOLBYVISION": { "vulkan": "VK_COLOR_SPACE_DOLBYVISION_EXT", "webgpu": "" }, - "HDR10_HLG": { "vulkan": "VK_COLOR_SPACE_HDR10_HLG_EXT", "webgpu": "" }, - "ADOBERGB_LINEAR": { "vulkan": "VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT", "webgpu": "" }, - "ADOBERGB_NONLINEAR": { "vulkan": "VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT", "webgpu": "" }, - "PASS_THROUGH": { "vulkan": "VK_COLOR_SPACE_PASS_THROUGH_EXT", "webgpu": "" }, + "SRGB_NONLINEAR": { "vulkan": "VK_COLOR_SPACE_SRGB_NONLINEAR_KHR", "webgpu": "" }, + "DISPLAY_P3_NONLINEAR": { "vulkan": "VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT", "webgpu": "" }, + "EXTENDED_SRGB_LINEAR": { "vulkan": "VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT", "webgpu": "" }, + "DCI_P3_NONLINEAR": { "vulkan": "VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT", "webgpu": "" }, + "BT709_LINEAR": { "vulkan": "VK_COLOR_SPACE_BT709_LINEAR_EXT", "webgpu": "" }, + "BT709_NONLINEAR": { "vulkan": "VK_COLOR_SPACE_BT709_NONLINEAR_EXT", "webgpu": "" }, + "BT2020_LINEAR": { "vulkan": "VK_COLOR_SPACE_BT2020_LINEAR_EXT", "webgpu": "" }, + "HDR10_ST2084": { "vulkan": "VK_COLOR_SPACE_HDR10_ST2084_EXT", "webgpu": "" }, + "DOLBYVISION": { "vulkan": "VK_COLOR_SPACE_DOLBYVISION_EXT", "webgpu": "" }, + "HDR10_HLG": { "vulkan": "VK_COLOR_SPACE_HDR10_HLG_EXT", "webgpu": "" }, + "ADOBERGB_LINEAR": { "vulkan": "VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT", "webgpu": "" }, + "ADOBERGB_NONLINEAR": { "vulkan": "VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT", "webgpu": "" }, + "PASS_THROUGH": { "vulkan": "VK_COLOR_SPACE_PASS_THROUGH_EXT", "webgpu": "" }, "EXTENDED_SRGB_NONLINEAR": { "vulkan": "VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT", "webgpu": "" }, - "DISPLAY_NATIVE_AMD": { "vulkan": "VK_COLOR_SPACE_DISPLAY_NATIVE_AMD", "webgpu": "" }, - "DISPLAY_P3_LINEAR": { "vulkan": "VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT", "webgpu": "" } + "DISPLAY_NATIVE_AMD": { "vulkan": "VK_COLOR_SPACE_DISPLAY_NATIVE_AMD", "webgpu": "" }, + "DISPLAY_P3_LINEAR": { "vulkan": "VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT", "webgpu": "" } } }, "PresentMode": { @@ -708,11 +711,11 @@ "type": "u32", "vktype": "VkPresentModeKHR", "values": { - "IMMEDIATE": { "vulkan": "VK_PRESENT_MODE_IMMEDIATE_KHR", "webgpu": "" }, - "MAILBOX": { "vulkan": "VK_PRESENT_MODE_MAILBOX_KHR", "webgpu": "" }, - "FIFO": { "vulkan": "VK_PRESENT_MODE_FIFO_KHR", "webgpu": "" }, - "FIFO_RELAXED": { "vulkan": "VK_PRESENT_MODE_FIFO_RELAXED_KHR", "webgpu": "" }, - "SHARED_DEMAND_REFRESH": { "vulkan": "VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR", "webgpu": "" }, + "IMMEDIATE": { "vulkan": "VK_PRESENT_MODE_IMMEDIATE_KHR", "webgpu": "" }, + "MAILBOX": { "vulkan": "VK_PRESENT_MODE_MAILBOX_KHR", "webgpu": "" }, + "FIFO": { "vulkan": "VK_PRESENT_MODE_FIFO_KHR", "webgpu": "" }, + "FIFO_RELAXED": { "vulkan": "VK_PRESENT_MODE_FIFO_RELAXED_KHR", "webgpu": "" }, + "SHARED_DEMAND_REFRESH": { "vulkan": "VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR", "webgpu": "" }, "SHARED_CONTINUOUS_REFRESH": { "vulkan": "VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR", "webgpu": "" } } }, @@ -721,29 +724,42 @@ "type": "u32", "vktype": "VkFormatFeatureFlagBits", "values": { - "SAMPLED_IMAGE": { "vulkan": "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", "webgpu": ""}, - "STORAGE_IMAGE": { "vulkan": "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", "webgpu": ""}, - "STORAGE_IMAGE_ATOMIC": { "vulkan": "VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT", "webgpu": ""}, - "UNIFORM_TEXEL_BUFFER": { "vulkan": "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", "webgpu": ""}, - "STORAGE_TEXEL_BUFFER": { "vulkan": "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", "webgpu": ""}, - "STORAGE_TEXEL_BUFFER_ATOMIC": { "vulkan": "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT", "webgpu": ""}, - "VERTEX_BUFFER": { "vulkan": "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT", "webgpu": ""}, - "COLOR_ATTACHMENT": { "vulkan": "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", "webgpu": ""}, - "COLOR_ATTACHMENT_BLEND": { "vulkan": "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", "webgpu": ""}, - "DEPTH_STENCIL_ATTACHMENT": { "vulkan": "VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT", "webgpu": ""}, - "BLIT_SRC": { "vulkan": "VK_FORMAT_FEATURE_BLIT_SRC_BIT", "webgpu": ""}, - "BLIT_DST": { "vulkan": "VK_FORMAT_FEATURE_BLIT_DST_BIT", "webgpu": ""}, - "SAMPLED_IMAGE_FILTER_LINEAR": { "vulkan": "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", "webgpu": ""}, - "TRANSFER_SRC": { "vulkan": "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", "webgpu": ""}, - "TRANSFER_DST": { "vulkan": "VK_FORMAT_FEATURE_TRANSFER_DST_BIT", "webgpu": ""}, - "MIDPOINT_CHROMA_SAMPLES": { "vulkan": "VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT", "webgpu": ""}, - "SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER": { "vulkan": "VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT", "webgpu": ""}, - "SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER": { "vulkan": "VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT", "webgpu": ""}, - "SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT": { "vulkan": "VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT", "webgpu": ""}, - "SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE": { "vulkan": "VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT", "webgpu": ""}, - "DISJOINT": { "vulkan": "VK_FORMAT_FEATURE_DISJOINT_BIT", "webgpu": ""}, - "COSITED_CHROMA_SAMPLES": { "vulkan": "VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT", "webgpu": ""}, - "SAMPLED_IMAGE_FILTER_MINMAX": { "vulkan": "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT", "webgpu": ""} - } + "SAMPLED_IMAGE": { "vulkan": "VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT", "webgpu": "" }, + "STORAGE_IMAGE": { "vulkan": "VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT", "webgpu": "" }, + "STORAGE_IMAGE_ATOMIC": { "vulkan": "VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT", "webgpu": "" }, + "UNIFORM_TEXEL_BUFFER": { "vulkan": "VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT", "webgpu": "" }, + "STORAGE_TEXEL_BUFFER": { "vulkan": "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT", "webgpu": "" }, + "STORAGE_TEXEL_BUFFER_ATOMIC": { "vulkan": "VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT", "webgpu": "" }, + "VERTEX_BUFFER": { "vulkan": "VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT", "webgpu": "" }, + "COLOR_ATTACHMENT": { "vulkan": "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT", "webgpu": "" }, + "COLOR_ATTACHMENT_BLEND": { "vulkan": "VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT", "webgpu": "" }, + "DEPTH_STENCIL_ATTACHMENT": { "vulkan": "VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT", "webgpu": "" }, + "BLIT_SRC": { "vulkan": "VK_FORMAT_FEATURE_BLIT_SRC_BIT", "webgpu": "" }, + "BLIT_DST": { "vulkan": "VK_FORMAT_FEATURE_BLIT_DST_BIT", "webgpu": "" }, + "SAMPLED_IMAGE_FILTER_LINEAR": { "vulkan": "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT", "webgpu": "" }, + "TRANSFER_SRC": { "vulkan": "VK_FORMAT_FEATURE_TRANSFER_SRC_BIT", "webgpu": "" }, + "TRANSFER_DST": { "vulkan": "VK_FORMAT_FEATURE_TRANSFER_DST_BIT", "webgpu": "" }, + "MIDPOINT_CHROMA_SAMPLES": { "vulkan": "VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT", "webgpu": "" }, + "SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER": { "vulkan": "VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT", "webgpu": "" }, + "SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER": { "vulkan": "VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT", "webgpu": "" }, + "SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT": { "vulkan": "VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT", "webgpu": "" }, + "SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE": { "vulkan": "VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT", "webgpu": "" }, + "DISJOINT": { "vulkan": "VK_FORMAT_FEATURE_DISJOINT_BIT", "webgpu": "" }, + "COSITED_CHROMA_SAMPLES": { "vulkan": "VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT", "webgpu": "" }, + "SAMPLED_IMAGE_FILTER_MINMAX": { "vulkan": "VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT", "webgpu": "" } + } + }, + "ResolveModeFlag": { + "flag": true, + "type": "u8", + "vktype": "VkResolveModeFlagBits", + "values": { + "NONE": { "vulkan": "VK_RESOLVE_MODE_NONE", "webgpu": "" }, + "SAMPLE_ZERO": { "vulkan": "VK_RESOLVE_MODE_SAMPLE_ZERO_BIT", "webgpu": "" }, + "AVERAGE": { "vulkan": "VK_RESOLVE_MODE_AVERAGE_BIT", "webgpu": "" }, + "MIN": { "vulkan": "VK_RESOLVE_MODE_MIN_BIT", "webgpu": "" }, + "MAX": { "vulkan": "VK_RESOLVE_MODE_MAX_BIT", "webgpu": "" }, + "EXTERNAL_FORMAT_DOWNSAMPLE_ANDROID": { "vulkan": "VK_RESOLVE_MODE_EXTERNAL_FORMAT_DOWNSAMPLE_ANDROID", "webgpu": "" } + } } } diff --git a/modules/stormkit/gpu/core/vulkan/structs.mpp b/modules/stormkit/gpu/core/vulkan/structs.cppm similarity index 64% rename from modules/stormkit/gpu/core/vulkan/structs.mpp rename to modules/stormkit/gpu/core/vulkan/structs.cppm index d27ccde16..61ffc8180 100644 --- a/modules/stormkit/gpu/core/vulkan/structs.mpp +++ b/modules/stormkit/gpu/core/vulkan/structs.cppm @@ -14,70 +14,71 @@ import :structs; import :vulkan.volk; -export namespace stormkit::gpu { +export namespace stormkit::gpu::vk { template requires( - requires { std::declval().native_handle(); } - or requires { std::declval()->native_handle(); }) + requires { std::declval().native_handle(); } or requires { std::declval()->native_handle(); }) [[nodiscard]] auto to_vk(const T& value) noexcept -> decltype(auto); template [[nodiscard]] - constexpr auto to_vk(const math::vec2i& vector) noexcept -> Out; + constexpr auto to_vk(const math::ivec2& vector) noexcept -> Out; template [[nodiscard]] - constexpr auto to_vk(const math::vec3i& vector) noexcept -> Out; + constexpr auto to_vk(const math::ivec3& vector) noexcept -> Out; // template<> // [[nodiscard]] - // constexpr auto to_vk(const math::vec2i& vector) noexcept + // constexpr auto to_vk(const math::ivec2& vector) noexcept // -> VkOffset2D; [[nodiscard]] constexpr auto from_vk(const VkFormatProperties& properties) noexcept -> FormatProperties; [[nodiscard]] - constexpr auto from_vk(const VkOffset2D& vector) noexcept -> math::vec2i; + constexpr auto from_vk(const VkOffset2D& vector) noexcept -> math::ivec2; [[nodiscard]] - constexpr auto from_vk(const VkOffset3D& vector) noexcept -> math::vec3i; + constexpr auto from_vk(const VkOffset3D& vector) noexcept -> math::ivec3; [[nodiscard]] constexpr auto to_vk(const Viewport& viewport) noexcept -> VkViewport; + [[nodiscard]] + constexpr auto to_vk(const math::irect& rect) noexcept -> VkRect2D; + [[nodiscard]] constexpr auto to_vk(const Scissor& viewport) noexcept -> VkRect2D; [[nodiscard]] constexpr auto from_vk(const VkViewport& viewport) noexcept -> Viewport; - template + template [[nodiscard]] - constexpr auto to_vk(const Extent& extent) noexcept -> VkExtent2D; + constexpr auto to_vk(const Extent& extent) noexcept -> Out; - template + template [[nodiscard]] - constexpr auto to_vk(const Extent& extent) noexcept -> VkExtent3D; + constexpr auto to_vk(const Extent& extent) noexcept -> Out; - template> + template [[nodiscard]] - constexpr auto from_vk(const VkExtent2D& viewport) noexcept -> Extent; + constexpr auto from_vk(const VkExtent2D& viewport) noexcept -> Out; - template> + template [[nodiscard]] - constexpr auto from_vk(const VkExtent3D& viewport) noexcept -> Extent; -} // namespace stormkit::gpu + constexpr auto from_vk(const VkExtent3D& viewport) noexcept -> Out; +} // namespace stormkit::gpu::vk -namespace stormkit::gpu { +namespace stormkit::gpu::vk { ///////////////////////////////////// ///////////////////////////////////// template requires( - requires { std::declval().native_handle(); } - or requires { std::declval()->native_handle(); }) + requires { std::declval().native_handle(); } or requires { std::declval()->native_handle(); }) STORMKIT_FORCE_INLINE STORMKIT_PURE inline auto to_vk(const T& value) noexcept -> decltype(auto) { @@ -86,6 +87,15 @@ namespace stormkit::gpu { return value.native_handle(); } + ///////////////////////////////////// + ///////////////////////////////////// + constexpr auto to_vk(const math::irect& rect) noexcept -> VkRect2D { + return VkRect2D { + .offset = { rect.x, rect.y }, + .extent = { as(rect.width.value), as(rect.height.value) } + }; + } + ///////////////////////////////////// ///////////////////////////////////// STORMKIT_FORCE_INLINE STORMKIT_PURE @@ -126,7 +136,7 @@ namespace stormkit::gpu { template STORMKIT_FORCE_INLINE STORMKIT_PURE - constexpr auto to_vk(const math::vec2i& vector) noexcept -> Out { + constexpr auto to_vk(const math::ivec2& vector) noexcept -> Out { return Out { .x = vector.x, .y = vector.y }; } @@ -135,7 +145,7 @@ namespace stormkit::gpu { template STORMKIT_FORCE_INLINE STORMKIT_PURE - constexpr auto to_vk(const math::vec3i& vector) noexcept -> Out { + constexpr auto to_vk(const math::ivec3& vector) noexcept -> Out { return Out { .x = vector.x, .y = vector.y, .z = vector.z }; } @@ -153,54 +163,60 @@ namespace stormkit::gpu { ///////////////////////////////////// ///////////////////////////////////// STORMKIT_FORCE_INLINE STORMKIT_PURE - constexpr auto from_vk(const VkOffset2D& offset) noexcept -> math::vec2i { - return math::vec2i { offset.x, offset.y }; + constexpr auto from_vk(const VkOffset2D& offset) noexcept -> math::ivec2 { + return math::ivec2 { offset.x, offset.y }; } ///////////////////////////////////// ///////////////////////////////////// STORMKIT_FORCE_INLINE STORMKIT_PURE - constexpr auto from_vk(const VkOffset3D& offset) noexcept -> math::vec3i { - return math::vec3i { offset.x, offset.y, offset.z }; + constexpr auto from_vk(const VkOffset3D& offset) noexcept -> math::ivec3 { + return math::ivec3 { offset.x, offset.y, offset.z }; } ///////////////////////////////////// ///////////////////////////////////// - template + template STORMKIT_FORCE_INLINE STORMKIT_PURE - constexpr auto to_vk(const Extent& extent) noexcept -> VkExtent2D { - return VkExtent2D { .width = as(extent.width), .height = as(extent.height) }; + constexpr auto to_vk(const Extent& extent) noexcept -> Out { + if constexpr (stormkit::meta::Is) + return VkExtent2D { .width = as(extent.width), .height = as(extent.height) }; + else + return Out { .x = extent.width, .y = extent.height }; } ///////////////////////////////////// ///////////////////////////////////// - template + template STORMKIT_FORCE_INLINE STORMKIT_PURE - constexpr auto to_vk(const Extent& extent) noexcept -> VkExtent3D { - return VkExtent3D { .width = as(extent.width), - .height = as(extent.height), - .depth = as(extent.depth) }; + constexpr auto to_vk(const Extent& extent) noexcept -> Out { + if constexpr (stormkit::meta::Is) + return VkExtent3D { .width = as(extent.width), + .height = as(extent.height), + .depth = as(extent.depth) }; + else + return Out { .x = extent.width, .y = extent.height, .z = extent.depth }; } ///////////////////////////////////// ///////////////////////////////////// - template + template STORMKIT_FORCE_INLINE STORMKIT_PURE - constexpr auto from_vk(const VkExtent2D& extent) noexcept -> Extent { - using T = typename Extent::ElementType; - return Extent { .width = as(extent.width), .height = as(extent.height) }; + constexpr auto from_vk(const VkExtent2D& extent) noexcept -> Out { + using T = typename Out::ValueType; + return Out { .width = as(extent.width), .height = as(extent.height) }; } ///////////////////////////////////// ///////////////////////////////////// - template + template STORMKIT_FORCE_INLINE STORMKIT_PURE - constexpr auto from_vk(const VkExtent3D& extent) noexcept -> Extent { - using T = typename Extent::ElementType; - return Extent { .width = as(extent.width), .height = as(extent.height) }; + constexpr auto from_vk(const VkExtent3D& extent) noexcept -> Out { + using T = typename Out::ValueType; + return Out { .width = as(extent.width), .height = as(extent.height) }; } -} // namespace stormkit::gpu +} // namespace stormkit::gpu::vk diff --git a/modules/stormkit/gpu/core/vulkan/utils.cppm b/modules/stormkit/gpu/core/vulkan/utils.cppm new file mode 100644 index 000000000..10c60211f --- /dev/null +++ b/modules/stormkit/gpu/core/vulkan/utils.cppm @@ -0,0 +1,588 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +#include + +export module stormkit.gpu.core:vulkan.utils; + +import std; + +import stormkit.core; +import stormkit.log; + +import :vulkan.enums; +import :vulkan.structs; + +namespace stdr = std::ranges; + +namespace cmeta = stormkit::core::meta; +namespace cmonadic = stormkit::core::monadic; + +export namespace stormkit::gpu::vk { + namespace meta { + template + concept IsVulkanFunc = std::invocable; + + template + concept HasOutValueAsArgument = IsVulkanFunc; + + template + concept HasNoReturnValue = IsVulkanFunc and cmeta::Is, void>; + + template + concept HasResultReturnValue = IsVulkanFunc and cmeta::Is, VkResult>; + } // namespace meta + + template + [[nodiscard]] + constexpr auto make_version(T major, T minor, T patch) noexcept -> u32; + [[nodiscard]] + constexpr auto version_major(std::integral auto version) noexcept -> u32; + [[nodiscard]] + constexpr auto version_minor(std::integral auto version) noexcept -> u32; + [[nodiscard]] + constexpr auto version_patch(std::integral auto version) noexcept -> u32; + + template Func> + requires meta::HasNoReturnValue + auto call(const Func& func, Args&&... args) noexcept -> void; + + template Func> + requires(not meta::HasNoReturnValue) + [[nodiscard]] + auto call(const Func& func, Args&&... args) noexcept -> Out; + + template Func> + requires meta::HasNoReturnValue + [[nodiscard]] + auto call(const Func& func, Args&&... args) noexcept -> Out; + + template Func> + auto call_checked(const Func& func, Args&&... args) noexcept -> Expected; + + template Out, VkResult... SUCCESS_RESULTS, typename... Args, meta::HasResultReturnValue Func> + auto call_checked(const Func& func, Args&&... args) noexcept -> Expected; + + template Func> + requires meta::HasResultReturnValue + auto call_checked(const Func& func, Args&&... args) noexcept -> Expected; + + template Func> + auto call_unchecked(const Func& func, Args&&... args) noexcept -> void; + + template Out, typename... Args, meta::HasResultReturnValue Func> + [[nodiscard]] + auto call_unchecked(const Func& func, Args&&... args) noexcept -> VkResult; + + template Func> + requires meta::HasResultReturnValue + [[nodiscard]] + auto call_unchecked(const Func& func, Args&&... args) noexcept -> Out; + + template Func> + requires(meta::HasNoReturnValue and not cmeta::SameAs) + [[nodiscard]] + auto allocate(usize count, const Func& func, Args&&... args) noexcept -> dyn_array; + + template Func> + requires(meta::HasResultReturnValue and not cmeta::SameAs) + auto allocate_checked(usize count, const Func& func, Args&&... args) noexcept -> Expected>; + + template Func> + requires(meta::HasResultReturnValue and not cmeta::SameAs) + [[nodiscard]] + auto allocate_unchecked(usize count, const Func& func, Args&&... args) noexcept -> dyn_array; + + template Func> + requires(meta::HasNoReturnValue and not cmeta::SameAs) + [[nodiscard]] + auto enumerate(const Func& func, Args&&... args) noexcept -> dyn_array; + + template Func> + requires(meta::HasResultReturnValue and not cmeta::SameAs) + auto enumerate_checked(const Func& func, Args&&... args) noexcept -> Expected>; + + template Func> + requires(meta::HasResultReturnValue and not cmeta::SameAs) + [[nodiscard]] + auto enumerate_unchecked(const Func& func, Args&&... args) noexcept -> dyn_array; + + template + class Owned { + public: + // TODO function + using Deleter = std::function; + + Owned(Deleter deleter) noexcept; + ~Owned() noexcept; + + Owned(const Owned&) = delete; + auto operator=(const Owned&) -> Owned& = delete; + + Owned(Owned&& other) noexcept; + auto operator=(Owned&& other) noexcept -> Owned&; + + auto operator=(T&& value) noexcept -> void; + + auto value() const noexcept -> T; + + operator T() const noexcept; + + private: + T m_value = VK_NULL_HANDLE; + Deleter m_deleter; + }; + + template + class Observer { + public: + Observer(T value) noexcept; + Observer(const Owned& value) noexcept; + + ~Observer() noexcept; + + Observer(const Observer&) noexcept; + auto operator=(const Observer&) noexcept -> Observer&; + + Observer(Observer&&) noexcept; + auto operator=(Observer&&) noexcept -> Observer&; + + auto value() const noexcept -> T; + + operator T() const noexcept; + + private: + T m_value; + }; + + namespace monadic { + template + [[nodiscard]] + constexpr auto to_vk() noexcept -> decltype(auto); + + [[nodiscard]] + constexpr auto to_vk() noexcept -> decltype(auto); + + [[nodiscard]] + constexpr auto from_vk() noexcept -> decltype(auto); + + template + [[nodiscard]] + constexpr auto from_vk() noexcept -> decltype(auto); + } // namespace monadic +} // namespace stormkit::gpu::vk + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit::gpu::vk { + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + STORMKIT_CONST + constexpr auto make_version(T major, T minor, T patch) noexcept -> u32 { + return version_major(major) | version_minor(minor) | version_patch(patch); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_CONST STORMKIT_INTRINSIC + constexpr auto version_major(std::integral auto version) noexcept -> u32 { + return as(version) >> 22u; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_CONST STORMKIT_INTRINSIC + constexpr auto version_minor(std::integral auto version) noexcept -> u32 { + return ((as(version) >> 12u) & 0x3ffu); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_CONST STORMKIT_INTRINSIC + constexpr auto version_patch(std::integral auto version) noexcept -> u32 { + return as(version) & 0xfffu; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template Func> + requires meta::HasNoReturnValue + STORMKIT_FORCE_INLINE + inline auto call(const Func& func, Args&&... args) noexcept -> void { + std::invoke(func, std::forward(args)...); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template Func> + requires(not meta::HasNoReturnValue) + STORMKIT_FORCE_INLINE + inline auto call(const Func& func, Args&&... args) noexcept -> Out { + return std::invoke(func, std::forward(args)...); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template Func> + requires meta::HasNoReturnValue + STORMKIT_FORCE_INLINE + inline auto call(const Func& func, Args&&... args) noexcept -> Out { + auto out = Out {}; + std::invoke(func, std::forward(args)..., &out); + return out; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template Func> + inline auto call_checked(const Func& func, Args&&... args) noexcept -> Expected { + static constexpr auto SUCCESS_RESULTS = array { VK_SUCCESS, _SUCCESS_RESULTS... }; + + using OutExpected = Expected; + auto out_expected = OutExpected { std::in_place }; + + const auto result = std::invoke(func, std::forward(args)...); + if (not stdr::any_of(SUCCESS_RESULTS, cmonadic::is_equal(result))) [[likely]] + out_expected = std::unexpected { vk::from_vk(result) }; + + return out_expected; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template Out, VkResult... _SUCCESS_RESULTS, typename... Args, meta::HasResultReturnValue Func> + inline auto call_checked(const Func& func, Args&&... args) noexcept -> Expected { + static constexpr auto SUCCESS_RESULTS = array { VK_SUCCESS, _SUCCESS_RESULTS... }; + + using OutExpected = Expected; + auto out_expected = OutExpected { std::in_place }; + + const auto result = std::invoke(func, std::forward(args)...); + if (not stdr::any_of(SUCCESS_RESULTS, cmonadic::is_equal(result))) [[likely]] + out_expected = std::unexpected { vk::from_vk(result) }; + else + out_expected = result; + + return out_expected; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template Func> + requires meta::HasResultReturnValue + inline auto call_checked(const Func& func, Args&&... args) noexcept -> Expected { + static constexpr auto SUCCESS_RESULTS = array { VK_SUCCESS, _SUCCESS_RESULTS... }; + + using OutExpected = Expected; + auto out_expected = OutExpected { std::in_place }; + + auto out = Out {}; + const auto result = std::invoke(func, std::forward(args)..., &out); + if (not stdr::any_of(SUCCESS_RESULTS, cmonadic::is_equal(result))) [[likely]] + out_expected = std::unexpected { vk::from_vk(result) }; + else + out_expected = out; + + return out_expected; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template Func> + STORMKIT_FORCE_INLINE + inline auto call_unchecked(const Func& func, Args&&... args) noexcept -> void { + const auto _ = std::invoke(func, std::forward(args)...); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template Out, typename... Args, meta::HasResultReturnValue Func> + STORMKIT_FORCE_INLINE + inline auto call_unchecked(const Func& func, Args&&... args) noexcept -> Out { + return std::invoke(func, std::forward(args)...); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template Func> + requires meta::HasResultReturnValue + STORMKIT_FORCE_INLINE + inline auto call_unchecked(const Func& func, Args&&... args) noexcept -> Out { + auto out = Out {}; + const auto _ = std::invoke(func, std::forward(args)..., &out); + return out; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template Func> + requires(meta::HasNoReturnValue and not cmeta::SameAs) + inline auto allocate(usize count, const Func& func, Args&&... args) noexcept -> dyn_array { + auto out = dyn_array {}; + out.resize(count, VK_NULL_HANDLE); + std::invoke(func, std::forward(args)..., stdr::data(out)); + return out; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template Func> + requires(meta::HasResultReturnValue and not cmeta::SameAs) + inline auto allocate_checked(usize count, const Func& func, Args&&... args) noexcept -> Expected> { + static constexpr auto SUCCESS_RESULTS = array { VK_SUCCESS, _SUCCESS_RESULTS... }; + + using OutExpected = Expected>; + auto out_expected = OutExpected { std::in_place }; + + auto& out = out_expected.value(); + out.resize(count, VK_NULL_HANDLE); + const auto result = std::invoke(func, std::forward(args)..., stdr::data(out)); + if (not stdr::any_of(SUCCESS_RESULTS, cmonadic::is_equal(result))) [[likely]] + out_expected = std::unexpected { vk::from_vk(result) }; + + return out_expected; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template Func> + requires(meta::HasResultReturnValue and not cmeta::SameAs) + inline auto allocate_unchecked(usize count, const Func& func, Args&&... args) noexcept -> dyn_array { + auto out = dyn_array {}; + out.resize(count, VK_NULL_HANDLE); + const auto _ = std::invoke(func, std::forward(args)..., stdr::data(out)); + return out; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template Func> + requires(meta::HasNoReturnValue and not cmeta::SameAs) + inline auto enumerate(const Func& func, Args&&... args) noexcept -> dyn_array { + auto out = dyn_array {}; + auto size = 0_u32; + std::invoke(func, std::forward(args)..., &size, nullptr); + out.resize(size); + std::invoke(func, std::forward(args)..., &size, stdr::data(out)); + + return out; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template Func> + requires(meta::HasResultReturnValue and not cmeta::SameAs) + inline auto enumerate_checked(const Func& func, Args&&... args) noexcept -> Expected> { + static constexpr auto SUCCESS_RESULTS = array { VK_SUCCESS, _SUCCESS_RESULTS... }; + + using OutExpected = Expected>; + auto out_expected = OutExpected { std::in_place }; + + auto out = dyn_array {}; + auto size = 0_u32; + { + const auto result = std::invoke(func, std::forward(args)..., &size, nullptr); + if (not stdr::any_of(SUCCESS_RESULTS, cmonadic::is_equal(result))) [[likely]] + out_expected = std::unexpected { vk::from_vk(result) }; + } + out.resize(size); + { + const auto result = std::invoke(func, std::forward(args)..., &size, stdr::data(out)); + if (not stdr::any_of(SUCCESS_RESULTS, cmonadic::is_equal(result))) [[likely]] + out_expected = std::unexpected { vk::from_vk(result) }; + else + out_expected = std::move(out); + } + + return out_expected; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template Func> + requires(meta::HasResultReturnValue and not cmeta::SameAs) + inline auto enumerate_unchecked(const Func& func, Args&&... args) noexcept -> dyn_array { + auto out = dyn_array {}; + auto size = 0_u32; + const auto _ = std::invoke(func, std::forward(args)..., &size, nullptr); + out.resize(size); + const auto _ = std::invoke(func, std::forward(args)..., &size, stdr::data(out)); + + return out; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline Owned::Owned(Deleter deleter) noexcept + : m_deleter { std::move(deleter) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline Owned::~Owned() noexcept { + if (m_value != VK_NULL_HANDLE) { + m_deleter(m_value); + m_value = VK_NULL_HANDLE; + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline Owned::Owned(Owned&& other) noexcept + : m_value { std::exchange(other.m_value, VK_NULL_HANDLE) }, m_deleter { std::move(other.m_deleter) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Owned::operator=(Owned&& other) noexcept -> Owned& { + if (this == &other) [[unlikely]] + return *this; + + m_value = std::exchange(other.m_value, VK_NULL_HANDLE); + m_deleter = std::move(other.m_deleter); + + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Owned::operator=(T&& value) noexcept -> void { + if (m_value == value) return; + if (m_value) m_deleter(m_value); + m_value = std::move(value); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Owned::value() const noexcept -> T { + return m_value; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline Owned::operator T() const noexcept { + return value(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline Observer::Observer(T value) noexcept + : m_value { value } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline Observer::Observer(const Owned& value) noexcept + : m_value { value.value() } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline Observer::~Observer() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline Observer::Observer(const Observer&) noexcept = default; + ///////////////////////////////////// + ///////////////////////////////////// + + template + STORMKIT_FORCE_INLINE + inline auto Observer::operator=(const Observer&) noexcept -> Observer& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline Observer::Observer(Observer&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Observer::operator=(Observer&&) noexcept -> Observer& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Observer::value() const noexcept -> T { + return m_value; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline Observer::operator T() const noexcept { + return value(); + } + + namespace monadic { + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto to_vk() noexcept -> decltype(auto) { + return [](const U& value) static noexcept -> decltype(auto) + requires(requires { gpu::vk::to_vk(std::declval()); }) + { return gpu::vk::to_vk(value); }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto to_vk() noexcept -> decltype(auto) { + return [](const T& value) static noexcept -> decltype(auto) { return gpu::vk::to_vk(value); }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto from_vk() noexcept -> decltype(auto) { + return [](auto val) static noexcept -> decltype(auto) { return gpu::vk::from_vk(val); }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + STORMKIT_CONST + constexpr auto from_vk() noexcept -> decltype(auto) { + return [](U val) static noexcept -> T + requires(requires { gpu::vk::from_vk(std::declval()); }) + { return gpu::vk::from_vk(val); }; + } + } // namespace monadic +} // namespace stormkit::gpu::vk diff --git a/modules/stormkit/gpu/core/vulkan/utils.mpp b/modules/stormkit/gpu/core/vulkan/utils.mpp deleted file mode 100644 index 926ce3048..000000000 --- a/modules/stormkit/gpu/core/vulkan/utils.mpp +++ /dev/null @@ -1,368 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -#include - -export module stormkit.gpu.core:vulkan.utils; - -import std; - -import stormkit.core; -import stormkit.log; - -import :vulkan.enums; -import :vulkan.structs; - -namespace stdr = std::ranges; - -export namespace stormkit::gpu { - template - [[nodiscard]] - constexpr auto vk_make_version(T major, T minor, T patch) noexcept -> u32; - [[nodiscard]] - constexpr auto vk_version_major(std::integral auto version) noexcept -> u32; - [[nodiscard]] - constexpr auto vk_version_minor(std::integral auto version) noexcept -> u32; - [[nodiscard]] - constexpr auto vk_version_patch(std::integral auto version) noexcept -> u32; - - template - using VulkanExpected = std::expected; - - template - concept IsVulkanFuncWithResult = core::meta::Is, VkResult>; - - template - auto vk_call(const Func& func, Args&&... args) noexcept -> decltype(auto); - - template - requires(IsVulkanFuncWithResult) - [[nodiscard]] - auto vk_call(const Func& func, Args&&... args) noexcept -> decltype(auto); - - template - [[nodiscard]] - auto vk_call(const Func& func, Args&&... args) noexcept -> decltype(auto); - - template - [[nodiscard]] - auto vk_call(const Func& func, - std::span success_result, - Args&&... args) noexcept -> T; - - template - requires(IsVulkanFuncWithResult or IsVulkanFuncWithResult) - [[nodiscard]] - auto vk_call(const Func& func, - std::span success_result, - Args&&... args) noexcept -> VulkanExpected; - - template - requires(IsVulkanFuncWithResult) - [[nodiscard]] - auto vk_allocate(usize count, const Func& func, Args&&... args) noexcept - -> VulkanExpected>; - - template - requires(IsVulkanFuncWithResult) - [[nodiscard]] - auto vk_allocate(usize count, - const Func& func, - std::span possible_results, - Args&&... args) noexcept -> VulkanExpected>; - - template - [[nodiscard]] - auto vk_enumerate(const Func& func, Args&&... args) noexcept -> decltype(auto); - - template - requires(IsVulkanFuncWithResult) - [[nodiscard]] - auto vk_enumerate(const Func& func, - std::span possible_results, - Args&&... args) noexcept -> VulkanExpected>; - - template - class VkRAIIHandle { - public: - // TODO function - using Deleter = std::function; - - constexpr VkRAIIHandle(Deleter deleter) noexcept : m_deleter { std::move(deleter) } {} - - constexpr ~VkRAIIHandle() noexcept { - if (m_value) { - m_deleter(m_value); - m_value = nullptr; - } - } - - VkRAIIHandle(const VkRAIIHandle&) = delete; - auto operator=(const VkRAIIHandle&) -> VkRAIIHandle& = delete; - - constexpr VkRAIIHandle(VkRAIIHandle&& other) noexcept - : m_value { std::exchange(other.m_value, nullptr) }, - m_deleter { std::move(other.m_deleter) } {} - - constexpr auto operator=(VkRAIIHandle&& other) noexcept -> VkRAIIHandle& { - if (this == &other) [[unlikely]] - return *this; - - m_value = std::exchange(other.m_value, nullptr); - m_deleter = std::move(other.m_deleter); - - return *this; - } - - constexpr auto operator=(T&& value) noexcept -> void { - if (m_value == value) return; - if (m_value) m_deleter(m_value); - m_value = std::move(value); - } - - constexpr auto value() const noexcept -> const T& { return m_value; } - - constexpr operator T() const noexcept { return value(); } - - private: - T m_value = nullptr; - Deleter m_deleter; - }; - - namespace monadic { - template - [[nodiscard]] - constexpr auto to_vk() noexcept -> decltype(auto); - - [[nodiscard]] - constexpr auto to_vk() noexcept -> decltype(auto); - - [[nodiscard]] - constexpr auto from_vk() noexcept -> decltype(auto); - - template - [[nodiscard]] - constexpr auto from_vk() noexcept -> decltype(auto); - } // namespace monadic -} // namespace stormkit::gpu - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::gpu { - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - STORMKIT_CONST - inline constexpr auto vk_make_version(T major, T minor, T patch) noexcept -> u32 { - return vk_version_major(major) | vk_version_minor(minor) | vk_version_patch(patch); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_CONST STORMKIT_INTRINSIC - inline constexpr auto vk_version_major(std::integral auto version) noexcept -> u32 { - return as(version) >> 22u; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_CONST STORMKIT_INTRINSIC - inline constexpr auto vk_version_minor(std::integral auto version) noexcept -> u32 { - return ((as(version) >> 12u) & 0x3ffu); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_CONST STORMKIT_INTRINSIC - inline constexpr auto vk_version_patch(std::integral auto version) noexcept -> u32 { - return as(version) & 0xfffu; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - inline auto vk_call(const Func& func, Args&&... args) noexcept -> decltype(auto) { - std::invoke(func, std::forward(args)...); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - requires(IsVulkanFuncWithResult) - STORMKIT_FORCE_INLINE - inline auto vk_call(const Func& func, Args&&... args) noexcept -> decltype(auto) { - static constexpr auto POSSIBLE_RESULTS = std::array { VK_SUCCESS }; - return vk_call(func, - as_view(POSSIBLE_RESULTS), - std::forward(args)...); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - inline auto vk_call(const Func& func, Args&&... args) noexcept -> decltype(auto) { - static constexpr auto POSSIBLE_RESULTS = std::array { VK_SUCCESS }; - if constexpr (IsVulkanFuncWithResult - or IsVulkanFuncWithResult) - return vk_call(func, - as_view(POSSIBLE_RESULTS), - std::forward(args)...); - else if constexpr (not core::meta::Is) { - auto out = T {}; - std::invoke(func, std::forward(args)..., &out); - return out; - } else - std::invoke(func, std::forward(args)...); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - requires(IsVulkanFuncWithResult or IsVulkanFuncWithResult) - inline auto vk_call(const Func& func, - std::span success_result, - Args&&... args) noexcept -> VulkanExpected { - using Out = VulkanExpected; - auto out = Out { std::in_place }; - - const auto result = [&] noexcept { - if constexpr (core::meta::IsOneOf) - return std::invoke(func, std::forward(args)...); - else if constexpr (core::meta::Is) { - const auto _result = std::invoke(func, std::forward(args)...); - out = _result; - return _result; - } else - return std::invoke(func, std::forward(args)..., &(*out)); - }(); - - if (not stdr::any_of(success_result, core::monadic::is_equal(result))) [[likely]] - out = Out { std::unexpect, result }; - - return out; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - requires(IsVulkanFuncWithResult) - STORMKIT_FORCE_INLINE - inline auto vk_allocate(usize count, const Func& func, Args&&... args) noexcept - -> VulkanExpected> { - static constexpr auto POSSIBLE_RESULTS = std::array { VK_SUCCESS }; - return vk_allocate(count, func, as_view(POSSIBLE_RESULTS), std::forward(args)...); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - requires(IsVulkanFuncWithResult) - inline auto vk_allocate(usize count, - const Func& func, - std::span possible_results, - Args&&... args) noexcept -> VulkanExpected> { - using Out = VulkanExpected>; - auto out = Out { std::in_place, count }; - auto result = std::invoke(func, std::forward(args)..., stdr::data(*out)); - if (not stdr::any_of(possible_results, core::monadic::is_equal(result))) [[unlikely]] - out = Out { std::unexpect, result }; - - return out; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - inline auto vk_enumerate(const Func& func, Args&&... args) noexcept -> decltype(auto) { - static constexpr auto POSSIBLE_RESULTS = std::array { VK_SUCCESS }; - if constexpr (IsVulkanFuncWithResult) - return vk_enumerate(func, - as_view(POSSIBLE_RESULTS), - std::forward(args)...); - else { - auto out = std::vector {}; - - auto size = Size { 0 }; - std::invoke(func, std::forward(args)..., &size, nullptr); - out.resize(size); - std::invoke(func, std::forward(args)..., &size, stdr::data(out)); - - return out; - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - requires(IsVulkanFuncWithResult) - inline auto vk_enumerate(const Func& func, - std::span possible_results, - Args&&... args) noexcept -> VulkanExpected> { - using Out = VulkanExpected>; - auto out = Out {}; - - auto size = Size { 0 }; - auto result = std::invoke(func, std::forward(args)..., &size, nullptr); - if (not stdr::any_of(possible_results, core::monadic::is_equal(result))) [[unlikely]] - out = Out { std::unexpect, result }; - - out = Out { std::in_place, size }; - if (out) [[likely]] { - result = std::invoke(func, std::forward(args)..., &size, stdr::data(*out)); - if (not stdr::any_of(possible_results, core::monadic::is_equal(result))) [[unlikely]] - out = Out { std::unexpect, result }; - } - - return out; - } - - namespace monadic { - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto to_vk() noexcept -> decltype(auto) { - return [](const U& value) static noexcept -> decltype(auto) - requires(requires { gpu::to_vk(std::declval()); }) - { return gpu::to_vk(value); }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto to_vk() noexcept -> decltype(auto) { - return [](const T& value) static noexcept -> decltype(auto) { - return gpu::to_vk(value); - }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto from_vk() noexcept -> decltype(auto) { - return [](auto val) static noexcept -> decltype(auto) { return gpu::from_vk(val); }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - STORMKIT_CONST - constexpr auto from_vk() noexcept -> decltype(auto) { - return [](U val) static noexcept -> T - requires(requires { gpu::from_vk(std::declval()); }) - { return gpu::from_vk(val); }; - } - } // namespace monadic -} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/core/vulkan/vma.mpp b/modules/stormkit/gpu/core/vulkan/vma.cppm similarity index 90% rename from modules/stormkit/gpu/core/vulkan/vma.mpp rename to modules/stormkit/gpu/core/vulkan/vma.cppm index 6daf39e8c..46a2e875c 100644 --- a/modules/stormkit/gpu/core/vulkan/vma.mpp +++ b/modules/stormkit/gpu/core/vulkan/vma.cppm @@ -3,11 +3,14 @@ module; #include #include +#include #include #define VMA_DYNAMIC_VULKAN_FUNCTIONS 0 #define VMA_STATIC_VULKAN_FUNCTIONS 0 -#define VMA_CALL_PRE STORMKIT_API +// #ifdef STORMKIT_GPU_BUILD +#define VMA_CALL_PRE STORMKIT_GPU_API +// #endif #include export module stormkit.gpu.core:vulkan.vma; diff --git a/modules/stormkit/gpu/core/vulkan/volk.mpp b/modules/stormkit/gpu/core/vulkan/volk.cppm similarity index 100% rename from modules/stormkit/gpu/core/vulkan/volk.mpp rename to modules/stormkit/gpu/core/vulkan/volk.cppm diff --git a/modules/stormkit/gpu/execution.mpp b/modules/stormkit/gpu/execution.cppm similarity index 94% rename from modules/stormkit/gpu/execution.mpp rename to modules/stormkit/gpu/execution.cppm index 80f2671cd..cda4a4c1d 100644 --- a/modules/stormkit/gpu/execution.mpp +++ b/modules/stormkit/gpu/execution.cppm @@ -6,6 +6,7 @@ export module stormkit.gpu.execution; export import :command_buffer; export import :descriptors; +export import :objects; export import :pipeline; export import :raster_pipeline; export import :render_pass; diff --git a/modules/stormkit/gpu/execution/command_buffer.cppm b/modules/stormkit/gpu/execution/command_buffer.cppm new file mode 100644 index 000000000..beec66520 --- /dev/null +++ b/modules/stormkit/gpu/execution/command_buffer.cppm @@ -0,0 +1,706 @@ +// Copyright (C) 2023 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include +#include + +#include +#include + +export module stormkit.gpu.execution:command_buffer; + +import std; + +import stormkit.core; +import stormkit.gpu.core; +import stormkit.gpu.resource; + +import :descriptors; +import :render_pass; +import :pipeline; +import :swapchain; +import :objects; + +namespace stdr = std::ranges; + +namespace cmonadic = stormkit::core::monadic; + +namespace stormkit::gpu { + export { + struct RenderPassInheritanceInfo { + std::optional render_pass = std::nullopt; + u32 subpass = 0; + std::optional framebuffer = std::nullopt; + }; + + struct RenderingInheritanceInfo { + u32 view_mask = 0; + dyn_array color_attachments = {}; + std::optional depth_attachment = std::nullopt; + std::optional stencil_attachment = std::nullopt; + SampleCountFlag rasterization_samples = SampleCountFlag::C1; + }; + + using InheritanceInfo = std::variant; + + struct RenderingInfo { + struct Attachment { + struct Resolve { + view::ImageView image_view; + ResolveModeFlag mode; + ImageLayout layout = ImageLayout::ATTACHMENT_OPTIMAL; + }; + + view::ImageView image_view; + ImageLayout layout = ImageLayout::ATTACHMENT_OPTIMAL; + + std::optional resolve = std::nullopt; + + AttachmentLoadOperation load_op = AttachmentLoadOperation::CLEAR; + AttachmentStoreOperation store_op = AttachmentStoreOperation::STORE; + + std::optional clear_value = std::nullopt; + }; + + math::irect render_area; + u32 layer_count = 1u; + u32 view_mask = 0u; + + dyn_array color_attachments = {}; + std::optional depth_attachment = std::nullopt; + std::optional stencil_attachment = std::nullopt; + }; + } + + struct QueueInterfaceBase { + struct SubmitInfo { + array_view wait_semaphores = {}; + array_view wait_dst_stages = {}; + array_view command_buffers = {}; + array_view signal_semaphores = {}; + }; + }; + + export template + class QueueInterface final: public DeviceObject, public QueueInterfaceBase { + public: + using DeviceObject::DeviceObject; + using DeviceObject::operator=; + using TagType = QueueTag; + + using QueueInterfaceBase::SubmitInfo; + + auto wait_idle() const noexcept -> Expected; + + auto submit(array_view submit_infos, std::optional fence = std::nullopt) const noexcept + -> Expected; + + auto submit(const SubmitInfo& submit_info, std::optional fence = std::nullopt) const noexcept + -> Expected; + + [[nodiscard]] + auto present(array_view swapchains, + array_view wait_semaphores, + array_view image_indices) const noexcept -> Expected; + + [[nodiscard]] + auto entry() const noexcept -> const QueueEntry&; + }; + + struct CommandBufferInterfaceBase { + enum class State { + INITIAL, + RECORDING, + EXECUTABLE, + }; + using RecordClosure = std23::function_ref; + }; + + export { + template + class CommandBufferInterface final: public DeviceObject, public CommandBufferInterfaceBase { + public: + using DeviceObject::DeviceObject; + using DeviceObject::operator=; + using TagType = CommandBufferTag; + + using CommandBufferInterfaceBase::RecordClosure; + using CommandBufferInterfaceBase::State; + + [[nodiscard]] + auto state() const noexcept -> State; + [[nodiscard]] + auto level() const noexcept -> CommandBufferLevel; + + auto record(this auto&, + RecordClosure record_closure, + bool one_time_submit = false, + InheritanceInfo inheritance_info = std::monostate {}) noexcept -> Expected; + + auto reset() noexcept -> Expected; + auto begin(bool one_time_submit = false, InheritanceInfo inheritance_info = std::monostate {}) noexcept + -> Expected; + auto end() noexcept -> Expected; + + auto begin_debug_region(string_view name, const fcolor_rgb& color = colors::WHITE) const noexcept + -> const CommandBufferInterface&; + auto insert_debug_label(string_view name, const fcolor_rgb& color = colors::WHITE) const noexcept + -> const CommandBufferInterface&; + auto end_debug_region() const noexcept -> const CommandBufferInterface&; + + auto begin_rendering(const RenderingInfo& info, bool secondary_commandbuffers = false) const noexcept + -> const CommandBufferInterface&; + auto begin_render_pass(view::RenderPass render_pass, + view::FrameBuffer framebuffer, + array_view clear_values = array { ClearValue { + ClearColor { .color = colors::SILVER } } }, + bool secondary_commandbuffers = false) const noexcept -> const CommandBufferInterface&; + auto next_subpass() const noexcept -> const CommandBufferInterface&; + auto end_render_pass() const noexcept -> const CommandBufferInterface&; + auto end_rendering() const noexcept -> const CommandBufferInterface&; + + auto bind_pipeline(view::Pipeline pipeline) const noexcept -> const CommandBufferInterface&; + auto set_viewport(u32 first_viewport, array_view viewports) const noexcept + -> const CommandBufferInterface&; + auto set_scissor(u32 first_scissor, array_view scissors) const noexcept + -> const CommandBufferInterface&; + auto set_line_width(f32 width) const noexcept -> const CommandBufferInterface&; + auto set_depth_bias(f32 constant_factor, f32 clamp, f32 slope_factor) const noexcept -> const CommandBufferInterface&; + auto set_blend_constants(array_view constants) const noexcept -> const CommandBufferInterface&; + auto set_depth_bounds(f32 min, f32 max) const noexcept -> const CommandBufferInterface&; + auto set_stencil_compare_mask(StencilFaceFlag face, u32 mask) const noexcept -> const CommandBufferInterface&; + auto set_stencil_write_mask(StencilFaceFlag face, u32 mask) const noexcept -> const CommandBufferInterface&; + auto set_stencil_reference(StencilFaceFlag face, u32 reference) const noexcept -> const CommandBufferInterface&; + + auto dispatch(u32 group_count_x, u32 group_count_y, u32 group_count_z) const noexcept + -> const CommandBufferInterface&; + + auto draw(u32 vertex_count, u32 instance_count = 1u, u32 first_vertex = 0, u32 first_instance = 0) const noexcept + -> const CommandBufferInterface&; + auto draw_indexed(u32 index_count, + u32 instance_count = 1u, + u32 first_index = 0u, + i32 vertex_offset = 0, + u32 first_instance = 0u) const noexcept -> const CommandBufferInterface&; + auto draw_indirect(view::Buffer buffer, usize offset, u32 draw_count, u32 stride) const noexcept + -> const CommandBufferInterface&; + auto draw_indexed_indirect(view::Buffer buffer, usize offset, u32 draw_count, u32 stride) const noexcept + -> const CommandBufferInterface&; + + auto bind_vertex_buffers(array_view buffers, array_view offsets) const noexcept + -> const CommandBufferInterface&; + auto bind_index_buffer(view::Buffer buffer, u64 offset = 0, bool large_indices = false) const noexcept + -> const CommandBufferInterface&; + auto bind_descriptor_sets(view::Pipeline pipeline, + view::PipelineLayout layout, + array_view descriptor_sets, + array_view dynamic_offsets = {}) const noexcept -> const CommandBufferInterface&; + + auto copy_buffer(view::Buffer src, view::Buffer dst, usize size, u64 src_offset = 0u, u64 dst_offset = 0u) + const noexcept -> const CommandBufferInterface&; + auto copy_buffer_to_image(view::Buffer src, + view::Image dst, + array_view buffer_image_copies = {}) const noexcept + -> const CommandBufferInterface&; + auto copy_image_to_buffer(view::Image src, + view::Buffer dst, + array_view buffer_image_copies = {}) const noexcept + -> const CommandBufferInterface&; + auto copy_image(view::Image src, + view::Image dst, + ImageLayout src_layout, + ImageLayout dst_layout, + const ImageSubresourceLayers& src_subresource_layers, + const ImageSubresourceLayers& dst_subresource_layers, + const math::uextent3& extent) const noexcept -> const CommandBufferInterface&; + + auto resolve_image(view::Image src, + view::Image dst, + ImageLayout src_layout, + ImageLayout dst_layout, + const ImageSubresourceLayers& src_subresource_layers = {}, + const ImageSubresourceLayers& dst_subresource_layers = {}) const noexcept + -> const CommandBufferInterface&; + + auto blit_image(view::Image src, + view::Image dst, + ImageLayout src_layout, + ImageLayout dst_layout, + array_view regions, + Filter filter) const noexcept -> const CommandBufferInterface&; + + auto transition_image_layout(view::Image image, + ImageLayout src_layout, + ImageLayout dst_layout, + const ImageSubresourceRange& subresource_range = {}) const noexcept + -> const CommandBufferInterface&; + + auto execute_sub_command_buffers(array_view commandbuffers) const noexcept + -> const CommandBufferInterface&; + + auto pipeline_barrier(PipelineStageFlag src_mask, + PipelineStageFlag dst_mask, + DependencyFlag dependency, + array_view memory_barriers, + array_view buffer_memory_barriers, + array_view image_memory_barriers) const noexcept + -> const CommandBufferInterface&; + + auto push_constants(view::PipelineLayout pipeline_layout, ShaderStageFlag stage, byte_view<> data, u32 offset = 0u) + const noexcept -> const CommandBufferInterface&; + + auto submit(this const auto&, + view::Queue queue, + array_view wait_semaphores = {}, + array_view wait_dst_stages = {}, + array_view signal_semaphores = {}, + std::optional fence = std::nullopt) noexcept -> Expected; + }; + } + + class STORMKIT_GPU_API QueueImplementation: public GpuObjectImplementation { + public: + using SubmitInfo = QueueInterfaceBase::SubmitInfo; + + QueueImplementation(PrivateTag, view::Device&& device) noexcept; + ~QueueImplementation() noexcept; + + QueueImplementation(const QueueImplementation&) = delete; + auto operator=(const QueueImplementation&) = delete; + + QueueImplementation(QueueImplementation&&) noexcept; + auto operator=(QueueImplementation&&) noexcept -> QueueImplementation&; + + auto do_init(PrivateTag, const QueueEntry&) -> void; + + protected: + QueueEntry m_entry; + + friend class QueueInterface; + }; + + namespace view { + class QueueImplementation: public GpuObjectViewImplementation { + public: + using SubmitInfo = QueueInterfaceBase::SubmitInfo; + + QueueImplementation(const gpu::Queue& of) noexcept; + template TContainerOrPointer> + QueueImplementation(const TContainerOrPointer&) noexcept; + ~QueueImplementation() noexcept; + + QueueImplementation(const QueueImplementation&) noexcept; + auto operator=(const QueueImplementation&) noexcept -> QueueImplementation&; + + QueueImplementation(QueueImplementation&&) noexcept; + auto operator=(QueueImplementation&&) noexcept -> QueueImplementation&; + + protected: + QueueEntry m_entry; + }; + } // namespace view + + using CommandBufferDeleter = std::function; + + class STORMKIT_GPU_API CommandBufferImplementation + : public GpuObjectImplementation { + public: + using RecordClosure = CommandBufferInterfaceBase::RecordClosure; + using State = CommandBufferInterfaceBase::State; + + CommandBufferImplementation(PrivateTag, view::Device&&) noexcept; + ~CommandBufferImplementation() noexcept; + + CommandBufferImplementation(const CommandBufferImplementation&) = delete; + auto operator=(const CommandBufferImplementation&) -> CommandBufferImplementation& = delete; + + CommandBufferImplementation(CommandBufferImplementation&&) noexcept; + auto operator=(CommandBufferImplementation&&) noexcept -> CommandBufferImplementation&; + + auto do_init(PrivateTag, CommandBufferLevel, VkCommandBuffer&&, CommandBufferDeleter&&) noexcept -> void; + + protected: + using NamedConstructor::allocate; + using NamedConstructor::create; + + Heap m_state; + CommandBufferLevel m_level = CommandBufferLevel::PRIMARY; + + CommandBufferDeleter m_deleter; + + friend class CommandPoolInterface; + friend class CommandPoolInterface; + friend class view::CommandBufferImplementation; + }; + + namespace view { + class CommandBufferImplementation: public GpuObjectViewImplementation { + public: + using RecordClosure = CommandBufferInterfaceBase::RecordClosure; + using State = CommandBufferInterfaceBase::State; + + CommandBufferImplementation(const gpu::CommandBuffer& of) noexcept; + template TContainerOrPointer> + CommandBufferImplementation(const TContainerOrPointer&) noexcept; + ~CommandBufferImplementation() noexcept; + + CommandBufferImplementation(const CommandBufferImplementation&) noexcept; + auto operator=(const CommandBufferImplementation&) noexcept -> CommandBufferImplementation&; + + CommandBufferImplementation(CommandBufferImplementation&&) noexcept; + auto operator=(CommandBufferImplementation&&) noexcept -> CommandBufferImplementation&; + + protected: + ref m_state; + CommandBufferLevel m_level; + }; + } // namespace view + + export { + struct CommandPoolInterfaceBase { + struct CreateInfo { + view::Queue queue; + bool reset = true; + bool transient = false; + }; + }; + + template + class CommandPoolInterface final: public DeviceObject, public CommandPoolInterfaceBase { + public: + using DeviceObject::DeviceObject; + using DeviceObject::operator=; + using TagType = CommandPoolTag; + + auto create_command_buffer(CommandBufferLevel level = CommandBufferLevel::PRIMARY) const noexcept + -> Expected; + auto create_command_buffers(usize count, CommandBufferLevel level = CommandBufferLevel::PRIMARY) const noexcept + -> Expected>; + + auto allocate_command_buffer(CommandBufferLevel level = CommandBufferLevel::PRIMARY) const noexcept + -> Expected>; + auto allocate_command_buffers(usize count, CommandBufferLevel level = CommandBufferLevel::PRIMARY) const noexcept + -> Expected>>; + + protected: + auto create_vk_command_buffers(usize, CommandBufferLevel) const noexcept -> Expected>; + + static auto delete_vk_command_buffers(view::Device, view::CommandPool, VkCommandBuffer) noexcept -> void; + }; + } + + class STORMKIT_GPU_API + CommandPoolImplementation: public GpuObjectImplementation { + public: + using CreateInfo = CommandPoolInterfaceBase::CreateInfo; + + CommandPoolImplementation(PrivateTag, view::Device&& device) noexcept; + ~CommandPoolImplementation() noexcept; + + CommandPoolImplementation(const CommandPoolImplementation&) = delete; + auto operator=(const CommandPoolImplementation&) = delete; + + CommandPoolImplementation(CommandPoolImplementation&&) noexcept; + auto operator=(CommandPoolImplementation&&) noexcept -> CommandPoolImplementation&; + + auto do_init(PrivateTag, const CreateInfo&) noexcept -> Expected; + }; + + namespace view { + class CommandPoolImplementation: public GpuObjectViewImplementation { + public: + using GpuObjectViewImplementation::GpuObjectViewImplementation; + using GpuObjectViewImplementation::operator=; + }; + } // namespace view +} // namespace stormkit::gpu + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit::gpu { + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto QueueInterface::submit(const SubmitInfo& submit_info, std::optional fence) const noexcept + -> Expected { + return QueueInterface::submit(array_view { &submit_info, 1 }, std::move(fence)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto QueueInterface::entry() const noexcept -> const QueueEntry& { + return Base::m_entry; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto CommandBufferInterface::submit(this const auto& self, + view::Queue queue, + array_view wait_semaphores, + array_view wait_dst_stages, + array_view signal_semaphores, + std::optional fence) noexcept -> Expected { + auto cmbs = as_views(self); + auto submit_infos = array { + Queue::SubmitInfo { + .wait_semaphores = wait_semaphores, + .wait_dst_stages = wait_dst_stages, + .command_buffers = cmbs, + .signal_semaphores = signal_semaphores } + }; + + return queue.submit(submit_infos, std::move(fence)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto CommandBufferInterface::state() const noexcept -> State { + EXPECTS(Base::m_state != nullptr); + return *Base::m_state; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto CommandBufferInterface::level() const noexcept -> CommandBufferLevel { + return Base::m_level; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto CommandBufferInterface::record(this auto& self, + RecordClosure record_closure, + bool one_time_submit, + InheritanceInfo inheritance_info) noexcept -> Expected { + Try(self.begin(one_time_submit, std::move(inheritance_info))); + record_closure(gpu::as_view(self)); + Try(self.end()); + Return {}; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto CommandPoolInterface::create_command_buffer(CommandBufferLevel level) const noexcept + -> Expected { + auto device = Base::owner(); + auto vk_handle = Try(create_vk_command_buffers(1, level)).front(); + Return CommandBuffer::create(std::move(device), level, std::move(vk_handle), delete_vk_command_buffers); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto CommandPoolInterface::create_command_buffers(usize count, CommandBufferLevel level) const noexcept + -> Expected> { + Return transform(Try(create_vk_command_buffers(count, level)), [this, &level](auto vk_handle) noexcept { + auto device = Base::owner(); + return CommandBuffer::create(std::move(device), level, std::move(vk_handle), delete_vk_command_buffers); + }); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto CommandPoolInterface::allocate_command_buffer(CommandBufferLevel level) const noexcept + -> Expected> { + auto device = Base::owner(); + auto vk_handle = Try(create_vk_command_buffers(1, level)).front(); + Return CommandBuffer::allocate(std::move(device), level, std::move(vk_handle), delete_vk_command_buffers); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto CommandPoolInterface::allocate_command_buffers(usize count, CommandBufferLevel level) const noexcept + -> Expected>> { + Return transform(Try(create_vk_command_buffers(count, level)), [this, &level](auto vk_handle) noexcept { + auto device = Base::owner(); + return CommandBuffer::allocate(std::move(device), level, std::move(vk_handle), delete_vk_command_buffers); + }); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline QueueImplementation::QueueImplementation(PrivateTag, view::Device&& device) noexcept + : GpuObjectImplementation { std::move(device), cmonadic::noop() } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline QueueImplementation::~QueueImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline QueueImplementation::QueueImplementation(QueueImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto QueueImplementation::operator=(QueueImplementation&&) noexcept -> QueueImplementation& = default; + + namespace view { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline QueueImplementation::QueueImplementation(const gpu::Queue& of) noexcept + : GpuObjectViewImplementation { of }, m_entry { of.entry() } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template TContainerOrPointer> + STORMKIT_FORCE_INLINE + inline QueueImplementation::QueueImplementation(const TContainerOrPointer& of) noexcept + : QueueImplementation { *of } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline QueueImplementation::~QueueImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline QueueImplementation::QueueImplementation(const QueueImplementation&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto QueueImplementation::operator=(const QueueImplementation&) noexcept -> QueueImplementation& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline QueueImplementation::QueueImplementation(QueueImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto QueueImplementation::operator=(QueueImplementation&&) noexcept -> QueueImplementation& = default; + } // namespace view + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline CommandBufferImplementation::CommandBufferImplementation(PrivateTag, view::Device&& device) noexcept + : GpuObjectImplementation { std::move(device), cmonadic::noop() } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline CommandBufferImplementation::~CommandBufferImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline CommandBufferImplementation::CommandBufferImplementation(CommandBufferImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBufferImplementation::operator=(CommandBufferImplementation&&) noexcept + -> CommandBufferImplementation& = default; + + namespace view { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline CommandBufferImplementation::CommandBufferImplementation(const gpu::CommandBuffer& of) noexcept + : GpuObjectViewImplementation { of }, m_state { as_ref_mut(of.m_state) }, m_level { of.level() } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template TContainerOrPointer> + STORMKIT_FORCE_INLINE + inline CommandBufferImplementation::CommandBufferImplementation(const TContainerOrPointer& of) noexcept + : CommandBufferImplementation { *of } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline CommandBufferImplementation::~CommandBufferImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline CommandBufferImplementation::CommandBufferImplementation(const CommandBufferImplementation&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBufferImplementation::operator=(const CommandBufferImplementation& other) noexcept + -> CommandBufferImplementation& { + if (&other == this) [[unlikely]] + return *this; + + GpuObjectViewImplementation::operator=(other); + + m_level = other.m_level; + m_state = as_ref_mut(other.m_state); + + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline CommandBufferImplementation::CommandBufferImplementation(CommandBufferImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBufferImplementation::operator=(CommandBufferImplementation&&) noexcept + -> CommandBufferImplementation& = default; + } // namespace view + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline CommandPoolImplementation::CommandPoolImplementation(PrivateTag, view::Device&& device) noexcept + : GpuObjectImplementation { std::move(device), &VolkDeviceTable::vkDestroyCommandPool } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline CommandPoolImplementation::~CommandPoolImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline CommandPoolImplementation::CommandPoolImplementation(CommandPoolImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandPoolImplementation::operator=(CommandPoolImplementation&&) noexcept + -> CommandPoolImplementation& = default; +} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/execution/command_buffer.mpp b/modules/stormkit/gpu/execution/command_buffer.mpp deleted file mode 100644 index 68e82118e..000000000 --- a/modules/stormkit/gpu/execution/command_buffer.mpp +++ /dev/null @@ -1,915 +0,0 @@ -// Copyright (C) 2023 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include -#include -#include - -#include - -export module stormkit.gpu.execution:command_buffer; - -import std; - -import stormkit.core; -import stormkit.gpu.core; -import stormkit.gpu.resource; - -import :descriptors; -import :render_pass; -import :pipeline; -import :swapchain; - -namespace stdr = std::ranges; - -export namespace stormkit::gpu { - struct SubmitInfo { - std::span> wait_semaphores = {}; - std::span wait_dst_stages = {}; - std::span> command_buffers = {}; - std::span> signal_semaphores = {}; - }; - - class SwapChain; - - class STORMKIT_API Queue { - struct PrivateFuncTag {}; - - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::QUEUE; - - static auto create(const Device& device, const Device::QueueEntry& entry) noexcept -> Queue; - static auto allocate(const Device& device, const Device::QueueEntry& entry) noexcept - -> Heap; - ~Queue() noexcept; - - Queue(const Queue&) = delete; - auto operator=(const Queue&) = delete; - - Queue(Queue&&) noexcept; - auto operator=(Queue&&) noexcept -> Queue&; - - auto wait_idle() const noexcept -> Expected; - - auto submit(std::span submit_infos, - OptionalRef fence = std::nullopt) const noexcept -> Expected; - - auto submit(const SubmitInfo& submit_info, - OptionalRef fence = std::nullopt) const noexcept -> Expected; - - [[nodiscard]] - auto present(std::span> swapchains, - std::span> wait_semaphores, - std::span image_indices) const noexcept -> Expected; - - [[nodiscard]] - auto entry() const noexcept -> const Device::QueueEntry&; - - [[nodiscard]] - auto native_handle() const noexcept -> VkQueue; - - Queue(const Device& device, const Device::QueueEntry& entry, PrivateFuncTag) noexcept; - - private: - Device::QueueEntry m_entry; - - VkDevice m_vk_device = nullptr; - Ref m_vk_device_table; - VkQueue m_vk_handle = nullptr; - }; - - class CommandPool; - - struct InheritanceInfo { - OptionalRef render_pass = std::nullopt; - u32 subpass = 0; - OptionalRef framebuffer = std::nullopt; - }; - - class STORMKIT_API CommandBuffer { - struct PrivateFuncTag {}; - - public: - enum class State { - INITIAL, - RECORDING, - EXECUTABLE, - }; - - static constexpr auto DEBUG_TYPE = DebugObjectType::COMMAND_BUFFER; - - using Deleter = std::function< - void(VkDevice, VkCommandPool, const VolkDeviceTable&, VkCommandBuffer)>; - ~CommandBuffer() noexcept; - - CommandBuffer(const CommandBuffer&) = delete; - auto operator=(const CommandBuffer&) -> CommandBuffer& = delete; - - CommandBuffer(CommandBuffer&&) noexcept; - auto operator=(CommandBuffer&&) noexcept -> CommandBuffer&; - - auto reset() noexcept -> Expected>; - auto submit(const Queue& queue, - std::span> wait_semaphores = {}, - std::span wait_dst_stages = {}, - std::span> signal_semaphores = {}, - OptionalRef fence = std::nullopt) const noexcept -> Expected; - - [[nodiscard]] - auto state() const noexcept -> State; - [[nodiscard]] - auto level() const noexcept -> CommandBufferLevel; - - auto begin(bool one_time_submit = false, - std::optional inheritance_info = std::nullopt) noexcept - -> Expected>; - auto end() noexcept -> Expected>; - - auto begin_debug_region(std::string_view name, - const RGBColorF& color = RGBColorDef::WHITE) noexcept - -> CommandBuffer&; - auto insert_debug_label(std::string_view name, - const RGBColorF& color = RGBColorDef::WHITE) noexcept - -> CommandBuffer&; - auto end_debug_region() noexcept -> CommandBuffer&; - - auto begin_render_pass(const RenderPass& render_pass, - const FrameBuffer& framebuffer, - std::span clear_values = std::array { ClearValue { - ClearColor { .color = RGBColorDef::SILVER } } }, - bool secondary_commandbuffers = false) noexcept -> CommandBuffer&; - auto next_sub_pass() noexcept -> CommandBuffer&; - auto end_render_pass() noexcept -> CommandBuffer&; - - auto bind_pipeline(const Pipeline& pipeline) noexcept -> CommandBuffer&; - auto set_viewport(u32 first_viewport, std::span viewports) noexcept - -> CommandBuffer&; - auto set_scissor(u32 first_scissor, std::span scissors) noexcept - -> CommandBuffer&; - auto set_line_width(float width) noexcept -> CommandBuffer&; - auto set_depth_bias(float constant_factor, float clamp, float slope_factor) noexcept - -> CommandBuffer&; - auto set_blend_constants(std::span constants) noexcept -> CommandBuffer&; - auto set_depth_bounds(float min, float max) noexcept -> CommandBuffer&; - auto set_stencil_compare_mask(StencilFaceFlag face, u32 mask) noexcept -> CommandBuffer&; - auto set_stencil_write_mask(StencilFaceFlag face, u32 mask) noexcept -> CommandBuffer&; - auto set_stencil_reference(StencilFaceFlag face, u32 reference) noexcept -> CommandBuffer&; - - auto dispatch(u32 group_count_x, u32 group_count_y, u32 group_count_z) noexcept - -> CommandBuffer&; - - auto draw(u32 vertex_count, - u32 instance_count = 1u, - u32 first_vertex = 0, - u32 first_instance = 0) noexcept -> CommandBuffer&; - auto draw_indexed(u32 index_count, - u32 instance_count = 1u, - u32 first_index = 0u, - i32 vertex_offset = 0, - u32 first_instance = 0u) noexcept -> CommandBuffer&; - auto draw_indirect(const Buffer& buffer, usize offset, u32 draw_count, u32 stride) noexcept - -> CommandBuffer&; - auto draw_indexed_indirect(const Buffer& buffer, - usize offset, - u32 draw_count, - u32 stride) noexcept -> CommandBuffer&; - - auto bind_vertex_buffers(std::span> buffers, - std::span offsets) noexcept -> CommandBuffer&; - auto bind_index_buffer(const Buffer& buffer, - u64 offset = 0, - bool large_indices = false) noexcept -> CommandBuffer&; - auto bind_descriptor_sets(const Pipeline& pipeline, - const PipelineLayout& layout, - std::span> descriptor_sets, - std::span dynamic_offsets = {}) noexcept - -> CommandBuffer&; - - auto copy_buffer(const Buffer& src, - const Buffer& dst, - usize size, - u64 src_offset = 0u, - u64 dst_offset = 0u) noexcept -> CommandBuffer&; - auto copy_buffer_to_image(const Buffer& src, - const Image& dst, - std::span - buffer_image_copies = {}) noexcept -> CommandBuffer&; - auto copy_image_to_buffer(const Image& src, - const Buffer& dst, - std::span - buffer_image_copies = {}) noexcept -> CommandBuffer&; - auto copy_image(const Image& src, - const Image& dst, - ImageLayout src_layout, - ImageLayout dst_layout, - const ImageSubresourceLayers& src_subresource_layers, - const ImageSubresourceLayers& dst_subresource_layers, - const math::Extent3& extent) noexcept -> CommandBuffer&; - - auto resolve_image(const Image& src, - const Image& dst, - ImageLayout src_layout, - ImageLayout dst_layout, - const ImageSubresourceLayers& src_subresource_layers = {}, - const ImageSubresourceLayers& dst_subresource_layers = {}) noexcept - -> CommandBuffer&; - - auto blit_image(const Image& src, - const Image& dst, - ImageLayout src_layout, - ImageLayout dst_layout, - std::span regions, - Filter filter) noexcept -> CommandBuffer&; - - auto transition_image_layout(const Image& image, - ImageLayout src_layout, - ImageLayout dst_layout, - const ImageSubresourceRange& subresource_range = {}) noexcept - -> CommandBuffer&; - - auto execute_sub_command_buffers(std::span> - commandbuffers) noexcept -> CommandBuffer&; - - auto pipeline_barrier(PipelineStageFlag src_mask, - PipelineStageFlag dst_mask, - DependencyFlag dependency, - std::span memory_barriers, - std::span buffer_memory_barriers, - std::span image_memory_barriers) noexcept - -> CommandBuffer&; - - auto push_constants(const PipelineLayout& pipeline_layout, - ShaderStageFlag stage, - std::span data, - u32 offset = 0u) noexcept -> CommandBuffer&; - - [[nodiscard]] - auto native_handle() const noexcept -> VkCommandBuffer; - - CommandBuffer(VkDevice, - VkCommandPool, - Ref, - CommandBufferLevel, - VkCommandBuffer&&, - Deleter&&, - PrivateFuncTag) noexcept; - - private: - static auto create(VkDevice, - VkCommandPool, - Ref, - CommandBufferLevel, - VkCommandBuffer&&, - Deleter&&) noexcept -> CommandBuffer; - static auto allocate(VkDevice, - VkCommandPool, - Ref, - CommandBufferLevel, - VkCommandBuffer&&, - Deleter&&) noexcept -> Heap; - friend class CommandPool; - - CommandBufferLevel m_level = CommandBufferLevel::PRIMARY; - - Deleter m_deleter; - - State m_state = State::INITIAL; - - VkDevice m_vk_device = nullptr; - Ref m_vk_device_table; - VkCommandPool m_vk_pool = nullptr; - VkRAIIHandle m_vk_handle; - }; - - class STORMKIT_API CommandPool { - struct PrivateFuncTag {}; - - public: - static auto create(const Device& device) noexcept -> Expected; - static auto allocate(const Device& device) noexcept -> Expected>; - ~CommandPool() noexcept; - - CommandPool(const CommandPool&) = delete; - auto operator=(const CommandPool&) = delete; - - CommandPool(CommandPool&&) noexcept; - auto operator=(CommandPool&&) noexcept -> CommandPool&; - - auto create_command_buffer(CommandBufferLevel level = CommandBufferLevel::PRIMARY) - const noexcept -> Expected; - auto create_command_buffers(usize count, - CommandBufferLevel level = CommandBufferLevel::PRIMARY) - const noexcept -> Expected>; - - auto allocate_command_buffer(CommandBufferLevel level = CommandBufferLevel::PRIMARY) - const noexcept -> Expected>; - auto allocate_command_buffers(usize count, - CommandBufferLevel level = CommandBufferLevel::PRIMARY) - const noexcept -> Expected>>; - - [[nodiscard]] - auto native_handle() const noexcept -> VkCommandPool; - - CommandPool(const Device& device, PrivateFuncTag) noexcept; - - private: - auto do_init() noexcept -> Expected; - auto create_vk_command_buffers(usize count, CommandBufferLevel level) const noexcept - -> VulkanExpected>; - static auto delete_vk_command_buffers(VkDevice device, - VkCommandPool, - const VolkDeviceTable&, - VkCommandBuffer cmb) noexcept -> void; - - VkDevice m_vk_device = nullptr; - Ref m_vk_device_table; - VkRAIIHandle m_vk_handle; - - // std::mutex m_reuse_mutex; - std::vector m_reusable_command_buffers; - }; -} // namespace stormkit::gpu - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::gpu { - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Queue::Queue(const Device& device, - const Device::QueueEntry& entry, - PrivateFuncTag) noexcept - : m_entry { entry }, m_vk_device { device.native_handle() }, - m_vk_device_table { as_ref(device.device_table()) } { - m_vk_handle = vk_call(m_vk_device_table->vkGetDeviceQueue, - m_vk_device, - m_entry.id, - 0); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Queue::~Queue() noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Queue::Queue(Queue&&) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Queue::operator=(Queue&&) noexcept -> Queue& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Queue::create(const Device& device, const Device::QueueEntry& entry) noexcept - -> Queue { - return Queue { device, entry, PrivateFuncTag {} }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Queue::allocate(const Device& device, const Device::QueueEntry& entry) noexcept - -> Heap { - return core::allocate_unsafe(device, entry, PrivateFuncTag {}); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Queue::wait_idle() const noexcept -> Expected { - return vk_call(m_vk_device_table->vkQueueWaitIdle, m_vk_handle) - .transform_error(monadic::from_vk()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - // - STORMKIT_FORCE_INLINE - inline auto Queue::submit(const SubmitInfo& submit_info, - OptionalRef fence) const noexcept -> Expected { - return submit({ &submit_info, 1 }, std::move(fence)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Queue::entry() const noexcept -> const Device::QueueEntry& { - return m_entry; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Queue::native_handle() const noexcept -> VkQueue { - return m_vk_handle; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline CommandBuffer::CommandBuffer(VkDevice device, - VkCommandPool pool, - Ref device_table, - CommandBufferLevel level, - VkCommandBuffer&& command_buffer, - Deleter&& deleter, - PrivateFuncTag) noexcept - : m_level { level }, m_vk_device { device }, m_vk_device_table { device_table }, - m_vk_pool { pool }, - m_vk_handle { { [vk_device = m_vk_device, - vk_pool = m_vk_pool, - vk_device_table = *m_vk_device_table, - deleter = std::move(deleter)](auto handle) noexcept { - deleter(vk_device, vk_pool, vk_device_table, handle); - } } } { - m_vk_handle = std::move(command_buffer); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandBuffer::create(VkDevice device, - VkCommandPool pool, - Ref device_table, - CommandBufferLevel level, - VkCommandBuffer&& cmb, - Deleter&& deleter) noexcept -> CommandBuffer { - return CommandBuffer { - device, pool, device_table, level, std::move(cmb), std::move(deleter), PrivateFuncTag {} - }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandBuffer::allocate(VkDevice device, - VkCommandPool pool, - Ref device_table, - CommandBufferLevel level, - VkCommandBuffer&& cmb, - Deleter&& deleter) noexcept -> Heap { - return *allocate(device, - pool, - device_table, - level, - std::move(cmb), - std::move(deleter), - PrivateFuncTag {}) - .transform_error(core::monadic::assert()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline CommandBuffer::~CommandBuffer() noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline CommandBuffer::CommandBuffer(CommandBuffer&&) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandBuffer::operator=(CommandBuffer&&) noexcept -> CommandBuffer& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandBuffer::reset() noexcept -> Expected> { - return vk_call(m_vk_device_table->vkResetCommandBuffer, m_vk_handle, 0) - .transform([this, &self = *this] { - m_state = State::INITIAL; - return as_ref_mut(self); - }) - .transform_error(monadic::from_vk()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandBuffer::submit(const Queue& queue, - std::span> wait_semaphores, - std::span wait_dst_stages, - std::span> signal_semaphores, - OptionalRef fence) const noexcept - -> Expected { - auto cmbs = as_refs(*this); - - return queue.submit( - std::array { - SubmitInfo { .wait_semaphores = wait_semaphores, - .wait_dst_stages = wait_dst_stages, - .command_buffers = cmbs, - .signal_semaphores = signal_semaphores } - }, - std::move(fence)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandBuffer::state() const noexcept -> State { - return m_state; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandBuffer::level() const noexcept -> CommandBufferLevel { - return m_level; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandBuffer::end() noexcept -> Expected> { - EXPECTS(m_state == State::RECORDING); - - return vk_call(m_vk_device_table->vkEndCommandBuffer, m_vk_handle) - .transform([this, &self = *this] noexcept { - m_state = State::EXECUTABLE; - return as_ref_mut(self); - }) - .transform_error(monadic::from_vk()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandBuffer::begin_debug_region(std::string_view name, - const RGBColorF& color) noexcept - -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); - - if (not vkCmdBeginDebugUtilsLabelEXT) [[unlikely]] - return *this; - - const auto info = VkDebugUtilsLabelEXT { - .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT, - .pNext = nullptr, - .pLabelName = stdr::data(name), - .color = { color.red, color.green, color.blue, color.alpha } - }; - - vk_call(vkCmdBeginDebugUtilsLabelEXT, m_vk_handle, &info); - return *this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandBuffer::insert_debug_label(std::string_view name, - const RGBColorF& color) noexcept - -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); - - if (not vkCmdInsertDebugUtilsLabelEXT) [[unlikely]] - return *this; - - const auto info = VkDebugUtilsLabelEXT { - .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT, - .pNext = nullptr, - .pLabelName = stdr::data(name), - .color = { color.red, color.green, color.blue, color.alpha } - }; - - vk_call(vkCmdInsertDebugUtilsLabelEXT, m_vk_handle, &info); - return *this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandBuffer::end_debug_region() noexcept -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); - - if (not vkCmdEndDebugUtilsLabelEXT) [[unlikely]] - return *this; - - vk_call(vkCmdEndDebugUtilsLabelEXT, m_vk_handle); - return *this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandBuffer::next_sub_pass() noexcept -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); - - vk_call(m_vk_device_table->vkCmdNextSubpass, m_vk_handle, VK_SUBPASS_CONTENTS_INLINE); - return *this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandBuffer::end_render_pass() noexcept -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); - - vk_call(m_vk_device_table->vkCmdEndRenderPass, m_vk_handle); - return *this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandBuffer::bind_pipeline(const Pipeline& pipeline) noexcept -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); - - const auto bind_point = (pipeline.type() == Pipeline::Type::RASTER) - ? VK_PIPELINE_BIND_POINT_GRAPHICS - : VK_PIPELINE_BIND_POINT_COMPUTE; - - vk_call(m_vk_device_table->vkCmdBindPipeline, m_vk_handle, bind_point, to_vk(pipeline)); - return *this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandBuffer::set_line_width(float width) noexcept -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); - - vk_call(m_vk_device_table->vkCmdSetLineWidth, m_vk_handle, width); - return *this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandBuffer::set_depth_bias(float constant_factor, - float clamp, - float slope_factor) noexcept -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); - - vk_call(m_vk_device_table->vkCmdSetDepthBias, - m_vk_handle, - constant_factor, - clamp, - slope_factor); - return *this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandBuffer::set_blend_constants(std::span constants) noexcept - -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); - - f32 data[] = { constants[0], constants[1], constants[2], constants[3] }; - - vk_call(m_vk_device_table->vkCmdSetBlendConstants, m_vk_handle, data); - return *this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandBuffer::set_depth_bounds(float min, float max) noexcept -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); - - vk_call(m_vk_device_table->vkCmdSetDepthBounds, m_vk_handle, min, max); - return *this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandBuffer::set_stencil_compare_mask(StencilFaceFlag face, u32 mask) noexcept - -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); - - vk_call(m_vk_device_table->vkCmdSetStencilCompareMask, - m_vk_handle, - to_vk(face), - mask); - return *this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandBuffer::set_stencil_write_mask(StencilFaceFlag face, u32 mask) noexcept - -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); - - vk_call(m_vk_device_table->vkCmdSetStencilWriteMask, - m_vk_handle, - to_vk(face), - mask); - return *this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandBuffer::set_stencil_reference(StencilFaceFlag face, u32 reference) noexcept - -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); - - vk_call(m_vk_device_table->vkCmdSetStencilReference, - m_vk_handle, - to_vk(face), - reference); - return *this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandBuffer::dispatch(u32 group_count_x, - u32 group_count_y, - u32 group_count_z) noexcept -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); - - vk_call(m_vk_device_table->vkCmdDispatch, - m_vk_handle, - group_count_x, - group_count_y, - group_count_z); - return *this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandBuffer::draw(u32 vertex_count, - u32 instance_count, - u32 first_vertex, - u32 first_instance) noexcept -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); - EXPECTS(vertex_count > 0); - - vk_call(m_vk_device_table->vkCmdDraw, - m_vk_handle, - vertex_count, - instance_count, - first_vertex, - first_instance); - return *this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandBuffer::draw_indexed(u32 index_count, - u32 instance_count, - u32 first_index, - i32 vertex_offset, - u32 first_instance) noexcept -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); - EXPECTS(index_count > 0); - - vk_call(m_vk_device_table->vkCmdDrawIndexed, - m_vk_handle, - index_count, - instance_count, - first_index, - vertex_offset, - first_instance); - return *this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandBuffer::draw_indirect(const Buffer& buffer, - usize offset, - u32 draw_count, - u32 stride) noexcept -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); - EXPECTS(draw_count > 0); - - vk_call(m_vk_device_table->vkCmdDrawIndirect, - m_vk_handle, - to_vk(buffer), - offset, - draw_count, - stride); - return *this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandBuffer::draw_indexed_indirect(const Buffer& buffer, - usize offset, - u32 draw_count, - u32 stride) noexcept -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); - EXPECTS(draw_count > 0); - - vk_call(m_vk_device_table->vkCmdDrawIndexedIndirect, - m_vk_handle, - to_vk(buffer), - offset, - draw_count, - stride); - return *this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandBuffer::bind_index_buffer(const Buffer& buffer, - u64 offset, - bool large_indices) noexcept -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); - - vk_call(m_vk_device_table->vkCmdBindIndexBuffer, - m_vk_handle, - to_vk(buffer), - offset, - (large_indices) ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32); - return *this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandBuffer::native_handle() const noexcept -> VkCommandBuffer { - return m_vk_handle; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline CommandPool::CommandPool(const Device& device, PrivateFuncTag) noexcept - : m_vk_device { device.native_handle() }, - m_vk_device_table { as_ref(device.device_table()) }, - m_vk_handle { { [vk_device_table = *m_vk_device_table, - vk_device = m_vk_device](auto handle) noexcept { - vk_device_table.vkDestroyCommandPool(vk_device, handle, nullptr); - } } } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandPool::create(const Device& device) noexcept -> Expected { - auto pool = CommandPool { device, PrivateFuncTag {} }; - return pool.do_init().transform(core::monadic::consume(pool)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandPool::allocate(const Device& device) noexcept - -> Expected> { - auto pool = *core::allocate(device, PrivateFuncTag {}) - .transform_error(core::monadic::assert()); - return pool->do_init().transform(core::monadic::consume(pool)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline CommandPool::~CommandPool() noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline CommandPool::CommandPool(CommandPool&&) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandPool::operator=(CommandPool&&) noexcept -> CommandPool& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandPool::create_command_buffer(CommandBufferLevel level) const noexcept - -> Expected { - return create_command_buffers(1, level) - .transform([](auto&& cmbs) static noexcept { return std::move(cmbs.front()); }); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandPool::allocate_command_buffer(CommandBufferLevel level) const noexcept - -> Expected> { - return allocate_command_buffers(1, level) - .transform([](auto&& cmbs) static noexcept { return std::move(cmbs.front()); }); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto CommandPool::native_handle() const noexcept -> VkCommandPool { - return m_vk_handle; - } -} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/execution/descriptors.cppm b/modules/stormkit/gpu/execution/descriptors.cppm new file mode 100644 index 000000000..5721d85ae --- /dev/null +++ b/modules/stormkit/gpu/execution/descriptors.cppm @@ -0,0 +1,455 @@ +// Copyright (C) 2023 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include +#include + +#include +#include + +export module stormkit.gpu.execution:descriptors; + +import std; + +import stormkit.core; +import stormkit.gpu.core; +import stormkit.gpu.resource; + +import :objects; + +namespace stdr = std::ranges; +namespace stdv = std::views; + +namespace cmonadic = stormkit::core::monadic; +namespace cmeta = stormkit::core::meta; + +namespace stormkit::gpu { + export { + struct BufferDescriptor { + DescriptorType type = DescriptorType::UNIFORM_BUFFER; + u32 binding; + view::Buffer buffer; + std::optional range = std::nullopt; + u32 offset = 0; + }; + + struct ImageDescriptor { + DescriptorType type = DescriptorType::COMBINED_IMAGE_SAMPLER; + u32 binding; + ImageLayout layout; + view::ImageView image_view; + view::Sampler sampler; + }; + + using Descriptor = std::variant; + + struct DescriptorSetLayoutBinding { + u32 binding; + DescriptorType type; + ShaderStageFlag stages; + usize descriptor_count; + }; + + template + class DescriptorSetInterface final: public DeviceObject { + public: + using DeviceObject::DeviceObject; + using DeviceObject::operator=; + using TagType = DescriptorSetTag; + + auto update(array_view descriptors) const noexcept -> void; + }; + } + + using DescriptorSetDeleter = std::function; + + struct DescriptorSetLayoutInterfaceBase { + struct Size { + DescriptorType type; + u32 descriptor_count; + }; + }; + + export { + template + class DescriptorSetLayoutInterface final: public DeviceObject, public DescriptorSetLayoutInterfaceBase { + public: + using DeviceObject::DeviceObject; + using DeviceObject::operator=; + using TagType = DescriptorSetLayoutTag; + + using DescriptorSetLayoutInterfaceBase::Size; + + [[nodiscard]] + auto bindings() const noexcept -> array_view; + }; + + template + class DescriptorPoolInterface final: public DeviceObject { + public: + using DeviceObject::DeviceObject; + using DeviceObject::operator=; + using TagType = DescriptorPoolTag; + + auto create_descriptor_set(this const auto&, view::DescriptorSetLayout layout) noexcept -> Expected; + auto create_descriptor_sets(this const auto&, usize count, view::DescriptorSetLayout layout) noexcept + -> Expected>; + + auto allocate_descriptor_set(this const auto&, view::DescriptorSetLayout layout) noexcept + -> Expected>; + auto allocate_descriptor_sets(this const auto&, usize count, view::DescriptorSetLayout layout) noexcept + -> Expected>>; + + private: + auto create_vk_descriptor_sets(usize, view::DescriptorSetLayout&&) const noexcept + -> Expected>; + + static auto delete_vk_descriptor_set(view::Device, view::DescriptorPool, VkDescriptorSet) noexcept -> void; + }; + } + + class STORMKIT_GPU_API + DescriptorSetImplementation: public GpuObjectImplementation { + public: + DescriptorSetImplementation(PrivateTag, view::Device&&) noexcept; + ~DescriptorSetImplementation() noexcept; + + DescriptorSetImplementation(const DescriptorSetImplementation&) = delete; + auto operator=(const DescriptorSetImplementation&) -> DescriptorSetImplementation& = delete; + + DescriptorSetImplementation(DescriptorSetImplementation&&) noexcept; + auto operator=(DescriptorSetImplementation&&) noexcept -> DescriptorSetImplementation&; + + auto do_init(PrivateTag, VkDescriptorSet&&, DescriptorSetDeleter&&) noexcept -> Expected; + + protected: + using NamedConstructor::allocate; + using NamedConstructor::create; + + DescriptorSetDeleter m_deleter; + + friend class DescriptorPoolInterface; + friend class DescriptorPoolInterface; + }; + + namespace view { + class DescriptorSetImplementation: public GpuObjectViewImplementation { + public: + using GpuObjectViewImplementation::GpuObjectViewImplementation; + using GpuObjectViewImplementation::operator=; + }; + } // namespace view + + class STORMKIT_GPU_API DescriptorSetLayoutImplementation + : public GpuObjectImplementation> { + public: + DescriptorSetLayoutImplementation(PrivateTag, view::Device&&) noexcept; + ~DescriptorSetLayoutImplementation() noexcept; + + DescriptorSetLayoutImplementation(const DescriptorSetLayoutImplementation&) = delete; + auto operator=(const DescriptorSetLayoutImplementation&) -> DescriptorSetLayoutImplementation& = delete; + + DescriptorSetLayoutImplementation(DescriptorSetLayoutImplementation&&) noexcept; + auto operator=(DescriptorSetLayoutImplementation&&) noexcept -> DescriptorSetLayoutImplementation&; + + auto do_init(PrivateTag, dyn_array&&) noexcept -> Expected; + + protected: + dyn_array m_bindings; + }; + + namespace view { + class DescriptorSetLayoutImplementation: public GpuObjectViewImplementation { + public: + DescriptorSetLayoutImplementation(const gpu::DescriptorSetLayout& of) noexcept; + template TContainerOrPointer> + DescriptorSetLayoutImplementation(const TContainerOrPointer&) noexcept; + ~DescriptorSetLayoutImplementation() noexcept; + + DescriptorSetLayoutImplementation(const DescriptorSetLayoutImplementation&) noexcept; + auto operator=(const DescriptorSetLayoutImplementation&) noexcept -> DescriptorSetLayoutImplementation&; + + DescriptorSetLayoutImplementation(DescriptorSetLayoutImplementation&&) noexcept; + auto operator=(DescriptorSetLayoutImplementation&&) noexcept -> DescriptorSetLayoutImplementation&; + + protected: + array_view m_bindings; + }; + } // namespace view + + class STORMKIT_GPU_API DescriptorPoolImplementation + : public GpuObjectImplementation, u32> { + public: + using Size = DescriptorSetLayoutInterfaceBase::Size; + + DescriptorPoolImplementation(PrivateTag, view::Device&&) noexcept; + ~DescriptorPoolImplementation() noexcept; + + DescriptorPoolImplementation(const DescriptorPoolImplementation&) = delete; + auto operator=(const DescriptorPoolImplementation&) -> DescriptorPoolImplementation& = delete; + + DescriptorPoolImplementation(DescriptorPoolImplementation&&) noexcept; + auto operator=(DescriptorPoolImplementation&&) noexcept -> DescriptorPoolImplementation&; + + auto do_init(PrivateTag, array_view&&, u32) noexcept -> Expected; + }; + + namespace view { + class DescriptorPoolImplementation: public GpuObjectViewImplementation { + public: + using GpuObjectViewImplementation::GpuObjectViewImplementation; + using GpuObjectViewImplementation::operator=; + }; + } // namespace view + + template + constexpr auto hasher(view::DescriptorSetLayout value) noexcept -> Ret; + template + constexpr auto hasher(const DescriptorSetLayoutBinding& value) noexcept -> Ret; + template + constexpr auto hasher(const BufferDescriptor& value) noexcept -> Ret; + template + constexpr auto hasher(const ImageDescriptor& value) noexcept -> Ret; + template + constexpr auto hasher(const Descriptor& value) noexcept -> Ret; +} // namespace stormkit::gpu + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit::gpu { + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto DescriptorSetLayoutInterface::bindings() const noexcept -> array_view { + return Base::m_bindings; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto DescriptorPoolInterface::create_descriptor_set(this const auto& self, + view::DescriptorSetLayout layout) noexcept + -> Expected { + auto device = self.owner(); + auto vk_handle = Try(self.create_vk_descriptor_sets(1, std::move(layout))).front(); + Return DescriptorSet::create(device, + std::move(vk_handle), + bind_front(self.delete_vk_descriptor_set, std::move(device), gpu::as_view(self))); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto DescriptorPoolInterface::create_descriptor_sets(this const auto& self, + usize count, + view::DescriptorSetLayout layout) noexcept + -> Expected> { + auto device = self.owner(); + Return transform(Try(self.create_vk_descriptor_sets(count, std::move(layout))), [&self, device](auto vk_handle) noexcept { + return DescriptorSet::create(device, + std::move(vk_handle), + bind_front(self.delete_vk_descriptor_set, std::move(device), gpu::as_view(self))); + }); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto DescriptorPoolInterface::allocate_descriptor_set(this const auto& self, + view::DescriptorSetLayout layout) noexcept + -> Expected> { + auto device = self.owner(); + auto vk_handle = Try(self.create_vk_descriptor_sets(1, std::move(layout))).front(); + Return DescriptorSet::allocate(device, + std::move(vk_handle), + bind_front(self.delete_vk_descriptor_set, std::move(device), gpu::as_view(self))); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto DescriptorPoolInterface::allocate_descriptor_sets(this const auto& self, + usize count, + view::DescriptorSetLayout layout) noexcept + -> Expected>> { + auto device = self.owner(); + Return transform(Try(self.create_vk_descriptor_sets(count, std::move(layout))), [&self, device](auto vk_handle) noexcept { + return DescriptorSet::allocate(device, + std::move(vk_handle), + bind_front(self.delete_vk_descriptor_set, std::move(device), gpu::as_view(self))); + }); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline DescriptorSetLayoutImplementation::DescriptorSetLayoutImplementation(PrivateTag, view::Device&& device) noexcept + : GpuObjectImplementation { std::move(device), &VolkDeviceTable::vkDestroyDescriptorSetLayout } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline DescriptorSetLayoutImplementation::~DescriptorSetLayoutImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline DescriptorSetLayoutImplementation::DescriptorSetLayoutImplementation(DescriptorSetLayoutImplementation&& + other) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto DescriptorSetLayoutImplementation::operator=(DescriptorSetLayoutImplementation&& other) noexcept + -> DescriptorSetLayoutImplementation& = default; + + namespace view { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline DescriptorSetLayoutImplementation ::DescriptorSetLayoutImplementation(const gpu::DescriptorSetLayout& of) noexcept + : GpuObjectViewImplementation { of }, m_bindings { of.bindings() } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template TContainerOrPointer> + STORMKIT_FORCE_INLINE + inline DescriptorSetLayoutImplementation::DescriptorSetLayoutImplementation(const TContainerOrPointer& of) noexcept + : DescriptorSetLayoutImplementation { *of } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline DescriptorSetLayoutImplementation ::~DescriptorSetLayoutImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline DescriptorSetLayoutImplementation :: + DescriptorSetLayoutImplementation(const DescriptorSetLayoutImplementation&) noexcept = default; + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto DescriptorSetLayoutImplementation ::operator=(const DescriptorSetLayoutImplementation&) noexcept + -> DescriptorSetLayoutImplementation& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline DescriptorSetLayoutImplementation :: + DescriptorSetLayoutImplementation(DescriptorSetLayoutImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto DescriptorSetLayoutImplementation ::operator=(DescriptorSetLayoutImplementation&&) noexcept + -> DescriptorSetLayoutImplementation& = default; + } // namespace view + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline DescriptorSetImplementation::DescriptorSetImplementation(PrivateTag, view::Device&& device) noexcept + : GpuObjectImplementation { std::move(device), cmonadic::noop() } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline DescriptorSetImplementation::~DescriptorSetImplementation() noexcept { + if (m_vk_handle != VK_NULL_HANDLE) { + m_deleter(m_vk_handle); + m_vk_handle = VK_NULL_HANDLE; + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline DescriptorSetImplementation::DescriptorSetImplementation(DescriptorSetImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto DescriptorSetImplementation::operator=(DescriptorSetImplementation&&) noexcept + -> DescriptorSetImplementation& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline DescriptorPoolImplementation::DescriptorPoolImplementation(PrivateTag, view::Device&& device) noexcept + : GpuObjectImplementation { std::move(device), &VolkDeviceTable::vkDestroyDescriptorPool } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline DescriptorPoolImplementation::~DescriptorPoolImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline DescriptorPoolImplementation::DescriptorPoolImplementation(DescriptorPoolImplementation&& other) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto DescriptorPoolImplementation::operator=(DescriptorPoolImplementation&& other) noexcept + -> DescriptorPoolImplementation& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto hasher(view::DescriptorSetLayout value) noexcept -> Ret { + auto out = Ret {}; + for (const auto binding : value.bindings()) out = hash_combine(out, binding); + return out; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto hasher(const DescriptorSetLayoutBinding& value) noexcept -> Ret { + return hash(value.binding, value.type, value.stages, value.descriptor_count); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto hasher(const BufferDescriptor& value) noexcept -> Ret { + return hash(value.type, value.binding, value.buffer, value.range, value.offset); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto hasher(const ImageDescriptor& value) noexcept -> Ret { + return hash(value.type, value.binding, value.layout, value.image_view, value.sampler); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto hasher(const Descriptor& value) noexcept -> Ret { + return std::visit([](const auto& descriptor) static noexcept { return hash(descriptor); }, value); + } +} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/execution/descriptors.mpp b/modules/stormkit/gpu/execution/descriptors.mpp deleted file mode 100644 index 1061f3091..000000000 --- a/modules/stormkit/gpu/execution/descriptors.mpp +++ /dev/null @@ -1,648 +0,0 @@ -// Copyright (C) 2023 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include -#include -#include - -#include - -export module stormkit.gpu.execution:descriptors; - -import std; - -import stormkit.core; -import stormkit.gpu.core; -import stormkit.gpu.resource; - -namespace stdr = std::ranges; -namespace stdv = std::views; - -export { - namespace stormkit::gpu { - struct BufferDescriptor { - DescriptorType type = DescriptorType::UNIFORM_BUFFER; - u32 binding; - Ref buffer; - u32 range; - u32 offset = 0; - }; - - struct ImageDescriptor { - DescriptorType type = DescriptorType::COMBINED_IMAGE_SAMPLER; - u32 binding; - ImageLayout layout; - Ref image_view; - Ref sampler; - }; - - using Descriptor = std::variant; - class DescriptorPool; - - class STORMKIT_API DescriptorSet { - struct PrivateFuncTag {}; - - using Deleter = std::function; - - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::DESCRIPTOR_SET; - - ~DescriptorSet() noexcept; - - DescriptorSet(const DescriptorSet&) = delete; - auto operator=(const DescriptorSet&) -> DescriptorSet& = delete; - - DescriptorSet(DescriptorSet&&) noexcept; - auto operator=(DescriptorSet&&) noexcept -> DescriptorSet&; - - auto update(std::span descriptors) -> void; - - [[nodiscard]] - auto types() const noexcept -> const std::vector&; - - [[nodiscard]] - auto native_handle() const noexcept -> VkDescriptorSet; - - DescriptorSet(VkDevice, - const VolkDeviceTable&, - VkDescriptorSet&&, - Deleter&&, - PrivateFuncTag) noexcept; - - private: - VkDevice m_vk_device = nullptr; - Ref m_vk_device_table; - - VkDescriptorSet m_vk_handle; - - Deleter m_deleter; - friend class DescriptorPool; - }; - - struct DescriptorSetLayoutBinding { - u32 binding; - DescriptorType type; - ShaderStageFlag stages; - usize descriptor_count; - }; - - class STORMKIT_API DescriptorSetLayout { - struct PrivateFuncTag {}; - - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::DESCRIPTOR_SET_LAYOUT; - - static auto create(const Device& device, - std::vector bindings) noexcept - -> Expected; - static auto allocate(const Device& device, - std::vector bindings) noexcept - -> Expected>; - ~DescriptorSetLayout() noexcept; - - DescriptorSetLayout(const DescriptorSetLayout&) = delete; - auto operator=(const DescriptorSetLayout&) -> DescriptorSetLayout& = delete; - - DescriptorSetLayout(DescriptorSetLayout&&) noexcept; - auto operator=(DescriptorSetLayout&&) noexcept -> DescriptorSetLayout&; - - [[nodiscard]] - auto hash() const noexcept -> hash64; - [[nodiscard]] - auto bindings() const noexcept -> const std::vector&; - - [[nodiscard]] - auto native_handle() const noexcept -> VkDescriptorSetLayout; - - [[nodiscard]] - auto operator==(const DescriptorSetLayout& second) const noexcept -> bool; - - DescriptorSetLayout(const Device&, - std::vector&&, - PrivateFuncTag) noexcept; - - private: - auto do_init() noexcept -> Expected; - - std::vector m_bindings; - - hash64 m_hash = 0; - VkDevice m_vk_device = nullptr; - Ref m_vk_device_table; - VkRAIIHandle m_vk_handle; - }; - - class STORMKIT_API DescriptorPool { - struct PrivateFuncTag {}; - - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::DESCRIPTOR_POOL; - - struct Size { - DescriptorType type; - u32 descriptor_count; - }; - - static auto create(const Device& device, - std::span sizes, - u32 max_sets) noexcept -> Expected; - static auto allocate(const Device& device, - std::span sizes, - u32 max_sets) noexcept -> Expected>; - ~DescriptorPool() noexcept; - - DescriptorPool(const DescriptorPool&) = delete; - auto operator=(const DescriptorPool&) -> DescriptorPool& = delete; - - DescriptorPool(DescriptorPool&&) noexcept; - auto operator=(DescriptorPool&&) noexcept -> DescriptorPool&; - - auto create_descriptor_set(const DescriptorSetLayout& layout) const noexcept - -> Expected; - auto create_descriptor_sets(usize count, - const DescriptorSetLayout& layout) const noexcept - -> Expected>; - - auto allocate_descriptor_set(const DescriptorSetLayout& layout) const noexcept - -> Expected>; - auto allocate_descriptor_sets(usize count, - const DescriptorSetLayout& layout) const noexcept - -> Expected>>; - - [[nodiscard]] - auto native_handle() const noexcept -> VkDescriptorPool; - - DescriptorPool(const Device&, PrivateFuncTag) noexcept; - - private: - auto do_init(std::span, u32) noexcept -> Expected; - - auto create_vk_descriptor_sets(usize, const DescriptorSetLayout&) const - -> VulkanExpected>; - static auto delete_vk_descriptor_set(VkDescriptorSet) -> void; - - VkDevice m_vk_device = nullptr; - Ref m_vk_device_table; - VkRAIIHandle m_vk_handle; - }; - } // namespace stormkit::gpu - - template<> - struct STORMKIT_API std::hash { - [[nodiscard]] - auto operator()(const stormkit::gpu::DescriptorSetLayout& value) const noexcept - -> stormkit::hash64 { - return value.hash(); - } - }; - - HASH_FUNC(stormkit::gpu::DescriptorSetLayoutBinding, - value.binding, - value.type, - value.stages, - value.descriptor_count) - HASH_FUNC(stormkit::gpu::BufferDescriptor, - value.type, - value.binding, - value.buffer.get(), - value.range, - value.offset) - HASH_FUNC(stormkit::gpu::ImageDescriptor, - value.type, - value.binding, - value.layout, - value.image_view.get(), - value.sampler.get()) - - template<> - struct STORMKIT_API std::hash { - [[nodiscard]] - auto operator()(const stormkit::gpu::Descriptor& value) const noexcept -> stormkit::hash64 { - auto hash = stormkit::hash64 { 0 }; - - std::visit([&hash](auto& descriptor) { stormkit::hash_combine(hash, descriptor); }, - value); - - return hash; - } - }; -} - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::gpu { - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline DescriptorSet::DescriptorSet(VkDevice device, - const VolkDeviceTable& device_table, - VkDescriptorSet&& set, - Deleter&& deleter, - PrivateFuncTag) noexcept - : m_vk_device { device }, m_vk_device_table { as_ref(device_table) }, - m_vk_handle { std::move(set) }, m_deleter { std::move(deleter) } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline DescriptorSet::~DescriptorSet() noexcept { - if (m_vk_handle) m_deleter(m_vk_handle); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline DescriptorSet::DescriptorSet(DescriptorSet&&) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto DescriptorSet::operator=(DescriptorSet&&) noexcept -> DescriptorSet& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto DescriptorSet::update(std::span descriptors) -> void { - auto&& [_, _, _writes] = [this, &descriptors] noexcept -> decltype(auto) { - auto buffers = std::vector {}; - auto images = std::vector {}; - auto writes = std::vector {}; - buffers.reserve(std::size(descriptors)); - images.reserve(std::size(descriptors)); - writes.reserve(std::size(descriptors)); - - auto dst = 0u; - std::ranges:: - for_each(descriptors, - core::monadic::either( - [vk_handle = m_vk_handle, - &buffers, - &writes, - &dst](const BufferDescriptor& descriptor) mutable noexcept - -> decltype(auto) { - buffers.push_back(VkDescriptorBufferInfo { - .buffer = to_vk(descriptor.buffer), - .offset = descriptor.offset, - .range = descriptor.range, - }); - const auto& buffer_descriptor = buffers.back(); - - writes.push_back(VkWriteDescriptorSet { - .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .pNext = nullptr, - .dstSet = vk_handle, - .dstBinding = dst++, - .dstArrayElement = 0, - .descriptorCount = 1, - .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - .pImageInfo = nullptr, - .pBufferInfo = &buffer_descriptor, - .pTexelBufferView = nullptr, - }); - }, - [vk_handle = m_vk_handle, - &images, - &writes, - &dst](const ImageDescriptor& descriptor) mutable noexcept - -> decltype(auto) { - images.push_back(VkDescriptorImageInfo { - .sampler = to_vk(descriptor.sampler), - .imageView = to_vk(descriptor.image_view), - .imageLayout = narrow(descriptor.layout), - }); - const auto& image_descriptor = images.back(); - - writes.push_back(VkWriteDescriptorSet { - .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - .pNext = nullptr, - .dstSet = vk_handle, - .dstBinding = dst++, - .dstArrayElement = 0, - .descriptorCount = 1, - .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - .pImageInfo = &image_descriptor, - .pBufferInfo = nullptr, - .pTexelBufferView = nullptr, - }); - })); - - return std::tuple { std::move(buffers), std::move(images), std::move(writes) }; - }(); - - vk_call(m_vk_device_table->vkUpdateDescriptorSets, - m_vk_device, - stdr::size(_writes), - stdr::data(_writes), - 0, - nullptr); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto DescriptorSet::native_handle() const noexcept -> VkDescriptorSet { - return m_vk_handle; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline DescriptorSetLayout::DescriptorSetLayout(const Device& device, - std::vector&& - bindings, - PrivateFuncTag) noexcept - : m_bindings { std::move(bindings) }, m_vk_device { device.native_handle() }, - m_vk_device_table { as_ref(device.device_table()) }, - m_vk_handle { { [vk_device_table = m_vk_device_table, - vk_device = m_vk_device](VkDescriptorSetLayout handle) noexcept { - if (handle) vk_device_table->vkDestroyDescriptorSetLayout(vk_device, handle, nullptr); - } } } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto DescriptorSetLayout::create(const Device& device, - std::vector - bindings) noexcept -> Expected { - auto layout = DescriptorSetLayout { device, std::move(bindings), PrivateFuncTag {} }; - return layout.do_init().transform(core::monadic::consume(layout)); - } - - ////////////////////////////////////p/ - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto DescriptorSetLayout::allocate(const Device& device, - std::vector - bindings) noexcept - -> Expected> { - auto layout = allocate_unsafe(device, - std::move(bindings), - PrivateFuncTag {}); - return layout->do_init().transform(core::monadic::consume(layout)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline DescriptorSetLayout::~DescriptorSetLayout() noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline DescriptorSetLayout::DescriptorSetLayout(DescriptorSetLayout&& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto DescriptorSetLayout::operator=(DescriptorSetLayout&& other) noexcept - -> DescriptorSetLayout& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto DescriptorSetLayout::hash() const noexcept -> hash64 { - return m_hash; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto DescriptorSetLayout::bindings() const noexcept - -> const std::vector& { - return m_bindings; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto DescriptorSetLayout::native_handle() const noexcept -> VkDescriptorSetLayout { - return m_vk_handle; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto DescriptorSetLayout::operator==(const DescriptorSetLayout& second) const noexcept - -> bool { - return m_hash == second.hash(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto DescriptorSetLayout::do_init() noexcept -> Expected { - const auto vk_bindings = m_bindings - | std::views::transform([](const DescriptorSetLayoutBinding& - binding) static noexcept { - return VkDescriptorSetLayoutBinding { - .binding = binding.binding, - .descriptorType = to_vk(binding.type), - .descriptorCount = as(binding.descriptor_count), - .stageFlags = to_vk(binding.stages), - .pImmutableSamplers = nullptr, - }; - }) - | std::ranges::to(); - - const auto create_info = VkDescriptorSetLayoutCreateInfo { - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .bindingCount = as(std::ranges::size(vk_bindings)), - .pBindings = std::ranges::data(vk_bindings) - }; - - return vk_call(m_vk_device_table->vkCreateDescriptorSetLayout, - m_vk_device, - &create_info, - nullptr) - .transform(core::monadic::set(m_vk_handle)) - .transform_error(monadic::from_vk()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline DescriptorPool::DescriptorPool(const Device& device, PrivateFuncTag) noexcept - : m_vk_device { device.native_handle() }, - m_vk_device_table { as_ref(device.device_table()) }, - m_vk_handle { { [vk_device = m_vk_device, - vk_device_table = m_vk_device_table](VkDescriptorPool handle) noexcept { - vk_device_table->vkDestroyDescriptorPool(vk_device, handle, nullptr); - } } } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto DescriptorPool::create(const Device& device, - std::span extents, - u32 max_sets) noexcept -> Expected { - auto pool = DescriptorPool { device, PrivateFuncTag {} }; - return pool.do_init(extents, max_sets).transform(core::monadic::consume(pool)); - } - - ////////////////////////////////////p/ - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto DescriptorPool::allocate(const Device& device, - std::span extents, - u32 max_sets) noexcept -> Expected> { - auto pool = allocate_unsafe(device, PrivateFuncTag {}); - return pool->do_init(extents, max_sets).transform(core::monadic::consume(pool)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline DescriptorPool::~DescriptorPool() noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline DescriptorPool::DescriptorPool(DescriptorPool&& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto DescriptorPool::operator=(DescriptorPool&& other) noexcept - -> DescriptorPool& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - auto DescriptorPool::create_descriptor_set(const DescriptorSetLayout& layout) const noexcept - -> Expected { - return create_descriptor_sets(1, layout) - .transform([](std::vector&& sets) static noexcept { - return std::move(sets.front()); - }); - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto DescriptorPool::create_descriptor_sets(usize count, - const DescriptorSetLayout& layout) - const noexcept -> Expected> { - auto tag = DescriptorSet::PrivateFuncTag {}; - return create_vk_descriptor_sets(count, layout) - .transform([this, &tag](std::vector&& sets) noexcept { - return std::move(sets) - | stdv::as_rvalue - | stdv::transform([this, - &tag](VkDescriptorSet&& set) noexcept -> decltype(auto) { - return DescriptorSet { m_vk_device, - *m_vk_device_table, - std::move(set), - DescriptorPool::delete_vk_descriptor_set, - tag }; - }) - | stdr::to(); - }) - .transform_error(monadic::from_vk()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - auto DescriptorPool::allocate_descriptor_set(const DescriptorSetLayout& layout) const noexcept - -> Expected> { - return allocate_descriptor_sets(1, layout) - .transform([](std::vector>&& sets) static noexcept { - return std::move(sets.front()); - }); - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto DescriptorPool::allocate_descriptor_sets(usize count, - const DescriptorSetLayout& layout) - const noexcept -> Expected>> { - auto tag = DescriptorSet::PrivateFuncTag {}; - return create_vk_descriptor_sets(count, layout) - .transform([this, &tag](std::vector&& sets) noexcept { - return std::move(sets) - | stdv::as_rvalue - | stdv::transform([this, - &tag](VkDescriptorSet&& set) noexcept -> decltype(auto) { - return core::allocate_unsafe< - DescriptorSet>(m_vk_device, - *m_vk_device_table, - std::move(set), - DescriptorPool::delete_vk_descriptor_set, - tag); - }) - | stdr::to(); - }) - .transform_error(monadic::from_vk()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto DescriptorPool::native_handle() const noexcept -> VkDescriptorPool { - return m_vk_handle; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto DescriptorPool::do_init(std::span sizes, u32 max_sets) noexcept - -> Expected { - const auto pool_sizes = sizes - | std::views::transform([](const Size& size) static noexcept { - return VkDescriptorPoolSize { - .type = to_vk(size.type), - .descriptorCount = size.descriptor_count, - }; - }) - | std::ranges::to(); - - const auto create_info = VkDescriptorPoolCreateInfo { - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, - .pNext = nullptr, - .flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, - .maxSets = max_sets, - .poolSizeCount = as(std::ranges::size(sizes)), - .pPoolSizes = std::ranges::data(pool_sizes), - }; - - return vk_call(m_vk_device_table->vkCreateDescriptorPool, - m_vk_device, - &create_info, - nullptr) - .transform(core::monadic::set(m_vk_handle)) - .transform_error(monadic::from_vk()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto DescriptorPool::create_vk_descriptor_sets(usize count, - const DescriptorSetLayout& layout) const - -> VulkanExpected> { - const auto vk_layout = to_vk(layout); - const auto allocate_info = VkDescriptorSetAllocateInfo { - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, - .pNext = nullptr, - .descriptorPool = m_vk_handle, - .descriptorSetCount = as(count), - .pSetLayouts = &vk_layout, - }; - - return vk_allocate(count, - m_vk_device_table->vkAllocateDescriptorSets, - m_vk_device, - &allocate_info); - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto DescriptorPool::delete_vk_descriptor_set(VkDescriptorSet) -> void { - } -} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/execution/objects.cppm b/modules/stormkit/gpu/execution/objects.cppm new file mode 100644 index 000000000..75ab3e3ea --- /dev/null +++ b/modules/stormkit/gpu/execution/objects.cppm @@ -0,0 +1,267 @@ +// Copyright (C) 2023 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +export module stormkit.gpu.execution:objects; + +import std; + +import stormkit.core; +import stormkit.gpu.core; + +namespace cmonadic = stormkit::core::monadic; + +namespace stormkit::gpu { + class SwapChainImplementation; + class FrameBufferImplementation; + class RenderPassImplementation; + class PipelineCacheImplementation; + class PipelineLayoutImplementation; + class PipelineImplementation; + class DescriptorSetImplementation; + class DescriptorSetLayoutImplementation; + class DescriptorPoolImplementation; + class QueueImplementation; + class CommandPoolImplementation; + class CommandBufferImplementation; + + namespace view { + class SwapChainImplementation; + class FrameBufferImplementation; + class RenderPassImplementation; + class PipelineCacheImplementation; + class PipelineLayoutImplementation; + class PipelineImplementation; + class DescriptorSetImplementation; + class DescriptorSetLayoutImplementation; + class DescriptorPoolImplementation; + class QueueImplementation; + class CommandPoolImplementation; + class CommandBufferImplementation; + } // namespace view + + export { + class SwapChainTag; + template + class SwapChainInterface; + + class FrameBufferTag; + template + class FrameBufferInterface; + + class RenderPassTag; + template + class RenderPassInterface; + + class PipelineCacheTag; + template + class PipelineCacheInterface; + + class PipelineLayoutTag; + template + class PipelineLayoutInterface; + + class PipelineTag; + template + class PipelineInterface; + + class DescriptorSetTag; + template + class DescriptorSetInterface; + + class DescriptorSetLayoutTag; + template + class DescriptorSetLayoutInterface; + + class DescriptorPoolTag; + template + class DescriptorPoolInterface; + + class QueueTag; + template + class QueueInterface; + + class CommandBufferTag; + template + class CommandBufferInterface; + + class CommandPoolTag; + template + class CommandPoolInterface; + + using LoadSaveError = DecoratedError>; + template + using LoadSaveExpected = core::Expected; + + using SwapChain = SwapChainInterface; + using FrameBuffer = FrameBufferInterface; + using RenderPass = RenderPassInterface; + using PipelineCache = PipelineCacheInterface; + using PipelineLayout = PipelineLayoutInterface; + using Pipeline = PipelineInterface; + using DescriptorSet = DescriptorSetInterface; + using DescriptorSetLayout = DescriptorSetLayoutInterface; + using DescriptorPool = DescriptorPoolInterface; + using Queue = QueueInterface; + using CommandBuffer = CommandBufferInterface; + using CommandPool = CommandPoolInterface; + + namespace view { + using SwapChain = SwapChainInterface; + using FrameBuffer = FrameBufferInterface; + using RenderPass = RenderPassInterface; + using PipelineCache = PipelineCacheInterface; + using PipelineLayout = PipelineLayoutInterface; + using Pipeline = PipelineInterface; + using DescriptorSet = DescriptorSetInterface; + using DescriptorSetLayout = DescriptorSetLayoutInterface; + using DescriptorPool = DescriptorPoolInterface; + using Queue = QueueInterface; + using CommandBuffer = CommandBufferInterface; + using CommandPool = CommandPoolInterface; + } // namespace view + + namespace trait { + template<> + struct GpuObject { + using ValueType = VkSwapchainKHR; + using DeleterType = PFN_vkDestroySwapchainKHR VolkDeviceTable::*; + using ObjectType = SwapChain; + using ViewType = view::SwapChain; + using OwnerType = Device; + + static constexpr auto DEBUG_TYPE = DebugObjectType::SWAPCHAIN; + }; + + template<> + struct GpuObject { + using ValueType = VkFramebuffer; + using DeleterType = PFN_vkDestroyFramebuffer VolkDeviceTable::*; + using ObjectType = FrameBuffer; + using ViewType = view::FrameBuffer; + using OwnerType = Device; + + static constexpr auto DEBUG_TYPE = DebugObjectType::FRAMEBUFFER; + }; + + template<> + struct GpuObject { + using ValueType = VkRenderPass; + using DeleterType = PFN_vkDestroyRenderPass VolkDeviceTable::*; + using ObjectType = RenderPass; + using ViewType = view::RenderPass; + using OwnerType = Device; + + static constexpr auto DEBUG_TYPE = DebugObjectType::RENDER_PASS; + }; + + template<> + struct GpuObject { + using ValueType = VkPipelineCache; + using DeleterType = PFN_vkDestroyPipelineCache VolkDeviceTable::*; + using ObjectType = PipelineCache; + using ViewType = view::PipelineCache; + using OwnerType = Device; + using DoInitReturnType = LoadSaveExpected; + + static constexpr auto DEBUG_TYPE = DebugObjectType::PIPELINE_CACHE; + }; + + template<> + struct GpuObject { + using ValueType = VkPipelineLayout; + using DeleterType = PFN_vkDestroyPipelineLayout VolkDeviceTable::*; + using ObjectType = PipelineLayout; + using ViewType = view::PipelineLayout; + using OwnerType = Device; + + static constexpr auto DEBUG_TYPE = DebugObjectType::PIPELINE_LAYOUT; + }; + + template<> + struct GpuObject { + using ValueType = VkPipeline; + using DeleterType = PFN_vkDestroyPipeline VolkDeviceTable::*; + using ObjectType = Pipeline; + using ViewType = view::Pipeline; + using OwnerType = Device; + + static constexpr auto DEBUG_TYPE = DebugObjectType::PIPELINE; + }; + + template<> + struct GpuObject { + using ValueType = VkDescriptorSet; + using DeleterType = decltype(cmonadic::noop()); + using ObjectType = DescriptorSet; + using ViewType = view::DescriptorSet; + using OwnerType = Device; + using DoInitReturnType = void; + + static constexpr auto DEBUG_TYPE = DebugObjectType::DESCRIPTOR_SET; + }; + + template<> + struct GpuObject { + using ValueType = VkDescriptorSetLayout; + using DeleterType = PFN_vkDestroyDescriptorSetLayout VolkDeviceTable::*; + using ObjectType = DescriptorSetLayout; + using ViewType = view::DescriptorSetLayout; + using OwnerType = Device; + + static constexpr auto DEBUG_TYPE = DebugObjectType::DESCRIPTOR_SET_LAYOUT; + }; + + template<> + struct GpuObject { + using ValueType = VkDescriptorPool; + using DeleterType = PFN_vkDestroyDescriptorPool VolkDeviceTable::*; + using ObjectType = DescriptorPool; + using ViewType = view::DescriptorPool; + using OwnerType = Device; + + static constexpr auto DEBUG_TYPE = DebugObjectType::DESCRIPTOR_POOL; + }; + + template<> + struct GpuObject { + using ValueType = VkQueue; + using DeleterType = decltype(cmonadic::noop()); + using ObjectType = Queue; + using ViewType = view::Queue; + using OwnerType = Device; + using DoInitReturnType = void; + + static constexpr auto DEBUG_TYPE = DebugObjectType::QUEUE; + }; + + template<> + struct GpuObject { + using ValueType = VkCommandBuffer; + using DeleterType = decltype(cmonadic::noop()); + using ObjectType = CommandBuffer; + using ViewType = view::CommandBuffer; + using OwnerType = Device; + using DoInitReturnType = void; + + static constexpr auto DEBUG_TYPE = DebugObjectType::COMMAND_BUFFER; + }; + + template<> + struct GpuObject { + using ValueType = VkCommandPool; + using DeleterType = PFN_vkDestroyCommandPool VolkDeviceTable::*; + using ObjectType = CommandPool; + using ViewType = view::CommandPool; + using OwnerType = Device; + + static constexpr auto DEBUG_TYPE = DebugObjectType::COMMAND_POOL; + }; + + } // namespace trait + } +} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/execution/pipeline.cppm b/modules/stormkit/gpu/execution/pipeline.cppm new file mode 100644 index 000000000..4fbe4fe66 --- /dev/null +++ b/modules/stormkit/gpu/execution/pipeline.cppm @@ -0,0 +1,468 @@ +// Copyright (C) 2023 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include + +#include + +#include +#include + +export module stormkit.gpu.execution:pipeline; + +import std; + +import stormkit.core; +import stormkit.gpu.core; + +import :objects; +import :raster_pipeline; +import :render_pass; + +namespace stdfs = std::filesystem; + +namespace cmeta = stormkit::core::meta; + +namespace stormkit::gpu { + export { + template + class PipelineCacheInterface final: public DeviceObject { + public: + using DeviceObject::DeviceObject; + using DeviceObject::operator=; + using TagType = PipelineCacheTag; + }; + + template + class PipelineLayoutInterface final: public DeviceObject { + public: + using DeviceObject::DeviceObject; + using DeviceObject::operator=; + using TagType = PipelineLayoutTag; + + [[nodiscard]] + auto raster_layout() const noexcept -> const RasterPipelineLayout&; + }; + } + + class STORMKIT_GPU_API PipelineCacheImplementation: public GpuObjectImplementation { + public: + PipelineCacheImplementation(PrivateTag, view::Device&&) noexcept; + ~PipelineCacheImplementation() noexcept; + + PipelineCacheImplementation(const PipelineCacheImplementation&) = delete; + auto operator=(const PipelineCacheImplementation&) -> PipelineCacheImplementation& = delete; + + PipelineCacheImplementation(PipelineCacheImplementation&&) noexcept; + auto operator=(PipelineCacheImplementation&&) noexcept -> PipelineCacheImplementation&; + + static auto load_from_file(view::Device device, stdfs::path cache_path) noexcept -> LoadSaveExpected; + static auto allocate_load_from_file(view::Device device, stdfs::path cache_path) noexcept + -> LoadSaveExpected>; + + auto do_init(PrivateTag, stdfs::path&&) noexcept -> LoadSaveExpected; + + protected: + using NamedConstructor::allocate; + using NamedConstructor::create; + + auto create_new_pipeline_cache() noexcept -> LoadSaveExpected; + auto read_pipeline_cache() noexcept -> LoadSaveExpected; + auto save_cache() noexcept -> LoadSaveExpected; + + static constexpr auto MAGIC = u32 { 0xDEADBEEF }; + static constexpr auto VERSION = u32 { 1u }; + + struct SerializedCache { + struct { + u32 magic; + usize data_size; + u64 data_hash; + } guard; + + struct { + u32 version; + u64 vendor_id; + u64 device_id; + } infos; + + struct { + array value; + } uuid; + } m_serialized; + + stdfs::path m_path; + }; + + namespace view { + class PipelineCacheImplementation: public GpuObjectViewImplementation { + public: + using GpuObjectViewImplementation::GpuObjectViewImplementation; + using GpuObjectViewImplementation::operator=; + }; + } // namespace view + + class STORMKIT_GPU_API + PipelineLayoutImplementation: public GpuObjectImplementation { + public: + PipelineLayoutImplementation(PrivateTag, view::Device&& device) noexcept; + ~PipelineLayoutImplementation() noexcept; + + PipelineLayoutImplementation(const PipelineLayoutImplementation&) = delete; + auto operator=(const PipelineLayoutImplementation&) -> PipelineLayoutImplementation& = delete; + + PipelineLayoutImplementation(PipelineLayoutImplementation&&) noexcept; + auto operator=(PipelineLayoutImplementation&&) noexcept -> PipelineLayoutImplementation&; + + auto do_init(PrivateTag, const RasterPipelineLayout&) noexcept -> Expected; + + protected: + Heap m_layout; + + friend class view::PipelineLayoutImplementation; + }; + + namespace view { + class PipelineLayoutImplementation: public GpuObjectViewImplementation { + public: + PipelineLayoutImplementation(const gpu::PipelineLayout& of) noexcept; + template TContainerOrPointer> + PipelineLayoutImplementation(const TContainerOrPointer&) noexcept; + ~PipelineLayoutImplementation() noexcept; + + PipelineLayoutImplementation(const PipelineLayoutImplementation&) noexcept; + auto operator=(const PipelineLayoutImplementation&) noexcept -> PipelineLayoutImplementation&; + + PipelineLayoutImplementation(PipelineLayoutImplementation&&) noexcept; + auto operator=(PipelineLayoutImplementation&&) noexcept -> PipelineLayoutImplementation&; + + protected: + ref m_layout; + }; + } // namespace view + + export { + struct PipelineInterfaceBase { + using StateVariant = std::variant; + + enum class Type { + RASTER, + COMPUTE, + RAYTRACING, + }; + + struct RasterizationCreateInfo { + ref state; + view::PipelineLayout layout; + RasterPipelineRenderingInfo rendering_info; + std::optional cache = std::nullopt; + }; + + struct LegacyRasterizationCreateInfo { + ref state; + view::PipelineLayout layout; + view::RenderPass render_pass; + std::optional cache = std::nullopt; + }; + }; + + template + class PipelineInterface final: public DeviceObject, protected PipelineInterfaceBase { + public: + using DeviceObject::DeviceObject; + using DeviceObject::operator=; + using TagType = PipelineTag; + + using PipelineInterfaceBase::Type; + + [[nodiscard]] + auto type() const noexcept -> Type; + [[nodiscard]] + auto raster_state() const noexcept -> const RasterPipelineState&; + }; + } + + class STORMKIT_GPU_API PipelineImplementation + : public GpuObjectImplementation, + public core::NamedConstructor, + DoInitArgs> { + using StateVariant = PipelineInterfaceBase::StateVariant; + + using LegacyNamedConstructor = NamedConstructor, + DoInitArgs>; + + public: + using Type = PipelineInterfaceBase::Type; + using RasterizationCreateInfo = PipelineInterfaceBase::RasterizationCreateInfo; + using LegacyRasterizationCreateInfo = PipelineInterfaceBase::LegacyRasterizationCreateInfo; + + PipelineImplementation(PrivateTag, view::Device&&) noexcept; + ~PipelineImplementation() noexcept; + + PipelineImplementation(const PipelineImplementation&) = delete; + auto operator=(const PipelineImplementation&) -> PipelineImplementation& = delete; + + PipelineImplementation(PipelineImplementation&&) noexcept; + auto operator=(PipelineImplementation&&) noexcept -> PipelineImplementation&; + + using GpuObjectImplementation::allocate; + using GpuObjectImplementation::create; + using LegacyNamedConstructor::allocate; + using LegacyNamedConstructor::create; + + auto do_init(PrivateTag, const RasterizationCreateInfo&) noexcept -> Expected; + auto do_init(PrivateTag, const LegacyRasterizationCreateInfo&) noexcept -> Expected; + + protected: + Type m_type; + Heap m_state; + + friend class view::PipelineImplementation; + }; + + namespace view { + class PipelineImplementation: public GpuObjectViewImplementation { + using StateVariant = PipelineInterfaceBase::StateVariant; + + public: + using Type = PipelineInterfaceBase::Type; + + PipelineImplementation(const gpu::Pipeline& of) noexcept; + template TContainerOrPointer> + PipelineImplementation(const TContainerOrPointer&) noexcept; + ~PipelineImplementation() noexcept; + + PipelineImplementation(const PipelineImplementation&) noexcept; + auto operator=(const PipelineImplementation&) noexcept -> PipelineImplementation&; + + PipelineImplementation(PipelineImplementation&&) noexcept; + auto operator=(PipelineImplementation&&) noexcept -> PipelineImplementation&; + + protected: + Type m_type; + ref m_state; + }; + } // namespace view +} // namespace stormkit::gpu + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit::gpu { + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto PipelineLayoutInterface::raster_layout() const noexcept -> const RasterPipelineLayout& { + EXPECTS(Base::m_layout != nullptr); + return *Base::m_layout; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto PipelineInterface::type() const noexcept -> Type { + return Base::m_type; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto PipelineInterface::raster_state() const noexcept -> const RasterPipelineState& { + EXPECTS(Base::m_type == Type::RASTER); + EXPECTS(Base::m_state != nullptr); + EXPECTS(is(*Base::m_state)); + return as(*Base::m_state); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline PipelineCacheImplementation::PipelineCacheImplementation(PrivateTag, view::Device&& device) noexcept + : GpuObjectImplementation { std::move(device), &VolkDeviceTable::vkDestroyPipelineCache } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline PipelineCacheImplementation::PipelineCacheImplementation(PipelineCacheImplementation&& other) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto PipelineCacheImplementation::operator=(PipelineCacheImplementation&& other) noexcept + -> PipelineCacheImplementation& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto PipelineCacheImplementation::load_from_file(view::Device device, stdfs::path cache_path) noexcept + -> LoadSaveExpected { + Return NamedConstructor::create(std::move(device), std::move(cache_path)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto PipelineCacheImplementation::allocate_load_from_file(view::Device device, stdfs::path cache_path) noexcept + -> LoadSaveExpected> { + Return NamedConstructor::allocate(std::move(device), std::move(cache_path)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline PipelineLayoutImplementation::PipelineLayoutImplementation(PrivateTag, view::Device&& device) noexcept + : GpuObjectImplementation { std::move(device), &VolkDeviceTable::vkDestroyPipelineLayout } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline PipelineLayoutImplementation::~PipelineLayoutImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline PipelineLayoutImplementation::PipelineLayoutImplementation(PipelineLayoutImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto PipelineLayoutImplementation::operator=(PipelineLayoutImplementation&&) noexcept + -> PipelineLayoutImplementation& = default; + + namespace view { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline PipelineLayoutImplementation::PipelineLayoutImplementation(const gpu::PipelineLayout& of) noexcept + : GpuObjectViewImplementation { of }, m_layout { as_ref(of.raster_layout()) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template TContainerOrPointer> + STORMKIT_FORCE_INLINE + inline PipelineLayoutImplementation::PipelineLayoutImplementation(const TContainerOrPointer& of) noexcept + : PipelineLayoutImplementation { *of } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline PipelineLayoutImplementation::~PipelineLayoutImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline PipelineLayoutImplementation::PipelineLayoutImplementation(const PipelineLayoutImplementation&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto PipelineLayoutImplementation::operator=(const PipelineLayoutImplementation& other) noexcept + -> PipelineLayoutImplementation& { + if (&other == this) [[unlikely]] + return *this; + + m_layout = as_ref(other.m_layout); + + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline PipelineLayoutImplementation::PipelineLayoutImplementation(PipelineLayoutImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto PipelineLayoutImplementation::operator=(PipelineLayoutImplementation&&) noexcept + -> PipelineLayoutImplementation& = default; + } // namespace view + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline PipelineImplementation::PipelineImplementation(PrivateTag, view::Device&& device) noexcept + : GpuObjectImplementation { std::move(device), &VolkDeviceTable::vkDestroyPipeline } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline PipelineImplementation::~PipelineImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline PipelineImplementation::PipelineImplementation(PipelineImplementation&& other) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto PipelineImplementation::operator=(PipelineImplementation&& other) noexcept -> PipelineImplementation& = default; + + namespace view { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline PipelineImplementation::PipelineImplementation(const gpu::Pipeline& of) noexcept + : GpuObjectViewImplementation { of }, m_type { of.type() }, m_state { as_ref(of.m_state) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template TContainerOrPointer> + STORMKIT_FORCE_INLINE + inline PipelineImplementation::PipelineImplementation(const TContainerOrPointer& of) noexcept + : PipelineImplementation { *of } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline PipelineImplementation::~PipelineImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline PipelineImplementation::PipelineImplementation(const PipelineImplementation&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto PipelineImplementation::operator=(const PipelineImplementation& other) noexcept -> PipelineImplementation& { + if (&other == this) [[unlikely]] + return *this; + + GpuObjectViewImplementation::operator=(other); + + m_type = other.m_type; + m_state = as_ref(other.m_state); + + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline PipelineImplementation::PipelineImplementation(PipelineImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto PipelineImplementation::operator=(PipelineImplementation&&) noexcept -> PipelineImplementation& = default; + } // namespace view +} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/execution/pipeline.mpp b/modules/stormkit/gpu/execution/pipeline.mpp deleted file mode 100644 index 83645c0a4..000000000 --- a/modules/stormkit/gpu/execution/pipeline.mpp +++ /dev/null @@ -1,382 +0,0 @@ -// Copyright (C) 2023 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include -#include - -#include - -#include - -export module stormkit.gpu.execution:pipeline; - -import std; - -import stormkit.core; -import stormkit.gpu.core; - -import :raster_pipeline; -import :render_pass; - -export namespace stormkit::gpu { - class CommandBuffer; - - class STORMKIT_API PipelineCache { - struct PrivateFuncTag {}; - - public: - using LoadSaveError = DecoratedError>; - template - using LoadSaveExpected = core::Expected; - - static constexpr auto DEBUG_TYPE = DebugObjectType::PIPELINE_CACHE; - - static auto try_load(const Device& device, std::filesystem::path cache_path) noexcept - -> LoadSaveExpected; - ~PipelineCache() noexcept; - - PipelineCache(const PipelineCache&) = delete; - auto operator=(const PipelineCache&) -> PipelineCache& = delete; - - PipelineCache(PipelineCache&&) noexcept; - auto operator=(PipelineCache&&) noexcept -> PipelineCache&; - - [[nodiscard]] - auto native_handle() const noexcept -> VkPipelineCache; - - PipelineCache(const Device&, std::filesystem::path, PrivateFuncTag) noexcept; - - private: - auto do_init(const Device&) noexcept -> LoadSaveExpected; - auto create_new_pipeline_cache(const Device&) noexcept -> LoadSaveExpected; - auto read_pipeline_cache(const Device&) noexcept -> LoadSaveExpected; - auto save_cache() noexcept -> LoadSaveExpected; - - static constexpr auto MAGIC = u32 { 0xDEADBEEF }; - static constexpr auto VERSION = u32 { 1u }; - - struct SerializedCache { - struct { - u32 magic; - usize data_size; - u64 data_hash; - } guard; - - struct { - u32 version; - u64 vendor_id; - u64 device_id; - } infos; - - struct { - std::array value; - } uuid; - } m_serialized; - - std::filesystem::path m_path; - - VkDevice m_vk_device = nullptr; - Ref m_vk_device_table; - VkRAIIHandle m_vk_handle; - }; - - class STORMKIT_API PipelineLayout { - struct PrivateFuncTag {}; - - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::PIPELINE_LAYOUT; - - static auto create(const Device& device, const RasterPipelineLayout& layout) noexcept - -> Expected; - ~PipelineLayout() noexcept; - - PipelineLayout(const PipelineLayout&) = delete; - auto operator=(const PipelineLayout&) -> PipelineLayout& = delete; - - PipelineLayout(PipelineLayout&&) noexcept; - auto operator=(PipelineLayout&&) noexcept -> PipelineLayout&; - - [[nodiscard]] - auto rasterLayout() const noexcept -> const RasterPipelineLayout&; - - [[nodiscard]] - auto native_handle() const noexcept -> VkPipelineLayout; - - PipelineLayout(const Device& device, - const RasterPipelineLayout& layout, - PrivateFuncTag) noexcept; - - private: - auto do_init() noexcept -> Expected; - - RasterPipelineLayout m_layout; - VkDevice m_vk_device = nullptr; - Ref m_vk_device_table; - VkRAIIHandle m_vk_handle; - }; - - class STORMKIT_API Pipeline { - struct PrivateFuncTag {}; - - public: - enum class Type { - RASTER, - COMPUTE, - }; - - static constexpr auto DEBUG_TYPE = DebugObjectType::PIPELINE; - - static auto create(const Device& device, - const RasterPipelineState& state, - const PipelineLayout& layout, - const RenderPass& render_pass, - OptionalRef cache = std::nullopt) noexcept - -> Expected; - ~Pipeline() noexcept; - - Pipeline(const Pipeline&) = delete; - auto operator=(const Pipeline&) -> Pipeline& = delete; - - Pipeline(Pipeline&&) noexcept; - auto operator=(Pipeline&&) noexcept -> Pipeline&; - - // auto bind(CommandBuffer& commandbuffer) const noexcept -> void; - - [[nodiscard]] - auto type() const noexcept -> Type; - [[nodiscard]] - auto raster_state() const noexcept -> const RasterPipelineState&; - - [[nodiscard]] - auto native_handle() const noexcept -> VkPipeline; - - Pipeline(const Device&, const RasterPipelineState&, PrivateFuncTag) noexcept; - - private: - auto do_init(const PipelineLayout&, - const RenderPass&, - OptionalRef) noexcept -> Expected; - - Type m_type; - std::variant m_state; - - VkDevice m_vk_device = nullptr; - Ref m_vk_device_table; - VkRAIIHandle m_vk_handle; - }; -} // namespace stormkit::gpu - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::gpu { - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline PipelineCache::PipelineCache(const Device& device, - std::filesystem::path path, - PrivateFuncTag) noexcept - : m_path { std::move(path) }, m_vk_device { device.native_handle() }, - m_vk_device_table { as_ref(device.device_table()) }, - m_vk_handle { { [vk_device_table = *m_vk_device_table, - vk_device = m_vk_device](auto handle) noexcept { - vk_device_table.vkDestroyPipelineCache(vk_device, handle, nullptr); - } } } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline PipelineCache::PipelineCache(PipelineCache&& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto PipelineCache::operator=(PipelineCache&& other) noexcept - -> PipelineCache& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto PipelineCache::try_load(const Device& device, - std::filesystem::path cache_path) noexcept - -> LoadSaveExpected { - auto cache = PipelineCache { device, std::move(cache_path), PrivateFuncTag {} }; - Try(cache.do_init(device)); - Ret(cache); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto PipelineCache::native_handle() const noexcept -> VkPipelineCache { - return m_vk_handle; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto PipelineCache::do_init(const Device& device) noexcept -> LoadSaveExpected { - Ret(read_pipeline_cache(device)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline PipelineLayout::PipelineLayout(const Device& device, - const RasterPipelineLayout& layout, - PrivateFuncTag) noexcept - : m_layout { layout }, m_vk_device { device.native_handle() }, - m_vk_device_table { as_ref(device.device_table()) }, - m_vk_handle { { [vk_device_table = *m_vk_device_table, - vk_device = m_vk_device](auto handle) noexcept { - vk_device_table.vkDestroyPipelineLayout(vk_device, handle, nullptr); - } } } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline PipelineLayout::~PipelineLayout() noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline PipelineLayout::PipelineLayout(PipelineLayout&& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto PipelineLayout::operator=(PipelineLayout&& other) noexcept - -> PipelineLayout& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto PipelineLayout::create(const Device& device, - const RasterPipelineLayout& layout) noexcept - -> Expected { - auto pipeline_layout = PipelineLayout { device, layout, PrivateFuncTag {} }; - Try(pipeline_layout.do_init()); - Ret(pipeline_layout); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto PipelineLayout::native_handle() const noexcept -> VkPipelineLayout { - return m_vk_handle; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto PipelineLayout::do_init() noexcept -> Expected { - namespace stdv = std::views; - namespace stdr = std::ranges; - const auto set_layouts = m_layout.descriptor_set_layouts - | stdv::transform(core::monadic::unref()) - | stdv::transform(monadic::to_vk()) - | stdr::to(); - - const auto - push_constant_ranges = m_layout.push_constant_ranges - | stdv::transform([](auto&& push_constant_range) noexcept { - return VkPushConstantRange { - .stageFlags = to_vk< - VkShaderStageFlags>(push_constant_range.stages), - .offset = push_constant_range.offset, - .size = as(push_constant_range.size), - }; - }) - | stdr::to(); - - const auto create_info = VkPipelineLayoutCreateInfo { - .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .setLayoutCount = as(stdr::size(set_layouts)), - .pSetLayouts = stdr::data(set_layouts), - .pushConstantRangeCount = as(stdr::size(push_constant_ranges)), - .pPushConstantRanges = stdr::data(push_constant_ranges), - }; - - m_vk_handle = Try(vk_call(m_vk_device_table->vkCreatePipelineLayout, - m_vk_device, - &create_info, - nullptr) - .transform_error(monadic::from_vk())); - - Ret({}); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Pipeline::Pipeline(const Device& device, - const RasterPipelineState& state, - PrivateFuncTag) noexcept - : m_type { Type::RASTER }, m_state { state }, m_vk_device { device.native_handle() }, - m_vk_device_table { as_ref(device.device_table()) }, - m_vk_handle { { [vk_device_table = *m_vk_device_table, - vk_device = m_vk_device](auto handle) noexcept { - vk_device_table.vkDestroyPipeline(vk_device, handle, nullptr); - } } } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Pipeline::create(const Device& device, - const RasterPipelineState& state, - const PipelineLayout& layout, - const RenderPass& render_pass, - OptionalRef cache) noexcept - -> Expected { - auto pipeline = Pipeline { device, state, PrivateFuncTag {} }; - Try(pipeline.do_init(layout, render_pass, std::move(cache))); - Ret(pipeline); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Pipeline::~Pipeline() noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Pipeline::Pipeline(Pipeline&& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Pipeline::operator=(Pipeline&& other) noexcept -> Pipeline& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Pipeline::type() const noexcept -> Type { - return m_type; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Pipeline::raster_state() const noexcept -> const RasterPipelineState& { - EXPECTS(m_type == Type::RASTER); - EXPECTS(is(m_state)); - return as(m_state); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Pipeline::native_handle() const noexcept -> VkPipeline { - return m_vk_handle; - } -} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/execution/raster_pipeline.mpp b/modules/stormkit/gpu/execution/raster_pipeline.cppm similarity index 69% rename from modules/stormkit/gpu/execution/raster_pipeline.mpp rename to modules/stormkit/gpu/execution/raster_pipeline.cppm index abdcec973..1294575be 100644 --- a/modules/stormkit/gpu/execution/raster_pipeline.mpp +++ b/modules/stormkit/gpu/execution/raster_pipeline.cppm @@ -4,9 +4,8 @@ module; -#include - #include +#include #include @@ -36,8 +35,8 @@ export namespace stormkit::gpu { }; struct RasterPipelineVertexInputState { - std::vector binding_descriptions = {}; - std::vector input_attribute_descriptions = {}; + dyn_array binding_descriptions = {}; + dyn_array input_attribute_descriptions = {}; }; struct RasterPipelineInputAssemblyState { @@ -46,8 +45,8 @@ export namespace stormkit::gpu { }; struct RasterPipelineViewportState { - std::vector viewports = {}; - std::vector scissors = {}; + dyn_array viewports = {}; + dyn_array scissors = {}; }; struct RasterPipelineRasterizationState { @@ -58,15 +57,15 @@ export namespace stormkit::gpu { CullModeFlag cull_mode = CullModeFlag::BACK; FrontFace front_face = FrontFace::CLOCKWISE; bool depth_bias_enable = false; - float depth_bias_constant_factor = 0.f; - float depth_bias_clamp = 0.f; - float depth_bias_slope_factor = 0.f; + f32 depth_bias_constant_factor = 0.f; + f32 depth_bias_clamp = 0.f; + f32 depth_bias_slope_factor = 0.f; }; struct RasterPipelineMultiSampleState { bool sample_shading_enable = false; SampleCountFlag rasterization_samples = SampleCountFlag::C1; - float min_sample_shading = 0.f; + f32 min_sample_shading = 0.f; }; struct RasterPipelineColorBlendAttachmentState { @@ -83,14 +82,14 @@ export namespace stormkit::gpu { }; struct RasterPipelineColorBlendState { - bool logic_operation_enable = false; - LogicOperation logic_operation = LogicOperation::COPY; - std::vector attachments; - std::array blend_constants = { 0.f, 0.f, 0.f, 0.f }; + bool logic_operation_enable = false; + LogicOperation logic_operation = LogicOperation::COPY; + dyn_array attachments; + array blend_constants = { 0.f, 0.f, 0.f, 0.f }; }; - using RasterPipelineDynamicState = std::vector; - using RasterPipelineShaderState = std::vector>; + using RasterPipelineDynamicState = dyn_array; + using RasterPipelineShaderState = dyn_array; struct RasterPipelineDepthStencilState { bool depth_test_enable = false; @@ -100,13 +99,20 @@ export namespace stormkit::gpu { bool depth_bounds_test_enable = false; - float min_depth_bounds = 0.f; - float max_depth_bounds = 1.f; + f32 min_depth_bounds = 0.f; + f32 max_depth_bounds = 1.f; + }; + + struct RasterPipelineRenderingInfo { + u32 view_mask = 0u; + dyn_array color_attachment_formats; + std::optional depth_attachment_format = std::nullopt; + std::optional stencil_attachment_format = std::nullopt; }; struct RasterPipelineLayout { - std::vector> descriptor_set_layouts = {}; - std::vector push_constant_ranges = {}; + dyn_array descriptor_set_layouts = {}; + dyn_array push_constant_ranges = {}; }; struct RasterPipelineState { diff --git a/modules/stormkit/gpu/execution/render_pass.cppm b/modules/stormkit/gpu/execution/render_pass.cppm new file mode 100644 index 000000000..522b5f5b1 --- /dev/null +++ b/modules/stormkit/gpu/execution/render_pass.cppm @@ -0,0 +1,448 @@ +// Copyright (C) 2023 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include +#include + +#include +#include + +export module stormkit.gpu.execution:render_pass; + +import std; + +import stormkit.core; +import stormkit.gpu.core; +import stormkit.gpu.resource; + +import :objects; + +namespace cmeta = stormkit::core::meta; + +namespace stormkit::gpu { + export { + struct AttachmentDescription { + PixelFormat format; + SampleCountFlag samples = SampleCountFlag::C1; + + AttachmentLoadOperation load_op = AttachmentLoadOperation::CLEAR; + AttachmentStoreOperation store_op = AttachmentStoreOperation::STORE; + + AttachmentLoadOperation stencil_load_op = AttachmentLoadOperation::DONT_CARE; + AttachmentStoreOperation stencil_store_op = AttachmentStoreOperation::DONT_CARE; + + ImageLayout source_layout = ImageLayout::UNDEFINED; + ImageLayout destination_layout = ImageLayout::PRESENT_SRC; + + bool resolve = false; + }; + + using AttachmentDescriptions = dyn_array; + + struct Subpass { + struct Ref { + u32 attachment_id; + + ImageLayout layout = ImageLayout::COLOR_ATTACHMENT_OPTIMAL; + }; + + PipelineBindPoint bind_point; + dyn_array color_attachment_refs = {}; + dyn_array resolve_attachment_refs = {}; + std::optional depth_attachment_ref = {}; + }; + + using Subpasses = dyn_array; + + struct RenderPassDescription { + AttachmentDescriptions attachments; + Subpasses subpasses; + + auto is_compatible(const RenderPassDescription& description) const noexcept -> bool; + }; + + template + class FrameBufferInterface final: public DeviceObject { + public: + using DeviceObject::DeviceObject; + using DeviceObject::operator=; + using TagType = FrameBufferTag; + + [[nodiscard]] + auto extent() const noexcept -> const math::uextent2&; + [[nodiscard]] + auto attachments() const noexcept -> array_view; + }; + + template + class RenderPassInterface final: public DeviceObject { + public: + using DeviceObject::DeviceObject; + using DeviceObject::operator=; + using TagType = RenderPassTag; + + auto create_framebuffer(this const auto&, + view::Device device, + const math::uextent2& extent, + dyn_array attachments) noexcept -> Expected; + auto allocate_framebuffer(this const auto&, + view::Device device, + const math::uextent2& extent, + dyn_array attachments) noexcept -> Expected>; + + [[nodiscard]] + auto is_compatible(view::RenderPass render_pass) const noexcept -> bool; + [[nodiscard]] + auto is_compatible(const RenderPassDescription& description) const noexcept -> bool; + + [[nodiscard]] + auto description() const noexcept -> const RenderPassDescription&; + }; + } + + class STORMKIT_GPU_API FrameBufferImplementation + : public GpuObjectImplementation> { + public: + FrameBufferImplementation(PrivateTag, view::Device&&) noexcept; + ~FrameBufferImplementation() noexcept; + + FrameBufferImplementation(const FrameBufferImplementation&) = delete; + auto operator=(const FrameBufferImplementation&) -> FrameBufferImplementation& = delete; + + FrameBufferImplementation(FrameBufferImplementation&&) noexcept; + auto operator=(FrameBufferImplementation&&) noexcept -> FrameBufferImplementation&; + + auto do_init(PrivateTag, view::RenderPass&&, const math::uextent2&, dyn_array&&) noexcept + -> Expected; + + protected: + using NamedConstructor::allocate; + using NamedConstructor::create; + + math::uextent2 m_extent = { 0, 0 }; + dyn_array m_attachments; + + friend class RenderPassInterface; + friend class RenderPassInterface; + }; + + namespace view { + class FrameBufferImplementation: public GpuObjectViewImplementation { + public: + FrameBufferImplementation(const gpu::FrameBuffer& of) noexcept; + template TContainerOrPointer> + FrameBufferImplementation(const TContainerOrPointer&) noexcept; + ~FrameBufferImplementation() noexcept; + + FrameBufferImplementation(const FrameBufferImplementation&) noexcept; + auto operator=(const FrameBufferImplementation&) noexcept -> FrameBufferImplementation&; + + FrameBufferImplementation(FrameBufferImplementation&&) noexcept; + auto operator=(FrameBufferImplementation&&) noexcept -> FrameBufferImplementation&; + + protected: + math::uextent2 m_extent; + array_view m_attachments; + }; + } // namespace view + + class STORMKIT_GPU_API RenderPassImplementation: public GpuObjectImplementation { + public: + RenderPassImplementation(PrivateTag, view::Device&&) noexcept; + ~RenderPassImplementation() noexcept; + + RenderPassImplementation(const RenderPassImplementation&) = delete; + auto operator=(const RenderPassImplementation&) -> RenderPassImplementation& = delete; + + RenderPassImplementation(RenderPassImplementation&&) noexcept; + auto operator=(RenderPassImplementation&&) noexcept -> RenderPassImplementation&; + + auto do_init(PrivateTag, const RenderPassDescription&) noexcept -> Expected; + + protected: + Heap m_description = {}; + }; + + namespace view { + class RenderPassImplementation: public GpuObjectViewImplementation { + public: + RenderPassImplementation(const gpu::RenderPass& of) noexcept; + template TContainerOrPointer> + RenderPassImplementation(const TContainerOrPointer&) noexcept; + ~RenderPassImplementation() noexcept; + + RenderPassImplementation(const RenderPassImplementation&) noexcept; + auto operator=(const RenderPassImplementation&) noexcept -> RenderPassImplementation&; + + RenderPassImplementation(RenderPassImplementation&&) noexcept; + auto operator=(RenderPassImplementation&&) noexcept -> RenderPassImplementation&; + + protected: + ref m_description; + + friend class RenderPassInterface; + }; + } // namespace view + + template + constexpr auto hasher(const AttachmentDescription& value) noexcept -> Ret; + template + constexpr auto hasher(const Subpass::Ref& value) noexcept -> Ret; + template + constexpr auto hasher(const Subpass& value) noexcept -> Ret; + template + constexpr auto hasher(const RenderPassDescription& value) noexcept -> Ret; +} // namespace stormkit::gpu + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit::gpu { + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto FrameBufferInterface::extent() const noexcept -> const math::uextent2& { + return Base::m_extent; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto FrameBufferInterface::attachments() const noexcept -> array_view { + return Base::m_attachments; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto RenderPassInterface::create_framebuffer(this const auto& self, + view::Device device, + const math::uextent2& extent, + dyn_array attachments) noexcept + -> Expected { + return FrameBuffer::create(std::move(device), gpu::as_view(self), extent, std::move(attachments)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto RenderPassInterface::allocate_framebuffer(this const auto& self, + view::Device device, + const math::uextent2& extent, + dyn_array attachments) noexcept + -> Expected> { + return FrameBuffer::allocate(std::move(device), gpu::as_view(self), extent, std::move(attachments)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto RenderPassInterface::is_compatible(view::RenderPass) const noexcept -> bool { + // TODO implement proper compatibility check + // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/chap7.html#renderpass-compatibility + + return false; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto RenderPassInterface::description() const noexcept -> const RenderPassDescription& { + EXPECTS(Base::m_description != nullptr); + return *Base::m_description; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline FrameBufferImplementation::FrameBufferImplementation(PrivateTag, view::Device&& device) noexcept + : GpuObjectImplementation { std::move(device), &VolkDeviceTable::vkDestroyFramebuffer } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline FrameBufferImplementation::~FrameBufferImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline FrameBufferImplementation::FrameBufferImplementation(FrameBufferImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto FrameBufferImplementation::operator=(FrameBufferImplementation&&) noexcept + -> FrameBufferImplementation& = default; + + namespace view { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline FrameBufferImplementation::FrameBufferImplementation(const gpu::FrameBuffer& of) noexcept + : GpuObjectViewImplementation { of }, m_extent { of.extent() }, m_attachments { of.attachments() } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template TContainerOrPointer> + STORMKIT_FORCE_INLINE + inline FrameBufferImplementation::FrameBufferImplementation(const TContainerOrPointer& of) noexcept + : FrameBufferImplementation { *of } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline FrameBufferImplementation::~FrameBufferImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline FrameBufferImplementation::FrameBufferImplementation(const FrameBufferImplementation&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto FrameBufferImplementation::operator=(const FrameBufferImplementation&) noexcept + -> FrameBufferImplementation& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline FrameBufferImplementation::FrameBufferImplementation(FrameBufferImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto FrameBufferImplementation::operator=(FrameBufferImplementation&&) noexcept + -> FrameBufferImplementation& = default; + } // namespace view + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline RenderPassImplementation::RenderPassImplementation(PrivateTag, view::Device&& device) noexcept + : GpuObjectImplementation { std::move(device), &VolkDeviceTable::vkDestroyRenderPass } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline RenderPassImplementation::~RenderPassImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline RenderPassImplementation::RenderPassImplementation(RenderPassImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto RenderPassImplementation::operator=(RenderPassImplementation&&) noexcept -> RenderPassImplementation& = default; + + namespace view { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline RenderPassImplementation::RenderPassImplementation(const gpu::RenderPass& of) noexcept + : GpuObjectViewImplementation { of }, m_description { as_ref(of.description()) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template TContainerOrPointer> + STORMKIT_FORCE_INLINE + inline RenderPassImplementation::RenderPassImplementation(const TContainerOrPointer& of) noexcept + : RenderPassImplementation { *of } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline RenderPassImplementation::~RenderPassImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline RenderPassImplementation::RenderPassImplementation(const RenderPassImplementation&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto RenderPassImplementation::operator=(const RenderPassImplementation& other) noexcept + -> RenderPassImplementation& { + if (&other == this) [[unlikely]] + return *this; + + m_description = as_ref(other.m_description); + + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline RenderPassImplementation::RenderPassImplementation(RenderPassImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto RenderPassImplementation::operator=(RenderPassImplementation&&) noexcept + -> RenderPassImplementation& = default; + } // namespace view + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto hasher(const AttachmentDescription& value) noexcept -> Ret { + return hash(value.format, + value.samples, + value.load_op, + value.store_op, + value.stencil_load_op, + value.stencil_store_op, + value.source_layout, + value.destination_layout, + value.resolve); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto hasher(const Subpass::Ref& value) noexcept -> Ret { + return hash(value.attachment_id, value.layout); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto hasher(const Subpass& value) noexcept -> Ret { + return hash(value.bind_point, + value.color_attachment_refs, + value.depth_attachment_ref, + value.resolve_attachment_refs); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto hasher(const RenderPassDescription& value) noexcept -> Ret { + return hash(value.attachments, value.subpasses); + } +} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/execution/render_pass.mpp b/modules/stormkit/gpu/execution/render_pass.mpp deleted file mode 100644 index 2809f6ebd..000000000 --- a/modules/stormkit/gpu/execution/render_pass.mpp +++ /dev/null @@ -1,446 +0,0 @@ -// Copyright (C) 2023 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include -#include -#include - -#include - -export module stormkit.gpu.execution:render_pass; - -import std; - -import stormkit.core; -import stormkit.gpu.core; -import stormkit.gpu.resource; - -export { - namespace stormkit::gpu { - class RenderPass; - - class STORMKIT_API FrameBuffer { - struct PrivateFuncTag {}; - - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::FRAMEBUFFER; - - static auto create(const Device& device, - const RenderPass& render_pass, - const math::Extent2& extent, - std::vector> attachments) noexcept - -> Expected; - static auto allocate(const Device& device, - const RenderPass& render_pass, - const math::Extent2& extent, - std::vector> attachments) noexcept - -> Expected>; - ~FrameBuffer() noexcept; - - FrameBuffer(const FrameBuffer&) = delete; - auto operator=(const FrameBuffer&) -> FrameBuffer& = delete; - - FrameBuffer(FrameBuffer&&) noexcept; - auto operator=(FrameBuffer&&) noexcept -> FrameBuffer&; - - [[nodiscard]] - auto extent() const noexcept -> const math::Extent2&; - [[nodiscard]] - auto attachments() const noexcept -> const std::vector>&; - - [[nodiscard]] - auto native_handle() const noexcept -> VkFramebuffer; - - FrameBuffer(const Device&, - const math::Extent2&, - std::vector>, - PrivateFuncTag) noexcept; - - private: - auto do_init(const RenderPass&) noexcept -> Expected; - - math::Extent2 m_extent = { 0, 0 }; - std::vector> m_attachments; - - VkDevice m_vk_device = nullptr; - Ref m_vk_device_table; - VkRAIIHandle m_vk_handle; - }; - - struct AttachmentDescription { - PixelFormat format; - SampleCountFlag samples = SampleCountFlag::C1; - - AttachmentLoadOperation load_op = AttachmentLoadOperation::CLEAR; - AttachmentStoreOperation store_op = AttachmentStoreOperation::STORE; - - AttachmentLoadOperation stencil_load_op = AttachmentLoadOperation::DONT_CARE; - AttachmentStoreOperation stencil_store_op = AttachmentStoreOperation::DONT_CARE; - - ImageLayout source_layout = ImageLayout::UNDEFINED; - ImageLayout destination_layout = ImageLayout::PRESENT_SRC; - - bool resolve = false; - }; - - using AttachmentDescriptions = std::vector; - - struct Subpass { - struct Ref { - u32 attachment_id; - - ImageLayout layout = ImageLayout::COLOR_ATTACHMENT_OPTIMAL; - }; - - PipelineBindPoint bind_point; - std::vector color_attachment_refs = {}; - std::vector resolve_attachment_refs = {}; - std::optional depth_attachment_ref = {}; - }; - - using Subpasses = std::vector; - - struct RenderPassDescription { - AttachmentDescriptions attachments; - Subpasses subpasses; - - auto is_compatible(const RenderPassDescription& description) const noexcept -> bool; - }; - - class STORMKIT_API RenderPass { - struct PrivateFuncTag {}; - - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::RENDER_PASS; - - static auto create(const Device& device, - const RenderPassDescription& description) noexcept - -> Expected; - static auto allocate(const Device& device, - const RenderPassDescription& description) noexcept - -> Expected>; - ~RenderPass() noexcept; - - RenderPass(const RenderPass&) = delete; - auto operator=(const RenderPass&) -> RenderPass& = delete; - - RenderPass(RenderPass&&) noexcept; - auto operator=(RenderPass&&) noexcept -> RenderPass&; - - auto create_frame_buffer(const Device& device, - const math::Extent2& extent, - std::vector> attachments) const noexcept - -> Expected; - auto allocate_frame_buffer(const Device& device, - const math::Extent2& extent, - std::vector> attachments) const noexcept - -> Expected>; - - [[nodiscard]] - auto is_compatible(const RenderPass& render_pass) const noexcept -> bool; - [[nodiscard]] - auto is_compatible(const RenderPassDescription& description) const noexcept -> bool; - - [[nodiscard]] - auto description() const noexcept -> const RenderPassDescription&; - - [[nodiscard]] - auto native_handle() const noexcept -> VkRenderPass; - - RenderPass(const Device& device, - const RenderPassDescription& description, - PrivateFuncTag) noexcept; - - private: - auto do_init() noexcept -> Expected; - - RenderPassDescription m_description = {}; - - VkDevice m_vk_device = nullptr; - Ref m_vk_device_table; - VkRAIIHandle m_vk_handle; - }; - } // namespace stormkit::gpu - - namespace std { - template<> - struct hash { - [[nodiscard]] - constexpr auto operator()(const stormkit::gpu::AttachmentDescription&) const noexcept - -> stormkit::hash64; - }; - - template<> - struct hash { - [[nodiscard]] - constexpr auto operator()(const stormkit::gpu::Subpass::Ref&) const noexcept - -> stormkit::hash64; - }; - - template<> - struct hash { - [[nodiscard]] - constexpr auto operator()(const stormkit::gpu::Subpass&) const noexcept - -> stormkit::hash64; - }; - - template<> - struct hash { - [[nodiscard]] - constexpr auto operator()(const stormkit::gpu::RenderPassDescription&) const noexcept - -> stormkit::hash64; - }; - } // namespace std -} - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::gpu { - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline FrameBuffer::FrameBuffer(const Device& device, - const math::Extent2& extent, - std::vector> attachments, - PrivateFuncTag) noexcept - : m_extent { extent }, m_attachments { std::move(attachments) }, - m_vk_device { device.native_handle() }, - m_vk_device_table { as_ref(device.device_table()) }, - m_vk_handle { { [vk_device_table = *m_vk_device_table, - vk_device = m_vk_device](auto handle) noexcept { - vk_device_table.vkDestroyFramebuffer(vk_device, handle, nullptr); - } } } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto FrameBuffer::create(const Device& device, - const RenderPass& render_pass, - const math::Extent2& extent, - std::vector> attachments) noexcept - -> Expected { - auto - frame_buffer = FrameBuffer { device, extent, std::move(attachments), PrivateFuncTag {} }; - return frame_buffer.do_init(render_pass).transform(core::monadic::consume(frame_buffer)); - } - - ////////////////////////////////////p/ - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto FrameBuffer::allocate(const Device& device, - const RenderPass& render_pass, - const math::Extent2& extent, - std::vector> attachments) noexcept - -> Expected> { - auto frame_buffer = allocate_unsafe(device, - extent, - std::move(attachments), - PrivateFuncTag {}); - return frame_buffer->do_init(render_pass).transform(core::monadic::consume(frame_buffer)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline FrameBuffer::~FrameBuffer() noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline FrameBuffer::FrameBuffer(FrameBuffer&& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto FrameBuffer::operator=(FrameBuffer&& other) noexcept -> FrameBuffer& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto FrameBuffer::extent() const noexcept -> const math::Extent2& { - return m_extent; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto FrameBuffer::attachments() const noexcept - -> const std::vector>& { - return m_attachments; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto FrameBuffer::native_handle() const noexcept -> VkFramebuffer { - return m_vk_handle; - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto FrameBuffer::do_init(const RenderPass& render_pass) noexcept -> Expected { - const auto vk_attachments = m_attachments - | std::views::transform(core::monadic::unref()) - | std::views::transform(monadic::to_vk()) - | std::ranges::to(); - - const auto create_info = VkFramebufferCreateInfo { - .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .renderPass = to_vk(render_pass), - .attachmentCount = as(std::ranges::size(vk_attachments)), - .pAttachments = std::ranges::data(vk_attachments), - .width = m_extent.width, - .height = m_extent.height, - .layers = 1, - }; - - return vk_call(m_vk_device_table->vkCreateFramebuffer, - m_vk_device, - &create_info, - nullptr) - .transform(core::monadic::set(m_vk_handle)) - .transform_error(monadic::from_vk()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline RenderPass::RenderPass(const Device& device, - const RenderPassDescription& description, - PrivateFuncTag) noexcept - : m_description { description }, m_vk_device { device.native_handle() }, - m_vk_device_table { as_ref(device.device_table()) }, - m_vk_handle { { [vk_device_table = *m_vk_device_table, - vk_device = m_vk_device](auto handle) noexcept { - vk_device_table.vkDestroyRenderPass(vk_device, handle, nullptr); - } } } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - auto RenderPass::create(const Device& device, const RenderPassDescription& description) noexcept - -> Expected { - auto render_pass = RenderPass { device, description, PrivateFuncTag {} }; - return render_pass.do_init().transform(core::monadic::consume(render_pass)); - } - - ////////////////////////////////////p/ - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto RenderPass::allocate(const Device& device, - const RenderPassDescription& description) noexcept - -> Expected> { - auto render_pass = allocate_unsafe(device, description, PrivateFuncTag {}); - return render_pass->do_init().transform(core::monadic::consume(render_pass)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline RenderPass::~RenderPass() noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline RenderPass::RenderPass(RenderPass&& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto RenderPass::operator=(RenderPass&& other) noexcept -> RenderPass& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto RenderPass::create_frame_buffer(const Device& device, - const math::Extent2& extent, - std::vector> attachments) - const noexcept -> Expected { - return FrameBuffer::create(device, *this, extent, std::move(attachments)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto RenderPass::allocate_frame_buffer(const Device& device, - const math::Extent2& extent, - std::vector> attachments) - const noexcept -> Expected> { - return FrameBuffer::allocate(device, *this, extent, std::move(attachments)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto RenderPass::is_compatible(const RenderPass& render_pass) const noexcept -> bool { - // TODO implement proper compatibility check - // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/chap7.html#renderpass-compatibility - - return &render_pass == this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto RenderPass::description() const noexcept -> const RenderPassDescription& { - return m_description; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto RenderPass::native_handle() const noexcept -> VkRenderPass { - return m_vk_handle; - } -} // namespace stormkit::gpu - -constexpr auto std::hash:: - operator()(const stormkit::gpu::AttachmentDescription& value) const noexcept -> stormkit::hash64 { - auto hash = stormkit::hash64 { 0 }; - stormkit::hash_combine(hash, - value.format, - value.samples, - value.load_op, - value.store_op, - value.stencil_load_op, - value.stencil_store_op, - value.source_layout, - value.destination_layout, - value.resolve); - return hash; -} - -constexpr auto std::hash::operator()(const stormkit::gpu::Subpass::Ref& - value) const noexcept - -> stormkit::hash64 { - auto hash = stormkit::hash64 { 0 }; - stormkit::hash_combine(hash, value.attachment_id, value.layout); - return hash; -} - -constexpr auto std::hash::operator()(const stormkit::gpu::Subpass& value) - const noexcept -> stormkit::hash64 { - auto hash = stormkit::hash64 { 0 }; - stormkit::hash_combine(hash, - value.bind_point, - value.color_attachment_refs, - value.depth_attachment_ref, - value.resolve_attachment_refs); - return hash; -} - -constexpr auto std::hash:: - operator()(const stormkit::gpu::RenderPassDescription& value) const noexcept -> stormkit::hash64 { - auto hash = stormkit::hash64 { 0 }; - stormkit::hash_combine(hash, value.attachments, value.subpasses); - return hash; -} diff --git a/modules/stormkit/gpu/execution/swapchain.cppm b/modules/stormkit/gpu/execution/swapchain.cppm new file mode 100644 index 000000000..1d7873d8a --- /dev/null +++ b/modules/stormkit/gpu/execution/swapchain.cppm @@ -0,0 +1,194 @@ +// Copyright (C) 2023 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +#include +#include + +export module stormkit.gpu.execution:swapchain; + +import std; + +import stormkit.core; +import stormkit.gpu.core; +import stormkit.gpu.resource; + +import :objects; + +namespace cmeta = stormkit::core::meta; + +namespace stormkit::gpu { + struct SwapChainInterfaceBase { + using ImageID = u32; + + struct NextImage { + Result result; + ImageID id; + }; + + struct CreateInfo { + view::Surface surface; + math::uextent2 extent; + VkSwapchainKHR old = VK_NULL_HANDLE; + }; + }; + + export template + class STORMKIT_GPU_API SwapChainInterface final: public DeviceObject, public SwapChainInterfaceBase { + public: + using DeviceObject::DeviceObject; + using DeviceObject::operator=; + using TagType = SwapChainTag; + + using SwapChainInterfaceBase::ImageID; + using SwapChainInterfaceBase::NextImage; + + [[nodiscard]] + auto pixel_format() const noexcept -> PixelFormat; + [[nodiscard]] + auto images() const noexcept -> array_view; + auto acquire_next_image(std::chrono::nanoseconds wait, view::Semaphore image_available) const noexcept + -> Expected; + }; + + class STORMKIT_GPU_API + SwapChainImplementation: public GpuObjectImplementation { + public: + using ImageID = SwapChainInterfaceBase::ImageID; + using NextImage = SwapChainInterfaceBase::NextImage; + using CreateInfo = SwapChainInterfaceBase::CreateInfo; + + SwapChainImplementation(PrivateTag, view::Device&&) noexcept; + ~SwapChainImplementation() noexcept; + + SwapChainImplementation(const SwapChainImplementation&) = delete; + auto operator=(const SwapChainImplementation&) -> SwapChainImplementation& = delete; + + SwapChainImplementation(SwapChainImplementation&&) noexcept; + auto operator=(SwapChainImplementation&&) noexcept -> SwapChainImplementation&; + + auto do_init(PrivateTag, const CreateInfo&) noexcept -> Expected; + + protected: + math::uextent2 m_extent; + PixelFormat m_pixel_format; + u32 m_image_count; + + dyn_array m_images; + }; + + namespace view { + class SwapChainImplementation: public GpuObjectViewImplementation { + public: + using ImageID = SwapChainInterfaceBase::ImageID; + using NextImage = SwapChainInterfaceBase::NextImage; + + SwapChainImplementation(const gpu::SwapChain& of) noexcept; + template TContainerOrPointer> + SwapChainImplementation(const TContainerOrPointer&) noexcept; + ~SwapChainImplementation() noexcept; + + SwapChainImplementation(const SwapChainImplementation&) noexcept; + auto operator=(const SwapChainImplementation&) noexcept -> SwapChainImplementation&; + + SwapChainImplementation(SwapChainImplementation&&) noexcept; + auto operator=(SwapChainImplementation&&) noexcept -> SwapChainImplementation&; + + protected: + math::uextent2 m_extent; + PixelFormat m_pixel_format; + u32 m_image_count; + + array_view m_images; + }; + } // namespace view +} // namespace stormkit::gpu + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit::gpu { + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto SwapChainInterface::pixel_format() const noexcept -> PixelFormat { + return Base::m_pixel_format; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto SwapChainInterface::images() const noexcept -> array_view { + return Base::m_images; + } + + STORMKIT_FORCE_INLINE + inline SwapChainImplementation::SwapChainImplementation(PrivateTag, view::Device&& device) noexcept + : GpuObjectImplementation { std::move(device), &VolkDeviceTable::vkDestroySwapchainKHR } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline SwapChainImplementation::~SwapChainImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline SwapChainImplementation::SwapChainImplementation(SwapChainImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto SwapChainImplementation::operator=(SwapChainImplementation&&) noexcept -> SwapChainImplementation& = default; + + namespace view { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline SwapChainImplementation::SwapChainImplementation(const gpu::SwapChain& of) noexcept + : GpuObjectViewImplementation { of }, m_pixel_format { of.pixel_format() }, m_images { of.images() } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template TContainerOrPointer> + STORMKIT_FORCE_INLINE + inline SwapChainImplementation::SwapChainImplementation(const TContainerOrPointer& of) noexcept + : SwapChainImplementation { *of } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline SwapChainImplementation::~SwapChainImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline SwapChainImplementation::SwapChainImplementation(const SwapChainImplementation&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto SwapChainImplementation::operator=(const SwapChainImplementation&) noexcept + -> SwapChainImplementation& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline SwapChainImplementation::SwapChainImplementation(SwapChainImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto SwapChainImplementation::operator=(SwapChainImplementation&&) noexcept -> SwapChainImplementation& = default; + } // namespace view +} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/execution/swapchain.mpp b/modules/stormkit/gpu/execution/swapchain.mpp deleted file mode 100644 index 10ec92de6..000000000 --- a/modules/stormkit/gpu/execution/swapchain.mpp +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright (C) 2023 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -#include - -export module stormkit.gpu.execution:swapchain; - -import std; - -import stormkit.core; -import stormkit.gpu.core; -import stormkit.gpu.resource; - -export namespace stormkit::gpu { - class STORMKIT_API SwapChain { - struct PrivateFuncTag {}; - - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::SWAPCHAIN; - - using ImageID = u32; - - struct NextImage { - Result result; - ImageID id; - }; - - static auto create(const Device& device, - const Surface& surface, - const math::Extent2& extent, - OptionalRef old_swapchain = std::nullopt) noexcept - -> Expected; - static auto allocate(const Device& device, - const Surface& surface, - const math::Extent2& extent, - OptionalRef old_swapchain = std::nullopt) noexcept - -> Expected>; - ~SwapChain(); - - SwapChain(const SwapChain&) = delete; - auto operator=(const SwapChain&) -> SwapChain& = delete; - - SwapChain(SwapChain&&) noexcept; - auto operator=(SwapChain&&) noexcept -> SwapChain&; - - [[nodiscard]] - auto pixel_format() const noexcept -> PixelFormat; - [[nodiscard]] - auto images() const noexcept -> const std::vector&; - auto acquire_next_image(std::chrono::nanoseconds wait, - const Semaphore& image_available) const noexcept - -> Expected; - - [[nodiscard]] - auto native_handle() const noexcept -> VkSwapchainKHR; - - SwapChain(const Device&, PrivateFuncTag) noexcept; - - private: - auto do_init(const Device&, - const Surface&, - const math::Extent2&, - VkSwapchainKHR) noexcept -> Expected; - - math::Extent2 m_extent; - PixelFormat m_pixel_format; - u32 m_image_count; - - VkDevice m_vk_device; - Ref m_vk_device_table; - VkRAIIHandle m_vk_handle; - std::vector m_images; - }; -} // namespace stormkit::gpu - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::gpu { - STORMKIT_FORCE_INLINE - inline SwapChain::SwapChain(const Device& device, PrivateFuncTag) noexcept - : m_vk_device { device.native_handle() }, - m_vk_device_table { as_ref(device.device_table()) }, - m_vk_handle { [vk_device_table = *m_vk_device_table, - vk_device = m_vk_device](auto&& handle) noexcept { - vk_device_table.vkDestroySwapchainKHR(vk_device, handle, nullptr); - } } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline SwapChain::~SwapChain() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline SwapChain::SwapChain(SwapChain&&) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto SwapChain::operator=(SwapChain&&) noexcept -> SwapChain& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto SwapChain::create(const Device& device, - const Surface& surface, - const math::Extent2& extent, - OptionalRef old_swapchain) noexcept - -> Expected { - auto swapchain = SwapChain { device, PrivateFuncTag {} }; - return swapchain - .do_init(device, - surface, - extent, - old_swapchain ? old_swapchain->native_handle() : nullptr) - .transform(core::monadic::consume(swapchain)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto SwapChain::allocate(const Device& device, - const Surface& surface, - const math::Extent2& extent, - OptionalRef old_swapchain) noexcept - -> Expected> { - auto swapchain = std::make_unique(device, PrivateFuncTag {}); - return swapchain - ->do_init(device, - surface, - extent, - old_swapchain ? old_swapchain->native_handle() : nullptr) - .transform(core::monadic::consume(swapchain)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto SwapChain::pixel_format() const noexcept -> PixelFormat { - return m_pixel_format; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto SwapChain::images() const noexcept -> const std::vector& { - return m_images; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto SwapChain::native_handle() const noexcept -> VkSwapchainKHR { - return m_vk_handle; - } -} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/resource.mpp b/modules/stormkit/gpu/resource.cppm similarity index 92% rename from modules/stormkit/gpu/resource.mpp rename to modules/stormkit/gpu/resource.cppm index 53629a51b..ac97f86dc 100644 --- a/modules/stormkit/gpu/resource.mpp +++ b/modules/stormkit/gpu/resource.cppm @@ -4,6 +4,7 @@ export module stormkit.gpu.resource; +export import :objects; export import :buffer; export import :image; export import :shader; diff --git a/modules/stormkit/gpu/resource/buffer.cppm b/modules/stormkit/gpu/resource/buffer.cppm new file mode 100644 index 000000000..4c729c6d4 --- /dev/null +++ b/modules/stormkit/gpu/resource/buffer.cppm @@ -0,0 +1,399 @@ +// Copyright (C) 2023 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include +#include + +#include +#include + +export module stormkit.gpu.resource:buffer; + +import std; + +import stormkit.core; +import stormkit.gpu.core; + +import :objects; + +namespace stdr = std::ranges; + +namespace cmeta = stormkit::core::meta; +namespace cmonadic = stormkit::core::monadic; + +namespace stormkit::gpu { + struct BufferInterfaceBase { + struct CreateInfo { + BufferUsageFlag usages; + usize size; + MemoryPropertyFlag properties = MemoryPropertyFlag::HOST_VISIBLE | MemoryPropertyFlag::HOST_COHERENT; + + bool persistently_mapped = false; + }; + }; + + export template + class STORMKIT_GPU_API BufferInterface final: public DeviceObject, public BufferInterfaceBase { + public: + using DeviceObject::DeviceObject; + using DeviceObject::operator=; + using TagType = BufferTag; + + BufferInterface(const BufferInterface&) noexcept + requires(cmeta::IsCopyConstructible>); + auto operator=(const BufferInterface&) noexcept -> BufferInterface& + requires(cmeta::IsCopyAssignable>); + + BufferInterface(BufferInterface&&) noexcept; + auto operator=(BufferInterface&&) noexcept -> BufferInterface&; + ~BufferInterface() noexcept; + + [[nodiscard]] + auto usages() const noexcept -> BufferUsageFlag; + [[nodiscard]] + auto size() const noexcept -> usize; + [[nodiscard]] + auto memory_properties() const noexcept -> MemoryPropertyFlag; + [[nodiscard]] + auto is_persistently_mapped() const noexcept -> bool; + + auto map(ioffset offset) noexcept -> Expected; + auto map(ioffset offset, usize size) noexcept -> Expected>; + + template + auto map_as(ioffset offset) noexcept -> Expected>; + + bool mapped() const noexcept; + + template + [[nodiscard]] + auto data(this Self& self) noexcept -> cmeta::ForwardConst*; + template + [[nodiscard]] + auto data(this Self& self, usize size) noexcept -> cmeta::If, byte_mut_view<>, byte_view<>>; + + template + [[nodiscard]] + auto data_as(this auto& self) noexcept -> ref; + + auto flush(ioffset offset, usize size) const noexcept -> Expected; + auto unmap() noexcept -> void; + + auto upload(byte_view<> data, ioffset offset = 0) noexcept -> Expected; + + template + requires(not stormkit::meta::IsStdSpan) + auto upload(const T& data, ioffset offset = 0) noexcept -> Expected; + + [[nodiscard]] + auto allocation() const noexcept -> vk::Observer; + }; + + class STORMKIT_GPU_API + BufferImplementation: public GpuObjectImplementation { + public: + using CreateInfo = BufferInterfaceBase::CreateInfo; + + BufferImplementation(PrivateTag, view::Device&&) noexcept; + ~BufferImplementation() noexcept; + + BufferImplementation(const BufferImplementation&) noexcept = delete; + auto operator=(const BufferImplementation&) noexcept -> BufferImplementation& = delete; + + BufferImplementation(BufferImplementation&&) noexcept; + auto operator=(BufferImplementation&&) noexcept -> BufferImplementation&; + + auto do_init(PrivateTag, const CreateInfo&) noexcept -> Expected; + + protected: + BufferUsageFlag m_usages = {}; + usize m_size = 0; + MemoryPropertyFlag m_memory_properties = {}; + + bool m_is_persistently_mapped = false; + byte* m_mapped_pointer = nullptr; + + vk::Owned m_vma_allocation = { cmonadic::discard() }; + }; + + namespace view { + class BufferImplementation: public GpuObjectViewImplementation { + public: + BufferImplementation(const gpu::Buffer&) noexcept; + template TContainerOrPointer> + BufferImplementation(const TContainerOrPointer&) noexcept; + ~BufferImplementation() noexcept; + + BufferImplementation(const BufferImplementation&) noexcept; + auto operator=(const BufferImplementation&) noexcept -> BufferImplementation&; + + BufferImplementation(BufferImplementation&&) noexcept; + auto operator=(BufferImplementation&&) noexcept -> BufferImplementation&; + + protected: + BufferUsageFlag m_usages = {}; + usize m_size = 0; + MemoryPropertyFlag m_memory_properties = {}; + + bool m_is_persistently_mapped = false; + byte* m_mapped_pointer = nullptr; + + vk::Observer m_vma_allocation; + }; + } // namespace view + + export { + struct BufferMemoryBarrier { + AccessFlag src; + AccessFlag dst; + + u32 src_queue_family_index = QUEUE_FAMILY_IGNORED; + u32 dst_queue_family_index = QUEUE_FAMILY_IGNORED; + + view::Buffer buffer; + usize size; + u64 offset = 0; + }; + + template + constexpr auto hasher(const Buffer::CreateInfo& value) noexcept -> Ret; + } +} // namespace stormkit::gpu + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit::gpu { + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline BufferInterface::BufferInterface(const BufferInterface& other) noexcept + requires(cmeta::IsCopyConstructible>) + : DeviceObject { other } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto BufferInterface::operator=(const BufferInterface& other) noexcept -> BufferInterface& + requires(cmeta::IsCopyAssignable>) + = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline BufferInterface::BufferInterface(BufferInterface&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto BufferInterface::operator=(BufferInterface&&) noexcept -> BufferInterface& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline BufferInterface::~BufferInterface() noexcept { + if (allocation()) unmap(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto BufferInterface::usages() const noexcept -> BufferUsageFlag { + EXPECTS(Base::m_vma_allocation and Base::m_vk_handle); + return Base::m_usages; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto BufferInterface::size() const noexcept -> usize { + EXPECTS(Base::m_vma_allocation and Base::m_vk_handle); + return Base::m_size; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto BufferInterface::memory_properties() const noexcept -> MemoryPropertyFlag { + return Base::m_memory_properties; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto BufferInterface::is_persistently_mapped() const noexcept -> bool { + return Base::m_is_persistently_mapped; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto BufferInterface::map(ioffset offset, usize size) noexcept -> Expected> { + auto ptr = Try(map(offset)); + Return as_bytes_mut(ptr, size); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + template + STORMKIT_FORCE_INLINE + inline auto BufferInterface::map_as(ioffset offset) noexcept -> Expected> { + const auto ptr = Try(map(offset)); + Return from_bytes_mut(ptr); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto BufferInterface::mapped() const noexcept -> bool { + return Base::m_mapped_pointer != nullptr; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + template + STORMKIT_FORCE_INLINE + inline auto BufferInterface::data(this Self& self) noexcept -> cmeta::ForwardConst* { + EXPECTS(self.m_vma_allocation and self.m_vk_handle); + EXPECTS(self.m_mapped_pointer); + + using Out = cmeta::ForwardConst*; + return std::bit_cast(self.m_mapped_pointer); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + template + STORMKIT_FORCE_INLINE + inline auto BufferInterface::data(this Self& self, usize size) noexcept + -> cmeta::If, byte_mut_view<>, byte_view<>> { + using Out = array_view>; + return Out { std::bit_cast(self.data()), size }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + template + STORMKIT_FORCE_INLINE + inline auto BufferInterface::data_as(this Self& self) noexcept -> ref { + using Type = cmeta::ForwardConst*; + return as_ref_like(std::bit_cast(self.data())); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + template + requires(not stormkit::meta::IsStdSpan) + STORMKIT_FORCE_INLINE + inline auto BufferInterface::upload(const T& data, ioffset offset) noexcept -> Expected { + const auto bytes = as_bytes(data); + return upload(bytes, offset); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto BufferInterface::allocation() const noexcept -> vk::Observer { + return Base::m_vma_allocation; + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline BufferImplementation::BufferImplementation(PrivateTag, view::Device&& device) noexcept + : GpuObjectImplementation { std::move(device), &VolkDeviceTable::vkDestroyBuffer } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline BufferImplementation::~BufferImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline BufferImplementation::BufferImplementation(BufferImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto BufferImplementation::operator=(BufferImplementation&&) noexcept -> BufferImplementation& = default; + + namespace view { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline BufferImplementation::BufferImplementation(const gpu::Buffer& of) noexcept + : GpuObjectViewImplementation { of }, + m_usages { of.usages() }, + m_size { of.size() }, + m_memory_properties { of.memory_properties() }, + m_is_persistently_mapped { of.is_persistently_mapped() }, + m_mapped_pointer { nullptr }, + m_vma_allocation { of.allocation() } { + if (of.is_persistently_mapped()) m_mapped_pointer = std::bit_cast(of.data()); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template TContainerOrPointer> + STORMKIT_FORCE_INLINE + inline BufferImplementation::BufferImplementation(const TContainerOrPointer& of) noexcept + : BufferImplementation { *of } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline BufferImplementation::~BufferImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline BufferImplementation::BufferImplementation(const BufferImplementation&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto BufferImplementation::operator=(const BufferImplementation&) noexcept -> BufferImplementation& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline BufferImplementation::BufferImplementation(BufferImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto BufferImplementation::operator=(BufferImplementation&&) noexcept -> BufferImplementation& = default; + } // namespace view + + /////////////////////////////////// + /////////////////////////////////// + template + constexpr auto hasher(const Buffer::CreateInfo& create_info) noexcept -> Ret { + return hash(create_info.usages, create_info.size, create_info.properties); + } +} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/resource/buffer.mpp b/modules/stormkit/gpu/resource/buffer.mpp deleted file mode 100644 index dea610bc0..000000000 --- a/modules/stormkit/gpu/resource/buffer.mpp +++ /dev/null @@ -1,339 +0,0 @@ -// Copyright (C) 2023 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include -#include - -#include - -export module stormkit.gpu.resource:buffer; - -import std; - -import stormkit.core; -import stormkit.gpu.core; - -namespace stdr = std::ranges; - -export namespace stormkit::gpu { - class STORMKIT_API Buffer { - struct PrivateFuncTag {}; - - public: - struct CreateInfo { - BufferUsageFlag usages; - usize size; - MemoryPropertyFlag property = MemoryPropertyFlag::HOST_VISIBLE - | MemoryPropertyFlag::HOST_COHERENT; - }; - - static constexpr auto DEBUG_TYPE = DebugObjectType::BUFFER; - - ~Buffer(); - - Buffer(const Buffer&) = delete; - auto operator=(const Buffer&) -> Buffer& = delete; - - Buffer(Buffer&&) noexcept; - auto operator=(Buffer&&) noexcept -> Buffer&; - - static auto create(const Device& device, - const CreateInfo& info, - bool persistently_mapped = false) noexcept -> Expected; - static auto allocate(const Device& device, - const CreateInfo& info, - bool persistently_mapped = false) noexcept -> Expected>; - - [[nodiscard]] - auto usages() const noexcept -> BufferUsageFlag; - [[nodiscard]] - auto size() const noexcept -> usize; - [[nodiscard]] - auto memory_property() const noexcept -> MemoryPropertyFlag; - - auto map(ioffset offset) noexcept -> Expected; - auto map(ioffset offset, usize size) noexcept -> Expected; - - template - auto map_as(ioffset offset) noexcept -> Expected>; - - template - [[nodiscard]] - auto data(this Self& self) noexcept -> core::meta::ForwardConst*; - template - [[nodiscard]] - auto data(this Self& self, usize size) noexcept - -> core::meta::If, ByteView, MutableByteView>; - - template - [[nodiscard]] - auto data_as(this auto& self) noexcept -> Ref; - - auto flush(ioffset offset, usize size) noexcept -> Expected; - auto unmap() noexcept -> void; - - [[nodiscard]] - auto is_persistently_mapped() const noexcept -> bool; - - auto upload(std::span data, ioffset offset = 0) noexcept -> Expected; - - template T> - auto upload(const T& data, ioffset offset = 0) noexcept -> Expected; - - [[nodiscard]] - auto native_handle() const noexcept -> VkBuffer; - - Buffer(const Device& device, - const CreateInfo& info, - bool persistently_mapping, - PrivateFuncTag) noexcept; - - private: - static auto find_memory_type(u32, - VkMemoryPropertyFlagBits, - const VkPhysicalDeviceMemoryProperties&, - const VkMemoryRequirements&) noexcept -> u32; - - auto do_init(MemoryPropertyFlag memory_properties) noexcept -> Expected; - - BufferUsageFlag m_usages = {}; - usize m_size = 0; - MemoryPropertyFlag m_memory_property = {}; - - bool m_is_persistently_mapped = false; - Byte* m_mapped_pointer = nullptr; - - VkDevice m_vk_device; - Ref m_vk_device_table; - VmaAllocator m_vma_allocator; - VkRAIIHandle m_vma_allocation = { [](auto) static noexcept {} }; - VkRAIIHandle m_vk_handle; - }; - - struct BufferMemoryBarrier { - AccessFlag src; - AccessFlag dst; - - u32 src_queue_family_index = QUEUE_FAMILY_IGNORED; - u32 dst_queue_family_index = QUEUE_FAMILY_IGNORED; - - const Buffer& buffer; - usize size; - u64 offset = 0; - }; -} // namespace stormkit::gpu - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::gpu { - ///////////////////////////////////// - ///////////////////////////////////// - inline Buffer::Buffer(const Device& device, - const CreateInfo& info, - bool persistently_mapped, - PrivateFuncTag) noexcept - : m_usages { info.usages }, m_size { info.size }, m_memory_property { info.property }, - m_is_persistently_mapped { persistently_mapped }, m_vk_device { device.native_handle() }, - m_vk_device_table { as_ref(device.device_table()) }, - m_vma_allocator { device.allocator() }, - m_vk_handle { [vk_device_table = *m_vk_device_table, - vk_device = m_vk_device](auto handle) noexcept { - vk_device_table.vkDestroyBuffer(vk_device, handle, nullptr); - } } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Buffer::~Buffer() { - if (m_vma_allocation and m_mapped_pointer) { - vk_call(vmaUnmapMemory, m_vma_allocator, m_vma_allocation); - - m_mapped_pointer = nullptr; - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Buffer::Buffer(Buffer&& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Buffer::operator=(Buffer&& other) noexcept -> Buffer& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Buffer::create(const Device& device, - const CreateInfo& info, - bool persistently_mapped) noexcept -> Expected { - auto buffer = Buffer { device, info, persistently_mapped, PrivateFuncTag {} }; - return buffer.do_init(info.property).transform(core::monadic::consume(buffer)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Buffer::allocate(const Device& device, - const CreateInfo& info, - bool persistently_mapped) noexcept -> Expected> { - auto - buffer = std::make_unique(device, info, persistently_mapped, PrivateFuncTag {}); - return buffer->do_init(info.property).transform(core::monadic::consume(buffer)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Buffer::usages() const noexcept -> BufferUsageFlag { - EXPECTS(m_vma_allocation and m_vk_handle); - return m_usages; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Buffer::size() const noexcept -> usize { - EXPECTS(m_vma_allocation and m_vk_handle); - return m_size; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Buffer::map(ioffset offset) noexcept -> Expected { - EXPECTS(m_vma_allocation and m_vk_handle); - EXPECTS(offset < as(m_size)); - - return vk_call(vmaMapMemory, m_vma_allocator, m_vma_allocation) - .transform([this, &offset](auto&& ptr) noexcept { - m_mapped_pointer = std::bit_cast(ptr); - m_mapped_pointer += offset; - return m_mapped_pointer; - }) - .transform_error(monadic::from_vk()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Buffer::map(ioffset offset, usize size) noexcept -> Expected { - EXPECTS(m_vma_allocation and m_vk_handle); - return map(offset).transform([&size](auto&& ptr) noexcept { return as_bytes(ptr, size); }); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - inline auto Buffer::map_as(ioffset offset) noexcept -> Expected> { - EXPECTS(m_vma_allocation and m_vk_handle); - - return map(offset) - .transform([](auto&& ptr) static noexcept { return std::bit_cast(ptr); }) - .transform(core::monadic::as_ref_mut); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - inline auto Buffer::data(this Self& self) noexcept -> core::meta::ForwardConst* { - EXPECTS(self.m_vma_allocation and self.m_vk_handle); - EXPECTS(self.m_mapped_pointer); - - using Out = core::meta::ForwardConst*; - return std::bit_cast(self.m_mapped_pointer); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - inline auto Buffer::data(this Self& self, usize size) noexcept - -> core::meta::If, ByteView, MutableByteView> { - EXPECTS(self.m_vma_allocation and self.m_vk_handle); - EXPECTS(self.m_mapped_pointer); - - using Out = core::meta::If, ByteView, MutableByteView>; - return Out { std::bit_cast(self.m_mapped_pointer), size }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - inline auto Buffer::data_as(this Self& self) noexcept -> Ref { - EXPECTS(self.m_vma_allocation and self.m_vk_handle); - EXPECTS(self.m_mapped_pointer); - - using Type = core::meta::ForwardConst*; - return as_ref_like(std::bit_cast(self.data())); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Buffer::flush(ioffset offset, usize size) noexcept -> Expected { - EXPECTS(m_vma_allocation and m_vk_handle); - EXPECTS(offset <= as(m_size)); - EXPECTS(size <= m_size); - - return vk_call(vmaFlushAllocation, m_vma_allocator, m_vma_allocation, offset, size) - .transform_error(monadic::from_vk()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Buffer::unmap() noexcept -> void { - EXPECTS(m_vma_allocation and m_vk_handle); - expects(not m_is_persistently_mapped, "unmapping persistent buffer !"); - - vk_call(vmaUnmapMemory, m_vma_allocator, m_vma_allocation); - - m_mapped_pointer = nullptr; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Buffer::upload(std::span data, ioffset offset) noexcept - -> Expected { - EXPECTS(stdr::size(data) <= m_size); - - if (m_is_persistently_mapped) { - std::ranges::copy(data, m_mapped_pointer); - return {}; - } - - return map(offset, std::ranges::size(data)).transform([this, &data](auto&& out) noexcept { - std::ranges::copy(data, std::ranges::begin(out)); - unmap(); - }); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template T> - STORMKIT_FORCE_INLINE - inline auto Buffer::upload(const T& data, ioffset offset) noexcept -> Expected { - const auto bytes = as_bytes(data); - return upload(bytes, offset); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Buffer::native_handle() const noexcept -> VkBuffer { - EXPECTS(m_vk_handle); - return m_vk_handle; - } -} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/resource/image.cppm b/modules/stormkit/gpu/resource/image.cppm new file mode 100644 index 000000000..d8fc2d5cb --- /dev/null +++ b/modules/stormkit/gpu/resource/image.cppm @@ -0,0 +1,646 @@ +// Copyright (C) 2023 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include + +#include +#include + +export module stormkit.gpu.resource:image; + +import std; + +import stormkit.core; +import stormkit.image; +import stormkit.gpu.core; + +import :objects; + +namespace cmeta = stormkit::core::meta; +namespace cmonadic = stormkit::core::monadic; + +namespace stormkit::gpu { + struct SamplerInterfaceBase { + struct Settings { + Filter mag_filter = Filter::LINEAR; + Filter min_filter = Filter::LINEAR; + + SamplerAddressMode address_mode_u = SamplerAddressMode::REPEAT; + SamplerAddressMode address_mode_v = SamplerAddressMode::REPEAT; + SamplerAddressMode address_mode_w = SamplerAddressMode::REPEAT; + + bool enable_anisotropy = false; + f32 max_anisotropy = 0.f; + + BorderColor border_color = BorderColor::INT_OPAQUE_BLACK; + + bool unnormalized_coordinates = false; + + bool compare_enable = false; + CompareOperation compare_operation = CompareOperation::ALWAYS; + + SamplerMipmapMode mipmap_mode = SamplerMipmapMode::LINEAR; + f32 mip_lod_bias = 0.f; + + f32 min_lod = 0.f; + f32 max_lod = 0.f; + }; + }; + + struct ImageInterfaceBase { + struct CreateInfo { + math::uextent3 extent; + PixelFormat format = PixelFormat::RGBA8_UNORM; + u32 layers = 1u; + u32 mip_levels = 1u; + ImageType type = ImageType::T2D; + ImageCreateFlag flags = ImageCreateFlag::NONE; + SampleCountFlag samples = SampleCountFlag::C1; + ImageUsageFlag usages = ImageUsageFlag::SAMPLED | ImageUsageFlag::TRANSFER_DST | ImageUsageFlag::TRANSFER_SRC; + ImageTiling tiling = ImageTiling::OPTIMAL; + MemoryPropertyFlag properties = MemoryPropertyFlag::DEVICE_LOCAL; + }; + }; + + export { + template + class SamplerInterface: public DeviceObject, public SamplerInterfaceBase { + public: + using DeviceObject::DeviceObject; + using DeviceObject::operator=; + using TagType = SamplerTag; + + [[nodiscard]] + auto settings() const noexcept -> const Settings&; + }; + + template + class ImageInterface: public DeviceObject, public ImageInterfaceBase { + public: + using DeviceObject::DeviceObject; + using DeviceObject::operator=; + using TagType = ImageTag; + + [[nodiscard]] + auto extent() const noexcept -> const math::uextent3&; + [[nodiscard]] + auto format() const noexcept -> PixelFormat; + [[nodiscard]] + auto type() const noexcept -> ImageType; + [[nodiscard]] + auto samples() const noexcept -> SampleCountFlag; + [[nodiscard]] + auto layers() const noexcept -> u32; + [[nodiscard]] + auto faces() const noexcept -> u32; + [[nodiscard]] + auto mip_levels() const noexcept -> u32; + [[nodiscard]] + auto usages() const noexcept -> ImageUsageFlag; + [[nodiscard]] + auto allocation() const noexcept -> vk::Observer; + }; + } + + class STORMKIT_GPU_API ImageImplementation: public GpuObjectImplementation { + public: + using CreateInfo = ImageInterfaceBase::CreateInfo; + + ImageImplementation(PrivateTag, view::Device&&) noexcept; + ~ImageImplementation() noexcept; + + ImageImplementation(const ImageImplementation&) noexcept = delete; + auto operator=(const ImageImplementation&) noexcept -> ImageImplementation& = delete; + + ImageImplementation(ImageImplementation&&) noexcept; + auto operator=(ImageImplementation&&) noexcept -> ImageImplementation&; + + static auto from_existing(view::Device device, const CreateInfo& create_info, VkImage image) noexcept -> Image; + + auto do_init(PrivateTag, const CreateInfo&) noexcept -> Expected; + + protected: + bool m_no_delete = false; + + math::uextent3 m_extent = { 0, 0, 0 }; + PixelFormat m_format = {}; + u32 m_layers = 0; + u32 m_faces = 0; + u32 m_mip_levels = 0; + ImageType m_type = {}; + ImageCreateFlag m_flags = {}; + SampleCountFlag m_samples = {}; + ImageUsageFlag m_usages = {}; + + vk::Owned m_vma_allocation = { cmonadic::discard() }; + + friend class view::ImageImplementation; + }; + + namespace view { + class ImageImplementation: public GpuObjectViewImplementation { + public: + ImageImplementation(const gpu::Image&) noexcept; + template TContainerOrPointer> + ImageImplementation(const TContainerOrPointer&) noexcept; + ~ImageImplementation() noexcept; + + ImageImplementation(const ImageImplementation&) noexcept; + auto operator=(const ImageImplementation&) noexcept -> ImageImplementation&; + + ImageImplementation(ImageImplementation&&) noexcept; + auto operator=(ImageImplementation&&) noexcept -> ImageImplementation&; + + protected: + math::uextent3 m_extent = { 0, 0, 0 }; + PixelFormat m_format = {}; + u32 m_layers = 0; + u32 m_faces = 0; + u32 m_mip_levels = 0; + ImageType m_type = {}; + STORMKIT_PUSH_WARNINGS +#pragma clang diagnostic ignored "-Wunused-private-field" + ImageCreateFlag m_flags = {}; + STORMKIT_POP_WARNINGS + SampleCountFlag m_samples = {}; + ImageUsageFlag m_usages = {}; + + vk::Observer m_vma_allocation = VK_NULL_HANDLE; + }; + } // namespace view + + struct ImageViewInterfaceBase { + struct CreateInfo { + view::Image image; + ImageViewType type = ImageViewType::T2D; + ImageSubresourceRange subresource_range = {}; + }; + }; + + export template + class ImageViewInterface: public DeviceObject, public ImageViewInterfaceBase { + public: + using CreateInfo = ImageViewInterfaceBase::CreateInfo; + + using DeviceObject::DeviceObject; + using DeviceObject::operator=; + using TagType = ImageViewTag; + + [[nodiscard]] + auto type() const noexcept -> ImageViewType; + [[nodiscard]] + auto subresource_range() const noexcept -> const ImageSubresourceRange&; + }; + + class STORMKIT_GPU_API + SamplerImplementation: public GpuObjectImplementation { + public: + using Settings = SamplerInterfaceBase::Settings; + + SamplerImplementation(PrivateTag, view::Device&&) noexcept; + ~SamplerImplementation() noexcept; + + SamplerImplementation(const SamplerImplementation&) noexcept = delete; + auto operator=(const SamplerImplementation&) noexcept -> SamplerImplementation& = delete; + + SamplerImplementation(SamplerImplementation&&) noexcept; + auto operator=(SamplerImplementation&&) noexcept -> SamplerImplementation&; + + auto do_init(PrivateTag, const Settings&) noexcept -> Expected; + + protected: + Settings m_settings = {}; + }; + + namespace view { + class SamplerImplementation: public GpuObjectViewImplementation { + public: + using Settings = SamplerInterfaceBase::Settings; + + SamplerImplementation(const gpu::Sampler&) noexcept; + template TContainerOrPointer> + SamplerImplementation(const TContainerOrPointer&) noexcept; + ~SamplerImplementation() noexcept; + + SamplerImplementation(const SamplerImplementation&) noexcept; + auto operator=(const SamplerImplementation&) noexcept -> SamplerImplementation&; + + SamplerImplementation(SamplerImplementation&&) noexcept; + auto operator=(SamplerImplementation&&) noexcept -> SamplerImplementation&; + + protected: + Settings m_settings; + }; + } // namespace view + + class STORMKIT_GPU_API + ImageViewImplementation: public GpuObjectImplementation { + public: + using CreateInfo = ImageViewInterfaceBase::CreateInfo; + + ImageViewImplementation(PrivateTag, view::Device&&) noexcept; + ~ImageViewImplementation() noexcept; + + ImageViewImplementation(const ImageViewImplementation&) noexcept = delete; + auto operator=(const ImageViewImplementation&) noexcept -> ImageViewImplementation& = delete; + + ImageViewImplementation(ImageViewImplementation&&) noexcept; + auto operator=(ImageViewImplementation&&) noexcept -> ImageViewImplementation&; + + auto do_init(PrivateTag, const CreateInfo&) noexcept -> Expected; + + protected: + ImageViewType m_type = {}; + ImageSubresourceRange m_subresource_range = {}; + }; + + namespace view { + class ImageViewImplementation: public GpuObjectViewImplementation { + public: + ImageViewImplementation(const gpu::ImageView&) noexcept; + template TContainerOrPointer> + ImageViewImplementation(const TContainerOrPointer&) noexcept; + ~ImageViewImplementation() noexcept; + + ImageViewImplementation(const ImageViewImplementation&) noexcept; + auto operator=(const ImageViewImplementation&) noexcept -> ImageViewImplementation&; + + ImageViewImplementation(ImageViewImplementation&&) noexcept; + auto operator=(ImageViewImplementation&&) noexcept -> ImageViewImplementation&; + + protected: + ImageViewType m_type = {}; + ImageSubresourceRange m_subresource_range = {}; + }; + } // namespace view + + export { + struct ImageMemoryBarrier { + AccessFlag src; + AccessFlag dst; + + ImageLayout old_layout; + ImageLayout new_layout; + + u32 src_queue_family_index = QUEUE_FAMILY_IGNORED; + u32 dst_queue_family_index = QUEUE_FAMILY_IGNORED; + + view::Image image; + ImageSubresourceRange range; + }; + + template + constexpr auto hasher(const Image::CreateInfo& value) noexcept -> Ret; + } +} // namespace stormkit::gpu + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit::gpu { + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto SamplerInterface::settings() const noexcept -> const Settings& { + return Base::m_settings; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto ImageInterface::extent() const noexcept -> const math::uextent3& { + return Base::m_extent; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto ImageInterface::format() const noexcept -> PixelFormat { + return Base::m_format; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto ImageInterface::type() const noexcept -> ImageType { + return Base::m_type; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto ImageInterface::samples() const noexcept -> SampleCountFlag { + return Base::m_samples; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto ImageInterface::layers() const noexcept -> u32 { + return Base::m_layers; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto ImageInterface::faces() const noexcept -> u32 { + return Base::m_faces; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto ImageInterface::mip_levels() const noexcept -> u32 { + return Base::m_mip_levels; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto ImageInterface::usages() const noexcept -> ImageUsageFlag { + return Base::m_usages; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto ImageInterface::allocation() const noexcept -> vk::Observer { + EXPECTS(Base::m_vma_allocation != VK_NULL_HANDLE); + return Base::m_vma_allocation; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto ImageViewInterface::type() const noexcept -> ImageViewType { + return Base::m_type; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto ImageViewInterface::subresource_range() const noexcept -> const ImageSubresourceRange& { + return Base::m_subresource_range; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline SamplerImplementation::SamplerImplementation(PrivateTag, view::Device&& device) noexcept + : GpuObjectImplementation { std::move(device), &VolkDeviceTable::vkDestroySampler } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline SamplerImplementation::~SamplerImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline SamplerImplementation::SamplerImplementation(SamplerImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto SamplerImplementation::operator=(SamplerImplementation&&) noexcept -> SamplerImplementation& = default; + + namespace view { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline SamplerImplementation::SamplerImplementation(const gpu::Sampler& of) noexcept + : GpuObjectViewImplementation { of }, m_settings { of.settings() } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template TContainerOrPointer> + STORMKIT_FORCE_INLINE + inline SamplerImplementation::SamplerImplementation(const TContainerOrPointer& of) noexcept + : SamplerImplementation { *of } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline SamplerImplementation::~SamplerImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline SamplerImplementation::SamplerImplementation(const SamplerImplementation&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto SamplerImplementation::operator=(const SamplerImplementation&) noexcept -> SamplerImplementation& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline SamplerImplementation::SamplerImplementation(SamplerImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto SamplerImplementation::operator=(SamplerImplementation&&) noexcept -> SamplerImplementation& = default; + } // namespace view + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline ImageImplementation::ImageImplementation(PrivateTag, view::Device&& device) noexcept + : GpuObjectImplementation { std::move(device), &VolkDeviceTable::vkDestroyImage } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline ImageImplementation::~ImageImplementation() noexcept { + if (m_no_delete) [[unlikely]] + m_vk_handle = VK_NULL_HANDLE; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline ImageImplementation::ImageImplementation(ImageImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto ImageImplementation::operator=(ImageImplementation&&) noexcept -> ImageImplementation& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto ImageImplementation::from_existing(view::Device device, const CreateInfo& create_info, VkImage vk_image) noexcept + -> Image { + auto image = Image { NamedConstructor::PRIVATE, std::move(device) }; + image.m_extent = create_info.extent; + image.m_format = create_info.format; + image.m_layers = create_info.layers; + image.m_faces = 1; + image.m_mip_levels = create_info.mip_levels; + image.m_type = create_info.type; + image.m_flags = create_info.flags; + image.m_samples = create_info.samples; + image.m_usages = create_info.usages; + + image.m_vma_allocation = { core::monadic::noop() }; + image.m_vk_handle = std::move(vk_image); + image.m_no_delete = true; + + return image; + } + + namespace view { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline ImageImplementation::ImageImplementation(const gpu::Image& of) noexcept + : GpuObjectViewImplementation { of }, + m_extent { of.extent() }, + m_format { of.format() }, + m_layers { of.layers() }, + m_faces { of.faces() }, + m_mip_levels { of.mip_levels() }, + m_type { of.type() }, + m_flags { of.m_flags }, + m_samples { of.samples() }, + m_usages { of.usages() } { + if (not of.m_no_delete) m_vma_allocation = of.allocation(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template TContainerOrPointer> + STORMKIT_FORCE_INLINE + inline ImageImplementation::ImageImplementation(const TContainerOrPointer& of) noexcept + : ImageImplementation { *of } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline ImageImplementation::~ImageImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline ImageImplementation::ImageImplementation(const ImageImplementation&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto ImageImplementation::operator=(const ImageImplementation&) noexcept -> ImageImplementation& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline ImageImplementation::ImageImplementation(ImageImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto ImageImplementation::operator=(ImageImplementation&&) noexcept -> ImageImplementation& = default; + } // namespace view + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline ImageViewImplementation::ImageViewImplementation(PrivateTag, view::Device&& device) noexcept + : GpuObjectImplementation { std::move(device), &VolkDeviceTable::vkDestroyImageView } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline ImageViewImplementation::~ImageViewImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline ImageViewImplementation::ImageViewImplementation(ImageViewImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto ImageViewImplementation::operator=(ImageViewImplementation&&) noexcept -> ImageViewImplementation& = default; + + namespace view { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline ImageViewImplementation::ImageViewImplementation(const gpu::ImageView& of) noexcept + : GpuObjectViewImplementation { of }, m_type { of.type() }, m_subresource_range { of.subresource_range() } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template TContainerOrPointer> + STORMKIT_FORCE_INLINE + inline ImageViewImplementation::ImageViewImplementation(const TContainerOrPointer& of) noexcept + : ImageViewImplementation { *of } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline ImageViewImplementation::~ImageViewImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline ImageViewImplementation::ImageViewImplementation(const ImageViewImplementation&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto ImageViewImplementation::operator=(const ImageViewImplementation&) noexcept + -> ImageViewImplementation& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline ImageViewImplementation::ImageViewImplementation(ImageViewImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto ImageViewImplementation::operator=(ImageViewImplementation&&) noexcept -> ImageViewImplementation& = default; + } // namespace view + + ///////////////////////////////////// + ///////////////////////////////////// + template + constexpr auto hasher(const Image::CreateInfo& create_info) noexcept -> Ret { + return hash(create_info.extent, + create_info.format, + create_info.layers, + create_info.mip_levels, + create_info.type, + create_info.flags, + create_info.samples, + create_info.usages, + create_info.tiling, + create_info.properties); + } +} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/resource/image.mpp b/modules/stormkit/gpu/resource/image.mpp deleted file mode 100644 index cfc4c3848..000000000 --- a/modules/stormkit/gpu/resource/image.mpp +++ /dev/null @@ -1,587 +0,0 @@ -// Copyright (C) 2023 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include -#include - -#include - -export module stormkit.gpu.resource:image; - -import std; - -import stormkit.core; -import stormkit.image; -import stormkit.gpu.core; - -export namespace stormkit::gpu { - class STORMKIT_API Sampler { - struct PrivateFuncTag {}; - - public: - struct Settings { - Filter mag_filter = Filter::LINEAR; - Filter min_filter = Filter::LINEAR; - - SamplerAddressMode address_mode_u = SamplerAddressMode::REPEAT; - SamplerAddressMode address_mode_v = SamplerAddressMode::REPEAT; - SamplerAddressMode address_mode_w = SamplerAddressMode::REPEAT; - - bool enable_anisotropy = false; - float max_anisotropy = 0.f; - - BorderColor border_color = BorderColor::INT_OPAQUE_BLACK; - - bool unnormalized_coordinates = false; - - bool compare_enable = false; - CompareOperation compare_operation = CompareOperation::ALWAYS; - - SamplerMipmapMode mipmap_mode = SamplerMipmapMode::LINEAR; - float mip_lod_bias = 0.f; - - float min_lod = 0.f; - float max_lod = 0.f; - }; - - static constexpr auto DEBUG_TYPE = DebugObjectType::SAMPLER; - - static auto create(const Device& device, const Settings& settings) noexcept - -> Expected; - static auto allocate(const Device& device, const Settings& settings) noexcept - -> Expected>; - ~Sampler(); - - Sampler(const Sampler&) = delete; - auto operator=(const Sampler&) -> Sampler& = delete; - - Sampler(Sampler&&) noexcept; - auto operator=(Sampler&&) noexcept -> Sampler&; - - [[nodiscard]] - auto settings() const noexcept -> const Settings&; - - [[nodiscard]] - auto native_handle() const noexcept -> VkSampler; - - Sampler(const Device& device, const Settings& settings, PrivateFuncTag) noexcept; - - private: - auto do_init() noexcept -> Expected; - - Settings m_settings = {}; - - VkDevice m_vk_device = nullptr; - Ref m_vk_device_table; - VkRAIIHandle m_vk_handle; - }; - - class Image; - - class STORMKIT_API ImageView { - struct PrivateFuncTag {}; - - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::IMAGE_VIEW; - - static auto create(const Device& device, - const Image& image, - ImageViewType type = ImageViewType::T2D, - const ImageSubresourceRange& subresource_range = {}) noexcept - -> Expected; - static auto allocate(const Device& device, - const Image& image, - ImageViewType type = ImageViewType::T2D, - const ImageSubresourceRange& subresource_range = {}) noexcept - -> Expected>; - ~ImageView(); - - ImageView(const ImageView&) = delete; - auto operator=(const ImageView&) -> ImageView& = delete; - - ImageView(ImageView&&) noexcept; - auto operator=(ImageView&&) noexcept -> ImageView&; - - [[nodiscard]] - auto type() const noexcept -> ImageViewType; - [[nodiscard]] - auto subresource_range() const noexcept -> const ImageSubresourceRange&; - - [[nodiscard]] - auto native_handle() const noexcept -> VkImageView; - - ImageView(const Device&, - ImageViewType, - const ImageSubresourceRange&, - PrivateFuncTag) noexcept; - - private: - auto do_init(const Image&) noexcept -> Expected; - - ImageViewType m_type = {}; - ImageSubresourceRange m_subresource_range = {}; - - VkDevice m_vk_device = nullptr; - Ref m_vk_device_table; - VkRAIIHandle m_vk_handle; - }; - - class STORMKIT_API Image { - struct PrivateFuncTag {}; - - public: - struct CreateInfo { - math::Extent3 extent; - PixelFormat format = PixelFormat::RGBA8_UNORM; - u32 layers = 1u; - u32 mip_levels = 1u; - ImageType type = ImageType::T2D; - ImageCreateFlag flags = ImageCreateFlag::NONE; - SampleCountFlag samples = SampleCountFlag::C1; - ImageUsageFlag usages = ImageUsageFlag::SAMPLED - | ImageUsageFlag::TRANSFER_DST - | ImageUsageFlag::TRANSFER_SRC; - ImageTiling tiling = ImageTiling::OPTIMAL; - MemoryPropertyFlag property = MemoryPropertyFlag::DEVICE_LOCAL; - }; - - static constexpr auto DEBUG_TYPE = DebugObjectType::IMAGE; - - static auto create(const Device& device, const CreateInfo& info) noexcept - -> Expected; - static auto allocate(const Device& device, const CreateInfo& create_info) noexcept - -> Expected>; - ~Image(); - - Image(const Image&) = delete; - auto operator=(const Image&) -> Image& = delete; - - Image(Image&&) noexcept; - auto operator=(Image&&) noexcept -> Image&; - - [[nodiscard]] - auto extent() const noexcept -> const math::Extent3&; - [[nodiscard]] - auto format() const noexcept -> PixelFormat; - [[nodiscard]] - auto type() const noexcept -> ImageType; - [[nodiscard]] - auto samples() const noexcept -> SampleCountFlag; - [[nodiscard]] - auto layers() const noexcept -> u32; - [[nodiscard]] - auto faces() const noexcept -> u32; - [[nodiscard]] - auto mip_levels() const noexcept -> u32; - [[nodiscard]] - auto usages() const noexcept -> ImageUsageFlag; - - [[nodiscard]] - auto native_handle() const noexcept -> VkImage; - - Image(const Device&, const CreateInfo&, PrivateFuncTag) noexcept; - - [[nodiscard]] - static auto create(const Device&, const CreateInfo&, VkImage&&) noexcept -> Image; - - private: - auto do_init(const CreateInfo&) noexcept -> Expected; - auto do_init(const VkImageCreateInfo&, MemoryPropertyFlag) noexcept -> Expected; - - math::Extent3 m_extent = { 0, 0, 0 }; - PixelFormat m_format = {}; - u32 m_layers = 0; - u32 m_faces = 0; - u32 m_mip_levels = 0; - ImageType m_type = {}; - ImageCreateFlag m_flags = {}; - SampleCountFlag m_samples = {}; - ImageUsageFlag m_usages = {}; - - VkDevice m_vk_device = nullptr; - Ref m_vk_device_table; - VmaAllocator m_vma_allocator = nullptr; - VkRAIIHandle m_vma_allocation = { [](auto) static noexcept {} }; - VkRAIIHandle m_vk_handle; - }; - - struct ImageMemoryBarrier { - AccessFlag src; - AccessFlag dst; - - ImageLayout old_layout; - ImageLayout new_layout; - - u32 src_queue_family_index = QUEUE_FAMILY_IGNORED; - u32 dst_queue_family_index = QUEUE_FAMILY_IGNORED; - - const Image& image; - ImageSubresourceRange range; - }; -} // namespace stormkit::gpu - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::gpu { - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Sampler::do_init() noexcept -> Expected { - const auto create_info = VkSamplerCreateInfo { - .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .magFilter = to_vk(m_settings.mag_filter), - .minFilter = to_vk(m_settings.min_filter), - .mipmapMode = to_vk(m_settings.mipmap_mode), - .addressModeU = to_vk(m_settings.address_mode_u), - .addressModeV = to_vk(m_settings.address_mode_v), - .addressModeW = to_vk(m_settings.address_mode_w), - .mipLodBias = m_settings.mip_lod_bias, - .anisotropyEnable = m_settings.enable_anisotropy, - .maxAnisotropy = m_settings.max_anisotropy, - .compareEnable = m_settings.compare_enable, - .compareOp = to_vk(m_settings.compare_operation), - .minLod = m_settings.min_lod, - .maxLod = m_settings.max_lod, - .borderColor = to_vk(m_settings.border_color), - .unnormalizedCoordinates = m_settings.unnormalized_coordinates - }; - return vk_call(m_vk_device_table->vkCreateSampler, - m_vk_device, - &create_info, - nullptr) - .transform(core::monadic::set(m_vk_handle)) - .transform_error(monadic::from_vk()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Sampler::Sampler(const Device& device, const Settings& settings, PrivateFuncTag) noexcept - : m_settings { settings }, m_vk_device { device.native_handle() }, - m_vk_device_table { as_ref(device.device_table()) }, - m_vk_handle { [vk_device_table = *m_vk_device_table, - vk_device = m_vk_device](auto&& handle) noexcept { - vk_device_table.vkDestroySampler(vk_device, handle, nullptr); - } } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Sampler::~Sampler() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Sampler::Sampler(Sampler&&) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Sampler::operator=(Sampler&&) noexcept -> Sampler& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Sampler::create(const Device& device, const Settings& settings) noexcept - -> Expected { - auto sampler = Sampler { device, settings, PrivateFuncTag {} }; - return sampler.do_init().transform(core::monadic::consume(sampler)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Sampler::allocate(const Device& device, const Settings& settings) noexcept - -> Expected> { - auto sampler = std::make_unique(device, settings, PrivateFuncTag {}); - return sampler->do_init().transform(core::monadic::consume(sampler)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Sampler::settings() const noexcept -> const Settings& { - return m_settings; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Sampler::native_handle() const noexcept -> VkSampler { - EXPECTS(m_vk_handle); - return m_vk_handle; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto ImageView::do_init(const Image& image) noexcept -> Expected { - const auto vk_subresource_range = VkImageSubresourceRange { - .aspectMask = to_vk(m_subresource_range.aspect_mask), - .baseMipLevel = m_subresource_range.base_mip_level, - .levelCount = m_subresource_range.level_count, - .baseArrayLayer = m_subresource_range.base_array_layer, - .layerCount = m_subresource_range.layer_count, - }; - - const auto create_info = VkImageViewCreateInfo { - .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .image = image.native_handle(), - .viewType = to_vk(m_type), - .format = to_vk(image.format()), - .components = { .r = VK_COMPONENT_SWIZZLE_R, - .g = VK_COMPONENT_SWIZZLE_G, - .b = VK_COMPONENT_SWIZZLE_B, - .a = VK_COMPONENT_SWIZZLE_A }, - .subresourceRange = vk_subresource_range, - }; - - return vk_call(m_vk_device_table->vkCreateImageView, - m_vk_device, - &create_info, - nullptr) - .transform(core::monadic::set(m_vk_handle)) - .transform_error(monadic::from_vk()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline ImageView::ImageView(const Device& device, - ImageViewType type, - const ImageSubresourceRange& subresource_range, - PrivateFuncTag) noexcept - : m_type { type }, m_subresource_range { subresource_range }, - m_vk_device { device.native_handle() }, - m_vk_device_table { as_ref(device.device_table()) }, - m_vk_handle { [vk_device_table = *m_vk_device_table, - vk_device = m_vk_device](auto&& handle) noexcept { - vk_device_table.vkDestroyImageView(vk_device, handle, nullptr); - } } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline ImageView::~ImageView() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline ImageView::ImageView(ImageView&&) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto ImageView::operator=(ImageView&&) noexcept -> ImageView& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto ImageView::create(const Device& device, - const Image& image, - ImageViewType type, - const ImageSubresourceRange& subresource_range) noexcept - -> Expected { - auto image_view = ImageView { device, type, subresource_range, PrivateFuncTag {} }; - return image_view.do_init(image).transform(core::monadic::consume(image_view)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto ImageView::allocate(const Device& device, - const Image& image, - ImageViewType type, - const ImageSubresourceRange& subresource_range) noexcept - -> Expected> { - auto image_view = std::make_unique(device, - type, - subresource_range, - PrivateFuncTag {}); - return image_view->do_init(image).transform(core::monadic::consume(image_view)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto ImageView::type() const noexcept -> ImageViewType { - return m_type; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto ImageView::subresource_range() const noexcept -> const ImageSubresourceRange& { - return m_subresource_range; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto ImageView::native_handle() const noexcept -> VkImageView { - EXPECTS(m_vk_handle); - return m_vk_handle; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Image::Image(const Device& device, const CreateInfo& info, PrivateFuncTag) noexcept - : m_extent { info.extent }, m_format { info.format }, m_layers { info.layers }, - m_faces { 1 }, m_mip_levels { info.mip_levels }, m_type { info.type }, - m_flags { info.flags }, m_samples { info.samples }, m_usages { info.usages }, - m_vk_device { device.native_handle() }, - m_vk_device_table { as_ref(device.device_table()) }, - m_vma_allocator { device.allocator() }, - m_vk_handle { [vk_device_table = *m_vk_device_table, - vk_device = m_vk_device](auto handle) noexcept { - vk_device_table.vkDestroyImage(vk_device, handle, nullptr); - } } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Image::~Image() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Image::Image(Image&&) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Image::operator=(Image&&) noexcept -> Image& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Image::create(const Device& device, const CreateInfo& create_info) noexcept - -> Expected { - auto image = Image { device, create_info, PrivateFuncTag {} }; - return image.do_init(create_info).transform(core::monadic::consume(image)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Image::allocate(const Device& device, const CreateInfo& create_info) noexcept - -> Expected> { - auto image = std::make_unique(device, create_info, PrivateFuncTag {}); - return image->do_init(create_info).transform(core::monadic::consume(image)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Image::extent() const noexcept -> const math::Extent3& { - return m_extent; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Image::format() const noexcept -> PixelFormat { - return m_format; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Image::type() const noexcept -> ImageType { - return m_type; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Image::samples() const noexcept -> SampleCountFlag { - return m_samples; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Image::layers() const noexcept -> u32 { - return m_layers; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Image::faces() const noexcept -> u32 { - return m_faces; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Image::mip_levels() const noexcept -> u32 { - return m_mip_levels; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Image::usages() const noexcept -> ImageUsageFlag { - return m_usages; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Image::native_handle() const noexcept -> VkImage { - EXPECTS(m_vk_handle); - return m_vk_handle; - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::create(const Device& device, - const CreateInfo& info, - VkImage&& vk_image) noexcept -> Image { - auto image = Image { device, info, PrivateFuncTag {} }; - image.m_vma_allocation = { core::monadic::noop() }; - image.m_vk_handle = { core::monadic::noop() }; - image.m_vk_handle = std::move(vk_image); - return image; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Image::do_init(const CreateInfo& info) noexcept -> Expected { - if (core::check_flag_bit(m_flags, gpu::ImageCreateFlag::CUBE_COMPATIBLE)) m_faces = 6u; - const auto create_info = VkImageCreateInfo { - .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, - .pNext = nullptr, - .flags = to_vk(m_flags), - .imageType = to_vk(m_type), - .format = to_vk(m_format), - .extent = { m_extent.width, m_extent.height, m_extent.depth }, - .mipLevels = m_mip_levels, - .arrayLayers = m_layers * m_faces, - .samples = to_vk(m_samples), - .tiling = to_vk(info.tiling), - .usage = to_vk(m_usages), - .sharingMode = VK_SHARING_MODE_EXCLUSIVE, - .queueFamilyIndexCount = 0, // TODO CHECK IF VALID VALUE - .pQueueFamilyIndices = nullptr, - .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, - }; - - return do_init(create_info, info.property); - } -} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/resource/objects.cppm b/modules/stormkit/gpu/resource/objects.cppm new file mode 100644 index 000000000..ea5c351a0 --- /dev/null +++ b/modules/stormkit/gpu/resource/objects.cppm @@ -0,0 +1,123 @@ +// Copyright (C) 2023 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +export module stormkit.gpu.resource:objects; + +import std; + +import stormkit.core; +import stormkit.gpu.core; + +namespace stormkit::gpu { + class ShaderImplementation; + class BufferImplementation; + class ImageImplementation; + class ImageViewImplementation; + class SamplerImplementation; + + namespace view { + class ShaderImplementation; + class BufferImplementation; + class ImageImplementation; + class ImageViewImplementation; + class SamplerImplementation; + } // namespace view + + export { + class ShaderTag; + template + class ShaderInterface; + + class BufferTag; + template + class BufferInterface; + + class ImageTag; + template + class ImageInterface; + + class ImageViewTag; + template + class ImageViewInterface; + + class SamplerTag; + template + class SamplerInterface; + + using Shader = ShaderInterface; + using Buffer = BufferInterface; + using Image = ImageInterface; + using ImageView = ImageViewInterface; + using Sampler = SamplerInterface; + + namespace view { + using Shader = ShaderInterface; + using Buffer = BufferInterface; + using Image = ImageInterface; + using ImageView = ImageViewInterface; + using Sampler = SamplerInterface; + } // namespace view + + namespace trait { + template<> + struct GpuObject { + using ValueType = VkShaderModule; + using DeleterType = PFN_vkDestroyShaderModule VolkDeviceTable::*; + using ObjectType = Shader; + using ViewType = view::Shader; + using OwnerType = Device; + + static constexpr auto DEBUG_TYPE = DebugObjectType::SHADER_MODULE; + }; + + template<> + struct GpuObject { + using ValueType = VkBuffer; + using DeleterType = PFN_vkDestroyBuffer VolkDeviceTable::*; + using ObjectType = Buffer; + using ViewType = view::Buffer; + using OwnerType = Device; + + static constexpr auto DEBUG_TYPE = DebugObjectType::BUFFER; + }; + + template<> + struct GpuObject { + using ValueType = VkImage; + using DeleterType = PFN_vkDestroyImage VolkDeviceTable::*; + using ObjectType = Image; + using ViewType = view::Image; + using OwnerType = Device; + + static constexpr auto DEBUG_TYPE = DebugObjectType::IMAGE; + }; + + template<> + struct GpuObject { + using ValueType = VkImageView; + using DeleterType = PFN_vkDestroyImageView VolkDeviceTable::*; + using ObjectType = ImageView; + using ViewType = view::ImageView; + using OwnerType = Device; + + static constexpr auto DEBUG_TYPE = DebugObjectType::IMAGE_VIEW; + }; + + template<> + struct GpuObject { + using ValueType = VkSampler; + using DeleterType = PFN_vkDestroySampler VolkDeviceTable::*; + using ObjectType = Sampler; + using ViewType = view::Sampler; + using OwnerType = Device; + + static constexpr auto DEBUG_TYPE = DebugObjectType::SAMPLER; + }; + } // namespace trait + } +} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/resource/shader.cppm b/modules/stormkit/gpu/resource/shader.cppm new file mode 100644 index 000000000..045ec3e4d --- /dev/null +++ b/modules/stormkit/gpu/resource/shader.cppm @@ -0,0 +1,281 @@ +// Copyright (C) 2023 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include +#include + +#include +#include + +export module stormkit.gpu.resource:shader; + +import std; + +import stormkit.core; +import stormkit.gpu.core; + +import :objects; + +namespace stdr = std::ranges; +namespace stdv = std::views; + +namespace cmeta = stormkit::core::meta; + +namespace stormkit::gpu { + export template + class STORMKIT_GPU_API ShaderInterface: public DeviceObject { + public: + using DeviceObject::DeviceObject; + using DeviceObject::operator=; + using TagType = ShaderTag; + + [[nodiscard]] + auto type() const noexcept -> ShaderStageFlag; + [[nodiscard]] + auto source() const noexcept -> array_view; + [[nodiscard]] + auto source_as_bytes() const noexcept -> byte_view<>; + }; + + class STORMKIT_GPU_API + ShaderImplementation: public GpuObjectImplementation&&, ShaderStageFlag> { + public: + enum class Error { + INVALID_SPIRV, + }; + + using LoadError = std::variant; + template + using LoadExpected = std::expected; + + ShaderImplementation(PrivateTag, view::Device&&) noexcept; + ~ShaderImplementation() noexcept; + + ShaderImplementation(const ShaderImplementation&) noexcept = delete; + auto operator=(const ShaderImplementation&) noexcept -> ShaderImplementation& = delete; + + ShaderImplementation(ShaderImplementation&&) noexcept; + auto operator=(ShaderImplementation&&) noexcept -> ShaderImplementation&; + + static auto load_from_file(view::Device device, const std::filesystem::path& filepath, ShaderStageFlag type) noexcept + -> LoadExpected; + static auto load_from_bytes(view::Device device, byte_view<> data, ShaderStageFlag type) noexcept -> Expected; + static auto load_from_spirv(view::Device device, array_view data, ShaderStageFlag type) noexcept + -> Expected; + + static auto allocate_and_load_from_file(view::Device device, + const std::filesystem::path& filepath, + ShaderStageFlag type) noexcept -> LoadExpected>; + static auto allocate_and_load_from_bytes(view::Device device, byte_view<> data, ShaderStageFlag type) noexcept + -> Expected>; + static auto allocate_and_load_from_spirv(view::Device device, + array_view data, + ShaderStageFlag type) noexcept -> Expected>; + + auto do_init(PrivateTag, dyn_array&&, ShaderStageFlag) -> Expected; + + protected: + using NamedConstructor::allocate; + using NamedConstructor::create; + + ShaderStageFlag m_type = ShaderStageFlag::NONE; + dyn_array m_source = {}; + }; + + namespace view { + class ShaderImplementation: public GpuObjectViewImplementation { + public: + ShaderImplementation(const gpu::Shader&) noexcept; + template TContainerOrPointer> + ShaderImplementation(const TContainerOrPointer&) noexcept; + ~ShaderImplementation() noexcept; + + ShaderImplementation(const ShaderImplementation&) noexcept; + auto operator=(const ShaderImplementation&) noexcept -> ShaderImplementation&; + + ShaderImplementation(ShaderImplementation&&) noexcept; + auto operator=(ShaderImplementation&&) noexcept -> ShaderImplementation&; + + protected: + ShaderStageFlag m_type; + array_view m_source; + }; + } // namespace view +} // namespace stormkit::gpu + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit::gpu { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_PURE + inline auto sys_to_load_error(SystemError&& error) noexcept -> Shader::LoadError { + return Shader::LoadError { std::move(error) }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_PURE + inline auto result_to_load_error(gpu::Result&& error) noexcept -> Shader::LoadError { + return Shader::LoadError { std::move(error) }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto ShaderInterface::type() const noexcept -> ShaderStageFlag { + return Base::m_type; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto ShaderInterface::source() const noexcept -> array_view { + return Base::m_source; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto ShaderInterface::source_as_bytes() const noexcept -> byte_view<> { + return as_bytes(Base::m_source); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline ShaderImplementation::ShaderImplementation(PrivateTag, view::Device&& device) noexcept + : GpuObjectImplementation { std::move(device), &VolkDeviceTable::vkDestroyShaderModule } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline ShaderImplementation::~ShaderImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline ShaderImplementation::ShaderImplementation(ShaderImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto ShaderImplementation::operator=(ShaderImplementation&&) noexcept -> ShaderImplementation& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto ShaderImplementation::load_from_file(view::Device device, + const std::filesystem::path& filepath, + ShaderStageFlag type) noexcept -> LoadExpected { + expects(std::filesystem::is_regular_file(filepath), std::format("{} is not a file", filepath.string())); + + const auto data = TryTransformError(io::read(filepath), sys_to_load_error); + auto spirv = dyn_array { std::from_range, bytes_as_span(data) }; + Return TryTransformError(NamedConstructor::create(std::move(device), std::move(spirv), type), result_to_load_error); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto ShaderImplementation::load_from_bytes(view::Device device, byte_view<> data, ShaderStageFlag type) noexcept + -> Expected { + auto spirv = dyn_array { std::from_range, bytes_as_span(data) }; + return NamedConstructor::create(std::move(device), std::move(spirv), type); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto ShaderImplementation::load_from_spirv(view::Device device, + array_view data, + ShaderStageFlag type) noexcept -> Expected { + auto spirv = dyn_array { std::from_range, data }; + return NamedConstructor::create(std::move(device), std::move(spirv), type); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto ShaderImplementation::allocate_and_load_from_file(view::Device device, + const std::filesystem::path& filepath, + ShaderStageFlag type) noexcept -> LoadExpected> { + expects(std::filesystem::is_regular_file(filepath), std::format("{} is not a file", filepath.string())); + + const auto data = TryTransformError(io::read(filepath), sys_to_load_error); + auto spirv = dyn_array { std::from_range, bytes_as_span(data) }; + Return TryTransformError(NamedConstructor::allocate(std::move(device), std::move(spirv), type), result_to_load_error); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto ShaderImplementation::allocate_and_load_from_bytes(view::Device device, + byte_view<> data, + ShaderStageFlag type) noexcept -> Expected> { + auto spirv = dyn_array { std::from_range, bytes_as_span(data) }; + return NamedConstructor::allocate(std::move(device), std::move(spirv), type); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto ShaderImplementation::allocate_and_load_from_spirv(view::Device device, + array_view data, + ShaderStageFlag type) noexcept -> Expected> { + auto spirv = dyn_array { std::from_range, data }; + return NamedConstructor::allocate(std::move(device), std::move(spirv), type); + } + + namespace view { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline ShaderImplementation::ShaderImplementation(const gpu::Shader& of) noexcept + : GpuObjectViewImplementation { of }, m_type { of.type() }, m_source { of.source() } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + template TContainerOrPointer> + STORMKIT_FORCE_INLINE + inline ShaderImplementation::ShaderImplementation(const TContainerOrPointer& of) noexcept + : ShaderImplementation { *of } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline ShaderImplementation::~ShaderImplementation() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline ShaderImplementation::ShaderImplementation(const ShaderImplementation&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto ShaderImplementation::operator=(const ShaderImplementation&) noexcept -> ShaderImplementation& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline ShaderImplementation::ShaderImplementation(ShaderImplementation&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto ShaderImplementation::operator=(ShaderImplementation&&) noexcept -> ShaderImplementation& = default; + } // namespace view +} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/resource/shader.mpp b/modules/stormkit/gpu/resource/shader.mpp deleted file mode 100644 index d87ddc6b6..000000000 --- a/modules/stormkit/gpu/resource/shader.mpp +++ /dev/null @@ -1,293 +0,0 @@ -// Copyright (C) 2023 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include -#include - -#include - -export module stormkit.gpu.resource:shader; - -import std; - -import stormkit.core; -import stormkit.gpu.core; - -namespace stdr = std::ranges; - -export namespace stormkit::gpu { - class STORMKIT_API Shader { - struct PrivateFuncTag {}; - - public: - enum class Error { - INVALID_SPIRV, - }; - using LoadError = std::variant; - template - using LoadExpected = std::expected; - static constexpr auto DEBUG_TYPE = DebugObjectType::SHADER_MODULE; - - static auto load_from_file(const Device& device, - const std::filesystem::path& filepath, - ShaderStageFlag type) noexcept -> LoadExpected; - static auto load_from_bytes(const Device& device, - std::span data, - ShaderStageFlag type) noexcept -> Expected; - static auto load_from_spirvid(const Device& device, - std::span data, - ShaderStageFlag type) noexcept -> Expected; - - static auto allocate_and_load_from_file(const Device& device, - const std::filesystem::path& filepath, - ShaderStageFlag type) noexcept - -> LoadExpected>; - static auto allocate_and_load_from_bytes(const Device& device, - std::span data, - ShaderStageFlag type) noexcept - -> Expected>; - static auto allocate_and_load_from_spirvid(const Device& device, - std::span data, - ShaderStageFlag type) noexcept - -> Expected>; - ~Shader(); - - Shader(const Shader&) = delete; - auto operator=(const Shader&) -> Shader& = delete; - - Shader(Shader&&) noexcept; - auto operator=(Shader&&) noexcept -> Shader&; - - [[nodiscard]] - auto type() const noexcept -> ShaderStageFlag; - [[nodiscard]] - auto source() const noexcept -> const std::vector&; - [[nodiscard]] - auto source_as_bytes() const noexcept -> std::span; - - [[nodiscard]] - auto native_handle() const noexcept -> VkShaderModule; - - Shader(const Device&, std::vector, ShaderStageFlag, PrivateFuncTag) noexcept; - - private: - auto do_init() -> Expected; - auto reflect() noexcept -> void; - - ShaderStageFlag m_type = ShaderStageFlag::NONE; - std::vector m_source = {}; - - VkDevice m_vk_device = nullptr; - Ref m_vk_device_table; - VkRAIIHandle m_vk_handle; - }; -} // namespace stormkit::gpu - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::gpu { - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline auto sys_to_load_error(SystemError&& error) noexcept -> Shader::LoadError { - return Shader::LoadError { std::move(error) }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline auto result_to_load_error(gpu::Result&& error) noexcept -> Shader::LoadError { - return Shader::LoadError { std::move(error) }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Shader::do_init() -> Expected { - const auto create_info = VkShaderModuleCreateInfo { - .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .codeSize = stdr::size(m_source) * sizeof(SpirvID), - .pCode = stdr::data(m_source) - }; - - return vk_call(m_vk_device_table->vkCreateShaderModule, - m_vk_device, - &create_info, - nullptr) - .transform(core::monadic::set(m_vk_handle)) - .transform_error(monadic::from_vk()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Shader::Shader(const Device& device, - std::vector data, - ShaderStageFlag type, - PrivateFuncTag) noexcept - : m_type { type }, m_source { std::move(data) }, m_vk_device { device.native_handle() }, - m_vk_device_table { as_ref(device.device_table()) }, - m_vk_handle { [vk_device_table = *m_vk_device_table, - vk_device = m_vk_device](auto&& handle) noexcept { - vk_device_table.vkDestroyShaderModule(vk_device, handle, nullptr); - } } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Shader::~Shader() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Shader::Shader(Shader&&) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Shader::operator=(Shader&&) noexcept -> Shader& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Shader::load_from_file(const Device& device, - const std::filesystem::path& filepath, - ShaderStageFlag type) noexcept -> LoadExpected { - return io::File::open(filepath, io::Access::READ) - .transform_error(sys_to_load_error) - .and_then([](auto&& file) static noexcept -> LoadExpected> { - const auto size = file.size(); - if (size % sizeof(SpirvID) != 0) - return std::unexpected { LoadError { Error::INVALID_SPIRV } }; - auto spirv = std::vector(size / sizeof(SpirvID)); - return file.read_to(as_bytes(spirv)) - .transform(core::monadic::consume(spirv)) - .transform_error(sys_to_load_error); - }) - .and_then([&type, &device](auto&& spirv) noexcept { - auto shader = Shader { device, std::move(spirv), type, PrivateFuncTag {} }; - return shader.do_init() - .transform_error(result_to_load_error) - .transform(core::monadic::consume(shader)); - }); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Shader::load_from_bytes(const Device& device, - std::span data, - ShaderStageFlag type) noexcept -> Expected { - auto shader = Shader { device, - bytes_as>(data) | stdr::to(), - type, - PrivateFuncTag {} }; - return shader.do_init().transform(core::monadic::consume(shader)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Shader::load_from_spirvid(const Device& device, - std::span data, - ShaderStageFlag type) noexcept -> Expected { - auto shader = Shader { device, data | stdr::to(), type, PrivateFuncTag {} }; - return shader.do_init().transform(core::monadic::consume(shader)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Shader::allocate_and_load_from_file(const Device& device, - const std::filesystem::path& filepath, - ShaderStageFlag type) noexcept - -> LoadExpected> { - expects(std::filesystem::is_regular_file(filepath), - std::format("{} is not a file", filepath.string())); - - return io::File::open(filepath, io::Access::READ) - .transform_error(sys_to_load_error) - .and_then([](auto&& file) static noexcept { - const auto size = file.size(); - - auto spirv = std::vector(size / sizeof(SpirvID)); - return file.read_to(as_bytes(spirv)) - .transform(core::monadic::consume(spirv)) - .transform_error(sys_to_load_error); - }) - .and_then([&type, &device](auto&& spirv) noexcept { - auto shader = std::make_unique(device, - std::move(spirv), - type, - PrivateFuncTag {}); - return shader->do_init() - .transform(core::monadic::consume(shader)) - .transform_error(result_to_load_error); - }); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Shader::allocate_and_load_from_bytes(const Device& device, - std::span data, - ShaderStageFlag type) noexcept - -> Expected> { - auto shader = std::make_unique(device, - bytes_as>(data) - | stdr::to(), - type, - PrivateFuncTag {}); - return shader->do_init().transform(core::monadic::consume(shader)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Shader::allocate_and_load_from_spirvid(const Device& device, - std::span data, - ShaderStageFlag type) noexcept - -> Expected> { - auto shader = std::make_unique(device, - data | stdr::to(), - type, - PrivateFuncTag {}); - return shader->do_init().transform(core::monadic::consume(shader)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Shader::type() const noexcept -> ShaderStageFlag { - return m_type; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Shader::source() const noexcept -> const std::vector& { - return m_source; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Shader::source_as_bytes() const noexcept -> std::span { - return as_bytes(m_source); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Shader::native_handle() const noexcept -> VkShaderModule { - return m_vk_handle; - } -} // namespace stormkit::gpu diff --git a/modules/stormkit/image.mpp b/modules/stormkit/image.cppm similarity index 82% rename from modules/stormkit/image.mpp rename to modules/stormkit/image.cppm index 868e95005..bc224b3e2 100644 --- a/modules/stormkit/image.mpp +++ b/modules/stormkit/image.cppm @@ -1,713 +1,689 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -#include - -export module stormkit.image; - -import std; - -import stormkit.core; - -export namespace stormkit::image { - class STORMKIT_API Image { - public: - enum class Format : u8 { - R8_SNORM = 0, - RG8_SNORM = 1, - RGB8_SNORM = 2, - RGBA8_SNORM = 3, - R8_UNORM = 4, - RG8_UNORM = 5, - RGB8_UNORM = 6, - RGBA8_UNORM = 7, - R16_SNORM = 8, - RG16_SNORM = 9, - RGB16_SNORM = 10, - RGBA16_SNORM = 11, - R16_UNORM = 12, - RG16_UNORM = 13, - RGB16_UNORM = 14, - RGBA16_UNORM = 15, - RGBA4_UNORM = 17, - BGR8_UNORM = 20, - BGRA8_UNORM = 21, - R8I = 22, - RG8I = 23, - RGB8I = 24, - RGBA8I = 25, - R8U = 26, - RG8U = 27, - RGB8U = 28, - RGBA8U = 29, - R16I = 30, - RG16I = 31, - RGB16I = 32, - RGBA16I = 33, - R16U = 34, - RG16U = 35, - RGB16U = 36, - RGBA16U = 37, - R32I = 38, - RG32I = 39, - RGB32I = 40, - RGBA32I = 41, - R32U = 42, - RG32U = 43, - RGB32U = 44, - RGBA32U = 45, - R16F = 47, - RG16F = 48, - RGB16F = 49, - RGBA16F = 50, - R32F = 51, - RG32F = 52, - RGB32F = 53, - RGBA32F = 54, - SRGB8 = 56, - SRGBA8 = 57, - SBGR8 = 58, - SBGRA8 = 59, - UNDEFINED = 254, - }; - - enum class Codec : u8 { - AUTODETECT = 0, - JPEG = 1, - PNG = 2, - TARGA = 3, - PPM = 4, - HDR = 5, - KTX = 6, - QOI = 7, - UNKNOWN = 255, - }; - - enum class CodecArgs : u8 { - BINARY = 0, - ASCII = 1, - }; - - struct Error { - enum class Reason { - NOT_IMPLEMENTED, - FAILED_TO_PARSE, - FAILED_TO_SAVE, - FILE_NOT_FOUND, - INVALID_FORMAT, - UNKNOWN, - } reason; - - std::string str_error; - }; - - struct ImageData { - math::Extent3 extent = { .width = 0u, .height = 0u }; - u32 channel_count = 0u; - u32 bytes_per_channel = 0u; - u32 layers = 1u; - u32 faces = 1u; - u32 mip_levels = 1u; - Format format = Format::UNDEFINED; - - std::vector data = {}; - }; - - Image() noexcept; - explicit Image(ImageData&& data) noexcept; - Image(const math::Extent3& extent, Format format) noexcept; - Image(const std::filesystem::path& filepath, Codec codec = Codec::AUTODETECT) noexcept; - Image(std::span data, Codec codec = Codec::AUTODETECT) noexcept; - ~Image() noexcept; - - Image(const Image& rhs) noexcept; - auto operator=(const Image& rhs) noexcept -> Image&; - - Image(Image&& rhs) noexcept; - auto operator=(Image&& rhs) noexcept -> Image&; - - [[nodiscard]] - auto load_from_file(std::filesystem::path filepath, - Codec codec = Codec::AUTODETECT) noexcept -> std::expected; - [[nodiscard]] - auto load_from_memory(std::span data, Codec codec = Codec::AUTODETECT) noexcept - -> std::expected; - [[nodiscard]] - auto save_to_file(std::filesystem::path filename, - Codec codec, - CodecArgs args = CodecArgs::BINARY) const noexcept - -> std::expected; - - [[nodiscard]] - auto save_to_memory(Codec codec, CodecArgs args = CodecArgs::BINARY) const noexcept - -> std::expected, Error>; - - auto create(math::Extent3 extent, Format format) noexcept -> void; - - [[nodiscard]] - auto convert_to(Format format) const noexcept -> Image; - [[nodiscard]] - auto scale(const math::Extent3& scale_to) const noexcept -> Image; - [[nodiscard]] - auto flip_x() const noexcept -> Image; - [[nodiscard]] - auto flip_y() const noexcept -> Image; - [[nodiscard]] - auto flip_z() const noexcept -> Image; - [[nodiscard]] - auto rotate_90() const noexcept -> Image; - [[nodiscard]] - auto rotate_180() const noexcept -> Image; - [[nodiscard]] - auto rotate_270() const noexcept -> Image; - - [[nodiscard]] - auto pixel(usize id, u32 layer = 0u, u32 face = 0u, u32 level = 0u) noexcept - -> std::span; - [[nodiscard]] - auto pixel(usize id, u32 layer = 0u, u32 face = 0u, u32 level = 0u) const noexcept - -> std::span; - [[nodiscard]] - auto pixel(math::vec3u position, u32 layer = 0u, u32 face = 0u, u32 level = 0u) noexcept - -> std::span; - [[nodiscard]] - auto pixel(math::vec3u position, - u32 layer = 0u, - u32 face = 0u, - u32 level = 0u) const noexcept -> std::span; - - [[nodiscard]] - auto extent(u32 level = 0u) const noexcept -> math::Extent3; - - [[nodiscard]] - auto channelCount() const noexcept -> u32; - - [[nodiscard]] - auto bytesPerChannel() const noexcept -> u32; - - [[nodiscard]] - auto layers() const noexcept -> u32; - - [[nodiscard]] - auto faces() const noexcept -> u32; - - [[nodiscard]] - auto mip_levels() const noexcept -> u32; - - [[nodiscard]] - auto format() const noexcept -> Format; - - [[nodiscard]] - auto size() const noexcept -> usize; - [[nodiscard]] - auto size(u32 layer, u32 face, u32 level) const noexcept -> usize; - [[nodiscard]] - auto size(u32 layer, u32 face) const noexcept -> usize; - [[nodiscard]] - auto size(u32 layer) const noexcept -> usize; - - [[nodiscard]] - auto data() noexcept -> std::span; - [[nodiscard]] - auto data(u32 layer, u32 face, u32 level) noexcept -> std::span; - [[nodiscard]] - auto data() const noexcept -> std::span; - [[nodiscard]] - auto data(u32 layer, u32 face, u32 level) const noexcept -> std::span; - - [[nodiscard]] - auto begin() noexcept; - [[nodiscard]] - auto begin(u32 layer, u32 face, u32 level) noexcept; - [[nodiscard]] - auto begin() const noexcept; - [[nodiscard]] - auto begin(u32 layer, u32 face, u32 level) const noexcept; - - [[nodiscard]] - auto cbegin() const noexcept; - [[nodiscard]] - auto cbegin(u32 layer, u32 face, u32 level) const noexcept; - - [[nodiscard]] - auto end() noexcept; - [[nodiscard]] - auto end(u32 layer, u32 face, u32 level) noexcept; - [[nodiscard]] - auto end() const noexcept; - [[nodiscard]] - auto end(u32 layer, u32 face, u32 level) const noexcept; - - [[nodiscard]] - auto cend() const noexcept; - [[nodiscard]] - auto cend(u32 layer, u32 face, u32 level) const noexcept; - - [[nodiscard]] - auto image_data() const noexcept -> const ImageData&; - - private: - ImageData m_data; - }; - - constexpr auto get_format_channel_count(Image::Format format) noexcept -> u8; - constexpr auto getSizeof(Image::Format format) noexcept -> u8; - -} // namespace stormkit::image - -export { - template - struct std::formatter - : std::formatter, CharT> { - template - [[nodiscard]] - auto format(const stormkit::image::Image::Error& error, FormatContext& ctx) const noexcept - -> decltype(ctx.out()); - }; -} - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::image { - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::pixel(usize index, u32 layer, u32 face, u32 level) noexcept - -> std::span { - EXPECTS(m_data.mip_levels > level); - EXPECTS(m_data.faces > face); - EXPECTS(m_data.layers > layer); - - auto _data = data(layer, face, level); - - EXPECTS(index < m_data.extent.width * m_data.extent.height * m_data.extent.depth); - - const auto block_size = m_data.channel_count * m_data.bytes_per_channel; - - return { std::data(_data) + index * block_size, block_size }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::pixel(usize index, u32 layer, u32 face, u32 level) const noexcept - -> std::span { - EXPECTS(m_data.mip_levels > level); - EXPECTS(m_data.faces > face); - EXPECTS(m_data.layers > layer); - - auto _data = data(layer, face, level); - - const auto mip_extent = extent(level); - EXPECTS(index < mip_extent.width * mip_extent.height * mip_extent.depth); - - const auto block_size = m_data.channel_count * m_data.bytes_per_channel; - - return { std::data(_data) + index * block_size, block_size }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::pixel(math::vec3u position, u32 layer, u32 face, u32 level) noexcept - -> std::span { - const auto mip_extent = extent(level); - - const auto id = position.x - + (position.y * mip_extent.width) - + (mip_extent.width * mip_extent.height * position.z); - - return pixel(id, layer, face, level); - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::pixel(math::vec3u position, u32 layer, u32 face, u32 level) const noexcept - -> std::span { - const auto mip_extent = extent(level); - - const auto id = position.x - + (position.y * mip_extent.width) - + (mip_extent.width * mip_extent.height * position.z); - - return pixel(id, layer, face, level); - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::extent(u32 level) const noexcept -> math::Extent3 { - EXPECTS(m_data.mip_levels > level); - - return { .width = std::max(1u, m_data.extent.width >> level), - .height = std::max(1u, m_data.extent.height >> level), - .depth = std::max(1u, m_data.extent.depth >> level) }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::channelCount() const noexcept -> u32 { - return m_data.channel_count; - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::bytesPerChannel() const noexcept -> u32 { - return m_data.bytes_per_channel; - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::layers() const noexcept -> u32 { - return m_data.layers; - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::faces() const noexcept -> u32 { - return m_data.faces; - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::mip_levels() const noexcept -> u32 { - return m_data.mip_levels; - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::format() const noexcept -> Format { - return m_data.format; - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::size() const noexcept -> usize { - return std::size(m_data.data); - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::size(u32 layer, // TODO Use layer and face to get correct size - u32 face, - u32 level) const noexcept -> usize { - EXPECTS(m_data.mip_levels > level); - EXPECTS(m_data.faces > face); - EXPECTS(m_data.layers > layer); - - const auto mip_extent = extent(level); - - return mip_extent.width - * mip_extent.height - * mip_extent.depth - * m_data.channel_count - * m_data.bytes_per_channel; - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::size(u32 layer, u32 face) const noexcept -> usize { - auto _size = usize { 0u }; - for (auto i : range(m_data.mip_levels)) _size += size(layer, face, i); - - return _size; - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::size(u32 layer) const noexcept -> usize { - auto _size = usize { 0u }; - for (auto i : range(m_data.faces)) _size += size(layer, i); - - return _size; - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::data() noexcept -> std::span { - return m_data.data; - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::data(u32 layer, u32 face, u32 level) noexcept -> std::span { - const auto mip_size = size(layer, face, level); - - auto offset = usize { 0 }; - - for (auto i : range(layer)) offset += size(i); - - for (auto j : range(face)) offset += size(layer, j); - - for (auto k : range(level)) offset += size(layer, face, k); - - return { std::data(m_data.data) + offset, mip_size }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::data() const noexcept -> std::span { - return m_data.data; - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::data(u32 layer, u32 face, u32 level) const noexcept - -> std::span { - const auto mip_size = size(layer, face, level); - - auto offset = usize { 0 }; - - for (auto i : range(layer)) offset += size(i); - - for (auto j : range(face)) offset += size(layer, j); - - for (auto k : range(level)) offset += size(layer, face, k); - - return { std::data(m_data.data) + offset, mip_size }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::begin() noexcept { - return std::begin(m_data.data); - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::begin(u32 layer, u32 face, u32 level) noexcept { - EXPECTS(m_data.mip_levels > level); - EXPECTS(m_data.faces > face); - EXPECTS(m_data.layers > layer); - - return std::begin(data(layer, face, level)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::begin() const noexcept { - return std::begin(m_data.data); - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::begin(u32 layer, u32 face, u32 level) const noexcept { - return std::begin(data(layer, face, level)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::cbegin() const noexcept { - return std::cbegin(m_data.data); - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::cbegin(u32 layer, u32 face, u32 level) const noexcept { - EXPECTS(m_data.mip_levels > level); - EXPECTS(m_data.faces > face); - EXPECTS(m_data.layers > layer); - - return std::cbegin(data(layer, face, level)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::end() noexcept { - return std::end(m_data.data); - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::end(u32 layer, u32 face, u32 level) noexcept { - EXPECTS(m_data.mip_levels > level); - EXPECTS(m_data.faces > face); - EXPECTS(m_data.layers > layer); - - return std::end(data(layer, face, level)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::end() const noexcept { - return std::end(m_data.data); - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::end(u32 layer, u32 face, u32 level) const noexcept { - EXPECTS(m_data.mip_levels > level); - EXPECTS(m_data.faces > face); - EXPECTS(m_data.layers > layer); - - return std::end(data(layer, face, level)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::cend() const noexcept { - return std::cend(m_data.data); - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::cend(u32 layer, u32 face, u32 level) const noexcept { - EXPECTS(m_data.mip_levels > level); - EXPECTS(m_data.faces > face); - EXPECTS(m_data.layers > layer); - - return std::cend(data(layer, face, level)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto Image::image_data() const noexcept -> const ImageData& { - return m_data; - } - - ///////////////////////////////////// - ///////////////////////////////////// - constexpr auto get_format_channel_count(Image::Format format) noexcept -> u8 { - switch (format) { - case Image::Format::R8_SNORM: - case Image::Format::R8_UNORM: - case Image::Format::R16_SNORM: - case Image::Format::R16_UNORM: - case Image::Format::R8I: - case Image::Format::R8U: - case Image::Format::R16I: - case Image::Format::R16U: - case Image::Format::R32I: - case Image::Format::R32U: - case Image::Format::R16F: - case Image::Format::R32F: return 1; - - case Image::Format::RG8_SNORM: - case Image::Format::RG8_UNORM: - case Image::Format::RG16_SNORM: - case Image::Format::RG16_UNORM: - case Image::Format::RG8I: - case Image::Format::RG8U: - case Image::Format::RG16I: - case Image::Format::RG16U: - case Image::Format::RG32I: - case Image::Format::RG32U: - case Image::Format::RG16F: - case Image::Format::RG32F: return 2; - - case Image::Format::RGB8_SNORM: - case Image::Format::RGB8_UNORM: - case Image::Format::RGB16_SNORM: - case Image::Format::RGB16_UNORM: - case Image::Format::BGR8_UNORM: - case Image::Format::RGB8I: - case Image::Format::RGB8U: - case Image::Format::RGB16I: - case Image::Format::RGB16U: - case Image::Format::RGB32I: - case Image::Format::RGB32U: - case Image::Format::RGB16F: - case Image::Format::RGB32F: - case Image::Format::SRGB8: - case Image::Format::SBGR8: return 3; - - case Image::Format::RGBA8_SNORM: - case Image::Format::RGBA8_UNORM: - case Image::Format::RGBA16_SNORM: - case Image::Format::RGBA16_UNORM: - case Image::Format::BGRA8_UNORM: - case Image::Format::RGBA8I: - case Image::Format::RGBA8U: - case Image::Format::RGBA16I: - case Image::Format::RGBA16U: - case Image::Format::RGBA32I: - case Image::Format::RGBA32U: - case Image::Format::RGBA16F: - case Image::Format::RGBA32F: - case Image::Format::SRGBA8: - case Image::Format::SBGRA8: return 4; - - default: break; - } - - return 0u; - } - - ///////////////////////////////////// - ///////////////////////////////////// - constexpr auto getSizeof(Image::Format format) noexcept -> u8 { - switch (format) { - case Image::Format::R8_SNORM: - case Image::Format::R8_UNORM: - case Image::Format::RG8_SNORM: - case Image::Format::RG8_UNORM: - case Image::Format::R8I: - case Image::Format::R8U: - case Image::Format::RG8I: - case Image::Format::RG8U: - case Image::Format::RGB8_SNORM: - case Image::Format::RGB8_UNORM: - case Image::Format::BGR8_UNORM: - case Image::Format::RGB8I: - case Image::Format::RGB8U: - case Image::Format::RGBA8_SNORM: - case Image::Format::RGBA8_UNORM: - case Image::Format::RGBA16_SNORM: - case Image::Format::BGRA8_UNORM: - case Image::Format::SRGB8: - case Image::Format::SBGR8: - case Image::Format::SRGBA8: - case Image::Format::SBGRA8: return 1u; - - case Image::Format::R16_SNORM: - case Image::Format::R16_UNORM: - case Image::Format::R16I: - case Image::Format::R16U: - case Image::Format::RG16_SNORM: - case Image::Format::RG16_UNORM: - case Image::Format::RG16I: - case Image::Format::RG16U: - case Image::Format::RG16F: - case Image::Format::RGB16I: - case Image::Format::RGB16U: - case Image::Format::RGB16F: - case Image::Format::RGBA16I: - case Image::Format::RGBA16U: - case Image::Format::RGBA16F: - case Image::Format::R16F: return 2u; - - case Image::Format::R32I: - case Image::Format::R32U: - case Image::Format::R32F: - case Image::Format::RG32I: - case Image::Format::RG32U: - case Image::Format::RG32F: - case Image::Format::RGB16_SNORM: - case Image::Format::RGB32I: - case Image::Format::RGB32U: - case Image::Format::RGB32F: - case Image::Format::RGBA8I: - case Image::Format::RGBA8U: - case Image::Format::RGBA32I: - case Image::Format::RGBA32U: - case Image::Format::RGBA32F: return 4u; - - default: break; - } - - return 0u; - } - -} // namespace stormkit::image - -template -template -auto std::formatter::format(const stormkit::image::Image::Error& error, - FormatContext& ctx) const noexcept -> decltype(ctx.out()) { - auto&& out = ctx.out(); - return format_to(out, "{}", error.str_error); -} +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include + +#include + +export module stormkit.image; + +import std; + +import stormkit.core; + +export namespace stormkit::image { + class STORMKIT_IMAGE_API Image { + public: + enum class Format : u8 { + R8_SNORM = 0, + RG8_SNORM = 1, + RGB8_SNORM = 2, + RGBA8_SNORM = 3, + R8_UNORM = 4, + RG8_UNORM = 5, + RGB8_UNORM = 6, + RGBA8_UNORM = 7, + R16_SNORM = 8, + RG16_SNORM = 9, + RGB16_SNORM = 10, + RGBA16_SNORM = 11, + R16_UNORM = 12, + RG16_UNORM = 13, + RGB16_UNORM = 14, + RGBA16_UNORM = 15, + RGBA4_UNORM = 17, + BGR8_UNORM = 20, + BGRA8_UNORM = 21, + R8I = 22, + RG8I = 23, + RGB8I = 24, + RGBA8I = 25, + R8U = 26, + RG8U = 27, + RGB8U = 28, + RGBA8U = 29, + R16I = 30, + RG16I = 31, + RGB16I = 32, + RGBA16I = 33, + R16U = 34, + RG16U = 35, + RGB16U = 36, + RGBA16U = 37, + R32I = 38, + RG32I = 39, + RGB32I = 40, + RGBA32I = 41, + R32U = 42, + RG32U = 43, + RGB32U = 44, + RGBA32U = 45, + R16F = 47, + RG16F = 48, + RGB16F = 49, + RGBA16F = 50, + R32F = 51, + RG32F = 52, + RGB32F = 53, + RGBA32F = 54, + SRGB8 = 56, + SRGBA8 = 57, + SBGR8 = 58, + SBGRA8 = 59, + UNDEFINED = 254, + }; + + enum class Codec : u8 { + AUTODETECT = 0, + JPEG = 1, + PNG = 2, + TARGA = 3, + PPM = 4, + HDR = 5, + KTX = 6, + QOI = 7, + UNKNOWN = 255, + }; + + enum class CodecArgs : u8 { + BINARY = 0, + ASCII = 1, + }; + + struct Error { + enum class Reason { + NOT_IMPLEMENTED, + FAILED_TO_PARSE, + FAILED_TO_SAVE, + FILE_NOT_FOUND, + INVALID_FORMAT, + UNKNOWN, + } reason; + + string str_error; + }; + + struct ImageData { + math::uextent3 extent = { .width = 0u, .height = 0u }; + u32 channel_count = 0u; + u32 bytes_per_channel = 0u; + u32 layers = 1u; + u32 faces = 1u; + u32 mip_levels = 1u; + Format format = Format::UNDEFINED; + + byte_dyn_array data = {}; + }; + + Image() noexcept; + explicit Image(ImageData&& data) noexcept; + Image(const math::uextent3& extent, Format format) noexcept; + Image(const std::filesystem::path& filepath, Codec codec = Codec::AUTODETECT) noexcept; + Image(byte_view<> data, Codec codec = Codec::AUTODETECT) noexcept; + ~Image() noexcept; + + Image(const Image& rhs) noexcept; + auto operator=(const Image& rhs) noexcept -> Image&; + + Image(Image&& rhs) noexcept; + auto operator=(Image&& rhs) noexcept -> Image&; + + [[nodiscard]] + auto load_from_file(std::filesystem::path filepath, Codec codec = Codec::AUTODETECT) noexcept + -> std::expected; + [[nodiscard]] + auto load_from_memory(byte_view<> data, Codec codec = Codec::AUTODETECT) noexcept -> std::expected; + [[nodiscard]] + auto save_to_file(std::filesystem::path filename, Codec codec, CodecArgs args = CodecArgs::BINARY) const noexcept + -> std::expected; + + [[nodiscard]] + auto save_to_memory(Codec codec, CodecArgs args = CodecArgs::BINARY) const noexcept + -> std::expected; + + auto create(math::uextent3 extent, Format format) noexcept -> void; + + [[nodiscard]] + auto convert_to(Format format) const noexcept -> Image; + [[nodiscard]] + auto scale(const math::uextent3& scale_to) const noexcept -> Image; + [[nodiscard]] + auto flip_x() const noexcept -> Image; + [[nodiscard]] + auto flip_y() const noexcept -> Image; + [[nodiscard]] + auto flip_z() const noexcept -> Image; + [[nodiscard]] + auto rotate_90() const noexcept -> Image; + [[nodiscard]] + auto rotate_180() const noexcept -> Image; + [[nodiscard]] + auto rotate_270() const noexcept -> Image; + + [[nodiscard]] + auto pixel(usize id, u32 layer = 0u, u32 face = 0u, u32 level = 0u) noexcept -> byte_mut_view<>; + [[nodiscard]] + auto pixel(usize id, u32 layer = 0u, u32 face = 0u, u32 level = 0u) const noexcept -> byte_view<>; + [[nodiscard]] + auto pixel(math::uvec3 position, u32 layer = 0u, u32 face = 0u, u32 level = 0u) noexcept -> byte_mut_view<>; + [[nodiscard]] + auto pixel(math::uvec3 position, u32 layer = 0u, u32 face = 0u, u32 level = 0u) const noexcept -> byte_view<>; + + [[nodiscard]] + auto extent(u32 level = 0u) const noexcept -> math::uextent3; + + [[nodiscard]] + auto channelCount() const noexcept -> u32; + + [[nodiscard]] + auto bytesPerChannel() const noexcept -> u32; + + [[nodiscard]] + auto layers() const noexcept -> u32; + + [[nodiscard]] + auto faces() const noexcept -> u32; + + [[nodiscard]] + auto mip_levels() const noexcept -> u32; + + [[nodiscard]] + auto format() const noexcept -> Format; + + [[nodiscard]] + auto size() const noexcept -> usize; + [[nodiscard]] + auto size(u32 layer, u32 face, u32 level) const noexcept -> usize; + [[nodiscard]] + auto size(u32 layer, u32 face) const noexcept -> usize; + [[nodiscard]] + auto size(u32 layer) const noexcept -> usize; + + [[nodiscard]] + auto data() noexcept -> byte_mut_view<>; + [[nodiscard]] + auto data(u32 layer, u32 face, u32 level) noexcept -> byte_mut_view<>; + [[nodiscard]] + auto data() const noexcept -> byte_view<>; + [[nodiscard]] + auto data(u32 layer, u32 face, u32 level) const noexcept -> byte_view<>; + + [[nodiscard]] + auto begin() noexcept; + [[nodiscard]] + auto begin(u32 layer, u32 face, u32 level) noexcept; + [[nodiscard]] + auto begin() const noexcept; + [[nodiscard]] + auto begin(u32 layer, u32 face, u32 level) const noexcept; + + [[nodiscard]] + auto cbegin() const noexcept; + [[nodiscard]] + auto cbegin(u32 layer, u32 face, u32 level) const noexcept; + + [[nodiscard]] + auto end() noexcept; + [[nodiscard]] + auto end(u32 layer, u32 face, u32 level) noexcept; + [[nodiscard]] + auto end() const noexcept; + [[nodiscard]] + auto end(u32 layer, u32 face, u32 level) const noexcept; + + [[nodiscard]] + auto cend() const noexcept; + [[nodiscard]] + auto cend(u32 layer, u32 face, u32 level) const noexcept; + + [[nodiscard]] + auto image_data() const noexcept -> const ImageData&; + + private: + ImageData m_data; + }; + + constexpr auto get_format_channel_count(Image::Format format) noexcept -> u8; + constexpr auto getSizeof(Image::Format format) noexcept -> u8; + +} // namespace stormkit::image + +export { + template + struct std::formatter: std::formatter, CharT> { + template + [[nodiscard]] + auto format(const stormkit::image::Image::Error& error, FormatContext& ctx) const noexcept -> decltype(ctx.out()); + }; +} + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit::image { + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::pixel(usize index, u32 layer, u32 face, u32 level) noexcept -> byte_mut_view<> { + EXPECTS(m_data.mip_levels > level); + EXPECTS(m_data.faces > face); + EXPECTS(m_data.layers > layer); + + auto _data = data(layer, face, level); + + EXPECTS(index < m_data.extent.width * m_data.extent.height * m_data.extent.depth); + + const auto block_size = m_data.channel_count * m_data.bytes_per_channel; + + return { std::data(_data) + index * block_size, block_size }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::pixel(usize index, u32 layer, u32 face, u32 level) const noexcept -> byte_view<> { + EXPECTS(m_data.mip_levels > level); + EXPECTS(m_data.faces > face); + EXPECTS(m_data.layers > layer); + + auto _data = data(layer, face, level); + + const auto mip_extent = extent(level); + EXPECTS(index < mip_extent.width * mip_extent.height * mip_extent.depth); + + const auto block_size = m_data.channel_count * m_data.bytes_per_channel; + + return { std::data(_data) + index * block_size, block_size }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::pixel(math::uvec3 position, u32 layer, u32 face, u32 level) noexcept -> byte_mut_view<> { + const auto mip_extent = extent(level); + + const auto id = position.x + (position.y * mip_extent.width) + (mip_extent.width * mip_extent.height * position.z); + + return pixel(id, layer, face, level); + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::pixel(math::uvec3 position, u32 layer, u32 face, u32 level) const noexcept -> byte_view<> { + const auto mip_extent = extent(level); + + const auto id = position.x + (position.y * mip_extent.width) + (mip_extent.width * mip_extent.height * position.z); + + return pixel(id, layer, face, level); + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::extent(u32 level) const noexcept -> math::uextent3 { + EXPECTS(m_data.mip_levels > level); + + return { .width = std::max(1u, m_data.extent.width >> level), + .height = std::max(1u, m_data.extent.height >> level), + .depth = std::max(1u, m_data.extent.depth >> level) }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::channelCount() const noexcept -> u32 { + return m_data.channel_count; + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::bytesPerChannel() const noexcept -> u32 { + return m_data.bytes_per_channel; + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::layers() const noexcept -> u32 { + return m_data.layers; + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::faces() const noexcept -> u32 { + return m_data.faces; + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::mip_levels() const noexcept -> u32 { + return m_data.mip_levels; + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::format() const noexcept -> Format { + return m_data.format; + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::size() const noexcept -> usize { + return std::size(m_data.data); + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::size(u32 layer, // TODO Use layer and face to get correct size + u32 face, + u32 level) const noexcept -> usize { + EXPECTS(m_data.mip_levels > level); + EXPECTS(m_data.faces > face); + EXPECTS(m_data.layers > layer); + + const auto mip_extent = extent(level); + + return mip_extent.width * mip_extent.height * mip_extent.depth * m_data.channel_count * m_data.bytes_per_channel; + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::size(u32 layer, u32 face) const noexcept -> usize { + auto _size = usize { 0u }; + for (auto i : range(m_data.mip_levels)) _size += size(layer, face, i); + + return _size; + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::size(u32 layer) const noexcept -> usize { + auto _size = usize { 0u }; + for (auto i : range(m_data.faces)) _size += size(layer, i); + + return _size; + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::data() noexcept -> byte_mut_view<> { + return m_data.data; + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::data(u32 layer, u32 face, u32 level) noexcept -> byte_mut_view<> { + const auto mip_size = size(layer, face, level); + + auto offset = usize { 0 }; + + for (auto i : range(layer)) offset += size(i); + + for (auto j : range(face)) offset += size(layer, j); + + for (auto k : range(level)) offset += size(layer, face, k); + + return { std::data(m_data.data) + offset, mip_size }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::data() const noexcept -> byte_view<> { + return m_data.data; + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::data(u32 layer, u32 face, u32 level) const noexcept -> byte_view<> { + const auto mip_size = size(layer, face, level); + + auto offset = usize { 0 }; + + for (auto i : range(layer)) offset += size(i); + + for (auto j : range(face)) offset += size(layer, j); + + for (auto k : range(level)) offset += size(layer, face, k); + + return { std::data(m_data.data) + offset, mip_size }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::begin() noexcept { + return std::begin(m_data.data); + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::begin(u32 layer, u32 face, u32 level) noexcept { + EXPECTS(m_data.mip_levels > level); + EXPECTS(m_data.faces > face); + EXPECTS(m_data.layers > layer); + + return std::begin(data(layer, face, level)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::begin() const noexcept { + return std::begin(m_data.data); + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::begin(u32 layer, u32 face, u32 level) const noexcept { + return std::begin(data(layer, face, level)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::cbegin() const noexcept { + return std::cbegin(m_data.data); + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::cbegin(u32 layer, u32 face, u32 level) const noexcept { + EXPECTS(m_data.mip_levels > level); + EXPECTS(m_data.faces > face); + EXPECTS(m_data.layers > layer); + + return std::cbegin(data(layer, face, level)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::end() noexcept { + return std::end(m_data.data); + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::end(u32 layer, u32 face, u32 level) noexcept { + EXPECTS(m_data.mip_levels > level); + EXPECTS(m_data.faces > face); + EXPECTS(m_data.layers > layer); + + return std::end(data(layer, face, level)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::end() const noexcept { + return std::end(m_data.data); + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::end(u32 layer, u32 face, u32 level) const noexcept { + EXPECTS(m_data.mip_levels > level); + EXPECTS(m_data.faces > face); + EXPECTS(m_data.layers > layer); + + return std::end(data(layer, face, level)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::cend() const noexcept { + return std::cend(m_data.data); + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::cend(u32 layer, u32 face, u32 level) const noexcept { + EXPECTS(m_data.mip_levels > level); + EXPECTS(m_data.faces > face); + EXPECTS(m_data.layers > layer); + + return std::cend(data(layer, face, level)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Image::image_data() const noexcept -> const ImageData& { + return m_data; + } + + ///////////////////////////////////// + ///////////////////////////////////// + constexpr auto get_format_channel_count(Image::Format format) noexcept -> u8 { + switch (format) { + case Image::Format::R8_SNORM: + case Image::Format::R8_UNORM: + case Image::Format::R16_SNORM: + case Image::Format::R16_UNORM: + case Image::Format::R8I: + case Image::Format::R8U: + case Image::Format::R16I: + case Image::Format::R16U: + case Image::Format::R32I: + case Image::Format::R32U: + case Image::Format::R16F: + case Image::Format::R32F: return 1; + + case Image::Format::RG8_SNORM: + case Image::Format::RG8_UNORM: + case Image::Format::RG16_SNORM: + case Image::Format::RG16_UNORM: + case Image::Format::RG8I: + case Image::Format::RG8U: + case Image::Format::RG16I: + case Image::Format::RG16U: + case Image::Format::RG32I: + case Image::Format::RG32U: + case Image::Format::RG16F: + case Image::Format::RG32F: return 2; + + case Image::Format::RGB8_SNORM: + case Image::Format::RGB8_UNORM: + case Image::Format::RGB16_SNORM: + case Image::Format::RGB16_UNORM: + case Image::Format::BGR8_UNORM: + case Image::Format::RGB8I: + case Image::Format::RGB8U: + case Image::Format::RGB16I: + case Image::Format::RGB16U: + case Image::Format::RGB32I: + case Image::Format::RGB32U: + case Image::Format::RGB16F: + case Image::Format::RGB32F: + case Image::Format::SRGB8: + case Image::Format::SBGR8: return 3; + + case Image::Format::RGBA8_SNORM: + case Image::Format::RGBA8_UNORM: + case Image::Format::RGBA16_SNORM: + case Image::Format::RGBA16_UNORM: + case Image::Format::BGRA8_UNORM: + case Image::Format::RGBA8I: + case Image::Format::RGBA8U: + case Image::Format::RGBA16I: + case Image::Format::RGBA16U: + case Image::Format::RGBA32I: + case Image::Format::RGBA32U: + case Image::Format::RGBA16F: + case Image::Format::RGBA32F: + case Image::Format::SRGBA8: + case Image::Format::SBGRA8: return 4; + + default: break; + } + + return 0u; + } + + ///////////////////////////////////// + ///////////////////////////////////// + constexpr auto getSizeof(Image::Format format) noexcept -> u8 { + switch (format) { + case Image::Format::R8_SNORM: + case Image::Format::R8_UNORM: + case Image::Format::RG8_SNORM: + case Image::Format::RG8_UNORM: + case Image::Format::R8I: + case Image::Format::R8U: + case Image::Format::RG8I: + case Image::Format::RG8U: + case Image::Format::RGB8_SNORM: + case Image::Format::RGB8_UNORM: + case Image::Format::BGR8_UNORM: + case Image::Format::RGB8I: + case Image::Format::RGB8U: + case Image::Format::RGBA8_SNORM: + case Image::Format::RGBA8_UNORM: + case Image::Format::RGBA16_SNORM: + case Image::Format::BGRA8_UNORM: + case Image::Format::SRGB8: + case Image::Format::SBGR8: + case Image::Format::SRGBA8: + case Image::Format::SBGRA8: return 1u; + + case Image::Format::R16_SNORM: + case Image::Format::R16_UNORM: + case Image::Format::R16I: + case Image::Format::R16U: + case Image::Format::RG16_SNORM: + case Image::Format::RG16_UNORM: + case Image::Format::RG16I: + case Image::Format::RG16U: + case Image::Format::RG16F: + case Image::Format::RGB16I: + case Image::Format::RGB16U: + case Image::Format::RGB16F: + case Image::Format::RGBA16I: + case Image::Format::RGBA16U: + case Image::Format::RGBA16F: + case Image::Format::R16F: return 2u; + + case Image::Format::R32I: + case Image::Format::R32U: + case Image::Format::R32F: + case Image::Format::RG32I: + case Image::Format::RG32U: + case Image::Format::RG32F: + case Image::Format::RGB16_SNORM: + case Image::Format::RGB32I: + case Image::Format::RGB32U: + case Image::Format::RGB32F: + case Image::Format::RGBA8I: + case Image::Format::RGBA8U: + case Image::Format::RGBA32I: + case Image::Format::RGBA32U: + case Image::Format::RGBA32F: return 4u; + + default: break; + } + + return 0u; + } + +} // namespace stormkit::image + +template +template +auto std::formatter::format(const stormkit::image::Image::Error& error, FormatContext& ctx) + const noexcept -> decltype(ctx.out()) { + auto&& out = ctx.out(); + return format_to(out, "{}", error.str_error); +} diff --git a/modules/stormkit/log.cppm b/modules/stormkit/log.cppm new file mode 100644 index 000000000..2038e9b9a --- /dev/null +++ b/modules/stormkit/log.cppm @@ -0,0 +1,659 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include +#include + +#include + +export module stormkit.log; + +import std; +import frozen; + +import stormkit.core; + +namespace stdr = std::ranges; + +export { + namespace stormkit::log { + struct Module; + enum class Severity : u8 { + INFO = 1, + WARNING = 2, + ERROR = 4, + FATAL = 8, + DEBUG = 16, + }; + + [[nodiscard]] + constexpr auto as_string(Severity severity) noexcept -> string_view; + [[nodiscard]] + constexpr auto to_string(Severity severity) noexcept -> string; + + STORMKIT_LOG_API + auto parse_args(array_view args) noexcept -> void; + + class STORMKIT_LOG_API Logger { + public: + using LogClock = std::chrono::high_resolution_clock; + + explicit Logger(LogClock::time_point start) noexcept; + Logger(LogClock::time_point start, Severity log_level) noexcept; + virtual ~Logger() noexcept; + + virtual auto write(Severity severity, const Module& module, std::string_view string) noexcept -> void = 0; + virtual auto flush() noexcept -> void = 0; + + auto set_log_level(Severity log_level) noexcept -> void; + + [[nodiscard]] + auto start_time() const noexcept -> const LogClock::time_point&; + [[nodiscard]] + auto log_level() const noexcept -> const Severity&; + + [[nodiscard]] + auto mutex() noexcept -> std::mutex&; + + template + [[nodiscard]] + static auto create_logger_instance(Args&&... param_args) noexcept -> T; + + template + [[nodiscard]] + static auto allocate_logger_instance(Args&&... param_args) noexcept -> Heap; + + template + static auto log(Severity severity, + const Module& module, + std::format_string format_string, + Args&&... args) noexcept -> void; + + template + static auto log(Severity severity, std::format_string format_string, Args&&... args) noexcept -> void; + + template + static auto log_runtime(Severity severity, const Module& module, string_view format_string, Args&&... args) noexcept + -> void; + + template + static auto log_runtime(Severity severity, string_view format_string, Args&&... args) noexcept -> void; + + template + static auto dlog(std::format_string format_string, Args&&... args) noexcept -> void; + template + static auto ilog(std::format_string format_string, Args&&... args) noexcept -> void; + template + static auto wlog(std::format_string format_string, Args&&... args) noexcept -> void; + template + static auto elog(std::format_string format_string, Args&&... args) noexcept -> void; + template + static auto flog(std::format_string format_string, Args&&... args) noexcept -> void; + + template + static auto dlog(const Module& module, std::format_string format_string, Args&&... args) noexcept -> void; + template + static auto ilog(const Module& module, std::format_string format_string, Args&&... args) noexcept -> void; + template + static auto wlog(const Module& module, std::format_string format_string, Args&&... args) noexcept -> void; + template + static auto elog(const Module& module, std::format_string format_string, Args&&... args) noexcept -> void; + template + static auto flog(const Module& module, std::format_string format_string, Args&&... args) noexcept -> void; + + template + static auto dlog_runtime(std::string_view format_string, Args&&... args) noexcept -> void; + template + static auto ilog_runtime(std::string_view format_string, Args&&... args) noexcept -> void; + template + static auto wlog_runtime(std::string_view format_string, Args&&... args) noexcept -> void; + template + static auto elog_runtime(std::string_view format_string, Args&&... args) noexcept -> void; + template + static auto flog_runtime(std::string_view format_string, Args&&... args) noexcept -> void; + + template + static auto dlog_runtime(const Module& module, std::string_view format_string, Args&&... args) noexcept -> void; + template + static auto ilog_runtime(const Module& module, std::string_view format_string, Args&&... args) noexcept -> void; + template + static auto wlog_runtime(const Module& module, std::string_view format_string, Args&&... args) noexcept -> void; + template + static auto elog_runtime(const Module& module, std::string_view format_string, Args&&... args) noexcept -> void; + template + static auto flog_runtime(const Module& module, std::string_view format_string, Args&&... args) noexcept -> void; + + [[nodiscard]] + static auto has_logger() noexcept -> bool; + [[nodiscard]] + static auto instance() noexcept -> Logger&; + + protected: + LogClock::time_point m_start_time; + Severity m_log_level; + + std::mutex m_mutex; + }; + + struct Module { + template + auto dlog(std::format_string format_string, Args&&... args) const noexcept -> void; + template + auto ilog(std::format_string format_string, Args&&... args) const noexcept -> void; + template + auto wlog(std::format_string format_string, Args&&... args) const noexcept -> void; + template + auto elog(std::format_string format_string, Args&&... args) const noexcept -> void; + template + auto flog(std::format_string format_string, Args&&... args) const noexcept -> void; + + template + auto dlog_runtime(std::string_view format_string, Args&&... args) const noexcept -> void; + template + auto ilog_runtime(std::string_view format_string, Args&&... args) const noexcept -> void; + template + auto wlog_runtime(std::string_view format_string, Args&&... args) const noexcept -> void; + template + auto elog_runtime(std::string_view format_string, Args&&... args) const noexcept -> void; + template + auto flog_runtime(std::string_view format_string, Args&&... args) const noexcept -> void; + + auto flush() const noexcept -> void; + + string_view name = ""; + }; + + template + [[nodiscard]] + constexpr auto operator""_module() noexcept -> stormkit::log::Module; + + class STORMKIT_LOG_API FileLogger final: public Logger { + public: + FileLogger(LogClock::time_point start, std::filesystem::path path) noexcept; + FileLogger(LogClock::time_point start, std::filesystem::path path, Severity log_level) noexcept; + ~FileLogger() noexcept override; + + FileLogger(const FileLogger&) noexcept = delete; + auto operator=(const FileLogger&) noexcept -> FileLogger& = delete; + + FileLogger(FileLogger&&) noexcept = delete; + auto operator=(FileLogger&&) noexcept -> FileLogger& = delete; + + auto write(Severity severity, const Module& module, std::string_view string) noexcept -> void override; + auto flush() noexcept -> void override; + + private: + string_hash_map m_streams; + + std::filesystem::path m_base_path; + }; + + class STORMKIT_LOG_API ConsoleLogger final: public Logger { + public: + explicit ConsoleLogger(LogClock::time_point start) noexcept; + ConsoleLogger(LogClock::time_point start, Severity log_level) noexcept; + + ConsoleLogger(const ConsoleLogger&) noexcept = delete; + auto operator=(const ConsoleLogger&) noexcept -> ConsoleLogger& = delete; + + ConsoleLogger(ConsoleLogger&&) noexcept = delete; + auto operator=(ConsoleLogger&&) noexcept -> ConsoleLogger& = delete; + + ~ConsoleLogger() noexcept override; + + auto write(Severity severity, const Module& module, std::string_view string) noexcept -> void override; + auto flush() noexcept -> void override; + }; + } // namespace stormkit::log + FLAG_ENUM(stormkit::log::Severity) +} + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +using namespace std::literals; + +namespace stormkit::log { + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto as_string(Severity severity) noexcept -> string_view { + switch (severity) { + case Severity::INFO: return "INFO"; + case Severity::WARNING: return "WARNING"; + case Severity::ERROR: return "ERROR"; + case Severity::FATAL: return "FATAL"; + case Severity::DEBUG: return "DEBUG"; + default: break; + } + + std::unreachable(); + } + + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto to_string(Severity severity) noexcept -> string { + return string { as_string(severity) }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Logger::set_log_level(Severity log_level) noexcept -> void { + m_log_level = log_level; + } + + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Logger::start_time() const noexcept -> const LogClock::time_point& { + return m_start_time; + } + + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Logger::log_level() const noexcept -> const Severity& { + return m_log_level; + } + + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Logger::mutex() noexcept -> std::mutex& { + return m_mutex; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + inline auto Logger::create_logger_instance(Args&&... param_args) noexcept -> T { + static_assert(std::is_base_of::value, "T must inherit Logger"); + + auto time_point = LogClock::now(); + + return T { std::move(time_point), std::forward(param_args)... }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + inline auto Logger::allocate_logger_instance(Args&&... param_args) noexcept -> Heap { + static_assert(std::is_base_of::value, "T must inherit Logger"); + + auto time_point = LogClock::now(); + + return allocate(std::move(time_point), std::forward(param_args)...) + .transform_error(core::monadic::assert("Failed to allocate logger instance")); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + inline auto Logger::log(Severity severity, + const Module& m, + std::format_string format_string, + Args&&... param_args) noexcept -> void { + EXPECTS(has_logger()); + + const auto log_level = instance().log_level(); + if (not check_flag_bit(log_level, severity)) return; + + auto size = std::formatted_size(format_string, std::forward(param_args)...); + + if (size <= 64) { + thread_local auto memory_buffer = array {}; + const auto end_it = std::format_to(stdr::begin(memory_buffer), + std::move(format_string), + std::forward(param_args)...); + + const auto _ = std::unique_lock(instance().mutex()); + instance().write(severity, m, string_view { stdr::begin(memory_buffer), end_it }); + } else { + auto memory_buffer = dyn_array {}; + memory_buffer.resize(size); + const auto end_it = std::format_to(stdr::begin(memory_buffer), + std::move(format_string), + std::forward(param_args)...); + + const auto _ = std::unique_lock(instance().mutex()); + instance().write(severity, m, string_view { stdr::begin(memory_buffer), end_it }); + } + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Logger::log(Severity severity, std::format_string format_string, Args&&... param_args) noexcept -> void { + log(severity, Module {}, std::move(format_string), std::forward(param_args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + inline auto Logger::log_runtime(Severity severity, + const Module& m, + std::string_view format_string, + Args&&... param_args) noexcept -> void { + EXPECTS(has_logger()); + + struct counter { + usize n { 0 }; + using difference_type = long; + + auto operator*() const noexcept { return std::ignore; } + + auto operator++() noexcept -> counter& { + ++n; + return *this; + } + + auto operator++(int) noexcept -> counter { return counter { n++ }; } + }; + + const auto log_level = instance().log_level(); + if (not check_flag_bit(log_level, severity)) return; + + auto args = std::format_args { std::forward(param_args)... }; + + auto c = counter {}; + c = std::vformat_to(c, format_string, args); + + if (c.n <= 64) { + thread_local auto memory_buffer = array {}; + const auto end_it = std::format_to(stdr::begin(memory_buffer), + std::move(format_string), + std::forward(param_args)...); + + const auto _ = std::unique_lock(instance().mutex()); + instance().write(severity, m, string_view { stdr::begin(memory_buffer), end_it }); + } else { + auto memory_buffer = dyn_array {}; + memory_buffer.resize(c.n); + const auto end_it = std::vformat_to(stdr::begin(memory_buffer), std::move(format_string), args); + + const auto _ = std::unique_lock(instance().mutex()); + instance().write(severity, m, string_view { stdr::begin(memory_buffer), end_it }); + } + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Logger::log_runtime(Severity severity, string_view format_string, Args&&... param_args) noexcept -> void { + log(severity, Module {}, std::move(format_string), std::forward(param_args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_FORCE_INLINE + inline ConsoleLogger::~ConsoleLogger() noexcept = default; + + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_FORCE_INLINE + inline FileLogger::~FileLogger() noexcept = default; + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Logger::dlog(std::format_string format_string, Args&&... args) noexcept -> void { + log(Severity::DEBUG, std::move(format_string), std::forward(args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Logger::ilog(std::format_string format_string, Args&&... args) noexcept -> void { + log(Severity::INFO, std::move(format_string), std::forward(args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Logger::wlog(std::format_string format_string, Args&&... args) noexcept -> void { + log(Severity::WARNING, std::move(format_string), std::forward(args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Logger::elog(std::format_string format_string, Args&&... args) noexcept -> void { + log(Severity::ERROR, std::move(format_string), std::forward(args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Logger::flog(std::format_string format_string, Args&&... args) noexcept -> void { + log(Severity::FATAL, std::move(format_string), std::forward(args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Logger::dlog(const Module& module, std::format_string format_string, Args&&... args) noexcept -> void { + log(Severity::DEBUG, module, std::move(format_string), std::forward(args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Logger::ilog(const Module& module, std::format_string format_string, Args&&... args) noexcept -> void { + log(Severity::INFO, module, std::move(format_string), std::forward(args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Logger::wlog(const Module& module, std::format_string format_string, Args&&... args) noexcept -> void { + log(Severity::WARNING, module, std::move(format_string), std::forward(args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Logger::elog(const Module& module, std::format_string format_string, Args&&... args) noexcept -> void { + log(Severity::ERROR, module, std::move(format_string), std::forward(args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Logger::flog(const Module& module, std::format_string format_string, Args&&... args) noexcept -> void { + log(Severity::FATAL, module, std::move(format_string), std::forward(args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Logger::dlog_runtime(std::string_view format_string, Args&&... args) noexcept -> void { + log_runtime(Severity::DEBUG, std::move(format_string), std::forward(args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Logger::ilog_runtime(std::string_view format_string, Args&&... args) noexcept -> void { + log_runtime(Severity::INFO, std::move(format_string), std::forward(args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Logger::wlog_runtime(std::string_view format_string, Args&&... args) noexcept -> void { + log_runtime(Severity::WARNING, std::move(format_string), std::forward(args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Logger::elog_runtime(std::string_view format_string, Args&&... args) noexcept -> void { + log_runtime(Severity::ERROR, std::move(format_string), std::forward(args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Logger::flog_runtime(std::string_view format_string, Args&&... args) noexcept -> void { + log_runtime(Severity::FATAL, std::move(format_string), std::forward(args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Logger::dlog_runtime(const Module& module, std::string_view format_string, Args&&... args) noexcept -> void { + log_runtime(Severity::DEBUG, module, std::move(format_string), std::forward(args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Logger::ilog_runtime(const Module& module, std::string_view format_string, Args&&... args) noexcept -> void { + log_runtime(Severity::INFO, module, std::move(format_string), std::forward(args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Logger::wlog_runtime(const Module& module, std::string_view format_string, Args&&... args) noexcept -> void { + log_runtime(Severity::WARNING, module, std::move(format_string), std::forward(args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Logger::elog_runtime(const Module& module, std::string_view format_string, Args&&... args) noexcept -> void { + log_runtime(Severity::ERROR, module, std::move(format_string), std::forward(args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Logger::flog_runtime(const Module& module, std::string_view format_string, Args&&... args) noexcept -> void { + log_runtime(Severity::FATAL, module, std::move(format_string), std::forward(args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Module::dlog(std::format_string format_string, Args&&... args) const noexcept -> void { + Logger::dlog(*this, std::move(format_string), std::forward(args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Module::ilog(std::format_string format_string, Args&&... args) const noexcept -> void { + Logger::ilog(*this, std::move(format_string), std::forward(args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Module::wlog(std::format_string format_string, Args&&... args) const noexcept -> void { + Logger::wlog(*this, std::move(format_string), std::forward(args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Module::elog(std::format_string format_string, Args&&... args) const noexcept -> void { + Logger::elog(*this, std::move(format_string), std::forward(args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Module::flog(std::format_string format_string, Args&&... args) const noexcept -> void { + Logger::flog(*this, std::move(format_string), std::forward(args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Module::dlog_runtime(std::string_view format_string, Args&&... args) const noexcept -> void { + Logger::dlog_runtime(*this, std::move(format_string), std::forward(args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Module::ilog_runtime(std::string_view format_string, Args&&... args) const noexcept -> void { + Logger::ilog_runtime(*this, std::move(format_string), std::forward(args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Module::wlog_runtime(std::string_view format_string, Args&&... args) const noexcept -> void { + Logger::wlog_runtime(*this, std::move(format_string), std::forward(args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Module::elog_runtime(std::string_view format_string, Args&&... args) const noexcept -> void { + Logger::elog_runtime(*this, std::move(format_string), std::forward(args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto Module::flog_runtime(std::string_view format_string, Args&&... args) const noexcept -> void { + Logger::flog_runtime(*this, std::move(format_string), std::forward(args)...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Module::flush() const noexcept -> void { + Logger::instance().flush(); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto operator""_module() noexcept -> stormkit::log::Module { + return Module { str.view() }; + } +} // namespace stormkit::log diff --git a/modules/stormkit/log.mpp b/modules/stormkit/log.mpp deleted file mode 100644 index 903e3c560..000000000 --- a/modules/stormkit/log.mpp +++ /dev/null @@ -1,396 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include -#include -#include - -export module stormkit.log; - -import std; -import frozen; - -import stormkit.core; - -export { - namespace stormkit::log { - struct Module; - enum class Severity { - INFO = 1, - WARNING, - ERROR, - FATAL, - DEBUG, - }; - - [[nodiscard]] - constexpr auto as_string(Severity severity) noexcept -> std::string_view; - [[nodiscard]] - constexpr auto to_string(Severity severity) noexcept -> std::string; - - class STORMKIT_API Logger { - public: - using LogClock = std::chrono::high_resolution_clock; - - explicit Logger(LogClock::time_point start) noexcept; - Logger(LogClock::time_point start, Severity log_level) noexcept; - virtual ~Logger() noexcept; - - virtual auto write(Severity severity, const Module& module, CZString string) noexcept -> void = 0; - virtual auto flush() noexcept -> void = 0; - - auto set_log_level(Severity log_level) noexcept -> void; - - [[nodiscard]] - auto start_time() const noexcept -> const LogClock::time_point&; - [[nodiscard]] - auto log_level() const noexcept -> const Severity&; - - template - [[nodiscard]] - static auto create_logger_instance(Args&&... param_args) noexcept -> T; - - template - [[nodiscard]] - static auto allocate_logger_instance(Args&&... param_args) noexcept -> Heap; - - template - static auto log(Severity severity, - const Module& module, - std::string_view format_string, - Args&&... param_args) noexcept -> void; - - template - static auto log(Severity severity, std::string_view format_string, Args&&... param_args) noexcept -> void; - - template - static auto dlog(Args&&... param_args) noexcept -> void; - - template - static auto ilog(Args&&... param_args) noexcept -> void; - - template - static auto wlog(Args&&... param_args) noexcept -> void; - - template - static auto elog(Args&&... param_args) noexcept -> void; - - template - static auto flog(Args&&... param_args) noexcept -> void; - - [[nodiscard]] - static auto has_logger() noexcept -> bool; - [[nodiscard]] - static auto instance() noexcept -> Logger&; - - protected: - LogClock::time_point m_start_time; - Severity m_log_level; - }; - - struct Module { - template - auto dlog(Args&&... args) const noexcept -> void; - - template - auto ilog(Args&&... args) const noexcept -> void; - - template - auto wlog(Args&&... args) const noexcept -> void; - - template - auto elog(Args&&... args) const noexcept -> void; - - template - auto flog(Args&&... args) const noexcept -> void; - - auto flush() const noexcept -> void; - - std::string_view name = ""; - }; - - template - [[nodiscard]] - constexpr auto operator""_module() noexcept -> stormkit::log::Module; - - class STORMKIT_API FileLogger final: public Logger { - public: - FileLogger(LogClock::time_point start, std::filesystem::path path) noexcept; - FileLogger(LogClock::time_point start, std::filesystem::path path, Severity log_level) noexcept; - ~FileLogger() noexcept override; - - FileLogger(const FileLogger&) noexcept = delete; - auto operator=(const FileLogger&) noexcept -> FileLogger& = delete; - - FileLogger(FileLogger&&) noexcept; - auto operator=(FileLogger&&) noexcept -> FileLogger&; - - auto write(Severity severity, const Module& module, CZString string) noexcept -> void override; - auto flush() noexcept -> void override; - - private: - StringHashMap m_streams; - - std::filesystem::path m_base_path; - }; - - class STORMKIT_API ConsoleLogger final: public Logger { - public: - explicit ConsoleLogger(LogClock::time_point start) noexcept; - ConsoleLogger(LogClock::time_point start, Severity log_level) noexcept; - - ConsoleLogger(const ConsoleLogger&) noexcept; - auto operator=(const ConsoleLogger&) noexcept -> ConsoleLogger&; - - ConsoleLogger(ConsoleLogger&&) noexcept; - auto operator=(ConsoleLogger&&) noexcept -> ConsoleLogger&; - - ~ConsoleLogger() noexcept override; - - auto write(Severity severity, const Module& module, CZString string) noexcept -> void override; - auto flush() noexcept -> void override; - }; - } // namespace stormkit::log - FLAG_ENUM(stormkit::log::Severity) -} - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -using namespace std::literals; - -namespace stormkit::log { - //////////////////////////////////////// - //////////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_CONST - inline constexpr auto as_string(Severity severity) noexcept -> std::string_view { - switch (severity) { - case Severity::INFO: return "INFO"; - case Severity::WARNING: return "WARNING"; - case Severity::ERROR: return "ERROR"; - case Severity::FATAL: return "FATAL"; - case Severity::DEBUG: return "DEBUG"; - default: break; - } - - std::unreachable(); - } - - //////////////////////////////////////// - //////////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline constexpr auto to_string(Severity severity) noexcept -> std::string { - return std::string { as_string(severity) }; - } - - //////////////////////////////////////// - //////////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Logger::set_log_level(Severity log_level) noexcept -> void { - m_log_level = log_level; - } - - //////////////////////////////////////// - //////////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline auto Logger::start_time() const noexcept -> const LogClock::time_point& { - return m_start_time; - } - - //////////////////////////////////////// - //////////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline auto Logger::log_level() const noexcept -> const Severity& { - return m_log_level; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_FORCE_INLINE - STORMKIT_PURE - inline auto Logger::create_logger_instance(Args&&... param_args) noexcept -> T { - static_assert(std::is_base_of::value, "T must inherit Logger"); - - auto time_point = LogClock::now(); - - return T { std::move(time_point), std::forward(param_args)... }; - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_FORCE_INLINE - STORMKIT_PURE - auto Logger::allocate_logger_instance(Args&&... param_args) noexcept -> Heap { - static_assert(std::is_base_of::value, "T must inherit Logger"); - - auto time_point = LogClock::now(); - - return allocate(std::move(time_point), std::forward(param_args)...) - .transform_error(core::monadic::assert("Failed to allocate logger instance")); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_FORCE_INLINE - auto Logger::log(Severity severity, const Module& m, std::string_view format_string, Args&&... param_args) noexcept -> void { - EXPECTS(has_logger()); - - const auto format = format_string; - auto memory_buffer = std::string {}; - memory_buffer.reserve(std::size(format_string)); - std::vformat_to(std::back_inserter(memory_buffer), format, std::make_format_args(param_args...)); - - instance().write(severity, m, std::data(memory_buffer)); - } - - //////////////////////////////////////// - //////////////////////////////////////// - STORMKIT_FORCE_INLINE - inline ConsoleLogger::ConsoleLogger(const ConsoleLogger&) noexcept = default; - - //////////////////////////////////////// - //////////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto ConsoleLogger::operator=(const ConsoleLogger&) noexcept -> ConsoleLogger& = default; - - //////////////////////////////////////// - //////////////////////////////////////// - STORMKIT_FORCE_INLINE - inline ConsoleLogger::ConsoleLogger(ConsoleLogger&&) noexcept = default; - - //////////////////////////////////////// - //////////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto ConsoleLogger::operator=(ConsoleLogger&&) noexcept -> ConsoleLogger& = default; - - //////////////////////////////////////// - //////////////////////////////////////// - STORMKIT_FORCE_INLINE - inline ConsoleLogger::~ConsoleLogger() noexcept = default; - - //////////////////////////////////////// - //////////////////////////////////////// - STORMKIT_FORCE_INLINE - inline FileLogger::FileLogger(FileLogger&&) noexcept = default; - - //////////////////////////////////////// - //////////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto FileLogger::operator=(FileLogger&&) noexcept -> FileLogger& = default; - - //////////////////////////////////////// - //////////////////////////////////////// - STORMKIT_FORCE_INLINE - inline FileLogger::~FileLogger() noexcept = default; - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_FORCE_INLINE - inline auto Logger::log(Severity severity, std::string_view format_string, Args&&... param_args) noexcept -> void { - log(severity, Module {}, format_string, std::forward(param_args)...); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_FORCE_INLINE - inline auto Logger::dlog(Args&&... param_args) noexcept -> void { - log(Severity::DEBUG, std::forward(param_args)...); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_FORCE_INLINE - inline auto Logger::ilog(Args&&... param_args) noexcept -> void { - log(Severity::INFO, std::forward(param_args)...); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_FORCE_INLINE - inline auto Logger::wlog(Args&&... param_args) noexcept -> void { - log(Severity::WARNING, std::forward(param_args)...); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_FORCE_INLINE - inline auto Logger::elog(Args&&... param_args) noexcept -> void { - log(Severity::ERROR, std::forward(param_args)...); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_FORCE_INLINE - inline auto Logger::flog(Args&&... param_args) noexcept -> void { - log(Severity::FATAL, std::forward(param_args)...); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_FORCE_INLINE - inline auto Module::dlog(Args&&... args) const noexcept -> void { - Logger::dlog(*this, std::forward(args)...); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_FORCE_INLINE - inline auto Module::ilog(Args&&... args) const noexcept -> void { - Logger::ilog(*this, std::forward(args)...); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_FORCE_INLINE - inline auto Module::wlog(Args&&... args) const noexcept -> void { - Logger::wlog(*this, std::forward(args)...); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_FORCE_INLINE - inline auto Module::elog(Args&&... args) const noexcept -> void { - Logger::elog(*this, std::forward(args)...); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_FORCE_INLINE - inline auto Module::flog(Args&&... args) const noexcept -> void { - Logger::flog(*this, std::forward(args)...); - } - - //////////////////////////////////////// - //////////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Module::flush() const noexcept -> void { - Logger::instance().flush(); - } - - //////////////////////////////////////// - //////////////////////////////////////// - template - STORMKIT_FORCE_INLINE - STORMKIT_CONST - inline constexpr auto operator""_module() noexcept -> stormkit::log::Module { - return Module { str.view() }; - } -} // namespace stormkit::log diff --git a/modules/stormkit/lua.cppm b/modules/stormkit/lua.cppm new file mode 100644 index 000000000..dcc67ce83 --- /dev/null +++ b/modules/stormkit/lua.cppm @@ -0,0 +1,118 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include +#include + +#include +#include + +export module stormkit.lua; + +import std; + +import stormkit.core; + +namespace stdfs = std::filesystem; + +export namespace stormkit::lua { + struct Modules { + bool log = false; + bool image = false; + bool entities = false; + bool wsi = false; + bool gpu = false; + }; + + class STORMKIT_LUA_API Engine { + public: + using InitUserLibrariesClosure = std::function; + + ~Engine() noexcept; + + Engine(const Engine&) = delete; + auto operator=(const Engine&) -> Engine& = delete; + + Engine(Engine&& other) noexcept; + auto operator=(Engine&& other) noexcept -> Engine&; + + static auto load_from_file(stdfs::path path, + Modules modules = {}, + InitUserLibrariesClosure init_user_libraries = monadic::noop()) noexcept -> Engine; + auto run() noexcept -> sol::state; + + static auto run(stdfs::path file, + Modules modules = {}, + InitUserLibrariesClosure init_user_libraries = monadic::noop()) noexcept -> void; + + private: + Engine(Modules&&, InitUserLibrariesClosure&&) noexcept; + + auto load(stdfs::path&&) noexcept -> void; + + auto init_libraries(sol::state&) noexcept -> void; + + Modules m_modules; + InitUserLibrariesClosure m_init_user_libraries; + + dyn_array m_script; + }; + + template + auto luacall(const sol::protected_function& function, Args&&... args) noexcept -> decltype(function()); +} // namespace stormkit::lua + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit::lua { + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_FORCE_INLINE + inline Engine::Engine(Engine&& other) noexcept = default; + + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Engine::operator=(Engine&& other) noexcept -> Engine& = default; + + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_FORCE_INLINE + inline Engine::~Engine() noexcept = default; + + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Engine::load_from_file(stdfs::path file, Modules modules, InitUserLibrariesClosure init_user_libraries) noexcept + -> Engine { + auto engine = Engine { std::move(modules), std::move(init_user_libraries) }; + engine.load(std::move(file)); + return engine; + } + + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Engine::run(stdfs::path file, Modules modules, InitUserLibrariesClosure init_user_libraries) noexcept -> void { + Engine::load_from_file(std::move(file), std::move(modules), std::move(init_user_libraries)).run(); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + inline auto luacall(const sol::protected_function& function, Args&&... args) noexcept -> decltype(function()) { + auto result = function(std::forward(args)...); + if (not result.valid()) + ensures(false, + std::format("lua runtime error!\n-----------------------------------------\n{}", + sol::error { result }.what())); + return result; + } +} // namespace stormkit::lua diff --git a/modules/stormkit/main.mpp b/modules/stormkit/main.cppm similarity index 96% rename from modules/stormkit/main.mpp rename to modules/stormkit/main.cppm index c0a353901..339576753 100644 --- a/modules/stormkit/main.mpp +++ b/modules/stormkit/main.cppm @@ -1,9 +1,9 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -export module stormkit.main; - -// clang-format off - -// clang-format on +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +export module stormkit.main; + +// clang-format off + +// clang-format on diff --git a/modules/stormkit/test.mpp b/modules/stormkit/test.cppm similarity index 60% rename from modules/stormkit/test.mpp rename to modules/stormkit/test.cppm index da3f552ec..0efc2e4bc 100644 --- a/modules/stormkit/test.mpp +++ b/modules/stormkit/test.cppm @@ -16,36 +16,36 @@ import stormkit.core; import std; import frozen; +using namespace stormkit; + export namespace test { struct TestFunc { - std::string name; + string name; std::function func; }; struct TestSuiteHolder { - auto hasTest(std::string_view name) noexcept; - auto runTest(std::string_view name) noexcept; - auto runTests() noexcept; - std::string name; - std::vector tests; - std::source_location location; + auto hasTest(string_view name) noexcept; + auto runTest(string_view name) noexcept; + auto runTests() noexcept; + string name; + dyn_array tests; + std::source_location location; }; struct TestSuite { - TestSuite(std::string&& name, - std::vector&& tests, + TestSuite(string&& name, + dyn_array&& tests, const std::source_location& location = std::source_location::current()) noexcept; }; - auto expects(bool cond, - std::string_view message, - const std::source_location& location = std::source_location::current()) noexcept; + auto expects(bool cond, string_view message, const std::source_location& location = std::source_location::current()) noexcept; - auto parse_args(std::span args) noexcept -> void; + auto parse_args(array_view args) noexcept -> void; auto runTests() noexcept -> int; } // namespace test -module :private; +// module :private; using namespace std::literals; @@ -58,29 +58,25 @@ namespace test { }; struct TestState { - std::vector> test_suites; - bool verbose = false; - bool failed = false; - bool plain = false; - std::optional requested_test = std::nullopt; + dyn_array> test_suites; + bool verbose = false; + bool failed = false; + bool plain = false; + std::optional requested_test = std::nullopt; }; namespace { - constexpr auto StyleMap = frozen::make_unordered_map({ - { Status::Passed, - stormkit::ConsoleStyle { .fg = stormkit::ConsoleColor::BLACK, - .bg = stormkit::ConsoleColor::GREEN } }, - { Status::NotPassed, - stormkit::ConsoleStyle { .fg = stormkit::ConsoleColor::BLACK, - .bg = stormkit::ConsoleColor::RED } }, + constexpr auto StyleMap = frozen::make_unordered_map({ + { Status::Passed, ConsoleStyle { .fg = ConsoleColor::BLACK, .bg = ConsoleColor::GREEN } }, + { Status::NotPassed, ConsoleStyle { .fg = ConsoleColor::BLACK, .bg = ConsoleColor::RED } }, { Status::CheckMark, - stormkit::ConsoleStyle { - .fg = stormkit::ConsoleColor::GREEN, - } }, + ConsoleStyle { + .fg = ConsoleColor::GREEN, + } }, { Status::CrossMark, - stormkit::ConsoleStyle { - .fg = stormkit::ConsoleColor::RED, - } }, + ConsoleStyle { + .fg = ConsoleColor::RED, + } }, }); constexpr auto passed = StyleMap.at(Status::Passed) | "Passed"sv; @@ -91,7 +87,7 @@ namespace test { auto state = TestState {}; - auto TestSuiteHolder::hasTest(std::string_view _name) noexcept { + auto TestSuiteHolder::hasTest(string_view _name) noexcept { for (auto&& test : tests) { if (test.name == _name) return true; } @@ -99,7 +95,7 @@ namespace test { return false; } - auto TestSuiteHolder::runTest(std::string_view _name) noexcept { + auto TestSuiteHolder::runTest(string_view _name) noexcept { for (auto&& test : tests) { if (test.name == _name) { if (state.verbose) std::println(" running test {}", test.name); @@ -140,17 +136,11 @@ namespace test { return failed_tests == 0; } - TestSuite::TestSuite(std::string&& _name, - std::vector&& tests, - const std::source_location& location) noexcept { - state.test_suites.emplace_back(std::make_unique(std::move(_name), - std::move(tests), - location)); + TestSuite::TestSuite(string&& _name, dyn_array&& tests, const std::source_location& location) noexcept { + state.test_suites.emplace_back(std::make_unique(std::move(_name), std::move(tests), location)); } - auto expects(bool cond, - std::string_view message, - const std::source_location& location) noexcept { + auto expects(bool cond, string_view message, const std::source_location& location) noexcept { if (not cond) [[unlikely]] { state.failed = true; if (state.verbose) { @@ -163,16 +153,16 @@ namespace test { } } - auto split(std::string_view string, char delim) noexcept -> std::vector { - auto output = std::vector {}; + auto split(string_view str, char delim) noexcept -> dyn_array { + auto output = dyn_array {}; auto first = std::size_t { 0u }; - while (first < string.size()) { - const auto second = string.find_first_of(delim, first); + while (first < str.size()) { + const auto second = str.find_first_of(delim, first); - if (first != second) output.emplace_back(string.substr(first, second - first)); + if (first != second) output.emplace_back(str.substr(first, second - first)); - if (second == std::string_view::npos) break; + if (second == string_view::npos) break; first = second + 1; } @@ -180,7 +170,7 @@ namespace test { return output; } - auto parse_args(std::span args) noexcept -> void { + auto parse_args(array_view args) noexcept -> void { for (auto&& arg : args) { if (arg == "--verbose" or arg == "-v") state.verbose = true; else if (arg == "--plain" or arg == "-p") @@ -201,9 +191,7 @@ namespace test { } } else for (auto&& suite : state.test_suites) { - std::println("Running test suite {} ({} tests)", - suite->name, - std::size(suite->tests)); + std::println("Running test suite {} ({} tests)", suite->name, std::size(suite->tests)); if (not suite->runTests()) return_code = -1; } diff --git a/modules/stormkit/wsi.mpp b/modules/stormkit/wsi.cppm similarity index 96% rename from modules/stormkit/wsi.mpp rename to modules/stormkit/wsi.cppm index 259a58ee6..44ecc9ae2 100644 --- a/modules/stormkit/wsi.mpp +++ b/modules/stormkit/wsi.cppm @@ -1,12 +1,12 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -export module stormkit.wsi; - -export import :core; -export import :monitor; -export import :window; -// export import :event_handler; -export import :keyboard; -export import :mouse; +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +export module stormkit.wsi; + +export import :core; +export import :monitor; +export import :window; +// export import :event_handler; +export import :keyboard; +export import :mouse; diff --git a/modules/stormkit/wsi/core.mpp b/modules/stormkit/wsi/core.cppm similarity index 71% rename from modules/stormkit/wsi/core.mpp rename to modules/stormkit/wsi/core.cppm index 4f5eeaa2f..2a81971ec 100644 --- a/modules/stormkit/wsi/core.mpp +++ b/modules/stormkit/wsi/core.cppm @@ -6,6 +6,8 @@ module; #include +#include + export module stormkit.wsi:core; import std; @@ -24,14 +26,14 @@ export namespace stormkit::wsi { SWITCH, }; - constexpr auto as_string(WM wm) noexcept -> std::string_view; + constexpr auto as_string(WM wm) noexcept -> string_view; + constexpr auto to_string(WM wm) noexcept -> string; - STORMKIT_API - auto parse_args(std::span args) noexcept -> void; + STORMKIT_WSI_API + auto parse_args(array_view args) noexcept -> void; [[nodiscard]] - STORMKIT_API - auto wm() noexcept -> WM; + STORMKIT_WSI_API auto wm() noexcept -> WM; } // namespace stormkit::wsi //////////////////////////////////////////////////////////////////// @@ -42,7 +44,7 @@ namespace stormkit::wsi { //////////////////////////////////////// //////////////////////////////////////// STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto as_string(WM wm) noexcept -> std::string_view { + constexpr auto as_string(WM wm) noexcept -> string_view { switch (wm) { case WM::WIN32: return "WM::WIN32"; case WM::WAYLAND: return "WM::WAYLAND"; @@ -57,4 +59,11 @@ namespace stormkit::wsi { std::unreachable(); } + + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto to_string(WM wm) noexcept -> string { + return string { as_string(wm) }; + } } // namespace stormkit::wsi diff --git a/modules/stormkit/wsi/keyboard.mpp b/modules/stormkit/wsi/keyboard.cppm similarity index 94% rename from modules/stormkit/wsi/keyboard.mpp rename to modules/stormkit/wsi/keyboard.cppm index a248fb5d9..e01b8b205 100644 --- a/modules/stormkit/wsi/keyboard.mpp +++ b/modules/stormkit/wsi/keyboard.cppm @@ -142,7 +142,8 @@ export namespace stormkit::wsi { UNKNOWN = std::numeric_limits::max(), }; - constexpr auto as_string(Key key) noexcept -> std::string_view; + constexpr auto as_string(Key key) noexcept -> string_view; + constexpr auto to_string(Key key) noexcept -> string; } // namespace stormkit::wsi //////////////////////////////////////////////////////////////////// @@ -152,7 +153,8 @@ export namespace stormkit::wsi { namespace stormkit::wsi { //////////////////////////////////////// //////////////////////////////////////// - constexpr auto as_string(Key key) noexcept -> std::string_view { + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto as_string(Key key) noexcept -> string_view { switch (key) { case Key::A: return "Key::A"; case Key::B: return "Key::B"; @@ -282,4 +284,11 @@ namespace stormkit::wsi { } std::unreachable(); } + + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto to_string(Key key) noexcept -> string { + return string { as_string(key) }; + } } // namespace stormkit::wsi diff --git a/modules/stormkit/wsi/monitor.mpp b/modules/stormkit/wsi/monitor.cppm similarity index 54% rename from modules/stormkit/wsi/monitor.mpp rename to modules/stormkit/wsi/monitor.cppm index 1cd06e18b..4f4087d4c 100644 --- a/modules/stormkit/wsi/monitor.mpp +++ b/modules/stormkit/wsi/monitor.cppm @@ -7,6 +7,8 @@ module; #include #include +#include + export module stormkit.wsi:monitor; import std; @@ -21,30 +23,34 @@ export { PRIMARY, }; - Flags flags = Flags::NONE; - std::string name; + Flags flags = Flags::NONE; + string name; - std::vector> extents; - u32 scale_factor = 1; + dyn_array extents; + u32 scale_factor = 1; [[nodiscard]] constexpr auto operator<=>(const Monitor& other) const noexcept -> std::strong_ordering; + [[nodiscard]] + constexpr auto operator==(const Monitor& other) const noexcept -> bool; + void* native_handle = nullptr; }; - constexpr auto as_string(Monitor::Flags flags) noexcept -> std::string_view; + constexpr auto as_string(Monitor::Flags flags) noexcept -> string_view; + constexpr auto to_string(Monitor::Flags flags) noexcept -> string; + + auto to_string(const Monitor& monitor) noexcept -> string; template - auto format_as(const Monitor&, FormatContext&) noexcept -> FormatContext::iterator; + auto format_as(const Monitor& monitor, FormatContext& ctx) noexcept -> decltype(ctx.out()); [[nodiscard]] - STORMKIT_API - auto get_monitors(bool update = false) noexcept -> std::span; + STORMKIT_WSI_API auto get_monitors(bool update = false) noexcept -> array_view; [[nodiscard]] - STORMKIT_API - auto get_primary_monitor() noexcept -> const Monitor&; + STORMKIT_WSI_API auto get_primary_monitor() noexcept -> const Monitor&; } // namespace stormkit::wsi FLAG_ENUM(stormkit::wsi::Monitor::Flags); @@ -58,8 +64,7 @@ namespace stormkit::wsi { //////////////////////////////////////// //////////////////////////////////////// STORMKIT_PURE - constexpr auto Monitor::operator<=>(const Monitor& other) const noexcept - -> std::strong_ordering { + constexpr auto Monitor::operator<=>(const Monitor& other) const noexcept -> std::strong_ordering { if (auto ret = flags <=> other.flags; ret != 0) return ret; #ifdef STORMKIT_COMPILER_CLANG @@ -82,11 +87,26 @@ namespace stormkit::wsi { return std::strong_ordering::equal; } + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_PURE + constexpr auto Monitor::operator==(const Monitor& other) const noexcept -> bool { + if (flags != other.flags) return false; + if (name != other.name) return false; + if (std::size(extents) != std::size(other.extents)) return false; + for (auto i : range(std::size(extents))) { + if (extents[i].width != other.extents[i].width) return false; + if (extents[i].height != other.extents[i].height) return false; + } + + return true; + } + //////////////////////////////////////// //////////////////////////////////////// STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto as_string(Monitor::Flags wm) noexcept -> std::string_view { - switch (wm) { + constexpr auto as_string(Monitor::Flags flags) noexcept -> string_view { + switch (flags) { case Monitor::Flags::NONE: return "Monitor::Flags::NONE"; case Monitor::Flags::PRIMARY: return "Monitor::Flags::PRIMARY"; default: break; @@ -95,19 +115,30 @@ namespace stormkit::wsi { std::unreachable(); } + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto to_string(Monitor::Flags flags) noexcept -> string { + return string { as_string(flags) }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto to_string(const Monitor& monitor) noexcept -> string { + return std::format("{}", monitor); + } + //////////////////////////////////////// //////////////////////////////////////// template STORMKIT_FORCE_INLINE - inline auto format_as(const Monitor& monitor, FormatContext& ctx) noexcept - -> FormatContext::iterator { - auto&& out = ctx.out(); - return format_to( - out, - "{{ Monitor: .name = {}, .flags = {}, .extents = {}, .scale_factor = {} }}", - monitor.name, - monitor.flags, - monitor.extents, - monitor.scale_factor); + inline auto format_as(const Monitor& monitor, FormatContext& ctx) noexcept -> decltype(ctx.out()) { + return std::format_to(ctx.out(), + "[Monitor name: {}, flags: {}, extents: {}, scale_factor: {}]", + monitor.name, + monitor.flags, + monitor.extents, + monitor.scale_factor); } } // namespace stormkit::wsi diff --git a/modules/stormkit/wsi/mouse.mpp b/modules/stormkit/wsi/mouse.cppm similarity index 83% rename from modules/stormkit/wsi/mouse.mpp rename to modules/stormkit/wsi/mouse.cppm index 7aa6573ec..77c1f4af2 100644 --- a/modules/stormkit/wsi/mouse.mpp +++ b/modules/stormkit/wsi/mouse.cppm @@ -33,7 +33,8 @@ export namespace stormkit::wsi { BUTTON_12, }; - constexpr auto as_string(MouseButton button) noexcept -> std::string_view; + constexpr auto as_string(MouseButton button) noexcept -> string_view; + constexpr auto to_string(MouseButton button) noexcept -> string; } // namespace stormkit::wsi //////////////////////////////////////////////////////////////////// @@ -44,7 +45,7 @@ namespace stormkit::wsi { //////////////////////////////////////// //////////////////////////////////////// STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto as_string(MouseButton button) noexcept -> std::string_view { + constexpr auto as_string(MouseButton button) noexcept -> string_view { switch (button) { case MouseButton::LEFT: return "MouseButton::LEFT"; case MouseButton::RIGHT: return "MouseButton::RIGHT"; @@ -66,4 +67,11 @@ namespace stormkit::wsi { std::unreachable(); } + + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto to_string(MouseButton button) noexcept -> string { + return string { as_string(button) }; + } } // namespace stormkit::wsi diff --git a/modules/stormkit/wsi/window.mpp b/modules/stormkit/wsi/window.cppm similarity index 86% rename from modules/stormkit/wsi/window.mpp rename to modules/stormkit/wsi/window.cppm index 61041452a..d2f491cd8 100644 --- a/modules/stormkit/wsi/window.mpp +++ b/modules/stormkit/wsi/window.cppm @@ -8,6 +8,8 @@ module; #include #include +#include + export module stormkit.wsi:window; import std; @@ -36,7 +38,8 @@ export { RESIZEABLE = 0b100, EXTERNAL_CONTEXT = 0b1000, }; - constexpr auto as_string(WindowFlag button) noexcept -> std::string_view; + constexpr auto as_string(WindowFlag button) noexcept -> string_view; + constexpr auto to_string(WindowFlag button) noexcept -> string; enum class EventType : u8 { NONE = 0, @@ -53,7 +56,8 @@ export { ACTIVATE, DEACTIVATE, }; - constexpr auto as_string(EventType type) noexcept -> std::string_view; + constexpr auto as_string(EventType type) noexcept -> string_view; + constexpr auto to_string(EventType type) noexcept -> string; using NativeHandle = void*; @@ -65,8 +69,8 @@ export { using std::function::function; }; - struct ResizedEventFunc: std::function&)> { - using std::function&)>::function; + struct ResizedEventFunc: std::function { + using std::function::function; }; struct RestoredEventFunc: std::function { @@ -85,16 +89,16 @@ export { using std::function::function; }; - struct MouseButtonDownEventFunc: std::function { - using std::function::function; + struct MouseButtonDownEventFunc: std::function { + using std::function::function; }; - struct MouseButtonUpEventFunc: std::function { - using std::function::function; + struct MouseButtonUpEventFunc: std::function { + using std::function::function; }; - struct MouseMovedEventFunc: std::function { - using std::function::function; + struct MouseMovedEventFunc: std::function { + using std::function::function; }; struct DeactivateEventFunc: std::function { @@ -121,24 +125,23 @@ export { DeactivateEventFunc, ActivateEventFunc>; - class STORMKIT_API Window { + class STORMKIT_WSI_API Window { public: ~Window() noexcept; Window(Window&&) noexcept; auto operator=(Window&&) noexcept -> Window&; - static auto open(std::string title, - const math::Extent2& size, - WindowFlag flags) noexcept -> Window; + static auto open(string title, const math::uextent2& size, WindowFlag flags) noexcept -> Window; + static auto allocate_and_open(string title, const math::uextent2& size, WindowFlag flags) noexcept -> Heap; auto close() noexcept -> void; [[nodiscard]] auto is_open() const noexcept -> bool; auto handle_events() noexcept -> void; - auto clear(const rgbcolor& color = colors::BLACK) noexcept -> void; - auto fill_framebuffer(std::span> colors) noexcept -> void; + auto clear(const ucolor_rgb& color = colors::BLACK) noexcept -> void; + auto fill_framebuffer(array_view colors) noexcept -> void; template auto on(T&& callback) noexcept -> void; @@ -157,21 +160,20 @@ export { auto current_monitor() const noexcept -> const Monitor&; [[nodiscard]] - auto title() const noexcept -> const std::string&; - auto set_title(std::string title) noexcept -> void; + auto title() const noexcept -> const string&; + auto set_title(string title) noexcept -> void; - auto set_extent(const math::Extent2& extent) noexcept -> void; + auto set_extent(const math::uextent2& extent) noexcept -> void; [[nodiscard]] - auto extent() const noexcept -> const math::Extent2&; + auto extent() const noexcept -> const math::uextent2&; auto set_fullscreen(bool fullscreen) noexcept -> void; auto toggle_fullscreen() noexcept -> void; [[nodiscard]] auto fullscreen() const noexcept -> bool; - auto confine_mouse(bool confined = true, u8 mouse_id = GLOBAL_MOUSE_ID) noexcept - -> void; + auto confine_mouse(bool confined = true, u8 mouse_id = GLOBAL_MOUSE_ID) noexcept -> void; auto unconfine_mouse(u8 mouse_id = GLOBAL_MOUSE_ID) noexcept -> void; auto toggle_confined_mouse(u8 mouse_id = GLOBAL_MOUSE_ID) noexcept -> void; [[nodiscard]] @@ -189,14 +191,12 @@ export { [[nodiscard]] auto is_mouse_hidden(u8 mouse_id = GLOBAL_MOUSE_ID) const noexcept -> bool; - auto set_relative_mouse(bool enabled = true, u8 mouse_id = GLOBAL_MOUSE_ID) noexcept - -> void; + auto set_relative_mouse(bool enabled = true, u8 mouse_id = GLOBAL_MOUSE_ID) noexcept -> void; auto toggle_relative_mouse(u8 mouse_id = GLOBAL_MOUSE_ID) noexcept -> void; [[nodiscard]] auto is_mouse_relative(u8 mouse_id = GLOBAL_MOUSE_ID) const noexcept -> bool; - auto set_key_repeat(bool enabled = true, u8 keyboard_id = GLOBAL_KEYBOARD_ID) noexcept - -> void; + auto set_key_repeat(bool enabled = true, u8 keyboard_id = GLOBAL_KEYBOARD_ID) noexcept -> void; auto disable_key_repeat(u8 keyboard_id = GLOBAL_KEYBOARD_ID) noexcept -> void; auto toggle_key_repeat(u8 keyboard_id = GLOBAL_KEYBOARD_ID) noexcept -> void; [[nodiscard]] @@ -208,8 +208,7 @@ export { [[nodiscard]] auto is_virtual_keyboard_visible() const noexcept -> bool; - auto set_mouse_position(const math::vec2i& position, - u8 mouse_id = GLOBAL_MOUSE_ID) noexcept -> void; + auto set_mouse_position(const math::ivec2& position, u8 mouse_id = GLOBAL_MOUSE_ID) noexcept -> void; [[nodiscard]] auto native_handle() const noexcept -> NativeHandle; @@ -254,19 +253,18 @@ namespace stdr = std::ranges; using namespace std::literals; namespace stormkit::wsi { + //////////////////////////////////////// + //////////////////////////////////////// STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto as_string(WindowFlag flag) noexcept -> std::string_view { - using Pair = std::pair; - static constexpr auto MAPPING = core::generate_substitutions_as_string_for< - WindowFlag, - 4, - WindowFlag::DEFAULT, - 67>("WindowFlag::", - { - Pair { WindowFlag::DEFAULT, "DEFAULT"sv }, - Pair { WindowFlag::BORDERLESS, "BORDERLESS"sv }, - Pair { WindowFlag::RESIZEABLE, "RESIZEABLE"sv }, - Pair { WindowFlag::EXTERNAL_CONTEXT, "EXTERNAL_CONTEXT"sv }, + constexpr auto as_string(WindowFlag flag) noexcept -> string_view { + using Pair = std::pair; + static constexpr auto MAPPING = core::generate_substitutions_as_string_for( + "WindowFlag::", + { + Pair { WindowFlag::DEFAULT, "DEFAULT"sv }, + Pair { WindowFlag::BORDERLESS, "BORDERLESS"sv }, + Pair { WindowFlag::RESIZEABLE, "RESIZEABLE"sv }, + Pair { WindowFlag::EXTERNAL_CONTEXT, "EXTERNAL_CONTEXT"sv }, }); const auto it = stdr::find_if(MAPPING, [&flag](auto&& pair) { return pair.first == flag; }); @@ -274,10 +272,17 @@ namespace stormkit::wsi { return it->second; } + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto to_string(WindowFlag flag) noexcept -> string { + return string { as_string(flag) }; + } + //////////////////////////////////////// //////////////////////////////////////// STORMKIT_FORCE_INLINE STORMKIT_CONST - constexpr auto as_string(EventType type) noexcept -> std::string_view { + constexpr auto as_string(EventType type) noexcept -> string_view { switch (type) { case EventType::NONE: return "EventType::NONE"; case EventType::CLOSED: return "EventType::CLOSED"; @@ -297,6 +302,13 @@ namespace stormkit::wsi { std::unreachable(); } + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto to_string(EventType type) noexcept -> string { + return string { as_string(type) }; + } + //////////////////////////////////////// //////////////////////////////////////// template diff --git a/src/core/contract.mpp b/src/core/contract.cppm similarity index 79% rename from src/core/contract.mpp rename to src/core/contract.cppm index f5fbf979a..9b112ef99 100644 --- a/src/core/contract.mpp +++ b/src/core/contract.cppm @@ -21,10 +21,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// - auto assert_base(bool cond, - AssertType type, - std::string_view message, - const std::source_location& location) noexcept -> void { + auto assert_base(bool cond, AssertType type, string_view message, const std::source_location& location) noexcept -> void { if constexpr (STORMKIT_ASSERT == 1) { constexpr auto ASSERTION_PREFIX = ConsoleStyle { .fg = ConsoleColor::BRIGHT_RED, @@ -43,10 +40,11 @@ namespace stormkit { inline namespace core { ConsoleStyle { .fg = ConsoleColor::BLUE } | location.line(), ConsoleStyle { .fg = ConsoleColor::BLUE } | location.column(), ConsoleStyle { .fg = ConsoleColor::YELLOW } | location.function_name(), - ConsoleStyle { .fg = ConsoleColor::RED, - .modifiers = StyleModifier::BOLD } - | message); + ConsoleStyle { .fg = ConsoleColor::RED, .modifiers = StyleModifier::BOLD } | message); std::fflush(get_stderr()); +#if defined(__cpp_lib_debugging) and __cpp_lib_debugging >= 202311L + if (std::is_debugger_present) { std::breakpoint(); } +#endif std::terminate(); } diff --git a/src/core/darwin/threadutils.cpp b/src/core/darwin/threadutils.cpp index 61d1bf0e2..377d04402 100644 --- a/src/core/darwin/threadutils.cpp +++ b/src/core/darwin/threadutils.cpp @@ -13,39 +13,39 @@ import :parallelism.threadutils; namespace stormkit { inline namespace core { //////////////////////////////////////// //////////////////////////////////////// - auto set_current_thread_name(std::string_view name) noexcept -> void { + auto set_current_thread_name(string_view name) noexcept -> void { setCurrentNSThreadName(std::data(name)); } //////////////////////////////////////// //////////////////////////////////////// - auto set_thread_name(std::thread&, std::string_view) noexcept -> void { + auto set_thread_name(std::thread&, string_view) noexcept -> void { // auto id = thread.native_handle(); // details::set_thread_name(id, name); } //////////////////////////////////////// //////////////////////////////////////// - auto set_thread_name(std::jthread&, std::string_view) noexcept -> void { + auto set_thread_name(std::jthread&, string_view) noexcept -> void { // auto id = thread.native_handle(); // details::set_thread_name(id, name); } //////////////////////////////////////// //////////////////////////////////////// - auto get_current_thread_name() noexcept -> std::string { + auto get_current_thread_name() noexcept -> string { return {}; } //////////////////////////////////////// //////////////////////////////////////// - auto get_thread_name(std::thread&) noexcept -> std::string { + auto get_thread_name(std::thread&) noexcept -> string { return {}; } //////////////////////////////////////// //////////////////////////////////////// - auto get_thread_name(std::jthread&) noexcept -> std::string { + auto get_thread_name(std::jthread&) noexcept -> string { return {}; } }} // namespace stormkit::core diff --git a/src/core/dynamic_loader.cpp b/src/core/dynamic_loader.cpp index 061f80b7e..b792a89ef 100644 --- a/src/core/dynamic_loader.cpp +++ b/src/core/dynamic_loader.cpp @@ -57,7 +57,7 @@ namespace stormkit { ///////////////////////////////////// ///////////////////////////////////// - auto DynamicLoader::do_get_func(std::string_view name) const -> Expected { + auto DynamicLoader::do_get_func(string_view name) const -> Expected { EXPECTS(m_library_handle); #ifdef STORMKIT_OS_WINDOWS auto func = ::GetProcAddress(std::bit_cast(m_library_handle), std::data(name)); diff --git a/src/core/linux/threadutils.cpp b/src/core/linux/threadutils.cpp index 9784da45a..fd7bee48f 100644 --- a/src/core/linux/threadutils.cpp +++ b/src/core/linux/threadutils.cpp @@ -1,6 +1,7 @@ module; #include +#include module stormkit.core; @@ -10,57 +11,56 @@ namespace stormkit { inline namespace core { namespace details { //////////////////////////////////////// //////////////////////////////////////// - auto set_thread_name(pthread_t id, std::string_view name) noexcept -> void { + auto set_thread_name(pthread_t id, string_view name) noexcept -> void { pthread_setname_np(id, std::data(name)); } //////////////////////////////////////// //////////////////////////////////////// - auto get_thread_name(pthread_t id) noexcept -> std::string { - auto name = std::array {}; + auto get_thread_name(pthread_t id) noexcept -> string { + auto name = array {}; pthread_getname_np(id, std::data(name), std::size(name)); - return std::string { std::begin(name), std::begin(name) + std::strlen(std::data(name)) }; + return string { std::begin(name), std::begin(name) + std::strlen(std::data(name)) }; } } // namespace details //////////////////////////////////////// //////////////////////////////////////// - auto set_current_thread_name(std::string_view name) noexcept -> void { - const auto id = pthread_self(); - details::set_thread_name(id, name); + auto set_current_thread_name(string_view name) noexcept -> void { + prctl(PR_SET_NAME, stdr::data(name), 0, 0, 0); } //////////////////////////////////////// //////////////////////////////////////// - auto set_thread_name(std::thread& thread, std::string_view name) noexcept -> void { + auto set_thread_name(std::thread& thread, string_view name) noexcept -> void { const auto id = thread.native_handle(); details::set_thread_name(id, name); } //////////////////////////////////////// //////////////////////////////////////// - auto set_thread_name(std::jthread& thread, std::string_view name) noexcept -> void { + auto set_thread_name(std::jthread& thread, string_view name) noexcept -> void { const auto id = thread.native_handle(); details::set_thread_name(id, name); } //////////////////////////////////////// //////////////////////////////////////// - auto get_current_thread_name() noexcept -> std::string { + auto get_current_thread_name() noexcept -> string { const auto id = pthread_self(); return details::get_thread_name(id); } //////////////////////////////////////// //////////////////////////////////////// - auto get_thread_name(std::thread& thread) noexcept -> std::string { + auto get_thread_name(std::thread& thread) noexcept -> string { const auto id = thread.native_handle(); return details::get_thread_name(id); } //////////////////////////////////////// //////////////////////////////////////// - auto get_thread_name(std::jthread& thread) noexcept -> std::string { + auto get_thread_name(std::jthread& thread) noexcept -> string { const auto id = thread.native_handle(); return details::get_thread_name(id); } diff --git a/src/core/posix/shmbuffer.cpp b/src/core/posix/shmbuffer.cpp index 5fe0c002b..b7aa4cf4b 100644 --- a/src/core/posix/shmbuffer.cpp +++ b/src/core/posix/shmbuffer.cpp @@ -30,13 +30,17 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// - auto SHMBuffer::allocate_buffer() noexcept -> std::expected { - const auto shm_access = (check_flag_bit(m_access, Access::WRITE) ? O_RDWR : O_RDONLY) + auto SHMBuffer::do_init(PrivateTag, usize size, string name, io::Access access) noexcept + -> std::expected { + m_size = size; + m_name = std::move(name); + m_access = access; + const auto shm_access = (check_flag_bit(m_access, io::Access::WRITE) ? O_RDWR : O_RDONLY) | ((m_handle != nullptr) ? O_TRUNC : O_CREAT); const auto mode = init_by([access = m_access](auto& mode) noexcept { - if (check_flag_bit(access, Access::READ)) mode |= S_IRUSR; - if (check_flag_bit(access, Access::WRITE)) mode |= S_IWUSR; + if (check_flag_bit(access, io::Access::READ)) mode |= S_IRUSR; + if (check_flag_bit(access, io::Access::WRITE)) mode |= S_IWUSR; }); m_handle = std::bit_cast(iptr { shm_open(stdr::data(m_name), shm_access, mode) }); @@ -53,8 +57,8 @@ namespace stormkit { inline namespace core { }; const auto prot_access = init_by([access = m_access](auto& prot_access) noexcept { - if (check_flag_bit(access, Access::READ)) prot_access |= PROT_READ; - if (check_flag_bit(access, Access::WRITE)) prot_access |= PROT_WRITE; + if (check_flag_bit(access, io::Access::READ)) prot_access |= PROT_READ; + if (check_flag_bit(access, io::Access::WRITE)) prot_access |= PROT_WRITE; }); auto buf = mmap(nullptr, m_size, prot_access, MAP_SHARED, fd, 0); @@ -63,7 +67,7 @@ namespace stormkit { inline namespace core { std::error_code { as(errno), std::system_category() } }; - m_data = { std::bit_cast(buf), m_size }; + m_data = { std::bit_cast(buf), m_size }; return {}; } diff --git a/modules/stormkit/core/utils/signal_handler.mpp b/src/core/signal_handler.cpp similarity index 53% rename from modules/stormkit/core/utils/signal_handler.mpp rename to src/core/signal_handler.cpp index fcf3ee7e4..edb8efe36 100644 --- a/modules/stormkit/core/utils/signal_handler.mpp +++ b/src/core/signal_handler.cpp @@ -1,28 +1,25 @@ module; +#include #include #include -export module stormkit.core:utils.signal_handler; +module stormkit.core; import std; import :utils.stracktrace; -export namespace stormkit { inline namespace core { - STORMKIT_API auto setup_signal_handler() noexcept -> void; -}} // namespace stormkit::core - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - namespace stormkit { inline namespace core { + ///////////////////////////////////// + ///////////////////////////////////// extern "C" auto terminate_handler() noexcept -> void { print_stacktrace(3); } - extern "C" auto signalHandler(int signum) noexcept -> void { + ///////////////////////////////////// + ///////////////////////////////////// + extern "C" auto signal_handler(int signum) noexcept -> void { std::signal(signum, SIG_DFL); print_stacktrace(3); std::raise(SIGABRT); @@ -32,6 +29,6 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// auto setup_signal_handler() noexcept -> void { std::set_terminate(&terminate_handler); - std::signal(SIGSEGV, &signalHandler); + std::signal(SIGSEGV, &signal_handler); } }} // namespace stormkit::core diff --git a/src/core/stacktrace.cpp b/src/core/stacktrace.cpp index b2e5dde4d..4bf8f2b20 100644 --- a/src/core/stacktrace.cpp +++ b/src/core/stacktrace.cpp @@ -20,8 +20,8 @@ import :console; import :string.operations; namespace stormkit { inline namespace core { - auto prettify(std::string_view str) -> std::string { - auto out = std::string { str }; + auto prettify(string_view str) -> string { + auto out = string { str }; out = replace(out, "::__1::", "::"); out = replace(out, "::$_0::", "::"); out = replace(out, "__invoke", "invoke"); @@ -31,13 +31,13 @@ namespace stormkit { inline namespace core { out = replace(out, "basic_string_view>", "string_view"); out = replace(out, "basic_string_view >", "string_view"); out = replace(out, - "basic_string, " + "basic_string, " "std::allocator>", - "string"); + "string"); out = replace(out, - "basic_string, " + "basic_string, " "std::allocator >", - "string"); + "string"); return out; } @@ -63,14 +63,14 @@ namespace stormkit { inline namespace core { continue; } #ifdef STORMKIT_COMPILER_MSSTL - const auto frame_str = std::to_string(frame); - auto splitted = split(frame_str, "+"); - const auto address = from_string(splitted[1].substr(2), 16) - .transform_error([stderr, &splitted](auto&& err) noexcept { + const auto frame_str = std::to_string(frame); + auto splitted = split(frame_str, "+"); + const auto address = from_string(splitted[1].substr(2), 16) + .transform_error([stderr, &splitted](auto&& err) noexcept { std::println(stderr, "Failed to parse {}, reason: {}", splitted[0], err); return 0; - }) - .value(); + }) + .value(); splitted = split(splitted[0], "!"); const auto formatted_symbol = prettify((stdr::size(splitted) >= 2) ? "\n in " + (YELLOW_TEXT_STYLE | splitted[1]).render() @@ -83,11 +83,11 @@ namespace stormkit { inline namespace core { const auto frame_str = std::to_string(frame); const auto splitted = split(frame_str, ": "); const auto address = from_string(splitted[0].substr(2), 16) - .transform_error([stderr, &splitted](auto&& err) noexcept { + .transform_error([stderr, &splitted](auto&& err) noexcept { std::println(stderr, "Failed to parse {}, reason: {}", splitted[0], err); return 0; - }) - .value(); + }) + .value(); const auto formatted_symbol = prettify((stdr::size(splitted) > 2) ? "\n in " + (YELLOW_TEXT_STYLE | splitted[1]).render() diff --git a/src/core/threadpool.cpp b/src/core/threadpool.cpp index 8e90b2371..1dd5e2be8 100644 --- a/src/core/threadpool.cpp +++ b/src/core/threadpool.cpp @@ -6,20 +6,22 @@ module stormkit.core; import std; +namespace stdr = std::ranges; + namespace stormkit { ///////////////////////////////////// ///////////////////////////////////// - ThreadPool::ThreadPool(ThreadPool&& other) noexcept { + ThreadPool::ThreadPool(ThreadPool&& other) noexcept + : m_worker_count { other.m_worker_count }, m_running_task_counter { m_worker_count } { + wait_idle(); + other.wait_idle(); + auto lock = std::scoped_lock { other.m_mutex }; - m_worker_count = std::exchange(other.m_worker_count, 0u); - m_tasks = std::move(other.m_tasks); + m_tasks = std::move(other.m_tasks); - m_workers.reserve(m_worker_count); - for (const auto i : range(m_worker_count)) { - auto& thread = m_workers.emplace_back([this] { worker_main(); }); - set_thread_name(thread, std::format("StormKit:WorkerThread:{}", i)); - } + m_workers.clear(); + spawn_workers(); } ///////////////////////////////////// @@ -28,28 +30,28 @@ namespace stormkit { if (&other == this) [[unlikely]] return *this; - auto lock1 = std::unique_lock { other.m_mutex, std::defer_lock }; + wait_idle(); + other.wait_idle(); + + auto lock1 = std::unique_lock { m_mutex, std::defer_lock }; auto lock2 = std::unique_lock { other.m_mutex, std::defer_lock }; std::lock(lock1, lock2); join_all(); - m_worker_count = std::exchange(other.m_worker_count, 0u); + m_worker_count = other.m_worker_count; m_tasks = std::move(other.m_tasks); - m_workers.reserve(m_worker_count); - for (const auto i : range(m_worker_count)) { - auto& thread = m_workers.emplace_back([this] { worker_main(); }); - set_thread_name(thread, std::format("StormKit:WorkerThread:{}", i)); - } + m_workers.clear(); + spawn_workers(); return *this; } ///////////////////////////////////// ///////////////////////////////////// - auto ThreadPool::join_all() -> void { - for (const auto _ : range(m_worker_count)) post_task(Task::Type::Terminate, [] {}, ThreadPool::NoFuture); + auto ThreadPool::join_all() noexcept -> void { + for (const auto _ : range(m_worker_count)) post_task(Task::Type::Terminate, [] {}, ThreadPool::NO_FUTURE); for (auto& thread : m_workers) if (thread.joinable()) thread.join(); @@ -57,21 +59,59 @@ namespace stormkit { ///////////////////////////////////// ///////////////////////////////////// - auto ThreadPool::worker_main() noexcept -> void { + auto ThreadPool::wait_idle(bool cancel_tasks) noexcept -> void { + if (cancel_tasks) { + auto _ = std::unique_lock { m_mutex }; + while (not stdr::empty(m_tasks)) m_tasks.pop(); + } + + for (;;) { + { + auto _ = std::unique_lock { m_mutex }; + if (stdr::empty(m_tasks)) break; + } + std::this_thread::yield(); + } + + auto count = worker_count(); + for (;;) { + while (m_running_task_counter.try_acquire()) --count; + + if (count == 0) break; + + std::this_thread::yield(); + } + + for (auto _ : range(worker_count())) m_running_task_counter.release(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + auto ThreadPool::worker_main(i32 id) noexcept -> void { + set_current_thread_name(std::format("stormkit:worker_thread:{}", id)); for (;;) { auto task = Task {}; { auto lock = std::unique_lock { m_mutex }; - if (std::empty(m_tasks)) m_work_signal.wait(lock, [this] { return not std::empty(m_tasks); }); - + m_work_signal.wait(lock, [this] { return not std::empty(m_tasks); }); task = std::move(m_tasks.front()); m_tasks.pop(); } + m_running_task_counter.acquire(); task.work(); + m_running_task_counter.release(); if (task.type == Task::Type::Terminate) return; } } + + ///////////////////////////////////// + ///////////////////////////////////// + auto ThreadPool::spawn_workers() noexcept -> void { + m_workers.reserve(m_worker_count); + + for (auto i : range(m_worker_count)) m_workers.emplace_back(bind_front(&ThreadPool::worker_main, this, i)); + } } // namespace stormkit diff --git a/src/core/win32/shmbuffer.cpp b/src/core/win32/shmbuffer.cpp index 70ad0d1e8..a8ea6c76d 100644 --- a/src/core/win32/shmbuffer.cpp +++ b/src/core/win32/shmbuffer.cpp @@ -26,9 +26,12 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// - auto SHMBuffer::allocate_buffer() noexcept -> std::expected { - const auto page_access = (check_flag_bit(m_access, Access::WRITE) ? PAGE_READWRITE - : PAGE_READONLY); + auto SHMBuffer::do_init(PrivateTag, usize size, string name, io::Access access) noexcept + -> std::expected { + m_size = size; + m_name = std::move(name); + m_access = access; + const auto page_access = (check_flag_bit(m_access, io::Access::WRITE) ? PAGE_READWRITE : PAGE_READONLY); // TODO handle reallocation m_handle = ::CreateFileMapping(INVALID_HANDLE_VALUE, @@ -43,8 +46,8 @@ namespace stormkit { inline namespace core { }; const auto file_access = init_by([access = m_access](auto& file_access) noexcept { - if (check_flag_bit(access, Access::READ)) file_access |= FILE_MAP_READ; - if (check_flag_bit(access, Access::WRITE)) file_access |= FILE_MAP_WRITE; + if (check_flag_bit(access, io::Access::READ)) file_access |= FILE_MAP_READ; + if (check_flag_bit(access, io::Access::WRITE)) file_access |= FILE_MAP_WRITE; }); auto buf = ::MapViewOfFile(m_handle, file_access, 0, 0, as(m_size)); @@ -53,7 +56,7 @@ namespace stormkit { inline namespace core { std::error_code { as(GetLastError()), std::system_category() } }; - m_data = { std::bit_cast(buf), m_size }; + m_data = { std::bit_cast(buf), m_size }; return {}; } diff --git a/src/core/win32/threadutils.cpp b/src/core/win32/threadutils.cpp index b2cdcab42..88bb97c0d 100644 --- a/src/core/win32/threadutils.cpp +++ b/src/core/win32/threadutils.cpp @@ -25,7 +25,7 @@ namespace stormkit { inline namespace core { namespace details { //////////////////////////////////////// //////////////////////////////////////// - auto set_thread_name(HANDLE handle, std::string_view name) noexcept -> void { + auto set_thread_name(HANDLE handle, string_view name) noexcept -> void { const auto id = ::GetThreadId(handle); auto info = ThreadNameInfo { .szName = std::data(name), .dwThreadId = id }; @@ -39,11 +39,11 @@ namespace stormkit { inline namespace core { //////////////////////////////////////// //////////////////////////////////////// - auto get_thread_name(HANDLE handle) noexcept -> std::string { + auto get_thread_name(HANDLE handle) noexcept -> string { auto data = PWSTR { nullptr }; const auto hr = GetThreadDescription(handle, &data); - auto out = std::string {}; + auto out = string {}; if (SUCCEEDED(hr)) { out = wide_to_ascii(data); @@ -63,42 +63,42 @@ namespace stormkit { inline namespace core { //////////////////////////////////////// //////////////////////////////////////// - auto set_current_thread_name(std::string_view name) noexcept -> void { + auto set_current_thread_name(string_view name) noexcept -> void { const auto handle = ::GetCurrentThread(); details::set_thread_name(handle, name); } //////////////////////////////////////// //////////////////////////////////////// - auto set_thread_name(std::thread& thread, std::string_view name) noexcept -> void { + auto set_thread_name(std::thread& thread, string_view name) noexcept -> void { const auto handle = details::getThreadHandle(thread); details::set_thread_name(handle, name); } //////////////////////////////////////// //////////////////////////////////////// - auto set_thread_name(std::jthread& thread, std::string_view name) noexcept -> void { + auto set_thread_name(std::jthread& thread, string_view name) noexcept -> void { const auto handle = details::getThreadHandle(thread); details::set_thread_name(handle, name); } //////////////////////////////////////// //////////////////////////////////////// - auto get_current_thread_name() noexcept -> std::string { + auto get_current_thread_name() noexcept -> string { const auto handle = ::GetCurrentThread(); return details::get_thread_name(handle); } //////////////////////////////////////// //////////////////////////////////////// - auto get_thread_name(std::thread& thread) noexcept -> std::string { + auto get_thread_name(std::thread& thread) noexcept -> string { const auto handle = details::getThreadHandle(thread); return details::get_thread_name(handle); } //////////////////////////////////////// //////////////////////////////////////// - auto get_thread_name(std::jthread& thread) noexcept -> std::string { + auto get_thread_name(std::jthread& thread) noexcept -> string { const auto handle = details::getThreadHandle(thread); return details::get_thread_name(handle); } diff --git a/src/entities/entity_manager.cpp b/src/entities/entity_manager.cpp index 56b4c1d9a..1a4868fa7 100644 --- a/src/entities/entity_manager.cpp +++ b/src/entities/entity_manager.cpp @@ -18,35 +18,34 @@ namespace stdv = std::views; namespace stormkit::entities { ///////////////////////////////////// ///////////////////////////////////// - EntityManager::EntityManager() = default; + EntityManager::EntityManager() noexcept = default; ///////////////////////////////////// ///////////////////////////////////// - EntityManager::EntityManager(EntityManager&&) = default; + EntityManager::EntityManager(EntityManager&&) noexcept = default; ///////////////////////////////////// ///////////////////////////////////// - auto EntityManager::operator=(EntityManager&&) -> EntityManager& = default; + auto EntityManager::operator=(EntityManager&&) noexcept -> EntityManager& = default; ///////////////////////////////////// ///////////////////////////////////// - EntityManager::~EntityManager() = default; + EntityManager::~EntityManager() noexcept = default; ///////////////////////////////////// ///////////////////////////////////// - auto EntityManager::make_entity() -> Entity { + auto EntityManager::make_entity() noexcept -> Entity { const auto entity = [this]() { if (stdr::empty(m_free_entities)) return m_next_valid_entity++; else { - auto entity = m_free_entities.front(); - m_free_entities.pop(); + auto entity = m_free_entities.back(); + m_free_entities.pop_back(); return entity; } }(); m_added_entities.emplace(entity); m_updated_entities.emplace(entity); - m_registered_components_for_entities[entity] = {}; m_message_bus.push(Message { ADDED_ENTITY_MESSAGE_ID, { entity } }); return entity; @@ -54,7 +53,7 @@ namespace stormkit::entities { ///////////////////////////////////// ///////////////////////////////////// - auto EntityManager::destroy_entity(Entity entity) -> void { + auto EntityManager::destroy_entity(Entity entity) noexcept -> void { EXPECTS(entity != INVALID_ENTITY); if (has_entity(entity)) { @@ -65,7 +64,7 @@ namespace stormkit::entities { ///////////////////////////////////// ///////////////////////////////////// - auto EntityManager::destroy_all_entities() -> void { + auto EntityManager::destroy_all_entities() noexcept -> void { for (auto&& e : entities()) { m_removed_entities.emplace(e); m_message_bus.push(Message { REMOVED_ENTITY_MESSAGE_ID, { e } }); @@ -74,7 +73,7 @@ namespace stormkit::entities { ///////////////////////////////////// ///////////////////////////////////// - auto EntityManager::has_entity(Entity entity) const -> bool { + auto EntityManager::has_entity(Entity entity) const noexcept -> bool { EXPECTS(entity != INVALID_ENTITY); return stdr::any_of(entities(), monadic::is_equal(entity)) or stdr::any_of(m_added_entities, monadic::is_equal(entity)); @@ -82,50 +81,104 @@ namespace stormkit::entities { ///////////////////////////////////// ///////////////////////////////////// - auto EntityManager::has_component(Entity entity, Component::Type type) const -> bool { - EXPECTS(entity != INVALID_ENTITY and type != Component::INVALID_TYPE); + auto EntityManager::destroy_component(Entity entity, ComponentType type) noexcept -> void { + EXPECTS(has_entity(entity)); + EXPECTS(has_component(entity, type)); - return stdr::any_of(m_registered_components_for_entities.at(entity), monadic::is_equal(type)); + auto it = stdr::find_if(m_components, [type](const auto& pair) noexcept { return pair.type == type; }); + + auto& [_, size, entities, components, delete_func] = *it; + auto component_it = stdr::begin(components); + + for (;;) { + auto e = *std::launder(std::bit_cast(&*component_it)); + + if (e == entity) break; + + component_it += as(sizeof(Entity) + size); + } + + delete_func(&*component_it + sizeof(Entity)); + + components.erase(component_it, component_it + as(size)); + + auto&& [begin, end] = stdr::remove(entities, entity); + entities.erase(begin, end); + + m_updated_entities.emplace(entity); } ///////////////////////////////////// ///////////////////////////////////// - auto EntityManager::step(Secondf delta) -> void { - for (auto entity : m_removed_entities) { - auto it = m_registered_components_for_entities.find(entity); - // a this point, all entities should be valid - ensures(it != stdr::cend(m_registered_components_for_entities)); + auto EntityManager::has_component(Entity entity, ComponentType type) const noexcept -> bool { + EXPECTS(entity != INVALID_ENTITY); - for (auto&& key : it->second | stdv::transform([entity](auto&& type) { return component_key_for(entity, type); })) - m_components.erase(key); + auto it = stdr::find_if(m_components, [&type](const auto& pair) noexcept { return pair.type == type; }); + if (it == stdr::cend(m_components)) return false; - m_entities.erase(entity); + auto& [_, size, entities, _, _] = *it; - remove_from_systems(entity); + return stdr::any_of(entities, monadic::is_equal(entity)); + } - if (not stdr::any_of(m_added_entities, monadic::is_equal(entity))) m_free_entities.push(entity); + ///////////////////////////////////// + ///////////////////////////////////// + auto EntityManager::flush() noexcept -> void { + if (not stdr::empty(m_removed_entities)) { + if (stdr::size(m_entities) == stdr::size(m_removed_entities)) { + for (auto& [_, size, entities, data, delete_func] : m_components) { + for (auto component_it = stdr::data(data); component_it != stdr::data(data) + stdr::size(data); + component_it += as(sizeof(Entity) + size)) + delete_func(component_it + sizeof(Entity)); + + entities.clear(); + data.clear(); + } + + merge(m_free_entities, m_entities); + m_entities.clear(); + m_removed_entities.clear(); + } else { + for (auto entity : m_removed_entities) { + const auto components_types = components_types_of(entity); + + for (auto t : components_types) destroy_component(entity, t); + + auto&& [begin, end] = stdr::remove(m_entities, entity); + m_entities.erase(begin, end); + + remove_from_systems(entity); + + if (not stdr::any_of(m_added_entities, monadic::is_equal(entity))) m_free_entities.emplace_back(entity); + } + m_removed_entities.clear(); + } } - m_removed_entities.clear(); - stdr::for_each(m_added_entities, [this](auto&& entity) { m_entities.emplace(entity); }); + stdr::for_each(m_added_entities, [this](auto&& entity) noexcept { m_entities.emplace_back(entity); }); m_added_entities.clear(); - stdr::for_each(m_updated_entities, [this](auto&& entity) { purpose_to_systems(entity); }); + stdr::for_each(m_updated_entities, [this](auto&& entity) noexcept { purpose_to_systems(entity); }); m_updated_entities.clear(); while (!m_message_bus.empty()) { - for (auto& system : m_systems) system->on_message_received(m_message_bus.top()); + for (auto& system : m_systems) system.on_message_received(*this, m_message_bus.top()); m_message_bus.pop(); } + } - for (auto& system : m_systems) system->pre_update(); - for (auto& system : m_systems) system->update(delta); - for (auto& system : m_systems) system->post_update(); + ///////////////////////////////////// + ///////////////////////////////////// + auto EntityManager::step(fsecond delta) noexcept -> void { + flush(); + for (auto& system : m_systems) system.pre_update(*this); + for (auto& system : m_systems) system.update(*this, delta); + for (auto& system : m_systems) system.post_update(*this); } ///////////////////////////////////// ///////////////////////////////////// - auto EntityManager::purpose_to_systems(Entity e) -> void { + auto EntityManager::purpose_to_systems(Entity e) noexcept -> void { EXPECTS(e != INVALID_ENTITY); const auto reliable_system_filter = [e, this](auto&& system) { @@ -135,27 +188,28 @@ namespace stormkit::entities { return true; }; - stdr::for_each(systems() | stdv::filter(reliable_system_filter), [e](auto&& system) { system->add_entity(e); }); + stdr::for_each(systems() | stdv::filter(reliable_system_filter), [e](auto&& system) noexcept { system->add_entity(e); }); } ///////////////////////////////////// ///////////////////////////////////// - auto EntityManager::remove_from_systems(Entity e) -> void { + auto EntityManager::remove_from_systems(Entity e) noexcept -> void { EXPECTS(e != INVALID_ENTITY); - for (auto& s : m_systems) { s->remove_entity(e); } + for (auto& s : m_systems) { s.remove_entity(e); } } ///////////////////////////////////// ///////////////////////////////////// - auto EntityManager::get_needed_entities(System& system) -> void { - const auto reliable_entity_filter = [&system, this](auto&& entity) { + auto EntityManager::get_needed_entities(System& system) noexcept -> void { + const auto reliable_entity_filter = [&system, this](auto&& entity) noexcept { for (auto component_type : system.components_used()) if (not has_component(entity, component_type)) return false; return true; }; - stdr::for_each(entities() | stdv::filter(reliable_entity_filter), [&system](auto&& e) { system.add_entity(e); }); + stdr::for_each(entities() | stdv::filter(reliable_entity_filter), [&system](auto&& e) noexcept { system.add_entity(e); }); } + } // namespace stormkit::entities diff --git a/src/entities/system.cpp b/src/entities/system.cpp index 43f67c976..a021e3def 100644 --- a/src/entities/system.cpp +++ b/src/entities/system.cpp @@ -15,8 +15,8 @@ import stormkit.core; namespace stormkit::entities { ///////////////////////////////////// ///////////////////////////////////// - System::System(EntityManager& manager, u32 priority, ComponentTypes types) - : m_manager { as_ref(manager) }, m_priority { priority }, m_types { std::move(types) } { + System::System(string name, ComponentTypes types, Closures&& closures) noexcept + : m_name { std::move(name) }, m_types { std::move(types) }, m_closures { std::move(closures) } { } ///////////////////////////////////// @@ -29,31 +29,46 @@ namespace stormkit::entities { ///////////////////////////////////// ///////////////////////////////////// - System::~System() = default; + System::~System() noexcept = default; ///////////////////////////////////// ///////////////////////////////////// - auto System::pre_update() -> void { + auto System::add_entity(Entity e) noexcept -> void { + EXPECTS(e != INVALID_ENTITY); + + m_entities.emplace_back(e); } ///////////////////////////////////// ///////////////////////////////////// - auto System::post_update() -> void { + auto System::remove_entity(Entity e) noexcept -> void { + EXPECTS(e != INVALID_ENTITY); + + const auto [begin, end] = stdr::remove(m_entities, e); + m_entities.erase(begin, end); } ///////////////////////////////////// ///////////////////////////////////// - auto System::add_entity(Entity e) -> void { - EXPECTS(e != INVALID_ENTITY); + auto System::pre_update(EntityManager& manager) noexcept -> void { + m_closures.pre_update(manager, m_entities); + } - m_entities.insert(e); + ///////////////////////////////////// + ///////////////////////////////////// + auto System::update(EntityManager& manager, fsecond delta) noexcept -> void { + m_closures.update(manager, delta, m_entities); } ///////////////////////////////////// ///////////////////////////////////// - auto System::remove_entity(Entity e) -> void { - EXPECTS(e != INVALID_ENTITY); + auto System::post_update(EntityManager& manager) noexcept -> void { + m_closures.post_update(manager, m_entities); + } - m_entities.erase(e); + ///////////////////////////////////// + ///////////////////////////////////// + auto System::on_message_received(EntityManager& manager, const Message& message) noexcept -> void { + m_closures.on_message_received(manager, message, m_entities); } } // namespace stormkit::entities diff --git a/src/gpu/core/debug_callback.cpp b/src/gpu/core/debug_callback.cpp new file mode 100644 index 000000000..54c35b841 --- /dev/null +++ b/src/gpu/core/debug_callback.cpp @@ -0,0 +1,51 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +#include +#include + +module stormkit.gpu.core; + +import std; + +import stormkit.core; +import stormkit.log; + +namespace stdr = std::ranges; +namespace stdv = std::views; + +namespace stormkit::gpu { + template class DebugCallbackInterface; + template class DebugCallbackInterface; + + ///////////////////////////////////// + ///////////////////////////////////// + auto DebugCallbackImplementation::do_init(PrivateTag, const CreateInfo& create_info) noexcept -> Expected { + constexpr auto severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT + | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT + | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + + constexpr auto type = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT + | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT + | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + + const auto vk_create_info = VkDebugUtilsMessengerCreateInfoEXT { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, + .pNext = nullptr, + .flags = 0, + .messageSeverity = severity, + .messageType = type, + .pfnUserCallback = create_info.messenger_closure, + .pUserData = create_info.user_data, + }; + + m_vk_handle = Try(vk::call_checked< + VkDebugUtilsMessengerEXT>(vkCreateDebugUtilsMessengerEXT, owner(), &vk_create_info, nullptr)); + Return {}; + } +} // namespace stormkit::gpu diff --git a/src/gpu/core/device.cpp b/src/gpu/core/device.cpp index 69caee254..8e5763cb6 100644 --- a/src/gpu/core/device.cpp +++ b/src/gpu/core/device.cpp @@ -6,8 +6,11 @@ module; #include #include +#include + #include +#include #include module stormkit.gpu.core; @@ -22,24 +25,27 @@ using namespace std::literals; namespace stdr = std::ranges; namespace stdv = std::views; +namespace cmonadic = stormkit::core::monadic; + namespace { - constexpr auto RAYTRACING_EXTENSIONS = std::array { - VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, - VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, - VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME, - VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME, - VK_KHR_SPIRV_1_4_EXTENSION_NAME, - VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME, - VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME, - }; - - constexpr auto BASE_EXTENSIONS = std::array { - VK_KHR_MAINTENANCE_3_EXTENSION_NAME, - // "VK_KHR_maintenance4"sv, "VK_KHR_maintenance5"sv, "VK_KHR_maintenance6"sv - }; - constexpr auto SWAPCHAIN_EXTENSIONS = std::array { - VK_KHR_SWAPCHAIN_EXTENSION_NAME, - }; + constexpr auto RAYTRACING_EXTENSIONS = to_array({ + VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, + VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, + VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME, + VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME, + VK_KHR_SPIRV_1_4_EXTENSION_NAME, + VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME, + VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME, + }); + + constexpr auto BASE_EXTENSIONS = to_array({ + VK_KHR_MAINTENANCE_3_EXTENSION_NAME, + VK_KHR_MAINTENANCE_4_EXTENSION_NAME, + VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME, + }); + constexpr auto SWAPCHAIN_EXTENSIONS = to_array({ + VK_KHR_SWAPCHAIN_EXTENSION_NAME, + }); auto vma_import_functions_from_volk(const VmaAllocatorCreateInfo* pAllocatorCreateInfo, VolkDeviceTable* device_table, @@ -192,108 +198,128 @@ namespace { } // namespace namespace stormkit::gpu { - NAMED_LOGGER(device_logger, "stormkit.gpu:core.Device") - - template - constexpr auto find_queue() { - return [](const auto& family) static noexcept { - return core::check_flag_bit(family.flags, flag) and (not core::check_flag_bit(family.flags, no_flag) and ...); - }; + ///////////////////////////////////// + ///////////////////////////////////// + template + auto DeviceInterface::wait_idle() const noexcept -> Expected { + const auto device_table = this->device_table(); + Try(vk::call_checked(device_table.vkDeviceWaitIdle, *this)); + Return {}; } ///////////////////////////////////// ///////////////////////////////////// - auto Device::do_init(const Instance& instance, const Info& info) noexcept -> Expected { - const auto& queue_families = m_physical_device->queue_families(); - - struct Queue_ { - std::optional id = std::nullopt; - u32 count = 0u; - std::array _ = {}; // padding - QueueFlag flags = QueueFlag {}; - }; - - const auto raster_queue = [&queue_families]() -> Queue_ { - const auto it = stdr::find_if(queue_families, find_queue()); - if (it == stdr::cend(queue_families)) return {}; - - return { - .id = as(std::distance(stdr::cbegin(queue_families), it)), - .count = it->count, - .flags = it->flags, - }; - }(); - - const auto compute_queue = [&queue_families]() -> Queue_ { - const auto it = stdr::find_if(queue_families, find_queue()); - if (it == stdr::cend(queue_families)) return {}; - - return { .id = as(std::distance(stdr::cbegin(queue_families), it)), .count = it->count, .flags = it->flags }; - }(); + template + auto DeviceInterface::wait_for_fences(array_view fences, + bool wait_all, + const std::chrono::milliseconds& timeout) const noexcept -> Expected { + const auto device_table = this->device_table(); + const auto _fences = transform(fences, vk::monadic::to_vk()); + + const auto result = Try((vk::call_checked( + device_table.vkWaitForFences, + *this, + stdr::size(_fences), + stdr::data(_fences), + wait_all, + std::chrono::duration_cast(timeout).count()))); + return vk::from_vk(result); + } - const auto transfert_queue = [&queue_families]() -> Queue_ { - const auto it = stdr::find_if(queue_families, - find_queue()); - if (it == stdr::cend(queue_families)) return {}; + ///////////////////////////////////// + ///////////////////////////////////// + template + auto DeviceInterface::reset_fences(array_view fences) const noexcept -> Expected { + const auto device_table = this->device_table(); - return { .id = as(std::distance(stdr::cbegin(queue_families), it)), .count = it->count, .flags = it->flags }; - }(); + const auto _fences = transform(fences, vk::monadic::to_vk()); + Try(vk::call_checked(device_table.vkResetFences, *this, stdr::size(_fences), stdr::data(_fences))); + Return {}; + } - const auto queues = [&] { - auto q = std::vector {}; - q.reserve(3); + ///////////////////////////////////// + ///////////////////////////////////// + template + auto DeviceInterface::set_object_name(u64 object, DebugObjectType type, string_view name) const noexcept + -> Expected { + if (not vkSetDebugUtilsObjectNameEXT) return {}; - if (raster_queue.id) q.push_back(&raster_queue); - if (compute_queue.id) q.push_back(&compute_queue); - if (transfert_queue.id) q.push_back(&transfert_queue); + const auto info = VkDebugUtilsObjectNameInfoEXT { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, + .pNext = nullptr, + .objectType = vk::to_vk(type), + .objectHandle = object, + .pObjectName = stdr::data(name), + }; - return q; - }(); + Try(vk::call_checked(vkSetDebugUtilsObjectNameEXT, *this, &info)); + Return {}; + } - auto priorities = std::vector> {}; - priorities.reserve(stdr::size(queues)); + template class DeviceInterface; + template class DeviceInterface; - const auto queue_create_infos = transform(queues, [&priorities](auto queue) { + ///////////////////////////////////// + ///////////////////////////////////// + auto DeviceImplementation::do_init(PrivateTag, const CreateInfo& info) noexcept -> Expected { + const auto physical_device = owner(); + const auto& queue_families = physical_device.queue_families(); + + auto i = 0_u32; + auto priorities = dyn_array> {}; + priorities.reserve(stdr::size(queue_families)); + const auto queue_create_infos = transform(queue_families, [this, &i, &priorities](const auto& family) noexcept { auto& priority = priorities.emplace_back(); + priority.resize(family.count, 1.f); - priority.resize(queue->count, 1.f); + m_queue_entries.emplace_back(QueueEntry { + .id = i, + .count = family.count, + .flags = family.flags, + }); return VkDeviceQueueCreateInfo { .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, .pNext = nullptr, .flags = 0, - .queueFamilyIndex = queue->id.value(), - .queueCount = 1, + .queueFamilyIndex = i++, + .queueCount = family.count, .pQueuePriorities = stdr::data(priority), }; }); - const auto& capabilities = m_physical_device->capabilities(); - const auto enabled_features = [&capabilities] noexcept { - auto out = zeroed(); - out.sampleRateShading = capabilities.features.sampler_rate_shading; - out.multiDrawIndirect = capabilities.features.multi_draw_indirect; - out.fillModeNonSolid = capabilities.features.fill_Mode_non_solid; - out.samplerAnisotropy = capabilities.features.sampler_anisotropy; - return out; - }(); - - const auto device_extensions = m_physical_device->extensions(); + // const auto& capabilities = physical_device.capabilities(); + const auto enabled_1_0_features = init_by([](auto& out) static noexcept { + out.multiDrawIndirect = true; + out.samplerAnisotropy = true; + }); + const auto enabled_1_2_features = init_by([](auto& out) static noexcept { + out.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES; + out.pNext = nullptr; + out.descriptorIndexing = true; + out.descriptorBindingVariableDescriptorCount = true; + out.runtimeDescriptorArray = true; + out.bufferDeviceAddress = true; + }); + const auto enabled_1_3_features = init_by([&enabled_1_2_features](auto& out) noexcept { + out.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES; + out.pNext = std::bit_cast(&enabled_1_2_features); + out.synchronization2 = true; + out.dynamicRendering = true; + }); - device_logger.dlog("Device extensions: {}", device_extensions); + const auto device_extensions = physical_device.extensions(); const auto swapchain_available = [&] { for (const auto& ext : SWAPCHAIN_EXTENSIONS) - if (stdr::none_of(device_extensions, core::monadic::is_equal(ext))) return false; + if (stdr::none_of(device_extensions, cmonadic::is_equal(ext))) return false; return true; }(); - if (not swapchain_available) device_logger.wlog("Swapchain extension are not available"); - const auto raytracing_available = [&] { for (const auto& ext : RAYTRACING_EXTENSIONS) - if (stdr::none_of(device_extensions, core::monadic::is_equal(ext))) return false; + if (stdr::none_of(device_extensions, cmonadic::is_equal(ext))) return false; return true; }(); @@ -307,29 +333,28 @@ namespace stormkit::gpu { return e; }(); - device_logger.ilog("Enabled device extensions: {}", extensions); - const auto acceleration_feature = [] static noexcept { - auto out = zeroed(); - out.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR; - out.pNext = nullptr; - return out; - }(); - const auto rt_pipeline_feature = [&acceleration_feature] noexcept { - auto out = zeroed(); - out.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR; - out.pNext = std::bit_cast(&acceleration_feature); - return out; - }; - - const auto next = [&]() -> void* { - if (raytracing_available and info.enable_raytracing) return std::bit_cast(&rt_pipeline_feature); - return nullptr; - }(); + // const auto acceleration_feature = [] static noexcept { + // auto out = zeroed(); + // out.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR; + // out.pNext = nullptr; + // return out; + // }(); + // const auto rt_pipeline_feature = [&acceleration_feature] noexcept { + // auto out = zeroed(); + // out.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR; + // out.pNext = std::bit_cast(&acceleration_feature); + // return out; + // }; + + // const auto next = [&]() -> void* { + // if (raytracing_available and info.enable_raytracing) return std::bit_cast(&rt_pipeline_feature); + // return nullptr; + // }(); const auto create_info = VkDeviceCreateInfo { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, - .pNext = next, + .pNext = std::bit_cast(&enabled_1_3_features), .flags = 0, .queueCreateInfoCount = as(stdr::size(queue_create_infos)), .pQueueCreateInfos = stdr::data(queue_create_infos), @@ -337,258 +362,213 @@ namespace stormkit::gpu { .ppEnabledLayerNames = nullptr, .enabledExtensionCount = as(stdr::size(extensions)), .ppEnabledExtensionNames = stdr::data(extensions), - .pEnabledFeatures = &enabled_features, + .pEnabledFeatures = &enabled_1_0_features, }; + m_vk_handle = Try(vk::call_checked(vkCreateDevice, physical_device.native_handle(), &create_info, nullptr)); + volkLoadDeviceTable(&m_vk_device_table, m_vk_handle); + auto allocator_create_info = VmaAllocatorCreateInfo { .flags = 0, - .physicalDevice = m_physical_device->native_handle(), - .device = nullptr, + .physicalDevice = physical_device, + .device = m_vk_handle, .preferredLargeHeapBlockSize = 0, .pAllocationCallbacks = nullptr, .pDeviceMemoryCallbacks = nullptr, .pHeapSizeLimit = nullptr, .pVulkanFunctions = nullptr, - .instance = instance.native_handle(), - .vulkanApiVersion = vk_make_version(1, 4, 0), + .instance = physical_device.instance(), + .vulkanApiVersion = vk::make_version(1, 4, 0), .pTypeExternalMemoryHandleTypes = nullptr, }; + m_vma_function_table = Try(vk::call_checked(vma_import_functions_from_volk, + &allocator_create_info, + &m_vk_device_table)); - return vk_call(vkCreateDevice, m_physical_device->native_handle(), &create_info, nullptr) - .transform(core::monadic::set(m_vk_handle)) - .and_then([this, &allocator_create_info] mutable noexcept { - allocator_create_info.device = m_vk_handle; - volkLoadDeviceTable(&m_vk_device_table, m_vk_handle); - auto raw = m_vk_handle.value(); - m_vk_handle = { [vk_device_table = m_vk_device_table](auto handle) noexcept { - vk_device_table.vkDestroyDevice(handle, nullptr); - } }; - m_vk_handle = std::move(raw); - return vk_call(vma_import_functions_from_volk, &allocator_create_info, &m_vk_device_table); - }) - .transform(core::monadic::set(m_vma_function_table)) - .and_then([this, &allocator_create_info] mutable noexcept { - allocator_create_info.pVulkanFunctions = &m_vma_function_table; - - return vk_call(vmaCreateAllocator, &allocator_create_info); - }) - .transform(core::monadic::set(m_vma_allocator)) - .transform_error(monadic::from_vk()) - .and_then([this, &raster_queue] noexcept { - if (raster_queue.id) - m_raster_queue = QueueEntry { .id = *raster_queue.id, - .count = raster_queue.count, - .flags = raster_queue.flags }; - - return set_object_name(*this, std::format("StormKit:Device ({})", m_physical_device->info().device_name)); - }); - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto Device::wait_for_fences(std::span> fences, - bool wait_all, - const std::chrono::milliseconds& timeout) const noexcept -> Expected { - static constexpr auto POSSIBLE_RESULTS = std::array { VK_SUCCESS, VK_NOT_READY }; - - const auto vk_fences = fences | stdv::transform(monadic::to_vk()) | stdr::to(); - - return vk_call(m_vk_device_table.vkWaitForFences, - as_view(POSSIBLE_RESULTS), - m_vk_handle, - stdr::size(vk_fences), - stdr::data(vk_fences), - wait_all, - std::chrono::duration_cast(timeout).count()) - .transform(core::monadic::narrow()) - .transform_error(core::monadic::narrow()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto Device::reset_fences(std::span> fences) const noexcept -> Expected { - const auto vk_fences = fences | stdv::transform(monadic::to_vk()) | stdr::to(); + allocator_create_info.pVulkanFunctions = &m_vma_function_table; - return vk_call(m_vk_device_table.vkResetFences, m_vk_handle, std ::ranges::size(vk_fences), stdr::data(vk_fences)) - .transform_error(core::monadic::narrow()); - } + m_vma_allocator = Try(vk::call_checked(vmaCreateAllocator, &allocator_create_info)); - ///////////////////////////////////// - ///////////////////////////////////// - auto Device::set_object_name(u64 object, DebugObjectType type, std::string_view name) const -> Expected { - if (not vkSetDebugUtilsObjectNameEXT) return {}; + const auto name = std::format("StormKit:device ({})", physical_device.info().device_name); + if (not vkSetDebugUtilsObjectNameEXT) Return {}; - const auto info = VkDebugUtilsObjectNameInfoEXT { + const auto vk_object = native_handle(); + const auto debug_info = VkDebugUtilsObjectNameInfoEXT { .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, .pNext = nullptr, - .objectType = to_vk(type), - .objectHandle = object, - .pObjectName = std::data(name), + .objectType = vk::to_vk(trait::GpuObject::DEBUG_TYPE), + .objectHandle = as(std::bit_cast(vk_object)), + .pObjectName = stdr::data(name), }; - return vk_call(vkSetDebugUtilsObjectNameEXT, m_vk_handle, &info).transform_error(monadic::from_vk()); - } + Try(vk::call_checked(vkSetDebugUtilsObjectNameEXT, *this, &debug_info)); - ///////////////////////////////////// - ///////////////////////////////////// - auto imgui_vk_loader(const char* _func_name, void* user_data) noexcept -> PFN_vkVoidFunction { - const auto func_name = std::string_view { _func_name }; - const auto& device = *std::bit_cast(user_data); - - if (func_name == "vkAllocateCommandBuffers") - return std::bit_cast(device.device_table().vkAllocateCommandBuffers); - else if (func_name == "vkAllocateDescriptorSets") - return std::bit_cast(device.device_table().vkAllocateDescriptorSets); - else if (func_name == "vkAllocateMemory") - return std::bit_cast(device.device_table().vkAllocateMemory); - else if (func_name == "vkBeginCommandBuffer") - return std::bit_cast(device.device_table().vkBeginCommandBuffer); - else if (func_name == "vkBindBufferMemory") - return std::bit_cast(device.device_table().vkBindBufferMemory); - else if (func_name == "vkBindImageMemory") - return std::bit_cast(device.device_table().vkBindImageMemory); - else if (func_name == "vkCmdBindDescriptorSets") - return std::bit_cast(device.device_table().vkCmdBindDescriptorSets); - else if (func_name == "vkCmdBindIndexBuffer") - return std::bit_cast(device.device_table().vkCmdBindIndexBuffer); - else if (func_name == "vkCmdBindPipeline") - return std::bit_cast(device.device_table().vkCmdBindPipeline); - else if (func_name == "vkCmdBindVertexBuffers") - return std::bit_cast(device.device_table().vkCmdBindVertexBuffers); - else if (func_name == "vkCmdCopyBufferToImage") - return std::bit_cast(device.device_table().vkCmdCopyBufferToImage); - else if (func_name == "vkCmdDrawIndexed") - return std::bit_cast(device.device_table().vkCmdDrawIndexed); - else if (func_name == "vkCmdPipelineBarrier") - return std::bit_cast(device.device_table().vkCmdPipelineBarrier); - else if (func_name == "vkCmdPushConstants") - return std::bit_cast(device.device_table().vkCmdPushConstants); - else if (func_name == "vkCmdSetScissor") - return std::bit_cast(device.device_table().vkCmdSetScissor); - else if (func_name == "vkCmdSetViewport") - return std::bit_cast(device.device_table().vkCmdSetViewport); - else if (func_name == "vkCreateBuffer") - return std::bit_cast(device.device_table().vkCreateBuffer); - else if (func_name == "vkCreateCommandPool") - return std::bit_cast(device.device_table().vkCreateCommandPool); - else if (func_name == "vkCreateDescriptorPool") - return std::bit_cast(device.device_table().vkCreateDescriptorPool); - else if (func_name == "vkCreateDescriptorSetLayout") - return std::bit_cast(device.device_table().vkCreateDescriptorSetLayout); - else if (func_name == "vkCreateFence") - return std::bit_cast(device.device_table().vkCreateFence); - else if (func_name == "vkCreateFramebuffer") - return std::bit_cast(device.device_table().vkCreateFramebuffer); - else if (func_name == "vkCreateGraphicsPipelines") - return std::bit_cast(device.device_table().vkCreateGraphicsPipelines); - else if (func_name == "vkCreateImage") - return std::bit_cast(device.device_table().vkCreateImage); - else if (func_name == "vkCreateImageView") - return std::bit_cast(device.device_table().vkCreateImageView); - else if (func_name == "vkCreatePipelineLayout") - return std::bit_cast(device.device_table().vkCreatePipelineLayout); - else if (func_name == "vkCreateRenderPass") - return std::bit_cast(device.device_table().vkCreateRenderPass); - else if (func_name == "vkCreateSampler") - return std::bit_cast(device.device_table().vkCreateSampler); - else if (func_name == "vkCreateSemaphore") - return std::bit_cast(device.device_table().vkCreateSemaphore); - else if (func_name == "vkCreateShaderModule") - return std::bit_cast(device.device_table().vkCreateShaderModule); - else if (func_name == "vkCreateSwapchainKHR") - return std::bit_cast(device.device_table().vkCreateSwapchainKHR); - else if (func_name == "vkDestroyBuffer") - return std::bit_cast(device.device_table().vkDestroyBuffer); - else if (func_name == "vkDestroyCommandPool") - return std::bit_cast(device.device_table().vkDestroyCommandPool); - else if (func_name == "vkDestroyDescriptorPool") - return std::bit_cast(device.device_table().vkDestroyDescriptorPool); - else if (func_name == "vkDestroyDescriptorSetLayout") - return std::bit_cast(device.device_table().vkDestroyDescriptorSetLayout); - else if (func_name == "vkDestroyFence") - return std::bit_cast(device.device_table().vkDestroyFence); - else if (func_name == "vkDestroyFramebuffer") - return std::bit_cast(device.device_table().vkDestroyFramebuffer); - else if (func_name == "vkDestroyImage") - return std::bit_cast(device.device_table().vkDestroyImage); - else if (func_name == "vkDestroyImageView") - return std::bit_cast(device.device_table().vkDestroyImageView); - else if (func_name == "vkDestroyPipeline") - return std::bit_cast(device.device_table().vkDestroyPipeline); - else if (func_name == "vkDestroyPipelineLayout") - return std::bit_cast(device.device_table().vkDestroyPipelineLayout); - else if (func_name == "vkDestroyRenderPass") - return std::bit_cast(device.device_table().vkDestroyRenderPass); - else if (func_name == "vkDestroySampler") - return std::bit_cast(device.device_table().vkDestroySampler); - else if (func_name == "vkDestroySemaphore") - return std::bit_cast(device.device_table().vkDestroySemaphore); - else if (func_name == "vkDestroyShaderModule") - return std::bit_cast(device.device_table().vkDestroyShaderModule); - else if (func_name == "vkDestroySurfaceKHR") - return std::bit_cast(vkDestroySurfaceKHR); - else if (func_name == "vkDestroySwapchainKHR") - return std::bit_cast(device.device_table().vkDestroySwapchainKHR); - else if (func_name == "vkDeviceWaitIdle") - return std::bit_cast(device.device_table().vkDeviceWaitIdle); - else if (func_name == "vkEnumeratePhysicalDevices") - return std::bit_cast(vkEnumeratePhysicalDevices); - else if (func_name == "vkEndCommandBuffer") - return std::bit_cast(device.device_table().vkEndCommandBuffer); - else if (func_name == "vkFlushMappedMemoryRanges") - return std::bit_cast(device.device_table().vkFlushMappedMemoryRanges); - else if (func_name == "vkFreeCommandBuffers") - return std::bit_cast(device.device_table().vkFreeCommandBuffers); - else if (func_name == "vkFreeDescriptorSets") - return std::bit_cast(device.device_table().vkFreeDescriptorSets); - else if (func_name == "vkFreeMemory") - return std::bit_cast(device.device_table().vkFreeMemory); - else if (func_name == "vkGetBufferMemoryRequirements") - return std::bit_cast(device.device_table().vkGetBufferMemoryRequirements); - else if (func_name == "vkGetDeviceQueue") - return std::bit_cast(device.device_table().vkGetDeviceQueue); - else if (func_name == "vkGetImageMemoryRequirements") - return std::bit_cast(device.device_table().vkGetImageMemoryRequirements); - else if (func_name == "vkGetPhysicalDeviceProperties") - return std::bit_cast(vkGetPhysicalDeviceProperties); - else if (func_name == "vkGetPhysicalDeviceMemoryProperties") - return std::bit_cast(vkGetPhysicalDeviceMemoryProperties); - else if (func_name == "vkGetPhysicalDeviceQueueFamilyProperties") - return std::bit_cast(vkGetPhysicalDeviceQueueFamilyProperties); - else if (func_name == "vkGetPhysicalDeviceSurfaceCapabilitiesKHR") - return std::bit_cast(vkGetPhysicalDeviceSurfaceCapabilitiesKHR); - else if (func_name == "vkGetPhysicalDeviceSurfaceFormatsKHR") - return std::bit_cast(vkGetPhysicalDeviceSurfaceFormatsKHR); - else if (func_name == "vkGetPhysicalDeviceSurfacePresentModesKHR") - return std::bit_cast(vkGetPhysicalDeviceSurfacePresentModesKHR); - else if (func_name == "vkGetSwapchainImagesKHR") - return std::bit_cast(device.device_table().vkGetSwapchainImagesKHR); - else if (func_name == "vkMapMemory") - return std::bit_cast(device.device_table().vkMapMemory); - else if (func_name == "vkQueueSubmit") - return std::bit_cast(device.device_table().vkQueueSubmit); - else if (func_name == "vkQueueWaitIdle") - return std::bit_cast(device.device_table().vkQueueWaitIdle); - else if (func_name == "vkResetCommandPool") - return std::bit_cast(device.device_table().vkResetCommandPool); - else if (func_name == "vkResetFences") - return std::bit_cast(device.device_table().vkResetFences); - else if (func_name == "vkUnmapMemory") - return std::bit_cast(device.device_table().vkUnmapMemory); - else if (func_name == "vkUpdateDescriptorSets") - return std::bit_cast(device.device_table().vkUpdateDescriptorSets); - else if (func_name == "vkWaitForFences") - return std::bit_cast(device.device_table().vkWaitForFences); - else if (func_name == "vkCmdBeginRendering") - return std::bit_cast(device.device_table().vkCmdBeginRendering); - else if (func_name == "vkCmdEndRendering") - return std::bit_cast(device.device_table().vkCmdEndRendering); - else if (func_name == "vkCmdBeginRenderingKHR") - return std::bit_cast(device.device_table().vkCmdBeginRenderingKHR); - else if (func_name == "vkCmdEndRenderingKHR") - return std::bit_cast(device.device_table().vkCmdEndRenderingKHR); - - ensures(false, std::format("Unhandled vk func {}", func_name)); - std::unreachable(); + Return {}; } + + namespace vk { + ///////////////////////////////////// + ///////////////////////////////////// + auto imgui_vk_loader(const char* _func_name, void* user_data) noexcept -> PFN_vkVoidFunction { + const auto func_name = string_view { _func_name }; + const auto& device = *std::bit_cast(user_data); + const auto device_table = device.device_table(); + + if (func_name == "vkAllocateCommandBuffers") + return std::bit_cast(device_table.vkAllocateCommandBuffers); + else if (func_name == "vkAllocateDescriptorSets") + return std::bit_cast(device_table.vkAllocateDescriptorSets); + else if (func_name == "vkAllocateMemory") + return std::bit_cast(device_table.vkAllocateMemory); + else if (func_name == "vkBeginCommandBuffer") + return std::bit_cast(device_table.vkBeginCommandBuffer); + else if (func_name == "vkBindBufferMemory") + return std::bit_cast(device_table.vkBindBufferMemory); + else if (func_name == "vkBindImageMemory") + return std::bit_cast(device_table.vkBindImageMemory); + else if (func_name == "vkCmdBindDescriptorSets") + return std::bit_cast(device_table.vkCmdBindDescriptorSets); + else if (func_name == "vkCmdBindIndexBuffer") + return std::bit_cast(device_table.vkCmdBindIndexBuffer); + else if (func_name == "vkCmdBindPipeline") + return std::bit_cast(device_table.vkCmdBindPipeline); + else if (func_name == "vkCmdBindVertexBuffers") + return std::bit_cast(device_table.vkCmdBindVertexBuffers); + else if (func_name == "vkCmdCopyBufferToImage") + return std::bit_cast(device_table.vkCmdCopyBufferToImage); + else if (func_name == "vkCmdDrawIndexed") + return std::bit_cast(device_table.vkCmdDrawIndexed); + else if (func_name == "vkCmdPipelineBarrier") + return std::bit_cast(device_table.vkCmdPipelineBarrier); + else if (func_name == "vkCmdPushConstants") + return std::bit_cast(device_table.vkCmdPushConstants); + else if (func_name == "vkCmdSetScissor") + return std::bit_cast(device_table.vkCmdSetScissor); + else if (func_name == "vkCmdSetViewport") + return std::bit_cast(device_table.vkCmdSetViewport); + else if (func_name == "vkCreateBuffer") + return std::bit_cast(device_table.vkCreateBuffer); + else if (func_name == "vkCreateCommandPool") + return std::bit_cast(device_table.vkCreateCommandPool); + else if (func_name == "vkCreateDescriptorPool") + return std::bit_cast(device_table.vkCreateDescriptorPool); + else if (func_name == "vkCreateDescriptorSetLayout") + return std::bit_cast(device_table.vkCreateDescriptorSetLayout); + else if (func_name == "vkCreateFence") + return std::bit_cast(device_table.vkCreateFence); + else if (func_name == "vkCreateFramebuffer") + return std::bit_cast(device_table.vkCreateFramebuffer); + else if (func_name == "vkCreateGraphicsPipelines") + return std::bit_cast(device_table.vkCreateGraphicsPipelines); + else if (func_name == "vkCreateImage") + return std::bit_cast(device_table.vkCreateImage); + else if (func_name == "vkCreateImageView") + return std::bit_cast(device_table.vkCreateImageView); + else if (func_name == "vkCreatePipelineLayout") + return std::bit_cast(device_table.vkCreatePipelineLayout); + else if (func_name == "vkCreateRenderPass") + return std::bit_cast(device_table.vkCreateRenderPass); + else if (func_name == "vkCreateSampler") + return std::bit_cast(device_table.vkCreateSampler); + else if (func_name == "vkCreateSemaphore") + return std::bit_cast(device_table.vkCreateSemaphore); + else if (func_name == "vkCreateShaderModule") + return std::bit_cast(device_table.vkCreateShaderModule); + else if (func_name == "vkCreateSwapchainKHR") + return std::bit_cast(device_table.vkCreateSwapchainKHR); + else if (func_name == "vkDestroyBuffer") + return std::bit_cast(device_table.vkDestroyBuffer); + else if (func_name == "vkDestroyCommandPool") + return std::bit_cast(device_table.vkDestroyCommandPool); + else if (func_name == "vkDestroyDescriptorPool") + return std::bit_cast(device_table.vkDestroyDescriptorPool); + else if (func_name == "vkDestroyDescriptorSetLayout") + return std::bit_cast(device_table.vkDestroyDescriptorSetLayout); + else if (func_name == "vkDestroyFence") + return std::bit_cast(device_table.vkDestroyFence); + else if (func_name == "vkDestroyFramebuffer") + return std::bit_cast(device_table.vkDestroyFramebuffer); + else if (func_name == "vkDestroyImage") + return std::bit_cast(device_table.vkDestroyImage); + else if (func_name == "vkDestroyImageView") + return std::bit_cast(device_table.vkDestroyImageView); + else if (func_name == "vkDestroyPipeline") + return std::bit_cast(device_table.vkDestroyPipeline); + else if (func_name == "vkDestroyPipelineLayout") + return std::bit_cast(device_table.vkDestroyPipelineLayout); + else if (func_name == "vkDestroyRenderPass") + return std::bit_cast(device_table.vkDestroyRenderPass); + else if (func_name == "vkDestroySampler") + return std::bit_cast(device_table.vkDestroySampler); + else if (func_name == "vkDestroySemaphore") + return std::bit_cast(device_table.vkDestroySemaphore); + else if (func_name == "vkDestroyShaderModule") + return std::bit_cast(device_table.vkDestroyShaderModule); + else if (func_name == "vkDestroySurfaceKHR") + return std::bit_cast(vkDestroySurfaceKHR); + else if (func_name == "vkDestroySwapchainKHR") + return std::bit_cast(device_table.vkDestroySwapchainKHR); + else if (func_name == "vkDeviceWaitIdle") + return std::bit_cast(device_table.vkDeviceWaitIdle); + else if (func_name == "vkEnumeratePhysicalDevices") + return std::bit_cast(vkEnumeratePhysicalDevices); + else if (func_name == "vkEndCommandBuffer") + return std::bit_cast(device_table.vkEndCommandBuffer); + else if (func_name == "vkFlushMappedMemoryRanges") + return std::bit_cast(device_table.vkFlushMappedMemoryRanges); + else if (func_name == "vkFreeCommandBuffers") + return std::bit_cast(device_table.vkFreeCommandBuffers); + else if (func_name == "vkFreeDescriptorSets") + return std::bit_cast(device_table.vkFreeDescriptorSets); + else if (func_name == "vkFreeMemory") + return std::bit_cast(device_table.vkFreeMemory); + else if (func_name == "vkGetBufferMemoryRequirements") + return std::bit_cast(device_table.vkGetBufferMemoryRequirements); + else if (func_name == "vkGetDeviceQueue") + return std::bit_cast(device_table.vkGetDeviceQueue); + else if (func_name == "vkGetImageMemoryRequirements") + return std::bit_cast(device_table.vkGetImageMemoryRequirements); + else if (func_name == "vkGetPhysicalDeviceProperties") + return std::bit_cast(vkGetPhysicalDeviceProperties); + else if (func_name == "vkGetPhysicalDeviceMemoryProperties") + return std::bit_cast(vkGetPhysicalDeviceMemoryProperties); + else if (func_name == "vkGetPhysicalDeviceQueueFamilyProperties") + return std::bit_cast(vkGetPhysicalDeviceQueueFamilyProperties); + else if (func_name == "vkGetPhysicalDeviceSurfaceCapabilitiesKHR") + return std::bit_cast(vkGetPhysicalDeviceSurfaceCapabilitiesKHR); + else if (func_name == "vkGetPhysicalDeviceSurfaceFormatsKHR") + return std::bit_cast(vkGetPhysicalDeviceSurfaceFormatsKHR); + else if (func_name == "vkGetPhysicalDeviceSurfacePresentModesKHR") + return std::bit_cast(vkGetPhysicalDeviceSurfacePresentModesKHR); + else if (func_name == "vkGetSwapchainImagesKHR") + return std::bit_cast(device_table.vkGetSwapchainImagesKHR); + else if (func_name == "vkMapMemory") + return std::bit_cast(device_table.vkMapMemory); + else if (func_name == "vkQueueSubmit") + return std::bit_cast(device_table.vkQueueSubmit); + else if (func_name == "vkQueueWaitIdle") + return std::bit_cast(device_table.vkQueueWaitIdle); + else if (func_name == "vkResetCommandPool") + return std::bit_cast(device_table.vkResetCommandPool); + else if (func_name == "vkResetFences") + return std::bit_cast(device_table.vkResetFences); + else if (func_name == "vkUnmapMemory") + return std::bit_cast(device_table.vkUnmapMemory); + else if (func_name == "vkUpdateDescriptorSets") + return std::bit_cast(device_table.vkUpdateDescriptorSets); + else if (func_name == "vkWaitForFences") + return std::bit_cast(device_table.vkWaitForFences); + else if (func_name == "vkCmdBeginRendering") + return std::bit_cast(device_table.vkCmdBeginRendering); + else if (func_name == "vkCmdEndRendering") + return std::bit_cast(device_table.vkCmdEndRendering); + else if (func_name == "vkCmdBeginRenderingKHR") + return std::bit_cast(device_table.vkCmdBeginRenderingKHR); + else if (func_name == "vkCmdEndRenderingKHR") + return std::bit_cast(device_table.vkCmdEndRenderingKHR); + + ensures(false, std::format("Unhandled vk func {}", func_name)); + std::unreachable(); + } + } // namespace vk } // namespace stormkit::gpu diff --git a/src/gpu/core/fence.cpp b/src/gpu/core/fence.cpp new file mode 100644 index 000000000..32cdff7d8 --- /dev/null +++ b/src/gpu/core/fence.cpp @@ -0,0 +1,89 @@ +// Copyright (C) 2023 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include +#include + +#include +#include + +module stormkit.gpu.core; + +import std; + +import stormkit.core; + +import :vulkan; + +namespace stormkit::gpu { + ///////////////////////////////////// + ///////////////////////////////////// + template + auto FenceInterface::status() const noexcept -> Expected { + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + const auto result = Try((vk::call_checked(device_table.vkGetFenceStatus, device, *this))); + if (result == VK_NOT_READY) Return Fence::Status::UNSIGNALED; + Return Fence::Status::SIGNALED; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto FenceInterface::wait(const std::chrono::milliseconds& wait_for) const noexcept -> Expected { + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + const auto handle = Base::native_handle(); + + const auto + result = Try((vk::call_checked(device_table.vkWaitForFences, + device, + 1u, + &handle, + true, + std::chrono::duration_cast(wait_for).count()))); + + Return vk::from_vk(result); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto FenceInterface::reset() const noexcept -> Expected { + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + const auto handle = Base::native_handle(); + + Try(vk::call_checked(device_table.vkResetFences, device, 1u, &handle)); + + Return {}; + } + + template class FenceInterface; + template class FenceInterface; + + ///////////////////////////////////// + ///////////////////////////////////// + auto FenceImplementation::do_init(PrivateTag, const CreateInfo& create_info) noexcept -> Expected { + const auto flags = (create_info.signaled) ? VkFenceCreateFlags { VK_FENCE_CREATE_SIGNALED_BIT } : VkFenceCreateFlags {}; + + const auto vk_create_info = VkFenceCreateInfo { + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + .pNext = nullptr, + .flags = flags + }; + + const auto& device = owner(); + const auto& device_table = device.device_table(); + + m_vk_handle = Try(vk::call_checked(device_table.vkCreateFence, device, &vk_create_info, nullptr)); + + Return {}; + } +} // namespace stormkit::gpu diff --git a/src/gpu/core/instance.cpp b/src/gpu/core/instance.cpp index ec0d1bf5e..5cb269cbf 100644 --- a/src/gpu/core/instance.cpp +++ b/src/gpu/core/instance.cpp @@ -6,8 +6,9 @@ module; #include #include -#include +#include +#include #define STORMKIT_DEFINE_VK_PLATFORM #include @@ -16,233 +17,153 @@ module stormkit.gpu.core; import std; import stormkit.core; -import stormkit.log; namespace stdr = std::ranges; namespace stdv = std::views; -namespace stormkit::gpu { - LOGGER("stormkit.gpu") +using namespace std::literals; + +namespace cmonadic = stormkit::core::monadic; +namespace stormkit::gpu { namespace { - constexpr auto VALIDATION_LAYERS = std::array { - "VK_LAYER_KHRONOS_validation", - // "VK_LAYER_LUNARG_api_dump", - "VK_LAYER_LUNARG_monitor", - }; - constexpr auto OPTIONAL_VALIDATION_LAYERS = std::array { - // "VK_LAYER_MESA_overlay", - }; + constexpr auto VALIDATION_LAYERS = into_array_of("VK_LAYER_KHRONOS_validation", + // "VK_LAYER_LUNARG_api_dump", + "VK_LAYER_LUNARG_monitor", + "VK_LAYER_MESA_overlay"); - [[maybe_unused]] - constexpr auto VALIDATION_FEATURES - = std::array { - VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT, - VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT, - }; + // [[maybe_unused]] + // constexpr auto VALIDATION_FEATURES = into_array_of(VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT, + // VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT); - constexpr auto STORMKIT_VK_VERSION = vk_make_version(STORMKIT_MAJOR_VERSION, - STORMKIT_MINOR_VERSION, - STORMKIT_PATCH_VERSION); + constexpr auto + STORMKIT_VK_VERSION = vk::make_version(STORMKIT_MAJOR_VERSION, STORMKIT_MINOR_VERSION, STORMKIT_PATCH_VERSION); - constexpr auto BASE_EXTENSIONS = std::array { VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, + constexpr auto BASE_EXTENSIONS = into_array_of(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME #ifdef STORMKIT_OS_APPLE - VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME + , + VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME #endif - }; + ); - constexpr auto SURFACE_EXTENSIONS = std::array { - VK_KHR_SURFACE_EXTENSION_NAME, - VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME, - // VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME, - }; + constexpr auto SURFACE_EXTENSIONS = into_array_of(VK_KHR_SURFACE_EXTENSION_NAME, + VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME + // VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME, + ); - constexpr auto WSI_SURFACE_EXTENSIONS = std::array { + constexpr auto WSI_SURFACE_EXTENSIONS = into_array_of( #ifdef STORMKIT_OS_WINDOWS - VK_KHR_WIN32_SURFACE_EXTENSION_NAME, + VK_KHR_WIN32_SURFACE_EXTENSION_NAME #elif defined(STORMKIT_OS_LINUX) - VK_KHR_XCB_SURFACE_EXTENSION_NAME, - VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME, + VK_KHR_XCB_SURFACE_EXTENSION_NAME, + VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME #elif defined(STORMKIT_OS_MACOS) - VK_MVK_MACOS_SURFACE_EXTENSION_NAME, + VK_MVK_MACOS_SURFACE_EXTENSION_NAME #elif defined(STORMKIT_OS_IOS) - VK_MVK_IOS_SURFACE_EXTENSION_NAME, + VK_MVK_IOS_SURFACE_EXTENSION_NAME #endif - }; + ); ///////////////////////////////////// ///////////////////////////////////// - auto debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, - VkDebugUtilsMessageTypeFlagsEXT, - const VkDebugUtilsMessengerCallbackDataEXT* callback_data, - void*) noexcept -> u32 { - EXPECTS(callback_data); - auto message = std::format("{}", callback_data->pMessage); - - if (check_flag_bit(severity, VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT)) ilog("{}", message); - else if (check_flag_bit(severity, VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT)) - dlog("{}", message); - else if (check_flag_bit(severity, VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)) - elog("{}", message); - else if (check_flag_bit(severity, VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT)) - wlog("{}", message); - - return 0; - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto check_extension_support(std::span supported_extensions, - std::span extensions) noexcept -> bool { - auto required_extensions = HashSet { stdr::begin(extensions), stdr::end(extensions) }; + auto check_extension_support(array_view supported_extensions, + array_view extensions) noexcept -> std::optional> { + auto required_extensions = hash_set { stdr::begin(extensions), stdr::end(extensions) }; for (const auto& extension : supported_extensions) required_extensions.erase(extension); - return required_extensions.empty(); + if (not required_extensions.empty()) return required_extensions; + + return std::nullopt; } ///////////////////////////////////// ///////////////////////////////////// - auto check_extension_support(std::span supported_extensions, - std::span extensions) noexcept -> bool { - const auto ext = extensions | stdv::transform(core::monadic::init()) | stdr::to(); + auto check_extension_support(array_view supported_extensions, + array_view extensions) noexcept -> std::optional> { + const auto ext = transform(extensions, cmonadic::init()); return check_extension_support(supported_extensions, ext); } } // namespace + template class InstanceInterface; + template class InstanceInterface; + ///////////////////////////////////// ///////////////////////////////////// - auto Instance::do_init() noexcept -> Expected { - return vk_enumerate(vkEnumerateInstanceExtensionProperties, nullptr) - .and_then([this](auto&& exts) noexcept { - m_extensions = exts - | stdv::transform([](auto&& extension) static noexcept { - return std::string { extension.extensionName }; - }) - | stdr::to(); - - dlog("Instance extensions: {}", m_extensions); - - const auto validation_layers = init_by>([this](auto& out) noexcept { - if (not m_validation_layers_enabled) return; - - auto result = vk_enumerate(vkEnumerateInstanceLayerProperties); - if (not result) return; - const auto layers = std::move(result).value() | stdv::transform([](auto&& layer) static noexcept { - return std::string_view { layer.layerName }; - }); - - dlog("Layers found: {}", layers); - - for (const auto layer_name : VALIDATION_LAYERS) { - if (not stdr::contains(layers, std::string_view { layer_name })) return; - } - - out = VALIDATION_LAYERS | stdr::to(); - - for (const auto layer_name : OPTIONAL_VALIDATION_LAYERS) { - if (stdr::contains(layers, std::string_view { layer_name })) out.push_back(layer_name); - } - }); - - ilog("Enabled layers: {}", validation_layers); - - const auto instance_extensions = [this]() noexcept { - auto e = concat(BASE_EXTENSIONS, SURFACE_EXTENSIONS); - - for (auto&& ext_ : WSI_SURFACE_EXTENSIONS) { - const auto ext = std::array { ext_ }; - if (check_extension_support(m_extensions, ext)) merge(e, ext); - } - - if (m_validation_layers_enabled) merge(e, std::array { VK_EXT_DEBUG_UTILS_EXTENSION_NAME }); - - return e; - }(); - ilog("Enabled instance extensions: {}", instance_extensions); - - constexpr auto ENGINE_NAME = "StormKit"; - - const auto app_info = VkApplicationInfo { - .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, - .pNext = nullptr, - .pApplicationName = std::data(m_app_name), - .applicationVersion = vk_make_version(0, 0, 0), - .pEngineName = ENGINE_NAME, - .engineVersion = STORMKIT_VK_VERSION, - .apiVersion = VK_API_VERSION_1_1, - }; - - const auto create_info = VkInstanceCreateInfo { - .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, - .pNext = nullptr, + auto InstanceImplementation::do_init(PrivateTag, const CreateInfo& create_info) noexcept -> Expected { + const auto exts = Try(vk::enumerate_checked(vkEnumerateInstanceExtensionProperties, nullptr)); + m_extensions = transform(exts, [](const auto& ext) static noexcept { return string { ext.extensionName }; }); + const auto available_layers = Try(vk::enumerate_checked(vkEnumerateInstanceLayerProperties)); + // std::println("{}", available_layers | stdv::transform([](const auto& layer) static noexcept { + // return std::string_view { layer.layerName }; + // })); + const auto validation_layers = create_info.enable_validation_layers + ? transform_if( + available_layers, + [](const auto& layer) static noexcept { + return stdr::contains(VALIDATION_LAYERS, string_view { layer.layerName }); + }, + [](const auto& layer) static noexcept { return layer.layerName; }) + : dyn_array(); + + const auto instance_extensions = [enable_validation_layers = create_info.enable_validation_layers] noexcept { + auto e = concat(BASE_EXTENSIONS, SURFACE_EXTENSIONS, WSI_SURFACE_EXTENSIONS); + if (enable_validation_layers) e.emplace_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + return e; + }(); + const auto result = check_extension_support(m_extensions, instance_extensions); + if (result.has_value()) ensures(true, std::format("Missing extensions! {}", result.value())); + + constexpr auto ENGINE_NAME = "StormKit"; + + const auto app_info = VkApplicationInfo { + .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, + .pNext = nullptr, + .pApplicationName = std::data(create_info.application_name), + .applicationVersion = create_info.application_version, + .pEngineName = ENGINE_NAME, + .engineVersion = STORMKIT_VK_VERSION, + .apiVersion = VK_API_VERSION_1_3, + }; + + const auto vk_create_info = VkInstanceCreateInfo { + .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .pNext = nullptr, #ifdef STORMKIT_OS_APPLE - .flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR, + .flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR, #else - .flags = 0, + .flags = 0, #endif - .pApplicationInfo = &app_info, - .enabledLayerCount = as(stdr::size(validation_layers)), - .ppEnabledLayerNames = stdr::data(validation_layers), - .enabledExtensionCount = as(stdr::size(instance_extensions)), - .ppEnabledExtensionNames = stdr::data(instance_extensions), - }; - return vk_call(vkCreateInstance, &create_info, nullptr); - }) - .transform(core::monadic::set(m_vk_handle)) - .and_then(bind_front(&Instance::do_load_instance, this)) - .and_then(bind_front(&Instance::do_retrieve_physical_devices, this)) - .and_then(bind_front(&Instance::do_init_debug_report_callback, this)) - .transform_error(monadic::from_vk()); - } + .pApplicationInfo = &app_info, + .enabledLayerCount = as(stdr::size(validation_layers)), + .ppEnabledLayerNames = stdr::data(validation_layers), + .enabledExtensionCount = as(stdr::size(instance_extensions)), + .ppEnabledExtensionNames = stdr::data(instance_extensions), + }; - ///////////////////////////////////// - ///////////////////////////////////// - auto Instance::do_load_instance() noexcept -> VulkanExpected { - volkLoadInstanceOnly(m_vk_handle); - return {}; + m_vk_handle = Try(vk::call_checked(vkCreateInstance, &vk_create_info, nullptr)); + + Try(do_load_instance()); + Try(do_retrieve_physical_devices()); + + Return {}; } ///////////////////////////////////// ///////////////////////////////////// - auto Instance::do_init_debug_report_callback() noexcept -> VulkanExpected { - if (!m_validation_layers_enabled) return {}; - constexpr auto severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT - | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT - | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; - - constexpr auto type = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT - | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT - | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; - - const auto create_info = VkDebugUtilsMessengerCreateInfoEXT { - .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT, - .pNext = nullptr, - .flags = 0, - .messageSeverity = severity, - .messageType = type, - .pfnUserCallback = debug_callback, - .pUserData = nullptr, - }; - - m_vk_debug_utils_handle = { [vk_instance = m_vk_handle.value()](auto handle) noexcept { - vkDestroyDebugUtilsMessengerEXT(vk_instance, handle, nullptr); - } }; - - return vk_call(vkCreateDebugUtilsMessengerEXT, m_vk_handle, &create_info, nullptr) - .transform(core::monadic::set(m_vk_debug_utils_handle)) - .transform([] static noexcept { ilog("Vulkan debug callback enabled!"); }); + auto InstanceImplementation::do_load_instance() noexcept -> Expected { + volkLoadInstanceOnly(m_vk_handle); + Return {}; } ///////////////////////////////////// ///////////////////////////////////// - auto Instance::do_retrieve_physical_devices() noexcept -> VulkanExpected { - return vk_enumerate(vkEnumeratePhysicalDevices, m_vk_handle).transform([this](auto&& physical_devices) { - m_physical_devices = std::forward(physical_devices) - | stdv::transform([](auto&& physical_device) static noexcept { - return PhysicalDevice { std::move(physical_device) }; - }) - | stdr::to(); - }); + auto InstanceImplementation::do_retrieve_physical_devices() noexcept -> Expected { + m_physical_devices = transform(Try(vk::enumerate_checked(vkEnumeratePhysicalDevices, m_vk_handle)), + [this](auto physical_device) noexcept { + return PhysicalDevice::create(view::Instance { *this }, std::move(physical_device)); + }); + Return {}; } } // namespace stormkit::gpu diff --git a/src/gpu/core/loader.cpp b/src/gpu/core/loader.cpp index e74c971a9..9d21b5206 100644 --- a/src/gpu/core/loader.cpp +++ b/src/gpu/core/loader.cpp @@ -6,6 +6,6 @@ module stormkit.gpu.core; namespace stormkit::gpu { auto initialize_backend() -> Expected { - return vk_call(volkInitialize).transform_error(monadic::from_vk()); + return vk::call_checked(volkInitialize); } } // namespace stormkit::gpu diff --git a/src/gpu/core/physical_device.cpp b/src/gpu/core/physical_device.cpp index 6e3a1f382..4937ededf 100644 --- a/src/gpu/core/physical_device.cpp +++ b/src/gpu/core/physical_device.cpp @@ -4,6 +4,9 @@ module; +#include + +#include #include module stormkit.gpu.core; @@ -12,11 +15,18 @@ import std; import stormkit.core; +import :vulkan; + using namespace std::literals; +namespace stdr = std::ranges; +namespace stdv = std::views; + +namespace cm = stormkit::core::meta; + namespace stormkit::gpu { namespace { - constexpr auto RAYTRACING_EXTENSIONS = std::array { + constexpr auto RAYTRACING_EXTENSIONS = array { "VK_KHR_ray_tracing_pipeline"sv, "VK_KHR_acceleration_structure"sv, "VK_KHR_buffer_device_address"sv, "VK_KHR_deferred_host_operations"sv, "VK_EXT_descriptor_indexing"sv, "VK_KHR_spirv_1_4"sv, "VK_KHR_shader_float_controls"sv @@ -24,7 +34,7 @@ namespace stormkit::gpu { ///////////////////////////////////// ///////////////////////////////////// - auto vendor_name_by_id(u64 ID) -> std::string_view { + auto vendor_name_by_id(u64 ID) -> string_view { switch (ID) { case 0x1002: return "AMD"; case 0x1010: return "ImgTex"; @@ -36,11 +46,277 @@ namespace stormkit::gpu { return "UNKNOWN"; } + + auto info(const PhysicalDeviceImplementation& physical_device) noexcept -> PhysicalDeviceInfo { + const auto& handle = physical_device.native_handle(); + + auto device_info = PhysicalDeviceInfo {}; + + const auto properties = vk::call(vkGetPhysicalDeviceProperties, handle); + const auto vendor_id = properties.vendorID; + + device_info.device_id = properties.deviceID; + + const auto device_name_size = std::char_traits::length(properties.deviceName); + + device_info.device_name.resize(device_name_size); + stdr::copy(string_view { properties.deviceName, device_name_size }, std::begin(device_info.device_name)); + + device_info.vendor_id = vendor_id; + device_info.vendor_name = vendor_name_by_id(vendor_id); + device_info.api_major_version = vk::version_major(properties.apiVersion); + device_info.api_minor_version = vk::version_minor(properties.apiVersion); + device_info.api_patch_version = vk::version_patch(properties.apiVersion); + + device_info.driver_major_version = vk::version_major(properties.driverVersion); + device_info.driver_minor_version = vk::version_minor(properties.driverVersion); + device_info.driver_patch_version = vk::version_patch(properties.driverVersion); + stdr::copy(properties.pipelineCacheUUID, stdr::begin(device_info.pipeline_cache_uuid)); + + device_info.type = vk::from_vk(properties.deviceType); + + return device_info; + } + + auto capabilities(const PhysicalDeviceImplementation& physical_device) noexcept -> RenderCapabilities { + const auto& handle = physical_device.native_handle(); + + const auto properties = vk::call(vkGetPhysicalDeviceProperties, handle); + // TODO port to vkGetPhysicalDeviceFeatures2 + const auto features = vk::call(vkGetPhysicalDeviceFeatures, handle); + + auto capabilities = RenderCapabilities {}; + capabilities.limits.max_image_dimension_1D = properties.limits.maxImageDimension1D; + capabilities.limits.max_image_dimension_2D = properties.limits.maxImageDimension2D; + capabilities.limits.max_image_dimension_3D = properties.limits.maxImageDimension3D; + capabilities.limits.max_image_dimension_cube = properties.limits.maxImageDimensionCube; + capabilities.limits.max_image_array_layers = properties.limits.maxImageArrayLayers; + capabilities.limits.max_texel_buffer_elements = properties.limits.maxTexelBufferElements; + capabilities.limits.max_uniform_buffer_range = properties.limits.maxUniformBufferRange; + capabilities.limits.max_storage_buffer_range = properties.limits.maxStorageBufferRange; + capabilities.limits.max_push_constants_size = properties.limits.maxPushConstantsSize; + capabilities.limits.max_memory_allocation_count = properties.limits.maxMemoryAllocationCount; + capabilities.limits.max_sampler_allocation_count = properties.limits.maxSamplerAllocationCount; + capabilities.limits.buffer_image_granularity = properties.limits.bufferImageGranularity; + capabilities.limits.sparse_address_space_size = properties.limits.sparseAddressSpaceSize; + capabilities.limits.max_bound_descriptor_sets = properties.limits.maxBoundDescriptorSets; + capabilities.limits.max_per_stage_descriptor_samplers = properties.limits.maxPerStageDescriptorSamplers; + capabilities.limits.max_per_stage_descriptor_uniform_buffers = properties.limits.maxPerStageDescriptorUniformBuffers; + capabilities.limits.max_per_stage_descriptor_storage_buffers = properties.limits.maxPerStageDescriptorStorageBuffers; + capabilities.limits.max_per_stage_descriptor_sampled_images = properties.limits.maxPerStageDescriptorSampledImages; + capabilities.limits.max_per_stage_descriptor_storage_images = properties.limits.maxPerStageDescriptorStorageImages; + capabilities.limits.max_per_stage_descriptor_input_attachments + = properties.limits.maxPerStageDescriptorInputAttachments; + capabilities.limits.max_per_stage_resources = properties.limits.maxPerStageResources; + capabilities.limits.max_descriptor_set_samplers = properties.limits.maxDescriptorSetSamplers; + capabilities.limits.max_descriptor_set_uniform_buffers = properties.limits.maxDescriptorSetUniformBuffers; + capabilities.limits.max_descriptor_set_uniform_buffers_dynamic + = properties.limits.maxDescriptorSetUniformBuffersDynamic; + capabilities.limits.max_descriptor_set_storage_buffers = properties.limits.maxDescriptorSetStorageBuffers; + capabilities.limits.max_descriptor_set_storage_buffers_dynamic + = properties.limits.maxDescriptorSetStorageBuffersDynamic; + capabilities.limits.max_descriptor_set_sampled_images = properties.limits.maxDescriptorSetSampledImages; + capabilities.limits.max_descriptor_set_storage_images = properties.limits.maxDescriptorSetStorageImages; + capabilities.limits.max_descriptor_set_input_attachments = properties.limits.maxDescriptorSetInputAttachments; + capabilities.limits.max_vertex_input_attributes = properties.limits.maxVertexInputAttributes; + capabilities.limits.max_vertex_input_bindings = properties.limits.maxVertexInputBindings; + capabilities.limits.max_vertex_input_attribute_offset = properties.limits.maxVertexInputAttributeOffset; + capabilities.limits.max_vertex_input_binding_stride = properties.limits.maxVertexInputBindingStride; + capabilities.limits.max_vertex_output_components = properties.limits.maxVertexOutputComponents; + capabilities.limits.max_tessellation_generation_level = properties.limits.maxTessellationGenerationLevel; + capabilities.limits.max_tessellation_patch_size = properties.limits.maxTessellationPatchSize; + capabilities.limits.max_tessellation_control_per_vertex_input_components + = properties.limits.maxTessellationControlPerVertexInputComponents; + capabilities.limits.max_tessellation_control_per_vertex_output_components + = properties.limits.maxTessellationControlPerVertexOutputComponents; + capabilities.limits.max_tessellation_control_per_patch_output_components + = properties.limits.maxTessellationControlPerPatchOutputComponents; + capabilities.limits.max_tessellation_control_total_output_components + = properties.limits.maxTessellationControlTotalOutputComponents; + capabilities.limits.max_tessellation_evaluation_input_components + = properties.limits.maxTessellationEvaluationInputComponents; + capabilities.limits.max_tessellation_evaluation_output_components + = properties.limits.maxTessellationEvaluationOutputComponents; + capabilities.limits.max_geometry_shader_invocations = properties.limits.maxGeometryShaderInvocations; + capabilities.limits.max_geometry_input_components = properties.limits.maxGeometryInputComponents; + capabilities.limits.max_geometry_output_components = properties.limits.maxGeometryOutputComponents; + capabilities.limits.max_geometry_output_vertices = properties.limits.maxGeometryOutputVertices; + capabilities.limits.max_geometry_total_output_components = properties.limits.maxGeometryTotalOutputComponents; + capabilities.limits.max_fragment_input_components = properties.limits.maxFragmentInputComponents; + capabilities.limits.max_fragment_output_attachments = properties.limits.maxFragmentOutputAttachments; + capabilities.limits.max_fragment_dual_src_attachments = properties.limits.maxFragmentDualSrcAttachments; + capabilities.limits.max_fragment_combined_output_resources = properties.limits.maxFragmentCombinedOutputResources; + capabilities.limits.max_compute_shared_memory_size = properties.limits.maxComputeSharedMemorySize; + stdr::copy(properties.limits.maxComputeWorkGroupCount, stdr::begin(capabilities.limits.max_compute_work_group_count)); + capabilities.limits.max_compute_work_group_invocations = properties.limits.maxComputeWorkGroupInvocations; + stdr::copy(properties.limits.maxComputeWorkGroupSize, stdr::begin(capabilities.limits.max_compute_work_group_size)); + capabilities.limits.sub_pixel_precision_bits = properties.limits.subPixelPrecisionBits; + capabilities.limits.sub_texel_precision_bits = properties.limits.subTexelPrecisionBits; + capabilities.limits.mipmap_precision_bits = properties.limits.mipmapPrecisionBits; + capabilities.limits.max_draw_indexed_index_value = properties.limits.maxDrawIndexedIndexValue; + capabilities.limits.max_draw_indirect_count = properties.limits.maxDrawIndirectCount; + capabilities.limits.max_sampler_lod_bias = properties.limits.maxSamplerLodBias; + capabilities.limits.max_sampler_anisotropy = properties.limits.maxSamplerAnisotropy; + capabilities.limits.max_viewports = properties.limits.maxViewports; + stdr::copy(properties.limits.maxViewportDimensions, stdr::begin(capabilities.limits.max_viewport_dimensions)); + stdr::copy(properties.limits.viewportBoundsRange, stdr::begin(capabilities.limits.viewport_bounds_range)); + capabilities.limits.viewport_sub_pixel_bits = properties.limits.viewportSubPixelBits; + capabilities.limits.min_memory_map_alignment = properties.limits.minMemoryMapAlignment; + capabilities.limits.min_texel_buffer_offset_alignment = properties.limits.minTexelBufferOffsetAlignment; + capabilities.limits.min_uniform_buffer_offset_alignment = properties.limits.minUniformBufferOffsetAlignment; + capabilities.limits.min_storage_buffer_offset_alignment = properties.limits.minStorageBufferOffsetAlignment; + capabilities.limits.min_texel_offset = properties.limits.minTexelOffset; + capabilities.limits.max_texel_offset = properties.limits.maxTexelOffset; + capabilities.limits.min_texel_gather_offset = properties.limits.minTexelGatherOffset; + capabilities.limits.max_texel_gather_offset = properties.limits.maxTexelGatherOffset; + capabilities.limits.min_interpolation_offset = properties.limits.minInterpolationOffset; + capabilities.limits.max_interpolation_offset = properties.limits.maxInterpolationOffset; + capabilities.limits.sub_pixel_interpolation_offset_bits = properties.limits.subPixelInterpolationOffsetBits; + capabilities.limits.max_framebuffer_width = properties.limits.maxFramebufferWidth; + capabilities.limits.max_framebuffer_height = properties.limits.maxFramebufferHeight; + capabilities.limits.max_framebuffer_layers = properties.limits.maxFramebufferLayers; + capabilities.limits.framebuffer_color_sample_counts = narrow< + SampleCountFlag>(properties.limits.framebufferColorSampleCounts); + capabilities.limits.framebuffer_depth_sample_counts = narrow< + SampleCountFlag>(properties.limits.framebufferDepthSampleCounts); + capabilities.limits.framebuffer_stencil_sample_counts = narrow< + SampleCountFlag>(properties.limits.framebufferStencilSampleCounts); + capabilities.limits.framebuffer_no_attachments_sample_counts = narrow< + SampleCountFlag>(properties.limits.framebufferNoAttachmentsSampleCounts); + capabilities.limits.max_color_attachments = properties.limits.maxColorAttachments; + capabilities.limits.sampled_image_color_sample_counts = narrow< + SampleCountFlag>(properties.limits.sampledImageColorSampleCounts); + capabilities.limits.sampled_image_integer_sample_counts = narrow< + SampleCountFlag>(properties.limits.sampledImageIntegerSampleCounts); + capabilities.limits.sampled_image_depth_sample_counts = narrow< + SampleCountFlag>(properties.limits.sampledImageDepthSampleCounts); + capabilities.limits.sampled_image_stencil_sample_counts = narrow< + SampleCountFlag>(properties.limits.sampledImageStencilSampleCounts); + capabilities.limits.storage_image_sample_counts = narrow(properties.limits.storageImageSampleCounts); + capabilities.limits.max_sample_mask_words = properties.limits.maxSampleMaskWords; + capabilities.limits.timestamp_compute_and_engine = properties.limits.timestampComputeAndGraphics; + capabilities.limits.timestamp_period = properties.limits.timestampPeriod; + capabilities.limits.max_clip_distances = properties.limits.maxClipDistances; + capabilities.limits.max_cull_distances = properties.limits.maxCullDistances; + capabilities.limits.max_combined_clip_and_cull_distances = properties.limits.maxCombinedClipAndCullDistances; + capabilities.limits.discrete_queue_priorities = properties.limits.discreteQueuePriorities; + stdr::copy(properties.limits.pointSizeRange, stdr::begin(capabilities.limits.point_size_range)); + stdr::copy(properties.limits.lineWidthRange, stdr::begin(capabilities.limits.line_width_range)); + capabilities.limits.point_size_granularity = properties.limits.pointSizeGranularity; + capabilities.limits.line_width_granularity = properties.limits.lineWidthGranularity; + capabilities.limits.strict_lines = properties.limits.strictLines; + capabilities.limits.standard_sample_locations = properties.limits.standardSampleLocations; + capabilities.limits.optimal_buffer_copy_offset_alignment = properties.limits.optimalBufferCopyOffsetAlignment; + capabilities.limits.optimal_buffer_copy_row_pitch_alignment = properties.limits.optimalBufferCopyRowPitchAlignment; + capabilities.limits.non_coherent_atom_size = properties.limits.nonCoherentAtomSize; + + capabilities.features.robust_buffer_access = features.robustBufferAccess; + capabilities.features.full_draw_index_uint32 = features.fullDrawIndexUint32; + capabilities.features.image_cube_array = features.imageCubeArray; + capabilities.features.independent_blend = features.independentBlend; + capabilities.features.geometry_shader = features.geometryShader; + capabilities.features.tessellation_shader = features.tessellationShader; + capabilities.features.sampler_rate_shading = features.sampleRateShading; + capabilities.features.dual_src_blend = features.dualSrcBlend; + capabilities.features.logic_op = features.logicOp; + capabilities.features.multi_draw_indirect = features.multiDrawIndirect; + capabilities.features.draw_indirect_first_instance = features.drawIndirectFirstInstance; + capabilities.features.depth_clamp = features.depthClamp; + capabilities.features.depth_bias_clamp = features.depthBiasClamp; + capabilities.features.fill_Mode_non_solid = features.fillModeNonSolid; + capabilities.features.depth_bounds = features.depthBounds; + capabilities.features.wide_lines = features.wideLines; + capabilities.features.large_points = features.largePoints; + capabilities.features.alpha_to_one = features.alphaToOne; + capabilities.features.multi_viewport = features.multiViewport; + capabilities.features.sampler_anisotropy = features.samplerAnisotropy; + capabilities.features.texture_compression_etc2 = features.textureCompressionETC2; + capabilities.features.texture_compression_astc_ldr = features.textureCompressionASTC_LDR; + capabilities.features.texture_compression_bc = features.textureCompressionBC; + capabilities.features.occlusion_query_precise = features.occlusionQueryPrecise; + capabilities.features.pipeline_statistics_query = features.pipelineStatisticsQuery; + capabilities.features.vertex_pipeline_stores_and_atomics = features.vertexPipelineStoresAndAtomics; + capabilities.features.fragment_stores_and_atomics = features.fragmentStoresAndAtomics; + capabilities.features.shader_tessellation_and_geometry_point_size = features.shaderTessellationAndGeometryPointSize; + capabilities.features.shader_image_gather_extended = features.shaderImageGatherExtended; + capabilities.features.shader_storage_image_extended_formats = features.shaderStorageImageExtendedFormats; + capabilities.features.shader_storage_image_multisample = features.shaderStorageImageMultisample; + capabilities.features.shader_storage_image_read_without_format = features.shaderStorageImageReadWithoutFormat; + capabilities.features.shader_storage_image_write_without_format = features.shaderStorageImageWriteWithoutFormat; + capabilities.features.shader_uniform_buffer_array_dynamic_indexing = features.shaderUniformBufferArrayDynamicIndexing; + capabilities.features.shader_sampled_image_array_dynamic_indexing = features.shaderSampledImageArrayDynamicIndexing; + capabilities.features.shader_storage_buffer_array_dynamic_indexing = features.shaderStorageBufferArrayDynamicIndexing; + capabilities.features.shader_storage_image_array_dynamic_indexing = features.shaderStorageImageArrayDynamicIndexing; + capabilities.features.shader_clip_distance = features.shaderClipDistance; + capabilities.features.shader_cull_distance = features.shaderCullDistance; + capabilities.features.shader_float_64 = features.shaderFloat64; + capabilities.features.shader_int_64 = features.shaderInt64; + capabilities.features.shader_int_16 = features.shaderInt16; + capabilities.features.shader_resource_residency = features.shaderResourceResidency; + capabilities.features.shader_resource_min_lod = features.shaderResourceMinLod; + capabilities.features.sparse_binding = features.sparseBinding; + capabilities.features.sparse_residency_buffer = features.sparseResidencyBuffer; + capabilities.features.sparse_residency_image_2D = features.sparseResidencyImage2D; + capabilities.features.sparse_residency_image_3D = features.sparseResidencyImage3D; + capabilities.features.sparse_residency_2_samples = features.sparseResidency2Samples; + capabilities.features.sparse_residency_4_samples = features.sparseResidency4Samples; + capabilities.features.sparse_residency_8_samples = features.sparseResidency8Samples; + capabilities.features.sparse_residency_16_samples = features.sparseResidency16Samples; + capabilities.features.sparse_residency_aliased = features.sparseResidencyAliased; + capabilities.features.variable_multisample_rate = features.variableMultisampleRate; + capabilities.features.inherited_queries = features.inheritedQueries; + + return capabilities; + } + + auto memory_types(const PhysicalDeviceImplementation& physical_device) noexcept -> dyn_array { + const auto& handle = physical_device.native_handle(); + const auto vk_memory_properties = vk::call(vkGetPhysicalDeviceMemoryProperties, + handle); + + return transform(array_view { vk_memory_properties.memoryTypes, 32 }, [](const auto& type) static noexcept { + return narrow(type.propertyFlags); + }); + } + + auto queue_families(const PhysicalDeviceImplementation& physical_device) noexcept -> dyn_array { + const auto& handle = physical_device.native_handle(); + return transform(vk::enumerate(vkGetPhysicalDeviceQueueFamilyProperties, handle), + [](const auto& family) static noexcept { + return QueueFamily { .flags = narrow(family.queueFlags), .count = family.queueCount }; + }); + } + + auto extensions(const PhysicalDeviceImplementation& physical_device, const PhysicalDeviceInfo& info) noexcept + -> dyn_array { + const auto& handle = physical_device.native_handle(); + const auto extensions = TryAssert(vk::enumerate_checked(vkEnumerateDeviceExtensionProperties, + handle, + nullptr), + format("Failed to enumerate device {} extensions properties", info.device_name)); + + Return transform(extensions, [](const auto& extension) static noexcept { + const auto string_size = std::char_traits::length(extension.extensionName); + + return string { extension.extensionName, string_size }; + }); + } + + auto formats_properties(const PhysicalDeviceImplementation& physical_device) noexcept + -> dyn_array> { + const auto& handle = physical_device.native_handle(); + return transform(cm::enumerate(), [&handle](const auto val) noexcept { + return std::make_pair(val, + vk::from_vk(vk::call(vkGetPhysicalDeviceFormatProperties, + handle, + vk::to_vk(val)))); + }); + } } // namespace ///////////////////////////////////// ///////////////////////////////////// - auto score_physical_device(const PhysicalDevice& physical_device) noexcept -> u64 { + auto score_physical_device(view::PhysicalDevice physical_device) noexcept -> u64 { const auto support_raytracing = physical_device.check_extension_support(RAYTRACING_EXTENSIONS); auto score = u64 { 0u }; @@ -70,296 +346,23 @@ namespace stormkit::gpu { // TODO implement // https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_driver_properties.html - ///////////////////////////////////// - ///////////////////////////////////// - PhysicalDevice::PhysicalDevice(VkPhysicalDevice physical_device) noexcept : m_vk_handle { physical_device } { - const auto properties = vk_call(vkGetPhysicalDeviceProperties, m_vk_handle); - // TODO port to vkGetPhysicalDeviceFeatures2 - const auto features = vk_call(vkGetPhysicalDeviceFeatures, m_vk_handle); - - const auto vendor_id = properties.vendorID; - - m_device_info.device_id = properties.deviceID; - - const auto device_name_size = std::char_traits::length(properties.deviceName); - - m_device_info.device_name.resize(device_name_size); - stdr::copy(std::string_view { properties.deviceName, device_name_size }, std::begin(m_device_info.device_name)); - // std::char_traits::copy(std::data(m_device_info.device_name), - // std::data(properties.deviceName), - // device_name_size); - // m_device_info.device_name.shrink_to_fit(); - - m_device_info.vendor_id = vendor_id; - m_device_info.vendor_name = vendor_name_by_id(vendor_id); - m_device_info.api_major_version = vk_version_major(properties.apiVersion); - m_device_info.api_minor_version = vk_version_minor(properties.apiVersion); - m_device_info.api_patch_version = vk_version_patch(properties.apiVersion); - - m_device_info.driver_major_version = vk_version_major(properties.driverVersion); - m_device_info.driver_minor_version = vk_version_minor(properties.driverVersion); - m_device_info.driver_patch_version = vk_version_patch(properties.driverVersion); - std::ranges::copy(properties.pipelineCacheUUID, std::ranges::begin(m_device_info.pipeline_cache_uuid)); - - m_device_info.type = from_vk(properties.deviceType); - - m_capabilities.limits.max_image_dimension_1D = properties.limits.maxImageDimension1D; - m_capabilities.limits.max_image_dimension_2D = properties.limits.maxImageDimension2D; - m_capabilities.limits.max_image_dimension_3D = properties.limits.maxImageDimension3D; - m_capabilities.limits.max_image_dimension_cube = properties.limits.maxImageDimensionCube; - m_capabilities.limits.max_image_array_layers = properties.limits.maxImageArrayLayers; - m_capabilities.limits.max_texel_buffer_elements = properties.limits.maxTexelBufferElements; - m_capabilities.limits.max_uniform_buffer_range = properties.limits.maxUniformBufferRange; - m_capabilities.limits.max_storage_buffer_range = properties.limits.maxStorageBufferRange; - m_capabilities.limits.max_push_constants_size = properties.limits.maxPushConstantsSize; - m_capabilities.limits.max_memory_allocation_count = properties.limits.maxMemoryAllocationCount; - m_capabilities.limits.max_sampler_allocation_count = properties.limits.maxSamplerAllocationCount; - m_capabilities.limits.buffer_image_granularity = properties.limits.bufferImageGranularity; - m_capabilities.limits.sparse_address_space_size = properties.limits.sparseAddressSpaceSize; - m_capabilities.limits.max_bound_descriptor_sets = properties.limits.maxBoundDescriptorSets; - m_capabilities.limits.max_per_stage_descriptor_samplers = properties.limits.maxPerStageDescriptorSamplers; - m_capabilities.limits.max_per_stage_descriptor_uniform_buffers = properties.limits.maxPerStageDescriptorUniformBuffers; - m_capabilities.limits.max_per_stage_descriptor_storage_buffers = properties.limits.maxPerStageDescriptorStorageBuffers; - m_capabilities.limits.max_per_stage_descriptor_sampled_images = properties.limits.maxPerStageDescriptorSampledImages; - m_capabilities.limits.max_per_stage_descriptor_storage_images = properties.limits.maxPerStageDescriptorStorageImages; - m_capabilities.limits.max_per_stage_descriptor_input_attachments = properties.limits - .maxPerStageDescriptorInputAttachments; - m_capabilities.limits.max_per_stage_resources = properties.limits.maxPerStageResources; - m_capabilities.limits.max_descriptor_set_samplers = properties.limits.maxDescriptorSetSamplers; - m_capabilities.limits.max_descriptor_set_uniform_buffers = properties.limits.maxDescriptorSetUniformBuffers; - m_capabilities.limits.max_descriptor_set_uniform_buffers_dynamic = properties.limits - .maxDescriptorSetUniformBuffersDynamic; - m_capabilities.limits.max_descriptor_set_storage_buffers = properties.limits.maxDescriptorSetStorageBuffers; - m_capabilities.limits.max_descriptor_set_storage_buffers_dynamic = properties.limits - .maxDescriptorSetStorageBuffersDynamic; - m_capabilities.limits.max_descriptor_set_sampled_images = properties.limits.maxDescriptorSetSampledImages; - m_capabilities.limits.max_descriptor_set_storage_images = properties.limits.maxDescriptorSetStorageImages; - m_capabilities.limits.max_descriptor_set_input_attachments = properties.limits.maxDescriptorSetInputAttachments; - m_capabilities.limits.max_vertex_input_attributes = properties.limits.maxVertexInputAttributes; - m_capabilities.limits.max_vertex_input_bindings = properties.limits.maxVertexInputBindings; - m_capabilities.limits.max_vertex_input_attribute_offset = properties.limits.maxVertexInputAttributeOffset; - m_capabilities.limits.max_vertex_input_binding_stride = properties.limits.maxVertexInputBindingStride; - m_capabilities.limits.max_vertex_output_components = properties.limits.maxVertexOutputComponents; - m_capabilities.limits.max_tessellation_generation_level = properties.limits.maxTessellationGenerationLevel; - m_capabilities.limits.max_tessellation_patch_size = properties.limits.maxTessellationPatchSize; - m_capabilities.limits.max_tessellation_control_per_vertex_input_components - = properties.limits.maxTessellationControlPerVertexInputComponents; - m_capabilities.limits.max_tessellation_control_per_vertex_output_components - = properties.limits.maxTessellationControlPerVertexOutputComponents; - m_capabilities.limits.max_tessellation_control_per_patch_output_components - = properties.limits.maxTessellationControlPerPatchOutputComponents; - m_capabilities.limits.max_tessellation_control_total_output_components = properties.limits - .maxTessellationControlTotalOutputComponents; - m_capabilities.limits.max_tessellation_evaluation_input_components = properties.limits - .maxTessellationEvaluationInputComponents; - m_capabilities.limits.max_tessellation_evaluation_output_components = properties.limits - .maxTessellationEvaluationOutputComponents; - m_capabilities.limits.max_geometry_shader_invocations = properties.limits.maxGeometryShaderInvocations; - m_capabilities.limits.max_geometry_input_components = properties.limits.maxGeometryInputComponents; - m_capabilities.limits.max_geometry_output_components = properties.limits.maxGeometryOutputComponents; - m_capabilities.limits.max_geometry_output_vertices = properties.limits.maxGeometryOutputVertices; - m_capabilities.limits.max_geometry_total_output_components = properties.limits.maxGeometryTotalOutputComponents; - m_capabilities.limits.max_fragment_input_components = properties.limits.maxFragmentInputComponents; - m_capabilities.limits.max_fragment_output_attachments = properties.limits.maxFragmentOutputAttachments; - m_capabilities.limits.max_fragment_dual_src_attachments = properties.limits.maxFragmentDualSrcAttachments; - m_capabilities.limits.max_fragment_combined_output_resources = properties.limits.maxFragmentCombinedOutputResources; - m_capabilities.limits.max_compute_shared_memory_size = properties.limits.maxComputeSharedMemorySize; - std::ranges::copy(properties.limits.maxComputeWorkGroupCount, - std::ranges::begin(m_capabilities.limits.max_compute_work_group_count)); - m_capabilities.limits.max_compute_work_group_invocations = properties.limits.maxComputeWorkGroupInvocations; - std::ranges::copy(properties.limits.maxComputeWorkGroupSize, - std::ranges::begin(m_capabilities.limits.max_compute_work_group_size)); - m_capabilities.limits.sub_pixel_precision_bits = properties.limits.subPixelPrecisionBits; - m_capabilities.limits.sub_texel_precision_bits = properties.limits.subTexelPrecisionBits; - m_capabilities.limits.mipmap_precision_bits = properties.limits.mipmapPrecisionBits; - m_capabilities.limits.max_draw_indexed_index_value = properties.limits.maxDrawIndexedIndexValue; - m_capabilities.limits.max_draw_indirect_count = properties.limits.maxDrawIndirectCount; - m_capabilities.limits.max_sampler_lod_bias = properties.limits.maxSamplerLodBias; - m_capabilities.limits.max_sampler_anisotropy = properties.limits.maxSamplerAnisotropy; - m_capabilities.limits.max_viewports = properties.limits.maxViewports; - std::ranges::copy(properties.limits.maxViewportDimensions, - std::ranges::begin(m_capabilities.limits.max_viewport_dimensions)); - std::ranges::copy(properties.limits.viewportBoundsRange, std::ranges::begin(m_capabilities.limits.viewport_bounds_range)); - m_capabilities.limits.viewport_sub_pixel_bits = properties.limits.viewportSubPixelBits; - m_capabilities.limits.min_memory_map_alignment = properties.limits.minMemoryMapAlignment; - m_capabilities.limits.min_texel_buffer_offset_alignment = properties.limits.minTexelBufferOffsetAlignment; - m_capabilities.limits.min_uniform_buffer_offset_alignment = properties.limits.minUniformBufferOffsetAlignment; - m_capabilities.limits.min_storage_buffer_offset_alignment = properties.limits.minStorageBufferOffsetAlignment; - m_capabilities.limits.min_texel_offset = properties.limits.minTexelOffset; - m_capabilities.limits.max_texel_offset = properties.limits.maxTexelOffset; - m_capabilities.limits.min_texel_gather_offset = properties.limits.minTexelGatherOffset; - m_capabilities.limits.max_texel_gather_offset = properties.limits.maxTexelGatherOffset; - m_capabilities.limits.min_interpolation_offset = properties.limits.minInterpolationOffset; - m_capabilities.limits.max_interpolation_offset = properties.limits.maxInterpolationOffset; - m_capabilities.limits.sub_pixel_interpolation_offset_bits = properties.limits.subPixelInterpolationOffsetBits; - m_capabilities.limits.max_framebuffer_width = properties.limits.maxFramebufferWidth; - m_capabilities.limits.max_framebuffer_height = properties.limits.maxFramebufferHeight; - m_capabilities.limits.max_framebuffer_layers = properties.limits.maxFramebufferLayers; - m_capabilities.limits.framebuffer_color_sample_counts = narrow(properties.limits - .framebufferColorSampleCounts); - m_capabilities.limits.framebuffer_depth_sample_counts = narrow(properties.limits - .framebufferDepthSampleCounts); - m_capabilities.limits.framebuffer_stencil_sample_counts = narrow(properties.limits - .framebufferStencilSampleCounts); - m_capabilities.limits.framebuffer_no_attachments_sample_counts = narrow< - SampleCountFlag>(properties.limits.framebufferNoAttachmentsSampleCounts); - m_capabilities.limits.max_color_attachments = properties.limits.maxColorAttachments; - m_capabilities.limits.sampled_image_color_sample_counts = narrow(properties.limits - .sampledImageColorSampleCounts); - m_capabilities.limits.sampled_image_integer_sample_counts = narrow(properties.limits - .sampledImageIntegerSampleCounts); - m_capabilities.limits.sampled_image_depth_sample_counts = narrow(properties.limits - .sampledImageDepthSampleCounts); - m_capabilities.limits.sampled_image_stencil_sample_counts = narrow(properties.limits - .sampledImageStencilSampleCounts); - m_capabilities.limits.storage_image_sample_counts = narrow(properties.limits.storageImageSampleCounts); - m_capabilities.limits.max_sample_mask_words = properties.limits.maxSampleMaskWords; - m_capabilities.limits.timestamp_compute_and_engine = properties.limits.timestampComputeAndGraphics; - m_capabilities.limits.timestamp_period = properties.limits.timestampPeriod; - m_capabilities.limits.max_clip_distances = properties.limits.maxClipDistances; - m_capabilities.limits.max_cull_distances = properties.limits.maxCullDistances; - m_capabilities.limits.max_combined_clip_and_cull_distances = properties.limits.maxCombinedClipAndCullDistances; - m_capabilities.limits.discrete_queue_priorities = properties.limits.discreteQueuePriorities; - std::ranges::copy(properties.limits.pointSizeRange, std::ranges::begin(m_capabilities.limits.point_size_range)); - std::ranges::copy(properties.limits.lineWidthRange, std::ranges::begin(m_capabilities.limits.line_width_range)); - m_capabilities.limits.point_size_granularity = properties.limits.pointSizeGranularity; - m_capabilities.limits.line_width_granularity = properties.limits.lineWidthGranularity; - m_capabilities.limits.strict_lines = properties.limits.strictLines; - m_capabilities.limits.standard_sample_locations = properties.limits.standardSampleLocations; - m_capabilities.limits.optimal_buffer_copy_offset_alignment = properties.limits.optimalBufferCopyOffsetAlignment; - m_capabilities.limits.optimal_buffer_copy_row_pitch_alignment = properties.limits.optimalBufferCopyRowPitchAlignment; - m_capabilities.limits.non_coherent_atom_size = properties.limits.nonCoherentAtomSize; - - m_capabilities.features.robust_buffer_access = features.robustBufferAccess; - m_capabilities.features.full_draw_index_uint32 = features.fullDrawIndexUint32; - m_capabilities.features.image_cube_array = features.imageCubeArray; - m_capabilities.features.independent_blend = features.independentBlend; - m_capabilities.features.geometry_shader = features.geometryShader; - m_capabilities.features.tessellation_shader = features.tessellationShader; - m_capabilities.features.sampler_rate_shading = features.sampleRateShading; - m_capabilities.features.dual_src_blend = features.dualSrcBlend; - m_capabilities.features.logic_op = features.logicOp; - m_capabilities.features.multi_draw_indirect = features.multiDrawIndirect; - m_capabilities.features.draw_indirect_first_instance = features.drawIndirectFirstInstance; - m_capabilities.features.depth_clamp = features.depthClamp; - m_capabilities.features.depth_bias_clamp = features.depthBiasClamp; - m_capabilities.features.fill_Mode_non_solid = features.fillModeNonSolid; - m_capabilities.features.depth_bounds = features.depthBounds; - m_capabilities.features.wide_lines = features.wideLines; - m_capabilities.features.large_points = features.largePoints; - m_capabilities.features.alpha_to_one = features.alphaToOne; - m_capabilities.features.multi_viewport = features.multiViewport; - m_capabilities.features.sampler_anisotropy = features.samplerAnisotropy; - m_capabilities.features.texture_compression_etc2 = features.textureCompressionETC2; - m_capabilities.features.texture_compression_astc_ldr = features.textureCompressionASTC_LDR; - m_capabilities.features.texture_compression_bc = features.textureCompressionBC; - m_capabilities.features.occlusion_query_precise = features.occlusionQueryPrecise; - m_capabilities.features.pipeline_statistics_query = features.pipelineStatisticsQuery; - m_capabilities.features.vertex_pipeline_stores_and_atomics = features.vertexPipelineStoresAndAtomics; - m_capabilities.features.fragment_stores_and_atomics = features.fragmentStoresAndAtomics; - m_capabilities.features.shader_tessellation_and_geometry_point_size = features.shaderTessellationAndGeometryPointSize; - m_capabilities.features.shader_image_gather_extended = features.shaderImageGatherExtended; - m_capabilities.features.shader_storage_image_extended_formats = features.shaderStorageImageExtendedFormats; - m_capabilities.features.shader_storage_image_multisample = features.shaderStorageImageMultisample; - m_capabilities.features.shader_storage_image_read_without_format = features.shaderStorageImageReadWithoutFormat; - m_capabilities.features.shader_storage_image_write_without_format = features.shaderStorageImageWriteWithoutFormat; - m_capabilities.features.shader_uniform_buffer_array_dynamic_indexing = features.shaderUniformBufferArrayDynamicIndexing; - m_capabilities.features.shader_sampled_image_array_dynamic_indexing = features.shaderSampledImageArrayDynamicIndexing; - m_capabilities.features.shader_storage_buffer_array_dynamic_indexing = features.shaderStorageBufferArrayDynamicIndexing; - m_capabilities.features.shader_storage_image_array_dynamic_indexing = features.shaderStorageImageArrayDynamicIndexing; - m_capabilities.features.shader_clip_distance = features.shaderClipDistance; - m_capabilities.features.shader_cull_distance = features.shaderCullDistance; - m_capabilities.features.shader_float_64 = features.shaderFloat64; - m_capabilities.features.shader_int_64 = features.shaderInt64; - m_capabilities.features.shader_int_16 = features.shaderInt16; - m_capabilities.features.shader_resource_residency = features.shaderResourceResidency; - m_capabilities.features.shader_resource_min_lod = features.shaderResourceMinLod; - m_capabilities.features.sparse_binding = features.sparseBinding; - m_capabilities.features.sparse_residency_buffer = features.sparseResidencyBuffer; - m_capabilities.features.sparse_residency_image_2D = features.sparseResidencyImage2D; - m_capabilities.features.sparse_residency_image_3D = features.sparseResidencyImage3D; - m_capabilities.features.sparse_residency_2_samples = features.sparseResidency2Samples; - m_capabilities.features.sparse_residency_4_samples = features.sparseResidency4Samples; - m_capabilities.features.sparse_residency_8_samples = features.sparseResidency8Samples; - m_capabilities.features.sparse_residency_16_samples = features.sparseResidency16Samples; - m_capabilities.features.sparse_residency_aliased = features.sparseResidencyAliased; - m_capabilities.features.variable_multisample_rate = features.variableMultisampleRate; - m_capabilities.features.inherited_queries = features.inheritedQueries; - - m_extensions = *vk_enumerate(vkEnumerateDeviceExtensionProperties, m_vk_handle, nullptr) - .transform_error(core::monadic::assert(format("Failed to enumerate device {} extensions properties", - m_device_info.device_name))) - | std::views::transform([](auto&& extension) noexcept { - const auto string_size = std::char_traits::length(extension.extensionName); - - auto string = std::string {}; - string.resize(string_size); - stdr::copy(std::string_view { extension.extensionName, string_size }, std::begin(string)); - return string; - }) - | std::ranges::to(); - - const auto vk_memory_properties = vk_call(vkGetPhysicalDeviceMemoryProperties, - m_vk_handle); - m_memory_types = vk_memory_properties.memoryTypes - | std::views::transform([](auto&& type) static noexcept { - return core::narrow(type.propertyFlags); - }) - | std::ranges::to(); - - m_queue_families = vk_enumerate(vkGetPhysicalDeviceQueueFamilyProperties, m_vk_handle) - | std::views::transform([](auto&& family) static noexcept { - return QueueFamily { .flags = narrow(family.queueFlags), .count = family.queueCount }; - }) - | std::ranges::to(); - - const auto format_values = core::meta::enumerate(); - for (const auto val : format_values) { - m_format_properties - .emplace_back(val, - from_vk(vk_call(vkGetPhysicalDeviceFormatProperties, - m_vk_handle, - to_vk(val)))); - } - } - ///////////////////////////////////// - ///////////////////////////////////// - PhysicalDevice::~PhysicalDevice() = default; + template class PhysicalDeviceInterface; + template class PhysicalDeviceInterface; ///////////////////////////////////// ///////////////////////////////////// - PhysicalDevice::PhysicalDevice(PhysicalDevice&& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - auto PhysicalDevice::operator=(PhysicalDevice&& other) noexcept -> PhysicalDevice& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - auto PhysicalDevice::check_extension_support(std::string_view extension) const noexcept -> bool { - return std::ranges::any_of(m_extensions, [extension](const auto& e) { return e == extension; }); - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto PhysicalDevice::check_extension_support(std::span extensions) const noexcept -> bool { - auto required_extensions = HashSet { std::ranges::begin(extensions), std::ranges::end(extensions) }; - // HashSet { std::ranges::begin(extensions), - // std::ranges::end(extensions) }; - - for (const auto& extension : m_extensions) required_extensions.erase(extension); - - return std::ranges::empty(required_extensions); - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto PhysicalDevice::check_extension_support(std::span extensions) const noexcept -> bool { - auto required_extensions = HashSet { std::ranges::begin(extensions), std::ranges::end(extensions) }; - - for (const auto& extension : m_extensions) required_extensions.erase(extension); - - return std::ranges::empty(required_extensions); + auto PhysicalDeviceImplementation::do_init(PrivateTag, VkPhysicalDevice&& physical_device) noexcept -> void { + m_vk_handle = std::move(physical_device); + + m_data = core::allocate_unsafe(Data { + .device_info = gpu::info(*this), + .capabilities = gpu::capabilities(*this), + }); + + m_memory_types = gpu::memory_types(*this); + m_extensions = gpu::extensions(*this, m_data->device_info); + m_queue_families = gpu::queue_families(*this); + m_format_properties = gpu::formats_properties(*this); } } // namespace stormkit::gpu diff --git a/src/gpu/core/semaphore.cpp b/src/gpu/core/semaphore.cpp new file mode 100644 index 000000000..c1f6905ad --- /dev/null +++ b/src/gpu/core/semaphore.cpp @@ -0,0 +1,41 @@ +// Copyright (C) 2023 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include +#include + +#include +#include + +module stormkit.gpu.core; + +import std; + +import stormkit.core; + +import :vulkan; + +namespace stormkit::gpu { + template class SemaphoreInterface; + template class SemaphoreInterface; + + ///////////////////////////////////// + ///////////////////////////////////// + auto SemaphoreImplementation::do_init(PrivateTag) noexcept -> Expected { + const auto create_info = VkSemaphoreCreateInfo { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + }; + + const auto& device = owner(); + const auto& device_table = device.device_table(); + m_vk_handle = Try(vk::call_checked(device_table.vkCreateSemaphore, device, &create_info, nullptr)); + + Return {}; + } +} // namespace stormkit::gpu diff --git a/src/gpu/core/surface.cpp b/src/gpu/core/surface.cpp index 85d434e8d..cd92ae8b0 100644 --- a/src/gpu/core/surface.cpp +++ b/src/gpu/core/surface.cpp @@ -6,6 +6,7 @@ module; #include #include +#include #if defined(STORMKIT_OS_LINUX) #include @@ -14,6 +15,7 @@ module; #include #endif +#include #define STORMKIT_DEFINE_VK_PLATFORM #include @@ -24,32 +26,35 @@ import std; import stormkit.core; import stormkit.wsi; -; - namespace stormkit::gpu { + template class SurfaceInterface; + template class SurfaceInterface; + ///////////////////////////////////// ///////////////////////////////////// - auto Surface::do_init_offscreen(const Instance& instance) noexcept -> Expected { - m_vk_instance = instance.native_handle(); + auto SurfaceImplementation::do_init(PrivateTag, const OffscreenCreateInfo&) noexcept -> Expected { assert(false, "not implemented yet"); return {}; } ///////////////////////////////////// ///////////////////////////////////// - auto Surface::do_init_from_window(const Instance& instance, const wsi::Window& window) noexcept -> Expected { + auto SurfaceImplementation::do_init(PrivateTag, const CreateInfo& create_info) noexcept -> Expected { + const auto& window = *create_info.window; + EXPECTS(window.is_open()); - m_vk_instance = instance.native_handle(); + const auto instance = owner(); + #if defined(STORMKIT_OS_WINDOWS) const auto create_surface = [&window, &instance] { const auto create_info = VkWin32SurfaceCreateInfoKHR { - .sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, - .pNext = nullptr, - .flags = 0, - .hinstance = GetModuleHandleW(nullptr), - .hwnd = std::bit_cast(window.native_handle()) + .sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, + .pNext = nullptr, + .flags = 0, + .m_hinstance = GetModuleHandleW(nullptr), + .hwnd = std::bit_cast(window.native_handle()) }; - return vk_call(vkCreateWin32SurfaceKHR, instance.native_handle(), &create_info, nullptr); + return vk::call_checked(vkCreateWin32SurfaceKHR, instance, &create_info, nullptr); }; #elif defined(STORMKIT_OS_MACOS) const auto create_surface = [&window, &instance] { @@ -59,8 +64,7 @@ namespace stormkit::gpu { .flags = 0, .pView = window.native_handle() }; - std::println("{}", window.native_handle()); - return vk_call(vkCreateMacOSSurfaceMVK, instance.native_handle(), &create_info, nullptr); + return vk::call_checked(vkCreateMacOSSurfaceMVK, instance, &create_info, nullptr); }; #elif defined(STORMKIT_OS_LINUX) const auto make_wayland_surface = [&window, &instance] { @@ -76,7 +80,7 @@ namespace stormkit::gpu { .display = handles->display, .surface = handles->surface }; - return vk_call(vkCreateWaylandSurfaceKHR, instance.native_handle(), &create_info, nullptr); + return vk::call_checked(vkCreateWaylandSurfaceKHR, instance, &create_info, nullptr); }; const auto make_xcb_surface = [&window, &instance] { struct Handles { @@ -93,11 +97,11 @@ namespace stormkit::gpu { .connection = handles->connection, .window = handles->window }; - return vk_call(vkCreateXcbSurfaceKHR, instance.native_handle(), &create_info, nullptr); + return vk::call_checked(vkCreateXcbSurfaceKHR, instance, &create_info, nullptr); }; const auto create_surface = - [&window, &make_wayland_surface, &make_xcb_surface] noexcept -> FunctionRef()> { + [&window, &make_wayland_surface, &make_xcb_surface] noexcept -> std23::function_ref()> { const auto is_wayland = window.wm() == wsi::WM::WAYLAND; if (is_wayland) return make_wayland_surface; @@ -106,22 +110,22 @@ namespace stormkit::gpu { }(); #elif defined(STORMKIT_OS_IOS) - const auto create_surface = [this, &window, &instance] noexcept { + const auto create_surface = [this, &window, &m_instance] noexcept { const auto create_info = VkIOSSurfaceCreateInfoMVK { .sType = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK, .pNext = nullptr, .flags = 0, .pView = window->native_handle() }; - CHECK_VK_ERROR(vkCreateIOSSurfaceMVK(instance, &create_info, &m_surface)); + CHECK_VK_ERROR(vkCreateIOSSurfaceMVK(m_instance, &create_info, &m_surface)); }; #else const auto create_surface = [] static noexcept {}; assertWithMessage(true, "This platform WSI is not supported !"); #endif - m_vk_handle = { [vk_instance = m_vk_instance](auto handle) noexcept { - vkDestroySurfaceKHR(vk_instance, handle, nullptr); - } }; - return create_surface().transform(core::monadic::set(m_vk_handle)).transform_error(core::monadic::narrow()); + + m_vk_handle = Try(create_surface()); + + Return {}; } } // namespace stormkit::gpu diff --git a/src/gpu/core/vulkan.cpp b/src/gpu/core/vulkan.cpp index be4ef9241..58a5eaac1 100644 --- a/src/gpu/core/vulkan.cpp +++ b/src/gpu/core/vulkan.cpp @@ -1,12 +1,14 @@ #include +#include + #define STORMKIT_DEFINE_VK_PLATFORM #define VOLK_IMPLEMENTATION #include #include "assert.hpp" -#define VMA_CALL_PRE STORMKIT_API +#define VMA_CALL_PRE STORMKIT_GPU_API #define VMA_IMPLEMENTATION #define VMA_ASSERT(expr) vma_assert(expr, #expr) #include diff --git a/src/gpu/execution/command_buffer.cpp b/src/gpu/execution/command_buffer.cpp index 42e2f227f..3327d049c 100644 --- a/src/gpu/execution/command_buffer.cpp +++ b/src/gpu/execution/command_buffer.cpp @@ -6,6 +6,7 @@ module; #include #include +#include #include @@ -25,28 +26,30 @@ using namespace std::literals; namespace stdr = std::ranges; namespace stdv = std::views; +namespace cmonadic = stormkit::core::monadic; + namespace stormkit::gpu { namespace { - constexpr auto OLD_LAYOUT_ACCESS_MAP = frozen::make_unordered_map>({ - { VK_IMAGE_LAYOUT_UNDEFINED, { VK_ACCESS_NONE, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT } }, - { VK_IMAGE_LAYOUT_PREINITIALIZED, { VK_ACCESS_NONE, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT } }, - { VK_IMAGE_LAYOUT_GENERAL, - { VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT } }, - { VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - { VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT } }, - { VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - { VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, - VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT } }, - { VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, - { VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT } }, - { VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - { VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT } }, - { VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, { VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT } }, - { VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, { VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT } }, - { VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, { VK_ACCESS_MEMORY_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT } }, + constexpr auto + OLD_LAYOUT_ACCESS_MAP = frozen::make_unordered_map>({ + { VK_IMAGE_LAYOUT_UNDEFINED, { VK_ACCESS_NONE, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT } }, + { VK_IMAGE_LAYOUT_PREINITIALIZED, { VK_ACCESS_NONE, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT } }, + { VK_IMAGE_LAYOUT_GENERAL, + { VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT } }, + { VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + { VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT } }, + { VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + { VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT } }, + { VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, + { VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT } }, + { VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + { VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT } }, + { VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, { VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT } }, + { VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, { VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT } }, + { VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, { VK_ACCESS_MEMORY_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT } }, }); constexpr auto NEW_LAYOUT_ACCESS_MAP = frozen::make_unordered_map inheritance_info) noexcept - -> Expected> { - EXPECTS(m_state == State::INITIAL); + template + auto CommandBufferInterface::reset() noexcept -> Expected { + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); - const auto vk_inheritance_info = [&inheritance_info] { - auto info = zeroed(); - info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; - if (inheritance_info) { - info.renderPass = to_vk(*inheritance_info->render_pass); - info.subpass = inheritance_info->subpass; - info.framebuffer = to_vk(*inheritance_info->framebuffer); - } - return info; - }(); + Try(vk::call_checked(device_table.vkResetCommandBuffer, *this, 0)); + *Base::m_state = CommandBuffer::State::INITIAL; + + Return {}; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto CommandBufferInterface::begin(bool one_time_submit, InheritanceInfo inheritance_info_variant) noexcept + -> Expected { + auto& state = *Base::m_state; + EXPECTS(state == CommandBuffer::State::INITIAL); + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + auto rendering_color_attachments = dyn_array {}; + auto vk_rendering_inheritance_info = init_by([](auto& info) noexcept { + info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO; + info.pNext = nullptr; + }); - const auto flags = [this, one_time_submit]() -> VkCommandBufferUsageFlags { + const auto vk_inheritance_info = + [&inheritance_info_variant, &rendering_color_attachments, &vk_rendering_inheritance_info] noexcept { + auto info = init_by([](auto& info) noexcept { + info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; + info.pNext = nullptr; + }); + + if (is(inheritance_info_variant)) { + const auto& inheritance_info = as(inheritance_info_variant); + info.renderPass = vk::to_vk(*inheritance_info.render_pass); + info.subpass = inheritance_info.subpass; + info.framebuffer = vk::to_vk(*inheritance_info.framebuffer); + } else if (is(inheritance_info_variant)) { + info.pNext = &vk_rendering_inheritance_info; + + const auto& inheritance_info = as(inheritance_info_variant); + + rendering_color_attachments = inheritance_info.color_attachments + | stdv::transform(gpu::vk::monadic::to_vk()) + | stdr::to>(); + vk_rendering_inheritance_info.viewMask = inheritance_info.view_mask; + vk_rendering_inheritance_info.colorAttachmentCount = as(stdr::size(inheritance_info.color_attachments)); + vk_rendering_inheritance_info.pColorAttachmentFormats = stdr::data(rendering_color_attachments); + + if (inheritance_info.depth_attachment) + vk_rendering_inheritance_info.depthAttachmentFormat = gpu::vk::to_vk< + VkFormat>(*inheritance_info.depth_attachment); + if (inheritance_info.stencil_attachment) + vk_rendering_inheritance_info.stencilAttachmentFormat = gpu::vk::to_vk< + VkFormat>(*inheritance_info.stencil_attachment); + + vk_rendering_inheritance_info.rasterizationSamples = gpu::vk::to_vk< + VkSampleCountFlagBits>(inheritance_info.rasterization_samples); + } + return info; + }(); + + const auto flags = [this, one_time_submit, &inheritance_info_variant] noexcept -> VkCommandBufferUsageFlags { auto flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; if (!one_time_submit) flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; - if (m_level == CommandBufferLevel::SECONDARY) flags |= VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; + if (level() == CommandBufferLevel::SECONDARY) { + if (is(inheritance_info_variant) + or is(inheritance_info_variant)) + flags |= VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT; + } return flags; }(); @@ -102,46 +159,200 @@ namespace stormkit::gpu { .pInheritanceInfo = &vk_inheritance_info, }; - return vk_call(m_vk_device_table->vkBeginCommandBuffer, m_vk_handle, &begin_info) - .transform([this, &self = *this] noexcept { - m_state = State::RECORDING; - return as_ref_mut(self); - }) - .transform_error(monadic::from_vk()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto CommandBuffer::begin_render_pass(const RenderPass& render_pass, - const FrameBuffer& framebuffer, - std::span clear_values, - bool secondary_commandbuffers) noexcept -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); - - const auto vk_clear_values = clear_values - | stdv::transform(core::monadic::either( - [](const ClearColor& clear_color) static noexcept -> decltype(auto) { - return VkClearValue { - .color = VkClearColorValue { .float32 = { clear_color.color.red, - clear_color.color.blue, - clear_color.color.green, - clear_color.color.alpha } }, - }; - }, - [](const ClearDepthStencil& clear_depth_stencil) static noexcept -> decltype(auto) { - return VkClearValue { - .depthStencil = VkClearDepthStencilValue { .depth = clear_depth_stencil.depth, - .stencil = clear_depth_stencil - .stencil }, - }; - })) - | stdr::to(); + Try(vk::call_checked(device_table.vkBeginCommandBuffer, *this, &begin_info)); + state = CommandBuffer::State::RECORDING; + + Return {}; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto CommandBufferInterface::end() noexcept -> Expected { + auto& state = *Base::m_state; + EXPECTS(state == CommandBuffer::State::RECORDING); + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + Try(vk::call_checked(device_table.vkEndCommandBuffer, *this)); + state = CommandBuffer::State::EXECUTABLE; + + Return {}; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto CommandBufferInterface::begin_debug_region(string_view name, const fcolor_rgb& color) const noexcept + -> const CommandBufferInterface& { + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + if (not vkCmdBeginDebugUtilsLabelEXT) [[unlikely]] + return *this; + + const auto info = VkDebugUtilsLabelEXT { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT, + .pNext = nullptr, + .pLabelName = stdr::data(name), + .color = { color.r, color.g, color.b, 1.f } + }; + + vk::call(vkCmdBeginDebugUtilsLabelEXT, *this, &info); + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto CommandBufferInterface::insert_debug_label(string_view name, const fcolor_rgb& color) const noexcept + -> const CommandBufferInterface& { + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + if (not vkCmdInsertDebugUtilsLabelEXT) [[unlikely]] + return *this; + + const auto info = VkDebugUtilsLabelEXT { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT, + .pNext = nullptr, + .pLabelName = stdr::data(name), + .color = { color.r, color.g, color.b, 1.f } + }; + + vk::call(vkCmdInsertDebugUtilsLabelEXT, *this, &info); + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto CommandBufferInterface::end_debug_region() const noexcept -> const CommandBufferInterface& { + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + if (not vkCmdEndDebugUtilsLabelEXT) [[unlikely]] + return *this; + + vk::call(vkCmdEndDebugUtilsLabelEXT, *this); + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto CommandBufferInterface::begin_rendering(const RenderingInfo& info, bool secondary) const noexcept + -> const CommandBufferInterface& { + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + auto to_vk_attachment = [](const auto& attachment) static noexcept { + auto attachment_info = VkRenderingAttachmentInfo { + .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO, + .pNext = nullptr, + .imageView = vk::to_vk(attachment.image_view), + .imageLayout = vk::to_vk(attachment.layout), + .resolveMode = {}, + .resolveImageView = nullptr, + .resolveImageLayout = {}, + .loadOp = vk::to_vk(attachment.load_op), + .storeOp = vk::to_vk(attachment.store_op), + .clearValue = {}, + }; + + if (attachment.resolve) { + auto& resolve = *attachment.resolve; + + attachment_info.resolveMode = vk::to_vk(resolve.mode); + attachment_info.resolveImageView = vk::to_vk(resolve.image_view); + attachment_info.resolveImageLayout = vk::to_vk(resolve.layout); + } + if (attachment.clear_value) { + attachment_info.clearValue = std:: + visit(Overloaded { [](const ClearColor& clear_color) static noexcept -> decltype(auto) { + return VkClearValue { + .color = VkClearColorValue { .float32 = { clear_color.color.r, + clear_color.color.b, + clear_color.color.g, + clear_color.color.a } }, + }; + }, + [](const ClearDepthStencil& clear_depth_stencil) static noexcept -> decltype(auto) { + return VkClearValue { + .depthStencil = VkClearDepthStencilValue { .depth = clear_depth_stencil.depth, + .stencil = clear_depth_stencil.stencil }, + }; + } }, + *attachment.clear_value); + } + + return attachment_info; + }; + + const auto color_attachments = transform(info.color_attachments, to_vk_attachment); + const auto depth_attachment = info.depth_attachment ? to_vk_attachment(*info.depth_attachment) + : VkRenderingAttachmentInfo {}; + const auto stencil_attachment = info.stencil_attachment ? to_vk_attachment(*info.stencil_attachment) + : VkRenderingAttachmentInfo {}; + + const auto rendering_info = VkRenderingInfo { + .sType = VK_STRUCTURE_TYPE_RENDERING_INFO, + .pNext = nullptr, + .flags = as((secondary) ? VK_RENDERING_CONTENTS_SECONDARY_COMMAND_BUFFERS_BIT : 0), + .renderArea = vk::to_vk(info.render_area), + .layerCount = info.layer_count, + .viewMask = info.view_mask, + .colorAttachmentCount = as(stdr::size(color_attachments)), + .pColorAttachments = stdr::data(color_attachments), + .pDepthAttachment = info.depth_attachment ? &depth_attachment : nullptr, + .pStencilAttachment = info.stencil_attachment ? &stencil_attachment : nullptr, + }; + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + vk::call(device_table.vkCmdBeginRenderingKHR, *this, &rendering_info); + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto CommandBufferInterface::begin_render_pass(view::RenderPass render_pass, + view::FrameBuffer framebuffer, + array_view clear_values, + bool secondary_commandbuffers) const noexcept + -> const CommandBufferInterface& { + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + const auto vk_clear_values = transform( + clear_values, + cmonadic::either( + [](const ClearColor& clear_color) static noexcept -> decltype(auto) { + return VkClearValue { + .color = VkClearColorValue { .float32 = { clear_color.color.r, + clear_color.color.b, + clear_color.color.g, + clear_color.color.a } }, + }; + }, + [](const ClearDepthStencil& clear_depth_stencil) static noexcept -> decltype(auto) { + return VkClearValue { + .depthStencil = VkClearDepthStencilValue { .depth = clear_depth_stencil.depth, + .stencil = clear_depth_stencil.stencil }, + }; + })); const auto begin_info = VkRenderPassBeginInfo { .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, .pNext = nullptr, - .renderPass = to_vk(render_pass), - .framebuffer = to_vk(framebuffer), + .renderPass = vk::to_vk(render_pass), + .framebuffer = vk::to_vk(framebuffer), .renderArea = VkRect2D { .offset = { 0, 0 }, .extent = { framebuffer.extent().width, framebuffer.extent().height } }, .clearValueCount = as(stdr::size(vk_clear_values)), .pClearValues = stdr::data(vk_clear_values), @@ -150,329 +361,650 @@ namespace stormkit::gpu { const auto subpass_content = secondary_commandbuffers ? VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS : VK_SUBPASS_CONTENTS_INLINE; - vk_call(m_vk_device_table->vkCmdBeginRenderPass, m_vk_handle, &begin_info, subpass_content); + vk::call(device_table.vkCmdBeginRenderPass, *this, &begin_info, subpass_content); return *this; } ///////////////////////////////////// ///////////////////////////////////// - auto CommandBuffer::set_viewport(u32 first_viewport, std::span viewports) noexcept -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); + template + auto CommandBufferInterface::next_subpass() const noexcept -> const CommandBufferInterface& { + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); - const auto vk_viewports = viewports | stdv::transform(monadic::to_vk()) | stdr::to(); + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); - vk_call(m_vk_device_table->vkCmdSetViewport, - m_vk_handle, - first_viewport, - stdr::size(vk_viewports), - stdr::data(vk_viewports)); + vk::call(device_table.vkCmdNextSubpass, *this, VK_SUBPASS_CONTENTS_INLINE); return *this; } ///////////////////////////////////// ///////////////////////////////////// - auto CommandBuffer::set_scissor(u32 first_scissor, std::span scissors) noexcept -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); + template + auto CommandBufferInterface::end_render_pass() const noexcept -> const CommandBufferInterface& { + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); - const auto vk_scissors = scissors | stdv::transform(monadic::to_vk()) | stdr::to(); + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); - vk_call(m_vk_device_table->vkCmdSetScissor, m_vk_handle, first_scissor, stdr::size(vk_scissors), stdr::data(vk_scissors)); + vk::call(device_table.vkCmdEndRenderPass, *this); return *this; } ///////////////////////////////////// ///////////////////////////////////// - auto CommandBuffer::bind_vertex_buffers(std::span> buffers, std::span offsets) noexcept - -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); - EXPECTS(not std::empty(buffers)); - EXPECTS(std::size(buffers) == std::size(offsets)); + template + auto CommandBufferInterface::end_rendering() const noexcept -> const CommandBufferInterface& { + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + vk::call(device_table.vkCmdEndRendering, *this); + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto CommandBufferInterface::bind_pipeline(view::Pipeline pipeline) const noexcept -> const CommandBufferInterface& { + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + const auto bind_point = (pipeline.type() == Pipeline::Type::RASTER) + ? VK_PIPELINE_BIND_POINT_GRAPHICS + : VK_PIPELINE_BIND_POINT_COMPUTE; + + vk::call(device_table.vkCmdBindPipeline, *this, bind_point, pipeline); + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto CommandBufferInterface::set_viewport(u32 first_viewport, array_view viewports) const noexcept + -> const CommandBufferInterface& { + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + const auto vk_viewports = transform(viewports, vk::monadic::to_vk()); + + vk::call(device_table.vkCmdSetViewport, *this, first_viewport, stdr::size(vk_viewports), stdr::data(vk_viewports)); + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto CommandBufferInterface::set_scissor(u32 first_scissor, array_view scissors) const noexcept + -> const CommandBufferInterface& { + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + const auto vk_scissors = transform(scissors, vk::monadic::to_vk()); + + vk::call(device_table.vkCmdSetScissor, *this, first_scissor, stdr::size(vk_scissors), stdr::data(vk_scissors)); + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto CommandBufferInterface::set_line_width(f32 width) const noexcept -> const CommandBufferInterface& { + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + vk::call(device_table.vkCmdSetLineWidth, *this, width); + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto CommandBufferInterface::set_depth_bias(f32 constant_factor, f32 clamp, f32 slope_factor) const noexcept + -> const CommandBufferInterface& { + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); - const auto vk_buffers = buffers | stdv::transform(monadic::to_vk()) | stdr::to(); + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); - vk_call(m_vk_device_table->vkCmdBindVertexBuffers, - m_vk_handle, - 0, - stdr::size(vk_buffers), - stdr::data(vk_buffers), - stdr::data(offsets)); + vk::call(device_table.vkCmdSetDepthBias, *this, constant_factor, clamp, slope_factor); return *this; } ///////////////////////////////////// ///////////////////////////////////// - auto CommandBuffer::bind_descriptor_sets(const Pipeline& pipeline, - const PipelineLayout& layout, - std::span> descriptor_sets, - std::span dynamic_offsets) noexcept -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); + template + auto CommandBufferInterface::set_blend_constants(array_view constants) const noexcept + -> const CommandBufferInterface& { + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + f32 data[] = { constants[0], constants[1], constants[2], constants[3] }; + + vk::call(device_table.vkCmdSetBlendConstants, *this, data); + return *this; + } - const auto bind_point = (pipeline.type() == Pipeline::Type::RASTER) ? VK_PIPELINE_BIND_POINT_GRAPHICS - : VK_PIPELINE_BIND_POINT_COMPUTE; + ///////////////////////////////////// + ///////////////////////////////////// + template + auto CommandBufferInterface::set_depth_bounds(f32 min, f32 max) const noexcept -> const CommandBufferInterface& { + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); - const auto vk_descriptor_sets = descriptor_sets | stdv::transform(monadic::to_vk()) | stdr::to(); + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); - vk_call(m_vk_device_table->vkCmdBindDescriptorSets, - m_vk_handle, - bind_point, - to_vk(layout), - 0, - stdr::size(vk_descriptor_sets), - stdr::data(vk_descriptor_sets), - stdr::size(dynamic_offsets), - stdr::data(dynamic_offsets)); + vk::call(device_table.vkCmdSetDepthBounds, *this, min, max); return *this; } ///////////////////////////////////// ///////////////////////////////////// - auto CommandBuffer::copy_buffer(const Buffer& src, const Buffer& dst, usize size, u64 src_offset, u64 dst_offset) noexcept - -> CommandBuffer& { - const auto vk_copy_buffers = std::array { + template + auto CommandBufferInterface::set_stencil_compare_mask(StencilFaceFlag face, u32 mask) const noexcept + -> const CommandBufferInterface& { + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + vk::call(device_table.vkCmdSetStencilCompareMask, *this, vk::to_vk(face), mask); + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto CommandBufferInterface::set_stencil_write_mask(StencilFaceFlag face, u32 mask) const noexcept + -> const CommandBufferInterface& { + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + vk::call(device_table.vkCmdSetStencilWriteMask, *this, vk::to_vk(face), mask); + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto CommandBufferInterface::set_stencil_reference(StencilFaceFlag face, u32 reference) const noexcept + -> const CommandBufferInterface& { + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + vk::call(device_table.vkCmdSetStencilReference, *this, vk::to_vk(face), reference); + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto CommandBufferInterface::dispatch(u32 group_count_x, u32 group_count_y, u32 group_count_z) const noexcept + -> const CommandBufferInterface& { + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + vk::call(device_table.vkCmdDispatch, *this, group_count_x, group_count_y, group_count_z); + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto CommandBufferInterface::draw(u32 vertex_count, u32 instance_count, u32 first_vertex, u32 first_instance) + const noexcept -> const CommandBufferInterface& { + EXPECTS(vertex_count > 0); + + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + vk::call(device_table.vkCmdDraw, *this, vertex_count, instance_count, first_vertex, first_instance); + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto CommandBufferInterface:: + draw_indexed(u32 index_count, u32 instance_count, u32 first_index, i32 vertex_offset, u32 first_instance) const noexcept + -> const CommandBufferInterface& { + EXPECTS(index_count > 0); + + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + vk::call(device_table.vkCmdDrawIndexed, *this, index_count, instance_count, first_index, vertex_offset, first_instance); + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto CommandBufferInterface::draw_indirect(view::Buffer buffer, usize offset, u32 draw_count, u32 stride) const noexcept + -> const CommandBufferInterface& { + EXPECTS(draw_count > 0); + + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + vk::call(device_table.vkCmdDrawIndirect, *this, buffer, offset, draw_count, stride); + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto CommandBufferInterface::draw_indexed_indirect(view::Buffer buffer, usize offset, u32 draw_count, u32 stride) + const noexcept -> const CommandBufferInterface& { + EXPECTS(draw_count > 0); + + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + vk::call(device_table.vkCmdDrawIndexedIndirect, *this, buffer, offset, draw_count, stride); + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto CommandBufferInterface::bind_vertex_buffers(array_view buffers, array_view offsets) + const noexcept -> const CommandBufferInterface& { + EXPECTS(not std::empty(buffers)); + EXPECTS(std::size(buffers) == std::size(offsets)); + + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + const auto vk_buffers = transform(buffers, vk::monadic::to_vk()); + + vk::call(device_table.vkCmdBindVertexBuffers, + *this, + 0, + stdr::size(vk_buffers), + stdr::data(vk_buffers), + stdr::data(offsets)); + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto CommandBufferInterface::bind_index_buffer(view::Buffer buffer, u64 offset, bool large_indices) const noexcept + -> const CommandBufferInterface& { + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + vk::call(device_table.vkCmdBindIndexBuffer, + *this, + buffer, + offset, + (large_indices) ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32); + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto CommandBufferInterface::bind_descriptor_sets(view::Pipeline pipeline, + view::PipelineLayout layout, + array_view descriptor_sets, + array_view dynamic_offsets) const noexcept + -> const CommandBufferInterface& { + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + const auto bind_point = (pipeline.type() == Pipeline::Type::RASTER) + ? VK_PIPELINE_BIND_POINT_GRAPHICS + : VK_PIPELINE_BIND_POINT_COMPUTE; + + const auto vk_descriptor_sets = transform(descriptor_sets, vk::monadic::to_vk()); + + vk::call(device_table.vkCmdBindDescriptorSets, + *this, + bind_point, + layout, + 0, + stdr::size(vk_descriptor_sets), + stdr::data(vk_descriptor_sets), + stdr::size(dynamic_offsets), + stdr::data(dynamic_offsets)); + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto CommandBufferInterface::copy_buffer(view::Buffer src, view::Buffer dst, usize size, u64 src_offset, u64 dst_offset) + const noexcept -> const CommandBufferInterface& { + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + const auto vk_copy_buffers = array { VkBufferCopy { .srcOffset = src_offset, .dstOffset = dst_offset, .size = size } }; - vk_call(m_vk_device_table->vkCmdCopyBuffer, - m_vk_handle, - to_vk(src), - to_vk(dst), - stdr::size(vk_copy_buffers), - stdr::data(vk_copy_buffers)); + vk::call(device_table.vkCmdCopyBuffer, *this, src, dst, stdr::size(vk_copy_buffers), stdr::data(vk_copy_buffers)); return *this; } ///////////////////////////////////// ///////////////////////////////////// - auto CommandBuffer::copy_buffer_to_image(const Buffer& src, - const Image& dst, - std::span buffer_image_copies) noexcept -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); - - const auto DEFAULT_COPY = std::array { + template + auto CommandBufferInterface::copy_buffer_to_image(view::Buffer src, + view::Image dst, + array_view buffer_image_copies) const noexcept + -> const CommandBufferInterface& { + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + const auto DEFAULT_COPY = array { BufferImageCopy { 0, 0, 0, {}, { 0, 0, 0 }, dst.extent() } }; if (stdr::empty(buffer_image_copies)) buffer_image_copies = DEFAULT_COPY; - const auto vk_copy_regions = buffer_image_copies - | stdv::transform([](auto&& buffer_image_copy) noexcept { - const auto image_subresource = VkImageSubresourceLayers { - .aspectMask = to_vk(buffer_image_copy.subresource_layers - .aspect_mask), - .mipLevel = buffer_image_copy.subresource_layers.mip_level, - .baseArrayLayer = buffer_image_copy.subresource_layers.base_array_layer, - .layerCount = buffer_image_copy.subresource_layers.layer_count, - }; - - return VkBufferImageCopy { .bufferOffset = buffer_image_copy.buffer_offset, - .bufferRowLength = buffer_image_copy.buffer_row_length, - .bufferImageHeight = buffer_image_copy.buffer_image_height, - .imageSubresource = image_subresource, - .imageOffset = to_vk(buffer_image_copy.offset), - .imageExtent = to_vk(buffer_image_copy.extent) }; - }) - | stdr::to(); + const auto vk_copy_regions = transform(buffer_image_copies, [](const auto& buffer_image_copy) static noexcept { + const auto image_subresource = VkImageSubresourceLayers { + .aspectMask = vk::to_vk(buffer_image_copy.subresource_layers.aspect_mask), + .mipLevel = buffer_image_copy.subresource_layers.mip_level, + .baseArrayLayer = buffer_image_copy.subresource_layers.base_array_layer, + .layerCount = buffer_image_copy.subresource_layers.layer_count, + }; + + return VkBufferImageCopy { + .bufferOffset = buffer_image_copy.buffer_offset, + .bufferRowLength = buffer_image_copy.buffer_row_length, + .bufferImageHeight = buffer_image_copy.buffer_image_height, + .imageSubresource = image_subresource, + .imageOffset = vk::to_vk(buffer_image_copy.offset), + .imageExtent = vk::to_vk(buffer_image_copy.extent) + }; + }); - vk_call(m_vk_device_table->vkCmdCopyBufferToImage, - m_vk_handle, - to_vk(src), - to_vk(dst), - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - stdr::size(vk_copy_regions), - stdr::data(vk_copy_regions)); + vk::call(device_table.vkCmdCopyBufferToImage, + *this, + src, + dst, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + stdr::size(vk_copy_regions), + stdr::data(vk_copy_regions)); return *this; } ///////////////////////////////////// ///////////////////////////////////// - auto CommandBuffer::copy_image_to_buffer(const Image& src, - const Buffer& dst, - std::span buffer_image_copies) noexcept -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); - - const auto DEFAULT_COPY = std::array { - BufferImageCopy { 0, 0, 0, {}, { 0, 0, 0 }, src.extent() } - }; + template + auto CommandBufferInterface::copy_image_to_buffer(view::Image src, + view::Buffer dst, + array_view buffer_image_copies) const noexcept + -> const CommandBufferInterface& { + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + const auto DEFAULT_COPY = into_array({ + BufferImageCopy { 0, 0, 0, {}, { 0, 0, 0 }, src.extent() } + }); if (stdr::empty(buffer_image_copies)) buffer_image_copies = DEFAULT_COPY; - const auto vk_copy_regions = buffer_image_copies - | stdv::transform([](auto&& buffer_image_copy) noexcept { - const auto image_subresource = VkImageSubresourceLayers { - .aspectMask = to_vk(buffer_image_copy.subresource_layers - .aspect_mask), - .mipLevel = buffer_image_copy.subresource_layers.mip_level, - .baseArrayLayer = buffer_image_copy.subresource_layers.base_array_layer, - .layerCount = buffer_image_copy.subresource_layers.layer_count, - }; - - return VkBufferImageCopy { .bufferOffset = buffer_image_copy.buffer_offset, - .bufferRowLength = buffer_image_copy.buffer_row_length, - .bufferImageHeight = buffer_image_copy.buffer_image_height, - .imageSubresource = image_subresource, - .imageOffset = to_vk(buffer_image_copy.offset), - .imageExtent = to_vk(buffer_image_copy.extent) }; - }) - | stdr::to(); - - vk_call(m_vk_device_table->vkCmdCopyImageToBuffer, - m_vk_handle, - to_vk(src), - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - to_vk(dst), - stdr::size(vk_copy_regions), - stdr::data(vk_copy_regions)); - return *this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto CommandBuffer::copy_image(const Image& src, - const Image& dst, - ImageLayout src_layout, - ImageLayout dst_layout, - const ImageSubresourceLayers& src_subresource_layers, - const ImageSubresourceLayers& dst_subresource_layers, - const math::Extent3& extent) noexcept -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); + const auto vk_copy_regions = transform(buffer_image_copies, [](const auto& buffer_image_copy) static noexcept { + const auto image_subresource = VkImageSubresourceLayers { + .aspectMask = vk::to_vk(buffer_image_copy.subresource_layers.aspect_mask), + .mipLevel = buffer_image_copy.subresource_layers.mip_level, + .baseArrayLayer = buffer_image_copy.subresource_layers.base_array_layer, + .layerCount = buffer_image_copy.subresource_layers.layer_count, + }; + + return VkBufferImageCopy { + .bufferOffset = buffer_image_copy.buffer_offset, + .bufferRowLength = buffer_image_copy.buffer_row_length, + .bufferImageHeight = buffer_image_copy.buffer_image_height, + .imageSubresource = image_subresource, + .imageOffset = vk::to_vk(buffer_image_copy.offset), + .imageExtent = vk::to_vk(buffer_image_copy.extent) + }; + }); + + vk::call(device_table.vkCmdCopyImageToBuffer, + *this, + src, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + dst, + stdr::size(vk_copy_regions), + stdr::data(vk_copy_regions)); + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto CommandBufferInterface::copy_image(view::Image src, + view::Image dst, + ImageLayout src_layout, + ImageLayout dst_layout, + const ImageSubresourceLayers& src_subresource_layers, + const ImageSubresourceLayers& dst_subresource_layers, + const math::uextent3& extent) const noexcept -> const CommandBufferInterface& { + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); const auto vk_src_subresource_layers = VkImageSubresourceLayers { - .aspectMask = to_vk(src_subresource_layers.aspect_mask), + .aspectMask = vk::to_vk(src_subresource_layers.aspect_mask), .mipLevel = src_subresource_layers.mip_level, .baseArrayLayer = src_subresource_layers.base_array_layer, .layerCount = src_subresource_layers.layer_count }; const auto vk_dst_subresource_layers = VkImageSubresourceLayers { - .aspectMask = to_vk(dst_subresource_layers.aspect_mask), + .aspectMask = vk::to_vk(dst_subresource_layers.aspect_mask), .mipLevel = dst_subresource_layers.mip_level, .baseArrayLayer = dst_subresource_layers.base_array_layer, .layerCount = dst_subresource_layers.layer_count }; - const auto vk_regions = std::array { - VkImageCopy { .srcSubresource = vk_src_subresource_layers, - .srcOffset = { 0, 0, 0 }, - .dstSubresource = vk_dst_subresource_layers, - .dstOffset = { 0, 0, 0 }, - .extent = to_vk(extent) } - }; + const auto vk_regions = into_array({ + VkImageCopy { .srcSubresource = vk_src_subresource_layers, + .srcOffset = { 0, 0, 0 }, + .dstSubresource = vk_dst_subresource_layers, + .dstOffset = { 0, 0, 0 }, + .extent = vk::to_vk(extent) } + }); - vk_call(m_vk_device_table->vkCmdCopyImage, - m_vk_handle, - to_vk(src), - to_vk(src_layout), - to_vk(dst), - to_vk(dst_layout), - stdr::size(vk_regions), - stdr::data(vk_regions)); + vk::call(device_table.vkCmdCopyImage, + *this, + src, + vk::to_vk(src_layout), + dst, + vk::to_vk(dst_layout), + stdr::size(vk_regions), + stdr::data(vk_regions)); return *this; } ///////////////////////////////////// ///////////////////////////////////// - auto CommandBuffer::resolve_image(const Image& src, - const Image& dst, - ImageLayout src_layout, - ImageLayout dst_layout, - const ImageSubresourceLayers& src_subresource_layers, - const ImageSubresourceLayers& dst_subresource_layers) noexcept -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); - - const auto vk_extent = to_vk(dst.extent()); + template + auto CommandBufferInterface::resolve_image(view::Image src, + view::Image dst, + ImageLayout src_layout, + ImageLayout dst_layout, + const ImageSubresourceLayers& src_subresource_layers, + const ImageSubresourceLayers& dst_subresource_layers) const noexcept + -> const CommandBufferInterface& { + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + const auto vk_extent = vk::to_vk(dst.extent()); const auto vk_src_subresource_layers = VkImageSubresourceLayers { - .aspectMask = to_vk(src_subresource_layers.aspect_mask), + .aspectMask = vk::to_vk(src_subresource_layers.aspect_mask), .mipLevel = src_subresource_layers.mip_level, .baseArrayLayer = src_subresource_layers.base_array_layer, .layerCount = src_subresource_layers.layer_count }; const auto vk_dst_subresource_layers = VkImageSubresourceLayers { - .aspectMask = to_vk(dst_subresource_layers.aspect_mask), + .aspectMask = vk::to_vk(dst_subresource_layers.aspect_mask), .mipLevel = dst_subresource_layers.mip_level, .baseArrayLayer = dst_subresource_layers.base_array_layer, .layerCount = dst_subresource_layers.layer_count }; - const auto vk_regions = std::array { - VkImageResolve { .srcSubresource = vk_src_subresource_layers, - .srcOffset = { 0, 0, 0 }, - .dstSubresource = vk_dst_subresource_layers, - .dstOffset = { 0, 0, 0 }, - .extent = vk_extent } - }; + const auto vk_regions = into_array({ + VkImageResolve { .srcSubresource = vk_src_subresource_layers, + .srcOffset = { 0, 0, 0 }, + .dstSubresource = vk_dst_subresource_layers, + .dstOffset = { 0, 0, 0 }, + .extent = vk_extent } + }); + + vk::call(device_table.vkCmdResolveImage, + *this, + src, + vk::to_vk(src_layout), + dst, + vk::to_vk(dst_layout), + stdr::size(vk_regions), + stdr::data(vk_regions)); + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto CommandBufferInterface::blit_image(view::Image src, + view::Image dst, + ImageLayout src_layout, + ImageLayout dst_layout, + array_view regions, + Filter filter) const noexcept -> const CommandBufferInterface& { + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + const auto vk_regions = transform(regions, [](const auto& region) static noexcept { + const auto vk_src_subresource_layers = VkImageSubresourceLayers { + .aspectMask = vk::to_vk(region.src.aspect_mask), + .mipLevel = region.src.mip_level, + .baseArrayLayer = region.src.base_array_layer, + .layerCount = region.src.layer_count + }; + + const auto vk_dst_subresource_layers = VkImageSubresourceLayers { + .aspectMask = vk::to_vk(region.dst.aspect_mask), + .mipLevel = region.dst.mip_level, + .baseArrayLayer = region.dst.base_array_layer, + .layerCount = region.dst.layer_count + }; + + return VkImageBlit { + .srcSubresource = vk_src_subresource_layers, + .srcOffsets = { vk::to_vk(region.src_offset.position), + vk::to_vk(region.src_offset.extent) }, + .dstSubresource = vk_dst_subresource_layers, + .dstOffsets = { vk::to_vk(region.dst_offset.position), + vk::to_vk(region.dst_offset.extent) }, + }; + }); - vk_call(m_vk_device_table->vkCmdResolveImage, - m_vk_handle, - to_vk(src), - to_vk(src_layout), - to_vk(dst), - to_vk(dst_layout), - stdr::size(vk_regions), - stdr::data(vk_regions)); - return *this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto CommandBuffer::blit_image(const Image& src, - const Image& dst, - ImageLayout src_layout, - ImageLayout dst_layout, - std::span regions, - Filter filter) noexcept -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); - - const auto vk_regions = regions - | stdv::transform([](auto&& region) noexcept { - const auto vk_src_subresource_layers = VkImageSubresourceLayers { - .aspectMask = to_vk(region.src.aspect_mask), - .mipLevel = region.src.mip_level, - .baseArrayLayer = region.src.base_array_layer, - .layerCount = region.src.layer_count - }; - - const auto vk_dst_subresource_layers = VkImageSubresourceLayers { - .aspectMask = to_vk(region.dst.aspect_mask), - .mipLevel = region.dst.mip_level, - .baseArrayLayer = region.dst.base_array_layer, - .layerCount = region.dst.layer_count - }; - - return VkImageBlit { - .srcSubresource = vk_src_subresource_layers, - .srcOffsets = { to_vk(region.src_offset[0]), - to_vk(region.src_offset[1]) }, - .dstSubresource = vk_dst_subresource_layers, - .dstOffsets = { to_vk(region.dst_offset[0]), - to_vk(region.dst_offset[1]) }, - }; - }) - | stdr::to(); - - vk_call(m_vk_device_table->vkCmdBlitImage, - m_vk_handle, - to_vk(src), - to_vk(src_layout), - to_vk(dst), - to_vk(dst_layout), - stdr::size(vk_regions), - stdr::data(vk_regions), - to_vk(filter)); - return *this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto CommandBuffer::transition_image_layout(const Image& image, - ImageLayout src_layout, - ImageLayout dst_layout, - const ImageSubresourceRange& subresource_range) noexcept -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); - - const auto vk_src_layout = to_vk(src_layout); - const auto vk_dst_layout = to_vk(dst_layout); + vk::call(device_table.vkCmdBlitImage, + *this, + vk::to_vk(src), + vk::to_vk(src_layout), + vk::to_vk(dst), + vk::to_vk(dst_layout), + stdr::size(vk_regions), + stdr::data(vk_regions), + vk::to_vk(filter)); + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto CommandBufferInterface::transition_image_layout(view::Image image, + ImageLayout src_layout, + ImageLayout dst_layout, + const ImageSubresourceRange& subresource_range) const noexcept + -> const CommandBufferInterface& { + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + const auto vk_src_layout = vk::to_vk(src_layout); + const auto vk_dst_layout = vk::to_vk(dst_layout); const auto& src_access = OLD_LAYOUT_ACCESS_MAP.find(vk_src_layout); const auto& dst_access = NEW_LAYOUT_ACCESS_MAP.find(vk_dst_layout); @@ -481,156 +1013,179 @@ namespace stormkit::gpu { const auto dst_stage = dst_access->second.second; const auto vk_subresource_range = VkImageSubresourceRange { - .aspectMask = to_vk(subresource_range.aspect_mask), + .aspectMask = vk::to_vk(subresource_range.aspect_mask), .baseMipLevel = subresource_range.base_mip_level, .levelCount = subresource_range.level_count, .baseArrayLayer = subresource_range.base_array_layer, .layerCount = subresource_range.layer_count, }; - const auto barriers = std::array { - VkImageMemoryBarrier { - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - .pNext = nullptr, - .srcAccessMask = src_access->second.first, - .dstAccessMask = dst_access->second.first, - .oldLayout = vk_src_layout, - .newLayout = vk_dst_layout, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = to_vk(image), - .subresourceRange = vk_subresource_range + const auto barriers = into_array({ + VkImageMemoryBarrier { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = src_access->second.first, + .dstAccessMask = dst_access->second.first, + .oldLayout = vk_src_layout, + .newLayout = vk_dst_layout, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = vk::to_vk(image), + .subresourceRange = vk_subresource_range + + }, + }); - }, - }; + vk::call(device_table.vkCmdPipelineBarrier, + *this, + src_stage, + dst_stage, + 0, + 0, + nullptr, + 0, + nullptr, + stdr::size(barriers), + stdr::data(barriers)); + return *this; + } - vk_call(m_vk_device_table->vkCmdPipelineBarrier, - m_vk_handle, - src_stage, - dst_stage, - 0, - 0, - nullptr, - 0, - nullptr, - stdr::size(barriers), - stdr::data(barriers)); - return *this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto CommandBuffer::pipeline_barrier(PipelineStageFlag src_mask, - PipelineStageFlag dst_mask, - DependencyFlag dependency, - std::span memory_barriers, - std::span buffer_memory_barriers, - std::span image_memory_barriers) noexcept -> CommandBuffer& { - const auto vk_memory_barriers = memory_barriers - | stdv::transform([](auto&& barrier) noexcept -> decltype(auto) { - return VkMemoryBarrier { - .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER, - .pNext = nullptr, - .srcAccessMask = to_vk(barrier.src), - .dstAccessMask = to_vk(barrier.dst), - }; - }) - | stdr::to(); - - const auto vk_buffer_memory_barriers = buffer_memory_barriers - | stdv::transform([](auto&& barrier) noexcept -> decltype(auto) { - return VkBufferMemoryBarrier { - .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, - .pNext = nullptr, - .srcAccessMask = to_vk(barrier.src), - .dstAccessMask = to_vk(barrier.dst), - .srcQueueFamilyIndex = barrier.src_queue_family_index, - .dstQueueFamilyIndex = barrier.dst_queue_family_index, - .buffer = to_vk(barrier.buffer), - .offset = barrier.offset, - .size = barrier.size - }; - }) - | stdr::to(); - - const auto vk_image_memory_barriers = image_memory_barriers - | stdv::transform([](auto&& barrier) noexcept -> decltype(auto) { - const auto vk_subresource_range = VkImageSubresourceRange { - .aspectMask = to_vk(barrier.range.aspect_mask), - .baseMipLevel = barrier.range.base_mip_level, - .levelCount = barrier.range.level_count, - .baseArrayLayer = barrier.range.base_array_layer, - .layerCount = barrier.range.layer_count - }; - - return VkImageMemoryBarrier { - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, - .pNext = nullptr, - .srcAccessMask = to_vk(barrier.src), - .dstAccessMask = to_vk(barrier.dst), - .oldLayout = to_vk(barrier.old_layout), - .newLayout = to_vk(barrier.new_layout), - .srcQueueFamilyIndex = barrier.src_queue_family_index, - .dstQueueFamilyIndex = barrier.dst_queue_family_index, - .image = to_vk(barrier.image), - .subresourceRange = vk_subresource_range - }; - }) - | stdr::to(); - - vk_call(m_vk_device_table->vkCmdPipelineBarrier, - m_vk_handle, - to_vk(src_mask), - to_vk(dst_mask), - to_vk(dependency), - stdr::size(vk_memory_barriers), - stdr::data(vk_memory_barriers), - stdr::size(vk_buffer_memory_barriers), - stdr::data(vk_buffer_memory_barriers), - stdr::size(vk_image_memory_barriers), - stdr::data(vk_image_memory_barriers)); - return *this; - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto CommandBuffer::push_constants(const PipelineLayout& pipeline_layout, - ShaderStageFlag stage, - std::span data, - u32 offset) noexcept -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); + ///////////////////////////////////// + ///////////////////////////////////// + template + auto CommandBufferInterface::pipeline_barrier(PipelineStageFlag src_mask, + PipelineStageFlag dst_mask, + DependencyFlag dependency, + array_view memory_barriers, + array_view buffer_memory_barriers, + array_view image_memory_barriers) const noexcept + -> const CommandBufferInterface& { + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + const auto vk_memory_barriers = transform(memory_barriers, [](const auto& barrier) static noexcept -> decltype(auto) { + return VkMemoryBarrier { + .sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = vk::to_vk(barrier.src), + .dstAccessMask = vk::to_vk(barrier.dst), + }; + }); + const auto vk_buffer_memory_barriers = transform(buffer_memory_barriers, + [](const auto& barrier) static noexcept -> decltype(auto) { + return VkBufferMemoryBarrier { + .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = vk::to_vk(barrier.src), + .dstAccessMask = vk::to_vk(barrier.dst), + .srcQueueFamilyIndex = barrier.src_queue_family_index, + .dstQueueFamilyIndex = barrier.dst_queue_family_index, + .buffer = vk::to_vk(barrier.buffer), + .offset = barrier.offset, + .size = barrier.size + }; + }); + const auto + vk_image_memory_barriers = transform(image_memory_barriers, [](const auto& barrier) static noexcept -> decltype(auto) { + const auto vk_subresource_range = VkImageSubresourceRange { + .aspectMask = vk::to_vk(barrier.range.aspect_mask), + .baseMipLevel = barrier.range.base_mip_level, + .levelCount = barrier.range.level_count, + .baseArrayLayer = barrier.range.base_array_layer, + .layerCount = barrier.range.layer_count + }; + + return VkImageMemoryBarrier { + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, + .pNext = nullptr, + .srcAccessMask = vk::to_vk(barrier.src), + .dstAccessMask = vk::to_vk(barrier.dst), + .oldLayout = vk::to_vk(barrier.old_layout), + .newLayout = vk::to_vk(barrier.new_layout), + .srcQueueFamilyIndex = barrier.src_queue_family_index, + .dstQueueFamilyIndex = barrier.dst_queue_family_index, + .image = vk::to_vk(barrier.image), + .subresourceRange = vk_subresource_range + }; + }); + + vk::call(device_table.vkCmdPipelineBarrier, + *this, + vk::to_vk(src_mask), + vk::to_vk(dst_mask), + vk::to_vk(dependency), + stdr::size(vk_memory_barriers), + stdr::data(vk_memory_barriers), + stdr::size(vk_buffer_memory_barriers), + stdr::data(vk_buffer_memory_barriers), + stdr::size(vk_image_memory_barriers), + stdr::data(vk_image_memory_barriers)); + return *this; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto CommandBufferInterface::push_constants(view::PipelineLayout pipeline_layout, + ShaderStageFlag stage, + byte_view<> data, + u32 offset) const noexcept -> const CommandBufferInterface& { EXPECTS(not std::empty(data)); - vk_call(m_vk_device_table->vkCmdPushConstants, - m_vk_handle, - to_vk(pipeline_layout), - to_vk(stage), - offset, - stdr::size(data), - stdr::data(data)); + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + vk::call(device_table.vkCmdPushConstants, + *this, + vk::to_vk(pipeline_layout), + vk::to_vk(stage), + offset, + stdr::size(data), + stdr::data(data)); return *this; } ///////////////////////////////////// ///////////////////////////////////// - auto CommandBuffer::execute_sub_command_buffers(std::span> commandbuffers) noexcept - -> CommandBuffer& { - EXPECTS(m_state == State::RECORDING); + template + auto CommandBufferInterface::execute_sub_command_buffers(array_view commandbuffers) + const noexcept -> const CommandBufferInterface& { + const auto state = this->state(); + EXPECTS(state == CommandBuffer::State::RECORDING); - constexpr auto EXPECTS_secondary = [](auto&& cmb) noexcept -> decltype(auto) { + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + const auto expects_secondary = [](auto&& cmb) static noexcept -> decltype(auto) { EXPECTS(cmb.level() == CommandBufferLevel::SECONDARY); return cmb; }; - const auto vk_command_buffers = commandbuffers - | stdv::transform(core::monadic::unref()) - | stdv::transform(core::monadic::map(EXPECTS_secondary, monadic::to_vk())) - | stdr::to(); - - vk_call(m_vk_device_table->vkCmdExecuteCommands, - m_vk_handle, - stdr::size(vk_command_buffers), - stdr::data(vk_command_buffers)); + const auto vk_command_buffers = transform(commandbuffers, cmonadic::map(expects_secondary, vk::monadic::to_vk())); + vk::call(device_table.vkCmdExecuteCommands, *this, stdr::size(vk_command_buffers), stdr::data(vk_command_buffers)); return *this; } + + template class CommandBufferInterface; + template class CommandBufferInterface; + + ///////////////////////////////////// + ///////////////////////////////////// + auto CommandBufferImplementation::do_init(PrivateTag, + CommandBufferLevel level, + VkCommandBuffer&& handle, + CommandBufferDeleter&& deleter) noexcept -> void { + m_state = core::allocate_unsafe(State::INITIAL); + + m_level = level; + + m_vk_handle = std::move(handle); + m_deleter = std::move(deleter); + } } // namespace stormkit::gpu diff --git a/src/gpu/execution/command_pool.cpp b/src/gpu/execution/command_pool.cpp index c7cf87061..67e512485 100644 --- a/src/gpu/execution/command_pool.cpp +++ b/src/gpu/execution/command_pool.cpp @@ -4,6 +4,8 @@ module; +#include + #include module stormkit.gpu.execution; @@ -22,106 +24,57 @@ namespace stdv = std::views; namespace stormkit::gpu { ///////////////////////////////////// ///////////////////////////////////// - auto CommandPool::create_command_buffers(usize count, CommandBufferLevel level) const noexcept - -> Expected> { - return create_vk_command_buffers(count, level) - .transform([this, &level](auto&& command_buffers) noexcept { - return command_buffers - | stdv::as_rvalue - | stdv::transform([this, &level](VkCommandBuffer&& cmb) noexcept -> decltype(auto) { - return CommandBuffer::create(m_vk_device, - m_vk_handle, - m_vk_device_table, - level, - std::move(cmb), - CommandPool::delete_vk_command_buffers); - }) - | stdr::to(); - }) - .transform_error(monadic::from_vk()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto CommandPool::allocate_command_buffers(usize count, CommandBufferLevel level) const noexcept - -> Expected>> { - return create_vk_command_buffers(count, level) - .transform([this, &level](auto&& command_buffers) noexcept { - return command_buffers - | stdv::as_rvalue - | stdv::transform([this, &level](VkCommandBuffer&& cmb) noexcept -> decltype(auto) { - return CommandBuffer::allocate(m_vk_device, - m_vk_handle, - m_vk_device_table, - level, - std::move(cmb), - CommandPool::delete_vk_command_buffers); - }) - | stdr::to(); - }) - .transform_error(monadic::from_vk()); - } + template + auto CommandPoolInterface::create_vk_command_buffers(usize count, CommandBufferLevel level) const noexcept + -> Expected> { + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); - ///////////////////////////////////// - ///////////////////////////////////// - auto CommandPool::create_vk_command_buffers(usize count, CommandBufferLevel level) const noexcept - -> VulkanExpected> { - // auto out = std::vector {}; - // const auto reuse_count = stdr::empty(m_reusable_command_buffers) - // ? 0 - // : math::abs(stdr::size(m_reusable_command_buffers) - count); - // auto create_count = count - reuse_count; - - { - // auto lock = std::unique_lock { m_reuse_mutex }; - // auto erase_end = std::ranges::end(m_reusable_command_buffers); - // auto erase_begin = std::ranges::end(m_reusable_command_buffers) - reuse_count; - // - // std::ranges::for_each(m_reusable_command_buffers | std::views::reverse | - // std::views::take(reuse_count), - // [&out](VkCommandBuffer&& cmb) { - // out.emplace_back(std::move(cmb)); - // }); - // - // m_reusable_command_buffers.erase(erase_begin, erase_end); - } - // out.reserve(count); - - // if (create_count > 0) { const auto allocate_info = VkCommandBufferAllocateInfo { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, .pNext = nullptr, - .commandPool = m_vk_handle, - .level = to_vk(level), + .commandPool = *this, + .level = vk::to_vk(level), .commandBufferCount = as(count) }; - return vk_allocate(count, m_vk_device_table->vkAllocateCommandBuffers, m_vk_device, &allocate_info); + return vk::allocate_checked(count, device_table.vkAllocateCommandBuffers, device, &allocate_info); } ///////////////////////////////////// ///////////////////////////////////// - auto CommandPool::delete_vk_command_buffers(VkDevice device, - VkCommandPool command_pool, - const VolkDeviceTable& device_table, - VkCommandBuffer command_buffer) noexcept -> void { - vk_call(device_table.vkFreeCommandBuffers, device, command_pool, 1, &command_buffer); - // auto lock = std::unique_lock { m_reuse_mutex }; - // m_reusable_command_buffers.emplace_back(std::move(cmb)); + template + auto CommandPoolInterface::delete_vk_command_buffers(view::Device device, + view::CommandPool pool, + VkCommandBuffer cmb) noexcept -> void { + const auto& device_table = device.device_table(); + vk::call(device_table.vkFreeCommandBuffers, device, pool, 1, &cmb); } + template class CommandPoolInterface; + template class CommandPoolInterface; + ///////////////////////////////////// ///////////////////////////////////// - auto CommandPool::do_init() noexcept -> Expected { + auto CommandPoolImplementation::do_init(PrivateTag, const CreateInfo& create_info_) noexcept -> Expected { + const auto& device = owner(); + const auto& device_table = device.device_table(); + + const auto flags = [&create_info_] noexcept { + auto out = VkCommandPoolCreateFlags {}; + if (create_info_.reset) out |= VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + if (create_info_.transient) out |= VK_COMMAND_POOL_CREATE_TRANSIENT_BIT; + return out; + }(); + const auto create_info = VkCommandPoolCreateInfo { .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, .pNext = nullptr, - .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT | VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, - .queueFamilyIndex = 0, + .flags = flags, + .queueFamilyIndex = create_info_.queue.entry().id, }; - return vk_call(m_vk_device_table->vkCreateCommandPool, m_vk_device, &create_info, nullptr) - .transform(core::monadic::set(m_vk_handle)) - .transform_error(monadic::from_vk()); + m_vk_handle = Try(vk::call_checked(device_table.vkCreateCommandPool, device, &create_info, nullptr)); + Return {}; } } // namespace stormkit::gpu diff --git a/src/gpu/execution/descriptor_pool.cpp b/src/gpu/execution/descriptor_pool.cpp new file mode 100644 index 000000000..8d349053d --- /dev/null +++ b/src/gpu/execution/descriptor_pool.cpp @@ -0,0 +1,85 @@ + +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +#include + +module stormkit.gpu.execution; + +import std; + +import stormkit.core; + +import stormkit.gpu.core; + +namespace stdr = std::ranges; +namespace stdv = std::views; + +using namespace std::literals; + +namespace stormkit::gpu { + ///////////////////////////////////// + ///////////////////////////////////// + template + auto DescriptorPoolInterface::create_vk_descriptor_sets(usize count, view::DescriptorSetLayout&& layout) const noexcept + -> Expected> { + const auto vk_layout = vk::to_vk(layout); + const auto allocate_info = VkDescriptorSetAllocateInfo { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .pNext = nullptr, + .descriptorPool = *this, + .descriptorSetCount = as(count), + .pSetLayouts = &vk_layout, + }; + + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + return vk::allocate_checked(count, device_table.vkAllocateDescriptorSets, device, &allocate_info); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto DescriptorPoolInterface::delete_vk_descriptor_set(view::Device device, + view::DescriptorPool pool, + VkDescriptorSet set) noexcept -> void { + const auto& device_table = device.device_table(); + TryAssert(vk::call_checked(device_table.vkFreeDescriptorSets, device, pool, 1, &set), "Failed to free a descriptor set"); + } + + template class DescriptorPoolInterface; + template class DescriptorPoolInterface; + + ///////////////////////////////////// + ///////////////////////////////////// + auto DescriptorPoolImplementation::do_init(PrivateTag, array_view&& sizes, u32 max_sets) noexcept + -> Expected { + const auto pool_sizes = transform(sizes, [](const Size& size) static noexcept { + return VkDescriptorPoolSize { + .type = vk::to_vk(size.type), + .descriptorCount = size.descriptor_count, + }; + }); + + const auto create_info = VkDescriptorPoolCreateInfo { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + .pNext = nullptr, + .flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, + .maxSets = max_sets, + .poolSizeCount = as(stdr::size(sizes)), + .pPoolSizes = stdr::data(pool_sizes), + }; + + const auto& device = owner(); + const auto& device_table = device.device_table(); + + m_vk_handle = Try(vk::call_checked(device_table.vkCreateDescriptorPool, device, &create_info, nullptr)); + Return {}; + } +} // namespace stormkit::gpu diff --git a/src/gpu/execution/descriptor_set.cpp b/src/gpu/execution/descriptor_set.cpp new file mode 100644 index 000000000..cc53bb881 --- /dev/null +++ b/src/gpu/execution/descriptor_set.cpp @@ -0,0 +1,104 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +#include + +module stormkit.gpu.execution; + +import std; + +import stormkit.core; + +import stormkit.gpu.core; + +namespace stdr = std::ranges; +namespace stdv = std::views; + +using namespace std::literals; + +namespace stormkit::gpu { + ///////////////////////////////////// + ///////////////////////////////////// + template + auto DescriptorSetInterface::update(array_view descriptors) const noexcept -> void { + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + auto&& [_, _, _writes] = [this, descriptors = std::move(descriptors)] noexcept -> decltype(auto) { + auto buffers = dyn_array {}; + auto images = dyn_array {}; + auto writes = dyn_array {}; + buffers.reserve(std::size(descriptors)); + images.reserve(std::size(descriptors)); + writes.reserve(std::size(descriptors)); + + stdr::for_each(std::move(descriptors), + core::monadic::either( + [this, &buffers, &writes](const BufferDescriptor& descriptor) noexcept -> decltype(auto) { + buffers.push_back(VkDescriptorBufferInfo { + .buffer = descriptor.buffer, + .offset = descriptor.offset, + .range = descriptor.range.value_or(VK_WHOLE_SIZE), + }); + const auto& buffer_descriptor = buffers.back(); + + writes.push_back(VkWriteDescriptorSet { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .pNext = nullptr, + .dstSet = *this, + .dstBinding = descriptor.binding, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = vk::to_vk(descriptor.type), + .pImageInfo = nullptr, + .pBufferInfo = &buffer_descriptor, + .pTexelBufferView = nullptr, + }); + }, + [this, &images, &writes](const ImageDescriptor& descriptor) noexcept -> decltype(auto) { + images.push_back(VkDescriptorImageInfo { + .sampler = descriptor.sampler, + .imageView = descriptor.image_view, + .imageLayout = vk::to_vk(descriptor.layout), + }); + const auto& image_descriptor = images.back(); + + writes.push_back(VkWriteDescriptorSet { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .pNext = nullptr, + .dstSet = *this, + .dstBinding = descriptor.binding, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = vk::to_vk(descriptor.type), + .pImageInfo = &image_descriptor, + .pBufferInfo = nullptr, + .pTexelBufferView = nullptr, + }); + })); + + return std::tuple { std::move(buffers), std::move(images), std::move(writes) }; + }(); + + vk::call(device_table.vkUpdateDescriptorSets, device, stdr::size(_writes), stdr::data(_writes), 0, nullptr); + } + + template class DescriptorSetInterface; + template class DescriptorSetInterface; + + ///////////////////////////////////// + ///////////////////////////////////// + auto DescriptorSetImplementation::do_init(PrivateTag, + VkDescriptorSet&& descriptor_set, + DescriptorSetDeleter&& deleter) noexcept -> Expected { + m_vk_handle = std::move(descriptor_set); + m_deleter = std::move(deleter); + + return {}; + } +} // namespace stormkit::gpu diff --git a/src/gpu/execution/descriptor_set_layout.cpp b/src/gpu/execution/descriptor_set_layout.cpp new file mode 100644 index 000000000..099e430ca --- /dev/null +++ b/src/gpu/execution/descriptor_set_layout.cpp @@ -0,0 +1,58 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +#include + +module stormkit.gpu.execution; + +import std; + +import stormkit.core; + +import stormkit.gpu.core; + +namespace stdr = std::ranges; +namespace stdv = std::views; + +using namespace std::literals; + +namespace stormkit::gpu { + template class DescriptorSetLayoutInterface; + template class DescriptorSetLayoutInterface; + + ///////////////////////////////////// + ///////////////////////////////////// + auto DescriptorSetLayoutImplementation::do_init(PrivateTag, dyn_array&& bindings) noexcept + -> Expected { + m_bindings = std::move(bindings); + const auto vk_bindings = transform(m_bindings, [](const DescriptorSetLayoutBinding& binding) static noexcept { + return VkDescriptorSetLayoutBinding { + .binding = binding.binding, + .descriptorType = vk::to_vk(binding.type), + .descriptorCount = as(binding.descriptor_count), + .stageFlags = vk::to_vk(binding.stages), + .pImmutableSamplers = nullptr, + }; + }); + + const auto create_info = VkDescriptorSetLayoutCreateInfo { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .bindingCount = as(stdr::size(vk_bindings)), + .pBindings = stdr::data(vk_bindings) + }; + + const auto& device = owner(); + const auto& device_table = device.device_table(); + m_vk_handle = Try(vk::call_checked< + VkDescriptorSetLayout>(device_table.vkCreateDescriptorSetLayout, device, &create_info, nullptr)); + + Return {}; + } +} // namespace stormkit::gpu diff --git a/src/gpu/execution/frame_buffer.cpp b/src/gpu/execution/frame_buffer.cpp new file mode 100644 index 000000000..7c232d146 --- /dev/null +++ b/src/gpu/execution/frame_buffer.cpp @@ -0,0 +1,56 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +#include + +module stormkit.gpu.execution; + +import std; + +import stormkit.core; + +import stormkit.gpu.core; + +namespace stdr = std::ranges; +namespace stdv = std::views; + +using namespace std::literals; + +namespace stormkit::gpu { + template class FrameBufferInterface; + template class FrameBufferInterface; + + ///////////////////////////////////// + ///////////////////////////////////// + auto FrameBufferImplementation::do_init(PrivateTag, + view::RenderPass&& render_pass, + const math::uextent2& extent, + dyn_array&& attachments) noexcept -> Expected { + m_extent = extent; + m_attachments = std::move(attachments); + const auto vk_attachments = transform(m_attachments, vk::monadic::to_vk()); + + const auto create_info = VkFramebufferCreateInfo { + .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .renderPass = render_pass, + .attachmentCount = as(std::ranges::size(vk_attachments)), + .pAttachments = std::ranges::data(vk_attachments), + .width = m_extent.width, + .height = m_extent.height, + .layers = 1, + }; + + const auto& device = owner(); + const auto& device_table = device.device_table(); + + m_vk_handle = Try(vk::call_checked(device_table.vkCreateFramebuffer, device, &create_info, nullptr)); + Return {}; + } +} // namespace stormkit::gpu diff --git a/src/gpu/execution/pipeline.cpp b/src/gpu/execution/pipeline.cpp index a5d0b675b..c1f6056f1 100644 --- a/src/gpu/execution/pipeline.cpp +++ b/src/gpu/execution/pipeline.cpp @@ -4,6 +4,8 @@ module; +#include + #include module stormkit.gpu.execution; @@ -17,167 +19,299 @@ import stormkit.gpu.core; namespace stdr = std::ranges; namespace stdv = std::views; +namespace cmonadic = stormkit::core::monadic; + +using namespace std::literals; + namespace stormkit::gpu { + namespace { + struct PipelineData { + dyn_array binding_descriptions; + dyn_array input_attribute_descriptions; + VkPipelineVertexInputStateCreateInfo vertex_input_info; + VkPipelineInputAssemblyStateCreateInfo input_assembly; + dyn_array viewports; + dyn_array scissors; + VkPipelineViewportStateCreateInfo viewport_state; + VkPipelineRasterizationStateCreateInfo rasterizer; + VkPipelineMultisampleStateCreateInfo multisample; + dyn_array blend_attachments; + VkPipelineColorBlendStateCreateInfo color_blending; + dyn_array states; + VkPipelineDynamicStateCreateInfo dynamic_state; + dyn_array shaders; + VkPipelineDepthStencilStateCreateInfo depth_stencil; + }; + + auto do_init(const RasterPipelineState& state) noexcept -> PipelineData { + auto out = PipelineData {}; + out.binding_descriptions = transform(state.vertex_input_state.binding_descriptions, + [](const auto& binding_description) static noexcept { + return VkVertexInputBindingDescription { + .binding = binding_description.binding, + .stride = binding_description.stride, + .inputRate = vk::to_vk(binding_description.input_rate) + + }; + }); + + out.input_attribute_descriptions = transform(state.vertex_input_state.input_attribute_descriptions, + [](auto&& input_attribute_description) static noexcept { + return VkVertexInputAttributeDescription { + .location = input_attribute_description.location, + .binding = input_attribute_description.binding, + .format = vk::to_vk< + VkFormat>(input_attribute_description.format), + .offset = input_attribute_description.offset + }; + }); + out.vertex_input_info = VkPipelineVertexInputStateCreateInfo { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .vertexBindingDescriptionCount = as(stdr::size(out.binding_descriptions)), + .pVertexBindingDescriptions = std::data(out.binding_descriptions), + .vertexAttributeDescriptionCount = as(stdr::size(out.input_attribute_descriptions)), + .pVertexAttributeDescriptions = stdr::data(out.input_attribute_descriptions), + }; + + out.input_assembly = VkPipelineInputAssemblyStateCreateInfo { + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .topology = vk::to_vk(state.input_assembly_state.topology), + .primitiveRestartEnable = state.input_assembly_state.primitive_restart_enable + }; + + out.viewports = transform(state.viewport_state.viewports, vk::monadic::to_vk()); + + out.scissors = transform(state.viewport_state.scissors, vk::monadic::to_vk()); + + out.viewport_state = VkPipelineViewportStateCreateInfo { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .viewportCount = as(stdr::size(out.viewports)), + .pViewports = stdr::data(out.viewports), + .scissorCount = as(stdr::size(out.scissors)), + .pScissors = stdr::data(out.scissors), + }; + + out.rasterizer = VkPipelineRasterizationStateCreateInfo { + .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .depthClampEnable = state.rasterization_state.depth_clamp_enable, + .rasterizerDiscardEnable = state.rasterization_state.rasterizer_discard_enable, + .polygonMode = vk::to_vk(state.rasterization_state.polygon_mode), + .cullMode = vk::to_vk(state.rasterization_state.cull_mode), + .frontFace = vk::to_vk(state.rasterization_state.front_face), + .depthBiasEnable = state.rasterization_state.depth_bias_enable, + .depthBiasConstantFactor = state.rasterization_state.depth_bias_constant_factor, + .depthBiasClamp = state.rasterization_state.depth_bias_clamp, + .depthBiasSlopeFactor = state.rasterization_state.depth_bias_slope_factor, + .lineWidth = state.rasterization_state.line_width, + }; + + out.multisample = VkPipelineMultisampleStateCreateInfo { + .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .rasterizationSamples = vk::to_vk(state.multisample_state.rasterization_samples), + .sampleShadingEnable = state.multisample_state.sample_shading_enable, + .minSampleShading = state.multisample_state.min_sample_shading, + .pSampleMask = nullptr, + .alphaToCoverageEnable = false, + .alphaToOneEnable = false, + }; + + out.blend_attachments = transform(state.color_blend_state.attachments, [](auto&& attachment) static noexcept { + return VkPipelineColorBlendAttachmentState { + .blendEnable = attachment.blend_enable, + .srcColorBlendFactor = vk::to_vk(attachment.src_color_blend_factor), + .dstColorBlendFactor = vk::to_vk(attachment.dst_color_blend_factor), + .colorBlendOp = vk::to_vk(attachment.color_blend_operation), + .srcAlphaBlendFactor = vk::to_vk(attachment.src_alpha_blend_factor), + .dstAlphaBlendFactor = vk::to_vk(attachment.dst_alpha_blend_factor), + .alphaBlendOp = vk::to_vk(attachment.alpha_blend_operation), + .colorWriteMask = vk::to_vk(attachment.color_write_mask) + }; + }); + + out.color_blending = VkPipelineColorBlendStateCreateInfo { + .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .logicOpEnable = state.color_blend_state.logic_operation_enable, + .logicOp = vk::to_vk(state.color_blend_state.logic_operation), + .attachmentCount = as(stdr::size(out.blend_attachments)), + .pAttachments = stdr::data(out.blend_attachments), + .blendConstants = { state.color_blend_state.blend_constants[0], + state.color_blend_state.blend_constants[1], + state.color_blend_state.blend_constants[2], + state.color_blend_state.blend_constants[3] }, + }; + + out.states = transform(state.dynamic_state, vk::monadic::to_vk()); + + out.dynamic_state = VkPipelineDynamicStateCreateInfo { + .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .dynamicStateCount = as(stdr::size(out.states)), + .pDynamicStates = stdr::data(out.states), + }; + + out.shaders = transform(state.shader_state, [](const auto& shader) static noexcept { + const auto name = [](const auto& shader) static noexcept { + if (shader.type() == ShaderStageFlag::VERTEX) return "vert_main"sv; + else if (shader.type() == ShaderStageFlag::FRAGMENT) + return "frag_main"sv; + else + return "main"sv; + }(shader); + + return VkPipelineShaderStageCreateInfo { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .stage = vk::to_vk(shader.type()), + .module = shader, + .pName = stdr::data(name), + .pSpecializationInfo = nullptr, + }; + }); + + out.depth_stencil = VkPipelineDepthStencilStateCreateInfo { + .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .depthTestEnable = state.depth_stencil_state.depth_test_enable, + .depthWriteEnable = state.depth_stencil_state.depth_write_enable, + .depthCompareOp = vk::to_vk(state.depth_stencil_state.depth_compare_op), + .depthBoundsTestEnable = state.depth_stencil_state.depth_bounds_test_enable, + .stencilTestEnable = false, + .front = {}, + .back = {}, + .minDepthBounds = state.depth_stencil_state.min_depth_bounds, + .maxDepthBounds = state.depth_stencil_state.max_depth_bounds + }; + + return out; + } + } // namespace + + template class PipelineInterface; + template class PipelineInterface; + ///////////////////////////////////// ///////////////////////////////////// - auto Pipeline::do_init(const PipelineLayout& layout, - const RenderPass& render_pass, - OptionalRef pipeline_cache) noexcept -> Expected { - const auto& state = as(m_state); - - const auto binding_descriptions = state.vertex_input_state.binding_descriptions - | stdv::transform([](auto&& binding_description) static noexcept { - return VkVertexInputBindingDescription { - .binding = binding_description.binding, - .stride = binding_description.stride, - .inputRate = to_vk(binding_description.input_rate) - - }; - }) - | stdr::to(); - - const auto attribute_descriptions = state.vertex_input_state.input_attribute_descriptions - | stdv::transform([](auto&& input_attribute_description) static noexcept { - return VkVertexInputAttributeDescription { - .location = input_attribute_description.location, - .binding = input_attribute_description.binding, - .format = to_vk(input_attribute_description.format), - .offset = input_attribute_description.offset - }; - }) - | stdr::to(); - - const auto vertex_input_info = VkPipelineVertexInputStateCreateInfo { - .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .vertexBindingDescriptionCount = as(stdr::size(binding_descriptions)), - .pVertexBindingDescriptions = std::data(binding_descriptions), - .vertexAttributeDescriptionCount = as(stdr::size(attribute_descriptions)), - .pVertexAttributeDescriptions = stdr::data(attribute_descriptions), - }; + auto PipelineImplementation::do_init(PrivateTag, const RasterizationCreateInfo& create_info) noexcept -> Expected { + m_type = Type::RASTER; + m_state = core::allocate_unsafe(create_info.state); - const auto input_assembly = VkPipelineInputAssemblyStateCreateInfo { - .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .topology = to_vk(state.input_assembly_state.topology), - .primitiveRestartEnable = state.input_assembly_state.primitive_restart_enable - }; + const auto& state = as(*m_state); - const auto viewports = state.viewport_state.viewports | stdv::transform(monadic::to_vk()) | stdr::to(); + const auto [binding_descriptions, + attribute_descriptions, + vertex_input_info, + input_assembly, + viewports, + scissors, + viewport_state, + rasterizer, + multisampling, + blend_attachments, + color_blending, + states, + dynamic_state, + shaders, + depth_stencil] = gpu::do_init(state); - const auto scissors = state.viewport_state.scissors | stdv::transform(monadic::to_vk()) | stdr::to(); + const auto formats = transform(create_info.rendering_info.color_attachment_formats, vk::monadic::to_vk()); - const auto viewport_state = VkPipelineViewportStateCreateInfo { - .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .viewportCount = as(stdr::size(viewports)), - .pViewports = stdr::data(viewports), - .scissorCount = as(stdr::size(scissors)), - .pScissors = stdr::data(scissors), - }; + const auto rendering_info = [&] noexcept { + auto info = VkPipelineRenderingCreateInfo { + .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, + .pNext = nullptr, + .viewMask = create_info.rendering_info.view_mask, + .colorAttachmentCount = as(stdr::size(formats)), + .pColorAttachmentFormats = stdr::data(formats), + .depthAttachmentFormat = {}, + .stencilAttachmentFormat = {} + }; - const auto rasterizer = VkPipelineRasterizationStateCreateInfo { - .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .depthClampEnable = state.rasterization_state.depth_clamp_enable, - .rasterizerDiscardEnable = state.rasterization_state.rasterizer_discard_enable, - .polygonMode = to_vk(state.rasterization_state.polygon_mode), - .cullMode = to_vk(state.rasterization_state.cull_mode), - .frontFace = to_vk(state.rasterization_state.front_face), - .depthBiasEnable = state.rasterization_state.depth_bias_enable, - .depthBiasConstantFactor = state.rasterization_state.depth_bias_constant_factor, - .depthBiasClamp = state.rasterization_state.depth_bias_clamp, - .depthBiasSlopeFactor = state.rasterization_state.depth_bias_slope_factor, - .lineWidth = state.rasterization_state.line_width, - }; + if (create_info.rendering_info.depth_attachment_format) + info.depthAttachmentFormat = vk::to_vk(*create_info.rendering_info.depth_attachment_format); - const auto multisampling = VkPipelineMultisampleStateCreateInfo { - .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .rasterizationSamples = to_vk(state.multisample_state.rasterization_samples), - .sampleShadingEnable = state.multisample_state.sample_shading_enable, - .minSampleShading = state.multisample_state.min_sample_shading, - .pSampleMask = nullptr, - .alphaToCoverageEnable = false, - .alphaToOneEnable = false, - }; + if (create_info.rendering_info.stencil_attachment_format) + info.stencilAttachmentFormat = vk::to_vk(*create_info.rendering_info.stencil_attachment_format); - const auto blend_attachments = state.color_blend_state.attachments - | stdv::transform([](auto&& attachment) static noexcept { - return VkPipelineColorBlendAttachmentState { - .blendEnable = attachment.blend_enable, - .srcColorBlendFactor = to_vk(attachment.src_color_blend_factor), - .dstColorBlendFactor = to_vk(attachment.dst_color_blend_factor), - .colorBlendOp = to_vk(attachment.color_blend_operation), - .srcAlphaBlendFactor = to_vk(attachment.src_alpha_blend_factor), - .dstAlphaBlendFactor = to_vk(attachment.dst_alpha_blend_factor), - .alphaBlendOp = to_vk(attachment.alpha_blend_operation), - .colorWriteMask = to_vk(attachment.color_write_mask) - }; - }) - | stdr::to(); - - const auto color_blending = VkPipelineColorBlendStateCreateInfo { - .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .logicOpEnable = state.color_blend_state.logic_operation_enable, - .logicOp = to_vk(state.color_blend_state.logic_operation), - .attachmentCount = as(stdr::size(blend_attachments)), - .pAttachments = stdr::data(blend_attachments), - .blendConstants = { state.color_blend_state.blend_constants[0], - state.color_blend_state.blend_constants[1], - state.color_blend_state.blend_constants[2], - state.color_blend_state.blend_constants[3] }, + return info; + }(); + + const auto vk_create_info = VkGraphicsPipelineCreateInfo { + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .pNext = &rendering_info, + .flags = 0, + .stageCount = as(stdr::size(shaders)), + .pStages = stdr::data(shaders), + .pVertexInputState = &vertex_input_info, + .pInputAssemblyState = &input_assembly, + .pTessellationState = nullptr, + .pViewportState = &viewport_state, + .pRasterizationState = &rasterizer, + .pMultisampleState = &multisampling, + .pDepthStencilState = &depth_stencil, + .pColorBlendState = &color_blending, + .pDynamicState = &dynamic_state, + .layout = vk::to_vk(create_info.layout), + .renderPass = VK_NULL_HANDLE, + .subpass = 0, + .basePipelineHandle = nullptr, + .basePipelineIndex = -1, }; - const auto states = state.dynamic_state | stdv::transform(monadic::to_vk()) | stdr::to(); + const auto vk_pipeline_cache = either(create_info.cache, vk::monadic::to_vk(), cmonadic::init(nullptr)); - const auto dynamic_state = VkPipelineDynamicStateCreateInfo { - .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .dynamicStateCount = as(stdr::size(states)), - .pDynamicStates = stdr::data(states), - }; + const auto& device = owner(); + const auto& device_table = device.device_table(); - const auto shaders = state.shader_state - | stdv::transform(core::monadic::unref()) - | stdv::transform([](auto&& shader) static noexcept { - static constexpr auto NAME = "main"; - return VkPipelineShaderStageCreateInfo { - .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .stage = to_vk(shader.type()), - .module = to_vk(shader), - .pName = NAME, - .pSpecializationInfo = nullptr, - }; - }) - | stdr::to(); - - const auto depth_stencil = VkPipelineDepthStencilStateCreateInfo { - .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .depthTestEnable = state.depth_stencil_state.depth_test_enable, - .depthWriteEnable = state.depth_stencil_state.depth_write_enable, - .depthCompareOp = to_vk(state.depth_stencil_state.depth_compare_op), - .depthBoundsTestEnable = state.depth_stencil_state.depth_bounds_test_enable, - .stencilTestEnable = false, - .front = {}, - .back = {}, - .minDepthBounds = state.depth_stencil_state.min_depth_bounds, - .maxDepthBounds = state.depth_stencil_state.max_depth_bounds - }; + m_vk_handle = Try(vk::call_checked(device_table.vkCreateGraphicsPipelines, + device, + vk_pipeline_cache, + 1, + &vk_create_info, + nullptr)); + Return {}; + } - const auto create_info = VkGraphicsPipelineCreateInfo { + ///////////////////////////////////// + ///////////////////////////////////// + auto PipelineImplementation::do_init(PrivateTag, const LegacyRasterizationCreateInfo& create_info) noexcept + -> Expected { + m_type = Type::RASTER; + m_state = core::allocate_unsafe(create_info.state); + + const auto& state = as(*m_state); + + const auto [binding_descriptions, + attribute_descriptions, + vertex_input_info, + input_assembly, + viewports, + scissors, + viewport_state, + rasterizer, + multisampling, + blend_attachments, + color_blending, + states, + dynamic_state, + shaders, + depth_stencil] = gpu::do_init(state); + + const auto vk_create_info = VkGraphicsPipelineCreateInfo { .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .pNext = nullptr, .flags = 0, @@ -192,23 +326,24 @@ namespace stormkit::gpu { .pDepthStencilState = &depth_stencil, .pColorBlendState = &color_blending, .pDynamicState = &dynamic_state, - .layout = to_vk(layout), - .renderPass = to_vk(render_pass), + .layout = vk::to_vk(create_info.layout), + .renderPass = create_info.render_pass, .subpass = 0, .basePipelineHandle = nullptr, .basePipelineIndex = -1, }; - using namespace core::monadic; - const auto vk_pipeline_cache = core::either(pipeline_cache, monadic::to_vk(), init(nullptr)); - - return vk_call(m_vk_device_table->vkCreateGraphicsPipelines, - m_vk_device, - vk_pipeline_cache, - 1, - &create_info, - nullptr) - .transform(set(m_vk_handle)) - .transform_error(monadic::from_vk()); + const auto vk_pipeline_cache = either(create_info.cache, vk::monadic::to_vk(), cmonadic::init(nullptr)); + + const auto& device = owner(); + const auto& device_table = device.device_table(); + + m_vk_handle = Try(vk::call_checked(device_table.vkCreateGraphicsPipelines, + device, + vk_pipeline_cache, + 1, + &vk_create_info, + nullptr)); + Return {}; } } // namespace stormkit::gpu diff --git a/src/gpu/execution/pipeline_cache.cpp b/src/gpu/execution/pipeline_cache.cpp index df2133b2d..dad7e4707 100644 --- a/src/gpu/execution/pipeline_cache.cpp +++ b/src/gpu/execution/pipeline_cache.cpp @@ -6,8 +6,6 @@ module; #include -#include - #include module stormkit.gpu.execution; @@ -19,33 +17,42 @@ import stormkit.log; import stormkit.gpu.core; -namespace stdr = std::ranges; +namespace stdr = std::ranges; +namespace stdfs = std::filesystem; -LOGGER("stormkit.gpu") +using namespace stormkit::literals; namespace stormkit::gpu { - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline auto sys_to_load_error(SystemError error) noexcept -> PipelineCache::LoadSaveError { - return PipelineCache::LoadSaveError { { error } }; - } + namespace { + ///////////////////////////////////// + ///////////////////////////////////// + auto sys_to_load_error(SystemError error) noexcept -> LoadSaveError { + return LoadSaveError { { error } }; + } - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline auto result_to_load_error(Result error) noexcept -> PipelineCache::LoadSaveError { - return PipelineCache::LoadSaveError { { error } }; - } + ///////////////////////////////////// + ///////////////////////////////////// + auto result_to_load_error(Result error) noexcept -> LoadSaveError { + return LoadSaveError { { error } }; + } + } // namespace + + template class PipelineCacheInterface; + template class PipelineCacheInterface; ///////////////////////////////////// ///////////////////////////////////// - PipelineCache::~PipelineCache() noexcept = default; + auto PipelineCacheImplementation::do_init(PrivateTag, stdfs::path&& path) noexcept -> LoadSaveExpected { + m_path = std::move(path); + Return read_pipeline_cache(); + } ///////////////////////////////////// ///////////////////////////////////// - auto PipelineCache::create_new_pipeline_cache(const Device& device) noexcept -> LoadSaveExpected { - const auto physical_device_infos = device.physical_device().info(); + auto PipelineCacheImplementation::create_new_pipeline_cache() noexcept -> LoadSaveExpected { + const auto& device = owner(); + const auto& device_table = device.device_table(); + const auto& physical_device_infos = device.physical_device().info(); m_serialized.guard.magic = MAGIC; m_serialized.guard.data_size = 0u; @@ -65,61 +72,38 @@ namespace stormkit::gpu { .pInitialData = nullptr, }; - m_vk_handle = Try(vk_call(m_vk_device_table->vkCreatePipelineCache, m_vk_device, &create_info, nullptr) - .transform_error(monadic::from_vk()) - .transform_error(result_to_load_error)); + m_vk_handle = TryTransformError(vk::call_checked< + VkPipelineCache>(device_table.vkCreatePipelineCache, device, &create_info, nullptr), + result_to_load_error); - Ret({}); + Return {}; } ///////////////////////////////////// ///////////////////////////////////// - auto PipelineCache::read_pipeline_cache(const Device& device) noexcept -> LoadSaveExpected { - if (not std::filesystem::exists(m_path)) Ret(create_new_pipeline_cache(device)); - - const auto physical_device_infos = device.physical_device().info(); - - auto file = Try(io::File::open(m_path, io::Access::READ).transform_error(sys_to_load_error)); - Try(file.read_to(as_bytes(m_serialized.guard)).transform_error(sys_to_load_error)); - Try(file.read_to(as_bytes(m_serialized.infos)).transform_error(sys_to_load_error)); - Try(file.read_to(as_bytes(m_serialized.uuid.value)).transform_error(sys_to_load_error)); - - if (m_serialized.guard.magic != MAGIC) { - elog("Invalid pipeline cache magic number, have {}, expected: {}", m_serialized.guard.magic, MAGIC); - - Ret(create_new_pipeline_cache(device)); - } - - if (m_serialized.infos.version != VERSION) { - elog("Mismatch pipeline cache version, have {}, expected: {}", m_serialized.infos.version, VERSION); - - Ret(create_new_pipeline_cache(device)); - } - - if (m_serialized.infos.vendor_id != physical_device_infos.vendor_id) { - elog("Mismatch pipeline cache vendor id, have {:#06x}, expected: {:#06x}", - m_serialized.infos.vendor_id, - physical_device_infos.vendor_id); - - Ret(create_new_pipeline_cache(device)); - } - - if (m_serialized.infos.device_id != physical_device_infos.device_id) { - elog("Mismatch pipeline cache device id, have {:#06x}, expected: {:#06x}", - m_serialized.infos.device_id, - physical_device_infos.device_id); - - Ret(create_new_pipeline_cache(device)); - } - - if (not stdr::equal(m_serialized.uuid.value, physical_device_infos.pipeline_cache_uuid)) { - Ret(create_new_pipeline_cache(device)); - } - - auto data = std::vector {}; + auto PipelineCacheImplementation::read_pipeline_cache() noexcept -> LoadSaveExpected { + if (not stdfs::exists(m_path)) Return create_new_pipeline_cache(); + + const auto& device = owner(); + const auto& device_table = device.device_table(); + const auto& physical_device_infos = device.physical_device().info(); + + auto file = TryTransformError(io::File::open(m_path, io::Access::READ), sys_to_load_error); + TryTransformError(file.read_to(as_bytes_mut(m_serialized.guard)), sys_to_load_error); + TryTransformError(file.read_to(as_bytes_mut(m_serialized.infos)), sys_to_load_error); + TryTransformError(file.read_to(as_bytes_mut(m_serialized.uuid.value)), sys_to_load_error); + + if (m_serialized.guard.magic != MAGIC) Return create_new_pipeline_cache(); + if (m_serialized.infos.version != VERSION) Return create_new_pipeline_cache(); + if (m_serialized.infos.vendor_id != physical_device_infos.vendor_id) Return create_new_pipeline_cache(); + if (m_serialized.infos.device_id != physical_device_infos.device_id) Return create_new_pipeline_cache(); + if (not stdr::equal(m_serialized.uuid.value, physical_device_infos.pipeline_cache_uuid)) + Return create_new_pipeline_cache(); + + auto data = byte_dyn_array {}; data.resize(m_serialized.guard.data_size); - Try(io::read_to(m_path, data).transform_error(sys_to_load_error)); + TryTransformError(io::read_to(m_path, data), sys_to_load_error); const auto create_info = VkPipelineCacheCreateInfo { .sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, @@ -129,30 +113,37 @@ namespace stormkit::gpu { .pInitialData = stdr::data(data), }; - m_vk_handle = Try(vk_call(m_vk_device_table->vkCreatePipelineCache, m_vk_device, &create_info, nullptr) - .transform_error(monadic::from_vk()) - .transform_error(result_to_load_error)); + m_vk_handle = TryTransformError(vk::call_checked< + VkPipelineCache>(device_table.vkCreatePipelineCache, device, &create_info, nullptr), + result_to_load_error); - Ret({}); + Return {}; } ///////////////////////////////////// ///////////////////////////////////// - auto PipelineCache::save_cache() noexcept -> LoadSaveExpected { - auto data = Try((vk_enumerate(m_vk_device_table->vkGetPipelineCacheData, m_vk_device, m_vk_handle) - .transform_error(monadic::from_vk()) - .transform_error(result_to_load_error))); + auto PipelineCacheImplementation::save_cache() noexcept -> LoadSaveExpected { + const auto& device = owner(); + const auto& device_table = device.device_table(); + + auto size = 0_usize; + TryTransformError(vk::call_checked(device_table.vkGetPipelineCacheData, device, m_vk_handle, &size, nullptr), + result_to_load_error); + auto data = byte_dyn_array {}; + data.resize(size, 0_b); + TryTransformError(vk::call_checked(device_table.vkGetPipelineCacheData, device, m_vk_handle, &size, stdr::data(data)), + result_to_load_error); + m_serialized.guard.data_size = stdr::size(data); m_serialized.guard.data_hash = 0u; hash_combine(m_serialized.guard.data_hash, data); - auto file = Try(io::File::open(m_path, io::Access::WRITE).transform_error(sys_to_load_error)); - - Try(file.write(as_bytes(m_serialized.infos)).transform_error(sys_to_load_error)); - Try(file.write(as_bytes(m_serialized.uuid.value)).transform_error(sys_to_load_error)); - Try(file.write(as_bytes(data)).transform_error(sys_to_load_error)); + auto file = TryTransformError(io::File::open(m_path, io::Access::WRITE), sys_to_load_error); + TryTransformError(file.write(as_bytes(m_serialized.infos)), sys_to_load_error); + TryTransformError(file.write(as_bytes(m_serialized.uuid.value)), sys_to_load_error); + TryTransformError(file.write(as_bytes(data)), sys_to_load_error); - Ret({}); + Return {}; } } // namespace stormkit::gpu diff --git a/src/gpu/execution/pipeline_layout.cpp b/src/gpu/execution/pipeline_layout.cpp new file mode 100644 index 000000000..d7fba278d --- /dev/null +++ b/src/gpu/execution/pipeline_layout.cpp @@ -0,0 +1,59 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +#include + +module stormkit.gpu.execution; + +import std; + +import stormkit.core; + +import stormkit.gpu.core; + +namespace stdr = std::ranges; +namespace stdv = std::views; + +using namespace std::literals; + +namespace stormkit::gpu { + template class PipelineLayoutInterface; + template class PipelineLayoutInterface; + + ///////////////////////////////////// + ///////////////////////////////////// + auto PipelineLayoutImplementation::do_init(PrivateTag, const RasterPipelineLayout& layout) noexcept -> Expected { + m_layout = core::allocate_unsafe(layout); + + const auto set_layouts = transform(m_layout->descriptor_set_layouts, vk::monadic::to_vk()); + + const auto push_constant_ranges = transform(m_layout->push_constant_ranges, [](const auto& push_constant_range) noexcept { + return VkPushConstantRange { + .stageFlags = vk::to_vk(push_constant_range.stages), + .offset = push_constant_range.offset, + .size = as(push_constant_range.size), + }; + }); + + const auto create_info = VkPipelineLayoutCreateInfo { + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .setLayoutCount = as(stdr::size(set_layouts)), + .pSetLayouts = stdr::data(set_layouts), + .pushConstantRangeCount = as(stdr::size(push_constant_ranges)), + .pPushConstantRanges = stdr::data(push_constant_ranges), + }; + + const auto& device = owner(); + const auto& device_table = device.device_table(); + + m_vk_handle = Try(vk::call_checked(device_table.vkCreatePipelineLayout, device, &create_info, nullptr)); + Return {}; + } +} // namespace stormkit::gpu diff --git a/src/gpu/execution/queue.cpp b/src/gpu/execution/queue.cpp index 06984cdce..14637ec95 100644 --- a/src/gpu/execution/queue.cpp +++ b/src/gpu/execution/queue.cpp @@ -5,6 +5,7 @@ module; #include +#include #include @@ -20,18 +21,29 @@ using namespace std::literals; namespace stdr = std::ranges; namespace stdv = std::views; +namespace stdp = std::pmr; namespace stormkit::gpu { + ///////////////////////////////////// + ///////////////////////////////////// + template + auto QueueInterface::wait_idle() const noexcept -> Expected { + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + return vk::call_checked(device_table.vkQueueWaitIdle, *this); + } ///////////////////////////////////// ///////////////////////////////////// - auto Queue::submit(std::span submit_infos, OptionalRef fence) const noexcept + template + auto QueueInterface::submit(array_view submit_infos, std::optional fence) const noexcept -> Expected { struct SubmitInfoRange { - std::span wait_semaphores; - std::span wait_dst_stages; - std::span command_buffers; - std::span signal_semaphores; + array_view wait_semaphores; + array_view wait_dst_stages; + array_view command_buffers; + array_view signal_semaphores; }; const auto bytes_count = [&submit_infos] noexcept { @@ -53,39 +65,37 @@ namespace stormkit::gpu { + stdr::size(submit_infos) * sizeof(SubmitInfoRange); }(); - namespace stdp = std::pmr; - auto memory_resource = stdp::monotonic_buffer_resource { bytes_count }; - auto wait_semaphores_buf = stdp::vector> { &memory_resource }; + auto wait_semaphores_buf = pmr::dyn_array> { &memory_resource }; wait_semaphores_buf.reserve(stdr::size(submit_infos)); - auto wait_dst_stages_buf = stdp::vector> { &memory_resource }; + auto wait_dst_stages_buf = pmr::dyn_array> { &memory_resource }; wait_dst_stages_buf.reserve(stdr::size(submit_infos)); - auto command_buffers_buf = stdp::vector> { &memory_resource }; + auto command_buffers_buf = pmr::dyn_array> { &memory_resource }; command_buffers_buf.reserve(stdr::size(submit_infos)); - auto signal_semaphores_buf = stdp::vector> { &memory_resource }; + auto signal_semaphores_buf = pmr::dyn_array> { &memory_resource }; signal_semaphores_buf.reserve(stdr::size(submit_infos)); const auto submit_ranges = [&] noexcept { - auto vec = stdp::vector { &memory_resource }; + auto vec = pmr::dyn_array { &memory_resource }; vec.reserve(stdr::size(submit_infos)); for (auto&& submit_info : submit_infos) { - auto& wait_semaphores = wait_semaphores_buf - .emplace_back(std::from_range, - submit_info.wait_semaphores | stdv::transform(monadic::to_vk())); + auto& wait_semaphores = wait_semaphores_buf.emplace_back(std::from_range, + submit_info.wait_semaphores + | stdv::transform(vk::monadic::to_vk())); - auto& wait_dst_stages = wait_dst_stages_buf - .emplace_back(std::from_range, - submit_info.wait_dst_stages - | stdv::transform(monadic::to_vk())); + auto& wait_dst_stages = wait_dst_stages_buf.emplace_back(std::from_range, + submit_info.wait_dst_stages + | stdv::transform(vk::monadic::to_vk< + VkPipelineStageFlagBits>())); - auto& command_buffers = command_buffers_buf - .emplace_back(std::from_range, - submit_info.command_buffers | stdv::transform(monadic::to_vk())); + auto& command_buffers = command_buffers_buf.emplace_back(std::from_range, + submit_info.command_buffers + | stdv::transform(vk::monadic::to_vk())); - auto& signal_semaphores = signal_semaphores_buf - .emplace_back(std::from_range, - submit_info.signal_semaphores | stdv::transform(monadic::to_vk())); + auto& signal_semaphores = signal_semaphores_buf.emplace_back(std::from_range, + submit_info.signal_semaphores + | stdv::transform(vk::monadic::to_vk())); vec.emplace_back(SubmitInfoRange { .wait_semaphores = wait_semaphores, @@ -114,40 +124,44 @@ namespace stormkit::gpu { .pSignalSemaphores = stdr::data(submit_range.signal_semaphores), }; }) - | stdr::to(); + | stdr::to>(); - const auto vk_fence = core::either(fence, monadic::to_vk(), core::monadic::init(nullptr)); + const auto vk_fence = either(fence, vk::monadic::to_vk(), core::monadic::init(VK_NULL_HANDLE)); - return vk_call(m_vk_device_table->vkQueueSubmit, - m_vk_handle, - stdr::size(vk_submit_infos), - stdr::data(vk_submit_infos), - vk_fence) - .transform_error(monadic::from_vk()); + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + return vk::call_checked(device_table.vkQueueSubmit, + *this, + stdr::size(vk_submit_infos), + stdr::data(vk_submit_infos), + vk_fence); } ///////////////////////////////////// ///////////////////////////////////// - auto Queue::present(std::span> swapchains, - std::span> wait_semaphores, - std::span image_indices) const noexcept -> Expected { + template + auto QueueInterface::present(array_view swapchains, + array_view wait_semaphores, + array_view image_indices) const noexcept -> Expected { EXPECTS(stdr::size(wait_semaphores) >= 1); EXPECTS(stdr::size(image_indices) >= 1); const auto swapchains_count = stdr::size(swapchains); const auto wait_semaphores_count = stdr::size(wait_semaphores); - namespace stdp = std::pmr; - const auto bytes_count = swapchains_count * sizeof(VkSwapchainKHR) + wait_semaphores_count * sizeof(VkSemaphore); auto memory_resource = stdp::monotonic_buffer_resource { bytes_count }; - const auto vk_swapchains = stdp::vector { std::from_range, - swapchains | stdv::transform(monadic::to_vk()), - &memory_resource }; - const auto vk_semaphores = stdp::vector { std::from_range, - wait_semaphores | stdv::transform(monadic::to_vk()), - &memory_resource }; + const auto vk_swapchains = pmr::dyn_array { + std::from_range, + swapchains | stdv::transform(vk::monadic::to_vk()), + &memory_resource + }; + const auto vk_semaphores = pmr::dyn_array { + std::from_range, + wait_semaphores | stdv::transform(vk::monadic::to_vk()), + &memory_resource + }; const auto present_info = VkPresentInfoKHR { .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, @@ -160,9 +174,25 @@ namespace stormkit::gpu { .pResults = nullptr, }; - const auto possible_results = into_array_of(VK_SUCCESS, VK_ERROR_OUT_OF_DATE_KHR, VK_SUBOPTIMAL_KHR); - return vk_call(m_vk_device_table->vkQueuePresentKHR, as_view(possible_results), m_vk_handle, &present_info) - .transform(monadic::from_vk()) - .transform_error(monadic::from_vk()); + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + const auto + result = Try((vk::call_checked(device_table.vkQueuePresentKHR, + *this, + &present_info))); + Return vk::from_vk(result); + } + + template class QueueInterface; + template class QueueInterface; + + ///////////////////////////////////// + ///////////////////////////////////// + auto QueueImplementation::do_init(PrivateTag, const QueueEntry& entry) -> void { + m_entry = entry; + + const auto& device = owner(); + const auto& device_table = device.device_table(); + m_vk_handle = vk::call(device_table.vkGetDeviceQueue, device, m_entry.id, 0); } } // namespace stormkit::gpu diff --git a/src/gpu/execution/render_pass.cpp b/src/gpu/execution/render_pass.cpp index 64e69976a..9f22e7f5e 100644 --- a/src/gpu/execution/render_pass.cpp +++ b/src/gpu/execution/render_pass.cpp @@ -4,6 +4,8 @@ module; +#include + #include module stormkit.gpu.execution; @@ -23,54 +25,55 @@ namespace stormkit::gpu { return [](auto&& attachment_ref) noexcept -> VkAttachmentReference { return VkAttachmentReference { .attachment = attachment_ref.attachment_id, - .layout = to_vk(attachment_ref.layout), + .layout = vk::to_vk(attachment_ref.layout), }; }; } } // namespace monadic + template class RenderPassInterface; + template class RenderPassInterface; + ///////////////////////////////////// ///////////////////////////////////// - auto RenderPass::do_init() noexcept -> Expected { - const auto attachments = m_description.attachments - | stdv::transform([](auto&& attachment) static noexcept { - return VkAttachmentDescription { - .flags = 0, - .format = to_vk(attachment.format), - .samples = to_vk(attachment.samples), - .loadOp = to_vk(attachment.load_op), - .storeOp = to_vk(attachment.store_op), - .stencilLoadOp = to_vk(attachment.stencil_load_op), - .stencilStoreOp = to_vk(attachment.stencil_store_op), - .initialLayout = to_vk(attachment.source_layout), - .finalLayout = to_vk(attachment.destination_layout), - }; - }) - | stdr::to(); - - auto color_attachment_refs = std::vector> {}; + auto RenderPassImplementation::do_init(PrivateTag, const RenderPassDescription& description) noexcept -> Expected { + m_description = core::allocate_unsafe(description); + + const auto attachments = transform(m_description->attachments, [](auto&& attachment) static noexcept { + return VkAttachmentDescription { + .flags = 0, + .format = vk::to_vk(attachment.format), + .samples = vk::to_vk(attachment.samples), + .loadOp = vk::to_vk(attachment.load_op), + .storeOp = vk::to_vk(attachment.store_op), + .stencilLoadOp = vk::to_vk(attachment.stencil_load_op), + .stencilStoreOp = vk::to_vk(attachment.stencil_store_op), + .initialLayout = vk::to_vk(attachment.source_layout), + .finalLayout = vk::to_vk(attachment.destination_layout), + }; + }); + + auto color_attachment_refs = dyn_array> {}; auto depth_attachment_ref = std::optional {}; - auto resolve_attachment_refs = std::vector> {}; - auto subpasses = std::vector {}; - auto subpasses_deps = std::vector {}; - - color_attachment_refs.reserve(stdr::size(m_description.subpasses)); - resolve_attachment_refs.reserve(stdr::size(m_description.subpasses)); - subpasses.reserve(stdr::size(m_description.subpasses)); - subpasses_deps.reserve(stdr::size(m_description.subpasses)); - - for (const auto& subpass : m_description.subpasses) { - auto& color_attachment_ref = color_attachment_refs.emplace_back(subpass.color_attachment_refs - | stdv::transform(monadic::vk_ref()) - | stdr::to()); - auto& resolve_attachment_ref = resolve_attachment_refs.emplace_back(subpass.resolve_attachment_refs - | stdv::transform(monadic::vk_ref()) - | stdr::to()); + auto resolve_attachment_refs = dyn_array> {}; + auto subpasses = dyn_array {}; + auto subpasses_deps = dyn_array {}; + + color_attachment_refs.reserve(stdr::size(m_description->subpasses)); + resolve_attachment_refs.reserve(stdr::size(m_description->subpasses)); + subpasses.reserve(stdr::size(m_description->subpasses)); + subpasses_deps.reserve(stdr::size(m_description->subpasses)); + + for (const auto& subpass : m_description->subpasses) { + auto& color_attachment_ref = color_attachment_refs.emplace_back(transform(subpass.color_attachment_refs, + monadic::vk_ref())); + auto& resolve_attachment_ref = resolve_attachment_refs.emplace_back(transform(subpass.resolve_attachment_refs, + monadic::vk_ref())); if (subpass.depth_attachment_ref) depth_attachment_ref = monadic::vk_ref()(*subpass.depth_attachment_ref); subpasses.emplace_back(VkSubpassDescription { .flags = 0, - .pipelineBindPoint = to_vk(subpass.bind_point), + .pipelineBindPoint = vk::to_vk(subpass.bind_point), .inputAttachmentCount = 0, .pInputAttachments = nullptr, .colorAttachmentCount = as(stdr::size(color_attachment_ref)), @@ -104,9 +107,11 @@ namespace stormkit::gpu { .pDependencies = stdr::data(subpasses_deps), }; - return vk_call(m_vk_device_table->vkCreateRenderPass, m_vk_device, &create_info, nullptr) - .transform(core::monadic::set(m_vk_handle)) - .transform_error(monadic::from_vk()); + const auto& device = owner(); + const auto& device_table = device.device_table(); + + m_vk_handle = Try(vk::call_checked(device_table.vkCreateRenderPass, device, &create_info, nullptr)); + Return {}; } ///////////////////////////////////// diff --git a/src/gpu/execution/swapchain.cpp b/src/gpu/execution/swapchain.cpp index 111e792f0..34f941f8f 100644 --- a/src/gpu/execution/swapchain.cpp +++ b/src/gpu/execution/swapchain.cpp @@ -1,6 +1,7 @@ module; #include +#include #include @@ -17,7 +18,7 @@ namespace stormkit::gpu { namespace { ///////////////////////////////////// ///////////////////////////////////// - auto choose_swap_surface_format(std::span formats) noexcept -> VkSurfaceFormatKHR { + auto choose_swap_surface_format(array_view formats) noexcept -> VkSurfaceFormatKHR { for (const auto& format : formats) { if (format.format == VK_FORMAT_B8G8R8A8_UNORM && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) return format; @@ -28,7 +29,7 @@ namespace stormkit::gpu { ///////////////////////////////////// ///////////////////////////////////// - auto choose_swap_present_mode(std::span present_modes) noexcept -> VkPresentModeKHR { + auto choose_swap_present_mode(array_view present_modes) noexcept -> VkPresentModeKHR { auto present_mode_ = VK_PRESENT_MODE_FIFO_KHR; for (const auto& present_mode : present_modes) { @@ -42,16 +43,16 @@ namespace stormkit::gpu { ///////////////////////////////////// ///////////////////////////////////// - auto choose_swap_extent(const VkSurfaceCapabilitiesKHR& capabilities, const math::Extent2& extent) noexcept + auto choose_swap_extent(const VkSurfaceCapabilitiesKHR& capabilities, const math::uextent2& extent) noexcept -> VkExtent2D { static constexpr auto int_max = std::numeric_limits::max(); if (capabilities.currentExtent.width != int_max && capabilities.currentExtent.height != int_max) return capabilities.currentExtent; - auto actual_extent = to_vk(extent); + auto actual_extent = vk::to_vk(extent); actual_extent.width = std::max(capabilities.minImageExtent.width, - std::min(capabilities.maxImageExtent.width, actual_extent.width)); + std::min(capabilities.maxImageExtent.width, actual_extent.width)); actual_extent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actual_extent.height)); @@ -72,101 +73,90 @@ namespace stormkit::gpu { ///////////////////////////////////// ///////////////////////////////////// - auto SwapChain::do_init(const Device& device, - const Surface& surface, - const math::Extent2& extent, - VkSwapchainKHR old_swapchain) noexcept -> Expected { - const auto& physical_device = device.physical_device(); - - return vk_call(vkGetPhysicalDeviceSurfaceCapabilitiesKHR, - physical_device.native_handle(), - surface.native_handle()) - .and_then([&physical_device, &surface](auto&& capabilities) noexcept { - return vk_enumerate(vkGetPhysicalDeviceSurfaceFormatsKHR, - physical_device.native_handle(), - surface.native_handle()) - .transform(core::monadic::as_tuple(std::move(capabilities))); - }) - .and_then(core::monadic::unpack_tuple_to([&physical_device, &surface](auto&& capabilities, auto&& formats) noexcept { - return vk_enumerate(vkGetPhysicalDeviceSurfacePresentModesKHR, - physical_device.native_handle(), - surface.native_handle()) - .transform(core::monadic::as_tuple(std::move(capabilities), std::move(formats))); - })) - .and_then(core::monadic::unpack_tuple_to([this, &surface, &extent, &old_swapchain](auto&& capabilities, - auto&& formats, - auto&& present_modes) noexcept { - const auto format = choose_swap_surface_format(formats); - const auto present_mode = choose_swap_present_mode(present_modes); - const auto swapchain_extent = choose_swap_extent(capabilities, extent.to<2uz>()); - const auto image_count = choose_image_count(capabilities); - const auto image_sharing_mode = VK_SHARING_MODE_EXCLUSIVE; - const auto image_usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; - - m_extent = extent; - m_pixel_format = from_vk(format.format); - - const auto create_info = VkSwapchainCreateInfoKHR { - .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, - .pNext = nullptr, - .flags = 0, - .surface = surface.native_handle(), - .minImageCount = image_count, - .imageFormat = format.format, - .imageColorSpace = format.colorSpace, - .imageExtent = swapchain_extent, - .imageArrayLayers = 1, - .imageUsage = image_usage, - .imageSharingMode = image_sharing_mode, - .queueFamilyIndexCount = 0, - .pQueueFamilyIndices = nullptr, - .preTransform = capabilities.currentTransform, - .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, - .presentMode = present_mode, - .clipped = true, - .oldSwapchain = old_swapchain - }; - - ENSURES(m_vk_device_table->vkCreateSwapchainKHR != nullptr); - ENSURES(m_vk_device != nullptr); - - return vk_call(m_vk_device_table->vkCreateSwapchainKHR, m_vk_device, &create_info, nullptr); - })) - .transform(core::monadic::set(m_vk_handle)) - .and_then([this] noexcept { - return vk_enumerate(m_vk_device_table->vkGetSwapchainImagesKHR, m_vk_device, m_vk_handle); - }) - .transform([this, &device](auto&& vk_images) noexcept { - m_image_count = as(std::ranges::size(vk_images)); - m_images = vk_images - | std::views::transform([this, &device](auto&& image) noexcept { - const auto create_info = Image::CreateInfo { - .extent = { m_extent.width, m_extent.height, 1_u32 }, - .format = m_pixel_format - }; - return Image::create(device, create_info, std::move(image)); - }) - | std::ranges::to(); - }) - .transform_error(monadic::from_vk()); + template + auto SwapChainInterface::acquire_next_image(std::chrono::nanoseconds wait, + view::Semaphore image_available) const noexcept -> Expected { + const auto& device = Base::owner(); + const auto& device_table = device.device_table(); + + auto id = u32 { 0 }; + const auto result = Try((vk::call_checked( + device_table.vkAcquireNextImageKHR, + device, + *this, + wait.count(), + image_available, + nullptr, + &id))); + Return SwapChain::NextImage { .result = vk::from_vk(result), .id = id }; } + template class SwapChainInterface; + template class SwapChainInterface; + ///////////////////////////////////// ///////////////////////////////////// - auto SwapChain::acquire_next_image(std::chrono::nanoseconds wait, const Semaphore& image_available) const noexcept - -> Expected { - static constexpr auto POSSIBLE_RESULTS = std::array { VK_SUCCESS, VK_ERROR_OUT_OF_DATE_KHR, VK_SUBOPTIMAL_KHR }; - - auto id = u32 { 0 }; - return vk_call(m_vk_device_table->vkAcquireNextImageKHR, - as_view(POSSIBLE_RESULTS), - m_vk_device, - m_vk_handle, - wait.count(), - image_available.native_handle(), - nullptr, - &id) - .transform([&id](auto&& result) { return NextImage { .result = from_vk(result), .id = id }; }) - .transform_error(monadic::from_vk()); + auto SwapChainImplementation::do_init(PrivateTag, const CreateInfo& create_info) noexcept -> Expected { + const auto& device = owner(); + const auto& device_table = device.device_table(); + const auto& physical_device = device.physical_device(); + + const auto capabilities = Try(vk::call_checked(vkGetPhysicalDeviceSurfaceCapabilitiesKHR, + physical_device, + create_info.surface)); + const auto formats = Try(vk::enumerate_checked(vkGetPhysicalDeviceSurfaceFormatsKHR, + physical_device, + create_info.surface)); + const auto present_modes = Try(vk::enumerate_checked(vkGetPhysicalDeviceSurfacePresentModesKHR, + physical_device, + create_info.surface)); + + const auto format = choose_swap_surface_format(formats); + const auto present_mode = choose_swap_present_mode(present_modes); + const auto swapchain_extent = choose_swap_extent(capabilities, create_info.extent.to<2>()); + const auto image_count = choose_image_count(capabilities); + const auto image_sharing_mode = VK_SHARING_MODE_EXCLUSIVE; + const auto image_usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + + m_extent = create_info.extent; + m_pixel_format = vk::from_vk(format.format); + + const auto vk_create_info = VkSwapchainCreateInfoKHR { + .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, + .pNext = VK_NULL_HANDLE, + .flags = 0, + .surface = create_info.surface, + .minImageCount = image_count, + .imageFormat = format.format, + .imageColorSpace = format.colorSpace, + .imageExtent = swapchain_extent, + .imageArrayLayers = 1, + .imageUsage = image_usage, + .imageSharingMode = image_sharing_mode, + .queueFamilyIndexCount = 0, + .pQueueFamilyIndices = nullptr, + .preTransform = capabilities.currentTransform, + .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + .presentMode = present_mode, + .clipped = true, + .oldSwapchain = create_info.old, + }; + + ENSURES(device_table.vkCreateSwapchainKHR != nullptr); + ENSURES(device_table.vkGetSwapchainImagesKHR != nullptr); + + m_vk_handle = Try(vk::call_checked(device_table.vkCreateSwapchainKHR, device, &vk_create_info, nullptr)); + const auto vk_images = Try(vk::enumerate_checked(device_table.vkGetSwapchainImagesKHR, device, m_vk_handle)); + + m_image_count = as(stdr::size(vk_images)); + m_images = transform(vk_images, [this, &device](auto image) noexcept { + const auto create_info = Image::CreateInfo { + .extent = { m_extent.width, m_extent.height, 1_u32 }, + .format = m_pixel_format + }; + return Image::from_existing(device, create_info, image); + }); + + Return {}; } } // namespace stormkit::gpu diff --git a/src/gpu/resource/buffer.cpp b/src/gpu/resource/buffer.cpp index b090e84ab..68ef3d312 100644 --- a/src/gpu/resource/buffer.cpp +++ b/src/gpu/resource/buffer.cpp @@ -4,6 +4,9 @@ module; +#include +#include + #include module stormkit.gpu.resource; @@ -17,66 +20,140 @@ import stormkit.gpu.core; namespace stormkit::gpu { ///////////////////////////////////// ///////////////////////////////////// - auto Buffer::do_init(MemoryPropertyFlag memory_properties) noexcept -> Expected { - const auto create_info = VkBufferCreateInfo { + template + auto BufferInterface::map(ioffset offset) noexcept -> Expected { + EXPECTS(allocation() and Base::native_handle()); + EXPECTS(offset < as(size())); + + const auto& device = Base::owner(); + const auto& allocator = device.allocator(); + const auto& allocation = this->allocation(); + + auto ptr = Try(vk::call_checked(vmaMapMemory, allocator, allocation)); + + Base::m_mapped_pointer = std::bit_cast(ptr); + Base::m_mapped_pointer += offset; + return Base::m_mapped_pointer; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto BufferInterface::flush(ioffset offset, usize size) const noexcept -> Expected { + EXPECTS(allocation() and Base::native_handle()); + EXPECTS(offset <= as(this->size())); + EXPECTS(size <= this->size()); + + const auto& device = Base::owner(); + const auto& allocator = device.allocator(); + const auto& allocation = this->allocation(); + + return vk::call_checked(vmaFlushAllocation, allocator, allocation, offset, size); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto BufferInterface::unmap() noexcept -> void { + if (not mapped()) return; + + if constexpr (cmeta::SameAs) + if (is_persistently_mapped()) return; + + EXPECTS(allocation() and Base::native_handle()); + + const auto& device = Base::owner(); + const auto& allocator = device.allocator(); + const auto& allocation = this->allocation(); + + vk::call(vmaUnmapMemory, allocator, allocation); + + Base::m_mapped_pointer = nullptr; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + auto BufferInterface::upload(byte_view<> data, ioffset offset) noexcept -> Expected { + EXPECTS(stdr::size(data) <= this->size()); + + if (is_persistently_mapped()) { + stdr::copy(data, Base::m_mapped_pointer); + Return {}; + } + + auto gpu_data = Try(map(offset, stdr::size(data))); + stdr::copy(data, stdr::begin(gpu_data)); + unmap(); + + Return {}; + } + + template class BufferInterface; + template class BufferInterface; + + ///////////////////////////////////// + ///////////////////////////////////// + auto BufferImplementation::do_init(PrivateTag, const CreateInfo& _create_info) noexcept -> Expected { + m_usages = _create_info.usages; + m_size = _create_info.size; + m_memory_properties = _create_info.properties; + m_is_persistently_mapped = _create_info.persistently_mapped; + + const auto& device = owner(); + const auto& device_table = device.device_table(); + const auto create_info = VkBufferCreateInfo { .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .pNext = nullptr, .flags = 0, .size = m_size, - .usage = to_vk(m_usages), + .usage = vk::to_vk(m_usages), .sharingMode = VK_SHARING_MODE_EXCLUSIVE, .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, }; - return vk_call(m_vk_device_table->vkCreateBuffer, m_vk_device, &create_info, nullptr) - .transform(core::monadic::set(m_vk_handle)) - .and_then([this, &memory_properties] noexcept -> VulkanExpected { - const auto create_info = VmaAllocationCreateInfo { - .flags = 0, - .usage = VMA_MEMORY_USAGE_UNKNOWN, - .requiredFlags = to_vk(memory_properties), - .preferredFlags = 0, - .memoryTypeBits = 0, - .pool = nullptr, - .pUserData = nullptr, - .priority = 0 - }; - - auto out = VulkanExpected { std::in_place, nullptr }; - auto result = vmaAllocateMemoryForBuffer(m_vma_allocator, m_vk_handle, &create_info, &*out, nullptr); - if (result != VK_SUCCESS) out = std::unexpected { result }; - else { - m_vma_allocation = { [vma_allocator = m_vma_allocator](VmaAllocation handle) noexcept { - if (handle) { vmaFreeMemory(vma_allocator, handle); } - } }; - } - - return out; - }) - .transform(core::monadic::set(m_vma_allocation)) - .and_then([this] noexcept { return vk_call(vmaBindBufferMemory, m_vma_allocator, m_vma_allocation, m_vk_handle); }) - .transform_error(monadic::from_vk()) - .and_then([this] noexcept -> Expected { - if (m_is_persistently_mapped) return map(0u); - - return {}; - }) - .transform(core::monadic::discard()); - } + m_vk_handle = Try(vk::call_checked(device_table.vkCreateBuffer, device, &create_info, nullptr)); - ///////////////////////////////////// - ///////////////////////////////////// - auto Buffer::find_memory_type(u32 type_filter, - VkMemoryPropertyFlagBits properties, - const VkPhysicalDeviceMemoryProperties& mem_properties, - const VkMemoryRequirements&) noexcept -> u32 { - for (const auto i : range(mem_properties.memoryTypeCount)) { - if ((type_filter & (1 << i)) - and (check_flag_bit(static_cast(mem_properties.memoryTypes[i].propertyFlags), - properties))) - return i; + const auto vma_create_info = VmaAllocationCreateInfo { + .flags = 0, + .usage = VMA_MEMORY_USAGE_UNKNOWN, + .requiredFlags = vk::to_vk(m_memory_properties), + .preferredFlags = 0, + .memoryTypeBits = 0, + .pool = nullptr, + .pUserData = nullptr, + .priority = 0 + }; + const auto allocator = device.allocator(); + auto out = VmaAllocation { VK_NULL_HANDLE }; + Try(vk::call_checked(vmaAllocateMemoryForBuffer, allocator, m_vk_handle, &vma_create_info, &out, nullptr)); + m_vma_allocation = { [allocator](VmaAllocation handle) noexcept { + if (handle) { vmaFreeMemory(allocator, handle); } + } }; + m_vma_allocation = std::move(out); + Try(vk::call_checked(vmaBindBufferMemory, allocator, m_vma_allocation, m_vk_handle)); + + if (m_is_persistently_mapped) { + auto ptr = Try(vk::call_checked(vmaMapMemory, allocator, m_vma_allocation)); + m_mapped_pointer = std::bit_cast(ptr); } - return 0; + Return {}; } + + // ///////////////////////////////////// + // ///////////////////////////////////// + // auto BufferImplementation::find_memory_type(u32 type_filter, + // VkMemoryPropertyFlagBits properties, + // const VkPhysicalDeviceMemoryProperties& mem_properties, + // const VkMemoryRequirements&) noexcept -> u32 { + // for (const auto i : range(mem_properties.memoryTypeCount)) { + // if ((type_filter & (1 << i)) + // and (check_flag_bit(static_cast(mem_properties.memoryTypes[i].propertyFlags), + // properties))) + // return i; + // } + + // return 0; + // } } // namespace stormkit::gpu diff --git a/src/gpu/resource/image.cpp b/src/gpu/resource/image.cpp index 554026e9c..274610fe8 100644 --- a/src/gpu/resource/image.cpp +++ b/src/gpu/resource/image.cpp @@ -4,6 +4,8 @@ module; +#include + #include module stormkit.gpu.resource; @@ -80,33 +82,66 @@ namespace stormkit::gpu { // } } // namespace - auto Image::do_init(const VkImageCreateInfo& create_info, MemoryPropertyFlag memory_properties) noexcept -> Expected { - return vk_call(m_vk_device_table->vkCreateImage, m_vk_device, &create_info, nullptr) - .transform(core::monadic::set(m_vk_handle)) - .and_then([this, memory_properties] noexcept -> VulkanExpected { - const auto create_info = VmaAllocationCreateInfo { - .flags = 0, - .usage = VMA_MEMORY_USAGE_UNKNOWN, - .requiredFlags = to_vk(memory_properties), - .preferredFlags = 0, - .memoryTypeBits = 0, - .pool = nullptr, - .pUserData = nullptr, - .priority = 0 - }; - - auto out = VulkanExpected { std::in_place, nullptr }; - auto result = vmaAllocateMemoryForImage(m_vma_allocator, m_vk_handle, &create_info, &*out, nullptr); - if (result != VK_SUCCESS) out = std::unexpected { result }; - else { - m_vma_allocation = { [vma_allocator = m_vma_allocator](auto handle) noexcept { - vmaFreeMemory(vma_allocator, handle); - } }; - } - return out; - }) - .transform(core::monadic::set(m_vma_allocation)) - .and_then([this] noexcept { return vk_call(vmaBindImageMemory, m_vma_allocator, m_vma_allocation, m_vk_handle); }) - .transform_error(monadic::from_vk()); + template class ImageInterface; + template class ImageInterface; + + ///////////////////////////////////// + ///////////////////////////////////// + auto ImageImplementation::do_init(PrivateTag, const CreateInfo& _create_info) noexcept -> Expected { + m_extent = _create_info.extent; + m_format = _create_info.format; + m_layers = _create_info.layers; + m_faces = 1; + m_mip_levels = _create_info.mip_levels; + m_type = _create_info.type; + m_flags = _create_info.flags; + m_samples = _create_info.samples; + m_usages = _create_info.usages; + + if (core::check_flag_bit(m_flags, gpu::ImageCreateFlag::CUBE_COMPATIBLE)) m_faces = 6u; + const auto create_info = VkImageCreateInfo { + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .pNext = nullptr, + .flags = vk::to_vk(m_flags), + .imageType = vk::to_vk(m_type), + .format = vk::to_vk(m_format), + .extent = { m_extent.width, m_extent.height, m_extent.depth }, + .mipLevels = m_mip_levels, + .arrayLayers = m_layers * m_faces, + .samples = vk::to_vk(m_samples), + .tiling = vk::to_vk(_create_info.tiling), + .usage = vk::to_vk(m_usages), + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .queueFamilyIndexCount = 0, // TODO CHECK IF VALID VALUE + .pQueueFamilyIndices = nullptr, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + }; + + const auto& device = owner(); + + m_vk_handle = Try(vk::call_checked(device.device_table().vkCreateImage, device, &create_info, nullptr)); + + const auto vma_create_info = VmaAllocationCreateInfo { + .flags = 0, + .usage = VMA_MEMORY_USAGE_UNKNOWN, + .requiredFlags = vk::to_vk(_create_info.properties), + .preferredFlags = 0, + .memoryTypeBits = 0, + .pool = nullptr, + .pUserData = nullptr, + .priority = 0 + }; + + const auto allocator = device.allocator(); + auto out = VmaAllocation { VK_NULL_HANDLE }; + Try(vk::call_checked(vmaAllocateMemoryForImage, allocator, m_vk_handle, &vma_create_info, &out, nullptr)); + m_vma_allocation = { [allocator](VmaAllocation handle) noexcept { + if (handle != VK_NULL_HANDLE) vk::call(vmaFreeMemory, allocator, handle); + } }; + m_vma_allocation = std::move(out); + + Try(vk::call_checked(vmaBindImageMemory, allocator, m_vma_allocation, m_vk_handle)); + + Return {}; } } // namespace stormkit::gpu diff --git a/src/gpu/resource/image_view.cpp b/src/gpu/resource/image_view.cpp new file mode 100644 index 000000000..5e4dee04d --- /dev/null +++ b/src/gpu/resource/image_view.cpp @@ -0,0 +1,58 @@ + +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +#include + +module stormkit.gpu.resource; + +import std; + +import stormkit.core; + +import stormkit.gpu.core; + +namespace stormkit::gpu { + template class ImageViewInterface; + template class ImageViewInterface; + + ///////////////////////////////////// + ///////////////////////////////////// + auto ImageViewImplementation::do_init(PrivateTag, const CreateInfo& create_info) noexcept -> Expected { + m_type = create_info.type; + m_subresource_range = create_info.subresource_range; + + const auto vk_subresource_range = VkImageSubresourceRange { + .aspectMask = vk::to_vk(m_subresource_range.aspect_mask), + .baseMipLevel = m_subresource_range.base_mip_level, + .levelCount = m_subresource_range.level_count, + .baseArrayLayer = m_subresource_range.base_array_layer, + .layerCount = m_subresource_range.layer_count, + }; + + const auto vk_create_info = VkImageViewCreateInfo { + .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .image = create_info.image, + .viewType = vk::to_vk(m_type), + .format = vk::to_vk(create_info.image.format()), + .components = { .r = VK_COMPONENT_SWIZZLE_R, + .g = VK_COMPONENT_SWIZZLE_G, + .b = VK_COMPONENT_SWIZZLE_B, + .a = VK_COMPONENT_SWIZZLE_A }, + .subresourceRange = vk_subresource_range, + }; + + const auto device = owner(); + + m_vk_handle = Try(vk::call_checked< + VkImageView>(device.device_table().vkCreateImageView, device, &vk_create_info, nullptr)); + Return {}; + } +} // namespace stormkit::gpu diff --git a/src/gpu/resource/sampler.cpp b/src/gpu/resource/sampler.cpp new file mode 100644 index 000000000..1c193a5d4 --- /dev/null +++ b/src/gpu/resource/sampler.cpp @@ -0,0 +1,53 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +#include + +module stormkit.gpu.resource; + +import std; + +import stormkit.core; + +import stormkit.gpu.core; + +namespace stormkit::gpu { + template class SamplerInterface; + template class SamplerInterface; + + ///////////////////////////////////// + ///////////////////////////////////// + auto SamplerImplementation::do_init(PrivateTag, const Settings& settings) noexcept -> Expected { + m_settings = settings; + const auto create_info = VkSamplerCreateInfo { + .sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .magFilter = vk::to_vk(m_settings.mag_filter), + .minFilter = vk::to_vk(m_settings.min_filter), + .mipmapMode = vk::to_vk(m_settings.mipmap_mode), + .addressModeU = vk::to_vk(m_settings.address_mode_u), + .addressModeV = vk::to_vk(m_settings.address_mode_v), + .addressModeW = vk::to_vk(m_settings.address_mode_w), + .mipLodBias = m_settings.mip_lod_bias, + .anisotropyEnable = m_settings.enable_anisotropy, + .maxAnisotropy = m_settings.max_anisotropy, + .compareEnable = m_settings.compare_enable, + .compareOp = vk::to_vk(m_settings.compare_operation), + .minLod = m_settings.min_lod, + .maxLod = m_settings.max_lod, + .borderColor = vk::to_vk(m_settings.border_color), + .unnormalizedCoordinates = m_settings.unnormalized_coordinates + }; + const auto& device = owner(); + + m_vk_handle = Try(vk::call_checked(device.device_table().vkCreateSampler, device, &create_info, nullptr)); + Return {}; + } + +} // namespace stormkit::gpu diff --git a/src/gpu/resource/shader.cpp b/src/gpu/resource/shader.cpp index 4b049fbd7..7d4488b03 100644 --- a/src/gpu/resource/shader.cpp +++ b/src/gpu/resource/shader.cpp @@ -4,6 +4,8 @@ module; +#include + #include module stormkit.gpu.resource; @@ -16,38 +18,26 @@ import stormkit.gpu.core; ; namespace stormkit::gpu { + template class ShaderInterface; + template class ShaderInterface; + ///////////////////////////////////// ///////////////////////////////////// - auto Shader::reflect() noexcept -> void { -#ifdef STORMKIT_ENABLE_SPIRV_INTROSPECT - auto ir = std::vector {}; - ir.resize(std::size(m_source) / sizeof(SpirvID)); - std::memcpy(std::data(ir), std::data(m_source), std::size(m_source)); - - auto compiler = spirv_cross::CompilerGLSL { std::move(ir) }; - const auto add_bindings = [this, &compiler](span resources, gpu::DescriptorType type) { - for (const auto& resource : resources) { - /*const auto set = - spvc_compiler_get_decoration(compiler, resources[i].id, - SpvDecorationDescriptorSet);*/ - const auto binding = compiler.get_decoration(resource.id, spv::DecorationBinding); - // const auto name = spvc_compiler_get_name(compiler, resources[i].id); - - m_descriptor_set_layout - .addBinding({ binding, - type, - gpu::ShaderStageFlag::Vertex | gpu::ShaderStageFlag::Fragment | gpu::ShaderStageFlag::Compute, - 1 }); - } + auto ShaderImplementation::do_init(PrivateTag, dyn_array&& data, ShaderStageFlag type) -> Expected { + m_source = std::move(data); + m_type = type; + + const auto create_info = VkShaderModuleCreateInfo { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .codeSize = stdr::size(m_source) * sizeof(SpirvID), + .pCode = stdr::data(m_source) }; - auto resources = compiler.get_shader_resources(); - add_bindings(resources.uniform_buffers, DescriptorType::Uniform_Buffer); - add_bindings(resources.storage_buffers, DescriptorType::Storage_Buffer); - add_bindings(resources.sampled_images, DescriptorType::Sampled_Image); - add_bindings(resources.storage_images, DescriptorType::Storage_Image); - -#endif - // m_descriptor_set_layout.bake(); + const auto& device = owner(); + m_vk_handle = Try(vk::call_checked< + VkShaderModule>(device.device_table().vkCreateShaderModule, device, &create_info, nullptr)); + Return {}; } } // namespace stormkit::gpu diff --git a/src/image/hdr.mpp b/src/image/hdr.cppm similarity index 69% rename from src/image/hdr.mpp rename to src/image/hdr.cppm index 0fe9415a5..798a18891 100644 --- a/src/image/hdr.mpp +++ b/src/image/hdr.cppm @@ -1,55 +1,50 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -export module stormkit.image:hdr; - -import std; - -import stormkit.core; -import stormkit.image; - -export namespace stormkit::image::details { - [[nodiscard]] - auto load_hdr(std::span data) noexcept - -> std::expected; - - [[nodiscard]] - auto save_hdr(const image::Image& image, const std::filesystem::path& filepath) noexcept - -> std::expected; - - [[nodiscard]] - auto save_hdr(const image::Image& image) noexcept - -> std::expected, image::Image::Error>; -} // namespace stormkit::image::details - -namespace stormkit::image::details { - template - using Unexpected = std::unexpected; - using Error = image::Image::Error; - using Reason = image::Image::Error::Reason; - - ///////////////////////////////////// - ///////////////////////////////////// - auto load_hdr(std::span) noexcept - -> std::expected { - assert(false, "Not implemented yet !"); - return {}; - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto save_hdr(const image::Image&, const std::filesystem::path&) noexcept - -> std::expected { - assert(false, "Not implemented yet !"); - return {}; - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto save_hdr(const image::Image&) noexcept - -> std::expected, image::Image::Error> { - assert(false, "Not implemented yet !"); - return {}; - } -} // namespace stormkit::image::details +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +export module stormkit.image:hdr; + +import std; + +import stormkit.core; +import stormkit.image; + +export namespace stormkit::image::details { + [[nodiscard]] + auto load_hdr(byte_view<> data) noexcept -> std::expected; + + [[nodiscard]] + auto save_hdr(const image::Image& image, const std::filesystem::path& filepath) noexcept + -> std::expected; + + [[nodiscard]] + auto save_hdr(const image::Image& image) noexcept -> std::expected; +} // namespace stormkit::image::details + +namespace stormkit::image::details { + template + using Unexpected = std::unexpected; + using Error = image::Image::Error; + using Reason = image::Image::Error::Reason; + + ///////////////////////////////////// + ///////////////////////////////////// + auto load_hdr(byte_view<>) noexcept -> std::expected { + assert(false, "Not implemented yet !"); + return {}; + } + + ///////////////////////////////////// + ///////////////////////////////////// + auto save_hdr(const image::Image&, const std::filesystem::path&) noexcept -> std::expected { + assert(false, "Not implemented yet !"); + return {}; + } + + ///////////////////////////////////// + ///////////////////////////////////// + auto save_hdr(const image::Image&) noexcept -> std::expected { + assert(false, "Not implemented yet !"); + return {}; + } +} // namespace stormkit::image::details diff --git a/src/image/image.cpp b/src/image/image.cpp index b90f5c564..52108a07b 100644 --- a/src/image/image.cpp +++ b/src/image/image.cpp @@ -56,7 +56,7 @@ namespace stormkit::image { return Image::Codec::UNKNOWN; } - auto header_to_codec(std::span data) noexcept -> Image::Codec { + auto header_to_codec(byte_view<> data) noexcept -> Image::Codec { EXPECTS(std::size(data) >= 12); if (std::memcmp(std::data(data), std::data(KTX_HEADER), std::size(KTX_HEADER)) == 0) return Image::Codec::KTX; @@ -70,7 +70,7 @@ namespace stormkit::image { return Image::Codec::UNKNOWN; } - auto map(std::span bytes, u32 source_count, u32 destination_count) noexcept -> std::vector { + auto map(byte_view<> bytes, u32 source_count, u32 destination_count) noexcept -> byte_dyn_array { EXPECTS(source_count <= 4u and source_count > 0u and destination_count <= 4u and destination_count > 0u); static constexpr auto BYTE_1_MIN = std::numeric_limits::min(); @@ -80,7 +80,7 @@ namespace stormkit::image { static constexpr auto BYTE_4_MIN = std::numeric_limits::min(); static constexpr auto BYTE_4_MAX = std::numeric_limits::max(); - auto data = std::vector {}; + auto data = byte_dyn_array {}; data.resize(std::size(bytes) * destination_count); if (source_count == 1u and destination_count == 2u) { @@ -138,7 +138,7 @@ namespace stormkit::image { ///////////////////////////////////// ///////////////////////////////////// - Image::Image(const math::Extent3& extent, Format format) noexcept : Image {} { + Image::Image(const math::uextent3& extent, Format format) noexcept : Image {} { create(extent, format); } @@ -150,7 +150,7 @@ namespace stormkit::image { ///////////////////////////////////// ///////////////////////////////////// - Image::Image(std::span data, Image::Codec codec) noexcept : Image {} { + Image::Image(byte_view<> data, Image::Codec codec) noexcept : Image {} { const auto _ = load_from_memory(data, codec); } @@ -249,7 +249,7 @@ namespace stormkit::image { ///////////////////////////////////// ///////////////////////////////////// - auto Image::load_from_memory(std::span data, Image::Codec codec) noexcept -> std::expected { + auto Image::load_from_memory(byte_view<> data, Image::Codec codec) noexcept -> std::expected { EXPECTS(codec != Image::Codec::UNKNOWN); EXPECTS(!std::empty(data)); @@ -350,7 +350,7 @@ namespace stormkit::image { std::format("Failed to load " _Name " image from data\n > {}", result.error().str_error) \ }; \ } \ - return std::expected, Error> { std::in_place, std::move(*result) }; \ + return std::expected { std::in_place, std::move(*result) }; \ } #define CASE_ARGS_DO(_E, _Func, _Name) \ case Image::Codec::_E: { \ @@ -362,17 +362,17 @@ namespace stormkit::image { std::format("Failed to load " _Name " image from data\n > {}", result.error().str_error) \ }; \ } \ - return std::expected, Error> { std::in_place, std::move(*result) }; \ + return std::expected { std::in_place, std::move(*result) }; \ } ///////////////////////////////////// ///////////////////////////////////// - auto Image::save_to_memory(Codec codec, CodecArgs args) const noexcept -> std::expected, Error> { + auto Image::save_to_memory(Codec codec, CodecArgs args) const noexcept -> std::expected { EXPECTS(codec != Image::Codec::UNKNOWN); EXPECTS(codec != Image::Codec::AUTODETECT); EXPECTS(!std::empty(m_data.data)); - auto output = std::vector {}; + auto output = byte_dyn_array {}; switch (codec) { CASE_DO (JPEG, save_jpg, "JPEG") @@ -402,7 +402,7 @@ namespace stormkit::image { ///////////////////////////////////// ///////////////////////////////////// - auto Image::create(math::Extent3 extent, Format format) noexcept -> void { + auto Image::create(math::uextent3 extent, Format format) noexcept -> void { EXPECTS(extent.width > 0u and extent.height > 0u and extent.depth > 0u and format != Format::UNDEFINED); m_data.data.clear(); @@ -414,15 +414,14 @@ namespace stormkit::image { m_data.mip_levels = 1u; m_data.format = format; - m_data.data - .resize(m_data.extent.width - * m_data.extent.height - * m_data.extent.depth - * m_data.layers - * m_data.faces - * m_data.mip_levels - * m_data.channel_count - * m_data.bytes_per_channel); + m_data.data.resize(m_data.extent.width + * m_data.extent.height + * m_data.extent.depth + * m_data.layers + * m_data.faces + * m_data.mip_levels + * m_data.channel_count + * m_data.bytes_per_channel); } ///////////////////////////////////// @@ -449,7 +448,7 @@ namespace stormkit::image { static_cast(m_data.channel_count)));*/ const auto pixel_count = m_data.extent.width * m_data.extent.height * m_data.extent.depth; - image_data.data.resize(pixel_count * image_data.channel_count * image_data.bytes_per_channel, Byte { 255u }); + image_data.data.resize(pixel_count * image_data.channel_count * image_data.bytes_per_channel, byte { 255u }); auto image = Image { std::move(image_data) }; @@ -469,7 +468,7 @@ namespace stormkit::image { ///////////////////////////////////// ///////////////////////////////////// - auto Image::scale(const math::Extent3&) const noexcept -> Image { + auto Image::scale(const math::uextent3&) const noexcept -> Image { return *this; } diff --git a/src/image/jpg.mpp b/src/image/jpg.cppm similarity index 71% rename from src/image/jpg.mpp rename to src/image/jpg.cppm index 7b0e2ea4f..6ca657fe4 100644 --- a/src/image/jpg.mpp +++ b/src/image/jpg.cppm @@ -1,280 +1,261 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include -#include -#include - -#include - -#include -#include -#include - -#include - -export module stormkit.image:jpg; - -import std; - -import stormkit.core; -import stormkit.image; - -namespace stdr = std::ranges; - -export namespace stormkit::image::details { - [[nodiscard]] - auto load_jpg(std::span data) noexcept - -> std::expected; - - [[nodiscard]] - auto save_jpg(const image::Image& image, const std::filesystem::path& filepath) noexcept - -> std::expected; - - [[nodiscard]] - auto save_jpg(const image::Image& image) noexcept - -> std::expected, image::Image::Error>; -} // namespace stormkit::image::details - -namespace stormkit::image::details { - template - using Unexpected = std::unexpected; - using Error = image::Image::Error; - using Reason = image::Image::Error::Reason; - using Format = image::Image::Format; - - namespace jpg { - struct ErrorData { - std::jmp_buf setjmp_buffer; - std::string msg; - }; - - ///////////////////////////////////// - ///////////////////////////////////// - auto error_callback(jpeg_common_struct* st) noexcept -> void { - EXPECTS(st != nullptr); - - auto error_data = reinterpret_cast(st->client_data); - - auto message = std::string {}; - message.resize(JMSG_STR_PARM_MAX); - (*st->err->format_message)(st, stdr::data(message)); - - error_data->msg = message; - - std::longjmp(error_data->setjmp_buffer, 1); - } - } // namespace jpg - - ///////////////////////////////////// - ///////////////////////////////////// - auto load_jpg(std::span data) noexcept - -> std::expected { - auto image_memory = std::vector {}; - volatile auto format = Format {}; // NOTE volatile for error: variable ‘format’ might be - // clobbered by ‘longjmp’ or ‘vfork’ [-Werror=clobbered] - auto extent = math::Extent3 {}; - auto info = jpeg_decompress_struct {}; - auto error_mgr = jpeg_error_mgr {}; - - auto error_data = jpg::ErrorData {}; - - info.err = jpeg_std_error(&error_mgr); - info.client_data = &error_data; - error_mgr.error_exit = jpg::error_callback; - - jpeg_create_decompress(&info); - if (setjmp(error_data.setjmp_buffer)) { - return std::unexpected(Error { .reason = Reason::FAILED_TO_PARSE, - .str_error = error_data.msg }); - } - - jpeg_mem_src(&info, - reinterpret_cast(stdr::data(data)), - as(stdr::size(data))); - jpeg_read_header(&info, TRUE); - - jpeg_start_decompress(&info); - extent.width = info.output_width; - extent.height = info.output_height; - extent.depth = 1; - if (info.output_components == 1) format = Format::R8_UNORM; - if (info.output_components == 2) format = Format::RG8_UNORM; - if (info.output_components == 3) format = Format::RGB8_UNORM; - - image_memory.resize(as(extent.width - * extent.height - * extent.depth - * as(info.out_color_components))); - - auto row_ptr = std::array { nullptr }; - while (info.output_scanline < info.output_height) { - const auto index = as(extent.width - * as(info.output_components) - * info.output_scanline); - row_ptr[0] = stdr::data(image_memory) + index; - jpeg_read_scanlines(&info, - reinterpret_cast(stdr::data(row_ptr)), - as(stdr::size(row_ptr))); - } - - jpeg_finish_decompress(&info); - jpeg_destroy_decompress(&info); - - if (setjmp(error_data.setjmp_buffer)) { - jpeg_destroy_decompress(&info); - return std::unexpected(Error { .reason = Reason::FAILED_TO_PARSE, - .str_error = error_data.msg }); - } - - auto image_data = image::Image::ImageData {}; - - image_data.extent = extent; - image_data.channel_count = get_format_channel_count(format); - image_data.bytes_per_channel = 1u; - image_data.mip_levels = 1u; - image_data.faces = 1u; - image_data.layers = 1u; - image_data.data = std::move(image_memory); - image_data.format = format; - - return Image { std::move(image_data) }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto save_jpg(const image::Image& image, const std::filesystem::path& filepath) noexcept - -> std::expected { - auto _filename = filepath; - - auto image_rgb = image.convert_to(Format::RGB8_UNORM); - - auto info = jpeg_compress_struct {}; - auto error_mgr = jpeg_error_mgr {}; - - auto error_data = jpg::ErrorData {}; - - info.err = jpeg_std_error(&error_mgr); - info.client_data = &error_data; - error_mgr.error_exit = jpg::error_callback; - - for (auto i : range(image_rgb.mip_levels())) { - if (i >= 1u) _filename += to_native_encoding(std::format("_mip{}", i)); - - auto file = io::File::open(_filename, io::Access::WRITE); - if (not file) - return std::unexpected(Error { .reason = Reason::FAILED_TO_SAVE, - .str_error = error_data.msg }); - - auto data = image_rgb.data(0, 0, 0); - const auto& extent = image_rgb.extent(0); - - auto out = -#ifdef STORMKIT_OS_WINDOWS - _fdopen -#else - fdopen -#endif - (file->native_descriptor(), "w"); - - jpeg_create_compress(&info); - jpeg_stdio_dest(&info, out); - - info.image_width = extent.width; - info.image_height = extent.height; - info.input_components = get_format_channel_count(Format::RGB8_UNORM); - info.in_color_space = JCS_RGB; - jpeg_set_defaults(&info); - jpeg_set_quality(&info, 75, TRUE); - - jpeg_start_compress(&info, TRUE); - - auto row_ptr = std::array { nullptr }; - while (info.next_scanline < info.image_height) { - const auto index = info.next_scanline * 3u * info.image_width; - row_ptr[0] = stdr::data(data) + index; - - jpeg_write_scanlines(&info, reinterpret_cast(stdr::data(row_ptr)), 1); - } - - jpeg_finish_compress(&info); - jpeg_destroy_compress(&info); - - file->flush(); - } - - if (setjmp(error_data.setjmp_buffer)) { - jpeg_destroy_compress(&info); - return std::unexpected(Error { .reason = Reason::FAILED_TO_SAVE, - .str_error = error_data.msg }); - } - - return {}; - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto save_jpg(const image::Image& image) noexcept - -> std::expected, image::Image::Error> { - using uchar_ptr = unsigned char*; - - auto output_ptr = uchar_ptr { nullptr }; - - auto image_rgb = image.convert_to(Format::RGB8_UNORM); - - auto info = jpeg_compress_struct {}; - auto error_mgr = jpeg_error_mgr {}; - - auto error_data = jpg::ErrorData {}; - - info.err = jpeg_std_error(&error_mgr); - info.client_data = &error_data; - error_mgr.error_exit = jpg::error_callback; - - auto data = image_rgb.data(0, 0, 0); - const auto& extent = image_rgb.extent(0); - - jpeg_create_compress(&info); - - using ulong = unsigned long; - auto out_size = ulong { 0 }; - jpeg_mem_dest(&info, &output_ptr, &out_size); - - info.image_width = extent.width; - info.image_height = extent.height; - info.input_components = get_format_channel_count(Format::RGB8_UNORM); - info.in_color_space = JCS_RGB; - jpeg_set_defaults(&info); - jpeg_set_quality(&info, 75, TRUE); - - jpeg_start_compress(&info, TRUE); - - auto row_ptr = std::array { nullptr }; - while (info.next_scanline < info.image_height) { - const auto index = info.next_scanline * 3u * info.image_width; - row_ptr[0] = stdr::data(data) + index; - - jpeg_write_scanlines(&info, reinterpret_cast(stdr::data(row_ptr)), 1); - } - - jpeg_finish_compress(&info); - jpeg_destroy_compress(&info); - - if (setjmp(error_data.setjmp_buffer)) { - jpeg_destroy_compress(&info); - return std::unexpected(Error { .reason = Reason::FAILED_TO_SAVE, - .str_error = error_data.msg }); - } - - auto output = std::vector {}; - output.reserve((out_size)); - - std::ranges::copy(as_bytes(output_ptr, out_size), std::back_inserter(output)); - if (output_ptr != nullptr) std::free(output_ptr); - - return output; - } -} // namespace stormkit::image::details +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include +#include + +#include + +#include +#include +#include + +#include + +export module stormkit.image:jpg; + +import std; + +import stormkit.core; +import stormkit.image; + +namespace stdr = std::ranges; + +export namespace stormkit::image::details { + [[nodiscard]] + auto load_jpg(byte_view<> data) noexcept -> std::expected; + + [[nodiscard]] + auto save_jpg(const image::Image& image, const std::filesystem::path& filepath) noexcept + -> std::expected; + + [[nodiscard]] + auto save_jpg(const image::Image& image) noexcept -> std::expected; +} // namespace stormkit::image::details + +namespace stormkit::image::details { + template + using Unexpected = std::unexpected; + using Error = image::Image::Error; + using Reason = image::Image::Error::Reason; + using Format = image::Image::Format; + + namespace jpg { + struct ErrorData { + std::jmp_buf setjmp_buffer; + string msg; + }; + + ///////////////////////////////////// + ///////////////////////////////////// + auto error_callback(jpeg_common_struct* st) noexcept -> void { + EXPECTS(st != nullptr); + + auto error_data = reinterpret_cast(st->client_data); + + auto message = string {}; + message.resize(JMSG_STR_PARM_MAX); + (*st->err->format_message)(st, stdr::data(message)); + + error_data->msg = message; + + std::longjmp(error_data->setjmp_buffer, 1); + } + } // namespace jpg + + ///////////////////////////////////// + ///////////////////////////////////// + auto load_jpg(byte_view<> data) noexcept -> std::expected { + auto image_memory = byte_dyn_array {}; + volatile auto format = Format {}; // NOTE volatile for error: variable ‘format’ might be + // clobbered by ‘longjmp’ or ‘vfork’ [-Werror=clobbered] + auto extent = math::uextent3 {}; + auto info = jpeg_decompress_struct {}; + auto error_mgr = jpeg_error_mgr {}; + + auto error_data = jpg::ErrorData {}; + + info.err = jpeg_std_error(&error_mgr); + info.client_data = &error_data; + error_mgr.error_exit = jpg::error_callback; + + jpeg_create_decompress(&info); + if (setjmp(error_data.setjmp_buffer)) { + return std::unexpected(Error { .reason = Reason::FAILED_TO_PARSE, .str_error = error_data.msg }); + } + + jpeg_mem_src(&info, reinterpret_cast(stdr::data(data)), as(stdr::size(data))); + jpeg_read_header(&info, TRUE); + + jpeg_start_decompress(&info); + extent.width = info.output_width; + extent.height = info.output_height; + extent.depth = 1; + if (info.output_components == 1) format = Format::R8_UNORM; + if (info.output_components == 2) format = Format::RG8_UNORM; + if (info.output_components == 3) format = Format::RGB8_UNORM; + + image_memory.resize(as(extent.width * extent.height * extent.depth * as(info.out_color_components))); + + auto row_ptr = array { nullptr }; + while (info.output_scanline < info.output_height) { + const auto index = as(extent.width * as(info.output_components) * info.output_scanline); + row_ptr[0] = stdr::data(image_memory) + index; + jpeg_read_scanlines(&info, reinterpret_cast(stdr::data(row_ptr)), as(stdr::size(row_ptr))); + } + + jpeg_finish_decompress(&info); + jpeg_destroy_decompress(&info); + + if (setjmp(error_data.setjmp_buffer)) { + jpeg_destroy_decompress(&info); + return std::unexpected(Error { .reason = Reason::FAILED_TO_PARSE, .str_error = error_data.msg }); + } + + auto image_data = image::Image::ImageData {}; + + image_data.extent = extent; + image_data.channel_count = get_format_channel_count(format); + image_data.bytes_per_channel = 1u; + image_data.mip_levels = 1u; + image_data.faces = 1u; + image_data.layers = 1u; + image_data.data = std::move(image_memory); + image_data.format = format; + + return Image { std::move(image_data) }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + auto save_jpg(const image::Image& image, const std::filesystem::path& filepath) noexcept + -> std::expected { + auto _filename = filepath; + + auto image_rgb = image.convert_to(Format::RGB8_UNORM); + + auto info = jpeg_compress_struct {}; + auto error_mgr = jpeg_error_mgr {}; + + auto error_data = jpg::ErrorData {}; + + info.err = jpeg_std_error(&error_mgr); + info.client_data = &error_data; + error_mgr.error_exit = jpg::error_callback; + + for (auto i : range(image_rgb.mip_levels())) { + if (i >= 1u) _filename += to_native_encoding(std::format("_mip{}", i)); + + auto file = io::File::open(_filename, io::Access::WRITE); + if (not file) return std::unexpected(Error { .reason = Reason::FAILED_TO_SAVE, .str_error = error_data.msg }); + + auto data = image_rgb.data(0, 0, 0); + const auto& extent = image_rgb.extent(0); + + auto out = +#ifdef STORMKIT_OS_WINDOWS + _fdopen +#else + fdopen +#endif + (file->native_descriptor(), "w"); + + jpeg_create_compress(&info); + jpeg_stdio_dest(&info, out); + + info.image_width = extent.width; + info.image_height = extent.height; + info.input_components = get_format_channel_count(Format::RGB8_UNORM); + info.in_color_space = JCS_RGB; + jpeg_set_defaults(&info); + jpeg_set_quality(&info, 75, TRUE); + + jpeg_start_compress(&info, TRUE); + + auto row_ptr = array { nullptr }; + while (info.next_scanline < info.image_height) { + const auto index = info.next_scanline * 3u * info.image_width; + row_ptr[0] = stdr::data(data) + index; + + jpeg_write_scanlines(&info, reinterpret_cast(stdr::data(row_ptr)), 1); + } + + jpeg_finish_compress(&info); + jpeg_destroy_compress(&info); + + file->flush(); + } + + if (setjmp(error_data.setjmp_buffer)) { + jpeg_destroy_compress(&info); + return std::unexpected(Error { .reason = Reason::FAILED_TO_SAVE, .str_error = error_data.msg }); + } + + return {}; + } + + ///////////////////////////////////// + ///////////////////////////////////// + auto save_jpg(const image::Image& image) noexcept -> std::expected { + using uchar_ptr = unsigned char*; + + auto output_ptr = uchar_ptr { nullptr }; + + auto image_rgb = image.convert_to(Format::RGB8_UNORM); + + auto info = jpeg_compress_struct {}; + auto error_mgr = jpeg_error_mgr {}; + + auto error_data = jpg::ErrorData {}; + + info.err = jpeg_std_error(&error_mgr); + info.client_data = &error_data; + error_mgr.error_exit = jpg::error_callback; + + auto data = image_rgb.data(0, 0, 0); + const auto& extent = image_rgb.extent(0); + + jpeg_create_compress(&info); + + using ulong = unsigned long; + auto out_size = ulong { 0 }; + jpeg_mem_dest(&info, &output_ptr, &out_size); + + info.image_width = extent.width; + info.image_height = extent.height; + info.input_components = get_format_channel_count(Format::RGB8_UNORM); + info.in_color_space = JCS_RGB; + jpeg_set_defaults(&info); + jpeg_set_quality(&info, 75, TRUE); + + jpeg_start_compress(&info, TRUE); + + auto row_ptr = array { nullptr }; + while (info.next_scanline < info.image_height) { + const auto index = info.next_scanline * 3u * info.image_width; + row_ptr[0] = stdr::data(data) + index; + + jpeg_write_scanlines(&info, reinterpret_cast(stdr::data(row_ptr)), 1); + } + + jpeg_finish_compress(&info); + jpeg_destroy_compress(&info); + + if (setjmp(error_data.setjmp_buffer)) { + jpeg_destroy_compress(&info); + return std::unexpected(Error { .reason = Reason::FAILED_TO_SAVE, .str_error = error_data.msg }); + } + + auto output = byte_dyn_array {}; + output.reserve((out_size)); + + std::ranges::copy(as_bytes(output_ptr, out_size), std::back_inserter(output)); + if (output_ptr != nullptr) std::free(output_ptr); + + return output; + } +} // namespace stormkit::image::details diff --git a/src/image/ktx.mpp b/src/image/ktx.cppm similarity index 89% rename from src/image/ktx.mpp rename to src/image/ktx.cppm index 2537bcd49..63d5eae16 100644 --- a/src/image/ktx.mpp +++ b/src/image/ktx.cppm @@ -1,156 +1,151 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; -#include - -export module stormkit.image:ktx; - -import std; - -import stormkit.core; -import stormkit.image; - -export namespace stormkit::image::details { - [[nodiscard]] - auto load_ktx(std::span data) noexcept - -> std::expected; - - [[nodiscard]] - auto save_ktx(const image::Image& image, const std::filesystem::path& filepath) noexcept - -> std::expected; - - [[nodiscard]] - auto save_ktx(const image::Image& image) noexcept - -> std::expected, image::Image::Error>; -} // namespace stormkit::image::details - -namespace stormkit::image::details { - template - using Unexpected = std::unexpected; - using Error = image::Image::Error; - using Reason = image::Image::Error::Reason; - using Format = image::Image::Format; - - ///////////////////////////////////// - ///////////////////////////////////// - /*constexpr auto toStormFormat(gli::format format) noexcept {*/ - /*switch (format) {*/ - /* case gli::format_R8_SNORM_PACK8: return Format::R8_SNORM;*/ - /* case gli::format_R8_UNORM_PACK8: return Format::R8_UNORM;*/ - /* case gli::format_R16_SNORM_PACK16: return Format::R16_SNORM;*/ - /* case gli::format_R16_UNORM_PACK16: return Format::R16_UNORM;*/ - /* case gli::format_R8_SINT_PACK8: return Format::R8I;*/ - /* case gli::format_R8_UINT_PACK8: return Format::R8U;*/ - /* case gli::format_R16_SINT_PACK16: return Format::R16I;*/ - /* case gli::format_R16_UINT_PACK16: return Format::R16U;*/ - /* case gli::format_R32_SINT_PACK32: return Format::R32I;*/ - /* case gli::format_R32_UINT_PACK32: return Format::R32U;*/ - /* case gli::format_R16_SFLOAT_PACK16: return Format::R16F;*/ - /* case gli::format_R32_SFLOAT_PACK32: return Format::R32F;*/ - /**/ - /* case gli::format_RG8_SNORM_PACK8: return Format::RG8_SNORM;*/ - /* case gli::format_RG8_UNORM_PACK8: return Format::RG8_UNORM;*/ - /* case gli::format_RG16_SNORM_PACK16: return Format::RG16_SNORM;*/ - /* case gli::format_RG16_UNORM_PACK16: return Format::RG16_UNORM;*/ - /* case gli::format_RG8_SINT_PACK8: return Format::RG8I;*/ - /* case gli::format_RG8_UINT_PACK8: return Format::RG8U;*/ - /* case gli::format_RG16_SINT_PACK16: return Format::RG16I;*/ - /* case gli::format_RG16_UINT_PACK16: return Format::RG16U;*/ - /* case gli::format_RG32_SINT_PACK32: return Format::RG32I;*/ - /* case gli::format_RG32_UINT_PACK32: return Format::RG32U;*/ - /* case gli::format_RG16_SFLOAT_PACK16: return Format::RG16F;*/ - /* case gli::format_RG32_SFLOAT_PACK32: return Format::RG32F;*/ - /**/ - /* case gli::format_RGB8_SNORM_PACK8: return Format::RGB8_SNORM;*/ - /* case gli::format_RGB8_UNORM_PACK8: return Format::RGB8_UNORM;*/ - /* case gli::format_RGB16_SNORM_PACK16: return Format::RGB16_SNORM;*/ - /* case gli::format_RGB16_UNORM_PACK16: return Format::RGB16_UNORM;*/ - /* case gli::format_BGR8_UNORM_PACK8: return Format::RGB16_UNORM;*/ - /* case gli::format_RGB8_SINT_PACK8: return Format::RGB8I;*/ - /* case gli::format_RGB8_UINT_PACK8: return Format::RGB8U;*/ - /* case gli::format_RGB16_SINT_PACK16: return Format::RGB16I;*/ - /* case gli::format_RGB16_UINT_PACK16: return Format::RGB16U;*/ - /* case gli::format_RGB32_SINT_PACK32: return Format::RGB32I;*/ - /* case gli::format_RGB32_UINT_PACK32: return Format::RGB32U;*/ - /* case gli::format_RGB16_SFLOAT_PACK16: return Format::RGB16F;*/ - /* case gli::format_RGB32_SFLOAT_PACK32: return Format::RGB32F;*/ - /* case gli::format_RGB8_SRGB_PACK8: return Format::SRGB8;*/ - /* case gli::format_BGR8_SRGB_PACK8: return Format::SBGR8;*/ - /**/ - /* case gli::format_RGBA8_SNORM_PACK8: return Format::RGBA8_SNORM;*/ - /* case gli::format_RGBA8_UNORM_PACK8: return Format::RGBA8_UNORM;*/ - /* case gli::format_RGBA16_SNORM_PACK16: return Format::RGBA16_SNORM;*/ - /* case gli::format_RGBA16_UNORM_PACK16: return Format::RGBA16_UNORM;*/ - /* case gli::format_BGRA8_UNORM_PACK8: return Format::RGBA16_UNORM;*/ - /* case gli::format_RGBA8_SINT_PACK8: return Format::RGBA8I;*/ - /* case gli::format_RGBA8_UINT_PACK8: return Format::RGBA8U;*/ - /* case gli::format_RGBA16_SINT_PACK16: return Format::RGBA16I;*/ - /* case gli::format_RGBA16_UINT_PACK16: return Format::RGBA16U;*/ - /* case gli::format_RGBA32_SINT_PACK32: return Format::RGBA32I;*/ - /* case gli::format_RGBA32_UINT_PACK32: return Format::RGBA32U;*/ - /* case gli::format_RGBA16_SFLOAT_PACK16: return Format::RGBA16F;*/ - /* case gli::format_RGBA32_SFLOAT_PACK32: return Format::RGBA32F;*/ - /* case gli::format_RGBA8_SRGB_PACK8: return Format::SRGBA8;*/ - /* case gli::format_BGRA8_SRGB_PACK8: return Format::SBGRA8;*/ - /* default: break;*/ - /*}*/ - /**/ - /* return Format::UNDEFINED;*/ - /*}*/ - - ///////////////////////////////////// - ///////////////////////////////////// - auto load_ktx([[maybe_unused]] std::span data) noexcept - -> std::expected { - /*auto image = gli::load_ktx(reinterpret_cast(std::data(data)), - * std::size(data));*/ - /**/ - /*const auto faces = as(image.faces());*/ - /*const auto layers = as(image.layers());*/ - /*const auto mip_levels = as(image.levels());*/ - /*const auto format = toStormFormat(image.format());*/ - /**/ - /*if (format == Format::UNDEFINED)*/ - /* return std::unexpected(Error { .reason = Reason::FAILED_TO_PARSE,*/ - /* .str_error = "Unsupported pixel format" });*/ - /**/ - /*auto image_memory = std::vector {};*/ - /*image_memory.resize(image.size());*/ - /**/ - /*std::ranges::copy(as_bytes(image.data(), image.size()), std::begin(image_memory));*/ - /**/ - /*auto image_data = image::Image::ImageData {};*/ - /**/ - /*image_data.extent = math::ExtentI { image.extent().x, image.extent().y, image.extent().z - * };*/ - /*image_data.channel_count = get_format_channel_count(format);*/ - /*image_data.bytes_per_channel = getSizeof(format);*/ - /*image_data.mip_levels = mip_levels;*/ - /*image_data.faces = faces;*/ - /*image_data.layers = layers;*/ - /*image_data.data = std::move(image_memory);*/ - /*image_data.format = format;*/ - /**/ - /*return Image { std::move(image_data) };*/ - assert(false, "Not implemented yet !"); - return {}; - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto save_ktx(const image::Image&, const std::filesystem::path&) noexcept - -> std::expected { - assert(false, "Not implemented yet !"); - return {}; - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto save_ktx(const image::Image&) noexcept - -> std::expected, image::Image::Error> { - assert(false, "Not implemented yet !"); - return {}; - } -} // namespace stormkit::image::details +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; +#include + +export module stormkit.image:ktx; + +import std; + +import stormkit.core; +import stormkit.image; + +export namespace stormkit::image::details { + [[nodiscard]] + auto load_ktx(byte_view<> data) noexcept -> std::expected; + + [[nodiscard]] + auto save_ktx(const image::Image& image, const std::filesystem::path& filepath) noexcept + -> std::expected; + + [[nodiscard]] + auto save_ktx(const image::Image& image) noexcept -> std::expected; +} // namespace stormkit::image::details + +namespace stormkit::image::details { + template + using Unexpected = std::unexpected; + using Error = image::Image::Error; + using Reason = image::Image::Error::Reason; + using Format = image::Image::Format; + + ///////////////////////////////////// + ///////////////////////////////////// + /*constexpr auto toStormFormat(gli::format format) noexcept {*/ + /*switch (format) {*/ + /* case gli::format_R8_SNORM_PACK8: return Format::R8_SNORM;*/ + /* case gli::format_R8_UNORM_PACK8: return Format::R8_UNORM;*/ + /* case gli::format_R16_SNORM_PACK16: return Format::R16_SNORM;*/ + /* case gli::format_R16_UNORM_PACK16: return Format::R16_UNORM;*/ + /* case gli::format_R8_SINT_PACK8: return Format::R8I;*/ + /* case gli::format_R8_UINT_PACK8: return Format::R8U;*/ + /* case gli::format_R16_SINT_PACK16: return Format::R16I;*/ + /* case gli::format_R16_UINT_PACK16: return Format::R16U;*/ + /* case gli::format_R32_SINT_PACK32: return Format::R32I;*/ + /* case gli::format_R32_UINT_PACK32: return Format::R32U;*/ + /* case gli::format_R16_SFLOAT_PACK16: return Format::R16F;*/ + /* case gli::format_R32_SFLOAT_PACK32: return Format::R32F;*/ + /**/ + /* case gli::format_RG8_SNORM_PACK8: return Format::RG8_SNORM;*/ + /* case gli::format_RG8_UNORM_PACK8: return Format::RG8_UNORM;*/ + /* case gli::format_RG16_SNORM_PACK16: return Format::RG16_SNORM;*/ + /* case gli::format_RG16_UNORM_PACK16: return Format::RG16_UNORM;*/ + /* case gli::format_RG8_SINT_PACK8: return Format::RG8I;*/ + /* case gli::format_RG8_UINT_PACK8: return Format::RG8U;*/ + /* case gli::format_RG16_SINT_PACK16: return Format::RG16I;*/ + /* case gli::format_RG16_UINT_PACK16: return Format::RG16U;*/ + /* case gli::format_RG32_SINT_PACK32: return Format::RG32I;*/ + /* case gli::format_RG32_UINT_PACK32: return Format::RG32U;*/ + /* case gli::format_RG16_SFLOAT_PACK16: return Format::RG16F;*/ + /* case gli::format_RG32_SFLOAT_PACK32: return Format::RG32F;*/ + /**/ + /* case gli::format_RGB8_SNORM_PACK8: return Format::RGB8_SNORM;*/ + /* case gli::format_RGB8_UNORM_PACK8: return Format::RGB8_UNORM;*/ + /* case gli::format_RGB16_SNORM_PACK16: return Format::RGB16_SNORM;*/ + /* case gli::format_RGB16_UNORM_PACK16: return Format::RGB16_UNORM;*/ + /* case gli::format_BGR8_UNORM_PACK8: return Format::RGB16_UNORM;*/ + /* case gli::format_RGB8_SINT_PACK8: return Format::RGB8I;*/ + /* case gli::format_RGB8_UINT_PACK8: return Format::RGB8U;*/ + /* case gli::format_RGB16_SINT_PACK16: return Format::RGB16I;*/ + /* case gli::format_RGB16_UINT_PACK16: return Format::RGB16U;*/ + /* case gli::format_RGB32_SINT_PACK32: return Format::RGB32I;*/ + /* case gli::format_RGB32_UINT_PACK32: return Format::RGB32U;*/ + /* case gli::format_RGB16_SFLOAT_PACK16: return Format::RGB16F;*/ + /* case gli::format_RGB32_SFLOAT_PACK32: return Format::RGB32F;*/ + /* case gli::format_RGB8_SRGB_PACK8: return Format::SRGB8;*/ + /* case gli::format_BGR8_SRGB_PACK8: return Format::SBGR8;*/ + /**/ + /* case gli::format_RGBA8_SNORM_PACK8: return Format::RGBA8_SNORM;*/ + /* case gli::format_RGBA8_UNORM_PACK8: return Format::RGBA8_UNORM;*/ + /* case gli::format_RGBA16_SNORM_PACK16: return Format::RGBA16_SNORM;*/ + /* case gli::format_RGBA16_UNORM_PACK16: return Format::RGBA16_UNORM;*/ + /* case gli::format_BGRA8_UNORM_PACK8: return Format::RGBA16_UNORM;*/ + /* case gli::format_RGBA8_SINT_PACK8: return Format::RGBA8I;*/ + /* case gli::format_RGBA8_UINT_PACK8: return Format::RGBA8U;*/ + /* case gli::format_RGBA16_SINT_PACK16: return Format::RGBA16I;*/ + /* case gli::format_RGBA16_UINT_PACK16: return Format::RGBA16U;*/ + /* case gli::format_RGBA32_SINT_PACK32: return Format::RGBA32I;*/ + /* case gli::format_RGBA32_UINT_PACK32: return Format::RGBA32U;*/ + /* case gli::format_RGBA16_SFLOAT_PACK16: return Format::RGBA16F;*/ + /* case gli::format_RGBA32_SFLOAT_PACK32: return Format::RGBA32F;*/ + /* case gli::format_RGBA8_SRGB_PACK8: return Format::SRGBA8;*/ + /* case gli::format_BGRA8_SRGB_PACK8: return Format::SBGRA8;*/ + /* default: break;*/ + /*}*/ + /**/ + /* return Format::UNDEFINED;*/ + /*}*/ + + ///////////////////////////////////// + ///////////////////////////////////// + auto load_ktx([[maybe_unused]] byte_view<> data) noexcept -> std::expected { + /*auto image = gli::load_ktx(reinterpret_cast(std::data(data)), + * std::size(data));*/ + /**/ + /*const auto faces = as(image.faces());*/ + /*const auto layers = as(image.layers());*/ + /*const auto mip_levels = as(image.levels());*/ + /*const auto format = toStormFormat(image.format());*/ + /**/ + /*if (format == Format::UNDEFINED)*/ + /* return std::unexpected(Error { .reason = Reason::FAILED_TO_PARSE,*/ + /* .str_error = "Unsupported pixel format" });*/ + /**/ + /*auto image_memory = byte_dyn_array {};*/ + /*image_memory.resize(image.size());*/ + /**/ + /*std::ranges::copy(as_bytes(image.data(), image.size()), std::begin(image_memory));*/ + /**/ + /*auto image_data = image::Image::ImageData {};*/ + /**/ + /*image_data.extent = math::extentI { image.extent().x, image.extent().y, image.extent().z + * };*/ + /*image_data.channel_count = get_format_channel_count(format);*/ + /*image_data.bytes_per_channel = getSizeof(format);*/ + /*image_data.mip_levels = mip_levels;*/ + /*image_data.faces = faces;*/ + /*image_data.layers = layers;*/ + /*image_data.data = std::move(image_memory);*/ + /*image_data.format = format;*/ + /**/ + /*return Image { std::move(image_data) };*/ + assert(false, "Not implemented yet !"); + return {}; + } + + ///////////////////////////////////// + ///////////////////////////////////// + auto save_ktx(const image::Image&, const std::filesystem::path&) noexcept -> std::expected { + assert(false, "Not implemented yet !"); + return {}; + } + + ///////////////////////////////////// + ///////////////////////////////////// + auto save_ktx(const image::Image&) noexcept -> std::expected { + assert(false, "Not implemented yet !"); + return {}; + } +} // namespace stormkit::image::details diff --git a/src/image/png.mpp b/src/image/png.cppm similarity index 63% rename from src/image/png.mpp rename to src/image/png.cppm index 8af185424..b0b8043d7 100644 --- a/src/image/png.mpp +++ b/src/image/png.cppm @@ -1,281 +1,255 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include -#include - -#include - -export module stormkit.image:png; - -import std; - -import stormkit.core; -import stormkit.image; - -export namespace stormkit::image::details { - [[nodiscard]] - auto load_png(std::span data) noexcept - -> std::expected; - - [[nodiscard]] - auto save_png(const image::Image& image, const std::filesystem::path& filepath) noexcept - -> std::expected; - - [[nodiscard]] - auto save_png(const image::Image& image) noexcept - -> std::expected, image::Image::Error>; -} // namespace stormkit::image::details - -namespace stormkit::image::details { - template - using Unexpected = std::unexpected; - using Error = image::Image::Error; - using Reason = image::Image::Error::Reason; - using Format = image::Image::Format; - - namespace png { - struct ReadParam { - usize readed; - std::span& data; - }; - - struct WriteParam { - std::vector& data; - }; - - ///////////////////////////////////// - ///////////////////////////////////// - static auto read_func(png_struct* ps, png_byte* d, png_size_t length) noexcept -> void { - auto& param = *reinterpret_cast(png_get_io_ptr(ps)); - - auto _d = as_bytes(d, length); - auto data = param.data.subspan(param.readed, length); - - std::ranges::copy(data, std::ranges::begin(_d)); - - param.readed += length; - } - - ///////////////////////////////////// - ///////////////////////////////////// - static auto write_func(png_struct* ps, png_byte* d, png_size_t length) -> void { - auto& param = *reinterpret_cast(png_get_io_ptr(ps)); - - auto _d = as_bytes(d, length); - param.data.reserve(std::size(param.data) + length); - - std::ranges::copy(_d, std::back_inserter(param.data)); - } - } // namespace png - - ///////////////////////////////////// - ///////////////////////////////////// - auto load_png(std::span data) noexcept - -> std::expected { - auto image_memory = std::vector {}; - auto format = Format {}; - auto extent = math::Extent3 {}; - - auto read_param = png::ReadParam { 8u, data }; - - auto sig = reinterpret_cast(std::data(data)); - if (!png_check_sig(sig, 8u)) - return std::unexpected(Error { - .reason = Reason::FAILED_TO_PARSE, - .str_error = "[libpng] Failed to validate PNG signature" }); - - auto png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); - if (!png_ptr) - return std::unexpected(Error { - .reason = Reason::FAILED_TO_PARSE, - .str_error = "[libpng] Failed to init (png_create_read_struct)" }); - - auto info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - png_destroy_read_struct(&png_ptr, nullptr, nullptr); - return std::unexpected(Error { - .reason = Reason::FAILED_TO_PARSE, - .str_error = "[libpng] Failed to init (png_create_info_struct)" }); - } - - png_set_read_fn(png_ptr, &read_param, png::read_func); - png_set_sig_bytes(png_ptr, 8); - png_read_info(png_ptr, info_ptr); - - auto bit_depth = 0; - auto color_type = 0; - - png_get_IHDR(png_ptr, - info_ptr, - &extent.width, - &extent.height, - &bit_depth, - &color_type, - nullptr, - nullptr, - nullptr); - - if (color_type == PNG_COLOR_TYPE_GRAY) png_set_expand_gray_1_2_4_to_8(png_ptr); - else if (color_type == PNG_COLOR_TYPE_PALETTE) { - png_set_palette_to_rgb(png_ptr); - png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER); - } - if (bit_depth < 8) png_set_packing(png_ptr); - if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); - - png_get_IHDR(png_ptr, - info_ptr, - &extent.width, - &extent.height, - &bit_depth, - &color_type, - nullptr, - nullptr, - nullptr); - - switch (color_type) { - case PNG_COLOR_TYPE_GRAY: { - if (bit_depth == 8) format = Format::R8_UNORM; - else if (bit_depth == 16) - format = Format::R16_UNORM; - - break; - } - case PNG_COLOR_TYPE_GRAY_ALPHA: { - if (bit_depth == 8) format = Format::RG8_UNORM; - else if (bit_depth == 16) - format = Format::RG16_UNORM; - - break; - } - case PNG_COLOR_TYPE_RGB: { - if (bit_depth == 8) format = Format::RGB8_UNORM; - else if (bit_depth == 16) - format = Format::RGB16_UNORM; - - break; - } - case PNG_COLOR_TYPE_RGB_ALPHA: { - if (bit_depth == 8) format = Format::RGBA8_UNORM; - else if (bit_depth == 16) - format = Format::RGBA16_UNORM; - - break; - } - case PNG_COLOR_TYPE_PALETTE: { - if (bit_depth == 8) format = Format::RGBA8_UNORM; - else if (bit_depth == 16) - format = Format::RGBA16_UNORM; - - break; - } - - default: break; - } - - png_read_update_info(png_ptr, info_ptr); - - const auto row_bytes = png_get_rowbytes(png_ptr, info_ptr); - image_memory.resize(extent.height * row_bytes); - - auto row_pointers = std::vector { extent.height, nullptr }; - - auto buff_pos = std::data(image_memory); - - for (auto i : range(extent.height)) row_pointers[i] = &buff_pos[row_bytes * i]; - - png_read_image(png_ptr, reinterpret_cast(std::data(row_pointers))); - png_read_end(png_ptr, info_ptr); - - png_destroy_info_struct(png_ptr, &info_ptr); - png_destroy_read_struct(&png_ptr, nullptr, nullptr); - - auto image_data = image::Image::ImageData { - .extent = std::move(extent), - .channel_count = get_format_channel_count(format), - .bytes_per_channel = getSizeof(format), - .layers = 1u, - .faces = 1u, - .mip_levels = 1u, - .format = format, - .data = std::move(image_memory) - }; - - return Image { std::move(image_data) }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto save_png(const image::Image&, const std::filesystem::path&) noexcept - -> std::expected { - assert(false, "Not implemented yet !"); - return {}; - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto save_png(const image::Image& image) noexcept - -> std::expected, image::Image::Error> { - auto output = std::vector {}; - - auto write_param = png::WriteParam { output }; - - auto png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); - if (!png_ptr) - return std::unexpected(Error { - .reason = Reason::FAILED_TO_PARSE, - .str_error = "[libpng] Failed to init (png_create_write_struct)" }); - - auto info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - png_destroy_write_struct(&png_ptr, nullptr); - return std::unexpected(Error { - .reason = Reason::FAILED_TO_PARSE, - .str_error = "[libpng] Failed to init (png_create_info_struct)" }); - } - - if (setjmp(png_jmpbuf(png_ptr))) { - png_destroy_info_struct(png_ptr, &info_ptr); - png_destroy_write_struct(&png_ptr, nullptr); - return std::unexpected(Error { - .reason = Reason::FAILED_TO_PARSE, - .str_error = "[libpng] Unkown error during png creation" }); - } - - png_set_write_fn(png_ptr, &write_param, png::write_func, nullptr); - - const auto& data = image.image_data(); - - png_set_IHDR(png_ptr, - info_ptr, - data.extent.width, - data.extent.height, - 8, - PNG_COLOR_TYPE_RGB_ALPHA, - PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, - PNG_FILTER_TYPE_DEFAULT); - png_write_info(png_ptr, info_ptr); - - auto rows = std::vector { data.extent.height, nullptr }; - for (auto i : range(data.extent.height)) - rows[i] = const_cast(&data.data[i - * data.extent.width - * data.channel_count - * data.bytes_per_channel]); // TODO Fix this shit - - png_set_rows(png_ptr, info_ptr, reinterpret_cast(std::data(rows))); - png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, nullptr); - png_write_end(png_ptr, info_ptr); - - png_destroy_info_struct(png_ptr, &info_ptr); - png_destroy_write_struct(&png_ptr, nullptr); - - return output; - ; - } -} // namespace stormkit::image::details +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include + +#include + +export module stormkit.image:png; + +import std; + +import stormkit.core; +import stormkit.image; + +export namespace stormkit::image::details { + [[nodiscard]] + auto load_png(byte_view<> data) noexcept -> std::expected; + + [[nodiscard]] + auto save_png(const image::Image& image, const std::filesystem::path& filepath) noexcept + -> std::expected; + + [[nodiscard]] + auto save_png(const image::Image& image) noexcept -> std::expected; +} // namespace stormkit::image::details + +namespace stdr = std::ranges; + +namespace stormkit::image::details { + template + using Unexpected = std::unexpected; + using Error = image::Image::Error; + using Reason = image::Image::Error::Reason; + using Format = image::Image::Format; + + namespace png { + struct ReadParam { + usize readed; + byte_view<>& data; + }; + + struct WriteParam { + byte_dyn_array& data; + }; + + ///////////////////////////////////// + ///////////////////////////////////// + static auto read_func(png_struct* ps, png_byte* d, png_size_t length) noexcept -> void { + auto& param = *std::bit_cast(png_get_io_ptr(ps)); + + auto _d = as_bytes_mut(d, length); + auto data = param.data.subspan(param.readed, length); + + stdr::copy(data, stdr::begin(_d)); + + param.readed += length; + } + + ///////////////////////////////////// + ///////////////////////////////////// + static auto write_func(png_struct* ps, png_byte* d, png_size_t length) -> void { + auto& param = *std::bit_cast(png_get_io_ptr(ps)); + + auto _d = as_bytes(d, length); + param.data.reserve(std::size(param.data) + length); + + stdr::copy(_d, std::back_inserter(param.data)); + } + } // namespace png + + ///////////////////////////////////// + ///////////////////////////////////// + auto load_png(byte_view<> data) noexcept -> std::expected { + auto image_memory = byte_dyn_array {}; + auto format = Format {}; + auto extent = math::uextent3 {}; + + auto read_param = png::ReadParam { 8u, data }; + + auto sig = std::bit_cast(std::data(data)); + if (!png_check_sig(sig, 8u)) + return std::unexpected(Error { .reason = Reason::FAILED_TO_PARSE, + .str_error = "[libpng] Failed to validate PNG signature" }); + + auto png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + if (!png_ptr) + return std::unexpected(Error { .reason = Reason::FAILED_TO_PARSE, + .str_error = "[libpng] Failed to init (png_create_read_struct)" }); + + auto info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_read_struct(&png_ptr, nullptr, nullptr); + return std::unexpected(Error { .reason = Reason::FAILED_TO_PARSE, + .str_error = "[libpng] Failed to init (png_create_info_struct)" }); + } + + png_set_read_fn(png_ptr, &read_param, png::read_func); + png_set_sig_bytes(png_ptr, 8); + png_read_info(png_ptr, info_ptr); + + auto bit_depth = 0; + auto color_type = 0; + + png_get_IHDR(png_ptr, info_ptr, &extent.width, &extent.height, &bit_depth, &color_type, nullptr, nullptr, nullptr); + + if (color_type == PNG_COLOR_TYPE_GRAY) png_set_expand_gray_1_2_4_to_8(png_ptr); + else if (color_type == PNG_COLOR_TYPE_PALETTE) { + png_set_palette_to_rgb(png_ptr); + png_set_filler(png_ptr, 0xFF, PNG_FILLER_AFTER); + } + if (bit_depth < 8) png_set_packing(png_ptr); + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); + + png_get_IHDR(png_ptr, info_ptr, &extent.width, &extent.height, &bit_depth, &color_type, nullptr, nullptr, nullptr); + + switch (color_type) { + case PNG_COLOR_TYPE_GRAY: { + if (bit_depth == 8) format = Format::R8_UNORM; + else if (bit_depth == 16) + format = Format::R16_UNORM; + + break; + } + case PNG_COLOR_TYPE_GRAY_ALPHA: { + if (bit_depth == 8) format = Format::RG8_UNORM; + else if (bit_depth == 16) + format = Format::RG16_UNORM; + + break; + } + case PNG_COLOR_TYPE_RGB: { + if (bit_depth == 8) format = Format::RGB8_UNORM; + else if (bit_depth == 16) + format = Format::RGB16_UNORM; + + break; + } + case PNG_COLOR_TYPE_RGB_ALPHA: { + if (bit_depth == 8) format = Format::RGBA8_UNORM; + else if (bit_depth == 16) + format = Format::RGBA16_UNORM; + + break; + } + case PNG_COLOR_TYPE_PALETTE: { + if (bit_depth == 8) format = Format::RGBA8_UNORM; + else if (bit_depth == 16) + format = Format::RGBA16_UNORM; + + break; + } + + default: break; + } + + png_read_update_info(png_ptr, info_ptr); + + const auto row_bytes = png_get_rowbytes(png_ptr, info_ptr); + image_memory.resize(extent.height * row_bytes); + + auto row_pointers = dyn_array { extent.height, nullptr }; + + auto buff_pos = std::data(image_memory); + + for (auto i : range(extent.height)) row_pointers[i] = &buff_pos[row_bytes * i]; + + png_read_image(png_ptr, std::bit_cast(std::data(row_pointers))); + png_read_end(png_ptr, info_ptr); + + png_destroy_info_struct(png_ptr, &info_ptr); + png_destroy_read_struct(&png_ptr, nullptr, nullptr); + + auto image_data = image::Image::ImageData { + .extent = std::move(extent), + .channel_count = get_format_channel_count(format), + .bytes_per_channel = getSizeof(format), + .layers = 1u, + .faces = 1u, + .mip_levels = 1u, + .format = format, + .data = std::move(image_memory) + }; + + return Image { std::move(image_data) }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + auto save_png(const image::Image&, const std::filesystem::path&) noexcept -> std::expected { + assert(false, "Not implemented yet !"); + return {}; + } + + ///////////////////////////////////// + ///////////////////////////////////// + auto save_png(const image::Image& image) noexcept -> std::expected { + auto output = byte_dyn_array {}; + + auto write_param = png::WriteParam { output }; + + auto png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + if (!png_ptr) + return std::unexpected(Error { .reason = Reason::FAILED_TO_PARSE, + .str_error = "[libpng] Failed to init (png_create_write_struct)" }); + + auto info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_write_struct(&png_ptr, nullptr); + return std::unexpected(Error { .reason = Reason::FAILED_TO_PARSE, + .str_error = "[libpng] Failed to init (png_create_info_struct)" }); + } + + if (setjmp(png_jmpbuf(png_ptr))) { + png_destroy_info_struct(png_ptr, &info_ptr); + png_destroy_write_struct(&png_ptr, nullptr); + return std::unexpected(Error { .reason = Reason::FAILED_TO_PARSE, + .str_error = "[libpng] Unkown error during png creation" }); + } + + png_set_write_fn(png_ptr, &write_param, png::write_func, nullptr); + + const auto& data = image.image_data(); + + png_set_IHDR(png_ptr, + info_ptr, + data.extent.width, + data.extent.height, + 8, + PNG_COLOR_TYPE_RGB_ALPHA, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + png_write_info(png_ptr, info_ptr); + + auto rows = dyn_array { data.extent.height, nullptr }; + for (auto i : range(data.extent.height)) + rows[i] = const_cast< + byte*>(&data.data[i * data.extent.width * data.channel_count * data.bytes_per_channel]); // TODO Fix + // this shit + + png_set_rows(png_ptr, info_ptr, std::bit_cast(std::data(rows))); + png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, nullptr); + png_write_end(png_ptr, info_ptr); + + png_destroy_info_struct(png_ptr, &info_ptr); + png_destroy_write_struct(&png_ptr, nullptr); + + return output; + ; + } +} // namespace stormkit::image::details diff --git a/src/image/ppm.mpp b/src/image/ppm.cppm similarity index 72% rename from src/image/ppm.mpp rename to src/image/ppm.cppm index e884429b1..d0372e64c 100644 --- a/src/image/ppm.mpp +++ b/src/image/ppm.cppm @@ -1,99 +1,90 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -export module stormkit.image:ppm; - -import std; - -import stormkit.core; -import stormkit.image; - -export namespace stormkit::image::details { - [[nodiscard]] - auto load_ppm(std::span data) noexcept - -> std::expected; - - [[nodiscard]] - auto save_ppm(const image::Image& image, - image::Image::CodecArgs args, - const std::filesystem::path& filepath) noexcept - -> std::expected; - - [[nodiscard]] - auto save_ppm(const image::Image& image, image::Image::CodecArgs args) noexcept - -> std::expected, image::Image::Error>; -} // namespace stormkit::image::details - -using namespace std::literals; - -namespace stormkit::image::details { - template - using Unexpected = std::unexpected; - using Error = image::Image::Error; - using Reason = image::Image::Error::Reason; - using Format = image::Image::Format; - - ///////////////////////////////////// - ///////////////////////////////////// - auto load_ppm(std::span) noexcept - -> std::expected { - assert(false, "Not implemented yet !"); - return {}; - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto save_ppm(const image::Image& image, - image::Image::CodecArgs args, - const std::filesystem::path& filepath) noexcept - -> std::expected { - return save_ppm(image, args) - .and_then([&filepath](auto&& val) noexcept { - return io::write(filepath, val).transform_error([](auto&&) static noexcept { - return Error { .reason = Error::Reason::FAILED_TO_SAVE, .str_error = "" }; - }); - }) - .transform(monadic::discard()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto save_ppm(const image::Image& image, image::Image::CodecArgs args) noexcept - -> std::expected, image::Image::Error> { - const auto output_image = image.convert_to(Format::RGB8_UNORM); - const auto& data = output_image.image_data(); - - auto output = std::vector {}; - if (args == image::Image::CodecArgs::ASCII) { - auto result = std::format("P3\n{}\n{}\n255\n"sv, data.extent.width, data.extent.height); - - const auto& extent = output_image.extent(); - for (auto [i, j] : multi_range(extent.height, extent.width)) { - const auto pixel = output_image.pixel(i * output_image.extent().width + j); - - result += std::format("{} {} {}\n"sv, - as(pixel[0]), - as(pixel[1]), - as(pixel[2])); - - if (j == extent.width) result += '\n'; - } - - output.reserve(std::size(result)); - std::ranges::copy(as_bytes(result), std::back_inserter(output)); - } else if (args == image::Image::CodecArgs::BINARY) { - auto header = std::format("P3\n{}\n{}\n255\n"sv, data.extent.width, data.extent.height); - output.reserve(std::size(output) + std::size(output_image)); - - std::ranges::copy(as_bytes(header), std::back_inserter(output)); - std::ranges::copy(output_image, std::back_inserter(output)); - } - - return output; - } -} // namespace stormkit::image::details +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +export module stormkit.image:ppm; + +import std; + +import stormkit.core; +import stormkit.image; + +export namespace stormkit::image::details { + [[nodiscard]] + auto load_ppm(byte_view<> data) noexcept -> std::expected; + + [[nodiscard]] + auto save_ppm(const image::Image& image, image::Image::CodecArgs args, const std::filesystem::path& filepath) noexcept + -> std::expected; + + [[nodiscard]] + auto save_ppm(const image::Image& image, image::Image::CodecArgs args) noexcept + -> std::expected; +} // namespace stormkit::image::details + +using namespace std::literals; + +namespace stormkit::image::details { + template + using Unexpected = std::unexpected; + using Error = image::Image::Error; + using Reason = image::Image::Error::Reason; + using Format = image::Image::Format; + + ///////////////////////////////////// + ///////////////////////////////////// + auto load_ppm(byte_view<>) noexcept -> std::expected { + assert(false, "Not implemented yet !"); + return {}; + } + + ///////////////////////////////////// + ///////////////////////////////////// + auto save_ppm(const image::Image& image, image::Image::CodecArgs args, const std::filesystem::path& filepath) noexcept + -> std::expected { + return save_ppm(image, args) + .and_then([&filepath](auto&& val) noexcept { + return io::write(filepath, val).transform_error([](auto&&) static noexcept { + return Error { .reason = Error::Reason::FAILED_TO_SAVE, .str_error = "" }; + }); + }) + .transform(monadic::discard()); + } + + ///////////////////////////////////// + ///////////////////////////////////// + auto save_ppm(const image::Image& image, image::Image::CodecArgs args) noexcept + -> std::expected { + const auto output_image = image.convert_to(Format::RGB8_UNORM); + const auto& data = output_image.image_data(); + + auto output = byte_dyn_array {}; + if (args == image::Image::CodecArgs::ASCII) { + auto result = std::format("P3\n{}\n{}\n255\n"sv, data.extent.width, data.extent.height); + + const auto& extent = output_image.extent(); + for (auto [i, j] : multi_range(extent.height, extent.width)) { + const auto pixel = output_image.pixel(i * output_image.extent().width + j); + + result += std::format("{} {} {}\n"sv, as(pixel[0]), as(pixel[1]), as(pixel[2])); + + if (j == extent.width) result += '\n'; + } + + output.reserve(std::size(result)); + std::ranges::copy(as_bytes(result), std::back_inserter(output)); + } else if (args == image::Image::CodecArgs::BINARY) { + auto header = std::format("P3\n{}\n{}\n255\n"sv, data.extent.width, data.extent.height); + output.reserve(std::size(output) + std::size(output_image)); + + std::ranges::copy(as_bytes(header), std::back_inserter(output)); + std::ranges::copy(output_image, std::back_inserter(output)); + } + + return output; + } +} // namespace stormkit::image::details diff --git a/src/image/qoi.mpp b/src/image/qoi.cppm similarity index 68% rename from src/image/qoi.mpp rename to src/image/qoi.cppm index e6036affa..8508dce25 100644 --- a/src/image/qoi.mpp +++ b/src/image/qoi.cppm @@ -1,217 +1,209 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -export module stormkit.image:qoi; - -import std; - -import frozen; - -import stormkit.core; -import stormkit.image; - -export namespace stormkit::image::details { - [[nodiscard]] - auto load_qoi(std::span data) noexcept - -> std::expected; - - [[nodiscard]] - auto save_qoi(const image::Image& image, const std::filesystem::path& filepath) noexcept - -> std::expected; - - [[nodiscard]] - auto save_qoi(const image::Image& image) noexcept - -> std::expected, image::Image::Error>; -} // namespace stormkit::image::details - -using namespace std::literals; - -namespace stormkit::image::details { - template - using Unexpected = std::unexpected; - using Error = image::Image::Error; - using Reason = image::Image::Error::Reason; - - struct QOIHeader { - std::array magic; - u32 width; - u32 height; - u8 channels; - u8 colorspace; - }; - - namespace { - constexpr auto SIZE_OF_HEADER = 14; - - constexpr auto CHANNELS_TO_FORMAT = frozen:: - make_unordered_map>({ - { 3, std::array { image::Image::Format::SRGB8, image::Image::Format::RGB8_UNORM } }, - { 4, - std::array { image::Image::Format::SRGBA8, image::Image::Format::RGBA8_UNORM } } - }); - - constexpr auto END_OF_FILE = into_bytes({ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }); - - constexpr auto PIXEL_CACHE_SIZE = 64u; - } // namespace - - enum class QOI_OPERATION : u8 { - RGB = 0b11111110, - RGBA = 0b11111111, - INDEX = 0b00000000, - DIFF = 0b01000000, - LUMA = 0b10000000, - RUN = 0b11000000, - }; - - union Pixel { - struct { - u8 r = 0; - u8 g = 0; - u8 b = 0; - u8 a = 0; - } rgba; - - std::array data; - }; - - ///////////////////////////////////// - ///////////////////////////////////// - constexpr auto indexHash(const Pixel& pixel) noexcept { - return (pixel.rgba.r * 3u + pixel.rgba.g * 5u + pixel.rgba.b * 7u + pixel.rgba.a * 11u) - % PIXEL_CACHE_SIZE; - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto load_qoi(std::span data) noexcept - -> std::expected { - const auto raw_header = std::span { std::data(data), SIZE_OF_HEADER }; - const auto* header = std::bit_cast(std::data(raw_header)); - - const auto extent = math::Extent3 { .width = byte_swap(header->width), - .height = byte_swap(header->height) }; - const auto channels = header->channels; - const auto format = CHANNELS_TO_FORMAT.at(header->channels)[header->colorspace]; - - auto pixel_cache = std::array {}; - - const auto chunks = std::span { std::bit_cast(std::data(data)) + SIZE_OF_HEADER, - std::size(data) - SIZE_OF_HEADER }; - - const auto output_size = extent.width * extent.height * channels; - - auto output = std::vector {}; - output.reserve(output_size); - - auto previous_pixel = Pixel { .rgba = { .a = 255 } }; - - auto run = 0; - - const auto diff = 4 - channels; - auto it = std::ranges::begin(chunks); - - const auto chunks_size = output_size - std::size(END_OF_FILE); - for (auto _ : range(output_size, channels)) { - const auto tag = *it; - - const auto position = as(std::distance(std::ranges::begin(chunks), it)); - - if (run > 0) --run; - else if (std::memcmp(&*it, std::data(END_OF_FILE), std::size(END_OF_FILE)) == 0) - [[unlikely]] { - it = std::ranges::cend(chunks); - } else if (position < chunks_size) { - ++it; - if (static_cast(tag) == QOI_OPERATION::RGB) { - previous_pixel.rgba.r = *it; - previous_pixel.rgba.g = *(it + 1); - previous_pixel.rgba.b = *(it + 2); - - it += 3; - } else if (static_cast(tag) == QOI_OPERATION::RGBA) { - previous_pixel.rgba.r = *it; - previous_pixel.rgba.g = *(it + 1); - previous_pixel.rgba.b = *(it + 2); - previous_pixel.rgba.a = *(it + 3); - - it += 4; - } else { -#define CHECK(op) (tag & 0b11000000) == static_cast(op) - if (CHECK(QOI_OPERATION::INDEX)) { - const auto index = tag; - - previous_pixel = pixel_cache[index]; - } else if (CHECK(QOI_OPERATION::DIFF)) { - const auto r_diff = as(((tag >> 4) & 0x03) - 2); - const auto g_diff = as(((tag >> 2) & 0x03) - 2); - const auto b_diff = as((tag & 0x03) - 2); - - previous_pixel.rgba.r += r_diff; - previous_pixel.rgba.g += g_diff; - previous_pixel.rgba.b += b_diff; - - } else if (CHECK(QOI_OPERATION::LUMA)) { - const auto g_diff = (tag & 0x3f) - 32; - - const auto current_r = ((*it) >> 4) & 0x0f; - const auto current_b = (*it) & 0x0f; - - previous_pixel.rgba.r += as(g_diff - 8 + current_r); - previous_pixel.rgba.g += as(g_diff); - previous_pixel.rgba.b += as(g_diff - 8 + current_b); - - ++it; - } else if (CHECK(QOI_OPERATION::RUN)) { - run = (tag & 0x3f); - } -#undef CHECK - } - - auto& cached = pixel_cache[indexHash(previous_pixel)]; - cached = previous_pixel; - } - - std::ranges::transform(std::begin(previous_pixel.data), - std::end(previous_pixel.data) - diff, - std::back_inserter(output), - monadic::as()); - } - - auto image_data = image::Image::ImageData { - .extent = extent, - .channel_count = channels, - .bytes_per_channel = getSizeof(format), - .layers = 1u, - .faces = 1u, - .mip_levels = 1u, - .format = format, - .data = std::move(output) - - }; - - return image::Image { std::move(image_data) }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto save_qoi(const image::Image&, const std::filesystem::path&) noexcept - -> std::expected { - assert(false, "Not implemented yet !"); - return {}; - } - - ///////////////////////////////////// - ///////////////////////////////////// - [[nodiscard]] - auto save_qoi(const image::Image&) noexcept - -> std::expected, image::Image::Error> { - assert(false, "Not implemented yet !"); - return {}; - } -} // namespace stormkit::image::details +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +export module stormkit.image:qoi; + +import std; + +import frozen; + +import stormkit.core; +import stormkit.image; + +export namespace stormkit::image::details { + [[nodiscard]] + auto load_qoi(byte_view<> data) noexcept -> std::expected; + + [[nodiscard]] + auto save_qoi(const image::Image& image, const std::filesystem::path& filepath) noexcept + -> std::expected; + + [[nodiscard]] + auto save_qoi(const image::Image& image) noexcept -> std::expected; +} // namespace stormkit::image::details + +using namespace std::literals; + +namespace stdr = std::ranges; + +namespace stormkit::image::details { + template + using Unexpected = std::unexpected; + using Error = image::Image::Error; + using Reason = image::Image::Error::Reason; + + struct QOIHeader { + array magic; + u32 width; + u32 height; + u8 channels; + u8 colorspace; + }; + + namespace { + constexpr auto SIZE_OF_HEADER = 14; + + constexpr auto CHANNELS_TO_FORMAT = frozen::make_unordered_map>({ + { 3, array { image::Image::Format::SRGB8, image::Image::Format::RGB8_UNORM } }, + { 4, array { image::Image::Format::SRGBA8, image::Image::Format::RGBA8_UNORM } } + }); + + constexpr auto END_OF_FILE = into_bytes({ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }); + + constexpr auto PIXEL_CACHE_SIZE = 64u; + } // namespace + + enum class QOI_OPERATION : u8 { + RGB = 0b11111110, + RGBA = 0b11111111, + INDEX = 0b00000000, + DIFF = 0b01000000, + LUMA = 0b10000000, + RUN = 0b11000000, + }; + + union Pixel { + struct { + u8 r = 0; + u8 g = 0; + u8 b = 0; + u8 a = 0; + } rgba; + + array data; + }; + + ///////////////////////////////////// + ///////////////////////////////////// + constexpr auto indexHash(const Pixel& pixel) noexcept { + return (pixel.rgba.r * 3u + pixel.rgba.g * 5u + pixel.rgba.b * 7u + pixel.rgba.a * 11u) % PIXEL_CACHE_SIZE; + } + + ///////////////////////////////////// + ///////////////////////////////////// + auto load_qoi(byte_view<> data) noexcept -> std::expected { + const auto raw_header = data.subspan(SIZE_OF_HEADER); + const auto* header = std::bit_cast(stdr::data(raw_header)); + + const auto extent = math::uextent3 { .width = byte_swap(header->width), .height = byte_swap(header->height) }; + const auto channels = header->channels; + const auto format = CHANNELS_TO_FORMAT.at(header->channels)[header->colorspace]; + + auto pixel_cache = array {}; + + const auto chunks = array_view { std::bit_cast(stdr::data(data)) + SIZE_OF_HEADER, + stdr::size(data) - SIZE_OF_HEADER }; + + const auto output_size = extent.width * extent.height * channels; + + auto output = byte_dyn_array {}; + output.reserve(output_size); + + auto previous_pixel = Pixel { .rgba = { .a = 255 } }; + + auto run = 0; + + const auto diff = 4 - channels; + auto it = stdr::begin(chunks); + + const auto chunks_size = output_size - stdr::size(END_OF_FILE); + for (auto _ : range(output_size, channels)) { + const auto tag = *it; + + const auto position = as(std::distance(stdr::begin(chunks), it)); + + if (run > 0) --run; + else if (std::memcmp(&*it, std::data(END_OF_FILE), stdr::size(END_OF_FILE)) == 0) [[unlikely]] { + it = stdr::cend(chunks); + } else if (position < chunks_size) { + ++it; + if (static_cast(tag) == QOI_OPERATION::RGB) { + previous_pixel.rgba.r = *it; + previous_pixel.rgba.g = *(it + 1); + previous_pixel.rgba.b = *(it + 2); + + it += 3; + } else if (static_cast(tag) == QOI_OPERATION::RGBA) { + previous_pixel.rgba.r = *it; + previous_pixel.rgba.g = *(it + 1); + previous_pixel.rgba.b = *(it + 2); + previous_pixel.rgba.a = *(it + 3); + + it += 4; + } else { +#define CHECK(op) (tag & 0b11000000) == static_cast(op) + if (CHECK(QOI_OPERATION::INDEX)) { + const auto index = tag; + + previous_pixel = pixel_cache[index]; + } else if (CHECK(QOI_OPERATION::DIFF)) { + const auto r_diff = as(((tag >> 4) & 0x03) - 2); + const auto g_diff = as(((tag >> 2) & 0x03) - 2); + const auto b_diff = as((tag & 0x03) - 2); + + previous_pixel.rgba.r += r_diff; + previous_pixel.rgba.g += g_diff; + previous_pixel.rgba.b += b_diff; + + } else if (CHECK(QOI_OPERATION::LUMA)) { + const auto g_diff = (tag & 0x3f) - 32; + + const auto current_r = ((*it) >> 4) & 0x0f; + const auto current_b = (*it) & 0x0f; + + previous_pixel.rgba.r += as(g_diff - 8 + current_r); + previous_pixel.rgba.g += as(g_diff); + previous_pixel.rgba.b += as(g_diff - 8 + current_b); + + ++it; + } else if (CHECK(QOI_OPERATION::RUN)) { + run = (tag & 0x3f); + } +#undef CHECK + } + + auto& cached = pixel_cache[indexHash(previous_pixel)]; + cached = previous_pixel; + } + + stdr::transform(stdr::begin(previous_pixel.data), + stdr::end(previous_pixel.data) - diff, + std::back_inserter(output), + monadic::as()); + } + + auto image_data = image::Image::ImageData { + .extent = extent, + .channel_count = channels, + .bytes_per_channel = getSizeof(format), + .layers = 1u, + .faces = 1u, + .mip_levels = 1u, + .format = format, + .data = std::move(output) + + }; + + return image::Image { std::move(image_data) }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + auto save_qoi(const image::Image&, const std::filesystem::path&) noexcept -> std::expected { + assert(false, "Not implemented yet !"); + return {}; + } + + ///////////////////////////////////// + ///////////////////////////////////// + [[nodiscard]] + auto save_qoi(const image::Image&) noexcept -> std::expected { + assert(false, "Not implemented yet !"); + return {}; + } +} // namespace stormkit::image::details diff --git a/src/image/tga.mpp b/src/image/tga.cppm similarity index 70% rename from src/image/tga.mpp rename to src/image/tga.cppm index 6c94dbc33..3835a23b0 100644 --- a/src/image/tga.mpp +++ b/src/image/tga.cppm @@ -1,60 +1,55 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -export module stormkit.image:tga; - -import std; - -import stormkit.core; - -import stormkit.image; - -export namespace stormkit::image::details { - [[nodiscard]] - auto load_tga(std::span data) noexcept - -> std::expected; - - [[nodiscard]] - auto save_tga(const image::Image& image, const std::filesystem::path& filepath) noexcept - -> std::expected; - - [[nodiscard]] - auto save_tga(const image::Image& image) noexcept - -> std::expected, image::Image::Error>; -} // namespace stormkit::image::details - -namespace stormkit::image::details { - template - using Unexpected = std::unexpected; - using Error = image::Image::Error; - using Reason = image::Image::Error::Reason; - - ///////////////////////////////////// - ///////////////////////////////////// - auto load_tga(std::span) noexcept - -> std::expected { - assert(false, "Not implemented yet !"); - return {}; - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto save_tga(const image::Image&, const std::filesystem::path&) noexcept - -> std::expected { - assert(false, "Not implemented yet !"); - return {}; - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto save_tga(const image::Image&) noexcept - -> std::expected, image::Image::Error> { - assert(false, "Not implemented yet !"); - return {}; - } -} // namespace stormkit::image::details +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +export module stormkit.image:tga; + +import std; + +import stormkit.core; + +import stormkit.image; + +export namespace stormkit::image::details { + [[nodiscard]] + auto load_tga(byte_view<> data) noexcept -> std::expected; + + [[nodiscard]] + auto save_tga(const image::Image& image, const std::filesystem::path& filepath) noexcept + -> std::expected; + + [[nodiscard]] + auto save_tga(const image::Image& image) noexcept -> std::expected; +} // namespace stormkit::image::details + +namespace stormkit::image::details { + template + using Unexpected = std::unexpected; + using Error = image::Image::Error; + using Reason = image::Image::Error::Reason; + + ///////////////////////////////////// + ///////////////////////////////////// + auto load_tga(byte_view<>) noexcept -> std::expected { + assert(false, "Not implemented yet !"); + return {}; + } + + ///////////////////////////////////// + ///////////////////////////////////// + auto save_tga(const image::Image&, const std::filesystem::path&) noexcept -> std::expected { + assert(false, "Not implemented yet !"); + return {}; + } + + ///////////////////////////////////// + ///////////////////////////////////// + auto save_tga(const image::Image&) noexcept -> std::expected { + assert(false, "Not implemented yet !"); + return {}; + } +} // namespace stormkit::image::details diff --git a/src/log/console_logger.cpp b/src/log/console_logger.cpp index 17cace9bf..8ee24b74b 100644 --- a/src/log/console_logger.cpp +++ b/src/log/console_logger.cpp @@ -26,7 +26,10 @@ namespace stormkit::log { { Severity::FATAL, ConsoleStyle { .fg = ConsoleColor::RED, .modifiers = StyleModifier::INVERSE } }, { Severity::DEBUG, ConsoleStyle { .fg = ConsoleColor::CYAN, .modifiers = StyleModifier::INVERSE } }, }); - } + + constexpr auto format_string_with_module = "{}[{}, {:%S}, {}]{} {}"sv; + constexpr auto format_string = "{}[{}, {:%S}]{} {}"sv; + } // namespace //////////////////////////////////////// //////////////////////////////////////// @@ -41,29 +44,15 @@ namespace stormkit::log { //////////////////////////////////////// //////////////////////////////////////// - auto ConsoleLogger::write(Severity severity, const Module& module, CZString string) noexcept -> void { + auto ConsoleLogger::write(Severity severity, const Module& module, std::string_view str) noexcept -> void { const auto now = LogClock::now(); const auto time = std::chrono::duration_cast(now - m_start_time); const auto is_error = severity == Severity::ERROR or severity == Severity::FATAL; const auto out = (is_error) ? get_stderr() : get_stdout(); - const auto header = [&severity, &module, &time] noexcept { - if (std::empty(module.name)) return std::format("[{}, {:%S}]", as_string(severity), time); - else - return std::format("[{}, {:%S}, {}]", as_string(severity), time, module.name); - }(); - - const auto prefixed_string = [&header, string] noexcept { - const auto header_length = stdr::size(header) + 1; - - auto prefix = std::string {}; - prefix.resize(header_length + 1, ' '); - prefix.front() = '\n'; - return replace(string, "\n", prefix); - }(); - - const auto styled_header = std::format("{} ", StyleMap.at(severity) | header); - std::println(out, "{}{}", styled_header, prefixed_string); + if (stdr::empty(module.name)) std::println(out, format_string, StyleMap.at(severity), severity, time, ecma48::RESET, str); + else + std::println(out, format_string_with_module, StyleMap.at(severity), severity, time, module.name, ecma48::RESET, str); } //////////////////////////////////////// diff --git a/src/log/file_logger.cpp b/src/log/file_logger.cpp index 3ea007966..a6eae0864 100644 --- a/src/log/file_logger.cpp +++ b/src/log/file_logger.cpp @@ -47,7 +47,7 @@ namespace stormkit::log { //////////////////////////////////////// //////////////////////////////////////// - auto FileLogger::write(Severity severity, const Module& m, CZString string) noexcept -> void { + auto FileLogger::write(Severity severity, const Module& m, std::string_view str) noexcept -> void { const auto now = LogClock::now(); const auto time = std::chrono::duration_cast(now - m_start_time).count(); @@ -63,10 +63,11 @@ namespace stormkit::log { static constexpr auto LOG_LINE = "[{}, {}] {}\n"sv; static constexpr auto LOG_LINE_MODULE = "[{}, {}, {}] {}\n"sv; - auto final_string = std::string {}; - if (std::empty(m.name)) final_string = std::format(LOG_LINE, to_string(severity), time, string); + auto final_string = string {}; + const auto severity_str = replace(as_string(severity), "Severity::", ""); + if (std::empty(m.name)) final_string = std::format(LOG_LINE, severity_str, time, str); else - final_string = std::format(LOG_LINE_MODULE, to_string(severity), time, m.name, string); + final_string = std::format(LOG_LINE_MODULE, severity_str, time, m.name, str); m_streams.at(filepath.string()) << final_string << std::flush; } diff --git a/src/log/logger.cpp b/src/log/logger.cpp index b77785771..0becbe889 100644 --- a/src/log/logger.cpp +++ b/src/log/logger.cpp @@ -12,23 +12,32 @@ import std; import stormkit.core; +namespace stdr = std::ranges; + namespace stormkit::log { namespace { -#ifdef STORMKIT_BUILD_DEBUG - constexpr auto DEFAULT_SEVERITY = Severity::INFO - | Severity::DEBUG - | Severity::ERROR - | Severity::FATAL - | Severity::WARNING; -#else - constexpr auto DEFAULT_SEVERITY = Severity::INFO | Severity::ERROR | Severity::FATAL; -#endif constinit Logger* logger = nullptr; + + constinit auto debug_enabled = false; + + auto make_default_severity() noexcept { + auto severity = Severity::INFO | Severity::ERROR | Severity::FATAL | Severity::WARNING; + + if (debug_enabled) severity |= Severity::DEBUG; + + return severity; + } } // namespace ///////////////////////////////////// ///////////////////////////////////// - Logger::Logger(LogClock::time_point start_time) noexcept : Logger { std::move(start_time), DEFAULT_SEVERITY } { + auto parse_args(array_view args) noexcept -> void { + debug_enabled = stdr::find_if(args, [](auto&& v) { return v == "--debug" or v == "-d"; }) != stdr::cend(args); + } + + ///////////////////////////////////// + ///////////////////////////////////// + Logger::Logger(LogClock::time_point start_time) noexcept : Logger { std::move(start_time), make_default_severity() } { EXPECTS(not logger); logger = this; diff --git a/src/lua/core.cpp b/src/lua/core.cpp new file mode 100644 index 000000000..b7a0ef415 --- /dev/null +++ b/src/lua/core.cpp @@ -0,0 +1,25 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +module stormkit.lua; + +import std; + +import stormkit.core; + +namespace stormkit::lua::core { + extern auto bind_math(sol::state& global_state) noexcept -> void; + extern auto bind_color(sol::state& global_state) noexcept -> void; + + //////////////////////////////////////// + //////////////////////////////////////// + auto init_lua(sol::state& global_state) noexcept -> void { + bind_color(global_state); + bind_math(global_state); + } +} // namespace stormkit::lua::core diff --git a/src/lua/core.cppm b/src/lua/core.cppm new file mode 100644 index 000000000..9b0d4fb06 --- /dev/null +++ b/src/lua/core.cppm @@ -0,0 +1,17 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +module stormkit.lua:core; + +import std; + +import stormkit.core; + +export namespace stormkit::lua::core { + auto init_lua(sol::state& global_state) noexcept -> void; +} // namespace stormkit::lua::core diff --git a/src/lua/core/color.cpp b/src/lua/core/color.cpp new file mode 100644 index 000000000..c6bf69ecb --- /dev/null +++ b/src/lua/core/color.cpp @@ -0,0 +1,105 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +module stormkit.lua; + +import std; + +import stormkit.core; + +namespace stormkit::lua::core { + namespace { + //////////////////////////////////////// + //////////////////////////////////////// + template + auto _bind_color(string_view name, auto& parent, auto... values) { + auto metatable = parent.template new_usertype(name, sol::constructors {}); + metatable[sol::meta_function::to_string] = &stormkit::to_string; + metatable[sol::meta_function::equal_to] = &T::operator==; + + metatable["component_count"] = sol::var(std::cref(T::COMPONENTS_COUNT)); + metatable["layout"] = sol::var(std::cref(T::LAYOUT)); + + ( + [metatable, &values] mutable { + auto&& [k, v] = std::forward(values); + metatable[k] = v; + }(), + ...); + + metatable["BLACK"] = sol::var(stormkit::to_layout(stormkit::colors::BLACK.c)); + metatable["GRAY"] = sol::var(stormkit::to_layout(stormkit::colors::GRAY.c)); + metatable["SILVER"] = sol::var(stormkit::to_layout(stormkit::colors::SILVER.c)); + metatable["WHITE"] = sol::var(stormkit::to_layout(stormkit::colors::WHITE.c)); + metatable["MAROON"] = sol::var(stormkit::to_layout(stormkit::colors::MAROON.c)); + metatable["RED"] = sol::var(stormkit::to_layout(stormkit::colors::RED.c)); + metatable["OLIVE"] = sol::var(stormkit::to_layout(stormkit::colors::OLIVE.c)); + metatable["YELLOW"] = sol::var(stormkit::to_layout(stormkit::colors::YELLOW.c)); + metatable["GREEN"] = sol::var(stormkit::to_layout(stormkit::colors::GREEN.c)); + metatable["LIME"] = sol::var(stormkit::to_layout(stormkit::colors::LIME.c)); + metatable["TEAL"] = sol::var(stormkit::to_layout(stormkit::colors::TEAL.c)); + metatable["AQUA"] = sol::var(stormkit::to_layout(stormkit::colors::AQUA.c)); + metatable["NAVY"] = sol::var(stormkit::to_layout(stormkit::colors::NAVY.c)); + metatable["BLUE"] = sol::var(stormkit::to_layout(stormkit::colors::PURPLE.c)); + metatable["PURPLE"] = sol::var(stormkit::to_layout(stormkit::colors::PURPLE.c)); + metatable["FUSCHIA"] = sol::var(stormkit::to_layout(stormkit::colors::FUSCHIA.c)); + metatable["TRANSPARENT"] = sol::var(stormkit::to_layout< + T::LAYOUT>(stormkit::colors::TRANSPARENT.c)); + } + } // namespace + + //////////////////////////////////////// + //////////////////////////////////////// + auto bind_color(sol::state& global_state) noexcept -> void { + global_state["color_layout"] = global_state.create_table_with( + sol::meta_function::to_string, + +[](ColorLayout layout) static noexcept { return to_string(layout); }, + "R", + ColorLayout::R, + "RG", + ColorLayout::RG, + "RGB", + ColorLayout::RGB, + "BGR", + ColorLayout::BGR, + "RGBA", + ColorLayout::RGBA, + "ARGB", + ColorLayout::ARGB, + "BGRA", + ColorLayout::BGRA, + "ABGR", + ColorLayout::ABGR); + + auto f32_metatable = global_state["fcolor"].get_or_create(); + _bind_color("rgb", + f32_metatable, + std::pair { "r", &fcolor_rgb::r }, + std::pair { "g", &fcolor_rgb::g }, + std::pair { "b", &fcolor_rgb::b }); + _bind_color("rgba", + f32_metatable, + std::pair { "r", &fcolor_rgba::r }, + std::pair { "g", &fcolor_rgba::g }, + std::pair { "b", &fcolor_rgba::b }, + std::pair { "a", &fcolor_rgba::a }); + + auto u8_metatable = global_state["ucolor"].get_or_create(); + _bind_color("rgb", + u8_metatable, + std::pair { "r", &ucolor_rgb::r }, + std::pair { "g", &ucolor_rgb::g }, + std::pair { "b", &ucolor_rgb::b }); + _bind_color("rgba", + u8_metatable, + std::pair { "r", &ucolor_rgba::r }, + std::pair { "g", &ucolor_rgba::g }, + std::pair { "b", &ucolor_rgba::b }, + std::pair { "a", &ucolor_rgba::a }); + } +} // namespace stormkit::lua::core diff --git a/src/wsi/win32/utils.mpp b/src/lua/core/color.cppclear similarity index 100% rename from src/wsi/win32/utils.mpp rename to src/lua/core/color.cppclear diff --git a/src/lua/core/math.cpp b/src/lua/core/math.cpp new file mode 100644 index 000000000..691be3f88 --- /dev/null +++ b/src/lua/core/math.cpp @@ -0,0 +1,511 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +module stormkit.lua; + +import std; + +import stormkit.core; + +namespace stormkit::lua::core { + namespace { + //////////////////////////////////////// + //////////////////////////////////////// + template + auto _bind_rect(auto& parent) { + ( + [&] noexcept { + using Type = typename decltype(Rects)::Type; + using Rect = math::rect; + + parent.template new_usertype( + string { Rects.name }, + sol::constructors {}, + "position", + &Rect::position, + "extent", + &Rect::extent, + "to_bounding_rect", + +[](const Rect* rect) noexcept -> math::bounding_rect { return to_bounding_rect(*rect); }); + }(), + ...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto _bind_bounding_rect(auto& parent) { + ( + [&] noexcept { + using Type = typename decltype(Rects)::Type; + using Rect = math::bounding_rect; + + parent.template new_usertype( + string { Rects.name }, + sol::constructors {}, + "topleft", + &Rect::topleft, + "bottomright", + &Rect::bottomright, + "to_rect", + +[](const Rect* rect) noexcept -> math::rect { return to_rect(*rect); }); + }(), + ...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template typename T, typename U> + auto _bind_angle(string_view name, auto& parent) { + auto metatable = parent.template new_usertype>(name, sol::constructors(U)> {}); + metatable["value"] = sol::property( + +[](T* angle) static noexcept { return angle->get(); }, + +[](T* angle, U val) static noexcept { return angle->get() = val; }); + metatable[sol::meta_function::addition] = +[](T first, T second) static noexcept { return first + second; }; + metatable[sol::meta_function::subtraction] = +[](T first, T second) static noexcept { return first - second; }; + metatable[sol::meta_function::multiplication] = +[](T first, T second) static noexcept { + return first * second; + }; + metatable[sol::meta_function::division] = +[](T first, T second) static noexcept { return first / second; }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto _bind_extent(string_view name, auto& parent, auto... values) { + auto metatable = parent.template new_usertype(name, sol::constructors {}); + + metatable[sol::meta_function::to_string] = &math::to_string; + metatable[sol::meta_function::equal_to] = +[](const T& first, const T& second) static noexcept { + return first == second; + }; + + metatable["rank"] = sol::var(std::cref(T::RANK)); + + ( + [&metatable, &values] mutable { + auto&& [k, v] = std::forward(values); + metatable[k] = v; + }(), + ...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto _bind_vector(string_view name, auto& parent, auto... values) { + auto metatable = parent.template new_usertype(name, sol::constructors {}); + + metatable[sol::meta_function::to_string] = +[](const T& value) static noexcept { return to_string(value); }; + // metatable[sol::meta_function::equal_to] = +[](const T& first, const T& second) static noexcept { + // return first == second; + // }; + + ( + [&metatable, &values] mutable { + auto&& [k, v] = std::forward(values); + metatable[k] = v; + }(), + ...); + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + auto _bind_matrix(string_view name, auto& parent) { + auto metatable = parent.template new_usertype(name, sol::constructors {}); + + metatable[sol::meta_function::index] = +[](T* value, usize index) static noexcept { + return array_view { &((*value)[index, 0u]), T::EXTENTS[1] }; + }; + metatable[sol::meta_function::to_string] = +[](const T& value) static noexcept { return math::to_string(value); }; + + if constexpr (T::EXTENTS[0] == T::EXTENTS[1]) { + auto identity = parent["identity"].template get_or_create(); + identity[name] = T::identity(); + } + // metatable[sol::meta_function::equal_to] = +[](const T& first, const T& second) static noexcept { + // return first == second; + // }; + } + } // namespace + + //////////////////////////////////////// + //////////////////////////////////////// + auto bind_extent(sol::table& metatable) noexcept -> void { + _bind_extent("uextent2", + metatable, + std::pair { "width", &math::uextent2::width }, + std::pair { "height", &math::uextent2::height }); + _bind_extent("math::uextent3", + metatable, + std::pair { "width", &math::uextent3::width }, + std::pair { "height", &math::uextent3::height }, + std::pair { "depth", &math::uextent3::depth }); + _bind_extent("fextent2", + metatable, + std::pair { "width", &math::fextent2::width }, + std::pair { "height", &math::fextent2::height }); + _bind_extent("fextent3", + metatable, + std::pair { "width", &math::fextent3::width }, + std::pair { "height", &math::fextent3::height }, + std::pair { "depth", &math::fextent3::depth }); + _bind_extent("iextent2", + metatable, + std::pair { "width", &math::iextent2::width }, + std::pair { "height", &math::iextent2::height }); + _bind_extent("iextent3", + metatable, + std::pair { "width", &math::iextent3::width }, + std::pair { "height", &math::iextent3::height }, + std::pair { "depth", &math::iextent3::depth }); + } + + //////////////////////////////////////// + //////////////////////////////////////// + auto bind_linear_vector(sol::table& metatable) noexcept -> void { + _bind_vector("fvec2", + metatable, + std::pair { "x", &math::fvec2::x }, + std::pair { "y", &math::fvec2::y }); + _bind_vector("fvec3", + metatable, + std::pair { "x", &math::fvec3::x }, + std::pair { "y", &math::fvec3::y }, + std::pair { "z", &math::fvec3::z }); + _bind_vector("fvec4", + metatable, + std::pair { "x", &math::fvec4::x }, + std::pair { "y", &math::fvec4::y }, + std::pair { "z", &math::fvec4::z }, + std::pair { "w", &math::fvec4::w }); + _bind_vector("uvec2", + metatable, + std::pair { "x", &math::uvec2::x }, + std::pair { "y", &math::uvec2::y }); + _bind_vector("uvec3", + metatable, + std::pair { "x", &math::uvec3::x }, + std::pair { "y", &math::uvec3::y }, + std::pair { "z", &math::uvec3::z }); + _bind_vector("uvec4", + metatable, + std::pair { "x", &math::uvec4::x }, + std::pair { "y", &math::uvec4::y }, + std::pair { "z", &math::uvec4::z }, + std::pair { "w", &math::uvec4::w }); + _bind_vector("ivec2", + metatable, + std::pair { "x", &math::ivec2::x }, + std::pair { "y", &math::ivec2::y }); + _bind_vector("ivec3", + metatable, + std::pair { "x", &math::ivec3::x }, + std::pair { "y", &math::ivec3::y }, + std::pair { "z", &math::ivec3::z }); + _bind_vector("ivec4", + metatable, + std::pair { "x", &math::ivec4::x }, + std::pair { "y", &math::ivec4::y }, + std::pair { "z", &math::ivec4::z }, + std::pair { "w", &math::ivec4::w }); + + // [](const auto&... args) static noexcept { return math::add(args...); }); + + metatable["add"] = sol::overload(&math::add, + &math::add, + &math::add, + &math::add, + &math::add, + &math::add, + &math::add, + &math::add, + &math::add); + metatable["sub"] = sol::overload(&math::sub, + &math::sub, + &math::sub, + &math::sub, + &math::sub, + &math::sub, + &math::sub, + &math::sub, + &math::sub); + + metatable["mul"] = sol::overload(&math::mul, + &math::mul, + &math::mul, + &math::mul, + &math::mul, + &math::mul, + &math::mul, + &math::mul, + &math::mul); + metatable["div"] = sol::overload(&math::div, + &math::div, + &math::div, + &math::div, + &math::div, + &math::div, + &math::div, + &math::div, + &math::div); + + metatable["dot"] = sol::overload(&math::dot, + &math::dot, + &math::dot, + &math::dot, + &math::dot, + &math::dot, + &math::dot, + &math::dot, + &math::dot); + + metatable["cross"] = sol::overload( + +[](const math::fvec3& first, const math::fvec3& second) static noexcept { return math::cross(first, second); }, + +[](const math::uvec3& first, const math::uvec3& second) static noexcept { return math::cross(first, second); }, + +[](const math::ivec3& first, const math::ivec3& second) static noexcept { return math::cross(first, second); }); + + metatable["normalize"] = sol::overload(&math::normalize, + &math::normalize, + &math::normalize, + &math::normalize, + &math::normalize, + &math::normalize, + &math::normalize, + &math::normalize, + &math::normalize); + } + + //////////////////////////////////////// + //////////////////////////////////////// + auto bind_linear_matrix(sol::table& metatable) noexcept -> void { + _bind_matrix("fmat2", metatable); + _bind_matrix("fmat2x3", metatable); + _bind_matrix("fmat2x4", metatable); + _bind_matrix("fmat3", metatable); + _bind_matrix("fmat3x2", metatable); + _bind_matrix("fmat3x4", metatable); + _bind_matrix("fmat4", metatable); + _bind_matrix("fmat4x2", metatable); + _bind_matrix("fmat4x3", metatable); + _bind_matrix("umat2", metatable); + _bind_matrix("umat2x3", metatable); + _bind_matrix("umat2x4", metatable); + _bind_matrix("umat3", metatable); + _bind_matrix("umat3x2", metatable); + _bind_matrix("umat3x4", metatable); + _bind_matrix("umat4", metatable); + _bind_matrix("umat4x2", metatable); + _bind_matrix("umat4x3", metatable); + _bind_matrix("imat2", metatable); + _bind_matrix("imat2x3", metatable); + _bind_matrix("imat2x4", metatable); + _bind_matrix("imat3", metatable); + _bind_matrix("imat3x2", metatable); + _bind_matrix("imat3x4", metatable); + _bind_matrix("imat4", metatable); + _bind_matrix("imat4x2", metatable); + _bind_matrix("imat4x3", metatable); + metatable["determinant"] = sol::overload(&math::determinant, + &math::determinant, + &math::determinant, + &math::determinant, + &math::determinant, + &math::determinant, + &math::determinant, + &math::determinant, + &math::determinant); + metatable["transpose"] = sol::overload(&math::transpose, + &math::transpose, + &math::transpose, + &math::transpose, + &math::transpose, + &math::transpose, + &math::transpose, + &math::transpose, + &math::transpose); + metatable["inverse"] = sol::overload(&math::inverse, + &math::inverse, + &math::inverse, + &math::inverse, + &math::inverse, + &math::inverse, + &math::inverse, + &math::inverse, + &math::inverse); + + metatable["is_inversible"] = sol:: + overload(&math::is_inversible, + &math::is_inversible, + &math::is_inversible, + &math::is_inversible, + &math::is_inversible, + &math::is_inversible, + &math::is_inversible, + &math::is_inversible, + &math::is_inversible, + &math::is_inversible, + &math::is_inversible, + &math::is_inversible, + &math::is_inversible, + &math::is_inversible, + &math::is_inversible, + &math::is_inversible, + &math::is_inversible, + &math::is_inversible, + &math::is_inversible, + &math::is_inversible, + &math::is_inversible, + &math::is_inversible, + &math::is_inversible, + &math::is_inversible, + &math::is_inversible, + &math::is_inversible, + &math::is_inversible); + metatable["is_orthogonal"] = sol:: + overload(&math::is_orthogonal, + &math::is_orthogonal, + &math::is_orthogonal, + &math::is_orthogonal, + &math::is_orthogonal, + &math::is_orthogonal, + &math::is_orthogonal, + &math::is_orthogonal, + &math::is_orthogonal, + &math::is_orthogonal, + &math::is_orthogonal, + &math::is_orthogonal, + &math::is_orthogonal, + &math::is_orthogonal, + &math::is_orthogonal, + &math::is_orthogonal, + &math::is_orthogonal, + &math::is_orthogonal, + &math::is_orthogonal, + &math::is_orthogonal, + &math::is_orthogonal, + &math::is_orthogonal, + &math::is_orthogonal, + &math::is_orthogonal, + &math::is_orthogonal, + &math::is_orthogonal, + &math::is_orthogonal); + metatable["mul"] = sol::overload( + +[](const math::fmat2& a, typename math::fmat2::value_type b) static noexcept { return mul(a, b); }, + +[](const math::fmat2x3& a, typename math::fmat2x3::value_type b) static noexcept { return mul(a, b); }, + +[](const math::fmat2x4& a, typename math::fmat2x4::value_type b) static noexcept { return mul(a, b); }, + +[](const math::fmat3& a, typename math::fmat3::value_type b) static noexcept { return mul(a, b); }, + +[](const math::fmat3x2& a, typename math::fmat3x2::value_type b) static noexcept { return mul(a, b); }, + +[](const math::fmat3x4& a, typename math::fmat3x4::value_type b) static noexcept { return mul(a, b); }, + +[](const math::fmat4& a, typename math::fmat4::value_type b) static noexcept { return mul(a, b); }, + +[](const math::fmat4x2& a, typename math::fmat4x2::value_type b) static noexcept { return mul(a, b); }, + +[](const math::fmat4x3& a, typename math::fmat4x3::value_type b) static noexcept { return mul(a, b); }, + +[](const math::umat2& a, typename math::umat2::value_type b) static noexcept { return mul(a, b); }, + +[](const math::umat2x3& a, typename math::umat2x3::value_type b) static noexcept { return mul(a, b); }, + +[](const math::umat2x4& a, typename math::umat2x4::value_type b) static noexcept { return mul(a, b); }, + +[](const math::umat3& a, typename math::umat3::value_type b) static noexcept { return mul(a, b); }, + +[](const math::umat3x2& a, typename math::umat3x2::value_type b) static noexcept { return mul(a, b); }, + +[](const math::umat3x4& a, typename math::umat3x4::value_type b) static noexcept { return mul(a, b); }, + +[](const math::umat4& a, typename math::umat4::value_type b) static noexcept { return mul(a, b); }, + +[](const math::umat4x2& a, typename math::umat4x2::value_type b) static noexcept { return mul(a, b); }, + +[](const math::umat4x3& a, typename math::umat4x3::value_type b) static noexcept { return mul(a, b); }, + +[](const math::imat2& a, typename math::imat2::value_type b) static noexcept { return mul(a, b); }, + +[](const math::imat2x3& a, typename math::imat2x3::value_type b) static noexcept { return mul(a, b); }, + +[](const math::imat2x4& a, typename math::imat2x4::value_type b) static noexcept { return mul(a, b); }, + +[](const math::imat3& a, typename math::imat3::value_type b) static noexcept { return mul(a, b); }, + +[](const math::imat3x2& a, typename math::imat3x2::value_type b) static noexcept { return mul(a, b); }, + +[](const math::imat3x4& a, typename math::imat3x4::value_type b) static noexcept { return mul(a, b); }, + +[](const math::imat4& a, typename math::imat4::value_type b) static noexcept { return mul(a, b); }, + +[](const math::imat4x2& a, typename math::imat4x2::value_type b) static noexcept { return mul(a, b); }, + +[](const math::imat4x3& a, typename math::imat4x3::value_type b) static noexcept { return mul(a, b); }); + metatable["div"] = sol::overload( + +[](const math::fmat2& a, typename math::fmat2::value_type b) static noexcept { return div(a, b); }, + +[](const math::fmat2x3& a, typename math::fmat2x3::value_type b) static noexcept { return div(a, b); }, + +[](const math::fmat2x4& a, typename math::fmat2x4::value_type b) static noexcept { return div(a, b); }, + +[](const math::fmat3& a, typename math::fmat3::value_type b) static noexcept { return div(a, b); }, + +[](const math::fmat3x2& a, typename math::fmat3x2::value_type b) static noexcept { return div(a, b); }, + +[](const math::fmat3x4& a, typename math::fmat3x4::value_type b) static noexcept { return div(a, b); }, + +[](const math::fmat4& a, typename math::fmat4::value_type b) static noexcept { return div(a, b); }, + +[](const math::fmat4x2& a, typename math::fmat4x2::value_type b) static noexcept { return div(a, b); }, + +[](const math::fmat4x3& a, typename math::fmat4x3::value_type b) static noexcept { return div(a, b); }, + +[](const math::umat2& a, typename math::umat2::value_type b) static noexcept { return div(a, b); }, + +[](const math::umat2x3& a, typename math::umat2x3::value_type b) static noexcept { return div(a, b); }, + +[](const math::umat2x4& a, typename math::umat2x4::value_type b) static noexcept { return div(a, b); }, + +[](const math::umat3& a, typename math::umat3::value_type b) static noexcept { return div(a, b); }, + +[](const math::umat3x2& a, typename math::umat3x2::value_type b) static noexcept { return div(a, b); }, + +[](const math::umat3x4& a, typename math::umat3x4::value_type b) static noexcept { return div(a, b); }, + +[](const math::umat4& a, typename math::umat4::value_type b) static noexcept { return div(a, b); }, + +[](const math::umat4x2& a, typename math::umat4x2::value_type b) static noexcept { return div(a, b); }, + +[](const math::umat4x3& a, typename math::umat4x3::value_type b) static noexcept { return div(a, b); }, + +[](const math::imat2& a, typename math::imat2::value_type b) static noexcept { return div(a, b); }, + +[](const math::imat2x3& a, typename math::imat2x3::value_type b) static noexcept { return div(a, b); }, + +[](const math::imat2x4& a, typename math::imat2x4::value_type b) static noexcept { return div(a, b); }, + +[](const math::imat3& a, typename math::imat3::value_type b) static noexcept { return div(a, b); }, + +[](const math::imat3x2& a, typename math::imat3x2::value_type b) static noexcept { return div(a, b); }, + +[](const math::imat3x4& a, typename math::imat3x4::value_type b) static noexcept { return div(a, b); }, + +[](const math::imat4& a, typename math::imat4::value_type b) static noexcept { return div(a, b); }, + +[](const math::imat4x2& a, typename math::imat4x2::value_type b) static noexcept { return div(a, b); }, + +[](const math::imat4x3& a, typename math::imat4x3::value_type b) static noexcept { return div(a, b); }); + + metatable["translate"] = sol::overload(&math::matrix::translate, &math::matrix::translate); + metatable["scale"] = sol::overload(&math::matrix::scale, &math::matrix::scale, &math::matrix::scale); + metatable["rotate"] = &math::matrix::rotate; + metatable["orthographique"] = sol::overload( + +[](f32 left, f32 right, f32 bottom, f32 top, f32 near, f32 far) static noexcept { + return math::orthographique(left, right, bottom, top, near, far); + }, + +[](f32 left, f32 right, f32 bottom, f32 top) static noexcept { + return math::orthographique(left, right, bottom, top); + }); + metatable["perspective"] = &math::matrix::perspective; + metatable["look_at"] = &math::matrix::look_at; + } + + auto bind_linear(sol::table& parent) noexcept -> void { + auto angle = parent["angle"].get_or_create(); + + _bind_angle("euler", angle); + _bind_angle("radian", angle); + + angle["radians"] = sol::overload(&math::angle::radians); + + bind_linear_vector(parent); + bind_linear_matrix(parent); + } + + template + struct _Rect { + using Type = T; + static constexpr auto name = Name; + }; + + auto bind_geometry(sol::table& parent) noexcept -> void { + _bind_rect<_Rect {}, _Rect {}, _Rect {}>(parent); + _bind_bounding_rect<_Rect {}, + _Rect {}, + _Rect {}>(parent); + parent["AABB"] = sol::overload( + +[](const math::irect& rect1, const math::irect& rect2) static noexcept { return AABB(rect1, rect2); }, + +[](const math::ivec2& vec, const math::irect& rect) static noexcept { return AABB(vec, rect); }, + +[](const math::ivec2& vec, const math::ibounding_rect& rect) static noexcept { return AABB(vec, rect); }, + +[](const math::frect& rect1, const math::frect& rect2) static noexcept { return AABB(rect1, rect2); }, + +[](const math::fvec2& vec, const math::frect& rect) static noexcept { return AABB(vec, rect); }, + +[](const math::fvec2& vec, const math::fbounding_rect& rect) static noexcept { return AABB(vec, rect); }, + +[](const math::urect& rect1, const math::urect& rect2) static noexcept { return AABB(rect1, rect2); }, + +[](const math::uvec2& vec, const math::urect& rect) static noexcept { return AABB(vec, rect); }, + +[](const math::uvec2& vec, const math::ubounding_rect& rect) static noexcept { return AABB(vec, rect); }); + } + + auto bind_math(sol::state& global_state) noexcept -> void { + auto math_table = global_state["math"].get_or_create(); + bind_extent(math_table); + bind_linear(math_table); + bind_geometry(math_table); + } +} // namespace stormkit::lua::core diff --git a/src/lua/entities.cpp b/src/lua/entities.cpp new file mode 100644 index 000000000..d6231e053 --- /dev/null +++ b/src/lua/entities.cpp @@ -0,0 +1,108 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +module stormkit.lua; + +import std; + +import stormkit.core; +import stormkit.entities; + +namespace stdr = std::ranges; +namespace stdv = std::views; + +namespace stormkit::lua::entities { + using stormkit::entities::ComponentType; + using stormkit::entities::Entity; + using stormkit::entities::EntityManager; + using stormkit::entities::System; + + using stormkit::entities::lua::LuaComponent; + + //////////////////////////////////////// + //////////////////////////////////////// + auto bind_manager(sol::table& entities) noexcept -> void { + auto no_constructor = false; + + auto manager = [&entities, no_constructor]() { + if (no_constructor) return entities.new_usertype("manager", sol::no_constructor); + else + return entities.new_usertype("manager"); + }(/*config.engine*/); + + manager["make_entity"] = &EntityManager::make_entity; + manager["destroy_entity"] = &EntityManager::destroy_entity; + manager["destroy_all_entities"] = &EntityManager::destroy_all_entities; + manager["has_entity"] = &EntityManager::has_entity; + manager["add_component"] = +[](EntityManager* manager, Entity entity, sol::table component) static noexcept { + const auto type_closure = component.get>("type"); + ensures(type_closure.has_value(), "Missing type() function on lua component"); + + const auto type = sol::protected_function { *type_closure }; + const auto result = luacall(type, component); + const auto value = sol::object { result }; + + ensures(value.is(), "Component type() must return a string or a component type"); + const auto _type = hash(value.as()); + manager->add_component(entity, LuaComponent { .data = std::move(component), ._type = _type }); + }; + manager["get_component"] = +[](EntityManager* manager, Entity entity, string_view name) static noexcept { + return manager->get_component(entity, name).data; + }; + manager["has_component"] = +[](EntityManager* manager, Entity entity, string_view name) static noexcept { + return manager->has_component(entity, name); + }; + manager["entities"] = &EntityManager::entities; + manager["entity_count"] = &EntityManager::entity_count; + manager["components_types_of"] = &EntityManager::components_types_of; + manager["add_system"] = +[](EntityManager* manager, + string name, + dyn_array types, + sol::table opt) static noexcept { + auto update = opt.get>("update"); + expects(update.has_value(), std::format("No update closure supplied for system {}", name)); + + auto _closures = System::Closures { + .update = + [update = *std::move(update)](auto& manager, auto delta, const auto& entities) { + luacall(update, manager, delta.count(), sol::as_table(entities)); + }, + }; + + auto pre_update = opt.get>("pre_update"); + if (pre_update.has_value()) + _closures.pre_update = [pre_update = *std::move(pre_update)](auto& manager, const auto& entities) { + luacall(pre_update, manager, sol::as_table(entities)); + }; + auto post_update = opt.get>("post_update"); + if (post_update.has_value()) + _closures.post_update = [post_update = *std::move(post_update)](auto& manager, const auto& entities) { + luacall(post_update, manager, sol::as_table(entities)); + }; + + manager->add_system(std::move(name), + types | stdv::transform([](const auto& type) static noexcept { + return hash(type); + }) | stdr::to>(), + std::move(_closures)); + }; + manager["has_system"] = &EntityManager::has_system; + manager["remove_system"] = &EntityManager::remove_system; + + if (not no_constructor) { + manager["step"] = +[](EntityManager* manager, float delta) static noexcept { manager->step(fsecond { delta }); }; + } + } + + //////////////////////////////////////// + //////////////////////////////////////// + auto init_lua(sol::state& global_state) noexcept -> void { + auto entities = global_state["entities"].get_or_create(); + bind_manager(entities); + } +} // namespace stormkit::lua::entities diff --git a/src/lua/entities.cppm b/src/lua/entities.cppm new file mode 100644 index 000000000..bfca90932 --- /dev/null +++ b/src/lua/entities.cppm @@ -0,0 +1,18 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +module stormkit.lua:entities; + +import std; + +import stormkit.core; +import stormkit.entities; + +export namespace stormkit::lua::entities { + auto init_lua(sol::state& global_state) noexcept -> void; +} // namespace stormkit::lua::entities diff --git a/src/lua/gpu.cpp b/src/lua/gpu.cpp new file mode 100644 index 000000000..d01cb1bcb --- /dev/null +++ b/src/lua/gpu.cpp @@ -0,0 +1,21 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +module stormkit.lua; + +import std; + +import stormkit.core; +import stormkit.gpu; + +namespace stormkit::lua::gpu { + //////////////////////////////////////// + //////////////////////////////////////// + auto init_lua(sol::state&) noexcept -> void { + } +} // namespace stormkit::lua::gpu diff --git a/src/lua/gpu.cppm b/src/lua/gpu.cppm new file mode 100644 index 000000000..996cba31b --- /dev/null +++ b/src/lua/gpu.cppm @@ -0,0 +1,18 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +module stormkit.lua:gpu; + +import std; + +import stormkit.core; +import stormkit.gpu; + +export namespace stormkit::lua::gpu { + auto init_lua(sol::state& global_state) noexcept -> void; +} // namespace stormkit::lua::gpu diff --git a/src/lua/image.cpp b/src/lua/image.cpp new file mode 100644 index 000000000..eb1f8ba36 --- /dev/null +++ b/src/lua/image.cpp @@ -0,0 +1,19 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +module stormkit.lua; + +import std; + +import stormkit.core; +import stormkit.image; + +namespace stormkit::lua::image { + auto init_lua(sol::state&) noexcept -> void { + } +} // namespace stormkit::lua::image diff --git a/src/lua/image.cppm b/src/lua/image.cppm new file mode 100644 index 000000000..32ab13b62 --- /dev/null +++ b/src/lua/image.cppm @@ -0,0 +1,18 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +module stormkit.lua:image; + +import std; + +import stormkit.core; +import stormkit.image; + +export namespace stormkit::lua::image { + auto init_lua(sol::state& global_state) noexcept -> void; +} // namespace stormkit::lua::image diff --git a/src/lua/log.cpp b/src/lua/log.cpp new file mode 100644 index 000000000..eb72c4351 --- /dev/null +++ b/src/lua/log.cpp @@ -0,0 +1,54 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +#include + +module stormkit.lua; + +import std; + +import stormkit.core; +import stormkit.log; + +LOGGER("lua") + +namespace stormkit::lua::log { + auto init_lua(sol::state& global_state) noexcept -> void { + auto log_table = global_state["log"].get_or_create(); + log_table["info"] = [&global_state](string_view str, sol::variadic_args args) noexcept { + const auto format = sol::protected_function { global_state["format"] }; + const auto result = luacall(format, str, std::move(args)); + const auto out = sol::object { result }.as(); + ilog("{}", out); + }; + log_table["debug"] = [&global_state](string_view str, sol::variadic_args args) noexcept { + const auto format = sol::protected_function { global_state["format"] }; + const auto result = luacall(format, str, std::move(args)); + const auto out = sol::object { result }.as(); + dlog("{}", out); + }; + log_table["error"] = [&global_state](string_view str, sol::variadic_args args) noexcept { + const auto format = sol::protected_function { global_state["format"] }; + const auto result = luacall(format, str, std::move(args)); + const auto out = sol::object { result }.as(); + elog("{}", out); + }; + log_table["fatal"] = [&global_state](string_view str, sol::variadic_args args) noexcept { + const auto format = sol::protected_function { global_state["format"] }; + const auto result = luacall(format, str, std::move(args)); + const auto out = sol::object { result }.as(); + flog("{}", out); + }; + log_table["warning"] = [&global_state](string_view str, sol::variadic_args args) noexcept { + const auto format = sol::protected_function { global_state["format"] }; + const auto result = luacall(format, str, std::move(args)); + const auto out = sol::object { result }.as(); + wlog("{}", out); + }; + } +} // namespace stormkit::lua::log diff --git a/src/lua/log.cppm b/src/lua/log.cppm new file mode 100644 index 000000000..e9191a08e --- /dev/null +++ b/src/lua/log.cppm @@ -0,0 +1,18 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +module stormkit.lua:log; + +import std; + +import stormkit.core; +import stormkit.log; + +export namespace stormkit::lua::log { + auto init_lua(sol::state& global_state) noexcept -> void; +} // namespace stormkit::lua::log diff --git a/src/lua/lua.cpp b/src/lua/lua.cpp new file mode 100644 index 000000000..dbb1cf66d --- /dev/null +++ b/src/lua/lua.cpp @@ -0,0 +1,183 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#define NO_CONSTANTS +#include + +#include +#include +#include + +#include + +#include + +module stormkit.lua; + +import stormkit.core; +import :core; + +import stormkit.log; +import :log; + +#if STORMKIT_LIB_ENTITIES_ENABLED +import stormkit.entities; +import :entities; +#endif +#if STORMKIT_LIB_IMAGE_ENABLED +import stormkit.image; +import :image; +#endif +#if STORMKIT_LIB_WSI_ENABLED +import stormkit.wsi; +import :wsi; +#endif +#if STORMKIT_LIB_GPU_ENABLED +import stormkit.gpu; +import :gpu; +#endif + +namespace stdfs = std::filesystem; +namespace stdr = std::ranges; + +LOGGER("stormkit.lua") + +namespace stormkit::lua { + //////////////////////////////////////// + //////////////////////////////////////// + Engine::Engine(Modules&& modules, InitUserLibrariesClosure&& closure) noexcept + : m_modules { std::move(modules) }, m_init_user_libraries { std::move(closure) } { + } + + //////////////////////////////////////// + //////////////////////////////////////// + auto Engine::load(stdfs::path&& file) noexcept -> void { + m_script = TryAssert(io::read_text(file), std::format("Failed to load {}", file.string())); + } + + //////////////////////////////////////// + //////////////////////////////////////// + auto Engine::run() noexcept -> sol::state { + auto state = sol::state {}; + + init_libraries(state); + m_init_user_libraries(state); + + auto result = state.do_string(string_view { stdr::data(m_script), stdr::size(m_script) }); + if (not result.valid()) elog("lua error!\n{}", sol::error { result }.what()); + + return state; + } + + //////////////////////////////////////// + //////////////////////////////////////// + auto Engine::init_libraries(sol::state& global_state) noexcept -> void { + for (auto lib : { + sol::lib::base, + sol::lib::bit32, + sol::lib::debug, + sol::lib::io, + sol::lib::os, + sol::lib::string, + sol::lib::table, + }) + global_state.open_libraries(lib); + + auto tostring = sol::protected_function { global_state["tostring"] }; + global_state["tostring"] = [format = std::move(tostring)](sol::object v) noexcept { + if (not v.valid()) return string {}; + if (v.is()) { + auto out = string { "[lua_table " }; + for (auto&& [key, value] : v.as()) { + auto key_as_string = sol::object { luacall(format, key) }.as(); + auto value_as_string = sol::object { luacall(format, value) }.as(); + out += key_as_string; + out += ": "; + out += value_as_string; + out += ", "; + } + out = out.substr(0, stdr::size(out) - 2); + out += "]"; + return out; + } + return sol::object { luacall(format, v) }.as(); + }; + global_state["print"] = [&global_state](string_view str, sol::variadic_args args) noexcept { + const auto format = sol::protected_function { global_state["format"] }; + const auto result = luacall(format, str, std::move(args)); + const auto out = sol::object { result }.as(); + std::println("{}", out); + }; + + global_state["format"] = [&global_state](string_view str, sol::variadic_args args) noexcept { + auto slices = split(str, "{}"); + if (stdr::size(slices) == 1) { return std::format("{}", str); } + + expects(args.size() == stdr::size(slices) - 1, + std::format("Invalid count of args! should be {}, got {}", stdr::size(slices) - 1, args.size())); + + auto out = string {}; + out.reserve(stdr::size(str)); + auto it = stdr::begin(slices); + out += *it; + ++it; + for (auto v : args) { + auto format = sol::protected_function { global_state["tostring"] }; + const auto result = luacall(global_state["tostring"], v); + out += sol::object { result }.as(); + + out += *it; + ++it; + + if (it == stdr::cend(slices)) break; + } + + return out; + }; + + core::init_lua(global_state); + if (m_modules.log) { +#if STORMKIT_LIB_LOG_ENABLED + dlog("Log module enabled."); + log::init_lua(global_state); +#else + elog("Trying to bind log module while disabled in this stormkit distribution!"); +#endif + } + if (m_modules.entities) { +#if STORMKIT_LIB_ENTITIES_ENABLED + dlog("Entities module enabled."); + entities::init_lua(global_state); +#else + elog("Trying to bind entities module while disabled in this stormkit distribution!"); +#endif + } + if (m_modules.image) { +#if STORMKIT_LIB_IMAGE_ENABLED + dlog("Image module enabled."); + image::init_lua(global_state); +#else + elog("Trying to bind image module while disabled in this stormkit distribution!"); +#endif + } + if (m_modules.wsi) { +#if STORMKIT_LIB_WSI_ENABLED + dlog("Wsi module enabled."); + wsi::init_lua(global_state); +#else + elog("Trying to bind wsi module while disabled in this stormkit distribution!"); +#endif + } + if (m_modules.gpu) { +#if STORMKIT_LIB_GPU_ENABLED + dlog("Gpu module enabled."); + gpu::init_lua(global_state); +#else + elog("Trying to bind gpu module while disabled in this stormkit distribution!"); +#endif + } + } +} // namespace stormkit::lua diff --git a/src/lua/wsi.cpp b/src/lua/wsi.cpp new file mode 100644 index 000000000..4329b6cda --- /dev/null +++ b/src/lua/wsi.cpp @@ -0,0 +1,35 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +#include + +module stormkit.lua; + +import std; + +import stormkit.core; +import stormkit.wsi; + +namespace stormkit::lua::wsi { + extern auto bind_core(sol::state&, sol::table&) noexcept -> void; + extern auto bind_window(sol::state&, sol::table&) noexcept -> void; + extern auto bind_monitor(sol::state&, sol::table&) noexcept -> void; + extern auto bind_keyboard(sol::state&, sol::table&) noexcept -> void; + extern auto bind_mouse(sol::state&, sol::table&) noexcept -> void; + + //////////////////////////////////////// + //////////////////////////////////////// + auto init_lua(sol::state& global_state) noexcept -> void { + auto wsi = global_state["wsi"].get_or_create(); + bind_core(global_state, wsi); + bind_window(global_state, wsi); + bind_monitor(global_state, wsi); + bind_keyboard(global_state, wsi); + bind_mouse(global_state, wsi); + } +} // namespace stormkit::lua::wsi diff --git a/src/lua/wsi.cppm b/src/lua/wsi.cppm new file mode 100644 index 000000000..47f56c400 --- /dev/null +++ b/src/lua/wsi.cppm @@ -0,0 +1,54 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +#include + +module stormkit.lua:wsi; + +import std; + +import stormkit.core; +import stormkit.wsi; + +export { + // template<> + // struct lb::Stack: lb::Enum {}; + + // template<> + // struct lb::Stack + // : lb::Enum {}; + + // template<> + // struct lb::Stack + // : lb::Enum {}; + + namespace stormkit::lua::wsi { + auto init_lua(sol::state& global_state) noexcept -> void; + } // namespace stormkit::lua::wsi +} diff --git a/src/lua/wsi/core.cpp b/src/lua/wsi/core.cpp new file mode 100644 index 000000000..e84c86038 --- /dev/null +++ b/src/lua/wsi/core.cpp @@ -0,0 +1,44 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +#include + +module stormkit.lua; + +import std; + +import stormkit.core; +import stormkit.wsi; + +namespace stormkit::lua::wsi { + using stormkit::wsi::WM; + + //////////////////////////////////////// + //////////////////////////////////////// + auto bind_core(sol::state& global_state, sol::table& metatable) noexcept -> void { + metatable["window_manager"] = global_state.create_table_with( + sol::meta_function::to_string, + +[](WM wm) { return to_string(wm); }, + "WIN32", + WM::WIN32, + "WAYLAND", + WM::WAYLAND, + "X11", + WM::X11, + "ANDROID", + WM::ANDROID, + "MACOS", + WM::MACOS, + "IOS", + WM::IOS, + "TVOS", + WM::TVOS, + "SWITCH", + WM::SWITCH); + } +} // namespace stormkit::lua::wsi diff --git a/src/lua/wsi/keyboard.cpp b/src/lua/wsi/keyboard.cpp new file mode 100644 index 000000000..961a8ff50 --- /dev/null +++ b/src/lua/wsi/keyboard.cpp @@ -0,0 +1,254 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +#include + +module stormkit.lua; + +import std; + +import stormkit.core; +import stormkit.wsi; + +namespace stormkit::lua::wsi { + using stormkit::wsi::Key; + + //////////////////////////////////////// + //////////////////////////////////////// + auto bind_keyboard(sol::state& global_state, sol::table& metatable) noexcept -> void { + metatable["key"] = global_state.create_table_with( + sol::meta_function::to_string, + +[](Key key) { return to_string(key); }, + "A", + Key::A, + "B", + Key::B, + "C", + Key::C, + "D", + Key::D, + "E", + Key::E, + "F", + Key::F, + "G", + Key::G, + "H", + Key::H, + "I", + Key::I, + "J", + Key::J, + "K", + Key::K, + "L", + Key::L, + "M", + Key::M, + "N", + Key::N, + "O", + Key::O, + "P", + Key::P, + "Q", + Key::Q, + "R", + Key::R, + "S", + Key::S, + "T", + Key::T, + "U", + Key::U, + "V", + Key::V, + "W", + Key::W, + "X", + Key::X, + "Y", + Key::Y, + "Z", + Key::Z, + "NUM_0", + Key::NUM_0, + "NUM_1", + Key::NUM_1, + "NUM_2", + Key::NUM_2, + "NUM_3", + Key::NUM_3, + "NUM_4", + Key::NUM_4, + "NUM_5", + Key::NUM_5, + "NUM_6", + Key::NUM_6, + "NUM_7", + Key::NUM_7, + "NUM_8", + Key::NUM_8, + "NUM_9", + Key::NUM_9, + "LEFT", + Key::LEFT, + "RIGHT", + Key::RIGHT, + "UP", + Key::UP, + "DOWN", + Key::DOWN, + "L_CONTROL", + Key::L_CONTROL, + "L_SHIFT", + Key::L_SHIFT, + "L_ALT", + Key::L_ALT, + "L_META", + Key::L_META, + "R_CONTROL", + Key::R_CONTROL, + "R_SHIFT", + Key::R_SHIFT, + "R_ALT", + Key::R_ALT, + "R_META", + Key::R_META, + "ESCAPE", + Key::ESCAPE, + "TAB", + Key::TAB, + "MENU", + Key::MENU, + "QUOTE", + Key::QUOTE, + "BACK_SLASH", + Key::BACK_SLASH, + "COMMA", + Key::COMMA, + "EQUAL", + Key::EQUAL, + "GRAVE_ACCENT", + Key::GRAVE_ACCENT, + "L_BRACKET", + Key::L_BRACKET, + "MINUS", + Key::MINUS, + "PERIOD", + Key::PERIOD, + "R_BRACKET", + Key::R_BRACKET, + "SEMI_COLON", + Key::SEMI_COLON, + "SLASH", + Key::SLASH, + "ISO", + Key::ISO, + "BACK_SPACE", + Key::BACK_SPACE, + "CAPS_LOCK", + Key::CAPS_LOCK, + "ENTER", + Key::ENTER, + "SPACE", + Key::SPACE, + "F1", + Key::F1, + "F2", + Key::F2, + "F3", + Key::F3, + "F4", + Key::F4, + "F5", + Key::F5, + "F6", + Key::F6, + "F7", + Key::F7, + "F8", + Key::F8, + "F9", + Key::F9, + "F10", + Key::F10, + "F11", + Key::F11, + "F12", + Key::F12, + "F13", + Key::F13, + "F14", + Key::F14, + "F15", + Key::F15, + "F16", + Key::F16, + "F17", + Key::F17, + "F18", + Key::F18, + "F19", + Key::F19, + "F20", + Key::F20, + "PRINT_SCREEN", + Key::PRINT_SCREEN, + "INSERT", + Key::INSERT, + "DELETE", + Key::DELETE, + "HOME", + Key::HOME, + "END", + Key::END, + "PAGE_UP", + Key::PAGE_UP, + "PAGE_DOWN", + Key::PAGE_DOWN, + "NUMPAD_LOCK", + Key::NUMPAD_LOCK, + "NUMPAD_ADD", + Key::NUMPAD_ADD, + "NUMPAD_DECIMAL", + Key::NUMPAD_DECIMAL, + "NUMPAD_DIVIDE", + Key::NUMPAD_DIVIDE, + "NUMPAD_ENTER", + Key::NUMPAD_ENTER, + "NUMPAD_EQUAL", + Key::NUMPAD_EQUAL, + "NUMPAD_MULTIPLY", + Key::NUMPAD_MULTIPLY, + "NUMPAD_SUBTRACT", + Key::NUMPAD_SUBTRACT, + "NUMPAD_0", + Key::NUMPAD_0, + "NUMPAD_1", + Key::NUMPAD_1, + "NUMPAD_2", + Key::NUMPAD_2, + "NUMPAD_3", + Key::NUMPAD_3, + "NUMPAD_4", + Key::NUMPAD_4, + "NUMPAD_5", + Key::NUMPAD_5, + "NUMPAD_6", + Key::NUMPAD_6, + "NUMPAD_7", + Key::NUMPAD_7, + "NUMPAD_8", + Key::NUMPAD_8, + "NUMPAD_9", + Key::NUMPAD_9, + "UNKNOWN", + Key::UNKNOWN); + } +} // namespace stormkit::lua::wsi diff --git a/src/lua/wsi/monitor.cpp b/src/lua/wsi/monitor.cpp new file mode 100644 index 000000000..a5e184e75 --- /dev/null +++ b/src/lua/wsi/monitor.cpp @@ -0,0 +1,43 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +#include + +module stormkit.lua; + +import std; + +import stormkit.core; +import stormkit.wsi; + +namespace stormkit::lua::wsi { + using stormkit::wsi::Monitor; + + //////////////////////////////////////// + //////////////////////////////////////// + auto bind_monitor(sol::state& global_state, sol::table& metatable) noexcept -> void { + metatable["monitor_flag"] = global_state.create_table_with( + sol::meta_function::to_string, + +[](Monitor::Flags flags) { return to_string(flags); }, + "NONE", + Monitor::Flags::NONE, + "PRIMARY", + Monitor::Flags::PRIMARY); + + auto monitor = metatable.new_usertype("monitor"); + monitor[sol::meta_function::to_string] = +[](Monitor::Flags flags) { return to_string(flags); }, + monitor[sol::meta_function::equal_to] = &Monitor::operator==; + monitor[sol::meta_function::less_than] = +[](const Monitor& first, const Monitor& second) static noexcept { + return first < second; + }; + monitor["flags"] = &Monitor::flags; + monitor["name"] = &Monitor::name; + monitor["extents"] = &Monitor::extents; + monitor["scale_factor"] = &Monitor::scale_factor; + } +} // namespace stormkit::lua::wsi diff --git a/src/lua/wsi/mouse.cpp b/src/lua/wsi/mouse.cpp new file mode 100644 index 000000000..ae4695fd8 --- /dev/null +++ b/src/lua/wsi/mouse.cpp @@ -0,0 +1,58 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +#include + +module stormkit.lua; + +import std; + +import stormkit.core; +import stormkit.wsi; + +namespace stormkit::lua::wsi { + using stormkit::wsi::MouseButton; + + //////////////////////////////////////// + //////////////////////////////////////// + auto bind_mouse(sol::state& global_state, sol::table& metatable) noexcept -> void { + metatable["mouse_button"] = global_state.create_table_with( + sol::meta_function::to_string, + +[](MouseButton mouse_button) { return to_string(mouse_button); }, + "LEFT", + MouseButton::LEFT, + "RIGHT", + MouseButton::RIGHT, + "MIDDLE", + MouseButton::MIDDLE, + "BUTTON_1", + MouseButton::BUTTON_1, + "BUTTON_2", + MouseButton::BUTTON_2, + "BUTTON_3", + MouseButton::BUTTON_3, + "BUTTON_4", + MouseButton::BUTTON_4, + "BUTTON_5", + MouseButton::BUTTON_5, + "BUTTON_6", + MouseButton::BUTTON_6, + "BUTTON_7", + MouseButton::BUTTON_7, + "BUTTON_8", + MouseButton::BUTTON_8, + "BUTTON_9", + MouseButton::BUTTON_9, + "BUTTON_10", + MouseButton::BUTTON_10, + "BUTTON_11", + MouseButton::BUTTON_11, + "BUTTON_12", + MouseButton::BUTTON_12); + } +} // namespace stormkit::lua::wsi diff --git a/src/lua/wsi/window.cpp b/src/lua/wsi/window.cpp new file mode 100644 index 000000000..108021bcc --- /dev/null +++ b/src/lua/wsi/window.cpp @@ -0,0 +1,159 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +#include + +module stormkit.lua; + +import std; + +import stormkit.core; +import stormkit.wsi; + +namespace stormkit::lua::wsi { + using stormkit::wsi::EventType; + using stormkit::wsi::Key; + using stormkit::wsi::Monitor; + using stormkit::wsi::MouseButton; + using stormkit::wsi::Window; + using stormkit::wsi::WindowFlag; + + namespace { + //////////////////////////////////////// + //////////////////////////////////////// + template + constexpr auto make_lua_closure() noexcept { + return [](Window* window, sol::protected_function closure) static noexcept { + window->on([closure = std::move(closure)](Args&&... args) noexcept { + auto result = closure(std::forward(args)...); + if (not result.valid()) + ensures(false, + std::format("lua runtime error!\nlua callstack -------------------------\n{}", + sol::error { result }.what())); + }); + }; + } + } // namespace + + //////////////////////////////////////// + //////////////////////////////////////// + auto open_window(string name, u32 width, u32 height, wsi::WindowFlag flags) noexcept -> wsi::Window { + return wsi::Window::open(std::move(name), { width, height }, flags); + } + + //////////////////////////////////////// + //////////////////////////////////////// + auto bind_window(sol::state& global_state, sol::table& metatable) noexcept -> void { + metatable["window_flag"] = global_state.create_table_with( + sol::meta_function::to_string, + +[](WindowFlag flags) { return to_string(flags); }, + "DEFAULT", + WindowFlag::DEFAULT, + "BORDERLESS", + WindowFlag::BORDERLESS, + "RESIZEABLE", + WindowFlag::RESIZEABLE, + "EXTERNAL_CONTEXT", + WindowFlag::EXTERNAL_CONTEXT); + metatable["event_type"] = global_state.create_table_with( + sol::meta_function::to_string, + +[](EventType type) { return to_string(type); }, + "NONE", + EventType::NONE, + "CLOSED", + EventType::CLOSED, + "MONITOR_CHANGED", + EventType::MONITOR_CHANGED, + "RESIZED", + EventType::RESIZED, + "RESTORED", + EventType::RESTORED, + "MINIMIZED", + EventType::MINIMIZED, + "KEY_DOWN", + EventType::KEY_DOWN, + "KEY_UP", + EventType::KEY_UP, + "MOUSE_BUTTON_DOWN", + EventType::MOUSE_BUTTON_DOWN, + "MOUSE_BUTTON_UP", + EventType::MOUSE_BUTTON_UP, + "MOUSE_MOVED", + EventType::MOUSE_MOVED, + "ACTIVATE", + EventType::ACTIVATE, + "DEACTIVATE", + EventType::DEACTIVATE); + + auto window_metatable = metatable.new_usertype("window"); + window_metatable["open"] = &open_window; + window_metatable["window_manager"] = &Window::wm; + window_metatable["extent"] = &Window::extent; + window_metatable["set_extent"] = &Window::set_extent; + window_metatable["close"] = &Window::close; + window_metatable["title"] = &Window::title; + window_metatable["set_title"] = &Window::set_title; + window_metatable["fullscreen"] = &Window::fullscreen; + window_metatable["toggle_fullscreen"] = &Window::toggle_fullscreen; + + window_metatable["is_mouse_hidden"] = sol:: + overload(&Window::is_mouse_hidden, +[](Window* window) static noexcept { return window->is_mouse_hidden(); }); + window_metatable["toggle_hidden_mouse"] = sol:: + overload(&Window::toggle_hidden_mouse, +[](Window* window) static noexcept { return window->toggle_hidden_mouse(); }); + window_metatable["is_mouse_locked"] = sol:: + overload(&Window::is_mouse_locked, +[](Window* window) static noexcept { return window->is_mouse_locked(); }); + window_metatable["toggle_locked_mouse"] = sol:: + overload(&Window::toggle_locked_mouse, +[](Window* window) static noexcept { return window->toggle_locked_mouse(); }); + window_metatable["is_mouse_confined"] = sol:: + overload(&Window::is_mouse_confined, +[](Window* window) static noexcept { return window->is_mouse_confined(); }); + window_metatable["toggle_confined_mouse"] = sol::overload( + &Window::toggle_confined_mouse, + +[](Window* window) static noexcept { return window->toggle_confined_mouse(); }); + window_metatable["is_mouse_relative"] = sol:: + overload(&Window::is_mouse_relative, +[](Window* window) static noexcept { return window->is_mouse_relative(); }); + window_metatable["toggle_relative_mouse"] = sol::overload( + &Window::toggle_relative_mouse, + +[](Window* window) static noexcept { return window->toggle_relative_mouse(); }); + window_metatable["is_key_repeat_enabled"] = sol::overload( + &Window::is_key_repeat_enabled, + +[](Window* window) static noexcept { return window->is_key_repeat_enabled(); }); + window_metatable["toggle_key_repeat"] = sol:: + overload(&Window::toggle_key_repeat, +[](Window* window) static noexcept { return window->toggle_key_repeat(); }); + window_metatable["clear"] = sol:: + overload(&Window::clear, +[](Window* window) static noexcept { return window->clear(); }); + + window_metatable["event_loop"] = +[](Window* window, sol::protected_function closure) static noexcept { + window->event_loop([closure = std::move(closure)] noexcept { + auto result = closure(); + if (not result.valid()) ensures(false, sol::error { result }.what()); + }); + }; + window_metatable["on_closed"] = +[](Window* window, sol::protected_function closure) static noexcept { + window->on([closure = std::move(closure)] noexcept { + const auto result = closure(); + if (not result.valid()) ensures(false, sol::error { result }.what()); + auto value = sol::object { result }; + ensures(value.is(), "on_closed closure must return a boolean value"); + return value.as(); + }); + }; + window_metatable["on_monitor_changed"] = +make_lua_closure(); + window_metatable["on_resized"] = +make_lua_closure(); + window_metatable["on_restored"] = +make_lua_closure(); + window_metatable["on_minimized"] = +make_lua_closure(); + window_metatable["on_key_up"] = +make_lua_closure(); + window_metatable["on_key_down"] = +make_lua_closure(); + window_metatable + ["on_mouse_button_up"] = +make_lua_closure(); + window_metatable + ["on_mouse_button_down"] = +make_lua_closure(); + window_metatable["on_mouse_moved"] = +make_lua_closure(); + window_metatable["on_activated"] = +make_lua_closure(); + window_metatable["on_deactivated"] = +make_lua_closure(); + } +} // namespace stormkit::lua::wsi diff --git a/src/main/linux/main_linux.cpp b/src/main/linux/main_linux.cpp index 60c052300..4037eb59c 100644 --- a/src/main/linux/main_linux.cpp +++ b/src/main/linux/main_linux.cpp @@ -7,15 +7,17 @@ import stormkit.core; #include -extern auto user_main(std::span) -> int; +using namespace stormkit; -auto main(int argc, char** argv) -> int { - stormkit::setup_signal_handler(); - stormkit::set_current_thread_name("MainThread"); +extern auto user_main(array_view) -> i32; - auto args = std::vector {}; +auto main(i32 argc, char** argv) -> i32 { + setup_signal_handler(); + set_current_thread_name("stormkit:main_thread"); - for (auto i : stormkit::range(argc)) args.emplace_back(argv[i]); + auto args = dyn_array {}; + + for (auto i : range(argc)) args.emplace_back(argv[i]); return user_main(args); } diff --git a/src/main/macos/Main-macOS.mm b/src/main/macos/Main-macOS.mm index 3c7a4a504..f05c979fc 100644 --- a/src/main/macos/Main-macOS.mm +++ b/src/main/macos/Main-macOS.mm @@ -8,7 +8,7 @@ auto main(const int argc, const char** argv) -> int { setup_signal_handler(); - set_current_thread_name("MainThread"); + set_current_thread_name("stormkit:main_thread"); auto args = std::vector {}; diff --git a/src/main/macos/Main-macOS.swift b/src/main/macos/Main-macOS.swift deleted file mode 100644 index 3f3e328cd..000000000 --- a/src/main/macos/Main-macOS.swift +++ /dev/null @@ -1,3 +0,0 @@ -import Foundation - -print("hello world") diff --git a/src/main/macos/stormkit_core.cpp b/src/main/macos/stormkit_core.cpp index f025ad881..b36b4f1a4 100644 --- a/src/main/macos/stormkit_core.cpp +++ b/src/main/macos/stormkit_core.cpp @@ -6,6 +6,6 @@ auto setup_signal_handler() -> void { stormkit::setup_signal_handler(); } -auto set_current_thread_name(std::string_view name) -> void { +auto set_current_thread_name(string_view name) -> void { stormkit::set_current_thread_name(name); } diff --git a/src/main/macos/stormkit_core.hpp b/src/main/macos/stormkit_core.hpp index c4e83c1f6..7a56a9a4c 100644 --- a/src/main/macos/stormkit_core.hpp +++ b/src/main/macos/stormkit_core.hpp @@ -4,6 +4,6 @@ #include auto setup_signal_handler() -> void; -auto set_current_thread_name(std::string_view name) -> void; +auto set_current_thread_name(string_view name) -> void; #endif diff --git a/src/main/win32/main_win.cpp b/src/main/win32/main_win.cpp index a8c37d70b..0e9a8dfb5 100644 --- a/src/main/win32/main_win.cpp +++ b/src/main/win32/main_win.cpp @@ -75,10 +75,10 @@ namespace { } } // namespace -extern auto user_main(std::span) -> int; +extern auto user_main(array_view) -> int; auto __stdcall main(int argc, char** argv) -> int { - auto args = std::vector {}; + auto args = dyn_array {}; args.reserve(as(argc)); for (auto&& i : stormkit::range(argc)) args.emplace_back(argv[i]); @@ -86,7 +86,7 @@ auto __stdcall main(int argc, char** argv) -> int { redirect_io_to_console(false); setup_signal_handler(); - set_current_thread_name("MainThread"); + set_current_thread_name("stormkit:main_thread"); return user_main(args); } @@ -95,7 +95,7 @@ auto __stdcall WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) -> int { const auto argc = __argc; const auto argv = __argv; - auto args = std::vector {}; + auto args = dyn_array {}; args.reserve(as(argc)); for (auto&& i : stormkit::range(argc)) args.emplace_back(argv[i]); @@ -103,7 +103,7 @@ auto __stdcall WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) -> int { const auto has_allocated = redirect_io_to_console(false); setup_signal_handler(); - set_current_thread_name("MainThread"); + set_current_thread_name("stormkit:main_thread"); const auto ret_value = user_main(args); if (has_allocated) ::FreeConsole(); diff --git a/src/test/main.cpp b/src/test/main.cpp index 01097bf6f..875aa3880 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -9,7 +9,9 @@ import std; #include -auto main(std::span args) noexcept -> int { +using namespace stormkit; + +auto main(array_view args) noexcept -> i32 { test::parse_args(args); return test::runTests(); diff --git a/src/wsi/common/input_base.mpp b/src/wsi/common/input_base.cppm similarity index 91% rename from src/wsi/common/input_base.mpp rename to src/wsi/common/input_base.cppm index 2a2b00cec..814e76bc4 100644 --- a/src/wsi/common/input_base.mpp +++ b/src/wsi/common/input_base.cppm @@ -30,7 +30,7 @@ export namespace stormkit::wsi::common { u8 id; bool key_repeat = false; - std::array keys = filled_with<102>(KeyState::UP); + array keys = filled_with<102>(KeyState::UP); }; enum class ButtonState : u8 { @@ -45,10 +45,10 @@ export namespace stormkit::wsi::common { bool relative = false; bool confined = false; - math::vec2u locked_at = {}; - math::vec2u last_position = {}; + math::uvec2 locked_at = {}; + math::uvec2 last_position = {}; - std::array buttons = filled_with<15>(ButtonState::UP); + array buttons = filled_with<15>(ButtonState::UP); }; } // namespace stormkit::wsi::common diff --git a/src/wsi/common/monitor_base.mpp b/src/wsi/common/monitor_base.cppm similarity index 100% rename from src/wsi/common/monitor_base.mpp rename to src/wsi/common/monitor_base.cppm diff --git a/src/wsi/common/window_base.mpp b/src/wsi/common/window_base.cppm similarity index 84% rename from src/wsi/common/window_base.mpp rename to src/wsi/common/window_base.cppm index 3e19a3f44..451aa5722 100644 --- a/src/wsi/common/window_base.mpp +++ b/src/wsi/common/window_base.cppm @@ -24,19 +24,17 @@ export namespace stormkit::wsi::common { m_keyboard_states.push_back({ .id = GLOBAL_KEYBOARD_ID }); } - WindowBase(const WindowBase&) = delete; - auto operator=(const WindowBase&) -> WindowBase& = delete; + WindowBase(const WindowBase&) = delete; + auto operator=(const WindowBase&) -> WindowBase& = delete; STORMKIT_FORCE_INLINE - inline WindowBase(WindowBase&&) noexcept - = default; + inline WindowBase(WindowBase&&) noexcept = default; STORMKIT_FORCE_INLINE inline auto operator=(WindowBase&&) noexcept -> WindowBase& = default; STORMKIT_FORCE_INLINE - inline ~WindowBase() noexcept - = default; + inline ~WindowBase() noexcept = default; auto set_open(bool open) noexcept -> void; [[nodiscard]] @@ -49,13 +47,13 @@ export namespace stormkit::wsi::common { auto current_monitor() const noexcept -> const Monitor&; auto set_current_monitor(const Monitor& extent) noexcept -> void; - auto set_title(std::string title) noexcept -> bool; + auto set_title(string title) noexcept -> bool; [[nodiscard]] - auto title() const noexcept -> const std::string&; + auto title() const noexcept -> const string&; - auto set_extent(const math::Extent2& extent) noexcept -> bool; + auto set_extent(const math::uextent2& extent) noexcept -> bool; [[nodiscard]] - auto extent() const noexcept -> const math::Extent2&; + auto extent() const noexcept -> const math::uextent2&; auto set_fullscreen(bool fullscreen) noexcept -> bool; [[nodiscard]] @@ -91,27 +89,26 @@ export namespace stormkit::wsi::common { auto mouse_state(this T& self, u8 id) noexcept -> core::meta::ForwardConst&; template - auto keyboard_state(this T& self, u8 id) noexcept - -> core::meta::ForwardConst&; + auto keyboard_state(this T& self, u8 id) noexcept -> core::meta::ForwardConst&; protected: struct { - bool open = false; - bool minimized = false; - bool active = false; - bool fullscreen = false; - bool visible = false; - math::Extent2 extent; - OptionalRef current_monitor; - std::string title; + bool open = false; + bool minimized = false; + bool active = false; + bool fullscreen = false; + bool visible = false; + math::uextent2 extent; + optref current_monitor; + string title; f32 dpi = 1.f; - math::vec2i position = { 0, 0 }; + math::ivec2 position = { 0, 0 }; } m_state; - std::vector m_mouse_states; - std::vector m_keyboard_states; + dyn_array m_mouse_states; + dyn_array m_keyboard_states; }; } // namespace stormkit::wsi::common @@ -152,13 +149,13 @@ namespace stormkit::wsi::common { ///////////////////////////////////// STORMKIT_FORCE_INLINE inline auto WindowBase::set_current_monitor(const Monitor& monitor) noexcept -> void { - m_state.current_monitor = as_opt_ref(monitor); + m_state.current_monitor = as_optref(monitor); } ///////////////////////////////////// ///////////////////////////////////// STORMKIT_FORCE_INLINE - inline auto WindowBase::set_title(std::string title) noexcept -> bool { + inline auto WindowBase::set_title(string title) noexcept -> bool { if (not m_state.open) return false; m_state.title = std::move(title); @@ -168,14 +165,14 @@ namespace stormkit::wsi::common { ///////////////////////////////////// ///////////////////////////////////// STORMKIT_FORCE_INLINE - inline auto WindowBase::title() const noexcept -> const std::string& { + inline auto WindowBase::title() const noexcept -> const string& { return m_state.title; } ///////////////////////////////////// ///////////////////////////////////// STORMKIT_FORCE_INLINE - inline auto WindowBase::set_extent(const math::Extent2& extent) noexcept -> bool { + inline auto WindowBase::set_extent(const math::uextent2& extent) noexcept -> bool { if (not m_state.open) return false; m_state.extent = extent; @@ -185,7 +182,7 @@ namespace stormkit::wsi::common { ///////////////////////////////////// ///////////////////////////////////// STORMKIT_FORCE_INLINE - inline auto WindowBase::extent() const noexcept -> const math::Extent2& { + inline auto WindowBase::extent() const noexcept -> const math::uextent2& { return m_state.extent; } @@ -216,8 +213,7 @@ namespace stormkit::wsi::common { ///////////////////////////////////// ///////////////////////////////////// STORMKIT_FORCE_INLINE - inline auto WindowBase::set_monitor_changed_event(MonitorChangedEventFunc&& func) noexcept - -> void { + inline auto WindowBase::set_monitor_changed_event(MonitorChangedEventFunc&& func) noexcept -> void { monitor_changed_event = std::move(func); } @@ -259,16 +255,14 @@ namespace stormkit::wsi::common { ///////////////////////////////////// ///////////////////////////////////// STORMKIT_FORCE_INLINE - inline auto WindowBase::set_mouse_button_down_event(MouseButtonDownEventFunc&& func) noexcept - -> void { + inline auto WindowBase::set_mouse_button_down_event(MouseButtonDownEventFunc&& func) noexcept -> void { mouse_button_down_event = std::move(func); } ///////////////////////////////////// ///////////////////////////////////// STORMKIT_FORCE_INLINE - inline auto WindowBase::set_mouse_button_up_event(MouseButtonUpEventFunc&& func) noexcept - -> void { + inline auto WindowBase::set_mouse_button_up_event(MouseButtonUpEventFunc&& func) noexcept -> void { mouse_button_up_event = std::move(func); } @@ -297,8 +291,7 @@ namespace stormkit::wsi::common { ///////////////////////////////////// template STORMKIT_FORCE_INLINE - inline auto WindowBase::mouse_state(this T& self, u8 id) noexcept - -> core::meta::ForwardConst& { + inline auto WindowBase::mouse_state(this T& self, u8 id) noexcept -> core::meta::ForwardConst& { expects(id < stdr::size(self.m_mouse_states)); return self.m_mouse_states[id]; } @@ -307,8 +300,7 @@ namespace stormkit::wsi::common { ///////////////////////////////////// template STORMKIT_FORCE_INLINE - inline auto WindowBase::keyboard_state(this T& self, u8 id) noexcept - -> core::meta::ForwardConst& { + inline auto WindowBase::keyboard_state(this T& self, u8 id) noexcept -> core::meta::ForwardConst& { expects(id < stdr::size(self.m_keyboard_states)); return self.m_keyboard_states[id]; } diff --git a/src/wsi/core.cpp b/src/wsi/core.cpp index 87b15def0..bdafa40ae 100644 --- a/src/wsi/core.cpp +++ b/src/wsi/core.cpp @@ -21,7 +21,7 @@ namespace stormkit::wsi { ///////////////////////////////////// ///////////////////////////////////// - auto parse_args(std::span args) noexcept -> void { + auto parse_args(array_view args) noexcept -> void { auto hint = std::ranges::find_if(args, [](auto&& v) { return v == "--x11" or v == "--wayland"; }); if (hint != std::ranges::cend(args)) { diff --git a/src/wsi/ios/input_handler_impl.hpp b/src/wsi/ios/input_handler_impl.hpp index 2d5307ff6..409f574f3 100644 --- a/src/wsi/ios/input_handler_impl.hpp +++ b/src/wsi/ios/input_handler_impl.hpp @@ -23,10 +23,10 @@ namespace storm::window { static bool isKeyPressed(Key key); static bool isMouseButtonPressed(MouseButton button); - static void set_mouse_position(core::math::vec2u position); - static void set_mouse_position(core::math::vec2u position, const Window& relative_to); - static core::math::vec2u getMousePosition(); - static core::math::vec2u getMousePosition(const Window& relative_to); + static void set_mouse_position(core::math::uvec2 position); + static void set_mouse_position(core::math::uvec2 position, const Window& relative_to); + static core::math::uvec2 getMousePosition(); + static core::math::uvec2 getMousePosition(const Window& relative_to); static void toggle_virtual_keyboard_visibility(bool visible); diff --git a/src/wsi/ios/window_impl.hpp b/src/wsi/ios/window_impl.hpp index 0bf114f56..0dba9bc8c 100644 --- a/src/wsi/ios/window_impl.hpp +++ b/src/wsi/ios/window_impl.hpp @@ -28,12 +28,12 @@ namespace storm::window { class STORMKIT_PRIVATE Window: public storm::window::AbstractWindow { public: Window() noexcept; - Window(const std::string& title, + Window(const string& title, const storm::window::VideoSettings& settings, storm::window::WindowStyle style) noexcept; ~Window() override; - void create(const std::string& title, + void create(const string& title, const storm::window::VideoSettings& settings, storm::window::WindowStyle style) noexcept override; void close() noexcept override; @@ -41,10 +41,10 @@ namespace storm::window { bool poll_event(storm::window::Event& event, void* native_event) noexcept override; bool wait_event(storm::window::Event& event, void* native_event) noexcept override; - void set_title(const std::string& title) noexcept override; + void set_title(const string& title) noexcept override; void setVideoSettings(const storm::window::VideoSettings& settings) noexcept override; - storm::core::Extentu size() const noexcept override; + storm::core::extentu size() const noexcept override; bool is_open() const noexcept override; bool isVisible() const noexcept override; diff --git a/src/wsi/linux/common/fd.mpp b/src/wsi/linux/common/fd.cppm similarity index 100% rename from src/wsi/linux/common/fd.mpp rename to src/wsi/linux/common/fd.cppm diff --git a/src/wsi/linux/common/xkb.mpp b/src/wsi/linux/common/xkb.cppm similarity index 90% rename from src/wsi/linux/common/xkb.mpp rename to src/wsi/linux/common/xkb.cppm index 8f80259a6..ea8091a57 100644 --- a/src/wsi/linux/common/xkb.mpp +++ b/src/wsi/linux/common/xkb.cppm @@ -1,215 +1,206 @@ -// Copyright (C) 2021 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -#include -#include - -export module stormkit.wsi:linux.common.xkb; - -import std; -import frozen; - -import stormkit.core; -import stormkit.log; -import stormkit.wsi; - -export namespace stormkit::wsi::linux::common { - namespace xkb { - using Keymap = RAIICapsule; - using State - = RAIICapsule; - using Context = RAIICapsule; - - struct Mods { - xkb_mod_index_t shift; - xkb_mod_index_t lock; - xkb_mod_index_t control; - xkb_mod_index_t mod1; - xkb_mod_index_t mod2; - xkb_mod_index_t mod3; - xkb_mod_index_t mod4; - xkb_mod_index_t mod5; - }; - } // namespace xkb - - auto stormkit_key_to_xkb(Key key) noexcept -> xkb_keysym_t; - auto xkb_key_to_stormkit(xkb_keysym_t key) noexcept -> Key; -} // namespace stormkit::wsi::linux::common - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stdr = std::ranges; -namespace stdv = std::views; - -namespace stormkit::wsi::linux::common { - namespace { - constexpr auto SCANCODE_AS_KEY = frozen::make_map({ - { XKB_KEY_a, Key::A }, - { XKB_KEY_b, Key::B }, - { XKB_KEY_c, Key::C }, - { XKB_KEY_d, Key::D }, - { XKB_KEY_e, Key::E }, - { XKB_KEY_f, Key::F }, - { XKB_KEY_g, Key::G }, - { XKB_KEY_h, Key::H }, - { XKB_KEY_i, Key::I }, - { XKB_KEY_j, Key::J }, - { XKB_KEY_k, Key::K }, - { XKB_KEY_l, Key::L }, - { XKB_KEY_m, Key::M }, - { XKB_KEY_n, Key::N }, - { XKB_KEY_o, Key::O }, - { XKB_KEY_p, Key::P }, - { XKB_KEY_q, Key::Q }, - { XKB_KEY_r, Key::R }, - { XKB_KEY_s, Key::S }, - { XKB_KEY_t, Key::T }, - { XKB_KEY_u, Key::U }, - { XKB_KEY_v, Key::V }, - { XKB_KEY_w, Key::W }, - { XKB_KEY_x, Key::X }, - { XKB_KEY_y, Key::Y }, - { XKB_KEY_z, Key::Z }, - - { XKB_KEY_0, Key::NUM_0 }, - { XKB_KEY_1, Key::NUM_1 }, - { XKB_KEY_2, Key::NUM_2 }, - { XKB_KEY_3, Key::NUM_3 }, - { XKB_KEY_4, Key::NUM_4 }, - { XKB_KEY_5, Key::NUM_5 }, - { XKB_KEY_6, Key::NUM_6 }, - { XKB_KEY_7, Key::NUM_7 }, - { XKB_KEY_8, Key::NUM_8 }, - { XKB_KEY_9, Key::NUM_9 }, - - { XKB_KEY_Left, Key::LEFT }, - { XKB_KEY_Right, Key::RIGHT }, - { XKB_KEY_Up, Key::UP }, - { XKB_KEY_Down, Key::DOWN }, - - { XKB_KEY_Control_L, Key::L_CONTROL }, - { XKB_KEY_Shift_L, Key::L_SHIFT }, - { XKB_KEY_Alt_L, Key::L_ALT }, - { XKB_KEY_Super_L, Key::L_META }, - { XKB_KEY_Control_R, Key::R_CONTROL }, - { XKB_KEY_Shift_R, Key::R_SHIFT }, - { XKB_KEY_Alt_R, Key::R_ALT }, - { XKB_KEY_Super_R, Key::R_META }, - - { XKB_KEY_Escape, Key::ESCAPE }, - { XKB_KEY_Tab, Key::TAB }, - { XKB_KEY_Menu, Key::MENU }, - - { XKB_KEY_apostrophe, Key::QUOTE }, - { XKB_KEY_backslash, Key::BACK_SLASH }, - { XKB_KEY_comma, Key::COMMA }, - { XKB_KEY_equal, Key::EQUAL }, - - { XKB_KEY_grave, Key::GRAVE_ACCENT }, - { XKB_KEY_bracketleft, Key::L_BRACKET }, - { XKB_KEY_minus, Key::MINUS }, - { XKB_KEY_period, Key::PERIOD }, - { XKB_KEY_bracketright, Key::R_BRACKET }, - { XKB_KEY_semicolon, Key::SEMI_COLON }, - { XKB_KEY_slash, Key::SLASH }, - - { XKB_KEY_less, Key::ISO }, - - { XKB_KEY_BackSpace, Key::BACK_SPACE }, - { XKB_KEY_Caps_Lock, Key::CAPS_LOCK }, - { XKB_KEY_Return, Key::ENTER }, - { XKB_KEY_space, Key::SPACE }, - - { XKB_KEY_F1, Key::F1 }, - { XKB_KEY_F2, Key::F2 }, - { XKB_KEY_F3, Key::F3 }, - { XKB_KEY_F4, Key::F4 }, - { XKB_KEY_F5, Key::F5 }, - { XKB_KEY_F6, Key::F6 }, - { XKB_KEY_F7, Key::F7 }, - { XKB_KEY_F8, Key::F8 }, - { XKB_KEY_F9, Key::F9 }, - { XKB_KEY_F10, Key::F10 }, - { XKB_KEY_F11, Key::F11 }, - { XKB_KEY_F12, Key::F12 }, - { XKB_KEY_F14, Key::F14 }, - { XKB_KEY_F15, Key::F15 }, - { XKB_KEY_F16, Key::F16 }, - { XKB_KEY_F17, Key::F17 }, - { XKB_KEY_F18, Key::F18 }, - { XKB_KEY_F19, Key::F19 }, - { XKB_KEY_F20, Key::F20 }, - - { XKB_KEY_Print, Key::PRINT_SCREEN }, - - { XKB_KEY_Insert, Key::INSERT }, - { XKB_KEY_Delete, Key::DELETE }, - { XKB_KEY_Home, Key::HOME }, - { XKB_KEY_End, Key::END }, - { XKB_KEY_Page_Down, Key::PAGE_DOWN }, - { XKB_KEY_Page_Up, Key::PAGE_UP }, - - { XKB_KEY_Num_Lock, Key::NUMPAD_LOCK }, - { XKB_KEY_KP_Add, Key::NUMPAD_ADD }, - { XKB_KEY_KP_Decimal, Key::NUMPAD_DECIMAL }, - { XKB_KEY_KP_Divide, Key::NUMPAD_DIVIDE }, - { XKB_KEY_KP_Enter, Key::NUMPAD_ENTER }, - { XKB_KEY_KP_Equal, Key::NUMPAD_EQUAL }, - { XKB_KEY_KP_Multiply, Key::NUMPAD_MULTIPLY }, - { XKB_KEY_KP_Subtract, Key::NUMPAD_SUBTRACT }, - { XKB_KEY_KP_0, Key::NUMPAD_0 }, - { XKB_KEY_KP_1, Key::NUMPAD_1 }, - { XKB_KEY_KP_2, Key::NUMPAD_2 }, - { XKB_KEY_KP_3, Key::NUMPAD_3 }, - { XKB_KEY_KP_4, Key::NUMPAD_4 }, - { XKB_KEY_KP_5, Key::NUMPAD_5 }, - { XKB_KEY_KP_6, Key::NUMPAD_6 }, - { XKB_KEY_KP_7, Key::NUMPAD_7 }, - { XKB_KEY_KP_8, Key::NUMPAD_8 }, - { XKB_KEY_KP_9, Key::NUMPAD_9 }, - }); - - constexpr auto KEY_AS_SCANCODE = [] static noexcept -> decltype(auto) { - auto out = std::array, 111> {}; - auto i = 0_usize; - for (const auto& [key, value] : SCANCODE_AS_KEY) out[i++] = std::make_pair(value, key); - - return frozen::make_map(out); - }(); - } // namespace - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_CONST - inline auto xkb_key_to_stormkit(xkb_keysym_t scancode) noexcept -> Key { - const auto it = SCANCODE_AS_KEY.find(scancode); - if (it == stdr::cend(SCANCODE_AS_KEY)) return Key::UNKNOWN; - return it->second; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_CONST - inline auto stormkit_key_to_xkb(Key key) noexcept -> xkb_keysym_t { - ENSURES(key != Key::UNKNOWN); - const auto it = KEY_AS_SCANCODE.find(key); - return it->second; - } -} // namespace stormkit::wsi::linux::common - -#undef STORMKIT_XKB_SCOPED +// Copyright (C) 2021 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +#include +#include + +export module stormkit.wsi:linux.common.xkb; + +import std; +import frozen; + +import stormkit.core; +import stormkit.log; +import stormkit.wsi; + +export namespace stormkit::wsi::linux::common { + namespace xkb { + using Keymap = RAIICapsule; + using State = RAIICapsule; + using Context = RAIICapsule; + + struct Mods { + xkb_mod_index_t shift; + xkb_mod_index_t lock; + xkb_mod_index_t control; + xkb_mod_index_t mod1; + xkb_mod_index_t mod2; + xkb_mod_index_t mod3; + xkb_mod_index_t mod4; + xkb_mod_index_t mod5; + }; + } // namespace xkb + + auto stormkit_key_to_xkb(Key key) noexcept -> xkb_keysym_t; + auto xkb_key_to_stormkit(xkb_keysym_t key) noexcept -> Key; +} // namespace stormkit::wsi::linux::common + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stdr = std::ranges; +namespace stdv = std::views; + +namespace stormkit::wsi::linux::common { + namespace { + constexpr auto SCANCODE_AS_KEY = frozen::make_map({ + { XKB_KEY_a, Key::A }, + { XKB_KEY_b, Key::B }, + { XKB_KEY_c, Key::C }, + { XKB_KEY_d, Key::D }, + { XKB_KEY_e, Key::E }, + { XKB_KEY_f, Key::F }, + { XKB_KEY_g, Key::G }, + { XKB_KEY_h, Key::H }, + { XKB_KEY_i, Key::I }, + { XKB_KEY_j, Key::J }, + { XKB_KEY_k, Key::K }, + { XKB_KEY_l, Key::L }, + { XKB_KEY_m, Key::M }, + { XKB_KEY_n, Key::N }, + { XKB_KEY_o, Key::O }, + { XKB_KEY_p, Key::P }, + { XKB_KEY_q, Key::Q }, + { XKB_KEY_r, Key::R }, + { XKB_KEY_s, Key::S }, + { XKB_KEY_t, Key::T }, + { XKB_KEY_u, Key::U }, + { XKB_KEY_v, Key::V }, + { XKB_KEY_w, Key::W }, + { XKB_KEY_x, Key::X }, + { XKB_KEY_y, Key::Y }, + { XKB_KEY_z, Key::Z }, + + { XKB_KEY_0, Key::NUM_0 }, + { XKB_KEY_1, Key::NUM_1 }, + { XKB_KEY_2, Key::NUM_2 }, + { XKB_KEY_3, Key::NUM_3 }, + { XKB_KEY_4, Key::NUM_4 }, + { XKB_KEY_5, Key::NUM_5 }, + { XKB_KEY_6, Key::NUM_6 }, + { XKB_KEY_7, Key::NUM_7 }, + { XKB_KEY_8, Key::NUM_8 }, + { XKB_KEY_9, Key::NUM_9 }, + + { XKB_KEY_Left, Key::LEFT }, + { XKB_KEY_Right, Key::RIGHT }, + { XKB_KEY_Up, Key::UP }, + { XKB_KEY_Down, Key::DOWN }, + + { XKB_KEY_Control_L, Key::L_CONTROL }, + { XKB_KEY_Shift_L, Key::L_SHIFT }, + { XKB_KEY_Alt_L, Key::L_ALT }, + { XKB_KEY_Super_L, Key::L_META }, + { XKB_KEY_Control_R, Key::R_CONTROL }, + { XKB_KEY_Shift_R, Key::R_SHIFT }, + { XKB_KEY_Alt_R, Key::R_ALT }, + { XKB_KEY_Super_R, Key::R_META }, + + { XKB_KEY_Escape, Key::ESCAPE }, + { XKB_KEY_Tab, Key::TAB }, + { XKB_KEY_Menu, Key::MENU }, + + { XKB_KEY_apostrophe, Key::QUOTE }, + { XKB_KEY_backslash, Key::BACK_SLASH }, + { XKB_KEY_comma, Key::COMMA }, + { XKB_KEY_equal, Key::EQUAL }, + + { XKB_KEY_grave, Key::GRAVE_ACCENT }, + { XKB_KEY_bracketleft, Key::L_BRACKET }, + { XKB_KEY_minus, Key::MINUS }, + { XKB_KEY_period, Key::PERIOD }, + { XKB_KEY_bracketright, Key::R_BRACKET }, + { XKB_KEY_semicolon, Key::SEMI_COLON }, + { XKB_KEY_slash, Key::SLASH }, + + { XKB_KEY_less, Key::ISO }, + + { XKB_KEY_BackSpace, Key::BACK_SPACE }, + { XKB_KEY_Caps_Lock, Key::CAPS_LOCK }, + { XKB_KEY_Return, Key::ENTER }, + { XKB_KEY_space, Key::SPACE }, + + { XKB_KEY_F1, Key::F1 }, + { XKB_KEY_F2, Key::F2 }, + { XKB_KEY_F3, Key::F3 }, + { XKB_KEY_F4, Key::F4 }, + { XKB_KEY_F5, Key::F5 }, + { XKB_KEY_F6, Key::F6 }, + { XKB_KEY_F7, Key::F7 }, + { XKB_KEY_F8, Key::F8 }, + { XKB_KEY_F9, Key::F9 }, + { XKB_KEY_F10, Key::F10 }, + { XKB_KEY_F11, Key::F11 }, + { XKB_KEY_F12, Key::F12 }, + { XKB_KEY_F14, Key::F14 }, + { XKB_KEY_F15, Key::F15 }, + { XKB_KEY_F16, Key::F16 }, + { XKB_KEY_F17, Key::F17 }, + { XKB_KEY_F18, Key::F18 }, + { XKB_KEY_F19, Key::F19 }, + { XKB_KEY_F20, Key::F20 }, + + { XKB_KEY_Print, Key::PRINT_SCREEN }, + + { XKB_KEY_Insert, Key::INSERT }, + { XKB_KEY_Delete, Key::DELETE }, + { XKB_KEY_Home, Key::HOME }, + { XKB_KEY_End, Key::END }, + { XKB_KEY_Page_Down, Key::PAGE_DOWN }, + { XKB_KEY_Page_Up, Key::PAGE_UP }, + + { XKB_KEY_Num_Lock, Key::NUMPAD_LOCK }, + { XKB_KEY_KP_Add, Key::NUMPAD_ADD }, + { XKB_KEY_KP_Decimal, Key::NUMPAD_DECIMAL }, + { XKB_KEY_KP_Divide, Key::NUMPAD_DIVIDE }, + { XKB_KEY_KP_Enter, Key::NUMPAD_ENTER }, + { XKB_KEY_KP_Equal, Key::NUMPAD_EQUAL }, + { XKB_KEY_KP_Multiply, Key::NUMPAD_MULTIPLY }, + { XKB_KEY_KP_Subtract, Key::NUMPAD_SUBTRACT }, + { XKB_KEY_KP_0, Key::NUMPAD_0 }, + { XKB_KEY_KP_1, Key::NUMPAD_1 }, + { XKB_KEY_KP_2, Key::NUMPAD_2 }, + { XKB_KEY_KP_3, Key::NUMPAD_3 }, + { XKB_KEY_KP_4, Key::NUMPAD_4 }, + { XKB_KEY_KP_5, Key::NUMPAD_5 }, + { XKB_KEY_KP_6, Key::NUMPAD_6 }, + { XKB_KEY_KP_7, Key::NUMPAD_7 }, + { XKB_KEY_KP_8, Key::NUMPAD_8 }, + { XKB_KEY_KP_9, Key::NUMPAD_9 }, + }); + + constexpr auto KEY_AS_SCANCODE = [] static noexcept -> decltype(auto) { + auto out = array, 111> {}; + auto i = 0_usize; + for (const auto& [key, value] : SCANCODE_AS_KEY) out[i++] = std::make_pair(value, key); + + return frozen::make_map(out); + }(); + } // namespace + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_CONST + inline auto xkb_key_to_stormkit(xkb_keysym_t scancode) noexcept -> Key { + const auto it = SCANCODE_AS_KEY.find(scancode); + if (it == stdr::cend(SCANCODE_AS_KEY)) return Key::UNKNOWN; + return it->second; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_CONST + inline auto stormkit_key_to_xkb(Key key) noexcept -> xkb_keysym_t { + ENSURES(key != Key::UNKNOWN); + const auto it = KEY_AS_SCANCODE.find(key); + return it->second; + } +} // namespace stormkit::wsi::linux::common + +#undef STORMKIT_XKB_SCOPED diff --git a/src/wsi/linux/monitor.mpp b/src/wsi/linux/monitor.cppm similarity index 92% rename from src/wsi/linux/monitor.mpp rename to src/wsi/linux/monitor.cppm index 41a59e196..954813fdb 100644 --- a/src/wsi/linux/monitor.mpp +++ b/src/wsi/linux/monitor.cppm @@ -15,7 +15,7 @@ import :linux.x11.monitor; namespace stormkit::wsi::linux { ///////////////////////////////////// ///////////////////////////////////// - auto get_monitors(WM wm, bool update = false) noexcept -> std::span { + auto get_monitors(WM wm, bool update = false) noexcept -> array_view { switch (wm) { case WM::X11: return x11::get_monitors(wm, update); case WM::WAYLAND: return wayland::get_monitors(wm, update); diff --git a/src/wsi/linux/mouse.cppm b/src/wsi/linux/mouse.cppm new file mode 100644 index 000000000..e69de29bb diff --git a/src/wsi/linux/wayland/context.cpp b/src/wsi/linux/wayland/context.cpp index 91e96a760..fcb14876a 100644 --- a/src/wsi/linux/wayland/context.cpp +++ b/src/wsi/linux/wayland/context.cpp @@ -83,10 +83,10 @@ namespace stormkit::wsi::linux::wayland::wl { }; struct RegistryBinder { - const wl_interface* interface; - FunctionRef bind; - u32 version = 1; - FunctionRef after_bind = monadic::noop(); + const wl_interface* interface; + std23::function_ref bind; + u32 version = 1; + std23::function_ref after_bind = monadic::noop(); }; ///////////////////////////////////// @@ -95,7 +95,7 @@ namespace stormkit::wsi::linux::wayland::wl { constexpr auto make_binder() noexcept -> decltype(auto) { return [](Globals& _globals, void* ptr) static noexcept { using U = meta::ToPlainType; - (_globals.*member) = U::take(std::bit_cast>(ptr)); + (_globals.*member) = U::take(std::bit_cast>(ptr)); }; } @@ -105,8 +105,8 @@ namespace stormkit::wsi::linux::wayland::wl { constexpr auto make_binder_to_array() noexcept -> decltype(auto) { return [](Globals& _globals, void* ptr) static noexcept { using Vec = meta::ToPlainType; - using U = meta::UnderlyingType; - (_globals.*member).push_back(U::take(std::bit_cast>(ptr))); + using U = meta::ValueType; + (_globals.*member).push_back(U::take(std::bit_cast>(ptr))); }; } @@ -225,7 +225,7 @@ namespace stormkit::wsi::linux::wayland::wl { auto& _globals = *std::bit_cast(data); - const auto interface_name = std::string_view { interface, std::char_traits::length(interface) }; + const auto interface_name = string_view { interface, std::char_traits::length(interface) }; const auto it = INTERFACE_MAP.find(interface_name); if (it == stdr::cend(INTERFACE_MAP)) return; diff --git a/src/wsi/linux/wayland/context.cppm b/src/wsi/linux/wayland/context.cppm new file mode 100644 index 000000000..427a232d1 --- /dev/null +++ b/src/wsi/linux/wayland/context.cppm @@ -0,0 +1,77 @@ + +// Copyright (C) 2021 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include + +#include +#include +#include + +#include + +export module stormkit.wsi:linux.wayland.context; + +import std; + +import stormkit.core; + +import :linux.common.fd; +import :linux.common.xkb; +import :linux.wayland; +import :linux.wayland.input; + +export namespace stormkit::wsi::linux::wayland { + class Window; + + namespace wl { + struct WaylandMonitor { + uptr id; + wsi::Monitor monitor; + }; + + struct Globals { + bool initialized = false; + wl::Display display = wl::Display::empty(); + wl::Registry registry = wl::Registry::empty(); + wl::Compositor compositor = wl::Compositor::empty(); + dyn_array outputs; + wl::XDGWmBase xdg_wm_base = wl::XDGWmBase::empty(); + wl::Shm shm = wl::Shm::empty(); + wl::XDGDecorationManager decoration_manager = wl::XDGDecorationManager::empty(); + wl::Seat seat = wl::Seat::empty(); + wl::SinglePixelBufferManager single_pixel_buffer_manager = wl::SinglePixelBufferManager::empty(); + wl::Viewporter viewporter = wl::Viewporter::empty(); + wl::CursorShapeManager cursor_shape_manager = wl::CursorShapeManager::empty(); + wl::CursorShapeDevice cursor_shape_device = wl::CursorShapeDevice::empty(); + wl::PointerWarp pointer_warp = wl::PointerWarp::empty(); + wl::PointerConstraints pointer_constraints = wl::PointerConstraints::empty(); + wl::ContentTypeManager content_type_manager = wl::ContentTypeManager::empty(); + + wl::CursorTheme cursor_theme = wl::CursorTheme::empty(); + wl::CursorTheme cursor_theme_high_dpi = wl::CursorTheme::empty(); + + dyn_array> keyboards; + dyn_array> pointers; + dyn_array> touchs; + + wl::RelativePointerManager relative_pointer_manager = wl::RelativePointerManager::empty(); + + dyn_array monitors; + + dyn_array> windows; + + common::xkb::Context xkb_context = common::xkb::Context::empty(); + }; + + auto init() noexcept -> bool; + auto get_globals() noexcept -> Globals&; + auto get_monitor(Globals& _globals, void* output) noexcept -> Monitor&; + } // namespace wl +} // namespace stormkit::wsi::linux::wayland + +FLAG_ENUM(stormkit::wsi::linux::wayland::wl::PointerState::Flag); diff --git a/src/wsi/linux/wayland/context.mpp b/src/wsi/linux/wayland/context.mpp deleted file mode 100644 index 4923ee580..000000000 --- a/src/wsi/linux/wayland/context.mpp +++ /dev/null @@ -1,79 +0,0 @@ - -// Copyright (C) 2021 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include -#include - -#include -#include -#include - -#include - -export module stormkit.wsi:linux.wayland.context; - -import std; - -import stormkit.core; - -import :linux.common.fd; -import :linux.common.xkb; -import :linux.wayland; -import :linux.wayland.input; - -export namespace stormkit::wsi::linux::wayland { - class Window; - - namespace wl { - struct WaylandMonitor { - uptr id; - wsi::Monitor monitor; - }; - - struct Globals { - bool initialized = false; - wl::Display display = wl::Display::empty(); - wl::Registry registry = wl::Registry::empty(); - wl::Compositor compositor = wl::Compositor::empty(); - std::vector outputs; - wl::XDGWmBase xdg_wm_base = wl::XDGWmBase::empty(); - wl::Shm shm = wl::Shm::empty(); - wl::XDGDecorationManager decoration_manager = wl::XDGDecorationManager::empty(); - wl::Seat seat = wl::Seat::empty(); - wl::SinglePixelBufferManager - single_pixel_buffer_manager = wl::SinglePixelBufferManager::empty(); - wl::Viewporter viewporter = wl::Viewporter::empty(); - wl::CursorShapeManager cursor_shape_manager = wl::CursorShapeManager::empty(); - wl::CursorShapeDevice cursor_shape_device = wl::CursorShapeDevice::empty(); - wl::PointerWarp pointer_warp = wl::PointerWarp::empty(); - wl::PointerConstraints pointer_constraints = wl::PointerConstraints::empty(); - wl::ContentTypeManager content_type_manager = wl::ContentTypeManager::empty(); - - wl::CursorTheme cursor_theme = wl::CursorTheme::empty(); - wl::CursorTheme cursor_theme_high_dpi = wl::CursorTheme::empty(); - - std::vector> keyboards; - std::vector> pointers; - std::vector> touchs; - - wl::RelativePointerManager - relative_pointer_manager = wl::RelativePointerManager::empty(); - - std::vector monitors; - - std::vector> windows; - - common::xkb::Context xkb_context = common::xkb::Context::empty(); - }; - - auto init() noexcept -> bool; - auto get_globals() noexcept -> Globals&; - auto get_monitor(Globals& _globals, void* output) noexcept -> Monitor&; - } // namespace wl -} // namespace stormkit::wsi::linux::wayland - -FLAG_ENUM(stormkit::wsi::linux::wayland::wl::PointerState::Flag); diff --git a/src/wsi/linux/wayland/inputs.cpp b/src/wsi/linux/wayland/inputs.cpp index 577fcc931..d9ffeb8ce 100644 --- a/src/wsi/linux/wayland/inputs.cpp +++ b/src/wsi/linux/wayland/inputs.cpp @@ -36,7 +36,7 @@ namespace stormkit::wsi::linux::wayland::wl { auto keyboard_key_handler(void*, wl_keyboard*, u32, u32, u32, u32) noexcept -> void; auto keyboard_modifiers_handler(void*, wl_keyboard*, u32, u32, u32, u32, u32) noexcept -> void; auto keyboard_repeat_info_handler(void*, wl_keyboard*, i32, i32) noexcept -> void; - auto update_keymap(KeyboardState&, std::string_view) noexcept -> void; + auto update_keymap(KeyboardState&, string_view) noexcept -> void; auto pointer_enter_handler(void*, wl_pointer*, u32, wl_surface*, wl_fixed_t, wl_fixed_t) noexcept -> void; auto pointer_leave_handler(void*, wl_pointer*, u32, wl_surface*) noexcept -> void; @@ -140,7 +140,7 @@ namespace stormkit::wsi::linux::wayland::wl { if (format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { auto map_shm = std::bit_cast(mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0)); - update_keymap(state, std::string_view { map_shm, size }); + update_keymap(state, string_view { map_shm, size }); munmap(map_shm, size); ::close(fd); @@ -154,7 +154,7 @@ namespace stormkit::wsi::linux::wayland::wl { auto& state = *std::bit_cast(data); if (not state.focused_window or not state.xkb_state) return; - auto characters = std::array {}; + auto characters = array {}; // stdr const auto keycode = key + 8; @@ -218,7 +218,7 @@ namespace stormkit::wsi::linux::wayland::wl { ///////////////////////////////////// ///////////////////////////////////// - auto update_keymap(KeyboardState& state, std::string_view keymap) noexcept -> void { + auto update_keymap(KeyboardState& state, string_view keymap) noexcept -> void { auto& globals = get_globals(); state.xkb_keymap = common::xkb::Keymap::create(globals.xkb_context, std::data(keymap), diff --git a/src/wsi/linux/wayland/inputs.mpp b/src/wsi/linux/wayland/inputs.cppm similarity index 98% rename from src/wsi/linux/wayland/inputs.mpp rename to src/wsi/linux/wayland/inputs.cppm index 7879b4b95..2a1e5fe24 100644 --- a/src/wsi/linux/wayland/inputs.mpp +++ b/src/wsi/linux/wayland/inputs.cppm @@ -41,14 +41,14 @@ export namespace stormkit::wsi::linux::wayland { std::optional serial = std::nullopt; - std::array button_state; + array button_state; wl::ConfinedPointer confined_pointer = wl::ConfinedPointer::empty(); wl::LockedPointer locked_pointer = wl::LockedPointer::empty(); wl::RelativePointer relative_pointer = wl::RelativePointer::empty(); struct Cursor { - std::string name; + string name; wl::Surface surface = wl::Surface::empty(); wl::CursorShapeDevice shape_device = wl::CursorShapeDevice::empty(); @@ -85,7 +85,7 @@ export namespace stormkit::wsi::linux::wayland { Window* focused_window = nullptr; - std::array keyboard_state = { + array keyboard_state = { KeyState { XKB_KEY_a, false }, KeyState { XKB_KEY_b, false }, KeyState { XKB_KEY_c, false }, diff --git a/src/wsi/linux/wayland/log.mpp b/src/wsi/linux/wayland/log.cppm similarity index 96% rename from src/wsi/linux/wayland/log.mpp rename to src/wsi/linux/wayland/log.cppm index 51602908f..fa340748f 100644 --- a/src/wsi/linux/wayland/log.mpp +++ b/src/wsi/linux/wayland/log.cppm @@ -1,18 +1,18 @@ -// Copyright (C) 2021 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -export module stormkit.wsi:linux.wayland.log; - -import std; - -import stormkit.core; -import stormkit.log; - -export namespace stormkit::wsi::linux::wayland { - IN_MODULE_LOGGER("StormKit.Wsi.Linux.Wayland") -} // namespace stormkit::wsi::linux::wayland +// Copyright (C) 2021 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +export module stormkit.wsi:linux.wayland.log; + +import std; + +import stormkit.core; +import stormkit.log; + +export namespace stormkit::wsi::linux::wayland { + IN_MODULE_LOGGER("StormKit.Wsi.Linux.Wayland") +} // namespace stormkit::wsi::linux::wayland diff --git a/src/wsi/linux/wayland/monitor.mpp b/src/wsi/linux/wayland/monitor.cppm similarity index 66% rename from src/wsi/linux/wayland/monitor.mpp rename to src/wsi/linux/wayland/monitor.cppm index b08fe072f..3aad60239 100644 --- a/src/wsi/linux/wayland/monitor.mpp +++ b/src/wsi/linux/wayland/monitor.cppm @@ -17,15 +17,13 @@ namespace stdv = std::views; namespace stormkit::wsi::linux::wayland { ///////////////////////////////////// ///////////////////////////////////// - auto get_monitors(WM, bool update) noexcept -> std::span { - thread_local auto monitors = std::vector {}; + auto get_monitors(WM, bool update) noexcept -> array_view { + thread_local auto monitors = dyn_array {}; if (update or stdr::empty(monitors)) { auto& globals = wl::get_globals(); monitors = globals.monitors - | stdv::transform([](const wl::WaylandMonitor& pair) static noexcept { - return pair.monitor; - }) - | stdr::to(); + | stdv::transform([](const wl::WaylandMonitor& pair) static noexcept { return pair.monitor; }) + | stdr::to>(); } return monitors; diff --git a/src/wsi/linux/wayland/wayland.cppm b/src/wsi/linux/wayland/wayland.cppm new file mode 100644 index 000000000..8b0e7ec6d --- /dev/null +++ b/src/wsi/linux/wayland/wayland.cppm @@ -0,0 +1,123 @@ +// Copyright (C) 2021 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +export module stormkit.wsi:linux.wayland; + +import std; + +import stormkit.core; + +import stormkit.wsi; + +export namespace stormkit::wsi::linux::wayland::wl { + using Display = stormkit::RAIICapsule; + using Registry = stormkit:: + RAIICapsule; + using Compositor = stormkit:: + RAIICapsule; + using Output = stormkit::RAIICapsule; + using XDGWmBase = stormkit::RAIICapsule; + using XDGDecorationManager = stormkit::RAIICapsule< + zxdg_decoration_manager_v1*, + monadic::noop(), + zxdg_decoration_manager_v1_destroy, + struct XDGDescorationManagerTag, + nullptr>; + using Buffer = stormkit::RAIICapsule; + using Keyboard = stormkit::RAIICapsule; + using Pointer = stormkit::RAIICapsule; + using Touch = stormkit::RAIICapsule; + using Shm = stormkit::RAIICapsule; + using Seat = stormkit::RAIICapsule; + using SinglePixelBufferManager = stormkit::RAIICapsule< + wp_single_pixel_buffer_manager_v1*, + monadic::noop(), + wp_single_pixel_buffer_manager_v1_destroy, + struct SinglePixelBufferManagerTag, + nullptr>; + using Viewporter = stormkit:: + RAIICapsule; + using ContentTypeManager = stormkit::RAIICapsule; + + using ShmPool = stormkit::RAIICapsule; + using CursorTheme = stormkit:: + RAIICapsule; + using CursorShapeManager = stormkit::RAIICapsule; + using CursorShapeDevice = stormkit::RAIICapsule; + using PointerConstraints = stormkit::RAIICapsule; + using PointerWarp = stormkit:: + RAIICapsule; + using RelativePointerManager = stormkit::RAIICapsule< + zwp_relative_pointer_manager_v1*, + monadic::noop(), + zwp_relative_pointer_manager_v1_destroy, + struct RelativePointerManagerTag, + nullptr>; + + using Surface = stormkit:: + RAIICapsule; + using XDGSurface = stormkit:: + RAIICapsule; + using XDGTopLevel = stormkit:: + RAIICapsule; + using XDGTopLevelDecoration = stormkit::RAIICapsule< + zxdg_toplevel_decoration_v1*, + zxdg_decoration_manager_v1_get_toplevel_decoration, + zxdg_toplevel_decoration_v1_destroy, + struct XDGTopLevelDecorationTag, + nullptr>; + using LockedPointer = stormkit::RAIICapsule; + using ConfinedPointer = stormkit::RAIICapsule; + using RelativePointer = stormkit::RAIICapsule; + using Viewport = stormkit:: + RAIICapsule; + using ContentType = stormkit::RAIICapsule; +} // namespace stormkit::wsi::linux::wayland::wl diff --git a/src/wsi/linux/wayland/wayland.mpp b/src/wsi/linux/wayland/wayland.mpp deleted file mode 100644 index 07e6c194b..000000000 --- a/src/wsi/linux/wayland/wayland.mpp +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright (C) 2021 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -export module stormkit.wsi:linux.wayland; - -import std; - -import stormkit.core; - -import stormkit.wsi; - -export namespace stormkit::wsi::linux::wayland::wl { - using Display = stormkit::RAIICapsule; - using Registry = stormkit::RAIICapsule; - using Compositor = stormkit::RAIICapsule; - using Output = stormkit:: - RAIICapsule; - using XDGWmBase = stormkit:: - RAIICapsule; - using XDGDecorationManager = stormkit::RAIICapsule; - using Buffer = stormkit:: - RAIICapsule; - using Keyboard = stormkit::RAIICapsule; - using Pointer = stormkit:: - RAIICapsule; - using Touch = stormkit:: - RAIICapsule; - using Shm = stormkit:: - RAIICapsule; - using Seat = stormkit:: - RAIICapsule; - using SinglePixelBufferManager = stormkit::RAIICapsule< - wp_single_pixel_buffer_manager_v1*, - monadic::noop(), - wp_single_pixel_buffer_manager_v1_destroy, - struct SinglePixelBufferManagerTag, - nullptr>; - using Viewporter = stormkit::RAIICapsule; - using ContentTypeManager = stormkit::RAIICapsule; - - using ShmPool = stormkit::RAIICapsule; - using CursorTheme = stormkit::RAIICapsule; - using CursorShapeManager = stormkit::RAIICapsule; - using CursorShapeDevice = stormkit::RAIICapsule; - using PointerConstraints = stormkit::RAIICapsule; - using PointerWarp = stormkit::RAIICapsule; - using RelativePointerManager = stormkit::RAIICapsule; - - using Surface = stormkit::RAIICapsule; - using XDGSurface = stormkit::RAIICapsule; - using XDGTopLevel = stormkit::RAIICapsule; - using XDGTopLevelDecoration = stormkit::RAIICapsule< - zxdg_toplevel_decoration_v1*, - zxdg_decoration_manager_v1_get_toplevel_decoration, - zxdg_toplevel_decoration_v1_destroy, - struct XDGTopLevelDecorationTag, - nullptr>; - using LockedPointer = stormkit::RAIICapsule; - using ConfinedPointer = stormkit::RAIICapsule; - using RelativePointer = stormkit::RAIICapsule< - zwp_relative_pointer_v1*, - zwp_relative_pointer_manager_v1_get_relative_pointer, - zwp_relative_pointer_v1_destroy, - struct RelativePointerTag, - nullptr>; - using Viewport = stormkit::RAIICapsule; - using ContentType = stormkit::RAIICapsule; -} // namespace stormkit::wsi::linux::wayland::wl diff --git a/src/wsi/linux/wayland/window.cpp b/src/wsi/linux/wayland/window.cpp index 46c2b851e..891abc253 100644 --- a/src/wsi/linux/wayland/window.cpp +++ b/src/wsi/linux/wayland/window.cpp @@ -114,7 +114,7 @@ namespace stormkit::wsi::linux::wayland { ///////////////////////////////////// ///////////////////////////////////// - auto Window::open(std::string title, const math::Extent2& extent, WindowFlag flags) noexcept -> void { + auto Window::open(string title, const math::uextent2& extent, WindowFlag flags) noexcept -> void { auto& globals = wl::get_globals(); m_surface = wl::Surface::create(globals.compositor); @@ -194,10 +194,10 @@ namespace stormkit::wsi::linux::wayland { ///////////////////////////////////// ///////////////////////////////////// - auto Window::clear(const rgbcolor& color) noexcept -> void { + auto Window::clear(const ucolor_rgb& color) noexcept -> void { const auto value = (255 << 24) + (color.r << 16) + (color.g << 8) + (color.b); - auto view = std::span { std::bit_cast(m_shm_buffer.get().begin()), m_shm_buffer->size() / sizeof(i32) }; + auto view = array_view { std::bit_cast(m_shm_buffer.value().begin()), m_shm_buffer->size() / sizeof(i32) }; stdr::fill(view, value); const auto [width, height] = extent().to(); @@ -207,8 +207,8 @@ namespace stormkit::wsi::linux::wayland { ///////////////////////////////////// ///////////////////////////////////// - auto Window::fill_framebuffer(std::span> colors) noexcept -> void { - auto view = std::span { std::bit_cast(m_shm_buffer.get().begin()), m_shm_buffer->size() / sizeof(i32) }; + auto Window::fill_framebuffer(array_view colors) noexcept -> void { + auto view = array_view { std::bit_cast(m_shm_buffer.value().begin()), m_shm_buffer->size() / sizeof(i32) }; stdr::copy(colors | stdv::transform([](const auto& color) static noexcept { return (255 << 24) + (color.r << 16) + (color.g << 8) + (color.b); }), @@ -221,7 +221,7 @@ namespace stormkit::wsi::linux::wayland { ///////////////////////////////////// ///////////////////////////////////// - auto Window::set_title(std::string title) noexcept -> void { + auto Window::set_title(string title) noexcept -> void { if (!m_state.open) return; m_title = std::move(title); @@ -230,7 +230,7 @@ namespace stormkit::wsi::linux::wayland { ///////////////////////////////////// ///////////////////////////////////// - auto Window::set_extent(const math::Extent2&) noexcept -> void { + auto Window::set_extent(const math::uextent2&) noexcept -> void { } ///////////////////////////////////// @@ -261,11 +261,8 @@ namespace stormkit::wsi::linux::wayland { if (confined) { if (not check_flag_bit(state.flags, wl::PointerState::Flag::CONFINED)) { - state.confined_pointer = wl::ConfinedPointer ::create(globals.pointer_constraints, - m_surface, - pointer, - nullptr, - ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT); + state.confined_pointer = wl::ConfinedPointer :: + create(globals.pointer_constraints, m_surface, pointer, nullptr, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT); zwp_confined_pointer_v1_add_listener(state.confined_pointer, &wl::g_confined_pointer_listener, &state); state.flags |= wl::PointerState::Flag::CONFINED; @@ -430,7 +427,7 @@ namespace stormkit::wsi::linux::wayland { ///////////////////////////////////// ///////////////////////////////////// - auto Window::set_mouse_position(const math::vec2i& position, u8 mouse_id) noexcept -> void { + auto Window::set_mouse_position(const math::ivec2& position, u8 mouse_id) noexcept -> void { if (not m_state.open) return; auto& globals = wl::get_globals(); @@ -502,7 +499,7 @@ namespace stormkit::wsi::linux::wayland { ///////////////////////////////////// ///////////////////////////////////// - auto Window::handle_xdg_top_level_configure(u32 width, u32 height, std::span states) noexcept + auto Window::handle_xdg_top_level_configure(u32 width, u32 height, array_view states) noexcept -> void { m_state.open = true; @@ -606,14 +603,14 @@ namespace stormkit::wsi::linux::wayland { auto old_pixel_buffer = DeferInit {}; const auto [width, height] = extent.to(); - if (not m_shm_buffer or stdr::size(m_shm_buffer.get()) < size) { + if (not m_shm_buffer or stdr::size(m_shm_buffer.value()) < size) { old_shm_buffer = std::move(m_shm_buffer); old_shm_pool = std::move(m_shm_pool); old_pixel_buffer = std::move(m_pixel_buffer); - SHMBuffer::create(size, std::format("StormKit::{}::PixelBuffer", m_title)) - .transform(bind_front(&DeferInit::construct, &m_shm_buffer)) - .transform_error(monadic::assert()); + auto _ = SHMBuffer::create(size, std::format("StormKit::{}::PixelBuffer", m_title)) + .transform(bind_front(&DeferInit::construct, &m_shm_buffer)) + .transform_error(monadic::assert()); m_shm_pool = wl::ShmPool::create(globals.shm, narrow(std::bit_cast(m_shm_buffer->native_handle())), @@ -663,7 +660,7 @@ namespace stormkit::wsi::linux::wayland { ///////////////////////////////////// ///////////////////////////////////// - auto Window::set_cursor(std::string_view name, wl_pointer* pointer, wl::PointerState& state) noexcept -> void { + auto Window::set_cursor(string_view name, wl_pointer* pointer, wl::PointerState& state) noexcept -> void { auto& globals = wl::get_globals(); auto cursor_theme = globals.cursor_theme.handle(); diff --git a/src/wsi/linux/wayland/window.mpp b/src/wsi/linux/wayland/window.cppm similarity index 74% rename from src/wsi/linux/wayland/window.mpp rename to src/wsi/linux/wayland/window.cppm index e73d02345..c0b780455 100644 --- a/src/wsi/linux/wayland/window.mpp +++ b/src/wsi/linux/wayland/window.cppm @@ -1,158 +1,153 @@ -// Copyright (C) 2021 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include -#include - -#include - -#include -#include -#include - -export module stormkit.wsi:linux.wayland.window; - -import std; - -import stormkit.core; -import stormkit.wsi; - -import :common.window_base; - -import :linux.wayland; -import :linux.wayland.context; - -export { - namespace stormkit::wsi::linux::wayland { - class Window: public stormkit::wsi::common::WindowBase { - public: - struct Handles { - wl_display* display; - wl_surface* surface; - }; - - Window() noexcept; - ~Window() noexcept; - - Window(const Window&) noexcept = delete; - auto operator=(const Window&) noexcept -> Window& = delete; - - Window(Window&&) noexcept; - auto operator=(Window&&) noexcept -> Window&; - - auto open(std::string title, const math::Extent2& size, WindowFlag flags) noexcept - -> void; - auto close() noexcept -> void; - - auto handle_events() noexcept -> void; - - auto clear(const rgbcolor& color) noexcept -> void; - auto fill_framebuffer(std::span> colors) noexcept -> void; - - auto set_title(std::string title) noexcept -> void; - auto set_extent(const math::Extent2& extent) noexcept -> void; - auto set_fullscreen(bool fullscreen) noexcept -> void; - - auto confine_mouse(bool confined, u8 id) noexcept -> void; - [[nodiscard]] - auto is_mouse_confined(u8 id) const noexcept -> bool; - - auto lock_mouse(bool locked, u8 id) noexcept -> void; - [[nodiscard]] - auto is_mouse_locked(u8 id) const noexcept -> bool; - - auto hide_mouse(bool hidden, u8 id) noexcept -> void; - [[nodiscard]] - auto is_mouse_hidden(u8 id) const noexcept -> bool; - - auto set_relative_mouse(bool enabled, u8 id) noexcept -> void; - [[nodiscard]] - auto is_mouse_relative(u8 id) const noexcept -> bool; - - auto set_key_repeat(bool enabled, u8 id) noexcept -> void; - [[nodiscard]] - auto is_key_repeat_enabled(u8 id) const noexcept -> bool; - - auto show_virtual_keyboard(bool visible) noexcept -> void; - [[nodiscard]] - auto is_virtual_keyboard_visible() const noexcept -> bool; - - auto set_mouse_position(const math::vec2i& position, u8 id) noexcept -> void; - - [[nodiscard]] - auto native_handle() const noexcept -> NativeHandle; - - auto handle_xdg_surface_configure(u32) noexcept -> void; - auto handle_xdg_surface_close() noexcept -> void; - - auto handle_xdg_top_level_configure(u32, - u32, - std::span) noexcept - -> void; - auto handle_surface_enter(wl_surface*, wl_output*) noexcept -> void; - - auto handle_keyboard_key(Key, char, bool) noexcept -> void; - - auto handle_pointer_enter(wl_pointer*, wl::PointerState&) noexcept -> void; - auto handle_pointer_leave() noexcept -> void; - auto handle_pointer_motion(wl_fixed_t, wl_fixed_t) noexcept -> void; - auto handle_pointer_button(u32, u32, wl_fixed_t, wl_fixed_t) noexcept -> void; - - private: - auto reallocate_pixel_buffer() noexcept -> void; - - auto hide_mouse(bool hidden, wl_pointer*, wl::PointerState&) noexcept -> void; - auto set_cursor(std::string_view, wl_pointer*, wl::PointerState&) noexcept -> void; - - auto handle_key_repeat() noexcept -> void; - - u8 m_scale = 2u; - - bool m_configured = false; - bool m_scale_content = false; - WindowFlag m_flags; - wl_output* m_current_output = nullptr; - - std::string m_title; - - Handles m_handles; - - wl::Surface m_surface = wl::Surface::empty(); - wl::XDGSurface m_xdg_surface = wl::XDGSurface::empty(); - wl::XDGTopLevel m_xdg_top_level = wl::XDGTopLevel::empty(); - wl::XDGTopLevelDecoration - m_xdg_top_level_decoration = wl::XDGTopLevelDecoration::empty(); - wl::ContentType m_content_type = wl::ContentType::empty(); - wl::Viewport m_viewport = wl::Viewport::empty(); - - DeferInit m_shm_buffer; - wl::ShmPool m_shm_pool = wl::ShmPool::empty(); - wl::Buffer m_pixel_buffer = wl::Buffer::empty(); - - struct { - bool restored = false; - bool activated = false; - bool suspended = false; - bool fullscreen = false; - - std::optional> resizing; - } m_pending_state; - }; - } // namespace stormkit::wsi::linux::wayland -} - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::wsi::linux::wayland { - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_CONST - inline auto Window::is_virtual_keyboard_visible() const noexcept -> bool { - return false; - } -} // namespace stormkit::wsi::linux::wayland +// Copyright (C) 2021 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include + +#include + +#include +#include +#include + +export module stormkit.wsi:linux.wayland.window; + +import std; + +import stormkit.core; +import stormkit.wsi; + +import :common.window_base; + +import :linux.wayland; +import :linux.wayland.context; + +export { + namespace stormkit::wsi::linux::wayland { + class Window: public stormkit::wsi::common::WindowBase { + public: + struct Handles { + wl_display* display; + wl_surface* surface; + }; + + Window() noexcept; + ~Window() noexcept; + + Window(const Window&) noexcept = delete; + auto operator=(const Window&) noexcept -> Window& = delete; + + Window(Window&&) noexcept; + auto operator=(Window&&) noexcept -> Window&; + + auto open(string title, const math::uextent2& size, WindowFlag flags) noexcept -> void; + auto close() noexcept -> void; + + auto handle_events() noexcept -> void; + + auto clear(const ucolor_rgb& color) noexcept -> void; + auto fill_framebuffer(array_view colors) noexcept -> void; + + auto set_title(string title) noexcept -> void; + auto set_extent(const math::uextent2& extent) noexcept -> void; + auto set_fullscreen(bool fullscreen) noexcept -> void; + + auto confine_mouse(bool confined, u8 id) noexcept -> void; + [[nodiscard]] + auto is_mouse_confined(u8 id) const noexcept -> bool; + + auto lock_mouse(bool locked, u8 id) noexcept -> void; + [[nodiscard]] + auto is_mouse_locked(u8 id) const noexcept -> bool; + + auto hide_mouse(bool hidden, u8 id) noexcept -> void; + [[nodiscard]] + auto is_mouse_hidden(u8 id) const noexcept -> bool; + + auto set_relative_mouse(bool enabled, u8 id) noexcept -> void; + [[nodiscard]] + auto is_mouse_relative(u8 id) const noexcept -> bool; + + auto set_key_repeat(bool enabled, u8 id) noexcept -> void; + [[nodiscard]] + auto is_key_repeat_enabled(u8 id) const noexcept -> bool; + + auto show_virtual_keyboard(bool visible) noexcept -> void; + [[nodiscard]] + auto is_virtual_keyboard_visible() const noexcept -> bool; + + auto set_mouse_position(const math::ivec2& position, u8 id) noexcept -> void; + + [[nodiscard]] + auto native_handle() const noexcept -> NativeHandle; + + auto handle_xdg_surface_configure(u32) noexcept -> void; + auto handle_xdg_surface_close() noexcept -> void; + + auto handle_xdg_top_level_configure(u32, u32, array_view) noexcept -> void; + auto handle_surface_enter(wl_surface*, wl_output*) noexcept -> void; + + auto handle_keyboard_key(Key, char, bool) noexcept -> void; + + auto handle_pointer_enter(wl_pointer*, wl::PointerState&) noexcept -> void; + auto handle_pointer_leave() noexcept -> void; + auto handle_pointer_motion(wl_fixed_t, wl_fixed_t) noexcept -> void; + auto handle_pointer_button(u32, u32, wl_fixed_t, wl_fixed_t) noexcept -> void; + + private: + auto reallocate_pixel_buffer() noexcept -> void; + + auto hide_mouse(bool hidden, wl_pointer*, wl::PointerState&) noexcept -> void; + auto set_cursor(string_view, wl_pointer*, wl::PointerState&) noexcept -> void; + + auto handle_key_repeat() noexcept -> void; + + u8 m_scale = 2u; + + bool m_configured = false; + bool m_scale_content = false; + WindowFlag m_flags; + wl_output* m_current_output = nullptr; + + string m_title; + + Handles m_handles; + + wl::Surface m_surface = wl::Surface::empty(); + wl::XDGSurface m_xdg_surface = wl::XDGSurface::empty(); + wl::XDGTopLevel m_xdg_top_level = wl::XDGTopLevel::empty(); + wl::XDGTopLevelDecoration m_xdg_top_level_decoration = wl::XDGTopLevelDecoration::empty(); + wl::ContentType m_content_type = wl::ContentType::empty(); + wl::Viewport m_viewport = wl::Viewport::empty(); + + DeferInit m_shm_buffer; + wl::ShmPool m_shm_pool = wl::ShmPool::empty(); + wl::Buffer m_pixel_buffer = wl::Buffer::empty(); + + struct { + bool restored = false; + bool activated = false; + bool suspended = false; + bool fullscreen = false; + + std::optional resizing; + } m_pending_state; + }; + } // namespace stormkit::wsi::linux::wayland +} + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit::wsi::linux::wayland { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_CONST + inline auto Window::is_virtual_keyboard_visible() const noexcept -> bool { + return false; + } +} // namespace stormkit::wsi::linux::wayland diff --git a/src/wsi/linux/window.mpp b/src/wsi/linux/window.cppm similarity index 87% rename from src/wsi/linux/window.mpp rename to src/wsi/linux/window.cppm index 73344d438..35da13714 100644 --- a/src/wsi/linux/window.mpp +++ b/src/wsi/linux/window.cppm @@ -1,655 +1,635 @@ -// Copyright (C) 2021 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -export module stormkit.wsi:linux.window; - -import std; - -import stormkit.core; -import stormkit.wsi; - -import :common.window_base; -import :linux.x11.window; -import :linux.wayland.window; - -export namespace stormkit::wsi::linux { - class Window { - using BackendWindow = std::variant; - - WM m_wm; - - BackendWindow m_impl = std::monostate {}; - - public: - explicit Window(WM wm) noexcept; - ~Window() noexcept; - - Window(const Window&) noexcept = delete; - auto operator=(const Window&) noexcept -> Window& = delete; - - Window(Window&&) noexcept; - auto operator=(Window&&) noexcept -> Window&; - - auto open(std::string title, const math::Extent2& size, WindowFlag flags) noexcept - -> void; - auto close() noexcept -> void; - - [[nodiscard]] - auto is_open() const noexcept -> bool; - - [[nodiscard]] - auto visible() const noexcept -> bool; - - [[nodiscard]] - auto current_monitor() const noexcept -> const Monitor&; - - auto handle_events() noexcept -> void; - - auto clear(const rgbcolor& color) noexcept -> void; - auto fill_framebuffer(std::span> colors) noexcept -> void; - - auto set_title(std::string title) noexcept -> void; - [[nodiscard]] - auto title() const noexcept -> const std::string&; - - auto set_extent(const math::Extent2& extent) noexcept -> void; - [[nodiscard]] - auto extent() const noexcept -> const math::Extent2&; - - auto set_fullscreen(bool fullscreen) noexcept -> void; - [[nodiscard]] - auto fullscreen() const noexcept -> bool; - - auto confine_mouse(bool confined = true, u8 mouse_id = 0) noexcept -> void; - [[nodiscard]] - auto is_mouse_confined(u8 mouse_id) const noexcept -> bool; - - auto lock_mouse(bool locked = true, u8 mouse_id = 0) noexcept -> void; - [[nodiscard]] - auto is_mouse_locked(u8 mouse_id) const noexcept -> bool; - - auto hide_mouse(bool hidden = true, u8 mouse_id = 0) noexcept -> void; - [[nodiscard]] - auto is_mouse_hidden(u8 mouse_id) const noexcept -> bool; - - auto set_relative_mouse(bool enabled, u8 mouse_id = 0) noexcept -> void; - [[nodiscard]] - auto is_mouse_relative(u8 mouse_id = 0) const noexcept -> bool; - - auto set_key_repeat(bool enabled, u8 keyboard_id = 0) noexcept -> void; - [[nodiscard]] - auto is_key_repeat_enabled(u8 keyboard_id = 0) const noexcept -> bool; - - auto show_virtual_keyboard(bool visible = true) noexcept -> void; - [[nodiscard]] - auto is_virtual_keyboard_visible() const noexcept -> bool; - - auto set_mouse_position(const math::vec2i& position, u8 mouse_id = 0) noexcept -> void; - - [[nodiscard]] - auto native_handle() const noexcept -> NativeHandle; - - auto set_closed_event(ClosedEventFunc&& func) noexcept -> void; - auto set_monitor_changed_event(MonitorChangedEventFunc&& func) noexcept -> void; - auto set_resized_event(ResizedEventFunc&& func) noexcept -> void; - auto set_restored_event(RestoredEventFunc&& func) noexcept -> void; - auto set_minimized_event(MinimizedEventFunc&& func) noexcept -> void; - auto set_key_down_event(KeyDownEventFunc&& func) noexcept -> void; - auto set_key_up_event(KeyUpEventFunc&& func) noexcept -> void; - auto set_mouse_button_down_event(MouseButtonDownEventFunc&& func) noexcept -> void; - auto set_mouse_button_up_event(MouseButtonUpEventFunc&& func) noexcept -> void; - auto set_mouse_moved_event(MouseMovedEventFunc&& func) noexcept -> void; - auto set_deactivate_event(DeactivateEventFunc&& func) noexcept -> void; - auto set_activate_event(ActivateEventFunc&& func) noexcept -> void; - }; -} // namespace stormkit::wsi::linux - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::wsi::linux { - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Window::Window(WM wm) noexcept - : m_wm { wm } { - if (m_wm == WM::X11) m_impl = x11::Window {}; - else if (m_wm == WM::WAYLAND) - m_impl = wayland::Window {}; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Window::~Window() noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Window::Window(Window&&) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::operator=(Window&&) noexcept -> Window& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::open(std::string title, - const math::Extent2& extent, - WindowFlag flags) noexcept -> void { - switch (m_wm) { - case WM::X11: as(m_impl).open(std::move(title), extent, flags); break; - case WM::WAYLAND: - as(m_impl).open(std::move(title), extent, flags); - break; - - default: std::unreachable(); - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::close() noexcept -> void { - switch (m_wm) { - case WM::X11: as(m_impl).close(); break; - case WM::WAYLAND: as(m_impl).close(); break; - - default: std::unreachable(); - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline auto Window::is_open() const noexcept -> bool { - switch (m_wm) { - case WM::X11: return as(m_impl).is_open(); - case WM::WAYLAND: return as(m_impl).is_open(); - - default: break; - } - - std::unreachable(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline auto Window::visible() const noexcept -> bool { - switch (m_wm) { - case WM::X11: return as(m_impl).visible(); - case WM::WAYLAND: return as(m_impl).visible(); - - default: break; - } - - std::unreachable(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline auto Window::current_monitor() const noexcept -> const Monitor& { - switch (m_wm) { - case WM::X11: return as(m_impl).current_monitor(); - case WM::WAYLAND: return as(m_impl).current_monitor(); - - default: break; - } - - std::unreachable(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::handle_events() noexcept -> void { - switch (m_wm) { - case WM::X11: as(m_impl).handle_events(); break; - case WM::WAYLAND: as(m_impl).handle_events(); break; - - default: std::unreachable(); - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::clear(const rgbcolor& color) noexcept -> void { - switch (m_wm) { - case WM::X11: as(m_impl).clear(color); break; - case WM::WAYLAND: as(m_impl).clear(color); break; - - default: std::unreachable(); - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::fill_framebuffer(std::span> colors) noexcept -> void { - switch (m_wm) { - case WM::X11: as(m_impl).fill_framebuffer(colors); break; - case WM::WAYLAND: as(m_impl).fill_framebuffer(colors); break; - - default: std::unreachable(); - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::set_title(std::string title) noexcept -> void { - switch (m_wm) { - case WM::X11: as(m_impl).set_title(std::move(title)); break; - case WM::WAYLAND: as(m_impl).set_title(std::move(title)); break; - - default: std::unreachable(); - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline auto Window::title() const noexcept -> const std::string& { - switch (m_wm) { - case WM::X11: return as(m_impl).title(); - case WM::WAYLAND: return as(m_impl).title(); - - default: break; - } - - std::unreachable(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::set_extent(const math::Extent2& extent) noexcept -> void { - switch (m_wm) { - case WM::X11: as(m_impl).set_extent(extent); break; - case WM::WAYLAND: as(m_impl).set_extent(extent); break; - - default: std::unreachable(); - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline auto Window::extent() const noexcept -> const math::Extent2& { - switch (m_wm) { - case WM::X11: return as(m_impl).extent(); - case WM::WAYLAND: return as(m_impl).extent(); - - default: break; - } - - std::unreachable(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::set_fullscreen(bool enabled) noexcept -> void { - switch (m_wm) { - case WM::X11: as(m_impl).set_fullscreen(enabled); break; - case WM::WAYLAND: as(m_impl).set_fullscreen(enabled); break; - - default: std::unreachable(); - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline auto Window::fullscreen() const noexcept -> bool { - switch (m_wm) { - case WM::X11: return as(m_impl).fullscreen(); - case WM::WAYLAND: return as(m_impl).fullscreen(); - - default: break; - } - - std::unreachable(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::confine_mouse(bool confined, u8 mouse_id) noexcept -> void { - switch (m_wm) { - case WM::X11: as(m_impl).confine_mouse(confined, mouse_id); break; - case WM::WAYLAND: as(m_impl).confine_mouse(confined, mouse_id); break; - - default: std::unreachable(); - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline auto Window::is_mouse_confined(u8 mouse_id) const noexcept -> bool { - switch (m_wm) { - case WM::X11: return as(m_impl).is_mouse_confined(mouse_id); - case WM::WAYLAND: return as(m_impl).is_mouse_confined(mouse_id); - - default: break; - } - - std::unreachable(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::lock_mouse(bool locked, u8 mouse_id) noexcept -> void { - switch (m_wm) { - case WM::X11: as(m_impl).lock_mouse(locked, mouse_id); break; - case WM::WAYLAND: as(m_impl).lock_mouse(locked, mouse_id); break; - - default: std::unreachable(); - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline auto Window::is_mouse_locked(u8 mouse_id) const noexcept -> bool { - switch (m_wm) { - case WM::X11: return as(m_impl).is_mouse_locked(mouse_id); - case WM::WAYLAND: return as(m_impl).is_mouse_locked(mouse_id); - - default: break; - } - - std::unreachable(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::hide_mouse(bool hidden, u8 mouse_id) noexcept -> void { - switch (m_wm) { - case WM::X11: as(m_impl).hide_mouse(hidden, mouse_id); break; - case WM::WAYLAND: as(m_impl).hide_mouse(hidden, mouse_id); break; - - default: std::unreachable(); - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline auto Window::is_mouse_hidden(u8 mouse_id) const noexcept -> bool { - switch (m_wm) { - case WM::X11: return as(m_impl).is_mouse_hidden(mouse_id); - case WM::WAYLAND: return as(m_impl).is_mouse_hidden(mouse_id); - - default: break; - } - - std::unreachable(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::set_relative_mouse(bool enabled, u8 mouse_id) noexcept -> void { - switch (m_wm) { - case WM::X11: as(m_impl).set_relative_mouse(enabled, mouse_id); break; - case WM::WAYLAND: - as(m_impl).set_relative_mouse(enabled, mouse_id); - break; - - default: std::unreachable(); - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline auto Window::is_mouse_relative(u8 mouse_id) const noexcept -> bool { - switch (m_wm) { - case WM::X11: return as(m_impl).is_mouse_relative(mouse_id); - case WM::WAYLAND: return as(m_impl).is_mouse_relative(mouse_id); - - default: break; - } - - std::unreachable(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::set_key_repeat(bool enabled, u8 keyboard_id) noexcept -> void { - switch (m_wm) { - case WM::X11: return as(m_impl).set_key_repeat(enabled, keyboard_id); - case WM::WAYLAND: - return as(m_impl).set_key_repeat(enabled, keyboard_id); - - default: break; - } - - std::unreachable(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline auto Window::is_key_repeat_enabled(u8 keyboard_id) const noexcept -> bool { - switch (m_wm) { - case WM::X11: return as(m_impl).is_key_repeat_enabled(keyboard_id); - case WM::WAYLAND: return as(m_impl).is_key_repeat_enabled(keyboard_id); - - default: break; - } - - std::unreachable(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::show_virtual_keyboard(bool visible) noexcept -> void { - switch (m_wm) { - case WM::X11: as(m_impl).show_virtual_keyboard(visible); break; - case WM::WAYLAND: as(m_impl).show_virtual_keyboard(visible); break; - - default: std::unreachable(); - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline auto Window::is_virtual_keyboard_visible() const noexcept -> bool { - switch (m_wm) { - case WM::X11: return as(m_impl).is_virtual_keyboard_visible(); - case WM::WAYLAND: return as(m_impl).is_virtual_keyboard_visible(); - - default: break; - } - - std::unreachable(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::set_mouse_position(const math::vec2i& position, u8 mouse_id) noexcept - -> void { - switch (m_wm) { - case WM::X11: as(m_impl).set_mouse_position(position, mouse_id); break; - case WM::WAYLAND: - as(m_impl).set_mouse_position(position, mouse_id); - break; - - default: std::unreachable(); - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline auto Window::native_handle() const noexcept -> NativeHandle { - switch (m_wm) { - case WM::X11: return as(m_impl).native_handle(); - case WM::WAYLAND: return as(m_impl).native_handle(); - default: break; - } - - std::unreachable(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::set_closed_event(ClosedEventFunc&& func) noexcept -> void { - switch (m_wm) { - case WM::X11: as(m_impl).closed_event = std::move(func); break; - case WM::WAYLAND: as(m_impl).closed_event = std::move(func); break; - default: std::unreachable(); - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::set_monitor_changed_event(MonitorChangedEventFunc&& func) noexcept -> void { - switch (m_wm) { - case WM::X11: as(m_impl).monitor_changed_event = std::move(func); break; - case WM::WAYLAND: - as(m_impl).monitor_changed_event = std::move(func); - break; - default: std::unreachable(); - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::set_resized_event(ResizedEventFunc&& func) noexcept -> void { - switch (m_wm) { - case WM::X11: as(m_impl).resized_event = std::move(func); break; - case WM::WAYLAND: as(m_impl).resized_event = std::move(func); break; - default: std::unreachable(); - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::set_restored_event(RestoredEventFunc&& func) noexcept -> void { - switch (m_wm) { - case WM::X11: as(m_impl).restored_event = std::move(func); break; - case WM::WAYLAND: as(m_impl).restored_event = std::move(func); break; - default: std::unreachable(); - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::set_minimized_event(MinimizedEventFunc&& func) noexcept -> void { - switch (m_wm) { - case WM::X11: as(m_impl).minimized_event = std::move(func); break; - case WM::WAYLAND: as(m_impl).minimized_event = std::move(func); break; - default: std::unreachable(); - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::set_key_down_event(KeyDownEventFunc&& func) noexcept -> void { - switch (m_wm) { - case WM::X11: as(m_impl).key_down_event = std::move(func); break; - case WM::WAYLAND: as(m_impl).key_down_event = std::move(func); break; - default: std::unreachable(); - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::set_key_up_event(KeyUpEventFunc&& func) noexcept -> void { - switch (m_wm) { - case WM::X11: as(m_impl).key_up_event = std::move(func); break; - case WM::WAYLAND: as(m_impl).key_up_event = std::move(func); break; - default: std::unreachable(); - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::set_mouse_button_down_event(MouseButtonDownEventFunc&& func) noexcept - -> void { - switch (m_wm) { - case WM::X11: as(m_impl).mouse_button_down_event = std::move(func); break; - case WM::WAYLAND: - as(m_impl).mouse_button_down_event = std::move(func); - break; - default: std::unreachable(); - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::set_mouse_button_up_event(MouseButtonUpEventFunc&& func) noexcept -> void { - switch (m_wm) { - case WM::X11: as(m_impl).mouse_button_up_event = std::move(func); break; - case WM::WAYLAND: - as(m_impl).mouse_button_up_event = std::move(func); - break; - default: std::unreachable(); - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::set_mouse_moved_event(MouseMovedEventFunc&& func) noexcept -> void { - switch (m_wm) { - case WM::X11: as(m_impl).mouse_moved_event = std::move(func); break; - case WM::WAYLAND: - as(m_impl).mouse_moved_event = std::move(func); - break; - default: std::unreachable(); - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::set_deactivate_event(DeactivateEventFunc&& func) noexcept -> void { - switch (m_wm) { - case WM::X11: as(m_impl).deactivate_event = std::move(func); break; - case WM::WAYLAND: as(m_impl).deactivate_event = std::move(func); break; - default: std::unreachable(); - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::set_activate_event(ActivateEventFunc&& func) noexcept -> void { - switch (m_wm) { - case WM::X11: as(m_impl).activate_event = std::move(func); break; - case WM::WAYLAND: as(m_impl).activate_event = std::move(func); break; - default: std::unreachable(); - } - } -} // namespace stormkit::wsi::linux +// Copyright (C) 2021 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +export module stormkit.wsi:linux.window; + +import std; + +import stormkit.core; +import stormkit.wsi; + +import :common.window_base; +import :linux.x11.window; +import :linux.wayland.window; + +export namespace stormkit::wsi::linux { + class Window { + using BackendWindow = std::variant; + + WM m_wm; + + BackendWindow m_impl = std::monostate {}; + + public: + explicit Window(WM wm) noexcept; + ~Window() noexcept; + + Window(const Window&) noexcept = delete; + auto operator=(const Window&) noexcept -> Window& = delete; + + Window(Window&&) noexcept; + auto operator=(Window&&) noexcept -> Window&; + + auto open(string title, const math::uextent2& size, WindowFlag flags) noexcept -> void; + auto close() noexcept -> void; + + [[nodiscard]] + auto is_open() const noexcept -> bool; + + [[nodiscard]] + auto visible() const noexcept -> bool; + + [[nodiscard]] + auto current_monitor() const noexcept -> const Monitor&; + + auto handle_events() noexcept -> void; + + auto clear(const ucolor_rgb& color) noexcept -> void; + auto fill_framebuffer(array_view colors) noexcept -> void; + + auto set_title(string title) noexcept -> void; + [[nodiscard]] + auto title() const noexcept -> const string&; + + auto set_extent(const math::uextent2& extent) noexcept -> void; + [[nodiscard]] + auto extent() const noexcept -> const math::uextent2&; + + auto set_fullscreen(bool fullscreen) noexcept -> void; + [[nodiscard]] + auto fullscreen() const noexcept -> bool; + + auto confine_mouse(bool confined = true, u8 mouse_id = 0) noexcept -> void; + [[nodiscard]] + auto is_mouse_confined(u8 mouse_id) const noexcept -> bool; + + auto lock_mouse(bool locked = true, u8 mouse_id = 0) noexcept -> void; + [[nodiscard]] + auto is_mouse_locked(u8 mouse_id) const noexcept -> bool; + + auto hide_mouse(bool hidden = true, u8 mouse_id = 0) noexcept -> void; + [[nodiscard]] + auto is_mouse_hidden(u8 mouse_id) const noexcept -> bool; + + auto set_relative_mouse(bool enabled, u8 mouse_id = 0) noexcept -> void; + [[nodiscard]] + auto is_mouse_relative(u8 mouse_id = 0) const noexcept -> bool; + + auto set_key_repeat(bool enabled, u8 keyboard_id = 0) noexcept -> void; + [[nodiscard]] + auto is_key_repeat_enabled(u8 keyboard_id = 0) const noexcept -> bool; + + auto show_virtual_keyboard(bool visible = true) noexcept -> void; + [[nodiscard]] + auto is_virtual_keyboard_visible() const noexcept -> bool; + + auto set_mouse_position(const math::ivec2& position, u8 mouse_id = 0) noexcept -> void; + + [[nodiscard]] + auto native_handle() const noexcept -> NativeHandle; + + auto set_closed_event(ClosedEventFunc&& func) noexcept -> void; + auto set_monitor_changed_event(MonitorChangedEventFunc&& func) noexcept -> void; + auto set_resized_event(ResizedEventFunc&& func) noexcept -> void; + auto set_restored_event(RestoredEventFunc&& func) noexcept -> void; + auto set_minimized_event(MinimizedEventFunc&& func) noexcept -> void; + auto set_key_down_event(KeyDownEventFunc&& func) noexcept -> void; + auto set_key_up_event(KeyUpEventFunc&& func) noexcept -> void; + auto set_mouse_button_down_event(MouseButtonDownEventFunc&& func) noexcept -> void; + auto set_mouse_button_up_event(MouseButtonUpEventFunc&& func) noexcept -> void; + auto set_mouse_moved_event(MouseMovedEventFunc&& func) noexcept -> void; + auto set_deactivate_event(DeactivateEventFunc&& func) noexcept -> void; + auto set_activate_event(ActivateEventFunc&& func) noexcept -> void; + }; +} // namespace stormkit::wsi::linux + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit::wsi::linux { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline Window::Window(WM wm) noexcept + : m_wm { wm } { + if (m_wm == WM::X11) m_impl = x11::Window {}; + else if (m_wm == WM::WAYLAND) + m_impl = wayland::Window {}; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline Window::~Window() noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline Window::Window(Window&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::operator=(Window&&) noexcept -> Window& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::open(string title, const math::uextent2& extent, WindowFlag flags) noexcept -> void { + switch (m_wm) { + case WM::X11: as(m_impl).open(std::move(title), extent, flags); break; + case WM::WAYLAND: as(m_impl).open(std::move(title), extent, flags); break; + + default: std::unreachable(); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::close() noexcept -> void { + switch (m_wm) { + case WM::X11: as(m_impl).close(); break; + case WM::WAYLAND: as(m_impl).close(); break; + + default: std::unreachable(); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_PURE + inline auto Window::is_open() const noexcept -> bool { + switch (m_wm) { + case WM::X11: return as(m_impl).is_open(); + case WM::WAYLAND: return as(m_impl).is_open(); + + default: break; + } + + std::unreachable(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_PURE + inline auto Window::visible() const noexcept -> bool { + switch (m_wm) { + case WM::X11: return as(m_impl).visible(); + case WM::WAYLAND: return as(m_impl).visible(); + + default: break; + } + + std::unreachable(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_PURE + inline auto Window::current_monitor() const noexcept -> const Monitor& { + switch (m_wm) { + case WM::X11: return as(m_impl).current_monitor(); + case WM::WAYLAND: return as(m_impl).current_monitor(); + + default: break; + } + + std::unreachable(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::handle_events() noexcept -> void { + switch (m_wm) { + case WM::X11: as(m_impl).handle_events(); break; + case WM::WAYLAND: as(m_impl).handle_events(); break; + + default: std::unreachable(); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::clear(const ucolor_rgb& color) noexcept -> void { + switch (m_wm) { + case WM::X11: as(m_impl).clear(color); break; + case WM::WAYLAND: as(m_impl).clear(color); break; + + default: std::unreachable(); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::fill_framebuffer(array_view colors) noexcept -> void { + switch (m_wm) { + case WM::X11: as(m_impl).fill_framebuffer(colors); break; + case WM::WAYLAND: as(m_impl).fill_framebuffer(colors); break; + + default: std::unreachable(); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::set_title(string title) noexcept -> void { + switch (m_wm) { + case WM::X11: as(m_impl).set_title(std::move(title)); break; + case WM::WAYLAND: as(m_impl).set_title(std::move(title)); break; + + default: std::unreachable(); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_PURE + inline auto Window::title() const noexcept -> const string& { + switch (m_wm) { + case WM::X11: return as(m_impl).title(); + case WM::WAYLAND: return as(m_impl).title(); + + default: break; + } + + std::unreachable(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::set_extent(const math::uextent2& extent) noexcept -> void { + switch (m_wm) { + case WM::X11: as(m_impl).set_extent(extent); break; + case WM::WAYLAND: as(m_impl).set_extent(extent); break; + + default: std::unreachable(); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_PURE + inline auto Window::extent() const noexcept -> const math::uextent2& { + switch (m_wm) { + case WM::X11: return as(m_impl).extent(); + case WM::WAYLAND: return as(m_impl).extent(); + + default: break; + } + + std::unreachable(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::set_fullscreen(bool enabled) noexcept -> void { + switch (m_wm) { + case WM::X11: as(m_impl).set_fullscreen(enabled); break; + case WM::WAYLAND: as(m_impl).set_fullscreen(enabled); break; + + default: std::unreachable(); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_PURE + inline auto Window::fullscreen() const noexcept -> bool { + switch (m_wm) { + case WM::X11: return as(m_impl).fullscreen(); + case WM::WAYLAND: return as(m_impl).fullscreen(); + + default: break; + } + + std::unreachable(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::confine_mouse(bool confined, u8 mouse_id) noexcept -> void { + switch (m_wm) { + case WM::X11: as(m_impl).confine_mouse(confined, mouse_id); break; + case WM::WAYLAND: as(m_impl).confine_mouse(confined, mouse_id); break; + + default: std::unreachable(); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_PURE + inline auto Window::is_mouse_confined(u8 mouse_id) const noexcept -> bool { + switch (m_wm) { + case WM::X11: return as(m_impl).is_mouse_confined(mouse_id); + case WM::WAYLAND: return as(m_impl).is_mouse_confined(mouse_id); + + default: break; + } + + std::unreachable(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::lock_mouse(bool locked, u8 mouse_id) noexcept -> void { + switch (m_wm) { + case WM::X11: as(m_impl).lock_mouse(locked, mouse_id); break; + case WM::WAYLAND: as(m_impl).lock_mouse(locked, mouse_id); break; + + default: std::unreachable(); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_PURE + inline auto Window::is_mouse_locked(u8 mouse_id) const noexcept -> bool { + switch (m_wm) { + case WM::X11: return as(m_impl).is_mouse_locked(mouse_id); + case WM::WAYLAND: return as(m_impl).is_mouse_locked(mouse_id); + + default: break; + } + + std::unreachable(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::hide_mouse(bool hidden, u8 mouse_id) noexcept -> void { + switch (m_wm) { + case WM::X11: as(m_impl).hide_mouse(hidden, mouse_id); break; + case WM::WAYLAND: as(m_impl).hide_mouse(hidden, mouse_id); break; + + default: std::unreachable(); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_PURE + inline auto Window::is_mouse_hidden(u8 mouse_id) const noexcept -> bool { + switch (m_wm) { + case WM::X11: return as(m_impl).is_mouse_hidden(mouse_id); + case WM::WAYLAND: return as(m_impl).is_mouse_hidden(mouse_id); + + default: break; + } + + std::unreachable(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::set_relative_mouse(bool enabled, u8 mouse_id) noexcept -> void { + switch (m_wm) { + case WM::X11: as(m_impl).set_relative_mouse(enabled, mouse_id); break; + case WM::WAYLAND: as(m_impl).set_relative_mouse(enabled, mouse_id); break; + + default: std::unreachable(); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_PURE + inline auto Window::is_mouse_relative(u8 mouse_id) const noexcept -> bool { + switch (m_wm) { + case WM::X11: return as(m_impl).is_mouse_relative(mouse_id); + case WM::WAYLAND: return as(m_impl).is_mouse_relative(mouse_id); + + default: break; + } + + std::unreachable(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::set_key_repeat(bool enabled, u8 keyboard_id) noexcept -> void { + switch (m_wm) { + case WM::X11: return as(m_impl).set_key_repeat(enabled, keyboard_id); + case WM::WAYLAND: return as(m_impl).set_key_repeat(enabled, keyboard_id); + + default: break; + } + + std::unreachable(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_PURE + inline auto Window::is_key_repeat_enabled(u8 keyboard_id) const noexcept -> bool { + switch (m_wm) { + case WM::X11: return as(m_impl).is_key_repeat_enabled(keyboard_id); + case WM::WAYLAND: return as(m_impl).is_key_repeat_enabled(keyboard_id); + + default: break; + } + + std::unreachable(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::show_virtual_keyboard(bool visible) noexcept -> void { + switch (m_wm) { + case WM::X11: as(m_impl).show_virtual_keyboard(visible); break; + case WM::WAYLAND: as(m_impl).show_virtual_keyboard(visible); break; + + default: std::unreachable(); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_PURE + inline auto Window::is_virtual_keyboard_visible() const noexcept -> bool { + switch (m_wm) { + case WM::X11: return as(m_impl).is_virtual_keyboard_visible(); + case WM::WAYLAND: return as(m_impl).is_virtual_keyboard_visible(); + + default: break; + } + + std::unreachable(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::set_mouse_position(const math::ivec2& position, u8 mouse_id) noexcept -> void { + switch (m_wm) { + case WM::X11: as(m_impl).set_mouse_position(position, mouse_id); break; + case WM::WAYLAND: as(m_impl).set_mouse_position(position, mouse_id); break; + + default: std::unreachable(); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_PURE + inline auto Window::native_handle() const noexcept -> NativeHandle { + switch (m_wm) { + case WM::X11: return as(m_impl).native_handle(); + case WM::WAYLAND: return as(m_impl).native_handle(); + default: break; + } + + std::unreachable(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::set_closed_event(ClosedEventFunc&& func) noexcept -> void { + switch (m_wm) { + case WM::X11: as(m_impl).closed_event = std::move(func); break; + case WM::WAYLAND: as(m_impl).closed_event = std::move(func); break; + default: std::unreachable(); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::set_monitor_changed_event(MonitorChangedEventFunc&& func) noexcept -> void { + switch (m_wm) { + case WM::X11: as(m_impl).monitor_changed_event = std::move(func); break; + case WM::WAYLAND: as(m_impl).monitor_changed_event = std::move(func); break; + default: std::unreachable(); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::set_resized_event(ResizedEventFunc&& func) noexcept -> void { + switch (m_wm) { + case WM::X11: as(m_impl).resized_event = std::move(func); break; + case WM::WAYLAND: as(m_impl).resized_event = std::move(func); break; + default: std::unreachable(); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::set_restored_event(RestoredEventFunc&& func) noexcept -> void { + switch (m_wm) { + case WM::X11: as(m_impl).restored_event = std::move(func); break; + case WM::WAYLAND: as(m_impl).restored_event = std::move(func); break; + default: std::unreachable(); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::set_minimized_event(MinimizedEventFunc&& func) noexcept -> void { + switch (m_wm) { + case WM::X11: as(m_impl).minimized_event = std::move(func); break; + case WM::WAYLAND: as(m_impl).minimized_event = std::move(func); break; + default: std::unreachable(); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::set_key_down_event(KeyDownEventFunc&& func) noexcept -> void { + switch (m_wm) { + case WM::X11: as(m_impl).key_down_event = std::move(func); break; + case WM::WAYLAND: as(m_impl).key_down_event = std::move(func); break; + default: std::unreachable(); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::set_key_up_event(KeyUpEventFunc&& func) noexcept -> void { + switch (m_wm) { + case WM::X11: as(m_impl).key_up_event = std::move(func); break; + case WM::WAYLAND: as(m_impl).key_up_event = std::move(func); break; + default: std::unreachable(); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::set_mouse_button_down_event(MouseButtonDownEventFunc&& func) noexcept -> void { + switch (m_wm) { + case WM::X11: as(m_impl).mouse_button_down_event = std::move(func); break; + case WM::WAYLAND: as(m_impl).mouse_button_down_event = std::move(func); break; + default: std::unreachable(); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::set_mouse_button_up_event(MouseButtonUpEventFunc&& func) noexcept -> void { + switch (m_wm) { + case WM::X11: as(m_impl).mouse_button_up_event = std::move(func); break; + case WM::WAYLAND: as(m_impl).mouse_button_up_event = std::move(func); break; + default: std::unreachable(); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::set_mouse_moved_event(MouseMovedEventFunc&& func) noexcept -> void { + switch (m_wm) { + case WM::X11: as(m_impl).mouse_moved_event = std::move(func); break; + case WM::WAYLAND: as(m_impl).mouse_moved_event = std::move(func); break; + default: std::unreachable(); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::set_deactivate_event(DeactivateEventFunc&& func) noexcept -> void { + switch (m_wm) { + case WM::X11: as(m_impl).deactivate_event = std::move(func); break; + case WM::WAYLAND: as(m_impl).deactivate_event = std::move(func); break; + default: std::unreachable(); + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::set_activate_event(ActivateEventFunc&& func) noexcept -> void { + switch (m_wm) { + case WM::X11: as(m_impl).activate_event = std::move(func); break; + case WM::WAYLAND: as(m_impl).activate_event = std::move(func); break; + default: std::unreachable(); + } + } +} // namespace stormkit::wsi::linux diff --git a/src/wsi/linux/x11/context.cpp b/src/wsi/linux/x11/context.cpp index 3151fe049..81ffccd9d 100644 --- a/src/wsi/linux/x11/context.cpp +++ b/src/wsi/linux/x11/context.cpp @@ -30,7 +30,7 @@ namespace stormkit::wsi::linux::x11::xcb { namespace { thread_local constinit auto initialized = false; thread_local constinit auto globals = Globals {}; - thread_local auto atoms = stormkit::StringHashMap {}; + thread_local auto atoms = stormkit::string_hash_map {}; } // namespace ///////////////////////////////////// @@ -66,18 +66,16 @@ namespace stormkit::wsi::linux::x11::xcb { ///////////////////////////////////// ///////////////////////////////////// - auto get_atom(std::string_view name, bool only_if_exists) noexcept -> std::expected { + auto get_atom(string_view name, bool only_if_exists) noexcept -> std::expected { auto out = std::expected {}; auto it = atoms.find(name); if (it != stdr::end(atoms)) out = it->second; else { - const auto cookie = xcb_intern_atom(globals.connection, - (only_if_exists) ? 1 : 0, - as(stdr::size(name)), - stdr::data(name)); - auto error = xcb::GenericError::empty(); - const auto reply = xcb::InternAtomReply::create(globals.connection, cookie, &error.handle()); + const auto + cookie = xcb_intern_atom(globals.connection, (only_if_exists) ? 1 : 0, as(stdr::size(name)), stdr::data(name)); + auto error = xcb::GenericError::empty(); + const auto reply = xcb::InternAtomReply::create(globals.connection, cookie, &error.handle()); if (error or not reply.handle()) out = std::unexpected { std::in_place, get_error(as_ref_mut(*error)) }; else { @@ -91,8 +89,8 @@ namespace stormkit::wsi::linux::x11::xcb { return out; } - auto get_atom_name(xcb_atom_t atom) -> std::expected { - auto out = std::expected {}; + auto get_atom_name(xcb_atom_t atom) -> std::expected { + auto out = std::expected {}; const auto cookie = xcb_get_atom_name(globals.connection, atom); @@ -100,20 +98,20 @@ namespace stormkit::wsi::linux::x11::xcb { const auto reply = xcb::AtomNameReply::create(globals.connection, cookie, &error.handle()); if (error) out = std::unexpected { std::in_place, get_error(as_ref_mut(*error)) }; else - out = std::string { xcb_get_atom_name_name(reply), as(xcb_get_atom_name_name_length(reply)) }; + out = string { xcb_get_atom_name_name(reply), as(xcb_get_atom_name_name_length(reply)) }; return out; } ///////////////////////////////////// ///////////////////////////////////// - auto get_error(Ref error) -> std::string { + auto get_error(ref error) -> string { auto guard = xcb::GenericError::take(error); const auto major = xcb_errors_get_name_for_major_code(globals.error_context, error->major_code); const auto minor = xcb_errors_get_name_for_minor_code(globals.error_context, error->major_code, error->minor_code); - const auto* extension = CZString { nullptr }; + const auto* extension = czstring { nullptr }; const auto str_error = xcb_errors_get_name_for_error(globals.error_context, error->major_code, &extension); return std::format("{} extension: {} major: {} minor: {}\n", @@ -125,8 +123,8 @@ namespace stormkit::wsi::linux::x11::xcb { ///////////////////////////////////// ///////////////////////////////////// - auto get_xi_device_info(xcb_input_device_id_t device_id) -> std::expected, Error> { - auto out = std::expected, Error> { std::unexpect }; + auto get_xi_device_info(xcb_input_device_id_t device_id) -> std::expected, Error> { + auto out = std::expected, Error> { std::unexpect }; const auto cookie = xcb_input_xi_query_device(globals.connection, device_id); auto error = xcb::GenericError::empty(); diff --git a/src/wsi/linux/x11/context.mpp b/src/wsi/linux/x11/context.cppm similarity index 79% rename from src/wsi/linux/x11/context.mpp rename to src/wsi/linux/x11/context.cppm index f5a346bfe..7a4b06478 100644 --- a/src/wsi/linux/x11/context.mpp +++ b/src/wsi/linux/x11/context.cppm @@ -31,17 +31,15 @@ export namespace stormkit::wsi::linux::x11::xcb { auto init() noexcept -> bool; auto get_globals() noexcept -> Globals&; - auto get_atom(std::string_view name, bool only_if_exists) noexcept - -> std::expected; - auto get_atom_name(xcb_atom_t atom) -> std::expected; + auto get_atom(string_view name, bool only_if_exists) noexcept -> std::expected; + auto get_atom_name(xcb_atom_t atom) -> std::expected; - auto get_error(Ref error) -> std::string; + auto get_error(ref error) -> string; - auto get_xi_device_info(xcb_input_device_id_t device_id) - -> std::expected, Error>; + auto get_xi_device_info(xcb_input_device_id_t device_id) -> std::expected, Error>; // template - // auto get_xft_value(std::string_view name) -> std::optional; + // auto get_xft_value(string_view name) -> std::optional; } // namespace stormkit::wsi::linux::x11::xcb //////////////////////////////////////////////////////////////////// @@ -54,7 +52,7 @@ export namespace stormkit::wsi::linux::x11::xcb { // ///////////////////////////////////// // ///////////////////////////////////// // template - // auto get_xft_value(std::string_view name) -> std::optional { + // auto get_xft_value(string_view name) -> std::optional { // using XcbXrmDatabase = RAIICapsule -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -export module stormkit.wsi:linux.x11.log; - -import std; - -import stormkit.core; -import stormkit.log; - -export namespace stormkit::wsi::linux::x11 { - IN_MODULE_LOGGER("StormKit.Wsi.Linux.X11") -} // namespace stormkit::wsi::linux::x11 +// Copyright (C) 2021 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +export module stormkit.wsi:linux.x11.log; + +import std; + +import stormkit.core; +import stormkit.log; + +export namespace stormkit::wsi::linux::x11 { + IN_MODULE_LOGGER("StormKit.Wsi.Linux.X11") +} // namespace stormkit::wsi::linux::x11 diff --git a/src/wsi/linux/x11/monitor.mpp b/src/wsi/linux/x11/monitor.cppm similarity index 66% rename from src/wsi/linux/x11/monitor.mpp rename to src/wsi/linux/x11/monitor.cppm index a737e02a1..62e0debbf 100644 --- a/src/wsi/linux/x11/monitor.mpp +++ b/src/wsi/linux/x11/monitor.cppm @@ -21,8 +21,8 @@ namespace stdr = std::ranges; namespace stormkit::wsi::linux::x11 { ///////////////////////////////////// ///////////////////////////////////// - auto get_monitors(WM, bool update) noexcept -> std::span { - thread_local auto monitors = std::vector {}; + auto get_monitors(WM, bool update) noexcept -> array_view { + thread_local auto monitors = dyn_array {}; if (stdr::empty(monitors) or update) { auto& globals = xcb::get_globals(); @@ -35,22 +35,16 @@ namespace stormkit::wsi::linux::x11 { xcb_randr_get_output_info_reply, std::free, struct OutputTag>; - using CRTC = RAIICapsule; + using CRTC = RAIICapsule; const auto root = xcb_setup_roots_iterator(xcb_get_setup(globals.connection)).data; auto xcb_monitors = Monitors::create(globals.connection, - xcb_randr_get_monitors(globals.connection, - root->root, - 0), + xcb_randr_get_monitors(globals.connection, root->root, 0), nullptr); auto xcb_monitor_iter = xcb_randr_get_monitors_monitors_iterator(xcb_monitors); - for (auto i = 0; xcb_monitor_iter.rem; - xcb_randr_monitor_info_next(&xcb_monitor_iter), ++i) { + for (auto i = 0; xcb_monitor_iter.rem; xcb_randr_monitor_info_next(&xcb_monitor_iter), ++i) { auto monitor_info = xcb_monitor_iter.data; xcb_randr_select_input(globals.connection, root->root, true); @@ -67,11 +61,9 @@ namespace stormkit::wsi::linux::x11 { auto outputs = xcb_randr_monitor_info_outputs(monitor_info); for (auto j : range(len)) { - auto output_cookie = xcb_randr_get_output_info(globals.connection, - outputs[j], - xcb_monitors.handle() - ->timestamp); - auto output = Output::create(globals.connection, output_cookie, nullptr); + auto + output_cookie = xcb_randr_get_output_info(globals.connection, outputs[j], xcb_monitors.handle()->timestamp); + auto output = Output::create(globals.connection, output_cookie, nullptr); if (!output) continue; if (output.handle()->connection != XCB_RANDR_CONNECTION_CONNECTED) continue; @@ -84,14 +76,12 @@ namespace stormkit::wsi::linux::x11 { if (crtc == nullptr) {} - monitor.extents.emplace_back(math::Extent2 { as(crtc.handle()->width), - as(crtc.handle()->height) }); + monitor.extents.emplace_back(math::extent2 { as(crtc.handle()->width), as(crtc.handle()->height) }); } if (stdr::empty(monitor.extents)) - monitor.extents - .emplace_back(math::Extent2 { as(xcb_monitor_iter.data->width), - as(xcb_monitor_iter.data->height) }); + monitor.extents.emplace_back(math::extent2 { as(xcb_monitor_iter.data->width), + as(xcb_monitor_iter.data->height) }); } } return monitors; diff --git a/src/wsi/linux/x11/utils.mpp b/src/wsi/linux/x11/utils.cppm similarity index 95% rename from src/wsi/linux/x11/utils.mpp rename to src/wsi/linux/x11/utils.cppm index a8a52215e..6e18687c3 100644 --- a/src/wsi/linux/x11/utils.mpp +++ b/src/wsi/linux/x11/utils.cppm @@ -1,174 +1,172 @@ -// Copyright (C) 2021 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -#include - -#include -#include -#include - -#include - -export module stormkit.wsi:linux.x11.utils; - -import stormkit.core; -import stormkit.wsi; - -import :linux.x11.log; - -export namespace stormkit::wsi::linux::x11 { - auto x11_key_to_char(xcb_keysym_t key) noexcept -> char; - auto x11_button_to_stormkit(xcb_button_t button) noexcept -> MouseButton; - auto default_root_window(xcb_connection_t* connection, i32 screen_id) noexcept -> xcb_window_t; -} // namespace stormkit::wsi::linux::x11 - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::wsi::linux::x11 { - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_CONST - inline auto x11_button_to_stormkit(xcb_button_t button) noexcept -> MouseButton { - switch (button) { - case XCB_BUTTON_INDEX_1: return MouseButton::LEFT; - case XCB_BUTTON_INDEX_2: return MouseButton::MIDDLE; - case XCB_BUTTON_INDEX_3: return MouseButton::RIGHT; - case XCB_BUTTON_INDEX_4: return MouseButton::BUTTON_1; - case XCB_BUTTON_INDEX_5: return MouseButton::BUTTON_2; - default: break; - } - - std::unreachable(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto screen_of_display(xcb_connection_t* c, int screen) noexcept -> xcb_screen_t* { - auto iter = xcb_screen_iterator_t {}; - - for (iter = xcb_setup_roots_iterator(xcb_get_setup(c)); iter.rem; --screen, - xcb_screen_next(&iter)) - if (screen == 0) return iter.data; - - return iter.data; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto default_root_window(xcb_connection_t* connection, int32_t screen_id) noexcept - -> xcb_window_t { - auto screen = screen_of_display(connection, screen_id); - - return screen->root; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_CONST - inline auto x11_key_to_char(xcb_keysym_t key) noexcept -> char { - switch (key) { - case XK_a: return u8'a'; - case XK_b: return u8'b'; - case XK_c: return u8'c'; - case XK_d: return u8'd'; - case XK_e: return u8'e'; - case XK_f: return u8'f'; - case XK_g: return u8'g'; - case XK_h: return u8'h'; - case XK_i: return u8'i'; - case XK_j: return u8'j'; - case XK_k: return u8'k'; - case XK_l: return u8'l'; - case XK_m: return u8'm'; - case XK_n: return u8'n'; - case XK_o: return u8'o'; - case XK_p: return u8'p'; - case XK_q: return u8'q'; - case XK_r: return u8'r'; - case XK_s: return u8's'; - case XK_t: return u8't'; - case XK_u: return u8'u'; - case XK_v: return u8'v'; - case XK_w: return u8'w'; - case XK_x: return u8'x'; - case XK_y: return u8'y'; - case XK_z: return u8'z'; - case XK_A: return u8'A'; - case XK_B: return u8'B'; - case XK_C: return u8'C'; - case XK_D: return u8'D'; - case XK_E: return u8'E'; - case XK_F: return u8'F'; - case XK_G: return u8'G'; - case XK_H: return u8'H'; - case XK_I: return u8'I'; - case XK_J: return u8'J'; - case XK_K: return u8'K'; - case XK_L: return u8'L'; - case XK_M: return u8'M'; - case XK_N: return u8'N'; - case XK_O: return u8'O'; - case XK_P: return u8'P'; - case XK_Q: return u8'Q'; - case XK_R: return u8'R'; - case XK_S: return u8'S'; - case XK_T: return u8'T'; - case XK_U: return u8'U'; - case XK_V: return u8'V'; - case XK_W: return u8'W'; - case XK_X: return u8'X'; - case XK_Y: return u8'Y'; - case XK_Z: return u8'Z'; - case XK_KP_0: [[fallthrough]]; - case XK_0: return u8'0'; - case XK_KP_1: [[fallthrough]]; - case XK_1: return u8'1'; - case XK_KP_2: [[fallthrough]]; - case XK_2: return u8'2'; - case XK_KP_3: [[fallthrough]]; - case XK_3: return u8'3'; - case XK_KP_4: [[fallthrough]]; - case XK_4: return u8'4'; - case XK_KP_5: [[fallthrough]]; - case XK_5: return u8'5'; - case XK_KP_6: [[fallthrough]]; - case XK_6: return u8'6'; - case XK_KP_7: [[fallthrough]]; - case XK_7: return u8'7'; - case XK_KP_8: [[fallthrough]]; - case XK_8: return u8'8'; - case XK_KP_9: [[fallthrough]]; - case XK_9: return u8'9'; - case XK_bracketleft: return u8'{'; - case XK_bracketright: return u8'}'; - case XK_semicolon: return u8';'; - case XK_comma: return u8','; - case XK_period: return u8'.'; - case XK_quoteright: [[fallthrough]]; - case XK_quoteleft: return u8'"'; - case XK_slash: return u8'/'; - case XK_backslash: return u8'\\'; - case XK_dead_grave: return u8'~'; - case XK_equal: return u8'='; - case XK_hyphen: return u8'-'; - case XK_space: return u8' '; - case XK_Return: return u8'\n'; - case XK_Tab: return u8'\t'; - case XK_KP_Add: return u8'+'; - case XK_KP_Subtract: return u8'-'; - case XK_KP_Multiply: return u8'*'; - case XK_KP_Divide: return u8'/'; - default: return u8'\0'; - } - - std::unreachable(); - } -} // namespace stormkit::wsi::linux::x11 +// Copyright (C) 2021 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +#include + +#include +#include +#include + +#include + +export module stormkit.wsi:linux.x11.utils; + +import stormkit.core; +import stormkit.wsi; + +import :linux.x11.log; + +export namespace stormkit::wsi::linux::x11 { + auto x11_key_to_char(xcb_keysym_t key) noexcept -> char; + auto x11_button_to_stormkit(xcb_button_t button) noexcept -> MouseButton; + auto default_root_window(xcb_connection_t* connection, i32 screen_id) noexcept -> xcb_window_t; +} // namespace stormkit::wsi::linux::x11 + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit::wsi::linux::x11 { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_CONST + inline auto x11_button_to_stormkit(xcb_button_t button) noexcept -> MouseButton { + switch (button) { + case XCB_BUTTON_INDEX_1: return MouseButton::LEFT; + case XCB_BUTTON_INDEX_2: return MouseButton::MIDDLE; + case XCB_BUTTON_INDEX_3: return MouseButton::RIGHT; + case XCB_BUTTON_INDEX_4: return MouseButton::BUTTON_1; + case XCB_BUTTON_INDEX_5: return MouseButton::BUTTON_2; + default: break; + } + + std::unreachable(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto screen_of_display(xcb_connection_t* c, int screen) noexcept -> xcb_screen_t* { + auto iter = xcb_screen_iterator_t {}; + + for (iter = xcb_setup_roots_iterator(xcb_get_setup(c)); iter.rem; --screen, xcb_screen_next(&iter)) + if (screen == 0) return iter.data; + + return iter.data; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto default_root_window(xcb_connection_t* connection, int32_t screen_id) noexcept -> xcb_window_t { + auto screen = screen_of_display(connection, screen_id); + + return screen->root; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_CONST + inline auto x11_key_to_char(xcb_keysym_t key) noexcept -> char { + switch (key) { + case XK_a: return u8'a'; + case XK_b: return u8'b'; + case XK_c: return u8'c'; + case XK_d: return u8'd'; + case XK_e: return u8'e'; + case XK_f: return u8'f'; + case XK_g: return u8'g'; + case XK_h: return u8'h'; + case XK_i: return u8'i'; + case XK_j: return u8'j'; + case XK_k: return u8'k'; + case XK_l: return u8'l'; + case XK_m: return u8'm'; + case XK_n: return u8'n'; + case XK_o: return u8'o'; + case XK_p: return u8'p'; + case XK_q: return u8'q'; + case XK_r: return u8'r'; + case XK_s: return u8's'; + case XK_t: return u8't'; + case XK_u: return u8'u'; + case XK_v: return u8'v'; + case XK_w: return u8'w'; + case XK_x: return u8'x'; + case XK_y: return u8'y'; + case XK_z: return u8'z'; + case XK_A: return u8'A'; + case XK_B: return u8'B'; + case XK_C: return u8'C'; + case XK_D: return u8'D'; + case XK_E: return u8'E'; + case XK_F: return u8'F'; + case XK_G: return u8'G'; + case XK_H: return u8'H'; + case XK_I: return u8'I'; + case XK_J: return u8'J'; + case XK_K: return u8'K'; + case XK_L: return u8'L'; + case XK_M: return u8'M'; + case XK_N: return u8'N'; + case XK_O: return u8'O'; + case XK_P: return u8'P'; + case XK_Q: return u8'Q'; + case XK_R: return u8'R'; + case XK_S: return u8'S'; + case XK_T: return u8'T'; + case XK_U: return u8'U'; + case XK_V: return u8'V'; + case XK_W: return u8'W'; + case XK_X: return u8'X'; + case XK_Y: return u8'Y'; + case XK_Z: return u8'Z'; + case XK_KP_0: [[fallthrough]]; + case XK_0: return u8'0'; + case XK_KP_1: [[fallthrough]]; + case XK_1: return u8'1'; + case XK_KP_2: [[fallthrough]]; + case XK_2: return u8'2'; + case XK_KP_3: [[fallthrough]]; + case XK_3: return u8'3'; + case XK_KP_4: [[fallthrough]]; + case XK_4: return u8'4'; + case XK_KP_5: [[fallthrough]]; + case XK_5: return u8'5'; + case XK_KP_6: [[fallthrough]]; + case XK_6: return u8'6'; + case XK_KP_7: [[fallthrough]]; + case XK_7: return u8'7'; + case XK_KP_8: [[fallthrough]]; + case XK_8: return u8'8'; + case XK_KP_9: [[fallthrough]]; + case XK_9: return u8'9'; + case XK_bracketleft: return u8'{'; + case XK_bracketright: return u8'}'; + case XK_semicolon: return u8';'; + case XK_comma: return u8','; + case XK_period: return u8'.'; + case XK_quoteright: [[fallthrough]]; + case XK_quoteleft: return u8'"'; + case XK_slash: return u8'/'; + case XK_backslash: return u8'\\'; + case XK_dead_grave: return u8'~'; + case XK_equal: return u8'='; + case XK_hyphen: return u8'-'; + case XK_space: return u8' '; + case XK_Return: return u8'\n'; + case XK_Tab: return u8'\t'; + case XK_KP_Add: return u8'+'; + case XK_KP_Subtract: return u8'-'; + case XK_KP_Multiply: return u8'*'; + case XK_KP_Divide: return u8'/'; + default: return u8'\0'; + } + + std::unreachable(); + } +} // namespace stormkit::wsi::linux::x11 diff --git a/src/wsi/linux/x11/window.cpp b/src/wsi/linux/x11/window.cpp index 44ad009f5..89724012d 100644 --- a/src/wsi/linux/x11/window.cpp +++ b/src/wsi/linux/x11/window.cpp @@ -45,14 +45,13 @@ namespace stdv = std::views; namespace stormkit::wsi::linux::x11 { namespace { [[maybe_unused]] - constexpr auto WM_CLASS - = std::string_view("WM_CLASS"); - constexpr auto WM_HINTS_STR = std::string_view("_MOTIF_WM_HINTS"); - constexpr auto WM_PROTOCOLS = std::string_view("WM_PROTOCOLS"); - constexpr auto WM_DELETE_WINDOW = std::string_view("WM_DELETE_WINDOW"); - constexpr auto WM_STATE_STR = std::string_view("_NET_WM_STATE"); - constexpr auto WM_STATE_FULLSCREEN_STR = std::string_view("_NET_WM_STATE_FULLSCREEN"); - constexpr auto WM_STATE_HIDDEN_STR = std::string_view("_NET_WM_STATE_HIDDEN"); + constexpr auto WM_CLASS = string_view("WM_CLASS"); + constexpr auto WM_HINTS_STR = string_view("_MOTIF_WM_HINTS"); + constexpr auto WM_PROTOCOLS = string_view("WM_PROTOCOLS"); + constexpr auto WM_DELETE_WINDOW = string_view("WM_DELETE_WINDOW"); + constexpr auto WM_STATE_STR = string_view("_NET_WM_STATE"); + constexpr auto WM_STATE_FULLSCREEN_STR = string_view("_NET_WM_STATE_FULLSCREEN"); + constexpr auto WM_STATE_HIDDEN_STR = string_view("_NET_WM_STATE_HIDDEN"); constexpr auto MWM_HINTS_FUNCTIONS = 1 << 0; constexpr auto MWM_HINTS_DECORATIONS = 1 << 1; @@ -62,48 +61,48 @@ namespace stormkit::wsi::linux::x11 { constexpr auto MWM_DECOR_TITLE = 1 << 3; constexpr auto MWM_DECOR_MENU = 1 << 4; [[maybe_unused]] - constexpr auto MWM_DECOR_MINIMIZE - = 1 << 5; + constexpr auto MWM_DECOR_MINIMIZE = 1 << 5; [[maybe_unused]] - constexpr auto MWM_DECOR_MAXIMIZE - = 1 << 6; + constexpr auto MWM_DECOR_MAXIMIZE = 1 << 6; constexpr auto MWM_FUNC_RESIZE = 1 << 1; constexpr auto MWM_FUNC_MOVE = 1 << 2; [[maybe_unused]] - constexpr auto MWM_FUNC_MINIMIZE - = 1 << 3; + constexpr auto MWM_FUNC_MINIMIZE = 1 << 3; constexpr auto MWM_FUNC_MAXIMIZE = 1 << 4; constexpr auto MWM_FUNC_CLOSE = 1 << 5; constexpr auto _NET_WM_STATE_REMOVE = 0; // remove/unset property constexpr auto _NET_WM_STATE_ADD = 1; // add/set property [[maybe_unused]] - constexpr auto _NET_WM_STATE_TOGGLE - = 2; // toggle property + constexpr auto _NET_WM_STATE_TOGGLE = 2; // toggle property - constexpr auto MOUSE_RAW_EVENTS = u32 { XCB_INPUT_XI_EVENT_MASK_RAW_BUTTON_PRESS - | XCB_INPUT_XI_EVENT_MASK_RAW_BUTTON_RELEASE - | XCB_INPUT_XI_EVENT_MASK_RAW_MOTION }; - constexpr auto KEYBOARD_RAW_EVENTS = u32 { XCB_INPUT_XI_EVENT_MASK_RAW_KEY_PRESS - | XCB_INPUT_XI_EVENT_MASK_RAW_KEY_RELEASE }; - constexpr auto KEYBOARD_EVENTS = u32 { XCB_INPUT_XI_EVENT_MASK_KEY_PRESS | XCB_INPUT_XI_EVENT_MASK_KEY_RELEASE }; + constexpr auto MOUSE_RAW_EVENTS = u32 { + XCB_INPUT_XI_EVENT_MASK_RAW_BUTTON_PRESS + | XCB_INPUT_XI_EVENT_MASK_RAW_BUTTON_RELEASE + | XCB_INPUT_XI_EVENT_MASK_RAW_MOTION + }; + constexpr auto KEYBOARD_RAW_EVENTS = u32 { + XCB_INPUT_XI_EVENT_MASK_RAW_KEY_PRESS | XCB_INPUT_XI_EVENT_MASK_RAW_KEY_RELEASE + }; + constexpr auto KEYBOARD_EVENTS = u32 { XCB_INPUT_XI_EVENT_MASK_KEY_PRESS | XCB_INPUT_XI_EVENT_MASK_KEY_RELEASE }; constexpr auto XINPUT_MASK_MODIFIERS = u32 { XCB_INPUT_MODIFIER_MASK_ANY }; - constexpr const auto EVENTS = XCB_EVENT_MASK_FOCUS_CHANGE - | XCB_EVENT_MASK_BUTTON_PRESS - | XCB_EVENT_MASK_BUTTON_RELEASE - | XCB_EVENT_MASK_BUTTON_MOTION - | XCB_EVENT_MASK_POINTER_MOTION - | XCB_EVENT_MASK_KEY_PRESS - | XCB_EVENT_MASK_KEY_RELEASE - | XCB_EVENT_MASK_STRUCTURE_NOTIFY - | XCB_EVENT_MASK_ENTER_WINDOW - | XCB_EVENT_MASK_LEAVE_WINDOW - | XCB_EVENT_MASK_VISIBILITY_CHANGE - | XCB_EVENT_MASK_PROPERTY_CHANGE - | XCB_EVENT_MASK_EXPOSURE; + constexpr const auto + EVENTS = XCB_EVENT_MASK_FOCUS_CHANGE + | XCB_EVENT_MASK_BUTTON_PRESS + | XCB_EVENT_MASK_BUTTON_RELEASE + | XCB_EVENT_MASK_BUTTON_MOTION + | XCB_EVENT_MASK_POINTER_MOTION + | XCB_EVENT_MASK_KEY_PRESS + | XCB_EVENT_MASK_KEY_RELEASE + | XCB_EVENT_MASK_STRUCTURE_NOTIFY + | XCB_EVENT_MASK_ENTER_WINDOW + | XCB_EVENT_MASK_LEAVE_WINDOW + | XCB_EVENT_MASK_VISIBILITY_CHANGE + | XCB_EVENT_MASK_PROPERTY_CHANGE + | XCB_EVENT_MASK_EXPOSURE; constexpr auto REQUIRED_MAP_PARTS = u16 { XCB_XKB_MAP_PART_KEY_TYPES @@ -137,7 +136,7 @@ namespace stormkit::wsi::linux::x11 { ///////////////////////////////////// ///////////////////////////////////// - auto Window::open(std::string title, const math::Extent2& extent, WindowFlag flags) noexcept -> void { + auto Window::open(string title, const math::uextent2& extent, WindowFlag flags) noexcept -> void { const auto& connection = xcb::get_globals().connection; const auto screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data; @@ -149,7 +148,7 @@ namespace stormkit::wsi::linux::x11 { { m_color_map = xcb::ColorMap::create(connection); xcb_create_colormap(connection, XCB_COLORMAP_ALLOC_NONE, m_color_map, screen->root, screen->root_visual); - const auto value_list = std::array { screen->white_pixel, EVENTS, m_color_map }; + const auto value_list = array { screen->white_pixel, EVENTS, m_color_map }; const auto cookie = xcb_create_window_checked(connection, screen->root_depth, @@ -304,18 +303,18 @@ namespace stormkit::wsi::linux::x11 { xcb_icccm_set_wm_normal_hints(connection, m_window, &size_hints); } - xcb::get_atom(WM_CLASS, false) - .transform([this, &connection](auto&& atom) noexcept { - constexpr auto CLASS_NAME = "StormKit.Window\0StormKit.Window"; - xcb_change_property(connection, XCB_PROP_MODE_REPLACE, m_window, atom, atom, 8, 32, CLASS_NAME); - }) - .transform_error(xcb::atom_error(WM_HINTS_STR)); + auto _ = xcb::get_atom(WM_CLASS, false) + .transform([this, &connection](auto&& atom) noexcept { + constexpr auto CLASS_NAME = "StormKit.Window\0StormKit.Window"; + xcb_change_property(connection, XCB_PROP_MODE_REPLACE, m_window, atom, atom, 8, 32, CLASS_NAME); + }) + .transform_error(xcb::atom_error(WM_HINTS_STR)); - xcb::get_atom(WM_HINTS_STR, false) - .transform([this, &window_hints, &connection](auto&& atom) noexcept { - xcb_change_property(connection, XCB_PROP_MODE_REPLACE, m_window, atom, atom, 32, 5, &window_hints); - }) - .transform_error(xcb::atom_error(WM_HINTS_STR)); + auto _ = xcb::get_atom(WM_HINTS_STR, false) + .transform([this, &window_hints, &connection](auto&& atom) noexcept { + xcb_change_property(connection, XCB_PROP_MODE_REPLACE, m_window, atom, atom, 32, 5, &window_hints); + }) + .transform_error(xcb::atom_error(WM_HINTS_STR)); m_handles.connection = connection; m_handles.window = m_window; @@ -337,13 +336,13 @@ namespace stormkit::wsi::linux::x11 { 1, &(*close_atom)); - xcb::get_atom(WM_STATE_STR, false) - .transform([this, &connection](auto&& atom) noexcept { - xcb_change_property(connection, XCB_PROP_MODE_REPLACE, m_window, atom, XCB_ATOM_ATOM, 32, 0, nullptr); - }) - .transform_error(xcb::atom_error(WM_STATE_STR)); + auto _ = xcb::get_atom(WM_STATE_STR, false) + .transform([this, &connection](auto&& atom) noexcept { + xcb_change_property(connection, XCB_PROP_MODE_REPLACE, m_window, atom, XCB_ATOM_ATOM, 32, 0, nullptr); + }) + .transform_error(xcb::atom_error(WM_STATE_STR)); - xcb::get_atom(WM_STATE_HIDDEN_STR, false).transform_error(xcb::atom_error(WM_STATE_HIDDEN_STR)); + auto _ = xcb::get_atom(WM_STATE_HIDDEN_STR, false).transform_error(xcb::atom_error(WM_STATE_HIDDEN_STR)); xcb_map_window(connection, m_window); @@ -351,7 +350,7 @@ namespace stormkit::wsi::linux::x11 { if (not check_flag_bit(flags, WindowFlag::EXTERNAL_CONTEXT)) { m_graphics_context = xcb::GraphicsContext::create(connection); - const auto values = std::array { screen->white_pixel, screen->black_pixel, 0_u32 }; + const auto values = array { screen->white_pixel, screen->black_pixel, 0_u32 }; xcb_create_gc(connection, m_graphics_context, m_window, @@ -415,7 +414,7 @@ namespace stormkit::wsi::linux::x11 { ///////////////////////////////////// ///////////////////////////////////// - auto Window::clear(const rgbcolor& color) noexcept -> void { + auto Window::clear(const ucolor_rgb& color) noexcept -> void { expects(m_graphics_context, "clear called on a window opened with EXTERNAL_CONTEXT flag"); const auto _color = (255_u32 << 24) | as(color.r) << 16 | as(color.g) << 8 | color.b; stdr::fill(m_framebuffer, _color); @@ -429,7 +428,7 @@ namespace stormkit::wsi::linux::x11 { ///////////////////////////////////// ///////////////////////////////////// - auto Window::fill_framebuffer(std::span> pixels) noexcept -> void { + auto Window::fill_framebuffer(array_view pixels) noexcept -> void { expects(m_graphics_context, "fill_framebuffer called on a window opened with EXTERNAL_CONTEXT flag"); const auto count = std::min(stdr::size(pixels), stdr::size(m_framebuffer)); stdr::copy(pixels | stdv::take(count) | stdv::transform([](const auto& col) static noexcept { @@ -446,7 +445,7 @@ namespace stormkit::wsi::linux::x11 { ///////////////////////////////////// ///////////////////////////////////// - auto Window::set_title(std::string title) noexcept -> void { + auto Window::set_title(string title) noexcept -> void { const auto& globals = xcb::get_globals(); xcb_change_property(globals.connection, @@ -465,13 +464,13 @@ namespace stormkit::wsi::linux::x11 { ///////////////////////////////////// ///////////////////////////////////// - auto Window::set_extent(const math::Extent2& extent) noexcept -> void { + auto Window::set_extent(const math::uextent2& extent) noexcept -> void { auto& globals = xcb::get_globals(); const auto mask = XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT; const auto width = as(extent.width); const auto height = as(extent.height); - const auto values = std::array { as(width), as(height) }; + const auto values = array { as(width), as(height) }; xcb_configure_window(globals.connection, m_window, mask, stdr::data(values)); @@ -483,34 +482,34 @@ namespace stormkit::wsi::linux::x11 { ///////////////////////////////////// ///////////////////////////////////// auto Window::set_fullscreen(bool enabled) noexcept -> void { - xcb::get_atom(WM_STATE_FULLSCREEN_STR, false) - .transform_error(xcb::atom_error(WM_STATE_FULLSCREEN_STR)) - .and_then([](auto&& fullscreen_atom) static noexcept { - return xcb::get_atom(WM_STATE_STR, false).transform(monadic::as_tuple(std::move(fullscreen_atom))); - }) - .transform_error(xcb::atom_error(WM_STATE_STR)) - .transform(monadic::unpack_tuple_to([this, enabled](auto&& fullscreen_atom, auto&& state_atom) { - auto& globals = xcb::get_globals(); - auto ev = xcb_client_message_event_t {}; - ev.response_type = XCB_CLIENT_MESSAGE; - ev.type = state_atom; - ev.format = 32; - ev.window = m_window; - ev.data.data32[0] = enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; - ev.data.data32[1] = fullscreen_atom; - ev.data.data32[2] = XCB_ATOM_NONE; - ev.data.data32[3] = 0; - ev.data.data32[4] = 0; - - xcb_send_event(globals.connection, - 1, - m_window, - XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY, - std::bit_cast(&ev)); - - xcb_flush(globals.connection); - m_state.fullscreen = enabled; - })); + auto _ = xcb::get_atom(WM_STATE_FULLSCREEN_STR, false) + .transform_error(xcb::atom_error(WM_STATE_FULLSCREEN_STR)) + .and_then([](auto&& fullscreen_atom) static noexcept { + return xcb::get_atom(WM_STATE_STR, false).transform(monadic::as_tuple(std::move(fullscreen_atom))); + }) + .transform_error(xcb::atom_error(WM_STATE_STR)) + .transform(monadic::unpack_tuple_to([this, enabled](auto&& fullscreen_atom, auto&& state_atom) { + auto& globals = xcb::get_globals(); + auto ev = xcb_client_message_event_t {}; + ev.response_type = XCB_CLIENT_MESSAGE; + ev.type = state_atom; + ev.format = 32; + ev.window = m_window; + ev.data.data32[0] = enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE; + ev.data.data32[1] = fullscreen_atom; + ev.data.data32[2] = XCB_ATOM_NONE; + ev.data.data32[3] = 0; + ev.data.data32[4] = 0; + + xcb_send_event(globals.connection, + 1, + m_window, + XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY, + std::bit_cast(&ev)); + + xcb_flush(globals.connection); + m_state.fullscreen = enabled; + })); } ///////////////////////////////////// @@ -618,7 +617,7 @@ namespace stormkit::wsi::linux::x11 { ///////////////////////////////////// ///////////////////////////////////// - auto Window::set_mouse_position(const math::vec2i& position, u8) noexcept -> void { + auto Window::set_mouse_position(const math::ivec2& position, u8) noexcept -> void { auto& globals = xcb::get_globals(); const auto _position = position.to(); @@ -688,7 +687,7 @@ namespace stormkit::wsi::linux::x11 { auto configure_event = std::bit_cast(xevent); if ((configure_event->width != m_state.extent.width) || (configure_event->height != m_state.extent.height)) { - m_state.extent = math::Extent2 { configure_event->width, configure_event->height }.narrow_to(); + m_state.extent = math::extent2 { configure_event->width, configure_event->height }.narrow_to(); if (m_graphics_context) update_framebuffer(); @@ -698,11 +697,11 @@ namespace stormkit::wsi::linux::x11 { case XCB_CLIENT_MESSAGE: { auto client_message_event = std::bit_cast(xevent); - xcb::get_atom(WM_DELETE_WINDOW, false) - .transform([this, &client_message_event](auto&& atom) noexcept { - if (client_message_event->data.data32[0] == atom) closed_event(); - }) - .transform_error(xcb::atom_error(WM_DELETE_WINDOW)); + auto _ = xcb::get_atom(WM_DELETE_WINDOW, false) + .transform([this, &client_message_event](auto&& atom) noexcept { + if (client_message_event->data.data32[0] == atom) closed_event(); + }) + .transform_error(xcb::atom_error(WM_DELETE_WINDOW)); } break; case XCB_MAPPING_NOTIFY: { auto mapping_notify_event = std::bit_cast(xevent); @@ -717,14 +716,9 @@ namespace stormkit::wsi::linux::x11 { auto property_notify_event = std::bit_cast(xevent); auto _ = xcb::get_atom(WM_STATE_STR, false).transform([this, property_notify_event](auto wm_state_atom) { if (wm_state_atom == property_notify_event->atom) { - auto& globals = xcb::get_globals(); - const auto cookie = xcb_get_property(globals.connection, - false, - m_window, - wm_state_atom, - XCB_ATOM_ATOM, - 0, - 32); + auto& globals = xcb::get_globals(); + const auto + cookie = xcb_get_property(globals.connection, false, m_window, wm_state_atom, XCB_ATOM_ATOM, 0, 32); auto error = xcb::GenericError::empty(); auto reply = xcb_get_property_reply(globals.connection, cookie, &error.handle()); @@ -758,7 +752,7 @@ namespace stormkit::wsi::linux::x11 { auto button = button_event->detail; WindowBase::mouse_button_down_event(GLOBAL_MOUSE_ID, x11_button_to_stormkit(as(button)), - math::vec2i { button_event->event_x, button_event->event_y }); + math::ivec2 { button_event->event_x, button_event->event_y }); } break; case XCB_INPUT_BUTTON_RELEASE: [[fallthrough]]; case XCB_INPUT_RAW_BUTTON_RELEASE: { @@ -767,7 +761,7 @@ namespace stormkit::wsi::linux::x11 { auto button = button_event->detail; WindowBase::mouse_button_up_event(GLOBAL_MOUSE_ID, x11_button_to_stormkit(as(button)), - math::vec2i { button_event->event_x, button_event->event_y }); + math::ivec2 { button_event->event_x, button_event->event_y }); } break; } } @@ -801,10 +795,8 @@ namespace stormkit::wsi::linux::x11 { const auto device_id = xkb_x11_get_core_keyboard_device_id(globals.connection); - m_keymap = common::xkb::Keymap::take(xkb_x11_keymap_new_from_device(globals.xkb_context, - globals.connection, - device_id, - XKB_KEYMAP_COMPILE_NO_FLAGS)); + m_keymap = common::xkb::Keymap:: + take(xkb_x11_keymap_new_from_device(globals.xkb_context, globals.connection, device_id, XKB_KEYMAP_COMPILE_NO_FLAGS)); if (not m_keymap) { elog("Failed to compile a keymap"); return; diff --git a/src/wsi/linux/x11/window.mpp b/src/wsi/linux/x11/window.cppm similarity index 73% rename from src/wsi/linux/x11/window.mpp rename to src/wsi/linux/x11/window.cppm index 4212bb41f..a2b414a4e 100644 --- a/src/wsi/linux/x11/window.mpp +++ b/src/wsi/linux/x11/window.cppm @@ -1,230 +1,212 @@ -// Copyright (C) 2021 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -#include - -#include -#include -#include -STORMKIT_PUSH_WARNINGS -#pragma GCC diagnostic ignored "-Wkeyword-macro" -#define explicit _explicit -#include -#undef explicit -STORMKIT_POP_WARNINGS - -export module stormkit.wsi:linux.x11.window; - -import std; - -import stormkit.core; -import stormkit.wsi; - -import :common.window_base; - -import :linux.common.xkb; - -import :linux.x11.context; -import :linux.x11.xcb; -import :linux.x11.log; -import :linux.x11.utils; - -namespace stdr = std::ranges; - -export namespace stormkit::wsi::linux::x11 { - namespace xcb { - template - inline constexpr auto XCB_DELETER = [](auto val) { - auto& globals = get_globals(); - - Destructor(globals.connection, val); - }; - using Window = RAIICapsule, - struct WindowTag, - XCB_WINDOW_NONE>; - using ColorMap = RAIICapsule, - struct ColorMapTag, - XCB_NONE>; - using GraphicsContext = RAIICapsule, - struct GraphicsContextTag, - XCB_NONE>; - using Image = RAIICapsule; - using Pixmap = RAIICapsule, - struct PixmapTag, - XCB_NONE>; - } // namespace xcb - - class Window: public stormkit::wsi::common::WindowBase { - public: - struct Handles { - xcb_connection_t* connection; - xcb_window_t window; - xcb_key_symbols_t* key_symbols; - xkb_state* state; - }; - - Window() noexcept; - ~Window() noexcept; - - Window(const Window&) noexcept = delete; - auto operator=(const Window&) noexcept -> Window& = delete; - - Window(Window&&) noexcept; - auto operator=(Window&&) noexcept -> Window&; - - auto open(std::string title, const math::Extent2& size, WindowFlag flags) noexcept - -> void; - auto close() noexcept -> void; - - auto handle_events() noexcept -> void; - - auto clear(const rgbcolor& color) noexcept -> void; - auto fill_framebuffer(std::span> colors) noexcept -> void; - - auto set_title(std::string title) noexcept -> void; - auto set_extent(const math::Extent2& extent) noexcept -> void; - auto set_fullscreen(bool fullscreen) noexcept -> void; - - auto confine_mouse(bool confined, u8 mouse_id) noexcept -> void; - [[nodiscard]] - auto is_mouse_confined(u8 mouse_id) const noexcept -> bool; - - auto lock_mouse(bool locked, u8 mouse_id) noexcept -> void; - [[nodiscard]] - auto is_mouse_locked(u8 mouse_id) const noexcept -> bool; - - auto hide_mouse(bool hidden, u8 mouse_id) noexcept -> void; - [[nodiscard]] - auto is_mouse_hidden(u8 mouse_id) const noexcept -> bool; - - auto set_relative_mouse(bool enabled, u8 mouse_id) noexcept -> void; - [[nodiscard]] - auto is_mouse_relative(u8 mouse_id) const noexcept -> bool; - - auto set_key_repeat(bool enabled, u8 keyboard_id) noexcept -> void; - [[nodiscard]] - auto is_key_repeat_enabled(u8 keyboard_id) const noexcept -> bool; - - auto show_virtual_keyboard(bool visible) noexcept -> void; - [[nodiscard]] - auto is_virtual_keyboard_visible() const noexcept -> bool; - - auto set_mouse_position(const math::vec2i& position, u8 mouse_id) noexcept -> void; - - [[nodiscard]] - auto native_handle() const noexcept -> NativeHandle; - - private: - auto process_events(xcb_generic_event_t* xevent) -> void; - auto update_keymap() -> void; - - auto handle_key_event(xcb_keycode_t keycode, bool up) noexcept -> void; - - auto update_framebuffer() noexcept -> void; - - int m_xi_opcode = 0; - - Handles m_handles; - - xcb::Window m_window = xcb::Window::empty(); - xcb::ColorMap m_color_map = xcb::ColorMap::empty(); - xcb::GraphicsContext m_graphics_context = xcb::GraphicsContext::empty(); - xcb::Image m_image = xcb::Image::empty(); - std::span m_framebuffer; - xcb::Pixmap m_pixmap = xcb::Pixmap::empty(); - xcb::KeySymbols m_key_symbols = xcb::KeySymbols::empty(); - common::xkb::Keymap m_keymap = common::xkb::Keymap::empty(); - common::xkb::State m_xkb_state = common::xkb::State::empty(); - common::xkb::Mods m_mods; - f32 m_dpi = 1.f; - }; -} // namespace stormkit::wsi::linux::x11 - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::wsi::linux::x11 { - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Window::Window() noexcept { - xcb::init(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline Window::Window(Window&&) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::operator=(Window&&) noexcept -> Window& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::is_mouse_confined(u8) const noexcept -> bool { - return m_mouse_states[GLOBAL_MOUSE_ID].confined; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - inline auto Window::is_mouse_locked(u8) const noexcept -> bool { - return m_mouse_states[GLOBAL_MOUSE_ID].locked; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline auto Window::is_mouse_hidden(u8) const noexcept -> bool { - return m_mouse_states[GLOBAL_MOUSE_ID].hidden; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline auto Window::is_mouse_relative(u8) const noexcept -> bool { - return m_mouse_states[GLOBAL_MOUSE_ID].relative; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline auto Window::is_key_repeat_enabled(u8) const noexcept -> bool { - return m_keyboard_states[GLOBAL_KEYBOARD_ID].key_repeat; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline auto Window::is_virtual_keyboard_visible() const noexcept -> bool { - return false; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE STORMKIT_PURE - inline auto Window::native_handle() const noexcept -> NativeHandle { - return std::bit_cast(&m_handles); - } -} // namespace stormkit::wsi::linux::x11 +// Copyright (C) 2021 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include + +#include + +#include +#include +#include +STORMKIT_PUSH_WARNINGS +#pragma GCC diagnostic ignored "-Wkeyword-macro" +#define explicit _explicit +#include +#undef explicit +STORMKIT_POP_WARNINGS + +export module stormkit.wsi:linux.x11.window; + +import std; + +import stormkit.core; +import stormkit.wsi; + +import :common.window_base; + +import :linux.common.xkb; + +import :linux.x11.context; +import :linux.x11.xcb; +import :linux.x11.log; +import :linux.x11.utils; + +namespace stdr = std::ranges; + +export namespace stormkit::wsi::linux::x11 { + namespace xcb { + template + inline constexpr auto XCB_DELETER = [](auto val) { + auto& globals = get_globals(); + + Destructor(globals.connection, val); + }; + using Window + = RAIICapsule, struct WindowTag, XCB_WINDOW_NONE>; + using ColorMap + = RAIICapsule, struct ColorMapTag, XCB_NONE>; + using GraphicsContext + = RAIICapsule, struct GraphicsContextTag, XCB_NONE>; + using Image = RAIICapsule; + using Pixmap = RAIICapsule, struct PixmapTag, XCB_NONE>; + } // namespace xcb + + class Window: public stormkit::wsi::common::WindowBase { + public: + struct Handles { + xcb_connection_t* connection; + xcb_window_t window; + xcb_key_symbols_t* key_symbols; + xkb_state* state; + }; + + Window() noexcept; + ~Window() noexcept; + + Window(const Window&) noexcept = delete; + auto operator=(const Window&) noexcept -> Window& = delete; + + Window(Window&&) noexcept; + auto operator=(Window&&) noexcept -> Window&; + + auto open(string title, const math::uextent2& size, WindowFlag flags) noexcept -> void; + auto close() noexcept -> void; + + auto handle_events() noexcept -> void; + + auto clear(const ucolor_rgb& color) noexcept -> void; + auto fill_framebuffer(array_view colors) noexcept -> void; + + auto set_title(string title) noexcept -> void; + auto set_extent(const math::uextent2& extent) noexcept -> void; + auto set_fullscreen(bool fullscreen) noexcept -> void; + + auto confine_mouse(bool confined, u8 mouse_id) noexcept -> void; + [[nodiscard]] + auto is_mouse_confined(u8 mouse_id) const noexcept -> bool; + + auto lock_mouse(bool locked, u8 mouse_id) noexcept -> void; + [[nodiscard]] + auto is_mouse_locked(u8 mouse_id) const noexcept -> bool; + + auto hide_mouse(bool hidden, u8 mouse_id) noexcept -> void; + [[nodiscard]] + auto is_mouse_hidden(u8 mouse_id) const noexcept -> bool; + + auto set_relative_mouse(bool enabled, u8 mouse_id) noexcept -> void; + [[nodiscard]] + auto is_mouse_relative(u8 mouse_id) const noexcept -> bool; + + auto set_key_repeat(bool enabled, u8 keyboard_id) noexcept -> void; + [[nodiscard]] + auto is_key_repeat_enabled(u8 keyboard_id) const noexcept -> bool; + + auto show_virtual_keyboard(bool visible) noexcept -> void; + [[nodiscard]] + auto is_virtual_keyboard_visible() const noexcept -> bool; + + auto set_mouse_position(const math::ivec2& position, u8 mouse_id) noexcept -> void; + + [[nodiscard]] + auto native_handle() const noexcept -> NativeHandle; + + private: + auto process_events(xcb_generic_event_t* xevent) -> void; + auto update_keymap() -> void; + + auto handle_key_event(xcb_keycode_t keycode, bool up) noexcept -> void; + + auto update_framebuffer() noexcept -> void; + + int m_xi_opcode = 0; + + Handles m_handles; + + xcb::Window m_window = xcb::Window::empty(); + xcb::ColorMap m_color_map = xcb::ColorMap::empty(); + xcb::GraphicsContext m_graphics_context = xcb::GraphicsContext::empty(); + xcb::Image m_image = xcb::Image::empty(); + array_view m_framebuffer; + xcb::Pixmap m_pixmap = xcb::Pixmap::empty(); + xcb::KeySymbols m_key_symbols = xcb::KeySymbols::empty(); + common::xkb::Keymap m_keymap = common::xkb::Keymap::empty(); + common::xkb::State m_xkb_state = common::xkb::State::empty(); + common::xkb::Mods m_mods; + f32 m_dpi = 1.f; + }; +} // namespace stormkit::wsi::linux::x11 + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit::wsi::linux::x11 { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline Window::Window() noexcept { + xcb::init(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline Window::Window(Window&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::operator=(Window&&) noexcept -> Window& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::is_mouse_confined(u8) const noexcept -> bool { + return m_mouse_states[GLOBAL_MOUSE_ID].confined; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Window::is_mouse_locked(u8) const noexcept -> bool { + return m_mouse_states[GLOBAL_MOUSE_ID].locked; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_PURE + inline auto Window::is_mouse_hidden(u8) const noexcept -> bool { + return m_mouse_states[GLOBAL_MOUSE_ID].hidden; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_PURE + inline auto Window::is_mouse_relative(u8) const noexcept -> bool { + return m_mouse_states[GLOBAL_MOUSE_ID].relative; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_PURE + inline auto Window::is_key_repeat_enabled(u8) const noexcept -> bool { + return m_keyboard_states[GLOBAL_KEYBOARD_ID].key_repeat; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_PURE + inline auto Window::is_virtual_keyboard_visible() const noexcept -> bool { + return false; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_PURE + inline auto Window::native_handle() const noexcept -> NativeHandle { + return std::bit_cast(&m_handles); + } +} // namespace stormkit::wsi::linux::x11 diff --git a/src/wsi/linux/x11/xcb.cppm b/src/wsi/linux/x11/xcb.cppm new file mode 100644 index 000000000..b0c9613ba --- /dev/null +++ b/src/wsi/linux/x11/xcb.cppm @@ -0,0 +1,67 @@ +// Copyright (C) 2021 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +module; + +#include +#include +#include +#include +#include + +#include + +export module stormkit.wsi:linux.x11.xcb; + +import std; + +import stormkit.core; + +import :linux.x11.log; + +export namespace stormkit::wsi::linux::x11 { + struct Error { + string message; + }; + + namespace xcb { + using Connection = RAIICapsule; + using ErrorContext = RAIICapsule< + xcb_errors_context_t*, + monadic::init_by(), + xcb_errors_context_free, + struct ErrorContextTag, + nullptr>; + using GenericError = RAIICapsule; + using InternAtomReply + = RAIICapsule; + using AtomNameReply + = RAIICapsule; + using InputXIQueryDeviceReply = RAIICapsule; + using KeySymbols + = RAIICapsule; + + constexpr auto atom_error(string_view msg, string_view atom_name) -> decltype(auto); + } // namespace xcb +} // namespace stormkit::wsi::linux::x11 + +export namespace stormkit::wsi::linux::x11::xcb { + STORMKIT_FORCE_INLINE STORMKIT_PURE + constexpr auto atom_error(string_view atom_name) -> decltype(auto) { + return [atom_name](Error&& error) noexcept -> Error { + elog("Failed to get atom " + "{}\n > reason: {}", + atom_name, + error.message); + return std::forward(error); + }; + } +} // namespace stormkit::wsi::linux::x11::xcb diff --git a/src/wsi/linux/x11/xcb.mpp b/src/wsi/linux/x11/xcb.mpp deleted file mode 100644 index cabe661b4..000000000 --- a/src/wsi/linux/x11/xcb.mpp +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (C) 2021 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include -#include -#include -#include -#include - -#include - -export module stormkit.wsi:linux.x11.xcb; - -import std; - -import stormkit.core; - -import :linux.x11.log; - -export namespace stormkit::wsi::linux::x11 { - struct Error { - std::string message; - }; - - namespace xcb { - using Connection = RAIICapsule; - using ErrorContext = RAIICapsule< - xcb_errors_context_t*, - monadic::init_by(), - xcb_errors_context_free, - struct ErrorContextTag, - nullptr>; - using GenericError = RAIICapsule; - using InternAtomReply = RAIICapsule; - using AtomNameReply = RAIICapsule; - using InputXIQueryDeviceReply = RAIICapsule; - using KeySymbols = RAIICapsule; - - constexpr auto atom_error(std::string_view msg, std::string_view atom_name) - -> decltype(auto); - } // namespace xcb -} // namespace stormkit::wsi::linux::x11 - -export namespace stormkit::wsi::linux::x11::xcb { - STORMKIT_FORCE_INLINE STORMKIT_PURE - constexpr auto atom_error(std::string_view atom_name) -> decltype(auto) { - return [atom_name](Error&& error) noexcept -> Error { - elog("Failed to get atom " - "{}\n > reason: {}", - atom_name, - error.message); - return std::forward(error); - }; - } -} // namespace stormkit::wsi::linux::x11::xcb diff --git a/src/wsi/macos/monitor.mpp b/src/wsi/macos/monitor.cppm similarity index 96% rename from src/wsi/macos/monitor.mpp rename to src/wsi/macos/monitor.cppm index b2037221c..803d3c06c 100644 --- a/src/wsi/macos/monitor.mpp +++ b/src/wsi/macos/monitor.cppm @@ -17,7 +17,7 @@ namespace stormkit::wsi::macos { ///////////////////////////////////// ///////////////////////////////////// auto get_monitors(WM, [[maybe_unused]] bool update = false) noexcept - -> std::span { + -> array_view { return {}; } diff --git a/src/wsi/macos/swift/CppBridge.cpp b/src/wsi/macos/swift/CppBridge.cpp index 336111155..44fd46d9e 100644 --- a/src/wsi/macos/swift/CppBridge.cpp +++ b/src/wsi/macos/swift/CppBridge.cpp @@ -29,7 +29,7 @@ namespace stormkit::wsi::macos { } consteval auto generate_key_array() -> decltype(auto) { - auto out = std::array {}; + auto out = array {}; stdr::fill(out, Key::UNKNOWN); out[0x00] = Key::A; @@ -159,8 +159,8 @@ namespace stormkit::wsi::macos { return out; } - consteval auto generate_scancode_array(std::span keys) -> decltype(auto) { - auto out = std::array {}; + consteval auto generate_scancode_array(array_view keys) -> decltype(auto) { + auto out = array {}; stdr::fill(out, 0); for (auto i : range(256_u8)) { @@ -202,7 +202,7 @@ extern "C" { EXPECTS(ptr != 0); auto& window = *std::bit_cast(ptr); - window.WindowBase::set_extent(math::Extent2 { width, height }.to()); + window.WindowBase::set_extent(math::extent2 { width, height }.to()); window.resized_event(window.extent()); } diff --git a/src/wsi/macos/window.mpp b/src/wsi/macos/window.cppm similarity index 93% rename from src/wsi/macos/window.mpp rename to src/wsi/macos/window.cppm index abb538f20..a8ef407aa 100644 --- a/src/wsi/macos/window.mpp +++ b/src/wsi/macos/window.cppm @@ -56,7 +56,7 @@ export namespace stormkit::wsi::macos { return *this; } - auto open(std::string title, const math::Extent2& size, WindowFlag flags) noexcept + auto open(string title, const math::uextent2& size, WindowFlag flags) noexcept -> void { const auto resizeable = check_flag_bit(flags, WindowFlag::RESIZEABLE); const auto borderless = check_flag_bit(flags, WindowFlag::BORDERLESS); @@ -82,13 +82,13 @@ export namespace stormkit::wsi::macos { auto handle_events() noexcept -> void { macOS::processEvents(); } - auto clear([[maybe_unused]] const rgbcolor& color) noexcept -> void { + auto clear([[maybe_unused]] const ucolor_rgb& color) noexcept -> void { const auto value = as(color.r) << 16 | as(color.g) << 8 | color.b; stdr::fill(m_pixels, value); m_window->drawBitmap(std::bit_cast(stdr::data(m_pixels))); } - auto fill_framebuffer(std::span> pixels) noexcept -> void { + auto fill_framebuffer(array_view pixels) noexcept -> void { const auto [width, height] = extent(); const auto count = std::min(as(stdr::size(pixels)), height * width); if (stdr::size(pixels) > stdr::size(m_pixels)) m_pixels.resize(stdr::size(pixels)); @@ -102,13 +102,13 @@ export namespace stormkit::wsi::macos { m_window->drawBitmap(std::bit_cast(stdr::data(m_pixels))); } - auto set_title(std::string title) noexcept -> void { + auto set_title(string title) noexcept -> void { if (WindowBase::set_title(std::move(title))) { m_window->setTitle(swift::String { m_state.title }); } } - auto set_extent([[maybe_unused]] const math::Extent2& extent) noexcept -> void {} + auto set_extent([[maybe_unused]] const math::uextent2& extent) noexcept -> void {} auto set_fullscreen(bool fullscreen) noexcept -> void { if (WindowBase::set_fullscreen(fullscreen)) {} @@ -180,7 +180,7 @@ export namespace stormkit::wsi::macos { return false; } - auto set_mouse_position([[maybe_unused]] const math::vec2i& position, + auto set_mouse_position([[maybe_unused]] const math::ivec2& position, [[maybe_unused]] u8 mouse_id) noexcept -> void {} [[nodiscard]] @@ -205,6 +205,6 @@ export namespace stormkit::wsi::macos { private: DeferInit m_window; - std::vector m_pixels; + dyn_array m_pixels; }; } // namespace stormkit::wsi::macos diff --git a/src/wsi/monitor.cpp b/src/wsi/monitor.cpp index a924de108..35ccb4e98 100644 --- a/src/wsi/monitor.cpp +++ b/src/wsi/monitor.cpp @@ -38,7 +38,7 @@ using namespace std::literals; namespace stormkit::wsi { ///////////////////////////////////// ///////////////////////////////////// - auto get_monitors(bool update) noexcept -> std::span { + auto get_monitors(bool update) noexcept -> array_view { return impl::get_monitors(wm(), update); } diff --git a/src/wsi/win32/keyboard.mpp b/src/wsi/win32/keyboard.cppm similarity index 99% rename from src/wsi/win32/keyboard.mpp rename to src/wsi/win32/keyboard.cppm index f91b46699..e110b2528 100644 --- a/src/wsi/win32/keyboard.mpp +++ b/src/wsi/win32/keyboard.cppm @@ -154,7 +154,7 @@ namespace stormkit::wsi::win32 { }); constexpr auto KEY_AS_SCANCODE = [] static noexcept -> decltype(auto) { - auto out = std::array, 111> {}; + auto out = array, 111> {}; auto i = 0_usize; for (const auto& [key, value] : SCANCODE_AS_KEY) out[i++] = std::make_pair(value.first, key); diff --git a/src/wsi/win32/log.mpp b/src/wsi/win32/log.cppm similarity index 100% rename from src/wsi/win32/log.mpp rename to src/wsi/win32/log.cppm diff --git a/src/wsi/win32/monitor.mpp b/src/wsi/win32/monitor.cppm similarity index 89% rename from src/wsi/win32/monitor.mpp rename to src/wsi/win32/monitor.cppm index bb0e0bae0..58c23433e 100644 --- a/src/wsi/win32/monitor.mpp +++ b/src/wsi/win32/monitor.cppm @@ -29,7 +29,7 @@ namespace stormkit::wsi::win32 { if ((monitor_info.dwFlags & MONITORINFOF_PRIMARY) == MONITORINFOF_PRIMARY) monitor.flags = Monitor::Flags::PRIMARY; - monitor.name = std::string { monitor_info.szDevice }; + monitor.name = string { monitor_info.szDevice }; auto dm = zeroed(); @@ -49,7 +49,7 @@ namespace stormkit::wsi::win32 { auto load_monitors(HMONITOR native, HDC, LPRECT, LPARAM data) noexcept -> BOOL { if (native == nullptr) return TRUE; - auto& monitors = *std::bit_cast*>(data); + auto& monitors = *std::bit_cast*>(data); monitors.emplace_back(load_monitor(native)); return TRUE; @@ -57,8 +57,8 @@ namespace stormkit::wsi::win32 { ///////////////////////////////////// ///////////////////////////////////// - auto get_monitors(WM, bool update = false) noexcept -> std::span { - thread_local auto monitors = std::vector {}; + auto get_monitors(WM, bool update = false) noexcept -> array_view { + thread_local auto monitors = dyn_array {}; if (update or stdr::empty(monitors)) EnumDisplayMonitors(nullptr, nullptr, load_monitors, std::bit_cast(&monitors)); diff --git a/src/wsi/win32/mouse.mpp b/src/wsi/win32/mouse.cppm similarity index 98% rename from src/wsi/win32/mouse.mpp rename to src/wsi/win32/mouse.cppm index c7b090c0f..41ca6ce01 100644 --- a/src/wsi/win32/mouse.mpp +++ b/src/wsi/win32/mouse.cppm @@ -20,7 +20,7 @@ export namespace stormkit::wsi::win32 { constexpr auto extract_mouse_position(HWND handle, WPARAM w_param, LPARAM l_param, - bool to_client = true) noexcept -> math::vec2i; + bool to_client = true) noexcept -> math::ivec2; } // namespace stormkit::wsi::win32 //////////////////////////////////////////////////////////////////// @@ -57,7 +57,7 @@ namespace stormkit::wsi::win32 { constexpr auto extract_mouse_position(HWND handle, WPARAM, LPARAM l_param, - bool to_client) noexcept -> math::vec2i { + bool to_client) noexcept -> math::ivec2 { auto position = POINT { GET_X_LPARAM(l_param), GET_Y_LPARAM(l_param) }; if (to_client) ScreenToClient(handle, &position); diff --git a/src/wsi/win32/utils.cppm b/src/wsi/win32/utils.cppm new file mode 100644 index 000000000..e69de29bb diff --git a/src/wsi/win32/window.cpp b/src/wsi/win32/window.cpp index 100c2f443..b6639086a 100644 --- a/src/wsi/win32/window.cpp +++ b/src/wsi/win32/window.cpp @@ -28,21 +28,31 @@ import :win32.mouse; namespace stdv = std::views; namespace stdr = std::ranges; +using namespace stormkit; + template constexpr auto format_as(const POINT& point, FormatContext& ctx) -> decltype(ctx.out()) { - return std::format_to(ctx.out(), "{{ .x = {}, .y = {} }}", point.x, point.y); + return std::format_to(ctx.out(), "[vec2 x: {}, y: {}]", point.x, point.y); } template constexpr auto format_as(const RECT& rect, FormatContext& ctx) -> decltype(ctx.out()) { return std::format_to(ctx.out(), - "{{ .left = {}, .top = {}, .right = {}, .bottom = {} }}", + "[rect left: {}, top: {}, right: {}, bottom: {}]", rect.left, rect.top, rect.right, rect.bottom); } +auto adjust_extent(const math::uextent2& extent, DWORD style, DWORD style_ex) noexcept -> math::extent2 { + auto rect = RECT { .left = 0, .top = 0, .right = as(extent.width), .bottom = as(extent.height) }; + + AdjustWindowRectEx(&rect, style, FALSE, style_ex); + + return { rect.right - rect.left, rect.bottom - rect.top }; +} + namespace stormkit::wsi::win32 { using HBrush = RAIICapsule; @@ -51,11 +61,9 @@ namespace stormkit::wsi::win32 { auto get_client_rect(HWND window_handle) noexcept -> RECT; - // auto get_monitor_scale(HMONITOR monitor) -> math::vec2f; + // auto get_monitor_scale(HMONITOR monitor) -> math::fvec2; - auto CALLBACK - global_on_event(HWND handle, UINT message, WPARAM w_param, LPARAM l_param) noexcept - -> LRESULT; + auto CALLBACK global_on_event(HWND handle, UINT message, WPARAM w_param, LPARAM l_param) noexcept -> LRESULT; constinit auto g_window_count = std::atomic { 0 }; } // namespace @@ -97,9 +105,7 @@ namespace stormkit::wsi::win32 { ///////////////////////////////////// ///////////////////////////////////// - auto Window::open(std::string title, - const math::Extent2& extent, - WindowFlag flags) noexcept -> void { + auto Window::open(string title, const math::uextent2& extent, WindowFlag flags) noexcept -> void { auto style = DWORD { WS_SYSMENU | WS_BORDER }; auto style_ex = DWORD { 0 }; auto h_instance = GetModuleHandleA(nullptr); @@ -119,22 +125,23 @@ namespace stormkit::wsi::win32 { SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_SYSTEM_AWARE); + const auto adjusted = adjust_extent(extent, style, style_ex); m_window_handle = CreateWindowExA(style_ex, - CLASS_NAME, - std::data(title), - style, - CW_USEDEFAULT, - CW_USEDEFAULT, - as(extent.width), - as(extent.height), - nullptr, - nullptr, - h_instance, - this); + CLASS_NAME, + std::data(title), + style, + CW_USEDEFAULT, + CW_USEDEFAULT, + adjusted.width, + adjusted.height, + nullptr, + nullptr, + h_instance, + this); m_state.open = true; auto win32_monitor = MonitorFromWindow(m_window_handle, MONITOR_DEFAULTTONEAREST); const auto monitors = get_monitors(); - const auto& monitor = *stdr::find_if(monitors, [&win32_monitor](auto&& monitor) noexcept { + const auto& monitor = *stdr::find_if(monitors, [&win32_monitor](auto&& monitor) noexcept { return monitor.native_handle == win32_monitor; }); @@ -167,14 +174,11 @@ namespace stormkit::wsi::win32 { ///////////////////////////////////// ///////////////////////////////////// - auto Window::clear(const rgbcolor& color) noexcept -> void { + auto Window::clear(const ucolor_rgb& color) noexcept -> void { if (m_win32_state.external_context) return; auto hbrush = HBrush::create(RGB(color.r, color.g, color.b)); - const auto rect = RECT { 0, - 0, - as(m_state.extent.width), - as(m_state.extent.height) }; + const auto rect = RECT { 0, 0, as(m_state.extent.width), as(m_state.extent.height) }; FillRect(m_gdi_frame_data.context, &rect, hbrush); InvalidateRect(m_window_handle, nullptr, FALSE); @@ -183,16 +187,14 @@ namespace stormkit::wsi::win32 { ///////////////////////////////////// ///////////////////////////////////// - auto Window::fill_framebuffer(std::span> pixels) noexcept -> void { + auto Window::fill_framebuffer(array_view pixels) noexcept -> void { if (m_win32_state.external_context) return; const auto [width, height] = extent(); const auto count = std::min(as(stdr::size(pixels)), height * width); - stdr::copy(pixels - | stdv::take(count) - | stdv::transform([](const auto& col) static noexcept { - return as(col.r) << 16 | as(col.g) << 8 | col.b; - }), + stdr::copy(pixels | stdv::take(count) | stdv::transform([](const auto& col) static noexcept { + return as(col.r) << 16 | as(col.g) << 8 | col.b; + }), std::bit_cast(m_gdi_frame_data.pixels_ptr.load())); InvalidateRect(m_window_handle, nullptr, FALSE); @@ -213,7 +215,7 @@ namespace stormkit::wsi::win32 { ///////////////////////////////////// ///////////////////////////////////// - auto Window::set_title(std::string title) noexcept -> void { + auto Window::set_title(string title) noexcept -> void { SetWindowTextA(m_window_handle, std::data(title)); WindowBase::set_title(std::move(title)); @@ -221,13 +223,14 @@ namespace stormkit::wsi::win32 { ///////////////////////////////////// ///////////////////////////////////// - auto Window::set_extent(const math::Extent2& extent) noexcept -> void { + auto Window::set_extent(const math::uextent2& extent) noexcept -> void { + const auto adjusted = adjust_extent(extent, m_win32_state.style, m_win32_state.style_ex); SetWindowPos(m_window_handle, HWND_TOP, 0, 0, - as(extent.width), - as(extent.height), + adjusted.width, + adjusted.height, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE | SWP_NOOWNERZORDER); } @@ -240,10 +243,7 @@ namespace stormkit::wsi::win32 { auto style_ex = m_win32_state.style_ex; if (fullscreen) { style &= as(~(WS_CAPTION | WS_THICKFRAME)); - style_ex &= as(~(WS_EX_DLGMODALFRAME - | WS_EX_WINDOWEDGE - | WS_EX_CLIENTEDGE - | WS_EX_STATICEDGE)); + style_ex &= as(~(WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE)); x = 0; y = 0; @@ -421,7 +421,7 @@ namespace stormkit::wsi::win32 { ///////////////////////////////////// ///////////////////////////////////// - auto Window::set_mouse_position(const math::vec2i& position, u8 id) noexcept -> void { + auto Window::set_mouse_position(const math::ivec2& position, u8 id) noexcept -> void { expects(id == GLOBAL_MOUSE_ID, "StormKit WSI win32 backend only support one mouse"); auto mouse_position = POINT { as(position.x), as(position.y) }; ClientToScreen(m_window_handle, &mouse_position); @@ -456,13 +456,13 @@ namespace stormkit::wsi::win32 { auto ptr = core::ptr { nullptr }; m_gdi_frame_data.context = Hdc::create(hdesktop); - m_gdi_frame_data.bitmap = HBitmap:: - create(m_gdi_frame_data.context, - std::bit_cast(&frame_bitmap_info), - as(DIB_RGB_COLORS), - &ptr, - nullptr, - as(0)); + m_gdi_frame_data + .bitmap = HBitmap::create(m_gdi_frame_data.context, + std::bit_cast(&frame_bitmap_info), + as(DIB_RGB_COLORS), + &ptr, + nullptr, + as(0)); m_gdi_frame_data.pixels_ptr = ptr; m_gdi_frame_data.extent = { width, height }; SelectObject(m_gdi_frame_data.context, m_gdi_frame_data.bitmap); @@ -474,9 +474,7 @@ namespace stormkit::wsi::win32 { ///////////////////////////////////// ///////////////////////////////////// auto get_client_rect(HWND window_handle) noexcept -> RECT { - const auto client_rect = init_by([window_handle](auto& out) noexcept { - GetClientRect(window_handle, &out); - }); + const auto client_rect = init_by([window_handle](auto& out) noexcept { GetClientRect(window_handle, &out); }); const auto lefttop = init_by([window_handle, &client_rect](POINT& out) noexcept { out.x = client_rect.left; @@ -484,8 +482,7 @@ namespace stormkit::wsi::win32 { ClientToScreen(window_handle, &out); }); - const auto rightbottom = init_by([window_handle, - &client_rect](POINT& out) noexcept { + const auto rightbottom = init_by([window_handle, &client_rect](POINT& out) noexcept { out.x = client_rect.right; out.y = client_rect.bottom; ClientToScreen(window_handle, &out); @@ -501,8 +498,8 @@ namespace stormkit::wsi::win32 { ///////////////////////////////////// ///////////////////////////////////// - // auto get_monitor_scale(HMONITOR monitor) -> math::vec2f { - // auto scale = math::vec2f {}; + // auto get_monitor_scale(HMONITOR monitor) -> math::fvec2 { + // auto scale = math::fvec2 {}; // auto x_dpi = 0u; // auto y_dpi = 0u; @@ -524,16 +521,16 @@ namespace stormkit::wsi::win32 { ///////////////////////////////////// ///////////////////////////////////// - auto handle_window_events(Window& window, - UINT message, - WPARAM w_param, - LPARAM l_param) noexcept -> std::optional { + auto handle_window_events(Window& window, UINT message, WPARAM w_param, LPARAM l_param) noexcept + -> std::optional { const auto window_handle = std::bit_cast(window.native_handle()); if (message != WM_DESTROY and not window_handle) return 0; switch (message) { case WM_DESTROY: PostQuitMessage(0); return 0; - case WM_CLOSE: window.closed_event(); return 0; + case WM_CLOSE: + if (window.closed_event()) DestroyWindow(window_handle); + return 0; case WM_CREATE: window.WindowBase::set_open(true); break; case WM_NCDESTROY: window.WindowBase::set_open(false); break; case WM_MOUSEACTIVATE: { @@ -563,12 +560,9 @@ namespace stormkit::wsi::win32 { auto win32_monitor = MonitorFromWindow(window_handle, MONITOR_DEFAULTTONEAREST); if (window.current_monitor().native_handle != win32_monitor) { const auto monitors = get_monitors(); - const auto& _monitor = *stdr::find_if(monitors, - [&win32_monitor](auto&& - monitor) noexcept { - return monitor.native_handle - == win32_monitor; - }); + const auto& _monitor = *stdr::find_if(monitors, [&win32_monitor](auto&& monitor) noexcept { + return monitor.native_handle == win32_monitor; + }); window.set_current_monitor(_monitor); window.monitor_changed_event(std::move(_monitor)); @@ -623,10 +617,7 @@ namespace stormkit::wsi::win32 { ///////////////////////////////////// ///////////////////////////////////// - auto handle_input_events(Window& window, - UINT message, - WPARAM w_param, - LPARAM l_param) noexcept -> void { + auto handle_input_events(Window& window, UINT message, WPARAM w_param, LPARAM l_param) noexcept -> void { const auto window_handle = std::bit_cast(window.native_handle()); if (not window.state().active) return; @@ -635,23 +626,17 @@ namespace stormkit::wsi::win32 { case WM_RBUTTONDOWN: [[fallthrough]]; case WM_MBUTTONDOWN: [[fallthrough]]; case WM_XBUTTONDOWN: { - const auto [x, y] = extract_mouse_position(window_handle, - w_param, - l_param, - false); + const auto [x, y] = extract_mouse_position(window_handle, w_param, l_param, false); const auto button = extract_mouse_button(message, w_param, l_param); - window.mouse_button_down_event(GLOBAL_MOUSE_ID, button, math::vec2i { x, y }); + window.mouse_button_down_event(GLOBAL_MOUSE_ID, button, math::ivec2 { x, y }); } break; case WM_LBUTTONUP: [[fallthrough]]; case WM_RBUTTONUP: [[fallthrough]]; case WM_MBUTTONUP: [[fallthrough]]; case WM_XBUTTONUP: { - const auto [x, y] = extract_mouse_position(window_handle, - w_param, - l_param, - false); + const auto [x, y] = extract_mouse_position(window_handle, w_param, l_param, false); const auto button = extract_mouse_button(message, w_param, l_param); - window.mouse_button_up_event(GLOBAL_MOUSE_ID, button, math::vec2i { x, y }); + window.mouse_button_up_event(GLOBAL_MOUSE_ID, button, math::ivec2 { x, y }); } break; case WM_KEYDOWN: [[fallthrough]]; case WM_SYSKEYDOWN: { @@ -688,27 +673,21 @@ namespace stormkit::wsi::win32 { track_mouse_event.dwFlags = TME_LEAVE; track_mouse_event.hwndTrack = window_handle; track_mouse_event.dwHoverTime = HOVER_DEFAULT; - if (TrackMouseEvent(&track_mouse_event) != FALSE) - window.win32_state().mouse_tracked = true; + if (TrackMouseEvent(&track_mouse_event) != FALSE) window.win32_state().mouse_tracked = true; } - const auto [x, y] = extract_mouse_position(window_handle, - w_param, - l_param, - false); + const auto [x, y] = extract_mouse_position(window_handle, w_param, l_param, false); if (state.locked and state.relative) { const auto relative_x = x - as(state.locked_at.x); const auto relative_y = y - as(state.locked_at.y); - window.mouse_moved_event(GLOBAL_MOUSE_ID, - math::vec2i { relative_x, relative_y }); + window.mouse_moved_event(GLOBAL_MOUSE_ID, math::ivec2 { relative_x, relative_y }); } else if (state.relative) { const auto relative_x = x - as(state.last_position.x); const auto relative_y = y - as(state.last_position.y); - window.mouse_moved_event(GLOBAL_MOUSE_ID, - math::vec2i { relative_x, relative_y }); + window.mouse_moved_event(GLOBAL_MOUSE_ID, math::ivec2 { relative_x, relative_y }); } else - window.mouse_moved_event(GLOBAL_MOUSE_ID, math::vec2i { x, y }); + window.mouse_moved_event(GLOBAL_MOUSE_ID, math::ivec2 { x, y }); } break; default: return; } @@ -716,23 +695,18 @@ namespace stormkit::wsi::win32 { ///////////////////////////////////// ///////////////////////////////////// - auto global_on_event(HWND handle, UINT message, WPARAM w_param, LPARAM l_param) noexcept - -> LRESULT { + auto global_on_event(HWND handle, UINT message, WPARAM w_param, LPARAM l_param) noexcept -> LRESULT { if (message == WM_CREATE) { auto lp_create_params = std::bit_cast(l_param)->lpCreateParams; SetWindowLongPtrA(handle, GWLP_USERDATA, std::bit_cast(lp_create_params)); } - auto window = handle ? std::bit_cast(GetWindowLongPtrA(handle, GWLP_USERDATA)) - : nullptr; + auto window = handle ? std::bit_cast(GetWindowLongPtrA(handle, GWLP_USERDATA)) : nullptr; - if (auto result = handle_global_events(message, w_param, l_param); - result != std::nullopt) - return *result; + if (auto result = handle_global_events(message, w_param, l_param); result != std::nullopt) return *result; if (window) { - if (auto result = handle_window_events(*window, message, w_param, l_param); - result != std::nullopt) + if (auto result = handle_window_events(*window, message, w_param, l_param); result != std::nullopt) return *result; handle_input_events(*window, message, w_param, l_param); diff --git a/src/wsi/win32/window.mpp b/src/wsi/win32/window.cppm similarity index 91% rename from src/wsi/win32/window.mpp rename to src/wsi/win32/window.cppm index 6c2543812..49b0d62fc 100644 --- a/src/wsi/win32/window.mpp +++ b/src/wsi/win32/window.cppm @@ -34,17 +34,17 @@ export namespace stormkit::wsi::win32 { Window(Window&&) noexcept; auto operator=(Window&&) noexcept -> Window&; - auto open(std::string title, const math::Extent2& size, WindowFlag flags) noexcept + auto open(string title, const math::uextent2& size, WindowFlag flags) noexcept -> void; auto close() noexcept -> void; auto handle_events() noexcept -> void; - auto clear(const rgbcolor& color) noexcept -> void; - auto fill_framebuffer(std::span> colors) noexcept -> void; + auto clear(const ucolor_rgb& color) noexcept -> void; + auto fill_framebuffer(array_view colors) noexcept -> void; - auto set_title(std::string title) noexcept -> void; - auto set_extent(const math::Extent2& extent) noexcept -> void; + auto set_title(string title) noexcept -> void; + auto set_extent(const math::uextent2& extent) noexcept -> void; auto set_fullscreen(bool fullscreen) noexcept -> void; auto confine_mouse(bool confined, u8 mouse_id) noexcept -> void; @@ -71,7 +71,7 @@ export namespace stormkit::wsi::win32 { [[nodiscard]] auto is_virtual_keyboard_visible() const noexcept -> bool; - auto set_mouse_position(const math::vec2i& position, u8 mouse_id) noexcept -> void; + auto set_mouse_position(const math::ivec2& position, u8 mouse_id) noexcept -> void; [[nodiscard]] auto is_mouse_inside() const noexcept -> bool; @@ -84,7 +84,7 @@ export namespace stormkit::wsi::win32 { [[nodiscard]] auto native_handle() const noexcept -> NativeHandle; - auto update_geometry(const math::Extent2& extent) noexcept -> void; + auto update_geometry(const math::uextent2& extent) noexcept -> void; auto win32_state(this auto& self) noexcept -> decltype(auto); auto state(this auto& self) noexcept -> decltype(auto); @@ -102,8 +102,8 @@ export namespace stormkit::wsi::win32 { bool mouse_inside = false; bool resizing = false; - math::Extent2 extent; - math::Extent2 last_extent; + math::uextent2 extent; + math::uextent2 last_extent; DWORD tls_index = 0; @@ -131,7 +131,7 @@ export namespace stormkit::wsi::win32 { HBitmap bitmap = HBitmap::empty(); std::atomic pixels_ptr = nullptr; - math::Extent2 extent; + math::extent2 extent; } m_gdi_frame_data; }; } // namespace stormkit::wsi::win32 @@ -165,7 +165,7 @@ namespace stormkit::wsi::win32 { ///////////////////////////////////// ///////////////////////////////////// STORMKIT_FORCE_INLINE - inline auto Window::update_geometry(const math::Extent2& extent) noexcept -> void { + inline auto Window::update_geometry(const math::uextent2& extent) noexcept -> void { m_state.extent = extent; m_win32_state.extent = extent; } diff --git a/src/wsi/window.cpp b/src/wsi/window.cpp index 534ee90c9..97815ee07 100644 --- a/src/wsi/window.cpp +++ b/src/wsi/window.cpp @@ -63,12 +63,20 @@ namespace stormkit::wsi { ///////////////////////////////////// ///////////////////////////////////// - auto Window::open(std::string title, const math::Extent2& size, WindowFlag flags) noexcept -> Window { + auto Window::open(string title, const math::uextent2& size, WindowFlag flags) noexcept -> Window { auto window = Window {}; window.m_impl->open(std::move(title), size, flags); return window; } + ///////////////////////////////////// + ///////////////////////////////////// + auto Window::allocate_and_open(string title, const math::uextent2& size, WindowFlag flags) noexcept -> Heap { + auto window = allocate_unsafe(Window {}); + window->m_impl->open(std::move(title), size, flags); + return window; + } + ///////////////////////////////////// ///////////////////////////////////// auto Window::close() noexcept -> void { @@ -77,13 +85,13 @@ namespace stormkit::wsi { ///////////////////////////////////// ///////////////////////////////////// - auto Window::clear(const rgbcolor& color) noexcept -> void { + auto Window::clear(const ucolor_rgb& color) noexcept -> void { m_impl->clear(color); } ///////////////////////////////////// ///////////////////////////////////// - auto Window::fill_framebuffer(std::span> colors) noexcept -> void { + auto Window::fill_framebuffer(array_view colors) noexcept -> void { m_impl->fill_framebuffer(colors); } @@ -113,25 +121,25 @@ namespace stormkit::wsi { ///////////////////////////////////// ///////////////////////////////////// - auto Window::set_title(std::string title) noexcept -> void { + auto Window::set_title(string title) noexcept -> void { m_impl->set_title(std::move(title)); } ///////////////////////////////////// ///////////////////////////////////// - auto Window::title() const noexcept -> const std::string& { + auto Window::title() const noexcept -> const string& { return m_impl->title(); } ///////////////////////////////////// ///////////////////////////////////// - auto Window::set_extent(const math::Extent2& extent) noexcept -> void { + auto Window::set_extent(const math::uextent2& extent) noexcept -> void { m_impl->set_extent(extent); } ///////////////////////////////////// ///////////////////////////////////// - auto Window::extent() const noexcept -> const math::Extent2& { + auto Window::extent() const noexcept -> const math::uextent2& { return m_impl->extent(); } @@ -221,7 +229,7 @@ namespace stormkit::wsi { ///////////////////////////////////// ///////////////////////////////////// - auto Window::set_mouse_position(const math::vec2i& position, u8 mouse_id) noexcept -> void { + auto Window::set_mouse_position(const math::ivec2& position, u8 mouse_id) noexcept -> void { m_impl->set_mouse_position(position, mouse_id); } diff --git a/tests/core/containers/dag.cpp b/tests/core/containers/dag.cpp new file mode 100644 index 000000000..53119cca5 --- /dev/null +++ b/tests/core/containers/dag.cpp @@ -0,0 +1,214 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +import std; + +import stormkit.core; +import stormkit.test; + +#include + +using namespace stormkit::core; +using namespace std::literals; + +namespace stdr = std::ranges; + +namespace { + auto _ = test::TestSuite { + "core.containers.dag", + { + { "topological_sort", + [] { + using Edge = std::pair; + constexpr auto + edges = into_array(Edge { 0, 5 }, + Edge { 0, 2 }, + Edge { 0, 1 }, + Edge { 3, 6 }, + Edge { 3, 5 }, + Edge { 3, 4 }, + Edge { 5, 4 }, + Edge { 6, 4 }, + Edge { 6, 0 }, + Edge { 3, 2 }, + Edge { 1, 4 }); + + auto dag = DAG {}; + for (auto i : range(7)) dag.add_vertex(i); + + for (auto&& [from, to] : edges) dag.add_edge(from, to); + + auto result = dag.topological_sort(); + if (not result) { + for (auto id : result.error()) std::println(" {} ->", id); + } + EXPECTS((result.has_value())); + + auto ordered = std::move(*result); + + auto orders = hash_map {}; + { + auto i = 0; + for (auto id : ordered) orders.emplace(id, i++); + } + + for (auto&& [from, to] : edges) EXPECTS(orders[from] < orders[to]); + } }, + { "remove_edge_and_vertex", + [] { + auto dag = DAG {}; + dag.emplace_vertex("a"); + dag.emplace_vertex("b"); + dag.emplace_vertex("c"); + dag.emplace_vertex("d"); + + dag.add_edge(0, 1); + dag.add_edge(1, 2); + dag.add_edge(2, 3); + dag.add_edge(0, 3); + + EXPECTS(dag.has_edge(0, 1)); + + dag.remove_edge(0, 1); + + EXPECTS(not dag.has_edge(0, 1)); + EXPECTS(dag.has_edge(0, 3)); + + dag.remove_vertex(2); + + EXPECTS(not dag.has_edge(1, 2)); + EXPECTS(not dag.has_edge(2, 3)); + + EXPECTS(stdr::size(dag.vertices()) == 3); + + { + auto result = dag.topological_sort(); + if (not result) { + for (auto id : result.error()) std::println(" {} ->", id); + } + EXPECTS(result.has_value()); + EXPECTS(stdr::size(*result) == 3); + } + + dag.add_edge(1, 0); + dag.add_edge(3, 1); + { + auto result = dag.topological_sort(); + EXPECTS((not result.has_value())); + } + } }, + { "find_cycle", + [] { + auto dag = DAG {}; + dag.add_vertex(0); + dag.add_vertex(1); + dag.add_vertex(4); + dag.add_vertex(5); + dag.add_vertex(6); + dag.add_vertex(9); + + dag.add_edge(5, 1); + dag.add_edge(1, 4); + dag.add_edge(4, 0); + dag.add_edge(0, 1); + dag.add_edge(2, 3); + + { + auto result = dag.find_cycle(); + EXPECTS(result.has_value()); + + auto&& cycle = std::move(*result); + EXPECTS(stdr::size(cycle) == 4); + EXPECTS(dag.get_vertex_value(cycle[0]) == 0); + EXPECTS(dag.get_vertex_value(cycle[1]) == 1); + EXPECTS(dag.get_vertex_value(cycle[2]) == 6); + EXPECTS(dag.get_vertex_value(cycle[3]) == 0); + } + + { + auto result = dag.topological_sort(); + EXPECTS(not result.has_value()); + } + } }, + { "reverse_view", + [] { + auto dag = DAG {}; + dag.emplace_vertex("a"); + dag.emplace_vertex("b"); + dag.emplace_vertex("c"); + dag.emplace_vertex("d"); + + dag.add_edge(0, 1); + dag.add_edge(1, 2); + dag.add_edge(2, 3); + dag.add_edge(0, 3); + + auto reversed = dag.reverse_view(); + + const auto& edges = dag.edges(); + const auto& redges = reversed.edges(); + + for (auto i : range(4u)) { + const auto [from, to] = edges[i]; + const auto [rfrom, rto] = redges[i]; + EXPECTS(from == rto and rfrom == to); + } + } }, + { "reverse_clone", + [] { + auto dag = DAG {}; + dag.emplace_vertex("a"); + dag.emplace_vertex("b"); + dag.emplace_vertex("c"); + dag.emplace_vertex("d"); + + dag.add_edge(0, 1); + dag.add_edge(1, 2); + dag.add_edge(2, 3); + dag.add_edge(0, 3); + + auto reversed = dag.reverse_clone(); + + const auto& edges = dag.edges(); + const auto& redges = reversed.edges(); + + for (auto i : range(4u)) { + const auto [from, to] = edges[i]; + const auto [rfrom, rto] = redges[i]; + EXPECTS(from == rto and rfrom == to); + } + } }, + { "dump", + [] { + auto dag = DAG {}; + dag.emplace_vertex("a"); + dag.emplace_vertex("b"); + dag.emplace_vertex("c"); + dag.emplace_vertex("d"); + + dag.add_edge(0, 1); + dag.add_edge(1, 2); + dag.add_edge(2, 3); + dag.add_edge(0, 3); + + const auto required_result = "digraph G {\n" + " rankdir = LR\n" + " bgcolor = black\n" + " node [shape=box, fontname=\"helvetica\", fontsize=12];\n\n" + " \"node0\" [label=\"id: 0 value: a\", style=filled,color=\"white\"];\n" + " \"node1\" [label=\"id: 1 value: b\", style=filled,color=\"white\"];\n" + " \"node2\" [label=\"id: 2 value: c\", style=filled,color=\"white\"];\n" + " \"node3\" [label=\"id: 3 value: d\", style=filled,color=\"white\"];\n" + " \"node0\" -> \"node1\" [color=seagreen];\n" + " \"node1\" -> \"node2\" [color=seagreen];\n" + " \"node2\" -> \"node3\" [color=seagreen];\n" + " \"node0\" -> \"node3\" [color=seagreen];\n" + "}"sv; + + const auto out = dag.dump(); + EXPECTS(out == required_result); + } }, + } + }; +} // namespace diff --git a/tests/core/containers/tree.cpp b/tests/core/containers/tree.cpp index 8dfd67eaa..573ba77dc 100644 --- a/tests/core/containers/tree.cpp +++ b/tests/core/containers/tree.cpp @@ -13,13 +13,12 @@ using namespace stormkit::core; using namespace std::literals; namespace { - auto _ = test::TestSuite { "Core.Containers", - { { "Tree.Node.name", [] { - static constexpr auto name = "TestNodeName"sv; + auto _ = test::TestSuite { "Core.Containers", { { "Tree.Node.name", [] { + static constexpr auto name = "TestNodeName"sv; - auto node = TreeNode {}; - EXPECTS(node.name() == ""s); - node.set_name(std::string { name }); - EXPECTS(node.name() == name); - } } } }; + auto node = TreeNode {}; + EXPECTS(node.name() == ""s); + node.set_name(string { name }); + EXPECTS(node.name() == name); + } } } }; } // namespace diff --git a/tests/core/math/linear-matrix.cpp b/tests/core/math/linear-matrix.cpp index d8231a6dd..685d4ecc1 100644 --- a/tests/core/math/linear-matrix.cpp +++ b/tests/core/math/linear-matrix.cpp @@ -16,19 +16,47 @@ namespace { auto _ = test::TestSuite { "core.math.linear.matrix", { + { "linear.matrix.as_view", + [] static { + auto a = math::imat4 { 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 4, 0, 0, 0 }; + EXPECTS(a[0] == 0); + EXPECTS(a[1] == 1); + EXPECTS((a[1, 2] == 2)); + + const auto span = math::as_view(a); + auto span2 = math::as_view_mut(a); + + EXPECTS(span[0] == 0); + EXPECTS(span[1] == 1); + + span2[0] = 1; + + EXPECTS(span[0] == 1); + } }, + { "linear.matrix.operator[]", + [] static { + auto a = math::imat4 { 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 4, 0, 0, 0 }; + EXPECTS(a[0] == 0); + EXPECTS(a[1] == 1); + EXPECTS(a[0] == 0); + + EXPECTS((a[1, 2] == 2)); + + a[0] = 5; + } }, { "linear.matrix.determinant", [] static { - const auto det_1 = determinant(math::mat2i { 2, 1, 4, 5 }); + const auto det_1 = determinant(math::imat2 { 2, 1, 4, 5 }); EXPECTS(det_1 == 6); - const auto det_2 = determinant(math::mat3i { 2, 1, 1, 1, 0, 1, 0, 3, 1 }); + const auto det_2 = determinant(math::imat3 { 2, 1, 1, 1, 0, 1, 0, 3, 1 }); EXPECTS(det_2 == -4); }, }, { "linear.matrix.transpose", [] static { - const auto a = math::mat4i { 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 4, 0, 0, 0 }; + const auto a = math::imat4 { 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 4, 0, 0, 0 }; const auto result = transpose(a); EXPECTS((result[0, 1] == 0)); @@ -43,13 +71,13 @@ namespace { }, { "linear.matrix.is_inversible", [] static { - EXPECTS(math::is_inversible(math::mat2i { -3, 1, 5, 0 })); + EXPECTS(math::is_inversible(math::imat2 { -3, 1, 5, 0 })); EXPECTS(not math::is_inversible(math::mat { 2, 3, 4, 2, 1, 8 })); }, }, { "linear.matrix.inverse", [] static { - const auto a = math::mat3f { 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 8.f }; + const auto a = math::fmat3 { 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 8.f }; const auto result = math::inverse(a); EXPECTS(is_equal(result[0, 0], -8.f / 3.f)); @@ -65,13 +93,13 @@ namespace { }, { "linear.matrix.is_orthogonal", [] static { - EXPECTS(math::is_orthogonal(math::mat3i { 0, 1, 0, 0, 0, 1, 1, 0, 0 })); + EXPECTS(math::is_orthogonal(math::imat3 { 0, 1, 0, 0, 0, 1, 1, 0, 0 })); EXPECTS(not math::is_orthogonal(math::mat {})); }, }, { "linear.matrix.mul.scalar", [] static { - const auto a = math::mat4i { 22, 0, 0, 0, 0, 4, 0, 0, 0, 0, 8, 0, 0, 0, 0, 10 }; + const auto a = math::imat4 { 22, 0, 0, 0, 0, 4, 0, 0, 0, 0, 8, 0, 0, 0, 0, 10 }; const auto b = 2; const auto result = math::mul(a, b); @@ -83,7 +111,7 @@ namespace { }, { "linear.matrix.div.scalar", [] static { - const auto a = math::mat4i { 22, 0, 0, 0, 0, 4, 0, 0, 0, 0, 8, 0, 0, 0, 0, 10 }; + const auto a = math::imat4 { 22, 0, 0, 0, 0, 4, 0, 0, 0, 0, 8, 0, 0, 0, 0, 10 }; const auto b = 2; const auto result = math::div(a, b); @@ -95,8 +123,8 @@ namespace { }, { "linear.matrix.mul.matrix", [] static { - const auto a = math::mat4i { 22, 0, 0, 0, 0, 4, 0, 0, 0, 0, 8, 0, 0, 0, 0, 10 }; - const auto b = math::mat4i { 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 10, 0, 0, 0, 0, 26 }; + const auto a = math::imat4 { 22, 0, 0, 0, 0, 4, 0, 0, 0, 0, 8, 0, 0, 0, 0, 10 }; + const auto b = math::imat4 { 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 10, 0, 0, 0, 0, 26 }; const auto result = math::mul(a, b); EXPECTS((result[0, 0] == 44)); @@ -107,8 +135,8 @@ namespace { }, { "linear.matrix.div.matrix", [] static { - const auto a = math::mat2f { 0, 1, 2, 3 }; - const auto b = math::mat2f { 1, 2, 3, 4 }; + const auto a = math::fmat2 { 0, 1, 2, 3 }; + const auto b = math::fmat2 { 1, 2, 3, 4 }; const auto result = math::div(a, b); EXPECTS(is_equal(result[0], 3.f / 2.f)); @@ -119,23 +147,23 @@ namespace { }, { "linear.matrix.translate", [] static { - constexpr auto a = math::mat4f::identity(); - const auto b = math::vec3f { 3, 2, 3 }; + constexpr auto a = math::fmat4::identity(); + const auto b = math::fvec3 { 3, 2, 3 }; const auto result = math::translate(a, b); EXPECTS((result[0, 0] == 1)); EXPECTS((result[1, 1] == 1)); EXPECTS((result[2, 2] == 1)); - EXPECTS((result[3, 0] == 3)); - EXPECTS((result[3, 1] == 2)); - EXPECTS((result[3, 2] == 3)); + EXPECTS((result[0, 3] == 3)); + EXPECTS((result[1, 3] == 2)); + EXPECTS((result[2, 3] == 3)); EXPECTS((result[3, 3] == 1)); }, }, { "linear.matrix.scale", [] static { - const auto a = math::mat4i::identity(); - const auto b = math::vec3i { 3, 2, 3 }; + const auto a = math::imat4::identity(); + const auto b = math::ivec3 { 3, 2, 3 }; const auto result = math::scale(a, b); EXPECTS((result[0, 0] == 3)); @@ -143,6 +171,21 @@ namespace { EXPECTS((result[2, 2] == 3)); EXPECTS((result[3, 3] == 1)); }, - }, }, + }, { "linear.matrix.to_string", + [] static { + auto a = math::imat4x3 { + { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 } + }; + + const auto as_string = math::to_string(a); + EXPECTS((as_string == + // clang-format off +R"([mat 1, 2, 3 + 4, 5, 6 + 7, 8, 9 + 10, 11, 12])")); + // clang-format on + } }, + }, }; } // namespace diff --git a/tests/core/math/linear-vector.cpp b/tests/core/math/linear-vector.cpp index d9ff47151..422098840 100644 --- a/tests/core/math/linear-vector.cpp +++ b/tests/core/math/linear-vector.cpp @@ -16,11 +16,35 @@ namespace { auto _ = test::TestSuite { "core.math.linear.vector", { + { "linear.vector.as_view", + [] static { + auto a = math::ivec2 { 2, 3 }; + const auto span = math::as_view(a); + auto span2 = math::as_view_mut(a); + + EXPECTS(span[0] == 2); + EXPECTS(span[1] == 3); + + span2[0] = 1; + + EXPECTS(span[0] == 1); + } }, + { "linear.vector.operator[]", + [] static { + auto a = math::ivec2 { 2, 3 }; + EXPECTS(a[0] == 2); + const auto c = math::ivec3 { 1, 3, 3 }; + EXPECTS(c[1] == 3); + const auto b = math::ivec4 { 5, 3, 9, 2 }; + EXPECTS(b[2] == 9); + + a[0] = 5; + } }, { "linear.vector.add", [] static { - const auto a = math::vec2i { 2, 3 }; - const auto b = math::vec2i { 3, 2 }; + const auto a = math::ivec2 { 2, 3 }; + const auto b = math::ivec2 { 3, 2 }; const auto result = add(a, b); EXPECTS(result.x == 5); @@ -29,8 +53,8 @@ namespace { }, { "linear.vector.sub", [] static { - const auto a = math::vec2i { 2, 3 }; - const auto b = math::vec2i { 3, 2 }; + const auto a = math::ivec2 { 2, 3 }; + const auto b = math::ivec2 { 3, 2 }; const auto result = sub(a, b); EXPECTS(result.x == -1); @@ -39,7 +63,7 @@ namespace { }, { "linear.vector.mul", [] static { - const auto a = math::vec2i { 10, 6 }; + const auto a = math::ivec2 { 10, 6 }; const auto result = mul(a, 2); EXPECTS(result.x == 20); @@ -48,7 +72,7 @@ namespace { }, { "linear.vector.div", [] static { - const auto a = math::vec2i { 10, 6 }; + const auto a = math::ivec2 { 10, 6 }; const auto result = div(a, 2); EXPECTS(result.x == 5); @@ -57,16 +81,16 @@ namespace { }, { "linear.vector.dot", [] static { - const auto a = math::vec2i { 2, 3 }; - const auto b = math::vec2i { 3, 2 }; + const auto a = math::ivec2 { 2, 3 }; + const auto b = math::ivec2 { 3, 2 }; EXPECTS(math::dot(a, b) == 12); }, }, { "linear.vector.cross", [] static { - const auto a = math::vec3i { 2, 3, 2 }; - const auto b = math::vec3i { 3, 2, 3 }; + const auto a = math::ivec3 { 2, 3, 2 }; + const auto b = math::ivec3 { 3, 2, 3 }; const auto result = math::cross(a, b); EXPECTS(result.x == 5 and result.y == 0 and result.z == -5); @@ -74,7 +98,7 @@ namespace { }, { "linear.vector.normalize", [] static { - const auto a = math::vec2f { + const auto a = math::fvec2 { 1, 2, }; diff --git a/tests/core/parallelism/locked.cpp b/tests/core/parallelism/locked.cpp index 8f1926011..008892c88 100644 --- a/tests/core/parallelism/locked.cpp +++ b/tests/core/parallelism/locked.cpp @@ -34,6 +34,30 @@ namespace { EXPECTS(locked_int.unsafe() == (ITERATIONS * 2)); } }, + { "Locked.write_closure", + [] static noexcept { + static constexpr auto ITERATIONS = 1'000'000; + auto locked_int = Locked { 0 }; + const auto func = [&locked_int] noexcept { + for (auto foo = 0; foo != ITERATIONS; ++foo) { + locked_int.write([](auto& value) static noexcept { value += 1; }); + } + }; + + auto future_1 = std::async(std::launch::async, func); + auto future_2 = std::async(std::launch::async, func); + + future_1.wait(); + future_2.wait(); + + EXPECTS(locked_int.unsafe() == (ITERATIONS * 2)); + } }, + { "Locked.move", + [] static noexcept { + auto locked_int = Locked { 0 }; + + auto locked_int2 = std::move(locked_int); + } }, } }; } // namespace diff --git a/tests/core/parallelism/threadpool.cpp b/tests/core/parallelism/threadpool.cpp new file mode 100644 index 000000000..6f958effc --- /dev/null +++ b/tests/core/parallelism/threadpool.cpp @@ -0,0 +1,116 @@ +// Copyright (C) 2024 Arthur LAURENT +// This file is subject to the license terms in the LICENSE file +// found in the top-level of this distribution + +import std; + +import stormkit.core; +import stormkit.test; + +#include + +using namespace stormkit::core; + +using namespace std::literals; + +namespace stdr = std::ranges; +namespace stdv = std::views; + +namespace { + auto _ = test::TestSuite { + "Core.parallelism", + { + { "ThreadPool.post_task_future_void", + [] static noexcept { + auto thread_pool = ThreadPool {}; + + auto future = thread_pool.post_task([] static noexcept { std::println("Hello from a thread!"); }); + + EXPECTS(future.valid()); + future.wait(); + } }, + { "ThreadPool.post_task_future_int", + [] static noexcept { + auto thread_pool = ThreadPool {}; + + auto future = thread_pool.post_task([] static noexcept { + std::println("Hello from a thread!"); + return 8; + }); + + EXPECTS(future.valid()); + future.wait(); + EXPECTS(future.get() == 8); + } }, + { "ThreadPool.post_task_no_future", + [] static noexcept { + auto thread_pool = ThreadPool {}; + + auto val = std::atomic_int { 5 }; + + thread_pool.post_task( + [&val] noexcept { + std::println("Hello from a thread!"); + val = 8; + }, + ThreadPool::NO_FUTURE); + + std::this_thread::sleep_for(1s); + + EXPECTS(val == 8); + } }, + { "ThreadPool.post_task_from_other_task", + [] static noexcept { + auto thread_pool = ThreadPool {}; + + auto val = std::atomic_int { 5 }; + + thread_pool.post_task( + [&val, &thread_pool] noexcept { + thread_pool.post_task( + [&val] noexcept { + std::println("Hello from a thread!"); + val = 8; + }, + ThreadPool::NO_FUTURE); + }, + ThreadPool::NO_FUTURE); + + std::this_thread::sleep_for(1s); + + EXPECTS(val == 8); + } }, + { "ThreadPool.post_task_from_other_thread", + [] static noexcept { + auto thread_pool = ThreadPool {}; + + auto val = std::atomic_int { 5 }; + + auto thread = std::jthread { [&val, &thread_pool] noexcept { + thread_pool.post_task( + [&val] noexcept { + std::println("Hello from a thread!"); + val = 8; + }, + ThreadPool::NO_FUTURE); + } }; + + std::this_thread::sleep_for(1s); + + if (thread.joinable()) thread.join(); + + EXPECTS(val == 8); + } }, + { "ThreadPool.parallel_for", + [] static noexcept { + auto thread_pool = ThreadPool {}; + + auto values = dyn_array { std::from_range, range(0, 1000000) }; + parallel_for(thread_pool, values, [](auto& value) { value += value; }); + + auto k = 0; + for (auto v : values) EXPECTS(v == (k++ * 2)); + } }, + } + }; +} // namespace diff --git a/tests/core/typesafe/ref.cpp b/tests/core/typesafe/ref.cpp index f21148e7f..d163b4667 100644 --- a/tests/core/typesafe/ref.cpp +++ b/tests/core/typesafe/ref.cpp @@ -15,7 +15,7 @@ namespace { auto _ = test::TestSuite { "Core.typesafe", { - { "Ref.to_refs.std_vector.all_ref", + { "ref.to_refs.std_vector.all_ref", [] static noexcept { auto a = 0; auto b = 1; @@ -24,12 +24,12 @@ namespace { auto e = 4; auto f = 5; - auto refs = to_refs(a, b, c, d, e, f); + auto refs = to_refs(a, b, c, d, e, f); auto i = 0; for (auto&& ref : refs) EXPECTS(*ref == i++); } }, - { "Ref.as_refs.std_array.all_ref", + { "ref.as_refs.std_array.all_ref", [] static noexcept { auto a = 0; auto b = 1; @@ -38,12 +38,12 @@ namespace { auto e = 4; auto f = 5; - auto refs = as_refs(a, b, c, d, e, f); + auto refs = as_refs(a, b, c, d, e, f); auto i = 0; for (auto&& ref : refs) EXPECTS(*ref == i++); } }, - { "Ref.as_refs.default.all_ref", + { "ref.as_refs.default.all_ref", [] static noexcept { auto a = 0; auto b = 1; @@ -57,7 +57,7 @@ namespace { auto i = 0; for (auto&& ref : refs) EXPECTS(*ref == i++); } }, - { "Ref.to_refs.std_vector.all_ptr", + { "ref.to_refs.std_vector.all_ptr", [] static noexcept { auto a = std::make_unique(0); auto b = std::make_unique(1); @@ -66,7 +66,7 @@ namespace { auto e = new int { 4 }; auto f = 5; - auto refs = to_refs(a, b, c, d, e, &f); + auto refs = to_refs(a, b, c, d, e, &f); auto i = 0; for (auto&& ref : refs) EXPECTS(*ref == i++); @@ -74,7 +74,7 @@ namespace { delete d; delete e; } }, - { "Ref.as_refs.std_array.all_ptr", + { "ref.as_refs.std_array.all_ptr", [] static noexcept { auto a = std::make_unique(0); auto b = std::make_unique(1); @@ -83,7 +83,7 @@ namespace { auto e = new int { 4 }; auto f = 5; - auto refs = as_refs(a, b, c, d, e, &f); + auto refs = as_refs(a, b, c, d, e, &f); auto i = 0; for (auto&& ref : refs) EXPECTS(*ref == i++); @@ -91,7 +91,7 @@ namespace { delete d; delete e; } }, - { "Ref.as_refs.default.all_ptr", + { "ref.as_refs.default.all_ptr", [] static noexcept { auto a = std::make_unique(0); auto b = std::make_unique(1); @@ -108,17 +108,17 @@ namespace { delete d; delete e; } }, - { "Ref.to_refs.std_set", + { "ref.to_refs.std_set", [] static noexcept { - auto vec = std::vector { 1, 3, 5, 6, 9 }; + auto vec = dyn_array { 1, 3, 5, 6, 9 }; auto refs = to_refs(vec); auto i = 0u; for (auto&& ref : refs) EXPECTS(*ref == vec[i++]); } }, - { "Ref.to_refs.default", + { "ref.to_refs.default", [] static noexcept { - constexpr auto vec = std::array { 1, 3, 5, 6, 9 }; + constexpr auto vec = array { 1, 3, 5, 6, 9 }; auto refs = to_refs(vec); auto i = 0u; diff --git a/tools/terra/src/main.cpp b/tools/terra/src/main.cpp index f400b0665..627c665d6 100644 --- a/tools/terra/src/main.cpp +++ b/tools/terra/src/main.cpp @@ -4,6 +4,8 @@ import stormkit.core; #include +#include + namespace stdr = std::ranges; namespace stdfs = std::filesystem; @@ -11,19 +13,17 @@ using namespace std::literals; using namespace stormkit; -auto main(const std::span args) noexcept -> int { +auto main(const array_view args) noexcept -> int { if (stdr::size(args) < 2) { std::println(get_stderr(), "No template filename provided"); return -1; } const auto template_path = stdfs::path { args[1] }; if (not stdfs::exists(template_path)) { - std::println(get_stderr(), "Template file {} doesn't exists", template_path.c_str()); + std::println(get_stderr(), "Template file {} doesn't exists", template_path.string()); return -1; } else if (not stdfs::is_regular_file(template_path)) { - std::println(get_stderr(), - "Template file {} path is not a regular file", - template_path.c_str()); + std::println(get_stderr(), "Template file {} path is not a regular file", template_path.string()); return -1; } @@ -32,24 +32,20 @@ auto main(const std::span args) noexcept -> int { return stdfs::path { args[2] }; }(); - const auto - template_data = io::readfile(io::text_file_tag, template_path) - .transform_error(monadic:: - assert(std::format("Failed to read file {}, reason: ", - template_path.c_str()))) - .value(); + const auto template_data = TryAssert(io::read_text(template_path), + std::format("Failed to read file {}, reason: ", template_path.string())); - auto out = std::string {}; + auto out = string {}; out.reserve(stdr::size(template_data)); // TODO replace with std::hive when supported - auto buff = std::vector {}; + auto buff = dyn_array {}; buff.reserve(50); out += std::format(R"( outfile = io.open("{}", "w") )", - out_path.c_str()); + replace(out_path.string(), "\\", "/")); bool last_char_was_bracket = false; bool is_parsing_lua = false; @@ -75,8 +71,7 @@ outfile = io.open("{}", "w") buff.clear(); last_char_was_bracket = false; } else { - if (c == '{' and i + 1 < stdr::size(template_data) and template_data[i + 1] == '%') - last_char_was_bracket = true; + if (c == '{' and i + 1 < stdr::size(template_data) and template_data[i + 1] == '%') last_char_was_bracket = true; else buff.emplace_back(c); } @@ -92,7 +87,7 @@ outfile = io.open("{}", "w") out += "\\x" + str_char; } - out += "\")"; + out += "\")\n"; out += "outfile:close()"; std::println("{}", out); diff --git a/tools/terra/xmake.lua b/tools/terra/xmake.lua index 9cbef4d3b..fb5a071e1 100644 --- a/tools/terra/xmake.lua +++ b/tools/terra/xmake.lua @@ -1,19 +1,5 @@ target("terra", function() - set_kind("binary") - set_languages("cxxlatest", "clatest") - - add_rules("stormkit.flags") - add_rules("platform.windows.subsystem.console") - - add_deps("core", "main", "log") - - if is_mode("debug") then - add_defines("STORMKIT_BUILD_DEBUG") - add_defines("STORMKIT_ASSERT=1") - set_suffixname("-d") - else - add_defines("STORMKIT_ASSERT=0") - end + add_rules("stormkit::example") add_files("src/main.cpp") diff --git a/xmake.lua b/xmake.lua index 904013519..804f82d8a 100644 --- a/xmake.lua +++ b/xmake.lua @@ -6,6 +6,7 @@ local allowed_modes = { "profile", } +add_repositories("nazara-repo https://github.com/NazaraEngine/xmake-repo") add_repositories("tapzcrew-repo https://github.com/Tapzcrew/xmake-repo main") set_xmakever("3.0.0") @@ -13,24 +14,17 @@ set_project("StormKit") set_version("0.1.0", { build = "%Y%m%d%H%M" }) -includes("xmake/rules/*.lua") - ---------------------------- options ---------------------------- includes("xmake/options.xmake.lua") -if get_config("devmode") then - set_policy("build.c++.modules.non_cascading_changes", true) - set_policy("build.c++.modules.hide_dependencies", true) -end +if get_config("devmode") then set_policy("build.c++.modules.hide_dependencies", true) end ---------------------------- global rules ---------------------------- +includes("xmake/rules/*.xmake.lua") + if get_config("vsxmake") then add_rules("plugin.vsxmake.autoupdate") end if get_config("compile_commands") then - if test then - if test2 then - end - end add_rules("plugin.compile_commands.autoupdate", { outputdir = "build", lsp = "clangd" }) end @@ -40,208 +34,71 @@ end if not is_host("windows") then add_rules("mode.valgrind") end +---------------------------- global configs ---------------------------- +set_allowedmodes(allowed_modes) +set_allowedplats("windows", "mingw", "linux", "macosx", "wasm") +set_allowedarchs("windows|x64", "windows|arm64", "linux|x86_64", "linux|aarch64", "macosx|x86_64", "macosx|arm64") + set_fpmodels("fast") add_vectorexts("fma") add_vectorexts("neon") add_vectorexts("avx", "avx2") add_vectorexts("sse", "sse2", "sse3", "ssse3", "sse4.2") ----------------------------- global configs ---------------------------- -set_allowedmodes(allowed_modes) -set_allowedplats("windows", "mingw", "linux", "macosx", "wasm") -set_allowedarchs("windows|x64", "windows|arm64", "linux|x86_64", "linux|aarch64", "macosx|x86_64", "macosx|arm64") +local suffix +if is_kind("static") then suffix = "-static" end -add_defines("ANKERL_UNORDERED_DENSE_STD_MODULE=1", "FROZEN_STD_MODULE=1") +if is_mode("debug") then + suffix = (suffix or "") .. "-debug" +elseif is_mode("reldbg") then + suffix = (suffix or "") .. "-reldebug" +end -includes("xmake/dependencies.xmake.lua") -includes("xmake/targets.xmake.lua") +if suffix then set_suffixname(suffix) end ----------------------------- dependencies ---------------------------- -for name, module in pairs(modules) do - if name == "core" or name == "main" or name == "test" or get_config(name) then - for _, package in ipairs(module.public_packages) do - add_requires_with_conf_transitive(package) - end - for _, package in ipairs(module.packages) do - add_requires_with_conf(package) - end - end +---------------------------- configvar ---------------------------- +for _, name in ipairs({ "log", "entities", "image", "wsi", "gpu", "lua" }) do + if get_config(name) then set_configvar("STORMKIT_LIB_" .. string.upper(name) .. "_ENABLED", true) end end ---------------------------- targets ---------------------------- namespace("stormkit", function() - for _, name in ipairs({ "log", "entities", "image", "wsi", "gpu" }) do - if get_config(name) then set_configvar("STORMKIT_LIB_" .. string.upper(name) .. "_ENABLED", "true") end - end + module_dir = "$(projectdir)/modules/stormkit" + src_dir = "$(projectdir)/src" + include_dir = "$(projectdir)/include" - for name, module in pairs(modules) do - local modulename = module.modulename - - if name == "core" or name == "main" or name == "test" or get_config(name) then - target(name, function() - set_group("libraries") - - if module.custom then module.custom() end - - if name == "main" or name == "test" then - set_kind("static") - else - set_kind("$(kind)") - end - - set_languages("cxxlatest", "clatest") - - add_rules("stormkit.flags") - add_defines("STORMKIT_BUILD") - if is_mode("debug") then - add_defines("STORMKIT_BUILD_DEBUG") - set_suffixname("-d") - end - - if is_kind("static") then add_defines("STORMKIT_STATIC", { public = true }) end - - local src_path = path.join("src", modulename) - local module_path = path.join("modules", "stormkit", modulename) - local include_path = path.join("include", "(stormkit", modulename) - - for _, file in ipairs(os.files(path.join(src_path, "**.mpp"))) do - add_files(file) - end - for _, file in ipairs(os.files(path.join(src_path, "**.cpp"))) do - add_files(file) - end - for _, file in ipairs(os.files(path.join(src_path, "**.mm"))) do - add_files(file, { mxxflags = "-std=c++23" }) - end - for _, file in ipairs(os.files(path.join(src_path, "**.m"))) do - add_files(file) - end - for _, file in ipairs(os.files(path.join(src_path, "**.inl"))) do - add_files(file) - end - - if os.exists(module_path .. ".mpp") then add_files(module_path .. ".mpp", { public = true }) end - - if os.files(module_path) then - for _, file in ipairs(os.files(path.join(module_path, "**.mpp"))) do - add_files(file, { public = true }) - end - for _, file in ipairs(os.files(path.join(module_path, "**.inl"))) do - add_headerfiles(file) - end - end - - local _include_path = include_path:gsub("%(", "") - if os.exists(_include_path) then - add_headerfiles(path.join(include_path, "**.inl)")) - add_headerfiles(path.join(include_path, "**.hpp)")) - end - - if is_plat("windows") or is_plat("mingw") then - for _, plat in ipairs({ "posix", "linux", "darwin", "macos", "ios", "bsd", "android" }) do - remove_files(path.join(src_path, plat, "**")) - remove_headerfiles(path.join(src_path, plat, "**")) - end - elseif is_plat("macosx") then - for _, plat in ipairs({ "linux", "win32", "ios", "bsd", "android" }) do - remove_files(path.join(src_path, plat, "**")) - remove_headerfiles(path.join(src_path, plat, "**")) - end - elseif is_plat("ios") then - for _, plat in ipairs({ "linux", "macos", "win32", "bsd", "android" }) do - remove_files(path.join(src_path, plat, "**")) - remove_headerfiles(path.join(src_path, plat, "**")) - end - elseif is_plat("android") then - for _, plat in ipairs({ "linux", "darwin", "macos", "ios", "bsd", "win32" }) do - remove_files(path.join(src_path, plat, "**")) - remove_headerfiles(path.join(src_path, plat, "**")) - end - elseif is_plat("linux") then - for _, plat in ipairs({ "win32", "darwin", "macos", "ios", "bsd", "android" }) do - remove_files(path.join(src_path, plat, "**")) - remove_headerfiles(path.join(src_path, plat, "**")) - end - end - - add_includedirs("$(projectdir)/include", { public = true }) - - if module.defines then add_defines(module.defines) end - - if module.public_defines then add_defines(module.public_defines, { public = true }) end - - if module.cxxflags then - add_cxxflags(module.cxxflags) - add_mxxflags(module.cxxflags) - end - - if module.deps then add_deps(module.deps) end - - if module.public_deps then add_deps(module.public_deps, { public = true }) end - - if module.packages then - local packages = {} - for _, package in ipairs(module.packages) do - table.insert(packages, package:split(" ")[1]) - end - - add_packages(packages, { public = is_kind("static") }) - end - - if module.public_packages then - local packages = {} - for _, package in ipairs(module.public_packages) do - table.insert(packages, package:split(" ")[1]) - end - add_packages(packages, { public = true }) - end - - if module.frameworks then add_frameworks(module.frameworks, { public = is_kind("static") }) end - - add_options("sanitizers") - end) - end + includes("xmake/targets/core.xmake.lua") + includes("xmake/targets/main.xmake.lua") + includes("xmake/targets/test.xmake.lua") + + for _, name in ipairs({ "log", "entities", "gpu", "image", "wsi", "lua" }) do + if get_config(name) then includes("xmake/targets/" .. name .. ".xmake.lua") end end + includes("xmake/targets/examples.xmake.lua") + + if get_config("tests") then includes("xmake/targets/tests.xmake.lua") end + if get_config("tools") then includes("xmake/targets/tools.xmake.lua") end + target("stormkit", function() - set_group("libraries") - set_kind("moduleonly") + set_kind("static") set_languages("cxxlatest", "clatest") - add_rules("stormkit.flags") - add_files("modules/stormkit.mpp") + set_suffixname("") - add_deps("core", "main") - for _, name in ipairs({ "log", "entities", "image", "wsi", "gpu" }) do + add_rules("stormkit::flags") + + add_files("modules/stormkit.cppm", { public = true }) + + add_deps("stormkit::core") + for _, name in ipairs({ "log", "entities", "gpu", "image", "wsi", "lua" }) do if get_config(name) then - add_deps(name) - set_configvar("STORMKIT_LIB_" .. string.upper(name) .. "_ENABLED", "true") + add_deps("stormkit::" .. name) + add_defines("STORMKIT_IMPORT_" .. string.upper(name), { public = true }) end end - add_headerfiles("$(builddir)/.gens/include/(stormkit/*.hpp)") + set_group("libraries") end) - add_includedirs("$(builddir)/.gens/include") - - -- if not is_host("windows") then add_requireconfs("**.pkg-config", { override = true, system = true }) end - -- add_requireconfs("**.bison", { override = true, system = true }) - -- add_requireconfs("**.m4", { override = true, system = true }) - -- add_requireconfs("**.python", { override = true, system = true }) - -- add_requireconfs("**.meson", { override = true, system = true }) - -- add_requireconfs("**.autoconf", { override = true, system = true }) - -- add_requireconfs("**.cmake", { override = true, system = true }) - -- add_requireconfs("**.nasm", { override = true, system = true }) - - for name, _ in pairs(modules) do - if get_config("examples_" .. name) then - local example_dir = path.join("examples", name) - if os.exists(example_dir) and has_config("" .. name) then - includes(path.join(example_dir, "**", "xmake.lua")) - end - end - end - - if get_config("tests") then includes("xmake/tests.xmake.lua") end - if get_config("tools") then includes("tools/**.lua") end end) diff --git a/xmake/dependencies.xmake.lua b/xmake/dependencies.xmake.lua deleted file mode 100644 index 3d21f5338..000000000 --- a/xmake/dependencies.xmake.lua +++ /dev/null @@ -1,119 +0,0 @@ -local global_package_configs = { - configs = { - shared = get_config("shared_deps"), - ["x11"] = is_plat("linux"), - wayland = is_plat("linux"), - modules = true, - std_import = true, - cpp = "latest", - }, -} - -if get_config("on_ci") then global_package_configs.system = false end - -add_requireconfs("nzsl.fmt", { version = "master", override = true, system = false }) -if not is_plat("windows") then add_requires("libdwarf") end - -local package_configs = { - ["libjpeg-turbo"] = { - windows = { - system = false, - configs = { - runtimes = "MD", - shared = true, - }, - }, - }, - libktx = { - llvm = { - configs = { - cxflags = "-Wno-overriding-option", - }, - }, - }, - frozen = { - global = { - system = false, - }, - }, - ["vulkan-header"] = { - global = { - version = "v1.4.309", - system = false, - }, - }, - ["vulkan-memory-allocator"] = { - global = { - version = "v3.3.0", - system = false, - }, - }, - nzsl = { - linux = { - configs = { - toolchains = "gcc", - runtimes = "stdc++_shared", - }, - }, - windows = { - configs = { - toolchains = "msvc", - runtimes = "MD", - }, - }, - global = { - override = true, - configs = { - fs_watcher = false, - link = {}, - }, - }, - }, -} - -function add_requires_with_conf(package) - local configs = package_configs[package] or {} - add_requires( - package, - table.join( - global_package_configs, - configs.global or {}, - is_plat("windows") and configs.windows or {}, - is_plat("linux") and configs.linux or {}, - is_plat("macosx") and configs.macos or {}, - get_config("toolchain") == "llvm" and configs.llvm or {}, - get_config("toolchain") == "msvc" and configs.msvc or {}, - get_config("toolchain") == "gcc" and configs.gcc or {} - ) - ) -end - -function add_requires_with_conf_transitive(package) - local configs = package_configs[package] or {} - add_requires( - package, - table.join( - global_package_configs, - configs.global or {}, - is_plat("windows") and configs.windows or {}, - is_plat("linux") and configs.linux or {}, - is_plat("macosx") and configs.macos or {}, - get_config("toolchain") == "llvm" and configs.llvm or {}, - get_config("toolchain") == "msvc" and configs.msvc or {}, - get_config("toolchain") == "gcc" and configs.gcc or {} - ) - ) - add_requireconfs( - package .. ".**", - table.join( - global_package_configs, - configs.global or {}, - is_plat("windows") and configs.windows or {}, - is_plat("linux") and configs.linux or {}, - is_plat("macosx") and configs.macos or {}, - get_config("toolchain") == "llvm" and configs.llvm or {}, - get_config("toolchain") == "msvc" and configs.msvc or {}, - get_config("toolchain") == "gcc" and configs.gcc or {} - ) - ) -end diff --git a/xmake/ktx.xmake.lua b/xmake/ktx.xmake.lua deleted file mode 100644 index 59bd44d8a..000000000 --- a/xmake/ktx.xmake.lua +++ /dev/null @@ -1,46 +0,0 @@ -package("libktx", function() - set_kind("library") - set_homepage("https://github.com/KhronosGroup/KTX-Software") - set_description("KTX (Khronos Texture) Library and Tools") - set_license("Apache-2.0") - - set_urls( - "https://github.com/KhronosGroup/KTX-Software/archive/refs/tags/$(version).tar.gz", - "https://github.com/KhronosGroup/KTX-Software.git" - ) - add_versions("v4.3.2", "74a114f465442832152e955a2094274b446c7b2427c77b1964c85c173a52ea1f") - add_versions("v4.4.0", "3585d76edcdcbe3a671479686f8c81c1c10339f419e4b02a9a6f19cc6e4e0612") - - add_deps("cmake") - - add_configs("vulkan", { description = "Enable Vulkan texture upload.", default = true, type = "boolean" }) - add_configs("opengl", { description = "Enable OpenGL texture upload.", default = true, type = "boolean" }) - - on_install("macosx", "android", "linux", "windows", "mingw", "cross", function(package) - local configs = { - "-DCMAKE_BUILD_TYPE=" .. (package:is_debug() and "Debug" or "Release"), - "-DBUILD_SHARED_LIBS=" .. (package:config("shared") and "ON" or "OFF"), - "-DKTX_FEATURE_STATIC_LIBRARY=" .. (package:config("shared") and "OFF" or "ON"), - "-DKTX_FEATURE_VK_UPLOAD=" .. (package:config("vulkan") and "ON" or "OFF"), - "-DKTX_FEATURE_GL_UPLOAD=" .. (package:config("opengl") and "ON" or "OFF"), - "-DKTX_FEATURE_TESTS=OFF", - "-DKTX_FEATURE_TOOLS=OFF", - } - - import("package.tools.cmake").install(package, configs) - end) - - on_test( - function(package) - assert(package:check_csnippets({ - test = [[ - #include - - void test() { - ktxTexture* kTexture; - } - ]], - })) - end - ) -end) diff --git a/xmake/options.xmake.lua b/xmake/options.xmake.lua index bea2a18ba..01cb52673 100644 --- a/xmake/options.xmake.lua +++ b/xmake/options.xmake.lua @@ -2,36 +2,43 @@ option("examples_gpu", { default = false, category = "root menu/build", - deps = { "examples" }, + deps = { "examples", "gpu" }, after_check = function(option) - if option:dep("examples"):enabled() then option:enable(true) end + if option:dep("examples"):enabled() then option:enable(option:dep("gpu"):enabled()) end end, }) option("examples_wsi", { default = false, category = "root menu/build", - deps = { "examples" }, + deps = { "examples", "wsi" }, after_check = function(option) - if option:dep("examples"):enabled() then option:enable(true) end + if option:dep("examples"):enabled() then option:enable(option:dep("wsi"):enabled()) end end, }) option("examples_log", { default = false, category = "root menu/build", - deps = { "examples" }, + deps = { "examples", "log" }, after_check = function(option) - if option:dep("examples"):enabled() then option:enable(true) end + if option:dep("examples"):enabled() then option:enable(option:dep("log"):enabled()) end end, }) option("examples_entities", { default = false, category = "root menu/build", - deps = { "examples" }, + deps = { "examples", "entities" }, after_check = function(option) - if option:dep("examples"):enabled() then - end + if option:dep("examples"):enabled() then option:enable(option:dep("entities"):enabled()) end end, }) --option:enable(true) end end }) +option("examples_lua", { + default = false, + category = "root menu/build", + deps = { "examples", "lua" }, + after_check = function(option) + if option:dep("examples"):enabled() then option:enable(option:dep("lua"):enabled()) end + end, +}) option("examples", { default = false, category = "root menu/build" }) option("tools", { default = false, @@ -51,6 +58,7 @@ option("entities", { default = true, category = "root menu/modules" }) option("image", { default = true, category = "root menu/modules", deps = { "log" } }) option("wsi", { default = true, category = "root menu/modules", deps = { "log" } }) option("gpu", { default = true, category = "root menu/modules", deps = { "log", "image", "wsi" } }) +option("lua", { default = true, category = "root menu/modules", deps = { "log" } }) option("compile_commands", { default = false, category = "root menu/support" }) option("vsxmake", { default = false, category = "root menu/support" }) diff --git a/xmake/rules/nzsl2spv.xmake.lua b/xmake/rules/nzsl.xmake.lua similarity index 97% rename from xmake/rules/nzsl2spv.xmake.lua rename to xmake/rules/nzsl.xmake.lua index c4263094e..cf91ddd58 100644 --- a/xmake/rules/nzsl2spv.xmake.lua +++ b/xmake/rules/nzsl.xmake.lua @@ -87,6 +87,7 @@ rule("compile.shaders", function() before_buildcmd_file(function(target, batchcmds, shaderfile, opt) import("lib.detect.find_tool") + import("utils.progress") local outputdir = path.join(import("core.project.config").builddir(), "shaders") local nzslc = target:data("nzslc") @@ -96,6 +97,7 @@ rule("compile.shaders", function() local outputfile = path.join(outputdir or path.directory(shaderfile), path.basename(shaderfile) .. ".spv") -- add commands + if progress.apply_target then opt.progress = progress.apply_target(target, opt.progress) end batchcmds:show_progress(opt.progress, "${color.build.object}compiling.shader %s", shaderfile) local argv = { "--compile=spv", "--optimize", "--spv-version=130", "--gl-flipy" } if outputdir then diff --git a/xmake/rules/resource2cpp.xmake.lua b/xmake/rules/resources.xmake.lua similarity index 91% rename from xmake/rules/resource2cpp.xmake.lua rename to xmake/rules/resources.xmake.lua index 8fc1922fb..016def4aa 100644 --- a/xmake/rules/resource2cpp.xmake.lua +++ b/xmake/rules/resources.xmake.lua @@ -2,15 +2,12 @@ rule("stormkit.utils.resource2cpp", function() before_build(function(target, opt) import("core.base.option") - if xmake.version():ge("2.5.9") then - import("utils.progress") - elseif not import("utils.progress", { try = true }) then - import("private.utils.progress") - end + import("utils.progress") local function GenerateEmbedHeader(filepath, targetpath) local bufferSize = 1024 * 1024 + if progress.apply_target then opt.progress = progress.apply_target(target, opt.progress) end progress.show(opt.progress, "${color.build.object}embedding %s", filepath) local resource = assert(io.open(filepath, "rb")) diff --git a/xmake/rules/stormkit_application.xmake.lua b/xmake/rules/stormkit_application.xmake.lua new file mode 100644 index 000000000..ca5fb4fe8 --- /dev/null +++ b/xmake/rules/stormkit_application.xmake.lua @@ -0,0 +1,38 @@ +namespace("stormkit", function() + rule("application", function() + add_deps("@stormkit::flags") + + on_config(function(target) + import("core.base.hashset") + + local stormkit_components = target:values("stormkit.components") or {} + local stormkit_components_set = hashset.from(stormkit_components) + + -- core -- + target:add("packages", "frozen", "unordered_dense", "nontype_functional") + + if stormkit_components_set:has("image") then target:add("packages", "libktx", "libpng", "libjpeg-turbo") end + if stormkit_components_set:has("wsi") then + if target:is_plat("linux") then + target:add( + "packages", + "libxcb", + "xcb-util-keysyms", + "xcb-util", + "xcb-util-image", + "xcb-util-wm", + "xcb-util-errors", + "wayland", + "wayland-protocols", + "libxkbcommon" + ) + end + end + if stormkit_components_set:has("gpu") then + target:add("packages", "volk", "vulkan-headers", "vulkan-memory-allocator") + end + + target:add("packages", "stormkit", { components = table.join("core", "main", stormkit_components) }) + end) + end) +end) diff --git a/xmake/rules/stormkit_example.xmake.lua b/xmake/rules/stormkit_example.xmake.lua new file mode 100644 index 000000000..131dc2c14 --- /dev/null +++ b/xmake/rules/stormkit_example.xmake.lua @@ -0,0 +1,21 @@ +namespace("stormkit", function() + rule("example", function() + add_deps("stormkit::flags") + add_deps("platform.windows.subsystem.console") + + on_load(function(target) + target:set("kind", "binary") + target:set("languages", "cxxlatest", "clatest") + target:add("deps", "stormkit::stormkit", "stormkit::main") + if target:is_plat("windows") then target:add("files", "examples/common/Windows/manifest.manifest") end + if get_config("apple_bundle") then + target:add("rules", "xcode.application") + if target:is_plat("macosx") then + target:add("files", path.join("$(projectdir)", "examples/common/macOS/info.plist")) + elseif target:is_plat("iphoneos") then + target:add("files", path.join("$(projectdir)", "examples/common/iOS/info.plist")) + end + end + end) + end) +end) diff --git a/xmake/rules/stormkit_flags.xmake.lua b/xmake/rules/stormkit_flags.xmake.lua index 8e2dedb20..6a8168ebb 100644 --- a/xmake/rules/stormkit_flags.xmake.lua +++ b/xmake/rules/stormkit_flags.xmake.lua @@ -1,236 +1,254 @@ -rule("stormkit.flags", function() - on_load("linux", "mingw", "macosx", "ios", "android", function(target) - if get_config("lto") then target:set("policy", "build.optimization.lto", true) end - if get_config("mold") and not is_subhost("windows") then - local arg = "-fuse-ld=mold" - if type(get_config("mold")) == "string" then arg = "-fuse-ld=" .. get_config("mold") end - target:add("ldflags", arg, { force = true }) - target:add("shflags", arg, { force = true }) - end - target:set("utf-8", true) +namespace("stormkit", function() + rule("flags", function() + on_load("linux", "mingw", "macosx", "ios", "android", function(target) + if get_config("lto") then + target:set("policy", "build.optimization.lto", true) + if get_config("toolchain") == "llvm" or get_config("toolchain") == "clang" then + target:add("ldflags", "-flto=thin", { force = true }) + target:add("shflags", "-flto=thin", { force = true }) + end + end + if get_config("mold") and not is_subhost("windows") then + local arg = "-fuse-ld=mold" + if type(get_config("mold")) == "string" then arg = "-fuse-ld=" .. get_config("mold") end + target:add("ldflags", arg, { force = true }) + target:add("shflags", arg, { force = true }) + end + target:set("utf-8", true) - if get_config("sanitizers") and is_mode("release", "releasedbg") and target:is_binary() then - target:set("policy", "build.sanitizer.address", true) - target:set("policy", "build.sanitizer.undefined", true) - end - end) - on_load("windows", function(target) - import("core.tool.compiler") - local rad_enabled = false - if get_config("rad") and is_subhost("windows") then - rad_enabled = true - target:add("ldflags", "-fuse-ld=radlink", { force = true }) - target:add("shflags", "-fuse-ld=radlink", { force = true }) - end + if get_config("sanitizers") and is_mode("debug", "release", "releasedbg") and target:is_binary() then + target:set("policy", "build.sanitizer.address", true) + target:set("policy", "build.sanitizer.undefined", true) + end + if + get_config("toolchain") == "llvm" + or get_config("toolchain") == "clang" + or get_config("toolchain") == "gcc" + then + target:add("syslinks", "dl") + end + end) + on_load("windows", function(target) + import("core.tool.compiler") + local rad_enabled = false + if get_config("rad") and is_subhost("windows") then + rad_enabled = true + target:add("ldflags", "-fuse-ld=radlink", { force = true }) + target:add("shflags", "-fuse-ld=radlink", { force = true }) + end - if get_config("sanitizers") and is_mode("release", "releasedbg") and target:is_binary() then - if get_config("toolchain") == "llvm" or get_config("toolchain") == "clang" then - if get_config("runtimes") == "c++_shared" or get_config("runtimes") == "c++_static" then - target:set("policy", "build.sanitizer.address", true) - target:set("policy", "build.sanitizer.undefined", true) + if get_config("sanitizers") and is_mode("release", "releasedbg") and target:is_binary() then + if get_config("toolchain") == "llvm" or get_config("toolchain") == "clang" then + if get_config("runtimes") == "c++_shared" or get_config("runtimes") == "c++_static" then + target:set("policy", "build.sanitizer.address", true) + target:set("policy", "build.sanitizer.undefined", true) + end end end - end - end) - on_config(function(target) - if get_config("devmode") then - target:set("warnings", "allextra", "pedantic") - else - target:set("warnings", "allextra", "pedantic", "error") - end - local flags = { - cl = { - cxx = { - "/Zc:__cplusplus", - "/Zc:lambda", - "/Zc:referenceBinding", - }, - cx = { - "/bigobj", - "/permissive-", - "/Zc:wchar_t", - "/Zc:inline", - "/Zc:preprocessor", - "/Zc:strictStrings", - "/analyze", - "/wd4251", -- Disable warning: class needs to have dll-interface to be used by clients of class blah blah blah - "/wd4297", - "/wd4996", - "/wd5063", - "/wd5260", - "/wd5050", - "/wd4005", - "/wd4611", -- Disable setjmp warning - }, - }, - gcc = { - cx = table.join( - { - "-fstrict-aliasing", - "-Wno-error=unknown-attributes", - "-Wno-error=sign-conversion", - "-Wno-error=shadow", - "-Wstrict-aliasing", - "-fanalyzer", - "-Wconversion", - "-Wshadow", - "-fdiagnostics-color=always", - "-fstack-protector-strong", - "-fstack-clash-protection", - "-fcf-protection=full", - "-ftrivial-auto-var-init=zero", - "-Wsuggest-attribute=pure", - "-Wsuggest-attribute=const", + end) + on_config(function(target) + if get_config("devmode") then + target:set("warnings", "allextra", "pedantic") + else + target:set("warnings", "allextra", "pedantic", "error") + end + local flags = { + cl = { + cxx = { + "/Zc:__cplusplus", + "/Zc:lambda", + "/Zc:referenceBinding", }, - is_mode("debug", "releasedbg") and { "-ggdb3", "-fno-omit-frame-pointer", "-fno-sanitize-merge" } - or {} - ), - ld = target:has_runtime("c++_shared", "c++_static") and {} or {}, - sh = target:has_runtime("c++_shared", "c++_static") and {} or {}, - }, - clang = { - cxx = { - "-Wno-include-angled-in-module-purview", + cx = { + "/bigobj", + "/permissive-", + "/Zc:wchar_t", + "/Zc:inline", + "/Zc:preprocessor", + "/Zc:strictStrings", + "/analyze", + "/wd4251", -- Disable warning: class needs to have dll-interface to be used by clients of class blah blah blah + "/wd4297", + "/wd4996", + "/wd5063", + "/wd5260", + "/wd5050", + "/wd4005", + "/wd4611", -- Disable setjmp warning + }, + }, + gcc = { + cx = table.join( + { + "-fstrict-aliasing", + "-Wno-error=unknown-attributes", + "-Wno-error=sign-conversion", + "-Wno-error=shadow", + "-Wstrict-aliasing", + "-fanalyzer", + "-Wconversion", + "-Wshadow", + "-fdiagnostics-color=always", + "-fstack-protector-strong", + "-fstack-clash-protection", + "-fcf-protection=full", + "-ftrivial-auto-var-init=zero", + "-Wsuggest-attribute=pure", + "-Wsuggest-attribute=const", + }, + is_mode("debug", "releasedbg") + and { "-ggdb3", "-fno-omit-frame-pointer", "-fno-sanitize-merge" } + or {} + ), + ld = target:has_runtime("c++_shared", "c++_static") and {} or {}, + sh = target:has_runtime("c++_shared", "c++_static") and {} or {}, }, - cx = table.join( - { - "-fstrict-aliasing", - "-Wno-gnu-statement-expression-from-macro-expansion", - "-Wno-error=gnu-statement-expression-from-macro-expansion", - "-Wno-error=unknown-attributes", - "-Wstrict-aliasing", - "-Wno-error=sign-conversion", - "-Wno-error=shadow", - "-Wconversion", - "-Wshadow", - "-Wno-c23-extensions", - "-Wno-error=c23-extensions", - "-fretain-comments-from-system-headers", - "-fdiagnostics-color=always", - "-fcolor-diagnostics", - "-fansi-escape-codes", - "-fstack-protector-strong", - "-fstack-clash-protection", - "-ftrivial-auto-var-init=zero", + clang = { + cxx = { + "-Wno-include-angled-in-module-purview", }, - is_plat("linux") and { - "-fcf-protection=full", - } or {}, - is_mode("debug", "releasedbg") and { "-ggdb3", "-fno-omit-frame-pointer", "-fno-sanitize-merge" } + cx = table.join( + { + "-fstrict-aliasing", + "-Wno-gnu-statement-expression-from-macro-expansion", + "-Wno-error=gnu-statement-expression-from-macro-expansion", + "-Wno-error=unknown-attributes", + "-Wstrict-aliasing", + "-Wno-error=sign-conversion", + "-Wno-error=shadow", + "-Wconversion", + "-Wshadow", + "-Wno-c23-extensions", + "-Wno-error=c23-extensions", + "-fretain-comments-from-system-headers", + "-fdiagnostics-color=always", + "-fcolor-diagnostics", + "-fansi-escape-codes", + "-fstack-protector-strong", + "-fstack-clash-protection", + "-ftrivial-auto-var-init=zero", + }, + is_plat("linux") and { + "-fcf-protection=full", + } or {}, + is_mode("debug", "releasedbg") + and { "-ggdb3", "-fno-omit-frame-pointer", "-fno-sanitize-merge" } + or {}, + target:has_runtime("c++_shared", "c++_static") and { "-fexperimental-library" } or {} + ), + mx = is_mode("debug", "releasedbg") + and { "-ggdb3", "-fno-omit-frame-pointer", "-fno-sanitize-merge" } or {}, - target:has_runtime("c++_shared", "c++_static") and { "-fexperimental-library" } or {} - ), - mx = is_mode("debug", "releasedbg") and { "-ggdb3", "-fno-omit-frame-pointer", "-fno-sanitize-merge" } - or {}, - mxx = { - "-fexperimental-library", + mxx = { + "-fexperimental-library", + }, + ld = table.join( + target:has_runtime("c++_shared", "c++_static") and { "-fexperimental-library" } or {}, + ( + target:is_plat("windows") + and is_mode("release") + and target:has_runtime("c++_shared", "c++_static") + ) + and { "-Xlinker -NODEFAULTLIB:libcmt" } + or {} + ), + sh = target:has_runtime("c++_shared", "c++_static") and { "-fexperimental-library" } or {}, }, - ld = table.join( - target:has_runtime("c++_shared", "c++_static") and { "-fexperimental-library" } or {}, - ( - target:is_plat("windows") - and is_mode("release") - and target:has_runtime("c++_shared", "c++_static") - ) - and { "-Xlinker -NODEFAULTLIB:libcmt" } - or {} - ), - sh = target:has_runtime("c++_shared", "c++_static") and { "-fexperimental-library" } or {}, - }, - } - if target:has_tool("cxx", "clang", "clangxx") then - target:add("cxxflags", flags.clang.cxx or {}, { tools = { "clang", "clangxx" }, force = true }) - target:add("cxxflags", flags.clang.cx or {}, { tools = { "clang", "clangxx" }, force = true }) - target:add("cflags", flags.clang.cx or {}, { tools = { "clang" }, force = true }) - target:add("mxflags", flags.clang.mx or {}, { tools = { "clang" }, force = true }) - target:add("mxxflags", flags.clang.mxx or {}, { tools = { "clang", "clang++" }, force = true }) - target:add("ldflags", flags.clang.ld or {}, { tools = { "clang", "clangxx", "lld" }, force = true }) - target:add("shflags", flags.clang.sh or {}, { tools = { "clang", "clangxx", "lld" }, force = true }) - target:add("arflags", flags.clang.ar or {}, { tools = { "clang", "clangxx", "llvm-ar" }, force = true }) - if (is_plat("linux", "mingw")) and not target:has_runtime("c++_shared", "c++_static") then - target:add("syslinks", "stdc++exp", "stdc++fs") + } + if target:has_tool("cxx", "clang", "clangxx") then + target:add("cxxflags", flags.clang.cxx or {}, { tools = { "clang", "clangxx" }, force = true }) + target:add("cxxflags", flags.clang.cx or {}, { tools = { "clang", "clangxx" }, force = true }) + target:add("cflags", flags.clang.cx or {}, { tools = { "clang" }, force = true }) + target:add("mxflags", flags.clang.mx or {}, { tools = { "clang" }, force = true }) + target:add("mxxflags", flags.clang.mxx or {}, { tools = { "clang", "clang++" }, force = true }) + target:add("ldflags", flags.clang.ld or {}, { tools = { "clang", "clangxx", "lld" }, force = true }) + target:add("shflags", flags.clang.sh or {}, { tools = { "clang", "clangxx", "lld" }, force = true }) + target:add("arflags", flags.clang.ar or {}, { tools = { "clang", "clangxx", "llvm-ar" }, force = true }) + if (is_plat("linux", "mingw")) and not target:has_runtime("c++_shared", "c++_static") then + target:add("syslinks", "stdc++exp", "stdc++fs") + end end - end - if target:has_tool("cxx", "gcc", "gxx") then - target:add("cxxflags", flags.gcc.cxx or {}, { tools = { "gcc", "g++" }, force = true }) - target:add("cxxflags", flags.gcc.cx or {}, { tools = { "gcc", "g++" }, force = true }) - target:add("cflags", flags.gcc.cx or {}, { tools = { "gcc" }, force = true }) - target:add("ldflags", flags.gcc.ld or {}, { tools = { "gcc", "g++", "ld" }, force = true }) - target:add("shflags", flags.gcc.sh or {}, { tools = { "gcc", "g++", "ld" }, force = true }) - target:add("arflags", flags.gcc.ar or {}, { tools = { "gcc", "g++", "ar" }, force = true }) - target:add("syslinks", "stdc++exp", "stdc++fs") - end + if target:has_tool("cxx", "gcc", "gxx") then + target:add("cxxflags", flags.gcc.cxx or {}, { tools = { "gcc", "g++" }, force = true }) + target:add("cxxflags", flags.gcc.cx or {}, { tools = { "gcc", "g++" }, force = true }) + target:add("cflags", flags.gcc.cx or {}, { tools = { "gcc" }, force = true }) + target:add("ldflags", flags.gcc.ld or {}, { tools = { "gcc", "g++", "ld" }, force = true }) + target:add("shflags", flags.gcc.sh or {}, { tools = { "gcc", "g++", "ld" }, force = true }) + target:add("arflags", flags.gcc.ar or {}, { tools = { "gcc", "g++", "ar" }, force = true }) + target:add("syslinks", "stdc++exp", "stdc++fs") + end - if target:has_tool("cxx", "cl", "clang_cl") then - target:add("cxxflags", flags.cl.cxx or {}, { tools = { "cl", "clang_cl" }, force = true }) - target:add("cxxflags", flags.cl.cx or {}, { tools = { "cl", "clang_cl" }, force = true }) - target:add("cflags", flags.cl.cx or {}, { tools = { "cl", "clang_cl" }, force = true }) - target:add("ldflags", flags.cl.ld or {}, { tools = { "cl", "link" }, force = true }) - target:add("shflags", flags.cl.sh or {}, { tools = { "cl", "link" }, force = true }) - target:add("arflags", flags.cl.ar or {}, { tools = { "cl", "clang_cl" }, force = true }) - end + if target:has_tool("cxx", "cl", "clang_cl") then + target:add("cxxflags", flags.cl.cxx or {}, { tools = { "cl", "clang_cl" }, force = true }) + target:add("cxxflags", flags.cl.cx or {}, { tools = { "cl", "clang_cl" }, force = true }) + target:add("cflags", flags.cl.cx or {}, { tools = { "cl", "clang_cl" }, force = true }) + target:add("ldflags", flags.cl.ld or {}, { tools = { "cl", "link" }, force = true }) + target:add("shflags", flags.cl.sh or {}, { tools = { "cl", "link" }, force = true }) + target:add("arflags", flags.cl.ar or {}, { tools = { "cl", "clang_cl" }, force = true }) + end - if is_plat("windows") then - local runtimes = { is_mode("debug") and "MDd" or "MD" } + if is_plat("windows") then + local runtimes = { is_mode("debug") and "MDd" or "MD" } - local libcpp = target:has_runtime("c++_shared", "c++_static") - local libstdcpp = target:has_runtime("stdc++_shared", "stdc++_static") + local libcpp = target:has_runtime("c++_shared", "c++_static") + local libstdcpp = target:has_runtime("stdc++_shared", "stdc++_static") - if is_mode("debug") then - if libcpp then - target:add("defines", "_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG") - elseif libstdcpp then - target:add("defines", "_FORTIFY_SOURCE=3") - if get_config("devmode") then - target:add("defines", "_GLIBCXX_DEBUG") + if is_mode("debug") then + if libcpp then + target:add("defines", "_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG") + elseif libstdcpp then + target:add("defines", "_FORTIFY_SOURCE=3") + if get_config("devmode") then + target:add("defines", "_GLIBCXX_DEBUG") + else + target:add("defines", "_GLIBCXX_ASSERTIONS") + end else - target:add("defines", "_GLIBCXX_ASSERTIONS") + target:add("defines", "_MSVC_STL_HARDENING=1") + end + elseif is_mode("releasedbg") then + if libcpp then + target:add("defines", "_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE") + elseif libstdcpp then + target:add("defines", "_FORTIFY_SOURCE=2", "_GLIBCXX_ASSERTIONS") + else + target:add("defines", "_MSVC_STL_HARDENING=1") + end + elseif is_mode("release") then + if libcpp then + target:add("defines", "_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST") + elseif libstdcpp then + target:add("defines", "_FORTIFY_SOURCE=1") + else + target:add("defines", "_MSVC_STL_HARDENING=1") end - else - target:add("defines", "_MSVC_STL_HARDENING=1") - end - elseif is_mode("releasedbg") then - if libcpp then - target:add("defines", "_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE") - elseif libstdcpp then - target:add("defines", "_FORTIFY_SOURCE=2", "_GLIBCXX_ASSERTIONS") - else - target:add("defines", "_MSVC_STL_HARDENING=1") end - elseif is_mode("release") then - if libcpp then - target:add("defines", "_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST") - elseif libstdcpp then - target:add("defines", "_FORTIFY_SOURCE=1") - else - target:add("defines", "_MSVC_STL_HARDENING=1") + + if target:has_runtime("c++_shared") then + table.insert(runtimes, "c++_shared") + elseif target:has_runtime("c++_static") then + table.insert(runtimes, "c++_static") end + target:set("runtimes", table.unpack(runtimes)) end - - if target:has_runtime("c++_shared") then - table.insert(runtimes, "c++_shared") - elseif target:has_runtime("c++_static") then - table.insert(runtimes, "c++_static") + if is_mode("release") then + target:set("symbols", "hidden") + target:set("optimize", "fast") + elseif is_mode("debug") then + target:set("symbols", "debug") + target:add("cxflags", "-ggdb3", { tools = { "clang", "gcc" } }) + target:add("mxflags", "-ggdb3", { tools = { "clang", "gcc" } }) + elseif is_mode("releasedbg") then + target:set("optimize", "fast") + target:set("symbols", "debug", "hidden") + target:add("mxflags", "-ggdb3", { tools = { "clang", "gcc" } }) end - target:set("runtimes", table.unpack(runtimes)) - end - if is_mode("release") then - target:set("symbols", "hidden") - target:set("optimize", "fast") - elseif is_mode("debug") then - target:set("symbols", "debug") - target:add("cxflags", "-ggdb3", { tools = { "clang", "gcc" } }) - target:add("mxflags", "-ggdb3", { tools = { "clang", "gcc" } }) - elseif is_mode("releasedbg") then - target:set("optimize", "fast") - target:set("symbols", "debug", "hidden") - target:add("mxflags", "-ggdb3", { tools = { "clang", "gcc" } }) - end - target:set("fpmodels", "fast") - target:add("vectorexts", "fma") - target:add("vectorexts", "neon") - target:add("vectorexts", "avx", "avx2") - target:add("vectorexts", "sse", "sse2", "sse3", "ssse3", "sse4.2") + target:set("fpmodels", "fast") + target:add("vectorexts", "fma") + target:add("vectorexts", "neon") + target:add("vectorexts", "avx", "avx2") + target:add("vectorexts", "sse", "sse2", "sse3", "ssse3", "sse4.2") + end) end) end) diff --git a/xmake/rules/stormkit_library.xmake.lua b/xmake/rules/stormkit_library.xmake.lua new file mode 100644 index 000000000..979ea4af3 --- /dev/null +++ b/xmake/rules/stormkit_library.xmake.lua @@ -0,0 +1,38 @@ +namespace("stormkit", function() + rule("library", function() + add_deps("@stormkit::flags") + + on_config(function(target) + import("core.base.hashset") + + local stormkit_components = target:values("stormkit.components") or {} + local stormkit_components_set = hashset.from(stormkit_components) + + -- core -- + target:add("packages", "frozen", "unordered_dense", "nontype_functional") + + if stormkit_components_set:has("image") then target:add("packages", "libktx", "libpng", "libjpeg-turbo") end + if stormkit_components_set:has("wsi") then + if target:is_plat("linux") then + target:add( + "packages", + "libxcb", + "xcb-util-keysyms", + "xcb-util", + "xcb-util-image", + "xcb-util-wm", + "xcb-util-errors", + "wayland", + "wayland-protocols", + "libxkbcommon" + ) + end + end + if stormkit_components_set:has("gpu") then + target:add("packages", "volk", "vulkan-headers", "vulkan-memory-allocator") + end + + target:add("packages", "stormkit", { components = table.join("core", stormkit_components) }) + end) + end) +end) diff --git a/xmake/rules/wayland-protocols.xmake.lua b/xmake/rules/wayland-protocols.xmake.lua index 96778e3f7..7687e1c9d 100644 --- a/xmake/rules/wayland-protocols.xmake.lua +++ b/xmake/rules/wayland-protocols.xmake.lua @@ -51,6 +51,7 @@ rule("wayland.protocols", function() before_buildcmd_file(function(target, batchcmds, sourcefile, opt) import("lib.detect.find_tool") + import("utils.progress") local outputdir = target:extraconf("rules", "wayland.protocols", "outputdir") or path.join(target:autogendir(), "rules", "wayland.protocols") @@ -67,6 +68,7 @@ rule("wayland.protocols", function() local client_flags = { client_flag, sourcefile, clientfile } local private_flags = { private_flag, sourcefile, privatefile } + if progress.apply_target then opt.progress = progress.apply_target(target, opt.progress) end batchcmds:show_progress( opt.progress, "${color.build.object}generating.wayland.protocol.client %s", diff --git a/xmake/targets.xmake.lua b/xmake/targets.xmake.lua deleted file mode 100644 index 671456bb6..000000000 --- a/xmake/targets.xmake.lua +++ /dev/null @@ -1,144 +0,0 @@ -modules = { - core = { - public_packages = { "frozen", "unordered_dense", "tl_function_ref" }, - modulename = "core", - has_headers = true, - custom = function() - if is_plat("windows") then add_packages("wil") end - - set_configdir("$(builddir)/.gens/include/") - add_configfiles("include/(stormkit/core/config.hpp.in)") - add_headerfiles("$(builddir)/.gens/include/(stormkit/core/*.hpp)") - -- add_cxflags("clang::-Wno-language-extension-token") - - on_config(function(target) - local output, errors = os.iorunv("git", { "rev-parse", "--abbrev-ref", "HEAD" }) - - if not errors == "" then - print("Failed to get git hash and branch, reason: ", errors, output) - target:set("configvar", "STORMKIT_GIT_BRANCH", " ") - target:set("configvar", "STORMKIT_GIT_COMMIT_HASH", " ") - return - end - - target:set("configvar", "STORMKIT_GIT_BRANCH", output:trim()) - output, errors = os.iorunv("git", { "rev-parse", "--verify", "HEAD" }) - - target:set("configvar", "STORMKIT_GIT_COMMIT_HASH", output:trim()) - end) - end, - }, - test = { - modulename = "test", - public_deps = { "core" }, - has_headers = true, - }, - log = { - modulename = "log", - public_deps = { "core" }, - has_headers = true, - }, - entities = { - modulename = "entities", - public_deps = { "core" }, - }, - image = { - packages = { "libktx", "libpng", "libjpeg-turbo" }, - modulename = "image", - public_deps = { "core" }, - }, - main = { - modulename = "main", - has_headers = true, - deps = { "core" }, - custom = function() - add_cxflags("-Wno-main") - set_strip("debug") - end, - frameworks = is_plat("macosx") and { "CoreFoundation" } or nil, - }, - wsi = { - modulename = "wsi", - public_deps = { "core" }, - deps = { "log" }, - packages = is_plat("linux") and { - "libxcb", - "xcb-util-keysyms", - "xcb-util", - "xcb-util-image", - "xcb-util-wm", - "xcb-util-errors", - "wayland", - "wayland-protocols", - "libxkbcommon", - } or nil, - -- frameworks = is_plat("macosx") and { "CoreFoundation", "Foundation", "AppKit", "Metal", "IOKit", "QuartzCore" } - -- or nil, - custom = function() - if is_plat("macosx", "iphoneos", "tvos") then - if is_plat("macosx") then - add_files("src/wsi/macos/swift/*.swift", { public = true }) - add_files("src/wsi/macos/swift/*.m") - set_values("swift.modulename", "macOS") - add_scflags("-Isrc/wsi/macos/swift") - elseif is_plat("iphoneos") then - add_files("src/wsi/ios/swift/*.swift", { public = true }) - add_scflags("-Isrc/wsi/ios/swift") - set_values("swift.modulename", "iOS") - elseif is_plat("tvos") then - add_files("src/wsi/tvos/swift/*.swift", { public = true }) - add_scflags("-Isrc/wsi/tvos/swift") - set_values("swift.modulename", "tvOS") - end - set_values("swift.interop", "cxx") - elseif is_plat("linux") then - add_rules("wayland.protocols") - - on_load(function(target) - assert(target:pkg("wayland-protocols")) - local wayland_protocols_dir = - path.join(target:pkg("wayland-protocols"):installdir() or "/usr", "share", "wayland-protocols") - assert(wayland_protocols_dir, "wayland protocols directory not found") - - local protocols = { - path.join("stable", "xdg-shell", "xdg-shell.xml"), - path.join("stable", "tablet", "tablet-v2.xml"), - path.join("stable", "viewporter", "viewporter.xml"), - path.join("staging", "content-type", "content-type-v1.xml"), - path.join("staging", "pointer-warp", "pointer-warp-v1.xml"), - path.join("staging", "cursor-shape", "cursor-shape-v1.xml"), - path.join("staging", "single-pixel-buffer", "single-pixel-buffer-v1.xml"), - path.join("unstable", "xdg-decoration", "xdg-decoration-unstable-v1.xml"), - path.join("unstable", "pointer-constraints", "pointer-constraints-unstable-v1.xml"), - path.join("unstable", "relative-pointer", "relative-pointer-unstable-v1.xml"), - } - - for _, protocol in ipairs(protocols) do - target:add("files", path.join(wayland_protocols_dir, protocol)) - end - end) - elseif is_plat("windows", "mingw") then - add_syslinks("User32", "Shell32", "Gdi32", "Shcore", "Gdiplus") - end - end, - }, - gpu = { - modulename = "gpu", - has_headers = true, - public_packages = { - "frozen", - "volk", - "vulkan-headers", - "vulkan-memory-allocator", - }, - public_deps = { "core", "log", "wsi", "image" }, - packages = is_plat("linux") and { - "libxcb", - "wayland", - } or nil, - public_defines = { - "STORMKIT_GPU_VULKAN", - }, - custom = function() add_cxflags("clang::-Wno-missing-declarations") end, - }, -} diff --git a/xmake/targets/core.xmake.lua b/xmake/targets/core.xmake.lua new file mode 100644 index 000000000..da4b5cb13 --- /dev/null +++ b/xmake/targets/core.xmake.lua @@ -0,0 +1,62 @@ +add_requires("frozen", { system = false, configs = { modules = true, std_import = true, cpp = "latest" } }) +add_requires("unordered_dense", { system = false, configs = { modules = true, std_import = true } }) +add_requires("nontype_functional") + +local src_core_dir = path.join(src_dir, "core") +local module_core_dir = path.join(module_dir, "core") + +target("core", function() + set_kind("$(kind)") + add_rules("flags") + + set_languages("cxxlatest", "clatest") + + set_basename("stormkit-core") + + add_defines("ANKERL_UNORDERED_DENSE_STD_MODULE=1", "FROZEN_STD_MODULE=1", { public = true }) + add_defines("STORMKIT_CORE_BUILD", { public = false }) + if is_mode("debug") then add_defines("STORMKIT_BUILD_DEBUG", { public = true }) end + + if is_kind("static") then add_defines("STORMKIT_STATIC", { public = true }) end + + add_files(path.join(module_dir, "core.cppm"), path.join(module_core_dir, "**.cppm"), { public = true }) + add_files(path.join(src_core_dir, "*.cpp"), path.join(src_core_dir, "*.cppm")) + + if is_plat("linux", "macosx", "iphoneos", "tvos", "android") then + add_files(path.join(src_core_dir, "posix/**.cpp")) + end + if is_plat("linux") then add_files(path.join(src_core_dir, "linux/**.cpp")) end + if is_plat("windows") then add_files(path.join(src_core_dir, "win32/**.cpp")) end + if is_plat("macosx", "iphoneos", "tvos", "watchos") then + add_files(path.join(src_core_dir, "darwin/**.cpp"), path.join(src_core_dir, "darwin/**.m")) + end + + set_configdir("$(builddir)/.gens/include/") + add_configfiles(path.join(include_dir, "(stormkit/core/config.hpp.in)")) + add_includedirs("$(builddir)/.gens/include", { public = true }) + + add_headerfiles(path.join(include_dir, "(stormkit/core/**.hpp)"), "$(builddir)/.gens/include/(stormkit/core/*.hpp)") + add_includedirs(include_dir, { public = true }) + + add_packages("frozen", "unordered_dense", "nontype_functional", { public = true }) + + on_config(function(target) + local output, errors = os.iorunv("git", { "rev-parse", "--abbrev-ref", "HEAD" }) + + if not errors == "" then + print("Failed to get git hash and branch, reason: ", errors, output) + target:set("configvar", "STORMKIT_GIT_BRANCH", " ") + target:set("configvar", "STORMKIT_GIT_COMMIT_HASH", " ") + return + end + + target:set("configvar", "STORMKIT_GIT_BRANCH", output:trim()) + output, errors = os.iorunv("git", { "rev-parse", "--verify", "HEAD" }) + + target:set("configvar", "STORMKIT_GIT_COMMIT_HASH", output:trim()) + end) + + add_options("sanitizers") + + set_group("libraries") +end) diff --git a/xmake/targets/entities.xmake.lua b/xmake/targets/entities.xmake.lua new file mode 100644 index 000000000..badfc1aff --- /dev/null +++ b/xmake/targets/entities.xmake.lua @@ -0,0 +1,26 @@ +local src_entities_dir = path.join(src_dir, "entities") + +target("entities", function() + set_kind("$(kind)") + add_rules("flags") + + set_languages("cxxlatest", "clatest") + + set_basename("stormkit-entities") + + add_defines("STORMKIT_ENTITIES_BUILD", { public = false }) + + if get_config("lua") then add_packages("luau", "sol2_luau", { public = true }) end + + add_files(path.join(module_dir, "entities.cppm"), { public = true }) + add_files(path.join(src_entities_dir, "*.cpp")) + + add_headerfiles(path.join(include_dir, "(stormkit/entities/**.hpp)")) + add_includedirs(include_dir, { public = true }) + + add_options("sanitizers") + + add_deps("core") + + set_group("libraries") +end) diff --git a/xmake/targets/examples.xmake.lua b/xmake/targets/examples.xmake.lua new file mode 100644 index 000000000..dfc56471f --- /dev/null +++ b/xmake/targets/examples.xmake.lua @@ -0,0 +1,7 @@ +namespace("examples", function() + for _, name in ipairs({ "log", "entities", "gpu", "image", "wsi", "lua" }) do + if get_config("examples_" .. name) then + includes(path.join(os.projectdir(), "examples", name, "**/xmake.lua")) + end + end +end) diff --git a/xmake/targets/gpu.xmake.lua b/xmake/targets/gpu.xmake.lua new file mode 100644 index 000000000..a02cebfbe --- /dev/null +++ b/xmake/targets/gpu.xmake.lua @@ -0,0 +1,48 @@ +local vulkan_version = "1.4.335" +add_requires("volk", { + version = vulkan_version, + system = false, +}) +add_requires("vulkan-headers", { + version = vulkan_version, + system = false, + configs = { + modules = false, + }, +}) +add_requires("vulkan-memory-allocator", { + version = "v3.3.0", + system = false, +}) + +local src_gpu_dir = path.join(src_dir, "gpu") +local module_gpu_dir = path.join(module_dir, "gpu") + +target("gpu", function() + set_kind("$(kind)") + add_rules("flags") + + set_basename("stormkit-gpu") + + set_languages("cxxlatest", "clatest") + + add_defines("STORMKIT_GPU_BUILD", { public = false }) + + add_files(path.join(module_dir, "gpu.cppm"), path.join(module_gpu_dir, "**.cppm"), { public = true }) + add_files(path.join(src_gpu_dir, "**.cpp")) + -- add_files(path.join(src_gpu_dir, "*.cpp"), path.join(src_gpu_dir, "*.cppm")) + + add_headerfiles(path.join(include_dir, "(stormkit/gpu/**.hpp)")) + add_includedirs(include_dir, { public = true }) + + add_defines("STORMKIT_GPU_VULKAN", { public = true }) + + add_deps("core", "wsi", "image") + add_deps("log", { public = false }) + + add_packages("volk", "vulkan-headers", "vulkan-memory-allocator") + + add_options("sanitizers") + + set_group("libraries") +end) diff --git a/xmake/targets/image.xmake.lua b/xmake/targets/image.xmake.lua new file mode 100644 index 000000000..3499cd233 --- /dev/null +++ b/xmake/targets/image.xmake.lua @@ -0,0 +1,36 @@ +add_requires("libktx") +add_requires("libpng") +add_requires("libjpeg-turbo", is_plat("windows") and { + system = false, + configs = { + runtimes = "MD", + shared = true, + }, +} or {}) + +local src_image_dir = path.join(src_dir, "image") + +target("image", function() + set_kind("$(kind)") + add_rules("flags") + + set_languages("cxxlatest", "clatest") + + set_basename("stormkit-image") + + add_defines("STORMKIT_IMAGE_BUILD", { public = false }) + + add_files(path.join(module_dir, "image.cppm"), { public = true }) + add_files(path.join(src_image_dir, "*.cpp"), path.join(src_image_dir, "*.cppm")) + + add_headerfiles(path.join(include_dir, "(stormkit/image/**.hpp)")) + add_includedirs(include_dir, { public = true }) + + add_deps("core") + + add_packages("libktx", "libpng", "libjpeg-turbo") + + add_options("sanitizers") + + set_group("libraries") +end) diff --git a/xmake/targets/log.xmake.lua b/xmake/targets/log.xmake.lua new file mode 100644 index 000000000..ba7f0425d --- /dev/null +++ b/xmake/targets/log.xmake.lua @@ -0,0 +1,24 @@ +local src_log_dir = path.join(src_dir, "log") + +target("log", function() + set_kind("$(kind)") + add_rules("flags") + + set_languages("cxxlatest", "clatest") + + set_basename("stormkit-log") + + add_defines("STORMKIT_LOG_BUILD", { public = false }) + + add_files(path.join(module_dir, "log.cppm"), { public = true }) + add_files(path.join(src_log_dir, "*.cpp")) + + add_headerfiles(path.join(include_dir, "(stormkit/log/**.hpp)")) + add_includedirs(include_dir, { public = true }) + + add_deps("core") + + add_options("sanitizers") + + set_group("libraries") +end) diff --git a/xmake/targets/lua.xmake.lua b/xmake/targets/lua.xmake.lua new file mode 100644 index 000000000..ee4dd28b1 --- /dev/null +++ b/xmake/targets/lua.xmake.lua @@ -0,0 +1,76 @@ +local is_libcpp = false +if is_plat("linux") then + if has_config("runtimes") then is_libcpp = get_config("runtimes"):startswith("c++") end +end + +add_requires("luau", { + system = false, + version = "upstream", + configs = { + shared = false, + extern_c = true, + build_cli = false, + cxxflags = is_libcpp and { "-stdlib=libc++" } or nil, + shflags = is_libcpp and { "-stdlib=libc++" } or nil, + arflags = is_libcpp and { "-stdlib=libc++" } or nil, + }, +}) +add_requires("sol2_luau", { + system = false, + version = "develop", +}) + +local src_lua_dir = path.join(src_dir, "lua") +local module_lua_dir = path.join(module_dir, "lua") + +target("lua", function() + set_kind("$(kind)") + add_rules("flags") + + set_languages("cxxlatest", "clatest") + + set_basename("stormkit-lua") + + add_defines("STORMKIT_LUA_BUILD", { public = false }) + + add_files(path.join(module_dir, "lua.cppm"), { public = true }) + add_files(path.join(src_lua_dir, "lua.cpp")) + add_files(path.join(src_lua_dir, "core.cppm")) + add_files(path.join(src_lua_dir, "core.cpp")) + add_files(path.join(src_lua_dir, "core/*.cpp")) + add_files(path.join(src_lua_dir, "log.cppm")) + add_files(path.join(src_lua_dir, "log.cpp")) + + if get_config("entities") then + add_files(path.join(src_lua_dir, "entities.cppm")) + add_files(path.join(src_lua_dir, "entities.cpp")) + end + if get_config("image") then + add_files(path.join(src_lua_dir, "image.cppm")) + add_files(path.join(src_lua_dir, "image.cpp")) + end + if get_config("wsi") then + add_files(path.join(src_lua_dir, "wsi.cpp")) + add_files(path.join(src_lua_dir, "wsi/*.cpp")) + add_files(path.join(src_lua_dir, "wsi.cppm")) + end + if get_config("gpu") then + add_files(path.join(src_lua_dir, "gpu.cppm")) + add_files(path.join(src_lua_dir, "gpu.cpp")) + end + + add_headerfiles(path.join(include_dir, "(stormkit/lua/**.hpp)")) + add_includedirs(include_dir, { public = true }) + + add_deps("core", "log") + if get_config("image") then add_deps("image") end + if get_config("entities") then add_deps("entities") end + if get_config("wsi") then add_deps("wsi") end + if get_config("gpu") then add_deps("gpu") end + + add_packages("luau", "sol2_luau", { public = true }) + + add_options("sanitizers") + + set_group("libraries") +end) diff --git a/xmake/targets/main.xmake.lua b/xmake/targets/main.xmake.lua new file mode 100644 index 000000000..82a7b2909 --- /dev/null +++ b/xmake/targets/main.xmake.lua @@ -0,0 +1,33 @@ +local src_main_dir = path.join(src_dir, "main") + +target("main", function() + set_kind("static") + add_rules("flags") + + set_languages("cxxlatest", "clatest") + + set_basename("stormkit-main") + + add_defines("STORMKIT_MAIN_BUILD", { public = false }) + + add_files(path.join(module_dir, "main.cppm"), { public = true }) + if is_plat("linux") then add_files(path.join(src_main_dir, "linux/**.cpp")) end + if is_plat("windows") then add_files(path.join(src_main_dir, "win32/**.cpp")) end + if is_plat("macosx") then add_files(path.join(src_main_dir, "macos/**.cpp")) end + if is_plat("iphoneos") then add_files(path.join(src_main_dir, "ios/**.cpp")) end + if is_plat("tvos") then add_files(path.join(src_main_dir, "tvos/**.cpp")) end + if is_plat("android") then add_files(path.join(src_main_dir, "android/**.cpp")) end + + add_headerfiles("$(projectdir)/include/(stormkit/main/**.hpp)") + add_includedirs("$(projectdir)/include", { public = true }) + + add_cxflags("-Wno-main", { tools = { "clang", "gcc" } }) + + add_deps("core") + + if is_plat("macosx") then add_frameworks("CoreFoundation") end + + add_options("sanitizers") + + set_group("libraries") +end) diff --git a/xmake/targets/test.xmake.lua b/xmake/targets/test.xmake.lua new file mode 100644 index 000000000..e0f9a9496 --- /dev/null +++ b/xmake/targets/test.xmake.lua @@ -0,0 +1,22 @@ +local src_test_dir = path.join(src_dir, "test") + +target("test", function() + set_kind("static") + add_rules("flags") + + set_languages("cxxlatest", "clatest") + + set_basename("stormkit-test") + + add_files(path.join(module_dir, "test.cppm"), { public = true }) + add_files(path.join(src_test_dir, "*.cpp")) + + add_headerfiles(path.join(include_dir, "(stormkit/test/**.hpp)")) + add_includedirs(include_dir, { public = true }) + + add_deps("core") + + add_options("sanitizers") + + set_group("libraries") +end) diff --git a/xmake/targets/tests.xmake.lua b/xmake/targets/tests.xmake.lua new file mode 100644 index 000000000..2c84db293 --- /dev/null +++ b/xmake/targets/tests.xmake.lua @@ -0,0 +1,47 @@ +namespace("tests", function() + for _, name in ipairs({ "core", "log", "entities", "gpu", "image", "wsi", "lua" }) do + for _, file in ipairs(os.files(path.join(os.projectdir(), "tests", name, "**.cpp"))) do + local testname = path.basename(file) + + target(name .. "-" .. testname, function() + add_rules("stormkit::example") + + on_config(function(target) + function parseTestFile() + local code = io.readfile(file) + + local suite_name_regex = [[TestSuite%s-{.-"(.-)",]] + local test_name_regex = [[{%s-"(.-)"%s-,]] + + local suite_name = code:match(suite_name_regex) + + local test_names + for test_name in code:gmatch(test_name_regex) do + test_names = test_names or {} + if test_name ~= suite_name then table.insert(test_names, test_name) end + end + + return { suite_name = suite_name, test_names = test_names } + end + + local tests = parseTestFile() + for _, test_name in ipairs(tests.test_names) do + target:add( + "tests", + tests.suite_name .. "/" .. test_name, + { group = tests.suite_name, runargs = "--test_name=" .. test_name } + ) + end + end) + + add_files(file) + + add_deps("stormkit::test") + + add_options("sanitizers") + + set_group("tests") + end) + end + end +end) diff --git a/xmake/targets/tools.xmake.lua b/xmake/targets/tools.xmake.lua new file mode 100644 index 000000000..f1de021e0 --- /dev/null +++ b/xmake/targets/tools.xmake.lua @@ -0,0 +1 @@ +namespace("tools", function() includes(path.join(os.projectdir(), "tools/terra/xmake.lua")) end) diff --git a/xmake/targets/wsi.xmake.lua b/xmake/targets/wsi.xmake.lua new file mode 100644 index 000000000..add7c89f9 --- /dev/null +++ b/xmake/targets/wsi.xmake.lua @@ -0,0 +1,115 @@ +if is_plat("linux") then + add_requires("libxcb") + add_requires("xcb-util-keysyms") + add_requires("xcb-util") + add_requires("xcb-util-image") + add_requires("xcb-util-wm") + add_requires("xcb-util-errors") + add_requires("wayland") + add_requires("wayland-protocols") + add_requires("libxkbcommon", { + system = false, + configs = { + wayland = true, + x11 = true, + }, + }) +end + +local src_wsi_dir = path.join(src_dir, "wsi") +local module_wsi_dir = path.join(module_dir, "wsi") + +target("wsi", function() + set_kind("$(kind)") + add_rules("flags") + + set_languages("cxxlatest", "clatest") + + set_basename("stormkit-wsi") + + add_defines("STORMKIT_WSI_BUILD", { public = false }) + + add_files(path.join(module_dir, "wsi.cppm"), path.join(module_wsi_dir, "**.cppm"), { public = true }) + add_files(path.join(src_wsi_dir, "*.cpp"), path.join(src_wsi_dir, "common/*.cppm")) + + if is_plat("linux") then + add_files(path.join(src_wsi_dir, "linux/**.cpp"), path.join(src_wsi_dir, "linux/**.cppm")) + + add_rules("wayland.protocols") + + on_load(function(target) + assert(target:pkg("wayland-protocols")) + local wayland_protocols_dir = + path.join(target:pkg("wayland-protocols"):installdir() or "/usr", "share", "wayland-protocols") + assert(wayland_protocols_dir, "wayland protocols directory not found") + + local protocols = { + path.join("stable", "xdg-shell", "xdg-shell.xml"), + path.join("stable", "tablet", "tablet-v2.xml"), + path.join("stable", "viewporter", "viewporter.xml"), + path.join("staging", "content-type", "content-type-v1.xml"), + path.join("staging", "pointer-warp", "pointer-warp-v1.xml"), + path.join("staging", "cursor-shape", "cursor-shape-v1.xml"), + path.join("staging", "single-pixel-buffer", "single-pixel-buffer-v1.xml"), + path.join("unstable", "xdg-decoration", "xdg-decoration-unstable-v1.xml"), + path.join("unstable", "pointer-constraints", "pointer-constraints-unstable-v1.xml"), + path.join("unstable", "relative-pointer", "relative-pointer-unstable-v1.xml"), + } + + for _, protocol in ipairs(protocols) do + target:add("files", path.join(wayland_protocols_dir, protocol)) + end + end) + + add_packages( + "libxcb", + "xcb-util-keysyms", + "xcb-util", + "xcb-util-image", + "xcb-util-wm", + "xcb-util-errors", + "wayland", + "wayland-protocols", + "libxkbcommon" + ) + elseif is_plat("windows") then + add_files(path.join(src_wsi_dir, "win32/**.cpp"), path.join(src_wsi_dir, "win32/**.cppm")) + add_syslinks("User32", "Shell32", "Gdi32", "Shcore", "Gdiplus") + elseif is_plat("macosx") then + add_files( + path.join(src_wsi_dir, "macos/**.cpp"), + path.join(src_wsi_dir, "macos/**.m"), + path.join(src_wsi_dir, "macos/**.cppm") + ) + add_files(path.join(src_wsi_dir, "macos/**.swift"), { public = true }) + set_values("swift.modulename", "macOS") + set_values("swift.interop", "cxx") + add_scflags("-I" .. path.join(src_wsi_dir, "macos/swift")) + elseif is_plat("iphoneos") then + add_files(path.join(src_wsi_dir, "ios/**.cpp"), path.join(src_wsi_dir, "ios/**.m")) + add_files(path.join(src_wsi_dir, "ios/**.swift"), { public = true }) + set_values("swift.modulename", "iOS") + set_values("swift.interop", "cxx") + add_scflags("-I" .. path.join(src_wsi_dir, "ios/swift")) + elseif is_plat("tvos") then + add_files( + path.join(src_wsi_dir, "tvos/**.cpp"), + path.join(src_wsi_dir, "tvos/**.m"), + path.join(src_wsi_dir, "tvos/**.swift") + ) + set_values("swift.modulename", "tvOS") + set_values("swift.interop", "cxx") + add_scflags("-I" .. path.join(src_wsi_dir, "tvos/swift")) + end + + add_headerfiles(path.join(include_dir, "(stormkit/wsi/**.hpp)")) + add_includedirs(include_dir, { public = true }) + + add_deps("core", "log") + + add_packages(packages, { public = false }) + + add_options("sanitizers") + + set_group("libraries") +end) diff --git a/xmake/tests.xmake.lua b/xmake/tests.xmake.lua deleted file mode 100644 index 856e15d69..000000000 --- a/xmake/tests.xmake.lua +++ /dev/null @@ -1,56 +0,0 @@ -includes("targets.xmake.lua") - -namespace("tests", function() - for name, _ in pairs(modules) do - if name ~= "test" then - for _, file in ipairs(os.files(path.join(os.projectdir(), "tests", name, "**.cpp"))) do - local testname = path.basename(file) - - target(name .. "-" .. testname, function() - set_group("tests") - set_kind("binary") - set_languages("cxxlatest", "clatest") - - on_config(function(target) - function parseTestFile() - local code = io.readfile(file) - - local suite_name_regex = [[TestSuite%s-{.-"(.-)",]] - local test_name_regex = [[{%s-"(.-)"%s-,]] - - local suite_name = code:match(suite_name_regex) - - local test_names - for test_name in code:gmatch(test_name_regex) do - test_names = test_names or {} - if test_name ~= suite_name then table.insert(test_names, test_name) end - end - - return { suite_name = suite_name, test_names = test_names } - end - - local tests = parseTestFile() - for _, test_name in ipairs(tests.test_names) do - target:add( - "tests", - tests.suite_name .. "/" .. test_name, - { group = tests.suite_name, runargs = "--test_name=" .. test_name } - ) - end - end) - - add_rules("stormkit.flags") - add_rules("platform.windows.subsystem.console") - - add_files(file) - - add_packages("frozen") - add_deps("stormkit::main", "stormkit::test") - add_deps("stormkit::" .. name) - - add_options("sanitizers") - end) - end - end - end -end)