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