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