• 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/Display.h"
16 #include "libANGLE/renderer/driver_utils.h"
17 #include "libANGLE/renderer/renderer_utils.h"
18 #include "libANGLE/renderer/vulkan/BufferVk.h"
19 #include "libANGLE/renderer/vulkan/ContextVk.h"
20 #include "libANGLE/renderer/vulkan/DisplayVk.h"
21 #include "libANGLE/renderer/vulkan/FramebufferVk.h"
22 #include "libANGLE/renderer/vulkan/RenderTargetVk.h"
23 #include "libANGLE/renderer/vulkan/android/vk_android_utils.h"
24 #include "libANGLE/renderer/vulkan/vk_ref_counted_event.h"
25 #include "libANGLE/renderer/vulkan/vk_renderer.h"
26 #include "libANGLE/renderer/vulkan/vk_utils.h"
27 
28 namespace rx
29 {
30 namespace vk
31 {
32 namespace
33 {
34 // ANGLE_robust_resource_initialization requires color textures to be initialized to zero.
35 constexpr VkClearColorValue kRobustInitColorValue = {{0, 0, 0, 0}};
36 // When emulating a texture, we want the emulated channels to be 0, with alpha 1.
37 constexpr VkClearColorValue kEmulatedInitColorValue = {{0, 0, 0, 1.0f}};
38 // ANGLE_robust_resource_initialization requires depth to be initialized to 1 and stencil to 0.
39 // We are fine with these values for emulated depth/stencil textures too.
40 constexpr VkClearDepthStencilValue kRobustInitDepthStencilValue = {1.0f, 0};
41 
42 constexpr VkImageAspectFlags kDepthStencilAspects =
43     VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_DEPTH_BIT;
44 
45 constexpr angle::PackedEnumMap<PipelineStage, VkPipelineStageFlagBits> kPipelineStageFlagBitMap = {
46     {PipelineStage::TopOfPipe, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT},
47     {PipelineStage::DrawIndirect, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT},
48     {PipelineStage::VertexInput, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT},
49     {PipelineStage::VertexShader, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT},
50     {PipelineStage::TessellationControl, VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT},
51     {PipelineStage::TessellationEvaluation, VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT},
52     {PipelineStage::GeometryShader, VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT},
53     {PipelineStage::TransformFeedback, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT},
54     {PipelineStage::FragmentShadingRate,
55      VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR},
56     {PipelineStage::EarlyFragmentTest, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT},
57     {PipelineStage::FragmentShader, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT},
58     {PipelineStage::LateFragmentTest, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT},
59     {PipelineStage::ColorAttachmentOutput, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT},
60     {PipelineStage::ComputeShader, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT},
61     {PipelineStage::Transfer, VK_PIPELINE_STAGE_TRANSFER_BIT},
62     {PipelineStage::BottomOfPipe, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT},
63     {PipelineStage::Host, VK_PIPELINE_STAGE_HOST_BIT}};
64 
65 constexpr gl::ShaderMap<PipelineStage> kPipelineStageShaderMap = {
66     {gl::ShaderType::Vertex, PipelineStage::VertexShader},
67     {gl::ShaderType::TessControl, PipelineStage::TessellationControl},
68     {gl::ShaderType::TessEvaluation, PipelineStage::TessellationEvaluation},
69     {gl::ShaderType::Geometry, PipelineStage::GeometryShader},
70     {gl::ShaderType::Fragment, PipelineStage::FragmentShader},
71     {gl::ShaderType::Compute, PipelineStage::ComputeShader},
72 };
73 
74 // clang-format off
75 constexpr angle::PackedEnumMap<ImageLayout, ImageMemoryBarrierData> kImageMemoryBarrierData = {
76     {
77         ImageLayout::Undefined,
78         ImageMemoryBarrierData{
79             "Undefined",
80             VK_IMAGE_LAYOUT_UNDEFINED,
81             VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
82             VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
83             // Transition to: we don't expect to transition into Undefined.
84             0,
85             // Transition from: there's no data in the image to care about.
86             0,
87             ResourceAccess::ReadOnly,
88             PipelineStage::InvalidEnum,
89             // We do not directly using this layout in SetEvent. We transit to other layout before using
90             EventStage::InvalidEnum,
91         },
92     },
93     {
94         ImageLayout::ColorWrite,
95         ImageMemoryBarrierData{
96             "ColorWrite",
97             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
98             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
99             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
100             // Transition to: all reads and writes must happen after barrier.
101             VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
102             // Transition from: all writes must finish before barrier.
103             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
104             ResourceAccess::ReadWrite,
105             PipelineStage::ColorAttachmentOutput,
106             EventStage::ColorAttachmentOutput,
107         },
108     },
109     {
110         ImageLayout::MSRTTEmulationColorUnresolveAndResolve,
111         ImageMemoryBarrierData{
112             "MSRTTEmulationColorUnresolveAndResolve",
113             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
114             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
115             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
116             // Transition to: all reads and writes must happen after barrier.
117             VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
118             // Transition from: all writes must finish before barrier.
119             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
120             ResourceAccess::ReadWrite,
121             PipelineStage::FragmentShader,
122             EventStage::ColorAttachmentOutputAndFragmentShader,
123         },
124     },
125     {
126         ImageLayout::DepthWriteStencilWrite,
127         ImageMemoryBarrierData{
128             "DepthWriteStencilWrite",
129             VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
130             kAllDepthStencilPipelineStageFlags,
131             kAllDepthStencilPipelineStageFlags,
132             // Transition to: all reads and writes must happen after barrier.
133             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
134             // Transition from: all writes must finish before barrier.
135             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
136             ResourceAccess::ReadWrite,
137             PipelineStage::EarlyFragmentTest,
138             EventStage::AllFragmentTest,
139         },
140     },
141     {
142         ImageLayout::DepthWriteStencilRead,
143         ImageMemoryBarrierData{
144             "DepthWriteStencilRead",
145             VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL,
146             kAllDepthStencilPipelineStageFlags,
147             kAllDepthStencilPipelineStageFlags,
148             // Transition to: all reads and writes must happen after barrier.
149             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
150             // Transition from: all writes must finish before barrier.
151             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
152             ResourceAccess::ReadWrite,
153             PipelineStage::EarlyFragmentTest,
154             EventStage::AllFragmentTest,
155         },
156     },
157     {
158         ImageLayout::DepthWriteStencilReadFragmentShaderStencilRead,
159         ImageMemoryBarrierData{
160             "DepthWriteStencilReadFragmentShaderStencilRead",
161             VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL,
162             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
163             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
164             // Transition to: all reads and writes must happen after barrier.
165             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
166             // Transition from: all writes must finish before barrier.
167             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
168             ResourceAccess::ReadWrite,
169             PipelineStage::EarlyFragmentTest,
170             EventStage::AllFragmentTestAndFragmentShader,
171         },
172     },
173     {
174         ImageLayout::DepthWriteStencilReadAllShadersStencilRead,
175         ImageMemoryBarrierData{
176             "DepthWriteStencilReadAllShadersStencilRead",
177             VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL,
178             kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
179             kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
180             // Transition to: all reads and writes must happen after barrier.
181             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
182             // Transition from: all writes must finish before barrier.
183             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
184             ResourceAccess::ReadWrite,
185             PipelineStage::VertexShader,
186             EventStage::AllFragmentTestAndAllShaders,
187         },
188     },
189     {
190         ImageLayout::DepthReadStencilWrite,
191         ImageMemoryBarrierData{
192             "DepthReadStencilWrite",
193             VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL,
194             kAllDepthStencilPipelineStageFlags,
195             kAllDepthStencilPipelineStageFlags,
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,
198             // Transition from: all writes must finish before barrier.
199             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
200             ResourceAccess::ReadWrite,
201             PipelineStage::EarlyFragmentTest,
202             EventStage::AllFragmentTest,
203         },
204     },
205     {
206         ImageLayout::DepthReadStencilWriteFragmentShaderDepthRead,
207         ImageMemoryBarrierData{
208             "DepthReadStencilWriteFragmentShaderDepthRead",
209             VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL,
210             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
211             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
212             // Transition to: all reads and writes must happen after barrier.
213             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
214             // Transition from: all writes must finish before barrier.
215             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
216             ResourceAccess::ReadWrite,
217             PipelineStage::EarlyFragmentTest,
218             EventStage::AllFragmentTestAndFragmentShader,
219         },
220     },
221     {
222         ImageLayout::DepthReadStencilWriteAllShadersDepthRead,
223         ImageMemoryBarrierData{
224             "DepthReadStencilWriteAllShadersDepthRead",
225             VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL,
226             kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
227             kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
228             // Transition to: all reads and writes must happen after barrier.
229             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
230             // Transition from: all writes must finish before barrier.
231             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
232             ResourceAccess::ReadWrite,
233             PipelineStage::VertexShader,
234             EventStage::AllFragmentTestAndAllShaders,
235         },
236     },
237     {
238         ImageLayout::DepthReadStencilRead,
239             ImageMemoryBarrierData{
240             "DepthReadStencilRead",
241             VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
242             kAllDepthStencilPipelineStageFlags,
243             kAllDepthStencilPipelineStageFlags,
244             // Transition to: all reads must happen after barrier.
245             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
246             // Transition from: RAR and WAR don't need memory barrier.
247             0,
248             ResourceAccess::ReadOnly,
249             PipelineStage::EarlyFragmentTest,
250             EventStage::AllFragmentTest,
251         },
252     },
253 
254     {
255         ImageLayout::DepthReadStencilReadFragmentShaderRead,
256             ImageMemoryBarrierData{
257             "DepthReadStencilReadFragmentShaderRead",
258             VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
259             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
260             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
261             // Transition to: all reads must happen after barrier.
262             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
263             // Transition from: RAR and WAR don't need memory barrier.
264             0,
265             ResourceAccess::ReadOnly,
266             PipelineStage::EarlyFragmentTest,
267             EventStage::AllFragmentTestAndFragmentShader,
268         },
269     },
270     {
271         ImageLayout::DepthReadStencilReadAllShadersRead,
272             ImageMemoryBarrierData{
273             "DepthReadStencilReadAllShadersRead",
274             VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
275             kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
276             kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
277             // Transition to: all reads must happen after barrier.
278             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
279             // Transition from: RAR and WAR don't need memory barrier.
280             0,
281             ResourceAccess::ReadOnly,
282             PipelineStage::VertexShader,
283             EventStage::AllFragmentTestAndAllShaders,
284         },
285     },
286     {
287         ImageLayout::ColorWriteFragmentShaderFeedback,
288         ImageMemoryBarrierData{
289             "ColorWriteFragmentShaderFeedback",
290             VK_IMAGE_LAYOUT_GENERAL,
291             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
292             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
293             // Transition to: all reads and writes must happen after barrier.
294             VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
295             // Transition from: all writes must finish before barrier.
296             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
297             ResourceAccess::ReadWrite,
298             PipelineStage::FragmentShader,
299             EventStage::ColorAttachmentOutputAndFragmentShader,
300         },
301     },
302     {
303         ImageLayout::ColorWriteAllShadersFeedback,
304         ImageMemoryBarrierData{
305             "ColorWriteAllShadersFeedback",
306             VK_IMAGE_LAYOUT_GENERAL,
307             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | kAllShadersPipelineStageFlags,
308             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | kAllShadersPipelineStageFlags,
309             // Transition to: all reads and writes must happen after barrier.
310             VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
311             // Transition from: all writes must finish before barrier.
312             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
313             ResourceAccess::ReadWrite,
314             // In case of multiple destination stages, We barrier the earliest stage
315             PipelineStage::VertexShader,
316             EventStage::ColorAttachmentOutputAndAllShaders,
317         },
318     },
319     {
320         ImageLayout::DepthStencilFragmentShaderFeedback,
321         ImageMemoryBarrierData{
322             "DepthStencilFragmentShaderFeedback",
323             VK_IMAGE_LAYOUT_GENERAL,
324             kAllDepthStencilPipelineStageFlags | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
325             kAllDepthStencilPipelineStageFlags | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
326             // Transition to: all reads and writes must happen after barrier.
327             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
328             // Transition from: all writes must finish before barrier.
329             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
330             ResourceAccess::ReadWrite,
331             PipelineStage::FragmentShader,
332             EventStage::AllFragmentTestAndFragmentShader,
333         },
334     },
335     {
336         ImageLayout::DepthStencilAllShadersFeedback,
337         ImageMemoryBarrierData{
338             "DepthStencilAllShadersFeedback",
339             VK_IMAGE_LAYOUT_GENERAL,
340             kAllDepthStencilPipelineStageFlags | kAllShadersPipelineStageFlags,
341             kAllDepthStencilPipelineStageFlags | kAllShadersPipelineStageFlags,
342             // Transition to: all reads and writes must happen after barrier.
343             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
344             // Transition from: all writes must finish before barrier.
345             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
346             ResourceAccess::ReadWrite,
347             // In case of multiple destination stages, We barrier the earliest stage
348             PipelineStage::VertexShader,
349             EventStage::AllFragmentTestAndAllShaders,
350         },
351     },
352     {
353         ImageLayout::DepthStencilResolve,
354         ImageMemoryBarrierData{
355             "DepthStencilResolve",
356             VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
357             // Note: depth/stencil resolve uses color output stage and mask!
358             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
359             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
360             // Transition to: all reads and writes must happen after barrier.
361             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
362             // Transition from: all writes must finish before barrier.
363             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
364             ResourceAccess::ReadWrite,
365             PipelineStage::ColorAttachmentOutput,
366             EventStage::ColorAttachmentOutput,
367         },
368     },
369     {
370         ImageLayout::MSRTTEmulationDepthStencilUnresolveAndResolve,
371         ImageMemoryBarrierData{
372             "MSRTTEmulationDepthStencilUnresolveAndResolve",
373             VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
374             // Note: depth/stencil resolve uses color output stage and mask!
375             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
376             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
377             // Transition to: all reads and writes must happen after barrier.
378             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
379             // Transition from: all writes must finish before barrier.
380             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
381             ResourceAccess::ReadWrite,
382             PipelineStage::FragmentShader,
383             EventStage::ColorAttachmentOutputAndFragmentShader,
384         },
385     },
386     {
387         ImageLayout::Present,
388         ImageMemoryBarrierData{
389             "Present",
390             VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
391             // Transition to: do not delay execution of commands in the second synchronization
392             // scope. Allow layout transition to be delayed until present semaphore is signaled.
393             VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
394             // Transition from: use same stages as in Acquire Image Semaphore stage mask in order to
395             // build a dependency chain from the Acquire Image Semaphore to the layout transition's
396             // first synchronization scope.
397             kSwapchainAcquireImageWaitStageFlags,
398             // Transition to: vkQueuePresentKHR automatically performs the appropriate memory barriers:
399             //
400             // > Any writes to memory backing the images referenced by the pImageIndices and
401             // > pSwapchains members of pPresentInfo, that are available before vkQueuePresentKHR
402             // > is executed, are automatically made visible to the read access performed by the
403             // > presentation engine.
404             0,
405             // Transition from: RAR and WAR don't need memory barrier.
406             0,
407             ResourceAccess::ReadOnly,
408             PipelineStage::BottomOfPipe,
409             // We do not directly using this layout in SetEvent.
410             EventStage::InvalidEnum,
411         },
412     },
413     {
414         ImageLayout::SharedPresent,
415         ImageMemoryBarrierData{
416             "SharedPresent",
417             VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR,
418             // All currently possible stages for SharedPresent
419             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
420             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
421             // Transition to: all reads and writes must happen after barrier.
422             VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
423             // Transition from: all writes must finish before barrier.
424             VK_ACCESS_MEMORY_WRITE_BIT,
425             ResourceAccess::ReadWrite,
426             PipelineStage::BottomOfPipe,
427             EventStage::ColorAttachmentOutputAndFragmentShaderAndTransfer,
428         },
429     },
430     {
431         ImageLayout::ExternalPreInitialized,
432         ImageMemoryBarrierData{
433             "ExternalPreInitialized",
434             // Binding a VkImage with an initial layout of VK_IMAGE_LAYOUT_UNDEFINED to external
435             // memory whose content has already been defined does not make the content undefined
436             // (see 12.8.1.  External Resource Sharing).
437             //
438             // Note that for external memory objects, if the content is already defined, the
439             // ownership rules imply that the first operation on the texture must be a call to
440             // glWaitSemaphoreEXT that grants ownership of the image and informs us of the true
441             // layout.  If the content is not already defined, the first operation may not be a
442             // glWaitSemaphore, but in this case undefined layout is appropriate.
443             VK_IMAGE_LAYOUT_UNDEFINED,
444             VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
445             VK_PIPELINE_STAGE_HOST_BIT | VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
446             // Transition to: we don't expect to transition into PreInitialized.
447             0,
448             // Transition from: all writes must finish before barrier.
449             VK_ACCESS_MEMORY_WRITE_BIT,
450             ResourceAccess::ReadOnly,
451             PipelineStage::InvalidEnum,
452             // We do not directly using this layout in SetEvent. We transit to internal layout before using
453             EventStage::InvalidEnum,
454         },
455     },
456     {
457         ImageLayout::ExternalShadersReadOnly,
458         ImageMemoryBarrierData{
459             "ExternalShadersReadOnly",
460             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
461             VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
462             VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
463             // Transition to: all reads must happen after barrier.
464             VK_ACCESS_SHADER_READ_BIT,
465             // Transition from: RAR and WAR don't need memory barrier.
466             0,
467             ResourceAccess::ReadOnly,
468             // In case of multiple destination stages, We barrier the earliest stage
469             PipelineStage::TopOfPipe,
470             // We do not directly using this layout in SetEvent. We transit to internal layout before using
471             EventStage::InvalidEnum,
472         },
473     },
474     {
475         ImageLayout::ExternalShadersWrite,
476         ImageMemoryBarrierData{
477             "ExternalShadersWrite",
478             VK_IMAGE_LAYOUT_GENERAL,
479             VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
480             VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
481             // Transition to: all reads and writes must happen after barrier.
482             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
483             // Transition from: all writes must finish before barrier.
484             VK_ACCESS_SHADER_WRITE_BIT,
485             ResourceAccess::ReadWrite,
486             // In case of multiple destination stages, We barrier the earliest stage
487             PipelineStage::TopOfPipe,
488             // We do not directly using this layout in SetEvent. We transit to internal layout before using
489             EventStage::InvalidEnum,
490         },
491     },
492     {
493         ImageLayout::TransferSrc,
494         ImageMemoryBarrierData{
495             "TransferSrc",
496             VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
497             VK_PIPELINE_STAGE_TRANSFER_BIT,
498             VK_PIPELINE_STAGE_TRANSFER_BIT,
499             // Transition to: all reads must happen after barrier.
500             VK_ACCESS_TRANSFER_READ_BIT,
501             // Transition from: RAR and WAR don't need memory barrier.
502             0,
503             ResourceAccess::ReadOnly,
504             PipelineStage::Transfer,
505             EventStage::Transfer,
506         },
507     },
508     {
509         ImageLayout::TransferDst,
510         ImageMemoryBarrierData{
511             "TransferDst",
512             VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
513             VK_PIPELINE_STAGE_TRANSFER_BIT,
514             VK_PIPELINE_STAGE_TRANSFER_BIT,
515             // Transition to: all writes must happen after barrier.
516             VK_ACCESS_TRANSFER_WRITE_BIT,
517             // Transition from: all writes must finish before barrier.
518             VK_ACCESS_TRANSFER_WRITE_BIT,
519             ResourceAccess::ReadWrite,
520             PipelineStage::Transfer,
521             EventStage::Transfer,
522         },
523     },
524     {
525         ImageLayout::TransferSrcDst,
526         ImageMemoryBarrierData{
527             "TransferSrcDst",
528             VK_IMAGE_LAYOUT_GENERAL,
529             VK_PIPELINE_STAGE_TRANSFER_BIT,
530             VK_PIPELINE_STAGE_TRANSFER_BIT,
531             // Transition to: all reads and writes must happen after barrier.
532             VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
533             // Transition from: all writes must finish before barrier.
534             VK_ACCESS_TRANSFER_WRITE_BIT,
535             ResourceAccess::ReadWrite,
536             PipelineStage::Transfer,
537             EventStage::Transfer,
538         },
539     },
540     {
541         ImageLayout::HostCopy,
542         ImageMemoryBarrierData{
543             "HostCopy",
544             VK_IMAGE_LAYOUT_GENERAL,
545             VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
546             VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
547             // Transition to: we don't expect to transition into HostCopy on the GPU.
548             0,
549             // Transition from: the data was initialized in the image by the host.  Note that we
550             // only transition to this layout if the image was previously in UNDEFINED, in which
551             // case it didn't contain any data prior to the host copy either.
552             0,
553             ResourceAccess::ReadOnly,
554             PipelineStage::InvalidEnum,
555             // We do not directly using this layout in SetEvent.
556             EventStage::InvalidEnum,
557         },
558     },
559     {
560         ImageLayout::VertexShaderReadOnly,
561         ImageMemoryBarrierData{
562             "VertexShaderReadOnly",
563             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
564             VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
565             VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
566             // Transition to: all reads must happen after barrier.
567             VK_ACCESS_SHADER_READ_BIT,
568             // Transition from: RAR and WAR don't need memory barrier.
569             0,
570             ResourceAccess::ReadOnly,
571             PipelineStage::VertexShader,
572             EventStage::VertexShader,
573         },
574     },
575     {
576         ImageLayout::VertexShaderWrite,
577         ImageMemoryBarrierData{
578             "VertexShaderWrite",
579             VK_IMAGE_LAYOUT_GENERAL,
580             VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
581             VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
582             // Transition to: all reads and writes must happen after barrier.
583             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
584             // Transition from: all writes must finish before barrier.
585             VK_ACCESS_SHADER_WRITE_BIT,
586             ResourceAccess::ReadWrite,
587             PipelineStage::VertexShader,
588             EventStage::VertexShader,
589         },
590     },
591     {
592         ImageLayout::PreFragmentShadersReadOnly,
593         ImageMemoryBarrierData{
594             "PreFragmentShadersReadOnly",
595             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
596             kPreFragmentStageFlags,
597             kPreFragmentStageFlags,
598             // Transition to: all reads must happen after barrier.
599             VK_ACCESS_SHADER_READ_BIT,
600             // Transition from: RAR and WAR don't need memory barrier.
601             0,
602             ResourceAccess::ReadOnly,
603             // In case of multiple destination stages, We barrier the earliest stage
604             PipelineStage::VertexShader,
605             EventStage::PreFragmentShaders,
606         },
607     },
608     {
609         ImageLayout::PreFragmentShadersWrite,
610         ImageMemoryBarrierData{
611             "PreFragmentShadersWrite",
612             VK_IMAGE_LAYOUT_GENERAL,
613             kPreFragmentStageFlags,
614             kPreFragmentStageFlags,
615             // Transition to: all reads and writes must happen after barrier.
616             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
617             // Transition from: all writes must finish before barrier.
618             VK_ACCESS_SHADER_WRITE_BIT,
619             ResourceAccess::ReadWrite,
620             // In case of multiple destination stages, We barrier the earliest stage
621             PipelineStage::VertexShader,
622             EventStage::PreFragmentShaders,
623         },
624     },
625     {
626         ImageLayout::FragmentShadingRateAttachmentReadOnly,
627         ImageMemoryBarrierData{
628             "FragmentShadingRateAttachmentReadOnly",
629             VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR,
630             VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR,
631             VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR,
632             // Transition to: all reads must happen after barrier.
633             VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR,
634             // Transition from: RAR and WAR don't need memory barrier.
635             0,
636             ResourceAccess::ReadOnly,
637             PipelineStage::FragmentShadingRate,
638             EventStage::FragmentShadingRate,
639         },
640     },
641     {
642         ImageLayout::FragmentShaderReadOnly,
643         ImageMemoryBarrierData{
644             "FragmentShaderReadOnly",
645             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
646             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
647             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
648             // Transition to: all reads must happen after barrier.
649             VK_ACCESS_SHADER_READ_BIT,
650             // Transition from: RAR and WAR don't need memory barrier.
651             0,
652             ResourceAccess::ReadOnly,
653             PipelineStage::FragmentShader,
654             EventStage::FragmentShader,
655         },
656     },
657     {
658         ImageLayout::FragmentShaderWrite,
659         ImageMemoryBarrierData{
660             "FragmentShaderWrite",
661             VK_IMAGE_LAYOUT_GENERAL,
662             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
663             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
664             // Transition to: all reads and writes must happen after barrier.
665             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
666             // Transition from: all writes must finish before barrier.
667             VK_ACCESS_SHADER_WRITE_BIT,
668             ResourceAccess::ReadWrite,
669             PipelineStage::FragmentShader,
670             EventStage::FragmentShader,
671         },
672     },
673     {
674         ImageLayout::ComputeShaderReadOnly,
675         ImageMemoryBarrierData{
676             "ComputeShaderReadOnly",
677             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
678             VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
679             VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
680             // Transition to: all reads must happen after barrier.
681             VK_ACCESS_SHADER_READ_BIT,
682             // Transition from: RAR and WAR don't need memory barrier.
683             0,
684             ResourceAccess::ReadOnly,
685             PipelineStage::ComputeShader,
686             EventStage::ComputeShader,
687         },
688     },
689     {
690         ImageLayout::ComputeShaderWrite,
691         ImageMemoryBarrierData{
692             "ComputeShaderWrite",
693             VK_IMAGE_LAYOUT_GENERAL,
694             VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
695             VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
696             // Transition to: all reads and writes must happen after barrier.
697             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
698             // Transition from: all writes must finish before barrier.
699             VK_ACCESS_SHADER_WRITE_BIT,
700             ResourceAccess::ReadWrite,
701             PipelineStage::ComputeShader,
702             EventStage::ComputeShader,
703         },
704     },
705     {
706         ImageLayout::AllGraphicsShadersReadOnly,
707         ImageMemoryBarrierData{
708             "AllGraphicsShadersReadOnly",
709             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
710             kAllShadersPipelineStageFlags,
711             kAllShadersPipelineStageFlags,
712             // Transition to: all reads must happen after barrier.
713             VK_ACCESS_SHADER_READ_BIT,
714             // Transition from: RAR and WAR don't need memory barrier.
715             0,
716             ResourceAccess::ReadOnly,
717             // In case of multiple destination stages, We barrier the earliest stage
718             PipelineStage::VertexShader,
719             EventStage::AllShaders,
720         },
721     },
722     {
723         ImageLayout::AllGraphicsShadersWrite,
724         ImageMemoryBarrierData{
725             "AllGraphicsShadersWrite",
726             VK_IMAGE_LAYOUT_GENERAL,
727             kAllShadersPipelineStageFlags,
728             kAllShadersPipelineStageFlags,
729             // Transition to: all reads and writes must happen after barrier.
730             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
731             // Transition from: all writes must finish before barrier.
732             VK_ACCESS_SHADER_WRITE_BIT,
733             ResourceAccess::ReadWrite,
734             // In case of multiple destination stages, We barrier the earliest stage
735             PipelineStage::VertexShader,
736             EventStage::AllShaders,
737         },
738     },
739     {
740         ImageLayout::TransferDstAndComputeWrite,
741         ImageMemoryBarrierData{
742             "TransferDstAndComputeWrite",
743             VK_IMAGE_LAYOUT_GENERAL,
744             VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
745             VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
746             // Transition to: all reads and writes must happen after barrier.
747             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT,
748             // Transition from: all writes must finish before barrier.
749             VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
750             ResourceAccess::ReadWrite,
751             // In case of multiple destination stages, We barrier the earliest stage
752             PipelineStage::ComputeShader,
753             EventStage::TransferAndComputeShader,
754         },
755     },
756 };
757 // clang-format on
758 
GetImageLayoutEventStage(ImageLayout layout)759 EventStage GetImageLayoutEventStage(ImageLayout layout)
760 {
761     const ImageMemoryBarrierData &barrierData = kImageMemoryBarrierData[layout];
762     return barrierData.eventStage;
763 }
764 
HandlePrimitiveRestart(ContextVk * contextVk,gl::DrawElementsType glIndexType,GLsizei indexCount,const uint8_t * srcPtr,uint8_t * outPtr)765 void HandlePrimitiveRestart(ContextVk *contextVk,
766                             gl::DrawElementsType glIndexType,
767                             GLsizei indexCount,
768                             const uint8_t *srcPtr,
769                             uint8_t *outPtr)
770 {
771     switch (glIndexType)
772     {
773         case gl::DrawElementsType::UnsignedByte:
774             if (contextVk->getFeatures().supportsIndexTypeUint8.enabled)
775             {
776                 CopyLineLoopIndicesWithRestart<uint8_t, uint8_t>(indexCount, srcPtr, outPtr);
777             }
778             else
779             {
780                 CopyLineLoopIndicesWithRestart<uint8_t, uint16_t>(indexCount, srcPtr, outPtr);
781             }
782             break;
783         case gl::DrawElementsType::UnsignedShort:
784             CopyLineLoopIndicesWithRestart<uint16_t, uint16_t>(indexCount, srcPtr, outPtr);
785             break;
786         case gl::DrawElementsType::UnsignedInt:
787             CopyLineLoopIndicesWithRestart<uint32_t, uint32_t>(indexCount, srcPtr, outPtr);
788             break;
789         default:
790             UNREACHABLE();
791     }
792 }
793 
HasBothDepthAndStencilAspects(VkImageAspectFlags aspectFlags)794 bool HasBothDepthAndStencilAspects(VkImageAspectFlags aspectFlags)
795 {
796     return IsMaskFlagSet(aspectFlags, kDepthStencilAspects);
797 }
798 
GetContentDefinedLayerRangeBits(uint32_t layerStart,uint32_t layerCount,uint32_t maxLayerCount)799 uint8_t GetContentDefinedLayerRangeBits(uint32_t layerStart,
800                                         uint32_t layerCount,
801                                         uint32_t maxLayerCount)
802 {
803     uint8_t layerRangeBits = layerCount >= maxLayerCount ? static_cast<uint8_t>(~0u)
804                                                          : angle::BitMask<uint8_t>(layerCount);
805     layerRangeBits <<= layerStart;
806 
807     return layerRangeBits;
808 }
809 
GetImageLayerCountForView(const ImageHelper & image)810 uint32_t GetImageLayerCountForView(const ImageHelper &image)
811 {
812     // Depth > 1 means this is a 3D texture and depth is our layer count
813     return image.getExtents().depth > 1 ? image.getExtents().depth : image.getLayerCount();
814 }
815 
ReleaseImageViews(ImageViewVector * imageViewVector,GarbageObjects * garbage)816 void ReleaseImageViews(ImageViewVector *imageViewVector, GarbageObjects *garbage)
817 {
818     for (ImageView &imageView : *imageViewVector)
819     {
820         if (imageView.valid())
821         {
822             garbage->emplace_back(GetGarbage(&imageView));
823         }
824     }
825     imageViewVector->clear();
826 }
827 
DestroyImageViews(ImageViewVector * imageViewVector,VkDevice device)828 void DestroyImageViews(ImageViewVector *imageViewVector, VkDevice device)
829 {
830     for (ImageView &imageView : *imageViewVector)
831     {
832         imageView.destroy(device);
833     }
834     imageViewVector->clear();
835 }
836 
GetLevelImageView(ImageViewVector * imageViews,LevelIndex levelVk,uint32_t levelCount)837 ImageView *GetLevelImageView(ImageViewVector *imageViews, LevelIndex levelVk, uint32_t levelCount)
838 {
839     // Lazily allocate the storage for image views. We allocate the full level count because we
840     // don't want to trigger any std::vector reallocations. Reallocations could invalidate our
841     // view pointers.
842     if (imageViews->empty())
843     {
844         imageViews->resize(levelCount);
845     }
846     ASSERT(imageViews->size() > levelVk.get());
847 
848     return &(*imageViews)[levelVk.get()];
849 }
850 
GetLevelLayerImageView(LayerLevelImageViewVector * imageViews,LevelIndex levelVk,uint32_t layer,uint32_t levelCount,uint32_t layerCount)851 ImageView *GetLevelLayerImageView(LayerLevelImageViewVector *imageViews,
852                                   LevelIndex levelVk,
853                                   uint32_t layer,
854                                   uint32_t levelCount,
855                                   uint32_t layerCount)
856 {
857     // Lazily allocate the storage for image views. We allocate the full layer count because we
858     // don't want to trigger any std::vector reallocations. Reallocations could invalidate our
859     // view pointers.
860     if (imageViews->empty())
861     {
862         imageViews->resize(layerCount);
863     }
864     ASSERT(imageViews->size() > layer);
865 
866     return GetLevelImageView(&(*imageViews)[layer], levelVk, levelCount);
867 }
868 
869 // Special rules apply to VkBufferImageCopy with depth/stencil. The components are tightly packed
870 // into a depth or stencil section of the destination buffer. See the spec:
871 // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkBufferImageCopy.html
GetDepthStencilImageToBufferFormat(const angle::Format & imageFormat,VkImageAspectFlagBits copyAspect)872 const angle::Format &GetDepthStencilImageToBufferFormat(const angle::Format &imageFormat,
873                                                         VkImageAspectFlagBits copyAspect)
874 {
875     if (copyAspect == VK_IMAGE_ASPECT_STENCIL_BIT)
876     {
877         ASSERT(imageFormat.id == angle::FormatID::D24_UNORM_S8_UINT ||
878                imageFormat.id == angle::FormatID::D32_FLOAT_S8X24_UINT ||
879                imageFormat.id == angle::FormatID::S8_UINT);
880         return angle::Format::Get(angle::FormatID::S8_UINT);
881     }
882 
883     ASSERT(copyAspect == VK_IMAGE_ASPECT_DEPTH_BIT);
884 
885     switch (imageFormat.id)
886     {
887         case angle::FormatID::D16_UNORM:
888             return imageFormat;
889         case angle::FormatID::D24_UNORM_X8_UINT:
890             return imageFormat;
891         case angle::FormatID::D24_UNORM_S8_UINT:
892             return angle::Format::Get(angle::FormatID::D24_UNORM_X8_UINT);
893         case angle::FormatID::D32_FLOAT:
894             return imageFormat;
895         case angle::FormatID::D32_FLOAT_S8X24_UINT:
896             return angle::Format::Get(angle::FormatID::D32_FLOAT);
897         default:
898             UNREACHABLE();
899             return imageFormat;
900     }
901 }
902 
GetRobustResourceClearValue(const angle::Format & intendedFormat,const angle::Format & actualFormat)903 VkClearValue GetRobustResourceClearValue(const angle::Format &intendedFormat,
904                                          const angle::Format &actualFormat)
905 {
906     VkClearValue clearValue = {};
907     if (intendedFormat.hasDepthOrStencilBits())
908     {
909         clearValue.depthStencil = kRobustInitDepthStencilValue;
910     }
911     else
912     {
913         clearValue.color = HasEmulatedImageChannels(intendedFormat, actualFormat)
914                                ? kEmulatedInitColorValue
915                                : kRobustInitColorValue;
916     }
917     return clearValue;
918 }
919 
IsShaderReadOnlyLayout(const ImageMemoryBarrierData & imageLayout)920 bool IsShaderReadOnlyLayout(const ImageMemoryBarrierData &imageLayout)
921 {
922     // We also use VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL for texture sample from depth
923     // texture. See GetImageReadLayout() for detail.
924     return imageLayout.layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ||
925            imageLayout.layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
926 }
927 
IsAnySubresourceContentDefined(const gl::TexLevelArray<angle::BitSet8<8>> & contentDefined)928 bool IsAnySubresourceContentDefined(const gl::TexLevelArray<angle::BitSet8<8>> &contentDefined)
929 {
930     for (const angle::BitSet8<8> &levelContentDefined : contentDefined)
931     {
932         if (levelContentDefined.any())
933         {
934             return true;
935         }
936     }
937     return false;
938 }
939 
ExtendRenderPassInvalidateArea(const gl::Rectangle & invalidateArea,gl::Rectangle * out)940 void ExtendRenderPassInvalidateArea(const gl::Rectangle &invalidateArea, gl::Rectangle *out)
941 {
942     if (out->empty())
943     {
944         *out = invalidateArea;
945     }
946     else
947     {
948         gl::ExtendRectangle(*out, invalidateArea, out);
949     }
950 }
951 
CanCopyWithTransferForCopyImage(Renderer * renderer,ImageHelper * srcImage,VkImageTiling srcTilingMode,ImageHelper * dstImage,VkImageTiling dstTilingMode)952 bool CanCopyWithTransferForCopyImage(Renderer *renderer,
953                                      ImageHelper *srcImage,
954                                      VkImageTiling srcTilingMode,
955                                      ImageHelper *dstImage,
956                                      VkImageTiling dstTilingMode)
957 {
958     // Neither source nor destination formats can be emulated for copy image through transfer,
959     // unless they are emulated with the same format!
960     bool isFormatCompatible =
961         (!srcImage->hasEmulatedImageFormat() && !dstImage->hasEmulatedImageFormat()) ||
962         srcImage->getActualFormatID() == dstImage->getActualFormatID();
963 
964     // If neither formats are emulated, GL validation ensures that pixelBytes is the same for both.
965     ASSERT(!isFormatCompatible ||
966            srcImage->getActualFormat().pixelBytes == dstImage->getActualFormat().pixelBytes);
967 
968     return isFormatCompatible &&
969            CanCopyWithTransfer(renderer, srcImage->getActualFormatID(), srcTilingMode,
970                                dstImage->getActualFormatID(), dstTilingMode);
971 }
972 
ReleaseBufferListToRenderer(Renderer * renderer,BufferHelperQueue * buffers)973 void ReleaseBufferListToRenderer(Renderer *renderer, BufferHelperQueue *buffers)
974 {
975     for (std::unique_ptr<BufferHelper> &toFree : *buffers)
976     {
977         toFree->release(renderer);
978     }
979     buffers->clear();
980 }
981 
DestroyBufferList(Renderer * renderer,BufferHelperQueue * buffers)982 void DestroyBufferList(Renderer *renderer, BufferHelperQueue *buffers)
983 {
984     for (std::unique_ptr<BufferHelper> &toDestroy : *buffers)
985     {
986         toDestroy->destroy(renderer);
987     }
988     buffers->clear();
989 }
990 
991 // Helper functions used below
GetLoadOpShorthand(RenderPassLoadOp loadOp)992 char GetLoadOpShorthand(RenderPassLoadOp loadOp)
993 {
994     switch (loadOp)
995     {
996         case RenderPassLoadOp::Clear:
997             return 'C';
998         case RenderPassLoadOp::Load:
999             return 'L';
1000         case RenderPassLoadOp::None:
1001             return 'N';
1002         default:
1003             return 'D';
1004     }
1005 }
1006 
GetStoreOpShorthand(RenderPassStoreOp storeOp)1007 char GetStoreOpShorthand(RenderPassStoreOp storeOp)
1008 {
1009     switch (storeOp)
1010     {
1011         case RenderPassStoreOp::Store:
1012             return 'S';
1013         case RenderPassStoreOp::None:
1014             return 'N';
1015         default:
1016             return 'D';
1017     }
1018 }
1019 
IsClear(UpdateSource updateSource)1020 bool IsClear(UpdateSource updateSource)
1021 {
1022     return updateSource == UpdateSource::Clear ||
1023            updateSource == UpdateSource::ClearEmulatedChannelsOnly ||
1024            updateSource == UpdateSource::ClearAfterInvalidate;
1025 }
1026 
IsClearOfAllChannels(UpdateSource updateSource)1027 bool IsClearOfAllChannels(UpdateSource updateSource)
1028 {
1029     return updateSource == UpdateSource::Clear ||
1030            updateSource == UpdateSource::ClearAfterInvalidate;
1031 }
1032 
InitDynamicDescriptorPool(Context * context,const DescriptorSetLayoutDesc & descriptorSetLayoutDesc,const DescriptorSetLayout & descriptorSetLayout,uint32_t descriptorCountMultiplier,DynamicDescriptorPool * poolToInit)1033 angle::Result InitDynamicDescriptorPool(Context *context,
1034                                         const DescriptorSetLayoutDesc &descriptorSetLayoutDesc,
1035                                         const DescriptorSetLayout &descriptorSetLayout,
1036                                         uint32_t descriptorCountMultiplier,
1037                                         DynamicDescriptorPool *poolToInit)
1038 {
1039     std::vector<VkDescriptorPoolSize> descriptorPoolSizes;
1040     DescriptorSetLayoutBindingVector bindingVector;
1041     descriptorSetLayoutDesc.unpackBindings(&bindingVector);
1042 
1043     for (const VkDescriptorSetLayoutBinding &binding : bindingVector)
1044     {
1045         if (binding.descriptorCount > 0)
1046         {
1047             VkDescriptorPoolSize poolSize = {};
1048             poolSize.type                 = binding.descriptorType;
1049             poolSize.descriptorCount      = binding.descriptorCount * descriptorCountMultiplier;
1050             descriptorPoolSizes.emplace_back(poolSize);
1051         }
1052     }
1053 
1054     if (!descriptorPoolSizes.empty())
1055     {
1056         ANGLE_TRY(poolToInit->init(context, descriptorPoolSizes.data(), descriptorPoolSizes.size(),
1057                                    descriptorSetLayout));
1058     }
1059 
1060     return angle::Result::Continue;
1061 }
1062 
CheckSubpassCommandBufferCount(uint32_t count)1063 bool CheckSubpassCommandBufferCount(uint32_t count)
1064 {
1065     // When using angle::SharedRingBufferAllocator we must ensure that allocator is attached and
1066     // detached from the same priv::SecondaryCommandBuffer instance.
1067     // Custom command buffer (priv::SecondaryCommandBuffer) may contain commands for multiple
1068     // subpasses, therefore we do not need multiple buffers.
1069     return (count == 1 || !RenderPassCommandBuffer::ExecutesInline());
1070 }
1071 
IsAnyLayout(VkImageLayout needle,const VkImageLayout * haystack,uint32_t haystackCount)1072 bool IsAnyLayout(VkImageLayout needle, const VkImageLayout *haystack, uint32_t haystackCount)
1073 {
1074     const VkImageLayout *haystackEnd = haystack + haystackCount;
1075     return std::find(haystack, haystackEnd, needle) != haystackEnd;
1076 }
1077 
AggregateSkipLevels(const gl::CubeFaceArray<gl::TexLevelMask> & skipLevels)1078 gl::TexLevelMask AggregateSkipLevels(const gl::CubeFaceArray<gl::TexLevelMask> &skipLevels)
1079 {
1080     gl::TexLevelMask skipLevelsAllFaces = skipLevels[0];
1081     for (size_t face = 1; face < gl::kCubeFaceCount; ++face)
1082     {
1083         skipLevelsAllFaces |= skipLevels[face];
1084     }
1085     return skipLevelsAllFaces;
1086 }
1087 
1088 // Get layer mask for a particular image level.
GetImageLayerWriteMask(uint32_t layerStart,uint32_t layerCount)1089 ImageLayerWriteMask GetImageLayerWriteMask(uint32_t layerStart, uint32_t layerCount)
1090 {
1091     ImageLayerWriteMask layerMask = angle::BitMask<uint64_t>(layerCount);
1092     uint32_t rotateShift          = layerStart % kMaxParallelLayerWrites;
1093     layerMask = (layerMask << rotateShift) | (layerMask >> (kMaxParallelLayerWrites - rotateShift));
1094     return layerMask;
1095 }
1096 }  // anonymous namespace
1097 
1098 // This is an arbitrary max. We can change this later if necessary.
1099 uint32_t DynamicDescriptorPool::mMaxSetsPerPool           = 16;
1100 uint32_t DynamicDescriptorPool::mMaxSetsPerPoolMultiplier = 2;
1101 
GetImageLayoutFromGLImageLayout(Context * context,GLenum layout)1102 ImageLayout GetImageLayoutFromGLImageLayout(Context *context, GLenum layout)
1103 {
1104     const bool supportsMixedReadWriteDepthStencilLayouts =
1105         context->getFeatures().supportsMixedReadWriteDepthStencilLayouts.enabled;
1106     switch (layout)
1107     {
1108         case GL_NONE:
1109             return ImageLayout::Undefined;
1110         case GL_LAYOUT_GENERAL_EXT:
1111             return ImageLayout::ExternalShadersWrite;
1112         case GL_LAYOUT_COLOR_ATTACHMENT_EXT:
1113             return ImageLayout::ColorWrite;
1114         case GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT:
1115             return ImageLayout::DepthWriteStencilWrite;
1116         case GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT:
1117             return ImageLayout::DepthReadStencilRead;
1118         case GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT:
1119             return supportsMixedReadWriteDepthStencilLayouts ? ImageLayout::DepthReadStencilWrite
1120                                                              : ImageLayout::DepthWriteStencilWrite;
1121         case GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT:
1122             return supportsMixedReadWriteDepthStencilLayouts ? ImageLayout::DepthWriteStencilRead
1123                                                              : ImageLayout::DepthWriteStencilWrite;
1124         case GL_LAYOUT_SHADER_READ_ONLY_EXT:
1125             return ImageLayout::ExternalShadersReadOnly;
1126         case GL_LAYOUT_TRANSFER_SRC_EXT:
1127             return ImageLayout::TransferSrc;
1128         case GL_LAYOUT_TRANSFER_DST_EXT:
1129             return ImageLayout::TransferDst;
1130         default:
1131             UNREACHABLE();
1132             return vk::ImageLayout::Undefined;
1133     }
1134 }
1135 
ConvertImageLayoutToGLImageLayout(ImageLayout layout)1136 GLenum ConvertImageLayoutToGLImageLayout(ImageLayout layout)
1137 {
1138     switch (kImageMemoryBarrierData[layout].layout)
1139     {
1140         case VK_IMAGE_LAYOUT_UNDEFINED:
1141             return GL_NONE;
1142         case VK_IMAGE_LAYOUT_GENERAL:
1143             return GL_LAYOUT_GENERAL_EXT;
1144         case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
1145             return GL_LAYOUT_COLOR_ATTACHMENT_EXT;
1146         case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
1147             return GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT;
1148         case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
1149             return GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT;
1150         case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
1151             return GL_LAYOUT_SHADER_READ_ONLY_EXT;
1152         case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
1153             return GL_LAYOUT_TRANSFER_SRC_EXT;
1154         case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
1155             return GL_LAYOUT_TRANSFER_DST_EXT;
1156         case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL:
1157             return GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT;
1158         case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL:
1159             return GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT;
1160         default:
1161             break;
1162     }
1163     UNREACHABLE();
1164     return GL_NONE;
1165 }
1166 
ConvertImageLayoutToVkImageLayout(Renderer * renderer,ImageLayout imageLayout)1167 VkImageLayout ConvertImageLayoutToVkImageLayout(Renderer *renderer, ImageLayout imageLayout)
1168 {
1169     const ImageMemoryBarrierData &transition = renderer->getImageMemoryBarrierData(imageLayout);
1170     VkImageLayout layout                     = transition.layout;
1171 
1172     if (ANGLE_LIKELY(renderer->getFeatures().supportsMixedReadWriteDepthStencilLayouts.enabled))
1173     {
1174         return layout;
1175     }
1176 
1177     // If the layouts are not supported, substitute them with what's available.  This may be
1178     // less optimal and/or introduce synchronization hazards.
1179     if (layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL ||
1180         layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL)
1181     {
1182         layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
1183 
1184         // If the replacement layout causes a feedback loop, use the GENERAL layout
1185         if ((transition.dstStageMask &
1186              (VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT)) != 0)
1187         {
1188             layout = VK_IMAGE_LAYOUT_GENERAL;
1189         }
1190     }
1191 
1192     return layout;
1193 }
1194 
InitializeImageLayoutAndMemoryBarrierDataMap(angle::PackedEnumMap<ImageLayout,ImageMemoryBarrierData> * map,VkPipelineStageFlags supportedVulkanPipelineStageMask)1195 void InitializeImageLayoutAndMemoryBarrierDataMap(
1196     angle::PackedEnumMap<ImageLayout, ImageMemoryBarrierData> *map,
1197     VkPipelineStageFlags supportedVulkanPipelineStageMask)
1198 {
1199     *map = kImageMemoryBarrierData;
1200     for (ImageMemoryBarrierData &barrierData : *map)
1201     {
1202         barrierData.srcStageMask &= supportedVulkanPipelineStageMask;
1203         barrierData.dstStageMask &= supportedVulkanPipelineStageMask;
1204     }
1205 }
1206 
EventAndPipelineBarrierHaveMatchingStageFlags(const angle::PackedEnumMap<EventStage,VkPipelineStageFlags> & eventStageMap,const angle::PackedEnumMap<ImageLayout,ImageMemoryBarrierData> & barrierDataMap)1207 bool EventAndPipelineBarrierHaveMatchingStageFlags(
1208     const angle::PackedEnumMap<EventStage, VkPipelineStageFlags> &eventStageMap,
1209     const angle::PackedEnumMap<ImageLayout, ImageMemoryBarrierData> &barrierDataMap)
1210 {
1211     // mImageLayoutAndMemoryBarrierData's dstStageMask should match EventStage's
1212     // kEventStageAndPipelineStageFlagsMap
1213     for (const ImageMemoryBarrierData &barrierData : barrierDataMap)
1214     {
1215         if (barrierData.eventStage != EventStage::InvalidEnum &&
1216             eventStageMap[barrierData.eventStage] != barrierData.dstStageMask)
1217         {
1218             return false;
1219         }
1220     }
1221     return true;
1222 }
1223 
FormatHasNecessaryFeature(Renderer * renderer,angle::FormatID formatID,VkImageTiling tilingMode,VkFormatFeatureFlags featureBits)1224 bool FormatHasNecessaryFeature(Renderer *renderer,
1225                                angle::FormatID formatID,
1226                                VkImageTiling tilingMode,
1227                                VkFormatFeatureFlags featureBits)
1228 {
1229     return (tilingMode == VK_IMAGE_TILING_OPTIMAL)
1230                ? renderer->hasImageFormatFeatureBits(formatID, featureBits)
1231                : renderer->hasLinearImageFormatFeatureBits(formatID, featureBits);
1232 }
1233 
CanCopyWithTransfer(Renderer * renderer,angle::FormatID srcFormatID,VkImageTiling srcTilingMode,angle::FormatID dstFormatID,VkImageTiling dstTilingMode)1234 bool CanCopyWithTransfer(Renderer *renderer,
1235                          angle::FormatID srcFormatID,
1236                          VkImageTiling srcTilingMode,
1237                          angle::FormatID dstFormatID,
1238                          VkImageTiling dstTilingMode)
1239 {
1240     // Checks that the formats in the copy transfer have the appropriate tiling and transfer bits
1241     bool isTilingCompatible           = srcTilingMode == dstTilingMode;
1242     bool srcFormatHasNecessaryFeature = FormatHasNecessaryFeature(
1243         renderer, srcFormatID, srcTilingMode, VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
1244     bool dstFormatHasNecessaryFeature = FormatHasNecessaryFeature(
1245         renderer, dstFormatID, dstTilingMode, VK_FORMAT_FEATURE_TRANSFER_DST_BIT);
1246 
1247     return isTilingCompatible && srcFormatHasNecessaryFeature && dstFormatHasNecessaryFeature;
1248 }
1249 
1250 // PackedClearValuesArray implementation
PackedClearValuesArray()1251 PackedClearValuesArray::PackedClearValuesArray() : mValues{} {}
1252 PackedClearValuesArray::~PackedClearValuesArray() = default;
1253 
1254 PackedClearValuesArray::PackedClearValuesArray(const PackedClearValuesArray &other) = default;
1255 PackedClearValuesArray &PackedClearValuesArray::operator=(const PackedClearValuesArray &rhs) =
1256     default;
1257 
store(PackedAttachmentIndex index,VkImageAspectFlags aspectFlags,const VkClearValue & clearValue)1258 void PackedClearValuesArray::store(PackedAttachmentIndex index,
1259                                    VkImageAspectFlags aspectFlags,
1260                                    const VkClearValue &clearValue)
1261 {
1262     ASSERT(aspectFlags != 0);
1263     if (aspectFlags != VK_IMAGE_ASPECT_STENCIL_BIT)
1264     {
1265         storeNoDepthStencil(index, clearValue);
1266     }
1267 }
1268 
storeNoDepthStencil(PackedAttachmentIndex index,const VkClearValue & clearValue)1269 void PackedClearValuesArray::storeNoDepthStencil(PackedAttachmentIndex index,
1270                                                  const VkClearValue &clearValue)
1271 {
1272     mValues[index.get()] = clearValue;
1273 }
1274 
1275 // RenderPassAttachment implementation
RenderPassAttachment()1276 RenderPassAttachment::RenderPassAttachment()
1277 {
1278     reset();
1279 }
1280 
init(ImageHelper * image,UniqueSerial imageSiblingSerial,gl::LevelIndex levelIndex,uint32_t layerIndex,uint32_t layerCount,VkImageAspectFlagBits aspect)1281 void RenderPassAttachment::init(ImageHelper *image,
1282                                 UniqueSerial imageSiblingSerial,
1283                                 gl::LevelIndex levelIndex,
1284                                 uint32_t layerIndex,
1285                                 uint32_t layerCount,
1286                                 VkImageAspectFlagBits aspect)
1287 {
1288     ASSERT(mImage == nullptr);
1289 
1290     mImage              = image;
1291     mImageSiblingSerial = imageSiblingSerial;
1292     mLevelIndex         = levelIndex;
1293     mLayerIndex         = layerIndex;
1294     mLayerCount         = layerCount;
1295     mAspect             = aspect;
1296 
1297     mImage->setRenderPassUsageFlag(RenderPassUsage::RenderTargetAttachment);
1298 }
1299 
reset()1300 void RenderPassAttachment::reset()
1301 {
1302     mImage = nullptr;
1303 
1304     mAccess = ResourceAccess::Unused;
1305 
1306     mInvalidatedCmdCount = kInfiniteCmdCount;
1307     mDisabledCmdCount    = kInfiniteCmdCount;
1308     mInvalidateArea      = gl::Rectangle();
1309 }
1310 
onAccess(ResourceAccess access,uint32_t currentCmdCount)1311 void RenderPassAttachment::onAccess(ResourceAccess access, uint32_t currentCmdCount)
1312 {
1313     // Update the access for optimizing this render pass's loadOp
1314     UpdateAccess(&mAccess, access);
1315 
1316     // Update the invalidate state for optimizing this render pass's storeOp
1317     if (onAccessImpl(access, currentCmdCount))
1318     {
1319         // The attachment is no longer invalid, so restore its content.
1320         restoreContent();
1321     }
1322 }
1323 
invalidate(const gl::Rectangle & invalidateArea,bool isAttachmentEnabled,uint32_t currentCmdCount)1324 void RenderPassAttachment::invalidate(const gl::Rectangle &invalidateArea,
1325                                       bool isAttachmentEnabled,
1326                                       uint32_t currentCmdCount)
1327 {
1328     // Keep track of the command count in the render pass at the time of invalidation.  If there are
1329     // more commands in the future, invalidate must be undone.
1330     mInvalidatedCmdCount = currentCmdCount;
1331 
1332     // Also track the command count if the attachment is currently disabled.
1333     mDisabledCmdCount = isAttachmentEnabled ? kInfiniteCmdCount : currentCmdCount;
1334 
1335     // Set/extend the invalidate area.
1336     ExtendRenderPassInvalidateArea(invalidateArea, &mInvalidateArea);
1337 }
1338 
onRenderAreaGrowth(ContextVk * contextVk,const gl::Rectangle & newRenderArea)1339 void RenderPassAttachment::onRenderAreaGrowth(ContextVk *contextVk,
1340                                               const gl::Rectangle &newRenderArea)
1341 {
1342     // Remove invalidate if it's no longer applicable.
1343     if (mInvalidateArea.empty() || mInvalidateArea.encloses(newRenderArea))
1344     {
1345         return;
1346     }
1347 
1348     ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_LOW,
1349                           "InvalidateSubFramebuffer discarded due to increased scissor region");
1350 
1351     mInvalidateArea      = gl::Rectangle();
1352     mInvalidatedCmdCount = kInfiniteCmdCount;
1353 }
1354 
finalizeLoadStore(Context * context,uint32_t currentCmdCount,bool hasUnresolveAttachment,bool hasResolveAttachment,RenderPassLoadOp * loadOp,RenderPassStoreOp * storeOp,bool * isInvalidatedOut)1355 void RenderPassAttachment::finalizeLoadStore(Context *context,
1356                                              uint32_t currentCmdCount,
1357                                              bool hasUnresolveAttachment,
1358                                              bool hasResolveAttachment,
1359                                              RenderPassLoadOp *loadOp,
1360                                              RenderPassStoreOp *storeOp,
1361                                              bool *isInvalidatedOut)
1362 {
1363     if (mAspect != VK_IMAGE_ASPECT_COLOR_BIT)
1364     {
1365         const RenderPassUsage readOnlyAttachmentUsage =
1366             mAspect == VK_IMAGE_ASPECT_STENCIL_BIT ? RenderPassUsage::StencilReadOnlyAttachment
1367                                                    : RenderPassUsage::DepthReadOnlyAttachment;
1368         // Ensure we don't write to a read-only attachment. (ReadOnly -> !Write)
1369         ASSERT(!mImage->hasRenderPassUsageFlag(readOnlyAttachmentUsage) ||
1370                !HasResourceWriteAccess(mAccess));
1371     }
1372 
1373     // If the attachment is invalidated, skip the store op.  If we are not loading or clearing the
1374     // attachment and the attachment has not been used, auto-invalidate it.
1375     const bool notLoaded = *loadOp == RenderPassLoadOp::DontCare && !hasUnresolveAttachment;
1376     if (isInvalidated(currentCmdCount) || (notLoaded && !HasResourceWriteAccess(mAccess)))
1377     {
1378         *storeOp          = RenderPassStoreOp::DontCare;
1379         *isInvalidatedOut = true;
1380     }
1381     else if (hasWriteAfterInvalidate(currentCmdCount))
1382     {
1383         // The attachment was invalidated, but is now valid.  Let the image know the contents are
1384         // now defined so a future render pass would use loadOp=LOAD.
1385         restoreContent();
1386     }
1387 
1388     // For read only depth stencil, we can use StoreOpNone if available.  DontCare is still
1389     // preferred, so do this after handling DontCare.
1390     const bool supportsLoadStoreOpNone =
1391         context->getRenderer()->getFeatures().supportsRenderPassLoadStoreOpNone.enabled;
1392     const bool supportsStoreOpNone =
1393         supportsLoadStoreOpNone ||
1394         context->getRenderer()->getFeatures().supportsRenderPassStoreOpNone.enabled;
1395     if (mAccess == ResourceAccess::ReadOnly && supportsStoreOpNone)
1396     {
1397         if (*storeOp == RenderPassStoreOp::Store && *loadOp != RenderPassLoadOp::Clear)
1398         {
1399             *storeOp = RenderPassStoreOp::None;
1400         }
1401     }
1402 
1403     if (mAccess == ResourceAccess::Unused)
1404     {
1405         if (*storeOp != RenderPassStoreOp::DontCare)
1406         {
1407             switch (*loadOp)
1408             {
1409                 case RenderPassLoadOp::Clear:
1410                     // Cannot optimize away the ops if the attachment is cleared (even if not used
1411                     // afterwards)
1412                     break;
1413                 case RenderPassLoadOp::Load:
1414                     // Make sure the attachment is neither loaded nor stored (as it's neither used
1415                     // nor invalidated), if possible.
1416                     if (supportsLoadStoreOpNone)
1417                     {
1418                         *loadOp = RenderPassLoadOp::None;
1419                     }
1420                     if (supportsStoreOpNone)
1421                     {
1422                         *storeOp = RenderPassStoreOp::None;
1423                     }
1424                     break;
1425                 case RenderPassLoadOp::DontCare:
1426                     // loadOp=DontCare should be covered by storeOp=DontCare below.
1427                     break;
1428                 case RenderPassLoadOp::None:
1429                 default:
1430                     // loadOp=None is never decided upfront.
1431                     UNREACHABLE();
1432                     break;
1433             }
1434         }
1435     }
1436 
1437     if (mAccess == ResourceAccess::Unused || (mAccess == ResourceAccess::ReadOnly && notLoaded))
1438     {
1439         // If we are loading or clearing the attachment, but the attachment has not been used,
1440         // and the data has also not been stored back into attachment, then just skip the
1441         // load/clear op. If loadOp/storeOp=None is supported, prefer that to reduce the amount
1442         // of synchronization; DontCare is a write operation, while None is not.
1443         //
1444         // Don't optimize away a Load or Clear if there is a resolve attachment. Although the
1445         // storeOp=DontCare the image content needs to be resolved into the resolve attachment.
1446         const bool attachmentNeedsToBeResolved =
1447             hasResolveAttachment &&
1448             (*loadOp == RenderPassLoadOp::Load || *loadOp == RenderPassLoadOp::Clear);
1449         if (*storeOp == RenderPassStoreOp::DontCare && !attachmentNeedsToBeResolved)
1450         {
1451             if (supportsLoadStoreOpNone && !isInvalidated(currentCmdCount))
1452             {
1453                 *loadOp  = RenderPassLoadOp::None;
1454                 *storeOp = RenderPassStoreOp::None;
1455             }
1456             else
1457             {
1458                 *loadOp = RenderPassLoadOp::DontCare;
1459             }
1460         }
1461     }
1462 }
1463 
restoreContent()1464 void RenderPassAttachment::restoreContent()
1465 {
1466     // Note that the image may have been deleted since the render pass has started.
1467     if (mImage)
1468     {
1469         ASSERT(mImage->valid());
1470         if (mAspect == VK_IMAGE_ASPECT_STENCIL_BIT)
1471         {
1472             mImage->restoreSubresourceStencilContent(mLevelIndex, mLayerIndex, mLayerCount);
1473         }
1474         else
1475         {
1476             mImage->restoreSubresourceContent(mLevelIndex, mLayerIndex, mLayerCount);
1477         }
1478         mInvalidateArea = gl::Rectangle();
1479     }
1480 }
1481 
hasWriteAfterInvalidate(uint32_t currentCmdCount) const1482 bool RenderPassAttachment::hasWriteAfterInvalidate(uint32_t currentCmdCount) const
1483 {
1484     return (mInvalidatedCmdCount != kInfiniteCmdCount &&
1485             std::min(mDisabledCmdCount, currentCmdCount) != mInvalidatedCmdCount);
1486 }
1487 
isInvalidated(uint32_t currentCmdCount) const1488 bool RenderPassAttachment::isInvalidated(uint32_t currentCmdCount) const
1489 {
1490     return mInvalidatedCmdCount != kInfiniteCmdCount &&
1491            std::min(mDisabledCmdCount, currentCmdCount) == mInvalidatedCmdCount;
1492 }
1493 
onAccessImpl(ResourceAccess access,uint32_t currentCmdCount)1494 bool RenderPassAttachment::onAccessImpl(ResourceAccess access, uint32_t currentCmdCount)
1495 {
1496     if (mInvalidatedCmdCount == kInfiniteCmdCount)
1497     {
1498         // If never invalidated or no longer invalidated, return early.
1499         return false;
1500     }
1501     if (HasResourceWriteAccess(access))
1502     {
1503         // Drawing to this attachment is being enabled.  Assume that drawing will immediately occur
1504         // after this attachment is enabled, and that means that the attachment will no longer be
1505         // invalidated.
1506         mInvalidatedCmdCount = kInfiniteCmdCount;
1507         mDisabledCmdCount    = kInfiniteCmdCount;
1508         // Return true to indicate that the store op should remain STORE and that mContentDefined
1509         // should be set to true;
1510         return true;
1511     }
1512     // Drawing to this attachment is being disabled.
1513     if (hasWriteAfterInvalidate(currentCmdCount))
1514     {
1515         // The attachment was previously drawn while enabled, and so is no longer invalidated.
1516         mInvalidatedCmdCount = kInfiniteCmdCount;
1517         mDisabledCmdCount    = kInfiniteCmdCount;
1518         // Return true to indicate that the store op should remain STORE and that mContentDefined
1519         // should be set to true;
1520         return true;
1521     }
1522 
1523     // Use the latest CmdCount at the start of being disabled.  At the end of the render pass,
1524     // cmdCountDisabled is <= the actual command count, and so it's compared with
1525     // cmdCountInvalidated.  If the same, the attachment is still invalidated.
1526     mDisabledCmdCount = currentCmdCount;
1527     return false;
1528 }
1529 
1530 // CommandBufferHelperCommon implementation.
CommandBufferHelperCommon()1531 CommandBufferHelperCommon::CommandBufferHelperCommon()
1532     : mCommandPool(nullptr), mHasShaderStorageOutput(false), mHasGLMemoryBarrierIssued(false)
1533 {}
1534 
~CommandBufferHelperCommon()1535 CommandBufferHelperCommon::~CommandBufferHelperCommon() {}
1536 
initializeImpl()1537 void CommandBufferHelperCommon::initializeImpl()
1538 {
1539     mCommandAllocator.init();
1540 }
1541 
resetImpl(Context * context)1542 void CommandBufferHelperCommon::resetImpl(Context *context)
1543 {
1544     ASSERT(!mAcquireNextImageSemaphore.valid());
1545     mCommandAllocator.resetAllocator();
1546 
1547     ASSERT(mRefCountedEvents.mask.none());
1548     ASSERT(mRefCountedEventCollector.empty());
1549 }
1550 
1551 template <class DerivedT>
attachCommandPoolImpl(Context * context,SecondaryCommandPool * commandPool)1552 angle::Result CommandBufferHelperCommon::attachCommandPoolImpl(Context *context,
1553                                                                SecondaryCommandPool *commandPool)
1554 {
1555     if constexpr (!DerivedT::ExecutesInline())
1556     {
1557         DerivedT *derived = static_cast<DerivedT *>(this);
1558         ASSERT(commandPool != nullptr);
1559         ASSERT(mCommandPool == nullptr);
1560         ASSERT(!derived->getCommandBuffer().valid());
1561 
1562         mCommandPool = commandPool;
1563 
1564         ANGLE_TRY(derived->initializeCommandBuffer(context));
1565     }
1566     return angle::Result::Continue;
1567 }
1568 
1569 template <class DerivedT, bool kIsRenderPassBuffer>
detachCommandPoolImpl(Context * context,SecondaryCommandPool ** commandPoolOut)1570 angle::Result CommandBufferHelperCommon::detachCommandPoolImpl(
1571     Context *context,
1572     SecondaryCommandPool **commandPoolOut)
1573 {
1574     if constexpr (!DerivedT::ExecutesInline())
1575     {
1576         DerivedT *derived = static_cast<DerivedT *>(this);
1577         ASSERT(mCommandPool != nullptr);
1578         ASSERT(derived->getCommandBuffer().valid());
1579 
1580         if constexpr (!kIsRenderPassBuffer)
1581         {
1582             ASSERT(!derived->getCommandBuffer().empty());
1583             ANGLE_TRY(derived->endCommandBuffer(context));
1584         }
1585 
1586         *commandPoolOut = mCommandPool;
1587         mCommandPool    = nullptr;
1588     }
1589     ASSERT(mCommandPool == nullptr);
1590     return angle::Result::Continue;
1591 }
1592 
1593 template <class DerivedT>
releaseCommandPoolImpl()1594 void CommandBufferHelperCommon::releaseCommandPoolImpl()
1595 {
1596     if constexpr (!DerivedT::ExecutesInline())
1597     {
1598         DerivedT *derived = static_cast<DerivedT *>(this);
1599         ASSERT(mCommandPool != nullptr);
1600 
1601         if (derived->getCommandBuffer().valid())
1602         {
1603             ASSERT(derived->getCommandBuffer().empty());
1604             mCommandPool->collect(&derived->getCommandBuffer());
1605         }
1606 
1607         mCommandPool = nullptr;
1608     }
1609     ASSERT(mCommandPool == nullptr);
1610 }
1611 
1612 template <class DerivedT>
attachAllocatorImpl(SecondaryCommandMemoryAllocator * allocator)1613 void CommandBufferHelperCommon::attachAllocatorImpl(SecondaryCommandMemoryAllocator *allocator)
1614 {
1615     if constexpr (DerivedT::ExecutesInline())
1616     {
1617         auto &commandBuffer = static_cast<DerivedT *>(this)->getCommandBuffer();
1618         mCommandAllocator.attachAllocator(allocator);
1619         commandBuffer.attachAllocator(mCommandAllocator.getAllocator());
1620     }
1621 }
1622 
1623 template <class DerivedT>
detachAllocatorImpl()1624 SecondaryCommandMemoryAllocator *CommandBufferHelperCommon::detachAllocatorImpl()
1625 {
1626     SecondaryCommandMemoryAllocator *result = nullptr;
1627     if constexpr (DerivedT::ExecutesInline())
1628     {
1629         auto &commandBuffer = static_cast<DerivedT *>(this)->getCommandBuffer();
1630         commandBuffer.detachAllocator(mCommandAllocator.getAllocator());
1631         result = mCommandAllocator.detachAllocator(commandBuffer.empty());
1632     }
1633     return result;
1634 }
1635 
1636 template <class DerivedT>
assertCanBeRecycledImpl()1637 void CommandBufferHelperCommon::assertCanBeRecycledImpl()
1638 {
1639     DerivedT *derived = static_cast<DerivedT *>(this);
1640     ASSERT(mCommandPool == nullptr);
1641     ASSERT(!mCommandAllocator.hasAllocatorLinks());
1642     // Vulkan secondary command buffers must be invalid (collected).
1643     ASSERT(DerivedT::ExecutesInline() || !derived->getCommandBuffer().valid());
1644     // ANGLEs Custom secondary command buffers must be empty (reset).
1645     ASSERT(!DerivedT::ExecutesInline() || derived->getCommandBuffer().empty());
1646 }
1647 
bufferWrite(ContextVk * contextVk,VkAccessFlags writeAccessType,PipelineStage writeStage,BufferHelper * buffer)1648 void CommandBufferHelperCommon::bufferWrite(ContextVk *contextVk,
1649                                             VkAccessFlags writeAccessType,
1650                                             PipelineStage writeStage,
1651                                             BufferHelper *buffer)
1652 {
1653     buffer->setWriteQueueSerial(mQueueSerial);
1654 
1655     VkPipelineStageFlagBits stageBits = kPipelineStageFlagBitMap[writeStage];
1656     buffer->recordWriteBarrier(writeAccessType, stageBits, writeStage, &mPipelineBarriers);
1657 
1658     // Make sure host-visible buffer writes result in a barrier inserted at the end of the frame to
1659     // make the results visible to the host.  The buffer may be mapped by the application in the
1660     // future.
1661     if (buffer->isHostVisible())
1662     {
1663         contextVk->onHostVisibleBufferWrite();
1664     }
1665 }
1666 
executeBarriers(Renderer * renderer,CommandsState * commandsState)1667 void CommandBufferHelperCommon::executeBarriers(Renderer *renderer, CommandsState *commandsState)
1668 {
1669     // Add ANI semaphore to the command submission.
1670     if (mAcquireNextImageSemaphore.valid())
1671     {
1672         commandsState->waitSemaphores.emplace_back(mAcquireNextImageSemaphore.release());
1673         commandsState->waitSemaphoreStageMasks.emplace_back(kSwapchainAcquireImageWaitStageFlags);
1674     }
1675 
1676     mPipelineBarriers.execute(renderer, &commandsState->primaryCommands);
1677     mEventBarriers.execute(renderer, &commandsState->primaryCommands);
1678 }
1679 
bufferReadImpl(VkAccessFlags readAccessType,PipelineStage readStage,BufferHelper * buffer)1680 void CommandBufferHelperCommon::bufferReadImpl(VkAccessFlags readAccessType,
1681                                                PipelineStage readStage,
1682                                                BufferHelper *buffer)
1683 {
1684     VkPipelineStageFlagBits stageBits = kPipelineStageFlagBitMap[readStage];
1685     buffer->recordReadBarrier(readAccessType, stageBits, readStage, &mPipelineBarriers);
1686     ASSERT(!usesBufferForWrite(*buffer));
1687 }
1688 
imageReadImpl(Context * context,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,BarrierType barrierType,ImageHelper * image)1689 void CommandBufferHelperCommon::imageReadImpl(Context *context,
1690                                               VkImageAspectFlags aspectFlags,
1691                                               ImageLayout imageLayout,
1692                                               BarrierType barrierType,
1693                                               ImageHelper *image)
1694 {
1695     if (image->isReadBarrierNecessary(context->getRenderer(), imageLayout))
1696     {
1697         updateImageLayoutAndBarrier(context, image, aspectFlags, imageLayout, barrierType);
1698     }
1699 }
1700 
imageWriteImpl(Context * context,gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,BarrierType barrierType,ImageHelper * image)1701 void CommandBufferHelperCommon::imageWriteImpl(Context *context,
1702                                                gl::LevelIndex level,
1703                                                uint32_t layerStart,
1704                                                uint32_t layerCount,
1705                                                VkImageAspectFlags aspectFlags,
1706                                                ImageLayout imageLayout,
1707                                                BarrierType barrierType,
1708                                                ImageHelper *image)
1709 {
1710     image->onWrite(level, 1, layerStart, layerCount, aspectFlags);
1711     if (image->isWriteBarrierNecessary(imageLayout, level, 1, layerStart, layerCount))
1712     {
1713         updateImageLayoutAndBarrier(context, image, aspectFlags, imageLayout, barrierType);
1714     }
1715 }
1716 
updateImageLayoutAndBarrier(Context * context,ImageHelper * image,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,BarrierType barrierType)1717 void CommandBufferHelperCommon::updateImageLayoutAndBarrier(Context *context,
1718                                                             ImageHelper *image,
1719                                                             VkImageAspectFlags aspectFlags,
1720                                                             ImageLayout imageLayout,
1721                                                             BarrierType barrierType)
1722 {
1723     VkSemaphore semaphore = VK_NULL_HANDLE;
1724     image->updateLayoutAndBarrier(context, aspectFlags, imageLayout, barrierType, mQueueSerial,
1725                                   &mPipelineBarriers, &mEventBarriers, &mRefCountedEventCollector,
1726                                   &semaphore);
1727     // If image has an ANI semaphore, move it to command buffer so that we can wait for it in
1728     // next submission.
1729     if (semaphore != VK_NULL_HANDLE)
1730     {
1731         ASSERT(!mAcquireNextImageSemaphore.valid());
1732         mAcquireNextImageSemaphore.setHandle(semaphore);
1733     }
1734 }
1735 
retainImage(Context * context,ImageHelper * image)1736 void CommandBufferHelperCommon::retainImage(Context *context, ImageHelper *image)
1737 {
1738     image->setQueueSerial(mQueueSerial);
1739 
1740     if (context->getRenderer()->getFeatures().useVkEventForImageBarrier.enabled)
1741     {
1742         image->setCurrentRefCountedEvent(context, mRefCountedEvents);
1743     }
1744 }
1745 
1746 template <typename CommandBufferT>
flushSetEventsImpl(Context * context,CommandBufferT * commandBuffer)1747 void CommandBufferHelperCommon::flushSetEventsImpl(Context *context, CommandBufferT *commandBuffer)
1748 {
1749     if (mRefCountedEvents.mask.none())
1750     {
1751         return;
1752     }
1753 
1754     Renderer *renderer = context->getRenderer();
1755     // Add VkCmdSetEvent here to track the completion of this renderPass.
1756     for (EventStage stage : mRefCountedEvents.mask)
1757     {
1758         RefCountedEvent &refCountedEvent = mRefCountedEvents.map[stage];
1759         ASSERT(refCountedEvent.valid());
1760         VkPipelineStageFlags stageMask = renderer->getPipelineStageMask(stage);
1761         commandBuffer->setEvent(refCountedEvent.getEvent().getHandle(), stageMask);
1762         // We no longer need event, so garbage collect it.
1763         mRefCountedEventCollector.emplace_back(std::move(refCountedEvent));
1764     }
1765     mRefCountedEvents.mask.reset();
1766 }
1767 
1768 template void CommandBufferHelperCommon::flushSetEventsImpl<priv::SecondaryCommandBuffer>(
1769     Context *context,
1770     priv::SecondaryCommandBuffer *commandBuffer);
1771 template void CommandBufferHelperCommon::flushSetEventsImpl<VulkanSecondaryCommandBuffer>(
1772     Context *context,
1773     VulkanSecondaryCommandBuffer *commandBuffer);
1774 
addCommandDiagnosticsCommon(std::ostringstream * out)1775 void CommandBufferHelperCommon::addCommandDiagnosticsCommon(std::ostringstream *out)
1776 {
1777     mPipelineBarriers.addDiagnosticsString(*out);
1778     mEventBarriers.addDiagnosticsString(*out);
1779 }
1780 
1781 // OutsideRenderPassCommandBufferHelper implementation.
OutsideRenderPassCommandBufferHelper()1782 OutsideRenderPassCommandBufferHelper::OutsideRenderPassCommandBufferHelper() {}
1783 
~OutsideRenderPassCommandBufferHelper()1784 OutsideRenderPassCommandBufferHelper::~OutsideRenderPassCommandBufferHelper() {}
1785 
initialize(Context * context)1786 angle::Result OutsideRenderPassCommandBufferHelper::initialize(Context *context)
1787 {
1788     initializeImpl();
1789     return initializeCommandBuffer(context);
1790 }
initializeCommandBuffer(Context * context)1791 angle::Result OutsideRenderPassCommandBufferHelper::initializeCommandBuffer(Context *context)
1792 {
1793     // Skip initialization in the Pool-detached state.
1794     if (!ExecutesInline() && mCommandPool == nullptr)
1795     {
1796         return angle::Result::Continue;
1797     }
1798     return mCommandBuffer.initialize(context, mCommandPool, false,
1799                                      mCommandAllocator.getAllocator());
1800 }
1801 
reset(Context * context,SecondaryCommandBufferCollector * commandBufferCollector)1802 angle::Result OutsideRenderPassCommandBufferHelper::reset(
1803     Context *context,
1804     SecondaryCommandBufferCollector *commandBufferCollector)
1805 {
1806     resetImpl(context);
1807 
1808     // Collect/Reset the command buffer
1809     commandBufferCollector->collectCommandBuffer(std::move(mCommandBuffer));
1810     mIsCommandBufferEnded = false;
1811 
1812     // Invalidate the queue serial here. We will get a new queue serial after commands flush.
1813     mQueueSerial = QueueSerial();
1814 
1815     return initializeCommandBuffer(context);
1816 }
1817 
setBufferReadQueueSerial(ContextVk * contextVk,BufferHelper * buffer)1818 void OutsideRenderPassCommandBufferHelper::setBufferReadQueueSerial(ContextVk *contextVk,
1819                                                                     BufferHelper *buffer)
1820 {
1821     if (contextVk->isRenderPassStartedAndUsesBuffer(*buffer))
1822     {
1823         // We should not run into situation that RP is writing to it while we are reading it here
1824         ASSERT(!contextVk->isRenderPassStartedAndUsesBufferForWrite(*buffer));
1825         // A buffer could have read accessed by both renderPassCommands and
1826         // outsideRenderPassCommands and there is no need to endRP or flush. In this case, the
1827         // renderPassCommands' read will override the outsideRenderPassCommands' read, since its
1828         // queueSerial must be greater than outsideRP.
1829     }
1830     else
1831     {
1832         buffer->setQueueSerial(mQueueSerial);
1833     }
1834 }
1835 
imageRead(ContextVk * contextVk,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)1836 void OutsideRenderPassCommandBufferHelper::imageRead(ContextVk *contextVk,
1837                                                      VkImageAspectFlags aspectFlags,
1838                                                      ImageLayout imageLayout,
1839                                                      ImageHelper *image)
1840 {
1841     if (contextVk->isRenderPassStartedAndUsesImage(*image))
1842     {
1843         // If image is already used by renderPass, it may already set the event to renderPass's
1844         // event. In this case we already lost the previous event to wait for, thus use pipeline
1845         // barrier instead of event
1846         imageReadImpl(contextVk, aspectFlags, imageLayout, BarrierType::Pipeline, image);
1847     }
1848     else
1849     {
1850         imageReadImpl(contextVk, aspectFlags, imageLayout, BarrierType::Event, image);
1851         // Usually an image can only used by a RenderPassCommands or OutsideRenderPassCommands
1852         // because the layout will be different, except with image sampled from compute shader. In
1853         // this case, the renderPassCommands' read will override the outsideRenderPassCommands'
1854         retainImage(contextVk, image);
1855     }
1856 }
1857 
imageWrite(ContextVk * contextVk,gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)1858 void OutsideRenderPassCommandBufferHelper::imageWrite(ContextVk *contextVk,
1859                                                       gl::LevelIndex level,
1860                                                       uint32_t layerStart,
1861                                                       uint32_t layerCount,
1862                                                       VkImageAspectFlags aspectFlags,
1863                                                       ImageLayout imageLayout,
1864                                                       ImageHelper *image)
1865 {
1866     imageWriteImpl(contextVk, level, layerStart, layerCount, aspectFlags, imageLayout,
1867                    BarrierType::Event, image);
1868     retainImage(contextVk, image);
1869 }
1870 
trackImageWithEvent(Context * context,ImageHelper * image)1871 void OutsideRenderPassCommandBufferHelper::trackImageWithEvent(Context *context, ImageHelper *image)
1872 {
1873     image->setCurrentRefCountedEvent(context, mRefCountedEvents);
1874     flushSetEventsImpl(context, &mCommandBuffer);
1875 }
1876 
trackImagesWithEvent(Context * context,ImageHelper * srcImage,ImageHelper * dstImage)1877 void OutsideRenderPassCommandBufferHelper::trackImagesWithEvent(Context *context,
1878                                                                 ImageHelper *srcImage,
1879                                                                 ImageHelper *dstImage)
1880 {
1881     srcImage->setCurrentRefCountedEvent(context, mRefCountedEvents);
1882     dstImage->setCurrentRefCountedEvent(context, mRefCountedEvents);
1883     flushSetEventsImpl(context, &mCommandBuffer);
1884 }
1885 
trackImagesWithEvent(Context * context,const ImageHelperPtr * images,size_t count)1886 void OutsideRenderPassCommandBufferHelper::trackImagesWithEvent(Context *context,
1887                                                                 const ImageHelperPtr *images,
1888                                                                 size_t count)
1889 {
1890     for (size_t i = 0; i < count; i++)
1891     {
1892         images[i]->setCurrentRefCountedEvent(context, mRefCountedEvents);
1893     }
1894     flushSetEventsImpl(context, &mCommandBuffer);
1895 }
1896 
collectRefCountedEventsGarbage(RefCountedEventsGarbageRecycler * garbageRecycler)1897 void OutsideRenderPassCommandBufferHelper::collectRefCountedEventsGarbage(
1898     RefCountedEventsGarbageRecycler *garbageRecycler)
1899 {
1900     ASSERT(garbageRecycler != nullptr);
1901     if (!mRefCountedEventCollector.empty())
1902     {
1903         garbageRecycler->collectGarbage(mQueueSerial, std::move(mRefCountedEventCollector));
1904     }
1905 }
1906 
flushToPrimary(Context * context,CommandsState * commandsState)1907 angle::Result OutsideRenderPassCommandBufferHelper::flushToPrimary(Context *context,
1908                                                                    CommandsState *commandsState)
1909 {
1910     ANGLE_TRACE_EVENT0("gpu.angle", "OutsideRenderPassCommandBufferHelper::flushToPrimary");
1911     ASSERT(!empty());
1912 
1913     Renderer *renderer = context->getRenderer();
1914 
1915     // Commands that are added to primary before beginRenderPass command
1916     executeBarriers(renderer, commandsState);
1917 
1918     // When using Vulkan secondary command buffers and "asyncCommandQueue" is enabled, command
1919     // buffer MUST be already ended in the detachCommandPool() (called in the CommandProcessor).
1920     // After the detach, nothing is written to the buffer (the barriers above are written directly
1921     // to the primary buffer).
1922     // Note: RenderPass Command Buffers are explicitly ended in the endRenderPass().
1923     if (ExecutesInline() || !renderer->isAsyncCommandQueueEnabled())
1924     {
1925         ANGLE_TRY(endCommandBuffer(context));
1926     }
1927     ASSERT(mIsCommandBufferEnded);
1928     mCommandBuffer.executeCommands(&commandsState->primaryCommands);
1929 
1930     // Call VkCmdSetEvent to track the completion of this renderPass.
1931     flushSetEventsImpl(context, &commandsState->primaryCommands);
1932 
1933     // Proactively reset all released events before ending command buffer.
1934     context->getRenderer()->getRefCountedEventRecycler()->resetEvents(
1935         context, mQueueSerial, &commandsState->primaryCommands);
1936 
1937     // Restart the command buffer.
1938     return reset(context, &commandsState->secondaryCommands);
1939 }
1940 
endCommandBuffer(Context * context)1941 angle::Result OutsideRenderPassCommandBufferHelper::endCommandBuffer(Context *context)
1942 {
1943     ASSERT(ExecutesInline() || mCommandPool != nullptr);
1944     ASSERT(mCommandBuffer.valid());
1945     ASSERT(!mIsCommandBufferEnded);
1946 
1947     ANGLE_TRY(mCommandBuffer.end(context));
1948     mIsCommandBufferEnded = true;
1949 
1950     return angle::Result::Continue;
1951 }
1952 
attachCommandPool(Context * context,SecondaryCommandPool * commandPool)1953 angle::Result OutsideRenderPassCommandBufferHelper::attachCommandPool(
1954     Context *context,
1955     SecondaryCommandPool *commandPool)
1956 {
1957     return attachCommandPoolImpl<OutsideRenderPassCommandBufferHelper>(context, commandPool);
1958 }
1959 
detachCommandPool(Context * context,SecondaryCommandPool ** commandPoolOut)1960 angle::Result OutsideRenderPassCommandBufferHelper::detachCommandPool(
1961     Context *context,
1962     SecondaryCommandPool **commandPoolOut)
1963 {
1964     return detachCommandPoolImpl<OutsideRenderPassCommandBufferHelper, false>(context,
1965                                                                               commandPoolOut);
1966 }
1967 
releaseCommandPool()1968 void OutsideRenderPassCommandBufferHelper::releaseCommandPool()
1969 {
1970     releaseCommandPoolImpl<OutsideRenderPassCommandBufferHelper>();
1971 }
1972 
attachAllocator(SecondaryCommandMemoryAllocator * allocator)1973 void OutsideRenderPassCommandBufferHelper::attachAllocator(
1974     SecondaryCommandMemoryAllocator *allocator)
1975 {
1976     attachAllocatorImpl<OutsideRenderPassCommandBufferHelper>(allocator);
1977 }
1978 
detachAllocator()1979 SecondaryCommandMemoryAllocator *OutsideRenderPassCommandBufferHelper::detachAllocator()
1980 {
1981     return detachAllocatorImpl<OutsideRenderPassCommandBufferHelper>();
1982 }
1983 
assertCanBeRecycled()1984 void OutsideRenderPassCommandBufferHelper::assertCanBeRecycled()
1985 {
1986     assertCanBeRecycledImpl<OutsideRenderPassCommandBufferHelper>();
1987 }
1988 
getCommandDiagnostics()1989 std::string OutsideRenderPassCommandBufferHelper::getCommandDiagnostics()
1990 {
1991     std::ostringstream out;
1992     addCommandDiagnosticsCommon(&out);
1993 
1994     out << mCommandBuffer.dumpCommands("\\l");
1995 
1996     return out.str();
1997 }
1998 
1999 // RenderPassFramebuffer implementation.
reset()2000 void RenderPassFramebuffer::reset()
2001 {
2002     mInitialFramebuffer.release();
2003     mImageViews.clear();
2004     mIsImageless = false;
2005 }
2006 
addResolveAttachment(size_t viewIndex,VkImageView view)2007 void RenderPassFramebuffer::addResolveAttachment(size_t viewIndex, VkImageView view)
2008 {
2009     // The initial framebuffer is no longer usable.
2010     mInitialFramebuffer.release();
2011 
2012     if (viewIndex >= mImageViews.size())
2013     {
2014         mImageViews.resize(viewIndex + 1, VK_NULL_HANDLE);
2015     }
2016 
2017     ASSERT(mImageViews[viewIndex] == VK_NULL_HANDLE);
2018     mImageViews[viewIndex] = view;
2019 }
2020 
packResolveViewsAndCreateFramebuffer(Context * context,const RenderPass & renderPass,Framebuffer * framebufferOut)2021 angle::Result RenderPassFramebuffer::packResolveViewsAndCreateFramebuffer(
2022     Context *context,
2023     const RenderPass &renderPass,
2024     Framebuffer *framebufferOut)
2025 {
2026     // This is only called if the initial framebuffer was not usable.  Since this is called when
2027     // the render pass is finalized, the render pass that is passed in is the final one (not a
2028     // compatible one) and the framebuffer that is created is not imageless.
2029     ASSERT(!mInitialFramebuffer.valid());
2030 
2031     PackViews(&mImageViews);
2032     mIsImageless = false;
2033 
2034     VkFramebufferCreateInfo framebufferInfo = {};
2035     framebufferInfo.sType                   = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
2036     framebufferInfo.flags                   = 0;
2037     framebufferInfo.renderPass              = renderPass.getHandle();
2038     framebufferInfo.attachmentCount         = static_cast<uint32_t>(mImageViews.size());
2039     framebufferInfo.pAttachments            = mImageViews.data();
2040     framebufferInfo.width                   = mWidth;
2041     framebufferInfo.height                  = mHeight;
2042     framebufferInfo.layers                  = mLayers;
2043 
2044     ANGLE_VK_TRY(context, framebufferOut->init(context->getDevice(), framebufferInfo));
2045     return angle::Result::Continue;
2046 }
2047 
packResolveViewsForRenderPassBegin(VkRenderPassAttachmentBeginInfo * beginInfoOut)2048 void RenderPassFramebuffer::packResolveViewsForRenderPassBegin(
2049     VkRenderPassAttachmentBeginInfo *beginInfoOut)
2050 {
2051     // Called when using the initial framebuffer which is imageless
2052     ASSERT(mInitialFramebuffer.valid());
2053     ASSERT(mIsImageless);
2054 
2055     PackViews(&mImageViews);
2056 
2057     *beginInfoOut                 = {};
2058     beginInfoOut->sType           = VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO_KHR;
2059     beginInfoOut->attachmentCount = static_cast<uint32_t>(mImageViews.size());
2060     beginInfoOut->pAttachments    = mImageViews.data();
2061 }
2062 
2063 // static
PackViews(FramebufferAttachmentsVector<VkImageView> * views)2064 void RenderPassFramebuffer::PackViews(FramebufferAttachmentsVector<VkImageView> *views)
2065 {
2066     PackedAttachmentIndex packIndex = kAttachmentIndexZero;
2067     for (size_t viewIndex = 0; viewIndex < views->size(); ++viewIndex)
2068     {
2069         if ((*views)[viewIndex] != VK_NULL_HANDLE)
2070         {
2071             (*views)[packIndex.get()] = (*views)[viewIndex];
2072             ++packIndex;
2073         }
2074     }
2075 
2076     views->resize(packIndex.get());
2077 }
2078 
2079 // RenderPassCommandBufferHelper implementation.
RenderPassCommandBufferHelper()2080 RenderPassCommandBufferHelper::RenderPassCommandBufferHelper()
2081     : mCurrentSubpassCommandBufferIndex(0),
2082       mCounter(0),
2083       mClearValues{},
2084       mRenderPassStarted(false),
2085       mTransformFeedbackCounterBuffers{},
2086       mTransformFeedbackCounterBufferOffsets{},
2087       mValidTransformFeedbackBufferCount(0),
2088       mRebindTransformFeedbackBuffers(false),
2089       mIsTransformFeedbackActiveUnpaused(false),
2090       mPreviousSubpassesCmdCount(0),
2091       mDepthStencilAttachmentIndex(kAttachmentIndexInvalid),
2092       mColorAttachmentsCount(0),
2093       mImageOptimizeForPresent(nullptr)
2094 {}
2095 
~RenderPassCommandBufferHelper()2096 RenderPassCommandBufferHelper::~RenderPassCommandBufferHelper() {}
2097 
initialize(Context * context)2098 angle::Result RenderPassCommandBufferHelper::initialize(Context *context)
2099 {
2100     initializeImpl();
2101     return initializeCommandBuffer(context);
2102 }
initializeCommandBuffer(Context * context)2103 angle::Result RenderPassCommandBufferHelper::initializeCommandBuffer(Context *context)
2104 {
2105     // Skip initialization in the Pool-detached state.
2106     if (!ExecutesInline() && mCommandPool == nullptr)
2107     {
2108         return angle::Result::Continue;
2109     }
2110     return getCommandBuffer().initialize(context, mCommandPool, true,
2111                                          mCommandAllocator.getAllocator());
2112 }
2113 
reset(Context * context,SecondaryCommandBufferCollector * commandBufferCollector)2114 angle::Result RenderPassCommandBufferHelper::reset(
2115     Context *context,
2116     SecondaryCommandBufferCollector *commandBufferCollector)
2117 {
2118     resetImpl(context);
2119 
2120     for (PackedAttachmentIndex index = kAttachmentIndexZero; index < mColorAttachmentsCount;
2121          ++index)
2122     {
2123         mColorAttachments[index].reset();
2124         mColorResolveAttachments[index].reset();
2125     }
2126 
2127     mDepthAttachment.reset();
2128     mDepthResolveAttachment.reset();
2129     mStencilAttachment.reset();
2130     mStencilResolveAttachment.reset();
2131 
2132     mFragmentShadingRateAtachment.reset();
2133 
2134     mRenderPassStarted                 = false;
2135     mValidTransformFeedbackBufferCount = 0;
2136     mRebindTransformFeedbackBuffers    = false;
2137     mHasShaderStorageOutput            = false;
2138     mHasGLMemoryBarrierIssued          = false;
2139     mPreviousSubpassesCmdCount         = 0;
2140     mColorAttachmentsCount             = PackedAttachmentCount(0);
2141     mDepthStencilAttachmentIndex       = kAttachmentIndexInvalid;
2142     mImageOptimizeForPresent           = nullptr;
2143 
2144     ASSERT(CheckSubpassCommandBufferCount(getSubpassCommandBufferCount()));
2145 
2146     // Collect/Reset the command buffers
2147     for (uint32_t subpass = 0; subpass < getSubpassCommandBufferCount(); ++subpass)
2148     {
2149         commandBufferCollector->collectCommandBuffer(std::move(mCommandBuffers[subpass]));
2150     }
2151 
2152     mCurrentSubpassCommandBufferIndex = 0;
2153 
2154     // Reset the image views used for imageless framebuffer (if any)
2155     mFramebuffer.reset();
2156 
2157     // Invalidate the queue serial here. We will get a new queue serial when we begin renderpass.
2158     mQueueSerial = QueueSerial();
2159 
2160     return initializeCommandBuffer(context);
2161 }
2162 
imageRead(ContextVk * contextVk,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)2163 void RenderPassCommandBufferHelper::imageRead(ContextVk *contextVk,
2164                                               VkImageAspectFlags aspectFlags,
2165                                               ImageLayout imageLayout,
2166                                               ImageHelper *image)
2167 {
2168     imageReadImpl(contextVk, aspectFlags, imageLayout, BarrierType::Event, image);
2169     // As noted in the header we don't support multiple read layouts for Images.
2170     // We allow duplicate uses in the RP to accommodate for normal GL sampler usage.
2171     retainImage(contextVk, image);
2172 }
2173 
imageWrite(ContextVk * contextVk,gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)2174 void RenderPassCommandBufferHelper::imageWrite(ContextVk *contextVk,
2175                                                gl::LevelIndex level,
2176                                                uint32_t layerStart,
2177                                                uint32_t layerCount,
2178                                                VkImageAspectFlags aspectFlags,
2179                                                ImageLayout imageLayout,
2180                                                ImageHelper *image)
2181 {
2182     imageWriteImpl(contextVk, level, layerStart, layerCount, aspectFlags, imageLayout,
2183                    BarrierType::Event, image);
2184     retainImage(contextVk, image);
2185 }
2186 
colorImagesDraw(gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,ImageHelper * image,ImageHelper * resolveImage,UniqueSerial imageSiblingSerial,PackedAttachmentIndex packedAttachmentIndex)2187 void RenderPassCommandBufferHelper::colorImagesDraw(gl::LevelIndex level,
2188                                                     uint32_t layerStart,
2189                                                     uint32_t layerCount,
2190                                                     ImageHelper *image,
2191                                                     ImageHelper *resolveImage,
2192                                                     UniqueSerial imageSiblingSerial,
2193                                                     PackedAttachmentIndex packedAttachmentIndex)
2194 {
2195     ASSERT(packedAttachmentIndex < mColorAttachmentsCount);
2196 
2197     image->setQueueSerial(mQueueSerial);
2198 
2199     mColorAttachments[packedAttachmentIndex].init(image, imageSiblingSerial, level, layerStart,
2200                                                   layerCount, VK_IMAGE_ASPECT_COLOR_BIT);
2201 
2202     if (resolveImage)
2203     {
2204         resolveImage->setQueueSerial(mQueueSerial);
2205         mColorResolveAttachments[packedAttachmentIndex].init(resolveImage, imageSiblingSerial,
2206                                                              level, layerStart, layerCount,
2207                                                              VK_IMAGE_ASPECT_COLOR_BIT);
2208     }
2209 }
2210 
depthStencilImagesDraw(gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,ImageHelper * image,ImageHelper * resolveImage,UniqueSerial imageSiblingSerial)2211 void RenderPassCommandBufferHelper::depthStencilImagesDraw(gl::LevelIndex level,
2212                                                            uint32_t layerStart,
2213                                                            uint32_t layerCount,
2214                                                            ImageHelper *image,
2215                                                            ImageHelper *resolveImage,
2216                                                            UniqueSerial imageSiblingSerial)
2217 {
2218     ASSERT(!usesImage(*image));
2219     ASSERT(!resolveImage || !usesImage(*resolveImage));
2220 
2221     // Because depthStencil buffer's read/write property can change while we build renderpass, we
2222     // defer the image layout changes until endRenderPass time or when images going away so that we
2223     // only insert layout change barrier once.
2224     image->setQueueSerial(mQueueSerial);
2225 
2226     mDepthAttachment.init(image, imageSiblingSerial, level, layerStart, layerCount,
2227                           VK_IMAGE_ASPECT_DEPTH_BIT);
2228     mStencilAttachment.init(image, imageSiblingSerial, level, layerStart, layerCount,
2229                             VK_IMAGE_ASPECT_STENCIL_BIT);
2230 
2231     if (resolveImage)
2232     {
2233         // Note that the resolve depth/stencil image has the same level/layer index as the
2234         // depth/stencil image as currently it can only ever come from
2235         // multisampled-render-to-texture renderbuffers.
2236         resolveImage->setQueueSerial(mQueueSerial);
2237 
2238         mDepthResolveAttachment.init(resolveImage, imageSiblingSerial, level, layerStart,
2239                                      layerCount, VK_IMAGE_ASPECT_DEPTH_BIT);
2240         mStencilResolveAttachment.init(resolveImage, imageSiblingSerial, level, layerStart,
2241                                        layerCount, VK_IMAGE_ASPECT_STENCIL_BIT);
2242     }
2243 }
2244 
fragmentShadingRateImageRead(ImageHelper * image)2245 void RenderPassCommandBufferHelper::fragmentShadingRateImageRead(ImageHelper *image)
2246 {
2247     ASSERT(image && image->valid());
2248     ASSERT(!usesImage(*image));
2249 
2250     image->setQueueSerial(mQueueSerial);
2251 
2252     // Initialize RenderPassAttachment for fragment shading rate attachment.
2253     mFragmentShadingRateAtachment.init(image, {}, gl::LevelIndex(0), 0, 1,
2254                                        VK_IMAGE_ASPECT_COLOR_BIT);
2255 
2256     image->resetRenderPassUsageFlags();
2257     image->setRenderPassUsageFlag(RenderPassUsage::FragmentShadingRateReadOnlyAttachment);
2258 }
2259 
onColorAccess(PackedAttachmentIndex packedAttachmentIndex,ResourceAccess access)2260 void RenderPassCommandBufferHelper::onColorAccess(PackedAttachmentIndex packedAttachmentIndex,
2261                                                   ResourceAccess access)
2262 {
2263     ASSERT(packedAttachmentIndex < mColorAttachmentsCount);
2264     mColorAttachments[packedAttachmentIndex].onAccess(access, getRenderPassWriteCommandCount());
2265 }
2266 
onDepthAccess(ResourceAccess access)2267 void RenderPassCommandBufferHelper::onDepthAccess(ResourceAccess access)
2268 {
2269     mDepthAttachment.onAccess(access, getRenderPassWriteCommandCount());
2270 }
2271 
onStencilAccess(ResourceAccess access)2272 void RenderPassCommandBufferHelper::onStencilAccess(ResourceAccess access)
2273 {
2274     mStencilAttachment.onAccess(access, getRenderPassWriteCommandCount());
2275 }
2276 
updateDepthReadOnlyMode(RenderPassUsageFlags dsUsageFlags)2277 void RenderPassCommandBufferHelper::updateDepthReadOnlyMode(RenderPassUsageFlags dsUsageFlags)
2278 {
2279     ASSERT(mRenderPassStarted);
2280     updateStartedRenderPassWithDepthStencilMode(&mDepthResolveAttachment, hasDepthWriteOrClear(),
2281                                                 dsUsageFlags,
2282                                                 RenderPassUsage::DepthReadOnlyAttachment);
2283 }
2284 
updateStencilReadOnlyMode(RenderPassUsageFlags dsUsageFlags)2285 void RenderPassCommandBufferHelper::updateStencilReadOnlyMode(RenderPassUsageFlags dsUsageFlags)
2286 {
2287     ASSERT(mRenderPassStarted);
2288     updateStartedRenderPassWithDepthStencilMode(&mStencilResolveAttachment,
2289                                                 hasStencilWriteOrClear(), dsUsageFlags,
2290                                                 RenderPassUsage::StencilReadOnlyAttachment);
2291 }
2292 
updateDepthStencilReadOnlyMode(RenderPassUsageFlags dsUsageFlags,VkImageAspectFlags dsAspectFlags)2293 void RenderPassCommandBufferHelper::updateDepthStencilReadOnlyMode(
2294     RenderPassUsageFlags dsUsageFlags,
2295     VkImageAspectFlags dsAspectFlags)
2296 {
2297     ASSERT(mRenderPassStarted);
2298     if ((dsAspectFlags & VK_IMAGE_ASPECT_DEPTH_BIT) != 0)
2299     {
2300         updateDepthReadOnlyMode(dsUsageFlags);
2301     }
2302     if ((dsAspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
2303     {
2304         updateStencilReadOnlyMode(dsUsageFlags);
2305     }
2306 }
2307 
updateStartedRenderPassWithDepthStencilMode(RenderPassAttachment * resolveAttachment,bool renderPassHasWriteOrClear,RenderPassUsageFlags dsUsageFlags,RenderPassUsage readOnlyAttachmentUsage)2308 void RenderPassCommandBufferHelper::updateStartedRenderPassWithDepthStencilMode(
2309     RenderPassAttachment *resolveAttachment,
2310     bool renderPassHasWriteOrClear,
2311     RenderPassUsageFlags dsUsageFlags,
2312     RenderPassUsage readOnlyAttachmentUsage)
2313 {
2314     ASSERT(mRenderPassStarted);
2315     ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
2316     ASSERT(mDepthResolveAttachment.getImage() == mStencilResolveAttachment.getImage());
2317 
2318     // Determine read-only mode for depth or stencil
2319     const bool readOnlyMode =
2320         mDepthStencilAttachmentIndex != kAttachmentIndexInvalid &&
2321         resolveAttachment->getImage() == nullptr &&
2322         (dsUsageFlags.test(readOnlyAttachmentUsage) || !renderPassHasWriteOrClear);
2323 
2324     // If readOnlyMode is false, we are switching out of read only mode due to depth/stencil write.
2325     // We must not be in the read only feedback loop mode because the logic in
2326     // DIRTY_BIT_READ_ONLY_DEPTH_FEEDBACK_LOOP_MODE should ensure we end the previous renderpass and
2327     // a new renderpass will start with feedback loop disabled.
2328     ASSERT(readOnlyMode || !dsUsageFlags.test(readOnlyAttachmentUsage));
2329 
2330     ImageHelper *depthStencilImage = mDepthAttachment.getImage();
2331     if (depthStencilImage)
2332     {
2333         if (readOnlyMode)
2334         {
2335             depthStencilImage->setRenderPassUsageFlag(readOnlyAttachmentUsage);
2336         }
2337         else
2338         {
2339             depthStencilImage->clearRenderPassUsageFlag(readOnlyAttachmentUsage);
2340         }
2341     }
2342     // The depth/stencil resolve image is never in read-only mode
2343 }
2344 
finalizeColorImageLayout(Context * context,ImageHelper * image,PackedAttachmentIndex packedAttachmentIndex,bool isResolveImage)2345 void RenderPassCommandBufferHelper::finalizeColorImageLayout(
2346     Context *context,
2347     ImageHelper *image,
2348     PackedAttachmentIndex packedAttachmentIndex,
2349     bool isResolveImage)
2350 {
2351     ASSERT(packedAttachmentIndex < mColorAttachmentsCount);
2352     ASSERT(image != nullptr);
2353 
2354     // Do layout change.
2355     ImageLayout imageLayout;
2356     if (image->usedByCurrentRenderPassAsAttachmentAndSampler(RenderPassUsage::ColorTextureSampler))
2357     {
2358         // texture code already picked layout and inserted barrier
2359         imageLayout = image->getCurrentImageLayout();
2360         ASSERT(imageLayout == ImageLayout::ColorWriteFragmentShaderFeedback ||
2361                imageLayout == ImageLayout::ColorWriteAllShadersFeedback);
2362     }
2363     else
2364     {
2365         // When color is unresolved, use a layout that includes fragment shader reads.  This is done
2366         // for all color resolve attachments even if they are not all unresolved for simplicity.  In
2367         // particular, the GL color index is not available (only the packed index) at this point,
2368         // but that is needed to query whether the attachment is unresolved or not.
2369         const bool hasUnresolve =
2370             isResolveImage && mRenderPassDesc.getColorUnresolveAttachmentMask().any();
2371         imageLayout = hasUnresolve ? ImageLayout::MSRTTEmulationColorUnresolveAndResolve
2372                                    : ImageLayout::ColorWrite;
2373         updateImageLayoutAndBarrier(context, image, VK_IMAGE_ASPECT_COLOR_BIT, imageLayout,
2374                                     BarrierType::Event);
2375     }
2376 
2377     if (!isResolveImage)
2378     {
2379         mAttachmentOps.setLayouts(packedAttachmentIndex, imageLayout, imageLayout);
2380     }
2381 
2382     if (mImageOptimizeForPresent == image &&
2383         context->getRenderer()->getFeatures().supportsPresentation.enabled)
2384     {
2385         ASSERT(packedAttachmentIndex == kAttachmentIndexZero);
2386         // Use finalLayout instead of extra barrier for layout change to present
2387         mImageOptimizeForPresent->setCurrentImageLayout(ImageLayout::Present);
2388         // TODO(syoussefi):  We currently don't store the layout of the resolve attachments, so once
2389         // multisampled backbuffers are optimized to use resolve attachments, this information needs
2390         // to be stored somewhere.  http://anglebug.com/7150
2391         SetBitField(mAttachmentOps[packedAttachmentIndex].finalLayout,
2392                     mImageOptimizeForPresent->getCurrentImageLayout());
2393         mImageOptimizeForPresent = nullptr;
2394     }
2395 
2396     if (isResolveImage)
2397     {
2398         // Note: the color image will have its flags reset after load/store ops are determined.
2399         image->resetRenderPassUsageFlags();
2400     }
2401 }
2402 
finalizeColorImageLoadStore(Context * context,PackedAttachmentIndex packedAttachmentIndex)2403 void RenderPassCommandBufferHelper::finalizeColorImageLoadStore(
2404     Context *context,
2405     PackedAttachmentIndex packedAttachmentIndex)
2406 {
2407     PackedAttachmentOpsDesc &ops = mAttachmentOps[packedAttachmentIndex];
2408     RenderPassLoadOp loadOp      = static_cast<RenderPassLoadOp>(ops.loadOp);
2409     RenderPassStoreOp storeOp    = static_cast<RenderPassStoreOp>(ops.storeOp);
2410 
2411     // This has to be called after layout been finalized
2412     ASSERT(ops.initialLayout != static_cast<uint16_t>(ImageLayout::Undefined));
2413 
2414     uint32_t currentCmdCount = getRenderPassWriteCommandCount();
2415     bool isInvalidated       = false;
2416 
2417     RenderPassAttachment &colorAttachment = mColorAttachments[packedAttachmentIndex];
2418     colorAttachment.finalizeLoadStore(
2419         context, currentCmdCount, mRenderPassDesc.getColorUnresolveAttachmentMask().any(),
2420         mRenderPassDesc.getColorResolveAttachmentMask().any(), &loadOp, &storeOp, &isInvalidated);
2421 
2422     if (isInvalidated)
2423     {
2424         ops.isInvalidated = true;
2425     }
2426 
2427     if (!ops.isInvalidated)
2428     {
2429         mColorResolveAttachments[packedAttachmentIndex].restoreContent();
2430     }
2431 
2432     // If the image is being written to, mark its contents defined.
2433     // This has to be done after storeOp has been finalized.
2434     if (storeOp == RenderPassStoreOp::Store)
2435     {
2436         colorAttachment.restoreContent();
2437     }
2438 
2439     SetBitField(ops.loadOp, loadOp);
2440     SetBitField(ops.storeOp, storeOp);
2441 }
2442 
finalizeDepthStencilImageLayout(Context * context)2443 void RenderPassCommandBufferHelper::finalizeDepthStencilImageLayout(Context *context)
2444 {
2445     ASSERT(mDepthAttachment.getImage() != nullptr);
2446     ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
2447 
2448     ImageHelper *depthStencilImage = mDepthAttachment.getImage();
2449 
2450     // Do depth stencil layout change.
2451     ImageLayout imageLayout;
2452     bool barrierRequired;
2453 
2454     const bool isDepthAttachmentAndSampler =
2455         depthStencilImage->usedByCurrentRenderPassAsAttachmentAndSampler(
2456             RenderPassUsage::DepthTextureSampler);
2457     const bool isStencilAttachmentAndSampler =
2458         depthStencilImage->usedByCurrentRenderPassAsAttachmentAndSampler(
2459             RenderPassUsage::StencilTextureSampler);
2460     const bool isReadOnlyDepth =
2461         depthStencilImage->hasRenderPassUsageFlag(RenderPassUsage::DepthReadOnlyAttachment);
2462     const bool isReadOnlyStencil =
2463         depthStencilImage->hasRenderPassUsageFlag(RenderPassUsage::StencilReadOnlyAttachment);
2464     BarrierType barrierType = BarrierType::Event;
2465 
2466     if (isDepthAttachmentAndSampler || isStencilAttachmentAndSampler)
2467     {
2468         // texture code already picked layout and inserted barrier
2469         imageLayout = depthStencilImage->getCurrentImageLayout();
2470 
2471         if ((isDepthAttachmentAndSampler && !isReadOnlyDepth) ||
2472             (isStencilAttachmentAndSampler && !isReadOnlyStencil))
2473         {
2474             ASSERT(imageLayout == ImageLayout::DepthStencilFragmentShaderFeedback ||
2475                    imageLayout == ImageLayout::DepthStencilAllShadersFeedback);
2476             barrierRequired = true;
2477         }
2478         else
2479         {
2480             ASSERT(imageLayout == ImageLayout::DepthWriteStencilReadFragmentShaderStencilRead ||
2481                    imageLayout == ImageLayout::DepthWriteStencilReadAllShadersStencilRead ||
2482                    imageLayout == ImageLayout::DepthReadStencilWriteFragmentShaderDepthRead ||
2483                    imageLayout == ImageLayout::DepthReadStencilWriteAllShadersDepthRead ||
2484                    imageLayout == ImageLayout::DepthReadStencilReadFragmentShaderRead ||
2485                    imageLayout == ImageLayout::DepthReadStencilReadAllShadersRead);
2486             barrierRequired =
2487                 depthStencilImage->isReadBarrierNecessary(context->getRenderer(), imageLayout);
2488         }
2489     }
2490     else
2491     {
2492         if (isReadOnlyDepth)
2493         {
2494             imageLayout = isReadOnlyStencil ? ImageLayout::DepthReadStencilRead
2495                                             : ImageLayout::DepthReadStencilWrite;
2496         }
2497         else
2498         {
2499             imageLayout = isReadOnlyStencil ? ImageLayout::DepthWriteStencilRead
2500                                             : ImageLayout::DepthWriteStencilWrite;
2501         }
2502 
2503         barrierRequired =
2504             !isReadOnlyDepth || !isReadOnlyStencil ||
2505             depthStencilImage->isReadBarrierNecessary(context->getRenderer(), imageLayout);
2506     }
2507 
2508     mAttachmentOps.setLayouts(mDepthStencilAttachmentIndex, imageLayout, imageLayout);
2509 
2510     if (barrierRequired)
2511     {
2512         const angle::Format &format = depthStencilImage->getActualFormat();
2513         ASSERT(format.hasDepthOrStencilBits());
2514         VkImageAspectFlags aspectFlags = GetDepthStencilAspectFlags(format);
2515         updateImageLayoutAndBarrier(context, depthStencilImage, aspectFlags, imageLayout,
2516                                     barrierType);
2517     }
2518 }
2519 
finalizeDepthStencilResolveImageLayout(Context * context)2520 void RenderPassCommandBufferHelper::finalizeDepthStencilResolveImageLayout(Context *context)
2521 {
2522     ASSERT(mDepthResolveAttachment.getImage() != nullptr);
2523     ASSERT(mDepthResolveAttachment.getImage() == mStencilResolveAttachment.getImage());
2524 
2525     ImageHelper *depthStencilResolveImage = mDepthResolveAttachment.getImage();
2526 
2527     // When depth/stencil is unresolved, use a layout that includes fragment shader reads.
2528     ImageLayout imageLayout     = mRenderPassDesc.hasDepthStencilUnresolveAttachment()
2529                                       ? ImageLayout::MSRTTEmulationDepthStencilUnresolveAndResolve
2530                                       : ImageLayout::DepthStencilResolve;
2531     const angle::Format &format = depthStencilResolveImage->getActualFormat();
2532     ASSERT(format.hasDepthOrStencilBits());
2533     VkImageAspectFlags aspectFlags = GetDepthStencilAspectFlags(format);
2534 
2535     updateImageLayoutAndBarrier(context, depthStencilResolveImage, aspectFlags, imageLayout,
2536                                 BarrierType::Event);
2537 
2538     // The resolve image can never be read-only.
2539     ASSERT(!depthStencilResolveImage->hasRenderPassUsageFlag(
2540         RenderPassUsage::DepthReadOnlyAttachment));
2541     ASSERT(!depthStencilResolveImage->hasRenderPassUsageFlag(
2542         RenderPassUsage::StencilReadOnlyAttachment));
2543     ASSERT(mDepthStencilAttachmentIndex != kAttachmentIndexInvalid);
2544     const PackedAttachmentOpsDesc &dsOps = mAttachmentOps[mDepthStencilAttachmentIndex];
2545 
2546     // If the image is being written to, mark its contents defined.
2547     if (!dsOps.isInvalidated)
2548     {
2549         mDepthResolveAttachment.restoreContent();
2550     }
2551     if (!dsOps.isStencilInvalidated)
2552     {
2553         mStencilResolveAttachment.restoreContent();
2554     }
2555 
2556     depthStencilResolveImage->resetRenderPassUsageFlags();
2557 }
2558 
finalizeFragmentShadingRateImageLayout(Context * context)2559 void RenderPassCommandBufferHelper::finalizeFragmentShadingRateImageLayout(Context *context)
2560 {
2561     ImageHelper *image      = mFragmentShadingRateAtachment.getImage();
2562     ImageLayout imageLayout = ImageLayout::FragmentShadingRateAttachmentReadOnly;
2563     ASSERT(image && image->valid());
2564     if (image->isReadBarrierNecessary(context->getRenderer(), imageLayout))
2565     {
2566         updateImageLayoutAndBarrier(context, image, VK_IMAGE_ASPECT_COLOR_BIT, imageLayout,
2567                                     BarrierType::Event);
2568     }
2569     image->resetRenderPassUsageFlags();
2570 }
2571 
finalizeImageLayout(Context * context,const ImageHelper * image,UniqueSerial imageSiblingSerial)2572 void RenderPassCommandBufferHelper::finalizeImageLayout(Context *context,
2573                                                         const ImageHelper *image,
2574                                                         UniqueSerial imageSiblingSerial)
2575 {
2576     if (image->hasRenderPassUsageFlag(RenderPassUsage::RenderTargetAttachment))
2577     {
2578         for (PackedAttachmentIndex index = kAttachmentIndexZero; index < mColorAttachmentsCount;
2579              ++index)
2580         {
2581             if (mColorAttachments[index].hasImage(image, imageSiblingSerial))
2582             {
2583                 finalizeColorImageLayoutAndLoadStore(context, index);
2584                 mColorAttachments[index].reset();
2585             }
2586             else if (mColorResolveAttachments[index].hasImage(image, imageSiblingSerial))
2587             {
2588                 finalizeColorImageLayout(context, mColorResolveAttachments[index].getImage(), index,
2589                                          true);
2590                 mColorResolveAttachments[index].reset();
2591             }
2592         }
2593     }
2594 
2595     if (mDepthAttachment.hasImage(image, imageSiblingSerial))
2596     {
2597         finalizeDepthStencilImageLayoutAndLoadStore(context);
2598         mDepthAttachment.reset();
2599         mStencilAttachment.reset();
2600     }
2601 
2602     if (mDepthResolveAttachment.hasImage(image, imageSiblingSerial))
2603     {
2604         finalizeDepthStencilResolveImageLayout(context);
2605         mDepthResolveAttachment.reset();
2606         mStencilResolveAttachment.reset();
2607     }
2608 
2609     if (mFragmentShadingRateAtachment.hasImage(image, imageSiblingSerial))
2610     {
2611         finalizeFragmentShadingRateImageLayout(context);
2612         mFragmentShadingRateAtachment.reset();
2613     }
2614 }
2615 
finalizeDepthStencilLoadStore(Context * context)2616 void RenderPassCommandBufferHelper::finalizeDepthStencilLoadStore(Context *context)
2617 {
2618     ASSERT(mDepthStencilAttachmentIndex != kAttachmentIndexInvalid);
2619 
2620     PackedAttachmentOpsDesc &dsOps   = mAttachmentOps[mDepthStencilAttachmentIndex];
2621     RenderPassLoadOp depthLoadOp     = static_cast<RenderPassLoadOp>(dsOps.loadOp);
2622     RenderPassStoreOp depthStoreOp   = static_cast<RenderPassStoreOp>(dsOps.storeOp);
2623     RenderPassLoadOp stencilLoadOp   = static_cast<RenderPassLoadOp>(dsOps.stencilLoadOp);
2624     RenderPassStoreOp stencilStoreOp = static_cast<RenderPassStoreOp>(dsOps.stencilStoreOp);
2625 
2626     // This has to be called after layout been finalized
2627     ASSERT(dsOps.initialLayout != static_cast<uint16_t>(ImageLayout::Undefined));
2628 
2629     uint32_t currentCmdCount         = getRenderPassWriteCommandCount();
2630     bool isDepthInvalidated          = false;
2631     bool isStencilInvalidated        = false;
2632     bool hasDepthResolveAttachment   = mRenderPassDesc.hasDepthResolveAttachment();
2633     bool hasStencilResolveAttachment = mRenderPassDesc.hasStencilResolveAttachment();
2634 
2635     mDepthAttachment.finalizeLoadStore(
2636         context, currentCmdCount, mRenderPassDesc.hasDepthUnresolveAttachment(),
2637         hasDepthResolveAttachment, &depthLoadOp, &depthStoreOp, &isDepthInvalidated);
2638     mStencilAttachment.finalizeLoadStore(
2639         context, currentCmdCount, mRenderPassDesc.hasStencilUnresolveAttachment(),
2640         hasStencilResolveAttachment, &stencilLoadOp, &stencilStoreOp, &isStencilInvalidated);
2641 
2642     const bool disableMixedDepthStencilLoadOpNoneAndLoad =
2643         context->getRenderer()->getFeatures().disallowMixedDepthStencilLoadOpNoneAndLoad.enabled;
2644 
2645     if (disableMixedDepthStencilLoadOpNoneAndLoad)
2646     {
2647         if (depthLoadOp == RenderPassLoadOp::None && stencilLoadOp != RenderPassLoadOp::None)
2648         {
2649             depthLoadOp = RenderPassLoadOp::Load;
2650         }
2651         if (depthLoadOp != RenderPassLoadOp::None && stencilLoadOp == RenderPassLoadOp::None)
2652         {
2653             stencilLoadOp = RenderPassLoadOp::Load;
2654         }
2655     }
2656 
2657     if (isDepthInvalidated)
2658     {
2659         dsOps.isInvalidated = true;
2660     }
2661     if (isStencilInvalidated)
2662     {
2663         dsOps.isStencilInvalidated = true;
2664     }
2665 
2666     // If the image is being written to, mark its contents defined.
2667     // This has to be done after storeOp has been finalized.
2668     ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
2669     if (!mDepthAttachment.getImage()->hasRenderPassUsageFlag(
2670             RenderPassUsage::DepthReadOnlyAttachment))
2671     {
2672         if (depthStoreOp == RenderPassStoreOp::Store)
2673         {
2674             mDepthAttachment.restoreContent();
2675         }
2676     }
2677     if (!mStencilAttachment.getImage()->hasRenderPassUsageFlag(
2678             RenderPassUsage::StencilReadOnlyAttachment))
2679     {
2680         if (stencilStoreOp == RenderPassStoreOp::Store)
2681         {
2682             mStencilAttachment.restoreContent();
2683         }
2684     }
2685 
2686     SetBitField(dsOps.loadOp, depthLoadOp);
2687     SetBitField(dsOps.storeOp, depthStoreOp);
2688     SetBitField(dsOps.stencilLoadOp, stencilLoadOp);
2689     SetBitField(dsOps.stencilStoreOp, stencilStoreOp);
2690 }
2691 
finalizeColorImageLayoutAndLoadStore(Context * context,PackedAttachmentIndex packedAttachmentIndex)2692 void RenderPassCommandBufferHelper::finalizeColorImageLayoutAndLoadStore(
2693     Context *context,
2694     PackedAttachmentIndex packedAttachmentIndex)
2695 {
2696     finalizeColorImageLayout(context, mColorAttachments[packedAttachmentIndex].getImage(),
2697                              packedAttachmentIndex, false);
2698     finalizeColorImageLoadStore(context, packedAttachmentIndex);
2699 
2700     mColorAttachments[packedAttachmentIndex].getImage()->resetRenderPassUsageFlags();
2701 }
2702 
finalizeDepthStencilImageLayoutAndLoadStore(Context * context)2703 void RenderPassCommandBufferHelper::finalizeDepthStencilImageLayoutAndLoadStore(Context *context)
2704 {
2705     finalizeDepthStencilImageLayout(context);
2706     finalizeDepthStencilLoadStore(context);
2707 
2708     ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
2709     mDepthAttachment.getImage()->resetRenderPassUsageFlags();
2710 }
2711 
trackImagesWithEvent(Context * context,const ImageHelperPtr * images,size_t count)2712 void RenderPassCommandBufferHelper::trackImagesWithEvent(Context *context,
2713                                                          const ImageHelperPtr *images,
2714                                                          size_t count)
2715 {
2716     for (size_t i = 0; i < count; i++)
2717     {
2718         images[i]->setCurrentRefCountedEvent(context, mRefCountedEvents);
2719     }
2720 }
2721 
executeSetEvents(Context * context,PrimaryCommandBuffer * primary)2722 void RenderPassCommandBufferHelper::executeSetEvents(Context *context,
2723                                                      PrimaryCommandBuffer *primary)
2724 {
2725     Renderer *renderer = context->getRenderer();
2726     // Add VkCmdSetEvent here to track the completion of this renderPass.
2727     for (EventStage stage : mRefCountedEvents.mask)
2728     {
2729         // This must have been garbage collected. The VkEvent handle should have been copied to
2730         // VkEvents.
2731         ASSERT(!mRefCountedEvents.map[stage].valid());
2732         ASSERT(mRefCountedEvents.vkEvents[stage] != VK_NULL_HANDLE);
2733         primary->setEvent(mRefCountedEvents.vkEvents[stage], renderer->getPipelineStageMask(stage));
2734     }
2735     mRefCountedEvents.mask.reset();
2736 }
2737 
collectRefCountedEventsGarbage(RefCountedEventsGarbageRecycler * garbageRecycler)2738 void RenderPassCommandBufferHelper::collectRefCountedEventsGarbage(
2739     RefCountedEventsGarbageRecycler *garbageRecycler)
2740 {
2741     // For render pass the VkCmdSetEvent works differently from OutsideRenderPassCommands.
2742     // VkCmdEndRenderPass are called in the primary command buffer, and VkCmdSetEvents has to be
2743     // issued after VkCmdEndRenderPass. This means VkCmdSetEvent has to be delayed. Because of this,
2744     // here we simply make a local copy of the VkEvent and then add the RefCountedEvent to the
2745     // garbage collector. No VkCmdSetEvent call is issued here (they will be issued at
2746     // flushToPrimary time).
2747     for (EventStage stage : mRefCountedEvents.mask)
2748     {
2749         ASSERT(mRefCountedEvents.map[stage].valid());
2750         mRefCountedEvents.vkEvents[stage] = mRefCountedEvents.map[stage].getEvent().getHandle();
2751         mRefCountedEventCollector.emplace_back(std::move(mRefCountedEvents.map[stage]));
2752     }
2753 
2754     if (!mRefCountedEventCollector.empty())
2755     {
2756         garbageRecycler->collectGarbage(mQueueSerial, std::move(mRefCountedEventCollector));
2757     }
2758 }
2759 
beginRenderPass(ContextVk * contextVk,RenderPassFramebuffer && framebuffer,const gl::Rectangle & renderArea,const RenderPassDesc & renderPassDesc,const AttachmentOpsArray & renderPassAttachmentOps,const PackedAttachmentCount colorAttachmentCount,const PackedAttachmentIndex depthStencilAttachmentIndex,const PackedClearValuesArray & clearValues,const QueueSerial & queueSerial,RenderPassCommandBuffer ** commandBufferOut)2760 angle::Result RenderPassCommandBufferHelper::beginRenderPass(
2761     ContextVk *contextVk,
2762     RenderPassFramebuffer &&framebuffer,
2763     const gl::Rectangle &renderArea,
2764     const RenderPassDesc &renderPassDesc,
2765     const AttachmentOpsArray &renderPassAttachmentOps,
2766     const PackedAttachmentCount colorAttachmentCount,
2767     const PackedAttachmentIndex depthStencilAttachmentIndex,
2768     const PackedClearValuesArray &clearValues,
2769     const QueueSerial &queueSerial,
2770     RenderPassCommandBuffer **commandBufferOut)
2771 {
2772     ASSERT(!mRenderPassStarted);
2773 
2774     mRenderPassDesc              = renderPassDesc;
2775     mAttachmentOps               = renderPassAttachmentOps;
2776     mDepthStencilAttachmentIndex = depthStencilAttachmentIndex;
2777     mColorAttachmentsCount       = colorAttachmentCount;
2778     mFramebuffer                 = std::move(framebuffer);
2779     mRenderArea                  = renderArea;
2780     mClearValues                 = clearValues;
2781     mQueueSerial                 = queueSerial;
2782     *commandBufferOut            = &getCommandBuffer();
2783 
2784     mRenderPassStarted = true;
2785     mCounter++;
2786 
2787     return beginRenderPassCommandBuffer(contextVk);
2788 }
2789 
beginRenderPassCommandBuffer(ContextVk * contextVk)2790 angle::Result RenderPassCommandBufferHelper::beginRenderPassCommandBuffer(ContextVk *contextVk)
2791 {
2792     VkCommandBufferInheritanceInfo inheritanceInfo = {};
2793     ANGLE_TRY(RenderPassCommandBuffer::InitializeRenderPassInheritanceInfo(
2794         contextVk, mFramebuffer.getFramebuffer(), mRenderPassDesc, &inheritanceInfo));
2795     inheritanceInfo.subpass = mCurrentSubpassCommandBufferIndex;
2796 
2797     return getCommandBuffer().begin(contextVk, inheritanceInfo);
2798 }
2799 
endRenderPass(ContextVk * contextVk)2800 angle::Result RenderPassCommandBufferHelper::endRenderPass(ContextVk *contextVk)
2801 {
2802     ANGLE_TRY(endRenderPassCommandBuffer(contextVk));
2803 
2804     // *2 for resolve attachments
2805     angle::FixedVector<ImageHelperPtr, gl::IMPLEMENTATION_MAX_FRAMEBUFFER_ATTACHMENTS << 1>
2806         accessedImages;
2807     for (PackedAttachmentIndex index = kAttachmentIndexZero; index < mColorAttachmentsCount;
2808          ++index)
2809     {
2810         if (mColorAttachments[index].getImage() != nullptr)
2811         {
2812             finalizeColorImageLayoutAndLoadStore(contextVk, index);
2813             accessedImages.push_back(mColorAttachments[index].getImage());
2814         }
2815         if (mColorResolveAttachments[index].getImage() != nullptr)
2816         {
2817             finalizeColorImageLayout(contextVk, mColorResolveAttachments[index].getImage(), index,
2818                                      true);
2819             accessedImages.push_back(mColorResolveAttachments[index].getImage());
2820         }
2821     }
2822 
2823     if (mFragmentShadingRateAtachment.getImage() != nullptr)
2824     {
2825         finalizeFragmentShadingRateImageLayout(contextVk);
2826         accessedImages.push_back(mFragmentShadingRateAtachment.getImage());
2827     }
2828 
2829     if (mDepthStencilAttachmentIndex != kAttachmentIndexInvalid)
2830     {
2831         // Do depth stencil layout change and load store optimization.
2832         ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
2833         ASSERT(mDepthResolveAttachment.getImage() == mStencilResolveAttachment.getImage());
2834         if (mDepthAttachment.getImage() != nullptr)
2835         {
2836             finalizeDepthStencilImageLayoutAndLoadStore(contextVk);
2837             accessedImages.push_back(mDepthAttachment.getImage());
2838         }
2839         if (mDepthResolveAttachment.getImage() != nullptr)
2840         {
2841             finalizeDepthStencilResolveImageLayout(contextVk);
2842             accessedImages.push_back(mDepthResolveAttachment.getImage());
2843         }
2844     }
2845 
2846     if (contextVk->getRenderer()->getFeatures().useVkEventForImageBarrier.enabled)
2847     {
2848         // Even if there is no layout change, we always have to update event. In case of feedback
2849         // loop, the sampler code should already set the event, which means we will be set it twice
2850         // here. But since they uses the same layout and event is refCounted, it should work just
2851         // fine.
2852         trackImagesWithEvent(contextVk, accessedImages.data(), accessedImages.size());
2853     }
2854 
2855     return angle::Result::Continue;
2856 }
2857 
endRenderPassCommandBuffer(ContextVk * contextVk)2858 angle::Result RenderPassCommandBufferHelper::endRenderPassCommandBuffer(ContextVk *contextVk)
2859 {
2860     return getCommandBuffer().end(contextVk);
2861 }
2862 
nextSubpass(ContextVk * contextVk,RenderPassCommandBuffer ** commandBufferOut)2863 angle::Result RenderPassCommandBufferHelper::nextSubpass(ContextVk *contextVk,
2864                                                          RenderPassCommandBuffer **commandBufferOut)
2865 {
2866     if (ExecutesInline())
2867     {
2868         // When using ANGLE secondary command buffers, the commands are inline and are executed on
2869         // the primary command buffer.  This means that vkCmdNextSubpass can be intermixed with the
2870         // rest of the commands, and there is no need to split command buffers.
2871         //
2872         // Note also that the command buffer handle doesn't change in this case.
2873         getCommandBuffer().nextSubpass(VK_SUBPASS_CONTENTS_INLINE);
2874         return angle::Result::Continue;
2875     }
2876 
2877     // When using Vulkan secondary command buffers, each subpass's contents must be recorded in a
2878     // separate command buffer that is vkCmdExecuteCommands'ed in the primary command buffer.
2879     // vkCmdNextSubpass calls must also be issued in the primary command buffer.
2880     //
2881     // To support this, a list of command buffers are kept, one for each subpass.  When moving to
2882     // the next subpass, the previous command buffer is ended and a new one is initialized and
2883     // begun.
2884 
2885     // Accumulate command count for tracking purposes.
2886     mPreviousSubpassesCmdCount = getRenderPassWriteCommandCount();
2887 
2888     ANGLE_TRY(endRenderPassCommandBuffer(contextVk));
2889     markClosed();
2890 
2891     ++mCurrentSubpassCommandBufferIndex;
2892     ASSERT(getSubpassCommandBufferCount() <= kMaxSubpassCount);
2893 
2894     ANGLE_TRY(initializeCommandBuffer(contextVk));
2895     ANGLE_TRY(beginRenderPassCommandBuffer(contextVk));
2896     markOpen();
2897 
2898     // Return the new command buffer handle
2899     *commandBufferOut = &getCommandBuffer();
2900     return angle::Result::Continue;
2901 }
2902 
beginTransformFeedback(size_t validBufferCount,const VkBuffer * counterBuffers,const VkDeviceSize * counterBufferOffsets,bool rebindBuffers)2903 void RenderPassCommandBufferHelper::beginTransformFeedback(size_t validBufferCount,
2904                                                            const VkBuffer *counterBuffers,
2905                                                            const VkDeviceSize *counterBufferOffsets,
2906                                                            bool rebindBuffers)
2907 {
2908     mValidTransformFeedbackBufferCount = static_cast<uint32_t>(validBufferCount);
2909     mRebindTransformFeedbackBuffers    = rebindBuffers;
2910 
2911     for (size_t index = 0; index < validBufferCount; index++)
2912     {
2913         mTransformFeedbackCounterBuffers[index]       = counterBuffers[index];
2914         mTransformFeedbackCounterBufferOffsets[index] = counterBufferOffsets[index];
2915     }
2916 }
2917 
endTransformFeedback()2918 void RenderPassCommandBufferHelper::endTransformFeedback()
2919 {
2920     pauseTransformFeedback();
2921     mValidTransformFeedbackBufferCount = 0;
2922 }
2923 
invalidateRenderPassColorAttachment(const gl::State & state,size_t colorIndexGL,PackedAttachmentIndex attachmentIndex,const gl::Rectangle & invalidateArea)2924 void RenderPassCommandBufferHelper::invalidateRenderPassColorAttachment(
2925     const gl::State &state,
2926     size_t colorIndexGL,
2927     PackedAttachmentIndex attachmentIndex,
2928     const gl::Rectangle &invalidateArea)
2929 {
2930     // Color write is enabled if:
2931     //
2932     // - Draw buffer is enabled (this is implicit, as invalidate only affects enabled draw buffers)
2933     // - Color output is not entirely masked
2934     // - Rasterizer-discard is not enabled
2935     const gl::BlendStateExt &blendStateExt = state.getBlendStateExt();
2936     const bool isColorWriteEnabled =
2937         blendStateExt.getColorMaskIndexed(colorIndexGL) != 0 && !state.isRasterizerDiscardEnabled();
2938     mColorAttachments[attachmentIndex].invalidate(invalidateArea, isColorWriteEnabled,
2939                                                   getRenderPassWriteCommandCount());
2940 }
2941 
invalidateRenderPassDepthAttachment(const gl::DepthStencilState & dsState,const gl::Rectangle & invalidateArea)2942 void RenderPassCommandBufferHelper::invalidateRenderPassDepthAttachment(
2943     const gl::DepthStencilState &dsState,
2944     const gl::Rectangle &invalidateArea)
2945 {
2946     const bool isDepthWriteEnabled = dsState.depthTest && dsState.depthMask;
2947     mDepthAttachment.invalidate(invalidateArea, isDepthWriteEnabled,
2948                                 getRenderPassWriteCommandCount());
2949 }
2950 
invalidateRenderPassStencilAttachment(const gl::DepthStencilState & dsState,const gl::Rectangle & invalidateArea)2951 void RenderPassCommandBufferHelper::invalidateRenderPassStencilAttachment(
2952     const gl::DepthStencilState &dsState,
2953     const gl::Rectangle &invalidateArea)
2954 {
2955     const bool isStencilWriteEnabled =
2956         dsState.stencilTest && (!dsState.isStencilNoOp() || !dsState.isStencilBackNoOp());
2957     mStencilAttachment.invalidate(invalidateArea, isStencilWriteEnabled,
2958                                   getRenderPassWriteCommandCount());
2959 }
2960 
flushToPrimary(Context * context,CommandsState * commandsState,const RenderPass & renderPass,VkFramebuffer framebufferOverride)2961 angle::Result RenderPassCommandBufferHelper::flushToPrimary(Context *context,
2962                                                             CommandsState *commandsState,
2963                                                             const RenderPass &renderPass,
2964                                                             VkFramebuffer framebufferOverride)
2965 {
2966     // |framebufferOverride| must only be provided if the initial framebuffer the render pass was
2967     // started with is not usable (due to the addition of resolve attachments after the fact).
2968     ASSERT(framebufferOverride == VK_NULL_HANDLE ||
2969            mFramebuffer.needsNewFramebufferWithResolveAttachments());
2970     // When a new framebuffer had to be created because of addition of resolve attachments, it's
2971     // never imageless.
2972     ASSERT(!(framebufferOverride != VK_NULL_HANDLE && mFramebuffer.isImageless()));
2973 
2974     ANGLE_TRACE_EVENT0("gpu.angle", "RenderPassCommandBufferHelper::flushToPrimary");
2975     ASSERT(mRenderPassStarted);
2976     PrimaryCommandBuffer &primary = commandsState->primaryCommands;
2977 
2978     // Commands that are added to primary before beginRenderPass command
2979     executeBarriers(context->getRenderer(), commandsState);
2980 
2981     VkRenderPassBeginInfo beginInfo = {};
2982     beginInfo.sType                 = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
2983     beginInfo.renderPass            = renderPass.getHandle();
2984     beginInfo.framebuffer =
2985         framebufferOverride ? framebufferOverride : mFramebuffer.getFramebuffer().getHandle();
2986     beginInfo.renderArea.offset.x      = static_cast<uint32_t>(mRenderArea.x);
2987     beginInfo.renderArea.offset.y      = static_cast<uint32_t>(mRenderArea.y);
2988     beginInfo.renderArea.extent.width  = static_cast<uint32_t>(mRenderArea.width);
2989     beginInfo.renderArea.extent.height = static_cast<uint32_t>(mRenderArea.height);
2990     beginInfo.clearValueCount = static_cast<uint32_t>(mRenderPassDesc.clearableAttachmentCount());
2991     beginInfo.pClearValues    = mClearValues.data();
2992 
2993     // With imageless framebuffers, the attachments should be also added to beginInfo.
2994     VkRenderPassAttachmentBeginInfo attachmentBeginInfo = {};
2995     if (mFramebuffer.isImageless())
2996     {
2997         mFramebuffer.packResolveViewsForRenderPassBegin(&attachmentBeginInfo);
2998         AddToPNextChain(&beginInfo, &attachmentBeginInfo);
2999 
3000         // If nullColorAttachmentWithExternalFormatResolve is true, there will be no color
3001         // attachment even though mRenderPassDesc indicates so.
3002         ASSERT((mRenderPassDesc.hasYUVResolveAttachment() &&
3003                 context->getRenderer()->nullColorAttachmentWithExternalFormatResolve()) ||
3004                attachmentBeginInfo.attachmentCount == mRenderPassDesc.attachmentCount());
3005     }
3006 
3007     // Run commands inside the RenderPass.
3008     constexpr VkSubpassContents kSubpassContents =
3009         ExecutesInline() ? VK_SUBPASS_CONTENTS_INLINE
3010                          : VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS;
3011 
3012     primary.beginRenderPass(beginInfo, kSubpassContents);
3013     for (uint32_t subpass = 0; subpass < getSubpassCommandBufferCount(); ++subpass)
3014     {
3015         if (subpass > 0)
3016         {
3017             primary.nextSubpass(kSubpassContents);
3018         }
3019         mCommandBuffers[subpass].executeCommands(&primary);
3020     }
3021     primary.endRenderPass();
3022 
3023     // Now issue VkCmdSetEvents to primary command buffer
3024     executeSetEvents(context, &primary);
3025 
3026     // Restart the command buffer.
3027     return reset(context, &commandsState->secondaryCommands);
3028 }
3029 
addColorResolveAttachment(size_t colorIndexGL,VkImageView view)3030 void RenderPassCommandBufferHelper::addColorResolveAttachment(size_t colorIndexGL, VkImageView view)
3031 {
3032     mFramebuffer.addColorResolveAttachment(colorIndexGL, view);
3033     mRenderPassDesc.packColorResolveAttachment(colorIndexGL);
3034 }
3035 
addDepthStencilResolveAttachment(VkImageView view,VkImageAspectFlags aspects)3036 void RenderPassCommandBufferHelper::addDepthStencilResolveAttachment(VkImageView view,
3037                                                                      VkImageAspectFlags aspects)
3038 {
3039     mFramebuffer.addDepthStencilResolveAttachment(view);
3040     if ((aspects & VK_IMAGE_ASPECT_DEPTH_BIT) != 0)
3041     {
3042         mRenderPassDesc.packDepthResolveAttachment();
3043     }
3044     if ((aspects & VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
3045     {
3046         mRenderPassDesc.packStencilResolveAttachment();
3047     }
3048 }
3049 
resumeTransformFeedback()3050 void RenderPassCommandBufferHelper::resumeTransformFeedback()
3051 {
3052     ASSERT(isTransformFeedbackStarted());
3053 
3054     uint32_t numCounterBuffers =
3055         mRebindTransformFeedbackBuffers ? 0 : mValidTransformFeedbackBufferCount;
3056 
3057     mRebindTransformFeedbackBuffers    = false;
3058     mIsTransformFeedbackActiveUnpaused = true;
3059 
3060     getCommandBuffer().beginTransformFeedback(0, numCounterBuffers,
3061                                               mTransformFeedbackCounterBuffers.data(),
3062                                               mTransformFeedbackCounterBufferOffsets.data());
3063 }
3064 
pauseTransformFeedback()3065 void RenderPassCommandBufferHelper::pauseTransformFeedback()
3066 {
3067     ASSERT(isTransformFeedbackStarted() && isTransformFeedbackActiveUnpaused());
3068     mIsTransformFeedbackActiveUnpaused = false;
3069     getCommandBuffer().endTransformFeedback(0, mValidTransformFeedbackBufferCount,
3070                                             mTransformFeedbackCounterBuffers.data(),
3071                                             mTransformFeedbackCounterBufferOffsets.data());
3072 }
3073 
updateRenderPassColorClear(PackedAttachmentIndex colorIndexVk,const VkClearValue & clearValue)3074 void RenderPassCommandBufferHelper::updateRenderPassColorClear(PackedAttachmentIndex colorIndexVk,
3075                                                                const VkClearValue &clearValue)
3076 {
3077     mAttachmentOps.setClearOp(colorIndexVk);
3078     mClearValues.store(colorIndexVk, VK_IMAGE_ASPECT_COLOR_BIT, clearValue);
3079 }
3080 
updateRenderPassDepthStencilClear(VkImageAspectFlags aspectFlags,const VkClearValue & clearValue)3081 void RenderPassCommandBufferHelper::updateRenderPassDepthStencilClear(
3082     VkImageAspectFlags aspectFlags,
3083     const VkClearValue &clearValue)
3084 {
3085     // Don't overwrite prior clear values for individual aspects.
3086     VkClearValue combinedClearValue = mClearValues[mDepthStencilAttachmentIndex];
3087 
3088     if ((aspectFlags & VK_IMAGE_ASPECT_DEPTH_BIT) != 0)
3089     {
3090         mAttachmentOps.setClearOp(mDepthStencilAttachmentIndex);
3091         combinedClearValue.depthStencil.depth = clearValue.depthStencil.depth;
3092     }
3093 
3094     if ((aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
3095     {
3096         mAttachmentOps.setClearStencilOp(mDepthStencilAttachmentIndex);
3097         combinedClearValue.depthStencil.stencil = clearValue.depthStencil.stencil;
3098     }
3099 
3100     // Bypass special D/S handling. This clear values array stores values packed.
3101     mClearValues.storeNoDepthStencil(mDepthStencilAttachmentIndex, combinedClearValue);
3102 }
3103 
growRenderArea(ContextVk * contextVk,const gl::Rectangle & newRenderArea)3104 void RenderPassCommandBufferHelper::growRenderArea(ContextVk *contextVk,
3105                                                    const gl::Rectangle &newRenderArea)
3106 {
3107     // The render area is grown such that it covers both the previous and the new render areas.
3108     gl::GetEnclosingRectangle(mRenderArea, newRenderArea, &mRenderArea);
3109 
3110     // Remove invalidates that are no longer applicable.
3111     mDepthAttachment.onRenderAreaGrowth(contextVk, mRenderArea);
3112     mStencilAttachment.onRenderAreaGrowth(contextVk, mRenderArea);
3113 }
3114 
attachCommandPool(Context * context,SecondaryCommandPool * commandPool)3115 angle::Result RenderPassCommandBufferHelper::attachCommandPool(Context *context,
3116                                                                SecondaryCommandPool *commandPool)
3117 {
3118     ASSERT(!mRenderPassStarted);
3119     ASSERT(getSubpassCommandBufferCount() == 1);
3120     return attachCommandPoolImpl<RenderPassCommandBufferHelper>(context, commandPool);
3121 }
3122 
detachCommandPool(SecondaryCommandPool ** commandPoolOut)3123 void RenderPassCommandBufferHelper::detachCommandPool(SecondaryCommandPool **commandPoolOut)
3124 {
3125     ASSERT(mRenderPassStarted);
3126     angle::Result result =
3127         detachCommandPoolImpl<RenderPassCommandBufferHelper, true>(nullptr, commandPoolOut);
3128     ASSERT(result == angle::Result::Continue);
3129 }
3130 
releaseCommandPool()3131 void RenderPassCommandBufferHelper::releaseCommandPool()
3132 {
3133     ASSERT(!mRenderPassStarted);
3134     ASSERT(getSubpassCommandBufferCount() == 1);
3135     releaseCommandPoolImpl<RenderPassCommandBufferHelper>();
3136 }
3137 
attachAllocator(SecondaryCommandMemoryAllocator * allocator)3138 void RenderPassCommandBufferHelper::attachAllocator(SecondaryCommandMemoryAllocator *allocator)
3139 {
3140     ASSERT(CheckSubpassCommandBufferCount(getSubpassCommandBufferCount()));
3141     attachAllocatorImpl<RenderPassCommandBufferHelper>(allocator);
3142 }
3143 
detachAllocator()3144 SecondaryCommandMemoryAllocator *RenderPassCommandBufferHelper::detachAllocator()
3145 {
3146     ASSERT(CheckSubpassCommandBufferCount(getSubpassCommandBufferCount()));
3147     return detachAllocatorImpl<RenderPassCommandBufferHelper>();
3148 }
3149 
assertCanBeRecycled()3150 void RenderPassCommandBufferHelper::assertCanBeRecycled()
3151 {
3152     ASSERT(!mRenderPassStarted);
3153     ASSERT(getSubpassCommandBufferCount() == 1);
3154     assertCanBeRecycledImpl<RenderPassCommandBufferHelper>();
3155 }
3156 
getCommandDiagnostics()3157 std::string RenderPassCommandBufferHelper::getCommandDiagnostics()
3158 {
3159     std::ostringstream out;
3160     addCommandDiagnosticsCommon(&out);
3161 
3162     size_t attachmentCount             = mRenderPassDesc.clearableAttachmentCount();
3163     size_t depthStencilAttachmentCount = mRenderPassDesc.hasDepthStencilAttachment() ? 1 : 0;
3164     size_t colorAttachmentCount        = attachmentCount - depthStencilAttachmentCount;
3165 
3166     PackedAttachmentIndex attachmentIndexVk(0);
3167     std::string loadOps, storeOps;
3168 
3169     if (colorAttachmentCount > 0)
3170     {
3171         loadOps += " Color: ";
3172         storeOps += " Color: ";
3173 
3174         for (size_t i = 0; i < colorAttachmentCount; ++i)
3175         {
3176             loadOps += GetLoadOpShorthand(
3177                 static_cast<RenderPassLoadOp>(mAttachmentOps[attachmentIndexVk].loadOp));
3178             storeOps += GetStoreOpShorthand(
3179                 static_cast<RenderPassStoreOp>(mAttachmentOps[attachmentIndexVk].storeOp));
3180             ++attachmentIndexVk;
3181         }
3182     }
3183 
3184     if (depthStencilAttachmentCount > 0)
3185     {
3186         ASSERT(depthStencilAttachmentCount == 1);
3187 
3188         loadOps += " Depth/Stencil: ";
3189         storeOps += " Depth/Stencil: ";
3190 
3191         loadOps += GetLoadOpShorthand(
3192             static_cast<RenderPassLoadOp>(mAttachmentOps[attachmentIndexVk].loadOp));
3193         loadOps += GetLoadOpShorthand(
3194             static_cast<RenderPassLoadOp>(mAttachmentOps[attachmentIndexVk].stencilLoadOp));
3195 
3196         storeOps += GetStoreOpShorthand(
3197             static_cast<RenderPassStoreOp>(mAttachmentOps[attachmentIndexVk].storeOp));
3198         storeOps += GetStoreOpShorthand(
3199             static_cast<RenderPassStoreOp>(mAttachmentOps[attachmentIndexVk].stencilStoreOp));
3200     }
3201 
3202     if (attachmentCount > 0)
3203     {
3204         out << "LoadOp:  " << loadOps << "\\l";
3205         out << "StoreOp: " << storeOps << "\\l";
3206     }
3207 
3208     for (uint32_t subpass = 0; subpass < getSubpassCommandBufferCount(); ++subpass)
3209     {
3210         if (subpass > 0)
3211         {
3212             out << "Next Subpass" << "\\l";
3213         }
3214         out << mCommandBuffers[subpass].dumpCommands("\\l");
3215     }
3216 
3217     return out.str();
3218 }
3219 
3220 // CommandBufferRecycler implementation.
3221 template <typename CommandBufferHelperT>
onDestroy()3222 void CommandBufferRecycler<CommandBufferHelperT>::onDestroy()
3223 {
3224     std::unique_lock<angle::SimpleMutex> lock(mMutex);
3225     for (CommandBufferHelperT *commandBufferHelper : mCommandBufferHelperFreeList)
3226     {
3227         SafeDelete(commandBufferHelper);
3228     }
3229     mCommandBufferHelperFreeList.clear();
3230 }
3231 
3232 template void CommandBufferRecycler<OutsideRenderPassCommandBufferHelper>::onDestroy();
3233 template void CommandBufferRecycler<RenderPassCommandBufferHelper>::onDestroy();
3234 
3235 template <typename CommandBufferHelperT>
getCommandBufferHelper(Context * context,SecondaryCommandPool * commandPool,SecondaryCommandMemoryAllocator * commandsAllocator,CommandBufferHelperT ** commandBufferHelperOut)3236 angle::Result CommandBufferRecycler<CommandBufferHelperT>::getCommandBufferHelper(
3237     Context *context,
3238     SecondaryCommandPool *commandPool,
3239     SecondaryCommandMemoryAllocator *commandsAllocator,
3240     CommandBufferHelperT **commandBufferHelperOut)
3241 {
3242     std::unique_lock<angle::SimpleMutex> lock(mMutex);
3243     if (mCommandBufferHelperFreeList.empty())
3244     {
3245         CommandBufferHelperT *commandBuffer = new CommandBufferHelperT();
3246         *commandBufferHelperOut             = commandBuffer;
3247         ANGLE_TRY(commandBuffer->initialize(context));
3248     }
3249     else
3250     {
3251         CommandBufferHelperT *commandBuffer = mCommandBufferHelperFreeList.back();
3252         mCommandBufferHelperFreeList.pop_back();
3253         *commandBufferHelperOut = commandBuffer;
3254     }
3255 
3256     ANGLE_TRY((*commandBufferHelperOut)->attachCommandPool(context, commandPool));
3257 
3258     // Attach functions are only used for ring buffer allocators.
3259     (*commandBufferHelperOut)->attachAllocator(commandsAllocator);
3260 
3261     return angle::Result::Continue;
3262 }
3263 
3264 template angle::Result
3265 CommandBufferRecycler<OutsideRenderPassCommandBufferHelper>::getCommandBufferHelper(
3266     Context *,
3267     SecondaryCommandPool *,
3268     SecondaryCommandMemoryAllocator *,
3269     OutsideRenderPassCommandBufferHelper **);
3270 template angle::Result CommandBufferRecycler<RenderPassCommandBufferHelper>::getCommandBufferHelper(
3271     Context *,
3272     SecondaryCommandPool *,
3273     SecondaryCommandMemoryAllocator *,
3274     RenderPassCommandBufferHelper **);
3275 
3276 template <typename CommandBufferHelperT>
recycleCommandBufferHelper(CommandBufferHelperT ** commandBuffer)3277 void CommandBufferRecycler<CommandBufferHelperT>::recycleCommandBufferHelper(
3278     CommandBufferHelperT **commandBuffer)
3279 {
3280     (*commandBuffer)->assertCanBeRecycled();
3281     (*commandBuffer)->markOpen();
3282 
3283     {
3284         std::unique_lock<angle::SimpleMutex> lock(mMutex);
3285         mCommandBufferHelperFreeList.push_back(*commandBuffer);
3286     }
3287 
3288     *commandBuffer = nullptr;
3289 }
3290 
3291 template void
3292 CommandBufferRecycler<OutsideRenderPassCommandBufferHelper>::recycleCommandBufferHelper(
3293     OutsideRenderPassCommandBufferHelper **);
3294 template void CommandBufferRecycler<RenderPassCommandBufferHelper>::recycleCommandBufferHelper(
3295     RenderPassCommandBufferHelper **);
3296 
3297 // SecondaryCommandBufferCollector implementation.
collectCommandBuffer(priv::SecondaryCommandBuffer && commandBuffer)3298 void SecondaryCommandBufferCollector::collectCommandBuffer(
3299     priv::SecondaryCommandBuffer &&commandBuffer)
3300 {
3301     commandBuffer.reset();
3302 }
3303 
collectCommandBuffer(VulkanSecondaryCommandBuffer && commandBuffer)3304 void SecondaryCommandBufferCollector::collectCommandBuffer(
3305     VulkanSecondaryCommandBuffer &&commandBuffer)
3306 {
3307     ASSERT(commandBuffer.valid());
3308     mCollectedCommandBuffers.emplace_back(std::move(commandBuffer));
3309 }
3310 
retireCommandBuffers()3311 void SecondaryCommandBufferCollector::retireCommandBuffers()
3312 {
3313     // Note: we currently free the command buffers individually, but we could potentially reset the
3314     // entire command pool.  https://issuetracker.google.com/issues/166793850
3315     for (VulkanSecondaryCommandBuffer &commandBuffer : mCollectedCommandBuffers)
3316     {
3317         commandBuffer.destroy();
3318     }
3319     mCollectedCommandBuffers.clear();
3320 }
3321 
3322 // DynamicBuffer implementation.
DynamicBuffer()3323 DynamicBuffer::DynamicBuffer()
3324     : mUsage(0),
3325       mHostVisible(false),
3326       mInitialSize(0),
3327       mNextAllocationOffset(0),
3328       mSize(0),
3329       mSizeInRecentHistory(0),
3330       mAlignment(0),
3331       mMemoryPropertyFlags(0)
3332 {}
3333 
DynamicBuffer(DynamicBuffer && other)3334 DynamicBuffer::DynamicBuffer(DynamicBuffer &&other)
3335     : mUsage(other.mUsage),
3336       mHostVisible(other.mHostVisible),
3337       mInitialSize(other.mInitialSize),
3338       mBuffer(std::move(other.mBuffer)),
3339       mNextAllocationOffset(other.mNextAllocationOffset),
3340       mSize(other.mSize),
3341       mSizeInRecentHistory(other.mSizeInRecentHistory),
3342       mAlignment(other.mAlignment),
3343       mMemoryPropertyFlags(other.mMemoryPropertyFlags),
3344       mInFlightBuffers(std::move(other.mInFlightBuffers)),
3345       mBufferFreeList(std::move(other.mBufferFreeList))
3346 {}
3347 
init(Renderer * renderer,VkBufferUsageFlags usage,size_t alignment,size_t initialSize,bool hostVisible)3348 void DynamicBuffer::init(Renderer *renderer,
3349                          VkBufferUsageFlags usage,
3350                          size_t alignment,
3351                          size_t initialSize,
3352                          bool hostVisible)
3353 {
3354     mUsage       = usage;
3355     mHostVisible = hostVisible;
3356     mMemoryPropertyFlags =
3357         (hostVisible) ? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT : VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
3358 
3359     if (hostVisible && renderer->getFeatures().preferHostCachedForNonStaticBufferUsage.enabled)
3360     {
3361         mMemoryPropertyFlags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
3362     }
3363 
3364     // Check that we haven't overridden the initial size of the buffer in setMinimumSizeForTesting.
3365     if (mInitialSize == 0)
3366     {
3367         mInitialSize         = initialSize;
3368         mSize                = 0;
3369         mSizeInRecentHistory = initialSize;
3370     }
3371 
3372     // Workaround for the mock ICD not supporting allocations greater than 0x1000.
3373     // Could be removed if https://github.com/KhronosGroup/Vulkan-Tools/issues/84 is fixed.
3374     if (renderer->isMockICDEnabled())
3375     {
3376         mSize = std::min<size_t>(mSize, 0x1000);
3377     }
3378 
3379     requireAlignment(renderer, alignment);
3380 }
3381 
~DynamicBuffer()3382 DynamicBuffer::~DynamicBuffer()
3383 {
3384     ASSERT(mBuffer == nullptr);
3385     ASSERT(mInFlightBuffers.empty());
3386     ASSERT(mBufferFreeList.empty());
3387 }
3388 
allocateNewBuffer(Context * context)3389 angle::Result DynamicBuffer::allocateNewBuffer(Context *context)
3390 {
3391     context->getPerfCounters().dynamicBufferAllocations++;
3392 
3393     // Allocate the buffer
3394     ASSERT(!mBuffer);
3395     mBuffer = std::make_unique<BufferHelper>();
3396 
3397     VkBufferCreateInfo createInfo    = {};
3398     createInfo.sType                 = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
3399     createInfo.flags                 = 0;
3400     createInfo.size                  = mSize;
3401     createInfo.usage                 = mUsage;
3402     createInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
3403     createInfo.queueFamilyIndexCount = 0;
3404     createInfo.pQueueFamilyIndices   = nullptr;
3405 
3406     return mBuffer->init(context, createInfo, mMemoryPropertyFlags);
3407 }
3408 
allocateFromCurrentBuffer(size_t sizeInBytes,BufferHelper ** bufferHelperOut)3409 bool DynamicBuffer::allocateFromCurrentBuffer(size_t sizeInBytes, BufferHelper **bufferHelperOut)
3410 {
3411     mNextAllocationOffset =
3412         roundUp<uint32_t>(mNextAllocationOffset, static_cast<uint32_t>(mAlignment));
3413 
3414     ASSERT(bufferHelperOut);
3415     size_t sizeToAllocate                                      = roundUp(sizeInBytes, mAlignment);
3416     angle::base::CheckedNumeric<size_t> checkedNextWriteOffset = mNextAllocationOffset;
3417     checkedNextWriteOffset += sizeToAllocate;
3418 
3419     if (!checkedNextWriteOffset.IsValid() || checkedNextWriteOffset.ValueOrDie() > mSize)
3420     {
3421         return false;
3422     }
3423 
3424     ASSERT(mBuffer != nullptr);
3425     ASSERT(mHostVisible);
3426     ASSERT(mBuffer->getMappedMemory());
3427     mBuffer->setSuballocationOffsetAndSize(mNextAllocationOffset, sizeToAllocate);
3428     *bufferHelperOut = mBuffer.get();
3429 
3430     mNextAllocationOffset += static_cast<uint32_t>(sizeToAllocate);
3431     return true;
3432 }
3433 
allocate(Context * context,size_t sizeInBytes,BufferHelper ** bufferHelperOut,bool * newBufferAllocatedOut)3434 angle::Result DynamicBuffer::allocate(Context *context,
3435                                       size_t sizeInBytes,
3436                                       BufferHelper **bufferHelperOut,
3437                                       bool *newBufferAllocatedOut)
3438 {
3439     bool newBuffer = !allocateFromCurrentBuffer(sizeInBytes, bufferHelperOut);
3440     if (newBufferAllocatedOut)
3441     {
3442         *newBufferAllocatedOut = newBuffer;
3443     }
3444 
3445     if (!newBuffer)
3446     {
3447         return angle::Result::Continue;
3448     }
3449 
3450     size_t sizeToAllocate = roundUp(sizeInBytes, mAlignment);
3451 
3452     if (mBuffer)
3453     {
3454         // Make sure the buffer is not released externally.
3455         ASSERT(mBuffer->valid());
3456         mInFlightBuffers.push_back(std::move(mBuffer));
3457         ASSERT(!mBuffer);
3458     }
3459 
3460     Renderer *renderer = context->getRenderer();
3461 
3462     const size_t minRequiredBlockSize = std::max(mInitialSize, sizeToAllocate);
3463 
3464     // The average required buffer size in recent history is used to determine whether the currently
3465     // used buffer size needs to be reduced (when it goes below 1/8 of the current buffer size).
3466     constexpr uint32_t kDecayCoeffPercent = 20;
3467     static_assert(kDecayCoeffPercent >= 0 && kDecayCoeffPercent <= 100);
3468     mSizeInRecentHistory = (mSizeInRecentHistory * kDecayCoeffPercent +
3469                             minRequiredBlockSize * (100 - kDecayCoeffPercent) + 50) /
3470                            100;
3471 
3472     if (sizeToAllocate > mSize || mSizeInRecentHistory < mSize / 8)
3473     {
3474         mSize = minRequiredBlockSize;
3475         // Clear the free list since the free buffers are now either too small or too big.
3476         ReleaseBufferListToRenderer(renderer, &mBufferFreeList);
3477     }
3478 
3479     // The front of the free list should be the oldest. Thus if it is in use the rest of the
3480     // free list should be in use as well.
3481     if (mBufferFreeList.empty() ||
3482         !renderer->hasResourceUseFinished(mBufferFreeList.front()->getResourceUse()))
3483     {
3484         ANGLE_TRY(allocateNewBuffer(context));
3485     }
3486     else
3487     {
3488         mBuffer = std::move(mBufferFreeList.front());
3489         mBufferFreeList.pop_front();
3490     }
3491 
3492     ASSERT(mBuffer->getBlockMemorySize() == mSize);
3493 
3494     mNextAllocationOffset = 0;
3495 
3496     ASSERT(mBuffer != nullptr);
3497     mBuffer->setSuballocationOffsetAndSize(mNextAllocationOffset, sizeToAllocate);
3498     *bufferHelperOut = mBuffer.get();
3499 
3500     mNextAllocationOffset += static_cast<uint32_t>(sizeToAllocate);
3501     return angle::Result::Continue;
3502 }
3503 
release(Renderer * renderer)3504 void DynamicBuffer::release(Renderer *renderer)
3505 {
3506     reset();
3507 
3508     ReleaseBufferListToRenderer(renderer, &mInFlightBuffers);
3509     ReleaseBufferListToRenderer(renderer, &mBufferFreeList);
3510 
3511     if (mBuffer)
3512     {
3513         mBuffer->release(renderer);
3514         mBuffer.reset(nullptr);
3515     }
3516 }
3517 
updateQueueSerialAndReleaseInFlightBuffers(ContextVk * contextVk,const QueueSerial & queueSerial)3518 void DynamicBuffer::updateQueueSerialAndReleaseInFlightBuffers(ContextVk *contextVk,
3519                                                                const QueueSerial &queueSerial)
3520 {
3521     for (std::unique_ptr<BufferHelper> &bufferHelper : mInFlightBuffers)
3522     {
3523         // This function is used only for internal buffers, and they are all read-only.
3524         // It's possible this may change in the future, but there isn't a good way to detect that,
3525         // unfortunately.
3526         bufferHelper->setQueueSerial(queueSerial);
3527 
3528         // We only keep free buffers that have the same size. Note that bufferHelper's size is
3529         // suballocation's size. We need to use the whole block memory size here.
3530         if (bufferHelper->getBlockMemorySize() != mSize)
3531         {
3532             bufferHelper->release(contextVk->getRenderer());
3533         }
3534         else
3535         {
3536             mBufferFreeList.push_back(std::move(bufferHelper));
3537         }
3538     }
3539     mInFlightBuffers.clear();
3540 }
3541 
destroy(Renderer * renderer)3542 void DynamicBuffer::destroy(Renderer *renderer)
3543 {
3544     reset();
3545 
3546     DestroyBufferList(renderer, &mInFlightBuffers);
3547     DestroyBufferList(renderer, &mBufferFreeList);
3548 
3549     if (mBuffer)
3550     {
3551         mBuffer->unmap(renderer);
3552         mBuffer->destroy(renderer);
3553         mBuffer.reset(nullptr);
3554     }
3555 }
3556 
requireAlignment(Renderer * renderer,size_t alignment)3557 void DynamicBuffer::requireAlignment(Renderer *renderer, size_t alignment)
3558 {
3559     ASSERT(alignment > 0);
3560 
3561     size_t prevAlignment = mAlignment;
3562 
3563     // If alignment was never set, initialize it with the atom size limit.
3564     if (prevAlignment == 0)
3565     {
3566         prevAlignment =
3567             static_cast<size_t>(renderer->getPhysicalDeviceProperties().limits.nonCoherentAtomSize);
3568         ASSERT(gl::isPow2(prevAlignment));
3569     }
3570 
3571     // We need lcm(prevAlignment, alignment).  Usually, one divides the other so std::max() could be
3572     // used instead.  Only known case where this assumption breaks is for 3-component types with
3573     // 16- or 32-bit channels, so that's special-cased to avoid a full-fledged lcm implementation.
3574 
3575     if (gl::isPow2(prevAlignment * alignment))
3576     {
3577         ASSERT(alignment % prevAlignment == 0 || prevAlignment % alignment == 0);
3578 
3579         alignment = std::max(prevAlignment, alignment);
3580     }
3581     else
3582     {
3583         ASSERT(prevAlignment % 3 != 0 || gl::isPow2(prevAlignment / 3));
3584         ASSERT(alignment % 3 != 0 || gl::isPow2(alignment / 3));
3585 
3586         prevAlignment = prevAlignment % 3 == 0 ? prevAlignment / 3 : prevAlignment;
3587         alignment     = alignment % 3 == 0 ? alignment / 3 : alignment;
3588 
3589         alignment = std::max(prevAlignment, alignment) * 3;
3590     }
3591 
3592     // If alignment has changed, make sure the next allocation is done at an aligned offset.
3593     if (alignment != mAlignment)
3594     {
3595         mNextAllocationOffset = roundUp(mNextAllocationOffset, static_cast<uint32_t>(alignment));
3596     }
3597 
3598     mAlignment = alignment;
3599 }
3600 
setMinimumSizeForTesting(size_t minSize)3601 void DynamicBuffer::setMinimumSizeForTesting(size_t minSize)
3602 {
3603     // This will really only have an effect next time we call allocate.
3604     mInitialSize = minSize;
3605 
3606     // Forces a new allocation on the next allocate.
3607     mSize                = 0;
3608     mSizeInRecentHistory = 0;
3609 }
3610 
reset()3611 void DynamicBuffer::reset()
3612 {
3613     mSize                 = 0;
3614     mSizeInRecentHistory  = 0;
3615     mNextAllocationOffset = 0;
3616 }
3617 
3618 // BufferPool implementation.
BufferPool()3619 BufferPool::BufferPool()
3620     : mVirtualBlockCreateFlags(vma::VirtualBlockCreateFlagBits::GENERAL),
3621       mUsage(0),
3622       mHostVisible(false),
3623       mSize(0),
3624       mMemoryTypeIndex(0),
3625       mTotalMemorySize(0),
3626       mNumberOfNewBuffersNeededSinceLastPrune(0)
3627 {}
3628 
BufferPool(BufferPool && other)3629 BufferPool::BufferPool(BufferPool &&other)
3630     : mVirtualBlockCreateFlags(other.mVirtualBlockCreateFlags),
3631       mUsage(other.mUsage),
3632       mHostVisible(other.mHostVisible),
3633       mSize(other.mSize),
3634       mMemoryTypeIndex(other.mMemoryTypeIndex)
3635 {}
3636 
initWithFlags(Renderer * renderer,vma::VirtualBlockCreateFlags flags,VkBufferUsageFlags usage,VkDeviceSize initialSize,uint32_t memoryTypeIndex,VkMemoryPropertyFlags memoryPropertyFlags)3637 void BufferPool::initWithFlags(Renderer *renderer,
3638                                vma::VirtualBlockCreateFlags flags,
3639                                VkBufferUsageFlags usage,
3640                                VkDeviceSize initialSize,
3641                                uint32_t memoryTypeIndex,
3642                                VkMemoryPropertyFlags memoryPropertyFlags)
3643 {
3644     mVirtualBlockCreateFlags = flags;
3645     mUsage                   = usage;
3646     mMemoryTypeIndex         = memoryTypeIndex;
3647     if (initialSize)
3648     {
3649         // Should be power of two
3650         ASSERT(gl::isPow2(initialSize));
3651         mSize = initialSize;
3652     }
3653     else
3654     {
3655         mSize = renderer->getPreferedBufferBlockSize(memoryTypeIndex);
3656     }
3657     mHostVisible = ((memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0);
3658 }
3659 
~BufferPool()3660 BufferPool::~BufferPool()
3661 {
3662     ASSERT(mBufferBlocks.empty());
3663     ASSERT(mEmptyBufferBlocks.empty());
3664 }
3665 
pruneEmptyBuffers(Renderer * renderer)3666 void BufferPool::pruneEmptyBuffers(Renderer *renderer)
3667 {
3668     // First try to walk through mBuffers and move empty buffers to mEmptyBuffer and remove null
3669     // pointers for allocation performance.
3670     // The expectation is that we will find none needs to be compacted in most calls.
3671     bool needsCompact = false;
3672     for (std::unique_ptr<BufferBlock> &block : mBufferBlocks)
3673     {
3674         if (block->isEmpty())
3675         {
3676             // We will always free empty buffers that has smaller size. Or if the empty buffer has
3677             // been found empty for long enough time, or we accumulated too many empty buffers, we
3678             // also free it.
3679             if (block->getMemorySize() < mSize)
3680             {
3681                 mTotalMemorySize -= block->getMemorySize();
3682                 block->destroy(renderer);
3683                 block.reset();
3684             }
3685             else
3686             {
3687                 mEmptyBufferBlocks.push_back(std::move(block));
3688             }
3689             needsCompact = true;
3690         }
3691     }
3692 
3693     // Now remove the null pointers that left by empty buffers all at once, if any.
3694     if (needsCompact)
3695     {
3696         BufferBlockPointerVector compactedBlocks;
3697         for (std::unique_ptr<BufferBlock> &block : mBufferBlocks)
3698         {
3699             if (block)
3700             {
3701                 compactedBlocks.push_back(std::move(block));
3702             }
3703         }
3704         mBufferBlocks = std::move(compactedBlocks);
3705     }
3706 
3707     // Decide how many empty buffers to keep around and trim down the excessive empty buffers. We
3708     // keep track of how many buffers are needed since last prune. Assume we are in stable state,
3709     // which means we may still need that many empty buffers in next prune cycle. To reduce chance
3710     // to call into vulkan driver to allocate new buffers, we try to keep that many empty buffers
3711     // around, subject to the maximum cap. If we overestimate, next cycle they used fewer buffers,
3712     // we will trim excessive empty buffers at next prune call. Or if we underestimate, we will end
3713     // up have to call into vulkan driver allocate new buffers, but next cycle we should correct
3714     // ourselves to keep enough number of empty buffers around.
3715     size_t buffersToKeep = std::min(mNumberOfNewBuffersNeededSinceLastPrune,
3716                                     static_cast<size_t>(kMaxTotalEmptyBufferBytes / mSize));
3717     while (mEmptyBufferBlocks.size() > buffersToKeep)
3718     {
3719         std::unique_ptr<BufferBlock> &block = mEmptyBufferBlocks.back();
3720         mTotalMemorySize -= block->getMemorySize();
3721         block->destroy(renderer);
3722         mEmptyBufferBlocks.pop_back();
3723     }
3724     mNumberOfNewBuffersNeededSinceLastPrune = 0;
3725 }
3726 
allocateNewBuffer(Context * context,VkDeviceSize sizeInBytes)3727 VkResult BufferPool::allocateNewBuffer(Context *context, VkDeviceSize sizeInBytes)
3728 {
3729     Renderer *renderer         = context->getRenderer();
3730     const Allocator &allocator = renderer->getAllocator();
3731 
3732     VkDeviceSize heapSize =
3733         renderer->getMemoryProperties().getHeapSizeForMemoryType(mMemoryTypeIndex);
3734 
3735     // First ensure we are not exceeding the heapSize to avoid the validation error.
3736     VK_RESULT_CHECK(sizeInBytes <= heapSize, VK_ERROR_OUT_OF_DEVICE_MEMORY);
3737 
3738     // Double the size until meet the requirement. This also helps reducing the fragmentation. Since
3739     // this is global pool, we have less worry about memory waste.
3740     VkDeviceSize newSize = mSize;
3741     while (newSize < sizeInBytes)
3742     {
3743         newSize <<= 1;
3744     }
3745     mSize = std::min(newSize, heapSize);
3746 
3747     // Allocate buffer
3748     VkBufferCreateInfo createInfo    = {};
3749     createInfo.sType                 = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
3750     createInfo.flags                 = 0;
3751     createInfo.size                  = mSize;
3752     createInfo.usage                 = mUsage;
3753     createInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
3754     createInfo.queueFamilyIndexCount = 0;
3755     createInfo.pQueueFamilyIndices   = nullptr;
3756 
3757     VkMemoryPropertyFlags memoryPropertyFlags;
3758     allocator.getMemoryTypeProperties(mMemoryTypeIndex, &memoryPropertyFlags);
3759 
3760     DeviceScoped<Buffer> buffer(renderer->getDevice());
3761     VK_RESULT_TRY(buffer.get().init(context->getDevice(), createInfo));
3762 
3763     DeviceScoped<DeviceMemory> deviceMemory(renderer->getDevice());
3764     VkMemoryPropertyFlags memoryPropertyFlagsOut;
3765     VkDeviceSize sizeOut;
3766     uint32_t memoryTypeIndex;
3767     VK_RESULT_TRY(AllocateBufferMemory(context, MemoryAllocationType::Buffer, memoryPropertyFlags,
3768                                        &memoryPropertyFlagsOut, nullptr, &buffer.get(),
3769                                        &memoryTypeIndex, &deviceMemory.get(), &sizeOut));
3770     ASSERT(sizeOut >= mSize);
3771 
3772     // Allocate bufferBlock
3773     std::unique_ptr<BufferBlock> block = std::make_unique<BufferBlock>();
3774     VK_RESULT_TRY(block->init(context, buffer.get(), memoryTypeIndex, mVirtualBlockCreateFlags,
3775                               deviceMemory.get(), memoryPropertyFlagsOut, mSize));
3776 
3777     if (mHostVisible)
3778     {
3779         VK_RESULT_TRY(block->map(context->getDevice()));
3780     }
3781 
3782     mTotalMemorySize += block->getMemorySize();
3783     // Append the bufferBlock into the pool
3784     mBufferBlocks.push_back(std::move(block));
3785     context->getPerfCounters().allocateNewBufferBlockCalls++;
3786 
3787     return VK_SUCCESS;
3788 }
3789 
allocateBuffer(Context * context,VkDeviceSize sizeInBytes,VkDeviceSize alignment,BufferSuballocation * suballocation)3790 VkResult BufferPool::allocateBuffer(Context *context,
3791                                     VkDeviceSize sizeInBytes,
3792                                     VkDeviceSize alignment,
3793                                     BufferSuballocation *suballocation)
3794 {
3795     ASSERT(alignment);
3796     VmaVirtualAllocation allocation;
3797     VkDeviceSize offset;
3798     VkDeviceSize alignedSize = roundUp(sizeInBytes, alignment);
3799 
3800     if (alignedSize >= kMaxBufferSizeForSuballocation)
3801     {
3802         VkDeviceSize heapSize =
3803             context->getRenderer()->getMemoryProperties().getHeapSizeForMemoryType(
3804                 mMemoryTypeIndex);
3805         // First ensure we are not exceeding the heapSize to avoid the validation error.
3806         VK_RESULT_CHECK(sizeInBytes <= heapSize, VK_ERROR_OUT_OF_DEVICE_MEMORY);
3807 
3808         // Allocate buffer
3809         VkBufferCreateInfo createInfo    = {};
3810         createInfo.sType                 = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
3811         createInfo.flags                 = 0;
3812         createInfo.size                  = alignedSize;
3813         createInfo.usage                 = mUsage;
3814         createInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
3815         createInfo.queueFamilyIndexCount = 0;
3816         createInfo.pQueueFamilyIndices   = nullptr;
3817 
3818         VkMemoryPropertyFlags memoryPropertyFlags;
3819         const Allocator &allocator = context->getRenderer()->getAllocator();
3820         allocator.getMemoryTypeProperties(mMemoryTypeIndex, &memoryPropertyFlags);
3821 
3822         DeviceScoped<Buffer> buffer(context->getDevice());
3823         VK_RESULT_TRY(buffer.get().init(context->getDevice(), createInfo));
3824 
3825         DeviceScoped<DeviceMemory> deviceMemory(context->getDevice());
3826         VkMemoryPropertyFlags memoryPropertyFlagsOut;
3827         VkDeviceSize sizeOut;
3828         uint32_t memoryTypeIndex;
3829         VK_RESULT_TRY(AllocateBufferMemory(
3830             context, MemoryAllocationType::Buffer, memoryPropertyFlags, &memoryPropertyFlagsOut,
3831             nullptr, &buffer.get(), &memoryTypeIndex, &deviceMemory.get(), &sizeOut));
3832         ASSERT(sizeOut >= alignedSize);
3833 
3834         suballocation->initWithEntireBuffer(context, buffer.get(), MemoryAllocationType::Buffer,
3835                                             memoryTypeIndex, deviceMemory.get(),
3836                                             memoryPropertyFlagsOut, alignedSize, sizeOut);
3837         if (mHostVisible)
3838         {
3839             VK_RESULT_TRY(suballocation->map(context));
3840         }
3841         return VK_SUCCESS;
3842     }
3843 
3844     // We always allocate from reverse order so that older buffers have a chance to be empty. The
3845     // assumption is that to allocate from new buffers first may have a better chance to leave the
3846     // older buffers completely empty and we may able to free it.
3847     for (auto iter = mBufferBlocks.rbegin(); iter != mBufferBlocks.rend();)
3848     {
3849         std::unique_ptr<BufferBlock> &block = *iter;
3850         if (block->isEmpty() && block->getMemorySize() < mSize)
3851         {
3852             // Don't try to allocate from an empty buffer that has smaller size. It will get
3853             // released when pruneEmptyBuffers get called later on.
3854             ++iter;
3855             continue;
3856         }
3857 
3858         if (block->allocate(alignedSize, alignment, &allocation, &offset) == VK_SUCCESS)
3859         {
3860             suballocation->init(block.get(), allocation, offset, alignedSize);
3861             return VK_SUCCESS;
3862         }
3863         ++iter;
3864     }
3865 
3866     // Try to allocate from empty buffers
3867     while (!mEmptyBufferBlocks.empty())
3868     {
3869         std::unique_ptr<BufferBlock> &block = mEmptyBufferBlocks.back();
3870         if (block->getMemorySize() < mSize)
3871         {
3872             mTotalMemorySize -= block->getMemorySize();
3873             block->destroy(context->getRenderer());
3874             mEmptyBufferBlocks.pop_back();
3875         }
3876         else
3877         {
3878             VK_RESULT_TRY(block->allocate(alignedSize, alignment, &allocation, &offset));
3879             suballocation->init(block.get(), allocation, offset, alignedSize);
3880             mBufferBlocks.push_back(std::move(block));
3881             mEmptyBufferBlocks.pop_back();
3882             mNumberOfNewBuffersNeededSinceLastPrune++;
3883             return VK_SUCCESS;
3884         }
3885     }
3886 
3887     // Failed to allocate from empty buffer. Now try to allocate a new buffer.
3888     VK_RESULT_TRY(allocateNewBuffer(context, alignedSize));
3889 
3890     // Sub-allocate from the bufferBlock.
3891     std::unique_ptr<BufferBlock> &block = mBufferBlocks.back();
3892     VK_RESULT_CHECK(block->allocate(alignedSize, alignment, &allocation, &offset) == VK_SUCCESS,
3893                     VK_ERROR_OUT_OF_DEVICE_MEMORY);
3894     suballocation->init(block.get(), allocation, offset, alignedSize);
3895     mNumberOfNewBuffersNeededSinceLastPrune++;
3896 
3897     return VK_SUCCESS;
3898 }
3899 
destroy(Renderer * renderer,bool orphanNonEmptyBufferBlock)3900 void BufferPool::destroy(Renderer *renderer, bool orphanNonEmptyBufferBlock)
3901 {
3902     for (std::unique_ptr<BufferBlock> &block : mBufferBlocks)
3903     {
3904         if (block->isEmpty())
3905         {
3906             block->destroy(renderer);
3907         }
3908         else
3909         {
3910             // When orphan is not allowed, all BufferBlocks must be empty.
3911             ASSERT(orphanNonEmptyBufferBlock);
3912             renderer->addBufferBlockToOrphanList(block.release());
3913         }
3914     }
3915     mBufferBlocks.clear();
3916 
3917     for (std::unique_ptr<BufferBlock> &block : mEmptyBufferBlocks)
3918     {
3919         block->destroy(renderer);
3920     }
3921     mEmptyBufferBlocks.clear();
3922 }
3923 
getTotalEmptyMemorySize() const3924 VkDeviceSize BufferPool::getTotalEmptyMemorySize() const
3925 {
3926     VkDeviceSize totalMemorySize = 0;
3927     for (const std::unique_ptr<BufferBlock> &block : mEmptyBufferBlocks)
3928     {
3929         totalMemorySize += block->getMemorySize();
3930     }
3931     return totalMemorySize;
3932 }
3933 
addStats(std::ostringstream * out) const3934 void BufferPool::addStats(std::ostringstream *out) const
3935 {
3936     VkDeviceSize totalUnusedBytes = 0;
3937     VkDeviceSize totalMemorySize  = 0;
3938     for (size_t i = 0; i < mBufferBlocks.size(); i++)
3939     {
3940         const std::unique_ptr<BufferBlock> &block = mBufferBlocks[i];
3941         vma::StatInfo statInfo;
3942         block->calculateStats(&statInfo);
3943         ASSERT(statInfo.basicInfo.blockCount == 1);
3944         INFO() << "[" << i << "]={" << " allocationCount:" << statInfo.basicInfo.allocationCount
3945                << " blockBytes:" << statInfo.basicInfo.blockBytes
3946                << " allocationBytes:" << statInfo.basicInfo.allocationBytes
3947                << " unusedRangeCount:" << statInfo.unusedRangeCount
3948                << " allocationSizeMin:" << statInfo.allocationSizeMin
3949                << " allocationSizeMax:" << statInfo.allocationSizeMax
3950                << " unusedRangeSizeMin:" << statInfo.unusedRangeSizeMin
3951                << " unusedRangeSizeMax:" << statInfo.unusedRangeSizeMax << " }";
3952         VkDeviceSize unusedBytes =
3953             statInfo.basicInfo.blockBytes - statInfo.basicInfo.allocationBytes;
3954         totalUnusedBytes += unusedBytes;
3955         totalMemorySize += block->getMemorySize();
3956     }
3957     *out << "mBufferBlocks.size():" << mBufferBlocks.size()
3958          << " totalUnusedBytes:" << totalUnusedBytes / 1024
3959          << "KB / totalMemorySize:" << totalMemorySize / 1024 << "KB";
3960     *out << " emptyBuffers [memorySize:" << getTotalEmptyMemorySize() / 1024 << "KB "
3961          << " count:" << mEmptyBufferBlocks.size()
3962          << " needed: " << mNumberOfNewBuffersNeededSinceLastPrune << "]";
3963 }
3964 
3965 // DescriptorPoolHelper implementation.
DescriptorPoolHelper()3966 DescriptorPoolHelper::DescriptorPoolHelper() : mValidDescriptorSets(0), mFreeDescriptorSets(0) {}
3967 
~DescriptorPoolHelper()3968 DescriptorPoolHelper::~DescriptorPoolHelper()
3969 {
3970     // Caller must have already freed all caches. Clear call will assert that.
3971     mDescriptorSetCacheManager.clear();
3972     ASSERT(mDescriptorSetGarbageList.empty());
3973 }
3974 
init(Context * context,const std::vector<VkDescriptorPoolSize> & poolSizesIn,uint32_t maxSets)3975 angle::Result DescriptorPoolHelper::init(Context *context,
3976                                          const std::vector<VkDescriptorPoolSize> &poolSizesIn,
3977                                          uint32_t maxSets)
3978 {
3979     Renderer *renderer = context->getRenderer();
3980 
3981     // If there are descriptorSet garbage, they no longer relevant since the entire pool is going to
3982     // be destroyed.
3983     mDescriptorSetCacheManager.destroyKeys(renderer);
3984     mDescriptorSetGarbageList.clear();
3985 
3986     if (mDescriptorPool.valid())
3987     {
3988         ASSERT(renderer->hasResourceUseFinished(getResourceUse()));
3989         mDescriptorPool.destroy(renderer->getDevice());
3990     }
3991 
3992     // Make a copy of the pool sizes, so we can grow them to satisfy the specified maxSets.
3993     std::vector<VkDescriptorPoolSize> poolSizes = poolSizesIn;
3994 
3995     for (VkDescriptorPoolSize &poolSize : poolSizes)
3996     {
3997         poolSize.descriptorCount *= maxSets;
3998     }
3999 
4000     VkDescriptorPoolCreateInfo descriptorPoolInfo = {};
4001     descriptorPoolInfo.sType                      = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
4002     descriptorPoolInfo.flags                      = 0;
4003     descriptorPoolInfo.maxSets                    = maxSets;
4004     descriptorPoolInfo.poolSizeCount              = static_cast<uint32_t>(poolSizes.size());
4005     descriptorPoolInfo.pPoolSizes                 = poolSizes.data();
4006 
4007     mValidDescriptorSets = 0;
4008     mFreeDescriptorSets  = maxSets;
4009 
4010     ANGLE_VK_TRY(context, mDescriptorPool.init(renderer->getDevice(), descriptorPoolInfo));
4011 
4012     return angle::Result::Continue;
4013 }
4014 
destroy(Renderer * renderer)4015 void DescriptorPoolHelper::destroy(Renderer *renderer)
4016 {
4017     mDescriptorSetCacheManager.destroyKeys(renderer);
4018     mDescriptorSetGarbageList.clear();
4019     mDescriptorPool.destroy(renderer->getDevice());
4020 }
4021 
release(Renderer * renderer)4022 void DescriptorPoolHelper::release(Renderer *renderer)
4023 {
4024     mDescriptorSetGarbageList.clear();
4025 
4026     GarbageObjects garbageObjects;
4027     garbageObjects.emplace_back(GetGarbage(&mDescriptorPool));
4028     renderer->collectGarbage(mUse, std::move(garbageObjects));
4029     mUse.reset();
4030 }
4031 
allocateDescriptorSet(Context * context,const DescriptorSetLayout & descriptorSetLayout,VkDescriptorSet * descriptorSetsOut)4032 bool DescriptorPoolHelper::allocateDescriptorSet(Context *context,
4033                                                  const DescriptorSetLayout &descriptorSetLayout,
4034                                                  VkDescriptorSet *descriptorSetsOut)
4035 {
4036     // Try to reuse descriptorSet garbage first
4037     if (!mDescriptorSetGarbageList.empty())
4038     {
4039         Renderer *renderer = context->getRenderer();
4040 
4041         DescriptorSetHelper &garbage = mDescriptorSetGarbageList.front();
4042         if (renderer->hasResourceUseFinished(garbage.getResourceUse()))
4043         {
4044             *descriptorSetsOut = garbage.getDescriptorSet();
4045             mDescriptorSetGarbageList.pop_front();
4046             mValidDescriptorSets++;
4047             return true;
4048         }
4049     }
4050 
4051     if (mFreeDescriptorSets > 0)
4052     {
4053         VkDescriptorSetAllocateInfo allocInfo = {};
4054         allocInfo.sType                       = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
4055         allocInfo.descriptorPool              = mDescriptorPool.getHandle();
4056         allocInfo.descriptorSetCount          = 1;
4057         allocInfo.pSetLayouts                 = descriptorSetLayout.ptr();
4058 
4059         VkResult result = mDescriptorPool.allocateDescriptorSets(context->getDevice(), allocInfo,
4060                                                                  descriptorSetsOut);
4061         // If fail, it means our own accounting has a bug.
4062         ASSERT(result == VK_SUCCESS);
4063         mFreeDescriptorSets--;
4064         mValidDescriptorSets++;
4065         return true;
4066     }
4067 
4068     return false;
4069 }
4070 
4071 // DynamicDescriptorPool implementation.
DynamicDescriptorPool()4072 DynamicDescriptorPool::DynamicDescriptorPool()
4073     : mCurrentPoolIndex(0), mCachedDescriptorSetLayout(VK_NULL_HANDLE)
4074 {}
4075 
~DynamicDescriptorPool()4076 DynamicDescriptorPool::~DynamicDescriptorPool()
4077 {
4078     ASSERT(mDescriptorSetCache.empty());
4079 }
4080 
DynamicDescriptorPool(DynamicDescriptorPool && other)4081 DynamicDescriptorPool::DynamicDescriptorPool(DynamicDescriptorPool &&other)
4082     : DynamicDescriptorPool()
4083 {
4084     *this = std::move(other);
4085 }
4086 
operator =(DynamicDescriptorPool && other)4087 DynamicDescriptorPool &DynamicDescriptorPool::operator=(DynamicDescriptorPool &&other)
4088 {
4089     std::swap(mCurrentPoolIndex, other.mCurrentPoolIndex);
4090     std::swap(mDescriptorPools, other.mDescriptorPools);
4091     std::swap(mPoolSizes, other.mPoolSizes);
4092     std::swap(mCachedDescriptorSetLayout, other.mCachedDescriptorSetLayout);
4093     std::swap(mDescriptorSetCache, other.mDescriptorSetCache);
4094     return *this;
4095 }
4096 
init(Context * context,const VkDescriptorPoolSize * setSizes,size_t setSizeCount,const DescriptorSetLayout & descriptorSetLayout)4097 angle::Result DynamicDescriptorPool::init(Context *context,
4098                                           const VkDescriptorPoolSize *setSizes,
4099                                           size_t setSizeCount,
4100                                           const DescriptorSetLayout &descriptorSetLayout)
4101 {
4102     ASSERT(setSizes);
4103     ASSERT(setSizeCount);
4104     ASSERT(mCurrentPoolIndex == 0);
4105     ASSERT(mDescriptorPools.empty());
4106     ASSERT(mCachedDescriptorSetLayout == VK_NULL_HANDLE);
4107 
4108     mPoolSizes.assign(setSizes, setSizes + setSizeCount);
4109     mCachedDescriptorSetLayout = descriptorSetLayout.getHandle();
4110 
4111     mDescriptorPools.push_back(std::make_unique<RefCountedDescriptorPoolHelper>());
4112     mCurrentPoolIndex = mDescriptorPools.size() - 1;
4113     ANGLE_TRY(
4114         mDescriptorPools[mCurrentPoolIndex]->get().init(context, mPoolSizes, mMaxSetsPerPool));
4115 
4116     return angle::Result::Continue;
4117 }
4118 
destroy(Renderer * renderer)4119 void DynamicDescriptorPool::destroy(Renderer *renderer)
4120 {
4121     for (std::unique_ptr<RefCountedDescriptorPoolHelper> &pool : mDescriptorPools)
4122     {
4123         ASSERT(!pool->isReferenced());
4124         pool->get().destroy(renderer);
4125         pool = nullptr;
4126     }
4127 
4128     mDescriptorPools.clear();
4129     mCurrentPoolIndex          = 0;
4130     mCachedDescriptorSetLayout = VK_NULL_HANDLE;
4131 }
4132 
allocateDescriptorSet(Context * context,const DescriptorSetLayout & descriptorSetLayout,RefCountedDescriptorPoolBinding * bindingOut,VkDescriptorSet * descriptorSetOut)4133 angle::Result DynamicDescriptorPool::allocateDescriptorSet(
4134     Context *context,
4135     const DescriptorSetLayout &descriptorSetLayout,
4136     RefCountedDescriptorPoolBinding *bindingOut,
4137     VkDescriptorSet *descriptorSetOut)
4138 {
4139     ASSERT(!mDescriptorPools.empty());
4140     ASSERT(descriptorSetLayout.getHandle() == mCachedDescriptorSetLayout);
4141 
4142     // First try to allocate from the same pool
4143     if (bindingOut->valid() &&
4144         bindingOut->get().allocateDescriptorSet(context, descriptorSetLayout, descriptorSetOut))
4145     {
4146         return angle::Result::Continue;
4147     }
4148 
4149     // Next try to allocate from mCurrentPoolIndex pool
4150     if (mDescriptorPools[mCurrentPoolIndex]->get().valid() &&
4151         mDescriptorPools[mCurrentPoolIndex]->get().allocateDescriptorSet(
4152             context, descriptorSetLayout, descriptorSetOut))
4153     {
4154         bindingOut->set(mDescriptorPools[mCurrentPoolIndex].get());
4155         return angle::Result::Continue;
4156     }
4157 
4158     // Next try all existing pools
4159     for (std::unique_ptr<RefCountedDescriptorPoolHelper> &pool : mDescriptorPools)
4160     {
4161         if (!pool->get().valid())
4162         {
4163             continue;
4164         }
4165 
4166         if (pool->get().allocateDescriptorSet(context, descriptorSetLayout, descriptorSetOut))
4167         {
4168             bindingOut->set(pool.get());
4169             return angle::Result::Continue;
4170         }
4171     }
4172 
4173     // Last, try to allocate a new pool (and/or evict an existing pool)
4174     ANGLE_TRY(allocateNewPool(context));
4175     bool success = mDescriptorPools[mCurrentPoolIndex]->get().allocateDescriptorSet(
4176         context, descriptorSetLayout, descriptorSetOut);
4177     // Allocate from a new pool must succeed.
4178     ASSERT(success);
4179     bindingOut->set(mDescriptorPools[mCurrentPoolIndex].get());
4180 
4181     return angle::Result::Continue;
4182 }
4183 
getOrAllocateDescriptorSet(Context * context,CommandBufferHelperCommon * commandBufferHelper,const DescriptorSetDesc & desc,const DescriptorSetLayout & descriptorSetLayout,RefCountedDescriptorPoolBinding * bindingOut,VkDescriptorSet * descriptorSetOut,SharedDescriptorSetCacheKey * newSharedCacheKeyOut)4184 angle::Result DynamicDescriptorPool::getOrAllocateDescriptorSet(
4185     Context *context,
4186     CommandBufferHelperCommon *commandBufferHelper,
4187     const DescriptorSetDesc &desc,
4188     const DescriptorSetLayout &descriptorSetLayout,
4189     RefCountedDescriptorPoolBinding *bindingOut,
4190     VkDescriptorSet *descriptorSetOut,
4191     SharedDescriptorSetCacheKey *newSharedCacheKeyOut)
4192 {
4193     // First scan the descriptorSet cache.
4194     vk::RefCountedDescriptorPoolHelper *poolOut;
4195     if (mDescriptorSetCache.getDescriptorSet(desc, descriptorSetOut, &poolOut))
4196     {
4197         *newSharedCacheKeyOut = nullptr;
4198         bindingOut->set(poolOut);
4199         mCacheStats.hit();
4200         return angle::Result::Continue;
4201     }
4202 
4203     ANGLE_TRY(allocateDescriptorSet(context, descriptorSetLayout, bindingOut, descriptorSetOut));
4204     // The pool is still in use every time a new descriptor set is allocated from it.
4205     commandBufferHelper->retainResource(&bindingOut->get());
4206     ++context->getPerfCounters().descriptorSetAllocations;
4207 
4208     mDescriptorSetCache.insertDescriptorSet(desc, *descriptorSetOut, bindingOut->getRefCounted());
4209     mCacheStats.missAndIncrementSize();
4210     // Let pool know there is a shared cache key created and destroys the shared cache key
4211     // when it destroys the pool.
4212     *newSharedCacheKeyOut = CreateSharedDescriptorSetCacheKey(desc, this);
4213     bindingOut->get().onNewDescriptorSetAllocated(*newSharedCacheKeyOut);
4214 
4215     return angle::Result::Continue;
4216 }
4217 
allocateNewPool(Context * context)4218 angle::Result DynamicDescriptorPool::allocateNewPool(Context *context)
4219 {
4220     Renderer *renderer = context->getRenderer();
4221     // Eviction logic: Before we allocate a new pool, check to see if there is any existing pool is
4222     // not bound to program and is GPU compete. We destroy one pool in exchange for allocate a new
4223     // pool to keep total descriptorPool count under control.
4224     for (size_t poolIndex = 0; poolIndex < mDescriptorPools.size();)
4225     {
4226         if (!mDescriptorPools[poolIndex]->get().valid())
4227         {
4228             mDescriptorPools.erase(mDescriptorPools.begin() + poolIndex);
4229             continue;
4230         }
4231         if (!mDescriptorPools[poolIndex]->isReferenced() &&
4232             renderer->hasResourceUseFinished(mDescriptorPools[poolIndex]->get().getResourceUse()))
4233         {
4234             mDescriptorPools[poolIndex]->get().destroy(renderer);
4235             mDescriptorPools.erase(mDescriptorPools.begin() + poolIndex);
4236             break;
4237         }
4238         ++poolIndex;
4239     }
4240 
4241     mDescriptorPools.push_back(std::make_unique<RefCountedDescriptorPoolHelper>());
4242     mCurrentPoolIndex = mDescriptorPools.size() - 1;
4243 
4244     static constexpr size_t kMaxPools = 99999;
4245     ANGLE_VK_CHECK(context, mDescriptorPools.size() < kMaxPools, VK_ERROR_TOO_MANY_OBJECTS);
4246 
4247     // This pool is getting hot, so grow its max size to try and prevent allocating another pool in
4248     // the future.
4249     if (mMaxSetsPerPool < kMaxSetsPerPoolMax)
4250     {
4251         mMaxSetsPerPool *= mMaxSetsPerPoolMultiplier;
4252     }
4253 
4254     return mDescriptorPools[mCurrentPoolIndex]->get().init(context, mPoolSizes, mMaxSetsPerPool);
4255 }
4256 
releaseCachedDescriptorSet(Renderer * renderer,const DescriptorSetDesc & desc)4257 void DynamicDescriptorPool::releaseCachedDescriptorSet(Renderer *renderer,
4258                                                        const DescriptorSetDesc &desc)
4259 {
4260     VkDescriptorSet descriptorSet;
4261     RefCountedDescriptorPoolHelper *poolOut;
4262     if (mDescriptorSetCache.getDescriptorSet(desc, &descriptorSet, &poolOut))
4263     {
4264         // Remove from the cache hash map
4265         mDescriptorSetCache.eraseDescriptorSet(desc);
4266         mCacheStats.decrementSize();
4267 
4268         // Wrap it with helper object so that it can be GPU tracked and add it to resource list.
4269         DescriptorSetHelper descriptorSetHelper(poolOut->get().getResourceUse(), descriptorSet);
4270         poolOut->get().addGarbage(std::move(descriptorSetHelper));
4271         checkAndReleaseUnusedPool(renderer, poolOut);
4272     }
4273 }
4274 
destroyCachedDescriptorSet(Renderer * renderer,const DescriptorSetDesc & desc)4275 void DynamicDescriptorPool::destroyCachedDescriptorSet(Renderer *renderer,
4276                                                        const DescriptorSetDesc &desc)
4277 {
4278     VkDescriptorSet descriptorSet;
4279     RefCountedDescriptorPoolHelper *poolOut;
4280     if (mDescriptorSetCache.getDescriptorSet(desc, &descriptorSet, &poolOut))
4281     {
4282         // Remove from the cache hash map
4283         mDescriptorSetCache.eraseDescriptorSet(desc);
4284         mCacheStats.decrementSize();
4285 
4286         // Put descriptorSet to the garbage list for reuse.
4287         DescriptorSetHelper descriptorSetHelper(descriptorSet);
4288         poolOut->get().addGarbage(std::move(descriptorSetHelper));
4289         checkAndReleaseUnusedPool(renderer, poolOut);
4290     }
4291 }
4292 
checkAndReleaseUnusedPool(Renderer * renderer,RefCountedDescriptorPoolHelper * pool)4293 void DynamicDescriptorPool::checkAndReleaseUnusedPool(Renderer *renderer,
4294                                                       RefCountedDescriptorPoolHelper *pool)
4295 {
4296     // If pool still contains any valid descriptorSet cache, then don't destroy it. Note that even
4297     // if pool has no valid descriptorSet, pool itself may still be bound to a program until it gets
4298     // unbound when next descriptorSet gets allocated. We always keep at least one pool around.
4299     if (mDescriptorPools.size() < 2 || pool->get().hasValidDescriptorSet() || pool->isReferenced())
4300     {
4301         return;
4302     }
4303 
4304     // Erase it from the array
4305     size_t poolIndex;
4306     for (poolIndex = 0; poolIndex < mDescriptorPools.size(); ++poolIndex)
4307     {
4308         if (pool == mDescriptorPools[poolIndex].get())
4309         {
4310             break;
4311         }
4312     }
4313     // There must be a match
4314     ASSERT(poolIndex != mDescriptorPools.size());
4315     ASSERT(pool->get().valid());
4316     pool->get().release(renderer);
4317 }
4318 
4319 // For testing only!
GetMaxSetsPerPoolForTesting()4320 uint32_t DynamicDescriptorPool::GetMaxSetsPerPoolForTesting()
4321 {
4322     return mMaxSetsPerPool;
4323 }
4324 
4325 // For testing only!
SetMaxSetsPerPoolForTesting(uint32_t maxSetsPerPool)4326 void DynamicDescriptorPool::SetMaxSetsPerPoolForTesting(uint32_t maxSetsPerPool)
4327 {
4328     mMaxSetsPerPool = maxSetsPerPool;
4329 }
4330 
4331 // For testing only!
GetMaxSetsPerPoolMultiplierForTesting()4332 uint32_t DynamicDescriptorPool::GetMaxSetsPerPoolMultiplierForTesting()
4333 {
4334     return mMaxSetsPerPoolMultiplier;
4335 }
4336 
4337 // For testing only!
SetMaxSetsPerPoolMultiplierForTesting(uint32_t maxSetsPerPoolMultiplier)4338 void DynamicDescriptorPool::SetMaxSetsPerPoolMultiplierForTesting(uint32_t maxSetsPerPoolMultiplier)
4339 {
4340     mMaxSetsPerPoolMultiplier = maxSetsPerPoolMultiplier;
4341 }
4342 
4343 // DynamicallyGrowingPool implementation
4344 template <typename Pool>
DynamicallyGrowingPool()4345 DynamicallyGrowingPool<Pool>::DynamicallyGrowingPool()
4346     : mPoolSize(0), mCurrentPool(0), mCurrentFreeEntry(0)
4347 {}
4348 
4349 template <typename Pool>
4350 DynamicallyGrowingPool<Pool>::~DynamicallyGrowingPool() = default;
4351 
4352 template <typename Pool>
initEntryPool(Context * contextVk,uint32_t poolSize)4353 angle::Result DynamicallyGrowingPool<Pool>::initEntryPool(Context *contextVk, uint32_t poolSize)
4354 {
4355     ASSERT(mPools.empty());
4356     mPoolSize         = poolSize;
4357     mCurrentFreeEntry = poolSize;
4358     return angle::Result::Continue;
4359 }
4360 
4361 template <typename Pool>
destroyEntryPool(VkDevice device)4362 void DynamicallyGrowingPool<Pool>::destroyEntryPool(VkDevice device)
4363 {
4364     for (PoolResource &resource : mPools)
4365     {
4366         destroyPoolImpl(device, resource.pool);
4367     }
4368     mPools.clear();
4369 }
4370 
4371 template <typename Pool>
findFreeEntryPool(ContextVk * contextVk)4372 bool DynamicallyGrowingPool<Pool>::findFreeEntryPool(ContextVk *contextVk)
4373 {
4374     Renderer *renderer = contextVk->getRenderer();
4375     for (size_t poolIndex = 0; poolIndex < mPools.size(); ++poolIndex)
4376     {
4377         PoolResource &pool = mPools[poolIndex];
4378         if (pool.freedCount == mPoolSize && renderer->hasResourceUseFinished(pool.getResourceUse()))
4379         {
4380             mCurrentPool      = poolIndex;
4381             mCurrentFreeEntry = 0;
4382 
4383             pool.freedCount = 0;
4384 
4385             return true;
4386         }
4387     }
4388 
4389     return false;
4390 }
4391 
4392 template <typename Pool>
allocateNewEntryPool(ContextVk * contextVk,Pool && pool)4393 angle::Result DynamicallyGrowingPool<Pool>::allocateNewEntryPool(ContextVk *contextVk, Pool &&pool)
4394 {
4395     mPools.emplace_back(std::move(pool), 0);
4396 
4397     mCurrentPool      = mPools.size() - 1;
4398     mCurrentFreeEntry = 0;
4399 
4400     return angle::Result::Continue;
4401 }
4402 
4403 template <typename Pool>
onEntryFreed(ContextVk * contextVk,size_t poolIndex,const ResourceUse & use)4404 void DynamicallyGrowingPool<Pool>::onEntryFreed(ContextVk *contextVk,
4405                                                 size_t poolIndex,
4406                                                 const ResourceUse &use)
4407 {
4408     ASSERT(poolIndex < mPools.size() && mPools[poolIndex].freedCount < mPoolSize);
4409     if (!contextVk->getRenderer()->hasResourceUseFinished(use))
4410     {
4411         mPools[poolIndex].mergeResourceUse(use);
4412     }
4413     ++mPools[poolIndex].freedCount;
4414 }
4415 
4416 template <typename Pool>
allocatePoolEntries(ContextVk * contextVk,uint32_t entryCount,uint32_t * poolIndex,uint32_t * currentEntryOut)4417 angle::Result DynamicallyGrowingPool<Pool>::allocatePoolEntries(ContextVk *contextVk,
4418                                                                 uint32_t entryCount,
4419                                                                 uint32_t *poolIndex,
4420                                                                 uint32_t *currentEntryOut)
4421 {
4422     if (mCurrentFreeEntry + entryCount > mPoolSize)
4423     {
4424         if (!findFreeEntryPool(contextVk))
4425         {
4426             Pool newPool;
4427             ANGLE_TRY(allocatePoolImpl(contextVk, newPool, mPoolSize));
4428             ANGLE_TRY(allocateNewEntryPool(contextVk, std::move(newPool)));
4429         }
4430     }
4431 
4432     *poolIndex       = static_cast<uint32_t>(mCurrentPool);
4433     *currentEntryOut = mCurrentFreeEntry;
4434 
4435     mCurrentFreeEntry += entryCount;
4436 
4437     return angle::Result::Continue;
4438 }
4439 
4440 template <typename Pool>
PoolResource(Pool && poolIn,uint32_t freedCountIn)4441 DynamicallyGrowingPool<Pool>::PoolResource::PoolResource(Pool &&poolIn, uint32_t freedCountIn)
4442     : pool(std::move(poolIn)), freedCount(freedCountIn)
4443 {}
4444 
4445 template <typename Pool>
PoolResource(PoolResource && other)4446 DynamicallyGrowingPool<Pool>::PoolResource::PoolResource(PoolResource &&other)
4447     : Resource(std::move(other)), pool(std::move(other.pool)), freedCount(other.freedCount)
4448 {}
4449 
4450 // DynamicQueryPool implementation
4451 DynamicQueryPool::DynamicQueryPool() = default;
4452 
4453 DynamicQueryPool::~DynamicQueryPool() = default;
4454 
init(ContextVk * contextVk,VkQueryType type,uint32_t poolSize)4455 angle::Result DynamicQueryPool::init(ContextVk *contextVk, VkQueryType type, uint32_t poolSize)
4456 {
4457     // SecondaryCommandBuffer's ResetQueryPoolParams would like the query index to fit in 24 bits.
4458     ASSERT(poolSize < (1 << 24));
4459 
4460     ANGLE_TRY(initEntryPool(contextVk, poolSize));
4461     mQueryType = type;
4462     return angle::Result::Continue;
4463 }
4464 
destroy(VkDevice device)4465 void DynamicQueryPool::destroy(VkDevice device)
4466 {
4467     destroyEntryPool(device);
4468 }
4469 
destroyPoolImpl(VkDevice device,QueryPool & poolToDestroy)4470 void DynamicQueryPool::destroyPoolImpl(VkDevice device, QueryPool &poolToDestroy)
4471 {
4472     poolToDestroy.destroy(device);
4473 }
4474 
allocateQuery(ContextVk * contextVk,QueryHelper * queryOut,uint32_t queryCount)4475 angle::Result DynamicQueryPool::allocateQuery(ContextVk *contextVk,
4476                                               QueryHelper *queryOut,
4477                                               uint32_t queryCount)
4478 {
4479     ASSERT(!queryOut->valid());
4480 
4481     uint32_t currentPool = 0;
4482     uint32_t queryIndex  = 0;
4483     ANGLE_TRY(allocatePoolEntries(contextVk, queryCount, &currentPool, &queryIndex));
4484 
4485     queryOut->init(this, currentPool, queryIndex, queryCount);
4486 
4487     return angle::Result::Continue;
4488 }
4489 
allocatePoolImpl(ContextVk * contextVk,QueryPool & poolToAllocate,uint32_t entriesToAllocate)4490 angle::Result DynamicQueryPool::allocatePoolImpl(ContextVk *contextVk,
4491                                                  QueryPool &poolToAllocate,
4492                                                  uint32_t entriesToAllocate)
4493 {
4494     VkQueryPoolCreateInfo queryPoolInfo = {};
4495     queryPoolInfo.sType                 = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
4496     queryPoolInfo.flags                 = 0;
4497     queryPoolInfo.queryType             = this->mQueryType;
4498     queryPoolInfo.queryCount            = entriesToAllocate;
4499     queryPoolInfo.pipelineStatistics    = 0;
4500 
4501     if (this->mQueryType == VK_QUERY_TYPE_PIPELINE_STATISTICS)
4502     {
4503         queryPoolInfo.pipelineStatistics = VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT;
4504     }
4505 
4506     ANGLE_VK_TRY(contextVk, poolToAllocate.init(contextVk->getDevice(), queryPoolInfo));
4507     return angle::Result::Continue;
4508 }
4509 
freeQuery(ContextVk * contextVk,QueryHelper * query)4510 void DynamicQueryPool::freeQuery(ContextVk *contextVk, QueryHelper *query)
4511 {
4512     if (query->valid())
4513     {
4514         size_t poolIndex = query->mQueryPoolIndex;
4515         ASSERT(getQueryPool(poolIndex).valid());
4516 
4517         onEntryFreed(contextVk, poolIndex, query->getResourceUse());
4518 
4519         query->deinit();
4520     }
4521 }
4522 
4523 // QueryResult implementation
setResults(uint64_t * results,uint32_t queryCount)4524 void QueryResult::setResults(uint64_t *results, uint32_t queryCount)
4525 {
4526     ASSERT(mResults[0] == 0 && mResults[1] == 0);
4527 
4528     // Accumulate the query results.  For multiview, where multiple query indices are used to return
4529     // the results, it's undefined how the results are distributed between indices, but the sum is
4530     // guaranteed to be the desired result.
4531     for (uint32_t query = 0; query < queryCount; ++query)
4532     {
4533         for (uint32_t perQueryIndex = 0; perQueryIndex < mIntsPerResult; ++perQueryIndex)
4534         {
4535             mResults[perQueryIndex] += results[query * mIntsPerResult + perQueryIndex];
4536         }
4537     }
4538 }
4539 
4540 // QueryHelper implementation
QueryHelper()4541 QueryHelper::QueryHelper()
4542     : mDynamicQueryPool(nullptr),
4543       mQueryPoolIndex(0),
4544       mQuery(0),
4545       mQueryCount(0),
4546       mStatus(QueryStatus::Inactive)
4547 {}
4548 
~QueryHelper()4549 QueryHelper::~QueryHelper() {}
4550 
4551 // Move constructor
QueryHelper(QueryHelper && rhs)4552 QueryHelper::QueryHelper(QueryHelper &&rhs)
4553     : Resource(std::move(rhs)),
4554       mDynamicQueryPool(rhs.mDynamicQueryPool),
4555       mQueryPoolIndex(rhs.mQueryPoolIndex),
4556       mQuery(rhs.mQuery),
4557       mQueryCount(rhs.mQueryCount),
4558       mStatus(rhs.mStatus)
4559 {
4560     rhs.mDynamicQueryPool = nullptr;
4561     rhs.mQueryPoolIndex   = 0;
4562     rhs.mQuery            = 0;
4563     rhs.mQueryCount       = 0;
4564     rhs.mStatus           = QueryStatus::Inactive;
4565 }
4566 
operator =(QueryHelper && rhs)4567 QueryHelper &QueryHelper::operator=(QueryHelper &&rhs)
4568 {
4569     Resource::operator=(std::move(rhs));
4570     std::swap(mDynamicQueryPool, rhs.mDynamicQueryPool);
4571     std::swap(mQueryPoolIndex, rhs.mQueryPoolIndex);
4572     std::swap(mQuery, rhs.mQuery);
4573     std::swap(mQueryCount, rhs.mQueryCount);
4574     std::swap(mStatus, rhs.mStatus);
4575     return *this;
4576 }
4577 
init(const DynamicQueryPool * dynamicQueryPool,const size_t queryPoolIndex,uint32_t query,uint32_t queryCount)4578 void QueryHelper::init(const DynamicQueryPool *dynamicQueryPool,
4579                        const size_t queryPoolIndex,
4580                        uint32_t query,
4581                        uint32_t queryCount)
4582 {
4583     mDynamicQueryPool = dynamicQueryPool;
4584     mQueryPoolIndex   = queryPoolIndex;
4585     mQuery            = query;
4586     mQueryCount       = queryCount;
4587 
4588     ASSERT(mQueryCount <= gl::IMPLEMENTATION_ANGLE_MULTIVIEW_MAX_VIEWS);
4589 }
4590 
deinit()4591 void QueryHelper::deinit()
4592 {
4593     mDynamicQueryPool = nullptr;
4594     mQueryPoolIndex   = 0;
4595     mQuery            = 0;
4596     mQueryCount       = 0;
4597     mUse.reset();
4598     mStatus = QueryStatus::Inactive;
4599 }
4600 
4601 template <typename CommandBufferT>
beginQueryImpl(ContextVk * contextVk,OutsideRenderPassCommandBuffer * resetCommandBuffer,CommandBufferT * commandBuffer)4602 void QueryHelper::beginQueryImpl(ContextVk *contextVk,
4603                                  OutsideRenderPassCommandBuffer *resetCommandBuffer,
4604                                  CommandBufferT *commandBuffer)
4605 {
4606     ASSERT(mStatus != QueryStatus::Active);
4607     const QueryPool &queryPool = getQueryPool();
4608     resetQueryPoolImpl(contextVk, queryPool, resetCommandBuffer);
4609     commandBuffer->beginQuery(queryPool, mQuery, 0);
4610     mStatus = QueryStatus::Active;
4611 }
4612 
4613 template <typename CommandBufferT>
endQueryImpl(ContextVk * contextVk,CommandBufferT * commandBuffer)4614 void QueryHelper::endQueryImpl(ContextVk *contextVk, CommandBufferT *commandBuffer)
4615 {
4616     ASSERT(mStatus != QueryStatus::Ended);
4617     commandBuffer->endQuery(getQueryPool(), mQuery);
4618     mStatus = QueryStatus::Ended;
4619 }
4620 
beginQuery(ContextVk * contextVk)4621 angle::Result QueryHelper::beginQuery(ContextVk *contextVk)
4622 {
4623     if (contextVk->hasActiveRenderPass())
4624     {
4625         ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass(
4626             RenderPassClosureReason::BeginNonRenderPassQuery));
4627     }
4628 
4629     OutsideRenderPassCommandBuffer *commandBuffer;
4630     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer({}, &commandBuffer));
4631 
4632     ANGLE_TRY(contextVk->handleGraphicsEventLog(rx::GraphicsEventCmdBuf::InOutsideCmdBufQueryCmd));
4633 
4634     beginQueryImpl(contextVk, commandBuffer, commandBuffer);
4635 
4636     return angle::Result::Continue;
4637 }
4638 
endQuery(ContextVk * contextVk)4639 angle::Result QueryHelper::endQuery(ContextVk *contextVk)
4640 {
4641     if (contextVk->hasActiveRenderPass())
4642     {
4643         ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass(
4644             RenderPassClosureReason::EndNonRenderPassQuery));
4645     }
4646 
4647     CommandBufferAccess access;
4648     OutsideRenderPassCommandBuffer *commandBuffer;
4649     access.onQueryAccess(this);
4650     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
4651 
4652     ANGLE_TRY(contextVk->handleGraphicsEventLog(rx::GraphicsEventCmdBuf::InOutsideCmdBufQueryCmd));
4653 
4654     endQueryImpl(contextVk, commandBuffer);
4655 
4656     return angle::Result::Continue;
4657 }
4658 
4659 template <typename CommandBufferT>
resetQueryPoolImpl(ContextVk * contextVk,const QueryPool & queryPool,CommandBufferT * commandBuffer)4660 void QueryHelper::resetQueryPoolImpl(ContextVk *contextVk,
4661                                      const QueryPool &queryPool,
4662                                      CommandBufferT *commandBuffer)
4663 {
4664     Renderer *renderer = contextVk->getRenderer();
4665     if (renderer->getFeatures().supportsHostQueryReset.enabled)
4666     {
4667         vkResetQueryPoolEXT(contextVk->getDevice(), queryPool.getHandle(), mQuery, mQueryCount);
4668     }
4669     else
4670     {
4671         commandBuffer->resetQueryPool(queryPool, mQuery, mQueryCount);
4672     }
4673 }
4674 
beginRenderPassQuery(ContextVk * contextVk)4675 angle::Result QueryHelper::beginRenderPassQuery(ContextVk *contextVk)
4676 {
4677     OutsideRenderPassCommandBuffer *outsideRenderPassCommandBuffer;
4678     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer({}, &outsideRenderPassCommandBuffer));
4679 
4680     RenderPassCommandBuffer *renderPassCommandBuffer =
4681         &contextVk->getStartedRenderPassCommands().getCommandBuffer();
4682 
4683     beginQueryImpl(contextVk, outsideRenderPassCommandBuffer, renderPassCommandBuffer);
4684 
4685     return angle::Result::Continue;
4686 }
4687 
endRenderPassQuery(ContextVk * contextVk)4688 void QueryHelper::endRenderPassQuery(ContextVk *contextVk)
4689 {
4690     if (mStatus == QueryStatus::Active)
4691     {
4692         endQueryImpl(contextVk, &contextVk->getStartedRenderPassCommands().getCommandBuffer());
4693         contextVk->getStartedRenderPassCommands().retainResource(this);
4694     }
4695 }
4696 
flushAndWriteTimestamp(ContextVk * contextVk)4697 angle::Result QueryHelper::flushAndWriteTimestamp(ContextVk *contextVk)
4698 {
4699     if (contextVk->hasActiveRenderPass())
4700     {
4701         ANGLE_TRY(
4702             contextVk->flushCommandsAndEndRenderPass(RenderPassClosureReason::TimestampQuery));
4703     }
4704 
4705     CommandBufferAccess access;
4706     OutsideRenderPassCommandBuffer *commandBuffer;
4707     access.onQueryAccess(this);
4708     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
4709     writeTimestamp(contextVk, commandBuffer);
4710     return angle::Result::Continue;
4711 }
4712 
writeTimestampToPrimary(ContextVk * contextVk,PrimaryCommandBuffer * primary)4713 void QueryHelper::writeTimestampToPrimary(ContextVk *contextVk, PrimaryCommandBuffer *primary)
4714 {
4715     // Note that commands may not be flushed at this point.
4716 
4717     const QueryPool &queryPool = getQueryPool();
4718     resetQueryPoolImpl(contextVk, queryPool, primary);
4719     primary->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, queryPool, mQuery);
4720 }
4721 
writeTimestamp(ContextVk * contextVk,OutsideRenderPassCommandBuffer * commandBuffer)4722 void QueryHelper::writeTimestamp(ContextVk *contextVk,
4723                                  OutsideRenderPassCommandBuffer *commandBuffer)
4724 {
4725     const QueryPool &queryPool = getQueryPool();
4726     resetQueryPoolImpl(contextVk, queryPool, commandBuffer);
4727     commandBuffer->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, queryPool, mQuery);
4728 }
4729 
hasSubmittedCommands() const4730 bool QueryHelper::hasSubmittedCommands() const
4731 {
4732     return mUse.valid();
4733 }
4734 
getUint64ResultNonBlocking(ContextVk * contextVk,QueryResult * resultOut,bool * availableOut)4735 angle::Result QueryHelper::getUint64ResultNonBlocking(ContextVk *contextVk,
4736                                                       QueryResult *resultOut,
4737                                                       bool *availableOut)
4738 {
4739     ASSERT(valid());
4740     VkResult result;
4741 
4742     // Ensure that we only wait if we have inserted a query in command buffer. Otherwise you will
4743     // wait forever and trigger GPU timeout.
4744     if (hasSubmittedCommands())
4745     {
4746         constexpr VkQueryResultFlags kFlags = VK_QUERY_RESULT_64_BIT;
4747         result                              = getResultImpl(contextVk, kFlags, resultOut);
4748     }
4749     else
4750     {
4751         result     = VK_SUCCESS;
4752         *resultOut = 0;
4753     }
4754 
4755     if (result == VK_NOT_READY)
4756     {
4757         *availableOut = false;
4758         return angle::Result::Continue;
4759     }
4760     else
4761     {
4762         ANGLE_VK_TRY(contextVk, result);
4763         *availableOut = true;
4764     }
4765     return angle::Result::Continue;
4766 }
4767 
getUint64Result(ContextVk * contextVk,QueryResult * resultOut)4768 angle::Result QueryHelper::getUint64Result(ContextVk *contextVk, QueryResult *resultOut)
4769 {
4770     ASSERT(valid());
4771     if (hasSubmittedCommands())
4772     {
4773         constexpr VkQueryResultFlags kFlags = VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT;
4774         ANGLE_VK_TRY(contextVk, getResultImpl(contextVk, kFlags, resultOut));
4775     }
4776     else
4777     {
4778         *resultOut = 0;
4779     }
4780     return angle::Result::Continue;
4781 }
4782 
getResultImpl(ContextVk * contextVk,const VkQueryResultFlags flags,QueryResult * resultOut)4783 VkResult QueryHelper::getResultImpl(ContextVk *contextVk,
4784                                     const VkQueryResultFlags flags,
4785                                     QueryResult *resultOut)
4786 {
4787     std::array<uint64_t, 2 * gl::IMPLEMENTATION_ANGLE_MULTIVIEW_MAX_VIEWS> results;
4788 
4789     VkDevice device = contextVk->getDevice();
4790     VkResult result = getQueryPool().getResults(device, mQuery, mQueryCount, sizeof(results),
4791                                                 results.data(), sizeof(uint64_t), flags);
4792 
4793     if (result == VK_SUCCESS)
4794     {
4795         resultOut->setResults(results.data(), mQueryCount);
4796     }
4797 
4798     return result;
4799 }
4800 
4801 // SemaphoreHelper implementation
SemaphoreHelper()4802 SemaphoreHelper::SemaphoreHelper() : mSemaphorePoolIndex(0), mSemaphore(0) {}
4803 
~SemaphoreHelper()4804 SemaphoreHelper::~SemaphoreHelper() {}
4805 
SemaphoreHelper(SemaphoreHelper && other)4806 SemaphoreHelper::SemaphoreHelper(SemaphoreHelper &&other)
4807     : mSemaphorePoolIndex(other.mSemaphorePoolIndex), mSemaphore(other.mSemaphore)
4808 {
4809     other.mSemaphore = nullptr;
4810 }
4811 
operator =(SemaphoreHelper && other)4812 SemaphoreHelper &SemaphoreHelper::operator=(SemaphoreHelper &&other)
4813 {
4814     std::swap(mSemaphorePoolIndex, other.mSemaphorePoolIndex);
4815     std::swap(mSemaphore, other.mSemaphore);
4816     return *this;
4817 }
4818 
init(const size_t semaphorePoolIndex,const Semaphore * semaphore)4819 void SemaphoreHelper::init(const size_t semaphorePoolIndex, const Semaphore *semaphore)
4820 {
4821     mSemaphorePoolIndex = semaphorePoolIndex;
4822     mSemaphore          = semaphore;
4823 }
4824 
deinit()4825 void SemaphoreHelper::deinit()
4826 {
4827     mSemaphorePoolIndex = 0;
4828     mSemaphore          = nullptr;
4829 }
4830 
4831 // LineLoopHelper implementation.
LineLoopHelper(Renderer * renderer)4832 LineLoopHelper::LineLoopHelper(Renderer *renderer) {}
4833 LineLoopHelper::~LineLoopHelper() = default;
4834 
getIndexBufferForDrawArrays(ContextVk * contextVk,uint32_t clampedVertexCount,GLint firstVertex,BufferHelper ** bufferOut)4835 angle::Result LineLoopHelper::getIndexBufferForDrawArrays(ContextVk *contextVk,
4836                                                           uint32_t clampedVertexCount,
4837                                                           GLint firstVertex,
4838                                                           BufferHelper **bufferOut)
4839 {
4840     size_t allocateBytes = sizeof(uint32_t) * (static_cast<size_t>(clampedVertexCount) + 1);
4841     ANGLE_TRY(contextVk->initBufferForVertexConversion(&mDynamicIndexBuffer, allocateBytes,
4842                                                        MemoryHostVisibility::Visible));
4843     uint32_t *indices = reinterpret_cast<uint32_t *>(mDynamicIndexBuffer.getMappedMemory());
4844 
4845     // Note: there could be an overflow in this addition.
4846     uint32_t unsignedFirstVertex = static_cast<uint32_t>(firstVertex);
4847     uint32_t vertexCount         = (clampedVertexCount + unsignedFirstVertex);
4848     for (uint32_t vertexIndex = unsignedFirstVertex; vertexIndex < vertexCount; vertexIndex++)
4849     {
4850         *indices++ = vertexIndex;
4851     }
4852     *indices = unsignedFirstVertex;
4853 
4854     // Since we are not using the VK_MEMORY_PROPERTY_HOST_COHERENT_BIT flag when creating the
4855     // device memory in the StreamingBuffer, we always need to make sure we flush it after
4856     // writing.
4857     ANGLE_TRY(mDynamicIndexBuffer.flush(contextVk->getRenderer()));
4858 
4859     *bufferOut = &mDynamicIndexBuffer;
4860 
4861     return angle::Result::Continue;
4862 }
4863 
getIndexBufferForElementArrayBuffer(ContextVk * contextVk,BufferVk * elementArrayBufferVk,gl::DrawElementsType glIndexType,int indexCount,intptr_t elementArrayOffset,BufferHelper ** bufferOut,uint32_t * indexCountOut)4864 angle::Result LineLoopHelper::getIndexBufferForElementArrayBuffer(ContextVk *contextVk,
4865                                                                   BufferVk *elementArrayBufferVk,
4866                                                                   gl::DrawElementsType glIndexType,
4867                                                                   int indexCount,
4868                                                                   intptr_t elementArrayOffset,
4869                                                                   BufferHelper **bufferOut,
4870                                                                   uint32_t *indexCountOut)
4871 {
4872     if (glIndexType == gl::DrawElementsType::UnsignedByte ||
4873         contextVk->getState().isPrimitiveRestartEnabled())
4874     {
4875         ANGLE_TRACE_EVENT0("gpu.angle", "LineLoopHelper::getIndexBufferForElementArrayBuffer");
4876 
4877         void *srcDataMapping = nullptr;
4878         ANGLE_TRY(elementArrayBufferVk->mapImpl(contextVk, GL_MAP_READ_BIT, &srcDataMapping));
4879         ANGLE_TRY(streamIndices(contextVk, glIndexType, indexCount,
4880                                 static_cast<const uint8_t *>(srcDataMapping) + elementArrayOffset,
4881                                 bufferOut, indexCountOut));
4882         ANGLE_TRY(elementArrayBufferVk->unmapImpl(contextVk));
4883         return angle::Result::Continue;
4884     }
4885 
4886     *indexCountOut = indexCount + 1;
4887 
4888     size_t unitSize = contextVk->getVkIndexTypeSize(glIndexType);
4889 
4890     size_t allocateBytes = unitSize * (indexCount + 1) + 1;
4891     ANGLE_TRY(contextVk->initBufferForVertexConversion(&mDynamicIndexBuffer, allocateBytes,
4892                                                        MemoryHostVisibility::Visible));
4893 
4894     BufferHelper *sourceBuffer = &elementArrayBufferVk->getBuffer();
4895     VkDeviceSize sourceOffset =
4896         static_cast<VkDeviceSize>(elementArrayOffset) + sourceBuffer->getOffset();
4897     uint64_t unitCount                         = static_cast<VkDeviceSize>(indexCount);
4898     angle::FixedVector<VkBufferCopy, 2> copies = {
4899         {sourceOffset, mDynamicIndexBuffer.getOffset(), unitCount * unitSize},
4900         {sourceOffset, mDynamicIndexBuffer.getOffset() + unitCount * unitSize, unitSize},
4901     };
4902 
4903     vk::CommandBufferAccess access;
4904     access.onBufferTransferWrite(&mDynamicIndexBuffer);
4905     access.onBufferTransferRead(sourceBuffer);
4906 
4907     vk::OutsideRenderPassCommandBuffer *commandBuffer;
4908     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
4909 
4910     commandBuffer->copyBuffer(sourceBuffer->getBuffer(), mDynamicIndexBuffer.getBuffer(),
4911                               static_cast<uint32_t>(copies.size()), copies.data());
4912 
4913     ANGLE_TRY(mDynamicIndexBuffer.flush(contextVk->getRenderer()));
4914 
4915     *bufferOut = &mDynamicIndexBuffer;
4916 
4917     return angle::Result::Continue;
4918 }
4919 
streamIndices(ContextVk * contextVk,gl::DrawElementsType glIndexType,GLsizei indexCount,const uint8_t * srcPtr,BufferHelper ** bufferOut,uint32_t * indexCountOut)4920 angle::Result LineLoopHelper::streamIndices(ContextVk *contextVk,
4921                                             gl::DrawElementsType glIndexType,
4922                                             GLsizei indexCount,
4923                                             const uint8_t *srcPtr,
4924                                             BufferHelper **bufferOut,
4925                                             uint32_t *indexCountOut)
4926 {
4927     size_t unitSize = contextVk->getVkIndexTypeSize(glIndexType);
4928 
4929     uint32_t numOutIndices = indexCount + 1;
4930     if (contextVk->getState().isPrimitiveRestartEnabled())
4931     {
4932         numOutIndices = GetLineLoopWithRestartIndexCount(glIndexType, indexCount, srcPtr);
4933     }
4934     *indexCountOut = numOutIndices;
4935 
4936     ANGLE_TRY(contextVk->initBufferForVertexConversion(
4937         &mDynamicIndexBuffer, unitSize * numOutIndices, MemoryHostVisibility::Visible));
4938     uint8_t *indices = mDynamicIndexBuffer.getMappedMemory();
4939 
4940     if (contextVk->getState().isPrimitiveRestartEnabled())
4941     {
4942         HandlePrimitiveRestart(contextVk, glIndexType, indexCount, srcPtr, indices);
4943     }
4944     else
4945     {
4946         if (contextVk->shouldConvertUint8VkIndexType(glIndexType))
4947         {
4948             // If vulkan doesn't support uint8 index types, we need to emulate it.
4949             VkIndexType indexType = contextVk->getVkIndexType(glIndexType);
4950             ASSERT(indexType == VK_INDEX_TYPE_UINT16);
4951             uint16_t *indicesDst = reinterpret_cast<uint16_t *>(indices);
4952             for (int i = 0; i < indexCount; i++)
4953             {
4954                 indicesDst[i] = srcPtr[i];
4955             }
4956 
4957             indicesDst[indexCount] = srcPtr[0];
4958         }
4959         else
4960         {
4961             memcpy(indices, srcPtr, unitSize * indexCount);
4962             memcpy(indices + unitSize * indexCount, srcPtr, unitSize);
4963         }
4964     }
4965 
4966     ANGLE_TRY(mDynamicIndexBuffer.flush(contextVk->getRenderer()));
4967 
4968     *bufferOut = &mDynamicIndexBuffer;
4969 
4970     return angle::Result::Continue;
4971 }
4972 
streamIndicesIndirect(ContextVk * contextVk,gl::DrawElementsType glIndexType,BufferHelper * indexBuffer,BufferHelper * indirectBuffer,VkDeviceSize indirectBufferOffset,BufferHelper ** indexBufferOut,BufferHelper ** indirectBufferOut)4973 angle::Result LineLoopHelper::streamIndicesIndirect(ContextVk *contextVk,
4974                                                     gl::DrawElementsType glIndexType,
4975                                                     BufferHelper *indexBuffer,
4976                                                     BufferHelper *indirectBuffer,
4977                                                     VkDeviceSize indirectBufferOffset,
4978                                                     BufferHelper **indexBufferOut,
4979                                                     BufferHelper **indirectBufferOut)
4980 {
4981     size_t unitSize      = contextVk->getVkIndexTypeSize(glIndexType);
4982     size_t allocateBytes = static_cast<size_t>(indexBuffer->getSize() + unitSize);
4983 
4984     if (contextVk->getState().isPrimitiveRestartEnabled())
4985     {
4986         // If primitive restart, new index buffer is 135% the size of the original index buffer. The
4987         // smallest lineloop with primitive restart is 3 indices (point 1, point 2 and restart
4988         // value) when converted to linelist becomes 4 vertices. Expansion of 4/3. Any larger
4989         // lineloops would have less overhead and require less extra space. Any incomplete
4990         // primitives can be dropped or left incomplete and thus not increase the size of the
4991         // destination index buffer. Since we don't know the number of indices being used we'll use
4992         // the size of the index buffer as allocated as the index count.
4993         size_t numInputIndices    = static_cast<size_t>(indexBuffer->getSize() / unitSize);
4994         size_t numNewInputIndices = ((numInputIndices * 4) / 3) + 1;
4995         allocateBytes             = static_cast<size_t>(numNewInputIndices * unitSize);
4996     }
4997 
4998     // Allocate buffer for results
4999     ANGLE_TRY(contextVk->initBufferForVertexConversion(&mDynamicIndexBuffer, allocateBytes,
5000                                                        MemoryHostVisibility::Visible));
5001     ANGLE_TRY(contextVk->initBufferForVertexConversion(&mDynamicIndirectBuffer,
5002                                                        sizeof(VkDrawIndexedIndirectCommand),
5003                                                        MemoryHostVisibility::Visible));
5004 
5005     *indexBufferOut    = &mDynamicIndexBuffer;
5006     *indirectBufferOut = &mDynamicIndirectBuffer;
5007 
5008     BufferHelper *dstIndexBuffer    = &mDynamicIndexBuffer;
5009     BufferHelper *dstIndirectBuffer = &mDynamicIndirectBuffer;
5010 
5011     // Copy relevant section of the source into destination at allocated offset.  Note that the
5012     // offset returned by allocate() above is in bytes. As is the indices offset pointer.
5013     UtilsVk::ConvertLineLoopIndexIndirectParameters params = {};
5014     params.indirectBufferOffset    = static_cast<uint32_t>(indirectBufferOffset);
5015     params.dstIndirectBufferOffset = 0;
5016     params.srcIndexBufferOffset    = 0;
5017     params.dstIndexBufferOffset    = 0;
5018     params.indicesBitsWidth        = static_cast<uint32_t>(unitSize * 8);
5019 
5020     return contextVk->getUtils().convertLineLoopIndexIndirectBuffer(
5021         contextVk, indirectBuffer, dstIndirectBuffer, dstIndexBuffer, indexBuffer, params);
5022 }
5023 
streamArrayIndirect(ContextVk * contextVk,size_t vertexCount,BufferHelper * arrayIndirectBuffer,VkDeviceSize arrayIndirectBufferOffset,BufferHelper ** indexBufferOut,BufferHelper ** indexIndirectBufferOut)5024 angle::Result LineLoopHelper::streamArrayIndirect(ContextVk *contextVk,
5025                                                   size_t vertexCount,
5026                                                   BufferHelper *arrayIndirectBuffer,
5027                                                   VkDeviceSize arrayIndirectBufferOffset,
5028                                                   BufferHelper **indexBufferOut,
5029                                                   BufferHelper **indexIndirectBufferOut)
5030 {
5031     auto unitSize        = sizeof(uint32_t);
5032     size_t allocateBytes = static_cast<size_t>((vertexCount + 1) * unitSize);
5033 
5034     ANGLE_TRY(contextVk->initBufferForVertexConversion(&mDynamicIndexBuffer, allocateBytes,
5035                                                        MemoryHostVisibility::Visible));
5036     ANGLE_TRY(contextVk->initBufferForVertexConversion(&mDynamicIndirectBuffer,
5037                                                        sizeof(VkDrawIndexedIndirectCommand),
5038                                                        MemoryHostVisibility::Visible));
5039 
5040     *indexBufferOut         = &mDynamicIndexBuffer;
5041     *indexIndirectBufferOut = &mDynamicIndirectBuffer;
5042 
5043     BufferHelper *dstIndexBuffer    = &mDynamicIndexBuffer;
5044     BufferHelper *dstIndirectBuffer = &mDynamicIndirectBuffer;
5045 
5046     // Copy relevant section of the source into destination at allocated offset.  Note that the
5047     // offset returned by allocate() above is in bytes. As is the indices offset pointer.
5048     UtilsVk::ConvertLineLoopArrayIndirectParameters params = {};
5049     params.indirectBufferOffset    = static_cast<uint32_t>(arrayIndirectBufferOffset);
5050     params.dstIndirectBufferOffset = 0;
5051     params.dstIndexBufferOffset    = 0;
5052     return contextVk->getUtils().convertLineLoopArrayIndirectBuffer(
5053         contextVk, arrayIndirectBuffer, dstIndirectBuffer, dstIndexBuffer, params);
5054 }
5055 
release(ContextVk * contextVk)5056 void LineLoopHelper::release(ContextVk *contextVk)
5057 {
5058     mDynamicIndexBuffer.release(contextVk->getRenderer());
5059     mDynamicIndirectBuffer.release(contextVk->getRenderer());
5060 }
5061 
destroy(Renderer * renderer)5062 void LineLoopHelper::destroy(Renderer *renderer)
5063 {
5064     mDynamicIndexBuffer.destroy(renderer);
5065     mDynamicIndirectBuffer.destroy(renderer);
5066 }
5067 
5068 // static
Draw(uint32_t count,uint32_t baseVertex,RenderPassCommandBuffer * commandBuffer)5069 void LineLoopHelper::Draw(uint32_t count,
5070                           uint32_t baseVertex,
5071                           RenderPassCommandBuffer *commandBuffer)
5072 {
5073     // Our first index is always 0 because that's how we set it up in createIndexBuffer*.
5074     commandBuffer->drawIndexedBaseVertex(count, baseVertex);
5075 }
5076 
GetPipelineStage(gl::ShaderType stage)5077 PipelineStage GetPipelineStage(gl::ShaderType stage)
5078 {
5079     const PipelineStage pipelineStage = kPipelineStageShaderMap[stage];
5080     ASSERT(pipelineStage == PipelineStage::VertexShader ||
5081            pipelineStage == PipelineStage::TessellationControl ||
5082            pipelineStage == PipelineStage::TessellationEvaluation ||
5083            pipelineStage == PipelineStage::GeometryShader ||
5084            pipelineStage == PipelineStage::FragmentShader ||
5085            pipelineStage == PipelineStage::ComputeShader);
5086     return pipelineStage;
5087 }
5088 
5089 // PipelineBarrier implementation.
addDiagnosticsString(std::ostringstream & out) const5090 void PipelineBarrier::addDiagnosticsString(std::ostringstream &out) const
5091 {
5092     if (mMemoryBarrierSrcAccess != 0 || mMemoryBarrierDstAccess != 0)
5093     {
5094         out << "Src: 0x" << std::hex << mMemoryBarrierSrcAccess << " &rarr; Dst: 0x" << std::hex
5095             << mMemoryBarrierDstAccess << std::endl;
5096     }
5097 }
5098 
5099 // PipelineBarrierArray implementation.
execute(Renderer * renderer,PrimaryCommandBuffer * primary)5100 void PipelineBarrierArray::execute(Renderer *renderer, PrimaryCommandBuffer *primary)
5101 {
5102     // make a local copy for faster access
5103     PipelineStagesMask mask = mBarrierMask;
5104     if (mask.none())
5105     {
5106         return;
5107     }
5108 
5109     if (renderer->getFeatures().preferAggregateBarrierCalls.enabled)
5110     {
5111         PipelineStagesMask::Iterator iter = mask.begin();
5112         PipelineBarrier &barrier          = mBarriers[*iter];
5113         for (++iter; iter != mask.end(); ++iter)
5114         {
5115             barrier.merge(&mBarriers[*iter]);
5116         }
5117         barrier.execute(primary);
5118     }
5119     else
5120     {
5121         for (PipelineStage pipelineStage : mask)
5122         {
5123             PipelineBarrier &barrier = mBarriers[pipelineStage];
5124             barrier.execute(primary);
5125         }
5126     }
5127     mBarrierMask.reset();
5128 }
5129 
addDiagnosticsString(std::ostringstream & out) const5130 void PipelineBarrierArray::addDiagnosticsString(std::ostringstream &out) const
5131 {
5132     out << "Memory Barrier: ";
5133     for (PipelineStage pipelineStage : mBarrierMask)
5134     {
5135         const PipelineBarrier &barrier = mBarriers[pipelineStage];
5136         if (!barrier.isEmpty())
5137         {
5138             barrier.addDiagnosticsString(out);
5139         }
5140     }
5141     out << "\\l";
5142 }
5143 
5144 // BufferHelper implementation.
BufferHelper()5145 BufferHelper::BufferHelper()
5146     : mCurrentWriteAccess(0),
5147       mCurrentReadAccess(0),
5148       mCurrentWriteStages(0),
5149       mCurrentReadStages(0),
5150       mSerial(),
5151       mClientBuffer(nullptr),
5152       mIsReleasedToExternal(false)
5153 {}
5154 
~BufferHelper()5155 BufferHelper::~BufferHelper()
5156 {
5157     // We must have released external buffer properly
5158     ASSERT(mClientBuffer == nullptr);
5159 }
5160 
BufferHelper(BufferHelper && other)5161 BufferHelper::BufferHelper(BufferHelper &&other)
5162 {
5163     *this = std::move(other);
5164 }
5165 
operator =(BufferHelper && other)5166 BufferHelper &BufferHelper::operator=(BufferHelper &&other)
5167 {
5168     ReadWriteResource::operator=(std::move(other));
5169 
5170     mSuballocation      = std::move(other.mSuballocation);
5171     mBufferWithUserSize = std::move(other.mBufferWithUserSize);
5172 
5173     mCurrentDeviceQueueIndex = other.mCurrentDeviceQueueIndex;
5174     mIsReleasedToExternal    = other.mIsReleasedToExternal;
5175     mCurrentWriteAccess      = other.mCurrentWriteAccess;
5176     mCurrentReadAccess       = other.mCurrentReadAccess;
5177     mCurrentWriteStages      = other.mCurrentWriteStages;
5178     mCurrentReadStages       = other.mCurrentReadStages;
5179     mSerial                  = other.mSerial;
5180     mClientBuffer            = std::move(other.mClientBuffer);
5181 
5182     return *this;
5183 }
5184 
init(Context * context,const VkBufferCreateInfo & requestedCreateInfo,VkMemoryPropertyFlags memoryPropertyFlags)5185 angle::Result BufferHelper::init(Context *context,
5186                                  const VkBufferCreateInfo &requestedCreateInfo,
5187                                  VkMemoryPropertyFlags memoryPropertyFlags)
5188 {
5189     Renderer *renderer         = context->getRenderer();
5190     const Allocator &allocator = renderer->getAllocator();
5191 
5192     initializeBarrierTracker(context);
5193 
5194     VkBufferCreateInfo modifiedCreateInfo;
5195     const VkBufferCreateInfo *createInfo = &requestedCreateInfo;
5196 
5197     if (renderer->getFeatures().padBuffersToMaxVertexAttribStride.enabled)
5198     {
5199         const VkDeviceSize maxVertexAttribStride = renderer->getMaxVertexAttribStride();
5200         ASSERT(maxVertexAttribStride);
5201         modifiedCreateInfo = requestedCreateInfo;
5202         modifiedCreateInfo.size += maxVertexAttribStride;
5203         createInfo = &modifiedCreateInfo;
5204     }
5205 
5206     VkMemoryPropertyFlags requiredFlags =
5207         (memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
5208     VkMemoryPropertyFlags preferredFlags =
5209         (memoryPropertyFlags & (~VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
5210 
5211     bool persistentlyMapped = renderer->getFeatures().persistentlyMappedBuffers.enabled;
5212 
5213     // Check that the allocation is not too large.
5214     uint32_t memoryTypeIndex = kInvalidMemoryTypeIndex;
5215     ANGLE_VK_TRY(context, allocator.findMemoryTypeIndexForBufferInfo(
5216                               *createInfo, requiredFlags, preferredFlags, persistentlyMapped,
5217                               &memoryTypeIndex));
5218 
5219     VkDeviceSize heapSize =
5220         renderer->getMemoryProperties().getHeapSizeForMemoryType(memoryTypeIndex);
5221 
5222     ANGLE_VK_CHECK(context, createInfo->size <= heapSize, VK_ERROR_OUT_OF_DEVICE_MEMORY);
5223 
5224     VkMemoryPropertyFlags memoryPropertyFlagsOut;
5225     allocator.getMemoryTypeProperties(memoryTypeIndex, &memoryPropertyFlagsOut);
5226     // Allocate buffer object
5227     DeviceScoped<Buffer> buffer(renderer->getDevice());
5228     ANGLE_VK_TRY(context, buffer.get().init(context->getDevice(), *createInfo));
5229 
5230     DeviceScoped<DeviceMemory> deviceMemory(renderer->getDevice());
5231     VkDeviceSize sizeOut;
5232     uint32_t bufferMemoryTypeIndex;
5233     ANGLE_VK_TRY(context,
5234                  AllocateBufferMemory(context, MemoryAllocationType::Buffer, memoryPropertyFlagsOut,
5235                                       &memoryPropertyFlagsOut, nullptr, &buffer.get(),
5236                                       &bufferMemoryTypeIndex, &deviceMemory.get(), &sizeOut));
5237     ASSERT(sizeOut >= createInfo->size);
5238 
5239     mSuballocation.initWithEntireBuffer(context, buffer.get(), MemoryAllocationType::Buffer,
5240                                         bufferMemoryTypeIndex, deviceMemory.get(),
5241                                         memoryPropertyFlagsOut, requestedCreateInfo.size, sizeOut);
5242     if (isHostVisible())
5243     {
5244         uint8_t *ptrOut;
5245         ANGLE_TRY(map(context, &ptrOut));
5246     }
5247 
5248     if (renderer->getFeatures().allocateNonZeroMemory.enabled)
5249     {
5250         ANGLE_TRY(initializeNonZeroMemory(context, createInfo->usage, createInfo->size));
5251     }
5252 
5253     return angle::Result::Continue;
5254 }
5255 
initExternal(Context * context,VkMemoryPropertyFlags memoryProperties,const VkBufferCreateInfo & requestedCreateInfo,GLeglClientBufferEXT clientBuffer)5256 angle::Result BufferHelper::initExternal(Context *context,
5257                                          VkMemoryPropertyFlags memoryProperties,
5258                                          const VkBufferCreateInfo &requestedCreateInfo,
5259                                          GLeglClientBufferEXT clientBuffer)
5260 {
5261     ASSERT(IsAndroid());
5262 
5263     Renderer *renderer = context->getRenderer();
5264 
5265     initializeBarrierTracker(context);
5266 
5267     VkBufferCreateInfo modifiedCreateInfo             = requestedCreateInfo;
5268     VkExternalMemoryBufferCreateInfo externCreateInfo = {};
5269     externCreateInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO;
5270     externCreateInfo.handleTypes =
5271         VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
5272     externCreateInfo.pNext   = nullptr;
5273     modifiedCreateInfo.pNext = &externCreateInfo;
5274 
5275     DeviceScoped<Buffer> buffer(renderer->getDevice());
5276     ANGLE_VK_TRY(context, buffer.get().init(renderer->getDevice(), modifiedCreateInfo));
5277 
5278     DeviceScoped<DeviceMemory> deviceMemory(renderer->getDevice());
5279     VkMemoryPropertyFlags memoryPropertyFlagsOut;
5280     VkDeviceSize allocatedSize = 0;
5281     uint32_t memoryTypeIndex;
5282     ANGLE_TRY(InitAndroidExternalMemory(context, clientBuffer, memoryProperties, &buffer.get(),
5283                                         &memoryPropertyFlagsOut, &memoryTypeIndex,
5284                                         &deviceMemory.get(), &allocatedSize));
5285     mClientBuffer = clientBuffer;
5286 
5287     mSuballocation.initWithEntireBuffer(context, buffer.get(), MemoryAllocationType::BufferExternal,
5288                                         memoryTypeIndex, deviceMemory.get(), memoryPropertyFlagsOut,
5289                                         requestedCreateInfo.size, allocatedSize);
5290     if (isHostVisible())
5291     {
5292         uint8_t *ptrOut;
5293         ANGLE_TRY(map(context, &ptrOut));
5294     }
5295     return angle::Result::Continue;
5296 }
5297 
initSuballocation(Context * context,uint32_t memoryTypeIndex,size_t size,size_t alignment,BufferUsageType usageType,BufferPool * pool)5298 VkResult BufferHelper::initSuballocation(Context *context,
5299                                          uint32_t memoryTypeIndex,
5300                                          size_t size,
5301                                          size_t alignment,
5302                                          BufferUsageType usageType,
5303                                          BufferPool *pool)
5304 {
5305     ASSERT(pool != nullptr);
5306     Renderer *renderer = context->getRenderer();
5307 
5308     // We should reset these in case the BufferHelper object has been released and called
5309     // initSuballocation again.
5310     initializeBarrierTracker(context);
5311 
5312     if (renderer->getFeatures().padBuffersToMaxVertexAttribStride.enabled)
5313     {
5314         const VkDeviceSize maxVertexAttribStride = renderer->getMaxVertexAttribStride();
5315         ASSERT(maxVertexAttribStride);
5316         size += maxVertexAttribStride;
5317     }
5318 
5319     VK_RESULT_TRY(pool->allocateBuffer(context, size, alignment, &mSuballocation));
5320 
5321     context->getPerfCounters().bufferSuballocationCalls++;
5322 
5323     return VK_SUCCESS;
5324 }
5325 
initializeBarrierTracker(Context * context)5326 void BufferHelper::initializeBarrierTracker(Context *context)
5327 {
5328     Renderer *renderer       = context->getRenderer();
5329     mCurrentDeviceQueueIndex = context->getDeviceQueueIndex();
5330     mIsReleasedToExternal    = false;
5331     mSerial                  = renderer->getResourceSerialFactory().generateBufferSerial();
5332     mCurrentWriteAccess      = 0;
5333     mCurrentReadAccess       = 0;
5334     mCurrentWriteStages      = 0;
5335     mCurrentReadStages       = 0;
5336 }
5337 
initializeNonZeroMemory(Context * context,VkBufferUsageFlags usage,VkDeviceSize size)5338 angle::Result BufferHelper::initializeNonZeroMemory(Context *context,
5339                                                     VkBufferUsageFlags usage,
5340                                                     VkDeviceSize size)
5341 {
5342     Renderer *renderer = context->getRenderer();
5343 
5344     // This memory can't be mapped, so the buffer must be marked as a transfer destination so we
5345     // can use a staging resource to initialize it to a non-zero value. If the memory is
5346     // mappable we do the initialization in AllocateBufferMemory.
5347     if (!isHostVisible() && (usage & VK_BUFFER_USAGE_TRANSFER_DST_BIT) != 0)
5348     {
5349         ASSERT((usage & VK_BUFFER_USAGE_TRANSFER_DST_BIT) != 0);
5350         // Staging buffer memory is non-zero-initialized in 'init'.
5351         StagingBuffer stagingBuffer;
5352         ANGLE_TRY(stagingBuffer.init(context, size, StagingUsage::Both));
5353 
5354         PrimaryCommandBuffer commandBuffer;
5355         ANGLE_TRY(
5356             renderer->getCommandBufferOneOff(context, ProtectionType::Unprotected, &commandBuffer));
5357 
5358         // Queue a DMA copy.
5359         VkBufferCopy copyRegion = {};
5360         copyRegion.srcOffset    = 0;
5361         copyRegion.dstOffset    = getOffset();
5362         copyRegion.size         = size;
5363 
5364         commandBuffer.copyBuffer(stagingBuffer.getBuffer(), getBuffer(), 1, &copyRegion);
5365 
5366         ANGLE_VK_TRY(context, commandBuffer.end());
5367 
5368         QueueSerial queueSerial;
5369         ANGLE_TRY(renderer->queueSubmitOneOff(context, std::move(commandBuffer),
5370                                               ProtectionType::Unprotected,
5371                                               egl::ContextPriority::Medium, VK_NULL_HANDLE, 0,
5372                                               vk::SubmitPolicy::AllowDeferred, &queueSerial));
5373 
5374         stagingBuffer.collectGarbage(renderer, queueSerial);
5375         // Update both ResourceUse objects, since mReadOnlyUse tracks when the buffer can be
5376         // destroyed, and mReadWriteUse tracks when the write has completed.
5377         setWriteQueueSerial(queueSerial);
5378     }
5379     else if (isHostVisible())
5380     {
5381         // Can map the memory.
5382         // Pick an arbitrary value to initialize non-zero memory for sanitization.
5383         constexpr int kNonZeroInitValue = 55;
5384         uint8_t *mapPointer             = mSuballocation.getMappedMemory();
5385         memset(mapPointer, kNonZeroInitValue, static_cast<size_t>(getSize()));
5386         if (!isCoherent())
5387         {
5388             mSuballocation.flush(renderer->getDevice());
5389         }
5390     }
5391 
5392     return angle::Result::Continue;
5393 }
5394 
getBufferForVertexArray(ContextVk * contextVk,VkDeviceSize actualDataSize,VkDeviceSize * offsetOut)5395 const Buffer &BufferHelper::getBufferForVertexArray(ContextVk *contextVk,
5396                                                     VkDeviceSize actualDataSize,
5397                                                     VkDeviceSize *offsetOut)
5398 {
5399     ASSERT(mSuballocation.valid());
5400     ASSERT(actualDataSize <= mSuballocation.getSize());
5401 
5402     if (!contextVk->hasRobustAccess() || !mSuballocation.isSuballocated() ||
5403         actualDataSize == mSuballocation.getSize())
5404     {
5405         *offsetOut = mSuballocation.getOffset();
5406         return mSuballocation.getBuffer();
5407     }
5408 
5409     if (!mBufferWithUserSize.valid())
5410     {
5411         // Allocate buffer that is backed by sub-range of the memory for vertex array usage. This is
5412         // only needed when robust resource init is enabled so that vulkan driver will know the
5413         // exact size of the vertex buffer it is supposedly to use and prevent out of bound access.
5414         VkBufferCreateInfo createInfo    = {};
5415         createInfo.sType                 = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
5416         createInfo.flags                 = 0;
5417         createInfo.size                  = actualDataSize;
5418         createInfo.usage                 = kVertexBufferUsageFlags | kIndexBufferUsageFlags;
5419         createInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
5420         createInfo.queueFamilyIndexCount = 0;
5421         createInfo.pQueueFamilyIndices   = nullptr;
5422         mBufferWithUserSize.init(contextVk->getDevice(), createInfo);
5423 
5424         VkMemoryRequirements memoryRequirements;
5425         mBufferWithUserSize.getMemoryRequirements(contextVk->getDevice(), &memoryRequirements);
5426         ASSERT(contextVk->getRenderer()->isMockICDEnabled() ||
5427                mSuballocation.getSize() >= memoryRequirements.size);
5428         ASSERT(!contextVk->getRenderer()->isMockICDEnabled() ||
5429                mSuballocation.getOffset() % memoryRequirements.alignment == 0);
5430 
5431         mBufferWithUserSize.bindMemory(contextVk->getDevice(), mSuballocation.getDeviceMemory(),
5432                                        mSuballocation.getOffset());
5433     }
5434     *offsetOut = 0;
5435     return mBufferWithUserSize;
5436 }
5437 
onBufferUserSizeChange(Renderer * renderer)5438 bool BufferHelper::onBufferUserSizeChange(Renderer *renderer)
5439 {
5440     // Buffer's user size and allocation size may be different due to alignment requirement. In
5441     // normal usage we just use the actual allocation size and it is good enough. But when
5442     // robustResourceInit is enabled, mBufferWithUserSize is created to mjatch the exact user
5443     // size. Thus when user size changes, we must clear and recreate this mBufferWithUserSize.
5444     if (mBufferWithUserSize.valid())
5445     {
5446         BufferSuballocation unusedSuballocation;
5447         renderer->collectSuballocationGarbage(mUse, std::move(unusedSuballocation),
5448                                               std::move(mBufferWithUserSize));
5449         mSerial = renderer->getResourceSerialFactory().generateBufferSerial();
5450         return true;
5451     }
5452     return false;
5453 }
5454 
destroy(Renderer * renderer)5455 void BufferHelper::destroy(Renderer *renderer)
5456 {
5457     mDescriptorSetCacheManager.destroyKeys(renderer);
5458     unmap(renderer);
5459     mBufferWithUserSize.destroy(renderer->getDevice());
5460     mSuballocation.destroy(renderer);
5461     if (mClientBuffer != nullptr)
5462     {
5463         ReleaseAndroidExternalMemory(renderer, mClientBuffer);
5464         mClientBuffer = nullptr;
5465     }
5466 }
5467 
release(Renderer * renderer)5468 void BufferHelper::release(Renderer *renderer)
5469 {
5470     ASSERT(mDescriptorSetCacheManager.empty());
5471     unmap(renderer);
5472 
5473     if (mSuballocation.valid())
5474     {
5475         if (!mSuballocation.isSuballocated())
5476         {
5477             // Destroy cacheKeys now to avoid getting into situation that having to destroy
5478             // descriptorSet from garbage collection thread.
5479             mSuballocation.getBufferBlock()->releaseAllCachedDescriptorSetCacheKeys(renderer);
5480         }
5481         renderer->collectSuballocationGarbage(mUse, std::move(mSuballocation),
5482                                               std::move(mBufferWithUserSize));
5483     }
5484     mUse.reset();
5485     mWriteUse.reset();
5486     ASSERT(!mBufferWithUserSize.valid());
5487 
5488     if (mClientBuffer != nullptr)
5489     {
5490         ReleaseAndroidExternalMemory(renderer, mClientBuffer);
5491         mClientBuffer = nullptr;
5492     }
5493 }
5494 
releaseBufferAndDescriptorSetCache(Renderer * renderer)5495 void BufferHelper::releaseBufferAndDescriptorSetCache(Renderer *renderer)
5496 {
5497     if (renderer->hasResourceUseFinished(getResourceUse()))
5498     {
5499         mDescriptorSetCacheManager.destroyKeys(renderer);
5500     }
5501     else
5502     {
5503         mDescriptorSetCacheManager.releaseKeys(renderer);
5504     }
5505 
5506     release(renderer);
5507 }
5508 
map(Context * context,uint8_t ** ptrOut)5509 angle::Result BufferHelper::map(Context *context, uint8_t **ptrOut)
5510 {
5511     if (!mSuballocation.isMapped())
5512     {
5513         ANGLE_VK_TRY(context, mSuballocation.map(context));
5514     }
5515     *ptrOut = mSuballocation.getMappedMemory();
5516     return angle::Result::Continue;
5517 }
5518 
mapWithOffset(Context * context,uint8_t ** ptrOut,size_t offset)5519 angle::Result BufferHelper::mapWithOffset(Context *context, uint8_t **ptrOut, size_t offset)
5520 {
5521     uint8_t *mapBufPointer;
5522     ANGLE_TRY(map(context, &mapBufPointer));
5523     *ptrOut = mapBufPointer + offset;
5524     return angle::Result::Continue;
5525 }
5526 
flush(Renderer * renderer,VkDeviceSize offset,VkDeviceSize size)5527 angle::Result BufferHelper::flush(Renderer *renderer, VkDeviceSize offset, VkDeviceSize size)
5528 {
5529     mSuballocation.flush(renderer->getDevice());
5530     return angle::Result::Continue;
5531 }
flush(Renderer * renderer)5532 angle::Result BufferHelper::flush(Renderer *renderer)
5533 {
5534     return flush(renderer, 0, getSize());
5535 }
5536 
invalidate(Renderer * renderer,VkDeviceSize offset,VkDeviceSize size)5537 angle::Result BufferHelper::invalidate(Renderer *renderer, VkDeviceSize offset, VkDeviceSize size)
5538 {
5539     mSuballocation.invalidate(renderer->getDevice());
5540     return angle::Result::Continue;
5541 }
invalidate(Renderer * renderer)5542 angle::Result BufferHelper::invalidate(Renderer *renderer)
5543 {
5544     return invalidate(renderer, 0, getSize());
5545 }
5546 
changeQueueFamily(uint32_t srcQueueFamilyIndex,uint32_t dstQueueFamilyIndex,OutsideRenderPassCommandBuffer * commandBuffer)5547 void BufferHelper::changeQueueFamily(uint32_t srcQueueFamilyIndex,
5548                                      uint32_t dstQueueFamilyIndex,
5549                                      OutsideRenderPassCommandBuffer *commandBuffer)
5550 {
5551     VkBufferMemoryBarrier bufferMemoryBarrier = {};
5552     bufferMemoryBarrier.sType                 = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
5553     bufferMemoryBarrier.srcAccessMask         = 0;
5554     bufferMemoryBarrier.dstAccessMask         = 0;
5555     bufferMemoryBarrier.srcQueueFamilyIndex   = srcQueueFamilyIndex;
5556     bufferMemoryBarrier.dstQueueFamilyIndex   = dstQueueFamilyIndex;
5557     bufferMemoryBarrier.buffer                = getBuffer().getHandle();
5558     bufferMemoryBarrier.offset                = getOffset();
5559     bufferMemoryBarrier.size                  = getSize();
5560 
5561     commandBuffer->bufferBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
5562                                  VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, &bufferMemoryBarrier);
5563 }
5564 
acquireFromExternal(DeviceQueueIndex externalQueueFamilyIndex,DeviceQueueIndex newDeviceQueueIndex,OutsideRenderPassCommandBuffer * commandBuffer)5565 void BufferHelper::acquireFromExternal(DeviceQueueIndex externalQueueFamilyIndex,
5566                                        DeviceQueueIndex newDeviceQueueIndex,
5567                                        OutsideRenderPassCommandBuffer *commandBuffer)
5568 {
5569     changeQueueFamily(externalQueueFamilyIndex.familyIndex(), newDeviceQueueIndex.familyIndex(),
5570                       commandBuffer);
5571     mCurrentDeviceQueueIndex = newDeviceQueueIndex;
5572     mIsReleasedToExternal    = false;
5573 }
5574 
releaseToExternal(DeviceQueueIndex externalQueueIndex,OutsideRenderPassCommandBuffer * commandBuffer)5575 void BufferHelper::releaseToExternal(DeviceQueueIndex externalQueueIndex,
5576                                      OutsideRenderPassCommandBuffer *commandBuffer)
5577 {
5578     if (mCurrentDeviceQueueIndex.familyIndex() != externalQueueIndex.familyIndex())
5579     {
5580         changeQueueFamily(mCurrentDeviceQueueIndex.familyIndex(), externalQueueIndex.familyIndex(),
5581                           commandBuffer);
5582         mCurrentDeviceQueueIndex = kInvalidDeviceQueueIndex;
5583     }
5584     mIsReleasedToExternal = true;
5585 }
5586 
isReleasedToExternal() const5587 bool BufferHelper::isReleasedToExternal() const
5588 {
5589     return mIsReleasedToExternal;
5590 }
5591 
recordReadBarrier(VkAccessFlags readAccessType,VkPipelineStageFlags readStage,PipelineStage stageIndex,PipelineBarrierArray * barriers)5592 void BufferHelper::recordReadBarrier(VkAccessFlags readAccessType,
5593                                      VkPipelineStageFlags readStage,
5594                                      PipelineStage stageIndex,
5595                                      PipelineBarrierArray *barriers)
5596 {
5597     // If there was a prior write and we are making a read that is either a new access type or from
5598     // a new stage, we need a barrier
5599     if (mCurrentWriteAccess != 0 && (((mCurrentReadAccess & readAccessType) != readAccessType) ||
5600                                      ((mCurrentReadStages & readStage) != readStage)))
5601     {
5602         barriers->mergeMemoryBarrier(stageIndex, mCurrentWriteStages, readStage,
5603                                      mCurrentWriteAccess, readAccessType);
5604     }
5605 
5606     // Accumulate new read usage.
5607     mCurrentReadAccess |= readAccessType;
5608     mCurrentReadStages |= readStage;
5609 }
5610 
recordWriteBarrier(VkAccessFlags writeAccessType,VkPipelineStageFlags writeStage,PipelineStage stageIndex,PipelineBarrierArray * barriers)5611 void BufferHelper::recordWriteBarrier(VkAccessFlags writeAccessType,
5612                                       VkPipelineStageFlags writeStage,
5613                                       PipelineStage stageIndex,
5614                                       PipelineBarrierArray *barriers)
5615 {
5616     // We don't need to check mCurrentReadStages here since if it is not zero, mCurrentReadAccess
5617     // must not be zero as well. stage is finer grain than accessType.
5618     ASSERT((!mCurrentReadStages && !mCurrentReadAccess) ||
5619            (mCurrentReadStages && mCurrentReadAccess));
5620     if (mCurrentReadAccess != 0 || mCurrentWriteAccess != 0)
5621     {
5622         VkPipelineStageFlags srcStageMask = mCurrentWriteStages | mCurrentReadStages;
5623         barriers->mergeMemoryBarrier(stageIndex, srcStageMask, writeStage, mCurrentWriteAccess,
5624                                      writeAccessType);
5625     }
5626 
5627     // Reset usages on the new write.
5628     mCurrentWriteAccess = writeAccessType;
5629     mCurrentReadAccess  = 0;
5630     mCurrentWriteStages = writeStage;
5631     mCurrentReadStages  = 0;
5632 }
5633 
fillWithColor(const angle::Color<uint8_t> & color,const gl::InternalFormat & internalFormat)5634 void BufferHelper::fillWithColor(const angle::Color<uint8_t> &color,
5635                                  const gl::InternalFormat &internalFormat)
5636 {
5637     uint32_t count =
5638         static_cast<uint32_t>(getSize()) / static_cast<uint32_t>(internalFormat.pixelBytes);
5639     void *buffer = static_cast<void *>(getMappedMemory());
5640 
5641     switch (internalFormat.internalFormat)
5642     {
5643         case GL_RGB565:
5644         {
5645             uint16_t pixelColor =
5646                 ((color.blue & 0xF8) << 11) | ((color.green & 0xFC) << 5) | (color.red & 0xF8);
5647             uint16_t *pixelPtr = static_cast<uint16_t *>(buffer);
5648             std::fill_n<uint16_t *, uint32_t, uint16_t>(pixelPtr, count, pixelColor);
5649         }
5650         break;
5651         case GL_RGBA8:
5652         {
5653             uint32_t pixelColor =
5654                 (color.alpha << 24) | (color.blue << 16) | (color.green << 8) | (color.red);
5655             uint32_t *pixelPtr = static_cast<uint32_t *>(buffer);
5656             std::fill_n<uint32_t *, uint32_t, uint32_t>(pixelPtr, count, pixelColor);
5657         }
5658         break;
5659         case GL_BGR565_ANGLEX:
5660         {
5661             uint16_t pixelColor =
5662                 ((color.red & 0xF8) << 11) | ((color.green & 0xFC) << 5) | (color.blue & 0xF8);
5663             uint16_t *pixelPtr = static_cast<uint16_t *>(buffer);
5664             std::fill_n<uint16_t *, uint32_t, uint16_t>(pixelPtr, count, pixelColor);
5665         }
5666         break;
5667         case GL_BGRA8_EXT:
5668         {
5669             uint32_t pixelColor =
5670                 (color.alpha << 24) | (color.red << 16) | (color.green << 8) | (color.blue);
5671             uint32_t *pixelPtr = static_cast<uint32_t *>(buffer);
5672             std::fill_n<uint32_t *, uint32_t, uint32_t>(pixelPtr, count, pixelColor);
5673         }
5674         break;
5675         default:
5676             UNREACHABLE();  // Unsupported format
5677     }
5678 }
5679 
5680 // Used for ImageHelper non-zero memory allocation when useVmaForImageSuballocation is disabled.
InitMappableDeviceMemory(Context * context,DeviceMemory * deviceMemory,VkDeviceSize size,int value,VkMemoryPropertyFlags memoryPropertyFlags)5681 angle::Result InitMappableDeviceMemory(Context *context,
5682                                        DeviceMemory *deviceMemory,
5683                                        VkDeviceSize size,
5684                                        int value,
5685                                        VkMemoryPropertyFlags memoryPropertyFlags)
5686 {
5687     ASSERT(!context->getFeatures().useVmaForImageSuballocation.enabled);
5688     VkDevice device = context->getDevice();
5689 
5690     uint8_t *mapPointer;
5691     ANGLE_VK_TRY(context, deviceMemory->map(device, 0, VK_WHOLE_SIZE, 0, &mapPointer));
5692     memset(mapPointer, value, static_cast<size_t>(size));
5693 
5694     // if the memory type is not host coherent, we perform an explicit flush.
5695     if ((memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0)
5696     {
5697         VkMappedMemoryRange mappedRange = {};
5698         mappedRange.sType               = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
5699         mappedRange.memory              = deviceMemory->getHandle();
5700         mappedRange.size                = VK_WHOLE_SIZE;
5701         ANGLE_VK_TRY(context, vkFlushMappedMemoryRanges(device, 1, &mappedRange));
5702     }
5703 
5704     deviceMemory->unmap(device);
5705 
5706     return angle::Result::Continue;
5707 }
5708 
5709 // ImageHelper implementation.
ImageHelper()5710 ImageHelper::ImageHelper()
5711 {
5712     resetCachedProperties();
5713 }
5714 
~ImageHelper()5715 ImageHelper::~ImageHelper()
5716 {
5717     ASSERT(!valid());
5718     ASSERT(!mAcquireNextImageSemaphore.valid());
5719 }
5720 
resetCachedProperties()5721 void ImageHelper::resetCachedProperties()
5722 {
5723     mImageType                   = VK_IMAGE_TYPE_2D;
5724     mTilingMode                  = VK_IMAGE_TILING_OPTIMAL;
5725     mCreateFlags                 = kVkImageCreateFlagsNone;
5726     mUsage                       = 0;
5727     mExtents                     = {};
5728     mRotatedAspectRatio          = false;
5729     mIntendedFormatID            = angle::FormatID::NONE;
5730     mActualFormatID              = angle::FormatID::NONE;
5731     mSamples                     = 1;
5732     mImageSerial                 = kInvalidImageSerial;
5733     mCurrentLayout               = ImageLayout::Undefined;
5734     mCurrentDeviceQueueIndex     = kInvalidDeviceQueueIndex;
5735     mIsReleasedToExternal        = false;
5736     mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
5737     mCurrentShaderReadStageMask  = 0;
5738     mFirstAllocatedLevel         = gl::LevelIndex(0);
5739     mLayerCount                  = 0;
5740     mLevelCount                  = 0;
5741     mTotalStagedBufferUpdateSize = 0;
5742     mAllocationSize              = 0;
5743     mMemoryAllocationType        = MemoryAllocationType::InvalidEnum;
5744     mMemoryTypeIndex             = kInvalidMemoryTypeIndex;
5745     std::fill(mViewFormats.begin(), mViewFormats.begin() + mViewFormats.max_size(),
5746               VK_FORMAT_UNDEFINED);
5747     mYcbcrConversionDesc.reset();
5748     mCurrentSingleClearValue.reset();
5749     mRenderPassUsageFlags.reset();
5750 
5751     setEntireContentUndefined();
5752 }
5753 
setEntireContentDefined()5754 void ImageHelper::setEntireContentDefined()
5755 {
5756     for (LevelContentDefinedMask &levelContentDefined : mContentDefined)
5757     {
5758         levelContentDefined.set();
5759     }
5760     for (LevelContentDefinedMask &levelContentDefined : mStencilContentDefined)
5761     {
5762         levelContentDefined.set();
5763     }
5764 }
5765 
setEntireContentUndefined()5766 void ImageHelper::setEntireContentUndefined()
5767 {
5768     for (LevelContentDefinedMask &levelContentDefined : mContentDefined)
5769     {
5770         levelContentDefined.reset();
5771     }
5772     for (LevelContentDefinedMask &levelContentDefined : mStencilContentDefined)
5773     {
5774         levelContentDefined.reset();
5775     }
5776 
5777     // Note: this function is typically called during init/release, but also when importing an image
5778     // from Vulkan, so unlike invalidateSubresourceContentImpl, it doesn't attempt to make sure
5779     // emulated formats have a clear staged.
5780 }
5781 
setContentDefined(LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags)5782 void ImageHelper::setContentDefined(LevelIndex levelStart,
5783                                     uint32_t levelCount,
5784                                     uint32_t layerStart,
5785                                     uint32_t layerCount,
5786                                     VkImageAspectFlags aspectFlags)
5787 {
5788     // Mark the range as defined.  Layers above 8 are discarded, and are always assumed to have
5789     // defined contents.
5790     if (layerStart >= kMaxContentDefinedLayerCount)
5791     {
5792         return;
5793     }
5794 
5795     uint8_t layerRangeBits =
5796         GetContentDefinedLayerRangeBits(layerStart, layerCount, kMaxContentDefinedLayerCount);
5797 
5798     for (uint32_t levelOffset = 0; levelOffset < levelCount; ++levelOffset)
5799     {
5800         LevelIndex level = levelStart + levelOffset;
5801 
5802         if ((aspectFlags & ~VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
5803         {
5804             getLevelContentDefined(level) |= layerRangeBits;
5805         }
5806         if ((aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
5807         {
5808             getLevelStencilContentDefined(level) |= layerRangeBits;
5809         }
5810     }
5811 }
5812 
getLevelContentDefined(LevelIndex level)5813 ImageHelper::LevelContentDefinedMask &ImageHelper::getLevelContentDefined(LevelIndex level)
5814 {
5815     return mContentDefined[level.get()];
5816 }
5817 
getLevelStencilContentDefined(LevelIndex level)5818 ImageHelper::LevelContentDefinedMask &ImageHelper::getLevelStencilContentDefined(LevelIndex level)
5819 {
5820     return mStencilContentDefined[level.get()];
5821 }
5822 
getLevelContentDefined(LevelIndex level) const5823 const ImageHelper::LevelContentDefinedMask &ImageHelper::getLevelContentDefined(
5824     LevelIndex level) const
5825 {
5826     return mContentDefined[level.get()];
5827 }
5828 
getLevelStencilContentDefined(LevelIndex level) const5829 const ImageHelper::LevelContentDefinedMask &ImageHelper::getLevelStencilContentDefined(
5830     LevelIndex level) const
5831 {
5832     return mStencilContentDefined[level.get()];
5833 }
5834 
deriveConversionDesc(Context * context,angle::FormatID actualFormatID,angle::FormatID intendedFormatID)5835 YcbcrConversionDesc ImageHelper::deriveConversionDesc(Context *context,
5836                                                       angle::FormatID actualFormatID,
5837                                                       angle::FormatID intendedFormatID)
5838 {
5839     YcbcrConversionDesc conversionDesc{};
5840     const angle::Format &actualFormat = angle::Format::Get(actualFormatID);
5841 
5842     if (actualFormat.isYUV)
5843     {
5844         // Build a suitable conversionDesc; the image is not external but may be YUV
5845         // if app is using ANGLE's YUV internalformat extensions.
5846         Renderer *renderer = context->getRenderer();
5847 
5848         // The Vulkan spec states: The potential format features of the sampler YCBCR conversion
5849         // must support VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT or
5850         // VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT
5851         constexpr VkFormatFeatureFlags kChromaSubSampleFeatureBits =
5852             VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT |
5853             VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT |
5854             VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT;
5855 
5856         VkFormatFeatureFlags supportedFeatureBits =
5857             renderer->getImageFormatFeatureBits(actualFormatID, kChromaSubSampleFeatureBits);
5858 
5859         VkChromaLocation supportedLocation =
5860             (supportedFeatureBits & VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT) != 0
5861                 ? VK_CHROMA_LOCATION_COSITED_EVEN
5862                 : VK_CHROMA_LOCATION_MIDPOINT;
5863         vk::YcbcrLinearFilterSupport linearFilterSupported =
5864             (supportedFeatureBits &
5865              VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT) != 0
5866                 ? vk::YcbcrLinearFilterSupport::Supported
5867                 : vk::YcbcrLinearFilterSupport::Unsupported;
5868 
5869         VkSamplerYcbcrModelConversion conversionModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601;
5870         VkSamplerYcbcrRange colorRange                = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW;
5871         VkFilter chromaFilter                         = kDefaultYCbCrChromaFilter;
5872         VkComponentMapping components                 = {
5873             VK_COMPONENT_SWIZZLE_IDENTITY,
5874             VK_COMPONENT_SWIZZLE_IDENTITY,
5875             VK_COMPONENT_SWIZZLE_IDENTITY,
5876             VK_COMPONENT_SWIZZLE_IDENTITY,
5877         };
5878 
5879         conversionDesc.update(renderer, 0, conversionModel, colorRange, supportedLocation,
5880                               supportedLocation, chromaFilter, components, intendedFormatID,
5881                               linearFilterSupported);
5882     }
5883 
5884     return conversionDesc;
5885 }
5886 
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)5887 angle::Result ImageHelper::init(Context *context,
5888                                 gl::TextureType textureType,
5889                                 const VkExtent3D &extents,
5890                                 const Format &format,
5891                                 GLint samples,
5892                                 VkImageUsageFlags usage,
5893                                 gl::LevelIndex firstLevel,
5894                                 uint32_t mipLevels,
5895                                 uint32_t layerCount,
5896                                 bool isRobustResourceInitEnabled,
5897                                 bool hasProtectedContent)
5898 {
5899     return initExternal(context, textureType, extents, format.getIntendedFormatID(),
5900                         format.getActualRenderableImageFormatID(), samples, usage,
5901                         kVkImageCreateFlagsNone, ImageLayout::Undefined, nullptr, firstLevel,
5902                         mipLevels, layerCount, isRobustResourceInitEnabled, hasProtectedContent,
5903                         deriveConversionDesc(context, format.getActualRenderableImageFormatID(),
5904                                              format.getIntendedFormatID()));
5905 }
5906 
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)5907 angle::Result ImageHelper::initMSAASwapchain(Context *context,
5908                                              gl::TextureType textureType,
5909                                              const VkExtent3D &extents,
5910                                              bool rotatedAspectRatio,
5911                                              const Format &format,
5912                                              GLint samples,
5913                                              VkImageUsageFlags usage,
5914                                              gl::LevelIndex firstLevel,
5915                                              uint32_t mipLevels,
5916                                              uint32_t layerCount,
5917                                              bool isRobustResourceInitEnabled,
5918                                              bool hasProtectedContent)
5919 {
5920     ANGLE_TRY(initExternal(context, textureType, extents, format.getIntendedFormatID(),
5921                            format.getActualRenderableImageFormatID(), samples, usage,
5922                            kVkImageCreateFlagsNone, ImageLayout::Undefined, nullptr, firstLevel,
5923                            mipLevels, layerCount, isRobustResourceInitEnabled, hasProtectedContent,
5924                            YcbcrConversionDesc{}));
5925     if (rotatedAspectRatio)
5926     {
5927         std::swap(mExtents.width, mExtents.height);
5928     }
5929     mRotatedAspectRatio = rotatedAspectRatio;
5930     return angle::Result::Continue;
5931 }
5932 
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,YcbcrConversionDesc conversionDesc)5933 angle::Result ImageHelper::initExternal(Context *context,
5934                                         gl::TextureType textureType,
5935                                         const VkExtent3D &extents,
5936                                         angle::FormatID intendedFormatID,
5937                                         angle::FormatID actualFormatID,
5938                                         GLint samples,
5939                                         VkImageUsageFlags usage,
5940                                         VkImageCreateFlags additionalCreateFlags,
5941                                         ImageLayout initialLayout,
5942                                         const void *externalImageCreateInfo,
5943                                         gl::LevelIndex firstLevel,
5944                                         uint32_t mipLevels,
5945                                         uint32_t layerCount,
5946                                         bool isRobustResourceInitEnabled,
5947                                         bool hasProtectedContent,
5948                                         YcbcrConversionDesc conversionDesc)
5949 {
5950     ASSERT(!valid());
5951     ASSERT(!IsAnySubresourceContentDefined(mContentDefined));
5952     ASSERT(!IsAnySubresourceContentDefined(mStencilContentDefined));
5953 
5954     Renderer *renderer = context->getRenderer();
5955 
5956     mImageType           = gl_vk::GetImageType(textureType);
5957     mExtents             = extents;
5958     mRotatedAspectRatio  = false;
5959     mIntendedFormatID    = intendedFormatID;
5960     mActualFormatID      = actualFormatID;
5961     mSamples             = std::max(samples, 1);
5962     mImageSerial         = renderer->getResourceSerialFactory().generateImageSerial();
5963     mFirstAllocatedLevel = firstLevel;
5964     mLevelCount          = mipLevels;
5965     mLayerCount          = layerCount;
5966     mCreateFlags =
5967         vk::GetMinimalImageCreateFlags(renderer, textureType, usage) | additionalCreateFlags;
5968     mUsage = usage;
5969 
5970     // Validate that mLayerCount is compatible with the texture type
5971     ASSERT(textureType != gl::TextureType::_3D || mLayerCount == 1);
5972     ASSERT(textureType != gl::TextureType::_2DArray || mExtents.depth == 1);
5973     ASSERT(textureType != gl::TextureType::External || mLayerCount == 1);
5974     ASSERT(textureType != gl::TextureType::Rectangle || mLayerCount == 1);
5975     ASSERT(textureType != gl::TextureType::CubeMap || mLayerCount == gl::kCubeFaceCount);
5976     ASSERT(textureType != gl::TextureType::CubeMapArray || mLayerCount % gl::kCubeFaceCount == 0);
5977 
5978     // If externalImageCreateInfo is provided, use that directly.  Otherwise derive the necessary
5979     // pNext chain.
5980     const void *imageCreateInfoPNext = externalImageCreateInfo;
5981     VkImageFormatListCreateInfoKHR imageFormatListInfoStorage;
5982     ImageListFormats imageListFormatsStorage;
5983 
5984     if (externalImageCreateInfo == nullptr)
5985     {
5986         imageCreateInfoPNext =
5987             DeriveCreateInfoPNext(context, actualFormatID, nullptr, &imageFormatListInfoStorage,
5988                                   &imageListFormatsStorage, &mCreateFlags);
5989     }
5990     else
5991     {
5992         // Derive the tiling for external images.
5993         deriveExternalImageTiling(externalImageCreateInfo);
5994     }
5995 
5996     mYcbcrConversionDesc = conversionDesc;
5997 
5998     const angle::Format &actualFormat   = angle::Format::Get(actualFormatID);
5999     const angle::Format &intendedFormat = angle::Format::Get(intendedFormatID);
6000     VkFormat actualVkFormat             = GetVkFormatFromFormatID(actualFormatID);
6001 
6002     ANGLE_TRACE_EVENT_INSTANT("gpu.angle.texture_metrics", "ImageHelper::initExternal",
6003                               "intended_format", intendedFormat.glInternalFormat, "actual_format",
6004                               actualFormat.glInternalFormat, "width", extents.width, "height",
6005                               extents.height);
6006 
6007     if (actualFormat.isYUV)
6008     {
6009         ASSERT(mYcbcrConversionDesc.valid());
6010 
6011         // The Vulkan spec states: If the pNext chain includes a VkExternalFormatANDROID structure
6012         // whose externalFormat member is not 0, flags must not include
6013         // VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT
6014         if (!IsYUVExternalFormat(actualFormatID))
6015         {
6016             // The Vulkan spec states: If sampler is used and the VkFormat of the image is a
6017             // multi-planar format, the image must have been created with
6018             // VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT
6019             mCreateFlags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
6020         }
6021     }
6022 
6023     if (hasProtectedContent)
6024     {
6025         mCreateFlags |= VK_IMAGE_CREATE_PROTECTED_BIT;
6026     }
6027 
6028     VkImageCreateInfo imageInfo = {};
6029     imageInfo.sType             = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
6030     imageInfo.pNext             = imageCreateInfoPNext;
6031     imageInfo.flags             = mCreateFlags;
6032     imageInfo.imageType         = mImageType;
6033     imageInfo.format            = actualVkFormat;
6034     imageInfo.extent            = mExtents;
6035     imageInfo.mipLevels         = mLevelCount;
6036     imageInfo.arrayLayers       = mLayerCount;
6037     imageInfo.samples =
6038         gl_vk::GetSamples(mSamples, context->getFeatures().limitSampleCountTo2.enabled);
6039     imageInfo.tiling                = mTilingMode;
6040     imageInfo.usage                 = mUsage;
6041     imageInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
6042     imageInfo.queueFamilyIndexCount = 0;
6043     imageInfo.pQueueFamilyIndices   = nullptr;
6044     imageInfo.initialLayout         = ConvertImageLayoutToVkImageLayout(renderer, initialLayout);
6045 
6046     mCurrentLayout               = initialLayout;
6047     mCurrentDeviceQueueIndex     = kInvalidDeviceQueueIndex;
6048     mIsReleasedToExternal        = false;
6049     mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
6050     mCurrentShaderReadStageMask  = 0;
6051 
6052     ANGLE_VK_TRY(context, mImage.init(context->getDevice(), imageInfo));
6053 
6054     // Find the image formats in pNext chain in imageInfo.
6055     deriveImageViewFormatFromCreateInfoPNext(imageInfo, mViewFormats);
6056 
6057     mVkImageCreateInfo               = imageInfo;
6058     mVkImageCreateInfo.pNext         = nullptr;
6059     mVkImageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
6060 
6061     stageClearIfEmulatedFormat(isRobustResourceInitEnabled, externalImageCreateInfo != nullptr);
6062 
6063     // Consider the contents defined for any image that has the PREINITIALIZED layout, or is
6064     // imported from external.
6065     if (initialLayout != ImageLayout::Undefined || externalImageCreateInfo != nullptr)
6066     {
6067         setEntireContentDefined();
6068     }
6069 
6070     return angle::Result::Continue;
6071 }
6072 
6073 // static
DeriveCreateInfoPNext(Context * context,angle::FormatID actualFormatID,const void * pNext,VkImageFormatListCreateInfoKHR * imageFormatListInfoStorage,std::array<VkFormat,kImageListFormatCount> * imageListFormatsStorage,VkImageCreateFlags * createFlagsOut)6074 const void *ImageHelper::DeriveCreateInfoPNext(
6075     Context *context,
6076     angle::FormatID actualFormatID,
6077     const void *pNext,
6078     VkImageFormatListCreateInfoKHR *imageFormatListInfoStorage,
6079     std::array<VkFormat, kImageListFormatCount> *imageListFormatsStorage,
6080     VkImageCreateFlags *createFlagsOut)
6081 {
6082     // With the introduction of sRGB related GLES extensions any sample/render target could be
6083     // respecified causing it to be interpreted in a different colorspace.  Create the VkImage
6084     // accordingly.
6085     Renderer *renderer                = context->getRenderer();
6086     const angle::Format &actualFormat = angle::Format::Get(actualFormatID);
6087     angle::FormatID additionalFormat =
6088         actualFormat.isSRGB ? ConvertToLinear(actualFormatID) : ConvertToSRGB(actualFormatID);
6089     (*imageListFormatsStorage)[0] = vk::GetVkFormatFromFormatID(actualFormatID);
6090     (*imageListFormatsStorage)[1] = vk::GetVkFormatFromFormatID(additionalFormat);
6091 
6092     if (renderer->getFeatures().supportsImageFormatList.enabled &&
6093         renderer->haveSameFormatFeatureBits(actualFormatID, additionalFormat))
6094     {
6095         // Add VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT to VkImage create flag
6096         *createFlagsOut |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
6097 
6098         // There is just 1 additional format we might use to create a VkImageView for this
6099         // VkImage
6100         imageFormatListInfoStorage->sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR;
6101         imageFormatListInfoStorage->pNext = pNext;
6102         imageFormatListInfoStorage->viewFormatCount = kImageListFormatCount;
6103         imageFormatListInfoStorage->pViewFormats    = imageListFormatsStorage->data();
6104 
6105         pNext = imageFormatListInfoStorage;
6106     }
6107 
6108     return pNext;
6109 }
6110 
6111 // static
FormatSupportsUsage(Renderer * renderer,VkFormat format,VkImageType imageType,VkImageTiling tilingMode,VkImageUsageFlags usageFlags,VkImageCreateFlags createFlags,void * propertiesPNext,const FormatSupportCheck formatSupportCheck)6112 bool ImageHelper::FormatSupportsUsage(Renderer *renderer,
6113                                       VkFormat format,
6114                                       VkImageType imageType,
6115                                       VkImageTiling tilingMode,
6116                                       VkImageUsageFlags usageFlags,
6117                                       VkImageCreateFlags createFlags,
6118                                       void *propertiesPNext,
6119                                       const FormatSupportCheck formatSupportCheck)
6120 {
6121     VkPhysicalDeviceImageFormatInfo2 imageFormatInfo = {};
6122     imageFormatInfo.sType  = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
6123     imageFormatInfo.format = format;
6124     imageFormatInfo.type   = imageType;
6125     imageFormatInfo.tiling = tilingMode;
6126     imageFormatInfo.usage  = usageFlags;
6127     imageFormatInfo.flags  = createFlags;
6128 
6129     VkImageFormatProperties2 imageFormatProperties2 = {};
6130     imageFormatProperties2.sType                    = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
6131     imageFormatProperties2.pNext                    = propertiesPNext;
6132 
6133     VkResult result = vkGetPhysicalDeviceImageFormatProperties2(
6134         renderer->getPhysicalDevice(), &imageFormatInfo, &imageFormatProperties2);
6135 
6136     if (formatSupportCheck == FormatSupportCheck::RequireMultisampling)
6137     {
6138         // Some drivers return success but sampleCounts == 1 which means no MSRTT
6139         return result == VK_SUCCESS &&
6140                imageFormatProperties2.imageFormatProperties.sampleCounts > 1;
6141     }
6142     return result == VK_SUCCESS;
6143 }
6144 
setImageFormatsFromActualFormat(VkFormat actualFormat,ImageFormats & imageFormatsOut)6145 void ImageHelper::setImageFormatsFromActualFormat(VkFormat actualFormat,
6146                                                   ImageFormats &imageFormatsOut)
6147 {
6148     imageFormatsOut.push_back(actualFormat);
6149 }
6150 
deriveImageViewFormatFromCreateInfoPNext(VkImageCreateInfo & imageInfo,ImageFormats & formatOut)6151 void ImageHelper::deriveImageViewFormatFromCreateInfoPNext(VkImageCreateInfo &imageInfo,
6152                                                            ImageFormats &formatOut)
6153 {
6154     const VkBaseInStructure *pNextChain =
6155         reinterpret_cast<const VkBaseInStructure *>(imageInfo.pNext);
6156     while (pNextChain != nullptr &&
6157            pNextChain->sType != VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR)
6158     {
6159         pNextChain = pNextChain->pNext;
6160     }
6161 
6162     // Clear formatOut in case it has leftovers from previous VkImage in the case of releaseImage
6163     // followed by initExternal.
6164     std::fill(formatOut.begin(), formatOut.begin() + formatOut.max_size(), VK_FORMAT_UNDEFINED);
6165     if (pNextChain != nullptr)
6166     {
6167         const VkImageFormatListCreateInfoKHR *imageFormatCreateInfo =
6168             reinterpret_cast<const VkImageFormatListCreateInfoKHR *>(pNextChain);
6169 
6170         for (uint32_t i = 0; i < imageFormatCreateInfo->viewFormatCount; i++)
6171         {
6172             formatOut.push_back(*(imageFormatCreateInfo->pViewFormats + i));
6173         }
6174     }
6175     else
6176     {
6177         setImageFormatsFromActualFormat(imageInfo.format, formatOut);
6178     }
6179 }
6180 
deriveExternalImageTiling(const void * createInfoChain)6181 void ImageHelper::deriveExternalImageTiling(const void *createInfoChain)
6182 {
6183     const VkBaseInStructure *chain = reinterpret_cast<const VkBaseInStructure *>(createInfoChain);
6184     while (chain != nullptr)
6185     {
6186         if (chain->sType == VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT ||
6187             chain->sType == VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT)
6188         {
6189             mTilingMode = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
6190             return;
6191         }
6192 
6193         chain = reinterpret_cast<const VkBaseInStructure *>(chain->pNext);
6194     }
6195 }
6196 
releaseImage(Renderer * renderer)6197 void ImageHelper::releaseImage(Renderer *renderer)
6198 {
6199     // mDeviceMemory and mVmaAllocation should not be valid at the same time.
6200     ASSERT(!mDeviceMemory.valid() || !mVmaAllocation.valid());
6201     if (mDeviceMemory.valid())
6202     {
6203         renderer->onMemoryDealloc(mMemoryAllocationType, mAllocationSize, mMemoryTypeIndex,
6204                                   mDeviceMemory.getHandle());
6205     }
6206     if (mVmaAllocation.valid())
6207     {
6208         renderer->onMemoryDealloc(mMemoryAllocationType, mAllocationSize, mMemoryTypeIndex,
6209                                   mVmaAllocation.getHandle());
6210     }
6211     mCurrentEvent.release(renderer);
6212     mLastNonShaderReadOnlyEvent.release(renderer);
6213     renderer->collectGarbage(mUse, &mImage, &mDeviceMemory, &mVmaAllocation);
6214     mViewFormats.clear();
6215     mUse.reset();
6216     mImageSerial          = kInvalidImageSerial;
6217     mMemoryAllocationType = MemoryAllocationType::InvalidEnum;
6218     setEntireContentUndefined();
6219 }
6220 
releaseImageFromShareContexts(Renderer * renderer,ContextVk * contextVk,UniqueSerial imageSiblingSerial)6221 void ImageHelper::releaseImageFromShareContexts(Renderer *renderer,
6222                                                 ContextVk *contextVk,
6223                                                 UniqueSerial imageSiblingSerial)
6224 {
6225     finalizeImageLayoutInShareContexts(renderer, contextVk, imageSiblingSerial);
6226     contextVk->addToPendingImageGarbage(mUse, mAllocationSize);
6227     releaseImage(renderer);
6228 }
6229 
finalizeImageLayoutInShareContexts(Renderer * renderer,ContextVk * contextVk,UniqueSerial imageSiblingSerial)6230 void ImageHelper::finalizeImageLayoutInShareContexts(Renderer *renderer,
6231                                                      ContextVk *contextVk,
6232                                                      UniqueSerial imageSiblingSerial)
6233 {
6234     if (contextVk && mImageSerial.valid())
6235     {
6236         for (auto context : contextVk->getShareGroup()->getContexts())
6237         {
6238             vk::GetImpl(context.second)->finalizeImageLayout(this, imageSiblingSerial);
6239         }
6240     }
6241 }
6242 
releaseStagedUpdates(Renderer * renderer)6243 void ImageHelper::releaseStagedUpdates(Renderer *renderer)
6244 {
6245     ASSERT(validateSubresourceUpdateRefCountsConsistent());
6246 
6247     // Remove updates that never made it to the texture.
6248     for (std::vector<SubresourceUpdate> &levelUpdates : mSubresourceUpdates)
6249     {
6250         for (SubresourceUpdate &update : levelUpdates)
6251         {
6252             update.release(renderer);
6253         }
6254     }
6255 
6256     ASSERT(validateSubresourceUpdateRefCountsConsistent());
6257 
6258     mSubresourceUpdates.clear();
6259     mTotalStagedBufferUpdateSize = 0;
6260     mCurrentSingleClearValue.reset();
6261 }
6262 
resetImageWeakReference()6263 void ImageHelper::resetImageWeakReference()
6264 {
6265     mImage.reset();
6266     mImageSerial        = kInvalidImageSerial;
6267     mRotatedAspectRatio = false;
6268     // Caller must ensure ANI semaphores are properly waited or released.
6269     ASSERT(!mAcquireNextImageSemaphore.valid());
6270 }
6271 
initializeNonZeroMemory(Context * context,bool hasProtectedContent,VkMemoryPropertyFlags flags,VkDeviceSize size)6272 angle::Result ImageHelper::initializeNonZeroMemory(Context *context,
6273                                                    bool hasProtectedContent,
6274                                                    VkMemoryPropertyFlags flags,
6275                                                    VkDeviceSize size)
6276 {
6277     // If available, memory mapping should be used.
6278     Renderer *renderer = context->getRenderer();
6279 
6280     if ((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
6281     {
6282         // Wipe memory to an invalid value when the 'allocateNonZeroMemory' feature is enabled. The
6283         // invalid values ensures our testing doesn't assume zero-initialized memory.
6284         constexpr int kNonZeroInitValue = 0x3F;
6285         if (renderer->getFeatures().useVmaForImageSuballocation.enabled)
6286         {
6287             ANGLE_VK_TRY(context,
6288                          renderer->getImageMemorySuballocator().mapMemoryAndInitWithNonZeroValue(
6289                              renderer, &mVmaAllocation, size, kNonZeroInitValue, flags));
6290         }
6291         else
6292         {
6293             ANGLE_TRY(vk::InitMappableDeviceMemory(context, &mDeviceMemory, size, kNonZeroInitValue,
6294                                                    flags));
6295         }
6296 
6297         return angle::Result::Continue;
6298     }
6299 
6300     // If mapping the memory is unavailable, a staging resource is used.
6301     const angle::Format &angleFormat = getActualFormat();
6302     bool isCompressedFormat          = angleFormat.isBlock;
6303 
6304     if (angleFormat.isYUV)
6305     {
6306         // VUID-vkCmdClearColorImage-image-01545
6307         // vkCmdClearColorImage(): format must not be one of the formats requiring sampler YCBCR
6308         // conversion for VK_IMAGE_ASPECT_COLOR_BIT image views
6309         return angle::Result::Continue;
6310     }
6311 
6312     // Since we are going to do a one off out of order submission, there shouldn't any pending
6313     // setEvent.
6314     ASSERT(!mCurrentEvent.valid());
6315 
6316     PrimaryCommandBuffer commandBuffer;
6317     auto protectionType = ConvertProtectionBoolToType(hasProtectedContent);
6318     ANGLE_TRY(renderer->getCommandBufferOneOff(context, protectionType, &commandBuffer));
6319 
6320     // Queue a DMA copy.
6321     VkSemaphore acquireNextImageSemaphore;
6322     barrierImpl(context, getAspectFlags(), ImageLayout::TransferDst, context->getDeviceQueueIndex(),
6323                 nullptr, &commandBuffer, &acquireNextImageSemaphore);
6324     // SwapChain image should not come here
6325     ASSERT(acquireNextImageSemaphore == VK_NULL_HANDLE);
6326 
6327     StagingBuffer stagingBuffer;
6328 
6329     if (isCompressedFormat)
6330     {
6331         // If format is compressed, set its contents through buffer copies.
6332 
6333         // The staging buffer memory is non-zero-initialized in 'init'.
6334         ANGLE_TRY(stagingBuffer.init(context, size, StagingUsage::Write));
6335 
6336         for (LevelIndex level(0); level < LevelIndex(mLevelCount); ++level)
6337         {
6338             VkBufferImageCopy copyRegion = {};
6339 
6340             gl_vk::GetExtent(getLevelExtents(level), &copyRegion.imageExtent);
6341             copyRegion.imageSubresource.aspectMask = getAspectFlags();
6342             copyRegion.imageSubresource.layerCount = mLayerCount;
6343 
6344             // If image has depth and stencil, copy to each individually per Vulkan spec.
6345             bool hasBothDepthAndStencil = isCombinedDepthStencilFormat();
6346             if (hasBothDepthAndStencil)
6347             {
6348                 copyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
6349             }
6350 
6351             commandBuffer.copyBufferToImage(stagingBuffer.getBuffer().getHandle(), mImage,
6352                                             VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copyRegion);
6353 
6354             if (hasBothDepthAndStencil)
6355             {
6356                 copyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
6357 
6358                 commandBuffer.copyBufferToImage(stagingBuffer.getBuffer().getHandle(), mImage,
6359                                                 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1,
6360                                                 &copyRegion);
6361             }
6362         }
6363     }
6364     else
6365     {
6366         // Otherwise issue clear commands.
6367         VkImageSubresourceRange subresource = {};
6368         subresource.aspectMask              = getAspectFlags();
6369         subresource.baseMipLevel            = 0;
6370         subresource.levelCount              = mLevelCount;
6371         subresource.baseArrayLayer          = 0;
6372         subresource.layerCount              = mLayerCount;
6373 
6374         // Arbitrary value to initialize the memory with.  Note: the given uint value, reinterpreted
6375         // as float is about 0.7.
6376         constexpr uint32_t kInitValue   = 0x3F345678;
6377         constexpr float kInitValueFloat = 0.12345f;
6378 
6379         if ((subresource.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != 0)
6380         {
6381             VkClearColorValue clearValue;
6382             clearValue.uint32[0] = kInitValue;
6383             clearValue.uint32[1] = kInitValue;
6384             clearValue.uint32[2] = kInitValue;
6385             clearValue.uint32[3] = kInitValue;
6386 
6387             commandBuffer.clearColorImage(mImage, getCurrentLayout(renderer), clearValue, 1,
6388                                           &subresource);
6389         }
6390         else
6391         {
6392             VkClearDepthStencilValue clearValue;
6393             clearValue.depth   = kInitValueFloat;
6394             clearValue.stencil = kInitValue;
6395 
6396             commandBuffer.clearDepthStencilImage(mImage, getCurrentLayout(renderer), clearValue, 1,
6397                                                  &subresource);
6398         }
6399     }
6400 
6401     ANGLE_VK_TRY(context, commandBuffer.end());
6402 
6403     QueueSerial queueSerial;
6404     ANGLE_TRY(renderer->queueSubmitOneOff(context, std::move(commandBuffer), protectionType,
6405                                           egl::ContextPriority::Medium, VK_NULL_HANDLE, 0,
6406                                           vk::SubmitPolicy::AllowDeferred, &queueSerial));
6407 
6408     if (isCompressedFormat)
6409     {
6410         stagingBuffer.collectGarbage(renderer, queueSerial);
6411     }
6412     mUse.setQueueSerial(queueSerial);
6413 
6414     return angle::Result::Continue;
6415 }
6416 
initMemory(Context * context,const MemoryProperties & memoryProperties,VkMemoryPropertyFlags flags,VkMemoryPropertyFlags excludedFlags,const VkMemoryRequirements * memoryRequirements,const bool allocateDedicatedMemory,MemoryAllocationType allocationType,VkMemoryPropertyFlags * flagsOut,VkDeviceSize * sizeOut)6417 VkResult ImageHelper::initMemory(Context *context,
6418                                  const MemoryProperties &memoryProperties,
6419                                  VkMemoryPropertyFlags flags,
6420                                  VkMemoryPropertyFlags excludedFlags,
6421                                  const VkMemoryRequirements *memoryRequirements,
6422                                  const bool allocateDedicatedMemory,
6423                                  MemoryAllocationType allocationType,
6424                                  VkMemoryPropertyFlags *flagsOut,
6425                                  VkDeviceSize *sizeOut)
6426 {
6427     mMemoryAllocationType = allocationType;
6428 
6429     // To allocate memory here, if possible, we use the image memory suballocator which uses VMA.
6430     ASSERT(excludedFlags < VK_MEMORY_PROPERTY_FLAG_BITS_MAX_ENUM);
6431     Renderer *renderer = context->getRenderer();
6432     if (renderer->getFeatures().useVmaForImageSuballocation.enabled)
6433     {
6434         // While it may be preferable to allocate the image on the device, it should also be
6435         // possible to allocate on other memory types if the device is out of memory.
6436         VkMemoryPropertyFlags requiredFlags  = flags & (~excludedFlags);
6437         VkMemoryPropertyFlags preferredFlags = flags;
6438         VK_RESULT_TRY(renderer->getImageMemorySuballocator().allocateAndBindMemory(
6439             context, &mImage, &mVkImageCreateInfo, requiredFlags, preferredFlags,
6440             memoryRequirements, allocateDedicatedMemory, mMemoryAllocationType, &mVmaAllocation,
6441             flagsOut, &mMemoryTypeIndex, &mAllocationSize));
6442     }
6443     else
6444     {
6445         VK_RESULT_TRY(AllocateImageMemory(context, mMemoryAllocationType, flags, flagsOut, nullptr,
6446                                           &mImage, &mMemoryTypeIndex, &mDeviceMemory,
6447                                           &mAllocationSize));
6448     }
6449 
6450     mCurrentDeviceQueueIndex = context->getDeviceQueueIndex();
6451     mIsReleasedToExternal    = false;
6452     *sizeOut                 = mAllocationSize;
6453 
6454     return VK_SUCCESS;
6455 }
6456 
initMemoryAndNonZeroFillIfNeeded(Context * context,bool hasProtectedContent,const MemoryProperties & memoryProperties,VkMemoryPropertyFlags flags,MemoryAllocationType allocationType)6457 angle::Result ImageHelper::initMemoryAndNonZeroFillIfNeeded(
6458     Context *context,
6459     bool hasProtectedContent,
6460     const MemoryProperties &memoryProperties,
6461     VkMemoryPropertyFlags flags,
6462     MemoryAllocationType allocationType)
6463 {
6464     Renderer *renderer = context->getRenderer();
6465     VkMemoryPropertyFlags outputFlags;
6466     VkDeviceSize outputSize;
6467 
6468     if (hasProtectedContent)
6469     {
6470         flags |= VK_MEMORY_PROPERTY_PROTECTED_BIT;
6471     }
6472 
6473     // Get memory requirements for the allocation.
6474     VkMemoryRequirements memoryRequirements;
6475     mImage.getMemoryRequirements(renderer->getDevice(), &memoryRequirements);
6476     bool allocateDedicatedMemory =
6477         renderer->getImageMemorySuballocator().needsDedicatedMemory(memoryRequirements.size);
6478 
6479     ANGLE_VK_TRY(context,
6480                  initMemory(context, memoryProperties, flags, 0, &memoryRequirements,
6481                             allocateDedicatedMemory, allocationType, &outputFlags, &outputSize));
6482 
6483     if (renderer->getFeatures().allocateNonZeroMemory.enabled)
6484     {
6485         ANGLE_TRY(initializeNonZeroMemory(context, hasProtectedContent, outputFlags, outputSize));
6486     }
6487     return angle::Result::Continue;
6488 }
6489 
initExternalMemory(Context * context,const MemoryProperties & memoryProperties,const VkMemoryRequirements & memoryRequirements,uint32_t extraAllocationInfoCount,const void ** extraAllocationInfo,DeviceQueueIndex currentDeviceQueueIndex,VkMemoryPropertyFlags flags)6490 angle::Result ImageHelper::initExternalMemory(Context *context,
6491                                               const MemoryProperties &memoryProperties,
6492                                               const VkMemoryRequirements &memoryRequirements,
6493                                               uint32_t extraAllocationInfoCount,
6494                                               const void **extraAllocationInfo,
6495                                               DeviceQueueIndex currentDeviceQueueIndex,
6496                                               VkMemoryPropertyFlags flags)
6497 {
6498     // Vulkan allows up to 4 memory planes.
6499     constexpr size_t kMaxMemoryPlanes                                     = 4;
6500     constexpr VkImageAspectFlagBits kMemoryPlaneAspects[kMaxMemoryPlanes] = {
6501         VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT,
6502         VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT,
6503         VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT,
6504         VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT,
6505     };
6506     ASSERT(extraAllocationInfoCount <= kMaxMemoryPlanes);
6507 
6508     VkBindImagePlaneMemoryInfoKHR bindImagePlaneMemoryInfo = {};
6509     bindImagePlaneMemoryInfo.sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO;
6510 
6511     const VkBindImagePlaneMemoryInfoKHR *bindImagePlaneMemoryInfoPtr =
6512         extraAllocationInfoCount == 1 ? nullptr : &bindImagePlaneMemoryInfo;
6513 
6514     mAllocationSize       = memoryRequirements.size;
6515     mMemoryAllocationType = MemoryAllocationType::ImageExternal;
6516 
6517     for (uint32_t memoryPlane = 0; memoryPlane < extraAllocationInfoCount; ++memoryPlane)
6518     {
6519         bindImagePlaneMemoryInfo.planeAspect = kMemoryPlaneAspects[memoryPlane];
6520 
6521         ANGLE_VK_TRY(context, AllocateImageMemoryWithRequirements(
6522                                   context, mMemoryAllocationType, flags, memoryRequirements,
6523                                   extraAllocationInfo[memoryPlane], bindImagePlaneMemoryInfoPtr,
6524                                   &mImage, &mMemoryTypeIndex, &mDeviceMemory));
6525     }
6526     mCurrentDeviceQueueIndex = currentDeviceQueueIndex;
6527     mIsReleasedToExternal    = false;
6528 
6529     return angle::Result::Continue;
6530 }
6531 
initImageView(Context * context,gl::TextureType textureType,VkImageAspectFlags aspectMask,const gl::SwizzleState & swizzleMap,ImageView * imageViewOut,LevelIndex baseMipLevelVk,uint32_t levelCount,VkImageUsageFlags imageUsageFlags)6532 angle::Result ImageHelper::initImageView(Context *context,
6533                                          gl::TextureType textureType,
6534                                          VkImageAspectFlags aspectMask,
6535                                          const gl::SwizzleState &swizzleMap,
6536                                          ImageView *imageViewOut,
6537                                          LevelIndex baseMipLevelVk,
6538                                          uint32_t levelCount,
6539                                          VkImageUsageFlags imageUsageFlags)
6540 {
6541     return initLayerImageView(context, textureType, aspectMask, swizzleMap, imageViewOut,
6542                               baseMipLevelVk, levelCount, 0, mLayerCount,
6543                               gl::SrgbWriteControlMode::Default, gl::YuvSamplingMode::Default,
6544                               imageUsageFlags);
6545 }
6546 
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 srgbWriteControlMode,gl::YuvSamplingMode yuvSamplingMode,VkImageUsageFlags imageUsageFlags) const6547 angle::Result ImageHelper::initLayerImageView(Context *context,
6548                                               gl::TextureType textureType,
6549                                               VkImageAspectFlags aspectMask,
6550                                               const gl::SwizzleState &swizzleMap,
6551                                               ImageView *imageViewOut,
6552                                               LevelIndex baseMipLevelVk,
6553                                               uint32_t levelCount,
6554                                               uint32_t baseArrayLayer,
6555                                               uint32_t layerCount,
6556                                               gl::SrgbWriteControlMode srgbWriteControlMode,
6557                                               gl::YuvSamplingMode yuvSamplingMode,
6558                                               VkImageUsageFlags imageUsageFlags) const
6559 {
6560     angle::FormatID actualFormat = mActualFormatID;
6561 
6562     // If we are initializing an imageview for use with EXT_srgb_write_control, we need to override
6563     // the format to its linear counterpart. Formats that cannot be reinterpreted are exempt from
6564     // this requirement.
6565     if (srgbWriteControlMode == gl::SrgbWriteControlMode::Linear)
6566     {
6567         angle::FormatID linearFormat = ConvertToLinear(actualFormat);
6568         if (linearFormat != angle::FormatID::NONE)
6569         {
6570             actualFormat = linearFormat;
6571         }
6572     }
6573 
6574     return initLayerImageViewImpl(context, textureType, aspectMask, swizzleMap, imageViewOut,
6575                                   baseMipLevelVk, levelCount, baseArrayLayer, layerCount,
6576                                   GetVkFormatFromFormatID(actualFormat), imageUsageFlags,
6577                                   yuvSamplingMode);
6578 }
6579 
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,VkImageUsageFlags usageFlags,gl::YuvSamplingMode yuvSamplingMode) const6580 angle::Result ImageHelper::initLayerImageViewImpl(Context *context,
6581                                                   gl::TextureType textureType,
6582                                                   VkImageAspectFlags aspectMask,
6583                                                   const gl::SwizzleState &swizzleMap,
6584                                                   ImageView *imageViewOut,
6585                                                   LevelIndex baseMipLevelVk,
6586                                                   uint32_t levelCount,
6587                                                   uint32_t baseArrayLayer,
6588                                                   uint32_t layerCount,
6589                                                   VkFormat imageFormat,
6590                                                   VkImageUsageFlags usageFlags,
6591                                                   gl::YuvSamplingMode yuvSamplingMode) const
6592 {
6593     VkImageViewCreateInfo viewInfo = {};
6594     viewInfo.sType                 = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
6595     viewInfo.flags                 = 0;
6596     viewInfo.image                 = mImage.getHandle();
6597     viewInfo.viewType              = gl_vk::GetImageViewType(textureType);
6598     viewInfo.format                = imageFormat;
6599 
6600     if (swizzleMap.swizzleRequired() && !mYcbcrConversionDesc.valid())
6601     {
6602         viewInfo.components.r = gl_vk::GetSwizzle(swizzleMap.swizzleRed);
6603         viewInfo.components.g = gl_vk::GetSwizzle(swizzleMap.swizzleGreen);
6604         viewInfo.components.b = gl_vk::GetSwizzle(swizzleMap.swizzleBlue);
6605         viewInfo.components.a = gl_vk::GetSwizzle(swizzleMap.swizzleAlpha);
6606     }
6607     else
6608     {
6609         viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
6610         viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
6611         viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
6612         viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
6613     }
6614     viewInfo.subresourceRange.aspectMask     = aspectMask;
6615     viewInfo.subresourceRange.baseMipLevel   = baseMipLevelVk.get();
6616     viewInfo.subresourceRange.levelCount     = levelCount;
6617     viewInfo.subresourceRange.baseArrayLayer = baseArrayLayer;
6618     viewInfo.subresourceRange.layerCount     = layerCount;
6619 
6620     VkImageViewUsageCreateInfo imageViewUsageCreateInfo = {};
6621     if (usageFlags)
6622     {
6623         imageViewUsageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO;
6624         imageViewUsageCreateInfo.usage = usageFlags;
6625 
6626         viewInfo.pNext = &imageViewUsageCreateInfo;
6627     }
6628 
6629     VkSamplerYcbcrConversionInfo yuvConversionInfo = {};
6630 
6631     auto conversionDesc =
6632         yuvSamplingMode == gl::YuvSamplingMode::Y2Y ? getY2YConversionDesc() : mYcbcrConversionDesc;
6633 
6634     if (conversionDesc.valid())
6635     {
6636         ASSERT((context->getRenderer()->getFeatures().supportsYUVSamplerConversion.enabled));
6637         yuvConversionInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO;
6638         yuvConversionInfo.pNext = nullptr;
6639         ANGLE_TRY(context->getRenderer()->getYuvConversionCache().getSamplerYcbcrConversion(
6640             context, conversionDesc, &yuvConversionInfo.conversion));
6641         AddToPNextChain(&viewInfo, &yuvConversionInfo);
6642 
6643         // VUID-VkImageViewCreateInfo-image-02399
6644         // If image has an external format, format must be VK_FORMAT_UNDEFINED
6645         if (conversionDesc.getExternalFormat() != 0)
6646         {
6647             viewInfo.format = VK_FORMAT_UNDEFINED;
6648         }
6649     }
6650     ANGLE_VK_TRY(context, imageViewOut->init(context->getDevice(), viewInfo));
6651     return angle::Result::Continue;
6652 }
6653 
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) const6654 angle::Result ImageHelper::initReinterpretedLayerImageView(Context *context,
6655                                                            gl::TextureType textureType,
6656                                                            VkImageAspectFlags aspectMask,
6657                                                            const gl::SwizzleState &swizzleMap,
6658                                                            ImageView *imageViewOut,
6659                                                            LevelIndex baseMipLevelVk,
6660                                                            uint32_t levelCount,
6661                                                            uint32_t baseArrayLayer,
6662                                                            uint32_t layerCount,
6663                                                            VkImageUsageFlags imageUsageFlags,
6664                                                            angle::FormatID imageViewFormat) const
6665 {
6666     VkImageUsageFlags usageFlags =
6667         imageUsageFlags & GetMaximalImageUsageFlags(context->getRenderer(), imageViewFormat);
6668 
6669     return initLayerImageViewImpl(context, textureType, aspectMask, swizzleMap, imageViewOut,
6670                                   baseMipLevelVk, levelCount, baseArrayLayer, layerCount,
6671                                   vk::GetVkFormatFromFormatID(imageViewFormat), usageFlags,
6672                                   gl::YuvSamplingMode::Default);
6673 }
6674 
destroy(Renderer * renderer)6675 void ImageHelper::destroy(Renderer *renderer)
6676 {
6677     VkDevice device = renderer->getDevice();
6678 
6679     // mDeviceMemory and mVmaAllocation should not be valid at the same time.
6680     ASSERT(!mDeviceMemory.valid() || !mVmaAllocation.valid());
6681     if (mDeviceMemory.valid())
6682     {
6683         renderer->onMemoryDealloc(mMemoryAllocationType, mAllocationSize, mMemoryTypeIndex,
6684                                   mDeviceMemory.getHandle());
6685     }
6686     if (mVmaAllocation.valid())
6687     {
6688         renderer->onMemoryDealloc(mMemoryAllocationType, mAllocationSize, mMemoryTypeIndex,
6689                                   mVmaAllocation.getHandle());
6690     }
6691 
6692     mCurrentEvent.release(renderer);
6693     mLastNonShaderReadOnlyEvent.release(renderer);
6694     mImage.destroy(device);
6695     mDeviceMemory.destroy(device);
6696     mVmaAllocation.destroy(renderer->getAllocator());
6697     mCurrentLayout        = ImageLayout::Undefined;
6698     mImageType            = VK_IMAGE_TYPE_2D;
6699     mLayerCount           = 0;
6700     mLevelCount           = 0;
6701     mMemoryAllocationType = MemoryAllocationType::InvalidEnum;
6702 
6703     setEntireContentUndefined();
6704 }
6705 
init2DWeakReference(Context * context,VkImage handle,const gl::Extents & glExtents,bool rotatedAspectRatio,angle::FormatID intendedFormatID,angle::FormatID actualFormatID,VkImageCreateFlags createFlags,VkImageUsageFlags usage,GLint samples,bool isRobustResourceInitEnabled)6706 void ImageHelper::init2DWeakReference(Context *context,
6707                                       VkImage handle,
6708                                       const gl::Extents &glExtents,
6709                                       bool rotatedAspectRatio,
6710                                       angle::FormatID intendedFormatID,
6711                                       angle::FormatID actualFormatID,
6712                                       VkImageCreateFlags createFlags,
6713                                       VkImageUsageFlags usage,
6714                                       GLint samples,
6715                                       bool isRobustResourceInitEnabled)
6716 {
6717     ASSERT(!valid());
6718     ASSERT(!IsAnySubresourceContentDefined(mContentDefined));
6719     ASSERT(!IsAnySubresourceContentDefined(mStencilContentDefined));
6720 
6721     gl_vk::GetExtent(glExtents, &mExtents);
6722     mRotatedAspectRatio = rotatedAspectRatio;
6723     mIntendedFormatID   = intendedFormatID;
6724     mActualFormatID     = actualFormatID;
6725     mCreateFlags        = createFlags;
6726     mUsage              = usage;
6727     mSamples            = std::max(samples, 1);
6728     mImageSerial        = context->getRenderer()->getResourceSerialFactory().generateImageSerial();
6729     mCurrentDeviceQueueIndex = context->getDeviceQueueIndex();
6730     mIsReleasedToExternal    = false;
6731     mCurrentLayout           = ImageLayout::Undefined;
6732     mLayerCount              = 1;
6733     mLevelCount              = 1;
6734 
6735     // The view formats and usage flags are used for imageless framebuffers. Here, the former is set
6736     // similar to deriveImageViewFormatFromCreateInfoPNext() when there is no pNext from a
6737     // VkImageCreateInfo object.
6738     setImageFormatsFromActualFormat(GetVkFormatFromFormatID(actualFormatID), mViewFormats);
6739 
6740     mImage.setHandle(handle);
6741 
6742     stageClearIfEmulatedFormat(isRobustResourceInitEnabled, false);
6743 }
6744 
init2DStaging(Context * context,bool hasProtectedContent,const MemoryProperties & memoryProperties,const gl::Extents & glExtents,angle::FormatID intendedFormatID,angle::FormatID actualFormatID,VkImageUsageFlags usage,uint32_t layerCount)6745 angle::Result ImageHelper::init2DStaging(Context *context,
6746                                          bool hasProtectedContent,
6747                                          const MemoryProperties &memoryProperties,
6748                                          const gl::Extents &glExtents,
6749                                          angle::FormatID intendedFormatID,
6750                                          angle::FormatID actualFormatID,
6751                                          VkImageUsageFlags usage,
6752                                          uint32_t layerCount)
6753 {
6754     gl_vk::GetExtent(glExtents, &mExtents);
6755 
6756     return initStaging(context, hasProtectedContent, memoryProperties, VK_IMAGE_TYPE_2D, mExtents,
6757                        intendedFormatID, actualFormatID, 1, usage, 1, layerCount);
6758 }
6759 
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)6760 angle::Result ImageHelper::initStaging(Context *context,
6761                                        bool hasProtectedContent,
6762                                        const MemoryProperties &memoryProperties,
6763                                        VkImageType imageType,
6764                                        const VkExtent3D &extents,
6765                                        angle::FormatID intendedFormatID,
6766                                        angle::FormatID actualFormatID,
6767                                        GLint samples,
6768                                        VkImageUsageFlags usage,
6769                                        uint32_t mipLevels,
6770                                        uint32_t layerCount)
6771 {
6772     ASSERT(!valid());
6773     ASSERT(!IsAnySubresourceContentDefined(mContentDefined));
6774     ASSERT(!IsAnySubresourceContentDefined(mStencilContentDefined));
6775 
6776     mImageType          = imageType;
6777     mExtents            = extents;
6778     mRotatedAspectRatio = false;
6779     mIntendedFormatID   = intendedFormatID;
6780     mActualFormatID     = actualFormatID;
6781     mSamples            = std::max(samples, 1);
6782     mImageSerial        = context->getRenderer()->getResourceSerialFactory().generateImageSerial();
6783     mLayerCount         = layerCount;
6784     mLevelCount         = mipLevels;
6785     mUsage              = usage;
6786 
6787     // Validate that mLayerCount is compatible with the image type
6788     ASSERT(imageType != VK_IMAGE_TYPE_3D || mLayerCount == 1);
6789     ASSERT(imageType != VK_IMAGE_TYPE_2D || mExtents.depth == 1);
6790 
6791     mCurrentLayout = ImageLayout::Undefined;
6792 
6793     VkImageCreateInfo imageInfo = {};
6794     imageInfo.sType             = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
6795     imageInfo.flags             = hasProtectedContent ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
6796     imageInfo.imageType         = mImageType;
6797     imageInfo.format            = GetVkFormatFromFormatID(actualFormatID);
6798     imageInfo.extent            = mExtents;
6799     imageInfo.mipLevels         = mLevelCount;
6800     imageInfo.arrayLayers       = mLayerCount;
6801     imageInfo.samples =
6802         gl_vk::GetSamples(mSamples, context->getFeatures().limitSampleCountTo2.enabled);
6803     imageInfo.tiling                = VK_IMAGE_TILING_OPTIMAL;
6804     imageInfo.usage                 = usage;
6805     imageInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
6806     imageInfo.queueFamilyIndexCount = 0;
6807     imageInfo.pQueueFamilyIndices   = nullptr;
6808     imageInfo.initialLayout         = getCurrentLayout(context->getRenderer());
6809 
6810     ANGLE_VK_TRY(context, mImage.init(context->getDevice(), imageInfo));
6811 
6812     mVkImageCreateInfo               = imageInfo;
6813     mVkImageCreateInfo.pNext         = nullptr;
6814     mVkImageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
6815 
6816     // Allocate and bind device-local memory.
6817     VkMemoryPropertyFlags memoryPropertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
6818     if (hasProtectedContent)
6819     {
6820         memoryPropertyFlags |= VK_MEMORY_PROPERTY_PROTECTED_BIT;
6821     }
6822 
6823     ANGLE_TRY(initMemoryAndNonZeroFillIfNeeded(context, hasProtectedContent, memoryProperties,
6824                                                memoryPropertyFlags,
6825                                                vk::MemoryAllocationType::StagingImage));
6826     return angle::Result::Continue;
6827 }
6828 
initImplicitMultisampledRenderToTexture(Context * context,bool hasProtectedContent,const MemoryProperties & memoryProperties,gl::TextureType textureType,GLint samples,const ImageHelper & resolveImage,const VkExtent3D & multisampleImageExtents,bool isRobustResourceInitEnabled)6829 angle::Result ImageHelper::initImplicitMultisampledRenderToTexture(
6830     Context *context,
6831     bool hasProtectedContent,
6832     const MemoryProperties &memoryProperties,
6833     gl::TextureType textureType,
6834     GLint samples,
6835     const ImageHelper &resolveImage,
6836     const VkExtent3D &multisampleImageExtents,
6837     bool isRobustResourceInitEnabled)
6838 {
6839     ASSERT(!valid());
6840     ASSERT(samples > 1);
6841     ASSERT(!IsAnySubresourceContentDefined(mContentDefined));
6842     ASSERT(!IsAnySubresourceContentDefined(mStencilContentDefined));
6843 
6844     // The image is used as either color or depth/stencil attachment.  Additionally, its memory is
6845     // lazily allocated as the contents are discarded at the end of the renderpass and with tiling
6846     // GPUs no actual backing memory is required.
6847     //
6848     // Note that the Vulkan image is created with or without VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT
6849     // based on whether the memory that will be used to create the image would have
6850     // VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT.  TRANSIENT is provided if there is any memory that
6851     // supports LAZILY_ALLOCATED.  However, based on actual image requirements, such a memory may
6852     // not be suitable for the image.  We don't support such a case, which will result in the
6853     // |initMemory| call below failing.
6854     const bool hasLazilyAllocatedMemory = memoryProperties.hasLazilyAllocatedMemory();
6855 
6856     const VkImageUsageFlags kLazyFlags =
6857         hasLazilyAllocatedMemory ? VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT : 0;
6858     constexpr VkImageUsageFlags kColorFlags =
6859         VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
6860     constexpr VkImageUsageFlags kDepthStencilFlags = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
6861 
6862     const VkImageUsageFlags kMultisampledUsageFlags =
6863         kLazyFlags |
6864         (resolveImage.getAspectFlags() == VK_IMAGE_ASPECT_COLOR_BIT ? kColorFlags
6865                                                                     : kDepthStencilFlags);
6866     const VkImageCreateFlags kMultisampledCreateFlags =
6867         hasProtectedContent ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
6868 
6869     // Multisampled images have only 1 level
6870     constexpr uint32_t kLevelCount = 1;
6871 
6872     ANGLE_TRY(initExternal(context, textureType, multisampleImageExtents,
6873                            resolveImage.getIntendedFormatID(), resolveImage.getActualFormatID(),
6874                            samples, kMultisampledUsageFlags, kMultisampledCreateFlags,
6875                            ImageLayout::Undefined, nullptr, resolveImage.getFirstAllocatedLevel(),
6876                            kLevelCount, resolveImage.getLayerCount(), isRobustResourceInitEnabled,
6877                            hasProtectedContent, YcbcrConversionDesc{}));
6878 
6879     // Remove the emulated format clear from the multisampled image if any.  There is one already
6880     // staged on the resolve image if needed.
6881     removeStagedUpdates(context, getFirstAllocatedLevel(), getLastAllocatedLevel());
6882 
6883     const VkMemoryPropertyFlags kMultisampledMemoryFlags =
6884         VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
6885         (hasLazilyAllocatedMemory ? VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT : 0) |
6886         (hasProtectedContent ? VK_MEMORY_PROPERTY_PROTECTED_BIT : 0);
6887 
6888     // If this ever fails, it can be retried without the LAZILY_ALLOCATED flag (which will probably
6889     // still fail), but ideally that means GL_EXT_multisampled_render_to_texture should not be
6890     // advertized on this platform in the first place.
6891     ANGLE_TRY(initMemoryAndNonZeroFillIfNeeded(
6892         context, hasProtectedContent, memoryProperties, kMultisampledMemoryFlags,
6893         vk::MemoryAllocationType::ImplicitMultisampledRenderToTextureImage));
6894     return angle::Result::Continue;
6895 }
6896 
getAspectFlags() const6897 VkImageAspectFlags ImageHelper::getAspectFlags() const
6898 {
6899     return GetFormatAspectFlags(angle::Format::Get(mActualFormatID));
6900 }
6901 
isCombinedDepthStencilFormat() const6902 bool ImageHelper::isCombinedDepthStencilFormat() const
6903 {
6904     return (getAspectFlags() & kDepthStencilAspects) == kDepthStencilAspects;
6905 }
6906 
getCurrentLayout(Renderer * renderer) const6907 VkImageLayout ImageHelper::getCurrentLayout(Renderer *renderer) const
6908 {
6909     return ConvertImageLayoutToVkImageLayout(renderer, mCurrentLayout);
6910 }
6911 
getLevelExtents(LevelIndex levelVk) const6912 gl::Extents ImageHelper::getLevelExtents(LevelIndex levelVk) const
6913 {
6914     // Level 0 should be the size of the extents, after that every time you increase a level
6915     // you shrink the extents by half.
6916     uint32_t width  = std::max(mExtents.width >> levelVk.get(), 1u);
6917     uint32_t height = std::max(mExtents.height >> levelVk.get(), 1u);
6918     uint32_t depth  = std::max(mExtents.depth >> levelVk.get(), 1u);
6919 
6920     return gl::Extents(width, height, depth);
6921 }
6922 
getLevelExtents2D(LevelIndex levelVk) const6923 gl::Extents ImageHelper::getLevelExtents2D(LevelIndex levelVk) const
6924 {
6925     gl::Extents extents = getLevelExtents(levelVk);
6926     extents.depth       = 1;
6927     return extents;
6928 }
6929 
getRotatedExtents() const6930 const VkExtent3D ImageHelper::getRotatedExtents() const
6931 {
6932     VkExtent3D extents = mExtents;
6933     if (mRotatedAspectRatio)
6934     {
6935         std::swap(extents.width, extents.height);
6936     }
6937     return extents;
6938 }
6939 
getRotatedLevelExtents2D(LevelIndex levelVk) const6940 gl::Extents ImageHelper::getRotatedLevelExtents2D(LevelIndex levelVk) const
6941 {
6942     gl::Extents extents = getLevelExtents2D(levelVk);
6943     if (mRotatedAspectRatio)
6944     {
6945         std::swap(extents.width, extents.height);
6946     }
6947     return extents;
6948 }
6949 
isDepthOrStencil() const6950 bool ImageHelper::isDepthOrStencil() const
6951 {
6952     return getActualFormat().hasDepthOrStencilBits();
6953 }
6954 
setRenderPassUsageFlag(RenderPassUsage flag)6955 void ImageHelper::setRenderPassUsageFlag(RenderPassUsage flag)
6956 {
6957     mRenderPassUsageFlags.set(flag);
6958 }
6959 
clearRenderPassUsageFlag(RenderPassUsage flag)6960 void ImageHelper::clearRenderPassUsageFlag(RenderPassUsage flag)
6961 {
6962     mRenderPassUsageFlags.reset(flag);
6963 }
6964 
resetRenderPassUsageFlags()6965 void ImageHelper::resetRenderPassUsageFlags()
6966 {
6967     mRenderPassUsageFlags.reset();
6968 }
6969 
hasRenderPassUsageFlag(RenderPassUsage flag) const6970 bool ImageHelper::hasRenderPassUsageFlag(RenderPassUsage flag) const
6971 {
6972     return mRenderPassUsageFlags.test(flag);
6973 }
6974 
usedByCurrentRenderPassAsAttachmentAndSampler(RenderPassUsage textureSamplerUsage) const6975 bool ImageHelper::usedByCurrentRenderPassAsAttachmentAndSampler(
6976     RenderPassUsage textureSamplerUsage) const
6977 {
6978     return mRenderPassUsageFlags[RenderPassUsage::RenderTargetAttachment] &&
6979            mRenderPassUsageFlags[textureSamplerUsage];
6980 }
6981 
isReadBarrierNecessary(Renderer * renderer,ImageLayout newLayout) const6982 bool ImageHelper::isReadBarrierNecessary(Renderer *renderer, ImageLayout newLayout) const
6983 {
6984     // If transitioning to a different layout, we need always need a barrier.
6985     if (mCurrentLayout != newLayout)
6986     {
6987         return true;
6988     }
6989 
6990     // RAR (read-after-read) is not a hazard and doesn't require a barrier.
6991     //
6992     // RAW (read-after-write) hazards always require a memory barrier.  This can only happen if the
6993     // layout (same as new layout) is writable which in turn is only possible if the image is
6994     // simultaneously bound for shader write (i.e. the layout is GENERAL or SHARED_PRESENT).
6995     const ImageMemoryBarrierData &layoutData = renderer->getImageMemoryBarrierData(mCurrentLayout);
6996     return HasResourceWriteAccess(layoutData.type);
6997 }
6998 
isReadSubresourceBarrierNecessary(ImageLayout newLayout,gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount) const6999 bool ImageHelper::isReadSubresourceBarrierNecessary(ImageLayout newLayout,
7000                                                     gl::LevelIndex levelStart,
7001                                                     uint32_t levelCount,
7002                                                     uint32_t layerStart,
7003                                                     uint32_t layerCount) const
7004 {
7005     // In case an image has both read and write permissions, the written subresources since the last
7006     // barrier should be checked to avoid RAW and WAR hazards. However, if a layout change is
7007     // necessary regardless, there is no need to check the written subresources.
7008     if (mCurrentLayout != newLayout)
7009     {
7010         return true;
7011     }
7012 
7013     ImageLayerWriteMask layerMask = GetImageLayerWriteMask(layerStart, layerCount);
7014     for (uint32_t levelOffset = 0; levelOffset < levelCount; levelOffset++)
7015     {
7016         uint32_t level = levelStart.get() + levelOffset;
7017         if (areLevelSubresourcesWrittenWithinMaskRange(level, layerMask))
7018         {
7019             return true;
7020         }
7021     }
7022 
7023     return false;
7024 }
7025 
isWriteBarrierNecessary(ImageLayout newLayout,gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount) const7026 bool ImageHelper::isWriteBarrierNecessary(ImageLayout newLayout,
7027                                           gl::LevelIndex levelStart,
7028                                           uint32_t levelCount,
7029                                           uint32_t layerStart,
7030                                           uint32_t layerCount) const
7031 {
7032     // If transitioning to a different layout, we need always need a barrier.
7033     if (mCurrentLayout != newLayout)
7034     {
7035         return true;
7036     }
7037 
7038     if (layerCount >= kMaxParallelLayerWrites)
7039     {
7040         return true;
7041     }
7042 
7043     // If we are writing to the same parts of the image (level/layer), we need a barrier. Otherwise,
7044     // it can be done in parallel.
7045     ImageLayerWriteMask layerMask = GetImageLayerWriteMask(layerStart, layerCount);
7046     for (uint32_t levelOffset = 0; levelOffset < levelCount; levelOffset++)
7047     {
7048         uint32_t level = levelStart.get() + levelOffset;
7049         if (areLevelSubresourcesWrittenWithinMaskRange(level, layerMask))
7050         {
7051             return true;
7052         }
7053     }
7054 
7055     return false;
7056 }
7057 
changeLayoutAndQueue(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,DeviceQueueIndex newDeviceQueueIndex,OutsideRenderPassCommandBuffer * commandBuffer)7058 void ImageHelper::changeLayoutAndQueue(Context *context,
7059                                        VkImageAspectFlags aspectMask,
7060                                        ImageLayout newLayout,
7061                                        DeviceQueueIndex newDeviceQueueIndex,
7062                                        OutsideRenderPassCommandBuffer *commandBuffer)
7063 {
7064     ASSERT(isQueueFamilyChangeNeccesary(newDeviceQueueIndex));
7065     VkSemaphore acquireNextImageSemaphore;
7066     // barrierImpl should detect there is queue switch and fall back to pipelineBarrier properly.
7067     barrierImpl(context, aspectMask, newLayout, newDeviceQueueIndex, nullptr, commandBuffer,
7068                 &acquireNextImageSemaphore);
7069     // SwapChain image should not get here.
7070     ASSERT(acquireNextImageSemaphore == VK_NULL_HANDLE);
7071 }
7072 
acquireFromExternal(Context * context,DeviceQueueIndex externalQueueIndex,DeviceQueueIndex newDeviceQueueIndex,ImageLayout currentLayout,OutsideRenderPassCommandBuffer * commandBuffer)7073 void ImageHelper::acquireFromExternal(Context *context,
7074                                       DeviceQueueIndex externalQueueIndex,
7075                                       DeviceQueueIndex newDeviceQueueIndex,
7076                                       ImageLayout currentLayout,
7077                                       OutsideRenderPassCommandBuffer *commandBuffer)
7078 {
7079     // The image must be newly allocated or have been released to the external
7080     // queue. If this is not the case, it's an application bug, so ASSERT might
7081     // eventually need to change to a warning.
7082     ASSERT(mCurrentLayout == ImageLayout::ExternalPreInitialized ||
7083            mCurrentDeviceQueueIndex.familyIndex() == externalQueueIndex.familyIndex());
7084 
7085     mCurrentLayout           = currentLayout;
7086     mCurrentDeviceQueueIndex = externalQueueIndex;
7087     mIsReleasedToExternal    = false;
7088 
7089     // Only change the layout and queue if the layout is anything by Undefined.  If it is undefined,
7090     // leave it to transition out as the image is used later.
7091     if (currentLayout != ImageLayout::Undefined)
7092     {
7093         changeLayoutAndQueue(context, getAspectFlags(), mCurrentLayout, newDeviceQueueIndex,
7094                              commandBuffer);
7095     }
7096 
7097     // It is unknown how the external has modified the image, so assume every subresource has
7098     // defined content.  That is unless the layout is Undefined.
7099     if (currentLayout == ImageLayout::Undefined)
7100     {
7101         setEntireContentUndefined();
7102     }
7103     else
7104     {
7105         setEntireContentDefined();
7106     }
7107 }
7108 
releaseToExternal(Context * context,DeviceQueueIndex externalQueueIndex,ImageLayout desiredLayout,OutsideRenderPassCommandBuffer * commandBuffer)7109 void ImageHelper::releaseToExternal(Context *context,
7110                                     DeviceQueueIndex externalQueueIndex,
7111                                     ImageLayout desiredLayout,
7112                                     OutsideRenderPassCommandBuffer *commandBuffer)
7113 {
7114     ASSERT(!mIsReleasedToExternal);
7115 
7116     // A layout change is unnecessary if the image that was previously acquired was never used by
7117     // GL!
7118     if (mCurrentDeviceQueueIndex.familyIndex() != externalQueueIndex.familyIndex() ||
7119         mCurrentLayout != desiredLayout)
7120     {
7121         changeLayoutAndQueue(context, getAspectFlags(), desiredLayout, externalQueueIndex,
7122                              commandBuffer);
7123     }
7124 
7125     mIsReleasedToExternal = true;
7126 }
7127 
isReleasedToExternal() const7128 bool ImageHelper::isReleasedToExternal() const
7129 {
7130     return mIsReleasedToExternal;
7131 }
7132 
toVkLevel(gl::LevelIndex levelIndexGL) const7133 LevelIndex ImageHelper::toVkLevel(gl::LevelIndex levelIndexGL) const
7134 {
7135     return gl_vk::GetLevelIndex(levelIndexGL, mFirstAllocatedLevel);
7136 }
7137 
toGLLevel(LevelIndex levelIndexVk) const7138 gl::LevelIndex ImageHelper::toGLLevel(LevelIndex levelIndexVk) const
7139 {
7140     return vk_gl::GetLevelIndex(levelIndexVk, mFirstAllocatedLevel);
7141 }
7142 
initImageMemoryBarrierStruct(Renderer * renderer,VkImageAspectFlags aspectMask,ImageLayout newLayout,uint32_t newQueueFamilyIndex,VkImageMemoryBarrier * imageMemoryBarrier) const7143 ANGLE_INLINE void ImageHelper::initImageMemoryBarrierStruct(
7144     Renderer *renderer,
7145     VkImageAspectFlags aspectMask,
7146     ImageLayout newLayout,
7147     uint32_t newQueueFamilyIndex,
7148     VkImageMemoryBarrier *imageMemoryBarrier) const
7149 {
7150     ASSERT(mCurrentDeviceQueueIndex.familyIndex() != QueueFamily::kInvalidIndex);
7151     ASSERT(newQueueFamilyIndex != QueueFamily::kInvalidIndex);
7152 
7153     const ImageMemoryBarrierData &transitionFrom =
7154         renderer->getImageMemoryBarrierData(mCurrentLayout);
7155     const ImageMemoryBarrierData &transitionTo = renderer->getImageMemoryBarrierData(newLayout);
7156 
7157     imageMemoryBarrier->sType         = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
7158     imageMemoryBarrier->srcAccessMask = transitionFrom.srcAccessMask;
7159     imageMemoryBarrier->dstAccessMask = transitionTo.dstAccessMask;
7160     imageMemoryBarrier->oldLayout     = ConvertImageLayoutToVkImageLayout(renderer, mCurrentLayout);
7161     imageMemoryBarrier->newLayout     = ConvertImageLayoutToVkImageLayout(renderer, newLayout);
7162     imageMemoryBarrier->srcQueueFamilyIndex = mCurrentDeviceQueueIndex.familyIndex();
7163     imageMemoryBarrier->dstQueueFamilyIndex = newQueueFamilyIndex;
7164     imageMemoryBarrier->image               = mImage.getHandle();
7165 
7166     // Transition the whole resource.
7167     imageMemoryBarrier->subresourceRange.aspectMask     = aspectMask;
7168     imageMemoryBarrier->subresourceRange.baseMipLevel   = 0;
7169     imageMemoryBarrier->subresourceRange.levelCount     = mLevelCount;
7170     imageMemoryBarrier->subresourceRange.baseArrayLayer = 0;
7171     imageMemoryBarrier->subresourceRange.layerCount     = mLayerCount;
7172 }
7173 
7174 // Generalized to accept both "primary" and "secondary" command buffers.
7175 template <typename CommandBufferT>
barrierImpl(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,DeviceQueueIndex newDeviceQueueIndex,RefCountedEventCollector * eventCollector,CommandBufferT * commandBuffer,VkSemaphore * acquireNextImageSemaphoreOut)7176 void ImageHelper::barrierImpl(Context *context,
7177                               VkImageAspectFlags aspectMask,
7178                               ImageLayout newLayout,
7179                               DeviceQueueIndex newDeviceQueueIndex,
7180                               RefCountedEventCollector *eventCollector,
7181                               CommandBufferT *commandBuffer,
7182                               VkSemaphore *acquireNextImageSemaphoreOut)
7183 {
7184     Renderer *renderer = context->getRenderer();
7185     // mCurrentEvent must be invalid if useVkEventForImageBarrieris disabled.
7186     ASSERT(context->getRenderer()->getFeatures().useVkEventForImageBarrier.enabled ||
7187            !mCurrentEvent.valid());
7188 
7189     // Release the ANI semaphore to caller to add to the command submission.
7190     *acquireNextImageSemaphoreOut = mAcquireNextImageSemaphore.release();
7191 
7192     if (mCurrentLayout == ImageLayout::SharedPresent)
7193     {
7194         // For now we always use pipelineBarrier for singlebuffer mode. We could use event here in
7195         // future.
7196         mCurrentEvent.release(context);
7197 
7198         const ImageMemoryBarrierData &transition =
7199             renderer->getImageMemoryBarrierData(mCurrentLayout);
7200         VkMemoryBarrier memoryBarrier = {};
7201         memoryBarrier.sType           = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
7202         memoryBarrier.srcAccessMask   = transition.srcAccessMask;
7203         memoryBarrier.dstAccessMask   = transition.dstAccessMask;
7204 
7205         commandBuffer->memoryBarrier(transition.srcStageMask, transition.dstStageMask,
7206                                      memoryBarrier);
7207         return;
7208     }
7209 
7210     // Make sure we never transition out of SharedPresent
7211     ASSERT(mCurrentLayout != ImageLayout::SharedPresent || newLayout == ImageLayout::SharedPresent);
7212 
7213     const ImageMemoryBarrierData &transitionFrom =
7214         renderer->getImageMemoryBarrierData(mCurrentLayout);
7215     const ImageMemoryBarrierData &transitionTo = renderer->getImageMemoryBarrierData(newLayout);
7216 
7217     VkImageMemoryBarrier imageMemoryBarrier = {};
7218     initImageMemoryBarrierStruct(renderer, aspectMask, newLayout, newDeviceQueueIndex.familyIndex(),
7219                                  &imageMemoryBarrier);
7220 
7221     VkPipelineStageFlags dstStageMask = transitionTo.dstStageMask;
7222 
7223     // Fallback to pipelineBarrier if there is no event tracking image.
7224     // VkCmdWaitEvent requires the srcQueueFamilyIndex and dstQueueFamilyIndex members of any
7225     // element of pBufferMemoryBarriers or pImageMemoryBarriers must be equal
7226     // (VUID-vkCmdWaitEvents-srcQueueFamilyIndex-02803).
7227     BarrierType barrierType =
7228         mCurrentEvent.valid() && mCurrentDeviceQueueIndex == newDeviceQueueIndex
7229             ? BarrierType::Event
7230             : BarrierType::Pipeline;
7231 
7232     if (barrierType == BarrierType::Event)
7233     {
7234         // If there is an event, we use the waitEvent to do layout change. Once we have waited, the
7235         // event gets garbage collected (which is GPU completion tracked) to avoid waited again in
7236         // future. We always use DstStageMask since that is what setEvent used and
7237         // VUID-vkCmdWaitEvents-srcStageMask-01158 requires they must match.
7238         VkPipelineStageFlags srcStageMask =
7239             context->getRenderer()->getEventPipelineStageMask(mCurrentEvent);
7240         commandBuffer->imageWaitEvent(mCurrentEvent.getEvent().getHandle(), srcStageMask,
7241                                       dstStageMask, imageMemoryBarrier);
7242         eventCollector->emplace_back(std::move(mCurrentEvent));
7243     }
7244     else
7245     {
7246         // There might be other shaderRead operations there other than the current layout.
7247         VkPipelineStageFlags srcStageMask = transitionFrom.srcStageMask;
7248         if (mCurrentShaderReadStageMask)
7249         {
7250             srcStageMask |= mCurrentShaderReadStageMask;
7251             mCurrentShaderReadStageMask  = 0;
7252             mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
7253         }
7254         commandBuffer->imageBarrier(srcStageMask, dstStageMask, imageMemoryBarrier);
7255         // We use pipelineBarrier here, no needs to wait for events any more.
7256         mCurrentEvent.release(context);
7257     }
7258 
7259     mCurrentLayout           = newLayout;
7260     mCurrentDeviceQueueIndex = newDeviceQueueIndex;
7261     resetSubresourcesWrittenSinceBarrier();
7262 
7263     // We must release the event so that new event will be created and added. If we did not add new
7264     // event, because mCurrentEvent have been released, next barrier will automatically fallback to
7265     // pipelineBarrier. Otherwise if we keep mCurrentEvent here we may accidentally end up waiting
7266     // for an old event which creates sync hazard.
7267     ASSERT(!mCurrentEvent.valid());
7268 }
7269 
7270 template void ImageHelper::barrierImpl<priv::CommandBuffer>(
7271     Context *context,
7272     VkImageAspectFlags aspectMask,
7273     ImageLayout newLayout,
7274     DeviceQueueIndex newDeviceQueueIndex,
7275     RefCountedEventCollector *eventCollector,
7276     priv::CommandBuffer *commandBuffer,
7277     VkSemaphore *acquireNextImageSemaphoreOut);
7278 
setSubresourcesWrittenSinceBarrier(gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount)7279 void ImageHelper::setSubresourcesWrittenSinceBarrier(gl::LevelIndex levelStart,
7280                                                      uint32_t levelCount,
7281                                                      uint32_t layerStart,
7282                                                      uint32_t layerCount)
7283 {
7284     for (uint32_t levelOffset = 0; levelOffset < levelCount; levelOffset++)
7285     {
7286         uint32_t level = levelStart.get() + levelOffset;
7287         if (layerCount >= kMaxParallelLayerWrites)
7288         {
7289             mSubresourcesWrittenSinceBarrier[level].set();
7290         }
7291         else
7292         {
7293             ImageLayerWriteMask layerMask = GetImageLayerWriteMask(layerStart, layerCount);
7294             mSubresourcesWrittenSinceBarrier[level] |= layerMask;
7295         }
7296     }
7297 }
7298 
resetSubresourcesWrittenSinceBarrier()7299 void ImageHelper::resetSubresourcesWrittenSinceBarrier()
7300 {
7301     for (auto &layerWriteMask : mSubresourcesWrittenSinceBarrier)
7302     {
7303         layerWriteMask.reset();
7304     }
7305 }
7306 
recordWriteBarrier(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,OutsideRenderPassCommandBufferHelper * commands)7307 void ImageHelper::recordWriteBarrier(Context *context,
7308                                      VkImageAspectFlags aspectMask,
7309                                      ImageLayout newLayout,
7310                                      gl::LevelIndex levelStart,
7311                                      uint32_t levelCount,
7312                                      uint32_t layerStart,
7313                                      uint32_t layerCount,
7314                                      OutsideRenderPassCommandBufferHelper *commands)
7315 {
7316     if (isWriteBarrierNecessary(newLayout, levelStart, levelCount, layerStart, layerCount))
7317     {
7318         ASSERT(!mCurrentEvent.valid() || !commands->hasSetEventPendingFlush(mCurrentEvent));
7319         VkSemaphore acquireNextImageSemaphore;
7320         barrierImpl(context, aspectMask, newLayout, context->getDeviceQueueIndex(),
7321                     commands->getRefCountedEventCollector(), &commands->getCommandBuffer(),
7322                     &acquireNextImageSemaphore);
7323 
7324         if (acquireNextImageSemaphore != VK_NULL_HANDLE)
7325         {
7326             commands->setAcquireNextImageSemaphore(acquireNextImageSemaphore);
7327         }
7328     }
7329 
7330     setSubresourcesWrittenSinceBarrier(levelStart, levelCount, layerStart, layerCount);
7331 }
7332 
recordReadSubresourceBarrier(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,OutsideRenderPassCommandBufferHelper * commands)7333 void ImageHelper::recordReadSubresourceBarrier(Context *context,
7334                                                VkImageAspectFlags aspectMask,
7335                                                ImageLayout newLayout,
7336                                                gl::LevelIndex levelStart,
7337                                                uint32_t levelCount,
7338                                                uint32_t layerStart,
7339                                                uint32_t layerCount,
7340                                                OutsideRenderPassCommandBufferHelper *commands)
7341 {
7342     // This barrier is used for an image with both read/write permissions, including during mipmap
7343     // generation and self-copy.
7344     if (isReadSubresourceBarrierNecessary(newLayout, levelStart, levelCount, layerStart,
7345                                           layerCount))
7346     {
7347         ASSERT(!mCurrentEvent.valid() || !commands->hasSetEventPendingFlush(mCurrentEvent));
7348         VkSemaphore acquireNextImageSemaphore;
7349         barrierImpl(context, aspectMask, newLayout, context->getDeviceQueueIndex(),
7350                     commands->getRefCountedEventCollector(), &commands->getCommandBuffer(),
7351                     &acquireNextImageSemaphore);
7352 
7353         if (acquireNextImageSemaphore != VK_NULL_HANDLE)
7354         {
7355             commands->setAcquireNextImageSemaphore(acquireNextImageSemaphore);
7356         }
7357     }
7358 
7359     // Levels/layers being read from are also registered to avoid RAW and WAR hazards.
7360     setSubresourcesWrittenSinceBarrier(levelStart, levelCount, layerStart, layerCount);
7361 }
7362 
recordReadBarrier(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,OutsideRenderPassCommandBufferHelper * commands)7363 void ImageHelper::recordReadBarrier(Context *context,
7364                                     VkImageAspectFlags aspectMask,
7365                                     ImageLayout newLayout,
7366                                     OutsideRenderPassCommandBufferHelper *commands)
7367 {
7368     if (!isReadBarrierNecessary(context->getRenderer(), newLayout))
7369     {
7370         return;
7371     }
7372 
7373     ASSERT(!mCurrentEvent.valid() || !commands->hasSetEventPendingFlush(mCurrentEvent));
7374     VkSemaphore acquireNextImageSemaphore;
7375     barrierImpl(context, aspectMask, newLayout, context->getDeviceQueueIndex(),
7376                 commands->getRefCountedEventCollector(), &commands->getCommandBuffer(),
7377                 &acquireNextImageSemaphore);
7378 
7379     if (acquireNextImageSemaphore != VK_NULL_HANDLE)
7380     {
7381         commands->setAcquireNextImageSemaphore(acquireNextImageSemaphore);
7382     }
7383 }
7384 
updateLayoutAndBarrier(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,BarrierType barrierType,const QueueSerial & queueSerial,PipelineBarrierArray * pipelineBarriers,EventBarrierArray * eventBarriers,RefCountedEventCollector * eventCollector,VkSemaphore * semaphoreOut)7385 void ImageHelper::updateLayoutAndBarrier(Context *context,
7386                                          VkImageAspectFlags aspectMask,
7387                                          ImageLayout newLayout,
7388                                          BarrierType barrierType,
7389                                          const QueueSerial &queueSerial,
7390                                          PipelineBarrierArray *pipelineBarriers,
7391                                          EventBarrierArray *eventBarriers,
7392                                          RefCountedEventCollector *eventCollector,
7393                                          VkSemaphore *semaphoreOut)
7394 {
7395     Renderer *renderer = context->getRenderer();
7396     ASSERT(queueSerial.valid());
7397     ASSERT(!mBarrierQueueSerial.valid() ||
7398            mBarrierQueueSerial.getIndex() != queueSerial.getIndex() ||
7399            mBarrierQueueSerial.getSerial() <= queueSerial.getSerial());
7400     ASSERT(renderer->getImageMemoryBarrierData(newLayout).barrierIndex !=
7401            PipelineStage::InvalidEnum);
7402     // mCurrentEvent must be invalid if useVkEventForImageBarrieris disabled.
7403     ASSERT(renderer->getFeatures().useVkEventForImageBarrier.enabled || !mCurrentEvent.valid());
7404 
7405     if (mCurrentDeviceQueueIndex != context->getDeviceQueueIndex())
7406     {
7407         // Fallback to pipelineBarrier if the VkQueue has changed.
7408         barrierType              = BarrierType::Pipeline;
7409         mCurrentDeviceQueueIndex = context->getDeviceQueueIndex();
7410     }
7411     else if (!mCurrentEvent.valid())
7412     {
7413         // Fallback to pipelineBarrier if there is no event tracking image.
7414         barrierType = BarrierType::Pipeline;
7415     }
7416 
7417     // Once you transition to ImageLayout::SharedPresent, you never transition out of it.
7418     if (mCurrentLayout == ImageLayout::SharedPresent)
7419     {
7420         newLayout = ImageLayout::SharedPresent;
7421     }
7422 
7423     if (newLayout == mCurrentLayout)
7424     {
7425         if (mBarrierQueueSerial == queueSerial)
7426         {
7427             ASSERT(!mAcquireNextImageSemaphore.valid());
7428             // If there is no layout change and the previous layout change happened in the same
7429             // render pass, then early out do nothing. This can happen when the same image is
7430             // attached to the multiple attachments of the framebuffer.
7431             return;
7432         }
7433 
7434         const ImageMemoryBarrierData &layoutData =
7435             renderer->getImageMemoryBarrierData(mCurrentLayout);
7436         // RAR is not a hazard and doesn't require a barrier, especially as the image layout hasn't
7437         // changed.  The following asserts that such a barrier is not attempted.
7438         ASSERT(HasResourceWriteAccess(layoutData.type));
7439 
7440         // No layout change, only memory barrier is required
7441         if (barrierType == BarrierType::Event)
7442         {
7443             eventBarriers->addMemoryEvent(renderer, mCurrentEvent, layoutData.dstStageMask,
7444                                           layoutData.dstAccessMask);
7445             // Garbage collect the event, which tracks GPU completion automatically.
7446             eventCollector->emplace_back(std::move(mCurrentEvent));
7447         }
7448         else
7449         {
7450             pipelineBarriers->mergeMemoryBarrier(layoutData.barrierIndex, layoutData.dstStageMask,
7451                                                  layoutData.dstStageMask, layoutData.srcAccessMask,
7452                                                  layoutData.dstAccessMask);
7453 
7454             // Release it. No need to garbage collect since we did not use the event here. ALl
7455             // previous use of event should garbage tracked already.
7456             mCurrentEvent.release(context);
7457         }
7458         mBarrierQueueSerial = queueSerial;
7459     }
7460     else
7461     {
7462         const ImageMemoryBarrierData &transitionFrom =
7463             renderer->getImageMemoryBarrierData(mCurrentLayout);
7464         const ImageMemoryBarrierData &transitionTo = renderer->getImageMemoryBarrierData(newLayout);
7465         VkPipelineStageFlags srcStageMask          = transitionFrom.srcStageMask;
7466         VkPipelineStageFlags dstStageMask          = transitionTo.dstStageMask;
7467 
7468         if (transitionFrom.layout == transitionTo.layout && IsShaderReadOnlyLayout(transitionTo) &&
7469             mBarrierQueueSerial == queueSerial)
7470         {
7471             // If we are switching between different shader stage reads of the same render pass,
7472             // then there is no actual layout change or access type change. We only need a barrier
7473             // if we are making a read that is from a new stage. Also note that we do barrier
7474             // against previous non-shaderRead layout. We do not barrier between one shaderRead and
7475             // another shaderRead.
7476             bool isNewReadStage = (mCurrentShaderReadStageMask & dstStageMask) != dstStageMask;
7477             if (!isNewReadStage)
7478             {
7479                 ASSERT(!mAcquireNextImageSemaphore.valid());
7480                 return;
7481             }
7482 
7483             ASSERT(!mLastNonShaderReadOnlyEvent.valid() ||
7484                    mLastNonShaderReadOnlyEvent.getEventStage() ==
7485                        GetImageLayoutEventStage(mLastNonShaderReadOnlyLayout));
7486             if (!mLastNonShaderReadOnlyEvent.valid())
7487             {
7488                 barrierType = BarrierType::Pipeline;
7489             }
7490 
7491             if (barrierType == BarrierType::Event)
7492             {
7493                 // If we already inserted a barrier in the same renderPass, we has to add
7494                 // the new stage mask to the existing VkCmdWaitEvent call, otherwise VVL will
7495                 // complain.
7496                 eventBarriers->addAdditionalStageAccess(mLastNonShaderReadOnlyEvent, dstStageMask,
7497                                                         transitionTo.dstAccessMask);
7498                 eventCollector->emplace_back(mLastNonShaderReadOnlyEvent);
7499             }
7500             else
7501             {
7502                 const ImageMemoryBarrierData &layoutData =
7503                     renderer->getImageMemoryBarrierData(mLastNonShaderReadOnlyLayout);
7504                 pipelineBarriers->mergeMemoryBarrier(
7505                     transitionTo.barrierIndex, layoutData.srcStageMask, dstStageMask,
7506                     layoutData.srcAccessMask, transitionTo.dstAccessMask);
7507             }
7508 
7509             mBarrierQueueSerial = queueSerial;
7510             // Accumulate new read stage.
7511             mCurrentShaderReadStageMask |= dstStageMask;
7512 
7513             // Since we used pipelineBarrier, release the event now to avoid wait for the
7514             // event again.
7515             if (mCurrentEvent.valid())
7516             {
7517                 eventCollector->emplace_back(std::move(mCurrentEvent));
7518             }
7519         }
7520         else
7521         {
7522             VkImageMemoryBarrier imageMemoryBarrier = {};
7523             initImageMemoryBarrierStruct(renderer, aspectMask, newLayout,
7524                                          context->getDeviceQueueIndex().familyIndex(),
7525                                          &imageMemoryBarrier);
7526 
7527             if (transitionFrom.layout == transitionTo.layout &&
7528                 IsShaderReadOnlyLayout(transitionTo))
7529             {
7530                 // If we are transiting within shaderReadOnly layout, i.e. reading from different
7531                 // shader stages, VkEvent can't handle this right now. In order for VkEvent to
7532                 // handle this properly we have to wait for the previous shaderReadOnly layout
7533                 // transition event and add a new memoryBarrier. But we may have lost that event
7534                 // already if it has been used in a new render pass (because we have to update the
7535                 // event even if there is no barrier needed). To workaround this issue we fall back
7536                 // to pipelineBarrier for now.
7537                 barrierType = BarrierType::Pipeline;
7538             }
7539             else if (mBarrierQueueSerial == queueSerial)
7540             {
7541                 // If we already inserted a barrier in this render pass, force to use
7542                 // pipelineBarrier. Otherwise we will end up inserting a VkCmdWaitEvent that has not
7543                 // been set (See https://issuetracker.google.com/333419317 for example).
7544                 barrierType = BarrierType::Pipeline;
7545             }
7546 
7547             // if we transition from shaderReadOnly, we must add in stashed shader stage masks since
7548             // there might be outstanding shader reads from stages other than current layout. We do
7549             // not insert barrier between one shaderRead to another shaderRead
7550             if (mCurrentShaderReadStageMask)
7551             {
7552                 if ((mCurrentShaderReadStageMask & srcStageMask) != mCurrentShaderReadStageMask)
7553                 {
7554                     // mCurrentShaderReadStageMask has more bits than srcStageMask. This means it
7555                     // has been used by more than one shader stage in the same render pass. These
7556                     // two usages are tracked by two different ImageLayout, even though underline
7557                     // VkImageLayout is the same. This means two different RefCountedEvents since
7558                     // each RefCountedEvent is associated with one ImageLayout. When we transit out
7559                     // of this layout, we must wait for all reads to finish. But Right now
7560                     // ImageHelper only keep track of the last read. To workaround this problem we
7561                     // use pipelineBarrier in this case.
7562                     barrierType = BarrierType::Pipeline;
7563                     srcStageMask |= mCurrentShaderReadStageMask;
7564                 }
7565                 mCurrentShaderReadStageMask  = 0;
7566                 mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
7567                 if (mLastNonShaderReadOnlyEvent.valid())
7568                 {
7569                     mLastNonShaderReadOnlyEvent.release(context);
7570                 }
7571             }
7572 
7573             // If we are transition into shaderRead layout, remember the last
7574             // non-shaderRead layout here.
7575             const bool isShaderReadOnly = IsShaderReadOnlyLayout(transitionTo);
7576             if (isShaderReadOnly)
7577             {
7578                 mLastNonShaderReadOnlyEvent.release(context);
7579                 mLastNonShaderReadOnlyLayout = mCurrentLayout;
7580                 mCurrentShaderReadStageMask  = dstStageMask;
7581             }
7582 
7583             if (barrierType == BarrierType::Event)
7584             {
7585                 eventBarriers->addImageEvent(renderer, mCurrentEvent, dstStageMask,
7586                                              imageMemoryBarrier);
7587                 if (isShaderReadOnly)
7588                 {
7589                     mLastNonShaderReadOnlyEvent = mCurrentEvent;
7590                 }
7591                 eventCollector->emplace_back(std::move(mCurrentEvent));
7592             }
7593             else
7594             {
7595                 pipelineBarriers->mergeImageBarrier(transitionTo.barrierIndex, srcStageMask,
7596                                                     dstStageMask, imageMemoryBarrier);
7597                 mCurrentEvent.release(context);
7598             }
7599 
7600             mBarrierQueueSerial = queueSerial;
7601         }
7602         mCurrentLayout = newLayout;
7603     }
7604 
7605     *semaphoreOut = mAcquireNextImageSemaphore.release();
7606     // We must release the event so that new event will be created and added. If we did not add new
7607     // event, because mCurrentEvent have been released, next barrier will automatically fallback to
7608     // pipelineBarrier. Otherwise if we keep mCurrentEvent here we may accidentally end up waiting
7609     // for an old event which creates sync hazard.
7610     ASSERT(!mCurrentEvent.valid());
7611 }
7612 
setCurrentRefCountedEvent(Context * context,EventMaps & eventMaps)7613 void ImageHelper::setCurrentRefCountedEvent(Context *context, EventMaps &eventMaps)
7614 {
7615     ASSERT(context->getRenderer()->getFeatures().useVkEventForImageBarrier.enabled);
7616 
7617     // If there is already an event, release it first.
7618     mCurrentEvent.release(context);
7619 
7620     // Create the event if we have not yet so. Otherwise just use the already created event. This
7621     // means all images used in the same render pass that has the same layout will be tracked by the
7622     // same event.
7623     EventStage stage = GetImageLayoutEventStage(mCurrentLayout);
7624     if (!eventMaps.map[stage].valid())
7625     {
7626         if (!eventMaps.map[stage].init(context, stage))
7627         {
7628             // If VkEvent creation fail, we fallback to pipelineBarrier
7629             return;
7630         }
7631         eventMaps.mask.set(stage);
7632     }
7633 
7634     // Copy the event to mCurrentEvent so that we can wait for it in future. This will add extra
7635     // refcount to the underlying VkEvent.
7636     mCurrentEvent = eventMaps.map[stage];
7637 }
7638 
clearColor(Renderer * renderer,const VkClearColorValue & color,LevelIndex baseMipLevelVk,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount,OutsideRenderPassCommandBuffer * commandBuffer)7639 void ImageHelper::clearColor(Renderer *renderer,
7640                              const VkClearColorValue &color,
7641                              LevelIndex baseMipLevelVk,
7642                              uint32_t levelCount,
7643                              uint32_t baseArrayLayer,
7644                              uint32_t layerCount,
7645                              OutsideRenderPassCommandBuffer *commandBuffer)
7646 {
7647     ASSERT(valid());
7648 
7649     ASSERT(mCurrentLayout == ImageLayout::TransferDst ||
7650            mCurrentLayout == ImageLayout::SharedPresent);
7651 
7652     VkImageSubresourceRange range = {};
7653     range.aspectMask              = VK_IMAGE_ASPECT_COLOR_BIT;
7654     range.baseMipLevel            = baseMipLevelVk.get();
7655     range.levelCount              = levelCount;
7656     range.baseArrayLayer          = baseArrayLayer;
7657     range.layerCount              = layerCount;
7658 
7659     if (mImageType == VK_IMAGE_TYPE_3D)
7660     {
7661         ASSERT(baseArrayLayer == 0);
7662         ASSERT(layerCount == 1 ||
7663                layerCount == static_cast<uint32_t>(getLevelExtents(baseMipLevelVk).depth));
7664         range.layerCount = 1;
7665     }
7666 
7667     commandBuffer->clearColorImage(mImage, getCurrentLayout(renderer), color, 1, &range);
7668 }
7669 
clearDepthStencil(Renderer * renderer,VkImageAspectFlags clearAspectFlags,const VkClearDepthStencilValue & depthStencil,LevelIndex baseMipLevelVk,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount,OutsideRenderPassCommandBuffer * commandBuffer)7670 void ImageHelper::clearDepthStencil(Renderer *renderer,
7671                                     VkImageAspectFlags clearAspectFlags,
7672                                     const VkClearDepthStencilValue &depthStencil,
7673                                     LevelIndex baseMipLevelVk,
7674                                     uint32_t levelCount,
7675                                     uint32_t baseArrayLayer,
7676                                     uint32_t layerCount,
7677                                     OutsideRenderPassCommandBuffer *commandBuffer)
7678 {
7679     ASSERT(valid());
7680 
7681     ASSERT(mCurrentLayout == ImageLayout::TransferDst);
7682 
7683     VkImageSubresourceRange range = {};
7684     range.aspectMask              = clearAspectFlags;
7685     range.baseMipLevel            = baseMipLevelVk.get();
7686     range.levelCount              = levelCount;
7687     range.baseArrayLayer          = baseArrayLayer;
7688     range.layerCount              = layerCount;
7689 
7690     if (mImageType == VK_IMAGE_TYPE_3D)
7691     {
7692         ASSERT(baseArrayLayer == 0);
7693         ASSERT(layerCount == 1 ||
7694                layerCount == static_cast<uint32_t>(getLevelExtents(baseMipLevelVk).depth));
7695         range.layerCount = 1;
7696     }
7697 
7698     commandBuffer->clearDepthStencilImage(mImage, getCurrentLayout(renderer), depthStencil, 1,
7699                                           &range);
7700 }
7701 
clear(Renderer * renderer,VkImageAspectFlags aspectFlags,const VkClearValue & value,LevelIndex mipLevel,uint32_t baseArrayLayer,uint32_t layerCount,OutsideRenderPassCommandBuffer * commandBuffer)7702 void ImageHelper::clear(Renderer *renderer,
7703                         VkImageAspectFlags aspectFlags,
7704                         const VkClearValue &value,
7705                         LevelIndex mipLevel,
7706                         uint32_t baseArrayLayer,
7707                         uint32_t layerCount,
7708                         OutsideRenderPassCommandBuffer *commandBuffer)
7709 {
7710     const angle::Format &angleFormat = getActualFormat();
7711     bool isDepthStencil              = angleFormat.hasDepthOrStencilBits();
7712 
7713     if (isDepthStencil)
7714     {
7715         clearDepthStencil(renderer, aspectFlags, value.depthStencil, mipLevel, 1, baseArrayLayer,
7716                           layerCount, commandBuffer);
7717     }
7718     else
7719     {
7720         ASSERT(!angleFormat.isBlock);
7721 
7722         clearColor(renderer, value.color, mipLevel, 1, baseArrayLayer, layerCount, commandBuffer);
7723     }
7724 }
7725 
clearEmulatedChannels(ContextVk * contextVk,VkColorComponentFlags colorMaskFlags,const VkClearValue & value,LevelIndex mipLevel,uint32_t baseArrayLayer,uint32_t layerCount)7726 angle::Result ImageHelper::clearEmulatedChannels(ContextVk *contextVk,
7727                                                  VkColorComponentFlags colorMaskFlags,
7728                                                  const VkClearValue &value,
7729                                                  LevelIndex mipLevel,
7730                                                  uint32_t baseArrayLayer,
7731                                                  uint32_t layerCount)
7732 {
7733     const gl::Extents levelExtents = getLevelExtents(mipLevel);
7734 
7735     if (levelExtents.depth > 1)
7736     {
7737         // Currently not implemented for 3D textures
7738         UNIMPLEMENTED();
7739         return angle::Result::Continue;
7740     }
7741 
7742     UtilsVk::ClearImageParameters params = {};
7743     params.clearArea                     = {0, 0, levelExtents.width, levelExtents.height};
7744     params.dstMip                        = mipLevel;
7745     params.colorMaskFlags                = colorMaskFlags;
7746     params.colorClearValue               = value.color;
7747 
7748     for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex)
7749     {
7750         params.dstLayer = baseArrayLayer + layerIndex;
7751 
7752         ANGLE_TRY(contextVk->getUtils().clearImage(contextVk, this, params));
7753     }
7754 
7755     return angle::Result::Continue;
7756 }
7757 
7758 // static
Copy(Renderer * renderer,ImageHelper * srcImage,ImageHelper * dstImage,const gl::Offset & srcOffset,const gl::Offset & dstOffset,const gl::Extents & copySize,const VkImageSubresourceLayers & srcSubresource,const VkImageSubresourceLayers & dstSubresource,OutsideRenderPassCommandBuffer * commandBuffer)7759 void ImageHelper::Copy(Renderer *renderer,
7760                        ImageHelper *srcImage,
7761                        ImageHelper *dstImage,
7762                        const gl::Offset &srcOffset,
7763                        const gl::Offset &dstOffset,
7764                        const gl::Extents &copySize,
7765                        const VkImageSubresourceLayers &srcSubresource,
7766                        const VkImageSubresourceLayers &dstSubresource,
7767                        OutsideRenderPassCommandBuffer *commandBuffer)
7768 {
7769     ASSERT(commandBuffer->valid() && srcImage->valid() && dstImage->valid());
7770 
7771     ASSERT(srcImage->getCurrentLayout(renderer) == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
7772     ASSERT(dstImage->getCurrentLayout(renderer) == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
7773 
7774     VkImageCopy region    = {};
7775     region.srcSubresource = srcSubresource;
7776     region.srcOffset.x    = srcOffset.x;
7777     region.srcOffset.y    = srcOffset.y;
7778     region.srcOffset.z    = srcOffset.z;
7779     region.dstSubresource = dstSubresource;
7780     region.dstOffset.x    = dstOffset.x;
7781     region.dstOffset.y    = dstOffset.y;
7782     region.dstOffset.z    = dstOffset.z;
7783     region.extent.width   = copySize.width;
7784     region.extent.height  = copySize.height;
7785     region.extent.depth   = copySize.depth;
7786 
7787     commandBuffer->copyImage(srcImage->getImage(), srcImage->getCurrentLayout(renderer),
7788                              dstImage->getImage(), dstImage->getCurrentLayout(renderer), 1,
7789                              &region);
7790 }
7791 
7792 // 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)7793 angle::Result ImageHelper::CopyImageSubData(const gl::Context *context,
7794                                             ImageHelper *srcImage,
7795                                             GLint srcLevel,
7796                                             GLint srcX,
7797                                             GLint srcY,
7798                                             GLint srcZ,
7799                                             ImageHelper *dstImage,
7800                                             GLint dstLevel,
7801                                             GLint dstX,
7802                                             GLint dstY,
7803                                             GLint dstZ,
7804                                             GLsizei srcWidth,
7805                                             GLsizei srcHeight,
7806                                             GLsizei srcDepth)
7807 {
7808     ContextVk *contextVk = GetImpl(context);
7809     Renderer *renderer   = contextVk->getRenderer();
7810 
7811     VkImageTiling srcTilingMode  = srcImage->getTilingMode();
7812     VkImageTiling destTilingMode = dstImage->getTilingMode();
7813 
7814     const gl::LevelIndex srcLevelGL = gl::LevelIndex(srcLevel);
7815     const gl::LevelIndex dstLevelGL = gl::LevelIndex(dstLevel);
7816 
7817     if (CanCopyWithTransferForCopyImage(renderer, srcImage, srcTilingMode, dstImage,
7818                                         destTilingMode))
7819     {
7820         bool isSrc3D                         = srcImage->getType() == VK_IMAGE_TYPE_3D;
7821         bool isDst3D                         = dstImage->getType() == VK_IMAGE_TYPE_3D;
7822         const VkImageAspectFlags aspectFlags = srcImage->getAspectFlags();
7823 
7824         ASSERT(srcImage->getAspectFlags() == dstImage->getAspectFlags());
7825 
7826         VkImageCopy region = {};
7827 
7828         region.srcSubresource.aspectMask     = aspectFlags;
7829         region.srcSubresource.mipLevel       = srcImage->toVkLevel(srcLevelGL).get();
7830         region.srcSubresource.baseArrayLayer = isSrc3D ? 0 : srcZ;
7831         region.srcSubresource.layerCount     = isSrc3D ? 1 : srcDepth;
7832 
7833         region.dstSubresource.aspectMask     = aspectFlags;
7834         region.dstSubresource.mipLevel       = dstImage->toVkLevel(dstLevelGL).get();
7835         region.dstSubresource.baseArrayLayer = isDst3D ? 0 : dstZ;
7836         region.dstSubresource.layerCount     = isDst3D ? 1 : srcDepth;
7837 
7838         region.srcOffset.x   = srcX;
7839         region.srcOffset.y   = srcY;
7840         region.srcOffset.z   = isSrc3D ? srcZ : 0;
7841         region.dstOffset.x   = dstX;
7842         region.dstOffset.y   = dstY;
7843         region.dstOffset.z   = isDst3D ? dstZ : 0;
7844         region.extent.width  = srcWidth;
7845         region.extent.height = srcHeight;
7846         region.extent.depth  = (isSrc3D || isDst3D) ? srcDepth : 1;
7847 
7848         CommandBufferAccess access;
7849         if (srcImage == dstImage)
7850         {
7851             access.onImageSelfCopy(srcLevelGL, 1, region.srcSubresource.baseArrayLayer,
7852                                    region.srcSubresource.layerCount, dstLevelGL, 1,
7853                                    region.dstSubresource.baseArrayLayer,
7854                                    region.dstSubresource.layerCount, aspectFlags, srcImage);
7855         }
7856         else
7857         {
7858             access.onImageTransferRead(aspectFlags, srcImage);
7859             access.onImageTransferWrite(dstLevelGL, 1, region.dstSubresource.baseArrayLayer,
7860                                         region.dstSubresource.layerCount, aspectFlags, dstImage);
7861         }
7862 
7863         OutsideRenderPassCommandBuffer *commandBuffer;
7864         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
7865 
7866         ASSERT(srcImage->valid() && dstImage->valid());
7867         ASSERT(srcImage->getCurrentLayout(renderer) == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL ||
7868                srcImage->getCurrentLayout(renderer) == VK_IMAGE_LAYOUT_GENERAL);
7869         ASSERT(dstImage->getCurrentLayout(renderer) == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ||
7870                dstImage->getCurrentLayout(renderer) == VK_IMAGE_LAYOUT_GENERAL);
7871 
7872         commandBuffer->copyImage(srcImage->getImage(), srcImage->getCurrentLayout(renderer),
7873                                  dstImage->getImage(), dstImage->getCurrentLayout(renderer), 1,
7874                                  &region);
7875     }
7876     else if (!srcImage->getIntendedFormat().isBlock && !dstImage->getIntendedFormat().isBlock)
7877     {
7878         // The source and destination image formats may be using a fallback in the case of RGB
7879         // images.  A compute shader is used in such a case to perform the copy.
7880         UtilsVk &utilsVk = contextVk->getUtils();
7881 
7882         UtilsVk::CopyImageBitsParameters params;
7883         params.srcOffset[0]   = srcX;
7884         params.srcOffset[1]   = srcY;
7885         params.srcOffset[2]   = srcZ;
7886         params.srcLevel       = srcLevelGL;
7887         params.dstOffset[0]   = dstX;
7888         params.dstOffset[1]   = dstY;
7889         params.dstOffset[2]   = dstZ;
7890         params.dstLevel       = dstLevelGL;
7891         params.copyExtents[0] = srcWidth;
7892         params.copyExtents[1] = srcHeight;
7893         params.copyExtents[2] = srcDepth;
7894 
7895         ANGLE_TRY(utilsVk.copyImageBits(contextVk, dstImage, srcImage, params));
7896     }
7897     else
7898     {
7899         // No support for emulated compressed formats.
7900         UNIMPLEMENTED();
7901         ANGLE_VK_CHECK(contextVk, false, VK_ERROR_FEATURE_NOT_PRESENT);
7902     }
7903 
7904     contextVk->trackImagesWithOutsideRenderPassEvent(srcImage, dstImage);
7905 
7906     return angle::Result::Continue;
7907 }
7908 
generateMipmapsWithBlit(ContextVk * contextVk,LevelIndex baseLevel,LevelIndex maxLevel)7909 angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk,
7910                                                    LevelIndex baseLevel,
7911                                                    LevelIndex maxLevel)
7912 {
7913     Renderer *renderer = contextVk->getRenderer();
7914 
7915     CommandBufferAccess access;
7916     gl::LevelIndex baseLevelGL = toGLLevel(baseLevel);
7917     access.onImageTransferWrite(baseLevelGL + 1, maxLevel.get(), 0, mLayerCount,
7918                                 VK_IMAGE_ASPECT_COLOR_BIT, this);
7919 
7920     OutsideRenderPassCommandBuffer *commandBuffer;
7921     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
7922 
7923     // We are able to use blitImage since the image format we are using supports it.
7924     int32_t mipWidth  = mExtents.width;
7925     int32_t mipHeight = mExtents.height;
7926     int32_t mipDepth  = mExtents.depth;
7927 
7928     // Manually manage the image memory barrier because it uses a lot more parameters than our
7929     // usual one.
7930     VkImageMemoryBarrier barrier            = {};
7931     barrier.sType                           = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
7932     barrier.image                           = mImage.getHandle();
7933     barrier.srcQueueFamilyIndex             = VK_QUEUE_FAMILY_IGNORED;
7934     barrier.dstQueueFamilyIndex             = VK_QUEUE_FAMILY_IGNORED;
7935     barrier.subresourceRange.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
7936     barrier.subresourceRange.baseArrayLayer = 0;
7937     barrier.subresourceRange.layerCount     = mLayerCount;
7938     barrier.subresourceRange.levelCount     = 1;
7939 
7940     const VkFilter filter =
7941         gl_vk::GetFilter(CalculateGenerateMipmapFilter(contextVk, getActualFormatID()));
7942 
7943     for (LevelIndex mipLevel(1); mipLevel <= LevelIndex(mLevelCount); ++mipLevel)
7944     {
7945         int32_t nextMipWidth  = std::max<int32_t>(1, mipWidth >> 1);
7946         int32_t nextMipHeight = std::max<int32_t>(1, mipHeight >> 1);
7947         int32_t nextMipDepth  = std::max<int32_t>(1, mipDepth >> 1);
7948 
7949         if (mipLevel > baseLevel && mipLevel <= maxLevel)
7950         {
7951             barrier.subresourceRange.baseMipLevel = mipLevel.get() - 1;
7952             barrier.oldLayout                     = getCurrentLayout(renderer);
7953             barrier.newLayout                     = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
7954             barrier.srcAccessMask                 = VK_ACCESS_TRANSFER_WRITE_BIT;
7955             barrier.dstAccessMask                 = VK_ACCESS_TRANSFER_READ_BIT;
7956 
7957             // We can do it for all layers at once.
7958             commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
7959                                         VK_PIPELINE_STAGE_TRANSFER_BIT, barrier);
7960             VkImageBlit blit                   = {};
7961             blit.srcOffsets[0]                 = {0, 0, 0};
7962             blit.srcOffsets[1]                 = {mipWidth, mipHeight, mipDepth};
7963             blit.srcSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
7964             blit.srcSubresource.mipLevel       = mipLevel.get() - 1;
7965             blit.srcSubresource.baseArrayLayer = 0;
7966             blit.srcSubresource.layerCount     = mLayerCount;
7967             blit.dstOffsets[0]                 = {0, 0, 0};
7968             blit.dstOffsets[1]                 = {nextMipWidth, nextMipHeight, nextMipDepth};
7969             blit.dstSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
7970             blit.dstSubresource.mipLevel       = mipLevel.get();
7971             blit.dstSubresource.baseArrayLayer = 0;
7972             blit.dstSubresource.layerCount     = mLayerCount;
7973 
7974             commandBuffer->blitImage(mImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, mImage,
7975                                      VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, filter);
7976         }
7977         mipWidth  = nextMipWidth;
7978         mipHeight = nextMipHeight;
7979         mipDepth  = nextMipDepth;
7980     }
7981 
7982     // Transition all mip level to the same layout so we can declare our whole image layout to one
7983     // ImageLayout. FragmentShaderReadOnly is picked here since this is the most reasonable usage
7984     // after glGenerateMipmap call.
7985     barrier.oldLayout     = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
7986     barrier.newLayout     = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
7987     barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
7988     if (baseLevel.get() > 0)
7989     {
7990         // [0:baseLevel-1] from TRANSFER_DST to SHADER_READ
7991         barrier.subresourceRange.baseMipLevel = 0;
7992         barrier.subresourceRange.levelCount   = baseLevel.get();
7993         commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
7994                                     VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, barrier);
7995     }
7996     // [maxLevel:mLevelCount-1] from TRANSFER_DST to SHADER_READ
7997     ASSERT(mLevelCount > maxLevel.get());
7998     barrier.subresourceRange.baseMipLevel = maxLevel.get();
7999     barrier.subresourceRange.levelCount   = mLevelCount - maxLevel.get();
8000     commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
8001                                 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, barrier);
8002     // [baseLevel:maxLevel-1] from TRANSFER_SRC to SHADER_READ
8003     barrier.oldLayout                     = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
8004     barrier.srcAccessMask                 = VK_ACCESS_TRANSFER_READ_BIT;
8005     barrier.subresourceRange.baseMipLevel = baseLevel.get();
8006     barrier.subresourceRange.levelCount   = maxLevel.get() - baseLevel.get();
8007     commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
8008                                 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, barrier);
8009 
8010     // This is just changing the internal state of the image helper so that the next call
8011     // to changeLayout will use this layout as the "oldLayout" argument.
8012     // mLastNonShaderReadOnlyLayout is used to ensure previous write are made visible to reads,
8013     // since the only write here is transfer, hence mLastNonShaderReadOnlyLayout is set to
8014     // ImageLayout::TransferDst.
8015     mLastNonShaderReadOnlyLayout = ImageLayout::TransferDst;
8016     mCurrentShaderReadStageMask  = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
8017     mCurrentLayout               = ImageLayout::FragmentShaderReadOnly;
8018 
8019     contextVk->trackImageWithOutsideRenderPassEvent(this);
8020 
8021     return angle::Result::Continue;
8022 }
8023 
resolve(ImageHelper * dst,const VkImageResolve & region,OutsideRenderPassCommandBuffer * commandBuffer)8024 void ImageHelper::resolve(ImageHelper *dst,
8025                           const VkImageResolve &region,
8026                           OutsideRenderPassCommandBuffer *commandBuffer)
8027 {
8028     ASSERT(mCurrentLayout == ImageLayout::TransferSrc ||
8029            mCurrentLayout == ImageLayout::SharedPresent);
8030     commandBuffer->resolveImage(getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst->getImage(),
8031                                 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
8032 }
8033 
removeSingleSubresourceStagedUpdates(ContextVk * contextVk,gl::LevelIndex levelIndexGL,uint32_t layerIndex,uint32_t layerCount)8034 void ImageHelper::removeSingleSubresourceStagedUpdates(ContextVk *contextVk,
8035                                                        gl::LevelIndex levelIndexGL,
8036                                                        uint32_t layerIndex,
8037                                                        uint32_t layerCount)
8038 {
8039     mCurrentSingleClearValue.reset();
8040 
8041     // Find any staged updates for this index and remove them from the pending list.
8042     std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(levelIndexGL);
8043     if (levelUpdates == nullptr)
8044     {
8045         return;
8046     }
8047 
8048     for (size_t index = 0; index < levelUpdates->size();)
8049     {
8050         auto update = levelUpdates->begin() + index;
8051         if (update->matchesLayerRange(layerIndex, layerCount))
8052         {
8053             // Update total staging buffer size
8054             mTotalStagedBufferUpdateSize -= update->updateSource == UpdateSource::Buffer
8055                                                 ? update->data.buffer.bufferHelper->getSize()
8056                                                 : 0;
8057             update->release(contextVk->getRenderer());
8058             levelUpdates->erase(update);
8059         }
8060         else
8061         {
8062             index++;
8063         }
8064     }
8065 }
8066 
removeSingleStagedClearAfterInvalidate(gl::LevelIndex levelIndexGL,uint32_t layerIndex,uint32_t layerCount)8067 void ImageHelper::removeSingleStagedClearAfterInvalidate(gl::LevelIndex levelIndexGL,
8068                                                          uint32_t layerIndex,
8069                                                          uint32_t layerCount)
8070 {
8071     // When this function is called, it's expected that there may be at most one
8072     // ClearAfterInvalidate update pending to this subresource, and that's a color clear due to
8073     // emulated channels after invalidate.  This function removes that update.
8074 
8075     std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(levelIndexGL);
8076     if (levelUpdates == nullptr)
8077     {
8078         return;
8079     }
8080 
8081     for (size_t index = 0; index < levelUpdates->size(); ++index)
8082     {
8083         auto update = levelUpdates->begin() + index;
8084         if (update->updateSource == UpdateSource::ClearAfterInvalidate &&
8085             update->matchesLayerRange(layerIndex, layerCount))
8086         {
8087             // It's a clear, so doesn't need to be released.
8088             levelUpdates->erase(update);
8089             // There's only one such clear possible.
8090             return;
8091         }
8092     }
8093 }
8094 
removeStagedUpdates(Context * context,gl::LevelIndex levelGLStart,gl::LevelIndex levelGLEnd)8095 void ImageHelper::removeStagedUpdates(Context *context,
8096                                       gl::LevelIndex levelGLStart,
8097                                       gl::LevelIndex levelGLEnd)
8098 {
8099     ASSERT(validateSubresourceUpdateRefCountsConsistent());
8100 
8101     // Remove all updates to levels [start, end].
8102     for (gl::LevelIndex level = levelGLStart; level <= levelGLEnd; ++level)
8103     {
8104         std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(level);
8105         if (levelUpdates == nullptr)
8106         {
8107             ASSERT(static_cast<size_t>(level.get()) >= mSubresourceUpdates.size());
8108             return;
8109         }
8110 
8111         for (SubresourceUpdate &update : *levelUpdates)
8112         {
8113             // Update total staging buffer size
8114             mTotalStagedBufferUpdateSize -= update.updateSource == UpdateSource::Buffer
8115                                                 ? update.data.buffer.bufferHelper->getSize()
8116                                                 : 0;
8117             update.release(context->getRenderer());
8118         }
8119 
8120         levelUpdates->clear();
8121     }
8122 
8123     ASSERT(validateSubresourceUpdateRefCountsConsistent());
8124 }
8125 
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,ApplyImageUpdate applyUpdate,bool * updateAppliedImmediatelyOut)8126 angle::Result ImageHelper::stageSubresourceUpdateImpl(ContextVk *contextVk,
8127                                                       const gl::ImageIndex &index,
8128                                                       const gl::Extents &glExtents,
8129                                                       const gl::Offset &offset,
8130                                                       const gl::InternalFormat &formatInfo,
8131                                                       const gl::PixelUnpackState &unpack,
8132                                                       GLenum type,
8133                                                       const uint8_t *pixels,
8134                                                       const Format &vkFormat,
8135                                                       ImageAccess access,
8136                                                       const GLuint inputRowPitch,
8137                                                       const GLuint inputDepthPitch,
8138                                                       const GLuint inputSkipBytes,
8139                                                       ApplyImageUpdate applyUpdate,
8140                                                       bool *updateAppliedImmediatelyOut)
8141 {
8142     *updateAppliedImmediatelyOut = false;
8143 
8144     const angle::Format &storageFormat = vkFormat.getActualImageFormat(access);
8145 
8146     size_t outputRowPitch;
8147     size_t outputDepthPitch;
8148     size_t stencilAllocationSize = 0;
8149     uint32_t bufferRowLength;
8150     uint32_t bufferImageHeight;
8151     size_t allocationSize;
8152 
8153     LoadImageFunctionInfo loadFunctionInfo = vkFormat.getTextureLoadFunction(access, type);
8154     LoadImageFunction stencilLoadFunction  = nullptr;
8155 
8156     bool useComputeTransCoding = false;
8157     if (storageFormat.isBlock)
8158     {
8159         const gl::InternalFormat &storageFormatInfo = vkFormat.getInternalFormatInfo(type);
8160         GLuint rowPitch;
8161         GLuint depthPitch;
8162         GLuint totalSize;
8163 
8164         ANGLE_VK_CHECK_MATH(contextVk, storageFormatInfo.computeCompressedImageRowPitch(
8165                                            glExtents.width, &rowPitch));
8166         ANGLE_VK_CHECK_MATH(contextVk, storageFormatInfo.computeCompressedImageDepthPitch(
8167                                            glExtents.height, rowPitch, &depthPitch));
8168 
8169         ANGLE_VK_CHECK_MATH(contextVk,
8170                             storageFormatInfo.computeCompressedImageSize(glExtents, &totalSize));
8171 
8172         outputRowPitch   = rowPitch;
8173         outputDepthPitch = depthPitch;
8174         allocationSize   = totalSize;
8175 
8176         ANGLE_VK_CHECK_MATH(
8177             contextVk, storageFormatInfo.computeBufferRowLength(glExtents.width, &bufferRowLength));
8178         ANGLE_VK_CHECK_MATH(contextVk, storageFormatInfo.computeBufferImageHeight(
8179                                            glExtents.height, &bufferImageHeight));
8180 
8181         if (contextVk->getRenderer()->getFeatures().supportsComputeTranscodeEtcToBc.enabled &&
8182             IsETCFormat(vkFormat.getIntendedFormatID()) && IsBCFormat(storageFormat.id))
8183         {
8184             useComputeTransCoding =
8185                 shouldUseComputeForTransCoding(vk::LevelIndex(index.getLevelIndex()));
8186             if (!useComputeTransCoding)
8187             {
8188                 loadFunctionInfo = GetEtcToBcTransCodingFunc(vkFormat.getIntendedFormatID());
8189             }
8190         }
8191     }
8192     else
8193     {
8194         ASSERT(storageFormat.pixelBytes != 0);
8195         const bool stencilOnly = formatInfo.sizedInternalFormat == GL_STENCIL_INDEX8;
8196 
8197         if (!stencilOnly && storageFormat.id == angle::FormatID::D24_UNORM_S8_UINT)
8198         {
8199             switch (type)
8200             {
8201                 case GL_UNSIGNED_INT_24_8:
8202                     stencilLoadFunction = angle::LoadX24S8ToS8;
8203                     break;
8204                 case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
8205                     stencilLoadFunction = angle::LoadX32S8ToS8;
8206                     break;
8207             }
8208         }
8209         if (!stencilOnly && storageFormat.id == angle::FormatID::D32_FLOAT_S8X24_UINT)
8210         {
8211             // If depth is D32FLOAT_S8, we must pack D32F tightly (no stencil) for CopyBufferToImage
8212             outputRowPitch = sizeof(float) * glExtents.width;
8213 
8214             // The generic load functions don't handle tightly packing D32FS8 to D32F & S8 so call
8215             // special case load functions.
8216             switch (type)
8217             {
8218                 case GL_UNSIGNED_INT:
8219                     loadFunctionInfo.loadFunction = angle::LoadD32ToD32F;
8220                     stencilLoadFunction           = nullptr;
8221                     break;
8222                 case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
8223                     loadFunctionInfo.loadFunction = angle::LoadD32FS8X24ToD32F;
8224                     stencilLoadFunction           = angle::LoadX32S8ToS8;
8225                     break;
8226                 case GL_UNSIGNED_INT_24_8:
8227                     loadFunctionInfo.loadFunction = angle::LoadD24S8ToD32F;
8228                     stencilLoadFunction           = angle::LoadX24S8ToS8;
8229                     break;
8230                 default:
8231                     UNREACHABLE();
8232             }
8233         }
8234         else if (!stencilOnly)
8235         {
8236             outputRowPitch = storageFormat.pixelBytes * glExtents.width;
8237         }
8238         else
8239         {
8240             // Some Vulkan implementations do not support S8_UINT, so stencil-only data is
8241             // uploaded using one of combined depth-stencil formats there. Since the uploaded
8242             // stencil data must be tightly packed, the actual storage format should be ignored
8243             // with regards to its load function and output row pitch.
8244             loadFunctionInfo.loadFunction = angle::LoadToNative<GLubyte, 1>;
8245             outputRowPitch                = glExtents.width;
8246         }
8247         outputDepthPitch = outputRowPitch * glExtents.height;
8248 
8249         bufferRowLength   = glExtents.width;
8250         bufferImageHeight = glExtents.height;
8251 
8252         allocationSize = outputDepthPitch * glExtents.depth;
8253 
8254         // Note: because the LoadImageFunctionInfo functions are limited to copying a single
8255         // component, we have to special case packed depth/stencil use and send the stencil as a
8256         // separate chunk.
8257         if (storageFormat.hasDepthAndStencilBits() && formatInfo.depthBits > 0 &&
8258             formatInfo.stencilBits > 0)
8259         {
8260             // Note: Stencil is always one byte
8261             stencilAllocationSize = glExtents.width * glExtents.height * glExtents.depth;
8262             allocationSize += stencilAllocationSize;
8263         }
8264     }
8265 
8266     const uint8_t *source = pixels + static_cast<ptrdiff_t>(inputSkipBytes);
8267 
8268     // If possible, copy the buffer to the image directly on the host, to avoid having to use a temp
8269     // image (and do a double copy).
8270     if (applyUpdate != ApplyImageUpdate::Defer && !loadFunctionInfo.requiresConversion &&
8271         inputRowPitch == outputRowPitch && inputDepthPitch == outputDepthPitch)
8272     {
8273         bool copied = false;
8274         ANGLE_TRY(updateSubresourceOnHost(contextVk, applyUpdate, index, glExtents, offset, source,
8275                                           bufferRowLength, bufferImageHeight, &copied));
8276         if (copied)
8277         {
8278             *updateAppliedImmediatelyOut = true;
8279             return angle::Result::Continue;
8280         }
8281     }
8282 
8283     std::unique_ptr<RefCounted<BufferHelper>> stagingBuffer =
8284         std::make_unique<RefCounted<BufferHelper>>();
8285     BufferHelper *currentBuffer = &stagingBuffer->get();
8286 
8287     uint8_t *stagingPointer;
8288     VkDeviceSize stagingOffset;
8289     ANGLE_TRY(contextVk->initBufferForImageCopy(currentBuffer, allocationSize,
8290                                                 MemoryCoherency::CachedNonCoherent,
8291                                                 storageFormat.id, &stagingOffset, &stagingPointer));
8292 
8293     loadFunctionInfo.loadFunction(
8294         contextVk->getImageLoadContext(), glExtents.width, glExtents.height, glExtents.depth,
8295         source, inputRowPitch, inputDepthPitch, stagingPointer, outputRowPitch, outputDepthPitch);
8296 
8297     // YUV formats need special handling.
8298     if (storageFormat.isYUV)
8299     {
8300         gl::YuvFormatInfo yuvInfo(formatInfo.internalFormat, glExtents);
8301 
8302         constexpr VkImageAspectFlagBits kPlaneAspectFlags[3] = {
8303             VK_IMAGE_ASPECT_PLANE_0_BIT, VK_IMAGE_ASPECT_PLANE_1_BIT, VK_IMAGE_ASPECT_PLANE_2_BIT};
8304 
8305         // We only support mip level 0 and layerCount of 1 for YUV formats.
8306         ASSERT(index.getLevelIndex() == 0);
8307         ASSERT(index.getLayerCount() == 1);
8308 
8309         for (uint32_t plane = 0; plane < yuvInfo.planeCount; plane++)
8310         {
8311             VkBufferImageCopy copy           = {};
8312             copy.bufferOffset                = stagingOffset + yuvInfo.planeOffset[plane];
8313             copy.bufferRowLength             = 0;
8314             copy.bufferImageHeight           = 0;
8315             copy.imageSubresource.mipLevel   = 0;
8316             copy.imageSubresource.layerCount = 1;
8317             gl_vk::GetOffset(offset, &copy.imageOffset);
8318             gl_vk::GetExtent(yuvInfo.planeExtent[plane], &copy.imageExtent);
8319             copy.imageSubresource.baseArrayLayer = 0;
8320             copy.imageSubresource.aspectMask     = kPlaneAspectFlags[plane];
8321             appendSubresourceUpdate(
8322                 gl::LevelIndex(0),
8323                 SubresourceUpdate(stagingBuffer.get(), currentBuffer, copy, storageFormat.id));
8324         }
8325 
8326         stagingBuffer.release();
8327         return angle::Result::Continue;
8328     }
8329 
8330     VkBufferImageCopy copy         = {};
8331     VkImageAspectFlags aspectFlags = GetFormatAspectFlags(storageFormat);
8332 
8333     copy.bufferOffset      = stagingOffset;
8334     copy.bufferRowLength   = bufferRowLength;
8335     copy.bufferImageHeight = bufferImageHeight;
8336 
8337     gl::LevelIndex updateLevelGL(index.getLevelIndex());
8338     copy.imageSubresource.mipLevel   = updateLevelGL.get();
8339     copy.imageSubresource.layerCount = index.getLayerCount();
8340 
8341     gl_vk::GetOffset(offset, &copy.imageOffset);
8342     gl_vk::GetExtent(glExtents, &copy.imageExtent);
8343 
8344     if (gl::IsArrayTextureType(index.getType()))
8345     {
8346         copy.imageSubresource.baseArrayLayer = offset.z;
8347         copy.imageOffset.z                   = 0;
8348         copy.imageExtent.depth               = 1;
8349     }
8350     else
8351     {
8352         copy.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
8353     }
8354 
8355     if (stencilAllocationSize > 0)
8356     {
8357         // Note: Stencil is always one byte
8358         ASSERT((aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) != 0);
8359 
8360         // Skip over depth data.
8361         stagingPointer += outputDepthPitch * glExtents.depth;
8362         stagingOffset += outputDepthPitch * glExtents.depth;
8363 
8364         // recompute pitch for stencil data
8365         outputRowPitch   = glExtents.width;
8366         outputDepthPitch = outputRowPitch * glExtents.height;
8367 
8368         ASSERT(stencilLoadFunction != nullptr);
8369         stencilLoadFunction(contextVk->getImageLoadContext(), glExtents.width, glExtents.height,
8370                             glExtents.depth, source, inputRowPitch, inputDepthPitch, stagingPointer,
8371                             outputRowPitch, outputDepthPitch);
8372 
8373         VkBufferImageCopy stencilCopy = {};
8374 
8375         stencilCopy.bufferOffset                    = stagingOffset;
8376         stencilCopy.bufferRowLength                 = bufferRowLength;
8377         stencilCopy.bufferImageHeight               = bufferImageHeight;
8378         stencilCopy.imageSubresource.mipLevel       = copy.imageSubresource.mipLevel;
8379         stencilCopy.imageSubresource.baseArrayLayer = copy.imageSubresource.baseArrayLayer;
8380         stencilCopy.imageSubresource.layerCount     = copy.imageSubresource.layerCount;
8381         stencilCopy.imageOffset                     = copy.imageOffset;
8382         stencilCopy.imageExtent                     = copy.imageExtent;
8383         stencilCopy.imageSubresource.aspectMask     = VK_IMAGE_ASPECT_STENCIL_BIT;
8384         appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(stagingBuffer.get(), currentBuffer,
8385                                                                  stencilCopy, storageFormat.id));
8386 
8387         aspectFlags &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
8388     }
8389 
8390     if (HasBothDepthAndStencilAspects(aspectFlags))
8391     {
8392         // We still have both depth and stencil aspect bits set. That means we have a destination
8393         // buffer that is packed depth stencil and that the application is only loading one aspect.
8394         // Figure out which aspect the user is touching and remove the unused aspect bit.
8395         if (formatInfo.stencilBits > 0)
8396         {
8397             aspectFlags &= ~VK_IMAGE_ASPECT_DEPTH_BIT;
8398         }
8399         else
8400         {
8401             aspectFlags &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
8402         }
8403     }
8404 
8405     if (aspectFlags)
8406     {
8407         copy.imageSubresource.aspectMask = aspectFlags;
8408         appendSubresourceUpdate(
8409             updateLevelGL, SubresourceUpdate(stagingBuffer.get(), currentBuffer, copy,
8410                                              useComputeTransCoding ? vkFormat.getIntendedFormatID()
8411                                                                    : storageFormat.id));
8412         pruneSupersededUpdatesForLevel(contextVk, updateLevelGL, PruneReason::MemoryOptimization);
8413     }
8414 
8415     stagingBuffer.release();
8416     return angle::Result::Continue;
8417 }
8418 
updateSubresourceOnHost(Context * context,ApplyImageUpdate applyUpdate,const gl::ImageIndex & index,const gl::Extents & glExtents,const gl::Offset & offset,const uint8_t * source,const GLuint memoryRowLength,const GLuint memoryImageHeight,bool * copiedOut)8419 angle::Result ImageHelper::updateSubresourceOnHost(Context *context,
8420                                                    ApplyImageUpdate applyUpdate,
8421                                                    const gl::ImageIndex &index,
8422                                                    const gl::Extents &glExtents,
8423                                                    const gl::Offset &offset,
8424                                                    const uint8_t *source,
8425                                                    const GLuint memoryRowLength,
8426                                                    const GLuint memoryImageHeight,
8427                                                    bool *copiedOut)
8428 {
8429     // If the image is not set up for host copy, it can't be done.
8430     if (!valid() || (mUsage & VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT) == 0)
8431     {
8432         return angle::Result::Continue;
8433     }
8434 
8435     Renderer *renderer = context->getRenderer();
8436     const VkPhysicalDeviceHostImageCopyPropertiesEXT &hostImageCopyProperties =
8437         renderer->getPhysicalDeviceHostImageCopyProperties();
8438 
8439     // The image should be unused by the GPU.
8440     if (!renderer->hasResourceUseFinished(getResourceUse()))
8441     {
8442         ANGLE_TRY(renderer->checkCompletedCommands(context));
8443         if (!renderer->hasResourceUseFinished(getResourceUse()))
8444         {
8445             return angle::Result::Continue;
8446         }
8447     }
8448 
8449     // The image should not have any pending updates to this subresource.
8450     //
8451     // TODO: if there are any pending updates, see if they can be pruned given the incoming update.
8452     // This would most likely be the case where a clear is automatically staged for robustness or
8453     // other reasons, which would now be superseded by the data upload.  http://anglebug.com/8341
8454     const gl::LevelIndex updateLevelGL(index.getLevelIndex());
8455     const uint32_t layerIndex = index.hasLayer() ? index.getLayerIndex() : 0;
8456     const uint32_t layerCount = index.getLayerCount();
8457     if (hasStagedUpdatesForSubresource(updateLevelGL, layerIndex, layerCount))
8458     {
8459         return angle::Result::Continue;
8460     }
8461 
8462     // The image should be in a layout this is copiable.  If UNDEFINED, it can be transitioned to a
8463     // layout that is copyable.
8464     const VkImageAspectFlags aspectMask = getAspectFlags();
8465     if (mCurrentLayout == ImageLayout::Undefined)
8466     {
8467         VkHostImageLayoutTransitionInfoEXT transition = {};
8468         transition.sType     = VK_STRUCTURE_TYPE_HOST_IMAGE_LAYOUT_TRANSITION_INFO_EXT;
8469         transition.image     = mImage.getHandle();
8470         transition.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
8471         // The GENERAL layout is always guaranteed to be in
8472         // VkPhysicalDeviceHostImageCopyPropertiesEXT::pCopyDstLayouts
8473         transition.newLayout                       = VK_IMAGE_LAYOUT_GENERAL;
8474         transition.subresourceRange.aspectMask     = aspectMask;
8475         transition.subresourceRange.baseMipLevel   = 0;
8476         transition.subresourceRange.levelCount     = mLevelCount;
8477         transition.subresourceRange.baseArrayLayer = 0;
8478         transition.subresourceRange.layerCount     = mLayerCount;
8479 
8480         ANGLE_VK_TRY(context, vkTransitionImageLayoutEXT(renderer->getDevice(), 1, &transition));
8481         mCurrentLayout = ImageLayout::HostCopy;
8482     }
8483     else if (mCurrentLayout != ImageLayout::HostCopy &&
8484              !IsAnyLayout(getCurrentLayout(renderer), hostImageCopyProperties.pCopyDstLayouts,
8485                           hostImageCopyProperties.copyDstLayoutCount))
8486     {
8487         return angle::Result::Continue;
8488     }
8489 
8490     const bool isArray            = gl::IsArrayTextureType(index.getType());
8491     const uint32_t baseArrayLayer = isArray ? offset.z : layerIndex;
8492 
8493     onWrite(updateLevelGL, 1, baseArrayLayer, layerCount, aspectMask);
8494     *copiedOut = true;
8495 
8496     // Perform the copy without holding the lock.  This is important for applications that perform
8497     // the copy on a separate thread, and doing all the work while holding the lock effectively
8498     // destroys all parallelism.  Note that the texture may not be used by the other thread without
8499     // appropriate synchronization (such as through glFenceSync), and because the copy is happening
8500     // in this call (just without holding the lock), the sync function won't be called until the
8501     // copy is done.
8502     auto doCopy = [context, image = mImage.getHandle(), source, memoryRowLength, memoryImageHeight,
8503                    aspectMask, levelVk = toVkLevel(updateLevelGL), isArray, baseArrayLayer,
8504                    layerCount, offset, glExtents,
8505                    layout = getCurrentLayout(renderer)](void *resultOut) {
8506         ANGLE_TRACE_EVENT0("gpu.angle", "Upload image data on host");
8507         ANGLE_UNUSED_VARIABLE(resultOut);
8508 
8509         VkMemoryToImageCopyEXT copyRegion          = {};
8510         copyRegion.sType                           = VK_STRUCTURE_TYPE_MEMORY_TO_IMAGE_COPY_EXT;
8511         copyRegion.pHostPointer                    = source;
8512         copyRegion.memoryRowLength                 = memoryRowLength;
8513         copyRegion.memoryImageHeight               = memoryImageHeight;
8514         copyRegion.imageSubresource.aspectMask     = aspectMask;
8515         copyRegion.imageSubresource.mipLevel       = levelVk.get();
8516         copyRegion.imageSubresource.baseArrayLayer = baseArrayLayer;
8517         copyRegion.imageSubresource.layerCount     = layerCount;
8518         gl_vk::GetOffset(offset, &copyRegion.imageOffset);
8519         gl_vk::GetExtent(glExtents, &copyRegion.imageExtent);
8520 
8521         if (isArray)
8522         {
8523             copyRegion.imageOffset.z     = 0;
8524             copyRegion.imageExtent.depth = 1;
8525         }
8526 
8527         VkCopyMemoryToImageInfoEXT copyInfo = {};
8528         copyInfo.sType                      = VK_STRUCTURE_TYPE_COPY_MEMORY_TO_IMAGE_INFO_EXT;
8529         copyInfo.dstImage                   = image;
8530         copyInfo.dstImageLayout             = layout;
8531         copyInfo.regionCount                = 1;
8532         copyInfo.pRegions                   = &copyRegion;
8533 
8534         VkResult result = vkCopyMemoryToImageEXT(context->getDevice(), &copyInfo);
8535         if (result != VK_SUCCESS)
8536         {
8537             context->handleError(result, __FILE__, ANGLE_FUNCTION, __LINE__);
8538         }
8539     };
8540 
8541     switch (applyUpdate)
8542     {
8543         // If possible, perform the copy in an unlocked tail call.  Then the other threads of the
8544         // application are free to draw.
8545         case ApplyImageUpdate::ImmediatelyInUnlockedTailCall:
8546             egl::Display::GetCurrentThreadUnlockedTailCall()->add(doCopy);
8547             break;
8548 
8549         // In some cases, the copy cannot be delayed.  For example because the contents are
8550         // immediately needed (such as when the generate mipmap hint is set), or because unlocked
8551         // tail calls are not allowed (this is the case with incomplete textures which are lazily
8552         // created at draw, but unlocked tail calls are avoided on draw calls due to overhead).
8553         case ApplyImageUpdate::Immediately:
8554             doCopy(nullptr);
8555             break;
8556 
8557         default:
8558             UNREACHABLE();
8559             doCopy(nullptr);
8560     }
8561 
8562     return angle::Result::Continue;
8563 }
8564 
reformatStagedBufferUpdates(ContextVk * contextVk,angle::FormatID srcFormatID,angle::FormatID dstFormatID)8565 angle::Result ImageHelper::reformatStagedBufferUpdates(ContextVk *contextVk,
8566                                                        angle::FormatID srcFormatID,
8567                                                        angle::FormatID dstFormatID)
8568 {
8569     Renderer *renderer             = contextVk->getRenderer();
8570     const angle::Format &srcFormat = angle::Format::Get(srcFormatID);
8571     const angle::Format &dstFormat = angle::Format::Get(dstFormatID);
8572     const gl::InternalFormat &dstFormatInfo =
8573         gl::GetSizedInternalFormatInfo(dstFormat.glInternalFormat);
8574 
8575     for (std::vector<SubresourceUpdate> &levelUpdates : mSubresourceUpdates)
8576     {
8577         for (SubresourceUpdate &update : levelUpdates)
8578         {
8579             // Right now whenever we stage update from a source image, the formats always match.
8580             ASSERT(valid() || update.updateSource != UpdateSource::Image ||
8581                    update.data.image.formatID == srcFormatID);
8582 
8583             if (update.updateSource == UpdateSource::Buffer &&
8584                 update.data.buffer.formatID == srcFormatID)
8585             {
8586                 const VkBufferImageCopy &copy = update.data.buffer.copyRegion;
8587 
8588                 // Source and dst data are tightly packed
8589                 GLuint srcDataRowPitch = copy.imageExtent.width * srcFormat.pixelBytes;
8590                 GLuint dstDataRowPitch = copy.imageExtent.width * dstFormat.pixelBytes;
8591 
8592                 GLuint srcDataDepthPitch = srcDataRowPitch * copy.imageExtent.height;
8593                 GLuint dstDataDepthPitch = dstDataRowPitch * copy.imageExtent.height;
8594 
8595                 // Retrieve source buffer
8596                 vk::BufferHelper *srcBuffer = update.data.buffer.bufferHelper;
8597                 ASSERT(srcBuffer->isMapped());
8598                 // The bufferOffset is relative to the buffer block. We have to use the buffer
8599                 // block's memory pointer to get the source data pointer.
8600                 uint8_t *srcData = srcBuffer->getBlockMemory() + copy.bufferOffset;
8601 
8602                 // Allocate memory with dstFormat
8603                 std::unique_ptr<RefCounted<BufferHelper>> stagingBuffer =
8604                     std::make_unique<RefCounted<BufferHelper>>();
8605                 BufferHelper *dstBuffer = &stagingBuffer->get();
8606 
8607                 uint8_t *dstData;
8608                 VkDeviceSize dstBufferOffset;
8609                 size_t dstBufferSize = dstDataDepthPitch * copy.imageExtent.depth;
8610                 ANGLE_TRY(contextVk->initBufferForImageCopy(
8611                     dstBuffer, dstBufferSize, MemoryCoherency::CachedNonCoherent, dstFormatID,
8612                     &dstBufferOffset, &dstData));
8613 
8614                 rx::PixelReadFunction pixelReadFunction   = srcFormat.pixelReadFunction;
8615                 rx::PixelWriteFunction pixelWriteFunction = dstFormat.pixelWriteFunction;
8616 
8617                 CopyImageCHROMIUM(srcData, srcDataRowPitch, srcFormat.pixelBytes, srcDataDepthPitch,
8618                                   pixelReadFunction, dstData, dstDataRowPitch, dstFormat.pixelBytes,
8619                                   dstDataDepthPitch, pixelWriteFunction, dstFormatInfo.format,
8620                                   dstFormatInfo.componentType, copy.imageExtent.width,
8621                                   copy.imageExtent.height, copy.imageExtent.depth, false, false,
8622                                   false);
8623 
8624                 // Replace srcBuffer with dstBuffer
8625                 update.data.buffer.bufferHelper            = dstBuffer;
8626                 update.data.buffer.formatID                = dstFormatID;
8627                 update.data.buffer.copyRegion.bufferOffset = dstBufferOffset;
8628 
8629                 // Update total staging buffer size
8630                 mTotalStagedBufferUpdateSize -= srcBuffer->getSize();
8631                 mTotalStagedBufferUpdateSize += dstBuffer->getSize();
8632 
8633                 // Let update structure owns the staging buffer
8634                 if (update.refCounted.buffer)
8635                 {
8636                     update.refCounted.buffer->releaseRef();
8637                     if (!update.refCounted.buffer->isReferenced())
8638                     {
8639                         update.refCounted.buffer->get().release(renderer);
8640                         SafeDelete(update.refCounted.buffer);
8641                     }
8642                 }
8643                 update.refCounted.buffer = stagingBuffer.release();
8644                 update.refCounted.buffer->addRef();
8645             }
8646         }
8647     }
8648 
8649     return angle::Result::Continue;
8650 }
8651 
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)8652 angle::Result ImageHelper::CalculateBufferInfo(ContextVk *contextVk,
8653                                                const gl::Extents &glExtents,
8654                                                const gl::InternalFormat &formatInfo,
8655                                                const gl::PixelUnpackState &unpack,
8656                                                GLenum type,
8657                                                bool is3D,
8658                                                GLuint *inputRowPitch,
8659                                                GLuint *inputDepthPitch,
8660                                                GLuint *inputSkipBytes)
8661 {
8662     // YUV formats need special handling.
8663     if (gl::IsYuvFormat(formatInfo.internalFormat))
8664     {
8665         gl::YuvFormatInfo yuvInfo(formatInfo.internalFormat, glExtents);
8666 
8667         // row pitch = Y plane row pitch
8668         *inputRowPitch = yuvInfo.planePitch[0];
8669         // depth pitch = Y plane size + chroma plane size
8670         *inputDepthPitch = yuvInfo.planeSize[0] + yuvInfo.planeSize[1] + yuvInfo.planeSize[2];
8671         *inputSkipBytes  = 0;
8672 
8673         return angle::Result::Continue;
8674     }
8675 
8676     ANGLE_VK_CHECK_MATH(contextVk,
8677                         formatInfo.computeRowPitch(type, glExtents.width, unpack.alignment,
8678                                                    unpack.rowLength, inputRowPitch));
8679 
8680     ANGLE_VK_CHECK_MATH(contextVk,
8681                         formatInfo.computeDepthPitch(glExtents.height, unpack.imageHeight,
8682                                                      *inputRowPitch, inputDepthPitch));
8683 
8684     ANGLE_VK_CHECK_MATH(
8685         contextVk, formatInfo.computeSkipBytes(type, *inputRowPitch, *inputDepthPitch, unpack, is3D,
8686                                                inputSkipBytes));
8687 
8688     return angle::Result::Continue;
8689 }
8690 
onWrite(gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags)8691 void ImageHelper::onWrite(gl::LevelIndex levelStart,
8692                           uint32_t levelCount,
8693                           uint32_t layerStart,
8694                           uint32_t layerCount,
8695                           VkImageAspectFlags aspectFlags)
8696 {
8697     mCurrentSingleClearValue.reset();
8698 
8699     // Mark contents of the given subresource as defined.
8700     setContentDefined(toVkLevel(levelStart), levelCount, layerStart, layerCount, aspectFlags);
8701 }
8702 
hasSubresourceDefinedContent(gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount) const8703 bool ImageHelper::hasSubresourceDefinedContent(gl::LevelIndex level,
8704                                                uint32_t layerIndex,
8705                                                uint32_t layerCount) const
8706 {
8707     if (layerIndex >= kMaxContentDefinedLayerCount)
8708     {
8709         return true;
8710     }
8711 
8712     uint8_t layerRangeBits =
8713         GetContentDefinedLayerRangeBits(layerIndex, layerCount, kMaxContentDefinedLayerCount);
8714     return (getLevelContentDefined(toVkLevel(level)) & LevelContentDefinedMask(layerRangeBits))
8715         .any();
8716 }
8717 
hasSubresourceDefinedStencilContent(gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount) const8718 bool ImageHelper::hasSubresourceDefinedStencilContent(gl::LevelIndex level,
8719                                                       uint32_t layerIndex,
8720                                                       uint32_t layerCount) const
8721 {
8722     if (layerIndex >= kMaxContentDefinedLayerCount)
8723     {
8724         return true;
8725     }
8726 
8727     uint8_t layerRangeBits =
8728         GetContentDefinedLayerRangeBits(layerIndex, layerCount, kMaxContentDefinedLayerCount);
8729     return (getLevelStencilContentDefined(toVkLevel(level)) &
8730             LevelContentDefinedMask(layerRangeBits))
8731         .any();
8732 }
8733 
invalidateSubresourceContent(ContextVk * contextVk,gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount,bool * preferToKeepContentsDefinedOut)8734 void ImageHelper::invalidateSubresourceContent(ContextVk *contextVk,
8735                                                gl::LevelIndex level,
8736                                                uint32_t layerIndex,
8737                                                uint32_t layerCount,
8738                                                bool *preferToKeepContentsDefinedOut)
8739 {
8740     invalidateSubresourceContentImpl(
8741         contextVk, level, layerIndex, layerCount,
8742         static_cast<VkImageAspectFlagBits>(getAspectFlags() & ~VK_IMAGE_ASPECT_STENCIL_BIT),
8743         &getLevelContentDefined(toVkLevel(level)), preferToKeepContentsDefinedOut);
8744 }
8745 
invalidateSubresourceStencilContent(ContextVk * contextVk,gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount,bool * preferToKeepContentsDefinedOut)8746 void ImageHelper::invalidateSubresourceStencilContent(ContextVk *contextVk,
8747                                                       gl::LevelIndex level,
8748                                                       uint32_t layerIndex,
8749                                                       uint32_t layerCount,
8750                                                       bool *preferToKeepContentsDefinedOut)
8751 {
8752     invalidateSubresourceContentImpl(
8753         contextVk, level, layerIndex, layerCount, VK_IMAGE_ASPECT_STENCIL_BIT,
8754         &getLevelStencilContentDefined(toVkLevel(level)), preferToKeepContentsDefinedOut);
8755 }
8756 
invalidateSubresourceContentImpl(ContextVk * contextVk,gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount,VkImageAspectFlagBits aspect,LevelContentDefinedMask * contentDefinedMask,bool * preferToKeepContentsDefinedOut)8757 void ImageHelper::invalidateSubresourceContentImpl(ContextVk *contextVk,
8758                                                    gl::LevelIndex level,
8759                                                    uint32_t layerIndex,
8760                                                    uint32_t layerCount,
8761                                                    VkImageAspectFlagBits aspect,
8762                                                    LevelContentDefinedMask *contentDefinedMask,
8763                                                    bool *preferToKeepContentsDefinedOut)
8764 {
8765     // If the aspect being invalidated doesn't exist, skip invalidation altogether.
8766     if ((getAspectFlags() & aspect) == 0)
8767     {
8768         if (preferToKeepContentsDefinedOut)
8769         {
8770             // Let the caller know that this invalidate request was ignored.
8771             *preferToKeepContentsDefinedOut = true;
8772         }
8773         return;
8774     }
8775 
8776     // If the color format is emulated and has extra channels, those channels need to stay cleared.
8777     // On some devices, it's cheaper to skip invalidating the framebuffer attachment, while on
8778     // others it's cheaper to invalidate but then re-clear the image.
8779     //
8780     // For depth/stencil formats, each channel is separately invalidated, so the invalidate is
8781     // simply skipped for the emulated channel on all devices.
8782     const bool hasEmulatedChannels = hasEmulatedImageChannels();
8783     bool skip                      = false;
8784     switch (aspect)
8785     {
8786         case VK_IMAGE_ASPECT_DEPTH_BIT:
8787             skip = hasEmulatedDepthChannel();
8788             break;
8789         case VK_IMAGE_ASPECT_STENCIL_BIT:
8790             skip = hasEmulatedStencilChannel();
8791             break;
8792         case VK_IMAGE_ASPECT_COLOR_BIT:
8793             skip = hasEmulatedChannels &&
8794                    contextVk->getFeatures().preferSkippingInvalidateForEmulatedFormats.enabled;
8795             break;
8796         default:
8797             UNREACHABLE();
8798             skip = true;
8799     }
8800 
8801     if (preferToKeepContentsDefinedOut)
8802     {
8803         *preferToKeepContentsDefinedOut = skip;
8804     }
8805     if (skip)
8806     {
8807         return;
8808     }
8809 
8810     if (layerIndex >= kMaxContentDefinedLayerCount)
8811     {
8812         const char *aspectName = "color";
8813         if (aspect == VK_IMAGE_ASPECT_DEPTH_BIT)
8814         {
8815             aspectName = "depth";
8816         }
8817         else if (aspect == VK_IMAGE_ASPECT_STENCIL_BIT)
8818         {
8819             aspectName = "stencil";
8820         }
8821         ANGLE_VK_PERF_WARNING(
8822             contextVk, GL_DEBUG_SEVERITY_LOW,
8823             "glInvalidateFramebuffer (%s) ineffective on attachments with layer >= 8", aspectName);
8824         return;
8825     }
8826 
8827     uint8_t layerRangeBits =
8828         GetContentDefinedLayerRangeBits(layerIndex, layerCount, kMaxContentDefinedLayerCount);
8829     *contentDefinedMask &= static_cast<uint8_t>(~layerRangeBits);
8830 
8831     // If there are emulated channels, stage a clear to make sure those channels continue to contain
8832     // valid values.
8833     if (hasEmulatedChannels && aspect == VK_IMAGE_ASPECT_COLOR_BIT)
8834     {
8835         VkClearValue clearValue;
8836         clearValue.color = kEmulatedInitColorValue;
8837 
8838         prependSubresourceUpdate(
8839             level, SubresourceUpdate(aspect, clearValue, level, layerIndex, layerCount));
8840         mSubresourceUpdates[level.get()].front().updateSource = UpdateSource::ClearAfterInvalidate;
8841     }
8842 }
8843 
restoreSubresourceContent(gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount)8844 void ImageHelper::restoreSubresourceContent(gl::LevelIndex level,
8845                                             uint32_t layerIndex,
8846                                             uint32_t layerCount)
8847 {
8848     restoreSubresourceContentImpl(
8849         level, layerIndex, layerCount,
8850         static_cast<VkImageAspectFlagBits>(getAspectFlags() & ~VK_IMAGE_ASPECT_STENCIL_BIT),
8851         &getLevelContentDefined(toVkLevel(level)));
8852 }
8853 
restoreSubresourceStencilContent(gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount)8854 void ImageHelper::restoreSubresourceStencilContent(gl::LevelIndex level,
8855                                                    uint32_t layerIndex,
8856                                                    uint32_t layerCount)
8857 {
8858     restoreSubresourceContentImpl(level, layerIndex, layerCount, VK_IMAGE_ASPECT_STENCIL_BIT,
8859                                   &getLevelStencilContentDefined(toVkLevel(level)));
8860 }
8861 
restoreSubresourceContentImpl(gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount,VkImageAspectFlagBits aspect,LevelContentDefinedMask * contentDefinedMask)8862 void ImageHelper::restoreSubresourceContentImpl(gl::LevelIndex level,
8863                                                 uint32_t layerIndex,
8864                                                 uint32_t layerCount,
8865                                                 VkImageAspectFlagBits aspect,
8866                                                 LevelContentDefinedMask *contentDefinedMask)
8867 {
8868     if (layerIndex >= kMaxContentDefinedLayerCount)
8869     {
8870         return;
8871     }
8872 
8873     uint8_t layerRangeBits =
8874         GetContentDefinedLayerRangeBits(layerIndex, layerCount, kMaxContentDefinedLayerCount);
8875 
8876     switch (aspect)
8877     {
8878         case VK_IMAGE_ASPECT_DEPTH_BIT:
8879             // Emulated depth channel should never have been marked invalid, so it can retain its
8880             // cleared value.
8881             ASSERT(!hasEmulatedDepthChannel() ||
8882                    (contentDefinedMask->bits() & layerRangeBits) == layerRangeBits);
8883             break;
8884         case VK_IMAGE_ASPECT_STENCIL_BIT:
8885             // Emulated stencil channel should never have been marked invalid, so it can retain its
8886             // cleared value.
8887             ASSERT(!hasEmulatedStencilChannel() ||
8888                    (contentDefinedMask->bits() & layerRangeBits) == layerRangeBits);
8889             break;
8890         case VK_IMAGE_ASPECT_COLOR_BIT:
8891             // This function is called on attachments during a render pass when it's determined that
8892             // they should no longer be considered invalidated.  For an attachment with emulated
8893             // format that has extra channels, invalidateSubresourceContentImpl may have proactively
8894             // inserted a clear so that the extra channels continue to have defined values.  That
8895             // clear should be removed.
8896             if (hasEmulatedImageChannels())
8897             {
8898                 removeSingleStagedClearAfterInvalidate(level, layerIndex, layerCount);
8899             }
8900             break;
8901         default:
8902             UNREACHABLE();
8903             break;
8904     }
8905 
8906     // Additionally, as the resource has been rewritten to in the render pass, its no longer cleared
8907     // to the cached value.
8908     mCurrentSingleClearValue.reset();
8909 
8910     *contentDefinedMask |= layerRangeBits;
8911 }
8912 
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,ApplyImageUpdate applyUpdate,bool * updateAppliedImmediatelyOut)8913 angle::Result ImageHelper::stageSubresourceUpdate(ContextVk *contextVk,
8914                                                   const gl::ImageIndex &index,
8915                                                   const gl::Extents &glExtents,
8916                                                   const gl::Offset &offset,
8917                                                   const gl::InternalFormat &formatInfo,
8918                                                   const gl::PixelUnpackState &unpack,
8919                                                   GLenum type,
8920                                                   const uint8_t *pixels,
8921                                                   const Format &vkFormat,
8922                                                   ImageAccess access,
8923                                                   ApplyImageUpdate applyUpdate,
8924                                                   bool *updateAppliedImmediatelyOut)
8925 {
8926     GLuint inputRowPitch   = 0;
8927     GLuint inputDepthPitch = 0;
8928     GLuint inputSkipBytes  = 0;
8929     ANGLE_TRY(CalculateBufferInfo(contextVk, glExtents, formatInfo, unpack, type, index.usesTex3D(),
8930                                   &inputRowPitch, &inputDepthPitch, &inputSkipBytes));
8931 
8932     ANGLE_TRY(stageSubresourceUpdateImpl(
8933         contextVk, index, glExtents, offset, formatInfo, unpack, type, pixels, vkFormat, access,
8934         inputRowPitch, inputDepthPitch, inputSkipBytes, applyUpdate, updateAppliedImmediatelyOut));
8935 
8936     return angle::Result::Continue;
8937 }
8938 
stageSubresourceUpdateAndGetData(ContextVk * contextVk,size_t allocationSize,const gl::ImageIndex & imageIndex,const gl::Extents & glExtents,const gl::Offset & offset,uint8_t ** dstData,angle::FormatID formatID)8939 angle::Result ImageHelper::stageSubresourceUpdateAndGetData(ContextVk *contextVk,
8940                                                             size_t allocationSize,
8941                                                             const gl::ImageIndex &imageIndex,
8942                                                             const gl::Extents &glExtents,
8943                                                             const gl::Offset &offset,
8944                                                             uint8_t **dstData,
8945                                                             angle::FormatID formatID)
8946 {
8947     std::unique_ptr<RefCounted<BufferHelper>> stagingBuffer =
8948         std::make_unique<RefCounted<BufferHelper>>();
8949     BufferHelper *currentBuffer = &stagingBuffer->get();
8950 
8951     VkDeviceSize stagingOffset;
8952     ANGLE_TRY(contextVk->initBufferForImageCopy(currentBuffer, allocationSize,
8953                                                 MemoryCoherency::CachedNonCoherent, formatID,
8954                                                 &stagingOffset, dstData));
8955 
8956     gl::LevelIndex updateLevelGL(imageIndex.getLevelIndex());
8957 
8958     VkBufferImageCopy copy               = {};
8959     copy.bufferOffset                    = stagingOffset;
8960     copy.bufferRowLength                 = glExtents.width;
8961     copy.bufferImageHeight               = glExtents.height;
8962     copy.imageSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
8963     copy.imageSubresource.mipLevel       = updateLevelGL.get();
8964     copy.imageSubresource.baseArrayLayer = imageIndex.hasLayer() ? imageIndex.getLayerIndex() : 0;
8965     copy.imageSubresource.layerCount     = imageIndex.getLayerCount();
8966 
8967     // Note: Only support color now
8968     ASSERT((mActualFormatID == angle::FormatID::NONE) ||
8969            (getAspectFlags() == VK_IMAGE_ASPECT_COLOR_BIT));
8970 
8971     gl_vk::GetOffset(offset, &copy.imageOffset);
8972     gl_vk::GetExtent(glExtents, &copy.imageExtent);
8973 
8974     appendSubresourceUpdate(
8975         updateLevelGL, SubresourceUpdate(stagingBuffer.release(), currentBuffer, copy, formatID));
8976     return angle::Result::Continue;
8977 }
8978 
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)8979 angle::Result ImageHelper::stageSubresourceUpdateFromFramebuffer(
8980     const gl::Context *context,
8981     const gl::ImageIndex &index,
8982     const gl::Rectangle &sourceArea,
8983     const gl::Offset &dstOffset,
8984     const gl::Extents &dstExtent,
8985     const gl::InternalFormat &formatInfo,
8986     ImageAccess access,
8987     FramebufferVk *framebufferVk)
8988 {
8989     ContextVk *contextVk = GetImpl(context);
8990 
8991     // If the extents and offset is outside the source image, we need to clip.
8992     gl::Rectangle clippedRectangle;
8993     const gl::Extents readExtents = framebufferVk->getReadImageExtents();
8994     if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, readExtents.width, readExtents.height),
8995                        &clippedRectangle))
8996     {
8997         // Empty source area, nothing to do.
8998         return angle::Result::Continue;
8999     }
9000 
9001     bool isViewportFlipEnabled = contextVk->isViewportFlipEnabledForDrawFBO();
9002     if (isViewportFlipEnabled)
9003     {
9004         clippedRectangle.y = readExtents.height - clippedRectangle.y - clippedRectangle.height;
9005     }
9006 
9007     // 1- obtain a buffer handle to copy to
9008     Renderer *renderer = contextVk->getRenderer();
9009 
9010     const Format &vkFormat             = renderer->getFormat(formatInfo.sizedInternalFormat);
9011     const angle::Format &storageFormat = vkFormat.getActualImageFormat(access);
9012     LoadImageFunctionInfo loadFunction = vkFormat.getTextureLoadFunction(access, formatInfo.type);
9013 
9014     size_t outputRowPitch   = storageFormat.pixelBytes * clippedRectangle.width;
9015     size_t outputDepthPitch = outputRowPitch * clippedRectangle.height;
9016 
9017     std::unique_ptr<RefCounted<BufferHelper>> stagingBuffer =
9018         std::make_unique<RefCounted<BufferHelper>>();
9019     BufferHelper *currentBuffer = &stagingBuffer->get();
9020 
9021     uint8_t *stagingPointer;
9022     VkDeviceSize stagingOffset;
9023 
9024     // The destination is only one layer deep.
9025     size_t allocationSize = outputDepthPitch;
9026     ANGLE_TRY(contextVk->initBufferForImageCopy(currentBuffer, allocationSize,
9027                                                 MemoryCoherency::CachedNonCoherent,
9028                                                 storageFormat.id, &stagingOffset, &stagingPointer));
9029 
9030     const angle::Format &copyFormat =
9031         GetFormatFromFormatType(formatInfo.internalFormat, formatInfo.type);
9032     PackPixelsParams params(clippedRectangle, copyFormat, static_cast<GLuint>(outputRowPitch),
9033                             isViewportFlipEnabled, nullptr, 0);
9034 
9035     RenderTargetVk *readRenderTarget = framebufferVk->getColorReadRenderTarget();
9036 
9037     // 2- copy the source image region to the pixel buffer using a cpu readback
9038     if (loadFunction.requiresConversion)
9039     {
9040         // When a conversion is required, we need to use the loadFunction to read from a temporary
9041         // buffer instead so its an even slower path.
9042         size_t bufferSize =
9043             storageFormat.pixelBytes * clippedRectangle.width * clippedRectangle.height;
9044         angle::MemoryBuffer *memoryBuffer = nullptr;
9045         ANGLE_VK_CHECK_ALLOC(contextVk, context->getScratchBuffer(bufferSize, &memoryBuffer));
9046 
9047         // Read into the scratch buffer
9048         ANGLE_TRY(framebufferVk->readPixelsImpl(contextVk, clippedRectangle, params,
9049                                                 VK_IMAGE_ASPECT_COLOR_BIT, readRenderTarget,
9050                                                 memoryBuffer->data()));
9051 
9052         // Load from scratch buffer to our pixel buffer
9053         loadFunction.loadFunction(contextVk->getImageLoadContext(), clippedRectangle.width,
9054                                   clippedRectangle.height, 1, memoryBuffer->data(), outputRowPitch,
9055                                   0, stagingPointer, outputRowPitch, 0);
9056     }
9057     else
9058     {
9059         // We read directly from the framebuffer into our pixel buffer.
9060         ANGLE_TRY(framebufferVk->readPixelsImpl(contextVk, clippedRectangle, params,
9061                                                 VK_IMAGE_ASPECT_COLOR_BIT, readRenderTarget,
9062                                                 stagingPointer));
9063     }
9064 
9065     gl::LevelIndex updateLevelGL(index.getLevelIndex());
9066 
9067     // 3- enqueue the destination image subresource update
9068     VkBufferImageCopy copyToImage               = {};
9069     copyToImage.bufferOffset                    = static_cast<VkDeviceSize>(stagingOffset);
9070     copyToImage.bufferRowLength                 = 0;  // Tightly packed data can be specified as 0.
9071     copyToImage.bufferImageHeight               = clippedRectangle.height;
9072     copyToImage.imageSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
9073     copyToImage.imageSubresource.mipLevel       = updateLevelGL.get();
9074     copyToImage.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
9075     copyToImage.imageSubresource.layerCount     = index.getLayerCount();
9076     gl_vk::GetOffset(dstOffset, &copyToImage.imageOffset);
9077     gl_vk::GetExtent(dstExtent, &copyToImage.imageExtent);
9078 
9079     // 3- enqueue the destination image subresource update
9080     appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(stagingBuffer.release(), currentBuffer,
9081                                                              copyToImage, storageFormat.id));
9082 
9083     return angle::Result::Continue;
9084 }
9085 
stageSubresourceUpdateFromImage(RefCounted<ImageHelper> * image,const gl::ImageIndex & index,LevelIndex srcMipLevel,const gl::Offset & destOffset,const gl::Extents & glExtents,const VkImageType imageType)9086 void ImageHelper::stageSubresourceUpdateFromImage(RefCounted<ImageHelper> *image,
9087                                                   const gl::ImageIndex &index,
9088                                                   LevelIndex srcMipLevel,
9089                                                   const gl::Offset &destOffset,
9090                                                   const gl::Extents &glExtents,
9091                                                   const VkImageType imageType)
9092 {
9093     gl::LevelIndex updateLevelGL(index.getLevelIndex());
9094     VkImageAspectFlags imageAspectFlags = vk::GetFormatAspectFlags(image->get().getActualFormat());
9095 
9096     VkImageCopy copyToImage               = {};
9097     copyToImage.srcSubresource.aspectMask = imageAspectFlags;
9098     copyToImage.srcSubresource.mipLevel   = srcMipLevel.get();
9099     copyToImage.srcSubresource.layerCount = index.getLayerCount();
9100     copyToImage.dstSubresource.aspectMask = imageAspectFlags;
9101     copyToImage.dstSubresource.mipLevel   = updateLevelGL.get();
9102 
9103     if (imageType == VK_IMAGE_TYPE_3D)
9104     {
9105         // These values must be set explicitly to follow the Vulkan spec:
9106         // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkImageCopy.html
9107         // If either of the calling command's srcImage or dstImage parameters are of VkImageType
9108         // VK_IMAGE_TYPE_3D, the baseArrayLayer and layerCount members of the corresponding
9109         // subresource must be 0 and 1, respectively
9110         copyToImage.dstSubresource.baseArrayLayer = 0;
9111         copyToImage.dstSubresource.layerCount     = 1;
9112         // Preserve the assumption that destOffset.z == "dstSubresource.baseArrayLayer"
9113         ASSERT(destOffset.z == (index.hasLayer() ? index.getLayerIndex() : 0));
9114     }
9115     else
9116     {
9117         copyToImage.dstSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
9118         copyToImage.dstSubresource.layerCount     = index.getLayerCount();
9119     }
9120 
9121     gl_vk::GetOffset(destOffset, &copyToImage.dstOffset);
9122     gl_vk::GetExtent(glExtents, &copyToImage.extent);
9123 
9124     appendSubresourceUpdate(
9125         updateLevelGL, SubresourceUpdate(image, copyToImage, image->get().getActualFormatID()));
9126 }
9127 
stageSubresourceUpdatesFromAllImageLevels(RefCounted<ImageHelper> * image,gl::LevelIndex baseLevel)9128 void ImageHelper::stageSubresourceUpdatesFromAllImageLevels(RefCounted<ImageHelper> *image,
9129                                                             gl::LevelIndex baseLevel)
9130 {
9131     for (LevelIndex levelVk(0); levelVk < LevelIndex(image->get().getLevelCount()); ++levelVk)
9132     {
9133         const gl::LevelIndex levelGL = vk_gl::GetLevelIndex(levelVk, baseLevel);
9134         const gl::ImageIndex index =
9135             gl::ImageIndex::Make2DArrayRange(levelGL.get(), 0, image->get().getLayerCount());
9136 
9137         stageSubresourceUpdateFromImage(image, index, levelVk, gl::kOffsetZero,
9138                                         image->get().getLevelExtents(levelVk),
9139                                         image->get().getType());
9140     }
9141 }
9142 
stageClear(const gl::ImageIndex & index,VkImageAspectFlags aspectFlags,const VkClearValue & clearValue)9143 void ImageHelper::stageClear(const gl::ImageIndex &index,
9144                              VkImageAspectFlags aspectFlags,
9145                              const VkClearValue &clearValue)
9146 {
9147     gl::LevelIndex updateLevelGL(index.getLevelIndex());
9148     appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(aspectFlags, clearValue, index));
9149 }
9150 
stageRobustResourceClear(const gl::ImageIndex & index)9151 void ImageHelper::stageRobustResourceClear(const gl::ImageIndex &index)
9152 {
9153     const VkImageAspectFlags aspectFlags = getAspectFlags();
9154 
9155     ASSERT(mActualFormatID != angle::FormatID::NONE);
9156     VkClearValue clearValue = GetRobustResourceClearValue(getIntendedFormat(), getActualFormat());
9157 
9158     gl::LevelIndex updateLevelGL(index.getLevelIndex());
9159     appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(aspectFlags, clearValue, index));
9160 }
9161 
stageResourceClearWithFormat(ContextVk * contextVk,const gl::ImageIndex & index,const gl::Extents & glExtents,const angle::Format & intendedFormat,const angle::Format & imageFormat,const VkClearValue & clearValue)9162 angle::Result ImageHelper::stageResourceClearWithFormat(ContextVk *contextVk,
9163                                                         const gl::ImageIndex &index,
9164                                                         const gl::Extents &glExtents,
9165                                                         const angle::Format &intendedFormat,
9166                                                         const angle::Format &imageFormat,
9167                                                         const VkClearValue &clearValue)
9168 {
9169     // Robust clears must only be staged if we do not have any prior data for this subresource.
9170     ASSERT(!hasStagedUpdatesForSubresource(gl::LevelIndex(index.getLevelIndex()),
9171                                            index.getLayerIndex(), index.getLayerCount()));
9172 
9173     const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(imageFormat);
9174 
9175     gl::LevelIndex updateLevelGL(index.getLevelIndex());
9176 
9177     if (imageFormat.isBlock)
9178     {
9179         // This only supports doing an initial clear to 0, not clearing to a specific encoded RGBA
9180         // value
9181         ASSERT((clearValue.color.int32[0] == 0) && (clearValue.color.int32[1] == 0) &&
9182                (clearValue.color.int32[2] == 0) && (clearValue.color.int32[3] == 0));
9183 
9184         const gl::InternalFormat &formatInfo =
9185             gl::GetSizedInternalFormatInfo(imageFormat.glInternalFormat);
9186         GLuint totalSize;
9187         ANGLE_VK_CHECK_MATH(contextVk,
9188                             formatInfo.computeCompressedImageSize(glExtents, &totalSize));
9189 
9190         std::unique_ptr<RefCounted<BufferHelper>> stagingBuffer =
9191             std::make_unique<RefCounted<BufferHelper>>();
9192         BufferHelper *currentBuffer = &stagingBuffer->get();
9193 
9194         uint8_t *stagingPointer;
9195         VkDeviceSize stagingOffset;
9196         ANGLE_TRY(contextVk->initBufferForImageCopy(
9197             currentBuffer, totalSize, MemoryCoherency::CachedNonCoherent, imageFormat.id,
9198             &stagingOffset, &stagingPointer));
9199         memset(stagingPointer, 0, totalSize);
9200 
9201         VkBufferImageCopy copyRegion               = {};
9202         copyRegion.bufferOffset                    = stagingOffset;
9203         copyRegion.imageExtent.width               = glExtents.width;
9204         copyRegion.imageExtent.height              = glExtents.height;
9205         copyRegion.imageExtent.depth               = glExtents.depth;
9206         copyRegion.imageSubresource.mipLevel       = updateLevelGL.get();
9207         copyRegion.imageSubresource.aspectMask     = aspectFlags;
9208         copyRegion.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
9209         copyRegion.imageSubresource.layerCount     = index.getLayerCount();
9210 
9211         // The update structure owns the staging buffer.
9212         appendSubresourceUpdate(
9213             updateLevelGL,
9214             SubresourceUpdate(stagingBuffer.release(), currentBuffer, copyRegion, imageFormat.id));
9215     }
9216     else
9217     {
9218         appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(aspectFlags, clearValue, index));
9219     }
9220 
9221     return angle::Result::Continue;
9222 }
9223 
stageRobustResourceClearWithFormat(ContextVk * contextVk,const gl::ImageIndex & index,const gl::Extents & glExtents,const angle::Format & intendedFormat,const angle::Format & imageFormat)9224 angle::Result ImageHelper::stageRobustResourceClearWithFormat(ContextVk *contextVk,
9225                                                               const gl::ImageIndex &index,
9226                                                               const gl::Extents &glExtents,
9227                                                               const angle::Format &intendedFormat,
9228                                                               const angle::Format &imageFormat)
9229 {
9230     VkClearValue clearValue          = GetRobustResourceClearValue(intendedFormat, imageFormat);
9231     gl::ImageIndex fullResourceIndex = index;
9232     gl::Extents fullResourceExtents  = glExtents;
9233 
9234     if (gl::IsArrayTextureType(index.getType()))
9235     {
9236         // For 2Darray textures gl::Extents::depth is the layer count.
9237         fullResourceIndex = gl::ImageIndex::MakeFromType(
9238             index.getType(), index.getLevelIndex(), gl::ImageIndex::kEntireLevel, glExtents.depth);
9239         // Vulkan requires depth of 1 for 2Darray textures.
9240         fullResourceExtents.depth = 1;
9241     }
9242 
9243     return stageResourceClearWithFormat(contextVk, fullResourceIndex, fullResourceExtents,
9244                                         intendedFormat, imageFormat, clearValue);
9245 }
9246 
stageClearIfEmulatedFormat(bool isRobustResourceInitEnabled,bool isExternalImage)9247 void ImageHelper::stageClearIfEmulatedFormat(bool isRobustResourceInitEnabled, bool isExternalImage)
9248 {
9249     // Skip staging extra clears if robust resource init is enabled.
9250     if (!hasEmulatedImageChannels() || isRobustResourceInitEnabled)
9251     {
9252         return;
9253     }
9254 
9255     VkClearValue clearValue = {};
9256     if (getIntendedFormat().hasDepthOrStencilBits())
9257     {
9258         clearValue.depthStencil = kRobustInitDepthStencilValue;
9259     }
9260     else
9261     {
9262         clearValue.color = kEmulatedInitColorValue;
9263     }
9264 
9265     const VkImageAspectFlags aspectFlags = getAspectFlags();
9266 
9267     // If the image has an emulated channel and robust resource init is not enabled, always clear
9268     // it. These channels will be masked out in future writes, and shouldn't contain uninitialized
9269     // values.
9270     //
9271     // For external images, we cannot clear the image entirely, as it may contain data in the
9272     // non-emulated channels.  For depth/stencil images, clear is already per aspect, but for color
9273     // images we would need to take a special path where we only clear the emulated channels.
9274 
9275     // Block images are not cleared, since no emulated channels are present if decoded.
9276     if (isExternalImage && getIntendedFormat().isBlock)
9277     {
9278         return;
9279     }
9280 
9281     const bool clearOnlyEmulatedChannels =
9282         isExternalImage && !getIntendedFormat().hasDepthOrStencilBits();
9283     const VkColorComponentFlags colorMaskFlags =
9284         clearOnlyEmulatedChannels ? getEmulatedChannelsMask() : 0;
9285 
9286     for (LevelIndex level(0); level < LevelIndex(mLevelCount); ++level)
9287     {
9288         gl::LevelIndex updateLevelGL = toGLLevel(level);
9289         gl::ImageIndex index =
9290             gl::ImageIndex::Make2DArrayRange(updateLevelGL.get(), 0, mLayerCount);
9291 
9292         if (clearOnlyEmulatedChannels)
9293         {
9294             prependSubresourceUpdate(updateLevelGL,
9295                                      SubresourceUpdate(colorMaskFlags, clearValue.color, index));
9296         }
9297         else
9298         {
9299             prependSubresourceUpdate(updateLevelGL,
9300                                      SubresourceUpdate(aspectFlags, clearValue, index));
9301         }
9302     }
9303 }
9304 
verifyEmulatedClearsAreBeforeOtherUpdates(const std::vector<SubresourceUpdate> & updates)9305 bool ImageHelper::verifyEmulatedClearsAreBeforeOtherUpdates(
9306     const std::vector<SubresourceUpdate> &updates)
9307 {
9308     bool isIteratingEmulatedClears = true;
9309 
9310     for (const SubresourceUpdate &update : updates)
9311     {
9312         // If anything other than ClearEmulatedChannelsOnly is visited, there cannot be any
9313         // ClearEmulatedChannelsOnly updates after that.
9314         if (update.updateSource != UpdateSource::ClearEmulatedChannelsOnly)
9315         {
9316             isIteratingEmulatedClears = false;
9317         }
9318         else if (!isIteratingEmulatedClears)
9319         {
9320             // If ClearEmulatedChannelsOnly is visited after another update, that's an error.
9321             return false;
9322         }
9323     }
9324 
9325     // Additionally, verify that emulated clear is not applied multiple times.
9326     if (updates.size() >= 2 && updates[1].updateSource == UpdateSource::ClearEmulatedChannelsOnly)
9327     {
9328         return false;
9329     }
9330 
9331     return true;
9332 }
9333 
stageSelfAsSubresourceUpdates(ContextVk * contextVk,uint32_t levelCount,gl::TextureType textureType,const gl::CubeFaceArray<gl::TexLevelMask> & skipLevels)9334 void ImageHelper::stageSelfAsSubresourceUpdates(
9335     ContextVk *contextVk,
9336     uint32_t levelCount,
9337     gl::TextureType textureType,
9338     const gl::CubeFaceArray<gl::TexLevelMask> &skipLevels)
9339 
9340 {
9341     // Nothing to do if every level must be skipped
9342     const gl::TexLevelMask levelsMask(angle::BitMask<uint32_t>(levelCount)
9343                                       << mFirstAllocatedLevel.get());
9344     const gl::TexLevelMask skipLevelsAllFaces = AggregateSkipLevels(skipLevels);
9345 
9346     if ((~skipLevelsAllFaces & levelsMask).none())
9347     {
9348         return;
9349     }
9350 
9351     // Because we are cloning this object to another object, we must finalize the layout if it is
9352     // being used by current renderpass as attachment. Otherwise we are copying the incorrect layout
9353     // since it is determined at endRenderPass time.
9354     contextVk->finalizeImageLayout(this, {});
9355 
9356     std::unique_ptr<RefCounted<ImageHelper>> prevImage =
9357         std::make_unique<RefCounted<ImageHelper>>();
9358 
9359     // Move the necessary information for staged update to work, and keep the rest as part of this
9360     // object.
9361 
9362     // Usage info
9363     prevImage->get().Resource::operator=(std::move(*this));
9364 
9365     // Vulkan objects
9366     prevImage->get().mImage         = std::move(mImage);
9367     prevImage->get().mDeviceMemory  = std::move(mDeviceMemory);
9368     prevImage->get().mVmaAllocation = std::move(mVmaAllocation);
9369 
9370     // Barrier information.  Note: mLevelCount is set to levelCount so that only the necessary
9371     // levels are transitioned when flushing the update.
9372     prevImage->get().mIntendedFormatID            = mIntendedFormatID;
9373     prevImage->get().mActualFormatID              = mActualFormatID;
9374     prevImage->get().mCurrentLayout               = mCurrentLayout;
9375     prevImage->get().mCurrentDeviceQueueIndex     = mCurrentDeviceQueueIndex;
9376     prevImage->get().mLastNonShaderReadOnlyLayout = mLastNonShaderReadOnlyLayout;
9377     prevImage->get().mCurrentShaderReadStageMask  = mCurrentShaderReadStageMask;
9378     prevImage->get().mLevelCount                  = levelCount;
9379     prevImage->get().mLayerCount                  = mLayerCount;
9380     prevImage->get().mImageSerial                 = mImageSerial;
9381     prevImage->get().mAllocationSize              = mAllocationSize;
9382     prevImage->get().mMemoryAllocationType        = mMemoryAllocationType;
9383     prevImage->get().mMemoryTypeIndex             = mMemoryTypeIndex;
9384 
9385     // Reset information for current (invalid) image.
9386     mCurrentLayout               = ImageLayout::Undefined;
9387     mCurrentDeviceQueueIndex     = kInvalidDeviceQueueIndex;
9388     mIsReleasedToExternal        = false;
9389     mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
9390     mCurrentShaderReadStageMask  = 0;
9391     mImageSerial                 = kInvalidImageSerial;
9392     mMemoryAllocationType        = MemoryAllocationType::InvalidEnum;
9393 
9394     setEntireContentUndefined();
9395 
9396     // Stage updates from the previous image.
9397     for (LevelIndex levelVk(0); levelVk < LevelIndex(levelCount); ++levelVk)
9398     {
9399         gl::LevelIndex levelGL = toGLLevel(levelVk);
9400         if (!skipLevelsAllFaces.test(levelGL.get()))
9401         {
9402             const gl::ImageIndex index =
9403                 gl::ImageIndex::Make2DArrayRange(levelGL.get(), 0, mLayerCount);
9404 
9405             stageSubresourceUpdateFromImage(prevImage.get(), index, levelVk, gl::kOffsetZero,
9406                                             getLevelExtents(levelVk), mImageType);
9407         }
9408         else if (textureType == gl::TextureType::CubeMap)
9409         {
9410             for (uint32_t face = 0; face < gl::kCubeFaceCount; ++face)
9411             {
9412                 if (!skipLevels[face][levelGL.get()])
9413                 {
9414                     const gl::ImageIndex index =
9415                         gl::ImageIndex::Make2DArrayRange(levelGL.get(), face, 1);
9416 
9417                     stageSubresourceUpdateFromImage(prevImage.get(), index, levelVk,
9418                                                     gl::kOffsetZero, getLevelExtents(levelVk),
9419                                                     mImageType);
9420                 }
9421             }
9422         }
9423     }
9424 
9425     ASSERT(levelCount > 0);
9426     prevImage.release();
9427 }
9428 
flushSingleSubresourceStagedUpdates(ContextVk * contextVk,gl::LevelIndex levelGL,uint32_t layer,uint32_t layerCount,ClearValuesArray * deferredClears,uint32_t deferredClearIndex)9429 angle::Result ImageHelper::flushSingleSubresourceStagedUpdates(ContextVk *contextVk,
9430                                                                gl::LevelIndex levelGL,
9431                                                                uint32_t layer,
9432                                                                uint32_t layerCount,
9433                                                                ClearValuesArray *deferredClears,
9434                                                                uint32_t deferredClearIndex)
9435 {
9436     std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(levelGL);
9437     if (levelUpdates == nullptr || levelUpdates->empty())
9438     {
9439         return angle::Result::Continue;
9440     }
9441 
9442     // Handle deferred clears. Search the updates list for a matching clear index.
9443     if (deferredClears)
9444     {
9445         Optional<size_t> foundClear;
9446 
9447         for (size_t updateIndex = 0; updateIndex < levelUpdates->size(); ++updateIndex)
9448         {
9449             SubresourceUpdate &update = (*levelUpdates)[updateIndex];
9450 
9451             if (update.intersectsLayerRange(layer, layerCount))
9452             {
9453                 // On any data update or the clear does not match exact layer range, we'll need to
9454                 // do a full upload.
9455                 const bool isClear = IsClearOfAllChannels(update.updateSource);
9456                 if (isClear && update.matchesLayerRange(layer, layerCount))
9457                 {
9458                     foundClear = updateIndex;
9459                 }
9460                 else
9461                 {
9462                     foundClear.reset();
9463                     break;
9464                 }
9465             }
9466         }
9467 
9468         // If we have a valid index we defer the clear using the clear reference.
9469         if (foundClear.valid())
9470         {
9471             size_t foundIndex         = foundClear.value();
9472             const ClearUpdate &update = (*levelUpdates)[foundIndex].data.clear;
9473 
9474             // Note that this set command handles combined or separate depth/stencil clears.
9475             deferredClears->store(deferredClearIndex, update.aspectFlags, update.value);
9476 
9477             // Do not call onWrite as it removes mCurrentSingleClearValue, but instead call
9478             // setContentDefined directly.
9479             setContentDefined(toVkLevel(levelGL), 1, layer, layerCount, update.aspectFlags);
9480 
9481             // We process the updates again to erase any clears for this level.
9482             removeSingleSubresourceStagedUpdates(contextVk, levelGL, layer, layerCount);
9483             return angle::Result::Continue;
9484         }
9485 
9486         // Otherwise we proceed with a normal update.
9487     }
9488 
9489     return flushStagedUpdates(contextVk, levelGL, levelGL + 1, layer, layer + layerCount, {});
9490 }
9491 
flushStagedClearEmulatedChannelsUpdates(ContextVk * contextVk,gl::LevelIndex levelGLStart,gl::LevelIndex levelGLLimit,bool * otherUpdatesToFlushOut)9492 angle::Result ImageHelper::flushStagedClearEmulatedChannelsUpdates(ContextVk *contextVk,
9493                                                                    gl::LevelIndex levelGLStart,
9494                                                                    gl::LevelIndex levelGLLimit,
9495                                                                    bool *otherUpdatesToFlushOut)
9496 {
9497     *otherUpdatesToFlushOut = false;
9498     for (gl::LevelIndex updateMipLevelGL = levelGLStart; updateMipLevelGL < levelGLLimit;
9499          ++updateMipLevelGL)
9500     {
9501         // It is expected that the checked mip levels in this loop do not surpass the size of
9502         // mSubresourceUpdates.
9503         std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(updateMipLevelGL);
9504         ASSERT(levelUpdates != nullptr);
9505 
9506         // The levels with no updates should be skipped.
9507         if (levelUpdates->empty())
9508         {
9509             continue;
9510         }
9511 
9512         // Since ClearEmulatedChannelsOnly is expected in the beginning and there cannot be more
9513         // than one such update type, we can process the first update and move on if there is
9514         // another update type in the list.
9515         ASSERT(verifyEmulatedClearsAreBeforeOtherUpdates(*levelUpdates));
9516         std::vector<SubresourceUpdate>::iterator update = (*levelUpdates).begin();
9517 
9518         if (update->updateSource != UpdateSource::ClearEmulatedChannelsOnly)
9519         {
9520             *otherUpdatesToFlushOut = true;
9521             continue;
9522         }
9523 
9524         // If found, ClearEmulatedChannelsOnly should be flushed before the others and removed from
9525         // the update list.
9526         ASSERT(update->updateSource == UpdateSource::ClearEmulatedChannelsOnly);
9527         uint32_t updateBaseLayer, updateLayerCount;
9528         update->getDestSubresource(mLayerCount, &updateBaseLayer, &updateLayerCount);
9529 
9530         const LevelIndex updateMipLevelVk = toVkLevel(updateMipLevelGL);
9531         update->data.clear.levelIndex     = updateMipLevelVk.get();
9532         ANGLE_TRY(clearEmulatedChannels(contextVk, update->data.clear.colorMaskFlags,
9533                                         update->data.clear.value, updateMipLevelVk, updateBaseLayer,
9534                                         updateLayerCount));
9535         // Do not call onWrite. Even though some channels of the image are cleared, don't consider
9536         // the contents defined. Also, since clearing emulated channels is a one-time thing that's
9537         // superseded by Clears, |mCurrentSingleClearValue| is irrelevant and can't have a value.
9538         ASSERT(!mCurrentSingleClearValue.valid());
9539 
9540         levelUpdates->erase(update);
9541         if (!levelUpdates->empty())
9542         {
9543             ASSERT(levelUpdates->begin()->updateSource != UpdateSource::ClearEmulatedChannelsOnly);
9544             *otherUpdatesToFlushOut = true;
9545         }
9546     }
9547 
9548     return angle::Result::Continue;
9549 }
9550 
flushStagedUpdatesImpl(ContextVk * contextVk,gl::LevelIndex levelGLStart,gl::LevelIndex levelGLEnd,uint32_t layerStart,uint32_t layerEnd,const gl::TexLevelMask & skipLevelsAllFaces)9551 angle::Result ImageHelper::flushStagedUpdatesImpl(ContextVk *contextVk,
9552                                                   gl::LevelIndex levelGLStart,
9553                                                   gl::LevelIndex levelGLEnd,
9554                                                   uint32_t layerStart,
9555                                                   uint32_t layerEnd,
9556                                                   const gl::TexLevelMask &skipLevelsAllFaces)
9557 {
9558     Renderer *renderer = contextVk->getRenderer();
9559 
9560     const angle::FormatID &actualformat   = getActualFormatID();
9561     const angle::FormatID &intendedFormat = getIntendedFormatID();
9562 
9563     const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(getActualFormat());
9564 
9565     // Start in TransferDst.  Don't yet mark any subresource as having defined contents; that is
9566     // done with fine granularity as updates are applied.  This is achieved by specifying a layer
9567     // that is outside the tracking range. Under some circumstances, ComputeWrite is also required.
9568     // This need not be applied if the only updates are ClearEmulatedChannels.
9569     CommandBufferAccess transferAccess;
9570     OutsideRenderPassCommandBufferHelper *commandBuffer = nullptr;
9571     bool transCoding = renderer->getFeatures().supportsComputeTranscodeEtcToBc.enabled &&
9572                        IsETCFormat(intendedFormat) && IsBCFormat(actualformat);
9573 
9574     if (transCoding)
9575     {
9576         transferAccess.onImageTransferDstAndComputeWrite(
9577             levelGLStart, 1, kMaxContentDefinedLayerCount, 0, aspectFlags, this);
9578     }
9579     else
9580     {
9581         transferAccess.onImageTransferWrite(levelGLStart, 1, kMaxContentDefinedLayerCount, 0,
9582                                             aspectFlags, this);
9583     }
9584     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBufferHelper(transferAccess, &commandBuffer));
9585 
9586     // Flush the staged updates in each mip level.
9587     for (gl::LevelIndex updateMipLevelGL = levelGLStart; updateMipLevelGL < levelGLEnd;
9588          ++updateMipLevelGL)
9589     {
9590         // If updates to this level are specifically asked to be skipped, skip
9591         // them. This can happen when recreating an image that has been partially incompatibly
9592         // redefined, in which case only updates to the levels that haven't been redefined
9593         // should be flushed.
9594         if (skipLevelsAllFaces.test(updateMipLevelGL.get()))
9595         {
9596             continue;
9597         }
9598 
9599         // It is expected that the checked mip levels in this loop do not surpass the size of
9600         // mSubresourceUpdates.
9601         std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(updateMipLevelGL);
9602         std::vector<SubresourceUpdate> updatesToKeep;
9603         ASSERT(levelUpdates != nullptr);
9604 
9605         // Because updates may have overlapping layer ranges, we must first figure out the actual
9606         // layer ranges that will be flushed. The updatesToKeep list must compare against this
9607         // adjusted layer range. Otherwise you may end up keeping the update even though it is
9608         // overlapped with the update that gets flushed, and then content gets overwritten when
9609         // updatesToKeep gets flushed out.
9610         uint32_t adjustedLayerStart = layerStart, adjustedLayerEnd = layerEnd;
9611         if (levelUpdates->size() > 1)
9612         {
9613             adjustLayerRange(*levelUpdates, &adjustedLayerStart, &adjustedLayerEnd);
9614         }
9615 
9616         for (SubresourceUpdate &update : *levelUpdates)
9617         {
9618             ASSERT(IsClearOfAllChannels(update.updateSource) ||
9619                    (update.updateSource == UpdateSource::Buffer &&
9620                     update.data.buffer.bufferHelper != nullptr) ||
9621                    (update.updateSource == UpdateSource::Image &&
9622                     update.refCounted.image != nullptr && update.refCounted.image->isReferenced() &&
9623                     update.refCounted.image->get().valid()));
9624 
9625             uint32_t updateBaseLayer, updateLayerCount;
9626             update.getDestSubresource(mLayerCount, &updateBaseLayer, &updateLayerCount);
9627 
9628             // If the update layers don't intersect the requested layers, skip the update.
9629             const bool areUpdateLayersOutsideRange =
9630                 updateBaseLayer + updateLayerCount <= adjustedLayerStart ||
9631                 updateBaseLayer >= adjustedLayerEnd;
9632             if (areUpdateLayersOutsideRange)
9633             {
9634                 updatesToKeep.emplace_back(std::move(update));
9635                 continue;
9636             }
9637 
9638             const LevelIndex updateMipLevelVk = toVkLevel(updateMipLevelGL);
9639 
9640             // It seems we haven't fully support glCopyImageSubData
9641             // when compressed format emulated by uncompressed format.
9642             // make assumption that there is no data source come from image.
9643             ASSERT(!transCoding || (transCoding && update.updateSource == UpdateSource::Buffer));
9644             // The updates were holding gl::LevelIndex values so that they would not need
9645             // modification when the base level of the texture changes.  Now that the update is
9646             // about to take effect, we need to change miplevel to LevelIndex.
9647             switch (update.updateSource)
9648             {
9649                 case UpdateSource::Clear:
9650                 case UpdateSource::ClearAfterInvalidate:
9651                 {
9652                     update.data.clear.levelIndex = updateMipLevelVk.get();
9653                     break;
9654                 }
9655                 case UpdateSource::Buffer:
9656                 {
9657                     if (!transCoding && !isDataFormatMatchForCopy(update.data.buffer.formatID))
9658                     {
9659                         // TODO: http://anglebug.com/6368, we should handle this in higher level
9660                         // code. If we have incompatible updates, skip but keep it.
9661                         updatesToKeep.emplace_back(std::move(update));
9662                         continue;
9663                     }
9664                     update.data.buffer.copyRegion.imageSubresource.mipLevel =
9665                         updateMipLevelVk.get();
9666                     break;
9667                 }
9668                 case UpdateSource::Image:
9669                 {
9670                     if (!isDataFormatMatchForCopy(update.data.image.formatID))
9671                     {
9672                         // If we have incompatible updates, skip but keep it.
9673                         updatesToKeep.emplace_back(std::move(update));
9674                         continue;
9675                     }
9676                     update.data.image.copyRegion.dstSubresource.mipLevel = updateMipLevelVk.get();
9677                     break;
9678                 }
9679                 default:
9680                 {
9681                     UNREACHABLE();
9682                     break;
9683                 }
9684             }
9685 
9686             // When a barrier is necessary when uploading updates to a level, we could instead move
9687             // to the next level and continue uploads in parallel.  Once all levels need a barrier,
9688             // a single barrier can be issued and we could continue with the rest of the updates
9689             // from the first level. In case of multiple layer updates within the same level, a
9690             // barrier might be needed if there are multiple updates in the same parts of the image.
9691             ImageLayout barrierLayout =
9692                 transCoding ? ImageLayout::TransferDstAndComputeWrite : ImageLayout::TransferDst;
9693             if (updateLayerCount >= kMaxParallelLayerWrites)
9694             {
9695                 // If there are more subresources than bits we can track, always insert a barrier.
9696                 recordWriteBarrier(contextVk, aspectFlags, barrierLayout, updateMipLevelGL, 1,
9697                                    updateBaseLayer, updateLayerCount, commandBuffer);
9698                 mSubresourcesWrittenSinceBarrier[updateMipLevelGL.get()].set();
9699             }
9700             else
9701             {
9702                 ImageLayerWriteMask subresourceHash =
9703                     GetImageLayerWriteMask(updateBaseLayer, updateLayerCount);
9704 
9705                 if (areLevelSubresourcesWrittenWithinMaskRange(updateMipLevelGL.get(),
9706                                                                subresourceHash))
9707                 {
9708                     // If there's overlap in subresource upload, issue a barrier.
9709                     recordWriteBarrier(contextVk, aspectFlags, barrierLayout, updateMipLevelGL, 1,
9710                                        updateBaseLayer, updateLayerCount, commandBuffer);
9711                     mSubresourcesWrittenSinceBarrier[updateMipLevelGL.get()].reset();
9712                 }
9713                 mSubresourcesWrittenSinceBarrier[updateMipLevelGL.get()] |= subresourceHash;
9714             }
9715 
9716             // Add the necessary commands to the outside command buffer.
9717             switch (update.updateSource)
9718             {
9719                 case UpdateSource::Clear:
9720                 case UpdateSource::ClearAfterInvalidate:
9721                 {
9722                     clear(renderer, update.data.clear.aspectFlags, update.data.clear.value,
9723                           updateMipLevelVk, updateBaseLayer, updateLayerCount,
9724                           &commandBuffer->getCommandBuffer());
9725                     // Remember the latest operation is a clear call.
9726                     mCurrentSingleClearValue = update.data.clear;
9727 
9728                     // Do not call onWrite as it removes mCurrentSingleClearValue, but instead call
9729                     // setContentDefined directly.
9730                     setContentDefined(updateMipLevelVk, 1, updateBaseLayer, updateLayerCount,
9731                                       update.data.clear.aspectFlags);
9732                     break;
9733                 }
9734                 case UpdateSource::Buffer:
9735                 {
9736                     BufferUpdate &bufferUpdate = update.data.buffer;
9737 
9738                     BufferHelper *currentBuffer = bufferUpdate.bufferHelper;
9739                     ASSERT(currentBuffer && currentBuffer->valid());
9740                     ANGLE_TRY(currentBuffer->flush(renderer));
9741 
9742                     CommandBufferAccess bufferAccess;
9743                     VkBufferImageCopy *copyRegion = &update.data.buffer.copyRegion;
9744 
9745                     if (transCoding && update.data.buffer.formatID != actualformat)
9746                     {
9747                         bufferAccess.onBufferComputeShaderRead(currentBuffer);
9748                         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBufferHelper(
9749                             bufferAccess, &commandBuffer));
9750                         ANGLE_TRY(contextVk->getUtils().transCodeEtcToBc(contextVk, currentBuffer,
9751                                                                          this, copyRegion));
9752                     }
9753                     else
9754                     {
9755                         bufferAccess.onBufferTransferRead(currentBuffer);
9756                         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBufferHelper(
9757                             bufferAccess, &commandBuffer));
9758                         commandBuffer->getCommandBuffer().copyBufferToImage(
9759                             currentBuffer->getBuffer().getHandle(), mImage,
9760                             getCurrentLayout(renderer), 1, copyRegion);
9761                     }
9762                     bool commandBufferWasFlushed = false;
9763                     ANGLE_TRY(contextVk->onCopyUpdate(currentBuffer->getSize(),
9764                                                       &commandBufferWasFlushed));
9765                     onWrite(updateMipLevelGL, 1, updateBaseLayer, updateLayerCount,
9766                             copyRegion->imageSubresource.aspectMask);
9767 
9768                     // Update total staging buffer size.
9769                     mTotalStagedBufferUpdateSize -= bufferUpdate.bufferHelper->getSize();
9770 
9771                     if (commandBufferWasFlushed)
9772                     {
9773                         ANGLE_TRY(
9774                             contextVk->getOutsideRenderPassCommandBufferHelper({}, &commandBuffer));
9775                     }
9776                     break;
9777                 }
9778                 case UpdateSource::Image:
9779                 {
9780                     CommandBufferAccess imageAccess;
9781                     imageAccess.onImageTransferRead(aspectFlags, &update.refCounted.image->get());
9782                     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBufferHelper(imageAccess,
9783                                                                                  &commandBuffer));
9784 
9785                     VkImageCopy *copyRegion = &update.data.image.copyRegion;
9786                     commandBuffer->getCommandBuffer().copyImage(
9787                         update.refCounted.image->get().getImage(),
9788                         update.refCounted.image->get().getCurrentLayout(renderer), mImage,
9789                         getCurrentLayout(renderer), 1, copyRegion);
9790                     onWrite(updateMipLevelGL, 1, updateBaseLayer, updateLayerCount,
9791                             copyRegion->dstSubresource.aspectMask);
9792                     break;
9793                 }
9794                 default:
9795                 {
9796                     UNREACHABLE();
9797                     break;
9798                 }
9799             }
9800 
9801             update.release(renderer);
9802         }
9803 
9804         // Only remove the updates that were actually applied to the image.
9805         *levelUpdates = std::move(updatesToKeep);
9806     }
9807 
9808     if (commandBuffer != nullptr)
9809     {
9810         // Track completion of this copy operation.
9811         contextVk->trackImageWithOutsideRenderPassEvent(this);
9812     }
9813 
9814     return angle::Result::Continue;
9815 }
9816 
flushStagedUpdates(ContextVk * contextVk,gl::LevelIndex levelGLStart,gl::LevelIndex levelGLEnd,uint32_t layerStart,uint32_t layerEnd,const gl::CubeFaceArray<gl::TexLevelMask> & skipLevels)9817 angle::Result ImageHelper::flushStagedUpdates(ContextVk *contextVk,
9818                                               gl::LevelIndex levelGLStart,
9819                                               gl::LevelIndex levelGLEnd,
9820                                               uint32_t layerStart,
9821                                               uint32_t layerEnd,
9822                                               const gl::CubeFaceArray<gl::TexLevelMask> &skipLevels)
9823 {
9824     Renderer *renderer = contextVk->getRenderer();
9825 
9826     if (!hasStagedUpdatesInLevels(levelGLStart, levelGLEnd))
9827     {
9828         return angle::Result::Continue;
9829     }
9830 
9831     const gl::TexLevelMask skipLevelsAllFaces = AggregateSkipLevels(skipLevels);
9832     removeSupersededUpdates(contextVk, skipLevelsAllFaces);
9833 
9834     // If a clear is requested and we know it was previously cleared with the same value, we drop
9835     // the clear.
9836     if (mCurrentSingleClearValue.valid())
9837     {
9838         std::vector<SubresourceUpdate> *levelUpdates =
9839             getLevelUpdates(gl::LevelIndex(mCurrentSingleClearValue.value().levelIndex));
9840         if (levelUpdates && levelUpdates->size() == 1)
9841         {
9842             SubresourceUpdate &update = (*levelUpdates)[0];
9843             if (IsClearOfAllChannels(update.updateSource) &&
9844                 mCurrentSingleClearValue.value() == update.data.clear)
9845             {
9846                 ASSERT(levelGLStart + 1 == levelGLEnd);
9847                 setContentDefined(toVkLevel(levelGLStart), 1, layerStart, layerEnd - layerStart,
9848                                   update.data.clear.aspectFlags);
9849                 ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_LOW,
9850                                       "Repeated Clear on framebuffer attachment dropped");
9851                 update.release(renderer);
9852                 levelUpdates->clear();
9853                 return angle::Result::Continue;
9854             }
9855         }
9856     }
9857 
9858     ASSERT(validateSubresourceUpdateRefCountsConsistent());
9859 
9860     // Process the clear emulated channels from the updates first. They are expected to be at the
9861     // beginning of the level updates.
9862     bool otherUpdatesToFlushOut = false;
9863     clipLevelToUpdateListUpperLimit(&levelGLEnd);
9864     ANGLE_TRY(flushStagedClearEmulatedChannelsUpdates(contextVk, levelGLStart, levelGLEnd,
9865                                                       &otherUpdatesToFlushOut));
9866 
9867     // If updates remain after processing ClearEmulatedChannelsOnly updates, we should acquire the
9868     // outside command buffer and apply the necessary barriers. Otherwise, this function can return
9869     // early, skipping the next loop.
9870     if (otherUpdatesToFlushOut)
9871     {
9872         ANGLE_TRY(flushStagedUpdatesImpl(contextVk, levelGLStart, levelGLEnd, layerStart, layerEnd,
9873                                          skipLevelsAllFaces));
9874     }
9875 
9876     // Compact mSubresourceUpdates, then check if there are any updates left.
9877     size_t compactSize;
9878     for (compactSize = mSubresourceUpdates.size(); compactSize > 0; --compactSize)
9879     {
9880         if (!mSubresourceUpdates[compactSize - 1].empty())
9881         {
9882             break;
9883         }
9884     }
9885     mSubresourceUpdates.resize(compactSize);
9886 
9887     ASSERT(validateSubresourceUpdateRefCountsConsistent());
9888 
9889     // If no updates left, release the staging buffers to save memory.
9890     if (mSubresourceUpdates.empty())
9891     {
9892         ASSERT(mTotalStagedBufferUpdateSize == 0);
9893         onStateChange(angle::SubjectMessage::InitializationComplete);
9894     }
9895 
9896     return angle::Result::Continue;
9897 }
9898 
flushAllStagedUpdates(ContextVk * contextVk)9899 angle::Result ImageHelper::flushAllStagedUpdates(ContextVk *contextVk)
9900 {
9901     return flushStagedUpdates(contextVk, mFirstAllocatedLevel, mFirstAllocatedLevel + mLevelCount,
9902                               0, mLayerCount, {});
9903 }
9904 
hasStagedUpdatesForSubresource(gl::LevelIndex levelGL,uint32_t layer,uint32_t layerCount) const9905 bool ImageHelper::hasStagedUpdatesForSubresource(gl::LevelIndex levelGL,
9906                                                  uint32_t layer,
9907                                                  uint32_t layerCount) const
9908 {
9909     // Check to see if any updates are staged for the given level and layer
9910 
9911     const std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(levelGL);
9912     if (levelUpdates == nullptr || levelUpdates->empty())
9913     {
9914         return false;
9915     }
9916 
9917     for (const SubresourceUpdate &update : *levelUpdates)
9918     {
9919         uint32_t updateBaseLayer, updateLayerCount;
9920         update.getDestSubresource(mLayerCount, &updateBaseLayer, &updateLayerCount);
9921 
9922         const uint32_t updateLayerEnd = updateBaseLayer + updateLayerCount;
9923         const uint32_t layerEnd       = layer + layerCount;
9924 
9925         if ((layer >= updateBaseLayer && layer < updateLayerEnd) ||
9926             (layerEnd > updateBaseLayer && layerEnd <= updateLayerEnd))
9927         {
9928             // The layers intersect with the update range
9929             return true;
9930         }
9931     }
9932 
9933     return false;
9934 }
9935 
removeStagedClearUpdatesAndReturnColor(gl::LevelIndex levelGL,const VkClearColorValue ** color)9936 bool ImageHelper::removeStagedClearUpdatesAndReturnColor(gl::LevelIndex levelGL,
9937                                                          const VkClearColorValue **color)
9938 {
9939     std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(levelGL);
9940     if (levelUpdates == nullptr || levelUpdates->empty())
9941     {
9942         return false;
9943     }
9944 
9945     bool result = false;
9946 
9947     for (size_t index = 0; index < levelUpdates->size();)
9948     {
9949         auto update = levelUpdates->begin() + index;
9950         if (IsClearOfAllChannels(update->updateSource))
9951         {
9952             if (color != nullptr)
9953             {
9954                 *color = &update->data.clear.value.color;
9955             }
9956             levelUpdates->erase(update);
9957             result = true;
9958         }
9959     }
9960 
9961     return result;
9962 }
9963 
adjustLayerRange(const std::vector<SubresourceUpdate> & levelUpdates,uint32_t * layerStart,uint32_t * layerEnd)9964 void ImageHelper::adjustLayerRange(const std::vector<SubresourceUpdate> &levelUpdates,
9965                                    uint32_t *layerStart,
9966                                    uint32_t *layerEnd)
9967 {
9968     for (const SubresourceUpdate &update : levelUpdates)
9969     {
9970         uint32_t updateBaseLayer, updateLayerCount;
9971         update.getDestSubresource(mLayerCount, &updateBaseLayer, &updateLayerCount);
9972         uint32_t updateLayerEnd = updateBaseLayer + updateLayerCount;
9973 
9974         // In some cases, the update has the bigger layer range than the request. If the update
9975         // layers intersect the requested layers, then expand the layer range to the maximum from
9976         // the update and from the request.
9977         const bool areUpdateLayersWithinRange =
9978             updateBaseLayer < *layerEnd && updateLayerEnd > *layerStart;
9979         if (areUpdateLayersWithinRange)
9980         {
9981             *layerStart = std::min(*layerStart, updateBaseLayer);
9982             *layerEnd   = std::max(*layerEnd, updateLayerEnd);
9983         }
9984     }
9985 }
9986 
getLastAllocatedLevel() const9987 gl::LevelIndex ImageHelper::getLastAllocatedLevel() const
9988 {
9989     return mFirstAllocatedLevel + mLevelCount - 1;
9990 }
9991 
hasStagedUpdatesInAllocatedLevels() const9992 bool ImageHelper::hasStagedUpdatesInAllocatedLevels() const
9993 {
9994     return hasStagedUpdatesInLevels(mFirstAllocatedLevel, getLastAllocatedLevel() + 1);
9995 }
9996 
hasStagedUpdatesInLevels(gl::LevelIndex levelStart,gl::LevelIndex levelEnd) const9997 bool ImageHelper::hasStagedUpdatesInLevels(gl::LevelIndex levelStart, gl::LevelIndex levelEnd) const
9998 {
9999     for (gl::LevelIndex level = levelStart; level < levelEnd; ++level)
10000     {
10001         const std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(level);
10002         if (levelUpdates == nullptr)
10003         {
10004             ASSERT(static_cast<size_t>(level.get()) >= mSubresourceUpdates.size());
10005             return false;
10006         }
10007 
10008         if (!levelUpdates->empty())
10009         {
10010             return true;
10011         }
10012     }
10013     return false;
10014 }
10015 
hasStagedImageUpdatesWithMismatchedFormat(gl::LevelIndex levelStart,gl::LevelIndex levelEnd,angle::FormatID formatID) const10016 bool ImageHelper::hasStagedImageUpdatesWithMismatchedFormat(gl::LevelIndex levelStart,
10017                                                             gl::LevelIndex levelEnd,
10018                                                             angle::FormatID formatID) const
10019 {
10020     for (gl::LevelIndex level = levelStart; level < levelEnd; ++level)
10021     {
10022         const std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(level);
10023         if (levelUpdates == nullptr)
10024         {
10025             continue;
10026         }
10027 
10028         for (const SubresourceUpdate &update : *levelUpdates)
10029         {
10030             if (update.updateSource == UpdateSource::Image &&
10031                 update.data.image.formatID != formatID)
10032             {
10033                 return true;
10034             }
10035         }
10036     }
10037     return false;
10038 }
10039 
hasBufferSourcedStagedUpdatesInAllLevels() const10040 bool ImageHelper::hasBufferSourcedStagedUpdatesInAllLevels() const
10041 {
10042     for (gl::LevelIndex level = mFirstAllocatedLevel; level <= getLastAllocatedLevel(); ++level)
10043     {
10044         const std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(level);
10045         if (levelUpdates == nullptr || levelUpdates->empty())
10046         {
10047             return false;
10048         }
10049 
10050         bool hasUpdateSourceWithBuffer = false;
10051         for (const SubresourceUpdate &update : *levelUpdates)
10052         {
10053             if (update.updateSource == UpdateSource::Buffer)
10054             {
10055                 hasUpdateSourceWithBuffer = true;
10056                 break;
10057             }
10058         }
10059         if (!hasUpdateSourceWithBuffer)
10060         {
10061             return false;
10062         }
10063     }
10064     return true;
10065 }
10066 
validateSubresourceUpdateBufferRefConsistent(RefCounted<BufferHelper> * buffer) const10067 bool ImageHelper::validateSubresourceUpdateBufferRefConsistent(
10068     RefCounted<BufferHelper> *buffer) const
10069 {
10070     if (buffer == nullptr)
10071     {
10072         return true;
10073     }
10074 
10075     uint32_t refs = 0;
10076 
10077     for (const std::vector<SubresourceUpdate> &levelUpdates : mSubresourceUpdates)
10078     {
10079         for (const SubresourceUpdate &update : levelUpdates)
10080         {
10081             if (update.updateSource == UpdateSource::Buffer && update.refCounted.buffer == buffer)
10082             {
10083                 ++refs;
10084             }
10085         }
10086     }
10087 
10088     return buffer->isRefCountAsExpected(refs);
10089 }
10090 
validateSubresourceUpdateImageRefConsistent(RefCounted<ImageHelper> * image) const10091 bool ImageHelper::validateSubresourceUpdateImageRefConsistent(RefCounted<ImageHelper> *image) const
10092 {
10093     if (image == nullptr)
10094     {
10095         return true;
10096     }
10097 
10098     uint32_t refs = 0;
10099 
10100     for (const std::vector<SubresourceUpdate> &levelUpdates : mSubresourceUpdates)
10101     {
10102         for (const SubresourceUpdate &update : levelUpdates)
10103         {
10104             if (update.updateSource == UpdateSource::Image && update.refCounted.image == image)
10105             {
10106                 ++refs;
10107             }
10108         }
10109     }
10110 
10111     return image->isRefCountAsExpected(refs);
10112 }
10113 
validateSubresourceUpdateRefCountsConsistent() const10114 bool ImageHelper::validateSubresourceUpdateRefCountsConsistent() const
10115 {
10116     for (const std::vector<SubresourceUpdate> &levelUpdates : mSubresourceUpdates)
10117     {
10118         for (const SubresourceUpdate &update : levelUpdates)
10119         {
10120             if (update.updateSource == UpdateSource::Image)
10121             {
10122                 if (!validateSubresourceUpdateImageRefConsistent(update.refCounted.image))
10123                 {
10124                     return false;
10125                 }
10126             }
10127             else if (update.updateSource == UpdateSource::Buffer)
10128             {
10129                 if (!validateSubresourceUpdateBufferRefConsistent(update.refCounted.buffer))
10130                 {
10131                     return false;
10132                 }
10133             }
10134         }
10135     }
10136 
10137     return true;
10138 }
10139 
pruneSupersededUpdatesForLevel(ContextVk * contextVk,const gl::LevelIndex level,const PruneReason reason)10140 void ImageHelper::pruneSupersededUpdatesForLevel(ContextVk *contextVk,
10141                                                  const gl::LevelIndex level,
10142                                                  const PruneReason reason)
10143 {
10144     constexpr VkDeviceSize kSubresourceUpdateSizeBeforePruning = 16 * 1024 * 1024;  // 16 MB
10145     constexpr int kUpdateCountThreshold                        = 1024;
10146     std::vector<ImageHelper::SubresourceUpdate> *levelUpdates  = getLevelUpdates(level);
10147 
10148     // If we are below pruning threshold, nothing to do.
10149     const int updateCount      = static_cast<int>(levelUpdates->size());
10150     const bool withinThreshold = updateCount < kUpdateCountThreshold &&
10151                                  mTotalStagedBufferUpdateSize < kSubresourceUpdateSizeBeforePruning;
10152     if (updateCount == 1 || (reason == PruneReason::MemoryOptimization && withinThreshold))
10153     {
10154         return;
10155     }
10156 
10157     // Start from the most recent update and define a boundingBox that covers the region to be
10158     // updated. Walk through all earlier updates and if its update region is contained within the
10159     // boundingBox, mark it as superseded, otherwise reset the boundingBox and continue.
10160     //
10161     // Color, depth and stencil are the only types supported for now. The boundingBox for color and
10162     // depth types is at index 0 and index 1 has the boundingBox for stencil type.
10163     VkDeviceSize supersededUpdateSize  = 0;
10164     std::array<gl::Box, 2> boundingBox = {gl::Box(gl::kOffsetZero, gl::Extents())};
10165 
10166     auto canDropUpdate = [this, contextVk, level, &supersededUpdateSize,
10167                           &boundingBox](SubresourceUpdate &update) {
10168         VkDeviceSize updateSize       = 0;
10169         VkImageAspectFlags aspectMask = update.getDestAspectFlags();
10170         gl::Box currentUpdateBox(gl::kOffsetZero, gl::Extents());
10171 
10172         const bool isColor =
10173             (aspectMask & (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_PLANE_0_BIT |
10174                            VK_IMAGE_ASPECT_PLANE_1_BIT | VK_IMAGE_ASPECT_PLANE_2_BIT)) != 0;
10175         const bool isDepth   = (aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0;
10176         const bool isStencil = (aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0;
10177         ASSERT(isColor || isDepth || isStencil);
10178         int aspectIndex = (isColor || isDepth) ? 0 : 1;
10179 
10180         if (update.updateSource == UpdateSource::Buffer)
10181         {
10182             currentUpdateBox = gl::Box(update.data.buffer.copyRegion.imageOffset,
10183                                        update.data.buffer.copyRegion.imageExtent);
10184             updateSize       = update.data.buffer.bufferHelper->getSize();
10185         }
10186         else if (update.updateSource == UpdateSource::Image)
10187         {
10188             currentUpdateBox = gl::Box(update.data.image.copyRegion.dstOffset,
10189                                        update.data.image.copyRegion.extent);
10190         }
10191         else
10192         {
10193             ASSERT(IsClear(update.updateSource));
10194             currentUpdateBox = gl::Box(gl::kOffsetZero, getLevelExtents(toVkLevel(level)));
10195         }
10196 
10197         // Account for updates to layered images
10198         uint32_t layerIndex = 0;
10199         uint32_t layerCount = 0;
10200         update.getDestSubresource(mLayerCount, &layerIndex, &layerCount);
10201         if (layerIndex > 0 || layerCount > 1)
10202         {
10203             currentUpdateBox.z     = layerIndex;
10204             currentUpdateBox.depth = layerCount;
10205         }
10206 
10207         // Check if current update region is superseded by the accumulated update region
10208         if (boundingBox[aspectIndex].contains(currentUpdateBox))
10209         {
10210             ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_LOW,
10211                                   "Dropped texture update that is superseded by a more recent one");
10212 
10213             // Release the superseded update
10214             update.release(contextVk->getRenderer());
10215 
10216             // Update pruning size
10217             supersededUpdateSize += updateSize;
10218 
10219             return true;
10220         }
10221         else
10222         {
10223             // Extend boundingBox to best accommodate current update's box.
10224             boundingBox[aspectIndex].extend(currentUpdateBox);
10225             // If the volume of the current update box is larger than the extended boundingBox
10226             // use that as the new boundingBox instead.
10227             if (currentUpdateBox.volume() > boundingBox[aspectIndex].volume())
10228             {
10229                 boundingBox[aspectIndex] = currentUpdateBox;
10230             }
10231             return false;
10232         }
10233     };
10234 
10235     levelUpdates->erase(
10236         levelUpdates->begin(),
10237         std::remove_if(levelUpdates->rbegin(), levelUpdates->rend(), canDropUpdate).base());
10238 
10239     // Update total staging buffer size
10240     mTotalStagedBufferUpdateSize -= supersededUpdateSize;
10241 }
10242 
removeSupersededUpdates(ContextVk * contextVk,const gl::TexLevelMask skipLevelsAllFaces)10243 void ImageHelper::removeSupersededUpdates(ContextVk *contextVk,
10244                                           const gl::TexLevelMask skipLevelsAllFaces)
10245 {
10246     ASSERT(validateSubresourceUpdateRefCountsConsistent());
10247 
10248     for (LevelIndex levelVk(0); levelVk < LevelIndex(mLevelCount); ++levelVk)
10249     {
10250         gl::LevelIndex levelGL                       = toGLLevel(levelVk);
10251         std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(levelGL);
10252         if (levelUpdates == nullptr || levelUpdates->size() == 0 ||
10253             skipLevelsAllFaces.test(levelGL.get()))
10254         {
10255             // There are no valid updates to process, continue.
10256             continue;
10257         }
10258 
10259         // ClearEmulatedChannelsOnly updates can only be in the beginning of the list of updates.
10260         // They don't entirely clear the image, so they cannot supersede any update.
10261         ASSERT(verifyEmulatedClearsAreBeforeOtherUpdates(*levelUpdates));
10262 
10263         pruneSupersededUpdatesForLevel(contextVk, levelGL, PruneReason::MinimizeWorkBeforeFlush);
10264     }
10265 
10266     ASSERT(validateSubresourceUpdateRefCountsConsistent());
10267 }
10268 
copyImageDataToBuffer(ContextVk * contextVk,gl::LevelIndex sourceLevelGL,uint32_t layerCount,uint32_t baseLayer,const gl::Box & sourceArea,BufferHelper * dstBuffer,uint8_t ** outDataPtr)10269 angle::Result ImageHelper::copyImageDataToBuffer(ContextVk *contextVk,
10270                                                  gl::LevelIndex sourceLevelGL,
10271                                                  uint32_t layerCount,
10272                                                  uint32_t baseLayer,
10273                                                  const gl::Box &sourceArea,
10274                                                  BufferHelper *dstBuffer,
10275                                                  uint8_t **outDataPtr)
10276 {
10277     ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::copyImageDataToBuffer");
10278     Renderer *renderer = contextVk->getRenderer();
10279 
10280     const angle::Format &imageFormat = getActualFormat();
10281 
10282     // As noted in the OpenGL ES 3.2 specs, table 8.13, CopyTexImage cannot
10283     // be used for depth textures. There is no way for the image or buffer
10284     // used in this function to be of some combined depth and stencil format.
10285     ASSERT(getAspectFlags() == VK_IMAGE_ASPECT_COLOR_BIT);
10286 
10287     uint32_t pixelBytes = imageFormat.pixelBytes;
10288     size_t bufferSize =
10289         sourceArea.width * sourceArea.height * sourceArea.depth * pixelBytes * layerCount;
10290 
10291     const VkImageAspectFlags aspectFlags = getAspectFlags();
10292 
10293     // Allocate staging buffer prefer coherent
10294     ASSERT(dstBuffer != nullptr && !dstBuffer->valid());
10295     VkDeviceSize dstOffset;
10296     ANGLE_TRY(contextVk->initBufferForImageCopy(dstBuffer, bufferSize,
10297                                                 MemoryCoherency::CachedPreferCoherent,
10298                                                 imageFormat.id, &dstOffset, outDataPtr));
10299     ANGLE_TRY(dstBuffer->flush(contextVk->getRenderer()));
10300 
10301     VkBuffer bufferHandle = dstBuffer->getBuffer().getHandle();
10302 
10303     LevelIndex sourceLevelVk = toVkLevel(sourceLevelGL);
10304 
10305     VkBufferImageCopy regions = {};
10306     uint32_t regionCount      = 1;
10307     // Default to non-combined DS case
10308     regions.bufferOffset                    = dstOffset;
10309     regions.bufferRowLength                 = 0;
10310     regions.bufferImageHeight               = 0;
10311     regions.imageExtent.width               = sourceArea.width;
10312     regions.imageExtent.height              = sourceArea.height;
10313     regions.imageExtent.depth               = sourceArea.depth;
10314     regions.imageOffset.x                   = sourceArea.x;
10315     regions.imageOffset.y                   = sourceArea.y;
10316     regions.imageOffset.z                   = sourceArea.z;
10317     regions.imageSubresource.aspectMask     = aspectFlags;
10318     regions.imageSubresource.baseArrayLayer = baseLayer;
10319     regions.imageSubresource.layerCount     = layerCount;
10320     regions.imageSubresource.mipLevel       = sourceLevelVk.get();
10321 
10322     CommandBufferAccess access;
10323     access.onBufferTransferWrite(dstBuffer);
10324     access.onImageTransferRead(aspectFlags, this);
10325 
10326     OutsideRenderPassCommandBuffer *commandBuffer;
10327     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
10328 
10329     commandBuffer->copyImageToBuffer(mImage, getCurrentLayout(renderer), bufferHandle, regionCount,
10330                                      &regions);
10331     // Track completion of this copy.
10332     contextVk->trackImageWithOutsideRenderPassEvent(this);
10333 
10334     return angle::Result::Continue;
10335 }
10336 
copySurfaceImageToBuffer(DisplayVk * displayVk,gl::LevelIndex sourceLevelGL,uint32_t layerCount,uint32_t baseLayer,const gl::Box & sourceArea,vk::BufferHelper * bufferHelper)10337 angle::Result ImageHelper::copySurfaceImageToBuffer(DisplayVk *displayVk,
10338                                                     gl::LevelIndex sourceLevelGL,
10339                                                     uint32_t layerCount,
10340                                                     uint32_t baseLayer,
10341                                                     const gl::Box &sourceArea,
10342                                                     vk::BufferHelper *bufferHelper)
10343 {
10344     ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::copySurfaceImageToBuffer");
10345 
10346     Renderer *renderer = displayVk->getRenderer();
10347 
10348     VkBufferImageCopy region               = {};
10349     region.bufferOffset                    = 0;
10350     region.bufferRowLength                 = 0;
10351     region.bufferImageHeight               = 0;
10352     region.imageExtent.width               = sourceArea.width;
10353     region.imageExtent.height              = sourceArea.height;
10354     region.imageExtent.depth               = sourceArea.depth;
10355     region.imageOffset.x                   = sourceArea.x;
10356     region.imageOffset.y                   = sourceArea.y;
10357     region.imageOffset.z                   = sourceArea.z;
10358     region.imageSubresource.aspectMask     = getAspectFlags();
10359     region.imageSubresource.baseArrayLayer = baseLayer;
10360     region.imageSubresource.layerCount     = layerCount;
10361     region.imageSubresource.mipLevel       = toVkLevel(sourceLevelGL).get();
10362 
10363     // We may have a valid event here but we do not have a collector to collect it. Release the
10364     // event here to force pipelineBarrier.
10365     mCurrentEvent.release(displayVk->getRenderer());
10366 
10367     PrimaryCommandBuffer primaryCommandBuffer;
10368     ANGLE_TRY(renderer->getCommandBufferOneOff(displayVk, ProtectionType::Unprotected,
10369                                                &primaryCommandBuffer));
10370 
10371     VkSemaphore acquireNextImageSemaphore;
10372     barrierImpl(displayVk, getAspectFlags(), ImageLayout::TransferSrc,
10373                 displayVk->getDeviceQueueIndex(), nullptr, &primaryCommandBuffer,
10374                 &acquireNextImageSemaphore);
10375     primaryCommandBuffer.copyImageToBuffer(mImage, getCurrentLayout(renderer),
10376                                            bufferHelper->getBuffer().getHandle(), 1, &region);
10377 
10378     ANGLE_VK_TRY(displayVk, primaryCommandBuffer.end());
10379 
10380     QueueSerial submitQueueSerial;
10381     ANGLE_TRY(renderer->queueSubmitOneOff(
10382         displayVk, std::move(primaryCommandBuffer), ProtectionType::Unprotected,
10383         egl::ContextPriority::Medium, acquireNextImageSemaphore,
10384         kSwapchainAcquireImageWaitStageFlags, vk::SubmitPolicy::AllowDeferred, &submitQueueSerial));
10385 
10386     return renderer->finishQueueSerial(displayVk, submitQueueSerial);
10387 }
10388 
copyBufferToSurfaceImage(DisplayVk * displayVk,gl::LevelIndex sourceLevelGL,uint32_t layerCount,uint32_t baseLayer,const gl::Box & sourceArea,vk::BufferHelper * bufferHelper)10389 angle::Result ImageHelper::copyBufferToSurfaceImage(DisplayVk *displayVk,
10390                                                     gl::LevelIndex sourceLevelGL,
10391                                                     uint32_t layerCount,
10392                                                     uint32_t baseLayer,
10393                                                     const gl::Box &sourceArea,
10394                                                     vk::BufferHelper *bufferHelper)
10395 {
10396     ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::copyBufferToSurfaceImage");
10397 
10398     Renderer *renderer = displayVk->getRenderer();
10399 
10400     VkBufferImageCopy region               = {};
10401     region.bufferOffset                    = 0;
10402     region.bufferRowLength                 = 0;
10403     region.bufferImageHeight               = 0;
10404     region.imageExtent.width               = sourceArea.width;
10405     region.imageExtent.height              = sourceArea.height;
10406     region.imageExtent.depth               = sourceArea.depth;
10407     region.imageOffset.x                   = sourceArea.x;
10408     region.imageOffset.y                   = sourceArea.y;
10409     region.imageOffset.z                   = sourceArea.z;
10410     region.imageSubresource.aspectMask     = getAspectFlags();
10411     region.imageSubresource.baseArrayLayer = baseLayer;
10412     region.imageSubresource.layerCount     = layerCount;
10413     region.imageSubresource.mipLevel       = toVkLevel(sourceLevelGL).get();
10414 
10415     // We may have a valid event here but we do not have a collector to collect it. Release the
10416     // event here to force pipelineBarrier.
10417     mCurrentEvent.release(displayVk->getRenderer());
10418 
10419     PrimaryCommandBuffer commandBuffer;
10420     ANGLE_TRY(
10421         renderer->getCommandBufferOneOff(displayVk, ProtectionType::Unprotected, &commandBuffer));
10422 
10423     VkSemaphore acquireNextImageSemaphore;
10424     barrierImpl(displayVk, getAspectFlags(), ImageLayout::TransferDst,
10425                 displayVk->getDeviceQueueIndex(), nullptr, &commandBuffer,
10426                 &acquireNextImageSemaphore);
10427     commandBuffer.copyBufferToImage(bufferHelper->getBuffer().getHandle(), mImage,
10428                                     getCurrentLayout(renderer), 1, &region);
10429 
10430     ANGLE_VK_TRY(displayVk, commandBuffer.end());
10431 
10432     QueueSerial submitQueueSerial;
10433     ANGLE_TRY(renderer->queueSubmitOneOff(
10434         displayVk, std::move(commandBuffer), ProtectionType::Unprotected,
10435         egl::ContextPriority::Medium, acquireNextImageSemaphore,
10436         kSwapchainAcquireImageWaitStageFlags, vk::SubmitPolicy::AllowDeferred, &submitQueueSerial));
10437 
10438     return renderer->finishQueueSerial(displayVk, submitQueueSerial);
10439 }
10440 
10441 // 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)10442 angle::Result ImageHelper::GetReadPixelsParams(ContextVk *contextVk,
10443                                                const gl::PixelPackState &packState,
10444                                                gl::Buffer *packBuffer,
10445                                                GLenum format,
10446                                                GLenum type,
10447                                                const gl::Rectangle &area,
10448                                                const gl::Rectangle &clippedArea,
10449                                                PackPixelsParams *paramsOut,
10450                                                GLuint *skipBytesOut)
10451 {
10452     const gl::InternalFormat &sizedFormatInfo = gl::GetInternalFormatInfo(format, type);
10453 
10454     GLuint outputPitch = 0;
10455     ANGLE_VK_CHECK_MATH(contextVk,
10456                         sizedFormatInfo.computeRowPitch(type, area.width, packState.alignment,
10457                                                         packState.rowLength, &outputPitch));
10458     ANGLE_VK_CHECK_MATH(contextVk, sizedFormatInfo.computeSkipBytes(type, outputPitch, 0, packState,
10459                                                                     false, skipBytesOut));
10460 
10461     ANGLE_TRY(GetPackPixelsParams(sizedFormatInfo, outputPitch, packState, packBuffer, area,
10462                                   clippedArea, paramsOut, skipBytesOut));
10463     return angle::Result::Continue;
10464 }
10465 
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)10466 angle::Result ImageHelper::readPixelsForGetImage(ContextVk *contextVk,
10467                                                  const gl::PixelPackState &packState,
10468                                                  gl::Buffer *packBuffer,
10469                                                  gl::LevelIndex levelGL,
10470                                                  uint32_t layer,
10471                                                  uint32_t layerCount,
10472                                                  GLenum format,
10473                                                  GLenum type,
10474                                                  void *pixels)
10475 {
10476     const angle::Format &angleFormat = GetFormatFromFormatType(format, type);
10477 
10478     VkImageAspectFlagBits aspectFlags = {};
10479     if (angleFormat.redBits > 0 || angleFormat.blueBits > 0 || angleFormat.greenBits > 0 ||
10480         angleFormat.alphaBits > 0 || angleFormat.luminanceBits > 0)
10481     {
10482         aspectFlags = static_cast<VkImageAspectFlagBits>(aspectFlags | VK_IMAGE_ASPECT_COLOR_BIT);
10483     }
10484     else
10485     {
10486         if (angleFormat.depthBits > 0)
10487         {
10488             aspectFlags =
10489                 static_cast<VkImageAspectFlagBits>(aspectFlags | VK_IMAGE_ASPECT_DEPTH_BIT);
10490         }
10491         if (angleFormat.stencilBits > 0)
10492         {
10493             aspectFlags =
10494                 static_cast<VkImageAspectFlagBits>(aspectFlags | VK_IMAGE_ASPECT_STENCIL_BIT);
10495         }
10496     }
10497 
10498     ASSERT(aspectFlags != 0);
10499 
10500     PackPixelsParams params;
10501     GLuint outputSkipBytes = 0;
10502 
10503     const LevelIndex levelVk     = toVkLevel(levelGL);
10504     const gl::Extents mipExtents = getLevelExtents(levelVk);
10505     gl::Rectangle area(0, 0, mipExtents.width, mipExtents.height);
10506 
10507     ANGLE_TRY(GetReadPixelsParams(contextVk, packState, packBuffer, format, type, area, area,
10508                                   &params, &outputSkipBytes));
10509 
10510     if (mExtents.depth > 1 || layerCount > 1)
10511     {
10512         ASSERT(layer == 0);
10513         ASSERT(layerCount == 1 || mipExtents.depth == 1);
10514 
10515         uint32_t lastLayer = std::max(static_cast<uint32_t>(mipExtents.depth), layerCount);
10516 
10517         // Depth > 1 means this is a 3D texture and we need to copy all layers
10518         for (uint32_t mipLayer = 0; mipLayer < lastLayer; mipLayer++)
10519         {
10520             ANGLE_TRY(readPixels(contextVk, area, params, aspectFlags, levelGL, mipLayer,
10521                                  static_cast<uint8_t *>(pixels) + outputSkipBytes));
10522 
10523             outputSkipBytes += mipExtents.width * mipExtents.height *
10524                                gl::GetInternalFormatInfo(format, type).pixelBytes;
10525         }
10526     }
10527     else
10528     {
10529         ANGLE_TRY(readPixels(contextVk, area, params, aspectFlags, levelGL, layer,
10530                              static_cast<uint8_t *>(pixels) + outputSkipBytes));
10531     }
10532 
10533     return angle::Result::Continue;
10534 }
10535 
readPixelsForCompressedGetImage(ContextVk * contextVk,const gl::PixelPackState & packState,gl::Buffer * packBuffer,gl::LevelIndex levelGL,uint32_t layer,uint32_t layerCount,void * pixels)10536 angle::Result ImageHelper::readPixelsForCompressedGetImage(ContextVk *contextVk,
10537                                                            const gl::PixelPackState &packState,
10538                                                            gl::Buffer *packBuffer,
10539                                                            gl::LevelIndex levelGL,
10540                                                            uint32_t layer,
10541                                                            uint32_t layerCount,
10542                                                            void *pixels)
10543 {
10544     PackPixelsParams params;
10545     GLuint outputSkipBytes = 0;
10546 
10547     const LevelIndex levelVk = toVkLevel(levelGL);
10548     gl::Extents mipExtents   = getLevelExtents(levelVk);
10549     gl::Rectangle area(0, 0, mipExtents.width, mipExtents.height);
10550 
10551     VkImageAspectFlagBits aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT;
10552 
10553     const angle::Format *readFormat = &getActualFormat();
10554 
10555     // TODO(anglebug.com/6177): Implement encoding for emuluated compression formats
10556     ANGLE_VK_CHECK(contextVk, readFormat->isBlock, VK_ERROR_FORMAT_NOT_SUPPORTED);
10557 
10558     if (mExtents.depth > 1 || layerCount > 1)
10559     {
10560         ASSERT(layer == 0);
10561         ASSERT(layerCount == 1 || mipExtents.depth == 1);
10562 
10563         uint32_t lastLayer = std::max(static_cast<uint32_t>(mipExtents.depth), layerCount);
10564 
10565         const vk::Format &vkFormat = contextVk->getRenderer()->getFormat(readFormat->id);
10566         const gl::InternalFormat &storageFormatInfo =
10567             vkFormat.getInternalFormatInfo(readFormat->componentType);
10568 
10569         // Calculate size for one layer
10570         mipExtents.depth = 1;
10571         GLuint layerSize;
10572         ANGLE_VK_CHECK_MATH(contextVk,
10573                             storageFormatInfo.computeCompressedImageSize(mipExtents, &layerSize));
10574 
10575         // Depth > 1 means this is a 3D texture and we need to copy all layers
10576         for (uint32_t mipLayer = 0; mipLayer < lastLayer; mipLayer++)
10577         {
10578             ANGLE_TRY(readPixels(contextVk, area, params, aspectFlags, levelGL, mipLayer,
10579                                  static_cast<uint8_t *>(pixels) + outputSkipBytes));
10580             outputSkipBytes += layerSize;
10581         }
10582     }
10583     else
10584     {
10585         ANGLE_TRY(readPixels(contextVk, area, params, aspectFlags, levelGL, layer,
10586                              static_cast<uint8_t *>(pixels) + outputSkipBytes));
10587     }
10588 
10589     return angle::Result::Continue;
10590 }
10591 
readPixelsWithCompute(ContextVk * contextVk,ImageHelper * src,const PackPixelsParams & packPixelsParams,const VkOffset3D & srcOffset,const VkExtent3D & srcExtent,ptrdiff_t pixelsOffset,const VkImageSubresourceLayers & srcSubresource)10592 angle::Result ImageHelper::readPixelsWithCompute(ContextVk *contextVk,
10593                                                  ImageHelper *src,
10594                                                  const PackPixelsParams &packPixelsParams,
10595                                                  const VkOffset3D &srcOffset,
10596                                                  const VkExtent3D &srcExtent,
10597                                                  ptrdiff_t pixelsOffset,
10598                                                  const VkImageSubresourceLayers &srcSubresource)
10599 {
10600     ASSERT(srcOffset.z == 0 || srcSubresource.baseArrayLayer == 0);
10601 
10602     UtilsVk::CopyImageToBufferParameters params = {};
10603     params.srcOffset[0]                         = srcOffset.x;
10604     params.srcOffset[1]                         = srcOffset.y;
10605     params.srcLayer        = std::max<uint32_t>(srcOffset.z, srcSubresource.baseArrayLayer);
10606     params.srcMip          = LevelIndex(srcSubresource.mipLevel);
10607     params.size[0]         = srcExtent.width;
10608     params.size[1]         = srcExtent.height;
10609     params.outputOffset    = packPixelsParams.offset + pixelsOffset;
10610     params.outputPitch     = packPixelsParams.outputPitch;
10611     params.reverseRowOrder = packPixelsParams.reverseRowOrder;
10612     params.outputFormat    = packPixelsParams.destFormat;
10613 
10614     BufferHelper &packBuffer = GetImpl(packPixelsParams.packBuffer)->getBuffer();
10615 
10616     return contextVk->getUtils().copyImageToBuffer(contextVk, &packBuffer, src, params);
10617 }
10618 
canCopyWithTransformForReadPixels(const PackPixelsParams & packPixelsParams,const angle::Format * readFormat,ptrdiff_t pixelsOffset)10619 bool ImageHelper::canCopyWithTransformForReadPixels(const PackPixelsParams &packPixelsParams,
10620                                                     const angle::Format *readFormat,
10621                                                     ptrdiff_t pixelsOffset)
10622 {
10623     ASSERT(mActualFormatID != angle::FormatID::NONE && mIntendedFormatID != angle::FormatID::NONE);
10624 
10625     // Only allow copies to PBOs with identical format.
10626     const bool isSameFormatCopy = *readFormat == *packPixelsParams.destFormat;
10627 
10628     // Disallow any transformation.
10629     const bool needsTransformation =
10630         packPixelsParams.rotation != SurfaceRotation::Identity || packPixelsParams.reverseRowOrder;
10631 
10632     // Disallow copies when the output pitch cannot be correctly specified in Vulkan.
10633     const bool isPitchMultipleOfTexelSize =
10634         packPixelsParams.outputPitch % readFormat->pixelBytes == 0;
10635 
10636     // Disallow copies when PBO offset violates Vulkan bufferOffset alignment requirements.
10637     const BufferHelper &packBuffer = GetImpl(packPixelsParams.packBuffer)->getBuffer();
10638     const VkDeviceSize offset = packBuffer.getOffset() + packPixelsParams.offset + pixelsOffset;
10639     const bool isOffsetMultipleOfTexelSize = offset % readFormat->pixelBytes == 0;
10640 
10641     // Don't allow copies from emulated formats for simplicity.
10642     return !hasEmulatedImageFormat() && isSameFormatCopy && !needsTransformation &&
10643            isPitchMultipleOfTexelSize && isOffsetMultipleOfTexelSize;
10644 }
10645 
canCopyWithComputeForReadPixels(const PackPixelsParams & packPixelsParams,const angle::Format * readFormat,ptrdiff_t pixelsOffset)10646 bool ImageHelper::canCopyWithComputeForReadPixels(const PackPixelsParams &packPixelsParams,
10647                                                   const angle::Format *readFormat,
10648                                                   ptrdiff_t pixelsOffset)
10649 {
10650     ASSERT(mActualFormatID != angle::FormatID::NONE && mIntendedFormatID != angle::FormatID::NONE);
10651     const angle::Format *writeFormat = packPixelsParams.destFormat;
10652 
10653     // For now, only float formats are supported with 4-byte 4-channel normalized pixels for output.
10654     const bool isFloat =
10655         !readFormat->isSint() && !readFormat->isUint() && !readFormat->hasDepthOrStencilBits();
10656     const bool isFourByteOutput   = writeFormat->pixelBytes == 4 && writeFormat->channelCount == 4;
10657     const bool isNormalizedOutput = writeFormat->isUnorm() || writeFormat->isSnorm();
10658 
10659     // Disallow rotation.
10660     const bool needsTransformation = packPixelsParams.rotation != SurfaceRotation::Identity;
10661 
10662     // Disallow copies when the output pitch cannot be correctly specified in Vulkan.
10663     const bool isPitchMultipleOfTexelSize =
10664         packPixelsParams.outputPitch % readFormat->pixelBytes == 0;
10665 
10666     // Disallow copies when the output offset is not aligned to uint32_t
10667     const bool isOffsetMultipleOfUint =
10668         (packPixelsParams.offset + pixelsOffset) % readFormat->pixelBytes == 0;
10669 
10670     return isFloat && isFourByteOutput && isNormalizedOutput && !needsTransformation &&
10671            isPitchMultipleOfTexelSize && isOffsetMultipleOfUint;
10672 }
10673 
readPixels(ContextVk * contextVk,const gl::Rectangle & area,const PackPixelsParams & packPixelsParams,VkImageAspectFlagBits copyAspectFlags,gl::LevelIndex levelGL,uint32_t layer,void * pixels)10674 angle::Result ImageHelper::readPixels(ContextVk *contextVk,
10675                                       const gl::Rectangle &area,
10676                                       const PackPixelsParams &packPixelsParams,
10677                                       VkImageAspectFlagBits copyAspectFlags,
10678                                       gl::LevelIndex levelGL,
10679                                       uint32_t layer,
10680                                       void *pixels)
10681 {
10682     ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::readPixels");
10683 
10684     const angle::Format &readFormat = getActualFormat();
10685 
10686     if (readFormat.depthBits == 0)
10687     {
10688         copyAspectFlags =
10689             static_cast<VkImageAspectFlagBits>(copyAspectFlags & ~VK_IMAGE_ASPECT_DEPTH_BIT);
10690     }
10691     if (readFormat.stencilBits == 0)
10692     {
10693         copyAspectFlags =
10694             static_cast<VkImageAspectFlagBits>(copyAspectFlags & ~VK_IMAGE_ASPECT_STENCIL_BIT);
10695     }
10696 
10697     if (copyAspectFlags == IMAGE_ASPECT_DEPTH_STENCIL)
10698     {
10699         const angle::Format &depthFormat =
10700             GetDepthStencilImageToBufferFormat(readFormat, VK_IMAGE_ASPECT_DEPTH_BIT);
10701         const angle::Format &stencilFormat =
10702             GetDepthStencilImageToBufferFormat(readFormat, VK_IMAGE_ASPECT_STENCIL_BIT);
10703 
10704         int depthOffset   = 0;
10705         int stencilOffset = 0;
10706         switch (readFormat.id)
10707         {
10708             case angle::FormatID::D24_UNORM_S8_UINT:
10709                 depthOffset   = 1;
10710                 stencilOffset = 0;
10711                 break;
10712 
10713             case angle::FormatID::D32_FLOAT_S8X24_UINT:
10714                 depthOffset   = 0;
10715                 stencilOffset = 4;
10716                 break;
10717 
10718             default:
10719                 UNREACHABLE();
10720         }
10721 
10722         ASSERT(depthOffset > 0 || stencilOffset > 0);
10723         ASSERT(depthOffset + depthFormat.depthBits / 8 <= readFormat.pixelBytes);
10724         ASSERT(stencilOffset + stencilFormat.stencilBits / 8 <= readFormat.pixelBytes);
10725 
10726         // Read the depth values, tightly-packed
10727         angle::MemoryBuffer depthBuffer;
10728         ANGLE_VK_CHECK_ALLOC(contextVk,
10729                              depthBuffer.resize(depthFormat.pixelBytes * area.width * area.height));
10730         ANGLE_TRY(
10731             readPixelsImpl(contextVk, area,
10732                            PackPixelsParams(area, depthFormat, depthFormat.pixelBytes * area.width,
10733                                             false, nullptr, 0),
10734                            VK_IMAGE_ASPECT_DEPTH_BIT, levelGL, layer, depthBuffer.data()));
10735 
10736         // Read the stencil values, tightly-packed
10737         angle::MemoryBuffer stencilBuffer;
10738         ANGLE_VK_CHECK_ALLOC(
10739             contextVk, stencilBuffer.resize(stencilFormat.pixelBytes * area.width * area.height));
10740         ANGLE_TRY(readPixelsImpl(
10741             contextVk, area,
10742             PackPixelsParams(area, stencilFormat, stencilFormat.pixelBytes * area.width, false,
10743                              nullptr, 0),
10744             VK_IMAGE_ASPECT_STENCIL_BIT, levelGL, layer, stencilBuffer.data()));
10745 
10746         // Interleave them together
10747         angle::MemoryBuffer readPixelBuffer;
10748         ANGLE_VK_CHECK_ALLOC(
10749             contextVk, readPixelBuffer.resize(readFormat.pixelBytes * area.width * area.height));
10750         readPixelBuffer.fill(0);
10751         for (int i = 0; i < area.width * area.height; i++)
10752         {
10753             uint8_t *readPixel = readPixelBuffer.data() + i * readFormat.pixelBytes;
10754             memcpy(readPixel + depthOffset, depthBuffer.data() + i * depthFormat.pixelBytes,
10755                    depthFormat.depthBits / 8);
10756             memcpy(readPixel + stencilOffset, stencilBuffer.data() + i * stencilFormat.pixelBytes,
10757                    stencilFormat.stencilBits / 8);
10758         }
10759 
10760         // Pack the interleaved depth and stencil into user-provided
10761         // destination, per user's pack pixels params
10762 
10763         // The compressed format path in packReadPixelBuffer isn't applicable
10764         // to our case, let's make extra sure we won't hit it
10765         ASSERT(!readFormat.isBlock);
10766         return packReadPixelBuffer(contextVk, area, packPixelsParams, readFormat, readFormat,
10767                                    readPixelBuffer.data(), levelGL, pixels);
10768     }
10769 
10770     return readPixelsImpl(contextVk, area, packPixelsParams, copyAspectFlags, levelGL, layer,
10771                           pixels);
10772 }
10773 
readPixelsImpl(ContextVk * contextVk,const gl::Rectangle & area,const PackPixelsParams & packPixelsParams,VkImageAspectFlagBits copyAspectFlags,gl::LevelIndex levelGL,uint32_t layer,void * pixels)10774 angle::Result ImageHelper::readPixelsImpl(ContextVk *contextVk,
10775                                           const gl::Rectangle &area,
10776                                           const PackPixelsParams &packPixelsParams,
10777                                           VkImageAspectFlagBits copyAspectFlags,
10778                                           gl::LevelIndex levelGL,
10779                                           uint32_t layer,
10780                                           void *pixels)
10781 {
10782     ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::readPixelsImpl");
10783 
10784     Renderer *renderer = contextVk->getRenderer();
10785 
10786     bool isExternalFormat = getExternalFormat() != 0;
10787     ASSERT(!isExternalFormat || (mActualFormatID >= angle::FormatID::EXTERNAL0 &&
10788                                  mActualFormatID <= angle::FormatID::EXTERNAL7));
10789 
10790     // If the source image is multisampled, we need to resolve it into a temporary image before
10791     // performing a readback.
10792     bool isMultisampled = mSamples > 1;
10793     RendererScoped<ImageHelper> resolvedImage(contextVk->getRenderer());
10794 
10795     ImageHelper *src = this;
10796 
10797     ASSERT(!hasStagedUpdatesForSubresource(levelGL, layer, 1));
10798 
10799     if (isMultisampled)
10800     {
10801         ANGLE_TRY(resolvedImage.get().init2DStaging(
10802             contextVk, contextVk->getState().hasProtectedContent(), renderer->getMemoryProperties(),
10803             gl::Extents(area.width, area.height, 1), mIntendedFormatID, mActualFormatID,
10804             VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, 1));
10805     }
10806     else if (isExternalFormat)
10807     {
10808         ANGLE_TRY(resolvedImage.get().init2DStaging(
10809             contextVk, contextVk->getState().hasProtectedContent(), renderer->getMemoryProperties(),
10810             gl::Extents(area.width, area.height, 1), angle::FormatID::R8G8B8A8_UNORM,
10811             angle::FormatID::R8G8B8A8_UNORM,
10812             VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
10813                 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
10814             1));
10815     }
10816 
10817     VkImageAspectFlags layoutChangeAspectFlags = src->getAspectFlags();
10818 
10819     const angle::Format *rgbaFormat = &angle::Format::Get(angle::FormatID::R8G8B8A8_UNORM);
10820     const angle::Format *readFormat = isExternalFormat ? rgbaFormat : &getActualFormat();
10821     const vk::Format &vkFormat      = contextVk->getRenderer()->getFormat(readFormat->id);
10822     const gl::InternalFormat &storageFormatInfo =
10823         vkFormat.getInternalFormatInfo(readFormat->componentType);
10824 
10825     if (copyAspectFlags != VK_IMAGE_ASPECT_COLOR_BIT)
10826     {
10827         readFormat = &GetDepthStencilImageToBufferFormat(*readFormat, copyAspectFlags);
10828     }
10829 
10830     VkOffset3D srcOffset = {area.x, area.y, 0};
10831 
10832     VkImageSubresourceLayers srcSubresource = {};
10833     srcSubresource.aspectMask               = copyAspectFlags;
10834     srcSubresource.mipLevel                 = toVkLevel(levelGL).get();
10835     srcSubresource.baseArrayLayer           = layer;
10836     srcSubresource.layerCount               = 1;
10837 
10838     VkExtent3D srcExtent = {static_cast<uint32_t>(area.width), static_cast<uint32_t>(area.height),
10839                             1};
10840 
10841     if (mExtents.depth > 1)
10842     {
10843         // Depth > 1 means this is a 3D texture and we need special handling
10844         srcOffset.z                   = layer;
10845         srcSubresource.baseArrayLayer = 0;
10846     }
10847 
10848     if (isExternalFormat)
10849     {
10850         CommandBufferAccess access;
10851         access.onImageTransferRead(layoutChangeAspectFlags, this);
10852         OutsideRenderPassCommandBuffer *commandBuffer;
10853         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
10854 
10855         // Create some temp views because copyImage works in terms of them
10856         gl::TextureType textureType = Get2DTextureType(1, resolvedImage.get().getSamples());
10857 
10858         // Surely we have a view of this already!
10859         vk::ImageView srcView;
10860         ANGLE_TRY(src->initImageView(contextVk, textureType, VK_IMAGE_ASPECT_COLOR_BIT,
10861                                      gl::SwizzleState(), &srcView, vk::LevelIndex(0), 1,
10862                                      vk::ImageHelper::kDefaultImageViewUsageFlags));
10863         vk::ImageView stagingView;
10864         ANGLE_TRY(resolvedImage.get().initImageView(
10865             contextVk, textureType, VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(), &stagingView,
10866             vk::LevelIndex(0), 1, vk::ImageHelper::kDefaultImageViewUsageFlags));
10867 
10868         UtilsVk::CopyImageParameters params = {};
10869         params.srcOffset[0]                 = srcOffset.x;
10870         params.srcOffset[1]                 = srcOffset.y;
10871         params.srcExtents[0]                = srcExtent.width;
10872         params.srcExtents[1]                = srcExtent.height;
10873         params.srcHeight                    = srcExtent.height;
10874         ANGLE_TRY(contextVk->getUtils().copyImage(contextVk, &resolvedImage.get(), &stagingView,
10875                                                   src, &srcView, params));
10876 
10877         CommandBufferAccess readAccess;
10878         readAccess.onImageTransferRead(layoutChangeAspectFlags, &resolvedImage.get());
10879         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(readAccess, &commandBuffer));
10880 
10881         // Make the resolved image the target of buffer copy
10882         src                           = &resolvedImage.get();
10883         srcOffset                     = {0, 0, 0};
10884         srcSubresource.baseArrayLayer = 0;
10885         srcSubresource.layerCount     = 1;
10886         srcSubresource.mipLevel       = 0;
10887 
10888         // Mark our temp views as garbage immediately
10889         contextVk->addGarbage(&srcView);
10890         contextVk->addGarbage(&stagingView);
10891     }
10892 
10893     if (isMultisampled)
10894     {
10895         CommandBufferAccess access;
10896         access.onImageTransferRead(layoutChangeAspectFlags, this);
10897         access.onImageTransferWrite(gl::LevelIndex(0), 1, 0, 1, layoutChangeAspectFlags,
10898                                     &resolvedImage.get());
10899 
10900         OutsideRenderPassCommandBuffer *commandBuffer;
10901         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
10902 
10903         // Note: resolve only works on color images (not depth/stencil).
10904         ASSERT(copyAspectFlags == VK_IMAGE_ASPECT_COLOR_BIT);
10905 
10906         VkImageResolve resolveRegion                = {};
10907         resolveRegion.srcSubresource                = srcSubresource;
10908         resolveRegion.srcOffset                     = srcOffset;
10909         resolveRegion.dstSubresource.aspectMask     = copyAspectFlags;
10910         resolveRegion.dstSubresource.mipLevel       = 0;
10911         resolveRegion.dstSubresource.baseArrayLayer = 0;
10912         resolveRegion.dstSubresource.layerCount     = 1;
10913         resolveRegion.dstOffset                     = {};
10914         resolveRegion.extent                        = srcExtent;
10915 
10916         resolve(&resolvedImage.get(), resolveRegion, commandBuffer);
10917 
10918         // Make the resolved image the target of buffer copy.
10919         src                           = &resolvedImage.get();
10920         srcOffset                     = {0, 0, 0};
10921         srcSubresource.baseArrayLayer = 0;
10922         srcSubresource.layerCount     = 1;
10923         srcSubresource.mipLevel       = 0;
10924     }
10925 
10926     // If PBO and if possible, copy directly on the GPU.
10927     if (packPixelsParams.packBuffer)
10928     {
10929         ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::readPixelsImpl - PBO");
10930 
10931         const ptrdiff_t pixelsOffset = reinterpret_cast<ptrdiff_t>(pixels);
10932         if (canCopyWithTransformForReadPixels(packPixelsParams, readFormat, pixelsOffset))
10933         {
10934             BufferHelper &packBuffer      = GetImpl(packPixelsParams.packBuffer)->getBuffer();
10935             VkDeviceSize packBufferOffset = packBuffer.getOffset();
10936 
10937             CommandBufferAccess copyAccess;
10938             copyAccess.onBufferTransferWrite(&packBuffer);
10939             copyAccess.onImageTransferRead(layoutChangeAspectFlags, src);
10940 
10941             OutsideRenderPassCommandBuffer *copyCommandBuffer;
10942             ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(copyAccess, &copyCommandBuffer));
10943 
10944             ASSERT(packPixelsParams.outputPitch % readFormat->pixelBytes == 0);
10945 
10946             VkBufferImageCopy region = {};
10947             region.bufferImageHeight = srcExtent.height;
10948             region.bufferOffset      = packBufferOffset + packPixelsParams.offset + pixelsOffset;
10949             region.bufferRowLength   = packPixelsParams.outputPitch / readFormat->pixelBytes;
10950             region.imageExtent       = srcExtent;
10951             region.imageOffset       = srcOffset;
10952             region.imageSubresource  = srcSubresource;
10953 
10954             copyCommandBuffer->copyImageToBuffer(src->getImage(), src->getCurrentLayout(renderer),
10955                                                  packBuffer.getBuffer().getHandle(), 1, &region);
10956             contextVk->trackImageWithOutsideRenderPassEvent(this);
10957             return angle::Result::Continue;
10958         }
10959         if (canCopyWithComputeForReadPixels(packPixelsParams, readFormat, pixelsOffset))
10960         {
10961             ANGLE_TRY(readPixelsWithCompute(contextVk, src, packPixelsParams, srcOffset, srcExtent,
10962                                             pixelsOffset, srcSubresource));
10963             contextVk->trackImageWithOutsideRenderPassEvent(this);
10964             return angle::Result::Continue;
10965         }
10966     }
10967 
10968     ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::readPixelsImpl - CPU Readback");
10969 
10970     RendererScoped<vk::BufferHelper> readBuffer(renderer);
10971     vk::BufferHelper *stagingBuffer = &readBuffer.get();
10972 
10973     uint8_t *readPixelBuffer   = nullptr;
10974     VkDeviceSize stagingOffset = 0;
10975     size_t allocationSize      = readFormat->pixelBytes * area.width * area.height;
10976 
10977     ANGLE_TRY(contextVk->initBufferForImageCopy(stagingBuffer, allocationSize,
10978                                                 MemoryCoherency::CachedPreferCoherent,
10979                                                 readFormat->id, &stagingOffset, &readPixelBuffer));
10980     ANGLE_TRY(stagingBuffer->flush(renderer));
10981     VkBuffer bufferHandle = stagingBuffer->getBuffer().getHandle();
10982 
10983     VkBufferImageCopy region = {};
10984     region.bufferImageHeight = srcExtent.height;
10985     region.bufferOffset      = stagingOffset;
10986     region.bufferRowLength   = srcExtent.width;
10987     region.imageExtent       = srcExtent;
10988     region.imageOffset       = srcOffset;
10989     region.imageSubresource  = srcSubresource;
10990 
10991     // For compressed textures, vkCmdCopyImageToBuffer requires
10992     // a region that is a multiple of the block size.
10993     if (readFormat->isBlock)
10994     {
10995         region.bufferRowLength =
10996             roundUp(region.bufferRowLength, storageFormatInfo.compressedBlockWidth);
10997         region.bufferImageHeight =
10998             roundUp(region.bufferImageHeight, storageFormatInfo.compressedBlockHeight);
10999     }
11000 
11001     CommandBufferAccess readbackAccess;
11002     readbackAccess.onBufferTransferWrite(stagingBuffer);
11003     readbackAccess.onImageTransferRead(layoutChangeAspectFlags, src);
11004 
11005     OutsideRenderPassCommandBuffer *readbackCommandBuffer;
11006     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(readbackAccess, &readbackCommandBuffer));
11007 
11008     readbackCommandBuffer->copyImageToBuffer(src->getImage(), src->getCurrentLayout(renderer),
11009                                              bufferHandle, 1, &region);
11010 
11011     ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_HIGH, "GPU stall due to ReadPixels");
11012 
11013     // Triggers a full finish.
11014     ANGLE_TRY(contextVk->finishImpl(RenderPassClosureReason::GLReadPixels));
11015     // invalidate must be called after wait for finish.
11016     ANGLE_TRY(stagingBuffer->invalidate(renderer));
11017 
11018     return packReadPixelBuffer(contextVk, area, packPixelsParams, getActualFormat(), *readFormat,
11019                                readPixelBuffer, levelGL, pixels);
11020 }
11021 
packReadPixelBuffer(ContextVk * contextVk,const gl::Rectangle & area,const PackPixelsParams & packPixelsParams,const angle::Format & readFormat,const angle::Format & aspectFormat,const uint8_t * readPixelBuffer,gl::LevelIndex levelGL,void * pixels)11022 angle::Result ImageHelper::packReadPixelBuffer(ContextVk *contextVk,
11023                                                const gl::Rectangle &area,
11024                                                const PackPixelsParams &packPixelsParams,
11025                                                const angle::Format &readFormat,
11026                                                const angle::Format &aspectFormat,
11027                                                const uint8_t *readPixelBuffer,
11028                                                gl::LevelIndex levelGL,
11029                                                void *pixels)
11030 {
11031     const vk::Format &vkFormat = contextVk->getRenderer()->getFormat(readFormat.id);
11032     const gl::InternalFormat &storageFormatInfo =
11033         vkFormat.getInternalFormatInfo(readFormat.componentType);
11034 
11035     if (readFormat.isBlock)
11036     {
11037         ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::packReadPixelBuffer - Block");
11038 
11039         ASSERT(readFormat == aspectFormat);
11040 
11041         const LevelIndex levelVk = toVkLevel(levelGL);
11042         gl::Extents levelExtents = getLevelExtents(levelVk);
11043 
11044         // Calculate size of one layer
11045         levelExtents.depth = 1;
11046         GLuint layerSize;
11047         ANGLE_VK_CHECK_MATH(contextVk,
11048                             storageFormatInfo.computeCompressedImageSize(levelExtents, &layerSize));
11049         memcpy(pixels, readPixelBuffer, layerSize);
11050     }
11051     else if (packPixelsParams.packBuffer)
11052     {
11053         ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::packReadPixelBuffer - PBO");
11054 
11055         // Must map the PBO in order to read its contents (and then unmap it later)
11056         BufferVk *packBufferVk = GetImpl(packPixelsParams.packBuffer);
11057         void *mapPtr           = nullptr;
11058         ANGLE_TRY(packBufferVk->mapImpl(contextVk, GL_MAP_WRITE_BIT, &mapPtr));
11059         uint8_t *dst = static_cast<uint8_t *>(mapPtr) + reinterpret_cast<ptrdiff_t>(pixels);
11060         PackPixels(packPixelsParams, aspectFormat, area.width * aspectFormat.pixelBytes,
11061                    readPixelBuffer, dst);
11062         ANGLE_TRY(packBufferVk->unmapImpl(contextVk));
11063     }
11064     else
11065     {
11066         PackPixels(packPixelsParams, aspectFormat, area.width * aspectFormat.pixelBytes,
11067                    readPixelBuffer, static_cast<uint8_t *>(pixels));
11068     }
11069 
11070     return angle::Result::Continue;
11071 }
11072 
11073 // ImageHelper::SubresourceUpdate implementation
SubresourceUpdate()11074 ImageHelper::SubresourceUpdate::SubresourceUpdate() : updateSource(UpdateSource::Buffer)
11075 {
11076     data.buffer.bufferHelper = nullptr;
11077     refCounted.buffer        = nullptr;
11078 }
11079 
~SubresourceUpdate()11080 ImageHelper::SubresourceUpdate::~SubresourceUpdate() {}
11081 
SubresourceUpdate(RefCounted<BufferHelper> * bufferIn,BufferHelper * bufferHelperIn,const VkBufferImageCopy & copyRegionIn,angle::FormatID formatID)11082 ImageHelper::SubresourceUpdate::SubresourceUpdate(RefCounted<BufferHelper> *bufferIn,
11083                                                   BufferHelper *bufferHelperIn,
11084                                                   const VkBufferImageCopy &copyRegionIn,
11085                                                   angle::FormatID formatID)
11086     : updateSource(UpdateSource::Buffer)
11087 {
11088     refCounted.buffer = bufferIn;
11089     if (refCounted.buffer != nullptr)
11090     {
11091         refCounted.buffer->addRef();
11092     }
11093     data.buffer.bufferHelper = bufferHelperIn;
11094     data.buffer.copyRegion   = copyRegionIn;
11095     data.buffer.formatID     = formatID;
11096 }
11097 
SubresourceUpdate(RefCounted<ImageHelper> * imageIn,const VkImageCopy & copyRegionIn,angle::FormatID formatID)11098 ImageHelper::SubresourceUpdate::SubresourceUpdate(RefCounted<ImageHelper> *imageIn,
11099                                                   const VkImageCopy &copyRegionIn,
11100                                                   angle::FormatID formatID)
11101     : updateSource(UpdateSource::Image)
11102 {
11103     refCounted.image = imageIn;
11104     refCounted.image->addRef();
11105     data.image.copyRegion = copyRegionIn;
11106     data.image.formatID   = formatID;
11107 }
11108 
SubresourceUpdate(VkImageAspectFlags aspectFlags,const VkClearValue & clearValue,const gl::ImageIndex & imageIndex)11109 ImageHelper::SubresourceUpdate::SubresourceUpdate(VkImageAspectFlags aspectFlags,
11110                                                   const VkClearValue &clearValue,
11111                                                   const gl::ImageIndex &imageIndex)
11112     : SubresourceUpdate(
11113           aspectFlags,
11114           clearValue,
11115           gl::LevelIndex(imageIndex.getLevelIndex()),
11116           imageIndex.hasLayer() ? imageIndex.getLayerIndex() : 0,
11117           imageIndex.hasLayer() ? imageIndex.getLayerCount() : VK_REMAINING_ARRAY_LAYERS)
11118 {}
11119 
SubresourceUpdate(VkImageAspectFlags aspectFlags,const VkClearValue & clearValue,gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount)11120 ImageHelper::SubresourceUpdate::SubresourceUpdate(VkImageAspectFlags aspectFlags,
11121                                                   const VkClearValue &clearValue,
11122                                                   gl::LevelIndex level,
11123                                                   uint32_t layerIndex,
11124                                                   uint32_t layerCount)
11125     : updateSource(UpdateSource::Clear)
11126 {
11127     refCounted.image          = nullptr;
11128     data.clear.aspectFlags    = aspectFlags;
11129     data.clear.value          = clearValue;
11130     data.clear.levelIndex     = level.get();
11131     data.clear.layerIndex     = layerIndex;
11132     data.clear.layerCount     = layerCount;
11133     data.clear.colorMaskFlags = 0;
11134 }
11135 
SubresourceUpdate(VkColorComponentFlags colorMaskFlags,const VkClearColorValue & clearValue,const gl::ImageIndex & imageIndex)11136 ImageHelper::SubresourceUpdate::SubresourceUpdate(VkColorComponentFlags colorMaskFlags,
11137                                                   const VkClearColorValue &clearValue,
11138                                                   const gl::ImageIndex &imageIndex)
11139     : updateSource(UpdateSource::ClearEmulatedChannelsOnly)
11140 {
11141     refCounted.image       = nullptr;
11142     data.clear.aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT;
11143     data.clear.value.color = clearValue;
11144     data.clear.levelIndex  = imageIndex.getLevelIndex();
11145     data.clear.layerIndex  = imageIndex.hasLayer() ? imageIndex.getLayerIndex() : 0;
11146     data.clear.layerCount =
11147         imageIndex.hasLayer() ? imageIndex.getLayerCount() : VK_REMAINING_ARRAY_LAYERS;
11148     data.clear.colorMaskFlags = colorMaskFlags;
11149 }
11150 
SubresourceUpdate(SubresourceUpdate && other)11151 ImageHelper::SubresourceUpdate::SubresourceUpdate(SubresourceUpdate &&other)
11152     : updateSource(other.updateSource)
11153 {
11154     switch (updateSource)
11155     {
11156         case UpdateSource::Clear:
11157         case UpdateSource::ClearEmulatedChannelsOnly:
11158         case UpdateSource::ClearAfterInvalidate:
11159             data.clear        = other.data.clear;
11160             refCounted.buffer = nullptr;
11161             break;
11162         case UpdateSource::Buffer:
11163             data.buffer             = other.data.buffer;
11164             refCounted.buffer       = other.refCounted.buffer;
11165             other.refCounted.buffer = nullptr;
11166             break;
11167         case UpdateSource::Image:
11168             data.image             = other.data.image;
11169             refCounted.image       = other.refCounted.image;
11170             other.refCounted.image = nullptr;
11171             break;
11172         default:
11173             UNREACHABLE();
11174     }
11175 }
11176 
operator =(SubresourceUpdate && other)11177 ImageHelper::SubresourceUpdate &ImageHelper::SubresourceUpdate::operator=(SubresourceUpdate &&other)
11178 {
11179     // Given that the update is a union of three structs, we can't use std::swap on the fields.  For
11180     // example, |this| may be an Image update and |other| may be a Buffer update.
11181     // The following could work:
11182     //
11183     // SubresourceUpdate oldThis;
11184     // Set oldThis to this->field based on updateSource
11185     // Set this->otherField to other.otherField based on other.updateSource
11186     // Set other.field to oldThis->field based on updateSource
11187     // std::Swap(updateSource, other.updateSource);
11188     //
11189     // It's much simpler to just swap the memory instead.
11190 
11191     SubresourceUpdate oldThis;
11192     memcpy(&oldThis, this, sizeof(*this));
11193     memcpy(this, &other, sizeof(*this));
11194     memcpy(&other, &oldThis, sizeof(*this));
11195 
11196     return *this;
11197 }
11198 
release(Renderer * renderer)11199 void ImageHelper::SubresourceUpdate::release(Renderer *renderer)
11200 {
11201     if (updateSource == UpdateSource::Image)
11202     {
11203         refCounted.image->releaseRef();
11204 
11205         if (!refCounted.image->isReferenced())
11206         {
11207             // Staging images won't be used in render pass attachments.
11208             refCounted.image->get().releaseImage(renderer);
11209             refCounted.image->get().releaseStagedUpdates(renderer);
11210             SafeDelete(refCounted.image);
11211         }
11212 
11213         refCounted.image = nullptr;
11214     }
11215     else if (updateSource == UpdateSource::Buffer && refCounted.buffer != nullptr)
11216     {
11217         refCounted.buffer->releaseRef();
11218 
11219         if (!refCounted.buffer->isReferenced())
11220         {
11221             refCounted.buffer->get().release(renderer);
11222             SafeDelete(refCounted.buffer);
11223         }
11224 
11225         refCounted.buffer = nullptr;
11226     }
11227 }
11228 
matchesLayerRange(uint32_t layerIndex,uint32_t layerCount) const11229 bool ImageHelper::SubresourceUpdate::matchesLayerRange(uint32_t layerIndex,
11230                                                        uint32_t layerCount) const
11231 {
11232     uint32_t updateBaseLayer, updateLayerCount;
11233     getDestSubresource(gl::ImageIndex::kEntireLevel, &updateBaseLayer, &updateLayerCount);
11234 
11235     return updateBaseLayer == layerIndex &&
11236            (updateLayerCount == layerCount || updateLayerCount == VK_REMAINING_ARRAY_LAYERS);
11237 }
11238 
intersectsLayerRange(uint32_t layerIndex,uint32_t layerCount) const11239 bool ImageHelper::SubresourceUpdate::intersectsLayerRange(uint32_t layerIndex,
11240                                                           uint32_t layerCount) const
11241 {
11242     uint32_t updateBaseLayer, updateLayerCount;
11243     getDestSubresource(gl::ImageIndex::kEntireLevel, &updateBaseLayer, &updateLayerCount);
11244     uint32_t updateLayerEnd = updateBaseLayer + updateLayerCount;
11245 
11246     return updateBaseLayer < (layerIndex + layerCount) && updateLayerEnd > layerIndex;
11247 }
11248 
getDestSubresource(uint32_t imageLayerCount,uint32_t * baseLayerOut,uint32_t * layerCountOut) const11249 void ImageHelper::SubresourceUpdate::getDestSubresource(uint32_t imageLayerCount,
11250                                                         uint32_t *baseLayerOut,
11251                                                         uint32_t *layerCountOut) const
11252 {
11253     if (IsClear(updateSource))
11254     {
11255         *baseLayerOut  = data.clear.layerIndex;
11256         *layerCountOut = data.clear.layerCount;
11257 
11258         if (*layerCountOut == static_cast<uint32_t>(gl::ImageIndex::kEntireLevel))
11259         {
11260             *layerCountOut = imageLayerCount;
11261         }
11262     }
11263     else
11264     {
11265         const VkImageSubresourceLayers &dstSubresource =
11266             updateSource == UpdateSource::Buffer ? data.buffer.copyRegion.imageSubresource
11267                                                  : data.image.copyRegion.dstSubresource;
11268         *baseLayerOut  = dstSubresource.baseArrayLayer;
11269         *layerCountOut = dstSubresource.layerCount;
11270 
11271         ASSERT(*layerCountOut != static_cast<uint32_t>(gl::ImageIndex::kEntireLevel));
11272     }
11273 }
11274 
getDestAspectFlags() const11275 VkImageAspectFlags ImageHelper::SubresourceUpdate::getDestAspectFlags() const
11276 {
11277     if (IsClear(updateSource))
11278     {
11279         return data.clear.aspectFlags;
11280     }
11281     else if (updateSource == UpdateSource::Buffer)
11282     {
11283         return data.buffer.copyRegion.imageSubresource.aspectMask;
11284     }
11285     else
11286     {
11287         ASSERT(updateSource == UpdateSource::Image);
11288         return data.image.copyRegion.dstSubresource.aspectMask;
11289     }
11290 }
11291 
getLevelUpdateCount(gl::LevelIndex level) const11292 size_t ImageHelper::getLevelUpdateCount(gl::LevelIndex level) const
11293 {
11294     return static_cast<size_t>(level.get()) < mSubresourceUpdates.size()
11295                ? mSubresourceUpdates[level.get()].size()
11296                : 0;
11297 }
11298 
clipLevelToUpdateListUpperLimit(gl::LevelIndex * level) const11299 void ImageHelper::clipLevelToUpdateListUpperLimit(gl::LevelIndex *level) const
11300 {
11301     gl::LevelIndex levelLimit(static_cast<int>(mSubresourceUpdates.size()));
11302     *level = std::min(*level, levelLimit);
11303 }
11304 
getLevelUpdates(gl::LevelIndex level)11305 std::vector<ImageHelper::SubresourceUpdate> *ImageHelper::getLevelUpdates(gl::LevelIndex level)
11306 {
11307     return static_cast<size_t>(level.get()) < mSubresourceUpdates.size()
11308                ? &mSubresourceUpdates[level.get()]
11309                : nullptr;
11310 }
11311 
getLevelUpdates(gl::LevelIndex level) const11312 const std::vector<ImageHelper::SubresourceUpdate> *ImageHelper::getLevelUpdates(
11313     gl::LevelIndex level) const
11314 {
11315     return static_cast<size_t>(level.get()) < mSubresourceUpdates.size()
11316                ? &mSubresourceUpdates[level.get()]
11317                : nullptr;
11318 }
11319 
appendSubresourceUpdate(gl::LevelIndex level,SubresourceUpdate && update)11320 void ImageHelper::appendSubresourceUpdate(gl::LevelIndex level, SubresourceUpdate &&update)
11321 {
11322     if (mSubresourceUpdates.size() <= static_cast<size_t>(level.get()))
11323     {
11324         mSubresourceUpdates.resize(level.get() + 1);
11325     }
11326     // Update total staging buffer size
11327     mTotalStagedBufferUpdateSize += update.updateSource == UpdateSource::Buffer
11328                                         ? update.data.buffer.bufferHelper->getSize()
11329                                         : 0;
11330     mSubresourceUpdates[level.get()].emplace_back(std::move(update));
11331     onStateChange(angle::SubjectMessage::SubjectChanged);
11332 }
11333 
prependSubresourceUpdate(gl::LevelIndex level,SubresourceUpdate && update)11334 void ImageHelper::prependSubresourceUpdate(gl::LevelIndex level, SubresourceUpdate &&update)
11335 {
11336     if (mSubresourceUpdates.size() <= static_cast<size_t>(level.get()))
11337     {
11338         mSubresourceUpdates.resize(level.get() + 1);
11339     }
11340 
11341     // Update total staging buffer size
11342     mTotalStagedBufferUpdateSize += update.updateSource == UpdateSource::Buffer
11343                                         ? update.data.buffer.bufferHelper->getSize()
11344                                         : 0;
11345     mSubresourceUpdates[level.get()].insert(mSubresourceUpdates[level.get()].begin(),
11346                                             std::move(update));
11347     onStateChange(angle::SubjectMessage::SubjectChanged);
11348 }
11349 
hasEmulatedImageChannels() const11350 bool ImageHelper::hasEmulatedImageChannels() const
11351 {
11352     const angle::Format &angleFmt   = getIntendedFormat();
11353     const angle::Format &textureFmt = getActualFormat();
11354 
11355     // Block formats may be decoded and emulated with a non-block format.
11356     if (angleFmt.isBlock)
11357     {
11358         return !textureFmt.isBlock;
11359     }
11360 
11361     // The red channel is never emulated.
11362     ASSERT((angleFmt.redBits != 0 || angleFmt.luminanceBits != 0 || angleFmt.alphaBits != 0) ==
11363            (textureFmt.redBits != 0));
11364 
11365     return (angleFmt.alphaBits == 0 && textureFmt.alphaBits > 0) ||
11366            (angleFmt.blueBits == 0 && textureFmt.blueBits > 0) ||
11367            (angleFmt.greenBits == 0 && textureFmt.greenBits > 0) ||
11368            (angleFmt.depthBits == 0 && textureFmt.depthBits > 0) ||
11369            (angleFmt.stencilBits == 0 && textureFmt.stencilBits > 0);
11370 }
11371 
hasEmulatedDepthChannel() const11372 bool ImageHelper::hasEmulatedDepthChannel() const
11373 {
11374     return getIntendedFormat().depthBits == 0 && getActualFormat().depthBits > 0;
11375 }
11376 
hasEmulatedStencilChannel() const11377 bool ImageHelper::hasEmulatedStencilChannel() const
11378 {
11379     return getIntendedFormat().stencilBits == 0 && getActualFormat().stencilBits > 0;
11380 }
11381 
hasInefficientlyEmulatedImageFormat() const11382 bool ImageHelper::hasInefficientlyEmulatedImageFormat() const
11383 {
11384     if (hasEmulatedImageFormat())
11385     {
11386         // ETC2 compression is compatible with ETC1
11387         return !(mIntendedFormatID == angle::FormatID::ETC1_R8G8B8_UNORM_BLOCK &&
11388                  mActualFormatID == angle::FormatID::ETC2_R8G8B8_UNORM_BLOCK);
11389     }
11390     return false;
11391 }
11392 
getEmulatedChannelsMask() const11393 VkColorComponentFlags ImageHelper::getEmulatedChannelsMask() const
11394 {
11395     const angle::Format &angleFmt   = getIntendedFormat();
11396     const angle::Format &textureFmt = getActualFormat();
11397 
11398     ASSERT(!angleFmt.hasDepthOrStencilBits());
11399 
11400     VkColorComponentFlags emulatedChannelsMask = 0;
11401 
11402     if (angleFmt.alphaBits == 0 && textureFmt.alphaBits > 0)
11403     {
11404         emulatedChannelsMask |= VK_COLOR_COMPONENT_A_BIT;
11405     }
11406     if (angleFmt.blueBits == 0 && textureFmt.blueBits > 0)
11407     {
11408         emulatedChannelsMask |= VK_COLOR_COMPONENT_B_BIT;
11409     }
11410     if (angleFmt.greenBits == 0 && textureFmt.greenBits > 0)
11411     {
11412         emulatedChannelsMask |= VK_COLOR_COMPONENT_G_BIT;
11413     }
11414 
11415     // The red channel is never emulated.
11416     ASSERT((angleFmt.redBits != 0 || angleFmt.luminanceBits != 0 || angleFmt.alphaBits != 0) ==
11417            (textureFmt.redBits != 0));
11418 
11419     return emulatedChannelsMask;
11420 }
11421 
GetLayerMode(const vk::ImageHelper & image,uint32_t layerCount)11422 LayerMode GetLayerMode(const vk::ImageHelper &image, uint32_t layerCount)
11423 {
11424     const uint32_t imageLayerCount = GetImageLayerCountForView(image);
11425     const bool allLayers           = layerCount == imageLayerCount;
11426 
11427     ASSERT(allLayers || (layerCount > 0 && layerCount <= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS));
11428     return allLayers ? LayerMode::All : static_cast<LayerMode>(layerCount);
11429 }
11430 
11431 // ImageViewHelper implementation.
ImageViewHelper()11432 ImageViewHelper::ImageViewHelper() : mCurrentBaseMaxLevelHash(0), mLinearColorspace(true) {}
11433 
ImageViewHelper(ImageViewHelper && other)11434 ImageViewHelper::ImageViewHelper(ImageViewHelper &&other)
11435 {
11436     std::swap(mCurrentBaseMaxLevelHash, other.mCurrentBaseMaxLevelHash);
11437     std::swap(mLinearColorspace, other.mLinearColorspace);
11438 
11439     std::swap(mPerLevelRangeLinearReadImageViews, other.mPerLevelRangeLinearReadImageViews);
11440     std::swap(mPerLevelRangeSRGBReadImageViews, other.mPerLevelRangeSRGBReadImageViews);
11441     std::swap(mPerLevelRangeLinearFetchImageViews, other.mPerLevelRangeLinearFetchImageViews);
11442     std::swap(mPerLevelRangeSRGBFetchImageViews, other.mPerLevelRangeSRGBFetchImageViews);
11443     std::swap(mPerLevelRangeLinearCopyImageViews, other.mPerLevelRangeLinearCopyImageViews);
11444     std::swap(mPerLevelRangeSRGBCopyImageViews, other.mPerLevelRangeSRGBCopyImageViews);
11445     std::swap(mPerLevelRangeStencilReadImageViews, other.mPerLevelRangeStencilReadImageViews);
11446     std::swap(mPerLevelRangeSamplerExternal2DY2YEXTImageViews,
11447               other.mPerLevelRangeSamplerExternal2DY2YEXTImageViews);
11448 
11449     std::swap(mLayerLevelDrawImageViews, other.mLayerLevelDrawImageViews);
11450     std::swap(mLayerLevelDrawImageViewsLinear, other.mLayerLevelDrawImageViewsLinear);
11451     std::swap(mSubresourceDrawImageViews, other.mSubresourceDrawImageViews);
11452     std::swap(mLevelStorageImageViews, other.mLevelStorageImageViews);
11453     std::swap(mLayerLevelStorageImageViews, other.mLayerLevelStorageImageViews);
11454     std::swap(mFragmentShadingRateImageView, other.mFragmentShadingRateImageView);
11455     std::swap(mImageViewSerial, other.mImageViewSerial);
11456 }
11457 
~ImageViewHelper()11458 ImageViewHelper::~ImageViewHelper() {}
11459 
init(Renderer * renderer)11460 void ImageViewHelper::init(Renderer *renderer)
11461 {
11462     if (!mImageViewSerial.valid())
11463     {
11464         mImageViewSerial = renderer->getResourceSerialFactory().generateImageOrBufferViewSerial();
11465     }
11466 }
11467 
release(Renderer * renderer,const ResourceUse & use)11468 void ImageViewHelper::release(Renderer *renderer, const ResourceUse &use)
11469 {
11470     mCurrentBaseMaxLevelHash = 0;
11471 
11472     std::vector<vk::GarbageObject> garbage;
11473     // Release the read views
11474     ReleaseImageViews(&mPerLevelRangeLinearReadImageViews, &garbage);
11475     ReleaseImageViews(&mPerLevelRangeSRGBReadImageViews, &garbage);
11476     ReleaseImageViews(&mPerLevelRangeLinearFetchImageViews, &garbage);
11477     ReleaseImageViews(&mPerLevelRangeSRGBFetchImageViews, &garbage);
11478     ReleaseImageViews(&mPerLevelRangeLinearCopyImageViews, &garbage);
11479     ReleaseImageViews(&mPerLevelRangeSRGBCopyImageViews, &garbage);
11480     ReleaseImageViews(&mPerLevelRangeStencilReadImageViews, &garbage);
11481     ReleaseImageViews(&mPerLevelRangeSamplerExternal2DY2YEXTImageViews, &garbage);
11482 
11483     // Release the draw views
11484     for (ImageViewVector &layerViews : mLayerLevelDrawImageViews)
11485     {
11486         for (ImageView &imageView : layerViews)
11487         {
11488             if (imageView.valid())
11489             {
11490                 garbage.emplace_back(GetGarbage(&imageView));
11491             }
11492         }
11493     }
11494     mLayerLevelDrawImageViews.clear();
11495     for (ImageViewVector &layerViews : mLayerLevelDrawImageViewsLinear)
11496     {
11497         for (ImageView &imageView : layerViews)
11498         {
11499             if (imageView.valid())
11500             {
11501                 garbage.emplace_back(GetGarbage(&imageView));
11502             }
11503         }
11504     }
11505     mLayerLevelDrawImageViewsLinear.clear();
11506     for (auto &iter : mSubresourceDrawImageViews)
11507     {
11508         std::unique_ptr<ImageView> &imageView = iter.second;
11509         if (imageView->valid())
11510         {
11511             garbage.emplace_back(GetGarbage(imageView.get()));
11512         }
11513     }
11514     mSubresourceDrawImageViews.clear();
11515 
11516     // Release the storage views
11517     ReleaseImageViews(&mLevelStorageImageViews, &garbage);
11518     for (ImageViewVector &layerViews : mLayerLevelStorageImageViews)
11519     {
11520         for (ImageView &imageView : layerViews)
11521         {
11522             if (imageView.valid())
11523             {
11524                 garbage.emplace_back(GetGarbage(&imageView));
11525             }
11526         }
11527     }
11528     mLayerLevelStorageImageViews.clear();
11529 
11530     // Release fragment shading rate view
11531     if (mFragmentShadingRateImageView.valid())
11532     {
11533         garbage.emplace_back(GetGarbage(&mFragmentShadingRateImageView));
11534     }
11535 
11536     if (!garbage.empty())
11537     {
11538         renderer->collectGarbage(use, std::move(garbage));
11539     }
11540 
11541     // Update image view serial.
11542     mImageViewSerial = renderer->getResourceSerialFactory().generateImageOrBufferViewSerial();
11543 }
11544 
isImageViewGarbageEmpty() const11545 bool ImageViewHelper::isImageViewGarbageEmpty() const
11546 {
11547     return mPerLevelRangeLinearReadImageViews.empty() &&
11548            mPerLevelRangeLinearCopyImageViews.empty() &&
11549            mPerLevelRangeLinearFetchImageViews.empty() &&
11550            mPerLevelRangeSRGBReadImageViews.empty() && mPerLevelRangeSRGBCopyImageViews.empty() &&
11551            mPerLevelRangeSRGBFetchImageViews.empty() &&
11552            mPerLevelRangeStencilReadImageViews.empty() &&
11553            mPerLevelRangeSamplerExternal2DY2YEXTImageViews.empty() &&
11554            mLayerLevelDrawImageViews.empty() && mLayerLevelDrawImageViewsLinear.empty() &&
11555            mSubresourceDrawImageViews.empty() && mLayerLevelStorageImageViews.empty();
11556 }
11557 
destroy(VkDevice device)11558 void ImageViewHelper::destroy(VkDevice device)
11559 {
11560     mCurrentBaseMaxLevelHash = 0;
11561 
11562     // Release the read views
11563     DestroyImageViews(&mPerLevelRangeLinearReadImageViews, device);
11564     DestroyImageViews(&mPerLevelRangeSRGBReadImageViews, device);
11565     DestroyImageViews(&mPerLevelRangeLinearFetchImageViews, device);
11566     DestroyImageViews(&mPerLevelRangeSRGBFetchImageViews, device);
11567     DestroyImageViews(&mPerLevelRangeLinearCopyImageViews, device);
11568     DestroyImageViews(&mPerLevelRangeSRGBCopyImageViews, device);
11569     DestroyImageViews(&mPerLevelRangeStencilReadImageViews, device);
11570     DestroyImageViews(&mPerLevelRangeSamplerExternal2DY2YEXTImageViews, device);
11571 
11572     // Release the draw views
11573     for (ImageViewVector &layerViews : mLayerLevelDrawImageViews)
11574     {
11575         for (ImageView &imageView : layerViews)
11576         {
11577             imageView.destroy(device);
11578         }
11579     }
11580     mLayerLevelDrawImageViews.clear();
11581     for (ImageViewVector &layerViews : mLayerLevelDrawImageViewsLinear)
11582     {
11583         for (ImageView &imageView : layerViews)
11584         {
11585             imageView.destroy(device);
11586         }
11587     }
11588     mLayerLevelDrawImageViewsLinear.clear();
11589     for (auto &iter : mSubresourceDrawImageViews)
11590     {
11591         std::unique_ptr<ImageView> &imageView = iter.second;
11592         imageView->destroy(device);
11593     }
11594     mSubresourceDrawImageViews.clear();
11595 
11596     // Release the storage views
11597     DestroyImageViews(&mLevelStorageImageViews, device);
11598     for (ImageViewVector &layerViews : mLayerLevelStorageImageViews)
11599     {
11600         for (ImageView &imageView : layerViews)
11601         {
11602             imageView.destroy(device);
11603         }
11604     }
11605     mLayerLevelStorageImageViews.clear();
11606 
11607     // Destroy fragment shading rate view
11608     mFragmentShadingRateImageView.destroy(device);
11609 
11610     mImageViewSerial = kInvalidImageOrBufferViewSerial;
11611 }
11612 
initReadViews(ContextVk * contextVk,gl::TextureType viewType,const ImageHelper & image,const gl::SwizzleState & formatSwizzle,const gl::SwizzleState & readSwizzle,LevelIndex baseLevel,uint32_t levelCount,uint32_t baseLayer,uint32_t layerCount,bool requiresSRGBViews,VkImageUsageFlags imageUsageFlags)11613 angle::Result ImageViewHelper::initReadViews(ContextVk *contextVk,
11614                                              gl::TextureType viewType,
11615                                              const ImageHelper &image,
11616                                              const gl::SwizzleState &formatSwizzle,
11617                                              const gl::SwizzleState &readSwizzle,
11618                                              LevelIndex baseLevel,
11619                                              uint32_t levelCount,
11620                                              uint32_t baseLayer,
11621                                              uint32_t layerCount,
11622                                              bool requiresSRGBViews,
11623                                              VkImageUsageFlags imageUsageFlags)
11624 {
11625     ASSERT(levelCount > 0);
11626 
11627     const uint32_t maxLevel = levelCount - 1;
11628     ASSERT(maxLevel < 16);
11629     ASSERT(baseLevel.get() < 16);
11630     mCurrentBaseMaxLevelHash = static_cast<uint8_t>(baseLevel.get() << 4 | maxLevel);
11631 
11632     if (mCurrentBaseMaxLevelHash >= mPerLevelRangeLinearReadImageViews.size())
11633     {
11634         const uint32_t maxViewCount = mCurrentBaseMaxLevelHash + 1;
11635 
11636         mPerLevelRangeLinearReadImageViews.resize(maxViewCount);
11637         mPerLevelRangeSRGBReadImageViews.resize(maxViewCount);
11638         mPerLevelRangeLinearFetchImageViews.resize(maxViewCount);
11639         mPerLevelRangeSRGBFetchImageViews.resize(maxViewCount);
11640         mPerLevelRangeLinearCopyImageViews.resize(maxViewCount);
11641         mPerLevelRangeSRGBCopyImageViews.resize(maxViewCount);
11642         mPerLevelRangeStencilReadImageViews.resize(maxViewCount);
11643         mPerLevelRangeSamplerExternal2DY2YEXTImageViews.resize(maxViewCount);
11644     }
11645 
11646     // Determine if we already have ImageViews for the new max level
11647     if (getReadImageView().valid())
11648     {
11649         return angle::Result::Continue;
11650     }
11651 
11652     // Since we don't have a readImageView, we must create ImageViews for the new max level
11653     ANGLE_TRY(initReadViewsImpl(contextVk, viewType, image, formatSwizzle, readSwizzle, baseLevel,
11654                                 levelCount, baseLayer, layerCount, imageUsageFlags));
11655 
11656     if (requiresSRGBViews)
11657     {
11658         ANGLE_TRY(initSRGBReadViewsImpl(contextVk, viewType, image, formatSwizzle, readSwizzle,
11659                                         baseLevel, levelCount, baseLayer, layerCount,
11660                                         imageUsageFlags));
11661     }
11662 
11663     return angle::Result::Continue;
11664 }
11665 
initReadViewsImpl(ContextVk * contextVk,gl::TextureType viewType,const ImageHelper & image,const gl::SwizzleState & formatSwizzle,const gl::SwizzleState & readSwizzle,LevelIndex baseLevel,uint32_t levelCount,uint32_t baseLayer,uint32_t layerCount,VkImageUsageFlags imageUsageFlags)11666 angle::Result ImageViewHelper::initReadViewsImpl(ContextVk *contextVk,
11667                                                  gl::TextureType viewType,
11668                                                  const ImageHelper &image,
11669                                                  const gl::SwizzleState &formatSwizzle,
11670                                                  const gl::SwizzleState &readSwizzle,
11671                                                  LevelIndex baseLevel,
11672                                                  uint32_t levelCount,
11673                                                  uint32_t baseLayer,
11674                                                  uint32_t layerCount,
11675                                                  VkImageUsageFlags imageUsageFlags)
11676 {
11677     ASSERT(mImageViewSerial.valid());
11678 
11679     const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(image.getIntendedFormat());
11680     mLinearColorspace                    = !image.getActualFormat().isSRGB;
11681 
11682     if (HasBothDepthAndStencilAspects(aspectFlags))
11683     {
11684         ANGLE_TRY(image.initLayerImageView(contextVk, viewType, VK_IMAGE_ASPECT_DEPTH_BIT,
11685                                            readSwizzle, &getReadImageView(), baseLevel, levelCount,
11686                                            baseLayer, layerCount, gl::SrgbWriteControlMode::Default,
11687                                            gl::YuvSamplingMode::Default, imageUsageFlags));
11688         ANGLE_TRY(image.initLayerImageView(
11689             contextVk, viewType, VK_IMAGE_ASPECT_STENCIL_BIT, readSwizzle,
11690             &mPerLevelRangeStencilReadImageViews[mCurrentBaseMaxLevelHash], baseLevel, levelCount,
11691             baseLayer, layerCount, gl::SrgbWriteControlMode::Default, gl::YuvSamplingMode::Default,
11692             imageUsageFlags));
11693     }
11694     else
11695     {
11696         ANGLE_TRY(image.initLayerImageView(contextVk, viewType, aspectFlags, readSwizzle,
11697                                            &getReadImageView(), baseLevel, levelCount, baseLayer,
11698                                            layerCount, gl::SrgbWriteControlMode::Default,
11699                                            gl::YuvSamplingMode::Default, imageUsageFlags));
11700 
11701         if (image.getActualFormat().isYUV)
11702         {
11703             ANGLE_TRY(image.initLayerImageView(contextVk, viewType, aspectFlags, readSwizzle,
11704                                                &getSamplerExternal2DY2YEXTImageView(), baseLevel,
11705                                                levelCount, baseLayer, layerCount,
11706                                                gl::SrgbWriteControlMode::Default,
11707                                                gl::YuvSamplingMode::Y2Y, imageUsageFlags));
11708         }
11709     }
11710 
11711     gl::TextureType fetchType = viewType;
11712     if (viewType == gl::TextureType::CubeMap || viewType == gl::TextureType::_2DArray ||
11713         viewType == gl::TextureType::_2DMultisampleArray)
11714     {
11715         fetchType = Get2DTextureType(layerCount, image.getSamples());
11716         if (contextVk->emulateSeamfulCubeMapSampling())
11717         {
11718             ANGLE_TRY(image.initLayerImageView(
11719                 contextVk, fetchType, aspectFlags, readSwizzle, &getFetchImageView(), baseLevel,
11720                 levelCount, baseLayer, layerCount, gl::SrgbWriteControlMode::Default,
11721                 gl::YuvSamplingMode::Default, imageUsageFlags));
11722         }
11723     }
11724 
11725     if (!image.getActualFormat().isBlock)
11726     {
11727         ANGLE_TRY(image.initLayerImageView(contextVk, fetchType, aspectFlags, formatSwizzle,
11728                                            &getCopyImageView(), baseLevel, levelCount, baseLayer,
11729                                            layerCount, gl::SrgbWriteControlMode::Default,
11730                                            gl::YuvSamplingMode::Default, imageUsageFlags));
11731     }
11732     return angle::Result::Continue;
11733 }
11734 
initSRGBReadViewsImpl(ContextVk * contextVk,gl::TextureType viewType,const ImageHelper & image,const gl::SwizzleState & formatSwizzle,const gl::SwizzleState & readSwizzle,LevelIndex baseLevel,uint32_t levelCount,uint32_t baseLayer,uint32_t layerCount,VkImageUsageFlags imageUsageFlags)11735 angle::Result ImageViewHelper::initSRGBReadViewsImpl(ContextVk *contextVk,
11736                                                      gl::TextureType viewType,
11737                                                      const ImageHelper &image,
11738                                                      const gl::SwizzleState &formatSwizzle,
11739                                                      const gl::SwizzleState &readSwizzle,
11740                                                      LevelIndex baseLevel,
11741                                                      uint32_t levelCount,
11742                                                      uint32_t baseLayer,
11743                                                      uint32_t layerCount,
11744                                                      VkImageUsageFlags imageUsageFlags)
11745 {
11746     // When we select the linear/srgb counterpart formats, we must first make sure they're
11747     // actually supported by the ICD. If they are not supported by the ICD, then we treat that as if
11748     // there is no counterpart format. (In this case, the relevant extension should not be exposed)
11749     angle::FormatID srgbOverrideFormat = ConvertToSRGB(image.getActualFormatID());
11750     ASSERT((srgbOverrideFormat == angle::FormatID::NONE) ||
11751            (HasNonRenderableTextureFormatSupport(contextVk->getRenderer(), srgbOverrideFormat)));
11752 
11753     angle::FormatID linearOverrideFormat = ConvertToLinear(image.getActualFormatID());
11754     ASSERT((linearOverrideFormat == angle::FormatID::NONE) ||
11755            (HasNonRenderableTextureFormatSupport(contextVk->getRenderer(), linearOverrideFormat)));
11756 
11757     angle::FormatID linearFormat = (linearOverrideFormat != angle::FormatID::NONE)
11758                                        ? linearOverrideFormat
11759                                        : image.getActualFormatID();
11760     ASSERT(linearFormat != angle::FormatID::NONE);
11761 
11762     const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(image.getIntendedFormat());
11763 
11764     if (!mPerLevelRangeLinearReadImageViews[mCurrentBaseMaxLevelHash].valid())
11765     {
11766         ANGLE_TRY(image.initReinterpretedLayerImageView(
11767             contextVk, viewType, aspectFlags, readSwizzle,
11768             &mPerLevelRangeLinearReadImageViews[mCurrentBaseMaxLevelHash], baseLevel, levelCount,
11769             baseLayer, layerCount, imageUsageFlags, linearFormat));
11770     }
11771     if (srgbOverrideFormat != angle::FormatID::NONE &&
11772         !mPerLevelRangeSRGBReadImageViews[mCurrentBaseMaxLevelHash].valid())
11773     {
11774         ANGLE_TRY(image.initReinterpretedLayerImageView(
11775             contextVk, viewType, aspectFlags, readSwizzle,
11776             &mPerLevelRangeSRGBReadImageViews[mCurrentBaseMaxLevelHash], baseLevel, levelCount,
11777             baseLayer, layerCount, imageUsageFlags, srgbOverrideFormat));
11778     }
11779 
11780     gl::TextureType fetchType = viewType;
11781 
11782     if (viewType == gl::TextureType::CubeMap || viewType == gl::TextureType::_2DArray ||
11783         viewType == gl::TextureType::_2DMultisampleArray)
11784     {
11785         fetchType = Get2DTextureType(layerCount, image.getSamples());
11786         if (contextVk->emulateSeamfulCubeMapSampling())
11787         {
11788             if (!mPerLevelRangeLinearFetchImageViews[mCurrentBaseMaxLevelHash].valid())
11789             {
11790 
11791                 ANGLE_TRY(image.initReinterpretedLayerImageView(
11792                     contextVk, fetchType, aspectFlags, readSwizzle,
11793                     &mPerLevelRangeLinearFetchImageViews[mCurrentBaseMaxLevelHash], baseLevel,
11794                     levelCount, baseLayer, layerCount, imageUsageFlags, linearFormat));
11795             }
11796             if (srgbOverrideFormat != angle::FormatID::NONE &&
11797                 !mPerLevelRangeSRGBFetchImageViews[mCurrentBaseMaxLevelHash].valid())
11798             {
11799                 ANGLE_TRY(image.initReinterpretedLayerImageView(
11800                     contextVk, fetchType, aspectFlags, readSwizzle,
11801                     &mPerLevelRangeSRGBFetchImageViews[mCurrentBaseMaxLevelHash], baseLevel,
11802                     levelCount, baseLayer, layerCount, imageUsageFlags, srgbOverrideFormat));
11803             }
11804         }
11805     }
11806 
11807     if (!image.getActualFormat().isBlock)
11808     {
11809         if (!mPerLevelRangeLinearCopyImageViews[mCurrentBaseMaxLevelHash].valid())
11810         {
11811             ANGLE_TRY(image.initReinterpretedLayerImageView(
11812                 contextVk, fetchType, aspectFlags, formatSwizzle,
11813                 &mPerLevelRangeLinearCopyImageViews[mCurrentBaseMaxLevelHash], baseLevel,
11814                 levelCount, baseLayer, layerCount, imageUsageFlags, linearFormat));
11815         }
11816         if (srgbOverrideFormat != angle::FormatID::NONE &&
11817             !mPerLevelRangeSRGBCopyImageViews[mCurrentBaseMaxLevelHash].valid())
11818         {
11819             ANGLE_TRY(image.initReinterpretedLayerImageView(
11820                 contextVk, fetchType, aspectFlags, formatSwizzle,
11821                 &mPerLevelRangeSRGBCopyImageViews[mCurrentBaseMaxLevelHash], baseLevel, levelCount,
11822                 baseLayer, layerCount, imageUsageFlags, srgbOverrideFormat));
11823         }
11824     }
11825     return angle::Result::Continue;
11826 }
11827 
getLevelStorageImageView(Context * context,gl::TextureType viewType,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,VkImageUsageFlags imageUsageFlags,angle::FormatID formatID,const ImageView ** imageViewOut)11828 angle::Result ImageViewHelper::getLevelStorageImageView(Context *context,
11829                                                         gl::TextureType viewType,
11830                                                         const ImageHelper &image,
11831                                                         LevelIndex levelVk,
11832                                                         uint32_t layer,
11833                                                         VkImageUsageFlags imageUsageFlags,
11834                                                         angle::FormatID formatID,
11835                                                         const ImageView **imageViewOut)
11836 {
11837     ASSERT(mImageViewSerial.valid());
11838 
11839     ImageView *imageView =
11840         GetLevelImageView(&mLevelStorageImageViews, levelVk, image.getLevelCount());
11841 
11842     *imageViewOut = imageView;
11843     if (imageView->valid())
11844     {
11845         return angle::Result::Continue;
11846     }
11847 
11848     // Create the view.  Note that storage images are not affected by swizzle parameters.
11849     return image.initReinterpretedLayerImageView(context, viewType, image.getAspectFlags(),
11850                                                  gl::SwizzleState(), imageView, levelVk, 1, layer,
11851                                                  image.getLayerCount(), imageUsageFlags, formatID);
11852 }
11853 
getLevelLayerStorageImageView(Context * contextVk,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,VkImageUsageFlags imageUsageFlags,angle::FormatID formatID,const ImageView ** imageViewOut)11854 angle::Result ImageViewHelper::getLevelLayerStorageImageView(Context *contextVk,
11855                                                              const ImageHelper &image,
11856                                                              LevelIndex levelVk,
11857                                                              uint32_t layer,
11858                                                              VkImageUsageFlags imageUsageFlags,
11859                                                              angle::FormatID formatID,
11860                                                              const ImageView **imageViewOut)
11861 {
11862     ASSERT(image.valid());
11863     ASSERT(mImageViewSerial.valid());
11864     ASSERT(!image.getActualFormat().isBlock);
11865 
11866     ImageView *imageView =
11867         GetLevelLayerImageView(&mLayerLevelStorageImageViews, levelVk, layer, image.getLevelCount(),
11868                                GetImageLayerCountForView(image));
11869     *imageViewOut = imageView;
11870 
11871     if (imageView->valid())
11872     {
11873         return angle::Result::Continue;
11874     }
11875 
11876     // Create the view.  Note that storage images are not affected by swizzle parameters.
11877     gl::TextureType viewType = Get2DTextureType(1, image.getSamples());
11878     return image.initReinterpretedLayerImageView(contextVk, viewType, image.getAspectFlags(),
11879                                                  gl::SwizzleState(), imageView, levelVk, 1, layer,
11880                                                  1, imageUsageFlags, formatID);
11881 }
11882 
getLevelDrawImageView(Context * context,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,uint32_t layerCount,gl::SrgbWriteControlMode mode,const ImageView ** imageViewOut)11883 angle::Result ImageViewHelper::getLevelDrawImageView(Context *context,
11884                                                      const ImageHelper &image,
11885                                                      LevelIndex levelVk,
11886                                                      uint32_t layer,
11887                                                      uint32_t layerCount,
11888                                                      gl::SrgbWriteControlMode mode,
11889                                                      const ImageView **imageViewOut)
11890 {
11891     ASSERT(image.valid());
11892     ASSERT(mImageViewSerial.valid());
11893     ASSERT(!image.getActualFormat().isBlock);
11894 
11895     ImageSubresourceRange range = MakeImageSubresourceDrawRange(
11896         image.toGLLevel(levelVk), layer, GetLayerMode(image, layerCount), mode);
11897 
11898     std::unique_ptr<ImageView> &view = mSubresourceDrawImageViews[range];
11899     if (view)
11900     {
11901         *imageViewOut = view.get();
11902         return angle::Result::Continue;
11903     }
11904 
11905     view          = std::make_unique<ImageView>();
11906     *imageViewOut = view.get();
11907 
11908     // Lazily allocate the image view.
11909     // Note that these views are specifically made to be used as framebuffer attachments, and
11910     // therefore don't have swizzle.
11911     gl::TextureType viewType = Get2DTextureType(layerCount, image.getSamples());
11912     return image.initLayerImageView(context, viewType, image.getAspectFlags(), gl::SwizzleState(),
11913                                     view.get(), levelVk, 1, layer, layerCount, mode,
11914                                     gl::YuvSamplingMode::Default,
11915                                     vk::ImageHelper::kDefaultImageViewUsageFlags);
11916 }
11917 
getLevelLayerDrawImageView(Context * context,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,gl::SrgbWriteControlMode mode,const ImageView ** imageViewOut)11918 angle::Result ImageViewHelper::getLevelLayerDrawImageView(Context *context,
11919                                                           const ImageHelper &image,
11920                                                           LevelIndex levelVk,
11921                                                           uint32_t layer,
11922                                                           gl::SrgbWriteControlMode mode,
11923                                                           const ImageView **imageViewOut)
11924 {
11925     ASSERT(image.valid());
11926     ASSERT(mImageViewSerial.valid());
11927     ASSERT(!image.getActualFormat().isBlock);
11928 
11929     LayerLevelImageViewVector &imageViews = (mode == gl::SrgbWriteControlMode::Linear)
11930                                                 ? mLayerLevelDrawImageViewsLinear
11931                                                 : mLayerLevelDrawImageViews;
11932 
11933     // Lazily allocate the storage for image views
11934     ImageView *imageView = GetLevelLayerImageView(
11935         &imageViews, levelVk, layer, image.getLevelCount(), GetImageLayerCountForView(image));
11936     *imageViewOut = imageView;
11937 
11938     if (imageView->valid())
11939     {
11940         return angle::Result::Continue;
11941     }
11942 
11943     // Lazily allocate the image view itself.
11944     // Note that these views are specifically made to be used as framebuffer attachments, and
11945     // therefore don't have swizzle.
11946     gl::TextureType viewType = Get2DTextureType(1, image.getSamples());
11947     return image.initLayerImageView(
11948         context, viewType, image.getAspectFlags(), gl::SwizzleState(), imageView, levelVk, 1, layer,
11949         1, mode, gl::YuvSamplingMode::Default, vk::ImageHelper::kDefaultImageViewUsageFlags);
11950 }
11951 
initFragmentShadingRateView(ContextVk * contextVk,ImageHelper * image)11952 angle::Result ImageViewHelper::initFragmentShadingRateView(ContextVk *contextVk, ImageHelper *image)
11953 {
11954     ASSERT(image->valid());
11955     ASSERT(mImageViewSerial.valid());
11956 
11957     // Determine if we already have ImageView
11958     if (mFragmentShadingRateImageView.valid())
11959     {
11960         return angle::Result::Continue;
11961     }
11962 
11963     // Fragment shading rate image view always have -
11964     // - gl::TextureType    == gl::TextureType::_2D
11965     // - VkImageAspectFlags == VK_IMAGE_ASPECT_COLOR_BIT
11966     // - gl::SwizzleState   == gl::SwizzleState()
11967     // - baseMipLevelVk     == vk::LevelIndex(0)
11968     // - levelCount         == 1
11969     return image->initImageView(contextVk, gl::TextureType::_2D, VK_IMAGE_ASPECT_COLOR_BIT,
11970                                 gl::SwizzleState(), &mFragmentShadingRateImageView,
11971                                 vk::LevelIndex(0), 1, image->getUsage());
11972 }
11973 
getSubresourceSerial(gl::LevelIndex levelGL,uint32_t levelCount,uint32_t layer,LayerMode layerMode,SrgbDecodeMode srgbDecodeMode,gl::SrgbOverride srgbOverrideMode) const11974 ImageOrBufferViewSubresourceSerial ImageViewHelper::getSubresourceSerial(
11975     gl::LevelIndex levelGL,
11976     uint32_t levelCount,
11977     uint32_t layer,
11978     LayerMode layerMode,
11979     SrgbDecodeMode srgbDecodeMode,
11980     gl::SrgbOverride srgbOverrideMode) const
11981 {
11982     ASSERT(mImageViewSerial.valid());
11983 
11984     ImageOrBufferViewSubresourceSerial serial;
11985     serial.viewSerial  = mImageViewSerial;
11986     serial.subresource = MakeImageSubresourceReadRange(levelGL, levelCount, layer, layerMode,
11987                                                        srgbDecodeMode, srgbOverrideMode);
11988     return serial;
11989 }
11990 
MakeImageSubresourceReadRange(gl::LevelIndex level,uint32_t levelCount,uint32_t layer,LayerMode layerMode,SrgbDecodeMode srgbDecodeMode,gl::SrgbOverride srgbOverrideMode)11991 ImageSubresourceRange MakeImageSubresourceReadRange(gl::LevelIndex level,
11992                                                     uint32_t levelCount,
11993                                                     uint32_t layer,
11994                                                     LayerMode layerMode,
11995                                                     SrgbDecodeMode srgbDecodeMode,
11996                                                     gl::SrgbOverride srgbOverrideMode)
11997 {
11998     ImageSubresourceRange range;
11999 
12000     SetBitField(range.level, level.get());
12001     SetBitField(range.levelCount, levelCount);
12002     SetBitField(range.layer, layer);
12003     SetBitField(range.layerMode, layerMode);
12004     SetBitField(range.srgbDecodeMode, srgbDecodeMode);
12005     SetBitField(range.srgbMode, srgbOverrideMode);
12006 
12007     return range;
12008 }
12009 
MakeImageSubresourceDrawRange(gl::LevelIndex level,uint32_t layer,LayerMode layerMode,gl::SrgbWriteControlMode srgbWriteControlMode)12010 ImageSubresourceRange MakeImageSubresourceDrawRange(gl::LevelIndex level,
12011                                                     uint32_t layer,
12012                                                     LayerMode layerMode,
12013                                                     gl::SrgbWriteControlMode srgbWriteControlMode)
12014 {
12015     ImageSubresourceRange range;
12016 
12017     SetBitField(range.level, level.get());
12018     SetBitField(range.levelCount, 1);
12019     SetBitField(range.layer, layer);
12020     SetBitField(range.layerMode, layerMode);
12021     SetBitField(range.srgbDecodeMode, 0);
12022     SetBitField(range.srgbMode, srgbWriteControlMode);
12023 
12024     return range;
12025 }
12026 
12027 // BufferViewHelper implementation.
BufferViewHelper()12028 BufferViewHelper::BufferViewHelper() : mInitialized(false), mOffset(0), mSize(0) {}
12029 
BufferViewHelper(BufferViewHelper && other)12030 BufferViewHelper::BufferViewHelper(BufferViewHelper &&other) : Resource(std::move(other))
12031 {
12032     std::swap(mInitialized, other.mInitialized);
12033     std::swap(mOffset, other.mOffset);
12034     std::swap(mSize, other.mSize);
12035     std::swap(mViews, other.mViews);
12036     std::swap(mViewSerial, other.mViewSerial);
12037 }
12038 
~BufferViewHelper()12039 BufferViewHelper::~BufferViewHelper() {}
12040 
init(Renderer * renderer,VkDeviceSize offset,VkDeviceSize size)12041 void BufferViewHelper::init(Renderer *renderer, VkDeviceSize offset, VkDeviceSize size)
12042 {
12043     ASSERT(mViews.empty());
12044 
12045     mOffset = offset;
12046     mSize   = size;
12047 
12048     if (!mViewSerial.valid())
12049     {
12050         mViewSerial = renderer->getResourceSerialFactory().generateImageOrBufferViewSerial();
12051     }
12052 
12053     mInitialized = true;
12054 }
12055 
release(ContextVk * contextVk)12056 void BufferViewHelper::release(ContextVk *contextVk)
12057 {
12058     if (!mInitialized)
12059     {
12060         return;
12061     }
12062 
12063     contextVk->flushDescriptorSetUpdates();
12064 
12065     GarbageObjects garbage;
12066 
12067     for (auto &formatAndView : mViews)
12068     {
12069         BufferView &view = formatAndView.second;
12070         ASSERT(view.valid());
12071 
12072         garbage.emplace_back(GetGarbage(&view));
12073     }
12074 
12075     if (!garbage.empty())
12076     {
12077         Renderer *renderer = contextVk->getRenderer();
12078         renderer->collectGarbage(mUse, std::move(garbage));
12079         // Update image view serial.
12080         mViewSerial = renderer->getResourceSerialFactory().generateImageOrBufferViewSerial();
12081     }
12082 
12083     mUse.reset();
12084     mViews.clear();
12085     mOffset      = 0;
12086     mSize        = 0;
12087     mInitialized = false;
12088 }
12089 
destroy(VkDevice device)12090 void BufferViewHelper::destroy(VkDevice device)
12091 {
12092     for (auto &formatAndView : mViews)
12093     {
12094         BufferView &view = formatAndView.second;
12095         view.destroy(device);
12096     }
12097 
12098     mViews.clear();
12099 
12100     mOffset = 0;
12101     mSize   = 0;
12102 
12103     mViewSerial = kInvalidImageOrBufferViewSerial;
12104 }
12105 
getView(Context * context,const BufferHelper & buffer,VkDeviceSize bufferOffset,const Format & format,const BufferView ** viewOut)12106 angle::Result BufferViewHelper::getView(Context *context,
12107                                         const BufferHelper &buffer,
12108                                         VkDeviceSize bufferOffset,
12109                                         const Format &format,
12110                                         const BufferView **viewOut)
12111 {
12112     ASSERT(format.valid());
12113 
12114     VkFormat viewVkFormat = format.getActualBufferVkFormat(false);
12115 
12116     auto iter = mViews.find(viewVkFormat);
12117     if (iter != mViews.end())
12118     {
12119         *viewOut = &iter->second;
12120         return angle::Result::Continue;
12121     }
12122 
12123     // If the size is not a multiple of pixelBytes, remove the extra bytes.  The last element cannot
12124     // be read anyway, and this is a requirement of Vulkan (for size to be a multiple of format
12125     // texel block size).
12126     const angle::Format &bufferFormat = format.getActualBufferFormat(false);
12127     const GLuint pixelBytes           = bufferFormat.pixelBytes;
12128     VkDeviceSize size                 = mSize - mSize % pixelBytes;
12129 
12130     VkBufferViewCreateInfo viewCreateInfo = {};
12131     viewCreateInfo.sType                  = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
12132     viewCreateInfo.buffer                 = buffer.getBuffer().getHandle();
12133     viewCreateInfo.format                 = viewVkFormat;
12134     viewCreateInfo.offset                 = mOffset + bufferOffset;
12135     viewCreateInfo.range                  = size;
12136 
12137     BufferView view;
12138     ANGLE_VK_TRY(context, view.init(context->getDevice(), viewCreateInfo));
12139 
12140     // Cache the view
12141     auto insertIter = mViews.insert({viewVkFormat, std::move(view)});
12142     *viewOut        = &insertIter.first->second;
12143     ASSERT(insertIter.second);
12144 
12145     return angle::Result::Continue;
12146 }
12147 
getSerial() const12148 ImageOrBufferViewSubresourceSerial BufferViewHelper::getSerial() const
12149 {
12150     ASSERT(mViewSerial.valid());
12151 
12152     ImageOrBufferViewSubresourceSerial serial = {};
12153     serial.viewSerial                         = mViewSerial;
12154     return serial;
12155 }
12156 
12157 // ShaderProgramHelper implementation.
12158 ShaderProgramHelper::ShaderProgramHelper()  = default;
12159 ShaderProgramHelper::~ShaderProgramHelper() = default;
12160 
valid(const gl::ShaderType shaderType) const12161 bool ShaderProgramHelper::valid(const gl::ShaderType shaderType) const
12162 {
12163     return mShaders[shaderType].valid();
12164 }
12165 
destroy(Renderer * renderer)12166 void ShaderProgramHelper::destroy(Renderer *renderer)
12167 {
12168     for (BindingPointer<ShaderModule> &shader : mShaders)
12169     {
12170         shader.reset();
12171     }
12172 }
12173 
release(ContextVk * contextVk)12174 void ShaderProgramHelper::release(ContextVk *contextVk)
12175 {
12176     for (BindingPointer<ShaderModule> &shader : mShaders)
12177     {
12178         shader.reset();
12179     }
12180 }
12181 
setShader(gl::ShaderType shaderType,RefCounted<ShaderModule> * shader)12182 void ShaderProgramHelper::setShader(gl::ShaderType shaderType, RefCounted<ShaderModule> *shader)
12183 {
12184     // The shaders must be set once and are not expected to change.
12185     ASSERT(!mShaders[shaderType].valid());
12186     mShaders[shaderType].set(shader);
12187 }
12188 
createMonolithicPipelineCreationTask(vk::Context * context,PipelineCacheAccess * pipelineCache,const GraphicsPipelineDesc & desc,const PipelineLayout & pipelineLayout,const SpecializationConstants & specConsts,PipelineHelper * pipeline) const12189 void ShaderProgramHelper::createMonolithicPipelineCreationTask(
12190     vk::Context *context,
12191     PipelineCacheAccess *pipelineCache,
12192     const GraphicsPipelineDesc &desc,
12193     const PipelineLayout &pipelineLayout,
12194     const SpecializationConstants &specConsts,
12195     PipelineHelper *pipeline) const
12196 {
12197     std::shared_ptr<CreateMonolithicPipelineTask> monolithicPipelineCreationTask =
12198         std::make_shared<CreateMonolithicPipelineTask>(context->getRenderer(), *pipelineCache,
12199                                                        pipelineLayout, mShaders, specConsts, desc);
12200 
12201     pipeline->setMonolithicPipelineCreationTask(std::move(monolithicPipelineCreationTask));
12202 }
12203 
getOrCreateComputePipeline(vk::Context * context,ComputePipelineCache * computePipelines,PipelineCacheAccess * pipelineCache,const PipelineLayout & pipelineLayout,ComputePipelineFlags pipelineFlags,PipelineSource source,PipelineHelper ** pipelineOut,const char * shaderName,VkSpecializationInfo * specializationInfo) const12204 angle::Result ShaderProgramHelper::getOrCreateComputePipeline(
12205     vk::Context *context,
12206     ComputePipelineCache *computePipelines,
12207     PipelineCacheAccess *pipelineCache,
12208     const PipelineLayout &pipelineLayout,
12209     ComputePipelineFlags pipelineFlags,
12210     PipelineSource source,
12211     PipelineHelper **pipelineOut,
12212     const char *shaderName,
12213     VkSpecializationInfo *specializationInfo) const
12214 {
12215     PipelineHelper *computePipeline = &(*computePipelines)[pipelineFlags.bits()];
12216 
12217     if (computePipeline->valid())
12218     {
12219         *pipelineOut = computePipeline;
12220         return angle::Result::Continue;
12221     }
12222 
12223     VkPipelineShaderStageCreateInfo shaderStage = {};
12224     VkComputePipelineCreateInfo createInfo      = {};
12225 
12226     shaderStage.sType               = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
12227     shaderStage.flags               = 0;
12228     shaderStage.stage               = VK_SHADER_STAGE_COMPUTE_BIT;
12229     shaderStage.module              = mShaders[gl::ShaderType::Compute].get().getHandle();
12230     shaderStage.pName               = shaderName ? shaderName : "main";
12231     shaderStage.pSpecializationInfo = specializationInfo;
12232 
12233     createInfo.sType              = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
12234     createInfo.flags              = 0;
12235     createInfo.stage              = shaderStage;
12236     createInfo.layout             = pipelineLayout.getHandle();
12237     createInfo.basePipelineHandle = VK_NULL_HANDLE;
12238     createInfo.basePipelineIndex  = 0;
12239 
12240     VkPipelineRobustnessCreateInfoEXT robustness = {};
12241     robustness.sType = VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO_EXT;
12242 
12243     // Enable robustness on the pipeline if needed.  Note that the global robustBufferAccess feature
12244     // must be disabled by default.
12245     if (pipelineFlags[ComputePipelineFlag::Robust])
12246     {
12247         ASSERT(context->getFeatures().supportsPipelineRobustness.enabled);
12248 
12249         robustness.storageBuffers = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT;
12250         robustness.uniformBuffers = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT;
12251         robustness.vertexInputs   = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DEVICE_DEFAULT_EXT;
12252         robustness.images         = VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DEVICE_DEFAULT_EXT;
12253 
12254         AddToPNextChain(&createInfo, &robustness);
12255     }
12256 
12257     // Restrict pipeline to protected or unprotected command buffers if possible.
12258     if (pipelineFlags[ComputePipelineFlag::Protected])
12259     {
12260         ASSERT(context->getFeatures().supportsPipelineProtectedAccess.enabled);
12261         createInfo.flags |= VK_PIPELINE_CREATE_PROTECTED_ACCESS_ONLY_BIT_EXT;
12262     }
12263     else if (context->getFeatures().supportsPipelineProtectedAccess.enabled)
12264     {
12265         createInfo.flags |= VK_PIPELINE_CREATE_NO_PROTECTED_ACCESS_BIT_EXT;
12266     }
12267 
12268     VkPipelineCreationFeedback feedback               = {};
12269     VkPipelineCreationFeedback perStageFeedback       = {};
12270     VkPipelineCreationFeedbackCreateInfo feedbackInfo = {};
12271     feedbackInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO;
12272     feedbackInfo.pPipelineCreationFeedback = &feedback;
12273     // Note: see comment in GraphicsPipelineDesc::initializePipeline about why per-stage feedback is
12274     // specified even though unused.
12275     feedbackInfo.pipelineStageCreationFeedbackCount = 1;
12276     feedbackInfo.pPipelineStageCreationFeedbacks    = &perStageFeedback;
12277 
12278     const bool supportsFeedback =
12279         context->getRenderer()->getFeatures().supportsPipelineCreationFeedback.enabled;
12280     if (supportsFeedback)
12281     {
12282         AddToPNextChain(&createInfo, &feedbackInfo);
12283     }
12284 
12285     vk::Pipeline pipeline;
12286     ANGLE_VK_TRY(context, pipelineCache->createComputePipeline(context, createInfo, &pipeline));
12287 
12288     vk::CacheLookUpFeedback lookUpFeedback = CacheLookUpFeedback::None;
12289 
12290     if (supportsFeedback)
12291     {
12292         const bool cacheHit =
12293             (feedback.flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT) !=
12294             0;
12295 
12296         lookUpFeedback = cacheHit ? CacheLookUpFeedback::Hit : CacheLookUpFeedback::Miss;
12297         ApplyPipelineCreationFeedback(context, feedback);
12298     }
12299 
12300     computePipeline->setComputePipeline(std::move(pipeline), lookUpFeedback);
12301 
12302     *pipelineOut = computePipeline;
12303     return angle::Result::Continue;
12304 }
12305 
12306 // ActiveHandleCounter implementation.
ActiveHandleCounter()12307 ActiveHandleCounter::ActiveHandleCounter() : mActiveCounts{}, mAllocatedCounts{} {}
12308 
12309 ActiveHandleCounter::~ActiveHandleCounter() = default;
12310 
12311 // CommandBufferAccess implementation.
12312 CommandBufferAccess::CommandBufferAccess()  = default;
12313 CommandBufferAccess::~CommandBufferAccess() = default;
12314 
onBufferRead(VkAccessFlags readAccessType,PipelineStage readStage,BufferHelper * buffer)12315 void CommandBufferAccess::onBufferRead(VkAccessFlags readAccessType,
12316                                        PipelineStage readStage,
12317                                        BufferHelper *buffer)
12318 {
12319     ASSERT(!buffer->isReleasedToExternal());
12320     mReadBuffers.emplace_back(buffer, readAccessType, readStage);
12321 }
12322 
onBufferWrite(VkAccessFlags writeAccessType,PipelineStage writeStage,BufferHelper * buffer)12323 void CommandBufferAccess::onBufferWrite(VkAccessFlags writeAccessType,
12324                                         PipelineStage writeStage,
12325                                         BufferHelper *buffer)
12326 {
12327     ASSERT(!buffer->isReleasedToExternal());
12328     mWriteBuffers.emplace_back(buffer, writeAccessType, writeStage);
12329 }
12330 
onImageRead(VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)12331 void CommandBufferAccess::onImageRead(VkImageAspectFlags aspectFlags,
12332                                       ImageLayout imageLayout,
12333                                       ImageHelper *image)
12334 {
12335     ASSERT(!image->isReleasedToExternal());
12336     ASSERT(image->getImageSerial().valid());
12337     mReadImages.emplace_back(image, aspectFlags, imageLayout);
12338 }
12339 
onImageWrite(gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)12340 void CommandBufferAccess::onImageWrite(gl::LevelIndex levelStart,
12341                                        uint32_t levelCount,
12342                                        uint32_t layerStart,
12343                                        uint32_t layerCount,
12344                                        VkImageAspectFlags aspectFlags,
12345                                        ImageLayout imageLayout,
12346                                        ImageHelper *image)
12347 {
12348     ASSERT(!image->isReleasedToExternal());
12349     ASSERT(image->getImageSerial().valid());
12350     mWriteImages.emplace_back(CommandBufferImageAccess{image, aspectFlags, imageLayout}, levelStart,
12351                               levelCount, layerStart, layerCount);
12352 }
12353 
onImageReadSubresources(gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)12354 void CommandBufferAccess::onImageReadSubresources(gl::LevelIndex levelStart,
12355                                                   uint32_t levelCount,
12356                                                   uint32_t layerStart,
12357                                                   uint32_t layerCount,
12358                                                   VkImageAspectFlags aspectFlags,
12359                                                   ImageLayout imageLayout,
12360                                                   ImageHelper *image)
12361 {
12362     ASSERT(!image->isReleasedToExternal());
12363     ASSERT(image->getImageSerial().valid());
12364     mReadImageSubresources.emplace_back(CommandBufferImageAccess{image, aspectFlags, imageLayout},
12365                                         levelStart, levelCount, layerStart, layerCount);
12366 }
12367 
onBufferExternalAcquireRelease(BufferHelper * buffer)12368 void CommandBufferAccess::onBufferExternalAcquireRelease(BufferHelper *buffer)
12369 {
12370     mExternalAcquireReleaseBuffers.emplace_back(CommandBufferBufferExternalAcquireRelease{buffer});
12371 }
12372 
onResourceAccess(Resource * resource)12373 void CommandBufferAccess::onResourceAccess(Resource *resource)
12374 {
12375     mAccessResources.emplace_back(CommandBufferResourceAccess{resource});
12376 }
12377 
12378 // DescriptorMetaCache implementation.
12379 MetaDescriptorPool::MetaDescriptorPool() = default;
12380 
~MetaDescriptorPool()12381 MetaDescriptorPool::~MetaDescriptorPool()
12382 {
12383     ASSERT(mPayload.empty());
12384 }
12385 
destroy(Renderer * renderer)12386 void MetaDescriptorPool::destroy(Renderer *renderer)
12387 {
12388     for (auto &iter : mPayload)
12389     {
12390         RefCountedDescriptorPool &refCountedPool = iter.second;
12391         ASSERT(!refCountedPool.isReferenced());
12392         refCountedPool.get().destroy(renderer);
12393     }
12394 
12395     mPayload.clear();
12396 }
12397 
bindCachedDescriptorPool(Context * context,const DescriptorSetLayoutDesc & descriptorSetLayoutDesc,uint32_t descriptorCountMultiplier,DescriptorSetLayoutCache * descriptorSetLayoutCache,DescriptorPoolPointer * descriptorPoolOut)12398 angle::Result MetaDescriptorPool::bindCachedDescriptorPool(
12399     Context *context,
12400     const DescriptorSetLayoutDesc &descriptorSetLayoutDesc,
12401     uint32_t descriptorCountMultiplier,
12402     DescriptorSetLayoutCache *descriptorSetLayoutCache,
12403     DescriptorPoolPointer *descriptorPoolOut)
12404 {
12405     auto cacheIter = mPayload.find(descriptorSetLayoutDesc);
12406     if (cacheIter != mPayload.end())
12407     {
12408         RefCountedDescriptorPool &descriptorPool = cacheIter->second;
12409         descriptorPoolOut->set(&descriptorPool);
12410         return angle::Result::Continue;
12411     }
12412 
12413     AtomicBindingPointer<DescriptorSetLayout> descriptorSetLayout;
12414     ANGLE_TRY(descriptorSetLayoutCache->getDescriptorSetLayout(context, descriptorSetLayoutDesc,
12415                                                                &descriptorSetLayout));
12416 
12417     DynamicDescriptorPool newDescriptorPool;
12418     ANGLE_TRY(InitDynamicDescriptorPool(context, descriptorSetLayoutDesc, descriptorSetLayout.get(),
12419                                         descriptorCountMultiplier, &newDescriptorPool));
12420 
12421     auto insertIter = mPayload.emplace(descriptorSetLayoutDesc, std::move(newDescriptorPool));
12422 
12423     RefCountedDescriptorPool &descriptorPool = insertIter.first->second;
12424     descriptorPoolOut->set(&descriptorPool);
12425 
12426     return angle::Result::Continue;
12427 }
12428 
12429 static_assert(static_cast<uint32_t>(PresentMode::ImmediateKHR) == VK_PRESENT_MODE_IMMEDIATE_KHR,
12430               "PresentMode must be updated");
12431 static_assert(static_cast<uint32_t>(PresentMode::MailboxKHR) == VK_PRESENT_MODE_MAILBOX_KHR,
12432               "PresentMode must be updated");
12433 static_assert(static_cast<uint32_t>(PresentMode::FifoKHR) == VK_PRESENT_MODE_FIFO_KHR,
12434               "PresentMode must be updated");
12435 static_assert(static_cast<uint32_t>(PresentMode::FifoRelaxedKHR) ==
12436                   VK_PRESENT_MODE_FIFO_RELAXED_KHR,
12437               "PresentMode must be updated");
12438 static_assert(static_cast<uint32_t>(PresentMode::SharedDemandRefreshKHR) ==
12439                   VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR,
12440               "PresentMode must be updated");
12441 static_assert(static_cast<uint32_t>(PresentMode::SharedContinuousRefreshKHR) ==
12442                   VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR,
12443               "PresentMode must be updated");
12444 
ConvertPresentModeToVkPresentMode(PresentMode presentMode)12445 VkPresentModeKHR ConvertPresentModeToVkPresentMode(PresentMode presentMode)
12446 {
12447     return static_cast<VkPresentModeKHR>(presentMode);
12448 }
12449 
ConvertVkPresentModeToPresentMode(VkPresentModeKHR vkPresentMode)12450 PresentMode ConvertVkPresentModeToPresentMode(VkPresentModeKHR vkPresentMode)
12451 {
12452     return static_cast<PresentMode>(vkPresentMode);
12453 }
12454 
12455 }  // namespace vk
12456 }  // namespace rx
12457