зеркало из https://github.com/AvaloniaUI/angle.git
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:
Родитель
c2116cd3af
Коммит
4d422c2907
|
@ -675,13 +675,6 @@ gl::Error TextureVk::copySubTextureImpl(ContextVk *contextVk,
|
|||
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::TextureType type,
|
||||
size_t levels,
|
||||
|
@ -692,7 +685,7 @@ gl::Error TextureVk::setStorage(const gl::Context *context,
|
|||
RendererVk *renderer = contextVk->getRenderer();
|
||||
const vk::Format &format = renderer->getFormat(internalFormat);
|
||||
vk::CommandBuffer *commandBuffer = nullptr;
|
||||
ANGLE_TRY(getCommandBufferForWrite(contextVk, &commandBuffer));
|
||||
ANGLE_TRY(mImage.recordCommands(contextVk, &commandBuffer));
|
||||
|
||||
if (mImage.valid())
|
||||
{
|
||||
|
@ -761,7 +754,7 @@ angle::Result TextureVk::copyImageDataToBuffer(ContextVk *contextVk,
|
|||
size_t sourceCopyAllocationSize = sourceArea.width * sourceArea.height * imageFormat.pixelBytes;
|
||||
|
||||
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.
|
||||
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();
|
||||
}
|
||||
|
||||
angle::Result TextureVk::generateMipmapWithBlit(ContextVk *contextVk)
|
||||
{
|
||||
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)
|
||||
angle::Result TextureVk::generateMipmapsWithCPU(const gl::Context *context)
|
||||
{
|
||||
ContextVk *contextVk = vk::GetImpl(context);
|
||||
|
||||
|
@ -949,11 +856,12 @@ gl::Error TextureVk::generateMipmap(const gl::Context *context)
|
|||
// only.
|
||||
if (IsMaskFlagSet(kBlitFeatureFlags, imageProperties.linearTilingFeatures))
|
||||
{
|
||||
ANGLE_TRY(generateMipmapWithBlit(contextVk));
|
||||
ANGLE_TRY(ensureImageInitialized(contextVk));
|
||||
ANGLE_TRY(mImage.generateMipmapsWithBlit(contextVk, mState.getMipmapMaxLevel()));
|
||||
}
|
||||
else
|
||||
{
|
||||
ANGLE_TRY(generateMipmapWithCPU(context));
|
||||
ANGLE_TRY(generateMipmapsWithCPU(context));
|
||||
}
|
||||
|
||||
// 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();
|
||||
vk::CommandBuffer *commandBuffer = nullptr;
|
||||
ANGLE_TRY(getCommandBufferForWrite(contextVk, &commandBuffer));
|
||||
ANGLE_TRY(mImage.recordCommands(contextVk, &commandBuffer));
|
||||
|
||||
const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
|
||||
const gl::Extents &baseLevelExtents = baseLevelDesc.size;
|
||||
|
|
|
@ -221,9 +221,7 @@ class TextureVk : public TextureImpl
|
|||
const gl::Rectangle &sourceArea,
|
||||
uint8_t **outDataPtr);
|
||||
|
||||
angle::Result generateMipmapWithBlit(ContextVk *contextVk);
|
||||
|
||||
angle::Result generateMipmapWithCPU(const gl::Context *context);
|
||||
angle::Result generateMipmapsWithCPU(const gl::Context *context);
|
||||
|
||||
angle::Result generateMipmapLevelsWithCPU(ContextVk *contextVk,
|
||||
const angle::Format &sourceFormat,
|
||||
|
@ -259,8 +257,6 @@ class TextureVk : public TextureImpl
|
|||
const uint32_t levelCount,
|
||||
vk::CommandBuffer *commandBuffer);
|
||||
void releaseImage(const gl::Context *context, RendererVk *renderer);
|
||||
angle::Result getCommandBufferForWrite(ContextVk *contextVk,
|
||||
vk::CommandBuffer **commandBufferOut);
|
||||
uint32_t getLevelCount() const;
|
||||
angle::Result initCubeMapRenderTargets(ContextVk *contextVk);
|
||||
|
||||
|
|
|
@ -941,6 +941,87 @@ void ImageHelper::Copy(ImageHelper *srcImage,
|
|||
dstImage->getImage(), dstImage->getCurrentLayout(), 1, ®ion);
|
||||
}
|
||||
|
||||
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::FramebufferHelper() : CommandGraphResource(CommandGraphResourceType::Framebuffer)
|
||||
{
|
||||
|
|
|
@ -249,7 +249,6 @@ class ImageHelper final : public CommandGraphResource
|
|||
GLint getSamples() const;
|
||||
|
||||
VkImageLayout getCurrentLayout() const { return mCurrentLayout; }
|
||||
void updateLayout(VkImageLayout layout) { mCurrentLayout = layout; }
|
||||
|
||||
void changeLayoutWithStages(VkImageAspectFlags aspectMask,
|
||||
VkImageLayout newLayout,
|
||||
|
@ -282,6 +281,8 @@ class ImageHelper final : public CommandGraphResource
|
|||
VkImageAspectFlags aspectMask,
|
||||
CommandBuffer *commandBuffer);
|
||||
|
||||
angle::Result generateMipmapsWithBlit(ContextVk *contextVk, GLuint maxLevel);
|
||||
|
||||
private:
|
||||
// Vulkan objects.
|
||||
Image mImage;
|
||||
|
|
Загрузка…
Ссылка в новой задаче