Skip to content

Commit

Permalink
Allow writing directly into the packed descriptor buffer, saving a me…
Browse files Browse the repository at this point in the history
…mcpy.
  • Loading branch information
hrydgard committed Oct 11, 2023
1 parent f931f85 commit 183d493
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 42 deletions.
17 changes: 17 additions & 0 deletions Common/Data/Collections/FastVec.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,23 @@ class FastVec {
size_ += count;
}

T *extend_uninitialized(size_t count) {
size_t sz = size_;
if (size_ + count <= capacity_) {
size_ += count;
return &data_[sz];
} else {
size_t newCapacity = size_ + count * 2; // Leave some extra room when growing in all cases
if (newCapacity < capacity_ * 2) {
// Standard amortized O(1).
newCapacity = capacity_ * 2;
}
IncreaseCapacityTo(newCapacity);
size_ += count;
return &data_[sz];
}
}

void LockCapacity() {
#ifdef _DEBUG
capacityLocked_ = true;
Expand Down
3 changes: 1 addition & 2 deletions Common/GPU/Vulkan/VulkanRenderManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1747,10 +1747,9 @@ void VKRPipelineLayout::FlushDescSets(VulkanContext *vulkan, int frame, QueuePro
int numBuffers = 0;
int numImages = 0;
for (int i = 0; i < d.count; i++) {
if (!data[i].image.view) { // This automatically also checks for an null buffer.
if (!data[i].image.view) { // This automatically also checks for an null buffer due to the union.
continue;
}

switch (this->bindingTypes[i]) {
case BindingType::COMBINED_IMAGE_SAMPLER:
_dbg_assert_(data[i].image.sampler != VK_NULL_HANDLE);
Expand Down
19 changes: 8 additions & 11 deletions Common/GPU/Vulkan/VulkanRenderManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -451,38 +451,36 @@ class VulkanRenderManager {
curRenderStep_->render.stencilStore = VKRRenderPassStoreAction::DONT_CARE;
}

private:
// Descriptors will match the current pipeline layout, set by the last call to BindPipeline.
// Count is the count of void*s. Two are needed for COMBINED_IMAGE_SAMPLER, everything else is a single one.
// The goal is to keep this function very small and fast, and do the expensive work on the render thread or
// another thread.
int BindDescriptors(const PackedDescriptor *desc, int count) {
PackedDescriptor *PushDescriptorSet(int count, int *descSetIndex) {
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER);

int curFrame = vulkan_->GetCurFrame();

VKRPipelineLayout::FrameData &data = curPipelineLayout_->frameData[curFrame];

size_t offset = data.descData_.size();
data.descData_.extend(desc, count);
PackedDescriptor *retval = data.descData_.extend_uninitialized(count);

int setIndex = (int)data.descSets_.size();
PendingDescSet &descSet = data.descSets_.push_uninitialized();
descSet.offset = (uint32_t)offset;
descSet.count = count;
// descSet.set = VK_NULL_HANDLE; // to be filled in
return setIndex;
*descSetIndex = setIndex;
return retval;
}

public:
void Draw(const PackedDescriptor *desc, int descCount, int numUboOffsets, const uint32_t *uboOffsets, VkBuffer vbuffer, int voffset, int count, int offset = 0) {
void Draw(int descSetIndex, int numUboOffsets, const uint32_t *uboOffsets, VkBuffer vbuffer, int voffset, int count, int offset = 0) {
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER && curStepHasViewport_ && curStepHasScissor_);
int setIndex = BindDescriptors(desc, descCount);
VkRenderData &data = curRenderStep_->commands.push_uninitialized();
data.cmd = VKRRenderCommand::DRAW;
data.draw.count = count;
data.draw.offset = offset;
data.draw.descSetIndex = setIndex;
data.draw.descSetIndex = descSetIndex;
data.draw.vbuffer = vbuffer;
data.draw.voffset = voffset;
data.draw.numUboOffsets = numUboOffsets;
Expand All @@ -492,14 +490,13 @@ class VulkanRenderManager {
curRenderStep_->render.numDraws++;
}

void DrawIndexed(const PackedDescriptor *desc, int descCount, int numUboOffsets, const uint32_t *uboOffsets, VkBuffer vbuffer, int voffset, VkBuffer ibuffer, int ioffset, int count, int numInstances) {
void DrawIndexed(int descSetIndex, int numUboOffsets, const uint32_t *uboOffsets, VkBuffer vbuffer, int voffset, VkBuffer ibuffer, int ioffset, int count, int numInstances) {
_dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER && curStepHasViewport_ && curStepHasScissor_);
int setIndex = BindDescriptors(desc, descCount);
VkRenderData &data = curRenderStep_->commands.push_uninitialized();
data.cmd = VKRRenderCommand::DRAW_INDEXED;
data.drawIndexed.count = count;
data.drawIndexed.instances = numInstances;
data.drawIndexed.descSetIndex = setIndex;
data.drawIndexed.descSetIndex = descSetIndex;
data.drawIndexed.vbuffer = vbuffer;
data.drawIndexed.voffset = voffset;
data.drawIndexed.ibuffer = ibuffer;
Expand Down
15 changes: 9 additions & 6 deletions Common/GPU/Vulkan/thin3d_vulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1417,9 +1417,10 @@ void VKContext::Draw(int vertexCount, int offset) {

BindCurrentPipeline();
ApplyDynamicState();
PackedDescriptor descriptors[4];
int descSetIndex;
PackedDescriptor *descriptors = renderManager_.PushDescriptorSet(4, &descSetIndex);
BindDescriptors(vulkanUBObuf, descriptors);
renderManager_.Draw(descriptors, ARRAY_SIZE(descriptors), 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset + curVBufferOffsets_[0], vertexCount, offset);
renderManager_.Draw(descSetIndex, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset + curVBufferOffsets_[0], vertexCount, offset);
}

void VKContext::DrawIndexed(int vertexCount, int offset) {
Expand All @@ -1433,9 +1434,10 @@ void VKContext::DrawIndexed(int vertexCount, int offset) {

BindCurrentPipeline();
ApplyDynamicState();
PackedDescriptor descriptors[4];
int descSetIndex;
PackedDescriptor *descriptors = renderManager_.PushDescriptorSet(4, &descSetIndex);
BindDescriptors(vulkanUBObuf, descriptors);
renderManager_.DrawIndexed(descriptors, ARRAY_SIZE(descriptors), 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset + curVBufferOffsets_[0], vulkanIbuf, (int)ibBindOffset + offset * sizeof(uint32_t), vertexCount, 1);
renderManager_.DrawIndexed(descSetIndex, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset + curVBufferOffsets_[0], vulkanIbuf, (int)ibBindOffset + offset * sizeof(uint32_t), vertexCount, 1);
}

void VKContext::DrawUP(const void *vdata, int vertexCount) {
Expand All @@ -1455,9 +1457,10 @@ void VKContext::DrawUP(const void *vdata, int vertexCount) {

BindCurrentPipeline();
ApplyDynamicState();
PackedDescriptor descriptors[4];
int descSetIndex;
PackedDescriptor *descriptors = renderManager_.PushDescriptorSet(4, &descSetIndex);
BindDescriptors(vulkanUBObuf, descriptors);
renderManager_.Draw(descriptors, ARRAY_SIZE(descriptors), 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset + curVBufferOffsets_[0], vertexCount);
renderManager_.Draw(descSetIndex, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset + curVBufferOffsets_[0], vertexCount);
}

void VKContext::BindCurrentPipeline() {
Expand Down
41 changes: 18 additions & 23 deletions GPU/Vulkan/DrawEngineVulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -343,18 +343,17 @@ void DrawEngineVulkan::DoFlush() {
dirtyUniforms_ |= shaderManager_->UpdateUniforms(framebufferManager_->UseBufferedRendering());
UpdateUBOs();

PackedDescriptor descriptors[9]{};
int descCount = 6;
if (tess)
descCount = 9;
int descSetIndex;
PackedDescriptor *descriptors = renderManager->PushDescriptorSet(descCount, &descSetIndex);
descriptors[0].image.view = imageView;
descriptors[0].image.sampler = sampler;
if (boundSecondary_) {
descriptors[1].image.view = boundSecondary_;
descriptors[1].image.sampler = samplerSecondaryNearest_;
}
if (boundDepal_) {
descriptors[2].image.view = boundDepal_;
descriptors[2].image.sampler = boundDepalSmoothed_ ? samplerSecondaryLinear_ : samplerSecondaryNearest_;
}
descriptors[1].image.view = boundSecondary_;
descriptors[1].image.sampler = samplerSecondaryNearest_;
descriptors[2].image.view = boundDepal_;
descriptors[2].image.sampler = (boundDepal_ && boundDepalSmoothed_) ? samplerSecondaryLinear_ : samplerSecondaryNearest_;
descriptors[3].buffer.buffer = baseBuf;
descriptors[3].buffer.range = sizeof(UB_VS_FS_Base);
descriptors[4].buffer.buffer = lightBuf;
Expand All @@ -368,7 +367,6 @@ void DrawEngineVulkan::DoFlush() {
descriptors[j + 6].buffer.offset = bufInfo[j].offset;
descriptors[j + 6].buffer.range = bufInfo[j].range;
}
descCount = 9;
}
// TODO: Can we avoid binding all three when not needed? Same below for hardware transform.
// Think this will require different descriptor set layouts.
Expand All @@ -379,9 +377,9 @@ void DrawEngineVulkan::DoFlush() {
if (!ibuf) {
ibOffset = (uint32_t)pushIndex_->Push(decIndex_, sizeof(uint16_t) * indexGen.VertexCount(), 4, &ibuf);
}
renderManager->DrawIndexed(descriptors, descCount, ARRAY_SIZE(dynamicUBOOffsets), dynamicUBOOffsets, vbuf, vbOffset, ibuf, ibOffset, vertexCount, 1);
renderManager->DrawIndexed(descSetIndex, ARRAY_SIZE(dynamicUBOOffsets), dynamicUBOOffsets, vbuf, vbOffset, ibuf, ibOffset, vertexCount, 1);
} else {
renderManager->Draw(descriptors, descCount, ARRAY_SIZE(dynamicUBOOffsets), dynamicUBOOffsets, vbuf, vbOffset, vertexCount);
renderManager->Draw(descSetIndex, ARRAY_SIZE(dynamicUBOOffsets), dynamicUBOOffsets, vbuf, vbOffset, vertexCount);
}
} else {
PROFILE_THIS_SCOPE("soft");
Expand Down Expand Up @@ -509,18 +507,15 @@ void DrawEngineVulkan::DoFlush() {
// Even if the first draw is through-mode, make sure we at least have one copy of these uniforms buffered
UpdateUBOs();

PackedDescriptor descriptors[9]{};
int descCount = 6;
int descSetIndex;
PackedDescriptor *descriptors = renderManager->PushDescriptorSet(descCount, &descSetIndex);
descriptors[0].image.view = imageView;
descriptors[0].image.sampler = sampler;
if (boundSecondary_) {
descriptors[1].image.view = boundSecondary_;
descriptors[1].image.sampler = samplerSecondaryNearest_;
}
if (boundDepal_) {
descriptors[2].image.view = boundDepal_;
descriptors[2].image.sampler = boundDepalSmoothed_ ? samplerSecondaryLinear_ : samplerSecondaryNearest_;
}
descriptors[1].image.view = boundSecondary_;
descriptors[1].image.sampler = samplerSecondaryNearest_;
descriptors[2].image.view = boundDepal_;
descriptors[2].image.sampler = (boundDepal_ && boundDepalSmoothed_) ? samplerSecondaryLinear_ : samplerSecondaryNearest_;
descriptors[3].buffer.buffer = baseBuf;
descriptors[3].buffer.range = sizeof(UB_VS_FS_Base);
descriptors[4].buffer.buffer = lightBuf;
Expand All @@ -538,11 +533,11 @@ void DrawEngineVulkan::DoFlush() {
VkBuffer vbuf, ibuf;
vbOffset = (uint32_t)pushVertex_->Push(result.drawBuffer, maxIndex * sizeof(TransformedVertex), 4, &vbuf);
ibOffset = (uint32_t)pushIndex_->Push(inds, sizeof(short) * result.drawNumTrans, 4, &ibuf);
renderManager->DrawIndexed(descriptors, descCount, ARRAY_SIZE(dynamicUBOOffsets), dynamicUBOOffsets, vbuf, vbOffset, ibuf, ibOffset, result.drawNumTrans, 1);
renderManager->DrawIndexed(descSetIndex, ARRAY_SIZE(dynamicUBOOffsets), dynamicUBOOffsets, vbuf, vbOffset, ibuf, ibOffset, result.drawNumTrans, 1);
} else {
VkBuffer vbuf;
vbOffset = (uint32_t)pushVertex_->Push(result.drawBuffer, result.drawNumTrans * sizeof(TransformedVertex), 4, &vbuf);
renderManager->Draw(descriptors, descCount, ARRAY_SIZE(dynamicUBOOffsets), dynamicUBOOffsets, vbuf, vbOffset, result.drawNumTrans);
renderManager->Draw(descSetIndex, ARRAY_SIZE(dynamicUBOOffsets), dynamicUBOOffsets, vbuf, vbOffset, result.drawNumTrans);
}
} else if (result.action == SW_CLEAR) {
// Note: we won't get here if the clear is alpha but not color, or color but not alpha.
Expand Down

0 comments on commit 183d493

Please sign in to comment.