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