mirror of
https://github.com/bailwillharr/engine.git
synced 2024-09-21 04:51:18 +00:00
Add combined image sampler descriptor support
This commit is contained in:
parent
41174515a8
commit
9f88131371
@ -34,14 +34,14 @@ namespace engine {
|
||||
struct SetZeroBuffer {
|
||||
glm::mat4 proj;
|
||||
};
|
||||
gfx::DescriptorBuffer* setZeroBuffer;
|
||||
gfx::UniformBuffer* setZeroBuffer;
|
||||
/* uniforms for per-frame data */
|
||||
const gfx::DescriptorSetLayout* setOneLayout;
|
||||
const gfx::DescriptorSet* setOne;
|
||||
struct SetOneBuffer {
|
||||
glm::mat4 view;
|
||||
};
|
||||
gfx::DescriptorBuffer* setOneBuffer;
|
||||
gfx::UniformBuffer* setOneBuffer;
|
||||
};
|
||||
|
||||
class Application {
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <type_traits>
|
||||
|
||||
// Enums and structs for the graphics abstraction
|
||||
|
||||
@ -9,7 +10,7 @@ namespace engine::gfx {
|
||||
|
||||
// handles (incomplete types)
|
||||
struct Pipeline;
|
||||
struct DescriptorBuffer;
|
||||
struct UniformBuffer;
|
||||
struct Buffer;
|
||||
struct Texture;
|
||||
struct DrawBuffer;
|
||||
@ -80,10 +81,19 @@ namespace engine::gfx {
|
||||
LINEAR,
|
||||
};
|
||||
|
||||
struct VertexBufferDesc {
|
||||
uint64_t size;
|
||||
enum class DescriptorType {
|
||||
UNIFORM_BUFFER,
|
||||
COMBINED_IMAGE_SAMPLER,
|
||||
};
|
||||
|
||||
namespace ShaderStageFlags {
|
||||
enum Bits : uint32_t {
|
||||
VERTEX = 1 << 0,
|
||||
FRAGMENT = 1 << 1,
|
||||
};
|
||||
typedef std::underlying_type<Bits>::type Flags;
|
||||
}
|
||||
|
||||
struct VertexAttribDescription {
|
||||
VertexAttribDescription(uint32_t location, VertexAttribFormat format, uint32_t offset) :
|
||||
location(location),
|
||||
@ -108,4 +118,9 @@ namespace engine::gfx {
|
||||
std::vector<const DescriptorSetLayout*> descriptorSetLayouts;
|
||||
};
|
||||
|
||||
struct DescriptorSetLayoutBinding {
|
||||
DescriptorType descriptorType = DescriptorType::UNIFORM_BUFFER;
|
||||
ShaderStageFlags::Flags stageFlags = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -32,17 +32,18 @@ namespace engine {
|
||||
gfx::Pipeline* createPipeline(const gfx::PipelineInfo& info);
|
||||
void destroyPipeline(const gfx::Pipeline* pipeline);
|
||||
|
||||
gfx::DescriptorSetLayout* createDescriptorSetLayout();
|
||||
gfx::DescriptorSetLayout* createDescriptorSetLayout(const std::vector<gfx::DescriptorSetLayoutBinding>& bindings);
|
||||
void destroyDescriptorSetLayout(const gfx::DescriptorSetLayout* layout);
|
||||
|
||||
gfx::DescriptorSet* allocateDescriptorSet(const gfx::DescriptorSetLayout* layout);
|
||||
// This updates all copies of the descriptor. This cannot be used after any frames have been renderered
|
||||
void updateDescriptor(const gfx::DescriptorSet* set, uint32_t binding, const gfx::DescriptorBuffer* buffer, size_t offset, size_t range);
|
||||
void updateDescriptorUniformBuffer(const gfx::DescriptorSet* set, uint32_t binding, const gfx::UniformBuffer* buffer, size_t offset, size_t range);
|
||||
void updateDescriptorCombinedImageSampler(const gfx::DescriptorSet* set, uint32_t binding);
|
||||
|
||||
gfx::DescriptorBuffer* createDescriptorBuffer(uint64_t size, const void* initialData);
|
||||
void destroyDescriptorBuffer(const gfx::DescriptorBuffer* descriptorBuffer);
|
||||
gfx::UniformBuffer* createUniformBuffer(uint64_t size, const void* initialData);
|
||||
void destroyUniformBuffer(const gfx::UniformBuffer* descriptorBuffer);
|
||||
|
||||
void writeDescriptorBuffer(gfx::DescriptorBuffer* buffer, uint64_t offset, uint64_t size, const void* data);
|
||||
void writeUniformBuffer(gfx::UniformBuffer* buffer, uint64_t offset, uint64_t size, const void* data);
|
||||
|
||||
// Loads data into staging buffer and copies that into a single GPU buffer.
|
||||
gfx::Buffer* createBuffer(gfx::BufferType type, uint64_t size, const void* data);
|
||||
|
@ -76,21 +76,28 @@ namespace engine {
|
||||
// initialise the render data
|
||||
renderData.gfxdev = std::make_unique<GFXDevice>(appName, appVersion, m_window->getHandle(), graphicsSettings);
|
||||
|
||||
renderData.setZeroLayout = gfx()->createDescriptorSetLayout();
|
||||
std::vector<gfx::DescriptorSetLayoutBinding> layoutBindings;
|
||||
{
|
||||
auto& binding0 = layoutBindings.emplace_back();
|
||||
binding0.descriptorType = gfx::DescriptorType::UNIFORM_BUFFER;
|
||||
binding0.stageFlags = gfx::ShaderStageFlags::VERTEX;
|
||||
}
|
||||
|
||||
renderData.setZeroLayout = gfx()->createDescriptorSetLayout(layoutBindings);
|
||||
renderData.setZero = gfx()->allocateDescriptorSet(renderData.setZeroLayout);
|
||||
RenderData::SetZeroBuffer initialSetZeroData{
|
||||
.proj = glm::perspectiveZO(glm::radians(70.0f), 1024.0f / 768.0f, 0.1f, 1000.0f),
|
||||
};
|
||||
renderData.setZeroBuffer = gfx()->createDescriptorBuffer(sizeof(RenderData::SetZeroBuffer), &initialSetZeroData);
|
||||
gfx()->updateDescriptor(renderData.setZero, 0, renderData.setZeroBuffer, 0, sizeof(RenderData::SetZeroBuffer));
|
||||
renderData.setZeroBuffer = gfx()->createUniformBuffer(sizeof(RenderData::SetZeroBuffer), &initialSetZeroData);
|
||||
gfx()->updateDescriptorUniformBuffer(renderData.setZero, 0, renderData.setZeroBuffer, 0, sizeof(RenderData::SetZeroBuffer));
|
||||
|
||||
renderData.setOneLayout = gfx()->createDescriptorSetLayout();
|
||||
renderData.setOneLayout = gfx()->createDescriptorSetLayout(layoutBindings);
|
||||
renderData.setOne = gfx()->allocateDescriptorSet(renderData.setOneLayout);
|
||||
RenderData::SetOneBuffer initialSetOneData{
|
||||
.view = glm::mat4{ 1.0f },
|
||||
};
|
||||
renderData.setOneBuffer = gfx()->createDescriptorBuffer(sizeof(RenderData::SetOneBuffer), &initialSetOneData);
|
||||
gfx()->updateDescriptor(renderData.setOne, 0, renderData.setOneBuffer, 0, sizeof(RenderData::SetOneBuffer));
|
||||
renderData.setOneBuffer = gfx()->createUniformBuffer(sizeof(RenderData::SetOneBuffer), &initialSetOneData);
|
||||
gfx()->updateDescriptorUniformBuffer(renderData.setOne, 0, renderData.setOneBuffer, 0, sizeof(RenderData::SetOneBuffer));
|
||||
|
||||
// default resources
|
||||
{
|
||||
@ -135,9 +142,9 @@ namespace engine {
|
||||
|
||||
Application::~Application()
|
||||
{
|
||||
gfx()->destroyDescriptorBuffer(renderData.setOneBuffer);
|
||||
gfx()->destroyUniformBuffer(renderData.setOneBuffer);
|
||||
gfx()->destroyDescriptorSetLayout(renderData.setOneLayout);
|
||||
gfx()->destroyDescriptorBuffer(renderData.setZeroBuffer);
|
||||
gfx()->destroyUniformBuffer(renderData.setZeroBuffer);
|
||||
gfx()->destroyDescriptorSetLayout(renderData.setZeroLayout);
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,6 @@ namespace engine {
|
||||
VkBuffer buffer = VK_NULL_HANDLE;
|
||||
VmaAllocation allocation = nullptr;
|
||||
VkDeviceSize size = 0;
|
||||
bool hostVisible = false;
|
||||
};
|
||||
|
||||
struct gfx::Pipeline {
|
||||
@ -113,7 +112,7 @@ namespace engine {
|
||||
std::array<VkDescriptorSet, FRAMES_IN_FLIGHT> sets; // frames in flight cannot use the same descriptor set in case the buffer needs updating
|
||||
};
|
||||
|
||||
struct gfx::DescriptorBuffer {
|
||||
struct gfx::UniformBuffer {
|
||||
gfx::Buffer stagingBuffer{};
|
||||
std::array<gfx::Buffer, FRAMES_IN_FLIGHT> gpuBuffers;
|
||||
};
|
||||
@ -165,24 +164,39 @@ namespace engine {
|
||||
switch (level) {
|
||||
case gfx::MSAALevel::MSAA_OFF:
|
||||
return VK_SAMPLE_COUNT_1_BIT;
|
||||
break;
|
||||
case gfx::MSAALevel::MSAA_2X:
|
||||
return VK_SAMPLE_COUNT_2_BIT;
|
||||
break;
|
||||
case gfx::MSAALevel::MSAA_4X:
|
||||
return VK_SAMPLE_COUNT_4_BIT;
|
||||
break;
|
||||
case gfx::MSAALevel::MSAA_8X:
|
||||
return VK_SAMPLE_COUNT_8_BIT;
|
||||
break;
|
||||
case gfx::MSAALevel::MSAA_16X:
|
||||
return VK_SAMPLE_COUNT_16_BIT;
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Unknown MSAA level");
|
||||
}
|
||||
}
|
||||
|
||||
static VkDescriptorType getDescriptorType(gfx::DescriptorType type)
|
||||
{
|
||||
switch (type) {
|
||||
case gfx::DescriptorType::UNIFORM_BUFFER:
|
||||
return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
case gfx::DescriptorType::COMBINED_IMAGE_SAMPLER:
|
||||
return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
default:
|
||||
throw std::runtime_error("Unknown descriptor type");
|
||||
}
|
||||
}
|
||||
|
||||
static VkShaderStageFlags getShaderStageFlags(gfx::ShaderStageFlags::Flags flags)
|
||||
{
|
||||
VkShaderStageFlags out = 0;
|
||||
if (flags & gfx::ShaderStageFlags::VERTEX) out |= VK_SHADER_STAGE_VERTEX_BIT;
|
||||
if (flags & gfx::ShaderStageFlags::FRAGMENT) out |= VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// functions
|
||||
@ -296,7 +310,7 @@ namespace engine {
|
||||
Swapchain swapchain{};
|
||||
|
||||
VkDescriptorPool descriptorPool;
|
||||
std::array<std::unordered_set<gfx::DescriptorBuffer*>, FRAMES_IN_FLIGHT> descriptorBufferWriteQueues{};
|
||||
std::array<std::unordered_set<gfx::UniformBuffer*>, FRAMES_IN_FLIGHT> uniformBufferWriteQueues{};
|
||||
|
||||
VkCommandPool transferCommandPool = VK_NULL_HANDLE;
|
||||
|
||||
@ -540,16 +554,16 @@ namespace engine {
|
||||
// transfer cmds...
|
||||
|
||||
std::vector<VkBufferMemoryBarrier2> barriers{};
|
||||
for (gfx::DescriptorBuffer* descriptorBuffer : pimpl->descriptorBufferWriteQueues[currentFrameIndex]) {
|
||||
for (gfx::UniformBuffer* uniformBuffer : pimpl->uniformBufferWriteQueues[currentFrameIndex]) {
|
||||
|
||||
VkBufferCopy copyRegion{};
|
||||
copyRegion.srcOffset = 0;
|
||||
copyRegion.dstOffset = 0;
|
||||
copyRegion.size = descriptorBuffer->stagingBuffer.size;
|
||||
copyRegion.size = uniformBuffer->stagingBuffer.size;
|
||||
vkCmdCopyBuffer(
|
||||
frameData.transferBuf,
|
||||
descriptorBuffer->stagingBuffer.buffer,
|
||||
descriptorBuffer->gpuBuffers[currentFrameIndex].buffer,
|
||||
uniformBuffer->stagingBuffer.buffer,
|
||||
uniformBuffer->gpuBuffers[currentFrameIndex].buffer,
|
||||
1,
|
||||
©Region
|
||||
);
|
||||
@ -562,11 +576,11 @@ namespace engine {
|
||||
barrier.dstAccessMask = 0;
|
||||
barrier.srcQueueFamilyIndex = pimpl->device.queues.transferQueueFamily;
|
||||
barrier.dstQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily;
|
||||
barrier.buffer = descriptorBuffer->gpuBuffers[currentFrameIndex].buffer;
|
||||
barrier.buffer = uniformBuffer->gpuBuffers[currentFrameIndex].buffer;
|
||||
barrier.offset = 0;
|
||||
barrier.size = descriptorBuffer->gpuBuffers[currentFrameIndex].size;
|
||||
barrier.size = uniformBuffer->gpuBuffers[currentFrameIndex].size;
|
||||
}
|
||||
pimpl->descriptorBufferWriteQueues[currentFrameIndex].clear();
|
||||
pimpl->uniformBufferWriteQueues[currentFrameIndex].clear();
|
||||
|
||||
VkDependencyInfo dependencyInfo{};
|
||||
dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO;
|
||||
@ -989,23 +1003,28 @@ namespace engine {
|
||||
delete pipeline;
|
||||
}
|
||||
|
||||
gfx::DescriptorSetLayout* GFXDevice::createDescriptorSetLayout()
|
||||
gfx::DescriptorSetLayout* GFXDevice::createDescriptorSetLayout(const std::vector<gfx::DescriptorSetLayoutBinding>& bindings)
|
||||
{
|
||||
gfx::DescriptorSetLayout* out = new gfx::DescriptorSetLayout{};
|
||||
|
||||
std::vector<VkDescriptorSetLayoutBinding> bindings{};
|
||||
auto& binding = bindings.emplace_back();
|
||||
binding.binding = 0; // This should be as low as possible to avoid wasting memory
|
||||
binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
binding.descriptorCount = 1; // if > 1, accessible as an array in the shader
|
||||
binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; // only accessible in vertex
|
||||
std::vector<VkDescriptorSetLayoutBinding> vulkanBindings{};
|
||||
uint32_t i = 0;
|
||||
for (const auto& binding : bindings) {
|
||||
auto& vulkanBinding = vulkanBindings.emplace_back();
|
||||
vulkanBinding.binding = i; // This should be as low as possible to avoid wasting memory
|
||||
vulkanBinding.descriptorType = converters::getDescriptorType(binding.descriptorType);
|
||||
vulkanBinding.descriptorCount = 1; // if > 1, accessible as an array in the shader
|
||||
vulkanBinding.stageFlags = converters::getShaderStageFlags(binding.stageFlags);
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
VkDescriptorSetLayoutCreateInfo info{};
|
||||
info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||
info.pNext = nullptr;
|
||||
info.flags = 0;
|
||||
info.bindingCount = (uint32_t)bindings.size();
|
||||
info.pBindings = bindings.data();
|
||||
info.bindingCount = (uint32_t)vulkanBindings.size();
|
||||
info.pBindings = vulkanBindings.data();
|
||||
VKCHECK(vkCreateDescriptorSetLayout(pimpl->device.device, &info, nullptr, &out->layout));
|
||||
|
||||
return out;
|
||||
@ -1039,7 +1058,7 @@ namespace engine {
|
||||
return set;
|
||||
}
|
||||
|
||||
void GFXDevice::updateDescriptor(const gfx::DescriptorSet* set, uint32_t binding, const gfx::DescriptorBuffer* buffer, size_t offset, size_t range)
|
||||
void GFXDevice::updateDescriptorUniformBuffer(const gfx::DescriptorSet* set, uint32_t binding, const gfx::UniformBuffer* buffer, size_t offset, size_t range)
|
||||
{
|
||||
assert(pimpl->FRAMECOUNT == 0);
|
||||
|
||||
@ -1065,14 +1084,39 @@ namespace engine {
|
||||
}
|
||||
}
|
||||
|
||||
gfx::DescriptorBuffer* GFXDevice::createDescriptorBuffer(uint64_t size, const void* initialData)
|
||||
void GFXDevice::updateDescriptorCombinedImageSampler(const gfx::DescriptorSet *set, uint32_t binding)
|
||||
{
|
||||
gfx::DescriptorBuffer* out = new gfx::DescriptorBuffer{};
|
||||
assert(pimpl->FRAMECOUNT == 0);
|
||||
|
||||
VkDescriptorImageInfo imageInfo{};
|
||||
imageInfo.sampler = VK_NULL_HANDLE;
|
||||
imageInfo.imageView = VK_NULL_HANDLE;
|
||||
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
|
||||
for (uint32_t i = 0; i < FRAMES_IN_FLIGHT; i++) {
|
||||
VkWriteDescriptorSet descriptorWrite{
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.pNext = nullptr,
|
||||
.dstSet = set->sets[i],
|
||||
.dstBinding = binding,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.pImageInfo = &imageInfo,
|
||||
.pBufferInfo = nullptr,
|
||||
.pTexelBufferView = nullptr
|
||||
};
|
||||
vkUpdateDescriptorSets(pimpl->device.device, 1, &descriptorWrite, 0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
gfx::UniformBuffer* GFXDevice::createUniformBuffer(uint64_t size, const void* initialData)
|
||||
{
|
||||
gfx::UniformBuffer* out = new gfx::UniformBuffer{};
|
||||
|
||||
/* first make staging buffer */
|
||||
out->stagingBuffer.size = size;
|
||||
out->stagingBuffer.type = gfx::BufferType::UNIFORM;
|
||||
out->stagingBuffer.hostVisible = true;
|
||||
{
|
||||
VkBufferCreateInfo stagingBufferInfo{};
|
||||
stagingBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
@ -1098,7 +1142,6 @@ namespace engine {
|
||||
for (uint32_t i = 0; i < FRAMES_IN_FLIGHT; i++) {
|
||||
out->gpuBuffers[i].size = out->stagingBuffer.size;
|
||||
out->gpuBuffers[i].type = gfx::BufferType::UNIFORM;
|
||||
out->gpuBuffers[i].hostVisible = false;
|
||||
|
||||
VkBufferCreateInfo gpuBufferInfo{};
|
||||
gpuBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
@ -1121,18 +1164,18 @@ namespace engine {
|
||||
|
||||
}
|
||||
|
||||
void GFXDevice::destroyDescriptorBuffer(const gfx::DescriptorBuffer* descriptorBuffer)
|
||||
void GFXDevice::destroyUniformBuffer(const gfx::UniformBuffer* uniformBuffer)
|
||||
{
|
||||
for (uint32_t i = 0; i < FRAMES_IN_FLIGHT; i++) {
|
||||
vmaDestroyBuffer(pimpl->allocator, descriptorBuffer->gpuBuffers[i].buffer, descriptorBuffer->gpuBuffers[i].allocation);
|
||||
vmaDestroyBuffer(pimpl->allocator, uniformBuffer->gpuBuffers[i].buffer, uniformBuffer->gpuBuffers[i].allocation);
|
||||
}
|
||||
|
||||
vmaDestroyBuffer(pimpl->allocator, descriptorBuffer->stagingBuffer.buffer, descriptorBuffer->stagingBuffer.allocation);
|
||||
vmaDestroyBuffer(pimpl->allocator, uniformBuffer->stagingBuffer.buffer, uniformBuffer->stagingBuffer.allocation);
|
||||
|
||||
delete descriptorBuffer;
|
||||
delete uniformBuffer;
|
||||
}
|
||||
|
||||
void GFXDevice::writeDescriptorBuffer(gfx::DescriptorBuffer* buffer, uint64_t offset, uint64_t size, const void* data)
|
||||
void GFXDevice::writeUniformBuffer(gfx::UniformBuffer* buffer, uint64_t offset, uint64_t size, const void* data)
|
||||
{
|
||||
assert(offset + size <= buffer->stagingBuffer.size);
|
||||
|
||||
@ -1145,7 +1188,7 @@ namespace engine {
|
||||
/* queue the writes to each gpu buffer */
|
||||
// This is required as buffers cannot be updated if they are currently in use
|
||||
for (uint32_t i = 0; i < FRAMES_IN_FLIGHT; i++) {
|
||||
pimpl->descriptorBufferWriteQueues[i].insert(buffer);
|
||||
pimpl->uniformBufferWriteQueues[i].insert(buffer);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1157,7 +1200,6 @@ namespace engine {
|
||||
auto out = new gfx::Buffer{};
|
||||
out->size = size;
|
||||
out->type = type;
|
||||
out->hostVisible = false;
|
||||
|
||||
VkBuffer stagingBuffer;
|
||||
VmaAllocation stagingAllocation;
|
||||
|
@ -48,13 +48,13 @@ namespace engine {
|
||||
RenderData::SetZeroBuffer setZeroBuffer{
|
||||
.proj = projMatrix
|
||||
};
|
||||
m_gfx->writeDescriptorBuffer(renderData.setZeroBuffer, 0, sizeof(RenderData::SetZeroBuffer), &setZeroBuffer);
|
||||
m_gfx->writeUniformBuffer(renderData.setZeroBuffer, 0, sizeof(RenderData::SetZeroBuffer), &setZeroBuffer);
|
||||
}
|
||||
|
||||
RenderData::SetOneBuffer setOneBuffer{
|
||||
.view = viewMatrix
|
||||
};
|
||||
m_gfx->writeDescriptorBuffer(renderData.setOneBuffer, 0, sizeof(RenderData::SetOneBuffer), &setOneBuffer);
|
||||
m_gfx->writeUniformBuffer(renderData.setOneBuffer, 0, sizeof(RenderData::SetOneBuffer), &setOneBuffer);
|
||||
|
||||
/* render all renderable entities */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user