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