From 31e5bc8e864791ddd4aa31fa0272f1a0d2876c28 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Sun, 24 Dec 2023 11:20:25 +0100 Subject: [PATCH 01/58] Queue selection unit test vkutils function --- CMakeLists.txt | 17 +- examples/App.cpp | 8 +- examples/App.h | 2 +- include/IContext.h | 22 +- src/backend/vulkan/UtilsVK.h | 104 ++++++++- src/backend/vulkan/VulkanContext.cpp | 114 +++++++++- src/backend/vulkan/VulkanContext.h | 17 +- src/backend/vulkan/VulkanDevice.cpp | 80 +++++-- src/backend/vulkan/VulkanDevice.h | 15 +- src/backend/vulkan/VulkanDevice12.cpp | 2 +- src/backend/vulkan/VulkanDevice2.cpp | 4 +- tests/integration/vulkan/ImageUpload.test.cpp | 43 ++-- .../SwapchainCreationDestruction.test.cpp | 10 +- .../vulkan/UniformBufferUpload.test.cpp | 74 +++---- .../VertexBufferCreationDestruction.test.cpp | 36 +-- .../vulkan/VertexBufferUpload.test.cpp | 208 +++++++++--------- tests/unit/vulkan/VkUtils.test.cpp | 175 ++++++++++++++- tests/utilities/ExtractBuffer.h | 52 ++--- tests/utilities/ExtractImage.h | 58 ++--- 19 files changed, 761 insertions(+), 280 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b6bf7c..83b75ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,13 +20,22 @@ add_library(${PROJECT_NAME} STATIC "include/main.cpp" ) +## Volk add_subdirectory("thirdparty/volk") +## VMA add_subdirectory("thirdparty/VulkanMemoryAllocator") +## GLFW +set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "GLFW_BUILD_EXAMPLES" FORCE) +set(GLFW_BUILD_TESTS OFF CACHE BOOL "GLFW_BUILD_TESTS" FORCE) add_subdirectory("thirdparty/glfw") +# GLM add_subdirectory("thirdparty/glm") +# GLI +set(GLI_TEST_ENABLED OFF CACHE BOOL "" FORCE) add_subdirectory("thirdparty/gli") -set(TINYGLTF_HEADER_ONLY ON CACHE INTERNAL "" FORCE) -set(TINYGLTF_INSTALL OFF CACHE INTERNAL "" FORCE) +# TINYGLTF +set(TINYGLTF_HEADER_ONLY ON CACHE BOOL "" FORCE) +set(TINYGLTF_INSTALL OFF CACHE BOOL "" FORCE) add_subdirectory("thirdparty/tinygltf") target_link_libraries(${PROJECT_NAME} PRIVATE volk VulkanMemoryAllocator) @@ -100,8 +109,8 @@ target_sources(${PROJECT_NAME} PRIVATE -option(BUILD_TESTS "Build tests" ON) -option(BUILD_EXAMPLES "Build examples" ON) +option(BUILD_TESTS "Build tests" OFF) +option(BUILD_EXAMPLES "Build examples" OFF) if(BUILD_EXAMPLES) set(LIB_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/include") diff --git a/examples/App.cpp b/examples/App.cpp index 1bd56d6..89a6853 100644 --- a/examples/App.cpp +++ b/examples/App.cpp @@ -49,11 +49,17 @@ App::App() throw std::runtime_error("Failed to CreateSwapchain"); } } + + // Create graphics queue + { + _graphicsQueue = _ctx->FindQueue(Fox::EQueueType::QUEUE_GRAPHICS); + } + // Create per frame data for (uint32_t i = 0; i < MAX_FRAMES; i++) { _frameData[i].Fence = _ctx->CreateFence(true); // already signaled - _frameData[i].CmdPool = _ctx->CreateCommandPool(); + _frameData[i].CmdPool = _ctx->CreateCommandPool(_graphicsQueue); _frameData[i].Cmd = _ctx->CreateCommandBuffer(_frameData[i].CmdPool); _frameData[i].ImageAvailableSemaphore = _ctx->CreateGpuSemaphore(); _frameData[i].WorkFinishedSemaphore = _ctx->CreateGpuSemaphore(); diff --git a/examples/App.h b/examples/App.h index 5398ab4..e106323 100644 --- a/examples/App.h +++ b/examples/App.h @@ -34,7 +34,7 @@ class App Fox::EFormat format = Fox::EFormat::B8G8R8A8_UNORM; uint32_t _swapchain{}; uint32_t _swapchainImageIndex{}; - + uint32_t _graphicsQueue{}; struct PerFrameData { uint32_t Fence{}; diff --git a/include/IContext.h b/include/IContext.h index 42efadb..b9fa63e 100644 --- a/include/IContext.h +++ b/include/IContext.h @@ -42,6 +42,7 @@ enum EResourceType : uint8_t DESCRIPTOR_SET = 15, SAMPLER = 16, INDIRECT_DRAW_COMMAND = 17, + QUEUE = 18, }; // SHOULD BE PRIVATE @@ -576,12 +577,11 @@ enum class EResourceState SHADING_RATE_SOURCE = 0x8000, }; -enum class EQueueType +enum EQueueType { - GRAPHICS = 0, - TRANSFER, - COMPUTE, - MAX_QUEUE_TYPE + QUEUE_GRAPHICS = 0x1, + QUEUE_TRANSFER = 0x2, + QUEUE_COMPUTE = 0x4, }; enum class EPipelineType @@ -656,7 +656,7 @@ typedef struct TextureBarrier typedef struct RenderTargetBarrier { - uint32_t RenderTarget; + uint32_t RenderTarget{}; EResourceState mCurrentState; EResourceState mNewState; uint8_t mBeginOnly : 1; @@ -665,10 +665,10 @@ typedef struct RenderTargetBarrier uint8_t mRelease : 1; uint8_t mQueueType : 5; /// Specifiy whether following barrier targets particular subresource - uint8_t mSubresourceBarrier : 1; + uint8_t mSubresourceBarrier : 1 {}; /// Following values are ignored if mSubresourceBarrier is false - uint8_t mMipLevel : 7; - uint16_t mArrayLayer; + uint8_t mMipLevel : 7 {}; + uint16_t mArrayLayer{}; } RenderTargetBarrier; typedef struct DescriptorData @@ -705,6 +705,8 @@ class IContext virtual bool SwapchainAcquireNextImageIndex(uint32_t swapchainId, uint64_t timeoutNanoseconds, uint32_t sempahoreid, uint32_t* outImageIndex) = 0; virtual void DestroySwapchain(uint32_t swapchainId) = 0; + virtual uint32_t FindQueue(uint32_t queueTypeFlag) = 0; + virtual uint32_t CreateBuffer(uint32_t size, EResourceType type, EMemoryUsage usage) = 0; virtual void* BeginMapBuffer(uint32_t buffer) = 0; virtual void EndMapBuffer(uint32_t buffer) = 0; @@ -724,7 +726,7 @@ class IContext virtual void UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t setIndex, uint32_t paramCount, DescriptorData* params) = 0; virtual uint32_t CreateSampler(uint32_t minLod, uint32_t maxLod) = 0; - virtual uint32_t CreateCommandPool() = 0; + virtual uint32_t CreateCommandPool(uint32_t queueId) = 0; virtual void DestroyCommandPool(uint32_t commandPoolId) = 0; virtual void ResetCommandPool(uint32_t commandPoolId) = 0; virtual uint32_t CreateCommandBuffer(uint32_t commandPoolId) = 0; diff --git a/src/backend/vulkan/UtilsVK.h b/src/backend/vulkan/UtilsVK.h index 8973b27..9e04386 100644 --- a/src/backend/vulkan/UtilsVK.h +++ b/src/backend/vulkan/UtilsVK.h @@ -630,7 +630,7 @@ determinePipelineStageFlags(VkAccessFlags accessFlags, Fox::EQueueType queueType switch (queueType) { - case Fox::EQueueType::GRAPHICS: + case Fox::EQueueType::QUEUE_GRAPHICS: { if ((accessFlags & (VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT)) != 0) flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT; @@ -672,7 +672,7 @@ determinePipelineStageFlags(VkAccessFlags accessFlags, Fox::EQueueType queueType #endif break; } - case Fox::EQueueType::COMPUTE: + case Fox::EQueueType::QUEUE_COMPUTE: { if ((accessFlags & (VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT)) != 0 || (accessFlags & VK_ACCESS_INPUT_ATTACHMENT_READ_BIT) != 0 || (accessFlags & (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT)) != 0 || @@ -684,7 +684,7 @@ determinePipelineStageFlags(VkAccessFlags accessFlags, Fox::EQueueType queueType break; } - case Fox::EQueueType::TRANSFER: + case Fox::EQueueType::QUEUE_TRANSFER: return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; default: break; @@ -854,4 +854,102 @@ convertResourceStateToImageLayout(Fox::EResourceState state, bool isDepth) return VK_IMAGE_LAYOUT_UNDEFINED; } +inline VkFlags +convertQueueTypeToVkFlags(uint32_t queueTypeFlag) +{ + using namespace Fox; + uint32_t vkFlags{}; + if (queueTypeFlag & EQueueType::QUEUE_GRAPHICS) + { + vkFlags |= VK_QUEUE_GRAPHICS_BIT; + } + if (queueTypeFlag & EQueueType::QUEUE_COMPUTE) + { + vkFlags |= VK_QUEUE_COMPUTE_BIT; + } + if (queueTypeFlag & EQueueType::QUEUE_TRANSFER) + { + vkFlags |= VK_QUEUE_TRANSFER_BIT; + } + + return vkFlags; +} + +/** + * @brief Return a graphics flagged queue if requestedFlags is only graphics. If requested flags is only transfer or only compute it returns a dedicated queue with that flag only if available on + * hardware otherwise will return a non dedicated queue with also other flags. If no dedicated queue is found it will return the first queue that supports the requested flags; + * @param device The vulkan device + * @param outFamilyIndex out the family index found + * @param outQueueIndex out the queue index to use + * @param requestedFlags the queue flags requested + * @param queueFamilyPropertiesPtr a pointer to an array of VkQueueFamilyProperties + * @param queueFamilyPropertiesCount number of elements in queueFamilyPropertiesPtr + * @param queueFamilyIndexCreatedCount Array of int32 to count how many queues are used for each family. Length must be at least queueFamilyPropertiesCount + * @return The queue family index the has at least the requestedFlags. + */ +inline bool +findQueueWithFlags(uint32_t* outFamilyIndex, +uint32_t* outQueueIndex, +VkFlags requestedFlags, +const VkQueueFamilyProperties* const queueFamilyPropertiesPtr, +uint32_t queueFamilyPropertiesCount, +uint32_t* queueFamilyIndexCreatedCount) +{ + using namespace Fox; + + bool found{ false }; + *outFamilyIndex = 0; + *outQueueIndex = 0; + + for (uint32_t i = 0; i < queueFamilyPropertiesCount; i++) + { + const VkQueueFamilyProperties* const queueFamily = queueFamilyPropertiesPtr + i; + const bool isGraphics = (queueFamily->queueFlags & VK_QUEUE_GRAPHICS_BIT) ? true : false; + // If has the required flags but is also graphics and has unused queues + if (requestedFlags & VK_QUEUE_GRAPHICS_BIT && isGraphics) + { + found = true; + *outFamilyIndex = i; + // User can query as many graphics queue as it can, we will return always the same since there is no benefit of using multiple ones + break; + } + // if requested is specialized queue with only the flag requested + if (queueFamily->queueFlags & requestedFlags && (queueFamily->queueFlags & ~requestedFlags) == 0 && queueFamilyIndexCreatedCount[i] < queueFamily->queueCount) + { + found = true; + *outFamilyIndex = i; + *outQueueIndex = queueFamilyIndexCreatedCount[i]++; + + break; + } + uint32_t orRequestedFlags = (queueFamily->queueFlags & requestedFlags); + // Should return a queue with requestedFlag but is not general purpose nor specialized + if (queueFamily->queueFlags & orRequestedFlags && !isGraphics && queueFamilyIndexCreatedCount[i] < queueFamily->queueCount) + { + found = true; + *outFamilyIndex = i; + *outQueueIndex = queueFamilyIndexCreatedCount[i]++; + break; + } + } + + // Find a any queue with the requested queueTypeFlags + if (!found) + { + for (uint32_t i = 0; i < queueFamilyPropertiesCount; i++) + { + const VkQueueFamilyProperties* const queueFamily = queueFamilyPropertiesPtr + i; + if (queueFamily->queueFlags & requestedFlags) + { + found = true; + *outFamilyIndex = i; + break; + } + } + } + + check(found == true); + return found; +} + } \ No newline at end of file diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index b166452..350e367 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -193,7 +193,7 @@ VulkanContext::VulkanContext(const DContextConfig* const config) : _warningOutpu _initializeDebugger(); _initializeVersion(); _initializeDevice(); - _initializeStagingBuffer(config->stagingBufferSize); + //_initializeStagingBuffer(config->stagingBufferSize); // Initialize per frame pipeline layout map to descriptor pool manager _pipelineLayoutToDescriptorPool.resize(NUM_OF_FRAMES_IN_FLIGHT); @@ -206,7 +206,9 @@ VulkanContext::VulkanContext(const DContextConfig* const config) : _warningOutpu _emptySampler.Sampler = Device.CreateSampler(VK_FILTER_NEAREST, VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, 0, 1, VK_SAMPLER_MIPMAP_MODE_NEAREST, false, 0.f); { // Transition to attachment optimal - const auto pool = CreateCommandPool(); + const auto graphicsQueue = FindQueue(EQueueType::QUEUE_GRAPHICS); + + const auto pool = CreateCommandPool(graphicsQueue); const auto cmd = CreateCommandBuffer(pool); BeginCommandBuffer(cmd); TextureBarrier barrier; @@ -222,6 +224,8 @@ VulkanContext::VulkanContext(const DContextConfig* const config) : _warningOutpu DestroyFence(fence); DestroyCommandBuffer(cmd); DestroyCommandPool(pool); + + // DestroyQueue(graphicsQueue); } } @@ -367,6 +371,10 @@ VulkanContext::_initializeDevice() // replacing global function pointers with functions retrieved with vkGetDeviceProcAddr volkLoadDevice(Device.Device); + + // track count of queue instantiated from each family + _queueFamilyIndexCreatedCount.resize(Device.QueueFamilies.size()); + std::fill(_queueFamilyIndexCreatedCount.begin(), _queueFamilyIndexCreatedCount.end(), 0); } void @@ -399,6 +407,10 @@ VulkanContext::~VulkanContext() fbo.Id = FREE; } + Device.DestroyBuffer(_emptyUbo.Buffer); + DestroyImage(_emptyImageId); + Device.DestroySampler(_emptySampler.Sampler); + #if _DEBUG const auto validSwapchainsCount = std::count_if(_swapchains.begin(), _swapchains.end(), [](const DSwapchainVulkan& swapchain) { return IsValidId(swapchain.Id); }); check(validSwapchainsCount == 0); @@ -415,7 +427,7 @@ VulkanContext::~VulkanContext() // Destroy all descriptor pools managers _pipelineLayoutToDescriptorPool.clear(); - _deinitializeStagingBuffer(); + //_deinitializeStagingBuffer(); FlushDeletedBuffers(); @@ -680,6 +692,89 @@ VulkanContext::DestroySwapchain(SwapchainId swapchainId) swapchain.Id = FREE; } +uint32_t +VulkanContext::FindQueue(uint32_t queueTypeFlag) +{ + bool found{ false }; + uint32_t familyIndex{}; + uint32_t queueIndex{}; + + uint32_t vkFlags{}; + if (queueTypeFlag & EQueueType::QUEUE_GRAPHICS) + { + vkFlags |= VK_QUEUE_GRAPHICS_BIT; + } + if (queueTypeFlag & EQueueType::QUEUE_COMPUTE) + { + vkFlags |= VK_QUEUE_COMPUTE_BIT; + } + if (queueTypeFlag & EQueueType::QUEUE_TRANSFER) + { + vkFlags |= VK_QUEUE_TRANSFER_BIT; + } + + for (uint32_t i = 0; i < Device.QueueFamilies.size(); i++) + { + VkQueueFamilyProperties& queueFamily = Device.QueueFamilies[i]; + const bool isGraphics = (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) ? true : false; + // If has the required flags but is also graphics and has unused queues + if (vkFlags & VK_QUEUE_GRAPHICS_BIT && isGraphics) + { + found = true; + familyIndex = i; + // User can query as many graphics queue as it can, we will return always the same since there is no benefit of using multiple ones + break; + } + // if requested is specialized queue with only the flag requested + if (queueFamily.queueFlags & vkFlags && (queueFamily.queueFlags & ~vkFlags) == 0 && _queueFamilyIndexCreatedCount[i] < queueFamily.queueCount) + { + found = true; + familyIndex = i; + queueIndex = _queueFamilyIndexCreatedCount[i]++; + + break; + } + uint32_t orRequestedFlags = (queueFamily.queueFlags & vkFlags); + ; + if (queueFamily.queueFlags & orRequestedFlags && (queueFamily.queueFlags - orRequestedFlags) < UINT32_MAX == 0 && _queueFamilyIndexCreatedCount[i] < queueFamily.queueCount) + { + found = true; + familyIndex = i; + queueIndex = _queueFamilyIndexCreatedCount[i]++; + break; + } + } + + // Find a queue with the requested queueTypeFlags + if (!found) + { + for (uint32_t i = 0; i < Device.QueueFamilies.size(); i++) + { + VkQueueFamilyProperties& queueFamily = Device.QueueFamilies[i]; + if (queueFamily.queueFlags & vkFlags) + { + found = true; + familyIndex = i; + queueIndex = _queueFamilyIndexCreatedCount[i]++; + break; + } + } + } + + check(found == true); + { + const auto index = AllocResource(_queues); + auto& queueRef = _queues.at(index); + queueRef.QueueFamilyIndex = familyIndex; + vkGetDeviceQueue(Device.Device, familyIndex, queueIndex, &queueRef.QueuePtr); + + return *ResourceId(EResourceType::QUEUE, queueRef.Id, index); + } + + throw std::runtime_error("No vulkan queue available!"); + return 0; +} + BufferId VulkanContext::CreateBuffer(uint32_t size, EResourceType type, EMemoryUsage usage) { @@ -1444,12 +1539,17 @@ VulkanContext::_destroyFramebuffer(uint32_t framebufferId) } uint32_t -VulkanContext::CreateCommandPool() +VulkanContext::CreateCommandPool(uint32_t queueId) { const auto index = AllocResource(_commandPools); auto& commandPoolRef = _commandPools.at(index); - commandPoolRef.Pool = Device.CreateCommandPool2(Device.GetQueueFamilyIndex()); + commandPoolRef.Pool = Device.CreateCommandPool2(Device.GraphicsQueueInfo.FamilyIndex); + + const auto queueRef = GetResource(_queues, queueId); + commandPoolRef.QueueFamilyIndex = queueRef.QueueFamilyIndex; + + // commandPoolRef.Type = queueType; return *ResourceId(EResourceType::COMMAND_POOL, commandPoolRef.Id, index); } @@ -2199,8 +2299,8 @@ RenderTargetBarrier* p_rt_barriers) } } - VkPipelineStageFlags srcStageMask = VkUtils::determinePipelineStageFlags(srcAccessFlags, EQueueType::GRAPHICS); - VkPipelineStageFlags dstStageMask = VkUtils::determinePipelineStageFlags(dstAccessFlags, EQueueType::GRAPHICS); + VkPipelineStageFlags srcStageMask = VkUtils::determinePipelineStageFlags(srcAccessFlags, EQueueType::QUEUE_GRAPHICS); + VkPipelineStageFlags dstStageMask = VkUtils::determinePipelineStageFlags(dstAccessFlags, EQueueType::QUEUE_GRAPHICS); { auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); diff --git a/src/backend/vulkan/VulkanContext.h b/src/backend/vulkan/VulkanContext.h index 401458d..00cbf90 100644 --- a/src/backend/vulkan/VulkanContext.h +++ b/src/backend/vulkan/VulkanContext.h @@ -85,11 +85,15 @@ struct DPipelineVulkan : public DResource struct DCommandPoolVulkan : public DResource { VkCommandPool Pool{}; + EQueueType Type; + uint32_t QueueFamilyIndex{}; }; struct DCommandBufferVulkan : public DResource { VkCommandBuffer Cmd{}; + EQueueType Type; + uint32_t QueueFamilyIndex{}; bool IsRecording{}; VkRenderPass ActiveRenderPass{}; }; @@ -143,6 +147,13 @@ struct DSamplerVulkan : public DResource VkSampler Sampler{}; }; +struct DQueueVulkan : public DResource +{ + // RIVulkanQueue Queue{}; + uint32_t QueueFamilyIndex{}; + VkQueue QueuePtr{}; +}; + class VulkanContext final : public IContext { inline static constexpr uint32_t NUM_OF_FRAMES_IN_FLIGHT{ 2 }; @@ -156,6 +167,8 @@ class VulkanContext final : public IContext bool SwapchainAcquireNextImageIndex(SwapchainId swapchainId, uint64_t timeoutNanoseconds, uint32_t sempahoreid, uint32_t* outImageIndex) override; void DestroySwapchain(SwapchainId swapchainId) override; + uint32_t FindQueue(uint32_t queueTypeFlag) override; + BufferId CreateBuffer(uint32_t size, EResourceType type, EMemoryUsage usage) override; void* BeginMapBuffer(BufferId buffer) override; void EndMapBuffer(BufferId buffer) override; @@ -176,7 +189,7 @@ class VulkanContext final : public IContext void DestroyDescriptorSet(uint32_t descriptorSetId) override; void UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t setIndex, uint32_t paramCount, DescriptorData* params) override; - uint32_t CreateCommandPool() override; + uint32_t CreateCommandPool(uint32_t queueId) override; void DestroyCommandPool(uint32_t commandPoolId) override; void ResetCommandPool(uint32_t commandPoolId) override; @@ -263,7 +276,9 @@ class VulkanContext final : public IContext std::array _renderTargets; std::array _rootSignatures; std::array _descriptorSets; + std::array _queues; std::unordered_set _renderPasses; + std::vector _queueFamilyIndexCreatedCount; using DeleteFn = std::function; using FramesWaitToDeletionList = std::pair>; diff --git a/src/backend/vulkan/VulkanDevice.cpp b/src/backend/vulkan/VulkanDevice.cpp index 7f1e583..acd0c0d 100644 --- a/src/backend/vulkan/VulkanDevice.cpp +++ b/src/backend/vulkan/VulkanDevice.cpp @@ -40,30 +40,81 @@ std::vector validationLayers) PhysicalDevice = hardwareDevice; - _queueFamilyIndex = _queryGraphicsAndTransferQueueIndex(); - // Get it's physical properties vkGetPhysicalDeviceProperties(PhysicalDevice, &DeviceProperties); // It's memory properties vkGetPhysicalDeviceMemoryProperties(PhysicalDevice, &DeviceMemory); - const float queuePriority = 1.f; + std::array queuePriorities; + std::fill(queuePriorities.begin(), queuePriorities.end(), 1.f); + + uint32_t queueFamiliesCount{}; + vkGetPhysicalDeviceQueueFamilyProperties(PhysicalDevice, &queueFamiliesCount, NULL); + QueueFamilies.resize(queueFamiliesCount); + vkGetPhysicalDeviceQueueFamilyProperties(PhysicalDevice, &queueFamiliesCount, QueueFamilies.data()); + + // Find graphics queue + for (uint32_t i = 0; i < queueFamiliesCount; i++) + { + VkQueueFamilyProperties* queue = &QueueFamilies[i]; + if (queue->queueFlags & VK_QUEUE_GRAPHICS_BIT) + { + GraphicsQueueInfo.Flags = queue->queueFlags; + GraphicsQueueInfo.FamilyIndex = i; + if (queue->queueFlags & VK_QUEUE_TRANSFER_BIT) + { + TransferQueueInfo = GraphicsQueueInfo; + } + break; + } + } + // Find transfer only queue + for (uint32_t i = 0; i < queueFamiliesCount; i++) + { + VkQueueFamilyProperties* queue = &QueueFamilies[i]; + if (queue->queueFlags & VK_QUEUE_TRANSFER_BIT && (queue->queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0) + { + TransferQueueInfo.FamilyIndex = i; + break; + } + } + + if (GraphicsQueueInfo.FamilyIndex < 0) + { + throw std::runtime_error("No vulkan graphics queue available!"); + } - VkDeviceQueueCreateInfo queueCreateInfo{}; - queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queueCreateInfo.queueFamilyIndex = _queueFamilyIndex; - queueCreateInfo.queueCount = 1; - queueCreateInfo.flags = 0; - queueCreateInfo.pNext = NULL; - queueCreateInfo.pQueuePriorities = &queuePriority; + // Create all queues up front + std::vector queueCreateInfos; + for (uint32_t i = 0; i < queueFamiliesCount; i++) + { + VkDeviceQueueCreateInfo queueCreateInfo{}; + queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfo.queueFamilyIndex = i; + queueCreateInfo.queueCount = QueueFamilies[i].queueCount; + queueCreateInfo.flags = 0; + queueCreateInfo.pNext = NULL; + queueCreateInfo.pQueuePriorities = queuePriorities.data(); // must be a valid pointer to an array of queueCount float values + queueCreateInfos.emplace_back(std::move(queueCreateInfo)); + } + // if (GraphicsQueueInfo.FamilyIndex != TransferQueueInfo.FamilyIndex) + // { + // VkDeviceQueueCreateInfo queueCreateInfo{}; + // queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + // queueCreateInfo.queueFamilyIndex = TransferQueueInfo.FamilyIndex; + // queueCreateInfo.queueCount = 1; + // queueCreateInfo.flags = 0; + // queueCreateInfo.pNext = NULL; + // queueCreateInfo.pQueuePriorities = &queuePriority; + // queueCreateInfos.emplace_back(std::move(queueCreateInfo)); + // } VkDeviceCreateInfo deviceInfo{}; deviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; deviceInfo.pNext = pNext; - deviceInfo.enabledExtensionCount = 0; - deviceInfo.pQueueCreateInfos = &queueCreateInfo; - deviceInfo.queueCreateInfoCount = 1; + deviceInfo.pQueueCreateInfos = queueCreateInfos.data(); + deviceInfo.queueCreateInfoCount = (uint32_t)queueCreateInfos.size(); deviceInfo.pEnabledFeatures = pNext ? nullptr : (optDeviceFeatures ? optDeviceFeatures : nullptr); deviceInfo.enabledExtensionCount = (uint32_t)extensions.size(); deviceInfo.ppEnabledExtensionNames = extensions.data(); @@ -129,7 +180,8 @@ std::vector validationLayers) } } - vkGetDeviceQueue(Device, _queueFamilyIndex, 0, &MainQueue); + vkGetDeviceQueue(Device, GraphicsQueueInfo.FamilyIndex, 0, &MainQueue); + vkGetDeviceQueue(Device, TransferQueueInfo.FamilyIndex, 0, &TransferQueue); return VK_SUCCESS; } diff --git a/src/backend/vulkan/VulkanDevice.h b/src/backend/vulkan/VulkanDevice.h index 89214eb..07dc94d 100644 --- a/src/backend/vulkan/VulkanDevice.h +++ b/src/backend/vulkan/VulkanDevice.h @@ -17,6 +17,13 @@ namespace Fox { +struct RIVulkanQueue +{ + uint32_t Flags{}; + uint32_t FamilyIndex{}; + uint32_t QueueIndex{}; +}; + class RIVulkanDevice { public: @@ -29,7 +36,9 @@ class RIVulkanDevice std::vector validationLayers); void Deinit(); - inline int32_t GetQueueFamilyIndex() const { return _queueFamilyIndex; }; + RIVulkanQueue GraphicsQueueInfo{}; + RIVulkanQueue TransferQueueInfo{}; + std::vector QueueFamilies; inline int32_t GetMaxImageAllocations() const { return 4096; } @@ -39,8 +48,10 @@ class RIVulkanDevice VkPhysicalDeviceProperties DeviceProperties{}; /*Properties of the physical device*/ VkPhysicalDeviceMemoryProperties DeviceMemory{}; /*Properties about the physical device memory*/ VkQueue MainQueue{}; /* Graphics and Transfer queue*/ + VkQueue TransferQueue{}; /* Transfer queue*/ + private: - uint32_t _queueFamilyIndex; + uint32_t _queryGraphicsAndTransferQueueIndex() const; }; diff --git a/src/backend/vulkan/VulkanDevice12.cpp b/src/backend/vulkan/VulkanDevice12.cpp index 8b02611..4e25327 100644 --- a/src/backend/vulkan/VulkanDevice12.cpp +++ b/src/backend/vulkan/VulkanDevice12.cpp @@ -58,7 +58,7 @@ RIVulkanDevice12::CreateCommandPool() VkCommandPoolCreateInfo poolInfo{}; poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; /*Allow command buffers to be rerecorded individually, without this flag they all have to be reset together*/ - poolInfo.queueFamilyIndex = GetQueueFamilyIndex(); + poolInfo.queueFamilyIndex = GraphicsQueueInfo.FamilyIndex; const VkResult result = vkCreateCommandPool(Device, &poolInfo, nullptr, &commandPool); if (VKFAILED(result)) diff --git a/src/backend/vulkan/VulkanDevice2.cpp b/src/backend/vulkan/VulkanDevice2.cpp index e377795..599e726 100644 --- a/src/backend/vulkan/VulkanDevice2.cpp +++ b/src/backend/vulkan/VulkanDevice2.cpp @@ -17,7 +17,7 @@ RIVulkanDevice2::SurfaceSupportPresentationOnCurrentQueueFamily(VkSurfaceKHR sur { uint32_t supportPresentation = VK_FALSE; // To determine whether a queue family of a physical device supports presentation to a given surface - const VkResult result = vkGetPhysicalDeviceSurfaceSupportKHR(PhysicalDevice, GetQueueFamilyIndex(), surface, &supportPresentation); + const VkResult result = vkGetPhysicalDeviceSurfaceSupportKHR(PhysicalDevice, GraphicsQueueInfo.FamilyIndex, surface, &supportPresentation); if (VKFAILED(result)) { throw std::runtime_error(VkUtils::VkErrorString(result)); @@ -93,7 +93,7 @@ const VkSurfaceCapabilitiesKHR& capabilities, VkSwapchainKHR* outSwapchain, VkSwapchainKHR oldSwapchain) { - uint32_t queueFamilyIndices[] = { (uint32_t)GetQueueFamilyIndex() }; + uint32_t queueFamilyIndices[] = { (uint32_t)GraphicsQueueInfo.FamilyIndex }; critical(capabilities.minImageCount >= MAX_IMAGE_COUNT); VkSwapchainCreateInfoKHR swapchainInfo = {}; diff --git a/tests/integration/vulkan/ImageUpload.test.cpp b/tests/integration/vulkan/ImageUpload.test.cpp index dd015bc..2e7bf46 100644 --- a/tests/integration/vulkan/ImageUpload.test.cpp +++ b/tests/integration/vulkan/ImageUpload.test.cpp @@ -36,26 +36,41 @@ TEST_F(WindowFixture, ShouldCorrectlyUploadImage) Fox::IContext* context = Fox::CreateVulkanContext(&config); ASSERT_NE(context, nullptr); - Fox::DImage img = context->CreateImage(Fox::EFormat::R8G8B8A8_UNORM, 2, 2, 1); + uint32_t img = context->CreateImage(Fox::EFormat::R8G8B8A8_UNORM, 2, 2, 1); - ASSERT_NE(img, nullptr); + { + uint32_t stagingBuf = context->CreateBuffer(data.size(), Fox::EResourceType::TRANSFER, Fox::EMemoryUsage::RESOURCE_MEMORY_USAGE_CPU_TO_GPU); + const auto transferQueue = context->FindQueue(Fox::EQueueType::QUEUE_TRANSFER); - Fox::CopyDataCommand cmd; - cmd.CopyImageMipMap(img, 0, (void*)data.data(), 2, 2, 0, data.size()); + const auto pool = context->CreateCommandPool(transferQueue); + const auto cmd = context->CreateCommandBuffer(pool); + context->BeginCommandBuffer(cmd); + Fox::TextureBarrier barrier; + barrier.ImageId = img; + barrier.CurrentState = Fox::EResourceState::UNDEFINED; + barrier.NewState = Fox::EResourceState::COPY_DEST; + context->ResourceBarrier(cmd, 0, nullptr, 1, &barrier, 0, nullptr); + context->CopyImage(cmd, img, 2, 2, 0, stagingBuf, 0); + context->EndCommandBuffer(cmd); - context->SubmitCopy(std::move(cmd)); + const auto fence = context->CreateFence(false); + context->QueueSubmit({}, {}, { cmd }, fence); + context->WaitForFence(fence, 0xFFFFFFFF); + context->DestroyFence(fence); + context->DestroyCommandBuffer(cmd); + context->DestroyCommandPool(pool); + context->DestroyBuffer(stagingBuf); + } - context->AdvanceFrame(); + ASSERT_NE(img, 0); - { - Fox::VulkanContext* vkContext = static_cast(context); - vkContext->WaitDeviceIdle(); // wait copy operations to finish + //{ + // Fox::VulkanContext* vkContext = static_cast(context); + // std::array expected; + // ExtractImage(vkContext, img, 2, 2, 1, VK_FORMAT_R8G8B8A8_UNORM, data.size(), (void*)expected.data()); - std::array expected; - ExtractImage(vkContext, img, 2, 2, 1, VK_FORMAT_R8G8B8A8_UNORM, data.size(), (void*)expected.data()); - - EXPECT_EQ(data, expected); - } + // EXPECT_EQ(data, expected); + //} context->DestroyImage(img); diff --git a/tests/integration/vulkan/SwapchainCreationDestruction.test.cpp b/tests/integration/vulkan/SwapchainCreationDestruction.test.cpp index 4bd5e4e..8d275be 100644 --- a/tests/integration/vulkan/SwapchainCreationDestruction.test.cpp +++ b/tests/integration/vulkan/SwapchainCreationDestruction.test.cpp @@ -20,11 +20,11 @@ TEST_F(WindowFixture, ShouldCreateAndDestroySwapchain) windowData._window; #endif - Fox::DSwapchain swapchain; - auto presentMode = Fox::EPresentMode::IMMEDIATE_KHR; - auto format = Fox::EFormat::B8G8R8A8_UNORM; - ASSERT_EQ(context->CreateSwapchain(&windowData, presentMode, format, &swapchain), true); - ASSERT_NE(swapchain, nullptr); + uint32_t swapchain{}; + auto presentMode = Fox::EPresentMode::IMMEDIATE_KHR; + auto format = Fox::EFormat::B8G8R8A8_UNORM; + swapchain = context->CreateSwapchain(&windowData, presentMode, format); + ASSERT_NE(swapchain, 0); context->DestroySwapchain(swapchain); diff --git a/tests/integration/vulkan/UniformBufferUpload.test.cpp b/tests/integration/vulkan/UniformBufferUpload.test.cpp index 597d722..5e61bfa 100644 --- a/tests/integration/vulkan/UniformBufferUpload.test.cpp +++ b/tests/integration/vulkan/UniformBufferUpload.test.cpp @@ -10,40 +10,40 @@ #include -TEST_F(WindowFixture, ShouldCorrectlyUploadUniformBuffer) -{ - constexpr std::array data{ -1, -1, 3, -1, -1, 3 }; - constexpr size_t bufSize = sizeof(float) * data.size(); - - Fox::DContextConfig config; - config.warningFunction = &WarningAssert; - config.stagingBufferSize = bufSize; - - Fox::IContext* context = Fox::CreateVulkanContext(&config); - ASSERT_NE(context, nullptr); - - Fox::DBuffer buf = context->CreateUniformBuffer(bufSize); - - ASSERT_NE(buf, nullptr); - - Fox::CopyDataCommand cmd; - cmd.CopyUniformBuffer(buf, (void*)data.data(), bufSize); - - context->SubmitCopy(std::move(cmd)); - - context->AdvanceFrame(); - - { - Fox::VulkanContext* vkContext = static_cast(context); - vkContext->WaitDeviceIdle(); // wait copy operations to finish - - std::array expected; - ExtractBuffer(vkContext, buf, bufSize, expected.data()); - - EXPECT_EQ(data, expected); - } - - context->DestroyUniformBuffer(buf); - - delete context; -} +//TEST_F(WindowFixture, ShouldCorrectlyUploadUniformBuffer) +//{ +// constexpr std::array data{ -1, -1, 3, -1, -1, 3 }; +// constexpr size_t bufSize = sizeof(float) * data.size(); +// +// Fox::DContextConfig config; +// config.warningFunction = &WarningAssert; +// config.stagingBufferSize = bufSize; +// +// Fox::IContext* context = Fox::CreateVulkanContext(&config); +// ASSERT_NE(context, nullptr); +// +// Fox::DBuffer buf = context->CreateUniformBuffer(bufSize); +// +// ASSERT_NE(buf, nullptr); +// +// Fox::CopyDataCommand cmd; +// cmd.CopyUniformBuffer(buf, (void*)data.data(), bufSize); +// +// context->SubmitCopy(std::move(cmd)); +// +// context->AdvanceFrame(); +// +// { +// Fox::VulkanContext* vkContext = static_cast(context); +// vkContext->WaitDeviceIdle(); // wait copy operations to finish +// +// std::array expected; +// ExtractBuffer(vkContext, buf, bufSize, expected.data()); +// +// EXPECT_EQ(data, expected); +// } +// +// context->DestroyUniformBuffer(buf); +// +// delete context; +//} diff --git a/tests/integration/vulkan/VertexBufferCreationDestruction.test.cpp b/tests/integration/vulkan/VertexBufferCreationDestruction.test.cpp index 6a9e322..878baba 100644 --- a/tests/integration/vulkan/VertexBufferCreationDestruction.test.cpp +++ b/tests/integration/vulkan/VertexBufferCreationDestruction.test.cpp @@ -2,21 +2,21 @@ #include "backend/vulkan/VulkanContextFactory.h" -TEST_F(WindowFixture, ShouldCreateAndDestroyAVertexBuffer) -{ - - Fox::DContextConfig config; - config.warningFunction = &WarningAssert; - - Fox::IContext* context = Fox::CreateVulkanContext(&config); - ASSERT_NE(context, nullptr); - - Fox::DBuffer buf = context->CreateVertexBuffer(10 * 1024 * 1024); // 10mb - - ASSERT_NE(buf, nullptr); - EXPECT_EQ(buf->Type, Fox::EBufferType::VERTEX_INDEX_BUFFER); - - context->DestroyVertexBuffer(buf); - - delete context; -} +//TEST_F(WindowFixture, ShouldCreateAndDestroyAVertexBuffer) +//{ +// +// Fox::DContextConfig config; +// config.warningFunction = &WarningAssert; +// +// Fox::IContext* context = Fox::CreateVulkanContext(&config); +// ASSERT_NE(context, nullptr); +// +// Fox::DBuffer buf = context->CreateVertexBuffer(10 * 1024 * 1024); // 10mb +// +// ASSERT_NE(buf, nullptr); +// EXPECT_EQ(buf->Type, Fox::EBufferType::VERTEX_INDEX_BUFFER); +// +// context->DestroyVertexBuffer(buf); +// +// delete context; +//} diff --git a/tests/integration/vulkan/VertexBufferUpload.test.cpp b/tests/integration/vulkan/VertexBufferUpload.test.cpp index 9e5a5c3..34bd23d 100644 --- a/tests/integration/vulkan/VertexBufferUpload.test.cpp +++ b/tests/integration/vulkan/VertexBufferUpload.test.cpp @@ -9,107 +9,107 @@ #include -TEST_F(WindowFixture, ShouldCorrectlyUploadVertexBuffer) -{ - constexpr std::array ndcTriangle{ -1, -1, 3, -1, -1, 3 }; - constexpr size_t bufSize = sizeof(float) * ndcTriangle.size(); - - Fox::DContextConfig config; - config.warningFunction = &WarningAssert; - config.stagingBufferSize = bufSize; - - Fox::IContext* context = Fox::CreateVulkanContext(&config); - ASSERT_NE(context, nullptr); - - Fox::DBuffer buf = context->CreateVertexBuffer(bufSize); - - ASSERT_NE(buf, nullptr); - - Fox::CopyDataCommand cmd; - cmd.CopyVertex(buf, 0, (void*)ndcTriangle.data(), bufSize); - - context->SubmitCopy(std::move(cmd)); - - context->AdvanceFrame(); - - { - Fox::VulkanContext* vkContext = static_cast(context); - vkContext->WaitDeviceIdle(); // wait copy operations to finish - - std::array expected; - ExtractBuffer(vkContext, buf, bufSize, expected.data()); - - EXPECT_EQ(ndcTriangle, expected); - } - - context->DestroyVertexBuffer(buf); - - delete context; -} - -TEST_F(WindowFixture, ShouldCorrectlyUploadMultipleVertexBuffer) -{ - - constexpr std::array ndcTriangle{ -1, -1, 3, -1, -1, 3 }; - constexpr size_t triangleSize = sizeof(float) * ndcTriangle.size(); - - constexpr std::array data{ 1, 2, 3, 4, 5, 5, 6, 7, 8, 9 }; - constexpr size_t dataSize = sizeof(float) * data.size(); - - constexpr std::array data2{ 1, 2, 3, 4 }; - constexpr size_t data2Size = sizeof(float) * data2.size(); - - Fox::DContextConfig config; - config.warningFunction = &WarningAssert; - config.stagingBufferSize = triangleSize + dataSize + data2Size; - - Fox::IContext* context = Fox::CreateVulkanContext(&config); - ASSERT_NE(context, nullptr); - - Fox::DBuffer buf = context->CreateVertexBuffer(triangleSize); - ASSERT_NE(buf, nullptr); - Fox::CopyDataCommand cmd; - cmd.CopyVertex(buf, 0, (void*)ndcTriangle.data(), triangleSize); - context->SubmitCopy(std::move(cmd)); - - Fox::DBuffer buf1 = context->CreateVertexBuffer(dataSize); - ASSERT_NE(buf1, nullptr); - Fox::CopyDataCommand cmd1; - cmd1.CopyVertex(buf1, 0, (void*)data.data(), dataSize); - context->SubmitCopy(std::move(cmd1)); - - Fox::DBuffer buf2 = context->CreateVertexBuffer(data2Size); - ASSERT_NE(buf2, nullptr); - Fox::CopyDataCommand cmd2; - cmd2.CopyVertex(buf2, 0, (void*)data2.data(), data2Size); - context->SubmitCopy(std::move(cmd2)); - - context->AdvanceFrame(); - - { - Fox::VulkanContext* vkContext = static_cast(context); - vkContext->WaitDeviceIdle(); // wait copy operations to finish - - { - std::array output; - ExtractBuffer(vkContext, buf, triangleSize, output.data()); - EXPECT_EQ(ndcTriangle, output); - } - { - std::array output; - ExtractBuffer(vkContext, buf1, dataSize, output.data()); - EXPECT_EQ(data, output); - } - { - std::array output; - ExtractBuffer(vkContext, buf2, data2Size, output.data()); - EXPECT_EQ(data2, output); - } - } - - context->DestroyVertexBuffer(buf); - context->DestroyVertexBuffer(buf1); - context->DestroyVertexBuffer(buf2); - - delete context; -} +//TEST_F(WindowFixture, ShouldCorrectlyUploadVertexBuffer) +//{ +// constexpr std::array ndcTriangle{ -1, -1, 3, -1, -1, 3 }; +// constexpr size_t bufSize = sizeof(float) * ndcTriangle.size(); +// +// Fox::DContextConfig config; +// config.warningFunction = &WarningAssert; +// config.stagingBufferSize = bufSize; +// +// Fox::IContext* context = Fox::CreateVulkanContext(&config); +// ASSERT_NE(context, nullptr); +// +// Fox::DBuffer buf = context->CreateVertexBuffer(bufSize); +// +// ASSERT_NE(buf, nullptr); +// +// Fox::CopyDataCommand cmd; +// cmd.CopyVertex(buf, 0, (void*)ndcTriangle.data(), bufSize); +// +// context->SubmitCopy(std::move(cmd)); +// +// context->AdvanceFrame(); +// +// { +// Fox::VulkanContext* vkContext = static_cast(context); +// vkContext->WaitDeviceIdle(); // wait copy operations to finish +// +// std::array expected; +// ExtractBuffer(vkContext, buf, bufSize, expected.data()); +// +// EXPECT_EQ(ndcTriangle, expected); +// } +// +// context->DestroyVertexBuffer(buf); +// +// delete context; +//} +// +//TEST_F(WindowFixture, ShouldCorrectlyUploadMultipleVertexBuffer) +//{ +// +// constexpr std::array ndcTriangle{ -1, -1, 3, -1, -1, 3 }; +// constexpr size_t triangleSize = sizeof(float) * ndcTriangle.size(); +// +// constexpr std::array data{ 1, 2, 3, 4, 5, 5, 6, 7, 8, 9 }; +// constexpr size_t dataSize = sizeof(float) * data.size(); +// +// constexpr std::array data2{ 1, 2, 3, 4 }; +// constexpr size_t data2Size = sizeof(float) * data2.size(); +// +// Fox::DContextConfig config; +// config.warningFunction = &WarningAssert; +// config.stagingBufferSize = triangleSize + dataSize + data2Size; +// +// Fox::IContext* context = Fox::CreateVulkanContext(&config); +// ASSERT_NE(context, nullptr); +// +// Fox::DBuffer buf = context->CreateVertexBuffer(triangleSize); +// ASSERT_NE(buf, nullptr); +// Fox::CopyDataCommand cmd; +// cmd.CopyVertex(buf, 0, (void*)ndcTriangle.data(), triangleSize); +// context->SubmitCopy(std::move(cmd)); +// +// Fox::DBuffer buf1 = context->CreateVertexBuffer(dataSize); +// ASSERT_NE(buf1, nullptr); +// Fox::CopyDataCommand cmd1; +// cmd1.CopyVertex(buf1, 0, (void*)data.data(), dataSize); +// context->SubmitCopy(std::move(cmd1)); +// +// Fox::DBuffer buf2 = context->CreateVertexBuffer(data2Size); +// ASSERT_NE(buf2, nullptr); +// Fox::CopyDataCommand cmd2; +// cmd2.CopyVertex(buf2, 0, (void*)data2.data(), data2Size); +// context->SubmitCopy(std::move(cmd2)); +// +// context->AdvanceFrame(); +// +// { +// Fox::VulkanContext* vkContext = static_cast(context); +// vkContext->WaitDeviceIdle(); // wait copy operations to finish +// +// { +// std::array output; +// ExtractBuffer(vkContext, buf, triangleSize, output.data()); +// EXPECT_EQ(ndcTriangle, output); +// } +// { +// std::array output; +// ExtractBuffer(vkContext, buf1, dataSize, output.data()); +// EXPECT_EQ(data, output); +// } +// { +// std::array output; +// ExtractBuffer(vkContext, buf2, data2Size, output.data()); +// EXPECT_EQ(data2, output); +// } +// } +// +// context->DestroyVertexBuffer(buf); +// context->DestroyVertexBuffer(buf1); +// context->DestroyVertexBuffer(buf2); +// +// delete context; +//} diff --git a/tests/unit/vulkan/VkUtils.test.cpp b/tests/unit/vulkan/VkUtils.test.cpp index e5fa60e..c2ef113 100644 --- a/tests/unit/vulkan/VkUtils.test.cpp +++ b/tests/unit/vulkan/VkUtils.test.cpp @@ -37,4 +37,177 @@ TEST(UnitFilterExclusive, ShouldFilterAsExpected) const auto found = std::find_if(onlyIncluded.begin(), onlyIncluded.end(), [&source](const char* a) { return strcmp(a, source[2]) == 0; }); ASSERT_NE(found, onlyIncluded.end()); } -} \ No newline at end of file +} + +TEST(UnitConvertQueueTypeToVkFlags, ShouldConvertCorrectlyFlags) +{ + using namespace Fox; + + { + const VkFlags flag = convertQueueTypeToVkFlags(EQueueType::QUEUE_GRAPHICS); + ASSERT_TRUE(flag & VK_QUEUE_GRAPHICS_BIT && (~flag & VK_QUEUE_GRAPHICS_BIT) == 0); + } + { + const VkFlags flag = convertQueueTypeToVkFlags(EQueueType::QUEUE_COMPUTE); + ASSERT_TRUE(flag & VK_QUEUE_COMPUTE_BIT && (~flag & VK_QUEUE_COMPUTE_BIT) == 0); + } + { + const VkFlags flag = convertQueueTypeToVkFlags(EQueueType::QUEUE_TRANSFER); + ASSERT_TRUE(flag & VK_QUEUE_TRANSFER_BIT && (~flag & VK_QUEUE_TRANSFER_BIT) == 0); + } +} + +TEST(UnitFindQueueFromQueueFlags, ShouldReturnCorrectQueueFamilyAndIndex) +{ + using namespace Fox; + + { + // NVIDIA GeForce GTX 750 Ti GPU queue families + VkQueueFamilyProperties families[3]{}; + families[0].queueFlags = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT; + families[0].queueCount = 16; + + families[1].queueFlags = VK_QUEUE_TRANSFER_BIT | VK_QUEUE_SPARSE_BINDING_BIT; + families[1].queueCount = 1; + + families[2].queueFlags = VK_QUEUE_TRANSFER_BIT | VK_QUEUE_VIDEO_DECODE_BIT_KHR; + families[2].queueCount = 1; + + uint32_t queueIndexCreatedCount[3]{}; + { + uint32_t queueFamily{}; + uint32_t queueIndex{}; + const bool found = findQueueWithFlags(&queueFamily, &queueIndex, VK_QUEUE_GRAPHICS_BIT, families, sizeof(families) / sizeof(families[0]), queueIndexCreatedCount); + ASSERT_TRUE(found); + ASSERT_EQ(queueFamily, 0); + ASSERT_EQ(queueIndex, 0); + } + { + uint32_t queueFamily{}; + uint32_t queueIndex{}; + const bool found = findQueueWithFlags(&queueFamily, &queueIndex, VK_QUEUE_COMPUTE_BIT, families, sizeof(families) / sizeof(families[0]), queueIndexCreatedCount); + ASSERT_TRUE(found); + ASSERT_EQ(queueFamily, 0); + ASSERT_EQ(queueIndex, 0); + } + { + uint32_t queueFamily{}; + uint32_t queueIndex{}; + const bool found = findQueueWithFlags(&queueFamily, &queueIndex, VK_QUEUE_TRANSFER_BIT, families, sizeof(families) / sizeof(families[0]), queueIndexCreatedCount); + ASSERT_TRUE(found); + ASSERT_EQ(queueFamily, 1); + ASSERT_EQ(queueIndex, 0); + } + // Since previous call the queue index was taken now it should return second family that has transfer flag + { + uint32_t queueFamily{}; + uint32_t queueIndex{}; + const bool found = findQueueWithFlags(&queueFamily, &queueIndex, VK_QUEUE_TRANSFER_BIT, families, sizeof(families) / sizeof(families[0]), queueIndexCreatedCount); + ASSERT_TRUE(found); + ASSERT_EQ(queueFamily, 2); + ASSERT_EQ(queueIndex, 0); + } + // Since previous call the queue index was taken now it should return general purpose queue + { + uint32_t queueFamily{}; + uint32_t queueIndex{}; + const bool found = findQueueWithFlags(&queueFamily, &queueIndex, VK_QUEUE_TRANSFER_BIT, families, sizeof(families) / sizeof(families[0]), queueIndexCreatedCount); + ASSERT_TRUE(found); + ASSERT_EQ(queueFamily, 0); + ASSERT_EQ(queueIndex, 0); + } + } + + { + // NVIDIA GeForce GTX 1080 Ti GPU queue families + VkQueueFamilyProperties families[3]{}; + families[0].queueFlags = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT; + families[0].queueCount = 16; + + families[1].queueFlags = VK_QUEUE_TRANSFER_BIT; + families[1].queueCount = 2; + + families[2].queueFlags = VK_QUEUE_COMPUTE_BIT; + families[2].queueCount = 8; + + uint32_t queueIndexCreatedCount[3]{}; + { + uint32_t queueFamily{}; + uint32_t queueIndex{}; + const bool found = findQueueWithFlags(&queueFamily, &queueIndex, VK_QUEUE_GRAPHICS_BIT, families, sizeof(families) / sizeof(families[0]), queueIndexCreatedCount); + ASSERT_TRUE(found); + ASSERT_EQ(queueFamily, 0); + ASSERT_EQ(queueIndex, 0); + } + /*Should enumerate all queue indices*/ + for (uint32_t i = 0; i < families[2].queueCount; i++) + { + uint32_t queueFamily{}; + uint32_t queueIndex{}; + const bool found = findQueueWithFlags(&queueFamily, &queueIndex, VK_QUEUE_COMPUTE_BIT, families, sizeof(families) / sizeof(families[0]), queueIndexCreatedCount); + ASSERT_TRUE(found); + ASSERT_EQ(queueFamily, 2); + ASSERT_EQ(queueIndex, i); + } + /*Should enumerate all queue indices*/ + for (uint32_t i = 0; i < families[1].queueCount; i++) + { + uint32_t queueFamily{}; + uint32_t queueIndex{}; + const bool found = findQueueWithFlags(&queueFamily, &queueIndex, VK_QUEUE_TRANSFER_BIT, families, sizeof(families) / sizeof(families[0]), queueIndexCreatedCount); + ASSERT_TRUE(found); + ASSERT_EQ(queueFamily, 1); + ASSERT_EQ(queueIndex, i); + } + // Should return general purpose queue because we already queries all queues of this type + { + uint32_t queueFamily{}; + uint32_t queueIndex{}; + const bool found = findQueueWithFlags(&queueFamily, &queueIndex, VK_QUEUE_TRANSFER_BIT, families, sizeof(families) / sizeof(families[0]), queueIndexCreatedCount); + ASSERT_TRUE(found); + ASSERT_EQ(queueFamily, 0); + ASSERT_EQ(queueIndex, 0); + } + } + + { + // Intel(R) UHD Graphic GPU queue families + VkQueueFamilyProperties families[1]{}; + families[0].queueFlags = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT | VK_QUEUE_SPARSE_BINDING_BIT; + families[0].queueCount = 1; + + uint32_t queueIndexCreatedCount[1]{}; + { + uint32_t queueFamily{}; + uint32_t queueIndex{}; + const bool found = findQueueWithFlags(&queueFamily, &queueIndex, VK_QUEUE_GRAPHICS_BIT, families, 1, queueIndexCreatedCount); + ASSERT_TRUE(found); + ASSERT_EQ(queueFamily, 0); + ASSERT_EQ(queueIndex, 0); + } + { + uint32_t queueFamily{}; + uint32_t queueIndex{}; + const bool found = findQueueWithFlags(&queueFamily, &queueIndex, VK_QUEUE_COMPUTE_BIT, families, 1, queueIndexCreatedCount); + ASSERT_TRUE(found); + ASSERT_EQ(queueFamily, 0); + ASSERT_EQ(queueIndex, 0); + } + { + uint32_t queueFamily{}; + uint32_t queueIndex{}; + const bool found = findQueueWithFlags(&queueFamily, &queueIndex, VK_QUEUE_TRANSFER_BIT, families, 1, queueIndexCreatedCount); + ASSERT_TRUE(found); + ASSERT_EQ(queueFamily, 0); + ASSERT_EQ(queueIndex, 0); + } + { + uint32_t queueFamily{}; + uint32_t queueIndex{}; + const bool found = findQueueWithFlags(&queueFamily, &queueIndex, VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT, families, 1, queueIndexCreatedCount); + ASSERT_TRUE(found); + ASSERT_EQ(queueFamily, 0); + ASSERT_EQ(queueIndex, 0); + } + } +} diff --git a/tests/utilities/ExtractBuffer.h b/tests/utilities/ExtractBuffer.h index b205bd8..d13f0cf 100644 --- a/tests/utilities/ExtractBuffer.h +++ b/tests/utilities/ExtractBuffer.h @@ -5,29 +5,29 @@ #include "backend/vulkan/VulkanContextFactory.h" #include "backend/vulkan/VulkanDevice13.h" -static void -ExtractBuffer(Fox::VulkanContext* vkContext, Fox::DBuffer src, uint32_t bytes, void* outData) -{ - Fox::DBufferVulkan* vkSrcBuf = static_cast(src); - - Fox::RIVulkanDevice13& device = vkContext->GetDevice(); - auto outBuf = device.CreateBufferHostVisible(bytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT); - - auto cmdPool = device.CreateCommandPool(); - auto cmdBuffer = cmdPool->Allocate(); - Fox::CResourceTransfer transfer(cmdBuffer->Cmd); - transfer.CopyBuffer(vkSrcBuf->Buffer.Buffer, outBuf.Buffer, bytes, 0); - transfer.FinishCommandBuffer(); - - const std::vector cmds{ cmdBuffer }; - device.SubmitToMainQueue(cmds, {}, VK_NULL_HANDLE, VK_NULL_HANDLE); - vkContext->WaitDeviceIdle(); // wait copy operations to finish - - void* outputPtr = device.MapBuffer(outBuf); - memcpy(outData, outputPtr, bytes); - device.UnmapBuffer(outBuf); - - // cleanup - device.DestroyBuffer(outBuf); - device.DestroyCommandPool(cmdPool); -}; \ No newline at end of file +//static void +//ExtractBuffer(Fox::VulkanContext* vkContext, uint32_t src, uint32_t bytes, void* outData) +//{ +// Fox::DBufferVulkan* vkSrcBuf = static_cast(src); +// +// Fox::RIVulkanDevice13& device = vkContext->GetDevice(); +// auto outBuf = device.CreateBufferHostVisible(bytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT); +// +// auto cmdPool = device.CreateCommandPool(); +// auto cmdBuffer = cmdPool->Allocate(); +// Fox::CResourceTransfer transfer(cmdBuffer->Cmd); +// transfer.CopyBuffer(vkSrcBuf->Buffer.Buffer, outBuf.Buffer, bytes, 0); +// transfer.FinishCommandBuffer(); +// +// const std::vector cmds{ cmdBuffer }; +// device.SubmitToMainQueue(cmds, {}, VK_NULL_HANDLE, VK_NULL_HANDLE); +// vkContext->WaitDeviceIdle(); // wait copy operations to finish +// +// void* outputPtr = device.MapBuffer(outBuf); +// memcpy(outData, outputPtr, bytes); +// device.UnmapBuffer(outBuf); +// +// // cleanup +// device.DestroyBuffer(outBuf); +// device.DestroyCommandPool(cmdPool); +//}; \ No newline at end of file diff --git a/tests/utilities/ExtractImage.h b/tests/utilities/ExtractImage.h index bc11c29..0a360b0 100644 --- a/tests/utilities/ExtractImage.h +++ b/tests/utilities/ExtractImage.h @@ -5,32 +5,32 @@ #include "backend/vulkan/VulkanContextFactory.h" #include "backend/vulkan/VulkanDevice13.h" -static void -ExtractImage(Fox::VulkanContext* vkContext, Fox::DImage src, uint32_t width, uint32_t height, uint32_t mipLevels, VkFormat format, uint32_t bytes, void* outData) -{ - Fox::DImageVulkan* vkSrcImg = static_cast(src); - - Fox::RIVulkanDevice13& device = vkContext->GetDevice(); - - auto cmdPool = device.CreateCommandPool(); - auto cmdBuffer = cmdPool->Allocate(); - Fox::CResourceTransfer transfer(cmdBuffer->Cmd); - - auto outImg = device.CreateBufferHostVisible(16, VK_IMAGE_USAGE_TRANSFER_DST_BIT); - - transfer.CopyImageToBuffer(outImg.Buffer, vkSrcImg->Image.Image, { width, height }, 0); - - transfer.FinishCommandBuffer(); - - const std::vector cmds{ cmdBuffer }; - device.SubmitToMainQueue(cmds, {}, VK_NULL_HANDLE, VK_NULL_HANDLE); - vkContext->WaitDeviceIdle(); // wait copy operations to finish - - void* outputPtr = device.MapBuffer(outImg); - memcpy(outData, outputPtr, bytes); - device.UnmapBuffer(outImg); - - //// cleanup - device.DestroyBuffer(outImg); - device.DestroyCommandPool(cmdPool); -}; \ No newline at end of file +//static void +//ExtractImage(Fox::VulkanContext* vkContext, Fox::DImage src, uint32_t width, uint32_t height, uint32_t mipLevels, VkFormat format, uint32_t bytes, void* outData) +//{ +// Fox::DImageVulkan* vkSrcImg = static_cast(src); +// +// Fox::RIVulkanDevice13& device = vkContext->GetDevice(); +// +// auto cmdPool = device.CreateCommandPool(); +// auto cmdBuffer = cmdPool->Allocate(); +// Fox::CResourceTransfer transfer(cmdBuffer->Cmd); +// +// auto outImg = device.CreateBufferHostVisible(16, VK_IMAGE_USAGE_TRANSFER_DST_BIT); +// +// transfer.CopyImageToBuffer(outImg.Buffer, vkSrcImg->Image.Image, { width, height }, 0); +// +// transfer.FinishCommandBuffer(); +// +// const std::vector cmds{ cmdBuffer }; +// device.SubmitToMainQueue(cmds, {}, VK_NULL_HANDLE, VK_NULL_HANDLE); +// vkContext->WaitDeviceIdle(); // wait copy operations to finish +// +// void* outputPtr = device.MapBuffer(outImg); +// memcpy(outData, outputPtr, bytes); +// device.UnmapBuffer(outImg); +// +// //// cleanup +// device.DestroyBuffer(outImg); +// device.DestroyCommandPool(cmdPool); +//}; \ No newline at end of file From 83aeadb56bcd40b0755653c81c0c91be8430e123 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Sun, 24 Dec 2023 12:20:24 +0100 Subject: [PATCH 02/58] queue selection got working --- examples/App.cpp | 4 +- examples/Rendering/Rendering.cpp | 7 +- include/IContext.h | 20 ++++- src/backend/vulkan/VulkanContext.cpp | 114 ++++++++++---------------- src/backend/vulkan/VulkanContext.h | 17 ++-- src/backend/vulkan/VulkanDevice.cpp | 58 ++++--------- src/backend/vulkan/VulkanDevice.h | 4 - src/backend/vulkan/VulkanDevice12.cpp | 8 +- src/backend/vulkan/VulkanDevice12.h | 6 +- src/backend/vulkan/VulkanDevice2.cpp | 12 +-- src/backend/vulkan/VulkanDevice2.h | 16 ++-- 11 files changed, 118 insertions(+), 148 deletions(-) diff --git a/examples/App.cpp b/examples/App.cpp index 89a6853..30e7b7b 100644 --- a/examples/App.cpp +++ b/examples/App.cpp @@ -130,8 +130,8 @@ App::Run() Draw(data.Cmd, w, h); _ctx->ResetFence(data.Fence); - _ctx->QueueSubmit({ data.ImageAvailableSemaphore }, { data.WorkFinishedSemaphore }, { data.Cmd }, data.Fence); + _ctx->QueueSubmit(_graphicsQueue, { data.ImageAvailableSemaphore }, { data.WorkFinishedSemaphore }, { data.Cmd }, data.Fence); - _ctx->QueuePresent(_swapchain, _swapchainImageIndex, { data.WorkFinishedSemaphore }); + _ctx->QueuePresent(_graphicsQueue, _swapchain, _swapchainImageIndex, { data.WorkFinishedSemaphore }); } } \ No newline at end of file diff --git a/examples/Rendering/Rendering.cpp b/examples/Rendering/Rendering.cpp index fe7073b..40bfb92 100644 --- a/examples/Rendering/Rendering.cpp +++ b/examples/Rendering/Rendering.cpp @@ -250,6 +250,10 @@ class TriangleApp : public App public: TriangleApp() { + // Find graphics queue + _graphicsQueue = _ctx->FindQueue(Fox::EQueueType::QUEUE_GRAPHICS); + assert(_graphicsQueue > 0); + // Create vertex layout Fox::VertexLayoutInfo position("SV_POSITION", Fox::EFormat::R32G32B32_FLOAT, 0, Fox::EVertexInputClassification::PER_VERTEX_DATA); Fox::VertexLayoutInfo color("Color0", Fox::EFormat::R32G32B32A32_FLOAT, 4 * sizeof(float), Fox::EVertexInputClassification::PER_VERTEX_DATA); @@ -749,6 +753,7 @@ class TriangleApp : public App }; protected: + uint32_t _graphicsQueue{}; uint32_t _depthRt{}; uint32_t _shader{}; uint32_t _pipeline{}; @@ -822,7 +827,7 @@ class TriangleApp : public App _ctx->EndCommandBuffer(cmd); - _ctx->QueueSubmit({}, {}, { cmd }, NULL); + _ctx->QueueSubmit(_graphicsQueue, {}, {}, { cmd }, NULL); _ctx->WaitDeviceIdle(); _ctx->DestroyBuffer(tmpBuf); diff --git a/include/IContext.h b/include/IContext.h index b9fa63e..9fe8f7a 100644 --- a/include/IContext.h +++ b/include/IContext.h @@ -705,7 +705,14 @@ class IContext virtual bool SwapchainAcquireNextImageIndex(uint32_t swapchainId, uint64_t timeoutNanoseconds, uint32_t sempahoreid, uint32_t* outImageIndex) = 0; virtual void DestroySwapchain(uint32_t swapchainId) = 0; - virtual uint32_t FindQueue(uint32_t queueTypeFlag) = 0; + /** + * \brief If exists will return a specialized queue, otherwise if exists will return a queue with that feature, otherwise it will return a general purpose queue that supports that feature. If no + * queue with requested feature are available it will return 0. It will return as many queues as there are available, after it will return always a general purpose queue with same id. Don't loose + * the queue id because specialized queues return only once. + * \param queueTypeFlag + * \return A queue with the requested feature + */ + virtual uint32_t FindQueue(EQueueType queueType) = 0; virtual uint32_t CreateBuffer(uint32_t size, EResourceType type, EMemoryUsage usage) = 0; virtual void* BeginMapBuffer(uint32_t buffer) = 0; @@ -761,8 +768,15 @@ class IContext virtual void WaitForFence(uint32_t fenceId, uint64_t timeoutNanoseconds) = 0; virtual void ResetFence(uint32_t fenceId) = 0; - virtual void QueueSubmit(const std::vector& waitSemaphore, const std::vector& finishSemaphore, const std::vector& cmdIds, uint32_t fenceId) = 0; - virtual void QueuePresent(uint32_t swapchainId, uint32_t imageIndex, const std::vector& waitSemaphore) = 0; + /** + * \brief Must be externally synchronized if called from multiple threads + * \param waitSemaphore + * \param finishSemaphore + * \param cmdIds + * \param fenceId + */ + virtual void QueueSubmit(uint32_t queueId, const std::vector& waitSemaphore, const std::vector& finishSemaphore, const std::vector& cmdIds, uint32_t fenceId) = 0; + virtual void QueuePresent(uint32_t queueId, uint32_t swapchainId, uint32_t imageIndex, const std::vector& waitSemaphore) = 0; virtual uint32_t CreateGpuSemaphore() = 0; virtual void DestroyGpuSemaphore(uint32_t semaphoreId) = 0; diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index 350e367..ba75cdd 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -219,7 +219,7 @@ VulkanContext::VulkanContext(const DContextConfig* const config) : _warningOutpu EndCommandBuffer(cmd); const auto fence = CreateFence(false); - QueueSubmit({}, {}, { cmd }, fence); + QueueSubmit(graphicsQueue, {}, {}, { cmd }, fence); WaitForFence(fence, 0xFFFFFFFF); DestroyFence(fence); DestroyCommandBuffer(cmd); @@ -372,8 +372,7 @@ VulkanContext::_initializeDevice() // replacing global function pointers with functions retrieved with vkGetDeviceProcAddr volkLoadDevice(Device.Device); - // track count of queue instantiated from each family - _queueFamilyIndexCreatedCount.resize(Device.QueueFamilies.size()); + // track count of queue instantiated from each family; std::fill(_queueFamilyIndexCreatedCount.begin(), _queueFamilyIndexCreatedCount.end(), 0); } @@ -478,6 +477,19 @@ VulkanContext::_createSwapchain(DSwapchainVulkan& swapchain, const WindowData* w } } + uint32_t queueFamilyIndex{}; + { + uint32_t queueIndex{}; + uint32_t queueIndexCount[16]{}; + const auto foundGraphicsQueueId{ VkUtils::findQueueWithFlags( + &queueFamilyIndex, &queueIndex, VK_QUEUE_GRAPHICS_BIT, Device.QueueFamilies.data(), Device.QueueFamilies.size(), queueIndexCount) }; + const bool supportPresentation{ Device.SurfaceSupportPresentationOnQueueFamilyIndex(surface, queueFamilyIndex) }; + if (!supportPresentation) + { + throw std::runtime_error("Vulkan graphics queue does not support presentation to this surface!"); + } + } + // Query formats present mode and capabilities const auto formats = Device.GetSurfaceFormats(surface); outFormat = VkUtils::convertVkFormat(formats.front().format); @@ -496,7 +508,7 @@ VulkanContext::_createSwapchain(DSwapchainVulkan& swapchain, const WindowData* w // Create swapchain object VkSwapchainKHR vkSwapchain{}; { - const auto result = Device.CreateSwapchainFromSurface(surface, formats.at(0), vkPresentMode, capabilities, &vkSwapchain); + const auto result = Device.CreateSwapchainFromSurface(surface, formats.at(0), vkPresentMode, capabilities, &queueFamilyIndex, 1, &vkSwapchain); if (VKFAILED(result)) { throw std::runtime_error("Failed to create swapchain " + std::string(VkUtils::VkErrorString(result))); @@ -693,86 +705,45 @@ VulkanContext::DestroySwapchain(SwapchainId swapchainId) } uint32_t -VulkanContext::FindQueue(uint32_t queueTypeFlag) +VulkanContext::FindQueue(EQueueType queueType) { - bool found{ false }; uint32_t familyIndex{}; uint32_t queueIndex{}; - uint32_t vkFlags{}; - if (queueTypeFlag & EQueueType::QUEUE_GRAPHICS) - { - vkFlags |= VK_QUEUE_GRAPHICS_BIT; - } - if (queueTypeFlag & EQueueType::QUEUE_COMPUTE) - { - vkFlags |= VK_QUEUE_COMPUTE_BIT; - } - if (queueTypeFlag & EQueueType::QUEUE_TRANSFER) + const uint32_t vkFlags{ VkUtils::convertQueueTypeToVkFlags(queueType) }; + const bool found{ VkUtils::findQueueWithFlags(&familyIndex, &queueIndex, vkFlags, Device.QueueFamilies.data(), Device.QueueFamilies.size(), _queueFamilyIndexCreatedCount.data()) }; + + if (!found) { - vkFlags |= VK_QUEUE_TRANSFER_BIT; + // No queue family has this flag. + return 0; } - for (uint32_t i = 0; i < Device.QueueFamilies.size(); i++) + // Find already allocated queue object + for (uint32_t i = 0; i < MAX_RESOURCES; i++) { - VkQueueFamilyProperties& queueFamily = Device.QueueFamilies[i]; - const bool isGraphics = (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) ? true : false; - // If has the required flags but is also graphics and has unused queues - if (vkFlags & VK_QUEUE_GRAPHICS_BIT && isGraphics) + const auto& queueRef = _queues.at(i); + if (queueRef.Id == FREE) { - found = true; - familyIndex = i; - // User can query as many graphics queue as it can, we will return always the same since there is no benefit of using multiple ones break; } - // if requested is specialized queue with only the flag requested - if (queueFamily.queueFlags & vkFlags && (queueFamily.queueFlags & ~vkFlags) == 0 && _queueFamilyIndexCreatedCount[i] < queueFamily.queueCount) - { - found = true; - familyIndex = i; - queueIndex = _queueFamilyIndexCreatedCount[i]++; - break; - } - uint32_t orRequestedFlags = (queueFamily.queueFlags & vkFlags); - ; - if (queueFamily.queueFlags & orRequestedFlags && (queueFamily.queueFlags - orRequestedFlags) < UINT32_MAX == 0 && _queueFamilyIndexCreatedCount[i] < queueFamily.queueCount) + if (queueRef.QueueFamilyIndex == familyIndex && queueRef.QueueIndex == queueIndex) { - found = true; - familyIndex = i; - queueIndex = _queueFamilyIndexCreatedCount[i]++; - break; + return *ResourceId(EResourceType::QUEUE, queueRef.Id, i); } } - // Find a queue with the requested queueTypeFlags - if (!found) - { - for (uint32_t i = 0; i < Device.QueueFamilies.size(); i++) - { - VkQueueFamilyProperties& queueFamily = Device.QueueFamilies[i]; - if (queueFamily.queueFlags & vkFlags) - { - found = true; - familyIndex = i; - queueIndex = _queueFamilyIndexCreatedCount[i]++; - break; - } - } - } - - check(found == true); + // Allocate new queue object { const auto index = AllocResource(_queues); auto& queueRef = _queues.at(index); queueRef.QueueFamilyIndex = familyIndex; + queueRef.QueueIndex = queueIndex; vkGetDeviceQueue(Device.Device, familyIndex, queueIndex, &queueRef.QueuePtr); return *ResourceId(EResourceType::QUEUE, queueRef.Id, index); } - - throw std::runtime_error("No vulkan queue available!"); - return 0; } BufferId @@ -1544,12 +1515,11 @@ VulkanContext::CreateCommandPool(uint32_t queueId) const auto index = AllocResource(_commandPools); auto& commandPoolRef = _commandPools.at(index); - commandPoolRef.Pool = Device.CreateCommandPool2(Device.GraphicsQueueInfo.FamilyIndex); - - const auto queueRef = GetResource(_queues, queueId); - commandPoolRef.QueueFamilyIndex = queueRef.QueueFamilyIndex; - - // commandPoolRef.Type = queueType; + { + const auto& queueRef = GetResource(_queues, queueId); + commandPoolRef.Pool = Device.CreateCommandPool2(queueRef.QueueFamilyIndex); + commandPoolRef.QueueFamilyIndex = queueRef.QueueFamilyIndex; + } return *ResourceId(EResourceType::COMMAND_POOL, commandPoolRef.Id, index); } @@ -1877,7 +1847,7 @@ VulkanContext::CopyImage(uint32_t commandId, uint32_t imageId, uint32_t width, u } void -VulkanContext::QueueSubmit(const std::vector& waitSemaphore, const std::vector& finishSemaphore, const std::vector& cmdIds, uint32_t fenceId) +VulkanContext::QueueSubmit(uint32_t queueId, const std::vector& waitSemaphore, const std::vector& finishSemaphore, const std::vector& cmdIds, uint32_t fenceId) { std::vector commandBuffers; for (auto cmdId : cmdIds) @@ -1919,7 +1889,9 @@ VulkanContext::QueueSubmit(const std::vector& waitSemaphore, const std submitInfo.signalSemaphoreCount = (uint32_t)finishSemaphores.size(); submitInfo.pSignalSemaphores = finishSemaphores.data(); - const VkResult result = vkQueueSubmit(Device.MainQueue, 1, &submitInfo, fenceRef != nullptr ? fenceRef->Fence : VK_NULL_HANDLE); + const auto& queueRef = GetResource(_queues, queueId); + + const VkResult result = vkQueueSubmit(queueRef.QueuePtr, 1, &submitInfo, fenceRef != nullptr ? fenceRef->Fence : VK_NULL_HANDLE); if (VKFAILED(result)) { throw std::runtime_error(VkUtils::VkErrorString(result)); @@ -1927,7 +1899,7 @@ VulkanContext::QueueSubmit(const std::vector& waitSemaphore, const std } void -VulkanContext::QueuePresent(uint32_t swapchainId, uint32_t imageIndex, const std::vector& waitSemaphore) +VulkanContext::QueuePresent(uint32_t queueId, uint32_t swapchainId, uint32_t imageIndex, const std::vector& waitSemaphore) { std::vector waitSemaphores; for (auto semaphoreId : waitSemaphore) @@ -1947,7 +1919,9 @@ VulkanContext::QueuePresent(uint32_t swapchainId, uint32_t imageIndex, const std presentInfo.pImageIndices = &imageIndex; presentInfo.pResults = nullptr; - const VkResult result = vkQueuePresentKHR(Device.MainQueue, &presentInfo); + const auto& queueRef = GetResource(_queues, queueId); + + const VkResult result = vkQueuePresentKHR(queueRef.QueuePtr, &presentInfo); if (result == VK_SUCCESS || VK_SUBOPTIMAL_KHR) { return; diff --git a/src/backend/vulkan/VulkanContext.h b/src/backend/vulkan/VulkanContext.h index 00cbf90..8eaa795 100644 --- a/src/backend/vulkan/VulkanContext.h +++ b/src/backend/vulkan/VulkanContext.h @@ -149,8 +149,8 @@ struct DSamplerVulkan : public DResource struct DQueueVulkan : public DResource { - // RIVulkanQueue Queue{}; uint32_t QueueFamilyIndex{}; + uint32_t QueueIndex{}; VkQueue QueuePtr{}; }; @@ -167,7 +167,7 @@ class VulkanContext final : public IContext bool SwapchainAcquireNextImageIndex(SwapchainId swapchainId, uint64_t timeoutNanoseconds, uint32_t sempahoreid, uint32_t* outImageIndex) override; void DestroySwapchain(SwapchainId swapchainId) override; - uint32_t FindQueue(uint32_t queueTypeFlag) override; + uint32_t FindQueue(EQueueType queueType) override; BufferId CreateBuffer(uint32_t size, EResourceType type, EMemoryUsage usage) override; void* BeginMapBuffer(BufferId buffer) override; @@ -233,8 +233,8 @@ class VulkanContext final : public IContext void FlushDeletedBuffers() override; - void QueueSubmit(const std::vector& waitSemaphore, const std::vector& finishSemaphore, const std::vector& cmdIds, uint32_t fenceId) override; - void QueuePresent(uint32_t swapchainId, uint32_t imageIndex, const std::vector& waitSemaphore) override; + void QueueSubmit(uint32_t queueId, const std::vector& waitSemaphore, const std::vector& finishSemaphore, const std::vector& cmdIds, uint32_t fenceId) override; + void QueuePresent(uint32_t queueId, uint32_t swapchainId, uint32_t imageIndex, const std::vector& waitSemaphore) override; unsigned char* GetAdapterDescription() const override; size_t GetAdapterDedicatedVideoMemory() const override; @@ -276,9 +276,12 @@ class VulkanContext final : public IContext std::array _renderTargets; std::array _rootSignatures; std::array _descriptorSets; - std::array _queues; - std::unordered_set _renderPasses; - std::vector _queueFamilyIndexCreatedCount; + /*Since queues are never deallocated, we are sure that there is no fragmentation*/ + std::array _queues; + /*No gpu can have more than 16 queue families*/ + std::array _queueFamilyIndexCreatedCount; + + std::unordered_set _renderPasses; using DeleteFn = std::function; using FramesWaitToDeletionList = std::pair>; diff --git a/src/backend/vulkan/VulkanDevice.cpp b/src/backend/vulkan/VulkanDevice.cpp index acd0c0d..70cf5af 100644 --- a/src/backend/vulkan/VulkanDevice.cpp +++ b/src/backend/vulkan/VulkanDevice.cpp @@ -55,35 +55,23 @@ std::vector validationLayers) vkGetPhysicalDeviceQueueFamilyProperties(PhysicalDevice, &queueFamiliesCount, QueueFamilies.data()); // Find graphics queue - for (uint32_t i = 0; i < queueFamiliesCount; i++) - { - VkQueueFamilyProperties* queue = &QueueFamilies[i]; - if (queue->queueFlags & VK_QUEUE_GRAPHICS_BIT) - { - GraphicsQueueInfo.Flags = queue->queueFlags; - GraphicsQueueInfo.FamilyIndex = i; - if (queue->queueFlags & VK_QUEUE_TRANSFER_BIT) - { - TransferQueueInfo = GraphicsQueueInfo; - } - break; - } - } - // Find transfer only queue - for (uint32_t i = 0; i < queueFamiliesCount; i++) - { - VkQueueFamilyProperties* queue = &QueueFamilies[i]; - if (queue->queueFlags & VK_QUEUE_TRANSFER_BIT && (queue->queueFlags & VK_QUEUE_GRAPHICS_BIT) == 0) - { - TransferQueueInfo.FamilyIndex = i; - break; - } - } + { + int32_t graphicsFamilyIndex{ -1 }; + for (uint32_t i = 0; i < queueFamiliesCount; i++) + { + VkQueueFamilyProperties* queue = &QueueFamilies[i]; + if (queue->queueFlags & VK_QUEUE_GRAPHICS_BIT) + { + graphicsFamilyIndex = i; + break; + } + } - if (GraphicsQueueInfo.FamilyIndex < 0) - { - throw std::runtime_error("No vulkan graphics queue available!"); - } + if (graphicsFamilyIndex < 0) + { + throw std::runtime_error("No vulkan graphics queue available!"); + } + } // Create all queues up front std::vector queueCreateInfos; @@ -98,17 +86,6 @@ std::vector validationLayers) queueCreateInfo.pQueuePriorities = queuePriorities.data(); // must be a valid pointer to an array of queueCount float values queueCreateInfos.emplace_back(std::move(queueCreateInfo)); } - // if (GraphicsQueueInfo.FamilyIndex != TransferQueueInfo.FamilyIndex) - // { - // VkDeviceQueueCreateInfo queueCreateInfo{}; - // queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - // queueCreateInfo.queueFamilyIndex = TransferQueueInfo.FamilyIndex; - // queueCreateInfo.queueCount = 1; - // queueCreateInfo.flags = 0; - // queueCreateInfo.pNext = NULL; - // queueCreateInfo.pQueuePriorities = &queuePriority; - // queueCreateInfos.emplace_back(std::move(queueCreateInfo)); - // } VkDeviceCreateInfo deviceInfo{}; deviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; @@ -180,9 +157,6 @@ std::vector validationLayers) } } - vkGetDeviceQueue(Device, GraphicsQueueInfo.FamilyIndex, 0, &MainQueue); - vkGetDeviceQueue(Device, TransferQueueInfo.FamilyIndex, 0, &TransferQueue); - return VK_SUCCESS; } diff --git a/src/backend/vulkan/VulkanDevice.h b/src/backend/vulkan/VulkanDevice.h index 07dc94d..0ebaef6 100644 --- a/src/backend/vulkan/VulkanDevice.h +++ b/src/backend/vulkan/VulkanDevice.h @@ -36,8 +36,6 @@ class RIVulkanDevice std::vector validationLayers); void Deinit(); - RIVulkanQueue GraphicsQueueInfo{}; - RIVulkanQueue TransferQueueInfo{}; std::vector QueueFamilies; inline int32_t GetMaxImageAllocations() const { return 4096; } @@ -47,8 +45,6 @@ class RIVulkanDevice VmaAllocator VmaAllocator; VkPhysicalDeviceProperties DeviceProperties{}; /*Properties of the physical device*/ VkPhysicalDeviceMemoryProperties DeviceMemory{}; /*Properties about the physical device memory*/ - VkQueue MainQueue{}; /* Graphics and Transfer queue*/ - VkQueue TransferQueue{}; /* Transfer queue*/ private: diff --git a/src/backend/vulkan/VulkanDevice12.cpp b/src/backend/vulkan/VulkanDevice12.cpp index 4e25327..5c0b394 100644 --- a/src/backend/vulkan/VulkanDevice12.cpp +++ b/src/backend/vulkan/VulkanDevice12.cpp @@ -51,14 +51,14 @@ RICommandPool::Reset() } RICommandPool* -RIVulkanDevice12::CreateCommandPool() +RIVulkanDevice12::CreateCommandPool(uint32_t queueFamilyIndex) { VkCommandPool commandPool{}; { VkCommandPoolCreateInfo poolInfo{}; poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; /*Allow command buffers to be rerecorded individually, without this flag they all have to be reset together*/ - poolInfo.queueFamilyIndex = GraphicsQueueInfo.FamilyIndex; + poolInfo.queueFamilyIndex = queueFamilyIndex; const VkResult result = vkCreateCommandPool(Device, &poolInfo, nullptr, &commandPool); if (VKFAILED(result)) @@ -133,7 +133,7 @@ RIVulkanDevice12::DestroyCommandPool2(VkCommandPool commandPool) } void -RIVulkanDevice12::SubmitToMainQueue(const std::vector& cmds, const std::vector& waitSemaphore, VkSemaphore finishSemaphore, VkFence fence) +RIVulkanDevice12::SubmitToMainQueue(VkQueue queue, const std::vector& cmds, const std::vector& waitSemaphore, VkSemaphore finishSemaphore, VkFence fence) { std::for_each(cmds.begin(), cmds.end(), [](RICommandBuffer* cmd) { cmd->IncreaseCounter(); }); @@ -156,7 +156,7 @@ RIVulkanDevice12::SubmitToMainQueue(const std::vector& cmds, c submitInfo.signalSemaphoreCount = finishSemaphore ? 1 : 0; submitInfo.pSignalSemaphores = finishSemaphore ? &finishSemaphore : nullptr; - const VkResult result = vkQueueSubmit(MainQueue, 1, &submitInfo, fence); + const VkResult result = vkQueueSubmit(queue, 1, &submitInfo, fence); if (VKFAILED(result)) { throw std::runtime_error(VkUtils::VkErrorString(result)); diff --git a/src/backend/vulkan/VulkanDevice12.h b/src/backend/vulkan/VulkanDevice12.h index a6dd1e6..5141e34 100644 --- a/src/backend/vulkan/VulkanDevice12.h +++ b/src/backend/vulkan/VulkanDevice12.h @@ -91,16 +91,16 @@ class RIVulkanDevice12 : public RIVulkanDevice11 { public: /*don't delete pointer, is managed by a pool*/ - RICommandPool* CreateCommandPool(); + RICommandPool* CreateCommandPool(uint32_t queueFamilyIndex); /*This is explicit deletion, will be deleted in destructor automatically*/ void DestroyCommandPool(RICommandPool*); - void SubmitToMainQueue(const std::vector& cmds, const std::vector& waitSemaphore, VkSemaphore finishSemaphore, VkFence fence); - + void SubmitToMainQueue(VkQueue queue, const std::vector& cmds, const std::vector& waitSemaphore, VkSemaphore finishSemaphore, VkFence fence); VkCommandPool CreateCommandPool2(uint32_t queueFamilyIndex); void DestroyCommandPool2(VkCommandPool commandPool); void ResetCommandPool2(VkCommandPool commandPool); + public: virtual ~RIVulkanDevice12(); diff --git a/src/backend/vulkan/VulkanDevice2.cpp b/src/backend/vulkan/VulkanDevice2.cpp index 599e726..b26040f 100644 --- a/src/backend/vulkan/VulkanDevice2.cpp +++ b/src/backend/vulkan/VulkanDevice2.cpp @@ -13,11 +13,11 @@ namespace Fox RIVulkanDevice2::~RIVulkanDevice2() { check(_swapchains.size() == 0); } bool -RIVulkanDevice2::SurfaceSupportPresentationOnCurrentQueueFamily(VkSurfaceKHR surface) +RIVulkanDevice2::SurfaceSupportPresentationOnQueueFamilyIndex(VkSurfaceKHR surface, uint32_t queueFamilyIndex) { uint32_t supportPresentation = VK_FALSE; // To determine whether a queue family of a physical device supports presentation to a given surface - const VkResult result = vkGetPhysicalDeviceSurfaceSupportKHR(PhysicalDevice, GraphicsQueueInfo.FamilyIndex, surface, &supportPresentation); + const VkResult result = vkGetPhysicalDeviceSurfaceSupportKHR(PhysicalDevice, queueFamilyIndex, surface, &supportPresentation); if (VKFAILED(result)) { throw std::runtime_error(VkUtils::VkErrorString(result)); @@ -90,10 +90,12 @@ RIVulkanDevice2::CreateSwapchainFromSurface(VkSurfaceKHR surface, const VkSurfaceFormatKHR& format, const VkPresentModeKHR& presentMode, const VkSurfaceCapabilitiesKHR& capabilities, +uint32_t* queueFamilyIndices, +uint32_t queueFamilyIndicesCount, VkSwapchainKHR* outSwapchain, VkSwapchainKHR oldSwapchain) { - uint32_t queueFamilyIndices[] = { (uint32_t)GraphicsQueueInfo.FamilyIndex }; + check(queueFamilyIndices != nullptr); critical(capabilities.minImageCount >= MAX_IMAGE_COUNT); VkSwapchainCreateInfoKHR swapchainInfo = {}; @@ -182,7 +184,7 @@ RIVulkanDevice2::AcquireNextImage(VkSwapchainKHR swapchain, uint64_t timeoutNano } std::vector -RIVulkanDevice2::Present(std::vector> swapchainImageIndex, std::vector waitSemaphores) +RIVulkanDevice2::Present(VkQueue queue, std::vector> swapchainImageIndex, std::vector waitSemaphores) { std::vector results(swapchainImageIndex.size(), VK_SUCCESS); @@ -207,7 +209,7 @@ RIVulkanDevice2::Present(std::vector> swapch presentInfo.pResults = results.data(); { - [[maybe_unused]] const VkResult result = vkQueuePresentKHR(MainQueue, &presentInfo); + [[maybe_unused]] const VkResult result = vkQueuePresentKHR(queue, &presentInfo); } return results; } diff --git a/src/backend/vulkan/VulkanDevice2.h b/src/backend/vulkan/VulkanDevice2.h index cabb368..6495041 100644 --- a/src/backend/vulkan/VulkanDevice2.h +++ b/src/backend/vulkan/VulkanDevice2.h @@ -18,7 +18,7 @@ class RIVulkanDevice2 : public RIVulkanDevice public: virtual ~RIVulkanDevice2(); - bool SurfaceSupportPresentationOnCurrentQueueFamily(VkSurfaceKHR surface); + bool SurfaceSupportPresentationOnQueueFamilyIndex(VkSurfaceKHR surface, uint32_t queueFamilyIndex); std::vector GetSurfaceFormats(VkSurfaceKHR surface); VkSurfaceCapabilitiesKHR GetSurfaceCapabilities(VkSurfaceKHR surface); std::vector GetSurfacePresentModes(VkSurfaceKHR surface); @@ -32,11 +32,13 @@ class RIVulkanDevice2 : public RIVulkanDevice * @return */ VkResult CreateSwapchainFromSurface(VkSurfaceKHR surface, - const VkSurfaceFormatKHR& format, - const VkPresentModeKHR& presentMode, - const VkSurfaceCapabilitiesKHR& capabilities, - VkSwapchainKHR* outSwapchain, - VkSwapchainKHR oldSwapchain = nullptr); + const VkSurfaceFormatKHR& format, + const VkPresentModeKHR& presentMode, + const VkSurfaceCapabilitiesKHR& capabilities, + uint32_t* queueFamilyIndices, + uint32_t queueFamilyIndicesCount, + VkSwapchainKHR* outSwapchain, + VkSwapchainKHR oldSwapchain = nullptr); /** * @brief Must be externally synchronized * @param swapchain Swapchain to destroy @@ -47,7 +49,7 @@ class RIVulkanDevice2 : public RIVulkanDevice VkResult AcquireNextImage(VkSwapchainKHR swapchain, uint64_t timeoutNanoseconds, uint32_t* imageIndex, VkSemaphore imageAvailableSempahore, VkFence fence = VK_NULL_HANDLE); - std::vector Present(std::vector> swapchainImageIndex, std::vector waitSemaphores); + std::vector Present(VkQueue queue, std::vector> swapchainImageIndex, std::vector waitSemaphores); private: std::unordered_set _swapchains; From 87f622fc1897c6f33c7f845d9e16ef796c29615d Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Sun, 24 Dec 2023 14:35:03 +0100 Subject: [PATCH 03/58] buffer barrier --- include/IContext.h | 55 +++++++----- src/backend/vulkan/VulkanContext.cpp | 126 ++++++++++++++++++++------- 2 files changed, 127 insertions(+), 54 deletions(-) diff --git a/include/IContext.h b/include/IContext.h index 9fe8f7a..4fc91e3 100644 --- a/include/IContext.h +++ b/include/IContext.h @@ -625,28 +625,35 @@ struct DescriptorSetDesc ERIShaderStage Stage; }; +enum ETransferOwnership : uint8_t +{ + NONE = 0, + ACQUIRE, + RELEASE +}; + typedef struct BufferBarrier { - uint32_t BufferId; - EResourceState CurrentState; - EResourceState NewState; - uint8_t BeginOnly : 1; - uint8_t EndOnly : 1; - uint8_t Acquire : 1; - uint8_t Release : 1; - uint8_t QueueType : 5; + uint32_t BufferId; + EResourceState CurrentState; + EResourceState NewState; + uint8_t BeginOnly : 1; + uint8_t EndOnly : 1; + ETransferOwnership TransferOwnership{ ETransferOwnership::NONE }; + uint8_t SrcQueue{}; + uint8_t DstQueue{}; } BufferBarrier; typedef struct TextureBarrier { - uint32_t ImageId; - EResourceState CurrentState; - EResourceState NewState; - uint8_t BeginOnly : 1; - uint8_t EndOnly : 1; - uint8_t Acquire : 1; - uint8_t Release : 1; - uint8_t QueueType : 5; + uint32_t ImageId; + EResourceState CurrentState; + EResourceState NewState; + uint8_t BeginOnly : 1; + uint8_t EndOnly : 1; + ETransferOwnership TransferOwnership{ ETransferOwnership::NONE }; + uint8_t SrcQueue{}; + uint8_t DstQueue{}; /// Specifiy whether following barrier targets particular subresource uint8_t mSubresourceBarrier : 1; /// Following values are ignored if mSubresourceBarrier is false @@ -656,14 +663,14 @@ typedef struct TextureBarrier typedef struct RenderTargetBarrier { - uint32_t RenderTarget{}; - EResourceState mCurrentState; - EResourceState mNewState; - uint8_t mBeginOnly : 1; - uint8_t mEndOnly : 1; - uint8_t mAcquire : 1; - uint8_t mRelease : 1; - uint8_t mQueueType : 5; + uint32_t RenderTarget{}; + EResourceState mCurrentState; + EResourceState mNewState; + uint8_t mBeginOnly : 1; + uint8_t mEndOnly : 1; + ETransferOwnership TransferOwnership{ ETransferOwnership::NONE }; + uint8_t SrcQueue{}; + uint8_t DstQueue{}; /// Specifiy whether following barrier targets particular subresource uint8_t mSubresourceBarrier : 1 {}; /// Following values are ignored if mSubresourceBarrier is false diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index ba75cdd..0760ab3 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -2152,9 +2152,69 @@ RenderTargetBarrier* p_rt_barriers) imageBarriers.resize(rt_barrier_count + texture_barrier_count); uint32_t imageBarrierCount{}; + std::vector bufferBarriers; + bufferBarriers.resize(buffer_barrier_count); + uint32_t bufferBarrierCount{}; + VkAccessFlags srcAccessFlags = 0; VkAccessFlags dstAccessFlags = 0; + for (uint32_t i = 0; i < buffer_barrier_count; ++i) + { + BufferBarrier* pTrans = &p_buffer_barriers[i]; + const DBufferVulkan& bufferRef = GetResource(_vertexBuffers, pTrans->BufferId); + VkBuffer pBuffer = bufferRef.Buffer.Buffer; + VkBufferMemoryBarrier* pBufferBarrier = NULL; + + if (EResourceState::UNORDERED_ACCESS == pTrans->CurrentState && EResourceState::UNORDERED_ACCESS == pTrans->NewState) + { + pBufferBarrier = &bufferBarriers[bufferBarrierCount++]; //-V522 + pBufferBarrier->sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; //-V522 + pBufferBarrier->pNext = NULL; + + pBufferBarrier->srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + pBufferBarrier->dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT; + } + else + { + pBufferBarrier = &bufferBarriers[bufferBarrierCount++]; + pBufferBarrier->sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER; + pBufferBarrier->pNext = NULL; + + pBufferBarrier->srcAccessMask = VkUtils::resourceStateToAccessFlag(pTrans->CurrentState); + pBufferBarrier->dstAccessMask = VkUtils::resourceStateToAccessFlag(pTrans->NewState); + } + + if (pBufferBarrier) + { + pBufferBarrier->buffer = pBuffer; + pBufferBarrier->size = VK_WHOLE_SIZE; + pBufferBarrier->offset = 0; + + switch (pTrans->TransferOwnership) + { + default: + case ETransferOwnership::NONE: + pBufferBarrier->srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + pBufferBarrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + break; + case ETransferOwnership::ACQUIRE: + case ETransferOwnership::RELEASE: + { + check(pTrans->SrcQueue > 0); + const auto& srcQueueRef = GetResource(_queues, pTrans->SrcQueue); + pBufferBarrier->srcQueueFamilyIndex = srcQueueRef.QueueFamilyIndex; + const auto& dstQueueRef = GetResource(_queues, pTrans->DstQueue); + pBufferBarrier->dstQueueFamilyIndex = dstQueueRef.QueueFamilyIndex; + break; + } + } + + srcAccessFlags |= pBufferBarrier->srcAccessMask; + dstAccessFlags |= pBufferBarrier->dstAccessMask; + } + } + for (uint32_t i = 0; i < texture_barrier_count; ++i) { TextureBarrier* pTrans = &p_texture_barriers[i]; @@ -2193,21 +2253,24 @@ RenderTargetBarrier* p_rt_barriers) pImageBarrier->subresourceRange.baseArrayLayer = pTrans->mSubresourceBarrier ? pTrans->mArrayLayer : 0; pImageBarrier->subresourceRange.layerCount = pTrans->mSubresourceBarrier ? 1 : VK_REMAINING_ARRAY_LAYERS; - // if (pTrans->mAcquire && pTrans->mCurrentState != RESOURCE_STATE_UNDEFINED) - // { - // pImageBarrier->srcQueueFamilyIndex = pCmd->pRenderer->mVulkan.mQueueFamilyIndices[pTrans->mQueueType]; - // pImageBarrier->dstQueueFamilyIndex = pCmd->pQueue->mVulkan.mVkQueueFamilyIndex; - // } - // else if (pTrans->mRelease && pTrans->mCurrentState != RESOURCE_STATE_UNDEFINED) - // { - // pImageBarrier->srcQueueFamilyIndex = pCmd->pQueue->mVulkan.mVkQueueFamilyIndex; - // pImageBarrier->dstQueueFamilyIndex = pCmd->pRenderer->mVulkan.mQueueFamilyIndices[pTrans->mQueueType]; - // } - // else - { - pImageBarrier->srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - pImageBarrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - } + switch (pTrans->TransferOwnership) + { + default: + case ETransferOwnership::NONE: + pImageBarrier->srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + pImageBarrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + break; + case ETransferOwnership::ACQUIRE: + case ETransferOwnership::RELEASE: + { + check(pTrans->SrcQueue > 0); + const auto& srcQueueRef = GetResource(_queues, pTrans->SrcQueue); + pImageBarrier->srcQueueFamilyIndex = srcQueueRef.QueueFamilyIndex; + const auto& dstQueueRef = GetResource(_queues, pTrans->DstQueue); + pImageBarrier->dstQueueFamilyIndex = dstQueueRef.QueueFamilyIndex; + break; + } + } srcAccessFlags |= pImageBarrier->srcAccessMask; dstAccessFlags |= pImageBarrier->dstAccessMask; @@ -2252,21 +2315,24 @@ RenderTargetBarrier* p_rt_barriers) pImageBarrier->subresourceRange.baseArrayLayer = pTrans->mSubresourceBarrier ? pTrans->mArrayLayer : 0; pImageBarrier->subresourceRange.layerCount = pTrans->mSubresourceBarrier ? 1 : VK_REMAINING_ARRAY_LAYERS; - // if (pTrans->mAcquire && pTrans->mCurrentState != EResourceState::UNDEFINED) - // { - // pImageBarrier->srcQueueFamilyIndex = pCmd->pRenderer->mVulkan.mQueueFamilyIndices[pTrans->mQueueType]; - // pImageBarrier->dstQueueFamilyIndex = pCmd->pQueue->mVulkan.mVkQueueFamilyIndex; - // } - // else if (pTrans->mRelease && pTrans->mCurrentState != EResourceState::UNDEFINED) - // { - // pImageBarrier->srcQueueFamilyIndex = pCmd->pQueue->mVulkan.mVkQueueFamilyIndex; - // pImageBarrier->dstQueueFamilyIndex = pCmd->pRenderer->mVulkan.mQueueFamilyIndices[pTrans->mQueueType]; - // } - // else - { - pImageBarrier->srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - pImageBarrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - } + switch (pTrans->TransferOwnership) + { + default: + case ETransferOwnership::NONE: + pImageBarrier->srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + pImageBarrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + break; + case ETransferOwnership::ACQUIRE: + case ETransferOwnership::RELEASE: + { + check(pTrans->SrcQueue > 0); + const auto& srcQueueRef = GetResource(_queues, pTrans->SrcQueue); + pImageBarrier->srcQueueFamilyIndex = srcQueueRef.QueueFamilyIndex; + const auto& dstQueueRef = GetResource(_queues, pTrans->DstQueue); + pImageBarrier->dstQueueFamilyIndex = dstQueueRef.QueueFamilyIndex; + break; + } + } srcAccessFlags |= pImageBarrier->srcAccessMask; dstAccessFlags |= pImageBarrier->dstAccessMask; From 4844ba4a64a63da2ba3d85b98bdf6ec3bc72be27 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Tue, 26 Dec 2023 10:13:41 +0100 Subject: [PATCH 04/58] Release and acquire resource on queue test passing --- include/IContext.h | 12 +- src/backend/vulkan/VulkanContext.cpp | 34 ++++- src/backend/vulkan/VulkanContext.h | 10 +- tests/CMakeLists.txt | 3 +- .../vulkan/AcquireAndRelease.test.cpp | 139 ++++++++++++++++++ tests/integration/vulkan/ImageUpload.test.cpp | 44 +++--- 6 files changed, 203 insertions(+), 39 deletions(-) create mode 100644 tests/integration/vulkan/AcquireAndRelease.test.cpp diff --git a/include/IContext.h b/include/IContext.h index 4fc91e3..2b3c763 100644 --- a/include/IContext.h +++ b/include/IContext.h @@ -640,8 +640,8 @@ typedef struct BufferBarrier uint8_t BeginOnly : 1; uint8_t EndOnly : 1; ETransferOwnership TransferOwnership{ ETransferOwnership::NONE }; - uint8_t SrcQueue{}; - uint8_t DstQueue{}; + uint32_t SrcQueue{}; + uint32_t DstQueue{}; } BufferBarrier; typedef struct TextureBarrier @@ -652,8 +652,8 @@ typedef struct TextureBarrier uint8_t BeginOnly : 1; uint8_t EndOnly : 1; ETransferOwnership TransferOwnership{ ETransferOwnership::NONE }; - uint8_t SrcQueue{}; - uint8_t DstQueue{}; + uint32_t SrcQueue{}; + uint32_t DstQueue{}; /// Specifiy whether following barrier targets particular subresource uint8_t mSubresourceBarrier : 1; /// Following values are ignored if mSubresourceBarrier is false @@ -669,8 +669,8 @@ typedef struct RenderTargetBarrier uint8_t mBeginOnly : 1; uint8_t mEndOnly : 1; ETransferOwnership TransferOwnership{ ETransferOwnership::NONE }; - uint8_t SrcQueue{}; - uint8_t DstQueue{}; + uint32_t SrcQueue{}; + uint32_t DstQueue{}; /// Specifiy whether following barrier targets particular subresource uint8_t mSubresourceBarrier : 1 {}; /// Following values are ignored if mSubresourceBarrier is false diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index 0760ab3..349f582 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -741,6 +741,7 @@ VulkanContext::FindQueue(EQueueType queueType) queueRef.QueueFamilyIndex = familyIndex; queueRef.QueueIndex = queueIndex; vkGetDeviceQueue(Device.Device, familyIndex, queueIndex, &queueRef.QueuePtr); + queueRef.Type = queueType; return *ResourceId(EResourceType::QUEUE, queueRef.Id, index); } @@ -1519,6 +1520,7 @@ VulkanContext::CreateCommandPool(uint32_t queueId) const auto& queueRef = GetResource(_queues, queueId); commandPoolRef.Pool = Device.CreateCommandPool2(queueRef.QueueFamilyIndex); commandPoolRef.QueueFamilyIndex = queueRef.QueueFamilyIndex; + commandPoolRef.Type = queueRef.Type; } return *ResourceId(EResourceType::COMMAND_POOL, commandPoolRef.Id, index); @@ -1555,6 +1557,8 @@ VulkanContext::CreateCommandBuffer(uint32_t commandPoolId) auto& commandPoolRef = GetResource(_commandPools, commandPoolId); + commandBufferRef.Type = commandPoolRef.Type; + VkCommandBufferAllocateInfo info{}; info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; info.pNext = NULL; @@ -2161,9 +2165,27 @@ RenderTargetBarrier* p_rt_barriers) for (uint32_t i = 0; i < buffer_barrier_count; ++i) { - BufferBarrier* pTrans = &p_buffer_barriers[i]; - const DBufferVulkan& bufferRef = GetResource(_vertexBuffers, pTrans->BufferId); - VkBuffer pBuffer = bufferRef.Buffer.Buffer; + BufferBarrier* pTrans = &p_buffer_barriers[i]; + + const auto resourceType = ResourceId(pTrans->BufferId).First(); + const auto index = ResourceId(pTrans->BufferId).Value(); + DBufferVulkan* bufferPtr{}; + switch (resourceType) + { + case EResourceType::UNIFORM_BUFFER: + bufferPtr = &_uniformBuffers.at(index); + break; + case EResourceType::VERTEX_INDEX_BUFFER: + bufferPtr = &_vertexBuffers.at(index); + break; + case EResourceType::TRANSFER: + bufferPtr = &_transferBuffers.at(index); + break; + default: + check(0); // Invalid type + break; + } + VkBuffer pBuffer = bufferPtr->Buffer.Buffer; VkBufferMemoryBarrier* pBufferBarrier = NULL; if (EResourceState::UNORDERED_ACCESS == pTrans->CurrentState && EResourceState::UNORDERED_ACCESS == pTrans->NewState) @@ -2339,11 +2361,11 @@ RenderTargetBarrier* p_rt_barriers) } } - VkPipelineStageFlags srcStageMask = VkUtils::determinePipelineStageFlags(srcAccessFlags, EQueueType::QUEUE_GRAPHICS); - VkPipelineStageFlags dstStageMask = VkUtils::determinePipelineStageFlags(dstAccessFlags, EQueueType::QUEUE_GRAPHICS); + auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); + VkPipelineStageFlags srcStageMask = VkUtils::determinePipelineStageFlags(srcAccessFlags, commandBufferRef.Type); + VkPipelineStageFlags dstStageMask = VkUtils::determinePipelineStageFlags(dstAccessFlags, commandBufferRef.Type); { - auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); check(commandBufferRef.IsRecording); // Must be in recording state // If previous active render pass end it if (commandBufferRef.ActiveRenderPass) diff --git a/src/backend/vulkan/VulkanContext.h b/src/backend/vulkan/VulkanContext.h index 8eaa795..77c51f8 100644 --- a/src/backend/vulkan/VulkanContext.h +++ b/src/backend/vulkan/VulkanContext.h @@ -87,12 +87,13 @@ struct DCommandPoolVulkan : public DResource VkCommandPool Pool{}; EQueueType Type; uint32_t QueueFamilyIndex{}; + EQueueType QueueType{}; }; struct DCommandBufferVulkan : public DResource { VkCommandBuffer Cmd{}; - EQueueType Type; + EQueueType Type{}; uint32_t QueueFamilyIndex{}; bool IsRecording{}; VkRenderPass ActiveRenderPass{}; @@ -149,9 +150,10 @@ struct DSamplerVulkan : public DResource struct DQueueVulkan : public DResource { - uint32_t QueueFamilyIndex{}; - uint32_t QueueIndex{}; - VkQueue QueuePtr{}; + uint32_t QueueFamilyIndex{}; + uint32_t QueueIndex{}; + VkQueue QueuePtr{}; + EQueueType Type{}; }; class VulkanContext final : public IContext diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c6e0eff..502ddbd 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -16,6 +16,7 @@ set(SOURCES "integration/vulkan/VertexBufferUpload.test.cpp" "integration/vulkan/UniformBufferUpload.test.cpp" "integration/vulkan/ImageUpload.test.cpp" + "integration/vulkan/AcquireAndRelease.test.cpp" ) @@ -36,7 +37,7 @@ add_executable(tests target_sources(tests PRIVATE ${GTEST_DIR} ${GTEST_DIR_INCLUDE}${SOURCES}) -target_link_libraries(tests FoxFury GTest::gtest_main GTest::gmock volk VulkanMemoryAllocator glfw) +target_link_libraries(tests FoxFury GTest::gtest_main volk VulkanMemoryAllocator glfw) set_target_properties(tests PROPERTIES RUNTIME_OUTPUT_DIRECTORY "bin" diff --git a/tests/integration/vulkan/AcquireAndRelease.test.cpp b/tests/integration/vulkan/AcquireAndRelease.test.cpp new file mode 100644 index 0000000..1e91e8f --- /dev/null +++ b/tests/integration/vulkan/AcquireAndRelease.test.cpp @@ -0,0 +1,139 @@ +#include "WindowFixture.h" + +#include "ExtractImage.h" +#include "backend/vulkan/ResourceTransfer.h" +#include "backend/vulkan/VulkanContext.h" +#include "backend/vulkan/VulkanContextFactory.h" +#include "backend/vulkan/VulkanDevice13.h" + +#include + +TEST_F(WindowFixture, ShouldCorrectlyReleaseAndAcquireResources) +{ + constexpr std::array data{ + 0xff, + 0, + 0, + 0xff, + 0, + 0xff, + 0, + 0xff, + 0xff, + 0, + 0, + 0xff, + 0, + 0xff, + 0, + 0xff, + }; + + Fox::DContextConfig config; + config.warningFunction = &WarningAssert; + config.stagingBufferSize = 10 * 1024 * 1024; // 10mb + + Fox::IContext* context = Fox::CreateVulkanContext(&config); + ASSERT_NE(context, nullptr); + const auto graphicsQueue = context->FindQueue(Fox::EQueueType::QUEUE_GRAPHICS); + const auto transferQueue = context->FindQueue(Fox::EQueueType::QUEUE_TRANSFER); + ASSERT_NE(graphicsQueue, transferQueue); + + uint32_t img = context->CreateImage(Fox::EFormat::R8G8B8A8_UNORM, 2, 2, 1); + uint32_t buf = context->CreateBuffer(12, Fox::EResourceType::VERTEX_INDEX_BUFFER, Fox::EMemoryUsage::RESOURCE_MEMORY_USAGE_GPU_ONLY); + + { + uint32_t stagingBuf = context->CreateBuffer(data.size(), Fox::EResourceType::TRANSFER, Fox::EMemoryUsage::RESOURCE_MEMORY_USAGE_CPU_TO_GPU); + + // Upload something to img and buf - so the ownership is acquired for the transfer queue + { + const auto pool = context->CreateCommandPool(transferQueue); + const auto cmd = context->CreateCommandBuffer(pool); + + context->BeginCommandBuffer(cmd); + { + Fox::TextureBarrier barrier{}; + barrier.ImageId = img; + barrier.CurrentState = Fox::EResourceState::UNDEFINED; + barrier.NewState = Fox::EResourceState::COPY_DEST; + + Fox::BufferBarrier bufBarrier{}; + bufBarrier.BufferId = buf; + bufBarrier.CurrentState = Fox::EResourceState::UNDEFINED; + bufBarrier.NewState = Fox::EResourceState::COPY_DEST; + context->ResourceBarrier(cmd, 1, &bufBarrier, 1, &barrier, 0, nullptr); + + context->CopyImage(cmd, img, 2, 2, 0, stagingBuf, 0); + } + { + // Release ownership + Fox::TextureBarrier barrier{}; + barrier.ImageId = img; + barrier.CurrentState = Fox::EResourceState::COPY_DEST; + barrier.NewState = Fox::EResourceState::PIXEL_SHADER_RESOURCE; + barrier.TransferOwnership = Fox::ETransferOwnership::RELEASE; + barrier.SrcQueue = transferQueue; + barrier.DstQueue = graphicsQueue; + + Fox::BufferBarrier bufBarrier{}; + bufBarrier.BufferId = buf; + bufBarrier.CurrentState = Fox::EResourceState::COPY_DEST; + bufBarrier.NewState = Fox::EResourceState::VERTEX_AND_CONSTANT_BUFFER; + bufBarrier.TransferOwnership = Fox::ETransferOwnership::RELEASE; + bufBarrier.SrcQueue = transferQueue; + bufBarrier.DstQueue = graphicsQueue; + context->ResourceBarrier(cmd, 1, &bufBarrier, 1, &barrier, 0, nullptr); + } + + context->EndCommandBuffer(cmd); + + const auto fence = context->CreateFence(false); + context->QueueSubmit(transferQueue, {}, {}, { cmd }, fence); + context->WaitForFence(fence, 0xFFFFFFFF); + context->DestroyCommandBuffer(cmd); + context->DestroyCommandPool(pool); + context->DestroyFence(fence); + } + + // Acquire on the graphics queue + { + const auto pool = context->CreateCommandPool(graphicsQueue); + const auto cmd = context->CreateCommandBuffer(pool); + context->BeginCommandBuffer(cmd); + + Fox::TextureBarrier imgBarrier{}; + imgBarrier.ImageId = img; + imgBarrier.CurrentState = Fox::EResourceState::COPY_DEST; + imgBarrier.NewState = Fox::EResourceState::PIXEL_SHADER_RESOURCE; + imgBarrier.TransferOwnership = Fox::ACQUIRE; + imgBarrier.SrcQueue = transferQueue; + imgBarrier.DstQueue = graphicsQueue; + + Fox::BufferBarrier bufBarrier{}; + bufBarrier.BufferId = buf; + bufBarrier.CurrentState = Fox::EResourceState::COPY_DEST; + bufBarrier.NewState = Fox::EResourceState::VERTEX_AND_CONSTANT_BUFFER; + bufBarrier.TransferOwnership = Fox::ACQUIRE; + bufBarrier.SrcQueue = transferQueue; + bufBarrier.DstQueue = graphicsQueue; + + context->ResourceBarrier(cmd, 1, &bufBarrier, 1, &imgBarrier, 0, nullptr); + context->EndCommandBuffer(cmd); + + const auto fence = context->CreateFence(false); + context->QueueSubmit(graphicsQueue, {}, {}, { cmd }, fence); + context->WaitForFence(fence, 0xFFFFFFFF); + + context->DestroyCommandBuffer(cmd); + context->DestroyCommandPool(pool); + context->DestroyFence(fence); + } + + context->DestroyBuffer(stagingBuf); + } + + context->DestroyBuffer(buf); + context->DestroyImage(img); + + delete context; +} diff --git a/tests/integration/vulkan/ImageUpload.test.cpp b/tests/integration/vulkan/ImageUpload.test.cpp index 2e7bf46..daf65da 100644 --- a/tests/integration/vulkan/ImageUpload.test.cpp +++ b/tests/integration/vulkan/ImageUpload.test.cpp @@ -38,31 +38,31 @@ TEST_F(WindowFixture, ShouldCorrectlyUploadImage) uint32_t img = context->CreateImage(Fox::EFormat::R8G8B8A8_UNORM, 2, 2, 1); - { - uint32_t stagingBuf = context->CreateBuffer(data.size(), Fox::EResourceType::TRANSFER, Fox::EMemoryUsage::RESOURCE_MEMORY_USAGE_CPU_TO_GPU); - const auto transferQueue = context->FindQueue(Fox::EQueueType::QUEUE_TRANSFER); + //{ + // uint32_t stagingBuf = context->CreateBuffer(data.size(), Fox::EResourceType::TRANSFER, Fox::EMemoryUsage::RESOURCE_MEMORY_USAGE_CPU_TO_GPU); + // const auto transferQueue = context->FindQueue(Fox::EQueueType::QUEUE_TRANSFER); - const auto pool = context->CreateCommandPool(transferQueue); - const auto cmd = context->CreateCommandBuffer(pool); - context->BeginCommandBuffer(cmd); - Fox::TextureBarrier barrier; - barrier.ImageId = img; - barrier.CurrentState = Fox::EResourceState::UNDEFINED; - barrier.NewState = Fox::EResourceState::COPY_DEST; - context->ResourceBarrier(cmd, 0, nullptr, 1, &barrier, 0, nullptr); - context->CopyImage(cmd, img, 2, 2, 0, stagingBuf, 0); - context->EndCommandBuffer(cmd); + // const auto pool = context->CreateCommandPool(transferQueue); + // const auto cmd = context->CreateCommandBuffer(pool); + // context->BeginCommandBuffer(cmd); + // Fox::TextureBarrier barrier; + // barrier.ImageId = img; + // barrier.CurrentState = Fox::EResourceState::UNDEFINED; + // barrier.NewState = Fox::EResourceState::COPY_DEST; + // context->ResourceBarrier(cmd, 0, nullptr, 1, &barrier, 0, nullptr); + // context->CopyImage(cmd, img, 2, 2, 0, stagingBuf, 0); + // context->EndCommandBuffer(cmd); - const auto fence = context->CreateFence(false); - context->QueueSubmit({}, {}, { cmd }, fence); - context->WaitForFence(fence, 0xFFFFFFFF); - context->DestroyFence(fence); - context->DestroyCommandBuffer(cmd); - context->DestroyCommandPool(pool); - context->DestroyBuffer(stagingBuf); - } + // const auto fence = context->CreateFence(false); + // context->QueueSubmit({}, {}, { cmd }, fence); + // context->WaitForFence(fence, 0xFFFFFFFF); + // context->DestroyFence(fence); + // context->DestroyCommandBuffer(cmd); + // context->DestroyCommandPool(pool); + // context->DestroyBuffer(stagingBuf); + //} - ASSERT_NE(img, 0); + //ASSERT_NE(img, 0); //{ // Fox::VulkanContext* vkContext = static_cast(context); From b37cc0fcf16d22b9e537d22f3a797caeb89abc19 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Tue, 26 Dec 2023 14:58:37 +0100 Subject: [PATCH 05/58] fix compilation --- include/IContext.h | 4 ++-- src/backend/vulkan/VulkanContext.cpp | 30 +++++++++++++++++++++++----- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/include/IContext.h b/include/IContext.h index 9fe8f7a..00f252f 100644 --- a/include/IContext.h +++ b/include/IContext.h @@ -665,9 +665,9 @@ typedef struct RenderTargetBarrier uint8_t mRelease : 1; uint8_t mQueueType : 5; /// Specifiy whether following barrier targets particular subresource - uint8_t mSubresourceBarrier : 1 {}; + uint8_t mSubresourceBarrier : 1; /// Following values are ignored if mSubresourceBarrier is false - uint8_t mMipLevel : 7 {}; + uint8_t mMipLevel : 7; uint16_t mArrayLayer{}; } RenderTargetBarrier; diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index ba75cdd..f87a01e 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -1415,11 +1415,31 @@ VulkanContext::UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t setIndex, for (uint32_t i = 0; i < descriptorCount; i++) { - VkDescriptorImageInfo& img = imageInfo[imageInfoCount++]; - const DImageVulkan& imageRef = GetResource(_images, param->Textures[i]); - img.imageView = imageRef.View; - img.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - img.sampler = NULL; + VkDescriptorImageInfo& img = imageInfo[imageInfoCount++]; + const auto resourceType{ static_cast(ResourceId(param->Textures[i]).First()) }; + switch (resourceType) + { + case EResourceType::IMAGE: + { + const DImageVulkan& imageRef = GetResource(_images, param->Textures[i]); + img.imageView = imageRef.View; + img.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + img.sampler = NULL; + } + break; + case EResourceType::RENDER_TARGET: + { + const DRenderTargetVulkan& imageRef = + GetResource(_renderTargets, param->Textures[i]); + img.imageView = imageRef.View; + img.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + img.sampler = NULL; + } + break; + default: + check(0); // Invalid resource type + break; + } } } break; From 796bc2d8b80f5890a5493d99e19ade16bc40f97a Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Mon, 8 Jan 2024 12:29:59 +0100 Subject: [PATCH 06/58] Bug fix deleting pip layout would not condider caching also for set layouts --- src/backend/vulkan/VulkanContext.cpp | 115 ++++++++++++++++----------- 1 file changed, 69 insertions(+), 46 deletions(-) diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index 2a31823..5d9fa9b 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -1092,7 +1092,8 @@ VulkanContext::CreateRootSignature(const ShaderLayout& layout) std::map setIndexToSetLayout; for (const auto& setPair : layout.SetsLayout) { - const auto descriptorSetBindings = VkUtils::convertDescriptorBindings(setPair.second); + const auto descriptorSetBindings = VkUtils::convertDescriptorBindings(setPair.second); + // Can return already cached DescriptorSet layout if exists rootSignature.DescriptorSetLayouts[setPair.first] = Device.CreateDescriptorSetLayout(descriptorSetBindings); descriptorSetLayout.push_back(rootSignature.DescriptorSetLayouts[setPair.first]); @@ -1215,13 +1216,35 @@ VulkanContext::DestroyRootSignature(uint32_t rootSignatureId) { DRootSignature& rootSignature = GetResource(_rootSignatures, rootSignatureId); - Device.DestroyPipelineLayout(rootSignature.PipelineLayout); - - for (uint32_t i = 0; i < (uint32_t)EDescriptorFrequency::MAX_COUNT; i++) + // Check if the pipeline layout is not shared among other root signatures + const auto count{ std::count_if(_rootSignatures.begin(), _rootSignatures.end(), [rootSignature](const DRootSignature& sig) { return sig.PipelineLayout == rootSignature.PipelineLayout; }) }; + if (count == 1) { - if (rootSignature.DescriptorSetLayouts[i] != nullptr) + Device.DestroyPipelineLayout(rootSignature.PipelineLayout); + + // Only destroy non shared rootSignatures when pipeline layout can be destroyed + for (uint32_t i = 0; i < (uint32_t)EDescriptorFrequency::MAX_COUNT; i++) { - Device.DestroyDescriptorSetLayout(rootSignature.DescriptorSetLayouts[i]); + if (rootSignature.DescriptorSetLayouts[i] != nullptr) + { + // Check if the descriptor set layout is not shared among other root signatures + const auto usageCount{ std::count_if( + _rootSignatures.begin(), _rootSignatures.end(), [descriptorSetLayout = rootSignature.DescriptorSetLayouts[i]](const DRootSignature& sig) { + for (uint32_t i = 0; i < (uint32_t)EDescriptorFrequency::MAX_COUNT; i++) + { + if (sig.DescriptorSetLayouts[i] == descriptorSetLayout) + { + return true; + } + } + return false; + }) }; + // If not referenced in other root signatures + if (usageCount == 1) + { + Device.DestroyDescriptorSetLayout(rootSignature.DescriptorSetLayouts[i]); + } + } } } @@ -2626,19 +2649,19 @@ VulkanContext::_getInstanceSupportedExtensions(const std::vector& e const auto validExtentionsNames = VkUtils::convertExtensionPropertiesToNames(validExtensions); std::vector supportedExtensions = VkUtils::filterInclusive(extentions, validExtentionsNames); { - const std::string out = "Available extensions requested:" + std::to_string(supportedExtensions.size()) + "/" + std::to_string(extentions.size()); - Log(out); + // const std::string out = "Available extensions requested:" + std::to_string(supportedExtensions.size()) + "/" + std::to_string(extentions.size()); + // Log(out); // Print not supported validation layers - if (supportedExtensions.size() != extentions.size()) - { - Log("Unsupported instance extensions"); - std::vector unsupportedExtensions = VkUtils::filterExclusive(validExtentionsNames, extentions); - for (const char* extensionName : unsupportedExtensions) - { - Log(extensionName); - } - } + // if (supportedExtensions.size() != extentions.size()) + // { + // Log("Unsupported instance extensions"); + // std::vector unsupportedExtensions = VkUtils::filterExclusive(validExtentionsNames, extentions); + // for (const char* extensionName : unsupportedExtensions) + // { + // Log(extensionName); + // } + // } } return supportedExtensions; } @@ -2651,19 +2674,19 @@ VulkanContext::_getInstanceSupportedValidationLayers(const std::vector supportedValidationLayers = VkUtils::filterInclusive(validationLayers, layerNames); { - const std::string out = "Available validation layers requested:" + std::to_string(supportedValidationLayers.size()) + "/" + std::to_string(validationLayers.size()); - Log(out); - // Print not supported validation layers - if (supportedValidationLayers.size() != validationLayers.size()) - { - Log("Unsupported instance validation layers:"); - - std::vector unsupportedValidationLayers = VkUtils::filterExclusive(layerNames, validationLayers); - for (const char* layerName : unsupportedValidationLayers) - { - Log(layerName); - } - } + // const std::string out = "Available validation layers requested:" + std::to_string(supportedValidationLayers.size()) + "/" + std::to_string(validationLayers.size()); + // Log(out); + // Print not supported validation layers + // if (supportedValidationLayers.size() != validationLayers.size()) + // { + // Log("Unsupported instance validation layers:"); + + // std::vector unsupportedValidationLayers = VkUtils::filterExclusive(layerNames, validationLayers); + // for (const char* layerName : unsupportedValidationLayers) + // { + // Log(layerName); + // } + // } } return supportedValidationLayers; @@ -2692,18 +2715,18 @@ VulkanContext::_getDeviceSupportedExtensions(VkPhysicalDevice physicalDevice, co const auto extensionNames = VkUtils::convertExtensionPropertiesToNames(validExtensions); std::vector deviceSupportedExtensions = VkUtils::filterInclusive(extentions, extensionNames); - const std::string out = "Available device extensions requested:" + std::to_string(deviceSupportedExtensions.size()) + "/" + std::to_string(extentions.size()); - Log(out); + // const std::string out = "Available device extensions requested:" + std::to_string(deviceSupportedExtensions.size()) + "/" + std::to_string(extentions.size()); + // Log(out); // Print not supported validation layers if (deviceSupportedExtensions.size() != extentions.size()) { - Log("Unsupported device extensions:"); - std::vector deviceUnsupportedExtensions = VkUtils::filterExclusive(extensionNames, extentions); - for (const char* extensionName : deviceUnsupportedExtensions) - { - Log(extensionName); - } + // Log("Unsupported device extensions:"); + // std::vector deviceUnsupportedExtensions = VkUtils::filterExclusive(extensionNames, extentions); + // for (const char* extensionName : deviceUnsupportedExtensions) + // { + // Log(extensionName); + // } } return deviceSupportedExtensions; @@ -2716,18 +2739,18 @@ VulkanContext::_getDeviceSupportedValidationLayers(VkPhysicalDevice physicalDevi const auto validExtentionsNames = VkUtils::convertExtensionPropertiesToNames(validExtentions); std::vector deviceSupportedValidationLayers = VkUtils::filterInclusive(validationLayers, validExtentionsNames); - const std::string out = "Available device validation layers requested:" + std::to_string(deviceSupportedValidationLayers.size()) + "/" + std::to_string(validationLayers.size()); - Log(out); + // const std::string out = "Available device validation layers requested:" + std::to_string(deviceSupportedValidationLayers.size()) + "/" + std::to_string(validationLayers.size()); + // Log(out); // Print not supported validation layers if (deviceSupportedValidationLayers.size() != validationLayers.size()) { - Log("Unsupported device validation layers:"); - std::vector deviceUnsupportedValidationLayers = VkUtils::filterExclusive(validExtentionsNames, validationLayers); - for (const char* layerName : deviceUnsupportedValidationLayers) - { - Log(layerName); - } + // Log("Unsupported device validation layers:"); + // std::vector deviceUnsupportedValidationLayers = VkUtils::filterExclusive(validExtentionsNames, validationLayers); + // for (const char* layerName : deviceUnsupportedValidationLayers) + // { + // Log(layerName); + // } } return deviceSupportedValidationLayers; From 9d1307a16eb1321f1090a8a282ddcf5919b83d47 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Mon, 8 Jan 2024 12:30:08 +0100 Subject: [PATCH 07/58] Missing error case --- src/backend/vulkan/UtilsVK.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/backend/vulkan/UtilsVK.h b/src/backend/vulkan/UtilsVK.h index 9e04386..e824230 100644 --- a/src/backend/vulkan/UtilsVK.h +++ b/src/backend/vulkan/UtilsVK.h @@ -81,6 +81,9 @@ VkErrorString(enum VkResult result) case VK_ERROR_UNKNOWN: return "VK_ERROR_UNKNOWN"; break; + case VK_ERROR_SURFACE_LOST_KHR: + return "VK_ERROR_SURFACE_LOST_KHR"; + break; default: return "UNKNOWN VK ERROR"; break; From 4d751132b64f153320f09bef3cc8b6552e87c5dc Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Sat, 13 Jan 2024 15:59:05 +0100 Subject: [PATCH 08/58] moved tinygltf to fetch content instead of submodule --- .gitmodules | 3 - CMakeLists.txt | 33 +- examples/DepthBuffer/CMakeLists.txt | 18 - examples/DepthBuffer/DepthBuffer.cpp | 381 ------------------ examples/DepthBuffer/buildShaders.bat | 3 - examples/DepthBuffer/fragment.glsl | 20 - examples/DepthBuffer/fragment.spv | Bin 708 -> 0 bytes .../two spinning cubes in cirlce.txt | 0 examples/DepthBuffer/vertex.glsl | 21 - examples/DepthBuffer/vertex.spv | Bin 1640 -> 0 bytes examples/SpinningTriangle/CMakeLists.txt | 18 - .../SpinningTriangle/SpinningTriangle.cpp | 182 --------- examples/SpinningTriangle/buildShaders.bat | 3 - examples/SpinningTriangle/fragment.glsl | 18 - examples/SpinningTriangle/fragment.spv | Bin 452 -> 0 bytes examples/SpinningTriangle/vertex.glsl | 16 - examples/SpinningTriangle/vertex.spv | Bin 1336 -> 0 bytes examples/TexturedQuad/CMakeLists.txt | 18 - examples/TexturedQuad/TexturedQuad.cpp | 345 ---------------- examples/TexturedQuad/buildShaders.bat | 3 - examples/TexturedQuad/fragment.glsl | 20 - examples/TexturedQuad/fragment.spv | Bin 708 -> 0 bytes examples/TexturedQuad/screenshot.jpg | Bin 46405 -> 0 bytes examples/TexturedQuad/vertex.glsl | 16 - examples/TexturedQuad/vertex.spv | Bin 1388 -> 0 bytes thirdparty/tinygltf | 1 - 26 files changed, 22 insertions(+), 1097 deletions(-) delete mode 100644 examples/DepthBuffer/CMakeLists.txt delete mode 100644 examples/DepthBuffer/DepthBuffer.cpp delete mode 100644 examples/DepthBuffer/buildShaders.bat delete mode 100644 examples/DepthBuffer/fragment.glsl delete mode 100644 examples/DepthBuffer/fragment.spv delete mode 100644 examples/DepthBuffer/two spinning cubes in cirlce.txt delete mode 100644 examples/DepthBuffer/vertex.glsl delete mode 100644 examples/DepthBuffer/vertex.spv delete mode 100644 examples/SpinningTriangle/CMakeLists.txt delete mode 100644 examples/SpinningTriangle/SpinningTriangle.cpp delete mode 100644 examples/SpinningTriangle/buildShaders.bat delete mode 100644 examples/SpinningTriangle/fragment.glsl delete mode 100644 examples/SpinningTriangle/fragment.spv delete mode 100644 examples/SpinningTriangle/vertex.glsl delete mode 100644 examples/SpinningTriangle/vertex.spv delete mode 100644 examples/TexturedQuad/CMakeLists.txt delete mode 100644 examples/TexturedQuad/TexturedQuad.cpp delete mode 100644 examples/TexturedQuad/buildShaders.bat delete mode 100644 examples/TexturedQuad/fragment.glsl delete mode 100644 examples/TexturedQuad/fragment.spv delete mode 100644 examples/TexturedQuad/screenshot.jpg delete mode 100644 examples/TexturedQuad/vertex.glsl delete mode 100644 examples/TexturedQuad/vertex.spv delete mode 160000 thirdparty/tinygltf diff --git a/.gitmodules b/.gitmodules index 783bccb..9ebcb5b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,9 +13,6 @@ [submodule "thirdparty/gli"] path = thirdparty/gli url = https://github.com/g-truc/gli.git -[submodule "thirdparty/tinygltf"] - path = thirdparty/tinygltf - url = https://github.com/syoyo/tinygltf.git [submodule "thirdparty/stb"] path = thirdparty/stb url = https://github.com/nothings/stb.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 83b75ab..bee71f4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,11 @@ add_library(${PROJECT_NAME} STATIC "include/main.cpp" ) +option(BUILD_TESTS "Build tests" OFF) +option(BUILD_EXAMPLES "Build examples" OFF) + + + ## Volk add_subdirectory("thirdparty/volk") ## VMA @@ -31,12 +36,23 @@ add_subdirectory("thirdparty/glfw") # GLM add_subdirectory("thirdparty/glm") # GLI -set(GLI_TEST_ENABLED OFF CACHE BOOL "" FORCE) -add_subdirectory("thirdparty/gli") -# TINYGLTF -set(TINYGLTF_HEADER_ONLY ON CACHE BOOL "" FORCE) -set(TINYGLTF_INSTALL OFF CACHE BOOL "" FORCE) -add_subdirectory("thirdparty/tinygltf") +if(BUILD_EXAMPLES) + set(GLI_TEST_ENABLED OFF CACHE BOOL "" FORCE) + add_subdirectory("thirdparty/gli") + # TINYGLTF + set(TINYGLTF_HEADER_ONLY ON CACHE BOOL "" FORCE) + set(TINYGLTF_INSTALL OFF CACHE BOOL "" FORCE) + # Fetch tinygltf from GitHub + include(FetchContent) # once in the project to include the module + FetchContent_Declare( + tinygltf + GIT_REPOSITORY https://github.com/syoyo/tinygltf.git + GIT_TAG v2.8.19 + ) + + # Fetch the content and add it to your CMake project + FetchContent_MakeAvailable(tinygltf) +endif() target_link_libraries(${PROJECT_NAME} PRIVATE volk VulkanMemoryAllocator) @@ -107,11 +123,6 @@ target_sources(${PROJECT_NAME} PRIVATE "${SRC_DIR}/backend/vulkan/VulkanDevice13.cpp" ) - - -option(BUILD_TESTS "Build tests" OFF) -option(BUILD_EXAMPLES "Build examples" OFF) - if(BUILD_EXAMPLES) set(LIB_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/include") FILE(REAL_PATH "thirdparty/stb" STB_INCLUDE_DIR) diff --git a/examples/DepthBuffer/CMakeLists.txt b/examples/DepthBuffer/CMakeLists.txt deleted file mode 100644 index 1b8c49b..0000000 --- a/examples/DepthBuffer/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -cmake_minimum_required(VERSION 3.26.4) -project(DepthBuffer CXX) - -add_executable(${PROJECT_NAME} -"DepthBuffer.cpp" -) - - -target_link_libraries(${PROJECT_NAME} PRIVATE FoxFury glfw glm) - -set_target_properties(${PROJECT_NAME} PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "bin" -) - -#Set the debug working directory -set_target_properties(${PROJECT_NAME} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") - -include_directories(${LIB_INCLUDE_DIR}) \ No newline at end of file diff --git a/examples/DepthBuffer/DepthBuffer.cpp b/examples/DepthBuffer/DepthBuffer.cpp deleted file mode 100644 index 1c16333..0000000 --- a/examples/DepthBuffer/DepthBuffer.cpp +++ /dev/null @@ -1,381 +0,0 @@ -// Copyright RedFox Studio 2022 - -#include - -#include "IContext.h" -#include "backend/vulkan/VulkanContextFactory.h" - -#include - -#define GLFW_INCLUDE_NONE // makes the GLFW header not include any OpenGL or -// OpenGL ES API header.This is useful in combination with an extension loading library. -#include - -#define GLFW_EXPOSE_NATIVE_WIN32 -#include - -#define GLM_DEPTH_ZERO_TO_ONE -#include -#include - -#include -#include -#include - -void -Log(const char* msg) -{ - std::cout << msg << std::endl; -}; - -constexpr uint32_t imageWidth = 32; -constexpr uint32_t imageHeight = 32; -// converter https://notisrac.github.io/FileToCArray/ -// clang-format off -constexpr uint8_t image[] = {0x41, 0x3c, 0x38, 0xff, 0x3a, 0x48, 0x48, 0xff, 0x3a, 0x3f, 0x45, 0xff, 0x40, 0x41, 0x39, 0xff, 0x42, 0x42, 0x44, 0xff, 0x3f, 0x3d, 0x40, 0xff, 0x3c, 0x41, 0x44, 0xff, 0x42, 0x41, 0x3f, 0xff, - 0x3b, 0x43, 0x46, 0xff, 0x47, 0x3e, 0x3f, 0xff, 0x45, 0x3c, 0x35, 0xff, 0x3b, 0x41, 0x3d, 0xff, 0x3c, 0x3f, 0x48, 0xff, 0x3b, 0x40, 0x43, 0xff, 0x44, 0x45, 0x3f, 0xff, 0x43, 0x3b, 0x38, 0xff, - 0x3d, 0x3f, 0x3e, 0xff, 0x43, 0x42, 0x3d, 0xff, 0x44, 0x3f, 0x43, 0xff, 0x3d, 0x43, 0x41, 0xff, 0x40, 0x3d, 0x44, 0xff, 0x40, 0x40, 0x36, 0xff, 0x44, 0x40, 0x3f, 0xff, 0x3c, 0x42, 0x42, 0xff, - 0x3d, 0x42, 0x3e, 0xff, 0x38, 0x42, 0x44, 0xff, 0x3f, 0x3e, 0x3c, 0xff, 0x3f, 0x40, 0x42, 0xff, 0x3d, 0x3e, 0x40, 0xff, 0x3e, 0x43, 0x46, 0xff, 0x3f, 0x3e, 0x3a, 0xff, 0x43, 0x40, 0x3b, 0xff, - 0x48, 0x43, 0x3f, 0xff, 0x32, 0x3e, 0x3e, 0xff, 0x60, 0x3c, 0x26, 0xff, 0x5a, 0x36, 0x14, 0xff, 0x5a, 0x36, 0x1e, 0xff, 0x5e, 0x36, 0x1d, 0xff, 0x5d, 0x3b, 0x20, 0xff, 0x5f, 0x37, 0x1d, 0xff, - 0x5c, 0x3a, 0x21, 0xff, 0x5e, 0x34, 0x1c, 0xff, 0x62, 0x37, 0x17, 0xff, 0x60, 0x3d, 0x1f, 0xff, 0x5d, 0x38, 0x25, 0xff, 0x5b, 0x38, 0x22, 0xff, 0x59, 0x35, 0x15, 0xff, 0x67, 0x3b, 0x20, 0xff, - 0x62, 0x3d, 0x22, 0xff, 0x5a, 0x35, 0x18, 0xff, 0x5c, 0x33, 0x1d, 0xff, 0x5c, 0x3a, 0x1f, 0xff, 0x5e, 0x35, 0x21, 0xff, 0x61, 0x3a, 0x19, 0xff, 0x59, 0x34, 0x1a, 0xff, 0x5e, 0x3c, 0x21, 0xff, - 0x5a, 0x35, 0x18, 0xff, 0x58, 0x3c, 0x26, 0xff, 0x61, 0x3a, 0x1d, 0xff, 0x5c, 0x38, 0x20, 0xff, 0x5f, 0x37, 0x1e, 0xff, 0x5c, 0x39, 0x23, 0xff, 0x40, 0x3e, 0x3f, 0xff, 0x43, 0x42, 0x3e, 0xff, - 0x45, 0x3d, 0x3a, 0xff, 0x3c, 0x46, 0x48, 0xff, 0xe3, 0x6e, 0x21, 0xff, 0xe4, 0x76, 0x1f, 0xff, 0xe2, 0x74, 0x27, 0xff, 0xe0, 0x71, 0x20, 0xff, 0xe1, 0x73, 0x1e, 0xff, 0xde, 0x6f, 0x20, 0xff, - 0xe4, 0x6f, 0x1f, 0xff, 0xe2, 0x72, 0x2a, 0xff, 0xe1, 0x71, 0x1f, 0xff, 0xe4, 0x6f, 0x1f, 0xff, 0xe2, 0x73, 0x21, 0xff, 0xe0, 0x70, 0x24, 0xff, 0xe0, 0x71, 0x1f, 0xff, 0xe0, 0x70, 0x24, 0xff, - 0xe3, 0x6f, 0x1c, 0xff, 0xe3, 0x74, 0x25, 0xff, 0xe2, 0x72, 0x28, 0xff, 0xe4, 0x73, 0x23, 0xff, 0xe2, 0x72, 0x28, 0xff, 0xdf, 0x6f, 0x1d, 0xff, 0xde, 0x72, 0x29, 0xff, 0xde, 0x70, 0x21, 0xff, - 0xe6, 0x72, 0x1f, 0xff, 0xde, 0x74, 0x28, 0xff, 0xe1, 0x6d, 0x18, 0xff, 0xe2, 0x74, 0x27, 0xff, 0xe7, 0x6e, 0x1f, 0xff, 0xdd, 0x6e, 0x26, 0xff, 0x40, 0x3e, 0x43, 0xff, 0x3d, 0x41, 0x42, 0xff, - 0x45, 0x3d, 0x3a, 0xff, 0x37, 0x3e, 0x44, 0xff, 0xff, 0x67, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfb, 0x68, 0x01, 0xff, 0xfd, 0x69, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xff, 0x6a, 0x04, 0xff, - 0xff, 0x6a, 0x00, 0xff, 0xf9, 0x67, 0x04, 0xff, 0xff, 0x6d, 0x05, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfc, 0x68, 0x00, 0xff, 0xff, 0x6a, 0x04, 0xff, 0xfc, 0x68, 0x00, 0xff, 0xfe, 0x69, 0x03, 0xff, - 0xff, 0x69, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, 0xfa, 0x68, 0x03, 0xff, 0xff, 0x67, 0x00, 0xff, 0xff, 0x6a, 0x03, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfe, 0x6c, 0x07, 0xff, 0xff, 0x6c, 0x02, 0xff, - 0xff, 0x64, 0x00, 0xff, 0xff, 0x6e, 0x09, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xfd, 0x68, 0x01, 0xff, 0xff, 0x67, 0x00, 0xff, 0xff, 0x6a, 0x06, 0xff, 0x43, 0x40, 0x49, 0xff, 0x3c, 0x40, 0x43, 0xff, - 0x46, 0x41, 0x3b, 0xff, 0x3a, 0x43, 0x4a, 0xff, 0xff, 0x65, 0x00, 0xff, 0xfc, 0x69, 0x01, 0xff, 0xfd, 0x6a, 0x02, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfb, 0x67, 0x03, 0xff, - 0xfb, 0x66, 0x00, 0xff, 0xfd, 0x6b, 0x06, 0xff, 0xfa, 0x65, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xfd, 0x69, 0x05, 0xff, 0xfe, 0x6c, 0x05, 0xff, 0xff, 0x6c, 0x03, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xff, 0x68, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6f, 0x0b, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfb, 0x68, 0x00, 0xff, 0xfe, 0x6c, 0x00, 0xff, 0xfb, 0x67, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, - 0xff, 0x6a, 0x04, 0xff, 0xf9, 0x64, 0x00, 0xff, 0xff, 0x6d, 0x08, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfc, 0x68, 0x00, 0xff, 0xff, 0x6c, 0x00, 0xff, 0x3e, 0x3d, 0x42, 0xff, 0x40, 0x3e, 0x3f, 0xff, - 0x3d, 0x3c, 0x38, 0xff, 0x3f, 0x44, 0x4a, 0xff, 0xff, 0x67, 0x02, 0xff, 0xff, 0x6a, 0x03, 0xff, 0xff, 0x69, 0x01, 0xff, 0xfd, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x6c, 0x08, 0xff, - 0xfc, 0x6a, 0x03, 0xff, 0xff, 0x6a, 0x01, 0xff, 0xf0, 0x6e, 0x18, 0xff, 0xf2, 0x73, 0x16, 0xff, 0xec, 0x6a, 0x16, 0xff, 0xfb, 0x6a, 0x01, 0xff, 0xf0, 0x6b, 0x0e, 0xff, 0xf3, 0x6d, 0x0e, 0xff, - 0xfd, 0x6a, 0x03, 0xff, 0xff, 0x67, 0x00, 0xff, 0xfd, 0x6b, 0x04, 0xff, 0xf0, 0x6e, 0x0e, 0xff, 0xff, 0x6b, 0x01, 0xff, 0xf0, 0x71, 0x14, 0xff, 0xff, 0x68, 0x00, 0xff, 0xf2, 0x6f, 0x14, 0xff, - 0xee, 0x6b, 0x11, 0xff, 0xe2, 0x70, 0x27, 0xff, 0xfa, 0x68, 0x03, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xfe, 0x6b, 0x01, 0xff, 0xfb, 0x67, 0x00, 0xff, 0x41, 0x42, 0x46, 0xff, 0x45, 0x41, 0x40, 0xff, - 0x39, 0x42, 0x3f, 0xff, 0x44, 0x40, 0x3f, 0xff, 0xfa, 0x67, 0x00, 0xff, 0xfe, 0x65, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfc, 0x6c, 0x00, 0xff, 0xfc, 0x69, 0x01, 0xff, 0xfb, 0x6a, 0x01, 0xff, - 0xf8, 0x6b, 0x01, 0xff, 0xff, 0x66, 0x00, 0xff, 0x86, 0x31, 0x00, 0xff, 0x7e, 0x2b, 0x00, 0xff, 0x8a, 0x2c, 0x00, 0xff, 0xff, 0x6c, 0x02, 0xff, 0x8b, 0x2b, 0x00, 0xff, 0x8b, 0x2f, 0x00, 0xff, - 0xf7, 0x6b, 0x0a, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0x8c, 0x30, 0x00, 0xff, 0xf9, 0x65, 0x00, 0xff, 0x86, 0x2f, 0x00, 0xff, 0xff, 0x65, 0x00, 0xff, 0x86, 0x29, 0x00, 0xff, - 0x86, 0x2d, 0x00, 0xff, 0x61, 0x3b, 0x26, 0xff, 0xff, 0x6b, 0x01, 0xff, 0xfa, 0x65, 0x00, 0xff, 0xff, 0x6f, 0x03, 0xff, 0xfb, 0x6b, 0x00, 0xff, 0x3a, 0x42, 0x45, 0xff, 0x3e, 0x3d, 0x38, 0xff, - 0x3b, 0x44, 0x43, 0xff, 0x44, 0x3f, 0x3c, 0xff, 0xfd, 0x6b, 0x04, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xf9, 0x6b, 0x00, 0xff, 0xfd, 0x6b, 0x04, 0xff, 0xfc, 0x6a, 0x00, 0xff, - 0xf8, 0x6b, 0x01, 0xff, 0xff, 0x68, 0x00, 0xff, 0xcc, 0x74, 0x34, 0xff, 0xce, 0x79, 0x38, 0xff, 0xd6, 0x77, 0x37, 0xff, 0xfd, 0x66, 0x00, 0xff, 0xd4, 0x77, 0x2a, 0xff, 0xcf, 0x75, 0x39, 0xff, - 0xfb, 0x6c, 0x0c, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x66, 0x00, 0xff, 0xd1, 0x76, 0x2f, 0xff, 0xff, 0x69, 0x02, 0xff, 0xcf, 0x78, 0x35, 0xff, 0xff, 0x67, 0x00, 0xff, 0xd1, 0x77, 0x3b, 0xff, - 0xd1, 0x75, 0x32, 0xff, 0x3f, 0x3e, 0x46, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x6d, 0x05, 0xff, 0xfc, 0x64, 0x00, 0xff, 0xfe, 0x6c, 0x00, 0xff, 0x3b, 0x43, 0x46, 0xff, 0x42, 0x3f, 0x3a, 0xff, - 0x40, 0x41, 0x3c, 0xff, 0x3e, 0x40, 0x3b, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfc, 0x6b, 0x00, 0xff, 0xff, 0x6a, 0x03, 0xff, 0xfb, 0x6a, 0x01, 0xff, 0xfc, 0x6b, 0x02, 0xff, 0xff, 0x6a, 0x00, 0xff, - 0xfc, 0x6b, 0x00, 0xff, 0xff, 0x67, 0x00, 0xff, 0xef, 0x6e, 0x10, 0xff, 0xee, 0x6f, 0x0e, 0xff, 0xf2, 0x6d, 0x12, 0xff, 0xff, 0x68, 0x00, 0xff, 0xef, 0x6f, 0x0c, 0xff, 0xec, 0x6e, 0x1a, 0xff, - 0xff, 0x69, 0x02, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xeb, 0x70, 0x10, 0xff, 0xfd, 0x6a, 0x03, 0xff, 0xec, 0x70, 0x0e, 0xff, 0xff, 0x68, 0x00, 0xff, 0xee, 0x6e, 0x13, 0xff, - 0xf0, 0x6b, 0x0e, 0xff, 0x43, 0x43, 0x4b, 0xff, 0xf6, 0x68, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x6d, 0x00, 0xff, 0xfc, 0x69, 0x00, 0xff, 0x3f, 0x3f, 0x47, 0xff, 0x42, 0x3f, 0x3a, 0xff, - 0x47, 0x42, 0x3f, 0xff, 0x3c, 0x42, 0x3e, 0xff, 0xff, 0x68, 0x00, 0xff, 0xf8, 0x6b, 0x01, 0xff, 0xfe, 0x69, 0x03, 0xff, 0xff, 0x6b, 0x05, 0xff, 0xfc, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xfc, 0x6b, 0x02, 0xff, 0xff, 0x67, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xfc, 0x69, 0x09, 0xff, - 0xff, 0x68, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xf7, 0x6d, 0x02, 0xff, 0xfd, 0x6a, 0x03, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, - 0xff, 0x6c, 0x05, 0xff, 0x5c, 0x36, 0x21, 0xff, 0xfd, 0x6c, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfd, 0x65, 0x00, 0xff, 0xfe, 0x6b, 0x04, 0xff, 0x40, 0x3d, 0x44, 0xff, 0x48, 0x43, 0x40, 0xff, - 0x44, 0x3e, 0x40, 0xff, 0x38, 0x43, 0x3f, 0xff, 0xff, 0x6a, 0x03, 0xff, 0xfa, 0x6c, 0x00, 0xff, 0xff, 0x69, 0x02, 0xff, 0xff, 0x68, 0x06, 0xff, 0xff, 0x6c, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, - 0xfa, 0x6b, 0x05, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xf9, 0x6c, 0x02, 0xff, 0xff, 0x67, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, - 0xfd, 0x6a, 0x02, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xf7, 0x6c, 0x03, 0xff, 0xfc, 0x6b, 0x02, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, - 0xf7, 0x69, 0x03, 0xff, 0xe8, 0x72, 0x1b, 0xff, 0xfe, 0x68, 0x00, 0xff, 0xff, 0x6a, 0x03, 0xff, 0xff, 0x6c, 0x07, 0xff, 0xfd, 0x6b, 0x08, 0xff, 0x40, 0x3e, 0x43, 0xff, 0x3f, 0x3e, 0x3c, 0xff, - 0x44, 0x3d, 0x44, 0xff, 0x37, 0x40, 0x3b, 0xff, 0xff, 0x6a, 0x09, 0xff, 0xfd, 0x6c, 0x00, 0xff, 0xff, 0x69, 0x02, 0xff, 0xf3, 0x68, 0x15, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xfd, 0x68, 0x01, 0xff, - 0xfa, 0x6a, 0x07, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfa, 0x6b, 0x03, 0xff, 0xff, 0x67, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, - 0xfe, 0x69, 0x02, 0xff, 0xfe, 0x69, 0x02, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xf9, 0x6b, 0x05, 0xff, 0xfe, 0x69, 0x02, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, - 0xf8, 0x6a, 0x04, 0xff, 0xff, 0x66, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xfb, 0x68, 0x01, 0xff, 0xfd, 0x68, 0x04, 0xff, 0xfb, 0x6c, 0x06, 0xff, 0x44, 0x3f, 0x43, 0xff, 0x40, 0x3e, 0x3f, 0xff, - 0x42, 0x3f, 0x46, 0xff, 0x3f, 0x40, 0x3a, 0xff, 0xfc, 0x68, 0x08, 0xff, 0xfc, 0x6a, 0x00, 0xff, 0xfc, 0x69, 0x01, 0xff, 0xd3, 0x73, 0x39, 0xff, 0xff, 0x71, 0x03, 0xff, 0xfc, 0x69, 0x02, 0xff, - 0xfa, 0x6b, 0x03, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfc, 0x6b, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, - 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x02, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfc, 0x6a, 0x07, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, - 0xff, 0x6e, 0x01, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, 0xfe, 0x6c, 0x05, 0xff, 0xff, 0x6f, 0x04, 0xff, 0xfa, 0x69, 0x00, 0xff, 0x3f, 0x3e, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x40, 0x3f, 0x44, 0xff, 0x43, 0x42, 0x3e, 0xff, 0xfd, 0x69, 0x07, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xff, 0x70, 0x06, 0xff, 0x65, 0x2d, 0x0c, 0xff, 0xf8, 0x69, 0x00, 0xff, 0xfc, 0x67, 0x01, 0xff, - 0xfd, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfc, 0x6b, 0x02, 0xff, 0xfe, 0x69, 0x02, 0xff, 0xfc, 0x6b, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, - 0xff, 0x67, 0x00, 0xff, 0xff, 0x69, 0x02, 0xff, 0xff, 0x68, 0x02, 0xff, 0xfd, 0x69, 0x05, 0xff, 0xff, 0x67, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, - 0xfd, 0x66, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfa, 0x67, 0x00, 0xff, 0xfd, 0x6c, 0x03, 0xff, 0xfb, 0x69, 0x00, 0xff, 0xff, 0x6e, 0x00, 0xff, 0x40, 0x40, 0x40, 0xff, 0x40, 0x40, 0x42, 0xff, - 0x3e, 0x3d, 0x3b, 0xff, 0x41, 0x41, 0x43, 0xff, 0xfe, 0x6b, 0x03, 0xff, 0xfe, 0x68, 0x00, 0xff, 0xfc, 0x64, 0x00, 0xff, 0x52, 0x46, 0x38, 0xff, 0xfc, 0x69, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, - 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x68, 0x02, 0xff, 0xfc, 0x6b, 0x02, 0xff, 0xfe, 0x6b, 0x00, 0xff, 0xfa, 0x6a, 0x09, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, - 0xfd, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfd, 0x69, 0x07, 0xff, 0xfc, 0x6b, 0x00, 0xff, 0xff, 0x67, 0x00, 0xff, 0xfc, 0x6b, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfc, 0x6b, 0x00, 0xff, - 0xff, 0x6a, 0x02, 0xff, 0xfd, 0x6b, 0x06, 0xff, 0xff, 0x6c, 0x02, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x6d, 0x00, 0xff, 0xfa, 0x66, 0x00, 0xff, 0x3e, 0x42, 0x45, 0xff, 0x3f, 0x40, 0x3a, 0xff, - 0x42, 0x41, 0x3c, 0xff, 0x41, 0x40, 0x46, 0xff, 0xfd, 0x69, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, 0x39, 0x3f, 0x3d, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6a, 0x03, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xfa, 0x6a, 0x0a, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, - 0xfd, 0x6a, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xfc, 0x6a, 0x07, 0xff, 0xfc, 0x6c, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfa, 0x6c, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, - 0xff, 0x68, 0x00, 0xff, 0xfb, 0x69, 0x06, 0xff, 0xfe, 0x6b, 0x01, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xff, 0x64, 0x00, 0xff, 0xfe, 0x6c, 0x00, 0xff, 0x40, 0x41, 0x43, 0xff, 0x41, 0x41, 0x3f, 0xff, - 0x42, 0x3e, 0x3b, 0xff, 0x41, 0x41, 0x43, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x68, 0x01, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0x39, 0x3f, 0x3d, 0xff, 0xfe, 0x6e, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, - 0xfc, 0x6b, 0x02, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xf7, 0x6c, 0x07, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, - 0xfd, 0x6b, 0x00, 0xff, 0xf9, 0x6c, 0x02, 0xff, 0xfd, 0x6a, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xf9, 0x6c, 0x02, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xff, 0x68, 0x00, 0xff, 0xfc, 0x6a, 0x03, 0xff, 0xfc, 0x69, 0x00, 0xff, 0xfc, 0x6b, 0x02, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xf7, 0x6b, 0x00, 0xff, 0x45, 0x40, 0x3a, 0xff, 0x3c, 0x3d, 0x42, 0xff, - 0x40, 0x40, 0x3e, 0xff, 0x43, 0x42, 0x47, 0xff, 0xff, 0x67, 0x00, 0xff, 0xfe, 0x69, 0x03, 0xff, 0xfe, 0x6b, 0x03, 0xff, 0x5f, 0x3d, 0x21, 0xff, 0xfa, 0x6a, 0x00, 0xff, 0xff, 0x6b, 0x04, 0xff, - 0xfc, 0x6a, 0x03, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xf9, 0x6b, 0x05, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, - 0xff, 0x69, 0x00, 0xff, 0xfa, 0x6b, 0x05, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfa, 0x6b, 0x03, 0xff, 0xfd, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, - 0xff, 0x6b, 0x00, 0xff, 0xec, 0x6b, 0x10, 0xff, 0xff, 0x6b, 0x01, 0xff, 0xfe, 0x6b, 0x04, 0xff, 0xff, 0x65, 0x00, 0xff, 0xf8, 0x6e, 0x03, 0xff, 0x49, 0x42, 0x3c, 0xff, 0x43, 0x41, 0x4c, 0xff, - 0x39, 0x3f, 0x3f, 0xff, 0x3e, 0x41, 0x46, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xdd, 0x6e, 0x1d, 0xff, 0xfe, 0x6c, 0x00, 0xff, 0xfe, 0x66, 0x01, 0xff, - 0xfd, 0x6a, 0x02, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x69, 0x02, 0xff, 0xfc, 0x6a, 0x07, 0xff, 0xff, 0x67, 0x00, 0xff, 0xff, 0x69, 0x02, 0xff, 0xfd, 0x69, 0x05, 0xff, - 0xff, 0x67, 0x00, 0xff, 0xfe, 0x69, 0x05, 0xff, 0xff, 0x68, 0x03, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfa, 0x6b, 0x05, 0xff, 0xfc, 0x6a, 0x03, 0xff, 0xff, 0x68, 0x00, 0xff, - 0xf9, 0x68, 0x00, 0xff, 0x91, 0x32, 0x00, 0xff, 0xfc, 0x68, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x6a, 0x05, 0xff, 0xf7, 0x68, 0x00, 0xff, 0x42, 0x3e, 0x3b, 0xff, 0x42, 0x3d, 0x43, 0xff, - 0x40, 0x45, 0x49, 0xff, 0x3f, 0x40, 0x45, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xfd, 0x66, 0x00, 0xff, 0xe3, 0x72, 0x22, 0xff, 0xfe, 0x68, 0x00, 0xff, 0xff, 0x6b, 0x07, 0xff, - 0xfd, 0x6a, 0x02, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfe, 0x69, 0x03, 0xff, 0xfd, 0x69, 0x05, 0xff, 0xff, 0x67, 0x00, 0xff, 0xff, 0x68, 0x02, 0xff, 0xfe, 0x68, 0x07, 0xff, - 0xff, 0x67, 0x00, 0xff, 0xff, 0x67, 0x03, 0xff, 0xff, 0x68, 0x05, 0xff, 0xff, 0x67, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfd, 0x6a, 0x03, 0xff, 0xfa, 0x6b, 0x05, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xfb, 0x6a, 0x00, 0xff, 0xb6, 0x7a, 0x56, 0xff, 0xff, 0x6d, 0x02, 0xff, 0xff, 0x66, 0x00, 0xff, 0xff, 0x67, 0x06, 0xff, 0xfc, 0x69, 0x02, 0xff, 0x43, 0x43, 0x43, 0xff, 0x41, 0x3c, 0x40, 0xff, - 0x3b, 0x39, 0x44, 0xff, 0x40, 0x3f, 0x3d, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x02, 0xff, 0xff, 0x6c, 0x08, 0xff, 0x5c, 0x37, 0x1d, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xf9, 0x6a, 0x02, 0xff, - 0xfc, 0x6b, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x69, 0x05, 0xff, - 0xfe, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfd, 0x6a, 0x03, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, 0xfd, 0x6a, 0x00, 0xff, 0xfa, 0x6b, 0x03, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xff, 0x6c, 0x00, 0xff, 0x4c, 0x38, 0x31, 0xff, 0xfd, 0x65, 0x00, 0xff, 0xff, 0x68, 0x01, 0xff, 0xff, 0x67, 0x07, 0xff, 0xfe, 0x6b, 0x01, 0xff, 0x39, 0x3f, 0x3f, 0xff, 0x3d, 0x41, 0x40, 0xff, - 0x44, 0x41, 0x4a, 0xff, 0x43, 0x3f, 0x40, 0xff, 0xfc, 0x69, 0x01, 0xff, 0xff, 0x6b, 0x06, 0xff, 0xfe, 0x68, 0x07, 0xff, 0x53, 0x3c, 0x34, 0xff, 0xff, 0x66, 0x00, 0xff, 0xf8, 0x69, 0x01, 0xff, - 0xfc, 0x6b, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xfc, 0x6b, 0x02, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, - 0xfd, 0x6b, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfd, 0x6a, 0x03, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfc, 0x6a, 0x03, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xfd, 0x67, 0x00, 0xff, 0x43, 0x40, 0x47, 0xff, 0xff, 0x6f, 0x01, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x67, 0x05, 0xff, 0xfd, 0x68, 0x01, 0xff, 0x40, 0x44, 0x43, 0xff, 0x3f, 0x43, 0x42, 0xff, - 0x3d, 0x3d, 0x3f, 0xff, 0x43, 0x41, 0x46, 0xff, 0xfb, 0x6e, 0x02, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfc, 0x65, 0x00, 0xff, 0x72, 0x36, 0x12, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x6c, 0x08, 0xff, - 0xfd, 0x6a, 0x02, 0xff, 0xfd, 0x6a, 0x02, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, - 0xfc, 0x6c, 0x00, 0xff, 0xfe, 0x6b, 0x00, 0xff, 0xfd, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, - 0xff, 0x69, 0x00, 0xff, 0x41, 0x3f, 0x42, 0xff, 0xf7, 0x6a, 0x00, 0xff, 0xfb, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x03, 0xff, 0xfc, 0x6b, 0x02, 0xff, 0x44, 0x3f, 0x39, 0xff, 0x3f, 0x3e, 0x3c, 0xff, - 0x41, 0x42, 0x3d, 0xff, 0x3f, 0x40, 0x44, 0xff, 0xf6, 0x6c, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xb5, 0x7b, 0x56, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x68, 0x03, 0xff, - 0xfe, 0x69, 0x02, 0xff, 0xfe, 0x69, 0x03, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfc, 0x6b, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, - 0xfc, 0x6b, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xff, 0x6b, 0x00, 0xff, 0x50, 0x3c, 0x31, 0xff, 0xf8, 0x6c, 0x00, 0xff, 0xfc, 0x6e, 0x02, 0xff, 0xff, 0x65, 0x00, 0xff, 0xfd, 0x6c, 0x03, 0xff, 0x43, 0x3e, 0x3a, 0xff, 0x44, 0x40, 0x3f, 0xff, - 0x43, 0x3f, 0x34, 0xff, 0x3e, 0x43, 0x3d, 0xff, 0xf8, 0x6d, 0x04, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, 0x4d, 0x3d, 0x2e, 0xff, 0xfb, 0x67, 0x00, 0xff, 0xff, 0x6d, 0x03, 0xff, - 0xff, 0x68, 0x00, 0xff, 0xff, 0x6b, 0x04, 0xff, 0xfc, 0x67, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xf9, 0x6b, 0x05, 0xff, 0xfb, 0x68, 0x00, 0xff, 0xfe, 0x6d, 0x02, 0xff, - 0xfc, 0x69, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x01, 0xff, 0xf9, 0x67, 0x04, 0xff, 0xfd, 0x6b, 0x04, 0xff, 0xfd, 0x69, 0x00, 0xff, 0xff, 0x6c, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, - 0xff, 0x69, 0x00, 0xff, 0x6e, 0x34, 0x0f, 0xff, 0xf7, 0x6d, 0x00, 0xff, 0xfc, 0x6e, 0x02, 0xff, 0xff, 0x66, 0x00, 0xff, 0xfe, 0x6b, 0x01, 0xff, 0x39, 0x3f, 0x3d, 0xff, 0x41, 0x42, 0x3d, 0xff, - 0x45, 0x41, 0x38, 0xff, 0x3a, 0x3f, 0x3b, 0xff, 0xfa, 0x6b, 0x03, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x67, 0x00, 0xff, 0x50, 0x43, 0x32, 0xff, 0xed, 0x6e, 0x11, 0xff, 0xfd, 0x66, 0x00, 0xff, - 0xf5, 0x6e, 0x12, 0xff, 0xed, 0x6b, 0x13, 0xff, 0xff, 0x6a, 0x03, 0xff, 0xf3, 0x6e, 0x11, 0xff, 0xfa, 0x66, 0x00, 0xff, 0xfe, 0x6c, 0x05, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, - 0xfd, 0x69, 0x00, 0xff, 0xfc, 0x6a, 0x03, 0xff, 0xff, 0x67, 0x01, 0xff, 0xfd, 0x69, 0x07, 0xff, 0xff, 0x6d, 0x06, 0xff, 0xf3, 0x6e, 0x0f, 0xff, 0xef, 0x6d, 0x0b, 0xff, 0xee, 0x6d, 0x0f, 0xff, - 0xf3, 0x70, 0x18, 0xff, 0xd1, 0x73, 0x35, 0xff, 0xf9, 0x6d, 0x00, 0xff, 0xfa, 0x6b, 0x03, 0xff, 0xff, 0x63, 0x00, 0xff, 0xff, 0x6e, 0x02, 0xff, 0x3d, 0x43, 0x43, 0xff, 0x41, 0x41, 0x41, 0xff, - 0x3f, 0x41, 0x3e, 0xff, 0x40, 0x41, 0x46, 0xff, 0xfb, 0x68, 0x00, 0xff, 0xff, 0x68, 0x02, 0xff, 0xfc, 0x6e, 0x02, 0xff, 0x67, 0x31, 0x05, 0xff, 0x85, 0x31, 0x00, 0xff, 0xff, 0x6c, 0x03, 0xff, - 0x89, 0x2b, 0x00, 0xff, 0x88, 0x2f, 0x00, 0xff, 0xf9, 0x65, 0x00, 0xff, 0x88, 0x2e, 0x00, 0xff, 0xf9, 0x70, 0x10, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x67, 0x00, 0xff, 0xfa, 0x67, 0x00, 0xff, - 0xff, 0x6a, 0x00, 0xff, 0xf6, 0x6d, 0x0d, 0xff, 0xfc, 0x6a, 0x05, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xf9, 0x66, 0x00, 0xff, 0x89, 0x24, 0x00, 0xff, 0x8c, 0x34, 0x00, 0xff, 0x86, 0x2a, 0x00, 0xff, - 0x85, 0x27, 0x00, 0xff, 0xf4, 0x73, 0x15, 0xff, 0xfe, 0x6c, 0x00, 0xff, 0xfd, 0x6b, 0x06, 0xff, 0xff, 0x69, 0x09, 0xff, 0xfe, 0x63, 0x00, 0xff, 0x45, 0x44, 0x42, 0xff, 0x3a, 0x3d, 0x42, 0xff, - 0x3d, 0x3f, 0x3e, 0xff, 0x40, 0x40, 0x4a, 0xff, 0xff, 0x6d, 0x00, 0xff, 0xff, 0x67, 0x03, 0xff, 0xf8, 0x69, 0x01, 0xff, 0xd3, 0x76, 0x30, 0xff, 0xcf, 0x7b, 0x35, 0xff, 0xfd, 0x64, 0x00, 0xff, - 0xd6, 0x77, 0x33, 0xff, 0xc9, 0x73, 0x38, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xce, 0x74, 0x38, 0xff, 0xf5, 0x6c, 0x0c, 0xff, 0xff, 0x66, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x6a, 0x03, 0xff, - 0xff, 0x6b, 0x00, 0xff, 0xf4, 0x6b, 0x0b, 0xff, 0xfb, 0x69, 0x04, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x69, 0x00, 0xff, 0xe2, 0x7c, 0x34, 0xff, 0xca, 0x71, 0x35, 0xff, 0xd3, 0x75, 0x37, 0xff, - 0xd5, 0x79, 0x38, 0xff, 0xfc, 0x68, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6b, 0x08, 0xff, 0xff, 0x69, 0x0b, 0xff, 0xff, 0x67, 0x00, 0xff, 0x41, 0x40, 0x3e, 0xff, 0x41, 0x40, 0x46, 0xff, - 0x42, 0x41, 0x3f, 0xff, 0x39, 0x40, 0x46, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xfe, 0x65, 0x00, 0xff, 0xff, 0x6b, 0x04, 0xff, 0xef, 0x6d, 0x0b, 0xff, 0xf1, 0x6e, 0x13, 0xff, 0xff, 0x6b, 0x07, 0xff, - 0xee, 0x6e, 0x0d, 0xff, 0xea, 0x71, 0x18, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xef, 0x6f, 0x14, 0xff, 0xff, 0x6b, 0x04, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x66, 0x00, 0xff, 0xfd, 0x66, 0x00, 0xff, - 0xfd, 0x69, 0x00, 0xff, 0xf9, 0x6a, 0x01, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xf2, 0x6d, 0x10, 0xff, 0xed, 0x6b, 0x13, 0xff, 0xf4, 0x6e, 0x17, 0xff, - 0xf0, 0x6f, 0x13, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x6c, 0x00, 0xff, 0xfc, 0x6d, 0x07, 0xff, 0xfd, 0x65, 0x02, 0xff, 0xff, 0x6b, 0x00, 0xff, 0x3d, 0x41, 0x40, 0xff, 0x43, 0x3f, 0x3e, 0xff, - 0x41, 0x40, 0x3e, 0xff, 0x39, 0x41, 0x43, 0xff, 0xe5, 0x6e, 0x1a, 0xff, 0xe3, 0x72, 0x24, 0xff, 0xe1, 0x70, 0x24, 0xff, 0xe4, 0x76, 0x21, 0xff, 0xde, 0x6d, 0x1f, 0xff, 0xe2, 0x6e, 0x23, 0xff, - 0xe2, 0x73, 0x22, 0xff, 0xda, 0x70, 0x24, 0xff, 0xe4, 0x6e, 0x17, 0xff, 0xe3, 0x74, 0x25, 0xff, 0xe4, 0x6f, 0x1f, 0xff, 0xe5, 0x6e, 0x1e, 0xff, 0xe3, 0x73, 0x29, 0xff, 0xe4, 0x73, 0x25, 0xff, - 0xde, 0x71, 0x1f, 0xff, 0xe4, 0x73, 0x23, 0xff, 0xe5, 0x72, 0x22, 0xff, 0xe3, 0x70, 0x1f, 0xff, 0xe3, 0x72, 0x22, 0xff, 0xe1, 0x72, 0x23, 0xff, 0xe2, 0x71, 0x23, 0xff, 0xe1, 0x6d, 0x22, 0xff, - 0xe0, 0x71, 0x22, 0xff, 0xe5, 0x72, 0x21, 0xff, 0xe2, 0x72, 0x20, 0xff, 0xd9, 0x6e, 0x20, 0xff, 0xe7, 0x73, 0x26, 0xff, 0xe3, 0x75, 0x1e, 0xff, 0x39, 0x42, 0x41, 0xff, 0x46, 0x40, 0x40, 0xff, - 0x3f, 0x3f, 0x3d, 0xff, 0x3e, 0x42, 0x41, 0xff, 0x5c, 0x38, 0x18, 0xff, 0x5d, 0x39, 0x23, 0xff, 0x60, 0x38, 0x1f, 0xff, 0x5e, 0x39, 0x1c, 0xff, 0x57, 0x39, 0x1d, 0xff, 0x5f, 0x3a, 0x1d, 0xff, - 0x5f, 0x3c, 0x20, 0xff, 0x58, 0x38, 0x21, 0xff, 0x60, 0x37, 0x19, 0xff, 0x5e, 0x39, 0x1c, 0xff, 0x5d, 0x38, 0x1b, 0xff, 0x5b, 0x34, 0x15, 0xff, 0x5c, 0x3e, 0x26, 0xff, 0x5a, 0x36, 0x1c, 0xff, - 0x5d, 0x39, 0x21, 0xff, 0x60, 0x39, 0x1c, 0xff, 0x5c, 0x38, 0x1e, 0xff, 0x5c, 0x35, 0x18, 0xff, 0x58, 0x38, 0x1f, 0xff, 0x5e, 0x3a, 0x1a, 0xff, 0x5c, 0x39, 0x1d, 0xff, 0x61, 0x39, 0x1f, 0xff, - 0x5d, 0x39, 0x1f, 0xff, 0x5f, 0x37, 0x1e, 0xff, 0x59, 0x3a, 0x1e, 0xff, 0x5f, 0x3a, 0x1d, 0xff, 0x60, 0x39, 0x1c, 0xff, 0x5b, 0x3a, 0x19, 0xff, 0x3a, 0x40, 0x3c, 0xff, 0x40, 0x3b, 0x3f, 0xff, - 0x3e, 0x40, 0x3f, 0xff, 0x3e, 0x40, 0x3d, 0xff, 0x41, 0x43, 0x3e, 0xff, 0x3d, 0x40, 0x45, 0xff, 0x3f, 0x3d, 0x40, 0xff, 0x3f, 0x3f, 0x3d, 0xff, 0x3c, 0x46, 0x45, 0xff, 0x3f, 0x40, 0x3b, 0xff, - 0x3d, 0x3d, 0x3d, 0xff, 0x40, 0x44, 0x47, 0xff, 0x42, 0x3e, 0x3b, 0xff, 0x40, 0x3f, 0x3b, 0xff, 0x40, 0x40, 0x3e, 0xff, 0x42, 0x41, 0x3d, 0xff, 0x38, 0x42, 0x44, 0xff, 0x3d, 0x41, 0x40, 0xff, - 0x40, 0x41, 0x45, 0xff, 0x43, 0x3f, 0x3e, 0xff, 0x3e, 0x3f, 0x43, 0xff, 0x41, 0x40, 0x3c, 0xff, 0x3b, 0x43, 0x45, 0xff, 0x3f, 0x40, 0x3a, 0xff, 0x3d, 0x3f, 0x3c, 0xff, 0x42, 0x41, 0x3f, 0xff, - 0x3f, 0x3f, 0x41, 0xff, 0x41, 0x3f, 0x42, 0xff, 0x3b, 0x43, 0x45, 0xff, 0x3f, 0x3e, 0x39, 0xff, 0x42, 0x3f, 0x3a, 0xff, 0x3d, 0x43, 0x3f, 0xff, 0x3d, 0x43, 0x3f, 0xff, 0x42, 0x3f, 0x46, 0xff}; - -// clang-format on - -inline std::vector -ReadBlobUnsafe(const std::string& filename) -{ - std::ifstream file(filename, std::ios::binary | std::ios::ate); - - if (!file.is_open()) - return {}; - - std::ifstream::pos_type pos = file.tellg(); - - // What happens if the OS supports really big files. - // It may be larger than 32 bits? - // This will silently truncate the value/ - std::streamoff length = pos; - - std::vector bytes(length); - if (pos > 0) - { // Manuall memory management. - // Not a good idea use a container/. - file.seekg(0, std::ios::beg); - file.read((char*)bytes.data(), length); - } - file.close(); - return bytes; -}; - -int -main() -{ - - Fox::DContextConfig config; - config.logOutputFunction = &Log; - config.warningFunction = &Log; - - Fox::IContext* context = Fox::CreateVulkanContext(&config); - - { - if (!glfwInit()) - { - throw std::runtime_error("Failed to glfwInit"); - } - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); // as Vulkan, there is no need to create a context - GLFWwindow* window = glfwCreateWindow(640, 480, "My Title", NULL, NULL); - if (!window) - { - throw std::runtime_error("Failed to glfwCreateWindow"); - } - Fox::WindowData windowData; - windowData._hwnd = glfwGetWin32Window(window); - windowData._instance = GetModuleHandle(NULL); - - Fox::DSwapchain swapchain; - auto presentMode = Fox::EPresentMode::IMMEDIATE_KHR; - auto format = Fox::EFormat::B8G8R8A8_UNORM; - if (!context->CreateSwapchain(&windowData, presentMode, format, &swapchain)) - { - throw std::runtime_error("Failed to CreateSwapchain"); - } - - // Create vertex layout - Fox::VertexLayoutInfo position("SV_POSITION", Fox::EFormat::R32G32B32_FLOAT, 0, Fox::EVertexInputClassification::PER_VERTEX_DATA); - Fox::VertexLayoutInfo color("Color0", Fox::EFormat::R32G32B32A32_FLOAT, 3 * sizeof(float), Fox::EVertexInputClassification::PER_VERTEX_DATA); - Fox::DVertexInputLayout vertexLayout = context->CreateVertexLayout({ position, color }); - constexpr uint32_t stride = 7 * sizeof(float); - - Fox::ShaderSource shaderSource; - shaderSource.VertexLayout = vertexLayout; - shaderSource.VertexStride = stride; - shaderSource.SourceCode.VertexShader = ReadBlobUnsafe("vertex.spv"); - shaderSource.SourceCode.PixelShader = ReadBlobUnsafe("fragment.spv"); - - shaderSource.SetsLayout.SetsLayout[0].insert({ 0, Fox::ShaderDescriptorBindings("Camera", Fox::EBindingType::UNIFORM_BUFFER_OBJECT, sizeof(float) * 16, 1, Fox::EShaderStage::VERTEX) }); - shaderSource.SetsLayout.SetsLayout[1].insert({ 0, Fox::ShaderDescriptorBindings("MatrixUbo", Fox::EBindingType::UNIFORM_BUFFER_OBJECT, sizeof(float) * 16, 1, Fox::EShaderStage::VERTEX) }); - shaderSource.SetsLayout.SetsLayout[2].insert({ 0, Fox::ShaderDescriptorBindings("MyTexture", Fox::EBindingType::SAMPLER, 1, 1, Fox::EShaderStage::FRAGMENT) }); - - shaderSource.ColorAttachments.push_back({ format }); - shaderSource.DepthStencilAttachment = Fox::EFormat::DEPTH32_FLOAT; - - Fox::DShader shader = context->CreateShader(shaderSource); - - // clang-format off - constexpr std::array ndcQuad{ - -1, -1, -1,//pos - 0, 1, 0, 1,// color - 1, -1, -1,//pos - 0, 0, 1, 1,// color - 1, 1, -1,//pos - 0, 1, 1, 1,// color - //----------------// - -1, -1, -1,//pos - 0, 1, 0, 1,// color - 1, 1, -1,//pos - 0, 0, 1, 1,// color - -1, 1, -1,//pos - 0, 1, 1, 1,// color - //----------------// - -1, -1, 1,//pos - 0, 1, 0, 1,// color - 1, -1, 1,//pos - 0, 0, 1, 1,// color - 1, 1, 1,//pos - 0, 1, 1, 1,// color - //----------------// - -1, -1, 1,//pos - 0, 1, 0, 1,// color - 1, 1, 1,//pos - 0, 0, 1, 1,// color - -1, 1, 1,//pos - 0, 1, 1, 1,// color - }; - // clang-format on - constexpr size_t bufSize = sizeof(float) * ndcQuad.size(); - Fox::DBuffer quad = context->CreateVertexBuffer(bufSize); - - Fox::CopyDataCommand copy; - copy.CopyVertex(quad, 0, (void*)ndcQuad.data(), bufSize); - context->SubmitCopy(std::move(copy)); - - Fox::DImage depthBuffer = context->CreateImage(Fox::EFormat::DEPTH32_FLOAT, 640, 480, 1); - Fox::DFramebuffer swapchainFbo = context->CreateSwapchainFramebuffer_DEPRECATED(swapchain, depthBuffer); - - Fox::DRenderPassAttachment colorAttachment(format, - Fox::ESampleBit::COUNT_1_BIT, - Fox::ERenderPassLoad::Clear, - Fox::ERenderPassStore::Store, - Fox::ERenderPassLayout::Undefined, - Fox::ERenderPassLayout::Present, - Fox::EAttachmentReference::COLOR_ATTACHMENT); - Fox::DRenderPassAttachments renderPass; - renderPass.Attachments.push_back(colorAttachment); - - Fox::DRenderPassAttachment depthAttachment(Fox::EFormat::DEPTH32_FLOAT, - Fox::ESampleBit::COUNT_1_BIT, - Fox::ERenderPassLoad::Clear, - Fox::ERenderPassStore::Store, - Fox::ERenderPassLayout::Undefined, - Fox::ERenderPassLayout::Present, - Fox::EAttachmentReference::DEPTH_STENCIL_ATTACHMENT); - renderPass.Attachments.push_back(depthAttachment); - - Fox::DBuffer transformUniformBuffer = context->CreateUniformBuffer(sizeof(float) * 16); - float yaw{ 0 }; - - Fox::DImage texture = context->CreateImage(Fox::EFormat::R8G8B8A8_UNORM, imageWidth, imageHeight, 1); - { - Fox::CopyDataCommand copy; - copy.CopyImageMipMap(texture, 0, (void*)image, imageWidth, imageHeight, 0, sizeof(image)); - context->SubmitCopy(std::move(copy)); - } - - const auto perspective = glm::perspective(glm::radians(60.f), 1.f, 0.f, 1.f); - const auto view = glm::translate(glm::mat4(1.f), glm::vec3(0, 0, -5)); - glm::mat4 cameraProjection = perspective * view; - Fox::DBuffer cameraUniformBuffer = context->CreateUniformBuffer(sizeof(float) * 16); - { - Fox::CopyDataCommand copy; - copy.CopyUniformBuffer(cameraUniformBuffer, glm::value_ptr(cameraProjection), sizeof(float) * 16); - context->SubmitCopy(std::move(copy)); - } - - while (!glfwWindowShouldClose(window)) - { - // Keep running - glfwPollEvents(); - - int w, h; - glfwGetWindowSize(window, &w, &h); - Fox::DViewport viewport{ 0, 0, w, h, 0.f, 1.f }; - - { - yaw += 0.001f; - const float sinA = std::sin(yaw); - const float cosA = std::cos(yaw); - - float matrix[4][4]{ { cosA, 0, -sinA, 0 }, { 0, 1, 0, 0 }, { sinA, 0, cosA, 0 }, { 0, 0, 0, 1 } }; - Fox::CopyDataCommand copy; - copy.CopyUniformBuffer(transformUniformBuffer, &matrix[0][0], sizeof(float) * 16); - context->SubmitCopy(std::move(copy)); - } - - Fox::RenderPassData draw(swapchainFbo, viewport, renderPass); - draw.ClearColor(1, 0, 0, 1); - draw.ClearDepthStencil(0, 0); - - { - Fox::DrawCommand drawTriangle(shader); - drawTriangle.BindBufferUniformBuffer(0, 0, cameraUniformBuffer); - drawTriangle.BindBufferUniformBuffer(1, 0, transformUniformBuffer); - drawTriangle.BindImageArray(2, 0, { texture }); - drawTriangle.Draw(quad, 0, 12); - draw.AddDrawCommand(std::move(drawTriangle)); - } - - context->SubmitPass(std::move(draw)); - - context->AdvanceFrame(); - } - - context->DestroyShader(shader); - context->DestroyImage(texture); - context->DestroyImage(depthBuffer); - context->DestroyVertexBuffer(quad); - context->DestroyUniformBuffer(transformUniformBuffer); - context->DestroyUniformBuffer(cameraUniformBuffer); - context->_destroyFramebuffer(swapchainFbo); - context->DestroySwapchain(swapchain); - - glfwDestroyWindow(window); - - glfwTerminate(); - } - - delete context; - - return 0; -} \ No newline at end of file diff --git a/examples/DepthBuffer/buildShaders.bat b/examples/DepthBuffer/buildShaders.bat deleted file mode 100644 index 890d4a2..0000000 --- a/examples/DepthBuffer/buildShaders.bat +++ /dev/null @@ -1,3 +0,0 @@ -C:\VulkanSDK\1.3.261.1\Bin\glslc.exe -fshader-stage=vert vertex.glsl -o vertex.spv -C:\VulkanSDK\1.3.261.1\Bin\glslc.exe -fshader-stage=frag fragment.glsl -o fragment.spv -pause \ No newline at end of file diff --git a/examples/DepthBuffer/fragment.glsl b/examples/DepthBuffer/fragment.glsl deleted file mode 100644 index e7d06f8..0000000 --- a/examples/DepthBuffer/fragment.glsl +++ /dev/null @@ -1,20 +0,0 @@ -#version 450 - -layout(location = 0) in vec2 pos; -layout(location = 0) out vec4 outColor; - -layout(set =2, binding = 0) uniform sampler2D MyTexture; - -vec2 CorrectUv(vec2 uv) -{ -return vec2(uv.x, 1-uv.y); -} -vec2 xCorrectUv(vec2 uv) -{ -return uv; -} - -void main() { - vec4 texColor = texture(MyTexture, pos); - outColor = texColor; -} \ No newline at end of file diff --git a/examples/DepthBuffer/fragment.spv b/examples/DepthBuffer/fragment.spv deleted file mode 100644 index be6eb1b68c26365d4e96d21aa6c7f79c69567c9f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 708 zcmY+BO-lk{6oqe&qo(CYmJ&f|?WILU5VeVz&4i1BmP6<)1|~;z6#aYssy0FA8J(~f z?%emBd+ygePT{g_wr4dvw61MV%L-ylTq*OO|LPCs>3DE`bA_UAP9{Xtu(B29vCofa zLZBr(ku{}*R|DM~RW7jSNXgNnE8A9R^;KZQ*BX|C$8uE zcXE8DdNoDRk$N7l3m!d~o#2Qc%k!6+hd7uW;coS6)M0iG z+_xB49xc1@AINyUZ^oKY7Cm?qNErSZ#T8wm}8c1v)vl?%DO^6Y;;AGf4?RBU5sQcup3t2OD z7f8&yx#0A9{hkf%7-Lm@Q``|h64&)tll-lOd9!T7UKIBGVeefuoJ^u={w;~4#E#== zWV3jf+b=P3OO-e~9wxIsP$}IV`ljd6FYfpr}S}Q7iC;`Qb8vfMt{!hN zOp`Q|JQBj4ATK?}Ex?c-;|5^t>oIgN?jOp7PTWzsvs85{;<*9TE`+P$F@1REl9(D` z)Cg6Bo9v4rZ?_85_3-!bJ-l7*;jwBDFyDjw(Su#-f$e)>bJM06!tO{`ZElK9{-&x@ zx1~L}4f?jU1<63XqkQJT=4M;^U6KsMP^Yx{PomzQ>}5&f!J5*zv9Ey-4itA$(!a-x z(&ifkqtBX)E9%k*dtD6e%I5ymWv-^Ocn2_QUzTJSFluA-HemR#lsfU`a$ldjTl&Dr z#pcH3a*rF5?8ltc^0x#h9-B9q6EiolEwM2_UK4*Hja+7@-aScT{A~B7;|Hf6HgD+r zb){3AeEitFDcCc8z0~0*5IKK@@V&j!FMDr^xdpd;sYv$T7K8hkYtq@d8gpGX_%GEV zXHQHXICa=R5VQMx#jw-9I1ob~YfBHr%CDzw1#bIL3 - -#include "IContext.h" -#include "backend/vulkan/VulkanContextFactory.h" - -#include - -#define GLFW_INCLUDE_NONE // makes the GLFW header not include any OpenGL or -// OpenGL ES API header.This is useful in combination with an extension loading library. -#include - -#define GLFW_EXPOSE_NATIVE_WIN32 -#include - -#include -#include -#include - -void -Log(const char* msg) -{ - std::cout << msg << std::endl; -}; - -inline std::vector -ReadBlobUnsafe(const std::string& filename) -{ - std::ifstream file(filename, std::ios::binary | std::ios::ate); - - if (!file.is_open()) - return {}; - - std::ifstream::pos_type pos = file.tellg(); - - // What happens if the OS supports really big files. - // It may be larger than 32 bits? - // This will silently truncate the value/ - std::streamoff length = pos; - - std::vector bytes(length); - if (pos > 0) - { // Manuall memory management. - // Not a good idea use a container/. - file.seekg(0, std::ios::beg); - file.read((char*)bytes.data(), length); - } - file.close(); - return bytes; -}; - -int -main() -{ - - Fox::DContextConfig config; - config.logOutputFunction = &Log; - config.warningFunction = &Log; - - Fox::IContext* context = Fox::CreateVulkanContext(&config); - - { - if (!glfwInit()) - { - throw std::runtime_error("Failed to glfwInit"); - } - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); // as Vulkan, there is no need to create a context - GLFWwindow* window = glfwCreateWindow(640, 480, "My Title", NULL, NULL); - if (!window) - { - throw std::runtime_error("Failed to glfwCreateWindow"); - } - Fox::WindowData windowData; - windowData._hwnd = glfwGetWin32Window(window); - windowData._instance = GetModuleHandle(NULL); - - Fox::DSwapchain swapchain; - auto presentMode = Fox::EPresentMode::IMMEDIATE_KHR; - auto format = Fox::EFormat::B8G8R8A8_UNORM; - if (!context->CreateSwapchain(&windowData, presentMode, format, &swapchain)) - { - throw std::runtime_error("Failed to CreateSwapchain"); - } - - // Create vertex layout - Fox::VertexLayoutInfo position("SV_POSITION", Fox::EFormat::R32G32B32_FLOAT, 0, Fox::EVertexInputClassification::PER_VERTEX_DATA); - Fox::VertexLayoutInfo color("Color0", Fox::EFormat::R32G32B32A32_FLOAT, 3 * sizeof(float), Fox::EVertexInputClassification::PER_VERTEX_DATA); - Fox::DVertexInputLayout vertexLayout = context->CreateVertexLayout({ position, color }); - constexpr uint32_t stride = 7 * sizeof(float); - - Fox::ShaderSource shaderSource; - shaderSource.VertexLayout = vertexLayout; - shaderSource.VertexStride = stride; - shaderSource.SourceCode.VertexShader = ReadBlobUnsafe("vertex.spv"); - shaderSource.SourceCode.PixelShader = ReadBlobUnsafe("fragment.spv"); - shaderSource.ColorAttachments.push_back(format); - - shaderSource.SetsLayout.SetsLayout[0].insert({ 0, Fox::ShaderDescriptorBindings("MatrixUbo", Fox::EBindingType::UNIFORM_BUFFER_OBJECT, sizeof(float) * 16, 1, Fox::EShaderStage::VERTEX) }); - - Fox::DShader shader = context->CreateShader(shaderSource); - - // clang-format off - constexpr std::array ndcTriangle{ - -1, -1, 0.5,//pos - 0, 1, 0, 1,// color - 1, -1, 0.5,//pos - 0, 0, 1, 1,// color - 0, 1, 0.5,//pos - 0, 1, 1, 1// color - }; - // clang-format on - constexpr size_t bufSize = sizeof(float) * ndcTriangle.size(); - Fox::DBuffer triangle = context->CreateVertexBuffer(bufSize); - - Fox::CopyDataCommand copy; - copy.CopyVertex(triangle, 0, (void*)ndcTriangle.data(), bufSize); - context->SubmitCopy(std::move(copy)); - - Fox::DFramebuffer swapchainFbo = context->CreateSwapchainFramebuffer_DEPRECATED(swapchain); - - Fox::DRenderPassAttachment colorAttachment(format, - Fox::ESampleBit::COUNT_1_BIT, - Fox::ERenderPassLoad::Clear, - Fox::ERenderPassStore::Store, - Fox::ERenderPassLayout::Undefined, - Fox::ERenderPassLayout::Present, - Fox::EAttachmentReference::COLOR_ATTACHMENT); - Fox::DRenderPassAttachments renderPass; - renderPass.Attachments.push_back(colorAttachment); - - Fox::DBuffer transformUniformBuffer = context->CreateUniformBuffer(sizeof(float) * 16); - float yaw{ 0 }; - - while (!glfwWindowShouldClose(window)) - { - // Keep running - glfwPollEvents(); - - int w, h; - glfwGetWindowSize(window, &w, &h); - Fox::DViewport viewport{ 0, 0, w, h, 0.f, 1.f }; - - { - yaw += 0.01f; - const float sinA = std::sin(yaw); - const float cosA = std::cos(yaw); - - float matrix[4][4]{ { cosA, 0, -sinA, 0 }, { 0, 1, 0, 0 }, { sinA, 0, cosA, 0 }, { 0, 0, 0, 1 } }; - Fox::CopyDataCommand copy; - copy.CopyUniformBuffer(transformUniformBuffer, &matrix[0][0], sizeof(float) * 16); - context->SubmitCopy(std::move(copy)); - } - - Fox::RenderPassData draw(swapchainFbo, viewport, renderPass); - draw.ClearColor(1, 0, 0, 1); - - Fox::DrawCommand drawTriangle(shader); - drawTriangle.BindBufferUniformBuffer(0, 0, transformUniformBuffer); - drawTriangle.Draw(triangle, 0, 3); - - draw.AddDrawCommand(std::move(drawTriangle)); - - context->SubmitPass(std::move(draw)); - - context->AdvanceFrame(); - } - context->DestroyShader(shader); - context->DestroyVertexBuffer(triangle); - context->DestroyUniformBuffer(transformUniformBuffer); - - context->DestroySwapchain(swapchain); - - glfwDestroyWindow(window); - - glfwTerminate(); - } - - delete context; - - return 0; -} \ No newline at end of file diff --git a/examples/SpinningTriangle/buildShaders.bat b/examples/SpinningTriangle/buildShaders.bat deleted file mode 100644 index 890d4a2..0000000 --- a/examples/SpinningTriangle/buildShaders.bat +++ /dev/null @@ -1,3 +0,0 @@ -C:\VulkanSDK\1.3.261.1\Bin\glslc.exe -fshader-stage=vert vertex.glsl -o vertex.spv -C:\VulkanSDK\1.3.261.1\Bin\glslc.exe -fshader-stage=frag fragment.glsl -o fragment.spv -pause \ No newline at end of file diff --git a/examples/SpinningTriangle/fragment.glsl b/examples/SpinningTriangle/fragment.glsl deleted file mode 100644 index 1ba594f..0000000 --- a/examples/SpinningTriangle/fragment.glsl +++ /dev/null @@ -1,18 +0,0 @@ -#version 450 - -layout(location = 0) in vec4 fragColor; -layout(location = 0) out vec4 outColor; - - -vec2 CorrectUv(vec2 uv) -{ -return vec2(uv.x, 1-uv.y); -} -vec2 xCorrectUv(vec2 uv) -{ -return uv; -} - -void main() { - outColor = fragColor; -} \ No newline at end of file diff --git a/examples/SpinningTriangle/fragment.spv b/examples/SpinningTriangle/fragment.spv deleted file mode 100644 index 5696c4ab7a81fbcbf204a342a4833f74732ba6db..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 452 zcmYjNO>4qH5S<#=ulQ98dJ{|U;=vX{^de<10T2BFizI1TNRtqw(7)%e>ZQ>4)(^5_ zGCObH%zKGfdufV1h%Y@nm-8q!AOfu6vJO6i*`bVPi`O|BeeoQToPji@j?DPp+mwwq z!bc3jBMt%FJZu#?W2i12(SgysoethjnCIqD{v@$UY#N)$7I9eGQ%qi~!n0|Z9HS~h zfl<{}qMUYiEVo&b6_5j>oR`mH|8)a3rs#1(0uF2Xz12@}O0Un(wYd8T_Xe;jVhldN zi8b}7c(;)GSBS5!H8qH_-$BNw-}|hoN$d?CsmEPBocRT!kk>%Dvx^{qgD&^7{=@VV F@efF8ER+BM diff --git a/examples/SpinningTriangle/vertex.glsl b/examples/SpinningTriangle/vertex.glsl deleted file mode 100644 index a829209..0000000 --- a/examples/SpinningTriangle/vertex.glsl +++ /dev/null @@ -1,16 +0,0 @@ -#version 450 - -layout(location = 0) in vec3 position; -layout(location = 1) in vec4 color; - -layout(location = 0) out vec4 fragColor; - -layout (binding =0) uniform MyMatrix -{ - mat4 Matrix; -}ubo; - -void main() { - gl_Position = ubo.Matrix * vec4(position.xyz, 1.0); - fragColor = color; -} \ No newline at end of file diff --git a/examples/SpinningTriangle/vertex.spv b/examples/SpinningTriangle/vertex.spv deleted file mode 100644 index 3c51e37859113117e43e9af2c2b0980fc2a8dff5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1336 zcmYk4PjAye5XHAi+?JNMl+r&y2}x7nfK+h+goFU0g4{!@7FFui3XZ8(a_z`*5aq;I z;4AT|xFGR0Bf@QvVrW0tgT;5{*MwmX2pcVC_Fn0ho7T(GKr?;O`1fh z&5~$rizF`X_XOQ?Lua!%osFAfqGrl8CPj^o)ni!Q6@hG#a29fV)@jTHqXQ^ zIXyEt-e%>6{i&15sbci3*l}tnpX{_8WpOf(aRbC=X*!Punv>aCfqt9vr#Gjgvaoe8 z6-V5&_)Ip#vg z44z{T$DM|Xut#?yhB;V)486zn#cFbTOy-V^8tAAIss=M2$XFitE9fwDcN>`6P0Tw2 zGsl*yQn#-&=$rkHc8l^o*{;r`4>0p=>wj6kCu2RYF)x>T`@$>o=;6BBF~6@t4C_gE zTi)N*+ZyxD;W%gA>8iS%1KyCa_Jp|`>e5$NS=H0QXw&fWDZ6MV-H5 zcq1S6Pp{iD`e*)kQquR13?59M4`lTCMLG1hUvqME?orKguGjGv$fbvKbx4noW#pqL r&aA&xmsn56*=XpmFMlB8+tJ^9O#tr6=#8AGGUg@5y@3B|`Zu!wTkB)a diff --git a/examples/TexturedQuad/CMakeLists.txt b/examples/TexturedQuad/CMakeLists.txt deleted file mode 100644 index 63897ef..0000000 --- a/examples/TexturedQuad/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -cmake_minimum_required(VERSION 3.26.4) -project(TexturedQuad CXX) - -add_executable(${PROJECT_NAME} -"TexturedQuad.cpp" -) - - -target_link_libraries(${PROJECT_NAME} PRIVATE FoxFury glfw) - -set_target_properties(${PROJECT_NAME} PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "bin" -) - -#Set the debug working directory -set_target_properties(${PROJECT_NAME} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") - -include_directories(${LIB_INCLUDE_DIR}) \ No newline at end of file diff --git a/examples/TexturedQuad/TexturedQuad.cpp b/examples/TexturedQuad/TexturedQuad.cpp deleted file mode 100644 index e520473..0000000 --- a/examples/TexturedQuad/TexturedQuad.cpp +++ /dev/null @@ -1,345 +0,0 @@ -// Copyright RedFox Studio 2022 - -#include - -#include "IContext.h" -#include "backend/vulkan/VulkanContextFactory.h" - -#include - -#define GLFW_INCLUDE_NONE // makes the GLFW header not include any OpenGL or -// OpenGL ES API header.This is useful in combination with an extension loading library. -#include - -#define GLFW_EXPOSE_NATIVE_WIN32 -#include - -#include -#include -#include - -void -Log(const char* msg) -{ - std::cout << msg << std::endl; -}; - -constexpr uint32_t imageWidth = 32; -constexpr uint32_t imageHeight = 32; -// converter https://notisrac.github.io/FileToCArray/ -// clang-format off -constexpr uint8_t image[] = {0x41, 0x3c, 0x38, 0xff, 0x3a, 0x48, 0x48, 0xff, 0x3a, 0x3f, 0x45, 0xff, 0x40, 0x41, 0x39, 0xff, 0x42, 0x42, 0x44, 0xff, 0x3f, 0x3d, 0x40, 0xff, 0x3c, 0x41, 0x44, 0xff, 0x42, 0x41, 0x3f, 0xff, - 0x3b, 0x43, 0x46, 0xff, 0x47, 0x3e, 0x3f, 0xff, 0x45, 0x3c, 0x35, 0xff, 0x3b, 0x41, 0x3d, 0xff, 0x3c, 0x3f, 0x48, 0xff, 0x3b, 0x40, 0x43, 0xff, 0x44, 0x45, 0x3f, 0xff, 0x43, 0x3b, 0x38, 0xff, - 0x3d, 0x3f, 0x3e, 0xff, 0x43, 0x42, 0x3d, 0xff, 0x44, 0x3f, 0x43, 0xff, 0x3d, 0x43, 0x41, 0xff, 0x40, 0x3d, 0x44, 0xff, 0x40, 0x40, 0x36, 0xff, 0x44, 0x40, 0x3f, 0xff, 0x3c, 0x42, 0x42, 0xff, - 0x3d, 0x42, 0x3e, 0xff, 0x38, 0x42, 0x44, 0xff, 0x3f, 0x3e, 0x3c, 0xff, 0x3f, 0x40, 0x42, 0xff, 0x3d, 0x3e, 0x40, 0xff, 0x3e, 0x43, 0x46, 0xff, 0x3f, 0x3e, 0x3a, 0xff, 0x43, 0x40, 0x3b, 0xff, - 0x48, 0x43, 0x3f, 0xff, 0x32, 0x3e, 0x3e, 0xff, 0x60, 0x3c, 0x26, 0xff, 0x5a, 0x36, 0x14, 0xff, 0x5a, 0x36, 0x1e, 0xff, 0x5e, 0x36, 0x1d, 0xff, 0x5d, 0x3b, 0x20, 0xff, 0x5f, 0x37, 0x1d, 0xff, - 0x5c, 0x3a, 0x21, 0xff, 0x5e, 0x34, 0x1c, 0xff, 0x62, 0x37, 0x17, 0xff, 0x60, 0x3d, 0x1f, 0xff, 0x5d, 0x38, 0x25, 0xff, 0x5b, 0x38, 0x22, 0xff, 0x59, 0x35, 0x15, 0xff, 0x67, 0x3b, 0x20, 0xff, - 0x62, 0x3d, 0x22, 0xff, 0x5a, 0x35, 0x18, 0xff, 0x5c, 0x33, 0x1d, 0xff, 0x5c, 0x3a, 0x1f, 0xff, 0x5e, 0x35, 0x21, 0xff, 0x61, 0x3a, 0x19, 0xff, 0x59, 0x34, 0x1a, 0xff, 0x5e, 0x3c, 0x21, 0xff, - 0x5a, 0x35, 0x18, 0xff, 0x58, 0x3c, 0x26, 0xff, 0x61, 0x3a, 0x1d, 0xff, 0x5c, 0x38, 0x20, 0xff, 0x5f, 0x37, 0x1e, 0xff, 0x5c, 0x39, 0x23, 0xff, 0x40, 0x3e, 0x3f, 0xff, 0x43, 0x42, 0x3e, 0xff, - 0x45, 0x3d, 0x3a, 0xff, 0x3c, 0x46, 0x48, 0xff, 0xe3, 0x6e, 0x21, 0xff, 0xe4, 0x76, 0x1f, 0xff, 0xe2, 0x74, 0x27, 0xff, 0xe0, 0x71, 0x20, 0xff, 0xe1, 0x73, 0x1e, 0xff, 0xde, 0x6f, 0x20, 0xff, - 0xe4, 0x6f, 0x1f, 0xff, 0xe2, 0x72, 0x2a, 0xff, 0xe1, 0x71, 0x1f, 0xff, 0xe4, 0x6f, 0x1f, 0xff, 0xe2, 0x73, 0x21, 0xff, 0xe0, 0x70, 0x24, 0xff, 0xe0, 0x71, 0x1f, 0xff, 0xe0, 0x70, 0x24, 0xff, - 0xe3, 0x6f, 0x1c, 0xff, 0xe3, 0x74, 0x25, 0xff, 0xe2, 0x72, 0x28, 0xff, 0xe4, 0x73, 0x23, 0xff, 0xe2, 0x72, 0x28, 0xff, 0xdf, 0x6f, 0x1d, 0xff, 0xde, 0x72, 0x29, 0xff, 0xde, 0x70, 0x21, 0xff, - 0xe6, 0x72, 0x1f, 0xff, 0xde, 0x74, 0x28, 0xff, 0xe1, 0x6d, 0x18, 0xff, 0xe2, 0x74, 0x27, 0xff, 0xe7, 0x6e, 0x1f, 0xff, 0xdd, 0x6e, 0x26, 0xff, 0x40, 0x3e, 0x43, 0xff, 0x3d, 0x41, 0x42, 0xff, - 0x45, 0x3d, 0x3a, 0xff, 0x37, 0x3e, 0x44, 0xff, 0xff, 0x67, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfb, 0x68, 0x01, 0xff, 0xfd, 0x69, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xff, 0x6a, 0x04, 0xff, - 0xff, 0x6a, 0x00, 0xff, 0xf9, 0x67, 0x04, 0xff, 0xff, 0x6d, 0x05, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfc, 0x68, 0x00, 0xff, 0xff, 0x6a, 0x04, 0xff, 0xfc, 0x68, 0x00, 0xff, 0xfe, 0x69, 0x03, 0xff, - 0xff, 0x69, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, 0xfa, 0x68, 0x03, 0xff, 0xff, 0x67, 0x00, 0xff, 0xff, 0x6a, 0x03, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfe, 0x6c, 0x07, 0xff, 0xff, 0x6c, 0x02, 0xff, - 0xff, 0x64, 0x00, 0xff, 0xff, 0x6e, 0x09, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xfd, 0x68, 0x01, 0xff, 0xff, 0x67, 0x00, 0xff, 0xff, 0x6a, 0x06, 0xff, 0x43, 0x40, 0x49, 0xff, 0x3c, 0x40, 0x43, 0xff, - 0x46, 0x41, 0x3b, 0xff, 0x3a, 0x43, 0x4a, 0xff, 0xff, 0x65, 0x00, 0xff, 0xfc, 0x69, 0x01, 0xff, 0xfd, 0x6a, 0x02, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfb, 0x67, 0x03, 0xff, - 0xfb, 0x66, 0x00, 0xff, 0xfd, 0x6b, 0x06, 0xff, 0xfa, 0x65, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xfd, 0x69, 0x05, 0xff, 0xfe, 0x6c, 0x05, 0xff, 0xff, 0x6c, 0x03, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xff, 0x68, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6f, 0x0b, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfb, 0x68, 0x00, 0xff, 0xfe, 0x6c, 0x00, 0xff, 0xfb, 0x67, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, - 0xff, 0x6a, 0x04, 0xff, 0xf9, 0x64, 0x00, 0xff, 0xff, 0x6d, 0x08, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfc, 0x68, 0x00, 0xff, 0xff, 0x6c, 0x00, 0xff, 0x3e, 0x3d, 0x42, 0xff, 0x40, 0x3e, 0x3f, 0xff, - 0x3d, 0x3c, 0x38, 0xff, 0x3f, 0x44, 0x4a, 0xff, 0xff, 0x67, 0x02, 0xff, 0xff, 0x6a, 0x03, 0xff, 0xff, 0x69, 0x01, 0xff, 0xfd, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x6c, 0x08, 0xff, - 0xfc, 0x6a, 0x03, 0xff, 0xff, 0x6a, 0x01, 0xff, 0xf0, 0x6e, 0x18, 0xff, 0xf2, 0x73, 0x16, 0xff, 0xec, 0x6a, 0x16, 0xff, 0xfb, 0x6a, 0x01, 0xff, 0xf0, 0x6b, 0x0e, 0xff, 0xf3, 0x6d, 0x0e, 0xff, - 0xfd, 0x6a, 0x03, 0xff, 0xff, 0x67, 0x00, 0xff, 0xfd, 0x6b, 0x04, 0xff, 0xf0, 0x6e, 0x0e, 0xff, 0xff, 0x6b, 0x01, 0xff, 0xf0, 0x71, 0x14, 0xff, 0xff, 0x68, 0x00, 0xff, 0xf2, 0x6f, 0x14, 0xff, - 0xee, 0x6b, 0x11, 0xff, 0xe2, 0x70, 0x27, 0xff, 0xfa, 0x68, 0x03, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xfe, 0x6b, 0x01, 0xff, 0xfb, 0x67, 0x00, 0xff, 0x41, 0x42, 0x46, 0xff, 0x45, 0x41, 0x40, 0xff, - 0x39, 0x42, 0x3f, 0xff, 0x44, 0x40, 0x3f, 0xff, 0xfa, 0x67, 0x00, 0xff, 0xfe, 0x65, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfc, 0x6c, 0x00, 0xff, 0xfc, 0x69, 0x01, 0xff, 0xfb, 0x6a, 0x01, 0xff, - 0xf8, 0x6b, 0x01, 0xff, 0xff, 0x66, 0x00, 0xff, 0x86, 0x31, 0x00, 0xff, 0x7e, 0x2b, 0x00, 0xff, 0x8a, 0x2c, 0x00, 0xff, 0xff, 0x6c, 0x02, 0xff, 0x8b, 0x2b, 0x00, 0xff, 0x8b, 0x2f, 0x00, 0xff, - 0xf7, 0x6b, 0x0a, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0x8c, 0x30, 0x00, 0xff, 0xf9, 0x65, 0x00, 0xff, 0x86, 0x2f, 0x00, 0xff, 0xff, 0x65, 0x00, 0xff, 0x86, 0x29, 0x00, 0xff, - 0x86, 0x2d, 0x00, 0xff, 0x61, 0x3b, 0x26, 0xff, 0xff, 0x6b, 0x01, 0xff, 0xfa, 0x65, 0x00, 0xff, 0xff, 0x6f, 0x03, 0xff, 0xfb, 0x6b, 0x00, 0xff, 0x3a, 0x42, 0x45, 0xff, 0x3e, 0x3d, 0x38, 0xff, - 0x3b, 0x44, 0x43, 0xff, 0x44, 0x3f, 0x3c, 0xff, 0xfd, 0x6b, 0x04, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xf9, 0x6b, 0x00, 0xff, 0xfd, 0x6b, 0x04, 0xff, 0xfc, 0x6a, 0x00, 0xff, - 0xf8, 0x6b, 0x01, 0xff, 0xff, 0x68, 0x00, 0xff, 0xcc, 0x74, 0x34, 0xff, 0xce, 0x79, 0x38, 0xff, 0xd6, 0x77, 0x37, 0xff, 0xfd, 0x66, 0x00, 0xff, 0xd4, 0x77, 0x2a, 0xff, 0xcf, 0x75, 0x39, 0xff, - 0xfb, 0x6c, 0x0c, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x66, 0x00, 0xff, 0xd1, 0x76, 0x2f, 0xff, 0xff, 0x69, 0x02, 0xff, 0xcf, 0x78, 0x35, 0xff, 0xff, 0x67, 0x00, 0xff, 0xd1, 0x77, 0x3b, 0xff, - 0xd1, 0x75, 0x32, 0xff, 0x3f, 0x3e, 0x46, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x6d, 0x05, 0xff, 0xfc, 0x64, 0x00, 0xff, 0xfe, 0x6c, 0x00, 0xff, 0x3b, 0x43, 0x46, 0xff, 0x42, 0x3f, 0x3a, 0xff, - 0x40, 0x41, 0x3c, 0xff, 0x3e, 0x40, 0x3b, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfc, 0x6b, 0x00, 0xff, 0xff, 0x6a, 0x03, 0xff, 0xfb, 0x6a, 0x01, 0xff, 0xfc, 0x6b, 0x02, 0xff, 0xff, 0x6a, 0x00, 0xff, - 0xfc, 0x6b, 0x00, 0xff, 0xff, 0x67, 0x00, 0xff, 0xef, 0x6e, 0x10, 0xff, 0xee, 0x6f, 0x0e, 0xff, 0xf2, 0x6d, 0x12, 0xff, 0xff, 0x68, 0x00, 0xff, 0xef, 0x6f, 0x0c, 0xff, 0xec, 0x6e, 0x1a, 0xff, - 0xff, 0x69, 0x02, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xeb, 0x70, 0x10, 0xff, 0xfd, 0x6a, 0x03, 0xff, 0xec, 0x70, 0x0e, 0xff, 0xff, 0x68, 0x00, 0xff, 0xee, 0x6e, 0x13, 0xff, - 0xf0, 0x6b, 0x0e, 0xff, 0x43, 0x43, 0x4b, 0xff, 0xf6, 0x68, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x6d, 0x00, 0xff, 0xfc, 0x69, 0x00, 0xff, 0x3f, 0x3f, 0x47, 0xff, 0x42, 0x3f, 0x3a, 0xff, - 0x47, 0x42, 0x3f, 0xff, 0x3c, 0x42, 0x3e, 0xff, 0xff, 0x68, 0x00, 0xff, 0xf8, 0x6b, 0x01, 0xff, 0xfe, 0x69, 0x03, 0xff, 0xff, 0x6b, 0x05, 0xff, 0xfc, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xfc, 0x6b, 0x02, 0xff, 0xff, 0x67, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xfc, 0x69, 0x09, 0xff, - 0xff, 0x68, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xf7, 0x6d, 0x02, 0xff, 0xfd, 0x6a, 0x03, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, - 0xff, 0x6c, 0x05, 0xff, 0x5c, 0x36, 0x21, 0xff, 0xfd, 0x6c, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfd, 0x65, 0x00, 0xff, 0xfe, 0x6b, 0x04, 0xff, 0x40, 0x3d, 0x44, 0xff, 0x48, 0x43, 0x40, 0xff, - 0x44, 0x3e, 0x40, 0xff, 0x38, 0x43, 0x3f, 0xff, 0xff, 0x6a, 0x03, 0xff, 0xfa, 0x6c, 0x00, 0xff, 0xff, 0x69, 0x02, 0xff, 0xff, 0x68, 0x06, 0xff, 0xff, 0x6c, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, - 0xfa, 0x6b, 0x05, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xf9, 0x6c, 0x02, 0xff, 0xff, 0x67, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, - 0xfd, 0x6a, 0x02, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xf7, 0x6c, 0x03, 0xff, 0xfc, 0x6b, 0x02, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, - 0xf7, 0x69, 0x03, 0xff, 0xe8, 0x72, 0x1b, 0xff, 0xfe, 0x68, 0x00, 0xff, 0xff, 0x6a, 0x03, 0xff, 0xff, 0x6c, 0x07, 0xff, 0xfd, 0x6b, 0x08, 0xff, 0x40, 0x3e, 0x43, 0xff, 0x3f, 0x3e, 0x3c, 0xff, - 0x44, 0x3d, 0x44, 0xff, 0x37, 0x40, 0x3b, 0xff, 0xff, 0x6a, 0x09, 0xff, 0xfd, 0x6c, 0x00, 0xff, 0xff, 0x69, 0x02, 0xff, 0xf3, 0x68, 0x15, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xfd, 0x68, 0x01, 0xff, - 0xfa, 0x6a, 0x07, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfa, 0x6b, 0x03, 0xff, 0xff, 0x67, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, - 0xfe, 0x69, 0x02, 0xff, 0xfe, 0x69, 0x02, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xf9, 0x6b, 0x05, 0xff, 0xfe, 0x69, 0x02, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, - 0xf8, 0x6a, 0x04, 0xff, 0xff, 0x66, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xfb, 0x68, 0x01, 0xff, 0xfd, 0x68, 0x04, 0xff, 0xfb, 0x6c, 0x06, 0xff, 0x44, 0x3f, 0x43, 0xff, 0x40, 0x3e, 0x3f, 0xff, - 0x42, 0x3f, 0x46, 0xff, 0x3f, 0x40, 0x3a, 0xff, 0xfc, 0x68, 0x08, 0xff, 0xfc, 0x6a, 0x00, 0xff, 0xfc, 0x69, 0x01, 0xff, 0xd3, 0x73, 0x39, 0xff, 0xff, 0x71, 0x03, 0xff, 0xfc, 0x69, 0x02, 0xff, - 0xfa, 0x6b, 0x03, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfc, 0x6b, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, - 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x02, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfc, 0x6a, 0x07, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, - 0xff, 0x6e, 0x01, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, 0xfe, 0x6c, 0x05, 0xff, 0xff, 0x6f, 0x04, 0xff, 0xfa, 0x69, 0x00, 0xff, 0x3f, 0x3e, 0x3c, 0xff, 0x42, 0x42, 0x44, 0xff, - 0x40, 0x3f, 0x44, 0xff, 0x43, 0x42, 0x3e, 0xff, 0xfd, 0x69, 0x07, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xff, 0x70, 0x06, 0xff, 0x65, 0x2d, 0x0c, 0xff, 0xf8, 0x69, 0x00, 0xff, 0xfc, 0x67, 0x01, 0xff, - 0xfd, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfc, 0x6b, 0x02, 0xff, 0xfe, 0x69, 0x02, 0xff, 0xfc, 0x6b, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, - 0xff, 0x67, 0x00, 0xff, 0xff, 0x69, 0x02, 0xff, 0xff, 0x68, 0x02, 0xff, 0xfd, 0x69, 0x05, 0xff, 0xff, 0x67, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, - 0xfd, 0x66, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfa, 0x67, 0x00, 0xff, 0xfd, 0x6c, 0x03, 0xff, 0xfb, 0x69, 0x00, 0xff, 0xff, 0x6e, 0x00, 0xff, 0x40, 0x40, 0x40, 0xff, 0x40, 0x40, 0x42, 0xff, - 0x3e, 0x3d, 0x3b, 0xff, 0x41, 0x41, 0x43, 0xff, 0xfe, 0x6b, 0x03, 0xff, 0xfe, 0x68, 0x00, 0xff, 0xfc, 0x64, 0x00, 0xff, 0x52, 0x46, 0x38, 0xff, 0xfc, 0x69, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, - 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x68, 0x02, 0xff, 0xfc, 0x6b, 0x02, 0xff, 0xfe, 0x6b, 0x00, 0xff, 0xfa, 0x6a, 0x09, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, - 0xfd, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfd, 0x69, 0x07, 0xff, 0xfc, 0x6b, 0x00, 0xff, 0xff, 0x67, 0x00, 0xff, 0xfc, 0x6b, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfc, 0x6b, 0x00, 0xff, - 0xff, 0x6a, 0x02, 0xff, 0xfd, 0x6b, 0x06, 0xff, 0xff, 0x6c, 0x02, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x6d, 0x00, 0xff, 0xfa, 0x66, 0x00, 0xff, 0x3e, 0x42, 0x45, 0xff, 0x3f, 0x40, 0x3a, 0xff, - 0x42, 0x41, 0x3c, 0xff, 0x41, 0x40, 0x46, 0xff, 0xfd, 0x69, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, 0x39, 0x3f, 0x3d, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6a, 0x03, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xfa, 0x6a, 0x0a, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, - 0xfd, 0x6a, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xfc, 0x6a, 0x07, 0xff, 0xfc, 0x6c, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfa, 0x6c, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, - 0xff, 0x68, 0x00, 0xff, 0xfb, 0x69, 0x06, 0xff, 0xfe, 0x6b, 0x01, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xff, 0x64, 0x00, 0xff, 0xfe, 0x6c, 0x00, 0xff, 0x40, 0x41, 0x43, 0xff, 0x41, 0x41, 0x3f, 0xff, - 0x42, 0x3e, 0x3b, 0xff, 0x41, 0x41, 0x43, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x68, 0x01, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0x39, 0x3f, 0x3d, 0xff, 0xfe, 0x6e, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, - 0xfc, 0x6b, 0x02, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xf7, 0x6c, 0x07, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, - 0xfd, 0x6b, 0x00, 0xff, 0xf9, 0x6c, 0x02, 0xff, 0xfd, 0x6a, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xf9, 0x6c, 0x02, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xff, 0x68, 0x00, 0xff, 0xfc, 0x6a, 0x03, 0xff, 0xfc, 0x69, 0x00, 0xff, 0xfc, 0x6b, 0x02, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xf7, 0x6b, 0x00, 0xff, 0x45, 0x40, 0x3a, 0xff, 0x3c, 0x3d, 0x42, 0xff, - 0x40, 0x40, 0x3e, 0xff, 0x43, 0x42, 0x47, 0xff, 0xff, 0x67, 0x00, 0xff, 0xfe, 0x69, 0x03, 0xff, 0xfe, 0x6b, 0x03, 0xff, 0x5f, 0x3d, 0x21, 0xff, 0xfa, 0x6a, 0x00, 0xff, 0xff, 0x6b, 0x04, 0xff, - 0xfc, 0x6a, 0x03, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xf9, 0x6b, 0x05, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, - 0xff, 0x69, 0x00, 0xff, 0xfa, 0x6b, 0x05, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfa, 0x6b, 0x03, 0xff, 0xfd, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, - 0xff, 0x6b, 0x00, 0xff, 0xec, 0x6b, 0x10, 0xff, 0xff, 0x6b, 0x01, 0xff, 0xfe, 0x6b, 0x04, 0xff, 0xff, 0x65, 0x00, 0xff, 0xf8, 0x6e, 0x03, 0xff, 0x49, 0x42, 0x3c, 0xff, 0x43, 0x41, 0x4c, 0xff, - 0x39, 0x3f, 0x3f, 0xff, 0x3e, 0x41, 0x46, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xdd, 0x6e, 0x1d, 0xff, 0xfe, 0x6c, 0x00, 0xff, 0xfe, 0x66, 0x01, 0xff, - 0xfd, 0x6a, 0x02, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x69, 0x02, 0xff, 0xfc, 0x6a, 0x07, 0xff, 0xff, 0x67, 0x00, 0xff, 0xff, 0x69, 0x02, 0xff, 0xfd, 0x69, 0x05, 0xff, - 0xff, 0x67, 0x00, 0xff, 0xfe, 0x69, 0x05, 0xff, 0xff, 0x68, 0x03, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfa, 0x6b, 0x05, 0xff, 0xfc, 0x6a, 0x03, 0xff, 0xff, 0x68, 0x00, 0xff, - 0xf9, 0x68, 0x00, 0xff, 0x91, 0x32, 0x00, 0xff, 0xfc, 0x68, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x6a, 0x05, 0xff, 0xf7, 0x68, 0x00, 0xff, 0x42, 0x3e, 0x3b, 0xff, 0x42, 0x3d, 0x43, 0xff, - 0x40, 0x45, 0x49, 0xff, 0x3f, 0x40, 0x45, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xfd, 0x66, 0x00, 0xff, 0xe3, 0x72, 0x22, 0xff, 0xfe, 0x68, 0x00, 0xff, 0xff, 0x6b, 0x07, 0xff, - 0xfd, 0x6a, 0x02, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfe, 0x69, 0x03, 0xff, 0xfd, 0x69, 0x05, 0xff, 0xff, 0x67, 0x00, 0xff, 0xff, 0x68, 0x02, 0xff, 0xfe, 0x68, 0x07, 0xff, - 0xff, 0x67, 0x00, 0xff, 0xff, 0x67, 0x03, 0xff, 0xff, 0x68, 0x05, 0xff, 0xff, 0x67, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfd, 0x6a, 0x03, 0xff, 0xfa, 0x6b, 0x05, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xfb, 0x6a, 0x00, 0xff, 0xb6, 0x7a, 0x56, 0xff, 0xff, 0x6d, 0x02, 0xff, 0xff, 0x66, 0x00, 0xff, 0xff, 0x67, 0x06, 0xff, 0xfc, 0x69, 0x02, 0xff, 0x43, 0x43, 0x43, 0xff, 0x41, 0x3c, 0x40, 0xff, - 0x3b, 0x39, 0x44, 0xff, 0x40, 0x3f, 0x3d, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x02, 0xff, 0xff, 0x6c, 0x08, 0xff, 0x5c, 0x37, 0x1d, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xf9, 0x6a, 0x02, 0xff, - 0xfc, 0x6b, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x69, 0x05, 0xff, - 0xfe, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfd, 0x6a, 0x03, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, 0xfd, 0x6a, 0x00, 0xff, 0xfa, 0x6b, 0x03, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xff, 0x6c, 0x00, 0xff, 0x4c, 0x38, 0x31, 0xff, 0xfd, 0x65, 0x00, 0xff, 0xff, 0x68, 0x01, 0xff, 0xff, 0x67, 0x07, 0xff, 0xfe, 0x6b, 0x01, 0xff, 0x39, 0x3f, 0x3f, 0xff, 0x3d, 0x41, 0x40, 0xff, - 0x44, 0x41, 0x4a, 0xff, 0x43, 0x3f, 0x40, 0xff, 0xfc, 0x69, 0x01, 0xff, 0xff, 0x6b, 0x06, 0xff, 0xfe, 0x68, 0x07, 0xff, 0x53, 0x3c, 0x34, 0xff, 0xff, 0x66, 0x00, 0xff, 0xf8, 0x69, 0x01, 0xff, - 0xfc, 0x6b, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xfc, 0x6b, 0x02, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, - 0xfd, 0x6b, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfd, 0x6a, 0x03, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfc, 0x6a, 0x03, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xfd, 0x67, 0x00, 0xff, 0x43, 0x40, 0x47, 0xff, 0xff, 0x6f, 0x01, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x67, 0x05, 0xff, 0xfd, 0x68, 0x01, 0xff, 0x40, 0x44, 0x43, 0xff, 0x3f, 0x43, 0x42, 0xff, - 0x3d, 0x3d, 0x3f, 0xff, 0x43, 0x41, 0x46, 0xff, 0xfb, 0x6e, 0x02, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfc, 0x65, 0x00, 0xff, 0x72, 0x36, 0x12, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x6c, 0x08, 0xff, - 0xfd, 0x6a, 0x02, 0xff, 0xfd, 0x6a, 0x02, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, - 0xfc, 0x6c, 0x00, 0xff, 0xfe, 0x6b, 0x00, 0xff, 0xfd, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, - 0xff, 0x69, 0x00, 0xff, 0x41, 0x3f, 0x42, 0xff, 0xf7, 0x6a, 0x00, 0xff, 0xfb, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x03, 0xff, 0xfc, 0x6b, 0x02, 0xff, 0x44, 0x3f, 0x39, 0xff, 0x3f, 0x3e, 0x3c, 0xff, - 0x41, 0x42, 0x3d, 0xff, 0x3f, 0x40, 0x44, 0xff, 0xf6, 0x6c, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xb5, 0x7b, 0x56, 0xff, 0xfd, 0x6b, 0x00, 0xff, 0xff, 0x68, 0x03, 0xff, - 0xfe, 0x69, 0x02, 0xff, 0xfe, 0x69, 0x03, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfc, 0x6b, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, - 0xfc, 0x6b, 0x00, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfe, 0x69, 0x02, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, - 0xff, 0x6b, 0x00, 0xff, 0x50, 0x3c, 0x31, 0xff, 0xf8, 0x6c, 0x00, 0xff, 0xfc, 0x6e, 0x02, 0xff, 0xff, 0x65, 0x00, 0xff, 0xfd, 0x6c, 0x03, 0xff, 0x43, 0x3e, 0x3a, 0xff, 0x44, 0x40, 0x3f, 0xff, - 0x43, 0x3f, 0x34, 0xff, 0x3e, 0x43, 0x3d, 0xff, 0xf8, 0x6d, 0x04, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, 0x4d, 0x3d, 0x2e, 0xff, 0xfb, 0x67, 0x00, 0xff, 0xff, 0x6d, 0x03, 0xff, - 0xff, 0x68, 0x00, 0xff, 0xff, 0x6b, 0x04, 0xff, 0xfc, 0x67, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xf9, 0x6b, 0x05, 0xff, 0xfb, 0x68, 0x00, 0xff, 0xfe, 0x6d, 0x02, 0xff, - 0xfc, 0x69, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x69, 0x01, 0xff, 0xf9, 0x67, 0x04, 0xff, 0xfd, 0x6b, 0x04, 0xff, 0xfd, 0x69, 0x00, 0xff, 0xff, 0x6c, 0x00, 0xff, 0xff, 0x6b, 0x00, 0xff, - 0xff, 0x69, 0x00, 0xff, 0x6e, 0x34, 0x0f, 0xff, 0xf7, 0x6d, 0x00, 0xff, 0xfc, 0x6e, 0x02, 0xff, 0xff, 0x66, 0x00, 0xff, 0xfe, 0x6b, 0x01, 0xff, 0x39, 0x3f, 0x3d, 0xff, 0x41, 0x42, 0x3d, 0xff, - 0x45, 0x41, 0x38, 0xff, 0x3a, 0x3f, 0x3b, 0xff, 0xfa, 0x6b, 0x03, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x67, 0x00, 0xff, 0x50, 0x43, 0x32, 0xff, 0xed, 0x6e, 0x11, 0xff, 0xfd, 0x66, 0x00, 0xff, - 0xf5, 0x6e, 0x12, 0xff, 0xed, 0x6b, 0x13, 0xff, 0xff, 0x6a, 0x03, 0xff, 0xf3, 0x6e, 0x11, 0xff, 0xfa, 0x66, 0x00, 0xff, 0xfe, 0x6c, 0x05, 0xff, 0xfe, 0x6a, 0x00, 0xff, 0xfd, 0x6a, 0x02, 0xff, - 0xfd, 0x69, 0x00, 0xff, 0xfc, 0x6a, 0x03, 0xff, 0xff, 0x67, 0x01, 0xff, 0xfd, 0x69, 0x07, 0xff, 0xff, 0x6d, 0x06, 0xff, 0xf3, 0x6e, 0x0f, 0xff, 0xef, 0x6d, 0x0b, 0xff, 0xee, 0x6d, 0x0f, 0xff, - 0xf3, 0x70, 0x18, 0xff, 0xd1, 0x73, 0x35, 0xff, 0xf9, 0x6d, 0x00, 0xff, 0xfa, 0x6b, 0x03, 0xff, 0xff, 0x63, 0x00, 0xff, 0xff, 0x6e, 0x02, 0xff, 0x3d, 0x43, 0x43, 0xff, 0x41, 0x41, 0x41, 0xff, - 0x3f, 0x41, 0x3e, 0xff, 0x40, 0x41, 0x46, 0xff, 0xfb, 0x68, 0x00, 0xff, 0xff, 0x68, 0x02, 0xff, 0xfc, 0x6e, 0x02, 0xff, 0x67, 0x31, 0x05, 0xff, 0x85, 0x31, 0x00, 0xff, 0xff, 0x6c, 0x03, 0xff, - 0x89, 0x2b, 0x00, 0xff, 0x88, 0x2f, 0x00, 0xff, 0xf9, 0x65, 0x00, 0xff, 0x88, 0x2e, 0x00, 0xff, 0xf9, 0x70, 0x10, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x67, 0x00, 0xff, 0xfa, 0x67, 0x00, 0xff, - 0xff, 0x6a, 0x00, 0xff, 0xf6, 0x6d, 0x0d, 0xff, 0xfc, 0x6a, 0x05, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xf9, 0x66, 0x00, 0xff, 0x89, 0x24, 0x00, 0xff, 0x8c, 0x34, 0x00, 0xff, 0x86, 0x2a, 0x00, 0xff, - 0x85, 0x27, 0x00, 0xff, 0xf4, 0x73, 0x15, 0xff, 0xfe, 0x6c, 0x00, 0xff, 0xfd, 0x6b, 0x06, 0xff, 0xff, 0x69, 0x09, 0xff, 0xfe, 0x63, 0x00, 0xff, 0x45, 0x44, 0x42, 0xff, 0x3a, 0x3d, 0x42, 0xff, - 0x3d, 0x3f, 0x3e, 0xff, 0x40, 0x40, 0x4a, 0xff, 0xff, 0x6d, 0x00, 0xff, 0xff, 0x67, 0x03, 0xff, 0xf8, 0x69, 0x01, 0xff, 0xd3, 0x76, 0x30, 0xff, 0xcf, 0x7b, 0x35, 0xff, 0xfd, 0x64, 0x00, 0xff, - 0xd6, 0x77, 0x33, 0xff, 0xc9, 0x73, 0x38, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xce, 0x74, 0x38, 0xff, 0xf5, 0x6c, 0x0c, 0xff, 0xff, 0x66, 0x00, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x6a, 0x03, 0xff, - 0xff, 0x6b, 0x00, 0xff, 0xf4, 0x6b, 0x0b, 0xff, 0xfb, 0x69, 0x04, 0xff, 0xff, 0x68, 0x00, 0xff, 0xfd, 0x69, 0x00, 0xff, 0xe2, 0x7c, 0x34, 0xff, 0xca, 0x71, 0x35, 0xff, 0xd3, 0x75, 0x37, 0xff, - 0xd5, 0x79, 0x38, 0xff, 0xfc, 0x68, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xfd, 0x6b, 0x08, 0xff, 0xff, 0x69, 0x0b, 0xff, 0xff, 0x67, 0x00, 0xff, 0x41, 0x40, 0x3e, 0xff, 0x41, 0x40, 0x46, 0xff, - 0x42, 0x41, 0x3f, 0xff, 0x39, 0x40, 0x46, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xfe, 0x65, 0x00, 0xff, 0xff, 0x6b, 0x04, 0xff, 0xef, 0x6d, 0x0b, 0xff, 0xf1, 0x6e, 0x13, 0xff, 0xff, 0x6b, 0x07, 0xff, - 0xee, 0x6e, 0x0d, 0xff, 0xea, 0x71, 0x18, 0xff, 0xff, 0x6b, 0x00, 0xff, 0xef, 0x6f, 0x14, 0xff, 0xff, 0x6b, 0x04, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x66, 0x00, 0xff, 0xfd, 0x66, 0x00, 0xff, - 0xfd, 0x69, 0x00, 0xff, 0xf9, 0x6a, 0x01, 0xff, 0xff, 0x6a, 0x00, 0xff, 0xff, 0x68, 0x00, 0xff, 0xff, 0x69, 0x00, 0xff, 0xf2, 0x6d, 0x10, 0xff, 0xed, 0x6b, 0x13, 0xff, 0xf4, 0x6e, 0x17, 0xff, - 0xf0, 0x6f, 0x13, 0xff, 0xff, 0x69, 0x00, 0xff, 0xff, 0x6c, 0x00, 0xff, 0xfc, 0x6d, 0x07, 0xff, 0xfd, 0x65, 0x02, 0xff, 0xff, 0x6b, 0x00, 0xff, 0x3d, 0x41, 0x40, 0xff, 0x43, 0x3f, 0x3e, 0xff, - 0x41, 0x40, 0x3e, 0xff, 0x39, 0x41, 0x43, 0xff, 0xe5, 0x6e, 0x1a, 0xff, 0xe3, 0x72, 0x24, 0xff, 0xe1, 0x70, 0x24, 0xff, 0xe4, 0x76, 0x21, 0xff, 0xde, 0x6d, 0x1f, 0xff, 0xe2, 0x6e, 0x23, 0xff, - 0xe2, 0x73, 0x22, 0xff, 0xda, 0x70, 0x24, 0xff, 0xe4, 0x6e, 0x17, 0xff, 0xe3, 0x74, 0x25, 0xff, 0xe4, 0x6f, 0x1f, 0xff, 0xe5, 0x6e, 0x1e, 0xff, 0xe3, 0x73, 0x29, 0xff, 0xe4, 0x73, 0x25, 0xff, - 0xde, 0x71, 0x1f, 0xff, 0xe4, 0x73, 0x23, 0xff, 0xe5, 0x72, 0x22, 0xff, 0xe3, 0x70, 0x1f, 0xff, 0xe3, 0x72, 0x22, 0xff, 0xe1, 0x72, 0x23, 0xff, 0xe2, 0x71, 0x23, 0xff, 0xe1, 0x6d, 0x22, 0xff, - 0xe0, 0x71, 0x22, 0xff, 0xe5, 0x72, 0x21, 0xff, 0xe2, 0x72, 0x20, 0xff, 0xd9, 0x6e, 0x20, 0xff, 0xe7, 0x73, 0x26, 0xff, 0xe3, 0x75, 0x1e, 0xff, 0x39, 0x42, 0x41, 0xff, 0x46, 0x40, 0x40, 0xff, - 0x3f, 0x3f, 0x3d, 0xff, 0x3e, 0x42, 0x41, 0xff, 0x5c, 0x38, 0x18, 0xff, 0x5d, 0x39, 0x23, 0xff, 0x60, 0x38, 0x1f, 0xff, 0x5e, 0x39, 0x1c, 0xff, 0x57, 0x39, 0x1d, 0xff, 0x5f, 0x3a, 0x1d, 0xff, - 0x5f, 0x3c, 0x20, 0xff, 0x58, 0x38, 0x21, 0xff, 0x60, 0x37, 0x19, 0xff, 0x5e, 0x39, 0x1c, 0xff, 0x5d, 0x38, 0x1b, 0xff, 0x5b, 0x34, 0x15, 0xff, 0x5c, 0x3e, 0x26, 0xff, 0x5a, 0x36, 0x1c, 0xff, - 0x5d, 0x39, 0x21, 0xff, 0x60, 0x39, 0x1c, 0xff, 0x5c, 0x38, 0x1e, 0xff, 0x5c, 0x35, 0x18, 0xff, 0x58, 0x38, 0x1f, 0xff, 0x5e, 0x3a, 0x1a, 0xff, 0x5c, 0x39, 0x1d, 0xff, 0x61, 0x39, 0x1f, 0xff, - 0x5d, 0x39, 0x1f, 0xff, 0x5f, 0x37, 0x1e, 0xff, 0x59, 0x3a, 0x1e, 0xff, 0x5f, 0x3a, 0x1d, 0xff, 0x60, 0x39, 0x1c, 0xff, 0x5b, 0x3a, 0x19, 0xff, 0x3a, 0x40, 0x3c, 0xff, 0x40, 0x3b, 0x3f, 0xff, - 0x3e, 0x40, 0x3f, 0xff, 0x3e, 0x40, 0x3d, 0xff, 0x41, 0x43, 0x3e, 0xff, 0x3d, 0x40, 0x45, 0xff, 0x3f, 0x3d, 0x40, 0xff, 0x3f, 0x3f, 0x3d, 0xff, 0x3c, 0x46, 0x45, 0xff, 0x3f, 0x40, 0x3b, 0xff, - 0x3d, 0x3d, 0x3d, 0xff, 0x40, 0x44, 0x47, 0xff, 0x42, 0x3e, 0x3b, 0xff, 0x40, 0x3f, 0x3b, 0xff, 0x40, 0x40, 0x3e, 0xff, 0x42, 0x41, 0x3d, 0xff, 0x38, 0x42, 0x44, 0xff, 0x3d, 0x41, 0x40, 0xff, - 0x40, 0x41, 0x45, 0xff, 0x43, 0x3f, 0x3e, 0xff, 0x3e, 0x3f, 0x43, 0xff, 0x41, 0x40, 0x3c, 0xff, 0x3b, 0x43, 0x45, 0xff, 0x3f, 0x40, 0x3a, 0xff, 0x3d, 0x3f, 0x3c, 0xff, 0x42, 0x41, 0x3f, 0xff, - 0x3f, 0x3f, 0x41, 0xff, 0x41, 0x3f, 0x42, 0xff, 0x3b, 0x43, 0x45, 0xff, 0x3f, 0x3e, 0x39, 0xff, 0x42, 0x3f, 0x3a, 0xff, 0x3d, 0x43, 0x3f, 0xff, 0x3d, 0x43, 0x3f, 0xff, 0x42, 0x3f, 0x46, 0xff}; - -// clang-format on - -inline std::vector -ReadBlobUnsafe(const std::string& filename) -{ - std::ifstream file(filename, std::ios::binary | std::ios::ate); - - if (!file.is_open()) - return {}; - - std::ifstream::pos_type pos = file.tellg(); - - // What happens if the OS supports really big files. - // It may be larger than 32 bits? - // This will silently truncate the value/ - std::streamoff length = pos; - - std::vector bytes(length); - if (pos > 0) - { // Manuall memory management. - // Not a good idea use a container/. - file.seekg(0, std::ios::beg); - file.read((char*)bytes.data(), length); - } - file.close(); - return bytes; -}; - -int -main() -{ - - Fox::DContextConfig config; - config.logOutputFunction = &Log; - config.warningFunction = &Log; - - Fox::IContext* context = Fox::CreateVulkanContext(&config); - - { - if (!glfwInit()) - { - throw std::runtime_error("Failed to glfwInit"); - } - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); // as Vulkan, there is no need to create a context - GLFWwindow* window = glfwCreateWindow(640, 480, "My Title", NULL, NULL); - if (!window) - { - throw std::runtime_error("Failed to glfwCreateWindow"); - } - Fox::WindowData windowData; - windowData._hwnd = glfwGetWin32Window(window); - windowData._instance = GetModuleHandle(NULL); - - Fox::SwapchainId swapchain; - auto presentMode = Fox::EPresentMode::IMMEDIATE_KHR; - auto format = Fox::EFormat::B8G8R8A8_UNORM; - swapchain = context->CreateSwapchain(&windowData, presentMode, format); - if (swapchain == NULL) - { - throw std::runtime_error("Failed to CreateSwapchain"); - } - - // Create vertex layout - Fox::VertexLayoutInfo position("SV_POSITION", Fox::EFormat::R32G32B32_FLOAT, 0, Fox::EVertexInputClassification::PER_VERTEX_DATA); - Fox::VertexLayoutInfo color("Color0", Fox::EFormat::R32G32B32A32_FLOAT, 3 * sizeof(float), Fox::EVertexInputClassification::PER_VERTEX_DATA); - Fox::VertexInputLayoutId vertexLayout = context->CreateVertexLayout({ position, color }); - constexpr uint32_t stride = 7 * sizeof(float); - - Fox::ShaderSource shaderSource; - shaderSource.VertexLayout = vertexLayout; - shaderSource.VertexStride = stride; - shaderSource.SourceCode.VertexShader = ReadBlobUnsafe("vertex.spv"); - shaderSource.SourceCode.PixelShader = ReadBlobUnsafe("fragment.spv"); - - shaderSource.SetsLayout.SetsLayout[0].insert({ 0, Fox::ShaderDescriptorBindings("MatrixUbo", Fox::EBindingType::UNIFORM_BUFFER_OBJECT, sizeof(float) * 16, 1, Fox::EShaderStage::VERTEX) }); - shaderSource.SetsLayout.SetsLayout[1].insert({ 0, Fox::ShaderDescriptorBindings("MyTexture", Fox::EBindingType::SAMPLER, 1, 1, Fox::EShaderStage::FRAGMENT) }); - - shaderSource.ColorAttachments = 1; - shaderSource.DepthStencilAttachment = false; - - Fox::ShaderId shader = context->CreateShader(shaderSource); - - // clang-format off - constexpr std::array ndcQuad{ - -1, -1, 0.5,//pos - 0, 1, 0, 1,// color - 1, -1, 0.5,//pos - 0, 0, 1, 1,// color - 1, 1, 0.5,//pos - 0, 1, 1, 1,// color - //----------------// - -1, -1, 0.5,//pos - 0, 1, 0, 1,// color - 1, 1, 0.5,//pos - 0, 0, 1, 1,// color - -1, 1, 0.5,//pos - 0, 1, 1, 1// color - }; - // clang-format on - constexpr size_t bufSize = sizeof(float) * ndcQuad.size(); - Fox::BufferId quad = context->CreateVertexBuffer(bufSize); - - Fox::CopyDataCommand copy; - copy.CopyVertex(quad, 0, (void*)ndcQuad.data(), bufSize); - context->SubmitCopy(std::move(copy)); - - Fox::FramebufferId swapchainFbo = context->CreateSwapchainFramebuffer_DEPRECATED(swapchain); - - Fox::DRenderPassAttachment colorAttachment(format, - Fox::ESampleBit::COUNT_1_BIT, - Fox::ERenderPassLoad::Clear, - Fox::ERenderPassStore::Store, - Fox::ERenderPassLayout::Undefined, - Fox::ERenderPassLayout::Present, - Fox::EAttachmentReference::COLOR_ATTACHMENT); - Fox::DRenderPassAttachments renderPass; - renderPass.Attachments.push_back(colorAttachment); - - Fox::BufferId transformUniformBuffer = context->CreateUniformBuffer(sizeof(float) * 16); - float yaw{ 0 }; - - Fox::ImageId texture = context->CreateImage(Fox::EFormat::R8G8B8A8_UNORM, imageWidth, imageHeight, 1); - { - Fox::CopyDataCommand copy; - copy.CopyImageMipMap(texture, 0, (void*)image, imageWidth, imageHeight, 0, sizeof(image)); - context->SubmitCopy(std::move(copy)); - } - - bool wireFrame{}; - while (!glfwWindowShouldClose(window)) - { - // Keep running - glfwPollEvents(); - - if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) - { - wireFrame = !wireFrame; - } - - int w, h; - glfwGetWindowSize(window, &w, &h); - Fox::DViewport viewport{ 0, 0, w, h, 0.f, 1.f }; - - { - // yaw += 0.01f; - const float sinA = std::sin(yaw); - const float cosA = std::cos(yaw); - - float matrix[4][4]{ { cosA, 0, -sinA, 0 }, { 0, 1, 0, 0 }, { sinA, 0, cosA, 0 }, { 0, 0, 0, 1 } }; - Fox::CopyDataCommand copy; - copy.CopyUniformBuffer(transformUniformBuffer, &matrix[0][0], sizeof(float) * 16); - context->SubmitCopy(std::move(copy)); - } - - Fox::RenderPassData draw(swapchainFbo, viewport, renderPass); - draw.ClearColor(1, 0, 0, 1); - - Fox::DrawCommand drawTriangle(shader); - drawTriangle.PipelineFormat.FillMode = wireFrame ? Fox::EFillMode::LINE : Fox::EFillMode::FILL; - drawTriangle.BindBufferUniformBuffer(0, 0, transformUniformBuffer); - drawTriangle.BindImageArray(1, 0, { texture }); - drawTriangle.Draw(quad, 0, 6); - - draw.AddDrawCommand(std::move(drawTriangle)); - - context->SubmitPass(std::move(draw)); - - context->AdvanceFrame(); - } - - context->DestroyShader(shader); - context->DestroyImage(texture); - context->DestroyBuffer(quad); - context->DestroyBuffer(transformUniformBuffer); - context->_destroyFramebuffer(swapchainFbo); - context->DestroySwapchain(swapchain); - - glfwDestroyWindow(window); - - glfwTerminate(); - } - - delete context; - - return 0; -} \ No newline at end of file diff --git a/examples/TexturedQuad/buildShaders.bat b/examples/TexturedQuad/buildShaders.bat deleted file mode 100644 index 890d4a2..0000000 --- a/examples/TexturedQuad/buildShaders.bat +++ /dev/null @@ -1,3 +0,0 @@ -C:\VulkanSDK\1.3.261.1\Bin\glslc.exe -fshader-stage=vert vertex.glsl -o vertex.spv -C:\VulkanSDK\1.3.261.1\Bin\glslc.exe -fshader-stage=frag fragment.glsl -o fragment.spv -pause \ No newline at end of file diff --git a/examples/TexturedQuad/fragment.glsl b/examples/TexturedQuad/fragment.glsl deleted file mode 100644 index 4dc4738..0000000 --- a/examples/TexturedQuad/fragment.glsl +++ /dev/null @@ -1,20 +0,0 @@ -#version 450 - -layout(location = 0) in vec2 pos; -layout(location = 0) out vec4 outColor; - -layout(set =1, binding = 0) uniform sampler2D MyTexture; - -vec2 CorrectUv(vec2 uv) -{ -return vec2(uv.x, 1-uv.y); -} -vec2 xCorrectUv(vec2 uv) -{ -return uv; -} - -void main() { - vec4 texColor = texture(MyTexture, pos); - outColor = texColor; -} \ No newline at end of file diff --git a/examples/TexturedQuad/fragment.spv b/examples/TexturedQuad/fragment.spv deleted file mode 100644 index e2bcebc7c5b038061fbae37047a7261701bbdb8a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 708 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�D{lBwKIQ*&8xR) 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 JA0aO#e*wRVV@&`6 diff --git a/thirdparty/tinygltf b/thirdparty/tinygltf deleted file mode 160000 index 5e8a7fd..0000000 --- a/thirdparty/tinygltf +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5e8a7fd602af22aa9619ccd3baeaeeaff0ecb6f3 From 35e6f7f145e26142b778e4f94b578ba9a713e0c5 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Wed, 17 Jan 2024 10:24:04 +0100 Subject: [PATCH 09/58] improved minimized window surface functions --- include/IContext.h | 16 +- src/backend/vulkan/VulkanContext.cpp | 265 ++++++++++++++++++++------- src/backend/vulkan/VulkanContext.h | 3 + src/backend/vulkan/VulkanDevice2.cpp | 2 + 4 files changed, 219 insertions(+), 67 deletions(-) diff --git a/include/IContext.h b/include/IContext.h index 31e442f..727629c 100644 --- a/include/IContext.h +++ b/include/IContext.h @@ -706,11 +706,17 @@ class IContext { public: virtual ~IContext(){}; - virtual void WaitDeviceIdle() = 0; - virtual uint32_t CreateSwapchain(const WindowData* windowData, EPresentMode& presentMode, EFormat& outFormat, uint32_t* width = nullptr, uint32_t* height = nullptr) = 0; - virtual std::vector GetSwapchainRenderTargets(uint32_t swapchainId) = 0; - virtual bool SwapchainAcquireNextImageIndex(uint32_t swapchainId, uint64_t timeoutNanoseconds, uint32_t sempahoreid, uint32_t* outImageIndex) = 0; - virtual void DestroySwapchain(uint32_t swapchainId) = 0; + virtual void WaitDeviceIdle() = 0; + virtual uint32_t CreateSwapchain(const WindowData* windowData, EPresentMode& presentMode, EFormat& outFormat, uint32_t* width = nullptr, uint32_t* height = nullptr) = 0; + /** + * /brief Returns a list of render targers for each frame (1 single buffered, 2 double buffered) + * /param swapchainId the swapchain id + * /return List of render targer ids if swapchain is in valid state or empty vector otherwise + */ + virtual std::vector GetSwapchainRenderTargets(uint32_t swapchainId) = 0; + virtual bool SwapchainAcquireNextImageIndex(uint32_t swapchainId, uint64_t timeoutNanoseconds, uint32_t sempahoreid, uint32_t* outImageIndex) = 0; + virtual bool SwapchainHasValidSurface(SwapchainId swapchainId) = 0; + virtual void DestroySwapchain(uint32_t swapchainId) = 0; /** * \brief If exists will return a specialized queue, otherwise if exists will return a queue with that feature, otherwise it will return a general purpose queue that supports that feature. If no diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index 5d9fa9b..3158752 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -451,6 +451,8 @@ VulkanContext::CreateSwapchain(const WindowData* windowData, EPresentMode& prese { const auto index = AllocResource(_swapchains); DSwapchainVulkan& swapchain = _swapchains.at(index); + swapchain.Surface = nullptr; + swapchain.Swapchain = nullptr; _createSwapchain(swapchain, windowData, presentMode, outFormat); @@ -477,13 +479,12 @@ VulkanContext::_createSwapchain(DSwapchainVulkan& swapchain, const WindowData* w } } - uint32_t queueFamilyIndex{}; + // Find presentable graphics queue { - uint32_t queueIndex{}; uint32_t queueIndexCount[16]{}; const auto foundGraphicsQueueId{ VkUtils::findQueueWithFlags( - &queueFamilyIndex, &queueIndex, VK_QUEUE_GRAPHICS_BIT, Device.QueueFamilies.data(), Device.QueueFamilies.size(), queueIndexCount) }; - const bool supportPresentation{ Device.SurfaceSupportPresentationOnQueueFamilyIndex(surface, queueFamilyIndex) }; + &swapchain.QueueFamilyIndex, &swapchain.QueueIndex, VK_QUEUE_GRAPHICS_BIT, Device.QueueFamilies.data(), Device.QueueFamilies.size(), queueIndexCount) }; + const bool supportPresentation{ Device.SurfaceSupportPresentationOnQueueFamilyIndex(surface, swapchain.QueueFamilyIndex) }; if (!supportPresentation) { throw std::runtime_error("Vulkan graphics queue does not support presentation to this surface!"); @@ -506,14 +507,17 @@ VulkanContext::_createSwapchain(DSwapchainVulkan& swapchain, const WindowData* w const auto capabilities = Device.GetSurfaceCapabilities(surface); // Create swapchain object + check(swapchain.Swapchain == nullptr); VkSwapchainKHR vkSwapchain{}; - { - const auto result = Device.CreateSwapchainFromSurface(surface, formats.at(0), vkPresentMode, capabilities, &queueFamilyIndex, 1, &vkSwapchain); - if (VKFAILED(result)) - { - throw std::runtime_error("Failed to create swapchain " + std::string(VkUtils::VkErrorString(result))); - } - } + // Only create swapchain when extent is meaningful as > 0px + if (capabilities.currentExtent.width > 0 && capabilities.currentExtent.height > 0) + { + const auto result = Device.CreateSwapchainFromSurface(surface, formats.at(0), vkPresentMode, capabilities, &swapchain.QueueFamilyIndex, 1, &vkSwapchain); + if (VKFAILED(result)) + { + throw std::runtime_error("Failed to create swapchain " + std::string(VkUtils::VkErrorString(result))); + } + } // Setup new object swapchain.Surface = surface; swapchain.Capabilities = capabilities; @@ -521,30 +525,42 @@ VulkanContext::_createSwapchain(DSwapchainVulkan& swapchain, const WindowData* w swapchain.PresentMode = vkPresentMode; swapchain.Swapchain = vkSwapchain; - const auto swapchainImages = Device.GetSwapchainImages(vkSwapchain); - swapchain.ImagesCount = swapchainImages.size(); - for (size_t i = 0; i < swapchainImages.size(); i++) + // Reset the images/render targers ids + for (size_t i = 0; i < DSwapchainVulkan::MAX_IMAGE_COUNT; i++) { - swapchain.ImagesId[i] = _createImageFromVkImage(swapchainImages.at(i), swapchain.Format.format, swapchain.Capabilities.currentExtent.width, swapchain.Capabilities.currentExtent.height); + swapchain.ImagesId[i] = 0; + swapchain.RenderTargetsId[i] = 0; } - // Create render targets - for (size_t i = 0; i < swapchainImages.size(); i++) + // Only create image views and render targets when a swapchain was created + if (vkSwapchain != NULL) { - const auto index = AllocResource(_renderTargets); - auto& renderTargetRef = _renderTargets.at(index); - - const auto& imageRef = GetResource(_images, swapchain.ImagesId[i]); - renderTargetRef.Image = imageRef.Image; - renderTargetRef.ImageAspect = imageRef.ImageAspect; - - const auto result = Device.CreateImageView(imageRef.Image.Format, imageRef.Image.Image, imageRef.ImageAspect, 0, 1, &renderTargetRef.View); - if (VKFAILED(result)) + const auto swapchainImages = Device.GetSwapchainImages(vkSwapchain); + swapchain.ImagesCount = swapchainImages.size(); + for (size_t i = 0; i < swapchainImages.size(); i++) { - throw std::runtime_error("Failed to create swapchain imageView " + std::string(VkUtils::VkErrorString(result))); + swapchain.ImagesId[i] = + _createImageFromVkImage(swapchainImages.at(i), swapchain.Format.format, swapchain.Capabilities.currentExtent.width, swapchain.Capabilities.currentExtent.height); } - swapchain.RenderTargetsId[i] = *ResourceId(EResourceType::RENDER_TARGET, renderTargetRef.Id, index); + // Create render targets + for (size_t i = 0; i < swapchainImages.size(); i++) + { + const auto index = AllocResource(_renderTargets); + auto& renderTargetRef = _renderTargets.at(index); + + const auto& imageRef = GetResource(_images, swapchain.ImagesId[i]); + renderTargetRef.Image = imageRef.Image; + renderTargetRef.ImageAspect = imageRef.ImageAspect; + + const auto result = Device.CreateImageView(imageRef.Image.Format, imageRef.Image.Image, imageRef.ImageAspect, 0, 1, &renderTargetRef.View); + if (VKFAILED(result)) + { + throw std::runtime_error("Failed to create swapchain imageView " + std::string(VkUtils::VkErrorString(result))); + } + + swapchain.RenderTargetsId[i] = *ResourceId(EResourceType::RENDER_TARGET, renderTargetRef.Id, index); + } } } @@ -557,15 +573,130 @@ VulkanContext::GetSwapchainRenderTargets(SwapchainId swapchainId) DSwapchainVulkan& swapchain = GetResource(_swapchains, swapchainId); - std::vector images; - images.resize(swapchain.ImagesCount); + // If has no swapchain return none + if (swapchain.Swapchain == NULL) + { + return {}; + } + + std::vector rts; + rts.resize(swapchain.ImagesCount); for (size_t i = 0; i < swapchain.ImagesCount; i++) { - images[i] = swapchain.RenderTargetsId[i]; + rts[i] = swapchain.RenderTargetsId[i]; } - return images; + return rts; +} + +bool +VulkanContext::SwapchainHasValidSurface(SwapchainId swapchainId) +{ + DSwapchainVulkan& swapchain = GetResource(_swapchains, swapchainId); + swapchain.Capabilities = Device.GetSurfaceCapabilities(swapchain.Surface); + + if (swapchain.Capabilities.currentExtent.width == 0 || swapchain.Capabilities.currentExtent.height == 0) + { + // Destroy swapchain and imaged and RT + if (swapchain.Swapchain) + { + Device.DestroySwapchain(swapchain.Swapchain); + swapchain.Swapchain = nullptr; + + for (uint32_t i = 0; i < swapchain.ImagesCount; i++) + { + auto& imageRef = GetResource(_images, swapchain.ImagesId[i]); + Device.DestroyImageView(imageRef.View); + imageRef.Id = FREE; + + const auto renderTargetId{ swapchain.RenderTargetsId[i] }; + auto& renderTargetRef = GetResource(_renderTargets, renderTargetId); + + Device.DestroyImageView(renderTargetRef.View); + renderTargetRef.Id = FREE; + + // Must destroy all framebuffers that reference this render target @TODO find a better algorithm without iterating over the array multiple times + const auto referenceCount = std::count_if(_framebuffers.begin(), _framebuffers.end(), [renderTargetId](const DFramebufferVulkan& fbo) { + for (size_t i = 0; i < DFramebufferAttachments::MAX_ATTACHMENTS; i++) + { + if (fbo.Attachments.RenderTargets[i] == renderTargetId) + { + return true; + } + } + return false; + }); + for (uint32_t i = 0; i < referenceCount; i++) + { + auto foundFbo = std::find_if(_framebuffers.begin(), _framebuffers.end(), [renderTargetId](const DFramebufferVulkan& fbo) { + for (size_t i = 0; i < DFramebufferAttachments::MAX_ATTACHMENTS; i++) + { + if (fbo.Attachments.RenderTargets[i] == renderTargetId) + { + return true; + } + } + return false; + }); + + Device._destroyFramebuffer(foundFbo->Framebuffer); + foundFbo->Id = FREE; + } + } + + std::fill(swapchain.ImagesId.begin(), swapchain.ImagesId.end(), 0); + std::fill(swapchain.RenderTargetsId, swapchain.RenderTargetsId + DSwapchainVulkan::MAX_IMAGE_COUNT, 0); + } + + return false; + } + + if (swapchain.Swapchain != NULL) + { + return true; + } + + // Create swapchain object + { + const auto result = Device.CreateSwapchainFromSurface(swapchain.Surface, swapchain.Format, swapchain.PresentMode, swapchain.Capabilities, &swapchain.QueueFamilyIndex, 1, &swapchain.Swapchain); + if (VKFAILED(result)) + { + throw std::runtime_error("Failed to create swapchain " + std::string(VkUtils::VkErrorString(result))); + } + } + + // Recreate images and RTs + { + const auto swapchainImages = Device.GetSwapchainImages(swapchain.Swapchain); + swapchain.ImagesCount = swapchainImages.size(); + for (size_t i = 0; i < swapchainImages.size(); i++) + { + swapchain.ImagesId[i] = + _createImageFromVkImage(swapchainImages.at(i), swapchain.Format.format, swapchain.Capabilities.currentExtent.width, swapchain.Capabilities.currentExtent.height); + } + + // Create render targets + for (size_t i = 0; i < swapchainImages.size(); i++) + { + const auto index = AllocResource(_renderTargets); + auto& renderTargetRef = _renderTargets.at(index); + + const auto& imageRef = GetResource(_images, swapchain.ImagesId[i]); + renderTargetRef.Image = imageRef.Image; + renderTargetRef.ImageAspect = imageRef.ImageAspect; + + const auto result = Device.CreateImageView(imageRef.Image.Format, imageRef.Image.Image, imageRef.ImageAspect, 0, 1, &renderTargetRef.View); + if (VKFAILED(result)) + { + throw std::runtime_error("Failed to create swapchain imageView " + std::string(VkUtils::VkErrorString(result))); + } + + swapchain.RenderTargetsId[i] = *ResourceId(EResourceType::RENDER_TARGET, renderTargetRef.Id, index); + } + } + + return true; } bool @@ -574,6 +705,11 @@ VulkanContext::SwapchainAcquireNextImageIndex(SwapchainId swapchainId, uint64_t DSwapchainVulkan& swapchain = GetResource(_swapchains, swapchainId); DSemaphoreVulkan& semaphoreRef = GetResource(_semaphores, sempahoreid); + if (swapchain.Swapchain == NULL) + { + return false; + } + const VkResult result = Device.AcquireNextImage(swapchain.Swapchain, timeoutNanoseconds, outImageIndex, semaphoreRef.Semaphore, VK_NULL_HANDLE); /*Spec: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/vkQueueSubmit.html*/ /* @@ -653,38 +789,24 @@ VulkanContext::DestroySwapchain(SwapchainId swapchainId) check(resource.First() == EResourceType::SWAPCHAIN); DSwapchainVulkan& swapchain = GetResource(_swapchains, swapchainId); - - Device.DestroySwapchain(swapchain.Swapchain); - Instance.DestroySurface(swapchain.Surface); - - swapchain.Id = FREE; - - for (uint32_t i = 0; i < swapchain.ImagesCount; i++) + if (swapchain.Swapchain) { - auto& imageRef = GetResource(_images, swapchain.ImagesId[i]); - Device.DestroyImageView(imageRef.View); - imageRef.Id = FREE; + Device.DestroySwapchain(swapchain.Swapchain); - const auto renderTargetId{ swapchain.RenderTargetsId[i] }; - auto& renderTargetRef = GetResource(_renderTargets, renderTargetId); + for (uint32_t i = 0; i < swapchain.ImagesCount; i++) + { + auto& imageRef = GetResource(_images, swapchain.ImagesId[i]); + Device.DestroyImageView(imageRef.View); + imageRef.Id = FREE; - Device.DestroyImageView(renderTargetRef.View); - renderTargetRef.Id = FREE; + const auto renderTargetId{ swapchain.RenderTargetsId[i] }; + auto& renderTargetRef = GetResource(_renderTargets, renderTargetId); - // Must destroy all framebuffers that reference this render target @TODO find a better algorithm without iterating over the array multiple times - const auto referenceCount = std::count_if(_framebuffers.begin(), _framebuffers.end(), [renderTargetId](const DFramebufferVulkan& fbo) { - for (size_t i = 0; i < DFramebufferAttachments::MAX_ATTACHMENTS; i++) - { - if (fbo.Attachments.RenderTargets[i] == renderTargetId) - { - return true; - } - } - return false; - }); - for (uint32_t i = 0; i < referenceCount; i++) - { - auto foundFbo = std::find_if(_framebuffers.begin(), _framebuffers.end(), [renderTargetId](const DFramebufferVulkan& fbo) { + Device.DestroyImageView(renderTargetRef.View); + renderTargetRef.Id = FREE; + + // Must destroy all framebuffers that reference this render target @TODO find a better algorithm without iterating over the array multiple times + const auto referenceCount = std::count_if(_framebuffers.begin(), _framebuffers.end(), [renderTargetId](const DFramebufferVulkan& fbo) { for (size_t i = 0; i < DFramebufferAttachments::MAX_ATTACHMENTS; i++) { if (fbo.Attachments.RenderTargets[i] == renderTargetId) @@ -694,11 +816,27 @@ VulkanContext::DestroySwapchain(SwapchainId swapchainId) } return false; }); + for (uint32_t i = 0; i < referenceCount; i++) + { + auto foundFbo = std::find_if(_framebuffers.begin(), _framebuffers.end(), [renderTargetId](const DFramebufferVulkan& fbo) { + for (size_t i = 0; i < DFramebufferAttachments::MAX_ATTACHMENTS; i++) + { + if (fbo.Attachments.RenderTargets[i] == renderTargetId) + { + return true; + } + } + return false; + }); - Device._destroyFramebuffer(foundFbo->Framebuffer); - foundFbo->Id = FREE; + Device._destroyFramebuffer(foundFbo->Framebuffer); + foundFbo->Id = FREE; + } } } + + // Destroy surface always after the swapchain + Instance.DestroySurface(swapchain.Surface); swapchain.ImagesCount = 0; swapchain.Id = FREE; @@ -1777,6 +1915,9 @@ VulkanContext::SetScissor(uint32_t commandBufferId, uint32_t x, uint32_t y, uint check(commandBufferRef.IsRecording); // Must be in recording state check(commandBufferRef.ActiveRenderPass); // Must be in a render pass + check(x + width <= std::numeric_limits().max()); // sum must not overflow int32_t + check(y + height <= std::numeric_limits().max()); // sum must not overflow int32_t + VkRect2D rect{ x, y, width, height }; vkCmdSetScissor(commandBufferRef.Cmd, 0, 1, &rect); } diff --git a/src/backend/vulkan/VulkanContext.h b/src/backend/vulkan/VulkanContext.h index 77c51f8..ee67c6e 100644 --- a/src/backend/vulkan/VulkanContext.h +++ b/src/backend/vulkan/VulkanContext.h @@ -58,6 +58,8 @@ struct DSwapchainVulkan : public DResource VkSurfaceCapabilitiesKHR Capabilities; VkSurfaceFormatKHR Format; VkPresentModeKHR PresentMode; + uint32_t QueueFamilyIndex{}; + uint32_t QueueIndex{}; VkSwapchainKHR Swapchain{}; uint32_t ImagesCount{}; std::array ImagesId; @@ -166,6 +168,7 @@ class VulkanContext final : public IContext void WaitDeviceIdle() override; SwapchainId CreateSwapchain(const WindowData* windowData, EPresentMode& presentMode, EFormat& outFormat, uint32_t* width = nullptr, uint32_t* height = nullptr) override; std::vector GetSwapchainRenderTargets(SwapchainId swapchainId) override; + bool SwapchainHasValidSurface(SwapchainId swapchainId) override; bool SwapchainAcquireNextImageIndex(SwapchainId swapchainId, uint64_t timeoutNanoseconds, uint32_t sempahoreid, uint32_t* outImageIndex) override; void DestroySwapchain(SwapchainId swapchainId) override; diff --git a/src/backend/vulkan/VulkanDevice2.cpp b/src/backend/vulkan/VulkanDevice2.cpp index b26040f..fb65df7 100644 --- a/src/backend/vulkan/VulkanDevice2.cpp +++ b/src/backend/vulkan/VulkanDevice2.cpp @@ -107,6 +107,8 @@ VkSwapchainKHR oldSwapchain) swapchainInfo.imageFormat = format.format; swapchainInfo.imageColorSpace = format.colorSpace; + check(capabilities.currentExtent.width > 0); // imageExtent members width and height must both be non-zero + check(capabilities.currentExtent.height > 0); // imageExtent members width and height must both be non-zero check(capabilities.currentExtent.width <= capabilities.maxImageExtent.width); check(capabilities.currentExtent.height <= capabilities.maxImageExtent.height); From cad079c0045cfc1e9b7f5ccd7056a314eace4d8b Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Mon, 5 Feb 2024 14:00:45 +0100 Subject: [PATCH 10/58] reduced cmake version --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bee71f4..7a33df2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.26.4) +cmake_minimum_required(VERSION 3.12) project(FoxFury CXX) set(CMAKE_CXX_STANDARD 20) From b6e0dedd63dcbd0d7fd09aadfa3c58088d8dc6bc Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Tue, 6 Feb 2024 13:19:31 +0100 Subject: [PATCH 11/58] Avoid sdk and use headers from submodule --- .gitmodules | 3 +++ CMakeLists.txt | 6 ++++-- thirdparty/Vulkan-Headers | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) create mode 160000 thirdparty/Vulkan-Headers diff --git a/.gitmodules b/.gitmodules index 9ebcb5b..1eb3ea8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,3 +16,6 @@ [submodule "thirdparty/stb"] path = thirdparty/stb url = https://github.com/nothings/stb.git +[submodule "thirdparty/Vulkan-Headers"] + path = thirdparty/Vulkan-Headers + url = https://github.com/KhronosGroup/Vulkan-Headers.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a33df2..87b692b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,8 +24,10 @@ option(BUILD_TESTS "Build tests" OFF) option(BUILD_EXAMPLES "Build examples" OFF) - +## Vulkan headers +add_subdirectory("thirdparty/Vulkan-Headers") ## Volk +include_directories("thirdparty/Vulkan-Headers/include") add_subdirectory("thirdparty/volk") ## VMA add_subdirectory("thirdparty/VulkanMemoryAllocator") @@ -54,7 +56,7 @@ if(BUILD_EXAMPLES) FetchContent_MakeAvailable(tinygltf) endif() -target_link_libraries(${PROJECT_NAME} PRIVATE volk VulkanMemoryAllocator) +target_link_libraries(${PROJECT_NAME} PRIVATE Vulkan-Headers volk VulkanMemoryAllocator) # Set custom output directories - to have same behaviour accross different compilers # On linux with make it doesn't work, no debug or release folders diff --git a/thirdparty/Vulkan-Headers b/thirdparty/Vulkan-Headers new file mode 160000 index 0000000..5a5c9a6 --- /dev/null +++ b/thirdparty/Vulkan-Headers @@ -0,0 +1 @@ +Subproject commit 5a5c9a643484d888873e32c5d7d484fae8e71d3d From 18e2ea54bc9000879be1cfcb5fd1835089ef95b2 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Thu, 8 Feb 2024 16:42:11 +0100 Subject: [PATCH 12/58] temporary avoid nearest filter for default sampler for crisper UI until we create dedicaded function --- src/backend/vulkan/VulkanContext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index 3158752..00e78cc 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -1185,7 +1185,7 @@ VulkanContext::CreateSampler(uint32_t minLod, uint32_t maxLod) const auto index = AllocResource(_samplers); DSamplerVulkan& samplerRef = _samplers.at(index); - samplerRef.Sampler = Device.CreateSampler(VkFilter::VK_FILTER_NEAREST, VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT, minLod, maxLod, VK_SAMPLER_MIPMAP_MODE_LINEAR, true, 16); + samplerRef.Sampler = Device.CreateSampler(VkFilter::VK_FILTER_LINEAR, VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT, minLod, maxLod, VK_SAMPLER_MIPMAP_MODE_LINEAR, true, 16); return *ResourceId(EResourceType::SAMPLER, samplerRef.Id, index); } From 01f38094b21f0a744b69a1c1a9653d38d011b454 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Tue, 13 Feb 2024 17:23:45 +0100 Subject: [PATCH 13/58] removed useless code --- src/backend/vulkan/VulkanContext.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index 00e78cc..25c2d94 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -1121,7 +1121,6 @@ VulkanContext::CreateShader(const ShaderSource& source) const auto index = AllocResource(_shaders); DShaderVulkan& shader = _shaders.at(index); - shader.Id = GenIdentifier(); _createShader(source, _shaders.at(index)); From 61ad6ff231c1ea812bfd0c801233f571d4efadf6 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Tue, 20 Feb 2024 10:27:30 +0100 Subject: [PATCH 14/58] added missing function to copy buffers --- include/IContext.h | 1 + src/backend/vulkan/VulkanContext.cpp | 18 ++++++++++++++++++ src/backend/vulkan/VulkanContext.h | 2 ++ 3 files changed, 21 insertions(+) diff --git a/include/IContext.h b/include/IContext.h index 727629c..6c40325 100644 --- a/include/IContext.h +++ b/include/IContext.h @@ -764,6 +764,7 @@ class IContext virtual void DrawIndexedIndirect(uint32_t commandBufferId, uint32_t buffer, uint32_t offset, uint32_t drawCount, uint32_t stride) = 0; virtual void BindDescriptorSet(uint32_t commandBufferId, uint32_t setIndex, uint32_t descriptorSetId) = 0; virtual void CopyImage(uint32_t commandId, uint32_t imageId, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t stagingBufferId, uint32_t stagingBufferOffset) = 0; + virtual void CopyBuffer(uint32_t commandId, uint32_t bufferId, uint32_t offset, uint32_t bytes, uint32_t stagingBufferId, uint32_t stagingBufferOffset) = 0; virtual uint32_t CreateRenderTarget(EFormat format, ESampleBit samples, bool isDepth, uint32_t width, uint32_t height, uint32_t arrayLength, uint32_t mipMapCount, EResourceState initialState) = 0; virtual void DestroyRenderTarget(uint32_t renderTargetId) = 0; diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index 25c2d94..57fd78b 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -2033,6 +2033,24 @@ VulkanContext::CopyImage(uint32_t commandId, uint32_t imageId, uint32_t width, u vkCmdCopyBufferToImage(commandBufferRef.Cmd, buffRef.Buffer.Buffer, imageRef.Image.Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, (uint32_t)1, ®ion); } +void +VulkanContext::CopyBuffer(uint32_t commandId, uint32_t bufferId, uint32_t offset, uint32_t bytes, uint32_t stagingBufferId, uint32_t stagingBufferOffset) +{ + auto& commandBufferRef = GetResource(_commandBuffers, commandId); + check(commandBufferRef.IsRecording); // Must be in recording state + check(!commandBufferRef.ActiveRenderPass); // Must be in a render pass + + auto& vertexRef = GetResource(_vertexBuffers, bufferId); + auto& buffRef = GetResource(_transferBuffers, stagingBufferId); + + VkBufferCopy copy{}; + copy.dstOffset = offset; + copy.size = bytes; + copy.srcOffset = stagingBufferOffset; + + vkCmdCopyBuffer(commandBufferRef.Cmd, buffRef.Buffer.Buffer, vertexRef.Buffer.Buffer, 1, ©); +} + void VulkanContext::QueueSubmit(uint32_t queueId, const std::vector& waitSemaphore, const std::vector& finishSemaphore, const std::vector& cmdIds, uint32_t fenceId) { diff --git a/src/backend/vulkan/VulkanContext.h b/src/backend/vulkan/VulkanContext.h index ee67c6e..fa6a0b4 100644 --- a/src/backend/vulkan/VulkanContext.h +++ b/src/backend/vulkan/VulkanContext.h @@ -214,6 +214,7 @@ class VulkanContext final : public IContext void DrawIndexedIndirect(uint32_t commandBufferId, uint32_t buffer, uint32_t offset, uint32_t drawCount, uint32_t stride) override; void BindDescriptorSet(uint32_t commandBufferId, uint32_t setIndex, uint32_t descriptorSetId) override; void CopyImage(uint32_t commandId, uint32_t imageId, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t stagingBufferId, uint32_t stagingBufferOffset) override; + void CopyBuffer(uint32_t commandId, uint32_t bufferId, uint32_t offset, uint32_t bytes, uint32_t stagingBufferId, uint32_t stagingBufferOffset) override; uint32_t CreateFence(bool signaled) override; void DestroyFence(uint32_t fenceId) override; @@ -262,6 +263,7 @@ class VulkanContext final : public IContext DImageVulkan* _emptyImage; DSamplerVulkan _emptySampler; std::array _swapchains; + /*Vertex and index buffers pool*/ std::array _vertexBuffers; std::array _transferBuffers; std::array _uniformBuffers; From d6aec34f4ca35ca6b1ab33addd1b4d8e38233c61 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Wed, 21 Feb 2024 17:08:40 +0100 Subject: [PATCH 15/58] fix dangling fbo and added buffer offset/range to descriptor update --- include/IContext.h | 2 ++ src/backend/vulkan/VulkanContext.cpp | 32 ++++++++++++++++++++++++++-- src/backend/vulkan/VulkanDevice7.cpp | 4 ++-- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/include/IContext.h b/include/IContext.h index 6c40325..9514dce 100644 --- a/include/IContext.h +++ b/include/IContext.h @@ -684,6 +684,8 @@ typedef struct DescriptorData uint32_t Count{}; uint32_t ArrayOffset{}; uint32_t Index{}; + uint32_t BufferOffset{}; + uint32_t BufferRange{}; union { diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index 57fd78b..1b481ea 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -1564,8 +1564,8 @@ VulkanContext::UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t setIndex, VkDescriptorBufferInfo& buf = bufferInfo[bufferInfoCount++]; const DBufferVulkan& bufRef = GetResource(_uniformBuffers, param->Buffers[j]); buf.buffer = bufRef.Buffer.Buffer; - buf.offset = 0; - buf.range = VK_WHOLE_SIZE; + buf.offset = param->BufferOffset; + buf.range = param->BufferRange; } } break; @@ -2336,6 +2336,34 @@ VulkanContext::DestroyRenderTarget(uint32_t renderTargetId) { auto& renderTargetRef = GetResource(_renderTargets, renderTargetId); + // Must destroy all framebuffers that reference this render target @TODO find a better algorithm without iterating over the array multiple times + const auto referenceCount = std::count_if(_framebuffers.begin(), _framebuffers.end(), [renderTargetId](const DFramebufferVulkan& fbo) { + for (size_t i = 0; i < DFramebufferAttachments::MAX_ATTACHMENTS; i++) + { + if (fbo.Attachments.RenderTargets[i] == renderTargetId) + { + return true; + } + } + return false; + }); + for (uint32_t i = 0; i < referenceCount; i++) + { + auto foundFbo = std::find_if(_framebuffers.begin(), _framebuffers.end(), [renderTargetId](const DFramebufferVulkan& fbo) { + for (size_t i = 0; i < DFramebufferAttachments::MAX_ATTACHMENTS; i++) + { + if (fbo.Attachments.RenderTargets[i] == renderTargetId) + { + return true; + } + } + return false; + }); + + Device._destroyFramebuffer(foundFbo->Framebuffer); + foundFbo->Id = FREE; + } + Device.DestroyImageView(renderTargetRef.View); Device.DestroyImage(renderTargetRef.Image); diff --git a/src/backend/vulkan/VulkanDevice7.cpp b/src/backend/vulkan/VulkanDevice7.cpp index 13ba239..3c9aea1 100644 --- a/src/backend/vulkan/VulkanDevice7.cpp +++ b/src/backend/vulkan/VulkanDevice7.cpp @@ -30,7 +30,7 @@ RIVulkanDevice7::_createFramebuffer(const std::vector& imageViews, throw std::runtime_error(VkUtils::VkErrorString(result)); } - _framebuffers_DEPRECATED.insert(framebuffer); + //_framebuffers_DEPRECATED.insert(framebuffer); return framebuffer; } @@ -39,7 +39,7 @@ void RIVulkanDevice7::_destroyFramebuffer(VkFramebuffer framebuffer) { vkDestroyFramebuffer(Device, framebuffer, nullptr); - _framebuffers_DEPRECATED.erase(_framebuffers_DEPRECATED.find(framebuffer)); + //_framebuffers_DEPRECATED.erase(_framebuffers_DEPRECATED.find(framebuffer)); } } \ No newline at end of file From f8cc22e979d7f2186fc0099d03565f00b46646a6 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Thu, 7 Mar 2024 09:35:57 +0100 Subject: [PATCH 16/58] added missing check --- src/backend/vulkan/VulkanContext.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index 1b481ea..254a005 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -2001,6 +2001,8 @@ VulkanContext::BindDescriptorSet(uint32_t commandBufferId, uint32_t setIndex, ui const DDescriptorSet& descriptorSetRef = GetResource(_descriptorSets, descriptorSetId); + check(setIndex < descriptorSetRef.Sets.size()); + vkCmdBindDescriptorSets( commandBufferRef.Cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, descriptorSetRef.RootSignature->PipelineLayout, (uint32_t)descriptorSetRef.Frequency, 1, &descriptorSetRef.Sets[setIndex], 0, nullptr); } From 0c0b0f4ebb5460d84da6fddded9b2fd55b4e5b4b Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Sat, 9 Mar 2024 17:22:09 +0100 Subject: [PATCH 17/58] release zeromemory vector of structs --- src/backend/vulkan/VulkanContext.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index 254a005..bf92060 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -211,7 +211,7 @@ VulkanContext::VulkanContext(const DContextConfig* const config) : _warningOutpu const auto pool = CreateCommandPool(graphicsQueue); const auto cmd = CreateCommandBuffer(pool); BeginCommandBuffer(cmd); - TextureBarrier barrier; + TextureBarrier barrier{}; barrier.ImageId = _emptyImageId; barrier.CurrentState = EResourceState::UNDEFINED; barrier.NewState = EResourceState::SHADER_RESOURCE; @@ -2385,10 +2385,12 @@ RenderTargetBarrier* p_rt_barriers) std::vector imageBarriers; imageBarriers.resize(rt_barrier_count + texture_barrier_count); + memset(imageBarriers.data(), 0, sizeof(VkImageMemoryBarrier) * imageBarriers.size()); uint32_t imageBarrierCount{}; std::vector bufferBarriers; bufferBarriers.resize(buffer_barrier_count); + memset(bufferBarriers.data(), 0, sizeof(VkBufferMemoryBarrier) * bufferBarriers.size()); uint32_t bufferBarrierCount{}; VkAccessFlags srcAccessFlags = 0; @@ -2491,10 +2493,11 @@ RenderTargetBarrier* p_rt_barriers) pImageBarrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; pImageBarrier->pNext = NULL; - pImageBarrier->srcAccessMask = VkUtils::resourceStateToAccessFlag(pTrans->CurrentState); - pImageBarrier->dstAccessMask = VkUtils::resourceStateToAccessFlag(pTrans->NewState); - pImageBarrier->oldLayout = VkUtils::resourceStateToImageLayout(pTrans->CurrentState); - pImageBarrier->newLayout = VkUtils::resourceStateToImageLayout(pTrans->NewState); + pImageBarrier->subresourceRange.aspectMask = (VkImageAspectFlags)imageRef.ImageAspect; + pImageBarrier->srcAccessMask = VkUtils::resourceStateToAccessFlag(pTrans->CurrentState); + pImageBarrier->dstAccessMask = VkUtils::resourceStateToAccessFlag(pTrans->NewState); + pImageBarrier->oldLayout = VkUtils::resourceStateToImageLayout(pTrans->CurrentState); + pImageBarrier->newLayout = VkUtils::resourceStateToImageLayout(pTrans->NewState); } if (pImageBarrier) From 61c165e87d1aa4027f1af37fe137af7d5e402903 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Thu, 28 Mar 2024 16:30:39 +0100 Subject: [PATCH 18/58] added glslang compile shader function and renamed fury check with furyassert --- .gitmodules | 3 + CMakeLists.txt | 6 +- include/IContext.h | 2 + include/backend/vulkan/VulkanContextFactory.h | 8 +- src/AtomicCounter.h | 2 +- src/DescriptorPool.h | 2 +- src/RICacheMap.h | 4 +- src/RingBufferManager.h | 18 +- src/asserts.h | 8 +- src/backend/vulkan/ResourceTransfer.cpp | 4 +- src/backend/vulkan/UtilsVK.h | 30 +- src/backend/vulkan/VulkanContext.cpp | 325 +++++++++++++----- src/backend/vulkan/VulkanContext.h | 11 +- src/backend/vulkan/VulkanDevice.cpp | 22 +- src/backend/vulkan/VulkanDevice10.cpp | 8 +- src/backend/vulkan/VulkanDevice11.cpp | 14 +- src/backend/vulkan/VulkanDevice12.cpp | 8 +- src/backend/vulkan/VulkanDevice13.cpp | 2 +- src/backend/vulkan/VulkanDevice2.cpp | 22 +- src/backend/vulkan/VulkanDevice3.cpp | 4 +- src/backend/vulkan/VulkanDevice4.cpp | 2 +- src/backend/vulkan/VulkanDevice5.cpp | 8 +- src/backend/vulkan/VulkanDevice6.cpp | 2 +- src/backend/vulkan/VulkanDevice7.cpp | 2 +- src/backend/vulkan/VulkanDevice8.cpp | 2 +- src/backend/vulkan/VulkanDevice9.cpp | 2 +- src/backend/vulkan/VulkanInstance.cpp | 10 +- thirdparty/glslang | 1 + 28 files changed, 344 insertions(+), 188 deletions(-) create mode 160000 thirdparty/glslang diff --git a/.gitmodules b/.gitmodules index 1eb3ea8..40a432e 100644 --- a/.gitmodules +++ b/.gitmodules @@ -19,3 +19,6 @@ [submodule "thirdparty/Vulkan-Headers"] path = thirdparty/Vulkan-Headers url = https://github.com/KhronosGroup/Vulkan-Headers.git +[submodule "thirdparty/glslang"] + path = thirdparty/glslang + url = https://github.com/KhronosGroup/glslang.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 87b692b..1949fd8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,10 @@ include_directories("thirdparty/Vulkan-Headers/include") add_subdirectory("thirdparty/volk") ## VMA add_subdirectory("thirdparty/VulkanMemoryAllocator") +## Glsl lang +set(ENABLE_OPT 0)#disable optimizations for HLSL +set(BUILD_SHARED_LIBS 0) +add_subdirectory("thirdparty/glslang") ## GLFW set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "GLFW_BUILD_EXAMPLES" FORCE) set(GLFW_BUILD_TESTS OFF CACHE BOOL "GLFW_BUILD_TESTS" FORCE) @@ -56,7 +60,7 @@ if(BUILD_EXAMPLES) FetchContent_MakeAvailable(tinygltf) endif() -target_link_libraries(${PROJECT_NAME} PRIVATE Vulkan-Headers volk VulkanMemoryAllocator) +target_link_libraries(${PROJECT_NAME} Vulkan-Headers volk VulkanMemoryAllocator GenericCodeGen OSDependent MachineIndependent glslang glslang-default-resource-limits) # Set custom output directories - to have same behaviour accross different compilers # On linux with make it doesn't work, no debug or release folders diff --git a/include/IContext.h b/include/IContext.h index 9514dce..cfad244 100644 --- a/include/IContext.h +++ b/include/IContext.h @@ -708,6 +708,8 @@ class IContext { public: virtual ~IContext(){}; + virtual bool CompileNativeShader(const std::vector& blob, std::vector& outShader, EShaderStage shaderStage, std::string& errorMgs) = 0; + virtual void WaitDeviceIdle() = 0; virtual uint32_t CreateSwapchain(const WindowData* windowData, EPresentMode& presentMode, EFormat& outFormat, uint32_t* width = nullptr, uint32_t* height = nullptr) = 0; /** diff --git a/include/backend/vulkan/VulkanContextFactory.h b/include/backend/vulkan/VulkanContextFactory.h index 4c552a0..4d64bfd 100644 --- a/include/backend/vulkan/VulkanContextFactory.h +++ b/include/backend/vulkan/VulkanContextFactory.h @@ -4,7 +4,13 @@ #include "IContext.h" +#ifdef FURY_EXPORT +#define FURY_API __declspec(dllexport) +#else +#define FURY_API __declspec(dllimport) +#endif + namespace Fox { -IContext* CreateVulkanContext(DContextConfig const*const config); +IContext* CreateVulkanContext(DContextConfig const* const config); } \ No newline at end of file diff --git a/src/AtomicCounter.h b/src/AtomicCounter.h index 31f531f..1172d86 100644 --- a/src/AtomicCounter.h +++ b/src/AtomicCounter.h @@ -14,7 +14,7 @@ class CAtomicCounter inline void IncreaseCounter() { _counter.store(_counter.load() + 1); }; inline void DecreaseCounter() { - check(_counter.load() > 0); // count can't be negative + furyassert(_counter.load() > 0); // count can't be negative _counter.store(_counter.load() - 1); }; inline uint32_t Count() const { return _counter.load(); }; diff --git a/src/DescriptorPool.h b/src/DescriptorPool.h index 6067092..cb17891 100644 --- a/src/DescriptorPool.h +++ b/src/DescriptorPool.h @@ -43,7 +43,7 @@ namespace Fox // // void BindCombinedImageSamplerArray(uint32_t bindingIndex, const std::vector>& imageToSamplerArray) // { -// check(imageToSamplerArray.size() > 0); +// furyassert(imageToSamplerArray.size() > 0); // // _imageInfo.push_back({}); // diff --git a/src/RICacheMap.h b/src/RICacheMap.h index 93f3c8c..962c75e 100644 --- a/src/RICacheMap.h +++ b/src/RICacheMap.h @@ -16,7 +16,7 @@ class RICacheMap public: void Add(const Key& key, const Value value) { - check(Find(key) == nullptr); // element is already contained + furyassert(Find(key) == nullptr); // element is already contained auto pair = std::make_pair(key, value); _map.insert(std::move(pair)); } @@ -41,7 +41,7 @@ class RICacheMap return; } } - check(0); // element is not contained + furyassert(0); // element is not contained } size_t Size() const { return _map.size(); } diff --git a/src/RingBufferManager.h b/src/RingBufferManager.h index b9f3a57..f3d4391 100644 --- a/src/RingBufferManager.h +++ b/src/RingBufferManager.h @@ -19,13 +19,13 @@ struct RingBufferManager // Must receive the same number of pop with the same length as the number of time Push was called void Pop(uint32_t length) { - check(length, MaxSize); + furyassert(length, MaxSize); #if defined(_DEBUG) if (!Full && Tail != Head) { if (Tail < Head) { - check(Tail + length <= Head); + furyassert(Tail + length <= Head); } } #endif @@ -45,7 +45,7 @@ struct RingBufferManager Tail = 0; } - check(Tail >= 0 && Tail <= MaxSize); + furyassert(Tail >= 0 && Tail <= MaxSize); Full = false; // When Pop is called it means the we're not full anymore } @@ -95,23 +95,23 @@ struct RingBufferManager uint32_t Push(void* data, uint32_t length) { // Must not be full - check(!Full); + furyassert(!Full); // Allocation can be more than max size - check(length <= MaxSize); + furyassert(length <= MaxSize); // Check capacity - check(Capacity() >= length); + furyassert(Capacity() >= length); #if defined(_DEBUG) if (Head != Tail) { if (Head < Tail) { // If head < tail cannot go beyond tail - check(Head + length <= Tail); + furyassert(Head + length <= Tail); } // else if (_shouldWrapAround(Head + length)) // { // // If head > tail and wrap arounds can't go beyond tail - // check(length <= Tail);//no Capacity left + // furyassert(length <= Tail);//no Capacity left // } } #endif @@ -133,7 +133,7 @@ struct RingBufferManager } const uint32_t dataStart = Head - length; - check(_isInsideRange(dataStart, length)); + furyassert(_isInsideRange(dataStart, length)); if (data != nullptr) { unsigned char* addressWithOffset = static_cast(Mapped) + dataStart; diff --git a/src/asserts.h b/src/asserts.h index 3f0335e..a4a3ea9 100644 --- a/src/asserts.h +++ b/src/asserts.h @@ -45,16 +45,16 @@ inline void _fprint(const char* _condition, const char* file, const int line) { - std::cerr << "check(" << _condition << ") IN FILE " << file << " LINE " << line << "\n" << std::flush; + std::cerr << "furyassert(" << _condition << ") IN FILE " << file << " LINE " << line << "\n" << std::flush; }; #define ERRORLOG(msg) std::cerr << "Error:" << msg << " IN FILE " << __FILE__ << " LINE " << __LINE__ << "\n" << std::flush; -// Use check only to trigger an exception in debug mode +// Use furyassert only to trigger an exception in debug mode // if condition = false then the debugger will stop // clang-format off #if defined(_DEBUG) -#define check(condition) \ +#define furyassert(condition) \ { \ if (!(condition)) \ { \ @@ -63,7 +63,7 @@ _fprint(const char* _condition, const char* file, const int line) } \ }; #else -#define check(condition) +#define furyassert(condition) #endif // Use critical it will throw a runtime error if the condition is false even in release builds diff --git a/src/backend/vulkan/ResourceTransfer.cpp b/src/backend/vulkan/ResourceTransfer.cpp index 3902432..f0c9815 100644 --- a/src/backend/vulkan/ResourceTransfer.cpp +++ b/src/backend/vulkan/ResourceTransfer.cpp @@ -8,7 +8,7 @@ namespace Fox { CResourceTransfer::CResourceTransfer(VkCommandBuffer command) : _command(command) { - check(_command); + furyassert(_command); VkCommandBufferBeginInfo beginInfo{}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; @@ -23,7 +23,7 @@ CResourceTransfer::CResourceTransfer(VkCommandBuffer command) : _command(command // std::vector barriersTransfer; // std::vector barriersSampler; // -// check(beginOffset < std::numeric_limits::max()); +// furyassert(beginOffset < std::numeric_limits::max()); // uint32_t offset = (uint32_t)beginOffset; // uint32_t mipWidth = image.Width; // uint32_t mipHeight = image.Height; diff --git a/src/backend/vulkan/UtilsVK.h b/src/backend/vulkan/UtilsVK.h index e824230..bfdc43e 100644 --- a/src/backend/vulkan/UtilsVK.h +++ b/src/backend/vulkan/UtilsVK.h @@ -105,7 +105,7 @@ convertPresentMode(const Fox::EPresentMode mode) case Fox::EPresentMode::FIFO_RELAXED: return VkPresentModeKHR::VK_PRESENT_MODE_FIFO_RELAXED_KHR; } - check(0); + furyassert(0); return VkPresentModeKHR::VK_PRESENT_MODE_MAX_ENUM_KHR; }; @@ -152,7 +152,7 @@ convertVkFormat(const VkFormat format) return Fox::EFormat::SINT32; } - check(0); + furyassert(0); return Fox::EFormat::R8_UNORM; }; @@ -199,7 +199,7 @@ convertFormat(const Fox::EFormat format) return VK_FORMAT_R32_SINT; } - check(0); + furyassert(0); return VK_FORMAT_UNDEFINED; }; @@ -225,7 +225,7 @@ convertVkSampleCount(const Fox::ESampleBit sample) return VK_SAMPLE_COUNT_64_BIT; } - check(0); + furyassert(0); return VK_SAMPLE_COUNT_1_BIT; } @@ -240,7 +240,7 @@ convertAttachmentLoadOp(const Fox::ERenderPassLoad load) return VK_ATTACHMENT_LOAD_OP_LOAD; } - check(0); + furyassert(0); return VK_ATTACHMENT_LOAD_OP_CLEAR; } @@ -255,7 +255,7 @@ convertAttachmentStoreOp(const Fox::ERenderPassStore store) return VK_ATTACHMENT_STORE_OP_STORE; } - check(0); + furyassert(0); return VK_ATTACHMENT_STORE_OP_STORE; } @@ -314,7 +314,7 @@ convertRenderPassLayout(const Fox::ERenderPassLayout layout, bool isColor = true return VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; } - check(0); + furyassert(0); return VK_IMAGE_LAYOUT_UNDEFINED; } @@ -490,7 +490,7 @@ convertAttachmentReferenceLayout(const Fox::EAttachmentReference& att) return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; } - check(0); + furyassert(0); return VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL; } @@ -594,9 +594,9 @@ computeDescriptorSetsPoolSize(const std::map& byteCode, VkShaderModule* shaderModule) { - check(device); - check(byteCode.size() > 0); - check(shaderModule && !*shaderModule); + furyassert(device); + furyassert(byteCode.size() > 0); + furyassert(shaderModule && !*shaderModule); VkShaderModuleCreateInfo createInfo{}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; @@ -610,8 +610,8 @@ inline VkPipelineShaderStageCreateInfo createShaderStageInfo(VkShaderStageFlagBits stage, VkShaderModule shaderModule) { constexpr const char* PENTRYPOINTNAME{ "main" }; - check(shaderModule); - check(stage == VK_SHADER_STAGE_VERTEX_BIT || stage == VK_SHADER_STAGE_FRAGMENT_BIT); + furyassert(shaderModule); + furyassert(stage == VK_SHADER_STAGE_VERTEX_BIT || stage == VK_SHADER_STAGE_FRAGMENT_BIT); VkPipelineShaderStageCreateInfo stageInfo{}; stageInfo.pNext = nullptr; @@ -853,7 +853,7 @@ convertResourceStateToImageLayout(Fox::EResourceState state, bool isDepth) break; } - check(0); + furyassert(0); return VK_IMAGE_LAYOUT_UNDEFINED; } @@ -951,7 +951,7 @@ uint32_t* queueFamilyIndexCreatedCount) } } - check(found == true); + furyassert(found == true); return found; } diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index bf92060..39f2170 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -11,6 +11,14 @@ #include #include +// Thirdparty +#pragma warning(push, 0) +#include "glslang/Include/glslang_c_interface.h" +#include +#include +#include +#pragma warning(pop) + namespace Fox { @@ -27,13 +35,13 @@ template inline T& GetResource(std::array& container, uint32_t id) { - check(id != NULL); // Uninitialized ID + furyassert(id != NULL); // Uninitialized ID const auto resourceId = ResourceId(id); - check(resourceId.First() == type); // Invalid resource id - check(resourceId.Value() < maxSize); // Must be less than array size + furyassert(resourceId.First() == type); // Invalid resource id + furyassert(resourceId.Value() < maxSize); // Must be less than array size T& element = container.at(resourceId.Value()); - check(IsValidId(element.Id)); // The object must be in valid state - check(element.Id == resourceId.Second()); // The object must have not been destroyed previously and reallocated + furyassert(IsValidId(element.Id)); // The object must be in valid state + furyassert(element.Id == resourceId.Second()); // The object must have not been destroyed previously and reallocated return element; }; @@ -42,11 +50,11 @@ inline const T& GetResource(const std::array& container, uint32_t id) { const auto resourceId = ResourceId(id); - check(resourceId.First() == type); // Invalid resource id - check(resourceId.Value() < maxSize); // Must be less than array size + furyassert(resourceId.First() == type); // Invalid resource id + furyassert(resourceId.Value() < maxSize); // Must be less than array size const T& element = container.at(resourceId.Value()); - check(IsValidId(element.Id)); // The object must be in valid state - check(element.Id == resourceId.Second()); // The object must have not been destroyed previously and reallocated + furyassert(IsValidId(element.Id)); // The object must be in valid state + furyassert(element.Id == resourceId.Second()); // The object must have not been destroyed previously and reallocated return element; }; @@ -55,8 +63,8 @@ inline T& GetResourceUnsafe(std::array& container, uint32_t id) { const auto resourceId = ResourceId(id); - check(resourceId.First() == type); // Invalid resource id - check(resourceId.Value() < maxSize); // Must be less than array size + furyassert(resourceId.First() == type); // Invalid resource id + furyassert(resourceId.Value() < maxSize); // Must be less than array size T& element = container.at(resourceId.Value()); return element; }; @@ -78,7 +86,7 @@ GenIdentifier() }; static size_t counter = 0; const auto value = hash(counter++); - check(value != 0); // must not be 0 + furyassert(value != 0); // must not be 0 return (uint8_t)value; } @@ -96,8 +104,8 @@ AllocResource(std::array& container) { element.Id = GenIdentifier(); } // Messy but makes sure that id is never NULL - check(element.Id != FREE); - check(element.Id != PENDING_DESTROY); + furyassert(element.Id != FREE); + furyassert(element.Id != PENDING_DESTROY); return i; } } @@ -262,7 +270,7 @@ const VkDebugUtilsMessengerCallbackDataEXT* pCall void* pUserData) { VulkanContext* context = static_cast(pUserData); - check(context); + furyassert(context); if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) { @@ -281,7 +289,7 @@ void* pUser context->Log("Validation layer[INFO]: " + std::string(pCallbackData->pMessage)); } - // check(false); + // furyassert(false); return VK_FALSE; } @@ -412,15 +420,15 @@ VulkanContext::~VulkanContext() #if _DEBUG const auto validSwapchainsCount = std::count_if(_swapchains.begin(), _swapchains.end(), [](const DSwapchainVulkan& swapchain) { return IsValidId(swapchain.Id); }); - check(validSwapchainsCount == 0); + furyassert(validSwapchainsCount == 0); const auto validVertexBufferCount = std::count_if(_vertexBuffers.begin(), _vertexBuffers.end(), [](const DBufferVulkan& buffer) { return IsValidId(buffer.Id); }); - check(validVertexBufferCount == 0); + furyassert(validVertexBufferCount == 0); const auto validUniformBufferCount = std::count_if(_uniformBuffers.begin(), _uniformBuffers.end(), [](const DBufferVulkan& buffer) { return IsValidId(buffer.Id); }); - check(validUniformBufferCount == 0); + furyassert(validUniformBufferCount == 0); const auto validFramebufferCount = std::count_if(_framebuffers.begin(), _framebuffers.end(), [](const DFramebufferVulkan& buffer) { return IsValidId(buffer.Id); }); - check(validFramebufferCount == 0); + furyassert(validFramebufferCount == 0); const auto validShaderCount = std::count_if(_shaders.begin(), _shaders.end(), [](const DShaderVulkan& shader) { return IsValidId(shader.Id); }); - check(validShaderCount == 0); + furyassert(validShaderCount == 0); #endif // Destroy all descriptor pools managers @@ -440,6 +448,135 @@ VulkanContext::~VulkanContext() Instance.Deinit(); } +bool +VulkanContext::CompileNativeShader(const std::vector& blob, std::vector& outShader, EShaderStage shaderStage, std::string& errorMgs) +{ + // spirv_cross::CompilerGLSL compilerGLSL(reinterpret_cast(blob.data()), blob.size() / sizeof(uint32_t)); + + //// Compile the GLSL code into SPIR-V + // spirv_cross::CompilerGLSL::Options options; + // options.version = 450; // Set GLSL version (e.g., 450 for GLSL 4.50) + // compilerGLSL.set_common_options(options); + // auto spirv = compilerGLSL.compile(); + + // Initialize glslang + glslang::InitializeProcess(); + + EShLanguage language{ EShLangVertex }; + switch (shaderStage) + { + case EShaderStage::VERTEX: + language = EShLangVertex; + break; + case EShaderStage::FRAGMENT: + language = EShLangFragment; + break; + default: + furyassert(0); // Invalid shader stage choice + break; + } + + // Create glslang compiler + const char* shaderSource{ reinterpret_cast(blob.data()) }; + const int l{ (int)blob.size() }; + const EShMessages controls = EShMsgDefault; + glslang::TShader* shader(new glslang::TShader(language)); + + shader->setStringsWithLengths(&shaderSource, &l, 1); + shader->setEntryPoint("main"); + furyassert(shader->parse(GetDefaultResources(), 100, false, (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules))); + + glslang::TProgram* program{ new glslang::TProgram() }; + program->addShader(shader); + + furyassert(program->link((EShMessages)(EShMsgSpvRules | EShMsgVulkanRules))); + + glslang::GlslangToSpv(*program->getIntermediate(EShLanguage::EShLangVertex), outShader); + + delete program; + delete shader; + glslang::FinalizeProcess(); + // + // const glslang_input_t input = { + // .language = GLSLANG_SOURCE_GLSL, + // .stage = GLSLANG_STAGE_VERTEX, + // .client = GLSLANG_CLIENT_VULKAN, + // .client_version = GLSLANG_TARGET_VULKAN_1_2, + // .target_language = GLSLANG_TARGET_SPV, + // .target_language_version = GLSLANG_TARGET_SPV_1_3, + // .code = shaderSource, + // .default_version = 100, + // .default_profile = GLSLANG_NO_PROFILE, + // .force_default_version_and_profile = false, + // .forward_compatible = false, + // .messages = GLSLANG_MSG_DEFAULT_BIT, + // .resource = GetDefaultResources(); + // }; + + //// Set up shader options + // TBuiltInResource resources = {}; + // resources.maxLights = 32; + // resources.maxClipPlanes = 6; + // resources.maxTextureUnits = 32; + // resources.maxTextureCoords = 32; + // resources.maxVertexAttribs = 64; + // resources.maxVertexUniformComponents = 4096; + // resources.maxVaryingFloats = 64; + // resources.maxVertexTextureImageUnits = 32; + // resources.maxCombinedTextureImageUnits = 80; + // resources.maxTextureImageUnits = 32; + // resources.maxFragmentUniformComponents = 4096; + // resources.maxDrawBuffers = 32; + // resources.maxVertexUniformVectors = 128; + // resources.maxVaryingVectors = 8; + // resources.maxFragmentUniformVectors = 16; + // resources.maxVertexOutputVectors = 16; + // resources.maxFragmentInputVectors = 15; + + //// Compile the shader + // shader.setEnvInput(glslang::EShSourceGlsl, language, glslang::EShClientVulkan, 110); + // shader.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_2); + // shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_0); + + //// if (!shader.preprocess(&resources, 110, EProfile::ECompatibilityProfile, false, true, EsHM, &input)) + //// { + //// // use glslang_shader_get_info_log() and glslang_shader_get_info_debug_log() + //// } + + // if (!shader.parse(&resources, 110, false, EShMsgDefault)) + // { + // errorMgs = shader.getInfoLog(); + // // std::cerr << "Failed to parse shader:\n" << shader.getInfoLog() << std::endl; + // glslang::FinalizeProcess(); + // return false; + // } + + // glslang::TProgram program; + // program.addShader(&shader); + + // if (!program.link(EShMsgDefault)) + // { + // errorMgs = program.getInfoLog(); + // glslang::FinalizeProcess(); + // return false; + // } + + // std::vector outSpirv; + ///*glslang::GlslangToSpv(program.getIntermediate(language), outSpirv);*/ + + // spv::SpvBuildLogger logger; + // glslang::TIntermediate* intermediate{ program.getIntermediate(language) }; + // glslang::GlslangToSpv(*intermediate, outSpirv, &logger, nullptr); + + //// Clean up + // glslang::FinalizeProcess(); + + // outShader.resize(outSpirv.size()); + // memcpy(outShader.data(), outSpirv.data(), outSpirv.size() * sizeof(unsigned int)); + + return true; +} + void VulkanContext::WaitDeviceIdle() { @@ -458,7 +595,7 @@ VulkanContext::CreateSwapchain(const WindowData* windowData, EPresentMode& prese if (width != nullptr) { - check(height != nullptr); + furyassert(height != nullptr); *width = swapchain.Capabilities.currentExtent.width; *height = swapchain.Capabilities.currentExtent.height; } @@ -507,7 +644,7 @@ VulkanContext::_createSwapchain(DSwapchainVulkan& swapchain, const WindowData* w const auto capabilities = Device.GetSurfaceCapabilities(surface); // Create swapchain object - check(swapchain.Swapchain == nullptr); + furyassert(swapchain.Swapchain == nullptr); VkSwapchainKHR vkSwapchain{}; // Only create swapchain when extent is meaningful as > 0px if (capabilities.currentExtent.width > 0 && capabilities.currentExtent.height > 0) @@ -569,7 +706,7 @@ VulkanContext::GetSwapchainRenderTargets(SwapchainId swapchainId) { ResourceId resource(swapchainId); - check(resource.First() == EResourceType::SWAPCHAIN); + furyassert(resource.First() == EResourceType::SWAPCHAIN); DSwapchainVulkan& swapchain = GetResource(_swapchains, swapchainId); @@ -786,7 +923,7 @@ VulkanContext::DestroySwapchain(SwapchainId swapchainId) { ResourceId resource(swapchainId); - check(resource.First() == EResourceType::SWAPCHAIN); + furyassert(resource.First() == EResourceType::SWAPCHAIN); DSwapchainVulkan& swapchain = GetResource(_swapchains, swapchainId); if (swapchain.Swapchain) @@ -914,7 +1051,7 @@ VulkanContext::CreateBuffer(uint32_t size, EResourceType type, EMemoryUsage usag buffer = &_indirectBuffers.at(index); break; default: - check(0); // Invalid type + furyassert(0); // Invalid type break; } @@ -938,7 +1075,7 @@ VulkanContext::CreateBuffer(uint32_t size, EResourceType type, EMemoryUsage usag } break; default: - check(0); // invalid usage + furyassert(0); // invalid usage break; } @@ -967,11 +1104,11 @@ VulkanContext::BeginMapBuffer(BufferId buffer) bufferPtr = &_indirectBuffers.at(index); break; default: - check(0); // Invalid type + furyassert(0); // Invalid type break; } - check(bufferPtr->Buffer.IsMappable); // Must be mappable flag + furyassert(bufferPtr->Buffer.IsMappable); // Must be mappable flag return Device.MapBuffer(bufferPtr->Buffer); } @@ -997,11 +1134,11 @@ VulkanContext::EndMapBuffer(BufferId buffer) bufferPtr = &_indirectBuffers.at(index); break; default: - check(0); // Invalid type + furyassert(0); // Invalid type break; } - check(bufferPtr->Buffer.IsMappable); // Must be mappable flag + furyassert(bufferPtr->Buffer.IsMappable); // Must be mappable flag return Device.UnmapBuffer(bufferPtr->Buffer); } @@ -1025,10 +1162,10 @@ VulkanContext::DestroyBuffer(BufferId buffer) bufferPtr = &_transferBuffers.at(index); break; default: - check(0); // Invalid type + furyassert(0); // Invalid type break; } - check(IsValidId(bufferPtr->Id)); + furyassert(IsValidId(bufferPtr->Id)); bufferPtr->Id = FREE; Device.DestroyBuffer(bufferPtr->Buffer); } @@ -1077,7 +1214,7 @@ void VulkanContext::DestroyImage(ImageId imageId) { auto& resource = GetResourceUnsafe(_images, imageId); - check(IsValidId(resource.Id)); + furyassert(IsValidId(resource.Id)); resource.Id = PENDING_DESTROY; _deferDestruction([this, imageId]() { @@ -1117,7 +1254,7 @@ VulkanContext::CreateVertexLayout(const std::vector& info) ShaderId VulkanContext::CreateShader(const ShaderSource& source) { - check(source.ColorAttachments > 0); + furyassert(source.ColorAttachments > 0); const auto index = AllocResource(_shaders); DShaderVulkan& shader = _shaders.at(index); @@ -1164,9 +1301,9 @@ VulkanContext::_createShader(const ShaderSource& source, DShaderVulkan& shader) void VulkanContext::DestroyShader(const ShaderId shader) { - check(ResourceId(shader).First() == EResourceType::SHADER); + furyassert(ResourceId(shader).First() == EResourceType::SHADER); const auto index = ResourceId(shader).Value(); - check(IsValidId(_shaders.at(index).Id)); + furyassert(IsValidId(_shaders.at(index).Id)); _shaders.at(index).Id = PENDING_DESTROY; _deferDestruction([this, index]() { @@ -1220,7 +1357,7 @@ VulkanContext::DestroyPipeline(uint32_t pipelineId) uint32_t VulkanContext::CreateRootSignature(const ShaderLayout& layout) { - check(layout.SetsLayout.size() < (uint32_t)EDescriptorFrequency::MAX_COUNT); + furyassert(layout.SetsLayout.size() < (uint32_t)EDescriptorFrequency::MAX_COUNT); const auto index = AllocResource(_rootSignatures); DRootSignature& rootSignature = _rootSignatures.at(index); @@ -1276,7 +1413,7 @@ VulkanContext::CreateRootSignature(const ShaderLayout& layout) for (const auto index : rootSignature.SetsBindings[i]) { - check(index.second.Count < 8196); + furyassert(index.second.Count < 8196); const uint32_t descriptorCount = std::max(1u, index.second.Count); @@ -1291,7 +1428,7 @@ VulkanContext::CreateRootSignature(const ShaderLayout& layout) case EBindingType::STORAGE_BUFFER_OBJECT: { writeSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - check(0); // UNSUPPORTED YET + furyassert(0); // UNSUPPORTED YET } break; case EBindingType::UNIFORM_BUFFER_OBJECT: @@ -1409,7 +1546,7 @@ VulkanContext::CreateDescriptorSets(uint32_t rootSignatureId, EDescriptorFrequen descriptorSetRef.Sets.resize(count); descriptorSetRef.Frequency = frequency; - check(count < 8196); + furyassert(count < 8196); std::array descriptorSetLayouts; std::fill(descriptorSetLayouts.begin(), descriptorSetLayouts.begin() + count, rootSignature.DescriptorSetLayouts[(uint32_t)frequency]); { @@ -1440,7 +1577,7 @@ VulkanContext::CreateDescriptorSets(uint32_t rootSignatureId, EDescriptorFrequen for (const auto index : setBinding) { - check(index.second.Count < 8196); + furyassert(index.second.Count < 8196); const uint32_t descriptorCount = std::max(1u, index.second.Count); @@ -1455,7 +1592,7 @@ VulkanContext::CreateDescriptorSets(uint32_t rootSignatureId, EDescriptorFrequen case EBindingType::STORAGE_BUFFER_OBJECT: { writeSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - check(0); // UNSUPPORTED YET + furyassert(0); // UNSUPPORTED YET } break; case EBindingType::UNIFORM_BUFFER_OBJECT: @@ -1527,7 +1664,7 @@ VulkanContext::UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t setIndex, { const DDescriptorSet& descriptorSetRef = GetResource(_descriptorSets, descriptorSetId); - check(paramCount < 8196); + furyassert(paramCount < 8196); std::array write; std::array imageInfo; std::array bufferInfo; @@ -1550,7 +1687,7 @@ VulkanContext::UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t setIndex, case EBindingType::STORAGE_BUFFER_OBJECT: { writeSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - check(0); // UNSUPPORTED YET + furyassert(0); // UNSUPPORTED YET } break; case EBindingType::UNIFORM_BUFFER_OBJECT: @@ -1598,7 +1735,7 @@ VulkanContext::UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t setIndex, } break; default: - check(0); // Invalid resource type + furyassert(0); // Invalid resource type break; } } @@ -1641,7 +1778,7 @@ VulkanContext::_createFramebuffer(const DFramebufferAttachments& attachments) // Extrapolate all the renderTargetRef views const auto depthAttachmentCount = (uint32_t)(attachments.DepthStencil != 0); const auto attachmentCount = DFramebufferAttachments::MAX_ATTACHMENTS - std::count(attachments.RenderTargets.begin(), attachments.RenderTargets.end(), NULL) + depthAttachmentCount; - check(attachmentCount > 0); // Must have at least one attachment + furyassert(attachmentCount > 0); // Must have at least one attachment std::vector imageViewsAttachments; imageViewsAttachments.resize(attachmentCount); @@ -1655,13 +1792,13 @@ VulkanContext::_createFramebuffer(const DFramebufferAttachments& attachments) for (size_t i = 0; i < attachmentCount - depthAttachmentCount; i++) { - check(attachments.RenderTargets[i] != NULL); + furyassert(attachments.RenderTargets[i] != NULL); const auto& renderTargetRef = GetResource(_renderTargets, attachments.RenderTargets[i]); imageViewsAttachments[i] = renderTargetRef.View; - check(renderTargetRef.Image.Width == framebufferRef.Width); // All images must have the same width - check(renderTargetRef.Image.Height == framebufferRef.Height); // All images must have the same height - check(renderTargetRef.Image.MipLevels == 1); // Must have only 1 layer + furyassert(renderTargetRef.Image.Width == framebufferRef.Width); // All images must have the same width + furyassert(renderTargetRef.Image.Height == framebufferRef.Height); // All images must have the same height + furyassert(renderTargetRef.Image.MipLevels == 1); // Must have only 1 layer } if (depthAttachmentCount) @@ -1669,9 +1806,9 @@ VulkanContext::_createFramebuffer(const DFramebufferAttachments& attachments) const auto& renderTargetRef = GetResource(_renderTargets, attachments.DepthStencil); imageViewsAttachments.back() = renderTargetRef.View; - check(renderTargetRef.Image.Width == framebufferRef.Width); // All images must have the same width - check(renderTargetRef.Image.Height == framebufferRef.Height); // All images must have the same height - check(renderTargetRef.Image.MipLevels == 1); // Must have only 1 layer + furyassert(renderTargetRef.Image.Width == framebufferRef.Width); // All images must have the same width + furyassert(renderTargetRef.Image.Height == framebufferRef.Height); // All images must have the same height + furyassert(renderTargetRef.Image.MipLevels == 1); // Must have only 1 layer } framebufferRef.Framebuffer = Device._createFramebuffer(imageViewsAttachments, framebufferRef.Width, framebufferRef.Height, vkRenderPass); @@ -1760,7 +1897,7 @@ void VulkanContext::DestroyCommandBuffer(uint32_t commandBufferId) { auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); - check(!commandBufferRef.IsRecording); // Must not be in recording state + furyassert(!commandBufferRef.IsRecording); // Must not be in recording state commandBufferRef.Id = FREE; } @@ -1768,7 +1905,7 @@ void VulkanContext::BeginCommandBuffer(uint32_t commandBufferId) { auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); - check(!commandBufferRef.IsRecording); // Must not be in recording state + furyassert(!commandBufferRef.IsRecording); // Must not be in recording state commandBufferRef.IsRecording = true; VkCommandBufferBeginInfo beginInfo{}; @@ -1782,7 +1919,7 @@ VulkanContext::EndCommandBuffer(uint32_t commandBufferId) { auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); - check(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.IsRecording); // Must be in recording state commandBufferRef.IsRecording = false; // If previous active render pass end it @@ -1881,7 +2018,7 @@ VulkanContext::BindRenderTargets(uint32_t commandBufferId, const DFramebufferAtt renderPassInfo.pClearValues = clearValues; auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); - check(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.IsRecording); // Must be in recording state // If previous active render pass end it if (commandBufferRef.ActiveRenderPass) { @@ -1898,8 +2035,8 @@ void VulkanContext::SetViewport(uint32_t commandBufferId, uint32_t x, uint32_t y, uint32_t width, uint32_t height, float znear, float zfar) { auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); - check(commandBufferRef.IsRecording); // Must be in recording state - check(commandBufferRef.ActiveRenderPass); // Must be in a render pass + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass // Invert viewport on Y VkViewport viewport{ static_cast(x), static_cast(y) + static_cast(height), static_cast(width), -static_cast(height), znear, zfar }; @@ -1911,11 +2048,11 @@ void VulkanContext::SetScissor(uint32_t commandBufferId, uint32_t x, uint32_t y, uint32_t width, uint32_t height) { auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); - check(commandBufferRef.IsRecording); // Must be in recording state - check(commandBufferRef.ActiveRenderPass); // Must be in a render pass + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass - check(x + width <= std::numeric_limits().max()); // sum must not overflow int32_t - check(y + height <= std::numeric_limits().max()); // sum must not overflow int32_t + furyassert(x + width <= std::numeric_limits().max()); // sum must not overflow int32_t + furyassert(y + height <= std::numeric_limits().max()); // sum must not overflow int32_t VkRect2D rect{ x, y, width, height }; vkCmdSetScissor(commandBufferRef.Cmd, 0, 1, &rect); @@ -1925,8 +2062,8 @@ void VulkanContext::BindPipeline(uint32_t commandBufferId, uint32_t pipeline) { auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); - check(commandBufferRef.IsRecording); // Must be in recording state - check(commandBufferRef.ActiveRenderPass); // Must be in a render pass + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass auto& pipelineRef = GetResource(_pipelines, pipeline); @@ -1937,8 +2074,8 @@ void VulkanContext::BindVertexBuffer(uint32_t commandBufferId, uint32_t bufferId) { auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); - check(commandBufferRef.IsRecording); // Must be in recording state - check(commandBufferRef.ActiveRenderPass); // Must be in a render pass + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass auto& vertexBufRef = GetResource(_vertexBuffers, bufferId); @@ -1950,8 +2087,8 @@ void VulkanContext::BindIndexBuffer(uint32_t commandBufferId, uint32_t bufferId) { auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); - check(commandBufferRef.IsRecording); // Must be in recording state - check(commandBufferRef.ActiveRenderPass); // Must be in a render pass + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass auto& indexBufRef = GetResource(_vertexBuffers, bufferId); @@ -1963,8 +2100,8 @@ void VulkanContext::Draw(uint32_t commandBufferId, uint32_t firstVertex, uint32_t count) { auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); - check(commandBufferRef.IsRecording); // Must be in recording state - check(commandBufferRef.ActiveRenderPass); // Must be in a render pass + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass vkCmdDraw(commandBufferRef.Cmd, count, 1, firstVertex, 0); } @@ -1973,8 +2110,8 @@ void VulkanContext::DrawIndexed(uint32_t commandBufferId, uint32_t index_count, uint32_t first_index, uint32_t first_vertex) { auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); - check(commandBufferRef.IsRecording); // Must be in recording state - check(commandBufferRef.ActiveRenderPass); // Must be in a render pass + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass vkCmdDrawIndexed(commandBufferRef.Cmd, index_count, 1, first_index, first_vertex, 0); } @@ -1983,8 +2120,8 @@ void VulkanContext::DrawIndexedIndirect(uint32_t commandBufferId, uint32_t buffer, uint32_t offset, uint32_t drawCount, uint32_t stride) { auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); - check(commandBufferRef.IsRecording); // Must be in recording state - check(commandBufferRef.ActiveRenderPass); // Must be in a render pass + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass auto& indirectBufferRef = GetResource(_indirectBuffers, buffer); @@ -1996,12 +2133,12 @@ void VulkanContext::BindDescriptorSet(uint32_t commandBufferId, uint32_t setIndex, uint32_t descriptorSetId) { auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); - check(commandBufferRef.IsRecording); // Must be in recording state - check(commandBufferRef.ActiveRenderPass); // Must be in a render pass + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass const DDescriptorSet& descriptorSetRef = GetResource(_descriptorSets, descriptorSetId); - check(setIndex < descriptorSetRef.Sets.size()); + furyassert(setIndex < descriptorSetRef.Sets.size()); vkCmdBindDescriptorSets( commandBufferRef.Cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, descriptorSetRef.RootSignature->PipelineLayout, (uint32_t)descriptorSetRef.Frequency, 1, &descriptorSetRef.Sets[setIndex], 0, nullptr); @@ -2011,8 +2148,8 @@ void VulkanContext::CopyImage(uint32_t commandId, uint32_t imageId, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t stagingBufferId, uint32_t stagingBufferOffset) { auto& commandBufferRef = GetResource(_commandBuffers, commandId); - check(commandBufferRef.IsRecording); // Must be in recording state - check(!commandBufferRef.ActiveRenderPass); // Must be in a render pass + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(!commandBufferRef.ActiveRenderPass); // Must be in a render pass auto& imageRef = GetResource(_images, imageId); auto& buffRef = GetResource(_transferBuffers, stagingBufferId); @@ -2039,8 +2176,8 @@ void VulkanContext::CopyBuffer(uint32_t commandId, uint32_t bufferId, uint32_t offset, uint32_t bytes, uint32_t stagingBufferId, uint32_t stagingBufferOffset) { auto& commandBufferRef = GetResource(_commandBuffers, commandId); - check(commandBufferRef.IsRecording); // Must be in recording state - check(!commandBufferRef.ActiveRenderPass); // Must be in a render pass + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(!commandBufferRef.ActiveRenderPass); // Must be in a render pass auto& vertexRef = GetResource(_vertexBuffers, bufferId); auto& buffRef = GetResource(_transferBuffers, stagingBufferId); @@ -2230,7 +2367,7 @@ VulkanContext::DestroyGpuSemaphore(uint32_t semaphoreId) uint32_t VulkanContext::CreateRenderTarget(EFormat format, ESampleBit samples, bool isDepth, uint32_t width, uint32_t height, uint32_t arrayLength, uint32_t mipMapCount, EResourceState initialState) { - check(samples == ESampleBit::COUNT_1_BIT); + furyassert(samples == ESampleBit::COUNT_1_BIT); VkImageUsageFlags usageFlags{}; @@ -2266,7 +2403,7 @@ VulkanContext::CreateRenderTarget(EFormat format, ESampleBit samples, bool isDep break; case EResourceState::UNORDERED_ACCESS: initialLayout = VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL; // Valid? - check(0); // Verify is correct + furyassert(0); // Verify is correct break; case EResourceState::DEPTH_WRITE: initialLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; @@ -2308,7 +2445,7 @@ VulkanContext::CreateRenderTarget(EFormat format, ESampleBit samples, bool isDep case EResourceState::RAYTRACING_ACCELERATION_STRUCTURE: case EResourceState::SHADING_RATE_SOURCE: default: - check(0); + furyassert(0); break; } @@ -2415,7 +2552,7 @@ RenderTargetBarrier* p_rt_barriers) bufferPtr = &_transferBuffers.at(index); break; default: - check(0); // Invalid type + furyassert(0); // Invalid type break; } VkBuffer pBuffer = bufferPtr->Buffer.Buffer; @@ -2456,7 +2593,7 @@ RenderTargetBarrier* p_rt_barriers) case ETransferOwnership::ACQUIRE: case ETransferOwnership::RELEASE: { - check(pTrans->SrcQueue > 0); + furyassert(pTrans->SrcQueue > 0); const auto& srcQueueRef = GetResource(_queues, pTrans->SrcQueue); pBufferBarrier->srcQueueFamilyIndex = srcQueueRef.QueueFamilyIndex; const auto& dstQueueRef = GetResource(_queues, pTrans->DstQueue); @@ -2519,7 +2656,7 @@ RenderTargetBarrier* p_rt_barriers) case ETransferOwnership::ACQUIRE: case ETransferOwnership::RELEASE: { - check(pTrans->SrcQueue > 0); + furyassert(pTrans->SrcQueue > 0); const auto& srcQueueRef = GetResource(_queues, pTrans->SrcQueue); pImageBarrier->srcQueueFamilyIndex = srcQueueRef.QueueFamilyIndex; const auto& dstQueueRef = GetResource(_queues, pTrans->DstQueue); @@ -2581,7 +2718,7 @@ RenderTargetBarrier* p_rt_barriers) case ETransferOwnership::ACQUIRE: case ETransferOwnership::RELEASE: { - check(pTrans->SrcQueue > 0); + furyassert(pTrans->SrcQueue > 0); const auto& srcQueueRef = GetResource(_queues, pTrans->SrcQueue); pImageBarrier->srcQueueFamilyIndex = srcQueueRef.QueueFamilyIndex; const auto& dstQueueRef = GetResource(_queues, pTrans->DstQueue); @@ -2600,7 +2737,7 @@ RenderTargetBarrier* p_rt_barriers) VkPipelineStageFlags dstStageMask = VkUtils::determinePipelineStageFlags(dstAccessFlags, commandBufferRef.Type); { - check(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.IsRecording); // Must be in recording state // If previous active render pass end it if (commandBufferRef.ActiveRenderPass) { @@ -2662,7 +2799,7 @@ uint32_t stride) pipe.SetPolygonMode(VK_POLYGON_MODE_LINE); break; default: - check(0); + furyassert(0); break; } switch (format.CullMode) @@ -2677,7 +2814,7 @@ uint32_t stride) pipe.SetCulling(VK_CULL_MODE_BACK_BIT); break; default: - check(0); + furyassert(0); break; } switch (format.DepthTestMode) @@ -2978,7 +3115,7 @@ ConvertRenderPassAttachmentsToRIVkRenderPassInfo(const DRenderPassAttachments& a info.DepthStencilAttachmentReference.emplace_back(ref); break; default: - check(0); + furyassert(0); break; } diff --git a/src/backend/vulkan/VulkanContext.h b/src/backend/vulkan/VulkanContext.h index fa6a0b4..d1cf12a 100644 --- a/src/backend/vulkan/VulkanContext.h +++ b/src/backend/vulkan/VulkanContext.h @@ -165,6 +165,9 @@ class VulkanContext final : public IContext public: VulkanContext(const DContextConfig* const config); ~VulkanContext(); + + bool CompileNativeShader(const std::vector& blob, std::vector& outShader, EShaderStage shaderStage, std::string& errorMgs) override; + void WaitDeviceIdle() override; SwapchainId CreateSwapchain(const WindowData* windowData, EPresentMode& presentMode, EFormat& outFormat, uint32_t* width = nullptr, uint32_t* height = nullptr) override; std::vector GetSwapchainRenderTargets(SwapchainId swapchainId) override; @@ -264,10 +267,10 @@ class VulkanContext final : public IContext DSamplerVulkan _emptySampler; std::array _swapchains; /*Vertex and index buffers pool*/ - std::array _vertexBuffers; - std::array _transferBuffers; - std::array _uniformBuffers; - std::array _indirectBuffers; + std::array _vertexBuffers; + std::array _transferBuffers; + std::array _uniformBuffers; + std::array _indirectBuffers; /*Whenever a render target gets deleted remove also framebuffers that have that image id as attachment*/ std::array _framebuffers; std::array _shaders; diff --git a/src/backend/vulkan/VulkanDevice.cpp b/src/backend/vulkan/VulkanDevice.cpp index 70cf5af..761ea89 100644 --- a/src/backend/vulkan/VulkanDevice.cpp +++ b/src/backend/vulkan/VulkanDevice.cpp @@ -23,8 +23,8 @@ namespace Fox RIVulkanDevice::~RIVulkanDevice() { - check(PhysicalDevice == nullptr); - check(Device == nullptr); + furyassert(PhysicalDevice == nullptr); + furyassert(Device == nullptr); }; VkResult @@ -35,8 +35,8 @@ std::vector extensions, VkPhysicalDeviceFeatures* optDeviceFeatures, std::vector validationLayers) { - check(PhysicalDevice == nullptr); - check(Device == nullptr); + furyassert(PhysicalDevice == nullptr); + furyassert(Device == nullptr); PhysicalDevice = hardwareDevice; @@ -134,11 +134,11 @@ std::vector validationLayers) vma_vulkan_func.vkBindBufferMemory2KHR = vkBindBufferMemory2KHR; vma_vulkan_func.vkBindImageMemory2KHR = vkBindImageMemory2KHR; - check(vma_vulkan_func.vkGetPhysicalDeviceMemoryProperties2KHR); - check(vma_vulkan_func.vkGetBufferMemoryRequirements2KHR); - check(vma_vulkan_func.vkGetImageMemoryRequirements2KHR); - check(vma_vulkan_func.vkBindBufferMemory2KHR); - check(vma_vulkan_func.vkBindImageMemory2KHR); + furyassert(vma_vulkan_func.vkGetPhysicalDeviceMemoryProperties2KHR); + furyassert(vma_vulkan_func.vkGetBufferMemoryRequirements2KHR); + furyassert(vma_vulkan_func.vkGetImageMemoryRequirements2KHR); + furyassert(vma_vulkan_func.vkBindBufferMemory2KHR); + furyassert(vma_vulkan_func.vkBindImageMemory2KHR); VmaAllocatorCreateInfo allocatorCreateInfo = {}; allocatorCreateInfo.vulkanApiVersion = VK_API_VERSION_1_1; @@ -163,8 +163,8 @@ std::vector validationLayers) void RIVulkanDevice::Deinit() { - check(PhysicalDevice != nullptr); - check(Device != nullptr); + furyassert(PhysicalDevice != nullptr); + furyassert(Device != nullptr); vmaDestroyAllocator(VmaAllocator); diff --git a/src/backend/vulkan/VulkanDevice10.cpp b/src/backend/vulkan/VulkanDevice10.cpp index 946f498..03fefc8 100644 --- a/src/backend/vulkan/VulkanDevice10.cpp +++ b/src/backend/vulkan/VulkanDevice10.cpp @@ -245,7 +245,7 @@ RIVulkanPipelineBuilder::_fillViewportState() PipelineViewportState.pScissors = Scissors.data(); } -RIVulkanDevice10::~RIVulkanDevice10(){ check(_pipelines.size() == 0) } +RIVulkanDevice10::~RIVulkanDevice10(){ furyassert(_pipelines.size() == 0) } VkPipeline RIVulkanDevice10::CreatePipeline(const VkGraphicsPipelineCreateInfo* info) { @@ -264,8 +264,8 @@ VkPipeline RIVulkanDevice10::CreatePipeline(const VkGraphicsPipelineCreateInfo* void RIVulkanDevice10::DestroyPipeline(VkPipeline pipeline) { - check(pipeline); - check(_pipelines.size() > 0); + furyassert(pipeline); + furyassert(_pipelines.size() > 0); vkDestroyPipeline(Device, pipeline, nullptr); _pipelines.erase(_pipelines.find(pipeline)); @@ -323,7 +323,7 @@ RIVulkanDevice10::DestroyPipeline(VkPipeline pipeline) // VkViewport // RIVulkanDevice10::CreateViewport(uint32_t width, uint32_t height, float znear, float zfar) //{ -// check(zfar < 1.1f); // range 0 - 1 +// furyassert(zfar < 1.1f); // range 0 - 1 // // VkViewport v{}; // v.width = width; diff --git a/src/backend/vulkan/VulkanDevice11.cpp b/src/backend/vulkan/VulkanDevice11.cpp index cd679af..e4ed023 100644 --- a/src/backend/vulkan/VulkanDevice11.cpp +++ b/src/backend/vulkan/VulkanDevice11.cpp @@ -9,7 +9,7 @@ namespace Fox { -RIVulkanDevice11::~RIVulkanDevice11() { check(_descriptorPools.size() == 0); } +RIVulkanDevice11::~RIVulkanDevice11() { furyassert(_descriptorPools.size() == 0); } VkDescriptorSet RIDescriptorPoolManager::CreateDescriptorSet(VkDescriptorSetLayout descriptorSetLayout) @@ -131,7 +131,7 @@ RIDescriptorSetBinder::BindCombinedImageSamplerArray(uint32_t bindingIndex, cons void RIDescriptorSetBinder::BindDescriptorSet(VkCommandBuffer cmd, VkPipelineLayout pipelineLayout, VkDescriptorSetLayout descriptorSetLayout, uint32_t setIndex) { - check(_currentUpdate.has_value()); + furyassert(_currentUpdate.has_value()); VkDescriptorSet set = QueryOrMakeDescriptorSet(descriptorSetLayout); vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, setIndex, 1, &set, (uint32_t)_dynamicOffsets.size(), _dynamicOffsets.data()); @@ -142,7 +142,7 @@ RIDescriptorSetBinder::BindDescriptorSet(VkCommandBuffer cmd, VkPipelineLayout p VkDescriptorSet RIDescriptorSetBinder::QueryOrMakeDescriptorSet(VkDescriptorSetLayout descriptorSetLayout) { - check(_currentUpdate.has_value()); // You must bind something first + furyassert(_currentUpdate.has_value()); // You must bind something first VkDescriptorSet set = _queryDescriptorSet(descriptorSetLayout, _currentUpdate.value()); if (!set) @@ -154,7 +154,7 @@ RIDescriptorSetBinder::QueryOrMakeDescriptorSet(VkDescriptorSetLayout descriptor _cachedDescriptorSets[descriptorSetLayout][_currentUpdate.value()] = set; } - check(set != nullptr); + furyassert(set != nullptr); return set; } @@ -200,9 +200,9 @@ void RIVulkanDevice11::DestroyDescriptorPool(VkDescriptorPool pool) { vkDestroyDescriptorPool(Device, pool, nullptr); - check(_descriptorPools.size() > 0); + furyassert(_descriptorPools.size() > 0); const auto found = _descriptorPools.find(pool); - check(found != _descriptorPools.end()); + furyassert(found != _descriptorPools.end()); _descriptorPools.erase(found); } @@ -227,7 +227,7 @@ RIVulkanDevice11::CreateDescriptorSet(VkDescriptorPool pool, VkDescriptorSetLayo RIDescriptorPoolManager* RIVulkanDevice11::CreateDescriptorPool2(const std::vector& poolDimensions, uint32_t maxSets) { - check(0); + furyassert(0); VkDescriptorPool descriptorPool = CreateDescriptorPool(poolDimensions, maxSets); RIDescriptorPoolManager* pool = new RIDescriptorPoolManager(Device, poolDimensions, maxSets); return pool; diff --git a/src/backend/vulkan/VulkanDevice12.cpp b/src/backend/vulkan/VulkanDevice12.cpp index 5c0b394..bb57671 100644 --- a/src/backend/vulkan/VulkanDevice12.cpp +++ b/src/backend/vulkan/VulkanDevice12.cpp @@ -11,7 +11,7 @@ namespace Fox { -RIVulkanDevice12::~RIVulkanDevice12() { check(_cachedPools.size() == 0); } +RIVulkanDevice12::~RIVulkanDevice12() { furyassert(_cachedPools.size() == 0); } RICommandBuffer* RICommandPool::Allocate() @@ -38,7 +38,7 @@ RICommandPool::Allocate() void RICommandPool::Reset() { - check(_poolManager); // has beed moved, invalid state + furyassert(_poolManager); // has beed moved, invalid state vkResetCommandPool(_device, _poolManager, VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT); std::for_each(_cachedCmds.begin(), _cachedCmds.end(), [](RICommandBuffer& cmd) { @@ -46,7 +46,7 @@ RICommandPool::Reset() { cmd.DecreaseCounter(); } - check(cmd.Count() == 0); + furyassert(cmd.Count() == 0); }); } @@ -144,7 +144,7 @@ RIVulkanDevice12::SubmitToMainQueue(VkQueue queue, const std::vectorCmd; }); - check(commandBuffers.size() == cmds.size()); + furyassert(commandBuffers.size() == cmds.size()); VkSubmitInfo submitInfo{}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; diff --git a/src/backend/vulkan/VulkanDevice13.cpp b/src/backend/vulkan/VulkanDevice13.cpp index c782e53..9c4a333 100644 --- a/src/backend/vulkan/VulkanDevice13.cpp +++ b/src/backend/vulkan/VulkanDevice13.cpp @@ -9,7 +9,7 @@ namespace Fox { -RIVulkanDevice13::~RIVulkanDevice13(){ check(_renderPassMap.Size() == 0) } +RIVulkanDevice13::~RIVulkanDevice13(){ furyassert(_renderPassMap.Size() == 0) } VkResult RIVulkanDevice13::CreateRenderPass(const RIVkRenderPassInfo& info, VkRenderPass* renderPass) { diff --git a/src/backend/vulkan/VulkanDevice2.cpp b/src/backend/vulkan/VulkanDevice2.cpp index fb65df7..3f99b64 100644 --- a/src/backend/vulkan/VulkanDevice2.cpp +++ b/src/backend/vulkan/VulkanDevice2.cpp @@ -10,7 +10,7 @@ namespace Fox { -RIVulkanDevice2::~RIVulkanDevice2() { check(_swapchains.size() == 0); } +RIVulkanDevice2::~RIVulkanDevice2() { furyassert(_swapchains.size() == 0); } bool RIVulkanDevice2::SurfaceSupportPresentationOnQueueFamilyIndex(VkSurfaceKHR surface, uint32_t queueFamilyIndex) @@ -45,7 +45,7 @@ RIVulkanDevice2::GetSurfaceFormats(VkSurfaceKHR surface) return formats; } } - check(0); + furyassert(0); return {}; } @@ -95,7 +95,7 @@ uint32_t queueFamilyIndicesCount VkSwapchainKHR* outSwapchain, VkSwapchainKHR oldSwapchain) { - check(queueFamilyIndices != nullptr); + furyassert(queueFamilyIndices != nullptr); critical(capabilities.minImageCount >= MAX_IMAGE_COUNT); VkSwapchainCreateInfoKHR swapchainInfo = {}; @@ -107,10 +107,10 @@ VkSwapchainKHR oldSwapchain) swapchainInfo.imageFormat = format.format; swapchainInfo.imageColorSpace = format.colorSpace; - check(capabilities.currentExtent.width > 0); // imageExtent members width and height must both be non-zero - check(capabilities.currentExtent.height > 0); // imageExtent members width and height must both be non-zero - check(capabilities.currentExtent.width <= capabilities.maxImageExtent.width); - check(capabilities.currentExtent.height <= capabilities.maxImageExtent.height); + furyassert(capabilities.currentExtent.width > 0); // imageExtent members width and height must both be non-zero + furyassert(capabilities.currentExtent.height > 0); // imageExtent members width and height must both be non-zero + furyassert(capabilities.currentExtent.width <= capabilities.maxImageExtent.width); + furyassert(capabilities.currentExtent.height <= capabilities.maxImageExtent.height); swapchainInfo.imageExtent = capabilities.currentExtent; swapchainInfo.imageArrayLayers = capabilities.maxImageArrayLayers; @@ -148,7 +148,7 @@ RIVulkanDevice2::GetSwapchainImages(VkSwapchainKHR swapchain) uint32_t imageCount = 0; vkGetSwapchainImagesKHR(Device, swapchain, &imageCount, nullptr); - check(imageCount >= MAX_IMAGE_COUNT); + furyassert(imageCount >= MAX_IMAGE_COUNT); images.resize(imageCount); vkGetSwapchainImagesKHR(Device, swapchain, &imageCount, images.data()); @@ -190,7 +190,7 @@ RIVulkanDevice2::Present(VkQueue queue, std::vector results(swapchainImageIndex.size(), VK_SUCCESS); - check(results.size() == swapchainImageIndex.size()); + furyassert(results.size() == swapchainImageIndex.size()); std::vector swapchains(swapchainImageIndex.size()); std::vector imageIndices(swapchainImageIndex.size()); @@ -198,8 +198,8 @@ RIVulkanDevice2::Present(VkQueue queue, std::vector& p) { return p.first; }); std::transform(swapchainImageIndex.begin(), swapchainImageIndex.end(), imageIndices.begin(), [](const std::pair& p) { return p.second; }); - check(swapchains.size() == swapchainImageIndex.size()); - check(swapchains.size() == imageIndices.size()); + furyassert(swapchains.size() == swapchainImageIndex.size()); + furyassert(swapchains.size() == imageIndices.size()); VkPresentInfoKHR presentInfo{}; presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; diff --git a/src/backend/vulkan/VulkanDevice3.cpp b/src/backend/vulkan/VulkanDevice3.cpp index b4a5e85..903c575 100644 --- a/src/backend/vulkan/VulkanDevice3.cpp +++ b/src/backend/vulkan/VulkanDevice3.cpp @@ -11,8 +11,8 @@ namespace Fox RIVulkanDevice3::~RIVulkanDevice3() { - check(_fences.size() == 0); - check(_semaphores.size() == 0); + furyassert(_fences.size() == 0); + furyassert(_semaphores.size() == 0); } VkSemaphore diff --git a/src/backend/vulkan/VulkanDevice4.cpp b/src/backend/vulkan/VulkanDevice4.cpp index c963544..a30ab5f 100644 --- a/src/backend/vulkan/VulkanDevice4.cpp +++ b/src/backend/vulkan/VulkanDevice4.cpp @@ -9,7 +9,7 @@ namespace Fox { -RIVulkanDevice4::~RIVulkanDevice4() { check(_buffers.size() == 0); } +RIVulkanDevice4::~RIVulkanDevice4() { furyassert(_buffers.size() == 0); } RIVulkanBuffer RIVulkanDevice4::CreateBufferHostVisible(uint32_t size, VkBufferUsageFlags usage) diff --git a/src/backend/vulkan/VulkanDevice5.cpp b/src/backend/vulkan/VulkanDevice5.cpp index 224c814..286b4e5 100644 --- a/src/backend/vulkan/VulkanDevice5.cpp +++ b/src/backend/vulkan/VulkanDevice5.cpp @@ -11,8 +11,8 @@ namespace Fox RIVulkanDevice5::~RIVulkanDevice5() { - check(_images.size() == 0); - check(_imageViews.size() == 0); + furyassert(_images.size() == 0); + furyassert(_imageViews.size() == 0); } RIVulkanImage @@ -124,7 +124,7 @@ RIVulkanDevice5::CreateImageView_DEPRECATED(VkFormat format, const RIVulkanImage return nullptr; } } - check(imageView); + furyassert(imageView); _imageViews.insert(imageView); @@ -153,7 +153,7 @@ RIVulkanDevice5::CreateImageView(VkFormat format, VkImage image, VkImageAspectFl return result; } } - check(*outImageView); + furyassert(*outImageView); _imageViews.insert(*outImageView); diff --git a/src/backend/vulkan/VulkanDevice6.cpp b/src/backend/vulkan/VulkanDevice6.cpp index 76ae188..634acd1 100644 --- a/src/backend/vulkan/VulkanDevice6.cpp +++ b/src/backend/vulkan/VulkanDevice6.cpp @@ -9,7 +9,7 @@ namespace Fox { -RIVulkanDevice6::~RIVulkanDevice6() { check(_samplers.size() == 0); } +RIVulkanDevice6::~RIVulkanDevice6() { furyassert(_samplers.size() == 0); } VkSampler RIVulkanDevice6::CreateSampler(VkFilter minFilter, VkFilter magFilter, VkSamplerAddressMode mode, float minLod, float maxLod, VkSamplerMipmapMode mipmapMode, bool anisotropy, float maxAnisotropy) diff --git a/src/backend/vulkan/VulkanDevice7.cpp b/src/backend/vulkan/VulkanDevice7.cpp index 3c9aea1..0a9769d 100644 --- a/src/backend/vulkan/VulkanDevice7.cpp +++ b/src/backend/vulkan/VulkanDevice7.cpp @@ -9,7 +9,7 @@ namespace Fox { -RIVulkanDevice7::~RIVulkanDevice7() { check(_framebuffers_DEPRECATED.size() == 0); } +RIVulkanDevice7::~RIVulkanDevice7() { furyassert(_framebuffers_DEPRECATED.size() == 0); } VkFramebuffer RIVulkanDevice7::_createFramebuffer(const std::vector& imageViews, uint32_t width, uint32_t height, VkRenderPass renderpass) diff --git a/src/backend/vulkan/VulkanDevice8.cpp b/src/backend/vulkan/VulkanDevice8.cpp index 0e5ef9f..8c8107d 100644 --- a/src/backend/vulkan/VulkanDevice8.cpp +++ b/src/backend/vulkan/VulkanDevice8.cpp @@ -9,7 +9,7 @@ namespace Fox { -RIVulkanDevice8::~RIVulkanDevice8() { check(_descriptorSetLayoutCache.size() == 0); } +RIVulkanDevice8::~RIVulkanDevice8() { furyassert(_descriptorSetLayoutCache.size() == 0); } VkDescriptorSetLayoutBinding RIVulkanDevice8::CreateDescriptorSetLayoutBindingUniformBufferDynamic(uint32_t binding, uint32_t descriptorCount, VkShaderStageFlags stages) diff --git a/src/backend/vulkan/VulkanDevice9.cpp b/src/backend/vulkan/VulkanDevice9.cpp index c6f883d..c6e4cfa 100644 --- a/src/backend/vulkan/VulkanDevice9.cpp +++ b/src/backend/vulkan/VulkanDevice9.cpp @@ -9,7 +9,7 @@ namespace Fox { -RIVulkanDevice9::~RIVulkanDevice9() { check(_pipelineLayoutCache.Size() == 0); } +RIVulkanDevice9::~RIVulkanDevice9() { furyassert(_pipelineLayoutCache.Size() == 0); } VkPipelineLayout RIVulkanDevice9::CreatePipelineLayout(const std::vector& descriptorSetLayout, const std::vector& pushConstantRange) diff --git a/src/backend/vulkan/VulkanInstance.cpp b/src/backend/vulkan/VulkanInstance.cpp index 2a57b1e..8389830 100644 --- a/src/backend/vulkan/VulkanInstance.cpp +++ b/src/backend/vulkan/VulkanInstance.cpp @@ -14,7 +14,7 @@ namespace Fox VkResult RIVulkanInstance::Init(const char* applicationName, std::vector validationLayers, std::vector extensions) { - check(Instance == nullptr); + furyassert(Instance == nullptr); VkApplicationInfo applicationInfo = {}; applicationInfo.pNext = NULL; @@ -54,7 +54,7 @@ RIVulkanInstance::Deinit() _destroyDebugUtilsMessenger(); } #endif - check(Instance != nullptr); + furyassert(Instance != nullptr); vkDestroyInstance(Instance, nullptr); } @@ -78,7 +78,7 @@ RIVulkanInstance::CreateSurfaceFromWindow(const WindowData& windowData, VkSurfac #elif defined(__linux__) { Fox::WindowPlatformLinuxSDL* win = static_cast(window); - check(win); + furyassert(win); VkXlibSurfaceCreateInfoKHR createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; @@ -116,7 +116,7 @@ RIVulkanInstance::CreateDebugUtilsMessenger(PFN_vkDebugUtilsMessengerCallbackEXT dbgInfo.pUserData = userData; // Optional auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(Instance, "vkCreateDebugUtilsMessengerEXT"); - check(func); + furyassert(func); if (func != nullptr) { const VkResult result = func(Instance, &dbgInfo, nullptr, &_debugMessenger); @@ -130,7 +130,7 @@ void RIVulkanInstance::_destroyDebugUtilsMessenger() { auto func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(Instance, "vkDestroyDebugUtilsMessengerEXT"); - check(func); + furyassert(func); if (func != nullptr) { func(Instance, _debugMessenger, nullptr); diff --git a/thirdparty/glslang b/thirdparty/glslang new file mode 160000 index 0000000..022aea4 --- /dev/null +++ b/thirdparty/glslang @@ -0,0 +1 @@ +Subproject commit 022aea431c462f351c1120cb0b4a2144aa237a50 From cb35572bd248d077dab6a7c4eab08d98899017fc Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Fri, 29 Mar 2024 21:59:46 +0100 Subject: [PATCH 19/58] fixed bug getIntermediate always on vertex shader --- src/backend/vulkan/VulkanContext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index 39f2170..534e2a0 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -491,7 +491,7 @@ VulkanContext::CompileNativeShader(const std::vector& blob, std:: furyassert(program->link((EShMessages)(EShMsgSpvRules | EShMsgVulkanRules))); - glslang::GlslangToSpv(*program->getIntermediate(EShLanguage::EShLangVertex), outShader); + glslang::GlslangToSpv(*program->getIntermediate(language), outShader); delete program; delete shader; From 33c5ad125d28e29881d88e3542e730b586ed987d Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Tue, 2 Apr 2024 18:03:07 +0200 Subject: [PATCH 20/58] fixed additive blend mode --- src/backend/vulkan/VulkanDevice10.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/vulkan/VulkanDevice10.cpp b/src/backend/vulkan/VulkanDevice10.cpp index 03fefc8..a7becbc 100644 --- a/src/backend/vulkan/VulkanDevice10.cpp +++ b/src/backend/vulkan/VulkanDevice10.cpp @@ -146,7 +146,7 @@ RIVulkanPipelineBuilder::SetAlphaBlending() colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD; colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; - colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE; colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; PipelineColorBlendAttachmentStates.push_back(colorBlendAttachment); From c4b182cb9824dbe7213e0fced576b3041d73ccd4 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Tue, 2 Apr 2024 18:03:23 +0200 Subject: [PATCH 21/58] added error mgr when compiling shader --- src/backend/vulkan/VulkanContext.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index 534e2a0..37b3701 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -484,12 +484,21 @@ VulkanContext::CompileNativeShader(const std::vector& blob, std:: shader->setStringsWithLengths(&shaderSource, &l, 1); shader->setEntryPoint("main"); - furyassert(shader->parse(GetDefaultResources(), 100, false, (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules))); + if (!shader->parse(GetDefaultResources(), 100, false, (EShMessages)(EShMsgSpvRules | EShMsgVulkanRules))) + { + errorMgs = shader->getInfoLog(); + return false; + } glslang::TProgram* program{ new glslang::TProgram() }; program->addShader(shader); - furyassert(program->link((EShMessages)(EShMsgSpvRules | EShMsgVulkanRules))); + if(!program->link((EShMessages)(EShMsgSpvRules | EShMsgVulkanRules))) + { + errorMgs = shader->getInfoLog(); + return false; + } + glslang::GlslangToSpv(*program->getIntermediate(language), outShader); From 4eb6720327096413cca901a477d6b8260107a75d Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Tue, 2 Apr 2024 21:35:30 +0200 Subject: [PATCH 22/58] restore blend mode --- src/backend/vulkan/VulkanDevice10.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/vulkan/VulkanDevice10.cpp b/src/backend/vulkan/VulkanDevice10.cpp index a7becbc..03fefc8 100644 --- a/src/backend/vulkan/VulkanDevice10.cpp +++ b/src/backend/vulkan/VulkanDevice10.cpp @@ -146,7 +146,7 @@ RIVulkanPipelineBuilder::SetAlphaBlending() colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD; colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; - colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD; PipelineColorBlendAttachmentStates.push_back(colorBlendAttachment); From 27f3d5329c9f6d7758638d2f2459bc2818c2f713 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Wed, 3 Apr 2024 08:43:27 +0200 Subject: [PATCH 23/58] additive blend mode does not write to alpha --- src/backend/vulkan/VulkanDevice10.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/vulkan/VulkanDevice10.cpp b/src/backend/vulkan/VulkanDevice10.cpp index 03fefc8..fa9eb73 100644 --- a/src/backend/vulkan/VulkanDevice10.cpp +++ b/src/backend/vulkan/VulkanDevice10.cpp @@ -140,7 +140,7 @@ RIVulkanPipelineBuilder::SetAlphaBlending() } VkPipelineColorBlendAttachmentState colorBlendAttachment{}; - colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT;// | VK_COLOR_COMPONENT_A_BIT; colorBlendAttachment.blendEnable = VK_TRUE; colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; From ddc305a522d261e0785517f8c3426147865b6415 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Thu, 11 Apr 2024 08:45:47 +0200 Subject: [PATCH 24/58] increased useless rebindings and increased overall performance --- src/backend/vulkan/VulkanContext.cpp | 47 +++++++++++++++++++++------- src/backend/vulkan/VulkanContext.h | 4 +++ 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index 37b3701..322f7c6 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -493,12 +493,11 @@ VulkanContext::CompileNativeShader(const std::vector& blob, std:: glslang::TProgram* program{ new glslang::TProgram() }; program->addShader(shader); - if(!program->link((EShMessages)(EShMsgSpvRules | EShMsgVulkanRules))) - { - errorMgs = shader->getInfoLog(); - return false; - } - + if (!program->link((EShMessages)(EShMsgSpvRules | EShMsgVulkanRules))) + { + errorMgs = shader->getInfoLog(); + return false; + } glslang::GlslangToSpv(*program->getIntermediate(language), outShader); @@ -1916,6 +1915,10 @@ VulkanContext::BeginCommandBuffer(uint32_t commandBufferId) auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); furyassert(!commandBufferRef.IsRecording); // Must not be in recording state commandBufferRef.IsRecording = true; + commandBufferRef.BoundPipeline = {}; + commandBufferRef.CurrentScissor = {}; + commandBufferRef.CurrentVertexBuffer = {}; + commandBufferRef.CurrentIndexBuffer = {}; VkCommandBufferBeginInfo beginInfo{}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; @@ -2063,8 +2066,16 @@ VulkanContext::SetScissor(uint32_t commandBufferId, uint32_t x, uint32_t y, uint furyassert(x + width <= std::numeric_limits().max()); // sum must not overflow int32_t furyassert(y + height <= std::numeric_limits().max()); // sum must not overflow int32_t + auto areRect2dEqual = [](const VkRect2D& a, const VkRect2D& b) { + return a.extent.width == b.extent.width && a.extent.height == b.extent.height && a.offset.x == b.offset.x && a.offset.y == b.offset.y; + }; + VkRect2D rect{ x, y, width, height }; - vkCmdSetScissor(commandBufferRef.Cmd, 0, 1, &rect); + if (!areRect2dEqual(commandBufferRef.CurrentScissor, rect)) + { + commandBufferRef.CurrentScissor = rect; + vkCmdSetScissor(commandBufferRef.Cmd, 0, 1, &rect); + } } void @@ -2076,7 +2087,11 @@ VulkanContext::BindPipeline(uint32_t commandBufferId, uint32_t pipeline) auto& pipelineRef = GetResource(_pipelines, pipeline); - vkCmdBindPipeline(commandBufferRef.Cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineRef.Pipeline); + if (commandBufferRef.BoundPipeline != pipelineRef.Pipeline) + { + commandBufferRef.BoundPipeline = pipelineRef.Pipeline; + vkCmdBindPipeline(commandBufferRef.Cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineRef.Pipeline); + } } void @@ -2088,8 +2103,12 @@ VulkanContext::BindVertexBuffer(uint32_t commandBufferId, uint32_t bufferId) auto& vertexBufRef = GetResource(_vertexBuffers, bufferId); - VkDeviceSize offset{}; - vkCmdBindVertexBuffers(commandBufferRef.Cmd, 0, 1, &vertexBufRef.Buffer.Buffer, &offset); + if (commandBufferRef.CurrentVertexBuffer != vertexBufRef.Buffer.Buffer) + { + commandBufferRef.CurrentVertexBuffer = vertexBufRef.Buffer.Buffer; + VkDeviceSize offset{}; + vkCmdBindVertexBuffers(commandBufferRef.Cmd, 0, 1, &vertexBufRef.Buffer.Buffer, &offset); + } } void @@ -2101,8 +2120,12 @@ VulkanContext::BindIndexBuffer(uint32_t commandBufferId, uint32_t bufferId) auto& indexBufRef = GetResource(_vertexBuffers, bufferId); - VkDeviceSize offset{}; - vkCmdBindIndexBuffer(commandBufferRef.Cmd, indexBufRef.Buffer.Buffer, offset, VK_INDEX_TYPE_UINT32); + if (commandBufferRef.CurrentIndexBuffer != indexBufRef.Buffer.Buffer) + { + commandBufferRef.CurrentIndexBuffer = indexBufRef.Buffer.Buffer; + VkDeviceSize offset{}; + vkCmdBindIndexBuffer(commandBufferRef.Cmd, indexBufRef.Buffer.Buffer, offset, VK_INDEX_TYPE_UINT32); + } } void diff --git a/src/backend/vulkan/VulkanContext.h b/src/backend/vulkan/VulkanContext.h index d1cf12a..77910d9 100644 --- a/src/backend/vulkan/VulkanContext.h +++ b/src/backend/vulkan/VulkanContext.h @@ -99,6 +99,10 @@ struct DCommandBufferVulkan : public DResource uint32_t QueueFamilyIndex{}; bool IsRecording{}; VkRenderPass ActiveRenderPass{}; + VkPipeline BoundPipeline{}; + VkRect2D CurrentScissor{}; + VkBuffer CurrentVertexBuffer{}; + VkBuffer CurrentIndexBuffer{}; }; struct DFenceVulkan : public DResource From 6ff6c381116df512728aebb82ca418169c2df441 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Fri, 12 Apr 2024 07:29:43 +0200 Subject: [PATCH 25/58] Disable validation layers in debug mode --- src/backend/vulkan/VulkanContext.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index 322f7c6..265a0fd 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -367,7 +367,11 @@ VulkanContext::_initializeDevice() critical(descriptorIndexingFeatures.descriptorBindingStorageBufferUpdateAfterBind); // Check validation layers and extensions support for the device + #if _DEBUG auto validDeviceValidationLayers = _getDeviceSupportedValidationLayers(physicalDevice, _validationLayers); + #else + const std::vector validDeviceValidationLayers{}; + #endif auto validDeviceExtensions = _getDeviceSupportedExtensions(physicalDevice, _deviceExtensionNames); // Create device From a5c7273e18101f3e9d2f9eb29da7e35c5ea60041 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Fri, 12 Apr 2024 07:56:05 +0200 Subject: [PATCH 26/58] modified UpdateDescriptorSet do not take set Index as param but is not inside DescriptorData to batch more calls together --- include/IContext.h | 3 ++- src/backend/vulkan/VulkanContext.cpp | 4 ++-- src/backend/vulkan/VulkanContext.h | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/IContext.h b/include/IContext.h index cfad244..26a92bd 100644 --- a/include/IContext.h +++ b/include/IContext.h @@ -681,6 +681,7 @@ typedef struct RenderTargetBarrier typedef struct DescriptorData { const char* pName; + uint32_t SetIndex{}; uint32_t Count{}; uint32_t ArrayOffset{}; uint32_t Index{}; @@ -747,7 +748,7 @@ class IContext virtual void DestroyRootSignature(uint32_t rootSignatureId) = 0; virtual uint32_t CreateDescriptorSets(uint32_t rootSignatureId, EDescriptorFrequency frequency, uint32_t count) = 0; virtual void DestroyDescriptorSet(uint32_t descriptorSetId) = 0; - virtual void UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t setIndex, uint32_t paramCount, DescriptorData* params) = 0; + virtual void UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t paramCount, DescriptorData* params) = 0; virtual uint32_t CreateSampler(uint32_t minLod, uint32_t maxLod) = 0; virtual uint32_t CreateCommandPool(uint32_t queueId) = 0; diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index 265a0fd..24da7d0 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -1672,7 +1672,7 @@ VulkanContext::DestroyDescriptorSet(uint32_t descriptorSetId) } void -VulkanContext::UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t setIndex, uint32_t paramCount, DescriptorData* params) +VulkanContext::UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t paramCount, DescriptorData* params) { const DDescriptorSet& descriptorSetRef = GetResource(_descriptorSets, descriptorSetId); @@ -1772,7 +1772,7 @@ VulkanContext::UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t setIndex, writeSet->dstArrayElement = param->ArrayOffset; writeSet->dstBinding = param->Index; - writeSet->dstSet = descriptorSetRef.Sets.at(setIndex); + writeSet->dstSet = descriptorSetRef.Sets.at(param->SetIndex); } vkUpdateDescriptorSets(Device.Device, writeSetCount, write.data(), 0, nullptr); diff --git a/src/backend/vulkan/VulkanContext.h b/src/backend/vulkan/VulkanContext.h index 77910d9..22c0160 100644 --- a/src/backend/vulkan/VulkanContext.h +++ b/src/backend/vulkan/VulkanContext.h @@ -199,7 +199,7 @@ class VulkanContext final : public IContext void DestroyRootSignature(uint32_t rootSignatureId) override; uint32_t CreateDescriptorSets(uint32_t rootSignatureId, EDescriptorFrequency frequency, uint32_t count) override; void DestroyDescriptorSet(uint32_t descriptorSetId) override; - void UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t setIndex, uint32_t paramCount, DescriptorData* params) override; + void UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t paramCount, DescriptorData* params) override; uint32_t CreateCommandPool(uint32_t queueId) override; void DestroyCommandPool(uint32_t commandPoolId) override; From 84d9a124b5a416ca3c06166d4073e4494779213e Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Thu, 9 May 2024 08:51:02 +0200 Subject: [PATCH 27/58] added assert --- src/backend/vulkan/VulkanContext.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index 24da7d0..827edae 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -110,7 +110,8 @@ AllocResource(std::array& container) } } - throw std::runtime_error("Failed to allocate!"); + furyassert(0);//Possible memory leak, or bad usage of allocations + throw std::runtime_error("Rendering context run out of resource to allocate!"); return {}; } @@ -366,13 +367,13 @@ VulkanContext::_initializeDevice() critical(descriptorIndexingFeatures.shaderStorageBufferArrayNonUniformIndexing); critical(descriptorIndexingFeatures.descriptorBindingStorageBufferUpdateAfterBind); - // Check validation layers and extensions support for the device - #if _DEBUG +// Check validation layers and extensions support for the device +#if _DEBUG auto validDeviceValidationLayers = _getDeviceSupportedValidationLayers(physicalDevice, _validationLayers); - #else +#else const std::vector validDeviceValidationLayers{}; - #endif - auto validDeviceExtensions = _getDeviceSupportedExtensions(physicalDevice, _deviceExtensionNames); +#endif + auto validDeviceExtensions = _getDeviceSupportedExtensions(physicalDevice, _deviceExtensionNames); // Create device const auto result = Device.Create(Instance, (void*)&pDeviceFeatures, physicalDevice, validDeviceExtensions, nullptr, validDeviceValidationLayers); @@ -1918,9 +1919,9 @@ VulkanContext::BeginCommandBuffer(uint32_t commandBufferId) { auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); furyassert(!commandBufferRef.IsRecording); // Must not be in recording state - commandBufferRef.IsRecording = true; - commandBufferRef.BoundPipeline = {}; - commandBufferRef.CurrentScissor = {}; + commandBufferRef.IsRecording = true; + commandBufferRef.BoundPipeline = {}; + commandBufferRef.CurrentScissor = {}; commandBufferRef.CurrentVertexBuffer = {}; commandBufferRef.CurrentIndexBuffer = {}; From 0c0514397166b97e7239b50e76df01b330567756 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Tue, 14 May 2024 09:36:16 +0200 Subject: [PATCH 28/58] optimization --- src/backend/vulkan/VulkanContext.cpp | 7 ++++--- src/backend/vulkan/VulkanContext.h | 10 +++++++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index 827edae..c76728c 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -2282,14 +2282,15 @@ VulkanContext::QueueSubmit(uint32_t queueId, const std::vector& waitSe void VulkanContext::QueuePresent(uint32_t queueId, uint32_t swapchainId, uint32_t imageIndex, const std::vector& waitSemaphore) { - std::vector waitSemaphores; + static std::vector waitSemaphores(10); + waitSemaphores.clear(); for (auto semaphoreId : waitSemaphore) { auto& semaphoreRef = GetResource(_semaphores, semaphoreId); waitSemaphores.push_back(semaphoreRef.Semaphore); } - auto& swapchainRef = GetResource(_swapchains, swapchainId); + const auto& swapchainRef = GetResource(_swapchains, swapchainId); VkPresentInfoKHR presentInfo{}; presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; @@ -2303,7 +2304,7 @@ VulkanContext::QueuePresent(uint32_t queueId, uint32_t swapchainId, uint32_t ima const auto& queueRef = GetResource(_queues, queueId); const VkResult result = vkQueuePresentKHR(queueRef.QueuePtr, &presentInfo); - if (result == VK_SUCCESS || VK_SUBOPTIMAL_KHR) + if (result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) { return; } diff --git a/src/backend/vulkan/VulkanContext.h b/src/backend/vulkan/VulkanContext.h index 22c0160..40778c7 100644 --- a/src/backend/vulkan/VulkanContext.h +++ b/src/backend/vulkan/VulkanContext.h @@ -312,7 +312,8 @@ class VulkanContext final : public IContext /*Per frame map of per pipeline layout to descriptor pool, we can allocate descriptor sets per pipeline layout*/ std::vector>> _pipelineLayoutToDescriptorPool; - const std::vector _validationLayers = { +#if _DEBUG + const std::vector _validationLayers{ "VK_LAYER_KHRONOS_validation", "VK_LAYER_GOOGLE_threading", "VK_LAYER_LUNARG_parameter_validation", @@ -320,16 +321,19 @@ class VulkanContext final : public IContext "VK_LAYER_LUNARG_core_validation", "VK_LAYER_GOOGLE_unique_objects", }; +#else + const std::vector _validationLayers{}; +#endif #if FOX_PLATFORM == FOX_PLATFORM_WINDOWS32 - const std::vector _instanceExtensionNames = { "VK_EXT_debug_utils", + const std::vector _instanceExtensionNames{ "VK_EXT_debug_utils", "VK_KHR_surface", "VK_KHR_win32_surface", "VK_KHR_external_semaphore_capabilities", VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME }; #elif FOX_PLATFORM == FOX_PLATFORM_LINUX - const std::vector _instanceExtensionNames = { + const std::vector _instanceExtensionNames{ "VK_EXT_debug_utils", "VK_KHR_surface", "VK_KHR_wayland_surface", From b0020405eba38c51c4677edc01ce093d80da50a7 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Mon, 3 Jun 2024 09:48:40 +0200 Subject: [PATCH 29/58] Fix linux build --- CMakeLists.txt | 29 ++++++++++--------- src/AtomicCounter.h | 2 +- src/DescriptorPool.h | 5 ++-- src/RICacheMap.h | 2 +- src/RIComponents.cpp | 2 +- src/RIContextVk.cpp | 2 +- src/RIContextVk.inl | 2 +- src/RICoreVk.inl | 2 +- src/RIFactoryVk.h | 2 +- src/RIFactoryVk.inl | 2 +- src/RingBufferManager.h | 4 +-- src/backend/vulkan/ResourceTransfer.cpp | 2 +- src/backend/vulkan/UtilsVK.h | 11 ++++++- src/backend/vulkan/VulkanContext.cpp | 2 +- src/backend/vulkan/VulkanContext.h | 1 + src/backend/vulkan/VulkanDevice.cpp | 8 ++--- src/backend/vulkan/VulkanDevice.h | 2 +- src/backend/vulkan/VulkanDevice10.cpp | 4 +-- src/backend/vulkan/VulkanDevice11.cpp | 4 +-- src/backend/vulkan/VulkanDevice11.h | 3 +- src/backend/vulkan/VulkanDevice12.cpp | 4 +-- src/backend/vulkan/VulkanDevice13.cpp | 4 +-- src/backend/vulkan/VulkanDevice2.cpp | 4 +-- src/backend/vulkan/VulkanDevice3.cpp | 4 +-- src/backend/vulkan/VulkanDevice4.cpp | 14 ++++----- src/backend/vulkan/VulkanDevice5.cpp | 14 ++++----- src/backend/vulkan/VulkanDevice6.cpp | 4 +-- src/backend/vulkan/VulkanDevice7.cpp | 4 +-- src/backend/vulkan/VulkanDevice8.cpp | 4 +-- src/backend/vulkan/VulkanDevice9.cpp | 4 +-- src/backend/vulkan/VulkanInstance.cpp | 9 ++---- ...RIRenderPassAttachmentsConversion.test.cpp | 2 +- tests/unit/vulkan/VkUtils.test.cpp | 2 +- 33 files changed, 86 insertions(+), 78 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1949fd8..a120fe6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,8 @@ add_subdirectory("thirdparty/VulkanMemoryAllocator") set(ENABLE_OPT 0)#disable optimizations for HLSL set(BUILD_SHARED_LIBS 0) add_subdirectory("thirdparty/glslang") + +if(BUILD_EXAMPLES) ## GLFW set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "GLFW_BUILD_EXAMPLES" FORCE) set(GLFW_BUILD_TESTS OFF CACHE BOOL "GLFW_BUILD_TESTS" FORCE) @@ -42,19 +44,18 @@ add_subdirectory("thirdparty/glfw") # GLM add_subdirectory("thirdparty/glm") # GLI -if(BUILD_EXAMPLES) - set(GLI_TEST_ENABLED OFF CACHE BOOL "" FORCE) - add_subdirectory("thirdparty/gli") - # TINYGLTF - set(TINYGLTF_HEADER_ONLY ON CACHE BOOL "" FORCE) - set(TINYGLTF_INSTALL OFF CACHE BOOL "" FORCE) - # Fetch tinygltf from GitHub - include(FetchContent) # once in the project to include the module - FetchContent_Declare( - tinygltf - GIT_REPOSITORY https://github.com/syoyo/tinygltf.git - GIT_TAG v2.8.19 - ) +set(GLI_TEST_ENABLED OFF CACHE BOOL "" FORCE) +add_subdirectory("thirdparty/gli") +# TINYGLTF +set(TINYGLTF_HEADER_ONLY ON CACHE BOOL "" FORCE) +set(TINYGLTF_INSTALL OFF CACHE BOOL "" FORCE) +# Fetch tinygltf from GitHub +include(FetchContent) # once in the project to include the module +FetchContent_Declare( +tinygltf +GIT_REPOSITORY https://github.com/syoyo/tinygltf.git +GIT_TAG v2.8.19 +) # Fetch the content and add it to your CMake project FetchContent_MakeAvailable(tinygltf) @@ -141,4 +142,4 @@ endif() if(BUILD_TESTS) add_subdirectory("tests") -endif() \ No newline at end of file +endif() diff --git a/src/AtomicCounter.h b/src/AtomicCounter.h index 1172d86..191fe33 100644 --- a/src/AtomicCounter.h +++ b/src/AtomicCounter.h @@ -2,7 +2,7 @@ #pragma once -#include "asserts.h" +#include "Asserts.h" #include diff --git a/src/DescriptorPool.h b/src/DescriptorPool.h index cb17891..d37d518 100644 --- a/src/DescriptorPool.h +++ b/src/DescriptorPool.h @@ -2,13 +2,12 @@ #pragma once -#include "asserts.h" +#include "Asserts.h" -#include "backend/vulkan/UtilsVK.h" +#include "backend/vulkan/UtilsVk.h" #include -#define VK_USE_PLATFORM_WIN32_KHR #include namespace Fox diff --git a/src/RICacheMap.h b/src/RICacheMap.h index 962c75e..ee2ce6f 100644 --- a/src/RICacheMap.h +++ b/src/RICacheMap.h @@ -2,7 +2,7 @@ #pragma once -#include "asserts.h" +#include "Asserts.h" #include diff --git a/src/RIComponents.cpp b/src/RIComponents.cpp index 8574158..7a83e4d 100644 --- a/src/RIComponents.cpp +++ b/src/RIComponents.cpp @@ -1,6 +1,6 @@ #include "RIComponents.h" -#include "RenderInterface/vulkan/UtilsVK.h" +#include "RenderInterface/vulkan/UtilsVk.h" namespace Fox { diff --git a/src/RIContextVk.cpp b/src/RIContextVk.cpp index 6cab522..f7c3417 100644 --- a/src/RIContextVk.cpp +++ b/src/RIContextVk.cpp @@ -1,7 +1,7 @@ // Copyright RedFox Studio 2022 #include "RIContextVk.h" -#include "ResourceTransfer.h" +#include "backend/vulkan/ResourceTransfer.h" #include namespace Fox diff --git a/src/RIContextVk.inl b/src/RIContextVk.inl index fc121f7..aa515d7 100644 --- a/src/RIContextVk.inl +++ b/src/RIContextVk.inl @@ -5,7 +5,7 @@ #if defined(FOX_USE_VULKAN) #include "RIContextVk.h" -#include "RenderInterface/vulkan/UtilsVK.h" +#include "RenderInterface/vulkan/UtilsVk.h" #include #include diff --git a/src/RICoreVk.inl b/src/RICoreVk.inl index 02bd46c..7a3fbdf 100644 --- a/src/RICoreVk.inl +++ b/src/RICoreVk.inl @@ -3,7 +3,7 @@ #pragma once #include "RICoreVk.h" -#include "UtilsVK.h" +#include "UtilsVk.h" #include #include diff --git a/src/RIFactoryVk.h b/src/RIFactoryVk.h index d17ec7a..155b428 100644 --- a/src/RIFactoryVk.h +++ b/src/RIFactoryVk.h @@ -9,7 +9,7 @@ #include "Core/memory/RingBufferManager.h" #include "Core/window/WindowBase.h" #include "DescriptorPool.h" -#include "UtilsVK.h" +#include "UtilsVk.h" #include #include diff --git a/src/RIFactoryVk.inl b/src/RIFactoryVk.inl index 3b73e0b..54e5952 100644 --- a/src/RIFactoryVk.inl +++ b/src/RIFactoryVk.inl @@ -10,7 +10,7 @@ #include "Core/utils/Filter.h" #include "Core/utils/Fox_Assert.h" #include "RenderInterface/vulkan/RIFactoryVk.h" -#include "RenderInterface/vulkan/UtilsVK.h" +#include "RenderInterface/vulkan/UtilsVk.h" namespace Fox { diff --git a/src/RingBufferManager.h b/src/RingBufferManager.h index f3d4391..90fc6f8 100644 --- a/src/RingBufferManager.h +++ b/src/RingBufferManager.h @@ -2,7 +2,7 @@ #pragma once -#include "asserts.h" +#include "Asserts.h" namespace Fox { @@ -19,7 +19,7 @@ struct RingBufferManager // Must receive the same number of pop with the same length as the number of time Push was called void Pop(uint32_t length) { - furyassert(length, MaxSize); + furyassert(length > MaxSize); #if defined(_DEBUG) if (!Full && Tail != Head) { diff --git a/src/backend/vulkan/ResourceTransfer.cpp b/src/backend/vulkan/ResourceTransfer.cpp index f0c9815..4156589 100644 --- a/src/backend/vulkan/ResourceTransfer.cpp +++ b/src/backend/vulkan/ResourceTransfer.cpp @@ -1,7 +1,7 @@ // Copyright RedFox Studio 2022 #include "ResourceTransfer.h" -#include "asserts.h" +#include "../../Asserts.h" #include namespace Fox diff --git a/src/backend/vulkan/UtilsVK.h b/src/backend/vulkan/UtilsVK.h index bfdc43e..2f8ec74 100644 --- a/src/backend/vulkan/UtilsVK.h +++ b/src/backend/vulkan/UtilsVK.h @@ -3,14 +3,23 @@ #pragma once #include "IContext.h" -#include "asserts.h" +#include "Asserts.h" +#if FOX_PLATFORM == FOX_PLATFORM_WINDOWS32 #define VK_USE_PLATFORM_WIN32_KHR +#elif FOX_PLATFORM == FOX_PLATFORM_LINUX +#define VK_USE_PLATFORM_XLIB_KHR +#else +#pragma error "Not supported" +#endif + + #include #include #include #include +#include #include #define VKFAILED(result) ((result != VK_SUCCESS ? true : false)) diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index c76728c..b8a0bee 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -4,7 +4,7 @@ #include "ResourceId.h" #include "ResourceTransfer.h" -#include "UtilsVK.h" +#include "UtilsVk.h" #include #include diff --git a/src/backend/vulkan/VulkanContext.h b/src/backend/vulkan/VulkanContext.h index 40778c7..c28510c 100644 --- a/src/backend/vulkan/VulkanContext.h +++ b/src/backend/vulkan/VulkanContext.h @@ -14,6 +14,7 @@ #include #include #include +#include namespace Fox { diff --git a/src/backend/vulkan/VulkanDevice.cpp b/src/backend/vulkan/VulkanDevice.cpp index 761ea89..f1c839a 100644 --- a/src/backend/vulkan/VulkanDevice.cpp +++ b/src/backend/vulkan/VulkanDevice.cpp @@ -1,8 +1,8 @@ // Copyright RedFox Studio 2022 #include "VulkanDevice.h" -#include "UtilsVK.h" -#include "asserts.h" +#include "UtilsVk.h" +#include "Asserts.h" #define VMA_IMPLEMENTATION #pragma warning(push) @@ -148,7 +148,7 @@ std::vector validationLayers) allocatorCreateInfo.pVulkanFunctions = &vma_vulkan_func; { - const VkResult result = vmaCreateAllocator(&allocatorCreateInfo, &VmaAllocator); + const VkResult result = vmaCreateAllocator(&allocatorCreateInfo, &VmaAllocatorObject); if (result != VK_SUCCESS) { // std::runtime_error("Failed to initialize VMA"); @@ -166,7 +166,7 @@ RIVulkanDevice::Deinit() furyassert(PhysicalDevice != nullptr); furyassert(Device != nullptr); - vmaDestroyAllocator(VmaAllocator); + vmaDestroyAllocator(VmaAllocatorObject); vkDestroyDevice(Device, nullptr); diff --git a/src/backend/vulkan/VulkanDevice.h b/src/backend/vulkan/VulkanDevice.h index 0ebaef6..a752ca9 100644 --- a/src/backend/vulkan/VulkanDevice.h +++ b/src/backend/vulkan/VulkanDevice.h @@ -42,7 +42,7 @@ class RIVulkanDevice VkPhysicalDevice PhysicalDevice{}; /* GPU chosen as the default device */ VkDevice Device{}; /* Logical device */ - VmaAllocator VmaAllocator; + VmaAllocator VmaAllocatorObject; VkPhysicalDeviceProperties DeviceProperties{}; /*Properties of the physical device*/ VkPhysicalDeviceMemoryProperties DeviceMemory{}; /*Properties about the physical device memory*/ diff --git a/src/backend/vulkan/VulkanDevice10.cpp b/src/backend/vulkan/VulkanDevice10.cpp index fa9eb73..89002ff 100644 --- a/src/backend/vulkan/VulkanDevice10.cpp +++ b/src/backend/vulkan/VulkanDevice10.cpp @@ -2,9 +2,9 @@ #include "VulkanDevice10.h" -#include "asserts.h" +#include "Asserts.h" -#include "UtilsVK.h" +#include "UtilsVk.h" namespace Fox { diff --git a/src/backend/vulkan/VulkanDevice11.cpp b/src/backend/vulkan/VulkanDevice11.cpp index e4ed023..5b6245d 100644 --- a/src/backend/vulkan/VulkanDevice11.cpp +++ b/src/backend/vulkan/VulkanDevice11.cpp @@ -2,9 +2,9 @@ #include "VulkanDevice11.h" -#include "asserts.h" +#include "Asserts.h" -#include "UtilsVK.h" +#include "UtilsVk.h" namespace Fox { diff --git a/src/backend/vulkan/VulkanDevice11.h b/src/backend/vulkan/VulkanDevice11.h index 337a388..c91d1c9 100644 --- a/src/backend/vulkan/VulkanDevice11.h +++ b/src/backend/vulkan/VulkanDevice11.h @@ -3,7 +3,7 @@ #pragma once #include "RIResource.h" -#include "UtilsVK.h" +#include "UtilsVk.h" #include "VulkanDevice10.h" #include @@ -11,6 +11,7 @@ #include #include #include +#include #include namespace Fox diff --git a/src/backend/vulkan/VulkanDevice12.cpp b/src/backend/vulkan/VulkanDevice12.cpp index bb57671..eaee419 100644 --- a/src/backend/vulkan/VulkanDevice12.cpp +++ b/src/backend/vulkan/VulkanDevice12.cpp @@ -2,9 +2,9 @@ #include "VulkanDevice12.h" -#include "asserts.h" +#include "Asserts.h" -#include "UtilsVK.h" +#include "UtilsVk.h" #include diff --git a/src/backend/vulkan/VulkanDevice13.cpp b/src/backend/vulkan/VulkanDevice13.cpp index 9c4a333..73da156 100644 --- a/src/backend/vulkan/VulkanDevice13.cpp +++ b/src/backend/vulkan/VulkanDevice13.cpp @@ -2,9 +2,9 @@ #include "VulkanDevice13.h" -#include "asserts.h" +#include "Asserts.h" -#include "UtilsVK.h" +#include "UtilsVk.h" namespace Fox { diff --git a/src/backend/vulkan/VulkanDevice2.cpp b/src/backend/vulkan/VulkanDevice2.cpp index 3f99b64..70ea3aa 100644 --- a/src/backend/vulkan/VulkanDevice2.cpp +++ b/src/backend/vulkan/VulkanDevice2.cpp @@ -2,8 +2,8 @@ #include "VulkanDevice2.h" -#include "UtilsVK.h" -#include "asserts.h" +#include "UtilsVk.h" +#include "Asserts.h" #include diff --git a/src/backend/vulkan/VulkanDevice3.cpp b/src/backend/vulkan/VulkanDevice3.cpp index 903c575..7472f9a 100644 --- a/src/backend/vulkan/VulkanDevice3.cpp +++ b/src/backend/vulkan/VulkanDevice3.cpp @@ -2,9 +2,9 @@ #include "VulkanDevice3.h" -#include "asserts.h" +#include "Asserts.h" -#include "UtilsVK.h" +#include "UtilsVk.h" namespace Fox { diff --git a/src/backend/vulkan/VulkanDevice4.cpp b/src/backend/vulkan/VulkanDevice4.cpp index a30ab5f..815d605 100644 --- a/src/backend/vulkan/VulkanDevice4.cpp +++ b/src/backend/vulkan/VulkanDevice4.cpp @@ -2,9 +2,9 @@ #include "VulkanDevice4.h" -#include "asserts.h" +#include "Asserts.h" -#include "UtilsVK.h" +#include "UtilsVk.h" namespace Fox { @@ -27,7 +27,7 @@ RIVulkanDevice4::CreateBufferHostVisible(uint32_t size, VkBufferUsageFlags usage RIVulkanBuffer buf; buf.IsMappable = true; - const VkResult result = vmaCreateBuffer(VmaAllocator, &bufferInfo, &allocInfo, &buf.Buffer, &buf.Allocation, nullptr); + const VkResult result = vmaCreateBuffer(VmaAllocatorObject, &bufferInfo, &allocInfo, &buf.Buffer, &buf.Allocation, nullptr); if (VKFAILED(result)) { throw std::runtime_error(VkUtils::VkErrorString(result)); @@ -53,7 +53,7 @@ RIVulkanDevice4::CreateBufferDeviceLocalTransferBit(uint32_t size, VkBufferUsage RIVulkanBuffer buf; - const VkResult result = vmaCreateBuffer(VmaAllocator, &bufferInfo, &allocInfo, &buf.Buffer, &buf.Allocation, nullptr); + const VkResult result = vmaCreateBuffer(VmaAllocatorObject, &bufferInfo, &allocInfo, &buf.Buffer, &buf.Allocation, nullptr); if (VKFAILED(result)) { throw std::runtime_error(VkUtils::VkErrorString(result)); @@ -67,7 +67,7 @@ RIVulkanDevice4::CreateBufferDeviceLocalTransferBit(uint32_t size, VkBufferUsage void RIVulkanDevice4::DestroyBuffer(const RIVulkanBuffer& buffer) { - vmaDestroyBuffer(VmaAllocator, buffer.Buffer, buffer.Allocation); + vmaDestroyBuffer(VmaAllocatorObject, buffer.Buffer, buffer.Allocation); _buffers.erase(_buffers.find(buffer)); } @@ -75,7 +75,7 @@ void* RIVulkanDevice4::MapBuffer(const RIVulkanBuffer& buffer) { void* gpuVirtualAddress{}; - const VkResult result = vmaMapMemory(VmaAllocator, buffer.Allocation, &gpuVirtualAddress); + const VkResult result = vmaMapMemory(VmaAllocatorObject, buffer.Allocation, &gpuVirtualAddress); if (VKFAILED(result)) { throw std::runtime_error(VkUtils::VkErrorString(result)); @@ -86,7 +86,7 @@ RIVulkanDevice4::MapBuffer(const RIVulkanBuffer& buffer) void RIVulkanDevice4::UnmapBuffer(const RIVulkanBuffer& buffer) { - vmaUnmapMemory(VmaAllocator, buffer.Allocation); + vmaUnmapMemory(VmaAllocatorObject, buffer.Allocation); } } \ No newline at end of file diff --git a/src/backend/vulkan/VulkanDevice5.cpp b/src/backend/vulkan/VulkanDevice5.cpp index 286b4e5..ddaab6a 100644 --- a/src/backend/vulkan/VulkanDevice5.cpp +++ b/src/backend/vulkan/VulkanDevice5.cpp @@ -2,9 +2,9 @@ #include "VulkanDevice5.h" -#include "asserts.h" +#include "Asserts.h" -#include "UtilsVK.h" +#include "UtilsVk.h" namespace Fox { @@ -37,7 +37,7 @@ RIVulkanDevice5::CreateImageDeviceLocal(uint32_t width, uint32_t height, uint32_ allocInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; RIVulkanImage image{}; - const VkResult result = vmaCreateImage(VmaAllocator, &imageInfo, &allocInfo, &image.Image, &image.Allocation, nullptr); + const VkResult result = vmaCreateImage(VmaAllocatorObject, &imageInfo, &allocInfo, &image.Image, &image.Allocation, nullptr); if (VKFAILED(result)) { throw std::runtime_error(VkUtils::VkErrorString(result)); @@ -77,7 +77,7 @@ RIVulkanDevice5::CreateImageHostVisible(uint32_t width, uint32_t height, uint32_ allocInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_HOST; RIVulkanImage image{}; - const VkResult result = vmaCreateImage(VmaAllocator, &imageInfo, &allocInfo, &image.Image, &image.Allocation, nullptr); + const VkResult result = vmaCreateImage(VmaAllocatorObject, &imageInfo, &allocInfo, &image.Image, &image.Allocation, nullptr); if (VKFAILED(result)) { throw std::runtime_error(VkUtils::VkErrorString(result)); @@ -97,7 +97,7 @@ RIVulkanDevice5::CreateImageHostVisible(uint32_t width, uint32_t height, uint32_ void RIVulkanDevice5::DestroyImage(const RIVulkanImage& image) { - vmaDestroyImage(VmaAllocator, image.Image, image.Allocation); + vmaDestroyImage(VmaAllocatorObject, image.Image, image.Allocation); _images.erase(_images.find(image)); } @@ -171,7 +171,7 @@ void* RIVulkanDevice5::MapImage(const RIVulkanImage& image) { void* gpuVirtualAddress{}; - const VkResult result = vmaMapMemory(VmaAllocator, image.Allocation, &gpuVirtualAddress); + const VkResult result = vmaMapMemory(VmaAllocatorObject, image.Allocation, &gpuVirtualAddress); if (VKFAILED(result)) { throw std::runtime_error(VkUtils::VkErrorString(result)); @@ -182,7 +182,7 @@ RIVulkanDevice5::MapImage(const RIVulkanImage& image) void RIVulkanDevice5::UnmapImage(const RIVulkanImage& image) { - vmaUnmapMemory(VmaAllocator, image.Allocation); + vmaUnmapMemory(VmaAllocatorObject, image.Allocation); } } \ No newline at end of file diff --git a/src/backend/vulkan/VulkanDevice6.cpp b/src/backend/vulkan/VulkanDevice6.cpp index 634acd1..7756a48 100644 --- a/src/backend/vulkan/VulkanDevice6.cpp +++ b/src/backend/vulkan/VulkanDevice6.cpp @@ -2,9 +2,9 @@ #include "VulkanDevice6.h" -#include "asserts.h" +#include "Asserts.h" -#include "UtilsVK.h" +#include "UtilsVk.h" namespace Fox { diff --git a/src/backend/vulkan/VulkanDevice7.cpp b/src/backend/vulkan/VulkanDevice7.cpp index 0a9769d..e9773de 100644 --- a/src/backend/vulkan/VulkanDevice7.cpp +++ b/src/backend/vulkan/VulkanDevice7.cpp @@ -2,9 +2,9 @@ #include "VulkanDevice7.h" -#include "asserts.h" +#include "Asserts.h" -#include "UtilsVK.h" +#include "UtilsVk.h" namespace Fox { diff --git a/src/backend/vulkan/VulkanDevice8.cpp b/src/backend/vulkan/VulkanDevice8.cpp index 8c8107d..5b8906a 100644 --- a/src/backend/vulkan/VulkanDevice8.cpp +++ b/src/backend/vulkan/VulkanDevice8.cpp @@ -2,9 +2,9 @@ #include "VulkanDevice8.h" -#include "asserts.h" +#include "Asserts.h" -#include "UtilsVK.h" +#include "UtilsVk.h" namespace Fox { diff --git a/src/backend/vulkan/VulkanDevice9.cpp b/src/backend/vulkan/VulkanDevice9.cpp index c6e4cfa..f297553 100644 --- a/src/backend/vulkan/VulkanDevice9.cpp +++ b/src/backend/vulkan/VulkanDevice9.cpp @@ -2,9 +2,9 @@ #include "VulkanDevice9.h" -#include "asserts.h" +#include "Asserts.h" -#include "UtilsVK.h" +#include "UtilsVk.h" namespace Fox { diff --git a/src/backend/vulkan/VulkanInstance.cpp b/src/backend/vulkan/VulkanInstance.cpp index 8389830..d67869e 100644 --- a/src/backend/vulkan/VulkanInstance.cpp +++ b/src/backend/vulkan/VulkanInstance.cpp @@ -2,8 +2,8 @@ #include "VulkanInstance.h" -#include "UtilsVK.h" -#include "asserts.h" +#include "UtilsVk.h" +#include "Asserts.h" #define VOLK_IMPLEMENTATION // defined only once #include "volk.h" @@ -77,15 +77,12 @@ RIVulkanInstance::CreateSurfaceFromWindow(const WindowData& windowData, VkSurfac } #elif defined(__linux__) { - Fox::WindowPlatformLinuxSDL* win = static_cast(window); - furyassert(win); - VkXlibSurfaceCreateInfoKHR createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; createInfo.pNext = NULL; createInfo.dpy = windowData._display; createInfo.window = windowData._window; - const VkResult result = vkCreateXlibSurfaceKHR(_vkInstance, &createInfo, NULL, surface); + const VkResult result = vkCreateXlibSurfaceKHR(Instance, &createInfo, NULL, surface); if (VKFAILED(result)) { return result; diff --git a/tests/unit/vulkan/RIRenderPassAttachmentsConversion.test.cpp b/tests/unit/vulkan/RIRenderPassAttachmentsConversion.test.cpp index bba353c..a8b0f0c 100644 --- a/tests/unit/vulkan/RIRenderPassAttachmentsConversion.test.cpp +++ b/tests/unit/vulkan/RIRenderPassAttachmentsConversion.test.cpp @@ -1,5 +1,5 @@ #include "IContext.h" -#include "backend/vulkan/UtilsVK.h" +#include "backend/vulkan/UtilsVk.h" #include "backend/vulkan/VulkanContext.h" #include diff --git a/tests/unit/vulkan/VkUtils.test.cpp b/tests/unit/vulkan/VkUtils.test.cpp index c2ef113..a34639b 100644 --- a/tests/unit/vulkan/VkUtils.test.cpp +++ b/tests/unit/vulkan/VkUtils.test.cpp @@ -1,4 +1,4 @@ -#include "backend/vulkan/UtilsVK.h" +#include "backend/vulkan/UtilsVk.h" #include From 344f721382f6a1f68c9cab6fa408fef4826cd6d8 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Tue, 4 Jun 2024 15:44:24 +0200 Subject: [PATCH 30/58] fixed some warning on windows --- include/IContext.h | 2 + src/ResourceId.h | 18 +++ src/backend/vulkan/ResourceTransfer.cpp | 2 +- src/backend/vulkan/VulkanContext.cpp | 204 +++++++++--------------- src/backend/vulkan/VulkanDevice11.cpp | 1 - src/backend/vulkan/VulkanDevice5.cpp | 1 - src/backend/vulkan/VulkanDevice6.cpp | 1 - 7 files changed, 92 insertions(+), 137 deletions(-) diff --git a/include/IContext.h b/include/IContext.h index 26a92bd..e0293bd 100644 --- a/include/IContext.h +++ b/include/IContext.h @@ -8,7 +8,9 @@ #include #include +#ifndef NOMINMAX #define NOMINMAX +#endif #if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) #define WIN32_LEAN_AND_MEAN diff --git a/src/ResourceId.h b/src/ResourceId.h index e6dcac8..ba539df 100644 --- a/src/ResourceId.h +++ b/src/ResourceId.h @@ -2,7 +2,9 @@ #pragma once +#include #include +#include namespace Fox { @@ -30,6 +32,22 @@ class ResourceId _data.Decompose.Second = second; _data.Decompose.Value = value; }; + ResourceId(uint8_t first, uint8_t second, uint32_t value) + { + _data.Decompose.First = first; + _data.Decompose.Second = second; + _data.Decompose.Value = static_cast(value); + + assert(value < std::numeric_limits().max()); + }; + ResourceId(uint8_t first, uint8_t second, size_t value) + { + _data.Decompose.First = first; + _data.Decompose.Second = second; + _data.Decompose.Value = static_cast(value); + + assert(value < std::numeric_limits().max()); + }; uint16_t Value() const { return _data.Decompose.Value; }; diff --git a/src/backend/vulkan/ResourceTransfer.cpp b/src/backend/vulkan/ResourceTransfer.cpp index 4156589..c561ffa 100644 --- a/src/backend/vulkan/ResourceTransfer.cpp +++ b/src/backend/vulkan/ResourceTransfer.cpp @@ -94,7 +94,7 @@ CResourceTransfer::CResourceTransfer(VkCommandBuffer command) : _command(command // } void -CResourceTransfer::CopyMipMap(VkBuffer sourceBuffer, VkImage destination, VkExtent2D extent, uint32_t mipIndex, uint32_t internalOffset, size_t sourceOffset) +CResourceTransfer::CopyMipMap(VkBuffer sourceBuffer, VkImage destination, VkExtent2D extent, uint32_t mipIndex, uint32_t, size_t sourceOffset) { VkBufferImageCopy region{}; { diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index b8a0bee..b48fd62 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -12,7 +12,15 @@ #include // Thirdparty -#pragma warning(push, 0) +#pragma warning(push) +#pragma warning(disable : 4996) +#pragma warning(disable : 4458) +#pragma warning(disable : 4244) +#pragma warning(disable : 4389) +#pragma warning(disable : 4457) +#pragma warning(disable : 4456) +#pragma warning(disable : 4267) +#pragma warning(disable : 4702) #include "glslang/Include/glslang_c_interface.h" #include #include @@ -84,8 +92,12 @@ GenIdentifier() a = (a ^ 61) ^ (a >> 16); return a; }; - static size_t counter = 0; - const auto value = hash(counter++); + static uint32_t counter{ }; + auto value{ hash(counter++) }; + while (value == 0) + { + value = hash(counter++); + } furyassert(value != 0); // must not be 0 return (uint8_t)value; } @@ -112,7 +124,6 @@ AllocResource(std::array& container) furyassert(0);//Possible memory leak, or bad usage of allocations throw std::runtime_error("Rendering context run out of resource to allocate!"); - return {}; } DRenderPassAttachments @@ -120,8 +131,8 @@ VulkanContext::_createGenericRenderPassAttachments(const DFramebufferAttachments { DRenderPassAttachments rp; - const auto attachmentCount = DFramebufferAttachments::MAX_ATTACHMENTS - std::count(att.RenderTargets.begin(), att.RenderTargets.end(), NULL); - for (size_t i = 0; i < attachmentCount; i++) + const auto attachmentCount = DFramebufferAttachments::MAX_ATTACHMENTS - std::count(att.RenderTargets.begin(), att.RenderTargets.end(), (uint32_t)0); + for (int64_t i = 0; i < attachmentCount; i++) { const auto& renderTargetRef = GetResource(_renderTargets, att.RenderTargets[i]); @@ -163,7 +174,7 @@ VulkanContext::_createGenericRenderPassAttachmentsFromPipelineAttachments(const DRenderPassAttachments rp; const auto attachmentCount = DFramebufferAttachments::MAX_ATTACHMENTS - std::count(att.RenderTargets.begin(), att.RenderTargets.end(), EFormat::INVALID); - for (size_t i = 0; i < attachmentCount; i++) + for (uint32_t i = 0; i < attachmentCount; i++) { DRenderPassAttachment o(att.RenderTargets[i], ESampleBit::COUNT_1_BIT, @@ -266,7 +277,7 @@ VulkanContext::_initializeInstance() VKAPI_ATTR VkBool32 VKAPI_CALL VulkanContext::_vulkanDebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, -VkDebugUtilsMessageTypeFlagsEXT messageType, +VkDebugUtilsMessageTypeFlagsEXT , const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) { @@ -309,13 +320,17 @@ VulkanContext::_initializeDebugger() void VulkanContext::_initializeVersion() { - auto FN_vkEnumerateInstanceVersion = PFN_vkEnumerateInstanceVersion(vkGetInstanceProcAddr(nullptr, "vkEnumerateInstanceVersion")); if (vkEnumerateInstanceVersion == nullptr) { - Warning("Failed to vkGetInstanceProcAddr for vkEnumerateInstanceVersion"); + // Manually getting function + vkEnumerateInstanceVersion = PFN_vkEnumerateInstanceVersion(vkGetInstanceProcAddr(nullptr, "vkEnumerateInstanceVersion")); } - else + + if (vkEnumerateInstanceVersion == nullptr) { + Warning("Failed to vkGetInstanceProcAddr for vkEnumerateInstanceVersion"); + } + uint32_t instanceVersion = VK_API_VERSION_1_0; const VkResult result = vkEnumerateInstanceVersion(&instanceVersion); if (VKFAILED(result)) @@ -334,7 +349,6 @@ VulkanContext::_initializeVersion() const std::string out = "Vulkan version:" + std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(patch); Log(out); } - } } void @@ -484,7 +498,6 @@ VulkanContext::CompileNativeShader(const std::vector& blob, std:: // Create glslang compiler const char* shaderSource{ reinterpret_cast(blob.data()) }; const int l{ (int)blob.size() }; - const EShMessages controls = EShMsgDefault; glslang::TShader* shader(new glslang::TShader(language)); shader->setStringsWithLengths(&shaderSource, &l, 1); @@ -509,83 +522,6 @@ VulkanContext::CompileNativeShader(const std::vector& blob, std:: delete program; delete shader; glslang::FinalizeProcess(); - // - // const glslang_input_t input = { - // .language = GLSLANG_SOURCE_GLSL, - // .stage = GLSLANG_STAGE_VERTEX, - // .client = GLSLANG_CLIENT_VULKAN, - // .client_version = GLSLANG_TARGET_VULKAN_1_2, - // .target_language = GLSLANG_TARGET_SPV, - // .target_language_version = GLSLANG_TARGET_SPV_1_3, - // .code = shaderSource, - // .default_version = 100, - // .default_profile = GLSLANG_NO_PROFILE, - // .force_default_version_and_profile = false, - // .forward_compatible = false, - // .messages = GLSLANG_MSG_DEFAULT_BIT, - // .resource = GetDefaultResources(); - // }; - - //// Set up shader options - // TBuiltInResource resources = {}; - // resources.maxLights = 32; - // resources.maxClipPlanes = 6; - // resources.maxTextureUnits = 32; - // resources.maxTextureCoords = 32; - // resources.maxVertexAttribs = 64; - // resources.maxVertexUniformComponents = 4096; - // resources.maxVaryingFloats = 64; - // resources.maxVertexTextureImageUnits = 32; - // resources.maxCombinedTextureImageUnits = 80; - // resources.maxTextureImageUnits = 32; - // resources.maxFragmentUniformComponents = 4096; - // resources.maxDrawBuffers = 32; - // resources.maxVertexUniformVectors = 128; - // resources.maxVaryingVectors = 8; - // resources.maxFragmentUniformVectors = 16; - // resources.maxVertexOutputVectors = 16; - // resources.maxFragmentInputVectors = 15; - - //// Compile the shader - // shader.setEnvInput(glslang::EShSourceGlsl, language, glslang::EShClientVulkan, 110); - // shader.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_2); - // shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_0); - - //// if (!shader.preprocess(&resources, 110, EProfile::ECompatibilityProfile, false, true, EsHM, &input)) - //// { - //// // use glslang_shader_get_info_log() and glslang_shader_get_info_debug_log() - //// } - - // if (!shader.parse(&resources, 110, false, EShMsgDefault)) - // { - // errorMgs = shader.getInfoLog(); - // // std::cerr << "Failed to parse shader:\n" << shader.getInfoLog() << std::endl; - // glslang::FinalizeProcess(); - // return false; - // } - - // glslang::TProgram program; - // program.addShader(&shader); - - // if (!program.link(EShMsgDefault)) - // { - // errorMgs = program.getInfoLog(); - // glslang::FinalizeProcess(); - // return false; - // } - - // std::vector outSpirv; - ///*glslang::GlslangToSpv(program.getIntermediate(language), outSpirv);*/ - - // spv::SpvBuildLogger logger; - // glslang::TIntermediate* intermediate{ program.getIntermediate(language) }; - // glslang::GlslangToSpv(*intermediate, outSpirv, &logger, nullptr); - - //// Clean up - // glslang::FinalizeProcess(); - - // outShader.resize(outSpirv.size()); - // memcpy(outShader.data(), outSpirv.data(), outSpirv.size() * sizeof(unsigned int)); return true; } @@ -630,16 +566,18 @@ VulkanContext::_createSwapchain(DSwapchainVulkan& swapchain, const WindowData* w } // Find presentable graphics queue + /* { uint32_t queueIndexCount[16]{}; const auto foundGraphicsQueueId{ VkUtils::findQueueWithFlags( - &swapchain.QueueFamilyIndex, &swapchain.QueueIndex, VK_QUEUE_GRAPHICS_BIT, Device.QueueFamilies.data(), Device.QueueFamilies.size(), queueIndexCount) }; + &swapchain.QueueFamilyIndex, &swapchain.QueueIndex, VK_QUEUE_GRAPHICS_BIT, Device.QueueFamilies.data(), (uint32_t)Device.QueueFamilies.size(), queueIndexCount) }; const bool supportPresentation{ Device.SurfaceSupportPresentationOnQueueFamilyIndex(surface, swapchain.QueueFamilyIndex) }; if (!supportPresentation) { throw std::runtime_error("Vulkan graphics queue does not support presentation to this surface!"); } } + */ // Query formats present mode and capabilities const auto formats = Device.GetSurfaceFormats(surface); @@ -686,7 +624,7 @@ VulkanContext::_createSwapchain(DSwapchainVulkan& swapchain, const WindowData* w if (vkSwapchain != NULL) { const auto swapchainImages = Device.GetSwapchainImages(vkSwapchain); - swapchain.ImagesCount = swapchainImages.size(); + swapchain.ImagesCount = (uint32_t)swapchainImages.size(); for (size_t i = 0; i < swapchainImages.size(); i++) { swapchain.ImagesId[i] = @@ -768,21 +706,21 @@ VulkanContext::SwapchainHasValidSurface(SwapchainId swapchainId) // Must destroy all framebuffers that reference this render target @TODO find a better algorithm without iterating over the array multiple times const auto referenceCount = std::count_if(_framebuffers.begin(), _framebuffers.end(), [renderTargetId](const DFramebufferVulkan& fbo) { - for (size_t i = 0; i < DFramebufferAttachments::MAX_ATTACHMENTS; i++) + for (uint32_t j = 0; j < DFramebufferAttachments::MAX_ATTACHMENTS; j++) { - if (fbo.Attachments.RenderTargets[i] == renderTargetId) + if (fbo.Attachments.RenderTargets[j] == renderTargetId) { return true; } } return false; }); - for (uint32_t i = 0; i < referenceCount; i++) + for (uint32_t j = 0; j < referenceCount; j++) { auto foundFbo = std::find_if(_framebuffers.begin(), _framebuffers.end(), [renderTargetId](const DFramebufferVulkan& fbo) { - for (size_t i = 0; i < DFramebufferAttachments::MAX_ATTACHMENTS; i++) + for (uint32_t k = 0; k < DFramebufferAttachments::MAX_ATTACHMENTS; k++) { - if (fbo.Attachments.RenderTargets[i] == renderTargetId) + if (fbo.Attachments.RenderTargets[k] == renderTargetId) { return true; } @@ -819,7 +757,7 @@ VulkanContext::SwapchainHasValidSurface(SwapchainId swapchainId) // Recreate images and RTs { const auto swapchainImages = Device.GetSwapchainImages(swapchain.Swapchain); - swapchain.ImagesCount = swapchainImages.size(); + swapchain.ImagesCount = (uint32_t)swapchainImages.size(); for (size_t i = 0; i < swapchainImages.size(); i++) { swapchain.ImagesId[i] = @@ -957,21 +895,21 @@ VulkanContext::DestroySwapchain(SwapchainId swapchainId) // Must destroy all framebuffers that reference this render target @TODO find a better algorithm without iterating over the array multiple times const auto referenceCount = std::count_if(_framebuffers.begin(), _framebuffers.end(), [renderTargetId](const DFramebufferVulkan& fbo) { - for (size_t i = 0; i < DFramebufferAttachments::MAX_ATTACHMENTS; i++) + for (size_t j = 0; j < DFramebufferAttachments::MAX_ATTACHMENTS; j++) { - if (fbo.Attachments.RenderTargets[i] == renderTargetId) + if (fbo.Attachments.RenderTargets[j] == renderTargetId) { return true; } } return false; }); - for (uint32_t i = 0; i < referenceCount; i++) + for (uint32_t j = 0; j < referenceCount; j++) { auto foundFbo = std::find_if(_framebuffers.begin(), _framebuffers.end(), [renderTargetId](const DFramebufferVulkan& fbo) { - for (size_t i = 0; i < DFramebufferAttachments::MAX_ATTACHMENTS; i++) + for (size_t k = 0; k < DFramebufferAttachments::MAX_ATTACHMENTS; k++) { - if (fbo.Attachments.RenderTargets[i] == renderTargetId) + if (fbo.Attachments.RenderTargets[k] == renderTargetId) { return true; } @@ -999,7 +937,7 @@ VulkanContext::FindQueue(EQueueType queueType) uint32_t queueIndex{}; const uint32_t vkFlags{ VkUtils::convertQueueTypeToVkFlags(queueType) }; - const bool found{ VkUtils::findQueueWithFlags(&familyIndex, &queueIndex, vkFlags, Device.QueueFamilies.data(), Device.QueueFamilies.size(), _queueFamilyIndexCreatedCount.data()) }; + const bool found{ VkUtils::findQueueWithFlags(&familyIndex, &queueIndex, vkFlags, Device.QueueFamilies.data(), (uint32_t)Device.QueueFamilies.size(), _queueFamilyIndexCreatedCount.data()) }; if (!found) { @@ -1210,7 +1148,7 @@ VulkanContext::CreateImage(EFormat format, uint32_t width, uint32_t height, uint } // Create default sampler - image.Sampler = Device.CreateSampler(VK_FILTER_NEAREST, VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT, 0, mipMapCount, VK_SAMPLER_MIPMAP_MODE_NEAREST, true, 16); + image.Sampler = Device.CreateSampler(VK_FILTER_NEAREST, VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT, (float)0, (float)mipMapCount, VK_SAMPLER_MIPMAP_MODE_NEAREST, true, 16); return *ResourceId(EResourceType::IMAGE, image.Id, index); } @@ -1280,8 +1218,6 @@ VulkanContext::CreateShader(const ShaderSource& source) void VulkanContext::_createShader(const ShaderSource& source, DShaderVulkan& shader) { - constexpr uint32_t MAX_SETS_PER_POOL = 100; // Temporary, should not have a limit pool of pools - shader.VertexLayout = source.VertexLayout; shader.VertexStride = source.VertexStride; shader.ColorAttachments = source.ColorAttachments; @@ -1334,7 +1270,7 @@ VulkanContext::CreateSampler(uint32_t minLod, uint32_t maxLod) const auto index = AllocResource(_samplers); DSamplerVulkan& samplerRef = _samplers.at(index); - samplerRef.Sampler = Device.CreateSampler(VkFilter::VK_FILTER_LINEAR, VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT, minLod, maxLod, VK_SAMPLER_MIPMAP_MODE_LINEAR, true, 16); + samplerRef.Sampler = Device.CreateSampler(VkFilter::VK_FILTER_LINEAR, VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT, (float)minLod, (float)maxLod, VK_SAMPLER_MIPMAP_MODE_LINEAR, true, 16); return *ResourceId(EResourceType::SAMPLER, samplerRef.Id, index); } @@ -1424,18 +1360,18 @@ VulkanContext::CreateRootSignature(const ShaderLayout& layout) uint32_t imageInfoCount{}; uint32_t bufferInfoCount{}; - for (const auto index : rootSignature.SetsBindings[i]) + for (const auto bindingIndex : rootSignature.SetsBindings[i]) { - furyassert(index.second.Count < 8196); + furyassert(bindingIndex.second.Count < 8196); - const uint32_t descriptorCount = std::max(1u, index.second.Count); + const uint32_t descriptorCount = std::max(1u, bindingIndex.second.Count); VkWriteDescriptorSet* writeSet = &write[writeSetCount++]; writeSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; writeSet->pNext = NULL; writeSet->descriptorCount = descriptorCount; - const ShaderDescriptorBindings& bindingDesc = index.second; + const ShaderDescriptorBindings& bindingDesc = bindingIndex.second; switch (bindingDesc.StorageType) { case EBindingType::STORAGE_BUFFER_OBJECT: @@ -1462,7 +1398,7 @@ VulkanContext::CreateRootSignature(const ShaderLayout& layout) writeSet->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; writeSet->pImageInfo = &imageInfo[imageInfoCount]; - for (uint32_t i = 0; i < descriptorCount; i++) + for (uint32_t j = 0; j < descriptorCount; j++) { VkDescriptorImageInfo& img = imageInfo[imageInfoCount++]; img.imageView = _emptyImage->View; @@ -1476,7 +1412,7 @@ VulkanContext::CreateRootSignature(const ShaderLayout& layout) writeSet->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; writeSet->pImageInfo = &imageInfo[imageInfoCount]; - for (uint32_t i = 0; i < descriptorCount; i++) + for (uint32_t j = 0; j < descriptorCount; j++) { VkDescriptorImageInfo& img = imageInfo[imageInfoCount++]; img.imageView = 0; @@ -1488,7 +1424,7 @@ VulkanContext::CreateRootSignature(const ShaderLayout& layout) } writeSet->dstArrayElement = 0; - writeSet->dstBinding = index.first; + writeSet->dstBinding = bindingIndex.first; writeSet->dstSet = rootSignature.EmptySet[i]; } vkUpdateDescriptorSets(Device.Device, writeSetCount, write.data(), 0, nullptr); @@ -1588,18 +1524,18 @@ VulkanContext::CreateDescriptorSets(uint32_t rootSignatureId, EDescriptorFrequen uint32_t imageInfoCount{}; uint32_t bufferInfoCount{}; - for (const auto index : setBinding) + for (const auto bindingIndex : setBinding) { - furyassert(index.second.Count < 8196); + furyassert(bindingIndex.second.Count < 8196); - const uint32_t descriptorCount = std::max(1u, index.second.Count); + const uint32_t descriptorCount = std::max(1u, bindingIndex.second.Count); VkWriteDescriptorSet* writeSet = &write[writeSetCount++]; writeSet->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; writeSet->pNext = NULL; writeSet->descriptorCount = descriptorCount; - const ShaderDescriptorBindings& bindingDesc = index.second; + const ShaderDescriptorBindings& bindingDesc = bindingIndex.second; switch (bindingDesc.StorageType) { case EBindingType::STORAGE_BUFFER_OBJECT: @@ -1652,7 +1588,7 @@ VulkanContext::CreateDescriptorSets(uint32_t rootSignatureId, EDescriptorFrequen } writeSet->dstArrayElement = 0; - writeSet->dstBinding = index.first; + writeSet->dstBinding = bindingIndex.first; writeSet->dstSet = set; } vkUpdateDescriptorSets(Device.Device, writeSetCount, write.data(), 0, nullptr); @@ -1724,15 +1660,15 @@ VulkanContext::UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t paramCount writeSet->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE; writeSet->pImageInfo = &imageInfo[imageInfoCount]; - for (uint32_t i = 0; i < descriptorCount; i++) + for (uint32_t j = 0; j < descriptorCount; j++) { VkDescriptorImageInfo& img = imageInfo[imageInfoCount++]; - const auto resourceType{ static_cast(ResourceId(param->Textures[i]).First()) }; + const auto resourceType{ static_cast(ResourceId(param->Textures[j]).First()) }; switch (resourceType) { case EResourceType::IMAGE: { - const DImageVulkan& imageRef = GetResource(_images, param->Textures[i]); + const DImageVulkan& imageRef = GetResource(_images, param->Textures[j]); img.imageView = imageRef.View; img.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; img.sampler = NULL; @@ -1741,7 +1677,7 @@ VulkanContext::UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t paramCount case EResourceType::RENDER_TARGET: { const DRenderTargetVulkan& imageRef = - GetResource(_renderTargets, param->Textures[i]); + GetResource(_renderTargets, param->Textures[j]); img.imageView = imageRef.View; img.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; img.sampler = NULL; @@ -1759,10 +1695,10 @@ VulkanContext::UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t paramCount writeSet->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; writeSet->pImageInfo = &imageInfo[imageInfoCount]; - for (uint32_t i = 0; i < descriptorCount; i++) + for (uint32_t j = 0; j < descriptorCount; j++) { VkDescriptorImageInfo& img = imageInfo[imageInfoCount++]; - const DSamplerVulkan& samplerRef = GetResource(_samplers, param->Samplers[i]); + const DSamplerVulkan& samplerRef = GetResource(_samplers, param->Samplers[j]); img.imageView = 0; img.imageLayout = VK_IMAGE_LAYOUT_UNDEFINED; img.sampler = samplerRef.Sampler; @@ -1789,12 +1725,12 @@ VulkanContext::_createFramebuffer(const DFramebufferAttachments& attachments) const auto vkRenderPass = _createRenderPass(rpAttachments); // Extrapolate all the renderTargetRef views - const auto depthAttachmentCount = (uint32_t)(attachments.DepthStencil != 0); - const auto attachmentCount = DFramebufferAttachments::MAX_ATTACHMENTS - std::count(attachments.RenderTargets.begin(), attachments.RenderTargets.end(), NULL) + depthAttachmentCount; + const uint32_t depthAttachmentCount = (uint32_t)(attachments.DepthStencil != 0); + const int64_t attachmentCount = DFramebufferAttachments::MAX_ATTACHMENTS - std::count(attachments.RenderTargets.begin(), attachments.RenderTargets.end(), (uint32_t)0) + depthAttachmentCount; furyassert(attachmentCount > 0); // Must have at least one attachment std::vector imageViewsAttachments; - imageViewsAttachments.resize(attachmentCount); + imageViewsAttachments.resize((size_t)attachmentCount); { // First attachment must always exists @@ -1803,7 +1739,7 @@ VulkanContext::_createFramebuffer(const DFramebufferAttachments& attachments) framebufferRef.Height = renderTargetRef.Image.Height; } - for (size_t i = 0; i < attachmentCount - depthAttachmentCount; i++) + for (uint32_t i = 0; i < attachmentCount - depthAttachmentCount; i++) { furyassert(attachments.RenderTargets[i] != NULL); const auto& renderTargetRef = GetResource(_renderTargets, attachments.RenderTargets[i]); @@ -2068,14 +2004,16 @@ VulkanContext::SetScissor(uint32_t commandBufferId, uint32_t x, uint32_t y, uint furyassert(commandBufferRef.IsRecording); // Must be in recording state furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass - furyassert(x + width <= std::numeric_limits().max()); // sum must not overflow int32_t - furyassert(y + height <= std::numeric_limits().max()); // sum must not overflow int32_t + furyassert((int32_t)(x + width) <= std::numeric_limits().max()); // sum must not overflow int32_t + furyassert((int32_t)(y + height) <= std::numeric_limits().max()); // sum must not overflow int32_t auto areRect2dEqual = [](const VkRect2D& a, const VkRect2D& b) { return a.extent.width == b.extent.width && a.extent.height == b.extent.height && a.offset.x == b.offset.x && a.offset.y == b.offset.y; }; + furyassert(x < std::numeric_limits().max()); + furyassert(y < std::numeric_limits().max()); - VkRect2D rect{ x, y, width, height }; + VkRect2D rect{ (int32_t)x, (int32_t)y, width, height }; if (!areRect2dEqual(commandBufferRef.CurrentScissor, rect)) { commandBufferRef.CurrentScissor = rect; diff --git a/src/backend/vulkan/VulkanDevice11.cpp b/src/backend/vulkan/VulkanDevice11.cpp index 5b6245d..c467569 100644 --- a/src/backend/vulkan/VulkanDevice11.cpp +++ b/src/backend/vulkan/VulkanDevice11.cpp @@ -228,7 +228,6 @@ RIDescriptorPoolManager* RIVulkanDevice11::CreateDescriptorPool2(const std::vector& poolDimensions, uint32_t maxSets) { furyassert(0); - VkDescriptorPool descriptorPool = CreateDescriptorPool(poolDimensions, maxSets); RIDescriptorPoolManager* pool = new RIDescriptorPoolManager(Device, poolDimensions, maxSets); return pool; } diff --git a/src/backend/vulkan/VulkanDevice5.cpp b/src/backend/vulkan/VulkanDevice5.cpp index ddaab6a..f264027 100644 --- a/src/backend/vulkan/VulkanDevice5.cpp +++ b/src/backend/vulkan/VulkanDevice5.cpp @@ -121,7 +121,6 @@ RIVulkanDevice5::CreateImageView_DEPRECATED(VkFormat format, const RIVulkanImage if (VKFAILED(result)) { throw std::runtime_error(VkUtils::VkErrorString(result)); - return nullptr; } } furyassert(imageView); diff --git a/src/backend/vulkan/VulkanDevice6.cpp b/src/backend/vulkan/VulkanDevice6.cpp index 7756a48..135ecd4 100644 --- a/src/backend/vulkan/VulkanDevice6.cpp +++ b/src/backend/vulkan/VulkanDevice6.cpp @@ -39,7 +39,6 @@ RIVulkanDevice6::CreateSampler(VkFilter minFilter, VkFilter magFilter, VkSampler if (VKFAILED(result)) { throw std::runtime_error(VkUtils::VkErrorString(result)); - return nullptr; } } From b227951c58a61e98d919fe5a2def7cdba4bc5ed4 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Sat, 8 Jun 2024 15:25:19 +0200 Subject: [PATCH 31/58] Naming fix on linux --- src/{asserts.h => Asserts.h} | 0 src/backend/vulkan/{UtilsVK.h => UtilsVk.h} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/{asserts.h => Asserts.h} (100%) rename src/backend/vulkan/{UtilsVK.h => UtilsVk.h} (100%) diff --git a/src/asserts.h b/src/Asserts.h similarity index 100% rename from src/asserts.h rename to src/Asserts.h diff --git a/src/backend/vulkan/UtilsVK.h b/src/backend/vulkan/UtilsVk.h similarity index 100% rename from src/backend/vulkan/UtilsVK.h rename to src/backend/vulkan/UtilsVk.h From fc21659c17722d47e2aa5b1a5b6fe2ca68d8f260 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Sat, 8 Jun 2024 15:53:53 +0200 Subject: [PATCH 32/58] changed include order for linux compilation --- src/backend/vulkan/VulkanContext.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/backend/vulkan/VulkanContext.h b/src/backend/vulkan/VulkanContext.h index c28510c..ce48646 100644 --- a/src/backend/vulkan/VulkanContext.h +++ b/src/backend/vulkan/VulkanContext.h @@ -4,17 +4,18 @@ #include "IContext.h" +#include "VulkanInstance.h"//This first because it defines macros for vulkan platform + #include "DescriptorPool.h" #include "RingBufferManager.h" #include "VulkanDevice13.h" -#include "VulkanInstance.h" #include #include #include +#include #include #include -#include namespace Fox { From 845336f27f2ea148f3acb24de0d02e906d643569 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Sat, 8 Jun 2024 16:27:38 +0200 Subject: [PATCH 33/58] Linux fixes --- include/IContext.h | 1 + src/backend/vulkan/UtilsVk.h | 8 ++++---- src/backend/vulkan/VulkanContext.cpp | 7 ++++--- src/backend/vulkan/VulkanDevice13.h | 1 + 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/include/IContext.h b/include/IContext.h index e0293bd..043bb0e 100644 --- a/include/IContext.h +++ b/include/IContext.h @@ -7,6 +7,7 @@ #include #include #include +#include #ifndef NOMINMAX #define NOMINMAX diff --git a/src/backend/vulkan/UtilsVk.h b/src/backend/vulkan/UtilsVk.h index 2f8ec74..855ed30 100644 --- a/src/backend/vulkan/UtilsVk.h +++ b/src/backend/vulkan/UtilsVk.h @@ -5,12 +5,12 @@ #include "IContext.h" #include "Asserts.h" -#if FOX_PLATFORM == FOX_PLATFORM_WINDOWS32 +#if defined(_WIN32) || defined(WIN32) || defined(_WIN64) || defined(WIN64) #define VK_USE_PLATFORM_WIN32_KHR -#elif FOX_PLATFORM == FOX_PLATFORM_LINUX +// #include // Include the Win32-specific extension header +#elif defined(__linux__) #define VK_USE_PLATFORM_XLIB_KHR -#else -#pragma error "Not supported" +// #include #endif diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index b48fd62..eaaf05b 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -22,9 +22,10 @@ #pragma warning(disable : 4267) #pragma warning(disable : 4702) #include "glslang/Include/glslang_c_interface.h" -#include -#include -#include +#include "glslang/Public/ResourceLimits.h" +#include "glslang/Public/ShaderLang.h" +//#include "glslang/SPIRV/GlslangToSpv.h" +#include "../../thirdparty/glslang/SPIRV/GlslangToSpv.h" #pragma warning(pop) namespace Fox diff --git a/src/backend/vulkan/VulkanDevice13.h b/src/backend/vulkan/VulkanDevice13.h index 618f106..126e157 100644 --- a/src/backend/vulkan/VulkanDevice13.h +++ b/src/backend/vulkan/VulkanDevice13.h @@ -6,6 +6,7 @@ #include "RIResource.h" #include "VulkanDevice12.h" + #include #include From 7c16e3c0bd905ceb02f45d272ce15e3ad2750754 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Tue, 18 Jun 2024 13:47:36 +0200 Subject: [PATCH 34/58] Added dynamic functions removed EDepthTest for ECompareOp --- include/IContext.h | 44 +++++- src/backend/vulkan/UtilsVk.h | 122 ++++++++++++++- src/backend/vulkan/VulkanContext.cpp | 205 +++++++++++++++++++------- src/backend/vulkan/VulkanContext.h | 10 +- src/backend/vulkan/VulkanDevice10.cpp | 17 ++- src/backend/vulkan/VulkanInstance.cpp | 2 +- 6 files changed, 331 insertions(+), 69 deletions(-) diff --git a/include/IContext.h b/include/IContext.h index e0293bd..0370792 100644 --- a/include/IContext.h +++ b/include/IContext.h @@ -166,14 +166,39 @@ enum class ECullMode BACK }; -enum class EDepthTest +enum class EStencilOp { - ALWAYS, - NEVER, - LESS, - LESS_OR_EQUAL, - GREATER, - GREATER_OR_EQUAL + KEEP = 0, + ZERO = 1, + REPLACE = 2, + INCREMENT_AND_CLAMP = 3, + DECREMENT_AND_CLAMP = 4, + INVERT = 5, + INCREMENT_AND_WRAP = 6, + DECREMENT_AND_WRAP = 7, +}; + +enum class ECompareOp +{ + NEVER = 0, + LESS = 1, + EQUAL = 2, + LESS_OR_EQUAL = 3, + GREATER = 4, + NOT_EQUAL = 5, + GREATER_OR_EQUAL = 6, + ALWAYS = 7, +}; + +struct DStencilOpState +{ + EStencilOp FailOp{ EStencilOp::KEEP }; + EStencilOp PassOp{ EStencilOp::REPLACE }; + EStencilOp DepthFailOp{ EStencilOp::KEEP }; + ECompareOp CompareOp{ ECompareOp::GREATER_OR_EQUAL }; + uint32_t CompareMask{ 0xffff }; + uint32_t WriteMask{ 0xffff }; + uint32_t Reference{}; }; enum ERIBlendMode @@ -189,7 +214,7 @@ struct PipelineFormat ECullMode CullMode{ ECullMode::NONE }; bool DepthTest{ false }; bool DepthWrite{ false }; - EDepthTest DepthTestMode{ EDepthTest::ALWAYS }; + ECompareOp DepthTestMode{ ECompareOp::LESS_OR_EQUAL }; bool StencilTest{ false }; ERIBlendMode BlendMode{ ERIBlendMode::DefaultBlendMode }; }; @@ -772,6 +797,9 @@ class IContext virtual void BindDescriptorSet(uint32_t commandBufferId, uint32_t setIndex, uint32_t descriptorSetId) = 0; virtual void CopyImage(uint32_t commandId, uint32_t imageId, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t stagingBufferId, uint32_t stagingBufferOffset) = 0; virtual void CopyBuffer(uint32_t commandId, uint32_t bufferId, uint32_t offset, uint32_t bytes, uint32_t stagingBufferId, uint32_t stagingBufferOffset) = 0; + virtual void SetStencilTest(uint32_t commandId, bool enable, const DStencilOpState* frontFace, const DStencilOpState* backFace) = 0; + virtual void SetDepthTestCompareOp(uint32_t commandId, bool enabled, bool depthWrite, ECompareOp compareOp) = 0; + virtual void SetPrimitiveTopology(uint32_t commandId, ETopology primitiveTopology) = 0; virtual uint32_t CreateRenderTarget(EFormat format, ESampleBit samples, bool isDepth, uint32_t width, uint32_t height, uint32_t arrayLength, uint32_t mipMapCount, EResourceState initialState) = 0; virtual void DestroyRenderTarget(uint32_t renderTargetId) = 0; diff --git a/src/backend/vulkan/UtilsVk.h b/src/backend/vulkan/UtilsVk.h index 2f8ec74..5fde963 100644 --- a/src/backend/vulkan/UtilsVk.h +++ b/src/backend/vulkan/UtilsVk.h @@ -2,8 +2,8 @@ #pragma once -#include "IContext.h" #include "Asserts.h" +#include "IContext.h" #if FOX_PLATFORM == FOX_PLATFORM_WINDOWS32 #define VK_USE_PLATFORM_WIN32_KHR @@ -13,13 +13,12 @@ #pragma error "Not supported" #endif - #include #include +#include #include #include -#include #include #define VKFAILED(result) ((result != VK_SUCCESS ? true : false)) @@ -866,6 +865,49 @@ convertResourceStateToImageLayout(Fox::EResourceState state, bool isDepth) return VK_IMAGE_LAYOUT_UNDEFINED; } +inline const char* +VkImageLayoutToString(VkImageLayout layout) +{ + switch (layout) + { + CASE(VK_IMAGE_LAYOUT_UNDEFINED, "VK_IMAGE_LAYOUT_UNDEFINED"); + CASE(VK_IMAGE_LAYOUT_GENERAL, "VK_IMAGE_LAYOUT_GENERAL"); + CASE(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, "VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL"); + CASE(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, "VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL"); + CASE(VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, "VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL"); + CASE(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, "VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL"); + CASE(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, "VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL"); + CASE(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, "VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL"); + CASE(VK_IMAGE_LAYOUT_PREINITIALIZED, "VK_IMAGE_LAYOUT_PREINITIALIZED"); + CASE(VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL, "VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL"); + CASE(VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL, "VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL"); + CASE(VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, "VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL"); + CASE(VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL, "VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL"); + CASE(VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL, "VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL"); + CASE(VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL, "VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL"); + CASE(VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL, "VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL"); + CASE(VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL, "VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL"); + CASE(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, "VK_IMAGE_LAYOUT_PRESENT_SRC_KHR"); + CASE(VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR, "VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR"); + CASE(VK_IMAGE_LAYOUT_VIDEO_DECODE_SRC_KHR, "VK_IMAGE_LAYOUT_VIDEO_DECODE_SRC_KHR"); + CASE(VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR, "VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR"); + CASE(VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR, "VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR"); + CASE(VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT, "VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT"); + CASE(VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR, "VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR"); + CASE(VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ_KHR, "VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ_KHR"); + CASE(VK_IMAGE_LAYOUT_VIDEO_ENCODE_DST_KHR, "VK_IMAGE_LAYOUT_VIDEO_ENCODE_DST_KHR"); + CASE(VK_IMAGE_LAYOUT_VIDEO_ENCODE_SRC_KHR, "VK_IMAGE_LAYOUT_VIDEO_ENCODE_SRC_KHR"); + CASE(VK_IMAGE_LAYOUT_VIDEO_ENCODE_DPB_KHR, "VK_IMAGE_LAYOUT_VIDEO_ENCODE_DPB_KHR"); + CASE(VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT, "VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT"); + + default: + furyassert(false); + break; // Invalid enum + } + + return "UNKNOWN_VK_LAYOUT"; +}; + inline VkFlags convertQueueTypeToVkFlags(uint32_t queueTypeFlag) { @@ -964,4 +1006,78 @@ uint32_t* queueFamilyIndexCreatedCount) return found; } +inline VkStencilOp +VkStencilOpFromStencilOp(Fox::EStencilOp stencilOp) +{ + switch (stencilOp) + { + CASE(Fox::EStencilOp::KEEP, VK_STENCIL_OP_KEEP); + CASE(Fox::EStencilOp::ZERO, VK_STENCIL_OP_ZERO); + CASE(Fox::EStencilOp::REPLACE, VK_STENCIL_OP_REPLACE); + CASE(Fox::EStencilOp::INCREMENT_AND_CLAMP, VK_STENCIL_OP_INCREMENT_AND_CLAMP); + CASE(Fox::EStencilOp::DECREMENT_AND_CLAMP, VK_STENCIL_OP_DECREMENT_AND_CLAMP); + CASE(Fox::EStencilOp::INVERT, VK_STENCIL_OP_INVERT); + CASE(Fox::EStencilOp::INCREMENT_AND_WRAP, VK_STENCIL_OP_INCREMENT_AND_WRAP); + CASE(Fox::EStencilOp::DECREMENT_AND_WRAP, VK_STENCIL_OP_DECREMENT_AND_WRAP); + default: + furyassert(false); + break; // Invalid enum + } + + return VK_STENCIL_OP_KEEP; +}; + +inline VkCompareOp +VkCompareOpFromCompareOp(Fox::ECompareOp compareOp) +{ + switch (compareOp) + { + CASE(Fox::ECompareOp::NEVER, VK_COMPARE_OP_NEVER); + CASE(Fox::ECompareOp::LESS, VK_COMPARE_OP_LESS); + CASE(Fox::ECompareOp::EQUAL, VK_COMPARE_OP_EQUAL); + CASE(Fox::ECompareOp::LESS_OR_EQUAL, VK_COMPARE_OP_LESS_OR_EQUAL); + CASE(Fox::ECompareOp::GREATER, VK_COMPARE_OP_GREATER); + CASE(Fox::ECompareOp::NOT_EQUAL, VK_COMPARE_OP_NOT_EQUAL); + CASE(Fox::ECompareOp::GREATER_OR_EQUAL, VK_COMPARE_OP_GREATER_OR_EQUAL); + CASE(Fox::ECompareOp::ALWAYS, VK_COMPARE_OP_ALWAYS); + default: + furyassert(false); + break; // Invalid enum + } + + return VK_COMPARE_OP_NEVER; +}; + +inline VkPrimitiveTopology +VkPrimitiveTopologyFromTopology(Fox::ETopology topology) +{ + switch (topology) + { + CASE(Fox::ETopology::TRIANGLE_LIST, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST); + CASE(Fox::ETopology::LINES_LIST, VK_PRIMITIVE_TOPOLOGY_LINE_LIST); + default: + furyassert(false); + break; // Invalid enum + } + + return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; +}; + +inline const char* +ERenderPassLayoutToString(Fox::ERenderPassLayout layout) +{ + switch (layout) + { + CASE(Fox::ERenderPassLayout::AsAttachment, "AsAttachment"); + CASE(Fox::ERenderPassLayout::Present, "Present"); + CASE(Fox::ERenderPassLayout::ShaderReadOnly, "ShaderReadOnly"); + CASE(Fox::ERenderPassLayout::Undefined, "Undefined"); + default: + furyassert(false); + break; // Invalid enum + } + + return "UNKNOWN_LAYOUT"; +}; + } \ No newline at end of file diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index b48fd62..d2abdb3 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -92,8 +92,8 @@ GenIdentifier() a = (a ^ 61) ^ (a >> 16); return a; }; - static uint32_t counter{ }; - auto value{ hash(counter++) }; + static uint32_t counter{}; + auto value{ hash(counter++) }; while (value == 0) { value = hash(counter++); @@ -122,7 +122,7 @@ AllocResource(std::array& container) } } - furyassert(0);//Possible memory leak, or bad usage of allocations + furyassert(0); // Possible memory leak, or bad usage of allocations throw std::runtime_error("Rendering context run out of resource to allocate!"); } @@ -276,10 +276,7 @@ VulkanContext::_initializeInstance() } VKAPI_ATTR VkBool32 VKAPI_CALL -VulkanContext::_vulkanDebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, -VkDebugUtilsMessageTypeFlagsEXT , -const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, -void* pUserData) +VulkanContext::_vulkanDebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) { VulkanContext* context = static_cast(pUserData); furyassert(context); @@ -325,30 +322,30 @@ VulkanContext::_initializeVersion() // Manually getting function vkEnumerateInstanceVersion = PFN_vkEnumerateInstanceVersion(vkGetInstanceProcAddr(nullptr, "vkEnumerateInstanceVersion")); } - + if (vkEnumerateInstanceVersion == nullptr) { Warning("Failed to vkGetInstanceProcAddr for vkEnumerateInstanceVersion"); } - uint32_t instanceVersion = VK_API_VERSION_1_0; - const VkResult result = vkEnumerateInstanceVersion(&instanceVersion); - if (VKFAILED(result)) - { - const std::string out = "Failed to vkEnumerateInstanceVersion because:" + std::string(VkUtils::VkErrorString(result)); - Warning(out); - } - else - { - // Extract version info - uint32_t major, minor, patch; - major = VK_API_VERSION_MAJOR(instanceVersion); - minor = VK_API_VERSION_MINOR(instanceVersion); - patch = VK_API_VERSION_PATCH(instanceVersion); - - const std::string out = "Vulkan version:" + std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(patch); - Log(out); - } + uint32_t instanceVersion = VK_API_VERSION_1_0; + const VkResult result = vkEnumerateInstanceVersion(&instanceVersion); + if (VKFAILED(result)) + { + const std::string out = "Failed to vkEnumerateInstanceVersion because:" + std::string(VkUtils::VkErrorString(result)); + Warning(out); + } + else + { + // Extract version info + uint32_t major, minor, patch; + major = VK_API_VERSION_MAJOR(instanceVersion); + minor = VK_API_VERSION_MINOR(instanceVersion); + patch = VK_API_VERSION_PATCH(instanceVersion); + + const std::string out = "Vulkan version:" + std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(patch); + Log(out); + } } void @@ -1726,7 +1723,7 @@ VulkanContext::_createFramebuffer(const DFramebufferAttachments& attachments) // Extrapolate all the renderTargetRef views const uint32_t depthAttachmentCount = (uint32_t)(attachments.DepthStencil != 0); - const int64_t attachmentCount = DFramebufferAttachments::MAX_ATTACHMENTS - std::count(attachments.RenderTargets.begin(), attachments.RenderTargets.end(), (uint32_t)0) + depthAttachmentCount; + const int64_t attachmentCount = DFramebufferAttachments::MAX_ATTACHMENTS - std::count(attachments.RenderTargets.begin(), attachments.RenderTargets.end(), (uint32_t)0) + depthAttachmentCount; furyassert(attachmentCount > 0); // Must have at least one attachment std::vector imageViewsAttachments; @@ -1860,6 +1857,7 @@ VulkanContext::BeginCommandBuffer(uint32_t commandBufferId) commandBufferRef.CurrentScissor = {}; commandBufferRef.CurrentVertexBuffer = {}; commandBufferRef.CurrentIndexBuffer = {}; + commandBufferRef.StencilTestActive = {}; VkCommandBufferBeginInfo beginInfo{}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; @@ -1959,6 +1957,26 @@ VulkanContext::BindRenderTargets(uint32_t commandBufferId, const DFramebufferAtt } } +#if _DEBUG && DEBUG_RT_TRANSITIONS 1 + for (size_t i = 0; i < renderPassAttachments.Attachments.size(); i++) + { + if (VkUtils::isColorFormat(VkUtils::convertFormat(renderPassAttachments.Attachments.at(i).Format))) + { + const auto* rt = &GetResource(_renderTargets, framebufferPtr->Attachments.RenderTargets[i]); + std::cout << "Begin Render Pass for image:" << rt->Image.Image + << " from layout:" << VkUtils::VkImageLayoutToString(VkUtils::convertRenderPassLayout(renderPassAttachments.Attachments.at(i).InitialLayout)) << " to " + << VkUtils::VkImageLayoutToString(VkUtils::convertRenderPassLayout(renderPassAttachments.Attachments.at(i).FinalLayout)) << std::endl; + } + else + { + const auto* rt = &GetResource(_renderTargets, framebufferPtr->Attachments.DepthStencil); + std::cout << "Begin Render Pass for image:" << rt->Image.Image + << " from layout:" << VkUtils::VkImageLayoutToString(VkUtils::convertRenderPassLayout(renderPassAttachments.Attachments.at(i).InitialLayout)) << " to " + << VkUtils::VkImageLayoutToString(VkUtils::convertRenderPassLayout(renderPassAttachments.Attachments.at(i).FinalLayout)) << std::endl; + } + } +#endif + VkRenderPass renderPass = _createRenderPass(renderPassAttachments); VkRenderPassBeginInfo renderPassInfo{}; @@ -2165,6 +2183,102 @@ VulkanContext::CopyBuffer(uint32_t commandId, uint32_t bufferId, uint32_t offset vkCmdCopyBuffer(commandBufferRef.Cmd, buffRef.Buffer.Buffer, vertexRef.Buffer.Buffer, 1, ©); } +void +Fox::VulkanContext::SetStencilTest(uint32_t commandId, bool enable, const DStencilOpState* frontFace, const DStencilOpState* backFace) +{ + auto& commandBufferRef = GetResource(_commandBuffers, commandId); + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass +#if _DEBUG + if (enable) + { + furyassert(enable && frontFace && backFace); + } +#endif + + vkCmdSetStencilTestEnable(commandBufferRef.Cmd, static_cast(enable)); + + DStencilOpState defaultStencilState{}; + if (!frontFace) + { + frontFace = &defaultStencilState; + } + if (!backFace) + { + backFace = &defaultStencilState; + } + + // If has same stencil op for back and front do optimization + if (frontFace == backFace) + { + const VkStencilOp failOp{ VkUtils::VkStencilOpFromStencilOp(frontFace->FailOp) }; + const VkStencilOp passOp{ VkUtils::VkStencilOpFromStencilOp(frontFace->PassOp) }; + const VkStencilOp depthFailOp{ VkUtils::VkStencilOpFromStencilOp(frontFace->DepthFailOp) }; + const VkCompareOp compareOp{ VkUtils::VkCompareOpFromCompareOp(frontFace->CompareOp) }; + vkCmdSetStencilOp(commandBufferRef.Cmd, VkStencilFaceFlagBits::VK_STENCIL_FACE_FRONT_AND_BACK, failOp, passOp, depthFailOp, compareOp); + + vkCmdSetStencilReference(commandBufferRef.Cmd, VkStencilFaceFlagBits::VK_STENCIL_FACE_FRONT_AND_BACK, frontFace->Reference); + vkCmdSetStencilCompareMask(commandBufferRef.Cmd, VkStencilFaceFlagBits::VK_STENCIL_FACE_FRONT_AND_BACK, frontFace->CompareMask); + vkCmdSetStencilWriteMask(commandBufferRef.Cmd, VkStencilFaceFlagBits::VK_STENCIL_FACE_FRONT_AND_BACK, frontFace->WriteMask); + } + else + // Separate for front and back + { + { + // Front face + const VkStencilOp failOp{ VkUtils::VkStencilOpFromStencilOp(frontFace->FailOp) }; + const VkStencilOp passOp{ VkUtils::VkStencilOpFromStencilOp(frontFace->PassOp) }; + const VkStencilOp depthFailOp{ VkUtils::VkStencilOpFromStencilOp(frontFace->DepthFailOp) }; + const VkCompareOp compareOp{ VkUtils::VkCompareOpFromCompareOp(frontFace->CompareOp) }; + vkCmdSetStencilOp(commandBufferRef.Cmd, VkStencilFaceFlagBits::VK_STENCIL_FACE_FRONT_BIT, failOp, passOp, depthFailOp, compareOp); + + vkCmdSetStencilReference(commandBufferRef.Cmd, VkStencilFaceFlagBits::VK_STENCIL_FACE_FRONT_BIT, frontFace->Reference); + vkCmdSetStencilCompareMask(commandBufferRef.Cmd, VkStencilFaceFlagBits::VK_STENCIL_FACE_FRONT_BIT, frontFace->CompareMask); + vkCmdSetStencilWriteMask(commandBufferRef.Cmd, VkStencilFaceFlagBits::VK_STENCIL_FACE_FRONT_BIT, frontFace->WriteMask); + } + { + // Back face + const VkStencilOp failOp{ VkUtils::VkStencilOpFromStencilOp(backFace->FailOp) }; + const VkStencilOp passOp{ VkUtils::VkStencilOpFromStencilOp(backFace->PassOp) }; + const VkStencilOp depthFailOp{ VkUtils::VkStencilOpFromStencilOp(backFace->DepthFailOp) }; + const VkCompareOp compareOp{ VkUtils::VkCompareOpFromCompareOp(backFace->CompareOp) }; + vkCmdSetStencilOp(commandBufferRef.Cmd, VkStencilFaceFlagBits::VK_STENCIL_FACE_BACK_BIT, failOp, passOp, depthFailOp, compareOp); + + vkCmdSetStencilReference(commandBufferRef.Cmd, VkStencilFaceFlagBits::VK_STENCIL_FACE_BACK_BIT, backFace->Reference); + vkCmdSetStencilCompareMask(commandBufferRef.Cmd, VkStencilFaceFlagBits::VK_STENCIL_FACE_BACK_BIT, backFace->CompareMask); + vkCmdSetStencilWriteMask(commandBufferRef.Cmd, VkStencilFaceFlagBits::VK_STENCIL_FACE_BACK_BIT, backFace->WriteMask); + } + } +} + +void +VulkanContext::SetDepthTestCompareOp(uint32_t commandId, bool enabled, bool depthWrite, ECompareOp compareOp) +{ + auto& commandBufferRef = GetResource(_commandBuffers, commandId); + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass + + vkCmdSetDepthTestEnable(commandBufferRef.Cmd, static_cast(enabled)); + + if (enabled) + { + vkCmdSetDepthWriteEnable(commandBufferRef.Cmd, static_cast(depthWrite)); + const VkCompareOp compareOpVk{ VkUtils::VkCompareOpFromCompareOp(compareOp) }; + vkCmdSetDepthCompareOp(commandBufferRef.Cmd, compareOpVk); + } +} + +void +VulkanContext::SetPrimitiveTopology(uint32_t commandId, ETopology primitiveTopology) +{ + auto& commandBufferRef = GetResource(_commandBuffers, commandId); + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass + + const auto topology{ VkUtils::VkPrimitiveTopologyFromTopology(primitiveTopology) }; + vkCmdSetPrimitiveTopology(commandBufferRef.Cmd, topology); +} + void VulkanContext::QueueSubmit(uint32_t queueId, const std::vector& waitSemaphore, const std::vector& finishSemaphore, const std::vector& cmdIds, uint32_t fenceId) { @@ -2721,6 +2835,14 @@ RenderTargetBarrier* p_rt_barriers) commandBufferRef.ActiveRenderPass = nullptr; } +#if _DEBUG && DEBUG_RT_TRANSITIONS 1 + for (size_t i = 0; i < imageBarriers.size(); i++) + { + std::cout << "Explicit Image barrier for VkImage:" << imageBarriers.at(i).image << " from layout:" << VkUtils::VkImageLayoutToString(imageBarriers.at(i).oldLayout) << " to " + << VkUtils::VkImageLayoutToString(imageBarriers.at(i).newLayout) << std::endl; + } +#endif + vkCmdPipelineBarrier(commandBufferRef.Cmd, srcStageMask, dstStageMask, 0, 0, NULL, 0, NULL, (uint32_t)imageBarriers.size(), imageBarriers.data()); } } @@ -2765,7 +2887,7 @@ uint32_t stride) RIVulkanPipelineBuilder pipe(shaderStages, { inputBinding }, vertexInputAttributes, pipelineLayout, renderPass); pipe.AddViewport({}); pipe.AddScissor({}); - pipe.SetDynamicState({ VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }); + // pipe.SetDynamicState({ VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }); switch (format.FillMode) { case EFillMode::FILL: @@ -2793,31 +2915,8 @@ uint32_t stride) furyassert(0); break; } - switch (format.DepthTestMode) - { - case EDepthTest::ALWAYS: - pipe.SetDepthTestingOp(VK_COMPARE_OP_ALWAYS); - break; - case EDepthTest::NEVER: - pipe.SetDepthTestingOp(VK_COMPARE_OP_NEVER); - break; - case EDepthTest::LESS: - pipe.SetDepthTestingOp(VK_COMPARE_OP_LESS); - break; - case EDepthTest::LESS_OR_EQUAL: - pipe.SetDepthTestingOp(VK_COMPARE_OP_LESS_OR_EQUAL); - break; - case EDepthTest::GREATER: - pipe.SetDepthTestingOp(VK_COMPARE_OP_GREATER); - break; - case EDepthTest::GREATER_OR_EQUAL: - pipe.SetDepthTestingOp(VK_COMPARE_OP_GREATER_OR_EQUAL); - break; - default: - pipe.SetDepthTestingOp(VK_COMPARE_OP_LESS_OR_EQUAL); - critical(0); - break; - } + const auto vkCompareOpValue{ VkUtils::VkCompareOpFromCompareOp(format.DepthTestMode) }; + pipe.SetDepthTestingOp(vkCompareOpValue); pipe.SetDepthTesting(format.DepthTest, format.DepthWrite); pipe.SetDepthStencil(format.StencilTest); pipe.SetDepthStencilOp(VkStencilOpState{ VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_LESS_OR_EQUAL, 0, 0, 0 }); diff --git a/src/backend/vulkan/VulkanContext.h b/src/backend/vulkan/VulkanContext.h index ce48646..2dbadde 100644 --- a/src/backend/vulkan/VulkanContext.h +++ b/src/backend/vulkan/VulkanContext.h @@ -4,7 +4,7 @@ #include "IContext.h" -#include "VulkanInstance.h"//This first because it defines macros for vulkan platform +#include "VulkanInstance.h" //This first because it defines macros for vulkan platform #include "DescriptorPool.h" #include "RingBufferManager.h" @@ -17,6 +17,8 @@ #include #include +#define DEBUG_RT_TRANSITIONS 0 + namespace Fox { @@ -105,6 +107,7 @@ struct DCommandBufferVulkan : public DResource VkRect2D CurrentScissor{}; VkBuffer CurrentVertexBuffer{}; VkBuffer CurrentIndexBuffer{}; + bool StencilTestActive{}; }; struct DFenceVulkan : public DResource @@ -224,6 +227,9 @@ class VulkanContext final : public IContext void BindDescriptorSet(uint32_t commandBufferId, uint32_t setIndex, uint32_t descriptorSetId) override; void CopyImage(uint32_t commandId, uint32_t imageId, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t stagingBufferId, uint32_t stagingBufferOffset) override; void CopyBuffer(uint32_t commandId, uint32_t bufferId, uint32_t offset, uint32_t bytes, uint32_t stagingBufferId, uint32_t stagingBufferOffset) override; + void SetStencilTest(uint32_t commandId, bool enable, const DStencilOpState* frontFace, const DStencilOpState* backFace) override; + void SetDepthTestCompareOp(uint32_t commandId, bool enabled, bool depthWrite, ECompareOp compareOp) override; + void SetPrimitiveTopology(uint32_t commandId, ETopology primitiveTopology) override; uint32_t CreateFence(bool signaled) override; void DestroyFence(uint32_t fenceId) override; @@ -350,6 +356,8 @@ class VulkanContext final : public IContext const std::vector _deviceExtensionNames = { VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME, + VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME, + "VK_EXT_extended_dynamic_state2 ", "VK_KHR_Maintenance1", // passing negative viewport heights "VK_KHR_maintenance4", "VK_KHR_dedicated_allocation", diff --git a/src/backend/vulkan/VulkanDevice10.cpp b/src/backend/vulkan/VulkanDevice10.cpp index 89002ff..455fa60 100644 --- a/src/backend/vulkan/VulkanDevice10.cpp +++ b/src/backend/vulkan/VulkanDevice10.cpp @@ -14,9 +14,19 @@ const std::vector& const std::vector& vertexInputAttributes, VkPipelineLayout pipelineLayout, VkRenderPass renderPass) - : DynamicStates{ VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR } + : DynamicStates{ VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, + VK_DYNAMIC_STATE_LINE_WIDTH, + VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, + VK_DYNAMIC_STATE_STENCIL_WRITE_MASK, + VK_DYNAMIC_STATE_STENCIL_REFERENCE, + VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY, + VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE, + VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE, + VK_DYNAMIC_STATE_DEPTH_COMPARE_OP, + VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE, + VK_DYNAMIC_STATE_STENCIL_OP } { - PipelineShaderStages = shaders; InputBindings = vertexInputBinding; VertexInputAttributes = vertexInputAttributes; @@ -140,7 +150,7 @@ RIVulkanPipelineBuilder::SetAlphaBlending() } VkPipelineColorBlendAttachmentState colorBlendAttachment{}; - colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT;// | VK_COLOR_COMPONENT_A_BIT; + colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT; // | VK_COLOR_COMPONENT_A_BIT; colorBlendAttachment.blendEnable = VK_TRUE; colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; @@ -157,6 +167,7 @@ RIVulkanPipelineBuilder::SetAlphaBlending() void RIVulkanPipelineBuilder::SetDynamicState(const std::vector& states) { + furyassert(0); DynamicStates = states; _fillDynamicState(); } diff --git a/src/backend/vulkan/VulkanInstance.cpp b/src/backend/vulkan/VulkanInstance.cpp index d67869e..ac94ba5 100644 --- a/src/backend/vulkan/VulkanInstance.cpp +++ b/src/backend/vulkan/VulkanInstance.cpp @@ -19,7 +19,7 @@ RIVulkanInstance::Init(const char* applicationName, std::vector val VkApplicationInfo applicationInfo = {}; applicationInfo.pNext = NULL; applicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - applicationInfo.apiVersion = VK_API_VERSION_1_2; + applicationInfo.apiVersion = VK_API_VERSION_1_3; applicationInfo.applicationVersion = 1; applicationInfo.pApplicationName = applicationName; applicationInfo.pEngineName = "RedFox Game Engine"; From 3a4591ac42b3299e0db42b2bee382c873ff34ae0 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Fri, 21 Jun 2024 18:02:09 +0200 Subject: [PATCH 35/58] Set line width, render pass creation now take into account stencil --- include/IContext.h | 12 ++++++++---- src/backend/vulkan/VulkanContext.cpp | 17 ++++++++++++++--- src/backend/vulkan/VulkanContext.h | 1 + src/backend/vulkan/VulkanDevice10.cpp | 6 ++++++ src/backend/vulkan/VulkanDevice10.h | 1 + 5 files changed, 30 insertions(+), 7 deletions(-) diff --git a/include/IContext.h b/include/IContext.h index 0370792..71e5b68 100644 --- a/include/IContext.h +++ b/include/IContext.h @@ -196,8 +196,8 @@ struct DStencilOpState EStencilOp PassOp{ EStencilOp::REPLACE }; EStencilOp DepthFailOp{ EStencilOp::KEEP }; ECompareOp CompareOp{ ECompareOp::GREATER_OR_EQUAL }; - uint32_t CompareMask{ 0xffff }; - uint32_t WriteMask{ 0xffff }; + uint32_t CompareMask{ 0xff }; + uint32_t WriteMask{ 0xff }; uint32_t Reference{}; }; @@ -217,6 +217,7 @@ struct PipelineFormat ECompareOp DepthTestMode{ ECompareOp::LESS_OR_EQUAL }; bool StencilTest{ false }; ERIBlendMode BlendMode{ ERIBlendMode::DefaultBlendMode }; + float LineWidth{ 1.f }; }; struct PipelineFormatHashFn @@ -571,13 +572,15 @@ struct DFramebufferAttachmentEqualFn struct DLoadOpPass { - ERenderPassLoad LoadColor[DFramebufferAttachments::MAX_ATTACHMENTS]; - ERenderPassLoad LoadDepth; + ERenderPassLoad LoadColor[DFramebufferAttachments::MAX_ATTACHMENTS]; + ERenderPassLoad LoadDepth; + /*CURRENTLY NOT USED, USE LoadDepth to control both*/ ERenderPassLoad LoadStencil; DClearValue ClearColor[DFramebufferAttachments::MAX_ATTACHMENTS]; DClearValue ClearDepthStencil; ERenderPassStore StoreActionsColor[DFramebufferAttachments::MAX_ATTACHMENTS]; ERenderPassStore StoreDepth; + /*CURRENTLY NOT USED, USE LoadDepth to control both*/ ERenderPassStore StoreStencil; }; @@ -800,6 +803,7 @@ class IContext virtual void SetStencilTest(uint32_t commandId, bool enable, const DStencilOpState* frontFace, const DStencilOpState* backFace) = 0; virtual void SetDepthTestCompareOp(uint32_t commandId, bool enabled, bool depthWrite, ECompareOp compareOp) = 0; virtual void SetPrimitiveTopology(uint32_t commandId, ETopology primitiveTopology) = 0; + virtual void SetLineWidth(uint32_t commandId, float lineWidth) = 0; virtual uint32_t CreateRenderTarget(EFormat format, ESampleBit samples, bool isDepth, uint32_t width, uint32_t height, uint32_t arrayLength, uint32_t mipMapCount, EResourceState initialState) = 0; virtual void DestroyRenderTarget(uint32_t renderTargetId) = 0; diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index d2abdb3..d3d3530 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -2279,6 +2279,16 @@ VulkanContext::SetPrimitiveTopology(uint32_t commandId, ETopology primitiveTopol vkCmdSetPrimitiveTopology(commandBufferRef.Cmd, topology); } +void +VulkanContext::SetLineWidth(uint32_t commandId, float lineWidth) +{ + auto& commandBufferRef = GetResource(_commandBuffers, commandId); + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass + + vkCmdSetLineWidth(commandBufferRef.Cmd, lineWidth); +} + void VulkanContext::QueueSubmit(uint32_t queueId, const std::vector& waitSemaphore, const std::vector& finishSemaphore, const std::vector& cmdIds, uint32_t fenceId) { @@ -2887,6 +2897,7 @@ uint32_t stride) RIVulkanPipelineBuilder pipe(shaderStages, { inputBinding }, vertexInputAttributes, pipelineLayout, renderPass); pipe.AddViewport({}); pipe.AddScissor({}); + pipe.SetLineWidth(format.LineWidth); // pipe.SetDynamicState({ VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }); switch (format.FillMode) { @@ -3199,9 +3210,9 @@ ConvertRenderPassAttachmentsToRIVkRenderPassInfo(const DRenderPassAttachments& a desc.samples = VkUtils::convertVkSampleCount(att.Samples); desc.loadOp = VkUtils::convertAttachmentLoadOp(att.LoadOP); desc.storeOp = VkUtils::convertAttachmentStoreOp(att.StoreOP); - // Stencil not used right now - desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + // Stencil behave same as depth + desc.stencilLoadOp = desc.loadOp; + desc.stencilStoreOp = desc.storeOp; desc.initialLayout = VkUtils::convertRenderPassLayout(att.InitialLayout, VkUtils::isColorFormat(desc.format)); desc.finalLayout = VkUtils::convertRenderPassLayout(att.FinalLayout, VkUtils::isColorFormat(desc.format)); diff --git a/src/backend/vulkan/VulkanContext.h b/src/backend/vulkan/VulkanContext.h index 2dbadde..d36442c 100644 --- a/src/backend/vulkan/VulkanContext.h +++ b/src/backend/vulkan/VulkanContext.h @@ -230,6 +230,7 @@ class VulkanContext final : public IContext void SetStencilTest(uint32_t commandId, bool enable, const DStencilOpState* frontFace, const DStencilOpState* backFace) override; void SetDepthTestCompareOp(uint32_t commandId, bool enabled, bool depthWrite, ECompareOp compareOp) override; void SetPrimitiveTopology(uint32_t commandId, ETopology primitiveTopology) override; + void SetLineWidth(uint32_t commandId, float lineWidth) override; uint32_t CreateFence(bool signaled) override; void DestroyFence(uint32_t fenceId) override; diff --git a/src/backend/vulkan/VulkanDevice10.cpp b/src/backend/vulkan/VulkanDevice10.cpp index 455fa60..e0a87de 100644 --- a/src/backend/vulkan/VulkanDevice10.cpp +++ b/src/backend/vulkan/VulkanDevice10.cpp @@ -141,6 +141,12 @@ RIVulkanPipelineBuilder::SetTopology(VkPrimitiveTopology topology) PipelineInputAssembly.topology = topology; } +void +RIVulkanPipelineBuilder::SetLineWidth(float w) +{ + PipelineRasterization.lineWidth = w; +} + void RIVulkanPipelineBuilder::SetAlphaBlending() { diff --git a/src/backend/vulkan/VulkanDevice10.h b/src/backend/vulkan/VulkanDevice10.h index 65a4c98..fa5d7f5 100644 --- a/src/backend/vulkan/VulkanDevice10.h +++ b/src/backend/vulkan/VulkanDevice10.h @@ -22,6 +22,7 @@ struct RIVulkanPipelineBuilder void AddViewport(VkViewport viewport); void AddScissor(VkRect2D); void SetTopology(VkPrimitiveTopology topology); + void SetLineWidth(float w); void SetAlphaBlending(); void SetDynamicState(const std::vector& states); void SetDepthTesting(bool testDepth, bool writeDepth); From 33cbfb3044dc18073d01ee59cc50c3e7ee49aaa2 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Tue, 25 Jun 2024 09:17:25 +0200 Subject: [PATCH 36/58] Incresed resources limit and added info when running out of resources --- src/backend/vulkan/VulkanContext.cpp | 5 +++-- src/backend/vulkan/VulkanContext.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index 0801045..044788a 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -10,6 +10,7 @@ #include #include #include +#include // Thirdparty #pragma warning(push) @@ -24,7 +25,7 @@ #include "glslang/Include/glslang_c_interface.h" #include "glslang/Public/ResourceLimits.h" #include "glslang/Public/ShaderLang.h" -//#include "glslang/SPIRV/GlslangToSpv.h" +// #include "glslang/SPIRV/GlslangToSpv.h" #include "../../thirdparty/glslang/SPIRV/GlslangToSpv.h" #pragma warning(pop) @@ -124,7 +125,7 @@ AllocResource(std::array& container) } furyassert(0); // Possible memory leak, or bad usage of allocations - throw std::runtime_error("Rendering context run out of resource to allocate!"); + throw std::runtime_error(std::string("Rendering context run out of resource to allocate max") + std::to_string(container.size()) + " for " + std::type_index(typeid(T)).name()); } DRenderPassAttachments diff --git a/src/backend/vulkan/VulkanContext.h b/src/backend/vulkan/VulkanContext.h index d36442c..f97f59f 100644 --- a/src/backend/vulkan/VulkanContext.h +++ b/src/backend/vulkan/VulkanContext.h @@ -266,7 +266,7 @@ class VulkanContext final : public IContext #pragma endregion private: - static constexpr uint32_t MAX_RESOURCES = 1024; // Change this number to increase number of allocations per resource + static constexpr uint32_t MAX_RESOURCES = 1024 * 4; // Change this number to increase number of allocations per resource static constexpr uint64_t MAX_FENCE_TIMEOUT = 0xffff; // 0xffffffffffffffff; // nanoseconds RIVulkanInstance Instance; RIVulkanDevice13 Device; From 3043e19f43e75a5f3895bf88706427944a0b60fe Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Wed, 3 Jul 2024 10:57:10 +0200 Subject: [PATCH 37/58] Bug fix - not destroying descriptor pools and also destroying the same descriptorSetLayout twice --- src/backend/vulkan/VulkanContext.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index 044788a..6b5d059 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -1465,11 +1465,31 @@ VulkanContext::DestroyRootSignature(uint32_t rootSignatureId) if (usageCount == 1) { Device.DestroyDescriptorSetLayout(rootSignature.DescriptorSetLayouts[i]); + + // if the same descriptor set layout is used multiple times set the pointers to nullptr + for (uint32_t j = 0; j < (uint32_t)EDescriptorFrequency::MAX_COUNT; j++) + { + if (i != j && rootSignature.DescriptorSetLayouts[j] == rootSignature.DescriptorSetLayouts[i]) + { + rootSignature.DescriptorSetLayouts[j] = nullptr; + } + } + rootSignature.DescriptorSetLayouts[i] = nullptr; } } } } + // Destroy descriptor pools + for (uint32_t i = 0; i < (uint32_t)EDescriptorFrequency::MAX_COUNT; i++) + { + //@TODO shorten loop + if (rootSignature.EmptyPool[i] == nullptr) + continue; + + Device.DestroyDescriptorPool(rootSignature.EmptyPool[i]); + } + rootSignature.Id = FREE; memset(rootSignature.DescriptorSetLayouts, NULL, sizeof(rootSignature.DescriptorSetLayouts)); for (auto it = 0; it < (uint32_t)EDescriptorFrequency::MAX_COUNT; it++) From bd5932b81329afa528480550f83dfa4fee5e6434 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Wed, 3 Jul 2024 11:19:30 +0200 Subject: [PATCH 38/58] destroy sampler function --- include/IContext.h | 3 ++- src/backend/vulkan/VulkanContext.cpp | 11 +++++++++++ src/backend/vulkan/VulkanContext.h | 1 + 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/include/IContext.h b/include/IContext.h index b86cc8a..61ec72d 100644 --- a/include/IContext.h +++ b/include/IContext.h @@ -3,11 +3,11 @@ #pragma once #include +#include #include #include #include #include -#include #ifndef NOMINMAX #define NOMINMAX @@ -781,6 +781,7 @@ class IContext virtual void DestroyDescriptorSet(uint32_t descriptorSetId) = 0; virtual void UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t paramCount, DescriptorData* params) = 0; virtual uint32_t CreateSampler(uint32_t minLod, uint32_t maxLod) = 0; + virtual void DestroySampler(uint32_t samplerId) = 0; virtual uint32_t CreateCommandPool(uint32_t queueId) = 0; virtual void DestroyCommandPool(uint32_t commandPoolId) = 0; diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index 6b5d059..b61b6a7 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -1274,6 +1274,17 @@ VulkanContext::CreateSampler(uint32_t minLod, uint32_t maxLod) return *ResourceId(EResourceType::SAMPLER, samplerRef.Id, index); } +void +VulkanContext::DestroySampler(uint32_t samplerId) +{ + DSamplerVulkan& sampler = GetResource(_samplers, samplerId); + + Device.DestroySampler(sampler.Sampler); + + sampler.Id = FREE; + sampler.Sampler = nullptr; +} + uint32_t VulkanContext::CreatePipeline(const ShaderId shader, uint32_t rootSignatureId, const DPipelineAttachments& attachments, const PipelineFormat& format) { diff --git a/src/backend/vulkan/VulkanContext.h b/src/backend/vulkan/VulkanContext.h index f97f59f..2ac1fcc 100644 --- a/src/backend/vulkan/VulkanContext.h +++ b/src/backend/vulkan/VulkanContext.h @@ -197,6 +197,7 @@ class VulkanContext final : public IContext ShaderId CreateShader(const ShaderSource& source) override; void DestroyShader(const ShaderId shader) override; uint32_t CreateSampler(uint32_t minLod, uint32_t maxLod) override; + void DestroySampler(uint32_t samplerId) override; uint32_t CreatePipeline(const ShaderId shader, uint32_t rootSignatureId, const DPipelineAttachments& attachments, const PipelineFormat& format) override; void DestroyPipeline(uint32_t pipelineId) override; From ed2062e1b222d45ad45d084d963babc6233e7862 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Wed, 3 Jul 2024 14:03:13 +0200 Subject: [PATCH 39/58] Destroying debug checks --- src/backend/vulkan/VulkanContext.cpp | 57 +++++++++++++++++++++------- src/backend/vulkan/VulkanContext.h | 1 - 2 files changed, 43 insertions(+), 15 deletions(-) diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index b61b6a7..c1f220b 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -437,16 +437,40 @@ VulkanContext::~VulkanContext() Device.DestroySampler(_emptySampler.Sampler); #if _DEBUG - const auto validSwapchainsCount = std::count_if(_swapchains.begin(), _swapchains.end(), [](const DSwapchainVulkan& swapchain) { return IsValidId(swapchain.Id); }); - furyassert(validSwapchainsCount == 0); - const auto validVertexBufferCount = std::count_if(_vertexBuffers.begin(), _vertexBuffers.end(), [](const DBufferVulkan& buffer) { return IsValidId(buffer.Id); }); + const auto validVertexBufferCount = std::count_if(_vertexBuffers.begin(), _vertexBuffers.end(), [](const DBufferVulkan& e) { return IsValidId(e.Id); }); + const auto validTransferBufferCount = std::count_if(_transferBuffers.begin(), _transferBuffers.end(), [](const DBufferVulkan& e) { return IsValidId(e.Id); }); + const auto validUboCount = std::count_if(_uniformBuffers.begin(), _uniformBuffers.end(), [](const DBufferVulkan& e) { return IsValidId(e.Id); }); + const auto validIndirectBufferCount = std::count_if(_indirectBuffers.begin(), _indirectBuffers.end(), [](const DBufferVulkan& e) { return IsValidId(e.Id); }); + const auto validSwapchainsCount = std::count_if(_swapchains.begin(), _swapchains.end(), [](const DSwapchainVulkan& swapchain) { return IsValidId(swapchain.Id); }); + const auto validFramebufferCount = std::count_if(_framebuffers.begin(), _framebuffers.end(), [](const DFramebufferVulkan& buffer) { return IsValidId(buffer.Id); }); + const auto validShaderCount = std::count_if(_shaders.begin(), _shaders.end(), [](const DShaderVulkan& shader) { return IsValidId(shader.Id); }); + const auto validImageCount = std::count_if(_images.begin(), _images.end(), [](const DImageVulkan& e) { return IsValidId(e.Id); }); + const auto validPipelineCount = std::count_if(_pipelines.begin(), _pipelines.end(), [](const DPipelineVulkan& e) { return IsValidId(e.Id); }); + const auto validFenceCount = std::count_if(_fences.begin(), _fences.end(), [](const DFenceVulkan& e) { return IsValidId(e.Id); }); + const auto validSamplerCount = std::count_if(_samplers.begin(), _samplers.end(), [](const DSamplerVulkan& e) { return IsValidId(e.Id); }); + const auto validCmdPoolCount = std::count_if(_commandPools.begin(), _commandPools.end(), [](const DCommandPoolVulkan& e) { return IsValidId(e.Id); }); + const auto validRootSigCount = std::count_if(_rootSignatures.begin(), _rootSignatures.end(), [](const DRootSignature& e) { return IsValidId(e.Id); }); + const auto validRTCount = std::count_if(_renderTargets.begin(), _renderTargets.end(), [](const DRenderTargetVulkan& e) { return IsValidId(e.Id); }); + const auto validDescSetCount = std::count_if(_descriptorSets.begin(), _descriptorSets.end(), [](const DDescriptorSet& e) { return IsValidId(e.Id); }); + const auto validCmdBufCount = std::count_if(_commandBuffers.begin(), _commandBuffers.end(), [](const DCommandBufferVulkan& e) { return IsValidId(e.Id); }); + furyassert(validVertexBufferCount == 0); - const auto validUniformBufferCount = std::count_if(_uniformBuffers.begin(), _uniformBuffers.end(), [](const DBufferVulkan& buffer) { return IsValidId(buffer.Id); }); - furyassert(validUniformBufferCount == 0); - const auto validFramebufferCount = std::count_if(_framebuffers.begin(), _framebuffers.end(), [](const DFramebufferVulkan& buffer) { return IsValidId(buffer.Id); }); + furyassert(validTransferBufferCount == 0); + furyassert(validUboCount == 0); + furyassert(validIndirectBufferCount == 0); + furyassert(validSwapchainsCount == 0); furyassert(validFramebufferCount == 0); - const auto validShaderCount = std::count_if(_shaders.begin(), _shaders.end(), [](const DShaderVulkan& shader) { return IsValidId(shader.Id); }); furyassert(validShaderCount == 0); + furyassert(validImageCount == 0); + furyassert(validPipelineCount == 0); + furyassert(validFenceCount == 0); + furyassert(validSamplerCount == 0); + furyassert(validCmdPoolCount == 0); + furyassert(validRootSigCount == 0); + furyassert(validRTCount == 0); + furyassert(validDescSetCount == 0); + furyassert(validCmdBufCount == 0); + #endif // Destroy all descriptor pools managers @@ -1167,15 +1191,20 @@ VulkanContext::DestroyImage(ImageId imageId) furyassert(IsValidId(resource.Id)); resource.Id = PENDING_DESTROY; - _deferDestruction([this, imageId]() { - auto& resource = GetResourceUnsafe(_images, imageId); + //_deferDestruction([this, imageId]() { + // auto& resource = GetResourceUnsafe(_images, imageId); - Device.DestroyImageView(resource.View); - Device.DestroyImage(resource.Image); - Device.DestroySampler(resource.Sampler); + // Device.DestroyImageView(resource.View); + // Device.DestroyImage(resource.Image); + // Device.DestroySampler(resource.Sampler); - resource.Id = FREE; - }); + // resource.Id = FREE; + //}); + Device.DestroyImageView(resource.View); + Device.DestroyImage(resource.Image); + Device.DestroySampler(resource.Sampler); + resource.Id = FREE; + resource = {}; } VertexInputLayoutId diff --git a/src/backend/vulkan/VulkanContext.h b/src/backend/vulkan/VulkanContext.h index 2ac1fcc..041c05c 100644 --- a/src/backend/vulkan/VulkanContext.h +++ b/src/backend/vulkan/VulkanContext.h @@ -291,7 +291,6 @@ class VulkanContext final : public IContext std::array _vertexLayouts; std::array _images; std::array _pipelines; - std::array _commandPools_DEPRECATED; std::array _fences; std::array _samplers; std::array _semaphores; From ba8e45255c495f3cea35bc73ed17e9594067b571 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Wed, 3 Jul 2024 14:20:22 +0200 Subject: [PATCH 40/58] Bug fix not destroying vk pipeline layout --- src/backend/vulkan/VulkanContext.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index c1f220b..6359f60 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -1479,7 +1479,8 @@ VulkanContext::DestroyRootSignature(uint32_t rootSignatureId) DRootSignature& rootSignature = GetResource(_rootSignatures, rootSignatureId); // Check if the pipeline layout is not shared among other root signatures - const auto count{ std::count_if(_rootSignatures.begin(), _rootSignatures.end(), [rootSignature](const DRootSignature& sig) { return sig.PipelineLayout == rootSignature.PipelineLayout; }) }; + const auto count{ std::count_if( + _rootSignatures.begin(), _rootSignatures.end(), [rootSignature](const DRootSignature& sig) { return IsValidId(sig.Id) && sig.PipelineLayout == rootSignature.PipelineLayout; }) }; if (count == 1) { Device.DestroyPipelineLayout(rootSignature.PipelineLayout); @@ -1530,7 +1531,8 @@ VulkanContext::DestroyRootSignature(uint32_t rootSignatureId) Device.DestroyDescriptorPool(rootSignature.EmptyPool[i]); } - rootSignature.Id = FREE; + rootSignature.Id = FREE; + rootSignature.PipelineLayout = nullptr; memset(rootSignature.DescriptorSetLayouts, NULL, sizeof(rootSignature.DescriptorSetLayouts)); for (auto it = 0; it < (uint32_t)EDescriptorFrequency::MAX_COUNT; it++) { From 1a0af9e7f4d6d0f96bc5703709e10a3df1ed4350 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Fri, 12 Jul 2024 14:51:57 +0200 Subject: [PATCH 41/58] bump vma --- thirdparty/VulkanMemoryAllocator | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thirdparty/VulkanMemoryAllocator b/thirdparty/VulkanMemoryAllocator index cb08556..98c4f34 160000 --- a/thirdparty/VulkanMemoryAllocator +++ b/thirdparty/VulkanMemoryAllocator @@ -1 +1 @@ -Subproject commit cb085560229fa35254b2d7d36f9f61b572b8ac4c +Subproject commit 98c4f3414b015432c6b040bdb53b5ba0c5d6c680 From fca723708e918228f2f65d0d1bc8ca3671e55ec5 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Fri, 12 Jul 2024 14:52:19 +0200 Subject: [PATCH 42/58] bump volk --- thirdparty/volk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thirdparty/volk b/thirdparty/volk index 48dbfa8..692bef4 160000 --- a/thirdparty/volk +++ b/thirdparty/volk @@ -1 +1 @@ -Subproject commit 48dbfa81a03ec3b994cc2eec6f57c60d3994fbf5 +Subproject commit 692bef4349111d5a1e24fa0fed79eee41496a09f From 44b9fb3f8fe5232b65870e723402f1cddc8e10df Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Fri, 12 Jul 2024 14:52:43 +0200 Subject: [PATCH 43/58] added logs and commented unneded checks --- src/backend/vulkan/VulkanContext.cpp | 23 +++++++++++--- src/backend/vulkan/VulkanDevice.cpp | 46 ++++++++++++++++++++++++++-- src/backend/vulkan/VulkanDevice.h | 2 +- src/backend/vulkan/VulkanDevice4.cpp | 3 +- 4 files changed, 63 insertions(+), 11 deletions(-) diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index 6359f60..8d6925f 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -224,14 +224,14 @@ VulkanContext::VulkanContext(const DContextConfig* const config) : _warningOutpu _emptyUbo.Buffer = Device.CreateBufferHostVisible(4, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); _emptyImageId = CreateImage(EFormat::R8G8B8A8_UNORM, 1, 1, 1); - _emptyImage = &GetResource(_images, _emptyImageId); + _emptyImage = &GetResource(_images, _emptyImageId); _emptySampler.Sampler = Device.CreateSampler(VK_FILTER_NEAREST, VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, 0, 1, VK_SAMPLER_MIPMAP_MODE_NEAREST, false, 0.f); { // Transition to attachment optimal const auto graphicsQueue = FindQueue(EQueueType::QUEUE_GRAPHICS); const auto pool = CreateCommandPool(graphicsQueue); - const auto cmd = CreateCommandBuffer(pool); + const auto cmd = CreateCommandBuffer(pool); BeginCommandBuffer(cmd); TextureBarrier barrier{}; barrier.ImageId = _emptyImageId; @@ -249,6 +249,10 @@ VulkanContext::VulkanContext(const DContextConfig* const config) : _warningOutpu // DestroyQueue(graphicsQueue); } + { + const std::string out = "Vulkan initialized"; + Log(out); + } } void @@ -261,6 +265,7 @@ VulkanContext::_initializeVolk() Log("Failed to initialize volk"); throw std::runtime_error("Failed to initialize volk"); } + Log("Intialized Volk"); } void @@ -275,6 +280,7 @@ VulkanContext::_initializeInstance() { throw std::runtime_error("Could not create a vulkan instance" + std::string(VkUtils::VkErrorString(result))); } + Log("Intialized vulkan instance"); } VKAPI_ATTR VkBool32 VKAPI_CALL @@ -314,6 +320,7 @@ VulkanContext::_initializeDebugger() Warning("Failed to create vulkan debug utils messenger"); } #endif + Log("Intialized vulkan debugger"); } void @@ -374,11 +381,11 @@ VulkanContext::_initializeDevice() // binding flags for textures, uniforms, and buffers // are required for our extension critical(descriptorIndexingFeatures.shaderSampledImageArrayNonUniformIndexing); - critical(descriptorIndexingFeatures.descriptorBindingSampledImageUpdateAfterBind); + // critical(descriptorIndexingFeatures.descriptorBindingSampledImageUpdateAfterBind); critical(descriptorIndexingFeatures.shaderUniformBufferArrayNonUniformIndexing); - critical(descriptorIndexingFeatures.descriptorBindingUniformBufferUpdateAfterBind); + // critical(descriptorIndexingFeatures.descriptorBindingUniformBufferUpdateAfterBind); critical(descriptorIndexingFeatures.shaderStorageBufferArrayNonUniformIndexing); - critical(descriptorIndexingFeatures.descriptorBindingStorageBufferUpdateAfterBind); + // critical(descriptorIndexingFeatures.descriptorBindingStorageBufferUpdateAfterBind); // Check validation layers and extensions support for the device #if _DEBUG @@ -400,6 +407,12 @@ VulkanContext::_initializeDevice() // track count of queue instantiated from each family; std::fill(_queueFamilyIndexCreatedCount.begin(), _queueFamilyIndexCreatedCount.end(), 0); + + Log("Intialized vulkan device"); + + VkPhysicalDeviceProperties deviceProperties; + vkGetPhysicalDeviceProperties(Device.PhysicalDevice, &deviceProperties); + Log(std::string("Device: ") + deviceProperties.deviceName); } void diff --git a/src/backend/vulkan/VulkanDevice.cpp b/src/backend/vulkan/VulkanDevice.cpp index f1c839a..5fb973c 100644 --- a/src/backend/vulkan/VulkanDevice.cpp +++ b/src/backend/vulkan/VulkanDevice.cpp @@ -1,10 +1,12 @@ // Copyright RedFox Studio 2022 #include "VulkanDevice.h" -#include "UtilsVk.h" #include "Asserts.h" +#include "UtilsVk.h" #define VMA_IMPLEMENTATION +#define VMA_STATIC_VULKAN_FUNCTIONS VK_TRUE +#define VMA_DYNAMIC_VULKAN_FUNCTIONS VK_TRUE #pragma warning(push) #pragma warning(disable : 4100) #pragma warning(disable : 4127) @@ -134,6 +136,25 @@ std::vector validationLayers) vma_vulkan_func.vkBindBufferMemory2KHR = vkBindBufferMemory2KHR; vma_vulkan_func.vkBindImageMemory2KHR = vkBindImageMemory2KHR; + furyassert(vma_vulkan_func.vkGetInstanceProcAddr); + furyassert(vma_vulkan_func.vkGetDeviceProcAddr); + furyassert(vma_vulkan_func.vkAllocateMemory); + furyassert(vma_vulkan_func.vkBindBufferMemory); + furyassert(vma_vulkan_func.vkBindImageMemory); + furyassert(vma_vulkan_func.vkCreateBuffer); + furyassert(vma_vulkan_func.vkCreateImage); + furyassert(vma_vulkan_func.vkDestroyBuffer); + furyassert(vma_vulkan_func.vkDestroyImage); + furyassert(vma_vulkan_func.vkFlushMappedMemoryRanges); + furyassert(vma_vulkan_func.vkFreeMemory); + furyassert(vma_vulkan_func.vkGetBufferMemoryRequirements); + furyassert(vma_vulkan_func.vkGetImageMemoryRequirements); + furyassert(vma_vulkan_func.vkGetPhysicalDeviceMemoryProperties); + furyassert(vma_vulkan_func.vkGetPhysicalDeviceProperties); + furyassert(vma_vulkan_func.vkInvalidateMappedMemoryRanges); + furyassert(vma_vulkan_func.vkMapMemory); + furyassert(vma_vulkan_func.vkUnmapMemory); + furyassert(vma_vulkan_func.vkCmdCopyBuffer); furyassert(vma_vulkan_func.vkGetPhysicalDeviceMemoryProperties2KHR); furyassert(vma_vulkan_func.vkGetBufferMemoryRequirements2KHR); furyassert(vma_vulkan_func.vkGetImageMemoryRequirements2KHR); @@ -141,11 +162,11 @@ std::vector validationLayers) furyassert(vma_vulkan_func.vkBindImageMemory2KHR); VmaAllocatorCreateInfo allocatorCreateInfo = {}; - allocatorCreateInfo.vulkanApiVersion = VK_API_VERSION_1_1; + allocatorCreateInfo.vulkanApiVersion = VK_MAKE_VERSION(1,3,0); allocatorCreateInfo.physicalDevice = PhysicalDevice; allocatorCreateInfo.device = Device; allocatorCreateInfo.instance = instance.Instance; - allocatorCreateInfo.pVulkanFunctions = &vma_vulkan_func; + // allocatorCreateInfo.pVulkanFunctions = &vma_vulkan_func; { const VkResult result = vmaCreateAllocator(&allocatorCreateInfo, &VmaAllocatorObject); @@ -154,6 +175,25 @@ std::vector validationLayers) // std::runtime_error("Failed to initialize VMA"); return result; } + + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkGetDeviceProcAddr); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkGetPhysicalDeviceProperties); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkGetPhysicalDeviceMemoryProperties); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkAllocateMemory); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkFreeMemory); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkMapMemory); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkUnmapMemory); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkFlushMappedMemoryRanges); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkInvalidateMappedMemoryRanges); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkBindBufferMemory); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkBindImageMemory); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkGetBufferMemoryRequirements); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkGetImageMemoryRequirements); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkCreateBuffer); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkDestroyBuffer); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkCreateImage); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkDestroyImage); + furyassert(VmaAllocatorObject->GetVulkanFunctions().vkCmdCopyBuffer); } } diff --git a/src/backend/vulkan/VulkanDevice.h b/src/backend/vulkan/VulkanDevice.h index a752ca9..a0e20de 100644 --- a/src/backend/vulkan/VulkanDevice.h +++ b/src/backend/vulkan/VulkanDevice.h @@ -3,7 +3,7 @@ #pragma once #define VK_NO_PROTOTYPES -#define VMA_VULKAN_VERSION 1002000 // Vulkan 1.2 +#define VMA_VULKAN_VERSION 1003000 // Vulkan 1.3 #define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 // define 1 for custom func ptr from volk #define VMA_STATIC_VULKAN_FUNCTIONS 0 // define 0 for custom func ptr from volk #include "vk_mem_alloc.h" diff --git a/src/backend/vulkan/VulkanDevice4.cpp b/src/backend/vulkan/VulkanDevice4.cpp index 815d605..de99c0a 100644 --- a/src/backend/vulkan/VulkanDevice4.cpp +++ b/src/backend/vulkan/VulkanDevice4.cpp @@ -24,9 +24,8 @@ RIVulkanDevice4::CreateBufferHostVisible(uint32_t size, VkBufferUsageFlags usage allocInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; allocInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT; - RIVulkanBuffer buf; + RIVulkanBuffer buf{}; buf.IsMappable = true; - const VkResult result = vmaCreateBuffer(VmaAllocatorObject, &bufferInfo, &allocInfo, &buf.Buffer, &buf.Allocation, nullptr); if (VKFAILED(result)) { From 8190bbfe3d570719251a871d642ab6b16063daad Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Tue, 16 Jul 2024 10:49:04 +0200 Subject: [PATCH 44/58] Added compute commands --- include/IContext.h | 9 +++++++-- src/backend/vulkan/VulkanContext.cpp | 21 +++++++++++++++++++-- src/backend/vulkan/VulkanContext.h | 2 ++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/include/IContext.h b/include/IContext.h index 61ec72d..74534b5 100644 --- a/include/IContext.h +++ b/include/IContext.h @@ -52,8 +52,8 @@ enum EResourceType : uint8_t struct DContextConfig { uint32_t stagingBufferSize{ 64 * 1024 * 1024 }; // 64mb - void (*warningFunction)(const char*){}; - void (*logOutputFunction)(const char*){}; + void (*warningFunction)(const char*){}; + void (*logOutputFunction)(const char*){}; }; struct WindowData @@ -428,6 +428,7 @@ enum class EShaderStage { VERTEX, FRAGMENT, + COMPUTE, ALL }; @@ -516,6 +517,7 @@ struct ShaderByteCode // Compiled shader raw binary data std::vector VertexShader; std::vector PixelShader; + std::vector ComputeShader; }; struct ShaderSource @@ -643,6 +645,7 @@ enum class ERIShaderStage { VERTEX, FRAGMENT, + COMPUTE, ALL }; @@ -806,6 +809,8 @@ class IContext virtual void SetDepthTestCompareOp(uint32_t commandId, bool enabled, bool depthWrite, ECompareOp compareOp) = 0; virtual void SetPrimitiveTopology(uint32_t commandId, ETopology primitiveTopology) = 0; virtual void SetLineWidth(uint32_t commandId, float lineWidth) = 0; + virtual void DispatchCompute(uint32_t commandId, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) = 0; + virtual void ComputeWorkGroupCount(uint32_t* groupCountX, uint32_t* groupCountY, uint32_t* groupCountZ) = 0; virtual uint32_t CreateRenderTarget(EFormat format, ESampleBit samples, bool isDepth, uint32_t width, uint32_t height, uint32_t arrayLength, uint32_t mipMapCount, EResourceState initialState) = 0; virtual void DestroyRenderTarget(uint32_t renderTargetId) = 0; diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index 8d6925f..cec43ed 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -224,14 +224,14 @@ VulkanContext::VulkanContext(const DContextConfig* const config) : _warningOutpu _emptyUbo.Buffer = Device.CreateBufferHostVisible(4, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); _emptyImageId = CreateImage(EFormat::R8G8B8A8_UNORM, 1, 1, 1); - _emptyImage = &GetResource(_images, _emptyImageId); + _emptyImage = &GetResource(_images, _emptyImageId); _emptySampler.Sampler = Device.CreateSampler(VK_FILTER_NEAREST, VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, 0, 1, VK_SAMPLER_MIPMAP_MODE_NEAREST, false, 0.f); { // Transition to attachment optimal const auto graphicsQueue = FindQueue(EQueueType::QUEUE_GRAPHICS); const auto pool = CreateCommandPool(graphicsQueue); - const auto cmd = CreateCommandBuffer(pool); + const auto cmd = CreateCommandBuffer(pool); BeginCommandBuffer(cmd); TextureBarrier barrier{}; barrier.ImageId = _emptyImageId; @@ -2366,6 +2366,23 @@ VulkanContext::SetLineWidth(uint32_t commandId, float lineWidth) vkCmdSetLineWidth(commandBufferRef.Cmd, lineWidth); } +void +VulkanContext::DispatchCompute(uint32_t commandId, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) +{ + auto& commandBufferRef = GetResource(_commandBuffers, commandId); + furyassert(commandBufferRef.IsRecording); // Must be in recording state + + vkCmdDispatch(commandBufferRef.Cmd, groupCountX, groupCountY, groupCountZ); +} + +void +VulkanContext::ComputeWorkGroupCount(uint32_t* groupCountX, uint32_t* groupCountY, uint32_t* groupCountZ) +{ + *groupCountX = Device.DeviceProperties.limits.maxComputeWorkGroupCount[0]; + *groupCountY = Device.DeviceProperties.limits.maxComputeWorkGroupCount[1]; + *groupCountZ = Device.DeviceProperties.limits.maxComputeWorkGroupCount[2]; +} + void VulkanContext::QueueSubmit(uint32_t queueId, const std::vector& waitSemaphore, const std::vector& finishSemaphore, const std::vector& cmdIds, uint32_t fenceId) { diff --git a/src/backend/vulkan/VulkanContext.h b/src/backend/vulkan/VulkanContext.h index 041c05c..c0ce405 100644 --- a/src/backend/vulkan/VulkanContext.h +++ b/src/backend/vulkan/VulkanContext.h @@ -232,6 +232,8 @@ class VulkanContext final : public IContext void SetDepthTestCompareOp(uint32_t commandId, bool enabled, bool depthWrite, ECompareOp compareOp) override; void SetPrimitiveTopology(uint32_t commandId, ETopology primitiveTopology) override; void SetLineWidth(uint32_t commandId, float lineWidth) override; + void DispatchCompute(uint32_t commandId, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) override; + void ComputeWorkGroupCount(uint32_t* groupCountX, uint32_t* groupCountY, uint32_t* groupCountZ) override; uint32_t CreateFence(bool signaled) override; void DestroyFence(uint32_t fenceId) override; From 9cd7772061bb1a4842c46b44cd9ecccb56611a75 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Mon, 22 Jul 2024 09:46:33 +0200 Subject: [PATCH 45/58] improvements --- include/IContext.h | 22 ++++++++ src/backend/vulkan/VulkanContext.cpp | 80 +++++++++++++++++++--------- src/backend/vulkan/VulkanContext.h | 2 + 3 files changed, 80 insertions(+), 24 deletions(-) diff --git a/include/IContext.h b/include/IContext.h index 74534b5..4316d38 100644 --- a/include/IContext.h +++ b/include/IContext.h @@ -130,6 +130,26 @@ enum class EFormat SINT32, }; +inline bool +IsFormatDepth(EFormat format) +{ + return format == EFormat::DEPTH16_UNORM || format == EFormat::DEPTH32_FLOAT || format == EFormat::DEPTH16_UNORM_STENCIL8_UINT || format == EFormat::DEPTH24_UNORM_STENCIL8_UINT || + format == EFormat::DEPTH24_UNORM_STENCIL8_UINT || format == EFormat::DEPTH32_FLOAT_STENCIL8_UINT; +}; + +inline bool +isFormatColor(EFormat format) +{ + return !IsFormatDepth(format); +}; + +inline bool +IsFormatStencil(EFormat format) +{ + return format == EFormat::DEPTH16_UNORM_STENCIL8_UINT || format == EFormat::DEPTH24_UNORM_STENCIL8_UINT || format == EFormat::DEPTH24_UNORM_STENCIL8_UINT || + format == EFormat::DEPTH32_FLOAT_STENCIL8_UINT; +}; + enum class EVertexInputClassification { PER_VERTEX_DATA, @@ -535,6 +555,8 @@ struct DFramebufferAttachments static constexpr uint32_t MAX_ATTACHMENTS = 10; std::array RenderTargets{}; uint32_t DepthStencil{}; + + bool operator==(const DFramebufferAttachments& rhs) const { return memcmp(&RenderTargets[0], &rhs.RenderTargets[0], sizeof(uint32_t) * MAX_ATTACHMENTS) == 0 && DepthStencil == rhs.DepthStencil; }; }; struct DPipelineAttachments diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index cec43ed..b5675d1 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -410,6 +410,18 @@ VulkanContext::_initializeDevice() Log("Intialized vulkan device"); + if (validDeviceValidationLayers.size()) + { + std::string buf{ "Enabled device validation layers:\n" }; + + for (const auto& layer : validDeviceValidationLayers) + { + buf += layer; + buf += "\n"; + } + Log(buf); + } + VkPhysicalDeviceProperties deviceProperties; vkGetPhysicalDeviceProperties(Device.PhysicalDevice, &deviceProperties); Log(std::string("Device: ") + deviceProperties.deviceName); @@ -526,6 +538,9 @@ VulkanContext::CompileNativeShader(const std::vector& blob, std:: case EShaderStage::FRAGMENT: language = EShLangFragment; break; + case EShaderStage::COMPUTE: + language = EShLangCompute; + break; default: furyassert(0); // Invalid shader stage choice break; @@ -1806,22 +1821,33 @@ VulkanContext::_createFramebuffer(const DFramebufferAttachments& attachments) std::vector imageViewsAttachments; imageViewsAttachments.resize((size_t)attachmentCount); - { - // First attachment must always exists - const auto& renderTargetRef = GetResource(_renderTargets, attachments.RenderTargets[0]); - framebufferRef.Width = renderTargetRef.Image.Width; - framebufferRef.Height = renderTargetRef.Image.Height; - } - - for (uint32_t i = 0; i < attachmentCount - depthAttachmentCount; i++) + if (attachments.RenderTargets[0] != 0) { - furyassert(attachments.RenderTargets[i] != NULL); - const auto& renderTargetRef = GetResource(_renderTargets, attachments.RenderTargets[i]); - imageViewsAttachments[i] = renderTargetRef.View; + // Attachments must be specifies from 0 to max without gaps + { + const auto& renderTargetRef = GetResource(_renderTargets, attachments.RenderTargets[0]); + framebufferRef.Width = renderTargetRef.Image.Width; + framebufferRef.Height = renderTargetRef.Image.Height; + } + for (uint32_t i = 0; i < attachmentCount - depthAttachmentCount; i++) + { + furyassert(attachments.RenderTargets[i] != NULL); + const auto& renderTargetRef = GetResource(_renderTargets, attachments.RenderTargets[i]); + imageViewsAttachments[i] = renderTargetRef.View; - furyassert(renderTargetRef.Image.Width == framebufferRef.Width); // All images must have the same width - furyassert(renderTargetRef.Image.Height == framebufferRef.Height); // All images must have the same height - furyassert(renderTargetRef.Image.MipLevels == 1); // Must have only 1 layer + furyassert(renderTargetRef.Image.Width == framebufferRef.Width); // All images must have the same width + furyassert(renderTargetRef.Image.Height == framebufferRef.Height); // All images must have the same height + furyassert(renderTargetRef.Image.MipLevels == 1); // Must have only 1 layer (Vulkan requirement) + } + } + else + { + if (depthAttachmentCount) + { + const auto& renderTargetRef = GetResource(_renderTargets, attachments.DepthStencil); + framebufferRef.Width = renderTargetRef.Image.Width; + framebufferRef.Height = renderTargetRef.Image.Height; + } } if (depthAttachmentCount) @@ -1829,9 +1855,14 @@ VulkanContext::_createFramebuffer(const DFramebufferAttachments& attachments) const auto& renderTargetRef = GetResource(_renderTargets, attachments.DepthStencil); imageViewsAttachments.back() = renderTargetRef.View; - furyassert(renderTargetRef.Image.Width == framebufferRef.Width); // All images must have the same width - furyassert(renderTargetRef.Image.Height == framebufferRef.Height); // All images must have the same height - furyassert(renderTargetRef.Image.MipLevels == 1); // Must have only 1 layer +#if _DEBUG + furyassert(renderTargetRef.Image.MipLevels == 1); // Must have only 1 layer (Vulkan requirement) + if (attachmentCount > depthAttachmentCount) + { + furyassert(renderTargetRef.Image.Width == framebufferRef.Width); // All images must have the same width + furyassert(renderTargetRef.Image.Height == framebufferRef.Height); // All images must have the same height + } +#endif } framebufferRef.Framebuffer = Device._createFramebuffer(imageViewsAttachments, framebufferRef.Width, framebufferRef.Height, vkRenderPass); @@ -1969,7 +2000,10 @@ VulkanContext::BindRenderTargets(uint32_t commandBufferId, const DFramebufferAtt if (fbo.Id == FREE || fbo.Id == PENDING_DESTROY) return false; - return DFramebufferAttachmentEqualFn{}(fbo.Attachments, colorAttachments); + if (fbo.Attachments == colorAttachments) + return true; + + /*return DFramebufferAttachmentEqualFn{}(fbo.Attachments, colorAttachments);*/ }); DFramebufferVulkan* framebufferPtr{}; @@ -2071,12 +2105,10 @@ VulkanContext::BindRenderTargets(uint32_t commandBufferId, const DFramebufferAtt if (commandBufferRef.ActiveRenderPass) { vkCmdEndRenderPass(commandBufferRef.Cmd); - commandBufferRef.ActiveRenderPass = nullptr; } + commandBufferRef.ActiveRenderPass = renderPass; vkCmdBeginRenderPass(commandBufferRef.Cmd, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); - - commandBufferRef.ActiveRenderPass = renderPass; } void @@ -3243,9 +3275,9 @@ VulkanContext::_getDeviceSupportedExtensions(VkPhysicalDevice physicalDevice, co std::vector VulkanContext::_getDeviceSupportedValidationLayers(VkPhysicalDevice physicalDevice, const std::vector& validationLayers) { - const auto validExtentions = VkUtils::getDeviceExtensionProperties(physicalDevice); - const auto validExtentionsNames = VkUtils::convertExtensionPropertiesToNames(validExtentions); - std::vector deviceSupportedValidationLayers = VkUtils::filterInclusive(validationLayers, validExtentionsNames); + const auto validlayers = VkUtils::getDeviceLayerProperties(physicalDevice); + const auto validLayerNames = VkUtils::convertLayerPropertiesToNames(validlayers); + std::vector deviceSupportedValidationLayers = VkUtils::filterInclusive(validationLayers, validLayerNames); // const std::string out = "Available device validation layers requested:" + std::to_string(deviceSupportedValidationLayers.size()) + "/" + std::to_string(validationLayers.size()); // Log(out); diff --git a/src/backend/vulkan/VulkanContext.h b/src/backend/vulkan/VulkanContext.h index c0ce405..bb73277 100644 --- a/src/backend/vulkan/VulkanContext.h +++ b/src/backend/vulkan/VulkanContext.h @@ -53,6 +53,8 @@ struct DFramebufferVulkan : public DResource VkFramebuffer Framebuffer{}; uint32_t Width{}, Height{}; DFramebufferAttachments Attachments; // Used for comparing framebuffers + + bool operator==(const DFramebufferVulkan& rhs) const { return Framebuffer == rhs.Framebuffer && Width == rhs.Width && Height == rhs.Height && Attachments == rhs.Attachments; }; }; struct DSwapchainVulkan : public DResource From 6cc2d470778ccee8314a283d3cbbbabab76b7e32 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Mon, 22 Jul 2024 10:22:39 +0200 Subject: [PATCH 46/58] Fixed destroying depth rt cause dangling framebuffer --- include/IContext.h | 9 ++++++ src/backend/vulkan/VulkanContext.cpp | 41 ++++++++++++---------------- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/include/IContext.h b/include/IContext.h index 4316d38..ad69f95 100644 --- a/include/IContext.h +++ b/include/IContext.h @@ -556,6 +556,15 @@ struct DFramebufferAttachments std::array RenderTargets{}; uint32_t DepthStencil{}; + inline bool HasColorAttachment(uint32_t id) const + { + for (size_t i = 0; i < DFramebufferAttachments::MAX_ATTACHMENTS; i++) + { + if (RenderTargets[i] == id) + return true; + } + return false; + }; bool operator==(const DFramebufferAttachments& rhs) const { return memcmp(&RenderTargets[0], &rhs.RenderTargets[0], sizeof(uint32_t) * MAX_ATTACHMENTS) == 0 && DepthStencil == rhs.DepthStencil; }; }; diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index b5675d1..e2aab34 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -2702,31 +2702,26 @@ VulkanContext::DestroyRenderTarget(uint32_t renderTargetId) auto& renderTargetRef = GetResource(_renderTargets, renderTargetId); // Must destroy all framebuffers that reference this render target @TODO find a better algorithm without iterating over the array multiple times - const auto referenceCount = std::count_if(_framebuffers.begin(), _framebuffers.end(), [renderTargetId](const DFramebufferVulkan& fbo) { - for (size_t i = 0; i < DFramebufferAttachments::MAX_ATTACHMENTS; i++) - { - if (fbo.Attachments.RenderTargets[i] == renderTargetId) - { - return true; - } - } - return false; - }); - for (uint32_t i = 0; i < referenceCount; i++) + for (uint32_t i = 0; i < _framebuffers.size(); i++) { - auto foundFbo = std::find_if(_framebuffers.begin(), _framebuffers.end(), [renderTargetId](const DFramebufferVulkan& fbo) { - for (size_t i = 0; i < DFramebufferAttachments::MAX_ATTACHMENTS; i++) - { - if (fbo.Attachments.RenderTargets[i] == renderTargetId) - { - return true; - } - } - return false; - }); + DFramebufferVulkan& fbo{ _framebuffers[i] }; + if (fbo.Id == FREE || fbo.Id == PENDING_DESTROY) + continue; - Device._destroyFramebuffer(foundFbo->Framebuffer); - foundFbo->Id = FREE; + if (fbo.Attachments.DepthStencil == renderTargetId) + { + Device._destroyFramebuffer(fbo.Framebuffer); + fbo.Framebuffer = nullptr; + fbo.Id = FREE; + break; + } + else if (fbo.Attachments.HasColorAttachment(renderTargetId)) + { + Device._destroyFramebuffer(fbo.Framebuffer); + fbo.Framebuffer = nullptr; + fbo.Id = FREE; + break; + } } Device.DestroyImageView(renderTargetRef.View); From 3a69cf2ff5f4d2bd304a87959d69f1084a923e23 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Wed, 24 Jul 2024 10:56:21 +0200 Subject: [PATCH 47/58] comment --- src/backend/vulkan/VulkanContext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index e2aab34..257e0f0 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -1773,7 +1773,7 @@ VulkanContext::UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t paramCount } break; default: - furyassert(0); // Invalid resource type + furyassert(0); // Invalid resource type, must be a image or render target break; } } From 7e07baa89db6032fa49f59de5e28aa616fcfbf93 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Wed, 24 Jul 2024 15:30:51 +0200 Subject: [PATCH 48/58] bugfix recreating fbo every frame --- src/backend/vulkan/VulkanContext.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index 257e0f0..e2bbb68 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -1997,12 +1997,10 @@ VulkanContext::BindRenderTargets(uint32_t commandBufferId, const DFramebufferAtt // Find existing framebuffer auto framebufferIt = std::find_if(_framebuffers.begin(), _framebuffers.end(), [colorAttachments](const DFramebufferVulkan& fbo) { - if (fbo.Id == FREE || fbo.Id == PENDING_DESTROY) - return false; - - if (fbo.Attachments == colorAttachments) + if (fbo.Id != FREE && fbo.Id != PENDING_DESTROY && fbo.Attachments == colorAttachments) return true; + return false; /*return DFramebufferAttachmentEqualFn{}(fbo.Attachments, colorAttachments);*/ }); From 9a7a3f8a68a522b008a61aca891fd4f8cb396308 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Wed, 24 Jul 2024 17:20:04 +0200 Subject: [PATCH 49/58] fixed wrong log --- src/backend/vulkan/VulkanContext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index e2bbb68..dfb8bd0 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -319,8 +319,8 @@ VulkanContext::_initializeDebugger() { Warning("Failed to create vulkan debug utils messenger"); } -#endif Log("Intialized vulkan debugger"); +#endif } void From 54ebcde5d998030045533c53d1a3dc461bd3c10e Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Mon, 29 Jul 2024 14:49:11 +0200 Subject: [PATCH 50/58] Added command to image to image copy --- include/IContext.h | 51 ++++++------- src/backend/vulkan/VulkanContext.cpp | 104 ++++++++++++++++++++++++++- src/backend/vulkan/VulkanContext.h | 3 +- src/backend/vulkan/VulkanDevice13.h | 10 +-- 4 files changed, 135 insertions(+), 33 deletions(-) diff --git a/include/IContext.h b/include/IContext.h index ad69f95..50b41c6 100644 --- a/include/IContext.h +++ b/include/IContext.h @@ -817,31 +817,32 @@ class IContext virtual uint32_t CreateSampler(uint32_t minLod, uint32_t maxLod) = 0; virtual void DestroySampler(uint32_t samplerId) = 0; - virtual uint32_t CreateCommandPool(uint32_t queueId) = 0; - virtual void DestroyCommandPool(uint32_t commandPoolId) = 0; - virtual void ResetCommandPool(uint32_t commandPoolId) = 0; - virtual uint32_t CreateCommandBuffer(uint32_t commandPoolId) = 0; - virtual void DestroyCommandBuffer(uint32_t commandBufferId) = 0; - virtual void BeginCommandBuffer(uint32_t commandBufferId) = 0; - virtual void EndCommandBuffer(uint32_t commandBufferId) = 0; - virtual void BindRenderTargets(uint32_t commandBufferId, const DFramebufferAttachments& attachments, const DLoadOpPass& loadOP) = 0; - virtual void SetViewport(uint32_t commandBufferId, uint32_t x, uint32_t y, uint32_t width, uint32_t height, float znear, float zfar) = 0; - virtual void SetScissor(uint32_t commandBufferId, uint32_t x, uint32_t y, uint32_t width, uint32_t height) = 0; - virtual void BindPipeline(uint32_t commandBufferId, uint32_t pipeline) = 0; - virtual void BindVertexBuffer(uint32_t commandBufferId, uint32_t bufferId) = 0; - virtual void BindIndexBuffer(uint32_t commandBufferId, uint32_t bufferId) = 0; - virtual void Draw(uint32_t commandBufferId, uint32_t firstVertex, uint32_t count) = 0; - virtual void DrawIndexed(uint32_t commandBufferId, uint32_t index_count, uint32_t first_index, uint32_t first_vertex) = 0; - virtual void DrawIndexedIndirect(uint32_t commandBufferId, uint32_t buffer, uint32_t offset, uint32_t drawCount, uint32_t stride) = 0; - virtual void BindDescriptorSet(uint32_t commandBufferId, uint32_t setIndex, uint32_t descriptorSetId) = 0; - virtual void CopyImage(uint32_t commandId, uint32_t imageId, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t stagingBufferId, uint32_t stagingBufferOffset) = 0; - virtual void CopyBuffer(uint32_t commandId, uint32_t bufferId, uint32_t offset, uint32_t bytes, uint32_t stagingBufferId, uint32_t stagingBufferOffset) = 0; - virtual void SetStencilTest(uint32_t commandId, bool enable, const DStencilOpState* frontFace, const DStencilOpState* backFace) = 0; - virtual void SetDepthTestCompareOp(uint32_t commandId, bool enabled, bool depthWrite, ECompareOp compareOp) = 0; - virtual void SetPrimitiveTopology(uint32_t commandId, ETopology primitiveTopology) = 0; - virtual void SetLineWidth(uint32_t commandId, float lineWidth) = 0; - virtual void DispatchCompute(uint32_t commandId, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) = 0; - virtual void ComputeWorkGroupCount(uint32_t* groupCountX, uint32_t* groupCountY, uint32_t* groupCountZ) = 0; + virtual uint32_t CreateCommandPool(uint32_t queueId) = 0; + virtual void DestroyCommandPool(uint32_t commandPoolId) = 0; + virtual void ResetCommandPool(uint32_t commandPoolId) = 0; + virtual uint32_t CreateCommandBuffer(uint32_t commandPoolId) = 0; + virtual void DestroyCommandBuffer(uint32_t commandBufferId) = 0; + virtual void BeginCommandBuffer(uint32_t commandBufferId) = 0; + virtual void EndCommandBuffer(uint32_t commandBufferId) = 0; + virtual void BindRenderTargets(uint32_t commandBufferId, const DFramebufferAttachments& attachments, const DLoadOpPass& loadOP) = 0; + virtual void SetViewport(uint32_t commandBufferId, uint32_t x, uint32_t y, uint32_t width, uint32_t height, float znear, float zfar) = 0; + virtual void SetScissor(uint32_t commandBufferId, uint32_t x, uint32_t y, uint32_t width, uint32_t height) = 0; + virtual void BindPipeline(uint32_t commandBufferId, uint32_t pipeline) = 0; + virtual void BindVertexBuffer(uint32_t commandBufferId, uint32_t bufferId) = 0; + virtual void BindIndexBuffer(uint32_t commandBufferId, uint32_t bufferId) = 0; + virtual void Draw(uint32_t commandBufferId, uint32_t firstVertex, uint32_t count) = 0; + virtual void DrawIndexed(uint32_t commandBufferId, uint32_t index_count, uint32_t first_index, uint32_t first_vertex) = 0; + virtual void DrawIndexedIndirect(uint32_t commandBufferId, uint32_t buffer, uint32_t offset, uint32_t drawCount, uint32_t stride) = 0; + virtual void BindDescriptorSet(uint32_t commandBufferId, uint32_t setIndex, uint32_t descriptorSetId) = 0; + virtual void CopyImage(uint32_t commandId, uint32_t destImage, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t sourceImage) = 0; + virtual void CopyBufferToImage(uint32_t commandId, uint32_t imageId, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t stagingBufferId, uint32_t stagingBufferOffset) = 0; + virtual void CopyBuffer(uint32_t commandId, uint32_t bufferId, uint32_t offset, uint32_t bytes, uint32_t stagingBufferId, uint32_t stagingBufferOffset) = 0; + virtual void SetStencilTest(uint32_t commandId, bool enable, const DStencilOpState* frontFace, const DStencilOpState* backFace) = 0; + virtual void SetDepthTestCompareOp(uint32_t commandId, bool enabled, bool depthWrite, ECompareOp compareOp) = 0; + virtual void SetPrimitiveTopology(uint32_t commandId, ETopology primitiveTopology) = 0; + virtual void SetLineWidth(uint32_t commandId, float lineWidth) = 0; + virtual void DispatchCompute(uint32_t commandId, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) = 0; + virtual void ComputeWorkGroupCount(uint32_t* groupCountX, uint32_t* groupCountY, uint32_t* groupCountZ) = 0; virtual uint32_t CreateRenderTarget(EFormat format, ESampleBit samples, bool isDepth, uint32_t width, uint32_t height, uint32_t arrayLength, uint32_t mipMapCount, EResourceState initialState) = 0; virtual void DestroyRenderTarget(uint32_t renderTargetId) = 0; diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index dfb8bd0..a96fe39 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -1191,6 +1191,10 @@ VulkanContext::CreateImage(EFormat format, uint32_t width, uint32_t height, uint VK_IMAGE_LAYOUT_UNDEFINED); image.ImageAspect = VkUtils::isColorFormat(vkFormat) ? VK_IMAGE_ASPECT_COLOR_BIT : VK_IMAGE_ASPECT_DEPTH_BIT; + if (VkUtils::formatHasStencil(vkFormat)) + { + image.ImageAspect |= VK_IMAGE_ASPECT_STENCIL_BIT; + } const VkResult result = Device.CreateImageView(vkFormat, image.Image.Image, image.ImageAspect, 0, mipMapCount, &image.View); if (VKFAILED(result)) @@ -1261,7 +1265,7 @@ VulkanContext::CreateVertexLayout(const std::vector& info) ShaderId VulkanContext::CreateShader(const ShaderSource& source) { - furyassert(source.ColorAttachments > 0); + //furyassert(source.ColorAttachments > 0); const auto index = AllocResource(_shaders); DShaderVulkan& shader = _shaders.at(index); @@ -2245,7 +2249,103 @@ VulkanContext::BindDescriptorSet(uint32_t commandBufferId, uint32_t setIndex, ui } void -VulkanContext::CopyImage(uint32_t commandId, uint32_t imageId, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t stagingBufferId, uint32_t stagingBufferOffset) +VulkanContext::CopyImage(uint32_t commandId, uint32_t destImage, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t sourceImage) +{ + const auto& commandBufferRef = GetResource(_commandBuffers, commandId); + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(!commandBufferRef.ActiveRenderPass); // Must be in a render pass + + VkImageCopy region{}; + // region.srcSubresource.aspectMask = sourceImageRef.ImageAspect; + region.srcSubresource.mipLevel = mipMapIndex; + region.srcSubresource.baseArrayLayer = 0; + region.srcSubresource.layerCount = VK_REMAINING_MIP_LEVELS; + region.srcOffset.x; + region.srcOffset.y; + region.srcOffset.z; + // region.dstSubresource.aspectMask = destImageRef.ImageAspect; + region.dstSubresource.mipLevel = mipMapIndex; + region.dstSubresource.baseArrayLayer = 0; + region.dstSubresource.layerCount = VK_REMAINING_MIP_LEVELS; + region.dstOffset.x; + region.dstOffset.y; + region.dstOffset.z; + region.extent.width = width; + region.extent.height = height; + region.extent.depth = 1; + + VkImage srcImage{}; + VkImage dstImage{}; + + switch ((EResourceType)ResourceId(sourceImage).First()) + { + case EResourceType::IMAGE: + { + const auto& sourceImageRef = GetResource(_images, sourceImage); + region.srcSubresource.aspectMask = sourceImageRef.ImageAspect; + srcImage = sourceImageRef.Image.Image; + } + break; + case EResourceType::RENDER_TARGET: + { + const auto& sourceImageRef = GetResource(_renderTargets, sourceImage); + region.srcSubresource.aspectMask = sourceImageRef.ImageAspect; + srcImage = sourceImageRef.Image.Image; + } + break; + + default: + furyassert(0); + break; + }; + + switch ((EResourceType)ResourceId(destImage).First()) + { + case EResourceType::IMAGE: + { + const auto& destImageRef = GetResource(_images, destImage); + region.dstSubresource.aspectMask = destImageRef.ImageAspect; + dstImage = destImageRef.Image.Image; + } + break; + case EResourceType::RENDER_TARGET: + { + const auto& destImageRef = GetResource(_renderTargets, destImage); + region.dstSubresource.aspectMask = destImageRef.ImageAspect; + dstImage = destImageRef.Image.Image; + } + break; + + default: + furyassert(0); + break; + }; +#if _DEBUG + { + if (region.srcSubresource.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) + { + furyassert(region.dstSubresource.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT); + } + else if (region.srcSubresource.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) + { + furyassert(region.dstSubresource.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT); + } + else if (region.srcSubresource.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT && region.srcSubresource.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) + { + furyassert(region.dstSubresource.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT && region.srcSubresource.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT); + } + } +#endif + furyassert(srcImage); + furyassert(dstImage); + + const VkImageLayout sourceLayout{ VkImageLayout::VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL }; + const VkImageLayout destLayout{ VkImageLayout::VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL }; + vkCmdCopyImage(commandBufferRef.Cmd, srcImage, sourceLayout, dstImage, destLayout, 1, ®ion); +} + +void +VulkanContext::CopyBufferToImage(uint32_t commandId, uint32_t imageId, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t stagingBufferId, uint32_t stagingBufferOffset) { auto& commandBufferRef = GetResource(_commandBuffers, commandId); furyassert(commandBufferRef.IsRecording); // Must be in recording state diff --git a/src/backend/vulkan/VulkanContext.h b/src/backend/vulkan/VulkanContext.h index bb73277..99ba561 100644 --- a/src/backend/vulkan/VulkanContext.h +++ b/src/backend/vulkan/VulkanContext.h @@ -228,7 +228,8 @@ class VulkanContext final : public IContext void DrawIndexed(uint32_t commandBufferId, uint32_t index_count, uint32_t first_index, uint32_t first_vertex) override; void DrawIndexedIndirect(uint32_t commandBufferId, uint32_t buffer, uint32_t offset, uint32_t drawCount, uint32_t stride) override; void BindDescriptorSet(uint32_t commandBufferId, uint32_t setIndex, uint32_t descriptorSetId) override; - void CopyImage(uint32_t commandId, uint32_t imageId, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t stagingBufferId, uint32_t stagingBufferOffset) override; + void CopyImage(uint32_t commandId, uint32_t destImage, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t sourceImage) override; + void CopyBufferToImage(uint32_t commandId, uint32_t imageId, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t stagingBufferId, uint32_t stagingBufferOffset) override; void CopyBuffer(uint32_t commandId, uint32_t bufferId, uint32_t offset, uint32_t bytes, uint32_t stagingBufferId, uint32_t stagingBufferOffset) override; void SetStencilTest(uint32_t commandId, bool enable, const DStencilOpState* frontFace, const DStencilOpState* backFace) override; void SetDepthTestCompareOp(uint32_t commandId, bool enabled, bool depthWrite, ECompareOp compareOp) override; diff --git a/src/backend/vulkan/VulkanDevice13.h b/src/backend/vulkan/VulkanDevice13.h index 126e157..7b3cf23 100644 --- a/src/backend/vulkan/VulkanDevice13.h +++ b/src/backend/vulkan/VulkanDevice13.h @@ -85,11 +85,11 @@ struct VkSubpassDescriptionHashFn seed ^= std::hash{}(subpassDesc.flags) ^ 0x9e3779b9; seed += std::hash{}(subpassDesc.pipelineBindPoint) ^ 0x9e3779b1; seed ^= std::hash{}(subpassDesc.inputAttachmentCount); - // for (uint32_t i = 0; i < subpassDesc.inputAttachmentCount; i++) - // { - // const VkAttachmentReference* ref = subpassDesc.pInputAttachments + i; - // seed ^= VkAttachmentReferenceHashFn{}(*ref); - // } + for (uint32_t i = 0; i < subpassDesc.inputAttachmentCount; i++) + { + const VkAttachmentReference* ref = subpassDesc.pInputAttachments + i; + seed ^= VkAttachmentReferenceHashFn{}(*ref); + } seed += std::hash{}(subpassDesc.colorAttachmentCount) ^ 0x9e3779b9; // for (uint32_t i = 0; i < subpassDesc.colorAttachmentCount; i++) // { From 8b32736d1b717c4d081d308ba648dd0dfbe29121 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Tue, 30 Jul 2024 09:24:57 +0200 Subject: [PATCH 51/58] added mip map count to copyImage function --- include/IContext.h | 2 +- src/backend/vulkan/VulkanContext.cpp | 11 ++++++----- src/backend/vulkan/VulkanContext.h | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/include/IContext.h b/include/IContext.h index 50b41c6..e13d371 100644 --- a/include/IContext.h +++ b/include/IContext.h @@ -834,7 +834,7 @@ class IContext virtual void DrawIndexed(uint32_t commandBufferId, uint32_t index_count, uint32_t first_index, uint32_t first_vertex) = 0; virtual void DrawIndexedIndirect(uint32_t commandBufferId, uint32_t buffer, uint32_t offset, uint32_t drawCount, uint32_t stride) = 0; virtual void BindDescriptorSet(uint32_t commandBufferId, uint32_t setIndex, uint32_t descriptorSetId) = 0; - virtual void CopyImage(uint32_t commandId, uint32_t destImage, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t sourceImage) = 0; + virtual void CopyImage(uint32_t commandId, uint32_t destImage, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t mipMapCount, uint32_t sourceImage) = 0; virtual void CopyBufferToImage(uint32_t commandId, uint32_t imageId, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t stagingBufferId, uint32_t stagingBufferOffset) = 0; virtual void CopyBuffer(uint32_t commandId, uint32_t bufferId, uint32_t offset, uint32_t bytes, uint32_t stagingBufferId, uint32_t stagingBufferOffset) = 0; virtual void SetStencilTest(uint32_t commandId, bool enable, const DStencilOpState* frontFace, const DStencilOpState* backFace) = 0; diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index a96fe39..69991e0 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -1265,7 +1265,7 @@ VulkanContext::CreateVertexLayout(const std::vector& info) ShaderId VulkanContext::CreateShader(const ShaderSource& source) { - //furyassert(source.ColorAttachments > 0); + // furyassert(source.ColorAttachments > 0); const auto index = AllocResource(_shaders); DShaderVulkan& shader = _shaders.at(index); @@ -2249,7 +2249,7 @@ VulkanContext::BindDescriptorSet(uint32_t commandBufferId, uint32_t setIndex, ui } void -VulkanContext::CopyImage(uint32_t commandId, uint32_t destImage, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t sourceImage) +VulkanContext::CopyImage(uint32_t commandId, uint32_t destImage, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t mipMapCount, uint32_t sourceImage) { const auto& commandBufferRef = GetResource(_commandBuffers, commandId); furyassert(commandBufferRef.IsRecording); // Must be in recording state @@ -2259,14 +2259,14 @@ VulkanContext::CopyImage(uint32_t commandId, uint32_t destImage, uint32_t width, // region.srcSubresource.aspectMask = sourceImageRef.ImageAspect; region.srcSubresource.mipLevel = mipMapIndex; region.srcSubresource.baseArrayLayer = 0; - region.srcSubresource.layerCount = VK_REMAINING_MIP_LEVELS; + region.srcSubresource.layerCount = mipMapCount; region.srcOffset.x; region.srcOffset.y; region.srcOffset.z; // region.dstSubresource.aspectMask = destImageRef.ImageAspect; region.dstSubresource.mipLevel = mipMapIndex; region.dstSubresource.baseArrayLayer = 0; - region.dstSubresource.layerCount = VK_REMAINING_MIP_LEVELS; + region.dstSubresource.layerCount = mipMapCount; region.dstOffset.x; region.dstOffset.y; region.dstOffset.z; @@ -2775,7 +2775,8 @@ VulkanContext::CreateRenderTarget(EFormat format, ESampleBit samples, bool isDep const auto index = AllocResource(_renderTargets); auto& renderTargetRef = _renderTargets.at(index); - renderTargetRef.Image = Device.CreateImageDeviceLocal(width, height, mipMapCount, vkFormat, usageFlags, VK_IMAGE_TILING_OPTIMAL, initialLayout); + renderTargetRef.Image = + Device.CreateImageDeviceLocal(width, height, mipMapCount, vkFormat, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | usageFlags, VK_IMAGE_TILING_OPTIMAL, initialLayout); renderTargetRef.ImageAspect = VkUtils::isColorFormat(vkFormat) ? VK_IMAGE_ASPECT_COLOR_BIT : VK_IMAGE_ASPECT_DEPTH_BIT; if (VkUtils::formatHasStencil(vkFormat)) diff --git a/src/backend/vulkan/VulkanContext.h b/src/backend/vulkan/VulkanContext.h index 99ba561..23f6d27 100644 --- a/src/backend/vulkan/VulkanContext.h +++ b/src/backend/vulkan/VulkanContext.h @@ -228,7 +228,7 @@ class VulkanContext final : public IContext void DrawIndexed(uint32_t commandBufferId, uint32_t index_count, uint32_t first_index, uint32_t first_vertex) override; void DrawIndexedIndirect(uint32_t commandBufferId, uint32_t buffer, uint32_t offset, uint32_t drawCount, uint32_t stride) override; void BindDescriptorSet(uint32_t commandBufferId, uint32_t setIndex, uint32_t descriptorSetId) override; - void CopyImage(uint32_t commandId, uint32_t destImage, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t sourceImage) override; + void CopyImage(uint32_t commandId, uint32_t destImage, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t mipMapCount, uint32_t sourceImage) override; void CopyBufferToImage(uint32_t commandId, uint32_t imageId, uint32_t width, uint32_t height, uint32_t mipMapIndex, uint32_t stagingBufferId, uint32_t stagingBufferOffset) override; void CopyBuffer(uint32_t commandId, uint32_t bufferId, uint32_t offset, uint32_t bytes, uint32_t stagingBufferId, uint32_t stagingBufferOffset) override; void SetStencilTest(uint32_t commandId, bool enable, const DStencilOpState* frontFace, const DStencilOpState* backFace) override; From befc3282d7a609fb617dad3b4339e2b3633638d1 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Mon, 12 Aug 2024 11:43:21 +0200 Subject: [PATCH 52/58] Compute shaders, sampler params, storage images, anisotropy getter --- include/IContext.h | 75 ++++-- src/backend/vulkan/UtilsVk.h | 61 ++++- src/backend/vulkan/VulkanContext.cpp | 388 ++++++++++++++++++++++----- src/backend/vulkan/VulkanContext.h | 70 ++++- src/backend/vulkan/VulkanDevice6.cpp | 2 +- 5 files changed, 500 insertions(+), 96 deletions(-) diff --git a/include/IContext.h b/include/IContext.h index e13d371..5f7720f 100644 --- a/include/IContext.h +++ b/include/IContext.h @@ -35,7 +35,7 @@ enum EResourceType : uint8_t SWAPCHAIN = 5, FRAMEBUFFER = 6, IMAGE = 7, - GRAPHICS_PIPELINE = 8, + PIPELINE = 8, COMMAND_POOL = 9, COMMAND_BUFFER = 10, FENCE = 11, @@ -49,6 +49,28 @@ enum EResourceType : uint8_t }; // SHOULD BE PRIVATE +enum class EFilter : uint8_t +{ + NEAREST, + LINEAR, + CUBIC, // May not be supported on all hardware +}; + +enum class ESamplerAddressMode +{ + REPEAT, + MIRRORED_REPEAT, + CLAMP_TO_EDGE, + CLAMP_TO_BORDER, + MIRROR_CLAMP_TO_EDGE,//not all implementations could support it, +}; + +enum class ESamplerMipmapMode +{ + NEAREST, + LINEAR, +}; + struct DContextConfig { uint32_t stagingBufferSize{ 64 * 1024 * 1024 }; // 64mb @@ -440,6 +462,7 @@ enum class EBindingType UNIFORM_BUFFER_OBJECT, STORAGE_BUFFER_OBJECT, TEXTURE, + STORAGE_IMAGE, SAMPLER, COMBINED_IMAGE_SAMPLER, }; @@ -752,6 +775,8 @@ typedef struct DescriptorData uint32_t Index{}; uint32_t BufferOffset{}; uint32_t BufferRange{}; + uint32_t MipMapIndex{}; + uint32_t MipMapCount{ 1 }; union { @@ -797,25 +822,34 @@ class IContext */ virtual uint32_t FindQueue(EQueueType queueType) = 0; - virtual uint32_t CreateBuffer(uint32_t size, EResourceType type, EMemoryUsage usage) = 0; - virtual void* BeginMapBuffer(uint32_t buffer) = 0; - virtual void EndMapBuffer(uint32_t buffer) = 0; - virtual void DestroyBuffer(uint32_t buffer) = 0; - virtual ImageId CreateImage(EFormat format, uint32_t width, uint32_t height, uint32_t mipMapCount) = 0; - virtual EFormat GetImageFormat(ImageId) const = 0; - virtual void DestroyImage(ImageId imageId) = 0; - virtual uint32_t CreateVertexLayout(const std::vector& info) = 0; - virtual uint32_t CreateShader(const ShaderSource& source) = 0; - virtual void DestroyShader(const uint32_t shader) = 0; - virtual uint32_t CreatePipeline(const uint32_t shader, uint32_t rootSignatureId, const DPipelineAttachments& attachments, const PipelineFormat& format) = 0; - virtual void DestroyPipeline(uint32_t pipelineId) = 0; - virtual uint32_t CreateRootSignature(const ShaderLayout& layout) = 0; - virtual void DestroyRootSignature(uint32_t rootSignatureId) = 0; - virtual uint32_t CreateDescriptorSets(uint32_t rootSignatureId, EDescriptorFrequency frequency, uint32_t count) = 0; - virtual void DestroyDescriptorSet(uint32_t descriptorSetId) = 0; - virtual void UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t paramCount, DescriptorData* params) = 0; - virtual uint32_t CreateSampler(uint32_t minLod, uint32_t maxLod) = 0; - virtual void DestroySampler(uint32_t samplerId) = 0; + virtual uint32_t CreateBuffer(uint32_t size, EResourceType type, EMemoryUsage usage) = 0; + virtual void* BeginMapBuffer(uint32_t buffer) = 0; + virtual void EndMapBuffer(uint32_t buffer) = 0; + virtual void DestroyBuffer(uint32_t buffer) = 0; + virtual ImageId CreateImage(EFormat format, uint32_t width, uint32_t height, uint32_t mipMapCount, bool isDepth = false, bool isStencil = false) = 0; + virtual ImageId CreateStorageImage(EFormat format, uint32_t width, uint32_t height, uint32_t mipMapCount, bool isDepth = false, bool isStencil = false) = 0; + virtual EFormat GetImageFormat(ImageId) const = 0; + virtual void DestroyImage(ImageId imageId) = 0; + virtual uint32_t CreateVertexLayout(const std::vector& info) = 0; + virtual uint32_t CreateShader(const ShaderSource& source) = 0; + virtual void DestroyShader(const uint32_t shader) = 0; + virtual uint32_t CreateComputePipeline(const uint32_t shader, const uint32_t rootSignatureId) = 0; + virtual uint32_t CreatePipeline(const uint32_t shader, uint32_t rootSignatureId, const DPipelineAttachments& attachments, const PipelineFormat& format) = 0; + virtual void DestroyPipeline(uint32_t pipelineId) = 0; + virtual uint32_t CreateRootSignature(const ShaderLayout& layout) = 0; + virtual void DestroyRootSignature(uint32_t rootSignatureId) = 0; + virtual uint32_t CreateDescriptorSets(uint32_t rootSignatureId, EDescriptorFrequency frequency, uint32_t count) = 0; + virtual void DestroyDescriptorSet(uint32_t descriptorSetId) = 0; + virtual void UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t paramCount, DescriptorData* params) = 0; + virtual uint32_t CreateSampler(uint32_t minLod, + uint32_t maxLod, + EFilter minFilter, + EFilter magFilter, + ESamplerAddressMode addressMode, + ESamplerMipmapMode mipMapMode, + bool anisotropicFiltering, + float anisotropicFilter = 16.f) = 0; + virtual void DestroySampler(uint32_t samplerId) = 0; virtual uint32_t CreateCommandPool(uint32_t queueId) = 0; virtual void DestroyCommandPool(uint32_t commandPoolId) = 0; @@ -877,5 +911,6 @@ class IContext virtual unsigned char* GetAdapterDescription() const = 0; virtual size_t GetAdapterDedicatedVideoMemory() const = 0; + virtual float GetMaxAnisotropyFiltering(bool* isSupported = nullptr) const = 0; }; } \ No newline at end of file diff --git a/src/backend/vulkan/UtilsVk.h b/src/backend/vulkan/UtilsVk.h index 441d9fa..a49d054 100644 --- a/src/backend/vulkan/UtilsVk.h +++ b/src/backend/vulkan/UtilsVk.h @@ -535,6 +535,9 @@ convertDescriptorBindings(const std::map(_images, _emptyImageId); + _emptyStorageImageId = CreateStorageImage(EFormat::R8G8B8A8_UNORM, 1, 1, 1); + _emptyStorageImage = &GetResource(_images, _emptyStorageImageId); _emptySampler.Sampler = Device.CreateSampler(VK_FILTER_NEAREST, VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, 0, 1, VK_SAMPLER_MIPMAP_MODE_NEAREST, false, 0.f); { // Transition to attachment optimal @@ -238,6 +240,10 @@ VulkanContext::VulkanContext(const DContextConfig* const config) : _warningOutpu barrier.CurrentState = EResourceState::UNDEFINED; barrier.NewState = EResourceState::SHADER_RESOURCE; ResourceBarrier(cmd, 0, nullptr, 1, &barrier, 0, nullptr); + barrier.ImageId = _emptyStorageImageId; + barrier.CurrentState = EResourceState::UNDEFINED; + barrier.NewState = EResourceState::UNORDERED_ACCESS; + ResourceBarrier(cmd, 0, nullptr, 1, &barrier, 0, nullptr); EndCommandBuffer(cmd); const auto fence = CreateFence(false); @@ -459,6 +465,7 @@ VulkanContext::~VulkanContext() Device.DestroyBuffer(_emptyUbo.Buffer); DestroyImage(_emptyImageId); + DestroyImage(_emptyStorageImageId); Device.DestroySampler(_emptySampler.Sampler); #if _DEBUG @@ -746,7 +753,12 @@ VulkanContext::SwapchainHasValidSurface(SwapchainId swapchainId) for (uint32_t i = 0; i < swapchain.ImagesCount; i++) { auto& imageRef = GetResource(_images, swapchain.ImagesId[i]); - Device.DestroyImageView(imageRef.View); + + for (auto it = imageRef.ImageViews.begin(); it != imageRef.ImageViews.end(); it++) + { + Device.DestroyImageView(it->second); + } + imageRef.Id = FREE; const auto renderTargetId{ swapchain.RenderTargetsId[i] }; @@ -909,13 +921,6 @@ VulkanContext::_createImageFromVkImage(VkImage vkimage, VkFormat format, uint32_ // Create renderTargetRef view image.ImageAspect = VkUtils::isColorFormat(format) ? VK_IMAGE_ASPECT_COLOR_BIT : VK_IMAGE_ASPECT_DEPTH_BIT; - { - const VkResult result = Device.CreateImageView(format, image.Image.Image, image.ImageAspect, 0, 1, &image.View); - if (VKFAILED(result)) - { - throw std::runtime_error(VkUtils::VkErrorString(result)); - } - } return *ResourceId(EResourceType::IMAGE, image.Id, index); } @@ -935,7 +940,12 @@ VulkanContext::DestroySwapchain(SwapchainId swapchainId) for (uint32_t i = 0; i < swapchain.ImagesCount; i++) { auto& imageRef = GetResource(_images, swapchain.ImagesId[i]); - Device.DestroyImageView(imageRef.View); + + for (auto it = imageRef.ImageViews.begin(); it != imageRef.ImageViews.end(); it++) + { + Device.DestroyImageView(it->second); + } + imageRef.Id = FREE; const auto renderTargetId{ swapchain.RenderTargetsId[i] }; @@ -1173,7 +1183,7 @@ VulkanContext::DestroyBuffer(BufferId buffer) } ImageId -VulkanContext::CreateImage(EFormat format, uint32_t width, uint32_t height, uint32_t mipMapCount) +VulkanContext::CreateImage(EFormat format, uint32_t width, uint32_t height, uint32_t mipMapCount, bool isDepth, bool isStencil) { const auto index = AllocResource(_images); @@ -1190,16 +1200,40 @@ VulkanContext::CreateImage(EFormat format, uint32_t width, uint32_t height, uint VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_LAYOUT_UNDEFINED); - image.ImageAspect = VkUtils::isColorFormat(vkFormat) ? VK_IMAGE_ASPECT_COLOR_BIT : VK_IMAGE_ASPECT_DEPTH_BIT; - if (VkUtils::formatHasStencil(vkFormat)) + image.ImageAspect = VkUtils::isColorFormat(vkFormat) && (!isDepth && !isStencil) ? VK_IMAGE_ASPECT_COLOR_BIT : VK_IMAGE_ASPECT_DEPTH_BIT; + if (VkUtils::formatHasStencil(vkFormat) || isStencil) { image.ImageAspect |= VK_IMAGE_ASPECT_STENCIL_BIT; } - const VkResult result = Device.CreateImageView(vkFormat, image.Image.Image, image.ImageAspect, 0, mipMapCount, &image.View); - if (VKFAILED(result)) + // Create default sampler + image.Sampler = Device.CreateSampler(VK_FILTER_NEAREST, VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT, (float)0, (float)mipMapCount, VK_SAMPLER_MIPMAP_MODE_NEAREST, true, 16); + + return *ResourceId(EResourceType::IMAGE, image.Id, index); +} + +ImageId +VulkanContext::CreateStorageImage(EFormat format, uint32_t width, uint32_t height, uint32_t mipMapCount, bool isDepth, bool isStencil) +{ + + const auto index = AllocResource(_images); + DImageVulkan& image = _images.at(index); + + const auto vkFormat = VkUtils::convertFormat(format); + + const VkImageUsageFlags fomatAttachment = 0; // VkUtils::isColorFormat(vkFormat) ? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT : VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + image.Image = Device.CreateImageDeviceLocal(width, + height, + mipMapCount, + vkFormat, + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | fomatAttachment | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_LAYOUT_UNDEFINED); + + image.ImageAspect = VkUtils::isColorFormat(vkFormat) ? VK_IMAGE_ASPECT_COLOR_BIT : VK_IMAGE_ASPECT_DEPTH_BIT; + if (VkUtils::formatHasStencil(vkFormat)) { - throw std::runtime_error(VkUtils::VkErrorString(result)); + image.ImageAspect |= VK_IMAGE_ASPECT_STENCIL_BIT; } // Create default sampler @@ -1232,7 +1266,12 @@ VulkanContext::DestroyImage(ImageId imageId) // resource.Id = FREE; //}); - Device.DestroyImageView(resource.View); + + for (auto it = resource.ImageViews.begin(); it != resource.ImageViews.end(); it++) + { + Device.DestroyImageView(it->second); + } + Device.DestroyImage(resource.Image); Device.DestroySampler(resource.Sampler); resource.Id = FREE; @@ -1285,25 +1324,36 @@ VulkanContext::_createShader(const ShaderSource& source, DShaderVulkan& shader) // Create the shaders { + if (source.SourceCode.VertexShader.size()) + { + const VkResult result = VkUtils::createShaderModule(Device.Device, source.SourceCode.VertexShader, &shader.VertexShaderModule); + if (VKFAILED(result)) + { + throw std::runtime_error(VkUtils::VkErrorString(result)); + } + shader.ShaderStageCreateInfo.push_back(VkUtils::createShaderStageInfo(VkShaderStageFlagBits::VK_SHADER_STAGE_VERTEX_BIT, shader.VertexShaderModule)); + } + if (source.SourceCode.ComputeShader.size()) + { - { - const VkResult result = VkUtils::createShaderModule(Device.Device, source.SourceCode.VertexShader, &shader.VertexShaderModule); - if (VKFAILED(result)) - { - throw std::runtime_error(VkUtils::VkErrorString(result)); - } - shader.ShaderStageCreateInfo.push_back(VkUtils::createShaderStageInfo(VkShaderStageFlagBits::VK_SHADER_STAGE_VERTEX_BIT, shader.VertexShaderModule)); - } + const VkResult result = VkUtils::createShaderModule(Device.Device, source.SourceCode.ComputeShader, &shader.ComputeShaderModule); + if (VKFAILED(result)) + { + throw std::runtime_error(VkUtils::VkErrorString(result)); + } + shader.ShaderStageCreateInfo.push_back(VkUtils::createShaderStageInfo(VkShaderStageFlagBits::VK_SHADER_STAGE_COMPUTE_BIT, shader.ComputeShaderModule)); + } - { + if (source.SourceCode.PixelShader.size()) + { - const VkResult result = VkUtils::createShaderModule(Device.Device, source.SourceCode.PixelShader, &shader.PixelShaderModule); - if (VKFAILED(result)) - { - throw std::runtime_error(VkUtils::VkErrorString(result)); - } - shader.ShaderStageCreateInfo.push_back(VkUtils::createShaderStageInfo(VkShaderStageFlagBits::VK_SHADER_STAGE_FRAGMENT_BIT, shader.PixelShaderModule)); - } + const VkResult result = VkUtils::createShaderModule(Device.Device, source.SourceCode.PixelShader, &shader.PixelShaderModule); + if (VKFAILED(result)) + { + throw std::runtime_error(VkUtils::VkErrorString(result)); + } + shader.ShaderStageCreateInfo.push_back(VkUtils::createShaderStageInfo(VkShaderStageFlagBits::VK_SHADER_STAGE_FRAGMENT_BIT, shader.PixelShaderModule)); + } } } @@ -1325,12 +1375,37 @@ VulkanContext::DestroyShader(const ShaderId shader) } uint32_t -VulkanContext::CreateSampler(uint32_t minLod, uint32_t maxLod) +VulkanContext::CreateSampler(uint32_t minLod, +uint32_t maxLod, +EFilter minFilter, +EFilter magFilter, +ESamplerAddressMode addressMode, +ESamplerMipmapMode mipMapMode, +bool anisotropicFiltering, +float anisotropicFilter) { const auto index = AllocResource(_samplers); DSamplerVulkan& samplerRef = _samplers.at(index); +#if _DEBUG + if (anisotropicFiltering) + { + furyassert(anisotropicFilter > 0.f); + } +#endif + + samplerRef.Sampler = Device.CreateSampler(VkUtils::convertEFilterToVkFilter(minFilter), + VkUtils::convertEFilterToVkFilter(magFilter), + VkUtils::convertESamplerAddressModeToVkSamplerAddressMode(addressMode), + (float)minLod, + (float)maxLod, + VkUtils::convertESamplerMipmapModeToVkSamplerMipmapMode(mipMapMode), + anisotropicFiltering, + anisotropicFilter); - samplerRef.Sampler = Device.CreateSampler(VkFilter::VK_FILTER_LINEAR, VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT, (float)minLod, (float)maxLod, VK_SAMPLER_MIPMAP_MODE_LINEAR, true, 16); + // samplerRef.Sampler = Device.CreateSampler(VkFilter::VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_ADDRESS_MODE_REPEAT, (float)minLod, (float)maxLod, //VK_SAMPLER_MIPMAP_MODE_NEAREST, false, + // 0); + // + // samplerRef.Sampler = Device.CreateSampler(VkFilter::VK_FILTER_LINEAR, VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT, (float)minLod, (float)maxLod, VK_SAMPLER_MIPMAP_MODE_LINEAR, true, 16); return *ResourceId(EResourceType::SAMPLER, samplerRef.Id, index); } @@ -1346,6 +1421,44 @@ VulkanContext::DestroySampler(uint32_t samplerId) sampler.Sampler = nullptr; } +uint32_t +VulkanContext::CreateComputePipeline(const uint32_t shader, const uint32_t rootSignatureId) +{ + const auto& shaderRef = GetResource(_shaders, shader); + const DRootSignature& rootSignature = GetResource(_rootSignatures, rootSignatureId); + + VkPipelineShaderStageCreateInfo stageinfo{}; + stageinfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + stageinfo.pNext = nullptr; + stageinfo.stage = VK_SHADER_STAGE_COMPUTE_BIT; + stageinfo.module = shaderRef.ComputeShaderModule; + stageinfo.pName = "main"; + + VkComputePipelineCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; + createInfo.pNext = nullptr; + createInfo.flags = 0; + createInfo.stage = stageinfo; + createInfo.layout = rootSignature.PipelineLayout; + createInfo.basePipelineHandle = VK_NULL_HANDLE; // unused + createInfo.basePipelineIndex = NULL; // unused + + VkPipeline pipeline{}; + const VkResult result{ vkCreateComputePipelines(Device.Device, VK_NULL_HANDLE, 1, &createInfo, nullptr, &pipeline) }; + if (VKFAILED(result)) + { + throw std::runtime_error(VkUtils::VkErrorString(result)); + } + + const auto index = AllocResource(_pipelines); + DPipelineVulkan& pso = _pipelines.at(index); + pso.Pipeline = pipeline; + pso.PipelineLayout = &rootSignature.PipelineLayout; + pso.Type = EPipelineType::COMPUTE; + + return *ResourceId(EResourceType::PIPELINE, pso.Id, index); +} + uint32_t VulkanContext::CreatePipeline(const ShaderId shader, uint32_t rootSignatureId, const DPipelineAttachments& attachments, const PipelineFormat& format) { @@ -1361,17 +1474,28 @@ VulkanContext::CreatePipeline(const ShaderId shader, uint32_t rootSignatureId, c auto renderPassVk = _createRenderPass(rpAttachments); auto& vertexLayout = GetResource(_vertexLayouts, shaderRef.VertexLayout); pso.Pipeline = _createPipeline(rootSignature.PipelineLayout, renderPassVk, shaderRef.ShaderStageCreateInfo, format, vertexLayout, shaderRef.VertexStride); + pso.Type = EPipelineType::GRAPHICS; - return *ResourceId(EResourceType::GRAPHICS_PIPELINE, pso.Id, index); + return *ResourceId(EResourceType::PIPELINE, pso.Id, index); } void VulkanContext::DestroyPipeline(uint32_t pipelineId) { - auto& pipelineRef = GetResource(_pipelines, pipelineId); + auto& pipelineRef = GetResource(_pipelines, pipelineId); + switch (pipelineRef.Type) + { + case EPipelineType::GRAPHICS: + Device.DestroyPipeline(pipelineRef.Pipeline); + break; + case EPipelineType::COMPUTE: + vkDestroyPipeline(Device.Device, pipelineRef.Pipeline, nullptr); + break; + } - Device.DestroyPipeline(pipelineRef.Pipeline); - pipelineRef.Id = FREE; + pipelineRef.Pipeline = nullptr; + pipelineRef.PipelineLayout = nullptr; + pipelineRef.Id = FREE; } uint32_t @@ -1472,8 +1596,22 @@ VulkanContext::CreateRootSignature(const ShaderLayout& layout) for (uint32_t j = 0; j < descriptorCount; j++) { VkDescriptorImageInfo& img = imageInfo[imageInfoCount++]; - img.imageView = _emptyImage->View; + img.imageView = _emptyImage->GetImageView(0, 1, Device); img.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + img.sampler = _emptyImage->Sampler; + } + } + break; + case EBindingType::STORAGE_IMAGE: + { + writeSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + writeSet->pImageInfo = &imageInfo[imageInfoCount]; + + for (uint32_t j = 0; j < descriptorCount; j++) + { + VkDescriptorImageInfo& img = imageInfo[imageInfoCount++]; + img.imageView = _emptyStorageImage->GetImageView(0, 1, Device); + img.imageLayout = VK_IMAGE_LAYOUT_GENERAL; img.sampler = NULL; } } @@ -1492,6 +1630,10 @@ VulkanContext::CreateRootSignature(const ShaderLayout& layout) } } break; + + default: + furyassert(0); // Unhandled case + break; } writeSet->dstArrayElement = 0; @@ -1658,12 +1800,26 @@ VulkanContext::CreateDescriptorSets(uint32_t rootSignatureId, EDescriptorFrequen for (uint32_t i = 0; i < descriptorCount; i++) { VkDescriptorImageInfo& img = imageInfo[imageInfoCount++]; - img.imageView = _emptyImage->View; + img.imageView = _emptyImage->GetImageView(0, 1, Device); img.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; img.sampler = NULL; } } break; + case EBindingType::STORAGE_IMAGE: + { + writeSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + writeSet->pImageInfo = &imageInfo[imageInfoCount]; + + for (uint32_t i = 0; i < descriptorCount; i++) + { + VkDescriptorImageInfo& img = imageInfo[imageInfoCount++]; + img.imageView = _emptyStorageImage->GetImageView(0, 1, Device); + img.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + img.sampler = NULL; + } + } + break; case EBindingType::SAMPLER: { writeSet->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; @@ -1762,7 +1918,7 @@ VulkanContext::UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t paramCount case EResourceType::IMAGE: { const DImageVulkan& imageRef = GetResource(_images, param->Textures[j]); - img.imageView = imageRef.View; + img.imageView = imageRef.GetImageView(param->MipMapIndex, param->MipMapCount, Device); img.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; img.sampler = NULL; } @@ -1783,6 +1939,41 @@ VulkanContext::UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t paramCount } } break; + case EBindingType::STORAGE_IMAGE: + { + writeSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + writeSet->pImageInfo = &imageInfo[imageInfoCount]; + + for (uint32_t j = 0; j < descriptorCount; j++) + { + VkDescriptorImageInfo& img = imageInfo[imageInfoCount++]; + const auto resourceType{ static_cast(ResourceId(param->Textures[j]).First()) }; + switch (resourceType) + { + case EResourceType::IMAGE: + { + const DImageVulkan& imageRef = GetResource(_images, param->Textures[j]); + img.imageView = imageRef.GetImageView(param->MipMapIndex, param->MipMapCount, Device); + img.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + img.sampler = NULL; + } + break; + case EResourceType::RENDER_TARGET: + { + const DRenderTargetVulkan& imageRef = + GetResource(_renderTargets, param->Textures[j]); + img.imageView = imageRef.View; + img.imageLayout = VK_IMAGE_LAYOUT_GENERAL; + img.sampler = NULL; + } + break; + default: + furyassert(0); // Invalid resource type, must be a image or render target + break; + } + } + } + break; case EBindingType::SAMPLER: { writeSet->descriptorType = VK_DESCRIPTOR_TYPE_SAMPLER; @@ -1798,6 +1989,10 @@ VulkanContext::UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t paramCount } } break; + + default: + furyassert(0); + break; } writeSet->dstArrayElement = param->ArrayOffset; @@ -2155,14 +2350,45 @@ VulkanContext::BindPipeline(uint32_t commandBufferId, uint32_t pipeline) { auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); furyassert(commandBufferRef.IsRecording); // Must be in recording state - furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass + auto& pipelineRef = GetResource(_pipelines, pipeline); - auto& pipelineRef = GetResource(_pipelines, pipeline); +#if _DEBUG + { + if (pipelineRef.Type == EPipelineType::GRAPHICS) + { + furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass + } + else if (pipelineRef.Type == EPipelineType::COMPUTE) + { + furyassert(!commandBufferRef.ActiveRenderPass); // Must not be in a render pass + } + } +#endif if (commandBufferRef.BoundPipeline != pipelineRef.Pipeline) { - commandBufferRef.BoundPipeline = pipelineRef.Pipeline; - vkCmdBindPipeline(commandBufferRef.Cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineRef.Pipeline); + // If binding a compute pipeline after a graphics pipeline must end any active render passes before binding + if (pipelineRef.Type == EPipelineType::COMPUTE && commandBufferRef.ActiveRenderPass != nullptr) + { + vkCmdEndRenderPass(commandBufferRef.Cmd); + commandBufferRef.ActiveRenderPass = {}; + } + // Update current pipeline + commandBufferRef.BoundPipeline = pipelineRef.Pipeline; + commandBufferRef.BoundPipelineType = pipelineRef.Type; + + switch (pipelineRef.Type) + { + case EPipelineType::GRAPHICS: + vkCmdBindPipeline(commandBufferRef.Cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineRef.Pipeline); + break; + case EPipelineType::COMPUTE: + vkCmdBindPipeline(commandBufferRef.Cmd, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineRef.Pipeline); + break; + default: + furyassert(0); + break; + } } } @@ -2238,14 +2464,33 @@ VulkanContext::BindDescriptorSet(uint32_t commandBufferId, uint32_t setIndex, ui { auto& commandBufferRef = GetResource(_commandBuffers, commandBufferId); furyassert(commandBufferRef.IsRecording); // Must be in recording state - furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass + +#if _DEBUG + if (commandBufferRef.BoundPipelineType != EPipelineType::COMPUTE) + { + furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass + } +#endif const DDescriptorSet& descriptorSetRef = GetResource(_descriptorSets, descriptorSetId); furyassert(setIndex < descriptorSetRef.Sets.size()); - vkCmdBindDescriptorSets( - commandBufferRef.Cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, descriptorSetRef.RootSignature->PipelineLayout, (uint32_t)descriptorSetRef.Frequency, 1, &descriptorSetRef.Sets[setIndex], 0, nullptr); + VkPipelineBindPoint bindPoint{ VK_PIPELINE_BIND_POINT_GRAPHICS }; + switch (commandBufferRef.BoundPipelineType) + { + case EPipelineType::GRAPHICS: + bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + break; + case EPipelineType::COMPUTE: + bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE; + break; + default: + furyassert(0); + break; + } + + vkCmdBindDescriptorSets(commandBufferRef.Cmd, bindPoint, descriptorSetRef.RootSignature->PipelineLayout, (uint32_t)descriptorSetRef.Frequency, 1, &descriptorSetRef.Sets[setIndex], 0, nullptr); } void @@ -2320,22 +2565,7 @@ VulkanContext::CopyImage(uint32_t commandId, uint32_t destImage, uint32_t width, furyassert(0); break; }; -#if _DEBUG - { - if (region.srcSubresource.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) - { - furyassert(region.dstSubresource.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT); - } - else if (region.srcSubresource.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) - { - furyassert(region.dstSubresource.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT); - } - else if (region.srcSubresource.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT && region.srcSubresource.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) - { - furyassert(region.dstSubresource.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT && region.srcSubresource.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT); - } - } -#endif + furyassert(srcImage); furyassert(dstImage); @@ -2726,8 +2956,8 @@ VulkanContext::CreateRenderTarget(EFormat format, ESampleBit samples, bool isDep } break; case EResourceState::UNORDERED_ACCESS: - initialLayout = VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL; // Valid? - furyassert(0); // Verify is correct + initialLayout = VK_IMAGE_LAYOUT_GENERAL; // Valid? + // furyassert(0); // Verify is correct break; case EResourceState::DEPTH_WRITE: initialLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; @@ -3017,6 +3247,7 @@ RenderTargetBarrier* p_rt_barriers) pImageBarrier->dstAccessMask = VkUtils::resourceStateToAccessFlag(pTrans->mNewState); pImageBarrier->oldLayout = VkUtils::resourceStateToImageLayout(pTrans->mCurrentState); pImageBarrier->newLayout = VkUtils::resourceStateToImageLayout(pTrans->mNewState); + furyassert(pImageBarrier->newLayout != VK_IMAGE_LAYOUT_UNDEFINED && pImageBarrier->newLayout != VK_IMAGE_LAYOUT_PREINITIALIZED); } if (pImageBarrier) @@ -3195,6 +3426,31 @@ VulkanContext::GetAdapterDedicatedVideoMemory() const return 0; } +float +VulkanContext::GetMaxAnisotropyFiltering(bool* isSupported) const +{ + VkPhysicalDeviceFeatures deviceFeatures{}; + vkGetPhysicalDeviceFeatures(Device.PhysicalDevice, &deviceFeatures); + + if (deviceFeatures.samplerAnisotropy) + { + VkPhysicalDeviceProperties deviceProperties{}; + vkGetPhysicalDeviceProperties(Device.PhysicalDevice, &deviceProperties); + + const float maxAnisotropy = deviceProperties.limits.maxSamplerAnisotropy; + if (isSupported) + { + *isSupported = true; + } + return maxAnisotropy; + } + if (isSupported) + { + *isSupported = false; + } + return 0.0f; +} + void VulkanContext::Warning(const std::string& error) { diff --git a/src/backend/vulkan/VulkanContext.h b/src/backend/vulkan/VulkanContext.h index 23f6d27..b9c6c78 100644 --- a/src/backend/vulkan/VulkanContext.h +++ b/src/backend/vulkan/VulkanContext.h @@ -35,10 +35,49 @@ struct DBufferVulkan : public DResource struct DImageVulkan : public DResource { - RIVulkanImage Image; - VkImageView View{}; - VkImageAspectFlags ImageAspect{}; - VkSampler Sampler{}; + struct DMipMapRange + { + uint32_t First, Count; + }; + + struct DMipMapRangeHashFn + { + size_t operator()(const DMipMapRange& range)const + { + size_t hash{}; + hash += std::hash{}(range.First); + hash += (71 * hash + (size_t)std::hash{}(range.Count)) % 5; + return hash; + }; + }; + + struct DMipMapRangeEqualFn + { + bool operator()(const DMipMapRange& lhs, const DMipMapRange& rhs) const { return lhs.First == rhs.First && lhs.Count == rhs.Count; }; + }; + + inline static constexpr size_t MAX_IMAGE_VIEWS{ 32 }; + RIVulkanImage Image; + mutable std::unordered_map ImageViews{}; + VkImageAspectFlags ImageAspect{}; + VkSampler Sampler{}; + + VkImageView GetImageView(uint32_t mipMapIndex, uint32_t count, RIVulkanDevice13& device) const + { + const auto found{ ImageViews.find(DMipMapRange{ mipMapIndex, count }) }; + if (found != ImageViews.end()) + { + return found->second; + } + VkImageView newImageView{}; + const VkResult result = device.CreateImageView(Image.Format, Image.Image, ImageAspect, mipMapIndex, count, &newImageView); + if (VKFAILED(result)) + { + throw std::runtime_error(VkUtils::VkErrorString(result)); + } + ImageViews[DMipMapRange{ mipMapIndex, count }] = newImageView; + return newImageView; + } }; struct DRenderTargetVulkan : public DResource @@ -87,6 +126,7 @@ struct DPipelineVulkan_DEPRECATED : public DPipeline_T struct DPipelineVulkan : public DResource { VkPipeline Pipeline{}; + EPipelineType Type{}; const VkPipelineLayout* PipelineLayout{}; }; @@ -106,6 +146,7 @@ struct DCommandBufferVulkan : public DResource bool IsRecording{}; VkRenderPass ActiveRenderPass{}; VkPipeline BoundPipeline{}; + EPipelineType BoundPipelineType{}; VkRect2D CurrentScissor{}; VkBuffer CurrentVertexBuffer{}; VkBuffer CurrentIndexBuffer{}; @@ -128,6 +169,7 @@ struct DShaderVulkan : public DResource VertexInputLayoutId VertexLayout{}; uint32_t VertexStride{}; VkShaderModule VertexShaderModule{}; + VkShaderModule ComputeShaderModule{}; VkShaderModule PixelShaderModule{}; std::vector ShaderStageCreateInfo; uint32_t ColorAttachments{ 1 }; @@ -192,15 +234,24 @@ class VulkanContext final : public IContext void* BeginMapBuffer(BufferId buffer) override; void EndMapBuffer(BufferId buffer) override; void DestroyBuffer(BufferId buffer) override; - ImageId CreateImage(EFormat format, uint32_t width, uint32_t height, uint32_t mipMapCount) override; + ImageId CreateImage(EFormat format, uint32_t width, uint32_t height, uint32_t mipMapCount, bool isDepth = false, bool isStencil = false) override; + ImageId CreateStorageImage(EFormat format, uint32_t width, uint32_t height, uint32_t mipMapCount, bool isDepth = false, bool isStencil = false) override; EFormat GetImageFormat(ImageId) const override; void DestroyImage(ImageId imageId) override; VertexInputLayoutId CreateVertexLayout(const std::vector& info) override; ShaderId CreateShader(const ShaderSource& source) override; void DestroyShader(const ShaderId shader) override; - uint32_t CreateSampler(uint32_t minLod, uint32_t maxLod) override; + uint32_t CreateSampler(uint32_t minLod, + uint32_t maxLod, + EFilter minFilter, + EFilter magFilter, + ESamplerAddressMode addressMode, + ESamplerMipmapMode mipMapMode, + bool anisotropicFiltering, + float anisotropicFilter = 16.f) override; void DestroySampler(uint32_t samplerId) override; + uint32_t CreateComputePipeline(const uint32_t shader, const uint32_t rootSignatureId) override; uint32_t CreatePipeline(const ShaderId shader, uint32_t rootSignatureId, const DPipelineAttachments& attachments, const PipelineFormat& format) override; void DestroyPipeline(uint32_t pipelineId) override; uint32_t CreateRootSignature(const ShaderLayout& layout) override; @@ -266,7 +317,7 @@ class VulkanContext final : public IContext unsigned char* GetAdapterDescription() const override; size_t GetAdapterDedicatedVideoMemory() const override; - + float GetMaxAnisotropyFiltering(bool* isSupported = nullptr) const override; #pragma region Utility RIVulkanDevice13& GetDevice() { return Device; } #pragma endregion @@ -283,6 +334,8 @@ class VulkanContext final : public IContext DBufferVulkan _emptyUbo; uint32_t _emptyImageId{}; DImageVulkan* _emptyImage; + uint32_t _emptyStorageImageId{}; + DImageVulkan* _emptyStorageImage; DSamplerVulkan _emptySampler; std::array _swapchains; /*Vertex and index buffers pool*/ @@ -367,7 +420,8 @@ class VulkanContext final : public IContext "VK_KHR_Maintenance1", // passing negative viewport heights "VK_KHR_maintenance4", "VK_KHR_dedicated_allocation", - "VK_KHR_bind_memory2" }; + "VK_KHR_bind_memory2", + "VK_EXT_shader_atomic_float2" }; void Warning(const std::string& error); void Log(const std::string& error); diff --git a/src/backend/vulkan/VulkanDevice6.cpp b/src/backend/vulkan/VulkanDevice6.cpp index 135ecd4..d38893f 100644 --- a/src/backend/vulkan/VulkanDevice6.cpp +++ b/src/backend/vulkan/VulkanDevice6.cpp @@ -30,7 +30,7 @@ RIVulkanDevice6::CreateSampler(VkFilter minFilter, VkFilter magFilter, VkSampler samplerInfo.unnormalizedCoordinates = VK_FALSE; samplerInfo.compareEnable = VK_FALSE; samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; - samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerInfo.mipmapMode = mipmapMode; samplerInfo.mipLodBias = 0.f; samplerInfo.minLod = minLod; samplerInfo.maxLod = maxLod; From 496fed6429ab83b4cace2a9e5cad6a6bd0a858b9 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Wed, 14 Aug 2024 12:16:54 +0200 Subject: [PATCH 53/58] Implemented push constants --- include/IContext.h | 22 +++++++++++++------ src/backend/vulkan/VulkanContext.cpp | 26 +++++++++++++++++++--- src/backend/vulkan/VulkanContext.h | 32 +++++++++++++++------------- 3 files changed, 56 insertions(+), 24 deletions(-) diff --git a/include/IContext.h b/include/IContext.h index 5f7720f..480ab3d 100644 --- a/include/IContext.h +++ b/include/IContext.h @@ -62,7 +62,7 @@ enum class ESamplerAddressMode MIRRORED_REPEAT, CLAMP_TO_EDGE, CLAMP_TO_BORDER, - MIRROR_CLAMP_TO_EDGE,//not all implementations could support it, + MIRROR_CLAMP_TO_EDGE, // not all implementations could support it, }; enum class ESamplerMipmapMode @@ -550,9 +550,18 @@ class RIShaderDescriptorBindingsEqualFn } }; +struct PushConstantRange +{ + /*Does not affect the stage; do not use the Stage variable*/ + EShaderStage Stage{ EShaderStage::ALL }; + uint32_t Offset{}; + uint32_t Size{}; +}; + struct ShaderLayout { std::map> SetsLayout; + std::vector PushConstants; }; struct ShaderByteCode @@ -846,9 +855,9 @@ class IContext EFilter minFilter, EFilter magFilter, ESamplerAddressMode addressMode, - ESamplerMipmapMode mipMapMode, - bool anisotropicFiltering, - float anisotropicFilter = 16.f) = 0; + ESamplerMipmapMode mipMapMode, + bool anisotropicFiltering, + float anisotropicFilter = 16.f) = 0; virtual void DestroySampler(uint32_t samplerId) = 0; virtual uint32_t CreateCommandPool(uint32_t queueId) = 0; @@ -877,6 +886,7 @@ class IContext virtual void SetLineWidth(uint32_t commandId, float lineWidth) = 0; virtual void DispatchCompute(uint32_t commandId, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) = 0; virtual void ComputeWorkGroupCount(uint32_t* groupCountX, uint32_t* groupCountY, uint32_t* groupCountZ) = 0; + virtual void PushConstant(uint32_t commandId, EShaderStage stage, uint32_t offset, uint32_t size, void* data) = 0; virtual uint32_t CreateRenderTarget(EFormat format, ESampleBit samples, bool isDepth, uint32_t width, uint32_t height, uint32_t arrayLength, uint32_t mipMapCount, EResourceState initialState) = 0; virtual void DestroyRenderTarget(uint32_t renderTargetId) = 0; @@ -909,8 +919,8 @@ class IContext virtual void FlushDeletedBuffers() = 0; - virtual unsigned char* GetAdapterDescription() const = 0; - virtual size_t GetAdapterDedicatedVideoMemory() const = 0; + virtual unsigned char* GetAdapterDescription() const = 0; + virtual size_t GetAdapterDedicatedVideoMemory() const = 0; virtual float GetMaxAnisotropyFiltering(bool* isSupported = nullptr) const = 0; }; } \ No newline at end of file diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index 7ecde70..788a64c 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -1521,8 +1521,17 @@ VulkanContext::CreateRootSignature(const ShaderLayout& layout) rootSignature.PoolSizes[setPair.first] = VkUtils::computeDescriptorSetsPoolSize(setBindings); } + // Convert push constants + std::vector pushConstants; + for (const auto& p : layout.PushConstants) + { +#pragma message "Warning:src/backend/vulkan/VulkanContext.cpp: line 1528 : p.Stage is not used!" + p.Stage; + pushConstants.push_back(VkPushConstantRange{ VK_SHADER_STAGE_ALL_GRAPHICS, p.Offset, p.Size }); + }; + // Can return already cached pipeline layout if exists - rootSignature.PipelineLayout = Device.CreatePipelineLayout(descriptorSetLayout, {}); + rootSignature.PipelineLayout = Device.CreatePipelineLayout(descriptorSetLayout, pushConstants); rootSignature.SetsBindings = layout.SetsLayout; @@ -2374,8 +2383,9 @@ VulkanContext::BindPipeline(uint32_t commandBufferId, uint32_t pipeline) commandBufferRef.ActiveRenderPass = {}; } // Update current pipeline - commandBufferRef.BoundPipeline = pipelineRef.Pipeline; - commandBufferRef.BoundPipelineType = pipelineRef.Type; + commandBufferRef.BoundPipeline = pipelineRef.Pipeline; + commandBufferRef.BoundPipelineLayout = pipelineRef.PipelineLayout; + commandBufferRef.BoundPipelineType = pipelineRef.Type; switch (pipelineRef.Type) { @@ -2743,6 +2753,16 @@ VulkanContext::ComputeWorkGroupCount(uint32_t* groupCountX, uint32_t* groupCount *groupCountZ = Device.DeviceProperties.limits.maxComputeWorkGroupCount[2]; } +void +VulkanContext::PushConstant(uint32_t commandId, EShaderStage stage, uint32_t offset, uint32_t size, void* data) +{ + auto& commandBufferRef = GetResource(_commandBuffers, commandId); + furyassert(commandBufferRef.IsRecording); // Must be in recording state + furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass + + vkCmdPushConstants(commandBufferRef.Cmd, *commandBufferRef.BoundPipelineLayout, VK_SHADER_STAGE_ALL_GRAPHICS, offset, size, data); +} + void VulkanContext::QueueSubmit(uint32_t queueId, const std::vector& waitSemaphore, const std::vector& finishSemaphore, const std::vector& cmdIds, uint32_t fenceId) { diff --git a/src/backend/vulkan/VulkanContext.h b/src/backend/vulkan/VulkanContext.h index b9c6c78..e0caee5 100644 --- a/src/backend/vulkan/VulkanContext.h +++ b/src/backend/vulkan/VulkanContext.h @@ -42,7 +42,7 @@ struct DImageVulkan : public DResource struct DMipMapRangeHashFn { - size_t operator()(const DMipMapRange& range)const + size_t operator()(const DMipMapRange& range) const { size_t hash{}; hash += std::hash{}(range.First); @@ -140,17 +140,18 @@ struct DCommandPoolVulkan : public DResource struct DCommandBufferVulkan : public DResource { - VkCommandBuffer Cmd{}; - EQueueType Type{}; - uint32_t QueueFamilyIndex{}; - bool IsRecording{}; - VkRenderPass ActiveRenderPass{}; - VkPipeline BoundPipeline{}; - EPipelineType BoundPipelineType{}; - VkRect2D CurrentScissor{}; - VkBuffer CurrentVertexBuffer{}; - VkBuffer CurrentIndexBuffer{}; - bool StencilTestActive{}; + VkCommandBuffer Cmd{}; + EQueueType Type{}; + uint32_t QueueFamilyIndex{}; + bool IsRecording{}; + VkRenderPass ActiveRenderPass{}; + VkPipeline BoundPipeline{}; + const VkPipelineLayout* BoundPipelineLayout{}; + EPipelineType BoundPipelineType{}; + VkRect2D CurrentScissor{}; + VkBuffer CurrentVertexBuffer{}; + VkBuffer CurrentIndexBuffer{}; + bool StencilTestActive{}; }; struct DFenceVulkan : public DResource @@ -246,9 +247,9 @@ class VulkanContext final : public IContext EFilter minFilter, EFilter magFilter, ESamplerAddressMode addressMode, - ESamplerMipmapMode mipMapMode, - bool anisotropicFiltering, - float anisotropicFilter = 16.f) override; + ESamplerMipmapMode mipMapMode, + bool anisotropicFiltering, + float anisotropicFilter = 16.f) override; void DestroySampler(uint32_t samplerId) override; uint32_t CreateComputePipeline(const uint32_t shader, const uint32_t rootSignatureId) override; @@ -288,6 +289,7 @@ class VulkanContext final : public IContext void SetLineWidth(uint32_t commandId, float lineWidth) override; void DispatchCompute(uint32_t commandId, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) override; void ComputeWorkGroupCount(uint32_t* groupCountX, uint32_t* groupCountY, uint32_t* groupCountZ) override; + void PushConstant(uint32_t commandId, EShaderStage stage, uint32_t offset, uint32_t size, void* data) override; uint32_t CreateFence(bool signaled) override; void DestroyFence(uint32_t fenceId) override; From 116a15a5d901e0c48e02cc64079d7d096adb63a4 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Sun, 22 Sep 2024 12:13:42 +0200 Subject: [PATCH 54/58] Tracking bound pipeline in command buffer --- src/backend/vulkan/VulkanContext.cpp | 9 ++++++++- src/backend/vulkan/VulkanContext.h | 1 + src/backend/vulkan/VulkanDevice5.cpp | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index 788a64c..4ae89b2 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -2065,7 +2065,7 @@ VulkanContext::_createFramebuffer(const DFramebufferAttachments& attachments) #if _DEBUG furyassert(renderTargetRef.Image.MipLevels == 1); // Must have only 1 layer (Vulkan requirement) - if (attachmentCount > depthAttachmentCount) + if (attachmentCount >= depthAttachmentCount) { furyassert(renderTargetRef.Image.Width == framebufferRef.Width); // All images must have the same width furyassert(renderTargetRef.Image.Height == framebufferRef.Height); // All images must have the same height @@ -2132,6 +2132,9 @@ VulkanContext::CreateCommandBuffer(uint32_t commandPoolId) { commandBufferRef.ActiveRenderPass = nullptr; commandBufferRef.IsRecording = false; + commandBufferRef.BoundFramebuffer = nullptr; + commandBufferRef.BoundPipeline = nullptr; + commandBufferRef.BoundPipelineLayout = nullptr; } auto& commandPoolRef = GetResource(_commandPools, commandPoolId); @@ -2194,6 +2197,7 @@ VulkanContext::EndCommandBuffer(uint32_t commandBufferId) { vkCmdEndRenderPass(commandBufferRef.Cmd); commandBufferRef.ActiveRenderPass = nullptr; + commandBufferRef.BoundFramebuffer = nullptr; } vkEndCommandBuffer(commandBufferRef.Cmd); @@ -2311,8 +2315,10 @@ VulkanContext::BindRenderTargets(uint32_t commandBufferId, const DFramebufferAtt if (commandBufferRef.ActiveRenderPass) { vkCmdEndRenderPass(commandBufferRef.Cmd); + commandBufferRef.BoundFramebuffer = nullptr; } commandBufferRef.ActiveRenderPass = renderPass; + commandBufferRef.BoundFramebuffer = framebufferPtr->Framebuffer; vkCmdBeginRenderPass(commandBufferRef.Cmd, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); } @@ -3314,6 +3320,7 @@ RenderTargetBarrier* p_rt_barriers) { vkCmdEndRenderPass(commandBufferRef.Cmd); commandBufferRef.ActiveRenderPass = nullptr; + commandBufferRef.BoundFramebuffer = nullptr; } #if _DEBUG && DEBUG_RT_TRANSITIONS 1 diff --git a/src/backend/vulkan/VulkanContext.h b/src/backend/vulkan/VulkanContext.h index e0caee5..6df94ac 100644 --- a/src/backend/vulkan/VulkanContext.h +++ b/src/backend/vulkan/VulkanContext.h @@ -145,6 +145,7 @@ struct DCommandBufferVulkan : public DResource uint32_t QueueFamilyIndex{}; bool IsRecording{}; VkRenderPass ActiveRenderPass{}; + VkFramebuffer BoundFramebuffer{}; VkPipeline BoundPipeline{}; const VkPipelineLayout* BoundPipelineLayout{}; EPipelineType BoundPipelineType{}; diff --git a/src/backend/vulkan/VulkanDevice5.cpp b/src/backend/vulkan/VulkanDevice5.cpp index f264027..3c32e10 100644 --- a/src/backend/vulkan/VulkanDevice5.cpp +++ b/src/backend/vulkan/VulkanDevice5.cpp @@ -18,7 +18,7 @@ RIVulkanDevice5::~RIVulkanDevice5() RIVulkanImage RIVulkanDevice5::CreateImageDeviceLocal(uint32_t width, uint32_t height, uint32_t mipLevels, VkFormat format, VkImageUsageFlags usage, VkImageTiling tiling, VkImageLayout initialLayout) { - + furyassert(width > 0 && height > 0); VkImageCreateInfo imageInfo{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; imageInfo.imageType = VK_IMAGE_TYPE_2D; imageInfo.extent.width = width; From b20a43ccb9abddea061750b4c92bd81d5012af46 Mon Sep 17 00:00:00 2001 From: Stanislav Date: Tue, 26 Nov 2024 22:47:33 +0100 Subject: [PATCH 55/58] Added ssbo support to descriptor sets --- include/IContext.h | 7 ++-- src/backend/vulkan/VulkanContext.cpp | 54 +++++++++++++++++++++++----- src/backend/vulkan/VulkanContext.h | 2 ++ 3 files changed, 52 insertions(+), 11 deletions(-) diff --git a/include/IContext.h b/include/IContext.h index 480ab3d..8a9a669 100644 --- a/include/IContext.h +++ b/include/IContext.h @@ -46,6 +46,7 @@ enum EResourceType : uint8_t SAMPLER = 16, INDIRECT_DRAW_COMMAND = 17, QUEUE = 18, + STORAGE_BUFFER = 19, }; // SHOULD BE PRIVATE @@ -74,8 +75,8 @@ enum class ESamplerMipmapMode struct DContextConfig { uint32_t stagingBufferSize{ 64 * 1024 * 1024 }; // 64mb - void (*warningFunction)(const char*){}; - void (*logOutputFunction)(const char*){}; + void (*warningFunction)(const char*){}; + void (*logOutputFunction)(const char*){}; }; struct WindowData @@ -886,7 +887,7 @@ class IContext virtual void SetLineWidth(uint32_t commandId, float lineWidth) = 0; virtual void DispatchCompute(uint32_t commandId, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) = 0; virtual void ComputeWorkGroupCount(uint32_t* groupCountX, uint32_t* groupCountY, uint32_t* groupCountZ) = 0; - virtual void PushConstant(uint32_t commandId, EShaderStage stage, uint32_t offset, uint32_t size, void* data) = 0; + virtual void PushConstant(uint32_t commandId, EShaderStage stage, uint32_t offset, uint32_t size, void* data) = 0; virtual uint32_t CreateRenderTarget(EFormat format, ESampleBit samples, bool isDepth, uint32_t width, uint32_t height, uint32_t arrayLength, uint32_t mipMapCount, EResourceState initialState) = 0; virtual void DestroyRenderTarget(uint32_t renderTargetId) = 0; diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index 4ae89b2..82a8be2 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -222,6 +222,7 @@ VulkanContext::VulkanContext(const DContextConfig* const config) : _warningOutpu _deletionQueue.reserve(MAX_RESOURCES); _emptyUbo.Buffer = Device.CreateBufferHostVisible(4, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); + _emptySsbo.Buffer = Device.CreateBufferHostVisible(4, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); _emptyImageId = CreateImage(EFormat::R8G8B8A8_UNORM, 1, 1, 1); _emptyImage = &GetResource(_images, _emptyImageId); @@ -464,6 +465,7 @@ VulkanContext::~VulkanContext() } Device.DestroyBuffer(_emptyUbo.Buffer); + Device.DestroyBuffer(_emptySsbo.Buffer); DestroyImage(_emptyImageId); DestroyImage(_emptyStorageImageId); Device.DestroySampler(_emptySampler.Sampler); @@ -1047,6 +1049,11 @@ VulkanContext::CreateBuffer(uint32_t size, EResourceType type, EMemoryUsage usag index = AllocResource(_uniformBuffers); buffer = &_uniformBuffers.at(index); break; + case EResourceType::STORAGE_BUFFER: + usageFlags = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + index = AllocResource(_storageBuffers); + buffer = &_storageBuffers.at(index); + break; case EResourceType::VERTEX_INDEX_BUFFER: index = AllocResource(_vertexBuffers); usageFlags = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT; @@ -1068,6 +1075,7 @@ VulkanContext::CreateBuffer(uint32_t size, EResourceType type, EMemoryUsage usag } buffer->Size = size; + furyassert(usageFlags != 0); switch (usage) { @@ -1106,6 +1114,9 @@ VulkanContext::BeginMapBuffer(BufferId buffer) case EResourceType::UNIFORM_BUFFER: bufferPtr = &_uniformBuffers.at(index); break; + case EResourceType::STORAGE_BUFFER: + bufferPtr = &_storageBuffers.at(index); + break; case EResourceType::VERTEX_INDEX_BUFFER: bufferPtr = &_vertexBuffers.at(index); break; @@ -1136,6 +1147,9 @@ VulkanContext::EndMapBuffer(BufferId buffer) case EResourceType::UNIFORM_BUFFER: bufferPtr = &_uniformBuffers.at(index); break; + case EResourceType::STORAGE_BUFFER: + bufferPtr = &_storageBuffers.at(index); + break; case EResourceType::VERTEX_INDEX_BUFFER: bufferPtr = &_vertexBuffers.at(index); break; @@ -1157,7 +1171,6 @@ VulkanContext::EndMapBuffer(BufferId buffer) void VulkanContext::DestroyBuffer(BufferId buffer) { - const auto resourceType = ResourceId(buffer).First(); const auto index = ResourceId(buffer).Value(); DBufferVulkan* bufferPtr{}; @@ -1167,6 +1180,9 @@ VulkanContext::DestroyBuffer(BufferId buffer) case EResourceType::UNIFORM_BUFFER: bufferPtr = &_uniformBuffers.at(index); break; + case EResourceType::STORAGE_BUFFER: + bufferPtr = &_storageBuffers.at(index); + break; case EResourceType::VERTEX_INDEX_BUFFER: bufferPtr = &_vertexBuffers.at(index); break; @@ -1581,7 +1597,14 @@ VulkanContext::CreateRootSignature(const ShaderLayout& layout) case EBindingType::STORAGE_BUFFER_OBJECT: { writeSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - furyassert(0); // UNSUPPORTED YET + writeSet->pBufferInfo = &bufferInfo[bufferInfoCount]; + for (uint32_t j = 0; j < descriptorCount; j++) + { + VkDescriptorBufferInfo& buf = bufferInfo[bufferInfoCount++]; + buf.buffer = _emptySsbo.Buffer.Buffer; + buf.offset = 0; + buf.range = VK_WHOLE_SIZE; + } } break; case EBindingType::UNIFORM_BUFFER_OBJECT: @@ -1785,7 +1808,14 @@ VulkanContext::CreateDescriptorSets(uint32_t rootSignatureId, EDescriptorFrequen case EBindingType::STORAGE_BUFFER_OBJECT: { writeSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - furyassert(0); // UNSUPPORTED YET + writeSet->pBufferInfo = &bufferInfo[bufferInfoCount]; + for (uint32_t j = 0; j < descriptorCount; j++) + { + VkDescriptorBufferInfo& buf = bufferInfo[bufferInfoCount++]; + buf.buffer = _emptySsbo.Buffer.Buffer; + buf.offset = 0; + buf.range = VK_WHOLE_SIZE; + } } break; case EBindingType::UNIFORM_BUFFER_OBJECT: @@ -1894,14 +1924,22 @@ VulkanContext::UpdateDescriptorSet(uint32_t descriptorSetId, uint32_t paramCount case EBindingType::STORAGE_BUFFER_OBJECT: { writeSet->descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - furyassert(0); // UNSUPPORTED YET + writeSet->pBufferInfo = &bufferInfo[bufferInfoCount]; + + for (uint32_t j = 0; j < descriptorCount; j++) + { + VkDescriptorBufferInfo& buf = bufferInfo[bufferInfoCount++]; + const DBufferVulkan& bufRef = GetResource(_storageBuffers, param->Buffers[j]); + buf.buffer = bufRef.Buffer.Buffer; + buf.offset = param->BufferOffset; + buf.range = param->BufferRange; + } } break; case EBindingType::UNIFORM_BUFFER_OBJECT: { writeSet->descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - - writeSet->pBufferInfo = &bufferInfo[bufferInfoCount]; + writeSet->pBufferInfo = &bufferInfo[bufferInfoCount]; for (uint32_t j = 0; j < descriptorCount; j++) { @@ -2130,8 +2168,8 @@ VulkanContext::CreateCommandBuffer(uint32_t commandPoolId) // Reset internals { - commandBufferRef.ActiveRenderPass = nullptr; - commandBufferRef.IsRecording = false; + commandBufferRef.ActiveRenderPass = nullptr; + commandBufferRef.IsRecording = false; commandBufferRef.BoundFramebuffer = nullptr; commandBufferRef.BoundPipeline = nullptr; commandBufferRef.BoundPipelineLayout = nullptr; diff --git a/src/backend/vulkan/VulkanContext.h b/src/backend/vulkan/VulkanContext.h index 6df94ac..d1827e9 100644 --- a/src/backend/vulkan/VulkanContext.h +++ b/src/backend/vulkan/VulkanContext.h @@ -335,6 +335,7 @@ class VulkanContext final : public IContext void (*_logOutput)(const char*); DBufferVulkan _emptyUbo; + DBufferVulkan _emptySsbo; uint32_t _emptyImageId{}; DImageVulkan* _emptyImage; uint32_t _emptyStorageImageId{}; @@ -345,6 +346,7 @@ class VulkanContext final : public IContext std::array _vertexBuffers; std::array _transferBuffers; std::array _uniformBuffers; + std::array _storageBuffers; std::array _indirectBuffers; /*Whenever a render target gets deleted remove also framebuffers that have that image id as attachment*/ std::array _framebuffers; From 93bdc63378588172d19ad88e7eee3a230efd242d Mon Sep 17 00:00:00 2001 From: Stanislav Date: Wed, 27 Nov 2024 21:54:49 +0100 Subject: [PATCH 56/58] Fixed warning on correct behaviour --- src/backend/vulkan/VulkanContext.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index 82a8be2..92a099b 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -221,7 +221,7 @@ VulkanContext::VulkanContext(const DContextConfig* const config) : _warningOutpu _pipelineLayoutToDescriptorPool.resize(NUM_OF_FRAMES_IN_FLIGHT); _deletionQueue.reserve(MAX_RESOURCES); - _emptyUbo.Buffer = Device.CreateBufferHostVisible(4, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); + _emptyUbo.Buffer = Device.CreateBufferHostVisible(4, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); _emptySsbo.Buffer = Device.CreateBufferHostVisible(4, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); _emptyImageId = CreateImage(EFormat::R8G8B8A8_UNORM, 1, 1, 1); @@ -2750,10 +2750,10 @@ VulkanContext::SetDepthTestCompareOp(uint32_t commandId, bool enabled, bool dept furyassert(commandBufferRef.ActiveRenderPass); // Must be in a render pass vkCmdSetDepthTestEnable(commandBufferRef.Cmd, static_cast(enabled)); + vkCmdSetDepthWriteEnable(commandBufferRef.Cmd, static_cast(depthWrite)); if (enabled) { - vkCmdSetDepthWriteEnable(commandBufferRef.Cmd, static_cast(depthWrite)); const VkCompareOp compareOpVk{ VkUtils::VkCompareOpFromCompareOp(compareOp) }; vkCmdSetDepthCompareOp(commandBufferRef.Cmd, compareOpVk); } From b38acc402966b3ef96edd851f13a6c3b13bac6a6 Mon Sep 17 00:00:00 2001 From: Stanislav Kirichenko Date: Mon, 9 Dec 2024 20:59:44 +0100 Subject: [PATCH 57/58] Removed warning for dynamic state enabled for pipeline --- src/backend/vulkan/VulkanContext.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index 92a099b..96f9f7c 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -2751,12 +2751,8 @@ VulkanContext::SetDepthTestCompareOp(uint32_t commandId, bool enabled, bool dept vkCmdSetDepthTestEnable(commandBufferRef.Cmd, static_cast(enabled)); vkCmdSetDepthWriteEnable(commandBufferRef.Cmd, static_cast(depthWrite)); - - if (enabled) - { - const VkCompareOp compareOpVk{ VkUtils::VkCompareOpFromCompareOp(compareOp) }; - vkCmdSetDepthCompareOp(commandBufferRef.Cmd, compareOpVk); - } + const VkCompareOp compareOpVk{ VkUtils::VkCompareOpFromCompareOp(compareOp) }; + vkCmdSetDepthCompareOp(commandBufferRef.Cmd, compareOpVk); } void From 251a7b549aac27d9b2f21af1967e6acce29a8a31 Mon Sep 17 00:00:00 2001 From: Stanislav Date: Sun, 5 Jan 2025 17:46:08 +0100 Subject: [PATCH 58/58] Fix missing compute shader module destruction --- src/backend/vulkan/VulkanContext.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backend/vulkan/VulkanContext.cpp b/src/backend/vulkan/VulkanContext.cpp index 96f9f7c..198ae82 100644 --- a/src/backend/vulkan/VulkanContext.cpp +++ b/src/backend/vulkan/VulkanContext.cpp @@ -1385,6 +1385,7 @@ VulkanContext::DestroyShader(const ShaderId shader) DShaderVulkan& shaderVulkan = _shaders.at(index); vkDestroyShaderModule(Device.Device, shaderVulkan.VertexShaderModule, nullptr); + vkDestroyShaderModule(Device.Device, shaderVulkan.ComputeShaderModule, nullptr); vkDestroyShaderModule(Device.Device, shaderVulkan.PixelShaderModule, nullptr); _shaders.at(index).Id = FREE; });