Skip to content

Commit

Permalink
igl | vulkan | Consolidate typical image layout transitions
Browse files Browse the repository at this point in the history
Summary:
Image layout transitions to and from `SHADER_READ_ONLY_OPTIMAL` and `COLOR_ATTACHMENT_OPTIMAL` are used in multiple places. Consolidate them in `igl/vulkan/Common.cpp`.

P.S. Depth-stencil attachments will be fixed later.

Reviewed By: EricGriffith

Differential Revision: D49714595

fbshipit-source-id: 91af9dd8758bc0d8195550759d5d77b351f3c6d7
  • Loading branch information
corporateshark authored and facebook-github-bot committed Sep 28, 2023
1 parent 42a221a commit 18c008b
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 97 deletions.
54 changes: 0 additions & 54 deletions src/igl/vulkan/CommandBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,60 +29,6 @@ std::unique_ptr<IComputeCommandEncoder> CommandBuffer::createComputeCommandEncod
return std::make_unique<ComputeCommandEncoder>(shared_from_this(), ctx_);
}

namespace {

void transitionToColorAttachment(VkCommandBuffer buffer, ITexture* colorTex) {
// We really shouldn't get a null here, but just in case.
if (!IGL_VERIFY(colorTex)) {
return;
}

const auto& vkTex = static_cast<Texture&>(*colorTex);
const auto& colorImg = vkTex.getVulkanTexture().getVulkanImage();
if (IGL_UNEXPECTED(colorImg.isDepthFormat_ || colorImg.isStencilFormat_)) {
IGL_ASSERT_MSG(false, "Color attachments cannot have depth/stencil formats");
IGL_LOG_ERROR("Color attachments cannot have depth/stencil formats");
return;
}
IGL_ASSERT_MSG(colorImg.imageFormat_ != VK_FORMAT_UNDEFINED, "Invalid color attachment format");
if (!IGL_VERIFY((colorImg.usageFlags_ & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) != 0)) {
IGL_ASSERT_MSG(false, "Did you forget to specify TextureUsageBit::Attachment usage bit?");
IGL_LOG_ERROR("Did you forget to specify TextureUsageBit::Attachment usage bit?");
}
colorImg.transitionLayout(
buffer,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, // wait for all subsequent fragment/compute shaders
VkImageSubresourceRange{
VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS});
}

void transitionToShaderReadOnly(VkCommandBuffer cmdBuf, ITexture* texture) {
// We really shouldn't get a null here, but just in case.
if (!IGL_VERIFY(texture)) {
return;
}

const vulkan::Texture& tex = static_cast<vulkan::Texture&>(*texture);
const vulkan::VulkanImage& img = tex.getVulkanTexture().getVulkanImage();
// this must match the final layout of the render pass
img.imageLayout_ = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
if (img.usageFlags_ & VK_IMAGE_USAGE_SAMPLED_BIT) {
// transition sampled images to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
img.transitionLayout(
cmdBuf,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, // wait for all subsequent fragment shaders
VkImageSubresourceRange{
VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS});
}
}

} // namespace

std::unique_ptr<IRenderCommandEncoder> CommandBuffer::createRenderCommandEncoder(
const RenderPassDesc& renderPass,
std::shared_ptr<IFramebuffer> framebuffer,
Expand Down
56 changes: 56 additions & 0 deletions src/igl/vulkan/Common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@
#include <windows.h>
#endif

#include <igl/vulkan/Texture.h>
#include <igl/vulkan/VulkanHelpers.h>
#include <igl/vulkan/VulkanImage.h>
#include <igl/vulkan/VulkanTexture.h>
#include <igl/vulkan/util/TextureFormat.h>

namespace igl {
Expand Down Expand Up @@ -370,5 +373,58 @@ TextureRangeDesc atVkLayer(TextureType type, const TextureRangeDesc& range, uint
return type == TextureType::Cube ? range.atFace(vkLayer) : range.atLayer(vkLayer);
}

void transitionToColorAttachment(VkCommandBuffer cmdBuf, ITexture* colorTex) {
if (!colorTex) {
return;
}

const auto& vkTex = static_cast<Texture&>(*colorTex);
const auto& img = vkTex.getVulkanTexture().getVulkanImage();
if (IGL_UNEXPECTED(img.isDepthFormat_ || img.isStencilFormat_)) {
IGL_ASSERT_MSG(false, "Color attachments cannot have depth/stencil formats");
IGL_LOG_ERROR("Color attachments cannot have depth/stencil formats");
return;
}
IGL_ASSERT_MSG(img.imageFormat_ != VK_FORMAT_UNDEFINED, "Invalid color attachment format");
if (!IGL_VERIFY((img.usageFlags_ & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) != 0)) {
IGL_ASSERT_MSG(false, "Did you forget to specify TextureUsageBit::Attachment usage bit?");
IGL_LOG_ERROR("Did you forget to specify TextureUsageBit::Attachment usage bit?");
}
if (img.usageFlags_ & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
// transition to VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
img.transitionLayout(
cmdBuf,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, // wait for all subsequent fragment/compute
// shaders
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VkImageSubresourceRange{
VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS});
}
}

void transitionToShaderReadOnly(VkCommandBuffer cmdBuf, ITexture* texture) {
if (!texture) {
return;
}

const vulkan::Texture& tex = static_cast<vulkan::Texture&>(*texture);
const vulkan::VulkanImage& img = tex.getVulkanTexture().getVulkanImage();

if (img.usageFlags_ & VK_IMAGE_USAGE_SAMPLED_BIT) {
// transition to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
img.transitionLayout(
cmdBuf,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, // wait for all subsequent fragment/compute
// shaders
VkImageSubresourceRange{
VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS});
}
}

} // namespace vulkan
} // namespace igl
4 changes: 3 additions & 1 deletion src/igl/vulkan/Common.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,10 @@ igl::ColorSpace vkColorSpaceToColorSpace(VkColorSpaceKHR colorSpace);
VkMemoryPropertyFlags resourceStorageToVkMemoryPropertyFlags(igl::ResourceStorage resourceStorage);
VkCompareOp compareFunctionToVkCompareOp(igl::CompareFunction func);
VkSampleCountFlagBits getVulkanSampleCountFlags(size_t numSamples);
VkSurfaceFormatKHR colorSpaceToVkSurfaceFormat(igl::ColorSpace colorSpace, bool isBGR = false);
VkSurfaceFormatKHR colorSpaceToVkSurfaceFormat(igl::ColorSpace colorSpace, bool isBGR);
uint32_t getVkLayer(igl::TextureType type, uint32_t face, uint32_t layer);
TextureRangeDesc atVkLayer(TextureType type, const TextureRangeDesc& range, uint32_t vkLayer);
void transitionToColorAttachment(VkCommandBuffer cmdBuf, ITexture* colorTex);
void transitionToShaderReadOnly(VkCommandBuffer cmdBuf, ITexture* texture);

} // namespace igl::vulkan
45 changes: 3 additions & 42 deletions src/igl/vulkan/RenderCommandEncoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,53 +310,14 @@ void RenderCommandEncoder::endEncoding() {
return;
}

auto transitionToShaderReadOnly = [](VkCommandBuffer cmdBuf, ITexture* texture) {
if (!texture) {
return;
}
const vulkan::Texture& tex = static_cast<vulkan::Texture&>(*texture);
const vulkan::VulkanImage& img = tex.getVulkanTexture().getVulkanImage();
// this must match the final layout of the render pass
img.imageLayout_ = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
if (img.usageFlags_ & VK_IMAGE_USAGE_SAMPLED_BIT) {
// transition sampled images to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
img.transitionLayout(
cmdBuf,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, // wait for all subsequent fragment/compute
// shaders
VkImageSubresourceRange{
VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS});
}
};
auto transitionToColorAttachment = [](VkCommandBuffer cmdBuf, ITexture* texture) {
if (!texture) {
return;
}
const vulkan::Texture& tex = static_cast<vulkan::Texture&>(*texture);
const vulkan::VulkanImage& img = tex.getVulkanTexture().getVulkanImage();
img.imageLayout_ = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
if (img.usageFlags_ & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
img.transitionLayout(
cmdBuf,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VkImageSubresourceRange{
VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS});
}
};

isEncoding_ = false;

ctx_.vf_.vkCmdEndRenderPass(cmdBuffer_);

for (ITexture* IGL_NULLABLE tex : dependencies_.textures) {
if (tex) {
transitionToColorAttachment(cmdBuffer_, tex);
}
// TODO: at some point we might want to know in which layout a dependent texture wants to be. We
// can implement that by adding a notion of image layouts to IGL.
transitionToColorAttachment(cmdBuffer_, tex);
}
dependencies_ = {};

Expand Down

0 comments on commit 18c008b

Please sign in to comment.