diff --git a/aster/buffer.cpp b/aster/buffer.cpp index f52f53c..cfc01b2 100644 --- a/aster/buffer.cpp +++ b/aster/buffer.cpp @@ -11,11 +11,11 @@ void Buffer::Destroy(const Device *device) { - if (!IsValid()) + if (!IsValid() || !IsOwned()) return; vmaDestroyBuffer(device->m_Allocator, m_Buffer, m_Allocation); - m_Size &= ~VALID_BUFFER_BIT; + m_Size_ = 0; } void @@ -47,7 +47,7 @@ Buffer::Allocate(const Device *device, usize size, vk::BufferUsageFlags bufferUs bool hostAccessible = Cast(memoryPropertyFlags & vk::MemoryPropertyFlagBits::eHostVisible); m_Buffer = buffer; - m_Size = size | VALID_BUFFER_BIT | (hostAccessible ? HOST_ACCESSIBLE_BIT : 0); + m_Size_ = size | VALID_BUFFER_BIT | OWNED_BIT | (hostAccessible ? HOST_ACCESSIBLE_BIT : 0); m_Allocation = allocation; m_Mapped = Cast(allocationInfo.pMappedData); diff --git a/aster/buffer.h b/aster/buffer.h index e98330d..2467df2 100644 --- a/aster/buffer.h +++ b/aster/buffer.h @@ -19,23 +19,27 @@ struct Buffer [[nodiscard]] bool IsHostVisible() const; [[nodiscard]] bool IsValid() const; [[nodiscard]] bool IsMapped() const; + [[nodiscard]] bool IsOwned() const; void Destroy(const Device *device); void Write(const Device *device, usize offset, usize size, const void *data); - protected: void Allocate(const Device *device, usize size, vk::BufferUsageFlags bufferUsage, VmaAllocationCreateFlags allocationFlags, VmaMemoryUsage memoryUsage, cstr name); - // Buffer size is used intrusively by the Render Resource Manager - // If the buffer is Invalid, the remaining data in Buffer is used for other tasks. - usize m_Size = 0; + // Buffer.size is used for bookkeeping + // If the buffer is Invalid, the remaining data in Buffer is used intrusively by `GpuResourceManager`. + usize m_Size_ = 0; constexpr static usize VALID_BUFFER_BIT = Cast(1llu << 63); constexpr static usize HOST_ACCESSIBLE_BIT = 1llu << 62; - constexpr static usize SIZE_MASK = ~(VALID_BUFFER_BIT | HOST_ACCESSIBLE_BIT); + constexpr static usize OWNED_BIT = 1llu << 61; + constexpr static usize SIZE_MASK = ~(VALID_BUFFER_BIT | HOST_ACCESSIBLE_BIT | OWNED_BIT); }; +// Ensure that m_Size doesn't get used intrusively since it manages the state. +static_assert(offsetof(Buffer, m_Size_) > sizeof(usize)); + struct UniformBuffer : Buffer { void Init(const Device *device, usize size, cstr name = nullptr); @@ -66,19 +70,19 @@ struct StagingBuffer : Buffer inline usize Buffer::GetSize() const { - return m_Size & SIZE_MASK; + return m_Size_ & SIZE_MASK; } inline bool Buffer::IsHostVisible() const { - return m_Size & HOST_ACCESSIBLE_BIT; + return m_Size_ & HOST_ACCESSIBLE_BIT; } inline bool Buffer::IsValid() const { - return m_Size & VALID_BUFFER_BIT; + return m_Size_ & VALID_BUFFER_BIT; } inline bool @@ -86,3 +90,9 @@ Buffer::IsMapped() const { return m_Mapped; } + +inline bool +Buffer::IsOwned() const +{ + return m_Size_ & OWNED_BIT; +} diff --git a/aster/image.cpp b/aster/image.cpp index 8a1c64b..eefd4bb 100644 --- a/aster/image.cpp +++ b/aster/image.cpp @@ -10,12 +10,12 @@ void Image::Destroy(const Device *device) { - if (!IsValid()) + if (!IsValid() || !IsOwned()) return; device->m_Device.destroy(m_View, nullptr); vmaDestroyImage(device->m_Allocator, m_Image, m_Allocation); - m_Image = nullptr; + m_MipLevels_ = 0; } void @@ -23,6 +23,7 @@ Texture::Init(const Device *device, const vk::Extent2D extent, vk::Format imageF const cstr name) { const u32 mipLevels = isMipmapped ? 1 + Cast(floor(log2(eastl::max(extent.width, extent.height)))) : 1; + assert(mipLevels <= MIP_MASK); auto usage = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst; if (isMipmapped) @@ -75,7 +76,7 @@ Texture::Init(const Device *device, const vk::Extent2D extent, vk::Format imageF m_View = view; m_Allocation = allocation; m_Extent = {extent.width, extent.height, 1}; - m_MipLevels = Cast(mipLevels); + m_MipLevels_ = mipLevels | OWNED_BIT | VALID_BIT; device->SetName(m_Image, name); } @@ -129,6 +130,7 @@ DepthImage::Init(const Device *device, vk::Extent2D extent, cstr name) m_View = view; m_Allocation = allocation; m_Extent = {extent.width, extent.height, 1}; + m_MipLevels_ = 1 | OWNED_BIT | VALID_BIT; device->SetName(m_Image, name); } diff --git a/aster/image.h b/aster/image.h index c2c1d3d..22970d6 100644 --- a/aster/image.h +++ b/aster/image.h @@ -15,11 +15,19 @@ struct Image vk::ImageView m_View = nullptr; VmaAllocation m_Allocation = nullptr; vk::Extent3D m_Extent; - u8 m_MipLevels = 1; + // Image.m_MipLevels_ is used for bookkeeping + // If the image is Invalid, the remaining data in Image is used intrusively by `GpuResourceManager`. + u32 m_MipLevels_; [[nodiscard]] bool IsValid() const; + [[nodiscard]] bool IsOwned() const; + [[nodiscard]] u32 GetMipLevels() const; void Destroy(const Device *device); + + constexpr static u32 VALID_BIT = 1u << 31; + constexpr static u32 OWNED_BIT = 1u << 30; + constexpr static u32 MIP_MASK = ~(VALID_BIT | OWNED_BIT); }; struct Texture : Image @@ -35,5 +43,17 @@ struct DepthImage : Image inline bool Image::IsValid() const { - return m_Image; + return m_MipLevels_ & VALID_BIT; +} + +inline bool +Image::IsOwned() const +{ + return m_MipLevels_ & OWNED_BIT; +} + +inline u32 +Image::GetMipLevels() const +{ + return m_MipLevels_ & MIP_MASK; } \ No newline at end of file diff --git a/samples/03_model_render/model/OrientationTest.glb b/samples/03_model_render/model/OrientationTest.glb new file mode 100644 index 0000000..9713071 --- /dev/null +++ b/samples/03_model_render/model/OrientationTest.glb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a91cf448f37de06ab61bc615e123692dd29ac185e6c69e1fdbf1cf53e41045b2 +size 38920 diff --git a/samples/03_model_render/model_loader.cpp b/samples/03_model_render/model_loader.cpp index f54f236..9dbf2f6 100644 --- a/samples/03_model_render/model_loader.cpp +++ b/samples/03_model_render/model_loader.cpp @@ -45,13 +45,15 @@ VectorToVec3(const std::vector &vec) } TextureHandle -ModelLoader::LoadImage(vk::CommandBuffer commandBuffer, Texture *texture, StagingBuffer *stagingBuffer, +ModelLoader::LoadImage(vk::CommandBuffer commandBuffer, StagingBuffer *stagingBuffer, tinygltf::Image *image) const { assert(image->component == 4); + Texture texture; + usize byteSize = image->image.size(); - texture->Init(m_ResourceManager->m_Device, {.width = Cast(image->width), .height = Cast(image->height)}, + texture.Init(m_ResourceManager->m_Device, {.width = Cast(image->width), .height = Cast(image->height)}, vk::Format::eR8G8B8A8Srgb, true, image->name.data()); stagingBuffer->Init(m_ResourceManager->m_Device, byteSize); stagingBuffer->Write(m_ResourceManager->m_Device, 0, byteSize, image->image.data()); @@ -63,15 +65,15 @@ ModelLoader::LoadImage(vk::CommandBuffer commandBuffer, Texture *texture, Stagin .newLayout = vk::ImageLayout::eTransferDstOptimal, .srcQueueFamilyIndex = vk::QueueFamilyIgnored, .dstQueueFamilyIndex = vk::QueueFamilyIgnored, - .image = texture->m_Image, + .image = texture.m_Image, .subresourceRange = - { - .aspectMask = vk::ImageAspectFlagBits::eColor, - .baseMipLevel = 0, - .levelCount = texture->m_MipLevels, - .baseArrayLayer = 0, - .layerCount = 1, - }, + { + .aspectMask = vk::ImageAspectFlagBits::eColor, + .baseMipLevel = 0, + .levelCount = texture.GetMipLevels(), + .baseArrayLayer = 0, + .layerCount = 1, + }, }; vk::ImageMemoryBarrier nextMipBarrier = { @@ -81,15 +83,15 @@ ModelLoader::LoadImage(vk::CommandBuffer commandBuffer, Texture *texture, Stagin .newLayout = vk::ImageLayout::eTransferSrcOptimal, .srcQueueFamilyIndex = vk::QueueFamilyIgnored, .dstQueueFamilyIndex = vk::QueueFamilyIgnored, - .image = texture->m_Image, + .image = texture.m_Image, .subresourceRange = - { - .aspectMask = vk::ImageAspectFlagBits::eColor, - .baseMipLevel = 0, - .levelCount = 1, - .baseArrayLayer = 0, - .layerCount = 1, - }, + { + .aspectMask = vk::ImageAspectFlagBits::eColor, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, }; vk::ImageMemoryBarrier imageReadyBarrier = { @@ -99,15 +101,15 @@ ModelLoader::LoadImage(vk::CommandBuffer commandBuffer, Texture *texture, Stagin .newLayout = vk::ImageLayout::eShaderReadOnlyOptimal, .srcQueueFamilyIndex = m_TransferQueueIndex, .dstQueueFamilyIndex = m_GraphicsQueueIndex, - .image = texture->m_Image, + .image = texture.m_Image, .subresourceRange = - { - .aspectMask = vk::ImageAspectFlagBits::eColor, - .baseMipLevel = 0, - .levelCount = texture->m_MipLevels, - .baseArrayLayer = 0, - .layerCount = 1, - }, + { + .aspectMask = vk::ImageAspectFlagBits::eColor, + .baseMipLevel = 0, + .levelCount = texture.GetMipLevels(), + .baseArrayLayer = 0, + .layerCount = 1, + }, }; vk::BufferImageCopy imageCopy = { @@ -115,29 +117,31 @@ ModelLoader::LoadImage(vk::CommandBuffer commandBuffer, Texture *texture, Stagin .bufferRowLength = Cast(image->width), .bufferImageHeight = Cast(image->height), .imageSubresource = - { - .aspectMask = vk::ImageAspectFlagBits::eColor, - .mipLevel = 0, - .baseArrayLayer = 0, - .layerCount = 1, - }, + { + .aspectMask = vk::ImageAspectFlagBits::eColor, + .mipLevel = 0, + .baseArrayLayer = 0, + .layerCount = 1, + }, .imageOffset = {}, - .imageExtent = texture->m_Extent, + .imageExtent = texture.m_Extent, }; commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, 0, nullptr, 0, nullptr, 1, &imageStartBarrier); - commandBuffer.copyBufferToImage(stagingBuffer->m_Buffer, texture->m_Image, vk::ImageLayout::eTransferDstOptimal, 1, + commandBuffer.copyBufferToImage(stagingBuffer->m_Buffer, texture.m_Image, vk::ImageLayout::eTransferDstOptimal, 1, &imageCopy); commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer, {}, 0, nullptr, 0, nullptr, 1, &nextMipBarrier); - auto calcNextMip = [](i32 prev) { return eastl::max(prev / 2, 1); }; + auto calcNextMip = [](i32 prev) { + return eastl::max(prev / 2, 1); + }; - i32 prevMipWidth = Cast(texture->m_Extent.width); - i32 prevMipHeight = Cast(texture->m_Extent.height); + i32 prevMipWidth = Cast(texture.m_Extent.width); + i32 prevMipHeight = Cast(texture.m_Extent.height); - u32 maxPrevMip = texture->m_MipLevels - 1; + u32 maxPrevMip = texture.GetMipLevels() - 1; for (u32 prevMipLevel = 0; prevMipLevel < maxPrevMip; ++prevMipLevel) { i32 currentMipWidth = calcNextMip(prevMipWidth); @@ -146,33 +150,31 @@ ModelLoader::LoadImage(vk::CommandBuffer commandBuffer, Texture *texture, Stagin vk::ImageBlit blitRegion = { .srcSubresource = - { - .aspectMask = vk::ImageAspectFlagBits::eColor, - .mipLevel = prevMipLevel, - .baseArrayLayer = 0, - .layerCount = 1, - }, - .srcOffsets = - std::array{ - vk::Offset3D{0, 0, 0}, - vk::Offset3D{prevMipWidth, prevMipHeight, 1}, - }, + { + .aspectMask = vk::ImageAspectFlagBits::eColor, + .mipLevel = prevMipLevel, + .baseArrayLayer = 0, + .layerCount = 1, + }, + .srcOffsets = std::array{ + vk::Offset3D{0, 0, 0}, + vk::Offset3D{prevMipWidth, prevMipHeight, 1}, + }, .dstSubresource = - { - .aspectMask = vk::ImageAspectFlagBits::eColor, - .mipLevel = currentMipLevel, - .baseArrayLayer = 0, - .layerCount = 1, - }, - .dstOffsets = - std::array{ - vk::Offset3D{0, 0, 0}, - vk::Offset3D{currentMipWidth, currentMipHeight, 1}, - }, + { + .aspectMask = vk::ImageAspectFlagBits::eColor, + .mipLevel = currentMipLevel, + .baseArrayLayer = 0, + .layerCount = 1, + }, + .dstOffsets = std::array{ + vk::Offset3D{0, 0, 0}, + vk::Offset3D{currentMipWidth, currentMipHeight, 1}, + }, }; nextMipBarrier.subresourceRange.baseMipLevel = currentMipLevel; - commandBuffer.blitImage(texture->m_Image, vk::ImageLayout::eTransferSrcOptimal, texture->m_Image, + commandBuffer.blitImage(texture.m_Image, vk::ImageLayout::eTransferSrcOptimal, texture.m_Image, vk::ImageLayout::eTransferDstOptimal, 1, &blitRegion, vk::Filter::eLinear); commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer, {}, 0, nullptr, 0, nullptr, 1, &nextMipBarrier); @@ -184,7 +186,7 @@ ModelLoader::LoadImage(vk::CommandBuffer commandBuffer, Texture *texture, Stagin commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {}, 0, nullptr, 0, nullptr, 1, &imageReadyBarrier); - return m_ResourceManager->Commit(texture); + return m_ResourceManager->Commit(&texture); } Model @@ -225,7 +227,6 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched) } eastl::vector stagingBuffers; - eastl::vector textures; eastl::vector textureHandles; if (!model.images.empty()) @@ -233,15 +234,13 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched) u32 numImages = Cast(model.images.size()); stagingBuffers.resize(numImages); - textures.resize(numImages); textureHandles.resize(numImages); auto stagingPtr = stagingBuffers.data(); - auto texturePtr = textures.data(); auto imagePtr = model.images.data(); for (TextureHandle &handle : textureHandles) { - handle = LoadImage(m_CommandBuffer, texturePtr++, stagingPtr++, imagePtr++); + handle = LoadImage(m_CommandBuffer, stagingPtr++, imagePtr++); } } @@ -400,7 +399,7 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched) texCoord0.reserve(vertexPositions.size()); assert(uvAccessor->type == TINYGLTF_TYPE_VEC2 && - uvAccessor->componentType == TINYGLTF_COMPONENT_TYPE_FLOAT); + uvAccessor->componentType == TINYGLTF_COMPONENT_TYPE_FLOAT); { vec2 *data = Recast(uvBuffer->data.data() + byteOffset); texCoord0.insert(texCoord0.end(), data, data + vertexCount); @@ -466,6 +465,7 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched) } } +#pragma region Staging / Transfer / Uploads StorageBuffer positionBuffer; positionBuffer.Init(pDevice, vertexPositions.size() * sizeof vertexPositions[0], false); BufferHandle positionBufferHandle = m_ResourceManager->Commit(&positionBuffer); @@ -523,6 +523,8 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched) m_CommandBuffer.copyBuffer(indexStaging.m_Buffer, indexBuffer.m_Buffer, 1, &bufferCopy); } +#pragma endregion + AbortIfFailed(m_CommandBuffer.end()); vk::SubmitInfo submitInfo = { @@ -547,47 +549,34 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched) buffer.Destroy(pDevice); } - return Model{m_ResourceManager, std::move(textures), std::move(textureHandles), materialsBuffer, - materialsHandle, positionBuffer, positionBufferHandle, normalBuffer, - normalBufferHandle, texCoord0Buffer, texCoord0BufferHandle, indexBuffer, - meshPrimitives}; + return Model{m_ResourceManager, std::move(textureHandles), + materialsHandle, positionBufferHandle, normalBufferHandle, + texCoord0BufferHandle, indexBuffer, meshPrimitives}; } -Model::Model(RenderResourceManager *resourceManager, eastl::vector &&textures, - eastl::vector &&textureHandles, const StorageBuffer &materialsBuffer, - BufferHandle materialsHandle, const StorageBuffer &vertexPosBuffer, BufferHandle vertexPosHandle, - const StorageBuffer &normalBuffer, BufferHandle normalHandle, const StorageBuffer &uv0Buffer, +Model::Model(GpuResourceManager *resourceManager, eastl::vector &&textureHandles, + BufferHandle materialsHandle, BufferHandle vertexPosHandle, BufferHandle normalHandle, BufferHandle uv0Handle, const IndexBuffer &indexBuffer, const eastl::vector &meshPrimitives) : m_ResourceManager(resourceManager) - , m_Textures(textures) - , m_TextureHandles(textureHandles) - , m_MaterialsBuffer(materialsBuffer) - , m_MaterialsHandle(materialsHandle) - , m_VertexPositions(vertexPosBuffer) - , m_VertexPositionHandle(vertexPosHandle) - , m_NormalVectors(normalBuffer) - , m_NormalHandle(normalHandle) - , m_TexCoord0(uv0Buffer) - , m_TexCoord0Handle(uv0Handle) - , m_IndexBuffer(indexBuffer) - , m_MeshPrimitives(meshPrimitives) + , m_TextureHandles(std::move(textureHandles)) + , m_MaterialsHandle(materialsHandle) + , m_VertexPositionHandle(vertexPosHandle) + , m_NormalHandle(normalHandle) + , m_TexCoord0Handle(uv0Handle) + , m_IndexBuffer(indexBuffer) + , m_MeshPrimitives(meshPrimitives) { } Model::Model(Model &&other) noexcept : m_ResourceManager(Take(other.m_ResourceManager)) - , m_Textures(std::move(other.m_Textures)) - , m_TextureHandles(std::move(other.m_TextureHandles)) - , m_MaterialsBuffer(other.m_MaterialsBuffer) - , m_MaterialsHandle(other.m_MaterialsHandle) - , m_VertexPositions(other.m_VertexPositions) - , m_VertexPositionHandle(other.m_VertexPositionHandle) - , m_NormalVectors(other.m_NormalVectors) - , m_NormalHandle(other.m_NormalHandle) - , m_TexCoord0(other.m_TexCoord0) - , m_TexCoord0Handle(other.m_TexCoord0Handle) - , m_IndexBuffer(other.m_IndexBuffer) - , m_MeshPrimitives(std::move(other.m_MeshPrimitives)) + , m_TextureHandles(std::move(other.m_TextureHandles)) + , m_MaterialsHandle(other.m_MaterialsHandle) + , m_VertexPositionHandle(other.m_VertexPositionHandle) + , m_NormalHandle(other.m_NormalHandle) + , m_TexCoord0Handle(other.m_TexCoord0Handle) + , m_IndexBuffer(other.m_IndexBuffer) + , m_MeshPrimitives(std::move(other.m_MeshPrimitives)) { } @@ -597,15 +586,10 @@ Model::operator=(Model &&other) noexcept if (this == &other) return *this; m_ResourceManager = Take(other.m_ResourceManager); - m_Textures = std::move(other.m_Textures); m_TextureHandles = std::move(other.m_TextureHandles); - m_MaterialsBuffer = other.m_MaterialsBuffer; m_MaterialsHandle = other.m_MaterialsHandle; - m_VertexPositions = other.m_VertexPositions; m_VertexPositionHandle = other.m_VertexPositionHandle; - m_NormalVectors = other.m_NormalVectors; m_NormalHandle = other.m_NormalHandle; - m_TexCoord0 = other.m_TexCoord0; m_TexCoord0Handle = other.m_TexCoord0Handle; m_IndexBuffer = other.m_IndexBuffer; m_MeshPrimitives = std::move(other.m_MeshPrimitives); @@ -617,11 +601,7 @@ Model::~Model() if (!m_ResourceManager) return; - m_VertexPositions.Destroy(m_ResourceManager->m_Device); m_IndexBuffer.Destroy(m_ResourceManager->m_Device); - m_NormalVectors.Destroy(m_ResourceManager->m_Device); - m_TexCoord0.Destroy(m_ResourceManager->m_Device); - m_ResourceManager->Release(m_VertexPositionHandle); m_ResourceManager->Release(m_NormalHandle); m_ResourceManager->Release(m_TexCoord0Handle); @@ -630,19 +610,14 @@ Model::~Model() m_ResourceManager->Release(handle); } m_ResourceManager->Release(m_MaterialsHandle); - for (Texture &texture : m_Textures) - { - texture.Destroy(m_ResourceManager->m_Device); - } - m_MaterialsBuffer.Destroy(m_ResourceManager->m_Device); } -ModelLoader::ModelLoader(RenderResourceManager *resourceManager, vk::Queue transferQueue, u32 transferQueueIndex, +ModelLoader::ModelLoader(GpuResourceManager *resourceManager, vk::Queue transferQueue, u32 transferQueueIndex, u32 graphicsQueueIndex) : m_ResourceManager(resourceManager) - , m_TransferQueue(transferQueue) - , m_TransferQueueIndex(transferQueueIndex) - , m_GraphicsQueueIndex(graphicsQueueIndex) + , m_TransferQueue(transferQueue) + , m_TransferQueueIndex(transferQueueIndex) + , m_GraphicsQueueIndex(graphicsQueueIndex) { const Device *pDevice = resourceManager->m_Device; const vk::CommandPoolCreateInfo poolCreateInfo = { diff --git a/samples/03_model_render/model_loader.h b/samples/03_model_render/model_loader.h index bfaea3c..9437927 100644 --- a/samples/03_model_render/model_loader.h +++ b/samples/03_model_render/model_loader.h @@ -22,7 +22,7 @@ constexpr auto GLTF_BINARY_FILE_EXTENSION = ".glb"; struct MeshPrimitive { u32 m_VertexOffset; - i32 m_NormalOffset; // <0 for invalid + i32 m_NormalOffset; // <0 for invalid i32 m_TexCoord0Offset; // <0 for invalid u32 m_FirstIndex; u32 m_IndexCount; @@ -44,31 +44,21 @@ struct Material struct Model { - RenderResourceManager *m_ResourceManager; + GpuResourceManager *m_ResourceManager; - eastl::vector m_Textures; eastl::vector m_TextureHandles; - StorageBuffer m_MaterialsBuffer; BufferHandle m_MaterialsHandle; - - StorageBuffer m_VertexPositions; BufferHandle m_VertexPositionHandle; - - StorageBuffer m_NormalVectors; BufferHandle m_NormalHandle; - - StorageBuffer m_TexCoord0; BufferHandle m_TexCoord0Handle; IndexBuffer m_IndexBuffer; eastl::vector m_MeshPrimitives; - Model(RenderResourceManager *resourceManager, eastl::vector &&textures, - eastl::vector &&textureHandles, const StorageBuffer &materialsBuffer, - BufferHandle materialsHandle, const StorageBuffer &vertexPosBuffer, BufferHandle vertexPosHandle, - const StorageBuffer &normalBuffer, BufferHandle normalHandle, const StorageBuffer &uv0Buffer, - BufferHandle uv0Handle, const IndexBuffer &indexBuffer, const eastl::vector &meshPrimitives); + Model(GpuResourceManager *resourceManager, eastl::vector &&textureHandles, + BufferHandle materialsHandle, BufferHandle vertexPosHandle, BufferHandle normalHandle, BufferHandle uv0Handle, + const IndexBuffer &indexBuffer, const eastl::vector &meshPrimitives); Model(Model &&other) noexcept; Model &operator=(Model &&other) noexcept; @@ -80,18 +70,18 @@ struct Model struct ModelLoader { - RenderResourceManager *const m_ResourceManager; + GpuResourceManager *const m_ResourceManager; vk::CommandPool m_CommandPool; vk::CommandBuffer m_CommandBuffer; vk::Queue m_TransferQueue; u32 m_TransferQueueIndex; u32 m_GraphicsQueueIndex; - ModelLoader(RenderResourceManager *resourceManager, vk::Queue transferQueue, u32 transferQueueIndex, + ModelLoader(GpuResourceManager *resourceManager, vk::Queue transferQueue, u32 transferQueueIndex, u32 graphicsQueueIndex); ~ModelLoader(); - TextureHandle LoadImage(vk::CommandBuffer commandBuffer, Texture *texture, StagingBuffer *stagingBuffer, + TextureHandle LoadImage(vk::CommandBuffer commandBuffer, StagingBuffer *stagingBuffer, tinygltf::Image *image) const; Model LoadModel(cstr path, cstr name = nullptr, bool batched = false); diff --git a/samples/03_model_render/model_render.cpp b/samples/03_model_render/model_render.cpp index c61f51b..b2d2b9e 100644 --- a/samples/03_model_render/model_render.cpp +++ b/samples/03_model_render/model_render.cpp @@ -85,7 +85,7 @@ main(int, char **) Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"}; vk::Queue commandQueue = device.GetQueue(queueAllocation.m_Family, 0); Swapchain swapchain = {&window, &device, "Primary Chain"}; - RenderResourceManager resourceManager = {&device, 1000}; + GpuResourceManager resourceManager = {&device, 1000}; ModelLoader modelLoader = {&resourceManager, commandQueue, queueAllocation.m_Family, queueAllocation.m_Family}; diff --git a/samples/03_model_render/pipeline_utils.cpp b/samples/03_model_render/pipeline_utils.cpp index b19700b..0558181 100644 --- a/samples/03_model_render/pipeline_utils.cpp +++ b/samples/03_model_render/pipeline_utils.cpp @@ -13,7 +13,7 @@ #include Pipeline -CreatePipeline(const Device *device, const Swapchain *swapchain, const RenderResourceManager *resourceManager) +CreatePipeline(const Device *device, const Swapchain *swapchain, const GpuResourceManager *resourceManager) { // Pipeline Setup auto vertexShaderModule = CreateShader(device, VERTEX_SHADER_FILE); diff --git a/samples/03_model_render/pipeline_utils.h b/samples/03_model_render/pipeline_utils.h index f8c6550..c4f9161 100644 --- a/samples/03_model_render/pipeline_utils.h +++ b/samples/03_model_render/pipeline_utils.h @@ -8,7 +8,7 @@ #include "global.h" #include "pipeline.h" -struct RenderResourceManager; +struct GpuResourceManager; struct Swapchain; struct Device; @@ -22,4 +22,4 @@ struct Vertex }; vk::ShaderModule CreateShader(const Device *device, cstr shaderFile); -Pipeline CreatePipeline(const Device *device, const Swapchain *swapchain, const RenderResourceManager *resourceManager); +Pipeline CreatePipeline(const Device *device, const Swapchain *swapchain, const GpuResourceManager *resourceManager); diff --git a/samples/03_model_render/render_resource_manager.cpp b/samples/03_model_render/render_resource_manager.cpp index 7053d35..62e0418 100644 --- a/samples/03_model_render/render_resource_manager.cpp +++ b/samples/03_model_render/render_resource_manager.cpp @@ -12,25 +12,184 @@ #include -RenderResourceManager::WriteInfo::WriteInfo(vk::DescriptorBufferInfo info) +void +TextureManager::Init(const u32 maxCapacity) +{ + m_MaxCapacity = maxCapacity; + m_FreeHead = GpuResourceHandle::INVALID_HANDLE; +} + +TextureHandle +TextureManager::Commit(Texture *texture) +{ + ERROR_IF(!texture->IsValid() || !texture->IsOwned(), "Buffer must be valid and owned for commital") + THEN_ABORT(-1); + + if (m_FreeHead != GpuResourceHandle::INVALID_HANDLE) + { + const u32 index = m_FreeHead; + + Texture *allocatedTexture = &m_Textures[index]; + + assert(!allocatedTexture->IsValid()); + m_FreeHead = *Recast(allocatedTexture); + + // Ensure it is copyable. + static_assert(std::is_trivially_copyable_v); + memcpy(allocatedTexture, texture, sizeof *texture); + + // Take ownership of the buffer. + texture->m_MipLevels_ &= ~Texture::OWNED_BIT; + + return {index}; + } + + const u32 index = Cast(m_Textures.size()); + if (index < m_MaxCapacity) + { + Texture *allocatedTexture = &m_Textures.push_back(); + + // Ensure it is copyable. + static_assert(std::is_trivially_copyable_v); + memcpy(allocatedTexture, texture, sizeof *texture); + + texture->m_MipLevels_ &= ~Texture::OWNED_BIT; + + return {index}; + } + + ERROR("Out of Buffers") THEN_ABORT(-1); +} + +Texture * +TextureManager::Fetch(const TextureHandle handle) +{ + assert(!handle.IsInvalid()); + + return &m_Textures[handle.m_Index]; +} + +void +TextureManager::Release(const Device *device, const TextureHandle handle) +{ + assert(!handle.IsInvalid()); + + Texture *allocatedTexture = &m_Textures[handle.m_Index]; + allocatedTexture->Destroy(device); + + assert(!allocatedTexture->IsValid()); + *Recast(allocatedTexture) = m_FreeHead; + + m_FreeHead = handle.m_Index; +} + +void +TextureManager::Destroy(const Device *device) +{ + for (auto &texture : m_Textures) + { + texture.Destroy(device); + } +} + +void +BufferManager::Init(const u32 maxCapacity) +{ + m_MaxCapacity = maxCapacity; + m_FreeHead = GpuResourceHandle::INVALID_HANDLE; +} + +BufferHandle +BufferManager::Commit(StorageBuffer *buffer) +{ + ERROR_IF(!buffer->IsValid() || !buffer->IsOwned(), "Buffer must be valid and owned for commital") THEN_ABORT(-1); + + if (m_FreeHead != GpuResourceHandle::INVALID_HANDLE) + { + const u32 index = m_FreeHead; + + StorageBuffer *allocatedBuffer = &m_Buffers[index]; + + assert(!allocatedBuffer->IsValid()); + m_FreeHead = *Recast(allocatedBuffer); + + // Ensure it is copyable. + static_assert(std::is_trivially_copyable_v); + memcpy(allocatedBuffer, buffer, sizeof *buffer); + + // Take ownership of the buffer. + buffer->m_Size_ &= ~StorageBuffer::OWNED_BIT; + + return {index}; + } + + const u32 index = Cast(m_Buffers.size()); + if (index < m_MaxCapacity) + { + StorageBuffer *allocatedBuffer = &m_Buffers.push_back(); + + // Ensure it is copyable. + static_assert(std::is_trivially_copyable_v); + memcpy(allocatedBuffer, buffer, sizeof *buffer); + + buffer->m_Size_ &= ~StorageBuffer::OWNED_BIT; + + return {index}; + } + + ERROR("Out of Buffers") THEN_ABORT(-1); +} + +StorageBuffer * +BufferManager::Fetch(const BufferHandle handle) +{ + assert(!handle.IsInvalid()); + + return &m_Buffers[handle.m_Index]; +} + +void +BufferManager::Release(const Device *device, const BufferHandle handle) +{ + assert(!handle.IsInvalid()); + + StorageBuffer *allocatedBuffer = &m_Buffers[handle.m_Index]; + allocatedBuffer->Destroy(device); + + assert(!allocatedBuffer->IsValid()); + *Recast(allocatedBuffer) = m_FreeHead; + + m_FreeHead = handle.m_Index; +} + +void +BufferManager::Destroy(const Device *device) +{ + for (auto& buffer : m_Buffers) + { + buffer.Destroy(device); + } +} + +GpuResourceManager::WriteInfo::WriteInfo(vk::DescriptorBufferInfo info) : uBufferInfo(info) { } -RenderResourceManager::WriteInfo::WriteInfo(vk::DescriptorImageInfo info) +GpuResourceManager::WriteInfo::WriteInfo(vk::DescriptorImageInfo info) : uImageInfo(info) { } -RenderResourceManager::WriteInfo::WriteInfo(vk::BufferView info) +GpuResourceManager::WriteInfo::WriteInfo(vk::BufferView info) : uBufferView(info) { } BufferHandle -RenderResourceManager::Commit(const StorageBuffer *storageBuffer) +GpuResourceManager::Commit(StorageBuffer *storageBuffer) { - const u32 handle = m_BufferFreeList.Alloc(); + const BufferHandle handle = m_BufferManager.Commit(storageBuffer); m_WriteInfos.emplace_back(vk::DescriptorBufferInfo{ .buffer = storageBuffer->m_Buffer, @@ -41,19 +200,23 @@ RenderResourceManager::Commit(const StorageBuffer *storageBuffer) m_Writes.push_back({ .dstSet = m_DescriptorSet, .dstBinding = BUFFER_BINDING_INDEX, - .dstArrayElement = handle, + .dstArrayElement = handle.m_Index, .descriptorCount = 1, .descriptorType = vk::DescriptorType::eStorageBuffer, .pBufferInfo = &m_WriteInfos.back().uBufferInfo, }); - m_WriteOwner.emplace_back(HandleType::eBuffer, handle); + m_WriteOwner.emplace_back(HandleType::eBuffer, handle.m_Index); - return {handle}; +#if !defined(NDEBUG) + ++m_CommitedBufferCount; +#endif + + return handle; } void -RenderResourceManager::EraseWrites(u32 handleIndex, HandleType handleType) +GpuResourceManager::EraseWrites(u32 handleIndex, HandleType handleType) { auto writeIter = m_Writes.begin(); auto ownerIter = m_WriteOwner.begin(); @@ -76,31 +239,39 @@ RenderResourceManager::EraseWrites(u32 handleIndex, HandleType handleType) } void -RenderResourceManager::Release(BufferHandle handle) +GpuResourceManager::Release(BufferHandle handle) { if (handle.IsInvalid()) return; EraseWrites(handle.m_Index, HandleType::eBuffer); - m_BufferFreeList.Free(handle.m_Index); + m_BufferManager.Release(m_Device, handle); + +#if !defined(NDEBUG) + --m_CommitedBufferCount; +#endif } void -RenderResourceManager::Release(TextureHandle handle) +GpuResourceManager::Release(TextureHandle handle) { if (handle.IsInvalid()) return; EraseWrites(handle.m_Index, HandleType::eTexture); - m_TextureFreeList.Free(handle.m_Index); + m_TextureManager.Release(m_Device, handle); + +#if !defined(NDEBUG) + --m_CommitedTextureCount; +#endif } TextureHandle -RenderResourceManager::Commit(const Texture *texture) +GpuResourceManager::Commit(Texture* texture) { - const u32 handle = m_TextureFreeList.Alloc(); + TextureHandle handle = m_TextureManager.Commit(texture); m_WriteInfos.emplace_back(vk::DescriptorImageInfo{ .sampler = nullptr, @@ -111,19 +282,23 @@ RenderResourceManager::Commit(const Texture *texture) m_Writes.push_back({ .dstSet = m_DescriptorSet, .dstBinding = TEXTURE_BINDING_INDEX, - .dstArrayElement = handle, + .dstArrayElement = handle.m_Index, .descriptorCount = 1, .descriptorType = vk::DescriptorType::eCombinedImageSampler, .pImageInfo = &m_WriteInfos.back().uImageInfo, }); - m_WriteOwner.emplace_back(HandleType::eBuffer, handle); + m_WriteOwner.emplace_back(HandleType::eBuffer, handle.m_Index); + +#if !defined(NDEBUG) + ++m_CommitedTextureCount; +#endif return {handle}; } void -RenderResourceManager::Update() +GpuResourceManager::Update() { if (m_Writes.empty() || m_WriteInfos.empty()) return; @@ -135,7 +310,7 @@ RenderResourceManager::Update() m_WriteOwner.clear(); } -RenderResourceManager::RenderResourceManager(const Device *device, u16 maxSize) +GpuResourceManager::GpuResourceManager(const Device *device, u16 maxSize) : m_Device(device) { vk::PhysicalDeviceProperties properties; @@ -166,8 +341,8 @@ RenderResourceManager::RenderResourceManager(const Device *device, u16 maxSize) INFO("Max Buffer Count: {}", buffersCount); INFO("Max Texture Count: {}", texturesCount); - m_BufferFreeList.Init(buffersCount); - m_TextureFreeList.Init(texturesCount); + m_BufferManager.Init(buffersCount); + m_TextureManager.Init(texturesCount); eastl::array poolSizes = { vk::DescriptorPoolSize{ @@ -225,9 +400,54 @@ RenderResourceManager::RenderResourceManager(const Device *device, u16 maxSize) m_Device->SetName(m_DescriptorSet, "Bindless Set"); } -RenderResourceManager::~RenderResourceManager() +GpuResourceManager::~GpuResourceManager() { +#if !defined(NDEBUG) + WARN_IF(m_CommitedBufferCount > 0 || m_CommitedTextureCount > 0, "Resources alive: SSBO = {}, Textures = {}", + m_CommitedBufferCount, m_CommitedTextureCount); +#endif + + m_BufferManager.Destroy(m_Device); m_Device->m_Device.destroy(m_Sampler, nullptr); m_Device->m_Device.destroy(m_DescriptorPool, nullptr); m_Device->m_Device.destroy(m_SetLayout, nullptr); +} + +GpuResourceManager::GpuResourceManager(GpuResourceManager &&other) noexcept + : m_WriteInfos(std::move(other.m_WriteInfos)), + m_Writes(std::move(other.m_Writes)), + m_WriteOwner(std::move(other.m_WriteOwner)), + m_Sampler(other.m_Sampler), + m_BufferManager(std::move(other.m_BufferManager)), + m_TextureManager(std::move(other.m_TextureManager)), + m_Device(Take(other.m_Device)), + m_DescriptorPool(other.m_DescriptorPool), + m_SetLayout(other.m_SetLayout), + m_DescriptorSet(other.m_DescriptorSet), + m_CommitedBufferCount(other.m_CommitedBufferCount), + m_CommitedTextureCount(other.m_CommitedTextureCount) +{ + assert(!other.m_Device); +} + +GpuResourceManager & +GpuResourceManager::operator=(GpuResourceManager &&other) noexcept +{ + if (this == &other) + return *this; + m_WriteInfos = std::move(other.m_WriteInfos); + m_Writes = std::move(other.m_Writes); + m_WriteOwner = std::move(other.m_WriteOwner); + m_Sampler = other.m_Sampler; + m_BufferManager = std::move(other.m_BufferManager); + m_TextureManager = std::move(other.m_TextureManager); + m_Device = Take(other.m_Device); // Ensure taken. + m_DescriptorPool = other.m_DescriptorPool; + m_SetLayout = other.m_SetLayout; + m_DescriptorSet = other.m_DescriptorSet; + m_CommitedBufferCount = other.m_CommitedBufferCount; + m_CommitedTextureCount = other.m_CommitedTextureCount; + + assert(!other.m_Device); + return *this; } \ No newline at end of file diff --git a/samples/03_model_render/render_resource_manager.h b/samples/03_model_render/render_resource_manager.h index 94bf3a1..d88d6c1 100644 --- a/samples/03_model_render/render_resource_manager.h +++ b/samples/03_model_render/render_resource_manager.h @@ -5,8 +5,9 @@ #pragma once -#include "buffer.h" #include "global.h" +#include "buffer.h" +#include "image.h" #include #include @@ -16,7 +17,7 @@ struct Device; struct Texture; struct UniformStorageBuffer; -struct RenderResourceManager; +struct GpuResourceManager; struct GpuResourceHandle { @@ -38,54 +39,46 @@ struct TextureHandle : GpuResourceHandle { }; -struct FreeList +struct TextureManager { - eastl::stack> m_List; - u32 m_MaxVisited = 0; - u32 m_MaxCapacity = 16; + eastl::vector m_Textures; + u32 m_MaxCapacity; + u32 m_FreeHead; void - Init(u32 maxCapacity) - { - // MaxValue is 'invalid-handle' so you can't use it as a handle. - assert(maxCapacity < GpuResourceHandle::INVALID_HANDLE); - m_MaxCapacity = maxCapacity; - } - - [[nodiscard]] u32 - Alloc() - { - if (!m_List.empty()) - { - const u32 value = m_List.top(); - m_List.pop(); - return value; - } - if (m_MaxVisited < m_MaxCapacity) - { - return m_MaxVisited++; - } - ERROR("Out of Handles.") THEN_ABORT(-1); - } - - void - Free(u32 index) - { - WARN_IF(index >= m_MaxCapacity, "Trying to free an out-of-bounds index."); - - if (index < m_MaxCapacity) - m_List.push(index); - } + Init(u32 maxCapacity); + TextureHandle Commit(Texture *texture); + Texture *Fetch(TextureHandle handle); + void Release(const Device *device, TextureHandle handle); + void Destroy(const Device *device); }; -struct RenderResourceManager +struct BufferManager { - private: - union WriteInfo { + eastl::vector m_Buffers; + u32 m_MaxCapacity; + u32 m_FreeHead; + + void Init(u32 maxCapacity); + BufferHandle Commit(StorageBuffer *buffer); + StorageBuffer *Fetch(BufferHandle handle); + void Release(const Device *device, BufferHandle handle); + void Destroy(const Device *device); +}; + +struct GpuResourceManager +{ +private: + union WriteInfo + { vk::DescriptorBufferInfo uBufferInfo; vk::DescriptorImageInfo uImageInfo; vk::BufferView uBufferView; + WriteInfo() + { + } + explicit WriteInfo(vk::DescriptorBufferInfo info); explicit WriteInfo(vk::DescriptorImageInfo info); explicit WriteInfo(vk::BufferView info); @@ -105,12 +98,13 @@ struct RenderResourceManager vk::Sampler m_Sampler; - FreeList m_BufferFreeList; - FreeList m_TextureFreeList; + //FreeList m_BufferFreeList; + BufferManager m_BufferManager; + TextureManager m_TextureManager; void EraseWrites(u32 handleIndex, HandleType handleType); - public: +public: const Device *m_Device; constexpr static u32 BUFFER_BINDING_INDEX = 0; @@ -120,16 +114,24 @@ struct RenderResourceManager vk::DescriptorSetLayout m_SetLayout; vk::DescriptorSet m_DescriptorSet; - BufferHandle Commit(const StorageBuffer *storageBuffer); + BufferHandle Commit(StorageBuffer *storageBuffer); void Release(BufferHandle handle); - TextureHandle Commit(const Texture *texture); + TextureHandle Commit(Texture *texture); void Release(TextureHandle handle); void Update(); // Ctor/Dtor - RenderResourceManager(const Device *device, u16 maxSize); - ~RenderResourceManager(); + GpuResourceManager(const Device *device, u16 maxSize); + ~GpuResourceManager(); - DISALLOW_COPY_AND_ASSIGN(RenderResourceManager); + GpuResourceManager(GpuResourceManager &&other) noexcept; + GpuResourceManager &operator=(GpuResourceManager &&other) noexcept; + +#if !defined(NDEBUG) + usize m_CommitedBufferCount = 0; + usize m_CommitedTextureCount = 0; +#endif + + DISALLOW_COPY_AND_ASSIGN(GpuResourceManager); }; \ No newline at end of file