Texture bindless works!

This commit is contained in:
Anish Bhobe 2024-07-13 01:24:07 +02:00
parent c7ea45bce7
commit 6c15f599aa
15 changed files with 487 additions and 264 deletions

View File

@ -11,11 +11,11 @@
void void
Buffer::Destroy(const Device *device) Buffer::Destroy(const Device *device)
{ {
if (!m_Buffer) if (!IsValid())
return; return;
vmaDestroyBuffer(device->m_Allocator, m_Buffer, m_Allocation); vmaDestroyBuffer(device->m_Allocator, m_Buffer, m_Allocation);
m_Buffer = nullptr; m_Size &= ~VALID_BUFFER_BIT;
} }
void void
@ -41,24 +41,21 @@ Buffer::Allocate(const Device *device, usize size, vk::BufferUsageFlags bufferUs
&allocationCreateInfo, &buffer, &allocation, &allocationInfo)); &allocationCreateInfo, &buffer, &allocation, &allocationInfo));
ERROR_IF(Failed(result), "Could not allocate buffer. Cause: {}", result) THEN_ABORT(result); ERROR_IF(Failed(result), "Could not allocate buffer. Cause: {}", result) THEN_ABORT(result);
m_Buffer = buffer;
m_Size = size & SIZE_MASK;
m_Allocation = allocation;
m_Mapped = allocationInfo.pMappedData;
vk::MemoryPropertyFlags memoryPropertyFlags; vk::MemoryPropertyFlags memoryPropertyFlags;
vmaGetAllocationMemoryProperties(device->m_Allocator, allocation, vmaGetAllocationMemoryProperties(device->m_Allocator, allocation,
Recast<VkMemoryPropertyFlags *>(&memoryPropertyFlags)); Recast<VkMemoryPropertyFlags *>(&memoryPropertyFlags));
if (memoryPropertyFlags & vk::MemoryPropertyFlagBits::eHostVisible) bool hostAccessible = Cast<bool>(memoryPropertyFlags & vk::MemoryPropertyFlagBits::eHostVisible);
{
m_Size |= HOST_ACCESSIBLE_BIT; m_Buffer = buffer;
} m_Size = size | VALID_BUFFER_BIT | (hostAccessible ? HOST_ACCESSIBLE_BIT : 0);
m_Allocation = allocation;
m_Mapped = allocationInfo.pMappedData;
device->SetName(m_Buffer, name); device->SetName(m_Buffer, name);
} }
void void
Buffer::Write(const Device *device, usize offset, usize size, void *data) Buffer::Write(const Device *device, usize offset, usize size, const void *data)
{ {
assert(IsHostVisible()); assert(IsHostVisible());
@ -93,6 +90,15 @@ UniformBuffer::Init(const Device *device, const usize size, const cstr name)
VMA_MEMORY_USAGE_AUTO, name); VMA_MEMORY_USAGE_AUTO, name);
} }
void
UniformStorageBuffer::Init(const Device *device, usize size, 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);
}
void void
VertexBuffer::Init(const Device *device, usize size, cstr name) VertexBuffer::Init(const Device *device, usize size, cstr name)
{ {

View File

@ -17,19 +17,23 @@ struct Buffer
[[nodiscard]] usize GetSize() const; [[nodiscard]] usize GetSize() const;
[[nodiscard]] bool IsHostVisible() const; [[nodiscard]] bool IsHostVisible() const;
[[nodiscard]] bool IsValid() const;
[[nodiscard]] bool IsMapped() const; [[nodiscard]] bool IsMapped() const;
void Destroy(const Device *device); void Destroy(const Device *device);
void Write(const Device *device, usize offset, usize size, void *data); void Write(const Device *device, usize offset, usize size, const void *data);
protected: protected:
void Allocate(const Device *device, usize size, vk::BufferUsageFlags bufferUsage, void Allocate(const Device *device, usize size, vk::BufferUsageFlags bufferUsage,
VmaAllocationCreateFlags allocationFlags, VmaMemoryUsage memoryUsage, cstr name); VmaAllocationCreateFlags allocationFlags, VmaMemoryUsage memoryUsage, cstr name);
// Buffer size is used intrusively by the Render Resource Manager
// If the buffer is Invalid, the remaining data in Buffer is used for other tasks.
usize m_Size = 0; usize m_Size = 0;
constexpr static usize HOST_ACCESSIBLE_BIT = 1llu << 63; constexpr static usize VALID_BUFFER_BIT = Cast<usize>(1llu << 63);
constexpr static usize SIZE_MASK = ~HOST_ACCESSIBLE_BIT; constexpr static usize HOST_ACCESSIBLE_BIT = 1llu << 62;
constexpr static usize SIZE_MASK = ~(VALID_BUFFER_BIT | HOST_ACCESSIBLE_BIT);
}; };
struct UniformBuffer : Buffer struct UniformBuffer : Buffer
@ -37,6 +41,11 @@ struct UniformBuffer : Buffer
void Init(const Device *device, usize size, cstr name = nullptr); void Init(const Device *device, usize size, cstr name = nullptr);
}; };
struct UniformStorageBuffer : Buffer
{
void Init(const Device *device, usize size, cstr name = nullptr);
};
struct VertexBuffer : Buffer struct VertexBuffer : Buffer
{ {
void Init(const Device *device, usize size, cstr name = nullptr); void Init(const Device *device, usize size, cstr name = nullptr);
@ -60,6 +69,12 @@ Buffer::IsHostVisible() const
return m_Size & HOST_ACCESSIBLE_BIT; return m_Size & HOST_ACCESSIBLE_BIT;
} }
inline bool
Buffer::IsValid() const
{
return m_Size & VALID_BUFFER_BIT;
}
inline bool inline bool
Buffer::IsMapped() const Buffer::IsMapped() const
{ {

View File

@ -27,7 +27,7 @@ using f128 = long double;
using b8 = bool; using b8 = bool;
using b32 = u32; using b32 = u32;
using usize = size_t; using usize = size_t;
using p64 = intptr_t; using uptr = uintptr_t;
using cstr = const char *; using cstr = const char *;
namespace ansi_color namespace ansi_color

View File

@ -75,7 +75,7 @@ HashCombine(const usize hash0, const usize hash1)
struct Time struct Time
{ {
static constexpr f64 cMaxDelta = 0.1; static constexpr f64 MAX_DELTA = 0.1;
inline static f64 m_Elapsed{Qnan<f64>}; inline static f64 m_Elapsed{Qnan<f64>};
inline static f64 m_Delta{Qnan<f64>}; inline static f64 m_Delta{Qnan<f64>};
@ -93,7 +93,7 @@ struct Time
{ {
ERROR_IF(std::isnan(m_Elapsed), "Time not init."); ERROR_IF(std::isnan(m_Elapsed), "Time not init.");
const auto newElapsed = glfwGetTime(); const auto newElapsed = glfwGetTime();
m_Delta = std::clamp(newElapsed - m_Elapsed, 0.0, cMaxDelta); m_Delta = std::clamp(newElapsed - m_Elapsed, 0.0, MAX_DELTA);
m_Elapsed = newElapsed; m_Elapsed = newElapsed;
} }
}; };

View File

@ -10,9 +10,10 @@
void void
Image::Destroy(const Device *device) Image::Destroy(const Device *device)
{ {
if (!m_Image) if (!IsValid())
return; return;
device->m_Device.destroy(m_View, nullptr);
vmaDestroyImage(device->m_Allocator, m_Image, m_Allocation); vmaDestroyImage(device->m_Allocator, m_Image, m_Allocation);
m_Image = nullptr; m_Image = nullptr;
} }
@ -20,10 +21,12 @@ Image::Destroy(const Device *device)
void void
Texture::Init(const Device *device, const vk::Extent2D extent, const bool isMipmapped, const cstr name) Texture::Init(const Device *device, const vk::Extent2D extent, const bool isMipmapped, const cstr name)
{ {
constexpr vk::Format imageFormat = vk::Format::eR8G8B8A8Srgb;
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;
vk::ImageCreateInfo imageCreateInfo = { vk::ImageCreateInfo imageCreateInfo = {
.imageType = vk::ImageType::e2D, .imageType = vk::ImageType::e2D,
.format = vk::Format::eR8G8B8A8Srgb, .format = imageFormat,
.extent = {.width = extent.width, .height = extent.height, .depth = 1}, .extent = {.width = extent.width, .height = extent.height, .depth = 1},
.mipLevels = mipLevels, .mipLevels = mipLevels,
.arrayLayers = 1, .arrayLayers = 1,
@ -42,9 +45,28 @@ Texture::Init(const Device *device, const vk::Extent2D extent, const bool isMipm
VmaAllocation allocation; VmaAllocation allocation;
auto result = Cast<vk::Result>(vmaCreateImage(device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo), auto result = Cast<vk::Result>(vmaCreateImage(device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo),
&allocationCreateInfo, &image, &allocation, nullptr)); &allocationCreateInfo, &image, &allocation, nullptr));
ERROR_IF(Failed(result), "Could not allocate buffer. Cause: {}", result) THEN_ABORT(result); ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", name, result) THEN_ABORT(result);
vk::ImageView view;
vk::ImageViewCreateInfo imageViewCreateInfo = {
.image = image,
.viewType = vk::ImageViewType::e2D,
.format = imageFormat,
.components = {},
.subresourceRange =
{
.aspectMask = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0,
.levelCount = mipLevels,
.baseArrayLayer = 0,
.layerCount = 1,
},
};
result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", name, result) THEN_ABORT(result);
m_Image = image; m_Image = image;
m_View = view;
m_Allocation = allocation; m_Allocation = allocation;
m_Extent = {extent.width, extent.height, 1}; m_Extent = {extent.width, extent.height, 1};
@ -54,9 +76,10 @@ Texture::Init(const Device *device, const vk::Extent2D extent, const bool isMipm
void void
DepthImage::Init(const Device *device, vk::Extent2D extent, cstr name) DepthImage::Init(const Device *device, vk::Extent2D extent, cstr name)
{ {
constexpr vk::Format imageFormat = vk::Format::eD32Sfloat;
vk::ImageCreateInfo imageCreateInfo = { vk::ImageCreateInfo imageCreateInfo = {
.imageType = vk::ImageType::e2D, .imageType = vk::ImageType::e2D,
.format = vk::Format::eD32Sfloat, .format = imageFormat,
.extent = {.width = extent.width, .height = extent.height, .depth = 1}, .extent = {.width = extent.width, .height = extent.height, .depth = 1},
.mipLevels = 1, .mipLevels = 1,
.arrayLayers = 1, .arrayLayers = 1,
@ -75,9 +98,28 @@ DepthImage::Init(const Device *device, vk::Extent2D extent, cstr name)
VmaAllocation allocation; VmaAllocation allocation;
auto result = Cast<vk::Result>(vmaCreateImage(device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo), auto result = Cast<vk::Result>(vmaCreateImage(device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo),
&allocationCreateInfo, &image, &allocation, nullptr)); &allocationCreateInfo, &image, &allocation, nullptr));
ERROR_IF(Failed(result), "Could not allocate buffer. Cause: {}", result) THEN_ABORT(result); ERROR_IF(Failed(result), "Could not allocate depth buffer. Cause: {}", result) THEN_ABORT(result);
vk::ImageView view;
vk::ImageViewCreateInfo imageViewCreateInfo = {
.image = image,
.viewType = vk::ImageViewType::e2D,
.format = imageFormat,
.components = {},
.subresourceRange =
{
.aspectMask = vk::ImageAspectFlagBits::eDepth,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
};
result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
ERROR_IF(Failed(result), "Could not create depth image view {}. Cause: {}", name, result) THEN_ABORT(result);
m_Image = image; m_Image = image;
m_View = view;
m_Allocation = allocation; m_Allocation = allocation;
m_Extent = {extent.width, extent.height, 1}; m_Extent = {extent.width, extent.height, 1};

View File

@ -12,9 +12,11 @@ struct Device;
struct Image struct Image
{ {
vk::Image m_Image = nullptr; vk::Image m_Image = nullptr;
vk::ImageView m_View = nullptr;
VmaAllocation m_Allocation = nullptr; VmaAllocation m_Allocation = nullptr;
vk::Extent3D m_Extent; vk::Extent3D m_Extent;
usize m_Size = 0;
[[nodiscard]] bool IsValid() const;
void Destroy(const Device *device); void Destroy(const Device *device);
}; };
@ -27,4 +29,10 @@ struct Texture : Image
struct DepthImage : Image struct DepthImage : Image
{ {
void Init(const Device *device, vk::Extent2D extent, cstr name = nullptr); void Init(const Device *device, vk::Extent2D extent, cstr name = nullptr);
}; };
inline bool
Image::IsValid() const
{
return m_Image;
}

View File

@ -60,7 +60,7 @@ ImageFile::Load(cstr fileName)
usize usize
ImageFile::GetSize() const ImageFile::GetSize() const
{ {
return m_Width * m_Height * m_NumChannels; return Cast<usize>(m_Width) * m_Height * m_NumChannels;
} }
ImageFile::~ImageFile() ImageFile::~ImageFile()
@ -330,30 +330,8 @@ main(int, char **)
imageStaging.Destroy(&device); imageStaging.Destroy(&device);
} }
vk::ImageView imageView;
vk::Sampler sampler; vk::Sampler sampler;
{ {
vk::ImageViewCreateInfo imageViewCreateInfo = {
.image = crate.m_Image,
.viewType = vk::ImageViewType::e2D,
.format = vk::Format::eR8G8B8A8Srgb,
.components =
vk::ComponentMapping{
.r = vk::ComponentSwizzle::eIdentity,
.g = vk::ComponentSwizzle::eIdentity,
.b = vk::ComponentSwizzle::eIdentity,
.a = vk::ComponentSwizzle::eIdentity,
},
.subresourceRange =
{
.aspectMask = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
};
AbortIfFailed(device.m_Device.createImageView(&imageViewCreateInfo, nullptr, &imageView));
vk::SamplerCreateInfo samplerCreateInfo = { vk::SamplerCreateInfo samplerCreateInfo = {
.magFilter = vk::Filter::eLinear, .magFilter = vk::Filter::eLinear,
.minFilter = vk::Filter::eLinear, .minFilter = vk::Filter::eLinear,
@ -382,7 +360,7 @@ main(int, char **)
}; };
vk::DescriptorImageInfo descriptorImageInfo = { vk::DescriptorImageInfo descriptorImageInfo = {
.sampler = sampler, .sampler = sampler,
.imageView = imageView, .imageView = crate.m_View,
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal, .imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
}; };
eastl::array writeDescriptors = { eastl::array writeDescriptors = {
@ -452,52 +430,16 @@ main(int, char **)
FrameManager frameManager = {&device, queueAllocation.m_Family, MAX_FRAMES_IN_FLIGHT}; FrameManager frameManager = {&device, queueAllocation.m_Family, MAX_FRAMES_IN_FLIGHT};
eastl::fixed_vector<DepthImage, MAX_FRAMES_IN_FLIGHT> depthImages(frameManager.m_FramesInFlight); eastl::fixed_vector<DepthImage, MAX_FRAMES_IN_FLIGHT> depthImages(frameManager.m_FramesInFlight);
eastl::fixed_vector<vk::ImageView, MAX_FRAMES_IN_FLIGHT> depthViews(frameManager.m_FramesInFlight);
vk::ImageSubresourceRange depthSubresourceRange = {
.aspectMask = vk::ImageAspectFlagBits::eDepth,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
};
u32 index = 0;
for (auto &depthImage : depthImages) for (auto &depthImage : depthImages)
{ {
auto name = fmt::format("Depth image {}", index); depthImage.Init(&device, swapchain.m_Extent, "Depth");
depthImage.Init(&device, swapchain.m_Extent, name.c_str());
vk::ImageViewCreateInfo imageViewCreateInfo = {
.image = depthImage.m_Image,
.viewType = vk::ImageViewType::e2D,
.format = vk::Format::eD32Sfloat,
.components = vk::ComponentMapping{.r = vk::ComponentSwizzle::eIdentity},
.subresourceRange = depthSubresourceRange,
};
AbortIfFailed(device.m_Device.createImageView(&imageViewCreateInfo, nullptr, &depthViews[index]));
index++;
} }
auto recreateDepthBuffers = [&device, &depthImages, &depthViews, depthSubresourceRange](vk::Extent2D extent) { auto recreateDepthBuffers = [&device, &depthImages](vk::Extent2D extent) {
for (auto &depthView : depthViews)
{
device.m_Device.destroy(depthView, nullptr);
}
u32 index = 0;
for (auto &depthImage : depthImages) for (auto &depthImage : depthImages)
{ {
depthImage.Destroy(&device); depthImage.Destroy(&device);
depthImage.Init(&device, extent, "Depth"); depthImage.Init(&device, extent, "Depth");
vk::ImageViewCreateInfo imageViewCreateInfo = {
.image = depthImage.m_Image,
.viewType = vk::ImageViewType::e2D,
.format = vk::Format::eD32Sfloat,
.components = vk::ComponentMapping{.r = vk::ComponentSwizzle::eIdentity},
.subresourceRange = depthSubresourceRange,
};
AbortIfFailed(device.m_Device.createImageView(&imageViewCreateInfo, nullptr, &depthViews[index]));
++index;
} }
}; };
swapchain.RegisterResizeCallback(recreateDepthBuffers); swapchain.RegisterResizeCallback(recreateDepthBuffers);
@ -518,7 +460,7 @@ main(int, char **)
vk::ImageView currentImageView = swapchain.m_ImageViews[imageIndex]; vk::ImageView currentImageView = swapchain.m_ImageViews[imageIndex];
vk::Image currentImage = swapchain.m_Images[imageIndex]; vk::Image currentImage = swapchain.m_Images[imageIndex];
vk::CommandBuffer cmd = currentFrame->m_CommandBuffer; vk::CommandBuffer cmd = currentFrame->m_CommandBuffer;
vk::ImageView currentDepthImageView = depthViews[currentFrame->m_FrameIdx]; vk::ImageView currentDepthImageView = depthImages[currentFrame->m_FrameIdx].m_View;
topOfThePipeBarrier.image = currentImage; topOfThePipeBarrier.image = currentImage;
renderToPresentBarrier.image = currentImage; renderToPresentBarrier.image = currentImage;
@ -592,16 +534,11 @@ main(int, char **)
AbortIfFailed(device.m_Device.waitIdle()); AbortIfFailed(device.m_Device.waitIdle());
for (auto &depthView : depthViews)
{
device.m_Device.destroy(depthView, nullptr);
}
for (auto &depthImage : depthImages) for (auto &depthImage : depthImages)
{ {
depthImage.Destroy(&device); depthImage.Destroy(&device);
} }
device.m_Device.destroy(sampler, nullptr); device.m_Device.destroy(sampler, nullptr);
device.m_Device.destroy(imageView, nullptr);
ubo.Destroy(&device); ubo.Destroy(&device);
device.m_Device.destroy(descriptorPool, nullptr); device.m_Device.destroy(descriptorPool, nullptr);
device.m_Device.destroy(copyPool, nullptr); device.m_Device.destroy(copyPool, nullptr);

View File

@ -18,4 +18,5 @@ target_link_libraries(model_render PRIVATE util_helper)
target_include_directories(model_render PRIVATE ${TINYGLTF_INCLUDE_DIRS}) target_include_directories(model_render PRIVATE ${TINYGLTF_INCLUDE_DIRS})
add_resource_dir(model_render model) add_resource_dir(model_render model)
add_resource_dir(model_render image)

BIN
samples/03_model_render/image/container.jpg (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -36,11 +36,13 @@ constexpr auto MODEL_FILE = "model/Box.glb";
struct ImageFile struct ImageFile
{ {
u8 *m_Data = nullptr; void *m_Data = nullptr;
u32 m_Width = 512; u32 m_Width = 0;
u32 m_Height = 512; u32 m_Height = 0;
u32 m_NumChannels = 4; u32 m_NumChannels = 0;
bool m_Constant = false;
bool Load(cstr fileName);
bool Load(vec4 color); bool Load(vec4 color);
[[nodiscard]] usize GetSize() const; [[nodiscard]] usize GetSize() const;
~ImageFile(); ~ImageFile();
@ -102,14 +104,27 @@ main(int, char **)
Features enabledDeviceFeatures = { Features enabledDeviceFeatures = {
.m_Vulkan10Features = {.samplerAnisotropy = true}, .m_Vulkan10Features = {.samplerAnisotropy = true},
.m_Vulkan12Features = {.descriptorIndexing = true}, .m_Vulkan12Features =
{
.descriptorIndexing = true,
.shaderSampledImageArrayNonUniformIndexing = true,
.shaderStorageBufferArrayNonUniformIndexing = true,
.shaderStorageImageArrayNonUniformIndexing = true,
.descriptorBindingUniformBufferUpdateAfterBind = true, // Not related to Bindless
.descriptorBindingSampledImageUpdateAfterBind = true,
.descriptorBindingStorageImageUpdateAfterBind = true,
.descriptorBindingStorageBufferUpdateAfterBind = true,
.descriptorBindingPartiallyBound = true,
.runtimeDescriptorArray = true,
},
.m_Vulkan13Features = {.dynamicRendering = true}, .m_Vulkan13Features = {.dynamicRendering = true},
}; };
QueueAllocation queueAllocation = FindAppropriateQueueAllocation(&deviceToUse); QueueAllocation queueAllocation = FindAppropriateQueueAllocation(&deviceToUse);
Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"}; Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"};
vk::Queue commandQueue = device.GetQueue(queueAllocation.m_Family, 0); vk::Queue commandQueue = device.GetQueue(queueAllocation.m_Family, 0);
Swapchain swapchain = {&window, &device, "Primary Chain"}; Swapchain swapchain = {&window, &device, "Primary Chain"};
RenderResourceManager resourceManager(&device); RenderResourceManager resourceManager(&device, 10);
Pipeline pipeline = CreatePipeline(&device, &swapchain, &resourceManager); Pipeline pipeline = CreatePipeline(&device, &swapchain, &resourceManager);
@ -210,55 +225,97 @@ main(int, char **)
Vertex{.m_Position = vec3(0.5f, 0.5f, 0.5f), .m_UV0 = vec2(1.0f, 1.0f)}, Vertex{.m_Position = vec3(0.5f, 0.5f, 0.5f), .m_UV0 = vec2(1.0f, 1.0f)},
}; };
ImageFile imageFile; ImageFile crateImageFile;
bool loaded = imageFile.Load({0.7f, 0.4f, 0.1f, 1.0f}); ImageFile plainImageFile;
assert(loaded); assert(crateImageFile.Load("image/container.jpg"));
INFO("Image {}x{} : {} channels", imageFile.m_Width, imageFile.m_Height, imageFile.m_NumChannels); INFO("Image {}x{} : {} channels", crateImageFile.m_Width, crateImageFile.m_Height, crateImageFile.m_NumChannels);
assert(plainImageFile.Load({0.7f, 0.4f, 0.1f, 1.0f}));
VertexBuffer vbo; VertexBuffer vbo;
Texture crate; Texture crateTexture;
Texture plainTexture;
vbo.Init(&device, vertices.size() * sizeof vertices[0], "VBO"); vbo.Init(&device, vertices.size() * sizeof vertices[0], "VBO");
crate.Init(&device, {imageFile.m_Width, imageFile.m_Height}, false, "Crate Texture"); crateTexture.Init(&device, {crateImageFile.m_Width, crateImageFile.m_Height}, false, "Crate Texture");
plainTexture.Init(&device, {crateImageFile.m_Width, crateImageFile.m_Height}, false, "Plain Texture");
auto crateTextureId = resourceManager.Commit(&crateTexture);
auto plainTextureId = resourceManager.Commit(&plainTexture);
{ {
StagingBuffer vertexStaging, imageStaging; StagingBuffer vertexStaging, imageStaging1, imageStaging2;
vertexStaging.Init(&device, vertices.size() * sizeof vertices[0], "Vertex Staging"); vertexStaging.Init(&device, vertices.size() * sizeof vertices[0], "Vertex Staging");
vertexStaging.Write(&device, 0, vertices.size() * sizeof vertices[0], vertices.data()); vertexStaging.Write(&device, 0, vertices.size() * sizeof vertices[0], vertices.data());
imageStaging.Init(&device, imageFile.GetSize(), "Image Staging"); imageStaging1.Init(&device, crateImageFile.GetSize(), "Image Staging 1");
INFO("fine {}", imageFile.GetSize()); imageStaging1.Write(&device, 0, crateImageFile.GetSize(), crateImageFile.m_Data);
imageStaging.Write(&device, 0, imageFile.GetSize(), imageFile.m_Data);
vk::ImageMemoryBarrier imageReadyToWrite = { imageStaging2.Init(&device, plainImageFile.GetSize(), "Image Staging 2");
.oldLayout = vk::ImageLayout::eUndefined, imageStaging2.Write(&device, 0, plainImageFile.GetSize(), plainImageFile.m_Data);
.newLayout = vk::ImageLayout::eTransferDstOptimal,
.srcQueueFamilyIndex = queueAllocation.m_Family, eastl::array imageReadyToWrite = {
.dstQueueFamilyIndex = queueAllocation.m_Family, vk::ImageMemoryBarrier{
.image = crate.m_Image, .oldLayout = vk::ImageLayout::eUndefined,
.subresourceRange = .newLayout = vk::ImageLayout::eTransferDstOptimal,
{ .srcQueueFamilyIndex = queueAllocation.m_Family,
.aspectMask = vk::ImageAspectFlagBits::eColor, .dstQueueFamilyIndex = queueAllocation.m_Family,
.baseMipLevel = 0, .image = crateTexture.m_Image,
.levelCount = 1, .subresourceRange =
.baseArrayLayer = 0, {
.layerCount = 1, .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,
},
},
}; };
vk::ImageMemoryBarrier imageReadyToRead = { eastl::array imageReadyToRead = {
.oldLayout = vk::ImageLayout::eTransferDstOptimal, vk::ImageMemoryBarrier{
.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal, .oldLayout = vk::ImageLayout::eTransferDstOptimal,
.srcQueueFamilyIndex = queueAllocation.m_Family, .newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
.dstQueueFamilyIndex = queueAllocation.m_Family, .srcQueueFamilyIndex = queueAllocation.m_Family,
.image = crate.m_Image, .dstQueueFamilyIndex = queueAllocation.m_Family,
.subresourceRange = .image = crateTexture.m_Image,
{ .subresourceRange =
.aspectMask = vk::ImageAspectFlagBits::eColor, {
.baseMipLevel = 0, .aspectMask = vk::ImageAspectFlagBits::eColor,
.levelCount = 1, .baseMipLevel = 0,
.baseArrayLayer = 0, .levelCount = 1,
.layerCount = 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::Fence fence;
@ -268,15 +325,15 @@ main(int, char **)
vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit}; vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
AbortIfFailed(copyBuffer.begin(&beginInfo)); AbortIfFailed(copyBuffer.begin(&beginInfo));
copyBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eHost, vk::PipelineStageFlagBits::eTransfer, {}, 0, copyBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eHost, vk::PipelineStageFlagBits::eTransfer, {}, 0,
nullptr, 0, nullptr, 1, &imageReadyToWrite); nullptr, 0, nullptr, Cast<u32>(imageReadyToWrite.size()), imageReadyToWrite.data());
vk::BufferCopy bufferCopy = {.srcOffset = 0, .dstOffset = 0, .size = vertexStaging.GetSize()}; vk::BufferCopy bufferCopy = {.srcOffset = 0, .dstOffset = 0, .size = vertexStaging.GetSize()};
copyBuffer.copyBuffer(vertexStaging.m_Buffer, vbo.m_Buffer, 1, &bufferCopy); copyBuffer.copyBuffer(vertexStaging.m_Buffer, vbo.m_Buffer, 1, &bufferCopy);
vk::BufferImageCopy imageCopy = { vk::BufferImageCopy imageCopy = {
.bufferOffset = 0, .bufferOffset = 0,
.bufferRowLength = imageFile.m_Width, .bufferRowLength = crateImageFile.m_Width,
.bufferImageHeight = imageFile.m_Height, .bufferImageHeight = crateImageFile.m_Height,
.imageSubresource = .imageSubresource =
{ {
.aspectMask = vk::ImageAspectFlagBits::eColor, .aspectMask = vk::ImageAspectFlagBits::eColor,
@ -285,13 +342,15 @@ main(int, char **)
.layerCount = 1, .layerCount = 1,
}, },
.imageOffset = {}, .imageOffset = {},
.imageExtent = {imageFile.m_Width, imageFile.m_Height, 1}, .imageExtent = {crateImageFile.m_Width, crateImageFile.m_Height, 1},
}; };
copyBuffer.copyBufferToImage(imageStaging.m_Buffer, crate.m_Image, vk::ImageLayout::eTransferDstOptimal, 1, copyBuffer.copyBufferToImage(imageStaging1.m_Buffer, crateTexture.m_Image, vk::ImageLayout::eTransferDstOptimal,
&imageCopy); 1, &imageCopy);
copyBuffer.copyBufferToImage(imageStaging2.m_Buffer, plainTexture.m_Image, vk::ImageLayout::eTransferDstOptimal,
1, &imageCopy);
copyBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {}, copyBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {},
0, nullptr, 0, nullptr, 1, &imageReadyToRead); 0, nullptr, 0, nullptr, Cast<u32>(imageReadyToRead.size()), imageReadyToRead.data());
AbortIfFailed(copyBuffer.end()); AbortIfFailed(copyBuffer.end());
@ -310,49 +369,8 @@ main(int, char **)
device.m_Device.destroy(fence, nullptr); device.m_Device.destroy(fence, nullptr);
vertexStaging.Destroy(&device); vertexStaging.Destroy(&device);
imageStaging.Destroy(&device); imageStaging1.Destroy(&device);
} imageStaging2.Destroy(&device);
vk::ImageView imageView;
vk::Sampler sampler;
{
vk::ImageViewCreateInfo imageViewCreateInfo = {
.image = crate.m_Image,
.viewType = vk::ImageViewType::e2D,
.format = vk::Format::eR8G8B8A8Srgb,
.components =
vk::ComponentMapping{
.r = vk::ComponentSwizzle::eIdentity,
.g = vk::ComponentSwizzle::eIdentity,
.b = vk::ComponentSwizzle::eIdentity,
.a = vk::ComponentSwizzle::eIdentity,
},
.subresourceRange =
{
.aspectMask = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
};
AbortIfFailed(device.m_Device.createImageView(&imageViewCreateInfo, nullptr, &imageView));
vk::SamplerCreateInfo samplerCreateInfo = {
.magFilter = vk::Filter::eLinear,
.minFilter = vk::Filter::eLinear,
.mipmapMode = vk::SamplerMipmapMode::eLinear,
.addressModeU = vk::SamplerAddressMode::eRepeat,
.addressModeV = vk::SamplerAddressMode::eRepeat,
.addressModeW = vk::SamplerAddressMode::eRepeat,
.mipLodBias = 0.2,
.anisotropyEnable = true,
.maxAnisotropy = 1.0f,
.compareEnable = false,
.minLod = 0,
.maxLod = 4,
.unnormalizedCoordinates = false,
};
AbortIfFailed(device.m_Device.createSampler(&samplerCreateInfo, nullptr, &sampler));
} }
UniformBuffer ubo; UniformBuffer ubo;
@ -363,11 +381,6 @@ main(int, char **)
.offset = 0, .offset = 0,
.range = ubo.GetSize(), .range = ubo.GetSize(),
}; };
vk::DescriptorImageInfo descriptorImageInfo = {
.sampler = sampler,
.imageView = imageView,
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
};
eastl::array writeDescriptors = { eastl::array writeDescriptors = {
vk::WriteDescriptorSet{ vk::WriteDescriptorSet{
.dstSet = descriptorSet, .dstSet = descriptorSet,
@ -377,17 +390,11 @@ main(int, char **)
.descriptorType = vk::DescriptorType::eUniformBuffer, .descriptorType = vk::DescriptorType::eUniformBuffer,
.pBufferInfo = &descriptorBufferInfo, .pBufferInfo = &descriptorBufferInfo,
}, },
vk::WriteDescriptorSet{
.dstSet = descriptorSet,
.dstBinding = 1,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
.pImageInfo = &descriptorImageInfo,
},
}; };
device.m_Device.updateDescriptorSets(Cast<u32>(writeDescriptors.size()), writeDescriptors.data(), 0, nullptr); device.m_Device.updateDescriptorSets(Cast<u32>(writeDescriptors.size()), writeDescriptors.data(), 0, nullptr);
resourceManager.Update();
// Persistent variables // Persistent variables
vk::Viewport viewport = { vk::Viewport viewport = {
.x = 0, .x = 0,
@ -487,11 +494,27 @@ main(int, char **)
Time::Init(); Time::Init();
Handle *pushData = &crateTextureId;
Handle *otherPushData = &plainTextureId;
bool prevPressed = false;
auto isSpaceJustPressed = [&prevPressed, &window] {
bool pressed = glfwGetKey(window.m_Window, GLFW_KEY_SPACE) == GLFW_PRESS;
bool justPressed = pressed & !prevPressed;
prevPressed = pressed;
return justPressed;
};
INFO("Starting loop"); INFO("Starting loop");
while (window.Poll()) while (window.Poll())
{ {
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);
@ -546,6 +569,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.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.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline.m_Layout, 1, 1, &descriptorSet, 0, nullptr);
usize offsets = 0; usize offsets = 0;
cmd.bindVertexBuffers(0, 1, &vbo.m_Buffer, &offsets); cmd.bindVertexBuffers(0, 1, &vbo.m_Buffer, &offsets);
@ -583,12 +609,11 @@ main(int, char **)
{ {
depthImage.Destroy(&device); depthImage.Destroy(&device);
} }
device.m_Device.destroy(sampler, nullptr);
device.m_Device.destroy(imageView, nullptr);
ubo.Destroy(&device); ubo.Destroy(&device);
device.m_Device.destroy(descriptorPool, nullptr); device.m_Device.destroy(descriptorPool, nullptr);
device.m_Device.destroy(copyPool, nullptr); device.m_Device.destroy(copyPool, nullptr);
crate.Destroy(&device); crateTexture.Destroy(&device);
plainTexture.Destroy(&device);
vbo.Destroy(&device); vbo.Destroy(&device);
return 0; return 0;
@ -598,27 +623,60 @@ bool
ImageFile::Load(vec4 color) ImageFile::Load(vec4 color)
{ {
constexpr usize size = 512llu * 512llu * 4llu; constexpr usize size = 512llu * 512llu * 4llu;
m_Data = new u8[size]; u8 *pData = new u8[size];
vec4 color255 = 255.999f * color; vec4 color255 = 255.999f * color;
glm::vec<4, u8> color8 = color255; glm::vec<4, u8> color8 = color255;
for (usize i = 0; i < size; i += 4) for (usize i = 0; i < size; i += 4)
{ {
memcpy(m_Data + i, &color8, sizeof color8); memcpy(pData + i, &color8, sizeof color8);
} }
m_Data = pData;
m_Constant = true;
m_Height = 512;
m_Width = 512;
m_NumChannels = 4;
return true;
}
bool
ImageFile::Load(cstr fileName)
{
int width, height, nrChannels;
m_Data = stbi_load(fileName, &width, &height, &nrChannels, 4);
ERROR_IF(!m_Data, "Could not load {}", fileName);
if (!m_Data)
{
return false;
}
m_Width = width;
m_Height = height;
m_NumChannels = 4;
m_Constant = false;
return true; return true;
} }
usize usize
ImageFile::GetSize() const ImageFile::GetSize() const
{ {
return m_Width * m_Height * m_NumChannels; return Cast<usize>(m_Width) * m_Height * m_NumChannels;
} }
ImageFile::~ImageFile() ImageFile::~ImageFile()
{ {
delete[] m_Data; if (m_Constant)
{
delete[] Cast<u8 *>(m_Data);
}
else
{
stbi_image_free(m_Data);
}
m_Data = nullptr; m_Data = nullptr;
} }

View File

@ -44,12 +44,6 @@ CreatePipeline(const Device *device, const Swapchain *swapchain, const RenderRes
.descriptorCount = 1, .descriptorCount = 1,
.stageFlags = vk::ShaderStageFlagBits::eVertex, .stageFlags = vk::ShaderStageFlagBits::eVertex,
}, },
vk::DescriptorSetLayoutBinding{
.binding = 1,
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
.descriptorCount = 1,
.stageFlags = vk::ShaderStageFlagBits::eFragment,
},
}; };
vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = { vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = {
.bindingCount = Cast<u32>(descriptorSetLayoutBindings.size()), .bindingCount = Cast<u32>(descriptorSetLayoutBindings.size()),
@ -61,11 +55,17 @@ CreatePipeline(const Device *device, const Swapchain *swapchain, const RenderRes
descriptorSetLayouts.push_back(descriptorSetLayout); descriptorSetLayouts.push_back(descriptorSetLayout);
} }
vk::PushConstantRange pushConstantRange = {
.stageFlags = vk::ShaderStageFlagBits::eAll,
.offset = 0,
.size = 16,
};
vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = { vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = {
.setLayoutCount = Cast<u32>(descriptorSetLayouts.size()), .setLayoutCount = Cast<u32>(descriptorSetLayouts.size()),
.pSetLayouts = descriptorSetLayouts.data(), .pSetLayouts = descriptorSetLayouts.data(),
.pushConstantRangeCount = 0, .pushConstantRangeCount = 1,
.pPushConstantRanges = nullptr, .pPushConstantRanges = &pushConstantRange,
}; };
vk::PipelineLayout pipelineLayout; vk::PipelineLayout pipelineLayout;
AbortIfFailed(device->m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &pipelineLayout)); AbortIfFailed(device->m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &pipelineLayout));

View File

@ -10,45 +10,148 @@
#include "helpers.h" #include "helpers.h"
#include "image.h" #include "image.h"
RenderResourceManager::RenderResourceManager(const Device *device) #include <EASTL/array.h>
RenderResourceManager::WriteInfo::WriteInfo(vk::DescriptorBufferInfo info)
: uBufferInfo(info)
{
}
RenderResourceManager::WriteInfo::WriteInfo(vk::DescriptorImageInfo info)
: uImageInfo(info)
{
}
RenderResourceManager::WriteInfo::WriteInfo(vk::BufferView info)
: uBufferView(info)
{
}
BufferHandle
RenderResourceManager::Commit(const UniformStorageBuffer *storageBuffer)
{
const u32 handle = m_BufferFreeList.Alloc();
m_WriteInfos.emplace_back(vk::DescriptorBufferInfo{
.buffer = storageBuffer->m_Buffer,
.offset = 0,
.range = storageBuffer->GetSize(),
});
m_Writes.push_back({
.dstSet = m_DescriptorSet,
.dstBinding = BUFFER_BINDING_INDEX,
.dstArrayElement = handle,
.descriptorCount = 1,
.descriptorType = vk::DescriptorType::eStorageBuffer,
.pBufferInfo = &m_WriteInfos.back().uBufferInfo,
});
return {handle};
}
TextureHandle
RenderResourceManager::Commit(const Texture *texture)
{
const u32 handle = m_TextureFreeList.Alloc();
m_WriteInfos.emplace_back(vk::DescriptorImageInfo{
.sampler = nullptr,
.imageView = texture->m_View,
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
});
m_Writes.push_back({
.dstSet = m_DescriptorSet,
.dstBinding = TEXTURE_BINDING_INDEX,
.dstArrayElement = handle,
.descriptorCount = 1,
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
.pImageInfo = &m_WriteInfos.back().uImageInfo,
});
return {handle};
}
void
RenderResourceManager::Update()
{
usize count = Cast<usize>(m_Writes.size());
vk::WriteDescriptorSet *pData = m_Writes.data();
if (count > 0)
{
m_Device->m_Device.updateDescriptorSets(count, pData, 0, nullptr);
}
m_Writes.clear();
m_WriteInfos.clear();
}
RenderResourceManager::RenderResourceManager(const Device *device, u16 maxSize)
: m_Device(device) : m_Device(device)
{ {
vk::PhysicalDeviceProperties properties; vk::PhysicalDeviceProperties properties;
m_Device->m_PhysicalDevice.getProperties(&properties); m_Device->m_PhysicalDevice.getProperties(&properties);
auto maxBufferCount = properties.limits.maxDescriptorSetStorageBuffers - 1024; u32 buffersCount = eastl::min(properties.limits.maxPerStageDescriptorStorageBuffers - 1024, Cast<u32>(maxSize));
auto maxTextureCount = properties.limits.maxDescriptorSetSampledImages - 1024; u32 texturesCount = eastl::min(properties.limits.maxPerStageDescriptorSampledImages - 1024, Cast<u32>(maxSize));
INFO("Max Buffer Count: {}", maxBufferCount); vk::SamplerCreateInfo samplerCreateInfo = {
INFO("Max Texture Count: {}", maxTextureCount); .magFilter = vk::Filter::eLinear,
.minFilter = vk::Filter::eLinear,
.mipmapMode = vk::SamplerMipmapMode::eLinear,
.addressModeU = vk::SamplerAddressMode::eClampToBorder,
.addressModeV = vk::SamplerAddressMode::eClampToBorder,
.addressModeW = vk::SamplerAddressMode::eClampToBorder,
.mipLodBias = 0.0f,
.anisotropyEnable = true,
.maxAnisotropy = properties.limits.maxSamplerAnisotropy,
.compareEnable = false,
.minLod = 0,
.maxLod = vk::LodClampNone,
.borderColor = vk::BorderColor::eFloatOpaqueBlack,
.unnormalizedCoordinates = false,
};
AbortIfFailed(device->m_Device.createSampler(&samplerCreateInfo, nullptr, &m_Sampler));
m_Buffers.resize(maxBufferCount); INFO("Max Buffer Count: {}", buffersCount);
m_Textures.resize(maxTextureCount); INFO("Max Texture Count: {}", texturesCount);
m_BufferFreeList.Init(buffersCount);
m_TextureFreeList.Init(texturesCount);
eastl::array poolSizes = { eastl::array poolSizes = {
vk::DescriptorPoolSize{.type = vk::DescriptorType::eStorageBuffer, .descriptorCount = maxBufferCount}, vk::DescriptorPoolSize{
vk::DescriptorPoolSize{.type = vk::DescriptorType::eSampledImage, .descriptorCount = maxTextureCount}, .type = vk::DescriptorType::eStorageBuffer,
.descriptorCount = buffersCount,
},
vk::DescriptorPoolSize{
.type = vk::DescriptorType::eCombinedImageSampler,
.descriptorCount = texturesCount,
},
}; };
vk::DescriptorPoolCreateInfo poolCreateInfo = { const vk::DescriptorPoolCreateInfo poolCreateInfo = {
.flags = vk::DescriptorPoolCreateFlagBits::eUpdateAfterBind, .flags = vk::DescriptorPoolCreateFlagBits::eUpdateAfterBind,
.maxSets = 4, .maxSets = 1,
.poolSizeCount = Cast<u32>(poolSizes.size()), .poolSizeCount = Cast<u32>(poolSizes.size()),
.pPoolSizes = poolSizes.data(), .pPoolSizes = poolSizes.data(),
}; };
AbortIfFailed(device->m_Device.createDescriptorPool(&poolCreateInfo, nullptr, &m_DescriptorPool)); AbortIfFailed(device->m_Device.createDescriptorPool(&poolCreateInfo, nullptr, &m_DescriptorPool));
eastl::vector immutableSamplers(texturesCount, m_Sampler);
eastl::array descriptorLayoutBindings = { eastl::array descriptorLayoutBindings = {
vk::DescriptorSetLayoutBinding{ vk::DescriptorSetLayoutBinding{
.binding = 0, .binding = BUFFER_BINDING_INDEX,
.descriptorType = vk::DescriptorType::eStorageBuffer, .descriptorType = vk::DescriptorType::eStorageBuffer,
.descriptorCount = Cast<u32>(m_Buffers.size()), .descriptorCount = Cast<u32>(buffersCount),
.stageFlags = vk::ShaderStageFlagBits::eAll, .stageFlags = vk::ShaderStageFlagBits::eAll,
}, },
vk::DescriptorSetLayoutBinding{ vk::DescriptorSetLayoutBinding{
.binding = 1, .binding = TEXTURE_BINDING_INDEX,
.descriptorType = vk::DescriptorType::eSampledImage, .descriptorType = vk::DescriptorType::eCombinedImageSampler,
.descriptorCount = Cast<u32>(m_Textures.size()), .descriptorCount = Cast<u32>(texturesCount),
.stageFlags = vk::ShaderStageFlagBits::eAll, .stageFlags = vk::ShaderStageFlagBits::eAll,
.pImmutableSamplers = immutableSamplers.data(),
}, },
}; };
const vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = { const vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = {
@ -71,17 +174,7 @@ RenderResourceManager::RenderResourceManager(const Device *device)
RenderResourceManager::~RenderResourceManager() RenderResourceManager::~RenderResourceManager()
{ {
for (auto &buffer : m_Buffers) m_Device->m_Device.destroy(m_Sampler, nullptr);
{
buffer.Destroy(m_Device);
}
for (auto &image : m_Textures)
{
image.Destroy(m_Device);
}
m_Device->m_Device.destroy(m_TextureUpdate, nullptr);
m_Device->m_Device.destroy(m_BufferUpdate, nullptr);
m_Device->m_Device.destroy(m_DescriptorPool, nullptr); m_Device->m_Device.destroy(m_DescriptorPool, nullptr);
m_Device->m_Device.destroy(m_SetLayout, nullptr); m_Device->m_Device.destroy(m_SetLayout, nullptr);
} }

View File

@ -7,16 +7,18 @@
#include "global.h" #include "global.h"
#include <EASTL/array.h> #include <EASTL/deque.h>
#include <EASTL/vector.h> #include <EASTL/stack.h>
struct Device; struct Device;
struct Texture; struct Texture;
struct UniformBuffer; struct UniformStorageBuffer;
struct RenderResourceManager;
struct Handle struct Handle
{ {
u16 m_Index; u32 m_Index;
}; };
struct BufferHandle : Handle struct BufferHandle : Handle
@ -27,29 +29,81 @@ struct TextureHandle : Handle
{ {
}; };
struct FreeList
{
eastl::stack<u32, eastl::deque<u32>> m_List;
u32 m_MaxVisited = 0;
u32 m_MaxCapacity = 16;
void
Init(u32 maxCapacity)
{
m_MaxCapacity = maxCapacity;
}
[[nodiscard]] u32
Alloc()
{
if (!m_List.empty())
{
const u32 value = m_List.top();
m_List.pop();
return value;
}
if (m_MaxVisited < m_MaxCapacity)
{
return m_MaxVisited++;
}
ERROR("Out of Handles.") THEN_ABORT(-1);
}
void
Free(u32 index)
{
WARN_IF(index >= m_MaxCapacity, "Trying to free an out-of-bounds index.");
if (index < m_MaxCapacity)
m_List.push(index);
}
};
struct RenderResourceManager struct RenderResourceManager
{ {
private:
union WriteInfo {
vk::DescriptorBufferInfo uBufferInfo;
vk::DescriptorImageInfo uImageInfo;
vk::BufferView uBufferView;
explicit WriteInfo(vk::DescriptorBufferInfo info);
explicit WriteInfo(vk::DescriptorImageInfo info);
explicit WriteInfo(vk::BufferView info);
};
eastl::deque<WriteInfo> m_WriteInfos;
eastl::vector<vk::WriteDescriptorSet> m_Writes;
vk::Sampler m_Sampler;
FreeList m_BufferFreeList;
FreeList m_TextureFreeList;
public:
const Device *m_Device; const Device *m_Device;
constexpr static u32 BUFFER_BINDING_INDEX = 0;
constexpr static u32 TEXTURE_BINDING_INDEX = 1;
vk::DescriptorPool m_DescriptorPool; vk::DescriptorPool m_DescriptorPool;
vk::DescriptorSetLayout m_SetLayout; vk::DescriptorSetLayout m_SetLayout;
vk::DescriptorSet m_DescriptorSet; vk::DescriptorSet m_DescriptorSet;
vk::DescriptorUpdateTemplate m_BufferUpdate; BufferHandle Commit(const UniformStorageBuffer *storageBuffer);
vk::DescriptorUpdateTemplate m_TextureUpdate; TextureHandle Commit(const Texture *texture);
eastl::vector<UniformBuffer> m_Buffers; void Update();
eastl::vector<Texture> m_Textures;
// TODO: eastl::vector<StorageTexture> m_Textures;
// UniformBuffer *Allocate();
// UniformBuffer *Fetch(UniformHandle handle);
// void Commit(UniformHandle handle);
// Texture *Allocate();
// Texture *Fetch(TextureHandle handle);
// void Commit(TextureHandle handle);
// Ctor/Dtor // Ctor/Dtor
explicit RenderResourceManager(const Device *device); explicit RenderResourceManager(const Device *device, u16 maxSize);
~RenderResourceManager(); ~RenderResourceManager();
}; };

View File

@ -1,11 +1,16 @@
#version 450 #version 450
#pragma shader_stage(fragment) #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 (location = 0) out vec4 outColor;
layout(set = 1, binding = 1) uniform sampler2D tex; layout(set = 0, binding = 1) uniform sampler2D textures[];
layout(push_constant) uniform Block {
uint handle;
};
void main() { void main() {
outColor = vec4(texture(tex, inUV).rgb, 1.0f); outColor = vec4(texture(textures[handle], inUV).rgb, 1.0f);
} }

View File

@ -1,5 +1,6 @@
#version 450 #version 450
#pragma shader_stage(vertex) #pragma shader_stage(vertex)
#extension GL_EXT_nonuniform_qualifier : enable
layout(location = 0) in vec4 position; layout(location = 0) in vec4 position;
layout(location = 1) in vec2 uv0; layout(location = 1) in vec2 uv0;
@ -7,7 +8,7 @@ layout(location = 1) in vec2 uv0;
layout(location = 0) out vec2 outUV; layout(location = 0) out vec2 outUV;
//layout(std140, set=0, binding=0) readonly buffer buffers; //layout(std140, set=0, binding=0) readonly buffer buffers;
layout(set = 0, binding = 1) uniform texture2D textures[]; //layout(set = 0, binding = 1) uniform texture2D textures[];
layout(set = 1, binding = 0) uniform Camera { layout(set = 1, binding = 0) uniform Camera {
mat4 model; mat4 model;