Extended testing for vertices.

This commit is contained in:
Anish Bhobe 2024-07-15 00:20:37 +02:00
parent 362468ebe7
commit 0092ce4c9e
6 changed files with 220 additions and 286 deletions

View File

@ -23,6 +23,13 @@ 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;
auto usage = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst;
if (isMipmapped)
{
usage |= vk::ImageUsageFlagBits::eTransferSrc;
}
vk::ImageCreateInfo imageCreateInfo = { vk::ImageCreateInfo imageCreateInfo = {
.imageType = vk::ImageType::e2D, .imageType = vk::ImageType::e2D,
.format = imageFormat, .format = imageFormat,
@ -31,7 +38,7 @@ Texture::Init(const Device *device, const vk::Extent2D extent, vk::Format imageF
.arrayLayers = 1, .arrayLayers = 1,
.samples = vk::SampleCountFlagBits::e1, .samples = vk::SampleCountFlagBits::e1,
.tiling = vk::ImageTiling::eOptimal, .tiling = vk::ImageTiling::eOptimal,
.usage = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst, .usage = usage,
.sharingMode = vk::SharingMode::eExclusive, .sharingMode = vk::SharingMode::eExclusive,
.initialLayout = vk::ImageLayout::eUndefined, .initialLayout = vk::ImageLayout::eUndefined,
}; };

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

Binary file not shown.

View File

@ -52,8 +52,11 @@ ModelLoader::LoadImage(vk::CommandBuffer commandBuffer, Texture *texture, Stagin
{ {
assert(image->component == 4); assert(image->component == 4);
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->Write(m_ResourceManager->m_Device, 0, byteSize, image->image.data());
// .srcAccessMask = , // .srcAccessMask = ,
// .dstAccessMask = , // .dstAccessMask = ,
@ -144,7 +147,8 @@ ModelLoader::LoadImage(vk::CommandBuffer commandBuffer, Texture *texture, Stagin
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);
for (u32 prevMipLevel = 1; prevMipLevel < texture->m_MipLevels; ++prevMipLevel) u32 maxPrevMip = texture->m_MipLevels - 1;
for (u32 prevMipLevel = 0; prevMipLevel < maxPrevMip; ++prevMipLevel)
{ {
i32 currentMipWidth = calcNextMip(prevMipWidth); i32 currentMipWidth = calcNextMip(prevMipWidth);
i32 currentMipHeight = calcNextMip(prevMipHeight); i32 currentMipHeight = calcNextMip(prevMipHeight);
@ -177,21 +181,24 @@ ModelLoader::LoadImage(vk::CommandBuffer commandBuffer, Texture *texture, Stagin
}, },
}; };
nextMipBarrier.subresourceRange.baseMipLevel = prevMipLevel; 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);
prevMipHeight = currentMipHeight;
prevMipWidth = currentMipWidth;
} }
commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTopOfPipe, {}, 0, commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {},
nullptr, 0, nullptr, 1, &imageReadyBarrier); 0, nullptr, 0, nullptr, 1, &imageReadyBarrier);
return m_ResourceManager->Commit(texture); return m_ResourceManager->Commit(texture);
} }
Model Model
ModelLoader::LoadModel(cstr path, cstr name) ModelLoader::LoadModel(cstr path, cstr name, bool batched)
{ {
namespace fs = std::filesystem; namespace fs = std::filesystem;
tinygltf::Model model; tinygltf::Model model;
@ -222,17 +229,9 @@ ModelLoader::LoadModel(cstr path, cstr name)
} }
} }
vk::CommandBuffer commandBuffer;
{ {
vk::CommandBufferAllocateInfo commandBufferAllocateInfo = {
.commandPool = m_CommandPool,
.level = vk::CommandBufferLevel::ePrimary,
.commandBufferCount = 1,
};
AbortIfFailed(pDevice->m_Device.allocateCommandBuffers(&commandBufferAllocateInfo, &commandBuffer));
vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit}; vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
AbortIfFailed(commandBuffer.begin(&beginInfo)); AbortIfFailed(m_CommandBuffer.begin(&beginInfo));
} }
eastl::vector<StagingBuffer> stagingBuffers; eastl::vector<StagingBuffer> stagingBuffers;
@ -252,10 +251,8 @@ ModelLoader::LoadModel(cstr path, cstr name)
auto imagePtr = model.images.data(); auto imagePtr = model.images.data();
for (TextureHandle &handle : textureHandles) for (TextureHandle &handle : textureHandles)
{ {
handle = LoadImage(commandBuffer, texturePtr++, stagingPtr++, imagePtr++); handle = LoadImage(m_CommandBuffer, texturePtr++, stagingPtr++, imagePtr++);
} }
AbortIfFailed(commandBuffer.end());
} }
eastl::vector<Material> materials; eastl::vector<Material> materials;
@ -297,25 +294,32 @@ ModelLoader::LoadModel(cstr path, cstr name)
materialStaging.Write(pDevice, 0, materialsByteSize, materials.data()); materialStaging.Write(pDevice, 0, materialsByteSize, materials.data());
vk::BufferCopy bufferCopy = {.srcOffset = 0, .dstOffset = 0, .size = materialsByteSize}; vk::BufferCopy bufferCopy = {.srcOffset = 0, .dstOffset = 0, .size = materialsByteSize};
commandBuffer.copyBuffer(materialStaging.m_Buffer, materialsBuffer.m_Buffer, 1, &bufferCopy); m_CommandBuffer.copyBuffer(materialStaging.m_Buffer, materialsBuffer.m_Buffer, 1, &bufferCopy);
} }
// TODO: Mesh reordering based on nodes AND OR meshoptimizer // TODO: Mesh reordering based on nodes AND OR meshoptimizer
// TODO: Support scenes // TODO: Support scenes
eastl::vector<vec4> vertexPositions; eastl::vector<vec4> vertexPositions;
eastl::vector<vec4> normalVectors;
eastl::vector<vec2> texCoord0;
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());
u32 vertexOffset = 0;
i32 normalOffset = 0;
i32 texCoord0Offset = 0;
u32 indexOffset = 0;
for (auto &mesh : model.meshes) for (auto &mesh : model.meshes)
{ {
for (auto &prim : mesh.primitives) for (auto &prim : mesh.primitives)
{ {
u32 vertexOffset = Cast<u32>(vertexPositions.size()); u32 vertexCount = 0;
u32 vertexCount; u32 indexCount = 0;
u32 indexOffset = Cast<u32>(indices.size()); i32 normalCount = 0;
u32 indexCount; i32 texCoord0Count = 0;
assert(prim.attributes.contains(APosition)); assert(prim.attributes.contains(APosition));
assert(prim.mode == TINYGLTF_MODE_TRIANGLES); assert(prim.mode == TINYGLTF_MODE_TRIANGLES);
@ -354,6 +358,65 @@ ModelLoader::LoadModel(cstr path, cstr name)
} }
} }
// Normal Coords
if (prim.attributes.contains(ANormal))
{
tinygltf::Accessor *normAccessor = &model.accessors[prim.attributes[ANormal]];
assert(normAccessor->count <= MaxValue<u32>);
tinygltf::BufferView *normBufferView = &model.bufferViews[normAccessor->bufferView];
tinygltf::Buffer *normBuffer = &model.buffers[normBufferView->buffer];
usize byteOffset = (normAccessor->byteOffset + normBufferView->byteOffset);
normalCount = Cast<i32>(normAccessor->count);
normalVectors.reserve(vertexPositions.size());
if (normAccessor->type == TINYGLTF_TYPE_VEC4)
{
vec4 *data = Recast<vec4 *>(normBuffer->data.data() + byteOffset);
normalVectors.insert(normalVectors.end(), data, data + vertexCount);
}
else if (normAccessor->type == TINYGLTF_TYPE_VEC3)
{
vec3 *data = Recast<vec3 *>(normBuffer->data.data() + byteOffset);
for (u32 i = 0; i < vertexCount; ++i)
{
normalVectors.push_back(vec4(data[i], 1.0f));
}
}
else if (normAccessor->type == TINYGLTF_TYPE_VEC2)
{
vec2 *data = Recast<vec2 *>(normBuffer->data.data() + byteOffset);
for (u32 i = 0; i < vertexCount; ++i)
{
normalVectors.push_back(vec4(data[i], 0.0f, 1.0f));
}
}
}
// UV0
if (prim.attributes.contains(ATexCoord0))
{
tinygltf::Accessor *uvAccessor = &model.accessors[prim.attributes[ATexCoord0]];
assert(uvAccessor->count <= MaxValue<u32>);
tinygltf::BufferView *uvBufferView = &model.bufferViews[uvAccessor->bufferView];
tinygltf::Buffer *uvBuffer = &model.buffers[uvBufferView->buffer];
usize byteOffset = (uvAccessor->byteOffset + uvBufferView->byteOffset);
texCoord0Count = Cast<i32>(uvAccessor->count);
texCoord0.reserve(vertexPositions.size());
assert(uvAccessor->type == TINYGLTF_TYPE_VEC2);
{
vec2 *data = Recast<vec2 *>(uvBuffer->data.data() + byteOffset);
texCoord0.insert(texCoord0.end(), data, data + vertexCount);
}
}
// Indices
if (prim.indices >= 0) if (prim.indices >= 0)
{ {
tinygltf::Accessor *indexAccessor = &model.accessors[prim.indices]; tinygltf::Accessor *indexAccessor = &model.accessors[prim.indices];
@ -395,10 +458,20 @@ ModelLoader::LoadModel(cstr path, cstr name)
meshPrimitives.push_back({ meshPrimitives.push_back({
.m_VertexOffset = vertexOffset, .m_VertexOffset = vertexOffset,
.m_NormalOffset = normalCount > 0 ? normalOffset : -1,
.m_TexCoord0Offset = texCoord0Count > 0 ? texCoord0Offset : -1,
.m_FirstIndex = indexOffset, .m_FirstIndex = indexOffset,
.m_IndexCount = indexCount, .m_IndexCount = indexCount,
.m_MaterialIdx = prim.material, .m_MaterialIdx = prim.material,
}); });
vertexOffset += vertexCount;
indexOffset += indexCount;
texCoord0Offset += texCoord0Count;
normalOffset += normalCount;
assert(normalVectors.empty() || normalVectors.size() == vertexPositions.size());
assert(texCoord0.empty() || texCoord0.size() == vertexPositions.size());
} }
} }
@ -406,32 +479,66 @@ ModelLoader::LoadModel(cstr path, cstr name)
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);
StorageBuffer normalBuffer;
BufferHandle normalBufferHandle;
if (!normalVectors.empty())
{
normalBuffer.Init(pDevice, normalVectors.size() * sizeof normalVectors[0], false);
normalBufferHandle = m_ResourceManager->Commit(&normalBuffer);
}
StorageBuffer texCoord0Buffer;
BufferHandle texCoord0BufferHandle;
if (!texCoord0.empty())
{
texCoord0Buffer.Init(pDevice, texCoord0.size() * sizeof texCoord0[0], false);
texCoord0BufferHandle = m_ResourceManager->Commit(&texCoord0Buffer);
}
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}; vk::BufferCopy bufferCopy = {.srcOffset = 0, .dstOffset = 0};
StagingBuffer &positionStaging = stagingBuffers.push_back();
positionStaging.Init(pDevice, positionBuffer.GetSize());
positionStaging.Write(pDevice, 0, positionBuffer.GetSize(), vertexPositions.data());
bufferCopy.size = positionBuffer.GetSize(); bufferCopy.size = positionBuffer.GetSize();
commandBuffer.copyBuffer(positionStaging.m_Buffer, positionBuffer.m_Buffer, 1, &bufferCopy); 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())
{
bufferCopy.size = normalBuffer.GetSize();
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())
{
bufferCopy.size = texCoord0Buffer.GetSize();
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);
}
StagingBuffer &indexStaging = stagingBuffers.push_back();
indexStaging.Init(pDevice, indexBuffer.GetSize());
indexStaging.Write(pDevice, 0, indexBuffer.GetSize(), indices.data());
bufferCopy.size = indexBuffer.GetSize(); bufferCopy.size = indexBuffer.GetSize();
commandBuffer.copyBuffer(indexStaging.m_Buffer, indexBuffer.m_Buffer, 1, &bufferCopy); StagingBuffer &indexStaging = stagingBuffers.push_back();
indexStaging.Init(pDevice, bufferCopy.size);
indexStaging.Write(pDevice, 0, bufferCopy.size, indices.data());
m_CommandBuffer.copyBuffer(indexStaging.m_Buffer, indexBuffer.m_Buffer, 1, &bufferCopy);
} }
AbortIfFailed(commandBuffer.end()); AbortIfFailed(m_CommandBuffer.end());
vk::SubmitInfo submitInfo = { vk::SubmitInfo submitInfo = {
.waitSemaphoreCount = 0, .waitSemaphoreCount = 0,
.pWaitDstStageMask = 0, .pWaitDstStageMask = nullptr,
.commandBufferCount = 1, .commandBufferCount = 1,
.pCommandBuffers = &commandBuffer, .pCommandBuffers = &m_CommandBuffer,
}; };
vk::Fence fence; vk::Fence fence;
@ -441,20 +548,25 @@ ModelLoader::LoadModel(cstr path, cstr name)
AbortIfFailed(pDevice->m_Device.waitForFences(1, &fence, true, MaxValue<u32>)); AbortIfFailed(pDevice->m_Device.waitForFences(1, &fence, true, MaxValue<u32>));
pDevice->m_Device.destroy(fence, nullptr); pDevice->m_Device.destroy(fence, nullptr);
AbortIfFailed(pDevice->m_Device.resetCommandPool(
m_CommandPool, batched ? vk::CommandPoolResetFlags{} : vk::CommandPoolResetFlagBits::eReleaseResources));
for (auto &buffer : stagingBuffers) for (auto &buffer : stagingBuffers)
{ {
buffer.Destroy(pDevice); buffer.Destroy(pDevice);
} }
return Model{m_ResourceManager, std::move(textures), std::move(textureHandles), return Model{m_ResourceManager, std::move(textures), std::move(textureHandles), materialsBuffer,
materialsBuffer, materialsHandle, positionBuffer, materialsHandle, positionBuffer, positionBufferHandle, normalBuffer,
positionBufferHandle, indexBuffer, meshPrimitives}; normalBufferHandle, texCoord0Buffer, texCoord0BufferHandle, indexBuffer,
meshPrimitives};
} }
Model::Model(RenderResourceManager *resourceManager, eastl::vector<Texture> &&textures, Model::Model(RenderResourceManager *resourceManager, eastl::vector<Texture> &&textures,
eastl::vector<TextureHandle> &&textureHandles, const StorageBuffer &materialsBuffer, eastl::vector<TextureHandle> &&textureHandles, const StorageBuffer &materialsBuffer,
BufferHandle materialsHandle, const StorageBuffer &vertexPosBuffer, BufferHandle vertexPosHandle, BufferHandle materialsHandle, const StorageBuffer &vertexPosBuffer, BufferHandle vertexPosHandle,
const IndexBuffer &indexBuffer, const eastl::vector<MeshPrimitive> &meshPrimitives) const StorageBuffer &normalBuffer, BufferHandle normalHandle, const StorageBuffer &uv0Buffer,
BufferHandle uv0Handle, const IndexBuffer &indexBuffer, const eastl::vector<MeshPrimitive> &meshPrimitives)
: m_ResourceManager(resourceManager) : m_ResourceManager(resourceManager)
, m_Textures(textures) , m_Textures(textures)
, m_TextureHandles(textureHandles) , m_TextureHandles(textureHandles)
@ -462,6 +574,10 @@ Model::Model(RenderResourceManager *resourceManager, eastl::vector<Texture> &&te
, m_MaterialsHandle(materialsHandle) , m_MaterialsHandle(materialsHandle)
, m_VertexPositions(vertexPosBuffer) , m_VertexPositions(vertexPosBuffer)
, m_VertexPositionHandle(vertexPosHandle) , m_VertexPositionHandle(vertexPosHandle)
, m_NormalVectors(normalBuffer)
, m_NormalHandle(normalHandle)
, m_TexCoord0(uv0Buffer)
, m_TexCoord0Handle(uv0Handle)
, m_IndexBuffer(indexBuffer) , m_IndexBuffer(indexBuffer)
, m_MeshPrimitives(meshPrimitives) , m_MeshPrimitives(meshPrimitives)
{ {
@ -475,6 +591,10 @@ Model::Model(Model &&other) noexcept
, m_MaterialsHandle(other.m_MaterialsHandle) , m_MaterialsHandle(other.m_MaterialsHandle)
, m_VertexPositions(other.m_VertexPositions) , 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_TexCoord0(other.m_TexCoord0)
, m_TexCoord0Handle(other.m_TexCoord0Handle)
, m_IndexBuffer(other.m_IndexBuffer) , m_IndexBuffer(other.m_IndexBuffer)
, m_MeshPrimitives(std::move(other.m_MeshPrimitives)) , m_MeshPrimitives(std::move(other.m_MeshPrimitives))
{ {
@ -492,6 +612,10 @@ Model::operator=(Model &&other) noexcept
m_MaterialsHandle = other.m_MaterialsHandle; m_MaterialsHandle = other.m_MaterialsHandle;
m_VertexPositions = other.m_VertexPositions; 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_TexCoord0 = other.m_TexCoord0;
m_TexCoord0Handle = other.m_TexCoord0Handle;
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;
@ -504,8 +628,12 @@ Model::~Model()
m_VertexPositions.Destroy(m_ResourceManager->m_Device); 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_TexCoord0.Destroy(m_ResourceManager->m_Device);
m_ResourceManager->Release(m_VertexPositionHandle); m_ResourceManager->Release(m_VertexPositionHandle);
m_ResourceManager->Release(m_NormalHandle);
m_ResourceManager->Release(m_TexCoord0Handle);
for (const TextureHandle &handle : m_TextureHandles) for (const TextureHandle &handle : m_TextureHandles)
{ {
m_ResourceManager->Release(handle); m_ResourceManager->Release(handle);
@ -518,12 +646,30 @@ Model::~Model()
m_MaterialsBuffer.Destroy(m_ResourceManager->m_Device); m_MaterialsBuffer.Destroy(m_ResourceManager->m_Device);
} }
ModelLoader::ModelLoader(RenderResourceManager *resourceManager, vk::CommandPool commandPool, vk::Queue transferQueue, ModelLoader::ModelLoader(RenderResourceManager *resourceManager, vk::Queue transferQueue, u32 transferQueueIndex,
u32 transferQueueIndex, u32 graphicsQueueIndex) u32 graphicsQueueIndex)
: m_ResourceManager(resourceManager) : m_ResourceManager(resourceManager)
, m_CommandPool(commandPool)
, 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 vk::CommandPoolCreateInfo poolCreateInfo = {
.flags = vk::CommandPoolCreateFlagBits::eTransient,
.queueFamilyIndex = transferQueueIndex,
};
AbortIfFailedM(pDevice->m_Device.createCommandPool(&poolCreateInfo, nullptr, &m_CommandPool),
"Transfer command pool creation failed.");
const vk::CommandBufferAllocateInfo commandBufferAllocateInfo = {
.commandPool = m_CommandPool,
.level = vk::CommandBufferLevel::ePrimary,
.commandBufferCount = 1,
};
AbortIfFailed(pDevice->m_Device.allocateCommandBuffers(&commandBufferAllocateInfo, &m_CommandBuffer));
}
ModelLoader::~ModelLoader()
{
m_ResourceManager->m_Device->m_Device.destroy(m_CommandPool, nullptr);
} }

View File

@ -22,9 +22,11 @@ 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_TexCoord0Offset; // <0 for invalid
u32 m_FirstIndex; u32 m_FirstIndex;
u32 m_IndexCount; u32 m_IndexCount;
i32 m_MaterialIdx; // -1 for invalid i32 m_MaterialIdx; // <0 for invalid
}; };
struct Material struct Material
@ -43,19 +45,30 @@ struct Material
struct Model struct Model
{ {
RenderResourceManager *m_ResourceManager; RenderResourceManager *m_ResourceManager;
eastl::vector<Texture> m_Textures; eastl::vector<Texture> m_Textures;
eastl::vector<TextureHandle> m_TextureHandles; eastl::vector<TextureHandle> m_TextureHandles;
StorageBuffer m_MaterialsBuffer; StorageBuffer m_MaterialsBuffer;
BufferHandle m_MaterialsHandle; BufferHandle m_MaterialsHandle;
StorageBuffer m_VertexPositions; StorageBuffer m_VertexPositions;
BufferHandle m_VertexPositionHandle; BufferHandle m_VertexPositionHandle;
StorageBuffer m_NormalVectors;
BufferHandle m_NormalHandle;
StorageBuffer m_TexCoord0;
BufferHandle m_TexCoord0Handle;
IndexBuffer m_IndexBuffer; IndexBuffer m_IndexBuffer;
eastl::vector<MeshPrimitive> m_MeshPrimitives; eastl::vector<MeshPrimitive> m_MeshPrimitives;
Model(RenderResourceManager *resourceManager, eastl::vector<Texture> &&textures, Model(RenderResourceManager *resourceManager, eastl::vector<Texture> &&textures,
eastl::vector<TextureHandle> &&textureHandles, const StorageBuffer &materialsBuffer, eastl::vector<TextureHandle> &&textureHandles, const StorageBuffer &materialsBuffer,
BufferHandle materialsHandle, const StorageBuffer &vertexPosBuffer, BufferHandle vertexPosHandle, BufferHandle materialsHandle, const StorageBuffer &vertexPosBuffer, BufferHandle vertexPosHandle,
const IndexBuffer &indexBuffer, const eastl::vector<MeshPrimitive> &meshPrimitives); 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;
@ -69,16 +82,18 @@ struct ModelLoader
{ {
RenderResourceManager *const m_ResourceManager; RenderResourceManager *const m_ResourceManager;
vk::CommandPool m_CommandPool; vk::CommandPool m_CommandPool;
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::CommandPool commandPool, vk::Queue transferQueue, ModelLoader(RenderResourceManager *resourceManager, vk::Queue transferQueue, u32 transferQueueIndex,
u32 transferQueueIndex, u32 graphicsQueueIndex); u32 graphicsQueueIndex);
~ModelLoader();
TextureHandle TextureHandle
LoadImage(vk::CommandBuffer commandBuffer, Texture *texture, StagingBuffer *stagingBuffer, tinygltf::Image *image); LoadImage(vk::CommandBuffer commandBuffer, Texture *texture, StagingBuffer *stagingBuffer, tinygltf::Image *image);
Model LoadModel(cstr path, cstr name = nullptr); Model LoadModel(cstr path, cstr name = nullptr, bool batched = false);
constexpr static auto ANormal = "NORMAL"; constexpr static auto ANormal = "NORMAL";
constexpr static auto APosition = "POSITION"; constexpr static auto APosition = "POSITION";

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/Box.glb"; constexpr auto MODEL_FILE = "model/BoxTextured.glb";
struct ImageFile struct ImageFile
{ {
@ -87,27 +87,7 @@ main(int, char **)
Swapchain swapchain = {&window, &device, "Primary Chain"}; Swapchain swapchain = {&window, &device, "Primary Chain"};
RenderResourceManager resourceManager = {&device, 1000}; RenderResourceManager resourceManager = {&device, 1000};
vk::CommandPool copyPool; ModelLoader modelLoader = {&resourceManager, commandQueue, queueAllocation.m_Family, queueAllocation.m_Family};
vk::CommandBuffer copyBuffer;
{
vk::CommandPoolCreateInfo poolCreateInfo = {
.flags = vk::CommandPoolCreateFlagBits::eTransient,
.queueFamilyIndex = queueAllocation.m_Family,
};
AbortIfFailedM(device.m_Device.createCommandPool(&poolCreateInfo, nullptr, &copyPool),
"Copy command pool creation failed.");
vk::CommandBufferAllocateInfo bufferAllocateInfo = {
.commandPool = copyPool,
.level = vk::CommandBufferLevel::ePrimary,
.commandBufferCount = 1,
};
AbortIfFailedM(device.m_Device.allocateCommandBuffers(&bufferAllocateInfo, &copyBuffer),
"Copy command buffer allocation failed.");
}
ModelLoader modelLoader = {&resourceManager, copyPool, commandQueue, queueAllocation.m_Family,
queueAllocation.m_Family};
auto model = modelLoader.LoadModel(MODEL_FILE); auto model = modelLoader.LoadModel(MODEL_FILE);
@ -130,10 +110,6 @@ main(int, char **)
.type = vk::DescriptorType::eUniformBuffer, .type = vk::DescriptorType::eUniformBuffer,
.descriptorCount = 1, .descriptorCount = 1,
}, },
vk::DescriptorPoolSize{
.type = vk::DescriptorType::eCombinedImageSampler,
.descriptorCount = 1,
},
}; };
vk::DescriptorPoolCreateInfo descriptorPoolCreateInfo = { vk::DescriptorPoolCreateInfo descriptorPoolCreateInfo = {
.maxSets = 1, .poolSizeCount = Cast<u32>(poolSizes.size()), .pPoolSizes = poolSizes.data()}; .maxSets = 1, .poolSizeCount = Cast<u32>(poolSizes.size()), .pPoolSizes = poolSizes.data()};
@ -147,195 +123,6 @@ main(int, char **)
AbortIfFailed(device.m_Device.allocateDescriptorSets(&descriptorSetAllocateInfo, &descriptorSet)); AbortIfFailed(device.m_Device.allocateDescriptorSets(&descriptorSetAllocateInfo, &descriptorSet));
} }
eastl::array vertices = {
Vertex{.m_Position = vec3(0.5f, 0.5f, -0.5f), .m_TexCoord0 = vec2(1.0f, 1.0f)},
Vertex{.m_Position = vec3(0.5f, -0.5f, -0.5f), .m_TexCoord0 = vec2(1.0f, 0.0f)},
Vertex{.m_Position = vec3(-0.5f, -0.5f, -0.5f), .m_TexCoord0 = vec2(0.0f, 0.0f)},
Vertex{.m_Position = vec3(-0.5f, -0.5f, -0.5f), .m_TexCoord0 = vec2(0.0f, 0.0f)},
Vertex{.m_Position = vec3(-0.5f, 0.5f, -0.5f), .m_TexCoord0 = vec2(0.0f, 1.0f)},
Vertex{.m_Position = vec3(0.5f, 0.5f, -0.5f), .m_TexCoord0 = vec2(1.0f, 1.0f)},
Vertex{.m_Position = vec3(-0.5f, -0.5f, 0.5f), .m_TexCoord0 = vec2(0.0f, 0.0f)},
Vertex{.m_Position = vec3(0.5f, -0.5f, 0.5f), .m_TexCoord0 = vec2(1.0f, 0.0f)},
Vertex{.m_Position = vec3(0.5f, 0.5f, 0.5f), .m_TexCoord0 = vec2(1.0f, 1.0f)},
Vertex{.m_Position = vec3(0.5f, 0.5f, 0.5f), .m_TexCoord0 = vec2(1.0f, 1.0f)},
Vertex{.m_Position = vec3(-0.5f, 0.5f, 0.5f), .m_TexCoord0 = vec2(0.0f, 1.0f)},
Vertex{.m_Position = vec3(-0.5f, -0.5f, 0.5f), .m_TexCoord0 = vec2(0.0f, 0.0f)},
Vertex{.m_Position = vec3(-0.5f, 0.5f, 0.5f), .m_TexCoord0 = vec2(1.0f, 1.0f)},
Vertex{.m_Position = vec3(-0.5f, 0.5f, -0.5f), .m_TexCoord0 = vec2(1.0f, 0.0f)},
Vertex{.m_Position = vec3(-0.5f, -0.5f, -0.5f), .m_TexCoord0 = vec2(0.0f, 0.0f)},
Vertex{.m_Position = vec3(-0.5f, -0.5f, -0.5f), .m_TexCoord0 = vec2(0.0f, 0.0f)},
Vertex{.m_Position = vec3(-0.5f, -0.5f, 0.5f), .m_TexCoord0 = vec2(0.0f, 1.0f)},
Vertex{.m_Position = vec3(-0.5f, 0.5f, 0.5f), .m_TexCoord0 = vec2(1.0f, 1.0f)},
Vertex{.m_Position = vec3(0.5f, -0.5f, -0.5f), .m_TexCoord0 = vec2(0.0f, 0.0f)},
Vertex{.m_Position = vec3(0.5f, 0.5f, -0.5f), .m_TexCoord0 = vec2(1.0f, 0.0f)},
Vertex{.m_Position = vec3(0.5f, 0.5f, 0.5f), .m_TexCoord0 = vec2(1.0f, 1.0f)},
Vertex{.m_Position = vec3(0.5f, 0.5f, 0.5f), .m_TexCoord0 = vec2(1.0f, 1.0f)},
Vertex{.m_Position = vec3(0.5f, -0.5f, 0.5f), .m_TexCoord0 = vec2(0.0f, 1.0f)},
Vertex{.m_Position = vec3(0.5f, -0.5f, -0.5f), .m_TexCoord0 = vec2(0.0f, 0.0f)},
Vertex{.m_Position = vec3(-0.5f, -0.5f, -0.5f), .m_TexCoord0 = vec2(0.0f, 0.0f)},
Vertex{.m_Position = vec3(0.5f, -0.5f, -0.5f), .m_TexCoord0 = vec2(1.0f, 0.0f)},
Vertex{.m_Position = vec3(0.5f, -0.5f, 0.5f), .m_TexCoord0 = vec2(1.0f, 1.0f)},
Vertex{.m_Position = vec3(0.5f, -0.5f, 0.5f), .m_TexCoord0 = vec2(1.0f, 1.0f)},
Vertex{.m_Position = vec3(-0.5f, -0.5f, 0.5f), .m_TexCoord0 = vec2(0.0f, 1.0f)},
Vertex{.m_Position = vec3(-0.5f, -0.5f, -0.5f), .m_TexCoord0 = vec2(0.0f, 0.0f)},
Vertex{.m_Position = vec3(0.5f, 0.5f, 0.5f), .m_TexCoord0 = vec2(1.0f, 1.0f)},
Vertex{.m_Position = vec3(0.5f, 0.5f, -0.5f), .m_TexCoord0 = vec2(1.0f, 0.0f)},
Vertex{.m_Position = vec3(-0.5f, 0.5f, -0.5f), .m_TexCoord0 = vec2(0.0f, 0.0f)},
Vertex{.m_Position = vec3(-0.5f, 0.5f, -0.5f), .m_TexCoord0 = vec2(0.0f, 0.0f)},
Vertex{.m_Position = vec3(-0.5f, 0.5f, 0.5f), .m_TexCoord0 = vec2(0.0f, 1.0f)},
Vertex{.m_Position = vec3(0.5f, 0.5f, 0.5f), .m_TexCoord0 = vec2(1.0f, 1.0f)},
};
ImageFile crateImageFile;
ImageFile plainImageFile;
assert(crateImageFile.Load("image/container.jpg"));
INFO("Image {}x{} : {} channels", crateImageFile.m_Width, crateImageFile.m_Height, crateImageFile.m_NumChannels);
assert(plainImageFile.Load({0.7f, 0.4f, 0.1f, 1.0f}));
StorageBuffer pvbo;
Texture crateTexture;
Texture plainTexture;
crateTexture.Init(&device, {crateImageFile.m_Width, crateImageFile.m_Height}, vk::Format::eR8G8B8A8Srgb, false,
"Crate Texture");
plainTexture.Init(&device, {crateImageFile.m_Width, crateImageFile.m_Height}, vk::Format::eR8G8B8A8Srgb, false,
"Plain Texture");
pvbo.Init(&device, vertices.size() * sizeof vertices[0], true, "Pull VBO");
pvbo.Write(&device, 0, pvbo.GetSize(), vertices.data());
auto crateTextureId = resourceManager.Commit(&crateTexture);
auto plainTextureId = resourceManager.Commit(&plainTexture);
auto pvboBufferId = resourceManager.Commit(&pvbo);
{
StagingBuffer imageStaging1, imageStaging2;
imageStaging1.Init(&device, crateImageFile.GetSize(), "Image Staging 1");
imageStaging1.Write(&device, 0, crateImageFile.GetSize(), crateImageFile.m_Data);
imageStaging2.Init(&device, plainImageFile.GetSize(), "Image Staging 2");
imageStaging2.Write(&device, 0, plainImageFile.GetSize(), plainImageFile.m_Data);
eastl::array imageReadyToWrite = {
vk::ImageMemoryBarrier{
.oldLayout = vk::ImageLayout::eUndefined,
.newLayout = vk::ImageLayout::eTransferDstOptimal,
.srcQueueFamilyIndex = queueAllocation.m_Family,
.dstQueueFamilyIndex = queueAllocation.m_Family,
.image = crateTexture.m_Image,
.subresourceRange =
{
.aspectMask = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
},
vk::ImageMemoryBarrier{
.oldLayout = vk::ImageLayout::eUndefined,
.newLayout = vk::ImageLayout::eTransferDstOptimal,
.srcQueueFamilyIndex = queueAllocation.m_Family,
.dstQueueFamilyIndex = queueAllocation.m_Family,
.image = plainTexture.m_Image,
.subresourceRange =
{
.aspectMask = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
},
};
eastl::array imageReadyToRead = {
vk::ImageMemoryBarrier{
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
.srcQueueFamilyIndex = queueAllocation.m_Family,
.dstQueueFamilyIndex = queueAllocation.m_Family,
.image = crateTexture.m_Image,
.subresourceRange =
{
.aspectMask = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
},
vk::ImageMemoryBarrier{
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
.srcQueueFamilyIndex = queueAllocation.m_Family,
.dstQueueFamilyIndex = queueAllocation.m_Family,
.image = plainTexture.m_Image,
.subresourceRange =
{
.aspectMask = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
},
};
vk::Fence fence;
vk::FenceCreateInfo fenceCreateInfo = {};
AbortIfFailed(device.m_Device.createFence(&fenceCreateInfo, nullptr, &fence));
vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
AbortIfFailed(copyBuffer.begin(&beginInfo));
copyBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eHost, vk::PipelineStageFlagBits::eTransfer, {}, 0,
nullptr, 0, nullptr, Cast<u32>(imageReadyToWrite.size()), imageReadyToWrite.data());
vk::BufferImageCopy imageCopy = {
.bufferOffset = 0,
.bufferRowLength = crateImageFile.m_Width,
.bufferImageHeight = crateImageFile.m_Height,
.imageSubresource =
{
.aspectMask = vk::ImageAspectFlagBits::eColor,
.mipLevel = 0,
.baseArrayLayer = 0,
.layerCount = 1,
},
.imageOffset = {},
.imageExtent = {crateImageFile.m_Width, crateImageFile.m_Height, 1},
};
copyBuffer.copyBufferToImage(imageStaging1.m_Buffer, crateTexture.m_Image, vk::ImageLayout::eTransferDstOptimal,
1, &imageCopy);
copyBuffer.copyBufferToImage(imageStaging2.m_Buffer, plainTexture.m_Image, vk::ImageLayout::eTransferDstOptimal,
1, &imageCopy);
copyBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {},
0, nullptr, 0, nullptr, Cast<u32>(imageReadyToRead.size()), imageReadyToRead.data());
AbortIfFailed(copyBuffer.end());
vk::SubmitInfo submitInfo = {
.commandBufferCount = 1,
.pCommandBuffers = &copyBuffer,
};
AbortIfFailed(commandQueue.submit(1, &submitInfo, fence));
INFO("Submit copy");
AbortIfFailed(device.m_Device.waitForFences(1, &fence, true, MaxValue<u64>));
INFO("Fence wait");
AbortIfFailedM(device.m_Device.resetCommandPool(copyPool, {}), "Couldn't reset command pool.");
device.m_Device.destroy(fence, nullptr);
imageStaging1.Destroy(&device);
imageStaging2.Destroy(&device);
}
UniformBuffer ubo; UniformBuffer ubo;
ubo.Init(&device, sizeof camera, "Camera UBO"); ubo.Init(&device, sizeof camera, "Camera UBO");
ubo.Write(&device, 0, sizeof camera, &camera); ubo.Write(&device, 0, sizeof camera, &camera);
@ -427,17 +214,6 @@ main(int, char **)
Time::Init(); Time::Init();
GpuResourceHandle *pushData = &crateTextureId;
GpuResourceHandle *otherPushData = &plainTextureId;
bool prevPressed = false;
auto isSpaceJustPressed = [&prevPressed, &window] {
const bool pressed = glfwGetKey(window.m_Window, GLFW_KEY_SPACE) == GLFW_PRESS;
const bool justPressed = pressed & !prevPressed;
prevPressed = pressed;
return justPressed;
};
struct ModelData struct ModelData
{ {
BufferHandle m_VertexBuffer; BufferHandle m_VertexBuffer;
@ -454,11 +230,6 @@ main(int, char **)
{ {
Time::Update(); Time::Update();
if (isSpaceJustPressed())
{
eastl::swap(pushData, otherPushData);
}
camera.m_Model *= rotate(mat4{1.0f}, Cast<f32>(45.0_deg * Time::m_Delta), vec3(0.0f, 1.0f, 0.0f)); camera.m_Model *= rotate(mat4{1.0f}, Cast<f32>(45.0_deg * Time::m_Delta), vec3(0.0f, 1.0f, 0.0f));
ubo.Write(&device, 0, sizeof camera, &camera); ubo.Write(&device, 0, sizeof camera, &camera);
@ -513,13 +284,9 @@ main(int, char **)
cmd.setViewport(0, 1, &viewport); cmd.setViewport(0, 1, &viewport);
cmd.setScissor(0, 1, &scissor); cmd.setScissor(0, 1, &scissor);
cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.m_Pipeline); cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.m_Pipeline);
// cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, 0, sizeof *pushData, pushData);
// cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, sizeof *pushData, sizeof pvboBufferId,
// &pvboBufferId);
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline.m_Layout, 0, 1, cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline.m_Layout, 0, 1,
&resourceManager.m_DescriptorSet, 0, nullptr); &resourceManager.m_DescriptorSet, 0, nullptr);
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline.m_Layout, 1, 1, &descriptorSet, 0, nullptr); cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline.m_Layout, 1, 1, &descriptorSet, 0, nullptr);
// cmd.draw(Cast<u32>(vertices.size()), 1, 0, 0);
cmd.bindIndexBuffer(model.m_IndexBuffer.m_Buffer, 0, vk::IndexType::eUint32); cmd.bindIndexBuffer(model.m_IndexBuffer.m_Buffer, 0, vk::IndexType::eUint32);
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, 0, sizeof modelData, &modelData); cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, 0, sizeof modelData, &modelData);
@ -561,10 +328,6 @@ main(int, char **)
} }
ubo.Destroy(&device); ubo.Destroy(&device);
device.m_Device.destroy(descriptorPool, nullptr); device.m_Device.destroy(descriptorPool, nullptr);
device.m_Device.destroy(copyPool, nullptr);
crateTexture.Destroy(&device);
plainTexture.Destroy(&device);
pvbo.Destroy(&device);
return 0; return 0;
} }

View 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 = 16, .size = 32,
}; };
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = { vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = {