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