Extended testing for vertices.
This commit is contained in:
parent
362468ebe7
commit
0092ce4c9e
|
|
@ -23,6 +23,13 @@ Texture::Init(const Device *device, const vk::Extent2D extent, vk::Format imageF
|
|||
const cstr name)
|
||||
{
|
||||
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 = {
|
||||
.imageType = vk::ImageType::e2D,
|
||||
.format = imageFormat,
|
||||
|
|
@ -31,7 +38,7 @@ Texture::Init(const Device *device, const vk::Extent2D extent, vk::Format imageF
|
|||
.arrayLayers = 1,
|
||||
.samples = vk::SampleCountFlagBits::e1,
|
||||
.tiling = vk::ImageTiling::eOptimal,
|
||||
.usage = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst,
|
||||
.usage = usage,
|
||||
.sharingMode = vk::SharingMode::eExclusive,
|
||||
.initialLayout = vk::ImageLayout::eUndefined,
|
||||
};
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -52,8 +52,11 @@ ModelLoader::LoadImage(vk::CommandBuffer commandBuffer, Texture *texture, Stagin
|
|||
{
|
||||
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)},
|
||||
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 = ,
|
||||
// .dstAccessMask = ,
|
||||
|
|
@ -144,7 +147,8 @@ ModelLoader::LoadImage(vk::CommandBuffer commandBuffer, Texture *texture, Stagin
|
|||
i32 prevMipWidth = Cast<i32>(texture->m_Extent.width);
|
||||
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 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,
|
||||
vk::ImageLayout::eTransferDstOptimal, 1, &blitRegion, vk::Filter::eLinear);
|
||||
commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer, {}, 0,
|
||||
nullptr, 0, nullptr, 1, &nextMipBarrier);
|
||||
|
||||
prevMipHeight = currentMipHeight;
|
||||
prevMipWidth = currentMipWidth;
|
||||
}
|
||||
|
||||
commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTopOfPipe, {}, 0,
|
||||
nullptr, 0, nullptr, 1, &imageReadyBarrier);
|
||||
commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {},
|
||||
0, nullptr, 0, nullptr, 1, &imageReadyBarrier);
|
||||
|
||||
return m_ResourceManager->Commit(texture);
|
||||
}
|
||||
|
||||
Model
|
||||
ModelLoader::LoadModel(cstr path, cstr name)
|
||||
ModelLoader::LoadModel(cstr path, cstr name, bool batched)
|
||||
{
|
||||
namespace fs = std::filesystem;
|
||||
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};
|
||||
AbortIfFailed(commandBuffer.begin(&beginInfo));
|
||||
AbortIfFailed(m_CommandBuffer.begin(&beginInfo));
|
||||
}
|
||||
|
||||
eastl::vector<StagingBuffer> stagingBuffers;
|
||||
|
|
@ -252,10 +251,8 @@ ModelLoader::LoadModel(cstr path, cstr name)
|
|||
auto imagePtr = model.images.data();
|
||||
for (TextureHandle &handle : textureHandles)
|
||||
{
|
||||
handle = LoadImage(commandBuffer, texturePtr++, stagingPtr++, imagePtr++);
|
||||
handle = LoadImage(m_CommandBuffer, texturePtr++, stagingPtr++, imagePtr++);
|
||||
}
|
||||
|
||||
AbortIfFailed(commandBuffer.end());
|
||||
}
|
||||
|
||||
eastl::vector<Material> materials;
|
||||
|
|
@ -297,25 +294,32 @@ ModelLoader::LoadModel(cstr path, cstr name)
|
|||
materialStaging.Write(pDevice, 0, materialsByteSize, materials.data());
|
||||
|
||||
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: Support scenes
|
||||
|
||||
eastl::vector<vec4> vertexPositions;
|
||||
eastl::vector<vec4> normalVectors;
|
||||
eastl::vector<vec2> texCoord0;
|
||||
eastl::vector<u32> indices;
|
||||
eastl::vector<MeshPrimitive> meshPrimitives;
|
||||
meshPrimitives.reserve(model.meshes.size());
|
||||
|
||||
u32 vertexOffset = 0;
|
||||
i32 normalOffset = 0;
|
||||
i32 texCoord0Offset = 0;
|
||||
u32 indexOffset = 0;
|
||||
|
||||
for (auto &mesh : model.meshes)
|
||||
{
|
||||
for (auto &prim : mesh.primitives)
|
||||
{
|
||||
u32 vertexOffset = Cast<u32>(vertexPositions.size());
|
||||
u32 vertexCount;
|
||||
u32 indexOffset = Cast<u32>(indices.size());
|
||||
u32 indexCount;
|
||||
u32 vertexCount = 0;
|
||||
u32 indexCount = 0;
|
||||
i32 normalCount = 0;
|
||||
i32 texCoord0Count = 0;
|
||||
|
||||
assert(prim.attributes.contains(APosition));
|
||||
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)
|
||||
{
|
||||
tinygltf::Accessor *indexAccessor = &model.accessors[prim.indices];
|
||||
|
|
@ -395,10 +458,20 @@ ModelLoader::LoadModel(cstr path, cstr name)
|
|||
|
||||
meshPrimitives.push_back({
|
||||
.m_VertexOffset = vertexOffset,
|
||||
.m_NormalOffset = normalCount > 0 ? normalOffset : -1,
|
||||
.m_TexCoord0Offset = texCoord0Count > 0 ? texCoord0Offset : -1,
|
||||
.m_FirstIndex = indexOffset,
|
||||
.m_IndexCount = indexCount,
|
||||
.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);
|
||||
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.Init(pDevice, indices.size() * sizeof indices[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();
|
||||
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);
|
||||
|
||||
StagingBuffer &indexStaging = stagingBuffers.push_back();
|
||||
indexStaging.Init(pDevice, indexBuffer.GetSize());
|
||||
indexStaging.Write(pDevice, 0, indexBuffer.GetSize(), indices.data());
|
||||
bufferCopy.size = indexBuffer.GetSize();
|
||||
commandBuffer.copyBuffer(indexStaging.m_Buffer, indexBuffer.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);
|
||||
}
|
||||
|
||||
AbortIfFailed(commandBuffer.end());
|
||||
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);
|
||||
}
|
||||
|
||||
bufferCopy.size = indexBuffer.GetSize();
|
||||
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(m_CommandBuffer.end());
|
||||
|
||||
vk::SubmitInfo submitInfo = {
|
||||
.waitSemaphoreCount = 0,
|
||||
.pWaitDstStageMask = 0,
|
||||
.pWaitDstStageMask = nullptr,
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = &commandBuffer,
|
||||
.pCommandBuffers = &m_CommandBuffer,
|
||||
};
|
||||
|
||||
vk::Fence fence;
|
||||
|
|
@ -441,20 +548,25 @@ ModelLoader::LoadModel(cstr path, cstr name)
|
|||
AbortIfFailed(pDevice->m_Device.waitForFences(1, &fence, true, MaxValue<u32>));
|
||||
pDevice->m_Device.destroy(fence, nullptr);
|
||||
|
||||
AbortIfFailed(pDevice->m_Device.resetCommandPool(
|
||||
m_CommandPool, batched ? vk::CommandPoolResetFlags{} : vk::CommandPoolResetFlagBits::eReleaseResources));
|
||||
|
||||
for (auto &buffer : stagingBuffers)
|
||||
{
|
||||
buffer.Destroy(pDevice);
|
||||
}
|
||||
|
||||
return Model{m_ResourceManager, std::move(textures), std::move(textureHandles),
|
||||
materialsBuffer, materialsHandle, positionBuffer,
|
||||
positionBufferHandle, indexBuffer, meshPrimitives};
|
||||
return Model{m_ResourceManager, std::move(textures), std::move(textureHandles), materialsBuffer,
|
||||
materialsHandle, positionBuffer, positionBufferHandle, normalBuffer,
|
||||
normalBufferHandle, texCoord0Buffer, texCoord0BufferHandle, indexBuffer,
|
||||
meshPrimitives};
|
||||
}
|
||||
|
||||
Model::Model(RenderResourceManager *resourceManager, eastl::vector<Texture> &&textures,
|
||||
eastl::vector<TextureHandle> &&textureHandles, const StorageBuffer &materialsBuffer,
|
||||
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_Textures(textures)
|
||||
, m_TextureHandles(textureHandles)
|
||||
|
|
@ -462,6 +574,10 @@ Model::Model(RenderResourceManager *resourceManager, eastl::vector<Texture> &&te
|
|||
, m_MaterialsHandle(materialsHandle)
|
||||
, m_VertexPositions(vertexPosBuffer)
|
||||
, m_VertexPositionHandle(vertexPosHandle)
|
||||
, m_NormalVectors(normalBuffer)
|
||||
, m_NormalHandle(normalHandle)
|
||||
, m_TexCoord0(uv0Buffer)
|
||||
, m_TexCoord0Handle(uv0Handle)
|
||||
, m_IndexBuffer(indexBuffer)
|
||||
, m_MeshPrimitives(meshPrimitives)
|
||||
{
|
||||
|
|
@ -475,6 +591,10 @@ Model::Model(Model &&other) noexcept
|
|||
, m_MaterialsHandle(other.m_MaterialsHandle)
|
||||
, m_VertexPositions(other.m_VertexPositions)
|
||||
, m_VertexPositionHandle(other.m_VertexPositionHandle)
|
||||
, m_NormalVectors(other.m_NormalVectors)
|
||||
, m_NormalHandle(other.m_NormalHandle)
|
||||
, m_TexCoord0(other.m_TexCoord0)
|
||||
, m_TexCoord0Handle(other.m_TexCoord0Handle)
|
||||
, m_IndexBuffer(other.m_IndexBuffer)
|
||||
, m_MeshPrimitives(std::move(other.m_MeshPrimitives))
|
||||
{
|
||||
|
|
@ -492,6 +612,10 @@ Model::operator=(Model &&other) noexcept
|
|||
m_MaterialsHandle = other.m_MaterialsHandle;
|
||||
m_VertexPositions = other.m_VertexPositions;
|
||||
m_VertexPositionHandle = other.m_VertexPositionHandle;
|
||||
m_NormalVectors = other.m_NormalVectors;
|
||||
m_NormalHandle = other.m_NormalHandle;
|
||||
m_TexCoord0 = other.m_TexCoord0;
|
||||
m_TexCoord0Handle = other.m_TexCoord0Handle;
|
||||
m_IndexBuffer = other.m_IndexBuffer;
|
||||
m_MeshPrimitives = std::move(other.m_MeshPrimitives);
|
||||
return *this;
|
||||
|
|
@ -504,8 +628,12 @@ Model::~Model()
|
|||
|
||||
m_VertexPositions.Destroy(m_ResourceManager->m_Device);
|
||||
m_IndexBuffer.Destroy(m_ResourceManager->m_Device);
|
||||
m_NormalVectors.Destroy(m_ResourceManager->m_Device);
|
||||
m_TexCoord0.Destroy(m_ResourceManager->m_Device);
|
||||
|
||||
m_ResourceManager->Release(m_VertexPositionHandle);
|
||||
m_ResourceManager->Release(m_NormalHandle);
|
||||
m_ResourceManager->Release(m_TexCoord0Handle);
|
||||
for (const TextureHandle &handle : m_TextureHandles)
|
||||
{
|
||||
m_ResourceManager->Release(handle);
|
||||
|
|
@ -518,12 +646,30 @@ Model::~Model()
|
|||
m_MaterialsBuffer.Destroy(m_ResourceManager->m_Device);
|
||||
}
|
||||
|
||||
ModelLoader::ModelLoader(RenderResourceManager *resourceManager, vk::CommandPool commandPool, vk::Queue transferQueue,
|
||||
u32 transferQueueIndex, u32 graphicsQueueIndex)
|
||||
ModelLoader::ModelLoader(RenderResourceManager *resourceManager, vk::Queue transferQueue, u32 transferQueueIndex,
|
||||
u32 graphicsQueueIndex)
|
||||
: m_ResourceManager(resourceManager)
|
||||
, m_CommandPool(commandPool)
|
||||
, m_TransferQueue(transferQueue)
|
||||
, m_TransferQueueIndex(transferQueueIndex)
|
||||
, 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);
|
||||
}
|
||||
|
|
@ -22,9 +22,11 @@ constexpr auto GLTF_BINARY_FILE_EXTENSION = ".glb";
|
|||
struct MeshPrimitive
|
||||
{
|
||||
u32 m_VertexOffset;
|
||||
i32 m_NormalOffset; // <0 for invalid
|
||||
i32 m_TexCoord0Offset; // <0 for invalid
|
||||
u32 m_FirstIndex;
|
||||
u32 m_IndexCount;
|
||||
i32 m_MaterialIdx; // -1 for invalid
|
||||
i32 m_MaterialIdx; // <0 for invalid
|
||||
};
|
||||
|
||||
struct Material
|
||||
|
|
@ -43,19 +45,30 @@ struct Material
|
|||
struct Model
|
||||
{
|
||||
RenderResourceManager *m_ResourceManager;
|
||||
|
||||
eastl::vector<Texture> m_Textures;
|
||||
eastl::vector<TextureHandle> m_TextureHandles;
|
||||
|
||||
StorageBuffer m_MaterialsBuffer;
|
||||
BufferHandle m_MaterialsHandle;
|
||||
|
||||
StorageBuffer m_VertexPositions;
|
||||
BufferHandle m_VertexPositionHandle;
|
||||
|
||||
StorageBuffer m_NormalVectors;
|
||||
BufferHandle m_NormalHandle;
|
||||
|
||||
StorageBuffer m_TexCoord0;
|
||||
BufferHandle m_TexCoord0Handle;
|
||||
|
||||
IndexBuffer m_IndexBuffer;
|
||||
eastl::vector<MeshPrimitive> m_MeshPrimitives;
|
||||
|
||||
Model(RenderResourceManager *resourceManager, eastl::vector<Texture> &&textures,
|
||||
eastl::vector<TextureHandle> &&textureHandles, const StorageBuffer &materialsBuffer,
|
||||
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 &operator=(Model &&other) noexcept;
|
||||
|
|
@ -69,16 +82,18 @@ struct ModelLoader
|
|||
{
|
||||
RenderResourceManager *const m_ResourceManager;
|
||||
vk::CommandPool m_CommandPool;
|
||||
vk::CommandBuffer m_CommandBuffer;
|
||||
vk::Queue m_TransferQueue;
|
||||
u32 m_TransferQueueIndex;
|
||||
u32 m_GraphicsQueueIndex;
|
||||
|
||||
ModelLoader(RenderResourceManager *resourceManager, vk::CommandPool commandPool, vk::Queue transferQueue,
|
||||
u32 transferQueueIndex, u32 graphicsQueueIndex);
|
||||
ModelLoader(RenderResourceManager *resourceManager, vk::Queue transferQueue, u32 transferQueueIndex,
|
||||
u32 graphicsQueueIndex);
|
||||
~ModelLoader();
|
||||
|
||||
TextureHandle
|
||||
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 APosition = "POSITION";
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
#include <filesystem>
|
||||
|
||||
constexpr u32 MAX_FRAMES_IN_FLIGHT = 3;
|
||||
constexpr auto MODEL_FILE = "model/Box.glb";
|
||||
constexpr auto MODEL_FILE = "model/BoxTextured.glb";
|
||||
|
||||
struct ImageFile
|
||||
{
|
||||
|
|
@ -87,27 +87,7 @@ main(int, char **)
|
|||
Swapchain swapchain = {&window, &device, "Primary Chain"};
|
||||
RenderResourceManager resourceManager = {&device, 1000};
|
||||
|
||||
vk::CommandPool copyPool;
|
||||
vk::CommandBuffer copyBuffer;
|
||||
|
||||
{
|
||||
vk::CommandPoolCreateInfo poolCreateInfo = {
|
||||
.flags = vk::CommandPoolCreateFlagBits::eTransient,
|
||||
.queueFamilyIndex = queueAllocation.m_Family,
|
||||
};
|
||||
AbortIfFailedM(device.m_Device.createCommandPool(&poolCreateInfo, nullptr, ©Pool),
|
||||
"Copy command pool creation failed.");
|
||||
vk::CommandBufferAllocateInfo bufferAllocateInfo = {
|
||||
.commandPool = copyPool,
|
||||
.level = vk::CommandBufferLevel::ePrimary,
|
||||
.commandBufferCount = 1,
|
||||
};
|
||||
AbortIfFailedM(device.m_Device.allocateCommandBuffers(&bufferAllocateInfo, ©Buffer),
|
||||
"Copy command buffer allocation failed.");
|
||||
}
|
||||
|
||||
ModelLoader modelLoader = {&resourceManager, copyPool, commandQueue, queueAllocation.m_Family,
|
||||
queueAllocation.m_Family};
|
||||
ModelLoader modelLoader = {&resourceManager, commandQueue, queueAllocation.m_Family, queueAllocation.m_Family};
|
||||
|
||||
auto model = modelLoader.LoadModel(MODEL_FILE);
|
||||
|
||||
|
|
@ -130,10 +110,6 @@ main(int, char **)
|
|||
.type = vk::DescriptorType::eUniformBuffer,
|
||||
.descriptorCount = 1,
|
||||
},
|
||||
vk::DescriptorPoolSize{
|
||||
.type = vk::DescriptorType::eCombinedImageSampler,
|
||||
.descriptorCount = 1,
|
||||
},
|
||||
};
|
||||
vk::DescriptorPoolCreateInfo descriptorPoolCreateInfo = {
|
||||
.maxSets = 1, .poolSizeCount = Cast<u32>(poolSizes.size()), .pPoolSizes = poolSizes.data()};
|
||||
|
|
@ -147,195 +123,6 @@ main(int, char **)
|
|||
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 = ©Buffer,
|
||||
};
|
||||
|
||||
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;
|
||||
ubo.Init(&device, sizeof camera, "Camera UBO");
|
||||
ubo.Write(&device, 0, sizeof camera, &camera);
|
||||
|
|
@ -427,17 +214,6 @@ main(int, char **)
|
|||
|
||||
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
|
||||
{
|
||||
BufferHandle m_VertexBuffer;
|
||||
|
|
@ -454,11 +230,6 @@ main(int, char **)
|
|||
{
|
||||
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));
|
||||
ubo.Write(&device, 0, sizeof camera, &camera);
|
||||
|
||||
|
|
@ -513,13 +284,9 @@ main(int, char **)
|
|||
cmd.setViewport(0, 1, &viewport);
|
||||
cmd.setScissor(0, 1, &scissor);
|
||||
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,
|
||||
&resourceManager.m_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.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, 0, sizeof modelData, &modelData);
|
||||
|
|
@ -561,10 +328,6 @@ main(int, char **)
|
|||
}
|
||||
ubo.Destroy(&device);
|
||||
device.m_Device.destroy(descriptorPool, nullptr);
|
||||
device.m_Device.destroy(copyPool, nullptr);
|
||||
crateTexture.Destroy(&device);
|
||||
plainTexture.Destroy(&device);
|
||||
pvbo.Destroy(&device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ CreatePipeline(const Device *device, const Swapchain *swapchain, const RenderRes
|
|||
vk::PushConstantRange pushConstantRange = {
|
||||
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
||||
.offset = 0,
|
||||
.size = 16,
|
||||
.size = 32,
|
||||
};
|
||||
|
||||
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
|
||||
|
|
|
|||
Loading…
Reference in New Issue