• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2018 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 // vk_helpers:
7 //   Helper utilitiy classes that manage Vulkan resources.
8 
9 #include "libANGLE/renderer/vulkan/vk_helpers.h"
10 
11 #include "common/utilities.h"
12 #include "image_util/loadimage.h"
13 #include "libANGLE/Context.h"
14 #include "libANGLE/renderer/renderer_utils.h"
15 #include "libANGLE/renderer/vulkan/BufferVk.h"
16 #include "libANGLE/renderer/vulkan/ContextVk.h"
17 #include "libANGLE/renderer/vulkan/DisplayVk.h"
18 #include "libANGLE/renderer/vulkan/FramebufferVk.h"
19 #include "libANGLE/renderer/vulkan/RenderTargetVk.h"
20 #include "libANGLE/renderer/vulkan/RendererVk.h"
21 #include "libANGLE/renderer/vulkan/vk_utils.h"
22 #include "libANGLE/trace.h"
23 
24 namespace rx
25 {
26 namespace vk
27 {
28 namespace
29 {
30 // ANGLE_robust_resource_initialization requires color textures to be initialized to zero.
31 constexpr VkClearColorValue kRobustInitColorValue = {{0, 0, 0, 0}};
32 // When emulating a texture, we want the emulated channels to be 0, with alpha 1.
33 constexpr VkClearColorValue kEmulatedInitColorValue = {{0, 0, 0, 1.0f}};
34 // ANGLE_robust_resource_initialization requires depth to be initialized to 1 and stencil to 0.
35 // We are fine with these values for emulated depth/stencil textures too.
36 constexpr VkClearDepthStencilValue kRobustInitDepthStencilValue = {1.0f, 0};
37 
38 constexpr VkBufferUsageFlags kLineLoopDynamicBufferUsage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
39                                                            VK_BUFFER_USAGE_TRANSFER_DST_BIT |
40                                                            VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
41 constexpr int kLineLoopDynamicBufferInitialSize = 1024 * 1024;
42 constexpr VkBufferUsageFlags kLineLoopDynamicIndirectBufferUsage =
43     VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
44     VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
45 constexpr int kLineLoopDynamicIndirectBufferInitialSize = sizeof(VkDrawIndirectCommand) * 16;
46 
47 // This is an arbitrary max. We can change this later if necessary.
48 constexpr uint32_t kDefaultDescriptorPoolMaxSets = 128;
49 
50 struct ImageMemoryBarrierData
51 {
52     // The Vk layout corresponding to the ImageLayout key.
53     VkImageLayout layout;
54     // The stage in which the image is used (or Bottom/Top if not using any specific stage).  Unless
55     // Bottom/Top (Bottom used for transition to and Top used for transition from), the two values
56     // should match.
57     VkPipelineStageFlags dstStageMask;
58     VkPipelineStageFlags srcStageMask;
59     // Access mask when transitioning into this layout.
60     VkAccessFlags dstAccessMask;
61     // Access mask when transitioning out from this layout.  Note that source access mask never
62     // needs a READ bit, as WAR hazards don't need memory barriers (just execution barriers).
63     VkAccessFlags srcAccessMask;
64 
65     // If access is read-only, the memory barrier can be skipped altogether if retransitioning to
66     // the same layout.  This is because read-after-read does not need an execution or memory
67     // barrier.
68     //
69     // Otherwise, some same-layout transitions require a memory barrier.
70     bool sameLayoutTransitionRequiresBarrier;
71 };
72 
73 // clang-format off
74 constexpr angle::PackedEnumMap<ImageLayout, ImageMemoryBarrierData> kImageMemoryBarrierData = {
75     {
76         ImageLayout::Undefined,
77         {
78             VK_IMAGE_LAYOUT_UNDEFINED,
79             VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
80             VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
81             // Transition to: we don't expect to transition into Undefined.
82             0,
83             // Transition from: there's no data in the image to care about.
84             0,
85             false,
86         },
87     },
88     {
89         ImageLayout::ExternalPreInitialized,
90         {
91             VK_IMAGE_LAYOUT_PREINITIALIZED,
92             VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
93             VK_PIPELINE_STAGE_HOST_BIT | VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
94             // Transition to: we don't expect to transition into PreInitialized.
95             0,
96             // Transition from: all writes must finish before barrier.
97             VK_ACCESS_MEMORY_WRITE_BIT,
98             false,
99         },
100     },
101     {
102         ImageLayout::ExternalShadersReadOnly,
103         {
104             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
105             VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
106             VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
107             // Transition to: all reads must happen after barrier.
108             VK_ACCESS_SHADER_READ_BIT,
109             // Transition from: RAR and WAR don't need memory barrier.
110             0,
111             false,
112         },
113     },
114     {
115         ImageLayout::ExternalShadersWrite,
116         {
117             VK_IMAGE_LAYOUT_GENERAL,
118             VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
119             VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
120             // Transition to: all reads and writes must happen after barrier.
121             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
122             // Transition from: all writes must finish before barrier.
123             VK_ACCESS_SHADER_WRITE_BIT,
124             true,
125         },
126     },
127     {
128         ImageLayout::TransferSrc,
129         {
130             VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
131             VK_PIPELINE_STAGE_TRANSFER_BIT,
132             VK_PIPELINE_STAGE_TRANSFER_BIT,
133             // Transition to: all reads must happen after barrier.
134             VK_ACCESS_TRANSFER_READ_BIT,
135             // Transition from: RAR and WAR don't need memory barrier.
136             0,
137             false,
138         },
139     },
140     {
141         ImageLayout::TransferDst,
142         {
143             VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
144             VK_PIPELINE_STAGE_TRANSFER_BIT,
145             VK_PIPELINE_STAGE_TRANSFER_BIT,
146             // Transition to: all writes must happen after barrier.
147             VK_ACCESS_TRANSFER_WRITE_BIT,
148             // Transition from: all writes must finish before barrier.
149             VK_ACCESS_TRANSFER_WRITE_BIT,
150             true,
151         },
152     },
153     {
154         ImageLayout::VertexShaderReadOnly,
155         {
156             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
157             VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
158             VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
159             // Transition to: all reads must happen after barrier.
160             VK_ACCESS_SHADER_READ_BIT,
161             // Transition from: RAR and WAR don't need memory barrier.
162             0,
163             false,
164         },
165     },
166     {
167         ImageLayout::VertexShaderWrite,
168         {
169             VK_IMAGE_LAYOUT_GENERAL,
170             VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
171             VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
172             // Transition to: all reads and writes must happen after barrier.
173             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
174             // Transition from: all writes must finish before barrier.
175             VK_ACCESS_SHADER_WRITE_BIT,
176             true,
177         },
178     },
179     {
180         ImageLayout::GeometryShaderReadOnly,
181         {
182             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
183             VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,
184             VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,
185             // Transition to: all reads must happen after barrier.
186             VK_ACCESS_SHADER_READ_BIT,
187             // Transition from: RAR and WAR don't need memory barrier.
188             0,
189             false,
190         },
191     },
192     {
193         ImageLayout::GeometryShaderWrite,
194         {
195             VK_IMAGE_LAYOUT_GENERAL,
196             VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,
197             VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT,
198             // Transition to: all reads and writes must happen after barrier.
199             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
200             // Transition from: all writes must finish before barrier.
201             VK_ACCESS_SHADER_WRITE_BIT,
202             true,
203         },
204     },
205     {
206         ImageLayout::FragmentShaderReadOnly,
207         {
208             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
209             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
210             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
211             // Transition to: all reads must happen after barrier.
212             VK_ACCESS_SHADER_READ_BIT,
213             // Transition from: RAR and WAR don't need memory barrier.
214             0,
215             false,
216         },
217     },
218     {
219         ImageLayout::FragmentShaderWrite,
220         {
221             VK_IMAGE_LAYOUT_GENERAL,
222             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
223             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
224             // Transition to: all reads and writes must happen after barrier.
225             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
226             // Transition from: all writes must finish before barrier.
227             VK_ACCESS_SHADER_WRITE_BIT,
228             true,
229         },
230     },
231     {
232         ImageLayout::ComputeShaderReadOnly,
233         {
234             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
235             VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
236             VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
237             // Transition to: all reads must happen after barrier.
238             VK_ACCESS_SHADER_READ_BIT,
239             // Transition from: RAR and WAR don't need memory barrier.
240             0,
241             false,
242         },
243     },
244     {
245         ImageLayout::ComputeShaderWrite,
246         {
247             VK_IMAGE_LAYOUT_GENERAL,
248             VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
249             VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
250             // Transition to: all reads and writes must happen after barrier.
251             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
252             // Transition from: all writes must finish before barrier.
253             VK_ACCESS_SHADER_WRITE_BIT,
254             true,
255         },
256     },
257     {
258         ImageLayout::AllGraphicsShadersReadOnly,
259         {
260             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
261             VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
262             VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
263             // Transition to: all reads must happen after barrier.
264             VK_ACCESS_SHADER_READ_BIT,
265             // Transition from: RAR and WAR don't need memory barrier.
266             0,
267             false,
268         },
269     },
270     {
271         ImageLayout::AllGraphicsShadersReadWrite,
272         {
273             VK_IMAGE_LAYOUT_GENERAL,
274             VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
275             VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
276             // Transition to: all reads and writes must happen after barrier.
277             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
278             // Transition from: all writes must finish before barrier.
279             VK_ACCESS_SHADER_WRITE_BIT,
280             true,
281         },
282     },
283     {
284         ImageLayout::ColorAttachment,
285         {
286             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
287             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
288             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
289             // Transition to: all reads and writes must happen after barrier.
290             VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
291             // Transition from: all writes must finish before barrier.
292             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
293             true,
294         },
295     },
296     {
297         ImageLayout::DepthStencilAttachment,
298         {
299             VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
300             VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT,
301             VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
302             // Transition to: all reads and writes must happen after barrier.
303             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
304             // Transition from: all writes must finish before barrier.
305             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
306             true,
307         },
308     },
309     {
310         ImageLayout::Present,
311         {
312             VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
313             VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
314             VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
315             // transition to: vkQueuePresentKHR automatically performs the appropriate memory barriers:
316             //
317             // > Any writes to memory backing the images referenced by the pImageIndices and
318             // > pSwapchains members of pPresentInfo, that are available before vkQueuePresentKHR
319             // > is executed, are automatically made visible to the read access performed by the
320             // > presentation engine.
321             0,
322             // Transition from: RAR and WAR don't need memory barrier.
323             0,
324             false,
325         },
326     },
327 };
328 // clang-format on
329 
GetImageCreateFlags(gl::TextureType textureType)330 VkImageCreateFlags GetImageCreateFlags(gl::TextureType textureType)
331 {
332     switch (textureType)
333     {
334         case gl::TextureType::CubeMap:
335             return VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
336 
337         case gl::TextureType::_3D:
338             return VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
339 
340         default:
341             return 0;
342     }
343 }
344 
HandlePrimitiveRestart(ContextVk * contextVk,gl::DrawElementsType glIndexType,GLsizei indexCount,const uint8_t * srcPtr,uint8_t * outPtr)345 void HandlePrimitiveRestart(ContextVk *contextVk,
346                             gl::DrawElementsType glIndexType,
347                             GLsizei indexCount,
348                             const uint8_t *srcPtr,
349                             uint8_t *outPtr)
350 {
351     switch (glIndexType)
352     {
353         case gl::DrawElementsType::UnsignedByte:
354             if (contextVk->getFeatures().supportsIndexTypeUint8.enabled)
355             {
356                 CopyLineLoopIndicesWithRestart<uint8_t, uint8_t>(indexCount, srcPtr, outPtr);
357             }
358             else
359             {
360                 CopyLineLoopIndicesWithRestart<uint8_t, uint16_t>(indexCount, srcPtr, outPtr);
361             }
362             break;
363         case gl::DrawElementsType::UnsignedShort:
364             CopyLineLoopIndicesWithRestart<uint16_t, uint16_t>(indexCount, srcPtr, outPtr);
365             break;
366         case gl::DrawElementsType::UnsignedInt:
367             CopyLineLoopIndicesWithRestart<uint32_t, uint32_t>(indexCount, srcPtr, outPtr);
368             break;
369         default:
370             UNREACHABLE();
371     }
372 }
373 
HasBothDepthAndStencilAspects(VkImageAspectFlags aspectFlags)374 bool HasBothDepthAndStencilAspects(VkImageAspectFlags aspectFlags)
375 {
376     constexpr VkImageAspectFlags kDepthStencilAspects =
377         VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_DEPTH_BIT;
378     return (aspectFlags & kDepthStencilAspects) == kDepthStencilAspects;
379 }
380 
GetImageLayerCountForView(const ImageHelper & image)381 uint32_t GetImageLayerCountForView(const ImageHelper &image)
382 {
383     // Depth > 1 means this is a 3D texture and depth is our layer count
384     return image.getExtents().depth > 1 ? image.getExtents().depth : image.getLayerCount();
385 }
386 
GetLevelImageView(ImageViewVector * imageViews,uint32_t level,uint32_t levelCount)387 ImageView *GetLevelImageView(ImageViewVector *imageViews, uint32_t level, uint32_t levelCount)
388 {
389     // Lazily allocate the storage for image views. We allocate the full level count because we
390     // don't want to trigger any std::vecotr reallocations. Reallocations could invalidate our
391     // view pointers.
392     if (imageViews->empty())
393     {
394         imageViews->resize(levelCount);
395     }
396     ASSERT(imageViews->size() > level);
397 
398     return &(*imageViews)[level];
399 }
400 
401 // Special rules apply to VkBufferImageCopy with depth/stencil. The components are tightly packed
402 // into a depth or stencil section of the destination buffer. See the spec:
403 // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkBufferImageCopy.html
GetDepthStencilImageToBufferFormat(const angle::Format & imageFormat,VkImageAspectFlagBits copyAspect)404 const angle::Format &GetDepthStencilImageToBufferFormat(const angle::Format &imageFormat,
405                                                         VkImageAspectFlagBits copyAspect)
406 {
407     if (copyAspect == VK_IMAGE_ASPECT_STENCIL_BIT)
408     {
409         ASSERT(imageFormat.id == angle::FormatID::D24_UNORM_S8_UINT ||
410                imageFormat.id == angle::FormatID::D32_FLOAT_S8X24_UINT ||
411                imageFormat.id == angle::FormatID::S8_UINT);
412         return angle::Format::Get(angle::FormatID::S8_UINT);
413     }
414 
415     ASSERT(copyAspect == VK_IMAGE_ASPECT_DEPTH_BIT);
416 
417     switch (imageFormat.id)
418     {
419         case angle::FormatID::D16_UNORM:
420             return imageFormat;
421         case angle::FormatID::D24_UNORM_X8_UINT:
422             return imageFormat;
423         case angle::FormatID::D24_UNORM_S8_UINT:
424             return angle::Format::Get(angle::FormatID::D24_UNORM_X8_UINT);
425         case angle::FormatID::D32_FLOAT:
426             return imageFormat;
427         case angle::FormatID::D32_FLOAT_S8X24_UINT:
428             return angle::Format::Get(angle::FormatID::D32_FLOAT);
429         default:
430             UNREACHABLE();
431             return imageFormat;
432     }
433 }
434 
GetClearValue(const vk::Format & format)435 VkClearValue GetClearValue(const vk::Format &format)
436 {
437     VkClearValue clearValue;
438     if (format.intendedFormat().hasDepthOrStencilBits())
439     {
440         clearValue.depthStencil = kRobustInitDepthStencilValue;
441     }
442     else
443     {
444         clearValue.color =
445             format.hasEmulatedImageChannels() ? kEmulatedInitColorValue : kRobustInitColorValue;
446     }
447     return clearValue;
448 }
449 }  // anonymous namespace
450 
ConvertImageLayoutToVkImageLayout(ImageLayout imageLayout)451 VkImageLayout ConvertImageLayoutToVkImageLayout(ImageLayout imageLayout)
452 {
453     return kImageMemoryBarrierData[imageLayout].layout;
454 }
455 
456 // DynamicBuffer implementation.
DynamicBuffer()457 DynamicBuffer::DynamicBuffer()
458     : mUsage(0),
459       mHostVisible(false),
460       mInitialSize(0),
461       mBuffer(nullptr),
462       mNextAllocationOffset(0),
463       mLastFlushOrInvalidateOffset(0),
464       mSize(0),
465       mAlignment(0)
466 {}
467 
DynamicBuffer(DynamicBuffer && other)468 DynamicBuffer::DynamicBuffer(DynamicBuffer &&other)
469     : mUsage(other.mUsage),
470       mHostVisible(other.mHostVisible),
471       mInitialSize(other.mInitialSize),
472       mBuffer(other.mBuffer),
473       mNextAllocationOffset(other.mNextAllocationOffset),
474       mLastFlushOrInvalidateOffset(other.mLastFlushOrInvalidateOffset),
475       mSize(other.mSize),
476       mAlignment(other.mAlignment),
477       mInFlightBuffers(std::move(other.mInFlightBuffers))
478 {
479     other.mBuffer = nullptr;
480 }
481 
init(RendererVk * renderer,VkBufferUsageFlags usage,size_t alignment,size_t initialSize,bool hostVisible)482 void DynamicBuffer::init(RendererVk *renderer,
483                          VkBufferUsageFlags usage,
484                          size_t alignment,
485                          size_t initialSize,
486                          bool hostVisible)
487 {
488     mUsage       = usage;
489     mHostVisible = hostVisible;
490 
491     // Check that we haven't overriden the initial size of the buffer in setMinimumSizeForTesting.
492     if (mInitialSize == 0)
493     {
494         mInitialSize = initialSize;
495         mSize        = 0;
496     }
497 
498     // Workaround for the mock ICD not supporting allocations greater than 0x1000.
499     // Could be removed if https://github.com/KhronosGroup/Vulkan-Tools/issues/84 is fixed.
500     if (renderer->isMockICDEnabled())
501     {
502         mSize = std::min<size_t>(mSize, 0x1000);
503     }
504 
505     updateAlignment(renderer, alignment);
506 }
507 
~DynamicBuffer()508 DynamicBuffer::~DynamicBuffer()
509 {
510     ASSERT(mBuffer == nullptr);
511 }
512 
allocateNewBuffer(ContextVk * contextVk)513 angle::Result DynamicBuffer::allocateNewBuffer(ContextVk *contextVk)
514 {
515     std::unique_ptr<BufferHelper> buffer = std::make_unique<BufferHelper>();
516 
517     VkBufferCreateInfo createInfo    = {};
518     createInfo.sType                 = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
519     createInfo.flags                 = 0;
520     createInfo.size                  = mSize;
521     createInfo.usage                 = mUsage;
522     createInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
523     createInfo.queueFamilyIndexCount = 0;
524     createInfo.pQueueFamilyIndices   = nullptr;
525 
526     const VkMemoryPropertyFlags memoryProperty =
527         mHostVisible ? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT : VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
528     ANGLE_TRY(buffer->init(contextVk, createInfo, memoryProperty));
529 
530     ASSERT(!mBuffer);
531     mBuffer = buffer.release();
532 
533     return angle::Result::Continue;
534 }
535 
allocate(ContextVk * contextVk,size_t sizeInBytes,uint8_t ** ptrOut,VkBuffer * bufferOut,VkDeviceSize * offsetOut,bool * newBufferAllocatedOut)536 angle::Result DynamicBuffer::allocate(ContextVk *contextVk,
537                                       size_t sizeInBytes,
538                                       uint8_t **ptrOut,
539                                       VkBuffer *bufferOut,
540                                       VkDeviceSize *offsetOut,
541                                       bool *newBufferAllocatedOut)
542 {
543     size_t sizeToAllocate = roundUp(sizeInBytes, mAlignment);
544 
545     angle::base::CheckedNumeric<size_t> checkedNextWriteOffset = mNextAllocationOffset;
546     checkedNextWriteOffset += sizeToAllocate;
547 
548     if (!checkedNextWriteOffset.IsValid() || checkedNextWriteOffset.ValueOrDie() >= mSize)
549     {
550         if (mBuffer)
551         {
552             ANGLE_TRY(flush(contextVk));
553             mBuffer->unmap(contextVk->getRenderer());
554 
555             mInFlightBuffers.push_back(mBuffer);
556             mBuffer = nullptr;
557         }
558 
559         if (sizeToAllocate > mSize)
560         {
561             mSize = std::max(mInitialSize, sizeToAllocate);
562 
563             // Clear the free list since the free buffers are now too small.
564             for (BufferHelper *toFree : mBufferFreeList)
565             {
566                 toFree->release(contextVk->getRenderer());
567             }
568             mBufferFreeList.clear();
569         }
570 
571         // The front of the free list should be the oldest. Thus if it is in use the rest of the
572         // free list should be in use as well.
573         if (mBufferFreeList.empty() ||
574             mBufferFreeList.front()->isCurrentlyInUse(contextVk->getLastCompletedQueueSerial()))
575         {
576             ANGLE_TRY(allocateNewBuffer(contextVk));
577         }
578         else
579         {
580             mBuffer = mBufferFreeList.front();
581             mBufferFreeList.erase(mBufferFreeList.begin());
582         }
583 
584         ASSERT(mBuffer->getSize() == mSize);
585 
586         mNextAllocationOffset        = 0;
587         mLastFlushOrInvalidateOffset = 0;
588 
589         if (newBufferAllocatedOut != nullptr)
590         {
591             *newBufferAllocatedOut = true;
592         }
593     }
594     else if (newBufferAllocatedOut != nullptr)
595     {
596         *newBufferAllocatedOut = false;
597     }
598 
599     ASSERT(mBuffer != nullptr);
600 
601     if (bufferOut != nullptr)
602     {
603         *bufferOut = mBuffer->getBuffer().getHandle();
604     }
605 
606     // Optionally map() the buffer if possible
607     if (ptrOut)
608     {
609         ASSERT(mHostVisible);
610         uint8_t *mappedMemory;
611         ANGLE_TRY(mBuffer->map(contextVk, &mappedMemory));
612         *ptrOut = mappedMemory + mNextAllocationOffset;
613     }
614 
615     *offsetOut = static_cast<VkDeviceSize>(mNextAllocationOffset);
616     mNextAllocationOffset += static_cast<uint32_t>(sizeToAllocate);
617     return angle::Result::Continue;
618 }
619 
flush(ContextVk * contextVk)620 angle::Result DynamicBuffer::flush(ContextVk *contextVk)
621 {
622     if (mHostVisible && (mNextAllocationOffset > mLastFlushOrInvalidateOffset))
623     {
624         ASSERT(mBuffer != nullptr);
625         ANGLE_TRY(mBuffer->flush(contextVk->getRenderer(), mLastFlushOrInvalidateOffset,
626                                  mNextAllocationOffset - mLastFlushOrInvalidateOffset));
627         mLastFlushOrInvalidateOffset = mNextAllocationOffset;
628     }
629     return angle::Result::Continue;
630 }
631 
invalidate(ContextVk * contextVk)632 angle::Result DynamicBuffer::invalidate(ContextVk *contextVk)
633 {
634     if (mHostVisible && (mNextAllocationOffset > mLastFlushOrInvalidateOffset))
635     {
636         ASSERT(mBuffer != nullptr);
637         ANGLE_TRY(mBuffer->invalidate(contextVk->getRenderer(), mLastFlushOrInvalidateOffset,
638                                       mNextAllocationOffset - mLastFlushOrInvalidateOffset));
639         mLastFlushOrInvalidateOffset = mNextAllocationOffset;
640     }
641     return angle::Result::Continue;
642 }
643 
releaseBufferListToRenderer(RendererVk * renderer,std::vector<BufferHelper * > * buffers)644 void DynamicBuffer::releaseBufferListToRenderer(RendererVk *renderer,
645                                                 std::vector<BufferHelper *> *buffers)
646 {
647     for (BufferHelper *toFree : *buffers)
648     {
649         toFree->release(renderer);
650         delete toFree;
651     }
652 
653     buffers->clear();
654 }
655 
destroyBufferList(RendererVk * renderer,std::vector<BufferHelper * > * buffers)656 void DynamicBuffer::destroyBufferList(RendererVk *renderer, std::vector<BufferHelper *> *buffers)
657 {
658     for (BufferHelper *toFree : *buffers)
659     {
660         toFree->destroy(renderer);
661         delete toFree;
662     }
663 
664     buffers->clear();
665 }
666 
release(RendererVk * renderer)667 void DynamicBuffer::release(RendererVk *renderer)
668 {
669     reset();
670 
671     releaseBufferListToRenderer(renderer, &mInFlightBuffers);
672     releaseBufferListToRenderer(renderer, &mBufferFreeList);
673 
674     if (mBuffer)
675     {
676         mBuffer->release(renderer);
677         SafeDelete(mBuffer);
678     }
679 }
680 
releaseInFlightBuffers(ContextVk * contextVk)681 void DynamicBuffer::releaseInFlightBuffers(ContextVk *contextVk)
682 {
683     for (BufferHelper *toRelease : mInFlightBuffers)
684     {
685         // If the dynamic buffer was resized we cannot reuse the retained buffer.
686         if (toRelease->getSize() < mSize)
687         {
688             toRelease->release(contextVk->getRenderer());
689         }
690         else
691         {
692             mBufferFreeList.push_back(toRelease);
693         }
694     }
695 
696     mInFlightBuffers.clear();
697 }
698 
destroy(RendererVk * renderer)699 void DynamicBuffer::destroy(RendererVk *renderer)
700 {
701     reset();
702 
703     destroyBufferList(renderer, &mInFlightBuffers);
704     destroyBufferList(renderer, &mBufferFreeList);
705 
706     if (mBuffer)
707     {
708         mBuffer->unmap(renderer);
709         mBuffer->destroy(renderer);
710         delete mBuffer;
711         mBuffer = nullptr;
712     }
713 }
714 
updateAlignment(RendererVk * renderer,size_t alignment)715 void DynamicBuffer::updateAlignment(RendererVk *renderer, size_t alignment)
716 {
717     ASSERT(alignment > 0);
718 
719     size_t atomSize =
720         static_cast<size_t>(renderer->getPhysicalDeviceProperties().limits.nonCoherentAtomSize);
721 
722     // We need lcm(alignment, atomSize).  Usually, one divides the other so std::max() could be used
723     // instead.  Only known case where this assumption breaks is for 3-component types with 16- or
724     // 32-bit channels, so that's special-cased to avoid a full-fledged lcm implementation.
725 
726     if (gl::isPow2(alignment))
727     {
728         ASSERT(alignment % atomSize == 0 || atomSize % alignment == 0);
729         ASSERT(gl::isPow2(atomSize));
730 
731         alignment = std::max(alignment, atomSize);
732     }
733     else
734     {
735         ASSERT(gl::isPow2(atomSize));
736         ASSERT(alignment % 3 == 0);
737         ASSERT(gl::isPow2(alignment / 3));
738 
739         alignment = std::max(alignment / 3, atomSize) * 3;
740     }
741 
742     // If alignment has changed, make sure the next allocation is done at an aligned offset.
743     if (alignment != mAlignment)
744     {
745         mNextAllocationOffset = roundUp(mNextAllocationOffset, static_cast<uint32_t>(alignment));
746     }
747 
748     mAlignment = alignment;
749 }
750 
setMinimumSizeForTesting(size_t minSize)751 void DynamicBuffer::setMinimumSizeForTesting(size_t minSize)
752 {
753     // This will really only have an effect next time we call allocate.
754     mInitialSize = minSize;
755 
756     // Forces a new allocation on the next allocate.
757     mSize = 0;
758 }
759 
reset()760 void DynamicBuffer::reset()
761 {
762     mSize                        = 0;
763     mNextAllocationOffset        = 0;
764     mLastFlushOrInvalidateOffset = 0;
765 }
766 
767 // DynamicShadowBuffer implementation.
DynamicShadowBuffer()768 DynamicShadowBuffer::DynamicShadowBuffer() : mInitialSize(0), mSize(0) {}
769 
DynamicShadowBuffer(DynamicShadowBuffer && other)770 DynamicShadowBuffer::DynamicShadowBuffer(DynamicShadowBuffer &&other)
771     : mInitialSize(other.mInitialSize), mSize(other.mSize), mBuffer(std::move(other.mBuffer))
772 {}
773 
init(size_t initialSize)774 void DynamicShadowBuffer::init(size_t initialSize)
775 {
776     mInitialSize = initialSize;
777 }
778 
~DynamicShadowBuffer()779 DynamicShadowBuffer::~DynamicShadowBuffer()
780 {
781     ASSERT(mBuffer.empty());
782 }
783 
allocate(size_t sizeInBytes)784 angle::Result DynamicShadowBuffer::allocate(size_t sizeInBytes)
785 {
786     bool result = true;
787 
788     // Delete the current buffer, if any
789     if (!mBuffer.empty())
790     {
791         result &= mBuffer.resize(0);
792     }
793 
794     // Cache the new size
795     mSize = std::max(mInitialSize, sizeInBytes);
796 
797     // Allocate the buffer
798     result &= mBuffer.resize(mSize);
799 
800     // If allocation failed, release the buffer and return error.
801     if (!result)
802     {
803         release();
804         return angle::Result::Stop;
805     }
806 
807     return angle::Result::Continue;
808 }
809 
release()810 void DynamicShadowBuffer::release()
811 {
812     reset();
813 
814     if (!mBuffer.empty())
815     {
816         (void)mBuffer.resize(0);
817     }
818 }
819 
destroy(VkDevice device)820 void DynamicShadowBuffer::destroy(VkDevice device)
821 {
822     release();
823 }
824 
reset()825 void DynamicShadowBuffer::reset()
826 {
827     mSize = 0;
828 }
829 
830 // DescriptorPoolHelper implementation.
DescriptorPoolHelper()831 DescriptorPoolHelper::DescriptorPoolHelper() : mFreeDescriptorSets(0) {}
832 
833 DescriptorPoolHelper::~DescriptorPoolHelper() = default;
834 
hasCapacity(uint32_t descriptorSetCount) const835 bool DescriptorPoolHelper::hasCapacity(uint32_t descriptorSetCount) const
836 {
837     return mFreeDescriptorSets >= descriptorSetCount;
838 }
839 
init(Context * context,const std::vector<VkDescriptorPoolSize> & poolSizes,uint32_t maxSets)840 angle::Result DescriptorPoolHelper::init(Context *context,
841                                          const std::vector<VkDescriptorPoolSize> &poolSizes,
842                                          uint32_t maxSets)
843 {
844     if (mDescriptorPool.valid())
845     {
846         // This could be improved by recycling the descriptor pool.
847         mDescriptorPool.destroy(context->getDevice());
848     }
849 
850     VkDescriptorPoolCreateInfo descriptorPoolInfo = {};
851     descriptorPoolInfo.sType                      = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
852     descriptorPoolInfo.flags                      = 0;
853     descriptorPoolInfo.maxSets                    = maxSets;
854     descriptorPoolInfo.poolSizeCount              = static_cast<uint32_t>(poolSizes.size());
855     descriptorPoolInfo.pPoolSizes                 = poolSizes.data();
856 
857     mFreeDescriptorSets = maxSets;
858 
859     ANGLE_VK_TRY(context, mDescriptorPool.init(context->getDevice(), descriptorPoolInfo));
860     return angle::Result::Continue;
861 }
862 
destroy(VkDevice device)863 void DescriptorPoolHelper::destroy(VkDevice device)
864 {
865     mDescriptorPool.destroy(device);
866 }
867 
release(ContextVk * contextVk)868 void DescriptorPoolHelper::release(ContextVk *contextVk)
869 {
870     contextVk->addGarbage(&mDescriptorPool);
871 }
872 
allocateSets(ContextVk * contextVk,const VkDescriptorSetLayout * descriptorSetLayout,uint32_t descriptorSetCount,VkDescriptorSet * descriptorSetsOut)873 angle::Result DescriptorPoolHelper::allocateSets(ContextVk *contextVk,
874                                                  const VkDescriptorSetLayout *descriptorSetLayout,
875                                                  uint32_t descriptorSetCount,
876                                                  VkDescriptorSet *descriptorSetsOut)
877 {
878     VkDescriptorSetAllocateInfo allocInfo = {};
879     allocInfo.sType                       = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
880     allocInfo.descriptorPool              = mDescriptorPool.getHandle();
881     allocInfo.descriptorSetCount          = descriptorSetCount;
882     allocInfo.pSetLayouts                 = descriptorSetLayout;
883 
884     ASSERT(mFreeDescriptorSets >= descriptorSetCount);
885     mFreeDescriptorSets -= descriptorSetCount;
886 
887     ANGLE_VK_TRY(contextVk, mDescriptorPool.allocateDescriptorSets(contextVk->getDevice(),
888                                                                    allocInfo, descriptorSetsOut));
889     return angle::Result::Continue;
890 }
891 
892 // DynamicDescriptorPool implementation.
DynamicDescriptorPool()893 DynamicDescriptorPool::DynamicDescriptorPool()
894     : mMaxSetsPerPool(kDefaultDescriptorPoolMaxSets), mCurrentPoolIndex(0)
895 {}
896 
897 DynamicDescriptorPool::~DynamicDescriptorPool() = default;
898 
init(ContextVk * contextVk,const VkDescriptorPoolSize * setSizes,uint32_t setSizeCount)899 angle::Result DynamicDescriptorPool::init(ContextVk *contextVk,
900                                           const VkDescriptorPoolSize *setSizes,
901                                           uint32_t setSizeCount)
902 {
903     ASSERT(mCurrentPoolIndex == 0);
904     ASSERT(mDescriptorPools.empty() || (mDescriptorPools.size() == 1 &&
905                                         mDescriptorPools[0]->get().hasCapacity(mMaxSetsPerPool)));
906 
907     mPoolSizes.assign(setSizes, setSizes + setSizeCount);
908     for (uint32_t i = 0; i < setSizeCount; ++i)
909     {
910         mPoolSizes[i].descriptorCount *= mMaxSetsPerPool;
911     }
912 
913     mDescriptorPools.push_back(new RefCountedDescriptorPoolHelper());
914     return mDescriptorPools[0]->get().init(contextVk, mPoolSizes, mMaxSetsPerPool);
915 }
916 
destroy(VkDevice device)917 void DynamicDescriptorPool::destroy(VkDevice device)
918 {
919     for (RefCountedDescriptorPoolHelper *pool : mDescriptorPools)
920     {
921         ASSERT(!pool->isReferenced());
922         pool->get().destroy(device);
923         delete pool;
924     }
925 
926     mDescriptorPools.clear();
927 }
928 
release(ContextVk * contextVk)929 void DynamicDescriptorPool::release(ContextVk *contextVk)
930 {
931     for (RefCountedDescriptorPoolHelper *pool : mDescriptorPools)
932     {
933         ASSERT(!pool->isReferenced());
934         pool->get().release(contextVk);
935         delete pool;
936     }
937 
938     mDescriptorPools.clear();
939 }
940 
allocateSetsAndGetInfo(ContextVk * contextVk,const VkDescriptorSetLayout * descriptorSetLayout,uint32_t descriptorSetCount,RefCountedDescriptorPoolBinding * bindingOut,VkDescriptorSet * descriptorSetsOut,bool * newPoolAllocatedOut)941 angle::Result DynamicDescriptorPool::allocateSetsAndGetInfo(
942     ContextVk *contextVk,
943     const VkDescriptorSetLayout *descriptorSetLayout,
944     uint32_t descriptorSetCount,
945     RefCountedDescriptorPoolBinding *bindingOut,
946     VkDescriptorSet *descriptorSetsOut,
947     bool *newPoolAllocatedOut)
948 {
949     *newPoolAllocatedOut = false;
950 
951     if (!bindingOut->valid() || !bindingOut->get().hasCapacity(descriptorSetCount))
952     {
953         if (!mDescriptorPools[mCurrentPoolIndex]->get().hasCapacity(descriptorSetCount))
954         {
955             ANGLE_TRY(allocateNewPool(contextVk));
956             *newPoolAllocatedOut = true;
957         }
958 
959         // Make sure the old binding knows the descriptor sets can still be in-use. We only need
960         // to update the serial when we move to a new pool. This is because we only check serials
961         // when we move to a new pool.
962         if (bindingOut->valid())
963         {
964             Serial currentSerial = contextVk->getCurrentQueueSerial();
965             bindingOut->get().updateSerial(currentSerial);
966         }
967 
968         bindingOut->set(mDescriptorPools[mCurrentPoolIndex]);
969     }
970 
971     return bindingOut->get().allocateSets(contextVk, descriptorSetLayout, descriptorSetCount,
972                                           descriptorSetsOut);
973 }
974 
allocateNewPool(ContextVk * contextVk)975 angle::Result DynamicDescriptorPool::allocateNewPool(ContextVk *contextVk)
976 {
977     bool found = false;
978 
979     for (size_t poolIndex = 0; poolIndex < mDescriptorPools.size(); ++poolIndex)
980     {
981         if (!mDescriptorPools[poolIndex]->isReferenced() &&
982             !contextVk->isSerialInUse(mDescriptorPools[poolIndex]->get().getSerial()))
983         {
984             mCurrentPoolIndex = poolIndex;
985             found             = true;
986             break;
987         }
988     }
989 
990     if (!found)
991     {
992         mDescriptorPools.push_back(new RefCountedDescriptorPoolHelper());
993         mCurrentPoolIndex = mDescriptorPools.size() - 1;
994 
995         static constexpr size_t kMaxPools = 99999;
996         ANGLE_VK_CHECK(contextVk, mDescriptorPools.size() < kMaxPools, VK_ERROR_TOO_MANY_OBJECTS);
997     }
998 
999     return mDescriptorPools[mCurrentPoolIndex]->get().init(contextVk, mPoolSizes, mMaxSetsPerPool);
1000 }
1001 
setMaxSetsPerPoolForTesting(uint32_t maxSetsPerPool)1002 void DynamicDescriptorPool::setMaxSetsPerPoolForTesting(uint32_t maxSetsPerPool)
1003 {
1004     mMaxSetsPerPool = maxSetsPerPool;
1005 }
1006 
1007 // DynamicallyGrowingPool implementation
1008 template <typename Pool>
DynamicallyGrowingPool()1009 DynamicallyGrowingPool<Pool>::DynamicallyGrowingPool()
1010     : mPoolSize(0), mCurrentPool(0), mCurrentFreeEntry(0)
1011 {}
1012 
1013 template <typename Pool>
1014 DynamicallyGrowingPool<Pool>::~DynamicallyGrowingPool() = default;
1015 
1016 template <typename Pool>
initEntryPool(Context * contextVk,uint32_t poolSize)1017 angle::Result DynamicallyGrowingPool<Pool>::initEntryPool(Context *contextVk, uint32_t poolSize)
1018 {
1019     ASSERT(mPools.empty() && mPoolStats.empty());
1020     mPoolSize = poolSize;
1021     return angle::Result::Continue;
1022 }
1023 
1024 template <typename Pool>
destroyEntryPool()1025 void DynamicallyGrowingPool<Pool>::destroyEntryPool()
1026 {
1027     mPools.clear();
1028     mPoolStats.clear();
1029 }
1030 
1031 template <typename Pool>
findFreeEntryPool(ContextVk * contextVk)1032 bool DynamicallyGrowingPool<Pool>::findFreeEntryPool(ContextVk *contextVk)
1033 {
1034     Serial lastCompletedQueueSerial = contextVk->getLastCompletedQueueSerial();
1035     for (size_t i = 0; i < mPools.size(); ++i)
1036     {
1037         if (mPoolStats[i].freedCount == mPoolSize &&
1038             mPoolStats[i].serial <= lastCompletedQueueSerial)
1039         {
1040             mCurrentPool      = i;
1041             mCurrentFreeEntry = 0;
1042 
1043             mPoolStats[i].freedCount = 0;
1044 
1045             return true;
1046         }
1047     }
1048 
1049     return false;
1050 }
1051 
1052 template <typename Pool>
allocateNewEntryPool(ContextVk * contextVk,Pool && pool)1053 angle::Result DynamicallyGrowingPool<Pool>::allocateNewEntryPool(ContextVk *contextVk, Pool &&pool)
1054 {
1055     mPools.push_back(std::move(pool));
1056 
1057     PoolStats poolStats = {0, Serial()};
1058     mPoolStats.push_back(poolStats);
1059 
1060     mCurrentPool      = mPools.size() - 1;
1061     mCurrentFreeEntry = 0;
1062 
1063     return angle::Result::Continue;
1064 }
1065 
1066 template <typename Pool>
onEntryFreed(ContextVk * contextVk,size_t poolIndex)1067 void DynamicallyGrowingPool<Pool>::onEntryFreed(ContextVk *contextVk, size_t poolIndex)
1068 {
1069     ASSERT(poolIndex < mPoolStats.size() && mPoolStats[poolIndex].freedCount < mPoolSize);
1070 
1071     // Take note of the current serial to avoid reallocating a query in the same pool
1072     mPoolStats[poolIndex].serial = contextVk->getCurrentQueueSerial();
1073     ++mPoolStats[poolIndex].freedCount;
1074 }
1075 
1076 // DynamicQueryPool implementation
1077 DynamicQueryPool::DynamicQueryPool() = default;
1078 
1079 DynamicQueryPool::~DynamicQueryPool() = default;
1080 
init(ContextVk * contextVk,VkQueryType type,uint32_t poolSize)1081 angle::Result DynamicQueryPool::init(ContextVk *contextVk, VkQueryType type, uint32_t poolSize)
1082 {
1083     ANGLE_TRY(initEntryPool(contextVk, poolSize));
1084 
1085     mQueryType = type;
1086     ANGLE_TRY(allocateNewPool(contextVk));
1087 
1088     return angle::Result::Continue;
1089 }
1090 
destroy(VkDevice device)1091 void DynamicQueryPool::destroy(VkDevice device)
1092 {
1093     for (QueryPool &queryPool : mPools)
1094     {
1095         queryPool.destroy(device);
1096     }
1097 
1098     destroyEntryPool();
1099 }
1100 
allocateQuery(ContextVk * contextVk,QueryHelper * queryOut)1101 angle::Result DynamicQueryPool::allocateQuery(ContextVk *contextVk, QueryHelper *queryOut)
1102 {
1103     ASSERT(!queryOut->valid());
1104 
1105     if (mCurrentFreeEntry >= mPoolSize)
1106     {
1107         // No more queries left in this pool, create another one.
1108         ANGLE_TRY(allocateNewPool(contextVk));
1109     }
1110 
1111     uint32_t queryIndex = mCurrentFreeEntry++;
1112     queryOut->init(this, mCurrentPool, queryIndex);
1113 
1114     return angle::Result::Continue;
1115 }
1116 
freeQuery(ContextVk * contextVk,QueryHelper * query)1117 void DynamicQueryPool::freeQuery(ContextVk *contextVk, QueryHelper *query)
1118 {
1119     if (query->valid())
1120     {
1121         size_t poolIndex = query->mQueryPoolIndex;
1122         ASSERT(getQueryPool(poolIndex).valid());
1123 
1124         onEntryFreed(contextVk, poolIndex);
1125 
1126         query->deinit();
1127     }
1128 }
1129 
allocateNewPool(ContextVk * contextVk)1130 angle::Result DynamicQueryPool::allocateNewPool(ContextVk *contextVk)
1131 {
1132     if (findFreeEntryPool(contextVk))
1133     {
1134         return angle::Result::Continue;
1135     }
1136 
1137     VkQueryPoolCreateInfo queryPoolInfo = {};
1138     queryPoolInfo.sType                 = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
1139     queryPoolInfo.flags                 = 0;
1140     queryPoolInfo.queryType             = mQueryType;
1141     queryPoolInfo.queryCount            = mPoolSize;
1142     queryPoolInfo.pipelineStatistics    = 0;
1143 
1144     QueryPool queryPool;
1145 
1146     ANGLE_VK_TRY(contextVk, queryPool.init(contextVk->getDevice(), queryPoolInfo));
1147 
1148     return allocateNewEntryPool(contextVk, std::move(queryPool));
1149 }
1150 
1151 // QueryHelper implementation
QueryHelper()1152 QueryHelper::QueryHelper() : mDynamicQueryPool(nullptr), mQueryPoolIndex(0), mQuery(0) {}
1153 
~QueryHelper()1154 QueryHelper::~QueryHelper() {}
1155 
init(const DynamicQueryPool * dynamicQueryPool,const size_t queryPoolIndex,uint32_t query)1156 void QueryHelper::init(const DynamicQueryPool *dynamicQueryPool,
1157                        const size_t queryPoolIndex,
1158                        uint32_t query)
1159 {
1160     mDynamicQueryPool = dynamicQueryPool;
1161     mQueryPoolIndex   = queryPoolIndex;
1162     mQuery            = query;
1163 }
1164 
deinit()1165 void QueryHelper::deinit()
1166 {
1167     mDynamicQueryPool = nullptr;
1168     mQueryPoolIndex   = 0;
1169     mQuery            = 0;
1170     mMostRecentSerial = Serial();
1171 }
1172 
beginQuery(ContextVk * contextVk)1173 angle::Result QueryHelper::beginQuery(ContextVk *contextVk)
1174 {
1175     vk::PrimaryCommandBuffer *primaryCommands;
1176     ANGLE_TRY(contextVk->flushAndGetPrimaryCommandBuffer(&primaryCommands));
1177     const QueryPool &queryPool = getQueryPool();
1178     primaryCommands->resetQueryPool(queryPool, mQuery, 1);
1179     primaryCommands->beginQuery(queryPool, mQuery, 0);
1180     mMostRecentSerial = contextVk->getCurrentQueueSerial();
1181     return angle::Result::Continue;
1182 }
1183 
endQuery(ContextVk * contextVk)1184 angle::Result QueryHelper::endQuery(ContextVk *contextVk)
1185 {
1186     vk::PrimaryCommandBuffer *primaryCommands;
1187     ANGLE_TRY(contextVk->flushAndGetPrimaryCommandBuffer(&primaryCommands));
1188     primaryCommands->endQuery(getQueryPool(), mQuery);
1189     mMostRecentSerial = contextVk->getCurrentQueueSerial();
1190     return angle::Result::Continue;
1191 }
1192 
beginOcclusionQuery(ContextVk * contextVk,PrimaryCommandBuffer * primaryCommands,CommandBuffer * renderPassCommandBuffer)1193 void QueryHelper::beginOcclusionQuery(ContextVk *contextVk,
1194                                       PrimaryCommandBuffer *primaryCommands,
1195                                       CommandBuffer *renderPassCommandBuffer)
1196 {
1197     const QueryPool &queryPool = getQueryPool();
1198     // reset has to be encoded in primary command buffer per spec
1199     primaryCommands->resetQueryPool(queryPool, mQuery, 1);
1200     renderPassCommandBuffer->beginQuery(queryPool.getHandle(), mQuery, 0);
1201     mMostRecentSerial = contextVk->getCurrentQueueSerial();
1202 }
1203 
endOcclusionQuery(ContextVk * contextVk,CommandBuffer * renderPassCommandBuffer)1204 void QueryHelper::endOcclusionQuery(ContextVk *contextVk, CommandBuffer *renderPassCommandBuffer)
1205 {
1206     renderPassCommandBuffer->endQuery(getQueryPool().getHandle(), mQuery);
1207     mMostRecentSerial = contextVk->getCurrentQueueSerial();
1208 }
1209 
flushAndWriteTimestamp(ContextVk * contextVk)1210 angle::Result QueryHelper::flushAndWriteTimestamp(ContextVk *contextVk)
1211 {
1212     vk::PrimaryCommandBuffer *primary;
1213     ANGLE_TRY(contextVk->flushAndGetPrimaryCommandBuffer(&primary));
1214     writeTimestamp(contextVk, primary);
1215     return angle::Result::Continue;
1216 }
1217 
writeTimestamp(ContextVk * contextVk,PrimaryCommandBuffer * primary)1218 void QueryHelper::writeTimestamp(ContextVk *contextVk, PrimaryCommandBuffer *primary)
1219 {
1220     const QueryPool &queryPool = getQueryPool();
1221     primary->resetQueryPool(queryPool, mQuery, 1);
1222     primary->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, queryPool, mQuery);
1223     mMostRecentSerial = contextVk->getCurrentQueueSerial();
1224 }
1225 
hasPendingWork(ContextVk * contextVk)1226 bool QueryHelper::hasPendingWork(ContextVk *contextVk)
1227 {
1228     // If the renderer has a queue serial higher than the stored one, the command buffers that
1229     // recorded this query have already been submitted, so there is no pending work.
1230     return mMostRecentSerial.valid() && (mMostRecentSerial == contextVk->getCurrentQueueSerial());
1231 }
1232 
getUint64ResultNonBlocking(ContextVk * contextVk,uint64_t * resultOut,bool * availableOut)1233 angle::Result QueryHelper::getUint64ResultNonBlocking(ContextVk *contextVk,
1234                                                       uint64_t *resultOut,
1235                                                       bool *availableOut)
1236 {
1237     ASSERT(valid());
1238     VkResult result;
1239 
1240     // Ensure that we only wait if we have inserted a query in command buffer. Otherwise you will
1241     // wait forever and trigger GPU timeout.
1242     if (mMostRecentSerial.valid())
1243     {
1244         VkDevice device                     = contextVk->getDevice();
1245         constexpr VkQueryResultFlags kFlags = VK_QUERY_RESULT_64_BIT;
1246         result = getQueryPool().getResults(device, mQuery, 1, sizeof(uint64_t), resultOut,
1247                                            sizeof(uint64_t), kFlags);
1248     }
1249     else
1250     {
1251         result     = VK_SUCCESS;
1252         *resultOut = 0;
1253     }
1254 
1255     if (result == VK_NOT_READY)
1256     {
1257         *availableOut = false;
1258         return angle::Result::Continue;
1259     }
1260     else
1261     {
1262         ANGLE_VK_TRY(contextVk, result);
1263         *availableOut = true;
1264     }
1265     return angle::Result::Continue;
1266 }
1267 
getUint64Result(ContextVk * contextVk,uint64_t * resultOut)1268 angle::Result QueryHelper::getUint64Result(ContextVk *contextVk, uint64_t *resultOut)
1269 {
1270     ASSERT(valid());
1271     if (mMostRecentSerial.valid())
1272     {
1273         VkDevice device                     = contextVk->getDevice();
1274         constexpr VkQueryResultFlags kFlags = VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT;
1275         ANGLE_VK_TRY(contextVk, getQueryPool().getResults(device, mQuery, 1, sizeof(uint64_t),
1276                                                           resultOut, sizeof(uint64_t), kFlags));
1277     }
1278     else
1279     {
1280         *resultOut = 0;
1281     }
1282     return angle::Result::Continue;
1283 }
1284 
1285 // DynamicSemaphorePool implementation
1286 DynamicSemaphorePool::DynamicSemaphorePool() = default;
1287 
1288 DynamicSemaphorePool::~DynamicSemaphorePool() = default;
1289 
init(ContextVk * contextVk,uint32_t poolSize)1290 angle::Result DynamicSemaphorePool::init(ContextVk *contextVk, uint32_t poolSize)
1291 {
1292     ANGLE_TRY(initEntryPool(contextVk, poolSize));
1293     ANGLE_TRY(allocateNewPool(contextVk));
1294     return angle::Result::Continue;
1295 }
1296 
destroy(VkDevice device)1297 void DynamicSemaphorePool::destroy(VkDevice device)
1298 {
1299     for (auto &semaphorePool : mPools)
1300     {
1301         for (Semaphore &semaphore : semaphorePool)
1302         {
1303             semaphore.destroy(device);
1304         }
1305     }
1306 
1307     destroyEntryPool();
1308 }
1309 
allocateSemaphore(ContextVk * contextVk,SemaphoreHelper * semaphoreOut)1310 angle::Result DynamicSemaphorePool::allocateSemaphore(ContextVk *contextVk,
1311                                                       SemaphoreHelper *semaphoreOut)
1312 {
1313     ASSERT(!semaphoreOut->getSemaphore());
1314 
1315     if (mCurrentFreeEntry >= mPoolSize)
1316     {
1317         // No more queries left in this pool, create another one.
1318         ANGLE_TRY(allocateNewPool(contextVk));
1319     }
1320 
1321     semaphoreOut->init(mCurrentPool, &mPools[mCurrentPool][mCurrentFreeEntry++]);
1322 
1323     return angle::Result::Continue;
1324 }
1325 
freeSemaphore(ContextVk * contextVk,SemaphoreHelper * semaphore)1326 void DynamicSemaphorePool::freeSemaphore(ContextVk *contextVk, SemaphoreHelper *semaphore)
1327 {
1328     if (semaphore->getSemaphore())
1329     {
1330         onEntryFreed(contextVk, semaphore->getSemaphorePoolIndex());
1331         semaphore->deinit();
1332     }
1333 }
1334 
allocateNewPool(ContextVk * contextVk)1335 angle::Result DynamicSemaphorePool::allocateNewPool(ContextVk *contextVk)
1336 {
1337     if (findFreeEntryPool(contextVk))
1338     {
1339         return angle::Result::Continue;
1340     }
1341 
1342     std::vector<Semaphore> newPool(mPoolSize);
1343 
1344     for (Semaphore &semaphore : newPool)
1345     {
1346         ANGLE_VK_TRY(contextVk, semaphore.init(contextVk->getDevice()));
1347     }
1348 
1349     // This code is safe as long as the growth of the outer vector in vector<vector<T>> is done by
1350     // moving the inner vectors, making sure references to the inner vector remain intact.
1351     Semaphore *assertMove = mPools.size() > 0 ? mPools[0].data() : nullptr;
1352 
1353     ANGLE_TRY(allocateNewEntryPool(contextVk, std::move(newPool)));
1354 
1355     ASSERT(assertMove == nullptr || assertMove == mPools[0].data());
1356 
1357     return angle::Result::Continue;
1358 }
1359 
1360 // SemaphoreHelper implementation
SemaphoreHelper()1361 SemaphoreHelper::SemaphoreHelper() : mSemaphorePoolIndex(0), mSemaphore(0) {}
1362 
~SemaphoreHelper()1363 SemaphoreHelper::~SemaphoreHelper() {}
1364 
SemaphoreHelper(SemaphoreHelper && other)1365 SemaphoreHelper::SemaphoreHelper(SemaphoreHelper &&other)
1366     : mSemaphorePoolIndex(other.mSemaphorePoolIndex), mSemaphore(other.mSemaphore)
1367 {
1368     other.mSemaphore = nullptr;
1369 }
1370 
operator =(SemaphoreHelper && other)1371 SemaphoreHelper &SemaphoreHelper::operator=(SemaphoreHelper &&other)
1372 {
1373     std::swap(mSemaphorePoolIndex, other.mSemaphorePoolIndex);
1374     std::swap(mSemaphore, other.mSemaphore);
1375     return *this;
1376 }
1377 
init(const size_t semaphorePoolIndex,const Semaphore * semaphore)1378 void SemaphoreHelper::init(const size_t semaphorePoolIndex, const Semaphore *semaphore)
1379 {
1380     mSemaphorePoolIndex = semaphorePoolIndex;
1381     mSemaphore          = semaphore;
1382 }
1383 
deinit()1384 void SemaphoreHelper::deinit()
1385 {
1386     mSemaphorePoolIndex = 0;
1387     mSemaphore          = nullptr;
1388 }
1389 
1390 // LineLoopHelper implementation.
LineLoopHelper(RendererVk * renderer)1391 LineLoopHelper::LineLoopHelper(RendererVk *renderer)
1392 {
1393     // We need to use an alignment of the maximum size we're going to allocate, which is
1394     // VK_INDEX_TYPE_UINT32. When we switch from a drawElement to a drawArray call, the allocations
1395     // can vary in size. According to the Vulkan spec, when calling vkCmdBindIndexBuffer: 'The
1396     // sum of offset and the address of the range of VkDeviceMemory object that is backing buffer,
1397     // must be a multiple of the type indicated by indexType'.
1398     mDynamicIndexBuffer.init(renderer, kLineLoopDynamicBufferUsage, sizeof(uint32_t),
1399                              kLineLoopDynamicBufferInitialSize, true);
1400     mDynamicIndirectBuffer.init(renderer, kLineLoopDynamicIndirectBufferUsage, sizeof(uint32_t),
1401                                 kLineLoopDynamicIndirectBufferInitialSize, true);
1402 }
1403 
1404 LineLoopHelper::~LineLoopHelper() = default;
1405 
getIndexBufferForDrawArrays(ContextVk * contextVk,uint32_t clampedVertexCount,GLint firstVertex,BufferHelper ** bufferOut,VkDeviceSize * offsetOut)1406 angle::Result LineLoopHelper::getIndexBufferForDrawArrays(ContextVk *contextVk,
1407                                                           uint32_t clampedVertexCount,
1408                                                           GLint firstVertex,
1409                                                           BufferHelper **bufferOut,
1410                                                           VkDeviceSize *offsetOut)
1411 {
1412     uint32_t *indices    = nullptr;
1413     size_t allocateBytes = sizeof(uint32_t) * (static_cast<size_t>(clampedVertexCount) + 1);
1414 
1415     mDynamicIndexBuffer.releaseInFlightBuffers(contextVk);
1416     ANGLE_TRY(mDynamicIndexBuffer.allocate(contextVk, allocateBytes,
1417                                            reinterpret_cast<uint8_t **>(&indices), nullptr,
1418                                            offsetOut, nullptr));
1419     *bufferOut = mDynamicIndexBuffer.getCurrentBuffer();
1420 
1421     // Note: there could be an overflow in this addition.
1422     uint32_t unsignedFirstVertex = static_cast<uint32_t>(firstVertex);
1423     uint32_t vertexCount         = (clampedVertexCount + unsignedFirstVertex);
1424     for (uint32_t vertexIndex = unsignedFirstVertex; vertexIndex < vertexCount; vertexIndex++)
1425     {
1426         *indices++ = vertexIndex;
1427     }
1428     *indices = unsignedFirstVertex;
1429 
1430     // Since we are not using the VK_MEMORY_PROPERTY_HOST_COHERENT_BIT flag when creating the
1431     // device memory in the StreamingBuffer, we always need to make sure we flush it after
1432     // writing.
1433     ANGLE_TRY(mDynamicIndexBuffer.flush(contextVk));
1434 
1435     return angle::Result::Continue;
1436 }
1437 
getIndexBufferForElementArrayBuffer(ContextVk * contextVk,BufferVk * elementArrayBufferVk,gl::DrawElementsType glIndexType,int indexCount,intptr_t elementArrayOffset,BufferHelper ** bufferOut,VkDeviceSize * bufferOffsetOut,uint32_t * indexCountOut)1438 angle::Result LineLoopHelper::getIndexBufferForElementArrayBuffer(ContextVk *contextVk,
1439                                                                   BufferVk *elementArrayBufferVk,
1440                                                                   gl::DrawElementsType glIndexType,
1441                                                                   int indexCount,
1442                                                                   intptr_t elementArrayOffset,
1443                                                                   BufferHelper **bufferOut,
1444                                                                   VkDeviceSize *bufferOffsetOut,
1445                                                                   uint32_t *indexCountOut)
1446 {
1447     if (glIndexType == gl::DrawElementsType::UnsignedByte ||
1448         contextVk->getState().isPrimitiveRestartEnabled())
1449     {
1450         ANGLE_TRACE_EVENT0("gpu.angle", "LineLoopHelper::getIndexBufferForElementArrayBuffer");
1451 
1452         void *srcDataMapping = nullptr;
1453         ANGLE_TRY(elementArrayBufferVk->mapImpl(contextVk, &srcDataMapping));
1454         ANGLE_TRY(streamIndices(contextVk, glIndexType, indexCount,
1455                                 static_cast<const uint8_t *>(srcDataMapping) + elementArrayOffset,
1456                                 bufferOut, bufferOffsetOut, indexCountOut));
1457         ANGLE_TRY(elementArrayBufferVk->unmapImpl(contextVk));
1458         return angle::Result::Continue;
1459     }
1460 
1461     *indexCountOut = indexCount + 1;
1462 
1463     uint32_t *indices    = nullptr;
1464     size_t unitSize      = contextVk->getVkIndexTypeSize(glIndexType);
1465     size_t allocateBytes = unitSize * (indexCount + 1) + 1;
1466 
1467     mDynamicIndexBuffer.releaseInFlightBuffers(contextVk);
1468     ANGLE_TRY(mDynamicIndexBuffer.allocate(contextVk, allocateBytes,
1469                                            reinterpret_cast<uint8_t **>(&indices), nullptr,
1470                                            bufferOffsetOut, nullptr));
1471     *bufferOut = mDynamicIndexBuffer.getCurrentBuffer();
1472 
1473     VkDeviceSize sourceOffset                  = static_cast<VkDeviceSize>(elementArrayOffset);
1474     uint64_t unitCount                         = static_cast<VkDeviceSize>(indexCount);
1475     angle::FixedVector<VkBufferCopy, 3> copies = {
1476         {sourceOffset, *bufferOffsetOut, unitCount * unitSize},
1477         {sourceOffset, *bufferOffsetOut + unitCount * unitSize, unitSize},
1478     };
1479     if (contextVk->getRenderer()->getFeatures().extraCopyBufferRegion.enabled)
1480         copies.push_back({sourceOffset, *bufferOffsetOut + (unitCount + 1) * unitSize, 1});
1481 
1482     ANGLE_TRY(elementArrayBufferVk->copyToBufferImpl(
1483         contextVk, *bufferOut, static_cast<uint32_t>(copies.size()), copies.data()));
1484     ANGLE_TRY(mDynamicIndexBuffer.flush(contextVk));
1485     return angle::Result::Continue;
1486 }
1487 
streamIndices(ContextVk * contextVk,gl::DrawElementsType glIndexType,GLsizei indexCount,const uint8_t * srcPtr,BufferHelper ** bufferOut,VkDeviceSize * bufferOffsetOut,uint32_t * indexCountOut)1488 angle::Result LineLoopHelper::streamIndices(ContextVk *contextVk,
1489                                             gl::DrawElementsType glIndexType,
1490                                             GLsizei indexCount,
1491                                             const uint8_t *srcPtr,
1492                                             BufferHelper **bufferOut,
1493                                             VkDeviceSize *bufferOffsetOut,
1494                                             uint32_t *indexCountOut)
1495 {
1496     size_t unitSize = contextVk->getVkIndexTypeSize(glIndexType);
1497 
1498     uint8_t *indices = nullptr;
1499 
1500     uint32_t numOutIndices = indexCount + 1;
1501     if (contextVk->getState().isPrimitiveRestartEnabled())
1502     {
1503         numOutIndices = GetLineLoopWithRestartIndexCount(glIndexType, indexCount, srcPtr);
1504     }
1505     *indexCountOut       = numOutIndices;
1506     size_t allocateBytes = unitSize * numOutIndices;
1507     ANGLE_TRY(mDynamicIndexBuffer.allocate(contextVk, allocateBytes,
1508                                            reinterpret_cast<uint8_t **>(&indices), nullptr,
1509                                            bufferOffsetOut, nullptr));
1510     *bufferOut = mDynamicIndexBuffer.getCurrentBuffer();
1511 
1512     if (contextVk->getState().isPrimitiveRestartEnabled())
1513     {
1514         HandlePrimitiveRestart(contextVk, glIndexType, indexCount, srcPtr, indices);
1515     }
1516     else
1517     {
1518         if (contextVk->shouldConvertUint8VkIndexType(glIndexType))
1519         {
1520             // If vulkan doesn't support uint8 index types, we need to emulate it.
1521             VkIndexType indexType = contextVk->getVkIndexType(glIndexType);
1522             ASSERT(indexType == VK_INDEX_TYPE_UINT16);
1523             uint16_t *indicesDst = reinterpret_cast<uint16_t *>(indices);
1524             for (int i = 0; i < indexCount; i++)
1525             {
1526                 indicesDst[i] = srcPtr[i];
1527             }
1528 
1529             indicesDst[indexCount] = srcPtr[0];
1530         }
1531         else
1532         {
1533             memcpy(indices, srcPtr, unitSize * indexCount);
1534             memcpy(indices + unitSize * indexCount, srcPtr, unitSize);
1535         }
1536     }
1537 
1538     ANGLE_TRY(mDynamicIndexBuffer.flush(contextVk));
1539     return angle::Result::Continue;
1540 }
1541 
streamIndicesIndirect(ContextVk * contextVk,gl::DrawElementsType glIndexType,BufferHelper * indexBuffer,BufferHelper * indirectBuffer,VkDeviceSize indirectBufferOffset,BufferHelper ** indexBufferOut,VkDeviceSize * indexBufferOffsetOut,BufferHelper ** indirectBufferOut,VkDeviceSize * indirectBufferOffsetOut)1542 angle::Result LineLoopHelper::streamIndicesIndirect(ContextVk *contextVk,
1543                                                     gl::DrawElementsType glIndexType,
1544                                                     BufferHelper *indexBuffer,
1545                                                     BufferHelper *indirectBuffer,
1546                                                     VkDeviceSize indirectBufferOffset,
1547                                                     BufferHelper **indexBufferOut,
1548                                                     VkDeviceSize *indexBufferOffsetOut,
1549                                                     BufferHelper **indirectBufferOut,
1550                                                     VkDeviceSize *indirectBufferOffsetOut)
1551 {
1552     size_t unitSize      = contextVk->getVkIndexTypeSize(glIndexType);
1553     size_t allocateBytes = static_cast<size_t>(indexBuffer->getSize() + unitSize);
1554 
1555     if (contextVk->getState().isPrimitiveRestartEnabled())
1556     {
1557         // If primitive restart, new index buffer is 135% the size of the original index buffer. The
1558         // smallest lineloop with primitive restart is 3 indices (point 1, point 2 and restart
1559         // value) when converted to linelist becomes 4 vertices. Expansion of 4/3. Any larger
1560         // lineloops would have less overhead and require less extra space. Any incomplete
1561         // primitives can be dropped or left incomplete and thus not increase the size of the
1562         // destination index buffer. Since we don't know the number of indices being used we'll use
1563         // the size of the index buffer as allocated as the index count.
1564         size_t numInputIndices    = static_cast<size_t>(indexBuffer->getSize() / unitSize);
1565         size_t numNewInputIndices = ((numInputIndices * 4) / 3) + 1;
1566         allocateBytes             = static_cast<size_t>(numNewInputIndices * unitSize);
1567     }
1568 
1569     mDynamicIndexBuffer.releaseInFlightBuffers(contextVk);
1570     mDynamicIndirectBuffer.releaseInFlightBuffers(contextVk);
1571 
1572     ANGLE_TRY(mDynamicIndexBuffer.allocate(contextVk, allocateBytes, nullptr, nullptr,
1573                                            indexBufferOffsetOut, nullptr));
1574     *indexBufferOut = mDynamicIndexBuffer.getCurrentBuffer();
1575 
1576     ANGLE_TRY(mDynamicIndirectBuffer.allocate(contextVk, sizeof(VkDrawIndexedIndirectCommand),
1577                                               nullptr, nullptr, indirectBufferOffsetOut, nullptr));
1578     *indirectBufferOut = mDynamicIndirectBuffer.getCurrentBuffer();
1579 
1580     BufferHelper *destIndexBuffer    = mDynamicIndexBuffer.getCurrentBuffer();
1581     BufferHelper *destIndirectBuffer = mDynamicIndirectBuffer.getCurrentBuffer();
1582 
1583     // Copy relevant section of the source into destination at allocated offset.  Note that the
1584     // offset returned by allocate() above is in bytes. As is the indices offset pointer.
1585     UtilsVk::ConvertLineLoopIndexIndirectParameters params = {};
1586     params.indirectBufferOffset    = static_cast<uint32_t>(indirectBufferOffset);
1587     params.dstIndirectBufferOffset = static_cast<uint32_t>(*indirectBufferOffsetOut);
1588     params.dstIndexBufferOffset    = static_cast<uint32_t>(*indexBufferOffsetOut);
1589     params.indicesBitsWidth        = static_cast<uint32_t>(unitSize * 8);
1590 
1591     ANGLE_TRY(contextVk->getUtils().convertLineLoopIndexIndirectBuffer(
1592         contextVk, indirectBuffer, destIndirectBuffer, destIndexBuffer, indexBuffer, params));
1593 
1594     return angle::Result::Continue;
1595 }
1596 
streamArrayIndirect(ContextVk * contextVk,size_t vertexCount,BufferHelper * arrayIndirectBuffer,VkDeviceSize arrayIndirectBufferOffset,BufferHelper ** indexBufferOut,VkDeviceSize * indexBufferOffsetOut,BufferHelper ** indexIndirectBufferOut,VkDeviceSize * indexIndirectBufferOffsetOut)1597 angle::Result LineLoopHelper::streamArrayIndirect(ContextVk *contextVk,
1598                                                   size_t vertexCount,
1599                                                   BufferHelper *arrayIndirectBuffer,
1600                                                   VkDeviceSize arrayIndirectBufferOffset,
1601                                                   BufferHelper **indexBufferOut,
1602                                                   VkDeviceSize *indexBufferOffsetOut,
1603                                                   BufferHelper **indexIndirectBufferOut,
1604                                                   VkDeviceSize *indexIndirectBufferOffsetOut)
1605 {
1606     auto unitSize        = sizeof(uint32_t);
1607     size_t allocateBytes = static_cast<size_t>((vertexCount + 1) * unitSize);
1608 
1609     mDynamicIndexBuffer.releaseInFlightBuffers(contextVk);
1610     mDynamicIndirectBuffer.releaseInFlightBuffers(contextVk);
1611 
1612     ANGLE_TRY(mDynamicIndexBuffer.allocate(contextVk, allocateBytes, nullptr, nullptr,
1613                                            indexBufferOffsetOut, nullptr));
1614     *indexBufferOut = mDynamicIndexBuffer.getCurrentBuffer();
1615 
1616     ANGLE_TRY(mDynamicIndirectBuffer.allocate(contextVk, sizeof(VkDrawIndexedIndirectCommand),
1617                                               nullptr, nullptr, indexIndirectBufferOffsetOut,
1618                                               nullptr));
1619     *indexIndirectBufferOut = mDynamicIndirectBuffer.getCurrentBuffer();
1620 
1621     BufferHelper *destIndexBuffer    = mDynamicIndexBuffer.getCurrentBuffer();
1622     BufferHelper *destIndirectBuffer = mDynamicIndirectBuffer.getCurrentBuffer();
1623 
1624     // Copy relevant section of the source into destination at allocated offset.  Note that the
1625     // offset returned by allocate() above is in bytes. As is the indices offset pointer.
1626     UtilsVk::ConvertLineLoopArrayIndirectParameters params = {};
1627     params.indirectBufferOffset    = static_cast<uint32_t>(arrayIndirectBufferOffset);
1628     params.dstIndirectBufferOffset = static_cast<uint32_t>(*indexIndirectBufferOffsetOut);
1629     params.dstIndexBufferOffset    = static_cast<uint32_t>(*indexBufferOffsetOut);
1630 
1631     ANGLE_TRY(contextVk->getUtils().convertLineLoopArrayIndirectBuffer(
1632         contextVk, arrayIndirectBuffer, destIndirectBuffer, destIndexBuffer, params));
1633 
1634     return angle::Result::Continue;
1635 }
1636 
release(ContextVk * contextVk)1637 void LineLoopHelper::release(ContextVk *contextVk)
1638 {
1639     mDynamicIndexBuffer.release(contextVk->getRenderer());
1640     mDynamicIndirectBuffer.release(contextVk->getRenderer());
1641 }
1642 
destroy(RendererVk * renderer)1643 void LineLoopHelper::destroy(RendererVk *renderer)
1644 {
1645     mDynamicIndexBuffer.destroy(renderer);
1646     mDynamicIndirectBuffer.destroy(renderer);
1647 }
1648 
1649 // static
Draw(uint32_t count,uint32_t baseVertex,CommandBuffer * commandBuffer)1650 void LineLoopHelper::Draw(uint32_t count, uint32_t baseVertex, CommandBuffer *commandBuffer)
1651 {
1652     // Our first index is always 0 because that's how we set it up in createIndexBuffer*.
1653     commandBuffer->drawIndexedBaseVertex(count, baseVertex);
1654 }
1655 
1656 // BufferHelper implementation.
BufferHelper()1657 BufferHelper::BufferHelper()
1658     : mMemoryPropertyFlags{},
1659       mSize(0),
1660       mMappedMemory(nullptr),
1661       mViewFormat(nullptr),
1662       mCurrentQueueFamilyIndex(std::numeric_limits<uint32_t>::max()),
1663       mCurrentWriteAccess(0),
1664       mCurrentReadAccess(0)
1665 {}
1666 
1667 BufferHelper::~BufferHelper() = default;
1668 
init(ContextVk * contextVk,const VkBufferCreateInfo & requestedCreateInfo,VkMemoryPropertyFlags memoryPropertyFlags)1669 angle::Result BufferHelper::init(ContextVk *contextVk,
1670                                  const VkBufferCreateInfo &requestedCreateInfo,
1671                                  VkMemoryPropertyFlags memoryPropertyFlags)
1672 {
1673     RendererVk *renderer = contextVk->getRenderer();
1674 
1675     // TODO: Remove with anglebug.com/2162: Vulkan: Implement device memory sub-allocation
1676     // Check if we have too many resources allocated already and need to free some before allocating
1677     // more and (possibly) exceeding the device's limits.
1678     if (contextVk->shouldFlush())
1679     {
1680         ANGLE_TRY(contextVk->flushImpl(nullptr));
1681     }
1682 
1683     mSize = requestedCreateInfo.size;
1684 
1685     VkBufferCreateInfo modifiedCreateInfo;
1686     const VkBufferCreateInfo *createInfo = &requestedCreateInfo;
1687 
1688     if (renderer->getFeatures().padBuffersToMaxVertexAttribStride.enabled)
1689     {
1690         const VkDeviceSize maxVertexAttribStride = renderer->getMaxVertexAttribStride();
1691         ASSERT(maxVertexAttribStride);
1692         modifiedCreateInfo = requestedCreateInfo;
1693         modifiedCreateInfo.size += maxVertexAttribStride;
1694         createInfo = &modifiedCreateInfo;
1695     }
1696 
1697     VkMemoryPropertyFlags requiredFlags =
1698         (memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
1699     VkMemoryPropertyFlags preferredFlags =
1700         (memoryPropertyFlags & (~VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
1701 
1702     mAllocation.createBufferAndMemory(
1703         renderer->getAllocator(), createInfo, requiredFlags, preferredFlags,
1704         renderer->getFeatures().persistentlyMappedBuffers.enabled, &mBuffer, &mMemoryPropertyFlags);
1705 
1706     mCurrentQueueFamilyIndex = contextVk->getRenderer()->getQueueFamilyIndex();
1707 
1708     if (renderer->getFeatures().allocateNonZeroMemory.enabled)
1709     {
1710         // This memory can't be mapped, so the buffer must be marked as a transfer destination so we
1711         // can use a staging resource to initialize it to a non-zero value. If the memory is
1712         // mappable we do the initialization in AllocateBufferMemory.
1713         if ((mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0 &&
1714             (requestedCreateInfo.usage & VK_BUFFER_USAGE_TRANSFER_DST_BIT) != 0)
1715         {
1716             ANGLE_TRY(initializeNonZeroMemory(contextVk, createInfo->size));
1717         }
1718         else if ((mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
1719         {
1720             // Can map the memory.
1721             // Pick an arbitrary value to initialize non-zero memory for sanitization.
1722             constexpr int kNonZeroInitValue = 55;
1723             ANGLE_TRY(InitMappableAllocation(renderer->getAllocator(), &mAllocation, mSize,
1724                                              kNonZeroInitValue, mMemoryPropertyFlags));
1725         }
1726     }
1727 
1728     return angle::Result::Continue;
1729 }
1730 
initializeNonZeroMemory(Context * context,VkDeviceSize size)1731 angle::Result BufferHelper::initializeNonZeroMemory(Context *context, VkDeviceSize size)
1732 {
1733     // Staging buffer memory is non-zero-initialized in 'init'.
1734     StagingBuffer stagingBuffer;
1735     ANGLE_TRY(stagingBuffer.init(context, size, StagingUsage::Both));
1736 
1737     RendererVk *renderer = context->getRenderer();
1738 
1739     vk::PrimaryCommandBuffer commandBuffer;
1740     ANGLE_TRY(renderer->getCommandBufferOneOff(context, &commandBuffer));
1741 
1742     // Queue a DMA copy.
1743     VkBufferCopy copyRegion = {};
1744     copyRegion.srcOffset    = 0;
1745     copyRegion.dstOffset    = 0;
1746     copyRegion.size         = size;
1747 
1748     commandBuffer.copyBuffer(stagingBuffer.getBuffer(), mBuffer, 1, &copyRegion);
1749 
1750     ANGLE_VK_TRY(context, commandBuffer.end());
1751 
1752     Serial serial;
1753     ANGLE_TRY(renderer->queueSubmitOneOff(context, std::move(commandBuffer),
1754                                           egl::ContextPriority::Medium, &serial));
1755 
1756     stagingBuffer.collectGarbage(renderer, serial);
1757     mUse.updateSerialOneOff(serial);
1758 
1759     return angle::Result::Continue;
1760 }
1761 
destroy(RendererVk * renderer)1762 void BufferHelper::destroy(RendererVk *renderer)
1763 {
1764     VkDevice device = renderer->getDevice();
1765     unmap(renderer);
1766     mSize       = 0;
1767     mViewFormat = nullptr;
1768 
1769     mBuffer.destroy(device);
1770     mBufferView.destroy(device);
1771     mAllocation.destroy(renderer->getAllocator());
1772 }
1773 
release(RendererVk * renderer)1774 void BufferHelper::release(RendererVk *renderer)
1775 {
1776     unmap(renderer);
1777     mSize       = 0;
1778     mViewFormat = nullptr;
1779 
1780     renderer->collectGarbageAndReinit(&mUse, &mBuffer, &mBufferView, &mAllocation);
1781 }
1782 
needsOnWriteBarrier(VkAccessFlags writeAccessType,VkAccessFlags * barrierSrcOut,VkAccessFlags * barrierDstOut)1783 bool BufferHelper::needsOnWriteBarrier(VkAccessFlags writeAccessType,
1784                                        VkAccessFlags *barrierSrcOut,
1785                                        VkAccessFlags *barrierDstOut)
1786 {
1787     bool needsBarrier = mCurrentReadAccess != 0 || mCurrentWriteAccess != 0;
1788 
1789     // Note: mCurrentReadAccess is not part of barrier src flags as "anything-after-read" is
1790     // satisified by execution barriers alone.
1791     *barrierSrcOut = mCurrentWriteAccess;
1792     *barrierDstOut = writeAccessType;
1793 
1794     mCurrentWriteAccess = writeAccessType;
1795     mCurrentReadAccess  = 0;
1796 
1797     return needsBarrier;
1798 }
1799 
copyFromBuffer(ContextVk * contextVk,BufferHelper * srcBuffer,VkAccessFlags bufferAccessType,const VkBufferCopy & copyRegion)1800 angle::Result BufferHelper::copyFromBuffer(ContextVk *contextVk,
1801                                            BufferHelper *srcBuffer,
1802                                            VkAccessFlags bufferAccessType,
1803                                            const VkBufferCopy &copyRegion)
1804 {
1805     CommandBuffer *commandBuffer = nullptr;
1806     ANGLE_TRY(contextVk->onBufferWrite(bufferAccessType, this));
1807     ANGLE_TRY(contextVk->onBufferRead(VK_ACCESS_TRANSFER_READ_BIT, srcBuffer));
1808     ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
1809 
1810     commandBuffer->copyBuffer(srcBuffer->getBuffer(), mBuffer, 1, &copyRegion);
1811 
1812     return angle::Result::Continue;
1813 }
1814 
initBufferView(ContextVk * contextVk,const Format & format)1815 angle::Result BufferHelper::initBufferView(ContextVk *contextVk, const Format &format)
1816 {
1817     ASSERT(format.valid());
1818 
1819     if (mBufferView.valid())
1820     {
1821         ASSERT(mViewFormat->vkBufferFormat == format.vkBufferFormat);
1822         return angle::Result::Continue;
1823     }
1824 
1825     VkBufferViewCreateInfo viewCreateInfo = {};
1826     viewCreateInfo.sType                  = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
1827     viewCreateInfo.buffer                 = mBuffer.getHandle();
1828     viewCreateInfo.format                 = format.vkBufferFormat;
1829     viewCreateInfo.offset                 = 0;
1830     viewCreateInfo.range                  = mSize;
1831 
1832     ANGLE_VK_TRY(contextVk, mBufferView.init(contextVk->getDevice(), viewCreateInfo));
1833     mViewFormat = &format;
1834 
1835     return angle::Result::Continue;
1836 }
1837 
mapImpl(ContextVk * contextVk)1838 angle::Result BufferHelper::mapImpl(ContextVk *contextVk)
1839 {
1840     ANGLE_VK_TRY(contextVk,
1841                  mAllocation.map(contextVk->getRenderer()->getAllocator(), &mMappedMemory));
1842 
1843     return angle::Result::Continue;
1844 }
1845 
unmap(RendererVk * renderer)1846 void BufferHelper::unmap(RendererVk *renderer)
1847 {
1848     if (mMappedMemory)
1849     {
1850         mAllocation.unmap(renderer->getAllocator());
1851         mMappedMemory = nullptr;
1852     }
1853 }
1854 
flush(RendererVk * renderer,VkDeviceSize offset,VkDeviceSize size)1855 angle::Result BufferHelper::flush(RendererVk *renderer, VkDeviceSize offset, VkDeviceSize size)
1856 {
1857     bool hostVisible  = mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
1858     bool hostCoherent = mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
1859     if (hostVisible && !hostCoherent)
1860     {
1861         mAllocation.flush(renderer->getAllocator(), offset, size);
1862     }
1863     return angle::Result::Continue;
1864 }
1865 
invalidate(RendererVk * renderer,VkDeviceSize offset,VkDeviceSize size)1866 angle::Result BufferHelper::invalidate(RendererVk *renderer, VkDeviceSize offset, VkDeviceSize size)
1867 {
1868     bool hostVisible  = mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
1869     bool hostCoherent = mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
1870     if (hostVisible && !hostCoherent)
1871     {
1872         mAllocation.invalidate(renderer->getAllocator(), offset, size);
1873     }
1874     return angle::Result::Continue;
1875 }
1876 
changeQueue(uint32_t newQueueFamilyIndex,CommandBuffer * commandBuffer)1877 void BufferHelper::changeQueue(uint32_t newQueueFamilyIndex, CommandBuffer *commandBuffer)
1878 {
1879     VkBufferMemoryBarrier bufferMemoryBarrier = {};
1880     bufferMemoryBarrier.sType                 = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
1881     bufferMemoryBarrier.srcAccessMask         = 0;
1882     bufferMemoryBarrier.dstAccessMask         = 0;
1883     bufferMemoryBarrier.srcQueueFamilyIndex   = mCurrentQueueFamilyIndex;
1884     bufferMemoryBarrier.dstQueueFamilyIndex   = newQueueFamilyIndex;
1885     bufferMemoryBarrier.buffer                = mBuffer.getHandle();
1886     bufferMemoryBarrier.offset                = 0;
1887     bufferMemoryBarrier.size                  = VK_WHOLE_SIZE;
1888 
1889     commandBuffer->bufferBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
1890                                  VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, &bufferMemoryBarrier);
1891 
1892     mCurrentQueueFamilyIndex = newQueueFamilyIndex;
1893 }
1894 
canAccumulateRead(ContextVk * contextVk,VkAccessFlags readAccessType)1895 bool BufferHelper::canAccumulateRead(ContextVk *contextVk, VkAccessFlags readAccessType)
1896 {
1897     // We only need to start a new command buffer when we need a new barrier.
1898     // For simplicity's sake for now we always start a new command buffer.
1899     // TODO(jmadill): Re-use the command buffer. http://anglebug.com/4429
1900     return false;
1901 }
1902 
canAccumulateWrite(ContextVk * contextVk,VkAccessFlags writeAccessType)1903 bool BufferHelper::canAccumulateWrite(ContextVk *contextVk, VkAccessFlags writeAccessType)
1904 {
1905     // We only need to start a new command buffer when we need a new barrier.
1906     // For simplicity's sake for now we always start a new command buffer.
1907     // TODO(jmadill): Re-use the command buffer. http://anglebug.com/4429
1908     return false;
1909 }
1910 
updateReadBarrier(VkAccessFlags readAccessType,VkAccessFlags * barrierSrcOut,VkAccessFlags * barrierDstOut)1911 void BufferHelper::updateReadBarrier(VkAccessFlags readAccessType,
1912                                      VkAccessFlags *barrierSrcOut,
1913                                      VkAccessFlags *barrierDstOut)
1914 {
1915     if (mCurrentWriteAccess != 0 && (mCurrentReadAccess & readAccessType) != readAccessType)
1916     {
1917         *barrierSrcOut |= mCurrentWriteAccess;
1918         *barrierDstOut |= readAccessType;
1919     }
1920 
1921     // Accumulate new read usage.
1922     mCurrentReadAccess |= readAccessType;
1923 }
1924 
updateWriteBarrier(VkAccessFlags writeAccessType,VkAccessFlags * barrierSrcOut,VkAccessFlags * barrierDstOut)1925 void BufferHelper::updateWriteBarrier(VkAccessFlags writeAccessType,
1926                                       VkAccessFlags *barrierSrcOut,
1927                                       VkAccessFlags *barrierDstOut)
1928 {
1929     if (mCurrentReadAccess != 0 || mCurrentWriteAccess != 0)
1930     {
1931         *barrierSrcOut |= mCurrentWriteAccess;
1932         *barrierDstOut |= writeAccessType;
1933     }
1934 
1935     // Reset usages on the new write.
1936     mCurrentWriteAccess = writeAccessType;
1937     mCurrentReadAccess  = 0;
1938 }
1939 
1940 // ImageHelper implementation.
ImageHelper()1941 ImageHelper::ImageHelper()
1942 {
1943     resetCachedProperties();
1944 }
1945 
ImageHelper(ImageHelper && other)1946 ImageHelper::ImageHelper(ImageHelper &&other)
1947     : mImage(std::move(other.mImage)),
1948       mDeviceMemory(std::move(other.mDeviceMemory)),
1949       mImageType(other.mImageType),
1950       mExtents(other.mExtents),
1951       mFormat(other.mFormat),
1952       mSamples(other.mSamples),
1953       mSerial(other.mSerial),
1954       mCurrentLayout(other.mCurrentLayout),
1955       mCurrentQueueFamilyIndex(other.mCurrentQueueFamilyIndex),
1956       mBaseLevel(other.mBaseLevel),
1957       mMaxLevel(other.mMaxLevel),
1958       mLayerCount(other.mLayerCount),
1959       mLevelCount(other.mLevelCount),
1960       mStagingBuffer(std::move(other.mStagingBuffer)),
1961       mSubresourceUpdates(std::move(other.mSubresourceUpdates))
1962 {
1963     ASSERT(this != &other);
1964     other.resetCachedProperties();
1965 }
1966 
~ImageHelper()1967 ImageHelper::~ImageHelper()
1968 {
1969     ASSERT(!valid());
1970 }
1971 
resetCachedProperties()1972 void ImageHelper::resetCachedProperties()
1973 {
1974     mImageType               = VK_IMAGE_TYPE_2D;
1975     mExtents                 = {};
1976     mFormat                  = nullptr;
1977     mSamples                 = 1;
1978     mSerial                  = rx::kZeroSerial;
1979     mCurrentLayout           = ImageLayout::Undefined;
1980     mCurrentQueueFamilyIndex = std::numeric_limits<uint32_t>::max();
1981     mBaseLevel               = 0;
1982     mMaxLevel                = 0;
1983     mLayerCount              = 0;
1984     mLevelCount              = 0;
1985 }
1986 
initStagingBuffer(RendererVk * renderer,const Format & format,VkBufferUsageFlags usageFlags,size_t initialSize)1987 void ImageHelper::initStagingBuffer(RendererVk *renderer,
1988                                     const Format &format,
1989                                     VkBufferUsageFlags usageFlags,
1990                                     size_t initialSize)
1991 {
1992     mStagingBuffer.init(renderer, usageFlags, format.getImageCopyBufferAlignment(), initialSize,
1993                         true);
1994 }
1995 
init(Context * context,gl::TextureType textureType,const VkExtent3D & extents,const Format & format,GLint samples,VkImageUsageFlags usage,uint32_t baseLevel,uint32_t maxLevel,uint32_t mipLevels,uint32_t layerCount)1996 angle::Result ImageHelper::init(Context *context,
1997                                 gl::TextureType textureType,
1998                                 const VkExtent3D &extents,
1999                                 const Format &format,
2000                                 GLint samples,
2001                                 VkImageUsageFlags usage,
2002                                 uint32_t baseLevel,
2003                                 uint32_t maxLevel,
2004                                 uint32_t mipLevels,
2005                                 uint32_t layerCount)
2006 {
2007     mSerial = rx::kZeroSerial;
2008     return initExternal(context, textureType, extents, format, samples, usage,
2009                         ImageLayout::Undefined, nullptr, baseLevel, maxLevel, mipLevels,
2010                         layerCount);
2011 }
2012 
initExternal(Context * context,gl::TextureType textureType,const VkExtent3D & extents,const Format & format,GLint samples,VkImageUsageFlags usage,ImageLayout initialLayout,const void * externalImageCreateInfo,uint32_t baseLevel,uint32_t maxLevel,uint32_t mipLevels,uint32_t layerCount)2013 angle::Result ImageHelper::initExternal(Context *context,
2014                                         gl::TextureType textureType,
2015                                         const VkExtent3D &extents,
2016                                         const Format &format,
2017                                         GLint samples,
2018                                         VkImageUsageFlags usage,
2019                                         ImageLayout initialLayout,
2020                                         const void *externalImageCreateInfo,
2021                                         uint32_t baseLevel,
2022                                         uint32_t maxLevel,
2023                                         uint32_t mipLevels,
2024                                         uint32_t layerCount)
2025 {
2026     ASSERT(!valid());
2027 
2028     mImageType  = gl_vk::GetImageType(textureType);
2029     mExtents    = extents;
2030     mFormat     = &format;
2031     mSamples    = samples;
2032     mBaseLevel  = baseLevel;
2033     mMaxLevel   = maxLevel;
2034     mLevelCount = mipLevels;
2035     mLayerCount = layerCount;
2036 
2037     // Validate that mLayerCount is compatible with the texture type
2038     ASSERT(textureType != gl::TextureType::_3D || mLayerCount == 1);
2039     ASSERT(textureType != gl::TextureType::_2DArray || mExtents.depth == 1);
2040     ASSERT(textureType != gl::TextureType::External || mLayerCount == 1);
2041     ASSERT(textureType != gl::TextureType::Rectangle || mLayerCount == 1);
2042     ASSERT(textureType != gl::TextureType::CubeMap || mLayerCount == gl::kCubeFaceCount);
2043 
2044     VkImageCreateInfo imageInfo     = {};
2045     imageInfo.sType                 = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
2046     imageInfo.pNext                 = externalImageCreateInfo;
2047     imageInfo.flags                 = GetImageCreateFlags(textureType);
2048     imageInfo.imageType             = mImageType;
2049     imageInfo.format                = format.vkImageFormat;
2050     imageInfo.extent                = mExtents;
2051     imageInfo.mipLevels             = mipLevels;
2052     imageInfo.arrayLayers           = mLayerCount;
2053     imageInfo.samples               = gl_vk::GetSamples(samples);
2054     imageInfo.tiling                = VK_IMAGE_TILING_OPTIMAL;
2055     imageInfo.usage                 = usage;
2056     imageInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
2057     imageInfo.queueFamilyIndexCount = 0;
2058     imageInfo.pQueueFamilyIndices   = nullptr;
2059     imageInfo.initialLayout         = kImageMemoryBarrierData[initialLayout].layout;
2060 
2061     mCurrentLayout = initialLayout;
2062 
2063     ANGLE_VK_TRY(context, mImage.init(context->getDevice(), imageInfo));
2064 
2065     stageClearIfEmulatedFormat(context);
2066 
2067     return angle::Result::Continue;
2068 }
2069 
releaseImage(RendererVk * renderer)2070 void ImageHelper::releaseImage(RendererVk *renderer)
2071 {
2072     mSerial = rx::kZeroSerial;
2073     renderer->collectGarbageAndReinit(&mUse, &mImage, &mDeviceMemory);
2074 }
2075 
releaseStagingBuffer(RendererVk * renderer)2076 void ImageHelper::releaseStagingBuffer(RendererVk *renderer)
2077 {
2078     // Remove updates that never made it to the texture.
2079     for (SubresourceUpdate &update : mSubresourceUpdates)
2080     {
2081         update.release(renderer);
2082     }
2083     mStagingBuffer.release(renderer);
2084     mSubresourceUpdates.clear();
2085 }
2086 
resetImageWeakReference()2087 void ImageHelper::resetImageWeakReference()
2088 {
2089     mImage.reset();
2090 }
2091 
initializeNonZeroMemory(Context * context,VkDeviceSize size)2092 angle::Result ImageHelper::initializeNonZeroMemory(Context *context, VkDeviceSize size)
2093 {
2094     // The staging buffer memory is non-zero-initialized in 'init'.
2095     vk::StagingBuffer stagingBuffer;
2096     ANGLE_TRY(stagingBuffer.init(context, size, vk::StagingUsage::Write));
2097 
2098     RendererVk *renderer = context->getRenderer();
2099 
2100     vk::PrimaryCommandBuffer commandBuffer;
2101     ANGLE_TRY(renderer->getCommandBufferOneOff(context, &commandBuffer));
2102 
2103     // Queue a DMA copy.
2104     forceChangeLayoutAndQueue(getAspectFlags(), ImageLayout::TransferDst, mCurrentQueueFamilyIndex,
2105                               &commandBuffer);
2106 
2107     VkBufferImageCopy copyRegion           = {};
2108     copyRegion.imageExtent                 = mExtents;
2109     copyRegion.imageSubresource.aspectMask = getAspectFlags();
2110     copyRegion.imageSubresource.layerCount = 1;
2111 
2112     commandBuffer.copyBufferToImage(stagingBuffer.getBuffer().getHandle(), mImage,
2113                                     VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copyRegion);
2114 
2115     ANGLE_VK_TRY(context, commandBuffer.end());
2116 
2117     Serial serial;
2118     ANGLE_TRY(renderer->queueSubmitOneOff(context, std::move(commandBuffer),
2119                                           egl::ContextPriority::Medium, &serial));
2120 
2121     stagingBuffer.collectGarbage(renderer, serial);
2122     mUse.updateSerialOneOff(serial);
2123 
2124     return angle::Result::Continue;
2125 }
2126 
initMemory(Context * context,const MemoryProperties & memoryProperties,VkMemoryPropertyFlags flags)2127 angle::Result ImageHelper::initMemory(Context *context,
2128                                       const MemoryProperties &memoryProperties,
2129                                       VkMemoryPropertyFlags flags)
2130 {
2131     // TODO(jmadill): Memory sub-allocation. http://anglebug.com/2162
2132     VkDeviceSize size;
2133     ANGLE_TRY(AllocateImageMemory(context, flags, nullptr, &mImage, &mDeviceMemory, &size));
2134     mCurrentQueueFamilyIndex = context->getRenderer()->getQueueFamilyIndex();
2135 
2136     RendererVk *renderer = context->getRenderer();
2137     if (renderer->getFeatures().allocateNonZeroMemory.enabled)
2138     {
2139         // Can't map the memory. Use a staging resource.
2140         if ((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
2141         {
2142             // Only currently works with single-sampled color images with one mip/layer.
2143             if (mLevelCount == 1 && mLayerCount == 1 &&
2144                 getAspectFlags() == VK_IMAGE_ASPECT_COLOR_BIT && mSamples == 1)
2145             {
2146                 ANGLE_TRY(initializeNonZeroMemory(context, size));
2147             }
2148             else
2149             {
2150                 UNIMPLEMENTED();
2151             }
2152         }
2153     }
2154 
2155     return angle::Result::Continue;
2156 }
2157 
initExternalMemory(Context * context,const MemoryProperties & memoryProperties,const VkMemoryRequirements & memoryRequirements,const void * extraAllocationInfo,uint32_t currentQueueFamilyIndex,VkMemoryPropertyFlags flags)2158 angle::Result ImageHelper::initExternalMemory(Context *context,
2159                                               const MemoryProperties &memoryProperties,
2160                                               const VkMemoryRequirements &memoryRequirements,
2161                                               const void *extraAllocationInfo,
2162                                               uint32_t currentQueueFamilyIndex,
2163 
2164                                               VkMemoryPropertyFlags flags)
2165 {
2166     // TODO(jmadill): Memory sub-allocation. http://anglebug.com/2162
2167     ANGLE_TRY(AllocateImageMemoryWithRequirements(context, flags, memoryRequirements,
2168                                                   extraAllocationInfo, &mImage, &mDeviceMemory));
2169     mCurrentQueueFamilyIndex = currentQueueFamilyIndex;
2170     return angle::Result::Continue;
2171 }
2172 
initImageView(Context * context,gl::TextureType textureType,VkImageAspectFlags aspectMask,const gl::SwizzleState & swizzleMap,ImageView * imageViewOut,uint32_t baseMipLevel,uint32_t levelCount)2173 angle::Result ImageHelper::initImageView(Context *context,
2174                                          gl::TextureType textureType,
2175                                          VkImageAspectFlags aspectMask,
2176                                          const gl::SwizzleState &swizzleMap,
2177                                          ImageView *imageViewOut,
2178                                          uint32_t baseMipLevel,
2179                                          uint32_t levelCount)
2180 {
2181     return initLayerImageView(context, textureType, aspectMask, swizzleMap, imageViewOut,
2182                               baseMipLevel, levelCount, 0, mLayerCount);
2183 }
2184 
initLayerImageView(Context * context,gl::TextureType textureType,VkImageAspectFlags aspectMask,const gl::SwizzleState & swizzleMap,ImageView * imageViewOut,uint32_t baseMipLevel,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount) const2185 angle::Result ImageHelper::initLayerImageView(Context *context,
2186                                               gl::TextureType textureType,
2187                                               VkImageAspectFlags aspectMask,
2188                                               const gl::SwizzleState &swizzleMap,
2189                                               ImageView *imageViewOut,
2190                                               uint32_t baseMipLevel,
2191                                               uint32_t levelCount,
2192                                               uint32_t baseArrayLayer,
2193                                               uint32_t layerCount) const
2194 {
2195     VkImageViewCreateInfo viewInfo = {};
2196     viewInfo.sType                 = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
2197     viewInfo.flags                 = 0;
2198     viewInfo.image                 = mImage.getHandle();
2199     viewInfo.viewType              = gl_vk::GetImageViewType(textureType);
2200     viewInfo.format                = mFormat->vkImageFormat;
2201     if (swizzleMap.swizzleRequired())
2202     {
2203         viewInfo.components.r = gl_vk::GetSwizzle(swizzleMap.swizzleRed);
2204         viewInfo.components.g = gl_vk::GetSwizzle(swizzleMap.swizzleGreen);
2205         viewInfo.components.b = gl_vk::GetSwizzle(swizzleMap.swizzleBlue);
2206         viewInfo.components.a = gl_vk::GetSwizzle(swizzleMap.swizzleAlpha);
2207     }
2208     else
2209     {
2210         viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
2211         viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
2212         viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
2213         viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
2214     }
2215     viewInfo.subresourceRange.aspectMask     = aspectMask;
2216     viewInfo.subresourceRange.baseMipLevel   = baseMipLevel;
2217     viewInfo.subresourceRange.levelCount     = levelCount;
2218     viewInfo.subresourceRange.baseArrayLayer = baseArrayLayer;
2219     viewInfo.subresourceRange.layerCount     = layerCount;
2220 
2221     ANGLE_VK_TRY(context, imageViewOut->init(context->getDevice(), viewInfo));
2222     return angle::Result::Continue;
2223 }
2224 
destroy(RendererVk * renderer)2225 void ImageHelper::destroy(RendererVk *renderer)
2226 {
2227     VkDevice device = renderer->getDevice();
2228 
2229     mImage.destroy(device);
2230     mDeviceMemory.destroy(device);
2231     mStagingBuffer.destroy(renderer);
2232     mCurrentLayout = ImageLayout::Undefined;
2233     mImageType     = VK_IMAGE_TYPE_2D;
2234     mLayerCount    = 0;
2235     mLevelCount    = 0;
2236     mSerial        = rx::kZeroSerial;
2237 }
2238 
init2DWeakReference(Context * context,VkImage handle,const gl::Extents & glExtents,const Format & format,GLint samples)2239 void ImageHelper::init2DWeakReference(Context *context,
2240                                       VkImage handle,
2241                                       const gl::Extents &glExtents,
2242                                       const Format &format,
2243                                       GLint samples)
2244 {
2245     ASSERT(!valid());
2246 
2247     gl_vk::GetExtent(glExtents, &mExtents);
2248     mFormat        = &format;
2249     mSamples       = samples;
2250     mCurrentLayout = ImageLayout::Undefined;
2251     mLayerCount    = 1;
2252     mLevelCount    = 1;
2253 
2254     mImage.setHandle(handle);
2255 
2256     stageClearIfEmulatedFormat(context);
2257 }
2258 
init2DStaging(Context * context,const MemoryProperties & memoryProperties,const gl::Extents & glExtents,const Format & format,VkImageUsageFlags usage,uint32_t layerCount)2259 angle::Result ImageHelper::init2DStaging(Context *context,
2260                                          const MemoryProperties &memoryProperties,
2261                                          const gl::Extents &glExtents,
2262                                          const Format &format,
2263                                          VkImageUsageFlags usage,
2264                                          uint32_t layerCount)
2265 {
2266     ASSERT(!valid());
2267 
2268     gl_vk::GetExtent(glExtents, &mExtents);
2269     mImageType  = VK_IMAGE_TYPE_2D;
2270     mFormat     = &format;
2271     mSamples    = 1;
2272     mLayerCount = layerCount;
2273     mLevelCount = 1;
2274 
2275     mCurrentLayout = ImageLayout::Undefined;
2276 
2277     VkImageCreateInfo imageInfo     = {};
2278     imageInfo.sType                 = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
2279     imageInfo.flags                 = 0;
2280     imageInfo.imageType             = mImageType;
2281     imageInfo.format                = format.vkImageFormat;
2282     imageInfo.extent                = mExtents;
2283     imageInfo.mipLevels             = 1;
2284     imageInfo.arrayLayers           = mLayerCount;
2285     imageInfo.samples               = gl_vk::GetSamples(mSamples);
2286     imageInfo.tiling                = VK_IMAGE_TILING_OPTIMAL;
2287     imageInfo.usage                 = usage;
2288     imageInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
2289     imageInfo.queueFamilyIndexCount = 0;
2290     imageInfo.pQueueFamilyIndices   = nullptr;
2291     imageInfo.initialLayout         = getCurrentLayout();
2292 
2293     ANGLE_VK_TRY(context, mImage.init(context->getDevice(), imageInfo));
2294 
2295     // Allocate and bind device-local memory.
2296     VkMemoryPropertyFlags memoryPropertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
2297     ANGLE_TRY(initMemory(context, memoryProperties, memoryPropertyFlags));
2298 
2299     return angle::Result::Continue;
2300 }
2301 
getAspectFlags() const2302 VkImageAspectFlags ImageHelper::getAspectFlags() const
2303 {
2304     return GetFormatAspectFlags(mFormat->actualImageFormat());
2305 }
2306 
isCombinedDepthStencilFormat() const2307 bool ImageHelper::isCombinedDepthStencilFormat() const
2308 {
2309     return ((VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT) & getAspectFlags()) ==
2310            (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
2311 }
2312 
getCurrentLayout() const2313 VkImageLayout ImageHelper::getCurrentLayout() const
2314 {
2315     return kImageMemoryBarrierData[mCurrentLayout].layout;
2316 }
2317 
getLevelExtents2D(uint32_t level) const2318 gl::Extents ImageHelper::getLevelExtents2D(uint32_t level) const
2319 {
2320     uint32_t width  = std::max(mExtents.width >> level, 1u);
2321     uint32_t height = std::max(mExtents.height >> level, 1u);
2322 
2323     return gl::Extents(width, height, 1);
2324 }
2325 
isLayoutChangeNecessary(ImageLayout newLayout) const2326 bool ImageHelper::isLayoutChangeNecessary(ImageLayout newLayout) const
2327 {
2328     const ImageMemoryBarrierData &layoutData = kImageMemoryBarrierData[mCurrentLayout];
2329 
2330     // If transitioning to the same layout, we don't need a barrier if the layout is read-only as
2331     // RAR (read-after-read) doesn't need a barrier.  WAW (write-after-write) does require a memory
2332     // barrier though.
2333     bool sameLayoutAndNoNeedForBarrier =
2334         mCurrentLayout == newLayout && !layoutData.sameLayoutTransitionRequiresBarrier;
2335 
2336     return !sameLayoutAndNoNeedForBarrier;
2337 }
2338 
changeLayoutAndQueue(VkImageAspectFlags aspectMask,ImageLayout newLayout,uint32_t newQueueFamilyIndex,CommandBuffer * commandBuffer)2339 void ImageHelper::changeLayoutAndQueue(VkImageAspectFlags aspectMask,
2340                                        ImageLayout newLayout,
2341                                        uint32_t newQueueFamilyIndex,
2342                                        CommandBuffer *commandBuffer)
2343 {
2344     ASSERT(isQueueChangeNeccesary(newQueueFamilyIndex));
2345     forceChangeLayoutAndQueue(aspectMask, newLayout, newQueueFamilyIndex, commandBuffer);
2346 }
2347 
onExternalLayoutChange(ImageLayout newLayout)2348 void ImageHelper::onExternalLayoutChange(ImageLayout newLayout)
2349 {
2350     mCurrentLayout = newLayout;
2351 
2352     // The image must have already been owned by EXTERNAL.  If this is not the case, it's an
2353     // application bug, so ASSERT might eventually need to change to a warning.
2354     ASSERT(mCurrentQueueFamilyIndex == VK_QUEUE_FAMILY_EXTERNAL);
2355 }
2356 
getBaseLevel()2357 uint32_t ImageHelper::getBaseLevel()
2358 {
2359     return mBaseLevel;
2360 }
2361 
setBaseAndMaxLevels(uint32_t baseLevel,uint32_t maxLevel)2362 void ImageHelper::setBaseAndMaxLevels(uint32_t baseLevel, uint32_t maxLevel)
2363 {
2364     mBaseLevel = baseLevel;
2365     mMaxLevel  = maxLevel;
2366 }
2367 
2368 // Generalized to accept both "primary" and "secondary" command buffers.
2369 template <typename CommandBufferT>
forceChangeLayoutAndQueue(VkImageAspectFlags aspectMask,ImageLayout newLayout,uint32_t newQueueFamilyIndex,CommandBufferT * commandBuffer)2370 void ImageHelper::forceChangeLayoutAndQueue(VkImageAspectFlags aspectMask,
2371                                             ImageLayout newLayout,
2372                                             uint32_t newQueueFamilyIndex,
2373                                             CommandBufferT *commandBuffer)
2374 {
2375     const ImageMemoryBarrierData &transitionFrom = kImageMemoryBarrierData[mCurrentLayout];
2376     const ImageMemoryBarrierData &transitionTo   = kImageMemoryBarrierData[newLayout];
2377 
2378     VkImageMemoryBarrier imageMemoryBarrier = {};
2379     imageMemoryBarrier.sType                = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2380     imageMemoryBarrier.srcAccessMask        = transitionFrom.srcAccessMask;
2381     imageMemoryBarrier.dstAccessMask        = transitionTo.dstAccessMask;
2382     imageMemoryBarrier.oldLayout            = transitionFrom.layout;
2383     imageMemoryBarrier.newLayout            = transitionTo.layout;
2384     imageMemoryBarrier.srcQueueFamilyIndex  = mCurrentQueueFamilyIndex;
2385     imageMemoryBarrier.dstQueueFamilyIndex  = newQueueFamilyIndex;
2386     imageMemoryBarrier.image                = mImage.getHandle();
2387 
2388     // Transition the whole resource.
2389     imageMemoryBarrier.subresourceRange.aspectMask     = aspectMask;
2390     imageMemoryBarrier.subresourceRange.baseMipLevel   = 0;
2391     imageMemoryBarrier.subresourceRange.levelCount     = mLevelCount;
2392     imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
2393     imageMemoryBarrier.subresourceRange.layerCount     = mLayerCount;
2394 
2395     commandBuffer->imageBarrier(transitionFrom.srcStageMask, transitionTo.dstStageMask,
2396                                 imageMemoryBarrier);
2397     mCurrentLayout           = newLayout;
2398     mCurrentQueueFamilyIndex = newQueueFamilyIndex;
2399 }
2400 
2401 // Explicitly instantiate forceChangeLayoutAndQueue with CommandBufferHelper.
2402 template void ImageHelper::forceChangeLayoutAndQueue(VkImageAspectFlags aspectMask,
2403                                                      ImageLayout newLayout,
2404                                                      uint32_t newQueueFamilyIndex,
2405                                                      CommandBufferHelper *commandBuffer);
2406 
clearColor(const VkClearColorValue & color,uint32_t baseMipLevel,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount,CommandBuffer * commandBuffer)2407 void ImageHelper::clearColor(const VkClearColorValue &color,
2408                              uint32_t baseMipLevel,
2409                              uint32_t levelCount,
2410                              uint32_t baseArrayLayer,
2411                              uint32_t layerCount,
2412                              CommandBuffer *commandBuffer)
2413 {
2414     ASSERT(valid());
2415 
2416     ASSERT(mCurrentLayout == ImageLayout::TransferDst);
2417 
2418     VkImageSubresourceRange range = {};
2419     range.aspectMask              = VK_IMAGE_ASPECT_COLOR_BIT;
2420     range.baseMipLevel            = baseMipLevel;
2421     range.levelCount              = levelCount;
2422     range.baseArrayLayer          = baseArrayLayer;
2423     range.layerCount              = layerCount;
2424 
2425     commandBuffer->clearColorImage(mImage, getCurrentLayout(), color, 1, &range);
2426 }
2427 
clearDepthStencil(VkImageAspectFlags clearAspectFlags,const VkClearDepthStencilValue & depthStencil,uint32_t baseMipLevel,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount,CommandBuffer * commandBuffer)2428 void ImageHelper::clearDepthStencil(VkImageAspectFlags clearAspectFlags,
2429                                     const VkClearDepthStencilValue &depthStencil,
2430                                     uint32_t baseMipLevel,
2431                                     uint32_t levelCount,
2432                                     uint32_t baseArrayLayer,
2433                                     uint32_t layerCount,
2434                                     CommandBuffer *commandBuffer)
2435 {
2436     ASSERT(valid());
2437 
2438     ASSERT(mCurrentLayout == ImageLayout::TransferDst);
2439 
2440     VkImageSubresourceRange clearRange = {
2441         /*aspectMask*/ clearAspectFlags,
2442         /*baseMipLevel*/ baseMipLevel,
2443         /*levelCount*/ levelCount,
2444         /*baseArrayLayer*/ baseArrayLayer,
2445         /*layerCount*/ layerCount,
2446     };
2447 
2448     commandBuffer->clearDepthStencilImage(mImage, getCurrentLayout(), depthStencil, 1, &clearRange);
2449 }
2450 
clear(VkImageAspectFlags aspectFlags,const VkClearValue & value,uint32_t mipLevel,uint32_t baseArrayLayer,uint32_t layerCount,CommandBuffer * commandBuffer)2451 void ImageHelper::clear(VkImageAspectFlags aspectFlags,
2452                         const VkClearValue &value,
2453                         uint32_t mipLevel,
2454                         uint32_t baseArrayLayer,
2455                         uint32_t layerCount,
2456                         CommandBuffer *commandBuffer)
2457 {
2458     const angle::Format &angleFormat = mFormat->intendedFormat();
2459     bool isDepthStencil              = angleFormat.depthBits > 0 || angleFormat.stencilBits > 0;
2460 
2461     if (isDepthStencil)
2462     {
2463         clearDepthStencil(aspectFlags, value.depthStencil, mipLevel, 1, baseArrayLayer, layerCount,
2464                           commandBuffer);
2465     }
2466     else
2467     {
2468         clearColor(value.color, mipLevel, 1, baseArrayLayer, layerCount, commandBuffer);
2469     }
2470 }
2471 
getSize(const gl::ImageIndex & index) const2472 gl::Extents ImageHelper::getSize(const gl::ImageIndex &index) const
2473 {
2474     GLint mipLevel = index.getLevelIndex();
2475     // Level 0 should be the size of the extents, after that every time you increase a level
2476     // you shrink the extents by half.
2477     return gl::Extents(std::max(1u, mExtents.width >> mipLevel),
2478                        std::max(1u, mExtents.height >> mipLevel), mExtents.depth);
2479 }
2480 
getAssignSerial(ContextVk * contextVk)2481 Serial ImageHelper::getAssignSerial(ContextVk *contextVk)
2482 {
2483     if (mSerial.getValue() == 0)
2484     {
2485         mSerial = contextVk->generateAttachmentImageSerial();
2486     }
2487     return mSerial;
2488 }
2489 
2490 // static
Copy(ImageHelper * srcImage,ImageHelper * dstImage,const gl::Offset & srcOffset,const gl::Offset & dstOffset,const gl::Extents & copySize,const VkImageSubresourceLayers & srcSubresource,const VkImageSubresourceLayers & dstSubresource,CommandBuffer * commandBuffer)2491 void ImageHelper::Copy(ImageHelper *srcImage,
2492                        ImageHelper *dstImage,
2493                        const gl::Offset &srcOffset,
2494                        const gl::Offset &dstOffset,
2495                        const gl::Extents &copySize,
2496                        const VkImageSubresourceLayers &srcSubresource,
2497                        const VkImageSubresourceLayers &dstSubresource,
2498                        CommandBuffer *commandBuffer)
2499 {
2500     ASSERT(commandBuffer->valid() && srcImage->valid() && dstImage->valid());
2501 
2502     ASSERT(srcImage->getCurrentLayout() == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
2503     ASSERT(dstImage->getCurrentLayout() == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
2504 
2505     VkImageCopy region    = {};
2506     region.srcSubresource = srcSubresource;
2507     region.srcOffset.x    = srcOffset.x;
2508     region.srcOffset.y    = srcOffset.y;
2509     region.srcOffset.z    = srcOffset.z;
2510     region.dstSubresource = dstSubresource;
2511     region.dstOffset.x    = dstOffset.x;
2512     region.dstOffset.y    = dstOffset.y;
2513     region.dstOffset.z    = dstOffset.z;
2514     region.extent.width   = copySize.width;
2515     region.extent.height  = copySize.height;
2516     region.extent.depth   = copySize.depth;
2517 
2518     commandBuffer->copyImage(srcImage->getImage(), srcImage->getCurrentLayout(),
2519                              dstImage->getImage(), dstImage->getCurrentLayout(), 1, &region);
2520 }
2521 
generateMipmapsWithBlit(ContextVk * contextVk,GLuint maxLevel)2522 angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint maxLevel)
2523 {
2524     CommandBuffer *commandBuffer = nullptr;
2525     ANGLE_TRY(contextVk->onImageWrite(VK_IMAGE_ASPECT_COLOR_BIT, ImageLayout::TransferDst, this));
2526     ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
2527 
2528     // We are able to use blitImage since the image format we are using supports it. This
2529     // is a faster way we can generate the mips.
2530     int32_t mipWidth  = mExtents.width;
2531     int32_t mipHeight = mExtents.height;
2532     int32_t mipDepth  = mExtents.depth;
2533 
2534     // Manually manage the image memory barrier because it uses a lot more parameters than our
2535     // usual one.
2536     VkImageMemoryBarrier barrier            = {};
2537     barrier.sType                           = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
2538     barrier.image                           = mImage.getHandle();
2539     barrier.srcQueueFamilyIndex             = VK_QUEUE_FAMILY_IGNORED;
2540     barrier.dstQueueFamilyIndex             = VK_QUEUE_FAMILY_IGNORED;
2541     barrier.subresourceRange.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
2542     barrier.subresourceRange.baseArrayLayer = 0;
2543     barrier.subresourceRange.layerCount     = mLayerCount;
2544     barrier.subresourceRange.levelCount     = 1;
2545 
2546     for (uint32_t mipLevel = 1; mipLevel <= maxLevel; mipLevel++)
2547     {
2548         int32_t nextMipWidth  = std::max<int32_t>(1, mipWidth >> 1);
2549         int32_t nextMipHeight = std::max<int32_t>(1, mipHeight >> 1);
2550         int32_t nextMipDepth  = std::max<int32_t>(1, mipDepth >> 1);
2551 
2552         barrier.subresourceRange.baseMipLevel = mipLevel - 1;
2553         barrier.oldLayout                     = getCurrentLayout();
2554         barrier.newLayout                     = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
2555         barrier.srcAccessMask                 = VK_ACCESS_TRANSFER_WRITE_BIT;
2556         barrier.dstAccessMask                 = VK_ACCESS_TRANSFER_READ_BIT;
2557 
2558         // We can do it for all layers at once.
2559         commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
2560                                     barrier);
2561         VkImageBlit blit                   = {};
2562         blit.srcOffsets[0]                 = {0, 0, 0};
2563         blit.srcOffsets[1]                 = {mipWidth, mipHeight, mipDepth};
2564         blit.srcSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
2565         blit.srcSubresource.mipLevel       = mipLevel - 1;
2566         blit.srcSubresource.baseArrayLayer = 0;
2567         blit.srcSubresource.layerCount     = mLayerCount;
2568         blit.dstOffsets[0]                 = {0, 0, 0};
2569         blit.dstOffsets[1]                 = {nextMipWidth, nextMipHeight, nextMipDepth};
2570         blit.dstSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
2571         blit.dstSubresource.mipLevel       = mipLevel;
2572         blit.dstSubresource.baseArrayLayer = 0;
2573         blit.dstSubresource.layerCount     = mLayerCount;
2574 
2575         mipWidth  = nextMipWidth;
2576         mipHeight = nextMipHeight;
2577         mipDepth  = nextMipDepth;
2578 
2579         bool formatSupportsLinearFiltering = contextVk->getRenderer()->hasImageFormatFeatureBits(
2580             getFormat().vkImageFormat, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT);
2581 
2582         commandBuffer->blitImage(
2583             mImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, mImage,
2584             VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit,
2585             formatSupportsLinearFiltering ? VK_FILTER_LINEAR : VK_FILTER_NEAREST);
2586     }
2587 
2588     // Transition the last mip level to the same layout as all the other ones, so we can declare
2589     // our whole image layout to be SRC_OPTIMAL.
2590     barrier.subresourceRange.baseMipLevel = maxLevel;
2591     barrier.oldLayout                     = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
2592     barrier.newLayout                     = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
2593 
2594     // We can do it for all layers at once.
2595     commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
2596                                 barrier);
2597     // This is just changing the internal state of the image helper so that the next call
2598     // to changeLayout will use this layout as the "oldLayout" argument.
2599     mCurrentLayout = ImageLayout::TransferSrc;
2600 
2601     return angle::Result::Continue;
2602 }
2603 
resolve(ImageHelper * dest,const VkImageResolve & region,CommandBuffer * commandBuffer)2604 void ImageHelper::resolve(ImageHelper *dest,
2605                           const VkImageResolve &region,
2606                           CommandBuffer *commandBuffer)
2607 {
2608     ASSERT(mCurrentLayout == ImageLayout::TransferSrc);
2609     commandBuffer->resolveImage(getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dest->getImage(),
2610                                 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
2611 }
2612 
removeStagedUpdates(ContextVk * contextVk,const gl::ImageIndex & index)2613 void ImageHelper::removeStagedUpdates(ContextVk *contextVk, const gl::ImageIndex &index)
2614 {
2615     // Find any staged updates for this index and removes them from the pending list.
2616     uint32_t levelIndex = index.getLevelIndex();
2617     uint32_t layerIndex = index.hasLayer() ? index.getLayerIndex() : 0;
2618 
2619     for (size_t index = 0; index < mSubresourceUpdates.size();)
2620     {
2621         auto update = mSubresourceUpdates.begin() + index;
2622         if (update->isUpdateToLayerLevel(layerIndex, levelIndex))
2623         {
2624             update->release(contextVk->getRenderer());
2625             mSubresourceUpdates.erase(update);
2626         }
2627         else
2628         {
2629             index++;
2630         }
2631     }
2632 }
2633 
stageSubresourceUpdateImpl(ContextVk * contextVk,const gl::ImageIndex & index,const gl::Extents & glExtents,const gl::Offset & offset,const gl::InternalFormat & formatInfo,const gl::PixelUnpackState & unpack,GLenum type,const uint8_t * pixels,const Format & vkFormat,const GLuint inputRowPitch,const GLuint inputDepthPitch,const GLuint inputSkipBytes)2634 angle::Result ImageHelper::stageSubresourceUpdateImpl(ContextVk *contextVk,
2635                                                       const gl::ImageIndex &index,
2636                                                       const gl::Extents &glExtents,
2637                                                       const gl::Offset &offset,
2638                                                       const gl::InternalFormat &formatInfo,
2639                                                       const gl::PixelUnpackState &unpack,
2640                                                       GLenum type,
2641                                                       const uint8_t *pixels,
2642                                                       const Format &vkFormat,
2643                                                       const GLuint inputRowPitch,
2644                                                       const GLuint inputDepthPitch,
2645                                                       const GLuint inputSkipBytes)
2646 {
2647     const angle::Format &storageFormat = vkFormat.actualImageFormat();
2648 
2649     size_t outputRowPitch;
2650     size_t outputDepthPitch;
2651     size_t stencilAllocationSize = 0;
2652     uint32_t bufferRowLength;
2653     uint32_t bufferImageHeight;
2654     size_t allocationSize;
2655 
2656     LoadImageFunctionInfo loadFunctionInfo = vkFormat.textureLoadFunctions(type);
2657     LoadImageFunction stencilLoadFunction  = nullptr;
2658 
2659     if (storageFormat.isBlock)
2660     {
2661         const gl::InternalFormat &storageFormatInfo = vkFormat.getInternalFormatInfo(type);
2662         GLuint rowPitch;
2663         GLuint depthPitch;
2664         GLuint totalSize;
2665 
2666         ANGLE_VK_CHECK_MATH(contextVk, storageFormatInfo.computeCompressedImageSize(
2667                                            gl::Extents(glExtents.width, 1, 1), &rowPitch));
2668         ANGLE_VK_CHECK_MATH(contextVk,
2669                             storageFormatInfo.computeCompressedImageSize(
2670                                 gl::Extents(glExtents.width, glExtents.height, 1), &depthPitch));
2671 
2672         ANGLE_VK_CHECK_MATH(contextVk,
2673                             storageFormatInfo.computeCompressedImageSize(glExtents, &totalSize));
2674 
2675         outputRowPitch   = rowPitch;
2676         outputDepthPitch = depthPitch;
2677 
2678         angle::CheckedNumeric<uint32_t> checkedRowLength =
2679             rx::CheckedRoundUp<uint32_t>(glExtents.width, storageFormatInfo.compressedBlockWidth);
2680         angle::CheckedNumeric<uint32_t> checkedImageHeight =
2681             rx::CheckedRoundUp<uint32_t>(glExtents.height, storageFormatInfo.compressedBlockHeight);
2682 
2683         ANGLE_VK_CHECK_MATH(contextVk, checkedRowLength.IsValid());
2684         ANGLE_VK_CHECK_MATH(contextVk, checkedImageHeight.IsValid());
2685 
2686         bufferRowLength   = checkedRowLength.ValueOrDie();
2687         bufferImageHeight = checkedImageHeight.ValueOrDie();
2688         allocationSize    = totalSize;
2689     }
2690     else
2691     {
2692         ASSERT(storageFormat.pixelBytes != 0);
2693 
2694         if (storageFormat.id == angle::FormatID::D24_UNORM_S8_UINT)
2695         {
2696             stencilLoadFunction = angle::LoadX24S8ToS8;
2697         }
2698         if (storageFormat.id == angle::FormatID::D32_FLOAT_S8X24_UINT)
2699         {
2700             // If depth is D32FLOAT_S8, we must pack D32F tightly (no stencil) for CopyBufferToImage
2701             outputRowPitch = sizeof(float) * glExtents.width;
2702 
2703             // The generic load functions don't handle tightly packing D32FS8 to D32F & S8 so call
2704             // special case load functions.
2705             switch (type)
2706             {
2707                 case GL_UNSIGNED_INT:
2708                     loadFunctionInfo.loadFunction = angle::LoadD32ToD32F;
2709                     stencilLoadFunction           = nullptr;
2710                     break;
2711                 case GL_DEPTH32F_STENCIL8:
2712                 case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
2713                     loadFunctionInfo.loadFunction = angle::LoadD32FS8X24ToD32F;
2714                     stencilLoadFunction           = angle::LoadX32S8ToS8;
2715                     break;
2716                 case GL_UNSIGNED_INT_24_8_OES:
2717                     loadFunctionInfo.loadFunction = angle::LoadD24S8ToD32F;
2718                     stencilLoadFunction           = angle::LoadX24S8ToS8;
2719                     break;
2720                 default:
2721                     UNREACHABLE();
2722             }
2723         }
2724         else
2725         {
2726             outputRowPitch = storageFormat.pixelBytes * glExtents.width;
2727         }
2728         outputDepthPitch = outputRowPitch * glExtents.height;
2729 
2730         bufferRowLength   = glExtents.width;
2731         bufferImageHeight = glExtents.height;
2732 
2733         allocationSize = outputDepthPitch * glExtents.depth;
2734 
2735         // Note: because the LoadImageFunctionInfo functions are limited to copying a single
2736         // component, we have to special case packed depth/stencil use and send the stencil as a
2737         // separate chunk.
2738         if (storageFormat.depthBits > 0 && storageFormat.stencilBits > 0 &&
2739             formatInfo.depthBits > 0 && formatInfo.stencilBits > 0)
2740         {
2741             // Note: Stencil is always one byte
2742             stencilAllocationSize = glExtents.width * glExtents.height * glExtents.depth;
2743             allocationSize += stencilAllocationSize;
2744         }
2745     }
2746 
2747     VkBuffer bufferHandle = VK_NULL_HANDLE;
2748 
2749     uint8_t *stagingPointer    = nullptr;
2750     VkDeviceSize stagingOffset = 0;
2751     ANGLE_TRY(mStagingBuffer.allocate(contextVk, allocationSize, &stagingPointer, &bufferHandle,
2752                                       &stagingOffset, nullptr));
2753 
2754     const uint8_t *source = pixels + static_cast<ptrdiff_t>(inputSkipBytes);
2755 
2756     loadFunctionInfo.loadFunction(glExtents.width, glExtents.height, glExtents.depth, source,
2757                                   inputRowPitch, inputDepthPitch, stagingPointer, outputRowPitch,
2758                                   outputDepthPitch);
2759 
2760     VkBufferImageCopy copy         = {};
2761     VkImageAspectFlags aspectFlags = GetFormatAspectFlags(vkFormat.actualImageFormat());
2762 
2763     copy.bufferOffset      = stagingOffset;
2764     copy.bufferRowLength   = bufferRowLength;
2765     copy.bufferImageHeight = bufferImageHeight;
2766 
2767     copy.imageSubresource.mipLevel   = index.getLevelIndex();
2768     copy.imageSubresource.layerCount = index.getLayerCount();
2769 
2770     gl_vk::GetOffset(offset, &copy.imageOffset);
2771     gl_vk::GetExtent(glExtents, &copy.imageExtent);
2772 
2773     if (gl::IsArrayTextureType(index.getType()))
2774     {
2775         copy.imageSubresource.baseArrayLayer = offset.z;
2776         copy.imageOffset.z                   = 0;
2777         copy.imageExtent.depth               = 1;
2778     }
2779     else
2780     {
2781         copy.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
2782     }
2783 
2784     if (stencilAllocationSize > 0)
2785     {
2786         // Note: Stencil is always one byte
2787         ASSERT((aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) != 0);
2788 
2789         // Skip over depth data.
2790         stagingPointer += outputDepthPitch * glExtents.depth;
2791         stagingOffset += outputDepthPitch * glExtents.depth;
2792 
2793         // recompute pitch for stencil data
2794         outputRowPitch   = glExtents.width;
2795         outputDepthPitch = outputRowPitch * glExtents.height;
2796 
2797         ASSERT(stencilLoadFunction != nullptr);
2798         stencilLoadFunction(glExtents.width, glExtents.height, glExtents.depth, source,
2799                             inputRowPitch, inputDepthPitch, stagingPointer, outputRowPitch,
2800                             outputDepthPitch);
2801 
2802         VkBufferImageCopy stencilCopy = {};
2803 
2804         stencilCopy.bufferOffset                    = stagingOffset;
2805         stencilCopy.bufferRowLength                 = bufferRowLength;
2806         stencilCopy.bufferImageHeight               = bufferImageHeight;
2807         stencilCopy.imageSubresource.mipLevel       = copy.imageSubresource.mipLevel;
2808         stencilCopy.imageSubresource.baseArrayLayer = copy.imageSubresource.baseArrayLayer;
2809         stencilCopy.imageSubresource.layerCount     = copy.imageSubresource.layerCount;
2810         stencilCopy.imageOffset                     = copy.imageOffset;
2811         stencilCopy.imageExtent                     = copy.imageExtent;
2812         stencilCopy.imageSubresource.aspectMask     = VK_IMAGE_ASPECT_STENCIL_BIT;
2813         appendSubresourceUpdate(SubresourceUpdate(mStagingBuffer.getCurrentBuffer(), stencilCopy));
2814 
2815         aspectFlags &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
2816     }
2817 
2818     if (IsMaskFlagSet(aspectFlags, static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_STENCIL_BIT |
2819                                                                    VK_IMAGE_ASPECT_DEPTH_BIT)))
2820     {
2821         // We still have both depth and stencil aspect bits set. That means we have a destination
2822         // buffer that is packed depth stencil and that the application is only loading one aspect.
2823         // Figure out which aspect the user is touching and remove the unused aspect bit.
2824         if (formatInfo.stencilBits > 0)
2825         {
2826             aspectFlags &= ~VK_IMAGE_ASPECT_DEPTH_BIT;
2827         }
2828         else
2829         {
2830             aspectFlags &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
2831         }
2832     }
2833 
2834     if (aspectFlags)
2835     {
2836         copy.imageSubresource.aspectMask = aspectFlags;
2837         appendSubresourceUpdate(SubresourceUpdate(mStagingBuffer.getCurrentBuffer(), copy));
2838     }
2839 
2840     return angle::Result::Continue;
2841 }
2842 
CalculateBufferInfo(ContextVk * contextVk,const gl::Extents & glExtents,const gl::InternalFormat & formatInfo,const gl::PixelUnpackState & unpack,GLenum type,bool is3D,GLuint * inputRowPitch,GLuint * inputDepthPitch,GLuint * inputSkipBytes)2843 angle::Result ImageHelper::CalculateBufferInfo(ContextVk *contextVk,
2844                                                const gl::Extents &glExtents,
2845                                                const gl::InternalFormat &formatInfo,
2846                                                const gl::PixelUnpackState &unpack,
2847                                                GLenum type,
2848                                                bool is3D,
2849                                                GLuint *inputRowPitch,
2850                                                GLuint *inputDepthPitch,
2851                                                GLuint *inputSkipBytes)
2852 {
2853     ANGLE_VK_CHECK_MATH(contextVk,
2854                         formatInfo.computeRowPitch(type, glExtents.width, unpack.alignment,
2855                                                    unpack.rowLength, inputRowPitch));
2856 
2857     ANGLE_VK_CHECK_MATH(contextVk,
2858                         formatInfo.computeDepthPitch(glExtents.height, unpack.imageHeight,
2859                                                      *inputRowPitch, inputDepthPitch));
2860 
2861     ANGLE_VK_CHECK_MATH(
2862         contextVk, formatInfo.computeSkipBytes(type, *inputRowPitch, *inputDepthPitch, unpack, is3D,
2863                                                inputSkipBytes));
2864 
2865     return angle::Result::Continue;
2866 }
2867 
stageSubresourceUpdate(ContextVk * contextVk,const gl::ImageIndex & index,const gl::Extents & glExtents,const gl::Offset & offset,const gl::InternalFormat & formatInfo,const gl::PixelUnpackState & unpack,GLenum type,const uint8_t * pixels,const Format & vkFormat)2868 angle::Result ImageHelper::stageSubresourceUpdate(ContextVk *contextVk,
2869                                                   const gl::ImageIndex &index,
2870                                                   const gl::Extents &glExtents,
2871                                                   const gl::Offset &offset,
2872                                                   const gl::InternalFormat &formatInfo,
2873                                                   const gl::PixelUnpackState &unpack,
2874                                                   GLenum type,
2875                                                   const uint8_t *pixels,
2876                                                   const Format &vkFormat)
2877 {
2878     GLuint inputRowPitch   = 0;
2879     GLuint inputDepthPitch = 0;
2880     GLuint inputSkipBytes  = 0;
2881     ANGLE_TRY(CalculateBufferInfo(contextVk, glExtents, formatInfo, unpack, type, index.usesTex3D(),
2882                                   &inputRowPitch, &inputDepthPitch, &inputSkipBytes));
2883 
2884     ANGLE_TRY(stageSubresourceUpdateImpl(contextVk, index, glExtents, offset, formatInfo, unpack,
2885                                          type, pixels, vkFormat, inputRowPitch, inputDepthPitch,
2886                                          inputSkipBytes));
2887 
2888     return angle::Result::Continue;
2889 }
2890 
stageSubresourceUpdateAndGetData(ContextVk * contextVk,size_t allocationSize,const gl::ImageIndex & imageIndex,const gl::Extents & glExtents,const gl::Offset & offset,uint8_t ** destData)2891 angle::Result ImageHelper::stageSubresourceUpdateAndGetData(ContextVk *contextVk,
2892                                                             size_t allocationSize,
2893                                                             const gl::ImageIndex &imageIndex,
2894                                                             const gl::Extents &glExtents,
2895                                                             const gl::Offset &offset,
2896                                                             uint8_t **destData)
2897 {
2898     VkBuffer bufferHandle;
2899     VkDeviceSize stagingOffset = 0;
2900     ANGLE_TRY(mStagingBuffer.allocate(contextVk, allocationSize, destData, &bufferHandle,
2901                                       &stagingOffset, nullptr));
2902 
2903     VkBufferImageCopy copy               = {};
2904     copy.bufferOffset                    = stagingOffset;
2905     copy.bufferRowLength                 = glExtents.width;
2906     copy.bufferImageHeight               = glExtents.height;
2907     copy.imageSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
2908     copy.imageSubresource.mipLevel       = imageIndex.getLevelIndex();
2909     copy.imageSubresource.baseArrayLayer = imageIndex.hasLayer() ? imageIndex.getLayerIndex() : 0;
2910     copy.imageSubresource.layerCount     = imageIndex.getLayerCount();
2911 
2912     // Note: Only support color now
2913     ASSERT(getAspectFlags() == VK_IMAGE_ASPECT_COLOR_BIT);
2914 
2915     gl_vk::GetOffset(offset, &copy.imageOffset);
2916     gl_vk::GetExtent(glExtents, &copy.imageExtent);
2917 
2918     appendSubresourceUpdate(SubresourceUpdate(mStagingBuffer.getCurrentBuffer(), copy));
2919 
2920     return angle::Result::Continue;
2921 }
2922 
stageSubresourceUpdateFromBuffer(ContextVk * contextVk,size_t allocationSize,uint32_t mipLevel,uint32_t baseArrayLayer,uint32_t layerCount,const VkExtent3D & extent,const VkOffset3D & offset,BufferHelper * bufferHelper,StagingBufferOffsetArray stagingOffsets)2923 angle::Result ImageHelper::stageSubresourceUpdateFromBuffer(ContextVk *contextVk,
2924                                                             size_t allocationSize,
2925                                                             uint32_t mipLevel,
2926                                                             uint32_t baseArrayLayer,
2927                                                             uint32_t layerCount,
2928                                                             const VkExtent3D &extent,
2929                                                             const VkOffset3D &offset,
2930                                                             BufferHelper *bufferHelper,
2931                                                             StagingBufferOffsetArray stagingOffsets)
2932 {
2933     // This function stages an update from explicitly provided handle and offset
2934     // It is used when the texture base level has changed, and we need to propagate data
2935 
2936     VkBufferImageCopy copy[2]               = {};
2937     copy[0].bufferOffset                    = stagingOffsets[0];
2938     copy[0].bufferRowLength                 = extent.width;
2939     copy[0].bufferImageHeight               = extent.height;
2940     copy[0].imageSubresource.aspectMask     = getAspectFlags();
2941     copy[0].imageSubresource.mipLevel       = mipLevel;
2942     copy[0].imageSubresource.baseArrayLayer = baseArrayLayer;
2943     copy[0].imageSubresource.layerCount     = layerCount;
2944     copy[0].imageOffset                     = offset;
2945     copy[0].imageExtent                     = extent;
2946 
2947     if (isCombinedDepthStencilFormat())
2948     {
2949         // Force aspect to depth for first copy
2950         copy[0].imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
2951         // Copy stencil aspect separately
2952         copy[1].bufferOffset                    = stagingOffsets[1];
2953         copy[1].bufferRowLength                 = extent.width;
2954         copy[1].bufferImageHeight               = extent.height;
2955         copy[1].imageSubresource.aspectMask     = VK_IMAGE_ASPECT_STENCIL_BIT;
2956         copy[1].imageSubresource.mipLevel       = mipLevel;
2957         copy[1].imageSubresource.baseArrayLayer = baseArrayLayer;
2958         copy[1].imageSubresource.layerCount     = layerCount;
2959         copy[1].imageOffset                     = offset;
2960         copy[1].imageExtent                     = extent;
2961         appendSubresourceUpdate(SubresourceUpdate(bufferHelper, copy[1]));
2962     }
2963 
2964     appendSubresourceUpdate(SubresourceUpdate(bufferHelper, copy[0]));
2965 
2966     return angle::Result::Continue;
2967 }
2968 
stageSubresourceUpdateFromFramebuffer(const gl::Context * context,const gl::ImageIndex & index,const gl::Rectangle & sourceArea,const gl::Offset & dstOffset,const gl::Extents & dstExtent,const gl::InternalFormat & formatInfo,FramebufferVk * framebufferVk)2969 angle::Result ImageHelper::stageSubresourceUpdateFromFramebuffer(
2970     const gl::Context *context,
2971     const gl::ImageIndex &index,
2972     const gl::Rectangle &sourceArea,
2973     const gl::Offset &dstOffset,
2974     const gl::Extents &dstExtent,
2975     const gl::InternalFormat &formatInfo,
2976     FramebufferVk *framebufferVk)
2977 {
2978     ContextVk *contextVk = GetImpl(context);
2979 
2980     // If the extents and offset is outside the source image, we need to clip.
2981     gl::Rectangle clippedRectangle;
2982     const gl::Extents readExtents = framebufferVk->getReadImageExtents();
2983     if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, readExtents.width, readExtents.height),
2984                        &clippedRectangle))
2985     {
2986         // Empty source area, nothing to do.
2987         return angle::Result::Continue;
2988     }
2989 
2990     bool isViewportFlipEnabled = contextVk->isViewportFlipEnabledForDrawFBO();
2991     if (isViewportFlipEnabled)
2992     {
2993         clippedRectangle.y = readExtents.height - clippedRectangle.y - clippedRectangle.height;
2994     }
2995 
2996     // 1- obtain a buffer handle to copy to
2997     RendererVk *renderer = contextVk->getRenderer();
2998 
2999     const Format &vkFormat             = renderer->getFormat(formatInfo.sizedInternalFormat);
3000     const angle::Format &storageFormat = vkFormat.actualImageFormat();
3001     LoadImageFunctionInfo loadFunction = vkFormat.textureLoadFunctions(formatInfo.type);
3002 
3003     size_t outputRowPitch   = storageFormat.pixelBytes * clippedRectangle.width;
3004     size_t outputDepthPitch = outputRowPitch * clippedRectangle.height;
3005 
3006     VkBuffer bufferHandle = VK_NULL_HANDLE;
3007 
3008     uint8_t *stagingPointer    = nullptr;
3009     VkDeviceSize stagingOffset = 0;
3010 
3011     // The destination is only one layer deep.
3012     size_t allocationSize = outputDepthPitch;
3013     ANGLE_TRY(mStagingBuffer.allocate(contextVk, allocationSize, &stagingPointer, &bufferHandle,
3014                                       &stagingOffset, nullptr));
3015 
3016     const angle::Format &copyFormat =
3017         GetFormatFromFormatType(formatInfo.internalFormat, formatInfo.type);
3018     PackPixelsParams params(clippedRectangle, copyFormat, static_cast<GLuint>(outputRowPitch),
3019                             isViewportFlipEnabled, nullptr, 0);
3020 
3021     RenderTargetVk *readRenderTarget = framebufferVk->getColorReadRenderTarget();
3022 
3023     // 2- copy the source image region to the pixel buffer using a cpu readback
3024     if (loadFunction.requiresConversion)
3025     {
3026         // When a conversion is required, we need to use the loadFunction to read from a temporary
3027         // buffer instead so its an even slower path.
3028         size_t bufferSize =
3029             storageFormat.pixelBytes * clippedRectangle.width * clippedRectangle.height;
3030         angle::MemoryBuffer *memoryBuffer = nullptr;
3031         ANGLE_VK_CHECK_ALLOC(contextVk, context->getScratchBuffer(bufferSize, &memoryBuffer));
3032 
3033         // Read into the scratch buffer
3034         ANGLE_TRY(framebufferVk->readPixelsImpl(contextVk, clippedRectangle, params,
3035                                                 VK_IMAGE_ASPECT_COLOR_BIT, readRenderTarget,
3036                                                 memoryBuffer->data()));
3037 
3038         // Load from scratch buffer to our pixel buffer
3039         loadFunction.loadFunction(clippedRectangle.width, clippedRectangle.height, 1,
3040                                   memoryBuffer->data(), outputRowPitch, 0, stagingPointer,
3041                                   outputRowPitch, 0);
3042     }
3043     else
3044     {
3045         // We read directly from the framebuffer into our pixel buffer.
3046         ANGLE_TRY(framebufferVk->readPixelsImpl(contextVk, clippedRectangle, params,
3047                                                 VK_IMAGE_ASPECT_COLOR_BIT, readRenderTarget,
3048                                                 stagingPointer));
3049     }
3050 
3051     // 3- enqueue the destination image subresource update
3052     VkBufferImageCopy copyToImage               = {};
3053     copyToImage.bufferOffset                    = static_cast<VkDeviceSize>(stagingOffset);
3054     copyToImage.bufferRowLength                 = 0;  // Tightly packed data can be specified as 0.
3055     copyToImage.bufferImageHeight               = clippedRectangle.height;
3056     copyToImage.imageSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
3057     copyToImage.imageSubresource.mipLevel       = index.getLevelIndex();
3058     copyToImage.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
3059     copyToImage.imageSubresource.layerCount     = index.getLayerCount();
3060     gl_vk::GetOffset(dstOffset, &copyToImage.imageOffset);
3061     gl_vk::GetExtent(dstExtent, &copyToImage.imageExtent);
3062 
3063     // 3- enqueue the destination image subresource update
3064     appendSubresourceUpdate(SubresourceUpdate(mStagingBuffer.getCurrentBuffer(), copyToImage));
3065     return angle::Result::Continue;
3066 }
3067 
stageSubresourceUpdateFromImage(ImageHelper * image,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Extents & glExtents,const VkImageType imageType)3068 void ImageHelper::stageSubresourceUpdateFromImage(ImageHelper *image,
3069                                                   const gl::ImageIndex &index,
3070                                                   const gl::Offset &destOffset,
3071                                                   const gl::Extents &glExtents,
3072                                                   const VkImageType imageType)
3073 {
3074     VkImageCopy copyToImage               = {};
3075     copyToImage.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3076     copyToImage.srcSubresource.layerCount = index.getLayerCount();
3077     copyToImage.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
3078     copyToImage.dstSubresource.mipLevel   = index.getLevelIndex();
3079 
3080     if (imageType == VK_IMAGE_TYPE_3D)
3081     {
3082         // These values must be set explicitly to follow the Vulkan spec:
3083         // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkImageCopy.html
3084         // If either of the calling command’s srcImage or dstImage parameters are of VkImageType
3085         // VK_IMAGE_TYPE_3D, the baseArrayLayer and layerCount members of the corresponding
3086         // subresource must be 0 and 1, respectively
3087         copyToImage.dstSubresource.baseArrayLayer = 0;
3088         copyToImage.dstSubresource.layerCount     = 1;
3089         // Preserve the assumption that destOffset.z == "dstSubresource.baseArrayLayer"
3090         ASSERT(destOffset.z == (index.hasLayer() ? index.getLayerIndex() : 0));
3091     }
3092     else
3093     {
3094         copyToImage.dstSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
3095         copyToImage.dstSubresource.layerCount     = index.getLayerCount();
3096     }
3097 
3098     gl_vk::GetOffset(destOffset, &copyToImage.dstOffset);
3099     gl_vk::GetExtent(glExtents, &copyToImage.extent);
3100 
3101     appendSubresourceUpdate(SubresourceUpdate(image, copyToImage));
3102 }
3103 
stageSubresourceClear(const gl::ImageIndex & index)3104 void ImageHelper::stageSubresourceClear(const gl::ImageIndex &index)
3105 {
3106     const VkImageAspectFlags aspectFlags = getAspectFlags();
3107 
3108     ASSERT(mFormat);
3109     VkClearValue clearValue = GetClearValue(*mFormat);
3110     appendSubresourceUpdate(SubresourceUpdate(aspectFlags, clearValue, index));
3111 }
3112 
stageRobustResourceClear(const gl::ImageIndex & index,const vk::Format & format)3113 void ImageHelper::stageRobustResourceClear(const gl::ImageIndex &index, const vk::Format &format)
3114 {
3115     const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(format.actualImageFormat());
3116 
3117     // Robust clears must only be staged if we do not have any prior data for this subresource.
3118     ASSERT(!isUpdateStaged(index.getLevelIndex(), index.getLayerIndex()));
3119     VkClearValue clearValue = GetClearValue(format);
3120     appendSubresourceUpdate(SubresourceUpdate(aspectFlags, clearValue, index));
3121 }
3122 
stageClearIfEmulatedFormat(Context * context)3123 void ImageHelper::stageClearIfEmulatedFormat(Context *context)
3124 {
3125     // Skip staging extra clears if robust resource init is enabled.
3126     if (!mFormat->hasEmulatedImageChannels() || context->isRobustResourceInitEnabled())
3127         return;
3128 
3129     VkClearValue clearValue;
3130     if (mFormat->intendedFormat().hasDepthOrStencilBits())
3131     {
3132         clearValue.depthStencil = kRobustInitDepthStencilValue;
3133     }
3134     else
3135     {
3136         clearValue.color = kEmulatedInitColorValue;
3137     }
3138 
3139     const VkImageAspectFlags aspectFlags = getAspectFlags();
3140 
3141     // If the image has an emulated channel and robust resource init is not enabled, always clear
3142     // it. These channels will be masked out in future writes, and shouldn't contain uninitialized
3143     // values.
3144     for (uint32_t level = 0; level < mLevelCount; ++level)
3145     {
3146         gl::ImageIndex index = gl::ImageIndex::Make2DArrayRange(level, 0, mLayerCount);
3147         prependSubresourceUpdate(SubresourceUpdate(aspectFlags, clearValue, index));
3148     }
3149 }
3150 
allocateStagingMemory(ContextVk * contextVk,size_t sizeInBytes,uint8_t ** ptrOut,BufferHelper ** bufferOut,StagingBufferOffsetArray * offsetOut,bool * newBufferAllocatedOut)3151 angle::Result ImageHelper::allocateStagingMemory(ContextVk *contextVk,
3152                                                  size_t sizeInBytes,
3153                                                  uint8_t **ptrOut,
3154                                                  BufferHelper **bufferOut,
3155                                                  StagingBufferOffsetArray *offsetOut,
3156                                                  bool *newBufferAllocatedOut)
3157 {
3158     VkBuffer handle;
3159     ANGLE_TRY(mStagingBuffer.allocate(contextVk, sizeInBytes, ptrOut, &handle, &(*offsetOut)[0],
3160                                       newBufferAllocatedOut));
3161     *bufferOut = mStagingBuffer.getCurrentBuffer();
3162     return angle::Result::Continue;
3163 }
3164 
flushStagedUpdates(ContextVk * contextVk,uint32_t levelStart,uint32_t levelEnd,uint32_t layerStart,uint32_t layerEnd,CommandBuffer * commandBuffer)3165 angle::Result ImageHelper::flushStagedUpdates(ContextVk *contextVk,
3166                                               uint32_t levelStart,
3167                                               uint32_t levelEnd,
3168                                               uint32_t layerStart,
3169                                               uint32_t layerEnd,
3170                                               CommandBuffer *commandBuffer)
3171 {
3172     if (mSubresourceUpdates.empty())
3173     {
3174         return angle::Result::Continue;
3175     }
3176 
3177     ANGLE_TRY(mStagingBuffer.flush(contextVk));
3178 
3179     std::vector<SubresourceUpdate> updatesToKeep;
3180     const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(mFormat->actualImageFormat());
3181 
3182     // Upload levels and layers that don't conflict in parallel.  The (level, layer) pair is hashed
3183     // to `(level * mLayerCount + layer) % 64` and used to track whether that subresource is
3184     // currently in transfer.  If so, a barrier is inserted.  If mLayerCount * mLevelCount > 64,
3185     // there will be a few unnecessary barriers.
3186     constexpr uint32_t kMaxParallelSubresourceUpload = 64;
3187     uint64_t subresourceUploadsInProgress            = 0;
3188 
3189     // Start in TransferDst.
3190     ANGLE_TRY(contextVk->onImageWrite(aspectFlags, ImageLayout::TransferDst, this));
3191 
3192     for (SubresourceUpdate &update : mSubresourceUpdates)
3193     {
3194         ASSERT(update.updateSource == UpdateSource::Clear ||
3195                (update.updateSource == UpdateSource::Buffer &&
3196                 update.buffer.bufferHelper != nullptr) ||
3197                (update.updateSource == UpdateSource::Image && update.image.image != nullptr &&
3198                 update.image.image->valid()));
3199 
3200         uint32_t updateMipLevel;
3201         uint32_t updateBaseLayer;
3202         uint32_t updateLayerCount;
3203         if (update.updateSource == UpdateSource::Clear)
3204         {
3205             updateMipLevel   = update.clear.levelIndex;
3206             updateBaseLayer  = update.clear.layerIndex;
3207             updateLayerCount = update.clear.layerCount;
3208             if (updateLayerCount == static_cast<uint32_t>(gl::ImageIndex::kEntireLevel))
3209             {
3210                 updateLayerCount = mLayerCount;
3211             }
3212         }
3213         else
3214         {
3215             const VkImageSubresourceLayers &dstSubresource = update.dstSubresource();
3216             updateMipLevel                                 = dstSubresource.mipLevel;
3217             updateBaseLayer                                = dstSubresource.baseArrayLayer;
3218             updateLayerCount                               = dstSubresource.layerCount;
3219             ASSERT(updateLayerCount != static_cast<uint32_t>(gl::ImageIndex::kEntireLevel));
3220         }
3221 
3222         // If the update level is not within the requested range, skip the update.
3223         const bool isUpdateLevelOutsideRange =
3224             updateMipLevel < (levelStart + mBaseLevel) ||
3225             (updateMipLevel >= (levelEnd + mBaseLevel) || updateMipLevel > mMaxLevel);
3226 
3227         // If the update layers don't intersect the requested layers, skip the update.
3228         const bool areUpdateLayersOutsideRange =
3229             updateBaseLayer + updateLayerCount <= layerStart || updateBaseLayer >= layerEnd;
3230 
3231         if (isUpdateLevelOutsideRange || areUpdateLayersOutsideRange)
3232         {
3233             updatesToKeep.emplace_back(update);
3234             continue;
3235         }
3236 
3237         if (mBaseLevel > 0)
3238         {
3239             // We need to shift the miplevel in the update to fall into the vkiamge
3240             if (update.updateSource == UpdateSource::Clear)
3241             {
3242                 update.clear.levelIndex -= mBaseLevel;
3243             }
3244             else if (update.updateSource == UpdateSource::Buffer)
3245             {
3246                 update.buffer.copyRegion.imageSubresource.mipLevel -= mBaseLevel;
3247             }
3248             else if (update.updateSource == UpdateSource::Image)
3249             {
3250                 update.image.copyRegion.dstSubresource.mipLevel -= mBaseLevel;
3251             }
3252         }
3253 
3254         if (updateLayerCount >= kMaxParallelSubresourceUpload)
3255         {
3256             // If there are more subresources than bits we can track, always insert a barrier.
3257             changeLayout(aspectFlags, ImageLayout::TransferDst, commandBuffer);
3258             subresourceUploadsInProgress = std::numeric_limits<uint64_t>::max();
3259         }
3260         else
3261         {
3262             const uint64_t subresourceHashRange = angle::Bit<uint64_t>(updateLayerCount) - 1;
3263             const uint32_t subresourceHashOffset =
3264                 (updateMipLevel * mLayerCount + updateBaseLayer) % kMaxParallelSubresourceUpload;
3265             const uint64_t subresourceHash =
3266                 ANGLE_ROTL64(subresourceHashRange, subresourceHashOffset);
3267 
3268             if ((subresourceUploadsInProgress & subresourceHash) != 0)
3269             {
3270                 // If there's overlap in subresource upload, issue a barrier.
3271                 changeLayout(aspectFlags, ImageLayout::TransferDst, commandBuffer);
3272                 subresourceUploadsInProgress = 0;
3273             }
3274             subresourceUploadsInProgress |= subresourceHash;
3275         }
3276 
3277         if (update.updateSource == UpdateSource::Clear)
3278         {
3279             clear(update.clear.aspectFlags, update.clear.value, updateMipLevel, updateBaseLayer,
3280                   updateLayerCount, commandBuffer);
3281         }
3282         else if (update.updateSource == UpdateSource::Buffer)
3283         {
3284             BufferUpdate &bufferUpdate = update.buffer;
3285 
3286             BufferHelper *currentBuffer = bufferUpdate.bufferHelper;
3287             ASSERT(currentBuffer && currentBuffer->valid());
3288 
3289             ANGLE_TRY(contextVk->onBufferRead(VK_ACCESS_TRANSFER_READ_BIT, currentBuffer));
3290 
3291             commandBuffer->copyBufferToImage(currentBuffer->getBuffer().getHandle(), mImage,
3292                                              getCurrentLayout(), 1, &update.buffer.copyRegion);
3293         }
3294         else
3295         {
3296             ANGLE_TRY(
3297                 contextVk->onImageRead(aspectFlags, ImageLayout::TransferSrc, update.image.image));
3298 
3299             commandBuffer->copyImage(update.image.image->getImage(),
3300                                      update.image.image->getCurrentLayout(), mImage,
3301                                      getCurrentLayout(), 1, &update.image.copyRegion);
3302         }
3303 
3304         update.release(contextVk->getRenderer());
3305     }
3306 
3307     // Only remove the updates that were actually applied to the image.
3308     mSubresourceUpdates = std::move(updatesToKeep);
3309 
3310     if (mSubresourceUpdates.empty())
3311     {
3312         mStagingBuffer.releaseInFlightBuffers(contextVk);
3313     }
3314 
3315     return angle::Result::Continue;
3316 }
3317 
flushAllStagedUpdates(ContextVk * contextVk)3318 angle::Result ImageHelper::flushAllStagedUpdates(ContextVk *contextVk)
3319 {
3320     // Clear the image.
3321     CommandBuffer *commandBuffer = nullptr;
3322     ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
3323     return flushStagedUpdates(contextVk, 0, mLevelCount, 0, mLayerCount, commandBuffer);
3324 }
3325 
isUpdateStaged(uint32_t level,uint32_t layer)3326 bool ImageHelper::isUpdateStaged(uint32_t level, uint32_t layer)
3327 {
3328     // Check to see if any updates are staged for the given level and layer
3329 
3330     if (mSubresourceUpdates.empty())
3331     {
3332         return false;
3333     }
3334 
3335     for (SubresourceUpdate &update : mSubresourceUpdates)
3336     {
3337         uint32_t updateMipLevel;
3338         uint32_t updateBaseLayer;
3339         uint32_t updateLayerCount;
3340 
3341         if (update.updateSource == UpdateSource::Clear)
3342         {
3343             updateMipLevel   = update.clear.levelIndex;
3344             updateBaseLayer  = update.clear.layerIndex;
3345             updateLayerCount = update.clear.layerCount;
3346         }
3347         else
3348         {
3349             const VkImageSubresourceLayers &dstSubresource = update.dstSubresource();
3350             updateMipLevel                                 = dstSubresource.mipLevel;
3351             updateBaseLayer                                = dstSubresource.baseArrayLayer;
3352             updateLayerCount                               = dstSubresource.layerCount;
3353         }
3354 
3355         if (updateMipLevel == level)
3356         {
3357             if (layer >= updateBaseLayer && layer < (updateBaseLayer + updateLayerCount))
3358             {
3359                 // The level matches, and the layer is within the range
3360                 return true;
3361             }
3362         }
3363     }
3364 
3365     return false;
3366 }
3367 
copyImageDataToBuffer(ContextVk * contextVk,size_t sourceLevel,uint32_t layerCount,uint32_t baseLayer,const gl::Box & sourceArea,BufferHelper ** bufferOut,size_t * bufferSize,StagingBufferOffsetArray * bufferOffsetsOut,uint8_t ** outDataPtr)3368 angle::Result ImageHelper::copyImageDataToBuffer(ContextVk *contextVk,
3369                                                  size_t sourceLevel,
3370                                                  uint32_t layerCount,
3371                                                  uint32_t baseLayer,
3372                                                  const gl::Box &sourceArea,
3373                                                  BufferHelper **bufferOut,
3374                                                  size_t *bufferSize,
3375                                                  StagingBufferOffsetArray *bufferOffsetsOut,
3376                                                  uint8_t **outDataPtr)
3377 {
3378     ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::copyImageDataToBuffer");
3379 
3380     const angle::Format &imageFormat = mFormat->actualImageFormat();
3381 
3382     // Two VK formats (one depth-only, one combined depth/stencil) use an extra byte for depth.
3383     // From https://www.khronos.org/registry/vulkan/specs/1.1/html/vkspec.html#VkBufferImageCopy:
3384     //  data copied to or from the depth aspect of a VK_FORMAT_X8_D24_UNORM_PACK32 or
3385     //  VK_FORMAT_D24_UNORM_S8_UINT format is packed with one 32-bit word per texel...
3386     // So make sure if we hit the depth/stencil format that we have 5 bytes per pixel (4 for depth
3387     //  data, 1 for stencil). NOTE that depth-only VK_FORMAT_X8_D24_UNORM_PACK32 already has 4 bytes
3388     //  per pixel which is sufficient to contain its depth aspect (no stencil aspect).
3389     uint32_t pixelBytes         = imageFormat.pixelBytes;
3390     uint32_t depthBytesPerPixel = imageFormat.depthBits >> 3;
3391     if (mFormat->vkImageFormat == VK_FORMAT_D24_UNORM_S8_UINT)
3392     {
3393         pixelBytes         = 5;
3394         depthBytesPerPixel = 4;
3395     }
3396 
3397     *bufferSize = sourceArea.width * sourceArea.height * sourceArea.depth * pixelBytes * layerCount;
3398 
3399     const VkImageAspectFlags aspectFlags = getAspectFlags();
3400 
3401     // Allocate staging buffer data
3402     ANGLE_TRY(allocateStagingMemory(contextVk, *bufferSize, outDataPtr, bufferOut, bufferOffsetsOut,
3403                                     nullptr));
3404 
3405     CommandBuffer *commandBuffer = nullptr;
3406     ANGLE_TRY(contextVk->onImageRead(aspectFlags, ImageLayout::TransferSrc, this));
3407     ANGLE_TRY(contextVk->onBufferWrite(VK_ACCESS_TRANSFER_WRITE_BIT, *bufferOut));
3408     ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
3409 
3410     VkBufferImageCopy regions[2] = {};
3411     // Default to non-combined DS case
3412     regions[0].bufferOffset                    = (*bufferOffsetsOut)[0];
3413     regions[0].bufferRowLength                 = 0;
3414     regions[0].bufferImageHeight               = 0;
3415     regions[0].imageExtent.width               = sourceArea.width;
3416     regions[0].imageExtent.height              = sourceArea.height;
3417     regions[0].imageExtent.depth               = sourceArea.depth;
3418     regions[0].imageOffset.x                   = sourceArea.x;
3419     regions[0].imageOffset.y                   = sourceArea.y;
3420     regions[0].imageOffset.z                   = sourceArea.z;
3421     regions[0].imageSubresource.aspectMask     = aspectFlags;
3422     regions[0].imageSubresource.baseArrayLayer = baseLayer;
3423     regions[0].imageSubresource.layerCount     = layerCount;
3424     regions[0].imageSubresource.mipLevel       = static_cast<uint32_t>(sourceLevel);
3425 
3426     if (isCombinedDepthStencilFormat())
3427     {
3428         // For combined DS image we'll copy depth and stencil aspects separately
3429         // Depth aspect comes first in buffer and can use most settings from above
3430         regions[0].imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
3431 
3432         // Get depth data size since stencil data immediately follows depth data in buffer
3433         const VkDeviceSize depthSize = depthBytesPerPixel * sourceArea.width * sourceArea.height *
3434                                        sourceArea.depth * layerCount;
3435 
3436         // Double-check that we allocated enough buffer space (always 1 byte per stencil)
3437         ASSERT(*bufferSize >= (depthSize + (sourceArea.width * sourceArea.height *
3438                                             sourceArea.depth * layerCount)));
3439 
3440         // Copy stencil data into buffer immediately following the depth data
3441         const VkDeviceSize stencilOffset           = (*bufferOffsetsOut)[0] + depthSize;
3442         (*bufferOffsetsOut)[1]                     = stencilOffset;
3443         regions[1].bufferOffset                    = stencilOffset;
3444         regions[1].bufferRowLength                 = 0;
3445         regions[1].bufferImageHeight               = 0;
3446         regions[1].imageExtent.width               = sourceArea.width;
3447         regions[1].imageExtent.height              = sourceArea.height;
3448         regions[1].imageExtent.depth               = sourceArea.depth;
3449         regions[1].imageOffset.x                   = sourceArea.x;
3450         regions[1].imageOffset.y                   = sourceArea.y;
3451         regions[1].imageOffset.z                   = sourceArea.z;
3452         regions[1].imageSubresource.aspectMask     = VK_IMAGE_ASPECT_STENCIL_BIT;
3453         regions[1].imageSubresource.baseArrayLayer = baseLayer;
3454         regions[1].imageSubresource.layerCount     = layerCount;
3455         regions[1].imageSubresource.mipLevel       = static_cast<uint32_t>(sourceLevel);
3456         commandBuffer->copyImageToBuffer(mImage, getCurrentLayout(),
3457                                          (*bufferOut)->getBuffer().getHandle(), 1, &regions[1]);
3458     }
3459 
3460     commandBuffer->copyImageToBuffer(mImage, getCurrentLayout(),
3461                                      (*bufferOut)->getBuffer().getHandle(), 1, regions);
3462 
3463     return angle::Result::Continue;
3464 }
3465 
3466 // static
GetReadPixelsParams(ContextVk * contextVk,const gl::PixelPackState & packState,gl::Buffer * packBuffer,GLenum format,GLenum type,const gl::Rectangle & area,const gl::Rectangle & clippedArea,PackPixelsParams * paramsOut,GLuint * skipBytesOut)3467 angle::Result ImageHelper::GetReadPixelsParams(ContextVk *contextVk,
3468                                                const gl::PixelPackState &packState,
3469                                                gl::Buffer *packBuffer,
3470                                                GLenum format,
3471                                                GLenum type,
3472                                                const gl::Rectangle &area,
3473                                                const gl::Rectangle &clippedArea,
3474                                                PackPixelsParams *paramsOut,
3475                                                GLuint *skipBytesOut)
3476 {
3477     const gl::InternalFormat &sizedFormatInfo = gl::GetInternalFormatInfo(format, type);
3478 
3479     GLuint outputPitch = 0;
3480     ANGLE_VK_CHECK_MATH(contextVk,
3481                         sizedFormatInfo.computeRowPitch(type, area.width, packState.alignment,
3482                                                         packState.rowLength, &outputPitch));
3483     ANGLE_VK_CHECK_MATH(contextVk, sizedFormatInfo.computeSkipBytes(type, outputPitch, 0, packState,
3484                                                                     false, skipBytesOut));
3485 
3486     *skipBytesOut += (clippedArea.x - area.x) * sizedFormatInfo.pixelBytes +
3487                      (clippedArea.y - area.y) * outputPitch;
3488 
3489     const angle::Format &angleFormat = GetFormatFromFormatType(format, type);
3490 
3491     *paramsOut = PackPixelsParams(clippedArea, angleFormat, outputPitch, packState.reverseRowOrder,
3492                                   packBuffer, 0);
3493     return angle::Result::Continue;
3494 }
3495 
readPixelsForGetImage(ContextVk * contextVk,const gl::PixelPackState & packState,gl::Buffer * packBuffer,uint32_t level,uint32_t layer,GLenum format,GLenum type,void * pixels)3496 angle::Result ImageHelper::readPixelsForGetImage(ContextVk *contextVk,
3497                                                  const gl::PixelPackState &packState,
3498                                                  gl::Buffer *packBuffer,
3499                                                  uint32_t level,
3500                                                  uint32_t layer,
3501                                                  GLenum format,
3502                                                  GLenum type,
3503                                                  void *pixels)
3504 {
3505     const angle::Format &angleFormat = GetFormatFromFormatType(format, type);
3506 
3507     VkImageAspectFlagBits aspectFlags = {};
3508     if (angleFormat.redBits > 0 || angleFormat.blueBits > 0 || angleFormat.greenBits > 0 ||
3509         angleFormat.alphaBits > 0)
3510     {
3511         aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT;
3512     }
3513     else
3514     {
3515         if (angleFormat.depthBits > 0)
3516         {
3517             aspectFlags = VK_IMAGE_ASPECT_DEPTH_BIT;
3518         }
3519         if (angleFormat.stencilBits > 0)
3520         {
3521             ASSERT(angleFormat.depthBits == 0);
3522             aspectFlags = VK_IMAGE_ASPECT_STENCIL_BIT;
3523         }
3524     }
3525 
3526     ASSERT(aspectFlags != 0);
3527 
3528     PackPixelsParams params;
3529     GLuint outputSkipBytes = 0;
3530 
3531     uint32_t width  = std::max(1u, mExtents.width >> level);
3532     uint32_t height = std::max(1u, mExtents.height >> level);
3533     uint32_t depth  = std::max(1u, mExtents.depth >> level);
3534     gl::Rectangle area(0, 0, width, height);
3535 
3536     ANGLE_TRY(GetReadPixelsParams(contextVk, packState, packBuffer, format, type, area, area,
3537                                   &params, &outputSkipBytes));
3538 
3539     // Use a temporary staging buffer. Could be optimized.
3540     vk::RendererScoped<vk::DynamicBuffer> stagingBuffer(contextVk->getRenderer());
3541     stagingBuffer.get().init(contextVk->getRenderer(), VK_BUFFER_USAGE_TRANSFER_DST_BIT, 1,
3542                              kStagingBufferSize, true);
3543 
3544     if (mExtents.depth > 1)
3545     {
3546         // Depth > 1 means this is a 3D texture and we need to copy all layers
3547         for (layer = 0; layer < depth; layer++)
3548         {
3549             ANGLE_TRY(readPixels(contextVk, area, params, aspectFlags, level, layer,
3550                                  static_cast<uint8_t *>(pixels) + outputSkipBytes,
3551                                  &stagingBuffer.get()));
3552 
3553             outputSkipBytes += width * height * gl::GetInternalFormatInfo(format, type).pixelBytes;
3554         }
3555     }
3556     else
3557     {
3558         ANGLE_TRY(readPixels(contextVk, area, params, aspectFlags, level, layer,
3559                              static_cast<uint8_t *>(pixels) + outputSkipBytes,
3560                              &stagingBuffer.get()));
3561     }
3562 
3563     return angle::Result::Continue;
3564 }
3565 
readPixels(ContextVk * contextVk,const gl::Rectangle & area,const PackPixelsParams & packPixelsParams,VkImageAspectFlagBits copyAspectFlags,uint32_t level,uint32_t layer,void * pixels,DynamicBuffer * stagingBuffer)3566 angle::Result ImageHelper::readPixels(ContextVk *contextVk,
3567                                       const gl::Rectangle &area,
3568                                       const PackPixelsParams &packPixelsParams,
3569                                       VkImageAspectFlagBits copyAspectFlags,
3570                                       uint32_t level,
3571                                       uint32_t layer,
3572                                       void *pixels,
3573                                       DynamicBuffer *stagingBuffer)
3574 {
3575     ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::readPixels");
3576 
3577     RendererVk *renderer = contextVk->getRenderer();
3578 
3579     // If the source image is multisampled, we need to resolve it into a temporary image before
3580     // performing a readback.
3581     bool isMultisampled = mSamples > 1;
3582     RendererScoped<ImageHelper> resolvedImage(contextVk->getRenderer());
3583 
3584     ImageHelper *src = this;
3585 
3586     if (isMultisampled)
3587     {
3588         ANGLE_TRY(resolvedImage.get().init2DStaging(
3589             contextVk, renderer->getMemoryProperties(), gl::Extents(area.width, area.height, 1),
3590             *mFormat, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, 1));
3591         resolvedImage.get().retain(&contextVk->getResourceUseList());
3592     }
3593 
3594     VkImageAspectFlags layoutChangeAspectFlags = src->getAspectFlags();
3595 
3596     // Note that although we're reading from the image, we need to update the layout below.
3597     CommandBuffer *commandBuffer;
3598     if (isMultisampled)
3599     {
3600         ANGLE_TRY(contextVk->onImageWrite(layoutChangeAspectFlags, ImageLayout::TransferDst,
3601                                           &resolvedImage.get()));
3602     }
3603     ANGLE_TRY(contextVk->onImageRead(layoutChangeAspectFlags, ImageLayout::TransferSrc, this));
3604     ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
3605 
3606     const angle::Format *readFormat = &mFormat->actualImageFormat();
3607 
3608     if (copyAspectFlags != VK_IMAGE_ASPECT_COLOR_BIT)
3609     {
3610         readFormat = &GetDepthStencilImageToBufferFormat(*readFormat, copyAspectFlags);
3611     }
3612 
3613     VkOffset3D srcOffset = {area.x, area.y, 0};
3614 
3615     VkImageSubresourceLayers srcSubresource = {};
3616     srcSubresource.aspectMask               = copyAspectFlags;
3617     srcSubresource.mipLevel                 = level;
3618     srcSubresource.baseArrayLayer           = layer;
3619     srcSubresource.layerCount               = 1;
3620 
3621     VkExtent3D srcExtent = {static_cast<uint32_t>(area.width), static_cast<uint32_t>(area.height),
3622                             1};
3623 
3624     if (mExtents.depth > 1)
3625     {
3626         // Depth > 1 means this is a 3D texture and we need special handling
3627         srcOffset.z                   = layer;
3628         srcSubresource.baseArrayLayer = 0;
3629     }
3630 
3631     if (isMultisampled)
3632     {
3633         // Note: resolve only works on color images (not depth/stencil).
3634         //
3635         // TODO: Currently, depth/stencil blit can perform a depth/stencil readback, but that code
3636         // path will be optimized away.  http://anglebug.com/3200
3637         ASSERT(copyAspectFlags == VK_IMAGE_ASPECT_COLOR_BIT);
3638 
3639         VkImageResolve resolveRegion                = {};
3640         resolveRegion.srcSubresource                = srcSubresource;
3641         resolveRegion.srcOffset                     = srcOffset;
3642         resolveRegion.dstSubresource.aspectMask     = copyAspectFlags;
3643         resolveRegion.dstSubresource.mipLevel       = 0;
3644         resolveRegion.dstSubresource.baseArrayLayer = 0;
3645         resolveRegion.dstSubresource.layerCount     = 1;
3646         resolveRegion.dstOffset                     = {};
3647         resolveRegion.extent                        = srcExtent;
3648 
3649         resolve(&resolvedImage.get(), resolveRegion, commandBuffer);
3650 
3651         ANGLE_TRY(contextVk->onImageRead(layoutChangeAspectFlags, ImageLayout::TransferSrc,
3652                                          &resolvedImage.get()));
3653 
3654         // Make the resolved image the target of buffer copy.
3655         src                           = &resolvedImage.get();
3656         level                         = 0;
3657         layer                         = 0;
3658         srcOffset                     = {0, 0, 0};
3659         srcSubresource.baseArrayLayer = 0;
3660         srcSubresource.layerCount     = 1;
3661         srcSubresource.mipLevel       = 0;
3662     }
3663 
3664     VkBuffer bufferHandle      = VK_NULL_HANDLE;
3665     uint8_t *readPixelBuffer   = nullptr;
3666     VkDeviceSize stagingOffset = 0;
3667     size_t allocationSize      = readFormat->pixelBytes * area.width * area.height;
3668 
3669     ANGLE_TRY(stagingBuffer->allocate(contextVk, allocationSize, &readPixelBuffer, &bufferHandle,
3670                                       &stagingOffset, nullptr));
3671 
3672     VkBufferImageCopy region = {};
3673     region.bufferImageHeight = srcExtent.height;
3674     region.bufferOffset      = stagingOffset;
3675     region.bufferRowLength   = srcExtent.width;
3676     region.imageExtent       = srcExtent;
3677     region.imageOffset       = srcOffset;
3678     region.imageSubresource  = srcSubresource;
3679 
3680     commandBuffer->copyImageToBuffer(src->getImage(), src->getCurrentLayout(), bufferHandle, 1,
3681                                      &region);
3682 
3683     // Triggers a full finish.
3684     // TODO(jmadill): Don't block on asynchronous readback.
3685     ANGLE_TRY(contextVk->finishImpl());
3686 
3687     // The buffer we copied to needs to be invalidated before we read from it because its not been
3688     // created with the host coherent bit.
3689     ANGLE_TRY(stagingBuffer->invalidate(contextVk));
3690 
3691     if (packPixelsParams.packBuffer)
3692     {
3693         // Must map the PBO in order to read its contents (and then unmap it later)
3694         BufferVk *packBufferVk = GetImpl(packPixelsParams.packBuffer);
3695         void *mapPtr           = nullptr;
3696         ANGLE_TRY(packBufferVk->mapImpl(contextVk, &mapPtr));
3697         uint8_t *dest = static_cast<uint8_t *>(mapPtr) + reinterpret_cast<ptrdiff_t>(pixels);
3698         PackPixels(packPixelsParams, *readFormat, area.width * readFormat->pixelBytes,
3699                    readPixelBuffer, static_cast<uint8_t *>(dest));
3700         ANGLE_TRY(packBufferVk->unmapImpl(contextVk));
3701     }
3702     else
3703     {
3704         PackPixels(packPixelsParams, *readFormat, area.width * readFormat->pixelBytes,
3705                    readPixelBuffer, static_cast<uint8_t *>(pixels));
3706     }
3707 
3708     return angle::Result::Continue;
3709 }
3710 
3711 // ImageHelper::SubresourceUpdate implementation
SubresourceUpdate()3712 ImageHelper::SubresourceUpdate::SubresourceUpdate() : updateSource(UpdateSource::Buffer), buffer{}
3713 {}
3714 
SubresourceUpdate(BufferHelper * bufferHelperIn,const VkBufferImageCopy & copyRegionIn)3715 ImageHelper::SubresourceUpdate::SubresourceUpdate(BufferHelper *bufferHelperIn,
3716                                                   const VkBufferImageCopy &copyRegionIn)
3717     : updateSource(UpdateSource::Buffer), buffer{bufferHelperIn, copyRegionIn}
3718 {}
3719 
SubresourceUpdate(ImageHelper * imageIn,const VkImageCopy & copyRegionIn)3720 ImageHelper::SubresourceUpdate::SubresourceUpdate(ImageHelper *imageIn,
3721                                                   const VkImageCopy &copyRegionIn)
3722     : updateSource(UpdateSource::Image), image{imageIn, copyRegionIn}
3723 {}
3724 
SubresourceUpdate(VkImageAspectFlags aspectFlags,const VkClearValue & clearValue,const gl::ImageIndex & imageIndex)3725 ImageHelper::SubresourceUpdate::SubresourceUpdate(VkImageAspectFlags aspectFlags,
3726                                                   const VkClearValue &clearValue,
3727                                                   const gl::ImageIndex &imageIndex)
3728     : updateSource(UpdateSource::Clear)
3729 {
3730     clear.aspectFlags = aspectFlags;
3731     clear.value       = clearValue;
3732     clear.levelIndex  = imageIndex.getLevelIndex();
3733     clear.layerIndex  = imageIndex.hasLayer() ? imageIndex.getLayerIndex() : 0;
3734     clear.layerCount  = imageIndex.getLayerCount();
3735 }
3736 
SubresourceUpdate(const SubresourceUpdate & other)3737 ImageHelper::SubresourceUpdate::SubresourceUpdate(const SubresourceUpdate &other)
3738     : updateSource(other.updateSource)
3739 {
3740     if (updateSource == UpdateSource::Clear)
3741     {
3742         clear = other.clear;
3743     }
3744     else if (updateSource == UpdateSource::Buffer)
3745     {
3746         buffer = other.buffer;
3747     }
3748     else
3749     {
3750         image = other.image;
3751     }
3752 }
3753 
release(RendererVk * renderer)3754 void ImageHelper::SubresourceUpdate::release(RendererVk *renderer)
3755 {
3756     if (updateSource == UpdateSource::Image)
3757     {
3758         image.image->releaseImage(renderer);
3759         image.image->releaseStagingBuffer(renderer);
3760         SafeDelete(image.image);
3761     }
3762 }
3763 
isUpdateToLayerLevel(uint32_t layerIndex,uint32_t levelIndex) const3764 bool ImageHelper::SubresourceUpdate::isUpdateToLayerLevel(uint32_t layerIndex,
3765                                                           uint32_t levelIndex) const
3766 {
3767     if (updateSource == UpdateSource::Clear)
3768     {
3769         return clear.levelIndex == levelIndex && clear.layerIndex == layerIndex;
3770     }
3771 
3772     const VkImageSubresourceLayers &dst = dstSubresource();
3773     return dst.baseArrayLayer == layerIndex && dst.mipLevel == levelIndex;
3774 }
3775 
appendSubresourceUpdate(SubresourceUpdate && update)3776 void ImageHelper::appendSubresourceUpdate(SubresourceUpdate &&update)
3777 {
3778     mSubresourceUpdates.emplace_back(std::move(update));
3779     onStateChange(angle::SubjectMessage::SubjectChanged);
3780 }
3781 
prependSubresourceUpdate(SubresourceUpdate && update)3782 void ImageHelper::prependSubresourceUpdate(SubresourceUpdate &&update)
3783 {
3784     mSubresourceUpdates.insert(mSubresourceUpdates.begin(), std::move(update));
3785     onStateChange(angle::SubjectMessage::SubjectChanged);
3786 }
3787 
3788 // FramebufferHelper implementation.
3789 FramebufferHelper::FramebufferHelper() = default;
3790 
3791 FramebufferHelper::~FramebufferHelper() = default;
3792 
FramebufferHelper(FramebufferHelper && other)3793 FramebufferHelper::FramebufferHelper(FramebufferHelper &&other)
3794 {
3795     mFramebuffer = std::move(other.mFramebuffer);
3796 }
3797 
operator =(FramebufferHelper && other)3798 FramebufferHelper &FramebufferHelper::operator=(FramebufferHelper &&other)
3799 {
3800     std::swap(mFramebuffer, other.mFramebuffer);
3801     return *this;
3802 }
3803 
init(ContextVk * contextVk,const VkFramebufferCreateInfo & createInfo)3804 angle::Result FramebufferHelper::init(ContextVk *contextVk,
3805                                       const VkFramebufferCreateInfo &createInfo)
3806 {
3807     ANGLE_VK_TRY(contextVk, mFramebuffer.init(contextVk->getDevice(), createInfo));
3808     return angle::Result::Continue;
3809 }
3810 
release(ContextVk * contextVk)3811 void FramebufferHelper::release(ContextVk *contextVk)
3812 {
3813     contextVk->addGarbage(&mFramebuffer);
3814 }
3815 
3816 // ImageViewHelper implementation.
ImageViewHelper()3817 ImageViewHelper::ImageViewHelper()
3818 {
3819     mUse.init();
3820 }
3821 
ImageViewHelper(ImageViewHelper && other)3822 ImageViewHelper::ImageViewHelper(ImageViewHelper &&other)
3823 {
3824     std::swap(mReadImageView, other.mReadImageView);
3825     std::swap(mFetchImageView, other.mFetchImageView);
3826     std::swap(mStencilReadImageView, other.mStencilReadImageView);
3827     std::swap(mLevelDrawImageViews, other.mLevelDrawImageViews);
3828     std::swap(mLayerLevelDrawImageViews, other.mLayerLevelDrawImageViews);
3829 }
3830 
~ImageViewHelper()3831 ImageViewHelper::~ImageViewHelper()
3832 {
3833     mUse.release();
3834 }
3835 
release(RendererVk * renderer)3836 void ImageViewHelper::release(RendererVk *renderer)
3837 {
3838     std::vector<GarbageObject> garbage;
3839 
3840     if (mReadImageView.valid())
3841     {
3842         garbage.emplace_back(GetGarbage(&mReadImageView));
3843     }
3844     if (mFetchImageView.valid())
3845     {
3846         garbage.emplace_back(GetGarbage(&mFetchImageView));
3847     }
3848     if (mStencilReadImageView.valid())
3849     {
3850         garbage.emplace_back(GetGarbage(&mStencilReadImageView));
3851     }
3852 
3853     for (ImageView &imageView : mLevelDrawImageViews)
3854     {
3855         if (imageView.valid())
3856         {
3857             garbage.emplace_back(GetGarbage(&imageView));
3858         }
3859     }
3860     mLevelDrawImageViews.clear();
3861 
3862     for (ImageViewVector &layerViews : mLayerLevelDrawImageViews)
3863     {
3864         for (ImageView &imageView : layerViews)
3865         {
3866             if (imageView.valid())
3867             {
3868                 garbage.emplace_back(GetGarbage(&imageView));
3869             }
3870         }
3871     }
3872     mLayerLevelDrawImageViews.clear();
3873 
3874     if (!garbage.empty())
3875     {
3876         renderer->collectGarbage(std::move(mUse), std::move(garbage));
3877 
3878         // Ensure the resource use is always valid.
3879         mUse.init();
3880     }
3881 }
3882 
destroy(VkDevice device)3883 void ImageViewHelper::destroy(VkDevice device)
3884 {
3885     mReadImageView.destroy(device);
3886     mFetchImageView.destroy(device);
3887     mStencilReadImageView.destroy(device);
3888 
3889     for (ImageView &imageView : mLevelDrawImageViews)
3890     {
3891         imageView.destroy(device);
3892     }
3893     mLevelDrawImageViews.clear();
3894 
3895     for (ImageViewVector &layerViews : mLayerLevelDrawImageViews)
3896     {
3897         for (ImageView &imageView : layerViews)
3898         {
3899             imageView.destroy(device);
3900         }
3901     }
3902     mLayerLevelDrawImageViews.clear();
3903 }
3904 
initReadViews(ContextVk * contextVk,gl::TextureType viewType,const ImageHelper & image,const Format & format,const gl::SwizzleState & swizzleState,uint32_t baseLevel,uint32_t levelCount,uint32_t baseLayer,uint32_t layerCount)3905 angle::Result ImageViewHelper::initReadViews(ContextVk *contextVk,
3906                                              gl::TextureType viewType,
3907                                              const ImageHelper &image,
3908                                              const Format &format,
3909                                              const gl::SwizzleState &swizzleState,
3910                                              uint32_t baseLevel,
3911                                              uint32_t levelCount,
3912                                              uint32_t baseLayer,
3913                                              uint32_t layerCount)
3914 {
3915     const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(format.intendedFormat());
3916     if (HasBothDepthAndStencilAspects(aspectFlags))
3917     {
3918         ANGLE_TRY(image.initLayerImageView(contextVk, viewType, VK_IMAGE_ASPECT_DEPTH_BIT,
3919                                            swizzleState, &mReadImageView, baseLevel, levelCount,
3920                                            baseLayer, layerCount));
3921         ANGLE_TRY(image.initLayerImageView(contextVk, viewType, VK_IMAGE_ASPECT_STENCIL_BIT,
3922                                            swizzleState, &mStencilReadImageView, baseLevel,
3923                                            levelCount, baseLayer, layerCount));
3924     }
3925     else
3926     {
3927         ANGLE_TRY(image.initLayerImageView(contextVk, viewType, aspectFlags, swizzleState,
3928                                            &mReadImageView, baseLevel, levelCount, baseLayer,
3929                                            layerCount));
3930     }
3931 
3932     if (viewType == gl::TextureType::CubeMap || viewType == gl::TextureType::_2DArray ||
3933         viewType == gl::TextureType::_2DMultisampleArray)
3934     {
3935         gl::TextureType arrayType = Get2DTextureType(layerCount, image.getSamples());
3936 
3937         // TODO(http://anglebug.com/4004): SwizzleState incorrect for CopyTextureCHROMIUM.
3938         ANGLE_TRY(image.initLayerImageView(contextVk, arrayType, aspectFlags, swizzleState,
3939                                            &mFetchImageView, baseLevel, levelCount, baseLayer,
3940                                            layerCount));
3941     }
3942 
3943     return angle::Result::Continue;
3944 }
3945 
getLevelDrawImageView(ContextVk * contextVk,gl::TextureType viewType,const ImageHelper & image,uint32_t level,uint32_t layer,const ImageView ** imageViewOut)3946 angle::Result ImageViewHelper::getLevelDrawImageView(ContextVk *contextVk,
3947                                                      gl::TextureType viewType,
3948                                                      const ImageHelper &image,
3949                                                      uint32_t level,
3950                                                      uint32_t layer,
3951                                                      const ImageView **imageViewOut)
3952 {
3953     retain(&contextVk->getResourceUseList());
3954 
3955     ImageView *imageView = GetLevelImageView(&mLevelDrawImageViews, level, image.getLevelCount());
3956 
3957     *imageViewOut = imageView;
3958     if (imageView->valid())
3959     {
3960         return angle::Result::Continue;
3961     }
3962 
3963     // Create the view.  Note that storage images are not affected by swizzle parameters.
3964     return image.initLayerImageView(contextVk, viewType, image.getAspectFlags(), gl::SwizzleState(),
3965                                     imageView, level, 1, layer, image.getLayerCount());
3966 }
3967 
getLevelLayerDrawImageView(ContextVk * contextVk,const ImageHelper & image,uint32_t level,uint32_t layer,const ImageView ** imageViewOut)3968 angle::Result ImageViewHelper::getLevelLayerDrawImageView(ContextVk *contextVk,
3969                                                           const ImageHelper &image,
3970                                                           uint32_t level,
3971                                                           uint32_t layer,
3972                                                           const ImageView **imageViewOut)
3973 {
3974     ASSERT(image.valid());
3975     ASSERT(!image.getFormat().actualImageFormat().isBlock);
3976 
3977     retain(&contextVk->getResourceUseList());
3978 
3979     uint32_t layerCount = GetImageLayerCountForView(image);
3980 
3981     // Lazily allocate the storage for image views
3982     if (mLayerLevelDrawImageViews.empty())
3983     {
3984         mLayerLevelDrawImageViews.resize(layerCount);
3985     }
3986     ASSERT(mLayerLevelDrawImageViews.size() > layer);
3987 
3988     ImageView *imageView =
3989         GetLevelImageView(&mLayerLevelDrawImageViews[layer], level, image.getLevelCount());
3990     *imageViewOut = imageView;
3991 
3992     if (imageView->valid())
3993     {
3994         return angle::Result::Continue;
3995     }
3996 
3997     // Lazily allocate the image view itself.
3998     // Note that these views are specifically made to be used as color attachments, and therefore
3999     // don't have swizzle.
4000     gl::TextureType viewType = Get2DTextureType(1, image.getSamples());
4001     return image.initLayerImageView(contextVk, viewType, image.getAspectFlags(), gl::SwizzleState(),
4002                                     imageView, level, 1, layer, 1);
4003 }
4004 
4005 // SamplerHelper implementation.
SamplerHelper()4006 SamplerHelper::SamplerHelper()
4007 {
4008     mUse.init();
4009 }
4010 
~SamplerHelper()4011 SamplerHelper::~SamplerHelper()
4012 {
4013     mUse.release();
4014 }
4015 
release(RendererVk * renderer)4016 void SamplerHelper::release(RendererVk *renderer)
4017 {
4018     renderer->collectGarbageAndReinit(&mUse, &mSampler);
4019 }
4020 
4021 // DispatchHelper implementation.
4022 DispatchHelper::DispatchHelper() = default;
4023 
4024 DispatchHelper::~DispatchHelper() = default;
4025 
4026 // ShaderProgramHelper implementation.
4027 ShaderProgramHelper::ShaderProgramHelper() = default;
4028 
4029 ShaderProgramHelper::~ShaderProgramHelper() = default;
4030 
valid(const gl::ShaderType shaderType) const4031 bool ShaderProgramHelper::valid(const gl::ShaderType shaderType) const
4032 {
4033     return mShaders[shaderType].valid();
4034 }
4035 
destroy(VkDevice device)4036 void ShaderProgramHelper::destroy(VkDevice device)
4037 {
4038     mGraphicsPipelines.destroy(device);
4039     mComputePipeline.destroy(device);
4040     for (BindingPointer<ShaderAndSerial> &shader : mShaders)
4041     {
4042         shader.reset();
4043     }
4044 }
4045 
release(ContextVk * contextVk)4046 void ShaderProgramHelper::release(ContextVk *contextVk)
4047 {
4048     mGraphicsPipelines.release(contextVk);
4049     contextVk->addGarbage(&mComputePipeline.get());
4050     for (BindingPointer<ShaderAndSerial> &shader : mShaders)
4051     {
4052         shader.reset();
4053     }
4054 }
4055 
setShader(gl::ShaderType shaderType,RefCounted<ShaderAndSerial> * shader)4056 void ShaderProgramHelper::setShader(gl::ShaderType shaderType, RefCounted<ShaderAndSerial> *shader)
4057 {
4058     mShaders[shaderType].set(shader);
4059 }
4060 
enableSpecializationConstant(sh::vk::SpecializationConstantId id)4061 void ShaderProgramHelper::enableSpecializationConstant(sh::vk::SpecializationConstantId id)
4062 {
4063     ASSERT(id < sh::vk::SpecializationConstantId::EnumCount);
4064 
4065     mSpecializationConstants.set(id);
4066 }
4067 
getComputePipeline(Context * context,const PipelineLayout & pipelineLayout,PipelineAndSerial ** pipelineOut)4068 angle::Result ShaderProgramHelper::getComputePipeline(Context *context,
4069                                                       const PipelineLayout &pipelineLayout,
4070                                                       PipelineAndSerial **pipelineOut)
4071 {
4072     if (mComputePipeline.valid())
4073     {
4074         *pipelineOut = &mComputePipeline;
4075         return angle::Result::Continue;
4076     }
4077 
4078     RendererVk *renderer = context->getRenderer();
4079 
4080     VkPipelineShaderStageCreateInfo shaderStage = {};
4081     VkComputePipelineCreateInfo createInfo      = {};
4082 
4083     shaderStage.sType               = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
4084     shaderStage.flags               = 0;
4085     shaderStage.stage               = VK_SHADER_STAGE_COMPUTE_BIT;
4086     shaderStage.module              = mShaders[gl::ShaderType::Compute].get().get().getHandle();
4087     shaderStage.pName               = "main";
4088     shaderStage.pSpecializationInfo = nullptr;
4089 
4090     createInfo.sType              = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
4091     createInfo.flags              = 0;
4092     createInfo.stage              = shaderStage;
4093     createInfo.layout             = pipelineLayout.getHandle();
4094     createInfo.basePipelineHandle = VK_NULL_HANDLE;
4095     createInfo.basePipelineIndex  = 0;
4096 
4097     PipelineCache *pipelineCache = nullptr;
4098     ANGLE_TRY(renderer->getPipelineCache(&pipelineCache));
4099     ANGLE_VK_TRY(context, mComputePipeline.get().initCompute(context->getDevice(), createInfo,
4100                                                              *pipelineCache));
4101 
4102     *pipelineOut = &mComputePipeline;
4103     return angle::Result::Continue;
4104 }
4105 }  // namespace vk
4106 }  // namespace rx
4107