зеркало из 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();
|
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, ®ion);
|
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 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;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче