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