Compare commits

...

3 Commits

Author SHA1 Message Date
Anish Bhobe 8ea9cf5bef Fixed node orientations. 2024-07-19 21:14:24 +02:00
Anish Bhobe 6637756fcc Material Alignment and Color0.
Nodes WIP.
2024-07-18 00:07:12 +02:00
Anish Bhobe 912e197614 Gpu resource manager actually manages resource. 2024-07-17 22:16:05 +02:00
18 changed files with 775 additions and 292 deletions

View File

@ -11,11 +11,11 @@
void void
Buffer::Destroy(const Device *device) Buffer::Destroy(const Device *device)
{ {
if (!IsValid()) if (!IsValid() || !IsOwned())
return; return;
vmaDestroyBuffer(device->m_Allocator, m_Buffer, m_Allocation); vmaDestroyBuffer(device->m_Allocator, m_Buffer, m_Allocation);
m_Size &= ~VALID_BUFFER_BIT; m_Size_ = 0;
} }
void void
@ -47,7 +47,7 @@ Buffer::Allocate(const Device *device, usize size, vk::BufferUsageFlags bufferUs
bool hostAccessible = Cast<bool>(memoryPropertyFlags & vk::MemoryPropertyFlagBits::eHostVisible); bool hostAccessible = Cast<bool>(memoryPropertyFlags & vk::MemoryPropertyFlagBits::eHostVisible);
m_Buffer = buffer; 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_Allocation = allocation;
m_Mapped = Cast<u8 *>(allocationInfo.pMappedData); m_Mapped = Cast<u8 *>(allocationInfo.pMappedData);

View File

@ -19,23 +19,27 @@ struct Buffer
[[nodiscard]] bool IsHostVisible() const; [[nodiscard]] bool IsHostVisible() const;
[[nodiscard]] bool IsValid() const; [[nodiscard]] bool IsValid() const;
[[nodiscard]] bool IsMapped() const; [[nodiscard]] bool IsMapped() const;
[[nodiscard]] bool IsOwned() const;
void Destroy(const Device *device); void Destroy(const Device *device);
void Write(const Device *device, usize offset, usize size, const void *data); void Write(const Device *device, usize offset, usize size, const void *data);
protected:
void Allocate(const Device *device, usize size, vk::BufferUsageFlags bufferUsage, void Allocate(const Device *device, usize size, vk::BufferUsageFlags bufferUsage,
VmaAllocationCreateFlags allocationFlags, VmaMemoryUsage memoryUsage, cstr name); VmaAllocationCreateFlags allocationFlags, VmaMemoryUsage memoryUsage, cstr name);
// Buffer size is used intrusively by the Render Resource Manager // Buffer.size is used for bookkeeping
// If the buffer is Invalid, the remaining data in Buffer is used for other tasks. // If the buffer is Invalid, the remaining data in Buffer is used intrusively by `GpuResourceManager`.
usize m_Size = 0; usize m_Size_ = 0;
constexpr static usize VALID_BUFFER_BIT = Cast<usize>(1llu << 63); constexpr static usize VALID_BUFFER_BIT = Cast<usize>(1llu << 63);
constexpr static usize HOST_ACCESSIBLE_BIT = 1llu << 62; 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 struct UniformBuffer : Buffer
{ {
void Init(const Device *device, usize size, cstr name = nullptr); void Init(const Device *device, usize size, cstr name = nullptr);
@ -66,19 +70,19 @@ struct StagingBuffer : Buffer
inline usize inline usize
Buffer::GetSize() const Buffer::GetSize() const
{ {
return m_Size & SIZE_MASK; return m_Size_ & SIZE_MASK;
} }
inline bool inline bool
Buffer::IsHostVisible() const Buffer::IsHostVisible() const
{ {
return m_Size & HOST_ACCESSIBLE_BIT; return m_Size_ & HOST_ACCESSIBLE_BIT;
} }
inline bool inline bool
Buffer::IsValid() const Buffer::IsValid() const
{ {
return m_Size & VALID_BUFFER_BIT; return m_Size_ & VALID_BUFFER_BIT;
} }
inline bool inline bool
@ -86,3 +90,9 @@ Buffer::IsMapped() const
{ {
return m_Mapped; return m_Mapped;
} }
inline bool
Buffer::IsOwned() const
{
return m_Size_ & OWNED_BIT;
}

View File

@ -7,6 +7,7 @@
#define GLM_FORCE_RADIANS #define GLM_FORCE_RADIANS
#define GLM_FORCE_DEPTH_ZERO_TO_ONE #define GLM_FORCE_DEPTH_ZERO_TO_ONE
#define GLM_FORCE_QUATERNIONS_XYZW
#define GLFW_INCLUDE_VULKAN #define GLFW_INCLUDE_VULKAN
#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1 #define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1

View File

@ -87,6 +87,7 @@ using glm::ivec4;
using glm::vec2; using glm::vec2;
using glm::vec3; using glm::vec3;
using glm::vec4; using glm::vec4;
using glm::quat;
using glm::mat2; using glm::mat2;
using glm::mat3; using glm::mat3;

View File

@ -10,12 +10,12 @@
void void
Image::Destroy(const Device *device) Image::Destroy(const Device *device)
{ {
if (!IsValid()) if (!IsValid() || !IsOwned())
return; return;
device->m_Device.destroy(m_View, nullptr); device->m_Device.destroy(m_View, nullptr);
vmaDestroyImage(device->m_Allocator, m_Image, m_Allocation); vmaDestroyImage(device->m_Allocator, m_Image, m_Allocation);
m_Image = nullptr; m_MipLevels_ = 0;
} }
void void
@ -23,6 +23,7 @@ Texture::Init(const Device *device, const vk::Extent2D extent, vk::Format imageF
const cstr name) const cstr name)
{ {
const u32 mipLevels = isMipmapped ? 1 + Cast<u32>(floor(log2(eastl::max(extent.width, extent.height)))) : 1; const u32 mipLevels = isMipmapped ? 1 + Cast<u32>(floor(log2(eastl::max(extent.width, extent.height)))) : 1;
assert(mipLevels <= MIP_MASK);
auto usage = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst; auto usage = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst;
if (isMipmapped) if (isMipmapped)
@ -75,7 +76,7 @@ Texture::Init(const Device *device, const vk::Extent2D extent, vk::Format imageF
m_View = view; m_View = view;
m_Allocation = allocation; m_Allocation = allocation;
m_Extent = {extent.width, extent.height, 1}; m_Extent = {extent.width, extent.height, 1};
m_MipLevels = Cast<u8>(mipLevels); m_MipLevels_ = mipLevels | OWNED_BIT | VALID_BIT;
device->SetName(m_Image, name); device->SetName(m_Image, name);
} }
@ -129,6 +130,7 @@ DepthImage::Init(const Device *device, vk::Extent2D extent, cstr name)
m_View = view; m_View = view;
m_Allocation = allocation; m_Allocation = allocation;
m_Extent = {extent.width, extent.height, 1}; m_Extent = {extent.width, extent.height, 1};
m_MipLevels_ = 1 | OWNED_BIT | VALID_BIT;
device->SetName(m_Image, name); device->SetName(m_Image, name);
} }

View File

@ -15,11 +15,19 @@ struct Image
vk::ImageView m_View = nullptr; vk::ImageView m_View = nullptr;
VmaAllocation m_Allocation = nullptr; VmaAllocation m_Allocation = nullptr;
vk::Extent3D m_Extent; 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 IsValid() const;
[[nodiscard]] bool IsOwned() const;
[[nodiscard]] u32 GetMipLevels() const;
void Destroy(const Device *device); 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 struct Texture : Image
@ -35,5 +43,17 @@ struct DepthImage : Image
inline bool inline bool
Image::IsValid() const 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;
} }

BIN
samples/03_model_render/model/BoxVertexColors.glb (Stored with Git LFS) Normal file

Binary file not shown.

BIN
samples/03_model_render/model/OrientationTest.glb (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -18,6 +18,7 @@
#include "image.h" #include "image.h"
#include "render_resource_manager.h" #include "render_resource_manager.h"
#include <glm/gtc/type_ptr.hpp>
#include <EASTL/array.h> #include <EASTL/array.h>
vec4 vec4
@ -45,14 +46,16 @@ VectorToVec3(const std::vector<double> &vec)
} }
TextureHandle TextureHandle
ModelLoader::LoadImage(vk::CommandBuffer commandBuffer, Texture *texture, StagingBuffer *stagingBuffer, ModelLoader::LoadImage(vk::CommandBuffer commandBuffer, StagingBuffer *stagingBuffer,
tinygltf::Image *image) const tinygltf::Image *image) const
{ {
assert(image->component == 4); assert(image->component == 4);
Texture texture;
usize byteSize = image->image.size(); usize byteSize = image->image.size();
texture->Init(m_ResourceManager->m_Device, {.width = Cast<u32>(image->width), .height = Cast<u32>(image->height)}, texture.Init(m_ResourceManager->m_Device, {.width = Cast<u32>(image->width), .height = Cast<u32>(image->height)},
vk::Format::eR8G8B8A8Srgb, true, image->name.data()); vk::Format::eR8G8B8A8Srgb, true, image->name.data());
stagingBuffer->Init(m_ResourceManager->m_Device, byteSize); stagingBuffer->Init(m_ResourceManager->m_Device, byteSize);
stagingBuffer->Write(m_ResourceManager->m_Device, 0, byteSize, image->image.data()); stagingBuffer->Write(m_ResourceManager->m_Device, 0, byteSize, image->image.data());
@ -63,15 +66,15 @@ ModelLoader::LoadImage(vk::CommandBuffer commandBuffer, Texture *texture, Stagin
.newLayout = vk::ImageLayout::eTransferDstOptimal, .newLayout = vk::ImageLayout::eTransferDstOptimal,
.srcQueueFamilyIndex = vk::QueueFamilyIgnored, .srcQueueFamilyIndex = vk::QueueFamilyIgnored,
.dstQueueFamilyIndex = vk::QueueFamilyIgnored, .dstQueueFamilyIndex = vk::QueueFamilyIgnored,
.image = texture->m_Image, .image = texture.m_Image,
.subresourceRange = .subresourceRange =
{ {
.aspectMask = vk::ImageAspectFlagBits::eColor, .aspectMask = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0, .baseMipLevel = 0,
.levelCount = texture->m_MipLevels, .levelCount = texture.GetMipLevels(),
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = 1, .layerCount = 1,
}, },
}; };
vk::ImageMemoryBarrier nextMipBarrier = { vk::ImageMemoryBarrier nextMipBarrier = {
@ -81,15 +84,15 @@ ModelLoader::LoadImage(vk::CommandBuffer commandBuffer, Texture *texture, Stagin
.newLayout = vk::ImageLayout::eTransferSrcOptimal, .newLayout = vk::ImageLayout::eTransferSrcOptimal,
.srcQueueFamilyIndex = vk::QueueFamilyIgnored, .srcQueueFamilyIndex = vk::QueueFamilyIgnored,
.dstQueueFamilyIndex = vk::QueueFamilyIgnored, .dstQueueFamilyIndex = vk::QueueFamilyIgnored,
.image = texture->m_Image, .image = texture.m_Image,
.subresourceRange = .subresourceRange =
{ {
.aspectMask = vk::ImageAspectFlagBits::eColor, .aspectMask = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0, .baseMipLevel = 0,
.levelCount = 1, .levelCount = 1,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = 1, .layerCount = 1,
}, },
}; };
vk::ImageMemoryBarrier imageReadyBarrier = { vk::ImageMemoryBarrier imageReadyBarrier = {
@ -99,15 +102,15 @@ ModelLoader::LoadImage(vk::CommandBuffer commandBuffer, Texture *texture, Stagin
.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal, .newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
.srcQueueFamilyIndex = m_TransferQueueIndex, .srcQueueFamilyIndex = m_TransferQueueIndex,
.dstQueueFamilyIndex = m_GraphicsQueueIndex, .dstQueueFamilyIndex = m_GraphicsQueueIndex,
.image = texture->m_Image, .image = texture.m_Image,
.subresourceRange = .subresourceRange =
{ {
.aspectMask = vk::ImageAspectFlagBits::eColor, .aspectMask = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0, .baseMipLevel = 0,
.levelCount = texture->m_MipLevels, .levelCount = texture.GetMipLevels(),
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = 1, .layerCount = 1,
}, },
}; };
vk::BufferImageCopy imageCopy = { vk::BufferImageCopy imageCopy = {
@ -115,29 +118,31 @@ ModelLoader::LoadImage(vk::CommandBuffer commandBuffer, Texture *texture, Stagin
.bufferRowLength = Cast<u32>(image->width), .bufferRowLength = Cast<u32>(image->width),
.bufferImageHeight = Cast<u32>(image->height), .bufferImageHeight = Cast<u32>(image->height),
.imageSubresource = .imageSubresource =
{ {
.aspectMask = vk::ImageAspectFlagBits::eColor, .aspectMask = vk::ImageAspectFlagBits::eColor,
.mipLevel = 0, .mipLevel = 0,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = 1, .layerCount = 1,
}, },
.imageOffset = {}, .imageOffset = {},
.imageExtent = texture->m_Extent, .imageExtent = texture.m_Extent,
}; };
commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, 0, commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, 0,
nullptr, 0, nullptr, 1, &imageStartBarrier); 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); &imageCopy);
commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer, {}, 0, commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer, {}, 0,
nullptr, 0, nullptr, 1, &nextMipBarrier); 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<i32>(texture->m_Extent.width); i32 prevMipWidth = Cast<i32>(texture.m_Extent.width);
i32 prevMipHeight = Cast<i32>(texture->m_Extent.height); i32 prevMipHeight = Cast<i32>(texture.m_Extent.height);
u32 maxPrevMip = texture->m_MipLevels - 1; u32 maxPrevMip = texture.GetMipLevels() - 1;
for (u32 prevMipLevel = 0; prevMipLevel < maxPrevMip; ++prevMipLevel) for (u32 prevMipLevel = 0; prevMipLevel < maxPrevMip; ++prevMipLevel)
{ {
i32 currentMipWidth = calcNextMip(prevMipWidth); i32 currentMipWidth = calcNextMip(prevMipWidth);
@ -146,33 +151,31 @@ ModelLoader::LoadImage(vk::CommandBuffer commandBuffer, Texture *texture, Stagin
vk::ImageBlit blitRegion = { vk::ImageBlit blitRegion = {
.srcSubresource = .srcSubresource =
{ {
.aspectMask = vk::ImageAspectFlagBits::eColor, .aspectMask = vk::ImageAspectFlagBits::eColor,
.mipLevel = prevMipLevel, .mipLevel = prevMipLevel,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = 1, .layerCount = 1,
}, },
.srcOffsets = .srcOffsets = std::array{
std::array{ vk::Offset3D{0, 0, 0},
vk::Offset3D{0, 0, 0}, vk::Offset3D{prevMipWidth, prevMipHeight, 1},
vk::Offset3D{prevMipWidth, prevMipHeight, 1}, },
},
.dstSubresource = .dstSubresource =
{ {
.aspectMask = vk::ImageAspectFlagBits::eColor, .aspectMask = vk::ImageAspectFlagBits::eColor,
.mipLevel = currentMipLevel, .mipLevel = currentMipLevel,
.baseArrayLayer = 0, .baseArrayLayer = 0,
.layerCount = 1, .layerCount = 1,
}, },
.dstOffsets = .dstOffsets = std::array{
std::array{ vk::Offset3D{0, 0, 0},
vk::Offset3D{0, 0, 0}, vk::Offset3D{currentMipWidth, currentMipHeight, 1},
vk::Offset3D{currentMipWidth, currentMipHeight, 1}, },
},
}; };
nextMipBarrier.subresourceRange.baseMipLevel = currentMipLevel; 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); vk::ImageLayout::eTransferDstOptimal, 1, &blitRegion, vk::Filter::eLinear);
commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer, {}, 0, commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer, {}, 0,
nullptr, 0, nullptr, 1, &nextMipBarrier); nullptr, 0, nullptr, 1, &nextMipBarrier);
@ -184,7 +187,7 @@ ModelLoader::LoadImage(vk::CommandBuffer commandBuffer, Texture *texture, Stagin
commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {}, commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {},
0, nullptr, 0, nullptr, 1, &imageReadyBarrier); 0, nullptr, 0, nullptr, 1, &imageReadyBarrier);
return m_ResourceManager->Commit(texture); return m_ResourceManager->Commit(&texture);
} }
Model Model
@ -225,7 +228,6 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched)
} }
eastl::vector<StagingBuffer> stagingBuffers; eastl::vector<StagingBuffer> stagingBuffers;
eastl::vector<Texture> textures;
eastl::vector<TextureHandle> textureHandles; eastl::vector<TextureHandle> textureHandles;
if (!model.images.empty()) if (!model.images.empty())
@ -233,15 +235,13 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched)
u32 numImages = Cast<u32>(model.images.size()); u32 numImages = Cast<u32>(model.images.size());
stagingBuffers.resize(numImages); stagingBuffers.resize(numImages);
textures.resize(numImages);
textureHandles.resize(numImages); textureHandles.resize(numImages);
auto stagingPtr = stagingBuffers.data(); auto stagingPtr = stagingBuffers.data();
auto texturePtr = textures.data();
auto imagePtr = model.images.data(); auto imagePtr = model.images.data();
for (TextureHandle &handle : textureHandles) for (TextureHandle &handle : textureHandles)
{ {
handle = LoadImage(m_CommandBuffer, texturePtr++, stagingPtr++, imagePtr++); handle = LoadImage(m_CommandBuffer, stagingPtr++, imagePtr++);
} }
} }
@ -293,24 +293,33 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched)
eastl::vector<vec4> vertexPositions; eastl::vector<vec4> vertexPositions;
eastl::vector<vec4> normalVectors; eastl::vector<vec4> normalVectors;
eastl::vector<vec2> texCoord0; eastl::vector<vec2> texCoord0;
eastl::vector<vec4> color0;
eastl::vector<u32> indices; eastl::vector<u32> indices;
eastl::vector<MeshPrimitive> meshPrimitives; eastl::vector<MeshPrimitive> meshPrimitives;
meshPrimitives.reserve(model.meshes.size()); meshPrimitives.reserve(model.meshes.size());
// Offset, Count
eastl::vector<eastl::pair<usize, usize>> meshPrimRanges;
meshPrimRanges.reserve(model.meshes.size());
u32 vertexOffset = 0; u32 vertexOffset = 0;
i32 normalOffset = 0; u32 normalOffset = 0;
i32 texCoord0Offset = 0; u32 texCoord0Offset = 0;
u32 color0Offset = 0;
u32 indexOffset = 0; u32 indexOffset = 0;
for (auto &mesh : model.meshes) for (auto &mesh : model.meshes)
{ {
meshPrimRanges.emplace_back(meshPrimitives.size(), mesh.primitives.size());
for (auto &prim : mesh.primitives) for (auto &prim : mesh.primitives)
{ {
u32 vertexCount = 0; u32 vertexCount = 0;
u32 indexCount = 0; u32 indexCount = 0;
i32 normalCount = 0; u32 normalCount = 0;
i32 texCoord0Count = 0; u32 texCoord0Count = 0;
u32 color0Count = 0;
#pragma region Position
assert(prim.attributes.contains(APosition)); assert(prim.attributes.contains(APosition));
assert(prim.mode == TINYGLTF_MODE_TRIANGLES); assert(prim.mode == TINYGLTF_MODE_TRIANGLES);
{ {
@ -347,7 +356,8 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched)
} }
} }
} }
#pragma endregion
#pragma region Normal
// Normal Coords // Normal Coords
if (prim.attributes.contains(ANormal)) if (prim.attributes.contains(ANormal))
{ {
@ -384,7 +394,8 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched)
} }
} }
} }
#pragma endregion
#pragma region UV0
// UV0 // UV0
if (prim.attributes.contains(ATexCoord0)) if (prim.attributes.contains(ATexCoord0))
{ {
@ -400,13 +411,44 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched)
texCoord0.reserve(vertexPositions.size()); texCoord0.reserve(vertexPositions.size());
assert(uvAccessor->type == TINYGLTF_TYPE_VEC2 && assert(uvAccessor->type == TINYGLTF_TYPE_VEC2 &&
uvAccessor->componentType == TINYGLTF_COMPONENT_TYPE_FLOAT); uvAccessor->componentType == TINYGLTF_COMPONENT_TYPE_FLOAT);
{ {
vec2 *data = Recast<vec2 *>(uvBuffer->data.data() + byteOffset); vec2 *data = Recast<vec2 *>(uvBuffer->data.data() + byteOffset);
texCoord0.insert(texCoord0.end(), data, data + vertexCount); texCoord0.insert(texCoord0.end(), data, data + vertexCount);
} }
} }
#pragma endregion
#pragma region Color
if (prim.attributes.contains(AColor0))
{
tinygltf::Accessor *colorAccessor = &model.accessors[prim.attributes[AColor0]];
assert(colorAccessor->count <= MaxValue<u32>);
tinygltf::BufferView *colorBufferView = &model.bufferViews[colorAccessor->bufferView];
tinygltf::Buffer *colorBuffer = &model.buffers[colorBufferView->buffer];
usize byteOffset = (colorAccessor->byteOffset + colorBufferView->byteOffset);
color0Count = Cast<i32>(colorAccessor->count);
color0.reserve(vertexPositions.size());
assert(color0Count == vertexCount);
if (colorAccessor->type == TINYGLTF_TYPE_VEC4)
{
vec4 *data = Recast<vec4 *>(colorBuffer->data.data() + byteOffset);
color0.insert(color0.end(), data, data + vertexCount);
}
else if (colorAccessor->type == TINYGLTF_TYPE_VEC3)
{
vec3 *data = Recast<vec3 *>(colorBuffer->data.data() + byteOffset);
for (u32 i = 0; i < color0Count; ++i)
{
color0.push_back(vec4(data[i], 1.0f));
}
}
}
#pragma endregion
#pragma region Indices
// Indices // Indices
if (prim.indices >= 0) if (prim.indices >= 0)
{ {
@ -446,26 +488,93 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched)
indices.push_back(i); indices.push_back(i);
} }
} }
#pragma endregion
meshPrimitives.push_back({ meshPrimitives.push_back({
.m_VertexOffset = vertexOffset, .m_VertexOffset = vertexOffset,
.m_NormalOffset = normalCount > 0 ? normalOffset : -1, .m_NormalOffset = normalCount > 0 ? Cast<i32>(normalOffset) : -1,
.m_TexCoord0Offset = texCoord0Count > 0 ? texCoord0Offset : -1, .m_TexCoord0Offset = texCoord0Count > 0 ? Cast<i32>(texCoord0Offset) : -1,
// TODO: Color offset
.m_FirstIndex = indexOffset, .m_FirstIndex = indexOffset,
.m_IndexCount = indexCount, .m_IndexCount = indexCount,
.m_MaterialIdx = prim.material, .m_MaterialIdx = prim.material,
.m_TransformIdx = -1,
}); });
vertexOffset += vertexCount; vertexOffset += vertexCount;
indexOffset += indexCount; indexOffset += indexCount;
texCoord0Offset += texCoord0Count; texCoord0Offset += texCoord0Count;
normalOffset += normalCount; normalOffset += normalCount;
color0Offset += color0Count;
assert(normalVectors.empty() || normalVectors.size() == vertexPositions.size()); assert(normalVectors.empty() || normalVectors.size() == vertexPositions.size());
assert(texCoord0.empty() || texCoord0.size() == vertexPositions.size()); assert(texCoord0.empty() || texCoord0.size() == vertexPositions.size());
} }
} }
Nodes nodes;
{
if (model.defaultScene >= 0)
{
eastl::function<void(i32,i32)> processNode = [&processNode, &model, &nodes, &meshPrimRanges, &meshPrimitives](i32 idx, i32 parent) -> void {
INFO("parent {} -> idx {}", parent, idx);
const auto *node = &model.nodes[idx];
vec3 nodeTranslation = vec3{0.0f};
quat nodeRotation = quat{1.0f, 0.0f, 0.0f, 0.0f};
vec3 nodeScale = vec3{1.0f};
mat4 nodeMatrix = mat4{1.0f};
if (node->translation.size() == 3)
{
nodeTranslation = glm::make_vec3(node->translation.data());
}
if (node->rotation.size() == 4)
{
nodeRotation = glm::make_quat(node->rotation.data());
}
if (node->scale.size() == 3)
{
nodeScale = glm::make_vec3(node->scale.data());
}
if (node->matrix.size() == 16)
{
nodeMatrix = glm::make_mat4(node->matrix.data());
}
const mat4 transform =
translate(mat4(1.0f), nodeTranslation) * mat4_cast(nodeRotation) * scale(mat4(1.0f), nodeScale) * nodeMatrix;
const u32 nodeArrayIndex = nodes.Add(transform, parent);
if (node->mesh >= 0)
{
auto [start, count] = meshPrimRanges[node->mesh];
const auto end = start + count;
for (usize i = start; i != end; ++i)
{
meshPrimitives[i].m_TransformIdx = nodeArrayIndex;
}
}
for (const i32 child : node->children)
{
processNode(child, idx);
}
};
auto *scene = &model.scenes[model.defaultScene];
for (i32 rootNodeIdx : scene->nodes)
{
processNode(rootNodeIdx, -1);
}
}
}
nodes.Update();
StorageBuffer nodeBuffer;
nodeBuffer.Init(pDevice, nodes.GetGlobalTransformByteSize(), true);
nodeBuffer.Write(pDevice, 0, nodes.GetGlobalTransformByteSize(), nodes.GetGlobalTransformPtr());
BufferHandle nodeHandle = m_ResourceManager->Commit(&nodeBuffer);
#pragma region Staging / Transfer / Uploads
StorageBuffer positionBuffer; StorageBuffer positionBuffer;
positionBuffer.Init(pDevice, vertexPositions.size() * sizeof vertexPositions[0], false); positionBuffer.Init(pDevice, vertexPositions.size() * sizeof vertexPositions[0], false);
BufferHandle positionBufferHandle = m_ResourceManager->Commit(&positionBuffer); BufferHandle positionBufferHandle = m_ResourceManager->Commit(&positionBuffer);
@ -486,43 +595,48 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched)
texCoord0BufferHandle = m_ResourceManager->Commit(&texCoord0Buffer); texCoord0BufferHandle = m_ResourceManager->Commit(&texCoord0Buffer);
} }
StorageBuffer color0Buffer;
BufferHandle color0Handle;
if (!color0.empty())
{
color0Buffer.Init(pDevice, color0.size() * sizeof color0[0], false);
color0Handle = m_ResourceManager->Commit(&color0Buffer);
}
IndexBuffer indexBuffer; IndexBuffer indexBuffer;
indexBuffer.Init(pDevice, indices.size() * sizeof indices[0]); indexBuffer.Init(pDevice, indices.size() * sizeof indices[0]);
{ {
vk::BufferCopy bufferCopy = {.srcOffset = 0, .dstOffset = 0}; auto uploadBufferData = [cmd = this->m_CommandBuffer, &stagingBuffers, pDevice](const Buffer *buffer, void* data) {
vk::BufferCopy bufferCopy = {.srcOffset = 0, .dstOffset = 0, .size = buffer->GetSize()};
StagingBuffer &stagingBuffer = stagingBuffers.push_back();
stagingBuffer.Init(pDevice, bufferCopy.size);
stagingBuffer.Write(pDevice, 0, bufferCopy.size, data);
cmd.copyBuffer(stagingBuffer.m_Buffer, buffer->m_Buffer, 1, &bufferCopy);
};
bufferCopy.size = positionBuffer.GetSize(); uploadBufferData(&positionBuffer, vertexPositions.data());
StagingBuffer &positionStaging = stagingBuffers.push_back();
positionStaging.Init(pDevice, bufferCopy.size);
positionStaging.Write(pDevice, 0, bufferCopy.size, vertexPositions.data());
m_CommandBuffer.copyBuffer(positionStaging.m_Buffer, positionBuffer.m_Buffer, 1, &bufferCopy);
if (normalBuffer.IsValid()) if (normalBuffer.IsValid())
{ {
bufferCopy.size = normalBuffer.GetSize(); uploadBufferData(&normalBuffer, normalVectors.data());
StagingBuffer &normalStaging = stagingBuffers.push_back();
normalStaging.Init(pDevice, bufferCopy.size);
normalStaging.Write(pDevice, 0, bufferCopy.size, normalVectors.data());
m_CommandBuffer.copyBuffer(normalStaging.m_Buffer, normalBuffer.m_Buffer, 1, &bufferCopy);
} }
if (texCoord0Buffer.IsValid()) if (texCoord0Buffer.IsValid())
{ {
bufferCopy.size = texCoord0Buffer.GetSize(); uploadBufferData(&texCoord0Buffer, texCoord0.data());
StagingBuffer &textureStaging = stagingBuffers.push_back();
textureStaging.Init(pDevice, bufferCopy.size);
textureStaging.Write(pDevice, 0, bufferCopy.size, texCoord0.data());
m_CommandBuffer.copyBuffer(textureStaging.m_Buffer, texCoord0Buffer.m_Buffer, 1, &bufferCopy);
} }
bufferCopy.size = indexBuffer.GetSize(); if (color0Buffer.IsValid())
StagingBuffer &indexStaging = stagingBuffers.push_back(); {
indexStaging.Init(pDevice, bufferCopy.size); uploadBufferData(&color0Buffer, color0.data());
indexStaging.Write(pDevice, 0, bufferCopy.size, indices.data()); }
m_CommandBuffer.copyBuffer(indexStaging.m_Buffer, indexBuffer.m_Buffer, 1, &bufferCopy);
uploadBufferData(&indexBuffer, indices.data());
} }
#pragma endregion
AbortIfFailed(m_CommandBuffer.end()); AbortIfFailed(m_CommandBuffer.end());
vk::SubmitInfo submitInfo = { vk::SubmitInfo submitInfo = {
@ -547,28 +661,26 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched)
buffer.Destroy(pDevice); buffer.Destroy(pDevice);
} }
return Model{m_ResourceManager, std::move(textures), std::move(textureHandles), materialsBuffer, nodes.Update();
materialsHandle, positionBuffer, positionBufferHandle, normalBuffer,
normalBufferHandle, texCoord0Buffer, texCoord0BufferHandle, indexBuffer, return Model{m_ResourceManager, std::move(textureHandles), std::move(nodes),
meshPrimitives}; materialsHandle, positionBufferHandle, normalBufferHandle,
texCoord0BufferHandle, color0Handle, indexBuffer, meshPrimitives, nodeHandle};
} }
Model::Model(RenderResourceManager *resourceManager, eastl::vector<Texture> &&textures, Model::Model(GpuResourceManager *resourceManager, eastl::vector<TextureHandle> &&textureHandles, Nodes &&nodes,
eastl::vector<TextureHandle> &&textureHandles, const StorageBuffer &materialsBuffer, BufferHandle materialsHandle, BufferHandle vertexPosHandle, BufferHandle normalHandle,
BufferHandle materialsHandle, const StorageBuffer &vertexPosBuffer, BufferHandle vertexPosHandle, BufferHandle uv0Handle, BufferHandle vertexColor, const IndexBuffer &indexBuffer,
const StorageBuffer &normalBuffer, BufferHandle normalHandle, const StorageBuffer &uv0Buffer, const eastl::vector<MeshPrimitive> &meshPrimitives, BufferHandle nodeHandle)
BufferHandle uv0Handle, const IndexBuffer &indexBuffer, const eastl::vector<MeshPrimitive> &meshPrimitives)
: m_ResourceManager(resourceManager) : m_ResourceManager(resourceManager)
, m_Textures(textures) , m_TextureHandles(std::move(textureHandles))
, m_TextureHandles(textureHandles) , m_Nodes(std::move(nodes))
, m_MaterialsBuffer(materialsBuffer)
, m_MaterialsHandle(materialsHandle) , m_MaterialsHandle(materialsHandle)
, m_VertexPositions(vertexPosBuffer)
, m_VertexPositionHandle(vertexPosHandle) , m_VertexPositionHandle(vertexPosHandle)
, m_NormalVectors(normalBuffer)
, m_NormalHandle(normalHandle) , m_NormalHandle(normalHandle)
, m_TexCoord0(uv0Buffer)
, m_TexCoord0Handle(uv0Handle) , m_TexCoord0Handle(uv0Handle)
, m_VertexColorHandle(vertexColor)
, m_NodeHandle(nodeHandle)
, m_IndexBuffer(indexBuffer) , m_IndexBuffer(indexBuffer)
, m_MeshPrimitives(meshPrimitives) , m_MeshPrimitives(meshPrimitives)
{ {
@ -576,16 +688,13 @@ Model::Model(RenderResourceManager *resourceManager, eastl::vector<Texture> &&te
Model::Model(Model &&other) noexcept Model::Model(Model &&other) noexcept
: m_ResourceManager(Take(other.m_ResourceManager)) : m_ResourceManager(Take(other.m_ResourceManager))
, m_Textures(std::move(other.m_Textures))
, m_TextureHandles(std::move(other.m_TextureHandles)) , m_TextureHandles(std::move(other.m_TextureHandles))
, m_MaterialsBuffer(other.m_MaterialsBuffer)
, m_MaterialsHandle(other.m_MaterialsHandle) , m_MaterialsHandle(other.m_MaterialsHandle)
, m_VertexPositions(other.m_VertexPositions)
, m_VertexPositionHandle(other.m_VertexPositionHandle) , m_VertexPositionHandle(other.m_VertexPositionHandle)
, m_NormalVectors(other.m_NormalVectors)
, m_NormalHandle(other.m_NormalHandle) , m_NormalHandle(other.m_NormalHandle)
, m_TexCoord0(other.m_TexCoord0)
, m_TexCoord0Handle(other.m_TexCoord0Handle) , m_TexCoord0Handle(other.m_TexCoord0Handle)
, m_VertexColorHandle(other.m_VertexColorHandle)
, m_NodeHandle(other.m_NodeHandle)
, m_IndexBuffer(other.m_IndexBuffer) , m_IndexBuffer(other.m_IndexBuffer)
, m_MeshPrimitives(std::move(other.m_MeshPrimitives)) , m_MeshPrimitives(std::move(other.m_MeshPrimitives))
{ {
@ -597,16 +706,13 @@ Model::operator=(Model &&other) noexcept
if (this == &other) if (this == &other)
return *this; return *this;
m_ResourceManager = Take(other.m_ResourceManager); m_ResourceManager = Take(other.m_ResourceManager);
m_Textures = std::move(other.m_Textures);
m_TextureHandles = std::move(other.m_TextureHandles); m_TextureHandles = std::move(other.m_TextureHandles);
m_MaterialsBuffer = other.m_MaterialsBuffer;
m_MaterialsHandle = other.m_MaterialsHandle; m_MaterialsHandle = other.m_MaterialsHandle;
m_VertexPositions = other.m_VertexPositions;
m_VertexPositionHandle = other.m_VertexPositionHandle; m_VertexPositionHandle = other.m_VertexPositionHandle;
m_NormalVectors = other.m_NormalVectors;
m_NormalHandle = other.m_NormalHandle; m_NormalHandle = other.m_NormalHandle;
m_TexCoord0 = other.m_TexCoord0;
m_TexCoord0Handle = other.m_TexCoord0Handle; m_TexCoord0Handle = other.m_TexCoord0Handle;
m_VertexColorHandle = other.m_VertexColorHandle;
m_NodeHandle = std::move(other.m_NodeHandle);
m_IndexBuffer = other.m_IndexBuffer; m_IndexBuffer = other.m_IndexBuffer;
m_MeshPrimitives = std::move(other.m_MeshPrimitives); m_MeshPrimitives = std::move(other.m_MeshPrimitives);
return *this; return *this;
@ -617,11 +723,9 @@ Model::~Model()
if (!m_ResourceManager) if (!m_ResourceManager)
return; return;
m_VertexPositions.Destroy(m_ResourceManager->m_Device);
m_IndexBuffer.Destroy(m_ResourceManager->m_Device); m_IndexBuffer.Destroy(m_ResourceManager->m_Device);
m_NormalVectors.Destroy(m_ResourceManager->m_Device); m_ResourceManager->Release(m_NodeHandle);
m_TexCoord0.Destroy(m_ResourceManager->m_Device); m_ResourceManager->Release(m_VertexColorHandle);
m_ResourceManager->Release(m_VertexPositionHandle); m_ResourceManager->Release(m_VertexPositionHandle);
m_ResourceManager->Release(m_NormalHandle); m_ResourceManager->Release(m_NormalHandle);
m_ResourceManager->Release(m_TexCoord0Handle); m_ResourceManager->Release(m_TexCoord0Handle);
@ -630,19 +734,14 @@ Model::~Model()
m_ResourceManager->Release(handle); m_ResourceManager->Release(handle);
} }
m_ResourceManager->Release(m_MaterialsHandle); 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) u32 graphicsQueueIndex)
: m_ResourceManager(resourceManager) : m_ResourceManager(resourceManager)
, m_TransferQueue(transferQueue) , m_TransferQueue(transferQueue)
, m_TransferQueueIndex(transferQueueIndex) , m_TransferQueueIndex(transferQueueIndex)
, m_GraphicsQueueIndex(graphicsQueueIndex) , m_GraphicsQueueIndex(graphicsQueueIndex)
{ {
const Device *pDevice = resourceManager->m_Device; const Device *pDevice = resourceManager->m_Device;
const vk::CommandPoolCreateInfo poolCreateInfo = { const vk::CommandPoolCreateInfo poolCreateInfo = {

View File

@ -22,53 +22,150 @@ constexpr auto GLTF_BINARY_FILE_EXTENSION = ".glb";
struct MeshPrimitive struct MeshPrimitive
{ {
u32 m_VertexOffset; u32 m_VertexOffset;
i32 m_NormalOffset; // <0 for invalid i32 m_NormalOffset; // <0 for invalid
i32 m_TexCoord0Offset; // <0 for invalid i32 m_TexCoord0Offset; // <0 for invalid
u32 m_FirstIndex; u32 m_FirstIndex;
u32 m_IndexCount; u32 m_IndexCount;
i32 m_MaterialIdx; // <0 for invalid i32 m_MaterialIdx; // <0 for invalid
i32 m_TransformIdx;
};
struct Nodes
{
eastl::vector<mat4> m_Transforms;
eastl::vector<mat4> m_GlobalTransforms;
eastl::vector<u32> m_Parents_;
bool m_Dirty = true;
constexpr static u32 ROOT_BIT = 1u << 31;
constexpr static u32 DIRTY_BIT = 1u << 30;
constexpr static u32 PARENT_MASK = ~(ROOT_BIT | DIRTY_BIT);
u32
Add(const mat4& transform, i32 parent = -1)
{
m_Dirty = true;
u32 index = Count();
m_Transforms.push_back(transform);
m_GlobalTransforms.push_back(transform);
const u32 parentVal = (parent < 0 ? ROOT_BIT : parent & PARENT_MASK) | DIRTY_BIT;
m_Parents_.push_back(parentVal);
return index;
}
[[nodiscard]] const mat4 &
Get(const u32 index) const
{
return m_Transforms[index];
}
void
Set(const u32 index, const mat4 &transform)
{
m_Dirty = true;
m_Transforms[index] = transform;
m_Parents_[index] |= DIRTY_BIT;
}
[[nodiscard]] const mat4 &
operator[](const u32 index) const
{
return m_Transforms[index];
}
[[nodiscard]] mat4 &
operator[](const u32 index)
{
m_Dirty = true;
m_Parents_[index] |= DIRTY_BIT;
return m_Transforms[index];
}
[[nodiscard]] u32
Count() const
{
return Cast<u32>(m_Transforms.size());
}
[[nodiscard]] usize
GetGlobalTransformByteSize() const
{
return m_Transforms.size() * sizeof m_Transforms[0];
}
[[nodiscard]] const mat4 *
GetGlobalTransformPtr() const
{
return m_Transforms.data();
}
void
Update()
{
if (!m_Dirty)
return;
auto transformIter = m_Transforms.begin();
auto globalTransformIter = m_GlobalTransforms.begin();
auto parentIter = m_Parents_.begin();
const auto parentEnd = m_Parents_.end();
while (parentIter != parentEnd)
{
if (!(*parentIter & ROOT_BIT) && *parentIter & DIRTY_BIT)
{
u32 parent = *parentIter & PARENT_MASK;
*globalTransformIter = m_GlobalTransforms[parent] * *transformIter;
}
else
{
*globalTransformIter = *transformIter;
}
*parentIter &= ~DIRTY_BIT;
++parentIter;
++globalTransformIter;
++transformIter;
}
m_Dirty = false;
}
}; };
struct Material struct Material
{ {
vec4 m_AlbedoFactor; vec4 m_AlbedoFactor; // 16 16
vec3 m_EmissionFactor; vec3 m_EmissionFactor; // 12 28
f32 m_MetalFactor; f32 m_MetalFactor; // 04 32
f32 m_RoughFactor; f32 m_RoughFactor; // 04 36
TextureHandle m_AlbedoTex; TextureHandle m_AlbedoTex; // 04 40
TextureHandle m_NormalTex; TextureHandle m_NormalTex; // 04 44
TextureHandle m_MetalRoughTex; TextureHandle m_MetalRoughTex; // 04 48
TextureHandle m_OcclusionTex; TextureHandle m_OcclusionTex; // 04 52
TextureHandle m_EmissionTex; TextureHandle m_EmissionTex; // 04 56
}; };
struct Model struct Model
{ {
RenderResourceManager *m_ResourceManager; GpuResourceManager *m_ResourceManager;
eastl::vector<Texture> m_Textures;
eastl::vector<TextureHandle> m_TextureHandles; eastl::vector<TextureHandle> m_TextureHandles;
Nodes m_Nodes;
StorageBuffer m_MaterialsBuffer;
BufferHandle m_MaterialsHandle; BufferHandle m_MaterialsHandle;
StorageBuffer m_VertexPositions;
BufferHandle m_VertexPositionHandle; BufferHandle m_VertexPositionHandle;
StorageBuffer m_NormalVectors;
BufferHandle m_NormalHandle; BufferHandle m_NormalHandle;
StorageBuffer m_TexCoord0;
BufferHandle m_TexCoord0Handle; BufferHandle m_TexCoord0Handle;
BufferHandle m_VertexColorHandle;
BufferHandle m_NodeHandle;
IndexBuffer m_IndexBuffer; IndexBuffer m_IndexBuffer;
eastl::vector<MeshPrimitive> m_MeshPrimitives; eastl::vector<MeshPrimitive> m_MeshPrimitives;
Model(RenderResourceManager *resourceManager, eastl::vector<Texture> &&textures, Model(GpuResourceManager *resourceManager, eastl::vector<TextureHandle> &&textureHandles, Nodes&& nodes,
eastl::vector<TextureHandle> &&textureHandles, const StorageBuffer &materialsBuffer, BufferHandle materialsHandle, BufferHandle vertexPosHandle, BufferHandle normalHandle, BufferHandle uv0Handle, BufferHandle vertexColor,
BufferHandle materialsHandle, const StorageBuffer &vertexPosBuffer, BufferHandle vertexPosHandle, const IndexBuffer &indexBuffer, const eastl::vector<MeshPrimitive> &meshPrimitives, BufferHandle nodeHandle);
const StorageBuffer &normalBuffer, BufferHandle normalHandle, const StorageBuffer &uv0Buffer,
BufferHandle uv0Handle, const IndexBuffer &indexBuffer, const eastl::vector<MeshPrimitive> &meshPrimitives);
Model(Model &&other) noexcept; Model(Model &&other) noexcept;
Model &operator=(Model &&other) noexcept; Model &operator=(Model &&other) noexcept;
@ -80,18 +177,18 @@ struct Model
struct ModelLoader struct ModelLoader
{ {
RenderResourceManager *const m_ResourceManager; GpuResourceManager *m_ResourceManager;
vk::CommandPool m_CommandPool; vk::CommandPool m_CommandPool;
vk::CommandBuffer m_CommandBuffer; vk::CommandBuffer m_CommandBuffer;
vk::Queue m_TransferQueue; vk::Queue m_TransferQueue;
u32 m_TransferQueueIndex; u32 m_TransferQueueIndex;
u32 m_GraphicsQueueIndex; u32 m_GraphicsQueueIndex;
ModelLoader(RenderResourceManager *resourceManager, vk::Queue transferQueue, u32 transferQueueIndex, ModelLoader(GpuResourceManager *resourceManager, vk::Queue transferQueue, u32 transferQueueIndex,
u32 graphicsQueueIndex); u32 graphicsQueueIndex);
~ModelLoader(); ~ModelLoader();
TextureHandle LoadImage(vk::CommandBuffer commandBuffer, Texture *texture, StagingBuffer *stagingBuffer, TextureHandle LoadImage(vk::CommandBuffer commandBuffer, StagingBuffer *stagingBuffer,
tinygltf::Image *image) const; tinygltf::Image *image) const;
Model LoadModel(cstr path, cstr name = nullptr, bool batched = false); Model LoadModel(cstr path, cstr name = nullptr, bool batched = false);
@ -100,6 +197,7 @@ struct ModelLoader
constexpr static auto ATangent = "TANGENT"; constexpr static auto ATangent = "TANGENT";
constexpr static auto ATexCoord0 = "TEXCOORD_0"; constexpr static auto ATexCoord0 = "TEXCOORD_0";
constexpr static auto ATexCoord1 = "TEXCOORD_1"; constexpr static auto ATexCoord1 = "TEXCOORD_1";
constexpr static auto AColor0 = "COLOR_0";
constexpr static auto AJoints0 = "JOINTS_0"; constexpr static auto AJoints0 = "JOINTS_0";
constexpr static auto AWeights0 = "WEIGHTS_0"; constexpr static auto AWeights0 = "WEIGHTS_0";
}; };

View File

@ -27,7 +27,7 @@
#include <filesystem> #include <filesystem>
constexpr u32 MAX_FRAMES_IN_FLIGHT = 3; constexpr u32 MAX_FRAMES_IN_FLIGHT = 3;
constexpr auto MODEL_FILE = "model/BoxTextured.glb"; constexpr auto MODEL_FILE = "model/OrientationTest.glb";
struct ImageFile struct ImageFile
{ {
@ -85,7 +85,7 @@ main(int, char **)
Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"}; Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"};
vk::Queue commandQueue = device.GetQueue(queueAllocation.m_Family, 0); vk::Queue commandQueue = device.GetQueue(queueAllocation.m_Family, 0);
Swapchain swapchain = {&window, &device, "Primary Chain"}; Swapchain swapchain = {&window, &device, "Primary Chain"};
RenderResourceManager resourceManager = {&device, 1000}; GpuResourceManager resourceManager = {&device, 1000};
ModelLoader modelLoader = {&resourceManager, commandQueue, queueAllocation.m_Family, queueAllocation.m_Family}; ModelLoader modelLoader = {&resourceManager, commandQueue, queueAllocation.m_Family, queueAllocation.m_Family};
@ -95,7 +95,7 @@ main(int, char **)
Camera camera = { Camera camera = {
.m_Model = {1.0f}, .m_Model = {1.0f},
.m_View = glm::lookAt(vec3(0.0f, 2.0f, 2.0f), vec3(0.0f), vec3(0.0f, 1.0f, 0.0f)), .m_View = glm::lookAt(vec3(0.0f, 12.0f, 12.0f), vec3(0.0f), vec3(0.0f, 1.0f, 0.0f)),
.m_Perspective = glm::perspective( .m_Perspective = glm::perspective(
70_deg, Cast<f32>(swapchain.m_Extent.width) / Cast<f32>(swapchain.m_Extent.height), 0.1f, 100.0f), 70_deg, Cast<f32>(swapchain.m_Extent.width) / Cast<f32>(swapchain.m_Extent.height), 0.1f, 100.0f),
}; };
@ -217,14 +217,18 @@ main(int, char **)
struct ModelData struct ModelData
{ {
BufferHandle m_VertexBuffer; BufferHandle m_VertexBuffer;
BufferHandle m_Color;
BufferHandle m_UvBuffer; BufferHandle m_UvBuffer;
BufferHandle m_Materials; BufferHandle m_Materials;
BufferHandle m_Nodes;
}; };
ModelData modelData = { ModelData modelData = {
.m_VertexBuffer = model.m_VertexPositionHandle, .m_VertexBuffer = model.m_VertexPositionHandle,
.m_Color = model.m_VertexColorHandle,
.m_UvBuffer = model.m_TexCoord0Handle, .m_UvBuffer = model.m_TexCoord0Handle,
.m_Materials = model.m_MaterialsHandle, .m_Materials = model.m_MaterialsHandle,
.m_Nodes = model.m_NodeHandle,
}; };
INFO("Starting loop"); INFO("Starting loop");
@ -295,7 +299,10 @@ main(int, char **)
for (auto &prim : model.m_MeshPrimitives) for (auto &prim : model.m_MeshPrimitives)
{ {
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, sizeof modelData, sizeof prim, &prim); cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, sizeof modelData,
sizeof prim.m_MaterialIdx, &prim.m_MaterialIdx);
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, sizeof modelData + sizeof prim.m_MaterialIdx,
sizeof prim.m_TransformIdx, &prim.m_TransformIdx);
cmd.drawIndexed(prim.m_IndexCount, 1, prim.m_FirstIndex, Cast<i32>(prim.m_VertexOffset), 0); cmd.drawIndexed(prim.m_IndexCount, 1, prim.m_FirstIndex, Cast<i32>(prim.m_VertexOffset), 0);
} }

View File

@ -13,7 +13,7 @@
#include <EASTL/array.h> #include <EASTL/array.h>
Pipeline Pipeline
CreatePipeline(const Device *device, const Swapchain *swapchain, const RenderResourceManager *resourceManager) CreatePipeline(const Device *device, const Swapchain *swapchain, const GpuResourceManager *resourceManager)
{ {
// Pipeline Setup // Pipeline Setup
auto vertexShaderModule = CreateShader(device, VERTEX_SHADER_FILE); auto vertexShaderModule = CreateShader(device, VERTEX_SHADER_FILE);
@ -58,7 +58,7 @@ CreatePipeline(const Device *device, const Swapchain *swapchain, const RenderRes
vk::PushConstantRange pushConstantRange = { vk::PushConstantRange pushConstantRange = {
.stageFlags = vk::ShaderStageFlagBits::eAll, .stageFlags = vk::ShaderStageFlagBits::eAll,
.offset = 0, .offset = 0,
.size = 36, .size = 28,
}; };
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = { vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = {

View File

@ -8,7 +8,7 @@
#include "global.h" #include "global.h"
#include "pipeline.h" #include "pipeline.h"
struct RenderResourceManager; struct GpuResourceManager;
struct Swapchain; struct Swapchain;
struct Device; struct Device;
@ -22,4 +22,4 @@ struct Vertex
}; };
vk::ShaderModule CreateShader(const Device *device, cstr shaderFile); 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);

View File

@ -12,25 +12,184 @@
#include <EASTL/array.h> #include <EASTL/array.h>
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<u32 *>(allocatedTexture);
// Ensure it is copyable.
static_assert(std::is_trivially_copyable_v<Texture>);
memcpy(allocatedTexture, texture, sizeof *texture);
// Take ownership of the buffer.
texture->m_MipLevels_ &= ~Texture::OWNED_BIT;
return {index};
}
const u32 index = Cast<u32>(m_Textures.size());
if (index < m_MaxCapacity)
{
Texture *allocatedTexture = &m_Textures.push_back();
// Ensure it is copyable.
static_assert(std::is_trivially_copyable_v<Texture>);
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<u32 *>(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<u32 *>(allocatedBuffer);
// Ensure it is copyable.
static_assert(std::is_trivially_copyable_v<StorageBuffer>);
memcpy(allocatedBuffer, buffer, sizeof *buffer);
// Take ownership of the buffer.
buffer->m_Size_ &= ~StorageBuffer::OWNED_BIT;
return {index};
}
const u32 index = Cast<u32>(m_Buffers.size());
if (index < m_MaxCapacity)
{
StorageBuffer *allocatedBuffer = &m_Buffers.push_back();
// Ensure it is copyable.
static_assert(std::is_trivially_copyable_v<StorageBuffer>);
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<u32 *>(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) : uBufferInfo(info)
{ {
} }
RenderResourceManager::WriteInfo::WriteInfo(vk::DescriptorImageInfo info) GpuResourceManager::WriteInfo::WriteInfo(vk::DescriptorImageInfo info)
: uImageInfo(info) : uImageInfo(info)
{ {
} }
RenderResourceManager::WriteInfo::WriteInfo(vk::BufferView info) GpuResourceManager::WriteInfo::WriteInfo(vk::BufferView info)
: uBufferView(info) : uBufferView(info)
{ {
} }
BufferHandle 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{ m_WriteInfos.emplace_back(vk::DescriptorBufferInfo{
.buffer = storageBuffer->m_Buffer, .buffer = storageBuffer->m_Buffer,
@ -41,19 +200,23 @@ RenderResourceManager::Commit(const StorageBuffer *storageBuffer)
m_Writes.push_back({ m_Writes.push_back({
.dstSet = m_DescriptorSet, .dstSet = m_DescriptorSet,
.dstBinding = BUFFER_BINDING_INDEX, .dstBinding = BUFFER_BINDING_INDEX,
.dstArrayElement = handle, .dstArrayElement = handle.m_Index,
.descriptorCount = 1, .descriptorCount = 1,
.descriptorType = vk::DescriptorType::eStorageBuffer, .descriptorType = vk::DescriptorType::eStorageBuffer,
.pBufferInfo = &m_WriteInfos.back().uBufferInfo, .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 void
RenderResourceManager::EraseWrites(u32 handleIndex, HandleType handleType) GpuResourceManager::EraseWrites(u32 handleIndex, HandleType handleType)
{ {
auto writeIter = m_Writes.begin(); auto writeIter = m_Writes.begin();
auto ownerIter = m_WriteOwner.begin(); auto ownerIter = m_WriteOwner.begin();
@ -76,31 +239,39 @@ RenderResourceManager::EraseWrites(u32 handleIndex, HandleType handleType)
} }
void void
RenderResourceManager::Release(BufferHandle handle) GpuResourceManager::Release(BufferHandle handle)
{ {
if (handle.IsInvalid()) if (handle.IsInvalid())
return; return;
EraseWrites(handle.m_Index, HandleType::eBuffer); 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 void
RenderResourceManager::Release(TextureHandle handle) GpuResourceManager::Release(TextureHandle handle)
{ {
if (handle.IsInvalid()) if (handle.IsInvalid())
return; return;
EraseWrites(handle.m_Index, HandleType::eTexture); 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 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{ m_WriteInfos.emplace_back(vk::DescriptorImageInfo{
.sampler = nullptr, .sampler = nullptr,
@ -111,19 +282,23 @@ RenderResourceManager::Commit(const Texture *texture)
m_Writes.push_back({ m_Writes.push_back({
.dstSet = m_DescriptorSet, .dstSet = m_DescriptorSet,
.dstBinding = TEXTURE_BINDING_INDEX, .dstBinding = TEXTURE_BINDING_INDEX,
.dstArrayElement = handle, .dstArrayElement = handle.m_Index,
.descriptorCount = 1, .descriptorCount = 1,
.descriptorType = vk::DescriptorType::eCombinedImageSampler, .descriptorType = vk::DescriptorType::eCombinedImageSampler,
.pImageInfo = &m_WriteInfos.back().uImageInfo, .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}; return {handle};
} }
void void
RenderResourceManager::Update() GpuResourceManager::Update()
{ {
if (m_Writes.empty() || m_WriteInfos.empty()) if (m_Writes.empty() || m_WriteInfos.empty())
return; return;
@ -135,7 +310,7 @@ RenderResourceManager::Update()
m_WriteOwner.clear(); m_WriteOwner.clear();
} }
RenderResourceManager::RenderResourceManager(const Device *device, u16 maxSize) GpuResourceManager::GpuResourceManager(const Device *device, u16 maxSize)
: m_Device(device) : m_Device(device)
{ {
vk::PhysicalDeviceProperties properties; vk::PhysicalDeviceProperties properties;
@ -166,8 +341,8 @@ RenderResourceManager::RenderResourceManager(const Device *device, u16 maxSize)
INFO("Max Buffer Count: {}", buffersCount); INFO("Max Buffer Count: {}", buffersCount);
INFO("Max Texture Count: {}", texturesCount); INFO("Max Texture Count: {}", texturesCount);
m_BufferFreeList.Init(buffersCount); m_BufferManager.Init(buffersCount);
m_TextureFreeList.Init(texturesCount); m_TextureManager.Init(texturesCount);
eastl::array poolSizes = { eastl::array poolSizes = {
vk::DescriptorPoolSize{ vk::DescriptorPoolSize{
@ -225,9 +400,54 @@ RenderResourceManager::RenderResourceManager(const Device *device, u16 maxSize)
m_Device->SetName(m_DescriptorSet, "Bindless Set"); 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_Sampler, nullptr);
m_Device->m_Device.destroy(m_DescriptorPool, nullptr); m_Device->m_Device.destroy(m_DescriptorPool, nullptr);
m_Device->m_Device.destroy(m_SetLayout, 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;
} }

View File

@ -5,8 +5,9 @@
#pragma once #pragma once
#include "buffer.h"
#include "global.h" #include "global.h"
#include "buffer.h"
#include "image.h"
#include <EASTL/deque.h> #include <EASTL/deque.h>
#include <EASTL/stack.h> #include <EASTL/stack.h>
@ -16,7 +17,7 @@ struct Device;
struct Texture; struct Texture;
struct UniformStorageBuffer; struct UniformStorageBuffer;
struct RenderResourceManager; struct GpuResourceManager;
struct GpuResourceHandle struct GpuResourceHandle
{ {
@ -38,54 +39,46 @@ struct TextureHandle : GpuResourceHandle
{ {
}; };
struct FreeList struct TextureManager
{ {
eastl::stack<u32, eastl::deque<u32>> m_List; eastl::vector<Texture> m_Textures;
u32 m_MaxVisited = 0; u32 m_MaxCapacity;
u32 m_MaxCapacity = 16; u32 m_FreeHead;
void void
Init(u32 maxCapacity) Init(u32 maxCapacity);
{ TextureHandle Commit(Texture *texture);
// MaxValue<u32> is 'invalid-handle' so you can't use it as a handle. Texture *Fetch(TextureHandle handle);
assert(maxCapacity < GpuResourceHandle::INVALID_HANDLE); void Release(const Device *device, TextureHandle handle);
m_MaxCapacity = maxCapacity; void Destroy(const Device *device);
}
[[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);
}
}; };
struct RenderResourceManager struct BufferManager
{ {
private: eastl::vector<StorageBuffer> m_Buffers;
union WriteInfo { 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::DescriptorBufferInfo uBufferInfo;
vk::DescriptorImageInfo uImageInfo; vk::DescriptorImageInfo uImageInfo;
vk::BufferView uBufferView; vk::BufferView uBufferView;
WriteInfo()
{
}
explicit WriteInfo(vk::DescriptorBufferInfo info); explicit WriteInfo(vk::DescriptorBufferInfo info);
explicit WriteInfo(vk::DescriptorImageInfo info); explicit WriteInfo(vk::DescriptorImageInfo info);
explicit WriteInfo(vk::BufferView info); explicit WriteInfo(vk::BufferView info);
@ -105,12 +98,13 @@ struct RenderResourceManager
vk::Sampler m_Sampler; vk::Sampler m_Sampler;
FreeList m_BufferFreeList; //FreeList m_BufferFreeList;
FreeList m_TextureFreeList; BufferManager m_BufferManager;
TextureManager m_TextureManager;
void EraseWrites(u32 handleIndex, HandleType handleType); void EraseWrites(u32 handleIndex, HandleType handleType);
public: public:
const Device *m_Device; const Device *m_Device;
constexpr static u32 BUFFER_BINDING_INDEX = 0; constexpr static u32 BUFFER_BINDING_INDEX = 0;
@ -120,16 +114,24 @@ struct RenderResourceManager
vk::DescriptorSetLayout m_SetLayout; vk::DescriptorSetLayout m_SetLayout;
vk::DescriptorSet m_DescriptorSet; vk::DescriptorSet m_DescriptorSet;
BufferHandle Commit(const StorageBuffer *storageBuffer); BufferHandle Commit(StorageBuffer *storageBuffer);
void Release(BufferHandle handle); void Release(BufferHandle handle);
TextureHandle Commit(const Texture *texture); TextureHandle Commit(Texture *texture);
void Release(TextureHandle handle); void Release(TextureHandle handle);
void Update(); void Update();
// Ctor/Dtor // Ctor/Dtor
RenderResourceManager(const Device *device, u16 maxSize); GpuResourceManager(const Device *device, u16 maxSize);
~RenderResourceManager(); ~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);
}; };

View File

@ -2,11 +2,17 @@
typedef float4 PositionData; typedef float4 PositionData;
typedef float2 UVData; typedef float2 UVData;
typedef float4 NormalData; typedef float4 NormalData;
typedef float4 ColorData;
struct TransformData
{
float4x4 transform;
};
struct MaterialData struct MaterialData
{ {
float4 m_AlbedoFactor; float m_AlbedoFactor[4];
float3 m_EmissionFactor; float m_EmissionFactor[3];
float m_MetalFactor; float m_MetalFactor;
float m_RoughFactor; float m_RoughFactor;
uint m_AlbedoTex; uint m_AlbedoTex;
@ -19,21 +25,19 @@ struct MaterialData
struct Block struct Block
{ {
uint vertexBufferHandle; uint vertexBufferHandle;
uint colorHandle;
uint uvBufferHandle; uint uvBufferHandle;
uint materialBufferHandle; uint materialBufferHandle;
uint m_VertexOffset; uint nodeBufferHandle;
int m_NormalOffset;
int m_TexCoord0Offset;
uint m_FirstIndex;
uint m_IndexCount;
int m_MaterialIdx; int m_MaterialIdx;
uint m_NodeIdx;
}; };
struct Camera struct Camera
{ {
row_major float4x4 model; float4x4 model;
row_major float4x4 view; float4x4 view;
row_major float4x4 proj; float4x4 proj;
}; };
#define INVALID_HANDLE 0xFFFFFFFF #define INVALID_HANDLE 0xFFFFFFFF
@ -41,7 +45,9 @@ struct Camera
[[vk::binding(0, 0)]] StructuredBuffer<PositionData> vertexBuffer[]; [[vk::binding(0, 0)]] StructuredBuffer<PositionData> vertexBuffer[];
[[vk::binding(0, 0)]] StructuredBuffer<UVData> uvBuffer[]; [[vk::binding(0, 0)]] StructuredBuffer<UVData> uvBuffer[];
[[vk::binding(0, 0)]] StructuredBuffer<NormalData> normalBuffer[]; [[vk::binding(0, 0)]] StructuredBuffer<NormalData> normalBuffer[];
[[vk::binding(0, 0)]] StructuredBuffer<ColorData> colorBuffer[];
[[vk::binding(0, 0)]] StructuredBuffer<MaterialData> materialsBuffer[]; [[vk::binding(0, 0)]] StructuredBuffer<MaterialData> materialsBuffer[];
[[vk::binding(0, 0)]] StructuredBuffer<TransformData> nodeBuffer[];
[[vk::binding(1, 0)]] Texture2D<float4> textures[]; [[vk::binding(1, 0)]] Texture2D<float4> textures[];
[[vk::binding(1, 0)]] SamplerState immutableSamplers[]; [[vk::binding(1, 0)]] SamplerState immutableSamplers[];

View File

@ -2,6 +2,8 @@
struct FS_Input struct FS_Input
{ {
float4 inPosition : POSITION;
float4 inColor : COLOR0;
float2 inUV : TEXCOORD0; float2 inUV : TEXCOORD0;
}; };
@ -10,35 +12,27 @@ struct FS_Output
float4 outColor : SV_Target0; float4 outColor : SV_Target0;
}; };
struct Float4 float4 ArrayToVector(float arr[4])
{ {
float4 value; return float4(arr[0], arr[1], arr[2], arr[3]);
}; }
float4 GetAlbedo(uint materialBufferId, int materialId, float2 uv0) float4 GetAlbedo(uint materialBufferId, int materialId, float2 uv)
{ {
if (materialId < 0) uint albedoTexId = materialsBuffer[materialBufferId][materialId].m_AlbedoTex;
if (albedoTexId == INVALID_HANDLE)
{ {
return float4(1.0f, 0.0f, 1.0f, 1.0f); // Magenta return ArrayToVector(materialsBuffer[materialBufferId][materialId].m_AlbedoFactor);
} }
else else
{ {
float4 albedoFactor = materialsBuffer[materialBufferId][materialId].m_AlbedoFactor; return textures[albedoTexId].Sample(immutableSamplers[albedoTexId], uv);
uint albedoTexId = materialsBuffer[materialBufferId][materialId].m_AlbedoTex;
if (albedoTexId == INVALID_HANDLE)
{
return albedoFactor;
}
else
{
return textures[albedoTexId].Sample(immutableSamplers[albedoTexId], uv0);
}
} }
} }
FS_Output main(FS_Input stage_input) FS_Output main(FS_Input stage_input)
{ {
FS_Output stage_output; FS_Output output;
stage_output.outColor = GetAlbedo(pcb.materialBufferHandle, pcb.m_MaterialIdx, stage_input.inUV); output.outColor = pcb.m_MaterialIdx < 0 ? stage_input.inColor : GetAlbedo(pcb.materialBufferHandle, pcb.m_MaterialIdx, stage_input.inUV);
return stage_output; return output;
} }

View File

@ -7,7 +7,9 @@ struct VS_Input
struct VS_Output struct VS_Output
{ {
UVData outUV : TEXCOORD0; float4 outPosition : POSITION;
float4 outColor : COLOR0;
float2 outUV : TEXCOORD0;
float4 position : SV_Position; float4 position : SV_Position;
}; };
@ -23,15 +25,30 @@ float2 GetUV(uint bufferId, uint vertexIdx)
} }
} }
float3 GetPosition(uint bufferId, uint vertexIdx) float4 GetPosition(uint bufferId, uint vertexIdx)
{ {
return vertexBuffer[bufferId][vertexIdx].xyz; return float4(vertexBuffer[bufferId][vertexIdx].xyz, 1.0f);
}
float4 GetColor(uint bufferId, uint vertexIdx)
{
return (bufferId != INVALID_HANDLE) ? colorBuffer[bufferId][vertexIdx] : float4(1.0f, 0.0f, 1.0f, 1.0f);
}
float4x4 GetModel(uint bufferId, uint index)
{
return nodeBuffer[bufferId][index].transform;
} }
VS_Output main(VS_Input stage_input) VS_Output main(VS_Input stage_input)
{ {
VS_Output stage_output; VS_Output output;
stage_output.outUV = GetUV(pcb.uvBufferHandle, stage_input.vertexIndex); output.outPosition = GetPosition(pcb.vertexBufferHandle, stage_input.vertexIndex);
stage_output.position = mul(float4(GetPosition(pcb.vertexBufferHandle, stage_input.vertexIndex), 1.0f), mul(camera.model, mul(camera.view, camera.proj))); output.outUV = GetUV(pcb.uvBufferHandle, stage_input.vertexIndex);
return stage_output; output.outColor = GetColor(pcb.colorHandle, stage_input.vertexIndex);
float4 globalPosition = mul(camera.model, mul(GetModel(pcb.nodeBufferHandle, pcb.m_NodeIdx), GetPosition(pcb.vertexBufferHandle, stage_input.vertexIndex)));
float4 clipSpace = mul(camera.view, globalPosition);
output.position = mul(camera.proj, clipSpace);
return output;
} }