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