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/RendererVk.h"
25 #include "libANGLE/renderer/vulkan/SurfaceVk.h"
26 #include "libANGLE/renderer/vulkan/vk_format_utils.h"
27 #include "libANGLE/trace.h"
28
29 namespace rx
30 {
31 namespace
32 {
33 constexpr VkImageUsageFlags kDrawStagingImageFlags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
34 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
35 VK_IMAGE_USAGE_TRANSFER_DST_BIT;
36
37 constexpr VkImageUsageFlags kTransferStagingImageFlags =
38 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
39
40 constexpr VkFormatFeatureFlags kBlitFeatureFlags =
41 VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT;
42
43 constexpr angle::SubjectIndex kTextureImageSubjectIndex = 0;
44
CanCopyWithTransfer(RendererVk * renderer,const vk::Format & srcFormat,const vk::Format & destFormat)45 bool CanCopyWithTransfer(RendererVk *renderer,
46 const vk::Format &srcFormat,
47 const vk::Format &destFormat)
48 {
49 // NOTE(syoussefi): technically, you can transfer between formats as long as they have the same
50 // size and are compatible, but for now, let's just support same-format copies with transfer.
51 return srcFormat.internalFormat == destFormat.internalFormat &&
52 renderer->hasImageFormatFeatureBits(srcFormat.vkImageFormat,
53 VK_FORMAT_FEATURE_TRANSFER_SRC_BIT) &&
54 renderer->hasImageFormatFeatureBits(destFormat.vkImageFormat,
55 VK_FORMAT_FEATURE_TRANSFER_DST_BIT);
56 }
57
CanCopyWithDraw(RendererVk * renderer,const vk::Format & srcFormat,const vk::Format & destFormat)58 bool CanCopyWithDraw(RendererVk *renderer,
59 const vk::Format &srcFormat,
60 const vk::Format &destFormat)
61 {
62 return renderer->hasImageFormatFeatureBits(srcFormat.vkImageFormat,
63 VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) &&
64 renderer->hasImageFormatFeatureBits(destFormat.vkImageFormat,
65 VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT);
66 }
67
ForceCPUPathForCopy(RendererVk * renderer,const vk::ImageHelper & image)68 bool ForceCPUPathForCopy(RendererVk *renderer, const vk::ImageHelper &image)
69 {
70 return image.getLayerCount() > 1 && renderer->getFeatures().forceCPUPathForCubeMapCopy.enabled;
71 }
72
GetRenderTargetLayerCountAndIndex(vk::ImageHelper * image,const gl::ImageIndex & index,GLuint * layerCount,GLuint * layerIndex)73 void GetRenderTargetLayerCountAndIndex(vk::ImageHelper *image,
74 const gl::ImageIndex &index,
75 GLuint *layerCount,
76 GLuint *layerIndex)
77 {
78 switch (index.getType())
79 {
80 case gl::TextureType::_2D:
81 case gl::TextureType::_2DMultisample:
82 *layerIndex = 0;
83 *layerCount = 1;
84 return;
85
86 case gl::TextureType::CubeMap:
87 *layerIndex = index.cubeMapFaceIndex();
88 *layerCount = gl::kCubeFaceCount;
89 return;
90
91 case gl::TextureType::_3D:
92 *layerIndex = index.hasLayer() ? index.getLayerIndex() : 0;
93 *layerCount = image->getExtents().depth;
94 return;
95
96 case gl::TextureType::_2DArray:
97 case gl::TextureType::_2DMultisampleArray:
98 *layerIndex = index.hasLayer() ? index.getLayerIndex() : 0;
99 *layerCount = image->getLayerCount();
100 return;
101
102 default:
103 UNREACHABLE();
104 }
105 }
106
Set3DBaseArrayLayerAndLayerCount(VkImageSubresourceLayers * Subresource)107 void Set3DBaseArrayLayerAndLayerCount(VkImageSubresourceLayers *Subresource)
108 {
109 // If the srcImage/dstImage parameters are of VkImageType VK_IMAGE_TYPE_3D, the baseArrayLayer
110 // and layerCount members of the corresponding subresource must be 0 and 1, respectively.
111 Subresource->baseArrayLayer = 0;
112 Subresource->layerCount = 1;
113 }
114 } // anonymous namespace
115
116 // TextureVk implementation.
TextureVk(const gl::TextureState & state,RendererVk * renderer)117 TextureVk::TextureVk(const gl::TextureState &state, RendererVk *renderer)
118 : TextureImpl(state),
119 mOwnsImage(false),
120 mImageNativeType(gl::TextureType::InvalidEnum),
121 mImageLayerOffset(0),
122 mImageLevelOffset(0),
123 mImage(nullptr),
124 mStagingBufferInitialSize(vk::kStagingBufferSize),
125 mImageUsageFlags(0),
126 mImageCreateFlags(0),
127 mImageObserverBinding(this, kTextureImageSubjectIndex)
128 {}
129
130 TextureVk::~TextureVk() = default;
131
onDestroy(const gl::Context * context)132 void TextureVk::onDestroy(const gl::Context *context)
133 {
134 ContextVk *contextVk = vk::GetImpl(context);
135
136 releaseAndDeleteImage(contextVk);
137 mSampler.reset();
138 }
139
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)140 angle::Result TextureVk::setImage(const gl::Context *context,
141 const gl::ImageIndex &index,
142 GLenum internalFormat,
143 const gl::Extents &size,
144 GLenum format,
145 GLenum type,
146 const gl::PixelUnpackState &unpack,
147 gl::Buffer *unpackBuffer,
148 const uint8_t *pixels)
149 {
150 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat, type);
151
152 return setImageImpl(context, index, formatInfo, size, type, unpack, unpackBuffer, pixels);
153 }
154
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)155 angle::Result TextureVk::setSubImage(const gl::Context *context,
156 const gl::ImageIndex &index,
157 const gl::Box &area,
158 GLenum format,
159 GLenum type,
160 const gl::PixelUnpackState &unpack,
161 gl::Buffer *unpackBuffer,
162 const uint8_t *pixels)
163 {
164 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format, type);
165 ContextVk *contextVk = vk::GetImpl(context);
166 const gl::ImageDesc &levelDesc = mState.getImageDesc(index);
167 const vk::Format &vkFormat =
168 contextVk->getRenderer()->getFormat(levelDesc.format.info->sizedInternalFormat);
169
170 return setSubImageImpl(context, index, area, formatInfo, type, unpack, unpackBuffer, pixels,
171 vkFormat);
172 }
173
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)174 angle::Result TextureVk::setCompressedImage(const gl::Context *context,
175 const gl::ImageIndex &index,
176 GLenum internalFormat,
177 const gl::Extents &size,
178 const gl::PixelUnpackState &unpack,
179 size_t imageSize,
180 const uint8_t *pixels)
181 {
182 const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat);
183
184 const gl::State &glState = context->getState();
185 gl::Buffer *unpackBuffer = glState.getTargetBuffer(gl::BufferBinding::PixelUnpack);
186
187 return setImageImpl(context, index, formatInfo, size, GL_UNSIGNED_BYTE, unpack, unpackBuffer,
188 pixels);
189 }
190
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)191 angle::Result TextureVk::setCompressedSubImage(const gl::Context *context,
192 const gl::ImageIndex &index,
193 const gl::Box &area,
194 GLenum format,
195 const gl::PixelUnpackState &unpack,
196 size_t imageSize,
197 const uint8_t *pixels)
198 {
199
200 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format, GL_UNSIGNED_BYTE);
201 ContextVk *contextVk = vk::GetImpl(context);
202 const gl::ImageDesc &levelDesc = mState.getImageDesc(index);
203 const vk::Format &vkFormat =
204 contextVk->getRenderer()->getFormat(levelDesc.format.info->sizedInternalFormat);
205 const gl::State &glState = contextVk->getState();
206 gl::Buffer *unpackBuffer = glState.getTargetBuffer(gl::BufferBinding::PixelUnpack);
207
208 return setSubImageImpl(context, index, area, formatInfo, GL_UNSIGNED_BYTE, unpack, unpackBuffer,
209 pixels, vkFormat);
210 }
211
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)212 angle::Result TextureVk::setImageImpl(const gl::Context *context,
213 const gl::ImageIndex &index,
214 const gl::InternalFormat &formatInfo,
215 const gl::Extents &size,
216 GLenum type,
217 const gl::PixelUnpackState &unpack,
218 gl::Buffer *unpackBuffer,
219 const uint8_t *pixels)
220 {
221 ContextVk *contextVk = vk::GetImpl(context);
222 RendererVk *renderer = contextVk->getRenderer();
223
224 const vk::Format &vkFormat = renderer->getFormat(formatInfo.sizedInternalFormat);
225
226 ANGLE_TRY(redefineImage(context, index, vkFormat, size));
227
228 // Early-out on empty textures, don't create a zero-sized storage.
229 if (size.empty())
230 {
231 return angle::Result::Continue;
232 }
233
234 return setSubImageImpl(context, index, gl::Box(0, 0, 0, size.width, size.height, size.depth),
235 formatInfo, type, unpack, unpackBuffer, pixels, vkFormat);
236 }
237
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)238 angle::Result TextureVk::setSubImageImpl(const gl::Context *context,
239 const gl::ImageIndex &index,
240 const gl::Box &area,
241 const gl::InternalFormat &formatInfo,
242 GLenum type,
243 const gl::PixelUnpackState &unpack,
244 gl::Buffer *unpackBuffer,
245 const uint8_t *pixels,
246 const vk::Format &vkFormat)
247 {
248 ContextVk *contextVk = vk::GetImpl(context);
249
250 if (unpackBuffer)
251 {
252 BufferVk *unpackBufferVk = vk::GetImpl(unpackBuffer);
253 vk::BufferHelper &bufferHelper = unpackBufferVk->getBuffer();
254 uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
255 GLuint inputRowPitch = 0;
256 GLuint inputDepthPitch = 0;
257 GLuint inputSkipBytes = 0;
258
259 ANGLE_TRY(mImage->CalculateBufferInfo(
260 contextVk, gl::Extents(area.width, area.height, area.depth), formatInfo, unpack, type,
261 index.usesTex3D(), &inputRowPitch, &inputDepthPitch, &inputSkipBytes));
262
263 size_t offsetBytes = static_cast<size_t>(offset + inputSkipBytes);
264
265 if (isFastUnpackPossible(vkFormat, offsetBytes))
266 {
267 GLuint pixelSize = formatInfo.pixelBytes;
268 GLuint blockWidth = formatInfo.compressedBlockWidth;
269 GLuint blockHeight = formatInfo.compressedBlockHeight;
270 if (!formatInfo.compressed)
271 {
272 pixelSize = formatInfo.computePixelBytes(type);
273 blockWidth = 1;
274 blockHeight = 1;
275 }
276 ASSERT(pixelSize != 0 && inputRowPitch != 0 && blockWidth != 0 && blockHeight != 0);
277
278 GLuint rowLengthPixels = inputRowPitch / pixelSize * blockWidth;
279 GLuint imageHeightPixels = inputDepthPitch / inputRowPitch * blockHeight;
280
281 ANGLE_TRY(copyBufferDataToImage(contextVk, &bufferHelper, index, rowLengthPixels,
282 imageHeightPixels, area, offsetBytes));
283 }
284 else
285 {
286 void *mapPtr = nullptr;
287
288 ANGLE_TRY(unpackBufferVk->mapImpl(contextVk, &mapPtr));
289
290 const uint8_t *source =
291 static_cast<const uint8_t *>(mapPtr) + reinterpret_cast<ptrdiff_t>(pixels);
292
293 ANGLE_TRY(mImage->stageSubresourceUpdateImpl(
294 contextVk, getNativeImageIndex(index),
295 gl::Extents(area.width, area.height, area.depth),
296 gl::Offset(area.x, area.y, area.z), formatInfo, unpack, type, source, vkFormat,
297 inputRowPitch, inputDepthPitch, inputSkipBytes));
298
299 ANGLE_TRY(unpackBufferVk->unmapImpl(contextVk));
300 }
301 }
302 else if (pixels)
303 {
304 ANGLE_TRY(mImage->stageSubresourceUpdate(
305 contextVk, getNativeImageIndex(index), gl::Extents(area.width, area.height, area.depth),
306 gl::Offset(area.x, area.y, area.z), formatInfo, unpack, type, pixels, vkFormat));
307 }
308
309 return angle::Result::Continue;
310 }
311
copyImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Rectangle & sourceArea,GLenum internalFormat,gl::Framebuffer * source)312 angle::Result TextureVk::copyImage(const gl::Context *context,
313 const gl::ImageIndex &index,
314 const gl::Rectangle &sourceArea,
315 GLenum internalFormat,
316 gl::Framebuffer *source)
317 {
318 RendererVk *renderer = vk::GetImpl(context)->getRenderer();
319
320 gl::Extents newImageSize(sourceArea.width, sourceArea.height, 1);
321 const gl::InternalFormat &internalFormatInfo =
322 gl::GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE);
323 const vk::Format &vkFormat = renderer->getFormat(internalFormatInfo.sizedInternalFormat);
324
325 ANGLE_TRY(redefineImage(context, index, vkFormat, newImageSize));
326 return copySubImageImpl(context, index, gl::Offset(0, 0, 0), sourceArea, internalFormatInfo,
327 source);
328 }
329
copySubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,gl::Framebuffer * source)330 angle::Result TextureVk::copySubImage(const gl::Context *context,
331 const gl::ImageIndex &index,
332 const gl::Offset &destOffset,
333 const gl::Rectangle &sourceArea,
334 gl::Framebuffer *source)
335 {
336 const gl::InternalFormat ¤tFormat = *mState.getImageDesc(index).format.info;
337 return copySubImageImpl(context, index, destOffset, sourceArea, currentFormat, source);
338 }
339
copyTexture(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,GLenum type,size_t sourceLevel,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,const gl::Texture * source)340 angle::Result TextureVk::copyTexture(const gl::Context *context,
341 const gl::ImageIndex &index,
342 GLenum internalFormat,
343 GLenum type,
344 size_t sourceLevel,
345 bool unpackFlipY,
346 bool unpackPremultiplyAlpha,
347 bool unpackUnmultiplyAlpha,
348 const gl::Texture *source)
349 {
350 RendererVk *renderer = vk::GetImpl(context)->getRenderer();
351
352 TextureVk *sourceVk = vk::GetImpl(source);
353 const gl::ImageDesc &sourceImageDesc =
354 sourceVk->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), sourceLevel);
355 gl::Rectangle sourceArea(0, 0, sourceImageDesc.size.width, sourceImageDesc.size.height);
356
357 const gl::InternalFormat &destFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
358 const vk::Format &destVkFormat = renderer->getFormat(destFormatInfo.sizedInternalFormat);
359
360 ANGLE_TRY(redefineImage(context, index, destVkFormat, sourceImageDesc.size));
361
362 return copySubTextureImpl(vk::GetImpl(context), index, gl::kOffsetZero, destFormatInfo,
363 sourceLevel, sourceArea, unpackFlipY, unpackPremultiplyAlpha,
364 unpackUnmultiplyAlpha, sourceVk);
365 }
366
copySubTexture(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,size_t sourceLevel,const gl::Box & sourceBox,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,const gl::Texture * source)367 angle::Result TextureVk::copySubTexture(const gl::Context *context,
368 const gl::ImageIndex &index,
369 const gl::Offset &destOffset,
370 size_t sourceLevel,
371 const gl::Box &sourceBox,
372 bool unpackFlipY,
373 bool unpackPremultiplyAlpha,
374 bool unpackUnmultiplyAlpha,
375 const gl::Texture *source)
376 {
377 gl::TextureTarget target = index.getTarget();
378 size_t level = static_cast<size_t>(index.getLevelIndex());
379 const gl::InternalFormat &destFormatInfo = *mState.getImageDesc(target, level).format.info;
380 return copySubTextureImpl(vk::GetImpl(context), index, destOffset, destFormatInfo, sourceLevel,
381 sourceBox.toRect(), unpackFlipY, unpackPremultiplyAlpha,
382 unpackUnmultiplyAlpha, vk::GetImpl(source));
383 }
384
copyCompressedTexture(const gl::Context * context,const gl::Texture * source)385 angle::Result TextureVk::copyCompressedTexture(const gl::Context *context,
386 const gl::Texture *source)
387 {
388 ContextVk *contextVk = vk::GetImpl(context);
389 TextureVk *sourceVk = vk::GetImpl(source);
390
391 gl::TextureTarget sourceTarget = NonCubeTextureTypeToTarget(source->getType());
392 constexpr GLint sourceLevel = 0;
393 constexpr GLint destLevel = 0;
394
395 const gl::InternalFormat &internalFormat = *source->getFormat(sourceTarget, sourceLevel).info;
396 const vk::Format &vkFormat =
397 contextVk->getRenderer()->getFormat(internalFormat.sizedInternalFormat);
398 const gl::Extents size(static_cast<int>(source->getWidth(sourceTarget, sourceLevel)),
399 static_cast<int>(source->getHeight(sourceTarget, sourceLevel)), 1);
400 const gl::ImageIndex destIndex = gl::ImageIndex::MakeFromTarget(sourceTarget, destLevel, 1);
401
402 ANGLE_TRY(redefineImage(context, destIndex, vkFormat, size));
403
404 ANGLE_TRY(sourceVk->ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
405
406 return copySubImageImplWithTransfer(
407 contextVk, destIndex, gl::Offset(0, 0, 0), vkFormat, sourceLevel, 0,
408 gl::Rectangle(0, 0, size.width, size.height), &sourceVk->getImage());
409 }
410
copySubImageImpl(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,const gl::InternalFormat & internalFormat,gl::Framebuffer * source)411 angle::Result TextureVk::copySubImageImpl(const gl::Context *context,
412 const gl::ImageIndex &index,
413 const gl::Offset &destOffset,
414 const gl::Rectangle &sourceArea,
415 const gl::InternalFormat &internalFormat,
416 gl::Framebuffer *source)
417 {
418 gl::Extents fbSize = source->getReadColorAttachment()->getSize();
419 gl::Rectangle clippedSourceArea;
420 if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height),
421 &clippedSourceArea))
422 {
423 return angle::Result::Continue;
424 }
425
426 ContextVk *contextVk = vk::GetImpl(context);
427 RendererVk *renderer = contextVk->getRenderer();
428 FramebufferVk *framebufferVk = vk::GetImpl(source);
429
430 const gl::ImageIndex offsetImageIndex = getNativeImageIndex(index);
431
432 // If negative offsets are given, clippedSourceArea ensures we don't read from those offsets.
433 // However, that changes the sourceOffset->destOffset mapping. Here, destOffset is shifted by
434 // the same amount as clipped to correct the error.
435 VkImageType imageType = gl_vk::GetImageType(mState.getType());
436 int zOffset = (imageType == VK_IMAGE_TYPE_3D) ? destOffset.z : 0;
437 const gl::Offset modifiedDestOffset(destOffset.x + clippedSourceArea.x - sourceArea.x,
438 destOffset.y + clippedSourceArea.y - sourceArea.y, zOffset);
439
440 RenderTargetVk *colorReadRT = framebufferVk->getColorReadRenderTarget();
441
442 const vk::Format &srcFormat = colorReadRT->getImageFormat();
443 const vk::Format &destFormat = renderer->getFormat(internalFormat.sizedInternalFormat);
444
445 bool isViewportFlipY = contextVk->isViewportFlipEnabledForReadFBO();
446
447 // If it's possible to perform the copy with a transfer, that's the best option.
448 if (!isViewportFlipY && CanCopyWithTransfer(renderer, srcFormat, destFormat))
449 {
450 return copySubImageImplWithTransfer(contextVk, offsetImageIndex, modifiedDestOffset,
451 destFormat, colorReadRT->getLevelIndex(),
452 colorReadRT->getLayerIndex(), clippedSourceArea,
453 &colorReadRT->getImage());
454 }
455
456 bool forceCPUPath = ForceCPUPathForCopy(renderer, *mImage);
457
458 // If it's possible to perform the copy with a draw call, do that.
459 if (CanCopyWithDraw(renderer, srcFormat, destFormat) && !forceCPUPath)
460 {
461 // Layer count can only be 1 as the source is a framebuffer.
462 ASSERT(offsetImageIndex.getLayerCount() == 1);
463
464 const vk::ImageView *readImageView = nullptr;
465 ANGLE_TRY(colorReadRT->getImageView(contextVk, &readImageView));
466 colorReadRT->retainImageViews(contextVk);
467
468 return copySubImageImplWithDraw(contextVk, offsetImageIndex, modifiedDestOffset, destFormat,
469 0, clippedSourceArea, isViewportFlipY, false, false, false,
470 &colorReadRT->getImage(), readImageView);
471 }
472
473 // Do a CPU readback that does the conversion, and then stage the change to the pixel buffer.
474 ANGLE_TRY(mImage->stageSubresourceUpdateFromFramebuffer(
475 context, offsetImageIndex, clippedSourceArea, modifiedDestOffset,
476 gl::Extents(clippedSourceArea.width, clippedSourceArea.height, 1), internalFormat,
477 framebufferVk));
478
479 return angle::Result::Continue;
480 }
481
copySubTextureImpl(ContextVk * contextVk,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::InternalFormat & destFormat,size_t sourceLevel,const gl::Rectangle & sourceArea,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,TextureVk * source)482 angle::Result TextureVk::copySubTextureImpl(ContextVk *contextVk,
483 const gl::ImageIndex &index,
484 const gl::Offset &destOffset,
485 const gl::InternalFormat &destFormat,
486 size_t sourceLevel,
487 const gl::Rectangle &sourceArea,
488 bool unpackFlipY,
489 bool unpackPremultiplyAlpha,
490 bool unpackUnmultiplyAlpha,
491 TextureVk *source)
492 {
493 RendererVk *renderer = contextVk->getRenderer();
494
495 ANGLE_TRY(source->ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
496
497 const vk::Format &sourceVkFormat = source->getImage().getFormat();
498 const vk::Format &destVkFormat = renderer->getFormat(destFormat.sizedInternalFormat);
499
500 const gl::ImageIndex offsetImageIndex = getNativeImageIndex(index);
501
502 // If it's possible to perform the copy with a transfer, that's the best option.
503 if (!unpackFlipY && !unpackPremultiplyAlpha && !unpackUnmultiplyAlpha &&
504 CanCopyWithTransfer(renderer, sourceVkFormat, destVkFormat))
505 {
506 return copySubImageImplWithTransfer(contextVk, offsetImageIndex, destOffset, destVkFormat,
507 sourceLevel, 0, sourceArea, &source->getImage());
508 }
509
510 bool forceCPUPath =
511 (destFormat.colorEncoding == GL_SRGB) || ForceCPUPathForCopy(renderer, *mImage);
512
513 // If it's possible to perform the copy with a draw call, do that.
514 if (CanCopyWithDraw(renderer, sourceVkFormat, destVkFormat) && !forceCPUPath)
515 {
516 return copySubImageImplWithDraw(
517 contextVk, offsetImageIndex, destOffset, destVkFormat, sourceLevel, sourceArea, false,
518 unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha, &source->getImage(),
519 &source->getFetchImageViewAndRecordUse(contextVk));
520 }
521
522 if (sourceLevel != 0)
523 {
524 WARN() << "glCopyTextureCHROMIUM with sourceLevel != 0 not implemented.";
525 return angle::Result::Stop;
526 }
527
528 // Read back the requested region of the source texture
529 uint8_t *sourceData = nullptr;
530 gl::Box area(sourceArea.x, sourceArea.y, 0, sourceArea.width, sourceArea.height, 1);
531 ANGLE_TRY(
532 source->copyImageDataToBufferAndGetData(contextVk, sourceLevel, 1, area, &sourceData));
533
534 const angle::Format &sourceTextureFormat = sourceVkFormat.actualImageFormat();
535 const angle::Format &destTextureFormat = destVkFormat.actualImageFormat();
536 size_t destinationAllocationSize =
537 sourceArea.width * sourceArea.height * destTextureFormat.pixelBytes;
538
539 // Allocate memory in the destination texture for the copy/conversion
540 uint8_t *destData = nullptr;
541 ANGLE_TRY(mImage->stageSubresourceUpdateAndGetData(
542 contextVk, destinationAllocationSize, offsetImageIndex,
543 gl::Extents(sourceArea.width, sourceArea.height, 1), destOffset, &destData));
544
545 // Source and dest data is tightly packed
546 GLuint sourceDataRowPitch = sourceArea.width * sourceTextureFormat.pixelBytes;
547 GLuint destDataRowPitch = sourceArea.width * destTextureFormat.pixelBytes;
548
549 rx::PixelReadFunction pixelReadFunction = sourceTextureFormat.pixelReadFunction;
550 rx::PixelWriteFunction pixelWriteFunction = destTextureFormat.pixelWriteFunction;
551
552 // Fix up the read/write functions for the sake of luminance/alpha that are emulated with
553 // formats whose channels don't correspond to the original format (alpha is emulated with red,
554 // and luminance/alpha is emulated with red/green).
555 if (sourceVkFormat.intendedFormat().isLUMA())
556 {
557 pixelReadFunction = sourceVkFormat.intendedFormat().pixelReadFunction;
558 }
559 if (destVkFormat.intendedFormat().isLUMA())
560 {
561 pixelWriteFunction = destVkFormat.intendedFormat().pixelWriteFunction;
562 }
563
564 CopyImageCHROMIUM(sourceData, sourceDataRowPitch, sourceTextureFormat.pixelBytes, 0,
565 pixelReadFunction, destData, destDataRowPitch, destTextureFormat.pixelBytes,
566 0, pixelWriteFunction, destFormat.format, destFormat.componentType,
567 sourceArea.width, sourceArea.height, 1, unpackFlipY, unpackPremultiplyAlpha,
568 unpackUnmultiplyAlpha);
569
570 return angle::Result::Continue;
571 }
572
copySubImageImplWithTransfer(ContextVk * contextVk,const gl::ImageIndex & index,const gl::Offset & destOffset,const vk::Format & destFormat,size_t sourceLevel,size_t sourceLayer,const gl::Rectangle & sourceArea,vk::ImageHelper * srcImage)573 angle::Result TextureVk::copySubImageImplWithTransfer(ContextVk *contextVk,
574 const gl::ImageIndex &index,
575 const gl::Offset &destOffset,
576 const vk::Format &destFormat,
577 size_t sourceLevel,
578 size_t sourceLayer,
579 const gl::Rectangle &sourceArea,
580 vk::ImageHelper *srcImage)
581 {
582 RendererVk *renderer = contextVk->getRenderer();
583
584 uint32_t level = index.getLevelIndex();
585 uint32_t baseLayer = index.hasLayer() ? index.getLayerIndex() : 0;
586 uint32_t layerCount = index.getLayerCount();
587 gl::Offset srcOffset = {sourceArea.x, sourceArea.y, 0};
588 gl::Extents extents = {sourceArea.width, sourceArea.height, 1};
589
590 // Change source layout if necessary
591 ANGLE_TRY(
592 contextVk->onImageRead(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::TransferSrc, srcImage));
593
594 VkImageSubresourceLayers srcSubresource = {};
595 srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
596 srcSubresource.mipLevel = static_cast<uint32_t>(sourceLevel);
597 srcSubresource.baseArrayLayer = static_cast<uint32_t>(sourceLayer);
598 srcSubresource.layerCount = layerCount;
599
600 if (srcImage->getExtents().depth > 1)
601 {
602 srcOffset.z = srcSubresource.baseArrayLayer;
603 Set3DBaseArrayLayerAndLayerCount(&srcSubresource);
604 }
605
606 // If destination is valid, copy the source directly into it.
607 if (mImage->valid())
608 {
609 // Make sure any updates to the image are already flushed.
610 ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
611
612 vk::CommandBuffer *commandBuffer;
613 ANGLE_TRY(contextVk->onImageWrite(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::TransferDst,
614 mImage));
615 ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
616
617 VkImageSubresourceLayers destSubresource = srcSubresource;
618 destSubresource.mipLevel = level;
619 destSubresource.baseArrayLayer = baseLayer;
620
621 VkImageType imageType = gl_vk::GetImageType(mState.getType());
622 if (imageType == VK_IMAGE_TYPE_3D)
623 {
624 Set3DBaseArrayLayerAndLayerCount(&destSubresource);
625 }
626
627 vk::ImageHelper::Copy(srcImage, mImage, srcOffset, destOffset, extents, srcSubresource,
628 destSubresource, commandBuffer);
629 }
630 else
631 {
632 std::unique_ptr<vk::ImageHelper> stagingImage;
633
634 // Create a temporary image to stage the copy
635 stagingImage = std::make_unique<vk::ImageHelper>();
636
637 ANGLE_TRY(stagingImage->init2DStaging(contextVk, renderer->getMemoryProperties(),
638 gl::Extents(sourceArea.width, sourceArea.height, 1),
639 destFormat, kTransferStagingImageFlags, layerCount));
640
641 vk::CommandBuffer *commandBuffer;
642 ANGLE_TRY(contextVk->onImageWrite(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::TransferDst,
643 stagingImage.get()));
644 ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
645
646 VkImageSubresourceLayers destSubresource = srcSubresource;
647 destSubresource.mipLevel = 0;
648 destSubresource.baseArrayLayer = 0;
649
650 vk::ImageHelper::Copy(srcImage, stagingImage.get(), srcOffset, gl::Offset(), extents,
651 srcSubresource, destSubresource, commandBuffer);
652
653 // Stage the copy for when the image storage is actually created.
654 VkImageType imageType = gl_vk::GetImageType(mState.getType());
655 mImage->stageSubresourceUpdateFromImage(stagingImage.release(), index, destOffset, extents,
656 imageType);
657 }
658
659 return angle::Result::Continue;
660 }
661
copySubImageImplWithDraw(ContextVk * contextVk,const gl::ImageIndex & index,const gl::Offset & destOffset,const vk::Format & destFormat,size_t sourceLevel,const gl::Rectangle & sourceArea,bool isSrcFlipY,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,vk::ImageHelper * srcImage,const vk::ImageView * srcView)662 angle::Result TextureVk::copySubImageImplWithDraw(ContextVk *contextVk,
663 const gl::ImageIndex &index,
664 const gl::Offset &destOffset,
665 const vk::Format &destFormat,
666 size_t sourceLevel,
667 const gl::Rectangle &sourceArea,
668 bool isSrcFlipY,
669 bool unpackFlipY,
670 bool unpackPremultiplyAlpha,
671 bool unpackUnmultiplyAlpha,
672 vk::ImageHelper *srcImage,
673 const vk::ImageView *srcView)
674 {
675 RendererVk *renderer = contextVk->getRenderer();
676 UtilsVk &utilsVk = contextVk->getUtils();
677
678 UtilsVk::CopyImageParameters params;
679 params.srcOffset[0] = sourceArea.x;
680 params.srcOffset[1] = sourceArea.y;
681 params.srcExtents[0] = sourceArea.width;
682 params.srcExtents[1] = sourceArea.height;
683 params.destOffset[0] = destOffset.x;
684 params.destOffset[1] = destOffset.y;
685 params.srcMip = static_cast<uint32_t>(sourceLevel);
686 params.srcHeight = srcImage->getExtents().height;
687 params.srcPremultiplyAlpha = unpackPremultiplyAlpha && !unpackUnmultiplyAlpha;
688 params.srcUnmultiplyAlpha = unpackUnmultiplyAlpha && !unpackPremultiplyAlpha;
689 params.srcFlipY = isSrcFlipY;
690 params.destFlipY = unpackFlipY;
691
692 uint32_t level = index.getLevelIndex();
693 uint32_t baseLayer = index.hasLayer() ? index.getLayerIndex() : 0;
694 uint32_t layerCount = index.getLayerCount();
695
696 // If destination is valid, copy the source directly into it.
697 if (mImage->valid())
698 {
699 // Make sure any updates to the image are already flushed.
700 ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
701
702 for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex)
703 {
704 params.srcLayer = layerIndex;
705
706 const vk::ImageView *destView;
707 ANGLE_TRY(getLevelLayerImageView(contextVk, level, baseLayer + layerIndex, &destView));
708
709 ANGLE_TRY(utilsVk.copyImage(contextVk, mImage, destView, srcImage, srcView, params));
710 }
711 }
712 else
713 {
714 std::unique_ptr<vk::ImageHelper> stagingImage;
715
716 GLint samples = srcImage->getSamples();
717 gl::TextureType stagingTextureType = vk::Get2DTextureType(layerCount, samples);
718
719 // Create a temporary image to stage the copy
720 stagingImage = std::make_unique<vk::ImageHelper>();
721
722 ANGLE_TRY(stagingImage->init2DStaging(contextVk, renderer->getMemoryProperties(),
723 gl::Extents(sourceArea.width, sourceArea.height, 1),
724 destFormat, kDrawStagingImageFlags, layerCount));
725
726 params.destOffset[0] = 0;
727 params.destOffset[1] = 0;
728
729 for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex)
730 {
731 params.srcLayer = layerIndex;
732
733 // Create a temporary view for this layer.
734 vk::ImageView stagingView;
735 ANGLE_TRY(stagingImage->initLayerImageView(
736 contextVk, stagingTextureType, VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(),
737 &stagingView, 0, 1, layerIndex, 1));
738
739 ANGLE_TRY(utilsVk.copyImage(contextVk, stagingImage.get(), &stagingView, srcImage,
740 srcView, params));
741
742 // Queue the resource for cleanup as soon as the copy above is finished. There's no
743 // need to keep it around.
744 contextVk->addGarbage(&stagingView);
745 }
746
747 // Stage the copy for when the image storage is actually created.
748 VkImageType imageType = gl_vk::GetImageType(mState.getType());
749 mImage->stageSubresourceUpdateFromImage(stagingImage.release(), index, destOffset,
750 gl::Extents(sourceArea.width, sourceArea.height, 1),
751 imageType);
752 }
753
754 return angle::Result::Continue;
755 }
756
setStorage(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size)757 angle::Result TextureVk::setStorage(const gl::Context *context,
758 gl::TextureType type,
759 size_t levels,
760 GLenum internalFormat,
761 const gl::Extents &size)
762 {
763 return setStorageMultisample(context, type, 1, internalFormat, size, true);
764 }
765
setStorageMultisample(const gl::Context * context,gl::TextureType type,GLsizei samples,GLint internalformat,const gl::Extents & size,bool fixedSampleLocations)766 angle::Result TextureVk::setStorageMultisample(const gl::Context *context,
767 gl::TextureType type,
768 GLsizei samples,
769 GLint internalformat,
770 const gl::Extents &size,
771 bool fixedSampleLocations)
772 {
773 ContextVk *contextVk = GetAs<ContextVk>(context->getImplementation());
774 RendererVk *renderer = contextVk->getRenderer();
775
776 if (!mOwnsImage)
777 {
778 releaseAndDeleteImage(contextVk);
779 }
780
781 const vk::Format &format = renderer->getFormat(internalformat);
782 ANGLE_TRY(ensureImageAllocated(contextVk, format));
783
784 if (mImage->valid())
785 {
786 releaseImage(contextVk);
787 }
788 return angle::Result::Continue;
789 }
790
setStorageExternalMemory(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size,gl::MemoryObject * memoryObject,GLuint64 offset)791 angle::Result TextureVk::setStorageExternalMemory(const gl::Context *context,
792 gl::TextureType type,
793 size_t levels,
794 GLenum internalFormat,
795 const gl::Extents &size,
796 gl::MemoryObject *memoryObject,
797 GLuint64 offset)
798 {
799 ContextVk *contextVk = vk::GetImpl(context);
800 RendererVk *renderer = contextVk->getRenderer();
801 MemoryObjectVk *memoryObjectVk = vk::GetImpl(memoryObject);
802
803 releaseAndDeleteImage(contextVk);
804
805 const vk::Format &format = renderer->getFormat(internalFormat);
806
807 setImageHelper(contextVk, new vk::ImageHelper(), mState.getType(), format, 0, 0, 0, true);
808
809 ANGLE_TRY(
810 memoryObjectVk->createImage(contextVk, type, levels, internalFormat, size, offset, mImage));
811
812 gl::Format glFormat(internalFormat);
813 ANGLE_TRY(initImageViews(contextVk, format, glFormat.info->sized, static_cast<uint32_t>(levels),
814 mImage->getLayerCount()));
815
816 return angle::Result::Continue;
817 }
818
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)819 angle::Result TextureVk::setEGLImageTarget(const gl::Context *context,
820 gl::TextureType type,
821 egl::Image *image)
822 {
823 ContextVk *contextVk = vk::GetImpl(context);
824 RendererVk *renderer = contextVk->getRenderer();
825
826 releaseAndDeleteImage(contextVk);
827
828 const vk::Format &format = renderer->getFormat(image->getFormat().info->sizedInternalFormat);
829
830 ImageVk *imageVk = vk::GetImpl(image);
831 setImageHelper(contextVk, imageVk->getImage(), imageVk->getImageTextureType(), format,
832 imageVk->getImageLevel(), imageVk->getImageLayer(),
833 mState.getEffectiveBaseLevel(), false);
834
835 ASSERT(type != gl::TextureType::CubeMap);
836 ANGLE_TRY(initImageViews(contextVk, format, image->getFormat().info->sized, 1, 1));
837
838 // Transfer the image to this queue if needed
839 uint32_t rendererQueueFamilyIndex = renderer->getQueueFamilyIndex();
840 if (mImage->isQueueChangeNeccesary(rendererQueueFamilyIndex))
841 {
842 vk::CommandBuffer *commandBuffer = nullptr;
843 ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
844 mImage->changeLayoutAndQueue(VK_IMAGE_ASPECT_COLOR_BIT,
845 vk::ImageLayout::AllGraphicsShadersReadOnly,
846 rendererQueueFamilyIndex, commandBuffer);
847 }
848
849 return angle::Result::Continue;
850 }
851
setImageExternal(const gl::Context * context,gl::TextureType type,egl::Stream * stream,const egl::Stream::GLTextureDescription & desc)852 angle::Result TextureVk::setImageExternal(const gl::Context *context,
853 gl::TextureType type,
854 egl::Stream *stream,
855 const egl::Stream::GLTextureDescription &desc)
856 {
857 ANGLE_VK_UNREACHABLE(vk::GetImpl(context));
858 return angle::Result::Stop;
859 }
860
getNativeImageIndex(const gl::ImageIndex & inputImageIndex) const861 gl::ImageIndex TextureVk::getNativeImageIndex(const gl::ImageIndex &inputImageIndex) const
862 {
863 // The input index can be a specific layer (for cube maps, 2d arrays, etc) or mImageLayerOffset
864 // can be non-zero but both of these cannot be true at the same time. EGL images can source
865 // from a cube map or 3D texture but can only be a 2D destination.
866 ASSERT(!(inputImageIndex.hasLayer() && mImageLayerOffset > 0));
867
868 // handle the special-case where image index can represent a whole level of a texture
869 GLint resultImageLayer = inputImageIndex.getLayerIndex();
870 if (inputImageIndex.getType() != mImageNativeType)
871 {
872 ASSERT(!inputImageIndex.hasLayer());
873 resultImageLayer = mImageLayerOffset;
874 }
875
876 return gl::ImageIndex::MakeFromType(mImageNativeType,
877 getNativeImageLevel(inputImageIndex.getLevelIndex()),
878 resultImageLayer, inputImageIndex.getLayerCount());
879 }
880
getNativeImageLevel(uint32_t frontendLevel) const881 uint32_t TextureVk::getNativeImageLevel(uint32_t frontendLevel) const
882 {
883 return mImageLevelOffset + frontendLevel;
884 }
885
getNativeImageLayer(uint32_t frontendLayer) const886 uint32_t TextureVk::getNativeImageLayer(uint32_t frontendLayer) const
887 {
888 return mImageLayerOffset + frontendLayer;
889 }
890
releaseAndDeleteImage(ContextVk * contextVk)891 void TextureVk::releaseAndDeleteImage(ContextVk *contextVk)
892 {
893 if (mImage)
894 {
895 releaseImage(contextVk);
896 releaseStagingBuffer(contextVk);
897 mImageObserverBinding.bind(nullptr);
898 SafeDelete(mImage);
899 }
900 }
901
ensureImageAllocated(ContextVk * contextVk,const vk::Format & format)902 angle::Result TextureVk::ensureImageAllocated(ContextVk *contextVk, const vk::Format &format)
903 {
904 if (mImage == nullptr)
905 {
906 setImageHelper(contextVk, new vk::ImageHelper(), mState.getType(), format, 0, 0, 0, true);
907 }
908 else
909 {
910 updateImageHelper(contextVk, format);
911 }
912
913 mImageUsageFlags = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
914 VK_IMAGE_USAGE_SAMPLED_BIT;
915
916 // If the image has depth/stencil support, add those as possible usage.
917 if (contextVk->getRenderer()->hasImageFormatFeatureBits(
918 format.vkImageFormat, VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT))
919 {
920 mImageUsageFlags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
921 }
922 else if (contextVk->getRenderer()->hasImageFormatFeatureBits(
923 format.vkImageFormat, VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT))
924 {
925 mImageUsageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
926 }
927
928 return angle::Result::Continue;
929 }
930
setImageHelper(ContextVk * contextVk,vk::ImageHelper * imageHelper,gl::TextureType imageType,const vk::Format & format,uint32_t imageLevelOffset,uint32_t imageLayerOffset,uint32_t imageBaseLevel,bool selfOwned)931 void TextureVk::setImageHelper(ContextVk *contextVk,
932 vk::ImageHelper *imageHelper,
933 gl::TextureType imageType,
934 const vk::Format &format,
935 uint32_t imageLevelOffset,
936 uint32_t imageLayerOffset,
937 uint32_t imageBaseLevel,
938 bool selfOwned)
939 {
940 ASSERT(mImage == nullptr);
941
942 mImageObserverBinding.bind(imageHelper);
943
944 mOwnsImage = selfOwned;
945 mImageNativeType = imageType;
946 mImageLevelOffset = imageLevelOffset;
947 mImageLayerOffset = imageLayerOffset;
948 mImage = imageHelper;
949 mImage->initStagingBuffer(contextVk->getRenderer(), format, vk::kStagingBufferFlags,
950 mStagingBufferInitialSize);
951
952 // Force re-creation of render targets next time they are needed
953 for (RenderTargetVector &renderTargetLevels : mRenderTargets)
954 {
955 renderTargetLevels.clear();
956 }
957 mRenderTargets.clear();
958
959 mSerial = contextVk->generateTextureSerial();
960 }
961
updateImageHelper(ContextVk * contextVk,const vk::Format & format)962 void TextureVk::updateImageHelper(ContextVk *contextVk, const vk::Format &format)
963 {
964 ASSERT(mImage != nullptr);
965 mImage->initStagingBuffer(contextVk->getRenderer(), format, vk::kStagingBufferFlags,
966 mStagingBufferInitialSize);
967 }
968
redefineImage(const gl::Context * context,const gl::ImageIndex & index,const vk::Format & format,const gl::Extents & size)969 angle::Result TextureVk::redefineImage(const gl::Context *context,
970 const gl::ImageIndex &index,
971 const vk::Format &format,
972 const gl::Extents &size)
973 {
974 ContextVk *contextVk = vk::GetImpl(context);
975
976 if (!mOwnsImage)
977 {
978 releaseAndDeleteImage(contextVk);
979 }
980
981 if (mImage != nullptr)
982 {
983 // If there is any staged changes for this index, we can remove them since we're going to
984 // override them with this call.
985 uint32_t levelIndex = index.getLevelIndex();
986 uint32_t layerIndex = index.hasLayer() ? index.getLayerIndex() : 0;
987 mImage->removeStagedUpdates(contextVk, levelIndex, layerIndex);
988
989 if (mImage->valid())
990 {
991 // Calculate the expected size for the index we are defining. If the size is different
992 // from the given size, or the format is different, we are redefining the image so we
993 // must release it.
994 if (mImage->getFormat() != format || size != mImage->getSize(index))
995 {
996 releaseImage(contextVk);
997 }
998 }
999 }
1000
1001 if (!size.empty())
1002 {
1003 ANGLE_TRY(ensureImageAllocated(contextVk, format));
1004 }
1005
1006 return angle::Result::Continue;
1007 }
1008
copyImageDataToBufferAndGetData(ContextVk * contextVk,size_t sourceLevel,uint32_t layerCount,const gl::Box & sourceArea,uint8_t ** outDataPtr)1009 angle::Result TextureVk::copyImageDataToBufferAndGetData(ContextVk *contextVk,
1010 size_t sourceLevel,
1011 uint32_t layerCount,
1012 const gl::Box &sourceArea,
1013 uint8_t **outDataPtr)
1014 {
1015 ANGLE_TRACE_EVENT0("gpu.angle", "TextureVk::copyImageDataToBufferAndGetData");
1016
1017 // Make sure the source is initialized and it's images are flushed.
1018 ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
1019
1020 vk::BufferHelper *copyBuffer = nullptr;
1021 vk::StagingBufferOffsetArray sourceCopyOffsets = {0, 0};
1022 size_t bufferSize = 0;
1023
1024 ANGLE_TRY(mImage->copyImageDataToBuffer(contextVk, sourceLevel, layerCount, 0, sourceArea,
1025 ©Buffer, &bufferSize, &sourceCopyOffsets,
1026 outDataPtr));
1027
1028 // Explicitly finish. If new use cases arise where we don't want to block we can change this.
1029 ANGLE_TRY(contextVk->finishImpl());
1030
1031 return angle::Result::Continue;
1032 }
1033
copyBufferDataToImage(ContextVk * contextVk,vk::BufferHelper * srcBuffer,const gl::ImageIndex index,uint32_t rowLength,uint32_t imageHeight,const gl::Box & sourceArea,size_t offset)1034 angle::Result TextureVk::copyBufferDataToImage(ContextVk *contextVk,
1035 vk::BufferHelper *srcBuffer,
1036 const gl::ImageIndex index,
1037 uint32_t rowLength,
1038 uint32_t imageHeight,
1039 const gl::Box &sourceArea,
1040 size_t offset)
1041 {
1042 ANGLE_TRACE_EVENT0("gpu.angle", "TextureVk::copyBufferDataToImage");
1043
1044 // Vulkan Spec requires the bufferOffset to be a multiple of 4 for vkCmdCopyBufferToImage.
1045 ASSERT((offset & (kBufferOffsetMultiple - 1)) == 0);
1046
1047 GLuint layerCount = 0;
1048 GLuint layerIndex = 0;
1049 GetRenderTargetLayerCountAndIndex(mImage, index, &layerCount, &layerIndex);
1050
1051 // Make sure the source is initialized and its images are flushed.
1052 ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
1053
1054 vk::CommandBuffer *commandBuffer = nullptr;
1055 ANGLE_TRY(contextVk->onBufferTransferRead(srcBuffer));
1056 ANGLE_TRY(
1057 contextVk->onImageWrite(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::TransferDst, mImage));
1058 ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
1059
1060 VkBufferImageCopy region = {};
1061 region.bufferOffset = offset;
1062 region.bufferRowLength = rowLength;
1063 region.bufferImageHeight = imageHeight;
1064 region.imageExtent.width = sourceArea.width;
1065 region.imageExtent.height = sourceArea.height;
1066 region.imageExtent.depth = sourceArea.depth;
1067 region.imageOffset.x = sourceArea.x;
1068 region.imageOffset.y = sourceArea.y;
1069 region.imageOffset.z = sourceArea.z;
1070 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1071 region.imageSubresource.baseArrayLayer = layerIndex;
1072 region.imageSubresource.layerCount = 1;
1073 region.imageSubresource.mipLevel = static_cast<uint32_t>(index.getLevelIndex());
1074
1075 if (index.getType() == gl::TextureType::_2DArray)
1076 {
1077 region.imageExtent.depth = 1;
1078 region.imageSubresource.layerCount = sourceArea.depth;
1079 }
1080
1081 commandBuffer->copyBufferToImage(srcBuffer->getBuffer().getHandle(), mImage->getImage(),
1082 mImage->getCurrentLayout(), 1, ®ion);
1083
1084 return angle::Result::Continue;
1085 }
1086
generateMipmapsWithCPU(const gl::Context * context)1087 angle::Result TextureVk::generateMipmapsWithCPU(const gl::Context *context)
1088 {
1089 ContextVk *contextVk = vk::GetImpl(context);
1090
1091 const VkExtent3D baseLevelExtents = mImage->getExtents();
1092 uint32_t imageLayerCount = mImage->getLayerCount();
1093
1094 uint8_t *imageData = nullptr;
1095 gl::Box imageArea(0, 0, 0, baseLevelExtents.width, baseLevelExtents.height,
1096 baseLevelExtents.depth);
1097
1098 ANGLE_TRY(copyImageDataToBufferAndGetData(contextVk, mState.getEffectiveBaseLevel(),
1099 imageLayerCount, imageArea, &imageData));
1100
1101 const angle::Format &angleFormat = mImage->getFormat().actualImageFormat();
1102 GLuint sourceRowPitch = baseLevelExtents.width * angleFormat.pixelBytes;
1103 GLuint sourceDepthPitch = sourceRowPitch * baseLevelExtents.height;
1104 size_t baseLevelAllocationSize = sourceDepthPitch * baseLevelExtents.depth;
1105
1106 // We now have the base level available to be manipulated in the imageData pointer. Generate all
1107 // the missing mipmaps with the slow path. For each layer, use the copied data to generate all
1108 // the mips.
1109 for (GLuint layer = 0; layer < imageLayerCount; layer++)
1110 {
1111 size_t bufferOffset = layer * baseLevelAllocationSize;
1112
1113 ANGLE_TRY(generateMipmapLevelsWithCPU(
1114 contextVk, angleFormat, layer, mState.getEffectiveBaseLevel() + 1,
1115 mState.getMipmapMaxLevel(), baseLevelExtents.width, baseLevelExtents.height,
1116 baseLevelExtents.depth, sourceRowPitch, sourceDepthPitch, imageData + bufferOffset));
1117 }
1118
1119 vk::CommandBuffer *commandBuffer = nullptr;
1120 ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
1121 return mImage->flushStagedUpdates(contextVk, getNativeImageLevel(0), mImage->getLevelCount(),
1122 getNativeImageLayer(0), mImage->getLayerCount(),
1123 commandBuffer);
1124 }
1125
generateMipmap(const gl::Context * context)1126 angle::Result TextureVk::generateMipmap(const gl::Context *context)
1127 {
1128 ContextVk *contextVk = vk::GetImpl(context);
1129 RendererVk *renderer = contextVk->getRenderer();
1130 bool needRedefineImage = true;
1131
1132 const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
1133
1134 // Some data is pending, or the image has not been defined at all yet
1135 if (!mImage->valid())
1136 {
1137 // Let's initialize the image so we can generate the next levels.
1138 if (mImage->hasStagedUpdates())
1139 {
1140 ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::FullMipChain));
1141 ASSERT(mImage->valid());
1142 needRedefineImage = false;
1143 }
1144 else
1145 {
1146 // There is nothing to generate if there is nothing uploaded so far.
1147 return angle::Result::Continue;
1148 }
1149 }
1150
1151 // Check whether the image is already full mipmap
1152 if (mImage->getLevelCount() == getMipLevelCount(ImageMipLevels::FullMipChain) &&
1153 mImage->getBaseLevel() == mState.getEffectiveBaseLevel())
1154 {
1155 needRedefineImage = false;
1156 }
1157
1158 if (needRedefineImage)
1159 {
1160 // Flush update if needed.
1161 if (mImage->hasStagedUpdates())
1162 {
1163 vk::CommandBuffer *commandBuffer = nullptr;
1164 mImage->retain(&contextVk->getResourceUseList());
1165 ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
1166 ANGLE_TRY(mImage->flushStagedUpdates(contextVk, getNativeImageLevel(0),
1167 mImage->getLevelCount(), getNativeImageLayer(0),
1168 mImage->getLayerCount(), commandBuffer));
1169 }
1170
1171 // Redefine the images with mipmaps.
1172 // Copy image to the staging buffer and stage an update to the new one.
1173 ANGLE_TRY(copyAndStageImageSubresource(contextVk, baseLevelDesc, false,
1174 getNativeImageLayer(0), 0, mImage->getBaseLevel()));
1175
1176 // Release the origin image and recreate it with new mipmap counts.
1177 releaseImage(contextVk);
1178
1179 mImage->retain(&contextVk->getResourceUseList());
1180
1181 ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::FullMipChain));
1182 }
1183 // Check if the image supports blit. If it does, we can do the mipmap generation on the gpu
1184 // only.
1185 if (renderer->hasImageFormatFeatureBits(mImage->getFormat().vkImageFormat, kBlitFeatureFlags))
1186 {
1187 ANGLE_TRY(mImage->generateMipmapsWithBlit(
1188 contextVk, mState.getMipmapMaxLevel() - mState.getEffectiveBaseLevel()));
1189 }
1190 else
1191 {
1192 ANGLE_TRY(generateMipmapsWithCPU(context));
1193 }
1194
1195 return angle::Result::Continue;
1196 }
1197
copyAndStageImageSubresource(ContextVk * contextVk,const gl::ImageDesc & desc,bool ignoreLayerCount,uint32_t currentLayer,uint32_t sourceMipLevel,uint32_t stagingDstMipLevel)1198 angle::Result TextureVk::copyAndStageImageSubresource(ContextVk *contextVk,
1199 const gl::ImageDesc &desc,
1200 bool ignoreLayerCount,
1201 uint32_t currentLayer,
1202 uint32_t sourceMipLevel,
1203 uint32_t stagingDstMipLevel)
1204 {
1205 const gl::Extents &baseLevelExtents = desc.size;
1206
1207 VkExtent3D updatedExtents;
1208 VkOffset3D offset = {};
1209 uint32_t layerCount;
1210 gl_vk::GetExtentsAndLayerCount(mState.getType(), baseLevelExtents, &updatedExtents,
1211 &layerCount);
1212 gl::Box area(offset.x, offset.y, offset.z, updatedExtents.width, updatedExtents.height,
1213 updatedExtents.depth);
1214 // TODO: Refactor TextureVk::respecifyImageAttributesAndLevels() to avoid this workaround.
1215 if (ignoreLayerCount)
1216 {
1217 layerCount = 1;
1218 }
1219
1220 // Copy from the base level image to the staging buffer
1221 vk::BufferHelper *stagingBuffer = nullptr;
1222 vk::StagingBufferOffsetArray stagingBufferOffsets = {0, 0};
1223 size_t bufferSize = 0;
1224 ANGLE_TRY(mImage->copyImageDataToBuffer(contextVk, sourceMipLevel, layerCount, currentLayer,
1225 area, &stagingBuffer, &bufferSize,
1226 &stagingBufferOffsets, nullptr));
1227
1228 // Stage an update to the new image
1229 ASSERT(stagingBuffer);
1230 uint32_t bufferRowLength = updatedExtents.width;
1231 uint32_t bufferImageHeight = updatedExtents.height;
1232 if (desc.format.info->compressed)
1233 {
1234 // In the case of a compressed texture, bufferRowLength can never be smaller than the
1235 // compressed format's compressed block width, and bufferImageHeight can never be smaller
1236 // than the compressed block height.
1237 bufferRowLength = std::max(bufferRowLength, desc.format.info->compressedBlockWidth);
1238 bufferImageHeight = std::max(bufferImageHeight, desc.format.info->compressedBlockHeight);
1239 }
1240 ANGLE_TRY(mImage->stageSubresourceUpdateFromBuffer(
1241 contextVk, bufferSize, stagingDstMipLevel, currentLayer, layerCount, bufferRowLength,
1242 bufferImageHeight, updatedExtents, offset, stagingBuffer, stagingBufferOffsets));
1243
1244 return angle::Result::Continue;
1245 }
1246
setBaseLevel(const gl::Context * context,GLuint baseLevel)1247 angle::Result TextureVk::setBaseLevel(const gl::Context *context, GLuint baseLevel)
1248 {
1249 return angle::Result::Continue;
1250 }
1251
updateBaseMaxLevels(ContextVk * contextVk,GLuint baseLevel,GLuint maxLevel)1252 angle::Result TextureVk::updateBaseMaxLevels(ContextVk *contextVk,
1253 GLuint baseLevel,
1254 GLuint maxLevel)
1255 {
1256 if (!mImage)
1257 {
1258 return angle::Result::Continue;
1259 }
1260
1261 // Track the previous levels for use in update loop below
1262 uint32_t previousBaseLevel = mImage->getBaseLevel();
1263
1264 bool baseLevelChanged = baseLevel != previousBaseLevel;
1265 bool maxLevelChanged = (mImage->getLevelCount() + previousBaseLevel) != (maxLevel + 1);
1266
1267 if (!(baseLevelChanged || maxLevelChanged))
1268 {
1269 // This scenario is a noop, most likely maxLevel has been lowered to a level that already
1270 // reflects the current state of the image
1271 return angle::Result::Continue;
1272 }
1273
1274 if (!mImage->valid())
1275 {
1276 // Track the levels in our ImageHelper
1277 mImage->setBaseAndMaxLevels(baseLevel, maxLevel);
1278
1279 // No further work to do, let staged updates handle the new levels
1280 return angle::Result::Continue;
1281 }
1282
1283 return respecifyImageAttributesAndLevels(contextVk, previousBaseLevel, baseLevel, maxLevel);
1284 }
1285
respecifyImageAttributes(ContextVk * contextVk)1286 angle::Result TextureVk::respecifyImageAttributes(ContextVk *contextVk)
1287 {
1288 return respecifyImageAttributesAndLevels(contextVk, mImage->getBaseLevel(),
1289 mState.getEffectiveBaseLevel(),
1290 mState.getEffectiveMaxLevel());
1291 }
respecifyImageAttributesAndLevels(ContextVk * contextVk,GLuint previousBaseLevel,GLuint baseLevel,GLuint maxLevel)1292 angle::Result TextureVk::respecifyImageAttributesAndLevels(ContextVk *contextVk,
1293 GLuint previousBaseLevel,
1294 GLuint baseLevel,
1295 GLuint maxLevel)
1296 {
1297 // Recreate the image to reflect new base or max levels.
1298 // First, flush any pending updates so we have good data in the existing vkImage
1299 if (mImage->valid() && mImage->hasStagedUpdates())
1300 {
1301 vk::CommandBuffer *commandBuffer = nullptr;
1302 ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
1303 ANGLE_TRY(mImage->flushStagedUpdates(contextVk, getNativeImageLevel(0),
1304 mImage->getLevelCount(), getNativeImageLayer(0),
1305 mImage->getLayerCount(), commandBuffer));
1306 }
1307
1308 bool baseLevelChanged = baseLevel != previousBaseLevel;
1309
1310 // After flushing, track the new levels (they are used in the flush, hence the wait)
1311 mImage->setBaseAndMaxLevels(baseLevel, maxLevel);
1312
1313 // Next, back up any data we need to preserve by staging it as updates to the new image.
1314
1315 // Stage updates for all levels in the GL texture, while preserving the data in the vkImage.
1316 // This ensures we propagate all the current image data, even as max level moves around.
1317 uint32_t updateCount =
1318 std::max<GLuint>(mState.getMipmapMaxLevel() + 1, mImage->getLevelCount());
1319
1320 // The staged updates won't be applied until the image has the requisite mip levels
1321 for (uint32_t layer = 0; layer < mImage->getLayerCount(); layer++)
1322 {
1323 for (uint32_t level = 0; level < updateCount; level++)
1324 {
1325 if (mImage->isUpdateStaged(level, layer))
1326 {
1327 // If there is still an update staged for the surface at the designated
1328 // layer/level, we don't need to propagate any data from this image.
1329 // This can happen for original texture levels that have never fit into
1330 // the vkImage due to base/max level, and for vkImage data that has been
1331 // staged by previous calls to respecifyImageAttributesAndLevels that didn't fit
1332 // into the new vkImage.
1333 continue;
1334 }
1335
1336 // Pull data from the current image and stage it as an update for the new image
1337
1338 // First we populate the staging buffer with current level data
1339 const gl::ImageDesc &desc =
1340 mState.getImageDesc(gl::TextureTypeToTarget(mState.getType(), layer), level);
1341
1342 // We need to adjust the source Vulkan level to reflect the previous base level.
1343 // vk level 0 previously aligned with whatever the base level was.
1344 uint32_t srcLevelVK = baseLevelChanged ? level - previousBaseLevel : level;
1345 ASSERT(srcLevelVK <= mImage->getLevelCount());
1346
1347 ANGLE_TRY(
1348 copyAndStageImageSubresource(contextVk, desc, true, layer, srcLevelVK, level));
1349 }
1350 }
1351
1352 // Now that we've staged all the updates, release the current image so that it will be
1353 // recreated with the correct number of mip levels, base level, and max level.
1354 releaseImage(contextVk);
1355
1356 mImage->retain(&contextVk->getResourceUseList());
1357
1358 return angle::Result::Continue;
1359 }
1360
bindTexImage(const gl::Context * context,egl::Surface * surface)1361 angle::Result TextureVk::bindTexImage(const gl::Context *context, egl::Surface *surface)
1362 {
1363 ContextVk *contextVk = vk::GetImpl(context);
1364 RendererVk *renderer = contextVk->getRenderer();
1365
1366 releaseAndDeleteImage(contextVk);
1367
1368 GLenum internalFormat = surface->getConfig()->renderTargetFormat;
1369 const vk::Format &format = renderer->getFormat(internalFormat);
1370
1371 // eglBindTexImage can only be called with pbuffer (offscreen) surfaces
1372 OffscreenSurfaceVk *offscreenSurface = GetImplAs<OffscreenSurfaceVk>(surface);
1373 setImageHelper(contextVk, offscreenSurface->getColorAttachmentImage(), mState.getType(), format,
1374 surface->getMipmapLevel(), 0, mState.getEffectiveBaseLevel(), false);
1375
1376 ASSERT(mImage->getLayerCount() == 1);
1377 gl::Format glFormat(internalFormat);
1378 return initImageViews(contextVk, format, glFormat.info->sized, 1, 1);
1379 }
1380
releaseTexImage(const gl::Context * context)1381 angle::Result TextureVk::releaseTexImage(const gl::Context *context)
1382 {
1383 ContextVk *contextVk = vk::GetImpl(context);
1384
1385 releaseImage(contextVk);
1386
1387 return angle::Result::Continue;
1388 }
1389
getAttachmentRenderTarget(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex,GLsizei samples,FramebufferAttachmentRenderTarget ** rtOut)1390 angle::Result TextureVk::getAttachmentRenderTarget(const gl::Context *context,
1391 GLenum binding,
1392 const gl::ImageIndex &imageIndex,
1393 GLsizei samples,
1394 FramebufferAttachmentRenderTarget **rtOut)
1395 {
1396 ASSERT(imageIndex.getLevelIndex() >= 0);
1397
1398 ContextVk *contextVk = vk::GetImpl(context);
1399
1400 if (!mImage->valid())
1401 {
1402 const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
1403 const gl::Extents &baseLevelExtents = baseLevelDesc.size;
1404 const uint32_t levelCount = getMipLevelCount(ImageMipLevels::EnabledLevels);
1405 const vk::Format &format = getBaseLevelFormat(contextVk->getRenderer());
1406
1407 ANGLE_TRY(initImage(contextVk, format, baseLevelDesc.format.info->sized, baseLevelExtents,
1408 levelCount));
1409 }
1410
1411 // Don't flush staged updates here. We'll handle that in FramebufferVk so it can defer clears.
1412
1413 GLuint layerIndex = 0, layerCount = 0;
1414 GetRenderTargetLayerCountAndIndex(mImage, imageIndex, &layerCount, &layerIndex);
1415
1416 ANGLE_TRY(initRenderTargets(contextVk, layerCount, imageIndex.getLevelIndex()));
1417
1418 ASSERT(imageIndex.getLevelIndex() < static_cast<int32_t>(mRenderTargets.size()));
1419 *rtOut = &mRenderTargets[imageIndex.getLevelIndex()][layerIndex];
1420
1421 return angle::Result::Continue;
1422 }
1423
ensureImageInitialized(ContextVk * contextVk,ImageMipLevels mipLevels)1424 angle::Result TextureVk::ensureImageInitialized(ContextVk *contextVk, ImageMipLevels mipLevels)
1425 {
1426 const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
1427 const gl::Extents &baseLevelExtents = baseLevelDesc.size;
1428 const uint32_t levelCount = getMipLevelCount(mipLevels);
1429 const vk::Format &format = getBaseLevelFormat(contextVk->getRenderer());
1430 return ensureImageInitializedImpl(contextVk, baseLevelExtents, levelCount, format);
1431 }
1432
ensureImageInitializedImpl(ContextVk * contextVk,const gl::Extents & baseLevelExtents,uint32_t levelCount,const vk::Format & format)1433 angle::Result TextureVk::ensureImageInitializedImpl(ContextVk *contextVk,
1434 const gl::Extents &baseLevelExtents,
1435 uint32_t levelCount,
1436 const vk::Format &format)
1437 {
1438 if (mImage->valid() && !mImage->hasStagedUpdates())
1439 {
1440 return angle::Result::Continue;
1441 }
1442
1443 if (!mImage->valid())
1444 {
1445 const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
1446
1447 ANGLE_TRY(initImage(contextVk, format, baseLevelDesc.format.info->sized, baseLevelExtents,
1448 levelCount));
1449 }
1450
1451 vk::CommandBuffer *commandBuffer = nullptr;
1452 ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
1453 return mImage->flushStagedUpdates(contextVk, getNativeImageLevel(0), mImage->getLevelCount(),
1454 getNativeImageLayer(0), mImage->getLayerCount(),
1455 commandBuffer);
1456 }
1457
initRenderTargets(ContextVk * contextVk,GLuint layerCount,GLuint levelIndex)1458 angle::Result TextureVk::initRenderTargets(ContextVk *contextVk,
1459 GLuint layerCount,
1460 GLuint levelIndex)
1461 {
1462 if (mRenderTargets.size() <= levelIndex)
1463 {
1464 mRenderTargets.resize(levelIndex + 1);
1465 }
1466
1467 // Lazy init. Check if already initialized.
1468 if (!mRenderTargets[levelIndex].empty())
1469 return angle::Result::Continue;
1470
1471 mRenderTargets[levelIndex].resize(layerCount);
1472
1473 for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex)
1474 {
1475 mRenderTargets[levelIndex][layerIndex].init(
1476 mImage, &mImageViews, getNativeImageLevel(levelIndex), getNativeImageLayer(layerIndex));
1477 }
1478 return angle::Result::Continue;
1479 }
1480
syncState(const gl::Context * context,const gl::Texture::DirtyBits & dirtyBits)1481 angle::Result TextureVk::syncState(const gl::Context *context,
1482 const gl::Texture::DirtyBits &dirtyBits)
1483 {
1484 ContextVk *contextVk = vk::GetImpl(context);
1485
1486 VkImageUsageFlags oldUsageFlags = mImageUsageFlags;
1487 VkImageCreateFlags oldCreateFlags = mImageCreateFlags;
1488
1489 // Create a new image if the storage state is enabled for the first time.
1490 if (dirtyBits.test(gl::Texture::DIRTY_BIT_BOUND_AS_IMAGE))
1491 {
1492 // Recreate the image to include storage bit if needed.
1493 if (!(mImageUsageFlags & VK_IMAGE_USAGE_STORAGE_BIT))
1494 {
1495 mImageUsageFlags |= VK_IMAGE_USAGE_STORAGE_BIT;
1496 }
1497 }
1498
1499 if (dirtyBits.test(gl::Texture::DIRTY_BIT_SRGB_OVERRIDE))
1500 {
1501 if (!(mImageCreateFlags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) &&
1502 mState.getSRGBOverride() != gl::SrgbOverride::Default)
1503 {
1504 mImageCreateFlags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
1505 }
1506 }
1507
1508 if (oldUsageFlags != mImageUsageFlags || oldCreateFlags != mImageCreateFlags)
1509 {
1510 ANGLE_TRY(respecifyImageAttributes(contextVk));
1511 }
1512
1513 // Set base and max level before initializing the image
1514 if (dirtyBits.test(gl::Texture::DIRTY_BIT_MAX_LEVEL) ||
1515 dirtyBits.test(gl::Texture::DIRTY_BIT_BASE_LEVEL))
1516 {
1517 ANGLE_TRY(updateBaseMaxLevels(contextVk, mState.getEffectiveBaseLevel(),
1518 mState.getEffectiveMaxLevel()));
1519 }
1520
1521 // Initialize the image storage and flush the pixel buffer.
1522 ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
1523
1524 // Mask out the IMPLEMENTATION dirty bit to avoid unnecessary syncs.
1525 gl::Texture::DirtyBits localBits = dirtyBits;
1526 localBits.reset(gl::Texture::DIRTY_BIT_IMPLEMENTATION);
1527
1528 if (localBits.none() && mSampler.valid())
1529 {
1530 return angle::Result::Continue;
1531 }
1532
1533 RendererVk *renderer = contextVk->getRenderer();
1534 if (mSampler.valid())
1535 {
1536 mSampler.reset();
1537 }
1538
1539 if (localBits.test(gl::Texture::DIRTY_BIT_SWIZZLE_RED) ||
1540 localBits.test(gl::Texture::DIRTY_BIT_SWIZZLE_GREEN) ||
1541 localBits.test(gl::Texture::DIRTY_BIT_SWIZZLE_BLUE) ||
1542 localBits.test(gl::Texture::DIRTY_BIT_SWIZZLE_ALPHA) ||
1543 localBits.test(gl::Texture::DIRTY_BIT_SRGB_OVERRIDE))
1544 {
1545 if (mImage && mImage->valid())
1546 {
1547 // We use a special layer count here to handle EGLImages. They might only be
1548 // looking at one layer of a cube or 2D array texture.
1549 uint32_t layerCount =
1550 mState.getType() == gl::TextureType::_2D ? 1 : mImage->getLayerCount();
1551
1552 mImageViews.release(renderer);
1553 const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
1554
1555 ANGLE_TRY(initImageViews(contextVk, mImage->getFormat(),
1556 baseLevelDesc.format.info->sized, mImage->getLevelCount(),
1557 layerCount));
1558 }
1559 }
1560
1561 vk::SamplerDesc samplerDesc(mState.getSamplerState(), mState.isStencilMode());
1562 ANGLE_TRY(renderer->getSamplerCache().getSampler(contextVk, samplerDesc, &mSampler));
1563
1564 // Regenerate the serial on a sampler change.
1565 mSerial = contextVk->generateTextureSerial();
1566
1567 return angle::Result::Continue;
1568 }
1569
initializeContents(const gl::Context * context,const gl::ImageIndex & imageIndex)1570 angle::Result TextureVk::initializeContents(const gl::Context *context,
1571 const gl::ImageIndex &imageIndex)
1572 {
1573 ContextVk *contextVk = vk::GetImpl(context);
1574 const gl::ImageDesc &desc = mState.getImageDesc(imageIndex);
1575 const vk::Format &format =
1576 contextVk->getRenderer()->getFormat(desc.format.info->sizedInternalFormat);
1577
1578 ASSERT(mImage);
1579 // Note that we cannot ensure the image is initialized because we might be calling subImage
1580 // on a non-complete cube map.
1581 return mImage->stageRobustResourceClearWithFormat(contextVk, imageIndex, desc.size, format);
1582 }
1583
releaseOwnershipOfImage(const gl::Context * context)1584 void TextureVk::releaseOwnershipOfImage(const gl::Context *context)
1585 {
1586 ContextVk *contextVk = vk::GetImpl(context);
1587
1588 mOwnsImage = false;
1589 releaseAndDeleteImage(contextVk);
1590 }
1591
getReadImageViewAndRecordUse(ContextVk * contextVk) const1592 const vk::ImageView &TextureVk::getReadImageViewAndRecordUse(ContextVk *contextVk) const
1593 {
1594 ASSERT(mImage->valid());
1595
1596 mImageViews.retain(&contextVk->getResourceUseList());
1597
1598 if (mState.isStencilMode() && mImageViews.hasStencilReadImageView())
1599 {
1600 return mImageViews.getStencilReadImageView();
1601 }
1602
1603 if (mState.getSRGBOverride() == gl::SrgbOverride::Enabled)
1604 {
1605 ASSERT(mImageViews.getNonLinearReadImageView().valid());
1606 return mImageViews.getNonLinearReadImageView();
1607 }
1608
1609 return mImageViews.getReadImageView();
1610 }
1611
getFetchImageViewAndRecordUse(ContextVk * contextVk) const1612 const vk::ImageView &TextureVk::getFetchImageViewAndRecordUse(ContextVk *contextVk) const
1613 {
1614 ASSERT(mImage->valid());
1615
1616 mImageViews.retain(&contextVk->getResourceUseList());
1617
1618 // We don't currently support fetch for depth/stencil cube map textures.
1619 ASSERT(!mImageViews.hasStencilReadImageView() || !mImageViews.hasFetchImageView());
1620
1621 if (mState.getSRGBOverride() == gl::SrgbOverride::Enabled)
1622 {
1623 return (mImageViews.hasFetchImageView() ? mImageViews.getNonLinearFetchImageView()
1624 : mImageViews.getNonLinearReadImageView());
1625 }
1626
1627 return (mImageViews.hasFetchImageView() ? mImageViews.getFetchImageView()
1628 : mImageViews.getReadImageView());
1629 }
1630
getLevelLayerImageView(ContextVk * contextVk,size_t level,size_t layer,const vk::ImageView ** imageViewOut)1631 angle::Result TextureVk::getLevelLayerImageView(ContextVk *contextVk,
1632 size_t level,
1633 size_t layer,
1634 const vk::ImageView **imageViewOut)
1635 {
1636 ASSERT(mImage && mImage->valid());
1637
1638 uint32_t nativeLevel = getNativeImageLevel(static_cast<uint32_t>(level));
1639 uint32_t nativeLayer = getNativeImageLayer(static_cast<uint32_t>(layer));
1640
1641 return mImageViews.getLevelLayerDrawImageView(contextVk, *mImage, nativeLevel, nativeLayer,
1642 imageViewOut);
1643 }
1644
getStorageImageView(ContextVk * contextVk,bool allLayers,size_t level,size_t singleLayer,const vk::ImageView ** imageViewOut)1645 angle::Result TextureVk::getStorageImageView(ContextVk *contextVk,
1646 bool allLayers,
1647 size_t level,
1648 size_t singleLayer,
1649 const vk::ImageView **imageViewOut)
1650 {
1651 if (!allLayers)
1652 {
1653 return getLevelLayerImageView(contextVk, level, singleLayer, imageViewOut);
1654 }
1655
1656 uint32_t nativeLevel = getNativeImageLevel(static_cast<uint32_t>(level));
1657 uint32_t nativeLayer = getNativeImageLayer(0);
1658 return mImageViews.getLevelDrawImageView(contextVk, mState.getType(), *mImage, nativeLevel,
1659 nativeLayer, imageViewOut);
1660 }
1661
initImage(ContextVk * contextVk,const vk::Format & format,const bool sized,const gl::Extents & extents,const uint32_t levelCount)1662 angle::Result TextureVk::initImage(ContextVk *contextVk,
1663 const vk::Format &format,
1664 const bool sized,
1665 const gl::Extents &extents,
1666 const uint32_t levelCount)
1667 {
1668 RendererVk *renderer = contextVk->getRenderer();
1669
1670 VkExtent3D vkExtent;
1671 uint32_t layerCount;
1672 gl_vk::GetExtentsAndLayerCount(mState.getType(), extents, &vkExtent, &layerCount);
1673 GLint samples = mState.getBaseLevelDesc().samples ? mState.getBaseLevelDesc().samples : 1;
1674
1675 ANGLE_TRY(mImage->initExternal(
1676 contextVk, mState.getType(), vkExtent, format, samples, mImageUsageFlags, mImageCreateFlags,
1677 rx::vk::ImageLayout::Undefined, nullptr, mState.getEffectiveBaseLevel(),
1678 mState.getEffectiveMaxLevel(), levelCount, layerCount));
1679
1680 const VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
1681
1682 ANGLE_TRY(mImage->initMemory(contextVk, renderer->getMemoryProperties(), flags));
1683
1684 ANGLE_TRY(initImageViews(contextVk, format, sized, levelCount, layerCount));
1685
1686 mSerial = contextVk->generateTextureSerial();
1687
1688 return angle::Result::Continue;
1689 }
1690
initImageViews(ContextVk * contextVk,const vk::Format & format,const bool sized,uint32_t levelCount,uint32_t layerCount)1691 angle::Result TextureVk::initImageViews(ContextVk *contextVk,
1692 const vk::Format &format,
1693 const bool sized,
1694 uint32_t levelCount,
1695 uint32_t layerCount)
1696 {
1697 ASSERT(mImage != nullptr && mImage->valid());
1698
1699 // TODO(cnorthrop): May be missing non-zero base level http://anglebug.com/3948
1700 uint32_t baseLevel = getNativeImageLevel(0);
1701 uint32_t baseLayer = getNativeImageLayer(0);
1702
1703 gl::SwizzleState mappedSwizzle;
1704 MapSwizzleState(contextVk, format, sized, mState.getSwizzleState(), &mappedSwizzle);
1705
1706 ANGLE_TRY(mImageViews.initReadViews(contextVk, mState.getType(), *mImage, format, mappedSwizzle,
1707 baseLevel, levelCount, baseLayer, layerCount));
1708
1709 if ((mImageCreateFlags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) != 0)
1710 {
1711 ANGLE_TRY(mImageViews.initSRGBReadViews(contextVk, mState.getType(), *mImage, format,
1712 mappedSwizzle, baseLevel, levelCount, baseLayer,
1713 layerCount));
1714 }
1715
1716 return angle::Result::Continue;
1717 }
1718
releaseImage(ContextVk * contextVk)1719 void TextureVk::releaseImage(ContextVk *contextVk)
1720 {
1721 RendererVk *renderer = contextVk->getRenderer();
1722
1723 if (mImage)
1724 {
1725 if (mOwnsImage)
1726 {
1727 mImage->releaseImage(renderer);
1728 }
1729 else
1730 {
1731 mImageObserverBinding.bind(nullptr);
1732 mImage = nullptr;
1733 }
1734 }
1735
1736 mImageViews.release(renderer);
1737
1738 for (RenderTargetVector &renderTargetLevels : mRenderTargets)
1739 {
1740 // Clear the layers tracked for each level
1741 renderTargetLevels.clear();
1742 }
1743 // Then clear the levels
1744 mRenderTargets.clear();
1745
1746 onStateChange(angle::SubjectMessage::SubjectChanged);
1747 }
1748
releaseStagingBuffer(ContextVk * contextVk)1749 void TextureVk::releaseStagingBuffer(ContextVk *contextVk)
1750 {
1751 if (mImage)
1752 {
1753 mImage->releaseStagingBuffer(contextVk->getRenderer());
1754 }
1755 }
1756
getMipLevelCount(ImageMipLevels mipLevels) const1757 uint32_t TextureVk::getMipLevelCount(ImageMipLevels mipLevels) const
1758 {
1759 switch (mipLevels)
1760 {
1761 case ImageMipLevels::EnabledLevels:
1762 return mState.getEnabledLevelCount();
1763 case ImageMipLevels::FullMipChain:
1764 return getMaxLevelCount() - mState.getEffectiveBaseLevel();
1765
1766 default:
1767 UNREACHABLE();
1768 return 0;
1769 }
1770 }
1771
getMaxLevelCount() const1772 uint32_t TextureVk::getMaxLevelCount() const
1773 {
1774 // getMipmapMaxLevel will be 0 here if mipmaps are not used, so the levelCount is always +1.
1775 return mState.getMipmapMaxLevel() + 1;
1776 }
1777
generateMipmapLevelsWithCPU(ContextVk * contextVk,const angle::Format & sourceFormat,GLuint layer,GLuint firstMipLevel,GLuint maxMipLevel,const size_t sourceWidth,const size_t sourceHeight,const size_t sourceDepth,const size_t sourceRowPitch,const size_t sourceDepthPitch,uint8_t * sourceData)1778 angle::Result TextureVk::generateMipmapLevelsWithCPU(ContextVk *contextVk,
1779 const angle::Format &sourceFormat,
1780 GLuint layer,
1781 GLuint firstMipLevel,
1782 GLuint maxMipLevel,
1783 const size_t sourceWidth,
1784 const size_t sourceHeight,
1785 const size_t sourceDepth,
1786 const size_t sourceRowPitch,
1787 const size_t sourceDepthPitch,
1788 uint8_t *sourceData)
1789 {
1790 size_t previousLevelWidth = sourceWidth;
1791 size_t previousLevelHeight = sourceHeight;
1792 size_t previousLevelDepth = sourceDepth;
1793 uint8_t *previousLevelData = sourceData;
1794 size_t previousLevelRowPitch = sourceRowPitch;
1795 size_t previousLevelDepthPitch = sourceDepthPitch;
1796
1797 for (GLuint currentMipLevel = firstMipLevel; currentMipLevel <= maxMipLevel; currentMipLevel++)
1798 {
1799 // Compute next level width and height.
1800 size_t mipWidth = std::max<size_t>(1, previousLevelWidth >> 1);
1801 size_t mipHeight = std::max<size_t>(1, previousLevelHeight >> 1);
1802 size_t mipDepth = std::max<size_t>(1, previousLevelDepth >> 1);
1803
1804 // With the width and height of the next mip, we can allocate the next buffer we need.
1805 uint8_t *destData = nullptr;
1806 size_t destRowPitch = mipWidth * sourceFormat.pixelBytes;
1807 size_t destDepthPitch = destRowPitch * mipHeight;
1808
1809 size_t mipAllocationSize = destDepthPitch * mipDepth;
1810 gl::Extents mipLevelExtents(static_cast<int>(mipWidth), static_cast<int>(mipHeight),
1811 static_cast<int>(mipDepth));
1812
1813 ANGLE_TRY(mImage->stageSubresourceUpdateAndGetData(
1814 contextVk, mipAllocationSize,
1815 gl::ImageIndex::MakeFromType(mState.getType(), currentMipLevel, layer), mipLevelExtents,
1816 gl::Offset(), &destData));
1817
1818 // Generate the mipmap into that new buffer
1819 sourceFormat.mipGenerationFunction(
1820 previousLevelWidth, previousLevelHeight, previousLevelDepth, previousLevelData,
1821 previousLevelRowPitch, previousLevelDepthPitch, destData, destRowPitch, destDepthPitch);
1822
1823 // Swap for the next iteration
1824 previousLevelWidth = mipWidth;
1825 previousLevelHeight = mipHeight;
1826 previousLevelDepth = mipDepth;
1827 previousLevelData = destData;
1828 previousLevelRowPitch = destRowPitch;
1829 previousLevelDepthPitch = destDepthPitch;
1830 }
1831
1832 return angle::Result::Continue;
1833 }
1834
getImplementationSizedFormat(const gl::Context * context) const1835 const gl::InternalFormat &TextureVk::getImplementationSizedFormat(const gl::Context *context) const
1836 {
1837 GLenum sizedFormat = GL_NONE;
1838
1839 if (mImage && mImage->valid())
1840 {
1841 sizedFormat = mImage->getFormat().actualImageFormat().glInternalFormat;
1842 }
1843 else
1844 {
1845 ContextVk *contextVk = vk::GetImpl(context);
1846 const vk::Format &format = getBaseLevelFormat(contextVk->getRenderer());
1847 sizedFormat = format.actualImageFormat().glInternalFormat;
1848 }
1849
1850 return gl::GetSizedInternalFormatInfo(sizedFormat);
1851 }
1852
getColorReadFormat(const gl::Context * context)1853 GLenum TextureVk::getColorReadFormat(const gl::Context *context)
1854 {
1855 const gl::InternalFormat &sizedFormat = getImplementationSizedFormat(context);
1856 return sizedFormat.format;
1857 }
1858
getColorReadType(const gl::Context * context)1859 GLenum TextureVk::getColorReadType(const gl::Context *context)
1860 {
1861 const gl::InternalFormat &sizedFormat = getImplementationSizedFormat(context);
1862 return sizedFormat.type;
1863 }
1864
getTexImage(const gl::Context * context,const gl::PixelPackState & packState,gl::Buffer * packBuffer,gl::TextureTarget target,GLint level,GLenum format,GLenum type,void * pixels)1865 angle::Result TextureVk::getTexImage(const gl::Context *context,
1866 const gl::PixelPackState &packState,
1867 gl::Buffer *packBuffer,
1868 gl::TextureTarget target,
1869 GLint level,
1870 GLenum format,
1871 GLenum type,
1872 void *pixels)
1873 {
1874 ContextVk *contextVk = vk::GetImpl(context);
1875
1876 // Assumes Texture is consistent.
1877 // TODO(http://anglebug.com/4058): Handle incomplete textures.
1878 if (!mImage || !mImage->valid())
1879 {
1880 ANGLE_TRY(ensureImageInitialized(contextVk, ImageMipLevels::EnabledLevels));
1881 }
1882
1883 size_t layer =
1884 gl::IsCubeMapFaceTarget(target) ? gl::CubeMapTextureTargetToFaceIndex(target) : 0;
1885 return mImage->readPixelsForGetImage(contextVk, packState, packBuffer, level,
1886 static_cast<uint32_t>(layer), format, type, pixels);
1887 }
1888
getBaseLevelFormat(RendererVk * renderer) const1889 const vk::Format &TextureVk::getBaseLevelFormat(RendererVk *renderer) const
1890 {
1891 const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
1892 return renderer->getFormat(baseLevelDesc.format.info->sizedInternalFormat);
1893 }
1894
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)1895 void TextureVk::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
1896 {
1897 ASSERT(index == kTextureImageSubjectIndex && message == angle::SubjectMessage::SubjectChanged);
1898
1899 // Forward the notification to the parent that the staging buffer changed.
1900 onStateChange(angle::SubjectMessage::SubjectChanged);
1901 }
1902 } // namespace rx
1903