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

Commit 4f3b207

Browse files
ShabbyXCommit Bot
authored and
Commit Bot
committed
Vulkan: Shader path for texture-to-texture copy
This change implements glCopy[Sub]TextureCHROMIUM in GPU. As with the previous change implementing glCopyTex[Sub]Image2D, it currently only selects the shader path if the texture is already defined. Bug: angleproject:2958 Change-Id: Ia1b5625f92e6c9f91807c9b601e5c34d2d5e5c30 Reviewed-on: https://chromium-review.googlesource.com/c/1392394 Commit-Queue: Shahbaz Youssefi <[email protected]> Reviewed-by: Yuly Novikov <[email protected]>
1 parent 29b4941 commit 4f3b207

32 files changed

+3642
-848
lines changed

include/platform/FeaturesVk.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ struct FeaturesVk
5757
// Whether the VkDevice supports the VK_KHR_incremental_present extension, on which the
5858
// EGL_KHR_swap_buffers_with_damage extension can be layered.
5959
bool supportsIncrementalPresent = false;
60+
61+
// Whether texture copies on cube map targets should be done on GPU. This is a workaround for
62+
// Intel drivers on windows that have an issue with creating single-layer views on cube map
63+
// textures.
64+
bool forceCpuPathForCubeMapCopy = false;
6065
};
6166

6267
} // namespace angle

scripts/run_code_generation_hashes.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@
102102
"Vulkan internal shader programs:src/libANGLE/renderer/vulkan/shaders/src/ImageClear.frag":
103103
"98d490413d20118e92dd2b160c1dfc6e",
104104
"Vulkan internal shader programs:src/libANGLE/renderer/vulkan/shaders/src/ImageCopy.frag":
105-
"096ccb0e3c25067ddd0347556a12d7d6",
105+
"9b9fd690321f53163221f1ebba9f006d",
106106
"Vulkan mandatory format support table:src/libANGLE/renderer/angle_format.py":
107107
"b18ca0fe4835114a4a2f54977b19e798",
108108
"Vulkan mandatory format support table:src/libANGLE/renderer/vulkan/gen_vk_mandatory_format_support_table.py":

src/libANGLE/renderer/vulkan/RendererVk.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,9 @@ void RendererVk::initFeatures(const std::vector<VkExtensionProperties> &deviceEx
825825
#ifdef ANGLE_PLATFORM_WINDOWS
826826
// http://anglebug.com/2838
827827
mFeatures.extraCopyBufferRegion = IsIntel(mPhysicalDeviceProperties.vendorID);
828+
829+
// http://anglebug.com/3055
830+
mFeatures.forceCpuPathForCubeMapCopy = IsIntel(mPhysicalDeviceProperties.vendorID);
828831
#endif
829832

830833
angle::PlatformMethods *platform = ANGLEPlatformCurrent();

src/libANGLE/renderer/vulkan/TextureVk.cpp

Lines changed: 94 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@ constexpr size_t kStagingBufferSize = 1024 * 16;
2727

2828
constexpr VkFormatFeatureFlags kBlitFeatureFlags =
2929
VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT;
30+
31+
bool CanCopyWithDraw(RendererVk *renderer,
32+
const vk::Format &srcFormat,
33+
const vk::Format &destFormat)
34+
{
35+
return renderer->hasTextureFormatFeatureBits(srcFormat.vkTextureFormat,
36+
VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) &&
37+
renderer->hasTextureFormatFeatureBits(destFormat.vkTextureFormat,
38+
VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT);
39+
}
3040
} // anonymous namespace
3141

3242
// StagingStorage implementation.
@@ -575,21 +585,25 @@ angle::Result TextureVk::copySubImageImpl(const gl::Context *context,
575585
const vk::Format &destFormat = renderer->getFormat(internalFormat.sizedInternalFormat);
576586

577587
// TODO(syoussefi): Support draw path for when !mImage.valid(). http://anglebug.com/2958
578-
bool canDraw = mImage.valid() &&
579-
renderer->hasTextureFormatFeatureBits(srcFormat.vkTextureFormat,
580-
VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) &&
581-
renderer->hasTextureFormatFeatureBits(destFormat.vkTextureFormat,
582-
VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT);
588+
bool canDraw = mImage.valid() && CanCopyWithDraw(renderer, srcFormat, destFormat);
589+
bool forceCpuPath =
590+
mImage.getLayerCount() > 1 && renderer->getFeatures().forceCpuPathForCubeMapCopy;
583591

584592
// If it's possible to perform the copy with a draw call, do that.
585-
if (canDraw)
593+
if (canDraw && !forceCpuPath)
586594
{
587-
ANGLE_TRY(ensureImageInitialized(contextVk));
595+
RenderTargetVk *colorReadRT = framebufferVk->getColorReadRenderTarget();
596+
bool isViewportFlipY = contextVk->isViewportFlipEnabledForDrawFBO();
597+
598+
// Layer count can only be 1 as the source is a framebuffer.
599+
ASSERT(index.getLayerCount() == 1);
588600

589-
return copySubImageImplWithDraw(contextVk, index, modifiedDestOffset,
590-
gl::Offset(clippedSourceArea.x, clippedSourceArea.y, 0),
591-
gl::Extents(destArea.width, destArea.height, 1),
592-
framebufferVk);
601+
ANGLE_TRY(copySubImageImplWithDraw(
602+
contextVk, index, modifiedDestOffset, 0, clippedSourceArea, isViewportFlipY, false,
603+
false, false, &colorReadRT->getImage(), colorReadRT->getReadImageView()));
604+
605+
framebufferVk->getFramebuffer()->addReadDependency(&mImage);
606+
return angle::Result::Continue;
593607
}
594608

595609
// Do a CPU readback that does the conversion, and then stage the change to the pixel buffer.
@@ -603,51 +617,6 @@ angle::Result TextureVk::copySubImageImpl(const gl::Context *context,
603617
return angle::Result::Continue;
604618
}
605619

606-
angle::Result TextureVk::copySubImageImplWithDraw(ContextVk *contextVk,
607-
const gl::ImageIndex &index,
608-
const gl::Offset &destOffset,
609-
const gl::Offset &srcOffset,
610-
const gl::Extents &extents,
611-
FramebufferVk *source)
612-
{
613-
UtilsVk::CopyImageParameters params;
614-
params.srcOffset[0] = srcOffset.x;
615-
params.srcOffset[1] = srcOffset.y;
616-
params.srcExtents[0] = extents.width;
617-
params.srcExtents[1] = extents.height;
618-
params.destOffset[0] = destOffset.x;
619-
params.destOffset[1] = destOffset.y;
620-
params.srcMip = 0;
621-
params.srcHeight = source->getReadImageExtents().height;
622-
params.flipY = contextVk->isViewportFlipEnabledForDrawFBO();
623-
624-
uint32_t level = index.getLevelIndex();
625-
uint32_t baseLayer = index.hasLayer() ? index.getLayerIndex() : 0;
626-
uint32_t layerCount = index.getLayerCount();
627-
628-
// TODO(syoussefi): currently this is only called from copy[Sub]Image,
629-
// where layer count can only be 1, and source's level and layer are both 0.
630-
// Once this code is expanded to cover copy[Sub]Texture, it should be
631-
// adapted to get single-layer/level image views of the source as well.
632-
// http://anglebug.com/2958
633-
ASSERT(layerCount == 1);
634-
vk::ImageHelper *srcImage = &source->getColorReadRenderTarget()->getImage();
635-
vk::ImageView *srcView = source->getColorReadRenderTarget()->getReadImageView();
636-
637-
for (uint32_t i = 0; i < layerCount; ++i)
638-
{
639-
vk::ImageView *destView;
640-
ANGLE_TRY(getLayerLevelDrawImageView(contextVk, baseLayer + i, level, &destView));
641-
642-
ANGLE_TRY(contextVk->getRenderer()->getUtils().copyImage(contextVk, &mImage, destView,
643-
srcImage, srcView, params));
644-
}
645-
646-
source->getFramebuffer()->addReadDependency(&mImage);
647-
648-
return angle::Result::Continue;
649-
}
650-
651620
angle::Result TextureVk::copySubTextureImpl(ContextVk *contextVk,
652621
const gl::ImageIndex &index,
653622
const gl::Offset &destOffset,
@@ -661,6 +630,28 @@ angle::Result TextureVk::copySubTextureImpl(ContextVk *contextVk,
661630
{
662631
RendererVk *renderer = contextVk->getRenderer();
663632

633+
ANGLE_TRY(source->ensureImageInitialized(contextVk));
634+
635+
const vk::Format &sourceVkFormat = source->getImage().getFormat();
636+
const vk::Format &destVkFormat = renderer->getFormat(destFormat.sizedInternalFormat);
637+
638+
// TODO(syoussefi): Support draw path for when !mImage.valid(). http://anglebug.com/2958
639+
bool canDraw = mImage.valid() && CanCopyWithDraw(renderer, sourceVkFormat, destVkFormat);
640+
bool forceCpuPath =
641+
mImage.getLayerCount() > 1 && renderer->getFeatures().forceCpuPathForCubeMapCopy;
642+
643+
// If it's possible to perform the copy with a draw call, do that.
644+
if (canDraw && !forceCpuPath)
645+
{
646+
ANGLE_TRY(copySubImageImplWithDraw(contextVk, index, destOffset, sourceLevel, sourceArea,
647+
false, unpackFlipY, unpackPremultiplyAlpha,
648+
unpackUnmultiplyAlpha, &source->getImage(),
649+
&source->getReadImageView()));
650+
651+
source->getImage().addReadDependency(&mImage);
652+
return angle::Result::Continue;
653+
}
654+
664655
if (sourceLevel != 0)
665656
{
666657
WARN() << "glCopyTextureCHROMIUM with sourceLevel != 0 not implemented.";
@@ -671,9 +662,6 @@ angle::Result TextureVk::copySubTextureImpl(ContextVk *contextVk,
671662
uint8_t *sourceData = nullptr;
672663
ANGLE_TRY(source->copyImageDataToBuffer(contextVk, sourceLevel, 1, sourceArea, &sourceData));
673664

674-
const vk::Format &sourceVkFormat = source->getImage().getFormat();
675-
const vk::Format &destVkFormat = renderer->getFormat(destFormat.sizedInternalFormat);
676-
677665
const angle::Format &sourceTextureFormat = sourceVkFormat.textureFormat();
678666
const angle::Format &destTextureFormat = destVkFormat.textureFormat();
679667
size_t destinationAllocationSize =
@@ -716,6 +704,53 @@ angle::Result TextureVk::copySubTextureImpl(ContextVk *contextVk,
716704
return angle::Result::Continue;
717705
}
718706

707+
angle::Result TextureVk::copySubImageImplWithDraw(ContextVk *contextVk,
708+
const gl::ImageIndex &index,
709+
const gl::Offset &destOffset,
710+
size_t sourceLevel,
711+
const gl::Rectangle &sourceArea,
712+
bool isSrcFlipY,
713+
bool unpackFlipY,
714+
bool unpackPremultiplyAlpha,
715+
bool unpackUnmultiplyAlpha,
716+
vk::ImageHelper *srcImage,
717+
const vk::ImageView *srcView)
718+
{
719+
ANGLE_TRY(ensureImageInitialized(contextVk));
720+
721+
UtilsVk &utilsVk = contextVk->getRenderer()->getUtils();
722+
723+
UtilsVk::CopyImageParameters params;
724+
params.srcOffset[0] = sourceArea.x;
725+
params.srcOffset[1] = sourceArea.y;
726+
params.srcExtents[0] = sourceArea.width;
727+
params.srcExtents[1] = sourceArea.height;
728+
params.destOffset[0] = destOffset.x;
729+
params.destOffset[1] = destOffset.y;
730+
params.srcMip = sourceLevel;
731+
params.srcHeight = srcImage->getExtents().height;
732+
params.srcPremultiplyAlpha = unpackPremultiplyAlpha && !unpackUnmultiplyAlpha;
733+
params.srcUnmultiplyAlpha = unpackUnmultiplyAlpha && !unpackPremultiplyAlpha;
734+
params.srcFlipY = isSrcFlipY;
735+
params.destFlipY = unpackFlipY;
736+
737+
uint32_t level = index.getLevelIndex();
738+
uint32_t baseLayer = index.hasLayer() ? index.getLayerIndex() : 0;
739+
uint32_t layerCount = index.getLayerCount();
740+
741+
for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex)
742+
{
743+
params.srcLayer = layerIndex;
744+
745+
vk::ImageView *destView;
746+
ANGLE_TRY(getLayerLevelDrawImageView(contextVk, baseLayer + layerIndex, level, &destView));
747+
748+
ANGLE_TRY(utilsVk.copyImage(contextVk, &mImage, destView, srcImage, srcView, params));
749+
}
750+
751+
return angle::Result::Continue;
752+
}
753+
719754
angle::Result TextureVk::setStorage(const gl::Context *context,
720755
gl::TextureType type,
721756
size_t levels,

src/libANGLE/renderer/vulkan/TextureVk.h

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -244,13 +244,6 @@ class TextureVk : public TextureImpl
244244
const gl::InternalFormat &internalFormat,
245245
gl::Framebuffer *source);
246246

247-
angle::Result copySubImageImplWithDraw(ContextVk *contextVk,
248-
const gl::ImageIndex &index,
249-
const gl::Offset &destOffset,
250-
const gl::Offset &srcOffset,
251-
const gl::Extents &extents,
252-
FramebufferVk *source);
253-
254247
angle::Result copySubTextureImpl(ContextVk *contextVk,
255248
const gl::ImageIndex &index,
256249
const gl::Offset &destOffset,
@@ -262,6 +255,18 @@ class TextureVk : public TextureImpl
262255
bool unpackUnmultiplyAlpha,
263256
TextureVk *source);
264257

258+
angle::Result copySubImageImplWithDraw(ContextVk *contextVk,
259+
const gl::ImageIndex &index,
260+
const gl::Offset &destOffset,
261+
size_t sourceLevel,
262+
const gl::Rectangle &sourceArea,
263+
bool isSrcFlipY,
264+
bool unpackFlipY,
265+
bool unpackPremultiplyAlpha,
266+
bool unpackUnmultiplyAlpha,
267+
vk::ImageHelper *srcImage,
268+
const vk::ImageView *srcView);
269+
265270
angle::Result initImage(ContextVk *contextVk,
266271
const vk::Format &format,
267272
const gl::Extents &extents,

src/libANGLE/renderer/vulkan/UtilsVk.cpp

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,23 @@ uint32_t GetImageCopyFlags(const vk::Format &srcFormat, const vk::Format &destFo
133133

134134
return flags;
135135
}
136+
137+
uint32_t GetFormatDefaultChannelMask(const vk::Format &format)
138+
{
139+
uint32_t mask = 0;
140+
141+
const angle::Format &angleFormat = format.angleFormat();
142+
const angle::Format &textureFormat = format.textureFormat();
143+
144+
// Red can never be introduced due to format emulation (except for luma which is handled
145+
// especially)
146+
ASSERT(((angleFormat.redBits > 0) == (textureFormat.redBits > 0)) || angleFormat.isLUMA());
147+
mask |= angleFormat.greenBits == 0 && textureFormat.greenBits > 0 ? 2 : 0;
148+
mask |= angleFormat.blueBits == 0 && textureFormat.blueBits > 0 ? 4 : 0;
149+
mask |= angleFormat.alphaBits == 0 && textureFormat.alphaBits > 0 ? 8 : 0;
150+
151+
return mask;
152+
}
136153
} // namespace
137154

138155
UtilsVk::UtilsVk() = default;
@@ -547,7 +564,7 @@ angle::Result UtilsVk::convertVertexBuffer(vk::Context *context,
547564

548565
angle::Result UtilsVk::startRenderPass(vk::Context *context,
549566
vk::ImageHelper *image,
550-
vk::ImageView *imageView,
567+
const vk::ImageView *imageView,
551568
const vk::RenderPassDesc &renderPassDesc,
552569
const gl::Rectangle &renderArea,
553570
vk::CommandBuffer **commandBufferOut)
@@ -633,9 +650,9 @@ angle::Result UtilsVk::clearImage(ContextVk *contextVk,
633650

634651
angle::Result UtilsVk::copyImage(vk::Context *context,
635652
vk::ImageHelper *dest,
636-
vk::ImageView *destView,
653+
const vk::ImageView *destView,
637654
vk::ImageHelper *src,
638-
vk::ImageView *srcView,
655+
const vk::ImageView *srcView,
639656
const CopyImageParameters &params)
640657
{
641658
RendererVk *renderer = context->getRenderer();
@@ -646,24 +663,36 @@ angle::Result UtilsVk::copyImage(vk::Context *context,
646663
const vk::Format &destFormat = dest->getFormat();
647664

648665
ImageCopyShaderParams shaderParams;
649-
shaderParams.flipY = params.flipY;
666+
shaderParams.flipY = params.srcFlipY || params.destFlipY;
667+
shaderParams.premultiplyAlpha = params.srcPremultiplyAlpha;
668+
shaderParams.unmultiplyAlpha = params.srcUnmultiplyAlpha;
650669
shaderParams.destHasLuminance = destFormat.angleFormat().luminanceBits > 0;
651670
shaderParams.destIsAlpha =
652671
destFormat.angleFormat().isLUMA() && destFormat.angleFormat().alphaBits > 0;
653-
shaderParams.srcMip = params.srcMip;
654-
shaderParams.srcOffset[0] = params.srcOffset[0];
655-
shaderParams.srcOffset[1] = params.srcOffset[1];
656-
shaderParams.destOffset[0] = params.destOffset[0];
657-
shaderParams.destOffset[1] = params.destOffset[1];
658-
659-
if (params.flipY)
672+
shaderParams.destDefaultChannelsMask = GetFormatDefaultChannelMask(destFormat);
673+
shaderParams.srcMip = params.srcMip;
674+
shaderParams.srcLayer = params.srcLayer;
675+
shaderParams.srcOffset[0] = params.srcOffset[0];
676+
shaderParams.srcOffset[1] = params.srcOffset[1];
677+
shaderParams.destOffset[0] = params.destOffset[0];
678+
shaderParams.destOffset[1] = params.destOffset[1];
679+
680+
ASSERT(!(params.srcFlipY && params.destFlipY));
681+
if (params.srcFlipY)
660682
{
661683
// If viewport is flipped, the shader expects srcOffset[1] to have the
662684
// last row's index instead of the first's.
663-
shaderParams.srcOffset[1] = params.srcHeight - shaderParams.srcOffset[1] - 1;
685+
shaderParams.srcOffset[1] = params.srcHeight - params.srcOffset[1] - 1;
686+
}
687+
else if (params.destFlipY)
688+
{
689+
// If image is flipped during copy, the shader uses the same code path as above,
690+
// with srcOffset being set to the last row's index instead of the first's.
691+
shaderParams.srcOffset[1] = params.srcOffset[1] + params.srcExtents[1] - 1;
664692
}
665693

666694
uint32_t flags = GetImageCopyFlags(srcFormat, destFormat);
695+
flags |= src->getLayerCount() > 1 ? ImageCopy_frag::kSrcIsArray : 0;
667696

668697
VkDescriptorSet descriptorSet;
669698
vk::SharedDescriptorPoolBinding descriptorPoolBinding;

0 commit comments

Comments
 (0)