• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // TextureVk.cpp:
7 //    Implements the class methods for TextureVk.
8 //
9 
10 #include "libANGLE/renderer/vulkan/TextureVk.h"
11 #include <vulkan/vulkan.h>
12 
13 #include "common/debug.h"
14 #include "image_util/generatemip.inc"
15 #include "libANGLE/Config.h"
16 #include "libANGLE/Context.h"
17 #include "libANGLE/Image.h"
18 #include "libANGLE/MemoryObject.h"
19 #include "libANGLE/Surface.h"
20 #include "libANGLE/renderer/vulkan/ContextVk.h"
21 #include "libANGLE/renderer/vulkan/FramebufferVk.h"
22 #include "libANGLE/renderer/vulkan/ImageVk.h"
23 #include "libANGLE/renderer/vulkan/MemoryObjectVk.h"
24 #include "libANGLE/renderer/vulkan/RenderbufferVk.h"
25 #include "libANGLE/renderer/vulkan/RendererVk.h"
26 #include "libANGLE/renderer/vulkan/SurfaceVk.h"
27 #include "libANGLE/renderer/vulkan/UtilsVk.h"
28 #include "libANGLE/renderer/vulkan/vk_format_utils.h"
29 #include "libANGLE/renderer/vulkan/vk_helpers.h"
30 #include "libANGLE/renderer/vulkan/vk_utils.h"
31 
32 namespace rx
33 {
34 namespace
35 {
36 constexpr VkImageUsageFlags kTransferImageFlags =
37     VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
38 
39 constexpr VkImageUsageFlags kColorAttachmentImageFlags =
40     VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
41 
42 constexpr VkImageUsageFlags kDrawStagingImageFlags =
43     kTransferImageFlags | kColorAttachmentImageFlags;
44 
45 constexpr VkFormatFeatureFlags kBlitFeatureFlags =
46     VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT;
47 
48 constexpr VkImageAspectFlags kDepthStencilAspects =
49     VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_DEPTH_BIT;
50 
51 constexpr angle::SubjectIndex kTextureImageSubjectIndex = 0;
52 
53 // Test whether a texture level is within the range of levels for which the current image is
54 // allocated.  This is used to ensure out-of-range updates are staged in the image, and not
55 // attempted to be directly applied.
IsTextureLevelInAllocatedImage(const vk::ImageHelper & image,gl::LevelIndex textureLevelIndexGL)56 bool IsTextureLevelInAllocatedImage(const vk::ImageHelper &image,
57                                     gl::LevelIndex textureLevelIndexGL)
58 {
59     gl::LevelIndex imageFirstAllocateLevel = image.getFirstAllocatedLevel();
60     if (textureLevelIndexGL < imageFirstAllocateLevel)
61     {
62         return false;
63     }
64 
65     vk::LevelIndex imageLevelIndexVk = image.toVkLevel(textureLevelIndexGL);
66     return imageLevelIndexVk < vk::LevelIndex(image.getLevelCount());
67 }
68 
69 // Test whether a redefined texture level is compatible with the currently allocated image.  Returns
70 // true if the given size and format match the corresponding mip in the allocated image (taking
71 // base level into account).  This could return false when:
72 //
73 // - Defining a texture level that is outside the range of the image levels.  In this case, changes
74 //   to this level should remain staged until the texture is redefined to include this level.
75 // - Redefining a texture level that is within the range of the image levels, but has a different
76 //   size or format.  In this case too, changes to this level should remain staged as the texture
77 //   is no longer complete as is.
IsTextureLevelDefinitionCompatibleWithImage(const vk::ImageHelper & image,gl::LevelIndex textureLevelIndexGL,const gl::Extents & size,angle::FormatID intendedFormatID,angle::FormatID actualFormatID)78 bool IsTextureLevelDefinitionCompatibleWithImage(const vk::ImageHelper &image,
79                                                  gl::LevelIndex textureLevelIndexGL,
80                                                  const gl::Extents &size,
81                                                  angle::FormatID intendedFormatID,
82                                                  angle::FormatID actualFormatID)
83 {
84     ASSERT(IsTextureLevelInAllocatedImage(image, textureLevelIndexGL));
85 
86     vk::LevelIndex imageLevelIndexVk = image.toVkLevel(textureLevelIndexGL);
87     return size == image.getLevelExtents(imageLevelIndexVk) &&
88            intendedFormatID == image.getIntendedFormatID() &&
89            actualFormatID == image.getActualFormatID();
90 }
91 
CanCopyWithTransferForTexImage(RendererVk * renderer,angle::FormatID srcIntendedFormatID,angle::FormatID srcActualFormatID,VkImageTiling srcTilingMode,angle::FormatID dstIntendedFormatID,angle::FormatID dstActualFormatID,VkImageTiling dstTilingMode)92 bool CanCopyWithTransferForTexImage(RendererVk *renderer,
93                                     angle::FormatID srcIntendedFormatID,
94                                     angle::FormatID srcActualFormatID,
95                                     VkImageTiling srcTilingMode,
96                                     angle::FormatID dstIntendedFormatID,
97                                     angle::FormatID dstActualFormatID,
98                                     VkImageTiling dstTilingMode)
99 {
100     // For glTex[Sub]Image, only accept same-format transfers.
101     // There are cases that two images' actual format is the same, but intended formats are
102     // different due to one is using the fallback format (for example, RGB fallback to RGBA). In
103     // these situations CanCopyWithTransfer will say yes. But if we use transfer to do copy, the
104     // alpha channel will be also be copied with source data which is wrong.
105     bool isFormatCompatible =
106         srcIntendedFormatID == dstIntendedFormatID && srcActualFormatID == dstActualFormatID;
107 
108     return isFormatCompatible && vk::CanCopyWithTransfer(renderer, srcActualFormatID, srcTilingMode,
109                                                          dstActualFormatID, dstTilingMode);
110 }
111 
CanCopyWithTransferForCopyTexture(RendererVk * renderer,const vk::ImageHelper & srcImage,VkImageTiling srcTilingMode,angle::FormatID destIntendedFormatID,angle::FormatID destActualFormatID,VkImageTiling destTilingMode)112 bool CanCopyWithTransferForCopyTexture(RendererVk *renderer,
113                                        const vk::ImageHelper &srcImage,
114                                        VkImageTiling srcTilingMode,
115                                        angle::FormatID destIntendedFormatID,
116                                        angle::FormatID destActualFormatID,
117                                        VkImageTiling destTilingMode)
118 {
119     if (!vk::CanCopyWithTransfer(renderer, srcImage.getActualFormatID(), srcTilingMode,
120                                  destActualFormatID, destTilingMode))
121     {
122         return false;
123     }
124 
125     // If the formats are identical, we can always transfer between them.
126     if (srcImage.getIntendedFormatID() == destIntendedFormatID &&
127         srcImage.getActualFormatID() == destActualFormatID)
128     {
129         return true;
130     }
131 
132     // If either format is emulated, cannot transfer.
133     if (srcImage.hasEmulatedImageFormat() ||
134         vk::HasEmulatedImageFormat(destIntendedFormatID, destActualFormatID))
135     {
136         return false;
137     }
138 
139     // Otherwise, allow transfer between compatible formats.  This is derived from the specification
140     // of CHROMIUM_copy_texture.
141     const angle::Format &srcAngleFormat  = srcImage.getActualFormat();
142     const angle::Format &destAngleFormat = angle::Format::Get(destActualFormatID);
143 
144     const bool srcIsBGRA   = srcAngleFormat.isBGRA();
145     const bool srcHasR8    = srcAngleFormat.redBits == 8;
146     const bool srcHasG8    = srcAngleFormat.greenBits == 8;
147     const bool srcHasB8    = srcAngleFormat.blueBits == 8;
148     const bool srcHasA8    = srcAngleFormat.alphaBits == 8;
149     const bool srcIsSigned = srcAngleFormat.isSnorm() || srcAngleFormat.isSint();
150 
151     const bool destIsBGRA   = destAngleFormat.isBGRA();
152     const bool destHasR8    = destAngleFormat.redBits == 8;
153     const bool destHasG8    = destAngleFormat.greenBits == 8;
154     const bool destHasB8    = destAngleFormat.blueBits == 8;
155     const bool destHasA8    = destAngleFormat.alphaBits == 8;
156     const bool destIsSigned = destAngleFormat.isSnorm() || destAngleFormat.isSint();
157 
158     // Copy is allowed as long as they have the same number, ordering and sign of (8-bit) channels.
159     // CHROMIUM_copy_texture expects verbatim copy between these format, so this copy is done
160     // regardless of sRGB, normalized, etc.
161     return srcIsBGRA == destIsBGRA && srcHasR8 == destHasR8 && srcHasG8 == destHasG8 &&
162            srcHasB8 == destHasB8 && srcHasA8 == destHasA8 && srcIsSigned == destIsSigned;
163 }
164 
CanCopyWithDraw(RendererVk * renderer,const angle::FormatID srcFormatID,VkImageTiling srcTilingMode,const angle::FormatID dstFormatID,VkImageTiling destTilingMode)165 bool CanCopyWithDraw(RendererVk *renderer,
166                      const angle::FormatID srcFormatID,
167                      VkImageTiling srcTilingMode,
168                      const angle::FormatID dstFormatID,
169                      VkImageTiling destTilingMode)
170 {
171     // Checks that the formats in copy by drawing have the appropriate feature bits
172     bool srcFormatHasNecessaryFeature = vk::FormatHasNecessaryFeature(
173         renderer, srcFormatID, srcTilingMode, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
174     bool dstFormatHasNecessaryFeature = vk::FormatHasNecessaryFeature(
175         renderer, dstFormatID, destTilingMode, VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT);
176 
177     return srcFormatHasNecessaryFeature && dstFormatHasNecessaryFeature;
178 }
179 
CanGenerateMipmapWithCompute(RendererVk * renderer,VkImageType imageType,angle::FormatID formatID,GLint samples,bool canBeRespecified)180 bool CanGenerateMipmapWithCompute(RendererVk *renderer,
181                                   VkImageType imageType,
182                                   angle::FormatID formatID,
183                                   GLint samples,
184                                   bool canBeRespecified)
185 {
186     // Feature needs to be enabled
187     if (!renderer->getFeatures().allowGenerateMipmapWithCompute.enabled)
188     {
189         return false;
190     }
191 
192     // We need to be able to respecify the backing image
193     if (!canBeRespecified)
194     {
195         return false;
196     }
197 
198     const angle::Format &angleFormat = angle::Format::Get(formatID);
199     // Format must have STORAGE support.
200     const bool hasStorageSupport =
201         renderer->hasImageFormatFeatureBits(formatID, VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT);
202 
203     // No support for sRGB formats yet.
204     const bool isSRGB = angleFormat.isSRGB;
205 
206     // No support for integer formats yet.
207     const bool isInt = angleFormat.isInt();
208 
209     // Only 2D images are supported.
210     const bool is2D = imageType == VK_IMAGE_TYPE_2D;
211 
212     // No support for multisampled images yet.
213     const bool isMultisampled = samples > 1;
214 
215     // Only color formats are supported.
216     const bool isColorFormat = !angleFormat.hasDepthOrStencilBits();
217 
218     return hasStorageSupport && !isSRGB && !isInt && is2D && !isMultisampled && isColorFormat;
219 }
220 
GetRenderTargetLayerCountAndIndex(vk::ImageHelper * image,const gl::ImageIndex & index,GLuint * layerIndex,GLuint * layerCount,GLuint * imageLayerCount)221 void GetRenderTargetLayerCountAndIndex(vk::ImageHelper *image,
222                                        const gl::ImageIndex &index,
223                                        GLuint *layerIndex,
224                                        GLuint *layerCount,
225                                        GLuint *imageLayerCount)
226 {
227     *layerIndex = index.hasLayer() ? index.getLayerIndex() : 0;
228     *layerCount = index.getLayerCount();
229 
230     switch (index.getType())
231     {
232         case gl::TextureType::_2D:
233         case gl::TextureType::_2DMultisample:
234             ASSERT(*layerIndex == 0 &&
235                    (*layerCount == 1 ||
236                     *layerCount == static_cast<GLuint>(gl::ImageIndex::kEntireLevel)));
237             *imageLayerCount = 1;
238             break;
239 
240         case gl::TextureType::CubeMap:
241             ASSERT(!index.hasLayer() ||
242                    *layerIndex == static_cast<GLuint>(index.cubeMapFaceIndex()));
243             *imageLayerCount = gl::kCubeFaceCount;
244             break;
245 
246         case gl::TextureType::_3D:
247         {
248             gl::LevelIndex levelGL(index.getLevelIndex());
249             *imageLayerCount = image->getLevelExtents(image->toVkLevel(levelGL)).depth;
250             break;
251         }
252 
253         case gl::TextureType::_2DArray:
254         case gl::TextureType::_2DMultisampleArray:
255         case gl::TextureType::CubeMapArray:
256             *imageLayerCount = image->getLayerCount();
257             break;
258 
259         default:
260             UNREACHABLE();
261     }
262 
263     if (*layerCount == static_cast<GLuint>(gl::ImageIndex::kEntireLevel))
264     {
265         ASSERT(*layerIndex == 0);
266         *layerCount = *imageLayerCount;
267     }
268 }
269 
Set3DBaseArrayLayerAndLayerCount(VkImageSubresourceLayers * Subresource)270 void Set3DBaseArrayLayerAndLayerCount(VkImageSubresourceLayers *Subresource)
271 {
272     // If the srcImage/dstImage parameters are of VkImageType VK_IMAGE_TYPE_3D, the baseArrayLayer
273     // and layerCount members of the corresponding subresource must be 0 and 1, respectively.
274     Subresource->baseArrayLayer = 0;
275     Subresource->layerCount     = 1;
276 }
277 
AdjustStorageViewFormatPerWorkarounds(RendererVk * renderer,const vk::Format * intended,vk::ImageAccess access)278 const vk::Format *AdjustStorageViewFormatPerWorkarounds(RendererVk *renderer,
279                                                         const vk::Format *intended,
280                                                         vk::ImageAccess access)
281 {
282     // r32f images are emulated with r32ui.
283     if (renderer->getFeatures().emulateR32fImageAtomicExchange.enabled &&
284         intended->getActualImageFormatID(access) == angle::FormatID::R32_FLOAT)
285     {
286         return &renderer->getFormat(angle::FormatID::R32_UINT);
287     }
288 
289     return intended;
290 }
291 
GetRGBAEmulationDstFormat(angle::FormatID srcFormatID)292 angle::FormatID GetRGBAEmulationDstFormat(angle::FormatID srcFormatID)
293 {
294     switch (srcFormatID)
295     {
296         case angle::FormatID::R32G32B32_UINT:
297             return angle::FormatID::R32G32B32A32_UINT;
298         case angle::FormatID::R32G32B32_SINT:
299             return angle::FormatID::R32G32B32A32_SINT;
300         case angle::FormatID::R32G32B32_FLOAT:
301             return angle::FormatID::R32G32B32A32_FLOAT;
302         default:
303             return angle::FormatID::NONE;
304     }
305 }
306 
NeedsRGBAEmulation(RendererVk * renderer,angle::FormatID formatID)307 bool NeedsRGBAEmulation(RendererVk *renderer, angle::FormatID formatID)
308 {
309     if (renderer->hasBufferFormatFeatureBits(formatID, VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT))
310     {
311         return false;
312     }
313     // Vulkan driver support is required for all formats except the ones we emulate.
314     ASSERT(GetRGBAEmulationDstFormat(formatID) != angle::FormatID::NONE);
315     return true;
316 }
317 }  // anonymous namespace
318 
319 // TextureVk implementation.
TextureVk(const gl::TextureState & state,RendererVk * renderer)320 TextureVk::TextureVk(const gl::TextureState &state, RendererVk *renderer)
321     : TextureImpl(state),
322       mOwnsImage(false),
323       mRequiresMutableStorage(false),
324       mRequiredImageAccess(vk::ImageAccess::SampleOnly),
325       mImmutableSamplerDirty(false),
326       mEGLImageNativeType(gl::TextureType::InvalidEnum),
327       mEGLImageLayerOffset(0),
328       mEGLImageLevelOffset(0),
329       mImage(nullptr),
330       mImageUsageFlags(0),
331       mImageCreateFlags(0),
332       mImageObserverBinding(this, kTextureImageSubjectIndex),
333       mCurrentBaseLevel(state.getBaseLevel()),
334       mCurrentMaxLevel(state.getMaxLevel()),
335       mCachedImageViewSubresourceSerialSRGBDecode{},
336       mCachedImageViewSubresourceSerialSkipDecode{}
337 {}
338 
339 TextureVk::~TextureVk() = default;
340 
onDestroy(const gl::Context * context)341 void TextureVk::onDestroy(const gl::Context *context)
342 {
343     ContextVk *contextVk = vk::GetImpl(context);
344 
345     releaseAndDeleteImageAndViews(contextVk);
346     resetSampler();
347 }
348 
setImage(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels)349 angle::Result TextureVk::setImage(const gl::Context *context,
350                                   const gl::ImageIndex &index,
351                                   GLenum internalFormat,
352                                   const gl::Extents &size,
353                                   GLenum format,
354                                   GLenum type,
355                                   const gl::PixelUnpackState &unpack,
356                                   gl::Buffer *unpackBuffer,
357                                   const uint8_t *pixels)
358 {
359     const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat, type);
360 
361     return setImageImpl(context, index, formatInfo, size, type, unpack, unpackBuffer, pixels);
362 }
363 
setSubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels)364 angle::Result TextureVk::setSubImage(const gl::Context *context,
365                                      const gl::ImageIndex &index,
366                                      const gl::Box &area,
367                                      GLenum format,
368                                      GLenum type,
369                                      const gl::PixelUnpackState &unpack,
370                                      gl::Buffer *unpackBuffer,
371                                      const uint8_t *pixels)
372 {
373     const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format, type);
374     ContextVk *contextVk                 = vk::GetImpl(context);
375     const gl::ImageDesc &levelDesc       = mState.getImageDesc(index);
376     const vk::Format &vkFormat =
377         contextVk->getRenderer()->getFormat(levelDesc.format.info->sizedInternalFormat);
378 
379     return setSubImageImpl(context, index, area, formatInfo, type, unpack, unpackBuffer, pixels,
380                            vkFormat);
381 }
382 
setCompressedImage(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,const gl::PixelUnpackState & unpack,size_t imageSize,const uint8_t * pixels)383 angle::Result TextureVk::setCompressedImage(const gl::Context *context,
384                                             const gl::ImageIndex &index,
385                                             GLenum internalFormat,
386                                             const gl::Extents &size,
387                                             const gl::PixelUnpackState &unpack,
388                                             size_t imageSize,
389                                             const uint8_t *pixels)
390 {
391     const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat);
392 
393     const gl::State &glState = context->getState();
394     gl::Buffer *unpackBuffer = glState.getTargetBuffer(gl::BufferBinding::PixelUnpack);
395 
396     return setImageImpl(context, index, formatInfo, size, GL_UNSIGNED_BYTE, unpack, unpackBuffer,
397                         pixels);
398 }
399 
setCompressedSubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,const gl::PixelUnpackState & unpack,size_t imageSize,const uint8_t * pixels)400 angle::Result TextureVk::setCompressedSubImage(const gl::Context *context,
401                                                const gl::ImageIndex &index,
402                                                const gl::Box &area,
403                                                GLenum format,
404                                                const gl::PixelUnpackState &unpack,
405                                                size_t imageSize,
406                                                const uint8_t *pixels)
407 {
408 
409     const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format, GL_UNSIGNED_BYTE);
410     ContextVk *contextVk                 = vk::GetImpl(context);
411     const gl::ImageDesc &levelDesc       = mState.getImageDesc(index);
412     const vk::Format &vkFormat =
413         contextVk->getRenderer()->getFormat(levelDesc.format.info->sizedInternalFormat);
414     const gl::State &glState = contextVk->getState();
415     gl::Buffer *unpackBuffer = glState.getTargetBuffer(gl::BufferBinding::PixelUnpack);
416 
417     return setSubImageImpl(context, index, area, formatInfo, GL_UNSIGNED_BYTE, unpack, unpackBuffer,
418                            pixels, vkFormat);
419 }
420 
setImageImpl(const gl::Context * context,const gl::ImageIndex & index,const gl::InternalFormat & formatInfo,const gl::Extents & size,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels)421 angle::Result TextureVk::setImageImpl(const gl::Context *context,
422                                       const gl::ImageIndex &index,
423                                       const gl::InternalFormat &formatInfo,
424                                       const gl::Extents &size,
425                                       GLenum type,
426                                       const gl::PixelUnpackState &unpack,
427                                       gl::Buffer *unpackBuffer,
428                                       const uint8_t *pixels)
429 {
430     ContextVk *contextVk = vk::GetImpl(context);
431     RendererVk *renderer = contextVk->getRenderer();
432 
433     const vk::Format &vkFormat = renderer->getFormat(formatInfo.sizedInternalFormat);
434 
435     ANGLE_TRY(redefineLevel(context, index, vkFormat, size));
436 
437     // Early-out on empty textures, don't create a zero-sized storage.
438     if (size.empty())
439     {
440         return angle::Result::Continue;
441     }
442 
443     return setSubImageImpl(context, index, gl::Box(gl::kOffsetZero, size), formatInfo, type, unpack,
444                            unpackBuffer, pixels, vkFormat);
445 }
446 
isFastUnpackPossible(const vk::Format & vkFormat,size_t offset) const447 bool TextureVk::isFastUnpackPossible(const vk::Format &vkFormat, size_t offset) const
448 {
449     // Conditions to determine if fast unpacking is possible
450     // 1. Image must be well defined to unpack directly to it
451     //    TODO(http://anglebug.com/4222) Create and stage a temp image instead
452     // 2. Can't perform a fast copy for depth/stencil, except from non-emulated depth or stencil
453     //    to emulated depth/stencil.  GL requires depth and stencil data to be packed, while Vulkan
454     //    requires them to be separate.
455     // 2. Can't perform a fast copy for emulated formats, except from non-emulated depth or stencil
456     //    to emulated depth/stencil.
457     // 3. vkCmdCopyBufferToImage requires byte offset to be a multiple of 4.
458     const angle::Format &bufferFormat = vkFormat.getActualBufferFormat(false);
459     const bool isCombinedDepthStencil = bufferFormat.hasDepthAndStencilBits();
460     const bool isDepthXorStencil = bufferFormat.hasDepthOrStencilBits() && !isCombinedDepthStencil;
461     const bool isCompatibleDepth = vkFormat.getIntendedFormat().depthBits == bufferFormat.depthBits;
462     const VkDeviceSize imageCopyAlignment =
463         vk::GetImageCopyBufferAlignment(mImage->getActualFormatID());
464     return mImage->valid() && !isCombinedDepthStencil &&
465            (vkFormat.getIntendedFormatID() ==
466                 vkFormat.getActualImageFormatID(getRequiredImageAccess()) ||
467             (isDepthXorStencil && isCompatibleDepth)) &&
468            (offset % imageCopyAlignment) == 0;
469 }
470 
isMipImageDescDefined(gl::TextureTarget textureTarget,size_t level)471 bool TextureVk::isMipImageDescDefined(gl::TextureTarget textureTarget, size_t level)
472 {
473     // A defined image should have defined width, height, and format.
474     gl::ImageDesc imageDesc = mState.getImageDesc(textureTarget, level);
475     return imageDesc.size.height != 0 && imageDesc.size.width != 0 &&
476            imageDesc.format.info->format != GL_NONE;
477 }
478 
isMutableTextureConsistentlySpecifiedForFlush()479 bool TextureVk::isMutableTextureConsistentlySpecifiedForFlush()
480 {
481     // Disable optimization if the base level is not 0.
482     if (mState.getBaseLevel() != 0)
483     {
484         return false;
485     }
486 
487     // If the texture is a cubemap, we will have to wait until it is complete.
488     if (mState.getType() == gl::TextureType::CubeMap && !mState.isCubeComplete())
489     {
490         return false;
491     }
492 
493     // Before we initialize the full mip chain, we make sure that the base mip level and at least
494     // one other level after (1 for simplicity) are defined and have appropriate values.
495     if (mState.getImageDescs().size() < 2)
496     {
497         return false;
498     }
499 
500     gl::TextureTarget textureTarget = (mState.getType() == gl::TextureType::CubeMap)
501                                           ? gl::kCubeMapTextureTargetMin
502                                           : gl::TextureTypeToTarget(mState.getType(), 0);
503     if (!isMipImageDescDefined(textureTarget, 0) || !isMipImageDescDefined(textureTarget, 1))
504     {
505         return false;
506     }
507 
508     // The mip levels that are already defined should have attributes compatible with those of the
509     // base mip level. For each defined mip level, its size, format, number of samples, and depth
510     // are checked before flushing the texture updates. For complete cubemaps, there are 6 images
511     // per mip level. Therefore, mState would have 6 times as many images.
512     gl::ImageDesc baseImageDesc = mState.getImageDesc(textureTarget, 0);
513     size_t maxImageMipLevels    = (mState.getType() == gl::TextureType::CubeMap)
514                                       ? (mState.getImageDescs().size() / 6)
515                                       : mState.getImageDescs().size();
516 
517     for (size_t image = 1; image < maxImageMipLevels; image++)
518     {
519         gl::ImageDesc mipImageDesc = mState.getImageDesc(textureTarget, image);
520         if (!isMipImageDescDefined(textureTarget, image))
521         {
522             continue;
523         }
524 
525         // If the texture is 2DArray or 3D, the depths should also be checked according to the mip
526         // levels. If the texture type is a cube map array, the depth represents the number of
527         // layer-faces and does not change for mipmaps. Otherwise, we skip the depth comparison.
528         gl::Extents baseImageDescMipSize;
529         baseImageDescMipSize.width  = std::max(baseImageDesc.size.width >> image, 1);
530         baseImageDescMipSize.height = std::max(baseImageDesc.size.height >> image, 1);
531         baseImageDescMipSize.depth  = std::max(baseImageDesc.size.depth >> image, 1);
532 
533         bool isDepthCompatible = (mState.getType() == gl::TextureType::_3D ||
534                                   mState.getType() == gl::TextureType::_2DArray)
535                                      ? (baseImageDescMipSize.depth == mipImageDesc.size.depth)
536                                      : (mState.getType() != gl::TextureType::CubeMapArray ||
537                                         baseImageDesc.size.depth == mipImageDesc.size.depth);
538 
539         bool isSizeCompatible = (baseImageDescMipSize.width == mipImageDesc.size.width) &&
540                                 (baseImageDescMipSize.height == mipImageDesc.size.height) &&
541                                 isDepthCompatible;
542         bool isFormatCompatible          = (baseImageDesc.format.info->sizedInternalFormat ==
543                                    mipImageDesc.format.info->sizedInternalFormat);
544         bool isNumberOfSamplesCompatible = (baseImageDesc.samples == mipImageDesc.samples);
545 
546         if (!isSizeCompatible || !isFormatCompatible || !isNumberOfSamplesCompatible)
547         {
548             return false;
549         }
550     }
551 
552     return true;
553 }
554 
shouldUpdateBeStaged(gl::LevelIndex textureLevelIndexGL,angle::FormatID dstImageFormatID) const555 bool TextureVk::shouldUpdateBeStaged(gl::LevelIndex textureLevelIndexGL,
556                                      angle::FormatID dstImageFormatID) const
557 {
558     ASSERT(mImage);
559 
560     // For EGLImages we should never stage the update since staged update is subject to thread
561     // racing bugs when two textures in different share groups are accessed at same time.
562     if (!mOwnsImage)
563     {
564         // EGLImage is always initialized upon creation and format should always renderable so that
565         // there is no format upgrade.
566         ASSERT(mImage->valid());
567         ASSERT(IsTextureLevelInAllocatedImage(*mImage, textureLevelIndexGL));
568         ASSERT(mImage->getActualFormatID() == dstImageFormatID);
569         ASSERT(!mRedefinedLevels.test(textureLevelIndexGL.get()));
570         return false;
571     }
572 
573     // If we do not have storage yet, there is impossible to immediately do the copy, so just
574     // stage it. Note that immutable texture will have a valid storage.
575     if (!mImage->valid())
576     {
577         return true;
578     }
579 
580     // If update is outside the range of image levels, it must be staged.
581     if (!IsTextureLevelInAllocatedImage(*mImage, textureLevelIndexGL))
582     {
583         return true;
584     }
585 
586     // During the process of format change, mImage's format may become stale. In that case, we
587     // should always stage the update and let caller properly release mImage and initExternal and
588     // flush the update.
589     if (mImage->getActualFormatID() != dstImageFormatID)
590     {
591         return true;
592     }
593 
594     // Otherwise, it can only be directly applied to the image if the level is not previously
595     // incompatibly redefined.
596     return mRedefinedLevels.test(textureLevelIndexGL.get());
597 }
598 
setSubImageImpl(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,const gl::InternalFormat & formatInfo,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels,const vk::Format & vkFormat)599 angle::Result TextureVk::setSubImageImpl(const gl::Context *context,
600                                          const gl::ImageIndex &index,
601                                          const gl::Box &area,
602                                          const gl::InternalFormat &formatInfo,
603                                          GLenum type,
604                                          const gl::PixelUnpackState &unpack,
605                                          gl::Buffer *unpackBuffer,
606                                          const uint8_t *pixels,
607                                          const vk::Format &vkFormat)
608 {
609     ContextVk *contextVk = vk::GetImpl(context);
610 
611     // When possible flush out updates immediately.
612     bool shouldFlush = false;
613     if (!mOwnsImage || mState.getImmutableFormat() ||
614         (!shouldUpdateBeStaged(gl::LevelIndex(index.getLevelIndex()),
615                                vkFormat.getActualImageFormatID(getRequiredImageAccess()))))
616     {
617         shouldFlush = true;
618     }
619 
620     if (unpackBuffer)
621     {
622         BufferVk *unpackBufferVk       = vk::GetImpl(unpackBuffer);
623         vk::BufferHelper &bufferHelper = unpackBufferVk->getBuffer();
624         VkDeviceSize bufferOffset      = bufferHelper.getOffset();
625         uintptr_t offset               = reinterpret_cast<uintptr_t>(pixels);
626         GLuint inputRowPitch           = 0;
627         GLuint inputDepthPitch         = 0;
628         GLuint inputSkipBytes          = 0;
629 
630         ANGLE_TRY(mImage->CalculateBufferInfo(
631             contextVk, gl::Extents(area.width, area.height, area.depth), formatInfo, unpack, type,
632             index.usesTex3D(), &inputRowPitch, &inputDepthPitch, &inputSkipBytes));
633 
634         size_t offsetBytes = static_cast<size_t>(bufferOffset + offset + inputSkipBytes);
635 
636         // Note: cannot directly copy from a depth/stencil PBO.  GL requires depth and stencil data
637         // to be packed, while Vulkan requires them to be separate.
638         const VkImageAspectFlags aspectFlags =
639             vk::GetFormatAspectFlags(vkFormat.getIntendedFormat());
640 
641         if (!shouldUpdateBeStaged(gl::LevelIndex(index.getLevelIndex()),
642                                   vkFormat.getActualImageFormatID(getRequiredImageAccess())) &&
643             isFastUnpackPossible(vkFormat, offsetBytes))
644         {
645             GLuint pixelSize   = formatInfo.pixelBytes;
646             GLuint blockWidth  = formatInfo.compressedBlockWidth;
647             GLuint blockHeight = formatInfo.compressedBlockHeight;
648             if (!formatInfo.compressed)
649             {
650                 pixelSize   = formatInfo.computePixelBytes(type);
651                 blockWidth  = 1;
652                 blockHeight = 1;
653             }
654             ASSERT(pixelSize != 0 && inputRowPitch != 0 && blockWidth != 0 && blockHeight != 0);
655 
656             GLuint rowLengthPixels   = inputRowPitch / pixelSize * blockWidth;
657             GLuint imageHeightPixels = inputDepthPitch / inputRowPitch * blockHeight;
658 
659             ANGLE_TRY(copyBufferDataToImage(contextVk, &bufferHelper, index, rowLengthPixels,
660                                             imageHeightPixels, area, offsetBytes, aspectFlags));
661         }
662         else
663         {
664             ANGLE_VK_PERF_WARNING(
665                 contextVk, GL_DEBUG_SEVERITY_HIGH,
666                 "TexSubImage with unpack buffer copied on CPU due to store, format "
667                 "or offset restrictions");
668 
669             void *mapPtr = nullptr;
670 
671             ANGLE_TRY(unpackBufferVk->mapImpl(contextVk, GL_MAP_READ_BIT, &mapPtr));
672 
673             const uint8_t *source =
674                 static_cast<const uint8_t *>(mapPtr) + reinterpret_cast<ptrdiff_t>(pixels);
675 
676             ANGLE_TRY(mImage->stageSubresourceUpdateImpl(
677                 contextVk, getNativeImageIndex(index),
678                 gl::Extents(area.width, area.height, area.depth),
679                 gl::Offset(area.x, area.y, area.z), formatInfo, unpack, type, source, vkFormat,
680                 getRequiredImageAccess(), inputRowPitch, inputDepthPitch, inputSkipBytes));
681 
682             ANGLE_TRY(unpackBufferVk->unmapImpl(contextVk));
683         }
684     }
685     else if (pixels)
686     {
687         ANGLE_TRY(mImage->stageSubresourceUpdate(
688             contextVk, getNativeImageIndex(index), gl::Extents(area.width, area.height, area.depth),
689             gl::Offset(area.x, area.y, area.z), formatInfo, unpack, type, pixels, vkFormat,
690             getRequiredImageAccess()));
691     }
692 
693     // If we used context's staging buffer, flush out the updates
694     if (shouldFlush)
695     {
696         ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
697 
698         // If forceSubmitImmutableTextureUpdates is enabled, submit the staged updates as well
699         if (contextVk->getFeatures().forceSubmitImmutableTextureUpdates.enabled)
700         {
701             ANGLE_TRY(contextVk->submitStagedTextureUpdates());
702         }
703     }
704     else if (contextVk->isEligibleForMutableTextureFlush() && !mState.getImmutableFormat())
705     {
706         // Check if we should flush any mutable textures from before.
707         ANGLE_TRY(contextVk->getShareGroup()->onMutableTextureUpload(contextVk, this));
708     }
709 
710     return angle::Result::Continue;
711 }
712 
copyImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Rectangle & sourceArea,GLenum internalFormat,gl::Framebuffer * source)713 angle::Result TextureVk::copyImage(const gl::Context *context,
714                                    const gl::ImageIndex &index,
715                                    const gl::Rectangle &sourceArea,
716                                    GLenum internalFormat,
717                                    gl::Framebuffer *source)
718 {
719     RendererVk *renderer = vk::GetImpl(context)->getRenderer();
720 
721     gl::Extents newImageSize(sourceArea.width, sourceArea.height, 1);
722     const gl::InternalFormat &internalFormatInfo =
723         gl::GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE);
724     const vk::Format &vkFormat = renderer->getFormat(internalFormatInfo.sizedInternalFormat);
725 
726     ANGLE_TRY(redefineLevel(context, index, vkFormat, newImageSize));
727 
728     return copySubImageImpl(context, index, gl::Offset(0, 0, 0), sourceArea, internalFormatInfo,
729                             source);
730 }
731 
copySubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,gl::Framebuffer * source)732 angle::Result TextureVk::copySubImage(const gl::Context *context,
733                                       const gl::ImageIndex &index,
734                                       const gl::Offset &destOffset,
735                                       const gl::Rectangle &sourceArea,
736                                       gl::Framebuffer *source)
737 {
738     const gl::InternalFormat &currentFormat = *mState.getImageDesc(index).format.info;
739     return copySubImageImpl(context, index, destOffset, sourceArea, currentFormat, source);
740 }
741 
copyTexture(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,GLenum type,GLint sourceLevelGL,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,const gl::Texture * source)742 angle::Result TextureVk::copyTexture(const gl::Context *context,
743                                      const gl::ImageIndex &index,
744                                      GLenum internalFormat,
745                                      GLenum type,
746                                      GLint sourceLevelGL,
747                                      bool unpackFlipY,
748                                      bool unpackPremultiplyAlpha,
749                                      bool unpackUnmultiplyAlpha,
750                                      const gl::Texture *source)
751 {
752     RendererVk *renderer = vk::GetImpl(context)->getRenderer();
753 
754     TextureVk *sourceVk = vk::GetImpl(source);
755     const gl::ImageDesc &srcImageDesc =
756         sourceVk->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), sourceLevelGL);
757     gl::Box sourceBox(gl::kOffsetZero, srcImageDesc.size);
758 
759     const gl::InternalFormat &dstFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
760     const vk::Format &dstVkFormat = renderer->getFormat(dstFormatInfo.sizedInternalFormat);
761 
762     ANGLE_TRY(redefineLevel(context, index, dstVkFormat, srcImageDesc.size));
763 
764     return copySubTextureImpl(vk::GetImpl(context), index, gl::kOffsetZero, dstFormatInfo,
765                               gl::LevelIndex(sourceLevelGL), sourceBox, unpackFlipY,
766                               unpackPremultiplyAlpha, unpackUnmultiplyAlpha, sourceVk);
767 }
768 
copySubTexture(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & dstOffset,GLint srcLevelGL,const gl::Box & sourceBox,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,const gl::Texture * source)769 angle::Result TextureVk::copySubTexture(const gl::Context *context,
770                                         const gl::ImageIndex &index,
771                                         const gl::Offset &dstOffset,
772                                         GLint srcLevelGL,
773                                         const gl::Box &sourceBox,
774                                         bool unpackFlipY,
775                                         bool unpackPremultiplyAlpha,
776                                         bool unpackUnmultiplyAlpha,
777                                         const gl::Texture *source)
778 {
779     gl::TextureTarget target = index.getTarget();
780     gl::LevelIndex dstLevelGL(index.getLevelIndex());
781     const gl::InternalFormat &dstFormatInfo =
782         *mState.getImageDesc(target, dstLevelGL.get()).format.info;
783     return copySubTextureImpl(vk::GetImpl(context), index, dstOffset, dstFormatInfo,
784                               gl::LevelIndex(srcLevelGL), sourceBox, unpackFlipY,
785                               unpackPremultiplyAlpha, unpackUnmultiplyAlpha, vk::GetImpl(source));
786 }
787 
copyRenderbufferSubData(const gl::Context * context,const gl::Renderbuffer * srcBuffer,GLint srcLevel,GLint srcX,GLint srcY,GLint srcZ,GLint dstLevel,GLint dstX,GLint dstY,GLint dstZ,GLsizei srcWidth,GLsizei srcHeight,GLsizei srcDepth)788 angle::Result TextureVk::copyRenderbufferSubData(const gl::Context *context,
789                                                  const gl::Renderbuffer *srcBuffer,
790                                                  GLint srcLevel,
791                                                  GLint srcX,
792                                                  GLint srcY,
793                                                  GLint srcZ,
794                                                  GLint dstLevel,
795                                                  GLint dstX,
796                                                  GLint dstY,
797                                                  GLint dstZ,
798                                                  GLsizei srcWidth,
799                                                  GLsizei srcHeight,
800                                                  GLsizei srcDepth)
801 {
802     ContextVk *contextVk     = vk::GetImpl(context);
803     RenderbufferVk *sourceVk = vk::GetImpl(srcBuffer);
804 
805     // Make sure the source/destination targets are initialized and all staged updates are flushed.
806     ANGLE_TRY(sourceVk->ensureImageInitialized(context));
807     ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
808 
809     return vk::ImageHelper::CopyImageSubData(context, sourceVk->getImage(), srcLevel, srcX, srcY,
810                                              srcZ, mImage, dstLevel, dstX, dstY, dstZ, srcWidth,
811                                              srcHeight, srcDepth);
812 }
813 
copyTextureSubData(const gl::Context * context,const gl::Texture * srcTexture,GLint srcLevel,GLint srcX,GLint srcY,GLint srcZ,GLint dstLevel,GLint dstX,GLint dstY,GLint dstZ,GLsizei srcWidth,GLsizei srcHeight,GLsizei srcDepth)814 angle::Result TextureVk::copyTextureSubData(const gl::Context *context,
815                                             const gl::Texture *srcTexture,
816                                             GLint srcLevel,
817                                             GLint srcX,
818                                             GLint srcY,
819                                             GLint srcZ,
820                                             GLint dstLevel,
821                                             GLint dstX,
822                                             GLint dstY,
823                                             GLint dstZ,
824                                             GLsizei srcWidth,
825                                             GLsizei srcHeight,
826                                             GLsizei srcDepth)
827 {
828     ContextVk *contextVk = vk::GetImpl(context);
829     TextureVk *sourceVk  = vk::GetImpl(srcTexture);
830 
831     // Make sure the source/destination targets are initialized and all staged updates are flushed.
832     ANGLE_TRY(sourceVk->ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
833     ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
834 
835     return vk::ImageHelper::CopyImageSubData(context, &sourceVk->getImage(), srcLevel, srcX, srcY,
836                                              srcZ, mImage, dstLevel, dstX, dstY, dstZ, srcWidth,
837                                              srcHeight, srcDepth);
838 }
839 
copyCompressedTexture(const gl::Context * context,const gl::Texture * source)840 angle::Result TextureVk::copyCompressedTexture(const gl::Context *context,
841                                                const gl::Texture *source)
842 {
843     ContextVk *contextVk = vk::GetImpl(context);
844     TextureVk *sourceVk  = vk::GetImpl(source);
845 
846     gl::TextureTarget sourceTarget = NonCubeTextureTypeToTarget(source->getType());
847     constexpr GLint sourceLevelGL  = 0;
848     constexpr GLint destLevelGL    = 0;
849 
850     const gl::InternalFormat &internalFormat = *source->getFormat(sourceTarget, sourceLevelGL).info;
851     const vk::Format &vkFormat =
852         contextVk->getRenderer()->getFormat(internalFormat.sizedInternalFormat);
853     const gl::Extents size(static_cast<int>(source->getWidth(sourceTarget, sourceLevelGL)),
854                            static_cast<int>(source->getHeight(sourceTarget, sourceLevelGL)),
855                            static_cast<int>(source->getDepth(sourceTarget, sourceLevelGL)));
856     const gl::ImageIndex destIndex = gl::ImageIndex::MakeFromTarget(sourceTarget, destLevelGL, 1);
857 
858     ANGLE_TRY(redefineLevel(context, destIndex, vkFormat, size));
859 
860     ANGLE_TRY(sourceVk->ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
861 
862     return copySubImageImplWithTransfer(contextVk, destIndex, gl::kOffsetZero, vkFormat,
863                                         gl::LevelIndex(sourceLevelGL), 0,
864                                         gl::Box(gl::kOffsetZero, size), &sourceVk->getImage());
865 }
866 
copySubImageImpl(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,const gl::InternalFormat & internalFormat,gl::Framebuffer * source)867 angle::Result TextureVk::copySubImageImpl(const gl::Context *context,
868                                           const gl::ImageIndex &index,
869                                           const gl::Offset &destOffset,
870                                           const gl::Rectangle &sourceArea,
871                                           const gl::InternalFormat &internalFormat,
872                                           gl::Framebuffer *source)
873 {
874     gl::Extents fbSize = source->getReadColorAttachment()->getSize();
875     gl::Rectangle clippedSourceArea;
876     if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height),
877                        &clippedSourceArea))
878     {
879         return angle::Result::Continue;
880     }
881 
882     ContextVk *contextVk         = vk::GetImpl(context);
883     RendererVk *renderer         = contextVk->getRenderer();
884     FramebufferVk *framebufferVk = vk::GetImpl(source);
885 
886     const gl::ImageIndex offsetImageIndex = getNativeImageIndex(index);
887 
888     // If negative offsets are given, clippedSourceArea ensures we don't read from those offsets.
889     // However, that changes the sourceOffset->destOffset mapping.  Here, destOffset is shifted by
890     // the same amount as clipped to correct the error.
891     VkImageType imageType = gl_vk::GetImageType(mState.getType());
892     int zOffset           = (imageType == VK_IMAGE_TYPE_3D) ? destOffset.z : 0;
893     const gl::Offset modifiedDestOffset(destOffset.x + clippedSourceArea.x - sourceArea.x,
894                                         destOffset.y + clippedSourceArea.y - sourceArea.y, zOffset);
895 
896     RenderTargetVk *colorReadRT = framebufferVk->getColorReadRenderTarget();
897 
898     angle::FormatID srcIntendedFormatID = colorReadRT->getImageIntendedFormatID();
899     angle::FormatID srcActualFormatID   = colorReadRT->getImageActualFormatID();
900     VkImageTiling srcTilingMode         = colorReadRT->getImageForCopy().getTilingMode();
901     const vk::Format &dstFormat         = renderer->getFormat(internalFormat.sizedInternalFormat);
902     angle::FormatID dstIntendedFormatID = dstFormat.getIntendedFormatID();
903     angle::FormatID dstActualFormatID = dstFormat.getActualImageFormatID(getRequiredImageAccess());
904     VkImageTiling destTilingMode      = getTilingMode();
905 
906     bool isViewportFlipY = contextVk->isViewportFlipEnabledForReadFBO();
907 
908     gl::Box clippedSourceBox(clippedSourceArea.x, clippedSourceArea.y, colorReadRT->getLayerIndex(),
909                              clippedSourceArea.width, clippedSourceArea.height, 1);
910 
911     // If it's possible to perform the copy with a transfer, that's the best option.
912     if (!isViewportFlipY && CanCopyWithTransferForTexImage(
913                                 renderer, srcIntendedFormatID, srcActualFormatID, srcTilingMode,
914                                 dstIntendedFormatID, dstActualFormatID, destTilingMode))
915     {
916         return copySubImageImplWithTransfer(contextVk, offsetImageIndex, modifiedDestOffset,
917                                             dstFormat, colorReadRT->getLevelIndex(),
918                                             colorReadRT->getLayerIndex(), clippedSourceBox,
919                                             &colorReadRT->getImageForCopy());
920     }
921 
922     // If it's possible to perform the copy with a draw call, do that.
923     if (CanCopyWithDraw(renderer, srcActualFormatID, srcTilingMode, dstActualFormatID,
924                         destTilingMode))
925     {
926         // Layer count can only be 1 as the source is a framebuffer.
927         ASSERT(offsetImageIndex.getLayerCount() == 1);
928 
929         // Flush the render pass, which may incur a vkQueueSubmit, before taking any views.
930         // Otherwise the view serials would not reflect the render pass they are really used in.
931         // http://crbug.com/1272266#c22
932         ANGLE_TRY(
933             contextVk->flushCommandsAndEndRenderPass(RenderPassClosureReason::PrepareForImageCopy));
934 
935         const vk::ImageView *copyImageView = nullptr;
936         ANGLE_TRY(colorReadRT->getCopyImageView(contextVk, &copyImageView));
937 
938         return copySubImageImplWithDraw(contextVk, offsetImageIndex, modifiedDestOffset, dstFormat,
939                                         colorReadRT->getLevelIndex(), clippedSourceBox,
940                                         isViewportFlipY, false, false, false,
941                                         &colorReadRT->getImageForCopy(), copyImageView,
942                                         contextVk->getRotationReadFramebuffer());
943     }
944 
945     ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_HIGH,
946                           "Texture copied on CPU due to format restrictions");
947 
948     // Do a CPU readback that does the conversion, and then stage the change to the pixel buffer.
949     ANGLE_TRY(mImage->stageSubresourceUpdateFromFramebuffer(
950         context, offsetImageIndex, clippedSourceArea, modifiedDestOffset,
951         gl::Extents(clippedSourceArea.width, clippedSourceArea.height, 1), internalFormat,
952         getRequiredImageAccess(), framebufferVk));
953 
954     // Flush out staged update if possible
955     if (!shouldUpdateBeStaged(gl::LevelIndex(index.getLevelIndex()), dstActualFormatID))
956     {
957         ANGLE_TRY(flushImageStagedUpdates(contextVk));
958     }
959 
960     return angle::Result::Continue;
961 }
962 
copySubTextureImpl(ContextVk * contextVk,const gl::ImageIndex & index,const gl::Offset & dstOffset,const gl::InternalFormat & dstFormat,gl::LevelIndex sourceLevelGL,const gl::Box & sourceBox,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,TextureVk * source)963 angle::Result TextureVk::copySubTextureImpl(ContextVk *contextVk,
964                                             const gl::ImageIndex &index,
965                                             const gl::Offset &dstOffset,
966                                             const gl::InternalFormat &dstFormat,
967                                             gl::LevelIndex sourceLevelGL,
968                                             const gl::Box &sourceBox,
969                                             bool unpackFlipY,
970                                             bool unpackPremultiplyAlpha,
971                                             bool unpackUnmultiplyAlpha,
972                                             TextureVk *source)
973 {
974     RendererVk *renderer = contextVk->getRenderer();
975 
976     ANGLE_TRY(source->ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
977 
978     const angle::Format &srcIntendedFormat = source->getImage().getIntendedFormat();
979     angle::FormatID srcFormatID            = source->getImage().getActualFormatID();
980     VkImageTiling srcTilingMode            = source->getImage().getTilingMode();
981     const vk::Format &dstVkFormat          = renderer->getFormat(dstFormat.sizedInternalFormat);
982     angle::FormatID dstFormatID = dstVkFormat.getActualImageFormatID(getRequiredImageAccess());
983     VkImageTiling dstTilingMode = getTilingMode();
984 
985     const gl::ImageIndex offsetImageIndex = getNativeImageIndex(index);
986 
987     // If it's possible to perform the copy with a transfer, that's the best option.
988     if (!unpackFlipY && !unpackPremultiplyAlpha && !unpackUnmultiplyAlpha &&
989         CanCopyWithTransferForCopyTexture(renderer, source->getImage(), srcTilingMode,
990                                           dstVkFormat.getIntendedFormatID(), dstFormatID,
991                                           dstTilingMode))
992     {
993         return copySubImageImplWithTransfer(contextVk, offsetImageIndex, dstOffset, dstVkFormat,
994                                             sourceLevelGL, sourceBox.z, sourceBox,
995                                             &source->getImage());
996     }
997 
998     // If it's possible to perform the copy with a draw call, do that.
999     if (CanCopyWithDraw(renderer, srcFormatID, srcTilingMode, dstFormatID, dstTilingMode))
1000     {
1001         // Flush the render pass, which may incur a vkQueueSubmit, before taking any views.
1002         // Otherwise the view serials would not reflect the render pass they are really used in.
1003         // http://crbug.com/1272266#c22
1004         ANGLE_TRY(
1005             contextVk->flushCommandsAndEndRenderPass(RenderPassClosureReason::PrepareForImageCopy));
1006 
1007         return copySubImageImplWithDraw(
1008             contextVk, offsetImageIndex, dstOffset, dstVkFormat, sourceLevelGL, sourceBox, false,
1009             unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha, &source->getImage(),
1010             &source->getCopyImageView(), SurfaceRotation::Identity);
1011     }
1012 
1013     ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_HIGH,
1014                           "Texture copied on CPU due to format restrictions");
1015 
1016     // Read back the requested region of the source texture
1017     vk::RendererScoped<vk::BufferHelper> bufferHelper(renderer);
1018     uint8_t *sourceData = nullptr;
1019     ANGLE_TRY(source->copyImageDataToBufferAndGetData(
1020         contextVk, sourceLevelGL, sourceBox.depth, sourceBox,
1021         RenderPassClosureReason::CopyTextureOnCPU, &bufferHelper.get(), &sourceData));
1022 
1023     const angle::Format &srcTextureFormat = source->getImage().getActualFormat();
1024     const angle::Format &dstTextureFormat =
1025         dstVkFormat.getActualImageFormat(getRequiredImageAccess());
1026     size_t destinationAllocationSize =
1027         sourceBox.width * sourceBox.height * sourceBox.depth * dstTextureFormat.pixelBytes;
1028 
1029     // Allocate memory in the destination texture for the copy/conversion
1030     uint32_t stagingBaseLayer =
1031         offsetImageIndex.hasLayer() ? offsetImageIndex.getLayerIndex() : dstOffset.z;
1032     uint32_t stagingLayerCount = sourceBox.depth;
1033     gl::Offset stagingOffset   = dstOffset;
1034     gl::Extents stagingExtents(sourceBox.width, sourceBox.height, sourceBox.depth);
1035     bool is3D = gl_vk::GetImageType(mState.getType()) == VK_IMAGE_TYPE_3D;
1036 
1037     if (is3D)
1038     {
1039         stagingBaseLayer  = 0;
1040         stagingLayerCount = 1;
1041     }
1042     else
1043     {
1044         stagingOffset.z      = 0;
1045         stagingExtents.depth = 1;
1046     }
1047 
1048     const gl::ImageIndex stagingIndex = gl::ImageIndex::Make2DArrayRange(
1049         offsetImageIndex.getLevelIndex(), stagingBaseLayer, stagingLayerCount);
1050 
1051     uint8_t *destData = nullptr;
1052     ANGLE_TRY(mImage->stageSubresourceUpdateAndGetData(contextVk, destinationAllocationSize,
1053                                                        stagingIndex, stagingExtents, stagingOffset,
1054                                                        &destData, dstFormatID));
1055 
1056     // Source and dst data is tightly packed
1057     GLuint srcDataRowPitch = sourceBox.width * srcTextureFormat.pixelBytes;
1058     GLuint dstDataRowPitch = sourceBox.width * dstTextureFormat.pixelBytes;
1059 
1060     GLuint srcDataDepthPitch = srcDataRowPitch * sourceBox.height;
1061     GLuint dstDataDepthPitch = dstDataRowPitch * sourceBox.height;
1062 
1063     rx::PixelReadFunction pixelReadFunction   = srcTextureFormat.pixelReadFunction;
1064     rx::PixelWriteFunction pixelWriteFunction = dstTextureFormat.pixelWriteFunction;
1065 
1066     // Fix up the read/write functions for the sake of luminance/alpha that are emulated with
1067     // formats whose channels don't correspond to the original format (alpha is emulated with red,
1068     // and luminance/alpha is emulated with red/green).
1069     if (srcIntendedFormat.isLUMA())
1070     {
1071         pixelReadFunction = srcIntendedFormat.pixelReadFunction;
1072     }
1073     if (dstVkFormat.getIntendedFormat().isLUMA())
1074     {
1075         pixelWriteFunction = dstVkFormat.getIntendedFormat().pixelWriteFunction;
1076     }
1077 
1078     CopyImageCHROMIUM(sourceData, srcDataRowPitch, srcTextureFormat.pixelBytes, srcDataDepthPitch,
1079                       pixelReadFunction, destData, dstDataRowPitch, dstTextureFormat.pixelBytes,
1080                       dstDataDepthPitch, pixelWriteFunction, dstFormat.format,
1081                       dstFormat.componentType, sourceBox.width, sourceBox.height, sourceBox.depth,
1082                       unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha);
1083 
1084     if (!shouldUpdateBeStaged(gl::LevelIndex(index.getLevelIndex()), dstFormatID))
1085     {
1086         ANGLE_TRY(flushImageStagedUpdates(contextVk));
1087     }
1088 
1089     return angle::Result::Continue;
1090 }
1091 
copySubImageImplWithTransfer(ContextVk * contextVk,const gl::ImageIndex & index,const gl::Offset & dstOffset,const vk::Format & dstFormat,gl::LevelIndex sourceLevelGL,size_t sourceLayer,const gl::Box & sourceBox,vk::ImageHelper * srcImage)1092 angle::Result TextureVk::copySubImageImplWithTransfer(ContextVk *contextVk,
1093                                                       const gl::ImageIndex &index,
1094                                                       const gl::Offset &dstOffset,
1095                                                       const vk::Format &dstFormat,
1096                                                       gl::LevelIndex sourceLevelGL,
1097                                                       size_t sourceLayer,
1098                                                       const gl::Box &sourceBox,
1099                                                       vk::ImageHelper *srcImage)
1100 {
1101     RendererVk *renderer = contextVk->getRenderer();
1102 
1103     gl::LevelIndex level(index.getLevelIndex());
1104     uint32_t baseLayer  = index.hasLayer() ? index.getLayerIndex() : dstOffset.z;
1105     uint32_t layerCount = sourceBox.depth;
1106 
1107     gl::Offset srcOffset = {sourceBox.x, sourceBox.y, sourceBox.z};
1108     gl::Extents extents  = {sourceBox.width, sourceBox.height, sourceBox.depth};
1109 
1110     // Change source layout if necessary
1111     vk::CommandBufferAccess access;
1112     access.onImageTransferRead(VK_IMAGE_ASPECT_COLOR_BIT, srcImage);
1113 
1114     VkImageSubresourceLayers srcSubresource = {};
1115     srcSubresource.aspectMask               = VK_IMAGE_ASPECT_COLOR_BIT;
1116     srcSubresource.mipLevel                 = srcImage->toVkLevel(sourceLevelGL).get();
1117     srcSubresource.baseArrayLayer           = static_cast<uint32_t>(sourceLayer);
1118     srcSubresource.layerCount               = layerCount;
1119 
1120     bool isSrc3D  = srcImage->getExtents().depth > 1;
1121     bool isDest3D = gl_vk::GetImageType(mState.getType()) == VK_IMAGE_TYPE_3D;
1122 
1123     if (isSrc3D)
1124     {
1125         Set3DBaseArrayLayerAndLayerCount(&srcSubresource);
1126     }
1127     else
1128     {
1129         ASSERT(srcSubresource.baseArrayLayer == static_cast<uint32_t>(srcOffset.z));
1130         srcOffset.z = 0;
1131     }
1132 
1133     gl::Offset dstOffsetModified = dstOffset;
1134     if (!isDest3D)
1135     {
1136         // If destination is not 3D, destination offset must be 0.
1137         dstOffsetModified.z = 0;
1138     }
1139 
1140     // Perform self-copies through a staging buffer.
1141     // TODO: optimize to copy directly if possible.  http://anglebug.com/4719
1142     bool isSelfCopy = mImage == srcImage;
1143 
1144     // If destination is valid, copy the source directly into it.
1145     if (!shouldUpdateBeStaged(level, dstFormat.getActualImageFormatID(getRequiredImageAccess())) &&
1146         !isSelfCopy)
1147     {
1148         // Make sure any updates to the image are already flushed.
1149         ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
1150 
1151         access.onImageTransferWrite(level, 1, baseLayer, layerCount, VK_IMAGE_ASPECT_COLOR_BIT,
1152                                     mImage);
1153 
1154         vk::OutsideRenderPassCommandBuffer *commandBuffer;
1155         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
1156 
1157         VkImageSubresourceLayers destSubresource = srcSubresource;
1158         destSubresource.mipLevel                 = mImage->toVkLevel(level).get();
1159         destSubresource.baseArrayLayer           = baseLayer;
1160         destSubresource.layerCount               = layerCount;
1161 
1162         if (isDest3D)
1163         {
1164             Set3DBaseArrayLayerAndLayerCount(&destSubresource);
1165         }
1166         else if (!isSrc3D)
1167         {
1168             // extents.depth should be set to layer count if any of the source or destination is a
1169             // 2D Array.  If both are 2D Array, it should be set to 1.
1170             extents.depth = 1;
1171         }
1172 
1173         vk::ImageHelper::Copy(contextVk, srcImage, mImage, srcOffset, dstOffsetModified, extents,
1174                               srcSubresource, destSubresource, commandBuffer);
1175     }
1176     else
1177     {
1178         // Create a temporary image to stage the copy
1179         std::unique_ptr<vk::RefCounted<vk::ImageHelper>> stagingImage;
1180         stagingImage = std::make_unique<vk::RefCounted<vk::ImageHelper>>();
1181 
1182         ANGLE_TRY(stagingImage->get().init2DStaging(
1183             contextVk, mState.hasProtectedContent(), renderer->getMemoryProperties(),
1184             gl::Extents(sourceBox.width, sourceBox.height, 1), dstFormat.getIntendedFormatID(),
1185             dstFormat.getActualImageFormatID(getRequiredImageAccess()), kTransferImageFlags,
1186             layerCount));
1187 
1188         access.onImageTransferWrite(gl::LevelIndex(0), 1, 0, layerCount, VK_IMAGE_ASPECT_COLOR_BIT,
1189                                     &stagingImage->get());
1190 
1191         vk::OutsideRenderPassCommandBuffer *commandBuffer;
1192         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
1193 
1194         VkImageSubresourceLayers destSubresource = srcSubresource;
1195         destSubresource.mipLevel                 = 0;
1196         destSubresource.baseArrayLayer           = 0;
1197         destSubresource.layerCount               = layerCount;
1198 
1199         if (!isSrc3D)
1200         {
1201             // extents.depth should be set to layer count if any of the source or destination is a
1202             // 2D Array.  If both are 2D Array, it should be set to 1.
1203             extents.depth = 1;
1204         }
1205 
1206         vk::ImageHelper::Copy(contextVk, srcImage, &stagingImage->get(), srcOffset, gl::kOffsetZero,
1207                               extents, srcSubresource, destSubresource, commandBuffer);
1208 
1209         // Stage the copy for when the image storage is actually created.
1210         VkImageType imageType = gl_vk::GetImageType(mState.getType());
1211         const gl::ImageIndex stagingIndex =
1212             gl::ImageIndex::Make2DArrayRange(level.get(), baseLayer, layerCount);
1213         mImage->stageSubresourceUpdateFromImage(stagingImage.release(), stagingIndex,
1214                                                 vk::LevelIndex(0), dstOffsetModified, extents,
1215                                                 imageType);
1216     }
1217 
1218     return angle::Result::Continue;
1219 }
1220 
copySubImageImplWithDraw(ContextVk * contextVk,const gl::ImageIndex & index,const gl::Offset & dstOffset,const vk::Format & dstFormat,gl::LevelIndex sourceLevelGL,const gl::Box & sourceBox,bool isSrcFlipY,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,vk::ImageHelper * srcImage,const vk::ImageView * srcView,SurfaceRotation srcFramebufferRotation)1221 angle::Result TextureVk::copySubImageImplWithDraw(ContextVk *contextVk,
1222                                                   const gl::ImageIndex &index,
1223                                                   const gl::Offset &dstOffset,
1224                                                   const vk::Format &dstFormat,
1225                                                   gl::LevelIndex sourceLevelGL,
1226                                                   const gl::Box &sourceBox,
1227                                                   bool isSrcFlipY,
1228                                                   bool unpackFlipY,
1229                                                   bool unpackPremultiplyAlpha,
1230                                                   bool unpackUnmultiplyAlpha,
1231                                                   vk::ImageHelper *srcImage,
1232                                                   const vk::ImageView *srcView,
1233                                                   SurfaceRotation srcFramebufferRotation)
1234 {
1235     RendererVk *renderer = contextVk->getRenderer();
1236     UtilsVk &utilsVk     = contextVk->getUtils();
1237 
1238     // Potentially make adjustments for pre-rotation.
1239     gl::Box rotatedSourceBox = sourceBox;
1240     gl::Extents srcExtents   = srcImage->getLevelExtents2D(vk::LevelIndex(0));
1241     switch (srcFramebufferRotation)
1242     {
1243         case SurfaceRotation::Identity:
1244             // No adjustments needed
1245             break;
1246         case SurfaceRotation::Rotated90Degrees:
1247             // Turn off y-flip for 90 degrees, as we don't want it affecting the
1248             // shaderParams.srcOffset calculation done in UtilsVk::copyImage().
1249             ASSERT(isSrcFlipY);
1250             isSrcFlipY = false;
1251             std::swap(rotatedSourceBox.x, rotatedSourceBox.y);
1252             std::swap(rotatedSourceBox.width, rotatedSourceBox.height);
1253             std::swap(srcExtents.width, srcExtents.height);
1254             break;
1255         case SurfaceRotation::Rotated180Degrees:
1256             ASSERT(isSrcFlipY);
1257             rotatedSourceBox.x = srcExtents.width - sourceBox.x - sourceBox.width - 1;
1258             rotatedSourceBox.y = srcExtents.height - sourceBox.y - sourceBox.height - 1;
1259             break;
1260         case SurfaceRotation::Rotated270Degrees:
1261             // Turn off y-flip for 270 degrees, as we don't want it affecting the
1262             // shaderParams.srcOffset calculation done in UtilsVk::copyImage().  It is needed
1263             // within the shader (when it will affect how the shader looks-up the source pixel),
1264             // and so shaderParams.flipY is turned on at the right time within
1265             // UtilsVk::copyImage().
1266             ASSERT(isSrcFlipY);
1267             isSrcFlipY         = false;
1268             rotatedSourceBox.x = srcExtents.height - sourceBox.y - sourceBox.height - 1;
1269             rotatedSourceBox.y = srcExtents.width - sourceBox.x - sourceBox.width - 1;
1270             std::swap(rotatedSourceBox.width, rotatedSourceBox.height);
1271             std::swap(srcExtents.width, srcExtents.height);
1272             break;
1273         default:
1274             UNREACHABLE();
1275             break;
1276     }
1277 
1278     gl::LevelIndex level(index.getLevelIndex());
1279 
1280     UtilsVk::CopyImageParameters params;
1281     params.srcOffset[0]        = rotatedSourceBox.x;
1282     params.srcOffset[1]        = rotatedSourceBox.y;
1283     params.srcExtents[0]       = rotatedSourceBox.width;
1284     params.srcExtents[1]       = rotatedSourceBox.height;
1285     params.dstOffset[0]        = dstOffset.x;
1286     params.dstOffset[1]        = dstOffset.y;
1287     params.srcMip              = srcImage->toVkLevel(sourceLevelGL).get();
1288     params.srcHeight           = srcExtents.height;
1289     params.dstMip              = level;
1290     params.srcPremultiplyAlpha = unpackPremultiplyAlpha && !unpackUnmultiplyAlpha;
1291     params.srcUnmultiplyAlpha  = unpackUnmultiplyAlpha && !unpackPremultiplyAlpha;
1292     params.srcFlipY            = isSrcFlipY;
1293     params.dstFlipY            = unpackFlipY;
1294     params.srcRotation         = srcFramebufferRotation;
1295 
1296     uint32_t baseLayer  = index.hasLayer() ? index.getLayerIndex() : dstOffset.z;
1297     uint32_t layerCount = sourceBox.depth;
1298 
1299     gl::Extents extents = {sourceBox.width, sourceBox.height, sourceBox.depth};
1300 
1301     bool isSrc3D  = srcImage->getExtents().depth > 1;
1302     bool isDest3D = gl_vk::GetImageType(mState.getType()) == VK_IMAGE_TYPE_3D;
1303 
1304     // Perform self-copies through a staging buffer.
1305     // TODO: optimize to copy directly if possible.  http://anglebug.com/4719
1306     bool isSelfCopy = mImage == srcImage;
1307     params.srcColorEncoding =
1308         gl::GetSizedInternalFormatInfo(srcImage->getIntendedFormat().glInternalFormat)
1309             .colorEncoding;
1310     params.dstColorEncoding =
1311         gl::GetSizedInternalFormatInfo(dstFormat.getIntendedFormat().glInternalFormat)
1312             .colorEncoding;
1313 
1314     // If destination is valid, copy the source directly into it.
1315     if (!shouldUpdateBeStaged(level, dstFormat.getActualImageFormatID(getRequiredImageAccess())) &&
1316         !isSelfCopy)
1317     {
1318         // Make sure any updates to the image are already flushed.
1319         ANGLE_TRY(flushImageStagedUpdates(contextVk));
1320 
1321         for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex)
1322         {
1323             params.srcLayer = layerIndex + sourceBox.z;
1324             params.dstLayer = baseLayer + layerIndex;
1325 
1326             const vk::ImageView *destView;
1327             ANGLE_TRY(getLevelLayerImageView(contextVk, level, baseLayer + layerIndex, &destView));
1328 
1329             ANGLE_TRY(utilsVk.copyImage(contextVk, mImage, destView, srcImage, srcView, params));
1330         }
1331     }
1332     else
1333     {
1334         GLint samples                      = srcImage->getSamples();
1335         gl::TextureType stagingTextureType = vk::Get2DTextureType(layerCount, samples);
1336 
1337         // Create a temporary image to stage the copy
1338         std::unique_ptr<vk::RefCounted<vk::ImageHelper>> stagingImage;
1339         stagingImage = std::make_unique<vk::RefCounted<vk::ImageHelper>>();
1340 
1341         ANGLE_TRY(stagingImage->get().init2DStaging(
1342             contextVk, mState.hasProtectedContent(), renderer->getMemoryProperties(),
1343             gl::Extents(sourceBox.width, sourceBox.height, 1), dstFormat.getIntendedFormatID(),
1344             dstFormat.getActualImageFormatID(getRequiredImageAccess()), kDrawStagingImageFlags,
1345             layerCount));
1346 
1347         params.dstOffset[0] = 0;
1348         params.dstOffset[1] = 0;
1349 
1350         for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex)
1351         {
1352             params.srcLayer = layerIndex + sourceBox.z;
1353             params.dstLayer = layerIndex;
1354 
1355             // Create a temporary view for this layer.
1356             vk::ImageView stagingView;
1357             ANGLE_TRY(stagingImage->get().initLayerImageView(
1358                 contextVk, stagingTextureType, VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(),
1359                 &stagingView, vk::LevelIndex(0), 1, layerIndex, 1,
1360                 gl::SrgbWriteControlMode::Default, gl::YuvSamplingMode::Default,
1361                 vk::ImageHelper::kDefaultImageViewUsageFlags));
1362 
1363             ANGLE_TRY(utilsVk.copyImage(contextVk, &stagingImage->get(), &stagingView, srcImage,
1364                                         srcView, params));
1365 
1366             // Queue the resource for cleanup as soon as the copy above is finished.  There's no
1367             // need to keep it around.
1368             contextVk->addGarbage(&stagingView);
1369         }
1370 
1371         if (!isSrc3D)
1372         {
1373             // extents.depth should be set to layer count if any of the source or destination is a
1374             // 2D Array.  If both are 2D Array, it should be set to 1.
1375             extents.depth = 1;
1376         }
1377 
1378         gl::Offset dstOffsetModified = dstOffset;
1379         if (!isDest3D)
1380         {
1381             // If destination is not 3D, destination offset must be 0.
1382             dstOffsetModified.z = 0;
1383         }
1384 
1385         // Stage the copy for when the image storage is actually created.
1386         VkImageType imageType = gl_vk::GetImageType(mState.getType());
1387         const gl::ImageIndex stagingIndex =
1388             gl::ImageIndex::Make2DArrayRange(level.get(), baseLayer, layerCount);
1389         mImage->stageSubresourceUpdateFromImage(stagingImage.release(), stagingIndex,
1390                                                 vk::LevelIndex(0), dstOffsetModified, extents,
1391                                                 imageType);
1392     }
1393 
1394     return angle::Result::Continue;
1395 }
1396 
setStorage(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size)1397 angle::Result TextureVk::setStorage(const gl::Context *context,
1398                                     gl::TextureType type,
1399                                     size_t levels,
1400                                     GLenum internalFormat,
1401                                     const gl::Extents &size)
1402 {
1403     return setStorageMultisample(context, type, 1, internalFormat, size, true);
1404 }
1405 
setStorageMultisample(const gl::Context * context,gl::TextureType type,GLsizei samples,GLint internalformat,const gl::Extents & size,bool fixedSampleLocations)1406 angle::Result TextureVk::setStorageMultisample(const gl::Context *context,
1407                                                gl::TextureType type,
1408                                                GLsizei samples,
1409                                                GLint internalformat,
1410                                                const gl::Extents &size,
1411                                                bool fixedSampleLocations)
1412 {
1413     ContextVk *contextVk = GetAs<ContextVk>(context->getImplementation());
1414     RendererVk *renderer = contextVk->getRenderer();
1415 
1416     if (!mOwnsImage)
1417     {
1418         releaseAndDeleteImageAndViews(contextVk);
1419     }
1420     else if (mImage)
1421     {
1422         mImage->releaseStagedUpdates(contextVk->getRenderer());
1423     }
1424 
1425     // Assume all multisample texture types must be renderable.
1426     if (type == gl::TextureType::_2DMultisample || type == gl::TextureType::_2DMultisampleArray)
1427     {
1428         TextureUpdateResult updateResult = TextureUpdateResult::ImageUnaffected;
1429         ANGLE_TRY(ensureRenderable(contextVk, &updateResult));
1430     }
1431 
1432     const vk::Format &format = renderer->getFormat(internalformat);
1433     ANGLE_TRY(ensureImageAllocated(contextVk, format));
1434 
1435     if (mImage->valid())
1436     {
1437         releaseImage(contextVk);
1438     }
1439 
1440     ASSERT(mState.getImmutableFormat());
1441     ASSERT(!mRedefinedLevels.any());
1442     ANGLE_TRY(initImage(contextVk, format.getIntendedFormatID(),
1443                         format.getActualImageFormatID(getRequiredImageAccess()),
1444                         ImageMipLevels::FullMipChainForGenerateMipmap));
1445 
1446     return angle::Result::Continue;
1447 }
1448 
setStorageExternalMemory(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size,gl::MemoryObject * memoryObject,GLuint64 offset,GLbitfield createFlags,GLbitfield usageFlags,const void * imageCreateInfoPNext)1449 angle::Result TextureVk::setStorageExternalMemory(const gl::Context *context,
1450                                                   gl::TextureType type,
1451                                                   size_t levels,
1452                                                   GLenum internalFormat,
1453                                                   const gl::Extents &size,
1454                                                   gl::MemoryObject *memoryObject,
1455                                                   GLuint64 offset,
1456                                                   GLbitfield createFlags,
1457                                                   GLbitfield usageFlags,
1458                                                   const void *imageCreateInfoPNext)
1459 {
1460     ContextVk *contextVk           = vk::GetImpl(context);
1461     RendererVk *renderer           = contextVk->getRenderer();
1462     MemoryObjectVk *memoryObjectVk = vk::GetImpl(memoryObject);
1463 
1464     releaseAndDeleteImageAndViews(contextVk);
1465 
1466     const vk::Format &format = renderer->getFormat(internalFormat);
1467 
1468     setImageHelper(contextVk, new vk::ImageHelper(), gl::TextureType::InvalidEnum, format, 0, 0,
1469                    true, {});
1470 
1471     ANGLE_TRY(memoryObjectVk->createImage(contextVk, type, levels, internalFormat, size, offset,
1472                                           mImage, createFlags, usageFlags, imageCreateInfoPNext));
1473     mImageUsageFlags  = usageFlags;
1474     mImageCreateFlags = createFlags;
1475 
1476     constexpr VkImageUsageFlags kRenderableUsageFlags =
1477         kColorAttachmentImageFlags | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
1478     if ((usageFlags & kRenderableUsageFlags) != 0)
1479     {
1480         mRequiredImageAccess = vk::ImageAccess::Renderable;
1481     }
1482 
1483     ANGLE_TRY(initImageViews(contextVk, getImageViewLevelCount()));
1484 
1485     return angle::Result::Continue;
1486 }
1487 
handleImmutableSamplerTransition(const vk::ImageHelper * previousImage,const vk::ImageHelper * nextImage)1488 void TextureVk::handleImmutableSamplerTransition(const vk::ImageHelper *previousImage,
1489                                                  const vk::ImageHelper *nextImage)
1490 {
1491     // Did the previous image have an immutable sampler
1492     bool previousImageHadImmutableSampler =
1493         previousImage && previousImage->valid() && previousImage->hasImmutableSampler();
1494 
1495     // Does the next image require an immutable sampler?
1496     bool nextImageRequiresImmutableSampler =
1497         nextImage && nextImage->valid() && nextImage->hasImmutableSampler();
1498 
1499     // Has the external format changed?
1500     bool externalFormatChanged = false;
1501     if (previousImageHadImmutableSampler && nextImageRequiresImmutableSampler)
1502     {
1503         externalFormatChanged =
1504             previousImage->getExternalFormat() != nextImage->getExternalFormat();
1505     }
1506 
1507     // Handle transition of immutable sampler state
1508     if ((previousImageHadImmutableSampler != nextImageRequiresImmutableSampler) ||
1509         externalFormatChanged)
1510     {
1511         // The immutable sampler state is dirty.
1512         resetSampler();
1513         mImmutableSamplerDirty = true;
1514     }
1515 }
1516 
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)1517 angle::Result TextureVk::setEGLImageTarget(const gl::Context *context,
1518                                            gl::TextureType type,
1519                                            egl::Image *image)
1520 {
1521     ContextVk *contextVk = vk::GetImpl(context);
1522     RendererVk *renderer = contextVk->getRenderer();
1523     ImageVk *imageVk     = vk::GetImpl(image);
1524 
1525     // Early out if we are creating TextureVk with the exact same eglImage and target/face/level to
1526     // avoid unnecessarily dirty the state and allocating new ImageViews etc.
1527     if (mImage == imageVk->getImage() && mEGLImageNativeType == imageVk->getImageTextureType() &&
1528         static_cast<GLint>(mEGLImageLevelOffset) == imageVk->getImageLevel().get() &&
1529         mEGLImageLayerOffset == imageVk->getImageLayer())
1530     {
1531         return angle::Result::Continue;
1532     }
1533 
1534     ANGLE_TRY(contextVk->getShareGroup()->lockDefaultContextsPriority(contextVk));
1535 
1536     // TODO: Textures other than EGLImage targets can have immutable samplers.
1537     // http://anglebug.com/5773
1538     handleImmutableSamplerTransition(mImage, imageVk ? imageVk->getImage() : nullptr);
1539 
1540     releaseAndDeleteImageAndViews(contextVk);
1541 
1542     const vk::Format &format   = renderer->getFormat(image->getFormat().info->sizedInternalFormat);
1543     UniqueSerial siblingSerial = imageVk->generateSiblingSerial();
1544     setImageHelper(contextVk, imageVk->getImage(), imageVk->getImageTextureType(), format,
1545                    imageVk->getImageLevel().get(), imageVk->getImageLayer(), false, siblingSerial);
1546 
1547     ANGLE_TRY(initImageViews(contextVk, getImageViewLevelCount()));
1548 
1549     return angle::Result::Continue;
1550 }
1551 
setImageExternal(const gl::Context * context,gl::TextureType type,egl::Stream * stream,const egl::Stream::GLTextureDescription & desc)1552 angle::Result TextureVk::setImageExternal(const gl::Context *context,
1553                                           gl::TextureType type,
1554                                           egl::Stream *stream,
1555                                           const egl::Stream::GLTextureDescription &desc)
1556 {
1557     ANGLE_VK_UNREACHABLE(vk::GetImpl(context));
1558     return angle::Result::Stop;
1559 }
1560 
setBuffer(const gl::Context * context,GLenum internalFormat)1561 angle::Result TextureVk::setBuffer(const gl::Context *context, GLenum internalFormat)
1562 {
1563     // No longer an image
1564     releaseAndDeleteImageAndViews(vk::GetImpl(context));
1565     resetSampler();
1566 
1567     // There's nothing else to do here.
1568     return angle::Result::Continue;
1569 }
1570 
getNativeImageIndex(const gl::ImageIndex & inputImageIndex) const1571 gl::ImageIndex TextureVk::getNativeImageIndex(const gl::ImageIndex &inputImageIndex) const
1572 {
1573     if (mEGLImageNativeType == gl::TextureType::InvalidEnum)
1574     {
1575         return inputImageIndex;
1576     }
1577 
1578     // inputImageIndex can point to a specific layer, but only for non-2D textures.
1579     // mEGLImageNativeType can be a valid type, but only for 2D textures.
1580     // As such, both of these cannot be true at the same time.
1581     ASSERT(!inputImageIndex.hasLayer() && inputImageIndex.getLevelIndex() == 0);
1582 
1583     return gl::ImageIndex::MakeFromType(mEGLImageNativeType, mEGLImageLevelOffset,
1584                                         mEGLImageLayerOffset);
1585 }
1586 
getNativeImageLevel(gl::LevelIndex frontendLevel) const1587 gl::LevelIndex TextureVk::getNativeImageLevel(gl::LevelIndex frontendLevel) const
1588 {
1589     ASSERT(frontendLevel.get() == 0 || mEGLImageLevelOffset == 0);
1590     return frontendLevel + mEGLImageLevelOffset;
1591 }
1592 
getNativeImageLayer(uint32_t frontendLayer) const1593 uint32_t TextureVk::getNativeImageLayer(uint32_t frontendLayer) const
1594 {
1595     ASSERT(frontendLayer == 0 || mEGLImageLayerOffset == 0);
1596     return frontendLayer + mEGLImageLayerOffset;
1597 }
1598 
releaseAndDeleteImageAndViews(ContextVk * contextVk)1599 void TextureVk::releaseAndDeleteImageAndViews(ContextVk *contextVk)
1600 {
1601     if (mImage)
1602     {
1603         if (mOwnsImage)
1604         {
1605             releaseStagedUpdates(contextVk);
1606         }
1607         releaseImage(contextVk);
1608         mImageObserverBinding.bind(nullptr);
1609         mRequiresMutableStorage = false;
1610         mRequiredImageAccess    = vk::ImageAccess::SampleOnly;
1611         mImageCreateFlags       = 0;
1612         SafeDelete(mImage);
1613     }
1614 
1615     if (!contextVk->hasDisplayTextureShareGroup())
1616     {
1617         contextVk->getShareGroup()->onTextureRelease(this);
1618     }
1619 
1620     if (getBuffer().get() != nullptr)
1621     {
1622         mBufferContentsObservers->disableForBuffer(getBuffer().get());
1623     }
1624 
1625     if (mBufferViews.isInitialized())
1626     {
1627         mBufferViews.release(contextVk);
1628         onStateChange(angle::SubjectMessage::SubjectChanged);
1629     }
1630     mRedefinedLevels.reset();
1631     mDescriptorSetCacheManager.releaseKeys(contextVk);
1632 }
1633 
initImageUsageFlags(ContextVk * contextVk,angle::FormatID actualFormatID)1634 void TextureVk::initImageUsageFlags(ContextVk *contextVk, angle::FormatID actualFormatID)
1635 {
1636     ASSERT(actualFormatID != angle::FormatID::NONE);
1637 
1638     mImageUsageFlags = kTransferImageFlags | VK_IMAGE_USAGE_SAMPLED_BIT;
1639 
1640     // If the image has depth/stencil support, add those as possible usage.
1641     RendererVk *renderer = contextVk->getRenderer();
1642     if (angle::Format::Get(actualFormatID).hasDepthOrStencilBits())
1643     {
1644         // Work around a bug in the Mock ICD:
1645         // https://github.com/KhronosGroup/Vulkan-Tools/issues/445
1646         if (renderer->hasImageFormatFeatureBits(actualFormatID,
1647                                                 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT))
1648         {
1649             mImageUsageFlags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
1650         }
1651     }
1652     else if (renderer->hasImageFormatFeatureBits(actualFormatID,
1653                                                  VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT))
1654     {
1655         mImageUsageFlags |= kColorAttachmentImageFlags;
1656     }
1657 }
1658 
ensureImageAllocated(ContextVk * contextVk,const vk::Format & format)1659 angle::Result TextureVk::ensureImageAllocated(ContextVk *contextVk, const vk::Format &format)
1660 {
1661     if (mImage == nullptr)
1662     {
1663         setImageHelper(contextVk, new vk::ImageHelper(), gl::TextureType::InvalidEnum, format, 0, 0,
1664                        true, {});
1665     }
1666 
1667     initImageUsageFlags(contextVk, format.getActualImageFormatID(getRequiredImageAccess()));
1668 
1669     return angle::Result::Continue;
1670 }
1671 
setImageHelper(ContextVk * contextVk,vk::ImageHelper * imageHelper,gl::TextureType eglImageNativeType,const vk::Format & format,uint32_t imageLevelOffset,uint32_t imageLayerOffset,bool selfOwned,UniqueSerial siblingSerial)1672 void TextureVk::setImageHelper(ContextVk *contextVk,
1673                                vk::ImageHelper *imageHelper,
1674                                gl::TextureType eglImageNativeType,
1675                                const vk::Format &format,
1676                                uint32_t imageLevelOffset,
1677                                uint32_t imageLayerOffset,
1678                                bool selfOwned,
1679                                UniqueSerial siblingSerial)
1680 {
1681     ASSERT(mImage == nullptr);
1682 
1683     mImageObserverBinding.bind(imageHelper);
1684 
1685     ASSERT(selfOwned == !siblingSerial.valid());
1686     mOwnsImage          = selfOwned;
1687     mImageSiblingSerial = siblingSerial;
1688     // If image is shared between other container objects, force it to renderable format since we
1689     // don't know if other container object will render or not.
1690     if (!mOwnsImage)
1691     {
1692         mRequiredImageAccess = vk::ImageAccess::Renderable;
1693     }
1694     mEGLImageNativeType  = eglImageNativeType;
1695     mEGLImageLevelOffset = imageLevelOffset;
1696     mEGLImageLayerOffset = imageLayerOffset;
1697     mImage               = imageHelper;
1698 
1699     // Force re-creation of render targets next time they are needed
1700     for (auto &renderTargets : mSingleLayerRenderTargets)
1701     {
1702         for (RenderTargetVector &renderTargetLevels : renderTargets)
1703         {
1704             renderTargetLevels.clear();
1705         }
1706         renderTargets.clear();
1707     }
1708     mMultiLayerRenderTargets.clear();
1709 
1710     if (!selfOwned)
1711     {
1712         // (!selfOwned) implies that the texture is a target sibling.
1713         // Inherit a few VkImage's create attributes from ImageHelper.
1714         mImageCreateFlags       = mImage->getCreateFlags();
1715         mImageUsageFlags        = mImage->getUsage();
1716         mRequiresMutableStorage = (mImageCreateFlags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) != 0;
1717     }
1718 
1719     RendererVk *renderer = contextVk->getRenderer();
1720 
1721     getImageViews().init(renderer);
1722 }
1723 
redefineLevel(const gl::Context * context,const gl::ImageIndex & index,const vk::Format & format,const gl::Extents & size)1724 angle::Result TextureVk::redefineLevel(const gl::Context *context,
1725                                        const gl::ImageIndex &index,
1726                                        const vk::Format &format,
1727                                        const gl::Extents &size)
1728 {
1729     ContextVk *contextVk = vk::GetImpl(context);
1730 
1731     if (!mOwnsImage)
1732     {
1733         releaseAndDeleteImageAndViews(contextVk);
1734     }
1735 
1736     if (mImage != nullptr)
1737     {
1738         // If there are any staged changes for this index, we can remove them since we're going to
1739         // override them with this call.
1740         gl::LevelIndex levelIndexGL(index.getLevelIndex());
1741         uint32_t layerIndex = index.hasLayer() ? index.getLayerIndex() : 0;
1742         if (gl::IsArrayTextureType(index.getType()))
1743         {
1744             // A multi-layer texture is being redefined, remove all updates to this level; the
1745             // number of layers may have changed.
1746             mImage->removeStagedUpdates(contextVk, levelIndexGL, levelIndexGL);
1747         }
1748         else
1749         {
1750             // Otherwise remove only updates to this layer.  For example, cube map updates can be
1751             // done through glTexImage2D, one per cube face (i.e. layer) and so should not remove
1752             // updates to the other layers.
1753             ASSERT(index.getLayerCount() == 1);
1754             mImage->removeSingleSubresourceStagedUpdates(contextVk, levelIndexGL, layerIndex,
1755                                                          index.getLayerCount());
1756         }
1757 
1758         if (mImage->valid())
1759         {
1760             // If the level that's being redefined is outside the level range of the allocated
1761             // image, the application is free to use any size or format.  Any data uploaded to it
1762             // will live in staging area until the texture base/max level is adjusted to include
1763             // this level, at which point the image will be recreated.
1764             //
1765             // Otherwise, if the level that's being redefined has a different format or size,
1766             // only release the image if it's single-mip, and keep the uploaded data staged.
1767             // Otherwise the image is mip-incomplete anyway and will be eventually recreated when
1768             // needed.  Only exception to this latter is if all the levels of the texture are
1769             // redefined such that the image becomes mip-complete in the end.
1770             // mRedefinedLevels is used during syncState to support this use-case.
1771             //
1772             // Note that if the image has multiple mips, there could be a copy from one mip
1773             // happening to the other, which means the image cannot be released.
1774             //
1775             // In summary:
1776             //
1777             // - If the image has a single level, and that level is being redefined, release the
1778             //   image.
1779             // - Otherwise keep the image intact (another mip may be the source of a copy), and
1780             //   make sure any updates to this level are staged.
1781             bool isInAllocatedImage = IsTextureLevelInAllocatedImage(*mImage, levelIndexGL);
1782             bool isCompatibleRedefinition =
1783                 isInAllocatedImage && IsTextureLevelDefinitionCompatibleWithImage(
1784                                           *mImage, levelIndexGL, size, format.getIntendedFormatID(),
1785                                           format.getActualImageFormatID(getRequiredImageAccess()));
1786 
1787             // Mark the level as incompatibly redefined if that's the case.  Note that if the level
1788             // was previously incompatibly defined, then later redefined to be compatible, the
1789             // corresponding bit should clear.
1790             if (isInAllocatedImage)
1791             {
1792                 // Immutable texture should never have levels redefined.
1793                 ASSERT(isCompatibleRedefinition || !mState.getImmutableFormat());
1794                 mRedefinedLevels.set(levelIndexGL.get(), !isCompatibleRedefinition);
1795             }
1796 
1797             bool isUpdateToSingleLevelImage =
1798                 mImage->getLevelCount() == 1 && mImage->getFirstAllocatedLevel() == levelIndexGL;
1799 
1800             // If incompatible, and redefining the single-level image, release it so it can be
1801             // recreated immediately.  This is an optimization to avoid an extra copy.
1802             if (!isCompatibleRedefinition && isUpdateToSingleLevelImage)
1803             {
1804                 releaseImage(contextVk);
1805             }
1806         }
1807     }
1808 
1809     // If image is not released due to an out-of-range or incompatible level definition, the image
1810     // is still valid and we shouldn't redefine it to use the new format.  In that case,
1811     // ensureImageAllocated will only use the format to update the staging buffer's alignment to
1812     // support both the previous and the new formats.
1813     ANGLE_TRY(ensureImageAllocated(contextVk, format));
1814 
1815     return angle::Result::Continue;
1816 }
1817 
copyImageDataToBufferAndGetData(ContextVk * contextVk,gl::LevelIndex sourceLevelGL,uint32_t layerCount,const gl::Box & sourceArea,RenderPassClosureReason reason,vk::BufferHelper * copyBuffer,uint8_t ** outDataPtr)1818 angle::Result TextureVk::copyImageDataToBufferAndGetData(ContextVk *contextVk,
1819                                                          gl::LevelIndex sourceLevelGL,
1820                                                          uint32_t layerCount,
1821                                                          const gl::Box &sourceArea,
1822                                                          RenderPassClosureReason reason,
1823                                                          vk::BufferHelper *copyBuffer,
1824                                                          uint8_t **outDataPtr)
1825 {
1826     ANGLE_TRACE_EVENT0("gpu.angle", "TextureVk::copyImageDataToBufferAndGetData");
1827 
1828     // Make sure the source is initialized and it's images are flushed.
1829     ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
1830 
1831     gl::Box modifiedSourceArea = sourceArea;
1832 
1833     bool is3D = mImage->getExtents().depth > 1;
1834     if (is3D)
1835     {
1836         layerCount = 1;
1837     }
1838     else
1839     {
1840         modifiedSourceArea.depth = 1;
1841     }
1842 
1843     ANGLE_TRY(mImage->copyImageDataToBuffer(contextVk, sourceLevelGL, layerCount, 0,
1844                                             modifiedSourceArea, copyBuffer, outDataPtr));
1845 
1846     // Explicitly finish. If new use cases arise where we don't want to block we can change this.
1847     ANGLE_TRY(contextVk->finishImpl(reason));
1848 
1849     return angle::Result::Continue;
1850 }
1851 
copyBufferDataToImage(ContextVk * contextVk,vk::BufferHelper * srcBuffer,const gl::ImageIndex index,uint32_t rowLength,uint32_t imageHeight,const gl::Box & sourceArea,size_t offset,VkImageAspectFlags aspectFlags)1852 angle::Result TextureVk::copyBufferDataToImage(ContextVk *contextVk,
1853                                                vk::BufferHelper *srcBuffer,
1854                                                const gl::ImageIndex index,
1855                                                uint32_t rowLength,
1856                                                uint32_t imageHeight,
1857                                                const gl::Box &sourceArea,
1858                                                size_t offset,
1859                                                VkImageAspectFlags aspectFlags)
1860 {
1861     ANGLE_TRACE_EVENT0("gpu.angle", "TextureVk::copyBufferDataToImage");
1862 
1863     // Vulkan Spec requires the bufferOffset to be a multiple of pixel size for
1864     // vkCmdCopyBufferToImage.
1865     ASSERT((offset % vk::GetImageCopyBufferAlignment(mImage->getActualFormatID())) == 0);
1866 
1867     gl::LevelIndex level = gl::LevelIndex(index.getLevelIndex());
1868     GLuint layerCount    = index.getLayerCount();
1869     GLuint layerIndex    = 0;
1870 
1871     ASSERT((aspectFlags & kDepthStencilAspects) != kDepthStencilAspects);
1872 
1873     VkBufferImageCopy region           = {};
1874     region.bufferOffset                = offset;
1875     region.bufferRowLength             = rowLength;
1876     region.bufferImageHeight           = imageHeight;
1877     region.imageExtent.width           = sourceArea.width;
1878     region.imageExtent.height          = sourceArea.height;
1879     region.imageExtent.depth           = sourceArea.depth;
1880     region.imageOffset.x               = sourceArea.x;
1881     region.imageOffset.y               = sourceArea.y;
1882     region.imageOffset.z               = sourceArea.z;
1883     region.imageSubresource.aspectMask = aspectFlags;
1884     region.imageSubresource.layerCount = layerCount;
1885     region.imageSubresource.mipLevel   = mImage->toVkLevel(level).get();
1886 
1887     if (gl::IsArrayTextureType(index.getType()))
1888     {
1889         layerIndex               = sourceArea.z;
1890         region.imageOffset.z     = 0;
1891         region.imageExtent.depth = 1;
1892     }
1893     else if (index.getType() == gl::TextureType::CubeMap)
1894     {
1895         // Copy to the correct cube map face.
1896         layerIndex = index.getLayerIndex();
1897     }
1898     region.imageSubresource.baseArrayLayer = layerIndex;
1899 
1900     // Make sure the source is initialized and its images are flushed.
1901     ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
1902 
1903     vk::CommandBufferAccess access;
1904     access.onBufferTransferRead(srcBuffer);
1905     access.onImageTransferWrite(level, 1, layerIndex, layerCount, mImage->getAspectFlags(), mImage);
1906 
1907     vk::OutsideRenderPassCommandBuffer *commandBuffer;
1908     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
1909 
1910     commandBuffer->copyBufferToImage(srcBuffer->getBuffer().getHandle(), mImage->getImage(),
1911                                      mImage->getCurrentLayout(contextVk), 1, &region);
1912 
1913     return angle::Result::Continue;
1914 }
1915 
generateMipmapsWithCompute(ContextVk * contextVk)1916 angle::Result TextureVk::generateMipmapsWithCompute(ContextVk *contextVk)
1917 {
1918     RendererVk *renderer = contextVk->getRenderer();
1919 
1920     // Requires that the image:
1921     //
1922     // - is not sRGB
1923     // - is not integer
1924     // - is 2D or 2D array
1925     // - is single sample
1926     // - is color image
1927     //
1928     // Support for the first two can be added easily.  Supporting 3D textures, MSAA and
1929     // depth/stencil would be more involved.
1930     ASSERT(!mImage->getActualFormat().isSRGB);
1931     ASSERT(!mImage->getActualFormat().isInt());
1932     ASSERT(mImage->getType() == VK_IMAGE_TYPE_2D);
1933     ASSERT(mImage->getSamples() == 1);
1934     ASSERT(mImage->getAspectFlags() == VK_IMAGE_ASPECT_COLOR_BIT);
1935 
1936     // Create the appropriate sampler.
1937     GLenum filter = CalculateGenerateMipmapFilter(contextVk, mImage->getActualFormatID());
1938 
1939     gl::SamplerState samplerState;
1940     samplerState.setMinFilter(filter);
1941     samplerState.setMagFilter(filter);
1942     samplerState.setWrapS(GL_CLAMP_TO_EDGE);
1943     samplerState.setWrapT(GL_CLAMP_TO_EDGE);
1944     samplerState.setWrapR(GL_CLAMP_TO_EDGE);
1945 
1946     vk::BindingPointer<vk::SamplerHelper> sampler;
1947     vk::SamplerDesc samplerDesc(contextVk, samplerState, false, nullptr,
1948                                 static_cast<angle::FormatID>(0));
1949     ANGLE_TRY(renderer->getSamplerCache().getSampler(contextVk, samplerDesc, &sampler));
1950 
1951     // If the image has more levels than supported, generate as many mips as possible at a time.
1952     const vk::LevelIndex maxGenerateLevels(UtilsVk::GetGenerateMipmapMaxLevels(contextVk));
1953     vk::LevelIndex dstMaxLevelVk = mImage->toVkLevel(gl::LevelIndex(mState.getMipmapMaxLevel()));
1954     for (vk::LevelIndex dstBaseLevelVk =
1955              mImage->toVkLevel(gl::LevelIndex(mState.getEffectiveBaseLevel() + 1));
1956          dstBaseLevelVk <= dstMaxLevelVk; dstBaseLevelVk = dstBaseLevelVk + maxGenerateLevels.get())
1957     {
1958         vk::CommandBufferAccess access;
1959 
1960         uint32_t writeLevelCount =
1961             std::min(maxGenerateLevels.get(), dstMaxLevelVk.get() + 1 - dstBaseLevelVk.get());
1962         access.onImageComputeShaderWrite(mImage->toGLLevel(dstBaseLevelVk), writeLevelCount, 0,
1963                                          mImage->getLayerCount(), VK_IMAGE_ASPECT_COLOR_BIT,
1964                                          mImage);
1965 
1966         vk::OutsideRenderPassCommandBuffer *commandBuffer;
1967         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
1968 
1969         // Generate mipmaps for every layer separately.
1970         for (uint32_t layer = 0; layer < mImage->getLayerCount(); ++layer)
1971         {
1972             // Create the necessary views.
1973             const vk::ImageView *srcView                         = nullptr;
1974             UtilsVk::GenerateMipmapDestLevelViews destLevelViews = {};
1975 
1976             const vk::LevelIndex srcLevelVk = dstBaseLevelVk - 1;
1977             ANGLE_TRY(getImageViews().getLevelLayerDrawImageView(
1978                 contextVk, *mImage, srcLevelVk, layer, gl::SrgbWriteControlMode::Default,
1979                 &srcView));
1980 
1981             vk::LevelIndex dstLevelCount = maxGenerateLevels;
1982             for (vk::LevelIndex levelVk(0); levelVk < maxGenerateLevels; ++levelVk)
1983             {
1984                 vk::LevelIndex dstLevelVk = dstBaseLevelVk + levelVk.get();
1985 
1986                 // If fewer levels left than maxGenerateLevels, cut the loop short.
1987                 if (dstLevelVk > dstMaxLevelVk)
1988                 {
1989                     dstLevelCount = levelVk;
1990                     break;
1991                 }
1992 
1993                 ANGLE_TRY(getImageViews().getLevelLayerDrawImageView(
1994                     contextVk, *mImage, dstLevelVk, layer, gl::SrgbWriteControlMode::Default,
1995                     &destLevelViews[levelVk.get()]));
1996             }
1997 
1998             // If the image has fewer than maximum levels, fill the last views with a unused view.
1999             ASSERT(dstLevelCount > vk::LevelIndex(0));
2000             for (vk::LevelIndex levelVk = dstLevelCount;
2001                  levelVk < vk::LevelIndex(UtilsVk::kGenerateMipmapMaxLevels); ++levelVk)
2002             {
2003                 destLevelViews[levelVk.get()] = destLevelViews[levelVk.get() - 1];
2004             }
2005 
2006             // Generate mipmaps.
2007             UtilsVk::GenerateMipmapParameters params = {};
2008             params.srcLevel                          = srcLevelVk.get();
2009             params.dstLevelCount                     = dstLevelCount.get();
2010 
2011             ANGLE_TRY(contextVk->getUtils().generateMipmap(
2012                 contextVk, mImage, srcView, mImage, destLevelViews, sampler.get().get(), params));
2013         }
2014     }
2015 
2016     return angle::Result::Continue;
2017 }
2018 
generateMipmapsWithCPU(const gl::Context * context)2019 angle::Result TextureVk::generateMipmapsWithCPU(const gl::Context *context)
2020 {
2021     ContextVk *contextVk = vk::GetImpl(context);
2022 
2023     gl::LevelIndex baseLevelGL(mState.getEffectiveBaseLevel());
2024     vk::LevelIndex baseLevelVk         = mImage->toVkLevel(baseLevelGL);
2025     const gl::Extents baseLevelExtents = mImage->getLevelExtents(baseLevelVk);
2026     uint32_t imageLayerCount           = mImage->getLayerCount();
2027 
2028     uint8_t *imageData = nullptr;
2029     gl::Box imageArea(0, 0, 0, baseLevelExtents.width, baseLevelExtents.height,
2030                       baseLevelExtents.depth);
2031 
2032     vk::RendererScoped<vk::BufferHelper> bufferHelper(contextVk->getRenderer());
2033     ANGLE_TRY(copyImageDataToBufferAndGetData(contextVk, baseLevelGL, imageLayerCount, imageArea,
2034                                               RenderPassClosureReason::GenerateMipmapOnCPU,
2035                                               &bufferHelper.get(), &imageData));
2036 
2037     const angle::Format &angleFormat = mImage->getActualFormat();
2038     GLuint sourceRowPitch            = baseLevelExtents.width * angleFormat.pixelBytes;
2039     GLuint sourceDepthPitch          = sourceRowPitch * baseLevelExtents.height;
2040     size_t baseLevelAllocationSize   = sourceDepthPitch * baseLevelExtents.depth;
2041 
2042     // We now have the base level available to be manipulated in the imageData pointer. Generate all
2043     // the missing mipmaps with the slow path. For each layer, use the copied data to generate all
2044     // the mips.
2045     for (GLuint layer = 0; layer < imageLayerCount; layer++)
2046     {
2047         size_t bufferOffset = layer * baseLevelAllocationSize;
2048 
2049         ANGLE_TRY(generateMipmapLevelsWithCPU(contextVk, angleFormat, layer, baseLevelGL + 1,
2050                                               gl::LevelIndex(mState.getMipmapMaxLevel()),
2051                                               baseLevelExtents.width, baseLevelExtents.height,
2052                                               baseLevelExtents.depth, sourceRowPitch,
2053                                               sourceDepthPitch, imageData + bufferOffset));
2054     }
2055 
2056     ASSERT(!mRedefinedLevels.any());
2057     return flushImageStagedUpdates(contextVk);
2058 }
2059 
generateMipmap(const gl::Context * context)2060 angle::Result TextureVk::generateMipmap(const gl::Context *context)
2061 {
2062     ContextVk *contextVk = vk::GetImpl(context);
2063     RendererVk *renderer = contextVk->getRenderer();
2064 
2065     // The image should already be allocated by a prior syncState.
2066     ASSERT(mImage->valid());
2067 
2068     // If base level has changed, the front-end should have called syncState already.
2069     ASSERT(mState.getImmutableFormat() ||
2070            mImage->getFirstAllocatedLevel() == gl::LevelIndex(mState.getEffectiveBaseLevel()));
2071 
2072     // Only staged update here is the robust resource init if any.
2073     ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::FullMipChainForGenerateMipmap));
2074 
2075     vk::LevelIndex baseLevel = mImage->toVkLevel(gl::LevelIndex(mState.getEffectiveBaseLevel()));
2076     vk::LevelIndex maxLevel  = mImage->toVkLevel(gl::LevelIndex(mState.getMipmapMaxLevel()));
2077     ASSERT(maxLevel != vk::LevelIndex(0));
2078 
2079     // If it's possible to generate mipmap in compute, that would give the best possible
2080     // performance on some hardware.
2081     if (CanGenerateMipmapWithCompute(renderer, mImage->getType(), mImage->getActualFormatID(),
2082                                      mImage->getSamples(), mOwnsImage))
2083     {
2084         ASSERT((mImageUsageFlags & VK_IMAGE_USAGE_STORAGE_BIT) != 0);
2085         return generateMipmapsWithCompute(contextVk);
2086     }
2087     else if (renderer->hasImageFormatFeatureBits(mImage->getActualFormatID(), kBlitFeatureFlags))
2088     {
2089         // Otherwise, use blit if possible.
2090         return mImage->generateMipmapsWithBlit(contextVk, baseLevel, maxLevel);
2091     }
2092 
2093     ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_HIGH,
2094                           "Mipmap generated on CPU due to format restrictions");
2095 
2096     // If not possible to generate mipmaps on the GPU, do it on the CPU for conformance.
2097     return generateMipmapsWithCPU(context);
2098 }
2099 
setBaseLevel(const gl::Context * context,GLuint baseLevel)2100 angle::Result TextureVk::setBaseLevel(const gl::Context *context, GLuint baseLevel)
2101 {
2102     return angle::Result::Continue;
2103 }
2104 
maybeUpdateBaseMaxLevels(ContextVk * contextVk,TextureUpdateResult * updateResultOut)2105 angle::Result TextureVk::maybeUpdateBaseMaxLevels(ContextVk *contextVk,
2106                                                   TextureUpdateResult *updateResultOut)
2107 {
2108     if (!mImage)
2109     {
2110         return angle::Result::Continue;
2111     }
2112 
2113     bool baseLevelChanged = mCurrentBaseLevel.get() != static_cast<GLint>(mState.getBaseLevel());
2114     bool maxLevelChanged  = mCurrentMaxLevel.get() != static_cast<GLint>(mState.getMaxLevel());
2115 
2116     if (!maxLevelChanged && !baseLevelChanged)
2117     {
2118         return angle::Result::Continue;
2119     }
2120 
2121     gl::LevelIndex newBaseLevel = gl::LevelIndex(mState.getEffectiveBaseLevel());
2122     gl::LevelIndex newMaxLevel  = gl::LevelIndex(mState.getEffectiveMaxLevel());
2123     ASSERT(newBaseLevel <= newMaxLevel);
2124 
2125     if (!mImage->valid())
2126     {
2127         // No further work to do, let staged updates handle the new levels
2128         return angle::Result::Continue;
2129     }
2130 
2131     if (mState.getImmutableFormat())
2132     {
2133         // For immutable texture, baseLevel/maxLevel should be a subset of the texture's actual
2134         // number of mip levels. We don't need to respecify an image.
2135         ASSERT(!baseLevelChanged || newBaseLevel >= mImage->getFirstAllocatedLevel());
2136         ASSERT(!maxLevelChanged || newMaxLevel < gl::LevelIndex(mImage->getLevelCount()));
2137     }
2138     else if (!baseLevelChanged && (newMaxLevel <= mImage->getLastAllocatedLevel()))
2139     {
2140         // With a valid image, check if only changing the maxLevel to a subset of the texture's
2141         // actual number of mip levels
2142         ASSERT(maxLevelChanged);
2143     }
2144     else
2145     {
2146         *updateResultOut = TextureUpdateResult::ImageRespecified;
2147         return respecifyImageStorage(contextVk);
2148     }
2149 
2150     // Don't need to respecify the texture; but do need to update which vkImageView's are served up
2151     // by ImageViewHelper
2152 
2153     // Update the current max level in ImageViewHelper
2154     ANGLE_TRY(initImageViews(contextVk, newMaxLevel - newBaseLevel + 1));
2155 
2156     mCurrentBaseLevel = newBaseLevel;
2157     mCurrentMaxLevel  = newMaxLevel;
2158 
2159     return angle::Result::Continue;
2160 }
2161 
copyAndStageImageData(ContextVk * contextVk,gl::LevelIndex previousFirstAllocateLevel,vk::ImageHelper * srcImage,vk::ImageHelper * dstImage)2162 angle::Result TextureVk::copyAndStageImageData(ContextVk *contextVk,
2163                                                gl::LevelIndex previousFirstAllocateLevel,
2164                                                vk::ImageHelper *srcImage,
2165                                                vk::ImageHelper *dstImage)
2166 {
2167     // Preserve the data in the Vulkan image.  GL texture's staged updates that correspond to
2168     // levels outside the range of the Vulkan image will remain intact.
2169     RendererVk *renderer = contextVk->getRenderer();
2170 
2171     // This path is only called when switching from !owned to owned, in which case if any level was
2172     // redefined it's already released and deleted by TextureVk::redefineLevel().
2173     ASSERT(!mRedefinedLevels.any());
2174 
2175     // Create a temp copy of srcImage for staging.
2176     std::unique_ptr<vk::RefCounted<vk::ImageHelper>> stagingImage;
2177     stagingImage = std::make_unique<vk::RefCounted<vk::ImageHelper>>();
2178 
2179     const uint32_t levelCount = srcImage->getLevelCount();
2180     const uint32_t layerCount = srcImage->getLayerCount();
2181 
2182     ANGLE_TRY(stagingImage->get().initStaging(
2183         contextVk, mState.hasProtectedContent(), renderer->getMemoryProperties(),
2184         srcImage->getType(), srcImage->getExtents(), srcImage->getIntendedFormatID(),
2185         srcImage->getActualFormatID(), srcImage->getSamples(), kTransferImageFlags, levelCount,
2186         layerCount));
2187 
2188     // Copy the src image wholly into the staging image
2189     const VkImageAspectFlags aspectFlags = srcImage->getAspectFlags();
2190 
2191     vk::CommandBufferAccess access;
2192     access.onImageTransferWrite(gl::LevelIndex(0), levelCount, 0, layerCount, aspectFlags,
2193                                 &stagingImage->get());
2194     access.onImageTransferRead(aspectFlags, srcImage);
2195 
2196     vk::OutsideRenderPassCommandBuffer *commandBuffer;
2197     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
2198 
2199     VkImageCopy copyRegion               = {};
2200     copyRegion.srcSubresource.aspectMask = aspectFlags;
2201     copyRegion.srcSubresource.layerCount = layerCount;
2202     copyRegion.dstSubresource            = copyRegion.srcSubresource;
2203 
2204     for (vk::LevelIndex levelVk(0); levelVk < vk::LevelIndex(levelCount); ++levelVk)
2205     {
2206         gl::Extents levelExtents = srcImage->getLevelExtents(levelVk);
2207 
2208         copyRegion.srcSubresource.mipLevel = levelVk.get();
2209         copyRegion.dstSubresource.mipLevel = levelVk.get();
2210         gl_vk::GetExtent(levelExtents, &copyRegion.extent);
2211 
2212         commandBuffer->copyImage(srcImage->getImage(), srcImage->getCurrentLayout(contextVk),
2213                                  stagingImage->get().getImage(),
2214                                  stagingImage->get().getCurrentLayout(contextVk), 1, &copyRegion);
2215     }
2216 
2217     // Stage the staging image in the destination
2218     dstImage->stageSubresourceUpdatesFromAllImageLevels(stagingImage.release(),
2219                                                         previousFirstAllocateLevel);
2220 
2221     return angle::Result::Continue;
2222 }
2223 
reinitImageAsRenderable(ContextVk * contextVk,const vk::Format & format,gl::TexLevelMask skipLevelsMask)2224 angle::Result TextureVk::reinitImageAsRenderable(ContextVk *contextVk,
2225                                                  const vk::Format &format,
2226                                                  gl::TexLevelMask skipLevelsMask)
2227 {
2228     ASSERT(mImage->valid());
2229     RendererVk *renderer = contextVk->getRenderer();
2230 
2231     const uint32_t levelCount = mImage->getLevelCount();
2232     const uint32_t layerCount = mImage->getLayerCount();
2233 
2234     // Nothing to do if every level must be skipped
2235     gl::TexLevelMask levelsMask(angle::BitMask<uint32_t>(levelCount)
2236                                 << mImage->getFirstAllocatedLevel().get());
2237     if ((~skipLevelsMask & levelsMask).none())
2238     {
2239         return angle::Result::Continue;
2240     }
2241 
2242     // Make sure the source is initialized and its staged updates are flushed.
2243     ANGLE_TRY(flushImageStagedUpdates(contextVk));
2244 
2245     const angle::Format &srcFormat = mImage->getActualFormat();
2246     const angle::Format &dstFormat = format.getActualImageFormat(getRequiredImageAccess());
2247 
2248     // If layerCount or levelCount is bigger than 1, we go for the slow path for now. The problem
2249     // with draw path is that in the multiple level/layer case, we have to do copy in a loop.
2250     // Currently copySubImageImplWithDraw() calls ensureImageInitalized which forces flush out
2251     // staged updates that we just staged inside the loop which is wrong.
2252     if (levelCount == 1 && layerCount == 1)
2253     {
2254         ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_LOW,
2255                               "Copying image data due to texture format fallback");
2256 
2257         ASSERT(CanCopyWithDraw(renderer, mImage->getActualFormatID(), mImage->getTilingMode(),
2258                                format.getActualImageFormatID(getRequiredImageAccess()),
2259                                getTilingMode()));
2260         vk::LevelIndex levelVk(0);
2261         gl::LevelIndex sourceLevelGL = mImage->toGLLevel(levelVk);
2262         gl::Box sourceBox(gl::kOffsetZero, mImage->getLevelExtents(levelVk));
2263         const gl::ImageIndex index =
2264             gl::ImageIndex::MakeFromType(mState.getType(), sourceLevelGL.get());
2265 
2266         // Flush the render pass, which may incur a vkQueueSubmit, before taking any views.
2267         // Otherwise the view serials would not reflect the render pass they are really used in.
2268         // http://crbug.com/1272266#c22
2269         ANGLE_TRY(
2270             contextVk->flushCommandsAndEndRenderPass(RenderPassClosureReason::PrepareForImageCopy));
2271 
2272         return copySubImageImplWithDraw(contextVk, index, gl::kOffsetZero, format, sourceLevelGL,
2273                                         sourceBox, false, false, false, false, mImage,
2274                                         &getCopyImageView(), SurfaceRotation::Identity);
2275     }
2276 
2277     for (vk::LevelIndex levelVk(0); levelVk < vk::LevelIndex(levelCount); ++levelVk)
2278     {
2279         gl::LevelIndex levelGL = mImage->toGLLevel(levelVk);
2280         if (skipLevelsMask.test(levelGL.get()))
2281         {
2282             continue;
2283         }
2284 
2285         ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_HIGH,
2286                               "GPU stall due to texture format fallback");
2287 
2288         gl::Box sourceBox(gl::kOffsetZero, mImage->getLevelExtents(levelVk));
2289         // copy and stage entire layer
2290         const gl::ImageIndex index =
2291             gl::ImageIndex::MakeFromType(mState.getType(), levelGL.get(), 0, layerCount);
2292 
2293         // Read back the requested region of the source texture
2294         vk::RendererScoped<vk::BufferHelper> bufferHelper(renderer);
2295         vk::BufferHelper *srcBuffer = &bufferHelper.get();
2296         uint8_t *srcData            = nullptr;
2297         ANGLE_TRY(mImage->copyImageDataToBuffer(contextVk, levelGL, layerCount, 0, sourceBox,
2298                                                 srcBuffer, &srcData));
2299 
2300         // Explicitly finish. If new use cases arise where we don't want to block we can change
2301         // this.
2302         ANGLE_TRY(contextVk->finishImpl(RenderPassClosureReason::TextureReformatToRenderable));
2303 
2304         size_t dstBufferSize = sourceBox.width * sourceBox.height * sourceBox.depth *
2305                                dstFormat.pixelBytes * layerCount;
2306 
2307         // Allocate memory in the destination texture for the copy/conversion.
2308         uint8_t *dstData = nullptr;
2309         ANGLE_TRY(mImage->stageSubresourceUpdateAndGetData(
2310             contextVk, dstBufferSize, index, mImage->getLevelExtents(levelVk), gl::kOffsetZero,
2311             &dstData, dstFormat.id));
2312 
2313         // Source and destination data is tightly packed
2314         GLuint srcDataRowPitch = sourceBox.width * srcFormat.pixelBytes;
2315         GLuint dstDataRowPitch = sourceBox.width * dstFormat.pixelBytes;
2316 
2317         GLuint srcDataDepthPitch = srcDataRowPitch * sourceBox.height;
2318         GLuint dstDataDepthPitch = dstDataRowPitch * sourceBox.height;
2319 
2320         GLuint srcDataLayerPitch = srcDataDepthPitch * sourceBox.depth;
2321         GLuint dstDataLayerPitch = dstDataDepthPitch * sourceBox.depth;
2322 
2323         rx::PixelReadFunction pixelReadFunction   = srcFormat.pixelReadFunction;
2324         rx::PixelWriteFunction pixelWriteFunction = dstFormat.pixelWriteFunction;
2325 
2326         const gl::InternalFormat &dstFormatInfo = *mState.getImageDesc(index).format.info;
2327         for (uint32_t layer = 0; layer < layerCount; layer++)
2328         {
2329             CopyImageCHROMIUM(srcData + layer * srcDataLayerPitch, srcDataRowPitch,
2330                               srcFormat.pixelBytes, srcDataDepthPitch, pixelReadFunction,
2331                               dstData + layer * dstDataLayerPitch, dstDataRowPitch,
2332                               dstFormat.pixelBytes, dstDataDepthPitch, pixelWriteFunction,
2333                               dstFormatInfo.format, dstFormatInfo.componentType, sourceBox.width,
2334                               sourceBox.height, sourceBox.depth, false, false, false);
2335         }
2336     }
2337 
2338     return angle::Result::Continue;
2339 }
2340 
respecifyImageStorage(ContextVk * contextVk)2341 angle::Result TextureVk::respecifyImageStorage(ContextVk *contextVk)
2342 {
2343     if (!mImage->valid())
2344     {
2345         ASSERT(!mRedefinedLevels.any());
2346         return angle::Result::Continue;
2347     }
2348 
2349     // Recreate the image to reflect new base or max levels.
2350     // First, flush any pending updates so we have good data in the current mImage
2351     if (mImage->hasStagedUpdatesInAllocatedLevels())
2352     {
2353         ANGLE_TRY(flushImageStagedUpdates(contextVk));
2354     }
2355 
2356     if (!mOwnsImage)
2357     {
2358         // Cache values needed for copy and stage operations
2359         vk::ImageHelper *srcImage = mImage;
2360         const vk::Format &format  = getBaseLevelFormat(contextVk->getRenderer());
2361 
2362         // If any level was redefined but the image was not owned by the Texture, it's already
2363         // released and deleted by TextureVk::redefineLevel().
2364         ASSERT(!mRedefinedLevels.any());
2365 
2366         // Save previousFirstAllocateLevel before mImage becomes invalid
2367         gl::LevelIndex previousFirstAllocateLevel = mImage->getFirstAllocatedLevel();
2368 
2369         // If we didn't own the image, release the current and create a new one
2370         releaseImage(contextVk);
2371 
2372         // Create the image helper
2373         ANGLE_TRY(ensureImageAllocated(contextVk, format));
2374         ANGLE_TRY(initImage(contextVk, format.getIntendedFormatID(),
2375                             format.getActualImageFormatID(getRequiredImageAccess()),
2376                             mState.getImmutableFormat()
2377                                 ? ImageMipLevels::FullMipChainForGenerateMipmap
2378                                 : ImageMipLevels::EnabledLevels));
2379 
2380         // Make a copy of the old image (that's being released) and stage that as an update to the
2381         // new image.
2382         ANGLE_TRY(copyAndStageImageData(contextVk, previousFirstAllocateLevel, srcImage, mImage));
2383     }
2384     else
2385     {
2386         const vk::Format &format = getBaseLevelFormat(contextVk->getRenderer());
2387         if (mImage->getActualFormatID() != format.getActualImageFormatID(getRequiredImageAccess()))
2388         {
2389             ANGLE_TRY(reinitImageAsRenderable(contextVk, format, mRedefinedLevels));
2390         }
2391         else
2392         {
2393             stageSelfAsSubresourceUpdates(contextVk);
2394         }
2395         // Release the current image so that it will be recreated with the correct number of mip
2396         // levels, base level, and max level.
2397         releaseImage(contextVk);
2398     }
2399 
2400     return angle::Result::Continue;
2401 }
2402 
bindTexImage(const gl::Context * context,egl::Surface * surface)2403 angle::Result TextureVk::bindTexImage(const gl::Context *context, egl::Surface *surface)
2404 {
2405     ContextVk *contextVk = vk::GetImpl(context);
2406     RendererVk *renderer = contextVk->getRenderer();
2407 
2408     releaseAndDeleteImageAndViews(contextVk);
2409 
2410     const gl::InternalFormat &glInternalFormat = *surface->getBindTexImageFormat().info;
2411     const vk::Format &format = renderer->getFormat(glInternalFormat.sizedInternalFormat);
2412 
2413     // eglBindTexImage can only be called with pbuffer (offscreen) surfaces
2414     OffscreenSurfaceVk *offscreenSurface = GetImplAs<OffscreenSurfaceVk>(surface);
2415     // Surface can only have single target. Just generate valid serial with throw-away generator.
2416     UniqueSerial siblingSerial = UniqueSerialFactory().generate();
2417     setImageHelper(contextVk, offscreenSurface->getColorAttachmentImage(),
2418                    gl::TextureType::InvalidEnum, format, 0, 0, false, siblingSerial);
2419 
2420     ASSERT(mImage->getLayerCount() == 1);
2421     return initImageViews(contextVk, getImageViewLevelCount());
2422 }
2423 
releaseTexImage(const gl::Context * context)2424 angle::Result TextureVk::releaseTexImage(const gl::Context *context)
2425 {
2426     ContextVk *contextVk = vk::GetImpl(context);
2427 
2428     releaseImage(contextVk);
2429 
2430     return angle::Result::Continue;
2431 }
2432 
getAttachmentRenderTarget(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex,GLsizei samples,FramebufferAttachmentRenderTarget ** rtOut)2433 angle::Result TextureVk::getAttachmentRenderTarget(const gl::Context *context,
2434                                                    GLenum binding,
2435                                                    const gl::ImageIndex &imageIndex,
2436                                                    GLsizei samples,
2437                                                    FramebufferAttachmentRenderTarget **rtOut)
2438 {
2439     ASSERT(imageIndex.getLevelIndex() >= 0);
2440 
2441     ContextVk *contextVk = vk::GetImpl(context);
2442 
2443     // Sync the texture's image.  See comment on this function in the header.
2444     ANGLE_TRY(respecifyImageStorageIfNecessary(contextVk, gl::Command::Draw));
2445 
2446     // Don't flush staged updates here. We'll handle that in FramebufferVk so we can defer clears.
2447 
2448     if (!mImage->valid())
2449     {
2450         const vk::Format &format = getBaseLevelFormat(contextVk->getRenderer());
2451         ANGLE_TRY(initImage(contextVk, format.getIntendedFormatID(),
2452                             format.getActualImageFormatID(getRequiredImageAccess()),
2453                             ImageMipLevels::EnabledLevels));
2454     }
2455 
2456     ANGLE_TRY(performImageQueueTransferIfNecessary(contextVk));
2457 
2458     const bool hasRenderToTextureEXT =
2459         contextVk->getFeatures().supportsMultisampledRenderToSingleSampled.enabled ||
2460         contextVk->getFeatures().supportsMultisampledRenderToSingleSampledGOOGLEX.enabled;
2461 
2462     // If samples > 1 here, we have a singlesampled texture that's being multisampled rendered to.
2463     // In this case, create a multisampled image that is otherwise identical to the single sampled
2464     // image.  That multisampled image is used as color or depth/stencil attachment, while the
2465     // original image is used as the resolve attachment.
2466     const gl::RenderToTextureImageIndex renderToTextureIndex =
2467         hasRenderToTextureEXT
2468             ? gl::RenderToTextureImageIndex::Default
2469             : static_cast<gl::RenderToTextureImageIndex>(PackSampleCount(samples));
2470     if (samples > 1 && !mMultisampledImages[renderToTextureIndex].valid() && !hasRenderToTextureEXT)
2471     {
2472         ASSERT(mState.getBaseLevelDesc().samples <= 1);
2473         vk::ImageHelper *multisampledImage = &mMultisampledImages[renderToTextureIndex];
2474 
2475         // Ensure the view serial is valid.
2476         RendererVk *renderer = contextVk->getRenderer();
2477         mMultisampledImageViews[renderToTextureIndex].init(renderer);
2478 
2479         // The MSAA image always comes from the single sampled one, so disable robust init.
2480         bool useRobustInit = false;
2481 
2482         // Create the implicit multisampled image.
2483         ANGLE_TRY(multisampledImage->initImplicitMultisampledRenderToTexture(
2484             contextVk, mState.hasProtectedContent(), renderer->getMemoryProperties(),
2485             mState.getType(), samples, *mImage, useRobustInit));
2486     }
2487 
2488     GLuint layerIndex = 0, layerCount = 0, imageLayerCount = 0;
2489     GetRenderTargetLayerCountAndIndex(mImage, imageIndex, &layerIndex, &layerCount,
2490                                       &imageLayerCount);
2491 
2492     if (layerCount == 1)
2493     {
2494         initSingleLayerRenderTargets(contextVk, imageLayerCount,
2495                                      gl::LevelIndex(imageIndex.getLevelIndex()),
2496                                      renderToTextureIndex);
2497 
2498         std::vector<RenderTargetVector> &levelRenderTargets =
2499             mSingleLayerRenderTargets[renderToTextureIndex];
2500         ASSERT(imageIndex.getLevelIndex() < static_cast<int32_t>(levelRenderTargets.size()));
2501 
2502         RenderTargetVector &layerRenderTargets = levelRenderTargets[imageIndex.getLevelIndex()];
2503         ASSERT(imageIndex.getLayerIndex() < static_cast<int32_t>(layerRenderTargets.size()));
2504 
2505         *rtOut = &layerRenderTargets[layerIndex];
2506     }
2507     else
2508     {
2509         ASSERT(layerCount > 0);
2510         *rtOut = getMultiLayerRenderTarget(contextVk, gl::LevelIndex(imageIndex.getLevelIndex()),
2511                                            layerIndex, layerCount);
2512     }
2513 
2514     return angle::Result::Continue;
2515 }
2516 
ensureImageInitialized(ContextVk * contextVk,ImageMipLevels mipLevels)2517 angle::Result TextureVk::ensureImageInitialized(ContextVk *contextVk, ImageMipLevels mipLevels)
2518 {
2519     if (mImage->valid() && !mImage->hasStagedUpdatesInAllocatedLevels())
2520     {
2521         return angle::Result::Continue;
2522     }
2523 
2524     if (!mImage->valid())
2525     {
2526         ASSERT(!mRedefinedLevels.any());
2527 
2528         const vk::Format &format = getBaseLevelFormat(contextVk->getRenderer());
2529         ANGLE_TRY(initImage(contextVk, format.getIntendedFormatID(),
2530                             format.getActualImageFormatID(getRequiredImageAccess()), mipLevels));
2531         if (mipLevels == ImageMipLevels::FullMipChainForGenerateMipmap)
2532         {
2533             // Remove staged updates to non-base mips when generating mipmaps.  These can only be
2534             // emulated format init clears that are staged in initImage.
2535             mImage->removeStagedUpdates(contextVk,
2536                                         gl::LevelIndex(mState.getEffectiveBaseLevel() + 1),
2537                                         gl::LevelIndex(mState.getMipmapMaxLevel()));
2538         }
2539     }
2540 
2541     return flushImageStagedUpdates(contextVk);
2542 }
2543 
flushImageStagedUpdates(ContextVk * contextVk)2544 angle::Result TextureVk::flushImageStagedUpdates(ContextVk *contextVk)
2545 {
2546     ASSERT(mImage->valid());
2547 
2548     gl::LevelIndex firstLevelGL = getNativeImageLevel(mImage->getFirstAllocatedLevel());
2549     uint32_t firstLayer         = getNativeImageLayer(0);
2550 
2551     return mImage->flushStagedUpdates(contextVk, firstLevelGL,
2552                                       firstLevelGL + getImageViewLevelCount(), firstLayer,
2553                                       firstLayer + getImageViewLayerCount(), mRedefinedLevels);
2554 }
2555 
performImageQueueTransferIfNecessary(ContextVk * contextVk)2556 angle::Result TextureVk::performImageQueueTransferIfNecessary(ContextVk *contextVk)
2557 {
2558     const RendererVk *renderer = contextVk->getRenderer();
2559 
2560     const uint32_t rendererQueueFamilyIndex = renderer->getQueueFamilyIndex();
2561     if (mImage->valid() && mImage->isQueueChangeNeccesary(rendererQueueFamilyIndex))
2562     {
2563         vk::ImageLayout newLayout = vk::ImageLayout::AllGraphicsShadersWrite;
2564         if (mImage->getUsage() & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
2565         {
2566             newLayout = vk::ImageLayout::ColorWrite;
2567         }
2568         else if (mImage->getUsage() & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
2569         {
2570             newLayout = vk::ImageLayout::DepthWriteStencilWrite;
2571         }
2572         else if (mImage->getUsage() &
2573                  (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT))
2574         {
2575             newLayout = vk::ImageLayout::AllGraphicsShadersReadOnly;
2576         }
2577 
2578         vk::OutsideRenderPassCommandBuffer *commandBuffer;
2579         vk::CommandBufferAccess access;
2580         access.onExternalAcquireRelease(mImage);
2581         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
2582         mImage->changeLayoutAndQueue(contextVk, mImage->getAspectFlags(), newLayout,
2583                                      rendererQueueFamilyIndex, commandBuffer);
2584         ANGLE_TRY(contextVk->onEGLImageQueueChange());
2585     }
2586 
2587     return angle::Result::Continue;
2588 }
2589 
initSingleLayerRenderTargets(ContextVk * contextVk,GLuint layerCount,gl::LevelIndex levelIndex,gl::RenderToTextureImageIndex renderToTextureIndex)2590 void TextureVk::initSingleLayerRenderTargets(ContextVk *contextVk,
2591                                              GLuint layerCount,
2592                                              gl::LevelIndex levelIndex,
2593                                              gl::RenderToTextureImageIndex renderToTextureIndex)
2594 {
2595     std::vector<RenderTargetVector> &allLevelsRenderTargets =
2596         mSingleLayerRenderTargets[renderToTextureIndex];
2597 
2598     if (allLevelsRenderTargets.size() <= static_cast<uint32_t>(levelIndex.get()))
2599     {
2600         allLevelsRenderTargets.resize(levelIndex.get() + 1);
2601     }
2602 
2603     RenderTargetVector &renderTargets = allLevelsRenderTargets[levelIndex.get()];
2604 
2605     // Lazy init. Check if already initialized.
2606     if (!renderTargets.empty())
2607     {
2608         return;
2609     }
2610 
2611     // There are |layerCount| render targets, one for each layer
2612     renderTargets.resize(layerCount);
2613 
2614     const bool isMultisampledRenderToTexture =
2615         renderToTextureIndex != gl::RenderToTextureImageIndex::Default;
2616 
2617     for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex)
2618     {
2619         vk::ImageHelper *drawImage             = mImage;
2620         vk::ImageViewHelper *drawImageViews    = &getImageViews();
2621         vk::ImageHelper *resolveImage          = nullptr;
2622         vk::ImageViewHelper *resolveImageViews = nullptr;
2623 
2624         RenderTargetTransience transience = isMultisampledRenderToTexture
2625                                                 ? RenderTargetTransience::MultisampledTransient
2626                                                 : RenderTargetTransience::Default;
2627 
2628         // If multisampled render to texture, use the multisampled image as draw image instead, and
2629         // resolve into the texture's image automatically.
2630         if (isMultisampledRenderToTexture)
2631         {
2632             ASSERT(mMultisampledImages[renderToTextureIndex].valid());
2633 
2634             resolveImage      = drawImage;
2635             resolveImageViews = drawImageViews;
2636             drawImage         = &mMultisampledImages[renderToTextureIndex];
2637             drawImageViews    = &mMultisampledImageViews[renderToTextureIndex];
2638 
2639             // If the texture is depth/stencil, GL_EXT_multisampled_render_to_texture2 explicitly
2640             // indicates that there is no need for the image to be resolved.  In that case, mark the
2641             // render target as entirely transient.
2642             if (mImage->getAspectFlags() != VK_IMAGE_ASPECT_COLOR_BIT)
2643             {
2644                 transience = RenderTargetTransience::EntirelyTransient;
2645             }
2646         }
2647 
2648         renderTargets[layerIndex].init(drawImage, drawImageViews, resolveImage, resolveImageViews,
2649                                        mImageSiblingSerial, getNativeImageLevel(levelIndex),
2650                                        getNativeImageLayer(layerIndex), 1, transience);
2651     }
2652 }
2653 
getMultiLayerRenderTarget(ContextVk * contextVk,gl::LevelIndex level,GLuint layerIndex,GLuint layerCount)2654 RenderTargetVk *TextureVk::getMultiLayerRenderTarget(ContextVk *contextVk,
2655                                                      gl::LevelIndex level,
2656                                                      GLuint layerIndex,
2657                                                      GLuint layerCount)
2658 {
2659     vk::ImageSubresourceRange range =
2660         vk::MakeImageSubresourceDrawRange(level, layerIndex, vk::GetLayerMode(*mImage, layerCount),
2661                                           gl::SrgbWriteControlMode::Default);
2662 
2663     auto iter = mMultiLayerRenderTargets.find(range);
2664     if (iter != mMultiLayerRenderTargets.end())
2665     {
2666         return iter->second.get();
2667     }
2668 
2669     // Create the layered render target.  Note that multisampled render to texture is not
2670     // allowed with layered render targets.
2671     std::unique_ptr<RenderTargetVk> &rt = mMultiLayerRenderTargets[range];
2672     if (!rt)
2673     {
2674         rt = std::make_unique<RenderTargetVk>();
2675     }
2676 
2677     rt->init(mImage, &getImageViews(), nullptr, nullptr, mImageSiblingSerial,
2678              getNativeImageLevel(level), getNativeImageLayer(layerIndex), layerCount,
2679              RenderTargetTransience::Default);
2680 
2681     return rt.get();
2682 }
2683 
prepareForGenerateMipmap(ContextVk * contextVk)2684 void TextureVk::prepareForGenerateMipmap(ContextVk *contextVk)
2685 {
2686     gl::LevelIndex baseLevel(mState.getEffectiveBaseLevel());
2687     gl::LevelIndex maxLevel(mState.getMipmapMaxLevel());
2688 
2689     // Remove staged updates to the range that's being respecified (which is all the mips except
2690     // baseLevel).
2691     gl::LevelIndex firstGeneratedLevel = baseLevel + 1;
2692     mImage->removeStagedUpdates(contextVk, firstGeneratedLevel, maxLevel);
2693 
2694     static_assert(gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS < 32,
2695                   "levels mask assumes 32-bits is enough");
2696     // Generate bitmask for (baseLevel, maxLevel]. `+1` because bitMask takes `the number of bits`
2697     // but levels start counting from 0
2698     gl::TexLevelMask levelsMask(angle::BitMask<uint32_t>(maxLevel.get() + 1));
2699     levelsMask &= static_cast<uint32_t>(~angle::BitMask<uint32_t>(firstGeneratedLevel.get()));
2700     // Remove (baseLevel, maxLevel] from mRedefinedLevels. These levels are no longer incompatibly
2701     // defined if they previously were.  The corresponding bits in mRedefinedLevels should be
2702     // cleared.
2703     mRedefinedLevels &= ~levelsMask;
2704 
2705     // If generating mipmap and base level is incompatibly redefined, the image is going to be
2706     // recreated.  Don't try to preserve the other mips.
2707     if (mRedefinedLevels.test(baseLevel.get()))
2708     {
2709         ASSERT(!mState.getImmutableFormat());
2710         releaseImage(contextVk);
2711     }
2712 
2713     const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
2714     VkImageType imageType              = gl_vk::GetImageType(mState.getType());
2715     const vk::Format &format           = getBaseLevelFormat(contextVk->getRenderer());
2716     const GLint samples                = baseLevelDesc.samples ? baseLevelDesc.samples : 1;
2717 
2718     // If the compute path is to be used to generate mipmaps, add the STORAGE usage.
2719     if (CanGenerateMipmapWithCompute(contextVk->getRenderer(), imageType,
2720                                      format.getActualImageFormatID(getRequiredImageAccess()),
2721                                      samples, mOwnsImage))
2722     {
2723         mImageUsageFlags |= VK_IMAGE_USAGE_STORAGE_BIT;
2724     }
2725 }
2726 
respecifyImageStorageIfNecessary(ContextVk * contextVk,gl::Command source)2727 angle::Result TextureVk::respecifyImageStorageIfNecessary(ContextVk *contextVk, gl::Command source)
2728 {
2729     ASSERT(mState.getBuffer().get() == nullptr);
2730 
2731     VkImageUsageFlags oldUsageFlags   = mImageUsageFlags;
2732     VkImageCreateFlags oldCreateFlags = mImageCreateFlags;
2733 
2734     // Create a new image if the storage state is enabled for the first time.
2735     if (mState.hasBeenBoundAsImage())
2736     {
2737         mImageUsageFlags |= VK_IMAGE_USAGE_STORAGE_BIT;
2738         mRequiresMutableStorage = true;
2739     }
2740 
2741     // If we're handling dirty srgb decode/override state, we may have to reallocate the image with
2742     // VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT. Vulkan requires this bit to be set in order to use
2743     // imageviews with a format that does not match the texture's internal format.
2744     if (isSRGBOverrideEnabled())
2745     {
2746         mRequiresMutableStorage = true;
2747     }
2748 
2749     if (mRequiresMutableStorage)
2750     {
2751         mImageCreateFlags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
2752     }
2753 
2754     // Create a new image if used as attachment for the first time. This must be called before
2755     // prepareForGenerateMipmap since this changes the format which prepareForGenerateMipmap relies
2756     // on.
2757     if (mState.hasBeenBoundAsAttachment())
2758     {
2759         TextureUpdateResult updateResult = TextureUpdateResult::ImageUnaffected;
2760         ANGLE_TRY(ensureRenderable(contextVk, &updateResult));
2761         if (updateResult == TextureUpdateResult::ImageRespecified)
2762         {
2763             oldUsageFlags  = mImageUsageFlags;
2764             oldCreateFlags = mImageCreateFlags;
2765         }
2766     }
2767 
2768     // Before redefining the image for any reason, check to see if it's about to go through mipmap
2769     // generation.  In that case, drop every staged change for the subsequent mips after base, and
2770     // make sure the image is created with the complete mip chain.
2771     const bool isGenerateMipmap = source == gl::Command::GenerateMipmap;
2772     if (isGenerateMipmap)
2773     {
2774         prepareForGenerateMipmap(contextVk);
2775     }
2776 
2777     // For immutable texture, base level does not affect allocation. Only usage flags are. If usage
2778     // flag changed, we respecify image storage early on. This makes the code more reliable and also
2779     // better performance wise. Otherwise, we will try to preserve base level by calling
2780     // stageSelfAsSubresourceUpdates and then later on find out the mImageUsageFlags changed and the
2781     // whole thing has to be respecified.
2782     if (mState.getImmutableFormat() &&
2783         (oldUsageFlags != mImageUsageFlags || oldCreateFlags != mImageCreateFlags))
2784     {
2785         ANGLE_TRY(respecifyImageStorage(contextVk));
2786         oldUsageFlags  = mImageUsageFlags;
2787         oldCreateFlags = mImageCreateFlags;
2788     }
2789 
2790     // Set base and max level before initializing the image
2791     TextureUpdateResult updateResult = TextureUpdateResult::ImageUnaffected;
2792     ANGLE_TRY(maybeUpdateBaseMaxLevels(contextVk, &updateResult));
2793 
2794     // Updating levels could have respecified the storage, recapture mImageCreateFlags
2795     if (updateResult == TextureUpdateResult::ImageRespecified)
2796     {
2797         oldUsageFlags  = mImageUsageFlags;
2798         oldCreateFlags = mImageCreateFlags;
2799     }
2800 
2801     // It is possible for the image to have a single level (because it doesn't use mipmapping),
2802     // then have more levels defined in it and mipmapping enabled.  In that case, the image needs
2803     // to be recreated.
2804     bool isMipmapEnabledByMinFilter = false;
2805     if (!isGenerateMipmap && mImage && mImage->valid())
2806     {
2807         isMipmapEnabledByMinFilter =
2808             mImage->getLevelCount() < getMipLevelCount(ImageMipLevels::EnabledLevels);
2809     }
2810 
2811     // If generating mipmaps and the image needs to be recreated (not full-mip already, or changed
2812     // usage flags), make sure it's recreated.
2813     if (isGenerateMipmap && mImage && mImage->valid() &&
2814         (oldUsageFlags != mImageUsageFlags ||
2815          (!mState.getImmutableFormat() &&
2816           mImage->getLevelCount() !=
2817               getMipLevelCount(ImageMipLevels::FullMipChainForGenerateMipmap))))
2818     {
2819         ASSERT(mOwnsImage);
2820         // Immutable texture is not expected to reach here. The usage flag change should have
2821         // been handled earlier and level count change should not need to reallocate
2822         ASSERT(!mState.getImmutableFormat());
2823 
2824         // Flush staged updates to the base level of the image.  Note that updates to the rest of
2825         // the levels have already been discarded through the |removeStagedUpdates| call above.
2826         ANGLE_TRY(flushImageStagedUpdates(contextVk));
2827 
2828         stageSelfAsSubresourceUpdates(contextVk);
2829 
2830         // Release the mImage without collecting garbage from image views.
2831         releaseImage(contextVk);
2832     }
2833 
2834     // Respecify the image if it's changed in usage, or if any of its levels are redefined and no
2835     // update to base/max levels were done (otherwise the above call would have already taken care
2836     // of this).  Note that if both base/max and image usage are changed, the image is recreated
2837     // twice, which incurs unnecessary copies.  This is not expected to be happening in real
2838     // applications.
2839     if (oldUsageFlags != mImageUsageFlags || oldCreateFlags != mImageCreateFlags ||
2840         mRedefinedLevels.any() || isMipmapEnabledByMinFilter)
2841     {
2842         ANGLE_TRY(respecifyImageStorage(contextVk));
2843     }
2844 
2845     return angle::Result::Continue;
2846 }
2847 
onLabelUpdate(const gl::Context * context)2848 angle::Result TextureVk::onLabelUpdate(const gl::Context *context)
2849 {
2850     ContextVk *contextVk = vk::GetImpl(context);
2851     return updateTextureLabel(contextVk);
2852 }
2853 
updateTextureLabel(ContextVk * contextVk)2854 angle::Result TextureVk::updateTextureLabel(ContextVk *contextVk)
2855 {
2856     RendererVk *renderer = contextVk->getRenderer();
2857     std::string label    = mState.getLabel();
2858     if (!label.empty() && renderer->enableDebugUtils() && imageValid())
2859     {
2860         return vk::SetDebugUtilsObjectName(contextVk, VK_OBJECT_TYPE_IMAGE,
2861                                            (uint64_t)(getImage().getImage().getHandle()),
2862                                            mState.getLabel());
2863     }
2864     return angle::Result::Continue;
2865 }
2866 
getRGBAConversionBufferHelper(RendererVk * renderer,angle::FormatID formatID) const2867 vk::BufferHelper *TextureVk::getRGBAConversionBufferHelper(RendererVk *renderer,
2868                                                            angle::FormatID formatID) const
2869 {
2870     BufferVk *bufferVk                                        = vk::GetImpl(getBuffer().get());
2871     const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = mState.getBuffer();
2872     const VkDeviceSize bindingOffset                          = bufferBinding.getOffset();
2873     ConversionBuffer *conversion                              = bufferVk->getVertexConversionBuffer(
2874         renderer, formatID, 16, static_cast<uint32_t>(bindingOffset), false);
2875     return conversion->data.get();
2876 }
2877 
convertBufferToRGBA(ContextVk * contextVk,size_t & conversionBufferSize)2878 angle::Result TextureVk::convertBufferToRGBA(ContextVk *contextVk, size_t &conversionBufferSize)
2879 {
2880     RendererVk *renderer               = contextVk->getRenderer();
2881     const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
2882     const vk::Format *imageUniformFormat =
2883         &renderer->getFormat(baseLevelDesc.format.info->sizedInternalFormat);
2884     const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = mState.getBuffer();
2885     BufferVk *bufferVk                                        = vk::GetImpl(getBuffer().get());
2886     const VkDeviceSize bindingOffset                          = bufferBinding.getOffset();
2887     const VkDeviceSize bufferSize                             = bufferVk->getSize();
2888     const VkDeviceSize bufferSizeFromOffset                   = bufferSize - bindingOffset;
2889     conversionBufferSize = roundUpPow2<size_t>(static_cast<size_t>((bufferSizeFromOffset / 3) * 4),
2890                                                4 * sizeof(uint32_t));
2891 
2892     ConversionBuffer *conversion =
2893         bufferVk->getVertexConversionBuffer(renderer, imageUniformFormat->getIntendedFormatID(), 16,
2894                                             static_cast<uint32_t>(bindingOffset), false);
2895     mBufferContentsObservers->enableForBuffer(getBuffer().get());
2896     vk::BufferHelper *conversionBufferHelper = conversion->data.get();
2897     if (!conversionBufferHelper->valid())
2898     {
2899         ANGLE_TRY(conversionBufferHelper->allocateForVertexConversion(
2900             contextVk, conversionBufferSize, vk::MemoryHostVisibility::NonVisible));
2901     }
2902 
2903     if (conversion->dirty)
2904     {
2905         vk::BufferHelper &bufferHelper = bufferVk->getBuffer();
2906         UtilsVk &utilsVk               = contextVk->getUtils();
2907         const VkDeviceSize pixelSize   = 3 * sizeof(uint32_t);
2908         const VkDeviceSize pixelCount  = bufferSizeFromOffset / pixelSize;
2909 
2910         ANGLE_TRY(utilsVk.copyRgbToRgba(contextVk, imageUniformFormat->getIntendedFormat(),
2911                                         &bufferHelper, static_cast<uint32_t>(bindingOffset),
2912                                         static_cast<uint32_t>(pixelCount), conversionBufferHelper));
2913         conversion->dirty = false;
2914     }
2915 
2916     return angle::Result::Continue;
2917 }
2918 
syncState(const gl::Context * context,const gl::Texture::DirtyBits & dirtyBits,gl::Command source)2919 angle::Result TextureVk::syncState(const gl::Context *context,
2920                                    const gl::Texture::DirtyBits &dirtyBits,
2921                                    gl::Command source)
2922 {
2923     ContextVk *contextVk = vk::GetImpl(context);
2924     RendererVk *renderer = contextVk->getRenderer();
2925 
2926     // If this is a texture buffer, release buffer views.  There's nothing else to sync.  The
2927     // image must already be deleted, and the sampler reset.
2928     if (mState.getBuffer().get() != nullptr)
2929     {
2930         ASSERT(mImage == nullptr);
2931 
2932         const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = mState.getBuffer();
2933 
2934         VkDeviceSize offset = bufferBinding.getOffset();
2935         VkDeviceSize size   = gl::GetBoundBufferAvailableSize(bufferBinding);
2936 
2937         if (NeedsRGBAEmulation(renderer, getBaseLevelFormat(renderer).getIntendedFormatID()))
2938         {
2939             size_t conversionBufferSize;
2940             ANGLE_TRY(convertBufferToRGBA(contextVk, conversionBufferSize));
2941             offset = 0;
2942             size   = conversionBufferSize;
2943         }
2944 
2945         mBufferViews.release(contextVk);
2946         mBufferViews.init(renderer, offset, size);
2947         mDescriptorSetCacheManager.releaseKeys(contextVk);
2948         return angle::Result::Continue;
2949     }
2950 
2951     ANGLE_TRY(respecifyImageStorageIfNecessary(contextVk, source));
2952 
2953     ANGLE_TRY(performImageQueueTransferIfNecessary(contextVk));
2954 
2955     // Initialize the image storage and flush the pixel buffer.
2956     const bool isGenerateMipmap = source == gl::Command::GenerateMipmap;
2957     ANGLE_TRY(ensureImageInitialized(contextVk, isGenerateMipmap
2958                                                     ? ImageMipLevels::FullMipChainForGenerateMipmap
2959                                                     : ImageMipLevels::EnabledLevels));
2960 
2961     // Mask out the IMPLEMENTATION dirty bit to avoid unnecessary syncs.
2962     gl::Texture::DirtyBits localBits = dirtyBits;
2963     localBits.reset(gl::Texture::DIRTY_BIT_IMPLEMENTATION);
2964     localBits.reset(gl::Texture::DIRTY_BIT_BASE_LEVEL);
2965     localBits.reset(gl::Texture::DIRTY_BIT_MAX_LEVEL);
2966 
2967     // For AHBs, the ImageViews are created with VkSamplerYcbcrConversionInfo's chromaFilter
2968     // matching min/magFilters as part of the eglEGLImageTargetTexture2DOES() call. However, the
2969     // min/mag filters can change later, requiring the ImageViews to be refreshed.
2970     if (mImage->valid() && mImage->hasImmutableSampler() &&
2971         (dirtyBits.test(gl::Texture::DIRTY_BIT_MIN_FILTER) ||
2972          dirtyBits.test(gl::Texture::DIRTY_BIT_MAG_FILTER)))
2973     {
2974         const gl::SamplerState &samplerState = mState.getSamplerState();
2975         ASSERT(samplerState.getMinFilter() == samplerState.getMagFilter());
2976         if (mImage->updateChromaFilter(renderer, gl_vk::GetFilter(samplerState.getMinFilter())))
2977         {
2978             resetSampler();
2979             ANGLE_TRY(refreshImageViews(contextVk));
2980         }
2981     }
2982 
2983     if (localBits.none() && mSampler.valid())
2984     {
2985         return angle::Result::Continue;
2986     }
2987 
2988     if (mSampler.valid())
2989     {
2990         resetSampler();
2991     }
2992 
2993     if (localBits.test(gl::Texture::DIRTY_BIT_SWIZZLE_RED) ||
2994         localBits.test(gl::Texture::DIRTY_BIT_SWIZZLE_GREEN) ||
2995         localBits.test(gl::Texture::DIRTY_BIT_SWIZZLE_BLUE) ||
2996         localBits.test(gl::Texture::DIRTY_BIT_SWIZZLE_ALPHA))
2997     {
2998         ANGLE_TRY(refreshImageViews(contextVk));
2999     }
3000 
3001     if (!renderer->getFeatures().supportsImageFormatList.enabled &&
3002         (localBits.test(gl::Texture::DIRTY_BIT_SRGB_OVERRIDE) ||
3003          localBits.test(gl::Texture::DIRTY_BIT_SRGB_DECODE)))
3004     {
3005         ANGLE_TRY(refreshImageViews(contextVk));
3006     }
3007 
3008     vk::SamplerDesc samplerDesc(contextVk, mState.getSamplerState(), mState.isStencilMode(),
3009                                 &mImage->getYcbcrConversionDesc(), mImage->getIntendedFormatID());
3010     auto y2yConversionDesc = mImage->getY2YConversionDesc();
3011     vk::SamplerDesc samplerDescSamplerExternal2DY2YEXT(contextVk, mState.getSamplerState(),
3012                                                        mState.isStencilMode(), &y2yConversionDesc,
3013                                                        mImage->getIntendedFormatID());
3014     ANGLE_TRY(renderer->getSamplerCache().getSampler(contextVk, samplerDesc, &mSampler));
3015     ANGLE_TRY(renderer->getSamplerCache().getSampler(contextVk, samplerDescSamplerExternal2DY2YEXT,
3016                                                      &mY2YSampler));
3017 
3018     updateCachedImageViewSerials();
3019 
3020     return angle::Result::Continue;
3021 }
3022 
initializeContents(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex)3023 angle::Result TextureVk::initializeContents(const gl::Context *context,
3024                                             GLenum binding,
3025                                             const gl::ImageIndex &imageIndex)
3026 {
3027     ContextVk *contextVk      = vk::GetImpl(context);
3028     const gl::ImageDesc &desc = mState.getImageDesc(imageIndex);
3029     const vk::Format &format =
3030         contextVk->getRenderer()->getFormat(desc.format.info->sizedInternalFormat);
3031 
3032     ASSERT(mImage);
3033     // Note that we cannot ensure the image is initialized because we might be calling subImage
3034     // on a non-complete cube map.
3035     return mImage->stageRobustResourceClearWithFormat(
3036         contextVk, imageIndex, desc.size, format.getIntendedFormat(),
3037         format.getActualImageFormat(getRequiredImageAccess()));
3038 }
3039 
initializeContentsWithBlack(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex)3040 angle::Result TextureVk::initializeContentsWithBlack(const gl::Context *context,
3041                                                      GLenum binding,
3042                                                      const gl::ImageIndex &imageIndex)
3043 {
3044     ContextVk *contextVk      = vk::GetImpl(context);
3045     const gl::ImageDesc &desc = mState.getImageDesc(imageIndex);
3046     const vk::Format &format =
3047         contextVk->getRenderer()->getFormat(desc.format.info->sizedInternalFormat);
3048 
3049     VkClearValue clearValue = {};
3050     clearValue.color        = {{0, 0, 0, 1.0f}};
3051 
3052     ASSERT(mImage);
3053     // Note that we cannot ensure the image is initialized because we might be calling subImage
3054     // on a non-complete cube map.
3055     return mImage->stageResourceClearWithFormat(
3056         contextVk, imageIndex, desc.size, format.getIntendedFormat(),
3057         format.getActualImageFormat(getRequiredImageAccess()), clearValue);
3058 }
3059 
releaseOwnershipOfImage(const gl::Context * context)3060 void TextureVk::releaseOwnershipOfImage(const gl::Context *context)
3061 {
3062     ContextVk *contextVk = vk::GetImpl(context);
3063 
3064     ASSERT(!mImageSiblingSerial.valid());
3065 
3066     mOwnsImage = false;
3067     releaseAndDeleteImageAndViews(contextVk);
3068 }
3069 
shouldDecodeSRGB(vk::Context * context,GLenum srgbDecode,bool texelFetchStaticUse) const3070 bool TextureVk::shouldDecodeSRGB(vk::Context *context,
3071                                  GLenum srgbDecode,
3072                                  bool texelFetchStaticUse) const
3073 {
3074     // By default, we decode SRGB images.
3075     const vk::Format &format = getBaseLevelFormat(context->getRenderer());
3076     bool decodeSRGB          = format.getActualImageFormat(getRequiredImageAccess()).isSRGB;
3077 
3078     // If the SRGB override is enabled, we also decode SRGB.
3079     if (isSRGBOverrideEnabled() &&
3080         IsOverridableLinearFormat(format.getActualImageFormatID(getRequiredImageAccess())))
3081     {
3082         decodeSRGB = true;
3083     }
3084 
3085     // The decode step is optionally disabled by the skip decode setting, except for texelFetch:
3086     //
3087     // "The conversion of sRGB color space components to linear color space is always applied if the
3088     // TEXTURE_SRGB_DECODE_EXT parameter is DECODE_EXT. Table X.1 describes whether the conversion
3089     // is skipped if the TEXTURE_SRGB_DECODE_EXT parameter is SKIP_DECODE_EXT, depending on the
3090     // function used for the access, whether the access occurs through a bindless sampler, and
3091     // whether the texture is statically accessed elsewhere with a texelFetch function."
3092     if (srgbDecode == GL_SKIP_DECODE_EXT && !texelFetchStaticUse)
3093     {
3094         decodeSRGB = false;
3095     }
3096 
3097     return decodeSRGB;
3098 }
3099 
getReadImageView(vk::Context * context,GLenum srgbDecode,bool texelFetchStaticUse,bool samplerExternal2DY2YEXT) const3100 const vk::ImageView &TextureVk::getReadImageView(vk::Context *context,
3101                                                  GLenum srgbDecode,
3102                                                  bool texelFetchStaticUse,
3103                                                  bool samplerExternal2DY2YEXT) const
3104 {
3105     ASSERT(mImage->valid());
3106 
3107     const vk::ImageViewHelper &imageViews = getImageViews();
3108 
3109     if (mState.isStencilMode() && imageViews.hasStencilReadImageView())
3110     {
3111         return imageViews.getStencilReadImageView();
3112     }
3113 
3114     if (samplerExternal2DY2YEXT)
3115     {
3116         ASSERT(imageViews.getSamplerExternal2DY2YEXTImageView().valid());
3117         return imageViews.getSamplerExternal2DY2YEXTImageView();
3118     }
3119     else if (shouldDecodeSRGB(context, srgbDecode, texelFetchStaticUse))
3120     {
3121         ASSERT(imageViews.getSRGBReadImageView().valid());
3122         return imageViews.getSRGBReadImageView();
3123     }
3124 
3125     ASSERT(imageViews.getLinearReadImageView().valid());
3126     return imageViews.getLinearReadImageView();
3127 }
3128 
getFetchImageView(vk::Context * context,GLenum srgbDecode,bool texelFetchStaticUse) const3129 const vk::ImageView &TextureVk::getFetchImageView(vk::Context *context,
3130                                                   GLenum srgbDecode,
3131                                                   bool texelFetchStaticUse) const
3132 {
3133     ASSERT(mImage->valid());
3134 
3135     const vk::ImageViewHelper &imageViews = getImageViews();
3136 
3137     // We don't currently support fetch for depth/stencil cube map textures.
3138     ASSERT(!imageViews.hasStencilReadImageView() || !imageViews.hasFetchImageView());
3139 
3140     if (shouldDecodeSRGB(context, srgbDecode, texelFetchStaticUse))
3141     {
3142         return (imageViews.hasFetchImageView() ? imageViews.getSRGBFetchImageView()
3143                                                : imageViews.getSRGBReadImageView());
3144     }
3145 
3146     return (imageViews.hasFetchImageView() ? imageViews.getLinearFetchImageView()
3147                                            : imageViews.getLinearReadImageView());
3148 }
3149 
getCopyImageView() const3150 const vk::ImageView &TextureVk::getCopyImageView() const
3151 {
3152     ASSERT(mImage->valid());
3153 
3154     const vk::ImageViewHelper &imageViews = getImageViews();
3155 
3156     const angle::Format &angleFormat = mImage->getActualFormat();
3157     ASSERT(angleFormat.isSRGB ==
3158            (ConvertToLinear(mImage->getActualFormatID()) != angle::FormatID::NONE));
3159     if (angleFormat.isSRGB)
3160     {
3161         return imageViews.getSRGBCopyImageView();
3162     }
3163     return imageViews.getLinearCopyImageView();
3164 }
3165 
getLevelLayerImageView(vk::Context * context,gl::LevelIndex level,size_t layer,const vk::ImageView ** imageViewOut)3166 angle::Result TextureVk::getLevelLayerImageView(vk::Context *context,
3167                                                 gl::LevelIndex level,
3168                                                 size_t layer,
3169                                                 const vk::ImageView **imageViewOut)
3170 {
3171     ASSERT(mImage && mImage->valid());
3172 
3173     gl::LevelIndex levelGL = getNativeImageLevel(level);
3174     vk::LevelIndex levelVk = mImage->toVkLevel(levelGL);
3175     uint32_t nativeLayer   = getNativeImageLayer(static_cast<uint32_t>(layer));
3176 
3177     return getImageViews().getLevelLayerDrawImageView(
3178         context, *mImage, levelVk, nativeLayer, gl::SrgbWriteControlMode::Default, imageViewOut);
3179 }
3180 
getStorageImageView(vk::Context * context,const gl::ImageUnit & binding,const vk::ImageView ** imageViewOut)3181 angle::Result TextureVk::getStorageImageView(vk::Context *context,
3182                                              const gl::ImageUnit &binding,
3183                                              const vk::ImageView **imageViewOut)
3184 {
3185     RendererVk *renderer = context->getRenderer();
3186 
3187     angle::FormatID formatID = angle::Format::InternalFormatToID(binding.format);
3188     const vk::Format *format = &renderer->getFormat(formatID);
3189 
3190     format = AdjustStorageViewFormatPerWorkarounds(renderer, format, getRequiredImageAccess());
3191 
3192     gl::LevelIndex nativeLevelGL =
3193         getNativeImageLevel(gl::LevelIndex(static_cast<uint32_t>(binding.level)));
3194     vk::LevelIndex nativeLevelVk = mImage->toVkLevel(nativeLevelGL);
3195 
3196     if (binding.layered != GL_TRUE)
3197     {
3198         uint32_t nativeLayer = getNativeImageLayer(static_cast<uint32_t>(binding.layer));
3199 
3200         return getImageViews().getLevelLayerStorageImageView(
3201             context, *mImage, nativeLevelVk, nativeLayer,
3202             VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT,
3203             format->getActualImageFormatID(getRequiredImageAccess()), imageViewOut);
3204     }
3205 
3206     uint32_t nativeLayer = getNativeImageLayer(0);
3207 
3208     return getImageViews().getLevelStorageImageView(
3209         context, mState.getType(), *mImage, nativeLevelVk, nativeLayer,
3210         VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT,
3211         format->getActualImageFormatID(getRequiredImageAccess()), imageViewOut);
3212 }
3213 
getPossiblyEmulatedTextureBuffer(vk::Context * context) const3214 vk::BufferHelper *TextureVk::getPossiblyEmulatedTextureBuffer(vk::Context *context) const
3215 {
3216     RendererVk *renderer = context->getRenderer();
3217 
3218     angle::FormatID format = getBaseLevelFormat(renderer).getIntendedFormatID();
3219     if (NeedsRGBAEmulation(renderer, format))
3220     {
3221         return getRGBAConversionBufferHelper(renderer, format);
3222     }
3223 
3224     BufferVk *bufferVk = vk::GetImpl(getBuffer().get());
3225     return &bufferVk->getBuffer();
3226 }
3227 
getBufferViewAndRecordUse(vk::Context * context,const vk::Format * imageUniformFormat,bool isImage,const vk::BufferView ** viewOut)3228 angle::Result TextureVk::getBufferViewAndRecordUse(vk::Context *context,
3229                                                    const vk::Format *imageUniformFormat,
3230                                                    bool isImage,
3231                                                    const vk::BufferView **viewOut)
3232 {
3233     RendererVk *renderer = context->getRenderer();
3234 
3235     ASSERT(mState.getBuffer().get() != nullptr);
3236 
3237     // Use the format specified by glTexBuffer if no format specified by the shader.
3238     if (imageUniformFormat == nullptr)
3239     {
3240         imageUniformFormat = &getBaseLevelFormat(renderer);
3241     }
3242 
3243     if (isImage)
3244     {
3245         imageUniformFormat = AdjustStorageViewFormatPerWorkarounds(renderer, imageUniformFormat,
3246                                                                    getRequiredImageAccess());
3247     }
3248 
3249     // Create a view for the required format.
3250     const vk::BufferHelper &buffer = vk::GetImpl(mState.getBuffer().get())->getBuffer();
3251     VkDeviceSize bufferOffset      = buffer.getOffset();
3252 
3253     if (NeedsRGBAEmulation(renderer, imageUniformFormat->getIntendedFormatID()))
3254     {
3255         vk::BufferHelper *conversionBufferHelper =
3256             getRGBAConversionBufferHelper(renderer, imageUniformFormat->getIntendedFormatID());
3257         const vk::Format *format = &renderer->getFormat(
3258             GetRGBAEmulationDstFormat(imageUniformFormat->getIntendedFormatID()));
3259 
3260         return mBufferViews.getView(context, *conversionBufferHelper,
3261                                     conversionBufferHelper->getOffset(), *format, viewOut);
3262     }
3263 
3264     return mBufferViews.getView(context, buffer, bufferOffset, *imageUniformFormat, viewOut);
3265 }
3266 
initImage(ContextVk * contextVk,angle::FormatID intendedImageFormatID,angle::FormatID actualImageFormatID,ImageMipLevels mipLevels)3267 angle::Result TextureVk::initImage(ContextVk *contextVk,
3268                                    angle::FormatID intendedImageFormatID,
3269                                    angle::FormatID actualImageFormatID,
3270                                    ImageMipLevels mipLevels)
3271 {
3272     RendererVk *renderer = contextVk->getRenderer();
3273 
3274     // Create the image. For immutable texture, we always allocate the full immutable levels
3275     // specified by texStorage call. Otherwise we only try to allocate from base to max levels.
3276     const gl::ImageDesc *firstLevelDesc;
3277     uint32_t firstLevel, levelCount;
3278     if (mState.getImmutableFormat())
3279     {
3280         firstLevelDesc = &mState.getLevelZeroDesc();
3281         firstLevel     = 0;
3282         levelCount     = mState.getImmutableLevels();
3283     }
3284     else
3285     {
3286         firstLevelDesc = &mState.getBaseLevelDesc();
3287         firstLevel     = mState.getEffectiveBaseLevel();
3288         levelCount     = getMipLevelCount(mipLevels);
3289     }
3290     const gl::Extents &firstLevelExtents = firstLevelDesc->size;
3291 
3292     VkExtent3D vkExtent;
3293     uint32_t layerCount;
3294     gl_vk::GetExtentsAndLayerCount(mState.getType(), firstLevelExtents, &vkExtent, &layerCount);
3295     GLint samples = mState.getBaseLevelDesc().samples ? mState.getBaseLevelDesc().samples : 1;
3296 
3297     if (contextVk->getFeatures().limitSampleCountTo2.enabled)
3298     {
3299         samples = std::min(samples, 2);
3300     }
3301 
3302     if (mState.hasProtectedContent())
3303     {
3304         mImageCreateFlags |= VK_IMAGE_CREATE_PROTECTED_BIT;
3305     }
3306 
3307     if (renderer->getFeatures().supportsComputeTranscodeEtcToBc.enabled &&
3308         IsETCFormat(intendedImageFormatID) && IsBCFormat(actualImageFormatID))
3309     {
3310         mImageCreateFlags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT |
3311                              VK_IMAGE_CREATE_EXTENDED_USAGE_BIT |
3312                              VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT;
3313         mImageUsageFlags |= VK_IMAGE_USAGE_STORAGE_BIT;
3314     }
3315 
3316     if ((mImageUsageFlags & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
3317                              VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) != 0 &&
3318         mOwnsImage && samples == 1 &&
3319         contextVk->getFeatures().supportsMultisampledRenderToSingleSampled.enabled)
3320     {
3321 
3322         // Note: If we ever fail the following check, we should use the emulation path for this
3323         // texture instead of ignoring MSRTT.
3324         if (formatSupportsMultisampledRenderToSingleSampled(
3325                 renderer, rx::vk::GetVkFormatFromFormatID(actualImageFormatID),
3326                 gl_vk::GetImageType(mState.getType()), mImage->getTilingMode(), mImageUsageFlags,
3327                 mImageCreateFlags))
3328         {
3329             // If supported by format add the MSRTSS flag because any texture might end up as an
3330             // MSRTT attachment.
3331             mImageCreateFlags |= VK_IMAGE_CREATE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_BIT_EXT;
3332         }
3333     }
3334 
3335     ANGLE_TRY(mImage->initExternal(
3336         contextVk, mState.getType(), vkExtent, intendedImageFormatID, actualImageFormatID, samples,
3337         mImageUsageFlags, mImageCreateFlags, vk::ImageLayout::Undefined, nullptr,
3338         gl::LevelIndex(firstLevel), levelCount, layerCount,
3339         contextVk->isRobustResourceInitEnabled(), mState.hasProtectedContent()));
3340 
3341     ANGLE_TRY(updateTextureLabel(contextVk));
3342 
3343     mRequiresMutableStorage = (mImageCreateFlags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) != 0;
3344 
3345     VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
3346     if (mState.hasProtectedContent())
3347     {
3348         flags |= VK_MEMORY_PROPERTY_PROTECTED_BIT;
3349     }
3350 
3351     ANGLE_TRY(mImage->initMemory(contextVk, mState.hasProtectedContent(),
3352                                  renderer->getMemoryProperties(), flags,
3353                                  vk::MemoryAllocationType::TextureImage));
3354 
3355     const uint32_t viewLevelCount =
3356         mState.getImmutableFormat() ? getMipLevelCount(ImageMipLevels::EnabledLevels) : levelCount;
3357     ANGLE_TRY(initImageViews(contextVk, viewLevelCount));
3358 
3359     mCurrentBaseLevel = gl::LevelIndex(mState.getBaseLevel());
3360     mCurrentMaxLevel  = gl::LevelIndex(mState.getMaxLevel());
3361 
3362     return angle::Result::Continue;
3363 }
3364 
initImageViews(ContextVk * contextVk,uint32_t levelCount)3365 angle::Result TextureVk::initImageViews(ContextVk *contextVk, uint32_t levelCount)
3366 {
3367     ASSERT(mImage != nullptr && mImage->valid());
3368 
3369     gl::LevelIndex baseLevelGL =
3370         getNativeImageLevel(gl::LevelIndex(mState.getEffectiveBaseLevel()));
3371     vk::LevelIndex baseLevelVk = mImage->toVkLevel(baseLevelGL);
3372     uint32_t baseLayer         = getNativeImageLayer(0);
3373 
3374     const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
3375     const bool sized                   = baseLevelDesc.format.info->sized;
3376 
3377     const angle::Format &intendedFormat = mImage->getIntendedFormat();
3378     gl::SwizzleState formatSwizzle      = GetFormatSwizzle(intendedFormat, sized);
3379     gl::SwizzleState readSwizzle        = ApplySwizzle(formatSwizzle, mState.getSwizzleState());
3380 
3381     // Use this as a proxy for the SRGB override & skip decode settings.
3382     bool createExtraSRGBViews = mRequiresMutableStorage;
3383 
3384     const VkImageUsageFlags kDisallowedSwizzledUsage =
3385         VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT |
3386         VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
3387     ANGLE_TRY(getImageViews().initReadViews(contextVk, mState.getType(), *mImage, formatSwizzle,
3388                                             readSwizzle, baseLevelVk, levelCount, baseLayer,
3389                                             getImageViewLayerCount(), createExtraSRGBViews,
3390                                             getImage().getUsage() & ~kDisallowedSwizzledUsage));
3391 
3392     updateCachedImageViewSerials();
3393 
3394     return angle::Result::Continue;
3395 }
3396 
releaseImage(ContextVk * contextVk)3397 void TextureVk::releaseImage(ContextVk *contextVk)
3398 {
3399     RendererVk *renderer = contextVk->getRenderer();
3400 
3401     releaseImageViews(contextVk);
3402 
3403     if (mImage)
3404     {
3405         if (mOwnsImage)
3406         {
3407             mImage->releaseImageFromShareContexts(renderer, contextVk, mImageSiblingSerial);
3408         }
3409         else
3410         {
3411             mImage->finalizeImageLayoutInShareContexts(renderer, contextVk, mImageSiblingSerial);
3412             mImageObserverBinding.bind(nullptr);
3413             mImage = nullptr;
3414         }
3415     }
3416 
3417     for (vk::ImageHelper &image : mMultisampledImages)
3418     {
3419         if (image.valid())
3420         {
3421             image.releaseImageFromShareContexts(renderer, contextVk, mImageSiblingSerial);
3422         }
3423     }
3424 
3425     onStateChange(angle::SubjectMessage::SubjectChanged);
3426     mRedefinedLevels.reset();
3427 }
3428 
releaseImageViews(ContextVk * contextVk)3429 void TextureVk::releaseImageViews(ContextVk *contextVk)
3430 {
3431     RendererVk *renderer = contextVk->getRenderer();
3432 
3433     mDescriptorSetCacheManager.releaseKeys(contextVk);
3434 
3435     if (mImage == nullptr)
3436     {
3437         for (vk::ImageViewHelper &imageViewHelper : mMultisampledImageViews)
3438         {
3439             ASSERT(imageViewHelper.isImageViewGarbageEmpty());
3440         }
3441         return;
3442     }
3443 
3444     for (vk::ImageViewHelper &imageViewHelper : mMultisampledImageViews)
3445     {
3446         imageViewHelper.release(renderer, mImage->getResourceUse());
3447     }
3448 
3449     for (auto &renderTargets : mSingleLayerRenderTargets)
3450     {
3451         for (RenderTargetVector &renderTargetLevels : renderTargets)
3452         {
3453             for (RenderTargetVk &renderTargetVk : renderTargetLevels)
3454             {
3455                 renderTargetVk.release(contextVk);
3456             }
3457             // Clear the layers tracked for each level
3458             renderTargetLevels.clear();
3459         }
3460         // Then clear the levels
3461         renderTargets.clear();
3462     }
3463 
3464     for (auto &renderTargetPair : mMultiLayerRenderTargets)
3465     {
3466         renderTargetPair.second->release(contextVk);
3467     }
3468     mMultiLayerRenderTargets.clear();
3469 }
3470 
releaseStagedUpdates(ContextVk * contextVk)3471 void TextureVk::releaseStagedUpdates(ContextVk *contextVk)
3472 {
3473     if (mImage)
3474     {
3475         mImage->releaseStagedUpdates(contextVk->getRenderer());
3476     }
3477 }
3478 
getMipLevelCount(ImageMipLevels mipLevels) const3479 uint32_t TextureVk::getMipLevelCount(ImageMipLevels mipLevels) const
3480 {
3481     switch (mipLevels)
3482     {
3483         // Returns level count from base to max that has been specified, i.e, enabled.
3484         case ImageMipLevels::EnabledLevels:
3485             return mState.getEnabledLevelCount();
3486         // Returns all mipmap levels from base to max regardless if an image has been specified or
3487         // not.
3488         case ImageMipLevels::FullMipChain:
3489         case ImageMipLevels::FullMipChainForGenerateMipmap:
3490             return getMaxLevelCount() - mState.getEffectiveBaseLevel();
3491 
3492         default:
3493             UNREACHABLE();
3494             return 0;
3495     }
3496 }
3497 
getMaxLevelCount() const3498 uint32_t TextureVk::getMaxLevelCount() const
3499 {
3500     // getMipmapMaxLevel will be 0 here if mipmaps are not used, so the levelCount is always +1.
3501     return mState.getMipmapMaxLevel() + 1;
3502 }
3503 
generateMipmapLevelsWithCPU(ContextVk * contextVk,const angle::Format & sourceFormat,GLuint layer,gl::LevelIndex firstMipLevel,gl::LevelIndex maxMipLevel,const size_t sourceWidth,const size_t sourceHeight,const size_t sourceDepth,const size_t sourceRowPitch,const size_t sourceDepthPitch,uint8_t * sourceData)3504 angle::Result TextureVk::generateMipmapLevelsWithCPU(ContextVk *contextVk,
3505                                                      const angle::Format &sourceFormat,
3506                                                      GLuint layer,
3507                                                      gl::LevelIndex firstMipLevel,
3508                                                      gl::LevelIndex maxMipLevel,
3509                                                      const size_t sourceWidth,
3510                                                      const size_t sourceHeight,
3511                                                      const size_t sourceDepth,
3512                                                      const size_t sourceRowPitch,
3513                                                      const size_t sourceDepthPitch,
3514                                                      uint8_t *sourceData)
3515 {
3516     size_t previousLevelWidth      = sourceWidth;
3517     size_t previousLevelHeight     = sourceHeight;
3518     size_t previousLevelDepth      = sourceDepth;
3519     uint8_t *previousLevelData     = sourceData;
3520     size_t previousLevelRowPitch   = sourceRowPitch;
3521     size_t previousLevelDepthPitch = sourceDepthPitch;
3522 
3523     for (gl::LevelIndex currentMipLevel = firstMipLevel; currentMipLevel <= maxMipLevel;
3524          ++currentMipLevel)
3525     {
3526         // Compute next level width and height.
3527         size_t mipWidth  = std::max<size_t>(1, previousLevelWidth >> 1);
3528         size_t mipHeight = std::max<size_t>(1, previousLevelHeight >> 1);
3529         size_t mipDepth  = std::max<size_t>(1, previousLevelDepth >> 1);
3530 
3531         // With the width and height of the next mip, we can allocate the next buffer we need.
3532         uint8_t *destData     = nullptr;
3533         size_t destRowPitch   = mipWidth * sourceFormat.pixelBytes;
3534         size_t destDepthPitch = destRowPitch * mipHeight;
3535 
3536         size_t mipAllocationSize = destDepthPitch * mipDepth;
3537         gl::Extents mipLevelExtents(static_cast<int>(mipWidth), static_cast<int>(mipHeight),
3538                                     static_cast<int>(mipDepth));
3539 
3540         ANGLE_TRY(mImage->stageSubresourceUpdateAndGetData(
3541             contextVk, mipAllocationSize,
3542             gl::ImageIndex::MakeFromType(mState.getType(), currentMipLevel.get(), layer),
3543             mipLevelExtents, gl::Offset(), &destData, sourceFormat.id));
3544 
3545         // Generate the mipmap into that new buffer
3546         sourceFormat.mipGenerationFunction(
3547             previousLevelWidth, previousLevelHeight, previousLevelDepth, previousLevelData,
3548             previousLevelRowPitch, previousLevelDepthPitch, destData, destRowPitch, destDepthPitch);
3549 
3550         // Swap for the next iteration
3551         previousLevelWidth      = mipWidth;
3552         previousLevelHeight     = mipHeight;
3553         previousLevelDepth      = mipDepth;
3554         previousLevelData       = destData;
3555         previousLevelRowPitch   = destRowPitch;
3556         previousLevelDepthPitch = destDepthPitch;
3557     }
3558 
3559     return angle::Result::Continue;
3560 }
3561 
getImplementationSizedFormat(const gl::Context * context) const3562 const gl::InternalFormat &TextureVk::getImplementationSizedFormat(const gl::Context *context) const
3563 {
3564     GLenum sizedFormat = GL_NONE;
3565 
3566     if (mImage && mImage->valid())
3567     {
3568         sizedFormat = mImage->getActualFormat().glInternalFormat;
3569     }
3570     else
3571     {
3572         ContextVk *contextVk     = vk::GetImpl(context);
3573         const vk::Format &format = getBaseLevelFormat(contextVk->getRenderer());
3574         sizedFormat = format.getActualImageFormat(getRequiredImageAccess()).glInternalFormat;
3575     }
3576 
3577     return gl::GetSizedInternalFormatInfo(sizedFormat);
3578 }
3579 
getColorReadFormat(const gl::Context * context)3580 GLenum TextureVk::getColorReadFormat(const gl::Context *context)
3581 {
3582     const gl::InternalFormat &sizedFormat = getImplementationSizedFormat(context);
3583     return sizedFormat.format;
3584 }
3585 
getColorReadType(const gl::Context * context)3586 GLenum TextureVk::getColorReadType(const gl::Context *context)
3587 {
3588     const gl::InternalFormat &sizedFormat = getImplementationSizedFormat(context);
3589     return sizedFormat.type;
3590 }
3591 
getTexImage(const gl::Context * context,const gl::PixelPackState & packState,gl::Buffer * packBuffer,gl::TextureTarget target,GLint level,GLenum format,GLenum type,void * pixels)3592 angle::Result TextureVk::getTexImage(const gl::Context *context,
3593                                      const gl::PixelPackState &packState,
3594                                      gl::Buffer *packBuffer,
3595                                      gl::TextureTarget target,
3596                                      GLint level,
3597                                      GLenum format,
3598                                      GLenum type,
3599                                      void *pixels)
3600 {
3601     ContextVk *contextVk = vk::GetImpl(context);
3602     ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
3603 
3604     GLint baseLevel = static_cast<int>(mState.getBaseLevel());
3605     if (level < baseLevel || level >= baseLevel + static_cast<int>(mState.getEnabledLevelCount()))
3606     {
3607         // TODO(http://anglebug.com/6336): Handle inconsistent textures.
3608         WARN() << "GetTexImage for inconsistent texture levels is not implemented.";
3609         UNIMPLEMENTED();
3610         return angle::Result::Continue;
3611     }
3612 
3613     gl::MaybeOverrideLuminance(format, type, getColorReadFormat(context),
3614                                getColorReadType(context));
3615 
3616     uint32_t layer      = 0;
3617     uint32_t layerCount = 1;
3618 
3619     switch (target)
3620     {
3621         case gl::TextureTarget::CubeMapArray:
3622         case gl::TextureTarget::_2DArray:
3623             layerCount = mImage->getLayerCount();
3624             break;
3625         default:
3626             if (gl::IsCubeMapFaceTarget(target))
3627             {
3628                 layer = static_cast<uint32_t>(gl::CubeMapTextureTargetToFaceIndex(target));
3629             }
3630             break;
3631     }
3632 
3633     return mImage->readPixelsForGetImage(contextVk, packState, packBuffer, gl::LevelIndex(level),
3634                                          layer, layerCount, format, type, pixels);
3635 }
3636 
getCompressedTexImage(const gl::Context * context,const gl::PixelPackState & packState,gl::Buffer * packBuffer,gl::TextureTarget target,GLint level,void * pixels)3637 angle::Result TextureVk::getCompressedTexImage(const gl::Context *context,
3638                                                const gl::PixelPackState &packState,
3639                                                gl::Buffer *packBuffer,
3640                                                gl::TextureTarget target,
3641                                                GLint level,
3642                                                void *pixels)
3643 {
3644     ContextVk *contextVk = vk::GetImpl(context);
3645     ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
3646 
3647     GLint baseLevel = static_cast<int>(mState.getBaseLevel());
3648     if (level < baseLevel || level >= baseLevel + static_cast<int>(mState.getEnabledLevelCount()))
3649     {
3650         // TODO(http://anglebug.com/6336): Handle inconsistent textures.
3651         WARN() << "GetCompressedTexImage for inconsistent texture levels is not implemented.";
3652         UNIMPLEMENTED();
3653         return angle::Result::Continue;
3654     }
3655 
3656     uint32_t layer      = 0;
3657     uint32_t layerCount = 1;
3658 
3659     switch (target)
3660     {
3661         case gl::TextureTarget::CubeMapArray:
3662         case gl::TextureTarget::_2DArray:
3663             layerCount = mImage->getLayerCount();
3664             break;
3665         default:
3666             if (gl::IsCubeMapFaceTarget(target))
3667             {
3668                 layer = static_cast<uint32_t>(gl::CubeMapTextureTargetToFaceIndex(target));
3669             }
3670             break;
3671     }
3672 
3673     return mImage->readPixelsForCompressedGetImage(
3674         contextVk, packState, packBuffer, gl::LevelIndex(level), layer, layerCount, pixels);
3675 }
3676 
getBaseLevelFormat(RendererVk * renderer) const3677 const vk::Format &TextureVk::getBaseLevelFormat(RendererVk *renderer) const
3678 {
3679     const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
3680     return renderer->getFormat(baseLevelDesc.format.info->sizedInternalFormat);
3681 }
3682 
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)3683 void TextureVk::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
3684 {
3685     ASSERT(index == kTextureImageSubjectIndex &&
3686            (message == angle::SubjectMessage::SubjectChanged ||
3687             message == angle::SubjectMessage::InitializationComplete));
3688 
3689     // Forward the notification to the parent that the staging buffer changed.
3690     onStateChange(message);
3691 }
3692 
getImageViewSubresourceSerialImpl(GLenum srgbDecode) const3693 vk::ImageOrBufferViewSubresourceSerial TextureVk::getImageViewSubresourceSerialImpl(
3694     GLenum srgbDecode) const
3695 {
3696     gl::LevelIndex baseLevel(mState.getEffectiveBaseLevel());
3697     // getMipmapMaxLevel will clamp to the max level if it is smaller than the number of mips.
3698     uint32_t levelCount = gl::LevelIndex(mState.getMipmapMaxLevel()) - baseLevel + 1;
3699 
3700     const angle::Format &angleFormat  = mImage->getActualFormat();
3701     vk::SrgbDecodeMode srgbDecodeMode = (angleFormat.isSRGB && (srgbDecode == GL_DECODE_EXT))
3702                                             ? vk::SrgbDecodeMode::SrgbDecode
3703                                             : vk::SrgbDecodeMode::SkipDecode;
3704     gl::SrgbOverride srgbOverrideMode =
3705         (!angleFormat.isSRGB && (mState.getSRGBOverride() == gl::SrgbOverride::SRGB))
3706             ? gl::SrgbOverride::SRGB
3707             : gl::SrgbOverride::Default;
3708 
3709     return getImageViews().getSubresourceSerial(baseLevel, levelCount, 0, vk::LayerMode::All,
3710                                                 srgbDecodeMode, srgbOverrideMode);
3711 }
3712 
getBufferViewSerial() const3713 vk::ImageOrBufferViewSubresourceSerial TextureVk::getBufferViewSerial() const
3714 {
3715     return mBufferViews.getSerial();
3716 }
3717 
getStorageImageViewSerial(const gl::ImageUnit & binding) const3718 vk::ImageOrBufferViewSubresourceSerial TextureVk::getStorageImageViewSerial(
3719     const gl::ImageUnit &binding) const
3720 {
3721     vk::LayerMode layerMode = binding.layered == GL_TRUE ? vk::LayerMode::All : vk::LayerMode::_1;
3722     uint32_t frontendLayer  = binding.layered == GL_TRUE ? 0 : static_cast<uint32_t>(binding.layer);
3723     uint32_t nativeLayer    = getNativeImageLayer(frontendLayer);
3724 
3725     gl::LevelIndex baseLevel(mState.getEffectiveBaseLevel());
3726     // getMipmapMaxLevel will clamp to the max level if it is smaller than the number of mips.
3727     uint32_t levelCount = gl::LevelIndex(mState.getMipmapMaxLevel()) - baseLevel + 1;
3728 
3729     return getImageViews().getSubresourceSerial(baseLevel, levelCount, nativeLayer, layerMode,
3730                                                 vk::SrgbDecodeMode::SkipDecode,
3731                                                 gl::SrgbOverride::Default);
3732 }
3733 
getImageViewLayerCount() const3734 uint32_t TextureVk::getImageViewLayerCount() const
3735 {
3736     // We use a special layer count here to handle EGLImages. They might only be
3737     // looking at one layer of a cube or 2D array texture.
3738     return mEGLImageNativeType == gl::TextureType::InvalidEnum ? mImage->getLayerCount() : 1;
3739 }
3740 
getImageViewLevelCount() const3741 uint32_t TextureVk::getImageViewLevelCount() const
3742 {
3743     // We use a special level count here to handle EGLImages. They might only be
3744     // looking at one level of the texture's mipmap chain.
3745     return mEGLImageNativeType == gl::TextureType::InvalidEnum ? mImage->getLevelCount() : 1;
3746 }
3747 
refreshImageViews(ContextVk * contextVk)3748 angle::Result TextureVk::refreshImageViews(ContextVk *contextVk)
3749 {
3750     vk::ImageViewHelper &imageView = getImageViews();
3751     if (mImage == nullptr)
3752     {
3753         ASSERT(imageView.isImageViewGarbageEmpty());
3754     }
3755     else
3756     {
3757         RendererVk *renderer = contextVk->getRenderer();
3758         imageView.release(renderer, mImage->getResourceUse());
3759 
3760         for (auto &renderTargets : mSingleLayerRenderTargets)
3761         {
3762             for (RenderTargetVector &renderTargetLevels : renderTargets)
3763             {
3764                 for (RenderTargetVk &renderTargetVk : renderTargetLevels)
3765                 {
3766                     renderTargetVk.release(contextVk);
3767                 }
3768             }
3769         }
3770         for (auto &renderTargetPair : mMultiLayerRenderTargets)
3771         {
3772             renderTargetPair.second->release(contextVk);
3773         }
3774     }
3775 
3776     ANGLE_TRY(initImageViews(contextVk, getImageViewLevelCount()));
3777 
3778     // Let any Framebuffers know we need to refresh the RenderTarget cache.
3779     onStateChange(angle::SubjectMessage::SubjectChanged);
3780 
3781     return angle::Result::Continue;
3782 }
3783 
ensureMutable(ContextVk * contextVk)3784 angle::Result TextureVk::ensureMutable(ContextVk *contextVk)
3785 {
3786     if (mRequiresMutableStorage)
3787     {
3788         return angle::Result::Continue;
3789     }
3790 
3791     mRequiresMutableStorage = true;
3792     mImageCreateFlags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
3793 
3794     ANGLE_TRY(respecifyImageStorage(contextVk));
3795     ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
3796 
3797     return refreshImageViews(contextVk);
3798 }
3799 
ensureRenderable(ContextVk * contextVk,TextureUpdateResult * updateResultOut)3800 angle::Result TextureVk::ensureRenderable(ContextVk *contextVk,
3801                                           TextureUpdateResult *updateResultOut)
3802 {
3803     if (mRequiredImageAccess == vk::ImageAccess::Renderable)
3804     {
3805         return angle::Result::Continue;
3806     }
3807 
3808     mRequiredImageAccess = vk::ImageAccess::Renderable;
3809     if (!mImage)
3810     {
3811         // Later on when ensureImageAllocated() is called, it will ensure a renderable format is
3812         // used.
3813         return angle::Result::Continue;
3814     }
3815 
3816     RendererVk *renderer     = contextVk->getRenderer();
3817     const vk::Format &format = getBaseLevelFormat(renderer);
3818     if (!format.hasRenderableImageFallbackFormat())
3819     {
3820         // If there is no fallback format for renderable, then nothing to do.
3821         return angle::Result::Continue;
3822     }
3823 
3824     // luminance/alpha  format never fallback for rendering and if we ever do fallback, the
3825     // following code may not handle it properly.
3826     ASSERT(!format.getIntendedFormat().isLUMA());
3827 
3828     angle::FormatID previousActualFormatID =
3829         format.getActualImageFormatID(vk::ImageAccess::SampleOnly);
3830     angle::FormatID actualFormatID = format.getActualImageFormatID(vk::ImageAccess::Renderable);
3831 
3832     if (!mImage->valid())
3833     {
3834         // Immutable texture must already have a valid image
3835         ASSERT(!mState.getImmutableFormat());
3836         // If we have staged updates and they were encoded with different format, we need to flush
3837         // out these staged updates. The respecifyImageStorage should handle reading back the
3838         // flushed data and re-stage it with the new format.
3839         angle::FormatID intendedFormatID = format.getIntendedFormatID();
3840 
3841         gl::LevelIndex levelGLStart, levelGLEnd;
3842         ImageMipLevels mipLevels;
3843         if (mState.getImmutableFormat())
3844         {
3845             levelGLStart = gl::LevelIndex(0);
3846             levelGLEnd   = gl::LevelIndex(mState.getImmutableLevels());
3847             mipLevels    = ImageMipLevels::FullMipChainForGenerateMipmap;
3848         }
3849         else
3850         {
3851             levelGLStart = gl::LevelIndex(mState.getEffectiveBaseLevel());
3852             levelGLEnd =
3853                 gl::LevelIndex(levelGLStart + getMipLevelCount(ImageMipLevels::EnabledLevels));
3854             mipLevels = ImageMipLevels::EnabledLevels;
3855         }
3856 
3857         if (mImage->hasStagedImageUpdatesWithMismatchedFormat(levelGLStart, levelGLEnd,
3858                                                               actualFormatID))
3859         {
3860             angle::FormatID sampleOnlyFormatID =
3861                 format.getActualImageFormatID(vk::ImageAccess::SampleOnly);
3862 
3863             ANGLE_TRY(initImage(contextVk, intendedFormatID, sampleOnlyFormatID, mipLevels));
3864         }
3865         else
3866         {
3867             // First try to convert any staged buffer updates from old format to new format using
3868             // CPU.
3869             ANGLE_TRY(mImage->reformatStagedBufferUpdates(contextVk, previousActualFormatID,
3870                                                           actualFormatID));
3871         }
3872     }
3873 
3874     // Make sure we update mImageUsage bits
3875     ANGLE_TRY(ensureImageAllocated(contextVk, format));
3876     ANGLE_TRY(respecifyImageStorage(contextVk));
3877     ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
3878 
3879     *updateResultOut = TextureUpdateResult::ImageRespecified;
3880 
3881     return refreshImageViews(contextVk);
3882 }
3883 
stageSelfAsSubresourceUpdates(ContextVk * contextVk)3884 void TextureVk::stageSelfAsSubresourceUpdates(ContextVk *contextVk)
3885 {
3886     // If we are calling stageSelfAsSubresourceUpdates(), the current image will be swapped
3887     // to prevImage in stageSelfAsSubresourceUpdates(), therefore we need to release the
3888     // imageViews first as we want to use current image.mUse to keep track of imageViews' resource
3889     // lifetime.
3890     releaseImageViews(contextVk);
3891     // Make the image stage itself as updates to its levels.
3892     ASSERT(!mImageSiblingSerial.valid());
3893     mImage->stageSelfAsSubresourceUpdates(contextVk, mImage->getLevelCount(), mRedefinedLevels);
3894 }
3895 
updateCachedImageViewSerials()3896 void TextureVk::updateCachedImageViewSerials()
3897 {
3898     mCachedImageViewSubresourceSerialSRGBDecode = getImageViewSubresourceSerialImpl(GL_DECODE_EXT);
3899     mCachedImageViewSubresourceSerialSkipDecode =
3900         getImageViewSubresourceSerialImpl(GL_SKIP_DECODE_EXT);
3901 }
3902 
formatSupportsMultisampledRenderToSingleSampled(RendererVk * renderer,VkFormat format,VkImageType imageType,VkImageTiling tilingMode,VkImageUsageFlags usageFlags,VkImageCreateFlags createFlags)3903 bool TextureVk::formatSupportsMultisampledRenderToSingleSampled(RendererVk *renderer,
3904                                                                 VkFormat format,
3905                                                                 VkImageType imageType,
3906                                                                 VkImageTiling tilingMode,
3907                                                                 VkImageUsageFlags usageFlags,
3908                                                                 VkImageCreateFlags createFlags)
3909 {
3910     // Verify support for this image format after adding MSRTSS flag
3911     VkPhysicalDeviceImageFormatInfo2 imageFormatInfo = {};
3912     imageFormatInfo.sType  = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
3913     imageFormatInfo.format = format;
3914     imageFormatInfo.type   = imageType;
3915     imageFormatInfo.tiling = tilingMode;
3916     imageFormatInfo.usage  = usageFlags;
3917     imageFormatInfo.flags =
3918         createFlags | VK_IMAGE_CREATE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_BIT_EXT;
3919 
3920     VkImageFormatProperties imageFormatProperties                            = {};
3921     VkSamplerYcbcrConversionImageFormatProperties ycbcrImageFormatProperties = {};
3922     ycbcrImageFormatProperties.sType =
3923         VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES;
3924 
3925     VkImageFormatProperties2 imageFormatProperties2 = {};
3926     imageFormatProperties2.sType                    = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
3927     imageFormatProperties2.pNext                    = &ycbcrImageFormatProperties;
3928     imageFormatProperties2.imageFormatProperties    = imageFormatProperties;
3929 
3930     VkResult result = vkGetPhysicalDeviceImageFormatProperties2(
3931         renderer->getPhysicalDevice(), &imageFormatInfo, &imageFormatProperties2);
3932 
3933     return (result == VK_SUCCESS);
3934 }
3935 
3936 }  // namespace rx
3937