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