diff --git a/aster/include/aster/core/device.h b/aster/include/aster/core/device.h index a4f4669..2ba8c83 100644 --- a/aster/include/aster/core/device.h +++ b/aster/include/aster/core/device.h @@ -40,10 +40,9 @@ struct Device final void WaitIdle() const; // Ctor/Dtor - Device(const Instance *context, PhysicalDevice *physicalDevice, Features *enabledFeatures, - const eastl::vector &queueAllocations, NameString &&name); - Device(const Instance *context, PhysicalDevice *physicalDevice, Features *enabledFeatures, - const eastl::vector &queueAllocations, eastl::span &&pipelineCacheData, + Device() = default; + Device(const Instance &context, PhysicalDevice &physicalDevice, Features &enabledFeatures, + const eastl::span &queueAllocations, const eastl::span &pipelineCacheData, NameString &&name); ~Device(); diff --git a/aster/include/aster/core/global.h b/aster/include/aster/core/global.h index 3a017e4..f00d01b 100644 --- a/aster/include/aster/core/global.h +++ b/aster/include/aster/core/global.h @@ -55,6 +55,29 @@ constexpr u32 ASTER_API_VERSION = VK_API_VERSION_1_3; #define TODO(MSG) assert(false && ("Unimplemented: " MSG)) #define FIX(MSG) static_assert(false && ("Unimplemented: " MSG)) +#define AbortIfFailed(RESULT) \ + do \ + { \ + vk::Result _checkResultValue_; \ + ERROR_IF(Failed(_checkResultValue_ = Cast(RESULT)), "Cause: {}", _checkResultValue_) \ + THEN_ABORT(_checkResultValue_); \ + } while (false) + +#define AbortIfFailedMV(RESULT, MSG, EXTRA) \ + do \ + { \ + vk::Result _checkResultValue_; \ + ERROR_IF(Failed(_checkResultValue_ = Cast(RESULT)), MSG " Cause: {}", EXTRA, _checkResultValue_) \ + THEN_ABORT(_checkResultValue_); \ + } while (false) + +#define AbortIfFailedM(RESULT, MSG) \ + do \ + { \ + auto _checkResultValue_ = Cast(RESULT); \ + ERROR_IF(Failed(_checkResultValue_), MSG " Cause: {}", _checkResultValue_) THEN_ABORT(_checkResultValue_); \ + } while (false) + [[nodiscard]] inline bool Failed(const vk::Result result) { diff --git a/aster/include/aster/core/instance.h b/aster/include/aster/core/instance.h index 63225d8..1763bac 100644 --- a/aster/include/aster/core/instance.h +++ b/aster/include/aster/core/instance.h @@ -21,6 +21,7 @@ struct Instance final vk::DebugUtilsMessengerEXT m_DebugMessenger = nullptr; // Ctor/Dtor + Instance() = default; Instance(cstr appName, Version version, bool enableValidation = ENABLE_LAYER_MESSAGES_DEFAULT_VALUE); ~Instance(); diff --git a/aster/include/aster/core/physical_device.h b/aster/include/aster/core/physical_device.h index e7cea9f..fc1e7e2 100644 --- a/aster/include/aster/core/physical_device.h +++ b/aster/include/aster/core/physical_device.h @@ -54,5 +54,5 @@ struct PhysicalDevice final class PhysicalDevices : public eastl::fixed_vector { public: - PhysicalDevices(const Surface *surface, const Instance *context); + PhysicalDevices(const Surface &surface, const Instance &context); }; \ No newline at end of file diff --git a/aster/include/aster/core/surface.h b/aster/include/aster/core/surface.h index 0abbd35..bc9689f 100644 --- a/aster/include/aster/core/surface.h +++ b/aster/include/aster/core/surface.h @@ -17,7 +17,8 @@ struct Surface NameString m_Name; // Ctor Dtor - Surface(Instance *context, const Window *window, cstr name); + Surface() = default; + Surface(Instance &context, const Window &window); ~Surface(); // Move diff --git a/aster/include/aster/core/swapchain.h b/aster/include/aster/core/swapchain.h index 37e6d15..a380d69 100644 --- a/aster/include/aster/core/swapchain.h +++ b/aster/include/aster/core/swapchain.h @@ -21,7 +21,6 @@ struct Swapchain final const Device *m_Device; vk::SwapchainKHR m_Swapchain; - NameString m_Name; vk::Extent2D m_Extent; vk::Format m_Format; eastl::fixed_vector m_Images; @@ -29,11 +28,12 @@ struct Swapchain final eastl::vector m_ResizeCallbacks; - void Create(const Surface *window, Size2D size); + void Create(const Surface &surface, Size2D size); void RegisterResizeCallback(FnResizeCallback &&callback); // Ctor/Dtor - Swapchain(const Surface *window, const Device *device, Size2D size, NameString &&name); + Swapchain() = default; + Swapchain(const Surface &surface, const Device &device, Size2D size); ~Swapchain(); // Move diff --git a/aster/include/aster/core/window.h b/aster/include/aster/core/window.h index e4b7aff..e291c89 100644 --- a/aster/include/aster/core/window.h +++ b/aster/include/aster/core/window.h @@ -20,6 +20,8 @@ struct Window final static std::atomic_uint64_t m_WindowCount; static std::atomic_bool m_IsGlfwInit; + static void SetupLibrary(); + static cstr *GetInstanceExtensions(u32 *extensionCount); // Methods [[nodiscard]] bool diff --git a/aster/include/aster/systems/CMakeLists.txt b/aster/include/aster/systems/CMakeLists.txt index 6022578..9d34c71 100644 --- a/aster/include/aster/systems/CMakeLists.txt +++ b/aster/include/aster/systems/CMakeLists.txt @@ -4,10 +4,6 @@ cmake_minimum_required(VERSION 3.13) target_sources(aster_core INTERFACE - "buffer_manager.h" - "image_manager.h" - "view_manager.h" - "sampler_manager.h" + "device.h" "resource.h" - "resource_manager.h" "commit_manager.h") diff --git a/aster/include/aster/systems/buffer_manager.h b/aster/include/aster/systems/buffer_manager.h deleted file mode 100644 index f214a3a..0000000 --- a/aster/include/aster/systems/buffer_manager.h +++ /dev/null @@ -1,35 +0,0 @@ -// ============================================= -// Aster: buffer_manager.h -// Copyright (c) 2020-2025 Anish Bhobe -// ============================================= - -#pragma once - -#include "aster/aster.h" -#include "aster/core/buffer.h" - -namespace systems -{ - -template TTo, std::derived_from TFrom> -static Ref -CastBuffer(const Ref &from) -{ - if constexpr (not concepts::BufferInto) - assert(TTo::FLAGS & from->m_Flags); - return std::reinterpret_pointer_cast(from); -} - -class BufferManager final -{ - const Device *m_Device = nullptr; - - public: - explicit BufferManager(const Device *device); - - [[nodiscard]] Ref CreateStorageBuffer(usize size, cstr name = nullptr) const; - [[nodiscard]] Ref CreateUniformBuffer(usize size, cstr name = nullptr) const; - [[nodiscard]] Ref CreateStagingBuffer(usize size, cstr name = nullptr) const; - [[nodiscard]] Ref CreateVertexBuffer(usize size, cstr name = nullptr) const; -}; -} // namespace systems \ No newline at end of file diff --git a/aster/include/aster/systems/commit_manager.h b/aster/include/aster/systems/commit_manager.h index c791b66..99afcfb 100644 --- a/aster/include/aster/systems/commit_manager.h +++ b/aster/include/aster/systems/commit_manager.h @@ -7,16 +7,16 @@ #include "aster/aster.h" -#include "buffer_manager.h" -#include "sampler_manager.h" -#include "view_manager.h" - #include "aster/util/freelist.h" #include "EASTL/deque.h" #include "EASTL/intrusive_hash_map.h" #include "resource.h" +#include "EASTL/vector.h" +#include "aster/core/buffer.h" +#include "aster/core/image_view.h" +#include "aster/core/sampler.h" namespace systems { diff --git a/aster/include/aster/systems/device.h b/aster/include/aster/systems/device.h new file mode 100644 index 0000000..0d41368 --- /dev/null +++ b/aster/include/aster/systems/device.h @@ -0,0 +1,627 @@ +// ============================================= +// Aster: device.h +// Copyright (c) 2020-2025 Anish Bhobe +// ============================================= + +#include "resource.h" + +#include "aster/aster.h" +#include "aster/core/buffer.h" +#include "aster/core/device.h" +#include "aster/core/image.h" +#include "aster/core/image_view.h" +#include "aster/core/instance.h" +#include "aster/core/physical_device.h" +#include "aster/core/sampler.h" +#include "aster/core/swapchain.h" +#include "aster/core/pipeline.h" + +#include +#include +#include + +#include + +constexpr static u32 MAX_FRAMES_IN_FLIGHT = 3; + +struct Window; +using CoreDevice = Device; + +template <> +struct eastl::hash +{ + usize + operator()(const vk::SamplerCreateInfo &createInfo) const noexcept + { + usize hash = HashAny(createInfo.flags); + hash = HashCombine(hash, HashAny(createInfo.magFilter)); + hash = HashCombine(hash, HashAny(createInfo.minFilter)); + hash = HashCombine(hash, HashAny(createInfo.mipmapMode)); + hash = HashCombine(hash, HashAny(createInfo.addressModeU)); + hash = HashCombine(hash, HashAny(createInfo.addressModeV)); + hash = HashCombine(hash, HashAny(createInfo.addressModeW)); + hash = HashCombine(hash, HashAny(Cast(createInfo.mipLodBias * 1000))); // Resolution of 10^-3 + hash = HashCombine(hash, HashAny(createInfo.anisotropyEnable)); + hash = + HashCombine(hash, + HashAny(Cast(createInfo.maxAnisotropy * 0x20))); // 32:1 Anisotropy is enough resolution + hash = HashCombine(hash, HashAny(createInfo.compareEnable)); + hash = HashCombine(hash, HashAny(createInfo.compareOp)); + hash = HashCombine(hash, HashAny(Cast(createInfo.minLod * 1000))); // 0.001 resolution is enough. + hash = + HashCombine(hash, + HashAny(Cast(createInfo.maxLod * 1000))); // 0.001 resolution is enough. (1 == NO Clamp) + hash = HashCombine(hash, HashAny(createInfo.borderColor)); + hash = HashCombine(hash, HashAny(createInfo.unnormalizedCoordinates)); + + return hash; + } +}; + +namespace systems +{ + +// ==================================================================================================== +#pragma region Creation Structs +// ==================================================================================================== + +// ---------------------------------------------------------------------------------------------------- +#pragma region Image +// ---------------------------------------------------------------------------------------------------- + +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; +}; + +#pragma endregion + +// ---------------------------------------------------------------------------------------------------- +#pragma region View +// ---------------------------------------------------------------------------------------------------- + +template +struct ViewCreateInfo +{ + using ImageType = TImage; + + Ref m_Image; + cstr m_Name; + vk::ImageViewType m_ViewType = vk::ImageViewType::e2D; + vk::ComponentMapping m_Components = {}; + vk::ImageAspectFlags m_AspectMask = {}; + eastl::optional m_MipLevelCount = eastl::nullopt; + eastl::optional m_LayerCount = eastl::nullopt; + u8 m_BaseMipLevel = 0; + u8 m_BaseLayer = 0; + + [[nodiscard]] u8 + GetMipLevelCount() const + { + return m_MipLevelCount.value_or(m_Image->m_MipLevels - m_BaseMipLevel); + } + + [[nodiscard]] u8 + GetLayerCount() const + { + return m_LayerCount.value_or(m_Image->m_LayerCount - m_BaseLayer); + } + + explicit + operator vk::ImageViewCreateInfo() const + { + return { + .image = m_Image->m_Image, + .viewType = m_ViewType, + .format = m_Image->m_Format, + .components = m_Components, + .subresourceRange = + { + .aspectMask = m_AspectMask, + .baseMipLevel = m_BaseMipLevel, + .levelCount = GetMipLevelCount(), + .baseArrayLayer = m_BaseLayer, + .layerCount = GetLayerCount(), + }, + }; + } + + explicit + operator ViewCreateInfo() const + { + return { + .m_Image = CastImage(m_Image), + .m_Name = m_Name, + .m_ViewType = m_ViewType, + .m_Components = m_Components, + .m_AspectMask = m_AspectMask, + .m_MipLevelCount = m_MipLevelCount, + .m_LayerCount = m_LayerCount, + .m_BaseMipLevel = m_BaseMipLevel, + .m_BaseLayer = m_BaseLayer, + }; + } +}; +#pragma endregion + +// ---------------------------------------------------------------------------------------------------- +#pragma region Sampler +// ---------------------------------------------------------------------------------------------------- + +struct SamplerCreateInfo +{ + cstr m_Name = nullptr; + vk::SamplerCreateFlags m_Flags = {}; + vk::Filter m_MagFilter = vk::Filter::eLinear; + vk::Filter m_MinFilter = vk::Filter::eLinear; + vk::SamplerMipmapMode m_MipmapMode = vk::SamplerMipmapMode::eLinear; + vk::SamplerAddressMode m_AddressModeU = vk::SamplerAddressMode::eRepeat; + vk::SamplerAddressMode m_AddressModeV = vk::SamplerAddressMode::eRepeat; + vk::SamplerAddressMode m_AddressModeW = vk::SamplerAddressMode::eRepeat; + vk::BorderColor m_BorderColor = vk::BorderColor::eFloatOpaqueBlack; + vk::CompareOp m_CompareOp = vk::CompareOp::eNever; + f32 m_MipLodBias = 0.0f; + f32 m_MaxAnisotropy = 16.0f; + f32 m_MinLod = 0; + f32 m_MaxLod = VK_LOD_CLAMP_NONE; + bool m_AnisotropyEnable = true; + bool m_CompareEnable = false; + bool m_NormalizedCoordinates = true; + + explicit + operator vk::SamplerCreateInfo() const + { + return { + .flags = m_Flags, + .magFilter = m_MagFilter, + .minFilter = m_MinFilter, + .mipmapMode = m_MipmapMode, + .addressModeU = m_AddressModeU, + .addressModeV = m_AddressModeV, + .addressModeW = m_AddressModeW, + .mipLodBias = m_MipLodBias, + .anisotropyEnable = m_AnisotropyEnable, + .maxAnisotropy = m_MaxAnisotropy, + .compareEnable = m_CompareEnable, + .compareOp = m_CompareOp, + .minLod = m_MinLod, + .maxLod = m_MaxLod, + .borderColor = m_BorderColor, + .unnormalizedCoordinates = !m_NormalizedCoordinates, + }; + } +}; + +#pragma endregion + +// ---------------------------------------------------------------------------------------------------- +#pragma region Pipeline +// ---------------------------------------------------------------------------------------------------- + +// TODO + +#pragma endregion + +// ---------------------------------------------------------------------------------------------------- +#pragma region Device +// ---------------------------------------------------------------------------------------------------- + +PhysicalDevice DefaultPhysicalDeviceSelector(const PhysicalDevices &physicalDevices); + +using PhysicalDeviceSelectorFn = PhysicalDevice (*)(const PhysicalDevices &); +static_assert(std::convertible_to); + +struct DeviceCreateInfo +{ + cstr m_AppName = "Aster App"; + Version m_AppVersion = {0, 1, 0}; + PhysicalDeviceSelectorFn m_PhysicalDeviceSelector = DefaultPhysicalDeviceSelector; + std::span m_PipelineCacheData = {}; + std::reference_wrapper m_Window; + cstr m_Name = "Primary"; + Features m_Features; +}; + +#pragma endregion + +#pragma endregion + +class Device; +struct Frame; + +class Context +{ + protected: + vk::CommandBuffer m_Cmd; + + friend Device; + friend Frame; + + explicit Context(const vk::CommandBuffer cmd) + : m_Cmd{cmd} + { + } + + public: + void Begin(); + void End(); +}; + +class GraphicsContext : public Context +{ + protected: + friend Device; + friend Frame; + + explicit GraphicsContext(const vk::CommandBuffer cmd) + : Context{cmd} + { + } + + public: + void BindPipeline(vk::Pipeline pipeline); + void DrawIndexed(u32 indexCount); + + [[deprecated]] + void Dependency(const vk::DependencyInfo& dependencyInfo); + + [[deprecated]] + void BeginRendering(const vk::RenderingInfo& renderingInfo); + void EndRendering(); +}; + +struct Frame +{ + // Persistent + ::Device *m_Device; + // TODO: ThreadSafe + vk::CommandPool m_Pool; + vk::Fence m_FrameAvailableFence; + vk::Semaphore m_ImageAcquireSem; + vk::Semaphore m_RenderFinishSem; + u32 m_FrameIdx; + + // Transient + u32 m_ImageIdx; + vk::Image m_SwapchainImage; + vk::ImageView m_SwapchainImageView; + + GraphicsContext CreateGraphicsContext(); +}; + +class Device final +{ + public: // TODO: Temp + std::reference_wrapper m_Window; + Instance m_Instance; + Surface m_Surface; + ::Device m_Device; + Swapchain m_Swapchain; + + // TODO: This is single-threaded. + vk::Queue m_GraphicsQueue; + u32 m_GraphicsQueueFamily; + + std::array m_Frames; + u32 m_CurrentFrameIdx = 0; + + public: + // ==================================================================================================== + // Resource Management + // ==================================================================================================== + + // + // Buffer Management + // ---------------------------------------------------------------------------------------------------- + + [[nodiscard]] Ref CreateStorageBuffer(usize size, cstr name = nullptr); + [[nodiscard]] Ref CreateUniformBuffer(usize size, cstr name = nullptr); + [[nodiscard]] Ref CreateStagingBuffer(usize size, cstr name = nullptr); + [[nodiscard]] Ref CreateVertexBuffer(usize size, cstr name = nullptr); + + // + // Image Management + // ---------------------------------------------------------------------------------------------------- + + template T> + [[nodiscard]] Ref + CreateTexture2D(const Texture2DCreateInfo &createInfo) + { + return CastImage(CreateTexture2D(createInfo)); + } + + template T> + [[nodiscard]] Ref + CreateTextureCube(const TextureCubeCreateInfo &createInfo) + { + return CastImage(CreateTextureCube(createInfo)); + } + + [[nodiscard]] Ref CreateTexture2D(const Texture2DCreateInfo &createInfo); + [[nodiscard]] Ref CreateTextureCube(const TextureCubeCreateInfo &createInfo); + [[nodiscard]] Ref CreateAttachment(const AttachmentCreateInfo &createInfo); + [[nodiscard]] Ref CreateDepthStencilImage(const DepthStencilImageCreateInfo &createInfo); + + // + // View Management + // ---------------------------------------------------------------------------------------------------- + + template + Ref + CreateView(const ViewCreateInfo &createInfo) + { + return CastView(CreateView(ViewCreateInfo(createInfo))); + } + + [[nodiscard]] Ref CreateView(const ViewCreateInfo &createInfo); + + // + // Image - View Combined Management + // ---------------------------------------------------------------------------------------------------- + + template T> + [[nodiscard]] Ref + CreateTexture2DWithView(const Texture2DCreateInfo &createInfo) + { + auto handle = CreateTexture2D(createInfo); + return CastView(handle); + } + + template T> + [[nodiscard]] Ref + CreateTextureCubeWithView(const TextureCubeCreateInfo &createInfo) + { + auto handle = CreateTextureCube(createInfo); + return CastView(handle); + } + + [[nodiscard]] Ref CreateTexture2DWithView(const Texture2DCreateInfo &createInfo); + [[nodiscard]] Ref CreateTextureCubeWithView(const TextureCubeCreateInfo &createInfo); + [[nodiscard]] Ref CreateAttachmentWithView(const AttachmentCreateInfo &createInfo); + [[nodiscard]] Ref CreateDepthStencilImageWithView(const DepthStencilImageCreateInfo &createInfo); + + // + // Sampler Management + // ---------------------------------------------------------------------------------------------------- + + using Handle = Ref; + using WeakHandle = WeakRef; + eastl::hash_map m_HashToSamplerIdx; + + Ref CreateSampler(const SamplerCreateInfo &createInfo); + + // + // Pipeline + // ---------------------------------------------------------------------------------------------------- + + /* + Pipeline CreatePipeline() + { + // Pipeline Setup + auto vertexShaderModule = CreateShader(device, VERTEX_SHADER_FILE); + auto fragmentShaderModule = CreateShader(device, FRAGMENT_SHADER_FILE); + + eastl::array shaderStages = {{ + { + .stage = vk::ShaderStageFlagBits::eVertex, + .module = vertexShaderModule, + .pName = "main", + }, + { + .stage = vk::ShaderStageFlagBits::eFragment, + .module = fragmentShaderModule, + .pName = "main", + }, + }}; + + vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = { + .setLayoutCount = 0, + .pSetLayouts = nullptr, + .pushConstantRangeCount = 0, + .pPushConstantRanges = nullptr, + }; + vk::PipelineLayout pipelineLayout; + vk::Result result = m_Device.m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &pipelineLayout); + ERROR_IF(Failed(result), "Could not create a pipeline layout. Cause: {}", result) THEN_ABORT(result); + m_Device.SetName(pipelineLayout, "Triangle 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::PipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo = { + .topology = vk::PrimitiveTopology::eTriangleList, + .primitiveRestartEnable = false, + }; + + vk::PipelineViewportStateCreateInfo viewportStateCreateInfo = { + .viewportCount = 1, + .scissorCount = 1, + }; + + vk::PipelineRasterizationStateCreateInfo rasterizationStateCreateInfo = { + .depthClampEnable = false, + .rasterizerDiscardEnable = false, + .polygonMode = vk::PolygonMode::eFill, + .cullMode = vk::CullModeFlagBits::eNone, + .frontFace = vk::FrontFace::eCounterClockwise, + .depthBiasEnable = false, + .lineWidth = 1.0, + }; + vk::PipelineMultisampleStateCreateInfo multisampleStateCreateInfo = { + .rasterizationSamples = vk::SampleCountFlagBits::e1, + .sampleShadingEnable = false, + }; + vk::PipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo = { + .depthTestEnable = false, + .depthWriteEnable = false, + }; + vk::PipelineColorBlendAttachmentState colorBlendAttachmentState = { + .blendEnable = false, + .srcColorBlendFactor = vk::BlendFactor::eSrcColor, + .dstColorBlendFactor = vk::BlendFactor::eOneMinusSrcColor, + .colorBlendOp = vk::BlendOp::eAdd, + .srcAlphaBlendFactor = vk::BlendFactor::eSrcAlpha, + .dstAlphaBlendFactor = vk::BlendFactor::eOneMinusSrcAlpha, + .alphaBlendOp = vk::BlendOp::eAdd, + .colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | + vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA, + }; + vk::PipelineColorBlendStateCreateInfo colorBlendStateCreateInfo = { + .logicOpEnable = false, + .attachmentCount = 1, + .pAttachments = &colorBlendAttachmentState, + }; + + eastl::array dynamicStates = { + vk::DynamicState::eScissor, + vk::DynamicState::eViewport, + }; + + vk::PipelineDynamicStateCreateInfo dynamicStateCreateInfo = { + .dynamicStateCount = Cast(dynamicStates.size()), + .pDynamicStates = dynamicStates.data(), + }; + + vk::PipelineRenderingCreateInfo renderingCreateInfo = { + .viewMask = 0, + .colorAttachmentCount = 1, + .pColorAttachmentFormats = &swapchain->m_Format, + }; + + vk::GraphicsPipelineCreateInfo pipelineCreateInfo = { + .pNext = &renderingCreateInfo, + .stageCount = Cast(shaderStages.size()), + .pStages = shaderStages.data(), + .pVertexInputState = &vertexInputStateCreateInfo, + .pInputAssemblyState = &inputAssemblyStateCreateInfo, + .pViewportState = &viewportStateCreateInfo, + .pRasterizationState = &rasterizationStateCreateInfo, + .pMultisampleState = &multisampleStateCreateInfo, + .pDepthStencilState = &depthStencilStateCreateInfo, + .pColorBlendState = &colorBlendStateCreateInfo, + .pDynamicState = &dynamicStateCreateInfo, + .layout = pipelineLayout, + }; + vk::Pipeline pipeline; + result = m_Device.m_Device.createGraphicsPipelines(nullptr, 1, &pipelineCreateInfo, nullptr, &pipeline); + ERROR_IF(Failed(result), "Could not create a graphics pipeline. Cause: {}", result) + THEN_ABORT(result); + m_Device.SetName(pipeline, "Triangle Pipeline"); + + m_Device.m_Device.destroy(vertexShaderModule, nullptr); + m_Device.m_Device.destroy(fragmentShaderModule, nullptr); + + return {&m_Device, pipelineLayout, pipeline, {}}; + } + //*/ + + // + // Frames + // ---------------------------------------------------------------------------------------------------- + + private: + Frame CreateFrame(u32 frameIndex); + + public: + Frame &GetNextFrame(); + Size2D GetSwapchainSize() const + { + return {m_Swapchain.m_Extent.width, m_Swapchain.m_Extent.height}; + } + + using Receipt = u32; + Receipt Submit(Frame& frame, GraphicsContext& graphicsContext); + + void Present(Frame &frame); + + friend Context; + friend GraphicsContext; + + // + // Device Methods + // ---------------------------------------------------------------------------------------------------- + + template + void + SetName(const T &object, cstr name) const + { + m_Device.SetName(object, name); + } + + [[nodiscard]] vk::Queue + GetQueue(u32 familyIndex, u32 queueIndex) const + { + return m_Device.GetQueue(familyIndex, queueIndex); + } + + [[nodiscard]] eastl::vector + DumpPipelineCache() const + { + return m_Device.DumpPipelineCache(); + } + + void + WaitIdle() const + { + m_Device.WaitIdle(); + } + + // Inner + // ---------------------------------------------------------------------------------------------------- + + [[nodiscard]] CoreDevice & + GetInner() + { + return m_Device; + } + + [[nodiscard]] vk::Device & + GetHandle() + { + return m_Device.m_Device; + } + + // Ctor/Dtor + // ---------------------------------------------------------------------------------------------------- + explicit Device(const DeviceCreateInfo &createInfo); + + ~Device(); + + PIN_MEMORY(Device); +}; + +} // namespace systems diff --git a/aster/include/aster/systems/image_manager.h b/aster/include/aster/systems/image_manager.h deleted file mode 100644 index ddbb616..0000000 --- a/aster/include/aster/systems/image_manager.h +++ /dev/null @@ -1,84 +0,0 @@ -// ============================================= -// Aster: image_manager.h -// Copyright (c) 2020-2025 Anish Bhobe -// ============================================= - -#pragma once - -#include "aster/aster.h" -#include "aster/core/image.h" - -namespace systems -{ - -template TTo, std::derived_from TFrom> -static Ref -CastImage(const Ref &from) -{ - if constexpr (not concepts::ImageInto) - assert(TTo::FLAGS & from->m_Flags_); - return std::reinterpret_pointer_cast(from); -} - -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; -}; - -class ImageManager final -{ - const Device *m_Device; - - public: - explicit ImageManager(const Device *device); - - template T> - [[nodiscard]] Ref - CreateTexture2D(const Texture2DCreateInfo &createInfo) - { - auto handle = CreateTexture2D(createInfo); - return CastImage(handle); - } - - template T> - [[nodiscard]] Ref - CreateTextureCube(const TextureCubeCreateInfo &createInfo) - { - auto handle = CreateTextureCube(createInfo); - return CastImage(handle); - } - - [[nodiscard]] Ref CreateTexture2D(const Texture2DCreateInfo &createInfo); - [[nodiscard]] Ref CreateTextureCube(const TextureCubeCreateInfo &createInfo); - [[nodiscard]] Ref CreateAttachment(const AttachmentCreateInfo &createInfo); - [[nodiscard]] Ref CreateDepthStencilImage(const DepthStencilImageCreateInfo &createInfo); -}; -} // namespace systems \ No newline at end of file diff --git a/aster/include/aster/systems/resource.h b/aster/include/aster/systems/resource.h index b231441..e1cf952 100644 --- a/aster/include/aster/systems/resource.h +++ b/aster/include/aster/systems/resource.h @@ -5,11 +5,63 @@ #pragma once +#include "aster/core/buffer.h" +#include "aster/core/image.h" +#include "aster/core/image_view.h" + #include namespace systems { +// ==================================================================================================== +#pragma region Util Methods +// ==================================================================================================== + +#pragma region Buffer +// ---------------------------------------------------------------------------------------------------- + +template TTo, std::derived_from TFrom> +static Ref +CastBuffer(const Ref &from) +{ + if constexpr (not concepts::BufferInto) + assert(TTo::FLAGS & from->m_Flags); + return std::reinterpret_pointer_cast(from); +} + +#pragma endregion + +#pragma region Image +// ---------------------------------------------------------------------------------------------------- + +template TTo, std::derived_from TFrom> +static Ref +CastImage(const Ref &from) +{ + if constexpr (not concepts::ImageInto) + assert(TTo::FLAGS & from->m_Flags_); + return std::reinterpret_pointer_cast(from); +} +#pragma endregion + +#pragma region View +// ---------------------------------------------------------------------------------------------------- + +template TFrom> +static Ref +CastView(const Ref> &from) +{ + if constexpr (not concepts::ImageInto) + assert(TTo::ImageType::FLAGS & from->m_Image->m_Flags_); + return std::reinterpret_pointer_cast(from); +} +#pragma endregion + +#pragma endregion + + + /** * ResId manages the lifetime of the committed resource. * @tparam T Type of the committed resource. diff --git a/aster/include/aster/systems/resource_manager.h b/aster/include/aster/systems/resource_manager.h deleted file mode 100644 index 1bdda7c..0000000 --- a/aster/include/aster/systems/resource_manager.h +++ /dev/null @@ -1,142 +0,0 @@ -// ============================================= -// Aster: resource_manager.h -// Copyright (c) 2020-2025 Anish Bhobe -// ============================================= - -#pragma once - -#include "aster/aster.h" - -#include "buffer_manager.h" -#include "image_manager.h" -#include "sampler_manager.h" -#include "view_manager.h" - -namespace systems -{ -class ResourceManager -{ - - struct CombinedImageViewManager - { - ImageManager *m_ImageManager; - ViewManager *m_ViewManager; - - CombinedImageViewManager(ImageManager *imageManager, ViewManager *viewManager) - : m_ImageManager{imageManager} - , m_ViewManager{viewManager} - { - } - - template T> - [[nodiscard]] Ref - CreateTexture2D(const Texture2DCreateInfo &createInfo) - { - auto handle = CreateTexture2D(createInfo); - return CastView(handle); - } - - template T> - [[nodiscard]] Ref - CreateTextureCube(const TextureCubeCreateInfo &createInfo) - { - auto handle = CreateTextureCube(createInfo); - return CastView(handle); - } - - [[nodiscard]] Ref - CreateTexture2D(const Texture2DCreateInfo &createInfo) const - { - return m_ViewManager->CreateView({ - .m_Image = CastImage(m_ImageManager->CreateTexture2D(createInfo)), - .m_Name = createInfo.m_Name, - .m_ViewType = vk::ImageViewType::e2D, - .m_AspectMask = vk::ImageAspectFlagBits::eColor, - }); - } - - [[nodiscard]] Ref - CreateTextureCube(const TextureCubeCreateInfo &createInfo) const - { - return m_ViewManager->CreateView({ - .m_Image = m_ImageManager->CreateTextureCube(createInfo), - .m_Name = createInfo.m_Name, - .m_ViewType = vk::ImageViewType::eCube, - .m_AspectMask = vk::ImageAspectFlagBits::eColor, - }); - } - - [[nodiscard]] Ref - CreateAttachment(const AttachmentCreateInfo &createInfo) const - { - return m_ViewManager->CreateView({ - .m_Image = m_ImageManager->CreateAttachment(createInfo), - .m_Name = createInfo.m_Name, - .m_ViewType = vk::ImageViewType::e2D, - .m_AspectMask = vk::ImageAspectFlagBits::eColor, - }); - } - - [[nodiscard]] Ref - CreateDepthStencilImage(const DepthStencilImageCreateInfo &createInfo) const - { - return m_ViewManager->CreateView({ - .m_Image = m_ImageManager->CreateDepthStencilImage(createInfo), - .m_Name = createInfo.m_Name, - .m_ViewType = vk::ImageViewType::e2D, - .m_AspectMask = vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil, - }); - } - }; - - BufferManager m_Buffers; - ImageManager m_Images; - SamplerManager m_Samplers; - ViewManager m_Views; - CombinedImageViewManager m_CombinedImageViews; - - public: - explicit ResourceManager(const Device *device) - : m_Buffers{device} - , m_Images{device} - , m_Samplers{device} - , m_Views{device} - , m_CombinedImageViews{&m_Images, &m_Views} - { - } - - BufferManager & - Buffers() - { - return m_Buffers; - } - - ImageManager & - Images() - { - return m_Images; - } - - ViewManager & - Views() - { - return m_Views; - } - - SamplerManager & - Samplers() - { - return m_Samplers; - } - - CombinedImageViewManager & - CombinedImageViews() - { - return m_CombinedImageViews; - } - - ~ResourceManager() = default; - - PIN_MEMORY(ResourceManager); -}; -} // namespace systems \ No newline at end of file diff --git a/aster/include/aster/systems/sampler_manager.h b/aster/include/aster/systems/sampler_manager.h deleted file mode 100644 index ebc1358..0000000 --- a/aster/include/aster/systems/sampler_manager.h +++ /dev/null @@ -1,112 +0,0 @@ -// ============================================= -// Aster: sampler_manager.h -// Copyright (c) 2020-2025 Anish Bhobe -// ============================================= - -#pragma once - -#include "EASTL/hash_map.h" - -#include "aster/aster.h" -#include "aster/core/sampler.h" - -#include "EASTL/vector_map.h" - -template <> -struct eastl::hash -{ - usize - operator()(const vk::SamplerCreateInfo &createInfo) const noexcept - { - usize hash = HashAny(createInfo.flags); - hash = HashCombine(hash, HashAny(createInfo.magFilter)); - hash = HashCombine(hash, HashAny(createInfo.minFilter)); - hash = HashCombine(hash, HashAny(createInfo.mipmapMode)); - hash = HashCombine(hash, HashAny(createInfo.addressModeU)); - hash = HashCombine(hash, HashAny(createInfo.addressModeV)); - hash = HashCombine(hash, HashAny(createInfo.addressModeW)); - hash = HashCombine(hash, HashAny(Cast(createInfo.mipLodBias * 1000))); // Resolution of 10^-3 - hash = HashCombine(hash, HashAny(createInfo.anisotropyEnable)); - hash = - HashCombine(hash, - HashAny(Cast(createInfo.maxAnisotropy * 0x20))); // 32:1 Anisotropy is enough resolution - hash = HashCombine(hash, HashAny(createInfo.compareEnable)); - hash = HashCombine(hash, HashAny(createInfo.compareOp)); - hash = HashCombine(hash, HashAny(Cast(createInfo.minLod * 1000))); // 0.001 resolution is enough. - hash = - HashCombine(hash, - HashAny(Cast(createInfo.maxLod * 1000))); // 0.001 resolution is enough. (1 == NO Clamp) - hash = HashCombine(hash, HashAny(createInfo.borderColor)); - hash = HashCombine(hash, HashAny(createInfo.unnormalizedCoordinates)); - - return hash; - } -}; - -namespace systems -{ - -struct SamplerCreateInfo -{ - cstr m_Name = nullptr; - vk::SamplerCreateFlags m_Flags = {}; - vk::Filter m_MagFilter = vk::Filter::eLinear; - vk::Filter m_MinFilter = vk::Filter::eLinear; - vk::SamplerMipmapMode m_MipmapMode = vk::SamplerMipmapMode::eLinear; - vk::SamplerAddressMode m_AddressModeU = vk::SamplerAddressMode::eRepeat; - vk::SamplerAddressMode m_AddressModeV = vk::SamplerAddressMode::eRepeat; - vk::SamplerAddressMode m_AddressModeW = vk::SamplerAddressMode::eRepeat; - vk::BorderColor m_BorderColor = vk::BorderColor::eFloatOpaqueBlack; - vk::CompareOp m_CompareOp = vk::CompareOp::eNever; - f32 m_MipLodBias = 0.0f; - f32 m_MaxAnisotropy = 16.0f; - f32 m_MinLod = 0; - f32 m_MaxLod = VK_LOD_CLAMP_NONE; - bool m_AnisotropyEnable = true; - bool m_CompareEnable = false; - bool m_NormalizedCoordinates = true; - - explicit - operator vk::SamplerCreateInfo() const - { - return { - .flags = m_Flags, - .magFilter = m_MagFilter, - .minFilter = m_MinFilter, - .mipmapMode = m_MipmapMode, - .addressModeU = m_AddressModeU, - .addressModeV = m_AddressModeV, - .addressModeW = m_AddressModeW, - .mipLodBias = m_MipLodBias, - .anisotropyEnable = m_AnisotropyEnable, - .maxAnisotropy = m_MaxAnisotropy, - .compareEnable = m_CompareEnable, - .compareOp = m_CompareOp, - .minLod = m_MinLod, - .maxLod = m_MaxLod, - .borderColor = m_BorderColor, - .unnormalizedCoordinates = !m_NormalizedCoordinates, - }; - } -}; - -/** - * @class SamplerManager sampler_manager.h - * - * Manages (and caches) objects of sampler. Currently Samplers are never deleted. - */ -class SamplerManager final -{ - using Handle = Ref; - using WeakHandle = WeakRef; - eastl::hash_map m_HashToSamplerIdx; - - const Device *m_Device; - - public: - explicit SamplerManager(const Device *device); - ~SamplerManager(); - - Ref CreateSampler(const SamplerCreateInfo &createInfo); -}; -} // namespace systems \ No newline at end of file diff --git a/aster/include/aster/systems/view_manager.h b/aster/include/aster/systems/view_manager.h deleted file mode 100644 index 91a3ed2..0000000 --- a/aster/include/aster/systems/view_manager.h +++ /dev/null @@ -1,105 +0,0 @@ -// ============================================= -// Aster: view_manager.h -// Copyright (c) 2020-2025 Anish Bhobe -// ============================================= - -#pragma once - -#include "aster/aster.h" -#include "aster/core/image_view.h" - -#include - -namespace systems -{ - -template TFrom> -static Ref -CastView(const Ref> &from) -{ - if constexpr (not concepts::ImageInto) - assert(TTo::ImageType::FLAGS & from->m_Image->m_Flags_); - return std::reinterpret_pointer_cast(from); -} - -template -struct ViewCreateInfo -{ - using ImageType = TImage; - - Ref m_Image; - cstr m_Name; - vk::ImageViewType m_ViewType = vk::ImageViewType::e2D; - vk::ComponentMapping m_Components = {}; - vk::ImageAspectFlags m_AspectMask = {}; - eastl::optional m_MipLevelCount = eastl::nullopt; - eastl::optional m_LayerCount = eastl::nullopt; - u8 m_BaseMipLevel = 0; - u8 m_BaseLayer = 0; - - [[nodiscard]] u8 - GetMipLevelCount() const - { - return m_MipLevelCount.value_or(m_Image->m_MipLevels - m_BaseMipLevel); - } - - [[nodiscard]] u8 - GetLayerCount() const - { - return m_LayerCount.value_or(m_Image->m_LayerCount - m_BaseLayer); - } - - explicit - operator vk::ImageViewCreateInfo() const - { - return { - .image = m_Image->m_Image, - .viewType = m_ViewType, - .format = m_Image->m_Format, - .components = m_Components, - .subresourceRange = - { - .aspectMask = m_AspectMask, - .baseMipLevel = m_BaseMipLevel, - .levelCount = GetMipLevelCount(), - .baseArrayLayer = m_BaseLayer, - .layerCount = GetLayerCount(), - }, - }; - } - - explicit - operator ViewCreateInfo() const - { - return { - .m_Image = CastImage(m_Image), - .m_Name = m_Name, - .m_ViewType = m_ViewType, - .m_Components = m_Components, - .m_AspectMask = m_AspectMask, - .m_MipLevelCount = m_MipLevelCount, - .m_LayerCount = m_LayerCount, - .m_BaseMipLevel = m_BaseMipLevel, - .m_BaseLayer = m_BaseLayer, - }; - } -}; - -class ViewManager final -{ - const Device *m_Device; - - public: - explicit ViewManager(const Device *device); - - template - Ref - CreateView(const ViewCreateInfo &createInfo) - { - return CastView(CreateView(ViewCreateInfo(createInfo))); - } - - [[nodiscard]] Ref CreateView(const ViewCreateInfo &createInfo) const; -}; - -} // namespace systems \ No newline at end of file diff --git a/aster/src/aster/core/device.cpp b/aster/src/aster/core/device.cpp index f931a6c..6de1741 100644 --- a/aster/src/aster/core/device.cpp +++ b/aster/src/aster/core/device.cpp @@ -17,18 +17,12 @@ constexpr eastl::array DEVICE_EXTENSIONS = { VK_KHR_SWAPCHAIN_EXTENSION_NAME, }; -Device::Device(const Instance *context, PhysicalDevice *physicalDevice, Features *enabledFeatures, - const eastl::vector &queueAllocations, NameString &&name) - : Device(context, physicalDevice, enabledFeatures, queueAllocations, {}, std::move(name)) -{ -} - -Device::Device(const Instance *context, PhysicalDevice *physicalDevice, Features *enabledFeatures, - const eastl::vector &queueAllocations, eastl::span &&pipelineCacheData, +Device::Device(const Instance &context, PhysicalDevice &physicalDevice, Features &enabledFeatures, + const eastl::span &queueAllocations, const eastl::span &pipelineCacheData, NameString &&name) : m_Name(std::move(name)) - , m_PhysicalDevice(physicalDevice->m_PhysicalDevice) - , m_ValidationEnabled(context->m_DebugMessenger != nullptr) + , m_PhysicalDevice(physicalDevice.m_PhysicalDevice) + , m_ValidationEnabled(context.m_DebugMessenger != nullptr) { // Shouldn't have more than 4 deviceQueueFamilies in use anyway. Else we can heap eastl::fixed_vector deviceQueueCreateInfos; @@ -51,10 +45,10 @@ Device::Device(const Instance *context, PhysicalDevice *physicalDevice, Features }); } - vk::PhysicalDeviceFeatures *deviceFeatures = &enabledFeatures->m_Vulkan10Features; - vk::PhysicalDeviceVulkan11Features *vulkan11Features = &enabledFeatures->m_Vulkan11Features; - vk::PhysicalDeviceVulkan12Features *vulkan12Features = &enabledFeatures->m_Vulkan12Features; - vk::PhysicalDeviceVulkan13Features *vulkan13Features = &enabledFeatures->m_Vulkan13Features; + vk::PhysicalDeviceFeatures *deviceFeatures = &enabledFeatures.m_Vulkan10Features; + vk::PhysicalDeviceVulkan11Features *vulkan11Features = &enabledFeatures.m_Vulkan11Features; + vk::PhysicalDeviceVulkan12Features *vulkan12Features = &enabledFeatures.m_Vulkan12Features; + vk::PhysicalDeviceVulkan13Features *vulkan13Features = &enabledFeatures.m_Vulkan13Features; vulkan11Features->pNext = vulkan12Features; vulkan12Features->pNext = vulkan13Features; @@ -71,7 +65,7 @@ Device::Device(const Instance *context, PhysicalDevice *physicalDevice, Features vk::Result result = m_PhysicalDevice.createDevice(&deviceCreateInfo, nullptr, &m_Device); ERROR_IF(Failed(result), "Could not initialize Vulkan Device. Cause: {}", result) THEN_ABORT(result) - ELSE_DEBUG("{} ({}) Initialized.", m_Name, physicalDevice->m_DeviceProperties.deviceName.data()); + ELSE_DEBUG("{} ({}) Initialized.", m_Name, physicalDevice.m_DeviceProperties.deviceName.data()); SetName(m_Device, m_Name.data()); @@ -85,7 +79,7 @@ Device::Device(const Instance *context, PhysicalDevice *physicalDevice, Features .physicalDevice = m_PhysicalDevice, .device = m_Device, .pVulkanFunctions = &vmaVulkanFunctions, - .instance = context->m_Instance, + .instance = context.m_Instance, .vulkanApiVersion = ASTER_API_VERSION, }; @@ -110,6 +104,9 @@ Device::Device(const Instance *context, PhysicalDevice *physicalDevice, Features Device::~Device() { + if (!m_Device) + return; + m_Device.destroy(m_PipelineCache, nullptr); if (m_Allocator) { @@ -156,6 +153,7 @@ Device::Device(Device &&other) noexcept , m_PhysicalDevice(Take(other.m_PhysicalDevice)) , m_Device(Take(other.m_Device)) , m_Allocator(Take(other.m_Allocator)) + , m_PipelineCache(Take(other.m_PipelineCache)) { } @@ -168,5 +166,6 @@ Device::operator=(Device &&other) noexcept m_PhysicalDevice = Take(other.m_PhysicalDevice); m_Device = Take(other.m_Device); m_Allocator = Take(other.m_Allocator); + m_PipelineCache = Take(other.m_PipelineCache); return *this; } \ No newline at end of file diff --git a/aster/src/aster/core/instance.cpp b/aster/src/aster/core/instance.cpp index 9289cab..d8b0a22 100644 --- a/aster/src/aster/core/instance.cpp +++ b/aster/src/aster/core/instance.cpp @@ -5,6 +5,8 @@ #include "core/instance.h" +#include "core/window.h" + #include #include @@ -61,9 +63,9 @@ Instance::Instance(const cstr appName, const Version version, bool enableValidat .pUserData = nullptr, }; - u32 glfwExtensionCount = 0; - cstr *glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount); - eastl::fixed_vector instanceExtensions(glfwExtensions, glfwExtensions + glfwExtensionCount); + u32 windowExtensionCount = 0; + cstr *windowExtensions = Window::GetInstanceExtensions(&windowExtensionCount); + eastl::fixed_vector instanceExtensions(windowExtensions, windowExtensions + windowExtensionCount); if (enableValidation) { instanceExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); @@ -99,6 +101,9 @@ Instance::Instance(const cstr appName, const Version version, bool enableValidat Instance::~Instance() { + if (!m_Instance) + return; + if (m_DebugMessenger) { m_Instance.destroy(m_DebugMessenger, nullptr); diff --git a/aster/src/aster/core/physical_device.cpp b/aster/src/aster/core/physical_device.cpp index a0a1b6d..03a46b3 100644 --- a/aster/src/aster/core/physical_device.cpp +++ b/aster/src/aster/core/physical_device.cpp @@ -154,11 +154,10 @@ EnumeratePhysicalDevices(const vk::Instance instance) return physicalDevices; } -PhysicalDevices::PhysicalDevices(const Surface *surface, const Instance *context) +PhysicalDevices::PhysicalDevices(const Surface &surface, const Instance &context) { - auto physicalDevices = EnumeratePhysicalDevices(context->m_Instance); - for (auto physicalDevice : physicalDevices) + for (auto physicalDevices = EnumeratePhysicalDevices(context.m_Instance); auto physicalDevice : physicalDevices) { - this->emplace_back(surface->m_Surface, physicalDevice); + this->emplace_back(surface.m_Surface, physicalDevice); } } \ No newline at end of file diff --git a/aster/src/aster/core/surface.cpp b/aster/src/aster/core/surface.cpp index 5ccaf73..daa39a2 100644 --- a/aster/src/aster/core/surface.cpp +++ b/aster/src/aster/core/surface.cpp @@ -8,13 +8,12 @@ #include "core/instance.h" #include "core/window.h" -Surface::Surface(Instance *context, const Window *window, cstr name) - : m_Context(context) - , m_Name(name) +Surface::Surface(Instance &context, const Window &window) + : m_Context(&context) { VkSurfaceKHR surface; auto result = Cast( - glfwCreateWindowSurface(Cast(m_Context->m_Instance), window->m_Window, nullptr, &surface)); + glfwCreateWindowSurface(Cast(m_Context->m_Instance), window.m_Window, nullptr, &surface)); ERROR_IF(Failed(result), "Failed to create Surface with {}", result) THEN_ABORT(result) ELSE_DEBUG("Surface {} Created", m_Name); @@ -23,14 +22,14 @@ Surface::Surface(Instance *context, const Window *window, cstr name) Surface::~Surface() { - if (m_Context && m_Surface) - { - m_Context->m_Instance.destroy(m_Surface, nullptr); - DEBUG("Surface Destroyed"); + if (!m_Context || !m_Context->m_Instance || !m_Surface) + return; - m_Surface = nullptr; - m_Context = nullptr; - } + m_Context->m_Instance.destroy(m_Surface, nullptr); + DEBUG("Surface Destroyed"); + + m_Surface = nullptr; + m_Context = nullptr; } Surface::Surface(Surface &&other) noexcept diff --git a/aster/src/aster/core/swapchain.cpp b/aster/src/aster/core/swapchain.cpp index 19bb609..0c9d34e 100644 --- a/aster/src/aster/core/swapchain.cpp +++ b/aster/src/aster/core/swapchain.cpp @@ -11,9 +11,8 @@ [[nodiscard]] vk::Extent2D GetExtent(Size2D size, vk::SurfaceCapabilitiesKHR *surfaceCapabilities); -Swapchain::Swapchain(const Surface *surface, const Device *device, Size2D size, NameString &&name) - : m_Device(device) - , m_Name(std::move(name)) +Swapchain::Swapchain(const Surface &surface, const Device &device, Size2D size) + : m_Device(&device) , m_Format(vk::Format::eUndefined) { this->Create(surface, size); @@ -27,11 +26,11 @@ Swapchain::~Swapchain() Swapchain::Swapchain(Swapchain &&other) noexcept : m_Device(other.m_Device) , m_Swapchain(Take(other.m_Swapchain)) - , m_Name(std::move(other.m_Name)) , m_Extent(other.m_Extent) , m_Format(other.m_Format) , m_Images(std::move(other.m_Images)) , m_ImageViews(std::move(other.m_ImageViews)) + , m_ResizeCallbacks(std::move(other.m_ResizeCallbacks)) { } @@ -42,29 +41,29 @@ Swapchain::operator=(Swapchain &&other) noexcept return *this; m_Device = other.m_Device; m_Swapchain = Take(other.m_Swapchain); - m_Name = std::move(other.m_Name); m_Extent = other.m_Extent; m_Format = other.m_Format; m_Images = std::move(other.m_Images); m_ImageViews = std::move(other.m_ImageViews); + m_ResizeCallbacks = std::move(other.m_ResizeCallbacks); return *this; } void -Swapchain::Create(const Surface *surface, Size2D size) +Swapchain::Create(const Surface &surface, Size2D size) { - auto surfaceCapabilities = GetSurfaceCapabilities(m_Device->m_PhysicalDevice, surface->m_Surface); + auto surfaceCapabilities = GetSurfaceCapabilities(m_Device->m_PhysicalDevice, surface.m_Surface); m_Extent = GetExtent(size, &surfaceCapabilities); while (m_Extent.width == 0 || m_Extent.height == 0) { glfwWaitEvents(); - surfaceCapabilities = GetSurfaceCapabilities(m_Device->m_PhysicalDevice, surface->m_Surface); + surfaceCapabilities = GetSurfaceCapabilities(m_Device->m_PhysicalDevice, surface.m_Surface); m_Extent = GetExtent(size, &surfaceCapabilities); } - auto surfaceFormats = GetSurfaceFormats(m_Device->m_PhysicalDevice, surface->m_Surface); - auto presentModes = GetSurfacePresentModes(m_Device->m_PhysicalDevice, surface->m_Surface); + auto surfaceFormats = GetSurfaceFormats(m_Device->m_PhysicalDevice, surface.m_Surface); + auto presentModes = GetSurfacePresentModes(m_Device->m_PhysicalDevice, surface.m_Surface); m_Format = vk::Format::eUndefined; auto swapchainColorSpace = vk::ColorSpaceKHR::eSrgbNonlinear; @@ -95,16 +94,14 @@ Swapchain::Create(const Surface *surface, Size2D size) } u32 swapchainImageCount = 3; - if (surfaceCapabilities.maxImageCount > 0) - { - swapchainImageCount = - glm::clamp(swapchainImageCount, surfaceCapabilities.minImageCount, surfaceCapabilities.maxImageCount); - } + u32 maxImageCount = + glm::max(swapchainImageCount, glm::max(surfaceCapabilities.maxImageCount, surfaceCapabilities.minImageCount)); + swapchainImageCount = glm::clamp(swapchainImageCount, surfaceCapabilities.minImageCount, maxImageCount); // TODO: Note that different queues might need the images to be shared. const vk::SwapchainCreateInfoKHR swapchainCreateInfo = { - .surface = surface->m_Surface, + .surface = surface.m_Surface, .minImageCount = swapchainImageCount, .imageFormat = m_Format, .imageColorSpace = swapchainColorSpace, @@ -120,28 +117,30 @@ Swapchain::Create(const Surface *surface, Size2D size) }; vk::Device device = m_Device->m_Device; + NameString name = "Swapchain of "; + name += m_Device->m_Name; vk::SwapchainKHR swapchain; vk::Result result = device.createSwapchainKHR(&swapchainCreateInfo, nullptr, &swapchain); - ERROR_IF(Failed(result), "Swapchain {} creation failed. Cause {}", m_Name, result) + ERROR_IF(Failed(result), "'{}' creation failed. Cause {}", name, result) THEN_ABORT(result) - ELSE_DEBUG("Created Swapchain '{}'", m_Name); + ELSE_DEBUG("Created '{}'", name); // Irrelevant on the first run. Required for re-creation. Cleanup(); m_Swapchain = swapchain; - m_Device->SetName(m_Swapchain, m_Name.data()); + m_Device->SetName(m_Swapchain, m_Device->m_Name.data()); result = device.getSwapchainImagesKHR(m_Swapchain, &swapchainImageCount, nullptr); - ERROR_IF(Failed(result), "Failed getting swapchain {}'s images. Cause {}", m_Name, result) + ERROR_IF(Failed(result), "Failed getting {}'s images. Cause {}", name, result) THEN_ABORT(result); // Managed by the Swapchain. - m_Images.resize(swapchainImageCount); + m_Images.resize(swapchainImageCount, nullptr); result = device.getSwapchainImagesKHR(m_Swapchain, &swapchainImageCount, m_Images.data()); - ERROR_IF(Failed(result), "Failed getting swapchain {}'s images. Cause {}", m_Name, result) + ERROR_IF(Failed(result), "Failed getting {}'s images. Cause {}", name, result) THEN_ABORT(result); vk::ImageViewCreateInfo viewCreateInfo = { @@ -165,7 +164,7 @@ Swapchain::Create(const Surface *surface, Size2D size) vk::ImageView imageView; result = device.createImageView(&viewCreateInfo, nullptr, &imageView); - ERROR_IF(Failed(result), "Failed creating swapchain {}'s image view [{}]. Cause {}", m_Name, index, result) + ERROR_IF(Failed(result), "Failed creating {}'s image view [{}]. Cause {}", name, index, result) THEN_ABORT(result); m_ImageViews.push_back(imageView); @@ -173,7 +172,7 @@ Swapchain::Create(const Surface *surface, Size2D size) ++index; } - DEBUG("Swapchain {} Image Views created.", m_Name); + DEBUG("{} Image Views created.", name); for (auto &callback : m_ResizeCallbacks) { @@ -184,24 +183,31 @@ Swapchain::Create(const Surface *surface, Size2D size) void Swapchain::RegisterResizeCallback(FnResizeCallback &&callback) { - m_ResizeCallbacks.emplace_back(callback); + m_ResizeCallbacks.emplace_back(std::move(callback)); } void Swapchain::Cleanup() { - if (!m_ImageViews.empty()) // Don't want the condition in the logs. - DEBUG("Swapchain {} Image Views destroyed.", m_Name); + if (!m_Swapchain) + return; + + NameString name = "Swapchain of "; + name += m_Device->m_Name; + for (const auto imageView : m_ImageViews) { m_Device->m_Device.destroy(imageView, nullptr); } + if (!m_ImageViews.empty()) // Don't want the condition in the logs. + DEBUG("Swapchain {} Image Views destroyed.", name); m_ImageViews.clear(); + m_Images.clear(); if (m_Swapchain) { m_Device->m_Device.destroy(m_Swapchain, nullptr); m_Swapchain = nullptr; - DEBUG("Swapchain '{}' destroyed.", m_Name); + DEBUG("Swapchain '{}' destroyed.", name); } } diff --git a/aster/src/aster/core/window.cpp b/aster/src/aster/core/window.cpp index 9122701..f4beea3 100644 --- a/aster/src/aster/core/window.cpp +++ b/aster/src/aster/core/window.cpp @@ -11,6 +11,30 @@ std::atomic_uint64_t Window::m_WindowCount = 0; std::atomic_bool Window::m_IsGlfwInit = false; +void +Window::SetupLibrary() +{ + if (!m_IsGlfwInit) + { + if (!glfwInit()) + { + const char *error = nullptr; + const auto code = glfwGetError(&error); + ERROR("GLFW Init failed. Cause: ({}) {}", code, error) + THEN_ABORT(code); + } + m_WindowCount = 0; + m_IsGlfwInit = true; + } +} + +cstr* +Window::GetInstanceExtensions(u32 *extensionCount) +{ + SetupLibrary(); + return glfwGetRequiredInstanceExtensions(extensionCount); +} + void Window::RequestExit() const noexcept { @@ -42,18 +66,7 @@ Window::Window(const cstr title, Size2D extent, const b8 isFullScreen) { m_Name = title; - if (!m_IsGlfwInit) - { - if (!glfwInit()) - { - const char *error = nullptr; - const auto code = glfwGetError(&error); - ERROR("GLFW Init failed. Cause: ({}) {}", code, error) - THEN_ABORT(code); - } - m_WindowCount = 0; - m_IsGlfwInit = true; - } + SetupLibrary(); GLFWmonitor *monitor = glfwGetPrimaryMonitor(); ERROR_IF(!monitor, "No monitor found"); diff --git a/aster/src/aster/systems/CMakeLists.txt b/aster/src/aster/systems/CMakeLists.txt index 7f2baa2..ff666dd 100644 --- a/aster/src/aster/systems/CMakeLists.txt +++ b/aster/src/aster/systems/CMakeLists.txt @@ -4,8 +4,5 @@ cmake_minimum_required(VERSION 3.13) target_sources(aster_core PRIVATE -"buffer_manager.cpp" -"image_manager.cpp" -"view_manager.cpp" -"sampler_manager.cpp" +"device.cpp" "commit_manager.cpp") diff --git a/aster/src/aster/systems/buffer_manager.cpp b/aster/src/aster/systems/buffer_manager.cpp deleted file mode 100644 index c67d8a0..0000000 --- a/aster/src/aster/systems/buffer_manager.cpp +++ /dev/null @@ -1,160 +0,0 @@ -// ============================================= -// Aster: buffer_manager.cpp -// Copyright (c) 2020-2025 Anish Bhobe -// ============================================= - -#include "systems/buffer_manager.h" - -using namespace systems; - -Ref -BufferManager::CreateStorageBuffer(const usize size, const cstr name) const -{ - // TODO: Storage and Index buffer are set. - // This is hacky and should be improved. - constexpr vk::BufferUsageFlags usage = - vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eIndexBuffer | - vk::BufferUsageFlagBits::eShaderDeviceAddress | vk::BufferUsageFlagBits::eTransferDst; - 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; - return std::make_shared(Buffer{m_Device, size, usage, createFlags, memoryUsage, name}); -} - -Ref -BufferManager::CreateUniformBuffer(const usize size, const cstr name) const -{ - 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; - return std::make_shared(Buffer{m_Device, size, usage, createFlags, memoryUsage, name}); -} - -Ref -BufferManager::CreateStagingBuffer(const usize size, const cstr name) const -{ - constexpr vk::BufferUsageFlags usage = vk::BufferUsageFlagBits::eTransferSrc; - constexpr VmaAllocationCreateFlags createFlags = - VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT; - constexpr VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_AUTO; - return std::make_shared(Buffer{m_Device, size, usage, createFlags, memoryUsage, name}); -} - -Ref -BufferManager::CreateVertexBuffer(const usize size, const cstr name) const -{ - constexpr vk::BufferUsageFlags usage = vk::BufferUsageFlagBits::eVertexBuffer; - constexpr VmaAllocationCreateFlags createFlags = - VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT; - constexpr VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_AUTO; - return std::make_shared(Buffer{m_Device, size, usage, createFlags, memoryUsage, name}); -} - -// -// void -// UniformBuffer::Init(const Device *device, const usize size, const cstr name) -//{ -// Allocate(device, size, vk::BufferUsageFlagBits::eUniformBuffer, -// VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | -// VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT, -// VMA_MEMORY_USAGE_AUTO, name); -//} -// -// void -// StorageBuffer::Init(const Device *device, usize size, bool hostVisible, cstr name) -//{ -// Init(device, size, hostVisible, false, name); -//} -// -// void -// StorageBuffer::Init(const Device *device, usize size, bool hostVisible, bool deviceAddress, cstr name) -//{ -// vk::BufferUsageFlags usage = vk::BufferUsageFlagBits::eStorageBuffer; -// if (deviceAddress) -// { -// usage |= vk::BufferUsageFlagBits::eShaderDeviceAddress; -// } -// if (hostVisible) -// { -// Allocate(device, size, usage, -// VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | -// VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT, -// VMA_MEMORY_USAGE_AUTO, name); -// } -// else -// { -// usage |= vk::BufferUsageFlagBits::eTransferDst; -// Allocate(device, size, usage, 0, VMA_MEMORY_USAGE_AUTO, name); -// } -//} -// -// void -// StorageIndexBuffer::Init(const Device *device, usize size, bool hostVisible, bool deviceAddress, cstr name) -//{ -// vk::BufferUsageFlags usage = vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eIndexBuffer; -// if (deviceAddress) -// { -// usage |= vk::BufferUsageFlagBits::eShaderDeviceAddress; -// } -// if (hostVisible) -// { -// Allocate(device, size, usage, -// VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | -// VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT, -// VMA_MEMORY_USAGE_AUTO, name); -// } -// else -// { -// usage |= vk::BufferUsageFlagBits::eTransferDst; -// Allocate(device, size, usage, 0, VMA_MEMORY_USAGE_AUTO, name); -// } -//} -// -// void -// IndirectBuffer::Init(const Device *device, usize size, bool hostVisible, cstr name) -//{ -// vk::BufferUsageFlags usage = vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eIndirectBuffer | -// vk::BufferUsageFlagBits::eShaderDeviceAddress; -// if (hostVisible) -// { -// Allocate(device, size, usage, -// VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | -// VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT, -// VMA_MEMORY_USAGE_AUTO, name); -// } -// else -// { -// usage |= vk::BufferUsageFlagBits::eTransferDst; -// Allocate(device, size, usage, 0, VMA_MEMORY_USAGE_AUTO, name); -// } -//} -// -// void -// VertexBuffer::Init(const Device *device, usize size, cstr name) -//{ -// Allocate(device, size, vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eTransferDst, 0, -// VMA_MEMORY_USAGE_AUTO, name); -//} -// -// void -// IndexBuffer::Init(const Device *device, usize size, cstr name) -//{ -// Allocate(device, size, vk::BufferUsageFlagBits::eIndexBuffer | vk::BufferUsageFlagBits::eTransferDst, 0, -// VMA_MEMORY_USAGE_AUTO, name); -//} -// -// void -// StagingBuffer::Init(const Device *device, usize size, cstr name) -//{ -// Allocate(device, size, vk::BufferUsageFlagBits::eTransferSrc, -// VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT, -// VMA_MEMORY_USAGE_AUTO, name); -//} - -BufferManager::BufferManager(const Device *device) - : m_Device{device} -{ -} \ No newline at end of file diff --git a/aster/src/aster/systems/device.cpp b/aster/src/aster/systems/device.cpp new file mode 100644 index 0000000..ff11012 --- /dev/null +++ b/aster/src/aster/systems/device.cpp @@ -0,0 +1,694 @@ +// ============================================= +// Aster: device.cpp +// Copyright (c) 2020-2025 Anish Bhobe +// ============================================= + +#include "systems/device.h" + +#include "core/queue_allocation.h" +#include "core/window.h" +#include "systems/resource.h" + +static constexpr QueueSupportFlags REQUIRED_QUEUE_SUPPORT = + QueueSupportFlags{} | QueueSupportFlagBits::eGraphics | QueueSupportFlagBits::eCompute | + QueueSupportFlagBits::ePresent | QueueSupportFlagBits::eTransfer; + +PhysicalDevice +systems::DefaultPhysicalDeviceSelector(const PhysicalDevices &physicalDevices) +{ + for (auto &physicalDevice : physicalDevices) + { + const bool hasAllRequiredQueues = + std::ranges::any_of(physicalDevice.m_QueueFamilies, [](const auto &queueFamilyProp) { + return (queueFamilyProp.m_Support & REQUIRED_QUEUE_SUPPORT) == REQUIRED_QUEUE_SUPPORT; + }); + + const bool isNotCpu = physicalDevice.m_DeviceProperties.deviceType != vk::PhysicalDeviceType::eCpu; + + const bool hasPresentMode = !physicalDevice.m_PresentModes.empty(); + + const bool hasSurfaceFormat = !physicalDevice.m_SurfaceFormats.empty(); + + if (hasSurfaceFormat && hasPresentMode && isNotCpu && hasAllRequiredQueues) + { + return physicalDevice; + } + } + + ERROR("No suitable GPU available on the system.") + THEN_ABORT(vk::Result::eErrorUnknown); +} + +// ==================================================================================================== +#pragma region Buffer Management +// ==================================================================================================== + +Ref +systems::Device::CreateStorageBuffer(const usize size, const cstr name) +{ + // TODO: Storage and Index buffer are set. + // This is hacky and should be improved. + constexpr vk::BufferUsageFlags usage = + vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eIndexBuffer | + vk::BufferUsageFlagBits::eShaderDeviceAddress | vk::BufferUsageFlagBits::eTransferDst; + 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; + return std::make_shared(Buffer{&m_Device, size, usage, createFlags, memoryUsage, name}); +} + +Ref +systems::Device::CreateUniformBuffer(const usize size, const cstr name) +{ + 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; + return std::make_shared(Buffer{&m_Device, size, usage, createFlags, memoryUsage, name}); +} + +Ref +systems::Device::CreateStagingBuffer(const usize size, const cstr name) +{ + constexpr vk::BufferUsageFlags usage = vk::BufferUsageFlagBits::eTransferSrc; + constexpr VmaAllocationCreateFlags createFlags = + VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT; + constexpr VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_AUTO; + return std::make_shared(Buffer{&m_Device, size, usage, createFlags, memoryUsage, name}); +} + +Ref +systems::Device::CreateVertexBuffer(const usize size, const cstr name) +{ + constexpr vk::BufferUsageFlags usage = vk::BufferUsageFlagBits::eVertexBuffer; + constexpr VmaAllocationCreateFlags createFlags = + VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT; + constexpr VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_AUTO; + return std::make_shared(Buffer{&m_Device, size, usage, createFlags, memoryUsage, name}); +} +#pragma endregion + +// ==================================================================================================== +#pragma region Image Management +// ==================================================================================================== + +vk::ImageCreateInfo ToImageCreateInfo(const systems::Texture2DCreateInfo &createInfo); +vk::ImageCreateInfo ToImageCreateInfo(const systems::TextureCubeCreateInfo &createInfo); +vk::ImageCreateInfo ToImageCreateInfo(const systems::AttachmentCreateInfo &createInfo); +vk::ImageCreateInfo ToImageCreateInfo(const systems::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 + +Ref +systems::Device::CreateTexture2D(const Texture2DCreateInfo &createInfo) +{ + constexpr VmaAllocationCreateInfo allocationCreateInfo = { + .flags = {}, + .usage = VMA_MEMORY_USAGE_AUTO, + }; + + VkImage rawImage; + VmaAllocation allocation; + vk::ImageCreateInfo imageCreateInfo = ToImageCreateInfo(createInfo); + auto result = Cast(vmaCreateImage(m_Device.m_Allocator, Recast(&imageCreateInfo), + &allocationCreateInfo, &rawImage, &allocation, nullptr)); + ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", createInfo.m_Name, result) THEN_ABORT(result); + + vk::Image image = rawImage; + + u8 layerCount = Cast(imageCreateInfo.arrayLayers); + u8 mipLevels = Cast(imageCreateInfo.mipLevels); + Image::Flags flags = {}; + if (createInfo.m_IsSampled) + flags |= Image::FlagBits::eSampled; + if (createInfo.m_IsStorage) + flags |= Image::FlagBits::eStorage; + + m_Device.SetName(image, createInfo.m_Name); + + return std::make_shared(&m_Device, image, allocation, imageCreateInfo.extent, imageCreateInfo.format, flags, + layerCount, mipLevels); +} + +Ref +systems::Device::CreateTextureCube(const TextureCubeCreateInfo &createInfo) +{ + constexpr VmaAllocationCreateInfo allocationCreateInfo = { + .flags = {}, + .usage = VMA_MEMORY_USAGE_AUTO, + }; + + VkImage rawImage; + VmaAllocation allocation; + vk::ImageCreateInfo imageCreateInfo = ToImageCreateInfo(createInfo); + auto result = Cast(vmaCreateImage(m_Device.m_Allocator, Recast(&imageCreateInfo), + &allocationCreateInfo, &rawImage, &allocation, nullptr)); + ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", createInfo.m_Name, result) THEN_ABORT(result); + + vk::Image image = rawImage; + + u8 layerCount = Cast(imageCreateInfo.arrayLayers); + u8 mipLevels = Cast(imageCreateInfo.mipLevels); + Image::Flags flags = Image::FlagBits::eCube; + if (createInfo.m_IsSampled) + flags |= Image::FlagBits::eSampled; + if (createInfo.m_IsStorage) + flags |= Image::FlagBits::eStorage; + + m_Device.SetName(image, createInfo.m_Name); + + return CastImage(std::make_shared(&m_Device, image, allocation, imageCreateInfo.extent, + imageCreateInfo.format, flags, layerCount, mipLevels)); +} + +Ref +systems::Device::CreateAttachment(const AttachmentCreateInfo &createInfo) +{ + constexpr VmaAllocationCreateInfo allocationCreateInfo = { + .flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT, + .usage = VMA_MEMORY_USAGE_AUTO, + }; + + VkImage rawImage; + VmaAllocation allocation; + vk::ImageCreateInfo imageCreateInfo = ToImageCreateInfo(createInfo); + auto result = Cast(vmaCreateImage(m_Device.m_Allocator, Recast(&imageCreateInfo), + &allocationCreateInfo, &rawImage, &allocation, nullptr)); + ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", createInfo.m_Name, result) THEN_ABORT(result); + + vk::Image image = rawImage; + + u8 layerCount = Cast(imageCreateInfo.arrayLayers); + u8 mipLevels = Cast(imageCreateInfo.mipLevels); + + m_Device.SetName(image, createInfo.m_Name); + + return std::make_shared(&m_Device, image, allocation, imageCreateInfo.extent, imageCreateInfo.format, + Image::Flags{}, layerCount, mipLevels); +} + +Ref +systems::Device::CreateDepthStencilImage(const DepthStencilImageCreateInfo &createInfo) +{ + constexpr VmaAllocationCreateInfo allocationCreateInfo = { + .flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT, + .usage = VMA_MEMORY_USAGE_AUTO, + }; + + VkImage rawImage; + VmaAllocation allocation; + vk::ImageCreateInfo imageCreateInfo = ToImageCreateInfo(createInfo); + auto result = Cast(vmaCreateImage(m_Device.m_Allocator, Recast(&imageCreateInfo), + &allocationCreateInfo, &rawImage, &allocation, nullptr)); + ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", createInfo.m_Name, result) THEN_ABORT(result); + + vk::Image image = rawImage; + + u8 layerCount = Cast(imageCreateInfo.arrayLayers); + u8 mipLevels = Cast(imageCreateInfo.mipLevels); + + m_Device.SetName(image, createInfo.m_Name); + + return std::make_shared(&m_Device, image, allocation, imageCreateInfo.extent, imageCreateInfo.format, + Image::Flags{}, layerCount, mipLevels); +} + +vk::ImageCreateInfo +ToImageCreateInfo(const systems::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 systems::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 systems::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 systems::DepthStencilImageCreateInfo &createInfo) +{ + auto &[extent, name] = createInfo; + + constexpr auto 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, + }; +} + +#pragma endregion + +// ==================================================================================================== +#pragma region View Management +// ==================================================================================================== + +Ref +systems::Device::CreateView(const ViewCreateInfo &createInfo) +{ + const auto layerCount = createInfo.GetLayerCount(); + const auto mipCount = createInfo.GetMipLevelCount(); + ERROR_IF((createInfo.m_BaseLayer + layerCount) > createInfo.m_Image->m_LayerCount, "Invalid Layer Access") + THEN_ABORT(-1); + ERROR_IF((createInfo.m_BaseMipLevel + mipCount) > createInfo.m_Image->m_MipLevels, "Invalid Mip Level Access") + THEN_ABORT(-1); + + vk::ImageView view; + const auto imageViewCreateInfo = Cast(createInfo); + auto 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); + + m_Device.SetName(view, createInfo.m_Name); + + return std::make_shared(createInfo.m_Image, view, createInfo.m_Image->m_Extent, createInfo.m_BaseLayer, + layerCount, createInfo.m_BaseMipLevel, mipCount); +} + +#pragma endregion + +// ==================================================================================================== +#pragma region Image - View Combined Management +// ==================================================================================================== + +Ref +systems::Device::CreateTexture2DWithView(const Texture2DCreateInfo &createInfo) +{ + return CreateView({ + .m_Image = CastImage(CreateTexture2D(createInfo)), + .m_Name = createInfo.m_Name, + .m_ViewType = vk::ImageViewType::e2D, + .m_AspectMask = vk::ImageAspectFlagBits::eColor, + }); +} + +Ref +systems::Device::CreateTextureCubeWithView(const TextureCubeCreateInfo &createInfo) +{ + return CreateView({ + .m_Image = CreateTextureCube(createInfo), + .m_Name = createInfo.m_Name, + .m_ViewType = vk::ImageViewType::eCube, + .m_AspectMask = vk::ImageAspectFlagBits::eColor, + }); +} + +Ref +systems::Device::CreateAttachmentWithView(const AttachmentCreateInfo &createInfo) +{ + return CreateView({ + .m_Image = CreateAttachment(createInfo), + .m_Name = createInfo.m_Name, + .m_ViewType = vk::ImageViewType::e2D, + .m_AspectMask = vk::ImageAspectFlagBits::eColor, + }); +} + +Ref +systems::Device::CreateDepthStencilImageWithView(const DepthStencilImageCreateInfo &createInfo) +{ + return CreateView({ + .m_Image = CreateDepthStencilImage(createInfo), + .m_Name = createInfo.m_Name, + .m_ViewType = vk::ImageViewType::e2D, + .m_AspectMask = vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil, + }); +} + +#pragma endregion + +// ==================================================================================================== +#pragma region Sampler +// ==================================================================================================== + +Ref +systems::Device::CreateSampler(const SamplerCreateInfo &createInfo) +{ + auto vkCreateInfo = Cast(createInfo); + + if (const auto iter = m_HashToSamplerIdx.find(vkCreateInfo); + iter != m_HashToSamplerIdx.end() && !iter->second.expired()) + { + return iter->second.lock(); + } + + auto object = std::make_shared(&m_Device, vkCreateInfo, createInfo.m_Name ? createInfo.m_Name : nullptr); + m_HashToSamplerIdx.emplace(vkCreateInfo, object); + + return object; +} + +#pragma endregion + +QueueAllocation +FindAppropriateQueueAllocation(const PhysicalDevice &physicalDevice) +{ + for (auto &queueFamilyInfo : physicalDevice.m_QueueFamilies) + { + if ((queueFamilyInfo.m_Support & REQUIRED_QUEUE_SUPPORT) == REQUIRED_QUEUE_SUPPORT) + { + return { + .m_Family = queueFamilyInfo.m_Index, + .m_Count = queueFamilyInfo.m_Count, + }; + } + } + ERROR("No suitable queue family on the GPU.") + THEN_ABORT(vk::Result::eErrorUnknown); +} + +systems::Device::Device(const DeviceCreateInfo &createInfo) + : m_Window{createInfo.m_Window} +{ + assert(createInfo.m_AppName); + assert(createInfo.m_PhysicalDeviceSelector); + + m_Instance = Instance{createInfo.m_AppName, createInfo.m_AppVersion}; + m_Surface = Surface{m_Instance, createInfo.m_Window}; + + const auto physicalDevices = PhysicalDevices{m_Surface, m_Instance}; + auto physicalDevice = createInfo.m_PhysicalDeviceSelector(physicalDevices); + + Features features = createInfo.m_Features; + + // TODO: Add the other queues + QueueAllocation queueAllocation = FindAppropriateQueueAllocation(physicalDevice); + + m_Device = ::Device{ + m_Instance, physicalDevice, features, {&queueAllocation, 1}, createInfo.m_PipelineCacheData, createInfo.m_Name}; + + m_GraphicsQueueFamily = queueAllocation.m_Family; + m_GraphicsQueue = m_Device.GetQueue(m_GraphicsQueueFamily, 0); + + m_Swapchain = Swapchain{m_Surface, m_Device, m_Window.get().GetSize()}; + + u32 index = 0; + for (auto &frame : m_Frames) + { + frame = CreateFrame(index++); + } +} + +systems::Device::~Device() +{ + for (auto &frame : m_Frames) + { + m_Device.m_Device.destroy(Take(frame.m_FrameAvailableFence), nullptr); + m_Device.m_Device.destroy(Take(frame.m_ImageAcquireSem), nullptr); + m_Device.m_Device.destroy(Take(frame.m_RenderFinishSem), nullptr); + m_Device.m_Device.destroy(Take(frame.m_Pool), nullptr); + } + m_HashToSamplerIdx.clear(); +} + +// ==================================================================================================== +#pragma region Frames +// ==================================================================================================== + +systems::Frame +systems::Device::CreateFrame(u32 frameIndex) +{ + vk::CommandPool pool; + vk::Fence fence; + vk::Semaphore acquire; + vk::Semaphore finished; + + NameString name = "Frame "; + name += Cast(frameIndex + '0'); + + const vk::CommandPoolCreateInfo commandPoolCreateInfo = { + .flags = vk::CommandPoolCreateFlagBits::eTransient, + .queueFamilyIndex = m_GraphicsQueueFamily, + }; + AbortIfFailedMV(m_Device.m_Device.createCommandPool(&commandPoolCreateInfo, nullptr, &pool), + "Could not command pool for frame {}", frameIndex); + + constexpr vk::FenceCreateInfo fenceCreateInfo = {.flags = vk::FenceCreateFlagBits::eSignaled}; + AbortIfFailedMV(m_Device.m_Device.createFence(&fenceCreateInfo, nullptr, &fence), + "Could not create a fence for frame {}", frameIndex); + + constexpr vk::SemaphoreCreateInfo semaphoreCreateInfo = {}; + AbortIfFailedMV(m_Device.m_Device.createSemaphore(&semaphoreCreateInfo, nullptr, &acquire), + "Could not create IA semaphore for frame {}.", frameIndex); + AbortIfFailedMV(m_Device.m_Device.createSemaphore(&semaphoreCreateInfo, nullptr, &finished), + "Could not create RF semaphore for frame {}.", frameIndex); + + m_Device.SetName(pool, name.c_str()); + m_Device.SetName(fence, name.c_str()); + m_Device.SetName(acquire, name.c_str()); + m_Device.SetName(finished, name.c_str()); + + DEBUG("Frame {} created successfully.", frameIndex); + + return Frame{ + .m_Device = &m_Device, + .m_Pool = pool, + .m_FrameAvailableFence = fence, + .m_ImageAcquireSem = acquire, + .m_RenderFinishSem = finished, + .m_FrameIdx = frameIndex, + }; +} + +systems::Frame & +systems::Device::GetNextFrame() +{ + Frame ¤tFrame = m_Frames[m_CurrentFrameIdx]; + u32 frameIndex = m_CurrentFrameIdx; + + m_CurrentFrameIdx = (m_CurrentFrameIdx + 1) % MAX_FRAMES_IN_FLIGHT; + + AbortIfFailedMV(m_Device.m_Device.waitForFences(1, ¤tFrame.m_FrameAvailableFence, true, MaxValue), + "Waiting for fence {} failed.", frameIndex); + + u32 imageIndex = 0; + bool imageAcquired = false; + while (!imageAcquired) + { + switch (auto result = m_Device.m_Device.acquireNextImageKHR( + m_Swapchain.m_Swapchain, MaxValue, currentFrame.m_ImageAcquireSem, nullptr, &imageIndex)) + { + case vk::Result::eSuccess: + case vk::Result::eSuboptimalKHR: // Suboptimal can still render. Better to let this go for semaphores etc. + imageAcquired = true; + break; // Image acquired. Break out of loop. + case vk::Result::eErrorOutOfDateKHR: + DEBUG("Recreating Swapchain. Cause: {}", result); + m_Swapchain.Create(m_Surface, m_Window.get().GetSize()); + break; // Image acquire has failed. We move to the next frame. + default: + AbortIfFailedMV(result, "Waiting for swapchain image {} failed.", frameIndex); + } + } + + // Reset fences here. In case swapchain was out of date, we leave the fences signalled. + AbortIfFailedMV(m_Device.m_Device.resetFences(1, ¤tFrame.m_FrameAvailableFence), "Fence {} reset failed.", + frameIndex); + + AbortIfFailedMV(m_Device.m_Device.resetCommandPool(currentFrame.m_Pool, {}), "Command pool {} reset failed.", + frameIndex); + + currentFrame.m_ImageIdx = imageIndex; + + currentFrame.m_SwapchainImage = m_Swapchain.m_Images[imageIndex]; + currentFrame.m_SwapchainImageView = m_Swapchain.m_ImageViews[imageIndex]; + + return currentFrame; +} + +systems::Device::Receipt +systems::Device::Submit(Frame &frame, GraphicsContext &graphicsContext) +{ + // TODO Consider a semaphore pool that you can 'pick' a semaphore from and use for submits. + // This can be used as a wait-semaphore for the next submit if you say 'depends on'. + vk::PipelineStageFlags waitDstStage = vk::PipelineStageFlagBits::eColorAttachmentOutput; + vk::SubmitInfo submitInfo = { + .waitSemaphoreCount = 1, + .pWaitSemaphores = &frame.m_ImageAcquireSem, + .pWaitDstStageMask = &waitDstStage, + .commandBufferCount = 1, + .pCommandBuffers = &graphicsContext.m_Cmd, + .signalSemaphoreCount = 1, + .pSignalSemaphores = &frame.m_RenderFinishSem, + }; + auto result = m_GraphicsQueue.submit(1, &submitInfo, frame.m_FrameAvailableFence); + ERROR_IF(Failed(result), "Command queue submit failed. Cause: {}", result) + THEN_ABORT(result); + + return 0; +} + +void +systems::Device::Present(Frame &frame) +{ + vk::PresentInfoKHR presentInfo = { + .waitSemaphoreCount = 1, + .pWaitSemaphores = &frame.m_RenderFinishSem, + .swapchainCount = 1, + .pSwapchains = &m_Swapchain.m_Swapchain, + .pImageIndices = &frame.m_ImageIdx, + .pResults = nullptr, + }; + switch (auto result = m_GraphicsQueue.presentKHR(&presentInfo)) + { + case vk::Result::eSuccess: + break; + case vk::Result::eErrorOutOfDateKHR: + case vk::Result::eSuboptimalKHR: + DEBUG("Recreating Swapchain. Cause: {}", result); + m_Swapchain.Create(m_Surface, m_Window.get().GetSize()); + break; // Present failed. We do nothing. Frame is skipped. + default: + AbortIfFailedM(result, "Swapchain Present failed."); + } +} + +systems::GraphicsContext +systems::Frame::CreateGraphicsContext() +{ + vk::CommandBuffer cmd; + + const vk::CommandBufferAllocateInfo allocateInfo{ + .commandPool = m_Pool, + .level = vk::CommandBufferLevel::ePrimary, + .commandBufferCount = 1, + }; + AbortIfFailedMV(m_Device->m_Device.allocateCommandBuffers(&allocateInfo, &cmd), "Command buffer {} alloc failed.", + m_FrameIdx); + + return GraphicsContext{cmd}; +} + +#pragma endregion + +// ==================================================================================================== +#pragma region Context Impl +// ==================================================================================================== + +void +systems::Context::Begin() +{ + vk::CommandBufferBeginInfo commandBufferBeginInfo = { + .flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit, + }; + + auto result = m_Cmd.begin(&commandBufferBeginInfo); + ERROR_IF(Failed(result), "Could not begin context") THEN_ABORT(result); +} + +void +systems::Context::End() +{ + auto result = m_Cmd.end(); + ERROR_IF(Failed(result), "Could not end context") THEN_ABORT(result); +} + +void +systems::GraphicsContext::BindPipeline(vk::Pipeline pipeline) +{ + m_Cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline); +} + +void +systems::GraphicsContext::DrawIndexed(u32 indexCount) +{ + m_Cmd.drawIndexed(indexCount, 1, 0, 0, 0); +} + +void +systems::GraphicsContext::Dependency(const vk::DependencyInfo &dependencyInfo) +{ + m_Cmd.pipelineBarrier2(&dependencyInfo); +} + +void +systems::GraphicsContext::BeginRendering(const vk::RenderingInfo &renderingInfo) +{ + m_Cmd.beginRendering(&renderingInfo); +} + +void +systems::GraphicsContext::EndRendering() +{ + m_Cmd.endRendering(); +} + +#pragma endregion \ No newline at end of file diff --git a/aster/src/aster/systems/image_manager.cpp b/aster/src/aster/systems/image_manager.cpp deleted file mode 100644 index 762d83d..0000000 --- a/aster/src/aster/systems/image_manager.cpp +++ /dev/null @@ -1,236 +0,0 @@ -// ============================================= -// Aster: image_manager.cpp -// Copyright (c) 2020-2025 Anish Bhobe -// ============================================= - -#include "systems/image_manager.h" - -#include "core/device.h" - -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 - -ImageManager::ImageManager(const Device *device) - : m_Device{device} -{ -} - -Ref -ImageManager::CreateTexture2D(const Texture2DCreateInfo &createInfo) -{ - constexpr VmaAllocationCreateInfo allocationCreateInfo = { - .flags = {}, - .usage = VMA_MEMORY_USAGE_AUTO, - }; - - VkImage rawImage; - VmaAllocation allocation; - vk::ImageCreateInfo imageCreateInfo = ToImageCreateInfo(createInfo); - auto result = Cast(vmaCreateImage(m_Device->m_Allocator, Recast(&imageCreateInfo), - &allocationCreateInfo, &rawImage, &allocation, nullptr)); - ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", createInfo.m_Name, result) THEN_ABORT(result); - - vk::Image image = rawImage; - - u8 layerCount = Cast(imageCreateInfo.arrayLayers); - u8 mipLevels = Cast(imageCreateInfo.mipLevels); - Image::Flags flags = {}; - if (createInfo.m_IsSampled) - flags |= Image::FlagBits::eSampled; - if (createInfo.m_IsStorage) - flags |= Image::FlagBits::eStorage; - - m_Device->SetName(image, createInfo.m_Name); - - return std::make_shared(m_Device, image, allocation, imageCreateInfo.extent, imageCreateInfo.format, flags, - layerCount, mipLevels); -} - -Ref -ImageManager::CreateTextureCube(const TextureCubeCreateInfo &createInfo) -{ - constexpr VmaAllocationCreateInfo allocationCreateInfo = { - .flags = {}, - .usage = VMA_MEMORY_USAGE_AUTO, - }; - - VkImage rawImage; - VmaAllocation allocation; - vk::ImageCreateInfo imageCreateInfo = ToImageCreateInfo(createInfo); - auto result = Cast(vmaCreateImage(m_Device->m_Allocator, Recast(&imageCreateInfo), - &allocationCreateInfo, &rawImage, &allocation, nullptr)); - ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", createInfo.m_Name, result) THEN_ABORT(result); - - vk::Image image = rawImage; - - u8 layerCount = Cast(imageCreateInfo.arrayLayers); - u8 mipLevels = Cast(imageCreateInfo.mipLevels); - Image::Flags flags = Image::FlagBits::eCube; - if (createInfo.m_IsSampled) - flags |= Image::FlagBits::eSampled; - if (createInfo.m_IsStorage) - flags |= Image::FlagBits::eStorage; - - m_Device->SetName(image, createInfo.m_Name); - - return CastImage(std::make_shared(m_Device, image, allocation, imageCreateInfo.extent, - imageCreateInfo.format, flags, layerCount, mipLevels)); -} - -Ref -ImageManager::CreateAttachment(const AttachmentCreateInfo &createInfo) -{ - constexpr VmaAllocationCreateInfo allocationCreateInfo = { - .flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT, - .usage = VMA_MEMORY_USAGE_AUTO, - }; - - VkImage rawImage; - VmaAllocation allocation; - vk::ImageCreateInfo imageCreateInfo = ToImageCreateInfo(createInfo); - auto result = Cast(vmaCreateImage(m_Device->m_Allocator, Recast(&imageCreateInfo), - &allocationCreateInfo, &rawImage, &allocation, nullptr)); - ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", createInfo.m_Name, result) THEN_ABORT(result); - - vk::Image image = rawImage; - - u8 layerCount = Cast(imageCreateInfo.arrayLayers); - u8 mipLevels = Cast(imageCreateInfo.mipLevels); - - m_Device->SetName(image, createInfo.m_Name); - - return std::make_shared(m_Device, image, allocation, imageCreateInfo.extent, imageCreateInfo.format, - Image::Flags{}, layerCount, mipLevels); -} - -Ref -ImageManager::CreateDepthStencilImage(const DepthStencilImageCreateInfo &createInfo) -{ - constexpr VmaAllocationCreateInfo allocationCreateInfo = { - .flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT, - .usage = VMA_MEMORY_USAGE_AUTO, - }; - - VkImage rawImage; - VmaAllocation allocation; - vk::ImageCreateInfo imageCreateInfo = ToImageCreateInfo(createInfo); - auto result = Cast(vmaCreateImage(m_Device->m_Allocator, Recast(&imageCreateInfo), - &allocationCreateInfo, &rawImage, &allocation, nullptr)); - ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", createInfo.m_Name, result) THEN_ABORT(result); - - vk::Image image = rawImage; - - u8 layerCount = Cast(imageCreateInfo.arrayLayers); - u8 mipLevels = Cast(imageCreateInfo.mipLevels); - - m_Device->SetName(image, createInfo.m_Name); - - return std::make_shared(m_Device, image, allocation, imageCreateInfo.extent, imageCreateInfo.format, - Image::Flags{}, layerCount, mipLevels); -} - -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 auto 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, - }; -} \ No newline at end of file diff --git a/aster/src/aster/systems/sampler_manager.cpp b/aster/src/aster/systems/sampler_manager.cpp deleted file mode 100644 index dbc775d..0000000 --- a/aster/src/aster/systems/sampler_manager.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// ============================================= -// Aster: sampler_manager.cpp -// Copyright (c) 2020-2025 Anish Bhobe -// ============================================= - -#include "systems/sampler_manager.h" - -#include "core/device.h" - -using namespace systems; - -SamplerManager::SamplerManager(const Device *device) - : m_Device{device} -{ -} - -SamplerManager::~SamplerManager() -{ - m_HashToSamplerIdx.clear(); -} - -Ref -SamplerManager::CreateSampler(const SamplerCreateInfo &createInfo) -{ - auto vkCreateInfo = Cast(createInfo); - - if (const auto iter = m_HashToSamplerIdx.find(vkCreateInfo); iter != m_HashToSamplerIdx.end() && !iter->second.expired()) - { - return iter->second.lock(); - } - - auto object = std::make_shared(m_Device, vkCreateInfo, createInfo.m_Name ? createInfo.m_Name : nullptr); - m_HashToSamplerIdx.emplace(vkCreateInfo, object); - - return object; -} \ No newline at end of file diff --git a/aster/src/aster/systems/view_manager.cpp b/aster/src/aster/systems/view_manager.cpp deleted file mode 100644 index f812182..0000000 --- a/aster/src/aster/systems/view_manager.cpp +++ /dev/null @@ -1,37 +0,0 @@ -// ============================================= -// Aster: view_manager.cpp -// Copyright (c) 2020-2025 Anish Bhobe -// ============================================= - -#include "systems/view_manager.h" - -#include "core/device.h" - -using namespace systems; - -ViewManager::ViewManager(const Device *device) - : m_Device{device} -{ -} - -Ref -ViewManager::CreateView(const ViewCreateInfo &createInfo) const -{ - const auto layerCount = createInfo.GetLayerCount(); - const auto mipCount = createInfo.GetMipLevelCount(); - ERROR_IF((createInfo.m_BaseLayer + layerCount) > createInfo.m_Image->m_LayerCount, "Invalid Layer Access") - THEN_ABORT(-1); - ERROR_IF((createInfo.m_BaseMipLevel + mipCount) > createInfo.m_Image->m_MipLevels, "Invalid Mip Level Access") - THEN_ABORT(-1); - - vk::ImageView view; - const auto imageViewCreateInfo = Cast(createInfo); - auto 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); - - m_Device->SetName(view, createInfo.m_Name); - - return std::make_shared(createInfo.m_Image, view, createInfo.m_Image->m_Extent, createInfo.m_BaseLayer, - layerCount, createInfo.m_BaseMipLevel, mipCount); -} \ No newline at end of file diff --git a/samples/01_triangle/triangle.cpp b/samples/01_triangle/triangle.cpp index 19722d4..7af7a48 100644 --- a/samples/01_triangle/triangle.cpp +++ b/samples/01_triangle/triangle.cpp @@ -8,18 +8,16 @@ #include "aster/core/buffer.h" #include "aster/core/constants.h" #include "aster/core/instance.h" -#include "aster/core/device.h" #include "aster/core/physical_device.h" #include "aster/core/pipeline.h" #include "aster/core/swapchain.h" #include "aster/core/window.h" +#include "aster/systems/device.h" #include "helpers.h" -#include "aster/systems/resource_manager.h" #include -constexpr u32 MAX_FRAMES_IN_FLIGHT = 3; constexpr auto VERTEX_SHADER_FILE = "shader/triangle.vert.glsl.spv"; constexpr auto FRAGMENT_SHADER_FILE = "shader/triangle.frag.glsl.spv"; @@ -57,61 +55,21 @@ struct Vertex } }; -struct Frame -{ - const Device *m_Device; - vk::CommandPool m_Pool; - vk::CommandBuffer m_CommandBuffer; - vk::Fence m_FrameAvailableFence; - vk::Semaphore m_ImageAcquireSem; - vk::Semaphore m_RenderFinishSem; - - Frame(const Device *device, u32 queueFamilyIndex, u32 frameCount); - ~Frame(); -}; - int main(int, char **) { MIN_LOG_LEVEL(Logger::LogType::eInfo); Window window = {"Triangle (Aster)", {640, 480}}; - Instance context = {"Triangle", VERSION}; - Surface surface = {&context, &window, "Primary"}; + systems::Device device{{ + .m_AppName = "Triangle", + .m_Window = window, + .m_Name = "Primary", + .m_Features = {.m_Vulkan12Features = {.bufferDeviceAddress = true}, + .m_Vulkan13Features = {.synchronization2 = true, .dynamicRendering = true}}, + }}; - PhysicalDevices physicalDevices = {&surface, &context}; - PhysicalDevice deviceToUse = FindSuitableDevice(physicalDevices); - - INFO("Using {} as the primary device.", deviceToUse.m_DeviceProperties.deviceName.data()); - - Features enabledDeviceFeatures = { - .m_Vulkan12Features = {.bufferDeviceAddress = true}, - .m_Vulkan13Features = {.synchronization2 = true, .dynamicRendering = true}, - }; - QueueAllocation queueAllocation = FindAppropriateQueueAllocation(&deviceToUse); - Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"}; - vk::Queue commandQueue = device.GetQueue(queueAllocation.m_Family, 0); - Swapchain swapchain = {&surface, &device, window.GetSize(), "Primary Chain"}; - Pipeline pipeline = CreatePipeline(&device, &swapchain); - systems::ResourceManager resourceManager{&device}; - - vk::CommandPool copyPool; - vk::CommandBuffer copyBuffer; - { - vk::CommandPoolCreateInfo poolCreateInfo = { - .flags = vk::CommandPoolCreateFlagBits::eTransient, - .queueFamilyIndex = queueAllocation.m_Family, - }; - auto result = device.m_Device.createCommandPool(&poolCreateInfo, nullptr, ©Pool); - ERROR_IF(Failed(result), "Copy command pool creation failed. Cause: {}", result) THEN_ABORT(result); - vk::CommandBufferAllocateInfo bufferAllocateInfo = { - .commandPool = copyPool, - .level = vk::CommandBufferLevel::ePrimary, - .commandBufferCount = 1, - }; - result = device.m_Device.allocateCommandBuffers(&bufferAllocateInfo, ©Buffer); - ERROR_IF(Failed(result), "Copy command buffer allocation failed. Cause: {}", result) THEN_ABORT(result); - } + Pipeline pipeline = CreatePipeline(&device.m_Device, &device.m_Swapchain); // eastl::array vertices{}; eastl::array vertices = { @@ -119,22 +77,24 @@ main(int, char **) Vertex{.m_Position = {0.5f, -0.5f, 0.0f}, .m_Color = {0.0f, 1.0f, 0.0f}}, Vertex{.m_Position = {0.0f, 0.5f, 0.0f}, .m_Color = {0.0f, 0.0f, 1.0f}}, }; - auto vbo = resourceManager.Buffers().CreateVertexBuffer(vertices.size() * sizeof vertices[0], "VBO"); + auto vbo = device.CreateVertexBuffer(vertices.size() * sizeof vertices[0], "VBO"); vbo->Write(0, vertices.size() * sizeof vertices[0], vertices.data()); + Size2D swapchainSize = device.GetSwapchainSize(); + // Persistent variables vk::Viewport viewport = { .x = 0, - .y = Cast(swapchain.m_Extent.height), - .width = Cast(swapchain.m_Extent.width), - .height = -Cast(swapchain.m_Extent.height), + .y = Cast(swapchainSize.m_Height), + .width = Cast(swapchainSize.m_Width), + .height = -Cast(swapchainSize.m_Height), .minDepth = 0.0, .maxDepth = 1.0, }; vk::Rect2D scissor = { .offset = {0, 0}, - .extent = swapchain.m_Extent, + .extent = Cast(swapchainSize), }; vk::ImageSubresourceRange subresourceRange = { @@ -151,8 +111,8 @@ main(int, char **) .dstAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite, .oldLayout = vk::ImageLayout::eUndefined, .newLayout = vk::ImageLayout::eColorAttachmentOptimal, - .srcQueueFamilyIndex = queueAllocation.m_Family, - .dstQueueFamilyIndex = queueAllocation.m_Family, + .srcQueueFamilyIndex = vk::QueueFamilyIgnored, + .dstQueueFamilyIndex = vk::QueueFamilyIgnored, .subresourceRange = subresourceRange, }; vk::DependencyInfo topOfThePipeDependency = { @@ -166,8 +126,8 @@ main(int, char **) .dstAccessMask = vk::AccessFlagBits2::eNone, .oldLayout = vk::ImageLayout::eColorAttachmentOptimal, .newLayout = vk::ImageLayout::ePresentSrcKHR, - .srcQueueFamilyIndex = queueAllocation.m_Family, - .dstQueueFamilyIndex = queueAllocation.m_Family, + .srcQueueFamilyIndex = vk::QueueFamilyIgnored, + .dstQueueFamilyIndex = vk::QueueFamilyIgnored, .subresourceRange = subresourceRange, }; vk::DependencyInfo renderToPresentDependency = { @@ -175,70 +135,34 @@ main(int, char **) .pImageMemoryBarriers = &renderToPresentBarrier, }; - // Frames - eastl::fixed_vector frames; - for (u32 i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i) - { - frames.emplace_back(&device, queueAllocation.m_Family, i); - } - INFO("Starting loop"); u32 frameIndex = 0; while (window.Poll()) { - Frame *currentFrame = &frames[frameIndex]; + systems::Frame ¤tFrame = device.GetNextFrame(); - auto result = device.m_Device.waitForFences(1, ¤tFrame->m_FrameAvailableFence, true, MaxValue); - ERROR_IF(Failed(result), "Waiting for fence {} failed. Cause: {}", frameIndex, result) - THEN_ABORT(result); + vk::CommandBuffer cmd; - u32 imageIndex; - result = device.m_Device.acquireNextImageKHR(swapchain.m_Swapchain, MaxValue, - currentFrame->m_ImageAcquireSem, nullptr, &imageIndex); - if (Failed(result)) - { - switch (result) - { - case vk::Result::eErrorOutOfDateKHR: - case vk::Result::eSuboptimalKHR: - INFO("Recreating Swapchain. Cause: {}", result); - swapchain.Create(&surface, window.GetSize()); - viewport.y = Cast(swapchain.m_Extent.height); - viewport.width = Cast(swapchain.m_Extent.width); - viewport.height = -Cast(swapchain.m_Extent.height); - scissor.extent = swapchain.m_Extent; - continue; // Image acquire has failed. We move to the next frame. - default: - ERROR("Waiting for swapchain image {} failed. Cause: {}", frameIndex, result) - THEN_ABORT(result); - } - } - // Reset fences here. In case swapchain was out of date, we leave the fences signalled. - result = device.m_Device.resetFences(1, ¤tFrame->m_FrameAvailableFence); - ERROR_IF(Failed(result), "Fence {} reset failed. Cause: {}", frameIndex, result) - THEN_ABORT(result); + const vk::CommandBufferAllocateInfo allocateInfo{ + .commandPool = currentFrame.m_Pool, + .level = vk::CommandBufferLevel::ePrimary, + .commandBufferCount = 1, + }; + AbortIfFailedMV(device.m_Device.m_Device.allocateCommandBuffers(&allocateInfo, &cmd), + "Command buffer {} alloc failed.", currentFrame.m_FrameIdx); - result = device.m_Device.resetCommandPool(currentFrame->m_Pool, {}); - ERROR_IF(Failed(result), "Command pool {} reset failed. Cause: {}", frameIndex, result) - THEN_ABORT(result); + auto context = currentFrame.CreateGraphicsContext(); - vk::ImageView currentImageView = swapchain.m_ImageViews[imageIndex]; - vk::Image currentImage = swapchain.m_Images[imageIndex]; - vk::CommandBuffer cmd = currentFrame->m_CommandBuffer; + topOfThePipeBarrier.image = currentFrame.m_SwapchainImage; + renderToPresentBarrier.image = currentFrame.m_SwapchainImage; - topOfThePipeBarrier.image = currentImage; - renderToPresentBarrier.image = currentImage; + context.Begin(); - vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit}; - result = cmd.begin(&beginInfo); - ERROR_IF(Failed(result), "Command buffer begin failed. Cause: {}", result) - THEN_ABORT(result); - - cmd.pipelineBarrier2(&topOfThePipeDependency); + context.Dependency(topOfThePipeDependency); // Render vk::RenderingAttachmentInfo attachmentInfo = { - .imageView = currentImageView, + .imageView = currentFrame.m_SwapchainImageView, .imageLayout = vk::ImageLayout::eColorAttachmentOptimal, .resolveMode = vk::ResolveModeFlagBits::eNone, .loadOp = vk::AttachmentLoadOp::eClear, @@ -247,115 +171,37 @@ main(int, char **) }; vk::RenderingInfo renderingInfo = { - .renderArea = {.extent = swapchain.m_Extent}, + .renderArea = {.extent = scissor.extent}, .layerCount = 1, .colorAttachmentCount = 1, .pColorAttachments = &attachmentInfo, }; - cmd.beginRendering(&renderingInfo); + context.BeginRendering(renderingInfo); - cmd.setViewport(0, 1, &viewport); - cmd.setScissor(0, 1, &scissor); - cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.m_Pipeline); - usize offsets = 0; - cmd.bindVertexBuffers(0, 1, &vbo->m_Buffer, &offsets); - cmd.draw(3, 1, 0, 0); + // cmd.setViewport(0, 1, &viewport); + // cmd.setScissor(0, 1, &scissor); + // cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.m_Pipeline); + // usize offsets = 0; + // cmd.bindVertexBuffers(0, 1, &vbo->m_Buffer, &offsets); + // cmd.draw(3, 1, 0, 0); - cmd.endRendering(); + context.EndRendering(); - cmd.pipelineBarrier2(&renderToPresentDependency); + context.Dependency(renderToPresentDependency); - result = cmd.end(); - ERROR_IF(Failed(result), "Command buffer end failed. Cause: {}", result) - THEN_ABORT(result); + context.End(); - vk::PipelineStageFlags waitDstStage = vk::PipelineStageFlagBits::eColorAttachmentOutput; - vk::SubmitInfo submitInfo = { - .waitSemaphoreCount = 1, - .pWaitSemaphores = ¤tFrame->m_ImageAcquireSem, - .pWaitDstStageMask = &waitDstStage, - .commandBufferCount = 1, - .pCommandBuffers = &cmd, - .signalSemaphoreCount = 1, - .pSignalSemaphores = ¤tFrame->m_RenderFinishSem, - }; - result = commandQueue.submit(1, &submitInfo, currentFrame->m_FrameAvailableFence); - ERROR_IF(Failed(result), "Command queue submit failed. Cause: {}", result) - THEN_ABORT(result); + device.Submit(currentFrame, context); - vk::PresentInfoKHR presentInfo = { - .waitSemaphoreCount = 1, - .pWaitSemaphores = ¤tFrame->m_RenderFinishSem, - .swapchainCount = 1, - .pSwapchains = &swapchain.m_Swapchain, - .pImageIndices = &imageIndex, - .pResults = nullptr, - }; - result = commandQueue.presentKHR(&presentInfo); - if (Failed(result)) - { - switch (result) - { - case vk::Result::eErrorOutOfDateKHR: - case vk::Result::eSuboptimalKHR: - INFO("Recreating Swapchain. Cause: {}", result); - swapchain.Create(&surface, window.GetSize()); - viewport.y = Cast(swapchain.m_Extent.height); - viewport.width = Cast(swapchain.m_Extent.width); - viewport.height = -Cast(swapchain.m_Extent.height); - scissor.extent = swapchain.m_Extent; - break; // Present failed. We redo the frame. - default: - ERROR("Command queue present failed. Cause: {}", result) - THEN_ABORT(result); - } - } - frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; + device.Present(currentFrame); } device.WaitIdle(); - device.m_Device.destroy(copyPool, nullptr); - return 0; } -Frame::Frame(const Device *device, const u32 queueFamilyIndex, const u32 frameCount) -{ - m_Device = device; - - const vk::CommandPoolCreateInfo commandPoolCreateInfo = { - .flags = vk::CommandPoolCreateFlagBits::eTransient, - .queueFamilyIndex = queueFamilyIndex, - }; - vk::Result result = device->m_Device.createCommandPool(&commandPoolCreateInfo, nullptr, &m_Pool); - ERROR_IF(Failed(result), "Could not command pool for frame {}. Cause: {}", frameCount, result) - THEN_ABORT(result); - - constexpr vk::FenceCreateInfo fenceCreateInfo = {.flags = vk::FenceCreateFlagBits::eSignaled}; - result = device->m_Device.createFence(&fenceCreateInfo, nullptr, &m_FrameAvailableFence); - ERROR_IF(Failed(result), "Could not create a fence for frame {}. Cause: {}", frameCount, result) - THEN_ABORT(result); - - constexpr vk::SemaphoreCreateInfo semaphoreCreateInfo = {}; - result = device->m_Device.createSemaphore(&semaphoreCreateInfo, nullptr, &m_ImageAcquireSem); - ERROR_IF(Failed(result), "Could not create IA semaphore for frame {}. Cause: {}", frameCount, result) - THEN_ABORT(result); - result = device->m_Device.createSemaphore(&semaphoreCreateInfo, nullptr, &m_RenderFinishSem); - ERROR_IF(Failed(result), "Could not create RF semaphore for frame {}. Cause: {}", frameCount, result) - THEN_ABORT(result); - - const vk::CommandBufferAllocateInfo allocateInfo = { - .commandPool = m_Pool, .level = vk::CommandBufferLevel::ePrimary, .commandBufferCount = 1}; - - result = m_Device->m_Device.allocateCommandBuffers(&allocateInfo, &m_CommandBuffer); - ERROR_IF(Failed(result), "Command buffer allocation failed. Cause: {}", result) - THEN_ABORT(result); - - DEBUG("Frame {} created successfully.", frameCount); -} - Pipeline CreatePipeline(const Device *device, const Swapchain *swapchain) { @@ -498,13 +344,3 @@ CreateShader(const Device *device, cstr shaderFile) THEN_ABORT(result); return shaderModule; } - -Frame::~Frame() -{ - m_Device->m_Device.destroy(m_RenderFinishSem, nullptr); - m_Device->m_Device.destroy(m_ImageAcquireSem, nullptr); - m_Device->m_Device.destroy(m_FrameAvailableFence, nullptr); - m_Device->m_Device.destroy(m_Pool, nullptr); - - DEBUG("Destoryed Frame"); -} \ No newline at end of file