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