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