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 <jmadill@chromium.org>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
This commit is contained in:
Jamie Madill 2018-10-02 09:31:40 -04:00 коммит произвёл Commit Bot
Родитель c2116cd3af
Коммит 4d422c2907
4 изменённых файлов: 91 добавлений и 105 удалений

Просмотреть файл

@ -675,13 +675,6 @@ gl::Error TextureVk::copySubTextureImpl(ContextVk *contextVk,
return angle::Result::Continue(); return angle::Result::Continue();
} }
angle::Result TextureVk::getCommandBufferForWrite(ContextVk *contextVk,
vk::CommandBuffer **commandBufferOut)
{
ANGLE_TRY(mImage.recordCommands(contextVk, commandBufferOut));
return angle::Result::Continue();
}
gl::Error TextureVk::setStorage(const gl::Context *context, gl::Error TextureVk::setStorage(const gl::Context *context,
gl::TextureType type, gl::TextureType type,
size_t levels, size_t levels,
@ -692,7 +685,7 @@ gl::Error TextureVk::setStorage(const gl::Context *context,
RendererVk *renderer = contextVk->getRenderer(); RendererVk *renderer = contextVk->getRenderer();
const vk::Format &format = renderer->getFormat(internalFormat); const vk::Format &format = renderer->getFormat(internalFormat);
vk::CommandBuffer *commandBuffer = nullptr; vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(getCommandBufferForWrite(contextVk, &commandBuffer)); ANGLE_TRY(mImage.recordCommands(contextVk, &commandBuffer));
if (mImage.valid()) if (mImage.valid())
{ {
@ -761,7 +754,7 @@ angle::Result TextureVk::copyImageDataToBuffer(ContextVk *contextVk,
size_t sourceCopyAllocationSize = sourceArea.width * sourceArea.height * imageFormat.pixelBytes; size_t sourceCopyAllocationSize = sourceArea.width * sourceArea.height * imageFormat.pixelBytes;
vk::CommandBuffer *commandBuffer = nullptr; vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(getCommandBufferForWrite(contextVk, &commandBuffer)); ANGLE_TRY(mImage.recordCommands(contextVk, &commandBuffer));
// Requirement of the copyImageToBuffer, the source image must be in SRC_OPTIMAL layout. // Requirement of the copyImageToBuffer, the source image must be in SRC_OPTIMAL layout.
mImage.changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, mImage.changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
@ -800,93 +793,7 @@ angle::Result TextureVk::copyImageDataToBuffer(ContextVk *contextVk,
return angle::Result::Continue(); return angle::Result::Continue();
} }
angle::Result TextureVk::generateMipmapWithBlit(ContextVk *contextVk) angle::Result TextureVk::generateMipmapsWithCPU(const gl::Context *context)
{
ANGLE_TRY(ensureImageInitialized(contextVk));
uint32_t imageLayerCount = GetImageLayerCount(mState.getType());
const gl::Extents baseLevelExtents = mImage.getExtents();
vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(getCommandBufferForWrite(contextVk, &commandBuffer));
mImage.changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, commandBuffer);
// We are able to use blitImage since the image format we are using supports it. This
// is a faster way we can generate the mips.
int32_t mipWidth = baseLevelExtents.width;
int32_t mipHeight = baseLevelExtents.height;
// Manually manage the image memory barrier because it uses a lot more parameters than our
// usual one.
VkImageMemoryBarrier barrier;
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.image = mImage.getImage().getHandle();
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.pNext = nullptr;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = imageLayerCount;
barrier.subresourceRange.levelCount = 1;
for (uint32_t mipLevel = 1; mipLevel <= mState.getMipmapMaxLevel(); mipLevel++)
{
int32_t nextMipWidth = std::max<int32_t>(1, mipWidth >> 1);
int32_t nextMipHeight = std::max<int32_t>(1, mipHeight >> 1);
barrier.subresourceRange.baseMipLevel = mipLevel - 1;
barrier.oldLayout = mImage.getCurrentLayout();
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
// We can do it for all layers at once.
commandBuffer->pipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1,
&barrier);
VkImageBlit blit = {};
blit.srcOffsets[0] = {0, 0, 0};
blit.srcOffsets[1] = {mipWidth, mipHeight, 1};
blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
blit.srcSubresource.mipLevel = mipLevel - 1;
blit.srcSubresource.baseArrayLayer = 0;
blit.srcSubresource.layerCount = imageLayerCount;
blit.dstOffsets[0] = {0, 0, 0};
blit.dstOffsets[1] = {nextMipWidth, nextMipHeight, 1};
blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
blit.dstSubresource.mipLevel = mipLevel;
blit.dstSubresource.baseArrayLayer = 0;
blit.dstSubresource.layerCount = imageLayerCount;
mipWidth = nextMipWidth;
mipHeight = nextMipHeight;
commandBuffer->blitImage(mImage.getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
mImage.getImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit,
VK_FILTER_LINEAR);
}
// Transition the last mip level to the same layout as all the other ones, so we can declare
// our whole image layout to be SRC_OPTIMAL.
barrier.subresourceRange.baseMipLevel = mState.getMipmapMaxLevel();
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
// We can do it for all layers at once.
commandBuffer->pipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
0, 0, nullptr, 0, nullptr, 1, &barrier);
// This is just changing the internal state of the image helper so that the next call
// to changeLayoutWithStages will use this layout as the "oldLayout" argument.
mImage.updateLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
return angle::Result::Continue();
}
angle::Result TextureVk::generateMipmapWithCPU(const gl::Context *context)
{ {
ContextVk *contextVk = vk::GetImpl(context); ContextVk *contextVk = vk::GetImpl(context);
@ -949,11 +856,12 @@ gl::Error TextureVk::generateMipmap(const gl::Context *context)
// only. // only.
if (IsMaskFlagSet(kBlitFeatureFlags, imageProperties.linearTilingFeatures)) if (IsMaskFlagSet(kBlitFeatureFlags, imageProperties.linearTilingFeatures))
{ {
ANGLE_TRY(generateMipmapWithBlit(contextVk)); ANGLE_TRY(ensureImageInitialized(contextVk));
ANGLE_TRY(mImage.generateMipmapsWithBlit(contextVk, mState.getMipmapMaxLevel()));
} }
else else
{ {
ANGLE_TRY(generateMipmapWithCPU(context)); ANGLE_TRY(generateMipmapsWithCPU(context));
} }
// We're changing this textureVk content, make sure we let the graph know. // We're changing this textureVk content, make sure we let the graph know.
@ -1015,7 +923,7 @@ angle::Result TextureVk::ensureImageInitialized(ContextVk *contextVk)
} }
RendererVk *renderer = contextVk->getRenderer(); RendererVk *renderer = contextVk->getRenderer();
vk::CommandBuffer *commandBuffer = nullptr; vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(getCommandBufferForWrite(contextVk, &commandBuffer)); ANGLE_TRY(mImage.recordCommands(contextVk, &commandBuffer));
const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc(); const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
const gl::Extents &baseLevelExtents = baseLevelDesc.size; const gl::Extents &baseLevelExtents = baseLevelDesc.size;

Просмотреть файл

@ -221,9 +221,7 @@ class TextureVk : public TextureImpl
const gl::Rectangle &sourceArea, const gl::Rectangle &sourceArea,
uint8_t **outDataPtr); uint8_t **outDataPtr);
angle::Result generateMipmapWithBlit(ContextVk *contextVk); angle::Result generateMipmapsWithCPU(const gl::Context *context);
angle::Result generateMipmapWithCPU(const gl::Context *context);
angle::Result generateMipmapLevelsWithCPU(ContextVk *contextVk, angle::Result generateMipmapLevelsWithCPU(ContextVk *contextVk,
const angle::Format &sourceFormat, const angle::Format &sourceFormat,
@ -259,8 +257,6 @@ class TextureVk : public TextureImpl
const uint32_t levelCount, const uint32_t levelCount,
vk::CommandBuffer *commandBuffer); vk::CommandBuffer *commandBuffer);
void releaseImage(const gl::Context *context, RendererVk *renderer); void releaseImage(const gl::Context *context, RendererVk *renderer);
angle::Result getCommandBufferForWrite(ContextVk *contextVk,
vk::CommandBuffer **commandBufferOut);
uint32_t getLevelCount() const; uint32_t getLevelCount() const;
angle::Result initCubeMapRenderTargets(ContextVk *contextVk); angle::Result initCubeMapRenderTargets(ContextVk *contextVk);

Просмотреть файл

@ -941,6 +941,87 @@ void ImageHelper::Copy(ImageHelper *srcImage,
dstImage->getImage(), dstImage->getCurrentLayout(), 1, &region); dstImage->getImage(), dstImage->getCurrentLayout(), 1, &region);
} }
angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint maxLevel)
{
vk::CommandBuffer *commandBuffer = nullptr;
ANGLE_TRY(recordCommands(contextVk, &commandBuffer));
changeLayoutWithStages(VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
commandBuffer);
// We are able to use blitImage since the image format we are using supports it. This
// is a faster way we can generate the mips.
int32_t mipWidth = mExtents.width;
int32_t mipHeight = mExtents.height;
// Manually manage the image memory barrier because it uses a lot more parameters than our
// usual one.
VkImageMemoryBarrier barrier;
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.image = mImage.getHandle();
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.pNext = nullptr;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = mLayerCount;
barrier.subresourceRange.levelCount = 1;
for (uint32_t mipLevel = 1; mipLevel <= maxLevel; mipLevel++)
{
int32_t nextMipWidth = std::max<int32_t>(1, mipWidth >> 1);
int32_t nextMipHeight = std::max<int32_t>(1, mipHeight >> 1);
barrier.subresourceRange.baseMipLevel = mipLevel - 1;
barrier.oldLayout = mCurrentLayout;
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
// We can do it for all layers at once.
commandBuffer->pipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1,
&barrier);
VkImageBlit blit = {};
blit.srcOffsets[0] = {0, 0, 0};
blit.srcOffsets[1] = {mipWidth, mipHeight, 1};
blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
blit.srcSubresource.mipLevel = mipLevel - 1;
blit.srcSubresource.baseArrayLayer = 0;
blit.srcSubresource.layerCount = mLayerCount;
blit.dstOffsets[0] = {0, 0, 0};
blit.dstOffsets[1] = {nextMipWidth, nextMipHeight, 1};
blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
blit.dstSubresource.mipLevel = mipLevel;
blit.dstSubresource.baseArrayLayer = 0;
blit.dstSubresource.layerCount = mLayerCount;
mipWidth = nextMipWidth;
mipHeight = nextMipHeight;
commandBuffer->blitImage(mImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, mImage,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_LINEAR);
}
// Transition the last mip level to the same layout as all the other ones, so we can declare
// our whole image layout to be SRC_OPTIMAL.
barrier.subresourceRange.baseMipLevel = maxLevel;
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
// We can do it for all layers at once.
commandBuffer->pipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
0, 0, nullptr, 0, nullptr, 1, &barrier);
// This is just changing the internal state of the image helper so that the next call
// to changeLayoutWithStages will use this layout as the "oldLayout" argument.
mCurrentLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
return angle::Result::Continue();
}
// FramebufferHelper implementation. // FramebufferHelper implementation.
FramebufferHelper::FramebufferHelper() : CommandGraphResource(CommandGraphResourceType::Framebuffer) FramebufferHelper::FramebufferHelper() : CommandGraphResource(CommandGraphResourceType::Framebuffer)
{ {

Просмотреть файл

@ -249,7 +249,6 @@ class ImageHelper final : public CommandGraphResource
GLint getSamples() const; GLint getSamples() const;
VkImageLayout getCurrentLayout() const { return mCurrentLayout; } VkImageLayout getCurrentLayout() const { return mCurrentLayout; }
void updateLayout(VkImageLayout layout) { mCurrentLayout = layout; }
void changeLayoutWithStages(VkImageAspectFlags aspectMask, void changeLayoutWithStages(VkImageAspectFlags aspectMask,
VkImageLayout newLayout, VkImageLayout newLayout,
@ -282,6 +281,8 @@ class ImageHelper final : public CommandGraphResource
VkImageAspectFlags aspectMask, VkImageAspectFlags aspectMask,
CommandBuffer *commandBuffer); CommandBuffer *commandBuffer);
angle::Result generateMipmapsWithBlit(ContextVk *contextVk, GLuint maxLevel);
private: private:
// Vulkan objects. // Vulkan objects.
Image mImage; Image mImage;