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