• 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/RendererVk.h"
20 #include "libANGLE/renderer/vulkan/vk_utils.h"
21 #include "libANGLE/trace.h"
22 
23 namespace rx
24 {
25 namespace vk
26 {
27 namespace
28 {
29 // WebGL requires color textures to be initialized to transparent black.
30 constexpr VkClearColorValue kWebGLInitColorValue = {{0, 0, 0, 0}};
31 // When emulating a texture, we want the emulated channels to be 0, with alpha 1.
32 constexpr VkClearColorValue kEmulatedInitColorValue = {{0, 0, 0, 1.0f}};
33 // WebGL requires depth/stencil textures to be initialized to depth=1, stencil=0.  We are fine with
34 // these values for emulated depth/stencil textures too.
35 constexpr VkClearDepthStencilValue kWebGLInitDepthStencilValue = {1.0f, 0};
36 
37 constexpr VkBufferUsageFlags kLineLoopDynamicBufferUsage =
38     VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
39     VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT;
40 constexpr int kLineLoopDynamicBufferInitialSize = 1024 * 1024;
41 
42 // This is an arbitrary max. We can change this later if necessary.
43 constexpr uint32_t kDefaultDescriptorPoolMaxSets = 128;
44 
45 struct ImageMemoryBarrierData
46 {
47     // The Vk layout corresponding to the ImageLayout key.
48     VkImageLayout layout;
49     // The stage in which the image is used (or Bottom/Top if not using any specific stage).  Unless
50     // Bottom/Top (Bottom used for transition to and Top used for transition from), the two values
51     // should match.
52     VkPipelineStageFlags dstStageMask;
53     VkPipelineStageFlags srcStageMask;
54     // Access mask when transitioning into this layout.
55     VkAccessFlags dstAccessMask;
56     // Access mask when transitioning out from this layout.  Note that source access mask never
57     // needs a READ bit, as WAR hazards don't need memory barriers (just execution barriers).
58     VkAccessFlags srcAccessMask;
59 
60     // If access is read-only, the execution barrier can be skipped altogether if retransitioning to
61     // the same layout.  This is because read-after-read does not need an execution or memory
62     // barrier.
63     //
64     // Otherwise, same-layout transitions only require an execution barrier (and not a memory
65     // barrier).
66     bool sameLayoutTransitionRequiresBarrier;
67 };
68 
69 // clang-format off
70 constexpr angle::PackedEnumMap<ImageLayout, ImageMemoryBarrierData> kImageMemoryBarrierData = {
71     {
72         ImageLayout::Undefined,
73         {
74             VK_IMAGE_LAYOUT_UNDEFINED,
75             VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
76             VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
77             // Transition to: we don't expect to transition into Undefined.
78             0,
79             // Transition from: there's no data in the image to care about.
80             0,
81             false,
82         },
83     },
84     {
85         ImageLayout::ExternalPreInitialized,
86         {
87             VK_IMAGE_LAYOUT_PREINITIALIZED,
88             VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
89             VK_PIPELINE_STAGE_HOST_BIT | VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
90             // Transition to: we don't expect to transition into PreInitialized.
91             0,
92             // Transition from: all writes must finish before barrier.
93             VK_ACCESS_MEMORY_WRITE_BIT,
94             false,
95         },
96     },
97     {
98         ImageLayout::TransferSrc,
99         {
100             VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
101             VK_PIPELINE_STAGE_TRANSFER_BIT,
102             VK_PIPELINE_STAGE_TRANSFER_BIT,
103             // Transition to: all reads must happen after barrier.
104             VK_ACCESS_TRANSFER_READ_BIT,
105             // Transition from: RAR and WAR don't need memory barrier.
106             0,
107             false,
108         },
109     },
110     {
111         ImageLayout::TransferDst,
112         {
113             VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
114             VK_PIPELINE_STAGE_TRANSFER_BIT,
115             VK_PIPELINE_STAGE_TRANSFER_BIT,
116             // Transition to: all writes must happen after barrier.
117             VK_ACCESS_TRANSFER_WRITE_BIT,
118             // Transition from: all writes must finish before barrier.
119             VK_ACCESS_TRANSFER_WRITE_BIT,
120             true,
121         },
122     },
123     {
124         ImageLayout::ComputeShaderReadOnly,
125         {
126             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
127             VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
128             VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
129             // Transition to: all reads must happen after barrier.
130             VK_ACCESS_SHADER_READ_BIT,
131             // Transition from: RAR and WAR don't need memory barrier.
132             0,
133             false,
134         },
135     },
136     {
137         ImageLayout::ComputeShaderWrite,
138         {
139             VK_IMAGE_LAYOUT_GENERAL,
140             VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
141             VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
142             // Transition to: all reads and writes must happen after barrier.
143             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
144             // Transition from: all writes must finish before barrier.
145             VK_ACCESS_SHADER_WRITE_BIT,
146             true,
147         },
148     },
149     {
150         ImageLayout::ColorAttachment,
151         {
152             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
153             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
154             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
155             // Transition to: all reads and writes must happen after barrier.
156             VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
157             // Transition from: all writes must finish before barrier.
158             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
159             true,
160         },
161     },
162     {
163         ImageLayout::DepthStencilAttachment,
164         {
165             VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
166             VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
167             VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
168             // Transition to: all reads and writes must happen after barrier.
169             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
170             // Transition from: all writes must finish before barrier.
171             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
172             true,
173         },
174     },
175     {
176         ImageLayout::AllGraphicsShadersReadOnly,
177         {
178             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
179             VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
180             VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
181             // Transition to: all reads must happen after barrier.
182             VK_ACCESS_SHADER_READ_BIT,
183             // Transition from: RAR and WAR don't need memory barrier.
184             0,
185             false,
186         },
187     },
188     {
189         ImageLayout::Present,
190         {
191             VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
192             VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
193             VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
194             // transition to: vkQueuePresentKHR automatically performs the appropriate memory barriers:
195             //
196             // > Any writes to memory backing the images referenced by the pImageIndices and
197             // > pSwapchains members of pPresentInfo, that are available before vkQueuePresentKHR
198             // > is executed, are automatically made visible to the read access performed by the
199             // > presentation engine.
200             0,
201             // Transition from: RAR and WAR don't need memory barrier.
202             0,
203             false,
204         },
205     },
206 };
207 // clang-format on
208 
GetImageCreateFlags(gl::TextureType textureType)209 VkImageCreateFlags GetImageCreateFlags(gl::TextureType textureType)
210 {
211     switch (textureType)
212     {
213         case gl::TextureType::CubeMap:
214             return VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
215 
216         case gl::TextureType::_3D:
217             return VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
218 
219         default:
220             return 0;
221     }
222 }
223 
HandlePrimitiveRestart(gl::DrawElementsType glIndexType,GLsizei indexCount,const uint8_t * srcPtr,uint8_t * outPtr)224 void HandlePrimitiveRestart(gl::DrawElementsType glIndexType,
225                             GLsizei indexCount,
226                             const uint8_t *srcPtr,
227                             uint8_t *outPtr)
228 {
229     switch (glIndexType)
230     {
231         case gl::DrawElementsType::UnsignedByte:
232             CopyLineLoopIndicesWithRestart<uint8_t, uint16_t>(indexCount, srcPtr, outPtr);
233             break;
234         case gl::DrawElementsType::UnsignedShort:
235             CopyLineLoopIndicesWithRestart<uint16_t, uint16_t>(indexCount, srcPtr, outPtr);
236             break;
237         case gl::DrawElementsType::UnsignedInt:
238             CopyLineLoopIndicesWithRestart<uint32_t, uint32_t>(indexCount, srcPtr, outPtr);
239             break;
240         default:
241             UNREACHABLE();
242     }
243 }
244 }  // anonymous namespace
245 
246 // DynamicBuffer implementation.
DynamicBuffer()247 DynamicBuffer::DynamicBuffer()
248     : mUsage(0),
249       mHostVisible(false),
250       mInitialSize(0),
251       mBuffer(nullptr),
252       mNextAllocationOffset(0),
253       mLastFlushOrInvalidateOffset(0),
254       mSize(0),
255       mAlignment(0)
256 {}
257 
DynamicBuffer(DynamicBuffer && other)258 DynamicBuffer::DynamicBuffer(DynamicBuffer &&other)
259     : mUsage(other.mUsage),
260       mHostVisible(other.mHostVisible),
261       mInitialSize(other.mInitialSize),
262       mBuffer(other.mBuffer),
263       mNextAllocationOffset(other.mNextAllocationOffset),
264       mLastFlushOrInvalidateOffset(other.mLastFlushOrInvalidateOffset),
265       mSize(other.mSize),
266       mAlignment(other.mAlignment),
267       mInFlightBuffers(std::move(other.mInFlightBuffers))
268 {
269     other.mBuffer = nullptr;
270 }
271 
init(RendererVk * renderer,VkBufferUsageFlags usage,size_t alignment,size_t initialSize,bool hostVisible)272 void DynamicBuffer::init(RendererVk *renderer,
273                          VkBufferUsageFlags usage,
274                          size_t alignment,
275                          size_t initialSize,
276                          bool hostVisible)
277 {
278     mUsage       = usage;
279     mHostVisible = hostVisible;
280 
281     // Check that we haven't overriden the initial size of the buffer in setMinimumSizeForTesting.
282     if (mInitialSize == 0)
283     {
284         mInitialSize = initialSize;
285         mSize        = 0;
286     }
287 
288     // Workaround for the mock ICD not supporting allocations greater than 0x1000.
289     // Could be removed if https://github.com/KhronosGroup/Vulkan-Tools/issues/84 is fixed.
290     if (renderer->isMockICDEnabled())
291     {
292         mSize = std::min<size_t>(mSize, 0x1000);
293     }
294 
295     updateAlignment(renderer, alignment);
296 }
297 
~DynamicBuffer()298 DynamicBuffer::~DynamicBuffer()
299 {
300     ASSERT(mBuffer == nullptr);
301 }
302 
allocateNewBuffer(ContextVk * contextVk)303 angle::Result DynamicBuffer::allocateNewBuffer(ContextVk *contextVk)
304 {
305     std::unique_ptr<BufferHelper> buffer = std::make_unique<BufferHelper>();
306 
307     VkBufferCreateInfo createInfo    = {};
308     createInfo.sType                 = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
309     createInfo.flags                 = 0;
310     createInfo.size                  = mSize;
311     createInfo.usage                 = mUsage;
312     createInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
313     createInfo.queueFamilyIndexCount = 0;
314     createInfo.pQueueFamilyIndices   = nullptr;
315 
316     const VkMemoryPropertyFlags memoryProperty =
317         mHostVisible ? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT : VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
318     ANGLE_TRY(buffer->init(contextVk, createInfo, memoryProperty));
319 
320     ASSERT(!mBuffer);
321     mBuffer = buffer.release();
322 
323     return angle::Result::Continue;
324 }
325 
allocate(ContextVk * contextVk,size_t sizeInBytes,uint8_t ** ptrOut,VkBuffer * bufferOut,VkDeviceSize * offsetOut,bool * newBufferAllocatedOut)326 angle::Result DynamicBuffer::allocate(ContextVk *contextVk,
327                                       size_t sizeInBytes,
328                                       uint8_t **ptrOut,
329                                       VkBuffer *bufferOut,
330                                       VkDeviceSize *offsetOut,
331                                       bool *newBufferAllocatedOut)
332 {
333     size_t sizeToAllocate = roundUpPow2(sizeInBytes, mAlignment);
334 
335     angle::base::CheckedNumeric<size_t> checkedNextWriteOffset = mNextAllocationOffset;
336     checkedNextWriteOffset += sizeToAllocate;
337 
338     if (!checkedNextWriteOffset.IsValid() || checkedNextWriteOffset.ValueOrDie() >= mSize)
339     {
340         if (mBuffer)
341         {
342             ANGLE_TRY(flush(contextVk));
343             mBuffer->unmap(contextVk->getDevice());
344             mBuffer->updateQueueSerial(contextVk->getCurrentQueueSerial());
345 
346             mInFlightBuffers.push_back(mBuffer);
347             mBuffer = nullptr;
348         }
349 
350         if (sizeToAllocate > mSize)
351         {
352             mSize = std::max(mInitialSize, sizeToAllocate);
353 
354             // Clear the free list since the free buffers are now too small.
355             for (BufferHelper *toFree : mBufferFreeList)
356             {
357                 toFree->release(contextVk);
358             }
359             mBufferFreeList.clear();
360         }
361 
362         // The front of the free list should be the oldest. Thus if it is in use the rest of the
363         // free list should be in use as well.
364         if (mBufferFreeList.empty() || mBufferFreeList.front()->isResourceInUse(contextVk))
365         {
366             ANGLE_TRY(allocateNewBuffer(contextVk));
367         }
368         else
369         {
370             mBuffer = mBufferFreeList.front();
371             mBufferFreeList.erase(mBufferFreeList.begin());
372         }
373 
374         ASSERT(mBuffer->getSize() == mSize);
375 
376         mNextAllocationOffset        = 0;
377         mLastFlushOrInvalidateOffset = 0;
378 
379         if (newBufferAllocatedOut != nullptr)
380         {
381             *newBufferAllocatedOut = true;
382         }
383     }
384     else if (newBufferAllocatedOut != nullptr)
385     {
386         *newBufferAllocatedOut = false;
387     }
388 
389     ASSERT(mBuffer != nullptr);
390 
391     if (bufferOut != nullptr)
392     {
393         *bufferOut = mBuffer->getBuffer().getHandle();
394     }
395 
396     // Optionally map() the buffer if possible
397     if (ptrOut)
398     {
399         ASSERT(mHostVisible);
400         uint8_t *mappedMemory;
401         ANGLE_TRY(mBuffer->map(contextVk, &mappedMemory));
402         *ptrOut = mappedMemory + mNextAllocationOffset;
403     }
404 
405     *offsetOut = static_cast<VkDeviceSize>(mNextAllocationOffset);
406     mNextAllocationOffset += static_cast<uint32_t>(sizeToAllocate);
407     return angle::Result::Continue;
408 }
409 
flush(ContextVk * contextVk)410 angle::Result DynamicBuffer::flush(ContextVk *contextVk)
411 {
412     if (mHostVisible && (mNextAllocationOffset > mLastFlushOrInvalidateOffset))
413     {
414         ASSERT(mBuffer != nullptr);
415         ANGLE_TRY(mBuffer->flush(contextVk, mLastFlushOrInvalidateOffset,
416                                  mNextAllocationOffset - mLastFlushOrInvalidateOffset));
417         mLastFlushOrInvalidateOffset = mNextAllocationOffset;
418     }
419     return angle::Result::Continue;
420 }
421 
invalidate(ContextVk * contextVk)422 angle::Result DynamicBuffer::invalidate(ContextVk *contextVk)
423 {
424     if (mHostVisible && (mNextAllocationOffset > mLastFlushOrInvalidateOffset))
425     {
426         ASSERT(mBuffer != nullptr);
427         ANGLE_TRY(mBuffer->invalidate(contextVk, mLastFlushOrInvalidateOffset,
428                                       mNextAllocationOffset - mLastFlushOrInvalidateOffset));
429         mLastFlushOrInvalidateOffset = mNextAllocationOffset;
430     }
431     return angle::Result::Continue;
432 }
433 
releaseBufferListToContext(ContextVk * contextVk,std::vector<BufferHelper * > * buffers)434 void DynamicBuffer::releaseBufferListToContext(ContextVk *contextVk,
435                                                std::vector<BufferHelper *> *buffers)
436 {
437     for (BufferHelper *toFree : *buffers)
438     {
439         toFree->release(contextVk);
440         delete toFree;
441     }
442 
443     buffers->clear();
444 }
445 
releaseBufferListToDisplay(DisplayVk * display,std::vector<GarbageObjectBase> * garbageQueue,std::vector<BufferHelper * > * buffers)446 void DynamicBuffer::releaseBufferListToDisplay(DisplayVk *display,
447                                                std::vector<GarbageObjectBase> *garbageQueue,
448                                                std::vector<BufferHelper *> *buffers)
449 {
450     for (BufferHelper *toFree : *buffers)
451     {
452         toFree->release(display, garbageQueue);
453         delete toFree;
454     }
455 
456     buffers->clear();
457 }
458 
destroyBufferList(VkDevice device,std::vector<BufferHelper * > * buffers)459 void DynamicBuffer::destroyBufferList(VkDevice device, std::vector<BufferHelper *> *buffers)
460 {
461     for (BufferHelper *toFree : *buffers)
462     {
463         toFree->destroy(device);
464         delete toFree;
465     }
466 
467     buffers->clear();
468 }
469 
release(ContextVk * contextVk)470 void DynamicBuffer::release(ContextVk *contextVk)
471 {
472     reset();
473 
474     releaseBufferListToContext(contextVk, &mInFlightBuffers);
475     releaseBufferListToContext(contextVk, &mBufferFreeList);
476 
477     if (mBuffer)
478     {
479         mBuffer->unmap(contextVk->getDevice());
480 
481         // The buffers may not have been recording commands, but they could be used to store data so
482         // they should live until at most this frame.  For example a vertex buffer filled entirely
483         // by the CPU currently never gets a chance to have its serial set.
484         mBuffer->updateQueueSerial(contextVk->getCurrentQueueSerial());
485         mBuffer->release(contextVk);
486         delete mBuffer;
487         mBuffer = nullptr;
488     }
489 }
490 
release(DisplayVk * display,std::vector<GarbageObjectBase> * garbageQueue)491 void DynamicBuffer::release(DisplayVk *display, std::vector<GarbageObjectBase> *garbageQueue)
492 {
493     reset();
494 
495     releaseBufferListToDisplay(display, garbageQueue, &mInFlightBuffers);
496     releaseBufferListToDisplay(display, garbageQueue, &mBufferFreeList);
497 
498     if (mBuffer)
499     {
500         mBuffer->unmap(display->getDevice());
501 
502         mBuffer->release(display, garbageQueue);
503         delete mBuffer;
504         mBuffer = nullptr;
505     }
506 }
507 
releaseInFlightBuffers(ContextVk * contextVk)508 void DynamicBuffer::releaseInFlightBuffers(ContextVk *contextVk)
509 {
510     for (BufferHelper *toRelease : mInFlightBuffers)
511     {
512         // If the dynamic buffer was resized we cannot reuse the retained buffer.
513         if (toRelease->getSize() < mSize)
514         {
515             toRelease->release(contextVk);
516         }
517         else
518         {
519             mBufferFreeList.push_back(toRelease);
520         }
521     }
522 
523     mInFlightBuffers.clear();
524 }
525 
destroy(VkDevice device)526 void DynamicBuffer::destroy(VkDevice device)
527 {
528     reset();
529 
530     destroyBufferList(device, &mInFlightBuffers);
531     destroyBufferList(device, &mBufferFreeList);
532 
533     if (mBuffer)
534     {
535         mBuffer->unmap(device);
536         mBuffer->destroy(device);
537         delete mBuffer;
538         mBuffer = nullptr;
539     }
540 }
541 
updateAlignment(RendererVk * renderer,size_t alignment)542 void DynamicBuffer::updateAlignment(RendererVk *renderer, size_t alignment)
543 {
544     ASSERT(alignment > 0);
545 
546     size_t atomSize =
547         static_cast<size_t>(renderer->getPhysicalDeviceProperties().limits.nonCoherentAtomSize);
548 
549     // We need lcm(alignment, atomSize), we are assuming one divides the other so std::max() could
550     // be used instead.
551     ASSERT(alignment % atomSize == 0 || atomSize % alignment == 0);
552     alignment = std::max(alignment, atomSize);
553     ASSERT(gl::isPow2(alignment));
554 
555     // If alignment has changed, make sure the next allocation is done at an aligned offset.
556     if (alignment != mAlignment)
557     {
558         mNextAllocationOffset =
559             roundUpPow2(mNextAllocationOffset, static_cast<uint32_t>(alignment));
560     }
561 
562     mAlignment = alignment;
563 }
564 
setMinimumSizeForTesting(size_t minSize)565 void DynamicBuffer::setMinimumSizeForTesting(size_t minSize)
566 {
567     // This will really only have an effect next time we call allocate.
568     mInitialSize = minSize;
569 
570     // Forces a new allocation on the next allocate.
571     mSize = 0;
572 }
573 
reset()574 void DynamicBuffer::reset()
575 {
576     mSize                        = 0;
577     mNextAllocationOffset        = 0;
578     mLastFlushOrInvalidateOffset = 0;
579 }
580 
581 // DescriptorPoolHelper implementation.
DescriptorPoolHelper()582 DescriptorPoolHelper::DescriptorPoolHelper() : mFreeDescriptorSets(0) {}
583 
584 DescriptorPoolHelper::~DescriptorPoolHelper() = default;
585 
hasCapacity(uint32_t descriptorSetCount) const586 bool DescriptorPoolHelper::hasCapacity(uint32_t descriptorSetCount) const
587 {
588     return mFreeDescriptorSets >= descriptorSetCount;
589 }
590 
init(Context * context,const std::vector<VkDescriptorPoolSize> & poolSizes,uint32_t maxSets)591 angle::Result DescriptorPoolHelper::init(Context *context,
592                                          const std::vector<VkDescriptorPoolSize> &poolSizes,
593                                          uint32_t maxSets)
594 {
595     if (mDescriptorPool.valid())
596     {
597         // This could be improved by recycling the descriptor pool.
598         mDescriptorPool.destroy(context->getDevice());
599     }
600 
601     VkDescriptorPoolCreateInfo descriptorPoolInfo = {};
602     descriptorPoolInfo.sType                      = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
603     descriptorPoolInfo.flags                      = 0;
604     descriptorPoolInfo.maxSets                    = maxSets;
605     descriptorPoolInfo.poolSizeCount              = static_cast<uint32_t>(poolSizes.size());
606     descriptorPoolInfo.pPoolSizes                 = poolSizes.data();
607 
608     mFreeDescriptorSets = maxSets;
609 
610     ANGLE_VK_TRY(context, mDescriptorPool.init(context->getDevice(), descriptorPoolInfo));
611     return angle::Result::Continue;
612 }
613 
destroy(VkDevice device)614 void DescriptorPoolHelper::destroy(VkDevice device)
615 {
616     mDescriptorPool.destroy(device);
617 }
618 
release(ContextVk * contextVk)619 void DescriptorPoolHelper::release(ContextVk *contextVk)
620 {
621     contextVk->releaseObject(contextVk->getCurrentQueueSerial(), &mDescriptorPool);
622 }
623 
allocateSets(ContextVk * contextVk,const VkDescriptorSetLayout * descriptorSetLayout,uint32_t descriptorSetCount,VkDescriptorSet * descriptorSetsOut)624 angle::Result DescriptorPoolHelper::allocateSets(ContextVk *contextVk,
625                                                  const VkDescriptorSetLayout *descriptorSetLayout,
626                                                  uint32_t descriptorSetCount,
627                                                  VkDescriptorSet *descriptorSetsOut)
628 {
629     VkDescriptorSetAllocateInfo allocInfo = {};
630     allocInfo.sType                       = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
631     allocInfo.descriptorPool              = mDescriptorPool.getHandle();
632     allocInfo.descriptorSetCount          = descriptorSetCount;
633     allocInfo.pSetLayouts                 = descriptorSetLayout;
634 
635     ASSERT(mFreeDescriptorSets >= descriptorSetCount);
636     mFreeDescriptorSets -= descriptorSetCount;
637 
638     ANGLE_VK_TRY(contextVk, mDescriptorPool.allocateDescriptorSets(contextVk->getDevice(),
639                                                                    allocInfo, descriptorSetsOut));
640     return angle::Result::Continue;
641 }
642 
643 // DynamicDescriptorPool implementation.
DynamicDescriptorPool()644 DynamicDescriptorPool::DynamicDescriptorPool()
645     : mMaxSetsPerPool(kDefaultDescriptorPoolMaxSets), mCurrentPoolIndex(0)
646 {}
647 
648 DynamicDescriptorPool::~DynamicDescriptorPool() = default;
649 
init(ContextVk * contextVk,const VkDescriptorPoolSize * setSizes,uint32_t setSizeCount)650 angle::Result DynamicDescriptorPool::init(ContextVk *contextVk,
651                                           const VkDescriptorPoolSize *setSizes,
652                                           uint32_t setSizeCount)
653 {
654     ASSERT(mCurrentPoolIndex == 0);
655     ASSERT(mDescriptorPools.empty() || (mDescriptorPools.size() == 1 &&
656                                         mDescriptorPools[0]->get().hasCapacity(mMaxSetsPerPool)));
657 
658     mPoolSizes.assign(setSizes, setSizes + setSizeCount);
659     for (uint32_t i = 0; i < setSizeCount; ++i)
660     {
661         mPoolSizes[i].descriptorCount *= mMaxSetsPerPool;
662     }
663 
664     mDescriptorPools.push_back(new RefCountedDescriptorPoolHelper());
665     return mDescriptorPools[0]->get().init(contextVk, mPoolSizes, mMaxSetsPerPool);
666 }
667 
destroy(VkDevice device)668 void DynamicDescriptorPool::destroy(VkDevice device)
669 {
670     for (RefCountedDescriptorPoolHelper *pool : mDescriptorPools)
671     {
672         ASSERT(!pool->isReferenced());
673         pool->get().destroy(device);
674         delete pool;
675     }
676 
677     mDescriptorPools.clear();
678 }
679 
release(ContextVk * contextVk)680 void DynamicDescriptorPool::release(ContextVk *contextVk)
681 {
682     for (RefCountedDescriptorPoolHelper *pool : mDescriptorPools)
683     {
684         ASSERT(!pool->isReferenced());
685         pool->get().release(contextVk);
686         delete pool;
687     }
688 
689     mDescriptorPools.clear();
690 }
691 
allocateSetsAndGetInfo(ContextVk * contextVk,const VkDescriptorSetLayout * descriptorSetLayout,uint32_t descriptorSetCount,RefCountedDescriptorPoolBinding * bindingOut,VkDescriptorSet * descriptorSetsOut,bool * newPoolAllocatedOut)692 angle::Result DynamicDescriptorPool::allocateSetsAndGetInfo(
693     ContextVk *contextVk,
694     const VkDescriptorSetLayout *descriptorSetLayout,
695     uint32_t descriptorSetCount,
696     RefCountedDescriptorPoolBinding *bindingOut,
697     VkDescriptorSet *descriptorSetsOut,
698     bool *newPoolAllocatedOut)
699 {
700     *newPoolAllocatedOut = false;
701 
702     if (!bindingOut->valid() || !bindingOut->get().hasCapacity(descriptorSetCount))
703     {
704         if (!mDescriptorPools[mCurrentPoolIndex]->get().hasCapacity(descriptorSetCount))
705         {
706             ANGLE_TRY(allocateNewPool(contextVk));
707             *newPoolAllocatedOut = true;
708         }
709 
710         // Make sure the old binding knows the descriptor sets can still be in-use. We only need
711         // to update the serial when we move to a new pool. This is because we only check serials
712         // when we move to a new pool.
713         if (bindingOut->valid())
714         {
715             Serial currentSerial = contextVk->getCurrentQueueSerial();
716             bindingOut->get().updateSerial(currentSerial);
717         }
718 
719         bindingOut->set(mDescriptorPools[mCurrentPoolIndex]);
720     }
721 
722     return bindingOut->get().allocateSets(contextVk, descriptorSetLayout, descriptorSetCount,
723                                           descriptorSetsOut);
724 }
725 
allocateNewPool(ContextVk * contextVk)726 angle::Result DynamicDescriptorPool::allocateNewPool(ContextVk *contextVk)
727 {
728     bool found = false;
729 
730     for (size_t poolIndex = 0; poolIndex < mDescriptorPools.size(); ++poolIndex)
731     {
732         if (!mDescriptorPools[poolIndex]->isReferenced() &&
733             !contextVk->isSerialInUse(mDescriptorPools[poolIndex]->get().getSerial()))
734         {
735             mCurrentPoolIndex = poolIndex;
736             found             = true;
737             break;
738         }
739     }
740 
741     if (!found)
742     {
743         mDescriptorPools.push_back(new RefCountedDescriptorPoolHelper());
744         mCurrentPoolIndex = mDescriptorPools.size() - 1;
745 
746         static constexpr size_t kMaxPools = 99999;
747         ANGLE_VK_CHECK(contextVk, mDescriptorPools.size() < kMaxPools, VK_ERROR_TOO_MANY_OBJECTS);
748     }
749 
750     return mDescriptorPools[mCurrentPoolIndex]->get().init(contextVk, mPoolSizes, mMaxSetsPerPool);
751 }
752 
setMaxSetsPerPoolForTesting(uint32_t maxSetsPerPool)753 void DynamicDescriptorPool::setMaxSetsPerPoolForTesting(uint32_t maxSetsPerPool)
754 {
755     mMaxSetsPerPool = maxSetsPerPool;
756 }
757 
758 // DynamicallyGrowingPool implementation
759 template <typename Pool>
DynamicallyGrowingPool()760 DynamicallyGrowingPool<Pool>::DynamicallyGrowingPool()
761     : mPoolSize(0), mCurrentPool(0), mCurrentFreeEntry(0)
762 {}
763 
764 template <typename Pool>
765 DynamicallyGrowingPool<Pool>::~DynamicallyGrowingPool() = default;
766 
767 template <typename Pool>
initEntryPool(Context * contextVk,uint32_t poolSize)768 angle::Result DynamicallyGrowingPool<Pool>::initEntryPool(Context *contextVk, uint32_t poolSize)
769 {
770     ASSERT(mPools.empty() && mPoolStats.empty());
771     mPoolSize = poolSize;
772     return angle::Result::Continue;
773 }
774 
775 template <typename Pool>
destroyEntryPool()776 void DynamicallyGrowingPool<Pool>::destroyEntryPool()
777 {
778     mPools.clear();
779     mPoolStats.clear();
780 }
781 
782 template <typename Pool>
findFreeEntryPool(ContextVk * contextVk)783 bool DynamicallyGrowingPool<Pool>::findFreeEntryPool(ContextVk *contextVk)
784 {
785     Serial lastCompletedQueueSerial = contextVk->getLastCompletedQueueSerial();
786     for (size_t i = 0; i < mPools.size(); ++i)
787     {
788         if (mPoolStats[i].freedCount == mPoolSize &&
789             mPoolStats[i].serial <= lastCompletedQueueSerial)
790         {
791             mCurrentPool      = i;
792             mCurrentFreeEntry = 0;
793 
794             mPoolStats[i].freedCount = 0;
795 
796             return true;
797         }
798     }
799 
800     return false;
801 }
802 
803 template <typename Pool>
allocateNewEntryPool(ContextVk * contextVk,Pool && pool)804 angle::Result DynamicallyGrowingPool<Pool>::allocateNewEntryPool(ContextVk *contextVk, Pool &&pool)
805 {
806     mPools.push_back(std::move(pool));
807 
808     PoolStats poolStats = {0, Serial()};
809     mPoolStats.push_back(poolStats);
810 
811     mCurrentPool      = mPools.size() - 1;
812     mCurrentFreeEntry = 0;
813 
814     return angle::Result::Continue;
815 }
816 
817 template <typename Pool>
onEntryFreed(ContextVk * contextVk,size_t poolIndex)818 void DynamicallyGrowingPool<Pool>::onEntryFreed(ContextVk *contextVk, size_t poolIndex)
819 {
820     ASSERT(poolIndex < mPoolStats.size() && mPoolStats[poolIndex].freedCount < mPoolSize);
821 
822     // Take note of the current serial to avoid reallocating a query in the same pool
823     mPoolStats[poolIndex].serial = contextVk->getCurrentQueueSerial();
824     ++mPoolStats[poolIndex].freedCount;
825 }
826 
827 // DynamicQueryPool implementation
828 DynamicQueryPool::DynamicQueryPool() = default;
829 
830 DynamicQueryPool::~DynamicQueryPool() = default;
831 
init(ContextVk * contextVk,VkQueryType type,uint32_t poolSize)832 angle::Result DynamicQueryPool::init(ContextVk *contextVk, VkQueryType type, uint32_t poolSize)
833 {
834     ANGLE_TRY(initEntryPool(contextVk, poolSize));
835 
836     mQueryType = type;
837     ANGLE_TRY(allocateNewPool(contextVk));
838 
839     return angle::Result::Continue;
840 }
841 
destroy(VkDevice device)842 void DynamicQueryPool::destroy(VkDevice device)
843 {
844     for (QueryPool &queryPool : mPools)
845     {
846         queryPool.destroy(device);
847     }
848 
849     destroyEntryPool();
850 }
851 
allocateQuery(ContextVk * contextVk,QueryHelper * queryOut)852 angle::Result DynamicQueryPool::allocateQuery(ContextVk *contextVk, QueryHelper *queryOut)
853 {
854     ASSERT(!queryOut->getQueryPool());
855 
856     size_t poolIndex    = 0;
857     uint32_t queryIndex = 0;
858     ANGLE_TRY(allocateQuery(contextVk, &poolIndex, &queryIndex));
859 
860     queryOut->init(this, poolIndex, queryIndex);
861 
862     return angle::Result::Continue;
863 }
864 
freeQuery(ContextVk * contextVk,QueryHelper * query)865 void DynamicQueryPool::freeQuery(ContextVk *contextVk, QueryHelper *query)
866 {
867     if (query->getQueryPool())
868     {
869         size_t poolIndex = query->getQueryPoolIndex();
870         ASSERT(query->getQueryPool()->valid());
871 
872         freeQuery(contextVk, poolIndex, query->getQuery());
873 
874         query->deinit();
875     }
876 }
877 
allocateQuery(ContextVk * contextVk,size_t * poolIndex,uint32_t * queryIndex)878 angle::Result DynamicQueryPool::allocateQuery(ContextVk *contextVk,
879                                               size_t *poolIndex,
880                                               uint32_t *queryIndex)
881 {
882     if (mCurrentFreeEntry >= mPoolSize)
883     {
884         // No more queries left in this pool, create another one.
885         ANGLE_TRY(allocateNewPool(contextVk));
886     }
887 
888     *poolIndex  = mCurrentPool;
889     *queryIndex = mCurrentFreeEntry++;
890 
891     return angle::Result::Continue;
892 }
893 
freeQuery(ContextVk * contextVk,size_t poolIndex,uint32_t queryIndex)894 void DynamicQueryPool::freeQuery(ContextVk *contextVk, size_t poolIndex, uint32_t queryIndex)
895 {
896     ANGLE_UNUSED_VARIABLE(queryIndex);
897     onEntryFreed(contextVk, poolIndex);
898 }
899 
allocateNewPool(ContextVk * contextVk)900 angle::Result DynamicQueryPool::allocateNewPool(ContextVk *contextVk)
901 {
902     if (findFreeEntryPool(contextVk))
903     {
904         return angle::Result::Continue;
905     }
906 
907     VkQueryPoolCreateInfo queryPoolInfo = {};
908     queryPoolInfo.sType                 = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
909     queryPoolInfo.flags                 = 0;
910     queryPoolInfo.queryType             = mQueryType;
911     queryPoolInfo.queryCount            = mPoolSize;
912     queryPoolInfo.pipelineStatistics    = 0;
913 
914     vk::QueryPool queryPool;
915 
916     ANGLE_VK_TRY(contextVk, queryPool.init(contextVk->getDevice(), queryPoolInfo));
917 
918     return allocateNewEntryPool(contextVk, std::move(queryPool));
919 }
920 
921 // QueryHelper implementation
QueryHelper()922 QueryHelper::QueryHelper() : mDynamicQueryPool(nullptr), mQueryPoolIndex(0), mQuery(0) {}
923 
~QueryHelper()924 QueryHelper::~QueryHelper() {}
925 
init(const DynamicQueryPool * dynamicQueryPool,const size_t queryPoolIndex,uint32_t query)926 void QueryHelper::init(const DynamicQueryPool *dynamicQueryPool,
927                        const size_t queryPoolIndex,
928                        uint32_t query)
929 {
930     mDynamicQueryPool = dynamicQueryPool;
931     mQueryPoolIndex   = queryPoolIndex;
932     mQuery            = query;
933 }
934 
deinit()935 void QueryHelper::deinit()
936 {
937     mDynamicQueryPool = nullptr;
938     mQueryPoolIndex   = 0;
939     mQuery            = 0;
940 }
941 
beginQuery(ContextVk * contextVk)942 void QueryHelper::beginQuery(ContextVk *contextVk)
943 {
944     contextVk->getCommandGraph()->beginQuery(getQueryPool(), getQuery());
945     mMostRecentSerial = contextVk->getCurrentQueueSerial();
946 }
947 
endQuery(ContextVk * contextVk)948 void QueryHelper::endQuery(ContextVk *contextVk)
949 {
950     contextVk->getCommandGraph()->endQuery(getQueryPool(), getQuery());
951     mMostRecentSerial = contextVk->getCurrentQueueSerial();
952 }
953 
writeTimestamp(ContextVk * contextVk)954 void QueryHelper::writeTimestamp(ContextVk *contextVk)
955 {
956     contextVk->getCommandGraph()->writeTimestamp(getQueryPool(), getQuery());
957     mMostRecentSerial = contextVk->getCurrentQueueSerial();
958 }
959 
hasPendingWork(ContextVk * contextVk)960 bool QueryHelper::hasPendingWork(ContextVk *contextVk)
961 {
962     // If the renderer has a queue serial higher than the stored one, the command buffers that
963     // recorded this query have already been submitted, so there is no pending work.
964     return mMostRecentSerial == contextVk->getCurrentQueueSerial();
965 }
966 
967 // DynamicSemaphorePool implementation
968 DynamicSemaphorePool::DynamicSemaphorePool() = default;
969 
970 DynamicSemaphorePool::~DynamicSemaphorePool() = default;
971 
init(ContextVk * contextVk,uint32_t poolSize)972 angle::Result DynamicSemaphorePool::init(ContextVk *contextVk, uint32_t poolSize)
973 {
974     ANGLE_TRY(initEntryPool(contextVk, poolSize));
975     ANGLE_TRY(allocateNewPool(contextVk));
976     return angle::Result::Continue;
977 }
978 
destroy(VkDevice device)979 void DynamicSemaphorePool::destroy(VkDevice device)
980 {
981     for (auto &semaphorePool : mPools)
982     {
983         for (Semaphore &semaphore : semaphorePool)
984         {
985             semaphore.destroy(device);
986         }
987     }
988 
989     destroyEntryPool();
990 }
991 
allocateSemaphore(ContextVk * contextVk,SemaphoreHelper * semaphoreOut)992 angle::Result DynamicSemaphorePool::allocateSemaphore(ContextVk *contextVk,
993                                                       SemaphoreHelper *semaphoreOut)
994 {
995     ASSERT(!semaphoreOut->getSemaphore());
996 
997     if (mCurrentFreeEntry >= mPoolSize)
998     {
999         // No more queries left in this pool, create another one.
1000         ANGLE_TRY(allocateNewPool(contextVk));
1001     }
1002 
1003     semaphoreOut->init(mCurrentPool, &mPools[mCurrentPool][mCurrentFreeEntry++]);
1004 
1005     return angle::Result::Continue;
1006 }
1007 
freeSemaphore(ContextVk * contextVk,SemaphoreHelper * semaphore)1008 void DynamicSemaphorePool::freeSemaphore(ContextVk *contextVk, SemaphoreHelper *semaphore)
1009 {
1010     if (semaphore->getSemaphore())
1011     {
1012         onEntryFreed(contextVk, semaphore->getSemaphorePoolIndex());
1013         semaphore->deinit();
1014     }
1015 }
1016 
allocateNewPool(ContextVk * contextVk)1017 angle::Result DynamicSemaphorePool::allocateNewPool(ContextVk *contextVk)
1018 {
1019     if (findFreeEntryPool(contextVk))
1020     {
1021         return angle::Result::Continue;
1022     }
1023 
1024     std::vector<Semaphore> newPool(mPoolSize);
1025 
1026     for (Semaphore &semaphore : newPool)
1027     {
1028         ANGLE_VK_TRY(contextVk, semaphore.init(contextVk->getDevice()));
1029     }
1030 
1031     // This code is safe as long as the growth of the outer vector in vector<vector<T>> is done by
1032     // moving the inner vectors, making sure references to the inner vector remain intact.
1033     Semaphore *assertMove = mPools.size() > 0 ? mPools[0].data() : nullptr;
1034 
1035     ANGLE_TRY(allocateNewEntryPool(contextVk, std::move(newPool)));
1036 
1037     ASSERT(assertMove == nullptr || assertMove == mPools[0].data());
1038 
1039     return angle::Result::Continue;
1040 }
1041 
1042 // SemaphoreHelper implementation
SemaphoreHelper()1043 SemaphoreHelper::SemaphoreHelper() : mSemaphorePoolIndex(0), mSemaphore(0) {}
1044 
~SemaphoreHelper()1045 SemaphoreHelper::~SemaphoreHelper() {}
1046 
SemaphoreHelper(SemaphoreHelper && other)1047 SemaphoreHelper::SemaphoreHelper(SemaphoreHelper &&other)
1048     : mSemaphorePoolIndex(other.mSemaphorePoolIndex), mSemaphore(other.mSemaphore)
1049 {
1050     other.mSemaphore = nullptr;
1051 }
1052 
operator =(SemaphoreHelper && other)1053 SemaphoreHelper &SemaphoreHelper::operator=(SemaphoreHelper &&other)
1054 {
1055     std::swap(mSemaphorePoolIndex, other.mSemaphorePoolIndex);
1056     std::swap(mSemaphore, other.mSemaphore);
1057     return *this;
1058 }
1059 
init(const size_t semaphorePoolIndex,const vk::Semaphore * semaphore)1060 void SemaphoreHelper::init(const size_t semaphorePoolIndex, const vk::Semaphore *semaphore)
1061 {
1062     mSemaphorePoolIndex = semaphorePoolIndex;
1063     mSemaphore          = semaphore;
1064 }
1065 
deinit()1066 void SemaphoreHelper::deinit()
1067 {
1068     mSemaphorePoolIndex = 0;
1069     mSemaphore          = nullptr;
1070 }
1071 
1072 // LineLoopHelper implementation.
LineLoopHelper(RendererVk * renderer)1073 LineLoopHelper::LineLoopHelper(RendererVk *renderer)
1074 {
1075     // We need to use an alignment of the maximum size we're going to allocate, which is
1076     // VK_INDEX_TYPE_UINT32. When we switch from a drawElement to a drawArray call, the allocations
1077     // can vary in size. According to the Vulkan spec, when calling vkCmdBindIndexBuffer: 'The
1078     // sum of offset and the address of the range of VkDeviceMemory object that is backing buffer,
1079     // must be a multiple of the type indicated by indexType'.
1080     mDynamicIndexBuffer.init(renderer, kLineLoopDynamicBufferUsage, sizeof(uint32_t),
1081                              kLineLoopDynamicBufferInitialSize, true);
1082 }
1083 
1084 LineLoopHelper::~LineLoopHelper() = default;
1085 
getIndexBufferForDrawArrays(ContextVk * contextVk,uint32_t clampedVertexCount,GLint firstVertex,vk::BufferHelper ** bufferOut,VkDeviceSize * offsetOut)1086 angle::Result LineLoopHelper::getIndexBufferForDrawArrays(ContextVk *contextVk,
1087                                                           uint32_t clampedVertexCount,
1088                                                           GLint firstVertex,
1089                                                           vk::BufferHelper **bufferOut,
1090                                                           VkDeviceSize *offsetOut)
1091 {
1092     uint32_t *indices    = nullptr;
1093     size_t allocateBytes = sizeof(uint32_t) * (static_cast<size_t>(clampedVertexCount) + 1);
1094 
1095     mDynamicIndexBuffer.releaseInFlightBuffers(contextVk);
1096     ANGLE_TRY(mDynamicIndexBuffer.allocate(contextVk, allocateBytes,
1097                                            reinterpret_cast<uint8_t **>(&indices), nullptr,
1098                                            offsetOut, nullptr));
1099     *bufferOut = mDynamicIndexBuffer.getCurrentBuffer();
1100 
1101     // Note: there could be an overflow in this addition.
1102     uint32_t unsignedFirstVertex = static_cast<uint32_t>(firstVertex);
1103     uint32_t vertexCount         = (clampedVertexCount + unsignedFirstVertex);
1104     for (uint32_t vertexIndex = unsignedFirstVertex; vertexIndex < vertexCount; vertexIndex++)
1105     {
1106         *indices++ = vertexIndex;
1107     }
1108     *indices = unsignedFirstVertex;
1109 
1110     // Since we are not using the VK_MEMORY_PROPERTY_HOST_COHERENT_BIT flag when creating the
1111     // device memory in the StreamingBuffer, we always need to make sure we flush it after
1112     // writing.
1113     ANGLE_TRY(mDynamicIndexBuffer.flush(contextVk));
1114 
1115     return angle::Result::Continue;
1116 }
1117 
getIndexBufferForElementArrayBuffer(ContextVk * contextVk,BufferVk * elementArrayBufferVk,gl::DrawElementsType glIndexType,int indexCount,intptr_t elementArrayOffset,vk::BufferHelper ** bufferOut,VkDeviceSize * bufferOffsetOut,uint32_t * indexCountOut)1118 angle::Result LineLoopHelper::getIndexBufferForElementArrayBuffer(ContextVk *contextVk,
1119                                                                   BufferVk *elementArrayBufferVk,
1120                                                                   gl::DrawElementsType glIndexType,
1121                                                                   int indexCount,
1122                                                                   intptr_t elementArrayOffset,
1123                                                                   vk::BufferHelper **bufferOut,
1124                                                                   VkDeviceSize *bufferOffsetOut,
1125                                                                   uint32_t *indexCountOut)
1126 {
1127     if (glIndexType == gl::DrawElementsType::UnsignedByte ||
1128         contextVk->getState().isPrimitiveRestartEnabled())
1129     {
1130         ANGLE_TRACE_EVENT0("gpu.angle", "LineLoopHelper::getIndexBufferForElementArrayBuffer");
1131 
1132         void *srcDataMapping = nullptr;
1133         ANGLE_TRY(elementArrayBufferVk->mapImpl(contextVk, &srcDataMapping));
1134         ANGLE_TRY(streamIndices(contextVk, glIndexType, indexCount,
1135                                 static_cast<const uint8_t *>(srcDataMapping) + elementArrayOffset,
1136                                 bufferOut, bufferOffsetOut, indexCountOut));
1137         elementArrayBufferVk->unmapImpl(contextVk);
1138         return angle::Result::Continue;
1139     }
1140 
1141     *indexCountOut = indexCount + 1;
1142 
1143     VkIndexType indexType = gl_vk::kIndexTypeMap[glIndexType];
1144     ASSERT(indexType == VK_INDEX_TYPE_UINT16 || indexType == VK_INDEX_TYPE_UINT32);
1145     uint32_t *indices = nullptr;
1146 
1147     auto unitSize = (indexType == VK_INDEX_TYPE_UINT16 ? sizeof(uint16_t) : sizeof(uint32_t));
1148     size_t allocateBytes = unitSize * (indexCount + 1) + 1;
1149 
1150     mDynamicIndexBuffer.releaseInFlightBuffers(contextVk);
1151     ANGLE_TRY(mDynamicIndexBuffer.allocate(contextVk, allocateBytes,
1152                                            reinterpret_cast<uint8_t **>(&indices), nullptr,
1153                                            bufferOffsetOut, nullptr));
1154     *bufferOut = mDynamicIndexBuffer.getCurrentBuffer();
1155 
1156     VkDeviceSize sourceOffset                  = static_cast<VkDeviceSize>(elementArrayOffset);
1157     uint64_t unitCount                         = static_cast<VkDeviceSize>(indexCount);
1158     angle::FixedVector<VkBufferCopy, 3> copies = {
1159         {sourceOffset, *bufferOffsetOut, unitCount * unitSize},
1160         {sourceOffset, *bufferOffsetOut + unitCount * unitSize, unitSize},
1161     };
1162     if (contextVk->getRenderer()->getFeatures().extraCopyBufferRegion.enabled)
1163         copies.push_back({sourceOffset, *bufferOffsetOut + (unitCount + 1) * unitSize, 1});
1164 
1165     ANGLE_TRY(elementArrayBufferVk->copyToBuffer(
1166         contextVk, *bufferOut, static_cast<uint32_t>(copies.size()), copies.data()));
1167     ANGLE_TRY(mDynamicIndexBuffer.flush(contextVk));
1168     return angle::Result::Continue;
1169 }
1170 
streamIndices(ContextVk * contextVk,gl::DrawElementsType glIndexType,GLsizei indexCount,const uint8_t * srcPtr,vk::BufferHelper ** bufferOut,VkDeviceSize * bufferOffsetOut,uint32_t * indexCountOut)1171 angle::Result LineLoopHelper::streamIndices(ContextVk *contextVk,
1172                                             gl::DrawElementsType glIndexType,
1173                                             GLsizei indexCount,
1174                                             const uint8_t *srcPtr,
1175                                             vk::BufferHelper **bufferOut,
1176                                             VkDeviceSize *bufferOffsetOut,
1177                                             uint32_t *indexCountOut)
1178 {
1179     VkIndexType indexType = gl_vk::kIndexTypeMap[glIndexType];
1180 
1181     uint8_t *indices = nullptr;
1182 
1183     auto unitSize = (indexType == VK_INDEX_TYPE_UINT16 ? sizeof(uint16_t) : sizeof(uint32_t));
1184     uint32_t numOutIndices = indexCount + 1;
1185     if (contextVk->getState().isPrimitiveRestartEnabled())
1186     {
1187         numOutIndices = GetLineLoopWithRestartIndexCount(glIndexType, indexCount, srcPtr);
1188     }
1189     *indexCountOut       = numOutIndices;
1190     size_t allocateBytes = unitSize * numOutIndices;
1191     ANGLE_TRY(mDynamicIndexBuffer.allocate(contextVk, allocateBytes,
1192                                            reinterpret_cast<uint8_t **>(&indices), nullptr,
1193                                            bufferOffsetOut, nullptr));
1194     *bufferOut = mDynamicIndexBuffer.getCurrentBuffer();
1195 
1196     if (contextVk->getState().isPrimitiveRestartEnabled())
1197     {
1198         HandlePrimitiveRestart(glIndexType, indexCount, srcPtr, indices);
1199     }
1200     else
1201     {
1202         if (glIndexType == gl::DrawElementsType::UnsignedByte)
1203         {
1204             // Vulkan doesn't support uint8 index types, so we need to emulate it.
1205             ASSERT(indexType == VK_INDEX_TYPE_UINT16);
1206             uint16_t *indicesDst = reinterpret_cast<uint16_t *>(indices);
1207             for (int i = 0; i < indexCount; i++)
1208             {
1209                 indicesDst[i] = srcPtr[i];
1210             }
1211 
1212             indicesDst[indexCount] = srcPtr[0];
1213         }
1214         else
1215         {
1216             memcpy(indices, srcPtr, unitSize * indexCount);
1217             memcpy(indices + unitSize * indexCount, srcPtr, unitSize);
1218         }
1219     }
1220 
1221     ANGLE_TRY(mDynamicIndexBuffer.flush(contextVk));
1222     return angle::Result::Continue;
1223 }
1224 
release(ContextVk * contextVk)1225 void LineLoopHelper::release(ContextVk *contextVk)
1226 {
1227     mDynamicIndexBuffer.release(contextVk);
1228 }
1229 
destroy(VkDevice device)1230 void LineLoopHelper::destroy(VkDevice device)
1231 {
1232     mDynamicIndexBuffer.destroy(device);
1233 }
1234 
1235 // static
Draw(uint32_t count,vk::CommandBuffer * commandBuffer)1236 void LineLoopHelper::Draw(uint32_t count, vk::CommandBuffer *commandBuffer)
1237 {
1238     // Our first index is always 0 because that's how we set it up in createIndexBuffer*.
1239     commandBuffer->drawIndexed(count);
1240 }
1241 
1242 // BufferHelper implementation.
BufferHelper()1243 BufferHelper::BufferHelper()
1244     : CommandGraphResource(CommandGraphResourceType::Buffer),
1245       mMemoryPropertyFlags{},
1246       mSize(0),
1247       mMappedMemory(nullptr),
1248       mViewFormat(nullptr),
1249       mCurrentWriteAccess(0),
1250       mCurrentReadAccess(0)
1251 {}
1252 
1253 BufferHelper::~BufferHelper() = default;
1254 
init(ContextVk * contextVk,const VkBufferCreateInfo & createInfo,VkMemoryPropertyFlags memoryPropertyFlags)1255 angle::Result BufferHelper::init(ContextVk *contextVk,
1256                                  const VkBufferCreateInfo &createInfo,
1257                                  VkMemoryPropertyFlags memoryPropertyFlags)
1258 {
1259     mSize = createInfo.size;
1260     ANGLE_VK_TRY(contextVk, mBuffer.init(contextVk->getDevice(), createInfo));
1261     return vk::AllocateBufferMemory(contextVk, memoryPropertyFlags, &mMemoryPropertyFlags, nullptr,
1262                                     &mBuffer, &mDeviceMemory);
1263 }
1264 
destroy(VkDevice device)1265 void BufferHelper::destroy(VkDevice device)
1266 {
1267     unmap(device);
1268     mSize       = 0;
1269     mViewFormat = nullptr;
1270 
1271     mBuffer.destroy(device);
1272     mBufferView.destroy(device);
1273     mDeviceMemory.destroy(device);
1274 }
1275 
release(ContextVk * contextVk)1276 void BufferHelper::release(ContextVk *contextVk)
1277 {
1278     unmap(contextVk->getDevice());
1279     mSize       = 0;
1280     mViewFormat = nullptr;
1281 
1282     contextVk->releaseObject(getStoredQueueSerial(), &mBuffer);
1283     contextVk->releaseObject(getStoredQueueSerial(), &mBufferView);
1284     contextVk->releaseObject(getStoredQueueSerial(), &mDeviceMemory);
1285 }
1286 
release(DisplayVk * display,std::vector<GarbageObjectBase> * garbageQueue)1287 void BufferHelper::release(DisplayVk *display, std::vector<GarbageObjectBase> *garbageQueue)
1288 {
1289     unmap(display->getDevice());
1290     mSize       = 0;
1291     mViewFormat = nullptr;
1292 
1293     mBuffer.dumpResources(garbageQueue);
1294     mBufferView.dumpResources(garbageQueue);
1295     mDeviceMemory.dumpResources(garbageQueue);
1296 }
1297 
needsOnWriteBarrier(VkAccessFlags readAccessType,VkAccessFlags writeAccessType,VkAccessFlags * barrierSrcOut,VkAccessFlags * barrierDstOut)1298 bool BufferHelper::needsOnWriteBarrier(VkAccessFlags readAccessType,
1299                                        VkAccessFlags writeAccessType,
1300                                        VkAccessFlags *barrierSrcOut,
1301                                        VkAccessFlags *barrierDstOut)
1302 {
1303     bool needsBarrier = mCurrentReadAccess != 0 || mCurrentWriteAccess != 0;
1304 
1305     // Note: mCurrentReadAccess is not part of barrier src flags as "anything-after-read" is
1306     // satisified by execution barriers alone.
1307     *barrierSrcOut = mCurrentWriteAccess;
1308     *barrierDstOut = readAccessType | writeAccessType;
1309 
1310     mCurrentWriteAccess = writeAccessType;
1311     mCurrentReadAccess  = readAccessType;
1312 
1313     return needsBarrier;
1314 }
1315 
onWriteAccess(ContextVk * contextVk,VkAccessFlags readAccessType,VkAccessFlags writeAccessType)1316 void BufferHelper::onWriteAccess(ContextVk *contextVk,
1317                                  VkAccessFlags readAccessType,
1318                                  VkAccessFlags writeAccessType)
1319 {
1320     VkAccessFlags barrierSrc, barrierDst;
1321     if (needsOnWriteBarrier(readAccessType, writeAccessType, &barrierSrc, &barrierDst))
1322     {
1323         addGlobalMemoryBarrier(barrierSrc, barrierDst, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
1324     }
1325 
1326     bool hostVisible = mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
1327     if (hostVisible && writeAccessType != VK_ACCESS_HOST_WRITE_BIT)
1328     {
1329         contextVk->onHostVisibleBufferWrite();
1330     }
1331 }
1332 
copyFromBuffer(ContextVk * contextVk,const Buffer & buffer,VkAccessFlags bufferAccessType,const VkBufferCopy & copyRegion)1333 angle::Result BufferHelper::copyFromBuffer(ContextVk *contextVk,
1334                                            const Buffer &buffer,
1335                                            VkAccessFlags bufferAccessType,
1336                                            const VkBufferCopy &copyRegion)
1337 {
1338     // 'recordCommands' will implicitly stop any reads from using the old buffer data.
1339     vk::CommandBuffer *commandBuffer = nullptr;
1340     ANGLE_TRY(recordCommands(contextVk, &commandBuffer));
1341 
1342     if (mCurrentReadAccess != 0 || mCurrentWriteAccess != 0 || bufferAccessType != 0)
1343     {
1344         // Insert a barrier to ensure reads/writes are complete.
1345         // Use a global memory barrier to keep things simple.
1346         VkMemoryBarrier memoryBarrier = {};
1347         memoryBarrier.sType           = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
1348         memoryBarrier.srcAccessMask   = mCurrentReadAccess | mCurrentWriteAccess | bufferAccessType;
1349         memoryBarrier.dstAccessMask   = VK_ACCESS_TRANSFER_WRITE_BIT;
1350 
1351         commandBuffer->pipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
1352                                        VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 1, &memoryBarrier, 0,
1353                                        nullptr, 0, nullptr);
1354     }
1355 
1356     mCurrentWriteAccess = VK_ACCESS_TRANSFER_WRITE_BIT;
1357     mCurrentReadAccess  = 0;
1358 
1359     commandBuffer->copyBuffer(buffer, mBuffer, 1, &copyRegion);
1360 
1361     return angle::Result::Continue;
1362 }
1363 
initBufferView(ContextVk * contextVk,const Format & format)1364 angle::Result BufferHelper::initBufferView(ContextVk *contextVk, const Format &format)
1365 {
1366     ASSERT(format.valid());
1367 
1368     if (mBufferView.valid())
1369     {
1370         ASSERT(mViewFormat->vkBufferFormat == format.vkBufferFormat);
1371         return angle::Result::Continue;
1372     }
1373 
1374     VkBufferViewCreateInfo viewCreateInfo = {};
1375     viewCreateInfo.sType                  = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
1376     viewCreateInfo.buffer                 = mBuffer.getHandle();
1377     viewCreateInfo.format                 = format.vkBufferFormat;
1378     viewCreateInfo.offset                 = 0;
1379     viewCreateInfo.range                  = mSize;
1380 
1381     ANGLE_VK_TRY(contextVk, mBufferView.init(contextVk->getDevice(), viewCreateInfo));
1382     mViewFormat = &format;
1383 
1384     return angle::Result::Continue;
1385 }
1386 
mapImpl(ContextVk * contextVk)1387 angle::Result BufferHelper::mapImpl(ContextVk *contextVk)
1388 {
1389     ANGLE_VK_TRY(contextVk, mDeviceMemory.map(contextVk->getDevice(), 0, mSize, 0, &mMappedMemory));
1390     return angle::Result::Continue;
1391 }
1392 
unmap(VkDevice device)1393 void BufferHelper::unmap(VkDevice device)
1394 {
1395     if (mMappedMemory)
1396     {
1397         mDeviceMemory.unmap(device);
1398         mMappedMemory = nullptr;
1399     }
1400 }
1401 
flush(ContextVk * contextVk,size_t offset,size_t size)1402 angle::Result BufferHelper::flush(ContextVk *contextVk, size_t offset, size_t size)
1403 {
1404     bool hostVisible  = mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
1405     bool hostCoherent = mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
1406     if (hostVisible && !hostCoherent)
1407     {
1408         VkMappedMemoryRange range = {};
1409         range.sType               = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
1410         range.memory              = mDeviceMemory.getHandle();
1411         range.offset              = offset;
1412         range.size                = size;
1413         ANGLE_VK_TRY(contextVk, vkFlushMappedMemoryRanges(contextVk->getDevice(), 1, &range));
1414     }
1415     return angle::Result::Continue;
1416 }
1417 
invalidate(ContextVk * contextVk,size_t offset,size_t size)1418 angle::Result BufferHelper::invalidate(ContextVk *contextVk, size_t offset, size_t size)
1419 {
1420     bool hostVisible  = mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
1421     bool hostCoherent = mMemoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
1422     if (hostVisible && !hostCoherent)
1423     {
1424         VkMappedMemoryRange range = {};
1425         range.sType               = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
1426         range.memory              = mDeviceMemory.getHandle();
1427         range.offset              = offset;
1428         range.size                = size;
1429         ANGLE_VK_TRY(contextVk, vkInvalidateMappedMemoryRanges(contextVk->getDevice(), 1, &range));
1430     }
1431     return angle::Result::Continue;
1432 }
1433 
1434 // ImageHelper implementation.
ImageHelper()1435 ImageHelper::ImageHelper()
1436     : CommandGraphResource(CommandGraphResourceType::Image),
1437       mFormat(nullptr),
1438       mSamples(0),
1439       mCurrentLayout(ImageLayout::Undefined),
1440       mCurrentQueueFamilyIndex(std::numeric_limits<uint32_t>::max()),
1441       mLayerCount(0),
1442       mLevelCount(0)
1443 {}
1444 
ImageHelper(ImageHelper && other)1445 ImageHelper::ImageHelper(ImageHelper &&other)
1446     : CommandGraphResource(CommandGraphResourceType::Image),
1447       mImage(std::move(other.mImage)),
1448       mDeviceMemory(std::move(other.mDeviceMemory)),
1449       mExtents(other.mExtents),
1450       mFormat(other.mFormat),
1451       mSamples(other.mSamples),
1452       mCurrentLayout(other.mCurrentLayout),
1453       mCurrentQueueFamilyIndex(other.mCurrentQueueFamilyIndex),
1454       mLayerCount(other.mLayerCount),
1455       mLevelCount(other.mLevelCount),
1456       mStagingBuffer(std::move(other.mStagingBuffer)),
1457       mSubresourceUpdates(std::move(other.mSubresourceUpdates))
1458 {
1459     ASSERT(this != &other);
1460     other.mCurrentLayout = ImageLayout::Undefined;
1461     other.mLayerCount    = 0;
1462     other.mLevelCount    = 0;
1463 }
1464 
~ImageHelper()1465 ImageHelper::~ImageHelper()
1466 {
1467     ASSERT(!valid());
1468 }
1469 
initStagingBuffer(RendererVk * renderer,const vk::Format & format,VkBufferUsageFlags usageFlags,size_t initialSize)1470 void ImageHelper::initStagingBuffer(RendererVk *renderer,
1471                                     const vk::Format &format,
1472                                     VkBufferUsageFlags usageFlags,
1473                                     size_t initialSize)
1474 {
1475     mStagingBuffer.init(renderer, usageFlags, format.getImageCopyBufferAlignment(), initialSize,
1476                         true);
1477 }
1478 
init(Context * context,gl::TextureType textureType,const VkExtent3D & extents,const Format & format,GLint samples,VkImageUsageFlags usage,uint32_t mipLevels,uint32_t layerCount)1479 angle::Result ImageHelper::init(Context *context,
1480                                 gl::TextureType textureType,
1481                                 const VkExtent3D &extents,
1482                                 const Format &format,
1483                                 GLint samples,
1484                                 VkImageUsageFlags usage,
1485                                 uint32_t mipLevels,
1486                                 uint32_t layerCount)
1487 {
1488     return initExternal(context, textureType, extents, format, samples, usage,
1489                         ImageLayout::Undefined, nullptr, mipLevels, layerCount);
1490 }
1491 
initExternal(Context * context,gl::TextureType textureType,const VkExtent3D & extents,const Format & format,GLint samples,VkImageUsageFlags usage,ImageLayout initialLayout,const void * externalImageCreateInfo,uint32_t mipLevels,uint32_t layerCount)1492 angle::Result ImageHelper::initExternal(Context *context,
1493                                         gl::TextureType textureType,
1494                                         const VkExtent3D &extents,
1495                                         const Format &format,
1496                                         GLint samples,
1497                                         VkImageUsageFlags usage,
1498                                         ImageLayout initialLayout,
1499                                         const void *externalImageCreateInfo,
1500                                         uint32_t mipLevels,
1501                                         uint32_t layerCount)
1502 {
1503     ASSERT(!valid());
1504 
1505     mExtents    = extents;
1506     mFormat     = &format;
1507     mSamples    = samples;
1508     mLevelCount = mipLevels;
1509     mLayerCount = layerCount;
1510 
1511     // Validate that mLayerCount is compatible with the texture type
1512     ASSERT(textureType != gl::TextureType::_3D || mLayerCount == 1);
1513     ASSERT(textureType != gl::TextureType::_2DArray || mExtents.depth == 1);
1514     ASSERT(textureType != gl::TextureType::External || mLayerCount == 1);
1515     ASSERT(textureType != gl::TextureType::Rectangle || mLayerCount == 1);
1516     ASSERT(textureType != gl::TextureType::CubeMap || mLayerCount == gl::kCubeFaceCount);
1517 
1518     VkImageCreateInfo imageInfo     = {};
1519     imageInfo.sType                 = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1520     imageInfo.pNext                 = externalImageCreateInfo;
1521     imageInfo.flags                 = GetImageCreateFlags(textureType);
1522     imageInfo.imageType             = gl_vk::GetImageType(textureType);
1523     imageInfo.format                = format.vkImageFormat;
1524     imageInfo.extent                = mExtents;
1525     imageInfo.mipLevels             = mipLevels;
1526     imageInfo.arrayLayers           = mLayerCount;
1527     imageInfo.samples               = gl_vk::GetSamples(samples);
1528     imageInfo.tiling                = VK_IMAGE_TILING_OPTIMAL;
1529     imageInfo.usage                 = usage;
1530     imageInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
1531     imageInfo.queueFamilyIndexCount = 0;
1532     imageInfo.pQueueFamilyIndices   = nullptr;
1533     imageInfo.initialLayout         = kImageMemoryBarrierData[initialLayout].layout;
1534 
1535     mCurrentLayout = initialLayout;
1536 
1537     ANGLE_VK_TRY(context, mImage.init(context->getDevice(), imageInfo));
1538 
1539     return angle::Result::Continue;
1540 }
1541 
releaseImage(ContextVk * contextVk)1542 void ImageHelper::releaseImage(ContextVk *contextVk)
1543 {
1544     contextVk->releaseObject(getStoredQueueSerial(), &mImage);
1545     contextVk->releaseObject(getStoredQueueSerial(), &mDeviceMemory);
1546 }
1547 
releaseImage(DisplayVk * display,std::vector<GarbageObjectBase> * garbageQueue)1548 void ImageHelper::releaseImage(DisplayVk *display, std::vector<GarbageObjectBase> *garbageQueue)
1549 {
1550     mImage.dumpResources(garbageQueue);
1551     mDeviceMemory.dumpResources(garbageQueue);
1552 }
1553 
releaseStagingBuffer(ContextVk * contextVk)1554 void ImageHelper::releaseStagingBuffer(ContextVk *contextVk)
1555 {
1556     // Remove updates that never made it to the texture.
1557     for (SubresourceUpdate &update : mSubresourceUpdates)
1558     {
1559         update.release(contextVk);
1560     }
1561     mStagingBuffer.release(contextVk);
1562     mSubresourceUpdates.clear();
1563 }
1564 
releaseStagingBuffer(DisplayVk * display,std::vector<GarbageObjectBase> * garbageQueue)1565 void ImageHelper::releaseStagingBuffer(DisplayVk *display,
1566                                        std::vector<GarbageObjectBase> *garbageQueue)
1567 {
1568     // Remove updates that never made it to the texture.
1569     for (SubresourceUpdate &update : mSubresourceUpdates)
1570     {
1571         update.release(display, garbageQueue);
1572     }
1573     mStagingBuffer.release(display, garbageQueue);
1574     mSubresourceUpdates.clear();
1575 }
1576 
resetImageWeakReference()1577 void ImageHelper::resetImageWeakReference()
1578 {
1579     mImage.reset();
1580 }
1581 
initMemory(Context * context,const MemoryProperties & memoryProperties,VkMemoryPropertyFlags flags)1582 angle::Result ImageHelper::initMemory(Context *context,
1583                                       const MemoryProperties &memoryProperties,
1584                                       VkMemoryPropertyFlags flags)
1585 {
1586     // TODO(jmadill): Memory sub-allocation. http://anglebug.com/2162
1587     ANGLE_TRY(AllocateImageMemory(context, flags, nullptr, &mImage, &mDeviceMemory));
1588     mCurrentQueueFamilyIndex = context->getRenderer()->getQueueFamilyIndex();
1589     return angle::Result::Continue;
1590 }
1591 
initExternalMemory(Context * context,const MemoryProperties & memoryProperties,const VkMemoryRequirements & memoryRequirements,const void * extraAllocationInfo,uint32_t currentQueueFamilyIndex,VkMemoryPropertyFlags flags)1592 angle::Result ImageHelper::initExternalMemory(Context *context,
1593                                               const MemoryProperties &memoryProperties,
1594                                               const VkMemoryRequirements &memoryRequirements,
1595                                               const void *extraAllocationInfo,
1596                                               uint32_t currentQueueFamilyIndex,
1597 
1598                                               VkMemoryPropertyFlags flags)
1599 {
1600     // TODO(jmadill): Memory sub-allocation. http://anglebug.com/2162
1601     ANGLE_TRY(AllocateImageMemoryWithRequirements(context, flags, memoryRequirements,
1602                                                   extraAllocationInfo, &mImage, &mDeviceMemory));
1603     mCurrentQueueFamilyIndex = currentQueueFamilyIndex;
1604     return angle::Result::Continue;
1605 }
1606 
initImageView(Context * context,gl::TextureType textureType,VkImageAspectFlags aspectMask,const gl::SwizzleState & swizzleMap,ImageView * imageViewOut,uint32_t baseMipLevel,uint32_t levelCount)1607 angle::Result ImageHelper::initImageView(Context *context,
1608                                          gl::TextureType textureType,
1609                                          VkImageAspectFlags aspectMask,
1610                                          const gl::SwizzleState &swizzleMap,
1611                                          ImageView *imageViewOut,
1612                                          uint32_t baseMipLevel,
1613                                          uint32_t levelCount)
1614 {
1615     return initLayerImageView(context, textureType, aspectMask, swizzleMap, imageViewOut,
1616                               baseMipLevel, levelCount, 0, mLayerCount);
1617 }
1618 
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)1619 angle::Result ImageHelper::initLayerImageView(Context *context,
1620                                               gl::TextureType textureType,
1621                                               VkImageAspectFlags aspectMask,
1622                                               const gl::SwizzleState &swizzleMap,
1623                                               ImageView *imageViewOut,
1624                                               uint32_t baseMipLevel,
1625                                               uint32_t levelCount,
1626                                               uint32_t baseArrayLayer,
1627                                               uint32_t layerCount)
1628 {
1629     VkImageViewCreateInfo viewInfo = {};
1630     viewInfo.sType                 = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
1631     viewInfo.flags                 = 0;
1632     viewInfo.image                 = mImage.getHandle();
1633     viewInfo.viewType              = gl_vk::GetImageViewType(textureType);
1634     viewInfo.format                = mFormat->vkImageFormat;
1635     if (swizzleMap.swizzleRequired())
1636     {
1637         viewInfo.components.r = gl_vk::GetSwizzle(swizzleMap.swizzleRed);
1638         viewInfo.components.g = gl_vk::GetSwizzle(swizzleMap.swizzleGreen);
1639         viewInfo.components.b = gl_vk::GetSwizzle(swizzleMap.swizzleBlue);
1640         viewInfo.components.a = gl_vk::GetSwizzle(swizzleMap.swizzleAlpha);
1641     }
1642     else
1643     {
1644         viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
1645         viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
1646         viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
1647         viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
1648     }
1649     viewInfo.subresourceRange.aspectMask     = aspectMask;
1650     viewInfo.subresourceRange.baseMipLevel   = baseMipLevel;
1651     viewInfo.subresourceRange.levelCount     = levelCount;
1652     viewInfo.subresourceRange.baseArrayLayer = baseArrayLayer;
1653     viewInfo.subresourceRange.layerCount     = layerCount;
1654 
1655     ANGLE_VK_TRY(context, imageViewOut->init(context->getDevice(), viewInfo));
1656     return angle::Result::Continue;
1657 }
1658 
destroy(VkDevice device)1659 void ImageHelper::destroy(VkDevice device)
1660 {
1661     mImage.destroy(device);
1662     mDeviceMemory.destroy(device);
1663     mCurrentLayout = ImageLayout::Undefined;
1664     mLayerCount    = 0;
1665     mLevelCount    = 0;
1666 }
1667 
init2DWeakReference(VkImage handle,const gl::Extents & glExtents,const Format & format,GLint samples)1668 void ImageHelper::init2DWeakReference(VkImage handle,
1669                                       const gl::Extents &glExtents,
1670                                       const Format &format,
1671                                       GLint samples)
1672 {
1673     ASSERT(!valid());
1674 
1675     gl_vk::GetExtent(glExtents, &mExtents);
1676     mFormat        = &format;
1677     mSamples       = samples;
1678     mCurrentLayout = ImageLayout::Undefined;
1679     mLayerCount    = 1;
1680     mLevelCount    = 1;
1681 
1682     mImage.setHandle(handle);
1683 }
1684 
init2DStaging(Context * context,const MemoryProperties & memoryProperties,const gl::Extents & glExtents,const Format & format,VkImageUsageFlags usage,uint32_t layerCount)1685 angle::Result ImageHelper::init2DStaging(Context *context,
1686                                          const MemoryProperties &memoryProperties,
1687                                          const gl::Extents &glExtents,
1688                                          const Format &format,
1689                                          VkImageUsageFlags usage,
1690                                          uint32_t layerCount)
1691 {
1692     ASSERT(!valid());
1693 
1694     gl_vk::GetExtent(glExtents, &mExtents);
1695     mFormat     = &format;
1696     mSamples    = 1;
1697     mLayerCount = layerCount;
1698     mLevelCount = 1;
1699 
1700     mCurrentLayout = ImageLayout::Undefined;
1701 
1702     VkImageCreateInfo imageInfo     = {};
1703     imageInfo.sType                 = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1704     imageInfo.flags                 = 0;
1705     imageInfo.imageType             = VK_IMAGE_TYPE_2D;
1706     imageInfo.format                = format.vkImageFormat;
1707     imageInfo.extent                = mExtents;
1708     imageInfo.mipLevels             = 1;
1709     imageInfo.arrayLayers           = mLayerCount;
1710     imageInfo.samples               = gl_vk::GetSamples(mSamples);
1711     imageInfo.tiling                = VK_IMAGE_TILING_OPTIMAL;
1712     imageInfo.usage                 = usage;
1713     imageInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
1714     imageInfo.queueFamilyIndexCount = 0;
1715     imageInfo.pQueueFamilyIndices   = nullptr;
1716     imageInfo.initialLayout         = getCurrentLayout();
1717 
1718     ANGLE_VK_TRY(context, mImage.init(context->getDevice(), imageInfo));
1719 
1720     // Allocate and bind device-local memory.
1721     VkMemoryPropertyFlags memoryPropertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
1722     ANGLE_TRY(initMemory(context, memoryProperties, memoryPropertyFlags));
1723 
1724     return angle::Result::Continue;
1725 }
1726 
getAspectFlags() const1727 VkImageAspectFlags ImageHelper::getAspectFlags() const
1728 {
1729     return GetFormatAspectFlags(mFormat->imageFormat());
1730 }
1731 
dumpResources(Serial serial,std::vector<GarbageObject> * garbageQueue)1732 void ImageHelper::dumpResources(Serial serial, std::vector<GarbageObject> *garbageQueue)
1733 {
1734     mImage.dumpResources(serial, garbageQueue);
1735     mDeviceMemory.dumpResources(serial, garbageQueue);
1736 }
1737 
getCurrentLayout() const1738 VkImageLayout ImageHelper::getCurrentLayout() const
1739 {
1740     return kImageMemoryBarrierData[mCurrentLayout].layout;
1741 }
1742 
getLevelExtents2D(uint32_t level) const1743 gl::Extents ImageHelper::getLevelExtents2D(uint32_t level) const
1744 {
1745     uint32_t width  = std::max(mExtents.width >> level, 1u);
1746     uint32_t height = std::max(mExtents.height >> level, 1u);
1747 
1748     return gl::Extents(width, height, 1);
1749 }
1750 
isLayoutChangeNecessary(ImageLayout newLayout) const1751 bool ImageHelper::isLayoutChangeNecessary(ImageLayout newLayout) const
1752 {
1753     const ImageMemoryBarrierData &layoutData = kImageMemoryBarrierData[mCurrentLayout];
1754 
1755     // If transitioning to the same layout, we rarely need a barrier.  RAR (read-after-read)
1756     // doesn't need a barrier, and WAW (write-after-write) is guaranteed to not require a barrier
1757     // for color attachment and depth/stencil attachment writes.  Transfer dst and shader writes
1758     // are basically the only cases where an execution barrier is still necessary.
1759     bool sameLayoutAndNoNeedForBarrier =
1760         mCurrentLayout == newLayout && !layoutData.sameLayoutTransitionRequiresBarrier;
1761 
1762     return !sameLayoutAndNoNeedForBarrier;
1763 }
1764 
changeLayout(VkImageAspectFlags aspectMask,ImageLayout newLayout,vk::CommandBuffer * commandBuffer)1765 void ImageHelper::changeLayout(VkImageAspectFlags aspectMask,
1766                                ImageLayout newLayout,
1767                                vk::CommandBuffer *commandBuffer)
1768 {
1769     if (!isLayoutChangeNecessary(newLayout))
1770     {
1771         return;
1772     }
1773 
1774     forceChangeLayoutAndQueue(aspectMask, newLayout, mCurrentQueueFamilyIndex, commandBuffer);
1775 }
1776 
changeLayoutAndQueue(VkImageAspectFlags aspectMask,ImageLayout newLayout,uint32_t newQueueFamilyIndex,vk::CommandBuffer * commandBuffer)1777 void ImageHelper::changeLayoutAndQueue(VkImageAspectFlags aspectMask,
1778                                        ImageLayout newLayout,
1779                                        uint32_t newQueueFamilyIndex,
1780                                        vk::CommandBuffer *commandBuffer)
1781 {
1782     ASSERT(isQueueChangeNeccesary(newQueueFamilyIndex));
1783     forceChangeLayoutAndQueue(aspectMask, newLayout, newQueueFamilyIndex, commandBuffer);
1784 }
1785 
forceChangeLayoutAndQueue(VkImageAspectFlags aspectMask,ImageLayout newLayout,uint32_t newQueueFamilyIndex,vk::CommandBuffer * commandBuffer)1786 void ImageHelper::forceChangeLayoutAndQueue(VkImageAspectFlags aspectMask,
1787                                             ImageLayout newLayout,
1788                                             uint32_t newQueueFamilyIndex,
1789                                             vk::CommandBuffer *commandBuffer)
1790 {
1791     // If transitioning to the same layout (and there is no queue transfer), an execution barrier
1792     // suffices.
1793     //
1794     // TODO(syoussefi): AMD driver on windows has a bug where an execution barrier is not sufficient
1795     // between transfer dst operations (even if the transfer is not to the same subresource!).  A
1796     // workaround may be necessary.  http://anglebug.com/3554
1797     if (mCurrentLayout == newLayout && mCurrentQueueFamilyIndex == newQueueFamilyIndex &&
1798         mCurrentLayout != ImageLayout::TransferDst)
1799     {
1800         const ImageMemoryBarrierData &transition = kImageMemoryBarrierData[mCurrentLayout];
1801 
1802         // In this case, the image is going to be used in the same way, so the src and dst stage
1803         // masks must be necessarily equal.
1804         ASSERT(transition.srcStageMask == transition.dstStageMask);
1805 
1806         commandBuffer->executionBarrier(transition.dstStageMask);
1807         return;
1808     }
1809 
1810     const ImageMemoryBarrierData &transitionFrom = kImageMemoryBarrierData[mCurrentLayout];
1811     const ImageMemoryBarrierData &transitionTo   = kImageMemoryBarrierData[newLayout];
1812 
1813     VkImageMemoryBarrier imageMemoryBarrier = {};
1814     imageMemoryBarrier.sType                = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1815     imageMemoryBarrier.srcAccessMask        = transitionFrom.srcAccessMask;
1816     imageMemoryBarrier.dstAccessMask        = transitionTo.dstAccessMask;
1817     imageMemoryBarrier.oldLayout            = transitionFrom.layout;
1818     imageMemoryBarrier.newLayout            = transitionTo.layout;
1819     imageMemoryBarrier.srcQueueFamilyIndex  = mCurrentQueueFamilyIndex;
1820     imageMemoryBarrier.dstQueueFamilyIndex  = newQueueFamilyIndex;
1821     imageMemoryBarrier.image                = mImage.getHandle();
1822 
1823     // TODO(jmadill): Is this needed for mipped/layer images?
1824     imageMemoryBarrier.subresourceRange.aspectMask     = aspectMask;
1825     imageMemoryBarrier.subresourceRange.baseMipLevel   = 0;
1826     imageMemoryBarrier.subresourceRange.levelCount     = mLevelCount;
1827     imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
1828     imageMemoryBarrier.subresourceRange.layerCount     = mLayerCount;
1829 
1830     commandBuffer->imageBarrier(transitionFrom.srcStageMask, transitionTo.dstStageMask,
1831                                 &imageMemoryBarrier);
1832     mCurrentLayout           = newLayout;
1833     mCurrentQueueFamilyIndex = newQueueFamilyIndex;
1834 }
1835 
clearColor(const VkClearColorValue & color,uint32_t baseMipLevel,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount,vk::CommandBuffer * commandBuffer)1836 void ImageHelper::clearColor(const VkClearColorValue &color,
1837                              uint32_t baseMipLevel,
1838                              uint32_t levelCount,
1839                              uint32_t baseArrayLayer,
1840                              uint32_t layerCount,
1841                              vk::CommandBuffer *commandBuffer)
1842 {
1843     ASSERT(valid());
1844 
1845     ASSERT(mCurrentLayout == ImageLayout::TransferDst);
1846 
1847     VkImageSubresourceRange range = {};
1848     range.aspectMask              = VK_IMAGE_ASPECT_COLOR_BIT;
1849     range.baseMipLevel            = baseMipLevel;
1850     range.levelCount              = levelCount;
1851     range.baseArrayLayer          = baseArrayLayer;
1852     range.layerCount              = layerCount;
1853 
1854     commandBuffer->clearColorImage(mImage, getCurrentLayout(), color, 1, &range);
1855 }
1856 
clearDepthStencil(VkImageAspectFlags imageAspectFlags,VkImageAspectFlags clearAspectFlags,const VkClearDepthStencilValue & depthStencil,uint32_t baseMipLevel,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount,vk::CommandBuffer * commandBuffer)1857 void ImageHelper::clearDepthStencil(VkImageAspectFlags imageAspectFlags,
1858                                     VkImageAspectFlags clearAspectFlags,
1859                                     const VkClearDepthStencilValue &depthStencil,
1860                                     uint32_t baseMipLevel,
1861                                     uint32_t levelCount,
1862                                     uint32_t baseArrayLayer,
1863                                     uint32_t layerCount,
1864                                     vk::CommandBuffer *commandBuffer)
1865 {
1866     ASSERT(valid());
1867 
1868     ASSERT(mCurrentLayout == ImageLayout::TransferDst);
1869 
1870     VkImageSubresourceRange clearRange = {
1871         /*aspectMask*/ clearAspectFlags,
1872         /*baseMipLevel*/ baseMipLevel,
1873         /*levelCount*/ levelCount,
1874         /*baseArrayLayer*/ baseArrayLayer,
1875         /*layerCount*/ layerCount,
1876     };
1877 
1878     commandBuffer->clearDepthStencilImage(mImage, getCurrentLayout(), depthStencil, 1, &clearRange);
1879 }
1880 
clear(const VkClearValue & value,uint32_t mipLevel,uint32_t baseArrayLayer,uint32_t layerCount,vk::CommandBuffer * commandBuffer)1881 void ImageHelper::clear(const VkClearValue &value,
1882                         uint32_t mipLevel,
1883                         uint32_t baseArrayLayer,
1884                         uint32_t layerCount,
1885                         vk::CommandBuffer *commandBuffer)
1886 {
1887     const angle::Format &angleFormat = mFormat->angleFormat();
1888     bool isDepthStencil              = angleFormat.depthBits > 0 || angleFormat.stencilBits > 0;
1889 
1890     if (isDepthStencil)
1891     {
1892         const VkImageAspectFlags aspect = vk::GetDepthStencilAspectFlags(mFormat->imageFormat());
1893         clearDepthStencil(aspect, aspect, value.depthStencil, mipLevel, 1, baseArrayLayer,
1894                           layerCount, commandBuffer);
1895     }
1896     else
1897     {
1898         clearColor(value.color, mipLevel, 1, baseArrayLayer, layerCount, commandBuffer);
1899     }
1900 }
1901 
getSize(const gl::ImageIndex & index) const1902 gl::Extents ImageHelper::getSize(const gl::ImageIndex &index) const
1903 {
1904     GLint mipLevel = index.getLevelIndex();
1905     // Level 0 should be the size of the extents, after that every time you increase a level
1906     // you shrink the extents by half.
1907     return gl::Extents(std::max(1u, mExtents.width >> mipLevel),
1908                        std::max(1u, mExtents.height >> mipLevel), mExtents.depth);
1909 }
1910 
1911 // static
Copy(ImageHelper * srcImage,ImageHelper * dstImage,const gl::Offset & srcOffset,const gl::Offset & dstOffset,const gl::Extents & copySize,const VkImageSubresourceLayers & srcSubresource,const VkImageSubresourceLayers & dstSubresource,vk::CommandBuffer * commandBuffer)1912 void ImageHelper::Copy(ImageHelper *srcImage,
1913                        ImageHelper *dstImage,
1914                        const gl::Offset &srcOffset,
1915                        const gl::Offset &dstOffset,
1916                        const gl::Extents &copySize,
1917                        const VkImageSubresourceLayers &srcSubresource,
1918                        const VkImageSubresourceLayers &dstSubresource,
1919                        vk::CommandBuffer *commandBuffer)
1920 {
1921     ASSERT(commandBuffer->valid() && srcImage->valid() && dstImage->valid());
1922 
1923     ASSERT(srcImage->getCurrentLayout() == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
1924     ASSERT(dstImage->getCurrentLayout() == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
1925 
1926     VkImageCopy region    = {};
1927     region.srcSubresource = srcSubresource;
1928     region.srcOffset.x    = srcOffset.x;
1929     region.srcOffset.y    = srcOffset.y;
1930     region.srcOffset.z    = srcOffset.z;
1931     region.dstSubresource = dstSubresource;
1932     region.dstOffset.x    = dstOffset.x;
1933     region.dstOffset.y    = dstOffset.y;
1934     region.dstOffset.z    = dstOffset.z;
1935     region.extent.width   = copySize.width;
1936     region.extent.height  = copySize.height;
1937     region.extent.depth   = copySize.depth;
1938 
1939     commandBuffer->copyImage(srcImage->getImage(), srcImage->getCurrentLayout(),
1940                              dstImage->getImage(), dstImage->getCurrentLayout(), 1, &region);
1941 }
1942 
generateMipmapsWithBlit(ContextVk * contextVk,GLuint maxLevel)1943 angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk, GLuint maxLevel)
1944 {
1945     vk::CommandBuffer *commandBuffer = nullptr;
1946     ANGLE_TRY(recordCommands(contextVk, &commandBuffer));
1947 
1948     changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, ImageLayout::TransferDst, commandBuffer);
1949 
1950     // We are able to use blitImage since the image format we are using supports it. This
1951     // is a faster way we can generate the mips.
1952     int32_t mipWidth  = mExtents.width;
1953     int32_t mipHeight = mExtents.height;
1954 
1955     // Manually manage the image memory barrier because it uses a lot more parameters than our
1956     // usual one.
1957     VkImageMemoryBarrier barrier            = {};
1958     barrier.sType                           = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
1959     barrier.image                           = mImage.getHandle();
1960     barrier.srcQueueFamilyIndex             = VK_QUEUE_FAMILY_IGNORED;
1961     barrier.dstQueueFamilyIndex             = VK_QUEUE_FAMILY_IGNORED;
1962     barrier.subresourceRange.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
1963     barrier.subresourceRange.baseArrayLayer = 0;
1964     barrier.subresourceRange.layerCount     = mLayerCount;
1965     barrier.subresourceRange.levelCount     = 1;
1966 
1967     for (uint32_t mipLevel = 1; mipLevel <= maxLevel; mipLevel++)
1968     {
1969         int32_t nextMipWidth  = std::max<int32_t>(1, mipWidth >> 1);
1970         int32_t nextMipHeight = std::max<int32_t>(1, mipHeight >> 1);
1971 
1972         barrier.subresourceRange.baseMipLevel = mipLevel - 1;
1973         barrier.oldLayout                     = getCurrentLayout();
1974         barrier.newLayout                     = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
1975         barrier.srcAccessMask                 = VK_ACCESS_TRANSFER_WRITE_BIT;
1976         barrier.dstAccessMask                 = VK_ACCESS_TRANSFER_READ_BIT;
1977 
1978         // We can do it for all layers at once.
1979         commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
1980                                     &barrier);
1981         VkImageBlit blit                   = {};
1982         blit.srcOffsets[0]                 = {0, 0, 0};
1983         blit.srcOffsets[1]                 = {mipWidth, mipHeight, 1};
1984         blit.srcSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
1985         blit.srcSubresource.mipLevel       = mipLevel - 1;
1986         blit.srcSubresource.baseArrayLayer = 0;
1987         blit.srcSubresource.layerCount     = mLayerCount;
1988         blit.dstOffsets[0]                 = {0, 0, 0};
1989         blit.dstOffsets[1]                 = {nextMipWidth, nextMipHeight, 1};
1990         blit.dstSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
1991         blit.dstSubresource.mipLevel       = mipLevel;
1992         blit.dstSubresource.baseArrayLayer = 0;
1993         blit.dstSubresource.layerCount     = mLayerCount;
1994 
1995         mipWidth  = nextMipWidth;
1996         mipHeight = nextMipHeight;
1997 
1998         commandBuffer->blitImage(mImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, mImage,
1999                                  VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_LINEAR);
2000     }
2001 
2002     // Transition the last mip level to the same layout as all the other ones, so we can declare
2003     // our whole image layout to be SRC_OPTIMAL.
2004     barrier.subresourceRange.baseMipLevel = maxLevel;
2005     barrier.oldLayout                     = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
2006     barrier.newLayout                     = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
2007 
2008     // We can do it for all layers at once.
2009     commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
2010                                 &barrier);
2011     // This is just changing the internal state of the image helper so that the next call
2012     // to changeLayout will use this layout as the "oldLayout" argument.
2013     mCurrentLayout = ImageLayout::TransferSrc;
2014 
2015     return angle::Result::Continue;
2016 }
2017 
resolve(ImageHelper * dest,const VkImageResolve & region,vk::CommandBuffer * commandBuffer)2018 void ImageHelper::resolve(ImageHelper *dest,
2019                           const VkImageResolve &region,
2020                           vk::CommandBuffer *commandBuffer)
2021 {
2022     ASSERT(mCurrentLayout == vk::ImageLayout::TransferSrc);
2023     dest->changeLayout(region.dstSubresource.aspectMask, vk::ImageLayout::TransferDst,
2024                        commandBuffer);
2025 
2026     commandBuffer->resolveImage(getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dest->getImage(),
2027                                 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
2028 }
2029 
removeStagedUpdates(ContextVk * contextVk,const gl::ImageIndex & index)2030 void ImageHelper::removeStagedUpdates(ContextVk *contextVk, const gl::ImageIndex &index)
2031 {
2032     // Find any staged updates for this index and removes them from the pending list.
2033     uint32_t levelIndex = index.getLevelIndex();
2034     uint32_t layerIndex = index.hasLayer() ? index.getLayerIndex() : 0;
2035 
2036     for (size_t index = 0; index < mSubresourceUpdates.size();)
2037     {
2038         auto update = mSubresourceUpdates.begin() + index;
2039         if (update->isUpdateToLayerLevel(layerIndex, levelIndex))
2040         {
2041             update->release(contextVk);
2042             mSubresourceUpdates.erase(update);
2043         }
2044         else
2045         {
2046             index++;
2047         }
2048     }
2049 }
2050 
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 vk::Format & vkFormat)2051 angle::Result ImageHelper::stageSubresourceUpdate(ContextVk *contextVk,
2052                                                   const gl::ImageIndex &index,
2053                                                   const gl::Extents &glExtents,
2054                                                   const gl::Offset &offset,
2055                                                   const gl::InternalFormat &formatInfo,
2056                                                   const gl::PixelUnpackState &unpack,
2057                                                   GLenum type,
2058                                                   const uint8_t *pixels,
2059                                                   const vk::Format &vkFormat)
2060 {
2061     GLuint inputRowPitch = 0;
2062     ANGLE_VK_CHECK_MATH(contextVk,
2063                         formatInfo.computeRowPitch(type, glExtents.width, unpack.alignment,
2064                                                    unpack.rowLength, &inputRowPitch));
2065 
2066     GLuint inputDepthPitch = 0;
2067     ANGLE_VK_CHECK_MATH(
2068         contextVk, formatInfo.computeDepthPitch(glExtents.height, unpack.imageHeight, inputRowPitch,
2069                                                 &inputDepthPitch));
2070 
2071     GLuint inputSkipBytes = 0;
2072     ANGLE_VK_CHECK_MATH(contextVk,
2073                         formatInfo.computeSkipBytes(type, inputRowPitch, inputDepthPitch, unpack,
2074                                                     index.usesTex3D(), &inputSkipBytes));
2075 
2076     const angle::Format &storageFormat = vkFormat.imageFormat();
2077 
2078     size_t outputRowPitch;
2079     size_t outputDepthPitch;
2080     size_t stencilAllocationSize = 0;
2081     uint32_t bufferRowLength;
2082     uint32_t bufferImageHeight;
2083     size_t allocationSize;
2084 
2085     LoadImageFunctionInfo loadFunctionInfo = vkFormat.textureLoadFunctions(type);
2086     LoadImageFunction stencilLoadFunction  = nullptr;
2087 
2088     if (storageFormat.isBlock)
2089     {
2090         const gl::InternalFormat &storageFormatInfo = vkFormat.getInternalFormatInfo(type);
2091         GLuint rowPitch;
2092         GLuint depthPitch;
2093         GLuint totalSize;
2094 
2095         ANGLE_VK_CHECK_MATH(contextVk, storageFormatInfo.computeCompressedImageSize(
2096                                            gl::Extents(glExtents.width, 1, 1), &rowPitch));
2097         ANGLE_VK_CHECK_MATH(contextVk,
2098                             storageFormatInfo.computeCompressedImageSize(
2099                                 gl::Extents(glExtents.width, glExtents.height, 1), &depthPitch));
2100 
2101         ANGLE_VK_CHECK_MATH(contextVk,
2102                             storageFormatInfo.computeCompressedImageSize(glExtents, &totalSize));
2103 
2104         outputRowPitch   = rowPitch;
2105         outputDepthPitch = depthPitch;
2106 
2107         angle::CheckedNumeric<uint32_t> checkedRowLength =
2108             rx::CheckedRoundUp<uint32_t>(glExtents.width, storageFormatInfo.compressedBlockWidth);
2109         angle::CheckedNumeric<uint32_t> checkedImageHeight =
2110             rx::CheckedRoundUp<uint32_t>(glExtents.height, storageFormatInfo.compressedBlockHeight);
2111 
2112         ANGLE_VK_CHECK_MATH(contextVk, checkedRowLength.IsValid());
2113         ANGLE_VK_CHECK_MATH(contextVk, checkedImageHeight.IsValid());
2114 
2115         bufferRowLength   = checkedRowLength.ValueOrDie();
2116         bufferImageHeight = checkedImageHeight.ValueOrDie();
2117         allocationSize    = totalSize;
2118     }
2119     else
2120     {
2121         ASSERT(storageFormat.pixelBytes != 0);
2122 
2123         if (storageFormat.id == angle::FormatID::D24_UNORM_S8_UINT)
2124         {
2125             stencilLoadFunction = angle::LoadX24S8ToS8;
2126         }
2127         if (storageFormat.id == angle::FormatID::D32_FLOAT_S8X24_UINT)
2128         {
2129             // If depth is D32FLOAT_S8, we must pack D32F tightly (no stencil) for CopyBufferToImage
2130             outputRowPitch = sizeof(float) * glExtents.width;
2131 
2132             // The generic load functions don't handle tightly packing D32FS8 to D32F & S8 so call
2133             // special case load functions.
2134             loadFunctionInfo.loadFunction = angle::LoadD32FS8X24ToD32F;
2135             stencilLoadFunction           = angle::LoadX32S8ToS8;
2136         }
2137         else
2138         {
2139             outputRowPitch = storageFormat.pixelBytes * glExtents.width;
2140         }
2141         outputDepthPitch = outputRowPitch * glExtents.height;
2142 
2143         bufferRowLength   = glExtents.width;
2144         bufferImageHeight = glExtents.height;
2145 
2146         allocationSize = outputDepthPitch * glExtents.depth;
2147 
2148         // Note: because the LoadImageFunctionInfo functions are limited to copying a single
2149         // component, we have to special case packed depth/stencil use and send the stencil as a
2150         // separate chunk.
2151         if (storageFormat.depthBits > 0 && storageFormat.stencilBits > 0 &&
2152             formatInfo.depthBits > 0 && formatInfo.stencilBits > 0)
2153         {
2154             // Note: Stencil is always one byte
2155             stencilAllocationSize = glExtents.width * glExtents.height * glExtents.depth;
2156             allocationSize += stencilAllocationSize;
2157         }
2158     }
2159 
2160     VkBuffer bufferHandle = VK_NULL_HANDLE;
2161 
2162     uint8_t *stagingPointer    = nullptr;
2163     VkDeviceSize stagingOffset = 0;
2164     ANGLE_TRY(mStagingBuffer.allocate(contextVk, allocationSize, &stagingPointer, &bufferHandle,
2165                                       &stagingOffset, nullptr));
2166 
2167     const uint8_t *source = pixels + static_cast<ptrdiff_t>(inputSkipBytes);
2168 
2169     loadFunctionInfo.loadFunction(glExtents.width, glExtents.height, glExtents.depth, source,
2170                                   inputRowPitch, inputDepthPitch, stagingPointer, outputRowPitch,
2171                                   outputDepthPitch);
2172 
2173     VkBufferImageCopy copy         = {};
2174     VkImageAspectFlags aspectFlags = GetFormatAspectFlags(vkFormat.imageFormat());
2175 
2176     copy.bufferOffset      = stagingOffset;
2177     copy.bufferRowLength   = bufferRowLength;
2178     copy.bufferImageHeight = bufferImageHeight;
2179 
2180     copy.imageSubresource.mipLevel   = index.getLevelIndex();
2181     copy.imageSubresource.layerCount = index.getLayerCount();
2182 
2183     gl_vk::GetOffset(offset, &copy.imageOffset);
2184     gl_vk::GetExtent(glExtents, &copy.imageExtent);
2185 
2186     if (gl::IsArrayTextureType(index.getType()))
2187     {
2188         copy.imageSubresource.baseArrayLayer = offset.z;
2189         copy.imageOffset.z                   = 0;
2190         copy.imageExtent.depth               = 1;
2191     }
2192     else
2193     {
2194         copy.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
2195     }
2196 
2197     if (stencilAllocationSize > 0)
2198     {
2199         // Note: Stencil is always one byte
2200         ASSERT((aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) != 0);
2201 
2202         // Skip over depth data.
2203         stagingPointer += outputDepthPitch * glExtents.depth;
2204         stagingOffset += outputDepthPitch * glExtents.depth;
2205 
2206         // recompute pitch for stencil data
2207         outputRowPitch   = glExtents.width;
2208         outputDepthPitch = outputRowPitch * glExtents.height;
2209 
2210         ASSERT(stencilLoadFunction != nullptr);
2211         stencilLoadFunction(glExtents.width, glExtents.height, glExtents.depth, source,
2212                             inputRowPitch, inputDepthPitch, stagingPointer, outputRowPitch,
2213                             outputDepthPitch);
2214 
2215         VkBufferImageCopy stencilCopy = {};
2216 
2217         stencilCopy.bufferOffset                    = stagingOffset;
2218         stencilCopy.bufferRowLength                 = bufferRowLength;
2219         stencilCopy.bufferImageHeight               = bufferImageHeight;
2220         stencilCopy.imageSubresource.mipLevel       = copy.imageSubresource.mipLevel;
2221         stencilCopy.imageSubresource.baseArrayLayer = copy.imageSubresource.baseArrayLayer;
2222         stencilCopy.imageSubresource.layerCount     = copy.imageSubresource.layerCount;
2223         stencilCopy.imageOffset                     = copy.imageOffset;
2224         stencilCopy.imageExtent                     = copy.imageExtent;
2225         stencilCopy.imageSubresource.aspectMask     = VK_IMAGE_ASPECT_STENCIL_BIT;
2226         mSubresourceUpdates.emplace_back(bufferHandle, stencilCopy);
2227 
2228         aspectFlags &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
2229     }
2230 
2231     if (IsMaskFlagSet(aspectFlags, static_cast<VkImageAspectFlags>(VK_IMAGE_ASPECT_STENCIL_BIT |
2232                                                                    VK_IMAGE_ASPECT_DEPTH_BIT)))
2233     {
2234         // We still have both depth and stencil aspect bits set. That means we have a destination
2235         // buffer that is packed depth stencil and that the application is only loading one aspect.
2236         // Figure out which aspect the user is touching and remove the unused aspect bit.
2237         if (formatInfo.stencilBits > 0)
2238         {
2239             aspectFlags &= ~VK_IMAGE_ASPECT_DEPTH_BIT;
2240         }
2241         else
2242         {
2243             aspectFlags &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
2244         }
2245     }
2246 
2247     if (aspectFlags)
2248     {
2249         copy.imageSubresource.aspectMask = aspectFlags;
2250         mSubresourceUpdates.emplace_back(bufferHandle, copy);
2251     }
2252 
2253     return angle::Result::Continue;
2254 }
2255 
stageSubresourceUpdateAndGetData(ContextVk * contextVk,size_t allocationSize,const gl::ImageIndex & imageIndex,const gl::Extents & glExtents,const gl::Offset & offset,uint8_t ** destData)2256 angle::Result ImageHelper::stageSubresourceUpdateAndGetData(ContextVk *contextVk,
2257                                                             size_t allocationSize,
2258                                                             const gl::ImageIndex &imageIndex,
2259                                                             const gl::Extents &glExtents,
2260                                                             const gl::Offset &offset,
2261                                                             uint8_t **destData)
2262 {
2263     VkBuffer bufferHandle;
2264     VkDeviceSize stagingOffset = 0;
2265     ANGLE_TRY(mStagingBuffer.allocate(contextVk, allocationSize, destData, &bufferHandle,
2266                                       &stagingOffset, nullptr));
2267 
2268     VkBufferImageCopy copy               = {};
2269     copy.bufferOffset                    = stagingOffset;
2270     copy.bufferRowLength                 = glExtents.width;
2271     copy.bufferImageHeight               = glExtents.height;
2272     copy.imageSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
2273     copy.imageSubresource.mipLevel       = imageIndex.getLevelIndex();
2274     copy.imageSubresource.baseArrayLayer = imageIndex.hasLayer() ? imageIndex.getLayerIndex() : 0;
2275     copy.imageSubresource.layerCount     = imageIndex.getLayerCount();
2276 
2277     // Note: Only support color now
2278     ASSERT(getAspectFlags() == VK_IMAGE_ASPECT_COLOR_BIT);
2279 
2280     gl_vk::GetOffset(offset, &copy.imageOffset);
2281     gl_vk::GetExtent(glExtents, &copy.imageExtent);
2282 
2283     mSubresourceUpdates.emplace_back(bufferHandle, copy);
2284 
2285     return angle::Result::Continue;
2286 }
2287 
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)2288 angle::Result ImageHelper::stageSubresourceUpdateFromFramebuffer(
2289     const gl::Context *context,
2290     const gl::ImageIndex &index,
2291     const gl::Rectangle &sourceArea,
2292     const gl::Offset &dstOffset,
2293     const gl::Extents &dstExtent,
2294     const gl::InternalFormat &formatInfo,
2295     FramebufferVk *framebufferVk)
2296 {
2297     ContextVk *contextVk = vk::GetImpl(context);
2298 
2299     // If the extents and offset is outside the source image, we need to clip.
2300     gl::Rectangle clippedRectangle;
2301     const gl::Extents readExtents = framebufferVk->getReadImageExtents();
2302     if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, readExtents.width, readExtents.height),
2303                        &clippedRectangle))
2304     {
2305         // Empty source area, nothing to do.
2306         return angle::Result::Continue;
2307     }
2308 
2309     bool isViewportFlipEnabled = contextVk->isViewportFlipEnabledForDrawFBO();
2310     if (isViewportFlipEnabled)
2311     {
2312         clippedRectangle.y = readExtents.height - clippedRectangle.y - clippedRectangle.height;
2313     }
2314 
2315     // 1- obtain a buffer handle to copy to
2316     RendererVk *renderer = contextVk->getRenderer();
2317 
2318     const vk::Format &vkFormat         = renderer->getFormat(formatInfo.sizedInternalFormat);
2319     const angle::Format &storageFormat = vkFormat.imageFormat();
2320     LoadImageFunctionInfo loadFunction = vkFormat.textureLoadFunctions(formatInfo.type);
2321 
2322     size_t outputRowPitch   = storageFormat.pixelBytes * clippedRectangle.width;
2323     size_t outputDepthPitch = outputRowPitch * clippedRectangle.height;
2324 
2325     VkBuffer bufferHandle = VK_NULL_HANDLE;
2326 
2327     uint8_t *stagingPointer    = nullptr;
2328     VkDeviceSize stagingOffset = 0;
2329 
2330     // The destination is only one layer deep.
2331     size_t allocationSize = outputDepthPitch;
2332     ANGLE_TRY(mStagingBuffer.allocate(contextVk, allocationSize, &stagingPointer, &bufferHandle,
2333                                       &stagingOffset, nullptr));
2334 
2335     const angle::Format &copyFormat =
2336         GetFormatFromFormatType(formatInfo.internalFormat, formatInfo.type);
2337     PackPixelsParams params(clippedRectangle, copyFormat, static_cast<GLuint>(outputRowPitch),
2338                             isViewportFlipEnabled, nullptr, 0);
2339 
2340     // 2- copy the source image region to the pixel buffer using a cpu readback
2341     if (loadFunction.requiresConversion)
2342     {
2343         // When a conversion is required, we need to use the loadFunction to read from a temporary
2344         // buffer instead so its an even slower path.
2345         size_t bufferSize =
2346             storageFormat.pixelBytes * clippedRectangle.width * clippedRectangle.height;
2347         angle::MemoryBuffer *memoryBuffer = nullptr;
2348         ANGLE_VK_CHECK_ALLOC(contextVk, context->getScratchBuffer(bufferSize, &memoryBuffer));
2349 
2350         // Read into the scratch buffer
2351         ANGLE_TRY(framebufferVk->readPixelsImpl(
2352             contextVk, clippedRectangle, params, VK_IMAGE_ASPECT_COLOR_BIT,
2353             framebufferVk->getColorReadRenderTarget(), memoryBuffer->data()));
2354 
2355         // Load from scratch buffer to our pixel buffer
2356         loadFunction.loadFunction(clippedRectangle.width, clippedRectangle.height, 1,
2357                                   memoryBuffer->data(), outputRowPitch, 0, stagingPointer,
2358                                   outputRowPitch, 0);
2359     }
2360     else
2361     {
2362         // We read directly from the framebuffer into our pixel buffer.
2363         ANGLE_TRY(framebufferVk->readPixelsImpl(
2364             contextVk, clippedRectangle, params, VK_IMAGE_ASPECT_COLOR_BIT,
2365             framebufferVk->getColorReadRenderTarget(), stagingPointer));
2366     }
2367 
2368     // 3- enqueue the destination image subresource update
2369     VkBufferImageCopy copyToImage               = {};
2370     copyToImage.bufferOffset                    = static_cast<VkDeviceSize>(stagingOffset);
2371     copyToImage.bufferRowLength                 = 0;  // Tightly packed data can be specified as 0.
2372     copyToImage.bufferImageHeight               = clippedRectangle.height;
2373     copyToImage.imageSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
2374     copyToImage.imageSubresource.mipLevel       = index.getLevelIndex();
2375     copyToImage.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
2376     copyToImage.imageSubresource.layerCount     = index.getLayerCount();
2377     gl_vk::GetOffset(dstOffset, &copyToImage.imageOffset);
2378     gl_vk::GetExtent(dstExtent, &copyToImage.imageExtent);
2379 
2380     // 3- enqueue the destination image subresource update
2381     mSubresourceUpdates.emplace_back(bufferHandle, copyToImage);
2382     return angle::Result::Continue;
2383 }
2384 
stageSubresourceUpdateFromImage(vk::ImageHelper * image,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Extents & glExtents,const VkImageType imageType)2385 void ImageHelper::stageSubresourceUpdateFromImage(vk::ImageHelper *image,
2386                                                   const gl::ImageIndex &index,
2387                                                   const gl::Offset &destOffset,
2388                                                   const gl::Extents &glExtents,
2389                                                   const VkImageType imageType)
2390 {
2391     VkImageCopy copyToImage                   = {};
2392     copyToImage.srcSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
2393     copyToImage.srcSubresource.layerCount     = index.getLayerCount();
2394     copyToImage.dstSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
2395     copyToImage.dstSubresource.mipLevel       = index.getLevelIndex();
2396 
2397     if (imageType == VK_IMAGE_TYPE_3D)
2398     {
2399         // These values must be set explicitly to follow the Vulkan spec:
2400         // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkImageCopy.html
2401         // If either of the calling command’s srcImage or dstImage parameters are of VkImageType
2402         // VK_IMAGE_TYPE_3D, the baseArrayLayer and layerCount members of the corresponding
2403         // subresource must be 0 and 1, respectively
2404         copyToImage.dstSubresource.baseArrayLayer = 0;
2405         copyToImage.dstSubresource.layerCount     = 1;
2406         // Preserve the assumption that destOffset.z == "dstSubresource.baseArrayLayer"
2407         ASSERT(destOffset.z == (index.hasLayer() ? index.getLayerIndex() : 0));
2408     }
2409     else
2410     {
2411         copyToImage.dstSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
2412         copyToImage.dstSubresource.layerCount     = index.getLayerCount();
2413     }
2414 
2415     gl_vk::GetOffset(destOffset, &copyToImage.dstOffset);
2416     gl_vk::GetExtent(glExtents, &copyToImage.extent);
2417 
2418     mSubresourceUpdates.emplace_back(image, copyToImage);
2419 }
2420 
stageSubresourceRobustClear(const gl::ImageIndex & index,const angle::Format & format)2421 void ImageHelper::stageSubresourceRobustClear(const gl::ImageIndex &index,
2422                                               const angle::Format &format)
2423 {
2424     stageSubresourceClear(index, format, kWebGLInitColorValue, kWebGLInitDepthStencilValue);
2425 }
2426 
stageSubresourceEmulatedClear(const gl::ImageIndex & index,const angle::Format & format)2427 void ImageHelper::stageSubresourceEmulatedClear(const gl::ImageIndex &index,
2428                                                 const angle::Format &format)
2429 {
2430     stageSubresourceClear(index, format, kEmulatedInitColorValue, kWebGLInitDepthStencilValue);
2431 }
2432 
stageClearIfEmulatedFormat(const gl::ImageIndex & index,const Format & format)2433 void ImageHelper::stageClearIfEmulatedFormat(const gl::ImageIndex &index, const Format &format)
2434 {
2435     if (format.hasEmulatedImageChannels())
2436     {
2437         stageSubresourceEmulatedClear(index, format.angleFormat());
2438     }
2439 }
2440 
stageSubresourceClear(const gl::ImageIndex & index,const angle::Format & format,const VkClearColorValue & colorValue,const VkClearDepthStencilValue & depthStencilValue)2441 void ImageHelper::stageSubresourceClear(const gl::ImageIndex &index,
2442                                         const angle::Format &format,
2443                                         const VkClearColorValue &colorValue,
2444                                         const VkClearDepthStencilValue &depthStencilValue)
2445 {
2446     VkClearValue clearValue;
2447 
2448     bool isDepthStencil = format.depthBits > 0 || format.stencilBits > 0;
2449     if (isDepthStencil)
2450     {
2451         clearValue.depthStencil = depthStencilValue;
2452     }
2453     else
2454     {
2455         clearValue.color = colorValue;
2456     }
2457 
2458     // Note that clears can arrive out of order from the front-end with respect to staged changes,
2459     // but they are intended to be done first.
2460     mSubresourceUpdates.emplace(mSubresourceUpdates.begin(), clearValue, index);
2461 }
2462 
allocateStagingMemory(ContextVk * contextVk,size_t sizeInBytes,uint8_t ** ptrOut,VkBuffer * handleOut,VkDeviceSize * offsetOut,bool * newBufferAllocatedOut)2463 angle::Result ImageHelper::allocateStagingMemory(ContextVk *contextVk,
2464                                                  size_t sizeInBytes,
2465                                                  uint8_t **ptrOut,
2466                                                  VkBuffer *handleOut,
2467                                                  VkDeviceSize *offsetOut,
2468                                                  bool *newBufferAllocatedOut)
2469 {
2470     return mStagingBuffer.allocate(contextVk, sizeInBytes, ptrOut, handleOut, offsetOut,
2471                                    newBufferAllocatedOut);
2472 }
2473 
flushStagedUpdates(ContextVk * contextVk,uint32_t levelStart,uint32_t levelEnd,uint32_t layerStart,uint32_t layerEnd,vk::CommandBuffer * commandBuffer)2474 angle::Result ImageHelper::flushStagedUpdates(ContextVk *contextVk,
2475                                               uint32_t levelStart,
2476                                               uint32_t levelEnd,
2477                                               uint32_t layerStart,
2478                                               uint32_t layerEnd,
2479                                               vk::CommandBuffer *commandBuffer)
2480 {
2481     if (mSubresourceUpdates.empty())
2482     {
2483         return angle::Result::Continue;
2484     }
2485 
2486     ANGLE_TRY(mStagingBuffer.flush(contextVk));
2487 
2488     std::vector<SubresourceUpdate> updatesToKeep;
2489     const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(mFormat->imageFormat());
2490 
2491     // Upload levels and layers that don't conflict in parallel.  The (level, layer) pair is hashed
2492     // to `(level * mLayerCount + layer) % 64` and used to track whether that subresource is
2493     // currently in transfer.  If so, a barrier is inserted.  If mLayerCount * mLevelCount > 64,
2494     // there will be a few unnecessary barriers.
2495     constexpr uint32_t kMaxParallelSubresourceUpload = 64;
2496     uint64_t subresourceUploadsInProgress            = 0;
2497 
2498     // Start in TransferDst.
2499     changeLayout(aspectFlags, vk::ImageLayout::TransferDst, commandBuffer);
2500 
2501     for (SubresourceUpdate &update : mSubresourceUpdates)
2502     {
2503         ASSERT(update.updateSource == SubresourceUpdate::UpdateSource::Clear ||
2504                (update.updateSource == SubresourceUpdate::UpdateSource::Buffer &&
2505                 update.buffer.bufferHandle != VK_NULL_HANDLE) ||
2506                (update.updateSource == SubresourceUpdate::UpdateSource::Image &&
2507                 update.image.image != nullptr && update.image.image->valid()));
2508 
2509         uint32_t updateMipLevel;
2510         uint32_t updateBaseLayer;
2511         uint32_t updateLayerCount;
2512         if (update.updateSource == SubresourceUpdate::UpdateSource::Clear)
2513         {
2514             updateMipLevel   = update.clear.levelIndex;
2515             updateBaseLayer  = update.clear.layerIndex;
2516             updateLayerCount = update.clear.layerCount;
2517             if (updateLayerCount == static_cast<uint32_t>(gl::ImageIndex::kEntireLevel))
2518             {
2519                 updateLayerCount = mLayerCount;
2520             }
2521         }
2522         else
2523         {
2524             const VkImageSubresourceLayers &dstSubresource = update.dstSubresource();
2525             updateMipLevel                                 = dstSubresource.mipLevel;
2526             updateBaseLayer                                = dstSubresource.baseArrayLayer;
2527             updateLayerCount                               = dstSubresource.layerCount;
2528             ASSERT(updateLayerCount != static_cast<uint32_t>(gl::ImageIndex::kEntireLevel));
2529         }
2530 
2531         // If the update level is not within the requested range, skip the update.
2532         const bool isUpdateLevelOutsideRange =
2533             updateMipLevel < levelStart || updateMipLevel >= levelEnd;
2534         // If the update layers don't intersect the requested layers, skip the update.
2535         const bool areUpdateLayersOutsideRange =
2536             updateBaseLayer + updateLayerCount <= layerStart || updateBaseLayer >= layerEnd;
2537 
2538         if (isUpdateLevelOutsideRange || areUpdateLayersOutsideRange)
2539         {
2540             updatesToKeep.emplace_back(update);
2541             continue;
2542         }
2543 
2544         if (updateLayerCount >= kMaxParallelSubresourceUpload)
2545         {
2546             // If there are more subresources than bits we can track, always insert a barrier.
2547             changeLayout(aspectFlags, vk::ImageLayout::TransferDst, commandBuffer);
2548             subresourceUploadsInProgress = std::numeric_limits<uint64_t>::max();
2549         }
2550         else
2551         {
2552             const uint64_t subresourceHashRange = angle::Bit<uint64_t>(updateLayerCount) - 1;
2553             const uint32_t subresourceHashOffset =
2554                 (updateMipLevel * mLayerCount + updateBaseLayer) % kMaxParallelSubresourceUpload;
2555             const uint64_t subresourceHash =
2556                 ANGLE_ROTL64(subresourceHashRange, subresourceHashOffset);
2557 
2558             if ((subresourceUploadsInProgress & subresourceHash) != 0)
2559             {
2560                 // If there's overlap in subresource upload, issue a barrier.
2561                 changeLayout(aspectFlags, vk::ImageLayout::TransferDst, commandBuffer);
2562                 subresourceUploadsInProgress = 0;
2563             }
2564             subresourceUploadsInProgress |= subresourceHash;
2565         }
2566 
2567         if (update.updateSource == SubresourceUpdate::UpdateSource::Clear)
2568         {
2569             clear(update.clear.value, updateMipLevel, updateBaseLayer, updateLayerCount,
2570                   commandBuffer);
2571         }
2572         else if (update.updateSource == SubresourceUpdate::UpdateSource::Buffer)
2573         {
2574             commandBuffer->copyBufferToImage(update.buffer.bufferHandle, mImage, getCurrentLayout(),
2575                                              1, &update.buffer.copyRegion);
2576         }
2577         else
2578         {
2579             update.image.image->changeLayout(aspectFlags, vk::ImageLayout::TransferSrc,
2580                                              commandBuffer);
2581 
2582             update.image.image->addReadDependency(this);
2583 
2584             commandBuffer->copyImage(update.image.image->getImage(),
2585                                      update.image.image->getCurrentLayout(), mImage,
2586                                      getCurrentLayout(), 1, &update.image.copyRegion);
2587         }
2588 
2589         update.release(contextVk);
2590     }
2591 
2592     // Only remove the updates that were actually applied to the image.
2593     mSubresourceUpdates = std::move(updatesToKeep);
2594 
2595     if (mSubresourceUpdates.empty())
2596     {
2597         mStagingBuffer.releaseInFlightBuffers(contextVk);
2598     }
2599 
2600     return angle::Result::Continue;
2601 }
2602 
flushAllStagedUpdates(ContextVk * contextVk)2603 angle::Result ImageHelper::flushAllStagedUpdates(ContextVk *contextVk)
2604 {
2605     // Clear the image.
2606     vk::CommandBuffer *commandBuffer = nullptr;
2607     ANGLE_TRY(recordCommands(contextVk, &commandBuffer));
2608     return flushStagedUpdates(contextVk, 0, mLevelCount, 0, mLayerCount, commandBuffer);
2609 }
2610 
2611 // ImageHelper::SubresourceUpdate implementation
SubresourceUpdate()2612 ImageHelper::SubresourceUpdate::SubresourceUpdate()
2613     : updateSource(UpdateSource::Buffer), buffer{VK_NULL_HANDLE}
2614 {}
2615 
SubresourceUpdate(VkBuffer bufferHandleIn,const VkBufferImageCopy & copyRegionIn)2616 ImageHelper::SubresourceUpdate::SubresourceUpdate(VkBuffer bufferHandleIn,
2617                                                   const VkBufferImageCopy &copyRegionIn)
2618     : updateSource(UpdateSource::Buffer), buffer{bufferHandleIn, copyRegionIn}
2619 {}
2620 
SubresourceUpdate(vk::ImageHelper * imageIn,const VkImageCopy & copyRegionIn)2621 ImageHelper::SubresourceUpdate::SubresourceUpdate(vk::ImageHelper *imageIn,
2622                                                   const VkImageCopy &copyRegionIn)
2623     : updateSource(UpdateSource::Image), image{imageIn, copyRegionIn}
2624 {}
2625 
SubresourceUpdate(const VkClearValue & clearValue,const gl::ImageIndex & imageIndex)2626 ImageHelper::SubresourceUpdate::SubresourceUpdate(const VkClearValue &clearValue,
2627                                                   const gl::ImageIndex &imageIndex)
2628     : updateSource(UpdateSource::Clear)
2629 {
2630     clear.value      = clearValue;
2631     clear.levelIndex = imageIndex.getLevelIndex();
2632     clear.layerIndex = imageIndex.hasLayer() ? imageIndex.getLayerIndex() : 0;
2633     clear.layerCount = imageIndex.getLayerCount();
2634 }
2635 
SubresourceUpdate(const SubresourceUpdate & other)2636 ImageHelper::SubresourceUpdate::SubresourceUpdate(const SubresourceUpdate &other)
2637     : updateSource(other.updateSource)
2638 {
2639     if (updateSource == UpdateSource::Clear)
2640     {
2641         clear = other.clear;
2642     }
2643     else if (updateSource == UpdateSource::Buffer)
2644     {
2645         buffer = other.buffer;
2646     }
2647     else
2648     {
2649         image = other.image;
2650     }
2651 }
2652 
release(ContextVk * contextVk)2653 void ImageHelper::SubresourceUpdate::release(ContextVk *contextVk)
2654 {
2655     if (updateSource == UpdateSource::Image)
2656     {
2657         image.image->releaseImage(contextVk);
2658         image.image->releaseStagingBuffer(contextVk);
2659         SafeDelete(image.image);
2660     }
2661 }
2662 
release(DisplayVk * display,std::vector<GarbageObjectBase> * garbageQueue)2663 void ImageHelper::SubresourceUpdate::release(DisplayVk *display,
2664                                              std::vector<GarbageObjectBase> *garbageQueue)
2665 {
2666     if (updateSource == UpdateSource::Image)
2667     {
2668         image.image->releaseImage(display, garbageQueue);
2669         image.image->releaseStagingBuffer(display, garbageQueue);
2670         SafeDelete(image.image);
2671     }
2672 }
2673 
isUpdateToLayerLevel(uint32_t layerIndex,uint32_t levelIndex) const2674 bool ImageHelper::SubresourceUpdate::isUpdateToLayerLevel(uint32_t layerIndex,
2675                                                           uint32_t levelIndex) const
2676 {
2677     if (updateSource == UpdateSource::Clear)
2678     {
2679         return clear.levelIndex == levelIndex && clear.layerIndex == layerIndex;
2680     }
2681 
2682     const VkImageSubresourceLayers &dst = dstSubresource();
2683     return dst.baseArrayLayer == layerIndex && dst.mipLevel == levelIndex;
2684 }
2685 
2686 // FramebufferHelper implementation.
FramebufferHelper()2687 FramebufferHelper::FramebufferHelper() : CommandGraphResource(CommandGraphResourceType::Framebuffer)
2688 {}
2689 
2690 FramebufferHelper::~FramebufferHelper() = default;
2691 
init(ContextVk * contextVk,const VkFramebufferCreateInfo & createInfo)2692 angle::Result FramebufferHelper::init(ContextVk *contextVk,
2693                                       const VkFramebufferCreateInfo &createInfo)
2694 {
2695     ANGLE_VK_TRY(contextVk, mFramebuffer.init(contextVk->getDevice(), createInfo));
2696     return angle::Result::Continue;
2697 }
2698 
release(ContextVk * contextVk)2699 void FramebufferHelper::release(ContextVk *contextVk)
2700 {
2701     contextVk->releaseObject(getStoredQueueSerial(), &mFramebuffer);
2702 }
2703 
2704 // FramebufferHelper implementation.
DispatchHelper()2705 DispatchHelper::DispatchHelper() : CommandGraphResource(CommandGraphResourceType::Dispatcher) {}
2706 
2707 DispatchHelper::~DispatchHelper() = default;
2708 
2709 // ShaderProgramHelper implementation.
2710 ShaderProgramHelper::ShaderProgramHelper() = default;
2711 
2712 ShaderProgramHelper::~ShaderProgramHelper() = default;
2713 
valid() const2714 bool ShaderProgramHelper::valid() const
2715 {
2716     // This will need to be extended for compute shader support.
2717     return mShaders[gl::ShaderType::Vertex].valid();
2718 }
2719 
destroy(VkDevice device)2720 void ShaderProgramHelper::destroy(VkDevice device)
2721 {
2722     mGraphicsPipelines.destroy(device);
2723     mComputePipeline.destroy(device);
2724     for (BindingPointer<ShaderAndSerial> &shader : mShaders)
2725     {
2726         shader.reset();
2727     }
2728 }
2729 
release(ContextVk * contextVk)2730 void ShaderProgramHelper::release(ContextVk *contextVk)
2731 {
2732     mGraphicsPipelines.release(contextVk);
2733     contextVk->releaseObject(mComputePipeline.getSerial(), &mComputePipeline.get());
2734     for (BindingPointer<ShaderAndSerial> &shader : mShaders)
2735     {
2736         shader.reset();
2737     }
2738 }
2739 
setShader(gl::ShaderType shaderType,RefCounted<ShaderAndSerial> * shader)2740 void ShaderProgramHelper::setShader(gl::ShaderType shaderType, RefCounted<ShaderAndSerial> *shader)
2741 {
2742     mShaders[shaderType].set(shader);
2743 }
2744 
getComputePipeline(Context * context,const PipelineLayout & pipelineLayout,PipelineAndSerial ** pipelineOut)2745 angle::Result ShaderProgramHelper::getComputePipeline(Context *context,
2746                                                       const PipelineLayout &pipelineLayout,
2747                                                       PipelineAndSerial **pipelineOut)
2748 {
2749     if (mComputePipeline.valid())
2750     {
2751         *pipelineOut = &mComputePipeline;
2752         return angle::Result::Continue;
2753     }
2754 
2755     RendererVk *renderer = context->getRenderer();
2756 
2757     VkPipelineShaderStageCreateInfo shaderStage = {};
2758     VkComputePipelineCreateInfo createInfo      = {};
2759 
2760     shaderStage.sType               = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
2761     shaderStage.flags               = 0;
2762     shaderStage.stage               = VK_SHADER_STAGE_COMPUTE_BIT;
2763     shaderStage.module              = mShaders[gl::ShaderType::Compute].get().get().getHandle();
2764     shaderStage.pName               = "main";
2765     shaderStage.pSpecializationInfo = nullptr;
2766 
2767     createInfo.sType              = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
2768     createInfo.flags              = 0;
2769     createInfo.stage              = shaderStage;
2770     createInfo.layout             = pipelineLayout.getHandle();
2771     createInfo.basePipelineHandle = VK_NULL_HANDLE;
2772     createInfo.basePipelineIndex  = 0;
2773 
2774     vk::PipelineCache *pipelineCache = nullptr;
2775     ANGLE_TRY(renderer->getPipelineCache(&pipelineCache));
2776     ANGLE_VK_TRY(context, mComputePipeline.get().initCompute(context->getDevice(), createInfo,
2777                                                              *pipelineCache));
2778 
2779     *pipelineOut = &mComputePipeline;
2780     return angle::Result::Continue;
2781 }
2782 
2783 }  // namespace vk
2784 }  // namespace rx
2785