Add combined image sampler descriptor support

This commit is contained in:
Bailey Harrison 2023-03-21 20:10:23 +00:00
parent 41174515a8
commit 9f88131371
6 changed files with 122 additions and 57 deletions

View File

@ -34,14 +34,14 @@ namespace engine {
struct SetZeroBuffer { struct SetZeroBuffer {
glm::mat4 proj; glm::mat4 proj;
}; };
gfx::DescriptorBuffer* setZeroBuffer; gfx::UniformBuffer* setZeroBuffer;
/* uniforms for per-frame data */ /* uniforms for per-frame data */
const gfx::DescriptorSetLayout* setOneLayout; const gfx::DescriptorSetLayout* setOneLayout;
const gfx::DescriptorSet* setOne; const gfx::DescriptorSet* setOne;
struct SetOneBuffer { struct SetOneBuffer {
glm::mat4 view; glm::mat4 view;
}; };
gfx::DescriptorBuffer* setOneBuffer; gfx::UniformBuffer* setOneBuffer;
}; };
class Application { class Application {

View File

@ -2,6 +2,7 @@
#include <cstdint> #include <cstdint>
#include <vector> #include <vector>
#include <type_traits>
// Enums and structs for the graphics abstraction // Enums and structs for the graphics abstraction
@ -9,7 +10,7 @@ namespace engine::gfx {
// handles (incomplete types) // handles (incomplete types)
struct Pipeline; struct Pipeline;
struct DescriptorBuffer; struct UniformBuffer;
struct Buffer; struct Buffer;
struct Texture; struct Texture;
struct DrawBuffer; struct DrawBuffer;
@ -80,10 +81,19 @@ namespace engine::gfx {
LINEAR, LINEAR,
}; };
struct VertexBufferDesc { enum class DescriptorType {
uint64_t size; 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 { struct VertexAttribDescription {
VertexAttribDescription(uint32_t location, VertexAttribFormat format, uint32_t offset) : VertexAttribDescription(uint32_t location, VertexAttribFormat format, uint32_t offset) :
location(location), location(location),
@ -108,4 +118,9 @@ namespace engine::gfx {
std::vector<const DescriptorSetLayout*> descriptorSetLayouts; std::vector<const DescriptorSetLayout*> descriptorSetLayouts;
}; };
struct DescriptorSetLayoutBinding {
DescriptorType descriptorType = DescriptorType::UNIFORM_BUFFER;
ShaderStageFlags::Flags stageFlags = 0;
};
} }

View File

@ -32,17 +32,18 @@ namespace engine {
gfx::Pipeline* createPipeline(const gfx::PipelineInfo& info); gfx::Pipeline* createPipeline(const gfx::PipelineInfo& info);
void destroyPipeline(const gfx::Pipeline* pipeline); void destroyPipeline(const gfx::Pipeline* pipeline);
gfx::DescriptorSetLayout* createDescriptorSetLayout(); gfx::DescriptorSetLayout* createDescriptorSetLayout(const std::vector<gfx::DescriptorSetLayoutBinding>& bindings);
void destroyDescriptorSetLayout(const gfx::DescriptorSetLayout* layout); void destroyDescriptorSetLayout(const gfx::DescriptorSetLayout* layout);
gfx::DescriptorSet* allocateDescriptorSet(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 // 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); gfx::UniformBuffer* createUniformBuffer(uint64_t size, const void* initialData);
void destroyDescriptorBuffer(const gfx::DescriptorBuffer* descriptorBuffer); 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. // 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); gfx::Buffer* createBuffer(gfx::BufferType type, uint64_t size, const void* data);

View File

@ -76,21 +76,28 @@ namespace engine {
// initialise the render data // initialise the render data
renderData.gfxdev = std::make_unique<GFXDevice>(appName, appVersion, m_window->getHandle(), graphicsSettings); 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.setZero = gfx()->allocateDescriptorSet(renderData.setZeroLayout);
RenderData::SetZeroBuffer initialSetZeroData{ RenderData::SetZeroBuffer initialSetZeroData{
.proj = glm::perspectiveZO(glm::radians(70.0f), 1024.0f / 768.0f, 0.1f, 1000.0f), .proj = glm::perspectiveZO(glm::radians(70.0f), 1024.0f / 768.0f, 0.1f, 1000.0f),
}; };
renderData.setZeroBuffer = gfx()->createDescriptorBuffer(sizeof(RenderData::SetZeroBuffer), &initialSetZeroData); renderData.setZeroBuffer = gfx()->createUniformBuffer(sizeof(RenderData::SetZeroBuffer), &initialSetZeroData);
gfx()->updateDescriptor(renderData.setZero, 0, renderData.setZeroBuffer, 0, sizeof(RenderData::SetZeroBuffer)); 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.setOne = gfx()->allocateDescriptorSet(renderData.setOneLayout);
RenderData::SetOneBuffer initialSetOneData{ RenderData::SetOneBuffer initialSetOneData{
.view = glm::mat4{ 1.0f }, .view = glm::mat4{ 1.0f },
}; };
renderData.setOneBuffer = gfx()->createDescriptorBuffer(sizeof(RenderData::SetOneBuffer), &initialSetOneData); renderData.setOneBuffer = gfx()->createUniformBuffer(sizeof(RenderData::SetOneBuffer), &initialSetOneData);
gfx()->updateDescriptor(renderData.setOne, 0, renderData.setOneBuffer, 0, sizeof(RenderData::SetOneBuffer)); gfx()->updateDescriptorUniformBuffer(renderData.setOne, 0, renderData.setOneBuffer, 0, sizeof(RenderData::SetOneBuffer));
// default resources // default resources
{ {
@ -135,9 +142,9 @@ namespace engine {
Application::~Application() Application::~Application()
{ {
gfx()->destroyDescriptorBuffer(renderData.setOneBuffer); gfx()->destroyUniformBuffer(renderData.setOneBuffer);
gfx()->destroyDescriptorSetLayout(renderData.setOneLayout); gfx()->destroyDescriptorSetLayout(renderData.setOneLayout);
gfx()->destroyDescriptorBuffer(renderData.setZeroBuffer); gfx()->destroyUniformBuffer(renderData.setZeroBuffer);
gfx()->destroyDescriptorSetLayout(renderData.setZeroLayout); gfx()->destroyDescriptorSetLayout(renderData.setZeroLayout);
} }

View File

@ -87,7 +87,6 @@ namespace engine {
VkBuffer buffer = VK_NULL_HANDLE; VkBuffer buffer = VK_NULL_HANDLE;
VmaAllocation allocation = nullptr; VmaAllocation allocation = nullptr;
VkDeviceSize size = 0; VkDeviceSize size = 0;
bool hostVisible = false;
}; };
struct gfx::Pipeline { 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 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{}; gfx::Buffer stagingBuffer{};
std::array<gfx::Buffer, FRAMES_IN_FLIGHT> gpuBuffers; std::array<gfx::Buffer, FRAMES_IN_FLIGHT> gpuBuffers;
}; };
@ -165,24 +164,39 @@ namespace engine {
switch (level) { switch (level) {
case gfx::MSAALevel::MSAA_OFF: case gfx::MSAALevel::MSAA_OFF:
return VK_SAMPLE_COUNT_1_BIT; return VK_SAMPLE_COUNT_1_BIT;
break;
case gfx::MSAALevel::MSAA_2X: case gfx::MSAALevel::MSAA_2X:
return VK_SAMPLE_COUNT_2_BIT; return VK_SAMPLE_COUNT_2_BIT;
break;
case gfx::MSAALevel::MSAA_4X: case gfx::MSAALevel::MSAA_4X:
return VK_SAMPLE_COUNT_4_BIT; return VK_SAMPLE_COUNT_4_BIT;
break;
case gfx::MSAALevel::MSAA_8X: case gfx::MSAALevel::MSAA_8X:
return VK_SAMPLE_COUNT_8_BIT; return VK_SAMPLE_COUNT_8_BIT;
break;
case gfx::MSAALevel::MSAA_16X: case gfx::MSAALevel::MSAA_16X:
return VK_SAMPLE_COUNT_16_BIT; return VK_SAMPLE_COUNT_16_BIT;
break;
default: default:
throw std::runtime_error("Unknown MSAA level"); 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 // functions
@ -296,7 +310,7 @@ namespace engine {
Swapchain swapchain{}; Swapchain swapchain{};
VkDescriptorPool descriptorPool; 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; VkCommandPool transferCommandPool = VK_NULL_HANDLE;
@ -540,16 +554,16 @@ namespace engine {
// transfer cmds... // transfer cmds...
std::vector<VkBufferMemoryBarrier2> barriers{}; std::vector<VkBufferMemoryBarrier2> barriers{};
for (gfx::DescriptorBuffer* descriptorBuffer : pimpl->descriptorBufferWriteQueues[currentFrameIndex]) { for (gfx::UniformBuffer* uniformBuffer : pimpl->uniformBufferWriteQueues[currentFrameIndex]) {
VkBufferCopy copyRegion{}; VkBufferCopy copyRegion{};
copyRegion.srcOffset = 0; copyRegion.srcOffset = 0;
copyRegion.dstOffset = 0; copyRegion.dstOffset = 0;
copyRegion.size = descriptorBuffer->stagingBuffer.size; copyRegion.size = uniformBuffer->stagingBuffer.size;
vkCmdCopyBuffer( vkCmdCopyBuffer(
frameData.transferBuf, frameData.transferBuf,
descriptorBuffer->stagingBuffer.buffer, uniformBuffer->stagingBuffer.buffer,
descriptorBuffer->gpuBuffers[currentFrameIndex].buffer, uniformBuffer->gpuBuffers[currentFrameIndex].buffer,
1, 1,
&copyRegion &copyRegion
); );
@ -562,11 +576,11 @@ namespace engine {
barrier.dstAccessMask = 0; barrier.dstAccessMask = 0;
barrier.srcQueueFamilyIndex = pimpl->device.queues.transferQueueFamily; barrier.srcQueueFamilyIndex = pimpl->device.queues.transferQueueFamily;
barrier.dstQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily; barrier.dstQueueFamilyIndex = pimpl->device.queues.presentAndDrawQueueFamily;
barrier.buffer = descriptorBuffer->gpuBuffers[currentFrameIndex].buffer; barrier.buffer = uniformBuffer->gpuBuffers[currentFrameIndex].buffer;
barrier.offset = 0; 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{}; VkDependencyInfo dependencyInfo{};
dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; dependencyInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO;
@ -989,23 +1003,28 @@ namespace engine {
delete pipeline; delete pipeline;
} }
gfx::DescriptorSetLayout* GFXDevice::createDescriptorSetLayout() gfx::DescriptorSetLayout* GFXDevice::createDescriptorSetLayout(const std::vector<gfx::DescriptorSetLayoutBinding>& bindings)
{ {
gfx::DescriptorSetLayout* out = new gfx::DescriptorSetLayout{}; gfx::DescriptorSetLayout* out = new gfx::DescriptorSetLayout{};
std::vector<VkDescriptorSetLayoutBinding> bindings{}; std::vector<VkDescriptorSetLayoutBinding> vulkanBindings{};
auto& binding = bindings.emplace_back(); uint32_t i = 0;
binding.binding = 0; // This should be as low as possible to avoid wasting memory for (const auto& binding : bindings) {
binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; auto& vulkanBinding = vulkanBindings.emplace_back();
binding.descriptorCount = 1; // if > 1, accessible as an array in the shader vulkanBinding.binding = i; // This should be as low as possible to avoid wasting memory
binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; // only accessible in vertex 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{}; VkDescriptorSetLayoutCreateInfo info{};
info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
info.pNext = nullptr; info.pNext = nullptr;
info.flags = 0; info.flags = 0;
info.bindingCount = (uint32_t)bindings.size(); info.bindingCount = (uint32_t)vulkanBindings.size();
info.pBindings = bindings.data(); info.pBindings = vulkanBindings.data();
VKCHECK(vkCreateDescriptorSetLayout(pimpl->device.device, &info, nullptr, &out->layout)); VKCHECK(vkCreateDescriptorSetLayout(pimpl->device.device, &info, nullptr, &out->layout));
return out; return out;
@ -1039,7 +1058,7 @@ namespace engine {
return set; 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); 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)
{
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::DescriptorBuffer* out = new gfx::DescriptorBuffer{}; gfx::UniformBuffer* out = new gfx::UniformBuffer{};
/* first make staging buffer */ /* first make staging buffer */
out->stagingBuffer.size = size; out->stagingBuffer.size = size;
out->stagingBuffer.type = gfx::BufferType::UNIFORM; out->stagingBuffer.type = gfx::BufferType::UNIFORM;
out->stagingBuffer.hostVisible = true;
{ {
VkBufferCreateInfo stagingBufferInfo{}; VkBufferCreateInfo stagingBufferInfo{};
stagingBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; stagingBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
@ -1098,7 +1142,6 @@ namespace engine {
for (uint32_t i = 0; i < FRAMES_IN_FLIGHT; i++) { for (uint32_t i = 0; i < FRAMES_IN_FLIGHT; i++) {
out->gpuBuffers[i].size = out->stagingBuffer.size; out->gpuBuffers[i].size = out->stagingBuffer.size;
out->gpuBuffers[i].type = gfx::BufferType::UNIFORM; out->gpuBuffers[i].type = gfx::BufferType::UNIFORM;
out->gpuBuffers[i].hostVisible = false;
VkBufferCreateInfo gpuBufferInfo{}; VkBufferCreateInfo gpuBufferInfo{};
gpuBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; 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++) { 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); assert(offset + size <= buffer->stagingBuffer.size);
@ -1145,7 +1188,7 @@ namespace engine {
/* queue the writes to each gpu buffer */ /* queue the writes to each gpu buffer */
// This is required as buffers cannot be updated if they are currently in use // This is required as buffers cannot be updated if they are currently in use
for (uint32_t i = 0; i < FRAMES_IN_FLIGHT; i++) { 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{}; auto out = new gfx::Buffer{};
out->size = size; out->size = size;
out->type = type; out->type = type;
out->hostVisible = false;
VkBuffer stagingBuffer; VkBuffer stagingBuffer;
VmaAllocation stagingAllocation; VmaAllocation stagingAllocation;

View File

@ -48,13 +48,13 @@ namespace engine {
RenderData::SetZeroBuffer setZeroBuffer{ RenderData::SetZeroBuffer setZeroBuffer{
.proj = projMatrix .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{ RenderData::SetOneBuffer setOneBuffer{
.view = viewMatrix .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 */ /* render all renderable entities */