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