Skip to content

Commit

Permalink
igl | vulkan | Separate descriptor set updates for textures/buffers
Browse files Browse the repository at this point in the history
Summary: Separate descriptor set updates for textures/buffers.

Reviewed By: EricGriffith

Differential Revision: D47744330

fbshipit-source-id: 33b166b18e577128f33a8d1a111dce457dfeb269
  • Loading branch information
corporateshark authored and facebook-github-bot committed Jul 26, 2023
1 parent 77f10ab commit b3729a0
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 51 deletions.
3 changes: 1 addition & 2 deletions src/igl/vulkan/ComputeCommandEncoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ ComputeCommandEncoder::ComputeCommandEncoder(const std::shared_ptr<CommandBuffer
IGL_ASSERT(commandBuffer);

ctx_.checkAndUpdateDescriptorSets();

binder_.updateBindings();
ctx_.bindDefaultDescriptorSets(cmdBuffer_, VK_PIPELINE_BIND_POINT_COMPUTE);

isEncoding_ = true;
}
Expand Down
3 changes: 1 addition & 2 deletions src/igl/vulkan/RenderCommandEncoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -264,8 +264,7 @@ void RenderCommandEncoder::initialize(const RenderPassDesc& renderPass,
bindScissorRect(scissor);

ctx_.checkAndUpdateDescriptorSets();

binder_.updateBindings();
ctx_.bindDefaultDescriptorSets(cmdBuffer_, VK_PIPELINE_BIND_POINT_GRAPHICS);

vkCmdBeginRenderPass(cmdBuffer_, &bi, VK_SUBPASS_CONTENTS_INLINE);

Expand Down
34 changes: 22 additions & 12 deletions src/igl/vulkan/ResourcesBinder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,11 @@ void ResourcesBinder::bindBuffer(uint32_t index, igl::vulkan::Buffer* buffer, si
return;
}

bindings_.buffers[index] = {buffer, bufferOffset};
isBindingsUpdateRequired_ = true;
if (bindingsBuffers_.buffers[index].buf != buffer ||
bindingsBuffers_.buffers[index].offset != bufferOffset) {
bindingsBuffers_.buffers[index] = {buffer, bufferOffset};
isDirtyBuffers_ = true;
}
}

void ResourcesBinder::bindSamplerState(uint32_t index, igl::vulkan::SamplerState* samplerState) {
Expand All @@ -41,9 +44,12 @@ void ResourcesBinder::bindSamplerState(uint32_t index, igl::vulkan::SamplerState
return;
}

bindings_.samplers[index] = samplerState ? samplerState->sampler_.get() : nullptr;
igl::vulkan::VulkanSampler* newSampler = samplerState ? samplerState->sampler_.get() : nullptr;

isBindingsUpdateRequired_ = true;
if (bindingsTextures_.samplers[index] != newSampler) {
bindingsTextures_.samplers[index] = newSampler;
isDirtyTextures_ = true;
}
}

void ResourcesBinder::bindTexture(uint32_t index, igl::vulkan::Texture* tex) {
Expand Down Expand Up @@ -75,19 +81,23 @@ void ResourcesBinder::bindTexture(uint32_t index, igl::vulkan::Texture* tex) {
}
}

bindings_.textures[index] = tex ? &tex->getVulkanTexture() : nullptr;
igl::vulkan::VulkanTexture* newTexture = tex ? &tex->getVulkanTexture() : nullptr;

isBindingsUpdateRequired_ = true;
if (bindingsTextures_.textures[index] != newTexture) {
bindingsTextures_.textures[index] = newTexture;
isDirtyTextures_ = true;
}
}

void ResourcesBinder::updateBindings() {
if (!isBindingsUpdateRequired_) {
return;
if (isDirtyTextures_) {
ctx_.updateBindingsTextures(cmdBuffer_, bindPoint_, bindingsTextures_);
isDirtyTextures_ = false;
}
if (isDirtyBuffers_) {
ctx_.updateBindingsBuffers(cmdBuffer_, bindPoint_, bindingsBuffers_);
isDirtyBuffers_ = false;
}

ctx_.updateBindings(cmdBuffer_, bindPoint_, bindings_);

isBindingsUpdateRequired_ = false;
}

void ResourcesBinder::bindPipeline(VkPipeline pipeline) {
Expand Down
11 changes: 8 additions & 3 deletions src/igl/vulkan/ResourcesBinder.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,12 @@ struct BufferInfo {
size_t offset = 0;
};

struct Bindings {
struct BindingsTextures {
igl::vulkan::VulkanTexture* textures[IGL_TEXTURE_SAMPLERS_MAX] = {};
igl::vulkan::VulkanSampler* samplers[IGL_TEXTURE_SAMPLERS_MAX] = {};
};

struct BindingsBuffers {
BufferInfo buffers[IGL_UNIFORM_BLOCKS_BINDING_MAX] = {};
};

Expand Down Expand Up @@ -58,8 +61,10 @@ class ResourcesBinder final {
const VulkanContext& ctx_;
VkCommandBuffer cmdBuffer_ = VK_NULL_HANDLE;
VkPipeline lastPipelineBound_ = VK_NULL_HANDLE;
bool isBindingsUpdateRequired_ = true;
Bindings bindings_;
bool isDirtyTextures_ = true;
bool isDirtyBuffers_ = true;
BindingsTextures bindingsTextures_;
BindingsBuffers bindingsBuffers_;
VkPipelineBindPoint bindPoint_ = VK_PIPELINE_BIND_POINT_GRAPHICS;
};

Expand Down
105 changes: 80 additions & 25 deletions src/igl/vulkan/VulkanContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,15 @@

namespace {

/*
* 0 - bindless textures/samplers
* 1 - textures/samplers
* 2 - uniform buffers
* 3 - storage buffers
*/
const uint32_t kBindPoint_Bindless = 0;
const uint32_t kBindPoint_Textures = 1;
const uint32_t kBindPoint_Buffers = 2;

/*
These bindings should match GLSL declarations injected into shaders in
Expand Down Expand Up @@ -1235,19 +1243,30 @@ uint64_t VulkanContext::getFrameNumber() const {
return swapchain_ ? swapchain_->getFrameNumber() : 0u;
}

void VulkanContext::updateBindings(VkCommandBuffer cmdBuf,
VkPipelineBindPoint bindPoint,
const Bindings& data) const {
void VulkanContext::bindDefaultDescriptorSets(VkCommandBuffer cmdBuf,
VkPipelineBindPoint bindPoint) const {
const bool isGraphics = bindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS;

VkDescriptorSet dsetTex = textureDSets_[currentDSetIndex_].ds;
VkDescriptorSet dsetBufUniform = bufferUniformDSets_[currentDSetIndex_].ds;
VkDescriptorSet dsetBufStorage = bufferStorageDSets_[currentDSetIndex_].ds;
// they all have the same handle, so we wait only once
immediate_->wait(std::exchange(textureDSets_[currentDSetIndex_].handle, {}));
bufferUniformDSets_[currentDSetIndex_].handle = {};
bufferStorageDSets_[currentDSetIndex_].handle = {};
currentDSetIndex_ = (currentDSetIndex_ + 1) % textureDSets_.size();
#if IGL_VULKAN_PRINT_COMMANDS
IGL_LOG_INFO("%p vkCmdBindDescriptorSets(%u) - bindless\n", cmdBuf, bindPoint);
#endif // IGL_VULKAN_PRINT_COMMANDS
vkCmdBindDescriptorSets(
cmdBuf,
bindPoint,
(isGraphics ? pipelineLayoutGraphics_ : pipelineLayoutCompute_)->getVkPipelineLayout(),
kBindPoint_Bindless,
1,
&bindlessDSet_.ds,
0,
nullptr);
}

void VulkanContext::updateBindingsTextures(VkCommandBuffer cmdBuf,
VkPipelineBindPoint bindPoint,
const BindingsTextures& data) const {
VkDescriptorSet dsetTex = textureDSets_[currentDSetIndexTextures_].ds;
immediate_->wait(std::exchange(textureDSets_[currentDSetIndexTextures_].handle, {}));
currentDSetIndexTextures_ = (currentDSetIndexTextures_ + 1) % textureDSets_.size();

// 1. Sampled and storage images

Expand Down Expand Up @@ -1278,7 +1297,7 @@ void VulkanContext::updateBindings(VkCommandBuffer cmdBuf,
VK_NULL_HANDLE,
VK_IMAGE_LAYOUT_UNDEFINED};
}
std::array<VkWriteDescriptorSet, IGL_TEXTURE_SAMPLERS_MAX + IGL_UNIFORM_BLOCKS_BINDING_MAX> write;
std::array<VkWriteDescriptorSet, 6> write{}; // 2D, 2D array, 3D, Cube, Sampler, SamplerShadow
uint32_t numWrites = 0;

// use the same indexing for every texture type
Expand All @@ -1290,8 +1309,40 @@ void VulkanContext::updateBindings(VkCommandBuffer cmdBuf,
write[numWrites++] = ivkGetWriteDescriptorSet_ImageInfo(
dsetTex, i, VK_DESCRIPTOR_TYPE_SAMPLER, numSamplers, infoSamplers.data());
}
IGL_ASSERT(numWrites == write.size());

// 3. Uniform/storage buffers
vkUpdateDescriptorSets(device_->getVkDevice(), numWrites, write.data(), 0, nullptr);

const bool isGraphics = bindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS;

#if IGL_VULKAN_PRINT_COMMANDS
IGL_LOG_INFO("%p vkCmdBindDescriptorSets(%u) - textures\n", cmdBuf, bindPoint);
#endif // IGL_VULKAN_PRINT_COMMANDS
vkCmdBindDescriptorSets(
cmdBuf,
bindPoint,
(isGraphics ? pipelineLayoutGraphics_ : pipelineLayoutCompute_)->getVkPipelineLayout(),
kBindPoint_Textures,
1,
&dsetTex,
0,
nullptr);
}

void VulkanContext::updateBindingsBuffers(VkCommandBuffer cmdBuf,
VkPipelineBindPoint bindPoint,
const BindingsBuffers& data) const {
VkDescriptorSet dsetBufUniform = bufferUniformDSets_[currentDSetIndexBuffers_].ds;
VkDescriptorSet dsetBufStorage = bufferStorageDSets_[currentDSetIndexBuffers_].ds;
// both buffer types reuse the same handle, so we wait only once
immediate_->wait(std::exchange(bufferUniformDSets_[currentDSetIndexBuffers_].handle, {}));
bufferStorageDSets_[currentDSetIndexBuffers_].handle = {};
currentDSetIndexBuffers_ = (currentDSetIndexBuffers_ + 1) % bufferUniformDSets_.size();

// Update uniform/storage buffers

std::array<VkWriteDescriptorSet, IGL_UNIFORM_BLOCKS_BINDING_MAX> write;
uint32_t numWrites = 0;

std::array<VkDescriptorBufferInfo, IGL_UNIFORM_BLOCKS_BINDING_MAX> infoBuffers{};
uint32_t numBuffers = 0;
Expand Down Expand Up @@ -1320,24 +1371,24 @@ void VulkanContext::updateBindings(VkCommandBuffer cmdBuf,
1,
&infoBuffers[numBuffers]);
numBuffers++;
IGL_ASSERT(numWrites < IGL_TEXTURE_SAMPLERS_MAX + IGL_UNIFORM_BLOCKS_BINDING_MAX);
IGL_ASSERT(numWrites <= IGL_UNIFORM_BLOCKS_BINDING_MAX);
}

vkUpdateDescriptorSets(device_->getVkDevice(), numWrites, write.data(), 0, nullptr);

const bool isGraphics = bindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS;

// @lint-ignore CLANGTIDY
const VkDescriptorSet sets[] = {
bindlessDSet_.ds, dsetTex, dsetBufUniform, dsetBufStorage}; // 0, 1, 2, 3
const VkDescriptorSet sets[] = {dsetBufUniform, dsetBufStorage}; // 2, 3

#if IGL_VULKAN_PRINT_COMMANDS
IGL_LOG_INFO(
"%p vkCmdBindDescriptorSets(%u, %zu)\n", cmdBuf, bindPoint, IGL_ARRAY_NUM_ELEMENTS(sets));
IGL_LOG_INFO("%p vkCmdBindDescriptorSets(%u) - buffers\n", cmdBuf, bindPoint);
#endif // IGL_VULKAN_PRINT_COMMANDS
vkCmdBindDescriptorSets(
cmdBuf,
bindPoint,
(isGraphics ? pipelineLayoutGraphics_ : pipelineLayoutCompute_)->getVkPipelineLayout(),
kBindPoint_Bindless,
kBindPoint_Buffers,
IGL_ARRAY_NUM_ELEMENTS(sets),
sets,
0,
Expand All @@ -1347,19 +1398,23 @@ void VulkanContext::updateBindings(VkCommandBuffer cmdBuf,
void VulkanContext::markSubmit(const VulkanImmediateCommands::SubmitHandle& handle) const {
bindlessDSet_.handle = handle;

for (uint32_t i = prevSubmitIndexTextures_; i != currentDSetIndexTextures_;
i = (i + 1) % textureDSets_.size()) {
textureDSets_[i].handle = handle;
}

// they all should have the same number of elements
const uint32_t num = static_cast<uint32_t>(textureDSets_.size());
const uint32_t num = static_cast<uint32_t>(bufferUniformDSets_.size());

IGL_ASSERT(bufferUniformDSets_.size() == num);
IGL_ASSERT(bufferStorageDSets_.size() == num);
IGL_ASSERT(bufferUniformDSets_.size() == bufferStorageDSets_.size());

for (uint32_t i = prevSubmitIndex_; i != currentDSetIndex_; i = (i + 1) % num) {
textureDSets_[i].handle = handle;
for (uint32_t i = prevSubmitIndexBuffers_; i != currentDSetIndexBuffers_; i = (i + 1) % num) {
bufferUniformDSets_[i].handle = handle;
bufferStorageDSets_[i].handle = handle;
}

prevSubmitIndex_ = currentDSetIndex_;
prevSubmitIndexTextures_ = currentDSetIndexTextures_;
prevSubmitIndexBuffers_ = currentDSetIndexBuffers_;
}

void VulkanContext::deferredTask(std::packaged_task<void()>&& task, SubmitHandle handle) const {
Expand Down
20 changes: 13 additions & 7 deletions src/igl/vulkan/VulkanContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ class VulkanSemaphore;
class VulkanSwapchain;
class VulkanTexture;

struct Bindings;
struct TextureBindings;
struct BindingsBuffers;
struct BindingsTextures;
struct VulkanContextImpl;

struct DeviceQueues {
Expand Down Expand Up @@ -192,6 +192,7 @@ class VulkanContext final {
void createInstance(const size_t numExtraExtensions, const char** extraExtensions);
void createSurface(void* window, void* display);
void checkAndUpdateDescriptorSets() const;
void bindDefaultDescriptorSets(VkCommandBuffer cmdBuf, VkPipelineBindPoint bindPointa) const;
void querySurfaceCapabilities();
void processDeferredTasks() const;
void waitDeferredTasks();
Expand Down Expand Up @@ -274,8 +275,10 @@ class VulkanContext final {
mutable std::vector<DescriptorSet> textureDSets_;
mutable std::vector<DescriptorSet> bufferUniformDSets_;
mutable std::vector<DescriptorSet> bufferStorageDSets_;
mutable uint32_t currentDSetIndex_ = 0;
mutable uint32_t prevSubmitIndex_ = 0;
mutable uint32_t currentDSetIndexTextures_ = 0;
mutable uint32_t currentDSetIndexBuffers_ = 0;
mutable uint32_t prevSubmitIndexTextures_ = 0;
mutable uint32_t prevSubmitIndexBuffers_ = 0;
std::unique_ptr<igl::vulkan::VulkanPipelineLayout> pipelineLayoutGraphics_;
std::unique_ptr<igl::vulkan::VulkanPipelineLayout> pipelineLayoutCompute_;
// don't use staging on devices with shared host-visible memory
Expand Down Expand Up @@ -318,9 +321,12 @@ class VulkanContext final {
// Enhanced shader debug: line drawing
std::unique_ptr<EnhancedShaderDebuggingStore> enhancedShaderDebuggingStore_;

void updateBindings(VkCommandBuffer cmdBuf,
VkPipelineBindPoint bindPoint,
const Bindings& data) const;
void updateBindingsTextures(VkCommandBuffer cmdBuf,
VkPipelineBindPoint bindPoint,
const BindingsTextures& data) const;
void updateBindingsBuffers(VkCommandBuffer cmdBuf,
VkPipelineBindPoint bindPoint,
const BindingsBuffers& data) const;
void markSubmit(const SubmitHandle& handle) const;

struct DeferredTask {
Expand Down

0 comments on commit b3729a0

Please sign in to comment.