From 2e11ac64842fea56a3787010430aa0a3a41b7982 Mon Sep 17 00:00:00 2001 From: Jorijn van der Graaf Date: Wed, 28 Jan 2026 18:51:11 +0100 Subject: [PATCH] improved vulkanbuffer --- examples/HelloRotation/project.json | 3 +- examples/VulkanTriangle/main.cpp | 6 +- .../Crafter.Graphics-Mesh_vulkan.cpp | 92 +-- ...fter.Graphics-RenderingElement3DVulkan.cpp | 130 ++++ .../Crafter.Graphics-VulkanDevice.cpp | 1 + interfaces/Crafter.Graphics-Mesh.cppm | 11 +- ...ter.Graphics-RenderingElement3DVulkan.cppm | 648 +----------------- interfaces/Crafter.Graphics-VulkanBuffer.cppm | 261 +++++-- interfaces/Crafter.Graphics-VulkanDevice.cppm | 1 + interfaces/Crafter.Graphics.cppm | 1 + project.json | 4 +- 11 files changed, 396 insertions(+), 762 deletions(-) create mode 100644 implementations/Crafter.Graphics-RenderingElement3DVulkan.cpp diff --git a/examples/HelloRotation/project.json b/examples/HelloRotation/project.json index 3762cb1..755d2b9 100644 --- a/examples/HelloRotation/project.json +++ b/examples/HelloRotation/project.json @@ -9,7 +9,8 @@ "path":"../../project.json", "configuration":"lib-wayland-timing" } - ] + ], + "debug": true } ] } diff --git a/examples/VulkanTriangle/main.cpp b/examples/VulkanTriangle/main.cpp index c57d968..b50bf58 100644 --- a/examples/VulkanTriangle/main.cpp +++ b/examples/VulkanTriangle/main.cpp @@ -19,10 +19,12 @@ int main() { */ VkCommandBuffer cmd = window.StartInit(); - Mesh triangle; + Mesh triangleMesh; std::array verts {{{-0.1, 0, 0}, {0, 0.1, 0}, {0.1, 0, 0}}}; std::array index {{0,1,2}}; - triangle.Build(verts, index, cmd); + triangleMesh.Build(verts, index, cmd); + // RenderingElement3DVulkan::elements.emplace_back(triangleMesh); + // RenderingElement3DVulkan::BuildTLAS(cmd); /* FinishInit executes all commands recorded to StartInit. diff --git a/implementations/Crafter.Graphics-Mesh_vulkan.cpp b/implementations/Crafter.Graphics-Mesh_vulkan.cpp index d8d0d3a..0da143e 100644 --- a/implementations/Crafter.Graphics-Mesh_vulkan.cpp +++ b/implementations/Crafter.Graphics-Mesh_vulkan.cpp @@ -33,85 +33,14 @@ constexpr std::size_t alignUp(std::size_t value, std::size_t alignment) { } void Mesh::Build(std::span verticies, std::span indicies, VkCommandBuffer cmd) { - new (&vertexStaging) VulkanBuffer(VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, verticies.size()); - new (&indexStaging) VulkanBuffer(VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, indicies.size()); + vertexBuffer.Resize(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_2_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, verticies.size()); + indexBuffer.Resize(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_2_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, indicies.size()); - std::memcpy(vertexStaging.value, verticies.data(), verticies.size() * sizeof(Vertex)); - std::memcpy(indexStaging.value, indicies.data(), indicies.size() * sizeof(std::uint32_t)); - - new (&vertexBuffer) VulkanBuffer(VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_2_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, verticies.size()); - new (&indexBuffer) VulkanBuffer(VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_2_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indicies.size()); - - VkBufferCopy copyRegion = { - .srcOffset = 0, - .dstOffset = 0, - .size = verticies.size() * sizeof(Vertex) - }; - - vkCmdCopyBuffer( - cmd, - vertexStaging.buffer, - vertexBuffer.buffer, - 1, - ©Region - ); - - VkBufferCopy copyRegion2 = { - .srcOffset = 0, - .dstOffset = 0, - .size = indicies.size() * sizeof(std::uint32_t) - }; - - vkCmdCopyBuffer( - cmd, - indexStaging.buffer, - indexBuffer.buffer, - 1, - ©Region2 - ); - - VkBufferMemoryBarrier barrier = { - .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, - .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, - .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .buffer = vertexBuffer.buffer, - .offset = 0, - .size = VK_WHOLE_SIZE - }; - - vkCmdPipelineBarrier( - cmd, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, - 0, - 0, NULL, - 1, &barrier, - 0, NULL - ); - - VkBufferMemoryBarrier barrier2 = { - .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, - .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, - .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .buffer = indexStaging.buffer, - .offset = 0, - .size = VK_WHOLE_SIZE - }; - - vkCmdPipelineBarrier( - cmd, - VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, - 0, - 0, NULL, - 1, &barrier2, - 0, NULL - ); + std::memcpy(vertexBuffer.value, verticies.data(), verticies.size() * sizeof(Vertex)); + std::memcpy(indexBuffer.value, indicies.data(), indicies.size() * sizeof(std::uint32_t)); + vertexBuffer.FlushDevice(cmd, VK_ACCESS_MEMORY_READ_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR); + vertexBuffer.FlushDevice(cmd, VK_ACCESS_MEMORY_READ_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR); VkDeviceOrHostAddressConstKHR vertexAddr; vertexAddr.deviceAddress = vertexBuffer.address; @@ -160,7 +89,7 @@ void Mesh::Build(std::span verticies, std::span indicies, &blasBuildSizes ); - new (&scratchBuffer) VulkanBuffer(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, blasBuildSizes.buildScratchSize); + scratchBuffer.Resize(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, blasBuildSizes.buildScratchSize); VkPhysicalDeviceAccelerationStructurePropertiesKHR asProps{ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR @@ -169,7 +98,7 @@ void Mesh::Build(std::span verticies, std::span indicies, VkDeviceAddress scratchAddr = scratchBuffer.address; blasBuildGeometryInfo.scratchData.deviceAddress = scratchAddr; - new (&blasBuffer) VulkanBuffer(VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, blasBuildSizes.accelerationStructureSize); + blasBuffer.Resize(VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, blasBuildSizes.accelerationStructureSize); // Create and store the BLAS handle VkAccelerationStructureCreateInfoKHR blasCreateInfo{ @@ -180,10 +109,9 @@ void Mesh::Build(std::span verticies, std::span indicies, .type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR, }; - VkAccelerationStructureKHR aclereationStructure {}; - VulkanDevice::vkCreateAccelerationStructureKHR(VulkanDevice::device, &blasCreateInfo, nullptr, &aclereationStructure); - blasBuildGeometryInfo.dstAccelerationStructure = aclereationStructure; + VulkanDevice::CheckVkResult(VulkanDevice::vkCreateAccelerationStructureKHR(VulkanDevice::device, &blasCreateInfo, nullptr, &accelerationStructure)); + blasBuildGeometryInfo.dstAccelerationStructure = accelerationStructure; // Prepare the build range for the BLAS VkAccelerationStructureBuildRangeInfoKHR blasRangeInfo { diff --git a/implementations/Crafter.Graphics-RenderingElement3DVulkan.cpp b/implementations/Crafter.Graphics-RenderingElement3DVulkan.cpp new file mode 100644 index 0000000..1066139 --- /dev/null +++ b/implementations/Crafter.Graphics-RenderingElement3DVulkan.cpp @@ -0,0 +1,130 @@ +/* +Crafter®.Graphics +Copyright (C) 2026 Catcrafts® +Catcrafts.net + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 3.0 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ +module; +#include +module Crafter.Graphics:RenderingElement3DVulkan_impl; +import :RenderingElement3DVulkan; +import std; + +using namespace Crafter; + +//std::vector RenderingElement3DVulkan::elements; + +//RenderingElement3DVulkan::RenderingElement3DVulkan(Mesh& mesh) { +// VkTransformMatrixKHR identity{}; +// float tmp[3][4] = { +// {1.f, 0.f, 0.f, 0.f}, +// {0.f, 1.f, 0.f, 0.f}, +// {0.f, 0.f, 1.f, 0.f} +// }; +// std::memcpy(identity.matrix, tmp, sizeof(tmp)); + +// VkAccelerationStructureDeviceAddressInfoKHR addrInfo { +// .sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR, +// .accelerationStructure = mesh.accelerationStructure +// }; +// VkDeviceAddress blasDeviceAddr = VulkanDevice::vkGetAccelerationStructureDeviceAddressKHR(VulkanDevice::device, &addrInfo); + +// instance = { +// .transform = identity, +// .mask = 0xFF, +// .accelerationStructureReference = blasDeviceAddr +// }; +// } + +// void RenderingElement3DVulkan::BuildTLAS(VkCommandBuffer cmd) { +// VulkanBuffer newBuffer(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_2_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, elements.size()); + +// for(std::uint32_t i = 0; i < elements.size(); i++) { +// newBuffer.value[i] = elements[i].instance; +// } + +// VkAccelerationStructureGeometryInstancesDataKHR instancesData = VkAccelerationStructureGeometryInstancesDataKHR { +// .arrayOfPointers = VK_FALSE, +// .data = {newBuffer.address} +// }; + + // vk::AccelerationStructureGeometryDataKHR geometryData(instancesData); + + // vk::AccelerationStructureGeometryKHR tlasGeometry{ + // .geometryType = vk::GeometryTypeKHR::eInstances, + // .geometry = geometryData}; + + // vk::AccelerationStructureBuildGeometryInfoKHR tlasBuildGeometryInfo{ + // .type = vk::AccelerationStructureTypeKHR::eTopLevel, + // .mode = vk::BuildAccelerationStructureModeKHR::eBuild, + // .geometryCount = 1, + // .pGeometries = &tlasGeometry}; + + // // Query the memory sizes that will be needed for this TLAS + // auto primitiveCount = static_cast(instances.size()); + + // vk::AccelerationStructureBuildSizesInfoKHR tlasBuildSizes = + // device.getAccelerationStructureBuildSizesKHR( + // vk::AccelerationStructureBuildTypeKHR::eDevice, + // tlasBuildGeometryInfo, + // {primitiveCount}); + + // // Create a scratch buffer for the TLAS, this will hold temporary data + // // during the build process + // createBuffer( + // tlasBuildSizes.buildScratchSize, + // vk::BufferUsageFlagBits::eStorageBuffer | + // vk::BufferUsageFlagBits::eShaderDeviceAddress, + // vk::MemoryPropertyFlagBits::eDeviceLocal, + // tlasScratchBuffer, tlasScratchMemory); + + // // Save the scratch buffer address in the build info structure + // vk::BufferDeviceAddressInfo scratchAddressInfo{.buffer = *tlasScratchBuffer}; + // vk::DeviceAddress scratchAddr = device.getBufferAddressKHR(scratchAddressInfo); + // tlasBuildGeometryInfo.scratchData.deviceAddress = scratchAddr; + + // // Create a buffer for the TLAS itself now that we now the required size + // createBuffer( + // tlasBuildSizes.accelerationStructureSize, + // vk::BufferUsageFlagBits::eAccelerationStructureStorageKHR | + // vk::BufferUsageFlagBits::eShaderDeviceAddress | + // vk::BufferUsageFlagBits::eAccelerationStructureBuildInputReadOnlyKHR, + // vk::MemoryPropertyFlagBits::eDeviceLocal, + // tlasBuffer, tlasMemory); + + // // Create and store the TLAS handle + // vk::AccelerationStructureCreateInfoKHR tlasCreateInfo{ + // .buffer = tlasBuffer, + // .offset = 0, + // .size = tlasBuildSizes.accelerationStructureSize, + // .type = vk::AccelerationStructureTypeKHR::eTopLevel, + // }; + + // tlas = device.createAccelerationStructureKHR(tlasCreateInfo); + + // // Save the TLAS handle in the build info structure + // tlasBuildGeometryInfo.dstAccelerationStructure = tlas; + + // // Prepare the build range for the TLAS + // vk::AccelerationStructureBuildRangeInfoKHR tlasRangeInfo{ + // .primitiveCount = primitiveCount, + // .primitiveOffset = 0, + // .firstVertex = 0, + // .transformOffset = 0}; + + + // cmd->buildAccelerationStructuresKHR({tlasBuildGeometryInfo}, {&tlasRangeInfo}); +//} \ No newline at end of file diff --git a/implementations/Crafter.Graphics-VulkanDevice.cpp b/implementations/Crafter.Graphics-VulkanDevice.cpp index ca7d323..955a2ff 100644 --- a/implementations/Crafter.Graphics-VulkanDevice.cpp +++ b/implementations/Crafter.Graphics-VulkanDevice.cpp @@ -299,6 +299,7 @@ void VulkanDevice::CreateDevice() { vkGetAccelerationStructureBuildSizesKHR = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkGetAccelerationStructureBuildSizesKHR")); vkCreateAccelerationStructureKHR = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkCreateAccelerationStructureKHR")); vkCmdBuildAccelerationStructuresKHR = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkCmdBuildAccelerationStructuresKHR")); + vkGetAccelerationStructureDeviceAddressKHR = reinterpret_cast(vkGetInstanceProcAddr(instance, "vkGetAccelerationStructureDeviceAddressKHR")); } std::uint32_t VulkanDevice::GetMemoryType(uint32_t typeBits, VkMemoryPropertyFlags properties) { diff --git a/interfaces/Crafter.Graphics-Mesh.cppm b/interfaces/Crafter.Graphics-Mesh.cppm index 5a8dce4..542ef29 100644 --- a/interfaces/Crafter.Graphics-Mesh.cppm +++ b/interfaces/Crafter.Graphics-Mesh.cppm @@ -37,14 +37,13 @@ export namespace Crafter { #ifdef CRAFTER_GRAPHICS_VULKAN class Mesh { public: - VulkanBuffer scratchBuffer; - VulkanBuffer blasBuffer; - VulkanBuffer vertexStaging; - VulkanBuffer indexStaging; - VulkanBuffer vertexBuffer; - VulkanBuffer indexBuffer; + VulkanBuffer scratchBuffer; + VulkanBuffer blasBuffer; + VulkanBuffer vertexBuffer; + VulkanBuffer indexBuffer; VkAccelerationStructureGeometryTrianglesDataKHR blasData; VkAccelerationStructureGeometryKHR blas; + VkAccelerationStructureKHR accelerationStructure; bool opaque; void Build(std::span verticies, std::span indicies, VkCommandBuffer cmd); }; diff --git a/interfaces/Crafter.Graphics-RenderingElement3DVulkan.cppm b/interfaces/Crafter.Graphics-RenderingElement3DVulkan.cppm index 5a8640d..9165bd6 100644 --- a/interfaces/Crafter.Graphics-RenderingElement3DVulkan.cppm +++ b/interfaces/Crafter.Graphics-RenderingElement3DVulkan.cppm @@ -1,6 +1,6 @@ /* Crafter®.Graphics -Copyright (C) 2025 Catcrafts® +Copyright (C) 2026 Catcrafts® catcrafts.net This library is free software; you can redistribute it and/or @@ -18,636 +18,24 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ module; -#define STB_IMAGE_IMPLEMENTATION -#include "../lib/stb_image.h" -#include "../lib/stb_truetype.h" -export module Crafter.Graphics:RenderingElement; +#ifdef CRAFTER_GRAPHICS_VULKAN +#include +#endif +export module Crafter.Graphics:RenderingElement3DVulkan; +#ifdef CRAFTER_GRAPHICS_VULKAN import std; -import :Transform; -import :Font; -import :Types; -import :Image; -import :Window; +import :Mesh; +import :VulkanBuffer; export namespace Crafter { - enum class TextAlignment { - Left, - Center, - Right - }; - - enum class TextOverflowMode { - Clip, - Wrap - }; - - enum class TextScaleMode { - None, - Font, - Element, - Buffer - }; - - struct RenderElementScalingOwning { - std::vector scalingBuffer; - std::uint32_t bufferWidth; - std::uint32_t bufferHeight; - bool bufferUpdated = true; - RenderElementScalingOwning() = default; - RenderElementScalingOwning(std::uint32_t bufferWidth, std::uint32_t bufferHeight) : scalingBuffer(bufferWidth*bufferHeight), bufferWidth(bufferWidth), bufferHeight(bufferHeight) { - - } - }; - - struct RenderElementScalingNonOwning { - Pixel_BU8_GU8_RU8_AU8* scalingBuffer; - std::uint32_t bufferWidth; - std::uint32_t bufferHeight; - bool bufferUpdated = true; - RenderElementScalingNonOwning() = default; - RenderElementScalingNonOwning(Pixel_BU8_GU8_RU8_AU8* scalingBuffer, std::uint32_t bufferWidth, std::uint32_t bufferHeight) : scalingBuffer(scalingBuffer), bufferWidth(bufferWidth), bufferHeight(bufferHeight) { - - } - }; - - struct RenderElementRotating { - std::uint32_t rotation; - bool rotationUpdated = true; - RenderElementRotating() = default; - RenderElementRotating(std::uint32_t rotation) : rotation(rotation) { - - } - }; - - - struct EmptyScalingBase {}; - struct EmptyRotatingBase {}; - - template - using ScalingBase = - std::conditional_t< - Scaling, - std::conditional_t, - EmptyScalingBase - >; - - template - using RotatingBase = - std::conditional_t< - Rotating, - RenderElementRotating, - EmptyRotatingBase - >; - - class RenderingElementBase : public Transform { - public: - std::vector buffer; - OpaqueType opaque; - RenderingElementBase(Anchor anchor) : Transform(anchor) { - scaled.width = 0; - } - RenderingElementBase(Anchor anchor, OpaqueType opaque) : Transform(anchor), opaque(opaque) { - scaled.width = 0; - } - }; - - template requires ((!Rotating || Scaling) && (!Owning || Scaling)) - class RenderingElement : public RenderingElementBase, public ScalingBase, public RotatingBase { - public: - RenderingElement() = default; - RenderingElement(Anchor anchor, OpaqueType opaque) : RenderingElementBase(anchor, opaque) { - - } - RenderingElement(Anchor anchor, OpaqueType opaque, std::uint32_t rotation) requires(Rotating) : RenderingElementBase(anchor, opaque), RotatingBase(rotation) { - - } - - RenderingElement(Anchor anchor, const std::string_view imagePath) : RenderingElementBase(anchor) { - LoadImage(imagePath); - } - RenderingElement(Anchor anchor, const std::string_view imagePath, std::uint32_t rotation) requires(Rotating) : RenderingElementBase(anchor), RotatingBase(rotation) { - LoadImage(imagePath); - } - - RenderingElement(Anchor anchor, const std::string_view imagePath, OpaqueType opaque) : RenderingElementBase(anchor, opaque) { - LoadImageNoOpaqueCheck(imagePath); - } - RenderingElement(Anchor anchor, const std::string_view imagePath, OpaqueType opaque, std::uint32_t rotation) requires(Rotating) : RenderingElementBase(anchor, opaque), RotatingBase(rotation) { - LoadImageNoOpaqueCheck(imagePath); - } - - RenderingElement(Anchor anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight, Pixel_BU8_GU8_RU8_AU8* scalingBuffer) requires(Scaling && !Owning) : RenderingElementBase(anchor, opaque), ScalingBase(bufferWidth, bufferHeight, scalingBuffer) { - - } - RenderingElement(Anchor anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight, Pixel_BU8_GU8_RU8_AU8* scalingBuffer, std::uint32_t rotation) requires(Scaling && !Owning && Rotating) : RenderingElementBase(anchor, opaque), ScalingBase(bufferWidth, bufferHeight, scalingBuffer), RotatingBase(rotation) { - - } - - RenderingElement(Anchor anchor, OpaqueType opaque, Image& image) requires(Scaling && !Owning) : RenderingElementBase(anchor, opaque), ScalingBase(image.buffer.data(), image.width, image.height) { - - } - RenderingElement(Anchor anchor, OpaqueType opaque, Image& image, std::uint32_t rotation) requires(Scaling && !Owning && Rotating) : RenderingElementBase(anchor, opaque), ScalingBase(image.buffer.data(), image.width, image.height), RotatingBase(rotation) { - - } - - RenderingElement(Anchor anchor, Image& image) requires(Scaling && !Owning) : RenderingElementBase(anchor, image.opaque), ScalingBase(image.buffer.data(), image.width, image.height) { - - } - RenderingElement(Anchor anchor, Image& image, std::uint32_t rotation) requires(Scaling && !Owning && Rotating) : RenderingElementBase(anchor, image.opaque), ScalingBase(image.buffer.data(), image.width, image.height), RotatingBase(rotation) { - - } - - RenderingElement(Anchor anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight) requires(Owning) : RenderingElementBase(anchor, opaque), ScalingBase(bufferWidth, bufferHeight) { - - } - RenderingElement(Anchor anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight, std::uint32_t rotation) requires(Owning && Rotating) : RenderingElementBase(anchor, opaque), ScalingBase(bufferWidth, bufferHeight) , RotatingBase(rotation) { - - } - - RenderingElement(RenderingElement&) = delete; - RenderingElement& operator=(RenderingElement&) = delete; - - void ScaleNearestNeighbor() requires(Scaling) { - for (std::uint32_t y = 0; y < scaled.height; y++) { - std::uint32_t srcY = y * ScalingBase::bufferHeight / scaled.height; - for (std::uint32_t x = 0; x < scaled.width; x++) { - std::uint32_t srcX = x * ScalingBase::bufferWidth / scaled.width; - buffer[y * scaled.width + x] = ScalingBase::scalingBuffer[srcY * ScalingBase::bufferWidth + srcX]; - } - } - } - - void ScaleRotating() requires(Scaling) { - const double rad = (static_cast(RotatingBase::rotation) / static_cast(std::numeric_limits::max())) * 2.0 * std::numbers::pi; - - const std::uint32_t dstWidth = scaled.width; - const std::uint32_t dstHeight = scaled.height; - - const double c2 = std::abs(std::cos(rad)); - const double s2 = std::abs(std::sin(rad)); - - const double rotatedWidth = dstWidth * c2 + dstHeight * s2; - const double rotatedHeight = dstWidth * s2 + dstHeight * c2; - - const std::uint32_t diffX = static_cast(std::ceil((rotatedWidth - dstWidth) * 0.5)); - const std::uint32_t diffY = static_cast(std::ceil((rotatedHeight - dstHeight) * 0.5)); - - scaled.width += diffX + diffX; - scaled.height += diffY + diffY; - - scaled.x -= diffX; - scaled.y -= diffY; - - buffer.clear(); - buffer.resize(scaled.width * scaled.height); - - // Destination center - const double dstCx = (static_cast(scaled.width) - 1.0) * 0.5; - const double dstCy = (static_cast(scaled.height) - 1.0) * 0.5; - - // Source center - const double srcCx = (static_cast(ScalingBase::bufferWidth) - 1.0) * 0.5; - const double srcCy = (static_cast(ScalingBase::bufferHeight) - 1.0) * 0.5; - - const double c = std::cos(rad); - const double s = std::sin(rad); - - // Scale factors (destination → source) - const double scaleX = static_cast(ScalingBase::bufferWidth) / dstWidth; - const double scaleY = static_cast(ScalingBase::bufferHeight) / dstHeight; - - for (std::uint32_t yB = 0; yB < scaled.height; ++yB) { - for (std::uint32_t xB = 0; xB < scaled.width; ++xB) { - - // ---- Destination pixel relative to center ---- - const double dx = (static_cast(xB) - dstCx) * scaleX; - const double dy = (static_cast(yB) - dstCy) * scaleY; - - // ---- Inverse rotation ---- - const double sx = (c * dx - s * dy) + srcCx; - const double sy = (s * dx + c * dy) + srcCy; - - // ---- Nearest neighbour sampling ---- - const std::int32_t srcX = static_cast(std::round(sx)); - const std::int32_t srcY = static_cast(std::round(sy)); - - if (srcX >= 0 && srcX < ScalingBase::bufferWidth && srcY >= 0 && srcY < ScalingBase::bufferHeight) { - buffer[yB * scaled.width + xB] = ScalingBase::scalingBuffer[srcY * ScalingBase::bufferWidth + srcX]; - } - } - } - } - - void UpdatePosition(Window& window, ScaleData oldScale) { - if constexpr(Scaling && !Rotating) { - if(oldScale.width != scaled.width || oldScale.height != scaled.height) { - buffer.resize(scaled.width * scaled.height); - ScaleNearestNeighbor(); - window.AddDirtyRect(oldScale); - window.AddDirtyRect(scaled); - } else if(oldScale.x != scaled.x || oldScale.y != scaled.y) { - window.AddDirtyRect(oldScale); - window.AddDirtyRect(scaled); - if(ScalingBase::bufferUpdated) { - ScaleNearestNeighbor(); - ScalingBase::bufferUpdated = false; - } - } else if(ScalingBase::bufferUpdated) { - ScaleNearestNeighbor(); - ScalingBase::bufferUpdated = false; - } - } else if constexpr(Rotating) { - if(oldScale.width != scaled.width || oldScale.height != scaled.height) { - buffer.resize(scaled.width * scaled.height); - ScaleRotating(); - window.AddDirtyRect(oldScale); - window.AddDirtyRect(scaled); - } else if(oldScale.x != scaled.x || oldScale.y != scaled.y) { - window.AddDirtyRect(oldScale); - window.AddDirtyRect(scaled); - if(ScalingBase::bufferUpdated || RotatingBase::rotationUpdated) { - ScaleRotating(); - ScalingBase::bufferUpdated = false; - RotatingBase::rotationUpdated = false; - } - } else if(ScalingBase::bufferUpdated || RotatingBase::rotationUpdated) { - ScaleRotating(); - ScalingBase::bufferUpdated = false; - RotatingBase::rotationUpdated = false; - } - } else { - if(oldScale.width != scaled.width || oldScale.height != scaled.height) { - buffer.resize(scaled.width * scaled.height); - window.AddDirtyRect(oldScale); - window.AddDirtyRect(scaled); - } - if(oldScale.x != scaled.x || oldScale.y != scaled.y) { - window.AddDirtyRect(oldScale); - window.AddDirtyRect(scaled); - } - } - } - - void UpdatePosition(Window& window) override { - ScaleData oldScale = scaled; - window.ScaleElement(*this); - UpdatePosition(window, oldScale); - for(Transform* child : children) { - child->UpdatePosition(window, *this); - } - } - - void UpdatePosition(Window& window, Transform& parent) override { - ScaleData oldScale = scaled; - window.ScaleElement(*this, parent); - UpdatePosition(window, oldScale); - for(Transform* child : children) { - child->UpdatePosition(window, *this); - } + class RenderingElement3DVulkan { + // public: + // Mesh* mesh; + // VkAccelerationStructureInstanceKHR instance; + // static std::vector elements; + // inline static VulkanBuffer instanceBuffer; + // RenderingElement3DVulkan(Mesh& mesh); + // static void BuildTLAS(VkCommandBuffer cmd); + }; } - - void LoadImage(const std::string_view imagePath) { - std::filesystem::path abs = std::filesystem::absolute(imagePath); - int xSize; - int ySize; - unsigned char* bgData = stbi_load(abs.string().c_str(), &xSize, &ySize, nullptr, 4); - - if constexpr(Scaling && !Owning) { - ScalingBase::bufferUpdated = true; - } else if constexpr(Scaling && Owning) { - ScalingBase::bufferWidth = xSize; - ScalingBase::bufferHeight = ySize; - ScalingBase::bufferUpdated = true; - ScalingBase::scalingBuffer.resize(xSize*ySize); - } else { - buffer.resize(xSize*ySize); - } - - opaque = OpaqueType::FullyOpaque; - - if constexpr(Scaling) { - for(std::uint32_t x = 0; x < xSize; x++) { - for(std::uint32_t y = 0; y < ySize; y++) { - std::uint32_t idx = (x*ySize+y)*4; - ScalingBase::scalingBuffer[x*ySize+y].r = bgData[idx]; - ScalingBase::scalingBuffer[x*ySize+y].g = bgData[idx+1]; - ScalingBase::scalingBuffer[x*ySize+y].b = bgData[idx+2]; - ScalingBase::scalingBuffer[x*ySize+y].a = bgData[idx+3]; - } - } - - for(std::uint32_t i = 0; i < xSize*ySize; i++) { - if(ScalingBase::scalingBuffer[i].a != 255) { - opaque = OpaqueType::SemiOpaque; - for(std::uint32_t i2 = 0; i2 < xSize*ySize; i2++) { - if(ScalingBase::scalingBuffer[i2].a != 0 && ScalingBase::scalingBuffer[i2].a != 255) { - opaque = OpaqueType::Transparent; - return; - } - } - return; - } - } - } else { - for(std::uint32_t x = 0; x < xSize; x++) { - for(std::uint32_t y = 0; y < ySize; y++) { - std::uint32_t idx = (x*ySize+y)*4; - buffer[x*ySize+y].r = bgData[idx]; - buffer[x*ySize+y].g = bgData[idx+1]; - buffer[x*ySize+y].b = bgData[idx+2]; - buffer[x*ySize+y].a = bgData[idx+3]; - } - } - - for(std::uint32_t i = 0; i < xSize*ySize; i++) { - if(buffer[i].a != 255) { - opaque = OpaqueType::SemiOpaque; - for(std::uint32_t i2 = 0; i2 < xSize*ySize; i2++) { - if(buffer[i2].a != 0 && buffer[i2].a != 255) { - opaque = OpaqueType::Transparent; - return; - } - } - return; - } - } - } - } - void LoadImageNoOpaqueCheck(const std::string_view imagePath) { - std::filesystem::path abs = std::filesystem::absolute(imagePath); - int xSize; - int ySize; - unsigned char* bgData = stbi_load(abs.string().c_str(), &xSize, &ySize, nullptr, 4); - - - if constexpr(Scaling && !Owning) { - ScalingBase::bufferUpdated = true; - } else if constexpr(Scaling && Owning) { - ScalingBase::bufferWidth = xSize; - ScalingBase::bufferHeight = ySize; - ScalingBase::bufferUpdated = true; - ScalingBase::scalingBuffer.resize(xSize*ySize); - } else { - buffer.resize(xSize*ySize); - } - - - if constexpr(Scaling) { - for(std::uint32_t x = 0; x < xSize; x++) { - for(std::uint32_t y = 0; y < ySize; y++) { - std::uint32_t idx = (x*ySize+y)*4; - ScalingBase::scalingBuffer[x*ySize+y].r = bgData[idx]; - ScalingBase::scalingBuffer[x*ySize+y].g = bgData[idx+1]; - ScalingBase::scalingBuffer[x*ySize+y].b = bgData[idx+2]; - ScalingBase::scalingBuffer[x*ySize+y].a = bgData[idx+3]; - } - } - } else { - for(std::uint32_t x = 0; x < xSize; x++) { - for(std::uint32_t y = 0; y < ySize; y++) { - std::uint32_t idx = (x*ySize+y)*4; - buffer[x*ySize+y].r = bgData[idx]; - buffer[x*ySize+y].g = bgData[idx+1]; - buffer[x*ySize+y].b = bgData[idx+2]; - buffer[x*ySize+y].a = bgData[idx+3]; - } - } - } - } - std::vector ResizeText(Window& window, const std::string_view text, float size, Font& font, TextOverflowMode overflowMode = TextOverflowMode::Clip, TextScaleMode scaleMode = TextScaleMode::None, Transform* parent = nullptr) { - float scale = stbtt_ScaleForPixelHeight(&font.font, size); - int baseline = (int)(font.ascent * scale); - - std::vector lines; - std::string_view remaining = text; - - std::uint32_t lineHeight = (font.ascent - font.descent) * scale; - - if(overflowMode == TextOverflowMode::Clip) { - while (!remaining.empty()) { - // Find next newline or end of string - auto newlinePos = remaining.find('\n'); - if (newlinePos != std::string_view::npos) { - lines.emplace_back(remaining.substr(0, newlinePos)); - remaining = remaining.substr(newlinePos + 1); - } else { - lines.emplace_back(remaining); - break; - } - } - std::uint32_t maxWidth = 0; - - for(const std::string_view line: lines) { - std::uint32_t lineWidth = 0; - for (const char c : line) { - int advance, lsb; - stbtt_GetCodepointHMetrics(&font.font, c, &advance, &lsb); - lineWidth += (int)(advance * scale); - } - if(lineWidth > maxWidth) { - maxWidth = lineWidth; - } - } - - - if(scaleMode == TextScaleMode::Element) { - std::int32_t logicalPerPixelY = anchor.height / scaled.height; - std::int32_t oldHeight = anchor.height; - std::int32_t logicalPerPixelX = anchor.width / scaled.width; - std::int32_t oldwidth = anchor.width; - anchor.height = lineHeight * logicalPerPixelY; - anchor.width = maxWidth * logicalPerPixelX; - if(oldHeight != anchor.height || oldwidth != anchor.width) { - if(parent) { - UpdatePosition(window, *parent); - } else { - UpdatePosition(window); - } - } - } else if(scaleMode == TextScaleMode::Font) { - //todo - } else if(scaleMode == TextScaleMode::Buffer) { - if constexpr(Scaling && Owning) { - std::uint32_t neededHeight = lines.size() * lineHeight; - if(neededHeight != ScalingBase::bufferHeight || maxWidth != ScalingBase::bufferWidth) { - ScalingBase::bufferHeight = neededHeight; - ScalingBase::bufferWidth = maxWidth; - ScalingBase::bufferUpdated = true; - ScalingBase::scalingBuffer.resize(neededHeight*maxWidth); - } - } - } else { - if constexpr(Scaling) { - lines.resize(ScalingBase::bufferHeight / lines.size()); - } else { - lines.resize(scaled.height / lines.size()); - } - } - } else { - while (!remaining.empty()) { - std::string_view line; - auto newlinePos = remaining.find('\n'); - if (newlinePos != std::string_view::npos) { - line = remaining.substr(0, newlinePos); - remaining = remaining.substr(newlinePos + 1); - } else { - line = remaining; - remaining = ""; - } - - std::uint32_t lineWidth = 0; - std::size_t lastWrapPos = 0; // position of last space that can be used to wrap - std::size_t startPos = 0; - - for (std::size_t i = 0; i < line.size(); ++i) { - char c = line[i]; - - // get width of this character - int advance, lsb; - stbtt_GetCodepointHMetrics(&font.font, c, &advance, &lsb); - lineWidth += (std::uint32_t)(advance * scale); - - // remember last space for wrapping - if (c == ' ') { - lastWrapPos = i; - } - - // if line exceeds width, wrap - if (lineWidth > scaled.width) { - std::size_t wrapPos; - if (lastWrapPos > startPos) { - wrapPos = lastWrapPos; // wrap at last space - } else { - wrapPos = i; // no space, hard wrap - } - - // push the line up to wrapPos - lines.push_back(line.substr(startPos, wrapPos - startPos)); - - // skip any spaces at the beginning of next line - startPos = wrapPos; - while (startPos < line.size() && line[startPos] == ' ') { - ++startPos; - } - - // reset width and i - lineWidth = 0; - i = startPos - 1; // -1 because loop will increment i - } - } - - // add the remaining part of the line - if (startPos < line.size()) { - lines.push_back(line.substr(startPos)); - } - } - - if(scaleMode == TextScaleMode::Element) { - std::int32_t logicalPerPixelY = anchor.height / scaled.height; - std::int32_t oldHeight = anchor.height; - anchor.height = lineHeight * logicalPerPixelY; - if(oldHeight != anchor.height) { - if(parent) { - UpdatePosition(window, *parent); - } else { - UpdatePosition(window); - } - } - } else if(scaleMode == TextScaleMode::Font) { - //todo - } else if(scaleMode == TextScaleMode::Buffer) { - if constexpr(Scaling && Owning) { - std::uint32_t neededHeight = lines.size() * lineHeight; - if(neededHeight != ScalingBase::bufferHeight) { - ScalingBase::bufferHeight = neededHeight; - ScalingBase::bufferUpdated = true; - ScalingBase::scalingBuffer.resize(neededHeight*ScalingBase::bufferWidth); - } - } - } else { - if constexpr(Scaling) { - lines.resize(ScalingBase::bufferHeight / lines.size()); - } else { - lines.resize(scaled.height / lines.size()); - } - } - } - - return lines; - } - void RenderText(Window& window, std::span lines, float size, Pixel_BU8_GU8_RU8_AU8 color, Font& font, TextAlignment alignment = TextAlignment::Left, std::uint32_t offsetX = 0, std::uint32_t offsetY = 0) { - float scale = stbtt_ScaleForPixelHeight(&font.font, size); - int baseline = (int)(font.ascent * scale); - std::uint32_t lineHeight = (font.ascent - font.descent) * scale; - std::uint32_t currentY = baseline; - for(std::string_view line : lines) { - - std::uint32_t lineWidth = 0; - for (const char c : line) { - int advance, lsb; - stbtt_GetCodepointHMetrics(&font.font, c, &advance, &lsb); - lineWidth += (int)(advance * scale); - } - - std::uint32_t startX = 0; - switch (alignment) { - case TextAlignment::Left: - startX = 0; - break; - case TextAlignment::Center: - startX = (scaled.width - lineWidth) / 2; - break; - case TextAlignment::Right: - startX = scaled.width - lineWidth; - break; - } - std::uint32_t x = startX; - - for (std::size_t i = 0; i < line.size(); ++i) { - int codepoint = line[i]; - - int ax; - int lsb; - stbtt_GetCodepointHMetrics(&font.font, codepoint, &ax, &lsb); - - int c_x1, c_y1, c_x2, c_y2; - stbtt_GetCodepointBitmapBox(&font.font, codepoint, scale, scale, &c_x1, &c_y1, &c_x2, &c_y2); - - int w = c_x2 - c_x1; - int h = c_y2 - c_y1; - - std::vector bitmap(w * h); - stbtt_MakeCodepointBitmap(&font.font, bitmap.data(), w, h, w, scale, scale, codepoint); - - // Only render characters that fit within the scaled bounds - for (int j = 0; j < h; j++) { - for (int i = 0; i < w; i++) { - int bufferX = x + i + c_x1 + offsetX; - int bufferY = currentY + j + c_y1 + offsetY; - - // Only draw pixels that are within our scaled buffer bounds - if constexpr(Scaling) { - if (bufferX >= 0 && bufferX < ScalingBase::bufferWidth && bufferY >= 0 && bufferY < ScalingBase::bufferHeight) { - ScalingBase::scalingBuffer[bufferY * ScalingBase::bufferWidth + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]}; - } - } else { - if (bufferX >= 0 && bufferX < (int)scaled.width && bufferY >= 0 && bufferY < (int)scaled.height) { - buffer[bufferY * scaled.width + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]}; - } - } - } - } - - x += (int)(ax * scale); - - if (i + 1 < line.size()) { - x += (int)stbtt_GetCodepointKernAdvance(&font.font, codepoint, line[i+1]); - } - } - currentY += lineHeight; - } - } - }; -} \ No newline at end of file +#endif \ No newline at end of file diff --git a/interfaces/Crafter.Graphics-VulkanBuffer.cppm b/interfaces/Crafter.Graphics-VulkanBuffer.cppm index 5d580e8..de37c9b 100644 --- a/interfaces/Crafter.Graphics-VulkanBuffer.cppm +++ b/interfaces/Crafter.Graphics-VulkanBuffer.cppm @@ -29,72 +29,255 @@ import std; import :VulkanDevice; namespace Crafter { - export template - class VulkanBuffer { - public: - T* value; + export class VulkanBufferBase { + public: VkDescriptorBufferInfo descriptor; - VkDeviceSize alignment = 0; - VkMemoryPropertyFlags memoryPropertyFlags; - VkBufferUsageFlags usageFlags; VkBuffer buffer = VK_NULL_HANDLE; - VkDeviceMemory memory = VK_NULL_HANDLE; + VkDeviceMemory memory; + }; + + export class VulkanBufferAdressable { + public: VkDeviceAddress address; + }; + export class VulkanBufferAdressableEmpty {}; + template + using VulkanBufferAdressableConditional = + std::conditional_t< + Adressable, + VulkanBufferAdressable, + VulkanBufferAdressableEmpty + >; + + export template + class VulkanBufferMapped { + public: + T* value; + }; + export class VulkanBufferMappedEmpty {}; + template + using VulkanBufferMappedConditional = + std::conditional_t< + Mapped, + VulkanBufferMapped, + VulkanBufferMappedEmpty + >; + + + export template requires ((Mapped && !Staged) || (!Mapped && Staged) || (!Mapped && !Staged)) + class VulkanBuffer; + + export template + class VulkanBufferStaged { + VulkanBuffer* stagingBuffer; + }; + export class VulkanBufferStagedEmpty {}; + template + using VulkanBufferStagedConditional = + std::conditional_t< + Staged, + VulkanBufferStaged, + VulkanBufferStagedEmpty + >; + + + export template requires ((Mapped && !Staged) || (!Mapped && Staged) || (!Mapped && !Staged)) + class VulkanBuffer : public VulkanBufferBase, public VulkanBufferMappedConditional, public VulkanBufferAdressableConditional, public VulkanBufferStagedConditional { public: - VulkanBuffer() : value(nullptr) {}; - VulkanBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, std::uint32_t count = 1) { + VulkanBuffer() = default; + void Create(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, std::uint32_t count) { + if constexpr(Staged) { + new (&VulkanBufferMappedConditional::stagingBuffer) VulkanBuffer(); + VulkanBufferMappedConditional::stagingBuffer->Create(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, count); + } + VkBufferCreateInfo bufferCreateInfo {}; bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferCreateInfo.usage = usageFlags; bufferCreateInfo.size = sizeof(T)*count; VulkanDevice::CheckVkResult(vkCreateBuffer(VulkanDevice::device, &bufferCreateInfo, nullptr, &buffer)); - // Create the memory backing up the buffer handle VkMemoryRequirements memReqs; - VkMemoryAllocateInfo memAlloc {}; - memAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; vkGetBufferMemoryRequirements(VulkanDevice::device, buffer, &memReqs); - memAlloc.allocationSize = memReqs.size; - // Find a memory type index that fits the properties of the buffer - memAlloc.memoryTypeIndex = VulkanDevice::GetMemoryType(memReqs.memoryTypeBits, memoryPropertyFlags); - // If the buffer has VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT set we also need to enable the appropriate flag during allocation - VkMemoryAllocateFlagsInfoKHR allocFlagsInfo{}; - if (usageFlags & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) { - allocFlagsInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR; - allocFlagsInfo.flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR; + VkMemoryAllocateInfo memAlloc { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .allocationSize = memReqs.size, + .memoryTypeIndex = VulkanDevice::GetMemoryType(memReqs.memoryTypeBits, memoryPropertyFlags) + }; + if constexpr(Adressable) { + VkMemoryAllocateFlagsInfoKHR allocFlagsInfo { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR, + .flags = VK_MEMORY_ALLOCATE_DEVICE_ADDRESS_BIT_KHR, + }; memAlloc.pNext = &allocFlagsInfo; + VulkanDevice::CheckVkResult(vkAllocateMemory(VulkanDevice::device, &memAlloc, nullptr, &memory)); + } else { + VulkanDevice::CheckVkResult(vkAllocateMemory(VulkanDevice::device, &memAlloc, nullptr, &memory)); } - VulkanDevice::CheckVkResult(vkAllocateMemory(VulkanDevice::device, &memAlloc, nullptr, &memory)); - - alignment = memReqs.alignment; - usageFlags = usageFlags; - memoryPropertyFlags = memoryPropertyFlags; descriptor.offset = 0; descriptor.buffer = buffer; - descriptor.range = sizeof(T)*count; + descriptor.range = memReqs.size; VulkanDevice::CheckVkResult(vkBindBufferMemory(VulkanDevice::device, buffer, memory, 0)); - if(memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) { - VulkanDevice::CheckVkResult(vkMapMemory(VulkanDevice::device, memory, 0, sizeof(T)*count, 0, reinterpret_cast(&value))); + + if constexpr(Adressable) { + VkBufferDeviceAddressInfo addressInfo = { + .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, + .buffer = buffer + }; + VulkanBufferAdressableConditional::address = vkGetBufferDeviceAddress(VulkanDevice::device, &addressInfo); } - VkBufferDeviceAddressInfo addressInfo = { - .sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO, - .buffer = buffer + if constexpr(Mapped) { + VulkanDevice::CheckVkResult(vkMapMemory(VulkanDevice::device, memory, 0, memReqs.size, 0, reinterpret_cast(&(VulkanBufferMappedConditional::value)))); + } + } + + void Clear() { + if constexpr(Mapped) { + vkUnmapMemory(VulkanDevice::device, memory); + } + vkDestroyBuffer(VulkanDevice::device, buffer, nullptr); + vkFreeMemory(VulkanDevice::device, memory, nullptr); + buffer = VK_NULL_HANDLE; + if constexpr(Staged) { + delete VulkanBufferMappedConditional::stagingBuffer; + } + } + + void Resize(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, std::uint32_t count) { + if(buffer != VK_NULL_HANDLE) { + Clear(); + } + Create(usageFlags, memoryPropertyFlags, count); + } + + void Copy(VkCommandBuffer cmd, VulkanBuffer& dst) { + VkBufferCopy copyRegion = { + .srcOffset = 0, + .dstOffset = 0, + .size = descriptor.range }; - address = vkGetBufferDeviceAddress(VulkanDevice::device, &addressInfo); + vkCmdCopyBuffer( + cmd, + buffer, + dst.buffer, + 1, + ©Region + ); } + + void Copy(VkCommandBuffer cmd, VulkanBuffer& dst, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask) { + Copy(cmd, dst); + + VkBufferMemoryBarrier barrier = { + .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, + .srcAccessMask = srcAccessMask, + .dstAccessMask = dstAccessMask, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .buffer = buffer, + .offset = 0, + .size = VK_WHOLE_SIZE + }; + + vkCmdPipelineBarrier( + cmd, + srcStageMask, + dstStageMask, + 0, + 0, NULL, + 1, &barrier, + 0, NULL + ); + } + + void FlushDevice() requires(Mapped) { + VkMappedMemoryRange range = { + .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, + .memory = memory, + .offset = 0, + .size = VK_WHOLE_SIZE + }; + vkFlushMappedMemoryRanges(VulkanDevice::device, 1, &range); + } + + void FlushDevice(VkCommandBuffer cmd, VkAccessFlags dstAccessMask, VkPipelineStageFlags dstStageMask) requires(Mapped) { + FlushDevice(); + VkBufferMemoryBarrier barrier = { + .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, + .srcAccessMask = VK_ACCESS_HOST_WRITE_BIT, + .dstAccessMask = dstAccessMask, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .buffer = buffer, + .offset = 0, + .size = VK_WHOLE_SIZE + }; + + vkCmdPipelineBarrier( + cmd, + VK_PIPELINE_STAGE_HOST_BIT, + dstStageMask, + 0, + 0, NULL, + 1, &barrier, + 0, NULL + ); + } + + void FlushHost() requires(Mapped) { + VkMappedMemoryRange range = { + .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, + .memory = memory, + .offset = 0, + .size = VK_WHOLE_SIZE + }; + vkInvalidateMappedMemoryRanges(VulkanDevice::device, 1, &range); + } + + void FlushDevice(VkCommandBuffer cmd) requires(Staged) { + VulkanBufferStagedConditional::stagingBuffer.FlushDevice(VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + VulkanBufferStagedConditional::stagingBuffer.Copy(cmd, this); + } + + void FlushDevice(VkCommandBuffer cmd, VkAccessFlags dstAccessMask, VkPipelineStageFlags dstStageMask) requires(Staged) { + VulkanBufferStagedConditional::stagingBuffer.FlushDevice(VK_ACCESS_TRANSFER_READ_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + VulkanBufferStagedConditional::stagingBuffer.Copy(cmd, this, VK_ACCESS_TRANSFER_WRITE_BIT, dstAccessMask, VK_PIPELINE_STAGE_TRANSFER_BIT, dstStageMask); + } + + void FlushHost(VkCommandBuffer cmd) requires(Staged) { + Copy(cmd, VulkanBufferStagedConditional::stagingBuffer); + VulkanBufferStagedConditional::stagingBuffer.FlushHost(); + } + + + VulkanBuffer(VulkanBuffer&& other) { + descriptor = other.descriptor; + buffer = other.buffer; + memory = other.memory; + other.buffer = VK_NULL_HANDLE; + if constexpr(Adressable) { + VulkanBufferAdressableConditional::address = other.VulkanBufferAdressableConditional::address; + } + if constexpr(Mapped) { + VulkanBufferMappedConditional::value = other.VulkanBufferMappedConditional::value; + } + if constexpr(Staged) { + VulkanBufferStagedConditional::stagingBuffer = other.VulkanBufferStagedConditional::stagingBuffer; + } + }; + ~VulkanBuffer() { - if(value != nullptr) { - if(memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) { - vkUnmapMemory(VulkanDevice::device, memory); - } - vkDestroyBuffer(VulkanDevice::device, buffer, nullptr); - vkFreeMemory(VulkanDevice::device, memory, nullptr); + if(buffer != VK_NULL_HANDLE) { + Clear(); } } + + VulkanBuffer(VulkanBuffer&) = delete; + VulkanBuffer& operator=(const VulkanBuffer&) = delete; }; } #endif \ No newline at end of file diff --git a/interfaces/Crafter.Graphics-VulkanDevice.cppm b/interfaces/Crafter.Graphics-VulkanDevice.cppm index 23c309d..9855cf8 100644 --- a/interfaces/Crafter.Graphics-VulkanDevice.cppm +++ b/interfaces/Crafter.Graphics-VulkanDevice.cppm @@ -43,6 +43,7 @@ export namespace Crafter { inline static PFN_vkGetAccelerationStructureBuildSizesKHR vkGetAccelerationStructureBuildSizesKHR; inline static PFN_vkCreateAccelerationStructureKHR vkCreateAccelerationStructureKHR; inline static PFN_vkCmdBuildAccelerationStructuresKHR vkCmdBuildAccelerationStructuresKHR; + inline static PFN_vkGetAccelerationStructureDeviceAddressKHR vkGetAccelerationStructureDeviceAddressKHR; inline static VkPhysicalDeviceMemoryProperties memoryProperties; inline static VkFormat depthFormat = VK_FORMAT_UNDEFINED; static void CreateDevice(); diff --git a/interfaces/Crafter.Graphics.cppm b/interfaces/Crafter.Graphics.cppm index 457a111..3c56413 100644 --- a/interfaces/Crafter.Graphics.cppm +++ b/interfaces/Crafter.Graphics.cppm @@ -36,6 +36,7 @@ export import :Mesh; export import :VulkanDevice; export import :VulkanTransition; export import :VulkanBuffer; +export import :RenderingElement3DVulkan; #endif // export import :WindowWaylandVulkan; diff --git a/project.json b/project.json index 9d2550c..d1a5fb4 100644 --- a/project.json +++ b/project.json @@ -4,7 +4,7 @@ { "name": "base", "implementations": ["implementations/Crafter.Graphics-Font", "implementations/Crafter.Graphics-Shm", "implementations/Crafter.Graphics-Window", "implementations/Crafter.Graphics-MouseElement", "implementations/Crafter.Graphics-Transform", "implementations/Crafter.Graphics-GridElement", "implementations/Crafter.Graphics-Image"], - "interfaces": ["interfaces/Crafter.Graphics-Window", "interfaces/Crafter.Graphics", "interfaces/Crafter.Graphics-Types", "interfaces/Crafter.Graphics-Font", "interfaces/Crafter.Graphics-Image", "interfaces/Crafter.Graphics-Shm", "interfaces/Crafter.Graphics-Animation", "interfaces/Crafter.Graphics-RenderingElement", "interfaces/Crafter.Graphics-MouseElement", "interfaces/Crafter.Graphics-Transform", "interfaces/Crafter.Graphics-GridElement", "interfaces/Crafter.Graphics-VulkanDevice", "interfaces/Crafter.Graphics-VulkanTransition", "interfaces/Crafter.Graphics-Mesh", "interfaces/Crafter.Graphics-VulkanBuffer"], + "interfaces": ["interfaces/Crafter.Graphics-Window", "interfaces/Crafter.Graphics", "interfaces/Crafter.Graphics-Types", "interfaces/Crafter.Graphics-Font", "interfaces/Crafter.Graphics-Image", "interfaces/Crafter.Graphics-Shm", "interfaces/Crafter.Graphics-Animation", "interfaces/Crafter.Graphics-RenderingElement", "interfaces/Crafter.Graphics-MouseElement", "interfaces/Crafter.Graphics-Transform", "interfaces/Crafter.Graphics-GridElement", "interfaces/Crafter.Graphics-VulkanDevice", "interfaces/Crafter.Graphics-VulkanTransition", "interfaces/Crafter.Graphics-Mesh", "interfaces/Crafter.Graphics-VulkanBuffer", "interfaces/Crafter.Graphics-RenderingElement3DVulkan"], "type": "library" }, { @@ -22,7 +22,7 @@ }, { "name": "vulkan", - "implementations": ["implementations/Crafter.Graphics-VulkanDevice", "implementations/Crafter.Graphics-Window_vulkan", "implementations/Crafter.Graphics-Mesh_vulkan"], + "implementations": ["implementations/Crafter.Graphics-VulkanDevice", "implementations/Crafter.Graphics-Window_vulkan", "implementations/Crafter.Graphics-Mesh_vulkan", "implementations/Crafter.Graphics-RenderingElement3DVulkan"], "interfaces": [], "libs": ["wayland-client", "xkbcommon", "vulkan"], "c_files": ["lib/xdg-shell-protocol", "lib/wayland-xdg-decoration-unstable-v1-client-protocol", "lib/fractional-scale-v1", "lib/viewporter"],