• 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 utility classes that manage Vulkan resources.
8 
9 #include "libANGLE/renderer/vulkan/vk_helpers.h"
10 
11 #include "common/utilities.h"
12 #include "common/vulkan/vk_headers.h"
13 #include "image_util/loadimage.h"
14 #include "libANGLE/Context.h"
15 #include "libANGLE/renderer/driver_utils.h"
16 #include "libANGLE/renderer/renderer_utils.h"
17 #include "libANGLE/renderer/vulkan/BufferVk.h"
18 #include "libANGLE/renderer/vulkan/ContextVk.h"
19 #include "libANGLE/renderer/vulkan/DisplayVk.h"
20 #include "libANGLE/renderer/vulkan/FramebufferVk.h"
21 #include "libANGLE/renderer/vulkan/RenderTargetVk.h"
22 #include "libANGLE/renderer/vulkan/RendererVk.h"
23 #include "libANGLE/renderer/vulkan/android/vk_android_utils.h"
24 #include "libANGLE/renderer/vulkan/vk_utils.h"
25 #include "libANGLE/trace.h"
26 
27 namespace rx
28 {
29 namespace vk
30 {
31 namespace
32 {
33 // ANGLE_robust_resource_initialization requires color textures to be initialized to zero.
34 constexpr VkClearColorValue kRobustInitColorValue = {{0, 0, 0, 0}};
35 // When emulating a texture, we want the emulated channels to be 0, with alpha 1.
36 constexpr VkClearColorValue kEmulatedInitColorValue = {{0, 0, 0, 1.0f}};
37 // ANGLE_robust_resource_initialization requires depth to be initialized to 1 and stencil to 0.
38 // We are fine with these values for emulated depth/stencil textures too.
39 constexpr VkClearDepthStencilValue kRobustInitDepthStencilValue = {1.0f, 0};
40 
41 constexpr VkImageAspectFlags kDepthStencilAspects =
42     VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_DEPTH_BIT;
43 
44 constexpr angle::PackedEnumMap<PipelineStage, VkPipelineStageFlagBits> kPipelineStageFlagBitMap = {
45     {PipelineStage::TopOfPipe, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT},
46     {PipelineStage::DrawIndirect, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT},
47     {PipelineStage::VertexInput, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT},
48     {PipelineStage::VertexShader, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT},
49     {PipelineStage::TessellationControl, VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT},
50     {PipelineStage::TessellationEvaluation, VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT},
51     {PipelineStage::GeometryShader, VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT},
52     {PipelineStage::TransformFeedback, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT},
53     {PipelineStage::EarlyFragmentTest, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT},
54     {PipelineStage::FragmentShader, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT},
55     {PipelineStage::LateFragmentTest, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT},
56     {PipelineStage::ColorAttachmentOutput, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT},
57     {PipelineStage::ComputeShader, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT},
58     {PipelineStage::Transfer, VK_PIPELINE_STAGE_TRANSFER_BIT},
59     {PipelineStage::BottomOfPipe, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT},
60     {PipelineStage::Host, VK_PIPELINE_STAGE_HOST_BIT}};
61 
62 constexpr gl::ShaderMap<PipelineStage> kPipelineStageShaderMap = {
63     {gl::ShaderType::Vertex, PipelineStage::VertexShader},
64     {gl::ShaderType::TessControl, PipelineStage::TessellationControl},
65     {gl::ShaderType::TessEvaluation, PipelineStage::TessellationEvaluation},
66     {gl::ShaderType::Geometry, PipelineStage::GeometryShader},
67     {gl::ShaderType::Fragment, PipelineStage::FragmentShader},
68     {gl::ShaderType::Compute, PipelineStage::ComputeShader},
69 };
70 
71 constexpr size_t kDefaultPoolAllocatorPageSize = 16 * 1024;
72 
73 struct ImageMemoryBarrierData
74 {
75     char name[44];
76 
77     // The Vk layout corresponding to the ImageLayout key.
78     VkImageLayout layout;
79 
80     // The stage in which the image is used (or Bottom/Top if not using any specific stage).  Unless
81     // Bottom/Top (Bottom used for transition to and Top used for transition from), the two values
82     // should match.
83     VkPipelineStageFlags dstStageMask;
84     VkPipelineStageFlags srcStageMask;
85     // Access mask when transitioning into this layout.
86     VkAccessFlags dstAccessMask;
87     // Access mask when transitioning out from this layout.  Note that source access mask never
88     // needs a READ bit, as WAR hazards don't need memory barriers (just execution barriers).
89     VkAccessFlags srcAccessMask;
90     // Read or write.
91     ResourceAccess type;
92     // *CommandBufferHelper track an array of PipelineBarriers. This indicates which array element
93     // this should be merged into. Right now we track individual barrier for every PipelineStage. If
94     // layout has a single stage mask bit, we use that stage as index. If layout has multiple stage
95     // mask bits, we pick the lowest stage as the index since it is the first stage that needs
96     // barrier.
97     PipelineStage barrierIndex;
98 };
99 
100 constexpr VkPipelineStageFlags kPreFragmentStageFlags =
101     VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT |
102     VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT | VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
103 
104 constexpr VkPipelineStageFlags kAllShadersPipelineStageFlags =
105     kPreFragmentStageFlags | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
106     VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
107 
108 constexpr VkPipelineStageFlags kAllDepthStencilPipelineStageFlags =
109     VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
110 
111 // clang-format off
112 constexpr angle::PackedEnumMap<ImageLayout, ImageMemoryBarrierData> kImageMemoryBarrierData = {
113     {
114         ImageLayout::Undefined,
115         ImageMemoryBarrierData{
116             "Undefined",
117             VK_IMAGE_LAYOUT_UNDEFINED,
118             VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
119             VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
120             // Transition to: we don't expect to transition into Undefined.
121             0,
122             // Transition from: there's no data in the image to care about.
123             0,
124             ResourceAccess::ReadOnly,
125             PipelineStage::InvalidEnum,
126         },
127     },
128     {
129         ImageLayout::ColorAttachment,
130         ImageMemoryBarrierData{
131             "ColorAttachment",
132             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
133             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
134             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
135             // Transition to: all reads and writes must happen after barrier.
136             VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
137             // Transition from: all writes must finish before barrier.
138             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
139             ResourceAccess::Write,
140             PipelineStage::ColorAttachmentOutput,
141         },
142     },
143     {
144         ImageLayout::ColorAttachmentAndFragmentShaderRead,
145         ImageMemoryBarrierData{
146             "ColorAttachmentAndFragmentShaderRead",
147             VK_IMAGE_LAYOUT_GENERAL,
148             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
149             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
150             // Transition to: all reads and writes must happen after barrier.
151             VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
152             // Transition from: all writes must finish before barrier.
153             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
154             ResourceAccess::Write,
155             PipelineStage::FragmentShader,
156         },
157     },
158     {
159         ImageLayout::ColorAttachmentAndAllShadersRead,
160         ImageMemoryBarrierData{
161             "ColorAttachmentAndAllShadersRead",
162             VK_IMAGE_LAYOUT_GENERAL,
163             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | kAllShadersPipelineStageFlags,
164             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | kAllShadersPipelineStageFlags,
165             // Transition to: all reads and writes must happen after barrier.
166             VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
167             // Transition from: all writes must finish before barrier.
168             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
169             ResourceAccess::Write,
170             // In case of multiple destination stages, We barrier the earliest stage
171             PipelineStage::VertexShader,
172         },
173     },
174     {
175         ImageLayout::DSAttachmentWriteAndFragmentShaderRead,
176         ImageMemoryBarrierData{
177             "DSAttachmentWriteAndFragmentShaderRead",
178             VK_IMAGE_LAYOUT_GENERAL,
179             kAllDepthStencilPipelineStageFlags | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
180             kAllDepthStencilPipelineStageFlags | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
181             // Transition to: all reads and writes must happen after barrier.
182             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
183             // Transition from: all writes must finish before barrier.
184             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
185             ResourceAccess::Write,
186             PipelineStage::FragmentShader,
187         },
188     },
189     {
190         ImageLayout::DSAttachmentWriteAndAllShadersRead,
191         ImageMemoryBarrierData{
192             "DSAttachmentWriteAndAllShadersRead",
193             VK_IMAGE_LAYOUT_GENERAL,
194             kAllDepthStencilPipelineStageFlags | kAllShadersPipelineStageFlags,
195             kAllDepthStencilPipelineStageFlags | kAllShadersPipelineStageFlags,
196             // Transition to: all reads and writes must happen after barrier.
197             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
198             // Transition from: all writes must finish before barrier.
199             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
200             ResourceAccess::Write,
201             // In case of multiple destination stages, We barrier the earliest stage
202             PipelineStage::VertexShader,
203         },
204     },
205     {
206         ImageLayout::DSAttachmentReadAndFragmentShaderRead,
207             ImageMemoryBarrierData{
208             "DSAttachmentReadAndFragmentShaderRead",
209             VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
210             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
211             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
212             // Transition to: all reads must happen after barrier.
213             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
214             // Transition from: RAR and WAR don't need memory barrier.
215             0,
216             ResourceAccess::ReadOnly,
217             PipelineStage::EarlyFragmentTest,
218         },
219     },
220     {
221         ImageLayout::DSAttachmentReadAndAllShadersRead,
222             ImageMemoryBarrierData{
223             "DSAttachmentReadAndAllShadersRead",
224             VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
225             kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
226             kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
227             // Transition to: all reads must happen after barrier.
228             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
229             // Transition from: RAR and WAR don't need memory barrier.
230             0,
231             ResourceAccess::ReadOnly,
232             PipelineStage::VertexShader,
233         },
234     },
235     {
236         ImageLayout::DepthStencilAttachmentReadOnly,
237             ImageMemoryBarrierData{
238             "DepthStencilAttachmentReadOnly",
239             VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
240             kAllDepthStencilPipelineStageFlags,
241             kAllDepthStencilPipelineStageFlags,
242             // Transition to: all reads must happen after barrier.
243             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
244             // Transition from: RAR and WAR don't need memory barrier.
245             0,
246             ResourceAccess::ReadOnly,
247             PipelineStage::EarlyFragmentTest,
248         },
249     },
250     {
251         ImageLayout::DepthStencilAttachment,
252         ImageMemoryBarrierData{
253             "DepthStencilAttachment",
254             VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
255             kAllDepthStencilPipelineStageFlags,
256             kAllDepthStencilPipelineStageFlags,
257             // Transition to: all reads and writes must happen after barrier.
258             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
259             // Transition from: all writes must finish before barrier.
260             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
261             ResourceAccess::Write,
262             PipelineStage::EarlyFragmentTest,
263         },
264     },
265     {
266         ImageLayout::DepthStencilResolveAttachment,
267         ImageMemoryBarrierData{
268             "DepthStencilResolveAttachment",
269             VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
270             // Note: depth/stencil resolve uses color output stage and mask!
271             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
272             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
273             // Transition to: all reads and writes must happen after barrier.
274             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
275             // Transition from: all writes must finish before barrier.
276             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
277             ResourceAccess::Write,
278             PipelineStage::ColorAttachmentOutput,
279         },
280     },
281     {
282         ImageLayout::Present,
283         ImageMemoryBarrierData{
284             "Present",
285             VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
286             VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
287             VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
288             // transition to: vkQueuePresentKHR automatically performs the appropriate memory barriers:
289             //
290             // > Any writes to memory backing the images referenced by the pImageIndices and
291             // > pSwapchains members of pPresentInfo, that are available before vkQueuePresentKHR
292             // > is executed, are automatically made visible to the read access performed by the
293             // > presentation engine.
294             0,
295             // Transition from: RAR and WAR don't need memory barrier.
296             0,
297             ResourceAccess::ReadOnly,
298             PipelineStage::BottomOfPipe,
299         },
300     },
301     {
302         ImageLayout::SharedPresent,
303         ImageMemoryBarrierData{
304             "SharedPresent",
305             VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR,
306             VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
307             VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
308             // Transition to: all reads and writes must happen after barrier.
309             VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
310             // Transition from: all writes must finish before barrier.
311             VK_ACCESS_MEMORY_WRITE_BIT,
312             ResourceAccess::Write,
313             PipelineStage::BottomOfPipe,
314         },
315     },
316     {
317         ImageLayout::ExternalPreInitialized,
318         ImageMemoryBarrierData{
319             "ExternalPreInitialized",
320             // Binding a VkImage with an initial layout of VK_IMAGE_LAYOUT_UNDEFINED to external
321             // memory whose content has already been defined does not make the content undefined
322             // (see 12.8.1.  External Resource Sharing).
323             //
324             // Note that for external memory objects, if the content is already defined, the
325             // ownership rules imply that the first operation on the texture must be a call to
326             // glWaitSemaphoreEXT that grants ownership of the image and informs us of the true
327             // layout.  If the content is not already defined, the first operation may not be a
328             // glWaitSemaphore, but in this case undefined layout is appropriate.
329             VK_IMAGE_LAYOUT_UNDEFINED,
330             VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
331             VK_PIPELINE_STAGE_HOST_BIT | VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
332             // Transition to: we don't expect to transition into PreInitialized.
333             0,
334             // Transition from: all writes must finish before barrier.
335             VK_ACCESS_MEMORY_WRITE_BIT,
336             ResourceAccess::ReadOnly,
337             PipelineStage::InvalidEnum,
338         },
339     },
340     {
341         ImageLayout::ExternalShadersReadOnly,
342         ImageMemoryBarrierData{
343             "ExternalShadersReadOnly",
344             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
345             VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
346             VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
347             // Transition to: all reads must happen after barrier.
348             VK_ACCESS_SHADER_READ_BIT,
349             // Transition from: RAR and WAR don't need memory barrier.
350             0,
351             ResourceAccess::ReadOnly,
352             // In case of multiple destination stages, We barrier the earliest stage
353             PipelineStage::TopOfPipe,
354         },
355     },
356     {
357         ImageLayout::ExternalShadersWrite,
358         ImageMemoryBarrierData{
359             "ExternalShadersWrite",
360             VK_IMAGE_LAYOUT_GENERAL,
361             VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
362             VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
363             // Transition to: all reads and writes must happen after barrier.
364             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
365             // Transition from: all writes must finish before barrier.
366             VK_ACCESS_SHADER_WRITE_BIT,
367             ResourceAccess::Write,
368             // In case of multiple destination stages, We barrier the earliest stage
369             PipelineStage::TopOfPipe,
370         },
371     },
372     {
373         ImageLayout::TransferSrc,
374         ImageMemoryBarrierData{
375             "TransferSrc",
376             VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
377             VK_PIPELINE_STAGE_TRANSFER_BIT,
378             VK_PIPELINE_STAGE_TRANSFER_BIT,
379             // Transition to: all reads must happen after barrier.
380             VK_ACCESS_TRANSFER_READ_BIT,
381             // Transition from: RAR and WAR don't need memory barrier.
382             0,
383             ResourceAccess::ReadOnly,
384             PipelineStage::Transfer,
385         },
386     },
387     {
388         ImageLayout::TransferDst,
389         ImageMemoryBarrierData{
390             "TransferDst",
391             VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
392             VK_PIPELINE_STAGE_TRANSFER_BIT,
393             VK_PIPELINE_STAGE_TRANSFER_BIT,
394             // Transition to: all writes must happen after barrier.
395             VK_ACCESS_TRANSFER_WRITE_BIT,
396             // Transition from: all writes must finish before barrier.
397             VK_ACCESS_TRANSFER_WRITE_BIT,
398             ResourceAccess::Write,
399             PipelineStage::Transfer,
400         },
401     },
402     {
403         ImageLayout::VertexShaderReadOnly,
404         ImageMemoryBarrierData{
405             "VertexShaderReadOnly",
406             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
407             VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
408             VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
409             // Transition to: all reads must happen after barrier.
410             VK_ACCESS_SHADER_READ_BIT,
411             // Transition from: RAR and WAR don't need memory barrier.
412             0,
413             ResourceAccess::ReadOnly,
414             PipelineStage::VertexShader,
415         },
416     },
417     {
418         ImageLayout::VertexShaderWrite,
419         ImageMemoryBarrierData{
420             "VertexShaderWrite",
421             VK_IMAGE_LAYOUT_GENERAL,
422             VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
423             VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
424             // Transition to: all reads and writes must happen after barrier.
425             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
426             // Transition from: all writes must finish before barrier.
427             VK_ACCESS_SHADER_WRITE_BIT,
428             ResourceAccess::Write,
429             PipelineStage::VertexShader,
430         },
431     },
432     {
433         ImageLayout::PreFragmentShadersReadOnly,
434         ImageMemoryBarrierData{
435             "PreFragmentShadersReadOnly",
436             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
437             kPreFragmentStageFlags,
438             kPreFragmentStageFlags,
439             // Transition to: all reads must happen after barrier.
440             VK_ACCESS_SHADER_READ_BIT,
441             // Transition from: RAR and WAR don't need memory barrier.
442             0,
443             ResourceAccess::ReadOnly,
444             // In case of multiple destination stages, We barrier the earliest stage
445             PipelineStage::VertexShader,
446         },
447     },
448     {
449         ImageLayout::PreFragmentShadersWrite,
450         ImageMemoryBarrierData{
451             "PreFragmentShadersWrite",
452             VK_IMAGE_LAYOUT_GENERAL,
453             kPreFragmentStageFlags,
454             kPreFragmentStageFlags,
455             // Transition to: all reads and writes must happen after barrier.
456             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
457             // Transition from: all writes must finish before barrier.
458             VK_ACCESS_SHADER_WRITE_BIT,
459             ResourceAccess::Write,
460             // In case of multiple destination stages, We barrier the earliest stage
461             PipelineStage::VertexShader,
462         },
463     },
464     {
465         ImageLayout::FragmentShaderReadOnly,
466         ImageMemoryBarrierData{
467             "FragmentShaderReadOnly",
468             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
469             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
470             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
471             // Transition to: all reads must happen after barrier.
472             VK_ACCESS_SHADER_READ_BIT,
473             // Transition from: RAR and WAR don't need memory barrier.
474             0,
475             ResourceAccess::ReadOnly,
476             PipelineStage::FragmentShader,
477         },
478     },
479     {
480         ImageLayout::FragmentShaderWrite,
481         ImageMemoryBarrierData{
482             "FragmentShaderWrite",
483             VK_IMAGE_LAYOUT_GENERAL,
484             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
485             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
486             // Transition to: all reads and writes must happen after barrier.
487             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
488             // Transition from: all writes must finish before barrier.
489             VK_ACCESS_SHADER_WRITE_BIT,
490             ResourceAccess::Write,
491             PipelineStage::FragmentShader,
492         },
493     },
494     {
495         ImageLayout::ComputeShaderReadOnly,
496         ImageMemoryBarrierData{
497             "ComputeShaderReadOnly",
498             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
499             VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
500             VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
501             // Transition to: all reads must happen after barrier.
502             VK_ACCESS_SHADER_READ_BIT,
503             // Transition from: RAR and WAR don't need memory barrier.
504             0,
505             ResourceAccess::ReadOnly,
506             PipelineStage::ComputeShader,
507         },
508     },
509     {
510         ImageLayout::ComputeShaderWrite,
511         ImageMemoryBarrierData{
512             "ComputeShaderWrite",
513             VK_IMAGE_LAYOUT_GENERAL,
514             VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
515             VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
516             // Transition to: all reads and writes must happen after barrier.
517             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
518             // Transition from: all writes must finish before barrier.
519             VK_ACCESS_SHADER_WRITE_BIT,
520             ResourceAccess::Write,
521             PipelineStage::ComputeShader,
522         },
523     },
524     {
525         ImageLayout::AllGraphicsShadersReadOnly,
526         ImageMemoryBarrierData{
527             "AllGraphicsShadersReadOnly",
528             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
529             kAllShadersPipelineStageFlags,
530             kAllShadersPipelineStageFlags,
531             // Transition to: all reads must happen after barrier.
532             VK_ACCESS_SHADER_READ_BIT,
533             // Transition from: RAR and WAR don't need memory barrier.
534             0,
535             ResourceAccess::ReadOnly,
536             // In case of multiple destination stages, We barrier the earliest stage
537             PipelineStage::VertexShader,
538         },
539     },
540     {
541         ImageLayout::AllGraphicsShadersWrite,
542         ImageMemoryBarrierData{
543             "AllGraphicsShadersWrite",
544             VK_IMAGE_LAYOUT_GENERAL,
545             kAllShadersPipelineStageFlags,
546             kAllShadersPipelineStageFlags,
547             // Transition to: all reads and writes must happen after barrier.
548             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
549             // Transition from: all writes must finish before barrier.
550             VK_ACCESS_SHADER_WRITE_BIT,
551             ResourceAccess::Write,
552             // In case of multiple destination stages, We barrier the earliest stage
553             PipelineStage::VertexShader,
554         },
555     },
556 };
557 // clang-format on
558 
GetImageLayoutSrcStageMask(Context * context,const ImageMemoryBarrierData & transition)559 VkPipelineStageFlags GetImageLayoutSrcStageMask(Context *context,
560                                                 const ImageMemoryBarrierData &transition)
561 {
562     return transition.srcStageMask & context->getRenderer()->getSupportedVulkanPipelineStageMask();
563 }
564 
GetImageLayoutDstStageMask(Context * context,const ImageMemoryBarrierData & transition)565 VkPipelineStageFlags GetImageLayoutDstStageMask(Context *context,
566                                                 const ImageMemoryBarrierData &transition)
567 {
568     return transition.dstStageMask & context->getRenderer()->getSupportedVulkanPipelineStageMask();
569 }
570 
HandlePrimitiveRestart(ContextVk * contextVk,gl::DrawElementsType glIndexType,GLsizei indexCount,const uint8_t * srcPtr,uint8_t * outPtr)571 void HandlePrimitiveRestart(ContextVk *contextVk,
572                             gl::DrawElementsType glIndexType,
573                             GLsizei indexCount,
574                             const uint8_t *srcPtr,
575                             uint8_t *outPtr)
576 {
577     switch (glIndexType)
578     {
579         case gl::DrawElementsType::UnsignedByte:
580             if (contextVk->getFeatures().supportsIndexTypeUint8.enabled)
581             {
582                 CopyLineLoopIndicesWithRestart<uint8_t, uint8_t>(indexCount, srcPtr, outPtr);
583             }
584             else
585             {
586                 CopyLineLoopIndicesWithRestart<uint8_t, uint16_t>(indexCount, srcPtr, outPtr);
587             }
588             break;
589         case gl::DrawElementsType::UnsignedShort:
590             CopyLineLoopIndicesWithRestart<uint16_t, uint16_t>(indexCount, srcPtr, outPtr);
591             break;
592         case gl::DrawElementsType::UnsignedInt:
593             CopyLineLoopIndicesWithRestart<uint32_t, uint32_t>(indexCount, srcPtr, outPtr);
594             break;
595         default:
596             UNREACHABLE();
597     }
598 }
599 
HasBothDepthAndStencilAspects(VkImageAspectFlags aspectFlags)600 bool HasBothDepthAndStencilAspects(VkImageAspectFlags aspectFlags)
601 {
602     return IsMaskFlagSet(aspectFlags, kDepthStencilAspects);
603 }
604 
GetContentDefinedLayerRangeBits(uint32_t layerStart,uint32_t layerCount,uint32_t maxLayerCount)605 uint8_t GetContentDefinedLayerRangeBits(uint32_t layerStart,
606                                         uint32_t layerCount,
607                                         uint32_t maxLayerCount)
608 {
609     uint8_t layerRangeBits = layerCount >= maxLayerCount ? static_cast<uint8_t>(~0u)
610                                                          : angle::BitMask<uint8_t>(layerCount);
611     layerRangeBits <<= layerStart;
612 
613     return layerRangeBits;
614 }
615 
GetImageLayerCountForView(const ImageHelper & image)616 uint32_t GetImageLayerCountForView(const ImageHelper &image)
617 {
618     // Depth > 1 means this is a 3D texture and depth is our layer count
619     return image.getExtents().depth > 1 ? image.getExtents().depth : image.getLayerCount();
620 }
621 
ReleaseImageViews(ImageViewVector * imageViewVector,std::vector<GarbageObject> * garbage)622 void ReleaseImageViews(ImageViewVector *imageViewVector, std::vector<GarbageObject> *garbage)
623 {
624     for (ImageView &imageView : *imageViewVector)
625     {
626         if (imageView.valid())
627         {
628             garbage->emplace_back(GetGarbage(&imageView));
629         }
630     }
631     imageViewVector->clear();
632 }
633 
DestroyImageViews(ImageViewVector * imageViewVector,VkDevice device)634 void DestroyImageViews(ImageViewVector *imageViewVector, VkDevice device)
635 {
636     for (ImageView &imageView : *imageViewVector)
637     {
638         imageView.destroy(device);
639     }
640     imageViewVector->clear();
641 }
642 
GetLevelImageView(ImageViewVector * imageViews,LevelIndex levelVk,uint32_t levelCount)643 ImageView *GetLevelImageView(ImageViewVector *imageViews, LevelIndex levelVk, uint32_t levelCount)
644 {
645     // Lazily allocate the storage for image views. We allocate the full level count because we
646     // don't want to trigger any std::vector reallocations. Reallocations could invalidate our
647     // view pointers.
648     if (imageViews->empty())
649     {
650         imageViews->resize(levelCount);
651     }
652     ASSERT(imageViews->size() > levelVk.get());
653 
654     return &(*imageViews)[levelVk.get()];
655 }
656 
GetLevelLayerImageView(LayerLevelImageViewVector * imageViews,LevelIndex levelVk,uint32_t layer,uint32_t levelCount,uint32_t layerCount)657 ImageView *GetLevelLayerImageView(LayerLevelImageViewVector *imageViews,
658                                   LevelIndex levelVk,
659                                   uint32_t layer,
660                                   uint32_t levelCount,
661                                   uint32_t layerCount)
662 {
663     // Lazily allocate the storage for image views. We allocate the full layer count because we
664     // don't want to trigger any std::vector reallocations. Reallocations could invalidate our
665     // view pointers.
666     if (imageViews->empty())
667     {
668         imageViews->resize(layerCount);
669     }
670     ASSERT(imageViews->size() > layer);
671 
672     return GetLevelImageView(&(*imageViews)[layer], levelVk, levelCount);
673 }
674 
675 // Special rules apply to VkBufferImageCopy with depth/stencil. The components are tightly packed
676 // into a depth or stencil section of the destination buffer. See the spec:
677 // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkBufferImageCopy.html
GetDepthStencilImageToBufferFormat(const angle::Format & imageFormat,VkImageAspectFlagBits copyAspect)678 const angle::Format &GetDepthStencilImageToBufferFormat(const angle::Format &imageFormat,
679                                                         VkImageAspectFlagBits copyAspect)
680 {
681     if (copyAspect == VK_IMAGE_ASPECT_STENCIL_BIT)
682     {
683         ASSERT(imageFormat.id == angle::FormatID::D24_UNORM_S8_UINT ||
684                imageFormat.id == angle::FormatID::D32_FLOAT_S8X24_UINT ||
685                imageFormat.id == angle::FormatID::S8_UINT);
686         return angle::Format::Get(angle::FormatID::S8_UINT);
687     }
688 
689     ASSERT(copyAspect == VK_IMAGE_ASPECT_DEPTH_BIT);
690 
691     switch (imageFormat.id)
692     {
693         case angle::FormatID::D16_UNORM:
694             return imageFormat;
695         case angle::FormatID::D24_UNORM_X8_UINT:
696             return imageFormat;
697         case angle::FormatID::D24_UNORM_S8_UINT:
698             return angle::Format::Get(angle::FormatID::D24_UNORM_X8_UINT);
699         case angle::FormatID::D32_FLOAT:
700             return imageFormat;
701         case angle::FormatID::D32_FLOAT_S8X24_UINT:
702             return angle::Format::Get(angle::FormatID::D32_FLOAT);
703         default:
704             UNREACHABLE();
705             return imageFormat;
706     }
707 }
708 
GetRobustResourceClearValue(const angle::Format & intendedFormat,const angle::Format & actualFormat)709 VkClearValue GetRobustResourceClearValue(const angle::Format &intendedFormat,
710                                          const angle::Format &actualFormat)
711 {
712     VkClearValue clearValue = {};
713     if (intendedFormat.hasDepthOrStencilBits())
714     {
715         clearValue.depthStencil = kRobustInitDepthStencilValue;
716     }
717     else
718     {
719         clearValue.color = HasEmulatedImageChannels(intendedFormat, actualFormat)
720                                ? kEmulatedInitColorValue
721                                : kRobustInitColorValue;
722     }
723     return clearValue;
724 }
725 
726 #if !defined(ANGLE_PLATFORM_MACOS) && !defined(ANGLE_PLATFORM_ANDROID)
IsExternalQueueFamily(uint32_t queueFamilyIndex)727 bool IsExternalQueueFamily(uint32_t queueFamilyIndex)
728 {
729     return queueFamilyIndex == VK_QUEUE_FAMILY_EXTERNAL ||
730            queueFamilyIndex == VK_QUEUE_FAMILY_FOREIGN_EXT;
731 }
732 #endif
733 
IsShaderReadOnlyLayout(const ImageMemoryBarrierData & imageLayout)734 bool IsShaderReadOnlyLayout(const ImageMemoryBarrierData &imageLayout)
735 {
736     return imageLayout.layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
737 }
738 
IsAnySubresourceContentDefined(const gl::TexLevelArray<angle::BitSet8<8>> & contentDefined)739 bool IsAnySubresourceContentDefined(const gl::TexLevelArray<angle::BitSet8<8>> &contentDefined)
740 {
741     for (const angle::BitSet8<8> &levelContentDefined : contentDefined)
742     {
743         if (levelContentDefined.any())
744         {
745             return true;
746         }
747     }
748     return false;
749 }
750 
ExtendRenderPassInvalidateArea(const gl::Rectangle & invalidateArea,gl::Rectangle * out)751 void ExtendRenderPassInvalidateArea(const gl::Rectangle &invalidateArea, gl::Rectangle *out)
752 {
753     if (out->empty())
754     {
755         *out = invalidateArea;
756     }
757     else
758     {
759         gl::ExtendRectangle(*out, invalidateArea, out);
760     }
761 }
762 
CanCopyWithTransferForCopyImage(RendererVk * renderer,ImageHelper * srcImage,VkImageTiling srcTilingMode,ImageHelper * dstImage,VkImageTiling dstTilingMode)763 bool CanCopyWithTransferForCopyImage(RendererVk *renderer,
764                                      ImageHelper *srcImage,
765                                      VkImageTiling srcTilingMode,
766                                      ImageHelper *dstImage,
767                                      VkImageTiling dstTilingMode)
768 {
769     // Neither source nor destination formats can be emulated for copy image through transfer,
770     // unless they are emulated with the same format!
771     bool isFormatCompatible =
772         (!srcImage->hasEmulatedImageFormat() && !dstImage->hasEmulatedImageFormat()) ||
773         srcImage->getActualFormatID() == dstImage->getActualFormatID();
774 
775     // If neither formats are emulated, GL validation ensures that pixelBytes is the same for both.
776     ASSERT(!isFormatCompatible ||
777            srcImage->getActualFormat().pixelBytes == dstImage->getActualFormat().pixelBytes);
778 
779     return isFormatCompatible &&
780            CanCopyWithTransfer(renderer, srcImage->getActualFormatID(), srcTilingMode,
781                                dstImage->getActualFormatID(), dstTilingMode);
782 }
783 
ReleaseBufferListToRenderer(RendererVk * renderer,BufferHelperPointerVector * buffers)784 void ReleaseBufferListToRenderer(RendererVk *renderer, BufferHelperPointerVector *buffers)
785 {
786     for (std::unique_ptr<BufferHelper> &toFree : *buffers)
787     {
788         toFree->release(renderer);
789     }
790     buffers->clear();
791 }
792 
DestroyBufferList(RendererVk * renderer,BufferHelperPointerVector * buffers)793 void DestroyBufferList(RendererVk *renderer, BufferHelperPointerVector *buffers)
794 {
795     for (std::unique_ptr<BufferHelper> &toDestroy : *buffers)
796     {
797         toDestroy->destroy(renderer);
798     }
799     buffers->clear();
800 }
801 
802 // Helper functions used below
GetLoadOpShorthand(RenderPassLoadOp loadOp)803 char GetLoadOpShorthand(RenderPassLoadOp loadOp)
804 {
805     switch (loadOp)
806     {
807         case RenderPassLoadOp::Clear:
808             return 'C';
809         case RenderPassLoadOp::Load:
810             return 'L';
811         case RenderPassLoadOp::None:
812             return 'N';
813         default:
814             return 'D';
815     }
816 }
817 
GetStoreOpShorthand(RenderPassStoreOp storeOp)818 char GetStoreOpShorthand(RenderPassStoreOp storeOp)
819 {
820     switch (storeOp)
821     {
822         case RenderPassStoreOp::Store:
823             return 'S';
824         case RenderPassStoreOp::None:
825             return 'N';
826         default:
827             return 'D';
828     }
829 }
830 
831 template <typename CommandBufferHelperT>
RecycleCommandBufferHelper(VkDevice device,std::vector<CommandBufferHelperT * > * freeList,CommandBufferHelperT ** commandBufferHelper,priv::SecondaryCommandBuffer * commandBuffer)832 void RecycleCommandBufferHelper(VkDevice device,
833                                 std::vector<CommandBufferHelperT *> *freeList,
834                                 CommandBufferHelperT **commandBufferHelper,
835                                 priv::SecondaryCommandBuffer *commandBuffer)
836 {
837     freeList->push_back(*commandBufferHelper);
838 }
839 
840 template <typename CommandBufferHelperT>
RecycleCommandBufferHelper(VkDevice device,std::vector<CommandBufferHelperT * > * freeList,CommandBufferHelperT ** commandBufferHelper,VulkanSecondaryCommandBuffer * commandBuffer)841 void RecycleCommandBufferHelper(VkDevice device,
842                                 std::vector<CommandBufferHelperT *> *freeList,
843                                 CommandBufferHelperT **commandBufferHelper,
844                                 VulkanSecondaryCommandBuffer *commandBuffer)
845 {
846     CommandPool *pool = (*commandBufferHelper)->getCommandPool();
847 
848     pool->freeCommandBuffers(device, 1, commandBuffer->ptr());
849     commandBuffer->releaseHandle();
850     SafeDelete(*commandBufferHelper);
851 }
852 
ResetSecondaryCommandBuffer(std::vector<priv::SecondaryCommandBuffer> * resetList,priv::SecondaryCommandBuffer && commandBuffer)853 ANGLE_MAYBE_UNUSED void ResetSecondaryCommandBuffer(
854     std::vector<priv::SecondaryCommandBuffer> *resetList,
855     priv::SecondaryCommandBuffer &&commandBuffer)
856 {
857     commandBuffer.reset();
858 }
859 
ResetSecondaryCommandBuffer(std::vector<VulkanSecondaryCommandBuffer> * resetList,VulkanSecondaryCommandBuffer && commandBuffer)860 ANGLE_MAYBE_UNUSED void ResetSecondaryCommandBuffer(
861     std::vector<VulkanSecondaryCommandBuffer> *resetList,
862     VulkanSecondaryCommandBuffer &&commandBuffer)
863 {
864     resetList->push_back(std::move(commandBuffer));
865 }
866 
IsClear(UpdateSource updateSource)867 bool IsClear(UpdateSource updateSource)
868 {
869     return updateSource == UpdateSource::Clear ||
870            updateSource == UpdateSource::ClearEmulatedChannelsOnly ||
871            updateSource == UpdateSource::ClearAfterInvalidate;
872 }
873 
IsClearOfAllChannels(UpdateSource updateSource)874 bool IsClearOfAllChannels(UpdateSource updateSource)
875 {
876     return updateSource == UpdateSource::Clear ||
877            updateSource == UpdateSource::ClearAfterInvalidate;
878 }
879 }  // anonymous namespace
880 
881 // This is an arbitrary max. We can change this later if necessary.
882 uint32_t DynamicDescriptorPool::mMaxSetsPerPool           = 16;
883 uint32_t DynamicDescriptorPool::mMaxSetsPerPoolMultiplier = 2;
884 
GetImageCreateFlags(gl::TextureType textureType)885 VkImageCreateFlags GetImageCreateFlags(gl::TextureType textureType)
886 {
887     switch (textureType)
888     {
889         case gl::TextureType::CubeMap:
890         case gl::TextureType::CubeMapArray:
891             return VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
892 
893         case gl::TextureType::_3D:
894             return VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT;
895 
896         default:
897             return 0;
898     }
899 }
900 
GetImageLayoutFromGLImageLayout(GLenum layout)901 ImageLayout GetImageLayoutFromGLImageLayout(GLenum layout)
902 {
903     switch (layout)
904     {
905         case GL_NONE:
906             return ImageLayout::Undefined;
907         case GL_LAYOUT_GENERAL_EXT:
908             return ImageLayout::ExternalShadersWrite;
909         case GL_LAYOUT_COLOR_ATTACHMENT_EXT:
910             return ImageLayout::ColorAttachment;
911         case GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT:
912         case GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT:
913         case GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT:
914         case GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT:
915             // Note: once VK_KHR_separate_depth_stencil_layouts becomes core or ubiquitous, we
916             // should optimize depth/stencil image layout transitions to only be performed on the
917             // aspect that needs transition.  In that case, these four layouts can be distinguished
918             // and optimized.  Note that the exact equivalent of these layouts are specified in
919             // VK_KHR_maintenance2, which are also usable, granted we transition the pair of
920             // depth/stencil layouts accordingly elsewhere in ANGLE.
921             return ImageLayout::DepthStencilAttachment;
922         case GL_LAYOUT_SHADER_READ_ONLY_EXT:
923             return ImageLayout::ExternalShadersReadOnly;
924         case GL_LAYOUT_TRANSFER_SRC_EXT:
925             return ImageLayout::TransferSrc;
926         case GL_LAYOUT_TRANSFER_DST_EXT:
927             return ImageLayout::TransferDst;
928         default:
929             UNREACHABLE();
930             return vk::ImageLayout::Undefined;
931     }
932 }
933 
ConvertImageLayoutToGLImageLayout(ImageLayout layout)934 GLenum ConvertImageLayoutToGLImageLayout(ImageLayout layout)
935 {
936     switch (kImageMemoryBarrierData[layout].layout)
937     {
938         case VK_IMAGE_LAYOUT_UNDEFINED:
939             return GL_NONE;
940         case VK_IMAGE_LAYOUT_GENERAL:
941             return GL_LAYOUT_GENERAL_EXT;
942         case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
943             return GL_LAYOUT_COLOR_ATTACHMENT_EXT;
944         case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
945             return GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT;
946         case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
947             return GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT;
948         case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
949             return GL_LAYOUT_SHADER_READ_ONLY_EXT;
950         case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
951             return GL_LAYOUT_TRANSFER_SRC_EXT;
952         case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
953             return GL_LAYOUT_TRANSFER_DST_EXT;
954         case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL:
955             return GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT;
956         case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL:
957             return GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT;
958         default:
959             break;
960     }
961     UNREACHABLE();
962     return GL_NONE;
963 }
964 
ConvertImageLayoutToVkImageLayout(ImageLayout imageLayout)965 VkImageLayout ConvertImageLayoutToVkImageLayout(ImageLayout imageLayout)
966 {
967     return kImageMemoryBarrierData[imageLayout].layout;
968 }
969 
FormatHasNecessaryFeature(RendererVk * renderer,angle::FormatID formatID,VkImageTiling tilingMode,VkFormatFeatureFlags featureBits)970 bool FormatHasNecessaryFeature(RendererVk *renderer,
971                                angle::FormatID formatID,
972                                VkImageTiling tilingMode,
973                                VkFormatFeatureFlags featureBits)
974 {
975     return (tilingMode == VK_IMAGE_TILING_OPTIMAL)
976                ? renderer->hasImageFormatFeatureBits(formatID, featureBits)
977                : renderer->hasLinearImageFormatFeatureBits(formatID, featureBits);
978 }
979 
CanCopyWithTransfer(RendererVk * renderer,angle::FormatID srcFormatID,VkImageTiling srcTilingMode,angle::FormatID dstFormatID,VkImageTiling dstTilingMode)980 bool CanCopyWithTransfer(RendererVk *renderer,
981                          angle::FormatID srcFormatID,
982                          VkImageTiling srcTilingMode,
983                          angle::FormatID dstFormatID,
984                          VkImageTiling dstTilingMode)
985 {
986     // Checks that the formats in the copy transfer have the appropriate tiling and transfer bits
987     bool isTilingCompatible           = srcTilingMode == dstTilingMode;
988     bool srcFormatHasNecessaryFeature = FormatHasNecessaryFeature(
989         renderer, srcFormatID, srcTilingMode, VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
990     bool dstFormatHasNecessaryFeature = FormatHasNecessaryFeature(
991         renderer, dstFormatID, dstTilingMode, VK_FORMAT_FEATURE_TRANSFER_DST_BIT);
992 
993     return isTilingCompatible && srcFormatHasNecessaryFeature && dstFormatHasNecessaryFeature;
994 }
995 
996 // PackedClearValuesArray implementation
PackedClearValuesArray()997 PackedClearValuesArray::PackedClearValuesArray() : mValues{} {}
998 PackedClearValuesArray::~PackedClearValuesArray() = default;
999 
1000 PackedClearValuesArray::PackedClearValuesArray(const PackedClearValuesArray &other) = default;
1001 PackedClearValuesArray &PackedClearValuesArray::operator=(const PackedClearValuesArray &rhs) =
1002     default;
1003 
store(PackedAttachmentIndex index,VkImageAspectFlags aspectFlags,const VkClearValue & clearValue)1004 void PackedClearValuesArray::store(PackedAttachmentIndex index,
1005                                    VkImageAspectFlags aspectFlags,
1006                                    const VkClearValue &clearValue)
1007 {
1008     ASSERT(aspectFlags != 0);
1009     if (aspectFlags != VK_IMAGE_ASPECT_STENCIL_BIT)
1010     {
1011         storeNoDepthStencil(index, clearValue);
1012     }
1013 }
1014 
storeNoDepthStencil(PackedAttachmentIndex index,const VkClearValue & clearValue)1015 void PackedClearValuesArray::storeNoDepthStencil(PackedAttachmentIndex index,
1016                                                  const VkClearValue &clearValue)
1017 {
1018     mValues[index.get()] = clearValue;
1019 }
1020 
1021 // RenderPassAttachment implementation
RenderPassAttachment()1022 RenderPassAttachment::RenderPassAttachment()
1023 {
1024     reset();
1025 }
1026 
init(ImageHelper * image,gl::LevelIndex levelIndex,uint32_t layerIndex,uint32_t layerCount,VkImageAspectFlagBits aspect)1027 void RenderPassAttachment::init(ImageHelper *image,
1028                                 gl::LevelIndex levelIndex,
1029                                 uint32_t layerIndex,
1030                                 uint32_t layerCount,
1031                                 VkImageAspectFlagBits aspect)
1032 {
1033     ASSERT(mImage == nullptr);
1034 
1035     mImage      = image;
1036     mLevelIndex = levelIndex;
1037     mLayerIndex = layerIndex;
1038     mLayerCount = layerCount;
1039     mAspect     = aspect;
1040 
1041     mImage->setRenderPassUsageFlag(RenderPassUsage::RenderTargetAttachment);
1042 }
1043 
reset()1044 void RenderPassAttachment::reset()
1045 {
1046     mImage = nullptr;
1047 
1048     mAccess = ResourceAccess::Unused;
1049 
1050     mInvalidatedCmdCount = kInfiniteCmdCount;
1051     mDisabledCmdCount    = kInfiniteCmdCount;
1052     mInvalidateArea      = gl::Rectangle();
1053 }
1054 
onAccess(ResourceAccess access,uint32_t currentCmdCount)1055 void RenderPassAttachment::onAccess(ResourceAccess access, uint32_t currentCmdCount)
1056 {
1057     // Update the access for optimizing this render pass's loadOp
1058     UpdateAccess(&mAccess, access);
1059 
1060     // Update the invalidate state for optimizing this render pass's storeOp
1061     if (onAccessImpl(access, currentCmdCount))
1062     {
1063         // The attachment is no longer invalid, so restore its content.
1064         restoreContent();
1065     }
1066 }
1067 
invalidate(const gl::Rectangle & invalidateArea,bool isAttachmentEnabled,uint32_t currentCmdCount)1068 void RenderPassAttachment::invalidate(const gl::Rectangle &invalidateArea,
1069                                       bool isAttachmentEnabled,
1070                                       uint32_t currentCmdCount)
1071 {
1072     // Keep track of the command count in the render pass at the time of invalidation.  If there are
1073     // more commands in the future, invalidate must be undone.
1074     mInvalidatedCmdCount = currentCmdCount;
1075 
1076     // Also track the command count if the attachment is currently disabled.
1077     mDisabledCmdCount = isAttachmentEnabled ? kInfiniteCmdCount : currentCmdCount;
1078 
1079     // Set/extend the invalidate area.
1080     ExtendRenderPassInvalidateArea(invalidateArea, &mInvalidateArea);
1081 }
1082 
onRenderAreaGrowth(ContextVk * contextVk,const gl::Rectangle & newRenderArea)1083 void RenderPassAttachment::onRenderAreaGrowth(ContextVk *contextVk,
1084                                               const gl::Rectangle &newRenderArea)
1085 {
1086     // Remove invalidate if it's no longer applicable.
1087     if (mInvalidateArea.empty() || mInvalidateArea.encloses(newRenderArea))
1088     {
1089         return;
1090     }
1091 
1092     ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_LOW,
1093                           "InvalidateSubFramebuffer discarded due to increased scissor region");
1094 
1095     mInvalidateArea      = gl::Rectangle();
1096     mInvalidatedCmdCount = kInfiniteCmdCount;
1097 }
1098 
finalizeLoadStore(Context * context,uint32_t currentCmdCount,bool hasUnresolveAttachment,RenderPassLoadOp * loadOp,RenderPassStoreOp * storeOp,bool * isInvalidatedOut)1099 void RenderPassAttachment::finalizeLoadStore(Context *context,
1100                                              uint32_t currentCmdCount,
1101                                              bool hasUnresolveAttachment,
1102                                              RenderPassLoadOp *loadOp,
1103                                              RenderPassStoreOp *storeOp,
1104                                              bool *isInvalidatedOut)
1105 {
1106     // Ensure we don't write to a read-only attachment. (ReadOnly -> !Write)
1107     ASSERT(!mImage->hasRenderPassUsageFlag(RenderPassUsage::ReadOnlyAttachment) ||
1108            mAccess != ResourceAccess::Write);
1109 
1110     // If the attachment is invalidated, skip the store op.  If we are not loading or clearing the
1111     // attachment and the attachment has not been used, auto-invalidate it.
1112     const bool notLoaded = *loadOp == RenderPassLoadOp::DontCare && !hasUnresolveAttachment;
1113     if (isInvalidated(currentCmdCount) || (notLoaded && mAccess != ResourceAccess::Write))
1114     {
1115         *storeOp          = RenderPassStoreOp::DontCare;
1116         *isInvalidatedOut = true;
1117     }
1118     else if (hasWriteAfterInvalidate(currentCmdCount))
1119     {
1120         // The attachment was invalidated, but is now valid.  Let the image know the contents are
1121         // now defined so a future render pass would use loadOp=LOAD.
1122         restoreContent();
1123     }
1124 
1125     // For read only depth stencil, we can use StoreOpNone if available.  DontCare is still
1126     // preferred, so do this after handling DontCare.
1127     const bool supportsLoadStoreOpNone =
1128         context->getRenderer()->getFeatures().supportsRenderPassLoadStoreOpNone.enabled;
1129     const bool supportsStoreOpNone =
1130         supportsLoadStoreOpNone ||
1131         context->getRenderer()->getFeatures().supportsRenderPassStoreOpNone.enabled;
1132     if (mAccess == ResourceAccess::ReadOnly && supportsStoreOpNone)
1133     {
1134         if (*storeOp == RenderPassStoreOp::Store && *loadOp != RenderPassLoadOp::Clear)
1135         {
1136             *storeOp = RenderPassStoreOp::None;
1137         }
1138     }
1139 
1140     if (mAccess == ResourceAccess::Unused)
1141     {
1142         if (*storeOp == RenderPassStoreOp::DontCare)
1143         {
1144             // If we are loading or clearing the attachment, but the attachment has not been used,
1145             // and the data has also not been stored back into attachment, then just skip the
1146             // load/clear op.
1147             *loadOp = RenderPassLoadOp::DontCare;
1148         }
1149         else
1150         {
1151             switch (*loadOp)
1152             {
1153                 case RenderPassLoadOp::Clear:
1154                     // Cannot optimize away the ops if the attachment is cleared (even if not used
1155                     // afterwards)
1156                     break;
1157                 case RenderPassLoadOp::Load:
1158                     // Make sure the attachment is neither loaded nor stored (as it's neither used
1159                     // nor invalidated), if possible.
1160                     if (supportsLoadStoreOpNone)
1161                     {
1162                         *loadOp = RenderPassLoadOp::None;
1163                     }
1164                     if (supportsStoreOpNone)
1165                     {
1166                         *storeOp = RenderPassStoreOp::None;
1167                     }
1168                     break;
1169                 case RenderPassLoadOp::DontCare:
1170                 case RenderPassLoadOp::None:
1171                 default:
1172                     // loadOp=DontCare should be covered by storeOp=DontCare above.
1173                     // loadOp=None is never decided upfront.
1174                     UNREACHABLE();
1175                     break;
1176             }
1177         }
1178     }
1179 }
1180 
restoreContent()1181 void RenderPassAttachment::restoreContent()
1182 {
1183     // Note that the image may have been deleted since the render pass has started.
1184     if (mImage)
1185     {
1186         ASSERT(mImage->valid());
1187         if (mAspect == VK_IMAGE_ASPECT_STENCIL_BIT)
1188         {
1189             mImage->restoreSubresourceStencilContent(mLevelIndex, mLayerIndex, mLayerCount);
1190         }
1191         else
1192         {
1193             mImage->restoreSubresourceContent(mLevelIndex, mLayerIndex, mLayerCount);
1194         }
1195         mInvalidateArea = gl::Rectangle();
1196     }
1197 }
1198 
hasWriteAfterInvalidate(uint32_t currentCmdCount) const1199 bool RenderPassAttachment::hasWriteAfterInvalidate(uint32_t currentCmdCount) const
1200 {
1201     return (mInvalidatedCmdCount != kInfiniteCmdCount &&
1202             std::min(mDisabledCmdCount, currentCmdCount) != mInvalidatedCmdCount);
1203 }
1204 
isInvalidated(uint32_t currentCmdCount) const1205 bool RenderPassAttachment::isInvalidated(uint32_t currentCmdCount) const
1206 {
1207     return mInvalidatedCmdCount != kInfiniteCmdCount &&
1208            std::min(mDisabledCmdCount, currentCmdCount) == mInvalidatedCmdCount;
1209 }
1210 
onAccessImpl(ResourceAccess access,uint32_t currentCmdCount)1211 bool RenderPassAttachment::onAccessImpl(ResourceAccess access, uint32_t currentCmdCount)
1212 {
1213     if (mInvalidatedCmdCount == kInfiniteCmdCount)
1214     {
1215         // If never invalidated or no longer invalidated, return early.
1216         return false;
1217     }
1218     if (access == ResourceAccess::Write)
1219     {
1220         // Drawing to this attachment is being enabled.  Assume that drawing will immediately occur
1221         // after this attachment is enabled, and that means that the attachment will no longer be
1222         // invalidated.
1223         mInvalidatedCmdCount = kInfiniteCmdCount;
1224         mDisabledCmdCount    = kInfiniteCmdCount;
1225         // Return true to indicate that the store op should remain STORE and that mContentDefined
1226         // should be set to true;
1227         return true;
1228     }
1229     // Drawing to this attachment is being disabled.
1230     if (hasWriteAfterInvalidate(currentCmdCount))
1231     {
1232         // The attachment was previously drawn while enabled, and so is no longer invalidated.
1233         mInvalidatedCmdCount = kInfiniteCmdCount;
1234         mDisabledCmdCount    = kInfiniteCmdCount;
1235         // Return true to indicate that the store op should remain STORE and that mContentDefined
1236         // should be set to true;
1237         return true;
1238     }
1239 
1240     // Use the latest CmdCount at the start of being disabled.  At the end of the render pass,
1241     // cmdCountDisabled is <= the actual command count, and so it's compared with
1242     // cmdCountInvalidated.  If the same, the attachment is still invalidated.
1243     mDisabledCmdCount = currentCmdCount;
1244     return false;
1245 }
1246 
1247 // CommandBufferHelperCommon implementation.
CommandBufferHelperCommon()1248 CommandBufferHelperCommon::CommandBufferHelperCommon()
1249     : mPipelineBarriers(),
1250       mPipelineBarrierMask(),
1251       mCommandPool(nullptr),
1252       mHasShaderStorageOutput(false),
1253       mHasGLMemoryBarrierIssued(false),
1254       mResourceUseList()
1255 {}
1256 
~CommandBufferHelperCommon()1257 CommandBufferHelperCommon::~CommandBufferHelperCommon() {}
1258 
initializeImpl(Context * context,CommandPool * commandPool)1259 void CommandBufferHelperCommon::initializeImpl(Context *context, CommandPool *commandPool)
1260 {
1261     ASSERT(mUsedBuffers.empty());
1262 
1263     mAllocator.initialize(kDefaultPoolAllocatorPageSize, 1);
1264     // Push a scope into the pool allocator so we can easily free and re-init on reset()
1265     mAllocator.push();
1266 
1267     mCommandPool = commandPool;
1268 }
1269 
resetImpl()1270 void CommandBufferHelperCommon::resetImpl()
1271 {
1272     mAllocator.pop();
1273     mAllocator.push();
1274 
1275     mUsedBuffers.clear();
1276     ASSERT(mResourceUseList.empty());
1277 }
1278 
bufferRead(ContextVk * contextVk,VkAccessFlags readAccessType,PipelineStage readStage,BufferHelper * buffer)1279 void CommandBufferHelperCommon::bufferRead(ContextVk *contextVk,
1280                                            VkAccessFlags readAccessType,
1281                                            PipelineStage readStage,
1282                                            BufferHelper *buffer)
1283 {
1284     VkPipelineStageFlagBits stageBits = kPipelineStageFlagBitMap[readStage];
1285     if (buffer->recordReadBarrier(readAccessType, stageBits, &mPipelineBarriers[readStage]))
1286     {
1287         mPipelineBarrierMask.set(readStage);
1288     }
1289 
1290     ASSERT(!usesBufferForWrite(*buffer));
1291     if (!mUsedBuffers.contains(buffer->getBufferSerial()))
1292     {
1293         mUsedBuffers.insert(buffer->getBufferSerial(), BufferAccess::Read);
1294         buffer->retainReadOnly(&mResourceUseList);
1295     }
1296 }
1297 
bufferWrite(ContextVk * contextVk,VkAccessFlags writeAccessType,PipelineStage writeStage,AliasingMode aliasingMode,BufferHelper * buffer)1298 void CommandBufferHelperCommon::bufferWrite(ContextVk *contextVk,
1299                                             VkAccessFlags writeAccessType,
1300                                             PipelineStage writeStage,
1301                                             AliasingMode aliasingMode,
1302                                             BufferHelper *buffer)
1303 {
1304     buffer->retainReadWrite(&mResourceUseList);
1305     VkPipelineStageFlagBits stageBits = kPipelineStageFlagBitMap[writeStage];
1306     if (buffer->recordWriteBarrier(writeAccessType, stageBits, &mPipelineBarriers[writeStage]))
1307     {
1308         mPipelineBarrierMask.set(writeStage);
1309     }
1310 
1311     // Storage buffers are special. They can alias one another in a shader.
1312     // We support aliasing by not tracking storage buffers. This works well with the GL API
1313     // because storage buffers are required to be externally synchronized.
1314     // Compute / XFB emulation buffers are not allowed to alias.
1315     if (aliasingMode == AliasingMode::Disallowed)
1316     {
1317         ASSERT(!usesBuffer(*buffer));
1318         mUsedBuffers.insert(buffer->getBufferSerial(), BufferAccess::Write);
1319     }
1320 
1321     // Make sure host-visible buffer writes result in a barrier inserted at the end of the frame to
1322     // make the results visible to the host.  The buffer may be mapped by the application in the
1323     // future.
1324     if (buffer->isHostVisible())
1325     {
1326         contextVk->onHostVisibleBufferWrite();
1327     }
1328 }
1329 
usesBuffer(const BufferHelper & buffer) const1330 bool CommandBufferHelperCommon::usesBuffer(const BufferHelper &buffer) const
1331 {
1332     return mUsedBuffers.contains(buffer.getBufferSerial());
1333 }
1334 
usesBufferForWrite(const BufferHelper & buffer) const1335 bool CommandBufferHelperCommon::usesBufferForWrite(const BufferHelper &buffer) const
1336 {
1337     BufferAccess access;
1338     if (!mUsedBuffers.get(buffer.getBufferSerial(), &access))
1339     {
1340         return false;
1341     }
1342     return access == BufferAccess::Write;
1343 }
1344 
executeBarriers(const angle::FeaturesVk & features,PrimaryCommandBuffer * primary)1345 void CommandBufferHelperCommon::executeBarriers(const angle::FeaturesVk &features,
1346                                                 PrimaryCommandBuffer *primary)
1347 {
1348     // make a local copy for faster access
1349     PipelineStagesMask mask = mPipelineBarrierMask;
1350     if (mask.none())
1351     {
1352         return;
1353     }
1354 
1355     if (features.preferAggregateBarrierCalls.enabled)
1356     {
1357         PipelineStagesMask::Iterator iter = mask.begin();
1358         PipelineBarrier &barrier          = mPipelineBarriers[*iter];
1359         for (++iter; iter != mask.end(); ++iter)
1360         {
1361             barrier.merge(&mPipelineBarriers[*iter]);
1362         }
1363         barrier.execute(primary);
1364     }
1365     else
1366     {
1367         for (PipelineStage pipelineStage : mask)
1368         {
1369             PipelineBarrier &barrier = mPipelineBarriers[pipelineStage];
1370             barrier.execute(primary);
1371         }
1372     }
1373     mPipelineBarrierMask.reset();
1374 }
1375 
imageReadImpl(ContextVk * contextVk,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)1376 void CommandBufferHelperCommon::imageReadImpl(ContextVk *contextVk,
1377                                               VkImageAspectFlags aspectFlags,
1378                                               ImageLayout imageLayout,
1379                                               ImageHelper *image)
1380 {
1381     if (image->isReadBarrierNecessary(imageLayout))
1382     {
1383         updateImageLayoutAndBarrier(contextVk, image, aspectFlags, imageLayout);
1384     }
1385 }
1386 
imageWriteImpl(ContextVk * contextVk,gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,AliasingMode aliasingMode,ImageHelper * image)1387 void CommandBufferHelperCommon::imageWriteImpl(ContextVk *contextVk,
1388                                                gl::LevelIndex level,
1389                                                uint32_t layerStart,
1390                                                uint32_t layerCount,
1391                                                VkImageAspectFlags aspectFlags,
1392                                                ImageLayout imageLayout,
1393                                                AliasingMode aliasingMode,
1394                                                ImageHelper *image)
1395 {
1396     image->retain(&mResourceUseList);
1397     image->onWrite(level, 1, layerStart, layerCount, aspectFlags);
1398     // Write always requires a barrier
1399     updateImageLayoutAndBarrier(contextVk, image, aspectFlags, imageLayout);
1400 }
1401 
updateImageLayoutAndBarrier(Context * context,ImageHelper * image,VkImageAspectFlags aspectFlags,ImageLayout imageLayout)1402 void CommandBufferHelperCommon::updateImageLayoutAndBarrier(Context *context,
1403                                                             ImageHelper *image,
1404                                                             VkImageAspectFlags aspectFlags,
1405                                                             ImageLayout imageLayout)
1406 {
1407     PipelineStage barrierIndex = kImageMemoryBarrierData[imageLayout].barrierIndex;
1408     ASSERT(barrierIndex != PipelineStage::InvalidEnum);
1409     PipelineBarrier *barrier = &mPipelineBarriers[barrierIndex];
1410     if (image->updateLayoutAndBarrier(context, aspectFlags, imageLayout, barrier))
1411     {
1412         mPipelineBarrierMask.set(barrierIndex);
1413     }
1414 }
1415 
addCommandDiagnosticsCommon(std::ostringstream * out)1416 void CommandBufferHelperCommon::addCommandDiagnosticsCommon(std::ostringstream *out)
1417 {
1418     *out << "Memory Barrier: ";
1419     for (PipelineBarrier &barrier : mPipelineBarriers)
1420     {
1421         if (!barrier.isEmpty())
1422         {
1423             barrier.addDiagnosticsString(*out);
1424         }
1425     }
1426     *out << "\\l";
1427 }
1428 
1429 // OutsideRenderPassCommandBufferHelper implementation.
OutsideRenderPassCommandBufferHelper()1430 OutsideRenderPassCommandBufferHelper::OutsideRenderPassCommandBufferHelper() {}
1431 
~OutsideRenderPassCommandBufferHelper()1432 OutsideRenderPassCommandBufferHelper::~OutsideRenderPassCommandBufferHelper() {}
1433 
initialize(Context * context,CommandPool * commandPool)1434 angle::Result OutsideRenderPassCommandBufferHelper::initialize(Context *context,
1435                                                                CommandPool *commandPool)
1436 {
1437     initializeImpl(context, commandPool);
1438     return initializeCommandBuffer(context);
1439 }
1440 
initializeCommandBuffer(Context * context)1441 angle::Result OutsideRenderPassCommandBufferHelper::initializeCommandBuffer(Context *context)
1442 {
1443     return mCommandBuffer.initialize(context, mCommandPool, false, &mAllocator);
1444 }
1445 
reset(Context * context)1446 angle::Result OutsideRenderPassCommandBufferHelper::reset(Context *context)
1447 {
1448     resetImpl();
1449 
1450     // Reset and re-initialize the command buffer
1451     context->getRenderer()->resetOutsideRenderPassCommandBuffer(std::move(mCommandBuffer));
1452     return initializeCommandBuffer(context);
1453 }
1454 
imageRead(ContextVk * contextVk,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)1455 void OutsideRenderPassCommandBufferHelper::imageRead(ContextVk *contextVk,
1456                                                      VkImageAspectFlags aspectFlags,
1457                                                      ImageLayout imageLayout,
1458                                                      ImageHelper *image)
1459 {
1460     imageReadImpl(contextVk, aspectFlags, imageLayout, image);
1461     image->retain(&mResourceUseList);
1462 }
1463 
imageWrite(ContextVk * contextVk,gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,AliasingMode aliasingMode,ImageHelper * image)1464 void OutsideRenderPassCommandBufferHelper::imageWrite(ContextVk *contextVk,
1465                                                       gl::LevelIndex level,
1466                                                       uint32_t layerStart,
1467                                                       uint32_t layerCount,
1468                                                       VkImageAspectFlags aspectFlags,
1469                                                       ImageLayout imageLayout,
1470                                                       AliasingMode aliasingMode,
1471                                                       ImageHelper *image)
1472 {
1473     imageWriteImpl(contextVk, level, layerStart, layerCount, aspectFlags, imageLayout, aliasingMode,
1474                    image);
1475 }
1476 
flushToPrimary(Context * context,PrimaryCommandBuffer * primary)1477 angle::Result OutsideRenderPassCommandBufferHelper::flushToPrimary(Context *context,
1478                                                                    PrimaryCommandBuffer *primary)
1479 {
1480     ANGLE_TRACE_EVENT0("gpu.angle", "OutsideRenderPassCommandBufferHelper::flushToPrimary");
1481     ASSERT(!empty());
1482 
1483     // Commands that are added to primary before beginRenderPass command
1484     executeBarriers(context->getRenderer()->getFeatures(), primary);
1485 
1486     ANGLE_TRY(mCommandBuffer.end(context));
1487     mCommandBuffer.executeCommands(primary);
1488 
1489     // Restart the command buffer.
1490     return reset(context);
1491 }
1492 
addCommandDiagnostics(ContextVk * contextVk)1493 void OutsideRenderPassCommandBufferHelper::addCommandDiagnostics(ContextVk *contextVk)
1494 {
1495     std::ostringstream out;
1496     addCommandDiagnosticsCommon(&out);
1497 
1498     out << mCommandBuffer.dumpCommands("\\l");
1499     contextVk->addCommandBufferDiagnostics(out.str());
1500 }
1501 
1502 // RenderPassCommandBufferHelper implementation.
RenderPassCommandBufferHelper()1503 RenderPassCommandBufferHelper::RenderPassCommandBufferHelper()
1504     : mCurrentSubpass(0),
1505       mCounter(0),
1506       mClearValues{},
1507       mRenderPassStarted(false),
1508       mTransformFeedbackCounterBuffers{},
1509       mTransformFeedbackCounterBufferOffsets{},
1510       mValidTransformFeedbackBufferCount(0),
1511       mRebindTransformFeedbackBuffers(false),
1512       mIsTransformFeedbackActiveUnpaused(false),
1513       mPreviousSubpassesCmdCount(0),
1514       mDepthStencilAttachmentIndex(kAttachmentIndexInvalid),
1515       mColorAttachmentsCount(0),
1516       mImageOptimizeForPresent(nullptr)
1517 {}
1518 
~RenderPassCommandBufferHelper()1519 RenderPassCommandBufferHelper::~RenderPassCommandBufferHelper()
1520 {
1521     mFramebuffer.setHandle(VK_NULL_HANDLE);
1522 }
1523 
initialize(Context * context,CommandPool * commandPool)1524 angle::Result RenderPassCommandBufferHelper::initialize(Context *context, CommandPool *commandPool)
1525 {
1526     initializeImpl(context, commandPool);
1527     return initializeCommandBuffer(context);
1528 }
1529 
initializeCommandBuffer(Context * context)1530 angle::Result RenderPassCommandBufferHelper::initializeCommandBuffer(Context *context)
1531 {
1532     return getCommandBuffer().initialize(context, mCommandPool, true, &mAllocator);
1533 }
1534 
reset(Context * context)1535 angle::Result RenderPassCommandBufferHelper::reset(Context *context)
1536 {
1537     resetImpl();
1538 
1539     for (PackedAttachmentIndex index = kAttachmentIndexZero; index < mColorAttachmentsCount;
1540          ++index)
1541     {
1542         mColorAttachments[index].reset();
1543         mColorResolveAttachments[index].reset();
1544     }
1545 
1546     mDepthAttachment.reset();
1547     mDepthResolveAttachment.reset();
1548     mStencilAttachment.reset();
1549     mStencilResolveAttachment.reset();
1550 
1551     mRenderPassStarted                 = false;
1552     mValidTransformFeedbackBufferCount = 0;
1553     mRebindTransformFeedbackBuffers    = false;
1554     mHasShaderStorageOutput            = false;
1555     mHasGLMemoryBarrierIssued          = false;
1556     mPreviousSubpassesCmdCount         = 0;
1557     mColorAttachmentsCount             = PackedAttachmentCount(0);
1558     mDepthStencilAttachmentIndex       = kAttachmentIndexInvalid;
1559     mRenderPassUsedImages.clear();
1560     mImageOptimizeForPresent = nullptr;
1561 
1562     // Reset and re-initialize the command buffers
1563     for (uint32_t subpass = 0; subpass <= mCurrentSubpass; ++subpass)
1564     {
1565         context->getRenderer()->resetRenderPassCommandBuffer(std::move(mCommandBuffers[subpass]));
1566     }
1567 
1568     mCurrentSubpass = 0;
1569     return initializeCommandBuffer(context);
1570 }
1571 
imageRead(ContextVk * contextVk,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)1572 void RenderPassCommandBufferHelper::imageRead(ContextVk *contextVk,
1573                                               VkImageAspectFlags aspectFlags,
1574                                               ImageLayout imageLayout,
1575                                               ImageHelper *image)
1576 {
1577     imageReadImpl(contextVk, aspectFlags, imageLayout, image);
1578 
1579     // As noted in the header we don't support multiple read layouts for Images.
1580     // We allow duplicate uses in the RP to accommodate for normal GL sampler usage.
1581     if (!usesImage(*image))
1582     {
1583         mRenderPassUsedImages.insert(image->getImageSerial());
1584         image->retain(&mResourceUseList);
1585     }
1586 }
1587 
imageWrite(ContextVk * contextVk,gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,AliasingMode aliasingMode,ImageHelper * image)1588 void RenderPassCommandBufferHelper::imageWrite(ContextVk *contextVk,
1589                                                gl::LevelIndex level,
1590                                                uint32_t layerStart,
1591                                                uint32_t layerCount,
1592                                                VkImageAspectFlags aspectFlags,
1593                                                ImageLayout imageLayout,
1594                                                AliasingMode aliasingMode,
1595                                                ImageHelper *image)
1596 {
1597     imageWriteImpl(contextVk, level, layerStart, layerCount, aspectFlags, imageLayout, aliasingMode,
1598                    image);
1599 
1600     // When used as a storage image we allow for aliased writes.
1601     if (aliasingMode == AliasingMode::Disallowed)
1602     {
1603         ASSERT(!usesImage(*image));
1604     }
1605     if (!usesImage(*image))
1606     {
1607         mRenderPassUsedImages.insert(image->getImageSerial());
1608     }
1609 }
1610 
colorImagesDraw(ResourceUseList * resourceUseList,gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,ImageHelper * image,ImageHelper * resolveImage,PackedAttachmentIndex packedAttachmentIndex)1611 void RenderPassCommandBufferHelper::colorImagesDraw(ResourceUseList *resourceUseList,
1612                                                     gl::LevelIndex level,
1613                                                     uint32_t layerStart,
1614                                                     uint32_t layerCount,
1615                                                     ImageHelper *image,
1616                                                     ImageHelper *resolveImage,
1617                                                     PackedAttachmentIndex packedAttachmentIndex)
1618 {
1619     ASSERT(packedAttachmentIndex < mColorAttachmentsCount);
1620 
1621     image->retain(resourceUseList);
1622     if (!usesImage(*image))
1623     {
1624         // This is possible due to different layers of the same texture being attached to different
1625         // attachments
1626         mRenderPassUsedImages.insert(image->getImageSerial());
1627     }
1628     mColorAttachments[packedAttachmentIndex].init(image, level, layerStart, layerCount,
1629                                                   VK_IMAGE_ASPECT_COLOR_BIT);
1630 
1631     if (resolveImage)
1632     {
1633         resolveImage->retain(resourceUseList);
1634         if (!usesImage(*resolveImage))
1635         {
1636             mRenderPassUsedImages.insert(resolveImage->getImageSerial());
1637         }
1638         mColorResolveAttachments[packedAttachmentIndex].init(resolveImage, level, layerStart,
1639                                                              layerCount, VK_IMAGE_ASPECT_COLOR_BIT);
1640     }
1641 }
1642 
depthStencilImagesDraw(ResourceUseList * resourceUseList,gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,ImageHelper * image,ImageHelper * resolveImage)1643 void RenderPassCommandBufferHelper::depthStencilImagesDraw(ResourceUseList *resourceUseList,
1644                                                            gl::LevelIndex level,
1645                                                            uint32_t layerStart,
1646                                                            uint32_t layerCount,
1647                                                            ImageHelper *image,
1648                                                            ImageHelper *resolveImage)
1649 {
1650     ASSERT(!usesImage(*image));
1651     ASSERT(!resolveImage || !usesImage(*resolveImage));
1652 
1653     // Because depthStencil buffer's read/write property can change while we build renderpass, we
1654     // defer the image layout changes until endRenderPass time or when images going away so that we
1655     // only insert layout change barrier once.
1656     image->retain(resourceUseList);
1657     mRenderPassUsedImages.insert(image->getImageSerial());
1658 
1659     mDepthAttachment.init(image, level, layerStart, layerCount, VK_IMAGE_ASPECT_DEPTH_BIT);
1660     mStencilAttachment.init(image, level, layerStart, layerCount, VK_IMAGE_ASPECT_STENCIL_BIT);
1661 
1662     if (resolveImage)
1663     {
1664         // Note that the resolve depth/stencil image has the same level/layer index as the
1665         // depth/stencil image as currently it can only ever come from
1666         // multisampled-render-to-texture renderbuffers.
1667         resolveImage->retain(resourceUseList);
1668         mRenderPassUsedImages.insert(resolveImage->getImageSerial());
1669 
1670         mDepthResolveAttachment.init(resolveImage, level, layerStart, layerCount,
1671                                      VK_IMAGE_ASPECT_DEPTH_BIT);
1672         mStencilResolveAttachment.init(resolveImage, level, layerStart, layerCount,
1673                                        VK_IMAGE_ASPECT_STENCIL_BIT);
1674     }
1675 }
1676 
onColorAccess(PackedAttachmentIndex packedAttachmentIndex,ResourceAccess access)1677 void RenderPassCommandBufferHelper::onColorAccess(PackedAttachmentIndex packedAttachmentIndex,
1678                                                   ResourceAccess access)
1679 {
1680     ASSERT(packedAttachmentIndex < mColorAttachmentsCount);
1681     mColorAttachments[packedAttachmentIndex].onAccess(access, getRenderPassWriteCommandCount());
1682 }
1683 
onDepthAccess(ResourceAccess access)1684 void RenderPassCommandBufferHelper::onDepthAccess(ResourceAccess access)
1685 {
1686     mDepthAttachment.onAccess(access, getRenderPassWriteCommandCount());
1687 }
1688 
onStencilAccess(ResourceAccess access)1689 void RenderPassCommandBufferHelper::onStencilAccess(ResourceAccess access)
1690 {
1691     mStencilAttachment.onAccess(access, getRenderPassWriteCommandCount());
1692 }
1693 
updateStartedRenderPassWithDepthMode(bool readOnlyDepthStencilMode)1694 void RenderPassCommandBufferHelper::updateStartedRenderPassWithDepthMode(
1695     bool readOnlyDepthStencilMode)
1696 {
1697     ASSERT(mRenderPassStarted);
1698     ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
1699     ASSERT(mDepthResolveAttachment.getImage() == mStencilResolveAttachment.getImage());
1700 
1701     ImageHelper *depthStencilImage        = mDepthAttachment.getImage();
1702     ImageHelper *depthStencilResolveImage = mDepthResolveAttachment.getImage();
1703 
1704     if (depthStencilImage)
1705     {
1706         if (readOnlyDepthStencilMode)
1707         {
1708             depthStencilImage->setRenderPassUsageFlag(RenderPassUsage::ReadOnlyAttachment);
1709         }
1710         else
1711         {
1712             depthStencilImage->clearRenderPassUsageFlag(RenderPassUsage::ReadOnlyAttachment);
1713         }
1714 
1715         if (depthStencilResolveImage)
1716         {
1717             if (readOnlyDepthStencilMode)
1718             {
1719                 depthStencilResolveImage->setRenderPassUsageFlag(
1720                     RenderPassUsage::ReadOnlyAttachment);
1721             }
1722             else
1723             {
1724                 depthStencilResolveImage->clearRenderPassUsageFlag(
1725                     RenderPassUsage::ReadOnlyAttachment);
1726             }
1727         }
1728     }
1729 }
1730 
finalizeColorImageLayout(Context * context,ImageHelper * image,PackedAttachmentIndex packedAttachmentIndex,bool isResolveImage)1731 void RenderPassCommandBufferHelper::finalizeColorImageLayout(
1732     Context *context,
1733     ImageHelper *image,
1734     PackedAttachmentIndex packedAttachmentIndex,
1735     bool isResolveImage)
1736 {
1737     ASSERT(packedAttachmentIndex < mColorAttachmentsCount);
1738     ASSERT(image != nullptr);
1739 
1740     // Do layout change.
1741     ImageLayout imageLayout;
1742     if (image->usedByCurrentRenderPassAsAttachmentAndSampler())
1743     {
1744         // texture code already picked layout and inserted barrier
1745         imageLayout = image->getCurrentImageLayout();
1746         ASSERT(imageLayout == ImageLayout::ColorAttachmentAndFragmentShaderRead ||
1747                imageLayout == ImageLayout::ColorAttachmentAndAllShadersRead);
1748     }
1749     else
1750     {
1751         imageLayout = ImageLayout::ColorAttachment;
1752         updateImageLayoutAndBarrier(context, image, VK_IMAGE_ASPECT_COLOR_BIT, imageLayout);
1753     }
1754 
1755     if (!isResolveImage)
1756     {
1757         mAttachmentOps.setLayouts(packedAttachmentIndex, imageLayout, imageLayout);
1758     }
1759 
1760     if (mImageOptimizeForPresent == image)
1761     {
1762         ASSERT(packedAttachmentIndex == kAttachmentIndexZero);
1763         // Use finalLayout instead of extra barrier for layout change to present
1764         mImageOptimizeForPresent->setCurrentImageLayout(ImageLayout::Present);
1765         // TODO(syoussefi):  We currently don't store the layout of the resolve attachments, so once
1766         // multisampled backbuffers are optimized to use resolve attachments, this information needs
1767         // to be stored somewhere.  http://anglebug.com/7150
1768         SetBitField(mAttachmentOps[packedAttachmentIndex].finalLayout,
1769                     mImageOptimizeForPresent->getCurrentImageLayout());
1770         mImageOptimizeForPresent = nullptr;
1771     }
1772 
1773     if (isResolveImage)
1774     {
1775         // Note: the color image will have its flags reset after load/store ops are determined.
1776         image->resetRenderPassUsageFlags();
1777     }
1778 }
1779 
finalizeColorImageLoadStore(Context * context,PackedAttachmentIndex packedAttachmentIndex)1780 void RenderPassCommandBufferHelper::finalizeColorImageLoadStore(
1781     Context *context,
1782     PackedAttachmentIndex packedAttachmentIndex)
1783 {
1784     PackedAttachmentOpsDesc &ops = mAttachmentOps[packedAttachmentIndex];
1785     RenderPassLoadOp loadOp      = static_cast<RenderPassLoadOp>(ops.loadOp);
1786     RenderPassStoreOp storeOp    = static_cast<RenderPassStoreOp>(ops.storeOp);
1787 
1788     // This has to be called after layout been finalized
1789     ASSERT(ops.initialLayout != static_cast<uint16_t>(ImageLayout::Undefined));
1790 
1791     uint32_t currentCmdCount = getRenderPassWriteCommandCount();
1792     bool isInvalidated       = false;
1793 
1794     RenderPassAttachment &colorAttachment = mColorAttachments[packedAttachmentIndex];
1795     colorAttachment.finalizeLoadStore(context, currentCmdCount,
1796                                       mRenderPassDesc.getColorUnresolveAttachmentMask().any(),
1797                                       &loadOp, &storeOp, &isInvalidated);
1798 
1799     if (isInvalidated)
1800     {
1801         ops.isInvalidated = true;
1802     }
1803 
1804     if (!ops.isInvalidated)
1805     {
1806         mColorResolveAttachments[packedAttachmentIndex].restoreContent();
1807     }
1808 
1809     // If the image is being written to, mark its contents defined.
1810     // This has to be done after storeOp has been finalized.
1811     if (storeOp == RenderPassStoreOp::Store)
1812     {
1813         colorAttachment.restoreContent();
1814     }
1815 
1816     SetBitField(ops.loadOp, loadOp);
1817     SetBitField(ops.storeOp, storeOp);
1818 }
1819 
finalizeDepthStencilImageLayout(Context * context)1820 void RenderPassCommandBufferHelper::finalizeDepthStencilImageLayout(Context *context)
1821 {
1822     ASSERT(mDepthAttachment.getImage() != nullptr);
1823     ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
1824 
1825     ImageHelper *depthStencilImage = mDepthAttachment.getImage();
1826 
1827     // Do depth stencil layout change.
1828     ImageLayout imageLayout;
1829     bool barrierRequired;
1830 
1831     if (depthStencilImage->usedByCurrentRenderPassAsAttachmentAndSampler())
1832     {
1833         // texture code already picked layout and inserted barrier
1834         imageLayout = depthStencilImage->getCurrentImageLayout();
1835         if (depthStencilImage->hasRenderPassUsageFlag(RenderPassUsage::ReadOnlyAttachment))
1836         {
1837             ASSERT(imageLayout == ImageLayout::DSAttachmentReadAndFragmentShaderRead ||
1838                    imageLayout == ImageLayout::DSAttachmentReadAndAllShadersRead);
1839             barrierRequired = depthStencilImage->isReadBarrierNecessary(imageLayout);
1840         }
1841         else
1842         {
1843             ASSERT(imageLayout == ImageLayout::DSAttachmentWriteAndFragmentShaderRead ||
1844                    imageLayout == ImageLayout::DSAttachmentWriteAndAllShadersRead);
1845             barrierRequired = true;
1846         }
1847     }
1848     else if (depthStencilImage->hasRenderPassUsageFlag(RenderPassUsage::ReadOnlyAttachment))
1849     {
1850         imageLayout     = ImageLayout::DepthStencilAttachmentReadOnly;
1851         barrierRequired = depthStencilImage->isReadBarrierNecessary(imageLayout);
1852     }
1853     else
1854     {
1855         // Write always requires a barrier
1856         imageLayout     = ImageLayout::DepthStencilAttachment;
1857         barrierRequired = true;
1858     }
1859 
1860     mAttachmentOps.setLayouts(mDepthStencilAttachmentIndex, imageLayout, imageLayout);
1861 
1862     if (barrierRequired)
1863     {
1864         const angle::Format &format = depthStencilImage->getActualFormat();
1865         ASSERT(format.hasDepthOrStencilBits());
1866         VkImageAspectFlags aspectFlags = GetDepthStencilAspectFlags(format);
1867         updateImageLayoutAndBarrier(context, depthStencilImage, aspectFlags, imageLayout);
1868     }
1869 }
1870 
finalizeDepthStencilResolveImageLayout(Context * context)1871 void RenderPassCommandBufferHelper::finalizeDepthStencilResolveImageLayout(Context *context)
1872 {
1873     ASSERT(mDepthResolveAttachment.getImage() != nullptr);
1874     ASSERT(mDepthResolveAttachment.getImage() == mStencilResolveAttachment.getImage());
1875 
1876     ImageHelper *depthStencilResolveImage = mDepthResolveAttachment.getImage();
1877     ASSERT(!depthStencilResolveImage->hasRenderPassUsageFlag(RenderPassUsage::ReadOnlyAttachment));
1878 
1879     ImageLayout imageLayout     = ImageLayout::DepthStencilResolveAttachment;
1880     const angle::Format &format = depthStencilResolveImage->getActualFormat();
1881     ASSERT(format.hasDepthOrStencilBits());
1882     VkImageAspectFlags aspectFlags = GetDepthStencilAspectFlags(format);
1883 
1884     updateImageLayoutAndBarrier(context, depthStencilResolveImage, aspectFlags, imageLayout);
1885 
1886     if (!depthStencilResolveImage->hasRenderPassUsageFlag(RenderPassUsage::ReadOnlyAttachment))
1887     {
1888         ASSERT(mDepthStencilAttachmentIndex != kAttachmentIndexInvalid);
1889         const PackedAttachmentOpsDesc &dsOps = mAttachmentOps[mDepthStencilAttachmentIndex];
1890 
1891         // If the image is being written to, mark its contents defined.
1892         if (!dsOps.isInvalidated)
1893         {
1894             mDepthResolveAttachment.restoreContent();
1895         }
1896         if (!dsOps.isStencilInvalidated)
1897         {
1898             mStencilResolveAttachment.restoreContent();
1899         }
1900     }
1901 
1902     depthStencilResolveImage->resetRenderPassUsageFlags();
1903 }
1904 
finalizeImageLayout(Context * context,const ImageHelper * image)1905 void RenderPassCommandBufferHelper::finalizeImageLayout(Context *context, const ImageHelper *image)
1906 {
1907     if (image->hasRenderPassUsageFlag(RenderPassUsage::RenderTargetAttachment))
1908     {
1909         for (PackedAttachmentIndex index = kAttachmentIndexZero; index < mColorAttachmentsCount;
1910              ++index)
1911         {
1912             if (mColorAttachments[index].getImage() == image)
1913             {
1914                 finalizeColorImageLayoutAndLoadStore(context, index);
1915                 mColorAttachments[index].reset();
1916             }
1917             else if (mColorResolveAttachments[index].getImage() == image)
1918             {
1919                 finalizeColorImageLayout(context, mColorResolveAttachments[index].getImage(), index,
1920                                          true);
1921                 mColorResolveAttachments[index].reset();
1922             }
1923         }
1924     }
1925 
1926     if (mDepthAttachment.getImage() == image)
1927     {
1928         finalizeDepthStencilImageLayoutAndLoadStore(context);
1929         mDepthAttachment.reset();
1930         mStencilAttachment.reset();
1931     }
1932 
1933     if (mDepthResolveAttachment.getImage() == image)
1934     {
1935         finalizeDepthStencilResolveImageLayout(context);
1936         mDepthResolveAttachment.reset();
1937         mStencilResolveAttachment.reset();
1938     }
1939 }
1940 
finalizeDepthStencilLoadStore(Context * context)1941 void RenderPassCommandBufferHelper::finalizeDepthStencilLoadStore(Context *context)
1942 {
1943     ASSERT(mDepthStencilAttachmentIndex != kAttachmentIndexInvalid);
1944 
1945     PackedAttachmentOpsDesc &dsOps   = mAttachmentOps[mDepthStencilAttachmentIndex];
1946     RenderPassLoadOp depthLoadOp     = static_cast<RenderPassLoadOp>(dsOps.loadOp);
1947     RenderPassStoreOp depthStoreOp   = static_cast<RenderPassStoreOp>(dsOps.storeOp);
1948     RenderPassLoadOp stencilLoadOp   = static_cast<RenderPassLoadOp>(dsOps.stencilLoadOp);
1949     RenderPassStoreOp stencilStoreOp = static_cast<RenderPassStoreOp>(dsOps.stencilStoreOp);
1950 
1951     // This has to be called after layout been finalized
1952     ASSERT(dsOps.initialLayout != static_cast<uint16_t>(ImageLayout::Undefined));
1953 
1954     uint32_t currentCmdCount  = getRenderPassWriteCommandCount();
1955     bool isDepthInvalidated   = false;
1956     bool isStencilInvalidated = false;
1957 
1958     mDepthAttachment.finalizeLoadStore(context, currentCmdCount,
1959                                        mRenderPassDesc.hasDepthUnresolveAttachment(), &depthLoadOp,
1960                                        &depthStoreOp, &isDepthInvalidated);
1961     mStencilAttachment.finalizeLoadStore(context, currentCmdCount,
1962                                          mRenderPassDesc.hasStencilUnresolveAttachment(),
1963                                          &stencilLoadOp, &stencilStoreOp, &isStencilInvalidated);
1964 
1965     if (isDepthInvalidated)
1966     {
1967         dsOps.isInvalidated = true;
1968     }
1969     if (isStencilInvalidated)
1970     {
1971         dsOps.isStencilInvalidated = true;
1972     }
1973 
1974     // This has to be done after storeOp has been finalized.
1975     ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
1976     if (!mDepthAttachment.getImage()->hasRenderPassUsageFlag(RenderPassUsage::ReadOnlyAttachment))
1977     {
1978         // If the image is being written to, mark its contents defined.
1979         if (depthStoreOp == RenderPassStoreOp::Store)
1980         {
1981             mDepthAttachment.restoreContent();
1982         }
1983         if (stencilStoreOp == RenderPassStoreOp::Store)
1984         {
1985             mStencilAttachment.restoreContent();
1986         }
1987     }
1988 
1989     SetBitField(dsOps.loadOp, depthLoadOp);
1990     SetBitField(dsOps.storeOp, depthStoreOp);
1991     SetBitField(dsOps.stencilLoadOp, stencilLoadOp);
1992     SetBitField(dsOps.stencilStoreOp, stencilStoreOp);
1993 }
1994 
finalizeColorImageLayoutAndLoadStore(Context * context,PackedAttachmentIndex packedAttachmentIndex)1995 void RenderPassCommandBufferHelper::finalizeColorImageLayoutAndLoadStore(
1996     Context *context,
1997     PackedAttachmentIndex packedAttachmentIndex)
1998 {
1999     finalizeColorImageLayout(context, mColorAttachments[packedAttachmentIndex].getImage(),
2000                              packedAttachmentIndex, false);
2001     finalizeColorImageLoadStore(context, packedAttachmentIndex);
2002 
2003     mColorAttachments[packedAttachmentIndex].getImage()->resetRenderPassUsageFlags();
2004 }
2005 
finalizeDepthStencilImageLayoutAndLoadStore(Context * context)2006 void RenderPassCommandBufferHelper::finalizeDepthStencilImageLayoutAndLoadStore(Context *context)
2007 {
2008     finalizeDepthStencilImageLayout(context);
2009     finalizeDepthStencilLoadStore(context);
2010 
2011     ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
2012     mDepthAttachment.getImage()->resetRenderPassUsageFlags();
2013 }
2014 
beginRenderPass(ContextVk * contextVk,const Framebuffer & framebuffer,const gl::Rectangle & renderArea,const RenderPassDesc & renderPassDesc,const AttachmentOpsArray & renderPassAttachmentOps,const PackedAttachmentCount colorAttachmentCount,const PackedAttachmentIndex depthStencilAttachmentIndex,const PackedClearValuesArray & clearValues,RenderPassCommandBuffer ** commandBufferOut)2015 angle::Result RenderPassCommandBufferHelper::beginRenderPass(
2016     ContextVk *contextVk,
2017     const Framebuffer &framebuffer,
2018     const gl::Rectangle &renderArea,
2019     const RenderPassDesc &renderPassDesc,
2020     const AttachmentOpsArray &renderPassAttachmentOps,
2021     const PackedAttachmentCount colorAttachmentCount,
2022     const PackedAttachmentIndex depthStencilAttachmentIndex,
2023     const PackedClearValuesArray &clearValues,
2024     RenderPassCommandBuffer **commandBufferOut)
2025 {
2026     ASSERT(!mRenderPassStarted);
2027 
2028     mRenderPassDesc              = renderPassDesc;
2029     mAttachmentOps               = renderPassAttachmentOps;
2030     mDepthStencilAttachmentIndex = depthStencilAttachmentIndex;
2031     mColorAttachmentsCount       = colorAttachmentCount;
2032     mFramebuffer.setHandle(framebuffer.getHandle());
2033     mRenderArea       = renderArea;
2034     mClearValues      = clearValues;
2035     *commandBufferOut = &getCommandBuffer();
2036 
2037     mRenderPassStarted = true;
2038     mCounter++;
2039 
2040     return beginRenderPassCommandBuffer(contextVk);
2041 }
2042 
beginRenderPassCommandBuffer(ContextVk * contextVk)2043 angle::Result RenderPassCommandBufferHelper::beginRenderPassCommandBuffer(ContextVk *contextVk)
2044 {
2045     VkCommandBufferInheritanceInfo inheritanceInfo = {};
2046     ANGLE_TRY(RenderPassCommandBuffer::InitializeRenderPassInheritanceInfo(
2047         contextVk, mFramebuffer, mRenderPassDesc, &inheritanceInfo));
2048     inheritanceInfo.subpass = mCurrentSubpass;
2049 
2050     return getCommandBuffer().begin(contextVk, inheritanceInfo);
2051 }
2052 
endRenderPass(ContextVk * contextVk)2053 angle::Result RenderPassCommandBufferHelper::endRenderPass(ContextVk *contextVk)
2054 {
2055     ANGLE_TRY(endRenderPassCommandBuffer(contextVk));
2056 
2057     for (PackedAttachmentIndex index = kAttachmentIndexZero; index < mColorAttachmentsCount;
2058          ++index)
2059     {
2060         if (mColorAttachments[index].getImage() != nullptr)
2061         {
2062             finalizeColorImageLayoutAndLoadStore(contextVk, index);
2063         }
2064         if (mColorResolveAttachments[index].getImage() != nullptr)
2065         {
2066             finalizeColorImageLayout(contextVk, mColorResolveAttachments[index].getImage(), index,
2067                                      true);
2068         }
2069     }
2070 
2071     if (mDepthStencilAttachmentIndex == kAttachmentIndexInvalid)
2072     {
2073         return angle::Result::Continue;
2074     }
2075 
2076     // Do depth stencil layout change and load store optimization.
2077     ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
2078     ASSERT(mDepthResolveAttachment.getImage() == mStencilResolveAttachment.getImage());
2079     if (mDepthAttachment.getImage() != nullptr)
2080     {
2081         finalizeDepthStencilImageLayoutAndLoadStore(contextVk);
2082     }
2083     if (mDepthResolveAttachment.getImage() != nullptr)
2084     {
2085         finalizeDepthStencilResolveImageLayout(contextVk);
2086     }
2087 
2088     return angle::Result::Continue;
2089 }
2090 
endRenderPassCommandBuffer(ContextVk * contextVk)2091 angle::Result RenderPassCommandBufferHelper::endRenderPassCommandBuffer(ContextVk *contextVk)
2092 {
2093     return getCommandBuffer().end(contextVk);
2094 }
2095 
nextSubpass(ContextVk * contextVk,RenderPassCommandBuffer ** commandBufferOut)2096 angle::Result RenderPassCommandBufferHelper::nextSubpass(ContextVk *contextVk,
2097                                                          RenderPassCommandBuffer **commandBufferOut)
2098 {
2099     if (RenderPassCommandBuffer::ExecutesInline())
2100     {
2101         // When using ANGLE secondary command buffers, the commands are inline and are executed on
2102         // the primary command buffer.  This means that vkCmdNextSubpass can be intermixed with the
2103         // rest of the commands, and there is no need to split command buffers.
2104         //
2105         // Note also that the command buffer handle doesn't change in this case.
2106         getCommandBuffer().nextSubpass(VK_SUBPASS_CONTENTS_INLINE);
2107         return angle::Result::Continue;
2108     }
2109 
2110     // When using Vulkan secondary command buffers, each subpass's contents must be recorded in a
2111     // separate command buffer that is vkCmdExecuteCommands'ed in the primary command buffer.
2112     // vkCmdNextSubpass calls must also be issued in the primary command buffer.
2113     //
2114     // To support this, a list of command buffers are kept, one for each subpass.  When moving to
2115     // the next subpass, the previous command buffer is ended and a new one is initialized and
2116     // begun.
2117 
2118     // Accumulate command count for tracking purposes.
2119     mPreviousSubpassesCmdCount = getRenderPassWriteCommandCount();
2120 
2121     ANGLE_TRY(endRenderPassCommandBuffer(contextVk));
2122     markClosed();
2123 
2124     ++mCurrentSubpass;
2125     ASSERT(mCurrentSubpass < kMaxSubpassCount);
2126 
2127     ANGLE_TRY(initializeCommandBuffer(contextVk));
2128     ANGLE_TRY(beginRenderPassCommandBuffer(contextVk));
2129     markOpen();
2130 
2131     // Return the new command buffer handle
2132     *commandBufferOut = &getCommandBuffer();
2133     return angle::Result::Continue;
2134 }
2135 
beginTransformFeedback(size_t validBufferCount,const VkBuffer * counterBuffers,const VkDeviceSize * counterBufferOffsets,bool rebindBuffers)2136 void RenderPassCommandBufferHelper::beginTransformFeedback(size_t validBufferCount,
2137                                                            const VkBuffer *counterBuffers,
2138                                                            const VkDeviceSize *counterBufferOffsets,
2139                                                            bool rebindBuffers)
2140 {
2141     mValidTransformFeedbackBufferCount = static_cast<uint32_t>(validBufferCount);
2142     mRebindTransformFeedbackBuffers    = rebindBuffers;
2143 
2144     for (size_t index = 0; index < validBufferCount; index++)
2145     {
2146         mTransformFeedbackCounterBuffers[index]       = counterBuffers[index];
2147         mTransformFeedbackCounterBufferOffsets[index] = counterBufferOffsets[index];
2148     }
2149 }
2150 
endTransformFeedback()2151 void RenderPassCommandBufferHelper::endTransformFeedback()
2152 {
2153     pauseTransformFeedback();
2154     mValidTransformFeedbackBufferCount = 0;
2155 }
2156 
invalidateRenderPassColorAttachment(const gl::State & state,size_t colorIndexGL,PackedAttachmentIndex attachmentIndex,const gl::Rectangle & invalidateArea)2157 void RenderPassCommandBufferHelper::invalidateRenderPassColorAttachment(
2158     const gl::State &state,
2159     size_t colorIndexGL,
2160     PackedAttachmentIndex attachmentIndex,
2161     const gl::Rectangle &invalidateArea)
2162 {
2163     // Color write is enabled if:
2164     //
2165     // - Draw buffer is enabled (this is implicit, as invalidate only affects enabled draw buffers)
2166     // - Color output is not entirely masked
2167     // - Rasterizer-discard is not enabled
2168     const gl::BlendStateExt &blendStateExt = state.getBlendStateExt();
2169     const bool isColorWriteEnabled =
2170         blendStateExt.getColorMaskIndexed(colorIndexGL) != 0 && state.isRasterizerDiscardEnabled();
2171     mColorAttachments[attachmentIndex].invalidate(invalidateArea, isColorWriteEnabled,
2172                                                   getRenderPassWriteCommandCount());
2173 }
2174 
invalidateRenderPassDepthAttachment(const gl::DepthStencilState & dsState,const gl::Rectangle & invalidateArea)2175 void RenderPassCommandBufferHelper::invalidateRenderPassDepthAttachment(
2176     const gl::DepthStencilState &dsState,
2177     const gl::Rectangle &invalidateArea)
2178 {
2179     const bool isDepthWriteEnabled = dsState.depthTest && dsState.depthMask;
2180     mDepthAttachment.invalidate(invalidateArea, isDepthWriteEnabled,
2181                                 getRenderPassWriteCommandCount());
2182 }
2183 
invalidateRenderPassStencilAttachment(const gl::DepthStencilState & dsState,const gl::Rectangle & invalidateArea)2184 void RenderPassCommandBufferHelper::invalidateRenderPassStencilAttachment(
2185     const gl::DepthStencilState &dsState,
2186     const gl::Rectangle &invalidateArea)
2187 {
2188     const bool isStencilWriteEnabled =
2189         dsState.stencilTest && (!dsState.isStencilNoOp() || !dsState.isStencilBackNoOp());
2190     mStencilAttachment.invalidate(invalidateArea, isStencilWriteEnabled,
2191                                   getRenderPassWriteCommandCount());
2192 }
2193 
flushToPrimary(Context * context,PrimaryCommandBuffer * primary,const RenderPass * renderPass)2194 angle::Result RenderPassCommandBufferHelper::flushToPrimary(Context *context,
2195                                                             PrimaryCommandBuffer *primary,
2196                                                             const RenderPass *renderPass)
2197 {
2198     ANGLE_TRACE_EVENT0("gpu.angle", "RenderPassCommandBufferHelper::flushToPrimary");
2199     ASSERT(mRenderPassStarted);
2200 
2201     // Commands that are added to primary before beginRenderPass command
2202     executeBarriers(context->getRenderer()->getFeatures(), primary);
2203 
2204     ASSERT(renderPass != nullptr);
2205 
2206     VkRenderPassBeginInfo beginInfo    = {};
2207     beginInfo.sType                    = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
2208     beginInfo.renderPass               = renderPass->getHandle();
2209     beginInfo.framebuffer              = mFramebuffer.getHandle();
2210     beginInfo.renderArea.offset.x      = static_cast<uint32_t>(mRenderArea.x);
2211     beginInfo.renderArea.offset.y      = static_cast<uint32_t>(mRenderArea.y);
2212     beginInfo.renderArea.extent.width  = static_cast<uint32_t>(mRenderArea.width);
2213     beginInfo.renderArea.extent.height = static_cast<uint32_t>(mRenderArea.height);
2214     beginInfo.clearValueCount          = static_cast<uint32_t>(mRenderPassDesc.attachmentCount());
2215     beginInfo.pClearValues             = mClearValues.data();
2216 
2217     // Run commands inside the RenderPass.
2218     constexpr VkSubpassContents kSubpassContents =
2219         RenderPassCommandBuffer::ExecutesInline() ? VK_SUBPASS_CONTENTS_INLINE
2220                                                   : VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS;
2221 
2222     primary->beginRenderPass(beginInfo, kSubpassContents);
2223     for (uint32_t subpass = 0; subpass <= mCurrentSubpass; ++subpass)
2224     {
2225         if (subpass > 0)
2226         {
2227             primary->nextSubpass(kSubpassContents);
2228         }
2229         mCommandBuffers[subpass].executeCommands(primary);
2230     }
2231     primary->endRenderPass();
2232 
2233     // Restart the command buffer.
2234     return reset(context);
2235 }
2236 
updateRenderPassForResolve(ContextVk * contextVk,Framebuffer * newFramebuffer,const RenderPassDesc & renderPassDesc)2237 void RenderPassCommandBufferHelper::updateRenderPassForResolve(ContextVk *contextVk,
2238                                                                Framebuffer *newFramebuffer,
2239                                                                const RenderPassDesc &renderPassDesc)
2240 {
2241     ASSERT(newFramebuffer);
2242     mFramebuffer.setHandle(newFramebuffer->getHandle());
2243     mRenderPassDesc = renderPassDesc;
2244 }
2245 
resumeTransformFeedback()2246 void RenderPassCommandBufferHelper::resumeTransformFeedback()
2247 {
2248     ASSERT(isTransformFeedbackStarted());
2249 
2250     uint32_t numCounterBuffers =
2251         mRebindTransformFeedbackBuffers ? 0 : mValidTransformFeedbackBufferCount;
2252 
2253     mRebindTransformFeedbackBuffers    = false;
2254     mIsTransformFeedbackActiveUnpaused = true;
2255 
2256     getCommandBuffer().beginTransformFeedback(0, numCounterBuffers,
2257                                               mTransformFeedbackCounterBuffers.data(),
2258                                               mTransformFeedbackCounterBufferOffsets.data());
2259 }
2260 
pauseTransformFeedback()2261 void RenderPassCommandBufferHelper::pauseTransformFeedback()
2262 {
2263     ASSERT(isTransformFeedbackStarted() && isTransformFeedbackActiveUnpaused());
2264     mIsTransformFeedbackActiveUnpaused = false;
2265     getCommandBuffer().endTransformFeedback(0, mValidTransformFeedbackBufferCount,
2266                                             mTransformFeedbackCounterBuffers.data(),
2267                                             mTransformFeedbackCounterBufferOffsets.data());
2268 }
2269 
updateRenderPassColorClear(PackedAttachmentIndex colorIndexVk,const VkClearValue & clearValue)2270 void RenderPassCommandBufferHelper::updateRenderPassColorClear(PackedAttachmentIndex colorIndexVk,
2271                                                                const VkClearValue &clearValue)
2272 {
2273     mAttachmentOps.setClearOp(colorIndexVk);
2274     mClearValues.store(colorIndexVk, VK_IMAGE_ASPECT_COLOR_BIT, clearValue);
2275 }
2276 
updateRenderPassDepthStencilClear(VkImageAspectFlags aspectFlags,const VkClearValue & clearValue)2277 void RenderPassCommandBufferHelper::updateRenderPassDepthStencilClear(
2278     VkImageAspectFlags aspectFlags,
2279     const VkClearValue &clearValue)
2280 {
2281     // Don't overwrite prior clear values for individual aspects.
2282     VkClearValue combinedClearValue = mClearValues[mDepthStencilAttachmentIndex];
2283 
2284     if ((aspectFlags & VK_IMAGE_ASPECT_DEPTH_BIT) != 0)
2285     {
2286         mAttachmentOps.setClearOp(mDepthStencilAttachmentIndex);
2287         combinedClearValue.depthStencil.depth = clearValue.depthStencil.depth;
2288     }
2289 
2290     if ((aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
2291     {
2292         mAttachmentOps.setClearStencilOp(mDepthStencilAttachmentIndex);
2293         combinedClearValue.depthStencil.stencil = clearValue.depthStencil.stencil;
2294     }
2295 
2296     // Bypass special D/S handling. This clear values array stores values packed.
2297     mClearValues.storeNoDepthStencil(mDepthStencilAttachmentIndex, combinedClearValue);
2298 }
2299 
growRenderArea(ContextVk * contextVk,const gl::Rectangle & newRenderArea)2300 void RenderPassCommandBufferHelper::growRenderArea(ContextVk *contextVk,
2301                                                    const gl::Rectangle &newRenderArea)
2302 {
2303     // The render area is grown such that it covers both the previous and the new render areas.
2304     gl::GetEnclosingRectangle(mRenderArea, newRenderArea, &mRenderArea);
2305 
2306     // Remove invalidates that are no longer applicable.
2307     mDepthAttachment.onRenderAreaGrowth(contextVk, mRenderArea);
2308     mStencilAttachment.onRenderAreaGrowth(contextVk, mRenderArea);
2309 }
2310 
addCommandDiagnostics(ContextVk * contextVk)2311 void RenderPassCommandBufferHelper::addCommandDiagnostics(ContextVk *contextVk)
2312 {
2313     std::ostringstream out;
2314     addCommandDiagnosticsCommon(&out);
2315 
2316     size_t attachmentCount             = mRenderPassDesc.attachmentCount();
2317     size_t depthStencilAttachmentCount = mRenderPassDesc.hasDepthStencilAttachment() ? 1 : 0;
2318     size_t colorAttachmentCount        = attachmentCount - depthStencilAttachmentCount;
2319 
2320     PackedAttachmentIndex attachmentIndexVk(0);
2321     std::string loadOps, storeOps;
2322 
2323     if (colorAttachmentCount > 0)
2324     {
2325         loadOps += " Color: ";
2326         storeOps += " Color: ";
2327 
2328         for (size_t i = 0; i < colorAttachmentCount; ++i)
2329         {
2330             loadOps += GetLoadOpShorthand(
2331                 static_cast<RenderPassLoadOp>(mAttachmentOps[attachmentIndexVk].loadOp));
2332             storeOps += GetStoreOpShorthand(
2333                 static_cast<RenderPassStoreOp>(mAttachmentOps[attachmentIndexVk].storeOp));
2334             ++attachmentIndexVk;
2335         }
2336     }
2337 
2338     if (depthStencilAttachmentCount > 0)
2339     {
2340         ASSERT(depthStencilAttachmentCount == 1);
2341 
2342         loadOps += " Depth/Stencil: ";
2343         storeOps += " Depth/Stencil: ";
2344 
2345         loadOps += GetLoadOpShorthand(
2346             static_cast<RenderPassLoadOp>(mAttachmentOps[attachmentIndexVk].loadOp));
2347         loadOps += GetLoadOpShorthand(
2348             static_cast<RenderPassLoadOp>(mAttachmentOps[attachmentIndexVk].stencilLoadOp));
2349 
2350         storeOps += GetStoreOpShorthand(
2351             static_cast<RenderPassStoreOp>(mAttachmentOps[attachmentIndexVk].storeOp));
2352         storeOps += GetStoreOpShorthand(
2353             static_cast<RenderPassStoreOp>(mAttachmentOps[attachmentIndexVk].stencilStoreOp));
2354     }
2355 
2356     if (attachmentCount > 0)
2357     {
2358         out << "LoadOp:  " << loadOps << "\\l";
2359         out << "StoreOp: " << storeOps << "\\l";
2360     }
2361 
2362     for (uint32_t subpass = 0; subpass <= mCurrentSubpass; ++subpass)
2363     {
2364         if (subpass > 0)
2365         {
2366             out << "Next Subpass"
2367                 << "\\l";
2368         }
2369         out << mCommandBuffers[subpass].dumpCommands("\\l");
2370     }
2371     contextVk->addCommandBufferDiagnostics(out.str());
2372 }
2373 
2374 // CommandBufferRecycler implementation.
2375 template <typename CommandBufferT, typename CommandBufferHelperT>
onDestroy()2376 void CommandBufferRecycler<CommandBufferT, CommandBufferHelperT>::onDestroy()
2377 {
2378     for (CommandBufferHelperT *commandBufferHelper : mCommandBufferHelperFreeList)
2379     {
2380         SafeDelete(commandBufferHelper);
2381     }
2382     mCommandBufferHelperFreeList.clear();
2383 
2384     ASSERT(mSecondaryCommandBuffersToReset.empty());
2385 }
2386 
2387 template void CommandBufferRecycler<OutsideRenderPassCommandBuffer,
2388                                     OutsideRenderPassCommandBufferHelper>::onDestroy();
2389 template void
2390 CommandBufferRecycler<RenderPassCommandBuffer, RenderPassCommandBufferHelper>::onDestroy();
2391 
2392 template <typename CommandBufferT, typename CommandBufferHelperT>
getCommandBufferHelper(Context * context,CommandPool * commandPool,CommandBufferHelperT ** commandBufferHelperOut)2393 angle::Result CommandBufferRecycler<CommandBufferT, CommandBufferHelperT>::getCommandBufferHelper(
2394     Context *context,
2395     CommandPool *commandPool,
2396     CommandBufferHelperT **commandBufferHelperOut)
2397 {
2398     if (mCommandBufferHelperFreeList.empty())
2399     {
2400         CommandBufferHelperT *commandBuffer = new CommandBufferHelperT();
2401         *commandBufferHelperOut             = commandBuffer;
2402 
2403         return commandBuffer->initialize(context, commandPool);
2404     }
2405     else
2406     {
2407         CommandBufferHelperT *commandBuffer = mCommandBufferHelperFreeList.back();
2408         mCommandBufferHelperFreeList.pop_back();
2409         *commandBufferHelperOut = commandBuffer;
2410         return angle::Result::Continue;
2411     }
2412 }
2413 
2414 template angle::Result
2415 CommandBufferRecycler<OutsideRenderPassCommandBuffer, OutsideRenderPassCommandBufferHelper>::
2416     getCommandBufferHelper(Context *context,
2417                            CommandPool *commandPool,
2418                            OutsideRenderPassCommandBufferHelper **commandBufferHelperOut);
2419 template angle::Result
2420 CommandBufferRecycler<RenderPassCommandBuffer, RenderPassCommandBufferHelper>::
2421     getCommandBufferHelper(Context *context,
2422                            CommandPool *commandPool,
2423                            RenderPassCommandBufferHelper **commandBufferHelperOut);
2424 
2425 template <typename CommandBufferT, typename CommandBufferHelperT>
recycleCommandBufferHelper(VkDevice device,CommandBufferHelperT ** commandBuffer)2426 void CommandBufferRecycler<CommandBufferT, CommandBufferHelperT>::recycleCommandBufferHelper(
2427     VkDevice device,
2428     CommandBufferHelperT **commandBuffer)
2429 {
2430     ASSERT((*commandBuffer)->empty());
2431     (*commandBuffer)->markOpen();
2432     RecycleCommandBufferHelper(device, &mCommandBufferHelperFreeList, commandBuffer,
2433                                &(*commandBuffer)->getCommandBuffer());
2434 }
2435 
2436 template void
2437 CommandBufferRecycler<OutsideRenderPassCommandBuffer, OutsideRenderPassCommandBufferHelper>::
2438     recycleCommandBufferHelper(VkDevice device,
2439                                OutsideRenderPassCommandBufferHelper **commandBuffer);
2440 template void CommandBufferRecycler<RenderPassCommandBuffer, RenderPassCommandBufferHelper>::
2441     recycleCommandBufferHelper(VkDevice device, RenderPassCommandBufferHelper **commandBuffer);
2442 
2443 template <typename CommandBufferT, typename CommandBufferHelperT>
resetCommandBuffer(CommandBufferT && commandBuffer)2444 void CommandBufferRecycler<CommandBufferT, CommandBufferHelperT>::resetCommandBuffer(
2445     CommandBufferT &&commandBuffer)
2446 {
2447     ResetSecondaryCommandBuffer(&mSecondaryCommandBuffersToReset, std::move(commandBuffer));
2448 }
2449 
2450 // DynamicBuffer implementation.
DynamicBuffer()2451 DynamicBuffer::DynamicBuffer()
2452     : mUsage(0),
2453       mHostVisible(false),
2454       mInitialSize(0),
2455       mNextAllocationOffset(0),
2456       mSize(0),
2457       mAlignment(0),
2458       mMemoryPropertyFlags(0)
2459 {}
2460 
DynamicBuffer(DynamicBuffer && other)2461 DynamicBuffer::DynamicBuffer(DynamicBuffer &&other)
2462     : mUsage(other.mUsage),
2463       mHostVisible(other.mHostVisible),
2464       mInitialSize(other.mInitialSize),
2465       mBuffer(std::move(other.mBuffer)),
2466       mNextAllocationOffset(other.mNextAllocationOffset),
2467       mSize(other.mSize),
2468       mAlignment(other.mAlignment),
2469       mMemoryPropertyFlags(other.mMemoryPropertyFlags),
2470       mInFlightBuffers(std::move(other.mInFlightBuffers)),
2471       mBufferFreeList(std::move(other.mBufferFreeList))
2472 {}
2473 
init(RendererVk * renderer,VkBufferUsageFlags usage,size_t alignment,size_t initialSize,bool hostVisible)2474 void DynamicBuffer::init(RendererVk *renderer,
2475                          VkBufferUsageFlags usage,
2476                          size_t alignment,
2477                          size_t initialSize,
2478                          bool hostVisible)
2479 {
2480     mUsage       = usage;
2481     mHostVisible = hostVisible;
2482     mMemoryPropertyFlags =
2483         (hostVisible) ? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT : VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
2484 
2485     // Check that we haven't overridden the initial size of the buffer in setMinimumSizeForTesting.
2486     if (mInitialSize == 0)
2487     {
2488         mInitialSize = initialSize;
2489         mSize        = 0;
2490     }
2491 
2492     // Workaround for the mock ICD not supporting allocations greater than 0x1000.
2493     // Could be removed if https://github.com/KhronosGroup/Vulkan-Tools/issues/84 is fixed.
2494     if (renderer->isMockICDEnabled())
2495     {
2496         mSize = std::min<size_t>(mSize, 0x1000);
2497     }
2498 
2499     requireAlignment(renderer, alignment);
2500 }
2501 
~DynamicBuffer()2502 DynamicBuffer::~DynamicBuffer()
2503 {
2504     ASSERT(mBuffer == nullptr);
2505     ASSERT(mInFlightBuffers.empty());
2506     ASSERT(mBufferFreeList.empty());
2507 }
2508 
allocateNewBuffer(Context * context)2509 angle::Result DynamicBuffer::allocateNewBuffer(Context *context)
2510 {
2511     context->getPerfCounters().dynamicBufferAllocations++;
2512 
2513     // Allocate the buffer
2514     ASSERT(!mBuffer);
2515     mBuffer = std::make_unique<BufferHelper>();
2516 
2517     VkBufferCreateInfo createInfo    = {};
2518     createInfo.sType                 = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
2519     createInfo.flags                 = 0;
2520     createInfo.size                  = mSize;
2521     createInfo.usage                 = mUsage;
2522     createInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
2523     createInfo.queueFamilyIndexCount = 0;
2524     createInfo.pQueueFamilyIndices   = nullptr;
2525 
2526     return mBuffer->init(context, createInfo, mMemoryPropertyFlags);
2527 }
2528 
allocateFromCurrentBuffer(size_t sizeInBytes,BufferHelper ** bufferHelperOut)2529 bool DynamicBuffer::allocateFromCurrentBuffer(size_t sizeInBytes, BufferHelper **bufferHelperOut)
2530 {
2531     mNextAllocationOffset =
2532         roundUp<uint32_t>(mNextAllocationOffset, static_cast<uint32_t>(mAlignment));
2533 
2534     ASSERT(bufferHelperOut);
2535     size_t sizeToAllocate                                      = roundUp(sizeInBytes, mAlignment);
2536     angle::base::CheckedNumeric<size_t> checkedNextWriteOffset = mNextAllocationOffset;
2537     checkedNextWriteOffset += sizeToAllocate;
2538 
2539     if (!checkedNextWriteOffset.IsValid() || checkedNextWriteOffset.ValueOrDie() > mSize)
2540     {
2541         return false;
2542     }
2543 
2544     ASSERT(mBuffer != nullptr);
2545     ASSERT(mHostVisible);
2546     ASSERT(mBuffer->getMappedMemory());
2547     mBuffer->setSuballocationOffsetAndSize(mNextAllocationOffset, sizeToAllocate);
2548     *bufferHelperOut = mBuffer.get();
2549 
2550     mNextAllocationOffset += static_cast<uint32_t>(sizeToAllocate);
2551     return true;
2552 }
2553 
allocate(Context * context,size_t sizeInBytes,BufferHelper ** bufferHelperOut,bool * newBufferAllocatedOut)2554 angle::Result DynamicBuffer::allocate(Context *context,
2555                                       size_t sizeInBytes,
2556                                       BufferHelper **bufferHelperOut,
2557                                       bool *newBufferAllocatedOut)
2558 {
2559     bool newBuffer = !allocateFromCurrentBuffer(sizeInBytes, bufferHelperOut);
2560     if (newBufferAllocatedOut)
2561     {
2562         *newBufferAllocatedOut = newBuffer;
2563     }
2564 
2565     if (!newBuffer)
2566     {
2567         return angle::Result::Continue;
2568     }
2569 
2570     size_t sizeToAllocate = roundUp(sizeInBytes, mAlignment);
2571 
2572     if (mBuffer)
2573     {
2574         // Make sure the buffer is not released externally.
2575         ASSERT(mBuffer->valid());
2576         mInFlightBuffers.push_back(std::move(mBuffer));
2577         ASSERT(!mBuffer);
2578     }
2579 
2580     RendererVk *renderer = context->getRenderer();
2581 
2582     const size_t sizeIgnoringHistory = std::max(mInitialSize, sizeToAllocate);
2583     if (sizeToAllocate > mSize || sizeIgnoringHistory < mSize / 4)
2584     {
2585         mSize = sizeIgnoringHistory;
2586         // Clear the free list since the free buffers are now either too small or too big.
2587         ReleaseBufferListToRenderer(renderer, &mBufferFreeList);
2588     }
2589 
2590     // The front of the free list should be the oldest. Thus if it is in use the rest of the
2591     // free list should be in use as well.
2592     if (mBufferFreeList.empty() ||
2593         mBufferFreeList.front()->isCurrentlyInUse(renderer->getLastCompletedQueueSerial()))
2594     {
2595         ANGLE_TRY(allocateNewBuffer(context));
2596     }
2597     else
2598     {
2599         mBuffer = std::move(mBufferFreeList.front());
2600         mBufferFreeList.erase(mBufferFreeList.begin());
2601     }
2602 
2603     ASSERT(mBuffer->getBlockMemorySize() == mSize);
2604 
2605     mNextAllocationOffset = 0;
2606 
2607     ASSERT(mBuffer != nullptr);
2608     mBuffer->setSuballocationOffsetAndSize(mNextAllocationOffset, sizeToAllocate);
2609     *bufferHelperOut = mBuffer.get();
2610 
2611     mNextAllocationOffset += static_cast<uint32_t>(sizeToAllocate);
2612     return angle::Result::Continue;
2613 }
2614 
release(RendererVk * renderer)2615 void DynamicBuffer::release(RendererVk *renderer)
2616 {
2617     reset();
2618 
2619     ReleaseBufferListToRenderer(renderer, &mInFlightBuffers);
2620     ReleaseBufferListToRenderer(renderer, &mBufferFreeList);
2621 
2622     if (mBuffer)
2623     {
2624         mBuffer->release(renderer);
2625         mBuffer.reset(nullptr);
2626     }
2627 }
2628 
releaseInFlightBuffersToResourceUseList(ContextVk * contextVk)2629 void DynamicBuffer::releaseInFlightBuffersToResourceUseList(ContextVk *contextVk)
2630 {
2631     ResourceUseList *resourceUseList = &contextVk->getResourceUseList();
2632     for (std::unique_ptr<BufferHelper> &bufferHelper : mInFlightBuffers)
2633     {
2634         // This function is used only for internal buffers, and they are all read-only.
2635         // It's possible this may change in the future, but there isn't a good way to detect that,
2636         // unfortunately.
2637         bufferHelper->retainReadOnly(resourceUseList);
2638 
2639         // We only keep free buffers that have the same size. Note that bufferHelper's size is
2640         // suballocation's size. We need to use the whole block memory size here.
2641         if (bufferHelper->getBlockMemorySize() != mSize)
2642         {
2643             bufferHelper->release(contextVk->getRenderer());
2644         }
2645         else
2646         {
2647             mBufferFreeList.push_back(std::move(bufferHelper));
2648         }
2649     }
2650     mInFlightBuffers.clear();
2651 }
2652 
destroy(RendererVk * renderer)2653 void DynamicBuffer::destroy(RendererVk *renderer)
2654 {
2655     reset();
2656 
2657     DestroyBufferList(renderer, &mInFlightBuffers);
2658     DestroyBufferList(renderer, &mBufferFreeList);
2659 
2660     if (mBuffer)
2661     {
2662         mBuffer->unmap(renderer);
2663         mBuffer->destroy(renderer);
2664         mBuffer.reset(nullptr);
2665     }
2666 }
2667 
requireAlignment(RendererVk * renderer,size_t alignment)2668 void DynamicBuffer::requireAlignment(RendererVk *renderer, size_t alignment)
2669 {
2670     ASSERT(alignment > 0);
2671 
2672     size_t prevAlignment = mAlignment;
2673 
2674     // If alignment was never set, initialize it with the atom size limit.
2675     if (prevAlignment == 0)
2676     {
2677         prevAlignment =
2678             static_cast<size_t>(renderer->getPhysicalDeviceProperties().limits.nonCoherentAtomSize);
2679         ASSERT(gl::isPow2(prevAlignment));
2680     }
2681 
2682     // We need lcm(prevAlignment, alignment).  Usually, one divides the other so std::max() could be
2683     // used instead.  Only known case where this assumption breaks is for 3-component types with
2684     // 16- or 32-bit channels, so that's special-cased to avoid a full-fledged lcm implementation.
2685 
2686     if (gl::isPow2(prevAlignment * alignment))
2687     {
2688         ASSERT(alignment % prevAlignment == 0 || prevAlignment % alignment == 0);
2689 
2690         alignment = std::max(prevAlignment, alignment);
2691     }
2692     else
2693     {
2694         ASSERT(prevAlignment % 3 != 0 || gl::isPow2(prevAlignment / 3));
2695         ASSERT(alignment % 3 != 0 || gl::isPow2(alignment / 3));
2696 
2697         prevAlignment = prevAlignment % 3 == 0 ? prevAlignment / 3 : prevAlignment;
2698         alignment     = alignment % 3 == 0 ? alignment / 3 : alignment;
2699 
2700         alignment = std::max(prevAlignment, alignment) * 3;
2701     }
2702 
2703     // If alignment has changed, make sure the next allocation is done at an aligned offset.
2704     if (alignment != mAlignment)
2705     {
2706         mNextAllocationOffset = roundUp(mNextAllocationOffset, static_cast<uint32_t>(alignment));
2707     }
2708 
2709     mAlignment = alignment;
2710 }
2711 
setMinimumSizeForTesting(size_t minSize)2712 void DynamicBuffer::setMinimumSizeForTesting(size_t minSize)
2713 {
2714     // This will really only have an effect next time we call allocate.
2715     mInitialSize = minSize;
2716 
2717     // Forces a new allocation on the next allocate.
2718     mSize = 0;
2719 }
2720 
reset()2721 void DynamicBuffer::reset()
2722 {
2723     mSize                 = 0;
2724     mNextAllocationOffset = 0;
2725 }
2726 
2727 // BufferPool implementation.
BufferPool()2728 BufferPool::BufferPool()
2729     : mVirtualBlockCreateFlags(vma::VirtualBlockCreateFlagBits::GENERAL),
2730       mUsage(0),
2731       mHostVisible(false),
2732       mSize(0),
2733       mMemoryTypeIndex(0)
2734 {}
2735 
BufferPool(BufferPool && other)2736 BufferPool::BufferPool(BufferPool &&other)
2737     : mVirtualBlockCreateFlags(other.mVirtualBlockCreateFlags),
2738       mUsage(other.mUsage),
2739       mHostVisible(other.mHostVisible),
2740       mSize(other.mSize),
2741       mMemoryTypeIndex(other.mMemoryTypeIndex)
2742 {}
2743 
initWithFlags(RendererVk * renderer,vma::VirtualBlockCreateFlags flags,VkBufferUsageFlags usage,VkDeviceSize initialSize,uint32_t memoryTypeIndex,VkMemoryPropertyFlags memoryPropertyFlags)2744 void BufferPool::initWithFlags(RendererVk *renderer,
2745                                vma::VirtualBlockCreateFlags flags,
2746                                VkBufferUsageFlags usage,
2747                                VkDeviceSize initialSize,
2748                                uint32_t memoryTypeIndex,
2749                                VkMemoryPropertyFlags memoryPropertyFlags)
2750 {
2751     mVirtualBlockCreateFlags = flags;
2752     mUsage                   = usage;
2753     mMemoryTypeIndex         = memoryTypeIndex;
2754     if (initialSize)
2755     {
2756         // Should be power of two
2757         ASSERT(gl::isPow2(initialSize));
2758         mSize = initialSize;
2759     }
2760     else
2761     {
2762         mSize = renderer->getPreferedBufferBlockSize(memoryTypeIndex);
2763     }
2764     mHostVisible = ((memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0);
2765 }
2766 
~BufferPool()2767 BufferPool::~BufferPool()
2768 {
2769     ASSERT(mBufferBlocks.empty());
2770 }
2771 
pruneEmptyBuffers(RendererVk * renderer)2772 void BufferPool::pruneEmptyBuffers(RendererVk *renderer)
2773 {
2774     int emptyBufferCount = 0;
2775     int freedBufferCount = 0;
2776     for (auto iter = mBufferBlocks.rbegin(); iter != mBufferBlocks.rend();)
2777     {
2778         if (!(*iter)->isEmpty())
2779         {
2780             ++iter;
2781             continue;
2782         }
2783 
2784         // Record how many times this buffer block has found to be empty  seqentially.
2785         int32_t countRemainsEmpty = (*iter)->getAndIncrementEmptyCounter();
2786 
2787         // We will always free empty buffers that has smaller size. Or if the empty buffer has been
2788         // found empty for long enough time, or we accumulated too many empty buffers, we also free
2789         // it.
2790         if ((*iter)->getMemorySize() < mSize || countRemainsEmpty >= kMaxCountRemainsEmpty ||
2791             emptyBufferCount >= kMaxEmptyBufferCount)
2792         {
2793             (*iter)->destroy(renderer);
2794             (*iter).reset();
2795             ++freedBufferCount;
2796         }
2797         else
2798         {
2799             ++emptyBufferCount;
2800         }
2801         ++iter;
2802     }
2803 
2804     // Remove the null pointers all at once, if any.
2805     if (freedBufferCount)
2806     {
2807         BufferBlockPointerVector compactedBlocks;
2808         for (auto iter = mBufferBlocks.begin(); iter != mBufferBlocks.end(); ++iter)
2809         {
2810             if (*iter)
2811             {
2812                 compactedBlocks.push_back(std::move(*iter));
2813             }
2814         }
2815         mBufferBlocks = std::move(compactedBlocks);
2816     }
2817 }
2818 
allocateNewBuffer(Context * context,VkDeviceSize sizeInBytes)2819 angle::Result BufferPool::allocateNewBuffer(Context *context, VkDeviceSize sizeInBytes)
2820 {
2821     RendererVk *renderer       = context->getRenderer();
2822     const Allocator &allocator = renderer->getAllocator();
2823 
2824     VkDeviceSize heapSize =
2825         renderer->getMemoryProperties().getHeapSizeForMemoryType(mMemoryTypeIndex);
2826 
2827     // First ensure we are not exceeding the heapSize to avoid the validation error.
2828     ANGLE_VK_CHECK(context, sizeInBytes <= heapSize, VK_ERROR_OUT_OF_DEVICE_MEMORY);
2829 
2830     // Double the size until meet the requirement. This also helps reducing the fragmentation. Since
2831     // this is global pool, we have less worry about memory waste.
2832     VkDeviceSize newSize = mSize;
2833     while (newSize < sizeInBytes)
2834     {
2835         newSize <<= 1;
2836     }
2837     mSize = std::min(newSize, heapSize);
2838 
2839     // Allocate buffer
2840     VkBufferCreateInfo createInfo    = {};
2841     createInfo.sType                 = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
2842     createInfo.flags                 = 0;
2843     createInfo.size                  = mSize;
2844     createInfo.usage                 = mUsage;
2845     createInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
2846     createInfo.queueFamilyIndexCount = 0;
2847     createInfo.pQueueFamilyIndices   = nullptr;
2848 
2849     VkMemoryPropertyFlags memoryPropertyFlags;
2850     allocator.getMemoryTypeProperties(mMemoryTypeIndex, &memoryPropertyFlags);
2851 
2852     DeviceScoped<Buffer> buffer(renderer->getDevice());
2853     ANGLE_VK_TRY(context, buffer.get().init(context->getDevice(), createInfo));
2854 
2855     DeviceScoped<DeviceMemory> deviceMemory(renderer->getDevice());
2856     VkMemoryPropertyFlags memoryPropertyFlagsOut;
2857     VkDeviceSize sizeOut;
2858     ANGLE_TRY(AllocateBufferMemory(context, memoryPropertyFlags, &memoryPropertyFlagsOut, nullptr,
2859                                    &buffer.get(), &deviceMemory.get(), &sizeOut));
2860     ASSERT(sizeOut >= mSize);
2861 
2862     // Allocate bufferBlock
2863     std::unique_ptr<BufferBlock> block = std::make_unique<BufferBlock>();
2864     ANGLE_TRY(block->init(context, buffer.get(), mVirtualBlockCreateFlags, deviceMemory.get(),
2865                           memoryPropertyFlagsOut, mSize));
2866 
2867     if (mHostVisible)
2868     {
2869         ANGLE_VK_TRY(context, block->map(context->getDevice()));
2870     }
2871 
2872     // Append the bufferBlock into the pool
2873     mBufferBlocks.push_back(std::move(block));
2874     context->getPerfCounters().allocateNewBufferBlockCalls++;
2875 
2876     return angle::Result::Continue;
2877 }
2878 
allocateBuffer(Context * context,VkDeviceSize sizeInBytes,VkDeviceSize alignment,BufferSuballocation * suballocation)2879 angle::Result BufferPool::allocateBuffer(Context *context,
2880                                          VkDeviceSize sizeInBytes,
2881                                          VkDeviceSize alignment,
2882                                          BufferSuballocation *suballocation)
2883 {
2884     ASSERT(alignment);
2885     VkDeviceSize offset;
2886     VkDeviceSize alignedSize = roundUp(sizeInBytes, alignment);
2887 
2888     if (alignedSize >= kMaxBufferSizeForSuballocation)
2889     {
2890         VkDeviceSize heapSize =
2891             context->getRenderer()->getMemoryProperties().getHeapSizeForMemoryType(
2892                 mMemoryTypeIndex);
2893         // First ensure we are not exceeding the heapSize to avoid the validation error.
2894         ANGLE_VK_CHECK(context, sizeInBytes <= heapSize, VK_ERROR_OUT_OF_DEVICE_MEMORY);
2895 
2896         // Allocate buffer
2897         VkBufferCreateInfo createInfo    = {};
2898         createInfo.sType                 = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
2899         createInfo.flags                 = 0;
2900         createInfo.size                  = alignedSize;
2901         createInfo.usage                 = mUsage;
2902         createInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
2903         createInfo.queueFamilyIndexCount = 0;
2904         createInfo.pQueueFamilyIndices   = nullptr;
2905 
2906         VkMemoryPropertyFlags memoryPropertyFlags;
2907         const Allocator &allocator = context->getRenderer()->getAllocator();
2908         allocator.getMemoryTypeProperties(mMemoryTypeIndex, &memoryPropertyFlags);
2909 
2910         DeviceScoped<Buffer> buffer(context->getDevice());
2911         ANGLE_VK_TRY(context, buffer.get().init(context->getDevice(), createInfo));
2912 
2913         DeviceScoped<DeviceMemory> deviceMemory(context->getDevice());
2914         VkMemoryPropertyFlags memoryPropertyFlagsOut;
2915         VkDeviceSize sizeOut;
2916         ANGLE_TRY(AllocateBufferMemory(context, memoryPropertyFlags, &memoryPropertyFlagsOut,
2917                                        nullptr, &buffer.get(), &deviceMemory.get(), &sizeOut));
2918         ASSERT(sizeOut >= alignedSize);
2919 
2920         suballocation->initWithEntireBuffer(context, buffer.get(), deviceMemory.get(),
2921                                             memoryPropertyFlagsOut, alignedSize);
2922         if (mHostVisible)
2923         {
2924             ANGLE_VK_TRY(context, suballocation->map(context));
2925         }
2926         return angle::Result::Continue;
2927     }
2928 
2929     // We always allocate from reverse order so that older buffers have a chance to age out. The
2930     // assumption is that to allocate from new buffers first may have a better chance to leave the
2931     // older buffers completely empty and we may able to free it.
2932     for (auto iter = mBufferBlocks.rbegin(); iter != mBufferBlocks.rend();)
2933     {
2934         std::unique_ptr<BufferBlock> &block = *iter;
2935         if (block->isEmpty() && block->getMemorySize() < mSize)
2936         {
2937             // Don't try to allocate from an empty buffer that has smaller size. It will get
2938             // released when pruneEmptyBuffers get called later on.
2939             ++iter;
2940             continue;
2941         }
2942 
2943         if (block->allocate(alignedSize, alignment, &offset) == VK_SUCCESS)
2944         {
2945             suballocation->init(context->getDevice(), block.get(), offset, alignedSize);
2946             return angle::Result::Continue;
2947         }
2948         ++iter;
2949     }
2950 
2951     ANGLE_TRY(allocateNewBuffer(context, alignedSize));
2952 
2953     // Sub-allocate from the bufferBlock.
2954     std::unique_ptr<BufferBlock> &block = mBufferBlocks.back();
2955     ANGLE_VK_CHECK(context, block->allocate(alignedSize, alignment, &offset) == VK_SUCCESS,
2956                    VK_ERROR_OUT_OF_DEVICE_MEMORY);
2957     suballocation->init(context->getDevice(), block.get(), offset, alignedSize);
2958 
2959     return angle::Result::Continue;
2960 }
2961 
destroy(RendererVk * renderer,bool orphanNonEmptyBufferBlock)2962 void BufferPool::destroy(RendererVk *renderer, bool orphanNonEmptyBufferBlock)
2963 {
2964     for (std::unique_ptr<BufferBlock> &block : mBufferBlocks)
2965     {
2966         if (block->isEmpty())
2967         {
2968             block->destroy(renderer);
2969         }
2970         else
2971         {
2972             // When orphan is not allowed, all BufferBlocks must be empty.
2973             ASSERT(orphanNonEmptyBufferBlock);
2974             renderer->addBufferBlockToOrphanList(block.release());
2975         }
2976     }
2977     mBufferBlocks.clear();
2978 }
2979 
2980 // DescriptorPoolHelper implementation.
DescriptorPoolHelper()2981 DescriptorPoolHelper::DescriptorPoolHelper() : mFreeDescriptorSets(0) {}
2982 
2983 DescriptorPoolHelper::~DescriptorPoolHelper() = default;
2984 
hasCapacity(uint32_t descriptorSetCount) const2985 bool DescriptorPoolHelper::hasCapacity(uint32_t descriptorSetCount) const
2986 {
2987     return mFreeDescriptorSets >= descriptorSetCount;
2988 }
2989 
init(Context * context,const std::vector<VkDescriptorPoolSize> & poolSizesIn,uint32_t maxSets)2990 angle::Result DescriptorPoolHelper::init(Context *context,
2991                                          const std::vector<VkDescriptorPoolSize> &poolSizesIn,
2992                                          uint32_t maxSets)
2993 {
2994     RendererVk *renderer = context->getRenderer();
2995 
2996     if (mDescriptorPool.valid())
2997     {
2998         ASSERT(!isCurrentlyInUse(renderer->getLastCompletedQueueSerial()));
2999         mDescriptorPool.destroy(renderer->getDevice());
3000     }
3001 
3002     // Make a copy of the pool sizes, so we can grow them to satisfy the specified maxSets.
3003     std::vector<VkDescriptorPoolSize> poolSizes = poolSizesIn;
3004 
3005     for (VkDescriptorPoolSize &poolSize : poolSizes)
3006     {
3007         poolSize.descriptorCount *= maxSets;
3008     }
3009 
3010     VkDescriptorPoolCreateInfo descriptorPoolInfo = {};
3011     descriptorPoolInfo.sType                      = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
3012     descriptorPoolInfo.flags                      = 0;
3013     descriptorPoolInfo.maxSets                    = maxSets;
3014     descriptorPoolInfo.poolSizeCount              = static_cast<uint32_t>(poolSizes.size());
3015     descriptorPoolInfo.pPoolSizes                 = poolSizes.data();
3016 
3017     mFreeDescriptorSets = maxSets;
3018 
3019     ANGLE_VK_TRY(context, mDescriptorPool.init(renderer->getDevice(), descriptorPoolInfo));
3020 
3021     return angle::Result::Continue;
3022 }
3023 
destroy(VkDevice device)3024 void DescriptorPoolHelper::destroy(VkDevice device)
3025 {
3026     mDescriptorPool.destroy(device);
3027 }
3028 
release(ContextVk * contextVk)3029 void DescriptorPoolHelper::release(ContextVk *contextVk)
3030 {
3031     contextVk->addGarbage(&mDescriptorPool);
3032 }
3033 
allocateDescriptorSets(Context * context,ResourceUseList * resourceUseList,const DescriptorSetLayout & descriptorSetLayout,uint32_t descriptorSetCount,VkDescriptorSet * descriptorSetsOut)3034 angle::Result DescriptorPoolHelper::allocateDescriptorSets(
3035     Context *context,
3036     ResourceUseList *resourceUseList,
3037     const DescriptorSetLayout &descriptorSetLayout,
3038     uint32_t descriptorSetCount,
3039     VkDescriptorSet *descriptorSetsOut)
3040 {
3041     VkDescriptorSetAllocateInfo allocInfo = {};
3042     allocInfo.sType                       = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
3043     allocInfo.descriptorPool              = mDescriptorPool.getHandle();
3044     allocInfo.descriptorSetCount          = descriptorSetCount;
3045     allocInfo.pSetLayouts                 = descriptorSetLayout.ptr();
3046 
3047     ASSERT(mFreeDescriptorSets >= descriptorSetCount);
3048     mFreeDescriptorSets -= descriptorSetCount;
3049 
3050     ANGLE_VK_TRY(context, mDescriptorPool.allocateDescriptorSets(context->getDevice(), allocInfo,
3051                                                                  descriptorSetsOut));
3052 
3053     // The pool is still in use every time a new descriptor set is allocated from it.
3054     retain(resourceUseList);
3055 
3056     return angle::Result::Continue;
3057 }
3058 
3059 // DynamicDescriptorPool implementation.
DynamicDescriptorPool()3060 DynamicDescriptorPool::DynamicDescriptorPool()
3061     : mCurrentPoolIndex(0), mCachedDescriptorSetLayout(VK_NULL_HANDLE)
3062 {}
3063 
3064 DynamicDescriptorPool::~DynamicDescriptorPool() = default;
3065 
init(Context * context,const VkDescriptorPoolSize * setSizes,size_t setSizeCount,VkDescriptorSetLayout descriptorSetLayout)3066 angle::Result DynamicDescriptorPool::init(Context *context,
3067                                           const VkDescriptorPoolSize *setSizes,
3068                                           size_t setSizeCount,
3069                                           VkDescriptorSetLayout descriptorSetLayout)
3070 {
3071     ASSERT(setSizes);
3072     ASSERT(setSizeCount);
3073     ASSERT(mCurrentPoolIndex == 0);
3074     ASSERT(mDescriptorPools.empty() ||
3075            (mDescriptorPools.size() == 1 &&
3076             mDescriptorPools[mCurrentPoolIndex]->get().hasCapacity(mMaxSetsPerPool)));
3077     ASSERT(mCachedDescriptorSetLayout == VK_NULL_HANDLE);
3078 
3079     mPoolSizes.assign(setSizes, setSizes + setSizeCount);
3080     mCachedDescriptorSetLayout = descriptorSetLayout;
3081 
3082     mDescriptorPools.push_back(new RefCountedDescriptorPoolHelper());
3083     mCurrentPoolIndex = mDescriptorPools.size() - 1;
3084     return mDescriptorPools[mCurrentPoolIndex]->get().init(context, mPoolSizes, mMaxSetsPerPool);
3085 }
3086 
destroy(VkDevice device)3087 void DynamicDescriptorPool::destroy(VkDevice device)
3088 {
3089     for (RefCountedDescriptorPoolHelper *pool : mDescriptorPools)
3090     {
3091         ASSERT(!pool->isReferenced());
3092         pool->get().destroy(device);
3093         delete pool;
3094     }
3095 
3096     mDescriptorPools.clear();
3097     mCurrentPoolIndex          = 0;
3098     mCachedDescriptorSetLayout = VK_NULL_HANDLE;
3099 }
3100 
release(ContextVk * contextVk)3101 void DynamicDescriptorPool::release(ContextVk *contextVk)
3102 {
3103     for (RefCountedDescriptorPoolHelper *pool : mDescriptorPools)
3104     {
3105         ASSERT(!pool->isReferenced());
3106         pool->get().release(contextVk);
3107         delete pool;
3108     }
3109 
3110     mDescriptorPools.clear();
3111     mCurrentPoolIndex          = 0;
3112     mCachedDescriptorSetLayout = VK_NULL_HANDLE;
3113 }
3114 
allocateSetsAndGetInfo(Context * context,ResourceUseList * resourceUseList,const DescriptorSetLayout & descriptorSetLayout,uint32_t descriptorSetCount,RefCountedDescriptorPoolBinding * bindingOut,VkDescriptorSet * descriptorSetsOut,bool * newPoolAllocatedOut)3115 angle::Result DynamicDescriptorPool::allocateSetsAndGetInfo(
3116     Context *context,
3117     ResourceUseList *resourceUseList,
3118     const DescriptorSetLayout &descriptorSetLayout,
3119     uint32_t descriptorSetCount,
3120     RefCountedDescriptorPoolBinding *bindingOut,
3121     VkDescriptorSet *descriptorSetsOut,
3122     bool *newPoolAllocatedOut)
3123 {
3124     ASSERT(!mDescriptorPools.empty());
3125     ASSERT(descriptorSetLayout.getHandle() == mCachedDescriptorSetLayout);
3126 
3127     *newPoolAllocatedOut = false;
3128 
3129     if (!bindingOut->valid() || !bindingOut->get().hasCapacity(descriptorSetCount))
3130     {
3131         if (!mDescriptorPools[mCurrentPoolIndex]->get().hasCapacity(descriptorSetCount))
3132         {
3133             ANGLE_TRY(allocateNewPool(context));
3134             *newPoolAllocatedOut = true;
3135         }
3136 
3137         bindingOut->set(mDescriptorPools[mCurrentPoolIndex]);
3138     }
3139 
3140     ++context->getPerfCounters().descriptorSetAllocations;
3141 
3142     return bindingOut->get().allocateDescriptorSets(context, resourceUseList, descriptorSetLayout,
3143                                                     descriptorSetCount, descriptorSetsOut);
3144 }
3145 
allocateNewPool(Context * context)3146 angle::Result DynamicDescriptorPool::allocateNewPool(Context *context)
3147 {
3148     bool found = false;
3149 
3150     Serial lastCompletedSerial = context->getRenderer()->getLastCompletedQueueSerial();
3151     for (size_t poolIndex = 0; poolIndex < mDescriptorPools.size(); ++poolIndex)
3152     {
3153         if (!mDescriptorPools[poolIndex]->isReferenced() &&
3154             !mDescriptorPools[poolIndex]->get().isCurrentlyInUse(lastCompletedSerial))
3155         {
3156             mCurrentPoolIndex = poolIndex;
3157             found             = true;
3158             break;
3159         }
3160     }
3161 
3162     if (!found)
3163     {
3164         mDescriptorPools.push_back(new RefCountedDescriptorPoolHelper());
3165         mCurrentPoolIndex = mDescriptorPools.size() - 1;
3166 
3167         static constexpr size_t kMaxPools = 99999;
3168         ANGLE_VK_CHECK(context, mDescriptorPools.size() < kMaxPools, VK_ERROR_TOO_MANY_OBJECTS);
3169     }
3170 
3171     // This pool is getting hot, so grow its max size to try and prevent allocating another pool in
3172     // the future.
3173     if (mMaxSetsPerPool < kMaxSetsPerPoolMax)
3174     {
3175         mMaxSetsPerPool *= mMaxSetsPerPoolMultiplier;
3176     }
3177 
3178     return mDescriptorPools[mCurrentPoolIndex]->get().init(context, mPoolSizes, mMaxSetsPerPool);
3179 }
3180 
3181 // For testing only!
GetMaxSetsPerPoolForTesting()3182 uint32_t DynamicDescriptorPool::GetMaxSetsPerPoolForTesting()
3183 {
3184     return mMaxSetsPerPool;
3185 }
3186 
3187 // For testing only!
SetMaxSetsPerPoolForTesting(uint32_t maxSetsPerPool)3188 void DynamicDescriptorPool::SetMaxSetsPerPoolForTesting(uint32_t maxSetsPerPool)
3189 {
3190     mMaxSetsPerPool = maxSetsPerPool;
3191 }
3192 
3193 // For testing only!
GetMaxSetsPerPoolMultiplierForTesting()3194 uint32_t DynamicDescriptorPool::GetMaxSetsPerPoolMultiplierForTesting()
3195 {
3196     return mMaxSetsPerPoolMultiplier;
3197 }
3198 
3199 // For testing only!
SetMaxSetsPerPoolMultiplierForTesting(uint32_t maxSetsPerPoolMultiplier)3200 void DynamicDescriptorPool::SetMaxSetsPerPoolMultiplierForTesting(uint32_t maxSetsPerPoolMultiplier)
3201 {
3202     mMaxSetsPerPoolMultiplier = maxSetsPerPoolMultiplier;
3203 }
3204 
3205 // DynamicallyGrowingPool implementation
3206 template <typename Pool>
DynamicallyGrowingPool()3207 DynamicallyGrowingPool<Pool>::DynamicallyGrowingPool()
3208     : mPoolSize(0), mCurrentPool(0), mCurrentFreeEntry(0)
3209 {}
3210 
3211 template <typename Pool>
3212 DynamicallyGrowingPool<Pool>::~DynamicallyGrowingPool() = default;
3213 
3214 template <typename Pool>
initEntryPool(Context * contextVk,uint32_t poolSize)3215 angle::Result DynamicallyGrowingPool<Pool>::initEntryPool(Context *contextVk, uint32_t poolSize)
3216 {
3217     ASSERT(mPools.empty());
3218     mPoolSize         = poolSize;
3219     mCurrentFreeEntry = poolSize;
3220     return angle::Result::Continue;
3221 }
3222 
3223 template <typename Pool>
destroyEntryPool(VkDevice device)3224 void DynamicallyGrowingPool<Pool>::destroyEntryPool(VkDevice device)
3225 {
3226     for (PoolResource &resource : mPools)
3227     {
3228         destroyPoolImpl(device, resource.pool);
3229     }
3230     mPools.clear();
3231 }
3232 
3233 template <typename Pool>
findFreeEntryPool(ContextVk * contextVk)3234 bool DynamicallyGrowingPool<Pool>::findFreeEntryPool(ContextVk *contextVk)
3235 {
3236     Serial lastCompletedQueueSerial = contextVk->getLastCompletedQueueSerial();
3237     for (size_t poolIndex = 0; poolIndex < mPools.size(); ++poolIndex)
3238     {
3239         PoolResource &pool = mPools[poolIndex];
3240         if (pool.freedCount == mPoolSize && !pool.isCurrentlyInUse(lastCompletedQueueSerial))
3241         {
3242             mCurrentPool      = poolIndex;
3243             mCurrentFreeEntry = 0;
3244 
3245             pool.freedCount = 0;
3246 
3247             return true;
3248         }
3249     }
3250 
3251     return false;
3252 }
3253 
3254 template <typename Pool>
allocateNewEntryPool(ContextVk * contextVk,Pool && pool)3255 angle::Result DynamicallyGrowingPool<Pool>::allocateNewEntryPool(ContextVk *contextVk, Pool &&pool)
3256 {
3257     mPools.emplace_back(std::move(pool), 0);
3258 
3259     mCurrentPool      = mPools.size() - 1;
3260     mCurrentFreeEntry = 0;
3261 
3262     return angle::Result::Continue;
3263 }
3264 
3265 template <typename Pool>
onEntryFreed(ContextVk * contextVk,size_t poolIndex)3266 void DynamicallyGrowingPool<Pool>::onEntryFreed(ContextVk *contextVk, size_t poolIndex)
3267 {
3268     ASSERT(poolIndex < mPools.size() && mPools[poolIndex].freedCount < mPoolSize);
3269     mPools[poolIndex].retain(&contextVk->getResourceUseList());
3270     ++mPools[poolIndex].freedCount;
3271 }
3272 
3273 template <typename Pool>
allocatePoolEntries(ContextVk * contextVk,uint32_t entryCount,uint32_t * poolIndex,uint32_t * currentEntryOut)3274 angle::Result DynamicallyGrowingPool<Pool>::allocatePoolEntries(ContextVk *contextVk,
3275                                                                 uint32_t entryCount,
3276                                                                 uint32_t *poolIndex,
3277                                                                 uint32_t *currentEntryOut)
3278 {
3279     if (mCurrentFreeEntry + entryCount > mPoolSize)
3280     {
3281         if (!findFreeEntryPool(contextVk))
3282         {
3283             Pool newPool;
3284             ANGLE_TRY(allocatePoolImpl(contextVk, newPool, mPoolSize));
3285             ANGLE_TRY(allocateNewEntryPool(contextVk, std::move(newPool)));
3286         }
3287     }
3288 
3289     *poolIndex       = static_cast<uint32_t>(mCurrentPool);
3290     *currentEntryOut = mCurrentFreeEntry;
3291 
3292     mCurrentFreeEntry += entryCount;
3293 
3294     return angle::Result::Continue;
3295 }
3296 
3297 template <typename Pool>
PoolResource(Pool && poolIn,uint32_t freedCountIn)3298 DynamicallyGrowingPool<Pool>::PoolResource::PoolResource(Pool &&poolIn, uint32_t freedCountIn)
3299     : pool(std::move(poolIn)), freedCount(freedCountIn)
3300 {}
3301 
3302 template <typename Pool>
PoolResource(PoolResource && other)3303 DynamicallyGrowingPool<Pool>::PoolResource::PoolResource(PoolResource &&other)
3304     : pool(std::move(other.pool)), freedCount(other.freedCount)
3305 {}
3306 
3307 // DynamicQueryPool implementation
3308 DynamicQueryPool::DynamicQueryPool() = default;
3309 
3310 DynamicQueryPool::~DynamicQueryPool() = default;
3311 
init(ContextVk * contextVk,VkQueryType type,uint32_t poolSize)3312 angle::Result DynamicQueryPool::init(ContextVk *contextVk, VkQueryType type, uint32_t poolSize)
3313 {
3314     ANGLE_TRY(initEntryPool(contextVk, poolSize));
3315     mQueryType = type;
3316     return angle::Result::Continue;
3317 }
3318 
destroy(VkDevice device)3319 void DynamicQueryPool::destroy(VkDevice device)
3320 {
3321     destroyEntryPool(device);
3322 }
3323 
destroyPoolImpl(VkDevice device,QueryPool & poolToDestroy)3324 void DynamicQueryPool::destroyPoolImpl(VkDevice device, QueryPool &poolToDestroy)
3325 {
3326     poolToDestroy.destroy(device);
3327 }
3328 
allocateQuery(ContextVk * contextVk,QueryHelper * queryOut,uint32_t queryCount)3329 angle::Result DynamicQueryPool::allocateQuery(ContextVk *contextVk,
3330                                               QueryHelper *queryOut,
3331                                               uint32_t queryCount)
3332 {
3333     ASSERT(!queryOut->valid());
3334 
3335     uint32_t currentPool = 0;
3336     uint32_t queryIndex  = 0;
3337     ANGLE_TRY(allocatePoolEntries(contextVk, queryCount, &currentPool, &queryIndex));
3338 
3339     queryOut->init(this, currentPool, queryIndex, queryCount);
3340 
3341     return angle::Result::Continue;
3342 }
3343 
allocatePoolImpl(ContextVk * contextVk,QueryPool & poolToAllocate,uint32_t entriesToAllocate)3344 angle::Result DynamicQueryPool::allocatePoolImpl(ContextVk *contextVk,
3345                                                  QueryPool &poolToAllocate,
3346                                                  uint32_t entriesToAllocate)
3347 {
3348     VkQueryPoolCreateInfo queryPoolInfo = {};
3349     queryPoolInfo.sType                 = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
3350     queryPoolInfo.flags                 = 0;
3351     queryPoolInfo.queryType             = this->mQueryType;
3352     queryPoolInfo.queryCount            = entriesToAllocate;
3353     queryPoolInfo.pipelineStatistics    = 0;
3354 
3355     if (this->mQueryType == VK_QUERY_TYPE_PIPELINE_STATISTICS)
3356     {
3357         queryPoolInfo.pipelineStatistics = VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT;
3358     }
3359 
3360     ANGLE_VK_TRY(contextVk, poolToAllocate.init(contextVk->getDevice(), queryPoolInfo));
3361     return angle::Result::Continue;
3362 }
3363 
freeQuery(ContextVk * contextVk,QueryHelper * query)3364 void DynamicQueryPool::freeQuery(ContextVk *contextVk, QueryHelper *query)
3365 {
3366     if (query->valid())
3367     {
3368         size_t poolIndex = query->mQueryPoolIndex;
3369         ASSERT(getQueryPool(poolIndex).valid());
3370 
3371         onEntryFreed(contextVk, poolIndex);
3372 
3373         query->deinit();
3374     }
3375 }
3376 
3377 // QueryResult implementation
setResults(uint64_t * results,uint32_t queryCount)3378 void QueryResult::setResults(uint64_t *results, uint32_t queryCount)
3379 {
3380     ASSERT(mResults[0] == 0 && mResults[1] == 0);
3381 
3382     // Accumulate the query results.  For multiview, where multiple query indices are used to return
3383     // the results, it's undefined how the results are distributed between indices, but the sum is
3384     // guaranteed to be the desired result.
3385     for (uint32_t query = 0; query < queryCount; ++query)
3386     {
3387         for (uint32_t perQueryIndex = 0; perQueryIndex < mIntsPerResult; ++perQueryIndex)
3388         {
3389             mResults[perQueryIndex] += results[query * mIntsPerResult + perQueryIndex];
3390         }
3391     }
3392 }
3393 
3394 // QueryHelper implementation
QueryHelper()3395 QueryHelper::QueryHelper()
3396     : mDynamicQueryPool(nullptr),
3397       mQueryPoolIndex(0),
3398       mQuery(0),
3399       mQueryCount(0),
3400       mStatus(QueryStatus::Inactive)
3401 {}
3402 
~QueryHelper()3403 QueryHelper::~QueryHelper() {}
3404 
3405 // Move constructor
QueryHelper(QueryHelper && rhs)3406 QueryHelper::QueryHelper(QueryHelper &&rhs)
3407     : Resource(std::move(rhs)),
3408       mDynamicQueryPool(rhs.mDynamicQueryPool),
3409       mQueryPoolIndex(rhs.mQueryPoolIndex),
3410       mQuery(rhs.mQuery),
3411       mQueryCount(rhs.mQueryCount)
3412 {
3413     rhs.mDynamicQueryPool = nullptr;
3414     rhs.mQueryPoolIndex   = 0;
3415     rhs.mQuery            = 0;
3416     rhs.mQueryCount       = 0;
3417 }
3418 
operator =(QueryHelper && rhs)3419 QueryHelper &QueryHelper::operator=(QueryHelper &&rhs)
3420 {
3421     std::swap(mDynamicQueryPool, rhs.mDynamicQueryPool);
3422     std::swap(mQueryPoolIndex, rhs.mQueryPoolIndex);
3423     std::swap(mQuery, rhs.mQuery);
3424     std::swap(mQueryCount, rhs.mQueryCount);
3425     return *this;
3426 }
3427 
init(const DynamicQueryPool * dynamicQueryPool,const size_t queryPoolIndex,uint32_t query,uint32_t queryCount)3428 void QueryHelper::init(const DynamicQueryPool *dynamicQueryPool,
3429                        const size_t queryPoolIndex,
3430                        uint32_t query,
3431                        uint32_t queryCount)
3432 {
3433     mDynamicQueryPool = dynamicQueryPool;
3434     mQueryPoolIndex   = queryPoolIndex;
3435     mQuery            = query;
3436     mQueryCount       = queryCount;
3437 
3438     ASSERT(mQueryCount <= gl::IMPLEMENTATION_ANGLE_MULTIVIEW_MAX_VIEWS);
3439 }
3440 
deinit()3441 void QueryHelper::deinit()
3442 {
3443     mDynamicQueryPool = nullptr;
3444     mQueryPoolIndex   = 0;
3445     mQuery            = 0;
3446     mQueryCount       = 0;
3447     mUse.release();
3448     mUse.init();
3449     mStatus = QueryStatus::Inactive;
3450 }
3451 
3452 template <typename CommandBufferT>
beginQueryImpl(ContextVk * contextVk,OutsideRenderPassCommandBuffer * resetCommandBuffer,CommandBufferT * commandBuffer)3453 void QueryHelper::beginQueryImpl(ContextVk *contextVk,
3454                                  OutsideRenderPassCommandBuffer *resetCommandBuffer,
3455                                  CommandBufferT *commandBuffer)
3456 {
3457     ASSERT(mStatus != QueryStatus::Active);
3458     const QueryPool &queryPool = getQueryPool();
3459     resetQueryPoolImpl(contextVk, queryPool, resetCommandBuffer);
3460     commandBuffer->beginQuery(queryPool, mQuery, 0);
3461     mStatus = QueryStatus::Active;
3462 }
3463 
3464 template <typename CommandBufferT>
endQueryImpl(ContextVk * contextVk,CommandBufferT * commandBuffer)3465 void QueryHelper::endQueryImpl(ContextVk *contextVk, CommandBufferT *commandBuffer)
3466 {
3467     ASSERT(mStatus != QueryStatus::Ended);
3468     commandBuffer->endQuery(getQueryPool(), mQuery);
3469     mStatus = QueryStatus::Ended;
3470     // Query results are available after endQuery, retain this query so that we get its serial
3471     // updated which is used to indicate that query results are (or will be) available.
3472     retain(&contextVk->getResourceUseList());
3473 }
3474 
beginQuery(ContextVk * contextVk)3475 angle::Result QueryHelper::beginQuery(ContextVk *contextVk)
3476 {
3477     if (contextVk->hasStartedRenderPass())
3478     {
3479         ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass(
3480             RenderPassClosureReason::BeginNonRenderPassQuery));
3481     }
3482 
3483     OutsideRenderPassCommandBuffer *commandBuffer;
3484     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer({}, &commandBuffer));
3485 
3486     ANGLE_TRY(contextVk->handleGraphicsEventLog(rx::GraphicsEventCmdBuf::InOutsideCmdBufQueryCmd));
3487 
3488     beginQueryImpl(contextVk, commandBuffer, commandBuffer);
3489 
3490     return angle::Result::Continue;
3491 }
3492 
endQuery(ContextVk * contextVk)3493 angle::Result QueryHelper::endQuery(ContextVk *contextVk)
3494 {
3495     if (contextVk->hasStartedRenderPass())
3496     {
3497         ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass(
3498             RenderPassClosureReason::EndNonRenderPassQuery));
3499     }
3500 
3501     OutsideRenderPassCommandBuffer *commandBuffer;
3502     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer({}, &commandBuffer));
3503 
3504     ANGLE_TRY(contextVk->handleGraphicsEventLog(rx::GraphicsEventCmdBuf::InOutsideCmdBufQueryCmd));
3505 
3506     endQueryImpl(contextVk, commandBuffer);
3507 
3508     return angle::Result::Continue;
3509 }
3510 
3511 template <typename CommandBufferT>
resetQueryPoolImpl(ContextVk * contextVk,const QueryPool & queryPool,CommandBufferT * commandBuffer)3512 void QueryHelper::resetQueryPoolImpl(ContextVk *contextVk,
3513                                      const QueryPool &queryPool,
3514                                      CommandBufferT *commandBuffer)
3515 {
3516     RendererVk *renderer = contextVk->getRenderer();
3517     if (vkResetQueryPoolEXT != nullptr && renderer->getFeatures().supportsHostQueryReset.enabled)
3518     {
3519         vkResetQueryPoolEXT(contextVk->getDevice(), queryPool.getHandle(), mQuery, mQueryCount);
3520     }
3521     else
3522     {
3523         commandBuffer->resetQueryPool(queryPool, mQuery, mQueryCount);
3524     }
3525 }
3526 
beginRenderPassQuery(ContextVk * contextVk)3527 angle::Result QueryHelper::beginRenderPassQuery(ContextVk *contextVk)
3528 {
3529     OutsideRenderPassCommandBuffer *outsideRenderPassCommandBuffer;
3530     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer({}, &outsideRenderPassCommandBuffer));
3531 
3532     RenderPassCommandBuffer *renderPassCommandBuffer =
3533         &contextVk->getStartedRenderPassCommands().getCommandBuffer();
3534 
3535     beginQueryImpl(contextVk, outsideRenderPassCommandBuffer, renderPassCommandBuffer);
3536 
3537     return angle::Result::Continue;
3538 }
3539 
endRenderPassQuery(ContextVk * contextVk)3540 void QueryHelper::endRenderPassQuery(ContextVk *contextVk)
3541 {
3542     if (mStatus == QueryStatus::Active)
3543     {
3544         endQueryImpl(contextVk, &contextVk->getStartedRenderPassCommands().getCommandBuffer());
3545     }
3546 }
3547 
flushAndWriteTimestamp(ContextVk * contextVk)3548 angle::Result QueryHelper::flushAndWriteTimestamp(ContextVk *contextVk)
3549 {
3550     if (contextVk->hasStartedRenderPass())
3551     {
3552         ANGLE_TRY(
3553             contextVk->flushCommandsAndEndRenderPass(RenderPassClosureReason::TimestampQuery));
3554     }
3555 
3556     OutsideRenderPassCommandBuffer *commandBuffer;
3557     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer({}, &commandBuffer));
3558     writeTimestamp(contextVk, commandBuffer);
3559     return angle::Result::Continue;
3560 }
3561 
writeTimestampToPrimary(ContextVk * contextVk,PrimaryCommandBuffer * primary)3562 void QueryHelper::writeTimestampToPrimary(ContextVk *contextVk, PrimaryCommandBuffer *primary)
3563 {
3564     // Note that commands may not be flushed at this point.
3565 
3566     const QueryPool &queryPool = getQueryPool();
3567     resetQueryPoolImpl(contextVk, queryPool, primary);
3568     primary->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, queryPool, mQuery);
3569 }
3570 
writeTimestamp(ContextVk * contextVk,OutsideRenderPassCommandBuffer * commandBuffer)3571 void QueryHelper::writeTimestamp(ContextVk *contextVk,
3572                                  OutsideRenderPassCommandBuffer *commandBuffer)
3573 {
3574     const QueryPool &queryPool = getQueryPool();
3575     resetQueryPoolImpl(contextVk, queryPool, commandBuffer);
3576     commandBuffer->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, queryPool, mQuery);
3577     // timestamp results are available immediately, retain this query so that we get its serial
3578     // updated which is used to indicate that query results are (or will be) available.
3579     retain(&contextVk->getResourceUseList());
3580 }
3581 
hasSubmittedCommands() const3582 bool QueryHelper::hasSubmittedCommands() const
3583 {
3584     return mUse.getSerial().valid();
3585 }
3586 
getUint64ResultNonBlocking(ContextVk * contextVk,QueryResult * resultOut,bool * availableOut)3587 angle::Result QueryHelper::getUint64ResultNonBlocking(ContextVk *contextVk,
3588                                                       QueryResult *resultOut,
3589                                                       bool *availableOut)
3590 {
3591     ASSERT(valid());
3592     VkResult result;
3593 
3594     // Ensure that we only wait if we have inserted a query in command buffer. Otherwise you will
3595     // wait forever and trigger GPU timeout.
3596     if (hasSubmittedCommands())
3597     {
3598         constexpr VkQueryResultFlags kFlags = VK_QUERY_RESULT_64_BIT;
3599         result                              = getResultImpl(contextVk, kFlags, resultOut);
3600     }
3601     else
3602     {
3603         result     = VK_SUCCESS;
3604         *resultOut = 0;
3605     }
3606 
3607     if (result == VK_NOT_READY)
3608     {
3609         *availableOut = false;
3610         return angle::Result::Continue;
3611     }
3612     else
3613     {
3614         ANGLE_VK_TRY(contextVk, result);
3615         *availableOut = true;
3616     }
3617     return angle::Result::Continue;
3618 }
3619 
getUint64Result(ContextVk * contextVk,QueryResult * resultOut)3620 angle::Result QueryHelper::getUint64Result(ContextVk *contextVk, QueryResult *resultOut)
3621 {
3622     ASSERT(valid());
3623     if (hasSubmittedCommands())
3624     {
3625         constexpr VkQueryResultFlags kFlags = VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT;
3626         ANGLE_VK_TRY(contextVk, getResultImpl(contextVk, kFlags, resultOut));
3627     }
3628     else
3629     {
3630         *resultOut = 0;
3631     }
3632     return angle::Result::Continue;
3633 }
3634 
getResultImpl(ContextVk * contextVk,const VkQueryResultFlags flags,QueryResult * resultOut)3635 VkResult QueryHelper::getResultImpl(ContextVk *contextVk,
3636                                     const VkQueryResultFlags flags,
3637                                     QueryResult *resultOut)
3638 {
3639     std::array<uint64_t, 2 * gl::IMPLEMENTATION_ANGLE_MULTIVIEW_MAX_VIEWS> results;
3640 
3641     VkDevice device = contextVk->getDevice();
3642     VkResult result = getQueryPool().getResults(device, mQuery, mQueryCount, sizeof(results),
3643                                                 results.data(), sizeof(uint64_t), flags);
3644 
3645     if (result == VK_SUCCESS)
3646     {
3647         resultOut->setResults(results.data(), mQueryCount);
3648     }
3649 
3650     return result;
3651 }
3652 
3653 // DynamicSemaphorePool implementation
3654 DynamicSemaphorePool::DynamicSemaphorePool() = default;
3655 
3656 DynamicSemaphorePool::~DynamicSemaphorePool() = default;
3657 
init(ContextVk * contextVk,uint32_t poolSize)3658 angle::Result DynamicSemaphorePool::init(ContextVk *contextVk, uint32_t poolSize)
3659 {
3660     ANGLE_TRY(initEntryPool(contextVk, poolSize));
3661     return angle::Result::Continue;
3662 }
3663 
destroy(VkDevice device)3664 void DynamicSemaphorePool::destroy(VkDevice device)
3665 {
3666     destroyEntryPool(device);
3667 }
3668 
allocateSemaphore(ContextVk * contextVk,SemaphoreHelper * semaphoreOut)3669 angle::Result DynamicSemaphorePool::allocateSemaphore(ContextVk *contextVk,
3670                                                       SemaphoreHelper *semaphoreOut)
3671 {
3672     ASSERT(!semaphoreOut->getSemaphore());
3673 
3674     uint32_t currentPool  = 0;
3675     uint32_t currentEntry = 0;
3676     ANGLE_TRY(allocatePoolEntries(contextVk, 1, &currentPool, &currentEntry));
3677 
3678     semaphoreOut->init(currentPool, &getPool(currentPool)[currentEntry]);
3679 
3680     return angle::Result::Continue;
3681 }
3682 
freeSemaphore(ContextVk * contextVk,SemaphoreHelper * semaphore)3683 void DynamicSemaphorePool::freeSemaphore(ContextVk *contextVk, SemaphoreHelper *semaphore)
3684 {
3685     if (semaphore->getSemaphore())
3686     {
3687         onEntryFreed(contextVk, semaphore->getSemaphorePoolIndex());
3688         semaphore->deinit();
3689     }
3690 }
3691 
allocatePoolImpl(ContextVk * contextVk,std::vector<Semaphore> & poolToAllocate,uint32_t entriesToAllocate)3692 angle::Result DynamicSemaphorePool::allocatePoolImpl(ContextVk *contextVk,
3693                                                      std::vector<Semaphore> &poolToAllocate,
3694                                                      uint32_t entriesToAllocate)
3695 {
3696     poolToAllocate.resize(entriesToAllocate);
3697     for (Semaphore &semaphore : poolToAllocate)
3698     {
3699         ANGLE_VK_TRY(contextVk, semaphore.init(contextVk->getDevice()));
3700     }
3701     return angle::Result::Continue;
3702 }
3703 
destroyPoolImpl(VkDevice device,std::vector<Semaphore> & poolToDestroy)3704 void DynamicSemaphorePool::destroyPoolImpl(VkDevice device, std::vector<Semaphore> &poolToDestroy)
3705 {
3706     for (Semaphore &semaphore : poolToDestroy)
3707     {
3708         semaphore.destroy(device);
3709     }
3710 }
3711 
3712 // SemaphoreHelper implementation
SemaphoreHelper()3713 SemaphoreHelper::SemaphoreHelper() : mSemaphorePoolIndex(0), mSemaphore(0) {}
3714 
~SemaphoreHelper()3715 SemaphoreHelper::~SemaphoreHelper() {}
3716 
SemaphoreHelper(SemaphoreHelper && other)3717 SemaphoreHelper::SemaphoreHelper(SemaphoreHelper &&other)
3718     : mSemaphorePoolIndex(other.mSemaphorePoolIndex), mSemaphore(other.mSemaphore)
3719 {
3720     other.mSemaphore = nullptr;
3721 }
3722 
operator =(SemaphoreHelper && other)3723 SemaphoreHelper &SemaphoreHelper::operator=(SemaphoreHelper &&other)
3724 {
3725     std::swap(mSemaphorePoolIndex, other.mSemaphorePoolIndex);
3726     std::swap(mSemaphore, other.mSemaphore);
3727     return *this;
3728 }
3729 
init(const size_t semaphorePoolIndex,const Semaphore * semaphore)3730 void SemaphoreHelper::init(const size_t semaphorePoolIndex, const Semaphore *semaphore)
3731 {
3732     mSemaphorePoolIndex = semaphorePoolIndex;
3733     mSemaphore          = semaphore;
3734 }
3735 
deinit()3736 void SemaphoreHelper::deinit()
3737 {
3738     mSemaphorePoolIndex = 0;
3739     mSemaphore          = nullptr;
3740 }
3741 
3742 // LineLoopHelper implementation.
LineLoopHelper(RendererVk * renderer)3743 LineLoopHelper::LineLoopHelper(RendererVk *renderer) {}
3744 LineLoopHelper::~LineLoopHelper() = default;
3745 
getIndexBufferForDrawArrays(ContextVk * contextVk,uint32_t clampedVertexCount,GLint firstVertex,BufferHelper ** bufferOut)3746 angle::Result LineLoopHelper::getIndexBufferForDrawArrays(ContextVk *contextVk,
3747                                                           uint32_t clampedVertexCount,
3748                                                           GLint firstVertex,
3749                                                           BufferHelper **bufferOut)
3750 {
3751     size_t allocateBytes = sizeof(uint32_t) * (static_cast<size_t>(clampedVertexCount) + 1);
3752     ANGLE_TRY(mDynamicIndexBuffer.allocateForVertexConversion(contextVk, allocateBytes,
3753                                                               MemoryHostVisibility::Visible));
3754     uint32_t *indices = reinterpret_cast<uint32_t *>(mDynamicIndexBuffer.getMappedMemory());
3755 
3756     // Note: there could be an overflow in this addition.
3757     uint32_t unsignedFirstVertex = static_cast<uint32_t>(firstVertex);
3758     uint32_t vertexCount         = (clampedVertexCount + unsignedFirstVertex);
3759     for (uint32_t vertexIndex = unsignedFirstVertex; vertexIndex < vertexCount; vertexIndex++)
3760     {
3761         *indices++ = vertexIndex;
3762     }
3763     *indices = unsignedFirstVertex;
3764 
3765     // Since we are not using the VK_MEMORY_PROPERTY_HOST_COHERENT_BIT flag when creating the
3766     // device memory in the StreamingBuffer, we always need to make sure we flush it after
3767     // writing.
3768     ANGLE_TRY(mDynamicIndexBuffer.flush(contextVk->getRenderer()));
3769 
3770     *bufferOut = &mDynamicIndexBuffer;
3771 
3772     return angle::Result::Continue;
3773 }
3774 
getIndexBufferForElementArrayBuffer(ContextVk * contextVk,BufferVk * elementArrayBufferVk,gl::DrawElementsType glIndexType,int indexCount,intptr_t elementArrayOffset,BufferHelper ** bufferOut,uint32_t * indexCountOut)3775 angle::Result LineLoopHelper::getIndexBufferForElementArrayBuffer(ContextVk *contextVk,
3776                                                                   BufferVk *elementArrayBufferVk,
3777                                                                   gl::DrawElementsType glIndexType,
3778                                                                   int indexCount,
3779                                                                   intptr_t elementArrayOffset,
3780                                                                   BufferHelper **bufferOut,
3781                                                                   uint32_t *indexCountOut)
3782 {
3783     if (glIndexType == gl::DrawElementsType::UnsignedByte ||
3784         contextVk->getState().isPrimitiveRestartEnabled())
3785     {
3786         ANGLE_TRACE_EVENT0("gpu.angle", "LineLoopHelper::getIndexBufferForElementArrayBuffer");
3787 
3788         void *srcDataMapping = nullptr;
3789         ANGLE_TRY(elementArrayBufferVk->mapImpl(contextVk, GL_MAP_READ_BIT, &srcDataMapping));
3790         ANGLE_TRY(streamIndices(contextVk, glIndexType, indexCount,
3791                                 static_cast<const uint8_t *>(srcDataMapping) + elementArrayOffset,
3792                                 bufferOut, indexCountOut));
3793         ANGLE_TRY(elementArrayBufferVk->unmapImpl(contextVk));
3794         return angle::Result::Continue;
3795     }
3796 
3797     *indexCountOut = indexCount + 1;
3798 
3799     size_t unitSize = contextVk->getVkIndexTypeSize(glIndexType);
3800 
3801     size_t allocateBytes = unitSize * (indexCount + 1) + 1;
3802     ANGLE_TRY(mDynamicIndexBuffer.allocateForVertexConversion(contextVk, allocateBytes,
3803                                                               MemoryHostVisibility::Visible));
3804 
3805     BufferHelper *sourceBuffer = &elementArrayBufferVk->getBuffer();
3806     VkDeviceSize sourceOffset =
3807         static_cast<VkDeviceSize>(elementArrayOffset) + sourceBuffer->getOffset();
3808     uint64_t unitCount                         = static_cast<VkDeviceSize>(indexCount);
3809     angle::FixedVector<VkBufferCopy, 2> copies = {
3810         {sourceOffset, mDynamicIndexBuffer.getOffset(), unitCount * unitSize},
3811         {sourceOffset, mDynamicIndexBuffer.getOffset() + unitCount * unitSize, unitSize},
3812     };
3813 
3814     vk::CommandBufferAccess access;
3815     access.onBufferTransferWrite(&mDynamicIndexBuffer);
3816     access.onBufferTransferRead(sourceBuffer);
3817 
3818     vk::OutsideRenderPassCommandBuffer *commandBuffer;
3819     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
3820 
3821     commandBuffer->copyBuffer(sourceBuffer->getBuffer(), mDynamicIndexBuffer.getBuffer(),
3822                               static_cast<uint32_t>(copies.size()), copies.data());
3823 
3824     ANGLE_TRY(mDynamicIndexBuffer.flush(contextVk->getRenderer()));
3825 
3826     *bufferOut = &mDynamicIndexBuffer;
3827 
3828     return angle::Result::Continue;
3829 }
3830 
streamIndices(ContextVk * contextVk,gl::DrawElementsType glIndexType,GLsizei indexCount,const uint8_t * srcPtr,BufferHelper ** bufferOut,uint32_t * indexCountOut)3831 angle::Result LineLoopHelper::streamIndices(ContextVk *contextVk,
3832                                             gl::DrawElementsType glIndexType,
3833                                             GLsizei indexCount,
3834                                             const uint8_t *srcPtr,
3835                                             BufferHelper **bufferOut,
3836                                             uint32_t *indexCountOut)
3837 {
3838     size_t unitSize = contextVk->getVkIndexTypeSize(glIndexType);
3839 
3840     uint32_t numOutIndices = indexCount + 1;
3841     if (contextVk->getState().isPrimitiveRestartEnabled())
3842     {
3843         numOutIndices = GetLineLoopWithRestartIndexCount(glIndexType, indexCount, srcPtr);
3844     }
3845     *indexCountOut = numOutIndices;
3846 
3847     ANGLE_TRY(mDynamicIndexBuffer.allocateForVertexConversion(contextVk, unitSize * numOutIndices,
3848                                                               MemoryHostVisibility::Visible));
3849     uint8_t *indices = mDynamicIndexBuffer.getMappedMemory();
3850 
3851     if (contextVk->getState().isPrimitiveRestartEnabled())
3852     {
3853         HandlePrimitiveRestart(contextVk, glIndexType, indexCount, srcPtr, indices);
3854     }
3855     else
3856     {
3857         if (contextVk->shouldConvertUint8VkIndexType(glIndexType))
3858         {
3859             // If vulkan doesn't support uint8 index types, we need to emulate it.
3860             VkIndexType indexType = contextVk->getVkIndexType(glIndexType);
3861             ASSERT(indexType == VK_INDEX_TYPE_UINT16);
3862             uint16_t *indicesDst = reinterpret_cast<uint16_t *>(indices);
3863             for (int i = 0; i < indexCount; i++)
3864             {
3865                 indicesDst[i] = srcPtr[i];
3866             }
3867 
3868             indicesDst[indexCount] = srcPtr[0];
3869         }
3870         else
3871         {
3872             memcpy(indices, srcPtr, unitSize * indexCount);
3873             memcpy(indices + unitSize * indexCount, srcPtr, unitSize);
3874         }
3875     }
3876 
3877     ANGLE_TRY(mDynamicIndexBuffer.flush(contextVk->getRenderer()));
3878 
3879     *bufferOut = &mDynamicIndexBuffer;
3880 
3881     return angle::Result::Continue;
3882 }
3883 
streamIndicesIndirect(ContextVk * contextVk,gl::DrawElementsType glIndexType,BufferHelper * indexBuffer,BufferHelper * indirectBuffer,VkDeviceSize indirectBufferOffset,BufferHelper ** indexBufferOut,BufferHelper ** indirectBufferOut)3884 angle::Result LineLoopHelper::streamIndicesIndirect(ContextVk *contextVk,
3885                                                     gl::DrawElementsType glIndexType,
3886                                                     BufferHelper *indexBuffer,
3887                                                     BufferHelper *indirectBuffer,
3888                                                     VkDeviceSize indirectBufferOffset,
3889                                                     BufferHelper **indexBufferOut,
3890                                                     BufferHelper **indirectBufferOut)
3891 {
3892     size_t unitSize      = contextVk->getVkIndexTypeSize(glIndexType);
3893     size_t allocateBytes = static_cast<size_t>(indexBuffer->getSize() + unitSize);
3894 
3895     if (contextVk->getState().isPrimitiveRestartEnabled())
3896     {
3897         // If primitive restart, new index buffer is 135% the size of the original index buffer. The
3898         // smallest lineloop with primitive restart is 3 indices (point 1, point 2 and restart
3899         // value) when converted to linelist becomes 4 vertices. Expansion of 4/3. Any larger
3900         // lineloops would have less overhead and require less extra space. Any incomplete
3901         // primitives can be dropped or left incomplete and thus not increase the size of the
3902         // destination index buffer. Since we don't know the number of indices being used we'll use
3903         // the size of the index buffer as allocated as the index count.
3904         size_t numInputIndices    = static_cast<size_t>(indexBuffer->getSize() / unitSize);
3905         size_t numNewInputIndices = ((numInputIndices * 4) / 3) + 1;
3906         allocateBytes             = static_cast<size_t>(numNewInputIndices * unitSize);
3907     }
3908 
3909     // Allocate buffer for results
3910     ANGLE_TRY(mDynamicIndexBuffer.allocateForVertexConversion(contextVk, allocateBytes,
3911                                                               MemoryHostVisibility::Visible));
3912     ANGLE_TRY(mDynamicIndirectBuffer.allocateForVertexConversion(
3913         contextVk, sizeof(VkDrawIndexedIndirectCommand), MemoryHostVisibility::Visible));
3914 
3915     *indexBufferOut    = &mDynamicIndexBuffer;
3916     *indirectBufferOut = &mDynamicIndirectBuffer;
3917 
3918     BufferHelper *dstIndexBuffer    = &mDynamicIndexBuffer;
3919     BufferHelper *dstIndirectBuffer = &mDynamicIndirectBuffer;
3920 
3921     // Copy relevant section of the source into destination at allocated offset.  Note that the
3922     // offset returned by allocate() above is in bytes. As is the indices offset pointer.
3923     UtilsVk::ConvertLineLoopIndexIndirectParameters params = {};
3924     params.indirectBufferOffset    = static_cast<uint32_t>(indirectBufferOffset);
3925     params.dstIndirectBufferOffset = 0;
3926     params.srcIndexBufferOffset    = 0;
3927     params.dstIndexBufferOffset    = 0;
3928     params.indicesBitsWidth        = static_cast<uint32_t>(unitSize * 8);
3929 
3930     return contextVk->getUtils().convertLineLoopIndexIndirectBuffer(
3931         contextVk, indirectBuffer, dstIndirectBuffer, dstIndexBuffer, indexBuffer, params);
3932 }
3933 
streamArrayIndirect(ContextVk * contextVk,size_t vertexCount,BufferHelper * arrayIndirectBuffer,VkDeviceSize arrayIndirectBufferOffset,BufferHelper ** indexBufferOut,BufferHelper ** indexIndirectBufferOut)3934 angle::Result LineLoopHelper::streamArrayIndirect(ContextVk *contextVk,
3935                                                   size_t vertexCount,
3936                                                   BufferHelper *arrayIndirectBuffer,
3937                                                   VkDeviceSize arrayIndirectBufferOffset,
3938                                                   BufferHelper **indexBufferOut,
3939                                                   BufferHelper **indexIndirectBufferOut)
3940 {
3941     auto unitSize        = sizeof(uint32_t);
3942     size_t allocateBytes = static_cast<size_t>((vertexCount + 1) * unitSize);
3943 
3944     ANGLE_TRY(mDynamicIndexBuffer.allocateForVertexConversion(contextVk, allocateBytes,
3945                                                               MemoryHostVisibility::Visible));
3946     ANGLE_TRY(mDynamicIndirectBuffer.allocateForVertexConversion(
3947         contextVk, sizeof(VkDrawIndexedIndirectCommand), MemoryHostVisibility::Visible));
3948 
3949     *indexBufferOut         = &mDynamicIndexBuffer;
3950     *indexIndirectBufferOut = &mDynamicIndirectBuffer;
3951 
3952     BufferHelper *dstIndexBuffer    = &mDynamicIndexBuffer;
3953     BufferHelper *dstIndirectBuffer = &mDynamicIndirectBuffer;
3954 
3955     // Copy relevant section of the source into destination at allocated offset.  Note that the
3956     // offset returned by allocate() above is in bytes. As is the indices offset pointer.
3957     UtilsVk::ConvertLineLoopArrayIndirectParameters params = {};
3958     params.indirectBufferOffset    = static_cast<uint32_t>(arrayIndirectBufferOffset);
3959     params.dstIndirectBufferOffset = 0;
3960     params.dstIndexBufferOffset    = 0;
3961     return contextVk->getUtils().convertLineLoopArrayIndirectBuffer(
3962         contextVk, arrayIndirectBuffer, dstIndirectBuffer, dstIndexBuffer, params);
3963 }
3964 
release(ContextVk * contextVk)3965 void LineLoopHelper::release(ContextVk *contextVk)
3966 {
3967     mDynamicIndexBuffer.release(contextVk->getRenderer());
3968     mDynamicIndirectBuffer.release(contextVk->getRenderer());
3969 }
3970 
destroy(RendererVk * renderer)3971 void LineLoopHelper::destroy(RendererVk *renderer)
3972 {
3973     mDynamicIndexBuffer.destroy(renderer);
3974     mDynamicIndirectBuffer.destroy(renderer);
3975 }
3976 
3977 // static
Draw(uint32_t count,uint32_t baseVertex,RenderPassCommandBuffer * commandBuffer)3978 void LineLoopHelper::Draw(uint32_t count,
3979                           uint32_t baseVertex,
3980                           RenderPassCommandBuffer *commandBuffer)
3981 {
3982     // Our first index is always 0 because that's how we set it up in createIndexBuffer*.
3983     commandBuffer->drawIndexedBaseVertex(count, baseVertex);
3984 }
3985 
GetPipelineStage(gl::ShaderType stage)3986 PipelineStage GetPipelineStage(gl::ShaderType stage)
3987 {
3988     const PipelineStage pipelineStage = kPipelineStageShaderMap[stage];
3989     ASSERT(pipelineStage == PipelineStage::VertexShader ||
3990            pipelineStage == PipelineStage::TessellationControl ||
3991            pipelineStage == PipelineStage::TessellationEvaluation ||
3992            pipelineStage == PipelineStage::GeometryShader ||
3993            pipelineStage == PipelineStage::FragmentShader ||
3994            pipelineStage == PipelineStage::ComputeShader);
3995     return pipelineStage;
3996 }
3997 
3998 // PipelineBarrier implementation.
addDiagnosticsString(std::ostringstream & out) const3999 void PipelineBarrier::addDiagnosticsString(std::ostringstream &out) const
4000 {
4001     if (mMemoryBarrierSrcAccess != 0 || mMemoryBarrierDstAccess != 0)
4002     {
4003         out << "Src: 0x" << std::hex << mMemoryBarrierSrcAccess << " &rarr; Dst: 0x" << std::hex
4004             << mMemoryBarrierDstAccess << std::endl;
4005     }
4006 }
4007 
4008 // BufferHelper implementation.
BufferHelper()4009 BufferHelper::BufferHelper()
4010     : mCurrentQueueFamilyIndex(std::numeric_limits<uint32_t>::max()),
4011       mCurrentWriteAccess(0),
4012       mCurrentReadAccess(0),
4013       mCurrentWriteStages(0),
4014       mCurrentReadStages(0),
4015       mSerial()
4016 {}
4017 
4018 BufferHelper::~BufferHelper() = default;
4019 
BufferHelper(BufferHelper && other)4020 BufferHelper::BufferHelper(BufferHelper &&other)
4021 {
4022     *this = std::move(other);
4023 }
4024 
operator =(BufferHelper && other)4025 BufferHelper &BufferHelper::operator=(BufferHelper &&other)
4026 {
4027     ReadWriteResource::operator=(std::move(other));
4028 
4029     mSuballocation        = std::move(other.mSuballocation);
4030     mBufferForVertexArray = std::move(other.mBufferForVertexArray);
4031 
4032     mCurrentQueueFamilyIndex = other.mCurrentQueueFamilyIndex;
4033     mCurrentWriteAccess      = other.mCurrentWriteAccess;
4034     mCurrentReadAccess       = other.mCurrentReadAccess;
4035     mCurrentWriteStages      = other.mCurrentWriteStages;
4036     mCurrentReadStages       = other.mCurrentReadStages;
4037     mSerial                  = other.mSerial;
4038 
4039     return *this;
4040 }
4041 
init(Context * context,const VkBufferCreateInfo & requestedCreateInfo,VkMemoryPropertyFlags memoryPropertyFlags)4042 angle::Result BufferHelper::init(Context *context,
4043                                  const VkBufferCreateInfo &requestedCreateInfo,
4044                                  VkMemoryPropertyFlags memoryPropertyFlags)
4045 {
4046     RendererVk *renderer       = context->getRenderer();
4047     const Allocator &allocator = renderer->getAllocator();
4048 
4049     initializeBarrierTracker(context);
4050 
4051     VkBufferCreateInfo modifiedCreateInfo;
4052     const VkBufferCreateInfo *createInfo = &requestedCreateInfo;
4053 
4054     if (renderer->getFeatures().padBuffersToMaxVertexAttribStride.enabled)
4055     {
4056         const VkDeviceSize maxVertexAttribStride = renderer->getMaxVertexAttribStride();
4057         ASSERT(maxVertexAttribStride);
4058         modifiedCreateInfo = requestedCreateInfo;
4059         modifiedCreateInfo.size += maxVertexAttribStride;
4060         createInfo = &modifiedCreateInfo;
4061     }
4062 
4063     VkMemoryPropertyFlags requiredFlags =
4064         (memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
4065     VkMemoryPropertyFlags preferredFlags =
4066         (memoryPropertyFlags & (~VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
4067 
4068     bool persistentlyMapped = renderer->getFeatures().persistentlyMappedBuffers.enabled;
4069 
4070     // Check that the allocation is not too large.
4071     uint32_t memoryTypeIndex = kInvalidMemoryTypeIndex;
4072     ANGLE_VK_TRY(context, allocator.findMemoryTypeIndexForBufferInfo(
4073                               *createInfo, requiredFlags, preferredFlags, persistentlyMapped,
4074                               &memoryTypeIndex));
4075 
4076     VkDeviceSize heapSize =
4077         renderer->getMemoryProperties().getHeapSizeForMemoryType(memoryTypeIndex);
4078 
4079     ANGLE_VK_CHECK(context, createInfo->size <= heapSize, VK_ERROR_OUT_OF_DEVICE_MEMORY);
4080 
4081     // Allocate buffer object
4082     DeviceScoped<Buffer> buffer(renderer->getDevice());
4083     ANGLE_VK_TRY(context, buffer.get().init(context->getDevice(), *createInfo));
4084 
4085     DeviceScoped<DeviceMemory> deviceMemory(renderer->getDevice());
4086     VkMemoryPropertyFlags memoryPropertyFlagsOut;
4087     VkDeviceSize sizeOut;
4088     ANGLE_TRY(AllocateBufferMemory(context, requiredFlags, &memoryPropertyFlagsOut, nullptr,
4089                                    &buffer.get(), &deviceMemory.get(), &sizeOut));
4090     ASSERT(sizeOut >= createInfo->size);
4091 
4092     mSuballocation.initWithEntireBuffer(context, buffer.get(), deviceMemory.get(),
4093                                         memoryPropertyFlagsOut, requestedCreateInfo.size);
4094 
4095     if (isHostVisible())
4096     {
4097         uint8_t *ptrOut;
4098         ANGLE_TRY(map(context, &ptrOut));
4099     }
4100 
4101     if (renderer->getFeatures().allocateNonZeroMemory.enabled)
4102     {
4103         ANGLE_TRY(initializeNonZeroMemory(context, createInfo->usage, createInfo->size));
4104     }
4105 
4106     return angle::Result::Continue;
4107 }
4108 
initExternal(ContextVk * contextVk,VkMemoryPropertyFlags memoryProperties,const VkBufferCreateInfo & requestedCreateInfo,GLeglClientBufferEXT clientBuffer)4109 angle::Result BufferHelper::initExternal(ContextVk *contextVk,
4110                                          VkMemoryPropertyFlags memoryProperties,
4111                                          const VkBufferCreateInfo &requestedCreateInfo,
4112                                          GLeglClientBufferEXT clientBuffer)
4113 {
4114     ASSERT(IsAndroid());
4115 
4116     RendererVk *renderer = contextVk->getRenderer();
4117 
4118     initializeBarrierTracker(contextVk);
4119 
4120     VkBufferCreateInfo modifiedCreateInfo             = requestedCreateInfo;
4121     VkExternalMemoryBufferCreateInfo externCreateInfo = {};
4122     externCreateInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO;
4123     externCreateInfo.handleTypes =
4124         VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
4125     externCreateInfo.pNext   = nullptr;
4126     modifiedCreateInfo.pNext = &externCreateInfo;
4127 
4128     DeviceScoped<Buffer> buffer(renderer->getDevice());
4129     ANGLE_VK_TRY(contextVk, buffer.get().init(renderer->getDevice(), modifiedCreateInfo));
4130 
4131     DeviceScoped<DeviceMemory> deviceMemory(renderer->getDevice());
4132     VkMemoryPropertyFlags memoryPropertyFlagsOut;
4133     ANGLE_TRY(InitAndroidExternalMemory(contextVk, clientBuffer, memoryProperties, &buffer.get(),
4134                                         &memoryPropertyFlagsOut, &deviceMemory.get()));
4135 
4136     mSuballocation.initWithEntireBuffer(contextVk, buffer.get(), deviceMemory.get(),
4137                                         memoryPropertyFlagsOut, requestedCreateInfo.size);
4138 
4139     if (isHostVisible())
4140     {
4141         uint8_t *ptrOut;
4142         ANGLE_TRY(map(contextVk, &ptrOut));
4143     }
4144 
4145     return angle::Result::Continue;
4146 }
4147 
initSuballocation(ContextVk * contextVk,uint32_t memoryTypeIndex,size_t size,size_t alignment)4148 angle::Result BufferHelper::initSuballocation(ContextVk *contextVk,
4149                                               uint32_t memoryTypeIndex,
4150                                               size_t size,
4151                                               size_t alignment)
4152 {
4153     RendererVk *renderer = contextVk->getRenderer();
4154 
4155     // We should reset these in case the BufferHelper object has been released and called
4156     // initSuballocation again.
4157     initializeBarrierTracker(contextVk);
4158 
4159     if (renderer->getFeatures().padBuffersToMaxVertexAttribStride.enabled)
4160     {
4161         const VkDeviceSize maxVertexAttribStride = renderer->getMaxVertexAttribStride();
4162         ASSERT(maxVertexAttribStride);
4163         size += maxVertexAttribStride;
4164     }
4165 
4166     vk::BufferPool *pool = contextVk->getDefaultBufferPool(size, memoryTypeIndex);
4167     ANGLE_TRY(pool->allocateBuffer(contextVk, size, alignment, &mSuballocation));
4168 
4169     if (renderer->getFeatures().allocateNonZeroMemory.enabled)
4170     {
4171         ANGLE_TRY(initializeNonZeroMemory(contextVk, GetDefaultBufferUsageFlags(renderer), size));
4172     }
4173 
4174     return angle::Result::Continue;
4175 }
4176 
allocateForCopyBuffer(ContextVk * contextVk,size_t size,MemoryCoherency coherency)4177 angle::Result BufferHelper::allocateForCopyBuffer(ContextVk *contextVk,
4178                                                   size_t size,
4179                                                   MemoryCoherency coherency)
4180 {
4181     RendererVk *renderer     = contextVk->getRenderer();
4182     uint32_t memoryTypeIndex = renderer->getStagingBufferMemoryTypeIndex(coherency);
4183     size_t alignment         = renderer->getStagingBufferAlignment();
4184     return initSuballocation(contextVk, memoryTypeIndex, size, alignment);
4185 }
4186 
allocateForVertexConversion(ContextVk * contextVk,size_t size,MemoryHostVisibility hostVisibility)4187 angle::Result BufferHelper::allocateForVertexConversion(ContextVk *contextVk,
4188                                                         size_t size,
4189                                                         MemoryHostVisibility hostVisibility)
4190 {
4191     RendererVk *renderer = contextVk->getRenderer();
4192 
4193     if (valid())
4194     {
4195         // If size is big enough and it is idle, then just reuse the existing buffer.
4196         if (size <= getSize() &&
4197             (hostVisibility == MemoryHostVisibility::Visible) == isHostVisible())
4198         {
4199             if (!isCurrentlyInUse(contextVk->getLastCompletedQueueSerial()))
4200             {
4201                 initializeBarrierTracker(contextVk);
4202                 return angle::Result::Continue;
4203             }
4204             else if (hostVisibility == MemoryHostVisibility::NonVisible)
4205             {
4206                 // For device local buffer, we can reuse the buffer even if it is still GPU busy.
4207                 // The memory barrier should take care of this.
4208                 return angle::Result::Continue;
4209             }
4210         }
4211 
4212         release(renderer);
4213     }
4214 
4215     uint32_t memoryTypeIndex = renderer->getVertexConversionBufferMemoryTypeIndex(hostVisibility);
4216     size_t alignment         = static_cast<size_t>(renderer->getVertexConversionBufferAlignment());
4217 
4218     // The size is retrieved and used in descriptor set. The descriptor set wants aligned size,
4219     // otherwise there are test failures. Note that underline VMA allocation always allocate aligned
4220     // size anyway.
4221     size_t sizeToAllocate = roundUp(size, alignment);
4222 
4223     return initSuballocation(contextVk, memoryTypeIndex, sizeToAllocate, alignment);
4224 }
4225 
allocateForCopyImage(ContextVk * contextVk,size_t size,MemoryCoherency coherency,angle::FormatID formatId,VkDeviceSize * offset,uint8_t ** dataPtr)4226 angle::Result BufferHelper::allocateForCopyImage(ContextVk *contextVk,
4227                                                  size_t size,
4228                                                  MemoryCoherency coherency,
4229                                                  angle::FormatID formatId,
4230                                                  VkDeviceSize *offset,
4231                                                  uint8_t **dataPtr)
4232 {
4233     RendererVk *renderer = contextVk->getRenderer();
4234 
4235     // When a buffer is used in copyImage, the offset must be multiple of pixel bytes. This may
4236     // result in non-power of two alignment. VMA's virtual allocator can not handle non-power of two
4237     // alignment. We have to adjust offset manually.
4238     uint32_t memoryTypeIndex  = renderer->getStagingBufferMemoryTypeIndex(coherency);
4239     size_t imageCopyAlignment = GetImageCopyBufferAlignment(formatId);
4240 
4241     // Add extra padding for potential offset alignment
4242     size_t allocationSize   = size + imageCopyAlignment;
4243     allocationSize          = roundUp(allocationSize, imageCopyAlignment);
4244     size_t stagingAlignment = static_cast<size_t>(renderer->getStagingBufferAlignment());
4245 
4246     ANGLE_TRY(initSuballocation(contextVk, memoryTypeIndex, allocationSize, stagingAlignment));
4247 
4248     *offset  = roundUp(getOffset(), static_cast<VkDeviceSize>(imageCopyAlignment));
4249     *dataPtr = getMappedMemory() + (*offset) - getOffset();
4250 
4251     return angle::Result::Continue;
4252 }
4253 
initializeBarrierTracker(Context * context)4254 ANGLE_INLINE void BufferHelper::initializeBarrierTracker(Context *context)
4255 {
4256     RendererVk *renderer     = context->getRenderer();
4257     mCurrentQueueFamilyIndex = renderer->getQueueFamilyIndex();
4258     mSerial                  = renderer->getResourceSerialFactory().generateBufferSerial();
4259     mCurrentWriteAccess      = 0;
4260     mCurrentReadAccess       = 0;
4261     mCurrentWriteStages      = 0;
4262     mCurrentReadStages       = 0;
4263 }
4264 
initializeNonZeroMemory(Context * context,VkBufferUsageFlags usage,VkDeviceSize size)4265 angle::Result BufferHelper::initializeNonZeroMemory(Context *context,
4266                                                     VkBufferUsageFlags usage,
4267                                                     VkDeviceSize size)
4268 {
4269     RendererVk *renderer = context->getRenderer();
4270 
4271     // This memory can't be mapped, so the buffer must be marked as a transfer destination so we
4272     // can use a staging resource to initialize it to a non-zero value. If the memory is
4273     // mappable we do the initialization in AllocateBufferMemory.
4274     if (!isHostVisible() && (usage & VK_BUFFER_USAGE_TRANSFER_DST_BIT) != 0)
4275     {
4276         ASSERT((usage & VK_BUFFER_USAGE_TRANSFER_DST_BIT) != 0);
4277         // Staging buffer memory is non-zero-initialized in 'init'.
4278         StagingBuffer stagingBuffer;
4279         ANGLE_TRY(stagingBuffer.init(context, size, StagingUsage::Both));
4280 
4281         PrimaryCommandBuffer commandBuffer;
4282         ANGLE_TRY(renderer->getCommandBufferOneOff(context, false, &commandBuffer));
4283 
4284         // Queue a DMA copy.
4285         VkBufferCopy copyRegion = {};
4286         copyRegion.srcOffset    = 0;
4287         copyRegion.dstOffset    = 0;
4288         copyRegion.size         = size;
4289 
4290         commandBuffer.copyBuffer(stagingBuffer.getBuffer(), getBuffer(), 1, &copyRegion);
4291 
4292         ANGLE_VK_TRY(context, commandBuffer.end());
4293 
4294         Serial serial;
4295         ANGLE_TRY(renderer->queueSubmitOneOff(context, std::move(commandBuffer), false,
4296                                               egl::ContextPriority::Medium, nullptr, 0, nullptr,
4297                                               vk::SubmitPolicy::AllowDeferred, &serial));
4298 
4299         stagingBuffer.collectGarbage(renderer, serial);
4300         // Update both SharedResourceUse objects, since mReadOnlyUse tracks when the buffer can be
4301         // destroyed, and mReadWriteUse tracks when the write has completed.
4302         mReadOnlyUse.updateSerialOneOff(serial);
4303         mReadWriteUse.updateSerialOneOff(serial);
4304     }
4305     else if (isHostVisible())
4306     {
4307         // Can map the memory.
4308         // Pick an arbitrary value to initialize non-zero memory for sanitization.
4309         constexpr int kNonZeroInitValue = 55;
4310         uint8_t *mapPointer             = mSuballocation.getMappedMemory();
4311         memset(mapPointer, kNonZeroInitValue, static_cast<size_t>(getSize()));
4312         if (!isCoherent())
4313         {
4314             mSuballocation.flush(renderer->getDevice());
4315         }
4316     }
4317 
4318     return angle::Result::Continue;
4319 }
4320 
getBufferForVertexArray(ContextVk * contextVk,VkDeviceSize actualDataSize,VkDeviceSize * offsetOut)4321 const Buffer &BufferHelper::getBufferForVertexArray(ContextVk *contextVk,
4322                                                     VkDeviceSize actualDataSize,
4323                                                     VkDeviceSize *offsetOut)
4324 {
4325     ASSERT(mSuballocation.valid());
4326     ASSERT(actualDataSize <= mSuballocation.getSize());
4327 
4328     if (!contextVk->isRobustResourceInitEnabled() || !mSuballocation.isSuballocated())
4329     {
4330         *offsetOut = mSuballocation.getOffset();
4331         return mSuballocation.getBuffer();
4332     }
4333 
4334     if (!mBufferForVertexArray.valid())
4335     {
4336         // Allocate buffer that is backed by sub-range of the memory for vertex array usage. This is
4337         // only needed when robust resource init is enabled so that vulkan driver will know the
4338         // exact size of the vertex buffer it is supposedly to use and prevent out of bound access.
4339         VkBufferCreateInfo createInfo    = {};
4340         createInfo.sType                 = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4341         createInfo.flags                 = 0;
4342         createInfo.size                  = actualDataSize;
4343         createInfo.usage                 = kVertexBufferUsageFlags | kIndexBufferUsageFlags;
4344         createInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
4345         createInfo.queueFamilyIndexCount = 0;
4346         createInfo.pQueueFamilyIndices   = nullptr;
4347         mBufferForVertexArray.init(contextVk->getDevice(), createInfo);
4348 
4349         VkMemoryRequirements memoryRequirements;
4350         mBufferForVertexArray.getMemoryRequirements(contextVk->getDevice(), &memoryRequirements);
4351         ASSERT(contextVk->getRenderer()->isMockICDEnabled() ||
4352                mSuballocation.getSize() >= memoryRequirements.size);
4353         ASSERT(!contextVk->getRenderer()->isMockICDEnabled() ||
4354                mSuballocation.getOffset() % memoryRequirements.alignment == 0);
4355 
4356         mBufferForVertexArray.bindMemory(contextVk->getDevice(), mSuballocation.getDeviceMemory(),
4357                                          mSuballocation.getOffset());
4358     }
4359     *offsetOut = 0;
4360     return mBufferForVertexArray;
4361 }
4362 
destroy(RendererVk * renderer)4363 void BufferHelper::destroy(RendererVk *renderer)
4364 {
4365     unmap(renderer);
4366     mBufferForVertexArray.destroy(renderer->getDevice());
4367     mSuballocation.destroy(renderer);
4368 }
4369 
release(RendererVk * renderer)4370 void BufferHelper::release(RendererVk *renderer)
4371 {
4372     unmap(renderer);
4373 
4374     if (mSuballocation.valid())
4375     {
4376         if (mReadOnlyUse.isCurrentlyInUse(renderer->getLastCompletedQueueSerial()))
4377         {
4378             renderer->collectSuballocationGarbage(std::move(mReadOnlyUse),
4379                                                   std::move(mSuballocation),
4380                                                   std::move(mBufferForVertexArray));
4381             mReadOnlyUse.init();
4382         }
4383         else
4384         {
4385             mBufferForVertexArray.destroy(renderer->getDevice());
4386             mSuballocation.destroy(renderer);
4387         }
4388 
4389         if (mReadWriteUse.isCurrentlyInUse(renderer->getLastCompletedQueueSerial()))
4390         {
4391             mReadWriteUse.release();
4392             mReadWriteUse.init();
4393         }
4394     }
4395     ASSERT(!mBufferForVertexArray.valid());
4396 }
4397 
copyFromBuffer(ContextVk * contextVk,BufferHelper * srcBuffer,uint32_t regionCount,const VkBufferCopy * copyRegions)4398 angle::Result BufferHelper::copyFromBuffer(ContextVk *contextVk,
4399                                            BufferHelper *srcBuffer,
4400                                            uint32_t regionCount,
4401                                            const VkBufferCopy *copyRegions)
4402 {
4403     // Check for self-dependency.
4404     vk::CommandBufferAccess access;
4405     if (srcBuffer->getBufferSerial() == getBufferSerial())
4406     {
4407         access.onBufferSelfCopy(this);
4408     }
4409     else
4410     {
4411         access.onBufferTransferRead(srcBuffer);
4412         access.onBufferTransferWrite(this);
4413     }
4414 
4415     OutsideRenderPassCommandBuffer *commandBuffer;
4416     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
4417 
4418     commandBuffer->copyBuffer(srcBuffer->getBuffer(), getBuffer(), regionCount, copyRegions);
4419 
4420     return angle::Result::Continue;
4421 }
4422 
map(Context * context,uint8_t ** ptrOut)4423 angle::Result BufferHelper::map(Context *context, uint8_t **ptrOut)
4424 {
4425     if (!mSuballocation.isMapped())
4426     {
4427         ANGLE_VK_TRY(context, mSuballocation.map(context));
4428     }
4429     *ptrOut = mSuballocation.getMappedMemory();
4430     return angle::Result::Continue;
4431 }
4432 
mapWithOffset(ContextVk * contextVk,uint8_t ** ptrOut,size_t offset)4433 angle::Result BufferHelper::mapWithOffset(ContextVk *contextVk, uint8_t **ptrOut, size_t offset)
4434 {
4435     uint8_t *mapBufPointer;
4436     ANGLE_TRY(map(contextVk, &mapBufPointer));
4437     *ptrOut = mapBufPointer + offset;
4438     return angle::Result::Continue;
4439 }
4440 
flush(RendererVk * renderer,VkDeviceSize offset,VkDeviceSize size)4441 angle::Result BufferHelper::flush(RendererVk *renderer, VkDeviceSize offset, VkDeviceSize size)
4442 {
4443     mSuballocation.flush(renderer->getDevice());
4444     return angle::Result::Continue;
4445 }
flush(RendererVk * renderer)4446 angle::Result BufferHelper::flush(RendererVk *renderer)
4447 {
4448     return flush(renderer, 0, getSize());
4449 }
4450 
invalidate(RendererVk * renderer,VkDeviceSize offset,VkDeviceSize size)4451 angle::Result BufferHelper::invalidate(RendererVk *renderer, VkDeviceSize offset, VkDeviceSize size)
4452 {
4453     mSuballocation.invalidate(renderer->getDevice());
4454     return angle::Result::Continue;
4455 }
invalidate(RendererVk * renderer)4456 angle::Result BufferHelper::invalidate(RendererVk *renderer)
4457 {
4458     return invalidate(renderer, 0, getSize());
4459 }
4460 
changeQueue(uint32_t newQueueFamilyIndex,OutsideRenderPassCommandBuffer * commandBuffer)4461 void BufferHelper::changeQueue(uint32_t newQueueFamilyIndex,
4462                                OutsideRenderPassCommandBuffer *commandBuffer)
4463 {
4464     VkBufferMemoryBarrier bufferMemoryBarrier = {};
4465     bufferMemoryBarrier.sType                 = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
4466     bufferMemoryBarrier.srcAccessMask         = 0;
4467     bufferMemoryBarrier.dstAccessMask         = 0;
4468     bufferMemoryBarrier.srcQueueFamilyIndex   = mCurrentQueueFamilyIndex;
4469     bufferMemoryBarrier.dstQueueFamilyIndex   = newQueueFamilyIndex;
4470     bufferMemoryBarrier.buffer                = getBuffer().getHandle();
4471     bufferMemoryBarrier.offset                = getOffset();
4472     bufferMemoryBarrier.size                  = getSize();
4473 
4474     commandBuffer->bufferBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
4475                                  VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, &bufferMemoryBarrier);
4476 
4477     mCurrentQueueFamilyIndex = newQueueFamilyIndex;
4478 }
4479 
acquireFromExternal(ContextVk * contextVk,uint32_t externalQueueFamilyIndex,uint32_t rendererQueueFamilyIndex,OutsideRenderPassCommandBuffer * commandBuffer)4480 void BufferHelper::acquireFromExternal(ContextVk *contextVk,
4481                                        uint32_t externalQueueFamilyIndex,
4482                                        uint32_t rendererQueueFamilyIndex,
4483                                        OutsideRenderPassCommandBuffer *commandBuffer)
4484 {
4485     mCurrentQueueFamilyIndex = externalQueueFamilyIndex;
4486 
4487     retainReadWrite(&contextVk->getResourceUseList());
4488     changeQueue(rendererQueueFamilyIndex, commandBuffer);
4489 }
4490 
releaseToExternal(ContextVk * contextVk,uint32_t rendererQueueFamilyIndex,uint32_t externalQueueFamilyIndex,OutsideRenderPassCommandBuffer * commandBuffer)4491 void BufferHelper::releaseToExternal(ContextVk *contextVk,
4492                                      uint32_t rendererQueueFamilyIndex,
4493                                      uint32_t externalQueueFamilyIndex,
4494                                      OutsideRenderPassCommandBuffer *commandBuffer)
4495 {
4496     ASSERT(mCurrentQueueFamilyIndex == rendererQueueFamilyIndex);
4497 
4498     retainReadWrite(&contextVk->getResourceUseList());
4499     changeQueue(externalQueueFamilyIndex, commandBuffer);
4500 }
4501 
isReleasedToExternal() const4502 bool BufferHelper::isReleasedToExternal() const
4503 {
4504 #if !defined(ANGLE_PLATFORM_MACOS) && !defined(ANGLE_PLATFORM_ANDROID)
4505     return IsExternalQueueFamily(mCurrentQueueFamilyIndex);
4506 #else
4507     // TODO(anglebug.com/4635): Implement external memory barriers on Mac/Android.
4508     return false;
4509 #endif
4510 }
4511 
recordReadBarrier(VkAccessFlags readAccessType,VkPipelineStageFlags readStage,PipelineBarrier * barrier)4512 bool BufferHelper::recordReadBarrier(VkAccessFlags readAccessType,
4513                                      VkPipelineStageFlags readStage,
4514                                      PipelineBarrier *barrier)
4515 {
4516     bool barrierModified = false;
4517     // If there was a prior write and we are making a read that is either a new access type or from
4518     // a new stage, we need a barrier
4519     if (mCurrentWriteAccess != 0 && (((mCurrentReadAccess & readAccessType) != readAccessType) ||
4520                                      ((mCurrentReadStages & readStage) != readStage)))
4521     {
4522         barrier->mergeMemoryBarrier(mCurrentWriteStages, readStage, mCurrentWriteAccess,
4523                                     readAccessType);
4524         barrierModified = true;
4525     }
4526 
4527     // Accumulate new read usage.
4528     mCurrentReadAccess |= readAccessType;
4529     mCurrentReadStages |= readStage;
4530     return barrierModified;
4531 }
4532 
recordWriteBarrier(VkAccessFlags writeAccessType,VkPipelineStageFlags writeStage,PipelineBarrier * barrier)4533 bool BufferHelper::recordWriteBarrier(VkAccessFlags writeAccessType,
4534                                       VkPipelineStageFlags writeStage,
4535                                       PipelineBarrier *barrier)
4536 {
4537     bool barrierModified = false;
4538     // We don't need to check mCurrentReadStages here since if it is not zero, mCurrentReadAccess
4539     // must not be zero as well. stage is finer grain than accessType.
4540     ASSERT((!mCurrentReadStages && !mCurrentReadAccess) ||
4541            (mCurrentReadStages && mCurrentReadAccess));
4542     if (mCurrentReadAccess != 0 || mCurrentWriteAccess != 0)
4543     {
4544         VkPipelineStageFlags srcStageMask = mCurrentWriteStages | mCurrentReadStages;
4545         barrier->mergeMemoryBarrier(srcStageMask, writeStage, mCurrentWriteAccess, writeAccessType);
4546         barrierModified = true;
4547     }
4548 
4549     // Reset usages on the new write.
4550     mCurrentWriteAccess = writeAccessType;
4551     mCurrentReadAccess  = 0;
4552     mCurrentWriteStages = writeStage;
4553     mCurrentReadStages  = 0;
4554     return barrierModified;
4555 }
4556 
fillWithColor(const angle::Color<uint8_t> & color,const gl::InternalFormat & internalFormat)4557 void BufferHelper::fillWithColor(const angle::Color<uint8_t> &color,
4558                                  const gl::InternalFormat &internalFormat)
4559 {
4560     uint32_t count =
4561         static_cast<uint32_t>(getSize()) / static_cast<uint32_t>(internalFormat.pixelBytes);
4562     void *buffer = static_cast<void *>(getMappedMemory());
4563 
4564     switch (internalFormat.internalFormat)
4565     {
4566         case GL_RGB565:
4567         {
4568             uint16_t pixelColor =
4569                 ((color.blue & 0xF8) << 11) | ((color.green & 0xFC) << 5) | (color.red & 0xF8);
4570             uint16_t *pixelPtr = static_cast<uint16_t *>(buffer);
4571             std::fill_n<uint16_t *, uint32_t, uint16_t>(pixelPtr, count, pixelColor);
4572         }
4573         break;
4574         case GL_RGBA8:
4575         {
4576             uint32_t pixelColor =
4577                 (color.alpha << 24) | (color.blue << 16) | (color.green << 8) | (color.red);
4578             uint32_t *pixelPtr = static_cast<uint32_t *>(buffer);
4579             std::fill_n<uint32_t *, uint32_t, uint32_t>(pixelPtr, count, pixelColor);
4580         }
4581         break;
4582         case GL_BGR565_ANGLEX:
4583         {
4584             uint16_t pixelColor =
4585                 ((color.red & 0xF8) << 11) | ((color.green & 0xFC) << 5) | (color.blue & 0xF8);
4586             uint16_t *pixelPtr = static_cast<uint16_t *>(buffer);
4587             std::fill_n<uint16_t *, uint32_t, uint16_t>(pixelPtr, count, pixelColor);
4588         }
4589         break;
4590         case GL_BGRA8_EXT:
4591         {
4592             uint32_t pixelColor =
4593                 (color.alpha << 24) | (color.red << 16) | (color.green << 8) | (color.blue);
4594             uint32_t *pixelPtr = static_cast<uint32_t *>(buffer);
4595             std::fill_n<uint32_t *, uint32_t, uint32_t>(pixelPtr, count, pixelColor);
4596         }
4597         break;
4598         default:
4599             UNREACHABLE();  // Unsupported format
4600     }
4601 }
4602 
4603 // ImageHelper implementation.
ImageHelper()4604 ImageHelper::ImageHelper()
4605 {
4606     resetCachedProperties();
4607 }
4608 
ImageHelper(ImageHelper && other)4609 ImageHelper::ImageHelper(ImageHelper &&other)
4610     : Resource(std::move(other)),
4611       mImage(std::move(other.mImage)),
4612       mDeviceMemory(std::move(other.mDeviceMemory)),
4613       mImageType(other.mImageType),
4614       mTilingMode(other.mTilingMode),
4615       mCreateFlags(other.mCreateFlags),
4616       mUsage(other.mUsage),
4617       mExtents(other.mExtents),
4618       mRotatedAspectRatio(other.mRotatedAspectRatio),
4619       mIntendedFormatID(other.mIntendedFormatID),
4620       mActualFormatID(other.mActualFormatID),
4621       mSamples(other.mSamples),
4622       mImageSerial(other.mImageSerial),
4623       mCurrentLayout(other.mCurrentLayout),
4624       mCurrentQueueFamilyIndex(other.mCurrentQueueFamilyIndex),
4625       mLastNonShaderReadOnlyLayout(other.mLastNonShaderReadOnlyLayout),
4626       mCurrentShaderReadStageMask(other.mCurrentShaderReadStageMask),
4627       mYcbcrConversionDesc(other.mYcbcrConversionDesc),
4628       mFirstAllocatedLevel(other.mFirstAllocatedLevel),
4629       mLayerCount(other.mLayerCount),
4630       mLevelCount(other.mLevelCount),
4631       mSubresourceUpdates(std::move(other.mSubresourceUpdates)),
4632       mCurrentSingleClearValue(std::move(other.mCurrentSingleClearValue)),
4633       mContentDefined(std::move(other.mContentDefined)),
4634       mStencilContentDefined(std::move(other.mStencilContentDefined)),
4635       mImageAndViewGarbage(std::move(other.mImageAndViewGarbage))
4636 {
4637     ASSERT(this != &other);
4638     other.resetCachedProperties();
4639 }
4640 
~ImageHelper()4641 ImageHelper::~ImageHelper()
4642 {
4643     ASSERT(!valid());
4644 }
4645 
resetCachedProperties()4646 void ImageHelper::resetCachedProperties()
4647 {
4648     mImageType                   = VK_IMAGE_TYPE_2D;
4649     mTilingMode                  = VK_IMAGE_TILING_OPTIMAL;
4650     mCreateFlags                 = kVkImageCreateFlagsNone;
4651     mUsage                       = 0;
4652     mExtents                     = {};
4653     mRotatedAspectRatio          = false;
4654     mIntendedFormatID            = angle::FormatID::NONE;
4655     mActualFormatID              = angle::FormatID::NONE;
4656     mSamples                     = 1;
4657     mImageSerial                 = kInvalidImageSerial;
4658     mCurrentLayout               = ImageLayout::Undefined;
4659     mCurrentQueueFamilyIndex     = std::numeric_limits<uint32_t>::max();
4660     mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
4661     mCurrentShaderReadStageMask  = 0;
4662     mFirstAllocatedLevel         = gl::LevelIndex(0);
4663     mLayerCount                  = 0;
4664     mLevelCount                  = 0;
4665     mYcbcrConversionDesc.reset();
4666     mCurrentSingleClearValue.reset();
4667     mRenderPassUsageFlags.reset();
4668 
4669     setEntireContentUndefined();
4670 }
4671 
setEntireContentDefined()4672 void ImageHelper::setEntireContentDefined()
4673 {
4674     for (LevelContentDefinedMask &levelContentDefined : mContentDefined)
4675     {
4676         levelContentDefined.set();
4677     }
4678     for (LevelContentDefinedMask &levelContentDefined : mStencilContentDefined)
4679     {
4680         levelContentDefined.set();
4681     }
4682 }
4683 
setEntireContentUndefined()4684 void ImageHelper::setEntireContentUndefined()
4685 {
4686     for (LevelContentDefinedMask &levelContentDefined : mContentDefined)
4687     {
4688         levelContentDefined.reset();
4689     }
4690     for (LevelContentDefinedMask &levelContentDefined : mStencilContentDefined)
4691     {
4692         levelContentDefined.reset();
4693     }
4694 
4695     // Note: this function is only called during init/release, so unlike
4696     // invalidateSubresourceContentImpl, it doesn't attempt to make sure emulated formats have a
4697     // clear staged.
4698 }
4699 
setContentDefined(LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags)4700 void ImageHelper::setContentDefined(LevelIndex levelStart,
4701                                     uint32_t levelCount,
4702                                     uint32_t layerStart,
4703                                     uint32_t layerCount,
4704                                     VkImageAspectFlags aspectFlags)
4705 {
4706     // Mark the range as defined.  Layers above 8 are discarded, and are always assumed to have
4707     // defined contents.
4708     if (layerStart >= kMaxContentDefinedLayerCount)
4709     {
4710         return;
4711     }
4712 
4713     uint8_t layerRangeBits =
4714         GetContentDefinedLayerRangeBits(layerStart, layerCount, kMaxContentDefinedLayerCount);
4715 
4716     for (uint32_t levelOffset = 0; levelOffset < levelCount; ++levelOffset)
4717     {
4718         LevelIndex level = levelStart + levelOffset;
4719 
4720         if ((aspectFlags & ~VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
4721         {
4722             getLevelContentDefined(level) |= layerRangeBits;
4723         }
4724         if ((aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
4725         {
4726             getLevelStencilContentDefined(level) |= layerRangeBits;
4727         }
4728     }
4729 }
4730 
getLevelContentDefined(LevelIndex level)4731 ImageHelper::LevelContentDefinedMask &ImageHelper::getLevelContentDefined(LevelIndex level)
4732 {
4733     return mContentDefined[level.get()];
4734 }
4735 
getLevelStencilContentDefined(LevelIndex level)4736 ImageHelper::LevelContentDefinedMask &ImageHelper::getLevelStencilContentDefined(LevelIndex level)
4737 {
4738     return mStencilContentDefined[level.get()];
4739 }
4740 
getLevelContentDefined(LevelIndex level) const4741 const ImageHelper::LevelContentDefinedMask &ImageHelper::getLevelContentDefined(
4742     LevelIndex level) const
4743 {
4744     return mContentDefined[level.get()];
4745 }
4746 
getLevelStencilContentDefined(LevelIndex level) const4747 const ImageHelper::LevelContentDefinedMask &ImageHelper::getLevelStencilContentDefined(
4748     LevelIndex level) const
4749 {
4750     return mStencilContentDefined[level.get()];
4751 }
4752 
init(Context * context,gl::TextureType textureType,const VkExtent3D & extents,const Format & format,GLint samples,VkImageUsageFlags usage,gl::LevelIndex firstLevel,uint32_t mipLevels,uint32_t layerCount,bool isRobustResourceInitEnabled,bool hasProtectedContent)4753 angle::Result ImageHelper::init(Context *context,
4754                                 gl::TextureType textureType,
4755                                 const VkExtent3D &extents,
4756                                 const Format &format,
4757                                 GLint samples,
4758                                 VkImageUsageFlags usage,
4759                                 gl::LevelIndex firstLevel,
4760                                 uint32_t mipLevels,
4761                                 uint32_t layerCount,
4762                                 bool isRobustResourceInitEnabled,
4763                                 bool hasProtectedContent)
4764 {
4765     return initExternal(context, textureType, extents, format.getIntendedFormatID(),
4766                         format.getActualRenderableImageFormatID(), samples, usage,
4767                         kVkImageCreateFlagsNone, ImageLayout::Undefined, nullptr, firstLevel,
4768                         mipLevels, layerCount, isRobustResourceInitEnabled, hasProtectedContent);
4769 }
4770 
initMSAASwapchain(Context * context,gl::TextureType textureType,const VkExtent3D & extents,bool rotatedAspectRatio,const Format & format,GLint samples,VkImageUsageFlags usage,gl::LevelIndex firstLevel,uint32_t mipLevels,uint32_t layerCount,bool isRobustResourceInitEnabled,bool hasProtectedContent)4771 angle::Result ImageHelper::initMSAASwapchain(Context *context,
4772                                              gl::TextureType textureType,
4773                                              const VkExtent3D &extents,
4774                                              bool rotatedAspectRatio,
4775                                              const Format &format,
4776                                              GLint samples,
4777                                              VkImageUsageFlags usage,
4778                                              gl::LevelIndex firstLevel,
4779                                              uint32_t mipLevels,
4780                                              uint32_t layerCount,
4781                                              bool isRobustResourceInitEnabled,
4782                                              bool hasProtectedContent)
4783 {
4784     ANGLE_TRY(initExternal(context, textureType, extents, format.getIntendedFormatID(),
4785                            format.getActualRenderableImageFormatID(), samples, usage,
4786                            kVkImageCreateFlagsNone, ImageLayout::Undefined, nullptr, firstLevel,
4787                            mipLevels, layerCount, isRobustResourceInitEnabled,
4788                            hasProtectedContent));
4789     if (rotatedAspectRatio)
4790     {
4791         std::swap(mExtents.width, mExtents.height);
4792     }
4793     mRotatedAspectRatio = rotatedAspectRatio;
4794     return angle::Result::Continue;
4795 }
4796 
initExternal(Context * context,gl::TextureType textureType,const VkExtent3D & extents,angle::FormatID intendedFormatID,angle::FormatID actualFormatID,GLint samples,VkImageUsageFlags usage,VkImageCreateFlags additionalCreateFlags,ImageLayout initialLayout,const void * externalImageCreateInfo,gl::LevelIndex firstLevel,uint32_t mipLevels,uint32_t layerCount,bool isRobustResourceInitEnabled,bool hasProtectedContent)4797 angle::Result ImageHelper::initExternal(Context *context,
4798                                         gl::TextureType textureType,
4799                                         const VkExtent3D &extents,
4800                                         angle::FormatID intendedFormatID,
4801                                         angle::FormatID actualFormatID,
4802                                         GLint samples,
4803                                         VkImageUsageFlags usage,
4804                                         VkImageCreateFlags additionalCreateFlags,
4805                                         ImageLayout initialLayout,
4806                                         const void *externalImageCreateInfo,
4807                                         gl::LevelIndex firstLevel,
4808                                         uint32_t mipLevels,
4809                                         uint32_t layerCount,
4810                                         bool isRobustResourceInitEnabled,
4811                                         bool hasProtectedContent)
4812 {
4813     ASSERT(!valid());
4814     ASSERT(!IsAnySubresourceContentDefined(mContentDefined));
4815     ASSERT(!IsAnySubresourceContentDefined(mStencilContentDefined));
4816 
4817     RendererVk *rendererVk = context->getRenderer();
4818 
4819     mImageType           = gl_vk::GetImageType(textureType);
4820     mExtents             = extents;
4821     mRotatedAspectRatio  = false;
4822     mIntendedFormatID    = intendedFormatID;
4823     mActualFormatID      = actualFormatID;
4824     mSamples             = std::max(samples, 1);
4825     mImageSerial         = context->getRenderer()->getResourceSerialFactory().generateImageSerial();
4826     mFirstAllocatedLevel = firstLevel;
4827     mLevelCount          = mipLevels;
4828     mLayerCount          = layerCount;
4829     mCreateFlags         = GetImageCreateFlags(textureType) | additionalCreateFlags;
4830     mUsage               = usage;
4831 
4832     // Validate that mLayerCount is compatible with the texture type
4833     ASSERT(textureType != gl::TextureType::_3D || mLayerCount == 1);
4834     ASSERT(textureType != gl::TextureType::_2DArray || mExtents.depth == 1);
4835     ASSERT(textureType != gl::TextureType::External || mLayerCount == 1);
4836     ASSERT(textureType != gl::TextureType::Rectangle || mLayerCount == 1);
4837     ASSERT(textureType != gl::TextureType::CubeMap || mLayerCount == gl::kCubeFaceCount);
4838     ASSERT(textureType != gl::TextureType::CubeMapArray || mLayerCount % gl::kCubeFaceCount == 0);
4839 
4840     // If externalImageCreateInfo is provided, use that directly.  Otherwise derive the necessary
4841     // pNext chain.
4842     const void *imageCreateInfoPNext = externalImageCreateInfo;
4843     VkImageFormatListCreateInfoKHR imageFormatListInfoStorage;
4844     ImageListFormats imageListFormatsStorage;
4845 
4846     if (externalImageCreateInfo == nullptr)
4847     {
4848         imageCreateInfoPNext =
4849             DeriveCreateInfoPNext(context, actualFormatID, nullptr, &imageFormatListInfoStorage,
4850                                   &imageListFormatsStorage, &mCreateFlags);
4851     }
4852     else
4853     {
4854         // Derive the tiling for external images.
4855         deriveExternalImageTiling(externalImageCreateInfo);
4856     }
4857 
4858     mYcbcrConversionDesc.reset();
4859 
4860     const angle::Format &actualFormat = angle::Format::Get(actualFormatID);
4861     VkFormat actualVkFormat           = GetVkFormatFromFormatID(actualFormatID);
4862 
4863     if (actualFormat.isYUV)
4864     {
4865         // The Vulkan spec states: If sampler is used and the VkFormat of the image is a
4866         // multi-planar format, the image must have been created with
4867         // VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT
4868         mCreateFlags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
4869 
4870         // The Vulkan spec states: The potential format features of the sampler YCBCR conversion
4871         // must support VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT or
4872         // VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT
4873         constexpr VkFormatFeatureFlags kChromaSubSampleFeatureBits =
4874             VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT |
4875             VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT;
4876 
4877         VkFormatFeatureFlags supportedChromaSubSampleFeatureBits =
4878             rendererVk->getImageFormatFeatureBits(mActualFormatID, kChromaSubSampleFeatureBits);
4879 
4880         VkChromaLocation supportedLocation = ((supportedChromaSubSampleFeatureBits &
4881                                                VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT) != 0)
4882                                                  ? VK_CHROMA_LOCATION_COSITED_EVEN
4883                                                  : VK_CHROMA_LOCATION_MIDPOINT;
4884         VkSamplerYcbcrModelConversion conversionModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601;
4885         VkSamplerYcbcrRange colorRange                = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW;
4886         VkFilter chromaFilter                         = VK_FILTER_NEAREST;
4887         VkComponentMapping components                 = {
4888             VK_COMPONENT_SWIZZLE_IDENTITY,
4889             VK_COMPONENT_SWIZZLE_IDENTITY,
4890             VK_COMPONENT_SWIZZLE_IDENTITY,
4891             VK_COMPONENT_SWIZZLE_IDENTITY,
4892         };
4893 
4894         // Create the VkSamplerYcbcrConversion to associate with image views and samplers
4895         // Update the SamplerYcbcrConversionCache key
4896         mYcbcrConversionDesc.update(rendererVk, 0, conversionModel, colorRange, supportedLocation,
4897                                     supportedLocation, chromaFilter, components, intendedFormatID);
4898     }
4899 
4900     if (hasProtectedContent)
4901     {
4902         mCreateFlags |= VK_IMAGE_CREATE_PROTECTED_BIT;
4903     }
4904 
4905     VkImageCreateInfo imageInfo     = {};
4906     imageInfo.sType                 = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
4907     imageInfo.pNext                 = imageCreateInfoPNext;
4908     imageInfo.flags                 = mCreateFlags;
4909     imageInfo.imageType             = mImageType;
4910     imageInfo.format                = actualVkFormat;
4911     imageInfo.extent                = mExtents;
4912     imageInfo.mipLevels             = mLevelCount;
4913     imageInfo.arrayLayers           = mLayerCount;
4914     imageInfo.samples               = gl_vk::GetSamples(mSamples);
4915     imageInfo.tiling                = mTilingMode;
4916     imageInfo.usage                 = mUsage;
4917     imageInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
4918     imageInfo.queueFamilyIndexCount = 0;
4919     imageInfo.pQueueFamilyIndices   = nullptr;
4920     imageInfo.initialLayout         = ConvertImageLayoutToVkImageLayout(initialLayout);
4921 
4922     mCurrentLayout = initialLayout;
4923 
4924     ANGLE_VK_TRY(context, mImage.init(context->getDevice(), imageInfo));
4925 
4926     mVkImageCreateInfo               = imageInfo;
4927     mVkImageCreateInfo.pNext         = nullptr;
4928     mVkImageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
4929 
4930     stageClearIfEmulatedFormat(isRobustResourceInitEnabled, externalImageCreateInfo != nullptr);
4931 
4932     // Consider the contents defined for any image that has the PREINITIALIZED layout, or is
4933     // imported from external.
4934     if (initialLayout != ImageLayout::Undefined || externalImageCreateInfo != nullptr)
4935     {
4936         setEntireContentDefined();
4937     }
4938 
4939     return angle::Result::Continue;
4940 }
4941 
DeriveCreateInfoPNext(Context * context,angle::FormatID actualFormatID,const void * pNext,VkImageFormatListCreateInfoKHR * imageFormatListInfoStorage,std::array<VkFormat,kImageListFormatCount> * imageListFormatsStorage,VkImageCreateFlags * createFlagsOut)4942 const void *ImageHelper::DeriveCreateInfoPNext(
4943     Context *context,
4944     angle::FormatID actualFormatID,
4945     const void *pNext,
4946     VkImageFormatListCreateInfoKHR *imageFormatListInfoStorage,
4947     std::array<VkFormat, kImageListFormatCount> *imageListFormatsStorage,
4948     VkImageCreateFlags *createFlagsOut)
4949 {
4950     // With the introduction of sRGB related GLES extensions any sample/render target could be
4951     // respecified causing it to be interpreted in a different colorspace.  Create the VkImage
4952     // accordingly.
4953     RendererVk *rendererVk            = context->getRenderer();
4954     const angle::Format &actualFormat = angle::Format::Get(actualFormatID);
4955     angle::FormatID additionalFormat =
4956         actualFormat.isSRGB ? ConvertToLinear(actualFormatID) : ConvertToSRGB(actualFormatID);
4957     (*imageListFormatsStorage)[0] = vk::GetVkFormatFromFormatID(actualFormatID);
4958     (*imageListFormatsStorage)[1] = vk::GetVkFormatFromFormatID(additionalFormat);
4959 
4960     if (rendererVk->getFeatures().supportsImageFormatList.enabled &&
4961         rendererVk->haveSameFormatFeatureBits(actualFormatID, additionalFormat))
4962     {
4963         // Add VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT to VkImage create flag
4964         *createFlagsOut |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
4965 
4966         // There is just 1 additional format we might use to create a VkImageView for this
4967         // VkImage
4968         imageFormatListInfoStorage->sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR;
4969         imageFormatListInfoStorage->pNext = pNext;
4970         imageFormatListInfoStorage->viewFormatCount = kImageListFormatCount;
4971         imageFormatListInfoStorage->pViewFormats    = imageListFormatsStorage->data();
4972 
4973         pNext = imageFormatListInfoStorage;
4974     }
4975 
4976     return pNext;
4977 }
4978 
deriveExternalImageTiling(const void * createInfoChain)4979 void ImageHelper::deriveExternalImageTiling(const void *createInfoChain)
4980 {
4981     const VkBaseInStructure *chain = reinterpret_cast<const VkBaseInStructure *>(createInfoChain);
4982     while (chain != nullptr)
4983     {
4984         if (chain->sType == VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT ||
4985             chain->sType == VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT)
4986         {
4987             mTilingMode = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
4988             return;
4989         }
4990 
4991         chain = reinterpret_cast<const VkBaseInStructure *>(chain->pNext);
4992     }
4993 }
4994 
releaseImage(RendererVk * renderer)4995 void ImageHelper::releaseImage(RendererVk *renderer)
4996 {
4997     CollectGarbage(&mImageAndViewGarbage, &mImage, &mDeviceMemory);
4998     // Notify us if the application pattern causes the views to keep getting reallocated and create
4999     // infinite garbage
5000     ASSERT(mImageAndViewGarbage.size() <= 1000);
5001     releaseImageAndViewGarbage(renderer);
5002     setEntireContentUndefined();
5003 }
5004 
releaseImageFromShareContexts(RendererVk * renderer,ContextVk * contextVk)5005 void ImageHelper::releaseImageFromShareContexts(RendererVk *renderer, ContextVk *contextVk)
5006 {
5007     if (contextVk && mImageSerial.valid())
5008     {
5009         const ContextVkSet &shareContextSet = contextVk->getShareGroupVk()->getContexts();
5010         for (ContextVk *ctx : shareContextSet)
5011         {
5012             ctx->finalizeImageLayout(this);
5013         }
5014     }
5015 
5016     releaseImage(renderer);
5017 }
5018 
collectViewGarbage(RendererVk * renderer,vk::ImageViewHelper * imageView)5019 void ImageHelper::collectViewGarbage(RendererVk *renderer, vk::ImageViewHelper *imageView)
5020 {
5021     imageView->release(renderer, mImageAndViewGarbage);
5022     // If we do not have any ImageHelper::mUse retained in ResourceUseList, make a cloned copy of
5023     // ImageHelper::mUse and use it to free any garbage in mImageAndViewGarbage immediately.
5024     if (!mUse.usedInRecordedCommands() && !mImageAndViewGarbage.empty())
5025     {
5026         // clone ImageHelper::mUse
5027         rx::vk::SharedResourceUse clonedmUse;
5028         clonedmUse.init();
5029         clonedmUse.updateSerialOneOff(mUse.getSerial());
5030         renderer->collectGarbage(std::move(clonedmUse), std::move(mImageAndViewGarbage));
5031     }
5032     ASSERT(mImageAndViewGarbage.size() <= 1000);
5033 }
5034 
releaseStagedUpdates(RendererVk * renderer)5035 void ImageHelper::releaseStagedUpdates(RendererVk *renderer)
5036 {
5037     ASSERT(validateSubresourceUpdateRefCountsConsistent());
5038 
5039     // Remove updates that never made it to the texture.
5040     for (std::vector<SubresourceUpdate> &levelUpdates : mSubresourceUpdates)
5041     {
5042         for (SubresourceUpdate &update : levelUpdates)
5043         {
5044             update.release(renderer);
5045         }
5046     }
5047 
5048     ASSERT(validateSubresourceUpdateRefCountsConsistent());
5049 
5050     mSubresourceUpdates.clear();
5051     mCurrentSingleClearValue.reset();
5052 }
5053 
resetImageWeakReference()5054 void ImageHelper::resetImageWeakReference()
5055 {
5056     mImage.reset();
5057     mImageSerial        = kInvalidImageSerial;
5058     mRotatedAspectRatio = false;
5059 }
5060 
releaseImageAndViewGarbage(RendererVk * renderer)5061 void ImageHelper::releaseImageAndViewGarbage(RendererVk *renderer)
5062 {
5063     if (!mImageAndViewGarbage.empty())
5064     {
5065         renderer->collectGarbage(std::move(mUse), std::move(mImageAndViewGarbage));
5066     }
5067     else
5068     {
5069         mUse.release();
5070     }
5071     mUse.init();
5072     mImageSerial = kInvalidImageSerial;
5073 }
5074 
initializeNonZeroMemory(Context * context,bool hasProtectedContent,VkDeviceSize size)5075 angle::Result ImageHelper::initializeNonZeroMemory(Context *context,
5076                                                    bool hasProtectedContent,
5077                                                    VkDeviceSize size)
5078 {
5079     const angle::Format &angleFormat = getActualFormat();
5080     bool isCompressedFormat          = angleFormat.isBlock;
5081 
5082     if (angleFormat.isYUV)
5083     {
5084         // VUID-vkCmdClearColorImage-image-01545
5085         // vkCmdClearColorImage(): format must not be one of the formats requiring sampler YCBCR
5086         // conversion for VK_IMAGE_ASPECT_COLOR_BIT image views
5087         return angle::Result::Continue;
5088     }
5089 
5090     RendererVk *renderer = context->getRenderer();
5091 
5092     PrimaryCommandBuffer commandBuffer;
5093     ANGLE_TRY(renderer->getCommandBufferOneOff(context, hasProtectedContent, &commandBuffer));
5094 
5095     // Queue a DMA copy.
5096     barrierImpl(context, getAspectFlags(), ImageLayout::TransferDst, mCurrentQueueFamilyIndex,
5097                 &commandBuffer);
5098 
5099     StagingBuffer stagingBuffer;
5100 
5101     if (isCompressedFormat)
5102     {
5103         // If format is compressed, set its contents through buffer copies.
5104 
5105         // The staging buffer memory is non-zero-initialized in 'init'.
5106         ANGLE_TRY(stagingBuffer.init(context, size, StagingUsage::Write));
5107 
5108         for (LevelIndex level(0); level < LevelIndex(mLevelCount); ++level)
5109         {
5110             VkBufferImageCopy copyRegion = {};
5111 
5112             gl_vk::GetExtent(getLevelExtents(level), &copyRegion.imageExtent);
5113             copyRegion.imageSubresource.aspectMask = getAspectFlags();
5114             copyRegion.imageSubresource.layerCount = mLayerCount;
5115 
5116             // If image has depth and stencil, copy to each individually per Vulkan spec.
5117             bool hasBothDepthAndStencil = isCombinedDepthStencilFormat();
5118             if (hasBothDepthAndStencil)
5119             {
5120                 copyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
5121             }
5122 
5123             commandBuffer.copyBufferToImage(stagingBuffer.getBuffer().getHandle(), mImage,
5124                                             VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copyRegion);
5125 
5126             if (hasBothDepthAndStencil)
5127             {
5128                 copyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
5129 
5130                 commandBuffer.copyBufferToImage(stagingBuffer.getBuffer().getHandle(), mImage,
5131                                                 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1,
5132                                                 &copyRegion);
5133             }
5134         }
5135     }
5136     else
5137     {
5138         // Otherwise issue clear commands.
5139         VkImageSubresourceRange subresource = {};
5140         subresource.aspectMask              = getAspectFlags();
5141         subresource.baseMipLevel            = 0;
5142         subresource.levelCount              = mLevelCount;
5143         subresource.baseArrayLayer          = 0;
5144         subresource.layerCount              = mLayerCount;
5145 
5146         // Arbitrary value to initialize the memory with.  Note: the given uint value, reinterpreted
5147         // as float is about 0.7.
5148         constexpr uint32_t kInitValue   = 0x3F345678;
5149         constexpr float kInitValueFloat = 0.12345f;
5150 
5151         if ((subresource.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != 0)
5152         {
5153             VkClearColorValue clearValue;
5154             clearValue.uint32[0] = kInitValue;
5155             clearValue.uint32[1] = kInitValue;
5156             clearValue.uint32[2] = kInitValue;
5157             clearValue.uint32[3] = kInitValue;
5158 
5159             commandBuffer.clearColorImage(mImage, getCurrentLayout(), clearValue, 1, &subresource);
5160         }
5161         else
5162         {
5163             VkClearDepthStencilValue clearValue;
5164             clearValue.depth   = kInitValueFloat;
5165             clearValue.stencil = kInitValue;
5166 
5167             commandBuffer.clearDepthStencilImage(mImage, getCurrentLayout(), clearValue, 1,
5168                                                  &subresource);
5169         }
5170     }
5171 
5172     ANGLE_VK_TRY(context, commandBuffer.end());
5173 
5174     Serial serial;
5175     ANGLE_TRY(renderer->queueSubmitOneOff(context, std::move(commandBuffer), hasProtectedContent,
5176                                           egl::ContextPriority::Medium, nullptr, 0, nullptr,
5177                                           vk::SubmitPolicy::AllowDeferred, &serial));
5178 
5179     if (isCompressedFormat)
5180     {
5181         stagingBuffer.collectGarbage(renderer, serial);
5182     }
5183     mUse.updateSerialOneOff(serial);
5184 
5185     return angle::Result::Continue;
5186 }
5187 
initMemory(Context * context,bool hasProtectedContent,const MemoryProperties & memoryProperties,VkMemoryPropertyFlags flags)5188 angle::Result ImageHelper::initMemory(Context *context,
5189                                       bool hasProtectedContent,
5190                                       const MemoryProperties &memoryProperties,
5191                                       VkMemoryPropertyFlags flags)
5192 {
5193     // TODO(jmadill): Memory sub-allocation. http://anglebug.com/2162
5194     VkDeviceSize size;
5195     if (hasProtectedContent)
5196     {
5197         flags |= VK_MEMORY_PROPERTY_PROTECTED_BIT;
5198     }
5199     ANGLE_TRY(AllocateImageMemory(context, flags, &flags, nullptr, &mImage, &mDeviceMemory, &size));
5200     mCurrentQueueFamilyIndex = context->getRenderer()->getQueueFamilyIndex();
5201 
5202     RendererVk *renderer = context->getRenderer();
5203     if (renderer->getFeatures().allocateNonZeroMemory.enabled)
5204     {
5205         // Can't map the memory. Use a staging resource.
5206         if ((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
5207         {
5208             ANGLE_TRY(initializeNonZeroMemory(context, hasProtectedContent, size));
5209         }
5210     }
5211 
5212     return angle::Result::Continue;
5213 }
5214 
initExternalMemory(Context * context,const MemoryProperties & memoryProperties,const VkMemoryRequirements & memoryRequirements,uint32_t extraAllocationInfoCount,const void ** extraAllocationInfo,uint32_t currentQueueFamilyIndex,VkMemoryPropertyFlags flags)5215 angle::Result ImageHelper::initExternalMemory(Context *context,
5216                                               const MemoryProperties &memoryProperties,
5217                                               const VkMemoryRequirements &memoryRequirements,
5218                                               uint32_t extraAllocationInfoCount,
5219                                               const void **extraAllocationInfo,
5220                                               uint32_t currentQueueFamilyIndex,
5221                                               VkMemoryPropertyFlags flags)
5222 {
5223     // Vulkan allows up to 4 memory planes.
5224     constexpr size_t kMaxMemoryPlanes                                     = 4;
5225     constexpr VkImageAspectFlagBits kMemoryPlaneAspects[kMaxMemoryPlanes] = {
5226         VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT,
5227         VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT,
5228         VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT,
5229         VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT,
5230     };
5231     ASSERT(extraAllocationInfoCount <= kMaxMemoryPlanes);
5232 
5233     VkBindImagePlaneMemoryInfoKHR bindImagePlaneMemoryInfo = {};
5234     bindImagePlaneMemoryInfo.sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO;
5235 
5236     const VkBindImagePlaneMemoryInfoKHR *bindImagePlaneMemoryInfoPtr =
5237         extraAllocationInfoCount == 1 ? nullptr : &bindImagePlaneMemoryInfo;
5238 
5239     for (uint32_t memoryPlane = 0; memoryPlane < extraAllocationInfoCount; ++memoryPlane)
5240     {
5241         bindImagePlaneMemoryInfo.planeAspect = kMemoryPlaneAspects[memoryPlane];
5242 
5243         ANGLE_TRY(AllocateImageMemoryWithRequirements(
5244             context, flags, memoryRequirements, extraAllocationInfo[memoryPlane],
5245             bindImagePlaneMemoryInfoPtr, &mImage, &mDeviceMemory));
5246     }
5247     mCurrentQueueFamilyIndex = currentQueueFamilyIndex;
5248 
5249     return angle::Result::Continue;
5250 }
5251 
initImageView(Context * context,gl::TextureType textureType,VkImageAspectFlags aspectMask,const gl::SwizzleState & swizzleMap,ImageView * imageViewOut,LevelIndex baseMipLevelVk,uint32_t levelCount)5252 angle::Result ImageHelper::initImageView(Context *context,
5253                                          gl::TextureType textureType,
5254                                          VkImageAspectFlags aspectMask,
5255                                          const gl::SwizzleState &swizzleMap,
5256                                          ImageView *imageViewOut,
5257                                          LevelIndex baseMipLevelVk,
5258                                          uint32_t levelCount)
5259 {
5260     return initLayerImageView(context, textureType, aspectMask, swizzleMap, imageViewOut,
5261                               baseMipLevelVk, levelCount, 0, mLayerCount,
5262                               gl::SrgbWriteControlMode::Default);
5263 }
5264 
initLayerImageView(Context * context,gl::TextureType textureType,VkImageAspectFlags aspectMask,const gl::SwizzleState & swizzleMap,ImageView * imageViewOut,LevelIndex baseMipLevelVk,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount,gl::SrgbWriteControlMode mode) const5265 angle::Result ImageHelper::initLayerImageView(Context *context,
5266                                               gl::TextureType textureType,
5267                                               VkImageAspectFlags aspectMask,
5268                                               const gl::SwizzleState &swizzleMap,
5269                                               ImageView *imageViewOut,
5270                                               LevelIndex baseMipLevelVk,
5271                                               uint32_t levelCount,
5272                                               uint32_t baseArrayLayer,
5273                                               uint32_t layerCount,
5274                                               gl::SrgbWriteControlMode mode) const
5275 {
5276     angle::FormatID actualFormat = mActualFormatID;
5277 
5278     // If we are initializing an imageview for use with EXT_srgb_write_control, we need to override
5279     // the format to its linear counterpart. Formats that cannot be reinterpreted are exempt from
5280     // this requirement.
5281     if (mode == gl::SrgbWriteControlMode::Linear)
5282     {
5283         angle::FormatID linearFormat = ConvertToLinear(actualFormat);
5284         if (linearFormat != angle::FormatID::NONE)
5285         {
5286             actualFormat = linearFormat;
5287         }
5288     }
5289 
5290     return initLayerImageViewImpl(context, textureType, aspectMask, swizzleMap, imageViewOut,
5291                                   baseMipLevelVk, levelCount, baseArrayLayer, layerCount,
5292                                   GetVkFormatFromFormatID(actualFormat), nullptr, nullptr);
5293 }
5294 
initLayerImageViewWithFormat(Context * context,gl::TextureType textureType,VkFormat imageFormat,VkImageAspectFlags aspectMask,const gl::SwizzleState & swizzleMap,ImageView * imageViewOut,LevelIndex baseMipLevelVk,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount,const gl::SamplerState & samplerState) const5295 angle::Result ImageHelper::initLayerImageViewWithFormat(Context *context,
5296                                                         gl::TextureType textureType,
5297                                                         VkFormat imageFormat,
5298                                                         VkImageAspectFlags aspectMask,
5299                                                         const gl::SwizzleState &swizzleMap,
5300                                                         ImageView *imageViewOut,
5301                                                         LevelIndex baseMipLevelVk,
5302                                                         uint32_t levelCount,
5303                                                         uint32_t baseArrayLayer,
5304                                                         uint32_t layerCount,
5305                                                         const gl::SamplerState &samplerState) const
5306 {
5307     return initLayerImageViewImpl(context, textureType, aspectMask, swizzleMap, imageViewOut,
5308                                   baseMipLevelVk, levelCount, baseArrayLayer, layerCount,
5309                                   imageFormat, nullptr, &samplerState);
5310 }
5311 
initLayerImageViewImpl(Context * context,gl::TextureType textureType,VkImageAspectFlags aspectMask,const gl::SwizzleState & swizzleMap,ImageView * imageViewOut,LevelIndex baseMipLevelVk,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount,VkFormat imageFormat,const VkImageViewUsageCreateInfo * imageViewUsageCreateInfo,const gl::SamplerState * samplerState) const5312 angle::Result ImageHelper::initLayerImageViewImpl(
5313     Context *context,
5314     gl::TextureType textureType,
5315     VkImageAspectFlags aspectMask,
5316     const gl::SwizzleState &swizzleMap,
5317     ImageView *imageViewOut,
5318     LevelIndex baseMipLevelVk,
5319     uint32_t levelCount,
5320     uint32_t baseArrayLayer,
5321     uint32_t layerCount,
5322     VkFormat imageFormat,
5323     const VkImageViewUsageCreateInfo *imageViewUsageCreateInfo,
5324     const gl::SamplerState *samplerState) const
5325 {
5326     VkImageViewCreateInfo viewInfo = {};
5327     viewInfo.sType                 = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
5328     viewInfo.flags                 = 0;
5329     viewInfo.image                 = mImage.getHandle();
5330     viewInfo.viewType              = gl_vk::GetImageViewType(textureType);
5331     viewInfo.format                = imageFormat;
5332 
5333     if (swizzleMap.swizzleRequired() && !mYcbcrConversionDesc.valid())
5334     {
5335         viewInfo.components.r = gl_vk::GetSwizzle(swizzleMap.swizzleRed);
5336         viewInfo.components.g = gl_vk::GetSwizzle(swizzleMap.swizzleGreen);
5337         viewInfo.components.b = gl_vk::GetSwizzle(swizzleMap.swizzleBlue);
5338         viewInfo.components.a = gl_vk::GetSwizzle(swizzleMap.swizzleAlpha);
5339     }
5340     else
5341     {
5342         viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
5343         viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
5344         viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
5345         viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
5346     }
5347     viewInfo.subresourceRange.aspectMask     = aspectMask;
5348     viewInfo.subresourceRange.baseMipLevel   = baseMipLevelVk.get();
5349     viewInfo.subresourceRange.levelCount     = levelCount;
5350     viewInfo.subresourceRange.baseArrayLayer = baseArrayLayer;
5351     viewInfo.subresourceRange.layerCount     = layerCount;
5352 
5353     viewInfo.pNext = imageViewUsageCreateInfo;
5354 
5355     VkSamplerYcbcrConversionInfo yuvConversionInfo = {};
5356     if (mYcbcrConversionDesc.valid())
5357     {
5358         // VUID-VkSamplerCreateInfo-minFilter VkCreateSampler:
5359         // VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT
5360         // specifies that the format can have different chroma, min, and mag filters. However,
5361         // VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT is
5362         // not supported for VkSamplerYcbcrConversionCreateInfo.format = VK_FORMAT_UNDEFINED so
5363         // chromaFilter needs to be equal to minFilter/magFilter.
5364         if (samplerState && mYcbcrConversionDesc.mIsExternalFormat)
5365         {
5366             ASSERT(samplerState->getMinFilter() == samplerState->getMagFilter());
5367             const_cast<YcbcrConversionDesc &>(mYcbcrConversionDesc).mChromaFilter =
5368                 gl_vk::GetFilter(samplerState->getMinFilter());
5369         }
5370 
5371         ASSERT((context->getRenderer()->getFeatures().supportsYUVSamplerConversion.enabled));
5372         yuvConversionInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO;
5373         yuvConversionInfo.pNext = nullptr;
5374         ANGLE_TRY(context->getRenderer()->getYuvConversionCache().getSamplerYcbcrConversion(
5375             context, mYcbcrConversionDesc, &yuvConversionInfo.conversion));
5376         AddToPNextChain(&viewInfo, &yuvConversionInfo);
5377 
5378         // VUID-VkImageViewCreateInfo-image-02399
5379         // If image has an external format, format must be VK_FORMAT_UNDEFINED
5380         if (mYcbcrConversionDesc.mIsExternalFormat)
5381         {
5382             viewInfo.format = VK_FORMAT_UNDEFINED;
5383         }
5384     }
5385     ANGLE_VK_TRY(context, imageViewOut->init(context->getDevice(), viewInfo));
5386     return angle::Result::Continue;
5387 }
5388 
initReinterpretedLayerImageView(Context * context,gl::TextureType textureType,VkImageAspectFlags aspectMask,const gl::SwizzleState & swizzleMap,ImageView * imageViewOut,LevelIndex baseMipLevelVk,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount,VkImageUsageFlags imageUsageFlags,angle::FormatID imageViewFormat) const5389 angle::Result ImageHelper::initReinterpretedLayerImageView(Context *context,
5390                                                            gl::TextureType textureType,
5391                                                            VkImageAspectFlags aspectMask,
5392                                                            const gl::SwizzleState &swizzleMap,
5393                                                            ImageView *imageViewOut,
5394                                                            LevelIndex baseMipLevelVk,
5395                                                            uint32_t levelCount,
5396                                                            uint32_t baseArrayLayer,
5397                                                            uint32_t layerCount,
5398                                                            VkImageUsageFlags imageUsageFlags,
5399                                                            angle::FormatID imageViewFormat) const
5400 {
5401     VkImageViewUsageCreateInfo imageViewUsageCreateInfo = {};
5402     imageViewUsageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO;
5403     imageViewUsageCreateInfo.usage =
5404         imageUsageFlags & GetMaximalImageUsageFlags(context->getRenderer(), imageViewFormat);
5405 
5406     return initLayerImageViewImpl(context, textureType, aspectMask, swizzleMap, imageViewOut,
5407                                   baseMipLevelVk, levelCount, baseArrayLayer, layerCount,
5408                                   vk::GetVkFormatFromFormatID(imageViewFormat),
5409                                   &imageViewUsageCreateInfo, nullptr);
5410 }
5411 
destroy(RendererVk * renderer)5412 void ImageHelper::destroy(RendererVk *renderer)
5413 {
5414     // destroy any pending garbage objects (most likely from ImageViewHelper) at this point
5415     for (GarbageObject &object : mImageAndViewGarbage)
5416     {
5417         object.destroy(renderer);
5418     }
5419 
5420     VkDevice device = renderer->getDevice();
5421 
5422     mImage.destroy(device);
5423     mDeviceMemory.destroy(device);
5424     mCurrentLayout = ImageLayout::Undefined;
5425     mImageType     = VK_IMAGE_TYPE_2D;
5426     mLayerCount    = 0;
5427     mLevelCount    = 0;
5428 
5429     setEntireContentUndefined();
5430 }
5431 
init2DWeakReference(Context * context,VkImage handle,const gl::Extents & glExtents,bool rotatedAspectRatio,angle::FormatID intendedFormatID,angle::FormatID actualFormatID,GLint samples,bool isRobustResourceInitEnabled)5432 void ImageHelper::init2DWeakReference(Context *context,
5433                                       VkImage handle,
5434                                       const gl::Extents &glExtents,
5435                                       bool rotatedAspectRatio,
5436                                       angle::FormatID intendedFormatID,
5437                                       angle::FormatID actualFormatID,
5438                                       GLint samples,
5439                                       bool isRobustResourceInitEnabled)
5440 {
5441     ASSERT(!valid());
5442     ASSERT(!IsAnySubresourceContentDefined(mContentDefined));
5443     ASSERT(!IsAnySubresourceContentDefined(mStencilContentDefined));
5444 
5445     gl_vk::GetExtent(glExtents, &mExtents);
5446     mRotatedAspectRatio = rotatedAspectRatio;
5447     mIntendedFormatID   = intendedFormatID;
5448     mActualFormatID     = actualFormatID;
5449     mSamples            = std::max(samples, 1);
5450     mImageSerial        = context->getRenderer()->getResourceSerialFactory().generateImageSerial();
5451     mCurrentQueueFamilyIndex = context->getRenderer()->getQueueFamilyIndex();
5452     mCurrentLayout           = ImageLayout::Undefined;
5453     mLayerCount              = 1;
5454     mLevelCount              = 1;
5455 
5456     mImage.setHandle(handle);
5457 
5458     stageClearIfEmulatedFormat(isRobustResourceInitEnabled, false);
5459 }
5460 
init2DStaging(Context * context,bool hasProtectedContent,const MemoryProperties & memoryProperties,const gl::Extents & glExtents,angle::FormatID intendedFormatID,angle::FormatID actualFormatID,VkImageUsageFlags usage,uint32_t layerCount)5461 angle::Result ImageHelper::init2DStaging(Context *context,
5462                                          bool hasProtectedContent,
5463                                          const MemoryProperties &memoryProperties,
5464                                          const gl::Extents &glExtents,
5465                                          angle::FormatID intendedFormatID,
5466                                          angle::FormatID actualFormatID,
5467                                          VkImageUsageFlags usage,
5468                                          uint32_t layerCount)
5469 {
5470     gl_vk::GetExtent(glExtents, &mExtents);
5471 
5472     return initStaging(context, hasProtectedContent, memoryProperties, VK_IMAGE_TYPE_2D, mExtents,
5473                        intendedFormatID, actualFormatID, 1, usage, 1, layerCount);
5474 }
5475 
initStaging(Context * context,bool hasProtectedContent,const MemoryProperties & memoryProperties,VkImageType imageType,const VkExtent3D & extents,angle::FormatID intendedFormatID,angle::FormatID actualFormatID,GLint samples,VkImageUsageFlags usage,uint32_t mipLevels,uint32_t layerCount)5476 angle::Result ImageHelper::initStaging(Context *context,
5477                                        bool hasProtectedContent,
5478                                        const MemoryProperties &memoryProperties,
5479                                        VkImageType imageType,
5480                                        const VkExtent3D &extents,
5481                                        angle::FormatID intendedFormatID,
5482                                        angle::FormatID actualFormatID,
5483                                        GLint samples,
5484                                        VkImageUsageFlags usage,
5485                                        uint32_t mipLevels,
5486                                        uint32_t layerCount)
5487 {
5488     ASSERT(!valid());
5489     ASSERT(!IsAnySubresourceContentDefined(mContentDefined));
5490     ASSERT(!IsAnySubresourceContentDefined(mStencilContentDefined));
5491 
5492     mImageType          = imageType;
5493     mExtents            = extents;
5494     mRotatedAspectRatio = false;
5495     mIntendedFormatID   = intendedFormatID;
5496     mActualFormatID     = actualFormatID;
5497     mSamples            = std::max(samples, 1);
5498     mImageSerial        = context->getRenderer()->getResourceSerialFactory().generateImageSerial();
5499     mLayerCount         = layerCount;
5500     mLevelCount         = mipLevels;
5501     mUsage              = usage;
5502 
5503     // Validate that mLayerCount is compatible with the image type
5504     ASSERT(imageType != VK_IMAGE_TYPE_3D || mLayerCount == 1);
5505     ASSERT(imageType != VK_IMAGE_TYPE_2D || mExtents.depth == 1);
5506 
5507     mCurrentLayout = ImageLayout::Undefined;
5508 
5509     VkImageCreateInfo imageInfo     = {};
5510     imageInfo.sType                 = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
5511     imageInfo.flags                 = hasProtectedContent ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
5512     imageInfo.imageType             = mImageType;
5513     imageInfo.format                = GetVkFormatFromFormatID(actualFormatID);
5514     imageInfo.extent                = mExtents;
5515     imageInfo.mipLevels             = mLevelCount;
5516     imageInfo.arrayLayers           = mLayerCount;
5517     imageInfo.samples               = gl_vk::GetSamples(mSamples);
5518     imageInfo.tiling                = VK_IMAGE_TILING_OPTIMAL;
5519     imageInfo.usage                 = usage;
5520     imageInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
5521     imageInfo.queueFamilyIndexCount = 0;
5522     imageInfo.pQueueFamilyIndices   = nullptr;
5523     imageInfo.initialLayout         = getCurrentLayout();
5524 
5525     ANGLE_VK_TRY(context, mImage.init(context->getDevice(), imageInfo));
5526 
5527     mVkImageCreateInfo               = imageInfo;
5528     mVkImageCreateInfo.pNext         = nullptr;
5529     mVkImageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
5530 
5531     // Allocate and bind device-local memory.
5532     VkMemoryPropertyFlags memoryPropertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
5533     if (hasProtectedContent)
5534     {
5535         memoryPropertyFlags |= VK_MEMORY_PROPERTY_PROTECTED_BIT;
5536     }
5537     ANGLE_TRY(initMemory(context, hasProtectedContent, memoryProperties, memoryPropertyFlags));
5538 
5539     return angle::Result::Continue;
5540 }
5541 
initImplicitMultisampledRenderToTexture(Context * context,bool hasProtectedContent,const MemoryProperties & memoryProperties,gl::TextureType textureType,GLint samples,const ImageHelper & resolveImage,bool isRobustResourceInitEnabled)5542 angle::Result ImageHelper::initImplicitMultisampledRenderToTexture(
5543     Context *context,
5544     bool hasProtectedContent,
5545     const MemoryProperties &memoryProperties,
5546     gl::TextureType textureType,
5547     GLint samples,
5548     const ImageHelper &resolveImage,
5549     bool isRobustResourceInitEnabled)
5550 {
5551     ASSERT(!valid());
5552     ASSERT(samples > 1);
5553     ASSERT(!IsAnySubresourceContentDefined(mContentDefined));
5554     ASSERT(!IsAnySubresourceContentDefined(mStencilContentDefined));
5555 
5556     // The image is used as either color or depth/stencil attachment.  Additionally, its memory is
5557     // lazily allocated as the contents are discarded at the end of the renderpass and with tiling
5558     // GPUs no actual backing memory is required.
5559     //
5560     // Note that the Vulkan image is created with or without VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT
5561     // based on whether the memory that will be used to create the image would have
5562     // VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT.  TRANSIENT is provided if there is any memory that
5563     // supports LAZILY_ALLOCATED.  However, based on actual image requirements, such a memory may
5564     // not be suitable for the image.  We don't support such a case, which will result in the
5565     // |initMemory| call below failing.
5566     const bool hasLazilyAllocatedMemory = memoryProperties.hasLazilyAllocatedMemory();
5567 
5568     const VkImageUsageFlags kMultisampledUsageFlags =
5569         (hasLazilyAllocatedMemory ? VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT : 0) |
5570         (resolveImage.getAspectFlags() == VK_IMAGE_ASPECT_COLOR_BIT
5571              ? VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
5572              : VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
5573     const VkImageCreateFlags kMultisampledCreateFlags =
5574         hasProtectedContent ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
5575 
5576     ANGLE_TRY(initExternal(context, textureType, resolveImage.getExtents(),
5577                            resolveImage.getIntendedFormatID(), resolveImage.getActualFormatID(),
5578                            samples, kMultisampledUsageFlags, kMultisampledCreateFlags,
5579                            ImageLayout::Undefined, nullptr, resolveImage.getFirstAllocatedLevel(),
5580                            resolveImage.getLevelCount(), resolveImage.getLayerCount(),
5581                            isRobustResourceInitEnabled, hasProtectedContent));
5582 
5583     // Remove the emulated format clear from the multisampled image if any.  There is one already
5584     // staged on the resolve image if needed.
5585     removeStagedUpdates(context, getFirstAllocatedLevel(), getLastAllocatedLevel());
5586 
5587     const VkMemoryPropertyFlags kMultisampledMemoryFlags =
5588         VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
5589         (hasLazilyAllocatedMemory ? VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT : 0) |
5590         (hasProtectedContent ? VK_MEMORY_PROPERTY_PROTECTED_BIT : 0);
5591 
5592     // If this ever fails, it can be retried without the LAZILY_ALLOCATED flag (which will probably
5593     // still fail), but ideally that means GL_EXT_multisampled_render_to_texture should not be
5594     // advertized on this platform in the first place.
5595     return initMemory(context, hasProtectedContent, memoryProperties, kMultisampledMemoryFlags);
5596 }
5597 
getAspectFlags() const5598 VkImageAspectFlags ImageHelper::getAspectFlags() const
5599 {
5600     return GetFormatAspectFlags(angle::Format::Get(mActualFormatID));
5601 }
5602 
isCombinedDepthStencilFormat() const5603 bool ImageHelper::isCombinedDepthStencilFormat() const
5604 {
5605     return (getAspectFlags() & kDepthStencilAspects) == kDepthStencilAspects;
5606 }
5607 
getCurrentLayout() const5608 VkImageLayout ImageHelper::getCurrentLayout() const
5609 {
5610     return ConvertImageLayoutToVkImageLayout(mCurrentLayout);
5611 }
5612 
getLevelExtents(LevelIndex levelVk) const5613 gl::Extents ImageHelper::getLevelExtents(LevelIndex levelVk) const
5614 {
5615     // Level 0 should be the size of the extents, after that every time you increase a level
5616     // you shrink the extents by half.
5617     uint32_t width  = std::max(mExtents.width >> levelVk.get(), 1u);
5618     uint32_t height = std::max(mExtents.height >> levelVk.get(), 1u);
5619     uint32_t depth  = std::max(mExtents.depth >> levelVk.get(), 1u);
5620 
5621     return gl::Extents(width, height, depth);
5622 }
5623 
getLevelExtents2D(LevelIndex levelVk) const5624 gl::Extents ImageHelper::getLevelExtents2D(LevelIndex levelVk) const
5625 {
5626     gl::Extents extents = getLevelExtents(levelVk);
5627     extents.depth       = 1;
5628     return extents;
5629 }
5630 
getRotatedExtents() const5631 const VkExtent3D ImageHelper::getRotatedExtents() const
5632 {
5633     VkExtent3D extents = mExtents;
5634     if (mRotatedAspectRatio)
5635     {
5636         std::swap(extents.width, extents.height);
5637     }
5638     return extents;
5639 }
5640 
getRotatedLevelExtents2D(LevelIndex levelVk) const5641 gl::Extents ImageHelper::getRotatedLevelExtents2D(LevelIndex levelVk) const
5642 {
5643     gl::Extents extents = getLevelExtents2D(levelVk);
5644     if (mRotatedAspectRatio)
5645     {
5646         std::swap(extents.width, extents.height);
5647     }
5648     return extents;
5649 }
5650 
isDepthOrStencil() const5651 bool ImageHelper::isDepthOrStencil() const
5652 {
5653     return getActualFormat().hasDepthOrStencilBits();
5654 }
5655 
setRenderPassUsageFlag(RenderPassUsage flag)5656 void ImageHelper::setRenderPassUsageFlag(RenderPassUsage flag)
5657 {
5658     mRenderPassUsageFlags.set(flag);
5659 }
5660 
clearRenderPassUsageFlag(RenderPassUsage flag)5661 void ImageHelper::clearRenderPassUsageFlag(RenderPassUsage flag)
5662 {
5663     mRenderPassUsageFlags.reset(flag);
5664 }
5665 
resetRenderPassUsageFlags()5666 void ImageHelper::resetRenderPassUsageFlags()
5667 {
5668     mRenderPassUsageFlags.reset();
5669 }
5670 
hasRenderPassUsageFlag(RenderPassUsage flag) const5671 bool ImageHelper::hasRenderPassUsageFlag(RenderPassUsage flag) const
5672 {
5673     return mRenderPassUsageFlags.test(flag);
5674 }
5675 
usedByCurrentRenderPassAsAttachmentAndSampler() const5676 bool ImageHelper::usedByCurrentRenderPassAsAttachmentAndSampler() const
5677 {
5678     return mRenderPassUsageFlags[RenderPassUsage::RenderTargetAttachment] &&
5679            mRenderPassUsageFlags[RenderPassUsage::TextureSampler];
5680 }
5681 
isReadBarrierNecessary(ImageLayout newLayout) const5682 bool ImageHelper::isReadBarrierNecessary(ImageLayout newLayout) const
5683 {
5684     // If transitioning to a different layout, we need always need a barrier.
5685     if (mCurrentLayout != newLayout)
5686     {
5687         return true;
5688     }
5689 
5690     // RAR (read-after-read) is not a hazard and doesn't require a barrier.
5691     //
5692     // RAW (read-after-write) hazards always require a memory barrier.  This can only happen if the
5693     // layout (same as new layout) is writable which in turn is only possible if the image is
5694     // simultaneously bound for shader write (i.e. the layout is GENERAL or SHARED_PRESENT).
5695     const ImageMemoryBarrierData &layoutData = kImageMemoryBarrierData[mCurrentLayout];
5696     return layoutData.type == ResourceAccess::Write;
5697 }
5698 
changeLayoutAndQueue(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,uint32_t newQueueFamilyIndex,OutsideRenderPassCommandBuffer * commandBuffer)5699 void ImageHelper::changeLayoutAndQueue(Context *context,
5700                                        VkImageAspectFlags aspectMask,
5701                                        ImageLayout newLayout,
5702                                        uint32_t newQueueFamilyIndex,
5703                                        OutsideRenderPassCommandBuffer *commandBuffer)
5704 {
5705     ASSERT(isQueueChangeNeccesary(newQueueFamilyIndex));
5706     barrierImpl(context, aspectMask, newLayout, newQueueFamilyIndex, commandBuffer);
5707 }
5708 
acquireFromExternal(ContextVk * contextVk,uint32_t externalQueueFamilyIndex,uint32_t rendererQueueFamilyIndex,ImageLayout currentLayout,OutsideRenderPassCommandBuffer * commandBuffer)5709 void ImageHelper::acquireFromExternal(ContextVk *contextVk,
5710                                       uint32_t externalQueueFamilyIndex,
5711                                       uint32_t rendererQueueFamilyIndex,
5712                                       ImageLayout currentLayout,
5713                                       OutsideRenderPassCommandBuffer *commandBuffer)
5714 {
5715     // The image must be newly allocated or have been released to the external
5716     // queue. If this is not the case, it's an application bug, so ASSERT might
5717     // eventually need to change to a warning.
5718     ASSERT(mCurrentLayout == ImageLayout::ExternalPreInitialized ||
5719            mCurrentQueueFamilyIndex == externalQueueFamilyIndex);
5720 
5721     mCurrentLayout           = currentLayout;
5722     mCurrentQueueFamilyIndex = externalQueueFamilyIndex;
5723 
5724     retain(&contextVk->getResourceUseList());
5725     changeLayoutAndQueue(contextVk, getAspectFlags(), mCurrentLayout, rendererQueueFamilyIndex,
5726                          commandBuffer);
5727 
5728     // It is unknown how the external has modified the image, so assume every subresource has
5729     // defined content.  That is unless the layout is Undefined.
5730     if (currentLayout == ImageLayout::Undefined)
5731     {
5732         setEntireContentUndefined();
5733     }
5734     else
5735     {
5736         setEntireContentDefined();
5737     }
5738 }
5739 
releaseToExternal(ContextVk * contextVk,uint32_t rendererQueueFamilyIndex,uint32_t externalQueueFamilyIndex,ImageLayout desiredLayout,OutsideRenderPassCommandBuffer * commandBuffer)5740 void ImageHelper::releaseToExternal(ContextVk *contextVk,
5741                                     uint32_t rendererQueueFamilyIndex,
5742                                     uint32_t externalQueueFamilyIndex,
5743                                     ImageLayout desiredLayout,
5744                                     OutsideRenderPassCommandBuffer *commandBuffer)
5745 {
5746     ASSERT(mCurrentQueueFamilyIndex == rendererQueueFamilyIndex);
5747 
5748     retain(&contextVk->getResourceUseList());
5749     changeLayoutAndQueue(contextVk, getAspectFlags(), desiredLayout, externalQueueFamilyIndex,
5750                          commandBuffer);
5751 }
5752 
isReleasedToExternal() const5753 bool ImageHelper::isReleasedToExternal() const
5754 {
5755 #if !defined(ANGLE_PLATFORM_MACOS) && !defined(ANGLE_PLATFORM_ANDROID)
5756     return IsExternalQueueFamily(mCurrentQueueFamilyIndex);
5757 #else
5758     // TODO(anglebug.com/4635): Implement external memory barriers on Mac/Android.
5759     return false;
5760 #endif
5761 }
5762 
toVkLevel(gl::LevelIndex levelIndexGL) const5763 LevelIndex ImageHelper::toVkLevel(gl::LevelIndex levelIndexGL) const
5764 {
5765     return gl_vk::GetLevelIndex(levelIndexGL, mFirstAllocatedLevel);
5766 }
5767 
toGLLevel(LevelIndex levelIndexVk) const5768 gl::LevelIndex ImageHelper::toGLLevel(LevelIndex levelIndexVk) const
5769 {
5770     return vk_gl::GetLevelIndex(levelIndexVk, mFirstAllocatedLevel);
5771 }
5772 
initImageMemoryBarrierStruct(VkImageAspectFlags aspectMask,ImageLayout newLayout,uint32_t newQueueFamilyIndex,VkImageMemoryBarrier * imageMemoryBarrier) const5773 ANGLE_INLINE void ImageHelper::initImageMemoryBarrierStruct(
5774     VkImageAspectFlags aspectMask,
5775     ImageLayout newLayout,
5776     uint32_t newQueueFamilyIndex,
5777     VkImageMemoryBarrier *imageMemoryBarrier) const
5778 {
5779     const ImageMemoryBarrierData &transitionFrom = kImageMemoryBarrierData[mCurrentLayout];
5780     const ImageMemoryBarrierData &transitionTo   = kImageMemoryBarrierData[newLayout];
5781 
5782     imageMemoryBarrier->sType               = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
5783     imageMemoryBarrier->srcAccessMask       = transitionFrom.srcAccessMask;
5784     imageMemoryBarrier->dstAccessMask       = transitionTo.dstAccessMask;
5785     imageMemoryBarrier->oldLayout           = transitionFrom.layout;
5786     imageMemoryBarrier->newLayout           = transitionTo.layout;
5787     imageMemoryBarrier->srcQueueFamilyIndex = mCurrentQueueFamilyIndex;
5788     imageMemoryBarrier->dstQueueFamilyIndex = newQueueFamilyIndex;
5789     imageMemoryBarrier->image               = mImage.getHandle();
5790 
5791     // Transition the whole resource.
5792     imageMemoryBarrier->subresourceRange.aspectMask     = aspectMask;
5793     imageMemoryBarrier->subresourceRange.baseMipLevel   = 0;
5794     imageMemoryBarrier->subresourceRange.levelCount     = mLevelCount;
5795     imageMemoryBarrier->subresourceRange.baseArrayLayer = 0;
5796     imageMemoryBarrier->subresourceRange.layerCount     = mLayerCount;
5797 }
5798 
5799 // Generalized to accept both "primary" and "secondary" command buffers.
5800 template <typename CommandBufferT>
barrierImpl(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,uint32_t newQueueFamilyIndex,CommandBufferT * commandBuffer)5801 void ImageHelper::barrierImpl(Context *context,
5802                               VkImageAspectFlags aspectMask,
5803                               ImageLayout newLayout,
5804                               uint32_t newQueueFamilyIndex,
5805                               CommandBufferT *commandBuffer)
5806 {
5807     if (mCurrentLayout == ImageLayout::SharedPresent)
5808     {
5809         const ImageMemoryBarrierData &transition = kImageMemoryBarrierData[mCurrentLayout];
5810 
5811         VkMemoryBarrier memoryBarrier = {};
5812         memoryBarrier.sType           = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
5813         memoryBarrier.srcAccessMask   = transition.srcAccessMask;
5814         memoryBarrier.dstAccessMask   = transition.dstAccessMask;
5815 
5816         commandBuffer->memoryBarrier(transition.srcStageMask, transition.dstStageMask,
5817                                      &memoryBarrier);
5818         return;
5819     }
5820 
5821     // Make sure we never transition out of SharedPresent
5822     ASSERT(mCurrentLayout != ImageLayout::SharedPresent || newLayout == ImageLayout::SharedPresent);
5823 
5824     const ImageMemoryBarrierData &transitionFrom = kImageMemoryBarrierData[mCurrentLayout];
5825     const ImageMemoryBarrierData &transitionTo   = kImageMemoryBarrierData[newLayout];
5826 
5827     VkImageMemoryBarrier imageMemoryBarrier = {};
5828     initImageMemoryBarrierStruct(aspectMask, newLayout, newQueueFamilyIndex, &imageMemoryBarrier);
5829 
5830     // There might be other shaderRead operations there other than the current layout.
5831     VkPipelineStageFlags srcStageMask = GetImageLayoutSrcStageMask(context, transitionFrom);
5832     if (mCurrentShaderReadStageMask)
5833     {
5834         srcStageMask |= mCurrentShaderReadStageMask;
5835         mCurrentShaderReadStageMask  = 0;
5836         mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
5837     }
5838     commandBuffer->imageBarrier(srcStageMask, GetImageLayoutDstStageMask(context, transitionTo),
5839                                 imageMemoryBarrier);
5840 
5841     mCurrentLayout           = newLayout;
5842     mCurrentQueueFamilyIndex = newQueueFamilyIndex;
5843 }
5844 
5845 template void ImageHelper::barrierImpl<priv::CommandBuffer>(Context *context,
5846                                                             VkImageAspectFlags aspectMask,
5847                                                             ImageLayout newLayout,
5848                                                             uint32_t newQueueFamilyIndex,
5849                                                             priv::CommandBuffer *commandBuffer);
5850 
updateLayoutAndBarrier(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,PipelineBarrier * barrier)5851 bool ImageHelper::updateLayoutAndBarrier(Context *context,
5852                                          VkImageAspectFlags aspectMask,
5853                                          ImageLayout newLayout,
5854                                          PipelineBarrier *barrier)
5855 {
5856     // Once you transition to ImageLayout::SharedPresent, you never transition out of it.
5857     if (mCurrentLayout == ImageLayout::SharedPresent)
5858     {
5859         newLayout = ImageLayout::SharedPresent;
5860     }
5861     bool barrierModified = false;
5862     if (newLayout == mCurrentLayout)
5863     {
5864         const ImageMemoryBarrierData &layoutData = kImageMemoryBarrierData[mCurrentLayout];
5865         // RAR is not a hazard and doesn't require a barrier, especially as the image layout hasn't
5866         // changed.  The following asserts that such a barrier is not attempted.
5867         ASSERT(layoutData.type == ResourceAccess::Write);
5868         // No layout change, only memory barrier is required
5869         barrier->mergeMemoryBarrier(GetImageLayoutSrcStageMask(context, layoutData),
5870                                     GetImageLayoutDstStageMask(context, layoutData),
5871                                     layoutData.srcAccessMask, layoutData.dstAccessMask);
5872         barrierModified = true;
5873     }
5874     else
5875     {
5876         const ImageMemoryBarrierData &transitionFrom = kImageMemoryBarrierData[mCurrentLayout];
5877         const ImageMemoryBarrierData &transitionTo   = kImageMemoryBarrierData[newLayout];
5878         VkPipelineStageFlags srcStageMask = GetImageLayoutSrcStageMask(context, transitionFrom);
5879         VkPipelineStageFlags dstStageMask = GetImageLayoutDstStageMask(context, transitionTo);
5880 
5881         if (IsShaderReadOnlyLayout(transitionTo) && IsShaderReadOnlyLayout(transitionFrom))
5882         {
5883             // If we are switching between different shader stage reads, then there is no actual
5884             // layout change or access type change. We only need a barrier if we are making a read
5885             // that is from a new stage. Also note that we barrier against previous non-shaderRead
5886             // layout. We do not barrier between one shaderRead and another shaderRead.
5887             bool isNewReadStage = (mCurrentShaderReadStageMask & dstStageMask) != dstStageMask;
5888             if (isNewReadStage)
5889             {
5890                 const ImageMemoryBarrierData &layoutData =
5891                     kImageMemoryBarrierData[mLastNonShaderReadOnlyLayout];
5892                 barrier->mergeMemoryBarrier(GetImageLayoutSrcStageMask(context, layoutData),
5893                                             dstStageMask, layoutData.srcAccessMask,
5894                                             transitionTo.dstAccessMask);
5895                 barrierModified = true;
5896                 // Accumulate new read stage.
5897                 mCurrentShaderReadStageMask |= dstStageMask;
5898             }
5899         }
5900         else
5901         {
5902             VkImageMemoryBarrier imageMemoryBarrier = {};
5903             initImageMemoryBarrierStruct(aspectMask, newLayout, mCurrentQueueFamilyIndex,
5904                                          &imageMemoryBarrier);
5905             // if we transition from shaderReadOnly, we must add in stashed shader stage masks since
5906             // there might be outstanding shader reads from stages other than current layout. We do
5907             // not insert barrier between one shaderRead to another shaderRead
5908             if (mCurrentShaderReadStageMask)
5909             {
5910                 srcStageMask |= mCurrentShaderReadStageMask;
5911                 mCurrentShaderReadStageMask  = 0;
5912                 mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
5913             }
5914             barrier->mergeImageBarrier(srcStageMask, dstStageMask, imageMemoryBarrier);
5915             barrierModified = true;
5916 
5917             // If we are transition into shaderRead layout, remember the last
5918             // non-shaderRead layout here.
5919             if (IsShaderReadOnlyLayout(transitionTo))
5920             {
5921                 ASSERT(!IsShaderReadOnlyLayout(transitionFrom));
5922                 mLastNonShaderReadOnlyLayout = mCurrentLayout;
5923                 mCurrentShaderReadStageMask  = dstStageMask;
5924             }
5925         }
5926         mCurrentLayout = newLayout;
5927     }
5928     return barrierModified;
5929 }
5930 
clearColor(const VkClearColorValue & color,LevelIndex baseMipLevelVk,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount,OutsideRenderPassCommandBuffer * commandBuffer)5931 void ImageHelper::clearColor(const VkClearColorValue &color,
5932                              LevelIndex baseMipLevelVk,
5933                              uint32_t levelCount,
5934                              uint32_t baseArrayLayer,
5935                              uint32_t layerCount,
5936                              OutsideRenderPassCommandBuffer *commandBuffer)
5937 {
5938     ASSERT(valid());
5939 
5940     ASSERT(mCurrentLayout == ImageLayout::TransferDst ||
5941            mCurrentLayout == ImageLayout::SharedPresent);
5942 
5943     VkImageSubresourceRange range = {};
5944     range.aspectMask              = VK_IMAGE_ASPECT_COLOR_BIT;
5945     range.baseMipLevel            = baseMipLevelVk.get();
5946     range.levelCount              = levelCount;
5947     range.baseArrayLayer          = baseArrayLayer;
5948     range.layerCount              = layerCount;
5949 
5950     if (mImageType == VK_IMAGE_TYPE_3D)
5951     {
5952         ASSERT(baseArrayLayer == 0);
5953         ASSERT(layerCount == 1 ||
5954                layerCount == static_cast<uint32_t>(getLevelExtents(baseMipLevelVk).depth));
5955         range.layerCount = 1;
5956     }
5957 
5958     commandBuffer->clearColorImage(mImage, getCurrentLayout(), color, 1, &range);
5959 }
5960 
clearDepthStencil(VkImageAspectFlags clearAspectFlags,const VkClearDepthStencilValue & depthStencil,LevelIndex baseMipLevelVk,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount,OutsideRenderPassCommandBuffer * commandBuffer)5961 void ImageHelper::clearDepthStencil(VkImageAspectFlags clearAspectFlags,
5962                                     const VkClearDepthStencilValue &depthStencil,
5963                                     LevelIndex baseMipLevelVk,
5964                                     uint32_t levelCount,
5965                                     uint32_t baseArrayLayer,
5966                                     uint32_t layerCount,
5967                                     OutsideRenderPassCommandBuffer *commandBuffer)
5968 {
5969     ASSERT(valid());
5970 
5971     ASSERT(mCurrentLayout == ImageLayout::TransferDst);
5972 
5973     VkImageSubresourceRange range = {};
5974     range.aspectMask              = clearAspectFlags;
5975     range.baseMipLevel            = baseMipLevelVk.get();
5976     range.levelCount              = levelCount;
5977     range.baseArrayLayer          = baseArrayLayer;
5978     range.layerCount              = layerCount;
5979 
5980     if (mImageType == VK_IMAGE_TYPE_3D)
5981     {
5982         ASSERT(baseArrayLayer == 0);
5983         ASSERT(layerCount == 1 ||
5984                layerCount == static_cast<uint32_t>(getLevelExtents(baseMipLevelVk).depth));
5985         range.layerCount = 1;
5986     }
5987 
5988     commandBuffer->clearDepthStencilImage(mImage, getCurrentLayout(), depthStencil, 1, &range);
5989 }
5990 
clear(VkImageAspectFlags aspectFlags,const VkClearValue & value,LevelIndex mipLevel,uint32_t baseArrayLayer,uint32_t layerCount,OutsideRenderPassCommandBuffer * commandBuffer)5991 void ImageHelper::clear(VkImageAspectFlags aspectFlags,
5992                         const VkClearValue &value,
5993                         LevelIndex mipLevel,
5994                         uint32_t baseArrayLayer,
5995                         uint32_t layerCount,
5996                         OutsideRenderPassCommandBuffer *commandBuffer)
5997 {
5998     const angle::Format &angleFormat = getActualFormat();
5999     bool isDepthStencil              = angleFormat.depthBits > 0 || angleFormat.stencilBits > 0;
6000 
6001     if (isDepthStencil)
6002     {
6003         clearDepthStencil(aspectFlags, value.depthStencil, mipLevel, 1, baseArrayLayer, layerCount,
6004                           commandBuffer);
6005     }
6006     else
6007     {
6008         ASSERT(!angleFormat.isBlock);
6009 
6010         clearColor(value.color, mipLevel, 1, baseArrayLayer, layerCount, commandBuffer);
6011     }
6012 }
6013 
clearEmulatedChannels(ContextVk * contextVk,VkColorComponentFlags colorMaskFlags,const VkClearValue & value,LevelIndex mipLevel,uint32_t baseArrayLayer,uint32_t layerCount)6014 angle::Result ImageHelper::clearEmulatedChannels(ContextVk *contextVk,
6015                                                  VkColorComponentFlags colorMaskFlags,
6016                                                  const VkClearValue &value,
6017                                                  LevelIndex mipLevel,
6018                                                  uint32_t baseArrayLayer,
6019                                                  uint32_t layerCount)
6020 {
6021     const gl::Extents levelExtents = getLevelExtents(mipLevel);
6022 
6023     if (levelExtents.depth > 1)
6024     {
6025         // Currently not implemented for 3D textures
6026         UNIMPLEMENTED();
6027         return angle::Result::Continue;
6028     }
6029 
6030     UtilsVk::ClearImageParameters params = {};
6031     params.clearArea                     = {0, 0, levelExtents.width, levelExtents.height};
6032     params.dstMip                        = mipLevel;
6033     params.colorMaskFlags                = colorMaskFlags;
6034     params.colorClearValue               = value.color;
6035 
6036     for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex)
6037     {
6038         params.dstLayer = baseArrayLayer + layerIndex;
6039 
6040         ANGLE_TRY(contextVk->getUtils().clearImage(contextVk, this, params));
6041     }
6042 
6043     return angle::Result::Continue;
6044 }
6045 
6046 // static
Copy(ImageHelper * srcImage,ImageHelper * dstImage,const gl::Offset & srcOffset,const gl::Offset & dstOffset,const gl::Extents & copySize,const VkImageSubresourceLayers & srcSubresource,const VkImageSubresourceLayers & dstSubresource,OutsideRenderPassCommandBuffer * commandBuffer)6047 void ImageHelper::Copy(ImageHelper *srcImage,
6048                        ImageHelper *dstImage,
6049                        const gl::Offset &srcOffset,
6050                        const gl::Offset &dstOffset,
6051                        const gl::Extents &copySize,
6052                        const VkImageSubresourceLayers &srcSubresource,
6053                        const VkImageSubresourceLayers &dstSubresource,
6054                        OutsideRenderPassCommandBuffer *commandBuffer)
6055 {
6056     ASSERT(commandBuffer->valid() && srcImage->valid() && dstImage->valid());
6057 
6058     ASSERT(srcImage->getCurrentLayout() == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
6059     ASSERT(dstImage->getCurrentLayout() == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
6060 
6061     VkImageCopy region    = {};
6062     region.srcSubresource = srcSubresource;
6063     region.srcOffset.x    = srcOffset.x;
6064     region.srcOffset.y    = srcOffset.y;
6065     region.srcOffset.z    = srcOffset.z;
6066     region.dstSubresource = dstSubresource;
6067     region.dstOffset.x    = dstOffset.x;
6068     region.dstOffset.y    = dstOffset.y;
6069     region.dstOffset.z    = dstOffset.z;
6070     region.extent.width   = copySize.width;
6071     region.extent.height  = copySize.height;
6072     region.extent.depth   = copySize.depth;
6073 
6074     commandBuffer->copyImage(srcImage->getImage(), srcImage->getCurrentLayout(),
6075                              dstImage->getImage(), dstImage->getCurrentLayout(), 1, &region);
6076 }
6077 
6078 // static
CopyImageSubData(const gl::Context * context,ImageHelper * srcImage,GLint srcLevel,GLint srcX,GLint srcY,GLint srcZ,ImageHelper * dstImage,GLint dstLevel,GLint dstX,GLint dstY,GLint dstZ,GLsizei srcWidth,GLsizei srcHeight,GLsizei srcDepth)6079 angle::Result ImageHelper::CopyImageSubData(const gl::Context *context,
6080                                             ImageHelper *srcImage,
6081                                             GLint srcLevel,
6082                                             GLint srcX,
6083                                             GLint srcY,
6084                                             GLint srcZ,
6085                                             ImageHelper *dstImage,
6086                                             GLint dstLevel,
6087                                             GLint dstX,
6088                                             GLint dstY,
6089                                             GLint dstZ,
6090                                             GLsizei srcWidth,
6091                                             GLsizei srcHeight,
6092                                             GLsizei srcDepth)
6093 {
6094     ContextVk *contextVk = GetImpl(context);
6095 
6096     VkImageTiling srcTilingMode  = srcImage->getTilingMode();
6097     VkImageTiling destTilingMode = dstImage->getTilingMode();
6098 
6099     const gl::LevelIndex srcLevelGL = gl::LevelIndex(srcLevel);
6100     const gl::LevelIndex dstLevelGL = gl::LevelIndex(dstLevel);
6101 
6102     if (CanCopyWithTransferForCopyImage(contextVk->getRenderer(), srcImage, srcTilingMode, dstImage,
6103                                         destTilingMode))
6104     {
6105         bool isSrc3D = srcImage->getType() == VK_IMAGE_TYPE_3D;
6106         bool isDst3D = dstImage->getType() == VK_IMAGE_TYPE_3D;
6107 
6108         srcImage->retain(&contextVk->getResourceUseList());
6109         dstImage->retain(&contextVk->getResourceUseList());
6110 
6111         VkImageCopy region = {};
6112 
6113         region.srcSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
6114         region.srcSubresource.mipLevel       = srcImage->toVkLevel(srcLevelGL).get();
6115         region.srcSubresource.baseArrayLayer = isSrc3D ? 0 : srcZ;
6116         region.srcSubresource.layerCount     = isSrc3D ? 1 : srcDepth;
6117 
6118         region.dstSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
6119         region.dstSubresource.mipLevel       = dstImage->toVkLevel(dstLevelGL).get();
6120         region.dstSubresource.baseArrayLayer = isDst3D ? 0 : dstZ;
6121         region.dstSubresource.layerCount     = isDst3D ? 1 : srcDepth;
6122 
6123         region.srcOffset.x   = srcX;
6124         region.srcOffset.y   = srcY;
6125         region.srcOffset.z   = isSrc3D ? srcZ : 0;
6126         region.dstOffset.x   = dstX;
6127         region.dstOffset.y   = dstY;
6128         region.dstOffset.z   = isDst3D ? dstZ : 0;
6129         region.extent.width  = srcWidth;
6130         region.extent.height = srcHeight;
6131         region.extent.depth  = (isSrc3D || isDst3D) ? srcDepth : 1;
6132 
6133         CommandBufferAccess access;
6134         access.onImageTransferRead(VK_IMAGE_ASPECT_COLOR_BIT, srcImage);
6135         access.onImageTransferWrite(dstLevelGL, 1, region.dstSubresource.baseArrayLayer,
6136                                     region.dstSubresource.layerCount, VK_IMAGE_ASPECT_COLOR_BIT,
6137                                     dstImage);
6138 
6139         OutsideRenderPassCommandBuffer *commandBuffer;
6140         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
6141 
6142         ASSERT(srcImage->valid() && dstImage->valid());
6143         ASSERT(srcImage->getCurrentLayout() == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
6144         ASSERT(dstImage->getCurrentLayout() == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
6145 
6146         commandBuffer->copyImage(srcImage->getImage(), srcImage->getCurrentLayout(),
6147                                  dstImage->getImage(), dstImage->getCurrentLayout(), 1, &region);
6148     }
6149     else if (!srcImage->getIntendedFormat().isBlock && !dstImage->getIntendedFormat().isBlock)
6150     {
6151         // The source and destination image formats may be using a fallback in the case of RGB
6152         // images.  A compute shader is used in such a case to perform the copy.
6153         UtilsVk &utilsVk = contextVk->getUtils();
6154 
6155         UtilsVk::CopyImageBitsParameters params;
6156         params.srcOffset[0]   = srcX;
6157         params.srcOffset[1]   = srcY;
6158         params.srcOffset[2]   = srcZ;
6159         params.srcLevel       = srcLevelGL;
6160         params.dstOffset[0]   = dstX;
6161         params.dstOffset[1]   = dstY;
6162         params.dstOffset[2]   = dstZ;
6163         params.dstLevel       = dstLevelGL;
6164         params.copyExtents[0] = srcWidth;
6165         params.copyExtents[1] = srcHeight;
6166         params.copyExtents[2] = srcDepth;
6167 
6168         ANGLE_TRY(utilsVk.copyImageBits(contextVk, dstImage, srcImage, params));
6169     }
6170     else
6171     {
6172         // No support for emulated compressed formats.
6173         UNIMPLEMENTED();
6174         ANGLE_VK_CHECK(contextVk, false, VK_ERROR_FEATURE_NOT_PRESENT);
6175     }
6176 
6177     return angle::Result::Continue;
6178 }
6179 
generateMipmapsWithBlit(ContextVk * contextVk,LevelIndex baseLevel,LevelIndex maxLevel)6180 angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk,
6181                                                    LevelIndex baseLevel,
6182                                                    LevelIndex maxLevel)
6183 {
6184     CommandBufferAccess access;
6185     gl::LevelIndex baseLevelGL = toGLLevel(baseLevel);
6186     access.onImageTransferWrite(baseLevelGL + 1, maxLevel.get(), 0, mLayerCount,
6187                                 VK_IMAGE_ASPECT_COLOR_BIT, this);
6188 
6189     OutsideRenderPassCommandBuffer *commandBuffer;
6190     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
6191 
6192     // We are able to use blitImage since the image format we are using supports it.
6193     int32_t mipWidth  = mExtents.width;
6194     int32_t mipHeight = mExtents.height;
6195     int32_t mipDepth  = mExtents.depth;
6196 
6197     // Manually manage the image memory barrier because it uses a lot more parameters than our
6198     // usual one.
6199     VkImageMemoryBarrier barrier            = {};
6200     barrier.sType                           = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
6201     barrier.image                           = mImage.getHandle();
6202     barrier.srcQueueFamilyIndex             = VK_QUEUE_FAMILY_IGNORED;
6203     barrier.dstQueueFamilyIndex             = VK_QUEUE_FAMILY_IGNORED;
6204     barrier.subresourceRange.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
6205     barrier.subresourceRange.baseArrayLayer = 0;
6206     barrier.subresourceRange.layerCount     = mLayerCount;
6207     barrier.subresourceRange.levelCount     = 1;
6208 
6209     const VkFilter filter =
6210         gl_vk::GetFilter(CalculateGenerateMipmapFilter(contextVk, getActualFormatID()));
6211 
6212     for (LevelIndex mipLevel(1); mipLevel <= LevelIndex(mLevelCount); ++mipLevel)
6213     {
6214         int32_t nextMipWidth  = std::max<int32_t>(1, mipWidth >> 1);
6215         int32_t nextMipHeight = std::max<int32_t>(1, mipHeight >> 1);
6216         int32_t nextMipDepth  = std::max<int32_t>(1, mipDepth >> 1);
6217 
6218         if (mipLevel > baseLevel && mipLevel <= maxLevel)
6219         {
6220             barrier.subresourceRange.baseMipLevel = mipLevel.get() - 1;
6221             barrier.oldLayout                     = getCurrentLayout();
6222             barrier.newLayout                     = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
6223             barrier.srcAccessMask                 = VK_ACCESS_TRANSFER_WRITE_BIT;
6224             barrier.dstAccessMask                 = VK_ACCESS_TRANSFER_READ_BIT;
6225 
6226             // We can do it for all layers at once.
6227             commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
6228                                         VK_PIPELINE_STAGE_TRANSFER_BIT, barrier);
6229             VkImageBlit blit                   = {};
6230             blit.srcOffsets[0]                 = {0, 0, 0};
6231             blit.srcOffsets[1]                 = {mipWidth, mipHeight, mipDepth};
6232             blit.srcSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
6233             blit.srcSubresource.mipLevel       = mipLevel.get() - 1;
6234             blit.srcSubresource.baseArrayLayer = 0;
6235             blit.srcSubresource.layerCount     = mLayerCount;
6236             blit.dstOffsets[0]                 = {0, 0, 0};
6237             blit.dstOffsets[1]                 = {nextMipWidth, nextMipHeight, nextMipDepth};
6238             blit.dstSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
6239             blit.dstSubresource.mipLevel       = mipLevel.get();
6240             blit.dstSubresource.baseArrayLayer = 0;
6241             blit.dstSubresource.layerCount     = mLayerCount;
6242 
6243             commandBuffer->blitImage(mImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, mImage,
6244                                      VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, filter);
6245         }
6246         mipWidth  = nextMipWidth;
6247         mipHeight = nextMipHeight;
6248         mipDepth  = nextMipDepth;
6249     }
6250 
6251     // Transition all mip level to the same layout so we can declare our whole image layout to one
6252     // ImageLayout. FragmentShaderReadOnly is picked here since this is the most reasonable usage
6253     // after glGenerateMipmap call.
6254     barrier.oldLayout     = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
6255     barrier.newLayout     = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
6256     barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
6257     if (baseLevel.get() > 0)
6258     {
6259         // [0:baseLevel-1] from TRANSFER_DST to SHADER_READ
6260         barrier.subresourceRange.baseMipLevel = 0;
6261         barrier.subresourceRange.levelCount   = baseLevel.get();
6262         commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
6263                                     VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, barrier);
6264     }
6265     // [maxLevel:mLevelCount-1] from TRANSFER_DST to SHADER_READ
6266     ASSERT(mLevelCount > maxLevel.get());
6267     barrier.subresourceRange.baseMipLevel = maxLevel.get();
6268     barrier.subresourceRange.levelCount   = mLevelCount - maxLevel.get();
6269     commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
6270                                 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, barrier);
6271     // [baseLevel:maxLevel-1] from TRANSFER_SRC to SHADER_READ
6272     barrier.oldLayout                     = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
6273     barrier.subresourceRange.baseMipLevel = baseLevel.get();
6274     barrier.subresourceRange.levelCount   = maxLevel.get() - baseLevel.get();
6275     commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
6276                                 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, barrier);
6277 
6278     // This is just changing the internal state of the image helper so that the next call
6279     // to changeLayout will use this layout as the "oldLayout" argument.
6280     // mLastNonShaderReadOnlyLayout is used to ensure previous write are made visible to reads,
6281     // since the only write here is transfer, hence mLastNonShaderReadOnlyLayout is set to
6282     // ImageLayout::TransferDst.
6283     mLastNonShaderReadOnlyLayout = ImageLayout::TransferDst;
6284     mCurrentShaderReadStageMask  = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
6285     mCurrentLayout               = ImageLayout::FragmentShaderReadOnly;
6286 
6287     return angle::Result::Continue;
6288 }
6289 
resolve(ImageHelper * dst,const VkImageResolve & region,OutsideRenderPassCommandBuffer * commandBuffer)6290 void ImageHelper::resolve(ImageHelper *dst,
6291                           const VkImageResolve &region,
6292                           OutsideRenderPassCommandBuffer *commandBuffer)
6293 {
6294     ASSERT(mCurrentLayout == ImageLayout::TransferSrc ||
6295            mCurrentLayout == ImageLayout::SharedPresent);
6296     commandBuffer->resolveImage(getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst->getImage(),
6297                                 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
6298 }
6299 
removeSingleSubresourceStagedUpdates(ContextVk * contextVk,gl::LevelIndex levelIndexGL,uint32_t layerIndex,uint32_t layerCount)6300 void ImageHelper::removeSingleSubresourceStagedUpdates(ContextVk *contextVk,
6301                                                        gl::LevelIndex levelIndexGL,
6302                                                        uint32_t layerIndex,
6303                                                        uint32_t layerCount)
6304 {
6305     mCurrentSingleClearValue.reset();
6306 
6307     // Find any staged updates for this index and remove them from the pending list.
6308     std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(levelIndexGL);
6309     if (levelUpdates == nullptr)
6310     {
6311         return;
6312     }
6313 
6314     for (size_t index = 0; index < levelUpdates->size();)
6315     {
6316         auto update = levelUpdates->begin() + index;
6317         if (update->isUpdateToLayers(layerIndex, layerCount))
6318         {
6319             update->release(contextVk->getRenderer());
6320             levelUpdates->erase(update);
6321         }
6322         else
6323         {
6324             index++;
6325         }
6326     }
6327 }
6328 
removeSingleStagedClearAfterInvalidate(gl::LevelIndex levelIndexGL,uint32_t layerIndex,uint32_t layerCount)6329 void ImageHelper::removeSingleStagedClearAfterInvalidate(gl::LevelIndex levelIndexGL,
6330                                                          uint32_t layerIndex,
6331                                                          uint32_t layerCount)
6332 {
6333     // When this function is called, it's expected that there may be at most one
6334     // ClearAfterInvalidate update pending to this subresource, and that's a color clear due to
6335     // emulated channels after invalidate.  This function removes that update.
6336 
6337     std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(levelIndexGL);
6338     if (levelUpdates == nullptr)
6339     {
6340         return;
6341     }
6342 
6343     for (size_t index = 0; index < levelUpdates->size(); ++index)
6344     {
6345         auto update = levelUpdates->begin() + index;
6346         if (update->updateSource == UpdateSource::ClearAfterInvalidate &&
6347             update->isUpdateToLayers(layerIndex, layerCount))
6348         {
6349             // It's a clear, so doesn't need to be released.
6350             levelUpdates->erase(update);
6351             // There's only one such clear possible.
6352             return;
6353         }
6354     }
6355 }
6356 
removeStagedUpdates(Context * context,gl::LevelIndex levelGLStart,gl::LevelIndex levelGLEnd)6357 void ImageHelper::removeStagedUpdates(Context *context,
6358                                       gl::LevelIndex levelGLStart,
6359                                       gl::LevelIndex levelGLEnd)
6360 {
6361     ASSERT(validateSubresourceUpdateRefCountsConsistent());
6362 
6363     // Remove all updates to levels [start, end].
6364     for (gl::LevelIndex level = levelGLStart; level <= levelGLEnd; ++level)
6365     {
6366         std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(level);
6367         if (levelUpdates == nullptr)
6368         {
6369             ASSERT(static_cast<size_t>(level.get()) >= mSubresourceUpdates.size());
6370             return;
6371         }
6372 
6373         for (SubresourceUpdate &update : *levelUpdates)
6374         {
6375             update.release(context->getRenderer());
6376         }
6377 
6378         levelUpdates->clear();
6379     }
6380 
6381     ASSERT(validateSubresourceUpdateRefCountsConsistent());
6382 }
6383 
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,ImageAccess access,const GLuint inputRowPitch,const GLuint inputDepthPitch,const GLuint inputSkipBytes)6384 angle::Result ImageHelper::stageSubresourceUpdateImpl(ContextVk *contextVk,
6385                                                       const gl::ImageIndex &index,
6386                                                       const gl::Extents &glExtents,
6387                                                       const gl::Offset &offset,
6388                                                       const gl::InternalFormat &formatInfo,
6389                                                       const gl::PixelUnpackState &unpack,
6390                                                       GLenum type,
6391                                                       const uint8_t *pixels,
6392                                                       const Format &vkFormat,
6393                                                       ImageAccess access,
6394                                                       const GLuint inputRowPitch,
6395                                                       const GLuint inputDepthPitch,
6396                                                       const GLuint inputSkipBytes)
6397 {
6398     const angle::Format &storageFormat = vkFormat.getActualImageFormat(access);
6399 
6400     size_t outputRowPitch;
6401     size_t outputDepthPitch;
6402     size_t stencilAllocationSize = 0;
6403     uint32_t bufferRowLength;
6404     uint32_t bufferImageHeight;
6405     size_t allocationSize;
6406 
6407     LoadImageFunctionInfo loadFunctionInfo = vkFormat.getTextureLoadFunction(access, type);
6408     LoadImageFunction stencilLoadFunction  = nullptr;
6409 
6410     if (storageFormat.isBlock)
6411     {
6412         const gl::InternalFormat &storageFormatInfo = vkFormat.getInternalFormatInfo(type);
6413         GLuint rowPitch;
6414         GLuint depthPitch;
6415         GLuint totalSize;
6416 
6417         ANGLE_VK_CHECK_MATH(contextVk, storageFormatInfo.computeCompressedImageSize(
6418                                            gl::Extents(glExtents.width, 1, 1), &rowPitch));
6419         ANGLE_VK_CHECK_MATH(contextVk,
6420                             storageFormatInfo.computeCompressedImageSize(
6421                                 gl::Extents(glExtents.width, glExtents.height, 1), &depthPitch));
6422 
6423         ANGLE_VK_CHECK_MATH(contextVk,
6424                             storageFormatInfo.computeCompressedImageSize(glExtents, &totalSize));
6425 
6426         outputRowPitch   = rowPitch;
6427         outputDepthPitch = depthPitch;
6428         allocationSize   = totalSize;
6429 
6430         ANGLE_VK_CHECK_MATH(
6431             contextVk, storageFormatInfo.computeBufferRowLength(glExtents.width, &bufferRowLength));
6432         ANGLE_VK_CHECK_MATH(contextVk, storageFormatInfo.computeBufferImageHeight(
6433                                            glExtents.height, &bufferImageHeight));
6434     }
6435     else
6436     {
6437         ASSERT(storageFormat.pixelBytes != 0);
6438 
6439         if (storageFormat.id == angle::FormatID::D24_UNORM_S8_UINT)
6440         {
6441             stencilLoadFunction = angle::LoadX24S8ToS8;
6442         }
6443         if (storageFormat.id == angle::FormatID::D32_FLOAT_S8X24_UINT)
6444         {
6445             // If depth is D32FLOAT_S8, we must pack D32F tightly (no stencil) for CopyBufferToImage
6446             outputRowPitch = sizeof(float) * glExtents.width;
6447 
6448             // The generic load functions don't handle tightly packing D32FS8 to D32F & S8 so call
6449             // special case load functions.
6450             switch (type)
6451             {
6452                 case GL_UNSIGNED_INT:
6453                     loadFunctionInfo.loadFunction = angle::LoadD32ToD32F;
6454                     stencilLoadFunction           = nullptr;
6455                     break;
6456                 case GL_DEPTH32F_STENCIL8:
6457                 case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
6458                     loadFunctionInfo.loadFunction = angle::LoadD32FS8X24ToD32F;
6459                     stencilLoadFunction           = angle::LoadX32S8ToS8;
6460                     break;
6461                 case GL_UNSIGNED_INT_24_8_OES:
6462                     loadFunctionInfo.loadFunction = angle::LoadD24S8ToD32F;
6463                     stencilLoadFunction           = angle::LoadX24S8ToS8;
6464                     break;
6465                 default:
6466                     UNREACHABLE();
6467             }
6468         }
6469         else
6470         {
6471             outputRowPitch = storageFormat.pixelBytes * glExtents.width;
6472         }
6473         outputDepthPitch = outputRowPitch * glExtents.height;
6474 
6475         bufferRowLength   = glExtents.width;
6476         bufferImageHeight = glExtents.height;
6477 
6478         allocationSize = outputDepthPitch * glExtents.depth;
6479 
6480         // Note: because the LoadImageFunctionInfo functions are limited to copying a single
6481         // component, we have to special case packed depth/stencil use and send the stencil as a
6482         // separate chunk.
6483         if (storageFormat.depthBits > 0 && storageFormat.stencilBits > 0 &&
6484             formatInfo.depthBits > 0 && formatInfo.stencilBits > 0)
6485         {
6486             // Note: Stencil is always one byte
6487             stencilAllocationSize = glExtents.width * glExtents.height * glExtents.depth;
6488             allocationSize += stencilAllocationSize;
6489         }
6490     }
6491 
6492     std::unique_ptr<RefCounted<BufferHelper>> stagingBuffer =
6493         std::make_unique<RefCounted<BufferHelper>>();
6494     BufferHelper *currentBuffer = &stagingBuffer->get();
6495 
6496     uint8_t *stagingPointer;
6497     VkDeviceSize stagingOffset;
6498     ANGLE_TRY(currentBuffer->allocateForCopyImage(contextVk, allocationSize,
6499                                                   MemoryCoherency::NonCoherent, storageFormat.id,
6500                                                   &stagingOffset, &stagingPointer));
6501 
6502     const uint8_t *source = pixels + static_cast<ptrdiff_t>(inputSkipBytes);
6503 
6504     loadFunctionInfo.loadFunction(glExtents.width, glExtents.height, glExtents.depth, source,
6505                                   inputRowPitch, inputDepthPitch, stagingPointer, outputRowPitch,
6506                                   outputDepthPitch);
6507 
6508     // YUV formats need special handling.
6509     if (storageFormat.isYUV)
6510     {
6511         gl::YuvFormatInfo yuvInfo(formatInfo.internalFormat, glExtents);
6512 
6513         constexpr VkImageAspectFlagBits kPlaneAspectFlags[3] = {
6514             VK_IMAGE_ASPECT_PLANE_0_BIT, VK_IMAGE_ASPECT_PLANE_1_BIT, VK_IMAGE_ASPECT_PLANE_2_BIT};
6515 
6516         // We only support mip level 0 and layerCount of 1 for YUV formats.
6517         ASSERT(index.getLevelIndex() == 0);
6518         ASSERT(index.getLayerCount() == 1);
6519 
6520         for (uint32_t plane = 0; plane < yuvInfo.planeCount; plane++)
6521         {
6522             VkBufferImageCopy copy           = {};
6523             copy.bufferOffset                = stagingOffset + yuvInfo.planeOffset[plane];
6524             copy.bufferRowLength             = 0;
6525             copy.bufferImageHeight           = 0;
6526             copy.imageSubresource.mipLevel   = 0;
6527             copy.imageSubresource.layerCount = 1;
6528             gl_vk::GetOffset(offset, &copy.imageOffset);
6529             gl_vk::GetExtent(yuvInfo.planeExtent[plane], &copy.imageExtent);
6530             copy.imageSubresource.baseArrayLayer = 0;
6531             copy.imageSubresource.aspectMask     = kPlaneAspectFlags[plane];
6532             appendSubresourceUpdate(
6533                 gl::LevelIndex(0),
6534                 SubresourceUpdate(stagingBuffer.get(), currentBuffer, copy, storageFormat.id));
6535         }
6536 
6537         stagingBuffer.release();
6538         return angle::Result::Continue;
6539     }
6540 
6541     VkBufferImageCopy copy         = {};
6542     VkImageAspectFlags aspectFlags = GetFormatAspectFlags(storageFormat);
6543 
6544     copy.bufferOffset      = stagingOffset;
6545     copy.bufferRowLength   = bufferRowLength;
6546     copy.bufferImageHeight = bufferImageHeight;
6547 
6548     gl::LevelIndex updateLevelGL(index.getLevelIndex());
6549     copy.imageSubresource.mipLevel   = updateLevelGL.get();
6550     copy.imageSubresource.layerCount = index.getLayerCount();
6551 
6552     gl_vk::GetOffset(offset, &copy.imageOffset);
6553     gl_vk::GetExtent(glExtents, &copy.imageExtent);
6554 
6555     if (gl::IsArrayTextureType(index.getType()))
6556     {
6557         copy.imageSubresource.baseArrayLayer = offset.z;
6558         copy.imageOffset.z                   = 0;
6559         copy.imageExtent.depth               = 1;
6560     }
6561     else
6562     {
6563         copy.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
6564     }
6565 
6566     if (stencilAllocationSize > 0)
6567     {
6568         // Note: Stencil is always one byte
6569         ASSERT((aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) != 0);
6570 
6571         // Skip over depth data.
6572         stagingPointer += outputDepthPitch * glExtents.depth;
6573         stagingOffset += outputDepthPitch * glExtents.depth;
6574 
6575         // recompute pitch for stencil data
6576         outputRowPitch   = glExtents.width;
6577         outputDepthPitch = outputRowPitch * glExtents.height;
6578 
6579         ASSERT(stencilLoadFunction != nullptr);
6580         stencilLoadFunction(glExtents.width, glExtents.height, glExtents.depth, source,
6581                             inputRowPitch, inputDepthPitch, stagingPointer, outputRowPitch,
6582                             outputDepthPitch);
6583 
6584         VkBufferImageCopy stencilCopy = {};
6585 
6586         stencilCopy.bufferOffset                    = stagingOffset;
6587         stencilCopy.bufferRowLength                 = bufferRowLength;
6588         stencilCopy.bufferImageHeight               = bufferImageHeight;
6589         stencilCopy.imageSubresource.mipLevel       = copy.imageSubresource.mipLevel;
6590         stencilCopy.imageSubresource.baseArrayLayer = copy.imageSubresource.baseArrayLayer;
6591         stencilCopy.imageSubresource.layerCount     = copy.imageSubresource.layerCount;
6592         stencilCopy.imageOffset                     = copy.imageOffset;
6593         stencilCopy.imageExtent                     = copy.imageExtent;
6594         stencilCopy.imageSubresource.aspectMask     = VK_IMAGE_ASPECT_STENCIL_BIT;
6595         appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(stagingBuffer.get(), currentBuffer,
6596                                                                  stencilCopy, storageFormat.id));
6597 
6598         aspectFlags &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
6599     }
6600 
6601     if (HasBothDepthAndStencilAspects(aspectFlags))
6602     {
6603         // We still have both depth and stencil aspect bits set. That means we have a destination
6604         // buffer that is packed depth stencil and that the application is only loading one aspect.
6605         // Figure out which aspect the user is touching and remove the unused aspect bit.
6606         if (formatInfo.stencilBits > 0)
6607         {
6608             aspectFlags &= ~VK_IMAGE_ASPECT_DEPTH_BIT;
6609         }
6610         else
6611         {
6612             aspectFlags &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
6613         }
6614     }
6615 
6616     if (aspectFlags)
6617     {
6618         copy.imageSubresource.aspectMask = aspectFlags;
6619         appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(stagingBuffer.get(), currentBuffer,
6620                                                                  copy, storageFormat.id));
6621     }
6622 
6623     stagingBuffer.release();
6624     return angle::Result::Continue;
6625 }
6626 
reformatStagedBufferUpdates(ContextVk * contextVk,angle::FormatID srcFormatID,angle::FormatID dstFormatID)6627 angle::Result ImageHelper::reformatStagedBufferUpdates(ContextVk *contextVk,
6628                                                        angle::FormatID srcFormatID,
6629                                                        angle::FormatID dstFormatID)
6630 {
6631     RendererVk *renderer           = contextVk->getRenderer();
6632     const angle::Format &srcFormat = angle::Format::Get(srcFormatID);
6633     const angle::Format &dstFormat = angle::Format::Get(dstFormatID);
6634     const gl::InternalFormat &dstFormatInfo =
6635         gl::GetSizedInternalFormatInfo(dstFormat.glInternalFormat);
6636 
6637     for (std::vector<SubresourceUpdate> &levelUpdates : mSubresourceUpdates)
6638     {
6639         for (SubresourceUpdate &update : levelUpdates)
6640         {
6641             // Right now whenever we stage update from a source image, the formats always match.
6642             ASSERT(valid() || update.updateSource != UpdateSource::Image ||
6643                    update.data.image.formatID == srcFormatID);
6644 
6645             if (update.updateSource == UpdateSource::Buffer &&
6646                 update.data.buffer.formatID == srcFormatID)
6647             {
6648                 const VkBufferImageCopy &copy = update.data.buffer.copyRegion;
6649 
6650                 // Source and dst data are tightly packed
6651                 GLuint srcDataRowPitch = copy.imageExtent.width * srcFormat.pixelBytes;
6652                 GLuint dstDataRowPitch = copy.imageExtent.width * dstFormat.pixelBytes;
6653 
6654                 GLuint srcDataDepthPitch = srcDataRowPitch * copy.imageExtent.height;
6655                 GLuint dstDataDepthPitch = dstDataRowPitch * copy.imageExtent.height;
6656 
6657                 // Retrieve source buffer
6658                 vk::BufferHelper *srcBuffer = update.data.buffer.bufferHelper;
6659                 ASSERT(srcBuffer->isMapped());
6660                 // The bufferOffset is relative to the buffer block. We have to use the buffer
6661                 // block's memory pointer to get the source data pointer.
6662                 uint8_t *srcData = srcBuffer->getBlockMemory() + copy.bufferOffset;
6663 
6664                 // Allocate memory with dstFormat
6665                 std::unique_ptr<RefCounted<BufferHelper>> stagingBuffer =
6666                     std::make_unique<RefCounted<BufferHelper>>();
6667                 BufferHelper *dstBuffer = &stagingBuffer->get();
6668 
6669                 uint8_t *dstData;
6670                 VkDeviceSize dstBufferOffset;
6671                 size_t dstBufferSize = dstDataDepthPitch * copy.imageExtent.depth;
6672                 ANGLE_TRY(dstBuffer->allocateForCopyImage(contextVk, dstBufferSize,
6673                                                           MemoryCoherency::NonCoherent, dstFormatID,
6674                                                           &dstBufferOffset, &dstData));
6675 
6676                 rx::PixelReadFunction pixelReadFunction   = srcFormat.pixelReadFunction;
6677                 rx::PixelWriteFunction pixelWriteFunction = dstFormat.pixelWriteFunction;
6678 
6679                 CopyImageCHROMIUM(srcData, srcDataRowPitch, srcFormat.pixelBytes, srcDataDepthPitch,
6680                                   pixelReadFunction, dstData, dstDataRowPitch, dstFormat.pixelBytes,
6681                                   dstDataDepthPitch, pixelWriteFunction, dstFormatInfo.format,
6682                                   dstFormatInfo.componentType, copy.imageExtent.width,
6683                                   copy.imageExtent.height, copy.imageExtent.depth, false, false,
6684                                   false);
6685 
6686                 // Replace srcBuffer with dstBuffer
6687                 update.data.buffer.bufferHelper            = dstBuffer;
6688                 update.data.buffer.formatID                = dstFormatID;
6689                 update.data.buffer.copyRegion.bufferOffset = dstBufferOffset;
6690 
6691                 // Let update structure owns the staging buffer
6692                 if (update.refCounted.buffer)
6693                 {
6694                     update.refCounted.buffer->releaseRef();
6695                     if (!update.refCounted.buffer->isReferenced())
6696                     {
6697                         update.refCounted.buffer->get().release(renderer);
6698                         SafeDelete(update.refCounted.buffer);
6699                     }
6700                 }
6701                 update.refCounted.buffer = stagingBuffer.release();
6702                 update.refCounted.buffer->addRef();
6703             }
6704         }
6705     }
6706 
6707     return angle::Result::Continue;
6708 }
6709 
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)6710 angle::Result ImageHelper::CalculateBufferInfo(ContextVk *contextVk,
6711                                                const gl::Extents &glExtents,
6712                                                const gl::InternalFormat &formatInfo,
6713                                                const gl::PixelUnpackState &unpack,
6714                                                GLenum type,
6715                                                bool is3D,
6716                                                GLuint *inputRowPitch,
6717                                                GLuint *inputDepthPitch,
6718                                                GLuint *inputSkipBytes)
6719 {
6720     // YUV formats need special handling.
6721     if (gl::IsYuvFormat(formatInfo.internalFormat))
6722     {
6723         gl::YuvFormatInfo yuvInfo(formatInfo.internalFormat, glExtents);
6724 
6725         // row pitch = Y plane row pitch
6726         *inputRowPitch = yuvInfo.planePitch[0];
6727         // depth pitch = Y plane size + chroma plane size
6728         *inputDepthPitch = yuvInfo.planeSize[0] + yuvInfo.planeSize[1] + yuvInfo.planeSize[2];
6729         *inputSkipBytes  = 0;
6730 
6731         return angle::Result::Continue;
6732     }
6733 
6734     ANGLE_VK_CHECK_MATH(contextVk,
6735                         formatInfo.computeRowPitch(type, glExtents.width, unpack.alignment,
6736                                                    unpack.rowLength, inputRowPitch));
6737 
6738     ANGLE_VK_CHECK_MATH(contextVk,
6739                         formatInfo.computeDepthPitch(glExtents.height, unpack.imageHeight,
6740                                                      *inputRowPitch, inputDepthPitch));
6741 
6742     ANGLE_VK_CHECK_MATH(
6743         contextVk, formatInfo.computeSkipBytes(type, *inputRowPitch, *inputDepthPitch, unpack, is3D,
6744                                                inputSkipBytes));
6745 
6746     return angle::Result::Continue;
6747 }
6748 
onWrite(gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags)6749 void ImageHelper::onWrite(gl::LevelIndex levelStart,
6750                           uint32_t levelCount,
6751                           uint32_t layerStart,
6752                           uint32_t layerCount,
6753                           VkImageAspectFlags aspectFlags)
6754 {
6755     mCurrentSingleClearValue.reset();
6756 
6757     // Mark contents of the given subresource as defined.
6758     setContentDefined(toVkLevel(levelStart), levelCount, layerStart, layerCount, aspectFlags);
6759 }
6760 
hasSubresourceDefinedContent(gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount) const6761 bool ImageHelper::hasSubresourceDefinedContent(gl::LevelIndex level,
6762                                                uint32_t layerIndex,
6763                                                uint32_t layerCount) const
6764 {
6765     if (layerIndex >= kMaxContentDefinedLayerCount)
6766     {
6767         return true;
6768     }
6769 
6770     uint8_t layerRangeBits =
6771         GetContentDefinedLayerRangeBits(layerIndex, layerCount, kMaxContentDefinedLayerCount);
6772     return (getLevelContentDefined(toVkLevel(level)) & LevelContentDefinedMask(layerRangeBits))
6773         .any();
6774 }
6775 
hasSubresourceDefinedStencilContent(gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount) const6776 bool ImageHelper::hasSubresourceDefinedStencilContent(gl::LevelIndex level,
6777                                                       uint32_t layerIndex,
6778                                                       uint32_t layerCount) const
6779 {
6780     if (layerIndex >= kMaxContentDefinedLayerCount)
6781     {
6782         return true;
6783     }
6784 
6785     uint8_t layerRangeBits =
6786         GetContentDefinedLayerRangeBits(layerIndex, layerCount, kMaxContentDefinedLayerCount);
6787     return (getLevelStencilContentDefined(toVkLevel(level)) &
6788             LevelContentDefinedMask(layerRangeBits))
6789         .any();
6790 }
6791 
invalidateSubresourceContent(ContextVk * contextVk,gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount,bool * preferToKeepContentsDefinedOut)6792 void ImageHelper::invalidateSubresourceContent(ContextVk *contextVk,
6793                                                gl::LevelIndex level,
6794                                                uint32_t layerIndex,
6795                                                uint32_t layerCount,
6796                                                bool *preferToKeepContentsDefinedOut)
6797 {
6798     invalidateSubresourceContentImpl(
6799         contextVk, level, layerIndex, layerCount,
6800         static_cast<VkImageAspectFlagBits>(getAspectFlags() & ~VK_IMAGE_ASPECT_STENCIL_BIT),
6801         &getLevelContentDefined(toVkLevel(level)), preferToKeepContentsDefinedOut);
6802 }
6803 
invalidateSubresourceStencilContent(ContextVk * contextVk,gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount,bool * preferToKeepContentsDefinedOut)6804 void ImageHelper::invalidateSubresourceStencilContent(ContextVk *contextVk,
6805                                                       gl::LevelIndex level,
6806                                                       uint32_t layerIndex,
6807                                                       uint32_t layerCount,
6808                                                       bool *preferToKeepContentsDefinedOut)
6809 {
6810     invalidateSubresourceContentImpl(
6811         contextVk, level, layerIndex, layerCount, VK_IMAGE_ASPECT_STENCIL_BIT,
6812         &getLevelStencilContentDefined(toVkLevel(level)), preferToKeepContentsDefinedOut);
6813 }
6814 
invalidateSubresourceContentImpl(ContextVk * contextVk,gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount,VkImageAspectFlagBits aspect,LevelContentDefinedMask * contentDefinedMask,bool * preferToKeepContentsDefinedOut)6815 void ImageHelper::invalidateSubresourceContentImpl(ContextVk *contextVk,
6816                                                    gl::LevelIndex level,
6817                                                    uint32_t layerIndex,
6818                                                    uint32_t layerCount,
6819                                                    VkImageAspectFlagBits aspect,
6820                                                    LevelContentDefinedMask *contentDefinedMask,
6821                                                    bool *preferToKeepContentsDefinedOut)
6822 {
6823     // If the aspect being invalidated doesn't exist, skip invalidation altogether.
6824     if ((getAspectFlags() & aspect) == 0)
6825     {
6826         if (preferToKeepContentsDefinedOut)
6827         {
6828             // Let the caller know that this invalidate request was ignored.
6829             *preferToKeepContentsDefinedOut = true;
6830         }
6831         return;
6832     }
6833 
6834     // If the color format is emulated and has extra channels, those channels need to stay cleared.
6835     // On some devices, it's cheaper to skip invalidating the framebuffer attachment, while on
6836     // others it's cheaper to invalidate but then re-clear the image.
6837     //
6838     // For depth/stencil formats, each channel is separately invalidated, so the invalidate is
6839     // simply skipped for the emulated channel on all devices.
6840     const bool hasEmulatedChannels = hasEmulatedImageChannels();
6841     bool skip                      = false;
6842     switch (aspect)
6843     {
6844         case VK_IMAGE_ASPECT_DEPTH_BIT:
6845             skip = hasEmulatedDepthChannel();
6846             break;
6847         case VK_IMAGE_ASPECT_STENCIL_BIT:
6848             skip = hasEmulatedStencilChannel();
6849             break;
6850         case VK_IMAGE_ASPECT_COLOR_BIT:
6851             skip = hasEmulatedChannels &&
6852                    contextVk->getFeatures().preferSkippingInvalidateForEmulatedFormats.enabled;
6853             break;
6854         default:
6855             UNREACHABLE();
6856             skip = true;
6857     }
6858 
6859     if (preferToKeepContentsDefinedOut)
6860     {
6861         *preferToKeepContentsDefinedOut = skip;
6862     }
6863     if (skip)
6864     {
6865         return;
6866     }
6867 
6868     if (layerIndex >= kMaxContentDefinedLayerCount)
6869     {
6870         const char *aspectName = "color";
6871         if (aspect == VK_IMAGE_ASPECT_DEPTH_BIT)
6872         {
6873             aspectName = "depth";
6874         }
6875         else if (aspect == VK_IMAGE_ASPECT_STENCIL_BIT)
6876         {
6877             aspectName = "stencil";
6878         }
6879         ANGLE_VK_PERF_WARNING(
6880             contextVk, GL_DEBUG_SEVERITY_LOW,
6881             "glInvalidateFramebuffer (%s) ineffective on attachments with layer >= 8", aspectName);
6882         return;
6883     }
6884 
6885     uint8_t layerRangeBits =
6886         GetContentDefinedLayerRangeBits(layerIndex, layerCount, kMaxContentDefinedLayerCount);
6887     *contentDefinedMask &= static_cast<uint8_t>(~layerRangeBits);
6888 
6889     // If there are emulated channels, stage a clear to make sure those channels continue to contain
6890     // valid values.
6891     if (hasEmulatedChannels && aspect == VK_IMAGE_ASPECT_COLOR_BIT)
6892     {
6893         VkClearValue clearValue;
6894         clearValue.color = kEmulatedInitColorValue;
6895 
6896         prependSubresourceUpdate(
6897             level, SubresourceUpdate(aspect, clearValue, level, layerIndex, layerCount));
6898         mSubresourceUpdates[level.get()].front().updateSource = UpdateSource::ClearAfterInvalidate;
6899     }
6900 }
6901 
restoreSubresourceContent(gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount)6902 void ImageHelper::restoreSubresourceContent(gl::LevelIndex level,
6903                                             uint32_t layerIndex,
6904                                             uint32_t layerCount)
6905 {
6906     restoreSubresourceContentImpl(
6907         level, layerIndex, layerCount,
6908         static_cast<VkImageAspectFlagBits>(getAspectFlags() & ~VK_IMAGE_ASPECT_STENCIL_BIT),
6909         &getLevelContentDefined(toVkLevel(level)));
6910 }
6911 
restoreSubresourceStencilContent(gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount)6912 void ImageHelper::restoreSubresourceStencilContent(gl::LevelIndex level,
6913                                                    uint32_t layerIndex,
6914                                                    uint32_t layerCount)
6915 {
6916     restoreSubresourceContentImpl(level, layerIndex, layerCount, VK_IMAGE_ASPECT_STENCIL_BIT,
6917                                   &getLevelStencilContentDefined(toVkLevel(level)));
6918 }
6919 
restoreSubresourceContentImpl(gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount,VkImageAspectFlagBits aspect,LevelContentDefinedMask * contentDefinedMask)6920 void ImageHelper::restoreSubresourceContentImpl(gl::LevelIndex level,
6921                                                 uint32_t layerIndex,
6922                                                 uint32_t layerCount,
6923                                                 VkImageAspectFlagBits aspect,
6924                                                 LevelContentDefinedMask *contentDefinedMask)
6925 {
6926     if (layerIndex >= kMaxContentDefinedLayerCount)
6927     {
6928         return;
6929     }
6930 
6931     uint8_t layerRangeBits =
6932         GetContentDefinedLayerRangeBits(layerIndex, layerCount, kMaxContentDefinedLayerCount);
6933 
6934     switch (aspect)
6935     {
6936         case VK_IMAGE_ASPECT_DEPTH_BIT:
6937             // Emulated depth channel should never have been marked invalid, so it can retain its
6938             // cleared value.
6939             ASSERT(!hasEmulatedDepthChannel() ||
6940                    (contentDefinedMask->bits() & layerRangeBits) == layerRangeBits);
6941             break;
6942         case VK_IMAGE_ASPECT_STENCIL_BIT:
6943             // Emulated stencil channel should never have been marked invalid, so it can retain its
6944             // cleared value.
6945             ASSERT(!hasEmulatedStencilChannel() ||
6946                    (contentDefinedMask->bits() & layerRangeBits) == layerRangeBits);
6947             break;
6948         case VK_IMAGE_ASPECT_COLOR_BIT:
6949             // This function is called on attachments during a render pass when it's determined that
6950             // they should no longer be considered invalidated.  For an attachment with emulated
6951             // format that has extra channels, invalidateSubresourceContentImpl may have proactively
6952             // inserted a clear so that the extra channels continue to have defined values.  That
6953             // clear should be removed.
6954             if (hasEmulatedImageChannels())
6955             {
6956                 removeSingleStagedClearAfterInvalidate(level, layerIndex, layerCount);
6957             }
6958             // Additionally, as the resource has been rewritten to in the render pass, its no longer
6959             // cleared to the cached value.
6960             mCurrentSingleClearValue.reset();
6961             break;
6962         default:
6963             UNREACHABLE();
6964             break;
6965     }
6966 
6967     *contentDefinedMask |= layerRangeBits;
6968 }
6969 
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,ImageAccess access)6970 angle::Result ImageHelper::stageSubresourceUpdate(ContextVk *contextVk,
6971                                                   const gl::ImageIndex &index,
6972                                                   const gl::Extents &glExtents,
6973                                                   const gl::Offset &offset,
6974                                                   const gl::InternalFormat &formatInfo,
6975                                                   const gl::PixelUnpackState &unpack,
6976                                                   GLenum type,
6977                                                   const uint8_t *pixels,
6978                                                   const Format &vkFormat,
6979                                                   ImageAccess access)
6980 {
6981     GLuint inputRowPitch   = 0;
6982     GLuint inputDepthPitch = 0;
6983     GLuint inputSkipBytes  = 0;
6984     ANGLE_TRY(CalculateBufferInfo(contextVk, glExtents, formatInfo, unpack, type, index.usesTex3D(),
6985                                   &inputRowPitch, &inputDepthPitch, &inputSkipBytes));
6986 
6987     ANGLE_TRY(stageSubresourceUpdateImpl(contextVk, index, glExtents, offset, formatInfo, unpack,
6988                                          type, pixels, vkFormat, access, inputRowPitch,
6989                                          inputDepthPitch, inputSkipBytes));
6990 
6991     return angle::Result::Continue;
6992 }
6993 
stageSubresourceUpdateAndGetData(ContextVk * contextVk,size_t allocationSize,const gl::ImageIndex & imageIndex,const gl::Extents & glExtents,const gl::Offset & offset,uint8_t ** dstData,angle::FormatID formatID)6994 angle::Result ImageHelper::stageSubresourceUpdateAndGetData(ContextVk *contextVk,
6995                                                             size_t allocationSize,
6996                                                             const gl::ImageIndex &imageIndex,
6997                                                             const gl::Extents &glExtents,
6998                                                             const gl::Offset &offset,
6999                                                             uint8_t **dstData,
7000                                                             angle::FormatID formatID)
7001 {
7002     std::unique_ptr<RefCounted<BufferHelper>> stagingBuffer =
7003         std::make_unique<RefCounted<BufferHelper>>();
7004     BufferHelper *currentBuffer = &stagingBuffer->get();
7005 
7006     VkDeviceSize stagingOffset;
7007     ANGLE_TRY(currentBuffer->allocateForCopyImage(contextVk, allocationSize,
7008                                                   MemoryCoherency::NonCoherent, formatID,
7009                                                   &stagingOffset, dstData));
7010 
7011     gl::LevelIndex updateLevelGL(imageIndex.getLevelIndex());
7012 
7013     VkBufferImageCopy copy               = {};
7014     copy.bufferOffset                    = stagingOffset;
7015     copy.bufferRowLength                 = glExtents.width;
7016     copy.bufferImageHeight               = glExtents.height;
7017     copy.imageSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
7018     copy.imageSubresource.mipLevel       = updateLevelGL.get();
7019     copy.imageSubresource.baseArrayLayer = imageIndex.hasLayer() ? imageIndex.getLayerIndex() : 0;
7020     copy.imageSubresource.layerCount     = imageIndex.getLayerCount();
7021 
7022     // Note: Only support color now
7023     ASSERT((mActualFormatID == angle::FormatID::NONE) ||
7024            (getAspectFlags() == VK_IMAGE_ASPECT_COLOR_BIT));
7025 
7026     gl_vk::GetOffset(offset, &copy.imageOffset);
7027     gl_vk::GetExtent(glExtents, &copy.imageExtent);
7028 
7029     appendSubresourceUpdate(
7030         updateLevelGL, SubresourceUpdate(stagingBuffer.release(), currentBuffer, copy, formatID));
7031     return angle::Result::Continue;
7032 }
7033 
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,ImageAccess access,FramebufferVk * framebufferVk)7034 angle::Result ImageHelper::stageSubresourceUpdateFromFramebuffer(
7035     const gl::Context *context,
7036     const gl::ImageIndex &index,
7037     const gl::Rectangle &sourceArea,
7038     const gl::Offset &dstOffset,
7039     const gl::Extents &dstExtent,
7040     const gl::InternalFormat &formatInfo,
7041     ImageAccess access,
7042     FramebufferVk *framebufferVk)
7043 {
7044     ContextVk *contextVk = GetImpl(context);
7045 
7046     // If the extents and offset is outside the source image, we need to clip.
7047     gl::Rectangle clippedRectangle;
7048     const gl::Extents readExtents = framebufferVk->getReadImageExtents();
7049     if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, readExtents.width, readExtents.height),
7050                        &clippedRectangle))
7051     {
7052         // Empty source area, nothing to do.
7053         return angle::Result::Continue;
7054     }
7055 
7056     bool isViewportFlipEnabled = contextVk->isViewportFlipEnabledForDrawFBO();
7057     if (isViewportFlipEnabled)
7058     {
7059         clippedRectangle.y = readExtents.height - clippedRectangle.y - clippedRectangle.height;
7060     }
7061 
7062     // 1- obtain a buffer handle to copy to
7063     RendererVk *renderer = contextVk->getRenderer();
7064 
7065     const Format &vkFormat             = renderer->getFormat(formatInfo.sizedInternalFormat);
7066     const angle::Format &storageFormat = vkFormat.getActualImageFormat(access);
7067     LoadImageFunctionInfo loadFunction = vkFormat.getTextureLoadFunction(access, formatInfo.type);
7068 
7069     size_t outputRowPitch   = storageFormat.pixelBytes * clippedRectangle.width;
7070     size_t outputDepthPitch = outputRowPitch * clippedRectangle.height;
7071 
7072     std::unique_ptr<RefCounted<BufferHelper>> stagingBuffer =
7073         std::make_unique<RefCounted<BufferHelper>>();
7074     BufferHelper *currentBuffer = &stagingBuffer->get();
7075 
7076     uint8_t *stagingPointer;
7077     VkDeviceSize stagingOffset;
7078 
7079     // The destination is only one layer deep.
7080     size_t allocationSize = outputDepthPitch;
7081     ANGLE_TRY(currentBuffer->allocateForCopyImage(contextVk, allocationSize,
7082                                                   MemoryCoherency::NonCoherent, storageFormat.id,
7083                                                   &stagingOffset, &stagingPointer));
7084 
7085     const angle::Format &copyFormat =
7086         GetFormatFromFormatType(formatInfo.internalFormat, formatInfo.type);
7087     PackPixelsParams params(clippedRectangle, copyFormat, static_cast<GLuint>(outputRowPitch),
7088                             isViewportFlipEnabled, nullptr, 0);
7089 
7090     RenderTargetVk *readRenderTarget = framebufferVk->getColorReadRenderTarget();
7091 
7092     // 2- copy the source image region to the pixel buffer using a cpu readback
7093     if (loadFunction.requiresConversion)
7094     {
7095         // When a conversion is required, we need to use the loadFunction to read from a temporary
7096         // buffer instead so its an even slower path.
7097         size_t bufferSize =
7098             storageFormat.pixelBytes * clippedRectangle.width * clippedRectangle.height;
7099         angle::MemoryBuffer *memoryBuffer = nullptr;
7100         ANGLE_VK_CHECK_ALLOC(contextVk, context->getScratchBuffer(bufferSize, &memoryBuffer));
7101 
7102         // Read into the scratch buffer
7103         ANGLE_TRY(framebufferVk->readPixelsImpl(contextVk, clippedRectangle, params,
7104                                                 VK_IMAGE_ASPECT_COLOR_BIT, readRenderTarget,
7105                                                 memoryBuffer->data()));
7106 
7107         // Load from scratch buffer to our pixel buffer
7108         loadFunction.loadFunction(clippedRectangle.width, clippedRectangle.height, 1,
7109                                   memoryBuffer->data(), outputRowPitch, 0, stagingPointer,
7110                                   outputRowPitch, 0);
7111     }
7112     else
7113     {
7114         // We read directly from the framebuffer into our pixel buffer.
7115         ANGLE_TRY(framebufferVk->readPixelsImpl(contextVk, clippedRectangle, params,
7116                                                 VK_IMAGE_ASPECT_COLOR_BIT, readRenderTarget,
7117                                                 stagingPointer));
7118     }
7119 
7120     gl::LevelIndex updateLevelGL(index.getLevelIndex());
7121 
7122     // 3- enqueue the destination image subresource update
7123     VkBufferImageCopy copyToImage               = {};
7124     copyToImage.bufferOffset                    = static_cast<VkDeviceSize>(stagingOffset);
7125     copyToImage.bufferRowLength                 = 0;  // Tightly packed data can be specified as 0.
7126     copyToImage.bufferImageHeight               = clippedRectangle.height;
7127     copyToImage.imageSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
7128     copyToImage.imageSubresource.mipLevel       = updateLevelGL.get();
7129     copyToImage.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
7130     copyToImage.imageSubresource.layerCount     = index.getLayerCount();
7131     gl_vk::GetOffset(dstOffset, &copyToImage.imageOffset);
7132     gl_vk::GetExtent(dstExtent, &copyToImage.imageExtent);
7133 
7134     // 3- enqueue the destination image subresource update
7135     appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(stagingBuffer.release(), currentBuffer,
7136                                                              copyToImage, storageFormat.id));
7137 
7138     return angle::Result::Continue;
7139 }
7140 
stageSubresourceUpdateFromImage(RefCounted<ImageHelper> * image,const gl::ImageIndex & index,LevelIndex srcMipLevel,const gl::Offset & destOffset,const gl::Extents & glExtents,const VkImageType imageType)7141 void ImageHelper::stageSubresourceUpdateFromImage(RefCounted<ImageHelper> *image,
7142                                                   const gl::ImageIndex &index,
7143                                                   LevelIndex srcMipLevel,
7144                                                   const gl::Offset &destOffset,
7145                                                   const gl::Extents &glExtents,
7146                                                   const VkImageType imageType)
7147 {
7148     gl::LevelIndex updateLevelGL(index.getLevelIndex());
7149     VkImageAspectFlags imageAspectFlags = vk::GetFormatAspectFlags(image->get().getActualFormat());
7150 
7151     VkImageCopy copyToImage               = {};
7152     copyToImage.srcSubresource.aspectMask = imageAspectFlags;
7153     copyToImage.srcSubresource.mipLevel   = srcMipLevel.get();
7154     copyToImage.srcSubresource.layerCount = index.getLayerCount();
7155     copyToImage.dstSubresource.aspectMask = imageAspectFlags;
7156     copyToImage.dstSubresource.mipLevel   = updateLevelGL.get();
7157 
7158     if (imageType == VK_IMAGE_TYPE_3D)
7159     {
7160         // These values must be set explicitly to follow the Vulkan spec:
7161         // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkImageCopy.html
7162         // If either of the calling command's srcImage or dstImage parameters are of VkImageType
7163         // VK_IMAGE_TYPE_3D, the baseArrayLayer and layerCount members of the corresponding
7164         // subresource must be 0 and 1, respectively
7165         copyToImage.dstSubresource.baseArrayLayer = 0;
7166         copyToImage.dstSubresource.layerCount     = 1;
7167         // Preserve the assumption that destOffset.z == "dstSubresource.baseArrayLayer"
7168         ASSERT(destOffset.z == (index.hasLayer() ? index.getLayerIndex() : 0));
7169     }
7170     else
7171     {
7172         copyToImage.dstSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
7173         copyToImage.dstSubresource.layerCount     = index.getLayerCount();
7174     }
7175 
7176     gl_vk::GetOffset(destOffset, &copyToImage.dstOffset);
7177     gl_vk::GetExtent(glExtents, &copyToImage.extent);
7178 
7179     appendSubresourceUpdate(
7180         updateLevelGL, SubresourceUpdate(image, copyToImage, image->get().getActualFormatID()));
7181 }
7182 
stageSubresourceUpdatesFromAllImageLevels(RefCounted<ImageHelper> * image,gl::LevelIndex baseLevel)7183 void ImageHelper::stageSubresourceUpdatesFromAllImageLevels(RefCounted<ImageHelper> *image,
7184                                                             gl::LevelIndex baseLevel)
7185 {
7186     for (LevelIndex levelVk(0); levelVk < LevelIndex(image->get().getLevelCount()); ++levelVk)
7187     {
7188         const gl::LevelIndex levelGL = vk_gl::GetLevelIndex(levelVk, baseLevel);
7189         const gl::ImageIndex index =
7190             gl::ImageIndex::Make2DArrayRange(levelGL.get(), 0, image->get().getLayerCount());
7191 
7192         stageSubresourceUpdateFromImage(image, index, levelVk, gl::kOffsetZero,
7193                                         image->get().getLevelExtents(levelVk),
7194                                         image->get().getType());
7195     }
7196 }
7197 
stageClear(const gl::ImageIndex & index,VkImageAspectFlags aspectFlags,const VkClearValue & clearValue)7198 void ImageHelper::stageClear(const gl::ImageIndex &index,
7199                              VkImageAspectFlags aspectFlags,
7200                              const VkClearValue &clearValue)
7201 {
7202     gl::LevelIndex updateLevelGL(index.getLevelIndex());
7203     appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(aspectFlags, clearValue, index));
7204 }
7205 
stageRobustResourceClear(const gl::ImageIndex & index)7206 void ImageHelper::stageRobustResourceClear(const gl::ImageIndex &index)
7207 {
7208     const VkImageAspectFlags aspectFlags = getAspectFlags();
7209 
7210     ASSERT(mActualFormatID != angle::FormatID::NONE);
7211     VkClearValue clearValue = GetRobustResourceClearValue(getIntendedFormat(), getActualFormat());
7212 
7213     gl::LevelIndex updateLevelGL(index.getLevelIndex());
7214     appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(aspectFlags, clearValue, index));
7215 }
7216 
stageRobustResourceClearWithFormat(ContextVk * contextVk,const gl::ImageIndex & index,const gl::Extents & glExtents,const angle::Format & intendedFormat,const angle::Format & imageFormat)7217 angle::Result ImageHelper::stageRobustResourceClearWithFormat(ContextVk *contextVk,
7218                                                               const gl::ImageIndex &index,
7219                                                               const gl::Extents &glExtents,
7220                                                               const angle::Format &intendedFormat,
7221                                                               const angle::Format &imageFormat)
7222 {
7223     const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(imageFormat);
7224 
7225     // Robust clears must only be staged if we do not have any prior data for this subresource.
7226     ASSERT(!hasStagedUpdatesForSubresource(gl::LevelIndex(index.getLevelIndex()),
7227                                            index.getLayerIndex(), index.getLayerCount()));
7228 
7229     VkClearValue clearValue = GetRobustResourceClearValue(intendedFormat, imageFormat);
7230 
7231     gl::LevelIndex updateLevelGL(index.getLevelIndex());
7232 
7233     if (imageFormat.isBlock)
7234     {
7235         // This only supports doing an initial clear to 0, not clearing to a specific encoded RGBA
7236         // value
7237         ASSERT((clearValue.color.int32[0] == 0) && (clearValue.color.int32[1] == 0) &&
7238                (clearValue.color.int32[2] == 0) && (clearValue.color.int32[3] == 0));
7239 
7240         const gl::InternalFormat &formatInfo =
7241             gl::GetSizedInternalFormatInfo(imageFormat.glInternalFormat);
7242         GLuint totalSize;
7243         ANGLE_VK_CHECK_MATH(contextVk,
7244                             formatInfo.computeCompressedImageSize(glExtents, &totalSize));
7245 
7246         std::unique_ptr<RefCounted<BufferHelper>> stagingBuffer =
7247             std::make_unique<RefCounted<BufferHelper>>();
7248         BufferHelper *currentBuffer = &stagingBuffer->get();
7249 
7250         uint8_t *stagingPointer;
7251         VkDeviceSize stagingOffset;
7252         ANGLE_TRY(currentBuffer->allocateForCopyImage(contextVk, totalSize,
7253                                                       MemoryCoherency::NonCoherent, imageFormat.id,
7254                                                       &stagingOffset, &stagingPointer));
7255         memset(stagingPointer, 0, totalSize);
7256 
7257         VkBufferImageCopy copyRegion               = {};
7258         copyRegion.bufferOffset                    = stagingOffset;
7259         copyRegion.imageExtent.width               = glExtents.width;
7260         copyRegion.imageExtent.height              = glExtents.height;
7261         copyRegion.imageExtent.depth               = glExtents.depth;
7262         copyRegion.imageSubresource.mipLevel       = updateLevelGL.get();
7263         copyRegion.imageSubresource.aspectMask     = aspectFlags;
7264         copyRegion.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
7265         copyRegion.imageSubresource.layerCount     = index.getLayerCount();
7266 
7267         // The update structure owns the staging buffer.
7268         appendSubresourceUpdate(
7269             updateLevelGL,
7270             SubresourceUpdate(stagingBuffer.release(), currentBuffer, copyRegion, imageFormat.id));
7271     }
7272     else
7273     {
7274         appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(aspectFlags, clearValue, index));
7275     }
7276 
7277     return angle::Result::Continue;
7278 }
7279 
stageClearIfEmulatedFormat(bool isRobustResourceInitEnabled,bool isExternalImage)7280 void ImageHelper::stageClearIfEmulatedFormat(bool isRobustResourceInitEnabled, bool isExternalImage)
7281 {
7282     // Skip staging extra clears if robust resource init is enabled.
7283     if (!hasEmulatedImageChannels() || isRobustResourceInitEnabled)
7284     {
7285         return;
7286     }
7287 
7288     VkClearValue clearValue = {};
7289     if (getIntendedFormat().hasDepthOrStencilBits())
7290     {
7291         clearValue.depthStencil = kRobustInitDepthStencilValue;
7292     }
7293     else
7294     {
7295         clearValue.color = kEmulatedInitColorValue;
7296     }
7297 
7298     const VkImageAspectFlags aspectFlags = getAspectFlags();
7299 
7300     // If the image has an emulated channel and robust resource init is not enabled, always clear
7301     // it. These channels will be masked out in future writes, and shouldn't contain uninitialized
7302     // values.
7303     //
7304     // For external images, we cannot clear the image entirely, as it may contain data in the
7305     // non-emulated channels.  For depth/stencil images, clear is already per aspect, but for color
7306     // images we would need to take a special path where we only clear the emulated channels.
7307     const bool clearOnlyEmulatedChannels =
7308         isExternalImage && !getIntendedFormat().hasDepthOrStencilBits();
7309     const VkColorComponentFlags colorMaskFlags =
7310         clearOnlyEmulatedChannels ? getEmulatedChannelsMask() : 0;
7311 
7312     for (LevelIndex level(0); level < LevelIndex(mLevelCount); ++level)
7313     {
7314         gl::LevelIndex updateLevelGL = toGLLevel(level);
7315         gl::ImageIndex index =
7316             gl::ImageIndex::Make2DArrayRange(updateLevelGL.get(), 0, mLayerCount);
7317 
7318         if (clearOnlyEmulatedChannels)
7319         {
7320             prependSubresourceUpdate(updateLevelGL,
7321                                      SubresourceUpdate(colorMaskFlags, clearValue.color, index));
7322         }
7323         else
7324         {
7325             prependSubresourceUpdate(updateLevelGL,
7326                                      SubresourceUpdate(aspectFlags, clearValue, index));
7327         }
7328     }
7329 }
7330 
verifyEmulatedClearsAreBeforeOtherUpdates(const std::vector<SubresourceUpdate> & updates)7331 bool ImageHelper::verifyEmulatedClearsAreBeforeOtherUpdates(
7332     const std::vector<SubresourceUpdate> &updates)
7333 {
7334     bool isIteratingEmulatedClears = true;
7335 
7336     for (const SubresourceUpdate &update : updates)
7337     {
7338         // If anything other than ClearEmulatedChannelsOnly is visited, there cannot be any
7339         // ClearEmulatedChannelsOnly updates after that.
7340         if (update.updateSource != UpdateSource::ClearEmulatedChannelsOnly)
7341         {
7342             isIteratingEmulatedClears = false;
7343         }
7344         else if (!isIteratingEmulatedClears)
7345         {
7346             // If ClearEmulatedChannelsOnly is visited after another update, that's an error.
7347             return false;
7348         }
7349     }
7350 
7351     // Additionally, verify that emulated clear is not applied multiple times.
7352     if (updates.size() >= 2 && updates[1].updateSource == UpdateSource::ClearEmulatedChannelsOnly)
7353     {
7354         return false;
7355     }
7356 
7357     return true;
7358 }
7359 
stageSelfAsSubresourceUpdates(ContextVk * contextVk,uint32_t levelCount,gl::TexLevelMask skipLevelsMask)7360 void ImageHelper::stageSelfAsSubresourceUpdates(ContextVk *contextVk,
7361                                                 uint32_t levelCount,
7362                                                 gl::TexLevelMask skipLevelsMask)
7363 
7364 {
7365     // Nothing to do if every level must be skipped
7366     gl::TexLevelMask levelsMask(angle::BitMask<uint32_t>(levelCount) << mFirstAllocatedLevel.get());
7367     if ((~skipLevelsMask & levelsMask).none())
7368     {
7369         return;
7370     }
7371 
7372     // Because we are cloning this object to another object, we must finalize the layout if it is
7373     // being used by current renderpass as attachment. Otherwise we are copying the incorrect layout
7374     // since it is determined at endRenderPass time.
7375     contextVk->finalizeImageLayout(this);
7376 
7377     std::unique_ptr<RefCounted<ImageHelper>> prevImage =
7378         std::make_unique<RefCounted<ImageHelper>>();
7379 
7380     // Move the necessary information for staged update to work, and keep the rest as part of this
7381     // object.
7382 
7383     // Usage info
7384     prevImage->get().Resource::operator=(std::move(*this));
7385 
7386     // Vulkan objects
7387     prevImage->get().mImage        = std::move(mImage);
7388     prevImage->get().mDeviceMemory = std::move(mDeviceMemory);
7389 
7390     // Barrier information.  Note: mLevelCount is set to levelCount so that only the necessary
7391     // levels are transitioned when flushing the update.
7392     prevImage->get().mIntendedFormatID            = mIntendedFormatID;
7393     prevImage->get().mActualFormatID              = mActualFormatID;
7394     prevImage->get().mCurrentLayout               = mCurrentLayout;
7395     prevImage->get().mCurrentQueueFamilyIndex     = mCurrentQueueFamilyIndex;
7396     prevImage->get().mLastNonShaderReadOnlyLayout = mLastNonShaderReadOnlyLayout;
7397     prevImage->get().mCurrentShaderReadStageMask  = mCurrentShaderReadStageMask;
7398     prevImage->get().mLevelCount                  = levelCount;
7399     prevImage->get().mLayerCount                  = mLayerCount;
7400     prevImage->get().mImageSerial                 = mImageSerial;
7401     prevImage->get().mImageAndViewGarbage         = std::move(mImageAndViewGarbage);
7402 
7403     // Reset information for current (invalid) image.
7404     mCurrentLayout               = ImageLayout::Undefined;
7405     mCurrentQueueFamilyIndex     = std::numeric_limits<uint32_t>::max();
7406     mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
7407     mCurrentShaderReadStageMask  = 0;
7408     mImageSerial                 = kInvalidImageSerial;
7409 
7410     setEntireContentUndefined();
7411 
7412     // Stage updates from the previous image.
7413     for (LevelIndex levelVk(0); levelVk < LevelIndex(levelCount); ++levelVk)
7414     {
7415         gl::LevelIndex levelGL = toGLLevel(levelVk);
7416         if (skipLevelsMask.test(levelGL.get()))
7417         {
7418             continue;
7419         }
7420 
7421         const gl::ImageIndex index =
7422             gl::ImageIndex::Make2DArrayRange(levelGL.get(), 0, mLayerCount);
7423 
7424         stageSubresourceUpdateFromImage(prevImage.get(), index, levelVk, gl::kOffsetZero,
7425                                         getLevelExtents(levelVk), mImageType);
7426     }
7427 
7428     ASSERT(levelCount > 0);
7429     prevImage.release();
7430 }
7431 
flushSingleSubresourceStagedUpdates(ContextVk * contextVk,gl::LevelIndex levelGL,uint32_t layer,uint32_t layerCount,ClearValuesArray * deferredClears,uint32_t deferredClearIndex)7432 angle::Result ImageHelper::flushSingleSubresourceStagedUpdates(ContextVk *contextVk,
7433                                                                gl::LevelIndex levelGL,
7434                                                                uint32_t layer,
7435                                                                uint32_t layerCount,
7436                                                                ClearValuesArray *deferredClears,
7437                                                                uint32_t deferredClearIndex)
7438 {
7439     std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(levelGL);
7440     if (levelUpdates == nullptr || levelUpdates->empty())
7441     {
7442         return angle::Result::Continue;
7443     }
7444 
7445     LevelIndex levelVk = toVkLevel(levelGL);
7446 
7447     // Handle deferred clears. Search the updates list for a matching clear index.
7448     if (deferredClears)
7449     {
7450         Optional<size_t> foundClear;
7451 
7452         for (size_t updateIndex = 0; updateIndex < levelUpdates->size(); ++updateIndex)
7453         {
7454             SubresourceUpdate &update = (*levelUpdates)[updateIndex];
7455 
7456             if (update.isUpdateToLayers(layer, layerCount))
7457             {
7458                 // On any data update, exit out. We'll need to do a full upload.
7459                 const bool isClear              = IsClearOfAllChannels(update.updateSource);
7460                 const uint32_t updateLayerCount = isClear ? update.data.clear.layerCount : 0;
7461                 const uint32_t imageLayerCount =
7462                     mImageType == VK_IMAGE_TYPE_3D ? getLevelExtents(levelVk).depth : mLayerCount;
7463 
7464                 if (!isClear || (updateLayerCount != layerCount &&
7465                                  !(update.data.clear.layerCount == VK_REMAINING_ARRAY_LAYERS &&
7466                                    imageLayerCount == layerCount)))
7467                 {
7468                     foundClear.reset();
7469                     break;
7470                 }
7471 
7472                 // Otherwise track the latest clear update index.
7473                 foundClear = updateIndex;
7474             }
7475         }
7476 
7477         // If we have a valid index we defer the clear using the clear reference.
7478         if (foundClear.valid())
7479         {
7480             size_t foundIndex         = foundClear.value();
7481             const ClearUpdate &update = (*levelUpdates)[foundIndex].data.clear;
7482 
7483             // Note that this set command handles combined or separate depth/stencil clears.
7484             deferredClears->store(deferredClearIndex, update.aspectFlags, update.value);
7485 
7486             // Do not call onWrite as it removes mCurrentSingleClearValue, but instead call
7487             // setContentDefined directly.
7488             setContentDefined(toVkLevel(levelGL), 1, layer, layerCount, update.aspectFlags);
7489 
7490             // We process the updates again to erase any clears for this level.
7491             removeSingleSubresourceStagedUpdates(contextVk, levelGL, layer, layerCount);
7492             return angle::Result::Continue;
7493         }
7494 
7495         // Otherwise we proceed with a normal update.
7496     }
7497 
7498     return flushStagedUpdates(contextVk, levelGL, levelGL + 1, layer, layer + layerCount, {});
7499 }
7500 
flushStagedUpdates(ContextVk * contextVk,gl::LevelIndex levelGLStart,gl::LevelIndex levelGLEnd,uint32_t layerStart,uint32_t layerEnd,gl::TexLevelMask skipLevelsMask)7501 angle::Result ImageHelper::flushStagedUpdates(ContextVk *contextVk,
7502                                               gl::LevelIndex levelGLStart,
7503                                               gl::LevelIndex levelGLEnd,
7504                                               uint32_t layerStart,
7505                                               uint32_t layerEnd,
7506                                               gl::TexLevelMask skipLevelsMask)
7507 {
7508     RendererVk *renderer = contextVk->getRenderer();
7509 
7510     if (!hasStagedUpdatesInLevels(levelGLStart, levelGLEnd))
7511     {
7512         return angle::Result::Continue;
7513     }
7514 
7515     removeSupersededUpdates(contextVk, skipLevelsMask);
7516 
7517     // If a clear is requested and we know it was previously cleared with the same value, we drop
7518     // the clear.
7519     if (mCurrentSingleClearValue.valid())
7520     {
7521         std::vector<SubresourceUpdate> *levelUpdates =
7522             getLevelUpdates(gl::LevelIndex(mCurrentSingleClearValue.value().levelIndex));
7523         if (levelUpdates && levelUpdates->size() == 1)
7524         {
7525             SubresourceUpdate &update = (*levelUpdates)[0];
7526             if (IsClearOfAllChannels(update.updateSource) &&
7527                 mCurrentSingleClearValue.value() == update.data.clear)
7528             {
7529                 ASSERT(levelGLStart + 1 == levelGLEnd);
7530                 setContentDefined(toVkLevel(levelGLStart), 1, layerStart, layerEnd - layerStart,
7531                                   update.data.clear.aspectFlags);
7532                 ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_LOW,
7533                                       "Repeated Clear on framebuffer attachment dropped");
7534                 update.release(contextVk->getRenderer());
7535                 levelUpdates->clear();
7536                 return angle::Result::Continue;
7537             }
7538         }
7539     }
7540 
7541     ASSERT(validateSubresourceUpdateRefCountsConsistent());
7542 
7543     const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(getActualFormat());
7544 
7545     // For each level, upload layers that don't conflict in parallel.  The layer is hashed to
7546     // `layer % 64` and used to track whether that subresource is currently in transfer.  If so, a
7547     // barrier is inserted.  If mLayerCount > 64, there will be a few unnecessary barriers.
7548     //
7549     // Note: when a barrier is necessary when uploading updates to a level, we could instead move to
7550     // the next level and continue uploads in parallel.  Once all levels need a barrier, a single
7551     // barrier can be issued and we could continue with the rest of the updates from the first
7552     // level.
7553     constexpr uint32_t kMaxParallelSubresourceUpload = 64;
7554 
7555     // Start in TransferDst.  Don't yet mark any subresource as having defined contents; that is
7556     // done with fine granularity as updates are applied.  This is achieved by specifying a layer
7557     // that is outside the tracking range.
7558     CommandBufferAccess access;
7559     access.onImageTransferWrite(levelGLStart, 1, kMaxContentDefinedLayerCount, 0, aspectFlags,
7560                                 this);
7561 
7562     OutsideRenderPassCommandBuffer *commandBuffer;
7563     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
7564 
7565     for (gl::LevelIndex updateMipLevelGL = levelGLStart; updateMipLevelGL < levelGLEnd;
7566          ++updateMipLevelGL)
7567     {
7568         std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(updateMipLevelGL);
7569         if (levelUpdates == nullptr)
7570         {
7571             ASSERT(static_cast<size_t>(updateMipLevelGL.get()) >= mSubresourceUpdates.size());
7572             break;
7573         }
7574 
7575         std::vector<SubresourceUpdate> updatesToKeep;
7576 
7577         // Hash map of uploads in progress.  See comment on kMaxParallelSubresourceUpload.
7578         uint64_t subresourceUploadsInProgress = 0;
7579 
7580         for (SubresourceUpdate &update : *levelUpdates)
7581         {
7582             ASSERT(IsClear(update.updateSource) ||
7583                    (update.updateSource == UpdateSource::Buffer &&
7584                     update.data.buffer.bufferHelper != nullptr) ||
7585                    (update.updateSource == UpdateSource::Image &&
7586                     update.refCounted.image != nullptr && update.refCounted.image->isReferenced() &&
7587                     update.refCounted.image->get().valid()));
7588 
7589             uint32_t updateBaseLayer, updateLayerCount;
7590             update.getDestSubresource(mLayerCount, &updateBaseLayer, &updateLayerCount);
7591 
7592             // If the update layers don't intersect the requested layers, skip the update.
7593             const bool areUpdateLayersOutsideRange =
7594                 updateBaseLayer + updateLayerCount <= layerStart || updateBaseLayer >= layerEnd;
7595 
7596             const LevelIndex updateMipLevelVk = toVkLevel(updateMipLevelGL);
7597 
7598             // Additionally, if updates to this level are specifically asked to be skipped, skip
7599             // them. This can happen when recreating an image that has been partially incompatibly
7600             // redefined, in which case only updates to the levels that haven't been redefined
7601             // should be flushed.
7602             if (areUpdateLayersOutsideRange || skipLevelsMask.test(updateMipLevelGL.get()))
7603             {
7604                 updatesToKeep.emplace_back(std::move(update));
7605                 continue;
7606             }
7607 
7608             // The updates were holding gl::LevelIndex values so that they would not need
7609             // modification when the base level of the texture changes.  Now that the update is
7610             // about to take effect, we need to change miplevel to LevelIndex.
7611             if (IsClear(update.updateSource))
7612             {
7613                 update.data.clear.levelIndex = updateMipLevelVk.get();
7614             }
7615             else if (update.updateSource == UpdateSource::Buffer)
7616             {
7617                 if (update.data.buffer.formatID != mActualFormatID)
7618                 {
7619                     // TODD: http://anglebug.com/6368, we should handle this in higher level code.
7620                     // If we have incompatible updates, skip but keep it.
7621                     updatesToKeep.emplace_back(std::move(update));
7622                     continue;
7623                 }
7624                 update.data.buffer.copyRegion.imageSubresource.mipLevel = updateMipLevelVk.get();
7625             }
7626             else if (update.updateSource == UpdateSource::Image)
7627             {
7628                 if (update.data.image.formatID != mActualFormatID)
7629                 {
7630                     // If we have incompatible updates, skip but keep it.
7631                     updatesToKeep.emplace_back(std::move(update));
7632                     continue;
7633                 }
7634                 update.data.image.copyRegion.dstSubresource.mipLevel = updateMipLevelVk.get();
7635             }
7636 
7637             if (updateLayerCount >= kMaxParallelSubresourceUpload)
7638             {
7639                 // If there are more subresources than bits we can track, always insert a barrier.
7640                 recordWriteBarrier(contextVk, aspectFlags, ImageLayout::TransferDst, commandBuffer);
7641                 subresourceUploadsInProgress = std::numeric_limits<uint64_t>::max();
7642             }
7643             else
7644             {
7645                 const uint64_t subresourceHashRange = angle::BitMask<uint64_t>(updateLayerCount);
7646                 const uint32_t subresourceHashOffset =
7647                     updateBaseLayer % kMaxParallelSubresourceUpload;
7648                 const uint64_t subresourceHash =
7649                     ANGLE_ROTL64(subresourceHashRange, subresourceHashOffset);
7650 
7651                 if ((subresourceUploadsInProgress & subresourceHash) != 0)
7652                 {
7653                     // If there's overlap in subresource upload, issue a barrier.
7654                     recordWriteBarrier(contextVk, aspectFlags, ImageLayout::TransferDst,
7655                                        commandBuffer);
7656                     subresourceUploadsInProgress = 0;
7657                 }
7658                 subresourceUploadsInProgress |= subresourceHash;
7659             }
7660 
7661             if (IsClearOfAllChannels(update.updateSource))
7662             {
7663                 clear(update.data.clear.aspectFlags, update.data.clear.value, updateMipLevelVk,
7664                       updateBaseLayer, updateLayerCount, commandBuffer);
7665                 // Remember the latest operation is a clear call
7666                 mCurrentSingleClearValue = update.data.clear;
7667 
7668                 // Do not call onWrite as it removes mCurrentSingleClearValue, but instead call
7669                 // setContentDefined directly.
7670                 setContentDefined(updateMipLevelVk, 1, updateBaseLayer, updateLayerCount,
7671                                   update.data.clear.aspectFlags);
7672             }
7673             else if (update.updateSource == UpdateSource::ClearEmulatedChannelsOnly)
7674             {
7675                 ANGLE_TRY(clearEmulatedChannels(contextVk, update.data.clear.colorMaskFlags,
7676                                                 update.data.clear.value, updateMipLevelVk,
7677                                                 updateBaseLayer, updateLayerCount));
7678 
7679                 // Do not call onWrite.  Even though some channels of the image are cleared, don't
7680                 // consider the contents defined.  Also, since clearing emulated channels is a
7681                 // one-time thing that's superseded by Clears, |mCurrentSingleClearValue| is
7682                 // irrelevant and can't have a value.
7683                 ASSERT(!mCurrentSingleClearValue.valid());
7684 
7685                 // Refresh the command buffer because clearEmulatedChannels may have flushed it.
7686                 // This also transitions the image back to TransferDst, in case it's no longer in
7687                 // that layout.
7688                 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
7689             }
7690             else if (update.updateSource == UpdateSource::Buffer)
7691             {
7692                 BufferUpdate &bufferUpdate = update.data.buffer;
7693 
7694                 BufferHelper *currentBuffer = bufferUpdate.bufferHelper;
7695                 ASSERT(currentBuffer && currentBuffer->valid());
7696                 ANGLE_TRY(currentBuffer->flush(renderer));
7697 
7698                 CommandBufferAccess bufferAccess;
7699                 bufferAccess.onBufferTransferRead(currentBuffer);
7700                 ANGLE_TRY(
7701                     contextVk->getOutsideRenderPassCommandBuffer(bufferAccess, &commandBuffer));
7702 
7703                 VkBufferImageCopy *copyRegion = &update.data.buffer.copyRegion;
7704                 commandBuffer->copyBufferToImage(currentBuffer->getBuffer().getHandle(), mImage,
7705                                                  getCurrentLayout(), 1, copyRegion);
7706                 ANGLE_TRY(contextVk->onCopyUpdate(currentBuffer->getSize()));
7707                 onWrite(updateMipLevelGL, 1, updateBaseLayer, updateLayerCount,
7708                         copyRegion->imageSubresource.aspectMask);
7709             }
7710             else
7711             {
7712                 ASSERT(update.updateSource == UpdateSource::Image);
7713                 CommandBufferAccess imageAccess;
7714                 imageAccess.onImageTransferRead(aspectFlags, &update.refCounted.image->get());
7715                 ANGLE_TRY(
7716                     contextVk->getOutsideRenderPassCommandBuffer(imageAccess, &commandBuffer));
7717 
7718                 VkImageCopy *copyRegion = &update.data.image.copyRegion;
7719                 commandBuffer->copyImage(update.refCounted.image->get().getImage(),
7720                                          update.refCounted.image->get().getCurrentLayout(), mImage,
7721                                          getCurrentLayout(), 1, copyRegion);
7722                 onWrite(updateMipLevelGL, 1, updateBaseLayer, updateLayerCount,
7723                         copyRegion->dstSubresource.aspectMask);
7724             }
7725 
7726             update.release(contextVk->getRenderer());
7727         }
7728 
7729         // Only remove the updates that were actually applied to the image.
7730         *levelUpdates = std::move(updatesToKeep);
7731     }
7732 
7733     // Compact mSubresourceUpdates, then check if there are any updates left.
7734     size_t compactSize;
7735     for (compactSize = mSubresourceUpdates.size(); compactSize > 0; --compactSize)
7736     {
7737         if (!mSubresourceUpdates[compactSize - 1].empty())
7738         {
7739             break;
7740         }
7741     }
7742     mSubresourceUpdates.resize(compactSize);
7743 
7744     ASSERT(validateSubresourceUpdateRefCountsConsistent());
7745 
7746     // If no updates left, release the staging buffers to save memory.
7747     if (mSubresourceUpdates.empty())
7748     {
7749         onStateChange(angle::SubjectMessage::InitializationComplete);
7750     }
7751 
7752     return angle::Result::Continue;
7753 }
7754 
flushAllStagedUpdates(ContextVk * contextVk)7755 angle::Result ImageHelper::flushAllStagedUpdates(ContextVk *contextVk)
7756 {
7757     return flushStagedUpdates(contextVk, mFirstAllocatedLevel, mFirstAllocatedLevel + mLevelCount,
7758                               0, mLayerCount, {});
7759 }
7760 
hasStagedUpdatesForSubresource(gl::LevelIndex levelGL,uint32_t layer,uint32_t layerCount) const7761 bool ImageHelper::hasStagedUpdatesForSubresource(gl::LevelIndex levelGL,
7762                                                  uint32_t layer,
7763                                                  uint32_t layerCount) const
7764 {
7765     // Check to see if any updates are staged for the given level and layer
7766 
7767     const std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(levelGL);
7768     if (levelUpdates == nullptr || levelUpdates->empty())
7769     {
7770         return false;
7771     }
7772 
7773     for (const SubresourceUpdate &update : *levelUpdates)
7774     {
7775         uint32_t updateBaseLayer, updateLayerCount;
7776         update.getDestSubresource(mLayerCount, &updateBaseLayer, &updateLayerCount);
7777 
7778         const uint32_t updateLayerEnd = updateBaseLayer + updateLayerCount;
7779         const uint32_t layerEnd       = layer + layerCount;
7780 
7781         if ((layer >= updateBaseLayer && layer < updateLayerEnd) ||
7782             (layerEnd > updateBaseLayer && layerEnd <= updateLayerEnd))
7783         {
7784             // The layers intersect with the update range
7785             return true;
7786         }
7787     }
7788 
7789     return false;
7790 }
7791 
removeStagedClearUpdatesAndReturnColor(gl::LevelIndex levelGL,const VkClearColorValue ** color)7792 bool ImageHelper::removeStagedClearUpdatesAndReturnColor(gl::LevelIndex levelGL,
7793                                                          const VkClearColorValue **color)
7794 {
7795     std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(levelGL);
7796     if (levelUpdates == nullptr || levelUpdates->empty())
7797     {
7798         return false;
7799     }
7800 
7801     bool result = false;
7802 
7803     for (size_t index = 0; index < levelUpdates->size();)
7804     {
7805         auto update = levelUpdates->begin() + index;
7806         if (IsClearOfAllChannels(update->updateSource))
7807         {
7808             if (color != nullptr)
7809             {
7810                 *color = &update->data.clear.value.color;
7811             }
7812             levelUpdates->erase(update);
7813             result = true;
7814         }
7815     }
7816 
7817     return result;
7818 }
7819 
getLastAllocatedLevel() const7820 gl::LevelIndex ImageHelper::getLastAllocatedLevel() const
7821 {
7822     return mFirstAllocatedLevel + mLevelCount - 1;
7823 }
7824 
hasStagedUpdatesInAllocatedLevels() const7825 bool ImageHelper::hasStagedUpdatesInAllocatedLevels() const
7826 {
7827     return hasStagedUpdatesInLevels(mFirstAllocatedLevel, getLastAllocatedLevel() + 1);
7828 }
7829 
hasStagedUpdatesInLevels(gl::LevelIndex levelStart,gl::LevelIndex levelEnd) const7830 bool ImageHelper::hasStagedUpdatesInLevels(gl::LevelIndex levelStart, gl::LevelIndex levelEnd) const
7831 {
7832     for (gl::LevelIndex level = levelStart; level < levelEnd; ++level)
7833     {
7834         const std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(level);
7835         if (levelUpdates == nullptr)
7836         {
7837             ASSERT(static_cast<size_t>(level.get()) >= mSubresourceUpdates.size());
7838             return false;
7839         }
7840 
7841         if (!levelUpdates->empty())
7842         {
7843             return true;
7844         }
7845     }
7846     return false;
7847 }
7848 
hasStagedImageUpdatesWithMismatchedFormat(gl::LevelIndex levelStart,gl::LevelIndex levelEnd,angle::FormatID formatID) const7849 bool ImageHelper::hasStagedImageUpdatesWithMismatchedFormat(gl::LevelIndex levelStart,
7850                                                             gl::LevelIndex levelEnd,
7851                                                             angle::FormatID formatID) const
7852 {
7853     for (gl::LevelIndex level = levelStart; level < levelEnd; ++level)
7854     {
7855         const std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(level);
7856         if (levelUpdates == nullptr)
7857         {
7858             continue;
7859         }
7860 
7861         for (const SubresourceUpdate &update : *levelUpdates)
7862         {
7863             if (update.updateSource == UpdateSource::Image &&
7864                 update.data.image.formatID != formatID)
7865             {
7866                 return true;
7867             }
7868         }
7869     }
7870     return false;
7871 }
7872 
validateSubresourceUpdateBufferRefConsistent(RefCounted<BufferHelper> * buffer) const7873 bool ImageHelper::validateSubresourceUpdateBufferRefConsistent(
7874     RefCounted<BufferHelper> *buffer) const
7875 {
7876     if (buffer == nullptr)
7877     {
7878         return true;
7879     }
7880 
7881     uint32_t refs = 0;
7882 
7883     for (const std::vector<SubresourceUpdate> &levelUpdates : mSubresourceUpdates)
7884     {
7885         for (const SubresourceUpdate &update : levelUpdates)
7886         {
7887             if (update.updateSource == UpdateSource::Buffer && update.refCounted.buffer == buffer)
7888             {
7889                 ++refs;
7890             }
7891         }
7892     }
7893 
7894     return buffer->isRefCountAsExpected(refs);
7895 }
7896 
validateSubresourceUpdateImageRefConsistent(RefCounted<ImageHelper> * image) const7897 bool ImageHelper::validateSubresourceUpdateImageRefConsistent(RefCounted<ImageHelper> *image) const
7898 {
7899     if (image == nullptr)
7900     {
7901         return true;
7902     }
7903 
7904     uint32_t refs = 0;
7905 
7906     for (const std::vector<SubresourceUpdate> &levelUpdates : mSubresourceUpdates)
7907     {
7908         for (const SubresourceUpdate &update : levelUpdates)
7909         {
7910             if (update.updateSource == UpdateSource::Image && update.refCounted.image == image)
7911             {
7912                 ++refs;
7913             }
7914         }
7915     }
7916 
7917     return image->isRefCountAsExpected(refs);
7918 }
7919 
validateSubresourceUpdateRefCountsConsistent() const7920 bool ImageHelper::validateSubresourceUpdateRefCountsConsistent() const
7921 {
7922     for (const std::vector<SubresourceUpdate> &levelUpdates : mSubresourceUpdates)
7923     {
7924         for (const SubresourceUpdate &update : levelUpdates)
7925         {
7926             if (update.updateSource == UpdateSource::Image)
7927             {
7928                 if (!validateSubresourceUpdateImageRefConsistent(update.refCounted.image))
7929                 {
7930                     return false;
7931                 }
7932             }
7933             else if (update.updateSource == UpdateSource::Buffer)
7934             {
7935                 if (!validateSubresourceUpdateBufferRefConsistent(update.refCounted.buffer))
7936                 {
7937                     return false;
7938                 }
7939             }
7940         }
7941     }
7942 
7943     return true;
7944 }
7945 
removeSupersededUpdates(ContextVk * contextVk,gl::TexLevelMask skipLevelsMask)7946 void ImageHelper::removeSupersededUpdates(ContextVk *contextVk, gl::TexLevelMask skipLevelsMask)
7947 {
7948     if (mLayerCount > 64)
7949     {
7950         // Not implemented for images with more than 64 layers.  A 64-bit mask is used for
7951         // efficiency, hence the limit.
7952         return;
7953     }
7954 
7955     ASSERT(validateSubresourceUpdateRefCountsConsistent());
7956 
7957     RendererVk *renderer = contextVk->getRenderer();
7958 
7959     // Go over updates in reverse order, and mark the layers they completely overwrite.  If an
7960     // update is encountered whose layers are all already marked, that update is superseded by
7961     // future updates, so it can be dropped.  This tracking is done per level.  If the aspect being
7962     // written to is color/depth or stencil, index 0 or 1 is used respectively.  This is so
7963     // that if a depth write for example covers the whole subresource, a stencil write to that same
7964     // subresource is not dropped.
7965     constexpr size_t kIndexColorOrDepth = 0;
7966     constexpr size_t kIndexStencil      = 1;
7967     uint64_t supersededLayers[2]        = {};
7968 
7969     gl::Extents levelExtents = {};
7970 
7971     // Note: this lambda only needs |this|, but = is specified because clang warns about kIndex* not
7972     // needing capture, while MSVC fails to compile without capturing them.
7973     auto markLayersAndDropSuperseded = [=, &supersededLayers,
7974                                         &levelExtents](SubresourceUpdate &update) {
7975         uint32_t updateBaseLayer, updateLayerCount;
7976         update.getDestSubresource(mLayerCount, &updateBaseLayer, &updateLayerCount);
7977 
7978         const VkImageAspectFlags aspectMask = update.getDestAspectFlags();
7979         const bool hasColorOrDepth =
7980             (aspectMask & (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_PLANE_0_BIT |
7981                            VK_IMAGE_ASPECT_PLANE_1_BIT | VK_IMAGE_ASPECT_PLANE_2_BIT |
7982                            VK_IMAGE_ASPECT_DEPTH_BIT)) != 0;
7983         const bool hasStencil = (aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0;
7984 
7985         // Test if the update is to layers that are all superseded.  In that case, drop the update.
7986         ASSERT(updateLayerCount <= 64);
7987         uint64_t updateLayersMask = updateLayerCount >= 64
7988                                         ? ~static_cast<uint64_t>(0)
7989                                         : angle::BitMask<uint64_t>(updateLayerCount);
7990         updateLayersMask <<= updateBaseLayer;
7991 
7992         const bool isColorOrDepthSuperseded =
7993             !hasColorOrDepth ||
7994             (supersededLayers[kIndexColorOrDepth] & updateLayersMask) == updateLayersMask;
7995         const bool isStencilSuperseded =
7996             !hasStencil || (supersededLayers[kIndexStencil] & updateLayersMask) == updateLayersMask;
7997 
7998         if (isColorOrDepthSuperseded && isStencilSuperseded)
7999         {
8000             ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_LOW,
8001                                   "Dropped image update that is superseded by an overlapping one");
8002 
8003             update.release(renderer);
8004             return true;
8005         }
8006 
8007         // Get the area this update affects.  Note that clear updates always clear the whole
8008         // subresource.
8009         gl::Box updateBox(gl::kOffsetZero, levelExtents);
8010 
8011         if (update.updateSource == UpdateSource::Buffer)
8012         {
8013             updateBox = gl::Box(update.data.buffer.copyRegion.imageOffset,
8014                                 update.data.buffer.copyRegion.imageExtent);
8015         }
8016         else if (update.updateSource == UpdateSource::Image)
8017         {
8018             updateBox = gl::Box(update.data.image.copyRegion.dstOffset,
8019                                 update.data.image.copyRegion.extent);
8020         }
8021 
8022         // Only if the update is to the whole subresource, mark its layers.
8023         if (updateBox.coversSameExtent(levelExtents))
8024         {
8025             if (hasColorOrDepth)
8026             {
8027                 supersededLayers[kIndexColorOrDepth] |= updateLayersMask;
8028             }
8029             if (hasStencil)
8030             {
8031                 supersededLayers[kIndexStencil] |= updateLayersMask;
8032             }
8033         }
8034 
8035         return false;
8036     };
8037 
8038     for (LevelIndex levelVk(0); levelVk < LevelIndex(mLevelCount); ++levelVk)
8039     {
8040         gl::LevelIndex levelGL                       = toGLLevel(levelVk);
8041         std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(levelGL);
8042         if (levelUpdates == nullptr)
8043         {
8044             ASSERT(static_cast<size_t>(levelGL.get()) >= mSubresourceUpdates.size());
8045             break;
8046         }
8047 
8048         // If level is skipped (because incompatibly redefined), don't remove any of its updates.
8049         if (skipLevelsMask.test(levelGL.get()))
8050         {
8051             continue;
8052         }
8053 
8054         // ClearEmulatedChannelsOnly updates can only be in the beginning of the list of updates.
8055         // They don't entirely clear the image, so they cannot supersede any update.
8056         ASSERT(verifyEmulatedClearsAreBeforeOtherUpdates(*levelUpdates));
8057 
8058         levelExtents                         = getLevelExtents(levelVk);
8059         supersededLayers[kIndexColorOrDepth] = 0;
8060         supersededLayers[kIndexStencil]      = 0;
8061 
8062         levelUpdates->erase(levelUpdates->rend().base(),
8063                             std::remove_if(levelUpdates->rbegin(), levelUpdates->rend(),
8064                                            markLayersAndDropSuperseded)
8065                                 .base());
8066     }
8067 
8068     ASSERT(validateSubresourceUpdateRefCountsConsistent());
8069 }
8070 
copyImageDataToBuffer(ContextVk * contextVk,gl::LevelIndex sourceLevelGL,uint32_t layerCount,uint32_t baseLayer,const gl::Box & sourceArea,BufferHelper * dstBuffer,uint8_t ** outDataPtr)8071 angle::Result ImageHelper::copyImageDataToBuffer(ContextVk *contextVk,
8072                                                  gl::LevelIndex sourceLevelGL,
8073                                                  uint32_t layerCount,
8074                                                  uint32_t baseLayer,
8075                                                  const gl::Box &sourceArea,
8076                                                  BufferHelper *dstBuffer,
8077                                                  uint8_t **outDataPtr)
8078 {
8079     ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::copyImageDataToBuffer");
8080 
8081     const angle::Format &imageFormat = getActualFormat();
8082 
8083     // Two VK formats (one depth-only, one combined depth/stencil) use an extra byte for depth.
8084     // From https://www.khronos.org/registry/vulkan/specs/1.1/html/vkspec.html#VkBufferImageCopy:
8085     //  data copied to or from the depth aspect of a VK_FORMAT_X8_D24_UNORM_PACK32 or
8086     //  VK_FORMAT_D24_UNORM_S8_UINT format is packed with one 32-bit word per texel...
8087     // So make sure if we hit the depth/stencil format that we have 5 bytes per pixel (4 for depth
8088     //  data, 1 for stencil). NOTE that depth-only VK_FORMAT_X8_D24_UNORM_PACK32 already has 4 bytes
8089     //  per pixel which is sufficient to contain its depth aspect (no stencil aspect).
8090     uint32_t pixelBytes         = imageFormat.pixelBytes;
8091     uint32_t depthBytesPerPixel = imageFormat.depthBits >> 3;
8092     if (getActualVkFormat() == VK_FORMAT_D24_UNORM_S8_UINT)
8093     {
8094         pixelBytes         = 5;
8095         depthBytesPerPixel = 4;
8096     }
8097 
8098     size_t bufferSize =
8099         sourceArea.width * sourceArea.height * sourceArea.depth * pixelBytes * layerCount;
8100 
8101     const VkImageAspectFlags aspectFlags = getAspectFlags();
8102 
8103     // Allocate coherent staging buffer
8104     ASSERT(dstBuffer != nullptr && !dstBuffer->valid());
8105     VkDeviceSize dstOffset;
8106     ANGLE_TRY(dstBuffer->allocateForCopyImage(contextVk, bufferSize, MemoryCoherency::Coherent,
8107                                               imageFormat.id, &dstOffset, outDataPtr));
8108     VkBuffer bufferHandle = dstBuffer->getBuffer().getHandle();
8109 
8110     LevelIndex sourceLevelVk = toVkLevel(sourceLevelGL);
8111 
8112     VkBufferImageCopy regions[2] = {};
8113     uint32_t regionCount         = 1;
8114     // Default to non-combined DS case
8115     regions[0].bufferOffset                    = dstOffset;
8116     regions[0].bufferRowLength                 = 0;
8117     regions[0].bufferImageHeight               = 0;
8118     regions[0].imageExtent.width               = sourceArea.width;
8119     regions[0].imageExtent.height              = sourceArea.height;
8120     regions[0].imageExtent.depth               = sourceArea.depth;
8121     regions[0].imageOffset.x                   = sourceArea.x;
8122     regions[0].imageOffset.y                   = sourceArea.y;
8123     regions[0].imageOffset.z                   = sourceArea.z;
8124     regions[0].imageSubresource.aspectMask     = aspectFlags;
8125     regions[0].imageSubresource.baseArrayLayer = baseLayer;
8126     regions[0].imageSubresource.layerCount     = layerCount;
8127     regions[0].imageSubresource.mipLevel       = sourceLevelVk.get();
8128 
8129     if (isCombinedDepthStencilFormat())
8130     {
8131         // For combined DS image we'll copy depth and stencil aspects separately
8132         // Depth aspect comes first in buffer and can use most settings from above
8133         regions[0].imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
8134 
8135         // Get depth data size since stencil data immediately follows depth data in buffer
8136         const VkDeviceSize depthSize = depthBytesPerPixel * sourceArea.width * sourceArea.height *
8137                                        sourceArea.depth * layerCount;
8138 
8139         // Double-check that we allocated enough buffer space (always 1 byte per stencil)
8140         ASSERT(bufferSize >= (depthSize + (sourceArea.width * sourceArea.height * sourceArea.depth *
8141                                            layerCount)));
8142 
8143         // Copy stencil data into buffer immediately following the depth data
8144         const VkDeviceSize stencilOffset       = dstOffset + depthSize;
8145         regions[1]                             = regions[0];
8146         regions[1].bufferOffset                = stencilOffset;
8147         regions[1].imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
8148         regionCount++;
8149     }
8150 
8151     CommandBufferAccess access;
8152     access.onBufferTransferWrite(dstBuffer);
8153     access.onImageTransferRead(aspectFlags, this);
8154 
8155     OutsideRenderPassCommandBuffer *commandBuffer;
8156     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
8157 
8158     commandBuffer->copyImageToBuffer(mImage, getCurrentLayout(), bufferHandle, regionCount,
8159                                      regions);
8160 
8161     return angle::Result::Continue;
8162 }
8163 
copySurfaceImageToBuffer(DisplayVk * displayVk,gl::LevelIndex sourceLevelGL,uint32_t layerCount,uint32_t baseLayer,const gl::Box & sourceArea,vk::BufferHelper * bufferHelper)8164 angle::Result ImageHelper::copySurfaceImageToBuffer(DisplayVk *displayVk,
8165                                                     gl::LevelIndex sourceLevelGL,
8166                                                     uint32_t layerCount,
8167                                                     uint32_t baseLayer,
8168                                                     const gl::Box &sourceArea,
8169                                                     vk::BufferHelper *bufferHelper)
8170 {
8171     ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::copySurfaceImageToBuffer");
8172 
8173     RendererVk *rendererVk = displayVk->getRenderer();
8174 
8175     VkBufferImageCopy region               = {};
8176     region.bufferOffset                    = 0;
8177     region.bufferRowLength                 = 0;
8178     region.bufferImageHeight               = 0;
8179     region.imageExtent.width               = sourceArea.width;
8180     region.imageExtent.height              = sourceArea.height;
8181     region.imageExtent.depth               = sourceArea.depth;
8182     region.imageOffset.x                   = sourceArea.x;
8183     region.imageOffset.y                   = sourceArea.y;
8184     region.imageOffset.z                   = sourceArea.z;
8185     region.imageSubresource.aspectMask     = getAspectFlags();
8186     region.imageSubresource.baseArrayLayer = baseLayer;
8187     region.imageSubresource.layerCount     = layerCount;
8188     region.imageSubresource.mipLevel       = toVkLevel(sourceLevelGL).get();
8189 
8190     PrimaryCommandBuffer primaryCommandBuffer;
8191     ANGLE_TRY(rendererVk->getCommandBufferOneOff(displayVk, false, &primaryCommandBuffer));
8192 
8193     barrierImpl(displayVk, getAspectFlags(), ImageLayout::TransferSrc, mCurrentQueueFamilyIndex,
8194                 &primaryCommandBuffer);
8195     primaryCommandBuffer.copyImageToBuffer(mImage, getCurrentLayout(),
8196                                            bufferHelper->getBuffer().getHandle(), 1, &region);
8197 
8198     ANGLE_VK_TRY(displayVk, primaryCommandBuffer.end());
8199 
8200     // Create fence for the submission
8201     VkFenceCreateInfo fenceInfo = {};
8202     fenceInfo.sType             = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
8203     fenceInfo.flags             = 0;
8204 
8205     vk::DeviceScoped<vk::Fence> fence(rendererVk->getDevice());
8206     ANGLE_VK_TRY(displayVk, fence.get().init(rendererVk->getDevice(), fenceInfo));
8207 
8208     Serial serial;
8209     ANGLE_TRY(rendererVk->queueSubmitOneOff(displayVk, std::move(primaryCommandBuffer), false,
8210                                             egl::ContextPriority::Medium, nullptr, 0, &fence.get(),
8211                                             vk::SubmitPolicy::EnsureSubmitted, &serial));
8212 
8213     ANGLE_VK_TRY(displayVk,
8214                  fence.get().wait(rendererVk->getDevice(), rendererVk->getMaxFenceWaitTimeNs()));
8215     return angle::Result::Continue;
8216 }
8217 
copyBufferToSurfaceImage(DisplayVk * displayVk,gl::LevelIndex sourceLevelGL,uint32_t layerCount,uint32_t baseLayer,const gl::Box & sourceArea,vk::BufferHelper * bufferHelper)8218 angle::Result ImageHelper::copyBufferToSurfaceImage(DisplayVk *displayVk,
8219                                                     gl::LevelIndex sourceLevelGL,
8220                                                     uint32_t layerCount,
8221                                                     uint32_t baseLayer,
8222                                                     const gl::Box &sourceArea,
8223                                                     vk::BufferHelper *bufferHelper)
8224 {
8225     ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::copyBufferToSurfaceImage");
8226 
8227     RendererVk *rendererVk = displayVk->getRenderer();
8228 
8229     VkBufferImageCopy region               = {};
8230     region.bufferOffset                    = 0;
8231     region.bufferRowLength                 = 0;
8232     region.bufferImageHeight               = 0;
8233     region.imageExtent.width               = sourceArea.width;
8234     region.imageExtent.height              = sourceArea.height;
8235     region.imageExtent.depth               = sourceArea.depth;
8236     region.imageOffset.x                   = sourceArea.x;
8237     region.imageOffset.y                   = sourceArea.y;
8238     region.imageOffset.z                   = sourceArea.z;
8239     region.imageSubresource.aspectMask     = getAspectFlags();
8240     region.imageSubresource.baseArrayLayer = baseLayer;
8241     region.imageSubresource.layerCount     = layerCount;
8242     region.imageSubresource.mipLevel       = toVkLevel(sourceLevelGL).get();
8243 
8244     PrimaryCommandBuffer commandBuffer;
8245     ANGLE_TRY(rendererVk->getCommandBufferOneOff(displayVk, false, &commandBuffer));
8246 
8247     barrierImpl(displayVk, getAspectFlags(), ImageLayout::TransferDst, mCurrentQueueFamilyIndex,
8248                 &commandBuffer);
8249     commandBuffer.copyBufferToImage(bufferHelper->getBuffer().getHandle(), mImage,
8250                                     getCurrentLayout(), 1, &region);
8251 
8252     ANGLE_VK_TRY(displayVk, commandBuffer.end());
8253 
8254     // Create fence for the submission
8255     VkFenceCreateInfo fenceInfo = {};
8256     fenceInfo.sType             = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
8257     fenceInfo.flags             = 0;
8258 
8259     vk::DeviceScoped<vk::Fence> fence(rendererVk->getDevice());
8260     ANGLE_VK_TRY(displayVk, fence.get().init(rendererVk->getDevice(), fenceInfo));
8261 
8262     Serial serial;
8263     ANGLE_TRY(rendererVk->queueSubmitOneOff(displayVk, std::move(commandBuffer), false,
8264                                             egl::ContextPriority::Medium, nullptr, 0, &fence.get(),
8265                                             vk::SubmitPolicy::EnsureSubmitted, &serial));
8266 
8267     ANGLE_VK_TRY(displayVk,
8268                  fence.get().wait(rendererVk->getDevice(), rendererVk->getMaxFenceWaitTimeNs()));
8269     return angle::Result::Continue;
8270 }
8271 
8272 // 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)8273 angle::Result ImageHelper::GetReadPixelsParams(ContextVk *contextVk,
8274                                                const gl::PixelPackState &packState,
8275                                                gl::Buffer *packBuffer,
8276                                                GLenum format,
8277                                                GLenum type,
8278                                                const gl::Rectangle &area,
8279                                                const gl::Rectangle &clippedArea,
8280                                                PackPixelsParams *paramsOut,
8281                                                GLuint *skipBytesOut)
8282 {
8283     const gl::InternalFormat &sizedFormatInfo = gl::GetInternalFormatInfo(format, type);
8284 
8285     GLuint outputPitch = 0;
8286     ANGLE_VK_CHECK_MATH(contextVk,
8287                         sizedFormatInfo.computeRowPitch(type, area.width, packState.alignment,
8288                                                         packState.rowLength, &outputPitch));
8289     ANGLE_VK_CHECK_MATH(contextVk, sizedFormatInfo.computeSkipBytes(type, outputPitch, 0, packState,
8290                                                                     false, skipBytesOut));
8291 
8292     *skipBytesOut += (clippedArea.x - area.x) * sizedFormatInfo.pixelBytes +
8293                      (clippedArea.y - area.y) * outputPitch;
8294 
8295     const angle::Format &angleFormat = GetFormatFromFormatType(format, type);
8296 
8297     *paramsOut = PackPixelsParams(clippedArea, angleFormat, outputPitch, packState.reverseRowOrder,
8298                                   packBuffer, 0);
8299     return angle::Result::Continue;
8300 }
8301 
readPixelsForGetImage(ContextVk * contextVk,const gl::PixelPackState & packState,gl::Buffer * packBuffer,gl::LevelIndex levelGL,uint32_t layer,uint32_t layerCount,GLenum format,GLenum type,void * pixels)8302 angle::Result ImageHelper::readPixelsForGetImage(ContextVk *contextVk,
8303                                                  const gl::PixelPackState &packState,
8304                                                  gl::Buffer *packBuffer,
8305                                                  gl::LevelIndex levelGL,
8306                                                  uint32_t layer,
8307                                                  uint32_t layerCount,
8308                                                  GLenum format,
8309                                                  GLenum type,
8310                                                  void *pixels)
8311 {
8312     const angle::Format &angleFormat = GetFormatFromFormatType(format, type);
8313 
8314     VkImageAspectFlagBits aspectFlags = {};
8315     if (angleFormat.redBits > 0 || angleFormat.blueBits > 0 || angleFormat.greenBits > 0 ||
8316         angleFormat.alphaBits > 0 || angleFormat.luminanceBits > 0)
8317     {
8318         aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT;
8319     }
8320     else
8321     {
8322         if (angleFormat.depthBits > 0)
8323         {
8324             if (angleFormat.stencilBits != 0)
8325             {
8326                 // TODO (anglebug.com/4688) Support combined depth stencil for GetTexImage
8327                 WARN() << "Unable to pull stencil from combined depth/stencil for GetTexImage";
8328             }
8329             aspectFlags = VK_IMAGE_ASPECT_DEPTH_BIT;
8330         }
8331         else if (angleFormat.stencilBits > 0)
8332         {
8333             aspectFlags = VK_IMAGE_ASPECT_STENCIL_BIT;
8334         }
8335     }
8336 
8337     ASSERT(aspectFlags != 0);
8338 
8339     PackPixelsParams params;
8340     GLuint outputSkipBytes = 0;
8341 
8342     const LevelIndex levelVk     = toVkLevel(levelGL);
8343     const gl::Extents mipExtents = getLevelExtents(levelVk);
8344     gl::Rectangle area(0, 0, mipExtents.width, mipExtents.height);
8345 
8346     ANGLE_TRY(GetReadPixelsParams(contextVk, packState, packBuffer, format, type, area, area,
8347                                   &params, &outputSkipBytes));
8348 
8349     if (mExtents.depth > 1 || layerCount > 1)
8350     {
8351         ASSERT(layer == 0);
8352         ASSERT(layerCount == 1 || mipExtents.depth == 1);
8353 
8354         uint32_t lastLayer = std::max(static_cast<uint32_t>(mipExtents.depth), layerCount);
8355 
8356         // Depth > 1 means this is a 3D texture and we need to copy all layers
8357         for (uint32_t mipLayer = 0; mipLayer < lastLayer; mipLayer++)
8358         {
8359             ANGLE_TRY(readPixels(contextVk, area, params, aspectFlags, levelGL, mipLayer,
8360                                  static_cast<uint8_t *>(pixels) + outputSkipBytes));
8361 
8362             outputSkipBytes += mipExtents.width * mipExtents.height *
8363                                gl::GetInternalFormatInfo(format, type).pixelBytes;
8364         }
8365     }
8366     else
8367     {
8368         ANGLE_TRY(readPixels(contextVk, area, params, aspectFlags, levelGL, layer,
8369                              static_cast<uint8_t *>(pixels) + outputSkipBytes));
8370     }
8371 
8372     return angle::Result::Continue;
8373 }
8374 
readPixelsForCompressedGetImage(ContextVk * contextVk,const gl::PixelPackState & packState,gl::Buffer * packBuffer,gl::LevelIndex levelGL,uint32_t layer,uint32_t layerCount,void * pixels)8375 angle::Result ImageHelper::readPixelsForCompressedGetImage(ContextVk *contextVk,
8376                                                            const gl::PixelPackState &packState,
8377                                                            gl::Buffer *packBuffer,
8378                                                            gl::LevelIndex levelGL,
8379                                                            uint32_t layer,
8380                                                            uint32_t layerCount,
8381                                                            void *pixels)
8382 {
8383     PackPixelsParams params;
8384     GLuint outputSkipBytes = 0;
8385 
8386     const LevelIndex levelVk = toVkLevel(levelGL);
8387     gl::Extents mipExtents   = getLevelExtents(levelVk);
8388     gl::Rectangle area(0, 0, mipExtents.width, mipExtents.height);
8389 
8390     VkImageAspectFlagBits aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT;
8391 
8392     const angle::Format *readFormat = &getActualFormat();
8393 
8394     // TODO(anglebug.com/6177): Implement encoding for emuluated compression formats
8395     ANGLE_VK_CHECK(contextVk, readFormat->isBlock, VK_ERROR_FORMAT_NOT_SUPPORTED);
8396 
8397     if (mExtents.depth > 1 || layerCount > 1)
8398     {
8399         ASSERT(layer == 0);
8400         ASSERT(layerCount == 1 || mipExtents.depth == 1);
8401 
8402         uint32_t lastLayer = std::max(static_cast<uint32_t>(mipExtents.depth), layerCount);
8403 
8404         const vk::Format &vkFormat = contextVk->getRenderer()->getFormat(readFormat->id);
8405         const gl::InternalFormat &storageFormatInfo =
8406             vkFormat.getInternalFormatInfo(readFormat->componentType);
8407 
8408         // Calculate size for one layer
8409         mipExtents.depth = 1;
8410         GLuint layerSize;
8411         ANGLE_VK_CHECK_MATH(contextVk,
8412                             storageFormatInfo.computeCompressedImageSize(mipExtents, &layerSize));
8413 
8414         // Depth > 1 means this is a 3D texture and we need to copy all layers
8415         for (uint32_t mipLayer = 0; mipLayer < lastLayer; mipLayer++)
8416         {
8417             ANGLE_TRY(readPixels(contextVk, area, params, aspectFlags, levelGL, mipLayer,
8418                                  static_cast<uint8_t *>(pixels) + outputSkipBytes));
8419             outputSkipBytes += layerSize;
8420         }
8421     }
8422     else
8423     {
8424         ANGLE_TRY(readPixels(contextVk, area, params, aspectFlags, levelGL, layer,
8425                              static_cast<uint8_t *>(pixels) + outputSkipBytes));
8426     }
8427 
8428     return angle::Result::Continue;
8429 }
8430 
canCopyWithTransformForReadPixels(const PackPixelsParams & packPixelsParams,const angle::Format * readFormat)8431 bool ImageHelper::canCopyWithTransformForReadPixels(const PackPixelsParams &packPixelsParams,
8432                                                     const angle::Format *readFormat)
8433 {
8434     ASSERT(mActualFormatID != angle::FormatID::NONE && mIntendedFormatID != angle::FormatID::NONE);
8435 
8436     // Only allow copies to PBOs with identical format.
8437     const bool isSameFormatCopy = *readFormat == *packPixelsParams.destFormat;
8438 
8439     // Disallow any transformation.
8440     const bool needsTransformation =
8441         packPixelsParams.rotation != SurfaceRotation::Identity || packPixelsParams.reverseRowOrder;
8442 
8443     // Disallow copies when the output pitch cannot be correctly specified in Vulkan.
8444     const bool isPitchMultipleOfTexelSize =
8445         packPixelsParams.outputPitch % readFormat->pixelBytes == 0;
8446 
8447     // Don't allow copies from emulated formats for simplicity.
8448     return !hasEmulatedImageFormat() && isSameFormatCopy && !needsTransformation &&
8449            isPitchMultipleOfTexelSize;
8450 }
8451 
readPixels(ContextVk * contextVk,const gl::Rectangle & area,const PackPixelsParams & packPixelsParams,VkImageAspectFlagBits copyAspectFlags,gl::LevelIndex levelGL,uint32_t layer,void * pixels)8452 angle::Result ImageHelper::readPixels(ContextVk *contextVk,
8453                                       const gl::Rectangle &area,
8454                                       const PackPixelsParams &packPixelsParams,
8455                                       VkImageAspectFlagBits copyAspectFlags,
8456                                       gl::LevelIndex levelGL,
8457                                       uint32_t layer,
8458                                       void *pixels)
8459 {
8460     ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::readPixels");
8461     RendererVk *renderer = contextVk->getRenderer();
8462 
8463     // If the source image is multisampled, we need to resolve it into a temporary image before
8464     // performing a readback.
8465     bool isMultisampled = mSamples > 1;
8466     RendererScoped<ImageHelper> resolvedImage(contextVk->getRenderer());
8467 
8468     ImageHelper *src = this;
8469 
8470     ASSERT(!hasStagedUpdatesForSubresource(levelGL, layer, 1));
8471 
8472     if (isMultisampled)
8473     {
8474         ANGLE_TRY(resolvedImage.get().init2DStaging(
8475             contextVk, contextVk->hasProtectedContent(), renderer->getMemoryProperties(),
8476             gl::Extents(area.width, area.height, 1), mIntendedFormatID, mActualFormatID,
8477             VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, 1));
8478         resolvedImage.get().retain(&contextVk->getResourceUseList());
8479     }
8480 
8481     VkImageAspectFlags layoutChangeAspectFlags = src->getAspectFlags();
8482 
8483     // Note that although we're reading from the image, we need to update the layout below.
8484     CommandBufferAccess access;
8485     access.onImageTransferRead(layoutChangeAspectFlags, this);
8486     if (isMultisampled)
8487     {
8488         access.onImageTransferWrite(gl::LevelIndex(0), 1, 0, 1, layoutChangeAspectFlags,
8489                                     &resolvedImage.get());
8490     }
8491 
8492     OutsideRenderPassCommandBuffer *commandBuffer;
8493     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
8494 
8495     const angle::Format *readFormat = &getActualFormat();
8496     const vk::Format &vkFormat      = contextVk->getRenderer()->getFormat(readFormat->id);
8497     const gl::InternalFormat &storageFormatInfo =
8498         vkFormat.getInternalFormatInfo(readFormat->componentType);
8499 
8500     if (copyAspectFlags != VK_IMAGE_ASPECT_COLOR_BIT)
8501     {
8502         readFormat = &GetDepthStencilImageToBufferFormat(*readFormat, copyAspectFlags);
8503     }
8504 
8505     VkOffset3D srcOffset = {area.x, area.y, 0};
8506 
8507     VkImageSubresourceLayers srcSubresource = {};
8508     srcSubresource.aspectMask               = copyAspectFlags;
8509     srcSubresource.mipLevel                 = toVkLevel(levelGL).get();
8510     srcSubresource.baseArrayLayer           = layer;
8511     srcSubresource.layerCount               = 1;
8512 
8513     VkExtent3D srcExtent = {static_cast<uint32_t>(area.width), static_cast<uint32_t>(area.height),
8514                             1};
8515 
8516     if (mExtents.depth > 1)
8517     {
8518         // Depth > 1 means this is a 3D texture and we need special handling
8519         srcOffset.z                   = layer;
8520         srcSubresource.baseArrayLayer = 0;
8521     }
8522 
8523     if (isMultisampled)
8524     {
8525         // Note: resolve only works on color images (not depth/stencil).
8526         ASSERT(copyAspectFlags == VK_IMAGE_ASPECT_COLOR_BIT);
8527 
8528         VkImageResolve resolveRegion                = {};
8529         resolveRegion.srcSubresource                = srcSubresource;
8530         resolveRegion.srcOffset                     = srcOffset;
8531         resolveRegion.dstSubresource.aspectMask     = copyAspectFlags;
8532         resolveRegion.dstSubresource.mipLevel       = 0;
8533         resolveRegion.dstSubresource.baseArrayLayer = 0;
8534         resolveRegion.dstSubresource.layerCount     = 1;
8535         resolveRegion.dstOffset                     = {};
8536         resolveRegion.extent                        = srcExtent;
8537 
8538         resolve(&resolvedImage.get(), resolveRegion, commandBuffer);
8539 
8540         CommandBufferAccess readAccess;
8541         readAccess.onImageTransferRead(layoutChangeAspectFlags, &resolvedImage.get());
8542         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(readAccess, &commandBuffer));
8543 
8544         // Make the resolved image the target of buffer copy.
8545         src                           = &resolvedImage.get();
8546         srcOffset                     = {0, 0, 0};
8547         srcSubresource.baseArrayLayer = 0;
8548         srcSubresource.layerCount     = 1;
8549         srcSubresource.mipLevel       = 0;
8550     }
8551 
8552     // If PBO and if possible, copy directly on the GPU.
8553     if (packPixelsParams.packBuffer &&
8554         canCopyWithTransformForReadPixels(packPixelsParams, readFormat))
8555     {
8556         BufferHelper &packBuffer      = GetImpl(packPixelsParams.packBuffer)->getBuffer();
8557         VkDeviceSize packBufferOffset = packBuffer.getOffset();
8558 
8559         CommandBufferAccess copyAccess;
8560         copyAccess.onBufferTransferWrite(&packBuffer);
8561         copyAccess.onImageTransferRead(copyAspectFlags, src);
8562 
8563         OutsideRenderPassCommandBuffer *copyCommandBuffer;
8564         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(copyAccess, &copyCommandBuffer));
8565 
8566         ASSERT(packPixelsParams.outputPitch % readFormat->pixelBytes == 0);
8567 
8568         VkBufferImageCopy region = {};
8569         region.bufferImageHeight = srcExtent.height;
8570         region.bufferOffset =
8571             packBufferOffset + packPixelsParams.offset + reinterpret_cast<ptrdiff_t>(pixels);
8572         region.bufferRowLength  = packPixelsParams.outputPitch / readFormat->pixelBytes;
8573         region.imageExtent      = srcExtent;
8574         region.imageOffset      = srcOffset;
8575         region.imageSubresource = srcSubresource;
8576 
8577         copyCommandBuffer->copyImageToBuffer(src->getImage(), src->getCurrentLayout(),
8578                                              packBuffer.getBuffer().getHandle(), 1, &region);
8579         return angle::Result::Continue;
8580     }
8581 
8582     RendererScoped<vk::BufferHelper> readBuffer(renderer);
8583     vk::BufferHelper *stagingBuffer = &readBuffer.get();
8584 
8585     uint8_t *readPixelBuffer   = nullptr;
8586     VkDeviceSize stagingOffset = 0;
8587     size_t allocationSize      = readFormat->pixelBytes * area.width * area.height;
8588 
8589     ANGLE_TRY(stagingBuffer->allocateForCopyImage(contextVk, allocationSize,
8590                                                   MemoryCoherency::Coherent, mActualFormatID,
8591                                                   &stagingOffset, &readPixelBuffer));
8592     VkBuffer bufferHandle = stagingBuffer->getBuffer().getHandle();
8593 
8594     VkBufferImageCopy region = {};
8595     region.bufferImageHeight = srcExtent.height;
8596     region.bufferOffset      = stagingOffset;
8597     region.bufferRowLength   = srcExtent.width;
8598     region.imageExtent       = srcExtent;
8599     region.imageOffset       = srcOffset;
8600     region.imageSubresource  = srcSubresource;
8601 
8602     // For compressed textures, vkCmdCopyImageToBuffer requires
8603     // a region that is a multiple of the block size.
8604     if (readFormat->isBlock)
8605     {
8606         region.bufferRowLength =
8607             roundUp(region.bufferRowLength, storageFormatInfo.compressedBlockWidth);
8608         region.bufferImageHeight =
8609             roundUp(region.bufferImageHeight, storageFormatInfo.compressedBlockHeight);
8610     }
8611 
8612     CommandBufferAccess readbackAccess;
8613     readbackAccess.onBufferTransferWrite(stagingBuffer);
8614 
8615     OutsideRenderPassCommandBuffer *readbackCommandBuffer;
8616     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(readbackAccess, &readbackCommandBuffer));
8617 
8618     readbackCommandBuffer->copyImageToBuffer(src->getImage(), src->getCurrentLayout(), bufferHandle,
8619                                              1, &region);
8620 
8621     ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_HIGH, "GPU stall due to ReadPixels");
8622 
8623     // Triggers a full finish.
8624     // TODO(jmadill): Don't block on asynchronous readback.
8625     ANGLE_TRY(contextVk->finishImpl(RenderPassClosureReason::GLReadPixels));
8626 
8627     if (readFormat->isBlock)
8628     {
8629         const LevelIndex levelVk = toVkLevel(levelGL);
8630         gl::Extents levelExtents = getLevelExtents(levelVk);
8631 
8632         // Calculate size of one layer
8633         levelExtents.depth = 1;
8634         GLuint layerSize;
8635         ANGLE_VK_CHECK_MATH(contextVk,
8636                             storageFormatInfo.computeCompressedImageSize(levelExtents, &layerSize));
8637         memcpy(pixels, readPixelBuffer, layerSize);
8638     }
8639     else if (packPixelsParams.packBuffer)
8640     {
8641         // Must map the PBO in order to read its contents (and then unmap it later)
8642         BufferVk *packBufferVk = GetImpl(packPixelsParams.packBuffer);
8643         void *mapPtr           = nullptr;
8644         ANGLE_TRY(packBufferVk->mapImpl(contextVk, GL_MAP_WRITE_BIT, &mapPtr));
8645         uint8_t *dst = static_cast<uint8_t *>(mapPtr) + reinterpret_cast<ptrdiff_t>(pixels);
8646         PackPixels(packPixelsParams, *readFormat, area.width * readFormat->pixelBytes,
8647                    readPixelBuffer, static_cast<uint8_t *>(dst));
8648         ANGLE_TRY(packBufferVk->unmapImpl(contextVk));
8649     }
8650     else
8651     {
8652         PackPixels(packPixelsParams, *readFormat, area.width * readFormat->pixelBytes,
8653                    readPixelBuffer, static_cast<uint8_t *>(pixels));
8654     }
8655 
8656     return angle::Result::Continue;
8657 }
8658 
8659 // ImageHelper::SubresourceUpdate implementation
SubresourceUpdate()8660 ImageHelper::SubresourceUpdate::SubresourceUpdate() : updateSource(UpdateSource::Buffer)
8661 {
8662     data.buffer.bufferHelper = nullptr;
8663     refCounted.buffer        = nullptr;
8664 }
8665 
~SubresourceUpdate()8666 ImageHelper::SubresourceUpdate::~SubresourceUpdate() {}
8667 
SubresourceUpdate(RefCounted<BufferHelper> * bufferIn,BufferHelper * bufferHelperIn,const VkBufferImageCopy & copyRegionIn,angle::FormatID formatID)8668 ImageHelper::SubresourceUpdate::SubresourceUpdate(RefCounted<BufferHelper> *bufferIn,
8669                                                   BufferHelper *bufferHelperIn,
8670                                                   const VkBufferImageCopy &copyRegionIn,
8671                                                   angle::FormatID formatID)
8672     : updateSource(UpdateSource::Buffer)
8673 {
8674     refCounted.buffer = bufferIn;
8675     if (refCounted.buffer != nullptr)
8676     {
8677         refCounted.buffer->addRef();
8678     }
8679     data.buffer.bufferHelper = bufferHelperIn;
8680     data.buffer.copyRegion   = copyRegionIn;
8681     data.buffer.formatID     = formatID;
8682 }
8683 
SubresourceUpdate(RefCounted<ImageHelper> * imageIn,const VkImageCopy & copyRegionIn,angle::FormatID formatID)8684 ImageHelper::SubresourceUpdate::SubresourceUpdate(RefCounted<ImageHelper> *imageIn,
8685                                                   const VkImageCopy &copyRegionIn,
8686                                                   angle::FormatID formatID)
8687     : updateSource(UpdateSource::Image)
8688 {
8689     refCounted.image = imageIn;
8690     refCounted.image->addRef();
8691     data.image.copyRegion = copyRegionIn;
8692     data.image.formatID   = formatID;
8693 }
8694 
SubresourceUpdate(VkImageAspectFlags aspectFlags,const VkClearValue & clearValue,const gl::ImageIndex & imageIndex)8695 ImageHelper::SubresourceUpdate::SubresourceUpdate(VkImageAspectFlags aspectFlags,
8696                                                   const VkClearValue &clearValue,
8697                                                   const gl::ImageIndex &imageIndex)
8698     : SubresourceUpdate(
8699           aspectFlags,
8700           clearValue,
8701           gl::LevelIndex(imageIndex.getLevelIndex()),
8702           imageIndex.hasLayer() ? imageIndex.getLayerIndex() : 0,
8703           imageIndex.hasLayer() ? imageIndex.getLayerCount() : VK_REMAINING_ARRAY_LAYERS)
8704 {}
8705 
SubresourceUpdate(VkImageAspectFlags aspectFlags,const VkClearValue & clearValue,gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount)8706 ImageHelper::SubresourceUpdate::SubresourceUpdate(VkImageAspectFlags aspectFlags,
8707                                                   const VkClearValue &clearValue,
8708                                                   gl::LevelIndex level,
8709                                                   uint32_t layerIndex,
8710                                                   uint32_t layerCount)
8711     : updateSource(UpdateSource::Clear)
8712 {
8713     refCounted.image          = nullptr;
8714     data.clear.aspectFlags    = aspectFlags;
8715     data.clear.value          = clearValue;
8716     data.clear.levelIndex     = level.get();
8717     data.clear.layerIndex     = layerIndex;
8718     data.clear.layerCount     = layerCount;
8719     data.clear.colorMaskFlags = 0;
8720 }
8721 
SubresourceUpdate(VkColorComponentFlags colorMaskFlags,const VkClearColorValue & clearValue,const gl::ImageIndex & imageIndex)8722 ImageHelper::SubresourceUpdate::SubresourceUpdate(VkColorComponentFlags colorMaskFlags,
8723                                                   const VkClearColorValue &clearValue,
8724                                                   const gl::ImageIndex &imageIndex)
8725     : updateSource(UpdateSource::ClearEmulatedChannelsOnly)
8726 {
8727     refCounted.image       = nullptr;
8728     data.clear.aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT;
8729     data.clear.value.color = clearValue;
8730     data.clear.levelIndex  = imageIndex.getLevelIndex();
8731     data.clear.layerIndex  = imageIndex.hasLayer() ? imageIndex.getLayerIndex() : 0;
8732     data.clear.layerCount =
8733         imageIndex.hasLayer() ? imageIndex.getLayerCount() : VK_REMAINING_ARRAY_LAYERS;
8734     data.clear.colorMaskFlags = colorMaskFlags;
8735 }
8736 
SubresourceUpdate(SubresourceUpdate && other)8737 ImageHelper::SubresourceUpdate::SubresourceUpdate(SubresourceUpdate &&other)
8738     : updateSource(other.updateSource)
8739 {
8740     switch (updateSource)
8741     {
8742         case UpdateSource::Clear:
8743         case UpdateSource::ClearEmulatedChannelsOnly:
8744         case UpdateSource::ClearAfterInvalidate:
8745             data.clear        = other.data.clear;
8746             refCounted.buffer = nullptr;
8747             break;
8748         case UpdateSource::Buffer:
8749             data.buffer             = other.data.buffer;
8750             refCounted.buffer       = other.refCounted.buffer;
8751             other.refCounted.buffer = nullptr;
8752             break;
8753         case UpdateSource::Image:
8754             data.image             = other.data.image;
8755             refCounted.image       = other.refCounted.image;
8756             other.refCounted.image = nullptr;
8757             break;
8758         default:
8759             UNREACHABLE();
8760     }
8761 }
8762 
operator =(SubresourceUpdate && other)8763 ImageHelper::SubresourceUpdate &ImageHelper::SubresourceUpdate::operator=(SubresourceUpdate &&other)
8764 {
8765     // Given that the update is a union of three structs, we can't use std::swap on the fields.  For
8766     // example, |this| may be an Image update and |other| may be a Buffer update.
8767     // The following could work:
8768     //
8769     // SubresourceUpdate oldThis;
8770     // Set oldThis to this->field based on updateSource
8771     // Set this->otherField to other.otherField based on other.updateSource
8772     // Set other.field to oldThis->field based on updateSource
8773     // std::Swap(updateSource, other.updateSource);
8774     //
8775     // It's much simpler to just swap the memory instead.
8776 
8777     SubresourceUpdate oldThis;
8778     memcpy(&oldThis, this, sizeof(*this));
8779     memcpy(this, &other, sizeof(*this));
8780     memcpy(&other, &oldThis, sizeof(*this));
8781 
8782     return *this;
8783 }
8784 
release(RendererVk * renderer)8785 void ImageHelper::SubresourceUpdate::release(RendererVk *renderer)
8786 {
8787     if (updateSource == UpdateSource::Image)
8788     {
8789         refCounted.image->releaseRef();
8790 
8791         if (!refCounted.image->isReferenced())
8792         {
8793             // Staging images won't be used in render pass attachments.
8794             refCounted.image->get().releaseImage(renderer);
8795             refCounted.image->get().releaseStagedUpdates(renderer);
8796             SafeDelete(refCounted.image);
8797         }
8798 
8799         refCounted.image = nullptr;
8800     }
8801     else if (updateSource == UpdateSource::Buffer && refCounted.buffer != nullptr)
8802     {
8803         refCounted.buffer->releaseRef();
8804 
8805         if (!refCounted.buffer->isReferenced())
8806         {
8807             refCounted.buffer->get().release(renderer);
8808             SafeDelete(refCounted.buffer);
8809         }
8810 
8811         refCounted.buffer = nullptr;
8812     }
8813 }
8814 
isUpdateToLayers(uint32_t layerIndex,uint32_t layerCount) const8815 bool ImageHelper::SubresourceUpdate::isUpdateToLayers(uint32_t layerIndex,
8816                                                       uint32_t layerCount) const
8817 {
8818     uint32_t updateBaseLayer, updateLayerCount;
8819     getDestSubresource(gl::ImageIndex::kEntireLevel, &updateBaseLayer, &updateLayerCount);
8820 
8821     return updateBaseLayer == layerIndex &&
8822            (updateLayerCount == layerCount || updateLayerCount == VK_REMAINING_ARRAY_LAYERS);
8823 }
8824 
getDestSubresource(uint32_t imageLayerCount,uint32_t * baseLayerOut,uint32_t * layerCountOut) const8825 void ImageHelper::SubresourceUpdate::getDestSubresource(uint32_t imageLayerCount,
8826                                                         uint32_t *baseLayerOut,
8827                                                         uint32_t *layerCountOut) const
8828 {
8829     if (IsClear(updateSource))
8830     {
8831         *baseLayerOut  = data.clear.layerIndex;
8832         *layerCountOut = data.clear.layerCount;
8833 
8834         if (*layerCountOut == static_cast<uint32_t>(gl::ImageIndex::kEntireLevel))
8835         {
8836             *layerCountOut = imageLayerCount;
8837         }
8838     }
8839     else
8840     {
8841         const VkImageSubresourceLayers &dstSubresource =
8842             updateSource == UpdateSource::Buffer ? data.buffer.copyRegion.imageSubresource
8843                                                  : data.image.copyRegion.dstSubresource;
8844         *baseLayerOut  = dstSubresource.baseArrayLayer;
8845         *layerCountOut = dstSubresource.layerCount;
8846 
8847         ASSERT(*layerCountOut != static_cast<uint32_t>(gl::ImageIndex::kEntireLevel));
8848     }
8849 }
8850 
getDestAspectFlags() const8851 VkImageAspectFlags ImageHelper::SubresourceUpdate::getDestAspectFlags() const
8852 {
8853     if (IsClear(updateSource))
8854     {
8855         return data.clear.aspectFlags;
8856     }
8857     else if (updateSource == UpdateSource::Buffer)
8858     {
8859         return data.buffer.copyRegion.imageSubresource.aspectMask;
8860     }
8861     else
8862     {
8863         ASSERT(updateSource == UpdateSource::Image);
8864         return data.image.copyRegion.dstSubresource.aspectMask;
8865     }
8866 }
8867 
getLevelUpdates(gl::LevelIndex level)8868 std::vector<ImageHelper::SubresourceUpdate> *ImageHelper::getLevelUpdates(gl::LevelIndex level)
8869 {
8870     return static_cast<size_t>(level.get()) < mSubresourceUpdates.size()
8871                ? &mSubresourceUpdates[level.get()]
8872                : nullptr;
8873 }
8874 
getLevelUpdates(gl::LevelIndex level) const8875 const std::vector<ImageHelper::SubresourceUpdate> *ImageHelper::getLevelUpdates(
8876     gl::LevelIndex level) const
8877 {
8878     return static_cast<size_t>(level.get()) < mSubresourceUpdates.size()
8879                ? &mSubresourceUpdates[level.get()]
8880                : nullptr;
8881 }
8882 
appendSubresourceUpdate(gl::LevelIndex level,SubresourceUpdate && update)8883 void ImageHelper::appendSubresourceUpdate(gl::LevelIndex level, SubresourceUpdate &&update)
8884 {
8885     if (mSubresourceUpdates.size() <= static_cast<size_t>(level.get()))
8886     {
8887         mSubresourceUpdates.resize(level.get() + 1);
8888     }
8889 
8890     mSubresourceUpdates[level.get()].emplace_back(std::move(update));
8891     onStateChange(angle::SubjectMessage::SubjectChanged);
8892 }
8893 
prependSubresourceUpdate(gl::LevelIndex level,SubresourceUpdate && update)8894 void ImageHelper::prependSubresourceUpdate(gl::LevelIndex level, SubresourceUpdate &&update)
8895 {
8896     if (mSubresourceUpdates.size() <= static_cast<size_t>(level.get()))
8897     {
8898         mSubresourceUpdates.resize(level.get() + 1);
8899     }
8900 
8901     mSubresourceUpdates[level.get()].insert(mSubresourceUpdates[level.get()].begin(),
8902                                             std::move(update));
8903     onStateChange(angle::SubjectMessage::SubjectChanged);
8904 }
8905 
hasEmulatedImageChannels() const8906 bool ImageHelper::hasEmulatedImageChannels() const
8907 {
8908     const angle::Format &angleFmt   = getIntendedFormat();
8909     const angle::Format &textureFmt = getActualFormat();
8910 
8911     // The red channel is never emulated.
8912     ASSERT((angleFmt.redBits != 0 || angleFmt.luminanceBits != 0 || angleFmt.alphaBits != 0) ==
8913            (textureFmt.redBits != 0));
8914 
8915     return (angleFmt.alphaBits == 0 && textureFmt.alphaBits > 0) ||
8916            (angleFmt.blueBits == 0 && textureFmt.blueBits > 0) ||
8917            (angleFmt.greenBits == 0 && textureFmt.greenBits > 0) ||
8918            (angleFmt.depthBits == 0 && textureFmt.depthBits > 0) ||
8919            (angleFmt.stencilBits == 0 && textureFmt.stencilBits > 0);
8920 }
8921 
hasEmulatedDepthChannel() const8922 bool ImageHelper::hasEmulatedDepthChannel() const
8923 {
8924     return getIntendedFormat().depthBits == 0 && getActualFormat().depthBits > 0;
8925 }
8926 
hasEmulatedStencilChannel() const8927 bool ImageHelper::hasEmulatedStencilChannel() const
8928 {
8929     return getIntendedFormat().stencilBits == 0 && getActualFormat().stencilBits > 0;
8930 }
8931 
getEmulatedChannelsMask() const8932 VkColorComponentFlags ImageHelper::getEmulatedChannelsMask() const
8933 {
8934     const angle::Format &angleFmt   = getIntendedFormat();
8935     const angle::Format &textureFmt = getActualFormat();
8936 
8937     ASSERT(!angleFmt.hasDepthOrStencilBits());
8938 
8939     VkColorComponentFlags emulatedChannelsMask = 0;
8940 
8941     if (angleFmt.alphaBits == 0 && textureFmt.alphaBits > 0)
8942     {
8943         emulatedChannelsMask |= VK_COLOR_COMPONENT_A_BIT;
8944     }
8945     if (angleFmt.blueBits == 0 && textureFmt.blueBits > 0)
8946     {
8947         emulatedChannelsMask |= VK_COLOR_COMPONENT_B_BIT;
8948     }
8949     if (angleFmt.greenBits == 0 && textureFmt.greenBits > 0)
8950     {
8951         emulatedChannelsMask |= VK_COLOR_COMPONENT_G_BIT;
8952     }
8953 
8954     // The red channel is never emulated.
8955     ASSERT((angleFmt.redBits != 0 || angleFmt.luminanceBits != 0 || angleFmt.alphaBits != 0) ==
8956            (textureFmt.redBits != 0));
8957 
8958     return emulatedChannelsMask;
8959 }
8960 
8961 // FramebufferHelper implementation.
8962 FramebufferHelper::FramebufferHelper() = default;
8963 
8964 FramebufferHelper::~FramebufferHelper() = default;
8965 
FramebufferHelper(FramebufferHelper && other)8966 FramebufferHelper::FramebufferHelper(FramebufferHelper &&other) : Resource(std::move(other))
8967 {
8968     mFramebuffer = std::move(other.mFramebuffer);
8969 }
8970 
operator =(FramebufferHelper && other)8971 FramebufferHelper &FramebufferHelper::operator=(FramebufferHelper &&other)
8972 {
8973     std::swap(mUse, other.mUse);
8974     std::swap(mFramebuffer, other.mFramebuffer);
8975     return *this;
8976 }
8977 
init(ContextVk * contextVk,const VkFramebufferCreateInfo & createInfo)8978 angle::Result FramebufferHelper::init(ContextVk *contextVk,
8979                                       const VkFramebufferCreateInfo &createInfo)
8980 {
8981     ANGLE_VK_TRY(contextVk, mFramebuffer.init(contextVk->getDevice(), createInfo));
8982     return angle::Result::Continue;
8983 }
8984 
release(ContextVk * contextVk)8985 void FramebufferHelper::release(ContextVk *contextVk)
8986 {
8987     contextVk->addGarbage(&mFramebuffer);
8988 }
8989 
GetLayerMode(const vk::ImageHelper & image,uint32_t layerCount)8990 LayerMode GetLayerMode(const vk::ImageHelper &image, uint32_t layerCount)
8991 {
8992     const uint32_t imageLayerCount = GetImageLayerCountForView(image);
8993     const bool allLayers           = layerCount == imageLayerCount;
8994 
8995     ASSERT(allLayers || layerCount > 0 && layerCount <= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
8996     return allLayers ? LayerMode::All : static_cast<LayerMode>(layerCount);
8997 }
8998 
8999 // ImageViewHelper implementation.
ImageViewHelper()9000 ImageViewHelper::ImageViewHelper() : mCurrentBaseMaxLevelHash(0), mLinearColorspace(true) {}
9001 
ImageViewHelper(ImageViewHelper && other)9002 ImageViewHelper::ImageViewHelper(ImageViewHelper &&other)
9003 {
9004     std::swap(mCurrentBaseMaxLevelHash, other.mCurrentBaseMaxLevelHash);
9005     std::swap(mLinearColorspace, other.mLinearColorspace);
9006 
9007     std::swap(mPerLevelRangeLinearReadImageViews, other.mPerLevelRangeLinearReadImageViews);
9008     std::swap(mPerLevelRangeSRGBReadImageViews, other.mPerLevelRangeSRGBReadImageViews);
9009     std::swap(mPerLevelRangeLinearFetchImageViews, other.mPerLevelRangeLinearFetchImageViews);
9010     std::swap(mPerLevelRangeSRGBFetchImageViews, other.mPerLevelRangeSRGBFetchImageViews);
9011     std::swap(mPerLevelRangeLinearCopyImageViews, other.mPerLevelRangeLinearCopyImageViews);
9012     std::swap(mPerLevelRangeSRGBCopyImageViews, other.mPerLevelRangeSRGBCopyImageViews);
9013     std::swap(mPerLevelRangeStencilReadImageViews, other.mPerLevelRangeStencilReadImageViews);
9014 
9015     std::swap(mLayerLevelDrawImageViews, other.mLayerLevelDrawImageViews);
9016     std::swap(mLayerLevelDrawImageViewsLinear, other.mLayerLevelDrawImageViewsLinear);
9017     std::swap(mSubresourceDrawImageViews, other.mSubresourceDrawImageViews);
9018     std::swap(mLevelStorageImageViews, other.mLevelStorageImageViews);
9019     std::swap(mLayerLevelStorageImageViews, other.mLayerLevelStorageImageViews);
9020     std::swap(mImageViewSerial, other.mImageViewSerial);
9021 }
9022 
~ImageViewHelper()9023 ImageViewHelper::~ImageViewHelper() {}
9024 
init(RendererVk * renderer)9025 void ImageViewHelper::init(RendererVk *renderer)
9026 {
9027     if (!mImageViewSerial.valid())
9028     {
9029         mImageViewSerial = renderer->getResourceSerialFactory().generateImageOrBufferViewSerial();
9030     }
9031 }
9032 
release(RendererVk * renderer,std::vector<vk::GarbageObject> & garbage)9033 void ImageViewHelper::release(RendererVk *renderer, std::vector<vk::GarbageObject> &garbage)
9034 {
9035     mCurrentBaseMaxLevelHash = 0;
9036 
9037     // Release the read views
9038     ReleaseImageViews(&mPerLevelRangeLinearReadImageViews, &garbage);
9039     ReleaseImageViews(&mPerLevelRangeSRGBReadImageViews, &garbage);
9040     ReleaseImageViews(&mPerLevelRangeLinearFetchImageViews, &garbage);
9041     ReleaseImageViews(&mPerLevelRangeSRGBFetchImageViews, &garbage);
9042     ReleaseImageViews(&mPerLevelRangeLinearCopyImageViews, &garbage);
9043     ReleaseImageViews(&mPerLevelRangeSRGBCopyImageViews, &garbage);
9044     ReleaseImageViews(&mPerLevelRangeStencilReadImageViews, &garbage);
9045 
9046     // Release the draw views
9047     for (ImageViewVector &layerViews : mLayerLevelDrawImageViews)
9048     {
9049         for (ImageView &imageView : layerViews)
9050         {
9051             if (imageView.valid())
9052             {
9053                 garbage.emplace_back(GetGarbage(&imageView));
9054             }
9055         }
9056     }
9057     mLayerLevelDrawImageViews.clear();
9058     for (ImageViewVector &layerViews : mLayerLevelDrawImageViewsLinear)
9059     {
9060         for (ImageView &imageView : layerViews)
9061         {
9062             if (imageView.valid())
9063             {
9064                 garbage.emplace_back(GetGarbage(&imageView));
9065             }
9066         }
9067     }
9068     mLayerLevelDrawImageViewsLinear.clear();
9069     for (auto &iter : mSubresourceDrawImageViews)
9070     {
9071         std::unique_ptr<ImageView> &imageView = iter.second;
9072         if (imageView->valid())
9073         {
9074             garbage.emplace_back(GetGarbage(imageView.get()));
9075         }
9076     }
9077     mSubresourceDrawImageViews.clear();
9078 
9079     // Release the storage views
9080     ReleaseImageViews(&mLevelStorageImageViews, &garbage);
9081     for (ImageViewVector &layerViews : mLayerLevelStorageImageViews)
9082     {
9083         for (ImageView &imageView : layerViews)
9084         {
9085             if (imageView.valid())
9086             {
9087                 garbage.emplace_back(GetGarbage(&imageView));
9088             }
9089         }
9090     }
9091     mLayerLevelStorageImageViews.clear();
9092 
9093     // Update image view serial.
9094     mImageViewSerial = renderer->getResourceSerialFactory().generateImageOrBufferViewSerial();
9095 }
9096 
isImageViewGarbageEmpty() const9097 bool ImageViewHelper::isImageViewGarbageEmpty() const
9098 {
9099     return mPerLevelRangeLinearReadImageViews.empty() &&
9100            mPerLevelRangeLinearCopyImageViews.empty() &&
9101            mPerLevelRangeLinearFetchImageViews.empty() &&
9102            mPerLevelRangeSRGBReadImageViews.empty() && mPerLevelRangeSRGBCopyImageViews.empty() &&
9103            mPerLevelRangeSRGBFetchImageViews.empty() &&
9104            mPerLevelRangeStencilReadImageViews.empty() && mLayerLevelDrawImageViews.empty() &&
9105            mLayerLevelDrawImageViewsLinear.empty() && mSubresourceDrawImageViews.empty() &&
9106            mLayerLevelStorageImageViews.empty();
9107 }
9108 
destroy(VkDevice device)9109 void ImageViewHelper::destroy(VkDevice device)
9110 {
9111     mCurrentBaseMaxLevelHash = 0;
9112 
9113     // Release the read views
9114     DestroyImageViews(&mPerLevelRangeLinearReadImageViews, device);
9115     DestroyImageViews(&mPerLevelRangeSRGBReadImageViews, device);
9116     DestroyImageViews(&mPerLevelRangeLinearFetchImageViews, device);
9117     DestroyImageViews(&mPerLevelRangeSRGBFetchImageViews, device);
9118     DestroyImageViews(&mPerLevelRangeLinearCopyImageViews, device);
9119     DestroyImageViews(&mPerLevelRangeSRGBCopyImageViews, device);
9120     DestroyImageViews(&mPerLevelRangeStencilReadImageViews, device);
9121 
9122     // Release the draw views
9123     for (ImageViewVector &layerViews : mLayerLevelDrawImageViews)
9124     {
9125         for (ImageView &imageView : layerViews)
9126         {
9127             imageView.destroy(device);
9128         }
9129     }
9130     mLayerLevelDrawImageViews.clear();
9131     for (ImageViewVector &layerViews : mLayerLevelDrawImageViewsLinear)
9132     {
9133         for (ImageView &imageView : layerViews)
9134         {
9135             imageView.destroy(device);
9136         }
9137     }
9138     mLayerLevelDrawImageViewsLinear.clear();
9139     for (auto &iter : mSubresourceDrawImageViews)
9140     {
9141         std::unique_ptr<ImageView> &imageView = iter.second;
9142         imageView->destroy(device);
9143     }
9144     mSubresourceDrawImageViews.clear();
9145 
9146     // Release the storage views
9147     DestroyImageViews(&mLevelStorageImageViews, device);
9148     for (ImageViewVector &layerViews : mLayerLevelStorageImageViews)
9149     {
9150         for (ImageView &imageView : layerViews)
9151         {
9152             imageView.destroy(device);
9153         }
9154     }
9155     mLayerLevelStorageImageViews.clear();
9156 
9157     mImageViewSerial = kInvalidImageOrBufferViewSerial;
9158 }
9159 
initReadViews(ContextVk * contextVk,gl::TextureType viewType,const ImageHelper & image,const angle::Format & format,const gl::SwizzleState & formatSwizzle,const gl::SwizzleState & readSwizzle,LevelIndex baseLevel,uint32_t levelCount,uint32_t baseLayer,uint32_t layerCount,bool requiresSRGBViews,VkImageUsageFlags imageUsageFlags,const gl::SamplerState & samplerState)9160 angle::Result ImageViewHelper::initReadViews(ContextVk *contextVk,
9161                                              gl::TextureType viewType,
9162                                              const ImageHelper &image,
9163                                              const angle::Format &format,
9164                                              const gl::SwizzleState &formatSwizzle,
9165                                              const gl::SwizzleState &readSwizzle,
9166                                              LevelIndex baseLevel,
9167                                              uint32_t levelCount,
9168                                              uint32_t baseLayer,
9169                                              uint32_t layerCount,
9170                                              bool requiresSRGBViews,
9171                                              VkImageUsageFlags imageUsageFlags,
9172                                              const gl::SamplerState &samplerState)
9173 {
9174     ASSERT(levelCount > 0);
9175 
9176     const uint32_t maxLevel = levelCount - 1;
9177     ASSERT(maxLevel < 16);
9178     ASSERT(baseLevel.get() < 16);
9179     mCurrentBaseMaxLevelHash = static_cast<uint8_t>(baseLevel.get() << 4 | maxLevel);
9180 
9181     if (mCurrentBaseMaxLevelHash >= mPerLevelRangeLinearReadImageViews.size())
9182     {
9183         const uint32_t maxViewCount = mCurrentBaseMaxLevelHash + 1;
9184 
9185         mPerLevelRangeLinearReadImageViews.resize(maxViewCount);
9186         mPerLevelRangeSRGBReadImageViews.resize(maxViewCount);
9187         mPerLevelRangeLinearFetchImageViews.resize(maxViewCount);
9188         mPerLevelRangeSRGBFetchImageViews.resize(maxViewCount);
9189         mPerLevelRangeLinearCopyImageViews.resize(maxViewCount);
9190         mPerLevelRangeSRGBCopyImageViews.resize(maxViewCount);
9191         mPerLevelRangeStencilReadImageViews.resize(maxViewCount);
9192     }
9193 
9194     // Determine if we already have ImageViews for the new max level
9195     if (getReadImageView().valid())
9196     {
9197         return angle::Result::Continue;
9198     }
9199 
9200     // Since we don't have a readImageView, we must create ImageViews for the new max level
9201     ANGLE_TRY(initReadViewsImpl(contextVk, viewType, image, format, formatSwizzle, readSwizzle,
9202                                 baseLevel, levelCount, baseLayer, layerCount, samplerState));
9203 
9204     if (requiresSRGBViews)
9205     {
9206         ANGLE_TRY(initSRGBReadViewsImpl(contextVk, viewType, image, format, formatSwizzle,
9207                                         readSwizzle, baseLevel, levelCount, baseLayer, layerCount,
9208                                         imageUsageFlags));
9209     }
9210 
9211     return angle::Result::Continue;
9212 }
9213 
initReadViewsImpl(ContextVk * contextVk,gl::TextureType viewType,const ImageHelper & image,const angle::Format & format,const gl::SwizzleState & formatSwizzle,const gl::SwizzleState & readSwizzle,LevelIndex baseLevel,uint32_t levelCount,uint32_t baseLayer,uint32_t layerCount,const gl::SamplerState & samplerState)9214 angle::Result ImageViewHelper::initReadViewsImpl(ContextVk *contextVk,
9215                                                  gl::TextureType viewType,
9216                                                  const ImageHelper &image,
9217                                                  const angle::Format &format,
9218                                                  const gl::SwizzleState &formatSwizzle,
9219                                                  const gl::SwizzleState &readSwizzle,
9220                                                  LevelIndex baseLevel,
9221                                                  uint32_t levelCount,
9222                                                  uint32_t baseLayer,
9223                                                  uint32_t layerCount,
9224                                                  const gl::SamplerState &samplerState)
9225 {
9226     ASSERT(mImageViewSerial.valid());
9227 
9228     const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(image.getIntendedFormat());
9229     mLinearColorspace                    = !format.isSRGB;
9230     VkFormat vkFormat                    = GetVkFormatFromFormatID(format.id);
9231 
9232     if (HasBothDepthAndStencilAspects(aspectFlags))
9233     {
9234         ANGLE_TRY(image.initLayerImageViewWithFormat(
9235             contextVk, viewType, vkFormat, VK_IMAGE_ASPECT_DEPTH_BIT, readSwizzle,
9236             &getReadImageView(), baseLevel, levelCount, baseLayer, layerCount, samplerState));
9237         ANGLE_TRY(image.initLayerImageViewWithFormat(
9238             contextVk, viewType, vkFormat, VK_IMAGE_ASPECT_STENCIL_BIT, readSwizzle,
9239             &mPerLevelRangeStencilReadImageViews[mCurrentBaseMaxLevelHash], baseLevel, levelCount,
9240             baseLayer, layerCount, samplerState));
9241     }
9242     else
9243     {
9244         ANGLE_TRY(image.initLayerImageViewWithFormat(
9245             contextVk, viewType, vkFormat, aspectFlags, readSwizzle, &getReadImageView(), baseLevel,
9246             levelCount, baseLayer, layerCount, samplerState));
9247     }
9248 
9249     gl::TextureType fetchType = viewType;
9250 
9251     if (viewType == gl::TextureType::CubeMap || viewType == gl::TextureType::_2DArray ||
9252         viewType == gl::TextureType::_2DMultisampleArray)
9253     {
9254         fetchType = Get2DTextureType(layerCount, image.getSamples());
9255 
9256         ANGLE_TRY(image.initLayerImageViewWithFormat(
9257             contextVk, fetchType, vkFormat, aspectFlags, readSwizzle, &getFetchImageView(),
9258             baseLevel, levelCount, baseLayer, layerCount, samplerState));
9259     }
9260 
9261     ANGLE_TRY(image.initLayerImageViewWithFormat(contextVk, fetchType, vkFormat, aspectFlags,
9262                                                  formatSwizzle, &getCopyImageView(), baseLevel,
9263                                                  levelCount, baseLayer, layerCount, samplerState));
9264 
9265     return angle::Result::Continue;
9266 }
9267 
initSRGBReadViewsImpl(ContextVk * contextVk,gl::TextureType viewType,const ImageHelper & image,const angle::Format & format,const gl::SwizzleState & formatSwizzle,const gl::SwizzleState & readSwizzle,LevelIndex baseLevel,uint32_t levelCount,uint32_t baseLayer,uint32_t layerCount,VkImageUsageFlags imageUsageFlags)9268 angle::Result ImageViewHelper::initSRGBReadViewsImpl(ContextVk *contextVk,
9269                                                      gl::TextureType viewType,
9270                                                      const ImageHelper &image,
9271                                                      const angle::Format &format,
9272                                                      const gl::SwizzleState &formatSwizzle,
9273                                                      const gl::SwizzleState &readSwizzle,
9274                                                      LevelIndex baseLevel,
9275                                                      uint32_t levelCount,
9276                                                      uint32_t baseLayer,
9277                                                      uint32_t layerCount,
9278                                                      VkImageUsageFlags imageUsageFlags)
9279 {
9280     // When we select the linear/srgb counterpart formats, we must first make sure they're
9281     // actually supported by the ICD. If they are not supported by the ICD, then we treat that as if
9282     // there is no counterpart format. (In this case, the relevant extension should not be exposed)
9283     angle::FormatID srgbOverrideFormat = ConvertToSRGB(image.getActualFormatID());
9284     ASSERT((srgbOverrideFormat == angle::FormatID::NONE) ||
9285            (HasNonRenderableTextureFormatSupport(contextVk->getRenderer(), srgbOverrideFormat)));
9286 
9287     angle::FormatID linearOverrideFormat = ConvertToLinear(image.getActualFormatID());
9288     ASSERT((linearOverrideFormat == angle::FormatID::NONE) ||
9289            (HasNonRenderableTextureFormatSupport(contextVk->getRenderer(), linearOverrideFormat)));
9290 
9291     angle::FormatID linearFormat =
9292         (linearOverrideFormat != angle::FormatID::NONE) ? linearOverrideFormat : format.id;
9293     ASSERT(linearFormat != angle::FormatID::NONE);
9294 
9295     const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(image.getIntendedFormat());
9296 
9297     if (!mPerLevelRangeLinearReadImageViews[mCurrentBaseMaxLevelHash].valid())
9298     {
9299         ANGLE_TRY(image.initReinterpretedLayerImageView(
9300             contextVk, viewType, aspectFlags, readSwizzle,
9301             &mPerLevelRangeLinearReadImageViews[mCurrentBaseMaxLevelHash], baseLevel, levelCount,
9302             baseLayer, layerCount, imageUsageFlags, linearFormat));
9303     }
9304     if (srgbOverrideFormat != angle::FormatID::NONE &&
9305         !mPerLevelRangeSRGBReadImageViews[mCurrentBaseMaxLevelHash].valid())
9306     {
9307         ANGLE_TRY(image.initReinterpretedLayerImageView(
9308             contextVk, viewType, aspectFlags, readSwizzle,
9309             &mPerLevelRangeSRGBReadImageViews[mCurrentBaseMaxLevelHash], baseLevel, levelCount,
9310             baseLayer, layerCount, imageUsageFlags, srgbOverrideFormat));
9311     }
9312 
9313     gl::TextureType fetchType = viewType;
9314 
9315     if (viewType == gl::TextureType::CubeMap || viewType == gl::TextureType::_2DArray ||
9316         viewType == gl::TextureType::_2DMultisampleArray)
9317     {
9318         fetchType = Get2DTextureType(layerCount, image.getSamples());
9319 
9320         if (!mPerLevelRangeLinearFetchImageViews[mCurrentBaseMaxLevelHash].valid())
9321         {
9322 
9323             ANGLE_TRY(image.initReinterpretedLayerImageView(
9324                 contextVk, fetchType, aspectFlags, readSwizzle,
9325                 &mPerLevelRangeLinearFetchImageViews[mCurrentBaseMaxLevelHash], baseLevel,
9326                 levelCount, baseLayer, layerCount, imageUsageFlags, linearFormat));
9327         }
9328         if (srgbOverrideFormat != angle::FormatID::NONE &&
9329             !mPerLevelRangeSRGBFetchImageViews[mCurrentBaseMaxLevelHash].valid())
9330         {
9331             ANGLE_TRY(image.initReinterpretedLayerImageView(
9332                 contextVk, fetchType, aspectFlags, readSwizzle,
9333                 &mPerLevelRangeSRGBFetchImageViews[mCurrentBaseMaxLevelHash], baseLevel, levelCount,
9334                 baseLayer, layerCount, imageUsageFlags, srgbOverrideFormat));
9335         }
9336     }
9337 
9338     if (!mPerLevelRangeLinearCopyImageViews[mCurrentBaseMaxLevelHash].valid())
9339     {
9340         ANGLE_TRY(image.initReinterpretedLayerImageView(
9341             contextVk, fetchType, aspectFlags, formatSwizzle,
9342             &mPerLevelRangeLinearCopyImageViews[mCurrentBaseMaxLevelHash], baseLevel, levelCount,
9343             baseLayer, layerCount, imageUsageFlags, linearFormat));
9344     }
9345     if (srgbOverrideFormat != angle::FormatID::NONE &&
9346         !mPerLevelRangeSRGBCopyImageViews[mCurrentBaseMaxLevelHash].valid())
9347     {
9348         ANGLE_TRY(image.initReinterpretedLayerImageView(
9349             contextVk, fetchType, aspectFlags, formatSwizzle,
9350             &mPerLevelRangeSRGBCopyImageViews[mCurrentBaseMaxLevelHash], baseLevel, levelCount,
9351             baseLayer, layerCount, imageUsageFlags, srgbOverrideFormat));
9352     }
9353 
9354     return angle::Result::Continue;
9355 }
9356 
getLevelStorageImageView(Context * context,gl::TextureType viewType,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,VkImageUsageFlags imageUsageFlags,angle::FormatID formatID,const ImageView ** imageViewOut)9357 angle::Result ImageViewHelper::getLevelStorageImageView(Context *context,
9358                                                         gl::TextureType viewType,
9359                                                         const ImageHelper &image,
9360                                                         LevelIndex levelVk,
9361                                                         uint32_t layer,
9362                                                         VkImageUsageFlags imageUsageFlags,
9363                                                         angle::FormatID formatID,
9364                                                         const ImageView **imageViewOut)
9365 {
9366     ASSERT(mImageViewSerial.valid());
9367 
9368     ImageView *imageView =
9369         GetLevelImageView(&mLevelStorageImageViews, levelVk, image.getLevelCount());
9370 
9371     *imageViewOut = imageView;
9372     if (imageView->valid())
9373     {
9374         return angle::Result::Continue;
9375     }
9376 
9377     // Create the view.  Note that storage images are not affected by swizzle parameters.
9378     return image.initReinterpretedLayerImageView(context, viewType, image.getAspectFlags(),
9379                                                  gl::SwizzleState(), imageView, levelVk, 1, layer,
9380                                                  image.getLayerCount(), imageUsageFlags, formatID);
9381 }
9382 
getLevelLayerStorageImageView(Context * contextVk,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,VkImageUsageFlags imageUsageFlags,angle::FormatID formatID,const ImageView ** imageViewOut)9383 angle::Result ImageViewHelper::getLevelLayerStorageImageView(Context *contextVk,
9384                                                              const ImageHelper &image,
9385                                                              LevelIndex levelVk,
9386                                                              uint32_t layer,
9387                                                              VkImageUsageFlags imageUsageFlags,
9388                                                              angle::FormatID formatID,
9389                                                              const ImageView **imageViewOut)
9390 {
9391     ASSERT(image.valid());
9392     ASSERT(mImageViewSerial.valid());
9393     ASSERT(!image.getActualFormat().isBlock);
9394 
9395     ImageView *imageView =
9396         GetLevelLayerImageView(&mLayerLevelStorageImageViews, levelVk, layer, image.getLevelCount(),
9397                                GetImageLayerCountForView(image));
9398     *imageViewOut = imageView;
9399 
9400     if (imageView->valid())
9401     {
9402         return angle::Result::Continue;
9403     }
9404 
9405     // Create the view.  Note that storage images are not affected by swizzle parameters.
9406     gl::TextureType viewType = Get2DTextureType(1, image.getSamples());
9407     return image.initReinterpretedLayerImageView(contextVk, viewType, image.getAspectFlags(),
9408                                                  gl::SwizzleState(), imageView, levelVk, 1, layer,
9409                                                  1, imageUsageFlags, formatID);
9410 }
9411 
getLevelDrawImageView(Context * context,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,uint32_t layerCount,gl::SrgbWriteControlMode mode,const ImageView ** imageViewOut)9412 angle::Result ImageViewHelper::getLevelDrawImageView(Context *context,
9413                                                      const ImageHelper &image,
9414                                                      LevelIndex levelVk,
9415                                                      uint32_t layer,
9416                                                      uint32_t layerCount,
9417                                                      gl::SrgbWriteControlMode mode,
9418                                                      const ImageView **imageViewOut)
9419 {
9420     ASSERT(image.valid());
9421     ASSERT(mImageViewSerial.valid());
9422     ASSERT(!image.getActualFormat().isBlock);
9423 
9424     ImageSubresourceRange range = MakeImageSubresourceDrawRange(
9425         image.toGLLevel(levelVk), layer, GetLayerMode(image, layerCount), mode);
9426 
9427     std::unique_ptr<ImageView> &view = mSubresourceDrawImageViews[range];
9428     if (view)
9429     {
9430         *imageViewOut = view.get();
9431         return angle::Result::Continue;
9432     }
9433 
9434     view          = std::make_unique<ImageView>();
9435     *imageViewOut = view.get();
9436 
9437     // Lazily allocate the image view.
9438     // Note that these views are specifically made to be used as framebuffer attachments, and
9439     // therefore don't have swizzle.
9440     gl::TextureType viewType = Get2DTextureType(layerCount, image.getSamples());
9441     return image.initLayerImageView(context, viewType, image.getAspectFlags(), gl::SwizzleState(),
9442                                     view.get(), levelVk, 1, layer, layerCount, mode);
9443 }
9444 
getLevelLayerDrawImageView(Context * context,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,gl::SrgbWriteControlMode mode,const ImageView ** imageViewOut)9445 angle::Result ImageViewHelper::getLevelLayerDrawImageView(Context *context,
9446                                                           const ImageHelper &image,
9447                                                           LevelIndex levelVk,
9448                                                           uint32_t layer,
9449                                                           gl::SrgbWriteControlMode mode,
9450                                                           const ImageView **imageViewOut)
9451 {
9452     ASSERT(image.valid());
9453     ASSERT(mImageViewSerial.valid());
9454     ASSERT(!image.getActualFormat().isBlock);
9455 
9456     LayerLevelImageViewVector &imageViews = (mode == gl::SrgbWriteControlMode::Linear)
9457                                                 ? mLayerLevelDrawImageViewsLinear
9458                                                 : mLayerLevelDrawImageViews;
9459 
9460     // Lazily allocate the storage for image views
9461     ImageView *imageView = GetLevelLayerImageView(
9462         &imageViews, levelVk, layer, image.getLevelCount(), GetImageLayerCountForView(image));
9463     *imageViewOut = imageView;
9464 
9465     if (imageView->valid())
9466     {
9467         return angle::Result::Continue;
9468     }
9469 
9470     // Lazily allocate the image view itself.
9471     // Note that these views are specifically made to be used as framebuffer attachments, and
9472     // therefore don't have swizzle.
9473     gl::TextureType viewType = Get2DTextureType(1, image.getSamples());
9474     return image.initLayerImageView(context, viewType, image.getAspectFlags(), gl::SwizzleState(),
9475                                     imageView, levelVk, 1, layer, 1, mode);
9476 }
9477 
getSubresourceSerial(gl::LevelIndex levelGL,uint32_t levelCount,uint32_t layer,LayerMode layerMode,SrgbDecodeMode srgbDecodeMode,gl::SrgbOverride srgbOverrideMode) const9478 ImageOrBufferViewSubresourceSerial ImageViewHelper::getSubresourceSerial(
9479     gl::LevelIndex levelGL,
9480     uint32_t levelCount,
9481     uint32_t layer,
9482     LayerMode layerMode,
9483     SrgbDecodeMode srgbDecodeMode,
9484     gl::SrgbOverride srgbOverrideMode) const
9485 {
9486     ASSERT(mImageViewSerial.valid());
9487 
9488     ImageOrBufferViewSubresourceSerial serial;
9489     serial.viewSerial  = mImageViewSerial;
9490     serial.subresource = MakeImageSubresourceReadRange(levelGL, levelCount, layer, layerMode,
9491                                                        srgbDecodeMode, srgbOverrideMode);
9492     return serial;
9493 }
9494 
MakeImageSubresourceReadRange(gl::LevelIndex level,uint32_t levelCount,uint32_t layer,LayerMode layerMode,SrgbDecodeMode srgbDecodeMode,gl::SrgbOverride srgbOverrideMode)9495 ImageSubresourceRange MakeImageSubresourceReadRange(gl::LevelIndex level,
9496                                                     uint32_t levelCount,
9497                                                     uint32_t layer,
9498                                                     LayerMode layerMode,
9499                                                     SrgbDecodeMode srgbDecodeMode,
9500                                                     gl::SrgbOverride srgbOverrideMode)
9501 {
9502     ImageSubresourceRange range;
9503 
9504     SetBitField(range.level, level.get());
9505     SetBitField(range.levelCount, levelCount);
9506     SetBitField(range.layer, layer);
9507     SetBitField(range.layerMode, layerMode);
9508     SetBitField(range.srgbDecodeMode, srgbDecodeMode);
9509     SetBitField(range.srgbMode, srgbOverrideMode);
9510 
9511     return range;
9512 }
9513 
MakeImageSubresourceDrawRange(gl::LevelIndex level,uint32_t layer,LayerMode layerMode,gl::SrgbWriteControlMode srgbWriteControlMode)9514 ImageSubresourceRange MakeImageSubresourceDrawRange(gl::LevelIndex level,
9515                                                     uint32_t layer,
9516                                                     LayerMode layerMode,
9517                                                     gl::SrgbWriteControlMode srgbWriteControlMode)
9518 {
9519     ImageSubresourceRange range;
9520 
9521     SetBitField(range.level, level.get());
9522     SetBitField(range.levelCount, 1);
9523     SetBitField(range.layer, layer);
9524     SetBitField(range.layerMode, layerMode);
9525     SetBitField(range.srgbDecodeMode, 0);
9526     SetBitField(range.srgbMode, srgbWriteControlMode);
9527 
9528     return range;
9529 }
9530 
9531 // BufferViewHelper implementation.
BufferViewHelper()9532 BufferViewHelper::BufferViewHelper() : mOffset(0), mSize(0) {}
9533 
BufferViewHelper(BufferViewHelper && other)9534 BufferViewHelper::BufferViewHelper(BufferViewHelper &&other) : Resource(std::move(other))
9535 {
9536     std::swap(mOffset, other.mOffset);
9537     std::swap(mSize, other.mSize);
9538     std::swap(mViews, other.mViews);
9539     std::swap(mViewSerial, other.mViewSerial);
9540 }
9541 
~BufferViewHelper()9542 BufferViewHelper::~BufferViewHelper() {}
9543 
init(RendererVk * renderer,VkDeviceSize offset,VkDeviceSize size)9544 void BufferViewHelper::init(RendererVk *renderer, VkDeviceSize offset, VkDeviceSize size)
9545 {
9546     ASSERT(mViews.empty());
9547 
9548     mOffset = offset;
9549     mSize   = size;
9550 
9551     if (!mViewSerial.valid())
9552     {
9553         mViewSerial = renderer->getResourceSerialFactory().generateImageOrBufferViewSerial();
9554     }
9555 }
9556 
release(ContextVk * contextVk)9557 void BufferViewHelper::release(ContextVk *contextVk)
9558 {
9559     contextVk->flushDescriptorSetUpdates();
9560 
9561     std::vector<GarbageObject> garbage;
9562 
9563     for (auto &formatAndView : mViews)
9564     {
9565         BufferView &view = formatAndView.second;
9566         ASSERT(view.valid());
9567 
9568         garbage.emplace_back(GetGarbage(&view));
9569     }
9570 
9571     if (!garbage.empty())
9572     {
9573         RendererVk *rendererVk = contextVk->getRenderer();
9574         rendererVk->collectGarbage(std::move(mUse), std::move(garbage));
9575 
9576         // Ensure the resource use is always valid.
9577         mUse.init();
9578 
9579         // Update image view serial.
9580         mViewSerial = rendererVk->getResourceSerialFactory().generateImageOrBufferViewSerial();
9581     }
9582 
9583     mViews.clear();
9584 
9585     mOffset = 0;
9586     mSize   = 0;
9587 }
9588 
destroy(VkDevice device)9589 void BufferViewHelper::destroy(VkDevice device)
9590 {
9591     for (auto &formatAndView : mViews)
9592     {
9593         BufferView &view = formatAndView.second;
9594         view.destroy(device);
9595     }
9596 
9597     mViews.clear();
9598 
9599     mOffset = 0;
9600     mSize   = 0;
9601 
9602     mViewSerial = kInvalidImageOrBufferViewSerial;
9603 }
9604 
getView(Context * context,const BufferHelper & buffer,VkDeviceSize bufferOffset,const Format & format,const BufferView ** viewOut)9605 angle::Result BufferViewHelper::getView(Context *context,
9606                                         const BufferHelper &buffer,
9607                                         VkDeviceSize bufferOffset,
9608                                         const Format &format,
9609                                         const BufferView **viewOut)
9610 {
9611     ASSERT(format.valid());
9612 
9613     VkFormat viewVkFormat = format.getActualBufferVkFormat(false);
9614 
9615     auto iter = mViews.find(viewVkFormat);
9616     if (iter != mViews.end())
9617     {
9618         *viewOut = &iter->second;
9619         return angle::Result::Continue;
9620     }
9621 
9622     // If the size is not a multiple of pixelBytes, remove the extra bytes.  The last element cannot
9623     // be read anyway, and this is a requirement of Vulkan (for size to be a multiple of format
9624     // texel block size).
9625     const angle::Format &bufferFormat = format.getActualBufferFormat(false);
9626     const GLuint pixelBytes           = bufferFormat.pixelBytes;
9627     VkDeviceSize size                 = mSize - mSize % pixelBytes;
9628 
9629     VkBufferViewCreateInfo viewCreateInfo = {};
9630     viewCreateInfo.sType                  = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
9631     viewCreateInfo.buffer                 = buffer.getBuffer().getHandle();
9632     viewCreateInfo.format                 = viewVkFormat;
9633     viewCreateInfo.offset                 = mOffset + bufferOffset;
9634     viewCreateInfo.range                  = size;
9635 
9636     BufferView view;
9637     ANGLE_VK_TRY(context, view.init(context->getDevice(), viewCreateInfo));
9638 
9639     // Cache the view
9640     auto insertIter = mViews.insert({viewVkFormat, std::move(view)});
9641     *viewOut        = &insertIter.first->second;
9642     ASSERT(insertIter.second);
9643 
9644     return angle::Result::Continue;
9645 }
9646 
getSerial() const9647 ImageOrBufferViewSubresourceSerial BufferViewHelper::getSerial() const
9648 {
9649     ASSERT(mViewSerial.valid());
9650 
9651     ImageOrBufferViewSubresourceSerial serial = {};
9652     serial.viewSerial                         = mViewSerial;
9653     return serial;
9654 }
9655 
9656 // ShaderProgramHelper implementation.
ShaderProgramHelper()9657 ShaderProgramHelper::ShaderProgramHelper() : mSpecializationConstants{} {}
9658 
9659 ShaderProgramHelper::~ShaderProgramHelper() = default;
9660 
valid(const gl::ShaderType shaderType) const9661 bool ShaderProgramHelper::valid(const gl::ShaderType shaderType) const
9662 {
9663     return mShaders[shaderType].valid();
9664 }
9665 
destroy(RendererVk * rendererVk)9666 void ShaderProgramHelper::destroy(RendererVk *rendererVk)
9667 {
9668     mGraphicsPipelines.destroy(rendererVk);
9669     mComputePipeline.destroy(rendererVk->getDevice());
9670     for (BindingPointer<ShaderAndSerial> &shader : mShaders)
9671     {
9672         shader.reset();
9673     }
9674 }
9675 
release(ContextVk * contextVk)9676 void ShaderProgramHelper::release(ContextVk *contextVk)
9677 {
9678     mGraphicsPipelines.release(contextVk);
9679     contextVk->addGarbage(&mComputePipeline.getPipeline());
9680     for (BindingPointer<ShaderAndSerial> &shader : mShaders)
9681     {
9682         shader.reset();
9683     }
9684 }
9685 
setShader(gl::ShaderType shaderType,RefCounted<ShaderAndSerial> * shader)9686 void ShaderProgramHelper::setShader(gl::ShaderType shaderType, RefCounted<ShaderAndSerial> *shader)
9687 {
9688     mShaders[shaderType].set(shader);
9689 }
9690 
setSpecializationConstant(sh::vk::SpecializationConstantId id,uint32_t value)9691 void ShaderProgramHelper::setSpecializationConstant(sh::vk::SpecializationConstantId id,
9692                                                     uint32_t value)
9693 {
9694     ASSERT(id < sh::vk::SpecializationConstantId::EnumCount);
9695     switch (id)
9696     {
9697         case sh::vk::SpecializationConstantId::LineRasterEmulation:
9698             mSpecializationConstants.lineRasterEmulation = value;
9699             break;
9700         case sh::vk::SpecializationConstantId::SurfaceRotation:
9701             mSpecializationConstants.surfaceRotation = value;
9702             break;
9703         case sh::vk::SpecializationConstantId::DrawableWidth:
9704             mSpecializationConstants.drawableWidth = static_cast<float>(value);
9705             break;
9706         case sh::vk::SpecializationConstantId::DrawableHeight:
9707             mSpecializationConstants.drawableHeight = static_cast<float>(value);
9708             break;
9709         case sh::vk::SpecializationConstantId::Dither:
9710             mSpecializationConstants.dither = value;
9711             break;
9712         default:
9713             UNREACHABLE();
9714             break;
9715     }
9716 }
9717 
getComputePipeline(Context * context,const PipelineLayout & pipelineLayout,PipelineHelper ** pipelineOut)9718 angle::Result ShaderProgramHelper::getComputePipeline(Context *context,
9719                                                       const PipelineLayout &pipelineLayout,
9720                                                       PipelineHelper **pipelineOut)
9721 {
9722     if (mComputePipeline.valid())
9723     {
9724         *pipelineOut = &mComputePipeline;
9725         return angle::Result::Continue;
9726     }
9727 
9728     RendererVk *renderer = context->getRenderer();
9729 
9730     VkPipelineShaderStageCreateInfo shaderStage = {};
9731     VkComputePipelineCreateInfo createInfo      = {};
9732 
9733     shaderStage.sType               = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
9734     shaderStage.flags               = 0;
9735     shaderStage.stage               = VK_SHADER_STAGE_COMPUTE_BIT;
9736     shaderStage.module              = mShaders[gl::ShaderType::Compute].get().get().getHandle();
9737     shaderStage.pName               = "main";
9738     shaderStage.pSpecializationInfo = nullptr;
9739 
9740     createInfo.sType              = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
9741     createInfo.flags              = 0;
9742     createInfo.stage              = shaderStage;
9743     createInfo.layout             = pipelineLayout.getHandle();
9744     createInfo.basePipelineHandle = VK_NULL_HANDLE;
9745     createInfo.basePipelineIndex  = 0;
9746 
9747     PipelineCache *pipelineCache = nullptr;
9748     ANGLE_TRY(renderer->getPipelineCache(&pipelineCache));
9749     ANGLE_VK_TRY(context, mComputePipeline.getPipeline().initCompute(context->getDevice(),
9750                                                                      createInfo, *pipelineCache));
9751 
9752     *pipelineOut = &mComputePipeline;
9753     return angle::Result::Continue;
9754 }
9755 
9756 // ActiveHandleCounter implementation.
ActiveHandleCounter()9757 ActiveHandleCounter::ActiveHandleCounter() : mActiveCounts{}, mAllocatedCounts{} {}
9758 
9759 ActiveHandleCounter::~ActiveHandleCounter() = default;
9760 
9761 // CommandBufferAccess implementation.
9762 CommandBufferAccess::CommandBufferAccess()  = default;
9763 CommandBufferAccess::~CommandBufferAccess() = default;
9764 
onBufferRead(VkAccessFlags readAccessType,PipelineStage readStage,BufferHelper * buffer)9765 void CommandBufferAccess::onBufferRead(VkAccessFlags readAccessType,
9766                                        PipelineStage readStage,
9767                                        BufferHelper *buffer)
9768 {
9769     ASSERT(!buffer->isReleasedToExternal());
9770     mReadBuffers.emplace_back(buffer, readAccessType, readStage);
9771 }
9772 
onBufferWrite(VkAccessFlags writeAccessType,PipelineStage writeStage,BufferHelper * buffer)9773 void CommandBufferAccess::onBufferWrite(VkAccessFlags writeAccessType,
9774                                         PipelineStage writeStage,
9775                                         BufferHelper *buffer)
9776 {
9777     ASSERT(!buffer->isReleasedToExternal());
9778     mWriteBuffers.emplace_back(buffer, writeAccessType, writeStage);
9779 }
9780 
onImageRead(VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)9781 void CommandBufferAccess::onImageRead(VkImageAspectFlags aspectFlags,
9782                                       ImageLayout imageLayout,
9783                                       ImageHelper *image)
9784 {
9785     ASSERT(!image->isReleasedToExternal());
9786     ASSERT(image->getImageSerial().valid());
9787     mReadImages.emplace_back(image, aspectFlags, imageLayout);
9788 }
9789 
onImageWrite(gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)9790 void CommandBufferAccess::onImageWrite(gl::LevelIndex levelStart,
9791                                        uint32_t levelCount,
9792                                        uint32_t layerStart,
9793                                        uint32_t layerCount,
9794                                        VkImageAspectFlags aspectFlags,
9795                                        ImageLayout imageLayout,
9796                                        ImageHelper *image)
9797 {
9798     ASSERT(!image->isReleasedToExternal());
9799     ASSERT(image->getImageSerial().valid());
9800     mWriteImages.emplace_back(CommandBufferImageAccess{image, aspectFlags, imageLayout}, levelStart,
9801                               levelCount, layerStart, layerCount);
9802 }
9803 
9804 }  // namespace vk
9805 }  // namespace rx
9806