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
12 #include "common/debug.h"
13 #include "image_util/generatemip.inc"
14 #include "libANGLE/Config.h"
15 #include "libANGLE/Context.h"
16 #include "libANGLE/Image.h"
17 #include "libANGLE/MemoryObject.h"
18 #include "libANGLE/Surface.h"
19 #include "libANGLE/renderer/vulkan/ContextVk.h"
20 #include "libANGLE/renderer/vulkan/FramebufferVk.h"
21 #include "libANGLE/renderer/vulkan/ImageVk.h"
22 #include "libANGLE/renderer/vulkan/MemoryObjectVk.h"
23 #include "libANGLE/renderer/vulkan/RendererVk.h"
24 #include "libANGLE/renderer/vulkan/SurfaceVk.h"
25 #include "libANGLE/renderer/vulkan/vk_format_utils.h"
26 #include "libANGLE/trace.h"
27
28 namespace rx
29 {
30 namespace
31 {
32 constexpr VkImageUsageFlags kDrawStagingImageFlags =
33 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
34
35 constexpr VkImageUsageFlags kTransferStagingImageFlags =
36 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
37
38 constexpr VkFormatFeatureFlags kBlitFeatureFlags =
39 VK_FORMAT_FEATURE_BLIT_SRC_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT;
40
CanCopyWithTransfer(RendererVk * renderer,const vk::Format & srcFormat,const vk::Format & destFormat)41 bool CanCopyWithTransfer(RendererVk *renderer,
42 const vk::Format &srcFormat,
43 const vk::Format &destFormat)
44 {
45 // NOTE(syoussefi): technically, you can transfer between formats as long as they have the same
46 // size and are compatible, but for now, let's just support same-format copies with transfer.
47 return srcFormat.internalFormat == destFormat.internalFormat &&
48 renderer->hasImageFormatFeatureBits(srcFormat.vkImageFormat,
49 VK_FORMAT_FEATURE_TRANSFER_SRC_BIT) &&
50 renderer->hasImageFormatFeatureBits(destFormat.vkImageFormat,
51 VK_FORMAT_FEATURE_TRANSFER_DST_BIT);
52 }
53
CanCopyWithDraw(RendererVk * renderer,const vk::Format & srcFormat,const vk::Format & destFormat)54 bool CanCopyWithDraw(RendererVk *renderer,
55 const vk::Format &srcFormat,
56 const vk::Format &destFormat)
57 {
58 return renderer->hasImageFormatFeatureBits(srcFormat.vkImageFormat,
59 VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) &&
60 renderer->hasImageFormatFeatureBits(destFormat.vkImageFormat,
61 VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT);
62 }
63
ForceCpuPathForCopy(RendererVk * renderer,vk::ImageHelper * image)64 bool ForceCpuPathForCopy(RendererVk *renderer, vk::ImageHelper *image)
65 {
66 return image->getLayerCount() > 1 && renderer->getFeatures().forceCpuPathForCubeMapCopy.enabled;
67 }
68
GetRenderTargetLayerCount(vk::ImageHelper * image)69 uint32_t GetRenderTargetLayerCount(vk::ImageHelper *image)
70 {
71 // Depth > 1 means this is a 3D texture and depth is our layer count
72 return image->getExtents().depth > 1 ? image->getExtents().depth : image->getLayerCount();
73 }
74
HasBothDepthAndStencilAspects(VkImageAspectFlags aspectFlags)75 bool HasBothDepthAndStencilAspects(VkImageAspectFlags aspectFlags)
76 {
77 constexpr VkImageAspectFlags kDepthStencilAspects =
78 VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_DEPTH_BIT;
79 return (aspectFlags & kDepthStencilAspects) == kDepthStencilAspects;
80 }
81 } // anonymous namespace
82
TextureVkViews()83 TextureVk::TextureVkViews::TextureVkViews() {}
~TextureVkViews()84 TextureVk::TextureVkViews::~TextureVkViews() {}
85
release(ContextVk * contextVk,Serial currentSerial)86 void TextureVk::TextureVkViews::release(ContextVk *contextVk, Serial currentSerial)
87 {
88 contextVk->releaseObject(currentSerial, &mDrawBaseLevelImageView);
89 contextVk->releaseObject(currentSerial, &mReadBaseLevelImageView);
90 contextVk->releaseObject(currentSerial, &mReadMipmapImageView);
91 contextVk->releaseObject(currentSerial, &mFetchBaseLevelImageView);
92 contextVk->releaseObject(currentSerial, &mFetchMipmapImageView);
93 }
94
generateMipmapLevelsWithCPU(ContextVk * contextVk,const angle::Format & sourceFormat,GLuint layer,GLuint firstMipLevel,GLuint maxMipLevel,const size_t sourceWidth,const size_t sourceHeight,const size_t sourceRowPitch,uint8_t * sourceData)95 angle::Result TextureVk::generateMipmapLevelsWithCPU(ContextVk *contextVk,
96 const angle::Format &sourceFormat,
97 GLuint layer,
98 GLuint firstMipLevel,
99 GLuint maxMipLevel,
100 const size_t sourceWidth,
101 const size_t sourceHeight,
102 const size_t sourceRowPitch,
103 uint8_t *sourceData)
104 {
105 size_t previousLevelWidth = sourceWidth;
106 size_t previousLevelHeight = sourceHeight;
107 uint8_t *previousLevelData = sourceData;
108 size_t previousLevelRowPitch = sourceRowPitch;
109
110 for (GLuint currentMipLevel = firstMipLevel; currentMipLevel <= maxMipLevel; currentMipLevel++)
111 {
112 // Compute next level width and height.
113 size_t mipWidth = std::max<size_t>(1, previousLevelWidth >> 1);
114 size_t mipHeight = std::max<size_t>(1, previousLevelHeight >> 1);
115
116 // With the width and height of the next mip, we can allocate the next buffer we need.
117 uint8_t *destData = nullptr;
118 size_t destRowPitch = mipWidth * sourceFormat.pixelBytes;
119
120 size_t mipAllocationSize = destRowPitch * mipHeight;
121 gl::Extents mipLevelExtents(static_cast<int>(mipWidth), static_cast<int>(mipHeight), 1);
122
123 ANGLE_TRY(mImage->stageSubresourceUpdateAndGetData(
124 contextVk, mipAllocationSize,
125 gl::ImageIndex::MakeFromType(mState.getType(), currentMipLevel, layer), mipLevelExtents,
126 gl::Offset(), &destData));
127 onStagingBufferChange();
128
129 // Generate the mipmap into that new buffer
130 sourceFormat.mipGenerationFunction(previousLevelWidth, previousLevelHeight, 1,
131 previousLevelData, previousLevelRowPitch, 0, destData,
132 destRowPitch, 0);
133
134 // Swap for the next iteration
135 previousLevelWidth = mipWidth;
136 previousLevelHeight = mipHeight;
137 previousLevelData = destData;
138 previousLevelRowPitch = destRowPitch;
139 }
140
141 return angle::Result::Continue;
142 }
143
144 // TextureVk implementation.
TextureVk(const gl::TextureState & state,RendererVk * renderer)145 TextureVk::TextureVk(const gl::TextureState &state, RendererVk *renderer)
146 : TextureImpl(state),
147 mOwnsImage(false),
148 mImageNativeType(gl::TextureType::InvalidEnum),
149 mImageLayerOffset(0),
150 mImageLevelOffset(0),
151 mImage(nullptr),
152 mStagingBufferInitialSize(vk::kStagingBufferSize)
153 {}
154
155 TextureVk::~TextureVk() = default;
156
onDestroy(const gl::Context * context)157 void TextureVk::onDestroy(const gl::Context *context)
158 {
159 ContextVk *contextVk = vk::GetImpl(context);
160
161 releaseAndDeleteImage(contextVk);
162 contextVk->releaseObject(contextVk->getCurrentQueueSerial(), &mSampler);
163 }
164
setImage(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,const uint8_t * pixels)165 angle::Result TextureVk::setImage(const gl::Context *context,
166 const gl::ImageIndex &index,
167 GLenum internalFormat,
168 const gl::Extents &size,
169 GLenum format,
170 GLenum type,
171 const gl::PixelUnpackState &unpack,
172 const uint8_t *pixels)
173 {
174 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat, type);
175
176 return setImageImpl(context, index, formatInfo, size, type, unpack, pixels);
177 }
178
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)179 angle::Result TextureVk::setSubImage(const gl::Context *context,
180 const gl::ImageIndex &index,
181 const gl::Box &area,
182 GLenum format,
183 GLenum type,
184 const gl::PixelUnpackState &unpack,
185 gl::Buffer *unpackBuffer,
186 const uint8_t *pixels)
187 {
188 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format, type);
189 ContextVk *contextVk = vk::GetImpl(context);
190 const gl::ImageDesc &levelDesc = mState.getImageDesc(index);
191 const vk::Format &vkFormat =
192 contextVk->getRenderer()->getFormat(levelDesc.format.info->sizedInternalFormat);
193
194 return setSubImageImpl(context, index, area, formatInfo, type, unpack, pixels, vkFormat);
195 }
196
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)197 angle::Result TextureVk::setCompressedImage(const gl::Context *context,
198 const gl::ImageIndex &index,
199 GLenum internalFormat,
200 const gl::Extents &size,
201 const gl::PixelUnpackState &unpack,
202 size_t imageSize,
203 const uint8_t *pixels)
204 {
205 const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat);
206
207 return setImageImpl(context, index, formatInfo, size, GL_UNSIGNED_BYTE, unpack, pixels);
208 }
209
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)210 angle::Result TextureVk::setCompressedSubImage(const gl::Context *context,
211 const gl::ImageIndex &index,
212 const gl::Box &area,
213 GLenum format,
214 const gl::PixelUnpackState &unpack,
215 size_t imageSize,
216 const uint8_t *pixels)
217 {
218
219 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format, GL_UNSIGNED_BYTE);
220 ContextVk *contextVk = vk::GetImpl(context);
221 const gl::ImageDesc &levelDesc = mState.getImageDesc(index);
222 const vk::Format &vkFormat =
223 contextVk->getRenderer()->getFormat(levelDesc.format.info->sizedInternalFormat);
224
225 return setSubImageImpl(context, index, area, formatInfo, GL_UNSIGNED_BYTE, unpack, pixels,
226 vkFormat);
227 }
228
setImageImpl(const gl::Context * context,const gl::ImageIndex & index,const gl::InternalFormat & formatInfo,const gl::Extents & size,GLenum type,const gl::PixelUnpackState & unpack,const uint8_t * pixels)229 angle::Result TextureVk::setImageImpl(const gl::Context *context,
230 const gl::ImageIndex &index,
231 const gl::InternalFormat &formatInfo,
232 const gl::Extents &size,
233 GLenum type,
234 const gl::PixelUnpackState &unpack,
235 const uint8_t *pixels)
236 {
237 ContextVk *contextVk = vk::GetImpl(context);
238 RendererVk *renderer = contextVk->getRenderer();
239
240 const vk::Format &vkFormat = renderer->getFormat(formatInfo.sizedInternalFormat);
241
242 ANGLE_TRY(redefineImage(context, index, vkFormat, size));
243
244 // Early-out on empty textures, don't create a zero-sized storage.
245 if (size.empty())
246 {
247 return angle::Result::Continue;
248 }
249
250 return setSubImageImpl(context, index, gl::Box(0, 0, 0, size.width, size.height, size.depth),
251 formatInfo, type, unpack, pixels, vkFormat);
252 }
253
setSubImageImpl(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,const gl::InternalFormat & formatInfo,GLenum type,const gl::PixelUnpackState & unpack,const uint8_t * pixels,const vk::Format & vkFormat)254 angle::Result TextureVk::setSubImageImpl(const gl::Context *context,
255 const gl::ImageIndex &index,
256 const gl::Box &area,
257 const gl::InternalFormat &formatInfo,
258 GLenum type,
259 const gl::PixelUnpackState &unpack,
260 const uint8_t *pixels,
261 const vk::Format &vkFormat)
262 {
263 ContextVk *contextVk = vk::GetImpl(context);
264 const gl::State &glState = contextVk->getState();
265 gl::Buffer *unpackBuffer = glState.getTargetBuffer(gl::BufferBinding::PixelUnpack);
266
267 if (unpackBuffer)
268 {
269 BufferVk *unpackBufferVk = vk::GetImpl(unpackBuffer);
270 void *mapPtr = nullptr;
271 ANGLE_TRY(unpackBufferVk->mapImpl(contextVk, &mapPtr));
272 const uint8_t *source =
273 static_cast<const uint8_t *>(mapPtr) + reinterpret_cast<ptrdiff_t>(pixels);
274
275 ANGLE_TRY(mImage->stageSubresourceUpdate(
276 contextVk, getNativeImageIndex(index), gl::Extents(area.width, area.height, area.depth),
277 gl::Offset(area.x, area.y, area.z), formatInfo, unpack, type, source, vkFormat));
278
279 unpackBufferVk->unmapImpl(contextVk);
280
281 onStagingBufferChange();
282 }
283 else if (pixels)
284 {
285 ANGLE_TRY(mImage->stageSubresourceUpdate(
286 contextVk, getNativeImageIndex(index), gl::Extents(area.width, area.height, area.depth),
287 gl::Offset(area.x, area.y, area.z), formatInfo, unpack, type, pixels, vkFormat));
288 onStagingBufferChange();
289 }
290
291 return angle::Result::Continue;
292 }
293
copyImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Rectangle & sourceArea,GLenum internalFormat,gl::Framebuffer * source)294 angle::Result TextureVk::copyImage(const gl::Context *context,
295 const gl::ImageIndex &index,
296 const gl::Rectangle &sourceArea,
297 GLenum internalFormat,
298 gl::Framebuffer *source)
299 {
300 RendererVk *renderer = vk::GetImpl(context)->getRenderer();
301
302 gl::Extents newImageSize(sourceArea.width, sourceArea.height, 1);
303 const gl::InternalFormat &internalFormatInfo =
304 gl::GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE);
305 const vk::Format &vkFormat = renderer->getFormat(internalFormatInfo.sizedInternalFormat);
306
307 ANGLE_TRY(redefineImage(context, index, vkFormat, newImageSize));
308 return copySubImageImpl(context, index, gl::Offset(0, 0, 0), sourceArea, internalFormatInfo,
309 source);
310 }
311
copySubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,gl::Framebuffer * source)312 angle::Result TextureVk::copySubImage(const gl::Context *context,
313 const gl::ImageIndex &index,
314 const gl::Offset &destOffset,
315 const gl::Rectangle &sourceArea,
316 gl::Framebuffer *source)
317 {
318 const gl::InternalFormat ¤tFormat = *mState.getImageDesc(index).format.info;
319 return copySubImageImpl(context, index, destOffset, sourceArea, currentFormat, source);
320 }
321
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)322 angle::Result TextureVk::copyTexture(const gl::Context *context,
323 const gl::ImageIndex &index,
324 GLenum internalFormat,
325 GLenum type,
326 size_t sourceLevel,
327 bool unpackFlipY,
328 bool unpackPremultiplyAlpha,
329 bool unpackUnmultiplyAlpha,
330 const gl::Texture *source)
331 {
332 RendererVk *renderer = vk::GetImpl(context)->getRenderer();
333
334 TextureVk *sourceVk = vk::GetImpl(source);
335 const gl::ImageDesc &sourceImageDesc =
336 sourceVk->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), sourceLevel);
337 gl::Rectangle sourceArea(0, 0, sourceImageDesc.size.width, sourceImageDesc.size.height);
338
339 const gl::InternalFormat &destFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
340 const vk::Format &destVkFormat = renderer->getFormat(destFormatInfo.sizedInternalFormat);
341
342 ANGLE_TRY(redefineImage(context, index, destVkFormat, sourceImageDesc.size));
343
344 return copySubTextureImpl(vk::GetImpl(context), index, gl::kOffsetZero, destFormatInfo,
345 sourceLevel, sourceArea, unpackFlipY, unpackPremultiplyAlpha,
346 unpackUnmultiplyAlpha, sourceVk);
347 }
348
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)349 angle::Result TextureVk::copySubTexture(const gl::Context *context,
350 const gl::ImageIndex &index,
351 const gl::Offset &destOffset,
352 size_t sourceLevel,
353 const gl::Box &sourceBox,
354 bool unpackFlipY,
355 bool unpackPremultiplyAlpha,
356 bool unpackUnmultiplyAlpha,
357 const gl::Texture *source)
358 {
359 gl::TextureTarget target = index.getTarget();
360 size_t level = static_cast<size_t>(index.getLevelIndex());
361 const gl::InternalFormat &destFormatInfo = *mState.getImageDesc(target, level).format.info;
362 return copySubTextureImpl(vk::GetImpl(context), index, destOffset, destFormatInfo, sourceLevel,
363 sourceBox.toRect(), unpackFlipY, unpackPremultiplyAlpha,
364 unpackUnmultiplyAlpha, vk::GetImpl(source));
365 }
366
copyCompressedTexture(const gl::Context * context,const gl::Texture * source)367 angle::Result TextureVk::copyCompressedTexture(const gl::Context *context,
368 const gl::Texture *source)
369 {
370 ContextVk *contextVk = vk::GetImpl(context);
371 TextureVk *sourceVk = vk::GetImpl(source);
372
373 gl::TextureTarget sourceTarget = NonCubeTextureTypeToTarget(source->getType());
374 constexpr GLint sourceLevel = 0;
375 constexpr GLint destLevel = 0;
376
377 const gl::InternalFormat &internalFormat = *source->getFormat(sourceTarget, sourceLevel).info;
378 const vk::Format &vkFormat =
379 contextVk->getRenderer()->getFormat(internalFormat.sizedInternalFormat);
380 const gl::Extents size(static_cast<int>(source->getWidth(sourceTarget, sourceLevel)),
381 static_cast<int>(source->getHeight(sourceTarget, sourceLevel)), 1);
382 const gl::ImageIndex destIndex = gl::ImageIndex::MakeFromTarget(sourceTarget, destLevel, 1);
383
384 ANGLE_TRY(redefineImage(context, destIndex, vkFormat, size));
385
386 ANGLE_TRY(sourceVk->ensureImageInitialized(contextVk));
387
388 return copySubImageImplWithTransfer(
389 contextVk, destIndex, gl::Offset(0, 0, 0), vkFormat, sourceLevel, 0,
390 gl::Rectangle(0, 0, size.width, size.height), &sourceVk->getImage());
391 }
392
copySubImageImpl(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,const gl::InternalFormat & internalFormat,gl::Framebuffer * source)393 angle::Result TextureVk::copySubImageImpl(const gl::Context *context,
394 const gl::ImageIndex &index,
395 const gl::Offset &destOffset,
396 const gl::Rectangle &sourceArea,
397 const gl::InternalFormat &internalFormat,
398 gl::Framebuffer *source)
399 {
400 gl::Extents fbSize = source->getReadColorAttachment()->getSize();
401 gl::Rectangle clippedSourceArea;
402 if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height),
403 &clippedSourceArea))
404 {
405 return angle::Result::Continue;
406 }
407
408 ContextVk *contextVk = vk::GetImpl(context);
409 RendererVk *renderer = contextVk->getRenderer();
410 FramebufferVk *framebufferVk = vk::GetImpl(source);
411
412 const gl::ImageIndex offsetImageIndex = getNativeImageIndex(index);
413
414 // If negative offsets are given, clippedSourceArea ensures we don't read from those offsets.
415 // However, that changes the sourceOffset->destOffset mapping. Here, destOffset is shifted by
416 // the same amount as clipped to correct the error.
417 VkImageType imageType = gl_vk::GetImageType(mState.getType());
418 int zOffset = (imageType == VK_IMAGE_TYPE_3D) ? destOffset.z : 0;
419 const gl::Offset modifiedDestOffset(destOffset.x + clippedSourceArea.x - sourceArea.x,
420 destOffset.y + clippedSourceArea.y - sourceArea.y, zOffset);
421
422 RenderTargetVk *colorReadRT = framebufferVk->getColorReadRenderTarget();
423
424 const vk::Format &srcFormat = colorReadRT->getImageFormat();
425 const vk::Format &destFormat = renderer->getFormat(internalFormat.sizedInternalFormat);
426
427 bool isViewportFlipY = contextVk->isViewportFlipEnabledForReadFBO();
428
429 // If it's possible to perform the copy with a transfer, that's the best option.
430 if (!isViewportFlipY && CanCopyWithTransfer(renderer, srcFormat, destFormat))
431 {
432 return copySubImageImplWithTransfer(contextVk, offsetImageIndex, modifiedDestOffset,
433 destFormat, colorReadRT->getLevelIndex(),
434 colorReadRT->getLayerIndex(), clippedSourceArea,
435 &colorReadRT->getImage());
436 }
437
438 bool forceCpuPath = ForceCpuPathForCopy(renderer, mImage);
439
440 // If it's possible to perform the copy with a draw call, do that.
441 if (CanCopyWithDraw(renderer, srcFormat, destFormat) && !forceCpuPath)
442 {
443 // Layer count can only be 1 as the source is a framebuffer.
444 ASSERT(offsetImageIndex.getLayerCount() == 1);
445
446 return copySubImageImplWithDraw(contextVk, offsetImageIndex, modifiedDestOffset, destFormat,
447 0, clippedSourceArea, isViewportFlipY, false, false, false,
448 &colorReadRT->getImage(), colorReadRT->getFetchImageView());
449 }
450
451 // Do a CPU readback that does the conversion, and then stage the change to the pixel buffer.
452 ANGLE_TRY(mImage->stageSubresourceUpdateFromFramebuffer(
453 context, offsetImageIndex, clippedSourceArea, modifiedDestOffset,
454 gl::Extents(clippedSourceArea.width, clippedSourceArea.height, 1), internalFormat,
455 framebufferVk));
456 onStagingBufferChange();
457
458 return angle::Result::Continue;
459 }
460
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)461 angle::Result TextureVk::copySubTextureImpl(ContextVk *contextVk,
462 const gl::ImageIndex &index,
463 const gl::Offset &destOffset,
464 const gl::InternalFormat &destFormat,
465 size_t sourceLevel,
466 const gl::Rectangle &sourceArea,
467 bool unpackFlipY,
468 bool unpackPremultiplyAlpha,
469 bool unpackUnmultiplyAlpha,
470 TextureVk *source)
471 {
472 RendererVk *renderer = contextVk->getRenderer();
473
474 ANGLE_TRY(source->ensureImageInitialized(contextVk));
475
476 const vk::Format &sourceVkFormat = source->getImage().getFormat();
477 const vk::Format &destVkFormat = renderer->getFormat(destFormat.sizedInternalFormat);
478
479 const gl::ImageIndex offsetImageIndex = getNativeImageIndex(index);
480
481 // If it's possible to perform the copy with a transfer, that's the best option.
482 if (!unpackFlipY && !unpackPremultiplyAlpha && !unpackUnmultiplyAlpha &&
483 CanCopyWithTransfer(renderer, sourceVkFormat, destVkFormat))
484 {
485 return copySubImageImplWithTransfer(contextVk, offsetImageIndex, destOffset, destVkFormat,
486 sourceLevel, 0, sourceArea, &source->getImage());
487 }
488
489 bool forceCpuPath = ForceCpuPathForCopy(renderer, mImage);
490
491 // If it's possible to perform the copy with a draw call, do that.
492 if (CanCopyWithDraw(renderer, sourceVkFormat, destVkFormat) && !forceCpuPath)
493 {
494 return copySubImageImplWithDraw(contextVk, offsetImageIndex, destOffset, destVkFormat,
495 sourceLevel, sourceArea, false, unpackFlipY,
496 unpackPremultiplyAlpha, unpackUnmultiplyAlpha,
497 &source->getImage(), &source->getFetchImageView());
498 }
499
500 if (sourceLevel != 0)
501 {
502 WARN() << "glCopyTextureCHROMIUM with sourceLevel != 0 not implemented.";
503 return angle::Result::Stop;
504 }
505
506 // Read back the requested region of the source texture
507 uint8_t *sourceData = nullptr;
508 ANGLE_TRY(source->copyImageDataToBuffer(contextVk, sourceLevel, 1, sourceArea, &sourceData));
509
510 const angle::Format &sourceTextureFormat = sourceVkFormat.imageFormat();
511 const angle::Format &destTextureFormat = destVkFormat.imageFormat();
512 size_t destinationAllocationSize =
513 sourceArea.width * sourceArea.height * destTextureFormat.pixelBytes;
514
515 // Allocate memory in the destination texture for the copy/conversion
516 uint8_t *destData = nullptr;
517 ANGLE_TRY(mImage->stageSubresourceUpdateAndGetData(
518 contextVk, destinationAllocationSize, offsetImageIndex,
519 gl::Extents(sourceArea.width, sourceArea.height, 1), destOffset, &destData));
520 onStagingBufferChange();
521
522 // Source and dest data is tightly packed
523 GLuint sourceDataRowPitch = sourceArea.width * sourceTextureFormat.pixelBytes;
524 GLuint destDataRowPitch = sourceArea.width * destTextureFormat.pixelBytes;
525
526 rx::PixelReadFunction pixelReadFunction = sourceTextureFormat.pixelReadFunction;
527 rx::PixelWriteFunction pixelWriteFunction = destTextureFormat.pixelWriteFunction;
528
529 // Fix up the read/write functions for the sake of luminance/alpha that are emulated with
530 // formats whose channels don't correspond to the original format (alpha is emulated with red,
531 // and luminance/alpha is emulated with red/green).
532 if (sourceVkFormat.angleFormat().isLUMA())
533 {
534 pixelReadFunction = sourceVkFormat.angleFormat().pixelReadFunction;
535 }
536 if (destVkFormat.angleFormat().isLUMA())
537 {
538 pixelWriteFunction = destVkFormat.angleFormat().pixelWriteFunction;
539 }
540
541 CopyImageCHROMIUM(sourceData, sourceDataRowPitch, sourceTextureFormat.pixelBytes, 0,
542 pixelReadFunction, destData, destDataRowPitch, destTextureFormat.pixelBytes,
543 0, pixelWriteFunction, destFormat.format, destFormat.componentType,
544 sourceArea.width, sourceArea.height, 1, unpackFlipY, unpackPremultiplyAlpha,
545 unpackUnmultiplyAlpha);
546
547 return angle::Result::Continue;
548 }
549
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)550 angle::Result TextureVk::copySubImageImplWithTransfer(ContextVk *contextVk,
551 const gl::ImageIndex &index,
552 const gl::Offset &destOffset,
553 const vk::Format &destFormat,
554 size_t sourceLevel,
555 size_t sourceLayer,
556 const gl::Rectangle &sourceArea,
557 vk::ImageHelper *srcImage)
558 {
559 RendererVk *renderer = contextVk->getRenderer();
560
561 uint32_t level = index.getLevelIndex();
562 uint32_t baseLayer = index.hasLayer() ? index.getLayerIndex() : 0;
563 uint32_t layerCount = index.getLayerCount();
564 gl::Offset srcOffset = {sourceArea.x, sourceArea.y, 0};
565 gl::Extents extents = {sourceArea.width, sourceArea.height, 1};
566
567 // Change source layout if necessary
568 if (srcImage->isLayoutChangeNecessary(vk::ImageLayout::TransferSrc))
569 {
570 vk::CommandBuffer *srcLayoutChange;
571 ANGLE_TRY(srcImage->recordCommands(contextVk, &srcLayoutChange));
572 srcImage->changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::TransferSrc,
573 srcLayoutChange);
574 }
575
576 VkImageSubresourceLayers srcSubresource = {};
577 srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
578 srcSubresource.mipLevel = static_cast<uint32_t>(sourceLevel);
579 srcSubresource.baseArrayLayer = static_cast<uint32_t>(sourceLayer);
580 srcSubresource.layerCount = layerCount;
581
582 // If destination is valid, copy the source directly into it.
583 if (mImage->valid())
584 {
585 // Make sure any updates to the image are already flushed.
586 ANGLE_TRY(ensureImageInitialized(contextVk));
587
588 vk::CommandBuffer *commandBuffer;
589 ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer));
590
591 // Change the image layout before the transfer
592 mImage->changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::TransferDst,
593 commandBuffer);
594
595 // Source's layout change should happen before the copy
596 srcImage->addReadDependency(mImage);
597
598 VkImageSubresourceLayers destSubresource = srcSubresource;
599 destSubresource.mipLevel = level;
600 destSubresource.baseArrayLayer = baseLayer;
601
602 VkImageType imageType = gl_vk::GetImageType(mState.getType());
603 if (imageType == VK_IMAGE_TYPE_3D)
604 {
605 destSubresource.baseArrayLayer = 0;
606 destSubresource.layerCount = 1;
607 }
608
609 vk::ImageHelper::Copy(srcImage, mImage, srcOffset, destOffset, extents, srcSubresource,
610 destSubresource, commandBuffer);
611 }
612 else
613 {
614 std::unique_ptr<vk::ImageHelper> stagingImage;
615
616 // Create a temporary image to stage the copy
617 stagingImage = std::make_unique<vk::ImageHelper>();
618
619 ANGLE_TRY(stagingImage->init2DStaging(contextVk, renderer->getMemoryProperties(),
620 gl::Extents(sourceArea.width, sourceArea.height, 1),
621 destFormat, kTransferStagingImageFlags, layerCount));
622
623 vk::CommandBuffer *commandBuffer;
624 ANGLE_TRY(stagingImage->recordCommands(contextVk, &commandBuffer));
625
626 // Change the image layout before the transfer
627 stagingImage->changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::TransferDst,
628 commandBuffer);
629
630 // Source's layout change should happen before the copy
631 srcImage->addReadDependency(stagingImage.get());
632
633 VkImageSubresourceLayers destSubresource = srcSubresource;
634 destSubresource.mipLevel = 0;
635 destSubresource.baseArrayLayer = 0;
636
637 vk::ImageHelper::Copy(srcImage, stagingImage.get(), srcOffset, gl::Offset(), extents,
638 srcSubresource, destSubresource, commandBuffer);
639
640 // Stage the copy for when the image storage is actually created.
641 VkImageType imageType = gl_vk::GetImageType(mState.getType());
642 mImage->stageSubresourceUpdateFromImage(stagingImage.release(), index, destOffset, extents,
643 imageType);
644 onStagingBufferChange();
645 }
646
647 return angle::Result::Continue;
648 }
649
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)650 angle::Result TextureVk::copySubImageImplWithDraw(ContextVk *contextVk,
651 const gl::ImageIndex &index,
652 const gl::Offset &destOffset,
653 const vk::Format &destFormat,
654 size_t sourceLevel,
655 const gl::Rectangle &sourceArea,
656 bool isSrcFlipY,
657 bool unpackFlipY,
658 bool unpackPremultiplyAlpha,
659 bool unpackUnmultiplyAlpha,
660 vk::ImageHelper *srcImage,
661 const vk::ImageView *srcView)
662 {
663 RendererVk *renderer = contextVk->getRenderer();
664 UtilsVk &utilsVk = contextVk->getUtils();
665 Serial currentQueueSerial = contextVk->getCurrentQueueSerial();
666
667 UtilsVk::CopyImageParameters params;
668 params.srcOffset[0] = sourceArea.x;
669 params.srcOffset[1] = sourceArea.y;
670 params.srcExtents[0] = sourceArea.width;
671 params.srcExtents[1] = sourceArea.height;
672 params.destOffset[0] = destOffset.x;
673 params.destOffset[1] = destOffset.y;
674 params.srcMip = static_cast<uint32_t>(sourceLevel);
675 params.srcHeight = srcImage->getExtents().height;
676 params.srcPremultiplyAlpha = unpackPremultiplyAlpha && !unpackUnmultiplyAlpha;
677 params.srcUnmultiplyAlpha = unpackUnmultiplyAlpha && !unpackPremultiplyAlpha;
678 params.srcFlipY = isSrcFlipY;
679 params.destFlipY = unpackFlipY;
680
681 uint32_t level = index.getLevelIndex();
682 uint32_t baseLayer = index.hasLayer() ? index.getLayerIndex() : 0;
683 uint32_t layerCount = index.getLayerCount();
684
685 // If destination is valid, copy the source directly into it.
686 if (mImage->valid())
687 {
688 // Make sure any updates to the image are already flushed.
689 ANGLE_TRY(ensureImageInitialized(contextVk));
690
691 for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex)
692 {
693 params.srcLayer = layerIndex;
694
695 vk::ImageView *destView;
696 ANGLE_TRY(
697 getLayerLevelDrawImageView(contextVk, baseLayer + layerIndex, level, &destView));
698
699 ANGLE_TRY(utilsVk.copyImage(contextVk, mImage, destView, srcImage, srcView, params));
700 }
701 }
702 else
703 {
704 std::unique_ptr<vk::ImageHelper> stagingImage;
705
706 GLint samples = srcImage->getSamples();
707 gl::TextureType stagingTextureType = vk::Get2DTextureType(layerCount, samples);
708
709 // Create a temporary image to stage the copy
710 stagingImage = std::make_unique<vk::ImageHelper>();
711
712 ANGLE_TRY(stagingImage->init2DStaging(contextVk, renderer->getMemoryProperties(),
713 gl::Extents(sourceArea.width, sourceArea.height, 1),
714 destFormat, kDrawStagingImageFlags, layerCount));
715
716 params.destOffset[0] = 0;
717 params.destOffset[1] = 0;
718
719 for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex)
720 {
721 params.srcLayer = layerIndex;
722
723 // Create a temporary view for this layer.
724 vk::ImageView stagingView;
725 ANGLE_TRY(stagingImage->initLayerImageView(
726 contextVk, stagingTextureType, VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(),
727 &stagingView, 0, 1, layerIndex, 1));
728
729 ANGLE_TRY(utilsVk.copyImage(contextVk, stagingImage.get(), &stagingView, srcImage,
730 srcView, params));
731
732 // Queue the resource for cleanup as soon as the copy above is finished. There's no
733 // need to keep it around.
734 contextVk->releaseObject(currentQueueSerial, &stagingView);
735 }
736
737 // Stage the copy for when the image storage is actually created.
738 VkImageType imageType = gl_vk::GetImageType(mState.getType());
739 mImage->stageSubresourceUpdateFromImage(stagingImage.release(), index, destOffset,
740 gl::Extents(sourceArea.width, sourceArea.height, 1),
741 imageType);
742 onStagingBufferChange();
743 }
744
745 return angle::Result::Continue;
746 }
747
setStorage(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size)748 angle::Result TextureVk::setStorage(const gl::Context *context,
749 gl::TextureType type,
750 size_t levels,
751 GLenum internalFormat,
752 const gl::Extents &size)
753 {
754 ContextVk *contextVk = GetAs<ContextVk>(context->getImplementation());
755 RendererVk *renderer = contextVk->getRenderer();
756
757 if (!mOwnsImage)
758 {
759 releaseAndDeleteImage(contextVk);
760 }
761
762 const vk::Format &format = renderer->getFormat(internalFormat);
763 ANGLE_TRY(ensureImageAllocated(contextVk, format));
764
765 vk::CommandBuffer *commandBuffer = nullptr;
766 ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer));
767
768 if (mImage->valid())
769 {
770 releaseImage(contextVk);
771 }
772
773 ANGLE_TRY(initImage(contextVk, format, size, static_cast<uint32_t>(levels), commandBuffer));
774 return angle::Result::Continue;
775 }
776
setStorageExternalMemory(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size,gl::MemoryObject * memoryObject,GLuint64 offset)777 angle::Result TextureVk::setStorageExternalMemory(const gl::Context *context,
778 gl::TextureType type,
779 size_t levels,
780 GLenum internalFormat,
781 const gl::Extents &size,
782 gl::MemoryObject *memoryObject,
783 GLuint64 offset)
784 {
785 ContextVk *contextVk = vk::GetImpl(context);
786 RendererVk *renderer = contextVk->getRenderer();
787 MemoryObjectVk *memoryObjectVk = vk::GetImpl(memoryObject);
788
789 releaseAndDeleteImage(contextVk);
790
791 const vk::Format &format = renderer->getFormat(internalFormat);
792
793 setImageHelper(contextVk, new vk::ImageHelper(), mState.getType(), format, 0, 0, true);
794
795 ANGLE_TRY(
796 memoryObjectVk->createImage(context, type, levels, internalFormat, size, offset, mImage));
797
798 ANGLE_TRY(
799 initImageViews(contextVk, format, static_cast<uint32_t>(levels), mImage->getLayerCount()));
800
801 // TODO(spang): This needs to be reworked when semaphores are added.
802 // http://anglebug.com/3289
803 uint32_t rendererQueueFamilyIndex = renderer->getQueueFamilyIndex();
804 if (mImage->isQueueChangeNeccesary(rendererQueueFamilyIndex))
805 {
806 vk::CommandBuffer *commandBuffer = nullptr;
807 ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer));
808 mImage->changeLayoutAndQueue(VK_IMAGE_ASPECT_COLOR_BIT,
809 vk::ImageLayout::AllGraphicsShadersReadOnly,
810 rendererQueueFamilyIndex, commandBuffer);
811 }
812
813 return angle::Result::Continue;
814 }
815
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)816 angle::Result TextureVk::setEGLImageTarget(const gl::Context *context,
817 gl::TextureType type,
818 egl::Image *image)
819 {
820 ContextVk *contextVk = vk::GetImpl(context);
821 RendererVk *renderer = contextVk->getRenderer();
822
823 releaseAndDeleteImage(contextVk);
824
825 const vk::Format &format = renderer->getFormat(image->getFormat().info->sizedInternalFormat);
826
827 ImageVk *imageVk = vk::GetImpl(image);
828 setImageHelper(contextVk, imageVk->getImage(), imageVk->getImageTextureType(), format,
829 imageVk->getImageLevel(), imageVk->getImageLayer(), false);
830
831 ASSERT(type != gl::TextureType::CubeMap);
832 ANGLE_TRY(initImageViews(contextVk, format, 1, 1));
833
834 // Transfer the image to this queue if needed
835 uint32_t rendererQueueFamilyIndex = renderer->getQueueFamilyIndex();
836 if (mImage->isQueueChangeNeccesary(rendererQueueFamilyIndex))
837 {
838 vk::CommandBuffer *commandBuffer = nullptr;
839 ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer));
840 mImage->changeLayoutAndQueue(VK_IMAGE_ASPECT_COLOR_BIT,
841 vk::ImageLayout::AllGraphicsShadersReadOnly,
842 rendererQueueFamilyIndex, commandBuffer);
843 }
844
845 return angle::Result::Continue;
846 }
847
setImageExternal(const gl::Context * context,gl::TextureType type,egl::Stream * stream,const egl::Stream::GLTextureDescription & desc)848 angle::Result TextureVk::setImageExternal(const gl::Context *context,
849 gl::TextureType type,
850 egl::Stream *stream,
851 const egl::Stream::GLTextureDescription &desc)
852 {
853 ANGLE_VK_UNREACHABLE(vk::GetImpl(context));
854 return angle::Result::Stop;
855 }
856
getNativeImageIndex(const gl::ImageIndex & inputImageIndex) const857 gl::ImageIndex TextureVk::getNativeImageIndex(const gl::ImageIndex &inputImageIndex) const
858 {
859 // The input index can be a specific layer (for cube maps, 2d arrays, etc) or mImageLayerOffset
860 // can be non-zero but both of these cannot be true at the same time. EGL images can source
861 // from a cube map or 3D texture but can only be a 2D destination.
862 ASSERT(!(inputImageIndex.hasLayer() && mImageLayerOffset > 0));
863
864 // handle the special-case where image index can represent a whole level of a texture
865 GLint resultImageLayer = inputImageIndex.getLayerIndex();
866 if (inputImageIndex.getType() != mImageNativeType)
867 {
868 ASSERT(!inputImageIndex.hasLayer());
869 resultImageLayer = mImageLayerOffset;
870 }
871
872 return gl::ImageIndex::MakeFromType(mImageNativeType,
873 getNativeImageLevel(inputImageIndex.getLevelIndex()),
874 resultImageLayer, inputImageIndex.getLayerCount());
875 }
876
getNativeImageLevel(uint32_t frontendLevel) const877 uint32_t TextureVk::getNativeImageLevel(uint32_t frontendLevel) const
878 {
879 return mImageLevelOffset + frontendLevel;
880 }
881
getNativeImageLayer(uint32_t frontendLayer) const882 uint32_t TextureVk::getNativeImageLayer(uint32_t frontendLayer) const
883 {
884 return mImageLayerOffset + frontendLayer;
885 }
886
releaseAndDeleteImage(ContextVk * context)887 void TextureVk::releaseAndDeleteImage(ContextVk *context)
888 {
889 if (mImage)
890 {
891 releaseImage(context);
892 releaseStagingBuffer(context);
893 SafeDelete(mImage);
894 }
895 }
896
ensureImageAllocated(ContextVk * contextVk,const vk::Format & format)897 angle::Result TextureVk::ensureImageAllocated(ContextVk *contextVk, const vk::Format &format)
898 {
899 if (mImage == nullptr)
900 {
901 setImageHelper(contextVk, new vk::ImageHelper(), mState.getType(), format, 0, 0, true);
902 }
903 else
904 {
905 updateImageHelper(contextVk, format);
906 }
907
908 return angle::Result::Continue;
909 }
910
setImageHelper(ContextVk * contextVk,vk::ImageHelper * imageHelper,gl::TextureType imageType,const vk::Format & format,uint32_t imageLevelOffset,uint32_t imageLayerOffset,bool selfOwned)911 void TextureVk::setImageHelper(ContextVk *contextVk,
912 vk::ImageHelper *imageHelper,
913 gl::TextureType imageType,
914 const vk::Format &format,
915 uint32_t imageLevelOffset,
916 uint32_t imageLayerOffset,
917 bool selfOwned)
918 {
919 ASSERT(mImage == nullptr);
920
921 mOwnsImage = selfOwned;
922 mImageNativeType = imageType;
923 mImageLevelOffset = imageLevelOffset;
924 mImageLayerOffset = imageLayerOffset;
925 mImage = imageHelper;
926 mImage->initStagingBuffer(contextVk->getRenderer(), format, vk::kStagingBufferFlags,
927 mStagingBufferInitialSize);
928
929 mRenderTarget.init(mImage, &mDefaultViews.mDrawBaseLevelImageView,
930 &mDefaultViews.mFetchBaseLevelImageView, getNativeImageLevel(0),
931 getNativeImageLayer(0));
932
933 // Force re-creation of layered render targets next time they are needed
934 mCubeMapRenderTargets.clear();
935 m3DRenderTargets.clear();
936
937 mSerial = contextVk->generateTextureSerial();
938 }
939
updateImageHelper(ContextVk * contextVk,const vk::Format & format)940 void TextureVk::updateImageHelper(ContextVk *contextVk, const vk::Format &format)
941 {
942 ASSERT(mImage != nullptr);
943 mImage->initStagingBuffer(contextVk->getRenderer(), format, vk::kStagingBufferFlags,
944 mStagingBufferInitialSize);
945 }
946
redefineImage(const gl::Context * context,const gl::ImageIndex & index,const vk::Format & format,const gl::Extents & size)947 angle::Result TextureVk::redefineImage(const gl::Context *context,
948 const gl::ImageIndex &index,
949 const vk::Format &format,
950 const gl::Extents &size)
951 {
952 ContextVk *contextVk = vk::GetImpl(context);
953
954 if (!mOwnsImage)
955 {
956 releaseAndDeleteImage(contextVk);
957 }
958
959 if (mImage != nullptr)
960 {
961 // If there is any staged changes for this index, we can remove them since we're going to
962 // override them with this call.
963 mImage->removeStagedUpdates(contextVk, index);
964
965 if (mImage->valid())
966 {
967 // Calculate the expected size for the index we are defining. If the size is different
968 // from the given size, or the format is different, we are redefining the image so we
969 // must release it.
970 if (mImage->getFormat() != format || size != mImage->getSize(index))
971 {
972 releaseImage(contextVk);
973 }
974 }
975 }
976
977 if (!size.empty())
978 {
979 ANGLE_TRY(ensureImageAllocated(contextVk, format));
980 }
981
982 return angle::Result::Continue;
983 }
984
copyImageDataToBuffer(ContextVk * contextVk,size_t sourceLevel,uint32_t layerCount,const gl::Rectangle & sourceArea,uint8_t ** outDataPtr)985 angle::Result TextureVk::copyImageDataToBuffer(ContextVk *contextVk,
986 size_t sourceLevel,
987 uint32_t layerCount,
988 const gl::Rectangle &sourceArea,
989 uint8_t **outDataPtr)
990 {
991 ANGLE_TRACE_EVENT0("gpu.angle", "TextureVk::copyImageDataToBuffer");
992 // Make sure the source is initialized and it's images are flushed.
993 ANGLE_TRY(ensureImageInitialized(contextVk));
994
995 const angle::Format &imageFormat = getImage().getFormat().imageFormat();
996 size_t sourceCopyAllocationSize =
997 sourceArea.width * sourceArea.height * imageFormat.pixelBytes * layerCount;
998
999 vk::CommandBuffer *commandBuffer = nullptr;
1000 ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer));
1001
1002 // Requirement of the copyImageToBuffer, the source image must be in SRC_OPTIMAL layout.
1003 mImage->changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::TransferSrc, commandBuffer);
1004
1005 // Allocate enough memory to copy the sourceArea region of the source texture into its pixel
1006 // buffer.
1007 VkBuffer copyBufferHandle = VK_NULL_HANDLE;
1008 VkDeviceSize sourceCopyOffset = 0;
1009 ANGLE_TRY(mImage->allocateStagingMemory(contextVk, sourceCopyAllocationSize, outDataPtr,
1010 ©BufferHandle, &sourceCopyOffset, nullptr));
1011
1012 VkBufferImageCopy region = {};
1013 region.bufferOffset = sourceCopyOffset;
1014 region.bufferRowLength = 0;
1015 region.bufferImageHeight = 0;
1016 region.imageExtent.width = sourceArea.width;
1017 region.imageExtent.height = sourceArea.height;
1018 region.imageExtent.depth = 1;
1019 region.imageOffset.x = sourceArea.x;
1020 region.imageOffset.y = sourceArea.y;
1021 region.imageOffset.z = 0;
1022 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1023 region.imageSubresource.baseArrayLayer = 0;
1024 region.imageSubresource.layerCount = layerCount;
1025 region.imageSubresource.mipLevel = static_cast<uint32_t>(sourceLevel);
1026
1027 commandBuffer->copyImageToBuffer(mImage->getImage(), mImage->getCurrentLayout(),
1028 copyBufferHandle, 1, ®ion);
1029
1030 // Explicitly finish. If new use cases arise where we don't want to block we can change this.
1031 ANGLE_TRY(contextVk->finishImpl());
1032
1033 return angle::Result::Continue;
1034 }
1035
generateMipmapsWithCPU(const gl::Context * context)1036 angle::Result TextureVk::generateMipmapsWithCPU(const gl::Context *context)
1037 {
1038 ContextVk *contextVk = vk::GetImpl(context);
1039
1040 const VkExtent3D baseLevelExtents = mImage->getExtents();
1041 uint32_t imageLayerCount = mImage->getLayerCount();
1042
1043 uint8_t *imageData = nullptr;
1044 gl::Rectangle imageArea(0, 0, baseLevelExtents.width, baseLevelExtents.height);
1045 ANGLE_TRY(copyImageDataToBuffer(contextVk, mState.getEffectiveBaseLevel(), imageLayerCount,
1046 imageArea, &imageData));
1047
1048 const angle::Format &angleFormat = mImage->getFormat().imageFormat();
1049 GLuint sourceRowPitch = baseLevelExtents.width * angleFormat.pixelBytes;
1050 size_t baseLevelAllocationSize = sourceRowPitch * baseLevelExtents.height;
1051
1052 // We now have the base level available to be manipulated in the imageData pointer. Generate all
1053 // the missing mipmaps with the slow path. For each layer, use the copied data to generate all
1054 // the mips.
1055 for (GLuint layer = 0; layer < imageLayerCount; layer++)
1056 {
1057 size_t bufferOffset = layer * baseLevelAllocationSize;
1058
1059 ANGLE_TRY(generateMipmapLevelsWithCPU(
1060 contextVk, angleFormat, layer, mState.getEffectiveBaseLevel() + 1,
1061 mState.getMipmapMaxLevel(), baseLevelExtents.width, baseLevelExtents.height,
1062 sourceRowPitch, imageData + bufferOffset));
1063 }
1064
1065 vk::CommandBuffer *commandBuffer = nullptr;
1066 ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer));
1067 return mImage->flushStagedUpdates(contextVk, getNativeImageLevel(0), mImage->getLevelCount(),
1068 getNativeImageLayer(0), mImage->getLayerCount(),
1069 commandBuffer);
1070 }
1071
generateMipmap(const gl::Context * context)1072 angle::Result TextureVk::generateMipmap(const gl::Context *context)
1073 {
1074 ContextVk *contextVk = vk::GetImpl(context);
1075
1076 // Some data is pending, or the image has not been defined at all yet
1077 if (!mImage->valid())
1078 {
1079 // Let's initialize the image so we can generate the next levels.
1080 if (mImage->hasStagedUpdates())
1081 {
1082 ANGLE_TRY(ensureImageInitialized(contextVk));
1083 ASSERT(mImage->valid());
1084 }
1085 else
1086 {
1087 // There is nothing to generate if there is nothing uploaded so far.
1088 return angle::Result::Continue;
1089 }
1090 }
1091
1092 RendererVk *renderer = contextVk->getRenderer();
1093
1094 // Check if the image supports blit. If it does, we can do the mipmap generation on the gpu
1095 // only.
1096 if (renderer->hasImageFormatFeatureBits(mImage->getFormat().vkImageFormat, kBlitFeatureFlags))
1097 {
1098 ANGLE_TRY(ensureImageInitialized(contextVk));
1099 ANGLE_TRY(mImage->generateMipmapsWithBlit(contextVk, mState.getMipmapMaxLevel()));
1100 }
1101 else
1102 {
1103 ANGLE_TRY(generateMipmapsWithCPU(context));
1104 }
1105
1106 return angle::Result::Continue;
1107 }
1108
setBaseLevel(const gl::Context * context,GLuint baseLevel)1109 angle::Result TextureVk::setBaseLevel(const gl::Context *context, GLuint baseLevel)
1110 {
1111 ANGLE_VK_UNREACHABLE(vk::GetImpl(context));
1112 return angle::Result::Stop;
1113 }
1114
bindTexImage(const gl::Context * context,egl::Surface * surface)1115 angle::Result TextureVk::bindTexImage(const gl::Context *context, egl::Surface *surface)
1116 {
1117 ContextVk *contextVk = vk::GetImpl(context);
1118 RendererVk *renderer = contextVk->getRenderer();
1119
1120 releaseAndDeleteImage(contextVk);
1121
1122 const vk::Format &format = renderer->getFormat(surface->getConfig()->renderTargetFormat);
1123
1124 // eglBindTexImage can only be called with pbuffer (offscreen) surfaces
1125 OffscreenSurfaceVk *offscreenSurface = GetImplAs<OffscreenSurfaceVk>(surface);
1126 setImageHelper(contextVk, offscreenSurface->getColorAttachmentImage(), mState.getType(), format,
1127 surface->getMipmapLevel(), 0, false);
1128
1129 ASSERT(mImage->getLayerCount() == 1);
1130 return initImageViews(contextVk, format, 1, 1);
1131 }
1132
releaseTexImage(const gl::Context * context)1133 angle::Result TextureVk::releaseTexImage(const gl::Context *context)
1134 {
1135 ContextVk *contextVk = vk::GetImpl(context);
1136
1137 releaseImage(contextVk);
1138
1139 return angle::Result::Continue;
1140 }
1141
getAttachmentRenderTarget(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex,FramebufferAttachmentRenderTarget ** rtOut)1142 angle::Result TextureVk::getAttachmentRenderTarget(const gl::Context *context,
1143 GLenum binding,
1144 const gl::ImageIndex &imageIndex,
1145 FramebufferAttachmentRenderTarget **rtOut)
1146 {
1147 // Non-zero mip level attachments are an ES 3.0 feature.
1148 ASSERT(imageIndex.getLevelIndex() == 0);
1149
1150 ContextVk *contextVk = vk::GetImpl(context);
1151 ANGLE_TRY(ensureImageInitialized(contextVk));
1152
1153 switch (imageIndex.getType())
1154 {
1155 case gl::TextureType::_2D:
1156 *rtOut = &mRenderTarget;
1157 break;
1158 case gl::TextureType::_2DArray:
1159 case gl::TextureType::_3D:
1160 ANGLE_TRY(init3DRenderTargets(contextVk));
1161 *rtOut = &m3DRenderTargets[imageIndex.getLayerIndex()];
1162 break;
1163 case gl::TextureType::CubeMap:
1164 ANGLE_TRY(initCubeMapRenderTargets(contextVk));
1165 *rtOut = &mCubeMapRenderTargets[imageIndex.cubeMapFaceIndex()];
1166 break;
1167 default:
1168 UNREACHABLE();
1169 }
1170
1171 return angle::Result::Continue;
1172 }
1173
ensureImageInitialized(ContextVk * contextVk)1174 angle::Result TextureVk::ensureImageInitialized(ContextVk *contextVk)
1175 {
1176 const gl::ImageDesc &baseLevelDesc = mState.getBaseLevelDesc();
1177 const gl::Extents &baseLevelExtents = baseLevelDesc.size;
1178 const uint32_t levelCount = getLevelCount();
1179
1180 const vk::Format &format =
1181 contextVk->getRenderer()->getFormat(baseLevelDesc.format.info->sizedInternalFormat);
1182
1183 return ensureImageInitializedImpl(contextVk, baseLevelExtents, levelCount, format);
1184 }
1185
ensureImageInitializedImpl(ContextVk * contextVk,const gl::Extents & baseLevelExtents,uint32_t levelCount,const vk::Format & format)1186 angle::Result TextureVk::ensureImageInitializedImpl(ContextVk *contextVk,
1187 const gl::Extents &baseLevelExtents,
1188 uint32_t levelCount,
1189 const vk::Format &format)
1190 {
1191 if (mImage->valid() && !mImage->hasStagedUpdates())
1192 {
1193 return angle::Result::Continue;
1194 }
1195
1196 vk::CommandBuffer *commandBuffer = nullptr;
1197 ANGLE_TRY(mImage->recordCommands(contextVk, &commandBuffer));
1198
1199 if (!mImage->valid())
1200 {
1201 ANGLE_TRY(initImage(contextVk, format, baseLevelExtents, levelCount, commandBuffer));
1202 }
1203
1204 return mImage->flushStagedUpdates(contextVk, getNativeImageLevel(0), mImage->getLevelCount(),
1205 getNativeImageLayer(0), mImage->getLayerCount(),
1206 commandBuffer);
1207 }
1208
init3DRenderTargets(ContextVk * contextVk)1209 angle::Result TextureVk::init3DRenderTargets(ContextVk *contextVk)
1210 {
1211 // Lazy init. Check if already initialized.
1212 if (!m3DRenderTargets.empty())
1213 return angle::Result::Continue;
1214
1215 uint32_t layerCount = GetRenderTargetLayerCount(mImage);
1216
1217 mLayerFetchImageView.resize(layerCount);
1218 m3DRenderTargets.resize(layerCount);
1219
1220 for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex)
1221 {
1222 vk::ImageView *drawView;
1223 ANGLE_TRY(getLayerLevelDrawImageView(contextVk, layerIndex, 0, &drawView));
1224
1225 // Users of the render target expect the views to directly view the desired layer, so we
1226 // need create a fetch view for each layer as well.
1227 gl::SwizzleState mappedSwizzle;
1228 MapSwizzleState(contextVk, mImage->getFormat(), mState.getSwizzleState(), &mappedSwizzle);
1229 gl::TextureType arrayType = vk::Get2DTextureType(layerCount, mImage->getSamples());
1230 ANGLE_TRY(mImage->initLayerImageView(contextVk, arrayType, mImage->getAspectFlags(),
1231 mappedSwizzle, &mLayerFetchImageView[layerIndex],
1232 getNativeImageLevel(0), 1,
1233 getNativeImageLayer(layerIndex), 1));
1234
1235 m3DRenderTargets[layerIndex].init(mImage, drawView, &mLayerFetchImageView[layerIndex],
1236 getNativeImageLevel(0), getNativeImageLayer(layerIndex));
1237 }
1238 return angle::Result::Continue;
1239 }
1240
initCubeMapRenderTargets(ContextVk * contextVk)1241 angle::Result TextureVk::initCubeMapRenderTargets(ContextVk *contextVk)
1242 {
1243 // Lazy init. Check if already initialized.
1244 if (!mCubeMapRenderTargets.empty())
1245 return angle::Result::Continue;
1246
1247 mLayerFetchImageView.resize(gl::kCubeFaceCount);
1248 mCubeMapRenderTargets.resize(gl::kCubeFaceCount);
1249 for (uint32_t cubeMapFaceIndex = 0; cubeMapFaceIndex < gl::kCubeFaceCount; ++cubeMapFaceIndex)
1250 {
1251 vk::ImageView *drawView;
1252 ANGLE_TRY(getLayerLevelDrawImageView(contextVk, cubeMapFaceIndex, 0, &drawView));
1253
1254 // Users of the render target expect the views to directly view the desired layer, so we
1255 // need create a fetch view for each layer as well.
1256 gl::SwizzleState mappedSwizzle;
1257 MapSwizzleState(contextVk, mImage->getFormat(), mState.getSwizzleState(), &mappedSwizzle);
1258 gl::TextureType arrayType = vk::Get2DTextureType(gl::kCubeFaceCount, mImage->getSamples());
1259 ANGLE_TRY(mImage->initLayerImageView(contextVk, arrayType, mImage->getAspectFlags(),
1260 mappedSwizzle, &mLayerFetchImageView[cubeMapFaceIndex],
1261 getNativeImageLevel(0), 1,
1262 getNativeImageLayer(cubeMapFaceIndex), 1));
1263
1264 mCubeMapRenderTargets[cubeMapFaceIndex].init(
1265 mImage, drawView, &mLayerFetchImageView[cubeMapFaceIndex], getNativeImageLevel(0),
1266 getNativeImageLayer(cubeMapFaceIndex));
1267 }
1268 return angle::Result::Continue;
1269 }
1270
syncState(const gl::Context * context,const gl::Texture::DirtyBits & dirtyBits)1271 angle::Result TextureVk::syncState(const gl::Context *context,
1272 const gl::Texture::DirtyBits &dirtyBits)
1273 {
1274 ContextVk *contextVk = vk::GetImpl(context);
1275
1276 // Initialize the image storage and flush the pixel buffer.
1277 ANGLE_TRY(ensureImageInitialized(contextVk));
1278
1279 if (dirtyBits.none() && mSampler.valid())
1280 {
1281 return angle::Result::Continue;
1282 }
1283
1284 RendererVk *renderer = contextVk->getRenderer();
1285 if (mSampler.valid())
1286 {
1287 contextVk->releaseObject(contextVk->getCurrentQueueSerial(), &mSampler);
1288 }
1289
1290 if (dirtyBits.test(gl::Texture::DIRTY_BIT_SWIZZLE_RED) ||
1291 dirtyBits.test(gl::Texture::DIRTY_BIT_SWIZZLE_GREEN) ||
1292 dirtyBits.test(gl::Texture::DIRTY_BIT_SWIZZLE_BLUE) ||
1293 dirtyBits.test(gl::Texture::DIRTY_BIT_SWIZZLE_ALPHA))
1294 {
1295 if (mImage && mImage->valid())
1296 {
1297 // We use a special layer count here to handle EGLImages. They might only be
1298 // looking at one layer of a cube or 2D array texture.
1299 uint32_t layerCount =
1300 mState.getType() == gl::TextureType::_2D ? 1 : mImage->getLayerCount();
1301
1302 releaseImageViews(contextVk);
1303 ANGLE_TRY(initImageViews(contextVk, mImage->getFormat(), mImage->getLevelCount(),
1304 layerCount));
1305 }
1306 }
1307
1308 const gl::Extensions &extensions = renderer->getNativeExtensions();
1309 const gl::SamplerState &samplerState = mState.getSamplerState();
1310
1311 float maxAnisotropy = samplerState.getMaxAnisotropy();
1312 bool anisotropyEnable = extensions.textureFilterAnisotropic && maxAnisotropy > 1.0f;
1313 bool compareEnable = samplerState.getCompareMode() == GL_COMPARE_REF_TO_TEXTURE;
1314 VkCompareOp compareOp = gl_vk::GetCompareOp(samplerState.getCompareFunc());
1315 // When sampling from stencil, deqp tests expect texture compare to have no effect
1316 // dEQP - GLES31.functional.stencil_texturing.misc.compare_mode_effect
1317 // states: NOTE: Texture compare mode has no effect when reading stencil values.
1318 if (mState.isStencilMode())
1319 {
1320 compareEnable = VK_FALSE;
1321 compareOp = VK_COMPARE_OP_ALWAYS;
1322 }
1323
1324 // Create a simple sampler. Force basic parameter settings.
1325 VkSamplerCreateInfo samplerInfo = {};
1326 samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
1327 samplerInfo.flags = 0;
1328 samplerInfo.magFilter = gl_vk::GetFilter(samplerState.getMagFilter());
1329 samplerInfo.minFilter = gl_vk::GetFilter(samplerState.getMinFilter());
1330 samplerInfo.mipmapMode = gl_vk::GetSamplerMipmapMode(samplerState.getMinFilter());
1331 samplerInfo.addressModeU = gl_vk::GetSamplerAddressMode(samplerState.getWrapS());
1332 samplerInfo.addressModeV = gl_vk::GetSamplerAddressMode(samplerState.getWrapT());
1333 samplerInfo.addressModeW = gl_vk::GetSamplerAddressMode(samplerState.getWrapR());
1334 samplerInfo.mipLodBias = 0.0f;
1335 samplerInfo.anisotropyEnable = anisotropyEnable;
1336 samplerInfo.maxAnisotropy = maxAnisotropy;
1337 samplerInfo.compareEnable = compareEnable;
1338 samplerInfo.compareOp = compareOp;
1339 samplerInfo.minLod = samplerState.getMinLod();
1340 samplerInfo.maxLod = samplerState.getMaxLod();
1341 samplerInfo.borderColor = VK_BORDER_COLOR_INT_TRANSPARENT_BLACK;
1342 samplerInfo.unnormalizedCoordinates = VK_FALSE;
1343
1344 ANGLE_VK_TRY(contextVk, mSampler.init(contextVk->getDevice(), samplerInfo));
1345
1346 // Regenerate the serial on a sampler change.
1347 mSerial = contextVk->generateTextureSerial();
1348
1349 return angle::Result::Continue;
1350 }
1351
setStorageMultisample(const gl::Context * context,gl::TextureType type,GLsizei samples,GLint internalformat,const gl::Extents & size,bool fixedSampleLocations)1352 angle::Result TextureVk::setStorageMultisample(const gl::Context *context,
1353 gl::TextureType type,
1354 GLsizei samples,
1355 GLint internalformat,
1356 const gl::Extents &size,
1357 bool fixedSampleLocations)
1358 {
1359 ANGLE_VK_UNREACHABLE(vk::GetImpl(context));
1360 return angle::Result::Stop;
1361 }
1362
initializeContents(const gl::Context * context,const gl::ImageIndex & imageIndex)1363 angle::Result TextureVk::initializeContents(const gl::Context *context,
1364 const gl::ImageIndex &imageIndex)
1365 {
1366 const gl::ImageDesc &desc = mState.getImageDesc(imageIndex);
1367 const vk::Format &format =
1368 vk::GetImpl(context)->getRenderer()->getFormat(desc.format.info->sizedInternalFormat);
1369
1370 mImage->stageSubresourceRobustClear(imageIndex, format.angleFormat());
1371
1372 // Note that we cannot ensure the image is initialized because we might be calling subImage
1373 // on a non-complete cube map.
1374 return angle::Result::Continue;
1375 }
1376
releaseOwnershipOfImage(const gl::Context * context)1377 void TextureVk::releaseOwnershipOfImage(const gl::Context *context)
1378 {
1379 ContextVk *contextVk = vk::GetImpl(context);
1380
1381 mOwnsImage = false;
1382 releaseAndDeleteImage(contextVk);
1383 }
1384
getTextureViews() const1385 const TextureVk::TextureVkViews *TextureVk::getTextureViews() const
1386 {
1387 VkImageAspectFlags aspectFlags = mImage->getAspectFlags();
1388 if (HasBothDepthAndStencilAspects(aspectFlags) && mState.isStencilMode())
1389 {
1390 return &mStencilViews;
1391 }
1392 return &mDefaultViews;
1393 }
1394
getReadImageView() const1395 const vk::ImageView &TextureVk::getReadImageView() const
1396 {
1397 ASSERT(mImage->valid());
1398 const TextureVkViews *activeView = getTextureViews();
1399
1400 if (!gl::IsMipmapFiltered(mState.getSamplerState()))
1401 {
1402 return activeView->mReadBaseLevelImageView;
1403 }
1404
1405 return activeView->mReadMipmapImageView;
1406 }
1407
getFetchImageView() const1408 const vk::ImageView &TextureVk::getFetchImageView() const
1409 {
1410
1411 if (!mDefaultViews.mFetchBaseLevelImageView.valid())
1412 {
1413 return getReadImageView();
1414 }
1415
1416 ASSERT(mImage->valid());
1417 const TextureVkViews *activeView = getTextureViews();
1418
1419 if (!gl::IsMipmapFiltered(mState.getSamplerState()))
1420 {
1421 return activeView->mFetchBaseLevelImageView;
1422 }
1423
1424 return activeView->mFetchMipmapImageView;
1425 }
1426
getLayerLevelDrawImageView(vk::Context * context,size_t layer,size_t level,vk::ImageView ** imageViewOut)1427 angle::Result TextureVk::getLayerLevelDrawImageView(vk::Context *context,
1428 size_t layer,
1429 size_t level,
1430 vk::ImageView **imageViewOut)
1431 {
1432 ASSERT(mImage->valid());
1433 ASSERT(!mImage->getFormat().imageFormat().isBlock);
1434
1435 // For 3D textures, layer count is tracked as depth
1436 uint32_t layerCount = mState.getType() == gl::TextureType::_3D ? mImage->getExtents().depth
1437 : mImage->getLayerCount();
1438 // Lazily allocate the storage for image views
1439 if (mLayerLevelDrawImageViews.empty())
1440 {
1441 mLayerLevelDrawImageViews.resize(layerCount);
1442 }
1443 ASSERT(mLayerLevelDrawImageViews.size() > layer);
1444
1445 if (mLayerLevelDrawImageViews[layer].empty())
1446 {
1447 mLayerLevelDrawImageViews[layer].resize(mImage->getLevelCount());
1448 }
1449 ASSERT(mLayerLevelDrawImageViews[layer].size() > level);
1450
1451 *imageViewOut = &mLayerLevelDrawImageViews[layer][level];
1452 if ((*imageViewOut)->valid())
1453 {
1454 return angle::Result::Continue;
1455 }
1456
1457 // Lazily allocate the image view itself.
1458 // Note that these views are specifically made to be used as color attachments, and therefore
1459 // don't have swizzle.
1460 gl::TextureType viewType = vk::Get2DTextureType(layerCount, mImage->getSamples());
1461 return mImage->initLayerImageView(context, viewType, mImage->getAspectFlags(),
1462 gl::SwizzleState(), *imageViewOut,
1463 getNativeImageLevel(static_cast<uint32_t>(level)), 1,
1464 getNativeImageLayer(static_cast<uint32_t>(layer)), 1);
1465 }
1466
getSampler() const1467 const vk::Sampler &TextureVk::getSampler() const
1468 {
1469 ASSERT(mSampler.valid());
1470 return mSampler;
1471 }
1472
initImage(ContextVk * contextVk,const vk::Format & format,const gl::Extents & extents,const uint32_t levelCount,vk::CommandBuffer * commandBuffer)1473 angle::Result TextureVk::initImage(ContextVk *contextVk,
1474 const vk::Format &format,
1475 const gl::Extents &extents,
1476 const uint32_t levelCount,
1477 vk::CommandBuffer *commandBuffer)
1478 {
1479 RendererVk *renderer = contextVk->getRenderer();
1480
1481 VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_TRANSFER_DST_BIT |
1482 VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
1483 VK_IMAGE_USAGE_SAMPLED_BIT;
1484 if (renderer->hasImageFormatFeatureBits(format.vkImageFormat,
1485 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT))
1486 {
1487 imageUsageFlags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
1488 }
1489 else if (renderer->hasImageFormatFeatureBits(format.vkImageFormat,
1490 VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT))
1491 {
1492 imageUsageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
1493 }
1494
1495 VkExtent3D vkExtent;
1496 uint32_t layerCount;
1497 gl_vk::GetExtentsAndLayerCount(mState.getType(), extents, &vkExtent, &layerCount);
1498
1499 ANGLE_TRY(mImage->init(contextVk, mState.getType(), vkExtent, format, 1, imageUsageFlags,
1500 levelCount, layerCount));
1501
1502 const VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
1503
1504 ANGLE_TRY(mImage->initMemory(contextVk, renderer->getMemoryProperties(), flags));
1505
1506 ANGLE_TRY(initImageViews(contextVk, format, levelCount, layerCount));
1507
1508 // If the image has an emulated channel, always clear it. These channels will be masked out in
1509 // future writes, and shouldn't contain uninitialized values.
1510 if (format.hasEmulatedImageChannels())
1511 {
1512 uint32_t levelCount = mImage->getLevelCount();
1513
1514 for (uint32_t level = 0; level < levelCount; ++level)
1515 {
1516 gl::ImageIndex index = gl::ImageIndex::Make2DArrayRange(level, 0, layerCount);
1517 mImage->stageSubresourceEmulatedClear(index, format.angleFormat());
1518 onStagingBufferChange();
1519 }
1520 }
1521
1522 mSerial = contextVk->generateTextureSerial();
1523
1524 return angle::Result::Continue;
1525 }
1526
initImageViewImpl(ContextVk * contextVk,const vk::Format & format,uint32_t levelCount,uint32_t layerCount,TextureVkViews * view,VkImageAspectFlags aspectFlags,gl::SwizzleState mappedSwizzle)1527 angle::Result TextureVk::initImageViewImpl(ContextVk *contextVk,
1528 const vk::Format &format,
1529 uint32_t levelCount,
1530 uint32_t layerCount,
1531 TextureVkViews *view,
1532 VkImageAspectFlags aspectFlags,
1533 gl::SwizzleState mappedSwizzle)
1534 {
1535 // TODO: Support non-zero base level for ES 3.0 by passing it to getNativeImageLevel.
1536 // http://anglebug.com/3148
1537 uint32_t baseLevel = getNativeImageLevel(0);
1538 uint32_t baseLayer = getNativeImageLayer(0);
1539
1540 ANGLE_TRY(mImage->initLayerImageView(contextVk, mState.getType(), aspectFlags, mappedSwizzle,
1541 &view->mReadMipmapImageView, baseLevel, levelCount,
1542 baseLayer, layerCount));
1543 ANGLE_TRY(mImage->initLayerImageView(contextVk, mState.getType(), aspectFlags, mappedSwizzle,
1544 &view->mReadBaseLevelImageView, baseLevel, 1, baseLayer,
1545 layerCount));
1546 if (mState.getType() == gl::TextureType::CubeMap ||
1547 mState.getType() == gl::TextureType::_2DArray ||
1548 mState.getType() == gl::TextureType::_2DMultisampleArray)
1549 {
1550 gl::TextureType arrayType = vk::Get2DTextureType(layerCount, mImage->getSamples());
1551
1552 ANGLE_TRY(mImage->initLayerImageView(contextVk, arrayType, aspectFlags, mappedSwizzle,
1553 &view->mFetchMipmapImageView, baseLevel, levelCount,
1554 baseLayer, layerCount));
1555 ANGLE_TRY(mImage->initLayerImageView(contextVk, arrayType, aspectFlags, mappedSwizzle,
1556 &view->mFetchBaseLevelImageView, baseLevel, 1,
1557 baseLayer, layerCount));
1558 }
1559 if (!format.imageFormat().isBlock)
1560 {
1561 ANGLE_TRY(mImage->initLayerImageView(contextVk, mState.getType(), aspectFlags,
1562 gl::SwizzleState(), &view->mDrawBaseLevelImageView,
1563 baseLevel, 1, baseLayer, layerCount));
1564 }
1565
1566 return angle::Result::Continue;
1567 }
1568
initImageViews(ContextVk * contextVk,const vk::Format & format,uint32_t levelCount,uint32_t layerCount)1569 angle::Result TextureVk::initImageViews(ContextVk *contextVk,
1570 const vk::Format &format,
1571 uint32_t levelCount,
1572 uint32_t layerCount)
1573 {
1574 ASSERT(mImage != nullptr);
1575
1576 gl::SwizzleState mappedSwizzle;
1577 MapSwizzleState(contextVk, format, mState.getSwizzleState(), &mappedSwizzle);
1578
1579 VkImageAspectFlags aspectFlags = vk::GetFormatAspectFlags(format.angleFormat());
1580 if (HasBothDepthAndStencilAspects(aspectFlags))
1581 {
1582 ANGLE_TRY(initImageViewImpl(contextVk, format, levelCount, layerCount, &mStencilViews,
1583 VK_IMAGE_ASPECT_STENCIL_BIT, mappedSwizzle));
1584 aspectFlags = VK_IMAGE_ASPECT_DEPTH_BIT;
1585 }
1586 ANGLE_TRY(initImageViewImpl(contextVk, format, levelCount, layerCount, &mDefaultViews,
1587 aspectFlags, mappedSwizzle));
1588
1589 return angle::Result::Continue;
1590 }
1591
releaseImage(ContextVk * contextVk)1592 void TextureVk::releaseImage(ContextVk *contextVk)
1593 {
1594 if (mImage)
1595 {
1596 if (mOwnsImage)
1597 {
1598 mImage->releaseImage(contextVk);
1599 }
1600 else
1601 {
1602 mImage = nullptr;
1603 }
1604 }
1605
1606 releaseImageViews(contextVk);
1607
1608 mCubeMapRenderTargets.clear();
1609 m3DRenderTargets.clear();
1610
1611 onStagingBufferChange();
1612 }
1613
releaseImageViews(ContextVk * contextVk)1614 void TextureVk::releaseImageViews(ContextVk *contextVk)
1615 {
1616 Serial currentSerial = contextVk->getCurrentQueueSerial();
1617
1618 mDefaultViews.release(contextVk, currentSerial);
1619
1620 mStencilViews.release(contextVk, currentSerial);
1621
1622 for (auto &layerViews : mLayerLevelDrawImageViews)
1623 {
1624 for (vk::ImageView &imageView : layerViews)
1625 {
1626 contextVk->releaseObject(currentSerial, &imageView);
1627 }
1628 }
1629 mLayerLevelDrawImageViews.clear();
1630 for (vk::ImageView &imageView : mLayerFetchImageView)
1631 {
1632 contextVk->releaseObject(currentSerial, &imageView);
1633 }
1634 mLayerFetchImageView.clear();
1635 }
1636
releaseStagingBuffer(ContextVk * context)1637 void TextureVk::releaseStagingBuffer(ContextVk *context)
1638 {
1639 if (mImage)
1640 {
1641 mImage->releaseStagingBuffer(context);
1642 }
1643 }
1644
getLevelCount() const1645 uint32_t TextureVk::getLevelCount() const
1646 {
1647 ASSERT(mState.getEffectiveBaseLevel() == 0);
1648
1649 // getMipmapMaxLevel will be 0 here if mipmaps are not used, so the levelCount is always +1.
1650 return mState.getMipmapMaxLevel() + 1;
1651 }
1652 } // namespace rx
1653