Model Vertices rendered.
This commit is contained in:
parent
93981bca4c
commit
69aa72770f
|
|
@ -91,12 +91,20 @@ UniformBuffer::Init(const Device *device, const usize size, const cstr name)
|
|||
}
|
||||
|
||||
void
|
||||
UniformStorageBuffer::Init(const Device *device, usize size, cstr name)
|
||||
StorageBuffer::Init(const Device *device, usize size, bool hostVisible, cstr name)
|
||||
{
|
||||
Allocate(device, size, vk::BufferUsageFlagBits::eStorageBuffer,
|
||||
VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT |
|
||||
VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT,
|
||||
VMA_MEMORY_USAGE_AUTO, name);
|
||||
if (hostVisible)
|
||||
{
|
||||
Allocate(device, size, vk::BufferUsageFlagBits::eStorageBuffer,
|
||||
VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT |
|
||||
VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT,
|
||||
VMA_MEMORY_USAGE_AUTO, name);
|
||||
}
|
||||
else
|
||||
{
|
||||
Allocate(device, size, vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eTransferDst,
|
||||
VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT, VMA_MEMORY_USAGE_AUTO, name);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -106,6 +114,13 @@ VertexBuffer::Init(const Device *device, usize size, cstr name)
|
|||
VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT, VMA_MEMORY_USAGE_AUTO, name);
|
||||
}
|
||||
|
||||
void
|
||||
IndexBuffer::Init(const Device *device, usize size, cstr name)
|
||||
{
|
||||
Allocate(device, size, vk::BufferUsageFlagBits::eIndexBuffer | vk::BufferUsageFlagBits::eTransferDst,
|
||||
VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT, VMA_MEMORY_USAGE_AUTO, name);
|
||||
}
|
||||
|
||||
void
|
||||
StagingBuffer::Init(const Device *device, usize size, cstr name)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -41,9 +41,9 @@ struct UniformBuffer : Buffer
|
|||
void Init(const Device *device, usize size, cstr name = nullptr);
|
||||
};
|
||||
|
||||
struct UniformStorageBuffer : Buffer
|
||||
struct StorageBuffer : Buffer
|
||||
{
|
||||
void Init(const Device *device, usize size, cstr name = nullptr);
|
||||
void Init(const Device *device, usize size, bool hostVisible, cstr name = nullptr);
|
||||
};
|
||||
|
||||
struct VertexBuffer : Buffer
|
||||
|
|
@ -52,6 +52,12 @@ struct VertexBuffer : Buffer
|
|||
void Write(const Device *device, void *data, usize size, usize offset) const = delete;
|
||||
};
|
||||
|
||||
struct IndexBuffer : Buffer
|
||||
{
|
||||
void Init(const Device *device, usize size, cstr name = nullptr);
|
||||
void Write(const Device *device, void *data, usize size, usize offset) const = delete;
|
||||
};
|
||||
|
||||
struct StagingBuffer : Buffer
|
||||
{
|
||||
void Init(const Device *device, usize size, cstr name = nullptr);
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ constexpr u32 ASTER_API_VERSION = VK_API_VERSION_1_3;
|
|||
|
||||
#define Take(ELEMENT) eastl::exchange(ELEMENT, {})
|
||||
|
||||
#define TODO(MSG) assert(false && ("Unimplemented: " MSG))
|
||||
|
||||
[[nodiscard]] inline bool
|
||||
Failed(const vk::Result result)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ Texture::Init(const Device *device, const vk::Extent2D extent, vk::Format imageF
|
|||
m_View = view;
|
||||
m_Allocation = allocation;
|
||||
m_Extent = {extent.width, extent.height, 1};
|
||||
m_MipLevels = mipLevels;
|
||||
|
||||
device->SetName(m_Image, name);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ struct Image
|
|||
vk::ImageView m_View = nullptr;
|
||||
VmaAllocation m_Allocation = nullptr;
|
||||
vk::Extent3D m_Extent;
|
||||
u8 m_MipLevels = 1;
|
||||
|
||||
[[nodiscard]] bool IsValid() const;
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ add_executable(model_render model_render.cpp
|
|||
render_resource_manager.cpp
|
||||
render_resource_manager.h
|
||||
model_loader.cpp
|
||||
model_loader.h)
|
||||
model_loader.h
|
||||
)
|
||||
add_shader(model_render shader/model.vert.glsl)
|
||||
add_shader(model_render shader/model.frag.glsl)
|
||||
|
||||
|
|
|
|||
|
|
@ -12,16 +12,183 @@
|
|||
|
||||
#include "model_loader.h"
|
||||
|
||||
#include "buffer.h"
|
||||
#include "device.h"
|
||||
#include "helpers.h"
|
||||
#include "image.h"
|
||||
#include "render_resource_manager.h"
|
||||
|
||||
#include <EASTL/array.h>
|
||||
#include <EASTL/fixed_vector.h>
|
||||
#include <EASTL/span.h>
|
||||
|
||||
vec4
|
||||
VectorToVec4(const std::vector<double> &vec)
|
||||
{
|
||||
if (vec.empty())
|
||||
{
|
||||
return vec4{0.0f};
|
||||
}
|
||||
|
||||
return {vec[0], vec[1], vec[2], vec[3]};
|
||||
}
|
||||
|
||||
TextureHandle
|
||||
ModelLoader::LoadImage(vk::CommandBuffer commandBuffer, Texture *texture, StagingBuffer *stagingBuffer,
|
||||
tinygltf::Image *image)
|
||||
{
|
||||
assert(image->component == 4);
|
||||
|
||||
texture->Init(m_ResourceManager->m_Device, {.width = Cast<u32>(image->width), .height = Cast<u32>(image->height)},
|
||||
vk::Format::eR8G8B8A8Srgb, true, image->name.data());
|
||||
|
||||
// .srcAccessMask = ,
|
||||
// .dstAccessMask = ,
|
||||
// .oldLayout = ,
|
||||
// .newLayout = ,
|
||||
// .srcQueueFamilyIndex = ,
|
||||
// .dstQueueFamilyIndex = ,
|
||||
// .image = ,
|
||||
// .subresourceRange =
|
||||
vk::ImageMemoryBarrier imageStartBarrier = {
|
||||
.srcAccessMask = vk::AccessFlagBits::eNone,
|
||||
.dstAccessMask = vk::AccessFlagBits::eTransferWrite,
|
||||
.oldLayout = vk::ImageLayout::eUndefined,
|
||||
.newLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||
.srcQueueFamilyIndex = vk::QueueFamilyIgnored,
|
||||
.dstQueueFamilyIndex = vk::QueueFamilyIgnored,
|
||||
.image = texture->m_Image,
|
||||
.subresourceRange =
|
||||
{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = texture->m_MipLevels,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
};
|
||||
|
||||
vk::ImageMemoryBarrier nextMipBarrier = {
|
||||
.srcAccessMask = vk::AccessFlagBits::eTransferWrite,
|
||||
.dstAccessMask = vk::AccessFlagBits::eTransferRead,
|
||||
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||
.newLayout = vk::ImageLayout::eTransferSrcOptimal,
|
||||
.srcQueueFamilyIndex = vk::QueueFamilyIgnored,
|
||||
.dstQueueFamilyIndex = vk::QueueFamilyIgnored,
|
||||
.image = texture->m_Image,
|
||||
.subresourceRange =
|
||||
{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
};
|
||||
|
||||
vk::ImageMemoryBarrier imageReadyBarrier = {
|
||||
.srcAccessMask = vk::AccessFlagBits::eTransferRead,
|
||||
.dstAccessMask = vk::AccessFlagBits::eShaderRead,
|
||||
.oldLayout = vk::ImageLayout::eTransferSrcOptimal,
|
||||
.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||
.srcQueueFamilyIndex = m_TransferQueueIndex,
|
||||
.dstQueueFamilyIndex = m_GraphicsQueueIndex,
|
||||
.image = texture->m_Image,
|
||||
.subresourceRange =
|
||||
{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = texture->m_MipLevels,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
};
|
||||
|
||||
vk::BufferImageCopy imageCopy = {
|
||||
.bufferOffset = 0,
|
||||
.bufferRowLength = Cast<u32>(image->width),
|
||||
.bufferImageHeight = Cast<u32>(image->height),
|
||||
.imageSubresource =
|
||||
{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.mipLevel = 0,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
.imageOffset = {},
|
||||
.imageExtent = texture->m_Extent,
|
||||
};
|
||||
|
||||
commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, 0,
|
||||
nullptr, 0, nullptr, 1, &imageStartBarrier);
|
||||
commandBuffer.copyBufferToImage(stagingBuffer->m_Buffer, texture->m_Image, vk::ImageLayout::eTransferDstOptimal, 1,
|
||||
&imageCopy);
|
||||
commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer, {}, 0,
|
||||
nullptr, 0, nullptr, 1, &nextMipBarrier);
|
||||
|
||||
auto calcNextMip = [](i32 prev) { return eastl::max(prev / 2, 1); };
|
||||
|
||||
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)
|
||||
{
|
||||
i32 currentMipWidth = calcNextMip(prevMipWidth);
|
||||
i32 currentMipHeight = calcNextMip(prevMipHeight);
|
||||
u32 currentMipLevel = prevMipLevel + 1;
|
||||
|
||||
vk::ImageBlit blitRegion = {
|
||||
.srcSubresource =
|
||||
{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.mipLevel = prevMipLevel,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
.srcOffsets =
|
||||
std::array{
|
||||
vk::Offset3D{0, 0, 0},
|
||||
vk::Offset3D{prevMipWidth, prevMipHeight, 1},
|
||||
},
|
||||
.dstSubresource =
|
||||
{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.mipLevel = currentMipLevel,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
.dstOffsets =
|
||||
std::array{
|
||||
vk::Offset3D{0, 0, 0},
|
||||
vk::Offset3D{currentMipWidth, currentMipHeight, 1},
|
||||
},
|
||||
};
|
||||
|
||||
nextMipBarrier.subresourceRange.baseMipLevel = prevMipLevel;
|
||||
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);
|
||||
}
|
||||
|
||||
commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTopOfPipe, {}, 0,
|
||||
nullptr, 0, nullptr, 1, &imageReadyBarrier);
|
||||
|
||||
return m_ResourceManager->Commit(texture);
|
||||
}
|
||||
|
||||
Model
|
||||
LoadModel(RenderResourceManager *resourceManager, cstr path)
|
||||
ModelLoader::LoadModel(cstr path, cstr name)
|
||||
{
|
||||
namespace fs = std::filesystem;
|
||||
tinygltf::Model model;
|
||||
tinygltf::TinyGLTF loader;
|
||||
|
||||
const Device *pDevice = m_ResourceManager->m_Device;
|
||||
|
||||
const auto fsPath = fs::absolute(path);
|
||||
const auto ext = fsPath.extension();
|
||||
if (ext.c_str() == GLTF_ASCII_FILE_EXTENSION)
|
||||
if (ext == GLTF_ASCII_FILE_EXTENSION)
|
||||
{
|
||||
std::string err;
|
||||
std::string warn;
|
||||
|
|
@ -31,7 +198,7 @@ LoadModel(RenderResourceManager *resourceManager, cstr path)
|
|||
ELSE_IF_WARN(!warn.empty(), "{}", warn);
|
||||
}
|
||||
}
|
||||
if (ext.c_str() == GLTF_BINARY_FILE_EXTENSION)
|
||||
if (ext == GLTF_BINARY_FILE_EXTENSION)
|
||||
{
|
||||
std::string err;
|
||||
std::string warn;
|
||||
|
|
@ -41,4 +208,309 @@ LoadModel(RenderResourceManager *resourceManager, cstr path)
|
|||
ELSE_IF_WARN(!warn.empty(), "{}", warn);
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
eastl::vector<StagingBuffer> stagingBuffers;
|
||||
eastl::vector<Texture> textures;
|
||||
eastl::vector<TextureHandle> textureHandles;
|
||||
|
||||
if (!model.images.empty())
|
||||
{
|
||||
u32 numImages = model.images.size();
|
||||
|
||||
stagingBuffers.resize(numImages);
|
||||
textures.resize(numImages);
|
||||
textureHandles.resize(numImages);
|
||||
|
||||
auto stagingPtr = stagingBuffers.data();
|
||||
auto texturePtr = textures.data();
|
||||
auto imagePtr = model.images.data();
|
||||
for (TextureHandle &handle : textureHandles)
|
||||
{
|
||||
handle = LoadImage(commandBuffer, texturePtr++, stagingPtr++, imagePtr++);
|
||||
}
|
||||
|
||||
AbortIfFailed(commandBuffer.end());
|
||||
}
|
||||
|
||||
eastl::vector<Material> materials;
|
||||
StorageBuffer materialsBuffer;
|
||||
BufferHandle materialsHandle;
|
||||
|
||||
if (!model.materials.empty())
|
||||
{
|
||||
auto getTextureHandle = [&textureHandles](i32 index) -> TextureHandle {
|
||||
if (index >= 0)
|
||||
{
|
||||
return textureHandles[index];
|
||||
}
|
||||
return {};
|
||||
};
|
||||
|
||||
materials.reserve(model.materials.size());
|
||||
for (auto &material : model.materials)
|
||||
{
|
||||
materials.push_back({
|
||||
.m_AlbedoFactor = VectorToVec4(material.pbrMetallicRoughness.baseColorFactor),
|
||||
.m_EmissionFactor = VectorToVec4(material.emissiveFactor),
|
||||
.m_MetalFactor = Cast<f32>(material.pbrMetallicRoughness.metallicFactor),
|
||||
.m_RoughFactor = Cast<f32>(material.pbrMetallicRoughness.roughnessFactor),
|
||||
.m_AlbedoTex = getTextureHandle(material.pbrMetallicRoughness.baseColorTexture.index),
|
||||
.m_NormalTex = getTextureHandle(material.normalTexture.index),
|
||||
.m_MetalRoughTex = getTextureHandle(material.pbrMetallicRoughness.metallicRoughnessTexture.index),
|
||||
.m_OcclusionTex = getTextureHandle(material.occlusionTexture.index),
|
||||
.m_EmissionTex = getTextureHandle(material.emissiveTexture.index),
|
||||
});
|
||||
}
|
||||
|
||||
usize materialsByteSize = materials.size() * sizeof materials[0];
|
||||
materialsBuffer.Init(pDevice, materialsByteSize, false, name);
|
||||
materialsHandle = m_ResourceManager->Commit(&materialsBuffer);
|
||||
|
||||
StagingBuffer &materialStaging = stagingBuffers.push_back();
|
||||
materialStaging.Init(pDevice, materialsByteSize);
|
||||
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);
|
||||
}
|
||||
|
||||
// TODO: Mesh reordering based on nodes AND OR meshoptimizer
|
||||
// TODO: Support scenes
|
||||
|
||||
eastl::vector<vec4> vertexPositions;
|
||||
eastl::vector<u32> indices;
|
||||
eastl::vector<MeshPrimitive> meshPrimitives;
|
||||
meshPrimitives.reserve(model.meshes.size());
|
||||
|
||||
for (auto &mesh : model.meshes)
|
||||
{
|
||||
for (auto &prim : mesh.primitives)
|
||||
{
|
||||
u32 vertexOffset = vertexPositions.size();
|
||||
u32 vertexCount;
|
||||
u32 indexOffset = indices.size();
|
||||
u32 indexCount;
|
||||
|
||||
assert(prim.attributes.contains(APosition));
|
||||
assert(prim.mode == TINYGLTF_MODE_TRIANGLES);
|
||||
{
|
||||
tinygltf::Accessor *posAccessor = &model.accessors[prim.attributes[APosition]];
|
||||
|
||||
assert(posAccessor->count <= MaxValue<u32>);
|
||||
|
||||
tinygltf::BufferView *posBufferView = &model.bufferViews[posAccessor->bufferView];
|
||||
tinygltf::Buffer *posBuffer = &model.buffers[posBufferView->buffer];
|
||||
usize byteOffset = (posAccessor->byteOffset + posBufferView->byteOffset);
|
||||
|
||||
vertexCount = posAccessor->count;
|
||||
vertexPositions.reserve(vertexOffset + vertexCount);
|
||||
|
||||
if (posAccessor->type == TINYGLTF_TYPE_VEC4)
|
||||
{
|
||||
vec4 *data = Recast<vec4 *>(posBuffer->data.data() + byteOffset);
|
||||
vertexPositions.insert(vertexPositions.end(), data, data + vertexCount);
|
||||
}
|
||||
else if (posAccessor->type == TINYGLTF_TYPE_VEC3)
|
||||
{
|
||||
vec3 *data = Recast<vec3 *>(posBuffer->data.data() + byteOffset);
|
||||
for (u32 i = 0; i < vertexCount; ++i)
|
||||
{
|
||||
vertexPositions.push_back(vec4(data[i], 1.0f));
|
||||
}
|
||||
}
|
||||
else if (posAccessor->type == TINYGLTF_TYPE_VEC2)
|
||||
{
|
||||
vec2 *data = Recast<vec2 *>(posBuffer->data.data() + byteOffset);
|
||||
for (u32 i = 0; i < vertexCount; ++i)
|
||||
{
|
||||
vertexPositions.push_back(vec4(data[i], 0.0f, 1.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (prim.indices >= 0)
|
||||
{
|
||||
tinygltf::Accessor *indexAccessor = &model.accessors[prim.indices];
|
||||
|
||||
assert(indexAccessor->count <= MaxValue<u32>);
|
||||
|
||||
tinygltf::BufferView *indexBufferView = &model.bufferViews[indexAccessor->bufferView];
|
||||
tinygltf::Buffer *indexBuffer = &model.buffers[indexBufferView->buffer];
|
||||
usize byteOffset = (indexAccessor->byteOffset + indexBufferView->byteOffset);
|
||||
|
||||
indexCount = indexAccessor->count;
|
||||
indices.reserve(indexOffset + indexCount);
|
||||
|
||||
if (indexAccessor->componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT)
|
||||
{
|
||||
u32 *data = Recast<u32 *>(indexBuffer->data.data() + byteOffset);
|
||||
indices.insert(indices.end(), data, data + indexCount);
|
||||
}
|
||||
else if (indexAccessor->componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT)
|
||||
{
|
||||
u16 *data = Recast<u16 *>(indexBuffer->data.data() + byteOffset);
|
||||
indices.insert(indices.end(), data, data + indexCount);
|
||||
}
|
||||
else if (indexAccessor->componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE)
|
||||
{
|
||||
u8 *data = Recast<u8 *>(indexBuffer->data.data() + byteOffset);
|
||||
indices.insert(indices.end(), data, data + indexCount);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
indexCount = vertexCount;
|
||||
indices.reserve(indexOffset + vertexCount);
|
||||
for (u32 i = 0; i < indexCount; ++i)
|
||||
{
|
||||
indices.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
meshPrimitives.push_back({
|
||||
.m_VertexOffset = vertexOffset,
|
||||
.m_FirstIndex = indexOffset,
|
||||
.m_IndexCount = indexCount,
|
||||
.m_MaterialIdx = prim.material,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
StorageBuffer positionBuffer;
|
||||
positionBuffer.Init(pDevice, vertexPositions.size() * sizeof vertexPositions[0], false);
|
||||
BufferHandle positionBufferHandle = m_ResourceManager->Commit(&positionBuffer);
|
||||
|
||||
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 &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);
|
||||
}
|
||||
|
||||
AbortIfFailed(commandBuffer.end());
|
||||
|
||||
vk::SubmitInfo submitInfo = {
|
||||
.waitSemaphoreCount = 0,
|
||||
.pWaitDstStageMask = 0,
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = &commandBuffer,
|
||||
};
|
||||
|
||||
vk::Fence fence;
|
||||
vk::FenceCreateInfo fenceCreateInfo = {};
|
||||
AbortIfFailed(pDevice->m_Device.createFence(&fenceCreateInfo, nullptr, &fence));
|
||||
AbortIfFailed(m_TransferQueue.submit(1, &submitInfo, fence));
|
||||
AbortIfFailed(pDevice->m_Device.waitForFences(1, &fence, true, MaxValue<u32>));
|
||||
pDevice->m_Device.destroy(fence, nullptr);
|
||||
|
||||
for (auto &buffer : stagingBuffers)
|
||||
{
|
||||
buffer.Destroy(pDevice);
|
||||
}
|
||||
|
||||
return Model{m_ResourceManager, std::move(textures), std::move(textureHandles),
|
||||
materialsBuffer, materialsHandle, positionBuffer,
|
||||
positionBufferHandle, 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)
|
||||
: m_ResourceManager(resourceManager)
|
||||
, m_Textures(textures)
|
||||
, m_TextureHandles(textureHandles)
|
||||
, m_MaterialsBuffer(materialsBuffer)
|
||||
, m_MaterialsHandle(materialsHandle)
|
||||
, m_VertexPositions(vertexPosBuffer)
|
||||
, m_VertexPositionHandle(vertexPosHandle)
|
||||
, m_IndexBuffer(indexBuffer)
|
||||
, m_MeshPrimitives(meshPrimitives)
|
||||
{
|
||||
}
|
||||
|
||||
Model::Model(Model &&other) noexcept
|
||||
: m_ResourceManager(Take(other.m_ResourceManager))
|
||||
, m_Textures(std::move(other.m_Textures))
|
||||
, m_TextureHandles(std::move(other.m_TextureHandles))
|
||||
, m_MaterialsBuffer(other.m_MaterialsBuffer)
|
||||
, m_MaterialsHandle(other.m_MaterialsHandle)
|
||||
, m_VertexPositions(other.m_VertexPositions)
|
||||
, m_VertexPositionHandle(other.m_VertexPositionHandle)
|
||||
, m_IndexBuffer(other.m_IndexBuffer)
|
||||
, m_MeshPrimitives(std::move(other.m_MeshPrimitives))
|
||||
{
|
||||
}
|
||||
|
||||
Model &
|
||||
Model::operator=(Model &&other) noexcept
|
||||
{
|
||||
if (this == &other)
|
||||
return *this;
|
||||
m_ResourceManager = Take(other.m_ResourceManager);
|
||||
m_Textures = std::move(other.m_Textures);
|
||||
m_TextureHandles = std::move(other.m_TextureHandles);
|
||||
m_MaterialsBuffer = other.m_MaterialsBuffer;
|
||||
m_MaterialsHandle = other.m_MaterialsHandle;
|
||||
m_VertexPositions = other.m_VertexPositions;
|
||||
m_VertexPositionHandle = other.m_VertexPositionHandle;
|
||||
m_IndexBuffer = other.m_IndexBuffer;
|
||||
m_MeshPrimitives = std::move(other.m_MeshPrimitives);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Model::~Model()
|
||||
{
|
||||
if (!m_ResourceManager)
|
||||
return;
|
||||
|
||||
m_VertexPositions.Destroy(m_ResourceManager->m_Device);
|
||||
m_IndexBuffer.Destroy(m_ResourceManager->m_Device);
|
||||
|
||||
m_ResourceManager->Release(m_VertexPositionHandle);
|
||||
for (const TextureHandle &handle : m_TextureHandles)
|
||||
{
|
||||
m_ResourceManager->Release(handle);
|
||||
}
|
||||
m_ResourceManager->Release(m_MaterialsHandle);
|
||||
for (Texture &texture : m_Textures)
|
||||
{
|
||||
texture.Destroy(m_ResourceManager->m_Device);
|
||||
}
|
||||
m_MaterialsBuffer.Destroy(m_ResourceManager->m_Device);
|
||||
}
|
||||
|
||||
ModelLoader::ModelLoader(RenderResourceManager *resourceManager, vk::CommandPool commandPool, vk::Queue transferQueue,
|
||||
u32 transferQueueIndex, u32 graphicsQueueIndex)
|
||||
: m_ResourceManager(resourceManager)
|
||||
, m_CommandPool(commandPool)
|
||||
, m_TransferQueue(transferQueue)
|
||||
, m_TransferQueueIndex(transferQueueIndex)
|
||||
, m_GraphicsQueueIndex(graphicsQueueIndex)
|
||||
{
|
||||
}
|
||||
|
|
@ -5,26 +5,86 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "constants.h"
|
||||
#include "buffer.h"
|
||||
#include "global.h"
|
||||
#include "image.h"
|
||||
|
||||
#include "render_resource_manager.h"
|
||||
|
||||
#include <EASTL/vector.h>
|
||||
#include <tiny_gltf.h>
|
||||
|
||||
struct RenderResourceManager;
|
||||
struct TextureHandle;
|
||||
struct Texture;
|
||||
|
||||
constexpr auto GLTF_ASCII_FILE_EXTENSION = ".gltf";
|
||||
constexpr auto GLTF_BINARY_FILE_EXTENSION = ".glb";
|
||||
|
||||
constexpr static auto NORMAL = "NORMAL";
|
||||
constexpr static auto POSITION = "POSITION";
|
||||
constexpr static auto TANGENT = "TANGENT";
|
||||
constexpr static auto TEXCOORD_0 = "TEXCOORD_0";
|
||||
constexpr static auto TEXCOORD_1 = "TEXCOORD_1";
|
||||
constexpr static auto JOINTS_0 = "JOINTS_0";
|
||||
constexpr static auto WEIGHTS_0 = "WEIGHTS_0";
|
||||
struct MeshPrimitive
|
||||
{
|
||||
u32 m_VertexOffset;
|
||||
u32 m_FirstIndex;
|
||||
u32 m_IndexCount;
|
||||
i32 m_MaterialIdx; // -1 for invalid
|
||||
};
|
||||
|
||||
struct Material
|
||||
{
|
||||
vec4 m_AlbedoFactor;
|
||||
vec4 m_EmissionFactor;
|
||||
f32 m_MetalFactor;
|
||||
f32 m_RoughFactor;
|
||||
TextureHandle m_AlbedoTex;
|
||||
TextureHandle m_NormalTex;
|
||||
TextureHandle m_MetalRoughTex;
|
||||
TextureHandle m_OcclusionTex;
|
||||
TextureHandle m_EmissionTex;
|
||||
};
|
||||
|
||||
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;
|
||||
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);
|
||||
|
||||
Model(Model &&other) noexcept;
|
||||
Model &operator=(Model &&other) noexcept;
|
||||
|
||||
~Model();
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Model);
|
||||
};
|
||||
|
||||
Model LoadModel(RenderResourceManager *resourceManager, cstr path);
|
||||
struct ModelLoader
|
||||
{
|
||||
RenderResourceManager *const m_ResourceManager;
|
||||
vk::CommandPool m_CommandPool;
|
||||
vk::Queue m_TransferQueue;
|
||||
u32 m_TransferQueueIndex;
|
||||
u32 m_GraphicsQueueIndex;
|
||||
|
||||
ModelLoader(RenderResourceManager *resourceManager, vk::CommandPool commandPool, vk::Queue transferQueue,
|
||||
u32 transferQueueIndex, u32 graphicsQueueIndex);
|
||||
|
||||
TextureHandle
|
||||
LoadImage(vk::CommandBuffer commandBuffer, Texture *texture, StagingBuffer *stagingBuffer, tinygltf::Image *image);
|
||||
Model LoadModel(cstr path, cstr name = nullptr);
|
||||
|
||||
constexpr static auto ANormal = "NORMAL";
|
||||
constexpr static auto APosition = "POSITION";
|
||||
constexpr static auto ATangent = "TANGENT";
|
||||
constexpr static auto ATexCoord0 = "TEXCOORD_0";
|
||||
constexpr static auto ATexCoord1 = "TEXCOORD_1";
|
||||
constexpr static auto AJoints0 = "JOINTS_0";
|
||||
constexpr static auto AWeights0 = "WEIGHTS_0";
|
||||
};
|
||||
|
|
@ -31,7 +31,7 @@ constexpr auto MODEL_FILE = "model/Box.glb";
|
|||
|
||||
struct ImageFile
|
||||
{
|
||||
void *m_Data = nullptr;
|
||||
u8 *m_Data = nullptr;
|
||||
u32 m_Width = 0;
|
||||
u32 m_Height = 0;
|
||||
u32 m_NumChannels = 0;
|
||||
|
|
@ -85,7 +85,31 @@ main(int, char **)
|
|||
Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"};
|
||||
vk::Queue commandQueue = device.GetQueue(queueAllocation.m_Family, 0);
|
||||
Swapchain swapchain = {&window, &device, "Primary Chain"};
|
||||
RenderResourceManager resourceManager(&device, 10);
|
||||
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};
|
||||
|
||||
auto model = modelLoader.LoadModel(MODEL_FILE);
|
||||
|
||||
Pipeline pipeline = CreatePipeline(&device, &swapchain, &resourceManager);
|
||||
|
||||
|
|
@ -123,25 +147,6 @@ main(int, char **)
|
|||
AbortIfFailed(device.m_Device.allocateDescriptorSets(&descriptorSetAllocateInfo, &descriptorSet));
|
||||
}
|
||||
|
||||
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.");
|
||||
}
|
||||
|
||||
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)},
|
||||
|
|
@ -192,14 +197,14 @@ main(int, char **)
|
|||
INFO("Image {}x{} : {} channels", crateImageFile.m_Width, crateImageFile.m_Height, crateImageFile.m_NumChannels);
|
||||
assert(plainImageFile.Load({0.7f, 0.4f, 0.1f, 1.0f}));
|
||||
|
||||
UniformStorageBuffer pvbo;
|
||||
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], "Pull VBO");
|
||||
pvbo.Init(&device, vertices.size() * sizeof vertices[0], true, "Pull VBO");
|
||||
pvbo.Write(&device, 0, pvbo.GetSize(), vertices.data());
|
||||
|
||||
auto crateTextureId = resourceManager.Commit(&crateTexture);
|
||||
|
|
@ -308,7 +313,6 @@ main(int, char **)
|
|||
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());
|
||||
|
||||
|
|
@ -423,8 +427,8 @@ main(int, char **)
|
|||
|
||||
Time::Init();
|
||||
|
||||
Handle *pushData = &crateTextureId;
|
||||
Handle *otherPushData = &plainTextureId;
|
||||
GpuResourceHandle *pushData = &crateTextureId;
|
||||
GpuResourceHandle *otherPushData = &plainTextureId;
|
||||
|
||||
bool prevPressed = false;
|
||||
auto isSpaceJustPressed = [&prevPressed, &window] {
|
||||
|
|
@ -434,6 +438,17 @@ main(int, char **)
|
|||
return justPressed;
|
||||
};
|
||||
|
||||
struct ModelData
|
||||
{
|
||||
BufferHandle m_VertexBuffer;
|
||||
BufferHandle m_Materials;
|
||||
};
|
||||
|
||||
ModelData modelData = {
|
||||
.m_VertexBuffer = model.m_VertexPositionHandle,
|
||||
.m_Materials = model.m_MaterialsHandle,
|
||||
};
|
||||
|
||||
INFO("Starting loop");
|
||||
while (window.Poll())
|
||||
{
|
||||
|
|
@ -498,13 +513,23 @@ 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.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.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);
|
||||
|
||||
for (auto &prim : model.m_MeshPrimitives)
|
||||
{
|
||||
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, sizeof modelData,
|
||||
sizeof prim.m_MaterialIdx, &prim.m_MaterialIdx);
|
||||
cmd.drawIndexed(prim.m_IndexCount, 1, prim.m_FirstIndex, Cast<i32>(prim.m_VertexOffset), 0);
|
||||
}
|
||||
|
||||
cmd.endRendering();
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "global.h"
|
||||
#include "pipeline.h"
|
||||
|
||||
#include <EASTL/array.h>
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ RenderResourceManager::WriteInfo::WriteInfo(vk::BufferView info)
|
|||
}
|
||||
|
||||
BufferHandle
|
||||
RenderResourceManager::Commit(const UniformStorageBuffer *storageBuffer)
|
||||
RenderResourceManager::Commit(const StorageBuffer *storageBuffer)
|
||||
{
|
||||
const u32 handle = m_BufferFreeList.Alloc();
|
||||
|
||||
|
|
@ -47,18 +47,53 @@ RenderResourceManager::Commit(const UniformStorageBuffer *storageBuffer)
|
|||
.pBufferInfo = &m_WriteInfos.back().uBufferInfo,
|
||||
});
|
||||
|
||||
m_WriteOwner.emplace_back(HandleType::eBuffer, handle);
|
||||
|
||||
return {handle};
|
||||
}
|
||||
|
||||
void
|
||||
RenderResourceManager::EraseWrites(u32 handleIndex, HandleType handleType)
|
||||
{
|
||||
auto writeIter = m_Writes.begin();
|
||||
auto ownerIter = m_WriteOwner.begin();
|
||||
const auto ownerEnd = m_WriteOwner.end();
|
||||
|
||||
while (ownerIter != ownerEnd)
|
||||
{
|
||||
if (ownerIter->first == handleType && ownerIter->second == handleIndex)
|
||||
{
|
||||
*writeIter = m_Writes.back();
|
||||
*ownerIter = m_WriteOwner.back();
|
||||
m_Writes.pop_back();
|
||||
m_WriteOwner.pop_back();
|
||||
return;
|
||||
}
|
||||
|
||||
++ownerIter;
|
||||
++writeIter;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RenderResourceManager::Release(BufferHandle handle)
|
||||
{
|
||||
if (handle.IsInvalid())
|
||||
return;
|
||||
|
||||
EraseWrites(handle.m_Index, HandleType::eBuffer);
|
||||
|
||||
m_BufferFreeList.Free(handle.m_Index);
|
||||
}
|
||||
|
||||
void
|
||||
RenderResourceManager::Release(TextureHandle handle)
|
||||
{
|
||||
if (handle.IsInvalid())
|
||||
return;
|
||||
|
||||
EraseWrites(handle.m_Index, HandleType::eTexture);
|
||||
|
||||
m_TextureFreeList.Free(handle.m_Index);
|
||||
}
|
||||
|
||||
|
|
@ -82,13 +117,15 @@ RenderResourceManager::Commit(const Texture *texture)
|
|||
.pImageInfo = &m_WriteInfos.back().uImageInfo,
|
||||
});
|
||||
|
||||
m_WriteOwner.emplace_back(HandleType::eBuffer, handle);
|
||||
|
||||
return {handle};
|
||||
}
|
||||
|
||||
void
|
||||
RenderResourceManager::Update()
|
||||
{
|
||||
if (m_Writes.empty())
|
||||
if (m_Writes.empty() || m_WriteInfos.empty())
|
||||
return;
|
||||
|
||||
m_Device->m_Device.updateDescriptorSets(m_Writes.size(), m_Writes.data(), 0, nullptr);
|
||||
|
|
@ -180,6 +217,10 @@ RenderResourceManager::RenderResourceManager(const Device *device, u16 maxSize)
|
|||
.pSetLayouts = &m_SetLayout,
|
||||
};
|
||||
AbortIfFailed(device->m_Device.allocateDescriptorSets(&descriptorSetAllocateInfo, &m_DescriptorSet));
|
||||
|
||||
m_Device->SetName(m_SetLayout, "Bindless Layout");
|
||||
m_Device->SetName(m_DescriptorPool, "Bindless Pool");
|
||||
m_Device->SetName(m_DescriptorSet, "Bindless Set");
|
||||
}
|
||||
|
||||
RenderResourceManager::~RenderResourceManager()
|
||||
|
|
|
|||
|
|
@ -5,10 +5,12 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "buffer.h"
|
||||
#include "global.h"
|
||||
|
||||
#include <EASTL/deque.h>
|
||||
#include <EASTL/stack.h>
|
||||
#include <EASTL/vector_map.h>
|
||||
|
||||
struct Device;
|
||||
struct Texture;
|
||||
|
|
@ -16,16 +18,23 @@ struct UniformStorageBuffer;
|
|||
|
||||
struct RenderResourceManager;
|
||||
|
||||
struct Handle
|
||||
struct GpuResourceHandle
|
||||
{
|
||||
u32 m_Index;
|
||||
constexpr static u32 INVALID_HANDLE = MaxValue<u32>;
|
||||
u32 m_Index = INVALID_HANDLE; // Default = invalid
|
||||
|
||||
[[nodiscard]] bool
|
||||
IsInvalid() const
|
||||
{
|
||||
return m_Index == INVALID_HANDLE;
|
||||
}
|
||||
};
|
||||
|
||||
struct BufferHandle : Handle
|
||||
struct BufferHandle : GpuResourceHandle
|
||||
{
|
||||
};
|
||||
|
||||
struct TextureHandle : Handle
|
||||
struct TextureHandle : GpuResourceHandle
|
||||
{
|
||||
};
|
||||
|
||||
|
|
@ -38,6 +47,8 @@ struct FreeList
|
|||
void
|
||||
Init(u32 maxCapacity)
|
||||
{
|
||||
// MaxValue<u32> is 'invalid-handle' so you can't use it as a handle.
|
||||
assert(maxCapacity < GpuResourceHandle::INVALID_HANDLE);
|
||||
m_MaxCapacity = maxCapacity;
|
||||
}
|
||||
|
||||
|
|
@ -80,14 +91,25 @@ struct RenderResourceManager
|
|||
explicit WriteInfo(vk::BufferView info);
|
||||
};
|
||||
|
||||
enum class HandleType
|
||||
{
|
||||
eBuffer,
|
||||
eTexture,
|
||||
};
|
||||
|
||||
using WriteOwner = eastl::pair<HandleType, u32>;
|
||||
|
||||
eastl::deque<WriteInfo> m_WriteInfos;
|
||||
eastl::vector<vk::WriteDescriptorSet> m_Writes;
|
||||
eastl::vector<WriteOwner> m_WriteOwner;
|
||||
|
||||
vk::Sampler m_Sampler;
|
||||
|
||||
FreeList m_BufferFreeList;
|
||||
FreeList m_TextureFreeList;
|
||||
|
||||
void EraseWrites(u32 handleIndex, HandleType handleType);
|
||||
|
||||
public:
|
||||
const Device *m_Device;
|
||||
|
||||
|
|
@ -98,7 +120,7 @@ struct RenderResourceManager
|
|||
vk::DescriptorSetLayout m_SetLayout;
|
||||
vk::DescriptorSet m_DescriptorSet;
|
||||
|
||||
BufferHandle Commit(const UniformStorageBuffer *storageBuffer);
|
||||
BufferHandle Commit(const StorageBuffer *storageBuffer);
|
||||
void Release(BufferHandle handle);
|
||||
TextureHandle Commit(const Texture *texture);
|
||||
void Release(TextureHandle handle);
|
||||
|
|
@ -106,6 +128,8 @@ struct RenderResourceManager
|
|||
void Update();
|
||||
|
||||
// Ctor/Dtor
|
||||
explicit RenderResourceManager(const Device *device, u16 maxSize);
|
||||
RenderResourceManager(const Device *device, u16 maxSize);
|
||||
~RenderResourceManager();
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(RenderResourceManager);
|
||||
};
|
||||
|
|
@ -2,16 +2,45 @@
|
|||
#pragma shader_stage(fragment)
|
||||
#extension GL_EXT_nonuniform_qualifier : enable
|
||||
|
||||
layout (location = 0) in vec2 inUV;
|
||||
//layout (location = 0) in vec2 inUV;
|
||||
layout (location = 0) out vec4 outColor;
|
||||
|
||||
layout(set = 0, binding = 1) uniform sampler2D textures[];
|
||||
|
||||
layout(push_constant) uniform Block {
|
||||
uint textureHandle;
|
||||
uint vertexBufferHandle;
|
||||
struct VertexData {
|
||||
float position[4];
|
||||
// float uv[2];
|
||||
};
|
||||
|
||||
struct MaterialData {
|
||||
float m_AlbedoFactor[4];
|
||||
float m_EmissionFactor[4];
|
||||
float m_MetalFactor;
|
||||
float m_RoughFactor;
|
||||
uint m_AlbedoTex;
|
||||
uint m_NormalTex;
|
||||
uint m_MetalRoughTex;
|
||||
uint m_OcclusionTex;
|
||||
uint m_EmissionTex;
|
||||
};
|
||||
|
||||
layout(set = 0, binding = 1) uniform sampler2D textures[];
|
||||
layout(std430, set = 0, binding = 0) readonly buffer Vertices {
|
||||
VertexData data[];
|
||||
} vertexBuffer[];
|
||||
layout(std430, set = 0, binding = 0) readonly buffer Materials {
|
||||
MaterialData data[];
|
||||
} materialsBuffer[];
|
||||
|
||||
|
||||
layout(push_constant) uniform Block {
|
||||
uint vertexBufferHandle;
|
||||
uint materialBufferHandle;
|
||||
uint materialIdx;
|
||||
};
|
||||
|
||||
vec4 ToVec4(float array[4]) {
|
||||
return vec4(array[0],array[1],array[2],array[3]);
|
||||
}
|
||||
|
||||
void main() {
|
||||
outColor = vec4(texture(textures[textureHandle], inUV).rgb, 1.0f);
|
||||
outColor = ToVec4(materialsBuffer[materialBufferHandle].data[materialIdx].m_AlbedoFactor); // vec4(texture(textures[textureHandle], inUV).rgb, 1.0f);
|
||||
}
|
||||
|
|
@ -2,16 +2,31 @@
|
|||
#pragma shader_stage(vertex)
|
||||
#extension GL_EXT_nonuniform_qualifier : enable
|
||||
|
||||
layout(location = 0) out vec2 outUV;
|
||||
//layout(location = 0) out vec2 outUV;
|
||||
|
||||
struct VertexData {
|
||||
float position[3];
|
||||
float uv[2];
|
||||
float position[4];
|
||||
// float uv[2];
|
||||
};
|
||||
|
||||
struct MaterialData {
|
||||
float m_AlbedoFactor[4];
|
||||
float m_EmissionFactor[4];
|
||||
float m_MetalFactor;
|
||||
float m_RoughFactor;
|
||||
uint m_AlbedoTex;
|
||||
uint m_NormalTex;
|
||||
uint m_MetalRoughTex;
|
||||
uint m_OcclusionTex;
|
||||
uint m_EmissionTex;
|
||||
};
|
||||
|
||||
layout(std430, set = 0, binding = 0) readonly buffer Vertices {
|
||||
VertexData data[];
|
||||
} vertexBuffer[];
|
||||
layout(std430, set = 0, binding = 0) readonly buffer Materials {
|
||||
MaterialData data[];
|
||||
} materialsBuffer[];
|
||||
|
||||
vec3 GetPosition(uint bufferId, uint vertexIdx) {
|
||||
return vec3(
|
||||
|
|
@ -21,12 +36,12 @@ vec3 GetPosition(uint bufferId, uint vertexIdx) {
|
|||
);
|
||||
}
|
||||
|
||||
vec2 GetUV(uint bufferId, uint vertexIdx) {
|
||||
return vec2(
|
||||
vertexBuffer[bufferId].data[vertexIdx].uv[0],
|
||||
vertexBuffer[bufferId].data[vertexIdx].uv[1]
|
||||
);
|
||||
}
|
||||
//vec2 GetUV(uint bufferId, uint vertexIdx) {
|
||||
// return vec2(
|
||||
// vertexBuffer[bufferId].data[vertexIdx].uv[0],
|
||||
// vertexBuffer[bufferId].data[vertexIdx].uv[1]
|
||||
// );
|
||||
//}
|
||||
|
||||
layout(set = 1, binding = 0) uniform Camera {
|
||||
mat4 model;
|
||||
|
|
@ -35,11 +50,12 @@ layout(set = 1, binding = 0) uniform Camera {
|
|||
} ubo;
|
||||
|
||||
layout(push_constant) uniform Block {
|
||||
uint textureHandle;
|
||||
uint vertexBufferHandle;
|
||||
uint materialBufferHandle;
|
||||
uint materialIdx;
|
||||
};
|
||||
|
||||
void main() {
|
||||
outUV = GetUV(vertexBufferHandle, gl_VertexIndex);
|
||||
// outUV = GetUV(vertexBufferHandle, gl_VertexIndex);
|
||||
gl_Position = ubo.proj * ubo.view * ubo.model * vec4(GetPosition(vertexBufferHandle, gl_VertexIndex), 1.0f);
|
||||
}
|
||||
Loading…
Reference in New Issue