diff --git a/aster/include/aster/systems/CMakeLists.txt b/aster/include/aster/systems/CMakeLists.txt index 75395d1..381d233 100644 --- a/aster/include/aster/systems/CMakeLists.txt +++ b/aster/include/aster/systems/CMakeLists.txt @@ -5,4 +5,5 @@ cmake_minimum_required(VERSION 3.13) target_sources(aster_core INTERFACE "manager.h" - "buffer_manager.h") + "buffer_manager.h" + "image_manager.h") diff --git a/aster/include/aster/systems/buffer_manager.h b/aster/include/aster/systems/buffer_manager.h index 6447c11..bcfd8eb 100644 --- a/aster/include/aster/systems/buffer_manager.h +++ b/aster/include/aster/systems/buffer_manager.h @@ -20,5 +20,6 @@ class BufferManager final : public Manager BufferManager(const Device *device, const u32 maxCount); Handle CreateStorageBuffer(usize size, cstr name = nullptr); + Handle CreateUniformBuffer(usize size, cstr name = nullptr); }; } // namespace systems diff --git a/aster/include/aster/systems/image_manager.h b/aster/include/aster/systems/image_manager.h new file mode 100644 index 0000000..0da9fd6 --- /dev/null +++ b/aster/include/aster/systems/image_manager.h @@ -0,0 +1,60 @@ +// ============================================= +// Aster: image_manager.h +// Copyright (c) 2020-2024 Anish Bhobe +// ============================================= + +#pragma once + +#include "aster/aster.h" +#include "aster/core/image.h" +#include "manager.h" + +namespace systems +{ + +struct Texture2DCreateInfo +{ + vk::Format m_Format = vk::Format::eUndefined; + vk::Extent2D m_Extent = {}; + cstr m_Name = nullptr; + bool m_IsSampled = true; + bool m_IsMipMapped = false; + bool m_IsStorage = false; +}; + +struct TextureCubeCreateInfo +{ + vk::Format m_Format = vk::Format::eUndefined; + u32 m_Side = 0; + cstr m_Name = nullptr; + bool m_IsSampled = true; + bool m_IsMipMapped = false; + bool m_IsStorage = false; +}; + +struct AttachmentCreateInfo +{ + vk::Format m_Format = vk::Format::eUndefined; + vk::Extent2D m_Extent = {}; + cstr m_Name = nullptr; +}; + +struct DepthStencilImageCreateInfo +{ + vk::Extent2D m_Extent = {}; + cstr m_Name = nullptr; +}; + +using ImageHandle = Handle; + +class ImageManager final : public Manager +{ + public: + ImageManager(const Device *device, const u32 maxCount); + + Handle CreateTexture2D(const Texture2DCreateInfo& createInfo); + Handle CreateTextureCube(const TextureCubeCreateInfo &createInfo); + Handle CreateAttachment(const AttachmentCreateInfo &createInfo); + Handle CreateDepthStencilImage(const DepthStencilImageCreateInfo &createInfo); +}; +} // namespace systems diff --git a/aster/src/aster/systems/CMakeLists.txt b/aster/src/aster/systems/CMakeLists.txt index 548374e..18afab3 100644 --- a/aster/src/aster/systems/CMakeLists.txt +++ b/aster/src/aster/systems/CMakeLists.txt @@ -5,4 +5,5 @@ cmake_minimum_required(VERSION 3.13) target_sources(aster_core PRIVATE "manager.cpp" -"buffer_manager.cpp") +"buffer_manager.cpp" +"image_manager.cpp") diff --git a/aster/src/aster/systems/buffer_manager.cpp b/aster/src/aster/systems/buffer_manager.cpp index 67225f2..bf4b4e1 100644 --- a/aster/src/aster/systems/buffer_manager.cpp +++ b/aster/src/aster/systems/buffer_manager.cpp @@ -7,10 +7,12 @@ Manager *Manager::m_Instance; -systems::BufferManager::Ref -systems::BufferManager::CreateStorageBuffer(const usize size, const cstr name) +using namespace systems; + +BufferHandle +BufferManager::CreateStorageBuffer(const usize size, const cstr name) { - Ref object = Alloc(); + auto [handle, object] = Alloc(); // TODO: Storage and Index buffer are set. // This is hacky and should be improved. @@ -22,11 +24,25 @@ systems::BufferManager::CreateStorageBuffer(const usize size, const cstr name) constexpr VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_AUTO; object->Allocate(m_Device, size, usage, createFlags, memoryUsage, name); - return object; + return std::move(handle); } -systems::BufferManager::BufferManager(const Device *device, const u32 maxCount) +Manager::Handle +BufferManager::CreateUniformBuffer(usize size, cstr name) +{ + auto [handle, object] = Alloc(); + + constexpr vk::BufferUsageFlags usage = vk::BufferUsageFlagBits::eUniformBuffer; + constexpr VmaAllocationCreateFlags createFlags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | + VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT | + VMA_ALLOCATION_CREATE_MAPPED_BIT; + constexpr VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_AUTO; + object->Allocate(m_Device, size, usage, createFlags, memoryUsage, name); + + return std::move(handle); +} + +BufferManager::BufferManager(const Device *device, const u32 maxCount) : Manager{device, maxCount} { - SetInstance(this); } \ No newline at end of file diff --git a/aster/src/aster/systems/image_manager.cpp b/aster/src/aster/systems/image_manager.cpp new file mode 100644 index 0000000..7469892 --- /dev/null +++ b/aster/src/aster/systems/image_manager.cpp @@ -0,0 +1,316 @@ +// ============================================= +// Aster: buffer_manager.cpp +// Copyright (c) 2020-2025 Anish Bhobe +// ============================================= + +#include "systems/image_manager.h" + +#include "core/device.h" + +Manager *Manager::m_Instance; + +using namespace systems; + +vk::ImageCreateInfo ToImageCreateInfo(const Texture2DCreateInfo &createInfo); +vk::ImageCreateInfo ToImageCreateInfo(const TextureCubeCreateInfo &createInfo); +vk::ImageCreateInfo ToImageCreateInfo(const AttachmentCreateInfo &createInfo); +vk::ImageCreateInfo ToImageCreateInfo(const DepthStencilImageCreateInfo &createInfo); + +namespace usage_flags +{ +constexpr vk::ImageUsageFlags MIPMAP = vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst; +constexpr vk::ImageUsageFlags SAMPLE = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst; +constexpr vk::ImageUsageFlags STORAGE = + vk::ImageUsageFlagBits::eStorage | vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eTransferSrc; +constexpr vk::ImageUsageFlags COLOR_ATTACHMENT = + vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc; +constexpr vk::ImageUsageFlags DEPTH_STENCIL_ATTACHMENT = vk::ImageUsageFlagBits::eDepthStencilAttachment; +} // namespace usage_flags + +ImageHandle +ImageManager::CreateTexture2D(const Texture2DCreateInfo &createInfo) +{ + constexpr VmaAllocationCreateInfo allocationCreateInfo = { + .flags = {}, + .usage = VMA_MEMORY_USAGE_AUTO, + }; + + VkImage image; + VmaAllocation allocation; + vk::ImageCreateInfo imageCreateInfo = ToImageCreateInfo(createInfo); + auto result = Cast(vmaCreateImage(m_Device->m_Allocator, Recast(&imageCreateInfo), + &allocationCreateInfo, &image, &allocation, nullptr)); + ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", createInfo.m_Name, result) THEN_ABORT(result); + + vk::ImageView view; + const vk::ImageViewCreateInfo imageViewCreateInfo = { + .image = image, + .viewType = vk::ImageViewType::e2D, + .format = imageCreateInfo.format, + .components = {}, + .subresourceRange = + { + .aspectMask = vk::ImageAspectFlagBits::eColor, + .baseMipLevel = 0, + .levelCount = imageCreateInfo.mipLevels, + .baseArrayLayer = 0, + .layerCount = imageCreateInfo.arrayLayers, + }, + }; + result = m_Device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view); + ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", createInfo.m_Name, result) + THEN_ABORT(result); + + auto [handle, object] = Alloc(); + object->m_Image = image; + object->m_View = view; + object->m_Allocation = allocation; + object->m_Extent = imageCreateInfo.extent; + object->m_Flags_ = Image::OWNED_BIT | Image::VALID_BIT; + object->m_LayerCount = Cast(imageCreateInfo.arrayLayers); + object->m_MipLevels = Cast(imageCreateInfo.mipLevels); + + m_Device->SetName(object->m_Image, createInfo.m_Name); + + return handle; +} + +ImageHandle +ImageManager::CreateTextureCube(const TextureCubeCreateInfo &createInfo) +{ + constexpr VmaAllocationCreateInfo allocationCreateInfo = { + .flags = {}, + .usage = VMA_MEMORY_USAGE_AUTO, + }; + + VkImage image; + VmaAllocation allocation; + vk::ImageCreateInfo imageCreateInfo = ToImageCreateInfo(createInfo); + auto result = Cast(vmaCreateImage(m_Device->m_Allocator, Recast(&imageCreateInfo), + &allocationCreateInfo, &image, &allocation, nullptr)); + ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", createInfo.m_Name, result) THEN_ABORT(result); + + vk::ImageView view; + const vk::ImageViewCreateInfo imageViewCreateInfo = { + .image = image, + .viewType = vk::ImageViewType::eCube, + .format = imageCreateInfo.format, + .components = {}, + .subresourceRange = + { + .aspectMask = vk::ImageAspectFlagBits::eColor, + .baseMipLevel = 0, + .levelCount = imageCreateInfo.mipLevels, + .baseArrayLayer = 0, + .layerCount = imageCreateInfo.arrayLayers, + }, + }; + result = m_Device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view); + ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", createInfo.m_Name, result) + THEN_ABORT(result); + + auto [handle, object] = Alloc(); + object->m_Image = image; + object->m_View = view; + object->m_Allocation = allocation; + object->m_Extent = imageCreateInfo.extent; + object->m_Flags_ = Image::OWNED_BIT | Image::VALID_BIT; + object->m_LayerCount = Cast(imageCreateInfo.arrayLayers); + object->m_MipLevels = Cast(imageCreateInfo.mipLevels); + + m_Device->SetName(object->m_Image, createInfo.m_Name); + + return handle; +} + +ImageHandle +ImageManager::CreateAttachment(const AttachmentCreateInfo &createInfo) +{ + constexpr VmaAllocationCreateInfo allocationCreateInfo = { + .flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT, + .usage = VMA_MEMORY_USAGE_AUTO, + }; + + VkImage image; + VmaAllocation allocation; + vk::ImageCreateInfo imageCreateInfo = ToImageCreateInfo(createInfo); + auto result = Cast(vmaCreateImage(m_Device->m_Allocator, Recast(&imageCreateInfo), + &allocationCreateInfo, &image, &allocation, nullptr)); + ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", createInfo.m_Name, result) THEN_ABORT(result); + + vk::ImageView view; + const vk::ImageViewCreateInfo imageViewCreateInfo = { + .image = image, + .viewType = vk::ImageViewType::e2D, + .format = imageCreateInfo.format, + .components = {}, + .subresourceRange = + { + .aspectMask = vk::ImageAspectFlagBits::eColor, + .baseMipLevel = 0, + .levelCount = imageCreateInfo.mipLevels, + .baseArrayLayer = 0, + .layerCount = imageCreateInfo.arrayLayers, + }, + }; + result = m_Device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view); + ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", createInfo.m_Name, result) + THEN_ABORT(result); + + auto [handle, object] = Alloc(); + object->m_Image = image; + object->m_View = view; + object->m_Allocation = allocation; + object->m_Extent = imageCreateInfo.extent; + object->m_Flags_ = Image::OWNED_BIT | Image::VALID_BIT; + object->m_LayerCount = Cast(imageCreateInfo.arrayLayers); + object->m_MipLevels = Cast(imageCreateInfo.mipLevels); + + m_Device->SetName(object->m_Image, createInfo.m_Name); + + return handle; +} + +ImageHandle +ImageManager::CreateDepthStencilImage(const DepthStencilImageCreateInfo &createInfo) +{ + constexpr VmaAllocationCreateInfo allocationCreateInfo = { + .flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT, + .usage = VMA_MEMORY_USAGE_AUTO, + }; + + VkImage image; + VmaAllocation allocation; + vk::ImageCreateInfo imageCreateInfo = ToImageCreateInfo(createInfo); + auto result = Cast(vmaCreateImage(m_Device->m_Allocator, Recast(&imageCreateInfo), + &allocationCreateInfo, &image, &allocation, nullptr)); + ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", createInfo.m_Name, result) THEN_ABORT(result); + + vk::ImageView view; + const vk::ImageViewCreateInfo imageViewCreateInfo = { + .image = image, + .viewType = vk::ImageViewType::e2D, + .format = imageCreateInfo.format, + .components = {}, + .subresourceRange = + { + .aspectMask = vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil, + .baseMipLevel = 0, + .levelCount = imageCreateInfo.mipLevels, + .baseArrayLayer = 0, + .layerCount = imageCreateInfo.arrayLayers, + }, + }; + result = m_Device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view); + ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", createInfo.m_Name, result) + THEN_ABORT(result); + + auto [handle, object] = Alloc(); + object->m_Image = image; + object->m_View = view; + object->m_Allocation = allocation; + object->m_Extent = imageCreateInfo.extent; + object->m_Flags_ = Image::OWNED_BIT | Image::VALID_BIT; + object->m_LayerCount = Cast(imageCreateInfo.arrayLayers); + object->m_MipLevels = Cast(imageCreateInfo.mipLevels); + + m_Device->SetName(object->m_Image, createInfo.m_Name); + + return handle; +} + +vk::ImageCreateInfo +ToImageCreateInfo(const Texture2DCreateInfo &createInfo) +{ + auto &[format, extent, name, isSampled, isMipMapped, isStorage] = createInfo; + + WARN_IF(!IsPowerOfTwo(extent.width) || !IsPowerOfTwo(extent.width), "Image {2} is {0}x{1} (Non Power of Two)", + extent.width, extent.height, name ? name : ""); + + const u8 mipLevels = isMipMapped ? 1 + Cast(floor(log2(eastl::max(extent.width, extent.height)))) : 1; + + auto usage = vk::ImageUsageFlags{}; + if (isSampled) + usage |= usage_flags::SAMPLE; + if (isMipMapped) + usage |= usage_flags::MIPMAP; + if (isStorage) + usage |= usage_flags::STORAGE; + + return { + .imageType = vk::ImageType::e2D, + .format = format, + .extent = ToExtent3D(extent, 1), + .mipLevels = mipLevels, + .arrayLayers = 1, + .usage = usage, + }; +} + +vk::ImageCreateInfo +ToImageCreateInfo(const TextureCubeCreateInfo &createInfo) +{ + auto &[format, side, name, isSampled, isMipMapped, isStorage] = createInfo; + + WARN_IF(!IsPowerOfTwo(side), "ImageCube {1} is {0}x{0} (Non Power of Two)", side, name ? name : ""); + + const u8 mipLevels = isMipMapped ? 1 + Cast(floor(log2(side))) : 1; + + auto usage = vk::ImageUsageFlags{}; + if (isSampled) + usage |= usage_flags::SAMPLE; + if (isMipMapped) + usage |= usage_flags::MIPMAP; + if (isStorage) + usage |= usage_flags::STORAGE; + + return { + .flags = vk::ImageCreateFlagBits::eCubeCompatible, + .imageType = vk::ImageType::e2D, + .format = format, + .extent = {side, side, 1}, + .mipLevels = mipLevels, + .arrayLayers = 6, + .usage = usage, + }; +} + +vk::ImageCreateInfo +ToImageCreateInfo(const AttachmentCreateInfo &createInfo) +{ + auto &[format, extent, name] = createInfo; + + constexpr auto usage = usage_flags::COLOR_ATTACHMENT; + + return { + .imageType = vk::ImageType::e2D, + .format = format, + .extent = ToExtent3D(extent, 1), + .mipLevels = 1, + .arrayLayers = 1, + .usage = usage, + }; +} + +vk::ImageCreateInfo +ToImageCreateInfo(const DepthStencilImageCreateInfo &createInfo) +{ + auto &[extent, name] = createInfo; + + constexpr vk::Format format = vk::Format::eD24UnormS8Uint; + constexpr auto usage = usage_flags::DEPTH_STENCIL_ATTACHMENT; + + return { + .imageType = vk::ImageType::e2D, + .format = format, + .extent = ToExtent3D(extent, 1), + .mipLevels = 1, + .arrayLayers = 1, + .usage = usage, + }; +} + +ImageManager::ImageManager(const Device *device, const u32 maxCount) + : Manager{device, maxCount} +{ +} \ No newline at end of file diff --git a/samples/02_box/CMakeLists.txt b/samples/02_box/CMakeLists.txt index c71f222..c4ebfef 100644 --- a/samples/02_box/CMakeLists.txt +++ b/samples/02_box/CMakeLists.txt @@ -7,6 +7,8 @@ cmake_minimum_required(VERSION 3.13) add_executable(box "box.cpp" "stb_image.h") add_shader(box "shader/box.vert.glsl") add_shader(box "shader/box.frag.glsl") +add_shader(box "shader/box.vs.hlsl") +add_shader(box "shader/box.ps.hlsl") target_link_libraries(box PRIVATE aster_core) target_link_libraries(box PRIVATE util_helper) diff --git a/samples/02_box/box.cpp b/samples/02_box/box.cpp index 6e2c145..3d7da96 100644 --- a/samples/02_box/box.cpp +++ b/samples/02_box/box.cpp @@ -9,23 +9,25 @@ #include "aster/core/constants.h" #include "aster/core/context.h" #include "aster/core/device.h" +#include "aster/core/image.h" #include "aster/core/physical_device.h" #include "aster/core/pipeline.h" #include "aster/core/swapchain.h" #include "aster/core/window.h" -#include "aster/core/image.h" #include "helpers.h" #define STB_IMAGE_IMPLEMENTATION +#include "aster/systems/buffer_manager.h" +#include "aster/systems/image_manager.h" #include "frame.h" #include "stb_image.h" #include constexpr u32 MAX_FRAMES_IN_FLIGHT = 3; -constexpr auto VERTEX_SHADER_FILE = "shader/box.vert.glsl.spv"; -constexpr auto FRAGMENT_SHADER_FILE = "shader/box.frag.glsl.spv"; +constexpr auto VERTEX_SHADER_FILE = "shader/box.vs.hlsl.spv"; +constexpr auto FRAGMENT_SHADER_FILE = "shader/box.ps.hlsl.spv"; struct ImageFile { @@ -76,32 +78,9 @@ Pipeline CreatePipeline(const Device *device, const Swapchain *swapchain); struct Vertex { vec3 m_Position; + f32 m_PositionW = 1.0; vec2 m_TexCoord0; - - constexpr static vk::VertexInputBindingDescription - GetBinding(const u32 binding) - { - return {.binding = binding, .stride = sizeof(Vertex), .inputRate = vk::VertexInputRate::eVertex}; - } - - constexpr static eastl::array - GetAttributes(const u32 binding) - { - return { - vk::VertexInputAttributeDescription{ - .location = 0, - .binding = binding, - .format = vk::Format::eR32G32B32Sfloat, - .offset = offsetof(Vertex, m_Position), - }, - vk::VertexInputAttributeDescription{ - .location = 1, - .binding = binding, - .format = vk::Format::eR32G32Sfloat, - .offset = offsetof(Vertex, m_TexCoord0), - }, - }; - } + vec2 m_Padding0_ = {0.0f, 0.0f}; }; struct Camera @@ -127,7 +106,8 @@ main(int, char **) Features enabledDeviceFeatures = { .m_Vulkan10Features = {.samplerAnisotropy = true}, - .m_Vulkan13Features = {.dynamicRendering = true}, + .m_Vulkan12Features = {.bufferDeviceAddress = true}, + .m_Vulkan13Features = {.synchronization2 = true, .dynamicRendering = true}, }; QueueAllocation queueAllocation = FindAppropriateQueueAllocation(&deviceToUse); Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"}; @@ -135,6 +115,9 @@ main(int, char **) Swapchain swapchain = {&surface, &device, window.GetSize(), "Primary Chain"}; Pipeline pipeline = CreatePipeline(&device, &swapchain); + systems::BufferManager bufferManager{&device, 12}; + systems::ImageManager imageManager{&device, 12}; + Camera camera = { .m_Model = {1.0f}, .m_View = glm::lookAt(vec3(0.0f, 2.0f, 2.0f), vec3(0.0f), vec3(0.0f, 1.0f, 0.0f)), @@ -155,6 +138,10 @@ main(int, char **) .type = vk::DescriptorType::eCombinedImageSampler, .descriptorCount = 1, }, + vk::DescriptorPoolSize{ + .type = vk::DescriptorType::eStorageBuffer, + .descriptorCount = 1, + }, }; vk::DescriptorPoolCreateInfo descriptorPoolCreateInfo = { .maxSets = 1, .poolSizeCount = Cast(poolSizes.size()), .pPoolSizes = poolSizes.data()}; @@ -235,24 +222,32 @@ main(int, char **) assert(loaded); INFO("Image {}x{} : {} channels", imageFile.m_Width, imageFile.m_Height, imageFile.m_NumChannels); - VertexBuffer vbo; - Texture crate; - vbo.Init(&device, vertices.size() * sizeof vertices[0], "VBO"); - crate.Init(&device, {imageFile.m_Width, imageFile.m_Height}, vk::Format::eR8G8B8A8Srgb, false, "Crate Texture"); + auto vbo = bufferManager.CreateStorageBuffer(vertices.size() * sizeof vertices[0], "Vertex Buffer").ToPointer(); + auto crate = imageManager + .CreateTexture2D({ + .m_Format = vk::Format::eR8G8B8A8Srgb, + .m_Extent = {imageFile.m_Width, imageFile.m_Height}, + .m_Name = "Crate Texture", + }) + .ToPointer(); + vbo->Write(&device, 0, vertices.size() * sizeof vertices[0], vertices.data()); + { - StagingBuffer vertexStaging, imageStaging; - vertexStaging.Init(&device, vertices.size() * sizeof vertices[0], "Vertex Staging"); - vertexStaging.Write(&device, 0, vertices.size() * sizeof vertices[0], vertices.data()); + StagingBuffer imageStaging; imageStaging.Init(&device, imageFile.GetSize(), "Image Staging"); imageStaging.Write(&device, 0, imageFile.GetSize(), imageFile.m_Data); - vk::ImageMemoryBarrier imageReadyToWrite = { + vk::ImageMemoryBarrier2 imageReadyToWrite = { + .srcStageMask = vk::PipelineStageFlagBits2::eTransfer, + .srcAccessMask = vk::AccessFlagBits2::eNone, + .dstStageMask = vk::PipelineStageFlagBits2::eTransfer, + .dstAccessMask = vk::AccessFlagBits2::eTransferWrite, .oldLayout = vk::ImageLayout::eUndefined, .newLayout = vk::ImageLayout::eTransferDstOptimal, .srcQueueFamilyIndex = queueAllocation.m_Family, .dstQueueFamilyIndex = queueAllocation.m_Family, - .image = crate.m_Image, + .image = crate->m_Image, .subresourceRange = { .aspectMask = vk::ImageAspectFlagBits::eColor, @@ -262,13 +257,21 @@ main(int, char **) .layerCount = 1, }, }; + vk::DependencyInfo imageReadyToWriteDependency = { + .imageMemoryBarrierCount = 1, + .pImageMemoryBarriers = &imageReadyToWrite, + }; - vk::ImageMemoryBarrier imageReadyToRead = { + vk::ImageMemoryBarrier2 imageReadyToRead = { + .srcStageMask = vk::PipelineStageFlagBits2::eTransfer, + .srcAccessMask = vk::AccessFlagBits2::eTransferWrite, + .dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader, + .dstAccessMask = vk::AccessFlagBits2::eShaderRead, .oldLayout = vk::ImageLayout::eTransferDstOptimal, .newLayout = vk::ImageLayout::eShaderReadOnlyOptimal, .srcQueueFamilyIndex = queueAllocation.m_Family, .dstQueueFamilyIndex = queueAllocation.m_Family, - .image = crate.m_Image, + .image = crate->m_Image, .subresourceRange = { .aspectMask = vk::ImageAspectFlagBits::eColor, @@ -278,6 +281,10 @@ main(int, char **) .layerCount = 1, }, }; + vk::DependencyInfo imageReadyToReadDependency = { + .imageMemoryBarrierCount = 1, + .pImageMemoryBarriers = &imageReadyToRead, + }; vk::Fence fence; vk::FenceCreateInfo fenceCreateInfo = {}; @@ -285,11 +292,8 @@ main(int, char **) vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit}; AbortIfFailed(copyBuffer.begin(&beginInfo)); - copyBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eHost, vk::PipelineStageFlagBits::eTransfer, {}, 0, - nullptr, 0, nullptr, 1, &imageReadyToWrite); - vk::BufferCopy bufferCopy = {.srcOffset = 0, .dstOffset = 0, .size = vertexStaging.GetSize()}; - copyBuffer.copyBuffer(vertexStaging.m_Buffer, vbo.m_Buffer, 1, &bufferCopy); + copyBuffer.pipelineBarrier2(&imageReadyToWriteDependency); vk::BufferImageCopy imageCopy = { .bufferOffset = 0, @@ -305,11 +309,10 @@ main(int, char **) .imageOffset = {}, .imageExtent = {imageFile.m_Width, imageFile.m_Height, 1}, }; - copyBuffer.copyBufferToImage(imageStaging.m_Buffer, crate.m_Image, vk::ImageLayout::eTransferDstOptimal, 1, + copyBuffer.copyBufferToImage(imageStaging.m_Buffer, crate->m_Image, vk::ImageLayout::eTransferDstOptimal, 1, &imageCopy); - copyBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {}, - 0, nullptr, 0, nullptr, 1, &imageReadyToRead); + copyBuffer.pipelineBarrier2(&imageReadyToReadDependency); AbortIfFailed(copyBuffer.end()); @@ -327,7 +330,6 @@ main(int, char **) AbortIfFailedM(device.m_Device.resetCommandPool(copyPool, {}), "Couldn't reset command pool."); device.m_Device.destroy(fence, nullptr); - vertexStaging.Destroy(&device); imageStaging.Destroy(&device); } @@ -351,19 +353,23 @@ main(int, char **) AbortIfFailed(device.m_Device.createSampler(&samplerCreateInfo, nullptr, &sampler)); } - UniformBuffer ubo; - ubo.Init(&device, sizeof camera, "Camera UBO"); - ubo.Write(&device, 0, sizeof camera, &camera); + auto ubo = bufferManager.CreateUniformBuffer(sizeof camera, "Camera UBO").ToPointer(); + ubo->Write(&device, 0, sizeof camera, &camera); vk::DescriptorBufferInfo descriptorBufferInfo = { - .buffer = ubo.m_Buffer, + .buffer = ubo->m_Buffer, .offset = 0, - .range = ubo.GetSize(), + .range = ubo->GetSize(), }; vk::DescriptorImageInfo descriptorImageInfo = { .sampler = sampler, - .imageView = crate.m_View, + .imageView = crate->m_View, .imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal, }; + vk::DescriptorBufferInfo descriptorStorageBufferInfo = { + .buffer = vbo->m_Buffer, + .offset = 0, + .range = vbo->GetSize(), + }; eastl::array writeDescriptors = { vk::WriteDescriptorSet{ .dstSet = descriptorSet, @@ -381,6 +387,14 @@ main(int, char **) .descriptorType = vk::DescriptorType::eCombinedImageSampler, .pImageInfo = &descriptorImageInfo, }, + vk::WriteDescriptorSet{ + .dstSet = descriptorSet, + .dstBinding = 2, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = vk::DescriptorType::eStorageBuffer, + .pBufferInfo = &descriptorStorageBufferInfo, + }, }; device.m_Device.updateDescriptorSets(Cast(writeDescriptors.size()), writeDescriptors.data(), 0, nullptr); @@ -414,35 +428,56 @@ main(int, char **) .baseArrayLayer = 0, .layerCount = 1, }; - vk::ImageMemoryBarrier topOfThePipeBarrier = { + vk::ImageMemoryBarrier2 topOfThePipeBarrier = { + // For Color Attachment output ref: + // https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/7193#issuecomment-1875960974 + .srcStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput, + .srcAccessMask = vk::AccessFlagBits2::eNone, + .dstStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput, + .dstAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite, .oldLayout = vk::ImageLayout::eUndefined, .newLayout = vk::ImageLayout::eColorAttachmentOptimal, .srcQueueFamilyIndex = queueAllocation.m_Family, .dstQueueFamilyIndex = queueAllocation.m_Family, .subresourceRange = subresourceRange, }; - vk::ImageMemoryBarrier renderToPresentBarrier = { + vk::DependencyInfo topOfThePipeDependency = { + .imageMemoryBarrierCount = 1, + .pImageMemoryBarriers = &topOfThePipeBarrier, + }; + vk::ImageMemoryBarrier2 renderToPresentBarrier = { + .srcStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput, + .srcAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite, + .dstStageMask = vk::PipelineStageFlagBits2::eBottomOfPipe, + .dstAccessMask = vk::AccessFlagBits2::eNone, .oldLayout = vk::ImageLayout::eColorAttachmentOptimal, .newLayout = vk::ImageLayout::ePresentSrcKHR, .srcQueueFamilyIndex = queueAllocation.m_Family, .dstQueueFamilyIndex = queueAllocation.m_Family, .subresourceRange = subresourceRange, }; + vk::DependencyInfo renderToPresentDependency = { + .imageMemoryBarrierCount = 1, + .pImageMemoryBarriers = &renderToPresentBarrier, + }; FrameManager frameManager = {&device, queueAllocation.m_Family, MAX_FRAMES_IN_FLIGHT}; - eastl::fixed_vector depthImages(frameManager.m_FramesInFlight); - for (auto &depthImage : depthImages) - { - depthImage.Init(&device, swapchain.m_Extent, "Depth"); - } + eastl::fixed_vector, MAX_FRAMES_IN_FLIGHT> depthImages; - auto recreateDepthBuffers = [&device, &depthImages](vk::Extent2D extent) { - for (auto &depthImage : depthImages) + auto initDepthImages = [&imageManager, &depthImages, &frameManager] (const vk::Extent2D extent) { + for (u32 i = 0; i < frameManager.m_FramesInFlight; ++i) { - depthImage.Destroy(&device); - depthImage.Init(&device, extent, "Depth"); + depthImages.push_back( + imageManager.CreateDepthStencilImage({.m_Extent = extent, .m_Name = "Depth"}).ToPointer()); } }; + + initDepthImages(swapchain.m_Extent); + + auto recreateDepthBuffers = [&depthImages, &initDepthImages](const vk::Extent2D extent) { + depthImages.clear(); + initDepthImages(extent); + }; swapchain.RegisterResizeCallback(recreateDepthBuffers); Time::Init(); @@ -453,7 +488,7 @@ main(int, char **) Time::Update(); camera.m_Model *= rotate(mat4{1.0f}, Cast(45.0_deg * Time::m_Delta), vec3(0.0f, 1.0f, 0.0f)); - ubo.Write(&device, 0, sizeof camera, &camera); + ubo->Write(&device, 0, sizeof camera, &camera); Frame *currentFrame = frameManager.GetNextFrame(&swapchain, &surface, window.GetSize()); @@ -461,7 +496,7 @@ main(int, char **) vk::ImageView currentImageView = swapchain.m_ImageViews[imageIndex]; vk::Image currentImage = swapchain.m_Images[imageIndex]; vk::CommandBuffer cmd = currentFrame->m_CommandBuffer; - vk::ImageView currentDepthImageView = depthImages[currentFrame->m_FrameIdx].m_View; + vk::ImageView currentDepthImageView = depthImages[currentFrame->m_FrameIdx]->m_View; topOfThePipeBarrier.image = currentImage; renderToPresentBarrier.image = currentImage; @@ -469,8 +504,7 @@ main(int, char **) vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit}; AbortIfFailed(cmd.begin(&beginInfo)); - cmd.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eColorAttachmentOutput, - {}, 0, nullptr, 0, nullptr, 1, &topOfThePipeBarrier); + cmd.pipelineBarrier2(&topOfThePipeDependency); // Render eastl::array attachmentInfos = { @@ -480,7 +514,7 @@ main(int, char **) .resolveMode = vk::ResolveModeFlagBits::eNone, .loadOp = vk::AttachmentLoadOp::eClear, .storeOp = vk::AttachmentStoreOp::eStore, - .clearValue = vk::ClearColorValue{0.0f, 0.0f, 0.0f, 1.0f}, + .clearValue = vk::ClearColorValue{0.0f, 0.0f, 0.0f, 0.0f}, }, }; @@ -507,14 +541,11 @@ main(int, char **) cmd.setScissor(0, 1, &scissor); cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.m_Pipeline); cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline.m_Layout, 0, 1, &descriptorSet, 0, nullptr); - usize offsets = 0; - cmd.bindVertexBuffers(0, 1, &vbo.m_Buffer, &offsets); cmd.draw(Cast(vertices.size()), 1, 0, 0); cmd.endRendering(); - cmd.pipelineBarrier(vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::PipelineStageFlagBits::eBottomOfPipe, - {}, 0, nullptr, 0, nullptr, 1, &renderToPresentBarrier); + cmd.pipelineBarrier2(&renderToPresentDependency); AbortIfFailed(cmd.end()); @@ -534,17 +565,9 @@ main(int, char **) } device.WaitIdle(); - - for (auto &depthImage : depthImages) - { - depthImage.Destroy(&device); - } device.m_Device.destroy(sampler, nullptr); - ubo.Destroy(&device); device.m_Device.destroy(descriptorPool, nullptr); device.m_Device.destroy(copyPool, nullptr); - crate.Destroy(&device); - vbo.Destroy(&device); return 0; } @@ -582,6 +605,12 @@ CreatePipeline(const Device *device, const Swapchain *swapchain) .descriptorCount = 1, .stageFlags = vk::ShaderStageFlagBits::eFragment, }, + vk::DescriptorSetLayoutBinding{ + .binding = 2, + .descriptorType = vk::DescriptorType::eStorageBuffer, + .descriptorCount = 1, + .stageFlags = vk::ShaderStageFlagBits::eVertex, + }, }; vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = { .bindingCount = Cast(descriptorSetLayoutBinding.size()), @@ -601,15 +630,7 @@ CreatePipeline(const Device *device, const Swapchain *swapchain) AbortIfFailed(device->m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &pipelineLayout)); device->SetName(pipelineLayout, "Box Layout"); - vk::VertexInputBindingDescription inputBindingDescription = Vertex::GetBinding(0); - auto inputAttributeDescription = Vertex::GetAttributes(0); - - vk::PipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = { - .vertexBindingDescriptionCount = 1, - .pVertexBindingDescriptions = &inputBindingDescription, - .vertexAttributeDescriptionCount = Cast(inputAttributeDescription.size()), - .pVertexAttributeDescriptions = inputAttributeDescription.data(), - }; + vk::PipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = {}; vk::PipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo = { .topology = vk::PrimitiveTopology::eTriangleList, .primitiveRestartEnable = false, diff --git a/samples/02_box/shader/box.ps.hlsl b/samples/02_box/shader/box.ps.hlsl new file mode 100644 index 0000000..562c878 --- /dev/null +++ b/samples/02_box/shader/box.ps.hlsl @@ -0,0 +1,19 @@ +struct FS_Input { + float2 UV0 : TEXCOORD0; +}; + +struct FS_Output +{ + float4 ColorTarget : SV_Target0; +}; + +[[vk::binding(1, 0)]] Texture2D Texture; +[[vk::binding(1, 0)]] SamplerState Sampler; + +FS_Output main(FS_Input StageInput) { + FS_Output output; + + output.ColorTarget = float4(Texture.Sample(Sampler, StageInput.UV0).rgb, 1.0); + + return output; +} \ No newline at end of file diff --git a/samples/02_box/shader/box.vs.hlsl b/samples/02_box/shader/box.vs.hlsl new file mode 100644 index 0000000..4d96c75 --- /dev/null +++ b/samples/02_box/shader/box.vs.hlsl @@ -0,0 +1,36 @@ +struct VS_Input +{ + uint VertexIndex : SV_VertexID; +}; + +struct VS_Output +{ + float2 UV0 : TEXCOORD0; + float4 VertexPosition : SV_Position; +}; + +struct CameraData { + float4x4 Model; + float4x4 View; + float4x4 Projection; +}; + +struct VertexData { + float4 Position; + float2 UV0; +}; + +[[vk::binding(0, 0)]] ConstantBuffer Camera; +[[vk::binding(2, 0)]] StructuredBuffer Vertices; + +VS_Output main(VS_Input StageInput) { + VS_Output output; + + output.UV0 = Vertices[StageInput.VertexIndex].UV0; + + float4 position = Vertices[StageInput.VertexIndex].Position; + + output.VertexPosition = mul(Camera.Projection, mul(Camera.View, mul(Camera.Model, position))); + + return output; +} \ No newline at end of file