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