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