diff --git a/.clang-format b/.clang-format index 088a0645a..f2a87339c 100644 --- a/.clang-format +++ b/.clang-format @@ -23,6 +23,8 @@ BitFieldColonSpacing: After BreakBeforeConceptDeclarations: 'true' BreakBinaryOperations: RespectPrecedence EmptyLineBeforeAccessModifier: LogicalBlock +EnumTrailingComma: Insert +FixNamespaceComments: 'true' IndentExternBlock: Indent IndentGotoLabels: 'false' IndentRequiresClause: 'true' @@ -30,6 +32,13 @@ InsertBraces: 'false' InsertTrailingCommas: Wrapped LambdaBodyIndentation: Signature PPIndentWidth: 4 +PenaltyBreakAssignment: 1000 +PenaltyReturnTypeOnItsOwnLine: 1000 +PenaltyBreakBeforeFirstCallParameter: 1000 +PenaltyBreakOpenParenthesis: 1000 +PenaltyBreakBeforeMemberAccess: 10 +PenaltyIndentedWhitespace: 1 +ContinuationIndentWidth: 2 ReferenceAlignment: Left # RemoveBracesLLVM: 'true' RequiresClausePosition: OwnLine @@ -40,9 +49,18 @@ SpaceBeforeCaseColon: 'false' AlwaysBreakAfterDefinitionReturnType: None SpaceBeforeSquareBrackets: 'false' SpaceInEmptyBlock: 'false' -AttributeMacros: [STORMKIT_FORCE_INLINE, STORMKIT_API, STORMKIT_PRIVATE, STORMKIT_PUBLIC] +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: + - STORMKIT_FORCE_INLINE=[[maybe_unused]] + - STORMKIT_API=[[maybe_unused]] + - STORMKIT_PRIVATE=[[maybe_unused]] + - STORMKIT_PUBLIC=[[maybe_unused]] + - STORMKIT_CONST=[[maybe_unused]] + - STORMKIT_PURE=[[maybe_unused]] + - STORMKIT_INTRINSIC=[[maybe_unused]] + QualifierAlignment: Custom QualifierOrder: [static, inline, volatile, restrict, constexpr, const, type] @@ -64,7 +82,6 @@ ColumnLimit: '100' CompactNamespaces: 'true' ConstructorInitializerAllOnOneLineOrOnePerLine: 'false' ConstructorInitializerIndentWidth: '4' -ContinuationIndentWidth: '4' IncludeBlocks: Preserve IndentCaseLabels: 'true' IndentWidth: '4' @@ -76,7 +93,6 @@ MaxEmptyLinesToKeep: '1' NamespaceIndentation: All ObjCSpaceAfterProperty: true ObjCSpaceBeforeProtocolList: false -PenaltyBreakAssignment: '0' PointerAlignment: Left SortIncludes: 'true' SortUsingDeclarations: 'true' @@ -91,7 +107,6 @@ SpacesInAngles: 'false' Standard: c++20 TabWidth: '4' UseTab: Never -PenaltyBreakBeforeFirstCallParameter: '120' --- Language: ObjC AlignAfterOpenBracket: Align @@ -137,8 +152,12 @@ MaxEmptyLinesToKeep: '1' NamespaceIndentation: All ObjCSpaceAfterProperty: true ObjCSpaceBeforeProtocolList: false -PenaltyBreakAssignment: '0' PointerAlignment: Right +PenaltyBreakAssignment: 1000 +PenaltyReturnTypeOnItsOwnLine: 1000 +PenaltyBreakBeforeFirstCallParameter: 1000 +PenaltyBreakOpenParenthesis: 1000 +PenaltyBreakBeforeMemberAccess: 10 SortIncludes: 'true' SortUsingDeclarations: 'true' SpaceAfterTemplateKeyword: 'false' @@ -152,7 +171,6 @@ SpacesInAngles: 'false' Standard: c++20 TabWidth: '4' UseTab: Never -PenaltyBreakBeforeFirstCallParameter: '120' PenaltyIndentedWhitespace: '1' QualifierAlignment: Custom QualifierOrder: [static, inline, volatile, restrict, constexpr, const, type] diff --git a/.github/workflows/Linux.yml b/.github/workflows/Linux.yml index 25e46f8ae..2795e78d9 100644 --- a/.github/workflows/Linux.yml +++ b/.github/workflows/Linux.yml @@ -79,6 +79,7 @@ jobs: libelf-dev libdwarf-dev mold + nasm llvm${{ env.LLVM_VERSION }} llvm${{ env.LLVM_VERSION }}-dev llvm${{ env.LLVM_VERSION }}-runtime @@ -123,7 +124,7 @@ jobs: - name: Setup XMake uses: xmake-io/github-action-setup-xmake@v1 with: - xmake-version: Arthapz/xmake#branch@improve-jobgraph-support2 + xmake-version: branch@dev actions-cache-folder: .xmake-cache - name: Cache XMake diff --git a/.github/workflows/Windows.yml b/.github/workflows/Windows.yml index 4a1748e4e..c2f9db186 100644 --- a/.github/workflows/Windows.yml +++ b/.github/workflows/Windows.yml @@ -82,7 +82,7 @@ jobs: if: ${{ !steps.restore-xmakecache.outputs.cache-hit }} uses: xmake-io/github-action-setup-xmake@v1 with: - xmake-version: Arthapz/xmake#branch@fix-cmake-clang-msstl + xmake-version: branch@dev actions-cache-folder: '.xmake-cache' - name: Cache XMake diff --git a/.github/workflows/macOS.yml b/.github/workflows/macOS.yml index 7a45e6582..5d5713d20 100644 --- a/.github/workflows/macOS.yml +++ b/.github/workflows/macOS.yml @@ -49,7 +49,7 @@ jobs: - name: Install build tools uses: tecolicom/actions-use-homebrew-tools@v1 with: - tools: llvm ninja meson mold + tools: llvm ninja meson mold nasm pkgconf verbose: true - name: Checkout @@ -78,7 +78,7 @@ jobs: - name: Setup XMake uses: xmake-io/github-action-setup-xmake@v1 with: - xmake-version: Arthapz/xmake#branch@improve-jobgraph-support2 + xmake-version: branch@dev actions-cache-folder: .xmake-cache - name: Cache XMake diff --git a/src/Gpu/Execution/CommandPool.cpp b/backup-src/execution/command_pool.cpp similarity index 90% rename from src/Gpu/Execution/CommandPool.cpp rename to backup-src/execution/command_pool.cpp index 0c38e461e..082208a8c 100644 --- a/src/Gpu/Execution/CommandPool.cpp +++ b/backup-src/execution/command_pool.cpp @@ -2,13 +2,13 @@ // This file is subject to the license terms in the LICENSE file // found in the top-level of this distribution -module stormkit.Gpu; +module stormkit.gpu; import std; import stormkit.core; -import stormkit.Gpu.Vulkan; +import stormkit.gpu.vulkan; import :Core; import :Execution.CommandBuffer; @@ -17,7 +17,7 @@ using namespace std::literals; namespace stormkit::gpu { ///////////////////////////////////// ///////////////////////////////////// - auto CommandPool::createVkCommandBuffers(const Device& device, + auto CommandPool::create_vk_command_buffers(const Device& device, RangeExtent count, CommandBufferLevel level) const noexcept -> std::vector { @@ -44,13 +44,13 @@ namespace stormkit::gpu { if (create_count > 0) { const auto allocate_info - = vk::CommandBufferAllocateInfo { .commandPool = *vkHandle(), + = vk::CommandBufferAllocateInfo { .commandPool = *native_handle(), .level = narrow(level), .commandBufferCount = as(count) }; // TODO handle error here - std::ranges::move(device.vkHandle() - .allocateCommandBuffers(allocate_info) + std::ranges::move(device.native_handle() + .allocate_command_buffers(allocate_info) .transform_error(core :.monadic::assert( std::format("Failed to allocate {} command buffers", create_count))) diff --git a/src/Gpu/Execution/Pipeline.cpp b/backup-src/execution/pipeline.cpp similarity index 92% rename from src/Gpu/Execution/Pipeline.cpp rename to backup-src/execution/pipeline.cpp index 7a40bc9b9..543fc6df9 100644 --- a/src/Gpu/Execution/Pipeline.cpp +++ b/backup-src/execution/pipeline.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 -module stormkit.Gpu; +module stormkit.gpu; import std; import stormkit.core; -import stormkit.Gpu.Vulkan; +import stormkit.gpu.vulkan; import :Core; import :Execution.Pipeline; import :Execution.RenderPass; -import :Execution.RasterPipelineState; +import execution.raster_pipeline; namespace stormkit::gpu { ///////////////////////////////////// ///////////////////////////////////// - auto Pipeline::doInitRasterPipeline(const Device& device, + auto Pipeline::do_init(const Device& device, const PipelineLayout& layout, const RenderPass& render_pass, OptionalRef pipeline_cache) noexcept @@ -68,14 +68,14 @@ namespace stormkit::gpu { | std::ranges::to(); const auto viewport_state = - vk::PipelineViewportStateCreateInfo {}.setViewports(viewports).setScissors(scissors); + vk::PipelineViewportStateCreateInfo {}.set_viewports(viewports).set_scissors(scissors); const auto rasterizer = vk::PipelineRasterizationStateCreateInfo { .depthClampEnable = state.rasterization_state.depth_clamp_enable, .rasterizerDiscardEnable = state.rasterization_state.rasterizer_discard_enable, .polygonMode = narrow(state.rasterization_state.polygon_mode), - .cullMode = toVkFlags(state.rasterization_state.cull_mode), + .cullMode = to_vkflags(state.rasterization_state.cull_mode), .frontFace = narrow(state.rasterization_state.front_face), .lineWidth = state.rasterization_state.line_width }; @@ -97,7 +97,7 @@ namespace stormkit::gpu { .srcAlphaBlendFactor = narrow(attachment.src_alpha_blend_factor), .dstAlphaBlendFactor = narrow(attachment.dst_alpha_blend_factor), .alphaBlendOp = narrow(attachment.alpha_blend_operation), - .colorWriteMask = toVkFlags(attachment.color_write_mask) + .colorWriteMask = to_vkflags(attachment.color_write_mask) }; }) | std::ranges::to(); @@ -106,7 +106,7 @@ namespace stormkit::gpu { .logicOpEnable = state.color_blend_state.logic_operation_enable, .logicOp = narrow(state.color_blend_state.logic_operation), } - .setBlendConstants({ state.color_blend_state.blend_constants[0], + .set_blend_constants({ 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] }) @@ -124,7 +124,7 @@ namespace stormkit::gpu { static constexpr auto NAME = "main"; return vk::PipelineShaderStageCreateInfo { .stage = narrow(shader->type()), - .module = toVkHandle(shader), + .module = to_vkhandle(shader), .pName = NAME }; }) @@ -149,8 +149,8 @@ namespace stormkit::gpu { .pDepthStencilState = &depth_stencil, .pColorBlendState = &color_blending, .pDynamicState = &dynamic_state, - .layout = toVkHandle(layout), - .renderPass = toVkHandle(render_pass), + .layout = to_vkhandle(layout), + .renderPass = to_vkhandle(render_pass), .subpass = 0, .basePipelineHandle = nullptr, .basePipelineIndex = -1 diff --git a/src/Gpu/Execution/PipelineCache.cpp b/backup-src/execution/pipeline_cache.cpp similarity index 83% rename from src/Gpu/Execution/PipelineCache.cpp rename to backup-src/execution/pipeline_cache.cpp index 082345269..125f8b6b4 100644 --- a/src/Gpu/Execution/PipelineCache.cpp +++ b/backup-src/execution/pipeline_cache.cpp @@ -2,7 +2,7 @@ // This file is subject to the license terms in the LICENSE file // found in the top-level of this distribution -module stormkit.Gpu; +module stormkit.gpu; import std; @@ -11,17 +11,17 @@ import stormkit.log; #include -import stormkit.Gpu.Vulkan; +import stormkit.gpu.vulkan; import :Core; import :Execution.Pipeline; namespace stormkit::gpu { - LOGGER("stormkit.Gpu") + LOGGER("stormkit.gpu") ///////////////////////////////////// ///////////////////////////////////// - auto PipelineCache::createNewPipelineCache(const Device& device) -> VulkanExpected { - const auto physical_device_infos = device.physicalDevice().info(); + auto PipelineCache::create_new_pipeline_cache(const Device& device) -> VulkanExpected { + const auto physical_device_infos = device.physical_device().info(); m_serialized.guard.magic = MAGIC; m_serialized.guard.data_size = 0u; @@ -34,7 +34,7 @@ namespace stormkit::gpu { std::ranges::copy(physical_device_infos.pipeline_cache_uuid, std::ranges::begin(m_serialized.uuid.value)); - return device.vkHandle() + return device.native_handle() .createPipelineCache({}) .transform(core :.monadic::set(m_vk_pipeline_cache)) .transform([this] noexcept -> void { @@ -44,8 +44,8 @@ namespace stormkit::gpu { ///////////////////////////////////// ///////////////////////////////////// - auto PipelineCache::readPipelineCache(const Device& device) -> VulkanExpected { - const auto physical_device_infos = device.physicalDevice().info(); + auto PipelineCache::read_pipeline_cache(const Device& device) -> VulkanExpected { + const auto physical_device_infos = device.physical_device().info(); auto stream = std::ifstream { m_path.string(), std::ios::binary }; read(stream, as_bytes(m_serialized.guard)); @@ -57,7 +57,7 @@ namespace stormkit::gpu { m_serialized.guard.magic, MAGIC); - return createNewPipelineCache(device); + return create_new_pipeline_cache(device); } if (m_serialized.infos.version != VERSION) { @@ -65,7 +65,7 @@ namespace stormkit::gpu { m_serialized.infos.version, VERSION); - return createNewPipelineCache(device); + return create_new_pipeline_cache(device); } if (m_serialized.infos.vendor_id != physical_device_infos.vendor_id) { @@ -73,7 +73,7 @@ namespace stormkit::gpu { m_serialized.infos.vendor_id, physical_device_infos.vendor_id); - return createNewPipelineCache(device); + return create_new_pipeline_cache(device); } if (m_serialized.infos.device_id != physical_device_infos.device_id) { @@ -81,7 +81,7 @@ namespace stormkit::gpu { m_serialized.infos.device_id, physical_device_infos.device_id); - return createNewPipelineCache(device); + return create_new_pipeline_cache(device); } if (!std::equal(std::cbegin(m_serialized.uuid.value), @@ -89,14 +89,14 @@ namespace stormkit::gpu { std::cbegin(physical_device_infos.pipeline_cache_uuid))) { elog("Mismatch pipeline cache device UUID"); - return createNewPipelineCache(device); + return create_new_pipeline_cache(device); } const auto data = read(stream, m_serialized.guard.data_size); const auto create_info = vk::PipelineCacheCreateInfo {}.setInitialData(data); - return device.vkHandle() + return device.native_handle() .createPipelineCache(create_info) .transform(core :.monadic::set(m_vk_pipeline_cache)) .transform([this]() noexcept -> void { @@ -107,7 +107,7 @@ namespace stormkit::gpu { ///////////////////////////////////// ///////////////////////////////////// - auto PipelineCache::saveCache() -> void { + auto PipelineCache::save_cache() -> void { auto data = m_vk_pipeline_cache->getData(); m_serialized.guard.data_size = std::size(data); m_serialized.guard.data_hash = 0u; diff --git a/src/Gpu/Execution/RenderPass.cpp b/backup-src/execution/render_pass.cpp similarity index 93% rename from src/Gpu/Execution/RenderPass.cpp rename to backup-src/execution/render_pass.cpp index 311717dc6..815bc541c 100644 --- a/src/Gpu/Execution/RenderPass.cpp +++ b/backup-src/execution/render_pass.cpp @@ -2,7 +2,7 @@ // This file is subject to the license terms in the LICENSE file // found in the top-level of this distribution -module stormkit.Gpu; +module stormkit.gpu; import std; @@ -10,7 +10,7 @@ import stormkit.core; import :Execution.RenderPass; -import stormkit.Gpu.Vulkan; +import stormkit.gpu.vulkan; import :Core; import :Execution.RenderPass; @@ -27,7 +27,7 @@ namespace stormkit::gpu { ///////////////////////////////////// ///////////////////////////////////// - auto RenderPass::doInitRenderPass(const Device& device) noexcept -> VulkanExpected { + auto RenderPass::do_initRenderPass(const Device& device) noexcept -> VulkanExpected { const auto attachments = m_description.attachments | std::views::transform([](auto&& attachment) { @@ -93,7 +93,7 @@ namespace stormkit::gpu { .setSubpasses(subpasses) .setDependencies(subpasses_deps); - return device.vkHandle() + return device.native_handle() .createRenderPass(create_info) .transform(core :.monadic::set(m_vk_render_pass)); } @@ -102,7 +102,7 @@ namespace stormkit::gpu { ///////////////////////////////////// // TODO finish this auto - RenderPassDescription::isCompatible(const RenderPassDescription& description) const noexcept + RenderPassDescription::is_compatible(const RenderPassDescription& description) const noexcept -> bool { if (std::size(subpasses) == std::size(description.subpasses)) return false; diff --git a/backup-src/resource/buffer.cpp b/backup-src/resource/buffer.cpp new file mode 100644 index 000000000..3ee8064ad --- /dev/null +++ b/backup-src/resource/buffer.cpp @@ -0,0 +1,69 @@ +// 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 stormkit.gpu; + +import std; + +import stormkit.core; + +import :core; +import stormkit.gpu.vulkan; + +import :resource.buffer; + +namespace stormkit::gpu { + ///////////////////////////////////// + ///////////////////////////////////// + auto Buffer::do_init() noexcept -> Expected { + const auto create_info = VkBufferCreateInfo { + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .size = m_size, + .usage = to_vkflags(m_usages), + .sharingMode = VK_SHARING_MODE_EXCLUSIVE + }; + return vk_call(vkCreateBuffer, m_vk_device, &create_info, nullptr) + .transform(core::monadic::set(m_vk_handle)) + .transform([this, &info, &device]() noexcept -> VulkanExpected { + const auto requirements = vk_call(m_vk_device, m_vk_handle); + + const auto allocate_info = VmaAllocationCreateInfo { + .requiredFlags = to_vkflags(info.property) + }; + + auto&& allocator = device.vmaAllocator(); + + auto&& [error, vma_allocation] = allocator + .allocateMemoryUnique(requirements, allocate_info); + if (error != vk::Result::eSuccess) + return std::unexpected { narrow(error) }; + + m_vma_allocation = std::move(vma_allocation); + + error = allocator.bindBufferMemory(*m_vma_allocation, *m_vk_buffer.get()); + if (error != vk::Result::eSuccess) + return std::unexpected { narrow(error) }; + + if (m_is_persistently_mapped) auto _ = map(device, 0u); + + return {}; + }) + .transform_error(monadic::from_vkflags()); + } + + ///////////////////////////////////// + ///////////////////////////////////// + auto Buffer::find_memory_type(UInt type_filter, + vk::MemoryPropertyFlags properties, + const vk::PhysicalDeviceMemoryProperties& mem_properties, + const vk::MemoryRequirements&) -> UInt { + for (auto i : range(mem_properties.memoryTypeCount)) { + if ((type_filter & (1 << i)) + and (check_flag_bit(mem_properties.memoryTypes[i].propertyFlags, properties))) + return i; + } + + return 0; + } +} // namespace stormkit::gpu diff --git a/src/Gpu/Resource/Image.cpp b/backup-src/resource/image.cpp similarity index 96% rename from src/Gpu/Resource/Image.cpp rename to backup-src/resource/image.cpp index 35ca1dd91..7109feb50 100644 --- a/src/Gpu/Resource/Image.cpp +++ b/backup-src/resource/image.cpp @@ -2,17 +2,17 @@ // This file is subject to the license terms in the LICENSE file // found in the top-level of this distribution -module stormkit.Gpu; +module stormkit.gpu; import std; import stormkit.core; import stormkit.image; -import :Core; -import stormkit.Gpu.Vulkan; +import :core; +import stormkit.gpu.vulkan; -import :Resource.Image; +import :resource.image; // #include diff --git a/backup-src/resource/shader.cpp b/backup-src/resource/shader.cpp new file mode 100644 index 000000000..34079a2a4 --- /dev/null +++ b/backup-src/resource/shader.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 stormkit.gpu; + +import std; + +import stormkit.core; + +import :core; +import stormkit.gpu.vulkan; + +import :resource.shader; + +namespace stormkit::gpu { + ///////////////////////////////////// + ///////////////////////////////////// + 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 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(); + } +} // namespace stormkit::gpu diff --git a/src/Gpu/Resource/Swapchain.cpp b/backup-src/resource/swapchain.cpp similarity index 61% rename from src/Gpu/Resource/Swapchain.cpp rename to backup-src/resource/swapchain.cpp index 00f413866..68767b183 100644 --- a/src/Gpu/Resource/Swapchain.cpp +++ b/backup-src/resource/swapchain.cpp @@ -1,20 +1,20 @@ -module stormkit.Gpu; +module stormkit.gpu; import std; import stormkit.core; -import stormkit.Gpu.Vulkan; +import stormkit.gpu.vulkan; -import :Core; -import :Resource.Swapchain; +import :core; +import :resource.swapchain; namespace stormkit::gpu { namespace { ///////////////////////////////////// ///////////////////////////////////// auto chooseSwapSurfaceFormat(std::span formats) noexcept - -> vk::SurfaceFormatKHR { + -> vk::SurfaceFormatKHR { for (const auto& format : formats) { if (format.format == vk::format::eB8G8R8A8Unorm && format.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) @@ -27,7 +27,7 @@ namespace stormkit::gpu { ///////////////////////////////////// ///////////////////////////////////// auto chooseSwapPresentMode(std::span present_modes) noexcept - -> vk::PresentModeKHR { + -> vk::PresentModeKHR { auto present_mode_ = vk::PresentModeKHR::eFifo; for (const auto& present_mode : present_modes) { @@ -49,13 +49,13 @@ namespace stormkit::gpu { && capabilities.currentExtent.height != int_max) return capabilities.currentExtent; - auto actual_extent = as(extent); - actual_extent.width - = std::max(capabilities.minImageExtent.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)); + auto actual_extent = as(extent); + actual_extent.width = std::max(capabilities.minImageExtent.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)); return actual_extent; } @@ -79,12 +79,12 @@ namespace stormkit::gpu { const Surface& surface, const math::ExtentU& extent, std::optional old_swapchain) { - const auto& physical_device = device.physicalDevice(); - const auto capabilities - = physical_device.vkHandle().getSurfaceCapabilitiesKHR(*surface.vkHandle()); - const auto formats = physical_device.vkHandle().getSurfaceFormatsKHR(*(surface.vkHandle())); - const auto present_modes - = physical_device.vkHandle().getSurfacePresentModesKHR(*(surface.vkHandle())); + const auto& physical_device = device.physical_device(); + const auto capabilities = physical_device.native_handle() + .getSurfaceCapabilitiesKHR(*surface.native_handle()); + const auto formats = physical_device.native_handle().getSurfaceFormatsKHR(*(surface.native_handle())); + const auto present_modes = physical_device.native_handle() + .getSurfacePresentModesKHR(*(surface.native_handle())); const auto format = chooseSwapSurfaceFormat(formats); const auto present_mode = chooseSwapPresentMode(present_modes); @@ -93,29 +93,29 @@ namespace stormkit::gpu { const auto image_sharing_mode = vk::SharingMode::eExclusive; const auto create_info = [&] noexcept -> decltype(auto) { - auto info - = vk::SwapchainCreateInfoKHR { .surface = *surface.vkHandle(), - .minImageCount = image_count, - .imageFormat = format.format, - .imageColorSpace = format.colorSpace, - .imageExtent = swapchain_extent, - .imageArrayLayers = 1, - .imageUsage = vk::ImageUsageFlagBits::eTransferDst, - .imageSharingMode = image_sharing_mode, - .preTransform = capabilities.currentTransform, - .compositeAlpha - = vk::CompositeAlphaFlagBitsKHR::eOpaque, - .presentMode = present_mode, - .clipped = true }; + auto info = vk::SwapchainCreateInfoKHR { + .surface = *surface.native_handle(), + .minImageCount = image_count, + .imageFormat = format.format, + .imageColorSpace = format.colorSpace, + .imageExtent = swapchain_extent, + .imageArrayLayers = 1, + .imageUsage = vk::ImageUsageFlagBits::eTransferDst, + .imageSharingMode = image_sharing_mode, + .preTransform = capabilities.currentTransform, + .compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eOpaque, + .presentMode = present_mode, + .clipped = true + }; if (old_swapchain) info.oldSwapchain = **old_swapchain; return info; }(); - device.vkHandle() - .createSwapchainKHR(create_info) - .transform(core :.monadic::set(m_vk_swapchain)) - .transform_error(core :.monadic::map(core :.monadic::narrow(), - core :.monadic::throw_as_exception())); + device.native_handle() + .createSwapchainKHR(create_info) + .transform(core :.monadic::set(m_vk_swapchain)) + .transform_error(core :.monadic::map(core :.monadic::narrow(), + core :.monadic::throw_as_exception())); m_extent = as(swapchain_extent); m_image_count = as(std::size(m_images)); @@ -131,11 +131,11 @@ namespace stormkit::gpu { ///////////////////////////////////// ///////////////////////////////////// - auto Swapchain::acquireNextImage(std::chrono::nanoseconds wait, + auto Swapchain::acquire_next_image(std::chrono::nanoseconds wait, const Semaphore& image_available) const noexcept - -> Expected> { - auto&& [result, index] - = m_vk_swapchain->acquireNextImage(wait.count(), toVkHandle(image_available)); + -> Expected> { + auto&& [result, index] = m_vk_swapchain + ->acquire_next_image(wait.count(), to_vkhandle(image_available)); const auto possible_results = std::array { vk::Result::eSuccess, vk::Result::eErrorOutOfDateKHR, vk::Result::eSuboptimalKHR }; diff --git a/examples/engine/sprites/src/SpritesApp.mpp b/examples/engine/sprites/src/SpritesApp.mpp index 4113796ce..183aaa2ff 100644 --- a/examples/engine/sprites/src/SpritesApp.mpp +++ b/examples/engine/sprites/src/SpritesApp.mpp @@ -7,7 +7,7 @@ export module SpritesApp; import std; import stormkit.core; -import stormkit.Gpu; +import stormkit.gpu; import stormkit.Engine; import stormkit.wsi; @@ -50,7 +50,7 @@ auto SpritesApp::run(std::span _) -> Int { auto& render_system = world.add_system(renderer, window.extent()); m_application->setUpdateFrameGraphCallback( - bindFront(&engine::SpriteRenderSystem::updateFrameGraph, &render_system)); + bind_front(&engine::SpriteRenderSystem::updateFrameGraph, &render_system)); engine::makeSprite(world, { 32.f, 32.f }); diff --git a/examples/engine/sprites/xmake.lua b/examples/engine/sprites/xmake.lua index 5ad04b0db..21061fc2f 100644 --- a/examples/engine/sprites/xmake.lua +++ b/examples/engine/sprites/xmake.lua @@ -15,8 +15,6 @@ do add_defines("STORMKIT_ASSERT=0") end - if is_plat("windows") then add_ldflags("-Wl,/SUBSYSTEM:CONSOLE", { force = true }) end - add_files("src/*.cpp") add_files("src/*.mpp") add_files("shaders/*.nzsl") diff --git a/examples/engine/triangle/src/TriangleApp.mpp b/examples/engine/triangle/src/TriangleApp.mpp index 1ec3b0a9d..49808def9 100644 --- a/examples/engine/triangle/src/TriangleApp.mpp +++ b/examples/engine/triangle/src/TriangleApp.mpp @@ -7,7 +7,7 @@ export module TriangleApp; import std; import stormkit.core; -import stormkit.Gpu; +import stormkit.gpu; import stormkit.Engine; import stormkit.wsi; @@ -49,7 +49,7 @@ auto TriangleApp::run(std::span _) -> Int { m_application = engine::Application::create(APPLICATION_NAME, { 800u, 600u }, WINDOW_TITLE) .transform_error(assert("Failed to initialize Render engine")) .value(); - m_application->setUpdateFrameGraphCallback(bindFront(&TriangleApp::updateFrameGraph, this)); + m_application->setUpdateFrameGraphCallback(bind_front(&TriangleApp::updateFrameGraph, this)); auto& window = m_application->window(); auto& event_handler = m_application->eventHandler(); @@ -59,12 +59,12 @@ auto TriangleApp::run(std::span _) -> Int { m_window_extent = window.extent(); m_vertex_shader - = gpu::Shader::fromBytes(renderer.device(), SHADER_DATA, gpu::ShaderStageFlag::Vertex) + = gpu::Shader::load_from_bytes(renderer.device(), SHADER_DATA, gpu::ShaderStageFlag::Vertex) .transform_error(assert("Failed to load vertex shader")) .value(); m_fragment_shader - = gpu::Shader::fromBytes(renderer.device(), SHADER_DATA, gpu::ShaderStageFlag::Fragment) + = gpu::Shader::load_from_bytes(renderer.device(), SHADER_DATA, gpu::ShaderStageFlag::Fragment) .transform_error(assert("Failed to load fragment shader")) .value(); @@ -139,7 +139,7 @@ auto TriangleApp::updateFrameGraph(engine::FrameGraphBuilder& graph, .value(); } - cmb.bindPipeline(m_pipeline); + cmb.bind_pipeline(m_pipeline); cmb.draw(3); }); diff --git a/examples/engine/triangle/xmake.lua b/examples/engine/triangle/xmake.lua index b85777ef0..2a45c2f79 100644 --- a/examples/engine/triangle/xmake.lua +++ b/examples/engine/triangle/xmake.lua @@ -17,8 +17,6 @@ do add_defines("STORMKIT_ASSERT=0") end - if is_plat("windows") then add_ldflags("-Wl,/SUBSYSTEM:CONSOLE", { force = true }) end - add_files("src/*.cpp") add_files("src/*.mpp") add_files("shaders/*.nzsl") diff --git a/examples/entities/gameoflife/src/App.cpp b/examples/entities/gameoflife/src/App.cpp index b8497edd8..34d036572 100644 --- a/examples/entities/gameoflife/src/App.cpp +++ b/examples/entities/gameoflife/src/App.cpp @@ -1,7 +1,7 @@ #ifdef STORMKIT_BUILD_MODULES module App; -import stormkit.Gpu; +import stormkit.gpu; import Components; import Systems; @@ -30,7 +30,7 @@ auto App::run([[maybe_unused]] const int argc, [[maybe_unused]] const char** arg using namespace stormkit::literals; - doInitWindow(); + do_initWindow(); m_board = image::Image { { BOARD_SIZE, BOARD_SIZE }, @@ -80,7 +80,7 @@ auto App::run([[maybe_unused]] const int argc, [[maybe_unused]] const char** arg return EXIT_SUCCESS; } -auto App::doInitWindow() -> void { +auto App::do_initWindow() -> void { const auto window_style = wsi::WindowStyle::ALL; m_window = allocate(WINDOW_TITLE, math::ExtentU { 800u, 600u }, window_style); diff --git a/examples/entities/gameoflife/src/App.mpp b/examples/entities/gameoflife/src/App.mpp index 5bf3417d9..5d8d1e65c 100644 --- a/examples/entities/gameoflife/src/App.mpp +++ b/examples/entities/gameoflife/src/App.mpp @@ -34,7 +34,7 @@ export { auto run(const int argc, const char** argv) -> stormkit::Int32 override; private: - auto doInitWindow() -> void; + auto do_initWindow() -> void; auto handleKeyboard(const stormkit::wsi::KeyReleasedEventData& event) -> void; auto handleMouse(const stormkit::wsi::MouseButtonPushedEventData& event) -> void; diff --git a/examples/entities/gameoflife/src/Constants.mpp b/examples/entities/gameoflife/src/Constants.mpp index 4e9b5e978..96660864c 100644 --- a/examples/entities/gameoflife/src/Constants.mpp +++ b/examples/entities/gameoflife/src/Constants.mpp @@ -9,7 +9,7 @@ import std; import stormkit.core; import stormkit.log; -import stormkit.Gpu; +import stormkit.gpu; export { #else diff --git a/examples/entities/gameoflife/src/Renderer.cpp b/examples/entities/gameoflife/src/Renderer.cpp index b11d5ff17..27b849145 100644 --- a/examples/entities/gameoflife/src/Renderer.cpp +++ b/examples/entities/gameoflife/src/Renderer.cpp @@ -14,12 +14,12 @@ import Constants; using namespace stormkit; Renderer::Renderer(const wsi::Window& window) : m_window { &window } { - doInitBaseRenderObjects(); - doInitMeshRenderObjects(); + do_initBaseRenderObjects(); + do_initMeshRenderObjects(); } Renderer::~Renderer() { - m_device->waitIdle(); + m_device->wait_idle(); } Renderer::Renderer(Renderer&&) noexcept = default; @@ -32,7 +32,7 @@ auto Renderer::renderFrame() -> void { if (m_surface->needRecreate()) { m_surface->recreate(); - doInitPerFrameObjects(); + do_initPerFrameObjects(); } const auto viewports = [&] { @@ -65,15 +65,15 @@ auto Renderer::renderFrame() -> void { commandbuffer.reset(); commandbuffer.begin(); - commandbuffer.beginRenderPass(*m_render_pass, framebuffer); + commandbuffer.begin_render_pass(*m_render_pass, framebuffer); commandbuffer.bindRasterPipeline(*m_board.pipeline); - commandbuffer.setViewport(0, viewports); - commandbuffer.setScissor(0, scissors); - commandbuffer.bindDescriptorSets(*m_board.pipeline, sets, {}); + commandbuffer.set_viewport(0, viewports); + commandbuffer.set_scissor(0, scissors); + commandbuffer.bind_descriptor_sets(*m_board.pipeline, sets, {}); commandbuffer.draw(4); - commandbuffer.endRenderPass(); + commandbuffer.end_render_pass(); commandbuffer.end(); commandbuffer.submit(wait, signal, frame.in_flight); @@ -99,7 +99,7 @@ auto Renderer::updateBoard(const stormkit::image::Image& board) -> void { m_board.descriptor_set->update(descriptors); } -auto Renderer::doInitBaseRenderObjects() -> void { +auto Renderer::do_initBaseRenderObjects() -> void { // We create an instance and initialize device on best available GPU m_instance = allocate(); ilog("Render backend successfully initialized"); @@ -112,9 +112,9 @@ auto Renderer::doInitBaseRenderObjects() -> void { STORMKIT_COMPILER); ilog("--------- Physical Devices ----------"); - for (const auto& device : m_instance->physicalDevices()) ilog("{}", device.info()); + for (const auto& device : m_instance->physical_devices()) ilog("{}", device.info()); - auto surface = m_instance->allocateWindowSurface(*m_window); + auto surface = m_instance->allocate_window_surface(*m_window); const auto& physical_device = m_instance->pickPhysicalDevice(*surface); @@ -131,10 +131,10 @@ auto Renderer::doInitBaseRenderObjects() -> void { m_surface->initialize(*m_device); m_queue = makeConstObserver(m_device->graphicsQueue()); - m_command_buffers = m_queue->createCommandBuffers(m_surface->bufferingCount()); + m_command_buffers = m_queue->create_command_buffers(m_surface->bufferingCount()); } -auto Renderer::doInitMeshRenderObjects() -> void { +auto Renderer::do_initMeshRenderObjects() -> void { const auto& surface_extent = m_surface->extent(); const auto surface_extentf = math::ExtentF { surface_extent }; @@ -207,10 +207,10 @@ auto Renderer::doInitMeshRenderObjects() -> void { m_board.descriptor_set = m_descriptor_pool->allocateDescriptorSet(*m_descriptor_set_layout); - doInitPerFrameObjects(); + do_initPerFrameObjects(); } -auto Renderer::doInitPerFrameObjects() -> void { +auto Renderer::do_initPerFrameObjects() -> void { const auto& surface_extent = m_surface->extent(); const auto surface_extentf = math::ExtentF { surface_extent }; const auto buffering_count = m_surface->bufferingCount(); diff --git a/examples/entities/gameoflife/src/Renderer.mpp b/examples/entities/gameoflife/src/Renderer.mpp index 0aab4a676..82433cdf3 100644 --- a/examples/entities/gameoflife/src/Renderer.mpp +++ b/examples/entities/gameoflife/src/Renderer.mpp @@ -7,7 +7,7 @@ import std; import stormkit.core; import stormkit.wsi; -import stormkit.Gpu; +import stormkit.gpu; export { #else @@ -34,9 +34,9 @@ export { auto updateBoard(const stormkit::image::Image& board) -> void; private: - auto doInitBaseRenderObjects() -> void; - auto doInitMeshRenderObjects() -> void; - auto doInitPerFrameObjects() -> void; + auto do_initBaseRenderObjects() -> void; + auto do_initMeshRenderObjects() -> void; + auto do_initPerFrameObjects() -> void; const stormkit::wsi::Window* m_window = nullptr; diff --git a/examples/entities/gameoflife/xmake.lua b/examples/entities/gameoflife/xmake.lua index 2fe86335b..3858a512e 100644 --- a/examples/entities/gameoflife/xmake.lua +++ b/examples/entities/gameoflife/xmake.lua @@ -22,7 +22,7 @@ if has_config("enable_gpu") and has_config("enable_wsi") and has_config("enable- add_files("shaders/*.nzsl") if is_plat("windows") then add_files("win32/*.manifest") end - add_rules("windows.subsystem.windows") + add_rules("platform.windows.subsystem.windows") set_group("examples/stormkit-entities") end diff --git a/examples/gpu/triangle/iOS/Info.plist b/examples/gpu/triangle/iOS/Info.plist new file mode 100644 index 000000000..a62a3592d --- /dev/null +++ b/examples/gpu/triangle/iOS/Info.plist @@ -0,0 +1,46 @@ + + + + + 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 new file mode 100644 index 000000000..436820912 --- /dev/null +++ b/examples/gpu/triangle/iOS/LaunchScreen.storyboard @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/gpu/triangle/macOS/Info.plist b/examples/gpu/triangle/macOS/Info.plist new file mode 100644 index 000000000..f68f66070 --- /dev/null +++ b/examples/gpu/triangle/macOS/Info.plist @@ -0,0 +1,36 @@ + + + + + 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/src/main.cpp b/examples/gpu/triangle/src/main.cpp new file mode 100644 index 000000000..fad961de7 --- /dev/null +++ b/examples/gpu/triangle/src/main.cpp @@ -0,0 +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 + +import std; + +import stormkit.core; +import stormkit.log; +import stormkit.wsi; +import stormkit.gpu; + +#include +#include + +LOGGER("StormKit.Examples.Log.EventHandler"); + +auto main(std::span args) -> int { + using namespace stormkit; + using namespace std::literals; + + wsi::parse_args(args); + + // initialize logger + auto logger_singleton = log::Logger::create_logger_instance(); + + const auto monitors = wsi::Window::get_monitor_settings(); + ilog("--- Monitors ---"); + ilog("{}", monitors); + + // initialize WSI + auto window = wsi::Window { + "Hello world", + { 800u, 600u }, + wsi::WindowStyle::ALL + }; + + auto fullscreen = false; + auto toggle_fullscreen = false; + + auto event_handler = wsi::EventHandler {}; + event_handler.set_callbacks({ + { wsi::EventType::CLOSED, [&](const wsi::Event&) { window.close(); } }, + }); + + // initialize gpu + gpu::initialize_backend(); + + auto instance = *gpu::Instance::create("Triangle") + .transform_error(core::monadic::assert("Failed to initialize gpu instance")); + auto surface = *gpu::Surface::create_from_window(instance, window) + .transform_error(core::monadic:: + assert("Failed to initialize window gpu surface")); + + const auto& physical_devices = instance.physical_devices(); + if (std::ranges::empty(physical_devices)) { + std::println("No render physical device found!"); + return 0; + } + std::println("Physical devices: {}", physical_devices); + + auto physical_device = as_ref(physical_devices.front()); + auto score = gpu::score_physical_device(physical_device); + for (auto i = 1u; i < std::ranges::size(physical_devices); ++i) { + const auto& d = physical_devices[i]; + const auto d_score = gpu::score_physical_device(d); + if (d_score > score) { + physical_device = as_ref(d); + score = d_score; + } + } + + auto device = *gpu::Device::create(*physical_device, instance) + .transform_error(core::monadic::assert("Failed to initialize gpu device")); + + while (window.is_open()) { + event_handler.update(window); + + LOG_MODULE.flush(); + + if (toggle_fullscreen) { + fullscreen = !fullscreen; + window.toggle_fullscreen(fullscreen); + + toggle_fullscreen = false; + ilog("Toggle fullscreen to: {}", fullscreen); + } + } + + return 0; +} diff --git a/examples/gpu/triangle/win32/manifest.manifest b/examples/gpu/triangle/win32/manifest.manifest new file mode 100644 index 000000000..4a9b5f6a6 --- /dev/null +++ b/examples/gpu/triangle/win32/manifest.manifest @@ -0,0 +1,9 @@ + + + + + true + PerMonitorV2 + + + diff --git a/examples/gpu/triangle/xmake.lua b/examples/gpu/triangle/xmake.lua new file mode 100644 index 000000000..b4b197cbd --- /dev/null +++ b/examples/gpu/triangle/xmake.lua @@ -0,0 +1,22 @@ +target("triangle", function() + set_kind("binary") + set_languages("cxxlatest", "clatest") + + add_rules("stormkit.flags") + add_rules("platform.windows.subsystem.windows") + + add_deps("stormkit-core", "stormkit-main", "stormkit-log", "stormkit-wsi", "stormkit-gpu") + + 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 + + set_group("examples/stormkit-gpu") +end) diff --git a/examples/log/console-logger/xmake.lua b/examples/log/console-logger/xmake.lua index ac35f8bd9..a6f0033bc 100644 --- a/examples/log/console-logger/xmake.lua +++ b/examples/log/console-logger/xmake.lua @@ -4,7 +4,7 @@ do set_languages("cxxlatest", "clatest") add_rules("stormkit.flags") - add_rules("windows.subsystem.console") + add_rules("platform.windows.subsystem.console") add_deps("stormkit-core", "stormkit-main", "stormkit-log") @@ -18,10 +18,5 @@ do add_files("src/main.cpp") - if has_config("mold") then - add_ldflags("-Wl,-fuse-ld=mold") - add_shflags("-Wl,-fuse-ld=mold") - end - set_group("examples/stormkit-log") end diff --git a/examples/log/file-logger/xmake.lua b/examples/log/file-logger/xmake.lua index 789710c2a..12a4092a5 100644 --- a/examples/log/file-logger/xmake.lua +++ b/examples/log/file-logger/xmake.lua @@ -4,7 +4,7 @@ do set_languages("cxxlatest", "clatest") add_rules("stormkit.flags") - add_rules("windows.subsystem.console") + add_rules("platform.windows.subsystem.console") add_deps("stormkit-core", "stormkit-main", "stormkit-log") @@ -18,10 +18,5 @@ do add_files("src/main.cpp") - if has_config("mold") then - add_ldflags("-Wl,-fuse-ld=mold") - add_shflags("-Wl,-fuse-ld=mold") - end - set_group("examples/stormkit-log") end diff --git a/examples/wsi/event_handler/xmake.lua b/examples/wsi/event_handler/xmake.lua index 2fe03ecae..a2a50953d 100644 --- a/examples/wsi/event_handler/xmake.lua +++ b/examples/wsi/event_handler/xmake.lua @@ -3,7 +3,7 @@ target("event_handler", function() set_languages("cxxlatest", "clatest") add_rules("stormkit.flags") - add_rules("windows.subsystem.windows") + add_rules("platform.windows.subsystem.windows") add_deps("stormkit-core", "stormkit-main", "stormkit-log", "stormkit-wsi") @@ -18,10 +18,5 @@ target("event_handler", function() add_files("src/main.cpp") if is_plat("windows") then add_files("win32/*.manifest") end - if has_config("mold") then - add_ldflags("-Wl,-fuse-ld=mold") - add_shflags("-Wl,-fuse-ld=mold") - end - set_group("examples/stormkit-wsi") end) diff --git a/examples/wsi/polling/xmake.lua b/examples/wsi/polling/xmake.lua index 04bbff275..ed8bf768e 100644 --- a/examples/wsi/polling/xmake.lua +++ b/examples/wsi/polling/xmake.lua @@ -3,7 +3,7 @@ target("polling", function() set_languages("cxxlatest", "clatest") add_rules("stormkit.flags") - add_rules("windows.subsystem.windows") + add_rules("platform.windows.subsystem.windows") add_deps("stormkit-core", "stormkit-main", "stormkit-log", "stormkit-wsi") @@ -18,10 +18,5 @@ target("polling", function() add_files("src/main.cpp") if is_plat("windows") then add_files("win32/*.manifest") end - if has_config("mold") then - add_ldflags("-Wl,-fuse-ld=mold") - add_shflags("-Wl,-fuse-ld=mold") - end - set_group("examples/stormkit-wsi") end) diff --git a/include/stormkit/core/memory_macro.hpp b/include/stormkit/core/memory_macro.hpp index c8e508569..f345cc982 100644 --- a/include/stormkit/core/memory_macro.hpp +++ b/include/stormkit/core/memory_macro.hpp @@ -13,13 +13,13 @@ #define SINGLE_ARG(...) __VA_ARGS__ -#define ALLOCATE_HELPERS(T) \ - template \ - [[nodiscard]] \ - static inline auto allocate(Args&&... args) { \ - return allocate(std::forward(args)...) \ - .transform_error(stormkit::core :.monadic::assert()) \ - .value(); \ +#define ALLOCATE_HELPERS(T) \ + template \ + [[nodiscard]] \ + static inline auto allocate(Args&&... args) { \ + return allocate(std::forward(args)...) \ + .transform_error(stormkit::core :.monadic::assert()) \ + .value(); \ } /// \exclude @@ -59,7 +59,10 @@ /// \brief Add padding to a struct or a class /// \param size The size of the padding -#define PADDING(size) stormkit::Byte private____padding[size]; +#define PADDING(size) \ + stormkit::Byte _[size] = { \ + stormkit::Byte { 0 }, \ + } /// \exclude #define STORMKIT_UNUSED(x) (void)(x); diff --git a/include/stormkit/core/platform_macro.hpp b/include/stormkit/core/platform_macro.hpp index 8d4e0f558..a34cbcc58 100644 --- a/include/stormkit/core/platform_macro.hpp +++ b/include/stormkit/core/platform_macro.hpp @@ -27,7 +27,8 @@ #define STORMKIT_IMPORT __declspec(dllimport) #define STORMKIT_RESTRICT __restrict #define STORMKIT_PRIVATE - #define STORMKIT_FORCE_INLINE_IMPL __forceinline + #define STORMKIT_FORCE_INLINE_IMPL [[msvc::forceinline]] + #define STORMKIT_INTRINSIC [[msvc::intrinsic]] #elif defined(_MSC_VER) and defined(__clang__) #if defined(_LIBCPP_VERSION) #define STORMKIT_COMPILER_LIBCPP "libc++" @@ -40,7 +41,8 @@ #define STORMKIT_IMPORT __declspec(dllimport) #define STORMKIT_PRIVATE [[gnu::visibility("hidden")]] #define STORMKIT_RESTRICT __restrict - #define STORMKIT_FORCE_INLINE_IMPL [[gnu::always_inline]] inline + #define STORMKIT_FORCE_INLINE_IMPL [[gnu::always_inline]] + #define STORMKIT_INTRINSIC #elif defined(__MINGW32__) #if defined(_LIBCPP_VERSION) #define STORMKIT_COMPILER_LIBCPP "libc++" @@ -52,8 +54,9 @@ #define STORMKIT_EXPORT __declspec(dllexport) #define STORMKIT_IMPORT __declspec(dllimport) #define STORMKIT_PRIVATE - #define STORMKIT_RESTRICT __restrict inline - #define STORMKIT_FORCE_INLINE_IMPL [[gnu::always_inline]] inline + #define STORMKIT_RESTRICT __restrict + #define STORMKIT_FORCE_INLINE_IMPL [[gnu::always_inline]] + #define STORMKIT_INTRINSIC #else #if defined(_LIBCPP_VERSION) #define STORMKIT_COMPILER_LIBCPP "libc++" @@ -66,7 +69,8 @@ #define STORMKIT_EXPORT [[gnu::visibility("default")]] #define STORMKIT_PRIVATE [[gnu::visibility("hidden")]] #define STORMKIT_RESTRICT __restrict - #define STORMKIT_FORCE_INLINE_IMPL [[gnu::always_inline]] inline + #define STORMKIT_FORCE_INLINE_IMPL [[gnu::always_inline]] + #define STORMKIT_INTRINSIC #endif #if __has_cpp_attribute(lifetimebound) @@ -79,6 +83,18 @@ #define STORMKIT_LIFETIMEBOUND #endif +#if __has_cpp_attribute(gnu::pure) + #define STORMKIT_PURE [[gnu::pure]] +#else + #define STORMKIT_PURE +#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(__MINGW32__) @@ -87,14 +103,14 @@ #define STORMKIT_COMPILER_CLANG std::string { "MinGW Clang " } + __clang_version__ #define STORMKIT_COMPILER STORMKIT_COMPILER_CLANG #elif defined(__GNUC__) or defined(__GNUG__) - #define STORMKIT_COMPILER_GCC \ - "MinGW GCC " \ - + std::to_string(__GNUC__) \ - + "." \ - + std::to_string(__GNUC_MINOR__) \ - + "." \ - + "." \ - + std::to_string(__GNUC_PATCHLEVEL__) + #define STORMKIT_COMPILER_GCC \ + "MinGW GCC " \ + + std::to_string(__GNUC__) \ + + "." \ + + std::to_string(__GNUC_MINOR__) \ + + "." \ + + "." \ + + std::to_string(__GNUC_PATCHLEVEL__) #define STORMKIT_COMPILER_MINGW STORMKIT_COMPILER_GCC #endif #define STORMKIT_COMPILER_MINGW STORMKIT_COMPILER @@ -102,14 +118,14 @@ #define STORMKIT_COMPILER_CLANG std::string { "Clang " } + __clang_version__ #define STORMKIT_COMPILER STORMKIT_COMPILER_CLANG #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_GCC \ + "GCC " \ + + std::to_string(__GNUC__) \ + + "." \ + + std::to_string(__GNUC_MINOR__) \ + + "." \ + + "." \ + + std::to_string(__GNUC_PATCHLEVEL__) #define STORMKIT_COMPILER STORMKIT_COMPILER_GCC #endif @@ -163,16 +179,10 @@ extern "C" { #error "Targeted platform not supported !" #endif -#ifndef STORMKIT_STATIC - #ifdef STORMKIT_BUILD - #define STORMKIT_API STORMKIT_EXPORT - #else - #define STORMKIT_API STORMKIT_IMPORT - #endif -// #define STORMKIT_API STORMKIT_EXPORT +#ifdef STORMKIT_BUILD + #define STORMKIT_API STORMKIT_EXPORT #else - #define STORMKIT_PUBLIC - #define STORMKIT_API + #define STORMKIT_API STORMKIT_IMPORT #endif #ifdef _POSIX_VERSION diff --git a/include/stormkit/Gpu/Core/VulkanMacro.hpp b/include/stormkit/gpu/core/vulkan_macro.hpp similarity index 100% rename from include/stormkit/Gpu/Core/VulkanMacro.hpp rename to include/stormkit/gpu/core/vulkan_macro.hpp diff --git a/include/stormkit/log/log_macro.hpp b/include/stormkit/log/log_macro.hpp index 313dcc55a..a35ec637a 100644 --- a/include/stormkit/log/log_macro.hpp +++ b/include/stormkit/log/log_macro.hpp @@ -5,58 +5,60 @@ #ifndef STORMKIT_LOG_MACRO_HPP #define STORMKIT_LOG_MACRO_HPP +#include + #define NAMED_LOGGER(NAME, module_chars) \ namespace { \ constexpr auto NAME = stormkit::log::Module { module_chars }; \ } -#define LOGGER(module) \ - NAMED_LOGGER(LOG_MODULE, module) \ - template \ - auto dlog(Args&&... args) -> void { \ - LOG_MODULE.dlog(std::forward(args)...); \ - } \ - template \ - auto ilog(Args&&... args) -> void { \ - LOG_MODULE.ilog(std::forward(args)...); \ - } \ - template \ - auto wlog(Args&&... args) -> void { \ - LOG_MODULE.wlog(std::forward(args)...); \ - } \ - template \ - auto elog(Args&&... args) -> void { \ - LOG_MODULE.elog(std::forward(args)...); \ - } \ - template \ - auto flog(Args&&... args) -> void { \ - LOG_MODULE.flog(std::forward(args)...); \ +#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 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 \ - auto dlog(Args&&... args) -> void { \ - LOG_MODULE.dlog(std::forward(args)...); \ - } \ - template \ - auto ilog(Args&&... args) -> void { \ - LOG_MODULE.ilog(std::forward(args)...); \ - } \ - template \ - auto wlog(Args&&... args) -> void { \ - LOG_MODULE.wlog(std::forward(args)...); \ - } \ - template \ - auto elog(Args&&... args) -> void { \ - LOG_MODULE.elog(std::forward(args)...); \ - } \ - template \ - auto flog(Args&&... args) -> void { \ - LOG_MODULE.flog(std::forward(args)...); \ +#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)...); \ } -#endif \ No newline at end of file +#endif diff --git a/modules/stormkit.mpp b/modules/stormkit.mpp index 7e5461be6..c1e93a650 100644 --- a/modules/stormkit.mpp +++ b/modules/stormkit.mpp @@ -8,5 +8,5 @@ export import stormkit.core; export import stormkit.Main; export import stormkit.log; export import stormkit.entities; -export import stormkit.Gpu; +export import stormkit.gpu; export import stormkit.Engine; diff --git a/modules/stormkit/Engine/ECS/SpriteRenderSystem.mpp b/modules/stormkit/Engine/ECS/SpriteRenderSystem.mpp index 1c99b19d4..dcff221ab 100644 --- a/modules/stormkit/Engine/ECS/SpriteRenderSystem.mpp +++ b/modules/stormkit/Engine/ECS/SpriteRenderSystem.mpp @@ -12,7 +12,7 @@ import std; import stormkit.core; import stormkit.entities; -import stormkit.Gpu; +import stormkit.gpu; import :Renderer; import :SpriteRenderer; diff --git a/modules/stormkit/Engine/Renderer.mpp b/modules/stormkit/Engine/Renderer.mpp index b27ee58e2..01a08c3c2 100644 --- a/modules/stormkit/Engine/Renderer.mpp +++ b/modules/stormkit/Engine/Renderer.mpp @@ -12,7 +12,7 @@ import std; import stormkit.core; import stormkit.wsi; -import stormkit.Gpu; +import stormkit.gpu; export import :Renderer.FrameGraph; export import :Renderer.RenderSurface; @@ -59,11 +59,11 @@ export namespace stormkit::engine { auto mainCommandPool() const noexcept -> const gpu::CommandPool&; private: - auto doInit(std::string_view, std::optional>) noexcept + auto do_init(std::string_view, std::optional>) noexcept -> gpu::Expected; - auto doInitInstance(std::string_view) noexcept -> gpu::Expected; - auto doInitDevice() noexcept -> gpu::Expected; - auto doInitRenderSurface(std::optional>) noexcept + auto do_init_instance(std::string_view) noexcept -> gpu::Expected; + auto do_initDevice() noexcept -> gpu::Expected; + auto do_initRenderSurface(std::optional>) noexcept -> gpu::Expected; auto threadLoop(std::mutex&, std::atomic_bool&, std::stop_token) noexcept -> void; @@ -96,7 +96,7 @@ namespace stormkit::engine { STORMKIT_FORCE_INLINE Renderer::Renderer(std::string_view application_name, std::optional> window, Tag) { - doInit(application_name, std::move(window)).transform_error(monadic::throw_as_exception()); + do_init(application_name, std::move(window)).transform_error(monadic::throw_as_exception()); } ///////////////////////////////////// @@ -144,7 +144,7 @@ namespace stormkit::engine { STORMKIT_FORCE_INLINE auto Renderer::startRendering(std::mutex& framegraph_mutex, std::atomic_bool& rebuild_graph) noexcept -> void { - m_render_thread = std::jthread { bindFront(&Renderer::threadLoop, + m_render_thread = std::jthread { bind_front(&Renderer::threadLoop, this, std::ref(framegraph_mutex), std::ref(rebuild_graph)) }; diff --git a/modules/stormkit/Engine/Renderer/FrameGraph.mpp b/modules/stormkit/Engine/Renderer/FrameGraph.mpp index 6b9b4fa82..82ce3dfc9 100644 --- a/modules/stormkit/Engine/Renderer/FrameGraph.mpp +++ b/modules/stormkit/Engine/Renderer/FrameGraph.mpp @@ -7,7 +7,7 @@ export module stormkit.Engine:Renderer.FrameGraph; import std; import stormkit.core; -import stormkit.Gpu; +import stormkit.gpu; import :Renderer.RenderSurface; @@ -710,7 +710,7 @@ namespace stormkit::engine { STORMKIT_FORCE_INLINE auto FrameGraphBuilder::getTask(this auto& self, std::string_view name) noexcept -> decltype(auto) { - return as>(self.getTask(name)); + return as>(self.getTask(name)); } ///////////////////////////////////// @@ -718,7 +718,7 @@ namespace stormkit::engine { template STORMKIT_FORCE_INLINE auto FrameGraphBuilder::getTask(this auto& self, GraphID id) noexcept -> decltype(auto) { - return as>(self.getTask(id)); + return as>(self.getTask(id)); } ///////////////////////////////////// diff --git a/modules/stormkit/Engine/Renderer/RenderSurface.mpp b/modules/stormkit/Engine/Renderer/RenderSurface.mpp index da3a34555..e14ae416e 100644 --- a/modules/stormkit/Engine/Renderer/RenderSurface.mpp +++ b/modules/stormkit/Engine/Renderer/RenderSurface.mpp @@ -12,7 +12,7 @@ import std; import stormkit.core; import stormkit.wsi; -import stormkit.Gpu; +import stormkit.gpu; export namespace stormkit::engine { class STORMKIT_API RenderSurface { @@ -41,12 +41,12 @@ export namespace stormkit::engine { RenderSurface(RenderSurface&&) noexcept; auto operator=(RenderSurface&&) noexcept -> RenderSurface&; - static auto createFromWindow(const gpu::Instance& instance, + static auto create_from_window(const gpu::Instance& instance, const gpu::Device& device, const gpu::Queue& raster_queue, const wsi::Window& window) noexcept -> gpu::Expected; - static auto allocateFromWindow(const gpu::Instance& instance, + static auto allocate_from_window(const gpu::Instance& instance, const gpu::Device& device, const gpu::Queue& raster_queue, const wsi::Window& window) noexcept @@ -99,7 +99,7 @@ namespace stormkit::engine { ///////////////////////////////////// ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto RenderSurface::createFromWindow(const gpu::Instance& instance, + STORMKIT_FORCE_INLINE auto RenderSurface::create_from_window(const gpu::Instance& instance, const gpu::Device& device, const gpu::Queue& raster_queue, const wsi::Window& window) noexcept @@ -109,7 +109,7 @@ namespace stormkit::engine { ///////////////////////////////////// ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto RenderSurface::allocateFromWindow(const gpu::Instance& instance, + STORMKIT_FORCE_INLINE auto RenderSurface::allocate_from_window(const gpu::Instance& instance, const gpu::Device& device, const gpu::Queue& raster_queue, const wsi::Window& window) noexcept diff --git a/modules/stormkit/Engine/SpriteRenderer.mpp b/modules/stormkit/Engine/SpriteRenderer.mpp index 3442f9ec1..271c6555e 100644 --- a/modules/stormkit/Engine/SpriteRenderer.mpp +++ b/modules/stormkit/Engine/SpriteRenderer.mpp @@ -11,7 +11,7 @@ export module stormkit.Engine:SpriteRenderer; import std; import stormkit.core; -import stormkit.Gpu; +import stormkit.gpu; import :Core; import :Renderer; diff --git a/modules/stormkit/Gpu/Core/Device.mpp b/modules/stormkit/Gpu/Core/Device.mpp deleted file mode 100644 index e2575b302..000000000 --- a/modules/stormkit/Gpu/Core/Device.mpp +++ /dev/null @@ -1,269 +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:Core.Device; - -import std; - -import stormkit.core; -import stormkit.Gpu.Vulkan; - -import :Core.Types; - -export namespace stormkit::gpu { - class PhysicalDevice; - class Instance; - class Fence; - class Semaphore; - - class STORMKIT_API Device { - struct Tag {}; - - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::Device; - - struct QueueEntry { - UInt32 id; - UInt32 count; - QueueFlag flags = QueueFlag {}; - }; - - struct Info { - bool enable_swapchain; - bool enable_raytracing; - }; - - Device(const PhysicalDevice& physical_device, - const Instance& instance, - const Info& info, - Tag); - ~Device(); - - Device(const Device&) = delete; - auto operator=(const Device&) -> Device& = delete; - - Device(Device&&) noexcept; - auto operator=(Device&&) noexcept -> Device&; - - [[nodiscard]] - static auto create(const PhysicalDevice& physical_device, - const Instance& instance, - const Info& info = { true, false }) noexcept -> Expected; - [[nodiscard]] - static auto allocate(const PhysicalDevice& physical_device, - const Instance& instance, - const Info& info = { true, false }) noexcept - -> Expected>; - - auto waitIdle() const noexcept -> void; - - [[nodiscard]] - auto waitForFences(std::span> fences, - bool wait_all = true, - const std::chrono::milliseconds& timeout - = std::chrono::milliseconds::max()) const noexcept -> Expected; - [[nodiscard]] - auto waitForFence(const Fence& fence, - const std::chrono::milliseconds& timeout - = std::chrono::milliseconds::max()) const noexcept -> Expected; - - auto resetFences(std::span> fences) const noexcept -> void; - auto resetFence(const Fence& fence) const noexcept -> void; - - [[nodiscard]] - auto rasterQueueEntry() const noexcept -> const QueueEntry&; - [[nodiscard]] - auto asyncTransferQueueEntry() const noexcept -> const QueueEntry&; - [[nodiscard]] - auto asyncComputeQueueEntry() const noexcept -> const QueueEntry&; - - [[nodiscard]] - auto hasAsyncTransferQueue() const noexcept -> bool; - [[nodiscard]] - auto hasAsyncComputeQueue() const noexcept -> bool; - - [[nodiscard]] - auto physicalDevice() const noexcept -> const PhysicalDevice&; - - [[nodiscard]] - auto vkHandle() const noexcept -> const vk::raii::Device&; - - [[nodiscard]] - auto vmaAllocator() const noexcept -> const vma::Allocator&; - [[nodiscard]] - auto vmaFunctionTable() const noexcept -> const vma::VulkanFunctions&; - - template - auto setObjectName(const T& object, std::string_view name) const -> void; - - auto setObjectName(UInt64 object, DebugObjectType type, std::string_view name) const - -> void; - - private: - Ref m_physical_device; - - DeferInit m_vk_device; - - QueueEntry m_raster_queue; - std::optional m_async_transfert_queue; - std::optional m_async_compute_queue; - - vma::UniqueAllocator m_vma_allocator; - vma::VulkanFunctions m_vma_function_table; - }; -} // namespace stormkit::gpu - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::gpu { - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Device::~Device() { - if (m_vk_device.initialized()) [[likely]] - waitIdle(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Device::Device(Device&& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Device::operator=(Device&& other) noexcept -> Device& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Device::create(const PhysicalDevice& physical_device, - const Instance& instance, - const Info& info) noexcept -> Expected try { - return Device { physical_device, instance, info, Tag {} }; - } catch (Result result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Device::allocate(const PhysicalDevice& physical_device, - const Instance& instance, - const Info& info) noexcept - -> Expected> try { - return std::make_unique(physical_device, instance, info, Tag {}); - } catch (Result result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Device::waitIdle() const noexcept -> void { - vkHandle().waitIdle(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - Device::waitForFence(const Fence& fence, - const std::chrono::milliseconds& timeout) const noexcept - -> Expected { - return waitForFences(as_refs(fence), true, timeout); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Device::resetFence(const Fence& fence) const noexcept -> void { - resetFences(as_refs(fence)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Device::rasterQueueEntry() const noexcept -> const QueueEntry& { - return m_raster_queue; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Device::asyncTransferQueueEntry() const noexcept - -> const QueueEntry& { - expects(m_async_transfert_queue != std::nullopt); - - return *m_async_transfert_queue; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Device::asyncComputeQueueEntry() const noexcept - -> const QueueEntry& { - expects(m_async_compute_queue != std::nullopt); - - return *m_async_compute_queue; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Device::hasAsyncTransferQueue() const noexcept -> bool { - return m_async_transfert_queue != std::nullopt; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Device::hasAsyncComputeQueue() const noexcept -> bool { - return m_async_compute_queue != std::nullopt; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Device::physicalDevice() const noexcept -> const PhysicalDevice& { - return m_physical_device; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Device::vkHandle() const noexcept -> const vk::raii::Device& { - return m_vk_device; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Device::vmaAllocator() const noexcept -> const vma::Allocator& { - expects(m_vma_allocator.operator bool()); - - return *m_vma_allocator; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Device::vmaFunctionTable() const noexcept - -> const vma::VulkanFunctions& { - return m_vma_function_table; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE auto Device::setObjectName(const T& object, std::string_view name) const - -> void { - auto&& vk_object = toVkHandle(object); - setObjectName(std::bit_cast(static_cast(vk_object)), - T::DEBUG_TYPE, - name); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Device::setObjectName(UInt64 object, - DebugObjectType type, - std::string_view name) const -> void { - if (!vkHandle().getDispatcher()->vkSetDebugUtilsObjectNameEXT) return; - - const auto info = vk::DebugUtilsObjectNameInfoEXT {} - .setObjectType(narrow(type)) - .setObjectHandle(object) - .setPObjectName(std::data(name)); - - m_vk_device->setDebugUtilsObjectNameEXT(info); - } -} // namespace stormkit::gpu diff --git a/modules/stormkit/Gpu/Core/Instance.mpp b/modules/stormkit/Gpu/Core/Instance.mpp deleted file mode 100644 index bf9f00d80..000000000 --- a/modules/stormkit/Gpu/Core/Instance.mpp +++ /dev/null @@ -1,410 +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:Core.Instance; - -import std; - -import stormkit.core; -import stormkit.wsi; -import stormkit.Gpu.Vulkan; - -import :Core.Types; -import :Core.Device; - -export { - namespace stormkit::gpu { - class PhysicalDevice; - - class STORMKIT_API Instance { - struct Tag {}; - - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::Instance; - - Instance(std::string app_name, bool verbose, Tag); - ~Instance(); - - Instance(const Instance&) = delete; - auto operator=(const Instance&) -> Instance& = delete; - - Instance(Instance&&) noexcept; - auto operator=(Instance&&) noexcept -> 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>; - - [[nodiscard]] - auto physicalDevices() const noexcept -> const std::vector&; - - [[nodiscard]] - auto vkHandle() const noexcept -> const vk::raii::Instance&; - - // #ifdef STORMKIT_WSI_ENABLED - //[[nodiscard]] auto createWindowSurface( - // const wsi::Window& window, - // Surface::Buffering buffering = Surface::Buffering::Swapchain) const - //-> WindowSurface; - //[[nodiscard]] auto allocateWindowSurface( - // const wsi::Window& window, - // Surface::Buffering buffering = Surface::Buffering::Swapchain) const - //-> std::unique_ptr; - //[[nodiscard]] auto allocateRefCountedWindowSurface( - // const wsi::Window& window, - // Surface::Buffering buffering = Surface::Buffering::Swapchain) const - //-> std::shared_ptr; - // #endif - - //[[nodiscard]] auto createOffscreenSurface( - // const math::ExtentU& extent, - // Surface::Buffering buffering = Surface::Buffering::Triple) const - //-> OffscreenSurface; - //[[nodiscard]] auto allocateOffscreenSurface( - // const math::ExtentU& extent, - // Surface::Buffering buffering = Surface::Buffering::Triple) const - //-> std::unique_ptr; - //[[nodiscard]] auto allocateRefCountedOffscreenSurface( - // const math::ExtentU& extent, - // Surface::Buffering buffering = Surface::Buffering::Triple) const - //-> std::shared_ptr; - - private: - auto doInitInstance() noexcept -> VulkanExpected; - auto doInitDebugReportCallback() noexcept -> VulkanExpected; - auto doRetrievePhysicalDevices() noexcept -> VulkanExpected; - - std::string m_app_name; - bool m_validation_layers_enabled; - - DeferInit m_vk_context; - DeferInit m_vk_instance; - DeferInit m_vk_messenger; - - std::vector m_extensions; - std::vector m_physical_devices; - }; - - 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 checkExtensionSupport(std::string_view extension) const noexcept -> bool; - [[nodiscard]] - auto checkExtensionSupport(std::span extensions) const noexcept - -> bool; - [[nodiscard]] - auto checkExtensionSupport(std::span extensions) const noexcept -> bool; - - [[nodiscard]] - auto info() const noexcept -> const PhysicalDeviceInfo&; - [[nodiscard]] - auto capabilities() const noexcept -> const RenderCapabilities&; - [[nodiscard]] - auto memoryProperties() const noexcept -> const std::vector&; - - [[nodiscard]] - auto queueFamilies() const noexcept -> const std::vector&; - - [[nodiscard]] - auto vkHandle() const noexcept -> const vk::raii::PhysicalDevice&; - - private: - explicit PhysicalDevice(vk::raii::PhysicalDevice physical_device); - - vk::raii::PhysicalDevice m_vk_physical_device; - - PhysicalDeviceInfo m_device_info; - RenderCapabilities m_capabilities; - std::vector m_memory_properties; - - std::vector m_queue_families; - vk::PhysicalDeviceMemoryProperties m_vk_memory_properties; - - std::vector m_extensions; - - friend class Instance; - }; - - class STORMKIT_API Surface { - struct Tag {}; - - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::Surface; - - Surface(const Instance& instance, const wsi::Window& window, Tag); - // Surface(const Instance& instance, Tag); - ~Surface(); - - Surface(const Surface&) = delete; - auto operator=(const Surface&) -> Surface& = delete; - - Surface(Surface&&) noexcept; - auto operator=(Surface&&) noexcept -> Surface&; - - // [[nodiscard]] static auto createOffscreen(const Instance& instance) noexcept -> - // Expected; - // [[nodiscard]] static auto - // allocateOffscreen(const Instance& instance) noexcept -> - // Expected>; - - [[nodiscard]] - static auto createFromWindow(const Instance& instance, - const wsi::Window& window) noexcept -> Expected; - [[nodiscard]] - static auto allocateFromWindow(const Instance& instance, - const wsi::Window& window) noexcept - -> Expected>; - - [[nodiscard]] - auto vkHandle() const noexcept -> const vk::raii::SurfaceKHR&; - - private: - DeferInit m_vk_surface; - }; - } // 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 Instance::Instance(std::string app_name, bool enable_validation, Tag) - : m_app_name { std::move(app_name) }, m_validation_layers_enabled { enable_validation } { - doInitInstance() - .and_then(bindFront(&Instance::doInitDebugReportCallback, this)) - .and_then(bindFront(&Instance::doRetrievePhysicalDevices, this)) - .transform_error(core :.monadic::map(core :.monadic::narrow(), - core :.monadic::throw_as_exception())); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Instance::~Instance() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Instance::Instance(Instance&& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Instance::operator=(Instance&& other) noexcept - -> Instance& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Instance::create(std::string app_name, - bool enable_validation) noexcept - -> Expected try { - return Instance { std::move(app_name), enable_validation, Tag {} }; - } catch (Result result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Instance::allocate(std::string app_name, - bool enable_validation) noexcept - -> Expected> try { - return std::make_unique(std::move(app_name), enable_validation, Tag {}); - } catch (Result result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Instance::physicalDevices() const noexcept - -> const std::vector& { - return m_physical_devices; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Instance::vkHandle() const noexcept -> const vk::raii::Instance& { - return m_vk_instance; - } - - // #ifdef STORMKIT_WSI_ENABLED - // ///////////////////////////////////// - // ///////////////////////////////////// - // STORMKIT_FORCE_INLINE auto Instance::createWindowSurface(const wsi::Window& window, - // Surface::Buffering buffering) const - // -> WindowSurface { - // return WindowSurface { window, instance(), buffering }; - // } - - // ///////////////////////////////////// - // ///////////////////////////////////// - // STORMKIT_FORCE_INLINE auto Instance::allocateWindowSurface(const wsi::Window& window, - // Surface::Buffering buffering) const - // -> std::unique_ptr { - // return std::make_unique(window, instance(), buffering); - // } - - // ///////////////////////////////////// - // ///////////////////////////////////// - // STORMKIT_FORCE_INLINE auto - // Instance::allocateRefCountedWindowSurface(const wsi::Window& window, - // Surface::Buffering buffering) const - // -> std::shared_ptr { - // return std::make_shared(window, instance(), buffering); - // } - // #endif - - // ///////////////////////////////////// - // ///////////////////////////////////// - // STORMKIT_FORCE_INLINE auto Instance::createOffscreenSurface(const math::ExtentU& - // extent, Surface::Buffering buffering) const - // -> OffscreenSurface { - // return OffscreenSurface { extent, instance(), buffering }; - // } - - // ///////////////////////////////////// - // ///////////////////////////////////// - // STORMKIT_FORCE_INLINE auto Instance::allocateOffscreenSurface(const math::ExtentU& - // extent, Surface::Buffering buffering) const - // -> std::unique_ptr { - // return std::make_unique(extent, instance(), buffering); - // } - - // ///////////////////////////////////// - // ///////////////////////////////////// - // STORMKIT_FORCE_INLINE auto Instance::allocateRefCountedOffscreenSurface( - // const math::ExtentU& extent, - // Surface::Buffering buffering) const -> std::shared_ptr { - // return std::make_shared(extent, instance(), buffering); - // } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto PhysicalDevice::info() const noexcept -> const PhysicalDeviceInfo& { - return m_device_info; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto PhysicalDevice::capabilities() const noexcept - -> const RenderCapabilities& { - return m_capabilities; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto PhysicalDevice::memoryProperties() const noexcept - -> const std::vector& { - return m_memory_properties; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto PhysicalDevice::queueFamilies() const noexcept - -> const std::vector& { - return m_queue_families; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto PhysicalDevice::vkHandle() const noexcept - -> const vk::raii::PhysicalDevice& { - return m_vk_physical_device; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Surface::~Surface() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Surface::Surface(Surface&& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Surface::operator=(Surface&& other) noexcept -> Surface& = default; - - // ///////////////////////////////////// - // ///////////////////////////////////// - // STORMKIT_FORCE_INLINE auto - // Surface::createOffscreen(const Instance& instance) noexcept -> Expected try { - // return Surface { instance, Tag {} }; - // } catch (const Result& result) { return std::unexpected(result); } - // - // ///////////////////////////////////// - // ///////////////////////////////////// - // STORMKIT_FORCE_INLINE auto Surface::allocateOffscreen(const Instance& instance) noexcept - // -> Expected> try { - // return std::make_unique(instance, Tag {}); - // } catch (const Result& result) { return std::unexpected(result); } - // - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Surface::createFromWindow(const Instance& instance, - const wsi::Window& window) noexcept - -> Expected try { - return Surface { instance, window, Tag {} }; - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Surface::allocateFromWindow(const Instance& instance, - const wsi::Window& window) noexcept - -> Expected> try { - return std::make_unique(instance, window, Tag {}); - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Surface::vkHandle() const noexcept -> const vk::raii::SurfaceKHR& { - return m_vk_surface.get(); - } - -} // namespace stormkit::gpu diff --git a/modules/stormkit/Gpu/Core/Sync.mpp b/modules/stormkit/Gpu/Core/Sync.mpp deleted file mode 100644 index 26f6678b0..000000000 --- a/modules/stormkit/Gpu/Core/Sync.mpp +++ /dev/null @@ -1,243 +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 - -export module stormkit.Gpu:Core.Sync; - -import std; - -import stormkit.core; -import stormkit.Gpu.Vulkan; - -import :Core.Types; -import :Core.Device; - -export namespace stormkit::gpu { - class Device; - - class STORMKIT_API Fence { - struct Tag {}; - - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::Fence; - - enum class Status { - Signaled, - Unsignaled - }; - - Fence(const Device& device, bool signaled, Tag); - ~Fence(); - - Fence(const Fence&) = delete; - auto operator=(const Fence&) -> Fence& = delete; - - Fence(Fence&&) noexcept; - auto operator=(Fence&&) noexcept -> Fence&; - - [[nodiscard]] - static auto create(const Device& device, bool signaled = false) noexcept -> Expected; - [[nodiscard]] - static auto createSignaled(const Device& device) noexcept -> Expected; - [[nodiscard]] - static auto allocate(const Device& device, bool signaled = false) noexcept - -> Expected>; - [[nodiscard]] - static auto allocateSignaled(const Device& device) noexcept - -> Expected>; - - [[nodiscard]] - auto wait(const std::chrono::milliseconds& wait_for - = std::chrono::milliseconds::max()) const -> Expected; - auto reset() -> void; - - [[nodiscard]] - auto status() const noexcept -> Expected; - - [[nodiscard]] - auto vkHandle() const noexcept -> const vk::raii::Fence&; - - private: - DeferInit m_vk_fence; - }; - - class STORMKIT_API Semaphore { - struct Tag {}; - - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::Semaphore; - - Semaphore(const Device& device, Tag); - ~Semaphore(); - - Semaphore(const Semaphore&) = delete; - auto operator=(const Semaphore&) -> Semaphore& = delete; - - Semaphore(Semaphore&&) noexcept; - auto operator=(Semaphore&&) noexcept -> Semaphore&; - - [[nodiscard]] - static auto create(const Device& device) noexcept -> Expected; - [[nodiscard]] - static auto allocate(const Device& device) noexcept -> Expected>; - - [[nodiscard]] - auto vkHandle() const noexcept -> const vk::raii::Semaphore&; - - private: - DeferInit m_vk_semaphore; - }; -} // namespace stormkit::gpu - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::gpu { - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Fence::Fence(const Device& device, bool signaled, Tag) { - const auto flags - = (signaled) ? vk::FenceCreateFlagBits::eSignaled : vk::FenceCreateFlags {}; - - const auto create_info = vk::FenceCreateInfo {}.setFlags(flags); - - device.vkHandle() - .createFence(create_info) - .transform(core :.monadic::set(m_vk_fence)) - .transform_error(core :.monadic::map(core :.monadic::narrow(), - core :.monadic::throw_as_exception())); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Fence::~Fence() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Fence::Fence(Fence&& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Fence::operator=(Fence&& other) noexcept -> Fence& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Fence::status() const noexcept -> Expected { - return vkCall(*m_vk_fence, - &vk::raii::Fence::getStatus, - { - { vk::Result::eSuccess, vk::Result::eNotReady } - }) - .transform([](auto&& result) noexcept { - if (result == vk::Result::eNotReady) return Status::Unsignaled; - return Status::Signaled; - }) - .transform_error(core :.monadic::narrow()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Fence::create(const Device& device, bool signaled) noexcept - -> Expected try { - return Fence { device, signaled, Tag {} }; - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Fence::createSignaled(const Device& device) noexcept - -> Expected { - return create(device, true); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Fence::allocate(const Device& device, bool signaled) noexcept - -> Expected> try { - return std::make_unique(device, signaled, Tag {}); - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Fence::allocateSignaled(const Device& device) noexcept - -> Expected> { - return allocate(device, true); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Fence::wait(const std::chrono::milliseconds& wait_for) const - -> Expected { - const auto result = m_vk_fence->getDevice().waitForFences( - std::array { *vkHandle() }, - true, - std::chrono::duration_cast(wait_for).count()); - const auto possible_results = std::array { vk::Result::eSuccess, vk::Result::eNotReady }; - - if (std::ranges::any_of(possible_results, core :.monadic::is(result))) [[likely]] - return narrow(result); - - return std::unexpected { narrow(result) }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Fence::reset() -> void { - m_vk_fence->getDevice().resetFences(std::array { *vkHandle() }); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Fence::vkHandle() const noexcept -> const vk::raii::Fence& { - return m_vk_fence.get(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Semaphore::Semaphore(const Device& device, Tag) { - const auto create_info = vk::SemaphoreCreateInfo {}; - - device.vkHandle() - .createSemaphore(create_info) - .transform(core :.monadic::set(m_vk_semaphore)) - .transform_error(core :.monadic::map(core :.monadic::narrow(), - core :.monadic::throw_as_exception())); - }; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Semaphore::~Semaphore() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Semaphore::Semaphore(Semaphore&& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Semaphore::operator=(Semaphore&& other) noexcept - -> Semaphore& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Semaphore::create(const Device& device) noexcept - -> Expected try { - return Semaphore { device, Tag {} }; - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Semaphore::allocate(const Device& device) noexcept - -> Expected> try { - return std::make_unique(device, Tag {}); - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Semaphore::vkHandle() const noexcept -> const vk::raii::Semaphore& { - return m_vk_semaphore.get(); - } -} // namespace stormkit::gpu diff --git a/modules/stormkit/Gpu/Core/Types.mpp b/modules/stormkit/Gpu/Core/Types.mpp deleted file mode 100644 index a3c54f962..000000000 --- a/modules/stormkit/Gpu/Core/Types.mpp +++ /dev/null @@ -1,1267 +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:Core.Types; - -import std; - -import stormkit.core; -import stormkit.Gpu.Vulkan; - -export { - namespace stormkit::gpu { - inline constexpr auto QUEUE_FAMILY_IGNORED = UInt32 { vk::QueueFamilyIgnored }; - - enum class PhysicalDeviceType : UInt8 { - Discrete_GPU = as(vk::PhysicalDeviceType::eDiscreteGpu), - Virtual_GPU = as(vk::PhysicalDeviceType::eVirtualGpu), - Integrated_GPU = as(vk::PhysicalDeviceType::eIntegratedGpu), - CPU = as(vk::PhysicalDeviceType::eCpu), - Other = as(vk::PhysicalDeviceType::eOther), - }; - - enum class QueueFlag : UInt8 { - NONE = 0, - Graphics = as(vk::QueueFlagBits::eGraphics), - Compute = as(vk::QueueFlagBits::eCompute), - Transfer = as(vk::QueueFlagBits::eTransfer), - Sparse_Binding = as(vk::QueueFlagBits::eSparseBinding), - }; - - enum class ShaderStageFlag : UInt8 { - NONE = 0, - Vertex = as(vk::ShaderStageFlagBits::eVertex), - Fragment = as(vk::ShaderStageFlagBits::eFragment), - Geometry = as(vk::ShaderStageFlagBits::eGeometry), - Compute = as(vk::ShaderStageFlagBits::eCompute), - }; - - enum class PrimitiveTopology : UInt8 { - Point_List = as(vk::PrimitiveTopology::ePointList), - Line_List = as(vk::PrimitiveTopology::eLineList), - Line_Strip = as(vk::PrimitiveTopology::eLineStrip), - Triangle_List = as(vk::PrimitiveTopology::eTriangleList), - Triangle_Strip = as(vk::PrimitiveTopology::eTriangleStrip), - Triangle_Fan = as(vk::PrimitiveTopology::eTriangleFan), - }; - - enum class PolygonMode : UInt8 { - Fill = as(vk::PolygonMode::eFill), - Line = as(vk::PolygonMode::eLine), - Point = as(vk::PolygonMode::ePoint), - }; - - enum class CullModeFlag : UInt8 { - NONE = as(vk::CullModeFlagBits::eNONE), - Front = as(vk::CullModeFlagBits::eFront), - Back = as(vk::CullModeFlagBits::eBack), - Front_Back = Front | Back, - }; - - enum class FrontFace : UInt8 { - Clockwise = as(vk::FrontFace::eClockwise), - Counter_Clockwise = as(vk::FrontFace::eCounterClockwise), - }; - - enum class SampleCountFlag : UInt8 { - NONE = 0, - C1 = as(vk::SampleCountFlagBits::e1), - C2 = as(vk::SampleCountFlagBits::e2), - C4 = as(vk::SampleCountFlagBits::e4), - C8 = as(vk::SampleCountFlagBits::e8), - C16 = as(vk::SampleCountFlagBits::e16), - C32 = as(vk::SampleCountFlagBits::e32), - C64 = as(vk::SampleCountFlagBits::e64), - }; - - enum class ColorComponentFlag : UInt8 { - NONE = 0, - R = as(vk::ColorComponentFlagBits::eR), - G = as(vk::ColorComponentFlagBits::eG), - B = as(vk::ColorComponentFlagBits::eB), - A = as(vk::ColorComponentFlagBits::eA), - RG = R | G, - RGB = RG | B, - RGBA = RGB | A, - }; - - enum class BlendFactor : UInt8 { - One = as(vk::BlendFactor::eOne), - Zero = as(vk::BlendFactor::eZero), - Src_Color = as(vk::BlendFactor::eSrcColor), - One_Minus_Src_Color = as(vk::BlendFactor::eOneMinusSrcColor), - Dst_Color = as(vk::BlendFactor::eDstColor), - One_Minus_Dst_Color = as(vk::BlendFactor::eOneMinusDstColor), - Src_Alpha = as(vk::BlendFactor::eSrcAlpha), - One_Minus_Src_Alpha = as(vk::BlendFactor::eOneMinusSrcAlpha), - Dst_Alpha = as(vk::BlendFactor::eDstAlpha), - One_Minus_Dst_Alpha = as(vk::BlendFactor::eOneMinusDstAlpha), - Constant_Color = as(vk::BlendFactor::eConstantColor), - One_Minus_Constant_Color = as(vk::BlendFactor::eOneMinusConstantColor), - Constant_Alpha = as(vk::BlendFactor::eConstantAlpha), - One_Minus_Constant_Alpha = as(vk::BlendFactor::eOneMinusConstantAlpha), - Src_Alpha_Saturate = as(vk::BlendFactor::eSrcAlphaSaturate), - Src1_Color = as(vk::BlendFactor::eSrc1Color), - One_Minus_Src1_Color = as(vk::BlendFactor::eOneMinusSrc1Color), - Src1_Alpha = as(vk::BlendFactor::eSrc1Alpha), - One_Minus_Src1_Alpha = as(vk::BlendFactor::eOneMinusSrc1Alpha), - }; - - enum class BlendOperation : UInt8 { - Add = as(vk::BlendOp::eAdd), - Substract = as(vk::BlendOp::eSubtract), - Reverse_Substract = as(vk::BlendOp::eReverseSubtract), - Min = as(vk::BlendOp::eMin), - Max = as(vk::BlendOp::eMax), - }; - - enum class LogicOperation : UInt8 { - Clear = as(vk::LogicOp::eClear), - And = as(vk::LogicOp::eAnd), - And_Reverse = as(vk::LogicOp::eAndReverse), - Copy = as(vk::LogicOp::eCopy), - And_Inverted = as(vk::LogicOp::eAndInverted), - No_Operation = as(vk::LogicOp::eNoOp), - Xor = as(vk::LogicOp::eXor), - Or = as(vk::LogicOp::eOr), - Nor = as(vk::LogicOp::eNor), - Equivalent = as(vk::LogicOp::eEquivalent), - Invert = as(vk::LogicOp::eInvert), - Or_Reverse = as(vk::LogicOp::eOrReverse), - Copy_Inverted = as(vk::LogicOp::eCopyInverted), - Or_Inverted = as(vk::LogicOp::eOrInverted), - Nand = as(vk::LogicOp::eNand), - Set = as(vk::LogicOp::eSet), - }; - - enum class PixelFormat : UInt8 { - R8_SNORM = as(vk::format::eR8Snorm), - RG8_SNORM = as(vk::format::eR8G8Snorm), - RGB8_SNORM = as(vk::format::eR8G8B8Snorm), - RGBA8_SNORM = as(vk::format::eR8G8B8A8Snorm), - - R8_UNORM = as(vk::format::eR8Unorm), - RG8_UNORM = as(vk::format::eR8G8Unorm), - RGB8_UNORM = as(vk::format::eR8G8B8Unorm), - RGBA8_UNORM = as(vk::format::eR8G8B8A8Unorm), - - R16_SNORM = as(vk::format::eR16Snorm), - RG16_SNORM = as(vk::format::eR16G16Snorm), - RGB16_SNORM = as(vk::format::eR16G16B16Snorm), - RGBA16_SNORM = as(vk::format::eR16G16B16A16Snorm), - - R16_UNORM = as(vk::format::eR16Unorm), - RG16_UNORM = as(vk::format::eR16G16Unorm), - RGB16_UNORM = as(vk::format::eR16G16B16Unorm), - RGBA16_UNORM = as(vk::format::eR16G16B16A16Unorm), - - A2_RGB10_UNorm = as(vk::format::eA2R10G10B10UnormPack32), - - RGBA4_UNORM_Pack16 = as(vk::format::eR4G4B4A4UnormPack16), - - A1_RGB5_UNorm_Pack16 = as(vk::format::eA1R5G5B5UnormPack16), - - R5_G6_B5_UNorm_Pack16 = as(vk::format::eR5G6B5UnormPack16), - - BGR8_UNORM = as(vk::format::eB8G8R8Unorm), - BGRA8_UNORM = as(vk::format::eB8G8R8A8Unorm), - - R8I = as(vk::format::eR8Sint), - RG8I = as(vk::format::eR8G8Sint), - RGB8I = as(vk::format::eR8G8B8Sint), - RGBA8I = as(vk::format::eR8G8B8A8Sint), - - R8U = as(vk::format::eR8Uint), - RG8U = as(vk::format::eR8G8Uint), - RGB8U = as(vk::format::eR8G8B8Uint), - RGBA8U = as(vk::format::eR8G8B8A8Uint), - - R16I = as(vk::format::eR16Sint), - RG16I = as(vk::format::eR16G16Sint), - RGB16I = as(vk::format::eR16G16B16Sint), - RGBA16I = as(vk::format::eR16G16B16A16Sint), - - R16U = as(vk::format::eR16Uint), - RG16U = as(vk::format::eR16G16Uint), - RGB16U = as(vk::format::eR16G16B16Uint), - RGBA16U = as(vk::format::eR16G16B16A16Uint), - - R32I = as(vk::format::eR32Sint), - RG32I = as(vk::format::eR32G32Sint), - RGB32I = as(vk::format::eR32G32B32Sint), - RGBA32I = as(vk::format::eR32G32B32A32Sint), - - R32U = as(vk::format::eR32Uint), - RG32U = as(vk::format::eR32G32Uint), - RGB32U = as(vk::format::eR32G32B32Uint), - RGBA32U = as(vk::format::eR32G32B32A32Uint), - - A2_RGB10U_Pack32 = as(vk::format::eA2R10G10B10UintPack32), - - R16F = as(vk::format::eR16Sfloat), - RG16F = as(vk::format::eR16G16Sfloat), - RGB16F = as(vk::format::eR16G16B16Sfloat), - RGBA16F = as(vk::format::eR16G16B16A16Sfloat), - - R32F = as(vk::format::eR32Sfloat), - RG32F = as(vk::format::eR32G32Sfloat), - RGB32F = as(vk::format::eR32G32B32Sfloat), - RGBA32F = as(vk::format::eR32G32B32A32Sfloat), - - BG11_R10F_Pack32 = as(vk::format::eB10G11R11UfloatPack32), - - SRGB8 = as(vk::format::eR8G8B8Srgb), - SRGBA8 = as(vk::format::eR8G8B8A8Srgb), - SBGR8 = as(vk::format::eB8G8R8Srgb), - SBGRA8 = as(vk::format::eB8G8R8A8Srgb), - - Depth16 = as(vk::format::eD16Unorm), - Depth24 = as(vk::format::eX8D24UnormPack32), - Depth32F = as(vk::format::eD32Sfloat), - - Depth16_Stencil8 = as(vk::format::eD16UnormS8Uint), - Depth24_Stencil8 = as(vk::format::eD24UnormS8Uint), - Depth32F_Stencil8 = as(vk::format::eD32SfloatS8Uint), - - Undefined = as(vk::format::eUndefined), - }; - - enum class AttachmentLoadOperation : UInt8 { - Clear = as(vk::AttachmentLoadOp::eClear), - Load = as(vk::AttachmentLoadOp::eLoad), - Dont_Care = as(vk::AttachmentLoadOp::eDontCare), - }; - - enum class AttachmentStoreOperation : UInt8 { - Store = as(vk::AttachmentStoreOp::eStore), - Dont_Care = as(vk::AttachmentStoreOp::eDontCare), - }; - - enum class PipelineBindPoint : UInt8 { - Graphics = as(vk::PipelineBindPoint::eGraphics), - Compute = as(vk::PipelineBindPoint::eCompute), - }; - - enum class ImageLayout : UInt32 { - General = as(vk::ImageLayout::eGeneral), - Color_Attachment_Optimal = as(vk::ImageLayout::eColorAttachmentOptimal), - Depth_Stencil_Attachment_Optimal - = as(vk::ImageLayout::eDepthStencilAttachmentOptimal), - Depth_Stencil_Read_Only_Optimal - = as(vk::ImageLayout::eDepthStencilReadOnlyOptimal), - Shader_Read_Only_Optimal = as(vk::ImageLayout::eShaderReadOnlyOptimal), - Transfer_Src_Optimal = as(vk::ImageLayout::eTransferSrcOptimal), - Transfer_Dst_Optimal = as(vk::ImageLayout::eTransferDstOptimal), - Preinitialized = as(vk::ImageLayout::ePreinitialized), - Depth_Read_Only_Stencil_Attachment_Optimal - = as(vk::ImageLayout::eDepthReadOnlyStencilAttachmentOptimal), - Depth_Attachment_Stencil_Read_Only_Optimal - = as(vk::ImageLayout::eDepthAttachmentStencilReadOnlyOptimal), - Present_Src = as(vk::ImageLayout::ePresentSrcKHR), - Shared_Present = as(vk::ImageLayout::eSharedPresentKHR), - Undefined = as(vk::ImageLayout::eUndefined), - }; - - enum class ImageAspectMaskFlag : UInt8 { - NONE = 0, - Color = as(vk::ImageAspectFlagBits::eColor), - Depth = as(vk::ImageAspectFlagBits::eDepth), - Stencil = as(vk::ImageAspectFlagBits::eStencil), - }; - - enum class VertexInputRate : UInt8 { - Vertex = as(vk::VertexInputRate::eVertex), - Instance = as(vk::VertexInputRate::eInstance), - }; - - enum class ImageCreateFlag : UInt16 { - NONE = 0, - Sparse_Binding = as(vk::ImageCreateFlagBits::eSparseBinding), - Sparse_Residency = as(vk::ImageCreateFlagBits::eSparseResidency), - Sparse_Aliased = as(vk::ImageCreateFlagBits::eSparseAliased), - Mutable_Format = as(vk::ImageCreateFlagBits::eMutableFormat), - Cube_Compatible = as(vk::ImageCreateFlagBits::eCubeCompatible), - Alias = as(vk::ImageCreateFlagBits::eAlias), - Split_Instance_Bind_Regions - = as(vk::ImageCreateFlagBits::eSplitInstanceBindRegions), - Array_2D_Compatible = as(vk::ImageCreateFlagBits::e2DArrayCompatible), - Block_Texel_View_Compatible - = as(vk::ImageCreateFlagBits::eBlockTexelViewCompatible), - Extended_Usage = as(vk::ImageCreateFlagBits::eExtendedUsage), - Protected = as(vk::ImageCreateFlagBits::eProtected), - Disjoint = as(vk::ImageCreateFlagBits::eDisjoint), - }; - - enum class Format : UInt8 { - Byte = as(vk::format::eR8Sint), - Byte2 = as(vk::format::eR8G8Sint), - Byte3 = as(vk::format::eR8G8B8Sint), - Byte4 = as(vk::format::eR8G8B8A8Sint), - - Byte_Norm = as(vk::format::eR8Snorm), - Byte2_Norm = as(vk::format::eR8G8Snorm), - Byte3_Norm = as(vk::format::eR8G8B8Snorm), - Byte4_Norm = as(vk::format::eR8G8B8A8Snorm), - - Byte_Scaled = as(vk::format::eR8Sscaled), - Byte2_Scaled = as(vk::format::eR8G8Sscaled), - Byte3_Scaled = as(vk::format::eR8G8B8Sscaled), - Byte4_Scaled = as(vk::format::eR8G8B8A8Sscaled), - - UByte = as(vk::format::eR8Uint), - UByte2 = as(vk::format::eR8G8Uint), - UByte3 = as(vk::format::eR8G8B8Uint), - UByte4 = as(vk::format::eR8G8B8A8Uint), - - UByte_Norm = as(vk::format::eR8Unorm), - UByte2_Norm = as(vk::format::eR8G8Unorm), - UByte3_Norm = as(vk::format::eR8G8B8Unorm), - UByte4_Norm = as(vk::format::eR8G8B8A8Unorm), - - UByte_Ucaled = as(vk::format::eR8Uscaled), - UByte2_Ucaled = as(vk::format::eR8G8Uscaled), - UByte3_Ucaled = as(vk::format::eR8G8B8Uscaled), - UByte4_Ucaled = as(vk::format::eR8G8B8A8Uscaled), - - Short = as(vk::format::eR16Sint), - Short2 = as(vk::format::eR16G16Sint), - Short3 = as(vk::format::eR16G16B16Sint), - Short4 = as(vk::format::eR16G16B16A16Sint), - - Short_Norm = as(vk::format::eR16Sfloat), - Short2_Norm = as(vk::format::eR16G16Sfloat), - Short3_Norm = as(vk::format::eR16G16B16Sfloat), - Short4_Norm = as(vk::format::eR16G16B16A16Sfloat), - - Short_Scaled = as(vk::format::eR16Sscaled), - Short2_Scaled = as(vk::format::eR16G16Sscaled), - Short3_Scaled = as(vk::format::eR16G16B16Sscaled), - Short4_Scaled = as(vk::format::eR16G16B16A16Sscaled), - - UShort = as(vk::format::eR16Uint), - UShort2 = as(vk::format::eR16G16Uint), - UShort3 = as(vk::format::eR16G16B16Uint), - UShort4 = as(vk::format::eR16G16B16A16Uint), - - UShort_Norm = as(vk::format::eR16Unorm), - UShort2_Norm = as(vk::format::eR16G16Unorm), - UShort3_Norm = as(vk::format::eR16G16B16Unorm), - UShort4_Norm = as(vk::format::eR16G16B16A16Unorm), - - UShort_Ucaled = as(vk::format::eR16Uscaled), - UShort2_Ucaled = as(vk::format::eR16G16Uscaled), - UShort3_Ucaled = as(vk::format::eR16G16B16Uscaled), - UShort4_Ucaled = as(vk::format::eR16G16B16A16Uscaled), - - Int = as(vk::format::eR32Sint), - Int2 = as(vk::format::eR32G32Sint), - Int3 = as(vk::format::eR32G32B32Sint), - Int4 = as(vk::format::eR32G32B32A32Sint), - - UInt = as(vk::format::eR32Uint), - UInt2 = as(vk::format::eR32G32Uint), - UInt3 = as(vk::format::eR32G32B32Uint), - UInt4 = as(vk::format::eR32G32B32A32Uint), - - Long = as(vk::format::eR64Sint), - Long2 = as(vk::format::eR64G64Sint), - Long3 = as(vk::format::eR64G64B64Sint), - Long4 = as(vk::format::eR64G64B64A64Sint), - - ULong = as(vk::format::eR64Uint), - ULong2 = as(vk::format::eR64G64Uint), - ULong3 = as(vk::format::eR64G64B64Uint), - ULong4 = as(vk::format::eR64G64B64A64Uint), - - Float = as(vk::format::eR32Sfloat), - Float2 = as(vk::format::eR32G32Sfloat), - Float3 = as(vk::format::eR32G32B32Sfloat), - Float4 = as(vk::format::eR32G32B32A32Sfloat), - - Double = as(vk::format::eR64Sfloat), - Double2 = as(vk::format::eR64G64Sfloat), - Double3 = as(vk::format::eR64G64B64Sfloat), - Double4 = as(vk::format::eR64G64B64A64Sfloat), - - Undefined = as(vk::format::eUndefined), - }; - - enum class BufferUsageFlag : UInt16 { - Vertex = as(vk::BufferUsageFlagBits::eVertexBuffer), - Index = as(vk::BufferUsageFlagBits::eIndexBuffer), - Transfer_Src = as(vk::BufferUsageFlagBits::eTransferSrc), - Transfer_Dst = as(vk::BufferUsageFlagBits::eTransferDst), - Uniform = as(vk::BufferUsageFlagBits::eUniformBuffer), - Storage = as(vk::BufferUsageFlagBits::eStorageBuffer), - Uniform_Texel = as(vk::BufferUsageFlagBits::eUniformTexelBuffer), - Storage_Texel = as(vk::BufferUsageFlagBits::eStorageTexelBuffer), - Indirect = as(vk::BufferUsageFlagBits::eIndirectBuffer), - }; - - enum class ImageUsageFlag : UInt16 { - Transfer_Src = as(vk::ImageUsageFlagBits::eTransferSrc), - Transfer_Dst = as(vk::ImageUsageFlagBits::eTransferDst), - Sampled = as(vk::ImageUsageFlagBits::eSampled), - Storage = as(vk::ImageUsageFlagBits::eStorage), - Color_Attachment = as(vk::ImageUsageFlagBits::eColorAttachment), - Depth_Stencil_Attachment = as(vk::ImageUsageFlagBits::eDepthStencilAttachment), - Transient_Attachment = as(vk::ImageUsageFlagBits::eTransientAttachment), - Input_Attachment = as(vk::ImageUsageFlagBits::eInputAttachment), - }; - - enum class MemoryPropertyFlag : UInt8 { - Device_Local = as(vk::MemoryPropertyFlagBits::eDeviceLocal), - Host_Visible = as(vk::MemoryPropertyFlagBits::eHostVisible), - Host_Coherent = as(vk::MemoryPropertyFlagBits::eHostCoherent), - Host_Cached = as(vk::MemoryPropertyFlagBits::eHostCached), - }; - - enum class CommandBufferLevel : UInt8 { - Primary = as(vk::CommandBufferLevel::ePrimary), - Secondary = as(vk::CommandBufferLevel::eSecondary), - }; - - enum class DescriptorType : UInt8 { - Sampler = as(vk::DescriptorType::eSampler), - Combined_Image_Sampler = as(vk::DescriptorType::eCombinedImageSampler), - Sampled_Image = as(vk::DescriptorType::eSampledImage), - Storage_Image = as(vk::DescriptorType::eStorageImage), - Uniform_Texel_Buffer = as(vk::DescriptorType::eUniformTexelBuffer), - Storage_Texel_Buffer = as(vk::DescriptorType::eStorageTexelBuffer), - Uniform_Buffer = as(vk::DescriptorType::eUniformBuffer), - Storage_Buffer = as(vk::DescriptorType::eStorageBuffer), - Uniform_Buffer_Dynamic = as(vk::DescriptorType::eUniformBufferDynamic), - Storage_Buffer_Dynamic = as(vk::DescriptorType::eStorageBufferDynamic), - Input_Attachment = as(vk::DescriptorType::eInputAttachment), - }; - - enum class CompareOperation : UInt8 { - Never = as(vk::CompareOp::eNever), - Less = as(vk::CompareOp::eLess), - Equal = as(vk::CompareOp::eEqual), - Less_Or_Equal = as(vk::CompareOp::eLessOrEqual), - Greater = as(vk::CompareOp::eGreater), - Not_Equal = as(vk::CompareOp::eNotEqual), - Greater_Or_Equal = as(vk::CompareOp::eGreaterOrEqual), - Always = as(vk::CompareOp::eAlways), - }; - - enum class Filter : UInt32 { - Nearest = as(vk::Filter::eNearest), - Linear = as(vk::Filter::eLinear), - Cubic_Img = as(vk::Filter::eCubicIMG), - }; - - enum class SamplerAddressMode : UInt8 { - Repeat = as(vk::SamplerAddressMode::eRepeat), - Mirrored_Repeat = as(vk::SamplerAddressMode::eMirroredRepeat), - Clamp_To_Edge = as(vk::SamplerAddressMode::eClampToEdge), - Clamp_To_Border = as(vk::SamplerAddressMode::eClampToBorder), - Mirror_Clamp_To_Edge = as(vk::SamplerAddressMode::eMirrorClampToEdge), - }; - - enum class BorderColor : UInt8 { - Float_TRANSPARENT_BLACK = as(vk::BorderColor::eFloatTRANSPARENTBLACK), - Int_TRANSPARENT_BLACK = as(vk::BorderColor::eIntTRANSPARENTBLACK), - Float_Opaque_BLACK = as(vk::BorderColor::eFloatOpaqueBLACK), - Int_Opaque_BLACK = as(vk::BorderColor::eIntOpaqueBLACK), - Float_Opaque_WHITE = as(vk::BorderColor::eFloatOpaqueWHITE), - Int_opaque_WHITE = as(vk::BorderColor::eIntOpaqueWHITE), - }; - - enum class SamplerMipmapMode : UInt8 { - Nearest = as(vk::SamplerMipmapMode::eNearest), - Linear = as(vk::SamplerMipmapMode::eLinear), - }; - - enum class Result : Int32 { - Success = as(vk::Result::eSuccess), - Not_Ready = as(vk::Result::eNotReady), - Timeout = as(vk::Result::eTimeout), - Event_Set = as(vk::Result::eEventSet), - Event_RESET = as(vk::Result::eEventRESET), - Incomplete = as(vk::Result::eIncomplete), - Error_Out_Of_host_Memory = as(vk::Result::eErrorOutOfHostMemory), - Error_Out_Of_Device_Memory = as(vk::Result::eErrorOutOfDeviceMemory), - Error_Initialization_Failed = as(vk::Result::eErrorInitializationFailed), - Error_Device_Lost = as(vk::Result::eErrorDeviceLost), - Error_Memory_Map_Failed = as(vk::Result::eErrorMemoryMapFailed), - Error_Layer_Not_Present = as(vk::Result::eErrorLayerNotPresent), - Error_EXTension_Not_Present = as(vk::Result::eErrorExtensionNotPresent), - Error_Feature_Not_Present = as(vk::Result::eErrorFeatureNotPresent), - Error_Incompatible_Driver = as(vk::Result::eErrorIncompatibleDriver), - Error_Too_Many_Objects = as(vk::Result::eErrorTooManyObjects), - Error_Format_Not_Supported = as(vk::Result::eErrorFormatNotSupported), - Error_Fragmented_Pool = as(vk::Result::eErrorFragmentedPool), - Error_Unknown = as(vk::Result::eErrorUnknown), - Error_Out_Of_Pool_Memory = as(vk::Result::eErrorOutOfPoolMemory), - Error_Invalid_EXTernal_Handle = as(vk::Result::eErrorInvalidExternalHandle), - Error_Fragmentation = as(vk::Result::eErrorFragmentation), - Error_Invalid_Opaque_Capture_Address - = as(vk::Result::eErrorInvalidOpaqueCaptureAddress), - Error_Surface_Lost = as(vk::Result::eErrorSurfaceLostKHR), - Error_Native_Window_In_Use = as(vk::Result::eErrorNativeWindowInUseKHR), - Suboptimal = as(vk::Result::eSuboptimalKHR), - Error_Out_Of_Data = as(vk::Result::eErrorOutOfDateKHR), - Error_Incompatible_Display = as(vk::Result::eErrorIncompatibleDisplayKHR), - Error_Validation_Failed = as(vk::Result::eErrorValidationFailedEXT), - Error_Not_Permitted = as(vk::Result::eErrorNotPermittedEXT), -#if defined(VK_USE_PLATFORM_WIN32_KHR) - Error_Fullscreen_Exclusive_Mode_Lost - = as(vk::Result::eErrorFullScreenExclusiveModeLostEXT), -#endif - Thread_Idle = as(vk::Result::eThreadIdleKHR), - Thread_Done = as(vk::Result::eThreadDoneKHR), - Operation_Deferred = as(vk::Result::eOperationDeferredKHR), - Operation_Not_Deferred = as(vk::Result::eOperationNotDeferredKHR), - Pipeline_Compile_Required = as(vk::Result::ePipelineCompileRequired), - }; - - enum class ImageType : UInt8 { - T1D = as(vk::ImageType::e1D), - T2D = as(vk::ImageType::e2D), - T3D = as(vk::ImageType::e3D), - }; - - enum class ImageViewType : UInt8 { - T1D = as(vk::ImageViewType::e1D), - T2D = as(vk::ImageViewType::e2D), - T3D = as(vk::ImageViewType::e3D), - Cube = as(vk::ImageViewType::eCube), - T1D_Array = as(vk::ImageViewType::e1DArray), - T2D_Array = as(vk::ImageViewType::e2DArray), - Cube_Array = as(vk::ImageViewType::eCubeArray), - }; - - enum class DebugObjectType : UInt32 { - Unknown = as(vk::ObjectType::eUnknown), - Instance = as(vk::ObjectType::eInstance), - Physical_Device = as(vk::ObjectType::ePhysicalDevice), - Device = as(vk::ObjectType::eDevice), - Queue = as(vk::ObjectType::eQueue), - Semaphore = as(vk::ObjectType::eSemaphore), - Command_Buffer = as(vk::ObjectType::eCommandBuffer), - Fence = as(vk::ObjectType::eFence), - Device_Memory = as(vk::ObjectType::eDeviceMemory), - Buffer = as(vk::ObjectType::eBuffer), - Image = as(vk::ObjectType::eImage), - Event = as(vk::ObjectType::eEvent), - Query_Pool = as(vk::ObjectType::eQueryPool), - Buffer_View = as(vk::ObjectType::eBufferView), - Image_View = as(vk::ObjectType::eImageView), - Shader_Module = as(vk::ObjectType::eShaderModule), - Pipeline_Cache = as(vk::ObjectType::ePipelineCache), - Pipeline_Layout = as(vk::ObjectType::ePipelineLayout), - Render_Pass = as(vk::ObjectType::eRenderPass), - Pipeline = as(vk::ObjectType::ePipeline), - PipelineLayout = as(vk::ObjectType::ePipelineLayout), - Descriptor_Set_Layout = as(vk::ObjectType::eDescriptorSetLayout), - Sampler = as(vk::ObjectType::eSampler), - Descriptor_Pool = as(vk::ObjectType::eDescriptorPool), - Descriptor_Set = as(vk::ObjectType::eDescriptorSet), - FrameBuffer = as(vk::ObjectType::eFramebuffer), - Command_Pool = as(vk::ObjectType::eCommandPool), - Surface = as(vk::ObjectType::eSurfaceKHR), - Swapchain = as(vk::ObjectType::eSwapchainKHR), - Debug_Report_Callback = as(vk::ObjectType::eDebugReportCallbackEXT), - Display_KHR = as(vk::ObjectType::eDisplayKHR), - }; - - enum class AccessFlag : UInt32 { - NONE = as(vk::AccessFlagBits::eNONEKHR), - Indirect_Command_Read = as(vk::AccessFlagBits::eIndirectCommandRead), - Vertex_Attribute_Read = as(vk::AccessFlagBits::eVertexAttributeRead), - Uniform_Read = as(vk::AccessFlagBits::eUniformRead), - Input_Attachment_Read = as(vk::AccessFlagBits::eInputAttachmentRead), - Shader_Read = as(vk::AccessFlagBits::eShaderRead), - Shader_Write = as(vk::AccessFlagBits::eShaderWrite), - Color_Attachment_Read = as(vk::AccessFlagBits::eColorAttachmentRead), - Color_Attachment_Write = as(vk::AccessFlagBits::eColorAttachmentWrite), - Depth_Stencil_Attachment_Read - = as(vk::AccessFlagBits::eDepthStencilAttachmentRead), - Depth_Stencil_Attachment_Write - = as(vk::AccessFlagBits::eDepthStencilAttachmentWrite), - Transfer_Read = as(vk::AccessFlagBits::eTransferRead), - Transfer_Write = as(vk::AccessFlagBits::eTransferWrite), - Host_Read = as(vk::AccessFlagBits::eHostRead), - Host_Write = as(vk::AccessFlagBits::eHostWrite), - Memory_Read = as(vk::AccessFlagBits::eMemoryRead), - Memory_Write = as(vk::AccessFlagBits::eMemoryWrite), - }; - - enum class PipelineStageFlag : UInt32 { - NONE = as(vk::PipelineStageFlagBits::eNONEKHR), - Top_Of_Pipe = as(vk::PipelineStageFlagBits::eTopOfPipe), - Draw_Indirect = as(vk::PipelineStageFlagBits::eDrawIndirect), - Vertex_Input = as(vk::PipelineStageFlagBits::eVertexInput), - Vertex_Shader = as(vk::PipelineStageFlagBits::eVertexShader), - Tessellation_Control_Shader - = as(vk::PipelineStageFlagBits::eTessellationControlShader), - Tessellation_Evaluation_Shader - = as(vk::PipelineStageFlagBits::eTessellationEvaluationShader), - Geometry_Shader = as(vk::PipelineStageFlagBits::eGeometryShader), - Fragment_Shader = as(vk::PipelineStageFlagBits::eFragmentShader), - Early_Fragment_Tests = as(vk::PipelineStageFlagBits::eEarlyFragmentTests), - Late_Fragment_Tests = as(vk::PipelineStageFlagBits::eLateFragmentTests), - Color_Attachment_Output = as(vk::PipelineStageFlagBits::eColorAttachmentOutput), - Compute_Shader = as(vk::PipelineStageFlagBits::eComputeShader), - Transfer = as(vk::PipelineStageFlagBits::eTransfer), - Bottom_Of_Pipe = as(vk::PipelineStageFlagBits::eBottomOfPipe), - Host = as(vk::PipelineStageFlagBits::eHost), - All_Graphics = as(vk::PipelineStageFlagBits::eAllGraphics), - All_Commands = as(vk::PipelineStageFlagBits::eAllCommands), - }; - - enum class DependencyFlag : UInt8 { - NONE = 0, - By_Region = as(vk::DependencyFlagBits::eByRegion), - Device_Group = as(vk::DependencyFlagBits::eByRegion), - View_Local = as(vk::DependencyFlagBits::eViewLocal), - }; - - enum class DynamicState : UInt8 { - Viewport = as(vk::DynamicState::eViewport), - Scissor = as(vk::DynamicState::eScissor), - Line_Width = as(vk::DynamicState::eLineWidth), - Depth_Bias = as(vk::DynamicState::eDepthBias), - Blend_Constants = as(vk::DynamicState::eBlendConstants), - Depth_Bounds = as(vk::DynamicState::eDepthBounds), - Stencil_Compare_Mask = as(vk::DynamicState::eStencilCompareMask), - Stencil_Write_Mask = as(vk::DynamicState::eStencilWriteMask), - Stencil_Reference = as(vk::DynamicState::eStencilReference), - }; - - enum class ImageTiling : UInt32 { - Optimal = as(vk::ImageTiling::eOptimal), - Linear = as(vk::ImageTiling::eLinear), - DRM_Ext = as(vk::ImageTiling::eDrmFormatModifierEXT), - }; - - enum class StencilFaceFlag : UInt8 { - Front = as(vk::StencilFaceFlagBits::eFront), - Back = as(vk::StencilFaceFlagBits::eBack), - Front_And_Back = Front | Back - }; - - enum class GeometryType : UInt8 { - Triangles = as(vk::GeometryTypeKHR::eTriangles), - AABBS = as(vk::GeometryTypeKHR::eAabbs), - Instances = as(vk::GeometryTypeKHR::eInstances) - }; - - enum class GeometryFlag : UInt8 { - Opaque = as(vk::GeometryFlagBitsKHR::eOpaque), - No_Duplicate_Any_Hit_Invocation - = as(vk::GeometryFlagBitsKHR::eNoDuplicateAnyHitInvocation) - }; - - enum class ColorSpace : UInt32 { - SRGB_NonLinear = as(vk::ColorSpaceKHR::eSrgbNonlinear), - Display_P3_NonLinear = as(vk::ColorSpaceKHR::eDisplayP3NonlinearEXT), - // COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT = 1000104002, - // COLOR_SPACE_DISPLAY_P3_LINEAR_EXT = 1000104003, - // COLOR_SPACE_DCI_P3_NONLINEAR_EXT = 1000104004, - // COLOR_SPACE_BT709_LINEAR_EXT = 1000104005, - // COLOR_SPACE_BT709_NONLINEAR_EXT = 1000104006, - // COLOR_SPACE_BT2020_LINEAR_EXT = 1000104007, - // COLOR_SPACE_HDR10_ST2084_EXT = 1000104008, - // COLOR_SPACE_DOLBYVISION_EXT = 1000104009, - // COLOR_SPACE_HDR10_HLG_EXT = 1000104010, - // COLOR_SPACE_ADOBERGB_LINEAR_EXT = 1000104011, - // COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012, - // COLOR_SPACE_PASS_THROUGH_EXT = 1000104013, - // COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT = 1000104014, - // COLOR_SPACE_DISPLAY_NATIVE_AMD = 1000213000, - // COLORSPACE_SRGB_NONLINEAR_KHR = COLOR_SPACE_SRGB_NONLINEAR_KHR, - // COLOR_SPACE_DCI_P3_LINEAR_EXT = COLOR_SPACE_DISPLAY_P3_LINEAR_EXT, - }; - - enum class PresentMode : UInt32 { - Immediate = as(vk::PresentModeKHR::eImmediate), - Mailbox = as(vk::PresentModeKHR::eMailbox), - Fifo = as(vk::PresentModeKHR::eFifo), - Fifo_Relaxed = as(vk::PresentModeKHR::eFifoRelaxed), - Shared_Demand_Refresh = as(vk::PresentModeKHR::eSharedDemandRefresh), - Shared_Continuous_Refresh = as(vk::PresentModeKHR::eSharedContinuousRefresh), - }; - - struct SurfaceFormat { - PixelFormat format; - ColorSpace color_space; - }; - - struct MemoryBarrier { - AccessFlag src; - AccessFlag dst; - }; - - struct RenderCapabilities { - struct { - bool robust_buffer_access; - bool full_draw_index_uint32; - bool image_cube_array; - bool independent_blend; - bool geometry_shader; - bool tessellation_shader; - bool sampler_rate_shading; - bool dual_src_blend; - bool logic_op; - bool multi_draw_indirect; - bool draw_indirect_first_instance; - bool depth_clamp; - bool depth_bias_clamp; - bool fill_Mode_non_solid; - bool depth_bounds; - bool wide_lines; - bool large_points; - bool alpha_to_one; - bool multi_viewport; - bool sampler_anisotropy; - bool texture_compression_etc2; - bool texture_compression_astc_ldr; - bool texture_compression_bc; - bool occlusion_query_precise; - bool pipeline_statistics_query; - bool vertex_pipeline_stores_and_atomics; - bool fragment_stores_and_atomics; - bool shader_tessellation_and_geometry_point_size; - bool shader_image_gather_extended; - bool shader_storage_image_extended_formats; - bool shader_storage_image_multisample; - bool shader_storage_image_read_without_format; - bool shader_storage_image_write_without_format; - bool shader_uniform_buffer_array_dynamic_indexing; - bool shader_sampled_image_array_dynamic_indexing; - bool shader_storage_buffer_array_dynamic_indexing; - bool shader_storage_image_array_dynamic_indexing; - bool shader_clip_distance; - bool shader_cull_distance; - bool shader_float_64; - bool shader_int_64; - bool shader_int_16; - bool shader_resource_residency; - bool shader_resource_min_lod; - bool sparse_binding; - bool sparse_residency_buffer; - bool sparse_residency_image_2D; - bool sparse_residency_image_3D; - bool sparse_residency_2_samples; - bool sparse_residency_4_samples; - bool sparse_residency_6_samples; - bool sparse_residency_8_samples; - bool sparse_residency_16_samples; - bool sparse_residency_aliased; - bool variable_multisample_rate; - bool inherited_queries; - } features; - - struct { - UInt32 max_image_dimension_1D; - UInt32 max_image_dimension_2D; - UInt32 max_image_dimension_3D; - UInt32 max_image_dimension_cube; - UInt32 max_image_array_layers; - UInt32 max_texel_buffer_elements; - UInt32 max_uniform_buffer_range; - std::optional max_storage_buffer_range; - UInt32 max_push_constants_size; - std::optional max_memory_allocation_count; - std::optional max_sampler_allocation_count; - std::optional buffer_image_granularity; - std::optional sparse_address_space_size; - std::optional max_bound_descriptor_sets; - UInt32 max_per_stage_descriptor_samplers; - UInt32 max_per_stage_descriptor_uniform_buffers; - UInt32 max_per_stage_descriptor_storage_buffers; - UInt32 max_per_stage_descriptor_sampled_images; - UInt32 max_per_stage_descriptor_storage_images; - std::optional max_per_stage_descriptor_input_attachments; - std::optional max_per_stage_resources; - UInt32 max_descriptor_set_samplers; - UInt32 max_descriptor_set_uniform_buffers; - UInt32 max_descriptor_set_uniform_buffers_dynamic; - UInt32 max_descriptor_set_storage_buffers; - UInt32 max_descriptor_set_storage_buffers_dynamic; - UInt32 max_descriptor_set_sampled_images; - UInt32 max_descriptor_set_storage_images; - std::optional max_descriptor_set_input_attachments; - UInt32 max_vertex_input_attributes; - UInt32 max_vertex_input_bindings; - UInt32 max_vertex_input_attribute_offset; - std::optional max_vertex_input_binding_stride; - UInt32 max_vertex_output_components; - UInt32 max_tessellation_generation_level; - UInt32 max_tessellation_patch_size; - UInt32 max_tessellation_control_per_vertex_input_components; - UInt32 max_tessellation_control_per_vertex_output_components; - UInt32 max_tessellation_control_per_patch_output_components; - UInt32 max_tessellation_control_total_output_components; - UInt32 max_tessellation_evaluation_input_components; - UInt32 max_tessellation_evaluation_output_components; - UInt32 max_geometry_shader_invocations; - UInt32 max_geometry_input_components; - UInt32 max_geometry_output_components; - UInt32 max_geometry_output_vertices; - UInt32 max_geometry_total_output_components; - UInt32 max_fragment_input_components; - UInt32 max_fragment_output_attachments; - UInt32 max_fragment_dual_src_attachments; - UInt32 max_fragment_combined_output_resources; - UInt32 max_compute_shared_memory_size; - std::array max_compute_work_group_count; - UInt32 max_compute_work_group_invocations; - std::array max_compute_work_group_size; - std::optional sub_pixel_precision_bits; - std::optional sub_texel_precision_bits; - std::optional mipmap_precision_bits; - UInt32 max_draw_indexed_index_value; - std::optional max_draw_indirect_count; - float max_sampler_lod_bias; - float max_sampler_anisotropy; - UInt32 max_viewports; - std::array max_viewport_dimensions; - std::array viewport_bounds_range; - std::optional viewport_sub_pixel_bits; - std::optional min_memory_map_alignment; - std::optional min_texel_buffer_offset_alignment; - UInt64 min_uniform_buffer_offset_alignment; - UInt64 min_storage_buffer_offset_alignment; - Int32 min_texel_offset; - UInt32 max_texel_offset; - Int32 min_texel_gather_offset; - UInt32 max_texel_gather_offset; - float min_interpolation_offset; - float max_interpolation_offset; - std::optional sub_pixel_interpolation_offset_bits; - UInt32 max_framebuffer_width; - UInt32 max_framebuffer_height; - UInt32 max_framebuffer_layers; - SampleCountFlag framebuffer_color_sample_counts; - SampleCountFlag framebuffer_depth_sample_counts; - SampleCountFlag framebuffer_stencil_sample_counts; - SampleCountFlag framebuffer_no_attachments_sample_counts; - UInt32 max_color_attachments; - SampleCountFlag sampled_image_color_sample_counts; - SampleCountFlag sampled_image_integer_sample_counts; - SampleCountFlag sampled_image_depth_sample_counts; - SampleCountFlag sampled_image_stencil_sample_counts; - SampleCountFlag storage_image_sample_counts; - UInt32 max_sample_mask_words; - bool timestamp_compute_and_engine; - float timestamp_period; - UInt32 max_clip_distances; - UInt32 max_cull_distances; - UInt32 max_combined_clip_and_cull_distances; - UInt32 discrete_queue_priorities; - std::array point_size_range; - std::array line_width_range; - float point_size_granularity; - float line_width_granularity; - bool strict_lines; - bool standard_sample_locations; - std::optional optimal_buffer_copy_offset_alignment; - std::optional optimal_buffer_copy_row_pitch_alignment; - UInt64 non_coherent_atom_size; - } limits; - }; - - struct ImageSubresourceRange { - ImageAspectMaskFlag aspect_mask = ImageAspectMaskFlag::Color; - - UInt32 base_mip_level = 0u; - UInt32 level_count = 1u; - UInt32 base_array_layer = 0u; - UInt32 layer_count = 1u; - }; - - struct ImageSubresourceLayers { - ImageAspectMaskFlag aspect_mask = ImageAspectMaskFlag::Color; - - UInt32 mip_level = 0u; - UInt32 base_array_layer = 0u; - UInt32 layer_count = 1u; - }; - - struct Viewport { - math::Vector2F position; - math::ExtentF extent; - math::Vector2F depth; - - constexpr operator vk::Viewport() const noexcept; - }; - - struct Scissor { - math::Vector2I offset; - math::ExtentU extent; - - constexpr operator vk::Rect2D() const noexcept; - }; - - struct ClearColor { - RGBColorF color = stormkit::RGBColorDef::SILVER; - }; - - struct ClearDepthStencil { - float depth = 1.f; - UInt32 stencil = 0; - }; - - using ClearValue = std::variant; - - struct BufferImageCopy { - UInt32 buffer_offset; - UInt32 buffer_row_length; - UInt32 buffer_image_height; - - ImageSubresourceLayers subresource_layers; - - math::Vector3I offset; - math::ExtentU extent; - }; - - struct BlitRegion { - ImageSubresourceLayers src; - ImageSubresourceLayers dst; - - std::array src_offset; - std::array dst_offset; - }; - - struct PushConstantRange { - ShaderStageFlag stages; - UInt32 offset; - RangeExtent size; - }; - - struct PhysicalDeviceInfo { - UInt64 device_id; - std::string device_name; - UInt64 vendor_id; - std::string vendor_name; - - UInt32 api_major_version; - UInt32 api_minor_version; - UInt32 api_patch_version; - - UInt32 driver_major_version; - UInt32 driver_minor_version; - UInt32 driver_patch_version; - - std::array pipeline_cache_uuid; - - PhysicalDeviceType type; - }; - - struct QueueFamily { - QueueFlag flags; - UInt32 count; - }; - - using ClearValue = std::variant; - using SpirvID = UInt32; - - template - using Expected = std::expected; - - [[nodiscard]] - constexpr auto isDepthOnlyFormat(PixelFormat format) noexcept -> bool; - [[nodiscard]] - constexpr auto isDepthStencilFormat(PixelFormat format) noexcept -> bool; - [[nodiscard]] - constexpr auto isDepthFormat(PixelFormat format) noexcept -> bool; - - [[nodiscard]] - constexpr auto get_format_channel_count(PixelFormat format) noexcept -> UInt8; - [[nodiscard]] - constexpr auto getArraySizeByChannelFor(PixelFormat format) noexcept -> UInt8; - - [[nodiscard]] - auto computeMipLevel(const math::ExtentU& extent) noexcept -> UInt32; - [[nodiscard]] - constexpr auto - computeUniformBufferOffsetAlignement(RangeExtent size, - const RenderCapabilities& capabilities) noexcept - -> RangeExtent; - - [[nodiscard]] - auto to_string(const PhysicalDeviceInfo& data) noexcept; - - } // namespace stormkit::gpu - - ASCASTER_STRICT_DECLARE(vk::Viewport, stormkit::gpu::Viewport) - ASCASTER_STRICT_DECLARE(vk::Rect2D, stormkit::gpu::Scissor) - - FLAG_ENUM(stormkit::gpu::QueueFlag) - FLAG_ENUM(stormkit::gpu::ShaderStageFlag) - FLAG_ENUM(stormkit::gpu::SampleCountFlag) - FLAG_ENUM(stormkit::gpu::ColorComponentFlag) - FLAG_ENUM(stormkit::gpu::ImageAspectMaskFlag) - FLAG_ENUM(stormkit::gpu::ImageCreateFlag) - FLAG_ENUM(stormkit::gpu::CullModeFlag) - FLAG_ENUM(stormkit::gpu::BufferUsageFlag) - FLAG_ENUM(stormkit::gpu::ImageUsageFlag) - FLAG_ENUM(stormkit::gpu::MemoryPropertyFlag) - FLAG_ENUM(stormkit::gpu::AccessFlag) - FLAG_ENUM(stormkit::gpu::PipelineStageFlag) - FLAG_ENUM(stormkit::gpu::DependencyFlag) - FLAG_ENUM(stormkit::gpu::StencilFaceFlag) - FLAG_ENUM(stormkit::gpu::GeometryFlag) - HASH_FUNC(stormkit::gpu::Viewport, value.position, value.extent, value.depth) - HASH_FUNC(stormkit::gpu::Scissor, value.offset, value.extent) -} - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::gpu { - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE constexpr auto isDepthOnlyFormat(PixelFormat format) noexcept -> bool { - return format == PixelFormat::Depth16 - or format == PixelFormat::Depth24 - or format == PixelFormat::Depth32F; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE constexpr auto isDepthStencilFormat(PixelFormat format) noexcept -> bool { - return format == PixelFormat::Depth16_Stencil8 - or format == PixelFormat::Depth24_Stencil8 - or format == PixelFormat::Depth32F_Stencil8; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE constexpr auto isDepthFormat(PixelFormat format) noexcept -> bool { - return isDepthOnlyFormat(format) or isDepthStencilFormat(format); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE constexpr auto get_format_channel_count(PixelFormat format) noexcept - -> UInt8 { - switch (format) { - case PixelFormat::R8_SNORM: - case PixelFormat::R8_UNORM: - case PixelFormat::R16_SNORM: - case PixelFormat::R16_UNORM: - case PixelFormat::R8I: - case PixelFormat::R8U: - case PixelFormat::R16I: - case PixelFormat::R16U: - case PixelFormat::R32I: - case PixelFormat::R32U: - case PixelFormat::R16F: - case PixelFormat::R32F: - case PixelFormat::Depth16: - case PixelFormat::Depth24: - case PixelFormat::Depth32F: return 1; - - case PixelFormat::RG8_SNORM: - case PixelFormat::RG8_UNORM: - case PixelFormat::RG16_SNORM: - case PixelFormat::RG16_UNORM: - case PixelFormat::RG8I: - case PixelFormat::RG8U: - case PixelFormat::RG16I: - case PixelFormat::RG16U: - case PixelFormat::RG32I: - case PixelFormat::RG32U: - case PixelFormat::RG16F: - case PixelFormat::RG32F: - case PixelFormat::Depth16_Stencil8: - case PixelFormat::Depth24_Stencil8: - case PixelFormat::Depth32F_Stencil8: return 2; - - case PixelFormat::RGB8_SNORM: - case PixelFormat::RGB8_UNORM: - case PixelFormat::RGB16_SNORM: - case PixelFormat::RGB16_UNORM: - case PixelFormat::BGR8_UNORM: - case PixelFormat::RGB8I: - case PixelFormat::RGB8U: - case PixelFormat::RGB16I: - case PixelFormat::RGB16U: - case PixelFormat::RGB32I: - case PixelFormat::RGB32U: - case PixelFormat::RGB16F: - case PixelFormat::RGB32F: - case PixelFormat::SRGB8: - case PixelFormat::SBGR8: - case PixelFormat::R5_G6_B5_UNorm_Pack16: - case PixelFormat::BG11_R10F_Pack32: return 3; - - case PixelFormat::RGBA8_SNORM: - case PixelFormat::RGBA8_UNORM: - case PixelFormat::RGBA16_SNORM: - case PixelFormat::RGBA16_UNORM: - case PixelFormat::BGRA8_UNORM: - case PixelFormat::RGBA8I: - case PixelFormat::RGBA8U: - case PixelFormat::RGBA16I: - case PixelFormat::RGBA16U: - case PixelFormat::RGBA32I: - case PixelFormat::RGBA32U: - case PixelFormat::RGBA16F: - case PixelFormat::RGBA32F: - case PixelFormat::SRGBA8: - case PixelFormat::SBGRA8: return 4; - - default: break; - } - - return 0u; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE constexpr auto getArraySizeByChannelFor(PixelFormat format) noexcept - -> UInt8 { - switch (format) { - case PixelFormat::R8_SNORM: - case PixelFormat::R8_UNORM: - case PixelFormat::RG8_SNORM: - case PixelFormat::RG8_UNORM: - case PixelFormat::R8I: - case PixelFormat::R8U: - case PixelFormat::RG8I: - case PixelFormat::RG8U: - case PixelFormat::RGB8_SNORM: - case PixelFormat::RGB8_UNORM: - case PixelFormat::BGR8_UNORM: - case PixelFormat::RGB8I: - case PixelFormat::RGB8U: - case PixelFormat::RGBA8_SNORM: - case PixelFormat::RGBA8_UNORM: - case PixelFormat::RGBA16_SNORM: - case PixelFormat::BGRA8_UNORM: - case PixelFormat::SRGB8: - case PixelFormat::SBGR8: - case PixelFormat::SRGBA8: - case PixelFormat::SBGRA8: return 1u; - - case PixelFormat::R16_SNORM: - case PixelFormat::R16_UNORM: - case PixelFormat::R16I: - case PixelFormat::R16U: - case PixelFormat::RG16_SNORM: - case PixelFormat::RG16_UNORM: - case PixelFormat::RG16I: - case PixelFormat::RG16U: - case PixelFormat::RG16F: - case PixelFormat::RGB16I: - case PixelFormat::RGB16U: - case PixelFormat::RGB16F: - case PixelFormat::RGBA16I: - case PixelFormat::RGBA16U: - case PixelFormat::RGBA16F: - case PixelFormat::R16F: return 2u; - - case PixelFormat::R32I: - case PixelFormat::R32U: - case PixelFormat::R32F: - case PixelFormat::RG32I: - case PixelFormat::RG32U: - case PixelFormat::RG32F: - case PixelFormat::RGB16_SNORM: - case PixelFormat::RGB32I: - case PixelFormat::RGB32U: - case PixelFormat::RGB32F: - case PixelFormat::RGBA8I: - case PixelFormat::RGBA8U: - case PixelFormat::RGBA32I: - case PixelFormat::RGBA32U: - case PixelFormat::RGBA32F: return 4u; - - default: break; - } - - return 0u; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE constexpr Viewport::operator vk::Viewport() const noexcept { - return vk::Viewport {} - .setX(position.x) - .setY(position.y) - .setWidth(extent.width) - .setHeight(extent.height) - .setMinDepth(depth.x) - .setMaxDepth(depth.y); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE constexpr Scissor::operator vk::Rect2D() const noexcept { - return vk::Rect2D {} - .setOffset(as(offset)) - .set_extent(as(extent)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto computeMipLevel(const math::ExtentU& extent) noexcept -> UInt32 { - const auto as_float = math::ExtentF { extent }; - - return as(math::floor(math::log2(math::max(as_float.width, as_float.height)))) + 1; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE constexpr auto - computeUniformBufferOffsetAlignement(RangeExtent size, - const RenderCapabilities& capabilities) noexcept - -> RangeExtent { - 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); - - return size; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto to_string(const PhysicalDeviceInfo& data) noexcept { - return std::format("[PhysicalDeviceInfo:\n" - " .device_id = {:#06x},\n" - " .device_name = {},\n" - " .vendor_id = {:#06x},\n" - " .vendor_name = {},\n" - " .api_version = {}.{}.{},\n" - " .driver_version = {}.{}.{},\n" - " .type = {}]", - data.device_id, - data.device_name, - data.vendor_id, - data.vendor_name, - data.api_major_version, - data.api_minor_version, - data.api_patch_version, - data.driver_major_version, - data.driver_minor_version, - data.driver_patch_version, - data.type); - } -} // namespace stormkit::gpu - -///////////////////////////////////// -///////////////////////////////////// -ASCASTER_STRICT_DEFINE(vk::Viewport, stormkit::gpu::Viewport) { - return from.operator vk::Viewport(); -} - -///////////////////////////////////// -///////////////////////////////////// -ASCASTER_STRICT_DEFINE(vk::Rect2D, stormkit::gpu::Scissor) { - return from.operator vk::Rect2D(); -} diff --git a/modules/stormkit/Gpu/Execution.mpp b/modules/stormkit/Gpu/Execution.mpp deleted file mode 100644 index f31a5fb94..000000000 --- a/modules/stormkit/Gpu/Execution.mpp +++ /dev/null @@ -1,11 +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.Gpu:Execution; - -export import :Execution.CommandBuffer; -export import :Execution.Descriptors; -export import :Execution.Pipeline; -export import :Execution.RasterPipelineState; -export import :Execution.RenderPass; diff --git a/modules/stormkit/Gpu/Execution/CommandBuffer.mpp b/modules/stormkit/Gpu/Execution/CommandBuffer.mpp deleted file mode 100644 index 734de954f..000000000 --- a/modules/stormkit/Gpu/Execution/CommandBuffer.mpp +++ /dev/null @@ -1,1468 +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.CommandBuffer; - -import std; - -import frozen; - -import stormkit.core; -import stormkit.Gpu.Vulkan; - -import :Core; -import :Resource; -import :Execution.Descriptors; -import :Execution.RenderPass; -import :Execution.Pipeline; - -export namespace stormkit::gpu { - struct SubmitInfo { - std::span> wait_semaphores = {}; - std::span wait_dst_stages = {}; - std::span> command_buffers = {}; - std::span> signal_semaphores = {}; - }; - - class STORMKIT_API Queue { - struct Tag {}; - - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::Queue; - - Queue(const Device& device, const Device::QueueEntry& entry, Tag); - ~Queue(); - - Queue(const Queue&) = delete; - auto operator=(const Queue&) = delete; - - Queue(Queue&&) noexcept; - auto operator=(Queue&&) noexcept -> Queue&; - - [[nodiscard]] - static auto create(const Device& device, const Device::QueueEntry& entry) noexcept - -> Expected; - [[nodiscard]] - static auto allocate(const Device& device, const Device::QueueEntry& entry) noexcept - -> Expected>; - - auto waitIdle() const noexcept -> void; - - auto submit(std::span submit_infos, - OptionalRef fence = std::nullopt) const noexcept -> void; - - auto submit(const SubmitInfo& submit_info, - OptionalRef fence = std::nullopt) const noexcept -> void; - - [[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 vkHandle() const noexcept -> const vk::raii::Queue&; - - private: - Device::QueueEntry m_entry; - - DeferInit m_vk_queue; - }; - - class CommandPool; - - struct InheritanceInfo { - const RenderPass* render_pass = nullptr; - UInt32 subpass = 0; - const FrameBuffer* framebuffer = nullptr; - }; - - template - concept IsImage = requires(T&& img) { - img.extent(); - img.format(); - img.type(); - img.samples(); - img.layers(); - img.faces(); - img.mipLevels(); - img.usages(); - img.vkHandle(); - }; - - class STORMKIT_API CommandBuffer { - struct Tag {}; - - public: - enum class State { - Initial, - Recording, - Executable - }; - - static constexpr auto DEBUG_TYPE = DebugObjectType::Command_Buffer; - - using Deleter = std::function; - CommandBuffer(CommandBufferLevel, vk::raii::CommandBuffer&&, Deleter, Tag); - ~CommandBuffer(); - - CommandBuffer(const CommandBuffer&) = delete; - auto operator=(const CommandBuffer&) -> CommandBuffer& = delete; - - CommandBuffer(CommandBuffer&&) noexcept; - auto operator=(CommandBuffer&&) noexcept -> CommandBuffer&; - - [[nodiscard]] - static auto create(CommandBufferLevel, vk::raii::CommandBuffer&&, Deleter) noexcept - -> CommandBuffer; - [[nodiscard]] - static auto allocate(CommandBufferLevel, vk::raii::CommandBuffer&&, Deleter) noexcept - -> std::unique_ptr; - - auto reset() noexcept -> void; - auto submit(const Queue& queue, - std::span> wait_semaphores = {}, - std::span wait_dst_stages = {}, - std::span> signal_semaphores = {}, - OptionalRef fence = std::nullopt) const noexcept -> void; - - [[nodiscard]] - auto state() const noexcept -> State; - [[nodiscard]] - auto level() const noexcept -> CommandBufferLevel; - - auto beginDebugRegion(std::string_view name, - const RGBColorF& color = RGBColorDef::WHITE) -> void; - auto insertDebugLabel(std::string_view name, - const RGBColorF& color = RGBColorDef::WHITE) -> void; - auto endDebugRegion() -> void; - - auto begin(bool one_time_submit = false, - std::optional inheritance_info = std::nullopt) -> void; - auto end() -> void; - - auto beginRenderPass(const RenderPass& render_pass, - const FrameBuffer& framebuffer, - std::span clear_values = std::array { ClearValue { - ClearColor { .color = RGBColorDef::SILVER } } }, - bool secondary_commandbuffers = false) -> void; - auto nextSubPass() -> void; - auto endRenderPass() -> void; - - auto bindPipeline(const Pipeline& pipeline) -> void; - auto setViewport(UInt32 first_viewport, std::span viewports) -> void; - auto setScissor(UInt32 first_scissor, std::span scissors) -> void; - auto setLineWidth(float width) -> void; - auto setDepthBias(float constant_factor, float clamp, float slope_factor) -> void; - auto setBlendConstants(std::span constants) -> void; - auto setDepthBounds(float min, float max) -> void; - auto setStencilCompareMask(StencilFaceFlag face, UInt32 mask) -> void; - auto setStencilWriteMask(StencilFaceFlag face, UInt32 mask) -> void; - auto setStencilReference(StencilFaceFlag face, UInt32 reference) -> void; - - auto dispatch(UInt32 group_count_x, UInt32 group_count_y, UInt32 group_count_z) -> void; - - auto draw(UInt32 vertex_count, - UInt32 instance_count = 1u, - UInt32 first_vertex = 0, - UInt32 first_instance = 0) -> void; - auto drawIndexed(UInt32 index_count, - UInt32 instance_count = 1u, - UInt32 first_index = 0u, - Int32 vertex_offset = 0, - UInt32 first_instance = 0u) -> void; - auto - drawIndirect(const Buffer& buffer, RangeExtent offset, UInt32 draw_count, UInt32 stride) - -> void; - auto drawIndexedIndirect(const Buffer& buffer, - RangeExtent offset, - UInt32 draw_count, - UInt32 stride) -> void; - - auto bindVertexBuffers(std::span> buffers, - std::span offsets) -> void; - auto bindIndexBuffer(const Buffer& buffer, UInt64 offset = 0, bool large_indices = false) - -> void; - auto bindDescriptorSets(const Pipeline& pipeline, - const PipelineLayout& layout, - std::span> descriptor_sets, - std::span dynamic_offsets = {}) -> void; - - auto copyBuffer(const Buffer& src, - const Buffer& dst, - RangeExtent size, - UInt64 src_offset = 0u, - UInt64 dst_offset = 0u) -> void; - auto copyBufferToImage(const Buffer& src, - const IsImage auto& dst, - std::span buffer_image_copies = {}) -> void; - auto copyImageToBuffer(const IsImage auto& src, - const Buffer& dst, - std::span buffer_image_copies = {}) -> void; - auto copyImage(const IsImage auto& src, - const IsImage auto& dst, - ImageLayout src_layout, - ImageLayout dst_layout, - const ImageSubresourceLayers& src_subresource_layers, - const ImageSubresourceLayers& dst_subresource_layers, - const math::ExtentU& extent) -> void; - - auto resolveImage(const IsImage auto& src, - const IsImage auto& dst, - ImageLayout src_layout, - ImageLayout dst_layout, - const ImageSubresourceLayers& src_subresource_layers = {}, - const ImageSubresourceLayers& dst_subresource_layers = {}) -> void; - - auto blitImage(const IsImage auto& src, - const IsImage auto& dst, - ImageLayout src_layout, - ImageLayout dst_layout, - std::span regions, - Filter filter) -> void; - - auto transitionImageLayout(const IsImage auto& image, - ImageLayout src_layout, - ImageLayout dst_layout, - const ImageSubresourceRange& subresource_range = {}) -> void; - - auto executeSubCommandBuffers(std::span> commandbuffers) - -> void; - - auto pipelineBarrier(PipelineStageFlag src_mask, - PipelineStageFlag dst_mask, - DependencyFlag dependency, - std::span memory_barriers, - std::span buffer_memory_barriers, - std::span image_memory_barriers) -> void; - - auto pushConstants(const PipelineLayout& pipeline_layout, - ShaderStageFlag stage, - std::span data, - UInt32 offset = 0u) -> void; - - [[nodiscard]] - auto vkHandle() const noexcept -> const vk::raii::CommandBuffer&; - - private: - CommandBufferLevel m_level = CommandBufferLevel::Primary; - - vk::raii::CommandBuffer m_vk_command_buffer; - - Deleter m_deleter; - - State m_state = State::Initial; - }; - - class STORMKIT_API CommandPool { - struct Tag {}; - - public: - CommandPool(const Device& device, Tag); - ~CommandPool(); - - CommandPool(const CommandPool&) = delete; - auto operator=(const CommandPool&) = delete; - - CommandPool(CommandPool&&) noexcept; - auto operator=(CommandPool&&) noexcept -> CommandPool&; - - [[nodiscard]] - static auto create(const Device& device) noexcept -> Expected; - [[nodiscard]] - static auto allocate(const Device& device) noexcept - -> Expected>; - - [[nodiscard]] - auto createCommandBuffer(const Device& device, - CommandBufferLevel level - = CommandBufferLevel::Primary) const noexcept -> CommandBuffer; - [[nodiscard]] - auto createCommandBuffers(const Device& device, - RangeExtent count, - CommandBufferLevel level - = CommandBufferLevel::Primary) const noexcept - -> std::vector; - - [[nodiscard]] - auto allocateCommandBuffer(const Device& device, - CommandBufferLevel level - = CommandBufferLevel::Primary) const noexcept - -> std::unique_ptr; - [[nodiscard]] - auto allocateCommandBuffers(const Device& device, - RangeExtent count, - CommandBufferLevel level - = CommandBufferLevel::Primary) const noexcept - -> std::vector>; - - [[nodiscard]] - auto vkHandle() const noexcept -> const vk::raii::CommandPool&; - - private: - auto createVkCommandBuffers(const Device& device, - RangeExtent count, - CommandBufferLevel level) const noexcept - -> std::vector; - auto deleteVkCommandBuffer(vk::raii::CommandBuffer& cmb) noexcept -> void; - - DeferInit m_vk_command_pool; - - // std::mutex m_reuse_mutex; - std::vector m_reusable_command_buffers; - }; -} // namespace stormkit::gpu - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::gpu { - namespace { - constexpr auto old_layout_access_map - = frozen::make_unordered_map>({ - { vk::ImageLayout::eUndefined, - { vk::AccessFlagBits {}, vk::PipelineStageFlagBits::eTopOfPipe } }, - { vk::ImageLayout::ePreinitialized, - { vk::AccessFlagBits {}, vk::PipelineStageFlagBits::eTopOfPipe } }, - { vk::ImageLayout::eGeneral, - { vk::AccessFlagBits::eColorAttachmentWrite - | vk::AccessFlagBits::eColorAttachmentRead, - vk::PipelineStageFlagBits::eColorAttachmentOutput } }, - { vk::ImageLayout::eColorAttachmentOptimal, - { vk::AccessFlagBits::eColorAttachmentWrite - | vk::AccessFlagBits::eColorAttachmentRead, - vk::PipelineStageFlagBits::eColorAttachmentOutput } }, - { vk::ImageLayout::eDepthStencilAttachmentOptimal, - { vk::AccessFlagBits::eDepthStencilAttachmentRead - | vk::AccessFlagBits::eDepthStencilAttachmentWrite, - vk::PipelineStageFlagBits::eLateFragmentTests } }, - { vk::ImageLayout::eDepthStencilReadOnlyOptimal, - { vk::AccessFlagBits::eDepthStencilAttachmentRead, - vk::PipelineStageFlagBits::eLateFragmentTests } }, - { vk::ImageLayout::eShaderReadOnlyOptimal, - { vk::AccessFlagBits::eInputAttachmentRead, - vk::PipelineStageFlagBits::eFragmentShader } }, - { vk::ImageLayout::eTransferSrcOptimal, - { vk::AccessFlagBits::eTransferRead, vk::PipelineStageFlagBits::eTransfer } }, - { vk::ImageLayout::eTransferDstOptimal, - { vk::AccessFlagBits::eTransferWrite, vk::PipelineStageFlagBits::eTransfer } }, - { vk::ImageLayout::ePresentSrcKHR, - { vk::AccessFlagBits::eMemoryRead, vk::PipelineStageFlagBits::eTransfer } } - }); - - constexpr auto new_layout_access_map - = frozen::make_unordered_map>({ - { vk::ImageLayout::eUndefined, { vk::AccessFlagBits {}, {} } }, - { vk::ImageLayout::ePreinitialized, { vk::AccessFlagBits {}, {} } }, - { vk::ImageLayout::eGeneral, - { vk::AccessFlagBits::eShaderWrite | vk::AccessFlagBits::eShaderRead, - vk::PipelineStageFlagBits::eVertexShader } }, - { vk::ImageLayout::eColorAttachmentOptimal, - { vk::AccessFlagBits::eColorAttachmentWrite - | vk::AccessFlagBits::eColorAttachmentRead, - vk::PipelineStageFlagBits::eColorAttachmentOutput } }, - { vk::ImageLayout::eDepthStencilAttachmentOptimal, - { vk::AccessFlagBits::eDepthStencilAttachmentWrite - | vk::AccessFlagBits::eDepthStencilAttachmentRead, - vk::PipelineStageFlagBits::eEarlyFragmentTests } }, - { vk::ImageLayout::eDepthStencilReadOnlyOptimal, - { vk::AccessFlagBits::eShaderRead, vk::PipelineStageFlagBits::eVertexInput } }, - { vk::ImageLayout::eShaderReadOnlyOptimal, - { vk::AccessFlagBits::eShaderRead, vk::PipelineStageFlagBits::eFragmentShader } }, - { vk::ImageLayout::eTransferSrcOptimal, - { vk::AccessFlagBits::eTransferRead, vk::PipelineStageFlagBits::eTransfer } }, - { vk::ImageLayout::eTransferDstOptimal, - { vk::AccessFlagBits::eTransferWrite, vk::PipelineStageFlagBits::eTransfer } }, - { vk::ImageLayout::ePresentSrcKHR, - { vk::AccessFlagBits::eMemoryRead, vk::PipelineStageFlagBits::eTransfer } } - }); - } // namespace - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Queue::Queue(const Device& device, const Device::QueueEntry& entry, Tag) - : m_entry { entry } { - toRaiiVkHandle(device) - .getQueue(entry.id, 0) - .transform(core :.monadic::set(m_vk_queue)) - .transform_error(core :.monadic::map(core :.monadic::narrow(), - core :.monadic::throw_as_exception())); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Queue::~Queue() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Queue::Queue(Queue&&) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Queue::operator=(Queue&&) noexcept -> Queue& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Queue::create(const Device& device, - const Device::QueueEntry& entry) noexcept - -> Expected try { - return Queue { device, entry, Tag {} }; - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Queue::allocate(const Device& device, - const Device::QueueEntry& entry) noexcept - -> Expected> try { - return std::make_unique(device, entry, Tag {}); - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Queue::waitIdle() const noexcept -> void { - m_vk_queue->waitIdle(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Queue::submit(std::span submit_infos, - OptionalRef fence) const noexcept - -> void { - struct Storage { - std::vector wait_semaphores = {}; - std::vector wait_dst_stages = {}; - std::vector command_buffers = {}; - std::vector signal_semaphores = {}; - }; - - auto storages = std::vector {}; - storages.reserve(std::size(submit_infos)); - - // clang-format off - const auto vk_submit_infos = submit_infos - | std::views::transform([&storages](auto &&submit_info) noexcept { - core::expects(std::size(submit_info.wait_semaphores) == std::size(submit_info.wait_dst_stages)); - - const auto &storage = storages.emplace_back(Storage { - .wait_semaphores = submit_info.wait_semaphores - | std::views::transform(monadic::toVkHandle()) - | std::ranges::to(), - .wait_dst_stages = submit_info.wait_dst_stages - | std::views::transform(monadic::toVkFlags()) - | std::ranges::to(), - .command_buffers = submit_info.command_buffers - | std::views::transform(monadic::toVkHandle()) - | std::ranges::to(), - .signal_semaphores = submit_info.signal_semaphores - | std::views::transform(monadic::toVkHandle()) - | std::ranges::to() - }); - - return vk::SubmitInfo{} - .setWaitSemaphores(storage.wait_semaphores) - .setWaitDstStageMask(storage.wait_dst_stages) - .setCommandBuffers(storage.command_buffers) - .setSignalSemaphores(storage.signal_semaphores); - }) - | std::ranges::to(); - // clang-format on - - const auto vk_fence - = core::either(fence, monadic::toVkHandle(), core :.monadic::init(nullptr)); - - vkHandle().submit(vk_submit_infos, vk_fence); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Queue::submit(const SubmitInfo& submit_info, - OptionalRef fence) const noexcept - -> void { - submit({ &submit_info, 1 }, std::move(fence)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto Queue::present(std::span> swapchains, - std::span> wait_semaphores, - std::span image_indices) const noexcept - -> Expected { - expects(std::size(wait_semaphores) >= 1); - expects(std::size(image_indices) >= 1); - const auto vk_wait_semaphores = wait_semaphores - | std::views::transform(monadic::toVkHandle()) - | std::ranges::to(); - const auto vk_swapchains = swapchains - | std::views::transform(monadic::toVkHandle()) - | std::ranges::to(); - const auto present_info = vk::PresentInfoKHR {} - .setWaitSemaphores(vk_wait_semaphores) - .setSwapchains(vk_swapchains) - .setImageIndices(image_indices); - - const auto result = m_vk_queue->presentKHR(present_info); - const auto possible_results = std::array { vk::Result::eSuccess, - vk::Result::eErrorOutOfDateKHR, - vk::Result::eSuboptimalKHR }; - - if (not std::ranges::any_of(possible_results, core :.monadic::is(result))) [[likely]] - return std::unexpected { narrow(result) }; - - return narrow(result); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Queue::entry() const noexcept -> const Device::QueueEntry& { - return m_entry; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Queue::vkHandle() const noexcept -> const vk::raii::Queue& { - return m_vk_queue.get(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE CommandBuffer::CommandBuffer(CommandBufferLevel level, - vk::raii::CommandBuffer&& command_buffer, - Deleter deleter, - Tag) - : m_level { level }, m_vk_command_buffer { std::move(command_buffer) }, - m_deleter { std::move(deleter) } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::create(CommandBufferLevel level, - vk::raii::CommandBuffer&& cmb, - Deleter deleter) noexcept -> CommandBuffer { - return CommandBuffer { level, std::move(cmb), std::move(deleter), Tag {} }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::allocate(CommandBufferLevel level, - vk::raii::CommandBuffer&& cmb, - Deleter deleter) noexcept - -> std::unique_ptr { - return std::make_unique(level, std::move(cmb), std::move(deleter), Tag {}); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE CommandBuffer::~CommandBuffer() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE CommandBuffer::CommandBuffer(CommandBuffer&&) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::operator=(CommandBuffer&&) noexcept - -> CommandBuffer& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::reset() noexcept -> void { - vkHandle().reset(vk::CommandBufferRESETFlagBits {}); - m_state = State::Initial; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - CommandBuffer::submit(const Queue& queue, - std::span> wait_semaphores, - std::span wait_dst_stages, - std::span> signal_semaphores, - OptionalRef fence) const noexcept -> void { - auto cmbs = as_refs(*this); - - 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 auto CommandBuffer::state() const noexcept -> State { - return m_state; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::level() const noexcept -> CommandBufferLevel { - return m_level; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::beginDebugRegion(std::string_view name, - const RGBColorF& color) -> void { - expects(m_state == State::Recording); - - const auto& dispatcher = m_vk_command_buffer.getDispatcher(); - if (not dispatcher->vkCmdBeginDebugUtilsLabelEXT) [[unlikely]] - return; - - const auto payload - = vk::DebugUtilsLabelEXT {}.setPLabelName(std::data(name)).setColor(color); - - m_vk_command_buffer.beginDebugUtilsLabelEXT(payload); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::insertDebugLabel(std::string_view name, - const RGBColorF& color) -> void { - expects(m_state == State::Recording); - - const auto& dispatcher = m_vk_command_buffer.getDispatcher(); - if (not dispatcher->vkCmdInsertDebugUtilsLabelEXT) [[unlikely]] - return; - - const auto payload - = vk::DebugUtilsLabelEXT {}.setPLabelName(std::data(name)).setColor(color); - - m_vk_command_buffer.insertDebugUtilsLabelEXT(payload); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::endDebugRegion() -> void { - expects(m_state == State::Recording); - - const auto& dispatcher = m_vk_command_buffer.getDispatcher(); - if (not dispatcher->vkCmdEndDebugUtilsLabelEXT) [[unlikely]] - return; - - m_vk_command_buffer.endDebugUtilsLabelEXT(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::begin(bool one_time_submit, - std::optional inheritance_info) - -> void { - expects(m_state == State::Initial); - - const auto vk_inheritance_info = either( - inheritance_info, - [](auto&& inheritance_info) static noexcept { - return vk::CommandBufferInheritanceInfo {} - .setRenderPass(toVkHandle(inheritance_info.render_pass)) - .setSubpass(inheritance_info.subpass) - .setFramebuffer(toVkHandle(inheritance_info.framebuffer)); - }, - core :.monadic::init()); - - const auto flags = [this, one_time_submit]() { - auto flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit; - - if (!one_time_submit) flags = vk::CommandBufferUsageFlagBits::eSimultaneousUse; - if (m_level == CommandBufferLevel::Secondary) - return vk::CommandBufferUsageFlagBits::eRenderPassContinue; - - return flags; - }(); - - const auto begin_info = vk::CommandBufferBeginInfo {}.setFlags(flags).setPInheritanceInfo( - &vk_inheritance_info); - - m_vk_command_buffer.begin(begin_info); - - m_state = State::Recording; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::end() -> void { - expects(m_state == State::Recording); - - m_vk_command_buffer.end(); - m_state = State::Executable; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - CommandBuffer::beginRenderPass(const RenderPass& render_pass, - const FrameBuffer& framebuffer, - std::span clear_values, - bool secondary_commandbuffers) -> void { - expects(m_state == State::Recording); - - const auto vk_clear_values - = clear_values - | std::views::transform(core :.monadic::either( - [](const ClearColor& color) noexcept -> decltype(auto) { - return vk::ClearValue { - .color - = vk::ClearColorValue { .floating_point32 - = color.color.operator std::array() } - }; - }, - [](const ClearDepthStencil& depth_stencil) noexcept -> decltype(auto) { - return vk::ClearValue { - .depthStencil - = vk::ClearDepthStencilValue { .depth = depth_stencil.depth, - .stencil = depth_stencil.stencil } - }; - })) - | std::ranges::to(); - - const auto begin_info - = vk::RenderPassBeginInfo {} - .setRenderPass(toVkHandle(render_pass)) - .setFramebuffer(toVkHandle(framebuffer)) - .setRenderArea(vk::Rect2D {}.setOffset({ 0, 0 }).setExtent( - { framebuffer.extent().width, framebuffer.extent().height })) - .setClearValues(vk_clear_values); - - const auto subpass_content = secondary_commandbuffers - ? vk::SubpassContents::eSecondaryCommandBuffers - : vk::SubpassContents::eInline; - - m_vk_command_buffer.beginRenderPass(begin_info, subpass_content); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::nextSubPass() -> void { - expects(m_state == State::Recording); - - m_vk_command_buffer.nextSubpass(vk::SubpassContents::eInline); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::endRenderPass() -> void { - expects(m_state == State::Recording); - - m_vk_command_buffer.endRenderPass(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::bindPipeline(const Pipeline& pipeline) -> void { - expects(m_state == State::Recording); - - const auto bind_point = (pipeline.type() == Pipeline::Type::Raster) - ? vk::PipelineBindPoint::eGraphics - : vk::PipelineBindPoint::eCompute; - - m_vk_command_buffer.bindPipeline(bind_point, toVkHandle(pipeline)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::setViewport(UInt32 first_viewport, - std::span viewports) - -> void { - expects(m_state == State::Recording); - - const auto vk_viewports = viewports - | std::views::transform(core :.monadic::narrow()) - | std::ranges::to(); - - m_vk_command_buffer.setViewport(first_viewport, vk_viewports); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::setScissor(UInt32 first_scissor, - std::span scissors) - -> void { - expects(m_state == State::Recording); - - const auto vk_scissors = scissors - | std::views::transform(core :.monadic::narrow()) - | std::ranges::to(); - - m_vk_command_buffer.setScissor(first_scissor, vk_scissors); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::setLineWidth(float width) -> void { - expects(m_state == State::Recording); - - m_vk_command_buffer.setLineWidth(width); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::setDepthBias(float constant_factor, - float clamp, - float slope_factor) -> void { - expects(m_state == State::Recording); - - m_vk_command_buffer.setDepthBias(constant_factor, clamp, slope_factor); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::setBlendConstants(std::span constants) - -> void { - expects(m_state == State::Recording); - - float data[] = { constants[0], constants[1], constants[2], constants[3] }; - - m_vk_command_buffer.setBlendConstants(data); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::setDepthBounds(float min, float max) -> void { - expects(m_state == State::Recording); - - m_vk_command_buffer.setDepthBounds(min, max); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::setStencilCompareMask(StencilFaceFlag face, - UInt32 mask) -> void { - expects(m_state == State::Recording); - - m_vk_command_buffer.setStencilCompareMask(narrow(face), mask); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::setStencilWriteMask(StencilFaceFlag face, UInt32 mask) - -> void { - expects(m_state == State::Recording); - - m_vk_command_buffer.setStencilWriteMask(narrow(face), mask); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::setStencilReference(StencilFaceFlag face, - UInt32 reference) -> void { - expects(m_state == State::Recording); - - m_vk_command_buffer.setStencilReference(narrow(face), reference); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::dispatch(UInt32 group_count_x, - UInt32 group_count_y, - UInt32 group_count_z) -> void { - expects(m_state == State::Recording); - - m_vk_command_buffer.dispatch(group_count_x, group_count_y, group_count_z); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::draw(UInt32 vertex_count, - UInt32 instance_count, - UInt32 first_vertex, - UInt32 first_instance) -> void { - expects(m_state == State::Recording); - expects(vertex_count > 0); - - m_vk_command_buffer.draw(vertex_count, instance_count, first_vertex, first_instance); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::drawIndexed(UInt32 index_count, - UInt32 instance_count, - UInt32 first_index, - Int32 vertex_offset, - UInt32 first_instance) -> void { - expects(m_state == State::Recording); - expects(index_count > 0); - - m_vk_command_buffer.drawIndexed(index_count, - instance_count, - first_index, - vertex_offset, - first_instance); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::drawIndirect(const Buffer& buffer, - RangeExtent offset, - UInt32 draw_count, - UInt32 stride) -> void { - expects(m_state == State::Recording); - expects(draw_count > 0); - - m_vk_command_buffer.drawIndirect(toVkHandle(buffer), offset, draw_count, stride); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::drawIndexedIndirect(const Buffer& buffer, - RangeExtent offset, - UInt32 draw_count, - UInt32 stride) -> void { - expects(m_state == State::Recording); - expects(draw_count > 0); - - m_vk_command_buffer.drawIndexedIndirect(toVkHandle(buffer), offset, draw_count, stride); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - CommandBuffer::bindVertexBuffers(std::span> buffers, - std::span offsets) -> void { - expects(m_state == State::Recording); - expects(not std::empty(buffers)); - expects(std::size(buffers) == std::size(offsets)); - - const auto vk_buffers = buffers - | std::views::transform(monadic::toVkHandle()) - | std::ranges::to(); - - m_vk_command_buffer.bindVertexBuffers(0, vk_buffers, offsets); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::bindIndexBuffer(const Buffer& buffer, - UInt64 offset, - bool large_indices) -> void { - expects(m_state == State::Recording); - - m_vk_command_buffer.bindIndexBuffer(toVkHandle(buffer), - offset, - (large_indices) ? vk::IndexType::eUint16 - : vk::IndexType::eUint32); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - CommandBuffer::bindDescriptorSets(const Pipeline& pipeline, - const PipelineLayout& layout, - std::span> descriptor_sets, - std::span dynamic_offsets) -> void { - expects(m_state == State::Recording); - - const auto bind_point = (pipeline.type() == Pipeline::Type::Raster) - ? vk::PipelineBindPoint::eGraphics - : vk::PipelineBindPoint::eCompute; - - const auto vk_descriptor_sets = descriptor_sets - | std::views::transform(monadic::toVkHandle()) - | std::ranges::to(); - - m_vk_command_buffer.bindDescriptorSets(bind_point, - toVkHandle(layout), - 0, - vk_descriptor_sets, - dynamic_offsets); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::copyBuffer(const Buffer& src, - const Buffer& dst, - RangeExtent size, - UInt64 src_offset, - UInt64 dst_offset) -> void { - const auto vk_copy_buffers = std::array { - vk::BufferCopy { .srcOffset = src_offset, .dstOffset = dst_offset, .size = size } - }; - - m_vk_command_buffer.copyBuffer(toVkHandle(src), toVkHandle(dst), vk_copy_buffers); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - CommandBuffer::copyBufferToImage(const Buffer& src, - const IsImage auto& dst, - std::span buffer_image_copies) - -> void { - expects(m_state == State::Recording); - - const auto DEFAULT_COPY = std::array { - BufferImageCopy { 0, 0, 0, {}, { 0, 0, 0 }, dst.extent() } - }; - - if (std::empty(buffer_image_copies)) buffer_image_copies = DEFAULT_COPY; - - const auto vk_copy_regions - = buffer_image_copies - | std::views::transform([](auto&& buffer_image_copy) noexcept { - const auto image_subresource = vk::ImageSubresourceLayers { - .aspectMask = narrow( - 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 vk::BufferImageCopy { - .bufferOffset = buffer_image_copy.buffer_offset, - .bufferRowLength = buffer_image_copy.buffer_row_length, - .bufferImageHeight = buffer_image_copy.buffer_image_height, - .imageSubresource = image_subresource, - .imageOffset = narrow(buffer_image_copy.offset), - .imageExtent = as(buffer_image_copy.extent) - }; - }) - | std::ranges::to(); - - m_vk_command_buffer.copyBufferToImage(toVkHandle(src), - toVkHandle(dst), - vk::ImageLayout::eTransferDstOptimal, - vk_copy_regions); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - CommandBuffer::copyImageToBuffer(const IsImage auto& src, - const Buffer& dst, - std::span buffer_image_copies) - -> void { - expects(m_state == State::Recording); - - const auto DEFAULT_COPY = std::array { - BufferImageCopy { 0, 0, 0, {}, { 0, 0, 0 }, src.extent() } - }; - - if (std::empty(buffer_image_copies)) buffer_image_copies = DEFAULT_COPY; - - const auto vk_copy_regions - = buffer_image_copies - | std::views::transform([](auto&& buffer_image_copy) noexcept { - const auto image_subresource = vk::ImageSubresourceLayers { - .aspectMask = narrow( - 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 vk::BufferImageCopy { - .bufferOffset = buffer_image_copy.buffer_offset, - .bufferRowLength = buffer_image_copy.buffer_row_length, - .bufferImageHeight = buffer_image_copy.buffer_image_height, - .imageSubresource = image_subresource, - .imageOffset = narrow(buffer_image_copy.offset), - .imageExtent = as(buffer_image_copy.extent) - }; - }) - | std::ranges::to(); - - m_vk_command_buffer.copyImageToBuffer(toVkHandle(src), - vk::ImageLayout::eTransferDstOptimal, - toVkHandle(dst), - vk_copy_regions); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - CommandBuffer::copyImage(const IsImage auto& src, - const IsImage auto& dst, - ImageLayout src_layout, - ImageLayout dst_layout, - const ImageSubresourceLayers& src_subresource_layers, - const ImageSubresourceLayers& dst_subresource_layers, - const math::ExtentU& extent) -> void { - expects(m_state == State::Recording); - - const auto vk_src_subresource_layers = vk::ImageSubresourceLayers { - .aspectMask = narrow(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 = vk::ImageSubresourceLayers { - .aspectMask = narrow(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 { - vk::ImageCopy { .srcSubresource = vk_src_subresource_layers, - .dstSubresource = vk_dst_subresource_layers, - .extent = as(extent) } - }; - - m_vk_command_buffer.copyImage(toVkHandle(src), - narrow(src_layout), - toVkHandle(dst), - narrow(dst_layout), - vk_regions); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - CommandBuffer::resolveImage(const IsImage auto& src, - const IsImage auto& dst, - ImageLayout src_layout, - ImageLayout dst_layout, - const ImageSubresourceLayers& src_subresource_layers, - const ImageSubresourceLayers& dst_subresource_layers) -> void { - expects(m_state == State::Recording); - - const auto vk_extent = as(dst.extent()); - - const auto vk_src_subresource_layers = vk::ImageSubresourceLayers { - .aspectMask = narrow(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 = vk::ImageSubresourceLayers { - .aspectMask = narrow(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 { - vk::ImageResolve { .srcSubresource = vk_src_subresource_layers, - .dstSubresource = vk_dst_subresource_layers, - .extent = vk_extent } - }; - - m_vk_command_buffer.resolveImage(toVkHandle(src), - narrow(src_layout), - toVkHandle(dst), - narrow(dst_layout), - vk_regions); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::blitImage(const IsImage auto& src, - const IsImage auto& dst, - ImageLayout src_layout, - ImageLayout dst_layout, - std::span regions, - Filter filter) -> void { - expects(m_state == State::Recording); - - const auto vk_regions - = regions - | std::views::transform([](auto&& region) noexcept { - const auto vk_src_subresource_layers = vk::ImageSubresourceLayers { - .aspectMask = narrow(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 = vk::ImageSubresourceLayers { - .aspectMask = narrow(region.dst.aspect_mask), - .mipLevel = region.dst.mip_level, - .baseArrayLayer = region.dst.base_array_layer, - .layerCount = region.dst.layer_count - }; - - return vk::ImageBlit { - .srcSubresource = vk_src_subresource_layers, - .srcOffsets = std::array { narrow(region.src_offset[0]), - narrow(region.src_offset[1]) }, - .dstSubresource = vk_dst_subresource_layers, - .dstOffsets = std::array { narrow(region.dst_offset[0]), - narrow(region.dst_offset[1]) }, - }; - }) - | std::ranges::to(); - - m_vk_command_buffer.blitImage(toVkHandle(src), - narrow(src_layout), - toVkHandle(dst), - narrow(dst_layout), - vk_regions, - narrow(filter)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - CommandBuffer::transitionImageLayout(const IsImage auto& image, - ImageLayout src_layout, - ImageLayout dst_layout, - const ImageSubresourceRange& subresource_range) - -> void { - expects(m_state == State::Recording); - - const auto vk_src_layout = narrow(src_layout); - const auto vk_dst_layout = narrow(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); - - const auto src_stage = src_access->second.second; - const auto dst_stage = dst_access->second.second; - - const auto vk_subresource_range = vk::ImageSubresourceRange { - .aspectMask = narrow(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 { - vk::ImageMemoryBarrier { .srcAccessMask = src_access->second.first, - .dstAccessMask = dst_access->second.first, - .oldLayout = vk_src_layout, - .newLayout = vk_dst_layout, - .srcQueueFamilyIndex = vk::QueueFamilyIgnored, - .dstQueueFamilyIndex = vk::QueueFamilyIgnored, - .image = toVkHandle(image), - .subresourceRange = vk_subresource_range } - }; - - m_vk_command_buffer.pipelineBarrier(src_stage, dst_stage, {}, {}, {}, barriers); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - CommandBuffer::pipelineBarrier(PipelineStageFlag src_mask, - PipelineStageFlag dst_mask, - DependencyFlag dependency, - std::span memory_barriers, - std::span buffer_memory_barriers, - std::span image_memory_barriers) - -> void { - const auto vk_memory_barriers - = memory_barriers - | std::views::transform([](auto&& barrier) noexcept -> decltype(auto) { - return vk::MemoryBarrier { - .srcAccessMask = narrow(barrier.src), - .dstAccessMask = narrow(barrier.dst), - }; - }) - | std::ranges::to(); - - const auto vk_buffer_memory_barriers - = buffer_memory_barriers - | std::views::transform([](auto&& barrier) noexcept -> decltype(auto) { - return vk::BufferMemoryBarrier { - .srcAccessMask = narrow(barrier.src), - .dstAccessMask = narrow(barrier.dst), - .srcQueueFamilyIndex = barrier.src_queue_family_index, - .dstQueueFamilyIndex = barrier.dst_queue_family_index, - .buffer = toVkHandle(barrier.buffer), - .offset = barrier.offset, - .size = barrier.size - }; - }) - | std::ranges::to(); - - const auto vk_image_memory_barriers - = image_memory_barriers - | std::views::transform([](auto&& barrier) noexcept -> decltype(auto) { - const auto vk_subresource_range = vk::ImageSubresourceRange { - .aspectMask = narrow(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 vk::ImageMemoryBarrier { - .srcAccessMask = narrow(barrier.src), - .dstAccessMask = narrow(barrier.dst), - .oldLayout = narrow(barrier.old_layout), - .newLayout = narrow(barrier.new_layout), - .srcQueueFamilyIndex = barrier.src_queue_family_index, - .dstQueueFamilyIndex = barrier.dst_queue_family_index, - .image = toVkHandle(barrier.image), - .subresourceRange = vk_subresource_range - }; - }) - | std::ranges::to(); - - m_vk_command_buffer.pipelineBarrier(narrow(src_mask), - narrow(dst_mask), - narrow(dependency), - vk_memory_barriers, - vk_buffer_memory_barriers, - vk_image_memory_barriers); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::pushConstants(const PipelineLayout& pipeline_layout, - ShaderStageFlag stage, - std::span data, - UInt32 offset) -> void { - expects(m_state == State::Recording); - expects(not std::empty(data)); - - m_vk_command_buffer.pushConstants(toVkHandle(pipeline_layout), - narrow(stage), - offset, - data); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::executeSubCommandBuffers( - std::span> commandbuffers) -> void { - expects(m_state == State::Recording); - - constexpr auto expectsSecondary = [](auto&& cmb) noexcept -> decltype(auto) { - expects(cmb->level() == CommandBufferLevel::Secondary); - return cmb; - }; - - const auto vk_command_buffers - = commandbuffers - | std::views::transform(core :.monadic::map(expectsSecondary, monadic::toVkHandle())) - | std::ranges::to(); - - m_vk_command_buffer.executeCommands(vk_command_buffers); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandBuffer::vkHandle() const noexcept - -> const vk::raii::CommandBuffer& { - return m_vk_command_buffer; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE CommandPool::CommandPool(const Device& device, Tag) { - device.vkHandle() - .createCommandPool(vk::CommandPoolCreateInfo { - .flags = vk::CommandPoolCreateFlagBits::eTransient - | vk::CommandPoolCreateFlagBits::eRESETCommandBuffer }) - .transform(core :.monadic::set(m_vk_command_pool)) - .transform_error(core :.monadic::map(core :.monadic::narrow(), - core :.monadic::throw_as_exception())); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE CommandPool::~CommandPool() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE CommandPool::CommandPool(CommandPool&&) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandPool::operator=(CommandPool&&) noexcept - -> CommandPool& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandPool::create(const Device& device) noexcept - -> Expected try { - return CommandPool { device, Tag {} }; - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandPool::allocate(const Device& device) noexcept - -> Expected> try { - return allocate(device, Tag {}) - .transform_error(core :.monadic::assert()) - .value(); - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - CommandPool::createCommandBuffer(const Device& device, - CommandBufferLevel level) const noexcept -> CommandBuffer { - return std::move(createCommandBuffers(device, 1, level).front()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - CommandPool::createCommandBuffers(const Device& device, - RangeExtent count, - CommandBufferLevel level) const noexcept - -> std::vector { - return createVkCommandBuffers(device, count, level) - | std::views::as_rvalue - | std::views::transform( - [this, &level](vk::raii::CommandBuffer&& cmb) noexcept -> decltype(auto) { - return CommandBuffer::create(level, - std::move(cmb), - bindFront(&CommandPool::deleteVkCommandBuffer, - const_cast(this))); - }) - | std::ranges::to(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - CommandPool::allocateCommandBuffer(const Device& device, - CommandBufferLevel level) const noexcept - -> std::unique_ptr { - return std::move(allocateCommandBuffers(device, 1, level).front()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - CommandPool::allocateCommandBuffers(const Device& device, - RangeExtent count, - CommandBufferLevel level) const noexcept - -> std::vector> { - return createVkCommandBuffers(device, count, level) - | std::views::as_rvalue - | std::views::transform( - [this, &level](vk::raii::CommandBuffer&& cmb) noexcept -> decltype(auto) { - return CommandBuffer::allocate(level, - std::move(cmb), - bindFront(&CommandPool::deleteVkCommandBuffer, - const_cast(this))); - }) - | std::ranges::to(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto CommandPool::vkHandle() const noexcept - -> const vk::raii::CommandPool& { - return m_vk_command_pool; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - CommandPool::deleteVkCommandBuffer([[maybe_unused]] vk::raii::CommandBuffer& cmb) noexcept - -> void { - // auto lock = std::unique_lock { m_reuse_mutex }; - // m_reusable_command_buffers.emplace_back(std::move(cmb)); - } -} // namespace stormkit::gpu diff --git a/modules/stormkit/Gpu/Execution/Descriptors.mpp b/modules/stormkit/Gpu/Execution/Descriptors.mpp deleted file mode 100644 index 888443abb..000000000 --- a/modules/stormkit/Gpu/Execution/Descriptors.mpp +++ /dev/null @@ -1,430 +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.Descriptors; - -import std; - -import stormkit.core; -import stormkit.Gpu.Vulkan; - -import :Core; -import :Resource; - -export { - namespace stormkit::gpu { - struct BufferDescriptor { - DescriptorType type = DescriptorType::Uniform_Buffer; - UInt32 binding; - Ref buffer; - UInt32 range; - UInt32 offset; - }; - - struct ImageDescriptor { - DescriptorType type = DescriptorType::Combined_Image_Sampler; - UInt32 binding; - ImageLayout layout; - Ref image_view; - Ref sampler; - }; - - using Descriptor = std::variant; - class DescriptorPool; - - class STORMKIT_API DescriptorSet { - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::Descriptor_Set; - - ~DescriptorSet(); - - 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 vkHandle() const noexcept -> const vk::raii::DescriptorSet&; - - private: - using Deleter = std::function; - - DescriptorSet(std::vector type, - vk::raii::DescriptorSet&& sets, - Deleter deleter); - - std::vector m_types; - - vk::raii::DescriptorSet m_vk_descriptor_set; - - Deleter m_deleter; - friend class DescriptorPool; - }; - - struct DescriptorSetLayoutBinding { - UInt32 binding; - DescriptorType type; - ShaderStageFlag stages; - RangeExtent descriptor_count; - }; - - class STORMKIT_API DescriptorSetLayout { - struct Tag {}; - - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::Descriptor_Set_Layout; - - DescriptorSetLayout(const Device& device, - std::vector&& bindings, - Tag); - DescriptorSetLayout(const Device& device, - std::span bindings, - Tag); - ~DescriptorSetLayout(); - - 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 vkHandle() const noexcept -> const vk::raii::DescriptorSetLayout&; - - [[nodiscard]] - auto operator==(const DescriptorSetLayout& second) const noexcept -> bool; - - private: - explicit DescriptorSetLayout(const Device& device); - - std::vector m_bindings; - - Hash64 m_hash = 0; - DeferInit m_vk_descriptor_set_layout; - }; - - class STORMKIT_API DescriptorPool { - struct Tag {}; - - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::Descriptor_Pool; - - struct Size { - DescriptorType type; - UInt32 descriptor_count; - }; - - DescriptorPool(const Device& device, std::span sizes, UInt32 max_sets, Tag); - ~DescriptorPool(); - - DescriptorPool(const DescriptorPool&) = delete; - auto operator=(const DescriptorPool&) -> DescriptorPool& = delete; - - DescriptorPool(DescriptorPool&&) noexcept; - auto operator=(DescriptorPool&&) noexcept -> DescriptorPool&; - - [[nodiscard]] - static auto create(const Device& device, - std::span sizes, - UInt32 max_sets) noexcept -> Expected; - - [[nodiscard]] - static auto allocate(const Device& device, - std::span sizes, - UInt32 max_sets) noexcept - -> Expected>; - - [[nodiscard]] - auto vkHandle() const noexcept -> const vk::raii::DescriptorPool&; - - private: - auto createDescriptorSets(RangeExtent count, const DescriptorSetLayout& layout) const - -> std::pair, std::vector>; - auto deleteDescriptorSet(vk::raii::DescriptorSet& set) const -> void; - - DeferInit m_vk_descriptor_pool; - }; - } // 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 DescriptorSet::DescriptorSet(std::vector type, - vk::raii::DescriptorSet&& set, - Deleter deleter) - : m_types { std::move(type) }, m_vk_descriptor_set { std::move(set) }, - m_deleter { std::move(deleter) } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE DescriptorSet::~DescriptorSet() { - if (*m_vk_descriptor_set) [[likely]] - m_deleter(m_vk_descriptor_set); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE DescriptorSet::DescriptorSet(DescriptorSet&&) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto DescriptorSet::operator=(DescriptorSet&&) noexcept - -> DescriptorSet& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - inline auto DescriptorSet::update(std::span descriptors) -> void { - const auto [buffers, images] = [&descriptors]() -> decltype(auto) { - auto buffers = std::vector {}; - auto images = std::vector {}; - buffers.reserve(std::size(descriptors)); - images.reserve(std::size(descriptors)); - - std::ranges::for_each( - descriptors, - core :.monadic::either( - [&buffers](const BufferDescriptor& descriptor) noexcept -> decltype(auto) { - buffers.emplace_back(vk::DescriptorBufferInfo {} - .setBuffer(toVkHandle(descriptor.buffer)) - .setOffset(descriptor.offset) - .setRange(descriptor.range)); - }, - [&images](const ImageDescriptor& descriptor) noexcept -> decltype(auto) { - images.emplace_back( - vk::DescriptorImageInfo {} - .setSampler(toVkHandle(descriptor.sampler)) - .setImageView(toVkHandle(descriptor.image_view)) - .setImageLayout(narrow(descriptor.layout))); - })); - - return std::pair { std::move(buffers), std::move(images) }; - }(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto DescriptorSet::types() const noexcept - -> const std::vector& { - return m_types; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto DescriptorSet::vkHandle() const noexcept - -> const vk::raii::DescriptorSet& { - return m_vk_descriptor_set; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE DescriptorSetLayout::DescriptorSetLayout(const Device& device) { - const auto vk_bindings - = m_bindings - | std::views::transform([](auto&& binding) noexcept { - return vk::DescriptorSetLayoutBinding {} - .setBinding(binding.binding) - .setDescriptorType(narrow(binding.type)) - .setDescriptorCount(as(binding.descriptor_count)) - .setStageFlags(narrow(binding.stages)); - }) - | std::ranges::to(); - - const auto create_info = vk::DescriptorSetLayoutCreateInfo {}.setBindings(vk_bindings); - - device.vkHandle() - .createDescriptorSetLayout(create_info) - .transform(core :.monadic::set(m_vk_descriptor_set_layout)) - .transform_error(core :.monadic::map(core :.monadic::narrow(), - core :.monadic::throw_as_exception())); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - DescriptorSetLayout::DescriptorSetLayout(const Device& device, - std::vector&& bindings, - Tag) - : DescriptorSetLayout { device } { - m_bindings = std::move(bindings); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - DescriptorSetLayout::DescriptorSetLayout(const Device& device, - std::span bindings, - Tag) - : DescriptorSetLayout { device } { - m_bindings.reserve(std::ranges::size(bindings)); - std::ranges::copy(bindings, std::back_inserter(m_bindings)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE DescriptorSetLayout::~DescriptorSetLayout() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - DescriptorSetLayout::DescriptorSetLayout(DescriptorSetLayout&& other) noexcept - = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto DescriptorSetLayout::operator=(DescriptorSetLayout&& other) noexcept - -> DescriptorSetLayout& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto DescriptorSetLayout::hash() const noexcept -> Hash64 { - return m_hash; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto DescriptorSetLayout::bindings() const noexcept - -> const std::vector& { - return m_bindings; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto DescriptorSetLayout::vkHandle() const noexcept - -> const vk::raii::DescriptorSetLayout& { - return m_vk_descriptor_set_layout.get(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - DescriptorSetLayout::operator==(const DescriptorSetLayout& second) const noexcept -> bool { - return m_hash == second.hash(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE DescriptorPool::DescriptorPool(const Device& device, - std::span sizes, - UInt32 max_sets, - Tag) { - const auto pool_sizes = sizes - | std::views::transform([&](const auto& size) { - return vk::DescriptorPoolSize {} - .setType(narrow(size.type)) - .setDescriptorCount(size.descriptor_count); - }) - | std::ranges::to(); - - const auto create_info = vk::DescriptorPoolCreateInfo {} - .setFlags(vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet) - .setMaxSets(max_sets) - .setPoolSizes(pool_sizes); - - device.vkHandle() - .createDescriptorPool(create_info) - .transform(core :.monadic::set(m_vk_descriptor_pool)) - .transform_error(core :.monadic::map(core :.monadic::narrow(), - core :.monadic::throw_as_exception())); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE DescriptorPool::~DescriptorPool() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE DescriptorPool::DescriptorPool(DescriptorPool&& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto DescriptorPool::operator=(DescriptorPool&& other) noexcept - -> DescriptorPool& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto DescriptorPool::create(const Device& device, - std::span extents, - UInt32 max_sets) noexcept - -> Expected try { - return DescriptorPool { device, extents, max_sets, Tag {} }; - } catch (const Result& result) { return std::unexpected(result); } - - ////////////////////////////////////p/ - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto DescriptorPool::allocate(const Device& device, - std::span extents, - UInt32 max_sets) noexcept - -> Expected> try { - return std::make_unique(device, extents, max_sets, Tag {}); - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto DescriptorPool::vkHandle() const noexcept - -> const vk::raii::DescriptorPool& { - return m_vk_descriptor_pool; - } -} // namespace stormkit::gpu diff --git a/modules/stormkit/Gpu/Execution/Pipeline.mpp b/modules/stormkit/Gpu/Execution/Pipeline.mpp deleted file mode 100644 index 1ec07be40..000000000 --- a/modules/stormkit/Gpu/Execution/Pipeline.mpp +++ /dev/null @@ -1,373 +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 - -export module stormkit.Gpu:Execution.Pipeline; - -import std; - -import stormkit.core; -import stormkit.Gpu.Vulkan; - -import :Core; -import :Execution.RasterPipelineState; -import :Execution.RenderPass; - -export namespace stormkit::gpu { - class CommandBuffer; - - class STORMKIT_API PipelineCache { - struct Tag {}; - - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::Pipeline_Cache; - - PipelineCache(const Device& device, std::filesystem::path cache_path, Tag); - ~PipelineCache(); - - PipelineCache(const PipelineCache&) = delete; - auto operator=(const PipelineCache&) -> PipelineCache& = delete; - - PipelineCache(PipelineCache&&) noexcept; - auto operator=(PipelineCache&&) noexcept -> PipelineCache&; - - [[nodiscard]] - static auto create(const Device& device, std::filesystem::path cache_path) noexcept - -> Expected; - [[nodiscard]] - static auto allocate(const Device& device, std::filesystem::path cache_path) noexcept - -> Expected>; - - [[nodiscard]] - auto vkHandle() const noexcept -> const vk::raii::PipelineCache&; - - private: - auto createNewPipelineCache(const Device& device) -> VulkanExpected; - auto readPipelineCache(const Device& device) -> VulkanExpected; - auto saveCache() -> void; - - static constexpr auto MAGIC = UInt32 { 0xDEADBEEF }; - static constexpr auto VERSION = UInt32 { 1u }; - - struct SerializedCache { - struct { - UInt32 magic; - RangeExtent data_size; - UInt64 data_hash; - } guard; - - struct { - UInt32 version; - UInt64 vendor_id; - UInt64 device_id; - } infos; - - struct { - std::array value; - } uuid; - } m_serialized; - - std::filesystem::path m_path; - - DeferInit m_vk_pipeline_cache; - }; - - class STORMKIT_API PipelineLayout { - struct Tag {}; - - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::PipelineLayout; - - PipelineLayout(const Device& device, const RasterPipelineLayout& layout, Tag); - ~PipelineLayout(); - - PipelineLayout(const PipelineLayout&) = delete; - auto operator=(const PipelineLayout&) -> PipelineLayout& = delete; - - PipelineLayout(PipelineLayout&&) noexcept; - auto operator=(PipelineLayout&&) noexcept -> PipelineLayout&; - - [[nodiscard]] - static auto create(const Device& device, const RasterPipelineLayout& layout) noexcept - -> Expected; - [[nodiscard]] - static auto allocate(const Device& device, const RasterPipelineLayout& layout) noexcept - -> Expected>; - - [[nodiscard]] - auto rasterLayout() -> const RasterPipelineLayout&; - - [[nodiscard]] - auto vkHandle() const noexcept -> const vk::raii::PipelineLayout&; - - private: - RasterPipelineLayout m_layout; - DeferInit m_vk_pipeline_layout; - }; - - class STORMKIT_API Pipeline { - struct Tag {}; - - public: - enum class Type { - Raster, - Compute - }; - - static constexpr auto DEBUG_TYPE = DebugObjectType::Pipeline; - - Pipeline(const Device& device, - const RasterPipelineState& state, - const PipelineLayout& layout, - const RenderPass& render_pass, - OptionalRef cache, - Tag); - ~Pipeline(); - - Pipeline(const Pipeline&) = delete; - auto operator=(const Pipeline&) -> Pipeline& = delete; - - Pipeline(Pipeline&&) noexcept; - auto operator=(Pipeline&&) noexcept -> Pipeline&; - - [[nodiscard]] - static auto create(const Device& device, - const RasterPipelineState& state, - const PipelineLayout& layout, - const RenderPass& render_pass, - OptionalRef cache = std::nullopt) noexcept - -> Expected; - [[nodiscard]] - static auto allocate(const Device& device, - const RasterPipelineState& state, - const PipelineLayout& layout, - const RenderPass& render_pass, - OptionalRef cache = std::nullopt) noexcept - -> Expected>; - - // auto bind(CommandBuffer& commandbuffer) const noexcept -> void; - - [[nodiscard]] - auto type() const noexcept -> Type; - [[nodiscard]] - auto rasterState() const noexcept -> const RasterPipelineState&; - - [[nodiscard]] - auto vkHandle() const noexcept -> const vk::raii::Pipeline&; - - private: - auto doInitRasterPipeline(const Device&, - const PipelineLayout&, - const RenderPass&, - OptionalRef) noexcept - -> VulkanExpected; - - Type m_type; - - DeferInit m_vk_pipeline; - - std::variant m_state; - }; -} // namespace stormkit::gpu - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::gpu { - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - PipelineCache::PipelineCache(const Device& device, std::filesystem::path path, Tag) - : m_path { std::move(path) } { - either(std::filesystem::exists(m_path), - bindFront(&PipelineCache::readPipelineCache, this, std::cref(device)), - bindFront(&PipelineCache::createNewPipelineCache, this, std::cref(device))) - .transform_error(core :.monadic::map(core :.monadic::narrow(), - core :.monadic::throw_as_exception())); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE PipelineCache::~PipelineCache() { - if (*m_vk_pipeline_cache.get()) [[likely]] - saveCache(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE PipelineCache::PipelineCache(PipelineCache&& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto PipelineCache::operator=(PipelineCache&& other) noexcept - -> PipelineCache& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto PipelineCache::create(const Device& device, - std::filesystem::path cache_path) noexcept - -> Expected try { - return PipelineCache { device, std::move(cache_path), Tag {} }; - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto PipelineCache::allocate(const Device& device, - std::filesystem::path cache_path) noexcept - -> Expected> try { - return std::make_unique(device, std::move(cache_path), Tag {}); - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto PipelineCache::vkHandle() const noexcept - -> const vk::raii::PipelineCache& { - return m_vk_pipeline_cache; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - PipelineLayout::PipelineLayout(const Device& device, const RasterPipelineLayout& layout, Tag) - : m_layout { layout } { - const auto set_layouts = m_layout.descriptor_set_layouts - | std::views::transform(monadic::toVkHandle()) - | std::ranges::to(); - - const auto push_constant_ranges - = m_layout.push_constant_ranges - | std::views::transform([](auto&& push_constant_range) noexcept { - return vk::PushConstantRange {} - .setStageFlags(narrow(push_constant_range.stages)) - .setOffset(push_constant_range.offset) - .setSize(as(push_constant_range.size)); - }) - | std::ranges::to(); - - const auto create_info = vk::PipelineLayoutCreateInfo {} - .setSetLayouts(set_layouts) - .setPushConstantRanges(push_constant_ranges); - - device.vkHandle() - .createPipelineLayout(create_info) - .transform(core :.monadic::set(m_vk_pipeline_layout)) - .transform_error(core :.monadic::map(core :.monadic::narrow(), - core :.monadic::throw_as_exception())); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE PipelineLayout::~PipelineLayout() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE PipelineLayout::PipelineLayout(PipelineLayout&& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto PipelineLayout::operator=(PipelineLayout&& other) noexcept - -> PipelineLayout& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto PipelineLayout::create(const Device& device, - const RasterPipelineLayout& layout) noexcept - -> Expected try { - return PipelineLayout { device, layout, Tag {} }; - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto PipelineLayout::allocate(const Device& device, - const RasterPipelineLayout& layout) noexcept - -> Expected> try { - return std::make_unique(device, layout, Tag {}); - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto PipelineLayout::vkHandle() const noexcept - -> const vk::raii::PipelineLayout& { - return m_vk_pipeline_layout; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Pipeline::Pipeline(const Device& device, - const RasterPipelineState& state, - const PipelineLayout& layout, - const RenderPass& render_pass, - OptionalRef cache, - Tag) - : m_type { Type::Raster }, m_state { state } { - doInitRasterPipeline(device, layout, render_pass, std::move(cache)) - .transform_error(core :.monadic::map(core :.monadic::narrow(), - core :.monadic::throw_as_exception())); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Pipeline::~Pipeline() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Pipeline::Pipeline(Pipeline&& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Pipeline::operator=(Pipeline&& other) noexcept - -> Pipeline& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Pipeline::create(const Device& device, - const RasterPipelineState& state, - const PipelineLayout& layout, - const RenderPass& render_pass, - OptionalRef cache) noexcept - -> Expected try { - return Pipeline { device, state, layout, render_pass, std::move(cache), Tag {} }; - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Pipeline::allocate(const Device& device, - const RasterPipelineState& state, - const PipelineLayout& layout, - const RenderPass& render_pass, - OptionalRef cache) noexcept - -> Expected> try { - return std::make_unique(device, - state, - layout, - render_pass, - std::move(cache), - Tag {}); - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Pipeline::type() const noexcept -> Type { - return m_type; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Pipeline::rasterState() const noexcept - -> const RasterPipelineState& { - expects(m_type == Type::Raster); - expects(is(m_state)); - return as(m_state); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Pipeline::vkHandle() const noexcept -> const vk::raii::Pipeline& { - return m_vk_pipeline; - } -} // namespace stormkit::gpu diff --git a/modules/stormkit/Gpu/Execution/RenderPass.mpp b/modules/stormkit/Gpu/Execution/RenderPass.mpp deleted file mode 100644 index 0b54d443c..000000000 --- a/modules/stormkit/Gpu/Execution/RenderPass.mpp +++ /dev/null @@ -1,358 +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.RenderPass; - -import std; - -import stormkit.core; -import stormkit.Gpu.Vulkan; - -import :Core; -import :Resource; - -export { - namespace stormkit::gpu { - class RenderPass; - - class STORMKIT_API FrameBuffer { - struct Tag {}; - - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::FrameBuffer; - - FrameBuffer(const Device& device, - const RenderPass& render_pass, - const math::ExtentU& size, - std::vector> attachments, - Tag); - ~FrameBuffer(); - - FrameBuffer(const FrameBuffer&) = delete; - auto operator=(const FrameBuffer&) -> FrameBuffer& = delete; - - FrameBuffer(FrameBuffer&&) noexcept; - auto operator=(FrameBuffer&&) noexcept -> FrameBuffer&; - - [[nodiscard]] - static auto create(const Device& device, - const RenderPass& render_pass, - const math::ExtentU& size, - std::vector> attachments) noexcept - -> Expected; - [[nodiscard]] - static auto allocate(const Device& device, - const RenderPass& render_pass, - const math::ExtentU& size, - std::vector> attachments) noexcept - -> Expected>; - - [[nodiscard]] - auto extent() const noexcept -> const math::ExtentU&; - [[nodiscard]] - auto attachments() const noexcept -> const std::vector>&; - - [[nodiscard]] - auto vkHandle() const noexcept -> const vk::raii::Framebuffer&; - - private: - math::ExtentU m_extent = { 0, 0 }; - std::vector> m_attachments; - - DeferInit m_vk_framebuffer; - }; - - 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 { - UInt32 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 isCompatible(const RenderPassDescription& description) const noexcept -> bool; - }; - - class STORMKIT_API RenderPass { - struct Tag {}; - - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::Render_Pass; - - RenderPass(const Device& device, const RenderPassDescription& description, Tag); - ~RenderPass(); - - RenderPass(const RenderPass&) = delete; - auto operator=(const RenderPass&) -> RenderPass& = delete; - - RenderPass(RenderPass&&) noexcept; - auto operator=(RenderPass&&) noexcept -> RenderPass&; - - [[nodiscard]] - static auto create(const Device& device, - const RenderPassDescription& description) noexcept - -> Expected; - [[nodiscard]] - static auto allocate(const Device& device, - const RenderPassDescription& description) noexcept - -> Expected>; - - [[nodiscard]] - auto createFrameBuffer(const Device& device, - const math::ExtentU& size, - std::vector> attachments) const noexcept - -> Expected; - [[nodiscard]] - auto allocateFrameBuffer(const Device& device, - const math::ExtentU& size, - std::vector> attachments) const noexcept - -> Expected>; - - [[nodiscard]] - auto isCompatible(const RenderPass& render_pass) const noexcept -> bool; - [[nodiscard]] - auto isCompatible(const RenderPassDescription& description) const noexcept -> bool; - - [[nodiscard]] - auto description() const noexcept -> const RenderPassDescription&; - - [[nodiscard]] - auto vkHandle() const noexcept -> const vk::raii::RenderPass&; - - private: - auto doInitRenderPass(const Device& device) noexcept -> VulkanExpected; - - RenderPassDescription m_description = {}; - - DeferInit m_vk_render_pass; - }; - } // namespace stormkit::gpu - - HASH_FUNC(stormkit::gpu::AttachmentDescription, - 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) - HASH_FUNC(stormkit::gpu::Subpass::Ref, value.attachment_id, value.layout) - HASH_FUNC(stormkit::gpu::Subpass, - value.bind_point, - value.color_attachment_refs, - value.depth_attachment_ref, - value.resolve_attachment_refs) - HASH_FUNC(stormkit::gpu::RenderPassDescription, value.attachments, value.subpasses) -} - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::gpu { - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE FrameBuffer::FrameBuffer(const Device& device, - const RenderPass& render_pass, - const math::ExtentU& extent, - std::vector> attachments, - Tag) - : m_extent { std::move(extent) }, m_attachments { std::move(attachments) } { - const auto vk_attachments = m_attachments - | std::views::transform(monadic::toVkHandle()) - | std::ranges::to(); - - const auto create_info = vk::FramebufferCreateInfo {} - .setRenderPass(toVkHandle(render_pass)) - .setAttachments(vk_attachments) - .setWidth(m_extent.width) - .setHeight(m_extent.height) - .setLayers(1); - - device.vkHandle() - .createFramebuffer(create_info) - .transform(core :.monadic::set(m_vk_framebuffer)) - .transform_error(core :.monadic::map(core :.monadic::narrow(), - core :.monadic::throw_as_exception())); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE FrameBuffer::~FrameBuffer() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE FrameBuffer::FrameBuffer(FrameBuffer&& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto FrameBuffer::operator=(FrameBuffer&& other) noexcept - -> FrameBuffer& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - FrameBuffer::create(const Device& device, - const RenderPass& render_pass, - const math::ExtentU& size, - std::vector> attachments) noexcept - -> Expected try { - return FrameBuffer { device, render_pass, size, std::move(attachments), Tag {} }; - } catch (const Result& result) { return std::unexpected(result); } - - ////////////////////////////////////p/ - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - FrameBuffer::allocate(const Device& device, - const RenderPass& render_pass, - const math::ExtentU& size, - std::vector> attachments) noexcept - -> Expected> try { - return std::make_unique(device, - render_pass, - size, - std::move(attachments), - Tag {}); - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto FrameBuffer::extent() const noexcept -> const math::ExtentU& { - return m_extent; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto FrameBuffer::attachments() const noexcept - -> const std::vector>& { - return m_attachments; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto FrameBuffer::vkHandle() const noexcept - -> const vk::raii::Framebuffer& { - return m_vk_framebuffer; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - RenderPass::RenderPass(const Device& device, const RenderPassDescription& description, Tag) - : m_description { description } { - doInitRenderPass(device).transform_error( - core :.monadic::map(core :.monadic::narrow(), - core :.monadic::throw_as_exception())); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE RenderPass::~RenderPass() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE RenderPass::RenderPass(RenderPass&& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto RenderPass::operator=(RenderPass&& other) noexcept - -> RenderPass& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto RenderPass::create(const Device& device, - const RenderPassDescription& description) noexcept - -> Expected try { - return RenderPass { device, description, Tag {} }; - } catch (const Result& result) { return std::unexpected(result); } - - ////////////////////////////////////p/ - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - RenderPass::allocate(const Device& device, - const RenderPassDescription& description) noexcept - -> Expected> try { - return std::make_unique(device, description, Tag {}); - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - RenderPass::createFrameBuffer(const Device& device, - const math::ExtentU& extent, - std::vector> attachments) const noexcept - -> Expected { - return FrameBuffer::create(device, *this, extent, std::move(attachments)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto RenderPass::allocateFrameBuffer( - const Device& device, - const math::ExtentU& extent, - std::vector> attachments) const noexcept - -> Expected> { - return FrameBuffer::allocate(device, *this, extent, std::move(attachments)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - RenderPass::isCompatible(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 auto RenderPass::description() const noexcept - -> const RenderPassDescription& { - return m_description; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto RenderPass::vkHandle() const noexcept - -> const vk::raii::RenderPass& { - return m_vk_render_pass; - } -} // namespace stormkit::gpu diff --git a/modules/stormkit/Gpu/Resource.mpp b/modules/stormkit/Gpu/Resource.mpp deleted file mode 100644 index ffd067552..000000000 --- a/modules/stormkit/Gpu/Resource.mpp +++ /dev/null @@ -1,10 +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.Gpu:Resource; - -export import :Resource.Buffer; -export import :Resource.Image; -export import :Resource.Shader; -export import :Resource.Swapchain; diff --git a/modules/stormkit/Gpu/Resource/Buffer.mpp b/modules/stormkit/Gpu/Resource/Buffer.mpp deleted file mode 100644 index 4f79d85da..000000000 --- a/modules/stormkit/Gpu/Resource/Buffer.mpp +++ /dev/null @@ -1,290 +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 - -export module stormkit.Gpu:Resource.Buffer; - -import std; - -import stormkit.core; -import stormkit.Gpu.Vulkan; - -import :Core; - -export namespace stormkit::gpu { - class STORMKIT_API Buffer { - struct Tag {}; - - public: - struct CreateInfo { - BufferUsageFlag usages; - RangeExtent size; - MemoryPropertyFlag property - = MemoryPropertyFlag::Host_Visible | MemoryPropertyFlag::Host_Coherent; - }; - - static constexpr auto DEBUG_TYPE = DebugObjectType::Buffer; - - Buffer(const Device& device, const CreateInfo& info, bool persistently_mapping, Tag); - ~Buffer(); - - Buffer(const Buffer&) = delete; - auto operator=(const Buffer&) -> Buffer&; - - Buffer(Buffer&&) noexcept; - auto operator=(Buffer&&) noexcept -> Buffer&; - - [[nodiscard]] - static auto create(const Device& device, - const CreateInfo& info, - bool persistently_mapped = false) noexcept -> Expected; - [[nodiscard]] - 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 -> RangeExtent; - - [[nodiscard]] - auto map(const Device& device, RangeOffset offset) noexcept -> decltype(auto); - [[nodiscard]] - auto map(const Device& device, RangeOffset offset, RangeExtent size) noexcept - -> decltype(auto); - - template - [[nodiscard]] - auto mapAs(const Device& device, RangeOffset offset) noexcept -> decltype(auto); - - [[nodiscard]] - auto data(this auto& self) noexcept -> decltype(auto); - [[nodiscard]] - auto data(this auto& self, RangeExtent size) noexcept -> decltype(auto); - - template - [[nodiscard]] - auto dataAs(this auto& self) noexcept -> decltype(auto); - - auto flush(const Device& device, RangeOffset offset, RangeExtent size) -> void; - auto unmap(const Device& device) -> void; - - [[nodiscard]] - auto isPersistentlyMapped() const noexcept -> bool; - - auto upload(const Device& device, std::span data, RangeOffset offset = 0) - -> void; - template> T> - auto upload(const Device& device, const T& data, RangeOffset offset = 0) -> void; - - [[nodiscard]] - auto vkHandle() const noexcept -> const vk::raii::Buffer&; - - private: - static auto findMemoryType(UInt type_filter, - vk::MemoryPropertyFlags properties, - const vk::PhysicalDeviceMemoryProperties& mem_properties, - const vk::MemoryRequirements& mem_requirements) -> UInt; - - DeferInit m_vk_buffer; - vma::UniqueAllocation m_vma_allocation; - - BufferUsageFlag m_usages = {}; - RangeExtent m_size = 0; - - bool m_is_persistently_mapped = false; - Byte* m_mapped_pointer = nullptr; - }; - - struct BufferMemoryBarrier { - AccessFlag src; - AccessFlag dst; - - UInt32 src_queue_family_index = QUEUE_FAMILY_IGNORED; - UInt32 dst_queue_family_index = QUEUE_FAMILY_IGNORED; - - const Buffer& buffer; - RangeExtent size; - UInt64 offset = 0; - }; -} // namespace stormkit::gpu - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::gpu { - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Buffer::~Buffer() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Buffer::Buffer(Buffer&& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Buffer::operator=(Buffer&& other) noexcept -> Buffer& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Buffer::create(const Device& device, - const CreateInfo& info, - bool persistently_mapped) noexcept - -> Expected try { - return Buffer { device, info, persistently_mapped, Tag {} }; - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Buffer::allocate(const Device& device, - const CreateInfo& info, - bool persistently_mapped) noexcept - -> Expected> try { - return std::make_unique(device, info, persistently_mapped, Tag {}); - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Buffer::usages() const noexcept -> BufferUsageFlag { - expects(m_vma_allocation.operator bool()); - - return m_usages; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Buffer::size() const noexcept -> RangeExtent { - expects(m_vma_allocation.operator bool()); - - return m_size; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Buffer::map(const Device& device, RangeOffset offset) noexcept - -> decltype(auto) { - expects(m_vma_allocation.operator bool()); - expects(offset < as(m_size)); - - if (!m_mapped_pointer) { - auto _ = device.vmaAllocator().mapMemory(*m_vma_allocation, - std::bit_cast(&m_mapped_pointer)); - m_mapped_pointer += offset; - } - - return m_mapped_pointer; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Buffer::map(const Device& device, - RangeOffset offset, - RangeExtent size) noexcept -> decltype(auto) { - return std::span { map(device, offset), size }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE auto Buffer::mapAs(const Device& device, RangeOffset offset) noexcept - -> decltype(auto) { - expects(m_vma_allocation.operator bool()); - - return std::bit_cast(map(device, offset)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Buffer::data(this auto& self) noexcept -> decltype(auto) { - expects(self.m_vma_allocation.operator bool()); - expects(self.m_mapped_pointer); - - using Byte = meta::ConstnessLike; - - return std::bit_cast(self.m_mapped_pointer); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Buffer::data(this auto& self, RangeExtent size) noexcept - -> decltype(auto) { - expects(self.m_vma_allocation.operator bool()); - expects(self.m_mapped_pointer); - - using Byte = meta::ConstnessLike; - - return std::span { std::bit_cast(self.m_mapped_pointer), size }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE auto Buffer::dataAs(this auto& self) noexcept -> decltype(auto) { - expects(self.m_vma_allocation.operator bool()); - - using Type = meta::ConstnessLike; - - return std::bit_cast(self.data()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - Buffer::flush(const Device& device, RangeOffset offset, RangeExtent size) -> void { - expects(m_vma_allocation.operator bool()); - expects(offset <= as(m_size)); - expects(size <= m_size); - - device.vmaAllocator().flushAllocation(*m_vma_allocation, offset, size); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Buffer::unmap(const Device& device) -> void { - expects(m_vma_allocation.operator bool()); - expects(not m_is_persistently_mapped, "Trying to unmap persistent buffer !"); - - device.vmaAllocator().unmapMemory(*m_vma_allocation); - - m_mapped_pointer = nullptr; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Buffer::upload(const Device& device, - std::span data, - RangeOffset offset) -> void { - auto ptr = map(device, offset, std::size(data)); - - std::ranges::copy(data, std::ranges::begin(ptr)); - - unmap(device); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template> T> - STORMKIT_FORCE_INLINE auto - Buffer::upload(const Device& device, const T& data, RangeOffset offset) -> void { - const auto bytes = as_bytes(data); - - auto ptr = map(device, offset, std::size(bytes)); - - std::ranges::copy(bytes, std::ranges::begin(ptr)); - - unmap(device); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Buffer::vkHandle() const noexcept -> const vk::raii::Buffer& { - return m_vk_buffer; - } -} // namespace stormkit::gpu diff --git a/modules/stormkit/Gpu/Resource/Image.mpp b/modules/stormkit/Gpu/Resource/Image.mpp deleted file mode 100644 index cefd79295..000000000 --- a/modules/stormkit/Gpu/Resource/Image.mpp +++ /dev/null @@ -1,505 +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 - -export module stormkit.Gpu:Resource.Image; - -import std; - -import stormkit.core; -import stormkit.image; -import stormkit.Gpu.Vulkan; - -import :Core; - -export namespace stormkit::gpu { - class STORMKIT_API Sampler { - struct Tag {}; - - 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; - - Sampler(const Device& device, const Settings& settings, Tag); - ~Sampler(); - - Sampler(const Sampler&) = delete; - auto operator=(const Sampler&) -> Sampler& = delete; - - Sampler(Sampler&&) noexcept; - auto operator=(Sampler&&) noexcept -> Sampler&; - - [[nodiscard]] - static auto create(const Device& device, const Settings& settings) noexcept - -> Expected; - [[nodiscard]] - static auto allocate(const Device& device, const Settings& settings) noexcept - -> Expected>; - - [[nodiscard]] - auto settings() const noexcept -> const Settings&; - - [[nodiscard]] - auto vkHandle() const noexcept -> const vk::raii::Sampler&; - - private: - Settings m_settings = {}; - - DeferInit m_vk_sampler; - }; - - class Image; - - class STORMKIT_API ImageView { - struct Tag {}; - - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::Image_View; - - ImageView(const Device& device, - const Image& image, - ImageViewType type, - const ImageSubresourceRange& subresource_range, - Tag); - ~ImageView(); - - ImageView(const ImageView&) = delete; - auto operator=(const ImageView&) -> ImageView& = delete; - - ImageView(ImageView&&) noexcept; - auto operator=(ImageView&&) noexcept -> ImageView&; - - [[nodiscard]] - static auto create(const Device& device, - const Image& image, - ImageViewType type = ImageViewType::T2D, - const ImageSubresourceRange& subresource_range = {}) noexcept - -> Expected; - [[nodiscard]] - static auto allocate(const Device& device, - const Image& image, - ImageViewType type = ImageViewType::T2D, - const ImageSubresourceRange& subresource_range = {}) noexcept - -> Expected>; - - [[nodiscard]] - auto type() const noexcept -> ImageViewType; - [[nodiscard]] - auto subresourceRange() const noexcept -> const ImageSubresourceRange&; - - [[nodiscard]] - auto vkHandle() const noexcept -> const vk::raii::ImageView&; - - private: - ImageViewType m_type = {}; - ImageSubresourceRange m_subresource_range = {}; - - DeferInit m_vk_image_view; - }; - - class STORMKIT_API Image { - struct Tag {}; - - public: - struct CreateInfo { - math::ExtentU extent; - PixelFormat format = PixelFormat::RGBA8_UNORM; - UInt32 layers = 1u; - UInt32 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; - - Image(const Device& device, const CreateInfo& create_info, Tag); - ~Image(); - - Image(const Image&) = delete; - auto operator=(const Image&) -> Image& = delete; - - Image(Image&&) noexcept; - auto operator=(Image&&) noexcept -> Image&; - - [[nodiscard]] - static auto create(const Device& device, const CreateInfo& info) noexcept - -> Expected; - [[nodiscard]] - static auto allocate(const Device& device, const CreateInfo& create_info) noexcept - -> Expected>; - - [[nodiscard]] - auto extent() const noexcept -> const math::ExtentU&; - [[nodiscard]] - auto format() const noexcept -> PixelFormat; - [[nodiscard]] - auto type() const noexcept -> ImageType; - [[nodiscard]] - auto samples() const noexcept -> SampleCountFlag; - [[nodiscard]] - auto layers() const noexcept -> UInt32; - [[nodiscard]] - auto faces() const noexcept -> UInt32; - [[nodiscard]] - auto mipLevels() const noexcept -> UInt32; - [[nodiscard]] - auto usages() const noexcept -> ImageUsageFlag; - - [[nodiscard]] - auto vkHandle() const noexcept -> const vk::raii::Image&; - - private: - math::ExtentU m_extent = { 0, 0, 0 }; - PixelFormat m_format = {}; - UInt32 m_layers = 0; - UInt32 m_faces = 0; - UInt32 m_mip_levels = 0; - ImageType m_type = {}; - ImageCreateFlag m_flags = {}; - SampleCountFlag m_samples = {}; - ImageUsageFlag m_usages = {}; - - DeferInit m_vk_image; - vma::UniqueAllocation m_vma_allocation; - }; - - struct ImageMemoryBarrier { - AccessFlag src; - AccessFlag dst; - - ImageLayout old_layout; - ImageLayout new_layout; - - UInt32 src_queue_family_index = QUEUE_FAMILY_IGNORED; - UInt32 dst_queue_family_index = QUEUE_FAMILY_IGNORED; - - const Image& image; - ImageSubresourceRange range; - }; -} // namespace stormkit::gpu - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::gpu { - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Sampler::Sampler(const Device& device, const Settings& settings, Tag) - : m_settings { settings } { - device.vkHandle() - .createSampler( - { .magFilter = narrow(m_settings.mag_filter), - .minFilter = narrow(m_settings.min_filter), - .mipmapMode = narrow(m_settings.mipmap_mode), - .addressModeU = narrow(m_settings.address_mode_u), - .addressModeV = narrow(m_settings.address_mode_v), - .addressModeW = narrow(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 = narrow(m_settings.compare_operation), - .minLod = m_settings.min_lod, - .maxLod = m_settings.max_lod, - .borderColor = narrow(m_settings.border_color), - .unnormalizedCoordinates = m_settings.unnormalized_coordinates }) - .transform_error(core :.monadic::map(core :.monadic::narrow(), - core :.monadic::throw_as_exception())); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Sampler::~Sampler() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Sampler::Sampler(Sampler&& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Sampler::operator=(Sampler&& other) noexcept -> Sampler& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Sampler::create(const Device& device, - const Settings& settings) noexcept - -> Expected try { - return Sampler { device, settings, Tag {} }; - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Sampler::allocate(const Device& device, - const Settings& settings) noexcept - -> Expected> try { - return std::make_unique(device, settings, Tag {}); - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Sampler::settings() const noexcept -> const Settings& { - return m_settings; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Sampler::vkHandle() const noexcept -> const vk::raii::Sampler& { - return m_vk_sampler; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE ImageView::ImageView(const Device& device, - const Image& image, - ImageViewType type, - const ImageSubresourceRange& subresource_range, - Tag) - : m_type { type }, m_subresource_range { subresource_range } { - const auto vk_subresource_range - = vk::ImageSubresourceRange {} - .setAspectMask(narrow(m_subresource_range.aspect_mask)) - .setBaseMipLevel(m_subresource_range.base_mip_level) - .setLevelCount(m_subresource_range.level_count) - .setBaseArrayLayer(m_subresource_range.base_array_layer) - .setLayerCount(m_subresource_range.layer_count); - - device.vkHandle() - .createImageView({ - .image = *image.vkHandle(), - .viewType = narrow(m_type), - .format = narrow(image.format()), - .components = { .r = vk::ComponentSwizzle::eR, - .g = vk::ComponentSwizzle::eG, - .b = vk::ComponentSwizzle::eB, - .a = vk::ComponentSwizzle::eA }, - .subresourceRange = vk_subresource_range, - }) - .transform(core :.monadic::set(m_vk_image_view)) - .transform_error(core :.monadic::map(core :.monadic::narrow(), - core :.monadic::throw_as_exception())); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE ImageView::~ImageView() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE ImageView::ImageView(ImageView&& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto ImageView::operator=(ImageView&& other) noexcept - -> ImageView& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - ImageView::create(const Device& device, - const Image& image, - ImageViewType type, - const ImageSubresourceRange& subresource_range) noexcept - -> Expected try { - return ImageView { device, image, type, subresource_range, Tag {} }; - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - ImageView::allocate(const Device& device, - const Image& image, - ImageViewType type, - const ImageSubresourceRange& subresource_range) noexcept - -> Expected> try { - return std::make_unique(device, image, type, subresource_range, Tag {}); - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto ImageView::type() const noexcept -> ImageViewType { - return m_type; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto ImageView::subresourceRange() const noexcept - -> const ImageSubresourceRange& { - return m_subresource_range; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto ImageView::vkHandle() const noexcept -> const vk::raii::ImageView& { - return m_vk_image_view; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Image::Image(const Device& device, const CreateInfo& info, Tag) - : 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 } { - if (core::checkFlag(m_flags, gpu::ImageCreateFlag::Cube_Compatible)) m_faces = 6u; - const auto create_info - = vk::ImageCreateInfo {} - .setFlags(narrow(m_flags)) - .setImageType(narrow(m_type)) - .setFormat(narrow(m_format)) - .set_extent({ m_extent.width, m_extent.height, m_extent.depth }) - .setMipLevels(m_mip_levels) - .setArrayLayers(m_layers * m_faces) - .setSamples(narrow(m_samples)) - .setTiling(narrow(info.tiling)) - .setUsage(narrow(m_usages)) - .setSharingMode(vk::SharingMode::eExclusive) - .setInitialLayout(vk::ImageLayout::eUndefined); - - device.vkHandle() - .createImage(create_info) - .transform(core :.monadic::set(m_vk_image)) - .transform([this, &info, &device] noexcept -> VulkanExpected { - const auto requirements = m_vk_image->getMemoryRequirements(); - - const auto allocate_info = vma::AllocationCreateInfo {}.setRequiredFlags( - narrow(info.property)); - - auto&& allocator = device.vmaAllocator(); - - auto&& [error, allocation] - = allocator.allocateMemoryUnique(requirements, allocate_info); - - m_vma_allocation = std::move(allocation); - - if (error != vk::Result::eSuccess) [[unlikely]] - return std::unexpected { narrow(error) }; - - error = allocator.bindImageMemory(*m_vma_allocation, **m_vk_image); - - if (error != vk::Result::eSuccess) [[unlikely]] - return std::unexpected { narrow(error) }; - - return {}; - }) - .transform_error(core :.monadic::map(core :.monadic::narrow(), - core :.monadic::throw_as_exception())); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Image::~Image() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Image::Image(Image&& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Image::operator=(Image&& other) noexcept -> Image& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Image::create(const Device& device, - const CreateInfo& create_info) noexcept - -> Expected try { - return Image { device, create_info, Tag {} }; - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Image::allocate(const Device& device, - const CreateInfo& create_info) noexcept - -> Expected> try { - return std::make_unique(device, create_info, Tag {}); - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Image::extent() const noexcept -> const math::ExtentU& { - return m_extent; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Image::Format() const noexcept -> PixelFormat { - return m_format; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Image::type() const noexcept -> ImageType { - return m_type; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Image::samples() const noexcept -> SampleCountFlag { - return m_samples; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Image::layers() const noexcept -> UInt32 { - return m_layers; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Image::faces() const noexcept -> UInt32 { - return m_faces; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Image::mipLevels() const noexcept -> UInt32 { - return m_mip_levels; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Image::usages() const noexcept -> ImageUsageFlag { - return m_usages; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Image::vkHandle() const noexcept -> const vk::raii::Image& { - expects(m_vk_image.initialized()); - return *m_vk_image; - } - -} // namespace stormkit::gpu diff --git a/modules/stormkit/Gpu/Resource/Shader.mpp b/modules/stormkit/Gpu/Resource/Shader.mpp deleted file mode 100644 index 8d89c3e22..000000000 --- a/modules/stormkit/Gpu/Resource/Shader.mpp +++ /dev/null @@ -1,216 +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 - -export module stormkit.Gpu:Resource.Shader; - -import std; - -import stormkit.core; -import stormkit.Gpu.Vulkan; - -import :Core; - -export namespace stormkit::gpu { - class STORMKIT_API Shader { - struct Tag {}; - - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::Shader_Module; - - Shader(const Device& device, - const std::filesystem::path& filepath, - ShaderStageFlag type, - Tag); - Shader(const Device& device, std::span data, ShaderStageFlag type, Tag); - ~Shader(); - - Shader(const Shader&) = delete; - auto operator=(const Shader&) -> Shader& = delete; - - Shader(Shader&&) noexcept; - auto operator=(Shader&&) noexcept -> Shader&; - - [[nodiscard]] - static auto load_from_file(const Device& device, - const std::filesystem::path& filepath, - ShaderStageFlag type) noexcept -> Expected; - [[nodiscard]] - static auto fromBytes(const Device& device, - std::span data, - ShaderStageFlag type) noexcept -> Expected; - [[nodiscard]] - static auto fromSpirv(const Device& device, - std::span data, - ShaderStageFlag type) noexcept -> Expected; - - [[nodiscard]] - static auto allocate_and_load_from_file(const Device& device, - const std::filesystem::path& filepath, - ShaderStageFlag type) noexcept - -> Expected>; - [[nodiscard]] - static auto allocateFromBytes(const Device& device, - std::span data, - ShaderStageFlag type) noexcept - -> Expected>; - [[nodiscard]] - static auto allocateFromSpirv(const Device& device, - std::span data, - ShaderStageFlag type) noexcept - -> Expected>; - - [[nodiscard]] - auto type() const noexcept -> ShaderStageFlag; - [[nodiscard]] - auto source() const noexcept -> const std::vector&; - // const DescriptorSetLayout &descriptorSetLayout() const noexcept; - - [[nodiscard]] - auto vkHandle() const noexcept -> const vk::raii::ShaderModule&; - - private: - auto compile(const Device& device) -> void; - auto reflect() noexcept -> void; - - ShaderStageFlag m_type = ShaderStageFlag::NONE; - std::vector m_source = {}; - - DeferInit m_vk_shader_module; - }; -} // namespace stormkit::gpu - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::gpu { - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Shader::Shader(const Device& device, - const std::filesystem::path& filepath, - ShaderStageFlag type, - Tag) - : m_type { type } { - auto stream = std::ifstream { filepath.string(), std::ios::binary | std::ios::ate }; - const auto size = stream.tellg(); - - m_source.resize(size); - - read(stream, as_bytes(m_source)); - - compile(device); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - Shader::Shader(const Device& device, std::span data, ShaderStageFlag type, Tag) - : m_type { type } { - m_source.reserve(std::size(data)); - std::ranges::copy(data, std::back_inserter(m_source)); - - compile(device); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Shader::~Shader() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Shader::Shader(Shader&& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Shader::operator=(Shader&& other) noexcept -> Shader& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Shader::load_from_file(const Device& device, - const std::filesystem::path& filepath, - ShaderStageFlag type) noexcept - -> Expected try { - return Shader { device, std::move(filepath), type, Tag {} }; - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Shader::fromBytes(const Device& device, - std::span data, - ShaderStageFlag type) noexcept - -> Expected try { - return Shader { device, viewAs(data), type, Tag {} }; - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Shader::fromSpirv(const Device& device, - std::span data, - ShaderStageFlag type) noexcept - -> Expected try { - return Shader { device, data, type, Tag {} }; - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - Shader::allocate_and_load_from_file(const Device& device, - const std::filesystem::path& filepath, - ShaderStageFlag type) noexcept - -> Expected> try { - return std::make_unique(device, filepath, type, Tag {}); - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Shader::allocateFromBytes(const Device& device, - std::span data, - ShaderStageFlag type) noexcept - -> Expected> try { - return std::make_unique(device, viewAs(data), type, Tag {}); - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Shader::allocateFromSpirv(const Device& device, - std::span data, - ShaderStageFlag type) noexcept - -> Expected> try { - return std::make_unique(device, data, type, Tag {}); - } catch (const Result& result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Shader::compile(const Device& device) -> void { - const auto create_info = vk::ShaderModuleCreateInfo {}.setCode(m_source); - - device.vkHandle() - .createShaderModule(create_info) - .transform(core :.monadic::set(m_vk_shader_module)) - .transform_error(core :.monadic::map(core :.monadic::narrow(), - core :.monadic::throw_as_exception())); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Shader::type() const noexcept -> ShaderStageFlag { - return m_type; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Shader::source() const noexcept -> const std::vector& { - return m_source; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Shader::vkHandle() const noexcept -> const vk::raii::ShaderModule& { - return m_vk_shader_module; - } -} // namespace stormkit::gpu diff --git a/modules/stormkit/Gpu/Resource/Swapchain.mpp b/modules/stormkit/Gpu/Resource/Swapchain.mpp deleted file mode 100644 index 9e178789b..000000000 --- a/modules/stormkit/Gpu/Resource/Swapchain.mpp +++ /dev/null @@ -1,301 +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 - -export module stormkit.Gpu:Resource.Swapchain; - -import std; - -import stormkit.core; -import stormkit.Gpu.Vulkan; - -import :Core; -import :Resource.Image; - -export namespace stormkit::gpu { - class Queue; - - class STORMKIT_API SwapchainImage { - struct Tag {}; - - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::Image; - - SwapchainImage(const math::ExtentU& extent, - PixelFormat format, - const vk::Image& image, - Tag) noexcept; - ~SwapchainImage(); - - SwapchainImage(const SwapchainImage&) = delete; - auto operator=(const SwapchainImage&) -> SwapchainImage& = delete; - - SwapchainImage(SwapchainImage&&) noexcept; - auto operator=(SwapchainImage&&) noexcept -> SwapchainImage&; - - [[nodiscard]] - static auto create(const math::ExtentU& extent, - PixelFormat format, - const vk::Image& image) noexcept -> SwapchainImage; - [[nodiscard]] - static auto allocate(const math::ExtentU& extent, - PixelFormat format, - const vk::Image& image) noexcept -> std::unique_ptr; - - [[nodiscard]] - auto extent() const noexcept -> const math::ExtentU&; - [[nodiscard]] - auto format() const noexcept -> PixelFormat; - [[nodiscard]] - auto type() const noexcept -> ImageType; - [[nodiscard]] - auto samples() const noexcept -> SampleCountFlag; - [[nodiscard]] - auto layers() const noexcept -> UInt32; - [[nodiscard]] - auto faces() const noexcept -> UInt32; - [[nodiscard]] - auto mipLevels() const noexcept -> UInt32; - [[nodiscard]] - auto usages() const noexcept -> ImageUsageFlag; - - [[nodiscard]] - auto vkHandle() const noexcept -> const vk::Image&; - - private: - math::ExtentU m_extent = { 0, 0, 0 }; - PixelFormat m_format = {}; - UInt32 m_layers = 0; - UInt32 m_faces = 0; - UInt32 m_mip_levels = 0; - ImageType m_type = {}; - SampleCountFlag m_samples = {}; - ImageUsageFlag m_usages = {}; - - vk::Image m_vk_image; - }; - - class STORMKIT_API Swapchain { - struct Tag {}; - - public: - static constexpr auto DEBUG_TYPE = DebugObjectType::Swapchain; - - Swapchain(Tag, - const Device& device, - const Surface& surface, - const math::ExtentU& extent, - std::optional old_swapchain = std::nullopt); - ~Swapchain(); - - Swapchain(const Swapchain&) = delete; - auto operator=(const Swapchain&) -> Swapchain& = delete; - - Swapchain(Swapchain&&) noexcept; - auto operator=(Swapchain&&) noexcept -> Swapchain&; - - [[nodiscard]] - static auto create(const Device& device, - const Surface& surface, - const math::ExtentU& extent, - std::optional old_swapchain - = std::nullopt) noexcept -> Expected; - [[nodiscard]] - static auto allocate(const Device& device, - const Surface& surface, - const math::ExtentU& extent, - std::optional old_swapchain - = std::nullopt) noexcept -> Expected>; - - [[nodiscard]] - auto images() const noexcept -> const std::vector&; - [[nodiscard]] - auto acquireNextImage(std::chrono::nanoseconds wait, - const Semaphore& image_available) const noexcept - -> Expected>; - - [[nodiscard]] - auto vkHandle() const noexcept -> const vk::raii::SwapchainKHR&; - - private: - DeferInit m_vk_swapchain; - - math::ExtentU m_extent; - PixelFormat m_pixel_format; - UInt32 m_image_count; - - std::vector m_images; - }; - - template<> - auto toVkHandle(const SwapchainImage& value) noexcept -> decltype(auto); - - template<> - auto toRaiiVkHandle(const SwapchainImage& value) noexcept -> decltype(auto) = delete; -} // namespace stormkit::gpu - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::gpu { - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE SwapchainImage::SwapchainImage(const math::ExtentU& extent, - gpu::PixelFormat format, - const vk::Image& image, - Tag) noexcept - : m_extent { extent }, m_format { format }, m_layers { 1 }, m_faces { 1 }, - m_mip_levels { 1 }, m_type { ImageType::T2D }, m_samples { SampleCountFlag::C1 }, - m_usages { ImageUsageFlag::Transfer_Dst }, m_vk_image { image } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE SwapchainImage::~SwapchainImage() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE SwapchainImage::SwapchainImage(SwapchainImage&& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto SwapchainImage::operator=(SwapchainImage&& other) noexcept - -> SwapchainImage& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto SwapchainImage::create(const math::ExtentU& extent, - gpu::PixelFormat format, - const vk::Image& image) noexcept - -> SwapchainImage { - return SwapchainImage { extent, format, image, Tag {} }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto SwapchainImage::allocate(const math::ExtentU& extent, - gpu::PixelFormat format, - const vk::Image& image) noexcept - -> std::unique_ptr { - return std::make_unique(extent, format, image, Tag {}); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto SwapchainImage::extent() const noexcept -> const math::ExtentU& { - return m_extent; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto SwapchainImage::Format() const noexcept -> PixelFormat { - return m_format; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto SwapchainImage::type() const noexcept -> ImageType { - return m_type; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto SwapchainImage::samples() const noexcept -> SampleCountFlag { - return m_samples; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto SwapchainImage::layers() const noexcept -> UInt32 { - return m_layers; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto SwapchainImage::faces() const noexcept -> UInt32 { - return m_faces; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto SwapchainImage::mipLevels() const noexcept -> UInt32 { - return m_mip_levels; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto SwapchainImage::usages() const noexcept -> ImageUsageFlag { - return m_usages; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto SwapchainImage::vkHandle() const noexcept -> const vk::Image& { - return m_vk_image; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Swapchain::~Swapchain() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Swapchain::Swapchain(Swapchain&& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Swapchain::operator=(Swapchain&& other) noexcept - -> Swapchain& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - Swapchain::create(const Device& device, - const Surface& surface, - const math::ExtentU& extent, - std::optional old_swapchain) noexcept - -> Expected try { - return Swapchain { Tag {}, device, surface, extent, std::move(old_swapchain) }; - } catch (Result result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - Swapchain::allocate(const Device& device, - const Surface& surface, - const math::ExtentU& extent, - std::optional old_swapchain) noexcept - -> Expected> try { - return std::make_unique(Tag {}, - device, - surface, - extent, - std::move(old_swapchain)); - } catch (Result result) { return std::unexpected(result); } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Swapchain::images() const noexcept - -> const std::vector& { - return m_images; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Swapchain::vkHandle() const noexcept - -> const vk::raii::SwapchainKHR& { - return m_vk_swapchain; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template<> - STORMKIT_FORCE_INLINE auto toVkHandle(const SwapchainImage& image) noexcept -> decltype(auto) { - return image.vkHandle(); - } -} // namespace stormkit::gpu diff --git a/modules/stormkit/Gpu/Vulkan.mpp b/modules/stormkit/Gpu/Vulkan.mpp deleted file mode 100644 index 4592443d3..000000000 --- a/modules/stormkit/Gpu/Vulkan.mpp +++ /dev/null @@ -1,17 +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.Gpu.Vulkan; - -import std; - -import stormkit.core; - -export import vulkan_hpp; -export import vk_mem_alloc_hpp; -export import :utils; diff --git a/modules/stormkit/Gpu/Vulkan/Utils.mpp b/modules/stormkit/Gpu/Vulkan/Utils.mpp deleted file mode 100644 index df7442d31..000000000 --- a/modules/stormkit/Gpu/Vulkan/Utils.mpp +++ /dev/null @@ -1,207 +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.Gpu.Vulkan:utils; - -import std; - -import stormkit.core; -import stormkit.log; - -import vulkan_hpp; - -export namespace stormkit::gpu { - template - constexpr auto vkMakeVersion(T major, T minor, T patch) noexcept -> UInt32; - constexpr auto vkVersionMajor(std::integral auto version) noexcept -> UInt32; - constexpr auto vkVersionMinor(std::integral auto version) noexcept -> UInt32; - constexpr auto vkVersionPatch(std::integral auto version) noexcept -> UInt32; - - namespace meta { - using namespace stormkit::meta; - - template - concept IsStormKitVulkanType = requires(T&& t) { t.vkHandle(); }; - - template - concept IsStormKitVulkanWrappedType - = (IsViewPointer and IsStormKitVulkanType>>) - or IsStormKitVulkanType>; - - template - concept IsVulkanFlagsType = vk::FlagTraits::isBitmask; - } // namespace meta - - template - constexpr auto checkFlag(vk::Flags value, T flag) noexcept -> bool; - - template - constexpr auto checkFlag(vk::Flags value, vk::Flags flag) noexcept -> bool; - - template - using VulkanExpected = std::expected; - - template - requires(meta::Is, vk::Result>) - auto vkCall(const T& object, Func&& func, Args&&... args) noexcept - -> VulkanExpected; - - template - requires(meta::Is, vk::Result>) - auto vkCall(const T& object, - Func&& func, - std::span possible_results, - Args&&... args) noexcept -> VulkanExpected; - - template - auto toRaiiVkHandle(T&& value) noexcept -> decltype(auto); - - template - auto toVkHandle(T&& value) noexcept -> decltype(auto); - - template - auto toVkFlags(Flag&& flag) noexcept -> vk::Flags; - - namespace monadic { - auto toRaiiVkHandle() noexcept -> decltype(auto); - auto toVkHandle() noexcept -> decltype(auto); - template - auto toVkFlags() noexcept -> decltype(auto); - } // namespace monadic -} // namespace stormkit::gpu - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::gpu { - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE constexpr auto vkMakeVersion(T major, T minor, T patch) noexcept - -> UInt32 { - return vkVersionMajor(major) | vkVersionMinor(minor) | vkVersionPatch(patch); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE constexpr auto vkVersionMajor(std::integral auto version) noexcept - -> UInt32 { - return as(version >> 22u); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE constexpr auto vkVersionMinor(std::integral auto version) noexcept - -> UInt32 { - return as((version >> 12u) & 0x3ffu); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE constexpr auto vkVersionPatch(std::integral auto version) noexcept - -> UInt32 { - return as(version & 0xfffu); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE constexpr auto checkFlag(vk::Flags value, T flag) noexcept -> bool { - return (value & flag) == flag; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE constexpr auto checkFlag(vk::Flags value, vk::Flags flag) noexcept - -> bool { - return (value & flag) == flag; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - requires(meta::Is, vk::Result>) - STORMKIT_FORCE_INLINE auto vkCall(const T& value, Func&& func_ref, Args&&... args) noexcept - -> VulkanExpected { - return vkCall(value, - std::forward(func_ref), - { vk::Result::eSuccess }, - std::forward(args)...); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - requires(meta::Is, vk::Result>) - STORMKIT_FORCE_INLINE auto vkCall(const T& value, - Func&& func_ref, - std::span possible_results, - Args&&... args) noexcept -> VulkanExpected { - auto func = std::mem_fn(std::forward(func_ref)); - - const auto result = std::invoke(func, value, std::forward(args)...); - if (std::ranges::any_of(possible_results, core :.monadic::is(result))) [[likely]] - return result; - - return std::unexpected { result }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE auto toRaiiVkHandle(T&& value) noexcept -> decltype(auto) { - if constexpr (meta::IsPointer>) - return std::forward(value)->vkHandle(); - else - return std::forward(value).vkHandle(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE auto toVkHandle(T&& value) noexcept -> decltype(auto) { - return *toRaiiVkHandle(std::forward(value)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE auto toVkFlags(Flag&& flag) noexcept -> vk::Flags { - return vk::Flags { narrow(std::forward(flag)) }; - } - - namespace monadic { - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto toRaiiVkHandle() noexcept -> decltype(auto) { - return [](T&& value) static noexcept -> decltype(auto) { - return gpu::toRaiiVkHandle(std::forward(value)); - }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto toVkHandle() noexcept -> decltype(auto) { - return [](T&& value) static noexcept -> decltype(auto) { - return gpu::toVkHandle(std::forward(value)); - }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE auto toVkFlags() noexcept -> decltype(auto) { - return [](Flag&& flag) static noexcept -> decltype(auto) { - return gpu::toVkFlags(std::forward(flag)); - }; - } - - } // namespace monadic -} // namespace stormkit::gpu diff --git a/modules/stormkit/Gpu/Vulkan/vma.mpp b/modules/stormkit/Gpu/Vulkan/vma.mpp deleted file mode 100644 index 94c3f0796..000000000 --- a/modules/stormkit/Gpu/Vulkan/vma.mpp +++ /dev/null @@ -1,83 +0,0 @@ -/*module;*/ -/**/ -/*#define VMA_IMPLEMENTATION*/ -/*#include */ -/**/ -export module vma; -/**/ -/*export namespace VMA_HPP_NAMESPACE {*/ -/* using VMA_HPP_NAMESPACE::operator|;*/ -/* using VMA_HPP_NAMESPACE::operator&;*/ -/* using VMA_HPP_NAMESPACE::operator^;*/ -/* using VMA_HPP_NAMESPACE::operator~;*/ -/* using VMA_HPP_NAMESPACE::Allocation;*/ -/* using VMA_HPP_NAMESPACE::AllocationCreateFlagBits;*/ -/* using VMA_HPP_NAMESPACE::AllocationCreateFlags;*/ -/* using VMA_HPP_NAMESPACE::AllocationCreateInfo;*/ -/* using VMA_HPP_NAMESPACE::AllocationInfo;*/ -/* using VMA_HPP_NAMESPACE::Allocator;*/ -/* using VMA_HPP_NAMESPACE::AllocatorCreateFlagBits;*/ -/* using VMA_HPP_NAMESPACE::AllocatorCreateFlags;*/ -/* using VMA_HPP_NAMESPACE::AllocatorCreateInfo;*/ -/* using VMA_HPP_NAMESPACE::AllocatorInfo;*/ -/* using VMA_HPP_NAMESPACE::Budget;*/ -/* using VMA_HPP_NAMESPACE::createAllocator;*/ -/* using VMA_HPP_NAMESPACE::createVirtualBlock;*/ -/* using VMA_HPP_NAMESPACE::DefragmentationContext;*/ -/* using VMA_HPP_NAMESPACE::DefragmentationFlagBits;*/ -/* using VMA_HPP_NAMESPACE::DefragmentationFlags;*/ -/* using VMA_HPP_NAMESPACE::DefragmentationInfo;*/ -/* using VMA_HPP_NAMESPACE::DefragmentationMove;*/ -/* using VMA_HPP_NAMESPACE::DefragmentationMoveOperation;*/ -/* using VMA_HPP_NAMESPACE::DefragmentationPassMoveInfo;*/ -/* using VMA_HPP_NAMESPACE::DefragmentationStats;*/ -/* using VMA_HPP_NAMESPACE::DetailedStatistics;*/ -/* using VMA_HPP_NAMESPACE::DeviceMemoryCallbacks;*/ -/* using VMA_HPP_NAMESPACE::functionsFromDispatcher;*/ -/* using VMA_HPP_NAMESPACE::MemoryUsage;*/ -/* using VMA_HPP_NAMESPACE::Pool;*/ -/* using VMA_HPP_NAMESPACE::PoolCreateFlagBits;*/ -/* using VMA_HPP_NAMESPACE::PoolCreateFlags;*/ -/* using VMA_HPP_NAMESPACE::PoolCreateInfo;*/ -/* using VMA_HPP_NAMESPACE::Statistics;*/ -/* using VMA_HPP_NAMESPACE::to_string;*/ -/* using VMA_HPP_NAMESPACE::TotalStatistics;*/ -/* using VMA_HPP_NAMESPACE::VirtualAllocation;*/ -/* using VMA_HPP_NAMESPACE::VirtualAllocationCreateFlagBits;*/ -/* using VMA_HPP_NAMESPACE::VirtualAllocationCreateFlags;*/ -/* using VMA_HPP_NAMESPACE::VirtualAllocationCreateInfo;*/ -/* using VMA_HPP_NAMESPACE::VirtualAllocationInfo;*/ -/* using VMA_HPP_NAMESPACE::VirtualBlock;*/ -/* using VMA_HPP_NAMESPACE::VirtualBlockCreateFlagBits;*/ -/* using VMA_HPP_NAMESPACE::VirtualBlockCreateFlags;*/ -/* using VMA_HPP_NAMESPACE::VirtualBlockCreateInfo;*/ -/* using VMA_HPP_NAMESPACE::VulkanFunctions;*/ -/*} // namespace VMA_HPP_NAMESPACE*/ -/**/ -/*#ifndef VULKAN_HPP_NO_SMART_HANDLE*/ -/*export namespace VMA_HPP_NAMESPACE {*/ -/* using VMA_HPP_NAMESPACE::UniqueAllocation;*/ -/* using VMA_HPP_NAMESPACE::UniqueAllocator;*/ -/* using VMA_HPP_NAMESPACE::UniqueBuffer;*/ -/* using VMA_HPP_NAMESPACE::UniqueImage;*/ -/* using VMA_HPP_NAMESPACE::UniquePool;*/ -/* using VMA_HPP_NAMESPACE::UniqueVirtualAllocation;*/ -/* using VMA_HPP_NAMESPACE::UniqueVirtualBlock;*/ -/*} // namespace VMA_HPP_NAMESPACE*/ -/*#endif*/ -/**/ -/*#ifndef VULKAN_HPP_NO_SMART_HANDLE*/ -/*export namespace VMA_HPP_NAMESPACE {*/ -/* using VMA_HPP_NAMESPACE::createAllocatorUnique;*/ -/**/ -/* namespace raii {*/ -/* using Pool = VMA_HPP_NAMESPACE::UniquePool;*/ -/* using Buffer = VMA_HPP_NAMESPACE::UniqueBuffer;*/ -/* using Image = VMA_HPP_NAMESPACE::UniqueImage;*/ -/* using Allocator = VMA_HPP_NAMESPACE::UniqueAllocator;*/ -/* using VirtualBlock = VMA_HPP_NAMESPACE::UniqueVirtualBlock;*/ -/* using Allocation = VMA_HPP_NAMESPACE::UniqueAllocation;*/ -/* using VirtualAllocation = VMA_HPP_NAMESPACE::UniqueVirtualAllocation;*/ -/* } // namespace raii*/ -/*} // namespace VMA_HPP_NAMESPACE*/ -/*#endif*/ diff --git a/modules/stormkit/core.mpp b/modules/stormkit/core.mpp index 42aa270f4..59ad94b1b 100644 --- a/modules/stormkit/core.mpp +++ b/modules/stormkit/core.mpp @@ -4,6 +4,8 @@ export module stormkit.core; +import std.compat; + export import :config; export import :containers; export import :console; diff --git a/modules/stormkit/core/console/io.mpp b/modules/stormkit/core/console/io.mpp index 6a2d2ca61..8323b3f30 100644 --- a/modules/stormkit/core/console/io.mpp +++ b/modules/stormkit/core/console/io.mpp @@ -22,13 +22,15 @@ export namespace stormkit { inline namespace core { namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto get_stderr() noexcept -> std::FILE* { + STORMKIT_FORCE_INLINE STORMKIT_INTRINSIC + inline auto get_stderr() noexcept -> std::FILE* { return std::bit_cast(stderr); } ///////////////////////////////////// ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto get_stdout() noexcept -> std::FILE* { + STORMKIT_FORCE_INLINE STORMKIT_INTRINSIC + inline auto get_stdout() noexcept -> std::FILE* { return std::bit_cast(stdout); } }} // namespace stormkit::core diff --git a/modules/stormkit/core/console/style.mpp b/modules/stormkit/core/console/style.mpp index a3c56be83..3e616c9d5 100644 --- a/modules/stormkit/core/console/style.mpp +++ b/modules/stormkit/core/console/style.mpp @@ -165,11 +165,11 @@ namespace std { out.reserve(14); if (stylized.fg) out += std::string_view { ecma48::FOREGROUND.at(*stylized.fg) }; if (stylized.bg) out += std::string_view { ecma48::BACKGROUND.at(*stylized.bg) }; - if (checkFlag(stylized.modifiers, StyleModifier::BOLD)) out += ecma48::BOLD; - if (checkFlag(stylized.modifiers, StyleModifier::FAINT)) out += ecma48::FAINT; - if (checkFlag(stylized.modifiers, StyleModifier::ITALIC)) out += ecma48::ITALIC; - if (checkFlag(stylized.modifiers, StyleModifier::INVERSE)) out += ecma48::INVERSE; - if (checkFlag(stylized.modifiers, StyleModifier::UNDERLINE)) out += ecma48::UNDERLINE; + if (check_flag_bit(stylized.modifiers, StyleModifier::BOLD)) out += ecma48::BOLD; + if (check_flag_bit(stylized.modifiers, StyleModifier::FAINT)) out += ecma48::FAINT; + if (check_flag_bit(stylized.modifiers, StyleModifier::ITALIC)) out += ecma48::ITALIC; + if (check_flag_bit(stylized.modifiers, StyleModifier::INVERSE)) out += ecma48::INVERSE; + if (check_flag_bit(stylized.modifiers, StyleModifier::UNDERLINE)) out += ecma48::UNDERLINE; return out; }(); diff --git a/modules/stormkit/core/containers.mpp b/modules/stormkit/core/containers.mpp index 6c78a67ee..475c74e8f 100644 --- a/modules/stormkit/core/containers.mpp +++ b/modules/stormkit/core/containers.mpp @@ -4,6 +4,7 @@ export module stormkit.core:containers; +export import :containers.multi_buffer; export import :containers.ringbuffer; export import :containers.tree; export import :containers.utils; diff --git a/modules/stormkit/core/containers/multi_buffer.mpp b/modules/stormkit/core/containers/multi_buffer.mpp new file mode 100644 index 000000000..0a5a52b46 --- /dev/null +++ b/modules/stormkit/core/containers/multi_buffer.mpp @@ -0,0 +1,186 @@ +// 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.core:containers.multi_buffer; + +import std; + +import :meta; +import :typesafe; +import :functional; + +export namespace stormkit { inline namespace core { + template + class MultiBuffer { + public: + explicit constexpr MultiBuffer(std::array sizes_in_bytes); + constexpr ~MultiBuffer(); + + constexpr MultiBuffer(const MultiBuffer&); + constexpr auto operator=(const MultiBuffer&) -> MultiBuffer&; + + constexpr MultiBuffer(MultiBuffer&&) noexcept; + constexpr auto operator=(MultiBuffer&&) noexcept -> MultiBuffer&; + + [[nodiscard]] + constexpr auto size() const noexcept -> RangeExtent; + template + [[nodiscard]] + constexpr auto data(this Self& self) noexcept -> const meta::ForwardConst*; + + template + constexpr auto init_range(V&& init_data) noexcept -> std::span; + template + constexpr auto init_range(V&& init_data) noexcept -> std::span; + + template + [[nodiscard]] + constexpr auto range(this Self& self) noexcept -> std::span>; + + template + [[nodiscard]] + constexpr auto range(this Self& self) noexcept + -> std::span>; + + private: + std::array m_ranges_sizes; + std::array m_ranges_begin; + RangeExtent m_size = 0; + ByteDynArray m_data; + }; +}} // namespace stormkit::core + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit { inline namespace core { + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr MultiBuffer::MultiBuffer(std::array sizes_in_bytes) + : m_ranges_sizes { sizes_in_bytes } { + auto i = 0; + for (auto&& size : m_ranges_sizes) { + m_ranges_begin[i++] = m_size; + m_size += size; + } + m_data.resize(m_size); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE constexpr MultiBuffer::MultiBuffer(const MultiBuffer&) = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto MultiBuffer::operator=(const MultiBuffer&) -> MultiBuffer& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE constexpr MultiBuffer::MultiBuffer(MultiBuffer&&) noexcept = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto MultiBuffer::operator=(MultiBuffer&&) noexcept -> MultiBuffer& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE constexpr MultiBuffer::~MultiBuffer() = default; + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + constexpr auto MultiBuffer::size() const noexcept -> RangeExtent { + return m_size; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + template + STORMKIT_FORCE_INLINE + constexpr auto MultiBuffer::data(this Self& self) noexcept + -> const meta::ForwardConst* { + return std::ranges::data(self.m_data); + } + + ////////////////////////////////////// + ///////////////////////////////////// + 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"); + 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)); + } + + ////////////////////////////////////// + ///////////////////////////////////// + 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 { std::ranges::data(m_data) + m_ranges_begin[TYPE_INDEX], + m_ranges_sizes[TYPE_INDEX] }; + + auto begin = std::ranges::begin(span); + auto end = std::ranges::end(span); + for (auto&& bytes : + std::forward(init_data) | std::views::transform(monadic::as_bytes(Force {}))) { + std::ranges::copy(bytes, begin); + begin += std::ranges::size(bytes); + assert(begin != end); + } + + 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"); + static constexpr auto TYPE_INDEX = meta::find_type_index_of(); + return self.template range(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + 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 = std::ranges::begin(self.m_data) + self.m_ranges_begin[TYPE_INDEX]; + return std::span { +#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)), +#else + std::launder(std::bit_cast(ptr)), +#endif + self.m_ranges_sizes[TYPE_INDEX] / sizeof(U) + }; + } +}} // namespace stormkit::core diff --git a/modules/stormkit/core/containers/ringbuffer.mpp b/modules/stormkit/core/containers/ringbuffer.mpp index d6a63c167..1e3bc12de 100644 --- a/modules/stormkit/core/containers/ringbuffer.mpp +++ b/modules/stormkit/core/containers/ringbuffer.mpp @@ -10,7 +10,7 @@ export module stormkit.core:containers.ringbuffer; import std; -import :utils.contrat; +import :utils.contract; import :typesafe.integer; import :typesafe.byte; import :meta; @@ -272,7 +272,7 @@ namespace stormkit { inline namespace core { template template auto RingBuffer::get_ptr(this Self& self, ExtentType pos) noexcept -> decltype(auto) { - using OutPtr = meta::ConstnessLike; + using OutPtr = meta::ForwardConst; auto addr = std::forward_like(&(self.m_buffer[pos * sizeof(ValueType)])); return std::launder(std::bit_cast(addr)); diff --git a/modules/stormkit/core/containers/utils.mpp b/modules/stormkit/core/containers/utils.mpp index 80c208d46..187d6c8c8 100644 --- a/modules/stormkit/core/containers/utils.mpp +++ b/modules/stormkit/core/containers/utils.mpp @@ -2,6 +2,10 @@ // 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:containers.utils; import std; @@ -9,35 +13,72 @@ import std; import :meta; import :typesafe.byte; +namespace stdr = std::ranges; + export namespace stormkit { inline namespace core { - template + template constexpr auto merge(T& output, const U&... ranges) noexcept -> void; - template + template constexpr auto concat(const T& first, const U&... others) noexcept - -> std::vector>; + -> std::vector>; - template + template constexpr auto move_and_merge(T& output, U&&... ranges) noexcept -> void; - template + template constexpr auto move_and_concat(T&& first, U&&... others) noexcept - -> std::vector>; - - template - requires((meta::Is and ...) - or (std::convertible_to and ...) - or (std::constructible_from and ...)) - constexpr auto into_array(T&& first, Args&&... args) noexcept -> decltype(auto); - - template - requires((meta::Is and ...) - or (std::convertible_to and ...) - or (std::constructible_from and ...)) - constexpr auto into_dyn_array(T&& first, Args&&... args) noexcept -> decltype(auto); - - template - constexpr auto to_dyn_array(T&& range) noexcept -> decltype(auto); + -> std::vector>; + + template + requires(sizeof...(Args) > 0) + constexpr auto to_array(Args&&... args) noexcept + -> std::array, sizeof...(Args)>; + + template + requires(sizeof...(Args) > 0) + constexpr auto into_array(Args&&... args) noexcept + -> std::array, sizeof...(Args)>; + + template + constexpr auto to_dyn_array(T&& range) noexcept -> std::vector>; + + template + requires(sizeof...(Args) > 0) + constexpr auto into_dyn_array(Args&&... args) noexcept + -> std::vector>; + + template + requires(sizeof...(Args) > 0) + constexpr auto to_array_of(Args&&... args) noexcept -> std::array; + + template + requires(sizeof...(Args) > 0) + constexpr auto into_array_of(Args&&... args) noexcept -> std::array; + + template + requires(sizeof...(Args) > 0) + constexpr auto to_dyn_array_of(Args&&... args) noexcept -> std::vector; + + template + requires(sizeof...(Args) > 0) + constexpr auto into_dyn_array_of(Args&&... args) noexcept -> std::vector; + + template + requires(sizeof...(Args) > 0) + constexpr auto to_dyn_array(Args&&... args) noexcept + -> std::vector>; + + template + constexpr auto as_view(T& range) noexcept -> std::string_view; + + template + constexpr auto as_view(T& range) noexcept + -> std::span>>; + + template + constexpr auto as_view(T& range, Force) noexcept + -> std::span>>; }} // namespace stormkit::core //////////////////////////////////////////////////////////////////// @@ -47,17 +88,20 @@ export namespace stormkit { inline namespace core { namespace stormkit { inline namespace core { //////////////////////////////////////// //////////////////////////////////////// - template + template + STORMKIT_FORCE_INLINE constexpr auto merge(T& output, const U&... ranges) noexcept -> void { - output.reserve(std::size(output) + (std::ranges::size(ranges) + ...)); - (std::ranges::copy(ranges, std::back_inserter(output)), ...); + output.reserve(std::size(output) + (stdr::size(ranges) + ...)); + (stdr::copy(ranges, std::back_inserter(output)), ...); } //////////////////////////////////////// //////////////////////////////////////// - template + template + STORMKIT_FORCE_INLINE + STORMKIT_PURE constexpr auto concat(const T& first, const U&... others) noexcept - -> std::vector> { + -> std::vector> { auto output = std::vector> {}; merge(output, first, others...); @@ -66,17 +110,20 @@ namespace stormkit { inline namespace core { //////////////////////////////////////// //////////////////////////////////////// - template + template + STORMKIT_FORCE_INLINE constexpr auto move_and_merge(T& output, U&&... ranges) noexcept -> void { - output.reserve(std::size(output) + (std::ranges::size(ranges) + ...)); - (std::ranges::move(std::forward(ranges), std::back_inserter(output)), ...); + output.reserve(std::size(output) + (stdr::size(ranges) + ...)); + (stdr::move(std::forward(ranges), std::back_inserter(output)), ...); } //////////////////////////////////////// //////////////////////////////////////// - template + template + STORMKIT_FORCE_INLINE + STORMKIT_PURE constexpr auto move_and_concat(T&& first, U&&... others) noexcept - -> std::vector> { + -> std::vector> { auto output = std::vector> {}; move_and_merge(output, std::forward(first), std::forward(others)...); @@ -85,28 +132,119 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// - template - requires((meta::Is and ...) - or (std::convertible_to and ...) - or (std::constructible_from and ...)) - constexpr auto into_array(T&& first, Args&&... args) noexcept -> decltype(auto) { - return std::array { std::forward(first), static_cast(std::forward(args))... }; + template + requires(sizeof...(Args) > 0) + STORMKIT_FORCE_INLINE + STORMKIT_CONST + constexpr auto to_array(Args&&... args) noexcept + -> std::array, sizeof...(Args)> { + return std::array { std::forward(args)... }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(sizeof...(Args) > 0) + STORMKIT_FORCE_INLINE + STORMKIT_CONST + constexpr auto into_array(Args&&... args) noexcept + -> std::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)... }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE STORMKIT_PURE + constexpr auto to_dyn_array(Args&&... args) noexcept + -> std::vector> { + return std::vector { std::move(args)... }; } ///////////////////////////////////// ///////////////////////////////////// - template - requires((meta::Is and ...) - or (std::convertible_to and ...) - or (std::constructible_from and ...)) - constexpr auto into_dyn_array(T&& first, Args&&... args) noexcept -> decltype(auto) { - return std::vector { std::forward(first), static_cast(std::forward(args))... }; + template + STORMKIT_FORCE_INLINE STORMKIT_PURE + constexpr auto into_dyn_array(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)... }; } ///////////////////////////////////// ///////////////////////////////////// - template - constexpr auto to_dyn_array(T&& range) noexcept -> decltype(auto) { - return range | std::ranges::to(); + template + STORMKIT_FORCE_INLINE + STORMKIT_PURE + constexpr auto to_dyn_array(T&& range) noexcept -> std::vector> { + return std::forward(range) | stdr::to(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(sizeof...(Args) > 0) + STORMKIT_FORCE_INLINE + STORMKIT_CONST + constexpr auto to_array_of(Args&&... args) noexcept -> std::array { + return std::array { std::forward(args)... }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(sizeof...(Args) > 0) + STORMKIT_FORCE_INLINE + STORMKIT_CONST + 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)... }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE STORMKIT_PURE + constexpr auto to_dyn_array_of(Args&&... args) noexcept -> std::vector { + return std::vector { std::move(args)... }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + 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)... }; + } + + template + STORMKIT_FORCE_INLINE + STORMKIT_CONST + constexpr auto as_view(T& range) noexcept -> std::string_view { + return std::string_view { range }; + } + + template + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto as_view(T& range) noexcept + -> std::span>> { + return { range }; + } + + template + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto as_view(T& range, Force) noexcept + -> std::span>> { + return { range }; } }} // namespace stormkit::core diff --git a/modules/stormkit/core/functional/error_handling.mpp b/modules/stormkit/core/functional/error_handling.mpp index 36dd237d0..97ff7f223 100644 --- a/modules/stormkit/core/functional/error_handling.mpp +++ b/modules/stormkit/core/functional/error_handling.mpp @@ -14,7 +14,7 @@ import :meta.concepts; import :meta.traits; import :console; -import :utils.contrat; +import :utils.contract; export namespace stormkit { inline namespace core { namespace monadic { [[nodiscard]] diff --git a/modules/stormkit/core/functional/monadic.mpp b/modules/stormkit/core/functional/monadic.mpp index 96b2321ac..a745b33c7 100644 --- a/modules/stormkit/core/functional/monadic.mpp +++ b/modules/stormkit/core/functional/monadic.mpp @@ -12,6 +12,7 @@ import std; import :meta; +import :containers.utils; import :typesafe.integer_casts; import :functional.utils; import :typesafe.ref; @@ -26,13 +27,17 @@ export namespace stormkit { inline namespace core { namespace monadic { operator T&&(this auto&& self) noexcept; }; + [[nodiscard]] + constexpr auto identity(auto&& value) noexcept -> decltype(auto); + [[nodiscard]] + constexpr auto consume(auto& value) noexcept -> decltype(auto); template [[nodiscard]] 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); @@ -43,16 +48,30 @@ export namespace stormkit { inline namespace core { namespace monadic { [[nodiscard]] constexpr auto emplace_to(std::ranges::range auto& container) noexcept -> decltype(auto); [[nodiscard]] - constexpr auto is(auto&& value) noexcept; + constexpr auto is(auto&& value) noexcept -> decltype(auto); [[nodiscard]] - constexpr auto append_to(std::ranges::range auto& range) noexcept; + constexpr auto append_to(std::ranges::range auto& range) noexcept -> decltype(auto); [[nodiscard]] - constexpr auto wrap(auto&& func) noexcept; + constexpr auto wrap(auto&& func) noexcept -> decltype(auto); template [[nodiscard]] - constexpr auto wrap() noexcept; + constexpr auto wrap() noexcept -> decltype(auto); + [[nodiscard]] + constexpr auto as_byte() noexcept -> decltype(auto); + [[nodiscard]] + constexpr auto as_bytes() noexcept -> decltype(auto); + [[nodiscard]] + constexpr auto as_bytes(Force) noexcept -> decltype(auto); [[nodiscard]] - constexpr auto as_byte() noexcept; + constexpr auto as_view() noexcept -> decltype(auto); + // template + [[nodiscard]] + constexpr auto as_tuple(auto&&... args) noexcept -> decltype(auto); + [[nodiscard]] + constexpr auto unpack_tuple_to(auto&& func) noexcept -> decltype(auto); + + [[nodiscard]] + constexpr auto noop() noexcept -> decltype(auto); template First, @@ -65,7 +84,7 @@ export namespace stormkit { inline namespace core { namespace monadic { [[nodiscard]] constexpr auto either(std::regular_invocable auto&&... visitors) noexcept - -> decltype(auto); + -> decltype(auto); template [[nodiscard]] @@ -91,15 +110,20 @@ export namespace stormkit { inline namespace core { namespace monadic { [[nodiscard]] constexpr auto init() noexcept -> decltype(auto); - template + template [[nodiscard]] - constexpr auto init(Args&&... args) noexcept -> decltype(auto); + constexpr auto init(auto&&... args) noexcept -> decltype(auto); [[nodiscard]] constexpr auto as_ref() noexcept -> decltype(auto); [[nodiscard]] constexpr auto as_ref_mut() noexcept -> decltype(auto); + [[nodiscard]] + constexpr auto unref() noexcept -> decltype(auto); + [[nodiscard]] + constexpr auto unref_mut() noexcept -> decltype(auto); + template [[nodiscard]] constexpr auto forward_like() noexcept -> decltype(auto); @@ -112,7 +136,28 @@ export namespace stormkit { inline namespace core { namespace monadic { namespace stormkit { inline namespace core { namespace monadic { ///////////////////////////////////// ///////////////////////////////////// - STORMKIT_FORCE_INLINE constexpr auto value() noexcept -> decltype(auto) { + template + [[nodiscard]] + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto identity(T&& value) noexcept -> decltype(auto) { + return [value = std::forward(value)] mutable noexcept -> decltype(auto) { + return std::forward_like(value); + }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + [[nodiscard]] + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto consume(T& value) noexcept -> decltype(auto) { + return [value = std::move(value)] mutable noexcept -> T { return std::move(value); }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto value() noexcept -> decltype(auto) { return [](T&& value) static noexcept -> decltype(auto) { return std::forward_like(value.get()); }; @@ -121,8 +166,9 @@ namespace stormkit { inline namespace core { namespace monadic { ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr auto as(const std::source_location& location) noexcept - -> decltype(auto) { + STORMKIT_FORCE_INLINE + STORMKIT_CONST + constexpr auto as(const std::source_location& location) noexcept -> decltype(auto) { return [location](U&& value) noexcept -> T { return core::as(std::forward(value), location); }; @@ -131,7 +177,9 @@ namespace stormkit { inline namespace core { namespace monadic { ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr auto narrow() noexcept -> decltype(auto) { + STORMKIT_FORCE_INLINE + STORMKIT_CONST + constexpr auto narrow() noexcept -> decltype(auto) { return [](U&& value) static noexcept -> decltype(auto) { return core::narrow(std::forward(value)); }; @@ -139,15 +187,19 @@ namespace stormkit { inline namespace core { namespace monadic { //////////////////////////////////////// //////////////////////////////////////// - STORMKIT_FORCE_INLINE constexpr auto is(auto&& value) noexcept { - return [value = std::forward(value)](T&& other) { - return core::is(value, std::forward(other)); + template + STORMKIT_FORCE_INLINE + STORMKIT_CONST + constexpr auto is(T&& value) noexcept -> decltype(auto) { + return [value = std::forward(value)](U&& other) { + return core::is(value, std::forward(other)); }; } //////////////////////////////////////// //////////////////////////////////////// - STORMKIT_FORCE_INLINE constexpr auto append_to(std::ranges::range auto& range) noexcept { + STORMKIT_FORCE_INLINE STORMKIT_CONST + 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)); }; @@ -155,90 +207,152 @@ namespace stormkit { inline namespace core { namespace monadic { //////////////////////////////////////// //////////////////////////////////////// - STORMKIT_FORCE_INLINE constexpr auto wrap(auto&& func) noexcept { - return - [func = std::forward(func)](Args&&... args) noexcept { - return std::invoke(func, std::forward(args)...); - }; + template + STORMKIT_FORCE_INLINE + STORMKIT_CONST + constexpr auto wrap(T&& func) noexcept { + return [func = std::forward(func)](Args&&... args) noexcept + -> decltype(auto) { return std::invoke(func, std::forward(args)...); }; } //////////////////////////////////////// //////////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr auto wrap() noexcept { - return [](Args&&... args) static noexcept { + STORMKIT_FORCE_INLINE + STORMKIT_CONST + constexpr auto wrap() noexcept { + return [](Args&&... args) static noexcept -> decltype(auto) { return std::invoke(Func, std::forward(args)...); }; } + // //////////////////////////////////////// + // //////////////////////////////////////// + // STORMKIT_FORCE_INLINE STORMKIT_CONST + // constexpr auto as_byte() noexcept -> decltype(auto) { + // return [](auto&& val) static noexcept { return core::as_byte(val); }; + // } + //////////////////////////////////////// //////////////////////////////////////// - STORMKIT_FORCE_INLINE constexpr auto as_byte() noexcept { - return [](auto&& val) static noexcept { return core::as(val); }; + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto as_bytes() noexcept -> decltype(auto) { + return [](const auto& val) static noexcept { return core::as_bytes(val); }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto as_bytes(Force) noexcept -> decltype(auto) { + return [](const auto& val) static noexcept { return core::as_bytes(val, Force {}); }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto as_view() noexcept -> decltype(auto) { + return [](T& val) static noexcept { return core::as_view(val); }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + STORMKIT_CONST + constexpr auto as_tuple(Args&&... args) noexcept -> decltype(auto) { + return [... args = std::forward(args)](T&& arg) mutable noexcept { + return std::make_tuple(std::forward(args)..., std::forward(arg)); + }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + STORMKIT_CONST + constexpr auto unpack_tuple_to(T&& func) noexcept -> decltype(auto) { + return [func = std::forward(func)](U&& arg) noexcept { +#if defined(__cpp_­structured_­bindings) and __cpp_­structured_­bindings >= 202411L + auto&& [... values] = std::forward(arg); + return std::invoke(func, values...); +#else + return std::apply(func, std::forward(arg)); +#endif + }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto noop() noexcept -> decltype(auto) { + return [](auto&&...) static noexcept -> void {}; } ///////////////////////////////////// ///////////////////////////////////// - STORMKIT_FORCE_INLINE constexpr auto discard() noexcept -> decltype(auto) { - return [](auto&&) static noexcept -> void {}; + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto discard() noexcept -> decltype(auto) { + return [](auto&&...) static noexcept -> void {}; } ///////////////////////////////////// ///////////////////////////////////// - STORMKIT_FORCE_INLINE constexpr auto set(auto& output) noexcept -> decltype(auto) { + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto set(auto& output) noexcept -> decltype(auto) { return - [&output](T&& value) noexcept -> void { output = std::forward(value); }; + [&output](T&& value) noexcept -> void { output = std::forward(value); }; } ///////////////////////////////////// ///////////////////////////////////// - STORMKIT_FORCE_INLINE constexpr auto emplace_to(std::ranges::range auto& container) noexcept - -> decltype(auto) { + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto emplace_to(std::ranges::range auto& container) noexcept -> decltype(auto) { return [&container](T&& value) noexcept -> void { container.emplace_back(std::forward(value)); }; } template - inline constexpr auto is_noexcept - = noexcept(std::declval()(std::declval()(std::declval()...))); + constexpr auto is_noexcept = noexcept(std::declval< + Second>()(std::declval< + First>()(std::declval()...))); ///////////////////////////////////// ///////////////////////////////////// template First, std::invocable> Second> - STORMKIT_FORCE_INLINE constexpr auto map(First&& first, Second&& second) noexcept - -> decltype(auto) { + STORMKIT_FORCE_INLINE + STORMKIT_CONST + constexpr auto map(First&& first, Second&& second) noexcept -> decltype(auto) { return map(std::forward(first), std::forward(second)); } ///////////////////////////////////// ///////////////////////////////////// - STORMKIT_FORCE_INLINE constexpr auto map(auto&& first, auto&& second) noexcept - -> decltype(auto) { - using First = decltype(first); - using Second = decltype(second); + template + STORMKIT_FORCE_INLINE + STORMKIT_CONST + constexpr auto map(First&& first, Second&& second) noexcept -> decltype(auto) { using FirstP = meta::CanonicalType; using SecondP = meta::CanonicalType; - return - [first = std::forward(first), - second = std::forward(second)]( - Args&&... args) noexcept(is_noexcept) -> decltype(auto) { - return second(first(std::forward(args)...)); - }; + return [first = std::forward(first), second = std::forward(second)]< + typename... Args>(Args&&... args) noexcept(is_noexcept) + -> decltype(auto) { return second(first(std::forward(args)...)); }; } ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr auto either(meta::IsUnaryPredicate auto&& predicate, - std::invocable auto&& true_, - std::invocable auto&& false_) noexcept - -> decltype(auto) { - [predicate = std::move(predicate), true_ = std::move(true_), false_ = std::move(false_)]( - auto&& elem) noexcept -> decltype(auto) { + STORMKIT_FORCE_INLINE + STORMKIT_CONST + constexpr auto either(meta::IsUnaryPredicate auto&& predicate, + std::invocable auto&& true_, + std::invocable auto&& false_) noexcept -> decltype(auto) { + [predicate = std::move(predicate), + true_ = std::move(true_), + false_ = std::move(false_)](auto&& elem) noexcept -> decltype(auto) { if (predicate(elem)) return first(std::forward(elem)); return second(elem); }; @@ -247,7 +361,9 @@ namespace stormkit { inline namespace core { namespace monadic { ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr auto get() noexcept -> decltype(auto) { + STORMKIT_FORCE_INLINE + STORMKIT_CONST + constexpr auto get() noexcept -> decltype(auto) { return [](U&& value) static noexcept -> decltype(auto) { return std::get(std::forward(value)); }; @@ -255,8 +371,9 @@ namespace stormkit { inline namespace core { namespace monadic { ///////////////////////////////////// ///////////////////////////////////// - STORMKIT_FORCE_INLINE constexpr auto is() noexcept -> decltype(auto) { - return [](T&& first, U&& second) static noexcept { + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto is() noexcept -> decltype(auto) { + return [](T&& first, U&& second) static noexcept -> decltype(auto) { return core::is(std::forward(first), std::forward(second)); }; } @@ -264,38 +381,45 @@ namespace stormkit { inline namespace core { namespace monadic { ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr auto is() noexcept -> decltype(auto) { - return [](U&& value) static noexcept { - return core::is(std::forward(value)); - }; + STORMKIT_FORCE_INLINE + STORMKIT_CONST + constexpr auto is() noexcept -> decltype(auto) { + return + [](U&& value) static noexcept { return core::is(std::forward(value)); }; } ///////////////////////////////////// ///////////////////////////////////// - STORMKIT_FORCE_INLINE constexpr auto - either(std::regular_invocable auto&&... visitors) noexcept -> decltype(auto) { - return [... visitors = std::forward(visitors)]( - auto&& variant) mutable noexcept -> decltype(auto) { - return std::visit(core::Overloaded { std::forward(visitors)... }, - std::forward(variant)); - }; + template... Args> + STORMKIT_FORCE_INLINE + STORMKIT_CONST + 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)); + }; } ///////////////////////////////////// ///////////////////////////////////// - STORMKIT_FORCE_INLINE constexpr auto clone() noexcept -> decltype(auto) { - return [](auto&& value) static noexcept( - noexcept(std::is_nothrow_copy_constructible_v>)) { - return auto(std::forward(value)); - }; + 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)); }; } ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr auto init() noexcept -> decltype(auto) { + STORMKIT_FORCE_INLINE + STORMKIT_CONST + constexpr auto init() noexcept -> decltype(auto) { return [](Args&&... args) static noexcept( - noexcept(std::is_nothrow_constructible_v)) -> decltype(auto) { + noexcept(std::is_nothrow_constructible_v)) -> decltype(auto) { return T { std::forward(args)... }; }; } @@ -303,33 +427,56 @@ namespace stormkit { inline namespace core { namespace monadic { ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr auto init(Args&&... args) noexcept -> decltype(auto) { - return [... args = std::forward(args)]() mutable noexcept( - noexcept(std::is_nothrow_constructible_v)) -> decltype(auto) { - return T { std::forward(args)... }; - }; + STORMKIT_FORCE_INLINE + STORMKIT_CONST + 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)... }; }; } ///////////////////////////////////// ///////////////////////////////////// - STORMKIT_FORCE_INLINE constexpr auto as_ref() noexcept -> decltype(auto) { - return [](T&& value) static noexcept { + 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)); }; } ///////////////////////////////////// ///////////////////////////////////// - STORMKIT_FORCE_INLINE constexpr auto as_ref_mut() noexcept -> decltype(auto) { - return [](T&& value) static noexcept { + 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)); }; } + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto unref() noexcept -> decltype(auto) { + 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); + }; + } + ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr auto forward_like() noexcept -> decltype(auto) { + STORMKIT_FORCE_INLINE + STORMKIT_CONST + constexpr auto forward_like() noexcept -> decltype(auto) { return [](auto&& value) static noexcept -> decltype(auto) { return std::forward_like(value); }; diff --git a/modules/stormkit/core/functional/utils.mpp b/modules/stormkit/core/functional/utils.mpp index 3254fa008..12145164c 100644 --- a/modules/stormkit/core/functional/utils.mpp +++ b/modules/stormkit/core/functional/utils.mpp @@ -51,19 +51,19 @@ export namespace stormkit { inline namespace core { template [[nodiscard]] - constexpr auto bindFront(Args&&... args) noexcept -> decltype(auto); + constexpr auto bind_front(Args&&... args) noexcept -> decltype(auto); template [[nodiscard]] - constexpr auto bindFront(Func&& func, Args&&... args) noexcept -> decltype(auto); + constexpr auto bind_front(Func&& func, Args&&... args) noexcept -> decltype(auto); template [[nodiscard]] - constexpr auto bindBack(Func&& func, Args&&... args) noexcept -> decltype(auto); + constexpr auto bind_back(Func&& func, Args&&... args) noexcept -> decltype(auto); template [[nodiscard]] - constexpr auto bindBack(Args&&... args) noexcept -> decltype(auto); + constexpr auto bind_back(Args&&... args) noexcept -> decltype(auto); }} // namespace stormkit::core //////////////////////////////////////////////////////////////////// @@ -105,14 +105,14 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr auto bindFront(Args&&... args) noexcept -> decltype(auto) { + STORMKIT_FORCE_INLINE constexpr auto bind_front(Args&&... args) noexcept -> decltype(auto) { return std::bind_front(std::forward(args)...); } ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr auto bindFront(Func&& func, Args&&... args) noexcept + STORMKIT_FORCE_INLINE constexpr auto bind_front(Func&& func, Args&&... args) noexcept -> decltype(auto) { return std::bind_front(std::forward(func), std::forward(args)...); } @@ -120,7 +120,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr auto bindBack(Args&&... args) noexcept -> decltype(auto) { + STORMKIT_FORCE_INLINE constexpr auto bind_back(Args&&... args) noexcept -> decltype(auto) { #if defined(__cpp_lib_bind_back) and __cpp_lib_bind_back >= 202306L return std::bind_back(std::forward(args)...); #else @@ -147,7 +147,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr auto bindBack(Func&& func, Args&&... args) noexcept + STORMKIT_FORCE_INLINE constexpr auto bind_back(Func&& func, Args&&... args) noexcept -> decltype(auto) { return std::bind_back(std::forward(func), std::forward(args)...); } diff --git a/modules/stormkit/core/meta.mpp b/modules/stormkit/core/meta.mpp index 9a91ccc2a..d1adc511e 100644 --- a/modules/stormkit/core/meta.mpp +++ b/modules/stormkit/core/meta.mpp @@ -17,4 +17,14 @@ export namespace stormkit { inline namespace core { template Overloaded(Ts...) -> Overloaded; + + namespace meta { + template + consteval auto find_type_index_of() noexcept -> RangeExtent { + static_assert(IsOneOf); + auto i = 0u; + ((not Is and ++i) and ...); + return i; + } + } // namespace meta }} // namespace stormkit::core diff --git a/modules/stormkit/core/meta/concepts.mpp b/modules/stormkit/core/meta/concepts.mpp index c994232d2..b03190444 100644 --- a/modules/stormkit/core/meta/concepts.mpp +++ b/modules/stormkit/core/meta/concepts.mpp @@ -17,7 +17,7 @@ namespace stormkit { inline namespace core { namespace meta::details { template class T, typename T2, auto... Args> constexpr auto is_specialization_of_with_helper(const T&) noexcept - -> std::true_type { + -> std::true_type { return {}; } }}} // namespace stormkit::core::meta::details @@ -100,9 +100,9 @@ export namespace stormkit { inline namespace core { namespace meta { concept IsMovedOwningPointer = IsOwningPointer and IsRValueReference; template - concept IsViewPointer - = (IsOwningPointer> and not IsMovedOwningPointer) - or IsNonOwningPointer>; + concept IsViewPointer = (IsOwningPointer> + and not IsMovedOwningPointer) + or IsNonOwningPointer>; template concept IsRawPointerOrLValueReference = IsRawPointer or IsLValueReference; @@ -117,8 +117,8 @@ export namespace stormkit { inline namespace core { namespace meta { concept IsPolymorphic = std::is_polymorphic_v; template - concept IsPolymorphicPointer - = IsPointer and IsPolymorphic::element_type>; + concept IsPolymorphicPointer = IsPointer + and IsPolymorphic::element_type>; template concept IsPolymorphicReference = IsReference and IsPolymorphic>; @@ -135,16 +135,23 @@ export namespace stormkit { inline namespace core { namespace meta { 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>>; + concept IsIntegral = (std::integral and not IsStrict and not IsByte) + or Is>> + or Is>>; template concept IsIntegralOrEnumeration = IsIntegral or IsEnumeration; @@ -153,8 +160,9 @@ export namespace stormkit { inline namespace core { namespace meta { concept IsFloatingPoint = std::floating_point; template - concept IsArithmetic - = (IsIntegral or IsFloatingPoint) and not IsPointer and not IsEnumeration; + concept IsArithmetic = (IsIntegral or IsFloatingPoint) + and not IsPointer + and not IsEnumeration; template concept IsScalar = IsArithmetic or IsPointer or IsEnumeration; @@ -211,12 +219,12 @@ export namespace stormkit { inline namespace core { namespace meta { // doesn't work atm template - concept IsFormattable - = true; // requires(std::formatter f, T val) { f.format("{}", val); }; + concept IsFormattable = true; // requires(std::formatter f, T val) { f.format("{}", + // val); }; template concept IsCharacter - = IsOneOf; + = IsOneOf; template concept IsColorComponent = Is or Is; @@ -250,7 +258,7 @@ export namespace stormkit { inline namespace core { namespace meta { }; template - concept EnableCtor - = sizeof...(Args) != 1 - || (sizeof...(Args) == 1 && !Is::type>); + concept EnableCtor = sizeof...(Args) != 1 + || (sizeof...(Args) == 1 + && !Is::type>); }}} // namespace stormkit::core::meta diff --git a/modules/stormkit/core/meta/traits.mpp b/modules/stormkit/core/meta/traits.mpp index a4926b2c4..1c1108eea 100644 --- a/modules/stormkit/core/meta/traits.mpp +++ b/modules/stormkit/core/meta/traits.mpp @@ -9,6 +9,9 @@ import std; import :meta.concepts; export namespace stormkit { inline namespace core { namespace meta { + template + using If = std::conditional_t; + template using CanonicalType = std::remove_cvref_t; @@ -46,7 +49,7 @@ export namespace stormkit { inline namespace core { namespace meta { using SafeNarrowHelperOtherType = std::conditional_t(), V, T>; template - struct ConstnessLikeTrait { + struct ForwardConstTrait { private: using T1 = RemoveIndirectionsType; using U1 = std::conditional_t, std::add_const_t, U>; @@ -57,16 +60,16 @@ export namespace stormkit { inline namespace core { namespace meta { }; template - using ConstnessLike = ConstnessLikeTrait::Type; + using ForwardConst = ForwardConstTrait::Type; template struct ForwardLikeTrait { private: - using U1 = ConstnessLike; + using U1 = ForwardConst; using U2 = std:: - conditional_t, std::add_lvalue_reference_t, U1>; + conditional_t, std::add_lvalue_reference_t, U1>; using U3 = std:: - conditional_t, std::add_rvalue_reference_t, U2>; + conditional_t, std::add_rvalue_reference_t, U2>; public: using Type = U3; diff --git a/modules/stormkit/core/parallelism/locked.mpp b/modules/stormkit/core/parallelism/locked.mpp index b3be04c14..2d93ee118 100644 --- a/modules/stormkit/core/parallelism/locked.mpp +++ b/modules/stormkit/core/parallelism/locked.mpp @@ -86,7 +86,7 @@ export namespace stormkit { inline namespace core { noexcept(std::is_nothrow_assignable_v)) -> void; template - auto unsafe(this Self& self) noexcept -> meta::ConstnessLike; + auto unsafe(this Self& self) noexcept -> meta::ForwardConst; auto mutex() const noexcept -> const MutexType&; @@ -112,10 +112,10 @@ export namespace stormkit { inline namespace core { explicit Access(Locked& locked, LockArgs&&... args) noexcept; template - auto operator->(this Self&& self) noexcept -> meta::ConstnessLike; + auto operator->(this Self&& self) noexcept -> meta::ForwardConst; template - auto operator*(this Self&& self) noexcept -> meta::ConstnessLike; + auto operator*(this Self&& self) noexcept -> meta::ForwardConst; mutable Lock lock; @@ -218,7 +218,7 @@ namespace stormkit { inline namespace core { template template STORMKIT_FORCE_INLINE auto Locked::unsafe(this Self& self) noexcept - -> meta::ConstnessLike { + -> meta::ForwardConst { return self.m_value; } @@ -269,7 +269,7 @@ namespace stormkit { inline namespace core { template STORMKIT_FORCE_INLINE auto Locked::Access::operator->(this Self&& self) noexcept - -> meta::ConstnessLike { + -> meta::ForwardConst { return self.m_value.get(); } @@ -280,7 +280,7 @@ namespace stormkit { inline namespace core { template STORMKIT_FORCE_INLINE auto Locked::Access::operator*(this Self&& self) noexcept - -> meta::ConstnessLike { + -> meta::ForwardConst { return *self.m_value; } }} // namespace stormkit::core diff --git a/modules/stormkit/core/string/operations.mpp b/modules/stormkit/core/string/operations.mpp index 901dd9606..6bcf1cdd2 100644 --- a/modules/stormkit/core/string/operations.mpp +++ b/modules/stormkit/core/string/operations.mpp @@ -10,7 +10,7 @@ export module stormkit.core:string.operations; import std; -import :utils.contrat; +import :utils.contract; import :meta.traits; import :meta.concepts; import :typesafe.integer; diff --git a/modules/stormkit/core/typesafe/as_cast.mpp b/modules/stormkit/core/typesafe/as_cast.mpp index 773b1ef67..b17901bea 100644 --- a/modules/stormkit/core/typesafe/as_cast.mpp +++ b/modules/stormkit/core/typesafe/as_cast.mpp @@ -11,7 +11,7 @@ export module stormkit.core:typesafe.integer_casts; import std; import magic_enum; -import :utils.contrat; +import :utils.contract; import :typesafe.byte; import :utils.function_ref; import :typesafe.ref; @@ -653,7 +653,7 @@ namespace stormkit { inline namespace core { STORMKIT_FORCE_INLINE constexpr auto as(From&& variant, const std::source_location& location) noexcept -> meta::ForwardLike { - /*using PtrType = meta::ConstnessLike*;*/ + /*using PtrType = meta::ForwardConst*;*/ /*auto ptr = PtrType { nullptr };*/ /**/ /*variant_type_find_if(variant, [&]() noexcept {*/ diff --git a/modules/stormkit/core/typesafe/byte.mpp b/modules/stormkit/core/typesafe/byte.mpp index b546224dc..619a2ec40 100644 --- a/modules/stormkit/core/typesafe/byte.mpp +++ b/modules/stormkit/core/typesafe/byte.mpp @@ -2,6 +2,10 @@ // 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.byte; import std; @@ -9,7 +13,7 @@ import std; import :meta.concepts; import :meta.traits; import :typesafe.integer; -import :utils.contrat; +import :utils.contract; export namespace stormkit { inline namespace core { using Byte = std::byte; @@ -19,19 +23,45 @@ export namespace stormkit { inline namespace core { using ByteDynArray = std::vector; using MutableByteView = std::span; + struct Force {}; + + template + constexpr auto zero_bytes(T& value) noexcept -> void; + + template + constexpr auto zeroed() noexcept -> T; + + template [[nodiscard]] - constexpr auto byte_swap(auto value) noexcept; + constexpr auto byte_swap(const T& value) noexcept -> T; + template [[nodiscard]] - constexpr auto as_bytes(std::ranges::range auto& container); + constexpr auto as_bytes(T& container) noexcept -> std::span>; + template [[nodiscard]] - constexpr auto as_bytes(meta::IsPointer auto ptr, RangeExtent size = 1); + constexpr auto as_bytes(T ptr, RangeExtent size = 1) noexcept + -> std::span, Byte>>; template - requires(not std::ranges::range and not meta::IsPointer) [[nodiscard]] - constexpr auto as_bytes(T& value); + constexpr auto as_bytes(T& value) noexcept -> std::span>; + + template + [[nodiscard]] + constexpr auto as_bytes(T& value, Force) noexcept -> std::span>; + + template + requires(std::ranges::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]] @@ -43,25 +73,25 @@ export namespace stormkit { inline namespace core { namespace literals { [[nodiscard]] - constexpr auto operator""_b(unsigned long long int value) noexcept; + constexpr auto operator""_b(unsigned long long value) noexcept -> Byte; [[nodiscard]] - constexpr auto operator""_kb(unsigned long long x) noexcept -> core::UInt64; + constexpr auto operator""_kb(unsigned long long x) noexcept -> UInt64; [[nodiscard]] - constexpr auto operator""_mb(unsigned long long x) noexcept -> core::UInt64; + constexpr auto operator""_mb(unsigned long long x) noexcept -> UInt64; [[nodiscard]] - constexpr auto operator""_gb(unsigned long long x) noexcept -> core::UInt64; + constexpr auto operator""_gb(unsigned long long x) noexcept -> UInt64; [[nodiscard]] - constexpr auto operator""_kib(unsigned long long x) noexcept -> core::UInt64; + constexpr auto operator""_kib(unsigned long long x) noexcept -> UInt64; [[nodiscard]] - constexpr auto operator""_mib(unsigned long long x) noexcept -> core::UInt64; + constexpr auto operator""_mib(unsigned long long x) noexcept -> UInt64; [[nodiscard]] - constexpr auto operator""_gib(unsigned long long x) noexcept -> core::UInt64; + constexpr auto operator""_gib(unsigned long long x) noexcept -> UInt64; } // namespace literals }} // namespace stormkit::core @@ -73,28 +103,60 @@ export namespace stormkit { inline namespace core { namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// - constexpr auto byte_swap(auto value) noexcept { + template + STORMKIT_API + STORMKIT_FORCE_INLINE + inline constexpr auto zero_bytes(T& value) noexcept -> void { + auto bytes = as_bytes(value); + + std::memset(&bytes[0], 0, std::ranges::size(bytes)); + } + + template + STORMKIT_API + STORMKIT_FORCE_INLINE + inline constexpr auto zeroed() noexcept -> T { + auto data = T {}; + zero_bytes(data); + return data; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_API + STORMKIT_CONST + STORMKIT_FORCE_INLINE + inline constexpr auto byte_swap(const T& value) noexcept -> T { auto repr = std::bit_cast>(value); std::ranges::reverse(repr); - return std::bit_cast(repr); + return std::bit_cast(repr); } ///////////////////////////////////// ///////////////////////////////////// - constexpr auto as_bytes(std::ranges::range auto& container) { - return as_bytes(std::data(container), std::size(container)); + template + STORMKIT_FORCE_INLINE + STORMKIT_PURE + inline constexpr auto as_bytes(T& container) noexcept + -> std::span> { + return as_bytes(std::ranges::data(container), std::ranges::size(container)); } ///////////////////////////////////// ///////////////////////////////////// - constexpr auto as_bytes(meta::IsPointer auto ptr, std::size_t size) { + template + STORMKIT_FORCE_INLINE + STORMKIT_PURE + inline constexpr auto as_bytes(T ptr, RangeExtent size) noexcept + -> std::span, Byte>> { auto raw_ptr = std::to_address(ptr); using PtrType = decltype(raw_ptr); using ElementType = meta::ElementType; - using ByteType = meta::ConstnessLike; + using ByteType = meta::ForwardConst; constexpr auto byte_count = []() { if constexpr (meta::Is) return 1; @@ -102,21 +164,58 @@ namespace stormkit { inline namespace core { return sizeof(ElementType); }(); - return std::span { std::bit_cast(ptr), size * byte_count }; + 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 - requires(not std::ranges::range and not meta::IsPointer) - constexpr auto as_bytes(T& value) { + 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*>(std::ranges::data(bytes)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(std::ranges::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(std::ranges::data(bytes)), + std::ranges::size(bytes) * sizeof(ElementType) }; + } + ///////////////////////////////////// ///////////////////////////////////// template - constexpr auto into_bytes(Bytes... bytes) noexcept -> ByteArray { + STORMKIT_FORCE_INLINE + STORMKIT_PURE + inline constexpr auto into_bytes(Bytes... bytes) noexcept -> ByteArray { expects(((static_cast(static_cast(bytes)) == bytes) and ...)); return ByteArray { static_cast(bytes)... }; } @@ -124,51 +223,60 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// template - constexpr auto into_bytes(Bytes... bytes) noexcept -> ByteArray { + STORMKIT_FORCE_INLINE + STORMKIT_PURE + inline constexpr auto into_bytes(Bytes... bytes) noexcept -> ByteArray { return ByteArray { static_cast(bytes)... }; } namespace literals { ///////////////////////////////////// ///////////////////////////////////// - constexpr auto operator""_b(unsigned long long int value) noexcept { + STORMKIT_FORCE_INLINE STORMKIT_PURE STORMKIT_INTRINSIC + inline constexpr auto operator""_b(unsigned long long value) noexcept -> Byte { return static_cast(value); } ///////////////////////////////////// ///////////////////////////////////// - constexpr auto operator""_kb(unsigned long long x) noexcept -> core::UInt64 { - return 1000ULL * x; + STORMKIT_FORCE_INLINE STORMKIT_PURE + inline constexpr auto operator""_kb(unsigned long long x) noexcept -> UInt64 { + return x * 1000ULL; } ///////////////////////////////////// ///////////////////////////////////// - constexpr auto operator""_mb(unsigned long long x) noexcept -> core::UInt64 { - return 1000ULL * 1000ULL * x; + STORMKIT_FORCE_INLINE STORMKIT_PURE + inline constexpr auto operator""_mb(unsigned long long x) noexcept -> UInt64 { + return x * 1000_kb; } ///////////////////////////////////// ///////////////////////////////////// - constexpr auto operator""_gb(unsigned long long x) noexcept -> core::UInt64 { - return 1000ULL * 1000ULL * 1000ULL * x; + STORMKIT_FORCE_INLINE STORMKIT_PURE + inline constexpr auto operator""_gb(unsigned long long x) noexcept -> UInt64 { + return x * 1000_mb; } ///////////////////////////////////// ///////////////////////////////////// - constexpr auto operator""_kib(unsigned long long x) noexcept -> core::UInt64 { - return 1024ULL * x; + STORMKIT_FORCE_INLINE STORMKIT_PURE + inline constexpr auto operator""_kib(unsigned long long x) noexcept -> UInt64 { + return x * 1024; } ///////////////////////////////////// ///////////////////////////////////// - constexpr auto operator""_mib(unsigned long long x) noexcept -> core::UInt64 { - return 1024ULL * 1024ULL * x; + STORMKIT_FORCE_INLINE STORMKIT_PURE + inline constexpr auto operator""_mib(unsigned long long x) noexcept -> UInt64 { + return x * 1024_kib; } ///////////////////////////////////// ///////////////////////////////////// - constexpr auto operator""_gib(unsigned long long x) noexcept -> core::UInt64 { - return 1024ULL * 1000ULL * 1024ULL * x; + STORMKIT_FORCE_INLINE STORMKIT_PURE + inline constexpr auto operator""_gib(unsigned long long x) noexcept -> UInt64 { + return x * 1024_mib; } } // namespace literals }} // namespace stormkit::core diff --git a/modules/stormkit/core/typesafe/flags.mpp b/modules/stormkit/core/typesafe/flags.mpp index dd023e867..2d41489fe 100644 --- a/modules/stormkit/core/typesafe/flags.mpp +++ b/modules/stormkit/core/typesafe/flags.mpp @@ -26,47 +26,50 @@ export { inline constexpr auto BITMASK_OPERATORS_ENABLED = EnableBitmaskOperators::enable; } // namespace details - template - concept FlagsType - = meta::IsEnumeration> and details::BITMASK_OPERATORS_ENABLED; + 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 + template [[nodiscard]] - constexpr auto checkFlag(const T& value, const T& flag) noexcept -> bool; + constexpr auto check_flag_bit(const T& value, const T& flag) noexcept -> bool; /// \exclude - template + template [[nodiscard]] constexpr auto next_value(const T& value) noexcept -> T; }} // namespace stormkit::core - template + template [[nodiscard]] constexpr auto operator|(const T& lhs, const T& rhs) noexcept -> decltype(auto); - template + template [[nodiscard]] constexpr auto operator&(const T& lhs, const T& rhs) noexcept -> decltype(auto); - template + template [[nodiscard]] constexpr auto operator^(const T& lhs, const T& rhs) noexcept -> decltype(auto); - template + template [[nodiscard]] constexpr auto operator~(const T& lhs) noexcept -> decltype(auto); - template + template constexpr auto operator|=(T& lhs, const T& rhs) noexcept -> decltype(auto); - template + template constexpr auto operator&=(T& lhs, const T& rhs) noexcept -> decltype(auto); - template + template constexpr auto operator^=(T& lhs, const T& rhs) noexcept -> decltype(auto); } @@ -77,14 +80,15 @@ export { namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE constexpr auto checkFlag(const T& value, const T& flag) noexcept -> bool { + template + STORMKIT_FORCE_INLINE constexpr auto check_flag_bit(const T& value, const T& flag) noexcept + -> bool { return (value & flag) == flag; } ///////////////////////////////////// ///////////////////////////////////// - template + template STORMKIT_FORCE_INLINE constexpr auto next_value(const T& value) noexcept -> T { using Underlying = meta::UnderlyingType; return static_cast(static_cast(value) << 1); @@ -93,9 +97,9 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// -template +template STORMKIT_FORCE_INLINE constexpr auto operator|(const T& lhs, const T& rhs) noexcept - -> decltype(auto) { + -> decltype(auto) { using namespace stormkit; namespace details = stormkit::core::details; @@ -105,9 +109,9 @@ STORMKIT_FORCE_INLINE constexpr auto operator|(const T& lhs, const T& rhs) noexc ///////////////////////////////////// ///////////////////////////////////// -template +template STORMKIT_FORCE_INLINE constexpr auto operator&(const T& lhs, const T& rhs) noexcept - -> decltype(auto) { + -> decltype(auto) { using namespace stormkit; namespace details = stormkit::core::details; @@ -117,9 +121,9 @@ STORMKIT_FORCE_INLINE constexpr auto operator&(const T& lhs, const T& rhs) noexc ///////////////////////////////////// ///////////////////////////////////// -template +template STORMKIT_FORCE_INLINE constexpr auto operator^(const T& lhs, const T& rhs) noexcept - -> decltype(auto) { + -> decltype(auto) { using namespace stormkit; namespace details = stormkit::core::details; @@ -129,7 +133,7 @@ STORMKIT_FORCE_INLINE constexpr auto operator^(const T& lhs, const T& rhs) noexc ///////////////////////////////////// ///////////////////////////////////// -template +template STORMKIT_FORCE_INLINE constexpr auto operator~(const T& lhs) noexcept -> decltype(auto) { using namespace stormkit; namespace details = stormkit::core::details; @@ -140,7 +144,7 @@ STORMKIT_FORCE_INLINE constexpr auto operator~(const T& lhs) noexcept -> decltyp ///////////////////////////////////// ///////////////////////////////////// -template +template STORMKIT_FORCE_INLINE constexpr auto operator|=(T& lhs, const T& rhs) noexcept -> decltype(auto) { using namespace stormkit; namespace details = stormkit::core::details; @@ -151,7 +155,7 @@ STORMKIT_FORCE_INLINE constexpr auto operator|=(T& lhs, const T& rhs) noexcept - ///////////////////////////////////// ///////////////////////////////////// -template +template STORMKIT_FORCE_INLINE constexpr auto operator&=(T& lhs, const T& rhs) noexcept -> decltype(auto) { using namespace stormkit; namespace details = stormkit::core::details; @@ -162,7 +166,7 @@ STORMKIT_FORCE_INLINE constexpr auto operator&=(T& lhs, const T& rhs) noexcept - ///////////////////////////////////// ///////////////////////////////////// -template +template STORMKIT_FORCE_INLINE constexpr auto operator^=(T& lhs, const T& rhs) noexcept -> decltype(auto) { using namespace stormkit; namespace details = stormkit::core::details; diff --git a/modules/stormkit/core/typesafe/ref.mpp b/modules/stormkit/core/typesafe/ref.mpp index 1ae79bba9..ab4f345b9 100644 --- a/modules/stormkit/core/typesafe/ref.mpp +++ b/modules/stormkit/core/typesafe/ref.mpp @@ -13,7 +13,7 @@ import std; import :meta.concepts; import :meta.traits; -import :utils.contrat; +import :utils.contract; import :typesafe.boolean; import :hash.base; @@ -74,8 +74,8 @@ export { constexpr auto operator>=(std::nullptr_t) const noexcept; [[nodiscard]] constexpr auto operator<=>(std::nullptr_t) const noexcept - -> std::compare_three_way_result_t::PointerType, - typename Ref::PointerType> + -> std::compare_three_way_result_t::PointerType, + typename Ref::PointerType> requires std::three_way_comparable::PointerType, typename Ref::PointerType>; @@ -102,8 +102,8 @@ export { typename Ref::PointerType> [[nodiscard]] constexpr auto operator<=>(const Ref& other) const noexcept - -> std::compare_three_way_result_t::PointerType, - typename Ref::PointerType>; + -> std::compare_three_way_result_t::PointerType, + typename Ref::PointerType>; private: constexpr Ref(ReferenceType value STORMKIT_LIFETIMEBOUND) noexcept; @@ -111,15 +111,12 @@ export { PointerType m_value; - // template template friend constexpr auto as_ref(U&& value) noexcept -> decltype(auto); - // template template friend constexpr auto as_ref_mut(U&& value) noexcept -> decltype(auto); - // template template friend constexpr auto as_ref_like(U&& value) noexcept -> decltype(auto); }; @@ -131,16 +128,22 @@ export { [[nodiscard]] constexpr auto as_ref(T&& value STORMKIT_LIFETIMEBOUND) noexcept -> decltype(auto); - // template template [[nodiscard]] constexpr auto as_ref_mut(T&& value STORMKIT_LIFETIMEBOUND) noexcept -> decltype(auto); - // template template [[nodiscard]] constexpr auto as_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]] @@ -192,13 +195,17 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr Ref::Ref(ReferenceType value) noexcept : m_value { &value } { + 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 } { + STORMKIT_FORCE_INLINE + constexpr Ref::Ref(PointerType value) noexcept + : m_value { value } { core::expects(m_value != nullptr); } @@ -220,7 +227,8 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr auto Ref::operator=(Ref&& other) noexcept -> Ref& { + STORMKIT_FORCE_INLINE + constexpr auto Ref::operator=(Ref&& other) noexcept -> Ref& { // TODO improve const_cast::PointerType>&>(m_value) = other.m_value; return *this; @@ -229,93 +237,105 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr auto Ref::get() const noexcept -> PointerType { + STORMKIT_FORCE_INLINE + constexpr auto Ref::get() const noexcept -> PointerType { return m_value; } ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr auto Ref::operator->() const noexcept -> PointerType { + STORMKIT_FORCE_INLINE + constexpr auto Ref::operator->() const noexcept -> PointerType { return get(); } ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr auto Ref::operator*() const noexcept -> ReferenceType { + STORMKIT_FORCE_INLINE + constexpr auto Ref::operator*() const noexcept -> ReferenceType { return *get(); } ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr Ref::operator bool() const noexcept { + 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 { + STORMKIT_FORCE_INLINE + constexpr auto Ref::has_value() const noexcept -> Boolean { return operator bool(); } ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr Ref::operator ReferenceType() const noexcept { + STORMKIT_FORCE_INLINE + constexpr Ref::operator ReferenceType() const noexcept { return *m_value; } ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr Ref::operator PointerType() const noexcept { + 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 { + STORMKIT_FORCE_INLINE + constexpr auto Ref::operator==(std::nullptr_t) const noexcept { return !m_value; } ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr auto Ref::operator<(std::nullptr_t) const noexcept { + STORMKIT_FORCE_INLINE + constexpr auto Ref::operator<(std::nullptr_t) const noexcept { return std::less::pointer> {}(m_value, nullptr); } ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr auto Ref::operator<=(std::nullptr_t) const noexcept { + STORMKIT_FORCE_INLINE + constexpr auto Ref::operator<=(std::nullptr_t) const noexcept { return !(nullptr < *this); } ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr auto Ref::operator>(std::nullptr_t) const noexcept { + STORMKIT_FORCE_INLINE + constexpr auto Ref::operator>(std::nullptr_t) const noexcept { return nullptr < *this; } ///////////////////////////////////// ///////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr auto Ref::operator>=(std::nullptr_t) const noexcept { + STORMKIT_FORCE_INLINE + constexpr auto Ref::operator>=(std::nullptr_t) const noexcept { 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> + 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> @@ -327,7 +347,8 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template template - STORMKIT_FORCE_INLINE constexpr auto Ref::operator==(const Ref& other) const noexcept { + STORMKIT_FORCE_INLINE + constexpr auto Ref::operator==(const Ref& other) const noexcept { return m_value == other.value(); } @@ -335,7 +356,8 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template template - STORMKIT_FORCE_INLINE constexpr auto Ref::operator!=(const Ref& other) const noexcept { + STORMKIT_FORCE_INLINE + constexpr auto Ref::operator!=(const Ref& other) const noexcept { return m_value != other.value(); } @@ -343,17 +365,19 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template template - STORMKIT_FORCE_INLINE constexpr auto Ref::operator<(const Ref& other) const noexcept { - return std::less::PointerType, typename Ref::PointerType>> {}( - m_value, - other.m_value); + STORMKIT_FORCE_INLINE + constexpr auto Ref::operator<(const Ref& other) const noexcept { + 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 { + STORMKIT_FORCE_INLINE + constexpr auto Ref::operator<=(const Ref& other) const noexcept { return !(other < *this); } @@ -361,7 +385,8 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template template - STORMKIT_FORCE_INLINE constexpr auto Ref::operator>(const Ref& other) const noexcept { + STORMKIT_FORCE_INLINE + constexpr auto Ref::operator>(const Ref& other) const noexcept { return other < *this; } @@ -369,7 +394,8 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template template - STORMKIT_FORCE_INLINE constexpr auto Ref::operator>=(const Ref& other) const noexcept { + STORMKIT_FORCE_INLINE + constexpr auto Ref::operator>=(const Ref& other) const noexcept { return !(*this < other); } @@ -379,9 +405,10 @@ namespace stormkit { inline namespace core { 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> { + 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; } @@ -389,7 +416,8 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// // template template - STORMKIT_FORCE_INLINE constexpr auto as_ref(T&& value) noexcept -> decltype(auto) { + STORMKIT_FORCE_INLINE + constexpr auto as_ref(T&& value) noexcept -> decltype(auto) { using TValue = meta::CanonicalType; if constexpr (meta::IsPointer) { expects(value != nullptr); @@ -406,7 +434,8 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// // template template - STORMKIT_FORCE_INLINE constexpr auto as_ref_mut(T&& value) noexcept -> decltype(auto) { + 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) { @@ -429,7 +458,8 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// // template template - STORMKIT_FORCE_INLINE constexpr auto as_ref_like(T&& value) noexcept -> decltype(auto) { + STORMKIT_FORCE_INLINE + constexpr auto as_ref_like(T&& value) noexcept -> decltype(auto) { using TValue = meta::CanonicalType; if constexpr (meta::IsPointer) { expects(value != nullptr); @@ -442,11 +472,28 @@ namespace stormkit { inline namespace core { } } + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto unref(const Ref& value) noexcept -> const T& { + return *value; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE STORMKIT_CONST + 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) { + STORMKIT_FORCE_INLINE + constexpr auto as_refs(Args&&... args) noexcept -> decltype(auto) { return Out { as_ref(std::forward(args))... }; } @@ -454,7 +501,8 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template typename Out, typename... Args> requires(not std::ranges::range and ...) - STORMKIT_FORCE_INLINE constexpr auto to_refs(Args&&... args) noexcept -> decltype(auto) { + STORMKIT_FORCE_INLINE + constexpr auto to_refs(Args&&... args) noexcept -> decltype(auto) { return Out { { as_ref(std::forward(args))... } }; } @@ -462,7 +510,8 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// 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) { + STORMKIT_FORCE_INLINE + constexpr auto as_ref_muts(Args&&... args) noexcept -> decltype(auto) { return Out { { as_ref_mut(std::forward(args))... } }; } @@ -470,7 +519,8 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template typename Out, typename... Args> requires(not std::ranges::range and ...) - STORMKIT_FORCE_INLINE constexpr auto to_ref_muts(Args&&... args) noexcept -> decltype(auto) { + STORMKIT_FORCE_INLINE + constexpr auto to_ref_muts(Args&&... args) noexcept -> decltype(auto) { return Out { { as_ref_mut(std::forward(args))... } }; } @@ -478,7 +528,8 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// 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) { + 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)); @@ -490,7 +541,8 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// 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) { + 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)); diff --git a/modules/stormkit/core/utils.mpp b/modules/stormkit/core/utils.mpp index 44aba5d74..394fb726c 100644 --- a/modules/stormkit/core/utils.mpp +++ b/modules/stormkit/core/utils.mpp @@ -7,7 +7,7 @@ export module stormkit.core:utils; export import :utils.algorithms; export import :utils.allocation; export import :utils.app; -export import :utils.contrat; +export import :utils.contract; export import :utils.color; export import :utils.deferinit; export import :utils.dynamic_loader; diff --git a/modules/stormkit/core/utils/allocation.mpp b/modules/stormkit/core/utils/allocation.mpp index 41a69a62e..17fa666e7 100644 --- a/modules/stormkit/core/utils/allocation.mpp +++ b/modules/stormkit/core/utils/allocation.mpp @@ -22,13 +22,27 @@ struct MemoryAllocationError { export { namespace stormkit { inline namespace core { + template + using Heap = std::unique_ptr; + template + using HeapCounted = std::shared_ptr; + template auto allocate(Args&&... args) noexcept(noexcept(T(std::forward(args)...))) - -> std::expected, MemoryAllocationError>; + -> std::expected, MemoryAllocationError>; + + template + 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 allocateUnsafe(Args&&... args) noexcept(noexcept(T(std::forward(args)...))) - -> std::unique_ptr; + auto allocate_counted_unsafe(Args&&... args) noexcept(noexcept(T(std::forward< + Args>(args)...))) + -> HeapCounted; }} // namespace stormkit::core @@ -51,23 +65,45 @@ namespace stormkit { inline namespace core { //////////////////////////////////////// //////////////////////////////////////// template - STORMKIT_FORCE_INLINE auto - allocate(Args&&... args) noexcept(noexcept(T(std::forward(args)...))) - -> std::expected, MemoryAllocationError> { - auto value = std::unique_ptr { new (std::nothrow) T(std::forward(args)...) }; - if (not value) [[unexpected]] - return std::unexpected( - MemoryAllocationError { .type = typeid(T).name(), .size = sizeof(T) }); - return std::expected, MemoryAllocationError> { std::in_place, - std::move(value) }; + STORMKIT_FORCE_INLINE + auto allocate(Args&&... args) noexcept(noexcept(T(std::forward(args)...))) + -> 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::expected, MemoryAllocationError> { std::in_place, std::move(value) }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + auto allocate_unsafe(Args&&... args) noexcept(noexcept(T(std::forward(args)...))) + -> Heap { + return Heap { new (std::nothrow) T(std::forward(args)...) }; + } + + //////////////////////////////////////// + //////////////////////////////////////// + template + STORMKIT_FORCE_INLINE + auto allocate_counted(Args&&... args) noexcept(noexcept(T(std::forward(args)...))) + -> 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) }; } //////////////////////////////////////// //////////////////////////////////////// template - STORMKIT_FORCE_INLINE auto - allocateUnsafe(Args&&... args) noexcept(noexcept(T(std::forward(args)...))) - -> std::unique_ptr { - return std::unique_ptr { new (std::nothrow) T(std::forward(args)...) }; + STORMKIT_FORCE_INLINE + 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/color.mpp b/modules/stormkit/core/utils/color.mpp index 26e4ecf1f..f3e504392 100644 --- a/modules/stormkit/core/utils/color.mpp +++ b/modules/stormkit/core/utils/color.mpp @@ -93,8 +93,12 @@ export { ///``` namespace RGBColorDef { template - inline constexpr auto BLACK - = RGBColor { T { 0 }, T { 0 }, T { 0 }, max_color_component_value() }; + 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 }, @@ -103,26 +107,31 @@ export { 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() }; + 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() }; + 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() }; + 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(), @@ -131,21 +140,27 @@ export { 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() }; + 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() }; + 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() }; + 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 }, @@ -178,16 +193,20 @@ export { 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() }; + 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() }; + 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 } }; @@ -264,7 +283,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template constexpr auto RGBColor::operator=(const RGBColor& other) noexcept - -> RGBColor& = default; + -> RGBColor& = default; ///////////////////////////////////// ///////////////////////////////////// @@ -275,7 +294,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// template constexpr auto RGBColor::operator=(RGBColor&& other) noexcept - -> RGBColor& = default; + -> RGBColor& = default; ///////////////////////////////////// ///////////////////////////////////// diff --git a/modules/stormkit/core/utils/contract.mpp b/modules/stormkit/core/utils/contract.mpp index e83778c20..5049e2dae 100644 --- a/modules/stormkit/core/utils/contract.mpp +++ b/modules/stormkit/core/utils/contract.mpp @@ -10,7 +10,7 @@ module; #define STORMKIT_ASSERT 1 #endif -export module stormkit.core:utils.contrat; +export module stormkit.core:utils.contract; import std; import frozen; @@ -23,14 +23,14 @@ export namespace stormkit { inline namespace core { enum class AssertType { Assertion, PreCondition, - PostCondition + PostCondition, }; auto assert_base(bool cond, AssertType type, std::string_view message, - const std::source_location& location - = std::source_location::current()) noexcept -> void; + const std::source_location& location = std::source_location:: + current()) noexcept -> void; consteval auto consteval_assert_base(bool cond, AssertType type, @@ -38,30 +38,30 @@ export namespace stormkit { inline namespace core { constexpr auto assert(bool cond, std::string_view message, - const std::source_location& location - = std::source_location::current()) noexcept -> void; + 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; + 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; + 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; + 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; + 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; + const std::source_location& location = std::source_location:: + current()) noexcept -> void; namespace casts::core { template To> @@ -80,11 +80,11 @@ using namespace frozen::string_literals; namespace stormkit { inline namespace core { namespace casts::core { namespace { - constexpr auto AssertTypeToString - = frozen::make_unordered_map({ - { AssertType::Assertion, "Assertion"_s }, - { AssertType::PreCondition, "Expects"_s }, - { AssertType::PostCondition, "Ensures"_s }, + constexpr auto AssertTypeToString = frozen::make_unordered_map({ + { AssertType::Assertion, "Assertion"_s }, + { AssertType::PreCondition, "Expects"_s }, + { AssertType::PostCondition, "Ensures"_s }, }); } // namespace @@ -113,7 +113,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// consteval auto generateConstevalMessage(AssertType type, std::string_view message) noexcept - -> StringLiteral { + -> StringLiteral { auto result = StringLiteral {}; const auto str = "["s + casts::core::as(type) + "] " + std::string { message }; std::ranges::copy(str, std::begin(result.buff)); @@ -135,17 +135,17 @@ namespace stormkit { inline namespace core { " > file: {}:{}:{}\n" " function: {}\n" " reason: {}", - ConsoleStyle { .fg = ConsoleColor::BRIGHT_RED, - .modifiers - = StyleModifier::BOLD | StyleModifier::INVERSE } - | "["s + casts::core::as(type) + "]", + ConsoleStyle { + .fg = ConsoleColor::BRIGHT_RED, + .modifiers = StyleModifier::BOLD | StyleModifier::INVERSE } + | "["s + casts::core::as(type) + "]", ConsoleStyle { .fg = ConsoleColor::GREEN } | location.file_name(), 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); + | message); std::terminate(); } @@ -154,18 +154,19 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// ///////////////////////////////////// - STORMKIT_FORCE_INLINE consteval auto - consteval_assert_base(bool cond, AssertType type, std::string_view message) noexcept - -> void { + 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 { + 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 @@ -181,15 +182,16 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// STORMKIT_FORCE_INLINE constexpr auto assert(bool cond, const std::source_location& location) noexcept - -> void { + -> void { assert(cond, "Condition check failed", location); } ///////////////////////////////////// ///////////////////////////////////// - STORMKIT_FORCE_INLINE constexpr auto - expects(bool cond, std::string_view message, const std::source_location& location) noexcept - -> void { + 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 @@ -205,15 +207,16 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// STORMKIT_FORCE_INLINE constexpr auto expects(bool cond, const std::source_location& location) noexcept - -> void { + -> void { expects(cond, "Pre Condition check failed", location); } ///////////////////////////////////// ///////////////////////////////////// - STORMKIT_FORCE_INLINE constexpr auto - ensures(bool cond, std::string_view message, const std::source_location& location) noexcept - -> void { + 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 @@ -229,7 +232,7 @@ namespace stormkit { inline namespace core { ///////////////////////////////////// STORMKIT_FORCE_INLINE constexpr auto ensures(bool cond, const std::source_location& location) noexcept - -> void { + -> void { ensures(cond, "Post Condition check failed", location); } }} // namespace stormkit::core diff --git a/modules/stormkit/core/utils/deferinit.mpp b/modules/stormkit/core/utils/deferinit.mpp index b2a4f8102..f31077e7a 100644 --- a/modules/stormkit/core/utils/deferinit.mpp +++ b/modules/stormkit/core/utils/deferinit.mpp @@ -11,7 +11,7 @@ export module stormkit.core:utils.deferinit; import std; import :meta.traits; -import :utils.contrat; +import :utils.contract; export namespace stormkit { inline namespace core { template diff --git a/modules/stormkit/core/utils/dynamic_loader.mpp b/modules/stormkit/core/utils/dynamic_loader.mpp index 644c902b6..70a8c9af4 100644 --- a/modules/stormkit/core/utils/dynamic_loader.mpp +++ b/modules/stormkit/core/utils/dynamic_loader.mpp @@ -12,7 +12,7 @@ export module stormkit.core:utils.dynamic_loader; import std; -import :utils.contrat; +import :utils.contract; import :utils.pimpl; export namespace stormkit { inline namespace core { diff --git a/modules/stormkit/core/utils/pimpl.mpp b/modules/stormkit/core/utils/pimpl.mpp index 652932bd2..c095a72f8 100644 --- a/modules/stormkit/core/utils/pimpl.mpp +++ b/modules/stormkit/core/utils/pimpl.mpp @@ -11,7 +11,7 @@ export module stormkit.core:utils.pimpl; import std; import :meta; -import :utils.contrat; +import :utils.contract; export namespace stormkit { inline namespace core { template diff --git a/modules/stormkit/entities.mpp b/modules/stormkit/entities.mpp index ad6dba860..cf3e427b8 100644 --- a/modules/stormkit/entities.mpp +++ b/modules/stormkit/entities.mpp @@ -177,15 +177,15 @@ export namespace stormkit::entities { auto entities_with_component() const -> std::vector; template - auto getComponent(this Self& self, Entity entity) -> core::meta::ConstnessLike; + auto getComponent(this Self& self, Entity entity) -> core::meta::ForwardConst; template auto components(this Self& self, Entity entity) - -> std::vector>>; + -> std::vector>>; template auto components_of_type(this Self& self) noexcept - -> std::vector>>; + -> std::vector>>; template auto add_system(Args&&... args) -> T&; @@ -195,10 +195,10 @@ export namespace stormkit::entities { template auto systems(this Self& self) noexcept - -> std::vector>>; + -> std::vector>>; template - auto get_system(this Self& self) noexcept -> core::meta::ConstnessLike; + auto get_system(this Self& self) noexcept -> core::meta::ForwardConst; auto step(Secondf delta) -> void; @@ -373,7 +373,7 @@ namespace stormkit::entities { ///////////////////////////////////// template auto EntityManager::getComponent(this Self& self, Entity entity) - -> core::meta::ConstnessLike { + -> core::meta::ForwardConst { expects(self.template has_component(entity)); expects(self.has_entity(entity)); @@ -385,7 +385,7 @@ namespace stormkit::entities { ///////////////////////////////////// template auto EntityManager::components(this Self& self, Entity entity) - -> std::vector>> { + -> std::vector>> { if (not self.has_entity(entity)) [[unlikely]] return {}; // clang-format off @@ -403,11 +403,11 @@ namespace stormkit::entities { ///////////////////////////////////// template auto EntityManager::components_of_type(this Self& self) noexcept - -> std::vector>> { + -> std::vector>> { // clang-format off return self.m_entities - | std::views::filter(bindFront(&EntityManager::has_component, &self)) - | std::views::transform(bindFront(&EntityManager::getComponent, &self)) + | std::views::filter(bind_front(&EntityManager::has_component, &self)) + | std::views::transform(bind_front(&EntityManager::getComponent, &self)) | std::views::transform(monadic::forward_like()) | std::views::transform(monadic::as_ref()) | std::ranges::to(); @@ -438,7 +438,7 @@ namespace stormkit::entities { ///////////////////////////////////// template auto EntityManager::systems(this Self& self) noexcept - -> std::vector>> { + -> std::vector>> { constexpr auto as_refer = [] { if constexpr (core::meta::IsConst) return monadic::as_ref(); else @@ -452,12 +452,12 @@ namespace stormkit::entities { ///////////////////////////////////// template auto EntityManager::get_system(this Self& self) noexcept - -> core::meta::ConstnessLike { + -> core::meta::ForwardConst { expects(self.template has_system()); auto it = std::ranges::find_if(self.m_systems, monadic::is()); - return as>(*it->get()); + return as>(*it->get()); } ///////////////////////////////////// diff --git a/modules/stormkit/gpu.mpp b/modules/stormkit/gpu.mpp new file mode 100644 index 000000000..d4366a75d --- /dev/null +++ b/modules/stormkit/gpu.mpp @@ -0,0 +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.gpu; + +// export import stormkit.gpu:Core.Compute; +export import stormkit.gpu.core; +export import stormkit.gpu.execution; +export import stormkit.gpu.resource; +export import stormkit.gpu.vulkan; diff --git a/modules/stormkit/Gpu/Core.mpp b/modules/stormkit/gpu/core.mpp similarity index 53% rename from modules/stormkit/Gpu/Core.mpp rename to modules/stormkit/gpu/core.mpp index 2829fd456..02f260f6a 100644 --- a/modules/stormkit/Gpu/Core.mpp +++ b/modules/stormkit/gpu/core.mpp @@ -2,9 +2,10 @@ // 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 module stormkit.gpu.core; -export import :Core.Device; -export import :Core.Instance; -export import :Core.Types; -export import :Core.Sync; +export import :loader; +export import :device; +export import :instance; +export import :types; +export import :sync; diff --git a/modules/stormkit/gpu/core/device.mpp b/modules/stormkit/gpu/core/device.mpp new file mode 100644 index 000000000..75a39f636 --- /dev/null +++ b/modules/stormkit/gpu/core/device.mpp @@ -0,0 +1,291 @@ +// 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:device; + +import std; + +import stormkit.core; +import stormkit.gpu.vulkan; + +import :types; + +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 { + UInt32 id; + UInt32 count; + QueueFlag flags = QueueFlag {}; + }; + + struct Info { + bool enable_swapchain; + bool enable_raytracing; + }; + + 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 -> void; + + auto set_object_name(UInt64 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; + VkRAIIHandle m_vk_handle = { [this](auto handle) noexcept { + m_vk_device_table.vkDestroyDevice(handle, nullptr); + } }; + VmaVulkanFunctions m_vma_function_table; + VkRAIIHandle m_vma_allocator = { [](auto handle) static noexcept { + vmaDestroyAllocator(handle); + } }; + }; +} // namespace stormkit::gpu + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit::gpu { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + Device::Device(const PhysicalDevice& physical_device, PrivateFuncTag) noexcept + : m_physical_device { as_ref(physical_device) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + Device::~Device() noexcept { + if (m_vk_handle) wait_idle(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_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)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_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)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + Device::Device(Device&&) noexcept + = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Device::operator=(Device&&) noexcept -> Device& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Device::wait_idle() const noexcept -> void { + // native_handle().wait_idle(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_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); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Device::reset_fence(const Fence& fence) const noexcept -> Expected { + return reset_fences(as_refs(fence)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Device::raster_queue_entry() const noexcept -> const QueueEntry& { + return m_raster_queue; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Device::async_transfer_queue_entry() const noexcept -> const QueueEntry& { + expects(m_async_transfert_queue != std::nullopt); + + return *m_async_transfert_queue; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Device::async_compute_queue_entry() const noexcept -> const QueueEntry& { + expects(m_async_compute_queue != std::nullopt); + + return *m_async_compute_queue; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Device::has_async_transfer_queue() const noexcept -> bool { + return m_async_transfert_queue != std::nullopt; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Device::has_async_compute_queue() const noexcept -> bool { + return m_async_compute_queue != std::nullopt; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Device::physical_device() const noexcept -> const PhysicalDevice& { + return m_physical_device; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + auto Device::set_object_name(const T& object, std::string_view name) const -> void { + auto&& vk_object = to_vkhandle(object); + set_object_name(std::bit_cast(static_cast(vk_object)), + T::DEBUG_TYPE, + name); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Device::set_object_name(UInt64 object, DebugObjectType type, std::string_view name) const + -> Expected { + if (not vkSetDebugUtilsObjectNameEXT) return {}; + + const auto info = VkDebugUtilsObjectNameInfoEXT { + .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT, + .pNext = nullptr, + .objectType = narrow(type), + .objectHandle = object, + .pObjectName = std::data(name), + }; + + return vk_call(vkSetDebugUtilsObjectNameEXT, m_vk_handle, &info) + .transform_error(monadic::from_vk()); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Device::native_handle() const noexcept -> VkDevice { + expects(m_vk_handle); + return m_vk_handle; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Device::device_table() const noexcept -> const VolkDeviceTable& { + return m_vk_device_table; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Device::allocator() const noexcept -> VmaAllocator { + return m_vma_allocator; + } +} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/core/instance.mpp b/modules/stormkit/gpu/core/instance.mpp new file mode 100644 index 000000000..ea775b331 --- /dev/null +++ b/modules/stormkit/gpu/core/instance.mpp @@ -0,0 +1,392 @@ +// 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:instance; + +import std; + +import stormkit.core; +import stormkit.wsi; +import stormkit.gpu.vulkan; + +import :types; +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 = { + [this](auto handle) noexcept { + vkDestroyDebugUtilsMessengerEXT(m_vk_handle, handle, nullptr); + } + }; + }; + + [[nodiscard]] + STORMKIT_API + auto score_physical_device(const PhysicalDevice& physical_device) noexcept -> UInt64; + + 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 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; + + 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 = { [this](auto handle) noexcept { + vkDestroySurfaceKHR(m_vk_instance, handle, nullptr); + } }; + }; + } // 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 } { + // do_init_instance() + // .and_then(bind_front(&Instance::do_init_debug_report_callback, this)) + // .and_then(bind_front(&Instance::do_retrieve_physical_devices, this)) + // .transform_error(core :.monadic::map(core :.monadic::narrow(), + // core :.monadic::throw_as_exception())); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_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 + 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 + Instance::~Instance() + = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + Instance::Instance(Instance&&) noexcept + = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Instance::operator=(Instance&&) noexcept -> Instance& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Instance::physical_devices() const noexcept -> const std::vector& { + return m_physical_devices; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Instance::native_handle() const noexcept -> VkInstance { + expects(m_vk_handle); + return m_vk_handle; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto PhysicalDevice::info() const noexcept -> const PhysicalDeviceInfo& { + return m_device_info; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto PhysicalDevice::capabilities() const noexcept -> const RenderCapabilities& { + return m_capabilities; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto PhysicalDevice::memory_types() const noexcept -> const std::vector& { + return m_memory_types; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto PhysicalDevice::queue_families() const noexcept -> const std::vector& { + return m_queue_families; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto PhysicalDevice::extensions() const noexcept -> const std::vector& { + return m_extensions; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto PhysicalDevice::native_handle() const noexcept -> VkPhysicalDevice { + expects(m_vk_handle); + return m_vk_handle; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr Surface::Surface(PrivateFuncTag) noexcept { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + Surface::~Surface() + = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + Surface::Surface(Surface&&) noexcept + = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_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 + 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 + 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 + 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.mpp new file mode 100644 index 000000000..238826480 --- /dev/null +++ b/modules/stormkit/gpu/core/loader.mpp @@ -0,0 +1,12 @@ +module; + +#include + +export module stormkit.gpu.core:loader; + +import :types; + +export namespace stormkit::gpu { + STORMKIT_API + auto initialize_backend() -> Expected; +} diff --git a/modules/stormkit/gpu/core/sync.mpp b/modules/stormkit/gpu/core/sync.mpp new file mode 100644 index 000000000..d94c89191 --- /dev/null +++ b/modules/stormkit/gpu/core/sync.mpp @@ -0,0 +1,299 @@ +// 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:sync; + +import std; + +import stormkit.core; +import stormkit.gpu.vulkan; + +import :types; +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 = { [this](auto handle) noexcept { + m_vk_device_table->vkDestroyFence(m_vk_device, handle, nullptr); + } }; + }; + + 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 = { [this](auto handle) noexcept { + m_vk_device_table->vkDestroySemaphore(m_vk_device, handle, nullptr); + } }; + }; +} // namespace stormkit::gpu + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit::gpu { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + Fence::Fence(const Device& device, PrivateFuncTag) noexcept + : m_vk_device { device.native_handle() }, + m_vk_device_table { as_ref(device.device_table()) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_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 + auto Fence::create_signaled(const Device& device) noexcept -> Expected { + return create(device, true); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_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 + auto Fence::allocate_signaled(const Device& device) noexcept -> Expected> { + return allocate(device, true); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + Fence::~Fence() + = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + Fence::Fence(Fence&&) noexcept + = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Fence::operator=(Fence&&) noexcept -> Fence& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Fence::status() const noexcept -> Expected { + return vk_call(m_vk_device_table->vkGetFenceStatus, + { VK_SUCCESS, VK_NOT_READY }, + 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 + auto Fence::wait(const std::chrono::milliseconds& wait_for) const -> Expected { + return vk_call(m_vk_device_table->vkWaitForFences, + { VK_SUCCESS, VK_NOT_READY }, + 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 + 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 + auto Fence::native_handle() const noexcept -> VkFence { + expects(m_vk_handle); + return m_vk_handle; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_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 + Semaphore::Semaphore(const Device& device, PrivateFuncTag) noexcept + : m_vk_device { device.native_handle() }, + m_vk_device_table { as_ref(device.device_table()) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_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 + 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 + Semaphore::~Semaphore() + = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + Semaphore::Semaphore(Semaphore&&) noexcept + = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Semaphore::operator=(Semaphore&&) noexcept -> Semaphore& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Semaphore::native_handle() const noexcept -> VkSemaphore { + expects(m_vk_handle); + return m_vk_handle; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_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/types.mpp b/modules/stormkit/gpu/core/types.mpp new file mode 100644 index 000000000..085f7d3ad --- /dev/null +++ b/modules/stormkit/gpu/core/types.mpp @@ -0,0 +1,2863 @@ +// 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:types; + +import std; +import frozen; + +import stormkit.core; + +#ifdef STORMKIT_GPU_VULKAN +import stormkit.gpu.vulkan; + #define PHYSICAL_DEVICE_TYPE_VALUE(X) X = VK_PHYSICAL_DEVICE_TYPE_##X + #define QUEUE_FLAG_VALUE(X) X = VK_QUEUE_##X##_BIT + #define SHADER_STAGE_VALUE(X) X = VK_SHADER_STAGE_##X##_BIT + #define PRIMITIVE_TOPOLOGY_VALUE(X) X = VK_PRIMITIVE_TOPOLOGY_##X + #define POLYGON_MODE_VALUE(X) X = VK_POLYGON_MODE_##X + #define CULL_MODE_VALUE(X) X = VK_CULL_MODE_##X##_BIT + #define FRONT_FACE_VALUE(X) X = VK_FRONT_FACE_##X + #define SAMPLE_COUNT_VALUE(X) C##X = VK_SAMPLE_COUNT_##X##_BIT + #define COLOR_COMPONENT_VALUE(X) X + #define BLEND_FACTOR_VALUE(X) X = VK_BLEND_FACTOR_##X + #define BLEND_OP_VALUE(X) X = VK_BLEND_OP_##X + #define LOGIC_OP_VALUE(X) X = VK_LOGIC_OP_##X + #define PIXEL_FORMAT_VALUE(X) X = VK_FORMAT_##X + #define PIXEL_FORMAT_VALUE2(X, Y) X = VK_FORMAT_##Y + #define ATTACHMENT_LOAD_OP_VALUE(X) X = VK_ATTACHMENT_LOAD_OP_##X + #define ATTACHMENT_STORE_OP_VALUE(X) X = VK_ATTACHMENT_STORE_OP_##X + #define PIPELINE_BIND_POINT_VALUE(X) X = VK_PIPELINE_BIND_POINT_##X + #define IMAGE_LAYOUT_VALUE(X) X = VK_IMAGE_LAYOUT_##X + #define IMAGE_LAYOUT_VALUE_KHR(X) X = VK_IMAGE_LAYOUT_##X##_KHR + #define IMAGE_ASPECT_MASK_VALUE(X) X = VK_IMAGE_ASPECT_##X##_BIT + #define VERTEX_INPUT_RATE_VALUE(X) X = VK_VERTEX_INPUT_RATE_##X + #define IMAGE_CREATE_VALUE(X) X = VK_IMAGE_CREATE_##X##_BIT + #define IMAGE_CREATE_VALUE_EXT(X) X = VK_IMAGE_CREATE_##X##_BIT_EXT + #define BUFFER_USAGE_VALUE(X) X = VK_BUFFER_USAGE_##X##_BUFFER_BIT + #define BUFFER_USAGE_VALUE2(X) X = VK_BUFFER_USAGE_##X##_BIT + #define IMAGE_USAGE_VALUE(X) X = VK_IMAGE_USAGE_##X##_BIT + #define MEMORY_PROPERTY_VALUE(X) X = VK_MEMORY_PROPERTY_##X##_BIT + #define COMMAND_BUFFER_LEVEL_VALUE(X) X = VK_COMMAND_BUFFER_LEVEL_##X + #define DESCRIPTOR_TYPE_VALUE(X) X = VK_DESCRIPTOR_TYPE_##X + #define COMPARE_OP_VALUE(X) X = VK_COMPARE_OP_##X + #define FILTER_VALUE(X) X = VK_FILTER_##X + #define SAMPLER_ADDRESS_MODE_VALUE(X) X = VK_SAMPLER_ADDRESS_MODE_##X + #define BORDER_COLOR_VALUE(X) X = VK_BORDER_COLOR_##X + #define SAMPLER_MIPMAP_MODE_VALUE(X) X = VK_SAMPLER_MIPMAP_MODE_##X + #define RESULT_VALUE(X) X = VK_##X + #define RESULT_VALUE_KHR(X) X = VK_##X##_KHR + #define RESULT_VALUE_EXT(X) X = VK_##X##_EXT + #define DEBUG_OBJECT_TYPE_VALUE(X) X = VK_OBJECT_TYPE_##X + #define DEBUG_OBJECT_TYPE_VALUE_KHR(X) X = VK_OBJECT_TYPE_##X##_KHR + #define DEBUG_OBJECT_TYPE_VALUE_EXT(X) X = VK_OBJECT_TYPE_##X##_EXT + #define ACCESS_FLAG_VALUE(X) X = VK_ACCESS_##X##_BIT + #define PIPELINE_STAGE_VALUE(X) X = VK_PIPELINE_STAGE_##X##_BIT + #define DEPENDENCY_VALUE(X) X = VK_DEPENDENCY_##X##_BIT + #define DYNAMIC_STATE_VALUE(X) X = VK_DYNAMIC_STATE_##X + #define IMAGE_TILING_VALUE(X) X = VK_IMAGE_TILING_##X + #define STENCIL_FACE_VALUE(X) X = VK_STENCIL_FACE_##X##_BIT + #define GEOMETRY_TYPE_VALUE(X) X = VK_GEOMETRY_TYPE_##X##_KHR + #define GEOMETRY_VALUE(X) X = VK_GEOMETRY_##X##_BIT_KHR + #define COLOR_SPACE_VALUE(X) X = VK_COLOR_SPACE_##X + #define COLOR_SPACE_VALUE_EXT(X) X = VK_COLOR_SPACE_##X##_EXT + #define PRESENT_MODE_VALUE(X) X = VK_PRESENT_MODE_##X##_KHR +#elifdef STORMKIT_GPU_WGPU +import stormkit.gpu.wgpu; +#else + #error "No GPU Backend set!" +#endif + +export { + namespace stormkit::gpu { + inline constexpr auto QUEUE_FAMILY_IGNORED = std::numeric_limits::max(); + +#ifdef STORMKIT_GPU_VULKAN + #define DISCRETE_GPU PHYSICAL_DEVICE_TYPE_VALUE(DISCRETE_GPU) + #define VIRTUAL_GPU PHYSICAL_DEVICE_TYPE_VALUE(VIRTUAL_GPU) + #define INTEGRATED_GPU PHYSICAL_DEVICE_TYPE_VALUE(INTEGRATED_GPU) + #define CPU PHYSICAL_DEVICE_TYPE_VALUE(CPU) + #define OTHER PHYSICAL_DEVICE_TYPE_VALUE(OTHER) +#elifdef STORMKIT_GPU_WGPU + #define DISCRETE_GPU DISCRETE_GPU, + #define VIRTUAL_GPU VIRTUAL_GPU, + #define INTEGRATED_GPU INTEGRATED_GPU, + #define CPU CPU, + #define OTHER OTHER, +#endif + enum class PhysicalDeviceType : UInt8 { + DISCRETE_GPU, + VIRTUAL_GPU, + INTEGRATED_GPU, + CPU, + OTHER, + }; +#undef DISCRETE_GPU +#undef VIRTUAL_GPU +#undef INTEGRATED_GPU +#undef CPU +#undef OTHER + +#ifdef STORMKIT_GPU_VULKAN + #define GRAPHICS QUEUE_FLAG_VALUE(GRAPHICS) + #define COMPUTE QUEUE_FLAG_VALUE(COMPUTE) + #define TRANSFER QUEUE_FLAG_VALUE(TRANSFER) + #define SPARSE_BINDING QUEUE_FLAG_VALUE(SPARSE_BINDING) + #define PROTECTED QUEUE_FLAG_VALUE(PROTECTED) +#elifdef STORMKIT_GPU_WGPU + #define GRAPHICS + #define COMPUTE + #define TRANSFER + #define SPARSE_BINDING + #define PROTECTED +#endif + enum class QueueFlag : UInt8 { + NONE = 0, + GRAPHICS, + COMPUTE, + TRANSFER, + SPARSE_BINDING, + PROTECTED, + }; +#undef GRAPHICS +#undef COMPUTE +#undef TRANSFER +#undef SPARSE_BINDING +#undef PROTECTED + +#ifdef STORMKIT_GPU_VULKAN + #define VERTEX SHADER_STAGE_VALUE(VERTEX) + #define FRAGMENT SHADER_STAGE_VALUE(FRAGMENT) + #define GEOMETRY SHADER_STAGE_VALUE(GEOMETRY) + #define COMPUTE SHADER_STAGE_VALUE(COMPUTE) +#elifdef STORMKIT_GPU_WGPU + #define VERTEX + #define FRAGMENT + #define GEOMETRY + #define COMPUTE +#endif + enum class ShaderStageFlag : UInt8 { + NONE = 0, + VERTEX, + FRAGMENT, + GEOMETRY, + COMPUTE, + }; +#undef VERTEX +#undef FRAGMENT +#undef GEOMETRY +#undef COMPUTE + +#ifdef STORMKIT_GPU_VULKAN + #define POINT_LIST PRIMITIVE_TOPOLOGY_VALUE(POINT_LIST) + #define LINE_LIST PRIMITIVE_TOPOLOGY_VALUE(LINE_LIST) + #define LINE_STRIP PRIMITIVE_TOPOLOGY_VALUE(LINE_STRIP) + #define TRIANGLE_LIST PRIMITIVE_TOPOLOGY_VALUE(TRIANGLE_LIST) + #define TRIANGLE_STRIP PRIMITIVE_TOPOLOGY_VALUE(TRIANGLE_STRIP) + #define TRIANGLE_FAN PRIMITIVE_TOPOLOGY_VALUE(TRIANGLE_FAN) +#elifdef STORMKIT_GPU_WGPU + #define POINT_LIST + #define LINE_LIST + #define LINE_STRIP + #define TRIANGLE_LIST + #define TRIANGLE_STRIP + #define TRIANGLE_FAN +#endif + enum class PrimitiveTopology : UInt8 { + POINT_LIST, + LINE_LIST, + LINE_STRIP, + TRIANGLE_LIST, + TRIANGLE_STRIP, + TRIANGLE_FAN, + }; +#undef POINT_LIST +#undef LINE_LIST +#undef LINE_STRIP +#undef TRIANGLE_LIST +#undef TRIANGLE_STRIP +#undef TRIANGLE_FAN + +#ifdef STORMKIT_GPU_VULKAN + #define FILL POLYGON_MODE_VALUE(FILL) + #define LINE POLYGON_MODE_VALUE(LINE) + #define POINT POLYGON_MODE_VALUE(POINT) +#elifdef STORMKIT_GPU_WGPU + #define FILL + #define LINE + #define POINT +#endif + enum class PolygonMode : UInt8 { + FILL, + LINE, + POINT, + }; +#undef FILL +#undef LINE +#undef POINT + +#ifdef STORMKIT_GPU_VULKAN + #define FRONT CULL_MODE_VALUE(FRONT) + #define BACK CULL_MODE_VALUE(BACK) +#elifdef STORMKIT_GPU_WGPU + #define FRONT + #define BACK +#endif + enum class CullModeFlag : UInt8 { + NONE = 0, + FRONT, + BACK, +#undef FRONT +#undef BACK + FRONT_BACK = FRONT | BACK, + }; + +#ifdef STORMKIT_GPU_VULKAN + #define CLOCKWISE FRONT_FACE_VALUE(CLOCKWISE) + #define COUNTER_CLOCKWISE FRONT_FACE_VALUE(COUNTER_CLOCKWISE) +#elifdef STORMKIT_GPU_WGPU + #define CLOCKWISE + #define COUNTER_CLOCKWISE +#endif + enum class FrontFace : UInt8 { + CLOCKWISE, + COUNTER_CLOCKWISE, + }; +#undef CLOCKWISE +#undef COUNTER_CLOCKWISE + +#ifdef STORMKIT_GPU_VULKAN + #define C1 SAMPLE_COUNT_VALUE(1) + #define C2 SAMPLE_COUNT_VALUE(2) + #define C4 SAMPLE_COUNT_VALUE(4) + #define C8 SAMPLE_COUNT_VALUE(8) + #define C16 SAMPLE_COUNT_VALUE(16) + #define C32 SAMPLE_COUNT_VALUE(32) + #define C64 SAMPLE_COUNT_VALUE(64) +#elifdef STORMKIT_GPU_WGPU + #define C1 + #define C2 + #define C4 + #define C8 + #define C16 + #define C32 + #define C64 +#endif + enum class SampleCountFlag : UInt8 { + NONE = 0, + C1, + C2, + C4, + C8, + C16, + C32, + C64, + }; +#undef C1 +#undef C2 +#undef C4 +#undef C8 +#undef C16 +#undef C32 +#undef C64 + +#ifdef STORMKIT_GPU_VULKAN + #define R COLOR_COMPONENT_VALUE(R) + #define G COLOR_COMPONENT_VALUE(G) + #define B COLOR_COMPONENT_VALUE(B) + #define A COLOR_COMPONENT_VALUE(A) +#elifdef STORMKIT_GPU_WGPU + #define R + #define G + #define B + #define A +#endif + enum class ColorComponentFlag : UInt8 { + NONE = 0, + R, + G, + B, + A, + RG = R | G, + RGB = RG | B, + RGBA = RGB | A, + }; +#undef R +#undef G +#undef B +#undef A + +#ifdef STORMKIT_GPU_VULKAN + #define ONE BLEND_FACTOR_VALUE(ONE) + #define ZERO BLEND_FACTOR_VALUE(ZERO) + #define SRC_COLOR BLEND_FACTOR_VALUE(SRC_COLOR) + #define ONE_MINUS_SRC_COLOR BLEND_FACTOR_VALUE(ONE_MINUS_SRC_COLOR) + #define DST BLEND_FACTOR_VALUE(DST) + #define ONE_MINUS_DST_COLOR BLEND_FACTOR_VALUE(ONE_MINUS_DST_COLOR) + #define SRC_ALPHA BLEND_FACTOR_VALUE(SRC_ALPHA) + #define ONE_MINUS_SRC_ALPHA BLEND_FACTOR_VALUE(ONE_MINUS_SRC_ALPHA) + #define DST_ALPHA BLEND_FACTOR_VALUE(DST_ALPHA) + #define ONE_MINUS_DST_ALPHA BLEND_FACTOR_VALUE(ONE_MINUS_DST_ALPHA) + #define CONSTANCE_COLOR BLEND_FACTOR_VALUE(CONSTANCE_COLOR) + #define ONE_MINUS_CONSTANT_COLOR BLEND_FACTOR_VALUE(ONE_MINUS_CONSTANT_COLOR) + #define CONSTANT_ALPHA BLEND_FACTOR_VALUE(CONSTANT_ALPHA) + #define ONE_MINUS_CONSTANT_ALPHA BLEND_FACTOR_VALUE(ONE_MINUS_CONSTANT_ALPHA) + #define SRC_ALPHA_SATURATE BLEND_FACTOR_VALUE(SRC_ALPHA_SATURATE) + #define SRC1_COLOR BLEND_FACTOR_VALUE(SRC1_COLOR) + #define ONE_MINUS_SRC1_COLOR BLEND_FACTOR_VALUE(ONE_MINUS_SRC1_COLOR) + #define SRC1_ALPHA BLEND_FACTOR_VALUE(SRC1_ALPHA) + #define ONE_MINUS_SRC1_ALPHA BLEND_FACTOR_VALUE(ONE_MINUS_SRC1_ALPHA) +#elifdef STORMKIT_GPU_WGPU + #define ONE + #define ZERO + #define SRC_COLOR + #define ONE_MINUS_SRC_COLOR + #define DST + #define ONE_MINUS_DST_COLOR + #define SRC_ALPHA + #define ONE_MINUS_SRC_ALPHA + #define DST_ALPHA + #define ONE_MINUS_DST_ALPHA + #define CONSTANCE_COLOR + #define ONE_MINUS_CONSTANT_COLOR + #define CONSTANT_ALPHA + #define ONE_MINUS_CONSTANT_ALPHA + #define SRC_ALPHA_SATURATE + #define SRC1_COLOR + #define ONE_MINUS_SRC1_COLOR + #define SRC1_ALPHA + #define ONE_MINUS_SRC1_ALPHA +#endif + enum class BlendFactor : UInt8 { + ONE, + ZERO, + SRC_COLOR, + ONE_MINUS_SRC_COLOR, + DST_COLOR, + ONE_MINUS_DST_COLOR, + SRC_ALPHA, + ONE_MINUS_SRC_ALPHA, + DST_ALPHA, + ONE_MINUS_DST_ALPHA, + CONSTANT_COLOR, + ONE_MINUS_CONSTANT_COLOR, + CONSTANT_ALPHA, + ONE_MINUS_CONSTANT_ALPHA, + SRC_ALPHA_SATURATE, + SRC1_COLOR, + ONE_MINUS_SRC1_COLOR, + SRC1_ALPHA, + ONE_MINUS_SRC1_ALPHA, + }; +#undef ONE +#undef ZERO +#undef SRC_COLOR +#undef ONE_MINUS_SRC_COLOR +#undef DST +#undef ONE_MINUS_DST_COLOR +#undef SRC_ALPHA +#undef ONE_MINUS_SRC_ALPHA +#undef DST_ALPHA +#undef ONE_MINUS_DST_ALPHA +#undef CONSTANCE_COLOR +#undef ONE_MINUS_CONSTANT_COLOR +#undef CONSTANT_ALPHA +#undef ONE_MINUS_CONSTANT_ALPHA +#undef SRC_ALPHA_SATURATE +#undef SRC1_COLOR +#undef ONE_MINUS_SRC1_COLOR +#undef SRC1_ALPHA +#undef ONE_MINUS_SRC1_ALPHA + +#ifdef STORMKIT_GPU_VULKAN + #define ADD BLEND_OP_VALUE(ADD) + #define SUBTRACT BLEND_OP_VALUE(SUBTRACT) + #define REVERSE_SUBTRACT BLEND_OP_VALUE(REVERSE_SUBTRACT) + #define MIN BLEND_OP_VALUE(MIN) + #define MAX BLEND_OP_VALUE(MAX) +#elifdef STORMKIT_GPU_WGPU + #define ADD + #define SUBTRACT + #define REVERSE_SUBTRACT + #define MIN + #define MAX +#endif + enum class BlendOperation : UInt8 { + ADD, + SUBTRACT, + REVERSE_SUBTRACT, + MIN, + MAX, + }; +#undef ADD +#undef SUBTRACT +#undef REVERSE_SUBTRACT +#undef MIN +#undef MAX + +#ifdef STORMKIT_GPU_VULKAN + #define CLEAR LOGIC_OP_VALUE(CLEAR) + #define AND LOGIC_OP_VALUE(AND) + #define AND_REVERSE LOGIC_OP_VALUE(AND_REVERSE) + #define COPY LOGIC_OP_VALUE(COPY) + #define AND_INVERTED LOGIC_OP_VALUE(AND_INVERTED) + #define NO_OP LOGIC_OP_VALUE(NO_OP) + #define XOR LOGIC_OP_VALUE(XOR) + #define OR LOGIC_OP_VALUE(OR) + #define NOR LOGIC_OP_VALUE(NOR) + #define EQUIVALENT LOGIC_OP_VALUE(EQUIVALENT) + #define INVERT LOGIC_OP_VALUE(INVERT) + #define OR_REVERSE LOGIC_OP_VALUE(OR_REVERSE) + #define COPY_INVERTED LOGIC_OP_VALUE(COPY_INVERTED) + #define OR_INVERTED LOGIC_OP_VALUE(OR_INVERTED) + #define NAND LOGIC_OP_VALUE(NAND) + #define SET LOGIC_OP_VALUE(SET) +#elifdef STORMKIT_GPU_WGPU + #define CLEAR + #define AND + #define AND_REVERSE + #define COPY + #define AND_INVERTED + #define NO_OP + #define XOR + #define OR + #define NOR + #define EQUIVALENT + #define INVERT + #define OR_REVERSE + #define COPY_INVERTED + #define OR_INVERTED + #define NAND + #define SET +#endif + enum class LogicOperation : UInt8 { + CLEAR, + AND, + AND_REVERSE, + COPY, + AND_INVERTED, + NO_OP, + XOR, + OR, + NOR, + EQUIVALENT, + INVERT, + OR_REVERSE, + COPY_INVERTED, + OR_INVERTED, + NAND, + SET, + }; +#undef CLEAR +#undef AND +#undef AND_REVERSE +#undef COPY +#undef AND_INVERTED +#undef NO_OP +#undef XOR +#undef OR +#undef NOR +#undef EQUIVALENT +#undef INVERT +#undef OR_REVERSE +#undef COPY_INVERTED +#undef OR_INVERTED +#undef NAND +#undef SET + +#ifdef STORMKIT_GPU_VULKAN + #define UNDEFINED PIXEL_FORMAT_VALUE(UNDEFINED) + + #define R8_SNORM PIXEL_FORMAT_VALUE(R8_SNORM) + #define RG8_SNORM PIXEL_FORMAT_VALUE2(RG8_SNORM, R8G8_SNORM) + #define RGB8_SNORM PIXEL_FORMAT_VALUE2(RGB8_SNORM, R8G8B8_SNORM) + #define RGBA8_SNORM PIXEL_FORMAT_VALUE2(RGBA8_SNORM, R8G8B8A8_SNORM) + #define R8_UNORM PIXEL_FORMAT_VALUE(R8_UNORM) + #define RG8_UNORM PIXEL_FORMAT_VALUE2(RG8_UNORM, R8G8_UNORM) + #define RGB8_UNORM PIXEL_FORMAT_VALUE2(RGB8_UNORM, R8G8B8_UNORM) + #define RGBA8_UNORM PIXEL_FORMAT_VALUE2(RGBA8_UNORM, R8G8B8A8_UNORM) + + #define R16_SNORM PIXEL_FORMAT_VALUE(R16_SNORM) + #define RG16_SNORM PIXEL_FORMAT_VALUE2(RG16_SNORM, R16G16_SNORM) + #define RGB16_SNORM PIXEL_FORMAT_VALUE2(RGB16_SNORM, R16G16B16_SNORM) + #define RGBA16_SNORM PIXEL_FORMAT_VALUE2(RGBA16_SNORM, R16G16B16A16_SNORM) + #define R16_UNORM PIXEL_FORMAT_VALUE(R16_UNORM) + #define RG16_UNORM PIXEL_FORMAT_VALUE2(RG16_UNORM, R16G16_UNORM) + #define RGB16_UNORM PIXEL_FORMAT_VALUE2(RGB16_UNORM, R16G16B16_UNORM) + #define RGBA16_UNORM PIXEL_FORMAT_VALUE2(RGBA16_UNORM, R16G16B16A16_UNORM) + + #define A2_RGB10_UNORM_PACK32 \ + PIXEL_FORMAT_VALUE2(A2_RGB10_UNORM_PACK32, A2R10G10B10_UNORM_PACK32) + #define A2_RGB10_SNORM_PACK32 \ + PIXEL_FORMAT_VALUE2(A2_RGB10_SNORM_PACK32, A2R10G10B10_SNORM_PACK32) + + #define A2_RGB10U_PACK32 PIXEL_FORMAT_VALUE2(A2_RGB10U_PACK32, A2R10G10B10_UINT_PACK32) + #define A2_RGB10I_PACK32 PIXEL_FORMAT_VALUE2(A2_RGB10I_PACK32, A2R10G10B10_SINT_PACK32) + + #define RGBA4_UNORM_PACK16 PIXEL_FORMAT_VALUE2(RGBA4_UNORM_PACK16, R4G4B4A4_UNORM_PACK16) + + #define A1_RGB5_UNORM_PACK16 PIXEL_FORMAT_VALUE2(A1_RGB5_UNORM_PACK16, A1R5G5B5_UNORM_PACK16) + #define R5_G6_B5_UNORM_PACK16 PIXEL_FORMAT_VALUE2(R5_G6_B5_UNORM_PACK16, R5G6B5_UNORM_PACK16) + + #define BGR8_UNORM PIXEL_FORMAT_VALUE2(BGR8_UNORM, B8G8R8_UNORM) + #define BGRA8_UNORM PIXEL_FORMAT_VALUE2(BGRA8_UNORM, B8G8R8A8_UNORM) + + #define R8I PIXEL_FORMAT_VALUE2(R8I, R8_SINT) + #define RG8I PIXEL_FORMAT_VALUE2(RG8I, R8G8_SINT) + #define RGB8I PIXEL_FORMAT_VALUE2(RGB8I, R8G8B8_SINT) + #define RGBA8I PIXEL_FORMAT_VALUE2(RGBA8I, R8G8B8A8_SINT) + + #define R8U PIXEL_FORMAT_VALUE2(R8U, R8_UINT) + #define RG8U PIXEL_FORMAT_VALUE2(RG8U, R8G8_UINT) + #define RGB8U PIXEL_FORMAT_VALUE2(RGB8U, R8G8B8_UINT) + #define RGBA8U PIXEL_FORMAT_VALUE2(RGBA8U, R8G8B8A8_UINT) + + #define R16I PIXEL_FORMAT_VALUE2(R16I, R16_SINT) + #define RG16I PIXEL_FORMAT_VALUE2(RG16I, R16G16_SINT) + #define RGB16I PIXEL_FORMAT_VALUE2(RGB16I, R16G16B16_SINT) + #define RGBA16I PIXEL_FORMAT_VALUE2(RGBA16I, R16G16B16A16_SINT) + + #define R16U PIXEL_FORMAT_VALUE2(R16U, R16_UINT) + #define RG16U PIXEL_FORMAT_VALUE2(RG16U, R16G16_UINT) + #define RGB16U PIXEL_FORMAT_VALUE2(RGB16U, R16G16B16_UINT) + #define RGBA16U PIXEL_FORMAT_VALUE2(RGBA16U, R16G16B16A16_UINT) + + #define R32I PIXEL_FORMAT_VALUE2(R32I, R32_SINT) + #define RG32I PIXEL_FORMAT_VALUE2(RG32I, R32G32_SINT) + #define RGB32I PIXEL_FORMAT_VALUE2(RGB32I, R32G32B32_SINT) + #define RGBA32I PIXEL_FORMAT_VALUE2(RGBA32I, R32G32B32A32_SINT) + + #define R32U PIXEL_FORMAT_VALUE2(R32U, R32_UINT) + #define RG32U PIXEL_FORMAT_VALUE2(RG32U, R32G32_UINT) + #define RGB32U PIXEL_FORMAT_VALUE2(RGB32U, R32G32B32_UINT) + #define RGBA32U PIXEL_FORMAT_VALUE2(RGBA32U, R32G32B32A32_UINT) + + #define R16F PIXEL_FORMAT_VALUE2(R16F, R16_SFLOAT) + #define RG16F PIXEL_FORMAT_VALUE2(RG16F, R16G16_SFLOAT) + #define RGB16F PIXEL_FORMAT_VALUE2(RGB16F, R16G16B16_SFLOAT) + #define RGBA16F PIXEL_FORMAT_VALUE2(RGBA16F, R16G16B16A16_SFLOAT) + + #define R32F PIXEL_FORMAT_VALUE2(R32F, R32_SFLOAT) + #define RG32F PIXEL_FORMAT_VALUE2(RG32F, R32G32_SFLOAT) + #define RGB32F PIXEL_FORMAT_VALUE2(RGB32F, R32G32B32_SFLOAT) + #define RGBA32F PIXEL_FORMAT_VALUE2(RGBA32F, R32G32B32A32_SFLOAT) + + #define B10_GR11UF_PACK32 PIXEL_FORMAT_VALUE2(B10_GR11UF_PACK32, B10G11R11_UFLOAT_PACK32) + + #define SR8 PIXEL_FORMAT_VALUE2(SR8, R8_SRGB) + #define SRG8 PIXEL_FORMAT_VALUE2(SRG8, R8G8_SRGB) + #define SRGB8 PIXEL_FORMAT_VALUE2(SRGB8, R8G8B8_SRGB) + #define SRGBA8 PIXEL_FORMAT_VALUE2(SRGBA8, R8G8B8A8_SRGB) + + #define SBGR8 PIXEL_FORMAT_VALUE2(SBGR8, B8G8R8_SRGB) + #define SBGRA8 PIXEL_FORMAT_VALUE2(SBGRA8, B8G8R8A8_SRGB) + + #define DEPTH16_UNORM PIXEL_FORMAT_VALUE2(DEPTH16_UNORM, D16_UNORM) + #define DEPTH24_UNORM PIXEL_FORMAT_VALUE2(DEPTH24_UNORM, D24_UNORM) + #define DEPTH32F PIXEL_FORMAT_VALUE2(DEPTH32F, D32_SFLOAT) + + #define DEPTH16_UNORM_STENCIL8U PIXEL_FORMAT_VALUE2(DEPTH16_UNORM_STENCIL8U, D16_UNORM_S8_UINT) + #define DEPTH24_UNORM_STENCIL8U PIXEL_FORMAT_VALUE2(DEPTH24_UNORM_STENCIL8U, D24_UNORM_S8_UINT) + #define DEPTH32F_STENCIL8U PIXEL_FORMAT_VALUE2(DEPTH32F_STENCIL8U, D32_SFLOAT_S8_UINT) +#elifdef STORMKIT_GPU_WGPU + #define UNDEFINED + + #define R8_SNORM + #define RG8_SNORM + #define RGB8_SNORM + #define RGBA8_SNORM + #define R8_UNORM + #define RG8_UNORM + #define RGB8_UNORM + #define RGBA8_UNORM + + #define R16_SNORM + #define RG16_SNORM + #define RGB16_SNORM + #define RGBA16_SNORM + #define R16_UNORM + #define RG16_UNORM + #define RGB16_UNORM + #define RGBA16_UNORM + + #define A2_RGB10_UNORM_PACK32 + + #define A2_RGB10_SNORM_PACK32 + + #define A2_RGB10U_PACK32 + #define A2_RGB10I_PACK32 + + #define RGBA4_UNORM_PACK16 + + #define A1_RGB5_UNORM_PACK16 + #define R5_G6_B5_UNORM_PACK16 + + #define BGR8_UNORM + #define BGRA8_UNORM + + #define R8I + #define RG8I + #define RGB8I + #define RGBA8I + + #define R8U + #define RG8U + #define RGB8U + #define RGBA8U + + #define R16I + #define RG16I + #define RGB16I + #define RGBA16I + + #define R16U + #define RG16U + #define RGB16U + #define RGBA16U + + #define R32I + #define RG32I + #define RGB32I + #define RGBA32I + + #define R32U + #define RG32U + #define RGB32U + #define RGBA32U + + #define R16F + #define RG16F + #define RGB16F + #define RGBA16F + + #define R32F + #define RG32F + #define RGB32F + #define RGBA32F + + #define B10_GR11UF_PACK32 + + #define SR8 + #define SRG8 + #define SRGB8 + #define SRGBA8 + + #define SBGR8 + #define SBGRA8 + + #define DEPTH16_UNORM + #define DEPTH24_UNORM + #define DEPTH32F + + #define DEPTH16_UNORM_STENCIL8U + #define DEPTH24_UNORM_STENCIL8U + #define DEPTH32F_STENCIL8U +#endif + enum class PixelFormat : UInt32 { + UNDEFINED, + + R8_SNORM, + RG8_SNORM, + RGB8_SNORM, + RGBA8_SNORM, + R8_UNORM, + RG8_UNORM, + RGB8_UNORM, + RGBA8_UNORM, + + R16_SNORM, + RG16_SNORM, + RGB16_SNORM, + RGBA16_SNORM, + R16_UNORM, + RG16_UNORM, + RGB16_UNORM, + RGBA16_UNORM, + + A2_RGB10_UNORM_PACK32, + A2_RGB10_SNORM_PACK32, + + RGBA4_UNORM_PACK16, + + A1_RGB5_UNORM_PACK16, + + R5_G6_B5_UNORM_PACK16, + + BGR8_UNORM, + BGRA8_UNORM, + + R8I, + RG8I, + RGB8I, + RGBA8I, + + R8U, + RG8U, + RGB8U, + RGBA8U, + + R16I, + RG16I, + RGB16I, + RGBA16I, + + R16U, + RG16U, + RGB16U, + RGBA16U, + + R32I, + RG32I, + RGB32I, + RGBA32I, + + R32U, + RG32U, + RGB32U, + RGBA32U, + + A2_RGB10U_PACK32, + + R16F, + RG16F, + RGB16F, + RGBA16F, + + R32F, + RG32F, + RGB32F, + RGBA32F, + + B10_GR11UF_PACK32, + + SR8, + SRG8, + SRGB8, + SRGBA8, + + SBGR8, + SBGRA8, + + DEPTH16, + DEPTH24, + DEPTH32F, + + DEPTH16_STENCIL8, + DEPTH24_STENCIL8, + DEPTH32F_STENCIL8, + }; +#undef UNDEFINED + +#undef R8_SNORM +#undef RG8_SNORM +#undef RGB8_SNORM +#undef RGBA8_SNORM +#undef R8_UNORM +#undef RG8_UNORM +#undef RGB8_UNORM +#undef RGBA8_UNORM + +#undef R16_SNORM +#undef RG16_SNORM +#undef RGB16_SNORM +#undef RGBA16_SNORM +#undef R16_UNORM +#undef RG16_UNORM +#undef RGB16_UNORM +#undef RGBA16_UNORM + +#undef A2_RGB10_UNORM_PACK32 + +#undef A2_RGB10_SNORM_PACK32 + +#undef A2_RGB10U_PACK32 +#undef A2_RGB10I_PACK32 + +#undef RGBA4_UNORM_PACK16 + +#undef A1_RGB5_UNORM_PACK16 +#undef R5_G6_B5_UNORM_PACK16 + +#undef BGR8_UNORM +#undef BGRA8_UNORM + +#undef R8I +#undef RG8I +#undef RGB8I +#undef RGBA8I + +#undef R8U +#undef RG8U +#undef RGB8U +#undef RGBA8U + +#undef R16I +#undef RG16I +#undef RGB16I +#undef RGBA16I + +#undef R16U +#undef RG16U +#undef RGB16U +#undef RGBA16U + +#undef R32I +#undef RG32I +#undef RGB32I +#undef RGBA32I + +#undef R32U +#undef RG32U +#undef RGB32U +#undef RGBA32U + +#undef R16F +#undef RG16F +#undef RGB16F +#undef RGBA16F + +#undef R32F +#undef RG32F +#undef RGB32F +#undef RGBA32F + +#undef B10_GR11UF_PACK32 + +#undef SR8 +#undef SRG8 +#undef SRGB8 +#undef SRGBA8 + +#undef SBGR8 +#undef SBGRA8 + +#undef DEPTH16_UNORM +#undef DEPTH24_UNORM +#undef DEPTH32F + +#undef DEPTH16_UNORM_STENCIL8U +#undef DEPTH24_UNORM_STENCIL8U +#undef DEPTH32F_STENCIL8U + +#ifdef STORMKIT_GPU_VULKAN + #define LOAD ATTACHMENT_LOAD_OP_VALUE(LOAD) + #define CLEAR ATTACHMENT_LOAD_OP_VALUE(CLEAR) + #define DONT_CARE ATTACHMENT_LOAD_OP_VALUE(DONT_CARE) +#elifdef STORMKIT_GPU_WGPU + #define LOAD + #define CLEAR + #define DONT_CARE +#endif + enum class AttachmentLoadOperation : UInt8 { + LOAD, + CLEAR, + DONT_CARE, + }; +#undef LOAD +#undef CLEAR +#undef DONT_CARE + +#ifdef STORMKIT_GPU_VULKAN + #define STORE ATTACHMENT_STORE_OP_VALUE(STORE) + #define DONT_CARE ATTACHMENT_STORE_OP_VALUE(DONT_CARE) +#elifdef STORMKIT_GPU_WGPU + #define STORE + #define DONT_CARE +#endif + enum class AttachmentStoreOperation : UInt8 { + STORE, + DONT_CARE, + }; +#undef STORE +#undef DONT_CARE + +#ifdef STORMKIT_GPU_VULKAN + #define GRAPHICS PIPELINE_BIND_POINT_VALUE(GRAPHICS) + #define COMPUTE PIPELINE_BIND_POINT_VALUE(COMPUTE) +#elifdef STORMKIT_GPU_WGPU + #define GRAPHICS + #define COMPUTE +#endif + enum class PipelineBindPoint : UInt8 { + GRAPHICS, + COMPUTE, + }; +#undef GRAPHICS +#undef COMPUTE + +#ifdef STORMKIT_GPU_VULKAN + #define UNDEFINED IMAGE_LAYOUT_VALUE(UNDEFINED) + #define GENERAL IMAGE_LAYOUT_VALUE(GENERAL) + #define COLOR_ATTACHMENT_OPTIMAL IMAGE_LAYOUT_VALUE(COLOR_ATTACHMENT_OPTIMAL) + #define DEPTH_STENCIL_ATTACHMENT_OPTIOMAL IMAGE_LAYOUT_VALUE(DEPTH_STENCIL_ATTACHMENT_OPTIOMAL) + #define DEPTH_STENCIL_READ_ONLY_OPTIMAL IMAGE_LAYOUT_VALUE(DEPTH_STENCIL_READ_ONLY_OPTIMAL) + #define SHADER_READ_ONLY_OPTIMAL IMAGE_LAYOUT_VALUE(SHADER_READ_ONLY_OPTIMAL) + #define TRANSFER_SRC_OPTIMAL IMAGE_LAYOUT_VALUE(TRANSFER_SRC_OPTIMAL) + #define TRANSFER_DST_OPTIMAL IMAGE_LAYOUT_VALUE(TRANSFER_DST_OPTIMAL) + #define PREINITIALIZED IMAGE_LAYOUT_VALUE(PREINITIALIZED) + #define DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL \ + IMAGE_LAYOUT_VALUE(DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL) + #define DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL \ + IMAGE_LAYOUT_VALUE(DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL) + #define PRESENT_SRC IMAGE_LAYOUT_VALUE_KHR(PRESENT_SRC) + #define SHARED_PRESENT IMAGE_LAYOUT_VALUE_KHR(SHARED_PRESENT) +#elifdef STORMKIT_GPU_WGPU + #define UNDEFINED + #define GENERAL + #define COLOR_ATTACHMENT_OPTIMAL + #define DEPTH_STENCIL_ATTACHMENT_OPTIOMAL + #define DEPTH_STENCIL_READ_ONLY_OPTIMAL + #define SHADER_READ_ONLY_OPTIMAL + #define TRANSFER_SRC_OPTIMAL + #define TRANSFER_DST_OPTIMAL + #define PREINITIALIZED + #define DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL + #define DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL + #define PRESENT_SRC + #define SHARED_PRESENT +#endif + enum class ImageLayout : UInt32 { + UNDEFINED, + GENERAL, + COLOR_ATTACHMENT_OPTIMAL, + DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + DEPTH_STENCIL_READ_ONLY_OPTIMAL, + SHADER_READ_ONLY_OPTIMAL, + TRANSFER_SRC_OPTIMAL, + TRANSFER_DST_OPTIMAL, + PREINITIALIZED, + DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, + DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, + PRESENT_SRC, + SHARED_PRESENT, + }; +#undef UNDEFINED +#undef GENERAL +#undef COLOR_ATTACHMENT_OPTIMAL +#undef DEPTH_STENCIL_ATTACHMENT_OPTIOMAL +#undef DEPTH_STENCIL_READ_ONLY_OPTIMAL +#undef SHADER_READ_ONLY_OPTIMAL +#undef TRANSFER_SRC_OPTIMAL +#undef TRANSFER_DST_OPTIMAL +#undef PREINITIALIZED +#undef DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL +#undef DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL +#undef PRESENT_SRC +#undef SHARED_PRESENT + +#ifdef STORMKIT_GPU_VULKAN + #define COLOR IMAGE_ASPECT_MASK_VALUE(COLOR) + #define DEPTH IMAGE_ASPECT_MASK_VALUE(DEPTH) + #define STENCIL IMAGE_ASPECT_MASK_VALUE(STENCIL) +#elifdef STORMKIT_GPU_WGPU + #define COLOR + #define DEPTH + #define STENCIL +#endif + enum class ImageAspectMaskFlag : UInt8 { + NONE = 0, + COLOR, + DEPTH, + STENCIL, + }; +#undef COLOR +#undef DEPTH +#undef STENCIL + +#ifdef STORMKIT_GPU_VULKAN + #define VERTEX VERTEX_INPUT_RATE_VALUE(VERTEX) + #define INSTANCE VERTEX_INPUT_RATE_VALUE(INSTANCE) +#elifdef STORMKIT_GPU_WGPU + #define VERTEX + #define INSTANCE +#endif + enum class VertexInputRate : UInt8 { + VERTEX, + INSTANCE, + }; +#undef VERTEX +#undef INSTANCE + +#ifdef STORMKIT_GPU_VULKAN + #define SPARSE_BINDING IMAGE_CREATE_VALUE(SPARSE_BINDING) + #define SPARSE_RESIDENCY IMAGE_CREATE_VALUE(SPARSE_RESIDENCY) + #define SPARSE_ALIASED IMAGE_CREATE_VALUE(SPARSE_ALIASED) + #define MUTABLE_FORMAT IMAGE_CREATE_VALUE(MUTABLE_FORMAT) + #define CUBE_COMPATIBLE IMAGE_CREATE_VALUE(CUBE_COMPATIBLE) + #define ALIAS IMAGE_CREATE_VALUE(ALIAS) + #define SPLIT_INSTANCE_BIND_REGIONS IMAGE_CREATE_VALUE(SPLIT_INSTANCE_BIND_REGIONS) + #define ARRAY_2D_COMPATIBLE ARRAY_2D_COMPATIBLE = VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT + #define BLOCK_TEXEL_VIEW_COMPATIBLE IMAGE_CREATE_VALUE(BLOCK_TEXEL_VIEW_COMPATIBLE) + #define EXTENDED_USAGE IMAGE_CREATE_VALUE(EXTENDED_USAGE) + #define PRETECTED IMAGE_CREATE_VALUE(PRETECTED) + #define DISJOINT IMAGE_CREATE_VALUE(DISJOINT) +#elifdef STORMKIT_GPU_WGPU + #define SPARSE_BINDING + #define SPARSE_RESIDENCY + #define SPARSE_ALIASED + #define MUTABLE_FORMAT + #define CUBE_COMPATIBLE + #define ALIAS + #define SPLIT_INSTANCE_BIND_REGIONS + #define ARRAY_2D_COMPATIBLE + #define BLOCK_TEXEL_VIEW_COMPATIBLE + #define EXTENDED_USAGE + #define PRETECTED + #define DISJOINT +#endif + enum class ImageCreateFlag : UInt16 { + NONE = 0, + SPARSE_BINDING, + SPARSE_RESIDENCY, + SPARSE_ALIASED, + MUTABLE_FORMAT, + CUBE_COMPATIBLE, + ALIAS, + SPLIT_INSTANCE_BIND_REGIONS, + ARRAY_2D_COMPATIBLE, + BLOCK_TEXEL_VIEW_COMPATIBLE, + EXTENDED_USAGE, + PROTECTED, + DISJOINT, + }; +#undef SPARSE_BINDING +#undef SPARSE_RESIDENCY +#undef SPARSE_ALIASED +#undef MUTABLE_FORMAT +#undef CUBE_COMPATIBLE +#undef ALIAS +#undef SPLIT_INSTANCE_BIND_REGIONS +#undef ARRAY_2D_COMPATIBLE +#undef BLOCK_TEXEL_VIEW_COMPATIBLE +#undef EXTENDED_USAGE +#undef PRETECTED +#undef DISJOINT + + // enum class Format : UInt8 { + // 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, + // }; + +#ifdef STORMKIT_GPU_VULKAN + #define VERTEX BUFFER_USAGE_VALUE(VERTEX) + #define INDEX BUFFER_USAGE_VALUE(INDEX) + #define TRANSFER_SRC BUFFER_USAGE_VALUE2(TRANSFER_SRC) + #define TRANFERT_DST BUFFER_USAGE_VALUE2(TRANFERT_DST) + #define UNIFORM BUFFER_USAGE_VALUE(UNIFORM) + #define STORAGE BUFFER_USAGE_VALUE(STORAGE) + #define UNIFORM_TEXEL BUFFER_USAGE_VALUE(UNIFORM_TEXEL) + #define STORAGE_TEXEL BUFFER_USAGE_VALUE(STORAGE_TEXEL) + #define INDIRECT BUFFER_USAGE_VALUE(INDIRECT) +#elifdef STORMKIT_GPU_WGPU + #define VERTEX + #define INDEX + #define TRANSFER_SRC + #define TRANFERT_DST + #define UNIFORM + #define STORAGE + #define UNIFORM_TEXEL + #define STORAGE_TEXEL + #define INDIRECT +#endif + enum class BufferUsageFlag : UInt16 { + VERTEX, + INDEX, + TRANSFER_SRC, + TRANSFER_DST, + UNIFORM, + STORAGE, + UNIFORM_TEXEL, + STORAGE_TEXEL, + INDIRECT, + }; +#undef VERTEX +#undef INDEX +#undef TRANSFER_SRC +#undef TRANFERT_DST +#undef UNIFORM +#undef STORAGE +#undef UNIFORM_TEXEL +#undef STORAGE_TEXEL +#undef INDIRECT + +#ifdef STORMKIT_GPU_VULKAN + #define TRANSFER_SRC IMAGE_USAGE_VALUE(TRANSFER_SRC) + #define TRANSFER_DST IMAGE_USAGE_VALUE(TRANSFER_DST) + #define SAMPLED IMAGE_USAGE_VALUE(SAMPLED) + #define STORAGE IMAGE_USAGE_VALUE(STORAGE) + #define COLOR_ATTACHMENT IMAGE_USAGE_VALUE(COLOR_ATTACHMENT) + #define DEPTH_STENCIL_ATTACHMENT IMAGE_USAGE_VALUE(DEPTH_STENCIL_ATTACHMENT) + #define TRANSIENT_ATTACHMENT IMAGE_USAGE_VALUE(TRANSIENT_ATTACHMENT) + #define INPUT_ATTACHMENT IMAGE_USAGE_VALUE(INPUT_ATTACHMENT) +#elifdef STORMKIT_GPU_WGPU + #define TRANSFER_SRC + #define TRANSFER_DST + #define SAMPLED + #define STORAGE + #define COLOR_ATTACHMENT + #define DEPTH_STENCIL_ATTACHMENT + #define TRANSIENT_ATTACHMENT + #define INPUT_ATTACHMENT +#endif + enum class ImageUsageFlag : UInt16 { + TRANSFER_SRC, + TRANSFER_DST, + SAMPLED, + STORAGE, + COLOR_ATTACHMENT, + DEPTH_STENCIL_ATTACHMENT, + TRANSIENT_ATTACHMENT, + INPUT_ATTACHMENT, + }; +#undef TRANSFER_SRC +#undef TRANSFER_DST +#undef SAMPLED +#undef STORAGE +#undef COLOR_ATTACHMENT +#undef DEPTH_STENCIL_ATTACHMENT +#undef TRANSIENT_ATTACHMENT +#undef INPUT_ATTACHMENT + +#ifdef STORMKIT_GPU_VULKAN + #define DEVICE_LOCAL MEMORY_PROPERTY_VALUE(DEVICE_LOCAL) + #define HOST_VISIBLE MEMORY_PROPERTY_VALUE(HOST_VISIBLE) + #define HOST_COHERENT MEMORY_PROPERTY_VALUE(HOST_COHERENT) + #define HOST_CACHED MEMORY_PROPERTY_VALUE(HOST_CACHED) +#elifdef STORMKIT_GPU_WGPU + #define DEVICE_LOCAL + #define HOST_VISIBLE + #define HOST_COHERENT + #define HOST_CACHED +#endif + enum class MemoryPropertyFlag : UInt8 { + DEVICE_LOCAL, + HOST_VISIBLE, + HOST_COHERENT, + HOST_CACHED, + }; +#undef DEVICE_LOCAL +#undef HOST_VISIBLE +#undef HOST_COHERENT +#undef HOST_CACHED + +#ifdef STORMKIT_GPU_VULKAN + #define PRIMARY COMMAND_BUFFER_LEVEL_VALUE(PRIMARY) + #define SECONDARY COMMAND_BUFFER_LEVEL_VALUE(SECONDARY) +#elifdef STORMKIT_GPU_WGPU + #define PRIMARY + #define SECONDARY +#endif + enum class CommandBufferLevel : UInt8 { + PRIMARY, + SECONDARY, + }; +#undef PRIMARY +#undef SECONDARY + +#ifdef STORMKIT_GPU_VULKAN + #define SAMPLER DESCRIPTOR_TYPE_VALUE(SAMPLER) + #define COMBINED_IMAGE_SAMPLER DESCRIPTOR_TYPE_VALUE(COMBINED_IMAGE_SAMPLER) + #define SAMPLED_IMAGE DESCRIPTOR_TYPE_VALUE(SAMPLED_IMAGE) + #define STORAGE_IMAGE DESCRIPTOR_TYPE_VALUE(STORAGE_IMAGE) + #define UNIFORM_TEXEL_BUFFER DESCRIPTOR_TYPE_VALUE(UNIFORM_TEXEL_BUFFER) + #define STORAGE_TEXEL_BUFFER DESCRIPTOR_TYPE_VALUE(STORAGE_TEXEL_BUFFER) + #define UNIFORM_BUFFER DESCRIPTOR_TYPE_VALUE(UNIFORM_BUFFER) + #define STORAGE_BUFFER DESCRIPTOR_TYPE_VALUE(STORAGE_BUFFER) + #define UNIFORM_BUFFER_DYNAMIC DESCRIPTOR_TYPE_VALUE(UNIFORM_BUFFER_DYNAMIC) + #define STORAGE_BUFFER_DYNAMIC DESCRIPTOR_TYPE_VALUE(STORAGE_BUFFER_DYNAMIC) + #define INPUT_ATTACHMENT DESCRIPTOR_TYPE_VALUE(INPUT_ATTACHMENT) +#elifdef STORMKIT_GPU_WGPU + #define SAMPLER + #define COMBINED_IMAGE_SAMPLER + #define SAMPLED_IMAGE + #define STORAGE_IMAGE + #define UNIFORM_TEXEL_BUFFER + #define STORAGE_TEXEL_BUFFER + #define UNIFORM_BUFFER + #define STORAGE_BUFFER + #define UNIFORM_BUFFER_DYNAMIC + #define STORAGE_BUFFER_DYNAMIC + #define INPUT_ATTACHMENT +#endif + enum class DescriptorType : UInt8 { + SAMPLER, + COMBINED_IMAGE_SAMPLER, + SAMPLED_IMAGE, + STORAGE_IMAGE, + UNIFORM_TEXEL_BUFFER, + STORAGE_TEXEL_BUFFER, + UNIFORM_BUFFER, + STORAGE_BUFFER, + UNIFORM_BUFFER_DYNAMIC, + STORAGE_BUFFER_DYNAMIC, + INPUT_ATTACHMENT, + }; +#undef SAMPLER +#undef COMBINED_IMAGE_SAMPLER +#undef SAMPLED_IMAGE +#undef STORAGE_IMAGE +#undef UNIFORM_TEXEL_BUFFER +#undef STORAGE_TEXEL_BUFFER +#undef UNIFORM_BUFFER +#undef STORAGE_BUFFER +#undef UNIFORM_BUFFER_DYNAMIC +#undef STORAGE_BUFFER_DYNAMIC +#undef INPUT_ATTACHMENT + +#ifdef STORMKIT_GPU_VULKAN + #define NEVER COMPARE_OP_VALUE(NEVER) + #define LESS COMPARE_OP_VALUE(LESS) + #define EQUAL COMPARE_OP_VALUE(EQUAL) + #define LESS_OR_EQUAL COMPARE_OP_VALUE(LESS_OR_EQUAL) + #define GREATER COMPARE_OP_VALUE(GREATER) + #define NOT_EQUAL COMPARE_OP_VALUE(NOT_EQUAL) + #define GREATER_OR_EQUAL COMPARE_OP_VALUE(GREATER_OR_EQUAL) + #define ALWAYS COMPARE_OP_VALUE(ALWAYS) +#elifdef STORMKIT_GPU_WGPU + #define NEVER + #define LESS + #define EQUAL + #define LESS_OR_EQUAL + #define GREATER + #define NOT_EQUAL + #define GREATER_OR_EQUAL + #define ALWAYS + +#endif + enum class CompareOperation : UInt8 { + NEVER, + LESS, + EQUAL, + LESS_OR_EQUAL, + GREATER, + NOT_EQUAL, + GREATER_OR_EQUAL, + ALWAYS, + }; +#undef NEVER +#undef LESS +#undef EQUAL +#undef LESS_OR_EQUAL +#undef GREATER +#undef NOT_EQUAL +#undef GREATER_OR_EQUAL +#undef ALWAYS + +#ifdef STORMKIT_GPU_VULKAN + #define NEAREST FILTER_VALUE(NEAREST) + #define LINEAR FILTER_VALUE(LINEAR) + #define CUBIC_IMG FILTER_VALUE(CUBIC_IMG) +#elifdef STORMKIT_GPU_WGPU + #define NEAREST + #define LINEAR + #define CUBIC_IMG +#endif + enum class Filter : UInt32 { + NEAREST, + LINEAR, + CUBIC_IMG, + }; +#undef NEAREST +#undef LINEAR +#undef CUBIC_IMG + +#ifdef STORMKIT_GPU_VULKAN + #define REPEAT SAMPLER_ADDRESS_MODE_VALUE(REPEAT) + #define MIRRORED_REPEAT SAMPLER_ADDRESS_MODE_VALUE(MIRRORED_REPEAT) + #define CLAMP_TO_EDGE SAMPLER_ADDRESS_MODE_VALUE(CLAMP_TO_EDGE) + #define CLAMP_TO_BORDER SAMPLER_ADDRESS_MODE_VALUE(CLAMP_TO_BORDER) + #define MIRROR_CLAMP_TO_EDGE SAMPLER_ADDRESS_MODE_VALUE(MIRROR_CLAMP_TO_EDGE) +#elifdef STORMKIT_GPU_WGPU + #define REPEAT + #define MIRRORED_REPEAT + #define CLAMP_TO_EDGE + #define CLAMP_TO_BORDER + #define MIRROR_CLAMP_TO_EDGE +#endif + enum class SamplerAddressMode : UInt8 { + REPEAT, + MIRRORED_REPEAT, + CLAMP_TO_EDGE, + CLAMP_TO_BORDER, + MIRROR_CLAMP_TO_EDGE, + }; +#undef REPEAT +#undef MIRRORED_REPEAT +#undef CLAMP_TO_EDGE +#undef CLAMP_TO_BORDER +#undef MIRROR_CLAMP_TO_EDGE + +#ifdef STORMKIT_GPU_VULKAN + #define FLOAT_TRANSPARENT_BLACK BORDER_COLOR_VALUE(FLOAT_TRANSPARENT_BLACK) + #define INT_TRANSPARENT_BLACK BORDER_COLOR_VALUE(INT_TRANSPARENT_BLACK) + #define FLOAT_OPAQUE_BLACK BORDER_COLOR_VALUE(FLOAT_OPAQUE_BLACK) + #define INT_OPAQUE_BLACK BORDER_COLOR_VALUE(INT_OPAQUE_BLACK) + #define FLOAT_OPAQUE_WHITE BORDER_COLOR_VALUE(FLOAT_OPAQUE_WHITE) + #define INT_OPAQUE_WHITE BORDER_COLOR_VALUE(INT_OPAQUE_WHITE) +#elifdef STORMKIT_GPU_WGPU + #define FLOAT_TRANSPARENT_BLACK + #define INT_TRANSPARENT_BLACK + #define FLOAT_OPAQUE_BLACK + #define INT_OPAQUE_BLACK + #define FLOAT_OPAQUE_WHITE + #define INT_OPAQUE_WHITE +#endif + enum class BorderColor : UInt8 { + FLOAT_TRANSPARENT_BLACK, + INT_TRANSPARENT_BLACK, + FLOAT_OPAQUE_BLACK, + INT_OPAQUE_BLACK, + FLOAT_OPAQUE_WHITE, + INT_OPAQUE_WHITE, + }; +#undef FLOAT_TRANSPARENT_BLACK +#undef INT_TRANSPARENT_BLACK +#undef FLOAT_OPAQUE_BLACK +#undef INT_OPAQUE_BLACK +#undef FLOAT_OPAQUE_WHITE +#undef INT_OPAQUE_WHITE + +#ifdef STORMKIT_GPU_VULKAN + #define NEAREST SAMPLER_MIPMAP_MODE_VALUE(NEAREST) + #define LINEAR SAMPLER_MIPMAP_MODE_VALUE(LINEAR) +#elifdef STORMKIT_GPU_WGPU + #define NEAREST + #define LINEAR +#endif + enum class SamplerMipmapMode : UInt8 { + NEAREST, + LINEAR, + }; +#undef NEAREST +#undef LINEAR + +#ifdef STORMKIT_GPU_VULKAN + #define SUCCESS RESULT_VALUE(SUCCESS) + #define NOT_READY RESULT_VALUE(NOT_READY) + #define TIMEOUT RESULT_VALUE(TIMEOUT) + #define EVENT_SET RESULT_VALUE(EVENT_SET) + #define EVENT_RESET RESULT_VALUE(EVENT_RESET) + #define INCOMPLETE RESULT_VALUE(INCOMPLETE) + #define ERROR_OUT_OF_HOST_MEMORY RESULT_VALUE(ERROR_OUT_OF_HOST_MEMORY) + #define ERROR_OUT_OF_DEVICE_MEMORY RESULT_VALUE(ERROR_OUT_OF_DEVICE_MEMORY) + #define ERROR_INITIALIZATION_FAILED RESULT_VALUE(ERROR_INITIALIZATION_FAILED) + #define ERROR_DEVICE_LOST RESULT_VALUE(ERROR_DEVICE_LOST) + #define ERROR_MEMORY_MAP_FAILED RESULT_VALUE(ERROR_MEMORY_MAP_FAILED) + #define ERROR_LAYER_NOT_PRESENT RESULT_VALUE(ERROR_LAYER_NOT_PRESENT) + #define ERROR_EXTENSION_NOT_PRESENT RESULT_VALUE(ERROR_EXTENSION_NOT_PRESENT) + #define ERROR_FEATURE_NOT_PRESENT RESULT_VALUE(ERROR_FEATURE_NOT_PRESENT) + #define ERROR_INCOMPATIBLE_DRIVER RESULT_VALUE(ERROR_INCOMPATIBLE_DRIVER) + #define ERROR_TOO_MANY_OBJECTS RESULT_VALUE(ERROR_TOO_MANY_OBJECTS) + #define ERROR_FORMAT_NOT_SUPPORTED RESULT_VALUE(ERROR_FORMAT_NOT_SUPPORTED) + #define ERROR_FRAGMENTED_POOL RESULT_VALUE(ERROR_FRAGMENTED_POOL) + #define ERROR_UNKNOWN RESULT_VALUE(ERROR_UNKNOWN) + #define ERROR_OUT_OF_POOL_MEMORY RESULT_VALUE(ERROR_OUT_OF_POOL_MEMORY) + #define ERROR_INVALID_EXTERNAL_HANDLE RESULT_VALUE(ERROR_INVALID_EXTERNAL_HANDLE) + #define ERROR_FRAGMENTATION RESULT_VALUE(ERROR_FRAGMENTATION) + #define ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS RESULT_VALUE(ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS) + #define ERROR_SURFACE_LOST RESULT_VALUE_KHR(ERROR_SURFACE_LOST) + #define ERROR_NATIVE_WINDOW_IN_USE RESULT_VALUE_KHR(ERROR_NATIVE_WINDOW_IN_USE) + #define SUBOPTIMAL RESULT_VALUE_KHR(SUBOPTIMAL) + #define ERROR_OUT_OF_DATE RESULT_VALUE_KHR(ERROR_OUT_OF_DATE) + #define ERROR_INCOMPATIBLE_DISPLAY RESULT_VALUE_KHR(ERROR_INCOMPATIBLE_DISPLAY) + #define ERROR_VALIDATION_FAILED RESULT_VALUE_EXT(ERROR_VALIDATION_FAILED) + #define ERROR_NOT_PERMITTED RESULT_VALUE(ERROR_NOT_PERMITTED) + #define ERROR_FULLSCREEN_EXCLUSIVE_MODE_LOST \ + ERROR_FULLSCREEN_EXCLUSIVE_MODE_LOST = VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT + #define THREAD_IDLE RESULT_VALUE_KHR(THREAD_IDLE) + #define THREAD_DONE RESULT_VALUE_KHR(THREAD_DONE) + #define OPERATION_DEFERRED RESULT_VALUE_KHR(OPERATION_DEFERRED) + #define OPERATION_NOT_DEFERRED RESULT_VALUE_KHR(OPERATION_NOT_DEFERRED) + #define PIPELINE_COMPILE_REQUIRED RESULT_VALUE(PIPELINE_COMPILE_REQUIRED) +#elifdef STORMKIT_GPU_WGPU + #define SUCCESS + #define NOT_READY + #define TIMEOUT + #define EVENT_SET + #define EVENT_RESET + #define INCOMPLETE + #define ERROR_OUT_OF_HOST_MEMORY + #define ERROR_OUT_OF_DEVICE_MEMORY + #define ERROR_INITIALIZATION_FAILED + #define ERROR_DEVICE_LOST + #define ERROR_MEMORY_MAP_FAILED + #define ERROR_LAYER_NOT_PRESENT + #define ERROR_EXTENSION_NOT_PRESENT + #define ERROR_FEATURE_NOT_PRESENT + #define ERROR_INCOMPATIBLE_DRIVER + #define ERROR_TOO_MANY_OBJECTS + #define ERROR_FORMAT_NOT_SUPPORTED + #define ERROR_FRAGMENTED_POOL + #define ERROR_UNKNOWN + #define ERROR_OUT_OF_POOL_MEMORY + #define ERROR_INVALID_EXTERNAL_HANDLE + #define ERROR_FRAGMENTATION + #define ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS + #define ERROR_SURFACE_LOST + #define ERROR_NATIVE_WINDOW_IN_USE + #define SUBOPTIMAL + #define ERROR_OUT_OF_DATE + #define ERROR_INCOMPATIBLE_DISPLAY + #define ERROR_VALIDATION_FAILED + #define ERROR_NOT_PERMITTED + #define ERROR_FULLSCREEN_EXCLUSIVE_MODE_LOST + #define THREAD_IDLE + #define THREAD_DONE + #define OPERATION_DEFERRED + #define OPERATION_NOT_DEFERRED + #define PIPELINE_COMPILE_REQUIRED +#endif + enum class Result : Int32 { + SUCCESS, + NOT_READY, + TIMEOUT, + EVENT_SET, + EVENT_RESET, + INCOMPLETE, + ERROR_OUT_OF_HOST_MEMORY, + ERROR_OUT_OF_DEVICE_MEMORY, + ERROR_INITIALIZATION_FAILED, + ERROR_DEVICE_LOST, + ERROR_MEMORY_MAP_FAILED, + ERROR_LAYER_NOT_PRESENT, + ERROR_EXTENSION_NOT_PRESENT, + ERROR_FEATURE_NOT_PRESENT, + ERROR_INCOMPATIBLE_DRIVER, + ERROR_TOO_MANY_OBJECTS, + ERROR_FORMAT_NOT_SUPPORTED, + ERROR_FRAGMENTED_POOL, + ERROR_UNKNOWN, + ERROR_OUT_OF_POOL_MEMORY, + ERROR_INVALID_EXTERNAL_HANDLE, + ERROR_FRAGMENTATION, + ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS, + ERROR_SURFACE_LOST, + ERROR_NATIVE_WINDOW_IN_USE, + SUBOPTIMAL, + ERROR_OUT_OF_DATE, + ERROR_INCOMPATIBLE_DISPLAY, + ERROR_VALIDATION_FAILED, + ERROR_NOT_PERMITTED, + ERROR_FULLSCREEN_EXCLUSIVE_MODE_LOST, + THREAD_IDLE, + THREAD_DONE, + OPERATION_DEFERRED, + OPERATION_NOT_DEFERRED, + PIPELINE_COMPILE_REQUIRED, + }; +#undef SUCCESS +#undef NOT_READY +#undef TIMEOUT +#undef EVENT_SET +#undef EVENT_RESET +#undef INCOMPLETE +#undef ERROR_OUT_OF_HOST_MEMORY +#undef ERROR_OUT_OF_DEVICE_MEMORY +#undef ERROR_INITIALIZATION_FAILED +#undef ERROR_DEVICE_LOST +#undef ERROR_MEMORY_MAP_FAILED +#undef ERROR_LAYER_NOT_PRESENT +#undef ERROR_EXTENSION_NOT_PRESENT +#undef ERROR_FEATURE_NOT_PRESENT +#undef ERROR_INCOMPATIBLE_DRIVER +#undef ERROR_TOO_MANY_OBJECTS +#undef ERROR_FORMAT_NOT_SUPPORTED +#undef ERROR_FRAGMENTED_POOL +#undef ERROR_UNKNOWN +#undef ERROR_OUT_OF_POOL_MEMORY +#undef ERROR_INVALID_EXTERNAL_HANDLE +#undef ERROR_FRAGMENTATION +#undef ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS +#undef ERROR_SURFACE_LOST +#undef ERROR_NATIVE_WINDOW_IN_USE +#undef SUBOPTIMAL +#undef ERROR_OUT_OF_DATE +#undef ERROR_INCOMPATIBLE_DISPLAY +#undef ERROR_VALIDATION_FAILED +#undef ERROR_NOT_PERMITTED +#undef ERROR_FULLSCREEN_EXCLUSIVE_MODE_LOST +#undef THREAD_IDLE +#undef THREAD_DONE +#undef OPERATION_DEFERRED +#undef OPERATION_NOT_DEFERRED +#undef PIPELINE_COMPILE_REQUIRED + +#ifdef STORMKIT_GPU_VULKAN + #define T1D T1D = VK_IMAGE_TYPE_1D + #define T2D T2D = VK_IMAGE_TYPE_2D + #define T3D T3D = VK_IMAGE_TYPE_3D +#elifdef STORMKIT_GPU_WGPU + #define T1D + #define T2D + #define T3D +#endif + enum class ImageType : UInt8 { + T1D, + T2D, + T3D, + }; +#undef T1D +#undef T2D +#undef T3D + +#ifdef STORMKIT_GPU_VULKAN + #define T1D T1D = VK_IMAGE_VIEW_TYPE_1D + #define T2D T2D = VK_IMAGE_VIEW_TYPE_2D + #define T3D T3D = VK_IMAGE_VIEW_TYPE_3D + #define CUBE CUBE = VK_IMAGE_VIEW_TYPE_CUBE + #define T1D_ARRAY T1D_ARRAY = VK_IMAGE_VIEW_TYPE_1D_ARRAY + #define T2D_ARRAY T2D_ARRAY = VK_IMAGE_VIEW_TYPE_2D_ARRAY + #define CUBE_ARRAY CUBE_ARRAY = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY +#elifdef STORMKIT_GPU_WGPU + #define T1D + #define T2D + #define T3D + #define CUBE + #define T1D_ARRAY + #define T2D_ARRAY + #define CUBE_ARRAY +#endif + enum class ImageViewType : UInt8 { + T1D, + T2D, + T3D, + CUBE, + T1D_ARRAY, + T2D_ARRAY, + CUBE_ARRAY, + }; +#undef T1D +#undef T2D +#undef T3D +#undef CUBE +#undef T1D_ARRAY +#undef T2D_ARRAY +#undef CUBE_ARRAY + +#ifdef STORMKIT_GPU_VULKAN + #define UNKNOWN DEBUG_OBJECT_TYPE_VALUE(UNKNOWN) + #define INSTANCE DEBUG_OBJECT_TYPE_VALUE(INSTANCE) + #define PHYSICAL_DEVICE DEBUG_OBJECT_TYPE_VALUE(PHYSICAL_DEVICE) + #define DEVICE DEBUG_OBJECT_TYPE_VALUE(DEVICE) + #define QUEUE DEBUG_OBJECT_TYPE_VALUE(QUEUE) + #define SEMAPHORE DEBUG_OBJECT_TYPE_VALUE(SEMAPHORE) + #define COMMAND_BUFFER DEBUG_OBJECT_TYPE_VALUE(COMMAND_BUFFER) + #define FENCE DEBUG_OBJECT_TYPE_VALUE(FENCE) + #define DEVICE_MEMORY DEBUG_OBJECT_TYPE_VALUE(DEVICE_MEMORY) + #define BUFFER DEBUG_OBJECT_TYPE_VALUE(BUFFER) + #define IMAGE DEBUG_OBJECT_TYPE_VALUE(IMAGE) + #define EVENT DEBUG_OBJECT_TYPE_VALUE(EVENT) + #define QUERY_POOL DEBUG_OBJECT_TYPE_VALUE(QUERY_POOL) + #define BUFFER_VIEW DEBUG_OBJECT_TYPE_VALUE(BUFFER_VIEW) + #define IMAGE_VIEW DEBUG_OBJECT_TYPE_VALUE(IMAGE_VIEW) + #define SHADER_MODULE DEBUG_OBJECT_TYPE_VALUE(SHADER_MODULE) + #define PIPELINE_CACHE DEBUG_OBJECT_TYPE_VALUE(PIPELINE_CACHE) + #define PIPELINE_LAYOUT DEBUG_OBJECT_TYPE_VALUE(PIPELINE_LAYOUT) + #define RENDER_PASS DEBUG_OBJECT_TYPE_VALUE(RENDER_PASS) + #define PIPELINE DEBUG_OBJECT_TYPE_VALUE(PIPELINE) + #define DESCRIPTOR_SET_LAYOUT DEBUG_OBJECT_TYPE_VALUE(DESCRIPTOR_SET_LAYOUT) + #define SAMPLER DEBUG_OBJECT_TYPE_VALUE(SAMPLER) + #define DESCRIPTOR_POOL DEBUG_OBJECT_TYPE_VALUE(DESCRIPTOR_POOL) + #define DESCRIPTOR_SET DEBUG_OBJECT_TYPE_VALUE(DESCRIPTOR_SET) + #define FRAMEBUFFER DEBUG_OBJECT_TYPE_VALUE(FRAMEBUFFER) + #define COMMAND_POOL DEBUG_OBJECT_TYPE_VALUE(COMMAND_POOL) + #define SURFACE DEBUG_OBJECT_TYPE_VALUE_KHR(SURFACE) + #define SWAPCHAIN DEBUG_OBJECT_TYPE_VALUE_KHR(SWAPCHAIN) + #define DEBUG_REPORT_CALLBACK DEBUG_OBJECT_TYPE_VALUE_EXT(DEBUG_REPORT_CALLBACK) + #define DISPLAY DEBUG_OBJECT_TYPE_VALUE_KHR(DISPLAY) +#elifdef STORMKIT_GPU_WGPU + #define UNKNOWN + #define INSTANCE + #define PHYSICAL_DEVICE + #define DEVICE + #define QUEUE + #define SEMAPHORE + #define COMMAND_BUFFER + #define FENCE + #define DEVICE_MEMORY + #define BUFFER + #define IMAGE + #define EVENT + #define QUERY_POOL + #define BUFFER_VIEW + #define IMAGE_VIEW + #define SHADER_MODULE + #define PIPELINE_CACHE + #define PIPELINE_LAYOUT + #define RENDER_PASS + #define PIPELINE + #define DESCRIPTOR_SET_LAYOUT + #define SAMPLER + #define DESCRIPTOR_POOL + #define DESCRIPTOR_SET + #define FRAMEBUFFER + #define COMMAND_POOL + #define SURFACE + #define SWAPCHAIN + #define DEBUG_REPORT_CALLBACK + #define DISPLAY_KHR +#endif + enum class DebugObjectType : UInt32 { + UNKNOWN, + INSTANCE, + PHYSICAL_DEVICE, + DEVICE, + QUEUE, + SEMAPHORE, + COMMAND_BUFFER, + FENCE, + DEVICE_MEMORY, + BUFFER, + IMAGE, + EVENT, + QUERY_POOL, + BUFFER_VIEW, + IMAGE_VIEW, + SHADER_MODULE, + PIPELINE_CACHE, + PIPELINE_LAYOUT, + RENDER_PASS, + PIPELINE, + DESCRIPTOR_SET_LAYOUT, + SAMPLER, + DESCRIPTOR_POOL, + DESCRIPTOR_SET, + FRAMEBUFFER, + COMMAND_POOL, + SURFACE, + SWAPCHAIN, + DEBUG_REPORT_CALLBACK, + DISPLAY, + }; +#undef UNKNOWN +#undef INSTANCE +#undef PHYSICAL_DEVICE +#undef DEVICE +#undef QUEUE +#undef SEMAPHORE +#undef COMMAND_BUFFER +#undef FENCE +#undef DEVICE_MEMORY +#undef BUFFER +#undef IMAGE +#undef EVENT +#undef QUERY_POOL +#undef BUFFER_VIEW +#undef IMAGE_VIEW +#undef SHADER_MODULE +#undef PIPELINE_CACHE +#undef PIPELINE_LAYOUT +#undef RENDER_PASS +#undef PIPELINE +#undef PIPELINELAYOUT +#undef DESCRIPTOR_SET_LAYOUT +#undef SAMPLER +#undef DESCRIPTOR_POOL +#undef DESCRIPTOR_SET +#undef FRAMEBUFFER +#undef COMMAND_POOL +#undef SURFACE +#undef SWAPCHAIN +#undef DEBUG_REPORT_CALLBACK +#undef DISPLAY_KHR + +#ifdef STORMKIT_GPU_VULKAN + #define INDIRECT_COMMAND_READ ACCESS_FLAG_VALUE(INDIRECT_COMMAND_READ) + #define VERTEX_ATTRIBUTE_READ ACCESS_FLAG_VALUE(VERTEX_ATTRIBUTE_READ) + #define UNIFORM_READ ACCESS_FLAG_VALUE(UNIFORM_READ) + #define INPUT_ATTACHMENT_READ ACCESS_FLAG_VALUE(INPUT_ATTACHMENT_READ) + #define SHADER_READ ACCESS_FLAG_VALUE(SHADER_READ) + #define SHADER_WRITE ACCESS_FLAG_VALUE(SHADER_WRITE) + #define COLOR_ATTACHMENT_READ ACCESS_FLAG_VALUE(COLOR_ATTACHMENT_READ) + #define COLOR_ATTACHMENT_WRITE ACCESS_FLAG_VALUE(COLOR_ATTACHMENT_WRITE) + #define DEPTH_STENCIL_ATTACHMENT_READ ACCESS_FLAG_VALUE(DEPTH_STENCIL_ATTACHMENT_READ) + #define DEPTH_STENCIL_ATTACHMENT_WRITE ACCESS_FLAG_VALUE(DEPTH_STENCIL_ATTACHMENT_WRITE) + #define TRANSFER_READ ACCESS_FLAG_VALUE(TRANSFER_READ) + #define TRANSFER_WRITE ACCESS_FLAG_VALUE(TRANSFER_WRITE) + #define HOST_READ ACCESS_FLAG_VALUE(HOST_READ) + #define HOST_WRITE ACCESS_FLAG_VALUE(HOST_WRITE) + #define MEMORY_READ ACCESS_FLAG_VALUE(MEMORY_READ) + #define MEMORY_WRITE ACCESS_FLAG_VALUE(MEMORY_WRITE) +#elifdef STORMKIT_GPU_WGPU + #define INDIRECT_COMMAND_READ + #define VERTEX_ATTRIBUTE_READ + #define UNIFORM_READ + #define INPUT_ATTACHMENT_READ + #define SHADER_READ + #define SHADER_WRITE + #define COLOR_ATTACHMENT_READ + #define COLOR_ATTACHMENT_WRITE + #define DEPTH_STENCIL_ATTACHMENT_READ + #define DEPTH_STENCIL_ATTACHMENT_WRITE + #define TRANSFER_READ + #define TRANSFER_WRITE + #define HOST_READ + #define HOST_WRITE + #define MEMORY_READ + #define MEMORY_WRITE +#endif + enum class AccessFlag : UInt32 { + NONE = 0, + INDIRECT_COMMAND_READ, + VERTEX_ATTRIBUTE_READ, + UNIFORM_READ, + INPUT_ATTACHMENT_READ, + SHADER_READ, + SHADER_WRITE, + COLOR_ATTACHMENT_READ, + COLOR_ATTACHMENT_WRITE, + DEPTH_STENCIL_ATTACHMENT_READ, + DEPTH_STENCIL_ATTACHMENT_WRITE, + TRANSFER_READ, + TRANSFER_WRITE, + HOST_READ, + HOST_WRITE, + MEMORY_READ, + MEMORY_WRITE, + }; +#undef INDIRECT_COMMAND_READ +#undef VERTEX_ATTRIBUTE_READ +#undef UNIFORM_READ +#undef INPUT_ATTACHMENT_READ +#undef SHADER_READ +#undef SHADER_WRITE +#undef COLOR_ATTACHMENT_READ +#undef COLOR_ATTACHMENT_WRITE +#undef DEPTH_STENCIL_ATTACHMENT_READ +#undef DEPTH_STENCIL_ATTACHMENT_WRITE +#undef TRANSFER_READ +#undef TRANSFER_WRITE +#undef HOST_READ +#undef HOST_WRITE +#undef MEMORY_READ +#undef MEMORY_WRITE + +#ifdef STORMKIT_GPU_VULKAN + #define TOP_OF_PIPE PIPELINE_STAGE_VALUE(TOP_OF_PIPE) + #define DRAW_INDIRECT PIPELINE_STAGE_VALUE(DRAW_INDIRECT) + #define VERTEX_INPUT PIPELINE_STAGE_VALUE(VERTEX_INPUT) + #define VERTEX_SHADER PIPELINE_STAGE_VALUE(VERTEX_SHADER) + #define TESSELLATION_CONTROL_SHADER PIPELINE_STAGE_VALUE(TESSELLATION_CONTROL_SHADER) + #define TESSELLATION_EVALUATION_SHADER PIPELINE_STAGE_VALUE(TESSELLATION_EVALUATION_SHADER) + #define GEOMETRY_SHADER PIPELINE_STAGE_VALUE(GEOMETRY_SHADER) + #define FRAGMENT_SHADER PIPELINE_STAGE_VALUE(FRAGMENT_SHADER) + #define EARLY_FRAGMENT_TESTS PIPELINE_STAGE_VALUE(EARLY_FRAGMENT_TESTS) + #define LATE_FRAGMENT_TESTS PIPELINE_STAGE_VALUE(LATE_FRAGMENT_TESTS) + #define COLOR_ATTACHMENT_OUTPUT PIPELINE_STAGE_VALUE(COLOR_ATTACHMENT_OUTPUT) + #define COMPUTE_SHADER PIPELINE_STAGE_VALUE(COMPUTE_SHADER) + #define TRANSFER PIPELINE_STAGE_VALUE(TRANSFER) + #define BOTTOM_OF_PIPE PIPELINE_STAGE_VALUE(BOTTOM_OF_PIPE) + #define HOST PIPELINE_STAGE_VALUE(HOST) + #define ALL_GRAPHICS PIPELINE_STAGE_VALUE(ALL_GRAPHICS) + #define ALL_COMMANDS PIPELINE_STAGE_VALUE(ALL_COMMANDS) +#elifdef STORMKIT_GPU_WGPU + #define TOP_OF_PIPE + #define DRAW_INDIRECT + #define VERTEX_INPUT + #define VERTEX_SHADER + #define TESSELLATION_CONTROL_SHADER + #define TESSELLATION_EVALUATION_SHADER + #define GEOMETRY_SHADER + #define FRAGMENT_SHADER + #define EARLY_FRAGMENT_TESTS + #define LATE_FRAGMENT_TESTS + #define COLOR_ATTACHMENT_OUTPUT + #define COMPUTE_SHADER + #define TRANSFER + #define BOTTOM_OF_PIPE + #define HOST + #define ALL_GRAPHICS + #define ALL_COMMANDS +#endif + enum class PipelineStageFlag : UInt32 { + NONE = 0, + TOP_OF_PIPE, + DRAW_INDIRECT, + VERTEX_INPUT, + VERTEX_SHADER, + TESSELLATION_CONTROL_SHADER, + TESSELLATION_EVALUATION_SHADER, + GEOMETRY_SHADER, + FRAGMENT_SHADER, + EARLY_FRAGMENT_TESTS, + LATE_FRAGMENT_TESTS, + COLOR_ATTACHMENT_OUTPUT, + COMPUTE_SHADER, + TRANSFER, + BOTTOM_OF_PIPE, + HOST, + ALL_GRAPHICS, + ALL_COMMANDS, + }; +#undef TOP_OF_PIPE +#undef DRAW_INDIRECT +#undef VERTEX_INPUT +#undef VERTEX_SHADER +#undef TESSELLATION_CONTROL_SHADER +#undef TESSELLATION_EVALUATION_SHADER +#undef GEOMETRY_SHADER +#undef FRAGMENT_SHADER +#undef EARLY_FRAGMENT_TESTS +#undef LATE_FRAGMENT_TESTS +#undef COLOR_ATTACHMENT_OUTPUT +#undef COMPUTE_SHADER +#undef TRANSFER +#undef BOTTOM_OF_PIPE +#undef HOST +#undef ALL_GRAPHICS +#undef ALL_COMMANDS + +#ifdef STORMKIT_GPU_VULKAN + #define BY_REGION DEPENDENCY_VALUE(BY_REGION) + #define DEVICE_GROUP DEPENDENCY_VALUE(DEVICE_GROUP) + #define VIEW_LOCAL DEPENDENCY_VALUE(VIEW_LOCAL) +#elifdef STORMKIT_GPU_WGPU + #define BY_REGION + #define DEVICE_GROUP + #define VIEW_LOCAL +#endif + enum class DependencyFlag : UInt8 { + NONE = 0, + BY_REGION, + DEVICE_GROUP, + VIEW_LOCAL, + }; +#undef BY_REGION +#undef DEVICE_GROUP +#undef VIEW_LOCAL + +#ifdef STORMKIT_GPU_VULKAN + #define VIEWPORT DYNAMIC_STATE_VALUE(VIEWPORT) + #define SCISSOR DYNAMIC_STATE_VALUE(SCISSOR) + #define LINE_WIDTH DYNAMIC_STATE_VALUE(LINE_WIDTH) + #define DEPTH_BIAS DYNAMIC_STATE_VALUE(DEPTH_BIAS) + #define BLEND_CONSTANTS DYNAMIC_STATE_VALUE(BLEND_CONSTANTS) + #define DEPTH_BOUNDS DYNAMIC_STATE_VALUE(DEPTH_BOUNDS) + #define STENCIL_COMPARE_MASK DYNAMIC_STATE_VALUE(STENCIL_COMPARE_MASK) + #define STENCIL_WRITE_MASK DYNAMIC_STATE_VALUE(STENCIL_WRITE_MASK) + #define STENCIL_REFERENCE DYNAMIC_STATE_VALUE(STENCIL_REFERENCE) +#elifdef STORMKIT_GPU_WGPU + #define VIEWPORT + #define SCISSOR + #define LINE_WIDTH + #define DEPTH_BIAS + #define BLEND_CONSTANTS + #define DEPTH_BOUNDS + #define STENCIL_COMPARE_MASK + #define STENCIL_WRITE_MASK + #define STENCIL_REFERENCE +#endif + enum class DynamicState : UInt8 { + VIEWPORT, + SCISSOR, + LINE_WIDTH, + DEPTH_BIAS, + BLEND_CONSTANTS, + DEPTH_BOUNDS, + STENCIL_COMPARE_MASK, + STENCIL_WRITE_MASK, + STENCIL_REFERENCE, + }; +#undef VIEWPORT +#undef SCISSOR +#undef LINE_WIDTH +#undef DEPTH_BIAS +#undef BLEND_CONSTANTS +#undef DEPTH_BOUNDS +#undef STENCIL_COMPARE_MASK +#undef STENCIL_WRITE_MASK +#undef STENCIL_REFERENCE + +#ifdef STORMKIT_GPU_VULKAN + #define OPTIMAL IMAGE_TILING_VALUE(OPTIMAL) + #define LINEAR IMAGE_TILING_VALUE(LINEAR) +#elifdef STORMKIT_GPU_WGPU + #define OPTIMAL + #define LINEAR +#endif + enum class ImageTiling : UInt32 { + OPTIMAL, + LINEAR, + }; +#undef OPTIMAL +#undef LINEAR + +#ifdef STORMKIT_GPU_VULKAN + #define FRONT STENCIL_FACE_VALUE(FRONT) + #define BACK STENCIL_FACE_VALUE(BACK) +#elifdef STORMKIT_GPU_WGPU + #define FRONT + #define BACK +#endif + enum class StencilFaceFlag : UInt8 { + FRONT, + BACK, +#undef FRONT +#undef BACK + FRONT_AND_BACK = FRONT | BACK, + }; + +#ifdef STORMKIT_GPU_VULKAN + #define TRIANGLES GEOMETRY_TYPE_VALUE(TRIANGLES) + #define AABBS GEOMETRY_TYPE_VALUE(AABBS) + #define INSTANCES GEOMETRY_TYPE_VALUE(INSTANCES) +#elifdef STORMKIT_GPU_WGPU + #define TRIANGLES + #define AABBS + #define INSTANCES +#endif + enum class GeometryType : UInt8 { + TRIANGLES, + AABBS, + INSTANCES, + }; +#undef TRIANGLES +#undef AABBS +#undef INSTANCES + +#ifdef STORMKIT_GPU_VULKAN + #define OPAQUE GEOMETRY_VALUE(OPAQUE) + #define NO_DUPLICATE_ANY_HIT_INVOCATION GEOMETRY_VALUE(NO_DUPLICATE_ANY_HIT_INVOCATION) +#elifdef STORMKIT_GPU_WGPU + #define OPAQUE + #define NO_DUPLICATE_ANY_HIT_INVOCATION +#endif + enum class GeometryFlag : UInt8 { + OPAQUE, + NO_DUPLICATE_ANY_HIT_INVOCATION, + }; +#undef OPAQUE +#undef NO_DUPLICATE_ANY_HIT_INVOCATION + +#ifdef STORMKIT_GPU_VULKAN + #define SRGB_NONLINEAR COLOR_SPACE_VALUE(SRGB_NONLINEAR_KHR) + #define DISPLAY_P3_NONLINEAR COLOR_SPACE_VALUE_EXT(DISPLAY_P3_NONLINEAR) + #define EXTENDED_SRGB_LINEAR COLOR_SPACE_VALUE_EXT(EXTENDED_SRGB_LINEAR) + #define DCI_P3_NONLINEAR COLOR_SPACE_VALUE_EXT(DCI_P3_NONLINEAR) + #define BT709_LINEAR COLOR_SPACE_VALUE_EXT(BT709_LINEAR) + #define BT709_NONLINEAR COLOR_SPACE_VALUE_EXT(BT709_NONLINEAR) + #define BT2020_LINEAR COLOR_SPACE_VALUE_EXT(BT2020_LINEAR) + #define HDR10_ST2084 COLOR_SPACE_VALUE_EXT(HDR10_ST2084) + #define DOLBYVISION COLOR_SPACE_VALUE_EXT(DOLBYVISION) + #define HDR10_HLG COLOR_SPACE_VALUE_EXT(HDR10_HLG) + #define ADOBERGB_LINEAR COLOR_SPACE_VALUE_EXT(ADOBERGB_LINEAR) + #define ADOBERGB_NONLINEAR COLOR_SPACE_VALUE_EXT(ADOBERGB_NONLINEAR) + #define PASS_THROUGH COLOR_SPACE_VALUE_EXT(PASS_THROUGH) + #define EXTENDED_SRGB_NONLINEAR COLOR_SPACE_VALUE_EXT(EXTENDED_SRGB_NONLINEAR) + #define DISPLAY_NATIVE_AMD COLOR_SPACE_VALUE(DISPLAY_NATIVE_AMD) + #define DISPLAY_P3_LINEAR COLOR_SPACE_VALUE_EXT(DISPLAY_P3_LINEAR) +#elifdef STORMKIT_GPU_WGPU + #define SRGB_NONLINEAR + #define DISPLAY_P3_NONLINEAR + #define DISPLAY_P3_LINEAR + #define DCI_P3_NONLINEAR + #define BT709_LINEAR + #define BT709_NONLINEAR + #define BT2020_LINEAR + #define HDR10_ST2084 + #define DOLBYVISION + #define HDR10_HLG + #define ADOBERGB_LINEAR + #define ADOBERGB_NONLINEAR + #define PASS_THROUGH + #define EXTENDED_SRGB_LINEAR + #define EXTENDED_SRGB_NONLINEAR + #define DISPLAY_NATIVE_AMD +#endif + enum class ColorSpace : UInt32 { + SRGB_NONLINEAR, + DISPLAY_P3_NONLINEAR, + DISPLAY_P3_LINEAR, + EXTENDED_SRGB_LINEAR, + DCI_P3_NONLINEAR, + BT709_LINEAR, + BT709_NONLINEAR, + BT2020_LINEAR, + HDR10_ST2084, + DOLBYVISION, + HDR10_HLG, + ADOBERGB_LINEAR, + ADOBERGB_NONLINEAR, + PASS_THROUGH, + EXTENDED_SRGB_NONLINEAR, + DISPLAY_NATIVE_AMD, + }; +#undef NO_DUPLICATE_ANY_HIT_INVOCATION +#undef DISPLAY_P3_NONLINEAR +#undef EXTENDED_SRGB_LINEAR +#undef DCI_P3_NONLINEAR +#undef BT709_LINEAR +#undef BT709_NONLINEAR +#undef BT2020_LINEAR +#undef HDR10_ST2084 +#undef DOLBYVISION +#undef HDR10_HLG +#undef ADOBERGB_LINEAR +#undef ADOBERGB_NONLINEAR +#undef PASS_THROUGH +#undef EXTENDED_SRGB_NONLINEAR +#undef DISPLAY_NATIVE_AMD +#undef SRGB_NONLINEAR +#undef DCI_P3_LINEAR +#undef DISPLAY_P3_LINEAR + +#ifdef STORMKIT_GPU_VULKAN + #define IMMEDIATE PRESENT_MODE_VALUE(IMMEDIATE) + #define MAILBOX PRESENT_MODE_VALUE(MAILBOX) + #define FIFO PRESENT_MODE_VALUE(FIFO) + #define FIFO_RELAXED PRESENT_MODE_VALUE(FIFO_RELAXED) + #define SHARED_DEMAND_REFRESH PRESENT_MODE_VALUE(SHARED_DEMAND_REFRESH) + #define SHARED_CONTINUOUS_REFRESH PRESENT_MODE_VALUE(SHARED_CONTINUOUS_REFRESH) +#elifdef STORMKIT_GPU_WGPU + #define IMMEDIATE + #define MAILBOX + #define FIFO + #define FIFO_RELAXED + #define SHARED_DEMAND_REFRESH + #define SHARED_CONTINUOUS_REFRESH +#endif + enum class PresentMode : UInt32 { + IMMEDIATE, + MAILBOX, + FIFO, + FIFO_RELAXED, + SHARED_DEMAND_REFRESH, + SHARED_CONTINUOUS_REFRESH, + }; +#undef IMMEDIATE +#undef MAILBOX +#undef FIFO +#undef FIFO_RELAXED +#undef SHARED_DEMAND_REFRESH +#undef SHARED_CONTINUOUS_REFRESH + + struct SurfaceFormat { + PixelFormat format; + ColorSpace color_space; + }; + + struct MemoryBarrier { + AccessFlag src; + AccessFlag dst; + }; + + struct RenderCapabilities { + struct { + bool robust_buffer_access; + bool full_draw_index_uint32; + bool image_cube_array; + bool independent_blend; + bool geometry_shader; + bool tessellation_shader; + bool sampler_rate_shading; + bool dual_src_blend; + bool logic_op; + bool multi_draw_indirect; + bool draw_indirect_first_instance; + bool depth_clamp; + bool depth_bias_clamp; + bool fill_Mode_non_solid; + bool depth_bounds; + bool wide_lines; + bool large_points; + bool alpha_to_one; + bool multi_viewport; + bool sampler_anisotropy; + bool texture_compression_etc2; + bool texture_compression_astc_ldr; + bool texture_compression_bc; + bool occlusion_query_precise; + bool pipeline_statistics_query; + bool vertex_pipeline_stores_and_atomics; + bool fragment_stores_and_atomics; + bool shader_tessellation_and_geometry_point_size; + bool shader_image_gather_extended; + bool shader_storage_image_extended_formats; + bool shader_storage_image_multisample; + bool shader_storage_image_read_without_format; + bool shader_storage_image_write_without_format; + bool shader_uniform_buffer_array_dynamic_indexing; + bool shader_sampled_image_array_dynamic_indexing; + bool shader_storage_buffer_array_dynamic_indexing; + bool shader_storage_image_array_dynamic_indexing; + bool shader_clip_distance; + bool shader_cull_distance; + bool shader_float_64; + bool shader_int_64; + bool shader_int_16; + bool shader_resource_residency; + bool shader_resource_min_lod; + bool sparse_binding; + bool sparse_residency_buffer; + bool sparse_residency_image_2D; + bool sparse_residency_image_3D; + bool sparse_residency_2_samples; + bool sparse_residency_4_samples; + bool sparse_residency_6_samples; + bool sparse_residency_8_samples; + bool sparse_residency_16_samples; + bool sparse_residency_aliased; + bool variable_multisample_rate; + bool inherited_queries; + } features; + + struct { + UInt32 max_image_dimension_1D; + UInt32 max_image_dimension_2D; + UInt32 max_image_dimension_3D; + UInt32 max_image_dimension_cube; + UInt32 max_image_array_layers; + UInt32 max_texel_buffer_elements; + UInt32 max_uniform_buffer_range; + std::optional max_storage_buffer_range; + UInt32 max_push_constants_size; + std::optional max_memory_allocation_count; + std::optional max_sampler_allocation_count; + std::optional buffer_image_granularity; + std::optional sparse_address_space_size; + std::optional max_bound_descriptor_sets; + UInt32 max_per_stage_descriptor_samplers; + UInt32 max_per_stage_descriptor_uniform_buffers; + UInt32 max_per_stage_descriptor_storage_buffers; + UInt32 max_per_stage_descriptor_sampled_images; + UInt32 max_per_stage_descriptor_storage_images; + std::optional max_per_stage_descriptor_input_attachments; + std::optional max_per_stage_resources; + UInt32 max_descriptor_set_samplers; + UInt32 max_descriptor_set_uniform_buffers; + UInt32 max_descriptor_set_uniform_buffers_dynamic; + UInt32 max_descriptor_set_storage_buffers; + UInt32 max_descriptor_set_storage_buffers_dynamic; + UInt32 max_descriptor_set_sampled_images; + UInt32 max_descriptor_set_storage_images; + std::optional max_descriptor_set_input_attachments; + UInt32 max_vertex_input_attributes; + UInt32 max_vertex_input_bindings; + UInt32 max_vertex_input_attribute_offset; + std::optional max_vertex_input_binding_stride; + UInt32 max_vertex_output_components; + UInt32 max_tessellation_generation_level; + UInt32 max_tessellation_patch_size; + UInt32 max_tessellation_control_per_vertex_input_components; + UInt32 max_tessellation_control_per_vertex_output_components; + UInt32 max_tessellation_control_per_patch_output_components; + UInt32 max_tessellation_control_total_output_components; + UInt32 max_tessellation_evaluation_input_components; + UInt32 max_tessellation_evaluation_output_components; + UInt32 max_geometry_shader_invocations; + UInt32 max_geometry_input_components; + UInt32 max_geometry_output_components; + UInt32 max_geometry_output_vertices; + UInt32 max_geometry_total_output_components; + UInt32 max_fragment_input_components; + UInt32 max_fragment_output_attachments; + UInt32 max_fragment_dual_src_attachments; + UInt32 max_fragment_combined_output_resources; + UInt32 max_compute_shared_memory_size; + std::array max_compute_work_group_count; + UInt32 max_compute_work_group_invocations; + std::array max_compute_work_group_size; + std::optional sub_pixel_precision_bits; + std::optional sub_texel_precision_bits; + std::optional mipmap_precision_bits; + UInt32 max_draw_indexed_index_value; + std::optional max_draw_indirect_count; + float max_sampler_lod_bias; + float max_sampler_anisotropy; + UInt32 max_viewports; + std::array max_viewport_dimensions; + std::array viewport_bounds_range; + std::optional viewport_sub_pixel_bits; + std::optional min_memory_map_alignment; + std::optional min_texel_buffer_offset_alignment; + UInt64 min_uniform_buffer_offset_alignment; + UInt64 min_storage_buffer_offset_alignment; + Int32 min_texel_offset; + UInt32 max_texel_offset; + Int32 min_texel_gather_offset; + UInt32 max_texel_gather_offset; + float min_interpolation_offset; + float max_interpolation_offset; + std::optional sub_pixel_interpolation_offset_bits; + UInt32 max_framebuffer_width; + UInt32 max_framebuffer_height; + UInt32 max_framebuffer_layers; + SampleCountFlag framebuffer_color_sample_counts; + SampleCountFlag framebuffer_depth_sample_counts; + SampleCountFlag framebuffer_stencil_sample_counts; + SampleCountFlag framebuffer_no_attachments_sample_counts; + UInt32 max_color_attachments; + SampleCountFlag sampled_image_color_sample_counts; + SampleCountFlag sampled_image_integer_sample_counts; + SampleCountFlag sampled_image_depth_sample_counts; + SampleCountFlag sampled_image_stencil_sample_counts; + SampleCountFlag storage_image_sample_counts; + UInt32 max_sample_mask_words; + bool timestamp_compute_and_engine; + float timestamp_period; + UInt32 max_clip_distances; + UInt32 max_cull_distances; + UInt32 max_combined_clip_and_cull_distances; + UInt32 discrete_queue_priorities; + std::array point_size_range; + std::array line_width_range; + float point_size_granularity; + float line_width_granularity; + bool strict_lines; + bool standard_sample_locations; + std::optional optimal_buffer_copy_offset_alignment; + std::optional optimal_buffer_copy_row_pitch_alignment; + UInt64 non_coherent_atom_size; + } limits; + }; + + struct ImageSubresourceRange { + ImageAspectMaskFlag aspect_mask = ImageAspectMaskFlag::COLOR; + + UInt32 base_mip_level = 0u; + UInt32 level_count = 1u; + UInt32 base_array_layer = 0u; + UInt32 layer_count = 1u; + }; + + struct ImageSubresourceLayers { + ImageAspectMaskFlag aspect_mask = ImageAspectMaskFlag::COLOR; + + UInt32 mip_level = 0u; + UInt32 base_array_layer = 0u; + UInt32 layer_count = 1u; + }; + + struct Viewport { + math::Vector2F position; + math::ExtentF extent; + math::Vector2F depth; + }; + + struct Scissor { + math::Vector2I offset; + math::ExtentU extent; + }; + + struct ClearColor { + RGBColorF color = stormkit::RGBColorDef::SILVER; + }; + + struct ClearDepthStencil { + float depth = 1.f; + UInt32 stencil = 0; + }; + + using ClearValue = std::variant; + + struct BufferImageCopy { + UInt32 buffer_offset; + UInt32 buffer_row_length; + UInt32 buffer_image_height; + + ImageSubresourceLayers subresource_layers; + + math::Vector3I offset; + math::ExtentU extent; + }; + + struct BlitRegion { + ImageSubresourceLayers src; + ImageSubresourceLayers dst; + + std::array src_offset; + std::array dst_offset; + }; + + struct PushConstantRange { + ShaderStageFlag stages; + UInt32 offset; + RangeExtent size; + }; + + struct PhysicalDeviceInfo { + UInt64 device_id; + std::string device_name; + UInt64 vendor_id; + std::string vendor_name; + + UInt32 api_major_version; + UInt32 api_minor_version; + UInt32 api_patch_version; + + UInt32 driver_major_version; + UInt32 driver_minor_version; + UInt32 driver_patch_version; + + std::array pipeline_cache_uuid; + + PhysicalDeviceType type; + }; + + struct QueueFamily { + QueueFlag flags; + UInt32 count; + }; + + using ClearValue = std::variant; + using SpirvID = UInt32; + + template + using Expected = std::expected; + + [[nodiscard]] + constexpr auto is_depth_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 get_format_channel_count(PixelFormat format) noexcept -> UInt8; + [[nodiscard]] + constexpr auto get_format_element_count(PixelFormat format) noexcept -> UInt8; + + [[nodiscard]] + auto compute_mip_level(const math::ExtentU& extent) noexcept -> UInt32; + [[nodiscard]] + constexpr auto compute_uniform_buffer_offset_align(RangeExtent size, + const RenderCapabilities& + capabilities) noexcept -> RangeExtent; + + [[nodiscard]] + auto to_string(const PhysicalDeviceInfo& data) noexcept; + + template + [[nodiscard]] + constexpr auto to_vk(U value) noexcept -> T; + + template + [[nodiscard]] + auto to_vk(const T& value) noexcept -> decltype(auto); + + template + [[nodiscard]] + constexpr auto from_vk(VkFlags) noexcept -> T; + + namespace monadic { + template + [[nodiscard]] + constexpr auto to_vk() noexcept -> decltype(auto); + + [[nodiscard]] + constexpr auto to_vk() noexcept -> decltype(auto); + + template + [[nodiscard]] + constexpr auto from_vk() noexcept -> decltype(auto); + + [[nodiscard]] + constexpr auto from_vk() noexcept -> decltype(auto); + } // namespace monadic + + [[nodiscard]] + constexpr auto to_vk(const Viewport& viewport) noexcept -> VkViewport; + + [[nodiscard]] + constexpr auto to_vk(const Scissor& viewport) noexcept -> VkRect2D; + + [[nodiscard]] + constexpr auto from_vk(const Viewport& viewport) noexcept -> VkViewport; + } // namespace stormkit::gpu + + FLAG_ENUM(stormkit::gpu::QueueFlag) + FLAG_ENUM(stormkit::gpu::ShaderStageFlag) + FLAG_ENUM(stormkit::gpu::SampleCountFlag) + FLAG_ENUM(stormkit::gpu::ColorComponentFlag) + FLAG_ENUM(stormkit::gpu::ImageAspectMaskFlag) + FLAG_ENUM(stormkit::gpu::ImageCreateFlag) + FLAG_ENUM(stormkit::gpu::CullModeFlag) + FLAG_ENUM(stormkit::gpu::BufferUsageFlag) + FLAG_ENUM(stormkit::gpu::ImageUsageFlag) + FLAG_ENUM(stormkit::gpu::MemoryPropertyFlag) + FLAG_ENUM(stormkit::gpu::AccessFlag) + FLAG_ENUM(stormkit::gpu::PipelineStageFlag) + FLAG_ENUM(stormkit::gpu::DependencyFlag) + FLAG_ENUM(stormkit::gpu::StencilFaceFlag) + FLAG_ENUM(stormkit::gpu::GeometryFlag) + HASH_FUNC(stormkit::gpu::Viewport, value.position, value.extent, value.depth) + HASH_FUNC(stormkit::gpu::Scissor, value.offset, value.extent) +} + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit::gpu { + // namespace details { namespace { + // template + // [[maybe_unused]] + // constexpr auto FLAG_MAPPER + // = frozen::unordered_map {}; + + // template<> + // [[maybe_unused]] + // constexpr auto FLAG_MAPPER + // = frozen::make_unordered_map({ + // { PhysicalDeviceType::DISCRETE_GPU, VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU }, + // { PhysicalDeviceType::VIRTUAL_GPU, VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU }, + // { PhysicalDeviceType::INTEGRATED_GPU, VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU }, + // { PhysicalDeviceType::CPU, VK_PHYSICAL_DEVICE_TYPE_CPU }, + // { PhysicalDeviceType::OTHER, VK_PHYSICAL_DEVICE_TYPE_OTHER }, + // }); + // }} // namespace details + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto is_depth_only_format(PixelFormat format) noexcept -> bool { + return format == PixelFormat::DEPTH16 + or format == PixelFormat::DEPTH24 + or format == PixelFormat::DEPTH32F; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto is_depth_stencil_format(PixelFormat format) noexcept -> bool { + return format == PixelFormat::DEPTH16_STENCIL8 + or format == PixelFormat::DEPTH24_STENCIL8 + or format == PixelFormat::DEPTH32F_STENCIL8; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto is_depth_format(PixelFormat format) noexcept -> bool { + return is_depth_only_format(format) or is_depth_stencil_format(format); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto get_format_channel_count(PixelFormat format) noexcept -> UInt8 { + switch (format) { + case PixelFormat::R8_SNORM: + case PixelFormat::R8_UNORM: + case PixelFormat::R16_SNORM: + case PixelFormat::R16_UNORM: + case PixelFormat::R8I: + case PixelFormat::R8U: + case PixelFormat::R16I: + case PixelFormat::R16U: + case PixelFormat::R32I: + case PixelFormat::R32U: + case PixelFormat::R16F: + case PixelFormat::R32F: + case PixelFormat::DEPTH16: + case PixelFormat::DEPTH24: + case PixelFormat::DEPTH32F: return 1; + + case PixelFormat::RG8_SNORM: + case PixelFormat::RG8_UNORM: + case PixelFormat::RG16_SNORM: + case PixelFormat::RG16_UNORM: + case PixelFormat::RG8I: + case PixelFormat::RG8U: + case PixelFormat::RG16I: + case PixelFormat::RG16U: + case PixelFormat::RG32I: + case PixelFormat::RG32U: + case PixelFormat::RG16F: + case PixelFormat::RG32F: + case PixelFormat::DEPTH16_STENCIL8: + case PixelFormat::DEPTH24_STENCIL8: + case PixelFormat::DEPTH32F_STENCIL8: return 2; + + case PixelFormat::RGB8_SNORM: + case PixelFormat::RGB8_UNORM: + case PixelFormat::RGB16_SNORM: + case PixelFormat::RGB16_UNORM: + case PixelFormat::BGR8_UNORM: + case PixelFormat::RGB8I: + case PixelFormat::RGB8U: + case PixelFormat::RGB16I: + case PixelFormat::RGB16U: + case PixelFormat::RGB32I: + case PixelFormat::RGB32U: + case PixelFormat::RGB16F: + case PixelFormat::RGB32F: + case PixelFormat::SRGB8: + case PixelFormat::SBGR8: + case PixelFormat::R5_G6_B5_UNORM_PACK16: + case PixelFormat::B10_GR11UF_PACK32: return 3; + + case PixelFormat::RGBA8_SNORM: + case PixelFormat::RGBA8_UNORM: + case PixelFormat::RGBA16_SNORM: + case PixelFormat::RGBA16_UNORM: + case PixelFormat::BGRA8_UNORM: + case PixelFormat::RGBA8I: + case PixelFormat::RGBA8U: + case PixelFormat::RGBA16I: + case PixelFormat::RGBA16U: + case PixelFormat::RGBA32I: + case PixelFormat::RGBA32U: + case PixelFormat::RGBA16F: + case PixelFormat::RGBA32F: + case PixelFormat::SRGBA8: + case PixelFormat::SBGRA8: return 4; + + default: break; + } + + return 0u; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto get_format_element_count(PixelFormat format) noexcept -> UInt8 { + switch (format) { + case PixelFormat::R8_SNORM: + case PixelFormat::R8_UNORM: + case PixelFormat::RG8_SNORM: + case PixelFormat::RG8_UNORM: + case PixelFormat::R8I: + case PixelFormat::R8U: + case PixelFormat::RG8I: + case PixelFormat::RG8U: + case PixelFormat::RGB8_SNORM: + case PixelFormat::RGB8_UNORM: + case PixelFormat::BGR8_UNORM: + case PixelFormat::RGB8I: + case PixelFormat::RGB8U: + case PixelFormat::RGBA8_SNORM: + case PixelFormat::RGBA8_UNORM: + case PixelFormat::RGBA16_SNORM: + case PixelFormat::BGRA8_UNORM: + case PixelFormat::SRGB8: + case PixelFormat::SBGR8: + case PixelFormat::SRGBA8: + case PixelFormat::SBGRA8: return 1u; + + case PixelFormat::R16_SNORM: + case PixelFormat::R16_UNORM: + case PixelFormat::R16I: + case PixelFormat::R16U: + case PixelFormat::RG16_SNORM: + case PixelFormat::RG16_UNORM: + case PixelFormat::RG16I: + case PixelFormat::RG16U: + case PixelFormat::RG16F: + case PixelFormat::RGB16I: + case PixelFormat::RGB16U: + case PixelFormat::RGB16F: + case PixelFormat::RGBA16I: + case PixelFormat::RGBA16U: + case PixelFormat::RGBA16F: + case PixelFormat::R16F: return 2u; + + case PixelFormat::R32I: + case PixelFormat::R32U: + case PixelFormat::R32F: + case PixelFormat::RG32I: + case PixelFormat::RG32U: + case PixelFormat::RG32F: + case PixelFormat::RGB16_SNORM: + case PixelFormat::RGB32I: + case PixelFormat::RGB32U: + case PixelFormat::RGB32F: + case PixelFormat::RGBA8I: + case PixelFormat::RGBA8U: + case PixelFormat::RGBA32I: + case PixelFormat::RGBA32U: + case PixelFormat::RGBA32F: return 4u; + + default: break; + } + + return 0u; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto compute_mip_level(const math::ExtentU& extent) noexcept -> UInt32 { + const auto as_float = math::ExtentF { extent }; + + return as(math::floor(math::log2(math::max(as_float.width, as_float.height)))) + 1; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + constexpr auto compute_uniform_buffer_offset_align(RangeExtent size, + const RenderCapabilities& + capabilities) noexcept -> RangeExtent { + 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); + + return size; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto to_string(const PhysicalDeviceInfo& data) noexcept { + return std::format("[PhysicalDeviceInfo:\n" + " .device_id = {:#06x},\n" + " .device_name = {},\n" + " .vendor_id = {:#06x},\n" + " .vendor_name = {},\n" + " .api_version = {}.{}.{},\n" + " .driver_version = {}.{}.{},\n" + " .type = {}]", + data.device_id, + data.device_name, + data.vendor_id, + data.vendor_name, + data.api_major_version, + data.api_minor_version, + data.api_patch_version, + data.driver_major_version, + data.driver_minor_version, + data.driver_patch_version, + data.type); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + STORMKIT_INTRINSIC + constexpr auto to_vk(U value) noexcept -> T { + return narrow(value); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + STORMKIT_INTRINSIC + constexpr auto from_vk(VkFlags value) noexcept -> T { + return narrow(value); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + STORMKIT_CONST + inline auto to_vk(const T& value) noexcept -> decltype(auto) { + if constexpr (meta::IsPointer) return value->native_handle(); + else + return value.native_handle(); + } + + namespace monadic { + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto to_vk() noexcept -> decltype(auto) { + return [](auto flag) static noexcept -> decltype(auto) { return gpu::to_vk(flag); }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto to_vk() noexcept -> decltype(auto) { + return + [](const auto& value) static noexcept -> decltype(auto) { return gpu::to_vk(value); }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto from_vk() noexcept -> decltype(auto) { + return + [](auto flag) static noexcept -> decltype(auto) { return gpu::from_vk(flag); }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto from_vk() noexcept -> decltype(auto) { + return [](auto val) static noexcept -> decltype(auto) { return gpu::from_vk(val); }; + } + } // namespace monadic + + [[nodiscard]] + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto to_vk(const Viewport& viewport) noexcept -> VkViewport { + return VkViewport { + .x = viewport.position.x, + .y = viewport.position.y, + .width = viewport.extent.width, + .height = viewport.extent.height, + .minDepth = viewport.depth.x, + .maxDepth = viewport.depth.y, + }; + } + + [[nodiscard]] + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto to_vk(const Scissor& scissor) noexcept -> VkRect2D { + return VkRect2D { + .offset = { scissor.offset.x, scissor.offset.y }, + .extent = { scissor.extent.width, scissor.extent.height } + }; + } + + [[nodiscard]] + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto from_vk(const VkViewport& viewport) noexcept -> Viewport { + return Viewport { + .position = { viewport.x, viewport.y }, + .extent = { viewport.width, viewport.height }, + .depth = { viewport.minDepth, viewport.maxDepth }, + }; + } + +#define SPECIALIZATION(x, y) \ + template x from_vk(VkFlags); \ + template y to_vk(x) + + SPECIALIZATION(PhysicalDeviceType, VkPhysicalDeviceType); + SPECIALIZATION(QueueFlag, VkQueueFlagBits); + SPECIALIZATION(ShaderStageFlag, VkShaderStageFlagBits); + SPECIALIZATION(PrimitiveTopology, VkPrimitiveTopology); + SPECIALIZATION(PolygonMode, VkPolygonMode); + SPECIALIZATION(CullModeFlag, VkCullModeFlagBits); + SPECIALIZATION(FrontFace, VkFrontFace); + SPECIALIZATION(SampleCountFlag, VkSampleCountFlagBits); + SPECIALIZATION(ColorComponentFlag, VkColorComponentFlagBits); + SPECIALIZATION(BlendFactor, VkBlendFactor); + SPECIALIZATION(BlendOperation, VkBlendOp); + SPECIALIZATION(LogicOperation, VkLogicOp); + SPECIALIZATION(PixelFormat, VkFormat); + SPECIALIZATION(AttachmentLoadOperation, VkAttachmentLoadOp); + SPECIALIZATION(AttachmentStoreOperation, VkAttachmentStoreOp); + SPECIALIZATION(PipelineBindPoint, VkPipelineBindPoint); + SPECIALIZATION(ImageLayout, VkImageLayout); + SPECIALIZATION(ImageAspectMaskFlag, VkImageAspectFlagBits); + SPECIALIZATION(VertexInputRate, VkVertexInputRate); + SPECIALIZATION(ImageCreateFlag, VkImageCreateFlagBits); + SPECIALIZATION(BufferUsageFlag, VkBufferUsageFlagBits); + SPECIALIZATION(ImageUsageFlag, VkImageUsageFlagBits); + SPECIALIZATION(MemoryPropertyFlag, VkMemoryPropertyFlagBits); + SPECIALIZATION(DescriptorType, VkDescriptorType); + SPECIALIZATION(CompareOperation, VkCompareOp); + SPECIALIZATION(Filter, VkFilter); + SPECIALIZATION(SamplerAddressMode, VkSamplerAddressMode); + SPECIALIZATION(BorderColor, VkBorderColor); + SPECIALIZATION(SamplerMipmapMode, VkSamplerMipmapMode); + SPECIALIZATION(Result, VkResult); + SPECIALIZATION(ImageType, VkImageType); + SPECIALIZATION(ImageViewType, VkImageViewType); + SPECIALIZATION(DebugObjectType, VkObjectType); + SPECIALIZATION(AccessFlag, VkAccessFlagBits); + SPECIALIZATION(PipelineStageFlag, VkPipelineStageFlagBits); + SPECIALIZATION(DependencyFlag, VkDependencyFlagBits); + SPECIALIZATION(DynamicState, VkDynamicState); + SPECIALIZATION(ImageTiling, VkImageTiling); + SPECIALIZATION(StencilFaceFlag, VkStencilFaceFlagBits); + SPECIALIZATION(GeometryType, VkGeometryTypeKHR); + SPECIALIZATION(GeometryFlag, VkGeometryFlagBitsKHR); + SPECIALIZATION(ColorSpace, VkColorSpaceKHR); + SPECIALIZATION(PresentMode, VkPresentModeKHR); +} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/execution.mpp b/modules/stormkit/gpu/execution.mpp new file mode 100644 index 000000000..80f2671cd --- /dev/null +++ b/modules/stormkit/gpu/execution.mpp @@ -0,0 +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.gpu.execution; + +export import :command_buffer; +export import :descriptors; +export import :pipeline; +export import :raster_pipeline; +export import :render_pass; +export import :swapchain; diff --git a/modules/stormkit/gpu/execution/command_buffer.mpp b/modules/stormkit/gpu/execution/command_buffer.mpp new file mode 100644 index 000000000..b355a32eb --- /dev/null +++ b/modules/stormkit/gpu/execution/command_buffer.mpp @@ -0,0 +1,1709 @@ +// 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:command_buffer; + +import std; +import frozen; + +import stormkit.core; +import stormkit.gpu.core; +import stormkit.gpu.resource; +import stormkit.gpu.vulkan; + +import :descriptors; +import :render_pass; +import :pipeline; +import :swapchain; + +namespace stdr = std::ranges; +namespace stdv = std::views; + +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; + UInt32 subpass = 0; + OptionalRef framebuffer = std::nullopt; + }; + + template + concept IsImage = requires(T&& img) { + img.extent(); + img.format(); + img.type(); + img.samples(); + img.layers(); + img.faces(); + img.mip_levels(); + img.usages(); + img.native_handle(); + }; + + 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; + ~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 beginDebugRegion(std::string_view name, + const RGBColorF& color = RGBColorDef::WHITE) noexcept -> void; + auto insertDebugLabel(std::string_view name, + const RGBColorF& color = RGBColorDef::WHITE) noexcept -> void; + auto endDebugRegion() noexcept -> void; + + auto begin(bool one_time_submit = false, + std::optional inheritance_info = std::nullopt) noexcept + -> Expected; + auto end() noexcept -> Expected; + + 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 -> void; + auto next_sub_pass() noexcept -> void; + auto end_render_pass() noexcept -> void; + + auto bind_pipeline(const Pipeline& pipeline) noexcept -> void; + auto set_viewport(UInt32 first_viewport, std::span viewports) noexcept + -> void; + auto set_scissor(UInt32 first_scissor, std::span scissors) noexcept -> void; + auto set_line_width(float width) noexcept -> void; + auto set_depth_bias(float constant_factor, float clamp, float slope_factor) noexcept + -> void; + auto set_blend_constants(std::span constants) noexcept -> void; + auto set_depth_bounds(float min, float max) noexcept -> void; + auto set_stencil_compare_mask(StencilFaceFlag face, UInt32 mask) noexcept -> void; + auto set_stencil_write_mask(StencilFaceFlag face, UInt32 mask) noexcept -> void; + auto set_stencil_reference(StencilFaceFlag face, UInt32 reference) noexcept -> void; + + auto dispatch(UInt32 group_count_x, UInt32 group_count_y, UInt32 group_count_z) noexcept + -> void; + + auto draw(UInt32 vertex_count, + UInt32 instance_count = 1u, + UInt32 first_vertex = 0, + UInt32 first_instance = 0) noexcept -> void; + auto draw_indexed(UInt32 index_count, + UInt32 instance_count = 1u, + UInt32 first_index = 0u, + Int32 vertex_offset = 0, + UInt32 first_instance = 0u) noexcept -> void; + auto draw_indirect(const Buffer& buffer, + RangeExtent offset, + UInt32 draw_count, + UInt32 stride) noexcept -> void; + auto draw_indexed_indirect(const Buffer& buffer, + RangeExtent offset, + UInt32 draw_count, + UInt32 stride) noexcept -> void; + + auto bind_vertex_buffers(std::span> buffers, + std::span offsets) noexcept -> void; + auto bindIndexBuffer(const Buffer& buffer, + UInt64 offset = 0, + bool large_indices = false) noexcept -> void; + auto bind_descriptor_sets(const Pipeline& pipeline, + const PipelineLayout& layout, + std::span> descriptor_sets, + std::span dynamic_offsets = {}) noexcept -> void; + + auto copy_buffer(const Buffer& src, + const Buffer& dst, + RangeExtent size, + UInt64 src_offset = 0u, + UInt64 dst_offset = 0u) noexcept -> void; + auto copy_buffer_to_image( + const Buffer& src, + const IsImage auto& dst, + std::span buffer_image_copies = {}) noexcept -> void; + auto copy_image_to_buffer( + const IsImage auto& src, + const Buffer& dst, + std::span buffer_image_copies = {}) noexcept -> void; + auto copy_image(const IsImage auto& src, + const IsImage auto& dst, + ImageLayout src_layout, + ImageLayout dst_layout, + const ImageSubresourceLayers& src_subresource_layers, + const ImageSubresourceLayers& dst_subresource_layers, + const math::ExtentU& extent) noexcept -> void; + + auto resolve_image(const IsImage auto& src, + const IsImage auto& dst, + ImageLayout src_layout, + ImageLayout dst_layout, + const ImageSubresourceLayers& src_subresource_layers = {}, + const ImageSubresourceLayers& dst_subresource_layers = {}) noexcept + -> void; + + auto blit_image(const IsImage auto& src, + const IsImage auto& dst, + ImageLayout src_layout, + ImageLayout dst_layout, + std::span regions, + Filter filter) -> void; + + auto transition_image_layout(const IsImage auto& image, + ImageLayout src_layout, + ImageLayout dst_layout, + const ImageSubresourceRange& subresource_range = {}) noexcept + -> void; + + auto execute_sub_command_buffers(std::span> + commandbuffers) noexcept -> void; + + 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 + -> void; + + auto push_constants(const PipelineLayout& pipeline_layout, + ShaderStageFlag stage, + std::span data, + UInt32 offset = 0u) noexcept -> void; + + [[nodiscard]] + auto native_handle() const noexcept -> VkCommandBuffer; + + CommandBuffer(const Device&, + CommandBufferLevel, + VkCommandBuffer&&, + Deleter&&, + PrivateFuncTag) noexcept; + + private: + static auto create(const Device&, CommandBufferLevel, VkCommandBuffer&&, Deleter&&) noexcept + -> CommandBuffer; + static auto allocate(const Device&, + CommandBufferLevel, + VkCommandBuffer&&, + Deleter&&) noexcept -> Heap; + + CommandBufferLevel m_level = CommandBufferLevel::PRIMARY; + + Deleter m_deleter; + + State m_state = State::INITIAL; + + VkDevice m_vk_device = nullptr; + Ref m_vk_device_table; + VkCommandBuffer m_vk_handle = nullptr; + }; + + 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(const Device& device, + CommandBufferLevel level = CommandBufferLevel::PRIMARY) + const noexcept -> Expected; + auto create_command_buffers(const Device& device, + RangeExtent count, + CommandBufferLevel level = CommandBufferLevel::PRIMARY) + const noexcept -> Expected>; + + auto allocate_command_buffer(const Device& device, + CommandBufferLevel level = CommandBufferLevel::PRIMARY) + const noexcept -> Expected>; + auto allocate_command_buffers(const Device& device, + RangeExtent 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(const Device& device, + RangeExtent count, + CommandBufferLevel level) const noexcept + -> std::vector; + auto deleteVkCommandBuffer(VkCommandBuffer cmb) noexcept -> void; + + VkDevice m_vk_device = nullptr; + VkRAIIHandle m_vk_handle = { { [this](auto handle) noexcept { + vkDestroyCommandPool(m_vk_device, handle, nullptr); + } } }; + + // std::mutex m_reuse_mutex; + std::vector m_reusable_command_buffers; + }; +} // namespace stormkit::gpu + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit::gpu { + namespace { + constexpr auto OLD_LAYOUT_ACCESS_MAP = frozen::make_unordered_map< + VkImageLayout, + std::pair>({ + { 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>({ + { VK_IMAGE_LAYOUT_UNDEFINED, { VK_ACCESS_NONE, {} } }, + { VK_IMAGE_LAYOUT_PREINITIALIZED, { VK_ACCESS_NONE, {} } }, + { VK_IMAGE_LAYOUT_GENERAL, + { VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT, + VK_PIPELINE_STAGE_VERTEX_SHADER_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_WRITE_BIT + | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT, + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT } }, + { VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, + { VK_ACCESS_SHADER_READ_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT } }, + { VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + { VK_ACCESS_SHADER_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 } }, + }); + } // namespace + + ///////////////////////////////////// + ///////////////////////////////////// + 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(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(vkQueueWaitIdle, m_vk_handle).transform_error(monadic::from_vk()); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Queue::submit(std::span submit_infos, + OptionalRef fence) const noexcept -> Expected { + struct SubmitInfoRange { + std::span wait_semaphores; + std::span wait_dst_stages; + std::span command_buffers; + std::span signal_semaphores; + }; + + const auto [wait_semaphores_count, + wait_dst_stages_count, + command_buffers_count, + signal_semaphores_count] + = [&submit_infos] noexcept { + auto wait_semaphores_count = 0u; + auto wait_dst_stages_count = 0u; + auto command_buffers_count = 0u; + auto signal_semaphores_count = 0u; + + for (auto&& submit_info : submit_infos) { + wait_semaphores_count = stdr::size(submit_info.wait_semaphores); + wait_dst_stages_count = stdr::size(submit_info.wait_dst_stages); + command_buffers_count = stdr::size(submit_info.command_buffers); + signal_semaphores_count = stdr::size(submit_info.signal_semaphores); + } + return std::make_tuple(wait_semaphores_count, + wait_dst_stages_count, + command_buffers_count, + signal_semaphores_count); + }(); + + // replace with strong type + struct VkWaitSemaphore { + VkSemaphore* _; + }; + + struct VkSignalSemaphore { + VkSemaphore* _; + }; + + auto payload = MultiBuffer { + { wait_semaphores_count, + wait_dst_stages_count, command_buffers_count, + signal_semaphores_count } + }; + + const auto submit_ranges + = submit_infos + | stdv::transform([&payload](auto&& submit_info) mutable noexcept { + const auto wait_semaphores = payload.init_range< + 0>(submit_info.wait_semaphores | stdv::transform(monadic::to_vkhandle())); + const auto wait_dst_stages = payload.init_range< + VkPipelineStageFlags>(submit_info.wait_dst_stages + | stdv::transform(core::monadic::narrow< + VkPipelineStageFlags>())); + const auto command_buffers = payload.init_range< + VkCommandBuffer>(submit_info.command_buffers + | stdv::transform(monadic::to_vkhandle())); + const auto signal_semaphores = payload.init_range< + 3>(submit_info.signal_semaphores | stdv::transform(monadic::to_vkhandle())); + + return SubmitInfoRange { + .wait_semaphores = { std::bit_cast< + VkSemaphore*>(stdr::begin(wait_semaphores)), + stdr::size(wait_semaphores) }, + .wait_dst_stages = wait_dst_stages, + .command_buffers = command_buffers, + .signal_semaphores = { std::bit_cast< + VkSemaphore*>(stdr::begin(signal_semaphores)), + stdr::size(signal_semaphores) }, + }; + }) + | stdr::to(); + + const auto vk_submit_infos + = submit_ranges + | stdv::transform([](auto&& submit_range) noexcept { + expects(stdr::size(submit_range.wait_semaphores) + == stdr::size(submit_range.wait_dst_stages)); + + return VkSubmitInfo { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .pNext = nullptr, + .waitSemaphoreCount = as(stdr::size(submit_range.wait_semaphores)), + .pWaitSemaphores = stdr::data(submit_range.wait_semaphores), + .pWaitDstStageMask = stdr::data(submit_range.wait_dst_stages), + .commandBufferCount = as(stdr::size(submit_range.command_buffers)), + .pCommandBuffers = stdr::data(submit_range.command_buffers), + .signalSemaphoreCount = as(stdr::size(submit_range + .signal_semaphores)), + .pSignalSemaphores = stdr::data(submit_range.signal_semaphores), + }; + }) + | stdr::to(); + + const auto vk_fence = core::either(fence, + monadic::to_vkhandle(), + core::monadic::init(nullptr)); + + return vk_call(vkQueueSubmit, + m_vk_handle, + stdr::size(vk_submit_infos), + stdr::data(vk_submit_infos), + vk_fence) + .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)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + inline auto Queue::present(std::span> swapchains, + std::span> wait_semaphores, + std::span image_indices) const noexcept + -> Expected { + namespace stdr = std::ranges; + namespace stdv = std::views; + 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); + + auto payload = MultiBuffer { + { swapchains_count, wait_semaphores_count } + }; + const auto vk_swapchains = payload.init_range< + VkSwapchainKHR>(swapchains | stdv::transform(monadic::to_vkhandle())); + const auto vk_semaphores = payload.init_range< + VkSemaphore>(wait_semaphores | stdv::transform(monadic::to_vkhandle())); + + const auto present_info = VkPresentInfoKHR { + .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, + .pNext = nullptr, + .waitSemaphoreCount = as(stdr::size(vk_semaphores)), + .pWaitSemaphores = stdr::data(vk_semaphores), + .swapchainCount = as(stdr::size(vk_swapchains)), + .pSwapchains = stdr::data(vk_swapchains), + .pImageIndices = stdr::data(image_indices), + .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()); + } + + ///////////////////////////////////// + ///////////////////////////////////// + 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(const Device& device, + CommandBufferLevel level, + VkCommandBuffer&& command_buffer, + Deleter&& deleter, + PrivateFuncTag) noexcept + : m_level { level }, m_deleter { std::move(deleter) }, + m_vk_device { device.native_handle() }, + m_vk_device_table { as_ref(device.device_table()) }, + m_vk_handle { std::move(command_buffer) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::create(const Device& device, + CommandBufferLevel level, + VkCommandBuffer&& cmb, + Deleter&& deleter) noexcept -> CommandBuffer { + return CommandBuffer { device, + level, + std::move(cmb), + std::move(deleter), + PrivateFuncTag {} }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::allocate(const Device& device, + CommandBufferLevel level, + VkCommandBuffer&& cmb, + Deleter&& deleter) noexcept -> Heap { + return allocate_unsafe(device, + level, + std::move(cmb), + std::move(deleter), + PrivateFuncTag {}); + } + + ///////////////////////////////////// + ///////////////////////////////////// + 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] { m_state = State::INITIAL; }) + .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::beginDebugRegion(std::string_view name, + const RGBColorF& color) noexcept -> void { + expects(m_state == State::RECORDING); + + if (not vkCmdBeginDebugUtilsLabelEXT) [[unlikely]] + return; + + 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); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::insertDebugLabel(std::string_view name, + const RGBColorF& color) noexcept -> void { + expects(m_state == State::RECORDING); + + if (not vkCmdInsertDebugUtilsLabelEXT) [[unlikely]] + return; + + 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); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::endDebugRegion() noexcept -> void { + expects(m_state == State::RECORDING); + + if (not vkCmdEndDebugUtilsLabelEXT) [[unlikely]] + return; + + vk_call(vkCmdEndDebugUtilsLabelEXT, m_vk_handle); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::begin(bool one_time_submit, + std::optional inheritance_info) noexcept + -> Expected { + expects(m_state == State::INITIAL); + + 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_vkhandle(*inheritance_info->render_pass); + info.subpass = inheritance_info->subpass; + info.framebuffer = to_vkhandle(*inheritance_info->framebuffer); + } + return info; + }(); + + const auto flags = [this, one_time_submit]() { + 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; + + return flags; + }(); + + const auto begin_info = VkCommandBufferBeginInfo { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + .pNext = nullptr, + .flags = flags, + .pInheritanceInfo = &vk_inheritance_info, + }; + + return vk_call(m_vk_device_table->vkBeginCommandBuffer, m_vk_handle, &begin_info) + .transform([this] noexcept { m_state = State::RECORDING; }) + .transform_error(monadic::from_vk()); + } + + ///////////////////////////////////// + ///////////////////////////////////// + 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] noexcept { m_state = State::EXECUTABLE; }) + .transform_error(monadic::from_vk()); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::begin_render_pass(const RenderPass& render_pass, + const FrameBuffer& framebuffer, + std::span clear_values, + bool secondary_commandbuffers) noexcept -> void { + 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(); + + const auto begin_info = VkRenderPassBeginInfo { + .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + .pNext = nullptr, + .renderPass = to_vkhandle(render_pass), + .framebuffer = to_vkhandle(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), + }; + + 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); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::next_sub_pass() noexcept -> void { + expects(m_state == State::RECORDING); + + vk_call(m_vk_device_table->vkCmdNextSubpass, m_vk_handle, VK_SUBPASS_CONTENTS_INLINE); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::end_render_pass() noexcept -> void { + expects(m_state == State::RECORDING); + + vk_call(m_vk_device_table->vkCmdEndRenderPass, m_vk_handle); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::bind_pipeline(const Pipeline& pipeline) noexcept -> void { + 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_vkhandle(pipeline)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::set_viewport(UInt32 first_viewport, + std::span viewports) noexcept -> void { + expects(m_state == State::RECORDING); + + const auto vk_viewports = viewports + | stdv::transform(monadic::to_vk()) + | stdr::to(); + + vk_call(m_vk_device_table->vkCmdSetViewport, + m_vk_handle, + first_viewport, + stdr::size(vk_viewports), + stdr::data(vk_viewports)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::set_scissor(UInt32 first_scissor, + std::span scissors) noexcept -> void { + expects(m_state == State::RECORDING); + + const auto vk_scissors = scissors + | stdv::transform(monadic::to_vk()) + | stdr::to(); + + vk_call(m_vk_device_table->vkCmdSetScissor, + m_vk_handle, + first_scissor, + stdr::size(vk_scissors), + stdr::data(vk_scissors)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::set_line_width(float width) noexcept -> void { + expects(m_state == State::RECORDING); + + vk_call(m_vk_device_table->vkCmdSetLineWidth, m_vk_handle, width); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::set_depth_bias(float constant_factor, + float clamp, + float slope_factor) noexcept -> void { + expects(m_state == State::RECORDING); + + vk_call(m_vk_device_table->vkCmdSetDepthBias, + m_vk_handle, + constant_factor, + clamp, + slope_factor); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::set_blend_constants(std::span constants) noexcept + -> void { + expects(m_state == State::RECORDING); + + float data[] = { constants[0], constants[1], constants[2], constants[3] }; + + vk_call(m_vk_device_table->vkCmdSetBlendConstants, m_vk_handle, data); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::set_depth_bounds(float min, float max) noexcept -> void { + expects(m_state == State::RECORDING); + + vk_call(m_vk_device_table->vkCmdSetDepthBounds, m_vk_handle, min, max); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::set_stencil_compare_mask(StencilFaceFlag face, UInt32 mask) noexcept + -> void { + expects(m_state == State::RECORDING); + + vk_call(m_vk_device_table->vkCmdSetStencilCompareMask, + m_vk_handle, + to_vk(face), + mask); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::set_stencil_write_mask(StencilFaceFlag face, UInt32 mask) noexcept + -> void { + expects(m_state == State::RECORDING); + + vk_call(m_vk_device_table->vkCmdSetStencilWriteMask, + m_vk_handle, + to_vk(face), + mask); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::set_stencil_reference(StencilFaceFlag face, + UInt32 reference) noexcept -> void { + expects(m_state == State::RECORDING); + + vk_call(m_vk_device_table->vkCmdSetStencilReference, + m_vk_handle, + to_vk(face), + reference); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::dispatch(UInt32 group_count_x, + UInt32 group_count_y, + UInt32 group_count_z) noexcept -> void { + expects(m_state == State::RECORDING); + + vk_call(m_vk_device_table->vkCmdDispatch, + m_vk_handle, + group_count_x, + group_count_y, + group_count_z); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::draw(UInt32 vertex_count, + UInt32 instance_count, + UInt32 first_vertex, + UInt32 first_instance) noexcept -> void { + 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); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::draw_indexed(UInt32 index_count, + UInt32 instance_count, + UInt32 first_index, + Int32 vertex_offset, + UInt32 first_instance) noexcept -> void { + 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); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::draw_indirect(const Buffer& buffer, + RangeExtent offset, + UInt32 draw_count, + UInt32 stride) noexcept -> void { + 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); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::draw_indexed_indirect(const Buffer& buffer, + RangeExtent offset, + UInt32 draw_count, + UInt32 stride) noexcept -> void { + 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); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::bind_vertex_buffers(std::span> buffers, + std::span offsets) noexcept + -> void { + expects(m_state == State::RECORDING); + expects(not std::empty(buffers)); + expects(std::size(buffers) == std::size(offsets)); + + const auto vk_buffers = buffers + | stdv::transform(monadic::to_vkhandle()) + | stdr::to(); + + vk_call(m_vk_device_table->vkCmdBindVertexBuffers, + m_vk_handle, + 0, + stdr::size(vk_buffers), + stdr::data(vk_buffers), + stdr::data(offsets)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::bindIndexBuffer(const Buffer& buffer, + UInt64 offset, + bool large_indices) noexcept -> void { + 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); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer:: + bind_descriptor_sets(const Pipeline& pipeline, + const PipelineLayout& layout, + std::span> descriptor_sets, + std::span dynamic_offsets) noexcept -> void { + expects(m_state == State::RECORDING); + + const auto bind_point = (pipeline.type() == Pipeline::Type::Raster) + ? VK_PIPELINE_BIND_POINT_GRAPHICS + : VK_PIPELINE_BIND_POINT_COMPUTE; + + const auto vk_descriptor_sets = descriptor_sets + | stdv::transform(monadic::to_vkhandle()) + | stdr::to(); + + vk_call(m_vk_device_table->vkCmdBindDescriptorSets, + m_vk_handle, + bind_point, + to_vkhandle(layout), + 0, + stdr::size(vk_descriptor_sets), + stdr::data(vk_descriptor_sets), + stdr::size(dynamic_offsets), + stdr::data(dynamic_offsets)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::copy_buffer(const Buffer& src, + const Buffer& dst, + RangeExtent size, + UInt64 src_offset, + UInt64 dst_offset) noexcept -> void { + const auto vk_copy_buffers = std::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)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::copy_buffer_to_image(const Buffer& src, + const IsImage auto& dst, + std::span + buffer_image_copies) noexcept -> void { + expects(m_state == State::RECORDING); + + const auto DEFAULT_COPY = std::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(); + + vk_call(m_vk_device_table->vkCmdCopyBufferToImage, to_vk(src), to_vk(dst), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, std::ranges::size(vk_copy_regions), std::ranges::data(vk_copy_regions))); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::copy_image_to_buffer(const IsImage auto& src, + const Buffer& dst, + std::span + buffer_image_copies) noexcept -> void { + expects(m_state == State::RECORDING); + + const auto DEFAULT_COPY = std::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, to_vk(src), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, to_vk(dst), std::ranges::size(vk_copy_regions), std::ranges::data(vk_copy_regions))); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::copy_image(const IsImage auto& src, + const IsImage auto& dst, + ImageLayout src_layout, + ImageLayout dst_layout, + const ImageSubresourceLayers& src_subresource_layers, + const ImageSubresourceLayers& dst_subresource_layers, + const math::ExtentU& extent) noexcept -> void { + expects(m_state == State::RECORDING); + + const auto vk_src_subresource_layers = VkImageSubresourceLayers { + .aspectMask = 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), + .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, + .dstSubresource = vk_dst_subresource_layers, + .extent = 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), + vk_regions); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::resolve_image(const IsImage auto& src, + const IsImage auto& dst, + ImageLayout src_layout, + ImageLayout dst_layout, + const ImageSubresourceLayers& src_subresource_layers, + const ImageSubresourceLayers& + dst_subresource_layers) noexcept -> void { + expects(m_state == State::RECORDING); + + const auto vk_extent = to_vk(dst.extent()); + + const auto vk_src_subresource_layers = VkImageSubresourceLayers { + .aspectMask = 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), + .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, + .dstSubresource = vk_dst_subresource_layers, + .extent = vk_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), + vk_regions); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::blit_image(const IsImage auto& src, + const IsImage auto& dst, + ImageLayout src_layout, + ImageLayout dst_layout, + std::span regions, + Filter filter) noexcept -> void { + expects(m_state == State::RECORDING); + + const auto vk_regions + = regions + | stdv::transform([](auto&& region) noexcept { + const auto vk_src_subresource_layers = vk::ImageSubresourceLayers { + .aspectMask = narrow(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 = vk::ImageSubresourceLayers { + .aspectMask = narrow(region.dst.aspect_mask), + .mipLevel = region.dst.mip_level, + .baseArrayLayer = region.dst.base_array_layer, + .layerCount = region.dst.layer_count + }; + + return vk::ImageBlit { + .srcSubresource = vk_src_subresource_layers, + .srcOffsets = std::array { narrow(region.src_offset[0]), + narrow(region.src_offset[1]) }, + .dstSubresource = vk_dst_subresource_layers, + .dstOffsets = std::array { narrow(region.dst_offset[0]), + narrow(region.dst_offset[1]) }, + }; + }) + | stdr::to(); + + m_vk_handle.blit_image(to_vkhandle(src), + narrow(src_layout), + to_vkhandle(dst), + narrow(dst_layout), + vk_regions, + narrow(filter)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::transition_image_layout(const IsImage auto& image, + ImageLayout src_layout, + ImageLayout dst_layout, + const ImageSubresourceRange& + subresource_range) noexcept -> void { + expects(m_state == State::RECORDING); + + const auto vk_src_layout = narrow(src_layout); + const auto vk_dst_layout = narrow(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); + + const auto src_stage = src_access->second.second; + const auto dst_stage = dst_access->second.second; + + const auto vk_subresource_range = vk::ImageSubresourceRange { + .aspectMask = narrow(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 { + vk::ImageMemoryBarrier { + .srcAccessMask = src_access->second.first, + .dstAccessMask = dst_access->second.first, + .oldLayout = vk_src_layout, + .newLayout = vk_dst_layout, + .srcQueueFamilyIndex = vk::QueueFamilyIgnored, + .dstQueueFamilyIndex = vk::QueueFamilyIgnored, + .image = to_vkhandle(image), + .subresource_range = vk_subresource_range } + }; + + m_vk_handle.pipeline_barrier(src_stage, dst_stage, {}, {}, {}, barriers); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline 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 -> void { + const auto vk_memory_barriers + = memory_barriers + | stdv::transform([](auto&& barrier) noexcept -> decltype(auto) { + return vk::MemoryBarrier { + .srcAccessMask = narrow(barrier.src), + .dstAccessMask = narrow(barrier.dst), + }; + }) + | stdr::to(); + + const auto vk_buffer_memory_barriers + = buffer_memory_barriers + | stdv::transform([](auto&& barrier) noexcept -> decltype(auto) { + return vk::BufferMemoryBarrier { + .srcAccessMask = narrow(barrier.src), + .dstAccessMask = narrow(barrier.dst), + .srcQueueFamilyIndex = barrier.src_queue_family_index, + .dstQueueFamilyIndex = barrier.dst_queue_family_index, + .buffer = to_vkhandle(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 = vk::ImageSubresourceRange { + .aspectMask = narrow(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 vk::ImageMemoryBarrier { + .srcAccessMask = narrow(barrier.src), + .dstAccessMask = narrow(barrier.dst), + .oldLayout = narrow(barrier.old_layout), + .newLayout = narrow(barrier.new_layout), + .srcQueueFamilyIndex = barrier.src_queue_family_index, + .dstQueueFamilyIndex = barrier.dst_queue_family_index, + .image = to_vkhandle(barrier.image), + .subresource_range = vk_subresource_range + }; + }) + | stdr::to(); + + m_vk_handle.pipeline_barrier(narrow(src_mask), + narrow(dst_mask), + narrow(dependency), + vk_memory_barriers, + vk_buffer_memory_barriers, + vk_image_memory_barriers); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::push_constants(const PipelineLayout& pipeline_layout, + ShaderStageFlag stage, + std::span data, + UInt32 offset) noexcept -> void { + expects(m_state == State::RECORDING); + expects(not std::empty(data)); + + m_vk_handle.push_constants(to_vkhandle(pipeline_layout), + narrow(stage), + offset, + data); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::execute_sub_command_buffers(std::span> + commandbuffers) noexcept -> void { + expects(m_state == State::RECORDING); + + constexpr auto expectsSecondary = [](auto&& cmb) noexcept -> decltype(auto) { + expects(cmb->level() == CommandBufferLevel::Secondary); + return cmb; + }; + + const auto vk_command_buffers = commandbuffers + | stdv::transform(core : + .monadic::map(expectsSecondary, + monadic::to_vkhandle())) + | stdr::to(); + + m_vk_handle.executeCommands(vk_command_buffers); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandBuffer::native_handle() const noexcept -> const vk::raii::CommandBuffer& { + return m_vk_handle; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline CommandPool::CommandPool(const Device& device, Tag) noexcept + : m_vk_device { device.native_handle() }, + m_vk_device_table { as_ref(device.device_table()) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandPool::create(const Device& device) noexcept -> Expected try { + 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 = allocate(device, PrivateFuncTag {}).transform_error(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(const Device& device, + CommandBufferLevel level) const noexcept + -> CommandBuffer { + return std::move(create_command_buffers(device, 1, level).front()); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandPool::create_command_buffers(const Device& device, + RangeExtent count, + CommandBufferLevel level) const noexcept + -> std::vector { + return create_vk_command_buffers(device, count, level) + | stdv::as_rvalue + | stdv::transform([this, &level](vk::raii::CommandBuffer&& cmb) noexcept + -> decltype(auto) { + return CommandBuffer::create(level, + std::move(cmb), + bind_front(&CommandPool::deleteVkCommandBuffer, + this)); + }) + | stdr::to(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandPool::allocate_command_buffer(const Device& device, + CommandBufferLevel level) const noexcept + -> Heap { + return std::move(allocate_command_buffers(device, 1, level).front()); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandPool::allocate_command_buffers(const Device& device, + RangeExtent count, + CommandBufferLevel level) const noexcept + -> std::vector> { + return create_vk_command_buffers(device, count, level) + | stdv::as_rvalue + | stdv::transform([this, &level](vk::raii::CommandBuffer&& cmb) noexcept + -> decltype(auto) { + return CommandBuffer::allocate(level, + std::move(cmb), + bind_front(&CommandPool::deleteVkCommandBuffer, + this)); + }) + | stdr::to(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandPool::native_handle() const noexcept -> VkCommandPool { + return m_vk_handle; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandPool::deleteVkCommandBuffer([[maybe_unused]] VkCommandBuffer&& cmb) noexcept + -> void { + // auto lock = std::unique_lock { m_reuse_mutex }; + // m_reusable_command_buffers.emplace_back(std::move(cmb)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto CommandPool::do_init(VkCommandBuffer&& cmb) noexcept -> Expected { + 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 + }; + + return vk_call(m_vk_device_table->vkCreateCommandPool, m_vk_device, &create_info, nullptr) + .transform(core::monadic::set(m_vk_handle)) + .transform_error(core::monadic::to_vk()); + } +} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/execution/descriptors.mpp b/modules/stormkit/gpu/execution/descriptors.mpp new file mode 100644 index 000000000..c17a02aaf --- /dev/null +++ b/modules/stormkit/gpu/execution/descriptors.mpp @@ -0,0 +1,496 @@ +// 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:descriptors; + +import std; + +import stormkit.core; +import stormkit.gpu.core; +import stormkit.gpu.resource; +import stormkit.gpu.vulkan; + +export { + namespace stormkit::gpu { + struct BufferDescriptor { + DescriptorType type = DescriptorType::UNIFORM_BUFFER; + UInt32 binding; + Ref buffer; + UInt32 range; + UInt32 offset; + }; + + struct ImageDescriptor { + DescriptorType type = DescriptorType::COMBINED_IMAGE_SAMPLER; + UInt32 binding; + ImageLayout layout; + Ref image_view; + Ref sampler; + }; + + using Descriptor = std::variant; + class DescriptorPool; + + class STORMKIT_API DescriptorSet { + 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; + + private: + using Deleter = std::function; + + DescriptorSet(std::vector&& type, + VkDescriptorSet&& sets, + Deleter&& deleter) noexcept; + + std::vector m_types; + + VkDescriptorSet m_vk_handle; + + Deleter m_deleter; + friend class DescriptorPool; + }; + + struct DescriptorSetLayoutBinding { + UInt32 binding; + DescriptorType type; + ShaderStageFlag stages; + RangeExtent 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 = { { [this](auto handle) noexcept { + m_vk_device_table->vkDestroyDescriptorSetLayout(m_vk_device, handle, nullptr); + } } }; + }; + + class STORMKIT_API DescriptorPool { + struct PrivateFuncTag {}; + + public: + static constexpr auto DEBUG_TYPE = DebugObjectType::DESCRIPTOR_POOL; + + struct Size { + DescriptorType type; + UInt32 descriptor_count; + }; + + static auto create(const Device& device, + std::span sizes, + UInt32 max_sets) noexcept -> Expected; + static auto allocate(const Device& device, + std::span sizes, + UInt32 max_sets) noexcept -> Expected>; + ~DescriptorPool() noexcept; + + DescriptorPool(const DescriptorPool&) = delete; + auto operator=(const DescriptorPool&) -> DescriptorPool& = delete; + + DescriptorPool(DescriptorPool&&) noexcept; + auto operator=(DescriptorPool&&) noexcept -> DescriptorPool&; + + [[nodiscard]] + auto native_handle() const noexcept -> VkDescriptorPool; + + DescriptorPool(const Device&, PrivateFuncTag) noexcept; + + private: + auto do_init(std::span, UInt32) noexcept -> Expected; + auto create_descriptor_sets(RangeExtent, const DescriptorSetLayout&) const + -> std::pair, std::vector>; + auto deleteDescriptorSet(VkDescriptorSet&) const -> void; + + VkDevice m_vk_device = nullptr; + Ref m_vk_device_table; + VkRAIIHandle m_vk_handle { { [this](auto handle) noexcept { + m_vk_device_table->vkDestroyDescriptorPool(m_vk_device, handle, nullptr); + } } }; + }; + } // 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(std::vector&& type, + VkDescriptorSet&& set, + Deleter&& deleter) noexcept + : m_types { std::move(type) }, 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) -> void { + // const auto [buffers, images] = [&descriptors]() -> decltype(auto) { + // const auto buffers_count = jk + + // auto buffers = std::vector {}; + // auto images = std::vector {}; + // buffers.reserve(std::size(descriptors)); + // images.reserve(std::size(descriptors)); + + // std::ranges:: + // for_each(descriptors, + // core :.monadic::either( + // [&buffers](const BufferDescriptor& descriptor) noexcept -> decltype(auto) + // { + // buffers.emplace_back(vk::DescriptorBufferInfo {} + // .setBuffer(to_vkhandle(descriptor.buffer)) + // .setOffset(descriptor.offset) + // .setRange(descriptor.range)); + // }, + // [&images](const ImageDescriptor& descriptor) noexcept -> decltype(auto) { + // images + // .emplace_back(vk::DescriptorImageInfo {} + // .setSampler(to_vkhandle(descriptor.sampler)) + // .setImageView(to_vkhandle(descriptor.image_view)) + // .setImageLayout(narrow(descriptor + // .layout))); + // })); + + // return std::pair { std::move(buffers), std::move(images) }; + // }(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto DescriptorSet::types() const noexcept -> const std::vector& { + return m_types; + } + + ///////////////////////////////////// + ///////////////////////////////////// + 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()) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + 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([](auto&& binding) static noexcept { + return VkDescriptorSetLayoutBinding { + .binding = binding.binding, + .descriptorType = to_vk(binding + .type), + .descriptorCount = as(binding.descriptor_count), + .stageFlags = to_vk< + VkShaderStageFlagBits>(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()) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto DescriptorPool::create(const Device& device, + std::span extents, + UInt32 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, + UInt32 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 + inline auto DescriptorPool::native_handle() const noexcept -> VkDescriptorPool { + return m_vk_handle; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto DescriptorPool::do_init(std::span sizes, UInt32 max_sets) noexcept + -> Expected { + const auto pool_sizes = sizes + | std::views::transform([](auto&& 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()); + } +} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/execution/pipeline.mpp b/modules/stormkit/gpu/execution/pipeline.mpp new file mode 100644 index 000000000..e76d0138b --- /dev/null +++ b/modules/stormkit/gpu/execution/pipeline.mpp @@ -0,0 +1,429 @@ +// 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:pipeline; + +import std; + +import stormkit.core; +import stormkit.gpu.core; +import stormkit.gpu.vulkan; + +import :raster_pipeline; +import :render_pass; + +export namespace stormkit::gpu { + class CommandBuffer; + + class STORMKIT_API PipelineCache { + struct PrivateFuncTag {}; + + public: + static constexpr auto DEBUG_TYPE = DebugObjectType::PIPELINE_CACHE; + + static auto create(const Device& device, std::filesystem::path cache_path) noexcept + -> Expected; + static auto allocate(const Device& device, std::filesystem::path cache_path) noexcept + -> Expected>; + ~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() noexcept -> Expected; + auto create_new_pipeline_cache() noexcept -> VulkanExpected; + auto read_pipeline_cache() noexcept -> VulkanExpected; + auto save_cache() noexcept -> void; + + static constexpr auto MAGIC = UInt32 { 0xDEADBEEF }; + static constexpr auto VERSION = UInt32 { 1u }; + + struct SerializedCache { + struct { + UInt32 magic; + RangeExtent data_size; + UInt64 data_hash; + } guard; + + struct { + UInt32 version; + UInt64 vendor_id; + UInt64 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 = { { [this](auto handle) noexcept { + m_vk_device_table->vkDestroyPipelineCache(m_vk_device, handle, nullptr); + } } }; + }; + + 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; + static auto allocate(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 = { { [this](auto handle) noexcept { + m_vk_device_table->vkDestroyPipelineLayout(m_vk_device, handle, nullptr); + } } }; + }; + + 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; + static auto allocate(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 = { { [this](auto handle) noexcept { + m_vk_device_table->vkDestroyPipeline(m_vk_device, handle, nullptr); + } } }; + }; +} // 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()) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline PipelineCache::~PipelineCache() noexcept { + if (m_vk_handle) save_cache(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + 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::create(const Device& device, + std::filesystem::path cache_path) noexcept + -> Expected { + auto cache = PipelineCache { device, std::move(cache_path), PrivateFuncTag {} }; + return cache.do_init().transform(core::monadic::consume(cache)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto PipelineCache::allocate(const Device& device, + std::filesystem::path cache_path) noexcept + -> Expected> { + auto cache = allocate_unsafe(device, + std::move(cache_path), + PrivateFuncTag {}); + return cache->do_init().transform(core::monadic::consume(cache)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto PipelineCache::native_handle() const noexcept -> VkPipelineCache { + return m_vk_handle; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto PipelineCache::do_init() noexcept -> Expected { + return either(std::filesystem::exists(m_path), + bind_front(&PipelineCache::read_pipeline_cache, this), + bind_front(&PipelineCache::create_new_pipeline_cache, this)) + .transform_error(monadic::from_vk()); + } + + ///////////////////////////////////// + ///////////////////////////////////// + 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()) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + 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 {} }; + return pipeline_layout.do_init().transform(core::monadic::consume(pipeline_layout)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto PipelineLayout::allocate(const Device& device, + const RasterPipelineLayout& layout) noexcept + -> Expected> { + auto pipeline_layout = allocate_unsafe(device, layout, PrivateFuncTag {}); + return pipeline_layout->do_init().transform(core::monadic::consume(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_vkhandle()) + | stdr::to(); + + const auto push_constant_ranges = m_layout.push_constant_ranges + | stdv::transform([](auto&& + push_constant_range) noexcept { + return VkPushConstantRange { + .stageFlags = to_vk< + VkShaderStageFlagBits>(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), + }; + + return vk_call(m_vk_device_table->vkCreatePipelineLayout, + m_vk_device, + &create_info, + nullptr) + .transform(core::monadic::set(m_vk_handle)) + .transform_error(monadic::from_vk()); + } + + ///////////////////////////////////// + ///////////////////////////////////// + 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()) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + 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 {} }; + return pipeline.do_init(layout, render_pass, std::move(cache)) + .transform(core::monadic::consume(pipeline)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto Pipeline::allocate(const Device& device, + const RasterPipelineState& state, + const PipelineLayout& layout, + const RenderPass& render_pass, + OptionalRef cache) noexcept + -> Expected> { + auto pipeline = allocate_unsafe(device, state, PrivateFuncTag {}); + return pipeline->do_init(layout, render_pass, std::move(cache)) + .transform(core::monadic::consume(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/RasterPipelineState.mpp b/modules/stormkit/gpu/execution/raster_pipeline.mpp similarity index 79% rename from modules/stormkit/Gpu/Execution/RasterPipelineState.mpp rename to modules/stormkit/gpu/execution/raster_pipeline.mpp index 1675850f8..8d8484984 100644 --- a/modules/stormkit/Gpu/Execution/RasterPipelineState.mpp +++ b/modules/stormkit/gpu/execution/raster_pipeline.mpp @@ -6,29 +6,30 @@ module; #include -export module stormkit.Gpu:Execution.RasterPipelineState; +export module stormkit.gpu.execution:raster_pipeline; import std; import stormkit.core; -import stormkit.Gpu.Vulkan; -import :Core; -import :Resource; -import :Execution.Descriptors; +import stormkit.gpu.core; +import stormkit.gpu.resource; +import stormkit.gpu.vulkan; + +import :descriptors; export namespace stormkit::gpu { struct VertexBindingDescription { UInt32 binding; UInt32 stride; - VertexInputRate input_rate = VertexInputRate::Vertex; + VertexInputRate input_rate = VertexInputRate::VERTEX; }; struct VertexInputAttributeDescription { - UInt32 location; - UInt32 binding; - Format format; - UInt32 offset; + UInt32 location; + UInt32 binding; + PixelFormat format; + UInt32 offset; }; struct RasterPipelineVertexInputState { @@ -37,7 +38,7 @@ export namespace stormkit::gpu { }; struct RasterPipelineInputAssemblyState { - PrimitiveTopology topology = PrimitiveTopology::Triangle_List; + PrimitiveTopology topology = PrimitiveTopology::TRIANGLE_LIST; bool primitive_restart_enable = false; }; @@ -49,10 +50,10 @@ export namespace stormkit::gpu { struct RasterPipelineRasterizationState { bool depth_clamp_enable = false; bool rasterizer_discard_enable = false; - PolygonMode polygon_mode = PolygonMode::Fill; + PolygonMode polygon_mode = PolygonMode::FILL; float line_width = 1; - CullModeFlag cull_mode = CullModeFlag::Back; - FrontFace front_face = FrontFace::Clockwise; + CullModeFlag cull_mode = CullModeFlag::BACK; + FrontFace front_face = FrontFace::CLOCKWISE; }; struct RasterPipelineMultiSampleState { @@ -64,18 +65,18 @@ export namespace stormkit::gpu { ColorComponentFlag color_write_mask = ColorComponentFlag::RGBA; bool blend_enable = false; - BlendFactor src_color_blend_factor = BlendFactor::One; - BlendFactor dst_color_blend_factor = BlendFactor::Zero; - BlendOperation color_blend_operation = BlendOperation::Add; + BlendFactor src_color_blend_factor = BlendFactor::ONE; + BlendFactor dst_color_blend_factor = BlendFactor::ZERO; + BlendOperation color_blend_operation = BlendOperation::ADD; - BlendFactor src_alpha_blend_factor = BlendFactor::One; - BlendFactor dst_alpha_blend_factor = BlendFactor::Zero; - BlendOperation alpha_blend_operation = BlendOperation::Substract; + BlendFactor src_alpha_blend_factor = BlendFactor::ONE; + BlendFactor dst_alpha_blend_factor = BlendFactor::ZERO; + BlendOperation alpha_blend_operation = BlendOperation::SUBTRACT; }; struct RasterPipelineColorBlendState { bool logic_operation_enable = false; - LogicOperation logic_operation = LogicOperation::Copy; + LogicOperation logic_operation = LogicOperation::COPY; std::vector attachments; std::array blend_constants = { 0.f, 0.f, 0.f, 0.f }; }; @@ -92,7 +93,7 @@ export namespace stormkit::gpu { bool depth_test_enable = false; bool depth_write_enable = false; - CompareOperation depth_compare_op = CompareOperation::Less; + CompareOperation depth_compare_op = CompareOperation::LESS; bool depth_bounds_test_enable = false; diff --git a/modules/stormkit/gpu/execution/render_pass.mpp b/modules/stormkit/gpu/execution/render_pass.mpp new file mode 100644 index 000000000..be0bcbd08 --- /dev/null +++ b/modules/stormkit/gpu/execution/render_pass.mpp @@ -0,0 +1,392 @@ +// 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:render_pass; + +import std; + +import stormkit.core; +import stormkit.gpu.core; +import stormkit.gpu.resource; +import stormkit.gpu.vulkan; + +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::ExtentU& extent, + std::vector> attachments) noexcept + -> Expected; + static auto allocate(const Device& device, + const RenderPass& render_pass, + const math::ExtentU& 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::ExtentU&; + [[nodiscard]] + auto attachments() const noexcept -> const std::vector>&; + + [[nodiscard]] + auto native_handle() const noexcept -> VkFramebuffer; + + FrameBuffer(const Device&, + const math::ExtentU&, + std::vector>, + PrivateFuncTag) noexcept; + + private: + auto do_init(const RenderPass&) noexcept -> Expected; + + math::ExtentU m_extent = { 0, 0 }; + std::vector> m_attachments; + + VkDevice m_vk_device = nullptr; + Ref m_vk_device_table; + VkRAIIHandle m_vk_handle = { { [this](auto handle) noexcept { + m_vk_device_table->vkDestroyFramebuffer(m_vk_device, handle, nullptr); + } } }; + }; + + 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 { + UInt32 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::ExtentU& extent, + std::vector> attachments) const noexcept + -> Expected; + auto allocate_frame_buffer(const Device& device, + const math::ExtentU& 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 = { { [this](auto handle) noexcept { + m_vk_device_table->vkDestroyRenderPass(m_vk_device, handle, nullptr); + } } }; + }; + } // namespace stormkit::gpu + + HASH_FUNC(stormkit::gpu::AttachmentDescription, + 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) + HASH_FUNC(stormkit::gpu::Subpass::Ref, value.attachment_id, value.layout) + HASH_FUNC(stormkit::gpu::Subpass, + value.bind_point, + value.color_attachment_refs, + value.depth_attachment_ref, + value.resolve_attachment_refs) + HASH_FUNC(stormkit::gpu::RenderPassDescription, value.attachments, value.subpasses) +} + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit::gpu { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline FrameBuffer::FrameBuffer(const Device& device, + const math::ExtentU& 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()) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + inline auto FrameBuffer::create(const Device& device, + const RenderPass& render_pass, + const math::ExtentU& 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::ExtentU& 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::ExtentU& { + 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_vkhandle()) + | std::ranges::to(); + + const auto create_info = VkFramebufferCreateInfo { + .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .renderPass = to_vkhandle(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()) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + 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::ExtentU& 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::ExtentU& 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 diff --git a/modules/stormkit/gpu/execution/swapchain.mpp b/modules/stormkit/gpu/execution/swapchain.mpp new file mode 100644 index 000000000..30a94f8a1 --- /dev/null +++ b/modules/stormkit/gpu/execution/swapchain.mpp @@ -0,0 +1,152 @@ +// 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:swapchain; + +import std; + +import stormkit.core; +import stormkit.gpu.core; +import stormkit.gpu.vulkan; +import stormkit.gpu.resource; + +export namespace stormkit::gpu { + class STORMKIT_API SwapChain { + struct PrivateFuncTag {}; + + public: + static constexpr auto DEBUG_TYPE = DebugObjectType::SWAPCHAIN; + + using ImageID = UInt32; + + struct NextImage { + Result result; + ImageID id; + }; + + static auto create(const Device& device, + const Surface& surface, + const math::ExtentU& extent, + OptionalRef old_swapchain = std::nullopt) noexcept + -> Expected; + static auto allocate(const Device& device, + const Surface& surface, + const math::ExtentU& 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 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::ExtentU&, VkSwapchainKHR) noexcept + -> Expected; + + math::ExtentU m_extent; + PixelFormat m_pixel_format; + UInt32 m_image_count; + + VkDevice m_vk_device; + Ref m_vk_device_table; + VkRAIIHandle m_vk_handle = { [this](auto&& handle) noexcept { + m_vk_device_table->vkDestroySwapchainKHR(m_vk_device, handle, nullptr); + } }; + std::vector m_images; + }; +} // namespace stormkit::gpu + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit::gpu { + STORMKIT_FORCE_INLINE + SwapChain::SwapChain(const Device& device, PrivateFuncTag) noexcept + : m_vk_device { device.native_handle() }, + m_vk_device_table { as_ref(device.device_table()) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + SwapChain::~SwapChain() + = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + SwapChain::SwapChain(SwapChain&&) noexcept + = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto SwapChain::operator=(SwapChain&&) noexcept -> SwapChain& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto SwapChain::create(const Device& device, + const Surface& surface, + const math::ExtentU& extent, + OptionalRef old_swapchain) noexcept -> Expected { + auto swapchain = SwapChain { device, PrivateFuncTag {} }; + return swapchain + .do_init(device, + surface, + extent, + old_swapchain.has_value() ? old_swapchain.value()->native_handle() : nullptr) + .transform(core::monadic::consume(swapchain)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto SwapChain::allocate(const Device& device, + const Surface& surface, + const math::ExtentU& extent, + OptionalRef old_swapchain) noexcept + -> Expected> { + auto swapchain = std::make_unique(device, PrivateFuncTag {}); + return swapchain + ->do_init(device, + surface, + extent, + old_swapchain.has_value() ? old_swapchain.value()->native_handle() : nullptr) + .transform(core::monadic::consume(swapchain)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto SwapChain::images() const noexcept -> const std::vector& { + return m_images; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto SwapChain::native_handle() const noexcept -> VkSwapchainKHR { + return m_vk_handle; + } +} // namespace stormkit::gpu diff --git a/modules/stormkit/Gpu.mpp b/modules/stormkit/gpu/resource.mpp similarity index 53% rename from modules/stormkit/Gpu.mpp rename to modules/stormkit/gpu/resource.mpp index 89c3b9fe3..53629a51b 100644 --- a/modules/stormkit/Gpu.mpp +++ b/modules/stormkit/gpu/resource.mpp @@ -1,10 +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.Gpu; - -// export import stormkit.Gpu:Core.Compute; -export import :Core; -export import :Execution; -export import :Resource; +// 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.resource; + +export import :buffer; +export import :image; +export import :shader; diff --git a/modules/stormkit/gpu/resource/buffer.mpp b/modules/stormkit/gpu/resource/buffer.mpp new file mode 100644 index 000000000..7ca6e1a78 --- /dev/null +++ b/modules/stormkit/gpu/resource/buffer.mpp @@ -0,0 +1,325 @@ +// 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:buffer; + +import std; + +import stormkit.core; +import stormkit.gpu.core; +import stormkit.gpu.vulkan; + +export namespace stormkit::gpu { + class STORMKIT_API Buffer { + struct PrivateFuncTag {}; + + public: + struct CreateInfo { + BufferUsageFlag usages; + RangeExtent 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 -> RangeExtent; + [[nodiscard]] + auto memory_property() const noexcept -> MemoryPropertyFlag; + + auto map(RangeOffset offset) noexcept -> Expected; + auto map(RangeOffset offset, RangeExtent size) noexcept -> Expected; + + template + auto map_as(RangeOffset offset) noexcept -> Expected>; + + template + [[nodiscard]] + auto data(this Self& self) noexcept -> meta::ForwardConst*; + template + [[nodiscard]] + auto data(this Self& self, RangeExtent size) noexcept + -> meta::If, ByteView, MutableByteView>; + + template + [[nodiscard]] + auto data_as(this auto& self) noexcept -> Ref; + + auto flush(RangeOffset offset, RangeExtent size) noexcept -> Expected; + auto unmap() noexcept -> void; + + [[nodiscard]] + auto is_persistently_mapped() const noexcept -> bool; + + auto upload(std::span data, RangeOffset offset = 0) noexcept -> Expected; + + template T> + auto upload(const T& data, RangeOffset 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(UInt, + VkMemoryPropertyFlagBits, + const VkPhysicalDeviceMemoryProperties&, + const VkMemoryRequirements&) noexcept -> UInt; + + auto do_init(MemoryPropertyFlag memory_properties) noexcept -> Expected; + + BufferUsageFlag m_usages = {}; + RangeExtent 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 = { [this](auto&& handle) noexcept { + vmaFreeMemory(m_vma_allocator, handle); + } }; + VkRAIIHandle m_vk_handle = { [this](auto handle) noexcept { + m_vk_device_table->vkDestroyBuffer(m_vk_device, handle, nullptr); + } }; + }; + + struct BufferMemoryBarrier { + AccessFlag src; + AccessFlag dst; + + UInt32 src_queue_family_index = QUEUE_FAMILY_IGNORED; + UInt32 dst_queue_family_index = QUEUE_FAMILY_IGNORED; + + const Buffer& buffer; + RangeExtent size; + UInt64 offset = 0; + }; +} // namespace stormkit::gpu + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit::gpu { + ///////////////////////////////////// + ///////////////////////////////////// + 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() } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + Buffer::~Buffer() + = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + Buffer::Buffer(Buffer&& other) noexcept + = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Buffer::operator=(Buffer&& other) noexcept -> Buffer& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_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 + 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 + auto Buffer::usages() const noexcept -> BufferUsageFlag { + expects(m_vma_allocation and m_vk_handle); + return m_usages; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Buffer::size() const noexcept -> RangeExtent { + expects(m_vma_allocation and m_vk_handle); + return m_size; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Buffer::map(RangeOffset 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 + auto Buffer::map(RangeOffset offset, RangeExtent 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 + auto Buffer::map_as(RangeOffset 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 + auto Buffer::data(this Self& self) noexcept -> meta::ForwardConst* { + expects(self.m_vma_allocation and self.m_vk_handle); + expects(self.m_mapped_pointer); + + using Out = meta::ForwardConst*; + return std::bit_cast(self.m_mapped_pointer); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + auto Buffer::data(this Self& self, RangeExtent size) noexcept + -> meta::If, ByteView, MutableByteView> { + expects(self.m_vma_allocation and self.m_vk_handle); + expects(self.m_mapped_pointer); + + using Out = meta::If, ByteView, MutableByteView>; + return Out { std::bit_cast(self.m_mapped_pointer), size }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_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 = meta::ForwardConst*; + return as_ref_like(std::bit_cast(self.data())); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Buffer::flush(RangeOffset offset, RangeExtent 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 + auto Buffer::unmap() noexcept -> void { + expects(m_vma_allocation and m_vk_handle); + expects(not m_is_persistently_mapped, "unmapping to unmap persistent buffer !"); + + vk_call(vmaUnmapMemory, m_vma_allocator, m_vma_allocation); + + m_mapped_pointer = nullptr; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Buffer::upload(std::span data, RangeOffset offset) noexcept -> Expected { + 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 + auto Buffer::upload(const T& data, RangeOffset offset) noexcept -> Expected { + const auto bytes = as_bytes(data); + return upload(bytes, offset); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_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.mpp b/modules/stormkit/gpu/resource/image.mpp new file mode 100644 index 000000000..052962b03 --- /dev/null +++ b/modules/stormkit/gpu/resource/image.mpp @@ -0,0 +1,586 @@ +// 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:image; + +import std; + +import stormkit.core; +import stormkit.image; +import stormkit.gpu.core; +import stormkit.gpu.vulkan; + +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 = { [this](auto&& handle) noexcept { + m_vk_device_table->vkDestroySampler(m_vk_device, handle, nullptr); + } }; + }; + + 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 = { [this](auto&& handle) noexcept { + m_vk_device_table->vkDestroyImageView(m_vk_device, handle, nullptr); + } }; + }; + + class STORMKIT_API Image { + struct PrivateFuncTag {}; + + public: + struct CreateInfo { + math::ExtentU extent; + PixelFormat format = PixelFormat::RGBA8_UNORM; + UInt32 layers = 1u; + UInt32 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::ExtentU&; + [[nodiscard]] + auto format() const noexcept -> PixelFormat; + [[nodiscard]] + auto type() const noexcept -> ImageType; + [[nodiscard]] + auto samples() const noexcept -> SampleCountFlag; + [[nodiscard]] + auto layers() const noexcept -> UInt32; + [[nodiscard]] + auto faces() const noexcept -> UInt32; + [[nodiscard]] + auto mip_levels() const noexcept -> UInt32; + [[nodiscard]] + auto usages() const noexcept -> ImageUsageFlag; + + [[nodiscard]] + auto native_handle() const noexcept -> VkImage; + + Image(const Device&, const CreateInfo&, PrivateFuncTag) noexcept; + + private: + [[nodiscard]] + static auto create(const Device&, const CreateInfo&, VkImage&&) noexcept -> Image; + + auto do_init(const CreateInfo&) noexcept -> Expected; + auto do_init(const VkImageCreateInfo&, MemoryPropertyFlag) noexcept -> Expected; + + math::ExtentU m_extent = { 0, 0, 0 }; + PixelFormat m_format = {}; + UInt32 m_layers = 0; + UInt32 m_faces = 0; + UInt32 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 = { [this](auto&& handle) noexcept { + vmaFreeMemory(m_vma_allocator, handle); + } }; + VkRAIIHandle m_vk_handle = { [this](auto&& handle) noexcept { + m_vk_device_table->vkDestroyImage(m_vk_device, handle, nullptr); + } }; + }; + + struct ImageMemoryBarrier { + AccessFlag src; + AccessFlag dst; + + ImageLayout old_layout; + ImageLayout new_layout; + + UInt32 src_queue_family_index = QUEUE_FAMILY_IGNORED; + UInt32 dst_queue_family_index = QUEUE_FAMILY_IGNORED; + + const Image& image; + ImageSubresourceRange range; + }; +} // namespace stormkit::gpu + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit::gpu { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_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 + 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()) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + Sampler::~Sampler() + = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + Sampler::Sampler(Sampler&&) noexcept + = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Sampler::operator=(Sampler&&) noexcept -> Sampler& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_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 + 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 + auto Sampler::settings() const noexcept -> const Settings& { + return m_settings; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Sampler::native_handle() const noexcept -> VkSampler { + expects(m_vk_handle); + return m_vk_handle; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_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 + 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()) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + ImageView::~ImageView() + = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + ImageView::ImageView(ImageView&&) noexcept + = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto ImageView::operator=(ImageView&&) noexcept -> ImageView& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_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 + 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 + auto ImageView::type() const noexcept -> ImageViewType { + return m_type; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto ImageView::subresource_range() const noexcept -> const ImageSubresourceRange& { + return m_subresource_range; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto ImageView::native_handle() const noexcept -> VkImageView { + expects(m_vk_handle); + return m_vk_handle; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_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() } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + Image::~Image() + = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + Image::Image(Image&&) noexcept + = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Image::operator=(Image&&) noexcept -> Image& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_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 + 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 + auto Image::extent() const noexcept -> const math::ExtentU& { + return m_extent; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Image::format() const noexcept -> PixelFormat { + return m_format; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Image::type() const noexcept -> ImageType { + return m_type; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Image::samples() const noexcept -> SampleCountFlag { + return m_samples; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Image::layers() const noexcept -> UInt32 { + return m_layers; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Image::faces() const noexcept -> UInt32 { + return m_faces; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Image::mip_levels() const noexcept -> UInt32 { + return m_mip_levels; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Image::usages() const noexcept -> ImageUsageFlag { + return m_usages; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Image::native_handle() const noexcept -> VkImage { + expects(m_vk_handle); + return m_vk_handle; + } + + ///////////////////////////////////// + ///////////////////////////////////// + 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 + 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/shader.mpp b/modules/stormkit/gpu/resource/shader.mpp new file mode 100644 index 000000000..32972275c --- /dev/null +++ b/modules/stormkit/gpu/resource/shader.mpp @@ -0,0 +1,242 @@ +// 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:shader; + +import std; + +import stormkit.core; +import stormkit.gpu.core; +import stormkit.gpu.vulkan; + +export namespace stormkit::gpu { + class STORMKIT_API Shader { + struct PrivateFuncTag {}; + + public: + static constexpr auto DEBUG_TYPE = DebugObjectType::SHADER_MODULE; + + static auto load_from_file(const Device& device, + const std::filesystem::path& filepath, + ShaderStageFlag type) noexcept -> Expected; + 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 + -> Expected>; + 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 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 = { [this](auto&& handle) noexcept { + m_vk_device_table->vkDestroyShaderModule(m_vk_device, handle, nullptr); + } }; + }; +} // namespace stormkit::gpu + +//////////////////////////////////////////////////////////////////// +/// IMPLEMENTATION /// +//////////////////////////////////////////////////////////////////// + +namespace stormkit::gpu { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Shader::do_init() -> Expected { + const auto create_info = VkShaderModuleCreateInfo { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .codeSize = std::ranges::size(m_source), + .pCode = std::ranges::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 + 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()) } { + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + Shader::~Shader() + = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + Shader::Shader(Shader&&) noexcept + = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Shader::operator=(Shader&&) noexcept -> Shader& = default; + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Shader::load_from_file(const Device& device, + const std::filesystem::path& filepath, + ShaderStageFlag type) noexcept -> Expected { + auto stream = std::ifstream { filepath.string(), std::ios::binary | std::ios::ate }; + const auto size = stream.tellg(); + + auto spirv = std::vector(size); + read(stream, as_bytes(spirv)); + + auto shader = Shader { device, std::move(spirv), type, PrivateFuncTag {} }; + return shader.do_init().transform(core::monadic::consume(shader)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Shader::load_from_bytes(const Device& device, + std::span data, + ShaderStageFlag type) noexcept -> Expected { + auto shader = Shader { + device, + bytes_as>(data) | std::ranges::to(), + type, + PrivateFuncTag {} + }; + return shader.do_init().transform(core::monadic::consume(shader)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Shader::load_from_spirvid(const Device& device, + std::span data, + ShaderStageFlag type) noexcept -> Expected { + auto shader = Shader { device, + data | std::ranges::to(), + type, + PrivateFuncTag {} }; + return shader.do_init().transform(core::monadic::consume(shader)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Shader::allocate_and_load_from_file(const Device& device, + const std::filesystem::path& filepath, + ShaderStageFlag type) noexcept + -> Expected> { + auto stream = std::ifstream { filepath.string(), std::ios::binary | std::ios::ate }; + const auto size = stream.tellg(); + + auto spirv = std::vector(size); + read(stream, as_bytes(spirv)); + + auto shader = std::make_unique(device, std::move(spirv), type, PrivateFuncTag {}); + return shader->do_init().transform(core::monadic::consume(shader)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_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) + | std::ranges::to(), + type, + PrivateFuncTag {}); + return shader->do_init().transform(core::monadic::consume(shader)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_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 | std::ranges::to(), + type, + PrivateFuncTag {}); + return shader->do_init().transform(core::monadic::consume(shader)); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Shader::type() const noexcept -> ShaderStageFlag { + return m_type; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Shader::source() const noexcept -> const std::vector& { + return m_source; + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE + auto Shader::native_handle() const noexcept -> VkShaderModule { + return m_vk_handle; + } +} // namespace stormkit::gpu diff --git a/modules/stormkit/gpu/vulkan.mpp b/modules/stormkit/gpu/vulkan.mpp new file mode 100644 index 000000000..b21fbb5e7 --- /dev/null +++ b/modules/stormkit/gpu/vulkan.mpp @@ -0,0 +1,14 @@ +module; + +#include + +export module stormkit.gpu.vulkan; + +export import :utils; + +export extern "C" { +#include + +#define VMA_CALL_PRE STORMKIT_API +#include +} diff --git a/modules/stormkit/gpu/vulkan/utils.mpp b/modules/stormkit/gpu/vulkan/utils.mpp new file mode 100644 index 000000000..40659011f --- /dev/null +++ b/modules/stormkit/gpu/vulkan/utils.mpp @@ -0,0 +1,294 @@ +// 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.vulkan:utils; + +import std; + +import stormkit.core; +import stormkit.log; + +export namespace stormkit::gpu { + template + [[nodiscard]] + constexpr auto vk_make_version(T major, T minor, T patch) noexcept -> UInt32; + [[nodiscard]] + constexpr auto vk_version_major(std::integral auto version) noexcept -> UInt32; + [[nodiscard]] + constexpr auto vk_version_minor(std::integral auto version) noexcept -> UInt32; + [[nodiscard]] + constexpr auto vk_version_patch(std::integral auto version) noexcept -> UInt32; + + template + using VulkanExpected = std::expected; + + template + concept IsVulkanFuncWithResult = meta::Is, VkResult>; + + template + auto vk_call(Func&& func, Args&&... args) noexcept -> decltype(auto); + + template + requires(IsVulkanFuncWithResult) + [[nodiscard]] + auto vk_call(Func&& func, Args&&... args) noexcept -> decltype(auto); + + template + [[nodiscard]] + auto vk_call(Func&& func, Args&&... args) noexcept -> decltype(auto); + + template + [[nodiscard]] + auto vk_call(Func&& func, std::span success_result, Args&&... args) noexcept + -> T; + + template + requires(IsVulkanFuncWithResult or IsVulkanFuncWithResult) + [[nodiscard]] + auto vk_call(Func&& func, std::span success_result, Args&&... args) noexcept + -> VulkanExpected; + + template + [[nodiscard]] + auto vk_enumerate(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 + [[nodiscard]] + auto to_vkhandle(const T& value) noexcept -> decltype(auto); + + namespace monadic { + [[nodiscard]] + constexpr auto to_vkhandle() noexcept -> decltype(auto); + } // namespace monadic + + template + class VkRAIIHandle { + public: + // TODO move_only_function + using Deleter = std::function; + + constexpr VkRAIIHandle(Deleter deleter) noexcept : m_deleter { 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) } {} + + constexpr auto operator=(VkRAIIHandle&& other) noexcept -> VkRAIIHandle& { + if (this == &other) [[unlikely]] + return *this; + + m_value = std::exchange(other.m_value, nullptr); + + return *this; + } + + constexpr auto operator=(T&& value) noexcept -> void { + if (m_value) m_deleter(m_value); + m_value = 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 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 -> UInt32 { + 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 -> UInt32 { + return as(version >> 22u); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_CONST STORMKIT_INTRINSIC + inline constexpr auto vk_version_minor(std::integral auto version) noexcept -> UInt32 { + return as((version >> 12u) & 0x3ffu); + } + + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_CONST STORMKIT_INTRINSIC + inline constexpr auto vk_version_patch(std::integral auto version) noexcept -> UInt32 { + return as(version & 0xfffu); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + STORMKIT_CONST + inline auto vk_call(Func&& func, Args&&... args) noexcept -> decltype(auto) { + std::invoke(func, std::forward(args)...); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(IsVulkanFuncWithResult) + STORMKIT_FORCE_INLINE + STORMKIT_CONST + inline auto vk_call(Func&& func, Args&&... args) noexcept -> decltype(auto) { + return vk_call(func, { VK_SUCCESS }, std::forward(args)...); + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + STORMKIT_CONST + inline auto vk_call(Func&& func, Args&&... args) noexcept -> decltype(auto) { + if constexpr (IsVulkanFuncWithResult + or IsVulkanFuncWithResult) + return vk_call(func, { VK_SUCCESS }, std::forward(args)...); + else if constexpr (not 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) + STORMKIT_FORCE_INLINE + STORMKIT_CONST + inline auto vk_call(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 (meta::IsOneOf) + return std::invoke(func, std::forward(args)...); + else if constexpr (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 std::ranges::any_of(success_result, core::monadic::is(result))) [[likely]] + out = Out { std::unexpect, result }; + + return out; + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + STORMKIT_FORCE_INLINE + STORMKIT_CONST + inline auto vk_enumerate(Func&& func, Args&&... args) noexcept -> decltype(auto) { + if constexpr (IsVulkanFuncWithResult) + return vk_enumerate(func, + { VK_SUCCESS }, + std::forward(args)...); + else { + auto out = std::vector {}; + + auto size = UInt32 { 0 }; + std::invoke(func, std::forward(args)..., &size, nullptr); + out.resize(size); + std::invoke(func, std::forward(args)..., &size, std::data(out)); + + return out; + } + } + + ///////////////////////////////////// + ///////////////////////////////////// + template + requires(IsVulkanFuncWithResult) + STORMKIT_FORCE_INLINE + STORMKIT_CONST + inline auto vk_enumerate(const Func& func, + std::span possible_results, + Args&&... args) noexcept -> VulkanExpected> { + using Out = VulkanExpected>; + auto out = Out {}; + + auto size = UInt32 { 0 }; + auto result = std::invoke(func, std::forward(args)..., &size, nullptr); + if (not std::ranges::any_of(possible_results, core::monadic::is(result))) [[unlikely]] + out = Out { std::unexpect, result }; + + out = Out { std::in_place, size }; + if (out) [[likely]] { + result = std::invoke(func, std::forward(args)..., &size, std::data(*out)); + if (not std::ranges::any_of(possible_results, core::monadic::is(result))) [[unlikely]] + out = Out { std::unexpect, result }; + } + + return out; + } + + ///////////////////////////////////// + ///////////////////////////////////// + // template + template + STORMKIT_FORCE_INLINE + STORMKIT_CONST + inline auto to_vkhandle(const T& value) noexcept -> decltype(auto) { + if constexpr (meta::IsPointer) return value->native_handle(); + else + return value.native_handle(); + } + + namespace monadic { + ///////////////////////////////////// + ///////////////////////////////////// + STORMKIT_FORCE_INLINE STORMKIT_CONST + constexpr auto to_vkhandle() noexcept -> decltype(auto) { + return [](const auto& value) static noexcept -> decltype(auto) { + return gpu::to_vkhandle(value); + }; + } + } // namespace monadic +} // namespace stormkit::gpu diff --git a/modules/stormkit/image.mpp b/modules/stormkit/image.mpp index b2d1696ea..ba6cff297 100644 --- a/modules/stormkit/image.mpp +++ b/modules/stormkit/image.mpp @@ -198,7 +198,7 @@ export namespace stormkit::image { auto faces() const noexcept -> UInt32; [[nodiscard]] - auto mipLevels() const noexcept -> UInt32; + auto mip_levels() const noexcept -> UInt32; [[nodiscard]] auto format() const noexcept -> Format; @@ -366,7 +366,7 @@ namespace stormkit::image { ///////////////////////////////////// ///////////////////////////////////// - inline auto Image::mipLevels() const noexcept -> UInt32 { + inline auto Image::mip_levels() const noexcept -> UInt32 { return m_data.mip_levels; } diff --git a/modules/stormkit/log.mpp b/modules/stormkit/log.mpp index 65f10b7b2..eda385c72 100644 --- a/modules/stormkit/log.mpp +++ b/modules/stormkit/log.mpp @@ -22,13 +22,13 @@ export { WARNING, ERROR, FATAL, - DEBUG + DEBUG, }; [[nodiscard]] constexpr auto as_string(Severity severity) noexcept -> std::string_view; [[nodiscard]] - constexpr auto to_string(Severity severity) -> std::string; + constexpr auto to_string(Severity severity) noexcept -> std::string; class STORMKIT_API Logger { public: @@ -36,11 +36,12 @@ export { explicit Logger(LogClock::time_point start) noexcept; Logger(LogClock::time_point start, Severity log_level) noexcept; - virtual ~Logger(); + virtual ~Logger() noexcept; - virtual auto write(Severity severity, const Module& module, const char* string) -> void - = 0; - virtual auto flush() -> void = 0; + virtual auto write(Severity severity, const Module& module, const char* string) noexcept + -> void + = 0; + virtual auto flush() noexcept -> void = 0; auto set_log_level(Severity log_level) noexcept -> void; @@ -51,36 +52,37 @@ export { template [[nodiscard]] - static auto create_logger_instance(Args&&... param_args) -> T; + static auto create_logger_instance(Args&&... param_args) noexcept -> T; template [[nodiscard]] - static auto allocate_logger_instance(Args&&... param_args) -> std::unique_ptr; + 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) -> void; + Args&&... param_args) noexcept -> void; template - static auto log(Severity severity, std::string_view format_string, Args&&... param_args) - -> void; + static auto log(Severity severity, + std::string_view format_string, + Args&&... param_args) noexcept -> void; template - static auto dlog(Args&&... param_args) -> void; + static auto dlog(Args&&... param_args) noexcept -> void; template - static auto ilog(Args&&... param_args) -> void; + static auto ilog(Args&&... param_args) noexcept -> void; template - static auto wlog(Args&&... param_args) -> void; + static auto wlog(Args&&... param_args) noexcept -> void; template - static auto elog(Args&&... param_args) -> void; + static auto elog(Args&&... param_args) noexcept -> void; template - static auto flog(Args&&... param_args) -> void; + static auto flog(Args&&... param_args) noexcept -> void; [[nodiscard]] static auto has_logger() noexcept -> bool; @@ -94,44 +96,47 @@ export { struct Module { template - auto dlog(Args&&... args) const -> void; + auto dlog(Args&&... args) const noexcept -> void; template - auto ilog(Args&&... args) const -> void; + auto ilog(Args&&... args) const noexcept -> void; template - auto wlog(Args&&... args) const -> void; + auto wlog(Args&&... args) const noexcept -> void; template - auto elog(Args&&... args) const -> void; + auto elog(Args&&... args) const noexcept -> void; template - auto flog(Args&&... args) const -> void; + auto flog(Args&&... args) const noexcept -> void; - auto flush() const -> void; + auto flush() const noexcept -> void; std::string_view name = ""; }; template [[nodiscard]] - constexpr auto operator""_module() -> stormkit::log::Module; + constexpr auto operator""_module() noexcept -> stormkit::log::Module; - class STORMKIT_API FileLogger final: public Logger { + class STORMKIT_API + FileLogger final: public Logger { public: - FileLogger(LogClock::time_point start, std::filesystem::path path); - FileLogger(LogClock::time_point start, std::filesystem::path path, Severity log_level); - ~FileLogger() override; + 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&) = delete; - auto operator=(const FileLogger&) -> FileLogger& = delete; + FileLogger(const FileLogger&) noexcept = delete; + auto operator=(const FileLogger&) noexcept -> FileLogger& = delete; - FileLogger(FileLogger&&); - auto operator=(FileLogger&&) -> FileLogger&; + FileLogger(FileLogger&&) noexcept; + auto operator=(FileLogger&&) noexcept -> FileLogger&; - auto write(Severity severity, const Module& module, const char* string) - -> void override; - auto flush() -> void override; + auto write(Severity severity, const Module& module, const char* string) noexcept + -> void override; + auto flush() noexcept -> void override; private: StringHashMap m_streams; @@ -139,21 +144,22 @@ export { std::filesystem::path m_base_path; }; - class STORMKIT_API ConsoleLogger final: public Logger { + 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&); - auto operator=(const ConsoleLogger&) -> ConsoleLogger&; + ConsoleLogger(const ConsoleLogger&) noexcept; + auto operator=(const ConsoleLogger&) noexcept -> ConsoleLogger&; - ConsoleLogger(ConsoleLogger&&); - auto operator=(ConsoleLogger&&) -> ConsoleLogger&; + ConsoleLogger(ConsoleLogger&&) noexcept; + auto operator=(ConsoleLogger&&) noexcept -> ConsoleLogger&; - ~ConsoleLogger() override; + ~ConsoleLogger() noexcept override; - auto write(Severity severity, const Module& module, const char* string) - -> void override; + auto write(Severity severity, const Module& module, const char* string) noexcept + -> void override; auto flush() noexcept -> void override; }; } // namespace stormkit::log @@ -165,10 +171,9 @@ export { template T, class CharT> struct formatter: formatter, CharT> { template - auto format(T data, FormatContext& ctx) const -> decltype(ctx.out()) { - return formatter, CharT>::format(stormkit::log::as_string( - data), - ctx); + auto format(T data, FormatContext& ctx) const noexcept -> decltype(ctx.out()) { + return formatter, + CharT>::format(stormkit::log::as_string(data), ctx); } }; } // namespace std @@ -178,24 +183,23 @@ export { /// IMPLEMENTATION /// //////////////////////////////////////////////////////////////////// +using namespace std::literals; + namespace stormkit::log { namespace details { namespace { - constexpr auto SEVERITY_TO_STRING = [] { - using namespace std::literals; - - return frozen::make_unordered_map({ - { Severity::INFO, "INFO"sv }, - { Severity::WARNING, "WARNING"sv }, - { Severity::ERROR, "ERROR"sv }, - { Severity::FATAL, "FATAL"sv }, - { Severity::DEBUG, "DEBUG"sv }, - }); - }(); + constexpr auto SEVERITY_TO_STRING = frozen::make_unordered_map({ + { Severity::INFO, "INFO"sv }, + { Severity::WARNING, "WARNING"sv }, + { Severity::ERROR, "ERROR"sv }, + { Severity::FATAL, "FATAL"sv }, + { Severity::DEBUG, "DEBUG"sv } + }); }} // namespace details //////////////////////////////////////// //////////////////////////////////////// - STORMKIT_FORCE_INLINE constexpr auto as_string(Severity severity) noexcept -> std::string_view { + STORMKIT_FORCE_INLINE STORMKIT_PURE + inline constexpr auto as_string(Severity severity) noexcept -> std::string_view { const auto it = details::SEVERITY_TO_STRING.find(severity); expects(it != std::ranges::cend(details::SEVERITY_TO_STRING)); @@ -204,32 +208,38 @@ namespace stormkit::log { //////////////////////////////////////// //////////////////////////////////////// - STORMKIT_FORCE_INLINE constexpr auto to_string(Severity severity) -> std::string { + STORMKIT_FORCE_INLINE STORMKIT_PURE + inline constexpr auto to_string(Severity severity) noexcept -> std::string { return std::string { as_string(severity) }; } //////////////////////////////////////// //////////////////////////////////////// - STORMKIT_FORCE_INLINE auto Logger::set_log_level(Severity log_level) noexcept -> void { + STORMKIT_FORCE_INLINE + inline auto Logger::set_log_level(Severity log_level) noexcept -> void { m_log_level = log_level; } //////////////////////////////////////// //////////////////////////////////////// - STORMKIT_FORCE_INLINE auto Logger::start_time() const noexcept -> const LogClock::time_point& { + STORMKIT_FORCE_INLINE STORMKIT_PURE + inline auto Logger::start_time() const noexcept -> const LogClock::time_point& { return m_start_time; } //////////////////////////////////////// //////////////////////////////////////// - STORMKIT_FORCE_INLINE auto Logger::log_level() const noexcept -> const Severity& { + STORMKIT_FORCE_INLINE STORMKIT_PURE + inline auto Logger::log_level() const noexcept -> const Severity& { return m_log_level; } //////////////////////////////////////// //////////////////////////////////////// template - STORMKIT_FORCE_INLINE auto Logger::create_logger_instance(Args&&... param_args) -> T { + STORMKIT_FORCE_INLINE + STORMKIT_PURE + inline auto Logger::create_logger_instance(Args&&... param_args) noexcept -> T { using LogClock = std::chrono::high_resolution_clock; static_assert(std::is_base_of::value, "T must inherit Logger"); @@ -241,23 +251,26 @@ namespace stormkit::log { //////////////////////////////////////// //////////////////////////////////////// template - STORMKIT_FORCE_INLINE auto Logger::allocate_logger_instance(Args&&... param_args) - -> std::unique_ptr { + STORMKIT_FORCE_INLINE + STORMKIT_PURE + auto Logger::allocate_logger_instance(Args&&... param_args) noexcept -> Heap { using LogClock = std::chrono::high_resolution_clock; static_assert(std::is_base_of::value, "T must inherit Logger"); auto time_point = LogClock::now(); - return std::make_unique(std::move(time_point), std::forward(param_args)...); + 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) -> void { + 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; @@ -272,125 +285,152 @@ namespace stormkit::log { //////////////////////////////////////// //////////////////////////////////////// - inline ConsoleLogger::ConsoleLogger(const ConsoleLogger&) = default; + STORMKIT_FORCE_INLINE + inline ConsoleLogger::ConsoleLogger(const ConsoleLogger&) noexcept + = default; //////////////////////////////////////// //////////////////////////////////////// - inline auto ConsoleLogger::operator=(const ConsoleLogger&) -> ConsoleLogger& = default; + STORMKIT_FORCE_INLINE + inline auto ConsoleLogger::operator=(const ConsoleLogger&) noexcept -> ConsoleLogger& = default; //////////////////////////////////////// //////////////////////////////////////// - inline ConsoleLogger::ConsoleLogger(ConsoleLogger&&) = default; + STORMKIT_FORCE_INLINE + inline ConsoleLogger::ConsoleLogger(ConsoleLogger&&) noexcept + = default; //////////////////////////////////////// //////////////////////////////////////// - inline auto ConsoleLogger::operator=(ConsoleLogger&&) -> ConsoleLogger& = default; + STORMKIT_FORCE_INLINE + inline auto ConsoleLogger::operator=(ConsoleLogger&&) noexcept -> ConsoleLogger& = default; //////////////////////////////////////// //////////////////////////////////////// - inline ConsoleLogger::~ConsoleLogger() = default; + STORMKIT_FORCE_INLINE + inline ConsoleLogger::~ConsoleLogger() noexcept + = default; //////////////////////////////////////// //////////////////////////////////////// - inline FileLogger::FileLogger(FileLogger&&) = default; + STORMKIT_FORCE_INLINE + inline FileLogger::FileLogger(FileLogger&&) noexcept + = default; //////////////////////////////////////// //////////////////////////////////////// - inline auto FileLogger::operator=(FileLogger&&) -> FileLogger& = default; + STORMKIT_FORCE_INLINE + inline auto FileLogger::operator=(FileLogger&&) noexcept -> FileLogger& = default; //////////////////////////////////////// //////////////////////////////////////// - inline FileLogger::~FileLogger() = default; + STORMKIT_FORCE_INLINE + inline FileLogger::~FileLogger() noexcept + = default; //////////////////////////////////////// //////////////////////////////////////// template - STORMKIT_FORCE_INLINE auto Logger::log(Severity severity, - std::string_view format_string, - Args&&... param_args) -> void { + 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 auto Logger::dlog(Args&&... param_args) -> void { + STORMKIT_FORCE_INLINE + inline auto Logger::dlog(Args&&... param_args) noexcept -> void { log(Severity::DEBUG, std::forward(param_args)...); } //////////////////////////////////////// //////////////////////////////////////// template - STORMKIT_FORCE_INLINE auto Logger::ilog(Args&&... param_args) -> void { + STORMKIT_FORCE_INLINE + inline auto Logger::ilog(Args&&... param_args) noexcept -> void { log(Severity::INFO, std::forward(param_args)...); } //////////////////////////////////////// //////////////////////////////////////// template - STORMKIT_FORCE_INLINE auto Logger::wlog(Args&&... param_args) -> void { + STORMKIT_FORCE_INLINE + inline auto Logger::wlog(Args&&... param_args) noexcept -> void { log(Severity::WARNING, std::forward(param_args)...); } //////////////////////////////////////// //////////////////////////////////////// template - STORMKIT_FORCE_INLINE auto Logger::elog(Args&&... param_args) -> void { + STORMKIT_FORCE_INLINE + inline auto Logger::elog(Args&&... param_args) noexcept -> void { log(Severity::ERROR, std::forward(param_args)...); } //////////////////////////////////////// //////////////////////////////////////// template - STORMKIT_FORCE_INLINE auto Logger::flog(Args&&... param_args) -> void { + STORMKIT_FORCE_INLINE + inline auto Logger::flog(Args&&... param_args) noexcept -> void { log(Severity::FATAL, std::forward(param_args)...); } //////////////////////////////////////// //////////////////////////////////////// template - STORMKIT_FORCE_INLINE auto Module::dlog(Args&&... args) const -> void { + STORMKIT_FORCE_INLINE + inline auto Module::dlog(Args&&... args) const noexcept -> void { Logger::dlog(*this, std::forward(args)...); } //////////////////////////////////////// //////////////////////////////////////// template - STORMKIT_FORCE_INLINE auto Module::ilog(Args&&... args) const -> void { + STORMKIT_FORCE_INLINE + inline auto Module::ilog(Args&&... args) const noexcept -> void { Logger::ilog(*this, std::forward(args)...); } //////////////////////////////////////// //////////////////////////////////////// template - STORMKIT_FORCE_INLINE auto Module::wlog(Args&&... args) const -> void { + STORMKIT_FORCE_INLINE + inline auto Module::wlog(Args&&... args) const noexcept -> void { Logger::wlog(*this, std::forward(args)...); } //////////////////////////////////////// //////////////////////////////////////// template - STORMKIT_FORCE_INLINE auto Module::elog(Args&&... args) const -> void { + STORMKIT_FORCE_INLINE + inline auto Module::elog(Args&&... args) const noexcept -> void { Logger::elog(*this, std::forward(args)...); } //////////////////////////////////////// //////////////////////////////////////// template - STORMKIT_FORCE_INLINE auto Module::flog(Args&&... args) const -> void { + STORMKIT_FORCE_INLINE + inline auto Module::flog(Args&&... args) const noexcept -> void { Logger::flog(*this, std::forward(args)...); } //////////////////////////////////////// //////////////////////////////////////// - STORMKIT_FORCE_INLINE auto Module::flush() const -> void { + STORMKIT_FORCE_INLINE + inline auto Module::flush() const noexcept -> void { Logger::instance().flush(); } //////////////////////////////////////// //////////////////////////////////////// template - STORMKIT_FORCE_INLINE constexpr auto operator""_module() -> stormkit::log::Module { + STORMKIT_FORCE_INLINE + STORMKIT_CONST + inline constexpr auto operator""_module() noexcept -> stormkit::log::Module { return Module { str.view() }; } } // namespace stormkit::log diff --git a/src/Engine/Core/Application.cpp b/src/Engine/Core/Application.cpp index 1083f0c10..6655e191d 100644 --- a/src/Engine/Core/Application.cpp +++ b/src/Engine/Core/Application.cpp @@ -38,7 +38,7 @@ namespace stormkit::engine { m_world->step(Secondf { 0 }); // if (m_surf0ace->needRecreate()) { // m_surface->recreate(); - // doInitPerFrameObjects(); + // do_initPerFrameObjects(); //} } } diff --git a/src/Engine/Renderer.cpp b/src/Engine/Renderer.cpp index 66841ca47..ab07f422a 100644 --- a/src/Engine/Renderer.cpp +++ b/src/Engine/Renderer.cpp @@ -9,7 +9,7 @@ import std; import stormkit.core; import stormkit.log; import stormkit.wsi; -import stormkit.Gpu; +import stormkit.gpu; import :Renderer; import :Renderer.FrameGraph; @@ -34,7 +34,7 @@ namespace stormkit::engine { ///////////////////////////////////// auto scorePhysicalDevice(const gpu::PhysicalDevice& physical_device) -> UInt64 { const auto support_raytracing - = physical_device.checkExtensionSupport(RAYTRACING_EXTENSIONS); + = physical_device.check_extension_support(RAYTRACING_EXTENSIONS); auto score = UInt64 { 0u }; @@ -68,11 +68,11 @@ namespace stormkit::engine { auto ranked_devices = std::multimap> {}; for (const auto& physical_device : physical_devices) { - if (not physical_device.checkExtensionSupport(BASE_EXTENSIONS)) { + if (not physical_device.check_extension_support(BASE_EXTENSIONS)) { dlog("Base required extensions not supported for GPU {}", physical_device); continue; } - if (not physical_device.checkExtensionSupport(SWAPCHAIN_EXTENSIONS)) { + if (not physical_device.check_extension_support(SWAPCHAIN_EXTENSIONS)) { dlog("Swapchain required extensions not supported for GPU {}", physical_device); continue; } @@ -146,25 +146,25 @@ namespace stormkit::engine { ///////////////////////////////////// ///////////////////////////////////// - auto Renderer::doInit(std::string_view application_name, + auto Renderer::do_init(std::string_view application_name, std::optional> window) noexcept -> gpu::Expected { ilog("Initializing Renderer"); - return doInitInstance(application_name) - .and_then(bindFront(&Renderer::doInitDevice, this)) + return do_init_instance(application_name) + .and_then(bind_front(&Renderer::do_initDevice, this)) .and_then( - bindFront(gpu::Queue::create, std::cref(*m_device), m_device->rasterQueueEntry())) + bind_front(gpu::Queue::create, std::cref(*m_device), m_device->raster_queue_entry())) .transform(monadic::set(m_raster_queue)) - .and_then(bindFront(gpu::CommandPool::create, + .and_then(bind_front(gpu::CommandPool::create, std::cref(*m_device), std::cref(*m_raster_queue))) .transform(monadic::set(m_main_command_pool)) - .and_then(bindFront(&Renderer::doInitRenderSurface, this, std::move(window))); + .and_then(bind_front(&Renderer::do_initRenderSurface, this, std::move(window))); } ///////////////////////////////////// ///////////////////////////////////// - auto Renderer::doInitInstance(std::string_view application_name) noexcept + auto Renderer::do_init_instance(std::string_view application_name) noexcept -> gpu::Expected { return gpu::Instance::create(std::string { application_name }) .transform(monadic::set(m_instance)); @@ -172,8 +172,8 @@ namespace stormkit::engine { ///////////////////////////////////// ///////////////////////////////////// - auto Renderer::doInitDevice() noexcept -> gpu::Expected { - const auto& physical_devices = m_instance->physicalDevices(); + auto Renderer::do_initDevice() noexcept -> gpu::Expected { + const auto& physical_devices = m_instance->physical_devices(); auto physical_device = pickPhysicalDevice(physical_devices) .or_else(expectsWithMessage>( "No suitable GPU found !")) @@ -186,10 +186,10 @@ namespace stormkit::engine { ///////////////////////////////////// ///////////////////////////////////// - auto Renderer::doInitRenderSurface(std::optional> window) noexcept + auto Renderer::do_initRenderSurface(std::optional> window) noexcept -> gpu::Expected { if (window) - return RenderSurface::createFromWindow(*m_instance, + return RenderSurface::create_from_window(*m_instance, *m_device, *m_raster_queue, *(window.value())) @@ -208,7 +208,7 @@ namespace stormkit::engine { set_current_thread_name("StormKit:RenderThread"); m_command_buffers - = m_main_command_pool->createCommandBuffers(m_device, m_surface->bufferingCount()); + = m_main_command_pool->create_command_buffers(m_device, m_surface->bufferingCount()); m_framegraphs.resize(m_surface->bufferingCount()); @@ -216,17 +216,17 @@ namespace stormkit::engine { if (token.stop_requested()) return; m_surface->beginFrame(m_device) - .and_then(bindFront(&Renderer::doRender, + .and_then(bind_front(&Renderer::doRender, this, std::ref(framegraph_mutex), std::ref(rebuild_graph))) - .and_then(bindFront(&RenderSurface::presentFrame, + .and_then(bind_front(&RenderSurface::presentFrame, &m_surface.get(), std::cref(*m_raster_queue))) .transform_error(assert("Failed to render frame")); } - m_device->waitIdle(); + m_device->wait_idle(); } ///////////////////////////////////// @@ -257,13 +257,13 @@ namespace stormkit::engine { auto&& semaphore = *result; auto&& backbuffer = framegraph->backbuffer(); - blit_cmb.transitionImageLayout(backbuffer, + blit_cmb.transition_image_layout(backbuffer, gpu::ImageLayout::Color_Attachment_Optimal, gpu::ImageLayout::Transfer_Src_Optimal); - blit_cmb.transitionImageLayout(present_image, + blit_cmb.transition_image_layout(present_image, gpu::ImageLayout::Present_Src, gpu::ImageLayout::Transfer_Dst_Optimal); - blit_cmb.blitImage(backbuffer, + blit_cmb.blit_image(backbuffer, present_image, gpu::ImageLayout::Transfer_Src_Optimal, gpu::ImageLayout::Transfer_Dst_Optimal, @@ -277,10 +277,10 @@ namespace stormkit::engine { as(present_image.extent()) } } }, gpu::Filter::Linear); - blit_cmb.transitionImageLayout(backbuffer, + blit_cmb.transition_image_layout(backbuffer, gpu::ImageLayout::Transfer_Src_Optimal, gpu::ImageLayout::Color_Attachment_Optimal); - blit_cmb.transitionImageLayout(present_image, + blit_cmb.transition_image_layout(present_image, gpu::ImageLayout::Transfer_Dst_Optimal, gpu::ImageLayout::Present_Src); blit_cmb.end(); diff --git a/src/Engine/Renderer/BakedFrameGraph.cpp b/src/Engine/Renderer/BakedFrameGraph.cpp index c6c47a058..3225eeee3 100644 --- a/src/Engine/Renderer/BakedFrameGraph.cpp +++ b/src/Engine/Renderer/BakedFrameGraph.cpp @@ -7,7 +7,7 @@ module stormkit.Engine; import std; import stormkit.core; -import stormkit.Gpu; +import stormkit.gpu; import :Renderer.FrameGraph; import :Renderer.RenderSurface; diff --git a/src/Engine/Renderer/FrameGraph.cpp b/src/Engine/Renderer/FrameGraph.cpp index cbaaa050b..54090f2e4 100644 --- a/src/Engine/Renderer/FrameGraph.cpp +++ b/src/Engine/Renderer/FrameGraph.cpp @@ -7,7 +7,7 @@ module stormkit.Engine; import std; import stormkit.core; -import stormkit.Gpu; +import stormkit.gpu; import :Renderer.FrameGraph; @@ -151,7 +151,7 @@ namespace stormkit::engine { const auto& description = resource.description(); const auto usages = [&description] noexcept { - if (gpu::isDepthStencilFormat(description.format)) + if (gpu::is_depth_stencil_format(description.format)) return gpu::ImageUsageFlag::Depth_Stencil_Attachment | gpu::ImageUsageFlag::Transfert_Src; @@ -160,7 +160,7 @@ namespace stormkit::engine { }(); const auto clear_value = [&description] noexcept -> gpu::ClearValue { - if (gpu::isDepthStencilFormat(description.format)) + if (gpu::is_depth_stencil_format(description.format)) return gpu::ClearDepthStencil {}; return gpu::ClearColor {}; @@ -243,7 +243,7 @@ namespace stormkit::engine { .destination_layout = gpu::ImageLayout::Color_Attachment_Optimal }; - if (isDepthStencilFormat(description.format)) [[unlikely]] { + if (is_depth_stencil_format(description.format)) [[unlikely]] { std::swap(attachment_description.load_op, attachment_description.stencil_load_op); std::swap(attachment_description.store_op, @@ -277,7 +277,7 @@ namespace stormkit::engine { .destination_layout = layouts.at(id) }; - if (isDepthStencilFormat(description.format)) [[unlikely]] { + if (is_depth_stencil_format(description.format)) [[unlikely]] { std::swap(attachment_description.load_op, attachment_description.stencil_load_op); std::swap(attachment_description.store_op, @@ -317,7 +317,7 @@ namespace stormkit::engine { = gpu::AttachmentStoreOperation::Store; } - if (isDepthStencilFormat(description.format)) [[unlikely]] { + if (is_depth_stencil_format(description.format)) [[unlikely]] { std::swap(attachment_description.load_op, attachment_description.stencil_load_op); std::swap(attachment_description.store_op, @@ -341,7 +341,7 @@ namespace stormkit::engine { auto depth_attachment_ref = std::optional {}; for (auto&& [i, attachment] : output.description.attachments | std::views::enumerate) { - if (isDepthFormat(attachment.format)) + if (is_depth_format(attachment.format)) depth_attachment_ref = gpu::Subpass::Ref { .attachment_id = as(i), .layout = attachment.destination_layout }; @@ -364,14 +364,14 @@ namespace stormkit::engine { auto FmameGraph::allocatePhysicalResources(const gpu::CommandPool& command_pool, const gpu::Device& device) -> void { auto output = BakedFrameGraph {}; - output.cmb = command_pool.createCommandBuffer(device); - device.setObjectName(*output.cmb, "FrameGraph:CommandBuffer:Main"); + output.cmb = command_pool.create_command_buffer(device); + device.set_object_name(*output.cmb, "FrameGraph:CommandBuffer:Main"); output.semaphore = *gpu::Semaphore::create(device); - device.setObjectName(*output.semaphore, "FrameGraph:Semaphore:Main"); + device.set_object_name(*output.semaphore, "FrameGraph:Semaphore:Main"); - output.fence = *gpu::Fence::createSignaled(device); - device.setObjectName(*output.fence, "FrameGraph:Fence:Main"); + output.fence = *gpu::Fence::create_signaled(device); + device.set_object_name(*output.fence, "FrameGraph:Fence:Main"); output.tasks.reserve(std::size(m_preprocessed_framegraph)); @@ -386,7 +386,7 @@ namespace stormkit::engine { = output.buffers.emplace_back(gpu::Buffer::create(device, buffer.create_info) .transform_error(expects()) .value()); - device.setObjectName(gpu_buffer, std::format("FrameGraph:Buffer:{}", buffer.name)); + device.set_object_name(gpu_buffer, std::format("FrameGraph:Buffer:{}", buffer.name)); } auto extent = math::ExtentU {}; @@ -401,13 +401,13 @@ namespace stormkit::engine { = output.images.emplace_back(gpu::Image::create(device, image.create_info) .transform_error(expects()) .value()); - device.setObjectName(gpu_image, std::format("FrameGraph:Image:{}", image.name)); + device.set_object_name(gpu_image, std::format("FrameGraph:Image:{}", image.name)); if (image.id == m_final_resource) output.backbuffer = as_ref(gpu_image); auto& gpu_image_view = output.image_views.emplace_back( gpu::ImageView::create(device, gpu_image).transform_error(expects()).value()); - device.setObjectName(gpu_image_view, + device.set_object_name(gpu_image_view, std::format("FrameGraph:ImageView:{}", image.name)); attachments.emplace_back(gpu_image_view); @@ -416,13 +416,13 @@ namespace stormkit::engine { expects(backbuffer != std::nullopt, "No final resource set !"); auto renderpass = *gpu::RenderPass::create(device, pass.renderpass.description); - device.setObjectName(renderpass, std::format("FrameGraph:RenderPass:{}", pass.name)); + device.set_object_name(renderpass, std::format("FrameGraph:RenderPass:{}", pass.name)); auto framebuffer = *gpu::FrameBuffer::create(device, renderpass, extent, attachments); - device.setObjectName(framebuffer, std::format("FrameGraph:FrameBuffer:{}", pass.name)); + device.set_object_name(framebuffer, std::format("FrameGraph:FrameBuffer:{}", pass.name)); - auto cmb = command_pool.createCommandBuffer(device, gpu::CommandBufferLevel::Secondary); - device.setObjectName(cmb, std::format("FrameGraph:CommandBuffer:{}", pass.name)); + auto cmb = command_pool.create_command_buffer(device, gpu::CommandBufferLevel::Secondary); + device.set_object_name(cmb, std::format("FrameGraph:CommandBuffer:{}", pass.name)); cmb.begin(false, gpu::InheritanceInfo { &renderpass, 0, &framebuffer }); auto&& graph_task = getTask(pass.id); @@ -440,18 +440,18 @@ namespace stormkit::engine { output.cmb->begin(); const auto visitors = Overloaded { [&output](const BakedFrameGraphBuilder::Data::RasterTask& task) { - output.cmb->beginRenderPass(task.renderpass, + output.cmb->begin_render_pass(task.renderpass, task.framebuffer, task.clear_values, true); const auto command_buffers = as_refs(task.cmb); - output.cmb->executeSubCommandBuffers(command_buffers); - output.cmb->endRenderPass(); + output.cmb->execute_sub_command_buffers(command_buffers); + output.cmb->end_render_pass(); }, [&output](const BakedFrameGraphBuilder::Data::ComputeTask& task) { const auto command_buffers = as_refs(task.cmb); - output.cmb->executeSubCommandBuffers(command_buffers); + output.cmb->execute_sub_command_buffers(command_buffers); } }; for (auto&& task : output.tasks) std::visit(visitors, task); output.cmb->end(); diff --git a/src/Engine/Renderer/FrameGraphBuilder.cpp b/src/Engine/Renderer/FrameGraphBuilder.cpp index 0ad189563..de5837cb5 100644 --- a/src/Engine/Renderer/FrameGraphBuilder.cpp +++ b/src/Engine/Renderer/FrameGraphBuilder.cpp @@ -7,7 +7,7 @@ module stormkit.Engine; import std; import stormkit.core; -import stormkit.Gpu; +import stormkit.gpu; import :Renderer.FrameGraph; @@ -151,7 +151,7 @@ namespace stormkit::engine { const auto& description = resource.description(); const auto usages = [&description] noexcept { - if (gpu::isDepthStencilFormat(description.format)) + if (gpu::is_depth_stencil_format(description.format)) return gpu::ImageUsageFlag::Depth_Stencil_Attachment | gpu::ImageUsageFlag::Transfert_Src; @@ -160,7 +160,7 @@ namespace stormkit::engine { }(); const auto clear_value = [&description] noexcept -> gpu::ClearValue { - if (gpu::isDepthStencilFormat(description.format)) + if (gpu::is_depth_stencil_format(description.format)) return gpu::ClearDepthStencil {}; return gpu::ClearColor {}; @@ -241,7 +241,7 @@ namespace stormkit::engine { .destination_layout = gpu::ImageLayout::Color_Attachment_Optimal }; - if (isDepthStencilFormat(description.format)) [[unlikely]] { + if (is_depth_stencil_format(description.format)) [[unlikely]] { std::swap(attachment_description.load_op, attachment_description.stencil_load_op); std::swap(attachment_description.store_op, @@ -275,7 +275,7 @@ namespace stormkit::engine { .destination_layout = layouts.at(id) }; - if (isDepthStencilFormat(description.format)) [[unlikely]] { + if (is_depth_stencil_format(description.format)) [[unlikely]] { std::swap(attachment_description.load_op, attachment_description.stencil_load_op); std::swap(attachment_description.store_op, @@ -315,7 +315,7 @@ namespace stormkit::engine { = gpu::AttachmentStoreOperation::Store; } - if (isDepthStencilFormat(description.format)) [[unlikely]] { + if (is_depth_stencil_format(description.format)) [[unlikely]] { std::swap(attachment_description.load_op, attachment_description.stencil_load_op); std::swap(attachment_description.store_op, @@ -339,7 +339,7 @@ namespace stormkit::engine { auto depth_attachment_ref = std::optional {}; for (auto&& [i, attachment] : output.description.attachments | std::views::enumerate) { - if (isDepthFormat(attachment.format)) + if (is_depth_format(attachment.format)) depth_attachment_ref = gpu::Subpass::Ref { .attachment_id = as(i), .layout = attachment.destination_layout }; @@ -365,14 +365,14 @@ namespace stormkit::engine { using Data = BakedFrameGraph::Data; auto output = Data {}; - output.cmb = command_pool.createCommandBuffer(device); - device.setObjectName(*output.cmb, "FrameGraph:CommandBuffer:Main"); + output.cmb = command_pool.create_command_buffer(device); + device.set_object_name(*output.cmb, "FrameGraph:CommandBuffer:Main"); output.semaphore = *gpu::Semaphore::create(device); - device.setObjectName(*output.semaphore, "FrameGraph:Semaphore:Main"); + device.set_object_name(*output.semaphore, "FrameGraph:Semaphore:Main"); - output.fence = *gpu::Fence::createSignaled(device); - device.setObjectName(*output.fence, "FrameGraph:Fence:Main"); + output.fence = *gpu::Fence::create_signaled(device); + device.set_object_name(*output.fence, "FrameGraph:Fence:Main"); output.tasks.reserve(std::size(m_preprocessed_framegraph)); @@ -390,7 +390,7 @@ namespace stormkit::engine { = output.buffers.emplace_back(gpu::Buffer::create(device, buffer.create_info) .transform_error(expects()) .value()); - device.setObjectName(gpu_buffer, std::format("FrameGraph:Buffer:{}", buffer.name)); + device.set_object_name(gpu_buffer, std::format("FrameGraph:Buffer:{}", buffer.name)); } auto extent = math::ExtentU {}; @@ -405,13 +405,13 @@ namespace stormkit::engine { = output.images.emplace_back(gpu::Image::create(device, image.create_info) .transform_error(expects()) .value()); - device.setObjectName(gpu_image, std::format("FrameGraph:Image:{}", image.name)); + device.set_object_name(gpu_image, std::format("FrameGraph:Image:{}", image.name)); if (image.id == m_final_resource) backbuffer = &gpu_image; auto& gpu_image_view = output.image_views.emplace_back( gpu::ImageView::create(device, gpu_image).transform_error(expects()).value()); - device.setObjectName(gpu_image_view, + device.set_object_name(gpu_image_view, std::format("FrameGraph:ImageView:{}", image.name)); attachments.emplace_back(gpu_image_view); @@ -420,13 +420,13 @@ namespace stormkit::engine { expects(backbuffer != nullptr, "No final resource set !"); auto renderpass = *gpu::RenderPass::create(device, pass.renderpass.description); - device.setObjectName(renderpass, std::format("FrameGraph:RenderPass:{}", pass.name)); + device.set_object_name(renderpass, std::format("FrameGraph:RenderPass:{}", pass.name)); auto framebuffer = *gpu::FrameBuffer::create(device, renderpass, extent, attachments); - device.setObjectName(framebuffer, std::format("FrameGraph:FrameBuffer:{}", pass.name)); + device.set_object_name(framebuffer, std::format("FrameGraph:FrameBuffer:{}", pass.name)); - auto cmb = command_pool.createCommandBuffer(device, gpu::CommandBufferLevel::Secondary); - device.setObjectName(cmb, std::format("FrameGraph:CommandBuffer:{}", pass.name)); + auto cmb = command_pool.create_command_buffer(device, gpu::CommandBufferLevel::Secondary); + device.set_object_name(cmb, std::format("FrameGraph:CommandBuffer:{}", pass.name)); cmb.begin(false, gpu::InheritanceInfo { &renderpass, 0, &framebuffer }); auto&& graph_task = getTask(pass.id); @@ -444,18 +444,18 @@ namespace stormkit::engine { output.cmb->begin(); const auto visitors = Overloaded { [&output](const BakedFrameGraph::Data::RasterTask& task) { - output.cmb->beginRenderPass(task.renderpass, + output.cmb->begin_render_pass(task.renderpass, task.framebuffer, task.clear_values, true); const auto command_buffers = as_refs(task.cmb); - output.cmb->executeSubCommandBuffers(command_buffers); - output.cmb->endRenderPass(); + output.cmb->execute_sub_command_buffers(command_buffers); + output.cmb->end_render_pass(); }, [&output](const BakedFrameGraph::Data::ComputeTask& task) { const auto command_buffers = as_refs(task.cmb); - output.cmb->executeSubCommandBuffers(command_buffers); + output.cmb->execute_sub_command_buffers(command_buffers); } }; for (auto&& task : output.tasks) std::visit(visitors, task); output.cmb->end(); diff --git a/src/Engine/Renderer/RenderSurface.cpp b/src/Engine/Renderer/RenderSurface.cpp index 8fa79a641..2f21885b8 100644 --- a/src/Engine/Renderer/RenderSurface.cpp +++ b/src/Engine/Renderer/RenderSurface.cpp @@ -5,7 +5,7 @@ import std; import stormkit.core; import stormkit.log; import stormkit.wsi; -import stormkit.Gpu; +import stormkit.gpu; import :Renderer; @@ -19,9 +19,9 @@ namespace stormkit::engine { const gpu::Queue& raster_queue, const wsi::Window& window, Tag) { - gpu::Surface::createFromWindow(instance, window) + gpu::Surface::create_from_window(instance, window) .transform(monadic::set(m_surface)) - .and_then(bindFront(gpu::Swapchain::create, + .and_then(bind_front(gpu::Swapchain::create, std::cref(device), std::cref(*m_surface), std::cref(window.extent()), @@ -32,9 +32,9 @@ namespace stormkit::engine { for (auto _ : range(std::size(m_swapchain->images()))) { gpu::Semaphore::create(device) .transform(monadic::emplace_to(m_image_availables)) - .and_then(bindFront(gpu::Semaphore::create, std::cref(device))) + .and_then(bind_front(gpu::Semaphore::create, std::cref(device))) .transform(monadic::emplace_to(m_render_finisheds)) - .and_then(bindFront(gpu::Fence::createSignaled, std::cref(device))) + .and_then(bind_front(gpu::Fence::create_signaled, std::cref(device))) .transform(monadic::emplace_to(m_in_flight_fences)) .transform_error( monadic::map(monadic::narrow(), monadic::throw_as_exception())); @@ -46,14 +46,14 @@ namespace stormkit::engine { .value(); auto transition_command_buffers - = command_pool.createCommandBuffers(device, std::size(m_swapchain->images())); + = command_pool.create_command_buffers(device, std::size(m_swapchain->images())); for (auto i : range(std::size(transition_command_buffers))) { auto&& image = m_swapchain->images()[i]; auto&& transition_command_buffer = transition_command_buffers[i]; transition_command_buffer.begin(true); - transition_command_buffer.transitionImageLayout(image, + transition_command_buffer.transition_image_layout(image, gpu::ImageLayout::UNDEFINED, gpu::ImageLayout::Present_Src); transition_command_buffer.end(); @@ -83,7 +83,7 @@ namespace stormkit::engine { return in_flight.wait() .transform([&in_flight](auto&& _) noexcept { in_flight.reset(); }) - .and_then(bindFront(&gpu::Swapchain::acquireNextImage, + .and_then(bind_front(&gpu::Swapchain::acquire_next_image, &(m_swapchain.get()), 100ms, std::cref(image_available))) diff --git a/src/Engine/Renderer/SpriteRenderer.cpp b/src/Engine/Renderer/SpriteRenderer.cpp index 2ff78a0b4..91db42b2d 100644 --- a/src/Engine/Renderer/SpriteRenderer.cpp +++ b/src/Engine/Renderer/SpriteRenderer.cpp @@ -7,7 +7,7 @@ module stormkit.Engine; import std; import stormkit.core; -import stormkit.Gpu; +import stormkit.gpu; import :SpriteRenderer; @@ -40,11 +40,11 @@ namespace stormkit::engine { SpriteRenderer::SpriteRenderer(const Renderer& renderer, const math::ExtentF& viewport, Tag) : m_renderer { as_ref(renderer) }, m_viewport { viewport } { m_render_data = allocate(); - gpu::Shader::fromBytes(renderer.device(), Quad_Sprite_Shader, gpu::ShaderStageFlag::Vertex) + gpu::Shader::load_from_bytes(renderer.device(), Quad_Sprite_Shader, gpu::ShaderStageFlag::Vertex) .transform(monadic::set(m_render_data->vertex_shader)) .transform_error(monadic::throw_as_exception()); - gpu::Shader::fromBytes(renderer.device(), + gpu::Shader::load_from_bytes(renderer.device(), Quad_Sprite_Shader, gpu::ShaderStageFlag::Fragment) .transform(monadic::set(m_render_data->fragment_shader)) @@ -121,7 +121,7 @@ namespace stormkit::engine { auto staging_buffer = graph_data.getActualResource(*task_data.staging_buffer); auto vertex_buffer = graph_data.getActualResource(*task_data.vertex_buffer); - cmb.copyBuffer(staging_buffer, vertex_buffer, Sprite_Vertex_Buffer_Size); + cmb.copy_buffer(staging_buffer, vertex_buffer, Sprite_Vertex_Buffer_Size); }); transfer_task_data = as_ref(graph.getTaskData(task.dataID())); m_dirty = false; @@ -164,8 +164,8 @@ namespace stormkit::engine { } auto buffers = as_refs(task_data.vertex_buffer); - cmb.bindPipeline(m_render_data->pipeline); - cmb.bindVertexBuffers(buffers); + cmb.bind_pipeline(m_render_data->pipeline); + cmb.bind_vertex_buffers(buffers); for (auto&& [_, sprite_data] : m_sprites) cmb.draw(std::size(sprite_data.sprite.vertices)); }, diff --git a/src/Gpu/Core/Device.cpp b/src/Gpu/Core/Device.cpp deleted file mode 100644 index 652ab699f..000000000 --- a/src/Gpu/Core/Device.cpp +++ /dev/null @@ -1,256 +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 - -module stormkit.Gpu; - -import std; - -import stormkit.core; -import stormkit.log; - -import :Core.Device; -import :Core.Sync; -import stormkit.Gpu.Vulkan; - -using namespace std::literals; - -namespace { - constexpr auto RAYTRACING_EXTENSIONS - = std::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 }; - - constexpr auto BASE_EXTENSIONS = std::array { "VK_KHR_maintenance3"sv }; - - constexpr auto SWAPCHAIN_EXTENSIONS = std::array { "VK_KHR_swapchain"sv }; - -} // namespace - -namespace stormkit::gpu { - NAMED_LOGGER(device_logger, "stormkit.Gpu:core.Device") - - template - constexpr auto findQueue() { - return [](const auto& family) { - return core::checkFlag(family.flags, flag) - and (not core::checkFlag(family.flags, no_flag) and ...); - }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - Device::Device(const PhysicalDevice& physical_device, - const Instance& instance, - const Info& info, - Tag) - : m_physical_device { as_ref(physical_device) } { - const auto& queue_families = m_physical_device->queueFamilies(); - - struct Queue_ { - std::optional id = std::nullopt; - UInt32 count = 0u; - Byte _[3]; - QueueFlag flags = QueueFlag {}; - }; - - const auto raster_queue = [&queue_families]() -> Queue_ { - const auto it = std::ranges::find_if(queue_families, findQueue()); - if (it == std::ranges::cend(queue_families)) return {}; - - return { .id = as(std::distance(std::ranges::cbegin(queue_families), it)), - .count = it->count, - .flags = it->flags }; - }(); - - const auto compute_queue = [&queue_families]() -> Queue_ { - const auto it - = std::ranges::find_if(queue_families, - findQueue()); - if (it == std::ranges::cend(queue_families)) return {}; - - return { .id = as(std::distance(std::ranges::cbegin(queue_families), it)), - .count = it->count, - .flags = it->flags }; - }(); - - const auto transfert_queue = [&queue_families]() -> Queue_ { - const auto it = std::ranges::find_if( - queue_families, - findQueue()); - if (it == std::ranges::cend(queue_families)) return {}; - - return { .id = as(std::distance(std::ranges::cbegin(queue_families), it)), - .count = it->count, - .flags = it->flags }; - }(); - - const auto queues = [&] { - auto q = std::vector {}; - q.reserve(3); - - 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); - - return q; - }(); - - auto priorities = std::vector> {}; - priorities.reserve(std::size(queues)); - - const auto queue_create_infos = transform(queues, [&priorities](auto queue) { - auto& priority = priorities.emplace_back(); - - priority.resize(queue->count, 1.f); - - return vk::DeviceQueueCreateInfo {} - .setQueueFamilyIndex(queue->id.value()) - .setQueuePriorities(priority); - }); - - const auto& capabilities = m_physical_device->capabilities(); - const auto enabled_features - = vk::PhysicalDeviceFeatures {} - .setSampleRateShading(capabilities.features.sampler_rate_shading) - .setMultiDrawIndirect(capabilities.features.multi_draw_indirect) - .setFillModeNonSolid(capabilities.features.fill_Mode_non_solid) - .setSamplerAnisotropy(capabilities.features.sampler_anisotropy); - - const auto device_extensions - = m_physical_device->vkHandle().enumerateDeviceExtensionProperties(); - - device_logger.dlog("Device extensions: {}", - device_extensions | std::views::transform([](auto&& ext) { - return std::string_view { ext.extensionName }; - })); - - const auto swapchain_available = [&] { - for (const auto& ext : SWAPCHAIN_EXTENSIONS) { - if (std::ranges::find_if(device_extensions, - [&](const auto& e) { return ext == e.extensionName; }) - == std::ranges::cend(device_extensions)) { - return false; - } - } - - return true; - }(); - - const auto raytracing_available = [&] { - for (const auto& ext : RAYTRACING_EXTENSIONS) { - if (std::ranges::find_if(device_extensions, - [&](const auto& e) { return ext == e.extensionName; }) - == std::ranges::cend(device_extensions)) { - return false; - } - } - - return true; - }(); - - const auto extensions = [&] { - constexpr auto as_czstring = [](const auto& v) { return std::data(v); }; - - auto e = transform(BASE_EXTENSIONS, as_czstring); - if (swapchain_available and info.enable_swapchain) - merge(e, transform(SWAPCHAIN_EXTENSIONS, as_czstring)); - if (raytracing_available and info.enable_raytracing) - merge(e, transform(RAYTRACING_EXTENSIONS, as_czstring)); - - return e; - }(); - - const auto acceleration_feature = vk::PhysicalDeviceAccelerationStructureFeaturesKHR {}; - const auto rt_pipeline_feature - = vk::PhysicalDeviceRayTracingPipelineFeaturesKHR {}.setPNext( - std::bit_cast(&acceleration_feature)); - - const auto next = [&]() -> void* { - if (raytracing_available and info.enable_raytracing) - return std::bit_cast(&rt_pipeline_feature); - return nullptr; - }(); - - const auto create_info = vk::DeviceCreateInfo {} - .setPNext(next) - .setQueueCreateInfos(queue_create_infos) - .setPEnabledExtensionNames(extensions) - .setPEnabledFeatures(&enabled_features); - - m_physical_device->vkHandle() - .createDevice(create_info) - .transform(core :.monadic::set(m_vk_device)) - .transform([this, &instance] noexcept -> VulkanExpected { - VULKAN_HPP_DEFAULT_DISPATCHER.init(*vkHandle()); - - m_vma_function_table - = vma::functionsFromDispatcher(instance.vkHandle().getDispatcher(), - vkHandle().getDispatcher()); - - const auto alloc_create_info - = vma::AllocatorCreateInfo {} - .setInstance(*(instance.vkHandle())) - .setPhysicalDevice(*m_physical_device->vkHandle()) - .setDevice(*vkHandle()) - .setPVulkanFunctions(&vmaFunctionTable()); - - auto&& [result, allocator] = vma::createAllocatorUnique(alloc_create_info); - if (result != vk::Result::eSuccess) return std::unexpected { result }; - - m_vma_allocator = std::move(allocator); - - return {}; - }) - .transform_error(core :.monadic::map(core :.monadic::narrow(), - core :.monadic::throw_as_exception())); - - if (raster_queue.id) - m_raster_queue = QueueEntry { .id = *raster_queue.id, - .count = raster_queue.count, - .flags = raster_queue.flags }; - - setObjectName(*this, - std::format("StormKit:Device ({})", m_physical_device->info().device_name)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto Device::waitForFences(std::span> fences, - bool wait_all, - const std::chrono::milliseconds& timeout) const noexcept - -> Expected { - const auto vk_fences = fences - | std::views::transform(monadic::toVkHandle()) - | std::ranges::to(); - - return vkCall(*m_vk_device, - &vk::raii::Device::waitForFences, - { - { vk::Result::eSuccess, vk::Result::eNotReady } - }, - vk_fences, - wait_all, - std::chrono::duration_cast(timeout).count()) - .transform(core :.monadic::narrow()) - .transform_error(core :.monadic::narrow()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto Device::resetFences(std::span> fences) const noexcept -> void { - const auto vk_fences = fences - | std::views::transform(monadic::toVkHandle()) - | std::ranges::to(); - - m_vk_device->resetFences(vk_fences); - } -} // namespace stormkit::gpu diff --git a/src/Gpu/Core/Instance.cpp b/src/Gpu/Core/Instance.cpp deleted file mode 100644 index 93691d14a..000000000 --- a/src/Gpu/Core/Instance.cpp +++ /dev/null @@ -1,233 +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 - -module stormkit.Gpu; - -import std; - -import stormkit.core; -import stormkit.log; - -import stormkit.Gpu.Vulkan; - -namespace stormkit::gpu { - LOGGER("stormkit.Gpu") - - namespace { - constexpr auto VALIDATION_LAYERS = std::array { - "VK_LAYER_KHRONOS_validation", -#ifdef STORMKIT_OS_LINUX - "VK_LAYER_MESA_overlay", -#endif - }; - - [[maybe_unused]] - constexpr auto VALIDATION_FEATURES - = std::array { vk::ValidationFeatureEnableEXT::eBestPractices, - vk::ValidationFeatureEnableEXT::eGpuAssisted }; - - constexpr auto STORMKIT_VK_VERSION = vkMakeVersion(STORMKIT_MAJOR_VERSION, - STORMKIT_MINOR_VERSION, - STORMKIT_PATCH_VERSION); - - constexpr auto BASE_EXTENSIONS = std::array { "VK_KHR_get_physical_device_properties2" }; - - constexpr auto SURFACE_EXTENSIONS = std::array { - "VK_KHR_surface", - }; - - constexpr auto WSI_SURFACE_EXTENSIONS = std::array { -#ifdef STORMKIT_OS_WINDOWS - "VK_KHR_win32_surface" -#elif defined(STORMKIT_OS_LINUX) - "VK_KHR_xcb_surface", - "VK_KHR_wayland_surface" -#elif defined(STORMKIT_OS_MACOS) - "VK_MVK_MACOS_surface" -#elif defined(STORMKIT_OS_IOS) - "VK_MVK_IOS_surface" -#endif - }; - - ///////////////////////////////////// - ///////////////////////////////////// - auto debugCallback(vk::DebugUtilsMessageSeverityFlagsEXT severity, - vk::DebugUtilsMessageTypeFlagsEXT _, - const vk::DebugUtilsMessengerCallbackDataEXT& callback_data, - void*) -> bool { - auto message = std::format("{}", callback_data.pMessage); - - if (checkFlag(severity, vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo)) - ilog("{}", message); - else if (checkFlag(severity, vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose)) - dlog("{}", message); - else if (checkFlag(severity, vk::DebugUtilsMessageSeverityFlagBitsEXT::eError)) - elog("{}", message); - else if (checkFlag(severity, vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning)) - wlog("{}", message); - - return false; - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto checkValidationLayerSupport(const vk::raii::Context& context, - bool validation_layers_enabled) noexcept -> bool { - if (!validation_layers_enabled) return validation_layers_enabled; - - const auto layers = context.enumerateInstanceLayerProperties(); - dlog("Layers found: {}", - layers | std::views::transform([](auto&& layer) static noexcept { - return std::string_view { layer.layerName }; - })); - for (const auto& layer_name : std::as_const(VALIDATION_LAYERS)) { - auto layer_found = false; - - for (const auto& layer_properties : layers) { - if (std::strcmp(layer_name, layer_properties.layerName) == 0) { - layer_found = true; - break; - } - } - - if (!layer_found) { - dlog("Failed to find validation layers, disabling..."); - return false; - } - } - - return validation_layers_enabled; - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto checkExtensionSupport(std::span supported_extensions, - std::span extensions) noexcept -> bool { - auto required_extensions = HashSet { std::ranges::begin(extensions), - std::ranges::end(extensions) }; - - for (const auto& extension : supported_extensions) required_extensions.erase(extension); - - return required_extensions.empty(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto checkExtensionSupport(std::span supported_extensions, - std::span extensions) noexcept -> bool { - // clang-format off - const auto ext = extensions - | std::views::transform(core:.monadic::init()) - | std::ranges::to(); - // clang-format on - return checkExtensionSupport(supported_extensions, ext); - } - } // namespace - - ///////////////////////////////////// - ///////////////////////////////////// - auto Instance::doInitInstance() noexcept -> VulkanExpected { - VULKAN_HPP_DEFAULT_DISPATCHER.init(); - - m_vk_context = vk::raii::Context(); - - const auto exts = m_vk_context->enumerateInstanceExtensionProperties(); - m_extensions = exts - | std::views::transform([](auto&& extension) noexcept { - return std::string { extension.extensionName }; - }) - | std::ranges::to(); - - dlog("Instance extensions: {}", m_extensions); - - const auto validation_layers = [this]() noexcept { - auto output = std::vector {}; - m_validation_layers_enabled - = checkValidationLayerSupport(m_vk_context, m_validation_layers_enabled); - if (m_validation_layers_enabled) { - ilog("Enabling layers: {}", VALIDATION_LAYERS); - - output = VALIDATION_LAYERS | std::ranges::to(); - } - - return output; - }(); - - 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 (checkExtensionSupport(m_extensions, ext)) merge(e, ext); - } - - if (m_validation_layers_enabled) merge(e, std::array { "VK_EXT_debug_utils" }); - - return e; - }(); - - constexpr auto ENGINE_NAME = "StormKit"; - - const auto app_info = vk::ApplicationInfo { .pApplicationName = std::data(m_app_name), - .pEngineName = ENGINE_NAME, - .engineVersion = STORMKIT_VK_VERSION, - .apiVersion = vkMakeVersion(1, 0, 0) }; - - const auto create_info = vk::InstanceCreateInfo { .pApplicationInfo = &app_info } - .setPEnabledExtensionNames(instance_extensions) - .setPEnabledLayerNames(validation_layers); - - return m_vk_context->createInstance(create_info) - .transform(core :.monadic::set(m_vk_instance)) - .and_then(bindFront(&Instance::doInitDebugReportCallback, this)) - .transform( - [this]() noexcept { VULKAN_HPP_DEFAULT_DISPATCHER.init(*m_vk_instance.get()); }); - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto Instance::doInitDebugReportCallback() noexcept -> VulkanExpected { - if (!m_validation_layers_enabled) return {}; - constexpr auto severity = vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose - | vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning - | vk::DebugUtilsMessageSeverityFlagBitsEXT::eError; - - constexpr auto type = vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral - | vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation - | vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance; - - const auto create_info = vk::DebugUtilsMessengerCreateInfoEXT { - .messageSeverity = severity, - .messageType = type, - .pfnUserCallback - = std::bit_cast( - &debugCallback) - }; - - return m_vk_instance->createDebugUtilsMessengerEXT(create_info) - .transform(core :.monadic::set(m_vk_messenger)) - .transform([] noexcept { ilog("Validation layers successfully enabled !"); }); - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto Instance::doRetrievePhysicalDevices() noexcept -> VulkanExpected { - return m_vk_instance->enumeratePhysicalDevices().transform([this](auto&& physical_devices) { - // clang-format off - m_physical_devices = std::forward(physical_devices) - | std::views::transform([](auto&& physical_device) static noexcept { - return PhysicalDevice { std::move(physical_device) }; - }) - | std::ranges::to(); - // clang-format on - }); - } -} // namespace stormkit::gpu diff --git a/src/Gpu/Core/Surface.cpp b/src/Gpu/Core/Surface.cpp deleted file mode 100644 index c51b0fa73..000000000 --- a/src/Gpu/Core/Surface.cpp +++ /dev/null @@ -1,99 +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 - -#if defined(STORMKIT_OS_LINUX) - #include - #include -#elif defined(STORMKIT_OS_WINDOWS) - #include -#endif - -module stormkit.Gpu; - -import std; - -import stormkit.core; -import stormkit.wsi; - -import stormkit.Gpu.Vulkan; - -namespace stormkit::gpu { - ///////////////////////////////////// - ///////////////////////////////////// - Surface::Surface(const Instance& instance, const wsi::Window& window, Tag) { -#if defined(STORMKIT_OS_WINDOWS) - const auto create_surface = [&window, &instance] { - const auto create_info = vk::Win32SurfaceCreateInfoKHR { - .flags = {}, - .hinstance = GetModuleHandleW(nullptr), - .hwnd = reinterpret_cast(window.native_handle()) - }; - return instance.vkHandle().createWin32SurfaceKHR(create_info, nullptr); - }; -#elif defined(STORMKIT_OS_MACOS) - const auto create_surface = [&window, &instance] { - const auto create_info - = vk::MacOSSurfaceCreateInfoMVK { .pView = window.native_handle() }; - return instance.vkHandle().createMacOSSurfaceMVK(create_info, nullptr); - }; -#elif defined(STORMKIT_OS_LINUX) - const auto make_wayland_surface = [&window, &instance] { - struct Handles { - wl_display* display; - wl_surface* surface; - }* handles = std::bit_cast(window.native_handle()); - - const auto create_info - = vk::WaylandSurfaceCreateInfoKHR { .display = handles->display, - .surface = handles->surface }; - - return instance.vkHandle().createWaylandSurfaceKHR(create_info, nullptr); - }; - const auto make_xcb_surface = [&window, &instance] { - struct Handles { - xcb_connection_t* connection; - xcb_window_t window; - }* handles = reinterpret_cast(window.native_handle()); - - const auto create_info - = vk::XcbSurfaceCreateInfoKHR { .connection = handles->connection, - .window = handles->window }; - - return instance.vkHandle().createXcbSurfaceKHR(create_info, nullptr); - }; - - const auto create_surface - = [&window, - &make_wayland_surface, - &make_xcb_surface] noexcept -> FunctionRef()> { - const auto is_wayland = window.wm() == wsi::WM::WAYLAND; - - if (is_wayland) return make_wayland_surface; - - return make_xcb_surface; - }(); - -#elif defined(STORMKIT_OS_IOS) - const auto create_surface = [this, &window, &instance] noexcept { - const auto create_info - = VkIOSSurfaceCreateInfoMVK { .sType - = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK, - .pView = m_window->native_handle() }; - CHECK_VK_ERROR(vkCreateIOSSurfaceMVK(instance, &create_info, &m_surface)); - }; -#else - const auto create_surface = [] static noexcept {}; - assertWithMessage(true, "This platform WSI is not supported !"); -#endif - - create_surface() - .transform(core :.monadic::set(m_vk_surface)) - .transform_error(core :.monadic::map(core :.monadic::narrow(), - core :.monadic::throw_as_exception())); - } -} // namespace stormkit::gpu diff --git a/src/Gpu/Core/Vulkan.cpp b/src/Gpu/Core/Vulkan.cpp deleted file mode 100644 index bb2e1d983..000000000 --- a/src/Gpu/Core/Vulkan.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include - -#include - -import vulkan_hpp; - -VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE diff --git a/src/Gpu/Resource/Buffer.cpp b/src/Gpu/Resource/Buffer.cpp deleted file mode 100644 index 90c5e6bd5..000000000 --- a/src/Gpu/Resource/Buffer.cpp +++ /dev/null @@ -1,68 +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 stormkit.Gpu; - -import std; - -import stormkit.core; - -import :Core; -import stormkit.Gpu.Vulkan; - -import :Resource.Buffer; - -namespace stormkit::gpu { - ///////////////////////////////////// - ///////////////////////////////////// - Buffer::Buffer(const Device& device, const CreateInfo& info, bool persistently_mapped, Tag) - : m_usages { info.usages }, m_size { info.size }, - m_is_persistently_mapped { persistently_mapped } { - device.vkHandle() - .createBuffer({ .size = m_size, - .usage = narrow(m_usages), - .sharingMode = vk::SharingMode::eExclusive }) - .transform(core :.monadic::set(m_vk_buffer)) - .transform([this, &info, &device]() noexcept -> VulkanExpected { - const auto requirements = m_vk_buffer->getMemoryRequirements(); - - auto allocate_info = vma::AllocationCreateInfo {}.setRequiredFlags( - narrow(info.property)); - - auto&& allocator = device.vmaAllocator(); - - auto&& [error, vma_allocation] - = allocator.allocateMemoryUnique(requirements, allocate_info); - if (error != vk::Result::eSuccess) - return std::unexpected { narrow(error) }; - - m_vma_allocation = std::move(vma_allocation); - - error = allocator.bindBufferMemory(*m_vma_allocation, *m_vk_buffer.get()); - if (error != vk::Result::eSuccess) - return std::unexpected { narrow(error) }; - - if (m_is_persistently_mapped) auto _ = map(device, 0u); - - return {}; - }) - .transform_error(core :.monadic::map(core :.monadic::narrow(), - core :.monadic::throw_as_exception())); - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto Buffer::findMemoryType(UInt type_filter, - vk::MemoryPropertyFlags properties, - const vk::PhysicalDeviceMemoryProperties& mem_properties, - const vk::MemoryRequirements&) -> UInt { - for (auto i : range(mem_properties.memoryTypeCount)) { - if ((type_filter & (1 << i)) - and (checkFlag(mem_properties.memoryTypes[i].propertyFlags, properties))) - return i; - } - - return 0; - } -} // namespace stormkit::gpu diff --git a/src/Gpu/Resource/Shader.cpp b/src/Gpu/Resource/Shader.cpp deleted file mode 100644 index 30294888d..000000000 --- a/src/Gpu/Resource/Shader.cpp +++ /dev/null @@ -1,53 +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 stormkit.Gpu; - -import std; - -import stormkit.core; - -import :Core; -import stormkit.Gpu.Vulkan; - -import :Resource.Shader; - -namespace stormkit::gpu { - ///////////////////////////////////// - ///////////////////////////////////// - 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 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(); - } -} // namespace stormkit::gpu diff --git a/src/core/stacktrace.cpp b/src/core/stacktrace.cpp index 79bce6893..fa6c26537 100644 --- a/src/core/stacktrace.cpp +++ b/src/core/stacktrace.cpp @@ -8,9 +8,7 @@ module; #include -#if defined(__cpp_lib_stacktrace) \ - and __cpp_lib_stacktrace >= 202011L \ - and not defined(STORMKIT_COMPILER_LIBCPP) +#if defined(__cpp_lib_stacktrace) and __cpp_lib_stacktrace >= 202011L #define STD_STACKTRACE_SUPPORTED #endif @@ -31,12 +29,12 @@ namespace stormkit { inline namespace core { auto print_stacktrace(int ignore_count) noexcept -> void { const auto thread_name = get_current_thread_name(); if (not std::empty(thread_name)) - std::println(std::cerr, + std::println(get_stderr(), "================= CALLSTACK (thread name: {}, id: {}) =================", thread_name, std::this_thread::get_id()); else - std::println(std::cerr, + std::println(get_stderr(), "================= CALLSTACK (thread id: {}) =================", std::this_thread::get_id()); #if defined(STD_STACKTRACE_SUPPORTED) @@ -57,27 +55,34 @@ namespace stormkit { inline namespace core { #endif #ifdef STORMKIT_COMPILER_LIBCPP - const auto address = 1; - const auto module = "aaa"sv; - auto symbol = "aaa"sv; + auto splitted = split(std::to_string(frame), ':'); + const auto address = *from_string(splitted[0].substr(2), 16); + auto symbol = (std::size(splitted) >= 2) ? splitted[1] : ""s; #endif - const auto object_address - = (address == 0 ? "inlined" : std::format("{:#010x}", address)); + const auto object_address = (address == 0 ? "inlined" + : std::format("{:#010x}", address)); - const auto formatted_symbol - = (symbol == "") ? std::format(" on {}", module) - : std::format(" in {} on {}", YELLOW_TEXT_STYLE | symbol, module); + const auto formatted_symbol = (symbol == "") + ? "" + : std::format(" in{}", YELLOW_TEXT_STYLE | symbol); - if (frame.source_file() != "" and frame.source_line() != 0) { - std::println(std::cerr, + if (not std::ranges::empty(frame.source_file()) and frame.source_line() != 0) { + std::println(get_stderr(), "{}# {}{} at {}:{}", (i++ - ignore_count), BLUE_TEXT_STYLE | object_address, formatted_symbol, - BLUE_TEXT_STYLE | frame.source_file(), + GREEN_TEXT_STYLE | frame.source_file(), BLUE_TEXT_STYLE | frame.source_line()); + } else if (not std::ranges::empty(frame.source_file())) { + std::println(get_stderr(), + "{}# {}{} at {}", + (i++ - ignore_count), + BLUE_TEXT_STYLE | object_address, + formatted_symbol, + GREEN_TEXT_STYLE | frame.source_file()); } else { - std::println(std::cerr, + std::println(get_stderr(), "{}# {}{}", (i++ - ignore_count), BLUE_TEXT_STYLE | object_address, @@ -95,22 +100,26 @@ namespace stormkit { inline namespace core { auto symbol = frame.symbol; #ifdef STORMKIT_COMPILER_LIBCPP symbol = replace(symbol, "::__1::", "::"); + symbol = replace(symbol, "__invoke", "invoke"); + symbol = replace(symbol, "[abi:se210000]", ""); #endif - symbol - = replace(symbol, "basic_string_view>", "string_view"); + symbol = replace(symbol, + "basic_string_view>", + "string_view"); symbol = replace(symbol, "basic_string, std::allocator>", "string"); - const auto object_address - = (frame.object_address == 0 ? "inlined" - : std::format("{:#010x}", frame.object_address)); + const auto object_address = (frame.object_address == 0 + ? "inlined" + : std::format("{:#010x}", frame.object_address)); - const auto formatted_symbol - = (frame.symbol == "") ? "" : std::format(" in {}", YELLOW_TEXT_STYLE | symbol); + const auto formatted_symbol = (frame.symbol == "") + ? "" + : std::format(" in {}", YELLOW_TEXT_STYLE | symbol); if (frame.line.has_value() and frame.column.has_value()) { - std::println(std::cerr, + std::println(get_stderr(), "{}# {}{} at {}:{}:{}", (i++ - ignore_count), BLUE_TEXT_STYLE | object_address, @@ -119,7 +128,7 @@ namespace stormkit { inline namespace core { BLUE_TEXT_STYLE | frame.line.value(), BLUE_TEXT_STYLE | frame.column.value()); } else - std::println(std::cerr, + std::println(get_stderr(), "{}# {}{} at {}", (i++ - ignore_count), BLUE_TEXT_STYLE | object_address, @@ -127,5 +136,7 @@ namespace stormkit { inline namespace core { GREEN_TEXT_STYLE | frame.filename); } #endif + std::println("=============================================================================" + "==============="); } }} // namespace stormkit::core diff --git a/src/gpu/core/device.cpp b/src/gpu/core/device.cpp new file mode 100644 index 000000000..e89b6fd51 --- /dev/null +++ b/src/gpu/core/device.cpp @@ -0,0 +1,428 @@ +// 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.core; + +import stormkit.log; + +using namespace std::literals; + +namespace { + constexpr auto RAYTRACING_EXTENSIONS = std::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 + }; + + constexpr auto BASE_EXTENSIONS = std::array { "VK_KHR_maintenance3"sv }; + constexpr auto SWAPCHAIN_EXTENSIONS = std::array { "VK_KHR_swapchain"sv }; + + VkResult vmaImportVulkanFunctionsFromVolk(const VmaAllocatorCreateInfo* pAllocatorCreateInfo, + VmaVulkanFunctions* pDstVulkanFunctions) noexcept { + using std::memset; + stormkit::expects(pAllocatorCreateInfo != nullptr); + stormkit::expects(pAllocatorCreateInfo->instance != nullptr); + stormkit::expects(pAllocatorCreateInfo->device != nullptr); + + memset(pDstVulkanFunctions, 0, sizeof(*pDstVulkanFunctions)); + + VolkDeviceTable src = {}; + + volkLoadDeviceTable(&src, pAllocatorCreateInfo->device); + +#define COPY_GLOBAL_TO_VMA_FUNC(volkName, vmaName) \ + if (!pDstVulkanFunctions->vmaName) pDstVulkanFunctions->vmaName = volkName; + +#define COPY_DEVICE_TO_VMA_FUNC(volkName, vmaName) \ + if (!pDstVulkanFunctions->vmaName) pDstVulkanFunctions->vmaName = src.volkName; + + COPY_GLOBAL_TO_VMA_FUNC(vkGetInstanceProcAddr, vkGetInstanceProcAddr) + + COPY_GLOBAL_TO_VMA_FUNC(vkGetDeviceProcAddr, vkGetDeviceProcAddr) + + COPY_GLOBAL_TO_VMA_FUNC(vkGetPhysicalDeviceProperties, vkGetPhysicalDeviceProperties) + + COPY_GLOBAL_TO_VMA_FUNC(vkGetPhysicalDeviceMemoryProperties, + vkGetPhysicalDeviceMemoryProperties) + + COPY_DEVICE_TO_VMA_FUNC(vkAllocateMemory, vkAllocateMemory) + + COPY_DEVICE_TO_VMA_FUNC(vkFreeMemory, vkFreeMemory) + + COPY_DEVICE_TO_VMA_FUNC(vkMapMemory, vkMapMemory) + + COPY_DEVICE_TO_VMA_FUNC(vkUnmapMemory, vkUnmapMemory) + + COPY_DEVICE_TO_VMA_FUNC(vkFlushMappedMemoryRanges, vkFlushMappedMemoryRanges) + + COPY_DEVICE_TO_VMA_FUNC(vkInvalidateMappedMemoryRanges, vkInvalidateMappedMemoryRanges) + + COPY_DEVICE_TO_VMA_FUNC(vkBindBufferMemory, vkBindBufferMemory) + + COPY_DEVICE_TO_VMA_FUNC(vkBindImageMemory, vkBindImageMemory) + + COPY_DEVICE_TO_VMA_FUNC(vkGetBufferMemoryRequirements, vkGetBufferMemoryRequirements) + + COPY_DEVICE_TO_VMA_FUNC(vkGetImageMemoryRequirements, vkGetImageMemoryRequirements) + + COPY_DEVICE_TO_VMA_FUNC(vkCreateBuffer, vkCreateBuffer) + + COPY_DEVICE_TO_VMA_FUNC(vkDestroyBuffer, vkDestroyBuffer) + + COPY_DEVICE_TO_VMA_FUNC(vkCreateImage, vkCreateImage) + + COPY_DEVICE_TO_VMA_FUNC(vkDestroyImage, vkDestroyImage) + + COPY_DEVICE_TO_VMA_FUNC(vkCmdCopyBuffer, vkCmdCopyBuffer) + +#if VMA_VULKAN_VERSION >= 1001000 + + if (pAllocatorCreateInfo->vulkanApiVersion >= VK_MAKE_VERSION(1, 1, 0)) + + { + COPY_GLOBAL_TO_VMA_FUNC(vkGetPhysicalDeviceMemoryProperties2, + vkGetPhysicalDeviceMemoryProperties2KHR) + + COPY_DEVICE_TO_VMA_FUNC(vkGetBufferMemoryRequirements2, + vkGetBufferMemoryRequirements2KHR) + + COPY_DEVICE_TO_VMA_FUNC(vkGetImageMemoryRequirements2, vkGetImageMemoryRequirements2KHR) + + COPY_DEVICE_TO_VMA_FUNC(vkBindBufferMemory2, vkBindBufferMemory2KHR) + + COPY_DEVICE_TO_VMA_FUNC(vkBindImageMemory2, vkBindImageMemory2KHR) + } + +#endif + +#if VMA_VULKAN_VERSION >= 1003000 + + if (pAllocatorCreateInfo->vulkanApiVersion >= VK_MAKE_VERSION(1, 3, 0)) + + { + COPY_DEVICE_TO_VMA_FUNC(vkGetDeviceBufferMemoryRequirements, + vkGetDeviceBufferMemoryRequirements) + + COPY_DEVICE_TO_VMA_FUNC(vkGetDeviceImageMemoryRequirements, + vkGetDeviceImageMemoryRequirements) + } + +#endif + +#if VMA_KHR_MAINTENANCE4 + + if ((pAllocatorCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_MAINTENANCE4_BIT) != 0) + + { + COPY_DEVICE_TO_VMA_FUNC(vkGetDeviceBufferMemoryRequirementsKHR, + vkGetDeviceBufferMemoryRequirements) + + COPY_DEVICE_TO_VMA_FUNC(vkGetDeviceImageMemoryRequirementsKHR, + vkGetDeviceImageMemoryRequirements) + } + +#endif + +#if VMA_DEDICATED_ALLOCATION + + if ((pAllocatorCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT) != 0) + + { + COPY_DEVICE_TO_VMA_FUNC(vkGetBufferMemoryRequirements2KHR, + vkGetBufferMemoryRequirements2KHR) + + COPY_DEVICE_TO_VMA_FUNC(vkGetImageMemoryRequirements2KHR, + vkGetImageMemoryRequirements2KHR) + } + +#endif + +#if VMA_BIND_MEMORY2 + + if ((pAllocatorCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT) != 0) + + { + COPY_DEVICE_TO_VMA_FUNC(vkBindBufferMemory2KHR, vkBindBufferMemory2KHR) + + COPY_DEVICE_TO_VMA_FUNC(vkBindImageMemory2KHR, vkBindImageMemory2KHR) + } + +#endif + +#if VMA_MEMORY_BUDGET + + if ((pAllocatorCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT) != 0) + + { + COPY_GLOBAL_TO_VMA_FUNC(vkGetPhysicalDeviceMemoryProperties2KHR, + vkGetPhysicalDeviceMemoryProperties2KHR) + } + +#endif + +#if VMA_EXTERNAL_MEMORY_WIN32 + + if ((pAllocatorCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_EXTERNAL_MEMORY_WIN32_BIT) != 0) + + { + COPY_DEVICE_TO_VMA_FUNC(vkGetMemoryWin32HandleKHR, vkGetMemoryWin32HandleKHR) + } + +#endif + +#undef COPY_DEVICE_TO_VMA_FUNC + +#undef COPY_GLOBAL_TO_VMA_FUNC + + return VK_SUCCESS; + } +} // 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 ...); + }; + } + + ///////////////////////////////////// + ///////////////////////////////////// + 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; + UInt32 count = 0u; + PADDING(3); + QueueFlag flags = QueueFlag {}; + }; + + const auto raster_queue = [&queue_families]() -> Queue_ { + const auto it = std::ranges::find_if(queue_families, find_queue()); + if (it == std::ranges::cend(queue_families)) return {}; + + return { + .id = as(std::distance(std::ranges::cbegin(queue_families), it)), + .count = it->count, + .flags = it->flags, + }; + }(); + + const auto compute_queue = [&queue_families]() -> Queue_ { + const auto it = std::ranges::find_if(queue_families, + find_queue()); + if (it == std::ranges::cend(queue_families)) return {}; + + return { .id = as(std::distance(std::ranges::cbegin(queue_families), it)), + .count = it->count, + .flags = it->flags }; + }(); + + const auto transfert_queue = [&queue_families]() -> Queue_ { + const auto it = std::ranges:: + find_if(queue_families, + find_queue()); + if (it == std::ranges::cend(queue_families)) return {}; + + return { .id = as(std::distance(std::ranges::cbegin(queue_families), it)), + .count = it->count, + .flags = it->flags }; + }(); + + const auto queues = [&] { + auto q = std::vector {}; + q.reserve(3); + + 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); + + return q; + }(); + + auto priorities = std::vector> {}; + priorities.reserve(std::size(queues)); + + const auto queue_create_infos = transform(queues, [&priorities](auto queue) { + auto& priority = priorities.emplace_back(); + + priority.resize(queue->count, 1.f); + + return VkDeviceQueueCreateInfo { + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .queueFamilyIndex = queue->id.value(), + .queueCount = 1, + .pQueuePriorities = std::data(priority), + }; + }); + + const auto& capabilities = m_physical_device->capabilities(); + const auto enabled_features = [&capabilities] noexcept { + auto out = VkPhysicalDeviceFeatures {}; + zero_bytes(out); + 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(); + + device_logger.dlog("Device extensions: {}", device_extensions); + + const auto swapchain_available = [&] { + for (const auto& ext : SWAPCHAIN_EXTENSIONS) + if (std::ranges::none_of(device_extensions, core::monadic::is(ext))) return false; + + return true; + }(); + + const auto raytracing_available = [&] { + for (const auto& ext : RAYTRACING_EXTENSIONS) + if (std::ranges::none_of(device_extensions, core::monadic::is(ext))) return false; + + return true; + }(); + + const auto extensions = [&] { + constexpr auto as_czstring = [](const auto& v) { return std::data(v); }; + + auto e = transform(BASE_EXTENSIONS, as_czstring); + if (swapchain_available and info.enable_swapchain) + merge(e, transform(SWAPCHAIN_EXTENSIONS, as_czstring)); + if (raytracing_available and info.enable_raytracing) + merge(e, transform(RAYTRACING_EXTENSIONS, as_czstring)); + + return e; + }(); + + const auto acceleration_feature = [] static noexcept { + auto out = VkPhysicalDeviceAccelerationStructureFeaturesKHR {}; + zero_bytes(out); + 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 = VkPhysicalDeviceRayTracingPipelineFeaturesKHR {}; + 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, + .flags = 0, + .queueCreateInfoCount = as(std::ranges::size(queue_create_infos)), + .pQueueCreateInfos = std::ranges::data(queue_create_infos), + .enabledLayerCount = 0, + .ppEnabledLayerNames = nullptr, + .enabledExtensionCount = as(std::ranges::size(extensions)), + .ppEnabledExtensionNames = std::ranges::data(extensions), + .pEnabledFeatures = &enabled_features, + }; + + auto allocator_create_info = VmaAllocatorCreateInfo { + .flags = 0, + .physicalDevice = m_physical_device->native_handle(), + .device = nullptr, + .preferredLargeHeapBlockSize = 0, + .pAllocationCallbacks = nullptr, + .pDeviceMemoryCallbacks = nullptr, + .pHeapSizeLimit = nullptr, + .pVulkanFunctions = nullptr, + .instance = instance.native_handle(), + .vulkanApiVersion = vk_make_version(1, 4, 0), + .pTypeExternalMemoryHandleTypes = nullptr, + }; + + 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); + return vk_call(vmaImportVulkanFunctionsFromVolk, + &allocator_create_info); + }) + .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([this, &raster_queue] noexcept { + if (raster_queue.id) + m_raster_queue = QueueEntry { .id = *raster_queue.id, + .count = raster_queue.count, + .flags = raster_queue.flags }; + + set_object_name(*this, + std::format("StormKit:Device ({})", + m_physical_device->info().device_name)); + }) + .transform_error(core::monadic::narrow()); + } + + ///////////////////////////////////// + ///////////////////////////////////// + auto Device::wait_for_fences(std::span> fences, + bool wait_all, + const std::chrono::milliseconds& timeout) const noexcept + -> Expected { + const auto vk_fences = fences + | std::views::transform(to_vkhandle) + | std::ranges::to(); + + return vk_call(m_vk_device_table.vkWaitForFences, + { VK_SUCCESS, VK_NOT_READY }, + m_vk_handle, + std::ranges::size(vk_fences), + std::ranges::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 + | std::views::transform(to_vkhandle) + | std::ranges::to(); + + return vk_call(m_vk_device_table.vkResetFences, + m_vk_handle, + std ::ranges::size(vk_fences), + std::ranges::data(vk_fences)) + .transform_error(core::monadic::narrow()); + } +} // namespace stormkit::gpu diff --git a/src/gpu/core/instance.cpp b/src/gpu/core/instance.cpp new file mode 100644 index 000000000..06d0bcfa3 --- /dev/null +++ b/src/gpu/core/instance.cpp @@ -0,0 +1,249 @@ +// 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.core; + +import stormkit.log; + +namespace stormkit::gpu { + LOGGER("stormkit.gpu") + + namespace { + constexpr auto VALIDATION_LAYERS = std::array { + "VK_LAYER_KHRONOS_validation", +#ifdef STORMKIT_OS_LINUX + "VK_LAYER_MESA_overlay", +#endif + }; + + [[maybe_unused]] + constexpr auto VALIDATION_FEATURES + = std::array { 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 BASE_EXTENSIONS = std::array { "VK_KHR_get_physical_device_properties2" }; + + constexpr auto SURFACE_EXTENSIONS = std::array { + "VK_KHR_surface", + }; + + constexpr auto WSI_SURFACE_EXTENSIONS = std::array { +#ifdef STORMKIT_OS_WINDOWS + "VK_KHR_win32_surface" +#elif defined(STORMKIT_OS_LINUX) + "VK_KHR_xcb_surface", + "VK_KHR_wayland_surface" +#elif defined(STORMKIT_OS_MACOS) + "VK_MVK_MACOS_surface" +#elif defined(STORMKIT_OS_IOS) + "VK_MVK_IOS_surface" +#endif + }; + + ///////////////////////////////////// + ///////////////////////////////////// + auto debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT severity, + VkDebugUtilsMessageTypeFlagsEXT, + const VkDebugUtilsMessengerCallbackDataEXT* callback_data, + void*) noexcept -> UInt32 { + 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_validation_layer_support(bool validation_layers_enabled) noexcept -> bool { + if (!validation_layers_enabled) return false; + + const auto result = vk_enumerate(vkEnumerateInstanceLayerProperties); + if (not result) return false; + const auto layers = std::move(result).value(); + dlog("Layers found: {}", + layers | std::views::transform([](auto&& layer) static noexcept { + return std::string_view { layer.layerName }; + })); + for (const auto& layer_name : std::as_const(VALIDATION_LAYERS)) { + auto layer_found = false; + + for (const auto& layer_properties : layers) { + if (std::strcmp(layer_name, layer_properties.layerName) == 0) { + layer_found = true; + break; + } + } + + if (!layer_found) { + dlog("Failed to find validation layers, disabling..."); + return false; + } + } + + return true; + } + + ///////////////////////////////////// + ///////////////////////////////////// + auto check_extension_support(std::span supported_extensions, + std::span extensions) noexcept + -> bool { + auto required_extensions = HashSet { std::ranges::begin(extensions), + std::ranges::end(extensions) }; + + for (const auto& extension : supported_extensions) required_extensions.erase(extension); + + return required_extensions.empty(); + } + + ///////////////////////////////////// + ///////////////////////////////////// + auto check_extension_support(std::span supported_extensions, + std::span extensions) noexcept -> bool { + const auto ext = extensions + | std::views::transform(core::monadic::init()) + | std::ranges::to(); + return check_extension_support(supported_extensions, ext); + } + } // namespace + + ///////////////////////////////////// + ///////////////////////////////////// + auto Instance::do_init() noexcept -> Expected { + return vk_enumerate(vkEnumerateInstanceExtensionProperties, nullptr) + .and_then([this](auto&& exts) noexcept { + m_extensions = exts + | std::views::transform([](auto&& extension) static noexcept { + return std::string { extension.extensionName }; + }) + | std::ranges::to(); + + dlog("Instance extensions: {}", m_extensions); + + const auto validation_layers = [this]() noexcept { + auto output = std::vector {}; + m_validation_layers_enabled + = check_validation_layer_support(m_validation_layers_enabled); + if (m_validation_layers_enabled) { + output = VALIDATION_LAYERS | std::ranges::to(); + } + + return output; + }(); + ilog("Enabling 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" }); + + return e; + }(); + + 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_make_version(1, 4, 0), + }; + + const auto create_info = VkInstanceCreateInfo { + .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .pApplicationInfo = &app_info, + .enabledLayerCount = as(std::ranges::size(validation_layers)), + .ppEnabledLayerNames = std::ranges::data(validation_layers), + .enabledExtensionCount = as(std::ranges::size(instance_extensions)), + .ppEnabledExtensionNames = std::ranges::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(core::monadic::narrow()); + } + + ///////////////////////////////////// + ///////////////////////////////////// + auto Instance::do_load_instance() noexcept -> VulkanExpected { + volkLoadInstanceOnly(m_vk_handle); + 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, + }; + + return vk_call(vkCreateDebugUtilsMessengerEXT, + m_vk_handle, + &create_info, + nullptr) + .transform(core::monadic::set(m_vk_debug_utils_handle)) + .transform([] static noexcept { ilog("Validation layers successfully enabled !"); }); + } + + ///////////////////////////////////// + ///////////////////////////////////// + auto Instance::do_retrieve_physical_devices() noexcept -> VulkanExpected { + return vk_enumerate(vkEnumeratePhysicalDevices, m_vk_handle) + .transform([this](auto&& physical_devices) { + // clang-format off + m_physical_devices = std::forward(physical_devices) + | std::views::transform([](auto&& physical_device) static noexcept { + return PhysicalDevice { std::move(physical_device) }; + }) + | std::ranges::to(); + // clang-format on + }); + } +} // namespace stormkit::gpu diff --git a/src/gpu/core/loader.cpp b/src/gpu/core/loader.cpp new file mode 100644 index 000000000..761b9ec37 --- /dev/null +++ b/src/gpu/core/loader.cpp @@ -0,0 +1,7 @@ +module stormkit.gpu.core; + +namespace stormkit::gpu { + auto initialize_backend() -> Expected { + return vk_call(volkInitialize).transform_error(monadic::from_vk()); + } +} // namespace stormkit::gpu diff --git a/src/Gpu/Core/PhysicalDevice.cpp b/src/gpu/core/physical_device.cpp similarity index 52% rename from src/Gpu/Core/PhysicalDevice.cpp rename to src/gpu/core/physical_device.cpp index d6b207890..70a440840 100644 --- a/src/Gpu/Core/PhysicalDevice.cpp +++ b/src/gpu/core/physical_device.cpp @@ -2,36 +2,77 @@ // This file is subject to the license terms in the LICENSE file // found in the top-level of this distribution -module stormkit.Gpu; +module stormkit.gpu.core; -import std; +using namespace std::literals; -import stormkit.core; +namespace stormkit::gpu { + namespace { + constexpr auto RAYTRACING_EXTENSIONS = std::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 + }; -import stormkit.Gpu.Vulkan; + ///////////////////////////////////// + ///////////////////////////////////// + auto vendor_name_by_id(UInt64 ID) -> std::string_view { + switch (ID) { + case 0x1002: return "AMD"; + case 0x1010: return "ImgTex"; + case 0x10DE: return "NVidia"; + case 0x8086: return "Intel"; + case 0x5143: return "Qualcomm"; + case 0x13B5: return "ARM"; + } -namespace stormkit::gpu { - static auto vendorNameByID(UInt64 ID) -> std::string_view { - switch (ID) { - case 0x1002: return "AMD"; - case 0x1010: return "ImgTex"; - case 0x10DE: return "NVidia"; - case 0x8086: return "Intel"; - case 0x5143: return "Qualcomm"; - case 0x13B5: return "ARM"; + return "UNKNOWN"; } + } // namespace + + ///////////////////////////////////// + ///////////////////////////////////// + auto score_physical_device(const PhysicalDevice& physical_device) noexcept -> UInt64 { + const auto support_raytracing = physical_device + .check_extension_support(RAYTRACING_EXTENSIONS); + + auto score = UInt64 { 0u }; - return "UNKNOWN"; + const auto& info = physical_device.info(); + const auto& capabilities = physical_device.capabilities(); + + if (info.type == PhysicalDeviceType::DISCRETE_GPU) score += 10000000u; + else if (info.type == PhysicalDeviceType::VIRTUAL_GPU) + score += 5000000u; + else if (info.type == PhysicalDeviceType::INTEGRATED_GPU) + score += 250000u; + + score += capabilities.limits.max_image_dimension_1D; + score += capabilities.limits.max_image_dimension_2D; + score += capabilities.limits.max_image_dimension_3D; + score += capabilities.limits.max_image_dimension_cube; + score += capabilities.limits.max_uniform_buffer_range; + score += info.api_major_version * 10000000u; + score += info.api_minor_version * 10000u; + score += info.api_patch_version * 100u; + + if (support_raytracing) score += 10000000u; + + return score; } // TODO implement // https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_KHR_driver_properties.html ///////////////////////////////////// ///////////////////////////////////// - PhysicalDevice::PhysicalDevice(vk::raii::PhysicalDevice physical_device) - : m_vk_physical_device { std::move(physical_device) } { - const auto properties = m_vk_physical_device.getProperties(); - const auto features = m_vk_physical_device.getFeatures(); + 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; @@ -46,18 +87,18 @@ namespace stormkit::gpu { m_device_info.device_name.shrink_to_fit(); m_device_info.vendor_id = vendor_id; - m_device_info.vendor_name = vendorNameByID(vendor_id); - m_device_info.api_major_version = vkVersionMajor(properties.apiVersion); - m_device_info.api_minor_version = vkVersionMinor(properties.apiVersion); - m_device_info.api_patch_version = vkVersionPatch(properties.apiVersion); - - m_device_info.driver_major_version = vkVersionMajor(properties.driverVersion); - m_device_info.driver_minor_version = vkVersionMinor(properties.driverVersion); - m_device_info.driver_patch_version = vkVersionPatch(properties.driverVersion); + 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 = narrow(properties.deviceType); + 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; @@ -68,98 +109,98 @@ namespace stormkit::gpu { 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.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_samplers = properties.limits + .maxPerStageDescriptorSamplers; m_capabilities.limits.max_per_stage_descriptor_uniform_buffers - = properties.limits.maxPerStageDescriptorUniformBuffers; + = properties.limits.maxPerStageDescriptorUniformBuffers; m_capabilities.limits.max_per_stage_descriptor_storage_buffers - = properties.limits.maxPerStageDescriptorStorageBuffers; + = properties.limits.maxPerStageDescriptorStorageBuffers; m_capabilities.limits.max_per_stage_descriptor_sampled_images - = properties.limits.maxPerStageDescriptorSampledImages; + = properties.limits.maxPerStageDescriptorSampledImages; m_capabilities.limits.max_per_stage_descriptor_storage_images - = properties.limits.maxPerStageDescriptorStorageImages; + = 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; + = 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; + = properties.limits.maxDescriptorSetUniformBuffers; m_capabilities.limits.max_descriptor_set_uniform_buffers_dynamic - = properties.limits.maxDescriptorSetUniformBuffersDynamic; + = properties.limits.maxDescriptorSetUniformBuffersDynamic; m_capabilities.limits.max_descriptor_set_storage_buffers - = properties.limits.maxDescriptorSetStorageBuffers; + = 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; + = 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; + = 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_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; + = properties.limits.maxTessellationControlPerVertexInputComponents; m_capabilities.limits.max_tessellation_control_per_vertex_output_components - = properties.limits.maxTessellationControlPerVertexOutputComponents; + = properties.limits.maxTessellationControlPerVertexOutputComponents; m_capabilities.limits.max_tessellation_control_per_patch_output_components - = properties.limits.maxTessellationControlPerPatchOutputComponents; + = properties.limits.maxTessellationControlPerPatchOutputComponents; m_capabilities.limits.max_tessellation_control_total_output_components - = properties.limits.maxTessellationControlTotalOutputComponents; + = properties.limits.maxTessellationControlTotalOutputComponents; m_capabilities.limits.max_tessellation_evaluation_input_components - = properties.limits.maxTessellationEvaluationInputComponents; + = 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; + = 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; + = 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; + = 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; + = 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_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; @@ -170,12 +211,12 @@ namespace stormkit::gpu { 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_texel_buffer_offset_alignment = properties.limits + .minTexelBufferOffsetAlignment; m_capabilities.limits.min_uniform_buffer_offset_alignment - = properties.limits.minUniformBufferOffsetAlignment; + = properties.limits.minUniformBufferOffsetAlignment; m_capabilities.limits.min_storage_buffer_offset_alignment - = properties.limits.minStorageBufferOffsetAlignment; + = 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; @@ -183,45 +224,37 @@ namespace stormkit::gpu { 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; + = 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. - operator vk::SampleCountFlags::MaskType()); - m_capabilities.limits.framebuffer_depth_sample_counts - = narrow(properties.limits.framebufferDepthSampleCounts. - operator vk::SampleCountFlags::MaskType()); - m_capabilities.limits.framebuffer_stencil_sample_counts - = narrow(properties.limits.framebufferStencilSampleCounts. - operator vk::SampleCountFlags::MaskType()); - m_capabilities.limits.framebuffer_no_attachments_sample_counts - = narrow(properties.limits.framebufferNoAttachmentsSampleCounts. - operator vk::SampleCountFlags::MaskType()); + m_capabilities.limits.framebuffer_color_sample_counts = narrow< + SampleCountFlag>(properties.limits.framebufferColorSampleCounts); + m_capabilities.limits.framebuffer_depth_sample_counts = narrow< + SampleCountFlag>(properties.limits.framebufferDepthSampleCounts); + m_capabilities.limits.framebuffer_stencil_sample_counts = narrow< + SampleCountFlag>(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. - operator vk::SampleCountFlags::MaskType()); - m_capabilities.limits.sampled_image_integer_sample_counts - = narrow(properties.limits.sampledImageIntegerSampleCounts. - operator vk::SampleCountFlags::MaskType()); - m_capabilities.limits.sampled_image_depth_sample_counts - = narrow(properties.limits.sampledImageDepthSampleCounts. - operator vk::SampleCountFlags::MaskType()); - m_capabilities.limits.sampled_image_stencil_sample_counts - = narrow(properties.limits.sampledImageStencilSampleCounts. - operator vk::SampleCountFlags::MaskType()); - m_capabilities.limits.storage_image_sample_counts = narrow( - properties.limits.storageImageSampleCounts.operator vk::SampleCountFlags::MaskType()); - m_capabilities.limits.max_sample_mask_words = properties.limits.maxSampleMaskWords; - m_capabilities.limits.timestamp_compute_and_engine - = properties.limits.timestampComputeAndGraphics; + m_capabilities.limits.sampled_image_color_sample_counts = narrow< + SampleCountFlag>(properties.limits.sampledImageColorSampleCounts); + m_capabilities.limits.sampled_image_integer_sample_counts = narrow< + SampleCountFlag>(properties.limits.sampledImageIntegerSampleCounts); + m_capabilities.limits.sampled_image_depth_sample_counts = narrow< + SampleCountFlag>(properties.limits.sampledImageDepthSampleCounts); + m_capabilities.limits.sampled_image_stencil_sample_counts = narrow< + SampleCountFlag>(properties.limits.sampledImageStencilSampleCounts); + m_capabilities.limits.storage_image_sample_counts = narrow< + SampleCountFlag>(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; + = 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)); @@ -232,9 +265,9 @@ namespace stormkit::gpu { 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; + = properties.limits.optimalBufferCopyOffsetAlignment; m_capabilities.limits.optimal_buffer_copy_row_pitch_alignment - = properties.limits.optimalBufferCopyRowPitchAlignment; + = properties.limits.optimalBufferCopyRowPitchAlignment; m_capabilities.limits.non_coherent_atom_size = properties.limits.nonCoherentAtomSize; m_capabilities.features.robust_buffer_access = features.robustBufferAccess; @@ -247,7 +280,7 @@ namespace stormkit::gpu { 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.draw_indirect_first_instance = features.draw_indirectFirstInstance; m_capabilities.features.depth_clamp = features.depthClamp; m_capabilities.features.depth_bias_clamp = features.depthBiasClamp; m_capabilities.features.fill_Mode_non_solid = features.fillModeNonSolid; @@ -263,27 +296,27 @@ namespace stormkit::gpu { 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; + = features.vertexPipelineStoresAndAtomics; m_capabilities.features.fragment_stores_and_atomics = features.fragmentStoresAndAtomics; m_capabilities.features.shader_tessellation_and_geometry_point_size - = features.shaderTessellationAndGeometryPointSize; + = 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; + = features.shaderStorageImageExtendedFormats; + m_capabilities.features.shader_storage_image_multisample = features + .shaderStorageImageMultisample; m_capabilities.features.shader_storage_image_read_without_format - = features.shaderStorageImageReadWithoutFormat; + = features.shaderStorageImageReadWithoutFormat; m_capabilities.features.shader_storage_image_write_without_format - = features.shaderStorageImageWriteWithoutFormat; + = features.shaderStorageImageWriteWithoutFormat; m_capabilities.features.shader_uniform_buffer_array_dynamic_indexing - = features.shaderUniformBufferArrayDynamicIndexing; + = features.shaderUniformBufferArrayDynamicIndexing; m_capabilities.features.shader_sampled_image_array_dynamic_indexing - = features.shaderSampledImageArrayDynamicIndexing; + = features.shaderSampledImageArrayDynamicIndexing; m_capabilities.features.shader_storage_buffer_array_dynamic_indexing - = features.shaderStorageBufferArrayDynamicIndexing; + = features.shaderStorageBufferArrayDynamicIndexing; m_capabilities.features.shader_storage_image_array_dynamic_indexing - = features.shaderStorageImageArrayDynamicIndexing; + = 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; @@ -303,10 +336,15 @@ namespace stormkit::gpu { m_capabilities.features.variable_multisample_rate = features.variableMultisampleRate; m_capabilities.features.inherited_queries = features.inheritedQueries; - m_extensions = m_vk_physical_device.enumerateDeviceExtensionProperties() + 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); + const auto string_size = std::char_traits< + char>::length(extension.extensionName); auto string = std::string {}; string.resize(string_size); @@ -318,25 +356,22 @@ namespace stormkit::gpu { }) | std::ranges::to(); - m_vk_memory_properties = m_vk_physical_device.getMemoryProperties(); - m_memory_properties - = m_vk_memory_properties.memoryTypes - | std::views::transform([](auto&& property) noexcept { - return narrow( - property.propertyFlags.operator vk::MemoryPropertyFlags::MaskType()); - }) - | std::ranges::to(); - - m_queue_families - = m_vk_physical_device.getQueueFamilyProperties() - | std::views::transform([](auto&& family) noexcept { - return QueueFamily { - .flags - = narrow(family.queueFlags.operator vk::QueueFlags::MaskType()), - .count = family.queueCount - }; - }) - | std::ranges::to(); + const auto vk_memory_properties = vk_call< + VkPhysicalDeviceMemoryProperties>(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< + VkQueueFamilyProperties>(vkGetPhysicalDeviceQueueFamilyProperties, + m_vk_handle) + | std::views::transform([](auto&& family) static noexcept { + return QueueFamily { .flags = narrow(family.queueFlags), + .count = family.queueCount }; + }) + | std::ranges::to(); } ///////////////////////////////////// @@ -353,15 +388,17 @@ namespace stormkit::gpu { ///////////////////////////////////// ///////////////////////////////////// - auto PhysicalDevice::checkExtensionSupport(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::string_view extension) const noexcept + -> bool { + return std::ranges::any_of(m_extensions, [extension](const auto& e) { + return e == extension; + }); } ///////////////////////////////////// ///////////////////////////////////// - auto PhysicalDevice::checkExtensionSupport( - std::span extensions) const noexcept -> bool { + 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), @@ -374,8 +411,8 @@ namespace stormkit::gpu { ///////////////////////////////////// ///////////////////////////////////// - auto PhysicalDevice::checkExtensionSupport(std::span extensions) const noexcept - -> bool { + auto PhysicalDevice::check_extension_support(std::span extensions) + const noexcept -> bool { auto required_extensions = HashSet { std::ranges::begin(extensions), std::ranges::end(extensions) }; diff --git a/src/gpu/core/surface.cpp b/src/gpu/core/surface.cpp new file mode 100644 index 000000000..2791ad45e --- /dev/null +++ b/src/gpu/core/surface.cpp @@ -0,0 +1,125 @@ +// 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 + +#if defined(STORMKIT_OS_LINUX) + #include + #include +#elif defined(STORMKIT_OS_WINDOWS) + #include +#endif + +module stormkit.gpu; + +namespace stormkit::gpu { + ///////////////////////////////////// + ///////////////////////////////////// + auto Surface::do_init_offscreen(const Instance& instance) noexcept -> Expected { + m_vk_instance = instance.native_handle(); + assert(false, "not implemented yet"); + return {}; + } + + ///////////////////////////////////// + ///////////////////////////////////// + auto Surface::do_init_from_window(const Instance& instance, const wsi::Window& window) noexcept + -> Expected { + m_vk_instance = instance.native_handle(); +#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 = reinterpret_cast(window.native_handle()) + }; + return vk_call(vkCreateWin32SurfaceKHR, + instance.native_handle(), + &create_info, + nullptr); + }; +#elif defined(STORMKIT_OS_MACOS) + const auto create_surface = [&window, &instance] { + const auto create_info = VkMacOSSurfaceCreateInfoMVK { + .sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, + .pNext = nullptr, + .flags = 0, + .pView = window.native_handle() + }; + return vk_call(vkCreateMacOSSurfaceCreateMVK, + instance.native_handle(), + &create_info, + nullptr); + }; +#elif defined(STORMKIT_OS_LINUX) + const auto make_wayland_surface = [&window, &instance] { + struct Handles { + wl_display* display; + wl_surface* surface; + }* handles = std::bit_cast(window.native_handle()); + + const auto create_info = VkWaylandSurfaceCreateInfoKHR { + .sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, + .pNext = nullptr, + .flags = 0, + .display = handles->display, + .surface = handles->surface + }; + return vk_call(vkCreateWaylandSurfaceKHR, + instance.native_handle(), + &create_info, + nullptr); + }; + const auto make_xcb_surface = [&window, &instance] { + struct Handles { + xcb_connection_t* connection; + xcb_window_t window; + }* handles = reinterpret_cast(window.native_handle()); + + const auto create_info = VkXcbSurfaceCreateInfoKHR { + .sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR, + .pNext = nullptr, + .flags = 0, + .connection = handles->connection, + .window = handles->window + }; + return vk_call(vkCreateXcbSurfaceKHR, + instance.native_handle(), + &create_info, + nullptr); + }; + + const auto create_surface = [&window, &make_wayland_surface, &make_xcb_surface] noexcept + -> FunctionRef()> { + const auto is_wayland = window.wm() == wsi::WM::WAYLAND; + + if (is_wayland) return make_wayland_surface; + + return make_xcb_surface; + }(); + +#elif defined(STORMKIT_OS_IOS) + const auto create_surface = [this, &window, &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)); + }; +#else + const auto create_surface = [] static noexcept {}; + assertWithMessage(true, "This platform WSI is not supported !"); +#endif + + return create_surface() + .transform(core::monadic::set(m_vk_handle)) + .transform_error(core::monadic::narrow()); + } +} // namespace stormkit::gpu diff --git a/src/gpu/resource/buffer.cpp b/src/gpu/resource/buffer.cpp new file mode 100644 index 000000000..a72f2f252 --- /dev/null +++ b/src/gpu/resource/buffer.cpp @@ -0,0 +1,78 @@ +// 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 stormkit.gpu; + +namespace stormkit::gpu { + ///////////////////////////////////// + ///////////////////////////////////// + auto Buffer::do_init(MemoryPropertyFlag memory_properties) noexcept -> Expected { + const auto create_info = VkBufferCreateInfo { + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .size = m_size, + .usage = 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 allocation = VmaAllocation { nullptr }; + auto result = vmaAllocateMemoryForBuffer(m_vma_allocator, + m_vk_handle, + &create_info, + &allocation, + nullptr); + if (result != VK_SUCCESS) return std::unexpected { result }; + + return VulkanExpected { allocation }; + }) + .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()); + } + + ///////////////////////////////////// + ///////////////////////////////////// + auto Buffer::find_memory_type(UInt type_filter, + VkMemoryPropertyFlagBits properties, + const VkPhysicalDeviceMemoryProperties& mem_properties, + const VkMemoryRequirements&) noexcept -> UInt { + 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 new file mode 100644 index 000000000..88b5f0a6f --- /dev/null +++ b/src/gpu/resource/image.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 stormkit.gpu; + +namespace stormkit::gpu { + namespace { + // constexpr auto to_pixel_format(image::Image::Format format) noexcept { + // switch (format) { + // case image::Image::Format::R8_SNORM: return PixelFormat::R8_SNORM; + // case image::Image::Format::R8_UNORM: return PixelFormat::R8_UNORM; + // case image::Image::Format::RG8_SNORM: return PixelFormat::RG8_SNORM; + // case image::Image::Format::RG8_UNORM: return PixelFormat::RG8_UNORM; + // case image::Image::Format::R8I: return PixelFormat::R8I; + // case image::Image::Format::R8U: return PixelFormat::R8U; + // case image::Image::Format::RG8I: return PixelFormat::RG8I; + // case image::Image::Format::RG8U: return PixelFormat::RG8U; + // case image::Image::Format::RGB8_SNORM: return PixelFormat::RGB8_SNORM; + // case image::Image::Format::RGB8_UNORM: return PixelFormat::RGB8_UNORM; + // case image::Image::Format::BGR8_UNORM: return PixelFormat::BGR8_UNORM; + // case image::Image::Format::RGB8I: return PixelFormat::RGB8I; + // case image::Image::Format::RGB8U: return PixelFormat::RGB8U; + // case image::Image::Format::RGBA8_SNORM: return PixelFormat::RGBA8_SNORM; + // case image::Image::Format::RGBA8_UNORM: return PixelFormat::RGBA8_UNORM; + // case image::Image::Format::RGBA16_SNORM: return PixelFormat::RGBA16_SNORM; + // case image::Image::Format::BGRA8_UNORM: return PixelFormat::BGRA8_UNORM; + // case image::Image::Format::SRGB8: return PixelFormat::SRGB8; + // case image::Image::Format::SBGR8: return PixelFormat::SBGR8; + // case image::Image::Format::SRGBA8: return PixelFormat::SRGBA8; + // case image::Image::Format::SBGRA8: return PixelFormat::SBGRA8; + + // case image::Image::Format::R16_SNORM: return PixelFormat::R16_SNORM; + // case image::Image::Format::R16_UNORM: return PixelFormat::R16_UNORM; + // case image::Image::Format::R16I: return PixelFormat::R16I; + // case image::Image::Format::R16U: return PixelFormat::R16U; + // case image::Image::Format::RG16_SNORM: return PixelFormat::RG16_SNORM; + // case image::Image::Format::RG16_UNORM: return PixelFormat::RG16_UNORM; + // case image::Image::Format::RG16I: return PixelFormat::RG16I; + // case image::Image::Format::RG16U: return PixelFormat::RG16U; + // case image::Image::Format::RG16F: return PixelFormat::RG16F; + // case image::Image::Format::RGB16I: return PixelFormat::RGB16I; + // case image::Image::Format::RGB16U: return PixelFormat::RGB16U; + // case image::Image::Format::RGB16F: return PixelFormat::RGB16F; + // case image::Image::Format::RGBA16I: return PixelFormat::RGBA16I; + // case image::Image::Format::RGBA16U: return PixelFormat::RGBA16U; + // case image::Image::Format::RGBA16F: return PixelFormat::RGBA16F; + // case image::Image::Format::R16F: return PixelFormat::R16F; + + // case image::Image::Format::R32I: return PixelFormat::R32I; + // case image::Image::Format::R32U: return PixelFormat::R32U; + // case image::Image::Format::R32F: return PixelFormat::R32F; + // case image::Image::Format::RG32I: return PixelFormat::RG32I; + // case image::Image::Format::RG32U: return PixelFormat::RG32U; + // case image::Image::Format::RG32F: return PixelFormat::RG32F; + // case image::Image::Format::RGB16_SNORM: return PixelFormat::RGB16_SNORM; + // case image::Image::Format::RGB32I: return PixelFormat::RGB32I; + // case image::Image::Format::RGB32U: return PixelFormat::RGB32U; + // case image::Image::Format::RGB32F: return PixelFormat::RGB32F; + // case image::Image::Format::RGBA8I: return PixelFormat::RGBA8I; + // case image::Image::Format::RGBA8U: return PixelFormat::RGBA8U; + // case image::Image::Format::RGBA32I: return PixelFormat::RGBA32I; + // case image::Image::Format::RGBA32U: return PixelFormat::RGBA32U; + // case image::Image::Format::RGBA32F: return PixelFormat::RGBA32F; + + // default: return PixelFormat::UNDEFINED; + // } + + // return PixelFormat::UNDEFINED; + // } + } // 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 allocation = VmaAllocation { nullptr }; + auto result = vmaAllocateMemoryForImage(m_vma_allocator, + m_vk_handle, + &create_info, + &allocation, + nullptr); + if (result != VK_SUCCESS) return std::unexpected { result }; + + return VulkanExpected { allocation }; + }) + .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()); + } +} // namespace stormkit::gpu diff --git a/src/gpu/resource/shader.cpp b/src/gpu/resource/shader.cpp new file mode 100644 index 000000000..62985693e --- /dev/null +++ b/src/gpu/resource/shader.cpp @@ -0,0 +1,45 @@ +// 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 stormkit.gpu; + +namespace stormkit::gpu { + ///////////////////////////////////// + ///////////////////////////////////// + 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 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(); + } +} // namespace stormkit::gpu diff --git a/src/gpu/resource/swapchain.cpp b/src/gpu/resource/swapchain.cpp new file mode 100644 index 000000000..3815164fb --- /dev/null +++ b/src/gpu/resource/swapchain.cpp @@ -0,0 +1,172 @@ +module stormkit.gpu; + +namespace stormkit::gpu { + namespace { + ///////////////////////////////////// + ///////////////////////////////////// + auto choose_swap_surface_format(std::span 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; + } + + return formats[0]; + } + + ///////////////////////////////////// + ///////////////////////////////////// + auto choose_swap_present_mode(std::span present_modes) noexcept + -> VkPresentModeKHR { + auto present_mode_ = VK_PRESENT_MODE_FIFO_KHR; + + for (const auto& present_mode : present_modes) { + if (present_mode == VK_PRESENT_MODE_IMMEDIATE_KHR) return present_mode; + else if (present_mode == VK_PRESENT_MODE_MAILBOX_KHR) + return present_mode; + } + + return present_mode_; + } + + ///////////////////////////////////// + ///////////////////////////////////// + auto choose_swap_extent(const VkSurfaceCapabilitiesKHR& capabilities, + const math::ExtentU& 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 = as(extent); + actual_extent.width = std::max(capabilities.minImageExtent.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)); + + return actual_extent; + } + + ///////////////////////////////////// + ///////////////////////////////////// + auto choose_image_count(const VkSurfaceCapabilitiesKHR& capabilities) noexcept -> UInt32 { + auto image_count = capabilities.minImageCount + 1; + + if (capabilities.maxImageCount > 0 && image_count > capabilities.maxImageCount) + image_count = capabilities.maxImageCount; + + return image_count; + } + } // namespace + + ///////////////////////////////////// + ///////////////////////////////////// + auto SwapChain::do_init(const Device& device, + const Surface& surface, + const math::ExtentU& 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); + const auto image_count = choose_image_count(capabilities); + const auto image_sharing_mode = VK_SHARING_MODE_EXCLUSIVE; + + m_extent = as(extent); + m_pixel_format = narrow(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 = VK_IMAGE_USAGE_TRANSFER_DST_BIT, + .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 + }; + + 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, + .format = m_pixel_format + }; + return Image::create(device, create_info, std::move(image)); + }) + | std::ranges::to(); + }) + .transform_error(monadic::from_vk()); + } + + ///////////////////////////////////// + ///////////////////////////////////// + auto SwapChain::acquire_next_image(std::chrono::nanoseconds wait, + const Semaphore& image_available) const noexcept + -> Expected { + auto id = UInt32 { 0 }; + return vk_call(m_vk_device_table->vkAcquireNextImageKHR, + { VK_SUCCESS, VK_ERROR_OUT_OF_DATE_KHR, VK_SUBOPTIMAL_KHR }, + 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()); + } +} // namespace stormkit::gpu diff --git a/src/gpu/vulkan.cpp b/src/gpu/vulkan.cpp new file mode 100644 index 000000000..37221382e --- /dev/null +++ b/src/gpu/vulkan.cpp @@ -0,0 +1,8 @@ +#include + +#define VOLK_IMPLEMENTATION +#include + +#define VMA_CALL_PRE STORMKIT_API +#define VMA_IMPLEMENTATION +#include diff --git a/src/image/jpg.mpp b/src/image/jpg.mpp index c296258d7..4f6ade224 100644 --- a/src/image/jpg.mpp +++ b/src/image/jpg.mpp @@ -153,7 +153,7 @@ namespace stormkit::image::details { info.client_data = &error_data; error_mgr.error_exit = jpg::error_callback; - for (auto i : range(image_rgb.mipLevels())) { + for (auto i : range(image_rgb.mip_levels())) { if (i >= 1u) _filename += to_native_encoding(std::format("_mip{}", i)); auto file = std::fopen(_filename.string().c_str(), "wb"); diff --git a/src/log/console_logger.cpp b/src/log/console_logger.cpp index 4b9634e88..ec98ac3dd 100644 --- a/src/log/console_logger.cpp +++ b/src/log/console_logger.cpp @@ -18,16 +18,16 @@ using namespace std::literals; namespace stormkit::log { namespace { constexpr auto StyleMap = frozen::make_unordered_map({ - { Severity::INFO, - ConsoleStyle { .fg = ConsoleColor::GREEN, .modifiers = StyleModifier::INVERSE } }, - { Severity::WARNING, - ConsoleStyle { .fg = ConsoleColor::MAGENTA, .modifiers = StyleModifier::INVERSE } }, - { Severity::ERROR, - ConsoleStyle { .fg = ConsoleColor::YELLOW, .modifiers = StyleModifier::INVERSE } }, - { Severity::FATAL, - ConsoleStyle { .fg = ConsoleColor::RED, .modifiers = StyleModifier::INVERSE } }, - { Severity::DEBUG, - ConsoleStyle { .fg = ConsoleColor::CYAN, .modifiers = StyleModifier::INVERSE } }, + { Severity::INFO, + ConsoleStyle { .fg = ConsoleColor::GREEN, .modifiers = StyleModifier::INVERSE } }, + { Severity::WARNING, + ConsoleStyle { .fg = ConsoleColor::MAGENTA, .modifiers = StyleModifier::INVERSE } }, + { Severity::ERROR, + ConsoleStyle { .fg = ConsoleColor::YELLOW, .modifiers = StyleModifier::INVERSE } }, + { Severity::FATAL, + ConsoleStyle { .fg = ConsoleColor::RED, .modifiers = StyleModifier::INVERSE } }, + { Severity::DEBUG, + ConsoleStyle { .fg = ConsoleColor::CYAN, .modifiers = StyleModifier::INVERSE } }, }); } @@ -45,7 +45,8 @@ namespace stormkit::log { //////////////////////////////////////// //////////////////////////////////////// - auto ConsoleLogger::write(Severity severity, const Module& m, const char* string) -> void { + auto ConsoleLogger::write(Severity severity, const Module& m, const char* string) noexcept + -> void { const auto now = LogClock::now(); const auto time = std::chrono::duration_cast(now - m_start_time); diff --git a/src/log/file_logger.cpp b/src/log/file_logger.cpp index 198d6f8fd..a945e2bf2 100644 --- a/src/log/file_logger.cpp +++ b/src/log/file_logger.cpp @@ -17,7 +17,7 @@ namespace { namespace stormkit::log { //////////////////////////////////////// //////////////////////////////////////// - FileLogger::FileLogger(LogClock::time_point start, std::filesystem::path path) + FileLogger::FileLogger(LogClock::time_point start, std::filesystem::path path) noexcept : Logger { std::move(start) }, m_base_path { std::move(path) } { if (not std::filesystem::exists(m_base_path)) std::filesystem::create_directory(m_base_path); @@ -32,7 +32,7 @@ namespace stormkit::log { //////////////////////////////////////// FileLogger::FileLogger(LogClock::time_point start, std::filesystem::path path, - Severity log_level) + Severity log_level) noexcept : Logger { std::move(start), log_level }, m_base_path { std::move(path) } { if (not std::filesystem::exists(m_base_path)) std::filesystem::create_directory(m_base_path); @@ -45,16 +45,17 @@ namespace stormkit::log { //////////////////////////////////////// //////////////////////////////////////// - auto FileLogger::flush() -> void { + auto FileLogger::flush() noexcept -> void { for (auto& [path, stream] : m_streams) stream.flush(); } //////////////////////////////////////// //////////////////////////////////////// - auto FileLogger::write(Severity severity, const Module& m, const char* string) -> void { - const auto now = LogClock::now(); - const auto time - = std::chrono::duration_cast(now - m_start_time).count(); + auto FileLogger::write(Severity severity, const Module& m, const char* string) noexcept + -> void { + const auto now = LogClock::now(); + const auto time = std::chrono::duration_cast(now - m_start_time) + .count(); auto filepath = m_base_path / std::filesystem::path { to_native_encoding(LOG_FILE_NAME) }; if (not std::empty(m.name)) { diff --git a/src/log/logger.cpp b/src/log/logger.cpp index fa881d92e..b6426d42c 100644 --- a/src/log/logger.cpp +++ b/src/log/logger.cpp @@ -19,7 +19,7 @@ namespace stormkit::log { #else constexpr auto DEFAULT_SEVERITY = Severity::INFO | Severity::ERROR | Severity::FATAL; #endif - Logger* logger = nullptr; + constinit Logger* logger = nullptr; } // namespace ///////////////////////////////////// @@ -39,7 +39,7 @@ namespace stormkit::log { ///////////////////////////////////// ///////////////////////////////////// - Logger::~Logger() { + Logger::~Logger() noexcept { logger = nullptr; } diff --git a/src/wsi/linux/wayland/implementation.cpp b/src/wsi/linux/wayland/implementation.cpp index dafd54dfd..8949ffd53 100644 --- a/src/wsi/linux/wayland/implementation.cpp +++ b/src/wsi/linux/wayland/implementation.cpp @@ -181,36 +181,47 @@ namespace stormkit::wsi::linux::wayland { namespace { auto globals = Globals {}; - constinit const auto stormkit_registry_listener - = wl_registry_listener { .global = registry_handler, - .global_remove = registry_remover_handler }; + constinit const auto stormkit_registry_listener = wl_registry_listener { + .global = registry_handler, + .global_remove = registry_remover_handler, + }; - constinit const auto stormkit_surface_listener - = wl_surface_listener { .enter = surface_enter_handler, - .leave = surface_leave_handler }; + constinit const auto stormkit_surface_listener = wl_surface_listener { + .enter = surface_enter_handler, + .leave = surface_leave_handler, + .preferred_buffer_scale = nullptr, + .preferred_buffer_transform = nullptr, + }; - constinit const auto stormkit_xdg_surface_listener - = xdg_surface_listener { .configure = surface_configure_handler }; + constinit const auto stormkit_xdg_surface_listener = xdg_surface_listener { + .configure = surface_configure_handler, + }; - constinit const auto stormkit_xdg_toplevel_listener - = xdg_toplevel_listener { .configure = top_level_configure_handler, - .close = top_level_close_handler }; + constinit const auto stormkit_xdg_toplevel_listener = xdg_toplevel_listener { + .configure = top_level_configure_handler, + .close = top_level_close_handler, + .configure_bounds = nullptr, + .wm_capabilities = nullptr, + }; - constinit const auto stormkit_shell_listener - = xdg_wm_base_listener { .ping = shell_ping_handler }; + constinit const auto stormkit_shell_listener = xdg_wm_base_listener { + .ping = shell_ping_handler, + }; - constinit const auto stormkit_shell_surface_listener - = wl_shell_surface_listener { .ping = shell_ping_handler, - .configure = shell_surface_configure_handler, - .popup_done = nullptr }; + constinit const auto stormkit_shell_surface_listener = wl_shell_surface_listener { + .ping = shell_ping_handler, + .configure = shell_surface_configure_handler, + .popup_done = nullptr, + }; - constinit const auto stormkit_relative_pointer_listener - = zwp_relative_pointer_v1_listener { .relative_motion - = relative_pointer_relative_motion_handler }; + constinit const auto stormkit_relative_pointer_listener = zwp_relative_pointer_v1_listener { + .relative_motion = relative_pointer_relative_motion_handler, + }; - constinit const auto stormkit_locked_pointer_listener - = zwp_locked_pointer_v1_listener { .locked = locker_pointer_locker_handler, - .unlocked = locker_pointer_unlocker_handler }; + constinit const auto stormkit_locked_pointer_listener = zwp_locked_pointer_v1_listener { + .locked = locker_pointer_locker_handler, + .unlocked = locker_pointer_unlocker_handler, + }; } // namespace void init() { @@ -955,7 +966,7 @@ namespace stormkit::wsi::linux::wayland { xdg_toplevel_set_title(m_xdg_toplevel.get(), m_title.c_str()); xdg_toplevel_set_app_id(m_xdg_toplevel.get(), m_title.c_str()); - if (!checkFlag(m_style, WindowStyle::RESIZEABLE)) { + if (!check_flag_bit(m_style, WindowStyle::RESIZEABLE)) { xdg_toplevel_set_min_size(m_xdg_toplevel.get(), m_extent.width, m_extent.height); xdg_toplevel_set_max_size(m_xdg_toplevel.get(), m_extent.width, m_extent.height); } else { @@ -1048,34 +1059,42 @@ namespace stormkit::wsi::linux::wayland { } namespace { - constinit const auto stormkit_output_listener - = wl_output_listener { .geometry = output_geometry_handler, - .mode = output_mode_handler, - .done = output_done_handler, - .scale = output_scale_handler }; - - constinit const auto stormkit_seat_listener - = wl_seat_listener { .capabilities = seat_capabilities_handler, - .name = seat_name_handler }; - - constinit const auto stormkit_pointer_listener - = wl_pointer_listener { .enter = pointer_enter_handler, - .leave = pointer_leave_handler, - .motion = pointer_motion_handler, - .button = pointer_button_handler, - .axis = pointer_axis_handler, - .frame = pointer_frame_handler, - .axis_source = pointer_axis_source_handler, - .axis_stop = pointer_axis_stop_handler, - .axis_discrete = pointer_axis_discrete_handler }; - - constinit const auto stormkit_keyboard_listener - = wl_keyboard_listener { .keymap = keyboard_keymap_handler, - .enter = keyboard_enter_handler, - .leave = keyboard_leave_handler, - .key = keyboard_key_handler, - .modifiers = keyboard_modifiers_handler, - .repeat_info = keyboard_repeat_info_handler }; + constinit const auto stormkit_output_listener = wl_output_listener { + .geometry = output_geometry_handler, + .mode = output_mode_handler, + .done = output_done_handler, + .scale = output_scale_handler, + .name = nullptr, + .description = nullptr, + }; + + constinit const auto stormkit_seat_listener = wl_seat_listener { + .capabilities = seat_capabilities_handler, + .name = seat_name_handler, + }; + + constinit const auto stormkit_pointer_listener = wl_pointer_listener { + .enter = pointer_enter_handler, + .leave = pointer_leave_handler, + .motion = pointer_motion_handler, + .button = pointer_button_handler, + .axis = pointer_axis_handler, + .frame = pointer_frame_handler, + .axis_source = pointer_axis_source_handler, + .axis_stop = pointer_axis_stop_handler, + .axis_discrete = pointer_axis_discrete_handler, + .axis_value120 = nullptr, + .axis_relative_direction = nullptr, + }; + + constinit const auto stormkit_keyboard_listener = wl_keyboard_listener { + .keymap = keyboard_keymap_handler, + .enter = keyboard_enter_handler, + .leave = keyboard_leave_handler, + .key = keyboard_key_handler, + .modifiers = keyboard_modifiers_handler, + .repeat_info = keyboard_repeat_info_handler, + }; // TODO support touchscreens [[maybe_unused]] diff --git a/src/wsi/linux/x11/window_impl.mpp b/src/wsi/linux/x11/window_impl.mpp index e39f3e2f5..5e2ecfe43 100644 --- a/src/wsi/linux/x11/window_impl.mpp +++ b/src/wsi/linux/x11/window_impl.mpp @@ -456,22 +456,22 @@ namespace stormkit::wsi::linux::x11 { m_window_hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; - if (checkFlag(style, WindowStyle::TITLE_BAR)) { + if (check_flag_bit(style, WindowStyle::TITLE_BAR)) { m_window_hints.decorations |= MWM_DECOR_BORDER | MWM_DECOR_TITLE | MWM_DECOR_MENU; m_window_hints.functions |= MWM_FUNC_MOVE; } - if (checkFlag(style, WindowStyle::CLOSE)) { + if (check_flag_bit(style, WindowStyle::CLOSE)) { m_window_hints.decorations |= 0; m_window_hints.functions |= MWM_FUNC_CLOSE; } - if (checkFlag(style, WindowStyle::MINIMIZABLE)) { + if (check_flag_bit(style, WindowStyle::MINIMIZABLE)) { m_window_hints.decorations |= MWM_DECOR_MINIMIZE; m_window_hints.functions |= MWM_FUNC_MINIMIZE; } - if (checkFlag(style, WindowStyle::RESIZEABLE)) { + if (check_flag_bit(style, WindowStyle::RESIZEABLE)) { m_window_hints.decorations |= MWM_DECOR_RESIZE | MWM_DECOR_MAXIMIZE; m_window_hints.functions |= MWM_FUNC_RESIZE | MWM_FUNC_MAXIMIZE; } else { diff --git a/src/wsi/window.cpp b/src/wsi/window.cpp index db2201f1b..5a92f1ec0 100644 --- a/src/wsi/window.cpp +++ b/src/wsi/window.cpp @@ -267,7 +267,7 @@ namespace stormkit::wsi { const auto settings = get_monitor_settings(); const auto it = std::ranges::find_if(settings, [](const auto& monitor) { - return checkFlag(monitor.flags, Monitor::Flags::PRIMARY); + return check_flag_bit(monitor.flags, Monitor::Flags::PRIMARY); }); ensures(it != std::ranges::cend(settings)); diff --git a/tests/src/core/TypeSafe/Boolean.cpp b/tests/src/core/TypeSafe/Boolean.cpp index 2ec854152..90d0d55f0 100644 --- a/tests/src/core/TypeSafe/Boolean.cpp +++ b/tests/src/core/TypeSafe/Boolean.cpp @@ -26,7 +26,7 @@ namespace { auto bool_1 = Boolean { true }; expects(static_cast(bool_1)); - bindBack([](auto) {}, 1)(); + bind_back([](auto) {}, 1)(); auto bool_2 = Boolean { false }; expects(!static_cast(bool_2)); diff --git a/tests/src/core/TypeSafe/Flags.cpp b/tests/src/core/TypeSafe/Flags.cpp index 78bb54491..e0d684f0a 100644 --- a/tests/src/core/TypeSafe/Flags.cpp +++ b/tests/src/core/TypeSafe/Flags.cpp @@ -70,10 +70,10 @@ namespace { } }, }, { - "Flags.enum_class.checkFlag", + "Flags.enum_class.check_flag_bit", [] static noexcept { auto foo = Flag::A | Flag::B; - expects(checkFlag(foo, Flag::A)); + expects(check_flag_bit(foo, Flag::A)); }, }, { "Flags.enum_class.next_value", @@ -118,10 +118,10 @@ namespace { } }, }, { - "Flags.enum.checkFlag", + "Flags.enum.check_flag_bit", [] static noexcept { auto foo = Flag2::A | Flag2::B; - expects(checkFlag(foo, Flag2::A)); + expects(check_flag_bit(foo, Flag2::A)); }, }, { "Flags.enum.next_value", diff --git a/tests/src/core/Utils/Allocation.cpp b/tests/src/core/Utils/Allocation.cpp index d049d4177..2b4f19a14 100644 --- a/tests/src/core/Utils/Allocation.cpp +++ b/tests/src/core/Utils/Allocation.cpp @@ -23,7 +23,7 @@ namespace { } }, { "Allocation.unsafe", [] static noexcept { - auto allocation = allocateUnsafe(5); + auto allocation = allocate_unsafe(5); expects(*allocation == 5); } } } }; diff --git a/tests/xmake.lua b/tests/xmake.lua index 4dad103a8..0094d82f7 100644 --- a/tests/xmake.lua +++ b/tests/xmake.lua @@ -3,7 +3,7 @@ target("test-base", function() set_kind("object") set_languages("cxxlatest", "clatest") add_rules("stormkit.flags") - add_rules("windows.subsystem.console") + add_rules("platform.windows.subsystem.console") add_files("src/main.cpp") add_files("src/Test.mpp", { public = true }) add_options("sanitizers") @@ -49,7 +49,7 @@ for name, _ in pairs(modules) do end) add_rules("stormkit.flags") - add_rules("windows.subsystem.console") + add_rules("platform.windows.subsystem.console") add_files(file) diff --git a/xmake.lua b/xmake.lua index 16979bb08..b75fbbcd2 100644 --- a/xmake.lua +++ b/xmake.lua @@ -58,7 +58,7 @@ modules = { public_deps = { "stormkit-core" }, }, image = { - packages = { "libktx", "libpng", "libjpeg-turbo 3.1.0" }, + packages = { "libktx", "libpng", "libjpeg-turbo" }, modulename = "image", public_deps = { "stormkit-core" }, }, @@ -134,12 +134,13 @@ modules = { end, }, gpu = { - modulename = "Gpu", + modulename = "gpu", has_headers = true, public_packages = { + "frozen", + "volk", "vulkan-headers v1.4.309", - "vulkan-memory-allocator 3.2.0", - "vulkan-memory-allocator-hpp 3.2.1", + "vulkan-memory-allocator v3.2.1", }, public_deps = { "stormkit-core", "stormkit-log", "stormkit-wsi", "stormkit-image" }, packages = is_plat("linux") and { @@ -147,28 +148,11 @@ modules = { "wayland", } or nil, public_defines = { - "VK_NO_PROTOTYPES", - "VMA_DYNAMIC_VULKAN_FUNCTIONS=1", + "VMA_DYNAMIC_VULKAN_FUNCTIONS=0", "VMA_STATIC_VULKAN_FUNCTIONS=0", - "VULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1", - "VULKAN_HPP_NO_STRUCT_CONSTRUCTORS", - "VULKAN_HPP_NO_UNION_CONSTRUCTORS", - "VULKAN_HPP_NO_EXCEPTIONS", - "VULKAN_HPP_NO_CONSTRUCTORS", - -- "VULKAN_HPP_NO_SMART_HANDLE", - "VULKAN_HPP_STD_MODULE=std.compat", - "VULKAN_HPP_ENABLE_STD_MODULE", - "VMA_HPP_ENABLE_VULKAN_HPP_MODULE", - "VMA_HPP_ENABLE_STD_MODULE", + "STORMKIT_GPU_VULKAN" }, custom = function() - on_load(function(target) - if target:kind() == "shared" then - target:add("defines", "VK_HPP_STORAGE_SHARED", { public = true }) - else - target:add("defines", "VK_HPP_STORAGE_API", { public = true }) - end - end) if is_plat("linux") then add_defines("VK_USE_PLATFORM_XCB_KHR", { public = true }) add_defines("VK_USE_PLATFORM_WAYLAND_KHR", { public = true }) @@ -177,6 +161,7 @@ modules = { elseif is_plat("windows") then add_defines("VK_USE_PLATFORM_WIN32_KHR", { public = true }) end + add_cxflags("clang::-Wno-missing-declarations") end, }, } @@ -238,6 +223,14 @@ option("examples_engine", { if option:dep("examples"):enabled() then option:enable(true) end end, }) +option("examples_gpu", { + default = false, + category = "root menu/others", + deps = { "examples" }, + after_check = function(option) + if option:dep("examples"):enabled() then option:enable(true) end + end, +}) option("examples_wsi", { default = false, category = "root menu/others", @@ -278,6 +271,7 @@ option("tests_core", { option("sanitizers", { default = false, category = "root menu/build" }) option("mold", { default = false, category = "root menu/build" }) option("lto", { default = false, category = "root menu/build" }) +option("shared_deps", { default = false, category = "root menu/build" }) option("on_ci", { default = false, category = "root menu/build" }) ---------------------------- module options ---------------------------- @@ -304,11 +298,9 @@ add_defines("MAGIC_ENUM_USE_STD_MODULE") add_defines("MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT=0") add_defines("FROZEN_USE_STD_MODULE") -set_policy("build.c++.modules.gcc.cxx11abi", true) - if not is_plat("wasm") then add_requireconfs("vulkan-headers", { system = false }) - -- add_requireconfs("vulkan-memory-allocator") + add_requireconfs("vulkan-memory-allocator", { system = false }) add_requireconfs("vulkan-memory-allocator-hpp", { system = false, configs = { use_vulkanheaders = true } }) end @@ -316,23 +308,27 @@ if get_config("toolchain") == "llvm" then add_requireconfs("libktx", { configs = { cxflags = "-Wno-overriding-option" } }) end -add_requireconfs("*", { configs = { modules = true, std_import = true, cpp = "latest" } }) - -add_requireconfs("libxkbcommon", { configs = { ["x11"] = true, wayland = true } }) add_requireconfs("frozen", { system = false }) -if get_config("on_ci") then add_requireconfs("*", { system = false }) end - add_requires("cpptrace") if not is_plat("windows") then add_requires("libdwarf") end +local package_configs = {configs = {shared = get_config("shared_deps"), ["x11"] = true, wayland = true, modules = true, std_import = true, cpp = "latest"}} +if get_config("on_ci") then + package_configs.system = false +end + ---------------------------- targets ---------------------------- for name, module in pairs(modules) do local modulename = module.modulename if name == "core" or name == "main" or get_config(name) then local packages = table.join(module.packages or {}, module.public_packages or {}) - add_requires(packages) + for _, package in ipairs(packages) do + add_requires(package, package_configs) + add_requireconfs(package .. ".**", package_configs) + end + local _packages = {} for _, package in ipairs(_packages) do table.insert(packages, package:split(" ")[1]) @@ -444,7 +440,7 @@ for name, module in pairs(modules) do table.insert(packages, package:split(" ")[1]) end - add_packages(packages) + add_packages(packages, {public = is_kind("static")}) end if module.public_packages then @@ -452,7 +448,6 @@ for name, module in pairs(modules) do for _, package in ipairs(module.public_packages) do table.insert(packages, package:split(" ")[1]) end - add_packages(packages, { public = true }) end @@ -474,7 +469,7 @@ for name, module in pairs(modules) do elseif is_mode("releasedbg") then set_optimize("fast") set_symbols("debug", "hidden") - add_cxflags("-fno-omit-frame-pointer", { tools = { "clang", "gcc" } }) + add_cxflags("-ggdb3", "-fno-omit-frame-pointer", { tools = { "clang", "gcc" } }) add_mxflags("-ggdb3", { tools = { "clang", "gcc" } }) end @@ -483,6 +478,17 @@ for name, module in pairs(modules) do end end +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) diff --git a/xmake/ktx.lua b/xmake/ktx.lua index 8f3cef3d8..a39662cb4 100644 --- a/xmake/ktx.lua +++ b/xmake/ktx.lua @@ -18,7 +18,8 @@ package("libktx", function() on_install("macosx", "android", "linux", "windows", "mingw", "cross", function(package) local configs = {} - table.insert(configs, "-DCMAKE_BUILD_TYPE=" .. (package:debug() and "Debug" or "Release")) + table.insert(configs, "-DCMAKE_BUILD_TYPE=" .. (package:is_debug() and "Debug" or "Release")) + table.insert(configs, "-DBUILD_SHARED_LIBS=".. (package:config("shared") and "ON" or "OFF")) table.insert(configs, "-DKTX_FEATURE_STATIC_LIBRARY=" .. (package:config("shared") and "OFF" or "ON")) table.insert(configs, "-DKTX_FEATURE_VK_UPLOAD=" .. (package:config("vulkan") and "ON" or "OFF")) table.insert(configs, "-DKTX_FEATURE_GL_UPLOAD=" .. (package:config("opengl") and "ON" or "OFF")) diff --git a/xmake/rules/stormkit_flags.lua b/xmake/rules/stormkit_flags.lua index c9d18c167..787be2678 100644 --- a/xmake/rules/stormkit_flags.lua +++ b/xmake/rules/stormkit_flags.lua @@ -1,43 +1,59 @@ rule("stormkit.flags", function() on_load("linux", "mingw", "macos", "ios", "android", function(target) + local target_add = target.add + local target_set = target.set if get_config("sanitizers") then - target:set("policy", "build.sanitizer.address", true) - target:set("policy", "build.sanitizer.undefined", true) + target_set(target, "policy", "build.sanitizer.address", true) + target_set(target, "policy", "build.sanitizer.undefined", true) end - if get_config("lto") then - target:set("policy", "build.optimization.lto", true) + if get_config("lto") then target_set(target, "policy", "build.optimization.lto", true) end + if get_config("mold") then + target_add(target, "ldflags", "-fuse-ld=mold") + target_add(target, "shflags", "-fuse-ld=mold") end end) on_load("windows", function(target) + import("core.tool.compiler") + local compinst = compiler.load("cxx") + local cxx = path.filename(compinst:program()) + local target_add = target.add + local target_set = target.set + local startswith = string.startswith if get_config("sanitizers") then - import("core.tool.compiler") - local compinst = compiler.load("cxx") - local cxx = path.filename(compinst:program()) if - not cxx:startswith("clang") - or cxx:startswith("clang") and target:has_runtime("c++_shared", "c++_static") + not startswith(cxx, "clang") + or startswith(cxx, "clang") and target:has_runtime("c++_shared", "c++_static") then - target:set("policy", "build.sanitizer.address", true) - target:set("policy", "build.sanitizer.undefined", true) + target_set(target, "policy", "build.sanitizer.address", true) + target_set(target, "policy", "build.sanitizer.undefined", true) end end + if startswith(cxx, "clang") or startswith(cxx, "g++") or startswith(cxx, "gcc") or get_config("mold") then + target_add(target, "ldflags", "-fuse-ld=mold") + target_add(target, "shflags", "-fuse-ld=mold") + end end) on_config(function(target) - target:set("warnings", "all", "pedantic", "extra", "error") + local target_add = target.add + local target_set = target.set + target_set(target, "warnings", "allextra", "pedantic", "error") local flags = { cl = { - cxx = { "/Zc:__cplusplus" }, + cxx = { + "/Zc:__cplusplus", + "/Zc:lambda", + "/Zc:referenceBinding", + }, cx = { "/utf-8", "/bigobj", "/permissive-", "/Zc:wchar_t", "/Zc:inline", - "/Zc:lambda", "/Zc:preprocessor", - "/Zc:referenceBinding", "/Zc:strictStrings", + "/analyze", "/wd4251", -- Disable warning: class needs to have dll-interface to be used by clients of class blah blah blah "/wd4297", "/wd5063", @@ -51,6 +67,9 @@ rule("stormkit.flags", function() cx = { "-fstrict-aliasing", "-Wstrict-aliasing", + "-fanalyzer", + "-Wconversion", + "-Wshadow" }, }, clang = { @@ -61,13 +80,10 @@ rule("stormkit.flags", function() "-fstrict-aliasing", "-fexperimental-library", "-Wstrict-aliasing", - -- "-Wno-missing-field-initializers", - "-Wno-unknown-attributes", - "-Wno-deprecated-declarations", - "-Wno-ignored-attributes", + "-Wconversion", + "-Wshadow", }, mx = { - -- "-Wno-missing-field-initializers", }, ld = { "-fexperimental-library", @@ -80,57 +96,57 @@ rule("stormkit.flags", function() }, }, } - target:add("cxxflags", flags.clang.cxx or {}, { tools = { "clang" } }) - target:add("cxxflags", flags.gcc.cxx or {}, { tools = { "gcc" } }) - target:add("cxxflags", flags.cl.cxx or {}, { tools = { "cl", "clang_cl" } }) + target_add(target, "cxxflags", flags.clang.cxx or {}, { tools = { "clang" } }) + target_add(target, "cxxflags", flags.gcc.cxx or {}, { tools = { "gcc" } }) + target_add(target, "cxxflags", flags.cl.cxx or {}, { tools = { "cl", "clang_cl" } }) - target:add("cxflags", flags.clang.cx or {}, { tools = { "clang" } }) - target:add("cxflags", flags.gcc.cx or {}, { tools = { "gcc" } }) - target:add("cxflags", flags.cl.cx or {}, { tools = { "cl", "clang_cl" } }) + target_add(target, "cxflags", flags.clang.cx or {}, { tools = { "clang" } }) + target_add(target, "cxflags", flags.gcc.cx or {}, { tools = { "gcc" } }) + target_add(target, "cxflags", flags.cl.cx or {}, { tools = { "cl", "clang_cl" } }) - target:add("mxflags", flags.clang.mx or {}, { tools = { "clang" } }) + target_add(target, "mxflags", flags.clang.mx or {}, { tools = { "clang" } }) - target:add("mxxflags", flags.clang.mxx or {}, { tools = { "clang" } }) + target_add(target, "mxxflags", flags.clang.mxx or {}, { tools = { "clang" } }) - target:add("ldflags", flags.clang.ld or {}, { tools = { "clang", "clangxx", "lld" } }) - target:add("ldflags", flags.gcc.ld or {}, { tools = { "gcc", "g++", "ld" } }) - target:add("ldflags", flags.cl.ld or {}, { tools = { "cl", "link" } }) + target_add(target, "ldflags", flags.clang.ld or {}, { tools = { "clang", "clangxx", "lld" } }) + target_add(target, "ldflags", flags.gcc.ld or {}, { tools = { "gcc", "g++", "ld" } }) + target_add(target, "ldflags", flags.cl.ld or {}, { tools = { "cl", "link" } }) - target:add("shflags", flags.clang.sh or {}, { tools = { "clang", "clangxx", "lld" } }) - target:add("shflags", flags.gcc.sh or {}, { tools = { "gcc", "g++", "ld" } }) - target:add("shflags", flags.cl.sh or {}, { tools = { "cl", "link" } }) + target_add(target, "shflags", flags.clang.sh or {}, { tools = { "clang", "clangxx", "lld" } }) + target_add(target, "shflags", flags.gcc.sh or {}, { tools = { "gcc", "g++", "ld" } }) + target_add(target, "shflags", flags.cl.sh or {}, { tools = { "cl", "link" } }) - target:add("arflags", flags.clang.ar or {}, { tools = { "clang", "clangxx", "llvm-ar" } }) - target:add("arflags", flags.gcc.ar or {}, { tools = { "gcc", "g++", "ar" } }) - target:add("arflags", flags.cl.ar or {}, { tools = { "cl", "clang_cl" } }) + target_add(target, "arflags", flags.clang.ar or {}, { tools = { "clang", "clangxx", "llvm-ar" } }) + target_add(target, "arflags", flags.gcc.ar or {}, { tools = { "gcc", "g++", "ar" } }) + target_add(target, "arflags", flags.cl.ar or {}, { tools = { "cl", "clang_cl" } }) if is_plat("windows") then - target:add("defines", { + target_add(target, "defines", { "_CRT_SECURE_NO_WARNINGS", "WIN32_LEAN_AND_MEAN", "NOMINMAX", }) if not target:has_runtime("c++_shared") then - target:add("defines", "_MSVC_STL_HARDENING") + target_add(target, "defines", "_MSVC_STL_HARDENING") if is_mode("debug") then - target:set("runtimes", "MDd") + target_set(target, "runtimes", "MDd") else - target:set("runtimes", "MD") + target_set(target, "runtimes", "MD") end end end - target:set("symbols", "hidden") + target_set(target, "symbols", "hidden") if is_mode("release") then - target:set("optimize", "fastest") + target_set(target, "optimize", "fastest") elseif is_mode("debug") then - target:set("symbols", "debug", "hidden") - target:add("cxflags", "-ggdb3", { tools = { "clang", "gcc" } }) - target:add("mxflags", "-ggdb3", { tools = { "clang", "gcc" } }) + target_set(target, "symbols", "debug", "hidden") + target_add(target, "cxflags", "-ggdb3", { tools = { "clang", "gcc" } }) + target_add(target, "mxflags", "-ggdb3", { tools = { "clang", "gcc" } }) elseif is_mode("releasedbg") then - target:set("optimize", "fast") - target:set("symbols", "debug", "hidden") - target:add("cxflags", "-fno-omit-frame-pointer", { tools = { "clang", "gcc" } }) - target:add("mxflags", "-ggdb3", { tools = { "clang", "gcc" } }) + target_set(target, "optimize", "fast") + target_set(target, "symbols", "debug", "hidden") + target_add(target, "cxflags", "-fno-omit-frame-pointer", { tools = { "clang", "gcc" } }) + target_add(target, "mxflags", "-ggdb3", { tools = { "clang", "gcc" } }) end end) end) diff --git a/xmake/rules/subsystem.lua b/xmake/rules/subsystem.lua deleted file mode 100644 index 1be9c83b4..000000000 --- a/xmake/rules/subsystem.lua +++ /dev/null @@ -1,28 +0,0 @@ -rule("windows.subsystem.console", function() - add_deps("windows.subsystem") - add_orders("windows.subsystem.console", "windows.subsystem") - on_load(function(target) target:data_set("windows.subsystem", "console") end) -end) - -rule("windows.subsystem.windows", function() - add_deps("windows.subsystem") - add_orders("windows.subsystem.windows", "windows.subsystem") - on_load(function(target) target:data_set("windows.subsystem", "windows") end) -end) - -rule("windows.subsystem", function() - on_config("mingw", "windows", function(target) - local subsystem = target:data("windows.subsystem") - local linker = target:tool("ld") - linker = path.filename(linker) - if linker:startswith("clang") then - target:add("ldflags", "-Wl,-subsystem:" .. subsystem, { force = true }) - elseif linker:startswith("link") or linker:startswith("lld") then - target:add("ldflags", "/SUBSYSTEM:" .. string.upper(subsystem), { force = true }) - elseif linker:startswith("gcc") or linker:startswith("g++") then - target:add("ldflags", "-Wl,-m" .. subsystem) - elseif linker:startswith("ld") then - target:add("ldflags", "-m" .. subsystem) - end - end) -end) diff --git a/xmake/rules/windows.lua b/xmake/rules/windows.lua new file mode 100644 index 000000000..41ab5550f --- /dev/null +++ b/xmake/rules/windows.lua @@ -0,0 +1,11 @@ +rule("platform.windows.subsystem.windows") + add_deps("platform.windows.subsystem") + on_load(function(target) + target:values_set("windows.subsystem", "windows") + end) + +rule("platform.windows.subsystem.console") + add_deps("platform.windows.subsystem") + on_load(function(target) + target:values_set("windows.subsystem", "console") + end)