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