Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 4d422c2

Browse files
null77Commit Bot
authored andcommitted
Vulkan: Move blit mipmap init to ImageHelper.
This hides the logic for manipulating the current layout and barriers into the image helper. This will make it easier to implement implicit pipeline barriers. It allows us to remove the updateLayout() hack. Bug: angleproject:2828 Change-Id: I3e59872e66064e6b105c1f398b4212fb3a6be1a7 Reviewed-on: https://chromium-review.googlesource.com/1255506 Commit-Queue: Jamie Madill <[email protected]> Reviewed-by: Shahbaz Youssefi <[email protected]>
1 parent c2116cd commit 4d422c2

File tree

4 files changed

+91
-105
lines changed

4 files changed

+91
-105
lines changed

src/libANGLE/renderer/vulkan/TextureVk.cpp

Lines changed: 7 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -675,13 +675,6 @@ gl::Error TextureVk::copySubTextureImpl(ContextVk *contextVk,
675675
return angle::Result::Continue();
676676
}
677677

678-
angle::Result TextureVk::getCommandBufferForWrite(ContextVk *contextVk,
679-
vk::CommandBuffer **commandBufferOut)
680-
{
681-
ANGLE_TRY(mImage.recordCommands(contextVk, commandBufferOut));
682-
return angle::Result::Continue();
683-
}
684-
685678
gl::Error TextureVk::setStorage(const gl::Context *context,
686679
gl::TextureType type,
687680
size_t levels,
@@ -692,7 +685,7 @@ gl::Error TextureVk::setStorage(const gl::Context *context,
692685
RendererVk *renderer = contextVk->getRenderer();
693686
const vk::Format &format = renderer->getFormat(internalFormat);
694687
vk::CommandBuffer *commandBuffer = nullptr;
695-
ANGLE_TRY(getCommandBufferForWrite(contextVk, &commandBuffer));
688+
ANGLE_TRY(mImage.recordCommands(contextVk, &commandBuffer));
696689

697690
if (mImage.valid())
698691
{
@@ -761,7 +754,7 @@ angle::Result TextureVk::copyImageDataToBuffer(ContextVk *contextVk,
761754
size_t sourceCopyAllocationSize = sourceArea.width * sourceArea.height * imageFormat.pixelBytes;
762755

763756
vk::CommandBuffer *commandBuffer = nullptr;
764-
ANGLE_TRY(getCommandBufferForWrite(contextVk, &commandBuffer));
757+
ANGLE_TRY(mImage.recordCommands(contextVk, &commandBuffer));
765758

766759
// Requirement of the copyImageToBuffer, the source image must be in SRC_OPTIMAL layout.
767760
mImage.changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
@@ -800,93 +793,7 @@ angle::Result TextureVk::copyImageDataToBuffer(ContextVk *contextVk,
800793
return angle::Result::Continue();
801794
}
802795

803-
angle::Result TextureVk::generateMipmapWithBlit(ContextVk *contextVk)
804-
{
805-
ANGLE_TRY(ensureImageInitialized(contextVk));
806-
807-
uint32_t imageLayerCount = GetImageLayerCount(mState.getType());
808-
const gl::Extents baseLevelExtents = mImage.getExtents();
809-
vk::CommandBuffer *commandBuffer = nullptr;
810-
ANGLE_TRY(getCommandBufferForWrite(contextVk, &commandBuffer));
811-
812-
mImage.changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
813-
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
814-
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, commandBuffer);
815-
816-
// We are able to use blitImage since the image format we are using supports it. This
817-
// is a faster way we can generate the mips.
818-
int32_t mipWidth = baseLevelExtents.width;
819-
int32_t mipHeight = baseLevelExtents.height;
820-
821-
// Manually manage the image memory barrier because it uses a lot more parameters than our
822-
// usual one.
823-
VkImageMemoryBarrier barrier;
824-
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
825-
barrier.image = mImage.getImage().getHandle();
826-
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
827-
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
828-
barrier.pNext = nullptr;
829-
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
830-
barrier.subresourceRange.baseArrayLayer = 0;
831-
barrier.subresourceRange.layerCount = imageLayerCount;
832-
barrier.subresourceRange.levelCount = 1;
833-
834-
for (uint32_t mipLevel = 1; mipLevel <= mState.getMipmapMaxLevel(); mipLevel++)
835-
{
836-
int32_t nextMipWidth = std::max<int32_t>(1, mipWidth >> 1);
837-
int32_t nextMipHeight = std::max<int32_t>(1, mipHeight >> 1);
838-
839-
barrier.subresourceRange.baseMipLevel = mipLevel - 1;
840-
barrier.oldLayout = mImage.getCurrentLayout();
841-
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
842-
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
843-
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
844-
845-
// We can do it for all layers at once.
846-
commandBuffer->pipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
847-
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1,
848-
&barrier);
849-
850-
VkImageBlit blit = {};
851-
blit.srcOffsets[0] = {0, 0, 0};
852-
blit.srcOffsets[1] = {mipWidth, mipHeight, 1};
853-
blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
854-
blit.srcSubresource.mipLevel = mipLevel - 1;
855-
blit.srcSubresource.baseArrayLayer = 0;
856-
blit.srcSubresource.layerCount = imageLayerCount;
857-
blit.dstOffsets[0] = {0, 0, 0};
858-
blit.dstOffsets[1] = {nextMipWidth, nextMipHeight, 1};
859-
blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
860-
blit.dstSubresource.mipLevel = mipLevel;
861-
blit.dstSubresource.baseArrayLayer = 0;
862-
blit.dstSubresource.layerCount = imageLayerCount;
863-
864-
mipWidth = nextMipWidth;
865-
mipHeight = nextMipHeight;
866-
867-
commandBuffer->blitImage(mImage.getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
868-
mImage.getImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit,
869-
VK_FILTER_LINEAR);
870-
}
871-
872-
// Transition the last mip level to the same layout as all the other ones, so we can declare
873-
// our whole image layout to be SRC_OPTIMAL.
874-
barrier.subresourceRange.baseMipLevel = mState.getMipmapMaxLevel();
875-
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
876-
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
877-
878-
// We can do it for all layers at once.
879-
commandBuffer->pipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
880-
0, 0, nullptr, 0, nullptr, 1, &barrier);
881-
882-
// This is just changing the internal state of the image helper so that the next call
883-
// to changeLayoutWithStages will use this layout as the "oldLayout" argument.
884-
mImage.updateLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
885-
886-
return angle::Result::Continue();
887-
}
888-
889-
angle::Result TextureVk::generateMipmapWithCPU(const gl::Context *context)
796+
angle::Result TextureVk::generateMipmapsWithCPU(const gl::Context *context)
890797
{
891798
ContextVk *contextVk = vk::GetImpl(context);
892799

@@ -949,11 +856,12 @@ gl::Error TextureVk::generateMipmap(const gl::Context *context)
949856
// only.
950857
if (IsMaskFlagSet(kBlitFeatureFlags, imageProperties.linearTilingFeatures))
951858
{
952-
ANGLE_TRY(generateMipmapWithBlit(contextVk));
859+
ANGLE_TRY(ensureImageInitialized(contextVk));
860+
ANGLE_TRY(mImage.generateMipmapsWithBlit(contextVk, mState.getMipmapMaxLevel()));
953861
}
954862
else
955863
{
956-
ANGLE_TRY(generateMipmapWithCPU(context));
864+
ANGLE_TRY(generateMipmapsWithCPU(context));
957865
}
958866

959867
// We're changing this textureVk content, make sure we let the graph know.
@@ -1015,7 +923,7 @@ angle::Result TextureVk::ensureImageInitialized(ContextVk *contextVk)
1015923
}
1016924
RendererVk *renderer = contextVk->getRenderer();
1017925
vk::CommandBuffer *commandBuffer = nullptr;
1018-
ANGLE_TRY(getCommandBufferForWrite(contextVk, &commandBuffer));
926+
ANGLE_TRY(mImage.recordCommands(contextVk, &commandBuffer));
1019927

1020928
const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
1021929
const gl::Extents &baseLevelExtents = baseLevelDesc.size;

src/libANGLE/renderer/vulkan/TextureVk.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -221,9 +221,7 @@ class TextureVk : public TextureImpl
221221
const gl::Rectangle &sourceArea,
222222
uint8_t **outDataPtr);
223223

224-
angle::Result generateMipmapWithBlit(ContextVk *contextVk);
225-
226-
angle::Result generateMipmapWithCPU(const gl::Context *context);
224+
angle::Result generateMipmapsWithCPU(const gl::Context *context);
227225

228226
angle::Result generateMipmapLevelsWithCPU(ContextVk *contextVk,
229227
const angle::Format &sourceFormat,
@@ -259,8 +257,6 @@ class TextureVk : public TextureImpl
259257
const uint32_t levelCount,
260258
vk::CommandBuffer *commandBuffer);
261259
void releaseImage(const gl::Context *context, RendererVk *renderer);
262-
angle::Result getCommandBufferForWrite(ContextVk *contextVk,
263-
vk::CommandBuffer **commandBufferOut);
264260
uint32_t getLevelCount() const;
265261
angle::Result initCubeMapRenderTargets(ContextVk *contextVk);
266262

src/libANGLE/renderer/vulkan/vk_helpers.cpp

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -941,6 +941,87 @@ void ImageHelper::Copy(ImageHelper *srcImage,
941941
dstImage->getImage(), dstImage->getCurrentLayout(), 1, &region);
942942
}
943943

944+
angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint maxLevel)
945+
{
946+
vk::CommandBuffer *commandBuffer = nullptr;
947+
ANGLE_TRY(recordCommands(contextVk, &commandBuffer));
948+
949+
changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
950+
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
951+
commandBuffer);
952+
953+
// We are able to use blitImage since the image format we are using supports it. This
954+
// is a faster way we can generate the mips.
955+
int32_t mipWidth = mExtents.width;
956+
int32_t mipHeight = mExtents.height;
957+
958+
// Manually manage the image memory barrier because it uses a lot more parameters than our
959+
// usual one.
960+
VkImageMemoryBarrier barrier;
961+
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
962+
barrier.image = mImage.getHandle();
963+
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
964+
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
965+
barrier.pNext = nullptr;
966+
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
967+
barrier.subresourceRange.baseArrayLayer = 0;
968+
barrier.subresourceRange.layerCount = mLayerCount;
969+
barrier.subresourceRange.levelCount = 1;
970+
971+
for (uint32_t mipLevel = 1; mipLevel <= maxLevel; mipLevel++)
972+
{
973+
int32_t nextMipWidth = std::max<int32_t>(1, mipWidth >> 1);
974+
int32_t nextMipHeight = std::max<int32_t>(1, mipHeight >> 1);
975+
976+
barrier.subresourceRange.baseMipLevel = mipLevel - 1;
977+
barrier.oldLayout = mCurrentLayout;
978+
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
979+
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
980+
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
981+
982+
// We can do it for all layers at once.
983+
commandBuffer->pipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
984+
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1,
985+
&barrier);
986+
987+
VkImageBlit blit = {};
988+
blit.srcOffsets[0] = {0, 0, 0};
989+
blit.srcOffsets[1] = {mipWidth, mipHeight, 1};
990+
blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
991+
blit.srcSubresource.mipLevel = mipLevel - 1;
992+
blit.srcSubresource.baseArrayLayer = 0;
993+
blit.srcSubresource.layerCount = mLayerCount;
994+
blit.dstOffsets[0] = {0, 0, 0};
995+
blit.dstOffsets[1] = {nextMipWidth, nextMipHeight, 1};
996+
blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
997+
blit.dstSubresource.mipLevel = mipLevel;
998+
blit.dstSubresource.baseArrayLayer = 0;
999+
blit.dstSubresource.layerCount = mLayerCount;
1000+
1001+
mipWidth = nextMipWidth;
1002+
mipHeight = nextMipHeight;
1003+
1004+
commandBuffer->blitImage(mImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, mImage,
1005+
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_LINEAR);
1006+
}
1007+
1008+
// Transition the last mip level to the same layout as all the other ones, so we can declare
1009+
// our whole image layout to be SRC_OPTIMAL.
1010+
barrier.subresourceRange.baseMipLevel = maxLevel;
1011+
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
1012+
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
1013+
1014+
// We can do it for all layers at once.
1015+
commandBuffer->pipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
1016+
0, 0, nullptr, 0, nullptr, 1, &barrier);
1017+
1018+
// This is just changing the internal state of the image helper so that the next call
1019+
// to changeLayoutWithStages will use this layout as the "oldLayout" argument.
1020+
mCurrentLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
1021+
1022+
return angle::Result::Continue();
1023+
}
1024+
9441025
// FramebufferHelper implementation.
9451026
FramebufferHelper::FramebufferHelper() : CommandGraphResource(CommandGraphResourceType::Framebuffer)
9461027
{

src/libANGLE/renderer/vulkan/vk_helpers.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,6 @@ class ImageHelper final : public CommandGraphResource
249249
GLint getSamples() const;
250250

251251
VkImageLayout getCurrentLayout() const { return mCurrentLayout; }
252-
void updateLayout(VkImageLayout layout) { mCurrentLayout = layout; }
253252

254253
void changeLayoutWithStages(VkImageAspectFlags aspectMask,
255254
VkImageLayout newLayout,
@@ -282,6 +281,8 @@ class ImageHelper final : public CommandGraphResource
282281
VkImageAspectFlags aspectMask,
283282
CommandBuffer *commandBuffer);
284283

284+
angle::Result generateMipmapsWithBlit(ContextVk *contextVk, GLuint maxLevel);
285+
285286
private:
286287
// Vulkan objects.
287288
Image mImage;

0 commit comments

Comments
 (0)