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