xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/vulkan/vk_helpers.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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/aligned_memory.h"
12 #include "common/utilities.h"
13 #include "common/vulkan/vk_headers.h"
14 #include "image_util/loadimage.h"
15 #include "libANGLE/Context.h"
16 #include "libANGLE/Display.h"
17 #include "libANGLE/renderer/driver_utils.h"
18 #include "libANGLE/renderer/renderer_utils.h"
19 #include "libANGLE/renderer/vulkan/BufferVk.h"
20 #include "libANGLE/renderer/vulkan/ContextVk.h"
21 #include "libANGLE/renderer/vulkan/DisplayVk.h"
22 #include "libANGLE/renderer/vulkan/FramebufferVk.h"
23 #include "libANGLE/renderer/vulkan/RenderTargetVk.h"
24 #include "libANGLE/renderer/vulkan/android/vk_android_utils.h"
25 #include "libANGLE/renderer/vulkan/vk_ref_counted_event.h"
26 #include "libANGLE/renderer/vulkan/vk_renderer.h"
27 #include "libANGLE/renderer/vulkan/vk_utils.h"
28 
29 namespace rx
30 {
31 namespace vk
32 {
33 namespace
34 {
35 // During descriptorSet cache eviction, we keep it in the cache only if it is recently used. If it
36 // has not been used in the past kDescriptorSetCacheRetireAge frames, it will be evicted.
37 constexpr uint32_t kDescriptorSetCacheRetireAge = 10;
38 
39 // ANGLE_robust_resource_initialization requires color textures to be initialized to zero.
40 constexpr VkClearColorValue kRobustInitColorValue = {{0, 0, 0, 0}};
41 // When emulating a texture, we want the emulated channels to be 0, with alpha 1.
42 constexpr VkClearColorValue kEmulatedInitColorValue = {{0, 0, 0, 1.0f}};
43 // ANGLE_robust_resource_initialization requires depth to be initialized to 1 and stencil to 0.
44 // We are fine with these values for emulated depth/stencil textures too.
45 constexpr VkClearDepthStencilValue kRobustInitDepthStencilValue = {1.0f, 0};
46 
47 constexpr VkImageAspectFlags kDepthStencilAspects =
48     VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_DEPTH_BIT;
49 
50 constexpr angle::PackedEnumMap<PipelineStage, VkPipelineStageFlagBits> kPipelineStageFlagBitMap = {
51     {PipelineStage::TopOfPipe, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT},
52     {PipelineStage::DrawIndirect, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT},
53     {PipelineStage::VertexInput, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT},
54     {PipelineStage::VertexShader, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT},
55     {PipelineStage::TessellationControl, VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT},
56     {PipelineStage::TessellationEvaluation, VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT},
57     {PipelineStage::GeometryShader, VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT},
58     {PipelineStage::TransformFeedback, VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT},
59     {PipelineStage::FragmentShadingRate,
60      VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR},
61     {PipelineStage::EarlyFragmentTest, VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT},
62     {PipelineStage::FragmentShader, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT},
63     {PipelineStage::LateFragmentTest, VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT},
64     {PipelineStage::ColorAttachmentOutput, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT},
65     {PipelineStage::ComputeShader, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT},
66     {PipelineStage::Transfer, VK_PIPELINE_STAGE_TRANSFER_BIT},
67     {PipelineStage::BottomOfPipe, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT},
68     {PipelineStage::Host, VK_PIPELINE_STAGE_HOST_BIT}};
69 
70 constexpr gl::ShaderMap<PipelineStage> kPipelineStageShaderMap = {
71     {gl::ShaderType::Vertex, PipelineStage::VertexShader},
72     {gl::ShaderType::TessControl, PipelineStage::TessellationControl},
73     {gl::ShaderType::TessEvaluation, PipelineStage::TessellationEvaluation},
74     {gl::ShaderType::Geometry, PipelineStage::GeometryShader},
75     {gl::ShaderType::Fragment, PipelineStage::FragmentShader},
76     {gl::ShaderType::Compute, PipelineStage::ComputeShader},
77 };
78 
79 // clang-format off
80 constexpr angle::PackedEnumMap<ImageLayout, ImageMemoryBarrierData> kImageMemoryBarrierData = {
81     {
82         ImageLayout::Undefined,
83         ImageMemoryBarrierData{
84             "Undefined",
85             VK_IMAGE_LAYOUT_UNDEFINED,
86             VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
87             VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
88             // Transition to: we don't expect to transition into Undefined.
89             0,
90             // Transition from: there's no data in the image to care about.
91             0,
92             ResourceAccess::ReadOnly,
93             PipelineStage::InvalidEnum,
94             // We do not directly using this layout in SetEvent. We transit to other layout before using
95             EventStage::InvalidEnum,
96             PipelineStageGroup::Other,
97         },
98     },
99     {
100         ImageLayout::ColorWrite,
101         ImageMemoryBarrierData{
102             "ColorWrite",
103             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
104             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
105             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
106             // Transition to: all reads and writes must happen after barrier.
107             VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
108             // Transition from: all writes must finish before barrier.
109             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
110             ResourceAccess::ReadWrite,
111             PipelineStage::ColorAttachmentOutput,
112             EventStage::ColorAttachmentOutput,
113             PipelineStageGroup::FragmentOnly,
114         },
115     },
116     {
117         ImageLayout::ColorWriteAndInput,
118         ImageMemoryBarrierData{
119             "ColorWriteAndInput",
120             VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ_KHR,
121             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
122             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
123             // Transition to: all reads and writes must happen after barrier.
124             VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
125             // Transition from: all writes must finish before barrier.
126             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
127             ResourceAccess::ReadWrite,
128             PipelineStage::ColorAttachmentOutput,
129             EventStage::ColorAttachmentOutput,
130             PipelineStageGroup::FragmentOnly,
131         },
132     },
133     {
134         ImageLayout::MSRTTEmulationColorUnresolveAndResolve,
135         ImageMemoryBarrierData{
136             "MSRTTEmulationColorUnresolveAndResolve",
137             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
138             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
139             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
140             // Transition to: all reads and writes must happen after barrier.
141             VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
142             // Transition from: all writes must finish before barrier.
143             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
144             ResourceAccess::ReadWrite,
145             PipelineStage::FragmentShader,
146             EventStage::ColorAttachmentOutputAndFragmentShader,
147             PipelineStageGroup::FragmentOnly,
148         },
149     },
150     {
151         ImageLayout::DepthWriteStencilWrite,
152         ImageMemoryBarrierData{
153             "DepthWriteStencilWrite",
154             VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
155             kAllDepthStencilPipelineStageFlags,
156             kAllDepthStencilPipelineStageFlags,
157             // Transition to: all reads and writes must happen after barrier.
158             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
159             // Transition from: all writes must finish before barrier.
160             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
161             ResourceAccess::ReadWrite,
162             PipelineStage::EarlyFragmentTest,
163             EventStage::AllFragmentTest,
164             PipelineStageGroup::FragmentOnly,
165         },
166     },
167     {
168         ImageLayout::DepthStencilWriteAndInput,
169         ImageMemoryBarrierData{
170             "DepthStencilWriteAndInput",
171             VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ_KHR,
172             kAllDepthStencilPipelineStageFlags,
173             kAllDepthStencilPipelineStageFlags,
174             // Transition to: all reads and writes must happen after barrier.
175             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
176             // Transition from: all writes must finish before barrier.
177             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
178             ResourceAccess::ReadWrite,
179             PipelineStage::EarlyFragmentTest,
180             EventStage::AllFragmentTest,
181             PipelineStageGroup::FragmentOnly,
182         },
183     },
184     {
185         ImageLayout::DepthWriteStencilRead,
186         ImageMemoryBarrierData{
187             "DepthWriteStencilRead",
188             VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL,
189             kAllDepthStencilPipelineStageFlags,
190             kAllDepthStencilPipelineStageFlags,
191             // Transition to: all reads and writes must happen after barrier.
192             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
193             // Transition from: all writes must finish before barrier.
194             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
195             ResourceAccess::ReadWrite,
196             PipelineStage::EarlyFragmentTest,
197             EventStage::AllFragmentTest,
198             PipelineStageGroup::FragmentOnly,
199         },
200     },
201     {
202         ImageLayout::DepthWriteStencilReadFragmentShaderStencilRead,
203         ImageMemoryBarrierData{
204             "DepthWriteStencilReadFragmentShaderStencilRead",
205             VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL,
206             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
207             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
208             // Transition to: all reads and writes must happen after barrier.
209             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
210             // Transition from: all writes must finish before barrier.
211             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
212             ResourceAccess::ReadWrite,
213             PipelineStage::EarlyFragmentTest,
214             EventStage::AllFragmentTestAndFragmentShader,
215             PipelineStageGroup::FragmentOnly,
216         },
217     },
218     {
219         ImageLayout::DepthWriteStencilReadAllShadersStencilRead,
220         ImageMemoryBarrierData{
221             "DepthWriteStencilReadAllShadersStencilRead",
222             VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL,
223             kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
224             kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
225             // Transition to: all reads and writes must happen after barrier.
226             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
227             // Transition from: all writes must finish before barrier.
228             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
229             ResourceAccess::ReadWrite,
230             PipelineStage::VertexShader,
231             EventStage::AllFragmentTestAndAllShaders,
232             PipelineStageGroup::Other,
233         },
234     },
235     {
236         ImageLayout::DepthReadStencilWrite,
237         ImageMemoryBarrierData{
238             "DepthReadStencilWrite",
239             VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL,
240             kAllDepthStencilPipelineStageFlags,
241             kAllDepthStencilPipelineStageFlags,
242             // Transition to: all reads and writes must happen after barrier.
243             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
244             // Transition from: all writes must finish before barrier.
245             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
246             ResourceAccess::ReadWrite,
247             PipelineStage::EarlyFragmentTest,
248             EventStage::AllFragmentTest,
249             PipelineStageGroup::FragmentOnly,
250         },
251     },
252     {
253         ImageLayout::DepthReadStencilWriteFragmentShaderDepthRead,
254         ImageMemoryBarrierData{
255             "DepthReadStencilWriteFragmentShaderDepthRead",
256             VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL,
257             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
258             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
259             // Transition to: all reads and writes must happen after barrier.
260             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
261             // Transition from: all writes must finish before barrier.
262             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
263             ResourceAccess::ReadWrite,
264             PipelineStage::EarlyFragmentTest,
265             EventStage::AllFragmentTestAndFragmentShader,
266             PipelineStageGroup::FragmentOnly,
267         },
268     },
269     {
270         ImageLayout::DepthReadStencilWriteAllShadersDepthRead,
271         ImageMemoryBarrierData{
272             "DepthReadStencilWriteAllShadersDepthRead",
273             VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL,
274             kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
275             kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
276             // Transition to: all reads and writes must happen after barrier.
277             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
278             // Transition from: all writes must finish before barrier.
279             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
280             ResourceAccess::ReadWrite,
281             PipelineStage::VertexShader,
282             EventStage::AllFragmentTestAndAllShaders,
283             PipelineStageGroup::Other,
284         },
285     },
286     {
287         ImageLayout::DepthReadStencilRead,
288             ImageMemoryBarrierData{
289             "DepthReadStencilRead",
290             VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
291             kAllDepthStencilPipelineStageFlags,
292             kAllDepthStencilPipelineStageFlags,
293             // Transition to: all reads must happen after barrier.
294             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
295             // Transition from: RAR and WAR don't need memory barrier.
296             0,
297             ResourceAccess::ReadOnly,
298             PipelineStage::EarlyFragmentTest,
299             EventStage::AllFragmentTest,
300             PipelineStageGroup::FragmentOnly,
301         },
302     },
303 
304     {
305         ImageLayout::DepthReadStencilReadFragmentShaderRead,
306             ImageMemoryBarrierData{
307             "DepthReadStencilReadFragmentShaderRead",
308             VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
309             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
310             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
311             // Transition to: all reads must happen after barrier.
312             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
313             // Transition from: RAR and WAR don't need memory barrier.
314             0,
315             ResourceAccess::ReadOnly,
316             PipelineStage::EarlyFragmentTest,
317             EventStage::AllFragmentTestAndFragmentShader,
318             PipelineStageGroup::FragmentOnly,
319         },
320     },
321     {
322         ImageLayout::DepthReadStencilReadAllShadersRead,
323             ImageMemoryBarrierData{
324             "DepthReadStencilReadAllShadersRead",
325             VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
326             kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
327             kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
328             // Transition to: all reads must happen after barrier.
329             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
330             // Transition from: RAR and WAR don't need memory barrier.
331             0,
332             ResourceAccess::ReadOnly,
333             PipelineStage::VertexShader,
334             EventStage::AllFragmentTestAndAllShaders,
335             PipelineStageGroup::Other,
336         },
337     },
338     {
339         ImageLayout::ColorWriteFragmentShaderFeedback,
340         ImageMemoryBarrierData{
341             "ColorWriteFragmentShaderFeedback",
342             VK_IMAGE_LAYOUT_GENERAL,
343             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
344             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
345             // Transition to: all reads and writes must happen after barrier.
346             VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
347             // Transition from: all writes must finish before barrier.
348             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
349             ResourceAccess::ReadWrite,
350             PipelineStage::FragmentShader,
351             EventStage::ColorAttachmentOutputAndFragmentShader,
352             PipelineStageGroup::FragmentOnly,
353         },
354     },
355     {
356         ImageLayout::ColorWriteAllShadersFeedback,
357         ImageMemoryBarrierData{
358             "ColorWriteAllShadersFeedback",
359             VK_IMAGE_LAYOUT_GENERAL,
360             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | kAllShadersPipelineStageFlags,
361             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | kAllShadersPipelineStageFlags,
362             // Transition to: all reads and writes must happen after barrier.
363             VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
364             // Transition from: all writes must finish before barrier.
365             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
366             ResourceAccess::ReadWrite,
367             // In case of multiple destination stages, We barrier the earliest stage
368             PipelineStage::VertexShader,
369             EventStage::ColorAttachmentOutputAndAllShaders,
370             PipelineStageGroup::Other,
371         },
372     },
373     {
374         ImageLayout::DepthStencilFragmentShaderFeedback,
375         ImageMemoryBarrierData{
376             "DepthStencilFragmentShaderFeedback",
377             VK_IMAGE_LAYOUT_GENERAL,
378             kAllDepthStencilPipelineStageFlags | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
379             kAllDepthStencilPipelineStageFlags | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
380             // Transition to: all reads and writes must happen after barrier.
381             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
382             // Transition from: all writes must finish before barrier.
383             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
384             ResourceAccess::ReadWrite,
385             PipelineStage::FragmentShader,
386             EventStage::AllFragmentTestAndFragmentShader,
387             PipelineStageGroup::FragmentOnly,
388         },
389     },
390     {
391         ImageLayout::DepthStencilAllShadersFeedback,
392         ImageMemoryBarrierData{
393             "DepthStencilAllShadersFeedback",
394             VK_IMAGE_LAYOUT_GENERAL,
395             kAllDepthStencilPipelineStageFlags | kAllShadersPipelineStageFlags,
396             kAllDepthStencilPipelineStageFlags | kAllShadersPipelineStageFlags,
397             // Transition to: all reads and writes must happen after barrier.
398             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
399             // Transition from: all writes must finish before barrier.
400             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
401             ResourceAccess::ReadWrite,
402             // In case of multiple destination stages, We barrier the earliest stage
403             PipelineStage::VertexShader,
404             EventStage::AllFragmentTestAndAllShaders,
405             PipelineStageGroup::Other,
406         },
407     },
408     {
409         ImageLayout::DepthStencilResolve,
410         ImageMemoryBarrierData{
411             "DepthStencilResolve",
412             VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
413             // Note: depth/stencil resolve uses color output stage and mask!
414             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
415             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
416             // Transition to: all reads and writes must happen after barrier.
417             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
418             // Transition from: all writes must finish before barrier.
419             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
420             ResourceAccess::ReadWrite,
421             PipelineStage::ColorAttachmentOutput,
422             EventStage::ColorAttachmentOutput,
423             PipelineStageGroup::FragmentOnly,
424         },
425     },
426     {
427         ImageLayout::MSRTTEmulationDepthStencilUnresolveAndResolve,
428         ImageMemoryBarrierData{
429             "MSRTTEmulationDepthStencilUnresolveAndResolve",
430             VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
431             // Note: depth/stencil resolve uses color output stage and mask!
432             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
433             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
434             // Transition to: all reads and writes must happen after barrier.
435             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
436             // Transition from: all writes must finish before barrier.
437             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
438             ResourceAccess::ReadWrite,
439             PipelineStage::FragmentShader,
440             EventStage::ColorAttachmentOutputAndFragmentShader,
441             PipelineStageGroup::FragmentOnly,
442         },
443     },
444     {
445         ImageLayout::Present,
446         ImageMemoryBarrierData{
447             "Present",
448             VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
449             // Transition to: do not delay execution of commands in the second synchronization
450             // scope. Allow layout transition to be delayed until present semaphore is signaled.
451             VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
452             // Transition from: use same stages as in Acquire Image Semaphore stage mask in order to
453             // build a dependency chain from the Acquire Image Semaphore to the layout transition's
454             // first synchronization scope.
455             kSwapchainAcquireImageWaitStageFlags,
456             // Transition to: vkQueuePresentKHR automatically performs the appropriate memory barriers:
457             //
458             // > Any writes to memory backing the images referenced by the pImageIndices and
459             // > pSwapchains members of pPresentInfo, that are available before vkQueuePresentKHR
460             // > is executed, are automatically made visible to the read access performed by the
461             // > presentation engine.
462             0,
463             // Transition from: RAR and WAR don't need memory barrier.
464             0,
465             ResourceAccess::ReadOnly,
466             PipelineStage::BottomOfPipe,
467             // We do not directly using this layout in SetEvent.
468             EventStage::InvalidEnum,
469             PipelineStageGroup::Other,
470         },
471     },
472     {
473         ImageLayout::SharedPresent,
474         ImageMemoryBarrierData{
475             "SharedPresent",
476             VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR,
477             // All currently possible stages for SharedPresent
478             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
479             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
480             // Transition to: all reads and writes must happen after barrier.
481             VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
482             // Transition from: all writes must finish before barrier.
483             VK_ACCESS_MEMORY_WRITE_BIT,
484             ResourceAccess::ReadWrite,
485             PipelineStage::BottomOfPipe,
486             EventStage::ColorAttachmentOutputAndFragmentShaderAndTransfer,
487             PipelineStageGroup::Other,
488         },
489     },
490     {
491         ImageLayout::ExternalPreInitialized,
492         ImageMemoryBarrierData{
493             "ExternalPreInitialized",
494             // Binding a VkImage with an initial layout of VK_IMAGE_LAYOUT_UNDEFINED to external
495             // memory whose content has already been defined does not make the content undefined
496             // (see 12.8.1.  External Resource Sharing).
497             //
498             // Note that for external memory objects, if the content is already defined, the
499             // ownership rules imply that the first operation on the texture must be a call to
500             // glWaitSemaphoreEXT that grants ownership of the image and informs us of the true
501             // layout.  If the content is not already defined, the first operation may not be a
502             // glWaitSemaphore, but in this case undefined layout is appropriate.
503             VK_IMAGE_LAYOUT_UNDEFINED,
504             VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
505             VK_PIPELINE_STAGE_HOST_BIT | VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
506             // Transition to: we don't expect to transition into PreInitialized.
507             0,
508             // Transition from: all writes must finish before barrier.
509             VK_ACCESS_MEMORY_WRITE_BIT,
510             ResourceAccess::ReadOnly,
511             PipelineStage::InvalidEnum,
512             // We do not directly using this layout in SetEvent. We transit to internal layout before using
513             EventStage::InvalidEnum,
514             PipelineStageGroup::Other,
515         },
516     },
517     {
518         ImageLayout::ExternalShadersReadOnly,
519         ImageMemoryBarrierData{
520             "ExternalShadersReadOnly",
521             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
522             VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
523             VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
524             // Transition to: all reads must happen after barrier.
525             VK_ACCESS_SHADER_READ_BIT,
526             // Transition from: RAR and WAR don't need memory barrier.
527             0,
528             ResourceAccess::ReadOnly,
529             // In case of multiple destination stages, We barrier the earliest stage
530             PipelineStage::TopOfPipe,
531             // We do not directly using this layout in SetEvent. We transit to internal layout before using
532             EventStage::InvalidEnum,
533             PipelineStageGroup::Other,
534         },
535     },
536     {
537         ImageLayout::ExternalShadersWrite,
538         ImageMemoryBarrierData{
539             "ExternalShadersWrite",
540             VK_IMAGE_LAYOUT_GENERAL,
541             VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
542             VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
543             // Transition to: all reads and writes must happen after barrier.
544             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
545             // Transition from: all writes must finish before barrier.
546             VK_ACCESS_SHADER_WRITE_BIT,
547             ResourceAccess::ReadWrite,
548             // In case of multiple destination stages, We barrier the earliest stage
549             PipelineStage::TopOfPipe,
550             // We do not directly using this layout in SetEvent. We transit to internal layout before using
551             EventStage::InvalidEnum,
552             PipelineStageGroup::Other,
553         },
554     },
555     {
556         ImageLayout::TransferSrc,
557         ImageMemoryBarrierData{
558             "TransferSrc",
559             VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
560             VK_PIPELINE_STAGE_TRANSFER_BIT,
561             VK_PIPELINE_STAGE_TRANSFER_BIT,
562             // Transition to: all reads must happen after barrier.
563             VK_ACCESS_TRANSFER_READ_BIT,
564             // Transition from: RAR and WAR don't need memory barrier.
565             0,
566             ResourceAccess::ReadOnly,
567             PipelineStage::Transfer,
568             EventStage::Transfer,
569             PipelineStageGroup::Other,
570         },
571     },
572     {
573         ImageLayout::TransferDst,
574         ImageMemoryBarrierData{
575             "TransferDst",
576             VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
577             VK_PIPELINE_STAGE_TRANSFER_BIT,
578             VK_PIPELINE_STAGE_TRANSFER_BIT,
579             // Transition to: all writes must happen after barrier.
580             VK_ACCESS_TRANSFER_WRITE_BIT,
581             // Transition from: all writes must finish before barrier.
582             VK_ACCESS_TRANSFER_WRITE_BIT,
583             ResourceAccess::ReadWrite,
584             PipelineStage::Transfer,
585             EventStage::Transfer,
586             PipelineStageGroup::Other,
587         },
588     },
589     {
590         ImageLayout::TransferSrcDst,
591         ImageMemoryBarrierData{
592             "TransferSrcDst",
593             VK_IMAGE_LAYOUT_GENERAL,
594             VK_PIPELINE_STAGE_TRANSFER_BIT,
595             VK_PIPELINE_STAGE_TRANSFER_BIT,
596             // Transition to: all reads and writes must happen after barrier.
597             VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
598             // Transition from: all writes must finish before barrier.
599             VK_ACCESS_TRANSFER_WRITE_BIT,
600             ResourceAccess::ReadWrite,
601             PipelineStage::Transfer,
602             EventStage::Transfer,
603             PipelineStageGroup::Other,
604         },
605     },
606     {
607         ImageLayout::HostCopy,
608         ImageMemoryBarrierData{
609             "HostCopy",
610             VK_IMAGE_LAYOUT_GENERAL,
611             VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
612             VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
613             // Transition to: we don't expect to transition into HostCopy on the GPU.
614             0,
615             // Transition from: the data was initialized in the image by the host.  Note that we
616             // only transition to this layout if the image was previously in UNDEFINED, in which
617             // case it didn't contain any data prior to the host copy either.
618             0,
619             ResourceAccess::ReadOnly,
620             PipelineStage::InvalidEnum,
621             // We do not directly using this layout in SetEvent.
622             EventStage::InvalidEnum,
623             PipelineStageGroup::Other,
624         },
625     },
626     {
627         ImageLayout::VertexShaderReadOnly,
628         ImageMemoryBarrierData{
629             "VertexShaderReadOnly",
630             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
631             VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
632             VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
633             // Transition to: all reads must happen after barrier.
634             VK_ACCESS_SHADER_READ_BIT,
635             // Transition from: RAR and WAR don't need memory barrier.
636             0,
637             ResourceAccess::ReadOnly,
638             PipelineStage::VertexShader,
639             EventStage::VertexShader,
640             PipelineStageGroup::PreFragmentOnly,
641         },
642     },
643     {
644         ImageLayout::VertexShaderWrite,
645         ImageMemoryBarrierData{
646             "VertexShaderWrite",
647             VK_IMAGE_LAYOUT_GENERAL,
648             VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
649             VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
650             // Transition to: all reads and writes must happen after barrier.
651             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
652             // Transition from: all writes must finish before barrier.
653             VK_ACCESS_SHADER_WRITE_BIT,
654             ResourceAccess::ReadWrite,
655             PipelineStage::VertexShader,
656             EventStage::VertexShader,
657             PipelineStageGroup::PreFragmentOnly,
658         },
659     },
660     {
661         ImageLayout::PreFragmentShadersReadOnly,
662         ImageMemoryBarrierData{
663             "PreFragmentShadersReadOnly",
664             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
665             kPreFragmentStageFlags,
666             kPreFragmentStageFlags,
667             // Transition to: all reads must happen after barrier.
668             VK_ACCESS_SHADER_READ_BIT,
669             // Transition from: RAR and WAR don't need memory barrier.
670             0,
671             ResourceAccess::ReadOnly,
672             // In case of multiple destination stages, We barrier the earliest stage
673             PipelineStage::VertexShader,
674             EventStage::PreFragmentShaders,
675             PipelineStageGroup::PreFragmentOnly,
676         },
677     },
678     {
679         ImageLayout::PreFragmentShadersWrite,
680         ImageMemoryBarrierData{
681             "PreFragmentShadersWrite",
682             VK_IMAGE_LAYOUT_GENERAL,
683             kPreFragmentStageFlags,
684             kPreFragmentStageFlags,
685             // Transition to: all reads and writes must happen after barrier.
686             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
687             // Transition from: all writes must finish before barrier.
688             VK_ACCESS_SHADER_WRITE_BIT,
689             ResourceAccess::ReadWrite,
690             // In case of multiple destination stages, We barrier the earliest stage
691             PipelineStage::VertexShader,
692             EventStage::PreFragmentShaders,
693             PipelineStageGroup::PreFragmentOnly,
694         },
695     },
696     {
697         ImageLayout::FragmentShadingRateAttachmentReadOnly,
698         ImageMemoryBarrierData{
699             "FragmentShadingRateAttachmentReadOnly",
700             VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR,
701             VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR,
702             VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR,
703             // Transition to: all reads must happen after barrier.
704             VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR,
705             // Transition from: RAR and WAR don't need memory barrier.
706             0,
707             ResourceAccess::ReadOnly,
708             PipelineStage::FragmentShadingRate,
709             EventStage::FragmentShadingRate,
710             PipelineStageGroup::Other,
711         },
712     },
713     {
714         ImageLayout::FragmentShaderReadOnly,
715         ImageMemoryBarrierData{
716             "FragmentShaderReadOnly",
717             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
718             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
719             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
720             // Transition to: all reads must happen after barrier.
721             VK_ACCESS_SHADER_READ_BIT,
722             // Transition from: RAR and WAR don't need memory barrier.
723             0,
724             ResourceAccess::ReadOnly,
725             PipelineStage::FragmentShader,
726             EventStage::FragmentShader,
727             PipelineStageGroup::FragmentOnly,
728         },
729     },
730     {
731         ImageLayout::FragmentShaderWrite,
732         ImageMemoryBarrierData{
733             "FragmentShaderWrite",
734             VK_IMAGE_LAYOUT_GENERAL,
735             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
736             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
737             // Transition to: all reads and writes must happen after barrier.
738             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
739             // Transition from: all writes must finish before barrier.
740             VK_ACCESS_SHADER_WRITE_BIT,
741             ResourceAccess::ReadWrite,
742             PipelineStage::FragmentShader,
743             EventStage::FragmentShader,
744             PipelineStageGroup::FragmentOnly,
745         },
746     },
747     {
748         ImageLayout::ComputeShaderReadOnly,
749         ImageMemoryBarrierData{
750             "ComputeShaderReadOnly",
751             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
752             VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
753             VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
754             // Transition to: all reads must happen after barrier.
755             VK_ACCESS_SHADER_READ_BIT,
756             // Transition from: RAR and WAR don't need memory barrier.
757             0,
758             ResourceAccess::ReadOnly,
759             PipelineStage::ComputeShader,
760             EventStage::ComputeShader,
761             PipelineStageGroup::ComputeOnly,
762         },
763     },
764     {
765         ImageLayout::ComputeShaderWrite,
766         ImageMemoryBarrierData{
767             "ComputeShaderWrite",
768             VK_IMAGE_LAYOUT_GENERAL,
769             VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
770             VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
771             // Transition to: all reads and writes must happen after barrier.
772             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
773             // Transition from: all writes must finish before barrier.
774             VK_ACCESS_SHADER_WRITE_BIT,
775             ResourceAccess::ReadWrite,
776             PipelineStage::ComputeShader,
777             EventStage::ComputeShader,
778             PipelineStageGroup::ComputeOnly,
779         },
780     },
781     {
782         ImageLayout::AllGraphicsShadersReadOnly,
783         ImageMemoryBarrierData{
784             "AllGraphicsShadersReadOnly",
785             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
786             kAllShadersPipelineStageFlags,
787             kAllShadersPipelineStageFlags,
788             // Transition to: all reads must happen after barrier.
789             VK_ACCESS_SHADER_READ_BIT,
790             // Transition from: RAR and WAR don't need memory barrier.
791             0,
792             ResourceAccess::ReadOnly,
793             // In case of multiple destination stages, We barrier the earliest stage
794             PipelineStage::VertexShader,
795             EventStage::AllShaders,
796             PipelineStageGroup::Other,
797         },
798     },
799     {
800         ImageLayout::AllGraphicsShadersWrite,
801         ImageMemoryBarrierData{
802             "AllGraphicsShadersWrite",
803             VK_IMAGE_LAYOUT_GENERAL,
804             kAllShadersPipelineStageFlags,
805             kAllShadersPipelineStageFlags,
806             // Transition to: all reads and writes must happen after barrier.
807             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
808             // Transition from: all writes must finish before barrier.
809             VK_ACCESS_SHADER_WRITE_BIT,
810             ResourceAccess::ReadWrite,
811             // In case of multiple destination stages, We barrier the earliest stage
812             PipelineStage::VertexShader,
813             EventStage::AllShaders,
814             PipelineStageGroup::Other,
815         },
816     },
817     {
818         ImageLayout::TransferDstAndComputeWrite,
819         ImageMemoryBarrierData{
820             "TransferDstAndComputeWrite",
821             VK_IMAGE_LAYOUT_GENERAL,
822             VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
823             VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
824             // Transition to: all reads and writes must happen after barrier.
825             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT,
826             // Transition from: all writes must finish before barrier.
827             VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
828             ResourceAccess::ReadWrite,
829             // In case of multiple destination stages, We barrier the earliest stage
830             PipelineStage::ComputeShader,
831             EventStage::TransferAndComputeShader,
832             PipelineStageGroup::Other,
833         },
834     },
835 };
836 // clang-format on
837 
GetImageLayoutEventStage(ImageLayout layout)838 EventStage GetImageLayoutEventStage(ImageLayout layout)
839 {
840     const ImageMemoryBarrierData &barrierData = kImageMemoryBarrierData[layout];
841     return barrierData.eventStage;
842 }
843 
HasBothDepthAndStencilAspects(VkImageAspectFlags aspectFlags)844 bool HasBothDepthAndStencilAspects(VkImageAspectFlags aspectFlags)
845 {
846     return IsMaskFlagSet(aspectFlags, kDepthStencilAspects);
847 }
848 
GetContentDefinedLayerRangeBits(uint32_t layerStart,uint32_t layerCount,uint32_t maxLayerCount)849 uint8_t GetContentDefinedLayerRangeBits(uint32_t layerStart,
850                                         uint32_t layerCount,
851                                         uint32_t maxLayerCount)
852 {
853     uint8_t layerRangeBits = layerCount >= maxLayerCount ? static_cast<uint8_t>(~0u)
854                                                          : angle::BitMask<uint8_t>(layerCount);
855     layerRangeBits <<= layerStart;
856 
857     return layerRangeBits;
858 }
859 
GetImageLayerCountForView(const ImageHelper & image)860 uint32_t GetImageLayerCountForView(const ImageHelper &image)
861 {
862     // Depth > 1 means this is a 3D texture and depth is our layer count
863     return image.getExtents().depth > 1 ? image.getExtents().depth : image.getLayerCount();
864 }
865 
ReleaseImageViews(ImageViewVector * imageViewVector,GarbageObjects * garbage)866 void ReleaseImageViews(ImageViewVector *imageViewVector, GarbageObjects *garbage)
867 {
868     for (ImageView &imageView : *imageViewVector)
869     {
870         if (imageView.valid())
871         {
872             garbage->emplace_back(GetGarbage(&imageView));
873         }
874     }
875     imageViewVector->clear();
876 }
877 
DestroyImageViews(ImageViewVector * imageViewVector,VkDevice device)878 void DestroyImageViews(ImageViewVector *imageViewVector, VkDevice device)
879 {
880     for (ImageView &imageView : *imageViewVector)
881     {
882         imageView.destroy(device);
883     }
884     imageViewVector->clear();
885 }
886 
ReleaseLayerLevelImageViews(LayerLevelImageViewVector * imageViewVector,GarbageObjects * garbage)887 void ReleaseLayerLevelImageViews(LayerLevelImageViewVector *imageViewVector,
888                                  GarbageObjects *garbage)
889 {
890     for (ImageViewVector &layerViews : *imageViewVector)
891     {
892         for (ImageView &imageView : layerViews)
893         {
894             if (imageView.valid())
895             {
896                 garbage->emplace_back(GetGarbage(&imageView));
897             }
898         }
899     }
900     imageViewVector->clear();
901 }
902 
DestroyLayerLevelImageViews(LayerLevelImageViewVector * imageViewVector,VkDevice device)903 void DestroyLayerLevelImageViews(LayerLevelImageViewVector *imageViewVector, VkDevice device)
904 {
905     for (ImageViewVector &layerViews : *imageViewVector)
906     {
907         for (ImageView &imageView : layerViews)
908         {
909             imageView.destroy(device);
910         }
911     }
912     imageViewVector->clear();
913 }
914 
ReleaseSubresourceImageViews(SubresourceImageViewMap * imageViews,GarbageObjects * garbage)915 void ReleaseSubresourceImageViews(SubresourceImageViewMap *imageViews, GarbageObjects *garbage)
916 {
917     for (auto &iter : *imageViews)
918     {
919         std::unique_ptr<ImageView> &imageView = iter.second;
920         if (imageView->valid())
921         {
922             garbage->emplace_back(GetGarbage(imageView.get()));
923         }
924     }
925     imageViews->clear();
926 }
927 
DestroySubresourceImageViews(SubresourceImageViewMap * imageViews,VkDevice device)928 void DestroySubresourceImageViews(SubresourceImageViewMap *imageViews, VkDevice device)
929 {
930     for (auto &iter : *imageViews)
931     {
932         std::unique_ptr<ImageView> &imageView = iter.second;
933         imageView->destroy(device);
934     }
935     imageViews->clear();
936 }
937 
GetLevelImageView(ImageViewVector * imageViews,LevelIndex levelVk,uint32_t levelCount)938 ImageView *GetLevelImageView(ImageViewVector *imageViews, LevelIndex levelVk, uint32_t levelCount)
939 {
940     // Lazily allocate the storage for image views. We allocate the full level count because we
941     // don't want to trigger any std::vector reallocations. Reallocations could invalidate our
942     // view pointers.
943     if (imageViews->empty())
944     {
945         imageViews->resize(levelCount);
946     }
947     ASSERT(imageViews->size() > levelVk.get());
948 
949     return &(*imageViews)[levelVk.get()];
950 }
951 
GetLevelLayerImageView(LayerLevelImageViewVector * imageViews,LevelIndex levelVk,uint32_t layer,uint32_t levelCount,uint32_t layerCount)952 ImageView *GetLevelLayerImageView(LayerLevelImageViewVector *imageViews,
953                                   LevelIndex levelVk,
954                                   uint32_t layer,
955                                   uint32_t levelCount,
956                                   uint32_t layerCount)
957 {
958     // Lazily allocate the storage for image views. We allocate the full layer count because we
959     // don't want to trigger any std::vector reallocations. Reallocations could invalidate our
960     // view pointers.
961     if (imageViews->empty())
962     {
963         imageViews->resize(layerCount);
964     }
965     ASSERT(imageViews->size() > layer);
966 
967     return GetLevelImageView(&(*imageViews)[layer], levelVk, levelCount);
968 }
969 
970 // Special rules apply to VkBufferImageCopy with depth/stencil. The components are tightly packed
971 // into a depth or stencil section of the destination buffer. See the spec:
972 // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkBufferImageCopy.html
GetDepthStencilImageToBufferFormat(const angle::Format & imageFormat,VkImageAspectFlagBits copyAspect)973 const angle::Format &GetDepthStencilImageToBufferFormat(const angle::Format &imageFormat,
974                                                         VkImageAspectFlagBits copyAspect)
975 {
976     if (copyAspect == VK_IMAGE_ASPECT_STENCIL_BIT)
977     {
978         ASSERT(imageFormat.id == angle::FormatID::D24_UNORM_S8_UINT ||
979                imageFormat.id == angle::FormatID::D32_FLOAT_S8X24_UINT ||
980                imageFormat.id == angle::FormatID::S8_UINT);
981         return angle::Format::Get(angle::FormatID::S8_UINT);
982     }
983 
984     ASSERT(copyAspect == VK_IMAGE_ASPECT_DEPTH_BIT);
985 
986     switch (imageFormat.id)
987     {
988         case angle::FormatID::D16_UNORM:
989             return imageFormat;
990         case angle::FormatID::D24_UNORM_X8_UINT:
991             return imageFormat;
992         case angle::FormatID::D24_UNORM_S8_UINT:
993             return angle::Format::Get(angle::FormatID::D24_UNORM_X8_UINT);
994         case angle::FormatID::D32_FLOAT:
995             return imageFormat;
996         case angle::FormatID::D32_FLOAT_S8X24_UINT:
997             return angle::Format::Get(angle::FormatID::D32_FLOAT);
998         default:
999             UNREACHABLE();
1000             return imageFormat;
1001     }
1002 }
1003 
GetRobustResourceClearValue(const angle::Format & intendedFormat,const angle::Format & actualFormat)1004 VkClearValue GetRobustResourceClearValue(const angle::Format &intendedFormat,
1005                                          const angle::Format &actualFormat)
1006 {
1007     VkClearValue clearValue = {};
1008     if (intendedFormat.hasDepthOrStencilBits())
1009     {
1010         clearValue.depthStencil = kRobustInitDepthStencilValue;
1011     }
1012     else
1013     {
1014         clearValue.color = HasEmulatedImageChannels(intendedFormat, actualFormat)
1015                                ? kEmulatedInitColorValue
1016                                : kRobustInitColorValue;
1017     }
1018     return clearValue;
1019 }
1020 
IsShaderReadOnlyLayout(const ImageMemoryBarrierData & imageLayout)1021 bool IsShaderReadOnlyLayout(const ImageMemoryBarrierData &imageLayout)
1022 {
1023     // We also use VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL for texture sample from depth
1024     // texture. See GetImageReadLayout() for detail.
1025     return imageLayout.layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ||
1026            imageLayout.layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
1027 }
1028 
IsAnySubresourceContentDefined(const gl::TexLevelArray<angle::BitSet8<8>> & contentDefined)1029 bool IsAnySubresourceContentDefined(const gl::TexLevelArray<angle::BitSet8<8>> &contentDefined)
1030 {
1031     for (const angle::BitSet8<8> &levelContentDefined : contentDefined)
1032     {
1033         if (levelContentDefined.any())
1034         {
1035             return true;
1036         }
1037     }
1038     return false;
1039 }
1040 
ExtendRenderPassInvalidateArea(const gl::Rectangle & invalidateArea,gl::Rectangle * out)1041 void ExtendRenderPassInvalidateArea(const gl::Rectangle &invalidateArea, gl::Rectangle *out)
1042 {
1043     if (out->empty())
1044     {
1045         *out = invalidateArea;
1046     }
1047     else
1048     {
1049         gl::ExtendRectangle(*out, invalidateArea, out);
1050     }
1051 }
1052 
CanCopyWithTransferForCopyImage(Renderer * renderer,ImageHelper * srcImage,VkImageTiling srcTilingMode,ImageHelper * dstImage,VkImageTiling dstTilingMode)1053 bool CanCopyWithTransferForCopyImage(Renderer *renderer,
1054                                      ImageHelper *srcImage,
1055                                      VkImageTiling srcTilingMode,
1056                                      ImageHelper *dstImage,
1057                                      VkImageTiling dstTilingMode)
1058 {
1059     // Neither source nor destination formats can be emulated for copy image through transfer,
1060     // unless they are emulated with the same format!
1061     bool isFormatCompatible =
1062         (!srcImage->hasEmulatedImageFormat() && !dstImage->hasEmulatedImageFormat()) ||
1063         srcImage->getActualFormatID() == dstImage->getActualFormatID();
1064 
1065     // If neither formats are emulated, GL validation ensures that pixelBytes is the same for both.
1066     ASSERT(!isFormatCompatible ||
1067            srcImage->getActualFormat().pixelBytes == dstImage->getActualFormat().pixelBytes);
1068 
1069     return isFormatCompatible &&
1070            CanCopyWithTransfer(renderer, srcImage->getActualFormatID(), srcTilingMode,
1071                                dstImage->getActualFormatID(), dstTilingMode);
1072 }
1073 
ReleaseBufferListToRenderer(Renderer * renderer,BufferHelperQueue * buffers)1074 void ReleaseBufferListToRenderer(Renderer *renderer, BufferHelperQueue *buffers)
1075 {
1076     for (std::unique_ptr<BufferHelper> &toFree : *buffers)
1077     {
1078         toFree->release(renderer);
1079     }
1080     buffers->clear();
1081 }
1082 
DestroyBufferList(Renderer * renderer,BufferHelperQueue * buffers)1083 void DestroyBufferList(Renderer *renderer, BufferHelperQueue *buffers)
1084 {
1085     for (std::unique_ptr<BufferHelper> &toDestroy : *buffers)
1086     {
1087         toDestroy->destroy(renderer);
1088     }
1089     buffers->clear();
1090 }
1091 
1092 // Helper functions used below
GetLoadOpShorthand(RenderPassLoadOp loadOp)1093 char GetLoadOpShorthand(RenderPassLoadOp loadOp)
1094 {
1095     switch (loadOp)
1096     {
1097         case RenderPassLoadOp::Clear:
1098             return 'C';
1099         case RenderPassLoadOp::Load:
1100             return 'L';
1101         case RenderPassLoadOp::None:
1102             return 'N';
1103         default:
1104             return 'D';
1105     }
1106 }
1107 
GetStoreOpShorthand(RenderPassStoreOp storeOp)1108 char GetStoreOpShorthand(RenderPassStoreOp storeOp)
1109 {
1110     switch (storeOp)
1111     {
1112         case RenderPassStoreOp::Store:
1113             return 'S';
1114         case RenderPassStoreOp::None:
1115             return 'N';
1116         default:
1117             return 'D';
1118     }
1119 }
1120 
IsClear(UpdateSource updateSource)1121 bool IsClear(UpdateSource updateSource)
1122 {
1123     return updateSource == UpdateSource::Clear ||
1124            updateSource == UpdateSource::ClearEmulatedChannelsOnly ||
1125            updateSource == UpdateSource::ClearAfterInvalidate;
1126 }
1127 
IsClearOfAllChannels(UpdateSource updateSource)1128 bool IsClearOfAllChannels(UpdateSource updateSource)
1129 {
1130     return updateSource == UpdateSource::Clear ||
1131            updateSource == UpdateSource::ClearAfterInvalidate;
1132 }
1133 
InitDynamicDescriptorPool(Context * context,const DescriptorSetLayoutDesc & descriptorSetLayoutDesc,const DescriptorSetLayout & descriptorSetLayout,uint32_t descriptorCountMultiplier,DynamicDescriptorPool * poolToInit)1134 angle::Result InitDynamicDescriptorPool(Context *context,
1135                                         const DescriptorSetLayoutDesc &descriptorSetLayoutDesc,
1136                                         const DescriptorSetLayout &descriptorSetLayout,
1137                                         uint32_t descriptorCountMultiplier,
1138                                         DynamicDescriptorPool *poolToInit)
1139 {
1140     std::vector<VkDescriptorPoolSize> descriptorPoolSizes;
1141     DescriptorSetLayoutBindingVector bindingVector;
1142     descriptorSetLayoutDesc.unpackBindings(&bindingVector);
1143 
1144     for (const VkDescriptorSetLayoutBinding &binding : bindingVector)
1145     {
1146         if (binding.descriptorCount > 0)
1147         {
1148             VkDescriptorPoolSize poolSize = {};
1149             poolSize.type                 = binding.descriptorType;
1150             poolSize.descriptorCount      = binding.descriptorCount * descriptorCountMultiplier;
1151             descriptorPoolSizes.emplace_back(poolSize);
1152         }
1153     }
1154 
1155     if (!descriptorPoolSizes.empty())
1156     {
1157         ANGLE_TRY(poolToInit->init(context, descriptorPoolSizes.data(), descriptorPoolSizes.size(),
1158                                    descriptorSetLayout));
1159     }
1160 
1161     return angle::Result::Continue;
1162 }
1163 
CheckSubpassCommandBufferCount(uint32_t count)1164 bool CheckSubpassCommandBufferCount(uint32_t count)
1165 {
1166     // When using angle::SharedRingBufferAllocator we must ensure that allocator is attached and
1167     // detached from the same priv::SecondaryCommandBuffer instance.
1168     // Custom command buffer (priv::SecondaryCommandBuffer) may contain commands for multiple
1169     // subpasses, therefore we do not need multiple buffers.
1170     return (count == 1 || !RenderPassCommandBuffer::ExecutesInline());
1171 }
1172 
IsAnyLayout(VkImageLayout needle,const VkImageLayout * haystack,uint32_t haystackCount)1173 bool IsAnyLayout(VkImageLayout needle, const VkImageLayout *haystack, uint32_t haystackCount)
1174 {
1175     const VkImageLayout *haystackEnd = haystack + haystackCount;
1176     return std::find(haystack, haystackEnd, needle) != haystackEnd;
1177 }
1178 
AggregateSkipLevels(const gl::CubeFaceArray<gl::TexLevelMask> & skipLevels)1179 gl::TexLevelMask AggregateSkipLevels(const gl::CubeFaceArray<gl::TexLevelMask> &skipLevels)
1180 {
1181     gl::TexLevelMask skipLevelsAllFaces = skipLevels[0];
1182     for (size_t face = 1; face < gl::kCubeFaceCount; ++face)
1183     {
1184         skipLevelsAllFaces |= skipLevels[face];
1185     }
1186     return skipLevelsAllFaces;
1187 }
1188 
1189 // Get layer mask for a particular image level.
GetImageLayerWriteMask(uint32_t layerStart,uint32_t layerCount)1190 ImageLayerWriteMask GetImageLayerWriteMask(uint32_t layerStart, uint32_t layerCount)
1191 {
1192     ImageLayerWriteMask layerMask = angle::BitMask<uint64_t>(layerCount);
1193     uint32_t rotateShift          = layerStart % kMaxParallelLayerWrites;
1194     layerMask = (layerMask << rotateShift) | (layerMask >> (kMaxParallelLayerWrites - rotateShift));
1195     return layerMask;
1196 }
1197 
MakeImageSubresourceReadRange(gl::LevelIndex level,uint32_t levelCount,uint32_t layer,LayerMode layerMode,ImageViewColorspace readColorspace,ImageViewColorspace writeColorspace)1198 ImageSubresourceRange MakeImageSubresourceReadRange(gl::LevelIndex level,
1199                                                     uint32_t levelCount,
1200                                                     uint32_t layer,
1201                                                     LayerMode layerMode,
1202                                                     ImageViewColorspace readColorspace,
1203                                                     ImageViewColorspace writeColorspace)
1204 {
1205     ImageSubresourceRange range;
1206 
1207     SetBitField(range.level, level.get());
1208     SetBitField(range.levelCount, levelCount);
1209     SetBitField(range.layer, layer);
1210     SetBitField(range.layerMode, layerMode);
1211     SetBitField(range.readColorspace, readColorspace == ImageViewColorspace::SRGB ? 1 : 0);
1212     SetBitField(range.writeColorspace, writeColorspace == ImageViewColorspace::SRGB ? 1 : 0);
1213 
1214     return range;
1215 }
1216 
MakeImageSubresourceDrawRange(gl::LevelIndex level,uint32_t layer,LayerMode layerMode,ImageViewColorspace readColorspace,ImageViewColorspace writeColorspace)1217 ImageSubresourceRange MakeImageSubresourceDrawRange(gl::LevelIndex level,
1218                                                     uint32_t layer,
1219                                                     LayerMode layerMode,
1220                                                     ImageViewColorspace readColorspace,
1221                                                     ImageViewColorspace writeColorspace)
1222 {
1223     ImageSubresourceRange range;
1224 
1225     SetBitField(range.level, level.get());
1226     SetBitField(range.levelCount, 1);
1227     SetBitField(range.layer, layer);
1228     SetBitField(range.layerMode, layerMode);
1229     SetBitField(range.readColorspace, readColorspace == ImageViewColorspace::SRGB ? 1 : 0);
1230     SetBitField(range.writeColorspace, writeColorspace == ImageViewColorspace::SRGB ? 1 : 0);
1231 
1232     return range;
1233 }
1234 
1235 // Obtain VkClearColorValue from input byte data and actual format.
GetVkClearColorValueFromBytes(uint8_t * actualData,const angle::Format & actualFormat,VkClearValue * clearValueOut)1236 void GetVkClearColorValueFromBytes(uint8_t *actualData,
1237                                    const angle::Format &actualFormat,
1238                                    VkClearValue *clearValueOut)
1239 {
1240     ASSERT(actualData != nullptr && !actualFormat.hasDepthOrStencilBits());
1241 
1242     *clearValueOut               = {};
1243     VkClearColorValue colorValue = {{}};
1244     actualFormat.pixelReadFunction(actualData, reinterpret_cast<uint8_t *>(&colorValue));
1245     clearValueOut->color = colorValue;
1246 }
1247 
1248 // Obtain VkClearDepthStencilValue from input byte data and intended format.
GetVkClearDepthStencilValueFromBytes(uint8_t * intendedData,const angle::Format & intendedFormat,VkClearValue * clearValueOut)1249 void GetVkClearDepthStencilValueFromBytes(uint8_t *intendedData,
1250                                           const angle::Format &intendedFormat,
1251                                           VkClearValue *clearValueOut)
1252 {
1253     ASSERT(intendedData != nullptr && intendedFormat.hasDepthOrStencilBits());
1254 
1255     *clearValueOut     = {};
1256     uint32_t dsData[4] = {0};
1257     double depthValue  = 0;
1258 
1259     intendedFormat.pixelReadFunction(intendedData, reinterpret_cast<uint8_t *>(dsData));
1260     memcpy(&depthValue, &dsData[0], sizeof(double));
1261     clearValueOut->depthStencil.depth   = static_cast<float>(depthValue);
1262     clearValueOut->depthStencil.stencil = dsData[2];
1263 }
1264 }  // anonymous namespace
1265 
1266 // This is an arbitrary max. We can change this later if necessary.
1267 uint32_t DynamicDescriptorPool::mMaxSetsPerPool           = 16;
1268 uint32_t DynamicDescriptorPool::mMaxSetsPerPoolMultiplier = 2;
1269 
GetImageLayoutFromGLImageLayout(Context * context,GLenum layout)1270 ImageLayout GetImageLayoutFromGLImageLayout(Context *context, GLenum layout)
1271 {
1272     const bool supportsMixedReadWriteDepthStencilLayouts =
1273         context->getFeatures().supportsMixedReadWriteDepthStencilLayouts.enabled;
1274     switch (layout)
1275     {
1276         case GL_NONE:
1277             return ImageLayout::Undefined;
1278         case GL_LAYOUT_GENERAL_EXT:
1279             return ImageLayout::ExternalShadersWrite;
1280         case GL_LAYOUT_COLOR_ATTACHMENT_EXT:
1281             return ImageLayout::ColorWrite;
1282         case GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT:
1283             return ImageLayout::DepthWriteStencilWrite;
1284         case GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT:
1285             return ImageLayout::DepthReadStencilRead;
1286         case GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT:
1287             return supportsMixedReadWriteDepthStencilLayouts ? ImageLayout::DepthReadStencilWrite
1288                                                              : ImageLayout::DepthWriteStencilWrite;
1289         case GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT:
1290             return supportsMixedReadWriteDepthStencilLayouts ? ImageLayout::DepthWriteStencilRead
1291                                                              : ImageLayout::DepthWriteStencilWrite;
1292         case GL_LAYOUT_SHADER_READ_ONLY_EXT:
1293             return ImageLayout::ExternalShadersReadOnly;
1294         case GL_LAYOUT_TRANSFER_SRC_EXT:
1295             return ImageLayout::TransferSrc;
1296         case GL_LAYOUT_TRANSFER_DST_EXT:
1297             return ImageLayout::TransferDst;
1298         default:
1299             UNREACHABLE();
1300             return vk::ImageLayout::Undefined;
1301     }
1302 }
1303 
ConvertImageLayoutToGLImageLayout(ImageLayout layout)1304 GLenum ConvertImageLayoutToGLImageLayout(ImageLayout layout)
1305 {
1306     switch (kImageMemoryBarrierData[layout].layout)
1307     {
1308         case VK_IMAGE_LAYOUT_UNDEFINED:
1309             return GL_NONE;
1310         case VK_IMAGE_LAYOUT_GENERAL:
1311             return GL_LAYOUT_GENERAL_EXT;
1312         case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
1313             return GL_LAYOUT_COLOR_ATTACHMENT_EXT;
1314         case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
1315             return GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT;
1316         case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
1317             return GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT;
1318         case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
1319             return GL_LAYOUT_SHADER_READ_ONLY_EXT;
1320         case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
1321             return GL_LAYOUT_TRANSFER_SRC_EXT;
1322         case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
1323             return GL_LAYOUT_TRANSFER_DST_EXT;
1324         case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL:
1325             return GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT;
1326         case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL:
1327             return GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT;
1328         default:
1329             break;
1330     }
1331     UNREACHABLE();
1332     return GL_NONE;
1333 }
1334 
ConvertImageLayoutToVkImageLayout(Renderer * renderer,ImageLayout imageLayout)1335 VkImageLayout ConvertImageLayoutToVkImageLayout(Renderer *renderer, ImageLayout imageLayout)
1336 {
1337     const ImageMemoryBarrierData &transition = renderer->getImageMemoryBarrierData(imageLayout);
1338     VkImageLayout layout                     = transition.layout;
1339 
1340     if (ANGLE_LIKELY(renderer->getFeatures().supportsMixedReadWriteDepthStencilLayouts.enabled))
1341     {
1342         return layout;
1343     }
1344 
1345     // If the layouts are not supported, substitute them with what's available.  This may be
1346     // less optimal and/or introduce synchronization hazards.
1347     if (layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL ||
1348         layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL)
1349     {
1350         layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
1351 
1352         // If the replacement layout causes a feedback loop, use the GENERAL layout
1353         if ((transition.dstStageMask &
1354              (VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT)) != 0)
1355         {
1356             layout = VK_IMAGE_LAYOUT_GENERAL;
1357         }
1358     }
1359 
1360     return layout;
1361 }
1362 
GetPipelineStageGroupFromStageFlags(VkPipelineStageFlags dstStageMask)1363 PipelineStageGroup GetPipelineStageGroupFromStageFlags(VkPipelineStageFlags dstStageMask)
1364 {
1365     if ((dstStageMask & ~kFragmentAndAttachmentPipelineStageFlags) == 0)
1366     {
1367         return PipelineStageGroup::FragmentOnly;
1368     }
1369     else if (dstStageMask == VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT)
1370     {
1371         return PipelineStageGroup::ComputeOnly;
1372     }
1373     else if ((dstStageMask & ~kPreFragmentStageFlags) == 0)
1374     {
1375         return PipelineStageGroup::PreFragmentOnly;
1376     }
1377     return PipelineStageGroup::Other;
1378 }
1379 
InitializeImageLayoutAndMemoryBarrierDataMap(angle::PackedEnumMap<ImageLayout,ImageMemoryBarrierData> * map,VkPipelineStageFlags supportedVulkanPipelineStageMask)1380 void InitializeImageLayoutAndMemoryBarrierDataMap(
1381     angle::PackedEnumMap<ImageLayout, ImageMemoryBarrierData> *map,
1382     VkPipelineStageFlags supportedVulkanPipelineStageMask)
1383 {
1384     *map = kImageMemoryBarrierData;
1385     for (ImageMemoryBarrierData &barrierData : *map)
1386     {
1387         barrierData.srcStageMask &= supportedVulkanPipelineStageMask;
1388         barrierData.dstStageMask &= supportedVulkanPipelineStageMask;
1389         ASSERT(barrierData.pipelineStageGroup ==
1390                GetPipelineStageGroupFromStageFlags(barrierData.dstStageMask));
1391     }
1392 }
1393 
EventAndPipelineBarrierHaveMatchingStageFlags(const angle::PackedEnumMap<EventStage,VkPipelineStageFlags> & eventStageMap,const angle::PackedEnumMap<ImageLayout,ImageMemoryBarrierData> & barrierDataMap)1394 bool EventAndPipelineBarrierHaveMatchingStageFlags(
1395     const angle::PackedEnumMap<EventStage, VkPipelineStageFlags> &eventStageMap,
1396     const angle::PackedEnumMap<ImageLayout, ImageMemoryBarrierData> &barrierDataMap)
1397 {
1398     // mImageLayoutAndMemoryBarrierData's dstStageMask should match EventStage's
1399     // kEventStageAndPipelineStageFlagsMap
1400     for (const ImageMemoryBarrierData &barrierData : barrierDataMap)
1401     {
1402         if (barrierData.eventStage != EventStage::InvalidEnum &&
1403             eventStageMap[barrierData.eventStage] != barrierData.dstStageMask)
1404         {
1405             return false;
1406         }
1407     }
1408     return true;
1409 }
1410 
FormatHasNecessaryFeature(Renderer * renderer,angle::FormatID formatID,VkImageTiling tilingMode,VkFormatFeatureFlags featureBits)1411 bool FormatHasNecessaryFeature(Renderer *renderer,
1412                                angle::FormatID formatID,
1413                                VkImageTiling tilingMode,
1414                                VkFormatFeatureFlags featureBits)
1415 {
1416     return (tilingMode == VK_IMAGE_TILING_OPTIMAL)
1417                ? renderer->hasImageFormatFeatureBits(formatID, featureBits)
1418                : renderer->hasLinearImageFormatFeatureBits(formatID, featureBits);
1419 }
1420 
CanCopyWithTransfer(Renderer * renderer,angle::FormatID srcFormatID,VkImageTiling srcTilingMode,angle::FormatID dstFormatID,VkImageTiling dstTilingMode)1421 bool CanCopyWithTransfer(Renderer *renderer,
1422                          angle::FormatID srcFormatID,
1423                          VkImageTiling srcTilingMode,
1424                          angle::FormatID dstFormatID,
1425                          VkImageTiling dstTilingMode)
1426 {
1427     // Checks that the formats in the copy transfer have the appropriate tiling and transfer bits
1428     bool isTilingCompatible           = srcTilingMode == dstTilingMode;
1429     bool srcFormatHasNecessaryFeature = FormatHasNecessaryFeature(
1430         renderer, srcFormatID, srcTilingMode, VK_FORMAT_FEATURE_TRANSFER_SRC_BIT);
1431     bool dstFormatHasNecessaryFeature = FormatHasNecessaryFeature(
1432         renderer, dstFormatID, dstTilingMode, VK_FORMAT_FEATURE_TRANSFER_DST_BIT);
1433 
1434     return isTilingCompatible && srcFormatHasNecessaryFeature && dstFormatHasNecessaryFeature;
1435 }
1436 
1437 // PackedClearValuesArray implementation
PackedClearValuesArray()1438 PackedClearValuesArray::PackedClearValuesArray() : mValues{} {}
1439 PackedClearValuesArray::~PackedClearValuesArray() = default;
1440 
1441 PackedClearValuesArray::PackedClearValuesArray(const PackedClearValuesArray &other) = default;
1442 PackedClearValuesArray &PackedClearValuesArray::operator=(const PackedClearValuesArray &rhs) =
1443     default;
1444 
storeColor(PackedAttachmentIndex index,const VkClearValue & clearValue)1445 void PackedClearValuesArray::storeColor(PackedAttachmentIndex index, const VkClearValue &clearValue)
1446 {
1447     mValues[index.get()] = clearValue;
1448 }
1449 
storeDepthStencil(PackedAttachmentIndex index,const VkClearValue & clearValue)1450 void PackedClearValuesArray::storeDepthStencil(PackedAttachmentIndex index,
1451                                                const VkClearValue &clearValue)
1452 {
1453     mValues[index.get()] = clearValue;
1454 }
1455 
1456 // RenderPassAttachment implementation
RenderPassAttachment()1457 RenderPassAttachment::RenderPassAttachment()
1458 {
1459     reset();
1460 }
1461 
init(ImageHelper * image,UniqueSerial imageSiblingSerial,gl::LevelIndex levelIndex,uint32_t layerIndex,uint32_t layerCount,VkImageAspectFlagBits aspect)1462 void RenderPassAttachment::init(ImageHelper *image,
1463                                 UniqueSerial imageSiblingSerial,
1464                                 gl::LevelIndex levelIndex,
1465                                 uint32_t layerIndex,
1466                                 uint32_t layerCount,
1467                                 VkImageAspectFlagBits aspect)
1468 {
1469     ASSERT(mImage == nullptr);
1470 
1471     mImage              = image;
1472     mImageSiblingSerial = imageSiblingSerial;
1473     mLevelIndex         = levelIndex;
1474     mLayerIndex         = layerIndex;
1475     mLayerCount         = layerCount;
1476     mAspect             = aspect;
1477 
1478     mImage->setRenderPassUsageFlag(RenderPassUsage::RenderTargetAttachment);
1479 }
1480 
reset()1481 void RenderPassAttachment::reset()
1482 {
1483     mImage = nullptr;
1484 
1485     mAccess = ResourceAccess::Unused;
1486 
1487     mInvalidatedCmdCount = kInfiniteCmdCount;
1488     mDisabledCmdCount    = kInfiniteCmdCount;
1489     mInvalidateArea      = gl::Rectangle();
1490 }
1491 
onAccess(ResourceAccess access,uint32_t currentCmdCount)1492 void RenderPassAttachment::onAccess(ResourceAccess access, uint32_t currentCmdCount)
1493 {
1494     // Update the access for optimizing this render pass's loadOp
1495     UpdateAccess(&mAccess, access);
1496 
1497     // Update the invalidate state for optimizing this render pass's storeOp
1498     if (onAccessImpl(access, currentCmdCount))
1499     {
1500         // The attachment is no longer invalid, so restore its content.
1501         restoreContent();
1502     }
1503 }
1504 
invalidate(const gl::Rectangle & invalidateArea,bool isAttachmentEnabled,uint32_t currentCmdCount)1505 void RenderPassAttachment::invalidate(const gl::Rectangle &invalidateArea,
1506                                       bool isAttachmentEnabled,
1507                                       uint32_t currentCmdCount)
1508 {
1509     // Keep track of the command count in the render pass at the time of invalidation.  If there are
1510     // more commands in the future, invalidate must be undone.
1511     mInvalidatedCmdCount = currentCmdCount;
1512 
1513     // Also track the command count if the attachment is currently disabled.
1514     mDisabledCmdCount = isAttachmentEnabled ? kInfiniteCmdCount : currentCmdCount;
1515 
1516     // Set/extend the invalidate area.
1517     ExtendRenderPassInvalidateArea(invalidateArea, &mInvalidateArea);
1518 }
1519 
onRenderAreaGrowth(ContextVk * contextVk,const gl::Rectangle & newRenderArea)1520 void RenderPassAttachment::onRenderAreaGrowth(ContextVk *contextVk,
1521                                               const gl::Rectangle &newRenderArea)
1522 {
1523     // Remove invalidate if it's no longer applicable.
1524     if (mInvalidateArea.empty() || mInvalidateArea.encloses(newRenderArea))
1525     {
1526         return;
1527     }
1528 
1529     ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_LOW,
1530                           "InvalidateSubFramebuffer discarded due to increased scissor region");
1531 
1532     mInvalidateArea      = gl::Rectangle();
1533     mInvalidatedCmdCount = kInfiniteCmdCount;
1534 }
1535 
finalizeLoadStore(Context * context,uint32_t currentCmdCount,bool hasUnresolveAttachment,bool hasResolveAttachment,RenderPassLoadOp * loadOp,RenderPassStoreOp * storeOp,bool * isInvalidatedOut)1536 void RenderPassAttachment::finalizeLoadStore(Context *context,
1537                                              uint32_t currentCmdCount,
1538                                              bool hasUnresolveAttachment,
1539                                              bool hasResolveAttachment,
1540                                              RenderPassLoadOp *loadOp,
1541                                              RenderPassStoreOp *storeOp,
1542                                              bool *isInvalidatedOut)
1543 {
1544     if (mAspect != VK_IMAGE_ASPECT_COLOR_BIT)
1545     {
1546         const RenderPassUsage readOnlyAttachmentUsage =
1547             mAspect == VK_IMAGE_ASPECT_STENCIL_BIT ? RenderPassUsage::StencilReadOnlyAttachment
1548                                                    : RenderPassUsage::DepthReadOnlyAttachment;
1549         // Ensure we don't write to a read-only attachment. (ReadOnly -> !Write)
1550         ASSERT(!mImage->hasRenderPassUsageFlag(readOnlyAttachmentUsage) ||
1551                !HasResourceWriteAccess(mAccess));
1552     }
1553 
1554     // If the attachment is invalidated, skip the store op.  If we are not loading or clearing the
1555     // attachment and the attachment has not been used, auto-invalidate it.
1556     const bool notLoaded = *loadOp == RenderPassLoadOp::DontCare && !hasUnresolveAttachment;
1557     if (isInvalidated(currentCmdCount) || (notLoaded && !HasResourceWriteAccess(mAccess)))
1558     {
1559         *storeOp          = RenderPassStoreOp::DontCare;
1560         *isInvalidatedOut = true;
1561     }
1562     else if (hasWriteAfterInvalidate(currentCmdCount))
1563     {
1564         // The attachment was invalidated, but is now valid.  Let the image know the contents are
1565         // now defined so a future render pass would use loadOp=LOAD.
1566         restoreContent();
1567     }
1568 
1569     // For read only depth stencil, we can use StoreOpNone if available.  DontCare is still
1570     // preferred, so do this after handling DontCare.
1571     const bool supportsLoadStoreOpNone =
1572         context->getFeatures().supportsRenderPassLoadStoreOpNone.enabled;
1573     const bool supportsStoreOpNone =
1574         supportsLoadStoreOpNone || context->getFeatures().supportsRenderPassStoreOpNone.enabled;
1575     if (mAccess == ResourceAccess::ReadOnly && supportsStoreOpNone)
1576     {
1577         if (*storeOp == RenderPassStoreOp::Store && *loadOp != RenderPassLoadOp::Clear)
1578         {
1579             *storeOp = RenderPassStoreOp::None;
1580         }
1581     }
1582 
1583     if (mAccess == ResourceAccess::Unused)
1584     {
1585         if (*storeOp != RenderPassStoreOp::DontCare)
1586         {
1587             switch (*loadOp)
1588             {
1589                 case RenderPassLoadOp::Clear:
1590                     // Cannot optimize away the ops if the attachment is cleared (even if not used
1591                     // afterwards)
1592                     break;
1593                 case RenderPassLoadOp::Load:
1594                     // Make sure the attachment is neither loaded nor stored (as it's neither used
1595                     // nor invalidated), if possible.
1596                     if (supportsLoadStoreOpNone)
1597                     {
1598                         *loadOp = RenderPassLoadOp::None;
1599                     }
1600                     if (supportsStoreOpNone)
1601                     {
1602                         *storeOp = RenderPassStoreOp::None;
1603                     }
1604                     break;
1605                 case RenderPassLoadOp::DontCare:
1606                     // loadOp=DontCare should be covered by storeOp=DontCare below.
1607                     break;
1608                 case RenderPassLoadOp::None:
1609                 default:
1610                     // loadOp=None is never decided upfront.
1611                     UNREACHABLE();
1612                     break;
1613             }
1614         }
1615     }
1616 
1617     if (mAccess == ResourceAccess::Unused || (mAccess == ResourceAccess::ReadOnly && notLoaded))
1618     {
1619         // If we are loading or clearing the attachment, but the attachment has not been used,
1620         // and the data has also not been stored back into attachment, then just skip the
1621         // load/clear op. If loadOp/storeOp=None is supported, prefer that to reduce the amount
1622         // of synchronization; DontCare is a write operation, while None is not.
1623         //
1624         // Don't optimize away a Load or Clear if there is a resolve attachment. Although the
1625         // storeOp=DontCare the image content needs to be resolved into the resolve attachment.
1626         const bool attachmentNeedsToBeResolved =
1627             hasResolveAttachment &&
1628             (*loadOp == RenderPassLoadOp::Load || *loadOp == RenderPassLoadOp::Clear);
1629         if (*storeOp == RenderPassStoreOp::DontCare && !attachmentNeedsToBeResolved)
1630         {
1631             if (supportsLoadStoreOpNone && !isInvalidated(currentCmdCount))
1632             {
1633                 *loadOp  = RenderPassLoadOp::None;
1634                 *storeOp = RenderPassStoreOp::None;
1635             }
1636             else
1637             {
1638                 *loadOp = RenderPassLoadOp::DontCare;
1639             }
1640         }
1641     }
1642 }
1643 
restoreContent()1644 void RenderPassAttachment::restoreContent()
1645 {
1646     // Note that the image may have been deleted since the render pass has started.
1647     if (mImage)
1648     {
1649         ASSERT(mImage->valid());
1650         if (mAspect == VK_IMAGE_ASPECT_STENCIL_BIT)
1651         {
1652             mImage->restoreSubresourceStencilContent(mLevelIndex, mLayerIndex, mLayerCount);
1653         }
1654         else
1655         {
1656             mImage->restoreSubresourceContent(mLevelIndex, mLayerIndex, mLayerCount);
1657         }
1658         mInvalidateArea = gl::Rectangle();
1659     }
1660 }
1661 
hasWriteAfterInvalidate(uint32_t currentCmdCount) const1662 bool RenderPassAttachment::hasWriteAfterInvalidate(uint32_t currentCmdCount) const
1663 {
1664     return (mInvalidatedCmdCount != kInfiniteCmdCount &&
1665             std::min(mDisabledCmdCount, currentCmdCount) != mInvalidatedCmdCount);
1666 }
1667 
isInvalidated(uint32_t currentCmdCount) const1668 bool RenderPassAttachment::isInvalidated(uint32_t currentCmdCount) const
1669 {
1670     return mInvalidatedCmdCount != kInfiniteCmdCount &&
1671            std::min(mDisabledCmdCount, currentCmdCount) == mInvalidatedCmdCount;
1672 }
1673 
onAccessImpl(ResourceAccess access,uint32_t currentCmdCount)1674 bool RenderPassAttachment::onAccessImpl(ResourceAccess access, uint32_t currentCmdCount)
1675 {
1676     if (mInvalidatedCmdCount == kInfiniteCmdCount)
1677     {
1678         // If never invalidated or no longer invalidated, return early.
1679         return false;
1680     }
1681     if (HasResourceWriteAccess(access))
1682     {
1683         // Drawing to this attachment is being enabled.  Assume that drawing will immediately occur
1684         // after this attachment is enabled, and that means that the attachment will no longer be
1685         // invalidated.
1686         mInvalidatedCmdCount = kInfiniteCmdCount;
1687         mDisabledCmdCount    = kInfiniteCmdCount;
1688         // Return true to indicate that the store op should remain STORE and that mContentDefined
1689         // should be set to true;
1690         return true;
1691     }
1692     // Drawing to this attachment is being disabled.
1693     if (hasWriteAfterInvalidate(currentCmdCount))
1694     {
1695         // The attachment was previously drawn while enabled, and so is no longer invalidated.
1696         mInvalidatedCmdCount = kInfiniteCmdCount;
1697         mDisabledCmdCount    = kInfiniteCmdCount;
1698         // Return true to indicate that the store op should remain STORE and that mContentDefined
1699         // should be set to true;
1700         return true;
1701     }
1702 
1703     // Use the latest CmdCount at the start of being disabled.  At the end of the render pass,
1704     // cmdCountDisabled is <= the actual command count, and so it's compared with
1705     // cmdCountInvalidated.  If the same, the attachment is still invalidated.
1706     mDisabledCmdCount = currentCmdCount;
1707     return false;
1708 }
1709 
1710 // CommandBufferHelperCommon implementation.
CommandBufferHelperCommon()1711 CommandBufferHelperCommon::CommandBufferHelperCommon()
1712     : mCommandPool(nullptr), mHasShaderStorageOutput(false), mHasGLMemoryBarrierIssued(false)
1713 {}
1714 
~CommandBufferHelperCommon()1715 CommandBufferHelperCommon::~CommandBufferHelperCommon() {}
1716 
initializeImpl()1717 void CommandBufferHelperCommon::initializeImpl()
1718 {
1719     mCommandAllocator.init();
1720 }
1721 
resetImpl(Context * context)1722 void CommandBufferHelperCommon::resetImpl(Context *context)
1723 {
1724     ASSERT(!mAcquireNextImageSemaphore.valid());
1725     mCommandAllocator.resetAllocator();
1726     ASSERT(!mIsAnyHostVisibleBufferWritten);
1727 
1728     ASSERT(mRefCountedEvents.mask.none());
1729     ASSERT(mRefCountedEventCollector.empty());
1730 }
1731 
1732 template <class DerivedT>
attachCommandPoolImpl(Context * context,SecondaryCommandPool * commandPool)1733 angle::Result CommandBufferHelperCommon::attachCommandPoolImpl(Context *context,
1734                                                                SecondaryCommandPool *commandPool)
1735 {
1736     if constexpr (!DerivedT::ExecutesInline())
1737     {
1738         DerivedT *derived = static_cast<DerivedT *>(this);
1739         ASSERT(commandPool != nullptr);
1740         ASSERT(mCommandPool == nullptr);
1741         ASSERT(!derived->getCommandBuffer().valid());
1742 
1743         mCommandPool = commandPool;
1744 
1745         ANGLE_TRY(derived->initializeCommandBuffer(context));
1746     }
1747     return angle::Result::Continue;
1748 }
1749 
1750 template <class DerivedT, bool kIsRenderPassBuffer>
detachCommandPoolImpl(Context * context,SecondaryCommandPool ** commandPoolOut)1751 angle::Result CommandBufferHelperCommon::detachCommandPoolImpl(
1752     Context *context,
1753     SecondaryCommandPool **commandPoolOut)
1754 {
1755     if constexpr (!DerivedT::ExecutesInline())
1756     {
1757         DerivedT *derived = static_cast<DerivedT *>(this);
1758         ASSERT(mCommandPool != nullptr);
1759         ASSERT(derived->getCommandBuffer().valid());
1760 
1761         if constexpr (!kIsRenderPassBuffer)
1762         {
1763             ASSERT(!derived->getCommandBuffer().empty());
1764             ANGLE_TRY(derived->endCommandBuffer(context));
1765         }
1766 
1767         *commandPoolOut = mCommandPool;
1768         mCommandPool    = nullptr;
1769     }
1770     ASSERT(mCommandPool == nullptr);
1771     return angle::Result::Continue;
1772 }
1773 
1774 template <class DerivedT>
releaseCommandPoolImpl()1775 void CommandBufferHelperCommon::releaseCommandPoolImpl()
1776 {
1777     if constexpr (!DerivedT::ExecutesInline())
1778     {
1779         DerivedT *derived = static_cast<DerivedT *>(this);
1780         ASSERT(mCommandPool != nullptr);
1781 
1782         if (derived->getCommandBuffer().valid())
1783         {
1784             ASSERT(derived->getCommandBuffer().empty());
1785             mCommandPool->collect(&derived->getCommandBuffer());
1786         }
1787 
1788         mCommandPool = nullptr;
1789     }
1790     ASSERT(mCommandPool == nullptr);
1791 }
1792 
1793 template <class DerivedT>
attachAllocatorImpl(SecondaryCommandMemoryAllocator * allocator)1794 void CommandBufferHelperCommon::attachAllocatorImpl(SecondaryCommandMemoryAllocator *allocator)
1795 {
1796     if constexpr (DerivedT::ExecutesInline())
1797     {
1798         auto &commandBuffer = static_cast<DerivedT *>(this)->getCommandBuffer();
1799         mCommandAllocator.attachAllocator(allocator);
1800         commandBuffer.attachAllocator(mCommandAllocator.getAllocator());
1801     }
1802 }
1803 
1804 template <class DerivedT>
detachAllocatorImpl()1805 SecondaryCommandMemoryAllocator *CommandBufferHelperCommon::detachAllocatorImpl()
1806 {
1807     SecondaryCommandMemoryAllocator *result = nullptr;
1808     if constexpr (DerivedT::ExecutesInline())
1809     {
1810         auto &commandBuffer = static_cast<DerivedT *>(this)->getCommandBuffer();
1811         commandBuffer.detachAllocator(mCommandAllocator.getAllocator());
1812         result = mCommandAllocator.detachAllocator(commandBuffer.empty());
1813     }
1814     return result;
1815 }
1816 
1817 template <class DerivedT>
assertCanBeRecycledImpl()1818 void CommandBufferHelperCommon::assertCanBeRecycledImpl()
1819 {
1820     DerivedT *derived = static_cast<DerivedT *>(this);
1821     ASSERT(mCommandPool == nullptr);
1822     ASSERT(!mCommandAllocator.hasAllocatorLinks());
1823     // Vulkan secondary command buffers must be invalid (collected).
1824     ASSERT(DerivedT::ExecutesInline() || !derived->getCommandBuffer().valid());
1825     // ANGLEs Custom secondary command buffers must be empty (reset).
1826     ASSERT(!DerivedT::ExecutesInline() || derived->getCommandBuffer().empty());
1827 }
1828 
bufferWrite(VkAccessFlags writeAccessType,PipelineStage writeStage,BufferHelper * buffer)1829 void CommandBufferHelperCommon::bufferWrite(VkAccessFlags writeAccessType,
1830                                             PipelineStage writeStage,
1831                                             BufferHelper *buffer)
1832 {
1833     buffer->setWriteQueueSerial(mQueueSerial);
1834 
1835     VkPipelineStageFlagBits stageBits = kPipelineStageFlagBitMap[writeStage];
1836     buffer->recordWriteBarrier(writeAccessType, stageBits, writeStage, &mPipelineBarriers);
1837 
1838     // Make sure host-visible buffer writes result in a barrier inserted at the end of the frame to
1839     // make the results visible to the host.  The buffer may be mapped by the application in the
1840     // future.
1841     if (buffer->isHostVisible())
1842     {
1843         mIsAnyHostVisibleBufferWritten = true;
1844     }
1845 }
1846 
executeBarriers(Renderer * renderer,CommandsState * commandsState)1847 void CommandBufferHelperCommon::executeBarriers(Renderer *renderer, CommandsState *commandsState)
1848 {
1849     // Add ANI semaphore to the command submission.
1850     if (mAcquireNextImageSemaphore.valid())
1851     {
1852         commandsState->waitSemaphores.emplace_back(mAcquireNextImageSemaphore.release());
1853         commandsState->waitSemaphoreStageMasks.emplace_back(kSwapchainAcquireImageWaitStageFlags);
1854     }
1855 
1856     mPipelineBarriers.execute(renderer, &commandsState->primaryCommands);
1857     mEventBarriers.execute(renderer, &commandsState->primaryCommands);
1858 }
1859 
bufferReadImpl(VkAccessFlags readAccessType,PipelineStage readStage,BufferHelper * buffer)1860 void CommandBufferHelperCommon::bufferReadImpl(VkAccessFlags readAccessType,
1861                                                PipelineStage readStage,
1862                                                BufferHelper *buffer)
1863 {
1864     VkPipelineStageFlagBits stageBits = kPipelineStageFlagBitMap[readStage];
1865     buffer->recordReadBarrier(readAccessType, stageBits, readStage, &mPipelineBarriers);
1866     ASSERT(!usesBufferForWrite(*buffer));
1867 }
1868 
imageReadImpl(Context * context,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,BarrierType barrierType,ImageHelper * image)1869 void CommandBufferHelperCommon::imageReadImpl(Context *context,
1870                                               VkImageAspectFlags aspectFlags,
1871                                               ImageLayout imageLayout,
1872                                               BarrierType barrierType,
1873                                               ImageHelper *image)
1874 {
1875     if (image->isReadBarrierNecessary(context->getRenderer(), imageLayout))
1876     {
1877         updateImageLayoutAndBarrier(context, image, aspectFlags, imageLayout, barrierType);
1878     }
1879 }
1880 
imageWriteImpl(Context * context,gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,BarrierType barrierType,ImageHelper * image)1881 void CommandBufferHelperCommon::imageWriteImpl(Context *context,
1882                                                gl::LevelIndex level,
1883                                                uint32_t layerStart,
1884                                                uint32_t layerCount,
1885                                                VkImageAspectFlags aspectFlags,
1886                                                ImageLayout imageLayout,
1887                                                BarrierType barrierType,
1888                                                ImageHelper *image)
1889 {
1890     image->onWrite(level, 1, layerStart, layerCount, aspectFlags);
1891     if (image->isWriteBarrierNecessary(imageLayout, level, 1, layerStart, layerCount))
1892     {
1893         updateImageLayoutAndBarrier(context, image, aspectFlags, imageLayout, barrierType);
1894     }
1895 }
1896 
updateImageLayoutAndBarrier(Context * context,ImageHelper * image,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,BarrierType barrierType)1897 void CommandBufferHelperCommon::updateImageLayoutAndBarrier(Context *context,
1898                                                             ImageHelper *image,
1899                                                             VkImageAspectFlags aspectFlags,
1900                                                             ImageLayout imageLayout,
1901                                                             BarrierType barrierType)
1902 {
1903     VkSemaphore semaphore = VK_NULL_HANDLE;
1904     image->updateLayoutAndBarrier(context, aspectFlags, imageLayout, barrierType, mQueueSerial,
1905                                   &mPipelineBarriers, &mEventBarriers, &mRefCountedEventCollector,
1906                                   &semaphore);
1907     // If image has an ANI semaphore, move it to command buffer so that we can wait for it in
1908     // next submission.
1909     if (semaphore != VK_NULL_HANDLE)
1910     {
1911         ASSERT(!mAcquireNextImageSemaphore.valid());
1912         mAcquireNextImageSemaphore.setHandle(semaphore);
1913     }
1914 }
1915 
retainImageWithEvent(Context * context,ImageHelper * image)1916 void CommandBufferHelperCommon::retainImageWithEvent(Context *context, ImageHelper *image)
1917 {
1918     image->setQueueSerial(mQueueSerial);
1919     image->updatePipelineStageAccessHistory();
1920 
1921     if (context->getFeatures().useVkEventForImageBarrier.enabled)
1922     {
1923         image->setCurrentRefCountedEvent(context, mRefCountedEvents);
1924     }
1925 }
1926 
1927 template <typename CommandBufferT>
flushSetEventsImpl(Context * context,CommandBufferT * commandBuffer)1928 void CommandBufferHelperCommon::flushSetEventsImpl(Context *context, CommandBufferT *commandBuffer)
1929 {
1930     if (mRefCountedEvents.mask.none())
1931     {
1932         return;
1933     }
1934 
1935     Renderer *renderer = context->getRenderer();
1936     // Add VkCmdSetEvent here to track the completion of this renderPass.
1937     for (EventStage stage : mRefCountedEvents.mask)
1938     {
1939         RefCountedEvent &refCountedEvent = mRefCountedEvents.map[stage];
1940         ASSERT(refCountedEvent.valid());
1941         VkPipelineStageFlags stageMask = renderer->getPipelineStageMask(stage);
1942         commandBuffer->setEvent(refCountedEvent.getEvent().getHandle(), stageMask);
1943         // We no longer need event, so garbage collect it.
1944         mRefCountedEventCollector.emplace_back(std::move(refCountedEvent));
1945     }
1946     mRefCountedEvents.mask.reset();
1947 }
1948 
1949 template void CommandBufferHelperCommon::flushSetEventsImpl<priv::SecondaryCommandBuffer>(
1950     Context *context,
1951     priv::SecondaryCommandBuffer *commandBuffer);
1952 template void CommandBufferHelperCommon::flushSetEventsImpl<VulkanSecondaryCommandBuffer>(
1953     Context *context,
1954     VulkanSecondaryCommandBuffer *commandBuffer);
1955 
addCommandDiagnosticsCommon(std::ostringstream * out)1956 void CommandBufferHelperCommon::addCommandDiagnosticsCommon(std::ostringstream *out)
1957 {
1958     mPipelineBarriers.addDiagnosticsString(*out);
1959     mEventBarriers.addDiagnosticsString(*out);
1960 }
1961 
setBufferReadQueueSerial(BufferHelper * buffer)1962 void CommandBufferHelperCommon::setBufferReadQueueSerial(BufferHelper *buffer)
1963 {
1964     if (buffer->getResourceUse() >= mQueueSerial)
1965     {
1966         // We should not run into situation that RP is writing to it while we are reading it here
1967         ASSERT(!(buffer->getWriteResourceUse() >= mQueueSerial));
1968         // A buffer could have read accessed by both renderPassCommands and
1969         // outsideRenderPassCommands and there is no need to endRP or flush. In this case, the
1970         // renderPassCommands' read will override the outsideRenderPassCommands' read, since its
1971         // queueSerial must be greater than outsideRP.
1972     }
1973     else
1974     {
1975         buffer->setQueueSerial(mQueueSerial);
1976     }
1977 }
1978 
1979 // OutsideRenderPassCommandBufferHelper implementation.
OutsideRenderPassCommandBufferHelper()1980 OutsideRenderPassCommandBufferHelper::OutsideRenderPassCommandBufferHelper() {}
1981 
~OutsideRenderPassCommandBufferHelper()1982 OutsideRenderPassCommandBufferHelper::~OutsideRenderPassCommandBufferHelper() {}
1983 
initialize(Context * context)1984 angle::Result OutsideRenderPassCommandBufferHelper::initialize(Context *context)
1985 {
1986     initializeImpl();
1987     return initializeCommandBuffer(context);
1988 }
initializeCommandBuffer(Context * context)1989 angle::Result OutsideRenderPassCommandBufferHelper::initializeCommandBuffer(Context *context)
1990 {
1991     // Skip initialization in the Pool-detached state.
1992     if (!ExecutesInline() && mCommandPool == nullptr)
1993     {
1994         return angle::Result::Continue;
1995     }
1996     return mCommandBuffer.initialize(context, mCommandPool, false,
1997                                      mCommandAllocator.getAllocator());
1998 }
1999 
reset(Context * context,SecondaryCommandBufferCollector * commandBufferCollector)2000 angle::Result OutsideRenderPassCommandBufferHelper::reset(
2001     Context *context,
2002     SecondaryCommandBufferCollector *commandBufferCollector)
2003 {
2004     resetImpl(context);
2005 
2006     // Collect/Reset the command buffer
2007     commandBufferCollector->collectCommandBuffer(std::move(mCommandBuffer));
2008     mIsCommandBufferEnded = false;
2009 
2010     // Invalidate the queue serial here. We will get a new queue serial after commands flush.
2011     mQueueSerial = QueueSerial();
2012 
2013     return initializeCommandBuffer(context);
2014 }
2015 
imageRead(Context * context,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)2016 void OutsideRenderPassCommandBufferHelper::imageRead(Context *context,
2017                                                      VkImageAspectFlags aspectFlags,
2018                                                      ImageLayout imageLayout,
2019                                                      ImageHelper *image)
2020 {
2021     if (image->getResourceUse() >= mQueueSerial)
2022     {
2023         // If image is already used by renderPass, it may already set the event to renderPass's
2024         // event. In this case we already lost the previous event to wait for, thus use pipeline
2025         // barrier instead of event
2026         imageReadImpl(context, aspectFlags, imageLayout, BarrierType::Pipeline, image);
2027     }
2028     else
2029     {
2030         imageReadImpl(context, aspectFlags, imageLayout, BarrierType::Event, image);
2031         // Usually an image can only used by a RenderPassCommands or OutsideRenderPassCommands
2032         // because the layout will be different, except with image sampled from compute shader. In
2033         // this case, the renderPassCommands' read will override the outsideRenderPassCommands'
2034         retainImageWithEvent(context, image);
2035     }
2036 }
2037 
imageWrite(Context * context,gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)2038 void OutsideRenderPassCommandBufferHelper::imageWrite(Context *context,
2039                                                       gl::LevelIndex level,
2040                                                       uint32_t layerStart,
2041                                                       uint32_t layerCount,
2042                                                       VkImageAspectFlags aspectFlags,
2043                                                       ImageLayout imageLayout,
2044                                                       ImageHelper *image)
2045 {
2046     imageWriteImpl(context, level, layerStart, layerCount, aspectFlags, imageLayout,
2047                    BarrierType::Event, image);
2048     retainImageWithEvent(context, image);
2049 }
2050 
retainImage(ImageHelper * image)2051 void OutsideRenderPassCommandBufferHelper::retainImage(ImageHelper *image)
2052 {
2053     // We want explicit control on when VkEvent is used for outsideRPCommands to minimize the
2054     // overhead, so do not setEvent here.
2055     image->setQueueSerial(mQueueSerial);
2056     image->updatePipelineStageAccessHistory();
2057 }
2058 
trackImageWithEvent(Context * context,ImageHelper * image)2059 void OutsideRenderPassCommandBufferHelper::trackImageWithEvent(Context *context, ImageHelper *image)
2060 {
2061     image->setCurrentRefCountedEvent(context, mRefCountedEvents);
2062     flushSetEventsImpl(context, &mCommandBuffer);
2063 }
2064 
collectRefCountedEventsGarbage(RefCountedEventsGarbageRecycler * garbageRecycler)2065 void OutsideRenderPassCommandBufferHelper::collectRefCountedEventsGarbage(
2066     RefCountedEventsGarbageRecycler *garbageRecycler)
2067 {
2068     ASSERT(garbageRecycler != nullptr);
2069     if (!mRefCountedEventCollector.empty())
2070     {
2071         garbageRecycler->collectGarbage(mQueueSerial, std::move(mRefCountedEventCollector));
2072     }
2073 }
2074 
flushToPrimary(Context * context,CommandsState * commandsState)2075 angle::Result OutsideRenderPassCommandBufferHelper::flushToPrimary(Context *context,
2076                                                                    CommandsState *commandsState)
2077 {
2078     ANGLE_TRACE_EVENT0("gpu.angle", "OutsideRenderPassCommandBufferHelper::flushToPrimary");
2079     ASSERT(!empty());
2080 
2081     Renderer *renderer = context->getRenderer();
2082 
2083     // Commands that are added to primary before beginRenderPass command
2084     executeBarriers(renderer, commandsState);
2085 
2086     // When using Vulkan secondary command buffers and "asyncCommandQueue" is enabled, command
2087     // buffer MUST be already ended in the detachCommandPool() (called in the CommandProcessor).
2088     // After the detach, nothing is written to the buffer (the barriers above are written directly
2089     // to the primary buffer).
2090     // Note: RenderPass Command Buffers are explicitly ended in the endRenderPass().
2091     if (ExecutesInline() || !renderer->isAsyncCommandQueueEnabled())
2092     {
2093         ANGLE_TRY(endCommandBuffer(context));
2094     }
2095     ASSERT(mIsCommandBufferEnded);
2096     mCommandBuffer.executeCommands(&commandsState->primaryCommands);
2097 
2098     // Call VkCmdSetEvent to track the completion of this renderPass.
2099     flushSetEventsImpl(context, &commandsState->primaryCommands);
2100 
2101     // Proactively reset all released events before ending command buffer.
2102     context->getRenderer()->getRefCountedEventRecycler()->resetEvents(
2103         context, mQueueSerial, &commandsState->primaryCommands);
2104 
2105     // Restart the command buffer.
2106     return reset(context, &commandsState->secondaryCommands);
2107 }
2108 
endCommandBuffer(Context * context)2109 angle::Result OutsideRenderPassCommandBufferHelper::endCommandBuffer(Context *context)
2110 {
2111     ASSERT(ExecutesInline() || mCommandPool != nullptr);
2112     ASSERT(mCommandBuffer.valid());
2113     ASSERT(!mIsCommandBufferEnded);
2114 
2115     ANGLE_TRY(mCommandBuffer.end(context));
2116     mIsCommandBufferEnded = true;
2117 
2118     return angle::Result::Continue;
2119 }
2120 
attachCommandPool(Context * context,SecondaryCommandPool * commandPool)2121 angle::Result OutsideRenderPassCommandBufferHelper::attachCommandPool(
2122     Context *context,
2123     SecondaryCommandPool *commandPool)
2124 {
2125     return attachCommandPoolImpl<OutsideRenderPassCommandBufferHelper>(context, commandPool);
2126 }
2127 
detachCommandPool(Context * context,SecondaryCommandPool ** commandPoolOut)2128 angle::Result OutsideRenderPassCommandBufferHelper::detachCommandPool(
2129     Context *context,
2130     SecondaryCommandPool **commandPoolOut)
2131 {
2132     return detachCommandPoolImpl<OutsideRenderPassCommandBufferHelper, false>(context,
2133                                                                               commandPoolOut);
2134 }
2135 
releaseCommandPool()2136 void OutsideRenderPassCommandBufferHelper::releaseCommandPool()
2137 {
2138     releaseCommandPoolImpl<OutsideRenderPassCommandBufferHelper>();
2139 }
2140 
attachAllocator(SecondaryCommandMemoryAllocator * allocator)2141 void OutsideRenderPassCommandBufferHelper::attachAllocator(
2142     SecondaryCommandMemoryAllocator *allocator)
2143 {
2144     attachAllocatorImpl<OutsideRenderPassCommandBufferHelper>(allocator);
2145 }
2146 
detachAllocator()2147 SecondaryCommandMemoryAllocator *OutsideRenderPassCommandBufferHelper::detachAllocator()
2148 {
2149     return detachAllocatorImpl<OutsideRenderPassCommandBufferHelper>();
2150 }
2151 
assertCanBeRecycled()2152 void OutsideRenderPassCommandBufferHelper::assertCanBeRecycled()
2153 {
2154     assertCanBeRecycledImpl<OutsideRenderPassCommandBufferHelper>();
2155 }
2156 
getCommandDiagnostics()2157 std::string OutsideRenderPassCommandBufferHelper::getCommandDiagnostics()
2158 {
2159     std::ostringstream out;
2160     addCommandDiagnosticsCommon(&out);
2161 
2162     out << mCommandBuffer.dumpCommands("\\l");
2163 
2164     return out.str();
2165 }
2166 
2167 // RenderPassFramebuffer implementation.
reset()2168 void RenderPassFramebuffer::reset()
2169 {
2170     mInitialFramebuffer.release();
2171     mImageViews.clear();
2172     mIsImageless = false;
2173     mIsDefault   = false;
2174 }
2175 
addResolveAttachment(size_t viewIndex,VkImageView view)2176 void RenderPassFramebuffer::addResolveAttachment(size_t viewIndex, VkImageView view)
2177 {
2178     // The initial framebuffer is no longer usable.
2179     mInitialFramebuffer.release();
2180 
2181     if (viewIndex >= mImageViews.size())
2182     {
2183         mImageViews.resize(viewIndex + 1, VK_NULL_HANDLE);
2184     }
2185 
2186     ASSERT(mImageViews[viewIndex] == VK_NULL_HANDLE);
2187     mImageViews[viewIndex] = view;
2188 }
2189 
packResolveViewsAndCreateFramebuffer(Context * context,const RenderPass & renderPass,Framebuffer * framebufferOut)2190 angle::Result RenderPassFramebuffer::packResolveViewsAndCreateFramebuffer(
2191     Context *context,
2192     const RenderPass &renderPass,
2193     Framebuffer *framebufferOut)
2194 {
2195     // This is only called if the initial framebuffer was not usable.  Since this is called when
2196     // the render pass is finalized, the render pass that is passed in is the final one (not a
2197     // compatible one) and the framebuffer that is created is not imageless.
2198     ASSERT(!mInitialFramebuffer.valid());
2199 
2200     PackViews(&mImageViews);
2201     mIsImageless = false;
2202 
2203     VkFramebufferCreateInfo framebufferInfo = {};
2204     framebufferInfo.sType                   = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
2205     framebufferInfo.flags                   = 0;
2206     framebufferInfo.renderPass              = renderPass.getHandle();
2207     framebufferInfo.attachmentCount         = static_cast<uint32_t>(mImageViews.size());
2208     framebufferInfo.pAttachments            = mImageViews.data();
2209     framebufferInfo.width                   = mWidth;
2210     framebufferInfo.height                  = mHeight;
2211     framebufferInfo.layers                  = mLayers;
2212 
2213     ANGLE_VK_TRY(context, framebufferOut->init(context->getDevice(), framebufferInfo));
2214     return angle::Result::Continue;
2215 }
2216 
packResolveViewsForRenderPassBegin(VkRenderPassAttachmentBeginInfo * beginInfoOut)2217 void RenderPassFramebuffer::packResolveViewsForRenderPassBegin(
2218     VkRenderPassAttachmentBeginInfo *beginInfoOut)
2219 {
2220     // Called when using the initial framebuffer which is imageless
2221     ASSERT(mInitialFramebuffer.valid());
2222     ASSERT(mIsImageless);
2223 
2224     PackViews(&mImageViews);
2225 
2226     *beginInfoOut                 = {};
2227     beginInfoOut->sType           = VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO_KHR;
2228     beginInfoOut->attachmentCount = static_cast<uint32_t>(mImageViews.size());
2229     beginInfoOut->pAttachments    = mImageViews.data();
2230 }
2231 
2232 // static
PackViews(FramebufferAttachmentsVector<VkImageView> * views)2233 void RenderPassFramebuffer::PackViews(FramebufferAttachmentsVector<VkImageView> *views)
2234 {
2235     PackedAttachmentIndex packIndex = kAttachmentIndexZero;
2236     for (size_t viewIndex = 0; viewIndex < views->size(); ++viewIndex)
2237     {
2238         if ((*views)[viewIndex] != VK_NULL_HANDLE)
2239         {
2240             (*views)[packIndex.get()] = (*views)[viewIndex];
2241             ++packIndex;
2242         }
2243     }
2244 
2245     views->resize(packIndex.get());
2246 }
2247 
2248 // RenderPassCommandBufferHelper implementation.
RenderPassCommandBufferHelper()2249 RenderPassCommandBufferHelper::RenderPassCommandBufferHelper()
2250     : mCurrentSubpassCommandBufferIndex(0),
2251       mCounter(0),
2252       mClearValues{},
2253       mRenderPassStarted(false),
2254       mTransformFeedbackCounterBuffers{},
2255       mTransformFeedbackCounterBufferOffsets{},
2256       mValidTransformFeedbackBufferCount(0),
2257       mRebindTransformFeedbackBuffers(false),
2258       mIsTransformFeedbackActiveUnpaused(false),
2259       mPreviousSubpassesCmdCount(0),
2260       mDepthStencilAttachmentIndex(kAttachmentIndexInvalid),
2261       mColorAttachmentsCount(0),
2262       mImageOptimizeForPresent(nullptr),
2263       mImageOptimizeForPresentOriginalLayout(ImageLayout::Undefined)
2264 {}
2265 
~RenderPassCommandBufferHelper()2266 RenderPassCommandBufferHelper::~RenderPassCommandBufferHelper() {}
2267 
initialize(Context * context)2268 angle::Result RenderPassCommandBufferHelper::initialize(Context *context)
2269 {
2270     initializeImpl();
2271     return initializeCommandBuffer(context);
2272 }
initializeCommandBuffer(Context * context)2273 angle::Result RenderPassCommandBufferHelper::initializeCommandBuffer(Context *context)
2274 {
2275     // Skip initialization in the Pool-detached state.
2276     if (!ExecutesInline() && mCommandPool == nullptr)
2277     {
2278         return angle::Result::Continue;
2279     }
2280     return getCommandBuffer().initialize(context, mCommandPool, true,
2281                                          mCommandAllocator.getAllocator());
2282 }
2283 
reset(Context * context,SecondaryCommandBufferCollector * commandBufferCollector)2284 angle::Result RenderPassCommandBufferHelper::reset(
2285     Context *context,
2286     SecondaryCommandBufferCollector *commandBufferCollector)
2287 {
2288     resetImpl(context);
2289 
2290     for (PackedAttachmentIndex index = kAttachmentIndexZero; index < mColorAttachmentsCount;
2291          ++index)
2292     {
2293         mColorAttachments[index].reset();
2294         mColorResolveAttachments[index].reset();
2295     }
2296 
2297     mDepthAttachment.reset();
2298     mDepthResolveAttachment.reset();
2299     mStencilAttachment.reset();
2300     mStencilResolveAttachment.reset();
2301 
2302     mFragmentShadingRateAtachment.reset();
2303 
2304     mRenderPassStarted                     = false;
2305     mValidTransformFeedbackBufferCount     = 0;
2306     mRebindTransformFeedbackBuffers        = false;
2307     mHasShaderStorageOutput                = false;
2308     mHasGLMemoryBarrierIssued              = false;
2309     mPreviousSubpassesCmdCount             = 0;
2310     mColorAttachmentsCount                 = PackedAttachmentCount(0);
2311     mDepthStencilAttachmentIndex           = kAttachmentIndexInvalid;
2312     mImageOptimizeForPresent               = nullptr;
2313     mImageOptimizeForPresentOriginalLayout = ImageLayout::Undefined;
2314 
2315     ASSERT(CheckSubpassCommandBufferCount(getSubpassCommandBufferCount()));
2316 
2317     // Collect/Reset the command buffers
2318     for (uint32_t subpass = 0; subpass < getSubpassCommandBufferCount(); ++subpass)
2319     {
2320         commandBufferCollector->collectCommandBuffer(std::move(mCommandBuffers[subpass]));
2321     }
2322 
2323     mCurrentSubpassCommandBufferIndex = 0;
2324 
2325     // Reset the image views used for imageless framebuffer (if any)
2326     mFramebuffer.reset();
2327 
2328     // Invalidate the queue serial here. We will get a new queue serial when we begin renderpass.
2329     mQueueSerial = QueueSerial();
2330 
2331     return initializeCommandBuffer(context);
2332 }
2333 
imageRead(ContextVk * contextVk,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)2334 void RenderPassCommandBufferHelper::imageRead(ContextVk *contextVk,
2335                                               VkImageAspectFlags aspectFlags,
2336                                               ImageLayout imageLayout,
2337                                               ImageHelper *image)
2338 {
2339     imageReadImpl(contextVk, aspectFlags, imageLayout, BarrierType::Event, image);
2340     // As noted in the header we don't support multiple read layouts for Images.
2341     // We allow duplicate uses in the RP to accommodate for normal GL sampler usage.
2342     retainImageWithEvent(contextVk, image);
2343 }
2344 
imageWrite(ContextVk * contextVk,gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)2345 void RenderPassCommandBufferHelper::imageWrite(ContextVk *contextVk,
2346                                                gl::LevelIndex level,
2347                                                uint32_t layerStart,
2348                                                uint32_t layerCount,
2349                                                VkImageAspectFlags aspectFlags,
2350                                                ImageLayout imageLayout,
2351                                                ImageHelper *image)
2352 {
2353     imageWriteImpl(contextVk, level, layerStart, layerCount, aspectFlags, imageLayout,
2354                    BarrierType::Event, image);
2355     retainImageWithEvent(contextVk, image);
2356 }
2357 
colorImagesDraw(gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,ImageHelper * image,ImageHelper * resolveImage,UniqueSerial imageSiblingSerial,PackedAttachmentIndex packedAttachmentIndex)2358 void RenderPassCommandBufferHelper::colorImagesDraw(gl::LevelIndex level,
2359                                                     uint32_t layerStart,
2360                                                     uint32_t layerCount,
2361                                                     ImageHelper *image,
2362                                                     ImageHelper *resolveImage,
2363                                                     UniqueSerial imageSiblingSerial,
2364                                                     PackedAttachmentIndex packedAttachmentIndex)
2365 {
2366     ASSERT(packedAttachmentIndex < mColorAttachmentsCount);
2367 
2368     image->onRenderPassAttach(mQueueSerial);
2369 
2370     mColorAttachments[packedAttachmentIndex].init(image, imageSiblingSerial, level, layerStart,
2371                                                   layerCount, VK_IMAGE_ASPECT_COLOR_BIT);
2372 
2373     if (resolveImage)
2374     {
2375         resolveImage->onRenderPassAttach(mQueueSerial);
2376         mColorResolveAttachments[packedAttachmentIndex].init(resolveImage, imageSiblingSerial,
2377                                                              level, layerStart, layerCount,
2378                                                              VK_IMAGE_ASPECT_COLOR_BIT);
2379     }
2380 }
2381 
depthStencilImagesDraw(gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,ImageHelper * image,ImageHelper * resolveImage,UniqueSerial imageSiblingSerial)2382 void RenderPassCommandBufferHelper::depthStencilImagesDraw(gl::LevelIndex level,
2383                                                            uint32_t layerStart,
2384                                                            uint32_t layerCount,
2385                                                            ImageHelper *image,
2386                                                            ImageHelper *resolveImage,
2387                                                            UniqueSerial imageSiblingSerial)
2388 {
2389     ASSERT(!usesImage(*image));
2390     ASSERT(!resolveImage || !usesImage(*resolveImage));
2391 
2392     // Because depthStencil buffer's read/write property can change while we build renderpass, we
2393     // defer the image layout changes until endRenderPass time or when images going away so that we
2394     // only insert layout change barrier once.
2395     image->onRenderPassAttach(mQueueSerial);
2396 
2397     mDepthAttachment.init(image, imageSiblingSerial, level, layerStart, layerCount,
2398                           VK_IMAGE_ASPECT_DEPTH_BIT);
2399     mStencilAttachment.init(image, imageSiblingSerial, level, layerStart, layerCount,
2400                             VK_IMAGE_ASPECT_STENCIL_BIT);
2401 
2402     if (resolveImage)
2403     {
2404         // Note that the resolve depth/stencil image has the same level/layer index as the
2405         // depth/stencil image as currently it can only ever come from
2406         // multisampled-render-to-texture renderbuffers.
2407         resolveImage->onRenderPassAttach(mQueueSerial);
2408 
2409         mDepthResolveAttachment.init(resolveImage, imageSiblingSerial, level, layerStart,
2410                                      layerCount, VK_IMAGE_ASPECT_DEPTH_BIT);
2411         mStencilResolveAttachment.init(resolveImage, imageSiblingSerial, level, layerStart,
2412                                        layerCount, VK_IMAGE_ASPECT_STENCIL_BIT);
2413     }
2414 }
2415 
fragmentShadingRateImageRead(ImageHelper * image)2416 void RenderPassCommandBufferHelper::fragmentShadingRateImageRead(ImageHelper *image)
2417 {
2418     ASSERT(image && image->valid());
2419     ASSERT(!usesImage(*image));
2420 
2421     image->onRenderPassAttach(mQueueSerial);
2422 
2423     // Initialize RenderPassAttachment for fragment shading rate attachment.
2424     mFragmentShadingRateAtachment.init(image, {}, gl::LevelIndex(0), 0, 1,
2425                                        VK_IMAGE_ASPECT_COLOR_BIT);
2426 
2427     image->resetRenderPassUsageFlags();
2428     image->setRenderPassUsageFlag(RenderPassUsage::FragmentShadingRateReadOnlyAttachment);
2429 }
2430 
onColorAccess(PackedAttachmentIndex packedAttachmentIndex,ResourceAccess access)2431 void RenderPassCommandBufferHelper::onColorAccess(PackedAttachmentIndex packedAttachmentIndex,
2432                                                   ResourceAccess access)
2433 {
2434     ASSERT(packedAttachmentIndex < mColorAttachmentsCount);
2435     mColorAttachments[packedAttachmentIndex].onAccess(access, getRenderPassWriteCommandCount());
2436 }
2437 
onDepthAccess(ResourceAccess access)2438 void RenderPassCommandBufferHelper::onDepthAccess(ResourceAccess access)
2439 {
2440     mDepthAttachment.onAccess(access, getRenderPassWriteCommandCount());
2441 }
2442 
onStencilAccess(ResourceAccess access)2443 void RenderPassCommandBufferHelper::onStencilAccess(ResourceAccess access)
2444 {
2445     mStencilAttachment.onAccess(access, getRenderPassWriteCommandCount());
2446 }
2447 
updateDepthReadOnlyMode(RenderPassUsageFlags dsUsageFlags)2448 void RenderPassCommandBufferHelper::updateDepthReadOnlyMode(RenderPassUsageFlags dsUsageFlags)
2449 {
2450     ASSERT(mRenderPassStarted);
2451     updateStartedRenderPassWithDepthStencilMode(&mDepthResolveAttachment, hasDepthWriteOrClear(),
2452                                                 dsUsageFlags,
2453                                                 RenderPassUsage::DepthReadOnlyAttachment);
2454 }
2455 
updateStencilReadOnlyMode(RenderPassUsageFlags dsUsageFlags)2456 void RenderPassCommandBufferHelper::updateStencilReadOnlyMode(RenderPassUsageFlags dsUsageFlags)
2457 {
2458     ASSERT(mRenderPassStarted);
2459     updateStartedRenderPassWithDepthStencilMode(&mStencilResolveAttachment,
2460                                                 hasStencilWriteOrClear(), dsUsageFlags,
2461                                                 RenderPassUsage::StencilReadOnlyAttachment);
2462 }
2463 
updateDepthStencilReadOnlyMode(RenderPassUsageFlags dsUsageFlags,VkImageAspectFlags dsAspectFlags)2464 void RenderPassCommandBufferHelper::updateDepthStencilReadOnlyMode(
2465     RenderPassUsageFlags dsUsageFlags,
2466     VkImageAspectFlags dsAspectFlags)
2467 {
2468     ASSERT(mRenderPassStarted);
2469     if ((dsAspectFlags & VK_IMAGE_ASPECT_DEPTH_BIT) != 0)
2470     {
2471         updateDepthReadOnlyMode(dsUsageFlags);
2472     }
2473     if ((dsAspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
2474     {
2475         updateStencilReadOnlyMode(dsUsageFlags);
2476     }
2477 }
2478 
updateStartedRenderPassWithDepthStencilMode(RenderPassAttachment * resolveAttachment,bool renderPassHasWriteOrClear,RenderPassUsageFlags dsUsageFlags,RenderPassUsage readOnlyAttachmentUsage)2479 void RenderPassCommandBufferHelper::updateStartedRenderPassWithDepthStencilMode(
2480     RenderPassAttachment *resolveAttachment,
2481     bool renderPassHasWriteOrClear,
2482     RenderPassUsageFlags dsUsageFlags,
2483     RenderPassUsage readOnlyAttachmentUsage)
2484 {
2485     ASSERT(mRenderPassStarted);
2486     ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
2487     ASSERT(mDepthResolveAttachment.getImage() == mStencilResolveAttachment.getImage());
2488 
2489     // Determine read-only mode for depth or stencil
2490     const bool readOnlyMode =
2491         mDepthStencilAttachmentIndex != kAttachmentIndexInvalid &&
2492         resolveAttachment->getImage() == nullptr &&
2493         (dsUsageFlags.test(readOnlyAttachmentUsage) || !renderPassHasWriteOrClear);
2494 
2495     // If readOnlyMode is false, we are switching out of read only mode due to depth/stencil write.
2496     // We must not be in the read only feedback loop mode because the logic in
2497     // DIRTY_BIT_READ_ONLY_DEPTH_FEEDBACK_LOOP_MODE should ensure we end the previous renderpass and
2498     // a new renderpass will start with feedback loop disabled.
2499     ASSERT(readOnlyMode || !dsUsageFlags.test(readOnlyAttachmentUsage));
2500 
2501     ImageHelper *depthStencilImage = mDepthAttachment.getImage();
2502     if (depthStencilImage)
2503     {
2504         if (readOnlyMode)
2505         {
2506             depthStencilImage->setRenderPassUsageFlag(readOnlyAttachmentUsage);
2507         }
2508         else
2509         {
2510             depthStencilImage->clearRenderPassUsageFlag(readOnlyAttachmentUsage);
2511         }
2512     }
2513     // The depth/stencil resolve image is never in read-only mode
2514 }
2515 
finalizeColorImageLayout(Context * context,ImageHelper * image,PackedAttachmentIndex packedAttachmentIndex,bool isResolveImage)2516 void RenderPassCommandBufferHelper::finalizeColorImageLayout(
2517     Context *context,
2518     ImageHelper *image,
2519     PackedAttachmentIndex packedAttachmentIndex,
2520     bool isResolveImage)
2521 {
2522     ASSERT(packedAttachmentIndex < mColorAttachmentsCount);
2523     ASSERT(image != nullptr);
2524 
2525     // Do layout change.
2526     ImageLayout imageLayout;
2527     if (image->usedByCurrentRenderPassAsAttachmentAndSampler(RenderPassUsage::ColorTextureSampler))
2528     {
2529         // texture code already picked layout and inserted barrier
2530         imageLayout = image->getCurrentImageLayout();
2531         ASSERT(imageLayout == ImageLayout::ColorWriteFragmentShaderFeedback ||
2532                imageLayout == ImageLayout::ColorWriteAllShadersFeedback);
2533     }
2534     else
2535     {
2536         // When color is unresolved, use a layout that includes fragment shader reads.  This is done
2537         // for all color resolve attachments even if they are not all unresolved for simplicity.  In
2538         // particular, the GL color index is not available (only the packed index) at this point,
2539         // but that is needed to query whether the attachment is unresolved or not.
2540         const bool hasUnresolve =
2541             isResolveImage && mRenderPassDesc.getColorUnresolveAttachmentMask().any();
2542         imageLayout = hasUnresolve ? ImageLayout::MSRTTEmulationColorUnresolveAndResolve
2543                                    : ImageLayout::ColorWrite;
2544         if (context->getFeatures().preferDynamicRendering.enabled &&
2545             mRenderPassDesc.hasColorFramebufferFetch())
2546         {
2547             // Note MSRTT emulation is not implemented with dynamic rendering.
2548             ASSERT(imageLayout == ImageLayout::ColorWrite);
2549             imageLayout = ImageLayout::ColorWriteAndInput;
2550         }
2551 
2552         updateImageLayoutAndBarrier(context, image, VK_IMAGE_ASPECT_COLOR_BIT, imageLayout,
2553                                     BarrierType::Event);
2554     }
2555 
2556     if (!isResolveImage)
2557     {
2558         mAttachmentOps.setLayouts(packedAttachmentIndex, imageLayout, imageLayout);
2559     }
2560 
2561     // Dynamic rendering does not have implicit layout transitions at render pass boundaries.  This
2562     // optimization is instead done by recording the necessary transition after the render pass
2563     // directly on the primary command buffer.
2564     if (mImageOptimizeForPresent == image)
2565     {
2566         ASSERT(isDefault());
2567         ASSERT(context->getFeatures().supportsPresentation.enabled);
2568         ASSERT(packedAttachmentIndex == kAttachmentIndexZero);
2569 
2570         // Use finalLayout instead of extra barrier for layout change to present.  For dynamic
2571         // rendering, this is not possible and is done when the render pass is flushed.  However,
2572         // because this function is expected to finalize the image layout, we still have to pretend
2573         // the image is in the present layout already.
2574         mImageOptimizeForPresentOriginalLayout = mImageOptimizeForPresent->getCurrentImageLayout();
2575         mImageOptimizeForPresent->setCurrentImageLayout(context->getRenderer(),
2576                                                         ImageLayout::Present);
2577 
2578         if (!context->getFeatures().preferDynamicRendering.enabled)
2579         {
2580             if (isResolveImage)
2581             {
2582                 SetBitField(mAttachmentOps[packedAttachmentIndex].finalResolveLayout,
2583                             mImageOptimizeForPresent->getCurrentImageLayout());
2584             }
2585             else
2586             {
2587                 SetBitField(mAttachmentOps[packedAttachmentIndex].finalLayout,
2588                             mImageOptimizeForPresent->getCurrentImageLayout());
2589             }
2590             mImageOptimizeForPresent               = nullptr;
2591             mImageOptimizeForPresentOriginalLayout = ImageLayout::Undefined;
2592         }
2593     }
2594 
2595     if (isResolveImage)
2596     {
2597         // Note: the color image will have its flags reset after load/store ops are determined.
2598         image->resetRenderPassUsageFlags();
2599     }
2600 }
2601 
finalizeColorImageLoadStore(Context * context,PackedAttachmentIndex packedAttachmentIndex)2602 void RenderPassCommandBufferHelper::finalizeColorImageLoadStore(
2603     Context *context,
2604     PackedAttachmentIndex packedAttachmentIndex)
2605 {
2606     PackedAttachmentOpsDesc &ops = mAttachmentOps[packedAttachmentIndex];
2607     RenderPassLoadOp loadOp      = static_cast<RenderPassLoadOp>(ops.loadOp);
2608     RenderPassStoreOp storeOp    = static_cast<RenderPassStoreOp>(ops.storeOp);
2609 
2610     // This has to be called after layout been finalized
2611     ASSERT(ops.initialLayout != static_cast<uint16_t>(ImageLayout::Undefined));
2612 
2613     uint32_t currentCmdCount = getRenderPassWriteCommandCount();
2614     bool isInvalidated       = false;
2615 
2616     RenderPassAttachment &colorAttachment = mColorAttachments[packedAttachmentIndex];
2617     colorAttachment.finalizeLoadStore(
2618         context, currentCmdCount, mRenderPassDesc.getColorUnresolveAttachmentMask().any(),
2619         mRenderPassDesc.getColorResolveAttachmentMask().any(), &loadOp, &storeOp, &isInvalidated);
2620 
2621     if (isInvalidated)
2622     {
2623         ops.isInvalidated = true;
2624     }
2625 
2626     if (!ops.isInvalidated)
2627     {
2628         mColorResolveAttachments[packedAttachmentIndex].restoreContent();
2629     }
2630 
2631     // If the image is being written to, mark its contents defined.
2632     // This has to be done after storeOp has been finalized.
2633     if (storeOp == RenderPassStoreOp::Store)
2634     {
2635         colorAttachment.restoreContent();
2636     }
2637 
2638     SetBitField(ops.loadOp, loadOp);
2639     SetBitField(ops.storeOp, storeOp);
2640 }
2641 
finalizeDepthStencilImageLayout(Context * context)2642 void RenderPassCommandBufferHelper::finalizeDepthStencilImageLayout(Context *context)
2643 {
2644     ASSERT(mDepthAttachment.getImage() != nullptr);
2645     ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
2646 
2647     ImageHelper *depthStencilImage = mDepthAttachment.getImage();
2648 
2649     // Do depth stencil layout change.
2650     ImageLayout imageLayout;
2651     bool barrierRequired;
2652 
2653     const bool isDepthAttachmentAndSampler =
2654         depthStencilImage->usedByCurrentRenderPassAsAttachmentAndSampler(
2655             RenderPassUsage::DepthTextureSampler);
2656     const bool isStencilAttachmentAndSampler =
2657         depthStencilImage->usedByCurrentRenderPassAsAttachmentAndSampler(
2658             RenderPassUsage::StencilTextureSampler);
2659     const bool isReadOnlyDepth =
2660         depthStencilImage->hasRenderPassUsageFlag(RenderPassUsage::DepthReadOnlyAttachment);
2661     const bool isReadOnlyStencil =
2662         depthStencilImage->hasRenderPassUsageFlag(RenderPassUsage::StencilReadOnlyAttachment);
2663     BarrierType barrierType = BarrierType::Event;
2664 
2665     if (isDepthAttachmentAndSampler || isStencilAttachmentAndSampler)
2666     {
2667         // texture code already picked layout and inserted barrier
2668         imageLayout = depthStencilImage->getCurrentImageLayout();
2669 
2670         if ((isDepthAttachmentAndSampler && !isReadOnlyDepth) ||
2671             (isStencilAttachmentAndSampler && !isReadOnlyStencil))
2672         {
2673             ASSERT(imageLayout == ImageLayout::DepthStencilFragmentShaderFeedback ||
2674                    imageLayout == ImageLayout::DepthStencilAllShadersFeedback);
2675             barrierRequired = true;
2676         }
2677         else
2678         {
2679             ASSERT(imageLayout == ImageLayout::DepthWriteStencilReadFragmentShaderStencilRead ||
2680                    imageLayout == ImageLayout::DepthWriteStencilReadAllShadersStencilRead ||
2681                    imageLayout == ImageLayout::DepthReadStencilWriteFragmentShaderDepthRead ||
2682                    imageLayout == ImageLayout::DepthReadStencilWriteAllShadersDepthRead ||
2683                    imageLayout == ImageLayout::DepthReadStencilReadFragmentShaderRead ||
2684                    imageLayout == ImageLayout::DepthReadStencilReadAllShadersRead);
2685             barrierRequired =
2686                 depthStencilImage->isReadBarrierNecessary(context->getRenderer(), imageLayout);
2687         }
2688     }
2689     else
2690     {
2691         if (mRenderPassDesc.hasDepthStencilFramebufferFetch())
2692         {
2693             imageLayout = ImageLayout::DepthStencilWriteAndInput;
2694         }
2695         else if (isReadOnlyDepth)
2696         {
2697             imageLayout = isReadOnlyStencil ? ImageLayout::DepthReadStencilRead
2698                                             : ImageLayout::DepthReadStencilWrite;
2699         }
2700         else
2701         {
2702             imageLayout = isReadOnlyStencil ? ImageLayout::DepthWriteStencilRead
2703                                             : ImageLayout::DepthWriteStencilWrite;
2704         }
2705 
2706         barrierRequired =
2707             !isReadOnlyDepth || !isReadOnlyStencil ||
2708             depthStencilImage->isReadBarrierNecessary(context->getRenderer(), imageLayout);
2709     }
2710 
2711     mAttachmentOps.setLayouts(mDepthStencilAttachmentIndex, imageLayout, imageLayout);
2712 
2713     if (barrierRequired)
2714     {
2715         const angle::Format &format = depthStencilImage->getActualFormat();
2716         ASSERT(format.hasDepthOrStencilBits());
2717         VkImageAspectFlags aspectFlags = GetDepthStencilAspectFlags(format);
2718         updateImageLayoutAndBarrier(context, depthStencilImage, aspectFlags, imageLayout,
2719                                     barrierType);
2720     }
2721 }
2722 
finalizeDepthStencilResolveImageLayout(Context * context)2723 void RenderPassCommandBufferHelper::finalizeDepthStencilResolveImageLayout(Context *context)
2724 {
2725     ASSERT(mDepthResolveAttachment.getImage() != nullptr);
2726     ASSERT(mDepthResolveAttachment.getImage() == mStencilResolveAttachment.getImage());
2727 
2728     ImageHelper *depthStencilResolveImage = mDepthResolveAttachment.getImage();
2729 
2730     // When depth/stencil is unresolved, use a layout that includes fragment shader reads.
2731     ImageLayout imageLayout     = mRenderPassDesc.hasDepthStencilUnresolveAttachment()
2732                                       ? ImageLayout::MSRTTEmulationDepthStencilUnresolveAndResolve
2733                                       : ImageLayout::DepthStencilResolve;
2734     const angle::Format &format = depthStencilResolveImage->getActualFormat();
2735     ASSERT(format.hasDepthOrStencilBits());
2736     VkImageAspectFlags aspectFlags = GetDepthStencilAspectFlags(format);
2737 
2738     updateImageLayoutAndBarrier(context, depthStencilResolveImage, aspectFlags, imageLayout,
2739                                 BarrierType::Event);
2740 
2741     // The resolve image can never be read-only.
2742     ASSERT(!depthStencilResolveImage->hasRenderPassUsageFlag(
2743         RenderPassUsage::DepthReadOnlyAttachment));
2744     ASSERT(!depthStencilResolveImage->hasRenderPassUsageFlag(
2745         RenderPassUsage::StencilReadOnlyAttachment));
2746     ASSERT(mDepthStencilAttachmentIndex != kAttachmentIndexInvalid);
2747     const PackedAttachmentOpsDesc &dsOps = mAttachmentOps[mDepthStencilAttachmentIndex];
2748 
2749     // If the image is being written to, mark its contents defined.
2750     if (!dsOps.isInvalidated && mRenderPassDesc.hasDepthResolveAttachment())
2751     {
2752         mDepthResolveAttachment.restoreContent();
2753     }
2754     if (!dsOps.isStencilInvalidated && mRenderPassDesc.hasStencilResolveAttachment())
2755     {
2756         mStencilResolveAttachment.restoreContent();
2757     }
2758 
2759     depthStencilResolveImage->resetRenderPassUsageFlags();
2760 }
2761 
finalizeFragmentShadingRateImageLayout(Context * context)2762 void RenderPassCommandBufferHelper::finalizeFragmentShadingRateImageLayout(Context *context)
2763 {
2764     ImageHelper *image      = mFragmentShadingRateAtachment.getImage();
2765     ImageLayout imageLayout = ImageLayout::FragmentShadingRateAttachmentReadOnly;
2766     ASSERT(image && image->valid());
2767     if (image->isReadBarrierNecessary(context->getRenderer(), imageLayout))
2768     {
2769         updateImageLayoutAndBarrier(context, image, VK_IMAGE_ASPECT_COLOR_BIT, imageLayout,
2770                                     BarrierType::Event);
2771     }
2772     image->resetRenderPassUsageFlags();
2773 }
2774 
finalizeImageLayout(Context * context,const ImageHelper * image,UniqueSerial imageSiblingSerial)2775 void RenderPassCommandBufferHelper::finalizeImageLayout(Context *context,
2776                                                         const ImageHelper *image,
2777                                                         UniqueSerial imageSiblingSerial)
2778 {
2779     if (image->hasRenderPassUsageFlag(RenderPassUsage::RenderTargetAttachment))
2780     {
2781         for (PackedAttachmentIndex index = kAttachmentIndexZero; index < mColorAttachmentsCount;
2782              ++index)
2783         {
2784             if (mColorAttachments[index].hasImage(image, imageSiblingSerial))
2785             {
2786                 finalizeColorImageLayoutAndLoadStore(context, index);
2787                 mColorAttachments[index].reset();
2788             }
2789             else if (mColorResolveAttachments[index].hasImage(image, imageSiblingSerial))
2790             {
2791                 finalizeColorImageLayout(context, mColorResolveAttachments[index].getImage(), index,
2792                                          true);
2793                 mColorResolveAttachments[index].reset();
2794             }
2795         }
2796     }
2797 
2798     if (mDepthAttachment.hasImage(image, imageSiblingSerial))
2799     {
2800         finalizeDepthStencilImageLayoutAndLoadStore(context);
2801         mDepthAttachment.reset();
2802         mStencilAttachment.reset();
2803     }
2804 
2805     if (mDepthResolveAttachment.hasImage(image, imageSiblingSerial))
2806     {
2807         finalizeDepthStencilResolveImageLayout(context);
2808         mDepthResolveAttachment.reset();
2809         mStencilResolveAttachment.reset();
2810     }
2811 
2812     if (mFragmentShadingRateAtachment.hasImage(image, imageSiblingSerial))
2813     {
2814         finalizeFragmentShadingRateImageLayout(context);
2815         mFragmentShadingRateAtachment.reset();
2816     }
2817 }
2818 
finalizeDepthStencilLoadStore(Context * context)2819 void RenderPassCommandBufferHelper::finalizeDepthStencilLoadStore(Context *context)
2820 {
2821     ASSERT(mDepthStencilAttachmentIndex != kAttachmentIndexInvalid);
2822 
2823     PackedAttachmentOpsDesc &dsOps   = mAttachmentOps[mDepthStencilAttachmentIndex];
2824     RenderPassLoadOp depthLoadOp     = static_cast<RenderPassLoadOp>(dsOps.loadOp);
2825     RenderPassStoreOp depthStoreOp   = static_cast<RenderPassStoreOp>(dsOps.storeOp);
2826     RenderPassLoadOp stencilLoadOp   = static_cast<RenderPassLoadOp>(dsOps.stencilLoadOp);
2827     RenderPassStoreOp stencilStoreOp = static_cast<RenderPassStoreOp>(dsOps.stencilStoreOp);
2828 
2829     // This has to be called after layout been finalized
2830     ASSERT(dsOps.initialLayout != static_cast<uint16_t>(ImageLayout::Undefined));
2831 
2832     uint32_t currentCmdCount         = getRenderPassWriteCommandCount();
2833     bool isDepthInvalidated          = false;
2834     bool isStencilInvalidated        = false;
2835     bool hasDepthResolveAttachment   = mRenderPassDesc.hasDepthResolveAttachment();
2836     bool hasStencilResolveAttachment = mRenderPassDesc.hasStencilResolveAttachment();
2837 
2838     mDepthAttachment.finalizeLoadStore(
2839         context, currentCmdCount, mRenderPassDesc.hasDepthUnresolveAttachment(),
2840         hasDepthResolveAttachment, &depthLoadOp, &depthStoreOp, &isDepthInvalidated);
2841     mStencilAttachment.finalizeLoadStore(
2842         context, currentCmdCount, mRenderPassDesc.hasStencilUnresolveAttachment(),
2843         hasStencilResolveAttachment, &stencilLoadOp, &stencilStoreOp, &isStencilInvalidated);
2844 
2845     const bool disableMixedDepthStencilLoadOpNoneAndLoad =
2846         context->getFeatures().disallowMixedDepthStencilLoadOpNoneAndLoad.enabled;
2847 
2848     if (disableMixedDepthStencilLoadOpNoneAndLoad)
2849     {
2850         if (depthLoadOp == RenderPassLoadOp::None && stencilLoadOp != RenderPassLoadOp::None)
2851         {
2852             depthLoadOp = RenderPassLoadOp::Load;
2853         }
2854         if (depthLoadOp != RenderPassLoadOp::None && stencilLoadOp == RenderPassLoadOp::None)
2855         {
2856             stencilLoadOp = RenderPassLoadOp::Load;
2857         }
2858     }
2859 
2860     if (isDepthInvalidated)
2861     {
2862         dsOps.isInvalidated = true;
2863     }
2864     if (isStencilInvalidated)
2865     {
2866         dsOps.isStencilInvalidated = true;
2867     }
2868 
2869     // If any aspect is missing, set the corresponding ops to don't care.
2870     const uint32_t depthStencilIndexGL =
2871         static_cast<uint32_t>(mRenderPassDesc.depthStencilAttachmentIndex());
2872     const angle::FormatID attachmentFormatID = mRenderPassDesc[depthStencilIndexGL];
2873     ASSERT(attachmentFormatID != angle::FormatID::NONE);
2874     const angle::Format &angleFormat = angle::Format::Get(attachmentFormatID);
2875 
2876     if (angleFormat.depthBits == 0)
2877     {
2878         depthLoadOp  = RenderPassLoadOp::DontCare;
2879         depthStoreOp = RenderPassStoreOp::DontCare;
2880     }
2881     if (angleFormat.stencilBits == 0)
2882     {
2883         stencilLoadOp  = RenderPassLoadOp::DontCare;
2884         stencilStoreOp = RenderPassStoreOp::DontCare;
2885     }
2886 
2887     // If the image is being written to, mark its contents defined.
2888     // This has to be done after storeOp has been finalized.
2889     ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
2890     if (!mDepthAttachment.getImage()->hasRenderPassUsageFlag(
2891             RenderPassUsage::DepthReadOnlyAttachment))
2892     {
2893         if (depthStoreOp == RenderPassStoreOp::Store)
2894         {
2895             mDepthAttachment.restoreContent();
2896         }
2897     }
2898     if (!mStencilAttachment.getImage()->hasRenderPassUsageFlag(
2899             RenderPassUsage::StencilReadOnlyAttachment))
2900     {
2901         if (stencilStoreOp == RenderPassStoreOp::Store)
2902         {
2903             mStencilAttachment.restoreContent();
2904         }
2905     }
2906 
2907     SetBitField(dsOps.loadOp, depthLoadOp);
2908     SetBitField(dsOps.storeOp, depthStoreOp);
2909     SetBitField(dsOps.stencilLoadOp, stencilLoadOp);
2910     SetBitField(dsOps.stencilStoreOp, stencilStoreOp);
2911 }
2912 
finalizeColorImageLayoutAndLoadStore(Context * context,PackedAttachmentIndex packedAttachmentIndex)2913 void RenderPassCommandBufferHelper::finalizeColorImageLayoutAndLoadStore(
2914     Context *context,
2915     PackedAttachmentIndex packedAttachmentIndex)
2916 {
2917     finalizeColorImageLayout(context, mColorAttachments[packedAttachmentIndex].getImage(),
2918                              packedAttachmentIndex, false);
2919     finalizeColorImageLoadStore(context, packedAttachmentIndex);
2920 
2921     mColorAttachments[packedAttachmentIndex].getImage()->resetRenderPassUsageFlags();
2922 }
2923 
finalizeDepthStencilImageLayoutAndLoadStore(Context * context)2924 void RenderPassCommandBufferHelper::finalizeDepthStencilImageLayoutAndLoadStore(Context *context)
2925 {
2926     finalizeDepthStencilImageLayout(context);
2927     finalizeDepthStencilLoadStore(context);
2928 
2929     ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
2930     mDepthAttachment.getImage()->resetRenderPassUsageFlags();
2931 }
2932 
executeSetEvents(Context * context,PrimaryCommandBuffer * primary)2933 void RenderPassCommandBufferHelper::executeSetEvents(Context *context,
2934                                                      PrimaryCommandBuffer *primary)
2935 {
2936     Renderer *renderer = context->getRenderer();
2937     // Add VkCmdSetEvent here to track the completion of this renderPass.
2938     for (EventStage stage : mRefCountedEvents.mask)
2939     {
2940         // This must have been garbage collected. The VkEvent handle should have been copied to
2941         // VkEvents.
2942         ASSERT(!mRefCountedEvents.map[stage].valid());
2943         ASSERT(mRefCountedEvents.vkEvents[stage] != VK_NULL_HANDLE);
2944         primary->setEvent(mRefCountedEvents.vkEvents[stage], renderer->getPipelineStageMask(stage));
2945         mRefCountedEvents.vkEvents[stage] = VK_NULL_HANDLE;
2946     }
2947     mRefCountedEvents.mask.reset();
2948 }
2949 
collectRefCountedEventsGarbage(RefCountedEventsGarbageRecycler * garbageRecycler)2950 void RenderPassCommandBufferHelper::collectRefCountedEventsGarbage(
2951     RefCountedEventsGarbageRecycler *garbageRecycler)
2952 {
2953     // For render pass the VkCmdSetEvent works differently from OutsideRenderPassCommands.
2954     // VkCmdEndRenderPass are called in the primary command buffer, and VkCmdSetEvents has to be
2955     // issued after VkCmdEndRenderPass. This means VkCmdSetEvent has to be delayed. Because of this,
2956     // here we simply make a local copy of the VkEvent and then add the RefCountedEvent to the
2957     // garbage collector. No VkCmdSetEvent call is issued here (they will be issued at
2958     // flushToPrimary time).
2959     for (EventStage stage : mRefCountedEvents.mask)
2960     {
2961         ASSERT(mRefCountedEvents.map[stage].valid());
2962         mRefCountedEvents.vkEvents[stage] = mRefCountedEvents.map[stage].getEvent().getHandle();
2963         mRefCountedEventCollector.emplace_back(std::move(mRefCountedEvents.map[stage]));
2964     }
2965 
2966     if (!mRefCountedEventCollector.empty())
2967     {
2968         garbageRecycler->collectGarbage(mQueueSerial, std::move(mRefCountedEventCollector));
2969     }
2970 }
2971 
updatePerfCountersForDynamicRenderingInstance(Context * context,angle::VulkanPerfCounters * countersOut)2972 void RenderPassCommandBufferHelper::updatePerfCountersForDynamicRenderingInstance(
2973     Context *context,
2974     angle::VulkanPerfCounters *countersOut)
2975 {
2976     mRenderPassDesc.updatePerfCounters(context, mFramebuffer.getUnpackedImageViews(),
2977                                        mAttachmentOps, countersOut);
2978 }
2979 
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)2980 angle::Result RenderPassCommandBufferHelper::beginRenderPass(
2981     ContextVk *contextVk,
2982     RenderPassFramebuffer &&framebuffer,
2983     const gl::Rectangle &renderArea,
2984     const RenderPassDesc &renderPassDesc,
2985     const AttachmentOpsArray &renderPassAttachmentOps,
2986     const PackedAttachmentCount colorAttachmentCount,
2987     const PackedAttachmentIndex depthStencilAttachmentIndex,
2988     const PackedClearValuesArray &clearValues,
2989     const QueueSerial &queueSerial,
2990     RenderPassCommandBuffer **commandBufferOut)
2991 {
2992     ASSERT(!mRenderPassStarted);
2993 
2994     mRenderPassDesc              = renderPassDesc;
2995     mAttachmentOps               = renderPassAttachmentOps;
2996     mDepthStencilAttachmentIndex = depthStencilAttachmentIndex;
2997     mColorAttachmentsCount       = colorAttachmentCount;
2998     mFramebuffer                 = std::move(framebuffer);
2999     mRenderArea                  = renderArea;
3000     mClearValues                 = clearValues;
3001     mQueueSerial                 = queueSerial;
3002     *commandBufferOut            = &getCommandBuffer();
3003 
3004     mRenderPassStarted = true;
3005     mCounter++;
3006 
3007     return beginRenderPassCommandBuffer(contextVk);
3008 }
3009 
beginRenderPassCommandBuffer(ContextVk * contextVk)3010 angle::Result RenderPassCommandBufferHelper::beginRenderPassCommandBuffer(ContextVk *contextVk)
3011 {
3012     VkCommandBufferInheritanceInfo inheritanceInfo;
3013     VkCommandBufferInheritanceRenderingInfo renderingInfo;
3014     gl::DrawBuffersArray<VkFormat> colorFormatStorage;
3015 
3016     ANGLE_TRY(RenderPassCommandBuffer::InitializeRenderPassInheritanceInfo(
3017         contextVk, mFramebuffer.getFramebuffer(), mRenderPassDesc, &inheritanceInfo, &renderingInfo,
3018         &colorFormatStorage));
3019     inheritanceInfo.subpass = mCurrentSubpassCommandBufferIndex;
3020 
3021     return getCommandBuffer().begin(contextVk, inheritanceInfo);
3022 }
3023 
endRenderPass(ContextVk * contextVk)3024 angle::Result RenderPassCommandBufferHelper::endRenderPass(ContextVk *contextVk)
3025 {
3026     ANGLE_TRY(endRenderPassCommandBuffer(contextVk));
3027 
3028     for (PackedAttachmentIndex index = kAttachmentIndexZero; index < mColorAttachmentsCount;
3029          ++index)
3030     {
3031         if (mColorAttachments[index].getImage() != nullptr)
3032         {
3033             finalizeColorImageLayoutAndLoadStore(contextVk, index);
3034         }
3035         if (mColorResolveAttachments[index].getImage() != nullptr)
3036         {
3037             finalizeColorImageLayout(contextVk, mColorResolveAttachments[index].getImage(), index,
3038                                      true);
3039         }
3040     }
3041 
3042     if (mFragmentShadingRateAtachment.getImage() != nullptr)
3043     {
3044         finalizeFragmentShadingRateImageLayout(contextVk);
3045     }
3046 
3047     if (mDepthStencilAttachmentIndex != kAttachmentIndexInvalid)
3048     {
3049         // Do depth stencil layout change and load store optimization.
3050         ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
3051         ASSERT(mDepthResolveAttachment.getImage() == mStencilResolveAttachment.getImage());
3052         if (mDepthAttachment.getImage() != nullptr)
3053         {
3054             finalizeDepthStencilImageLayoutAndLoadStore(contextVk);
3055         }
3056         if (mDepthResolveAttachment.getImage() != nullptr)
3057         {
3058             finalizeDepthStencilResolveImageLayout(contextVk);
3059         }
3060     }
3061 
3062     return angle::Result::Continue;
3063 }
3064 
endRenderPassCommandBuffer(ContextVk * contextVk)3065 angle::Result RenderPassCommandBufferHelper::endRenderPassCommandBuffer(ContextVk *contextVk)
3066 {
3067     return getCommandBuffer().end(contextVk);
3068 }
3069 
nextSubpass(ContextVk * contextVk,RenderPassCommandBuffer ** commandBufferOut)3070 angle::Result RenderPassCommandBufferHelper::nextSubpass(ContextVk *contextVk,
3071                                                          RenderPassCommandBuffer **commandBufferOut)
3072 {
3073     ASSERT(!contextVk->getFeatures().preferDynamicRendering.enabled);
3074 
3075     if (ExecutesInline())
3076     {
3077         // When using ANGLE secondary command buffers, the commands are inline and are executed on
3078         // the primary command buffer.  This means that vkCmdNextSubpass can be intermixed with the
3079         // rest of the commands, and there is no need to split command buffers.
3080         //
3081         // Note also that the command buffer handle doesn't change in this case.
3082         getCommandBuffer().nextSubpass(VK_SUBPASS_CONTENTS_INLINE);
3083         return angle::Result::Continue;
3084     }
3085 
3086     // When using Vulkan secondary command buffers, each subpass's contents must be recorded in a
3087     // separate command buffer that is vkCmdExecuteCommands'ed in the primary command buffer.
3088     // vkCmdNextSubpass calls must also be issued in the primary command buffer.
3089     //
3090     // To support this, a list of command buffers are kept, one for each subpass.  When moving to
3091     // the next subpass, the previous command buffer is ended and a new one is initialized and
3092     // begun.
3093 
3094     // Accumulate command count for tracking purposes.
3095     mPreviousSubpassesCmdCount = getRenderPassWriteCommandCount();
3096 
3097     ANGLE_TRY(endRenderPassCommandBuffer(contextVk));
3098     markClosed();
3099 
3100     ++mCurrentSubpassCommandBufferIndex;
3101     ASSERT(getSubpassCommandBufferCount() <= kMaxSubpassCount);
3102 
3103     ANGLE_TRY(initializeCommandBuffer(contextVk));
3104     ANGLE_TRY(beginRenderPassCommandBuffer(contextVk));
3105     markOpen();
3106 
3107     // Return the new command buffer handle
3108     *commandBufferOut = &getCommandBuffer();
3109     return angle::Result::Continue;
3110 }
3111 
beginTransformFeedback(size_t validBufferCount,const VkBuffer * counterBuffers,const VkDeviceSize * counterBufferOffsets,bool rebindBuffers)3112 void RenderPassCommandBufferHelper::beginTransformFeedback(size_t validBufferCount,
3113                                                            const VkBuffer *counterBuffers,
3114                                                            const VkDeviceSize *counterBufferOffsets,
3115                                                            bool rebindBuffers)
3116 {
3117     mValidTransformFeedbackBufferCount = static_cast<uint32_t>(validBufferCount);
3118     mRebindTransformFeedbackBuffers    = rebindBuffers;
3119 
3120     for (size_t index = 0; index < validBufferCount; index++)
3121     {
3122         mTransformFeedbackCounterBuffers[index]       = counterBuffers[index];
3123         mTransformFeedbackCounterBufferOffsets[index] = counterBufferOffsets[index];
3124     }
3125 }
3126 
endTransformFeedback()3127 void RenderPassCommandBufferHelper::endTransformFeedback()
3128 {
3129     pauseTransformFeedback();
3130     mValidTransformFeedbackBufferCount = 0;
3131 }
3132 
invalidateRenderPassColorAttachment(const gl::State & state,size_t colorIndexGL,PackedAttachmentIndex attachmentIndex,const gl::Rectangle & invalidateArea)3133 void RenderPassCommandBufferHelper::invalidateRenderPassColorAttachment(
3134     const gl::State &state,
3135     size_t colorIndexGL,
3136     PackedAttachmentIndex attachmentIndex,
3137     const gl::Rectangle &invalidateArea)
3138 {
3139     // Color write is enabled if:
3140     //
3141     // - Draw buffer is enabled (this is implicit, as invalidate only affects enabled draw buffers)
3142     // - Color output is not entirely masked
3143     // - Rasterizer-discard is not enabled
3144     const gl::BlendStateExt &blendStateExt = state.getBlendStateExt();
3145     const bool isColorWriteEnabled =
3146         blendStateExt.getColorMaskIndexed(colorIndexGL) != 0 && !state.isRasterizerDiscardEnabled();
3147     mColorAttachments[attachmentIndex].invalidate(invalidateArea, isColorWriteEnabled,
3148                                                   getRenderPassWriteCommandCount());
3149 }
3150 
invalidateRenderPassDepthAttachment(const gl::DepthStencilState & dsState,const gl::Rectangle & invalidateArea)3151 void RenderPassCommandBufferHelper::invalidateRenderPassDepthAttachment(
3152     const gl::DepthStencilState &dsState,
3153     const gl::Rectangle &invalidateArea)
3154 {
3155     const bool isDepthWriteEnabled = dsState.depthTest && dsState.depthMask;
3156     mDepthAttachment.invalidate(invalidateArea, isDepthWriteEnabled,
3157                                 getRenderPassWriteCommandCount());
3158 }
3159 
invalidateRenderPassStencilAttachment(const gl::DepthStencilState & dsState,GLuint framebufferStencilSize,const gl::Rectangle & invalidateArea)3160 void RenderPassCommandBufferHelper::invalidateRenderPassStencilAttachment(
3161     const gl::DepthStencilState &dsState,
3162     GLuint framebufferStencilSize,
3163     const gl::Rectangle &invalidateArea)
3164 {
3165     const bool isStencilWriteEnabled =
3166         dsState.stencilTest && (!dsState.isStencilNoOp(framebufferStencilSize) ||
3167                                 !dsState.isStencilBackNoOp(framebufferStencilSize));
3168     mStencilAttachment.invalidate(invalidateArea, isStencilWriteEnabled,
3169                                   getRenderPassWriteCommandCount());
3170 }
3171 
flushToPrimary(Context * context,CommandsState * commandsState,const RenderPass & renderPass,VkFramebuffer framebufferOverride)3172 angle::Result RenderPassCommandBufferHelper::flushToPrimary(Context *context,
3173                                                             CommandsState *commandsState,
3174                                                             const RenderPass &renderPass,
3175                                                             VkFramebuffer framebufferOverride)
3176 {
3177     // |framebufferOverride| must only be provided if the initial framebuffer the render pass was
3178     // started with is not usable (due to the addition of resolve attachments after the fact).
3179     ASSERT(framebufferOverride == VK_NULL_HANDLE ||
3180            mFramebuffer.needsNewFramebufferWithResolveAttachments());
3181     // When a new framebuffer had to be created because of addition of resolve attachments, it's
3182     // never imageless.
3183     ASSERT(!(framebufferOverride != VK_NULL_HANDLE && mFramebuffer.isImageless()));
3184 
3185     ANGLE_TRACE_EVENT0("gpu.angle", "RenderPassCommandBufferHelper::flushToPrimary");
3186     ASSERT(mRenderPassStarted);
3187     PrimaryCommandBuffer &primary = commandsState->primaryCommands;
3188 
3189     // Commands that are added to primary before beginRenderPass command
3190     executeBarriers(context->getRenderer(), commandsState);
3191 
3192     constexpr VkSubpassContents kSubpassContents =
3193         ExecutesInline() ? VK_SUBPASS_CONTENTS_INLINE
3194                          : VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS;
3195 
3196     if (!renderPass.valid())
3197     {
3198         mRenderPassDesc.beginRendering(context, &primary, mRenderArea, kSubpassContents,
3199                                        mFramebuffer.getUnpackedImageViews(), mAttachmentOps,
3200                                        mClearValues, mFramebuffer.getLayers());
3201     }
3202     else
3203     {
3204         // With imageless framebuffers, the attachments should be also added to beginInfo.
3205         VkRenderPassAttachmentBeginInfo attachmentBeginInfo = {};
3206         if (mFramebuffer.isImageless())
3207         {
3208             mFramebuffer.packResolveViewsForRenderPassBegin(&attachmentBeginInfo);
3209 
3210             // If nullColorAttachmentWithExternalFormatResolve is true, there will be no color
3211             // attachment even though mRenderPassDesc indicates so.
3212             ASSERT((mRenderPassDesc.hasYUVResolveAttachment() &&
3213                     context->getRenderer()->nullColorAttachmentWithExternalFormatResolve()) ||
3214                    attachmentBeginInfo.attachmentCount == mRenderPassDesc.attachmentCount());
3215         }
3216 
3217         mRenderPassDesc.beginRenderPass(
3218             context, &primary, renderPass,
3219             framebufferOverride ? framebufferOverride : mFramebuffer.getFramebuffer().getHandle(),
3220             mRenderArea, kSubpassContents, mClearValues,
3221             mFramebuffer.isImageless() ? &attachmentBeginInfo : nullptr);
3222     }
3223 
3224     // Run commands inside the RenderPass.
3225     for (uint32_t subpass = 0; subpass < getSubpassCommandBufferCount(); ++subpass)
3226     {
3227         if (subpass > 0)
3228         {
3229             ASSERT(!context->getFeatures().preferDynamicRendering.enabled);
3230             primary.nextSubpass(kSubpassContents);
3231         }
3232         mCommandBuffers[subpass].executeCommands(&primary);
3233     }
3234 
3235     if (!renderPass.valid())
3236     {
3237         primary.endRendering();
3238 
3239         if (mImageOptimizeForPresent != nullptr)
3240         {
3241             // finalizeColorImageLayout forces layout to Present.  If this is not the case, that
3242             // code was not run (so mImageOptimizeForPresentOriginalLayout is invalid).
3243             ASSERT(mImageOptimizeForPresent->getCurrentImageLayout() == ImageLayout::Present);
3244 
3245             // Restore the original layout of the image and do the real transition after the render
3246             // pass ends.
3247             mImageOptimizeForPresent->setCurrentImageLayout(context->getRenderer(),
3248                                                             mImageOptimizeForPresentOriginalLayout);
3249             mImageOptimizeForPresent->recordWriteBarrierOneOff(context, ImageLayout::Present,
3250                                                                &primary, nullptr);
3251             mImageOptimizeForPresent               = nullptr;
3252             mImageOptimizeForPresentOriginalLayout = ImageLayout::Undefined;
3253         }
3254     }
3255     else
3256     {
3257         primary.endRenderPass();
3258     }
3259 
3260     // Now issue VkCmdSetEvents to primary command buffer
3261     executeSetEvents(context, &primary);
3262 
3263     // Restart the command buffer.
3264     return reset(context, &commandsState->secondaryCommands);
3265 }
3266 
addColorResolveAttachment(size_t colorIndexGL,ImageHelper * image,VkImageView view,gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,UniqueSerial imageSiblingSerial)3267 void RenderPassCommandBufferHelper::addColorResolveAttachment(size_t colorIndexGL,
3268                                                               ImageHelper *image,
3269                                                               VkImageView view,
3270                                                               gl::LevelIndex level,
3271                                                               uint32_t layerStart,
3272                                                               uint32_t layerCount,
3273                                                               UniqueSerial imageSiblingSerial)
3274 {
3275     mFramebuffer.addColorResolveAttachment(colorIndexGL, view);
3276     mRenderPassDesc.packColorResolveAttachment(colorIndexGL);
3277 
3278     PackedAttachmentIndex packedAttachmentIndex =
3279         mRenderPassDesc.getPackedColorAttachmentIndex(colorIndexGL);
3280     ASSERT(mColorResolveAttachments[packedAttachmentIndex].getImage() == nullptr);
3281 
3282     image->onRenderPassAttach(mQueueSerial);
3283     mColorResolveAttachments[packedAttachmentIndex].init(
3284         image, imageSiblingSerial, level, layerStart, layerCount, VK_IMAGE_ASPECT_COLOR_BIT);
3285 }
3286 
addDepthStencilResolveAttachment(ImageHelper * image,VkImageView view,VkImageAspectFlags aspects,gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,UniqueSerial imageSiblingSerial)3287 void RenderPassCommandBufferHelper::addDepthStencilResolveAttachment(
3288     ImageHelper *image,
3289     VkImageView view,
3290     VkImageAspectFlags aspects,
3291     gl::LevelIndex level,
3292     uint32_t layerStart,
3293     uint32_t layerCount,
3294     UniqueSerial imageSiblingSerial)
3295 {
3296     mFramebuffer.addDepthStencilResolveAttachment(view);
3297     if ((aspects & VK_IMAGE_ASPECT_DEPTH_BIT) != 0)
3298     {
3299         mRenderPassDesc.packDepthResolveAttachment();
3300     }
3301     if ((aspects & VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
3302     {
3303         mRenderPassDesc.packStencilResolveAttachment();
3304     }
3305 
3306     image->onRenderPassAttach(mQueueSerial);
3307     mDepthResolveAttachment.init(image, imageSiblingSerial, level, layerStart, layerCount,
3308                                  VK_IMAGE_ASPECT_DEPTH_BIT);
3309     mStencilResolveAttachment.init(image, imageSiblingSerial, level, layerStart, layerCount,
3310                                    VK_IMAGE_ASPECT_STENCIL_BIT);
3311 }
3312 
resumeTransformFeedback()3313 void RenderPassCommandBufferHelper::resumeTransformFeedback()
3314 {
3315     ASSERT(isTransformFeedbackStarted());
3316 
3317     uint32_t numCounterBuffers =
3318         mRebindTransformFeedbackBuffers ? 0 : mValidTransformFeedbackBufferCount;
3319 
3320     mRebindTransformFeedbackBuffers    = false;
3321     mIsTransformFeedbackActiveUnpaused = true;
3322 
3323     getCommandBuffer().beginTransformFeedback(0, numCounterBuffers,
3324                                               mTransformFeedbackCounterBuffers.data(),
3325                                               mTransformFeedbackCounterBufferOffsets.data());
3326 }
3327 
pauseTransformFeedback()3328 void RenderPassCommandBufferHelper::pauseTransformFeedback()
3329 {
3330     ASSERT(isTransformFeedbackStarted() && isTransformFeedbackActiveUnpaused());
3331     mIsTransformFeedbackActiveUnpaused = false;
3332     getCommandBuffer().endTransformFeedback(0, mValidTransformFeedbackBufferCount,
3333                                             mTransformFeedbackCounterBuffers.data(),
3334                                             mTransformFeedbackCounterBufferOffsets.data());
3335 }
3336 
updateRenderPassColorClear(PackedAttachmentIndex colorIndexVk,const VkClearValue & clearValue)3337 void RenderPassCommandBufferHelper::updateRenderPassColorClear(PackedAttachmentIndex colorIndexVk,
3338                                                                const VkClearValue &clearValue)
3339 {
3340     mAttachmentOps.setClearOp(colorIndexVk);
3341     mClearValues.storeColor(colorIndexVk, clearValue);
3342 }
3343 
updateRenderPassDepthStencilClear(VkImageAspectFlags aspectFlags,const VkClearValue & clearValue)3344 void RenderPassCommandBufferHelper::updateRenderPassDepthStencilClear(
3345     VkImageAspectFlags aspectFlags,
3346     const VkClearValue &clearValue)
3347 {
3348     // Don't overwrite prior clear values for individual aspects.
3349     VkClearValue combinedClearValue = mClearValues[mDepthStencilAttachmentIndex];
3350 
3351     if ((aspectFlags & VK_IMAGE_ASPECT_DEPTH_BIT) != 0)
3352     {
3353         mAttachmentOps.setClearOp(mDepthStencilAttachmentIndex);
3354         combinedClearValue.depthStencil.depth = clearValue.depthStencil.depth;
3355     }
3356 
3357     if ((aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
3358     {
3359         mAttachmentOps.setClearStencilOp(mDepthStencilAttachmentIndex);
3360         combinedClearValue.depthStencil.stencil = clearValue.depthStencil.stencil;
3361     }
3362 
3363     // Bypass special D/S handling. This clear values array stores values packed.
3364     mClearValues.storeDepthStencil(mDepthStencilAttachmentIndex, combinedClearValue);
3365 }
3366 
growRenderArea(ContextVk * contextVk,const gl::Rectangle & newRenderArea)3367 void RenderPassCommandBufferHelper::growRenderArea(ContextVk *contextVk,
3368                                                    const gl::Rectangle &newRenderArea)
3369 {
3370     // The render area is grown such that it covers both the previous and the new render areas.
3371     gl::GetEnclosingRectangle(mRenderArea, newRenderArea, &mRenderArea);
3372 
3373     // Remove invalidates that are no longer applicable.
3374     mDepthAttachment.onRenderAreaGrowth(contextVk, mRenderArea);
3375     mStencilAttachment.onRenderAreaGrowth(contextVk, mRenderArea);
3376 }
3377 
attachCommandPool(Context * context,SecondaryCommandPool * commandPool)3378 angle::Result RenderPassCommandBufferHelper::attachCommandPool(Context *context,
3379                                                                SecondaryCommandPool *commandPool)
3380 {
3381     ASSERT(!mRenderPassStarted);
3382     ASSERT(getSubpassCommandBufferCount() == 1);
3383     return attachCommandPoolImpl<RenderPassCommandBufferHelper>(context, commandPool);
3384 }
3385 
detachCommandPool(SecondaryCommandPool ** commandPoolOut)3386 void RenderPassCommandBufferHelper::detachCommandPool(SecondaryCommandPool **commandPoolOut)
3387 {
3388     ASSERT(mRenderPassStarted);
3389     angle::Result result =
3390         detachCommandPoolImpl<RenderPassCommandBufferHelper, true>(nullptr, commandPoolOut);
3391     ASSERT(result == angle::Result::Continue);
3392 }
3393 
releaseCommandPool()3394 void RenderPassCommandBufferHelper::releaseCommandPool()
3395 {
3396     ASSERT(!mRenderPassStarted);
3397     ASSERT(getSubpassCommandBufferCount() == 1);
3398     releaseCommandPoolImpl<RenderPassCommandBufferHelper>();
3399 }
3400 
attachAllocator(SecondaryCommandMemoryAllocator * allocator)3401 void RenderPassCommandBufferHelper::attachAllocator(SecondaryCommandMemoryAllocator *allocator)
3402 {
3403     ASSERT(CheckSubpassCommandBufferCount(getSubpassCommandBufferCount()));
3404     attachAllocatorImpl<RenderPassCommandBufferHelper>(allocator);
3405 }
3406 
detachAllocator()3407 SecondaryCommandMemoryAllocator *RenderPassCommandBufferHelper::detachAllocator()
3408 {
3409     ASSERT(CheckSubpassCommandBufferCount(getSubpassCommandBufferCount()));
3410     return detachAllocatorImpl<RenderPassCommandBufferHelper>();
3411 }
3412 
assertCanBeRecycled()3413 void RenderPassCommandBufferHelper::assertCanBeRecycled()
3414 {
3415     ASSERT(!mRenderPassStarted);
3416     ASSERT(getSubpassCommandBufferCount() == 1);
3417     assertCanBeRecycledImpl<RenderPassCommandBufferHelper>();
3418 }
3419 
getCommandDiagnostics()3420 std::string RenderPassCommandBufferHelper::getCommandDiagnostics()
3421 {
3422     std::ostringstream out;
3423     addCommandDiagnosticsCommon(&out);
3424 
3425     size_t attachmentCount             = mRenderPassDesc.clearableAttachmentCount();
3426     size_t depthStencilAttachmentCount = mRenderPassDesc.hasDepthStencilAttachment() ? 1 : 0;
3427     size_t colorAttachmentCount        = attachmentCount - depthStencilAttachmentCount;
3428 
3429     PackedAttachmentIndex attachmentIndexVk(0);
3430     std::string loadOps, storeOps;
3431 
3432     if (colorAttachmentCount > 0)
3433     {
3434         loadOps += " Color: ";
3435         storeOps += " Color: ";
3436 
3437         for (size_t i = 0; i < colorAttachmentCount; ++i)
3438         {
3439             loadOps += GetLoadOpShorthand(
3440                 static_cast<RenderPassLoadOp>(mAttachmentOps[attachmentIndexVk].loadOp));
3441             storeOps += GetStoreOpShorthand(
3442                 static_cast<RenderPassStoreOp>(mAttachmentOps[attachmentIndexVk].storeOp));
3443             ++attachmentIndexVk;
3444         }
3445     }
3446 
3447     if (depthStencilAttachmentCount > 0)
3448     {
3449         ASSERT(depthStencilAttachmentCount == 1);
3450 
3451         loadOps += " Depth/Stencil: ";
3452         storeOps += " Depth/Stencil: ";
3453 
3454         loadOps += GetLoadOpShorthand(
3455             static_cast<RenderPassLoadOp>(mAttachmentOps[attachmentIndexVk].loadOp));
3456         loadOps += GetLoadOpShorthand(
3457             static_cast<RenderPassLoadOp>(mAttachmentOps[attachmentIndexVk].stencilLoadOp));
3458 
3459         storeOps += GetStoreOpShorthand(
3460             static_cast<RenderPassStoreOp>(mAttachmentOps[attachmentIndexVk].storeOp));
3461         storeOps += GetStoreOpShorthand(
3462             static_cast<RenderPassStoreOp>(mAttachmentOps[attachmentIndexVk].stencilStoreOp));
3463     }
3464 
3465     if (attachmentCount > 0)
3466     {
3467         out << "LoadOp:  " << loadOps << "\\l";
3468         out << "StoreOp: " << storeOps << "\\l";
3469     }
3470 
3471     for (uint32_t subpass = 0; subpass < getSubpassCommandBufferCount(); ++subpass)
3472     {
3473         if (subpass > 0)
3474         {
3475             out << "Next Subpass" << "\\l";
3476         }
3477         out << mCommandBuffers[subpass].dumpCommands("\\l");
3478     }
3479 
3480     return out.str();
3481 }
3482 
3483 // CommandBufferRecycler implementation.
3484 template <typename CommandBufferHelperT>
onDestroy()3485 void CommandBufferRecycler<CommandBufferHelperT>::onDestroy()
3486 {
3487     std::unique_lock<angle::SimpleMutex> lock(mMutex);
3488     for (CommandBufferHelperT *commandBufferHelper : mCommandBufferHelperFreeList)
3489     {
3490         SafeDelete(commandBufferHelper);
3491     }
3492     mCommandBufferHelperFreeList.clear();
3493 }
3494 
3495 template void CommandBufferRecycler<OutsideRenderPassCommandBufferHelper>::onDestroy();
3496 template void CommandBufferRecycler<RenderPassCommandBufferHelper>::onDestroy();
3497 
3498 template <typename CommandBufferHelperT>
getCommandBufferHelper(Context * context,SecondaryCommandPool * commandPool,SecondaryCommandMemoryAllocator * commandsAllocator,CommandBufferHelperT ** commandBufferHelperOut)3499 angle::Result CommandBufferRecycler<CommandBufferHelperT>::getCommandBufferHelper(
3500     Context *context,
3501     SecondaryCommandPool *commandPool,
3502     SecondaryCommandMemoryAllocator *commandsAllocator,
3503     CommandBufferHelperT **commandBufferHelperOut)
3504 {
3505     std::unique_lock<angle::SimpleMutex> lock(mMutex);
3506     if (mCommandBufferHelperFreeList.empty())
3507     {
3508         CommandBufferHelperT *commandBuffer = new CommandBufferHelperT();
3509         *commandBufferHelperOut             = commandBuffer;
3510         ANGLE_TRY(commandBuffer->initialize(context));
3511     }
3512     else
3513     {
3514         CommandBufferHelperT *commandBuffer = mCommandBufferHelperFreeList.back();
3515         mCommandBufferHelperFreeList.pop_back();
3516         *commandBufferHelperOut = commandBuffer;
3517     }
3518 
3519     ANGLE_TRY((*commandBufferHelperOut)->attachCommandPool(context, commandPool));
3520 
3521     // Attach functions are only used for ring buffer allocators.
3522     (*commandBufferHelperOut)->attachAllocator(commandsAllocator);
3523 
3524     return angle::Result::Continue;
3525 }
3526 
3527 template angle::Result
3528 CommandBufferRecycler<OutsideRenderPassCommandBufferHelper>::getCommandBufferHelper(
3529     Context *,
3530     SecondaryCommandPool *,
3531     SecondaryCommandMemoryAllocator *,
3532     OutsideRenderPassCommandBufferHelper **);
3533 template angle::Result CommandBufferRecycler<RenderPassCommandBufferHelper>::getCommandBufferHelper(
3534     Context *,
3535     SecondaryCommandPool *,
3536     SecondaryCommandMemoryAllocator *,
3537     RenderPassCommandBufferHelper **);
3538 
3539 template <typename CommandBufferHelperT>
recycleCommandBufferHelper(CommandBufferHelperT ** commandBuffer)3540 void CommandBufferRecycler<CommandBufferHelperT>::recycleCommandBufferHelper(
3541     CommandBufferHelperT **commandBuffer)
3542 {
3543     (*commandBuffer)->assertCanBeRecycled();
3544     (*commandBuffer)->markOpen();
3545 
3546     {
3547         std::unique_lock<angle::SimpleMutex> lock(mMutex);
3548         mCommandBufferHelperFreeList.push_back(*commandBuffer);
3549     }
3550 
3551     *commandBuffer = nullptr;
3552 }
3553 
3554 template void
3555 CommandBufferRecycler<OutsideRenderPassCommandBufferHelper>::recycleCommandBufferHelper(
3556     OutsideRenderPassCommandBufferHelper **);
3557 template void CommandBufferRecycler<RenderPassCommandBufferHelper>::recycleCommandBufferHelper(
3558     RenderPassCommandBufferHelper **);
3559 
3560 // SecondaryCommandBufferCollector implementation.
collectCommandBuffer(priv::SecondaryCommandBuffer && commandBuffer)3561 void SecondaryCommandBufferCollector::collectCommandBuffer(
3562     priv::SecondaryCommandBuffer &&commandBuffer)
3563 {
3564     commandBuffer.reset();
3565 }
3566 
collectCommandBuffer(VulkanSecondaryCommandBuffer && commandBuffer)3567 void SecondaryCommandBufferCollector::collectCommandBuffer(
3568     VulkanSecondaryCommandBuffer &&commandBuffer)
3569 {
3570     ASSERT(commandBuffer.valid());
3571     mCollectedCommandBuffers.emplace_back(std::move(commandBuffer));
3572 }
3573 
releaseCommandBuffers()3574 void SecondaryCommandBufferCollector::releaseCommandBuffers()
3575 {
3576     // Note: we currently free the command buffers individually, but we could potentially reset the
3577     // entire command pool.  https://issuetracker.google.com/issues/166793850
3578     for (VulkanSecondaryCommandBuffer &commandBuffer : mCollectedCommandBuffers)
3579     {
3580         commandBuffer.destroy();
3581     }
3582     mCollectedCommandBuffers.clear();
3583 }
3584 
3585 // DynamicBuffer implementation.
DynamicBuffer()3586 DynamicBuffer::DynamicBuffer()
3587     : mUsage(0),
3588       mHostVisible(false),
3589       mInitialSize(0),
3590       mNextAllocationOffset(0),
3591       mSize(0),
3592       mSizeInRecentHistory(0),
3593       mAlignment(0),
3594       mMemoryPropertyFlags(0)
3595 {}
3596 
DynamicBuffer(DynamicBuffer && other)3597 DynamicBuffer::DynamicBuffer(DynamicBuffer &&other)
3598     : mUsage(other.mUsage),
3599       mHostVisible(other.mHostVisible),
3600       mInitialSize(other.mInitialSize),
3601       mBuffer(std::move(other.mBuffer)),
3602       mNextAllocationOffset(other.mNextAllocationOffset),
3603       mSize(other.mSize),
3604       mSizeInRecentHistory(other.mSizeInRecentHistory),
3605       mAlignment(other.mAlignment),
3606       mMemoryPropertyFlags(other.mMemoryPropertyFlags),
3607       mInFlightBuffers(std::move(other.mInFlightBuffers)),
3608       mBufferFreeList(std::move(other.mBufferFreeList))
3609 {}
3610 
init(Renderer * renderer,VkBufferUsageFlags usage,size_t alignment,size_t initialSize,bool hostVisible)3611 void DynamicBuffer::init(Renderer *renderer,
3612                          VkBufferUsageFlags usage,
3613                          size_t alignment,
3614                          size_t initialSize,
3615                          bool hostVisible)
3616 {
3617     mUsage       = usage;
3618     mHostVisible = hostVisible;
3619     mMemoryPropertyFlags =
3620         (hostVisible) ? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT : VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
3621 
3622     if (hostVisible && renderer->getFeatures().preferHostCachedForNonStaticBufferUsage.enabled)
3623     {
3624         mMemoryPropertyFlags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
3625     }
3626 
3627     // Check that we haven't overridden the initial size of the buffer in setMinimumSizeForTesting.
3628     if (mInitialSize == 0)
3629     {
3630         mInitialSize         = initialSize;
3631         mSize                = 0;
3632         mSizeInRecentHistory = initialSize;
3633     }
3634 
3635     // Workaround for the mock ICD not supporting allocations greater than 0x1000.
3636     // Could be removed if https://github.com/KhronosGroup/Vulkan-Tools/issues/84 is fixed.
3637     if (renderer->isMockICDEnabled())
3638     {
3639         mSize = std::min<size_t>(mSize, 0x1000);
3640     }
3641 
3642     requireAlignment(renderer, alignment);
3643 }
3644 
~DynamicBuffer()3645 DynamicBuffer::~DynamicBuffer()
3646 {
3647     ASSERT(mBuffer == nullptr);
3648     ASSERT(mInFlightBuffers.empty());
3649     ASSERT(mBufferFreeList.empty());
3650 }
3651 
allocateNewBuffer(Context * context)3652 angle::Result DynamicBuffer::allocateNewBuffer(Context *context)
3653 {
3654     context->getPerfCounters().dynamicBufferAllocations++;
3655 
3656     // Allocate the buffer
3657     ASSERT(!mBuffer);
3658     mBuffer = std::make_unique<BufferHelper>();
3659 
3660     VkBufferCreateInfo createInfo    = {};
3661     createInfo.sType                 = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
3662     createInfo.flags                 = 0;
3663     createInfo.size                  = mSize;
3664     createInfo.usage                 = mUsage;
3665     createInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
3666     createInfo.queueFamilyIndexCount = 0;
3667     createInfo.pQueueFamilyIndices   = nullptr;
3668 
3669     return mBuffer->init(context, createInfo, mMemoryPropertyFlags);
3670 }
3671 
allocateFromCurrentBuffer(size_t sizeInBytes,BufferHelper ** bufferHelperOut)3672 bool DynamicBuffer::allocateFromCurrentBuffer(size_t sizeInBytes, BufferHelper **bufferHelperOut)
3673 {
3674     mNextAllocationOffset =
3675         roundUp<uint32_t>(mNextAllocationOffset, static_cast<uint32_t>(mAlignment));
3676 
3677     ASSERT(bufferHelperOut);
3678     size_t sizeToAllocate                                      = roundUp(sizeInBytes, mAlignment);
3679     angle::base::CheckedNumeric<size_t> checkedNextWriteOffset = mNextAllocationOffset;
3680     checkedNextWriteOffset += sizeToAllocate;
3681 
3682     if (!checkedNextWriteOffset.IsValid() || checkedNextWriteOffset.ValueOrDie() > mSize)
3683     {
3684         return false;
3685     }
3686 
3687     ASSERT(mBuffer != nullptr);
3688     ASSERT(mHostVisible);
3689     ASSERT(mBuffer->getMappedMemory());
3690     mBuffer->setSuballocationOffsetAndSize(mNextAllocationOffset, sizeToAllocate);
3691     *bufferHelperOut = mBuffer.get();
3692 
3693     mNextAllocationOffset += static_cast<uint32_t>(sizeToAllocate);
3694     return true;
3695 }
3696 
allocate(Context * context,size_t sizeInBytes,BufferHelper ** bufferHelperOut,bool * newBufferAllocatedOut)3697 angle::Result DynamicBuffer::allocate(Context *context,
3698                                       size_t sizeInBytes,
3699                                       BufferHelper **bufferHelperOut,
3700                                       bool *newBufferAllocatedOut)
3701 {
3702     bool newBuffer = !allocateFromCurrentBuffer(sizeInBytes, bufferHelperOut);
3703     if (newBufferAllocatedOut)
3704     {
3705         *newBufferAllocatedOut = newBuffer;
3706     }
3707 
3708     if (!newBuffer)
3709     {
3710         return angle::Result::Continue;
3711     }
3712 
3713     size_t sizeToAllocate = roundUp(sizeInBytes, mAlignment);
3714 
3715     if (mBuffer)
3716     {
3717         // Make sure the buffer is not released externally.
3718         ASSERT(mBuffer->valid());
3719         mInFlightBuffers.push_back(std::move(mBuffer));
3720         ASSERT(!mBuffer);
3721     }
3722 
3723     Renderer *renderer = context->getRenderer();
3724 
3725     const size_t minRequiredBlockSize = std::max(mInitialSize, sizeToAllocate);
3726 
3727     // The average required buffer size in recent history is used to determine whether the currently
3728     // used buffer size needs to be reduced (when it goes below 1/8 of the current buffer size).
3729     constexpr uint32_t kDecayCoeffPercent = 20;
3730     static_assert(kDecayCoeffPercent >= 0 && kDecayCoeffPercent <= 100);
3731     mSizeInRecentHistory = (mSizeInRecentHistory * kDecayCoeffPercent +
3732                             minRequiredBlockSize * (100 - kDecayCoeffPercent) + 50) /
3733                            100;
3734 
3735     if (sizeToAllocate > mSize || mSizeInRecentHistory < mSize / 8)
3736     {
3737         mSize = minRequiredBlockSize;
3738         // Clear the free list since the free buffers are now either too small or too big.
3739         ReleaseBufferListToRenderer(renderer, &mBufferFreeList);
3740     }
3741 
3742     // The front of the free list should be the oldest. Thus if it is in use the rest of the
3743     // free list should be in use as well.
3744     if (mBufferFreeList.empty() ||
3745         !renderer->hasResourceUseFinished(mBufferFreeList.front()->getResourceUse()))
3746     {
3747         ANGLE_TRY(allocateNewBuffer(context));
3748     }
3749     else
3750     {
3751         mBuffer = std::move(mBufferFreeList.front());
3752         mBufferFreeList.pop_front();
3753     }
3754 
3755     ASSERT(mBuffer->getBlockMemorySize() == mSize);
3756 
3757     mNextAllocationOffset = 0;
3758 
3759     ASSERT(mBuffer != nullptr);
3760     mBuffer->setSuballocationOffsetAndSize(mNextAllocationOffset, sizeToAllocate);
3761     *bufferHelperOut = mBuffer.get();
3762 
3763     mNextAllocationOffset += static_cast<uint32_t>(sizeToAllocate);
3764     return angle::Result::Continue;
3765 }
3766 
release(Renderer * renderer)3767 void DynamicBuffer::release(Renderer *renderer)
3768 {
3769     reset();
3770 
3771     ReleaseBufferListToRenderer(renderer, &mInFlightBuffers);
3772     ReleaseBufferListToRenderer(renderer, &mBufferFreeList);
3773 
3774     if (mBuffer)
3775     {
3776         mBuffer->release(renderer);
3777         mBuffer.reset(nullptr);
3778     }
3779 }
3780 
updateQueueSerialAndReleaseInFlightBuffers(ContextVk * contextVk,const QueueSerial & queueSerial)3781 void DynamicBuffer::updateQueueSerialAndReleaseInFlightBuffers(ContextVk *contextVk,
3782                                                                const QueueSerial &queueSerial)
3783 {
3784     for (std::unique_ptr<BufferHelper> &bufferHelper : mInFlightBuffers)
3785     {
3786         // This function is used only for internal buffers, and they are all read-only.
3787         // It's possible this may change in the future, but there isn't a good way to detect that,
3788         // unfortunately.
3789         bufferHelper->setQueueSerial(queueSerial);
3790 
3791         // We only keep free buffers that have the same size. Note that bufferHelper's size is
3792         // suballocation's size. We need to use the whole block memory size here.
3793         if (bufferHelper->getBlockMemorySize() != mSize)
3794         {
3795             bufferHelper->release(contextVk->getRenderer());
3796         }
3797         else
3798         {
3799             mBufferFreeList.push_back(std::move(bufferHelper));
3800         }
3801     }
3802     mInFlightBuffers.clear();
3803 }
3804 
destroy(Renderer * renderer)3805 void DynamicBuffer::destroy(Renderer *renderer)
3806 {
3807     reset();
3808 
3809     DestroyBufferList(renderer, &mInFlightBuffers);
3810     DestroyBufferList(renderer, &mBufferFreeList);
3811 
3812     if (mBuffer)
3813     {
3814         mBuffer->unmap(renderer);
3815         mBuffer->destroy(renderer);
3816         mBuffer.reset(nullptr);
3817     }
3818 }
3819 
requireAlignment(Renderer * renderer,size_t alignment)3820 void DynamicBuffer::requireAlignment(Renderer *renderer, size_t alignment)
3821 {
3822     ASSERT(alignment > 0);
3823 
3824     size_t prevAlignment = mAlignment;
3825 
3826     // If alignment was never set, initialize it with the atom size limit.
3827     if (prevAlignment == 0)
3828     {
3829         prevAlignment =
3830             static_cast<size_t>(renderer->getPhysicalDeviceProperties().limits.nonCoherentAtomSize);
3831         ASSERT(gl::isPow2(prevAlignment));
3832     }
3833 
3834     // We need lcm(prevAlignment, alignment).  Usually, one divides the other so std::max() could be
3835     // used instead.  Only known case where this assumption breaks is for 3-component types with
3836     // 16- or 32-bit channels, so that's special-cased to avoid a full-fledged lcm implementation.
3837 
3838     if (gl::isPow2(prevAlignment * alignment))
3839     {
3840         ASSERT(alignment % prevAlignment == 0 || prevAlignment % alignment == 0);
3841 
3842         alignment = std::max(prevAlignment, alignment);
3843     }
3844     else
3845     {
3846         ASSERT(prevAlignment % 3 != 0 || gl::isPow2(prevAlignment / 3));
3847         ASSERT(alignment % 3 != 0 || gl::isPow2(alignment / 3));
3848 
3849         prevAlignment = prevAlignment % 3 == 0 ? prevAlignment / 3 : prevAlignment;
3850         alignment     = alignment % 3 == 0 ? alignment / 3 : alignment;
3851 
3852         alignment = std::max(prevAlignment, alignment) * 3;
3853     }
3854 
3855     // If alignment has changed, make sure the next allocation is done at an aligned offset.
3856     if (alignment != mAlignment)
3857     {
3858         mNextAllocationOffset = roundUp(mNextAllocationOffset, static_cast<uint32_t>(alignment));
3859     }
3860 
3861     mAlignment = alignment;
3862 }
3863 
setMinimumSizeForTesting(size_t minSize)3864 void DynamicBuffer::setMinimumSizeForTesting(size_t minSize)
3865 {
3866     // This will really only have an effect next time we call allocate.
3867     mInitialSize = minSize;
3868 
3869     // Forces a new allocation on the next allocate.
3870     mSize                = 0;
3871     mSizeInRecentHistory = 0;
3872 }
3873 
reset()3874 void DynamicBuffer::reset()
3875 {
3876     mSize                 = 0;
3877     mSizeInRecentHistory  = 0;
3878     mNextAllocationOffset = 0;
3879 }
3880 
3881 // BufferPool implementation.
BufferPool()3882 BufferPool::BufferPool()
3883     : mVirtualBlockCreateFlags(vma::VirtualBlockCreateFlagBits::GENERAL),
3884       mUsage(0),
3885       mHostVisible(false),
3886       mSize(0),
3887       mMemoryTypeIndex(0),
3888       mTotalMemorySize(0),
3889       mNumberOfNewBuffersNeededSinceLastPrune(0)
3890 {}
3891 
BufferPool(BufferPool && other)3892 BufferPool::BufferPool(BufferPool &&other)
3893     : mVirtualBlockCreateFlags(other.mVirtualBlockCreateFlags),
3894       mUsage(other.mUsage),
3895       mHostVisible(other.mHostVisible),
3896       mSize(other.mSize),
3897       mMemoryTypeIndex(other.mMemoryTypeIndex)
3898 {}
3899 
initWithFlags(Renderer * renderer,vma::VirtualBlockCreateFlags flags,VkBufferUsageFlags usage,VkDeviceSize initialSize,uint32_t memoryTypeIndex,VkMemoryPropertyFlags memoryPropertyFlags)3900 void BufferPool::initWithFlags(Renderer *renderer,
3901                                vma::VirtualBlockCreateFlags flags,
3902                                VkBufferUsageFlags usage,
3903                                VkDeviceSize initialSize,
3904                                uint32_t memoryTypeIndex,
3905                                VkMemoryPropertyFlags memoryPropertyFlags)
3906 {
3907     mVirtualBlockCreateFlags = flags;
3908     mUsage                   = usage;
3909     mMemoryTypeIndex         = memoryTypeIndex;
3910     if (initialSize)
3911     {
3912         // Should be power of two
3913         ASSERT(gl::isPow2(initialSize));
3914         mSize = initialSize;
3915     }
3916     else
3917     {
3918         mSize = renderer->getPreferedBufferBlockSize(memoryTypeIndex);
3919     }
3920     mHostVisible = ((memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0);
3921 }
3922 
~BufferPool()3923 BufferPool::~BufferPool()
3924 {
3925     ASSERT(mBufferBlocks.empty());
3926     ASSERT(mEmptyBufferBlocks.empty());
3927 }
3928 
pruneEmptyBuffers(Renderer * renderer)3929 void BufferPool::pruneEmptyBuffers(Renderer *renderer)
3930 {
3931     // First try to walk through mBuffers and move empty buffers to mEmptyBuffer and remove null
3932     // pointers for allocation performance.
3933     // The expectation is that we will find none needs to be compacted in most calls.
3934     bool needsCompact = false;
3935     for (std::unique_ptr<BufferBlock> &block : mBufferBlocks)
3936     {
3937         if (block->isEmpty())
3938         {
3939             // We will always free empty buffers that has smaller size. Or if the empty buffer has
3940             // been found empty for long enough time, or we accumulated too many empty buffers, we
3941             // also free it.
3942             if (block->getMemorySize() < mSize)
3943             {
3944                 mTotalMemorySize -= block->getMemorySize();
3945                 block->destroy(renderer);
3946                 block.reset();
3947             }
3948             else
3949             {
3950                 mEmptyBufferBlocks.push_back(std::move(block));
3951             }
3952             needsCompact = true;
3953         }
3954     }
3955 
3956     // Now remove the null pointers that left by empty buffers all at once, if any.
3957     if (needsCompact)
3958     {
3959         BufferBlockPointerVector compactedBlocks;
3960         for (std::unique_ptr<BufferBlock> &block : mBufferBlocks)
3961         {
3962             if (block)
3963             {
3964                 compactedBlocks.push_back(std::move(block));
3965             }
3966         }
3967         mBufferBlocks = std::move(compactedBlocks);
3968     }
3969 
3970     // Decide how many empty buffers to keep around and trim down the excessive empty buffers. We
3971     // keep track of how many buffers are needed since last prune. Assume we are in stable state,
3972     // which means we may still need that many empty buffers in next prune cycle. To reduce chance
3973     // to call into vulkan driver to allocate new buffers, we try to keep that many empty buffers
3974     // around, subject to the maximum cap. If we overestimate, next cycle they used fewer buffers,
3975     // we will trim excessive empty buffers at next prune call. Or if we underestimate, we will end
3976     // up have to call into vulkan driver allocate new buffers, but next cycle we should correct
3977     // ourselves to keep enough number of empty buffers around.
3978     size_t buffersToKeep = std::min(mNumberOfNewBuffersNeededSinceLastPrune,
3979                                     static_cast<size_t>(kMaxTotalEmptyBufferBytes / mSize));
3980     while (mEmptyBufferBlocks.size() > buffersToKeep)
3981     {
3982         std::unique_ptr<BufferBlock> &block = mEmptyBufferBlocks.back();
3983         mTotalMemorySize -= block->getMemorySize();
3984         block->destroy(renderer);
3985         mEmptyBufferBlocks.pop_back();
3986     }
3987     mNumberOfNewBuffersNeededSinceLastPrune = 0;
3988 }
3989 
allocateNewBuffer(Context * context,VkDeviceSize sizeInBytes)3990 VkResult BufferPool::allocateNewBuffer(Context *context, VkDeviceSize sizeInBytes)
3991 {
3992     Renderer *renderer         = context->getRenderer();
3993     const Allocator &allocator = renderer->getAllocator();
3994 
3995     VkDeviceSize heapSize =
3996         renderer->getMemoryProperties().getHeapSizeForMemoryType(mMemoryTypeIndex);
3997 
3998     // First ensure we are not exceeding the heapSize to avoid the validation error.
3999     VK_RESULT_CHECK(sizeInBytes <= heapSize, VK_ERROR_OUT_OF_DEVICE_MEMORY);
4000 
4001     // Double the size until meet the requirement. This also helps reducing the fragmentation. Since
4002     // this is global pool, we have less worry about memory waste.
4003     VkDeviceSize newSize = mSize;
4004     while (newSize < sizeInBytes)
4005     {
4006         newSize <<= 1;
4007     }
4008     mSize = std::min(newSize, heapSize);
4009 
4010     // Allocate buffer
4011     VkBufferCreateInfo createInfo    = {};
4012     createInfo.sType                 = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4013     createInfo.flags                 = 0;
4014     createInfo.size                  = mSize;
4015     createInfo.usage                 = mUsage;
4016     createInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
4017     createInfo.queueFamilyIndexCount = 0;
4018     createInfo.pQueueFamilyIndices   = nullptr;
4019 
4020     VkMemoryPropertyFlags memoryPropertyFlags;
4021     allocator.getMemoryTypeProperties(mMemoryTypeIndex, &memoryPropertyFlags);
4022 
4023     DeviceScoped<Buffer> buffer(renderer->getDevice());
4024     VK_RESULT_TRY(buffer.get().init(context->getDevice(), createInfo));
4025 
4026     DeviceScoped<DeviceMemory> deviceMemory(renderer->getDevice());
4027     VkMemoryPropertyFlags memoryPropertyFlagsOut;
4028     VkDeviceSize sizeOut;
4029     uint32_t memoryTypeIndex;
4030     VK_RESULT_TRY(AllocateBufferMemory(context, MemoryAllocationType::Buffer, memoryPropertyFlags,
4031                                        &memoryPropertyFlagsOut, nullptr, &buffer.get(),
4032                                        &memoryTypeIndex, &deviceMemory.get(), &sizeOut));
4033     ASSERT(sizeOut >= mSize);
4034 
4035     // Allocate bufferBlock
4036     std::unique_ptr<BufferBlock> block = std::make_unique<BufferBlock>();
4037     VK_RESULT_TRY(block->init(context, buffer.get(), memoryTypeIndex, mVirtualBlockCreateFlags,
4038                               deviceMemory.get(), memoryPropertyFlagsOut, mSize));
4039 
4040     if (mHostVisible)
4041     {
4042         VK_RESULT_TRY(block->map(context->getDevice()));
4043     }
4044 
4045     mTotalMemorySize += block->getMemorySize();
4046     // Append the bufferBlock into the pool
4047     mBufferBlocks.push_back(std::move(block));
4048     context->getPerfCounters().allocateNewBufferBlockCalls++;
4049 
4050     return VK_SUCCESS;
4051 }
4052 
allocateBuffer(Context * context,VkDeviceSize sizeInBytes,VkDeviceSize alignment,BufferSuballocation * suballocation)4053 VkResult BufferPool::allocateBuffer(Context *context,
4054                                     VkDeviceSize sizeInBytes,
4055                                     VkDeviceSize alignment,
4056                                     BufferSuballocation *suballocation)
4057 {
4058     ASSERT(alignment);
4059     VmaVirtualAllocation allocation;
4060     VkDeviceSize offset;
4061     VkDeviceSize alignedSize = roundUp(sizeInBytes, alignment);
4062 
4063     if (alignedSize >= kMaxBufferSizeForSuballocation)
4064     {
4065         VkDeviceSize heapSize =
4066             context->getRenderer()->getMemoryProperties().getHeapSizeForMemoryType(
4067                 mMemoryTypeIndex);
4068         // First ensure we are not exceeding the heapSize to avoid the validation error.
4069         VK_RESULT_CHECK(sizeInBytes <= heapSize, VK_ERROR_OUT_OF_DEVICE_MEMORY);
4070 
4071         // Allocate buffer
4072         VkBufferCreateInfo createInfo    = {};
4073         createInfo.sType                 = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4074         createInfo.flags                 = 0;
4075         createInfo.size                  = alignedSize;
4076         createInfo.usage                 = mUsage;
4077         createInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
4078         createInfo.queueFamilyIndexCount = 0;
4079         createInfo.pQueueFamilyIndices   = nullptr;
4080 
4081         VkMemoryPropertyFlags memoryPropertyFlags;
4082         const Allocator &allocator = context->getRenderer()->getAllocator();
4083         allocator.getMemoryTypeProperties(mMemoryTypeIndex, &memoryPropertyFlags);
4084 
4085         DeviceScoped<Buffer> buffer(context->getDevice());
4086         VK_RESULT_TRY(buffer.get().init(context->getDevice(), createInfo));
4087 
4088         DeviceScoped<DeviceMemory> deviceMemory(context->getDevice());
4089         VkMemoryPropertyFlags memoryPropertyFlagsOut;
4090         VkDeviceSize sizeOut;
4091         uint32_t memoryTypeIndex;
4092         VK_RESULT_TRY(AllocateBufferMemory(
4093             context, MemoryAllocationType::Buffer, memoryPropertyFlags, &memoryPropertyFlagsOut,
4094             nullptr, &buffer.get(), &memoryTypeIndex, &deviceMemory.get(), &sizeOut));
4095         ASSERT(sizeOut >= alignedSize);
4096 
4097         suballocation->initWithEntireBuffer(context, buffer.get(), MemoryAllocationType::Buffer,
4098                                             memoryTypeIndex, deviceMemory.get(),
4099                                             memoryPropertyFlagsOut, alignedSize, sizeOut);
4100         if (mHostVisible)
4101         {
4102             VK_RESULT_TRY(suballocation->map(context));
4103         }
4104         return VK_SUCCESS;
4105     }
4106 
4107     // We always allocate from reverse order so that older buffers have a chance to be empty. The
4108     // assumption is that to allocate from new buffers first may have a better chance to leave the
4109     // older buffers completely empty and we may able to free it.
4110     for (auto iter = mBufferBlocks.rbegin(); iter != mBufferBlocks.rend();)
4111     {
4112         std::unique_ptr<BufferBlock> &block = *iter;
4113         if (block->isEmpty() && block->getMemorySize() < mSize)
4114         {
4115             // Don't try to allocate from an empty buffer that has smaller size. It will get
4116             // released when pruneEmptyBuffers get called later on.
4117             ++iter;
4118             continue;
4119         }
4120 
4121         if (block->allocate(alignedSize, alignment, &allocation, &offset) == VK_SUCCESS)
4122         {
4123             suballocation->init(block.get(), allocation, offset, alignedSize);
4124             return VK_SUCCESS;
4125         }
4126         ++iter;
4127     }
4128 
4129     // Try to allocate from empty buffers
4130     while (!mEmptyBufferBlocks.empty())
4131     {
4132         std::unique_ptr<BufferBlock> &block = mEmptyBufferBlocks.back();
4133         if (block->getMemorySize() < mSize)
4134         {
4135             mTotalMemorySize -= block->getMemorySize();
4136             block->destroy(context->getRenderer());
4137             mEmptyBufferBlocks.pop_back();
4138         }
4139         else
4140         {
4141             VK_RESULT_TRY(block->allocate(alignedSize, alignment, &allocation, &offset));
4142             suballocation->init(block.get(), allocation, offset, alignedSize);
4143             mBufferBlocks.push_back(std::move(block));
4144             mEmptyBufferBlocks.pop_back();
4145             mNumberOfNewBuffersNeededSinceLastPrune++;
4146             return VK_SUCCESS;
4147         }
4148     }
4149 
4150     // Failed to allocate from empty buffer. Now try to allocate a new buffer.
4151     VK_RESULT_TRY(allocateNewBuffer(context, alignedSize));
4152 
4153     // Sub-allocate from the bufferBlock.
4154     std::unique_ptr<BufferBlock> &block = mBufferBlocks.back();
4155     VK_RESULT_CHECK(block->allocate(alignedSize, alignment, &allocation, &offset) == VK_SUCCESS,
4156                     VK_ERROR_OUT_OF_DEVICE_MEMORY);
4157     suballocation->init(block.get(), allocation, offset, alignedSize);
4158     mNumberOfNewBuffersNeededSinceLastPrune++;
4159 
4160     return VK_SUCCESS;
4161 }
4162 
destroy(Renderer * renderer,bool orphanNonEmptyBufferBlock)4163 void BufferPool::destroy(Renderer *renderer, bool orphanNonEmptyBufferBlock)
4164 {
4165     for (std::unique_ptr<BufferBlock> &block : mBufferBlocks)
4166     {
4167         if (block->isEmpty())
4168         {
4169             block->destroy(renderer);
4170         }
4171         else
4172         {
4173             // When orphan is not allowed, all BufferBlocks must be empty.
4174             ASSERT(orphanNonEmptyBufferBlock);
4175             renderer->addBufferBlockToOrphanList(block.release());
4176         }
4177     }
4178     mBufferBlocks.clear();
4179 
4180     for (std::unique_ptr<BufferBlock> &block : mEmptyBufferBlocks)
4181     {
4182         block->destroy(renderer);
4183     }
4184     mEmptyBufferBlocks.clear();
4185 }
4186 
getTotalEmptyMemorySize() const4187 VkDeviceSize BufferPool::getTotalEmptyMemorySize() const
4188 {
4189     VkDeviceSize totalMemorySize = 0;
4190     for (const std::unique_ptr<BufferBlock> &block : mEmptyBufferBlocks)
4191     {
4192         totalMemorySize += block->getMemorySize();
4193     }
4194     return totalMemorySize;
4195 }
4196 
addStats(std::ostringstream * out) const4197 void BufferPool::addStats(std::ostringstream *out) const
4198 {
4199     VkDeviceSize totalUnusedBytes = 0;
4200     VkDeviceSize totalMemorySize  = 0;
4201     for (size_t i = 0; i < mBufferBlocks.size(); i++)
4202     {
4203         const std::unique_ptr<BufferBlock> &block = mBufferBlocks[i];
4204         vma::StatInfo statInfo;
4205         block->calculateStats(&statInfo);
4206         ASSERT(statInfo.basicInfo.blockCount == 1);
4207         INFO() << "[" << i << "]={" << " allocationCount:" << statInfo.basicInfo.allocationCount
4208                << " blockBytes:" << statInfo.basicInfo.blockBytes
4209                << " allocationBytes:" << statInfo.basicInfo.allocationBytes
4210                << " unusedRangeCount:" << statInfo.unusedRangeCount
4211                << " allocationSizeMin:" << statInfo.allocationSizeMin
4212                << " allocationSizeMax:" << statInfo.allocationSizeMax
4213                << " unusedRangeSizeMin:" << statInfo.unusedRangeSizeMin
4214                << " unusedRangeSizeMax:" << statInfo.unusedRangeSizeMax << " }";
4215         VkDeviceSize unusedBytes =
4216             statInfo.basicInfo.blockBytes - statInfo.basicInfo.allocationBytes;
4217         totalUnusedBytes += unusedBytes;
4218         totalMemorySize += block->getMemorySize();
4219     }
4220     *out << "mBufferBlocks.size():" << mBufferBlocks.size()
4221          << " totalUnusedBytes:" << totalUnusedBytes / 1024
4222          << "KB / totalMemorySize:" << totalMemorySize / 1024 << "KB";
4223     *out << " emptyBuffers [memorySize:" << getTotalEmptyMemorySize() / 1024 << "KB "
4224          << " count:" << mEmptyBufferBlocks.size()
4225          << " needed: " << mNumberOfNewBuffersNeededSinceLastPrune << "]";
4226 }
4227 
4228 // DescriptorSetHelper implementation.
destroy(VkDevice device)4229 void DescriptorSetHelper::destroy(VkDevice device)
4230 {
4231     if (valid())
4232     {
4233         // Since the pool is created without VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, we
4234         // don't call vkFreeDescriptorSets. We always add to garbage list so that it can be
4235         // recycled. Since we dont actually know if it is GPU completed, we always just add to the
4236         // pending garbage list assuming the worst case.
4237         DescriptorPoolPointer pool(device, mPool);
4238         DescriptorSetPointer garbage(device, std::move(*this));
4239         pool->addPendingGarbage(std::move(garbage));
4240         ASSERT(!valid());
4241     }
4242 }
4243 
4244 // DescriptorPoolHelper implementation.
DescriptorPoolHelper()4245 DescriptorPoolHelper::DescriptorPoolHelper()
4246     : mMaxDescriptorSets(0), mValidDescriptorSets(0), mFreeDescriptorSets(0)
4247 {}
4248 
~DescriptorPoolHelper()4249 DescriptorPoolHelper::~DescriptorPoolHelper()
4250 {
4251     ASSERT(mPendingGarbageList.empty());
4252     ASSERT(mFinishedGarbageList.empty());
4253 }
4254 
init(Context * context,const std::vector<VkDescriptorPoolSize> & poolSizesIn,uint32_t maxSets)4255 angle::Result DescriptorPoolHelper::init(Context *context,
4256                                          const std::vector<VkDescriptorPoolSize> &poolSizesIn,
4257                                          uint32_t maxSets)
4258 {
4259     Renderer *renderer = context->getRenderer();
4260 
4261     ASSERT(mPendingGarbageList.empty());
4262     ASSERT(mFinishedGarbageList.empty());
4263 
4264     if (mDescriptorPool.valid())
4265     {
4266         mDescriptorPool.destroy(renderer->getDevice());
4267     }
4268 
4269     // Make a copy of the pool sizes, so we can grow them to satisfy the specified maxSets.
4270     std::vector<VkDescriptorPoolSize> poolSizes = poolSizesIn;
4271 
4272     for (VkDescriptorPoolSize &poolSize : poolSizes)
4273     {
4274         poolSize.descriptorCount *= maxSets;
4275     }
4276 
4277     VkDescriptorPoolCreateInfo descriptorPoolInfo = {};
4278     descriptorPoolInfo.sType                      = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
4279     descriptorPoolInfo.flags                      = 0;
4280     descriptorPoolInfo.maxSets                    = maxSets;
4281     descriptorPoolInfo.poolSizeCount              = static_cast<uint32_t>(poolSizes.size());
4282     descriptorPoolInfo.pPoolSizes                 = poolSizes.data();
4283 
4284     mMaxDescriptorSets   = maxSets;
4285     mFreeDescriptorSets  = maxSets;
4286     mValidDescriptorSets = 0;
4287 
4288     ANGLE_VK_TRY(context, mDescriptorPool.init(renderer->getDevice(), descriptorPoolInfo));
4289 
4290     mRenderer = renderer;
4291 
4292     return angle::Result::Continue;
4293 }
4294 
destroy(VkDevice device)4295 void DescriptorPoolHelper::destroy(VkDevice device)
4296 {
4297     ASSERT(mValidDescriptorSets == 0);
4298     ASSERT(mPendingGarbageList.empty());
4299     ASSERT(mFinishedGarbageList.empty());
4300     mDescriptorPool.destroy(device);
4301 }
4302 
allocateVkDescriptorSet(Context * context,const DescriptorSetLayout & descriptorSetLayout,VkDescriptorSet * descriptorSetOut)4303 bool DescriptorPoolHelper::allocateVkDescriptorSet(Context *context,
4304                                                    const DescriptorSetLayout &descriptorSetLayout,
4305                                                    VkDescriptorSet *descriptorSetOut)
4306 {
4307     if (mFreeDescriptorSets > 0)
4308     {
4309         VkDescriptorSetAllocateInfo allocInfo = {};
4310         allocInfo.sType                       = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
4311         allocInfo.descriptorPool              = mDescriptorPool.getHandle();
4312         allocInfo.descriptorSetCount          = 1;
4313         allocInfo.pSetLayouts                 = descriptorSetLayout.ptr();
4314 
4315         VkResult result = mDescriptorPool.allocateDescriptorSets(context->getDevice(), allocInfo,
4316                                                                  descriptorSetOut);
4317         ++context->getPerfCounters().descriptorSetAllocations;
4318         // If fail, it means our own accounting has a bug.
4319         ASSERT(result == VK_SUCCESS);
4320         mFreeDescriptorSets--;
4321         mValidDescriptorSets++;
4322         return true;
4323     }
4324 
4325     return false;
4326 }
4327 
cleanupPendingGarbage()4328 void DescriptorPoolHelper::cleanupPendingGarbage()
4329 {
4330     while (!mPendingGarbageList.empty())
4331     {
4332         DescriptorSetPointer &garbage = mPendingGarbageList.front();
4333         if (!mRenderer->hasResourceUseFinished(garbage->getResourceUse()))
4334         {
4335             break;
4336         }
4337         mFinishedGarbageList.push_back(std::move(garbage));
4338         mPendingGarbageList.pop_front();
4339     }
4340 }
4341 
recycleFromGarbage(Renderer * renderer,DescriptorSetPointer * descriptorSetOut)4342 bool DescriptorPoolHelper::recycleFromGarbage(Renderer *renderer,
4343                                               DescriptorSetPointer *descriptorSetOut)
4344 {
4345     if (mFinishedGarbageList.empty())
4346     {
4347         cleanupPendingGarbage();
4348     }
4349 
4350     if (!mFinishedGarbageList.empty())
4351     {
4352         DescriptorSetPointer &garbage = mFinishedGarbageList.front();
4353         *descriptorSetOut             = std::move(garbage);
4354         mFinishedGarbageList.pop_front();
4355         mValidDescriptorSets++;
4356         return true;
4357     }
4358 
4359     return false;
4360 }
4361 
allocateDescriptorSet(Context * context,const DescriptorSetLayout & descriptorSetLayout,const DescriptorPoolPointer & pool,DescriptorSetPointer * descriptorSetOut)4362 bool DescriptorPoolHelper::allocateDescriptorSet(Context *context,
4363                                                  const DescriptorSetLayout &descriptorSetLayout,
4364                                                  const DescriptorPoolPointer &pool,
4365                                                  DescriptorSetPointer *descriptorSetOut)
4366 {
4367     ASSERT(pool.get() == this);
4368     VkDescriptorSet descriptorSet;
4369     if (allocateVkDescriptorSet(context, descriptorSetLayout, &descriptorSet))
4370     {
4371         DescriptorSetHelper helper = DescriptorSetHelper(descriptorSet, pool);
4372         *descriptorSetOut          = DescriptorSetPointer(context->getDevice(), std::move(helper));
4373         return true;
4374     }
4375     return false;
4376 }
4377 
destroyGarbage()4378 void DescriptorPoolHelper::destroyGarbage()
4379 {
4380     ASSERT(mPendingGarbageList.empty());
4381 
4382     while (!mFinishedGarbageList.empty())
4383     {
4384         DescriptorSetPointer &garbage = mFinishedGarbageList.front();
4385         ASSERT(garbage.unique());
4386         ASSERT(garbage->valid());
4387         // Because we do not use VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT when pool is
4388         // created, We can't free each individual descriptor set before destroying the pool, we
4389         // simply clear the descriptorSet and the mPool weak pointer so that
4390         // DescriptorSetHelper::destroy will not find it the garbage being valid  and try to add to
4391         // garbage list again.
4392         garbage->mDescriptorSet = VK_NULL_HANDLE;
4393         garbage->mPool.reset();
4394         ASSERT(!garbage->valid());
4395         mFinishedGarbageList.pop_front();
4396     }
4397 }
4398 
4399 // DynamicDescriptorPool implementation.
DynamicDescriptorPool()4400 DynamicDescriptorPool::DynamicDescriptorPool() : mCachedDescriptorSetLayout(VK_NULL_HANDLE) {}
4401 
~DynamicDescriptorPool()4402 DynamicDescriptorPool::~DynamicDescriptorPool()
4403 {
4404     ASSERT(mLRUList.empty());
4405     ASSERT(mDescriptorSetCache.empty());
4406     ASSERT(mDescriptorPools.empty());
4407 }
4408 
DynamicDescriptorPool(DynamicDescriptorPool && other)4409 DynamicDescriptorPool::DynamicDescriptorPool(DynamicDescriptorPool &&other)
4410     : DynamicDescriptorPool()
4411 {
4412     *this = std::move(other);
4413 }
4414 
operator =(DynamicDescriptorPool && other)4415 DynamicDescriptorPool &DynamicDescriptorPool::operator=(DynamicDescriptorPool &&other)
4416 {
4417     std::swap(mDescriptorPools, other.mDescriptorPools);
4418     std::swap(mPoolSizes, other.mPoolSizes);
4419     std::swap(mCachedDescriptorSetLayout, other.mCachedDescriptorSetLayout);
4420     std::swap(mLRUList, other.mLRUList);
4421     std::swap(mDescriptorSetCache, other.mDescriptorSetCache);
4422     return *this;
4423 }
4424 
init(Context * context,const VkDescriptorPoolSize * setSizes,size_t setSizeCount,const DescriptorSetLayout & descriptorSetLayout)4425 angle::Result DynamicDescriptorPool::init(Context *context,
4426                                           const VkDescriptorPoolSize *setSizes,
4427                                           size_t setSizeCount,
4428                                           const DescriptorSetLayout &descriptorSetLayout)
4429 {
4430     ASSERT(setSizes);
4431     ASSERT(setSizeCount);
4432     ASSERT(mDescriptorPools.empty());
4433     ASSERT(mCachedDescriptorSetLayout == VK_NULL_HANDLE);
4434 
4435     mPoolSizes.assign(setSizes, setSizes + setSizeCount);
4436     mCachedDescriptorSetLayout = descriptorSetLayout.getHandle();
4437 
4438     DescriptorPoolPointer newPool = DescriptorPoolPointer::MakeShared(context->getDevice());
4439     ANGLE_TRY(newPool->init(context, mPoolSizes, mMaxSetsPerPool));
4440 
4441     mDescriptorPools.emplace_back(std::move(newPool));
4442 
4443     return angle::Result::Continue;
4444 }
4445 
destroy(VkDevice device)4446 void DynamicDescriptorPool::destroy(VkDevice device)
4447 {
4448     // Destroy cache
4449     mDescriptorSetCache.clear();
4450 
4451     // Destroy LRU list and SharedDescriptorSetCacheKey.
4452     for (auto it = mLRUList.begin(); it != mLRUList.end();)
4453     {
4454         (it->sharedCacheKey)->destroy(device);
4455         it = mLRUList.erase(it);
4456     }
4457     ASSERT(mLRUList.empty());
4458 
4459     for (DescriptorPoolPointer &pool : mDescriptorPools)
4460     {
4461         pool->cleanupPendingGarbage();
4462         pool->destroyGarbage();
4463         ASSERT(pool.unique());
4464     }
4465     mDescriptorPools.clear();
4466 
4467     mCachedDescriptorSetLayout = VK_NULL_HANDLE;
4468 }
4469 
allocateFromExistingPool(Context * context,const DescriptorSetLayout & descriptorSetLayout,DescriptorSetPointer * descriptorSetOut)4470 bool DynamicDescriptorPool::allocateFromExistingPool(Context *context,
4471                                                      const DescriptorSetLayout &descriptorSetLayout,
4472                                                      DescriptorSetPointer *descriptorSetOut)
4473 {
4474     for (size_t poolIndex = 0; poolIndex < mDescriptorPools.size(); ++poolIndex)
4475     {
4476         DescriptorPoolPointer &pool = mDescriptorPools[poolIndex];
4477         if (!pool || !pool->valid())
4478         {
4479             continue;
4480         }
4481         if (pool->allocateDescriptorSet(context, descriptorSetLayout, pool, descriptorSetOut))
4482         {
4483             return true;
4484         }
4485     }
4486     return false;
4487 }
4488 
recycleFromGarbage(Renderer * renderer,DescriptorSetPointer * descriptorSetOut)4489 bool DynamicDescriptorPool::recycleFromGarbage(Renderer *renderer,
4490                                                DescriptorSetPointer *descriptorSetOut)
4491 {
4492     for (DescriptorPoolPointer &pool : mDescriptorPools)
4493     {
4494         if (pool->recycleFromGarbage(renderer, descriptorSetOut))
4495         {
4496             return true;
4497         }
4498     }
4499     return false;
4500 }
4501 
evictStaleDescriptorSets(Renderer * renderer,uint32_t oldestFrameToKeep,uint32_t currentFrame)4502 bool DynamicDescriptorPool::evictStaleDescriptorSets(Renderer *renderer,
4503                                                      uint32_t oldestFrameToKeep,
4504                                                      uint32_t currentFrame)
4505 {
4506     ASSERT(oldestFrameToKeep < currentFrame);
4507     size_t descriptorSetEvicted = 0;
4508     // Walk LRU list backwards from oldest to most recent, evict anything that earlier than
4509     // oldestFrameIDToKeep.
4510     auto it = mLRUList.rbegin();
4511     while (it != mLRUList.rend())
4512     {
4513         DescriptorSetPointer &descriptorSet = it->descriptorSet;
4514         if (descriptorSet.unique())
4515         {
4516             // Stop if it is recently being used.
4517             if (descriptorSet->getLastUsedFrame() > oldestFrameToKeep)
4518             {
4519                 break;
4520             }
4521             // Stop if GPU is still busy
4522             if (!renderer->hasResourceUseFinished(descriptorSet->getResourceUse()))
4523             {
4524                 break;
4525             }
4526             // Evict it from the cache and remove it from LRU list.
4527             bool removed = mDescriptorSetCache.eraseDescriptorSet(it->sharedCacheKey->getDesc());
4528             ASSERT(removed);
4529 
4530             // Note that erase it from LRU list will "destroy" descriptorSet. Since we
4531             // never actually destroy descriptorSet, it will just add to the garbage list. Here we
4532             // want more explicit control to add it to the front of list (because we know it is
4533             // already GPU completed) instead to the end of the list, so we do it explicitly.
4534             DescriptorPoolWeakPointer pool = descriptorSet->getPool();
4535             pool->addFinishedGarbage(std::move(descriptorSet));
4536             descriptorSetEvicted++;
4537 
4538             // This should destroy descriptorSet, which is already invalid;
4539             it = decltype(it)(mLRUList.erase(std::next(it).base()));
4540             mCacheStats.decrementSize();
4541         }
4542         else
4543         {
4544             // It means it is still bound to one of the programs. Move it to the front of the LRU
4545             // list to avoid repeatedly hitting it for every eviction.
4546             mLRUList.splice(mLRUList.begin(), mLRUList, std::next(it).base());
4547             ++it;
4548             // Update to currentFrame to maintain LRU order
4549             descriptorSet->updateLastUsedFrame(currentFrame);
4550         }
4551     }
4552 
4553     if (descriptorSetEvicted > 0)
4554     {
4555         // If there is any pool that is completely empty, destroy it first so that we can allocate
4556         // from partial pool.
4557         checkAndDestroyUnusedPool(renderer);
4558         return true;
4559     }
4560 
4561     return false;
4562 }
4563 
allocateDescriptorSet(Context * context,const DescriptorSetLayout & descriptorSetLayout,DescriptorSetPointer * descriptorSetOut)4564 angle::Result DynamicDescriptorPool::allocateDescriptorSet(
4565     Context *context,
4566     const DescriptorSetLayout &descriptorSetLayout,
4567     DescriptorSetPointer *descriptorSetOut)
4568 {
4569     ASSERT(!mDescriptorPools.empty());
4570     ASSERT(descriptorSetLayout.getHandle() == mCachedDescriptorSetLayout);
4571 
4572     if (allocateFromExistingPool(context, descriptorSetLayout, descriptorSetOut))
4573     {
4574         return angle::Result::Continue;
4575     }
4576 
4577     if (recycleFromGarbage(context->getRenderer(), descriptorSetOut))
4578     {
4579         return angle::Result::Continue;
4580     }
4581 
4582     // Last, try to allocate a new pool (and/or evict an existing pool)
4583     ANGLE_TRY(allocateNewPool(context));
4584     bool success = allocateFromExistingPool(context, descriptorSetLayout, descriptorSetOut);
4585     // Allocate from a new pool must succeed.
4586     ASSERT(success);
4587 
4588     return angle::Result::Continue;
4589 }
4590 
getOrAllocateDescriptorSet(Context * context,uint32_t currentFrame,const DescriptorSetDesc & desc,const DescriptorSetLayout & descriptorSetLayout,DescriptorSetPointer * descriptorSetOut,SharedDescriptorSetCacheKey * newSharedCacheKeyOut)4591 angle::Result DynamicDescriptorPool::getOrAllocateDescriptorSet(
4592     Context *context,
4593     uint32_t currentFrame,
4594     const DescriptorSetDesc &desc,
4595     const DescriptorSetLayout &descriptorSetLayout,
4596     DescriptorSetPointer *descriptorSetOut,
4597     SharedDescriptorSetCacheKey *newSharedCacheKeyOut)
4598 {
4599     Renderer *renderer = context->getRenderer();
4600     ASSERT(context->getFeatures().descriptorSetCache.enabled);
4601     bool success;
4602 
4603     // First scan the descriptorSet cache.
4604     DescriptorSetLRUListIterator listIterator;
4605     if (mDescriptorSetCache.getDescriptorSet(desc, &listIterator))
4606     {
4607         *descriptorSetOut = listIterator->descriptorSet;
4608         (*newSharedCacheKeyOut).reset();
4609         // Move it to the front of the LRU list.
4610         mLRUList.splice(mLRUList.begin(), mLRUList, listIterator);
4611         mCacheStats.hit();
4612         return angle::Result::Continue;
4613     }
4614 
4615     // Try to allocate from the existing pool (or recycle from grabage list)
4616     success = allocateFromExistingPool(context, descriptorSetLayout, descriptorSetOut);
4617 
4618     // Try to recycle from the garbage list.
4619     if (!success)
4620     {
4621         success = recycleFromGarbage(context->getRenderer(), descriptorSetOut);
4622     }
4623 
4624     // Try to evict oldest descriptorSets that has not being used in last
4625     // kDescriptorSetCacheRetireAge.
4626     if (!success && currentFrame > kDescriptorSetCacheRetireAge)
4627     {
4628         uint32_t oldestFrameToKeep = currentFrame - kDescriptorSetCacheRetireAge;
4629         if (evictStaleDescriptorSets(renderer, oldestFrameToKeep, currentFrame))
4630         {
4631             success = recycleFromGarbage(renderer, descriptorSetOut);
4632         }
4633     }
4634 
4635     // Last, try to allocate a new pool
4636     if (!success)
4637     {
4638         ANGLE_TRY(allocateNewPool(context));
4639         success = allocateFromExistingPool(context, descriptorSetLayout, descriptorSetOut);
4640         // Allocate from a new pool must succeed.
4641         ASSERT(success);
4642     }
4643 
4644     ASSERT(descriptorSetOut->unique());
4645     ASSERT((*descriptorSetOut)->valid());
4646 
4647     // Let pool know there is a shared cache key created and destroys the shared cache key
4648     // when it destroys the pool.
4649     SharedDescriptorSetCacheKey sharedCacheKey = CreateSharedDescriptorSetCacheKey(desc, this);
4650 
4651     // Add to the front of the LRU list and add list iterator to the cache
4652     mLRUList.push_front({sharedCacheKey, *descriptorSetOut});
4653     mDescriptorSetCache.insertDescriptorSet(desc, mLRUList.begin());
4654     mCacheStats.missAndIncrementSize();
4655 
4656     *newSharedCacheKeyOut = sharedCacheKey;
4657     return angle::Result::Continue;
4658 }
4659 
allocateNewPool(Context * context)4660 angle::Result DynamicDescriptorPool::allocateNewPool(Context *context)
4661 {
4662     static constexpr size_t kMaxPools = 99999;
4663     ANGLE_VK_CHECK(context, mDescriptorPools.size() < kMaxPools, VK_ERROR_TOO_MANY_OBJECTS);
4664     // This pool is getting hot, so grow its max size to try and prevent allocating another pool in
4665     // the future.
4666     if (mMaxSetsPerPool < kMaxSetsPerPoolMax)
4667     {
4668         mMaxSetsPerPool *= mMaxSetsPerPoolMultiplier;
4669     }
4670     DescriptorPoolPointer newPool = DescriptorPoolPointer::MakeShared(context->getDevice());
4671     ANGLE_TRY(newPool->init(context, mPoolSizes, mMaxSetsPerPool));
4672     mDescriptorPools.emplace_back(std::move(newPool));
4673 
4674     return angle::Result::Continue;
4675 }
4676 
releaseCachedDescriptorSet(Renderer * renderer,const DescriptorSetDesc & desc)4677 void DynamicDescriptorPool::releaseCachedDescriptorSet(Renderer *renderer,
4678                                                        const DescriptorSetDesc &desc)
4679 {
4680     ASSERT(renderer->getFeatures().descriptorSetCache.enabled);
4681     DescriptorSetLRUListIterator listIter;
4682     // Remove from the cache hash map. Note that we can't delete it until refcount goes to 0
4683     if (mDescriptorSetCache.eraseDescriptorSet(desc, &listIter))
4684     {
4685         DescriptorSetPointer descriptorSet = std::move(listIter->descriptorSet);
4686         mCacheStats.decrementSize();
4687         mLRUList.erase(listIter);
4688 
4689         if (descriptorSet.unique())
4690         {
4691             DescriptorPoolWeakPointer pool = descriptorSet->getPool();
4692             pool->addPendingGarbage(std::move(descriptorSet));
4693         }
4694     }
4695 }
4696 
destroyCachedDescriptorSet(Renderer * renderer,const DescriptorSetDesc & desc)4697 void DynamicDescriptorPool::destroyCachedDescriptorSet(Renderer *renderer,
4698                                                        const DescriptorSetDesc &desc)
4699 {
4700     ASSERT(renderer->getFeatures().descriptorSetCache.enabled);
4701     DescriptorSetLRUListIterator listIter;
4702     // Remove from the cache hash map. Note that we can't delete it until refcount goes to 0
4703     if (mDescriptorSetCache.eraseDescriptorSet(desc, &listIter))
4704     {
4705         DescriptorSetPointer descriptorSet = std::move(listIter->descriptorSet);
4706         mCacheStats.decrementSize();
4707         mLRUList.erase(listIter);
4708 
4709         if (descriptorSet.unique())
4710         {
4711             DescriptorPoolWeakPointer pool = descriptorSet->getPool();
4712             pool->addFinishedGarbage(std::move(descriptorSet));
4713             if (pool->canDestroy())
4714             {
4715                 destroyUnusedPool(renderer, pool);
4716             }
4717         }
4718     }
4719 }
4720 
destroyUnusedPool(Renderer * renderer,const DescriptorPoolWeakPointer & pool)4721 void DynamicDescriptorPool::destroyUnusedPool(Renderer *renderer,
4722                                               const DescriptorPoolWeakPointer &pool)
4723 {
4724     ASSERT(renderer->getFeatures().descriptorSetCache.enabled);
4725     ASSERT(pool->canDestroy());
4726 
4727     // We always keep at least one pool around.
4728     if (mDescriptorPools.size() < 2)
4729     {
4730         return;
4731     }
4732 
4733     // Erase it from the array
4734     for (auto it = mDescriptorPools.begin(); it != mDescriptorPools.end(); ++it)
4735     {
4736         if (pool.owner_equal(*it))
4737         {
4738             ASSERT(pool->valid());
4739             pool->destroyGarbage();
4740             ASSERT((*it).unique());
4741             it = mDescriptorPools.erase(it);
4742             return;
4743         }
4744     }
4745 }
4746 
checkAndDestroyUnusedPool(Renderer * renderer)4747 void DynamicDescriptorPool::checkAndDestroyUnusedPool(Renderer *renderer)
4748 {
4749     ASSERT(renderer->getFeatures().descriptorSetCache.enabled);
4750     for (auto pool : mDescriptorPools)
4751     {
4752         pool->cleanupPendingGarbage();
4753     }
4754 
4755     // We always keep at least one pool around.
4756     if (mDescriptorPools.size() < 2)
4757     {
4758         return;
4759     }
4760 
4761     // Erase it from the array
4762     for (auto it = mDescriptorPools.begin(); it != mDescriptorPools.end();)
4763     {
4764         if ((*it)->canDestroy())
4765         {
4766             (*it)->destroyGarbage();
4767             ASSERT((*it).unique());
4768             it = mDescriptorPools.erase(it);
4769         }
4770         else
4771         {
4772             ++it;
4773         }
4774     }
4775 }
4776 
4777 // For testing only!
GetMaxSetsPerPoolForTesting()4778 uint32_t DynamicDescriptorPool::GetMaxSetsPerPoolForTesting()
4779 {
4780     return mMaxSetsPerPool;
4781 }
4782 
4783 // For testing only!
SetMaxSetsPerPoolForTesting(uint32_t maxSetsPerPool)4784 void DynamicDescriptorPool::SetMaxSetsPerPoolForTesting(uint32_t maxSetsPerPool)
4785 {
4786     mMaxSetsPerPool = maxSetsPerPool;
4787 }
4788 
4789 // For testing only!
GetMaxSetsPerPoolMultiplierForTesting()4790 uint32_t DynamicDescriptorPool::GetMaxSetsPerPoolMultiplierForTesting()
4791 {
4792     return mMaxSetsPerPoolMultiplier;
4793 }
4794 
4795 // For testing only!
SetMaxSetsPerPoolMultiplierForTesting(uint32_t maxSetsPerPoolMultiplier)4796 void DynamicDescriptorPool::SetMaxSetsPerPoolMultiplierForTesting(uint32_t maxSetsPerPoolMultiplier)
4797 {
4798     mMaxSetsPerPoolMultiplier = maxSetsPerPoolMultiplier;
4799 }
4800 
4801 // DynamicallyGrowingPool implementation
4802 template <typename Pool>
DynamicallyGrowingPool()4803 DynamicallyGrowingPool<Pool>::DynamicallyGrowingPool()
4804     : mPoolSize(0), mCurrentPool(0), mCurrentFreeEntry(0)
4805 {}
4806 
4807 template <typename Pool>
4808 DynamicallyGrowingPool<Pool>::~DynamicallyGrowingPool() = default;
4809 
4810 template <typename Pool>
initEntryPool(Context * contextVk,uint32_t poolSize)4811 angle::Result DynamicallyGrowingPool<Pool>::initEntryPool(Context *contextVk, uint32_t poolSize)
4812 {
4813     ASSERT(mPools.empty());
4814     mPoolSize         = poolSize;
4815     mCurrentFreeEntry = poolSize;
4816     return angle::Result::Continue;
4817 }
4818 
4819 template <typename Pool>
destroyEntryPool(VkDevice device)4820 void DynamicallyGrowingPool<Pool>::destroyEntryPool(VkDevice device)
4821 {
4822     for (PoolResource &resource : mPools)
4823     {
4824         destroyPoolImpl(device, resource.pool);
4825     }
4826     mPools.clear();
4827 }
4828 
4829 template <typename Pool>
findFreeEntryPool(ContextVk * contextVk)4830 bool DynamicallyGrowingPool<Pool>::findFreeEntryPool(ContextVk *contextVk)
4831 {
4832     Renderer *renderer = contextVk->getRenderer();
4833     for (size_t poolIndex = 0; poolIndex < mPools.size(); ++poolIndex)
4834     {
4835         PoolResource &pool = mPools[poolIndex];
4836         if (pool.freedCount == mPoolSize && renderer->hasResourceUseFinished(pool.getResourceUse()))
4837         {
4838             mCurrentPool      = poolIndex;
4839             mCurrentFreeEntry = 0;
4840 
4841             pool.freedCount = 0;
4842 
4843             return true;
4844         }
4845     }
4846 
4847     return false;
4848 }
4849 
4850 template <typename Pool>
allocateNewEntryPool(ContextVk * contextVk,Pool && pool)4851 angle::Result DynamicallyGrowingPool<Pool>::allocateNewEntryPool(ContextVk *contextVk, Pool &&pool)
4852 {
4853     mPools.emplace_back(std::move(pool), 0);
4854 
4855     mCurrentPool      = mPools.size() - 1;
4856     mCurrentFreeEntry = 0;
4857 
4858     return angle::Result::Continue;
4859 }
4860 
4861 template <typename Pool>
onEntryFreed(ContextVk * contextVk,size_t poolIndex,const ResourceUse & use)4862 void DynamicallyGrowingPool<Pool>::onEntryFreed(ContextVk *contextVk,
4863                                                 size_t poolIndex,
4864                                                 const ResourceUse &use)
4865 {
4866     ASSERT(poolIndex < mPools.size() && mPools[poolIndex].freedCount < mPoolSize);
4867     if (!contextVk->getRenderer()->hasResourceUseFinished(use))
4868     {
4869         mPools[poolIndex].mergeResourceUse(use);
4870     }
4871     ++mPools[poolIndex].freedCount;
4872 }
4873 
4874 template <typename Pool>
allocatePoolEntries(ContextVk * contextVk,uint32_t entryCount,uint32_t * poolIndex,uint32_t * currentEntryOut)4875 angle::Result DynamicallyGrowingPool<Pool>::allocatePoolEntries(ContextVk *contextVk,
4876                                                                 uint32_t entryCount,
4877                                                                 uint32_t *poolIndex,
4878                                                                 uint32_t *currentEntryOut)
4879 {
4880     if (mCurrentFreeEntry + entryCount > mPoolSize)
4881     {
4882         if (!findFreeEntryPool(contextVk))
4883         {
4884             Pool newPool;
4885             ANGLE_TRY(allocatePoolImpl(contextVk, newPool, mPoolSize));
4886             ANGLE_TRY(allocateNewEntryPool(contextVk, std::move(newPool)));
4887         }
4888     }
4889 
4890     *poolIndex       = static_cast<uint32_t>(mCurrentPool);
4891     *currentEntryOut = mCurrentFreeEntry;
4892 
4893     mCurrentFreeEntry += entryCount;
4894 
4895     return angle::Result::Continue;
4896 }
4897 
4898 template <typename Pool>
PoolResource(Pool && poolIn,uint32_t freedCountIn)4899 DynamicallyGrowingPool<Pool>::PoolResource::PoolResource(Pool &&poolIn, uint32_t freedCountIn)
4900     : pool(std::move(poolIn)), freedCount(freedCountIn)
4901 {}
4902 
4903 template <typename Pool>
PoolResource(PoolResource && other)4904 DynamicallyGrowingPool<Pool>::PoolResource::PoolResource(PoolResource &&other)
4905     : Resource(std::move(other)), pool(std::move(other.pool)), freedCount(other.freedCount)
4906 {}
4907 
4908 // DynamicQueryPool implementation
4909 DynamicQueryPool::DynamicQueryPool() = default;
4910 
4911 DynamicQueryPool::~DynamicQueryPool() = default;
4912 
init(ContextVk * contextVk,VkQueryType type,uint32_t poolSize)4913 angle::Result DynamicQueryPool::init(ContextVk *contextVk, VkQueryType type, uint32_t poolSize)
4914 {
4915     // SecondaryCommandBuffer's ResetQueryPoolParams would like the query index to fit in 24 bits.
4916     ASSERT(poolSize < (1 << 24));
4917 
4918     ANGLE_TRY(initEntryPool(contextVk, poolSize));
4919     mQueryType = type;
4920     return angle::Result::Continue;
4921 }
4922 
destroy(VkDevice device)4923 void DynamicQueryPool::destroy(VkDevice device)
4924 {
4925     destroyEntryPool(device);
4926 }
4927 
destroyPoolImpl(VkDevice device,QueryPool & poolToDestroy)4928 void DynamicQueryPool::destroyPoolImpl(VkDevice device, QueryPool &poolToDestroy)
4929 {
4930     poolToDestroy.destroy(device);
4931 }
4932 
allocateQuery(ContextVk * contextVk,QueryHelper * queryOut,uint32_t queryCount)4933 angle::Result DynamicQueryPool::allocateQuery(ContextVk *contextVk,
4934                                               QueryHelper *queryOut,
4935                                               uint32_t queryCount)
4936 {
4937     ASSERT(!queryOut->valid());
4938 
4939     uint32_t currentPool = 0;
4940     uint32_t queryIndex  = 0;
4941     ANGLE_TRY(allocatePoolEntries(contextVk, queryCount, &currentPool, &queryIndex));
4942 
4943     queryOut->init(this, currentPool, queryIndex, queryCount);
4944 
4945     return angle::Result::Continue;
4946 }
4947 
allocatePoolImpl(ContextVk * contextVk,QueryPool & poolToAllocate,uint32_t entriesToAllocate)4948 angle::Result DynamicQueryPool::allocatePoolImpl(ContextVk *contextVk,
4949                                                  QueryPool &poolToAllocate,
4950                                                  uint32_t entriesToAllocate)
4951 {
4952     VkQueryPoolCreateInfo queryPoolInfo = {};
4953     queryPoolInfo.sType                 = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
4954     queryPoolInfo.flags                 = 0;
4955     queryPoolInfo.queryType             = this->mQueryType;
4956     queryPoolInfo.queryCount            = entriesToAllocate;
4957     queryPoolInfo.pipelineStatistics    = 0;
4958 
4959     if (this->mQueryType == VK_QUERY_TYPE_PIPELINE_STATISTICS)
4960     {
4961         queryPoolInfo.pipelineStatistics = VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT;
4962     }
4963 
4964     ANGLE_VK_TRY(contextVk, poolToAllocate.init(contextVk->getDevice(), queryPoolInfo));
4965     return angle::Result::Continue;
4966 }
4967 
freeQuery(ContextVk * contextVk,QueryHelper * query)4968 void DynamicQueryPool::freeQuery(ContextVk *contextVk, QueryHelper *query)
4969 {
4970     if (query->valid())
4971     {
4972         size_t poolIndex = query->mQueryPoolIndex;
4973         ASSERT(getQueryPool(poolIndex).valid());
4974 
4975         onEntryFreed(contextVk, poolIndex, query->getResourceUse());
4976 
4977         query->deinit();
4978     }
4979 }
4980 
4981 // QueryResult implementation
setResults(uint64_t * results,uint32_t queryCount)4982 void QueryResult::setResults(uint64_t *results, uint32_t queryCount)
4983 {
4984     ASSERT(mResults[0] == 0 && mResults[1] == 0);
4985 
4986     // Accumulate the query results.  For multiview, where multiple query indices are used to return
4987     // the results, it's undefined how the results are distributed between indices, but the sum is
4988     // guaranteed to be the desired result.
4989     for (uint32_t query = 0; query < queryCount; ++query)
4990     {
4991         for (uint32_t perQueryIndex = 0; perQueryIndex < mIntsPerResult; ++perQueryIndex)
4992         {
4993             mResults[perQueryIndex] += results[query * mIntsPerResult + perQueryIndex];
4994         }
4995     }
4996 }
4997 
4998 // QueryHelper implementation
QueryHelper()4999 QueryHelper::QueryHelper()
5000     : mDynamicQueryPool(nullptr),
5001       mQueryPoolIndex(0),
5002       mQuery(0),
5003       mQueryCount(0),
5004       mStatus(QueryStatus::Inactive)
5005 {}
5006 
~QueryHelper()5007 QueryHelper::~QueryHelper() {}
5008 
5009 // Move constructor
QueryHelper(QueryHelper && rhs)5010 QueryHelper::QueryHelper(QueryHelper &&rhs)
5011     : Resource(std::move(rhs)),
5012       mDynamicQueryPool(rhs.mDynamicQueryPool),
5013       mQueryPoolIndex(rhs.mQueryPoolIndex),
5014       mQuery(rhs.mQuery),
5015       mQueryCount(rhs.mQueryCount),
5016       mStatus(rhs.mStatus)
5017 {
5018     rhs.mDynamicQueryPool = nullptr;
5019     rhs.mQueryPoolIndex   = 0;
5020     rhs.mQuery            = 0;
5021     rhs.mQueryCount       = 0;
5022     rhs.mStatus           = QueryStatus::Inactive;
5023 }
5024 
operator =(QueryHelper && rhs)5025 QueryHelper &QueryHelper::operator=(QueryHelper &&rhs)
5026 {
5027     Resource::operator=(std::move(rhs));
5028     std::swap(mDynamicQueryPool, rhs.mDynamicQueryPool);
5029     std::swap(mQueryPoolIndex, rhs.mQueryPoolIndex);
5030     std::swap(mQuery, rhs.mQuery);
5031     std::swap(mQueryCount, rhs.mQueryCount);
5032     std::swap(mStatus, rhs.mStatus);
5033     return *this;
5034 }
5035 
init(const DynamicQueryPool * dynamicQueryPool,const size_t queryPoolIndex,uint32_t query,uint32_t queryCount)5036 void QueryHelper::init(const DynamicQueryPool *dynamicQueryPool,
5037                        const size_t queryPoolIndex,
5038                        uint32_t query,
5039                        uint32_t queryCount)
5040 {
5041     mDynamicQueryPool = dynamicQueryPool;
5042     mQueryPoolIndex   = queryPoolIndex;
5043     mQuery            = query;
5044     mQueryCount       = queryCount;
5045 
5046     ASSERT(mQueryCount <= gl::IMPLEMENTATION_ANGLE_MULTIVIEW_MAX_VIEWS);
5047 }
5048 
deinit()5049 void QueryHelper::deinit()
5050 {
5051     mDynamicQueryPool = nullptr;
5052     mQueryPoolIndex   = 0;
5053     mQuery            = 0;
5054     mQueryCount       = 0;
5055     mUse.reset();
5056     mStatus = QueryStatus::Inactive;
5057 }
5058 
5059 template <typename CommandBufferT>
beginQueryImpl(ContextVk * contextVk,OutsideRenderPassCommandBuffer * resetCommandBuffer,CommandBufferT * commandBuffer)5060 void QueryHelper::beginQueryImpl(ContextVk *contextVk,
5061                                  OutsideRenderPassCommandBuffer *resetCommandBuffer,
5062                                  CommandBufferT *commandBuffer)
5063 {
5064     ASSERT(mStatus != QueryStatus::Active);
5065     const QueryPool &queryPool = getQueryPool();
5066     resetQueryPoolImpl(contextVk, queryPool, resetCommandBuffer);
5067     commandBuffer->beginQuery(queryPool, mQuery, 0);
5068     mStatus = QueryStatus::Active;
5069 }
5070 
5071 template <typename CommandBufferT>
endQueryImpl(ContextVk * contextVk,CommandBufferT * commandBuffer)5072 void QueryHelper::endQueryImpl(ContextVk *contextVk, CommandBufferT *commandBuffer)
5073 {
5074     ASSERT(mStatus != QueryStatus::Ended);
5075     commandBuffer->endQuery(getQueryPool(), mQuery);
5076     mStatus = QueryStatus::Ended;
5077 }
5078 
beginQuery(ContextVk * contextVk)5079 angle::Result QueryHelper::beginQuery(ContextVk *contextVk)
5080 {
5081     if (contextVk->hasActiveRenderPass())
5082     {
5083         ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass(
5084             RenderPassClosureReason::BeginNonRenderPassQuery));
5085     }
5086 
5087     OutsideRenderPassCommandBuffer *commandBuffer;
5088     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer({}, &commandBuffer));
5089 
5090     ANGLE_TRY(contextVk->handleGraphicsEventLog(rx::GraphicsEventCmdBuf::InOutsideCmdBufQueryCmd));
5091 
5092     beginQueryImpl(contextVk, commandBuffer, commandBuffer);
5093 
5094     return angle::Result::Continue;
5095 }
5096 
endQuery(ContextVk * contextVk)5097 angle::Result QueryHelper::endQuery(ContextVk *contextVk)
5098 {
5099     if (contextVk->hasActiveRenderPass())
5100     {
5101         ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass(
5102             RenderPassClosureReason::EndNonRenderPassQuery));
5103     }
5104 
5105     CommandBufferAccess access;
5106     OutsideRenderPassCommandBuffer *commandBuffer;
5107     access.onQueryAccess(this);
5108     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
5109 
5110     ANGLE_TRY(contextVk->handleGraphicsEventLog(rx::GraphicsEventCmdBuf::InOutsideCmdBufQueryCmd));
5111 
5112     endQueryImpl(contextVk, commandBuffer);
5113 
5114     return angle::Result::Continue;
5115 }
5116 
5117 template <typename CommandBufferT>
resetQueryPoolImpl(ContextVk * contextVk,const QueryPool & queryPool,CommandBufferT * commandBuffer)5118 void QueryHelper::resetQueryPoolImpl(ContextVk *contextVk,
5119                                      const QueryPool &queryPool,
5120                                      CommandBufferT *commandBuffer)
5121 {
5122     Renderer *renderer = contextVk->getRenderer();
5123     if (renderer->getFeatures().supportsHostQueryReset.enabled)
5124     {
5125         vkResetQueryPoolEXT(contextVk->getDevice(), queryPool.getHandle(), mQuery, mQueryCount);
5126     }
5127     else
5128     {
5129         commandBuffer->resetQueryPool(queryPool, mQuery, mQueryCount);
5130     }
5131 }
5132 
beginRenderPassQuery(ContextVk * contextVk)5133 angle::Result QueryHelper::beginRenderPassQuery(ContextVk *contextVk)
5134 {
5135     OutsideRenderPassCommandBuffer *outsideRenderPassCommandBuffer;
5136     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer({}, &outsideRenderPassCommandBuffer));
5137 
5138     RenderPassCommandBuffer *renderPassCommandBuffer =
5139         &contextVk->getStartedRenderPassCommands().getCommandBuffer();
5140 
5141     beginQueryImpl(contextVk, outsideRenderPassCommandBuffer, renderPassCommandBuffer);
5142 
5143     return angle::Result::Continue;
5144 }
5145 
endRenderPassQuery(ContextVk * contextVk)5146 void QueryHelper::endRenderPassQuery(ContextVk *contextVk)
5147 {
5148     if (mStatus == QueryStatus::Active)
5149     {
5150         endQueryImpl(contextVk, &contextVk->getStartedRenderPassCommands().getCommandBuffer());
5151         contextVk->getStartedRenderPassCommands().retainResource(this);
5152     }
5153 }
5154 
flushAndWriteTimestamp(ContextVk * contextVk)5155 angle::Result QueryHelper::flushAndWriteTimestamp(ContextVk *contextVk)
5156 {
5157     if (contextVk->hasActiveRenderPass())
5158     {
5159         ANGLE_TRY(
5160             contextVk->flushCommandsAndEndRenderPass(RenderPassClosureReason::TimestampQuery));
5161     }
5162 
5163     CommandBufferAccess access;
5164     OutsideRenderPassCommandBuffer *commandBuffer;
5165     access.onQueryAccess(this);
5166     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
5167     writeTimestamp(contextVk, commandBuffer);
5168     return angle::Result::Continue;
5169 }
5170 
writeTimestampToPrimary(ContextVk * contextVk,PrimaryCommandBuffer * primary)5171 void QueryHelper::writeTimestampToPrimary(ContextVk *contextVk, PrimaryCommandBuffer *primary)
5172 {
5173     // Note that commands may not be flushed at this point.
5174 
5175     const QueryPool &queryPool = getQueryPool();
5176     resetQueryPoolImpl(contextVk, queryPool, primary);
5177     primary->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, queryPool, mQuery);
5178 }
5179 
writeTimestamp(ContextVk * contextVk,OutsideRenderPassCommandBuffer * commandBuffer)5180 void QueryHelper::writeTimestamp(ContextVk *contextVk,
5181                                  OutsideRenderPassCommandBuffer *commandBuffer)
5182 {
5183     const QueryPool &queryPool = getQueryPool();
5184     resetQueryPoolImpl(contextVk, queryPool, commandBuffer);
5185     commandBuffer->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, queryPool, mQuery);
5186 }
5187 
hasSubmittedCommands() const5188 bool QueryHelper::hasSubmittedCommands() const
5189 {
5190     return mUse.valid();
5191 }
5192 
getUint64ResultNonBlocking(ContextVk * contextVk,QueryResult * resultOut,bool * availableOut)5193 angle::Result QueryHelper::getUint64ResultNonBlocking(ContextVk *contextVk,
5194                                                       QueryResult *resultOut,
5195                                                       bool *availableOut)
5196 {
5197     ASSERT(valid());
5198     VkResult result;
5199 
5200     // Ensure that we only wait if we have inserted a query in command buffer. Otherwise you will
5201     // wait forever and trigger GPU timeout.
5202     if (hasSubmittedCommands())
5203     {
5204         constexpr VkQueryResultFlags kFlags = VK_QUERY_RESULT_64_BIT;
5205         result                              = getResultImpl(contextVk, kFlags, resultOut);
5206     }
5207     else
5208     {
5209         result     = VK_SUCCESS;
5210         *resultOut = 0;
5211     }
5212 
5213     if (result == VK_NOT_READY)
5214     {
5215         *availableOut = false;
5216         return angle::Result::Continue;
5217     }
5218     else
5219     {
5220         ANGLE_VK_TRY(contextVk, result);
5221         *availableOut = true;
5222     }
5223     return angle::Result::Continue;
5224 }
5225 
getUint64Result(ContextVk * contextVk,QueryResult * resultOut)5226 angle::Result QueryHelper::getUint64Result(ContextVk *contextVk, QueryResult *resultOut)
5227 {
5228     ASSERT(valid());
5229     if (hasSubmittedCommands())
5230     {
5231         constexpr VkQueryResultFlags kFlags = VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT;
5232         ANGLE_VK_TRY(contextVk, getResultImpl(contextVk, kFlags, resultOut));
5233     }
5234     else
5235     {
5236         *resultOut = 0;
5237     }
5238     return angle::Result::Continue;
5239 }
5240 
getResultImpl(ContextVk * contextVk,const VkQueryResultFlags flags,QueryResult * resultOut)5241 VkResult QueryHelper::getResultImpl(ContextVk *contextVk,
5242                                     const VkQueryResultFlags flags,
5243                                     QueryResult *resultOut)
5244 {
5245     std::array<uint64_t, 2 * gl::IMPLEMENTATION_ANGLE_MULTIVIEW_MAX_VIEWS> results;
5246 
5247     VkDevice device = contextVk->getDevice();
5248     VkResult result = getQueryPool().getResults(device, mQuery, mQueryCount, sizeof(results),
5249                                                 results.data(), sizeof(uint64_t), flags);
5250 
5251     if (result == VK_SUCCESS)
5252     {
5253         resultOut->setResults(results.data(), mQueryCount);
5254     }
5255 
5256     return result;
5257 }
5258 
5259 // SemaphoreHelper implementation
SemaphoreHelper()5260 SemaphoreHelper::SemaphoreHelper() : mSemaphorePoolIndex(0), mSemaphore(0) {}
5261 
~SemaphoreHelper()5262 SemaphoreHelper::~SemaphoreHelper() {}
5263 
SemaphoreHelper(SemaphoreHelper && other)5264 SemaphoreHelper::SemaphoreHelper(SemaphoreHelper &&other)
5265     : mSemaphorePoolIndex(other.mSemaphorePoolIndex), mSemaphore(other.mSemaphore)
5266 {
5267     other.mSemaphore = nullptr;
5268 }
5269 
operator =(SemaphoreHelper && other)5270 SemaphoreHelper &SemaphoreHelper::operator=(SemaphoreHelper &&other)
5271 {
5272     std::swap(mSemaphorePoolIndex, other.mSemaphorePoolIndex);
5273     std::swap(mSemaphore, other.mSemaphore);
5274     return *this;
5275 }
5276 
init(const size_t semaphorePoolIndex,const Semaphore * semaphore)5277 void SemaphoreHelper::init(const size_t semaphorePoolIndex, const Semaphore *semaphore)
5278 {
5279     mSemaphorePoolIndex = semaphorePoolIndex;
5280     mSemaphore          = semaphore;
5281 }
5282 
deinit()5283 void SemaphoreHelper::deinit()
5284 {
5285     mSemaphorePoolIndex = 0;
5286     mSemaphore          = nullptr;
5287 }
5288 
GetPipelineStage(gl::ShaderType stage)5289 PipelineStage GetPipelineStage(gl::ShaderType stage)
5290 {
5291     const PipelineStage pipelineStage = kPipelineStageShaderMap[stage];
5292     ASSERT(pipelineStage == PipelineStage::VertexShader ||
5293            pipelineStage == PipelineStage::TessellationControl ||
5294            pipelineStage == PipelineStage::TessellationEvaluation ||
5295            pipelineStage == PipelineStage::GeometryShader ||
5296            pipelineStage == PipelineStage::FragmentShader ||
5297            pipelineStage == PipelineStage::ComputeShader);
5298     return pipelineStage;
5299 }
5300 
5301 // PipelineBarrier implementation.
addDiagnosticsString(std::ostringstream & out) const5302 void PipelineBarrier::addDiagnosticsString(std::ostringstream &out) const
5303 {
5304     if (mMemoryBarrierSrcAccess != 0 || mMemoryBarrierDstAccess != 0)
5305     {
5306         out << "Src: 0x" << std::hex << mMemoryBarrierSrcAccess << " &rarr; Dst: 0x" << std::hex
5307             << mMemoryBarrierDstAccess << std::endl;
5308     }
5309 }
5310 
5311 // PipelineBarrierArray implementation.
execute(Renderer * renderer,PrimaryCommandBuffer * primary)5312 void PipelineBarrierArray::execute(Renderer *renderer, PrimaryCommandBuffer *primary)
5313 {
5314     // make a local copy for faster access
5315     PipelineStagesMask mask = mBarrierMask;
5316     if (mask.none())
5317     {
5318         return;
5319     }
5320 
5321     if (renderer->getFeatures().preferAggregateBarrierCalls.enabled)
5322     {
5323         PipelineStagesMask::Iterator iter = mask.begin();
5324         PipelineBarrier &barrier          = mBarriers[*iter];
5325         for (++iter; iter != mask.end(); ++iter)
5326         {
5327             barrier.merge(&mBarriers[*iter]);
5328         }
5329         barrier.execute(primary);
5330     }
5331     else
5332     {
5333         for (PipelineStage pipelineStage : mask)
5334         {
5335             PipelineBarrier &barrier = mBarriers[pipelineStage];
5336             barrier.execute(primary);
5337         }
5338     }
5339     mBarrierMask.reset();
5340 }
5341 
addDiagnosticsString(std::ostringstream & out) const5342 void PipelineBarrierArray::addDiagnosticsString(std::ostringstream &out) const
5343 {
5344     out << "Memory Barrier: ";
5345     for (PipelineStage pipelineStage : mBarrierMask)
5346     {
5347         const PipelineBarrier &barrier = mBarriers[pipelineStage];
5348         if (!barrier.isEmpty())
5349         {
5350             barrier.addDiagnosticsString(out);
5351         }
5352     }
5353     out << "\\l";
5354 }
5355 
5356 // BufferHelper implementation.
BufferHelper()5357 BufferHelper::BufferHelper()
5358     : mCurrentWriteAccess(0),
5359       mCurrentReadAccess(0),
5360       mCurrentWriteStages(0),
5361       mCurrentReadStages(0),
5362       mSerial(),
5363       mClientBuffer(nullptr),
5364       mIsReleasedToExternal(false)
5365 {}
5366 
~BufferHelper()5367 BufferHelper::~BufferHelper()
5368 {
5369     // We must have released external buffer properly
5370     ASSERT(mClientBuffer == nullptr);
5371 }
5372 
BufferHelper(BufferHelper && other)5373 BufferHelper::BufferHelper(BufferHelper &&other)
5374 {
5375     *this = std::move(other);
5376 }
5377 
operator =(BufferHelper && other)5378 BufferHelper &BufferHelper::operator=(BufferHelper &&other)
5379 {
5380     ReadWriteResource::operator=(std::move(other));
5381 
5382     mSuballocation      = std::move(other.mSuballocation);
5383     mBufferWithUserSize = std::move(other.mBufferWithUserSize);
5384 
5385     mCurrentDeviceQueueIndex = other.mCurrentDeviceQueueIndex;
5386     mIsReleasedToExternal    = other.mIsReleasedToExternal;
5387     mCurrentWriteAccess      = other.mCurrentWriteAccess;
5388     mCurrentReadAccess       = other.mCurrentReadAccess;
5389     mCurrentWriteStages      = other.mCurrentWriteStages;
5390     mCurrentReadStages       = other.mCurrentReadStages;
5391     mSerial                  = other.mSerial;
5392     mClientBuffer            = std::move(other.mClientBuffer);
5393 
5394     return *this;
5395 }
5396 
init(Context * context,const VkBufferCreateInfo & requestedCreateInfo,VkMemoryPropertyFlags memoryPropertyFlags)5397 angle::Result BufferHelper::init(Context *context,
5398                                  const VkBufferCreateInfo &requestedCreateInfo,
5399                                  VkMemoryPropertyFlags memoryPropertyFlags)
5400 {
5401     Renderer *renderer         = context->getRenderer();
5402     const Allocator &allocator = renderer->getAllocator();
5403 
5404     initializeBarrierTracker(context);
5405 
5406     VkBufferCreateInfo modifiedCreateInfo;
5407     const VkBufferCreateInfo *createInfo = &requestedCreateInfo;
5408 
5409     if (renderer->getFeatures().padBuffersToMaxVertexAttribStride.enabled)
5410     {
5411         const VkDeviceSize maxVertexAttribStride = renderer->getMaxVertexAttribStride();
5412         ASSERT(maxVertexAttribStride);
5413         modifiedCreateInfo = requestedCreateInfo;
5414         modifiedCreateInfo.size += maxVertexAttribStride;
5415         createInfo = &modifiedCreateInfo;
5416     }
5417 
5418     VkMemoryPropertyFlags requiredFlags =
5419         (memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
5420     VkMemoryPropertyFlags preferredFlags =
5421         (memoryPropertyFlags & (~VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
5422 
5423     bool persistentlyMapped = renderer->getFeatures().persistentlyMappedBuffers.enabled;
5424 
5425     // Check that the allocation is not too large.
5426     uint32_t memoryTypeIndex = kInvalidMemoryTypeIndex;
5427     ANGLE_VK_TRY(context, allocator.findMemoryTypeIndexForBufferInfo(
5428                               *createInfo, requiredFlags, preferredFlags, persistentlyMapped,
5429                               &memoryTypeIndex));
5430 
5431     VkDeviceSize heapSize =
5432         renderer->getMemoryProperties().getHeapSizeForMemoryType(memoryTypeIndex);
5433 
5434     ANGLE_VK_CHECK(context, createInfo->size <= heapSize, VK_ERROR_OUT_OF_DEVICE_MEMORY);
5435 
5436     VkMemoryPropertyFlags memoryPropertyFlagsOut;
5437     allocator.getMemoryTypeProperties(memoryTypeIndex, &memoryPropertyFlagsOut);
5438     // Allocate buffer object
5439     DeviceScoped<Buffer> buffer(renderer->getDevice());
5440     ANGLE_VK_TRY(context, buffer.get().init(context->getDevice(), *createInfo));
5441 
5442     DeviceScoped<DeviceMemory> deviceMemory(renderer->getDevice());
5443     VkDeviceSize sizeOut;
5444     uint32_t bufferMemoryTypeIndex;
5445     ANGLE_VK_TRY(context,
5446                  AllocateBufferMemory(context, MemoryAllocationType::Buffer, memoryPropertyFlagsOut,
5447                                       &memoryPropertyFlagsOut, nullptr, &buffer.get(),
5448                                       &bufferMemoryTypeIndex, &deviceMemory.get(), &sizeOut));
5449     ASSERT(sizeOut >= createInfo->size);
5450 
5451     mSuballocation.initWithEntireBuffer(context, buffer.get(), MemoryAllocationType::Buffer,
5452                                         bufferMemoryTypeIndex, deviceMemory.get(),
5453                                         memoryPropertyFlagsOut, requestedCreateInfo.size, sizeOut);
5454     if (isHostVisible())
5455     {
5456         uint8_t *ptrOut;
5457         ANGLE_TRY(map(context, &ptrOut));
5458     }
5459 
5460     if (renderer->getFeatures().allocateNonZeroMemory.enabled)
5461     {
5462         ANGLE_TRY(initializeNonZeroMemory(context, createInfo->usage, createInfo->size));
5463     }
5464 
5465     return angle::Result::Continue;
5466 }
5467 
initExternal(Context * context,VkMemoryPropertyFlags memoryProperties,const VkBufferCreateInfo & requestedCreateInfo,GLeglClientBufferEXT clientBuffer)5468 angle::Result BufferHelper::initExternal(Context *context,
5469                                          VkMemoryPropertyFlags memoryProperties,
5470                                          const VkBufferCreateInfo &requestedCreateInfo,
5471                                          GLeglClientBufferEXT clientBuffer)
5472 {
5473     ASSERT(IsAndroid());
5474 
5475     Renderer *renderer = context->getRenderer();
5476 
5477     initializeBarrierTracker(context);
5478 
5479     VkBufferCreateInfo modifiedCreateInfo             = requestedCreateInfo;
5480     VkExternalMemoryBufferCreateInfo externCreateInfo = {};
5481     externCreateInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO;
5482     externCreateInfo.handleTypes =
5483         VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
5484     externCreateInfo.pNext   = nullptr;
5485     modifiedCreateInfo.pNext = &externCreateInfo;
5486 
5487     DeviceScoped<Buffer> buffer(renderer->getDevice());
5488     ANGLE_VK_TRY(context, buffer.get().init(renderer->getDevice(), modifiedCreateInfo));
5489 
5490     DeviceScoped<DeviceMemory> deviceMemory(renderer->getDevice());
5491     VkMemoryPropertyFlags memoryPropertyFlagsOut;
5492     VkDeviceSize allocatedSize = 0;
5493     uint32_t memoryTypeIndex;
5494     ANGLE_TRY(InitAndroidExternalMemory(context, clientBuffer, memoryProperties, &buffer.get(),
5495                                         &memoryPropertyFlagsOut, &memoryTypeIndex,
5496                                         &deviceMemory.get(), &allocatedSize));
5497     mClientBuffer = clientBuffer;
5498 
5499     mSuballocation.initWithEntireBuffer(context, buffer.get(), MemoryAllocationType::BufferExternal,
5500                                         memoryTypeIndex, deviceMemory.get(), memoryPropertyFlagsOut,
5501                                         requestedCreateInfo.size, allocatedSize);
5502     if (isHostVisible())
5503     {
5504         uint8_t *ptrOut;
5505         ANGLE_TRY(map(context, &ptrOut));
5506     }
5507     return angle::Result::Continue;
5508 }
5509 
initSuballocation(Context * context,uint32_t memoryTypeIndex,size_t size,size_t alignment,BufferUsageType usageType,BufferPool * pool)5510 VkResult BufferHelper::initSuballocation(Context *context,
5511                                          uint32_t memoryTypeIndex,
5512                                          size_t size,
5513                                          size_t alignment,
5514                                          BufferUsageType usageType,
5515                                          BufferPool *pool)
5516 {
5517     ASSERT(pool != nullptr);
5518     Renderer *renderer = context->getRenderer();
5519 
5520     // We should reset these in case the BufferHelper object has been released and called
5521     // initSuballocation again.
5522     initializeBarrierTracker(context);
5523 
5524     if (renderer->getFeatures().padBuffersToMaxVertexAttribStride.enabled)
5525     {
5526         const VkDeviceSize maxVertexAttribStride = renderer->getMaxVertexAttribStride();
5527         ASSERT(maxVertexAttribStride);
5528         size += maxVertexAttribStride;
5529     }
5530 
5531     VK_RESULT_TRY(pool->allocateBuffer(context, size, alignment, &mSuballocation));
5532 
5533     context->getPerfCounters().bufferSuballocationCalls++;
5534 
5535     return VK_SUCCESS;
5536 }
5537 
initializeBarrierTracker(Context * context)5538 void BufferHelper::initializeBarrierTracker(Context *context)
5539 {
5540     Renderer *renderer       = context->getRenderer();
5541     mCurrentDeviceQueueIndex = context->getDeviceQueueIndex();
5542     mIsReleasedToExternal    = false;
5543     mSerial                  = renderer->getResourceSerialFactory().generateBufferSerial();
5544     mCurrentWriteAccess      = 0;
5545     mCurrentReadAccess       = 0;
5546     mCurrentWriteStages      = 0;
5547     mCurrentReadStages       = 0;
5548 }
5549 
initializeNonZeroMemory(Context * context,VkBufferUsageFlags usage,VkDeviceSize size)5550 angle::Result BufferHelper::initializeNonZeroMemory(Context *context,
5551                                                     VkBufferUsageFlags usage,
5552                                                     VkDeviceSize size)
5553 {
5554     Renderer *renderer = context->getRenderer();
5555 
5556     // This memory can't be mapped, so the buffer must be marked as a transfer destination so we
5557     // can use a staging resource to initialize it to a non-zero value. If the memory is
5558     // mappable we do the initialization in AllocateBufferMemory.
5559     if (!isHostVisible() && (usage & VK_BUFFER_USAGE_TRANSFER_DST_BIT) != 0)
5560     {
5561         ASSERT((usage & VK_BUFFER_USAGE_TRANSFER_DST_BIT) != 0);
5562         // Staging buffer memory is non-zero-initialized in 'init'.
5563         StagingBuffer stagingBuffer;
5564         ANGLE_TRY(stagingBuffer.init(context, size, StagingUsage::Both));
5565 
5566         PrimaryCommandBuffer commandBuffer;
5567         ANGLE_TRY(
5568             renderer->getCommandBufferOneOff(context, ProtectionType::Unprotected, &commandBuffer));
5569 
5570         // Queue a DMA copy.
5571         VkBufferCopy copyRegion = {};
5572         copyRegion.srcOffset    = 0;
5573         copyRegion.dstOffset    = getOffset();
5574         copyRegion.size         = size;
5575 
5576         commandBuffer.copyBuffer(stagingBuffer.getBuffer(), getBuffer(), 1, &copyRegion);
5577 
5578         ANGLE_VK_TRY(context, commandBuffer.end());
5579 
5580         QueueSerial queueSerial;
5581         ANGLE_TRY(renderer->queueSubmitOneOff(context, std::move(commandBuffer),
5582                                               ProtectionType::Unprotected,
5583                                               egl::ContextPriority::Medium, VK_NULL_HANDLE, 0,
5584                                               vk::SubmitPolicy::AllowDeferred, &queueSerial));
5585 
5586         stagingBuffer.collectGarbage(renderer, queueSerial);
5587         // Update both ResourceUse objects, since mReadOnlyUse tracks when the buffer can be
5588         // destroyed, and mReadWriteUse tracks when the write has completed.
5589         setWriteQueueSerial(queueSerial);
5590     }
5591     else if (isHostVisible())
5592     {
5593         // Can map the memory.
5594         // Pick an arbitrary value to initialize non-zero memory for sanitization.
5595         constexpr int kNonZeroInitValue = 55;
5596         uint8_t *mapPointer             = mSuballocation.getMappedMemory();
5597         memset(mapPointer, kNonZeroInitValue, static_cast<size_t>(getSize()));
5598         if (!isCoherent())
5599         {
5600             mSuballocation.flush(renderer->getDevice());
5601         }
5602     }
5603 
5604     return angle::Result::Continue;
5605 }
5606 
getBufferForVertexArray(ContextVk * contextVk,VkDeviceSize actualDataSize,VkDeviceSize * offsetOut)5607 const Buffer &BufferHelper::getBufferForVertexArray(ContextVk *contextVk,
5608                                                     VkDeviceSize actualDataSize,
5609                                                     VkDeviceSize *offsetOut)
5610 {
5611     ASSERT(mSuballocation.valid());
5612     ASSERT(actualDataSize <= mSuballocation.getSize());
5613 
5614     if (!contextVk->hasRobustAccess() || !mSuballocation.isSuballocated() ||
5615         actualDataSize == mSuballocation.getSize())
5616     {
5617         *offsetOut = mSuballocation.getOffset();
5618         return mSuballocation.getBuffer();
5619     }
5620 
5621     if (!mBufferWithUserSize.valid())
5622     {
5623         // Allocate buffer that is backed by sub-range of the memory for vertex array usage. This is
5624         // only needed when robust resource init is enabled so that vulkan driver will know the
5625         // exact size of the vertex buffer it is supposedly to use and prevent out of bound access.
5626         VkBufferCreateInfo createInfo    = {};
5627         createInfo.sType                 = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
5628         createInfo.flags                 = 0;
5629         createInfo.size                  = actualDataSize;
5630         createInfo.usage                 = kVertexBufferUsageFlags | kIndexBufferUsageFlags;
5631         createInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
5632         createInfo.queueFamilyIndexCount = 0;
5633         createInfo.pQueueFamilyIndices   = nullptr;
5634         mBufferWithUserSize.init(contextVk->getDevice(), createInfo);
5635 
5636         VkMemoryRequirements memoryRequirements;
5637         mBufferWithUserSize.getMemoryRequirements(contextVk->getDevice(), &memoryRequirements);
5638         ASSERT(contextVk->getRenderer()->isMockICDEnabled() ||
5639                mSuballocation.getSize() >= memoryRequirements.size);
5640         ASSERT(!contextVk->getRenderer()->isMockICDEnabled() ||
5641                mSuballocation.getOffset() % memoryRequirements.alignment == 0);
5642 
5643         mBufferWithUserSize.bindMemory(contextVk->getDevice(), mSuballocation.getDeviceMemory(),
5644                                        mSuballocation.getOffset());
5645     }
5646     *offsetOut = 0;
5647     return mBufferWithUserSize;
5648 }
5649 
onBufferUserSizeChange(Renderer * renderer)5650 bool BufferHelper::onBufferUserSizeChange(Renderer *renderer)
5651 {
5652     // Buffer's user size and allocation size may be different due to alignment requirement. In
5653     // normal usage we just use the actual allocation size and it is good enough. But when
5654     // robustResourceInit is enabled, mBufferWithUserSize is created to mjatch the exact user
5655     // size. Thus when user size changes, we must clear and recreate this mBufferWithUserSize.
5656     if (mBufferWithUserSize.valid())
5657     {
5658         BufferSuballocation unusedSuballocation;
5659         renderer->collectSuballocationGarbage(mUse, std::move(unusedSuballocation),
5660                                               std::move(mBufferWithUserSize));
5661         mSerial = renderer->getResourceSerialFactory().generateBufferSerial();
5662         return true;
5663     }
5664     return false;
5665 }
5666 
destroy(Renderer * renderer)5667 void BufferHelper::destroy(Renderer *renderer)
5668 {
5669     mDescriptorSetCacheManager.destroyKeys(renderer);
5670     unmap(renderer);
5671     mBufferWithUserSize.destroy(renderer->getDevice());
5672     mSuballocation.destroy(renderer);
5673     if (mClientBuffer != nullptr)
5674     {
5675         ReleaseAndroidExternalMemory(renderer, mClientBuffer);
5676         mClientBuffer = nullptr;
5677     }
5678 }
5679 
release(Renderer * renderer)5680 void BufferHelper::release(Renderer *renderer)
5681 {
5682     ASSERT(mDescriptorSetCacheManager.empty());
5683     unmap(renderer);
5684 
5685     if (mSuballocation.valid())
5686     {
5687         if (!mSuballocation.isSuballocated())
5688         {
5689             // Destroy cacheKeys now to avoid getting into situation that having to destroy
5690             // descriptorSet from garbage collection thread.
5691             mSuballocation.getBufferBlock()->releaseAllCachedDescriptorSetCacheKeys(renderer);
5692         }
5693         renderer->collectSuballocationGarbage(mUse, std::move(mSuballocation),
5694                                               std::move(mBufferWithUserSize));
5695     }
5696     mUse.reset();
5697     mWriteUse.reset();
5698     ASSERT(!mBufferWithUserSize.valid());
5699 
5700     if (mClientBuffer != nullptr)
5701     {
5702         ReleaseAndroidExternalMemory(renderer, mClientBuffer);
5703         mClientBuffer = nullptr;
5704     }
5705 }
5706 
releaseBufferAndDescriptorSetCache(Renderer * renderer)5707 void BufferHelper::releaseBufferAndDescriptorSetCache(Renderer *renderer)
5708 {
5709     if (renderer->hasResourceUseFinished(getResourceUse()))
5710     {
5711         mDescriptorSetCacheManager.destroyKeys(renderer);
5712     }
5713     else
5714     {
5715         mDescriptorSetCacheManager.releaseKeys(renderer);
5716     }
5717 
5718     release(renderer);
5719 }
5720 
map(Context * context,uint8_t ** ptrOut)5721 angle::Result BufferHelper::map(Context *context, uint8_t **ptrOut)
5722 {
5723     if (!mSuballocation.isMapped())
5724     {
5725         ANGLE_VK_TRY(context, mSuballocation.map(context));
5726     }
5727     *ptrOut = mSuballocation.getMappedMemory();
5728     return angle::Result::Continue;
5729 }
5730 
mapWithOffset(Context * context,uint8_t ** ptrOut,size_t offset)5731 angle::Result BufferHelper::mapWithOffset(Context *context, uint8_t **ptrOut, size_t offset)
5732 {
5733     uint8_t *mapBufPointer;
5734     ANGLE_TRY(map(context, &mapBufPointer));
5735     *ptrOut = mapBufPointer + offset;
5736     return angle::Result::Continue;
5737 }
5738 
flush(Renderer * renderer,VkDeviceSize offset,VkDeviceSize size)5739 angle::Result BufferHelper::flush(Renderer *renderer, VkDeviceSize offset, VkDeviceSize size)
5740 {
5741     mSuballocation.flush(renderer->getDevice());
5742     return angle::Result::Continue;
5743 }
flush(Renderer * renderer)5744 angle::Result BufferHelper::flush(Renderer *renderer)
5745 {
5746     return flush(renderer, 0, getSize());
5747 }
5748 
invalidate(Renderer * renderer,VkDeviceSize offset,VkDeviceSize size)5749 angle::Result BufferHelper::invalidate(Renderer *renderer, VkDeviceSize offset, VkDeviceSize size)
5750 {
5751     mSuballocation.invalidate(renderer->getDevice());
5752     return angle::Result::Continue;
5753 }
invalidate(Renderer * renderer)5754 angle::Result BufferHelper::invalidate(Renderer *renderer)
5755 {
5756     return invalidate(renderer, 0, getSize());
5757 }
5758 
changeQueueFamily(uint32_t srcQueueFamilyIndex,uint32_t dstQueueFamilyIndex,OutsideRenderPassCommandBuffer * commandBuffer)5759 void BufferHelper::changeQueueFamily(uint32_t srcQueueFamilyIndex,
5760                                      uint32_t dstQueueFamilyIndex,
5761                                      OutsideRenderPassCommandBuffer *commandBuffer)
5762 {
5763     VkBufferMemoryBarrier bufferMemoryBarrier = {};
5764     bufferMemoryBarrier.sType                 = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
5765     bufferMemoryBarrier.srcAccessMask         = 0;
5766     bufferMemoryBarrier.dstAccessMask         = 0;
5767     bufferMemoryBarrier.srcQueueFamilyIndex   = srcQueueFamilyIndex;
5768     bufferMemoryBarrier.dstQueueFamilyIndex   = dstQueueFamilyIndex;
5769     bufferMemoryBarrier.buffer                = getBuffer().getHandle();
5770     bufferMemoryBarrier.offset                = getOffset();
5771     bufferMemoryBarrier.size                  = getSize();
5772 
5773     commandBuffer->bufferBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
5774                                  VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, &bufferMemoryBarrier);
5775 }
5776 
acquireFromExternal(DeviceQueueIndex externalQueueFamilyIndex,DeviceQueueIndex newDeviceQueueIndex,OutsideRenderPassCommandBuffer * commandBuffer)5777 void BufferHelper::acquireFromExternal(DeviceQueueIndex externalQueueFamilyIndex,
5778                                        DeviceQueueIndex newDeviceQueueIndex,
5779                                        OutsideRenderPassCommandBuffer *commandBuffer)
5780 {
5781     changeQueueFamily(externalQueueFamilyIndex.familyIndex(), newDeviceQueueIndex.familyIndex(),
5782                       commandBuffer);
5783     mCurrentDeviceQueueIndex = newDeviceQueueIndex;
5784     mIsReleasedToExternal    = false;
5785 }
5786 
releaseToExternal(DeviceQueueIndex externalQueueIndex,OutsideRenderPassCommandBuffer * commandBuffer)5787 void BufferHelper::releaseToExternal(DeviceQueueIndex externalQueueIndex,
5788                                      OutsideRenderPassCommandBuffer *commandBuffer)
5789 {
5790     if (mCurrentDeviceQueueIndex.familyIndex() != externalQueueIndex.familyIndex())
5791     {
5792         changeQueueFamily(mCurrentDeviceQueueIndex.familyIndex(), externalQueueIndex.familyIndex(),
5793                           commandBuffer);
5794         mCurrentDeviceQueueIndex = kInvalidDeviceQueueIndex;
5795     }
5796     mIsReleasedToExternal = true;
5797 }
5798 
isReleasedToExternal() const5799 bool BufferHelper::isReleasedToExternal() const
5800 {
5801     return mIsReleasedToExternal;
5802 }
5803 
recordReadBarrier(VkAccessFlags readAccessType,VkPipelineStageFlags readStage,PipelineStage stageIndex,PipelineBarrierArray * barriers)5804 void BufferHelper::recordReadBarrier(VkAccessFlags readAccessType,
5805                                      VkPipelineStageFlags readStage,
5806                                      PipelineStage stageIndex,
5807                                      PipelineBarrierArray *barriers)
5808 {
5809     // If there was a prior write and we are making a read that is either a new access type or from
5810     // a new stage, we need a barrier
5811     if (mCurrentWriteAccess != 0 && (((mCurrentReadAccess & readAccessType) != readAccessType) ||
5812                                      ((mCurrentReadStages & readStage) != readStage)))
5813     {
5814         barriers->mergeMemoryBarrier(stageIndex, mCurrentWriteStages, readStage,
5815                                      mCurrentWriteAccess, readAccessType);
5816     }
5817 
5818     // Accumulate new read usage.
5819     mCurrentReadAccess |= readAccessType;
5820     mCurrentReadStages |= readStage;
5821 }
5822 
recordWriteBarrier(VkAccessFlags writeAccessType,VkPipelineStageFlags writeStage,PipelineStage stageIndex,PipelineBarrierArray * barriers)5823 void BufferHelper::recordWriteBarrier(VkAccessFlags writeAccessType,
5824                                       VkPipelineStageFlags writeStage,
5825                                       PipelineStage stageIndex,
5826                                       PipelineBarrierArray *barriers)
5827 {
5828     // We don't need to check mCurrentReadStages here since if it is not zero, mCurrentReadAccess
5829     // must not be zero as well. stage is finer grain than accessType.
5830     ASSERT((!mCurrentReadStages && !mCurrentReadAccess) ||
5831            (mCurrentReadStages && mCurrentReadAccess));
5832     if (mCurrentReadAccess != 0 || mCurrentWriteAccess != 0)
5833     {
5834         VkPipelineStageFlags srcStageMask = mCurrentWriteStages | mCurrentReadStages;
5835         barriers->mergeMemoryBarrier(stageIndex, srcStageMask, writeStage, mCurrentWriteAccess,
5836                                      writeAccessType);
5837     }
5838 
5839     // Reset usages on the new write.
5840     mCurrentWriteAccess = writeAccessType;
5841     mCurrentReadAccess  = 0;
5842     mCurrentWriteStages = writeStage;
5843     mCurrentReadStages  = 0;
5844 }
5845 
fillWithColor(const angle::Color<uint8_t> & color,const gl::InternalFormat & internalFormat)5846 void BufferHelper::fillWithColor(const angle::Color<uint8_t> &color,
5847                                  const gl::InternalFormat &internalFormat)
5848 {
5849     uint32_t count =
5850         static_cast<uint32_t>(getSize()) / static_cast<uint32_t>(internalFormat.pixelBytes);
5851     void *buffer = static_cast<void *>(getMappedMemory());
5852 
5853     switch (internalFormat.internalFormat)
5854     {
5855         case GL_RGB565:
5856         {
5857             uint16_t pixelColor =
5858                 ((color.blue & 0xF8) << 11) | ((color.green & 0xFC) << 5) | (color.red & 0xF8);
5859             uint16_t *pixelPtr = static_cast<uint16_t *>(buffer);
5860             std::fill_n<uint16_t *, uint32_t, uint16_t>(pixelPtr, count, pixelColor);
5861         }
5862         break;
5863         case GL_RGBA8:
5864         {
5865             uint32_t pixelColor =
5866                 (color.alpha << 24) | (color.blue << 16) | (color.green << 8) | (color.red);
5867             uint32_t *pixelPtr = static_cast<uint32_t *>(buffer);
5868             std::fill_n<uint32_t *, uint32_t, uint32_t>(pixelPtr, count, pixelColor);
5869         }
5870         break;
5871         case GL_BGR565_ANGLEX:
5872         {
5873             uint16_t pixelColor =
5874                 ((color.red & 0xF8) << 11) | ((color.green & 0xFC) << 5) | (color.blue & 0xF8);
5875             uint16_t *pixelPtr = static_cast<uint16_t *>(buffer);
5876             std::fill_n<uint16_t *, uint32_t, uint16_t>(pixelPtr, count, pixelColor);
5877         }
5878         break;
5879         case GL_BGRA8_EXT:
5880         {
5881             uint32_t pixelColor =
5882                 (color.alpha << 24) | (color.red << 16) | (color.green << 8) | (color.blue);
5883             uint32_t *pixelPtr = static_cast<uint32_t *>(buffer);
5884             std::fill_n<uint32_t *, uint32_t, uint32_t>(pixelPtr, count, pixelColor);
5885         }
5886         break;
5887         default:
5888             UNREACHABLE();  // Unsupported format
5889     }
5890 }
5891 
fillWithPattern(const void * pattern,size_t patternSize,size_t offset,size_t size)5892 void BufferHelper::fillWithPattern(const void *pattern,
5893                                    size_t patternSize,
5894                                    size_t offset,
5895                                    size_t size)
5896 {
5897     ASSERT(offset + size <= getSize());
5898     ASSERT((size % patternSize) == 0);
5899     ASSERT((offset % patternSize) == 0);
5900 
5901     uint8_t *buffer = getMappedMemory() + offset;
5902     std::memcpy(buffer, pattern, patternSize);
5903     size_t remaining = size - patternSize;
5904     while (remaining > patternSize)
5905     {
5906         std::memcpy(buffer + patternSize, buffer, patternSize);
5907         remaining -= patternSize;
5908         patternSize *= 2;
5909     }
5910     std::memcpy(buffer + patternSize, buffer, remaining);
5911     return;
5912 }
5913 
5914 // Used for ImageHelper non-zero memory allocation when useVmaForImageSuballocation is disabled.
InitMappableDeviceMemory(Context * context,DeviceMemory * deviceMemory,VkDeviceSize size,int value,VkMemoryPropertyFlags memoryPropertyFlags)5915 angle::Result InitMappableDeviceMemory(Context *context,
5916                                        DeviceMemory *deviceMemory,
5917                                        VkDeviceSize size,
5918                                        int value,
5919                                        VkMemoryPropertyFlags memoryPropertyFlags)
5920 {
5921     ASSERT(!context->getFeatures().useVmaForImageSuballocation.enabled);
5922     VkDevice device = context->getDevice();
5923 
5924     uint8_t *mapPointer;
5925     ANGLE_VK_TRY(context, deviceMemory->map(device, 0, VK_WHOLE_SIZE, 0, &mapPointer));
5926     memset(mapPointer, value, static_cast<size_t>(size));
5927 
5928     // if the memory type is not host coherent, we perform an explicit flush.
5929     if ((memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0)
5930     {
5931         VkMappedMemoryRange mappedRange = {};
5932         mappedRange.sType               = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
5933         mappedRange.memory              = deviceMemory->getHandle();
5934         mappedRange.size                = VK_WHOLE_SIZE;
5935         ANGLE_VK_TRY(context, vkFlushMappedMemoryRanges(device, 1, &mappedRange));
5936     }
5937 
5938     deviceMemory->unmap(device);
5939 
5940     return angle::Result::Continue;
5941 }
5942 
5943 // ImageHelper implementation.
ImageHelper()5944 ImageHelper::ImageHelper()
5945 {
5946     resetCachedProperties();
5947 }
5948 
~ImageHelper()5949 ImageHelper::~ImageHelper()
5950 {
5951     ASSERT(!valid());
5952     ASSERT(!mAcquireNextImageSemaphore.valid());
5953 }
5954 
resetCachedProperties()5955 void ImageHelper::resetCachedProperties()
5956 {
5957     mImageType                   = VK_IMAGE_TYPE_2D;
5958     mTilingMode                  = VK_IMAGE_TILING_OPTIMAL;
5959     mCreateFlags                 = kVkImageCreateFlagsNone;
5960     mUsage                       = 0;
5961     mExtents                     = {};
5962     mRotatedAspectRatio          = false;
5963     mIntendedFormatID            = angle::FormatID::NONE;
5964     mActualFormatID              = angle::FormatID::NONE;
5965     mSamples                     = 1;
5966     mImageSerial                 = kInvalidImageSerial;
5967     mCurrentLayout               = ImageLayout::Undefined;
5968     mCurrentDeviceQueueIndex     = kInvalidDeviceQueueIndex;
5969     mIsReleasedToExternal        = false;
5970     mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
5971     mCurrentShaderReadStageMask  = 0;
5972     mFirstAllocatedLevel         = gl::LevelIndex(0);
5973     mLayerCount                  = 0;
5974     mLevelCount                  = 0;
5975     mTotalStagedBufferUpdateSize = 0;
5976     mAllocationSize              = 0;
5977     mMemoryAllocationType        = MemoryAllocationType::InvalidEnum;
5978     mMemoryTypeIndex             = kInvalidMemoryTypeIndex;
5979     std::fill(mViewFormats.begin(), mViewFormats.begin() + mViewFormats.max_size(),
5980               VK_FORMAT_UNDEFINED);
5981     mYcbcrConversionDesc.reset();
5982     mCurrentSingleClearValue.reset();
5983     mRenderPassUsageFlags.reset();
5984 
5985     setEntireContentUndefined();
5986 }
5987 
setEntireContentDefined()5988 void ImageHelper::setEntireContentDefined()
5989 {
5990     for (LevelContentDefinedMask &levelContentDefined : mContentDefined)
5991     {
5992         levelContentDefined.set();
5993     }
5994     for (LevelContentDefinedMask &levelContentDefined : mStencilContentDefined)
5995     {
5996         levelContentDefined.set();
5997     }
5998 }
5999 
setEntireContentUndefined()6000 void ImageHelper::setEntireContentUndefined()
6001 {
6002     for (LevelContentDefinedMask &levelContentDefined : mContentDefined)
6003     {
6004         levelContentDefined.reset();
6005     }
6006     for (LevelContentDefinedMask &levelContentDefined : mStencilContentDefined)
6007     {
6008         levelContentDefined.reset();
6009     }
6010 
6011     // Note: this function is typically called during init/release, but also when importing an image
6012     // from Vulkan, so unlike invalidateSubresourceContentImpl, it doesn't attempt to make sure
6013     // emulated formats have a clear staged.
6014 }
6015 
setContentDefined(LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags)6016 void ImageHelper::setContentDefined(LevelIndex levelStart,
6017                                     uint32_t levelCount,
6018                                     uint32_t layerStart,
6019                                     uint32_t layerCount,
6020                                     VkImageAspectFlags aspectFlags)
6021 {
6022     // Mark the range as defined.  Layers above 8 are discarded, and are always assumed to have
6023     // defined contents.
6024     if (layerStart >= kMaxContentDefinedLayerCount)
6025     {
6026         return;
6027     }
6028 
6029     uint8_t layerRangeBits =
6030         GetContentDefinedLayerRangeBits(layerStart, layerCount, kMaxContentDefinedLayerCount);
6031 
6032     for (uint32_t levelOffset = 0; levelOffset < levelCount; ++levelOffset)
6033     {
6034         LevelIndex level = levelStart + levelOffset;
6035 
6036         if ((aspectFlags & ~VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
6037         {
6038             getLevelContentDefined(level) |= layerRangeBits;
6039         }
6040         if ((aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
6041         {
6042             getLevelStencilContentDefined(level) |= layerRangeBits;
6043         }
6044     }
6045 }
6046 
getLevelContentDefined(LevelIndex level)6047 ImageHelper::LevelContentDefinedMask &ImageHelper::getLevelContentDefined(LevelIndex level)
6048 {
6049     return mContentDefined[level.get()];
6050 }
6051 
getLevelStencilContentDefined(LevelIndex level)6052 ImageHelper::LevelContentDefinedMask &ImageHelper::getLevelStencilContentDefined(LevelIndex level)
6053 {
6054     return mStencilContentDefined[level.get()];
6055 }
6056 
getLevelContentDefined(LevelIndex level) const6057 const ImageHelper::LevelContentDefinedMask &ImageHelper::getLevelContentDefined(
6058     LevelIndex level) const
6059 {
6060     return mContentDefined[level.get()];
6061 }
6062 
getLevelStencilContentDefined(LevelIndex level) const6063 const ImageHelper::LevelContentDefinedMask &ImageHelper::getLevelStencilContentDefined(
6064     LevelIndex level) const
6065 {
6066     return mStencilContentDefined[level.get()];
6067 }
6068 
deriveConversionDesc(Context * context,angle::FormatID actualFormatID,angle::FormatID intendedFormatID)6069 YcbcrConversionDesc ImageHelper::deriveConversionDesc(Context *context,
6070                                                       angle::FormatID actualFormatID,
6071                                                       angle::FormatID intendedFormatID)
6072 {
6073     YcbcrConversionDesc conversionDesc{};
6074     const angle::Format &actualFormat = angle::Format::Get(actualFormatID);
6075 
6076     if (actualFormat.isYUV)
6077     {
6078         // Build a suitable conversionDesc; the image is not external but may be YUV
6079         // if app is using ANGLE's YUV internalformat extensions.
6080         Renderer *renderer = context->getRenderer();
6081 
6082         // The Vulkan spec states: The potential format features of the sampler YCBCR conversion
6083         // must support VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT or
6084         // VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT
6085         constexpr VkFormatFeatureFlags kChromaSubSampleFeatureBits =
6086             VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT |
6087             VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT |
6088             VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT;
6089 
6090         VkFormatFeatureFlags supportedFeatureBits =
6091             renderer->getImageFormatFeatureBits(actualFormatID, kChromaSubSampleFeatureBits);
6092 
6093         VkChromaLocation supportedLocation =
6094             (supportedFeatureBits & VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT) != 0
6095                 ? VK_CHROMA_LOCATION_COSITED_EVEN
6096                 : VK_CHROMA_LOCATION_MIDPOINT;
6097         vk::YcbcrLinearFilterSupport linearFilterSupported =
6098             (supportedFeatureBits &
6099              VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT) != 0
6100                 ? vk::YcbcrLinearFilterSupport::Supported
6101                 : vk::YcbcrLinearFilterSupport::Unsupported;
6102 
6103         VkSamplerYcbcrModelConversion conversionModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601;
6104         VkSamplerYcbcrRange colorRange                = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW;
6105         VkFilter chromaFilter                         = kDefaultYCbCrChromaFilter;
6106         VkComponentMapping components                 = {
6107             VK_COMPONENT_SWIZZLE_IDENTITY,
6108             VK_COMPONENT_SWIZZLE_IDENTITY,
6109             VK_COMPONENT_SWIZZLE_IDENTITY,
6110             VK_COMPONENT_SWIZZLE_IDENTITY,
6111         };
6112 
6113         conversionDesc.update(renderer, 0, conversionModel, colorRange, supportedLocation,
6114                               supportedLocation, chromaFilter, components, intendedFormatID,
6115                               linearFilterSupported);
6116     }
6117 
6118     return conversionDesc;
6119 }
6120 
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)6121 angle::Result ImageHelper::init(Context *context,
6122                                 gl::TextureType textureType,
6123                                 const VkExtent3D &extents,
6124                                 const Format &format,
6125                                 GLint samples,
6126                                 VkImageUsageFlags usage,
6127                                 gl::LevelIndex firstLevel,
6128                                 uint32_t mipLevels,
6129                                 uint32_t layerCount,
6130                                 bool isRobustResourceInitEnabled,
6131                                 bool hasProtectedContent)
6132 {
6133     return initExternal(context, textureType, extents, format.getIntendedFormatID(),
6134                         format.getActualRenderableImageFormatID(), samples, usage,
6135                         kVkImageCreateFlagsNone, ImageLayout::Undefined, nullptr, firstLevel,
6136                         mipLevels, layerCount, isRobustResourceInitEnabled, hasProtectedContent,
6137                         deriveConversionDesc(context, format.getActualRenderableImageFormatID(),
6138                                              format.getIntendedFormatID()),
6139                         nullptr);
6140 }
6141 
initFromCreateInfo(Context * context,const VkImageCreateInfo & requestedCreateInfo,VkMemoryPropertyFlags memoryPropertyFlags)6142 angle::Result ImageHelper::initFromCreateInfo(Context *context,
6143                                               const VkImageCreateInfo &requestedCreateInfo,
6144                                               VkMemoryPropertyFlags memoryPropertyFlags)
6145 {
6146     ASSERT(!valid());
6147     ASSERT(!IsAnySubresourceContentDefined(mContentDefined));
6148     ASSERT(!IsAnySubresourceContentDefined(mStencilContentDefined));
6149 
6150     mImageType          = requestedCreateInfo.imageType;
6151     mExtents            = requestedCreateInfo.extent;
6152     mRotatedAspectRatio = false;
6153     mSamples            = std::max((int)requestedCreateInfo.samples, 1);
6154     mImageSerial        = context->getRenderer()->getResourceSerialFactory().generateImageSerial();
6155     mLayerCount         = requestedCreateInfo.arrayLayers;
6156     mLevelCount         = requestedCreateInfo.mipLevels;
6157     mUsage              = requestedCreateInfo.usage;
6158 
6159     // Validate that mLayerCount is compatible with the image type
6160     ASSERT(requestedCreateInfo.imageType != VK_IMAGE_TYPE_3D || mLayerCount == 1);
6161     ASSERT(requestedCreateInfo.imageType != VK_IMAGE_TYPE_2D || mExtents.depth == 1);
6162 
6163     mCurrentLayout = ImageLayout::Undefined;
6164 
6165     ANGLE_VK_TRY(context, mImage.init(context->getDevice(), requestedCreateInfo));
6166 
6167     mVkImageCreateInfo               = requestedCreateInfo;
6168     mVkImageCreateInfo.pNext         = nullptr;
6169     mVkImageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
6170 
6171     MemoryProperties memoryProperties = {};
6172 
6173     ANGLE_TRY(initMemoryAndNonZeroFillIfNeeded(context, false, memoryProperties,
6174                                                memoryPropertyFlags,
6175                                                vk::MemoryAllocationType::StagingImage));
6176     return angle::Result::Continue;
6177 }
6178 
copyToBufferOneOff(Context * context,BufferHelper * stagingBuffer,VkBufferImageCopy copyRegion)6179 angle::Result ImageHelper::copyToBufferOneOff(Context *context,
6180                                               BufferHelper *stagingBuffer,
6181                                               VkBufferImageCopy copyRegion)
6182 {
6183     Renderer *renderer = context->getRenderer();
6184     PrimaryCommandBuffer commandBuffer;
6185     ANGLE_TRY(
6186         renderer->getCommandBufferOneOff(context, ProtectionType::Unprotected, &commandBuffer));
6187 
6188     VkSemaphore acquireNextImageSemaphore;
6189     barrierImpl(context, getAspectFlags(), ImageLayout::TransferDst,
6190                 renderer->getQueueFamilyIndex(), nullptr, &commandBuffer,
6191                 &acquireNextImageSemaphore);
6192     commandBuffer.copyBufferToImage(stagingBuffer->getBuffer().getHandle(), getImage(),
6193                                     getCurrentLayout(renderer), 1, &copyRegion);
6194     ANGLE_VK_TRY(context, commandBuffer.end());
6195 
6196     QueueSerial submitQueueSerial;
6197     ANGLE_TRY(renderer->queueSubmitOneOff(
6198         context, std::move(commandBuffer), ProtectionType::Unprotected,
6199         egl::ContextPriority::Medium, acquireNextImageSemaphore,
6200         kSwapchainAcquireImageWaitStageFlags, SubmitPolicy::AllowDeferred, &submitQueueSerial));
6201 
6202     return renderer->finishQueueSerial(context, submitQueueSerial);
6203 }
6204 
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)6205 angle::Result ImageHelper::initMSAASwapchain(Context *context,
6206                                              gl::TextureType textureType,
6207                                              const VkExtent3D &extents,
6208                                              bool rotatedAspectRatio,
6209                                              const Format &format,
6210                                              GLint samples,
6211                                              VkImageUsageFlags usage,
6212                                              gl::LevelIndex firstLevel,
6213                                              uint32_t mipLevels,
6214                                              uint32_t layerCount,
6215                                              bool isRobustResourceInitEnabled,
6216                                              bool hasProtectedContent)
6217 {
6218     ANGLE_TRY(initExternal(context, textureType, extents, format.getIntendedFormatID(),
6219                            format.getActualRenderableImageFormatID(), samples, usage,
6220                            kVkImageCreateFlagsNone, ImageLayout::Undefined, nullptr, firstLevel,
6221                            mipLevels, layerCount, isRobustResourceInitEnabled, hasProtectedContent,
6222                            YcbcrConversionDesc{}, nullptr));
6223     if (rotatedAspectRatio)
6224     {
6225         std::swap(mExtents.width, mExtents.height);
6226     }
6227     mRotatedAspectRatio = rotatedAspectRatio;
6228     return angle::Result::Continue;
6229 }
6230 
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,const void * compressionControl)6231 angle::Result ImageHelper::initExternal(Context *context,
6232                                         gl::TextureType textureType,
6233                                         const VkExtent3D &extents,
6234                                         angle::FormatID intendedFormatID,
6235                                         angle::FormatID actualFormatID,
6236                                         GLint samples,
6237                                         VkImageUsageFlags usage,
6238                                         VkImageCreateFlags additionalCreateFlags,
6239                                         ImageLayout initialLayout,
6240                                         const void *externalImageCreateInfo,
6241                                         gl::LevelIndex firstLevel,
6242                                         uint32_t mipLevels,
6243                                         uint32_t layerCount,
6244                                         bool isRobustResourceInitEnabled,
6245                                         bool hasProtectedContent,
6246                                         YcbcrConversionDesc conversionDesc,
6247                                         const void *compressionControl)
6248 {
6249     ASSERT(!valid());
6250     ASSERT(!IsAnySubresourceContentDefined(mContentDefined));
6251     ASSERT(!IsAnySubresourceContentDefined(mStencilContentDefined));
6252 
6253     Renderer *renderer = context->getRenderer();
6254 
6255     mImageType           = gl_vk::GetImageType(textureType);
6256     mExtents             = extents;
6257     mRotatedAspectRatio  = false;
6258     mIntendedFormatID    = intendedFormatID;
6259     mActualFormatID      = actualFormatID;
6260     mSamples             = std::max(samples, 1);
6261     mImageSerial         = renderer->getResourceSerialFactory().generateImageSerial();
6262     mFirstAllocatedLevel = firstLevel;
6263     mLevelCount          = mipLevels;
6264     mLayerCount          = layerCount;
6265     mCreateFlags =
6266         vk::GetMinimalImageCreateFlags(renderer, textureType, usage) | additionalCreateFlags;
6267     mUsage = usage;
6268 
6269     // Validate that mLayerCount is compatible with the texture type
6270     ASSERT(textureType != gl::TextureType::_3D || mLayerCount == 1);
6271     ASSERT(textureType != gl::TextureType::_2DArray || mExtents.depth == 1);
6272     ASSERT(textureType != gl::TextureType::External || mLayerCount == 1);
6273     ASSERT(textureType != gl::TextureType::Rectangle || mLayerCount == 1);
6274     ASSERT(textureType != gl::TextureType::CubeMap || mLayerCount == gl::kCubeFaceCount);
6275     ASSERT(textureType != gl::TextureType::CubeMapArray || mLayerCount % gl::kCubeFaceCount == 0);
6276 
6277     // If externalImageCreateInfo is provided, use that directly.  Otherwise derive the necessary
6278     // pNext chain.
6279     const void *imageCreateInfoPNext = externalImageCreateInfo;
6280     VkImageFormatListCreateInfoKHR imageFormatListInfoStorage;
6281     ImageListFormats imageListFormatsStorage;
6282 
6283     if (externalImageCreateInfo == nullptr)
6284     {
6285         imageCreateInfoPNext = DeriveCreateInfoPNext(context, actualFormatID, compressionControl,
6286                                                      &imageFormatListInfoStorage,
6287                                                      &imageListFormatsStorage, &mCreateFlags);
6288     }
6289     else
6290     {
6291         // Derive the tiling for external images.
6292         deriveExternalImageTiling(externalImageCreateInfo);
6293     }
6294 
6295     mYcbcrConversionDesc = conversionDesc;
6296 
6297     const angle::Format &actualFormat   = angle::Format::Get(actualFormatID);
6298     const angle::Format &intendedFormat = angle::Format::Get(intendedFormatID);
6299     VkFormat actualVkFormat             = GetVkFormatFromFormatID(renderer, actualFormatID);
6300 
6301     ANGLE_TRACE_EVENT_INSTANT("gpu.angle.texture_metrics", "ImageHelper::initExternal",
6302                               "intended_format", intendedFormat.glInternalFormat, "actual_format",
6303                               actualFormat.glInternalFormat, "width", extents.width, "height",
6304                               extents.height);
6305 
6306     if (actualFormat.isYUV)
6307     {
6308         ASSERT(mYcbcrConversionDesc.valid());
6309 
6310         // The Vulkan spec states: If the pNext chain includes a VkExternalFormatANDROID structure
6311         // whose externalFormat member is not 0, flags must not include
6312         // VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT
6313         if (!IsYUVExternalFormat(actualFormatID))
6314         {
6315             // The Vulkan spec states: If sampler is used and the VkFormat of the image is a
6316             // multi-planar format, the image must have been created with
6317             // VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT
6318             mCreateFlags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
6319         }
6320     }
6321 
6322     if (hasProtectedContent)
6323     {
6324         mCreateFlags |= VK_IMAGE_CREATE_PROTECTED_BIT;
6325     }
6326 
6327     VkImageCreateInfo imageInfo = {};
6328     imageInfo.sType             = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
6329     imageInfo.pNext             = imageCreateInfoPNext;
6330     imageInfo.flags             = mCreateFlags;
6331     imageInfo.imageType         = mImageType;
6332     imageInfo.format            = actualVkFormat;
6333     imageInfo.extent            = mExtents;
6334     imageInfo.mipLevels         = mLevelCount;
6335     imageInfo.arrayLayers       = mLayerCount;
6336     imageInfo.samples =
6337         gl_vk::GetSamples(mSamples, context->getFeatures().limitSampleCountTo2.enabled);
6338     imageInfo.tiling                = mTilingMode;
6339     imageInfo.usage                 = mUsage;
6340     imageInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
6341     imageInfo.queueFamilyIndexCount = 0;
6342     imageInfo.pQueueFamilyIndices   = nullptr;
6343     imageInfo.initialLayout         = ConvertImageLayoutToVkImageLayout(renderer, initialLayout);
6344 
6345     mCurrentLayout               = initialLayout;
6346     mCurrentDeviceQueueIndex     = kInvalidDeviceQueueIndex;
6347     mIsReleasedToExternal        = false;
6348     mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
6349     mCurrentShaderReadStageMask  = 0;
6350 
6351     ANGLE_VK_TRY(context, mImage.init(context->getDevice(), imageInfo));
6352 
6353     // Find the image formats in pNext chain in imageInfo.
6354     deriveImageViewFormatFromCreateInfoPNext(imageInfo, mViewFormats);
6355 
6356     mVkImageCreateInfo               = imageInfo;
6357     mVkImageCreateInfo.pNext         = nullptr;
6358     mVkImageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
6359 
6360     stageClearIfEmulatedFormat(isRobustResourceInitEnabled, externalImageCreateInfo != nullptr);
6361 
6362     // Consider the contents defined for any image that has the PREINITIALIZED layout, or is
6363     // imported from external.
6364     if (initialLayout != ImageLayout::Undefined || externalImageCreateInfo != nullptr)
6365     {
6366         setEntireContentDefined();
6367     }
6368 
6369     return angle::Result::Continue;
6370 }
6371 
6372 // static
DeriveCreateInfoPNext(Context * context,angle::FormatID actualFormatID,const void * pNext,VkImageFormatListCreateInfoKHR * imageFormatListInfoStorage,std::array<VkFormat,kImageListFormatCount> * imageListFormatsStorage,VkImageCreateFlags * createFlagsOut)6373 const void *ImageHelper::DeriveCreateInfoPNext(
6374     Context *context,
6375     angle::FormatID actualFormatID,
6376     const void *pNext,
6377     VkImageFormatListCreateInfoKHR *imageFormatListInfoStorage,
6378     std::array<VkFormat, kImageListFormatCount> *imageListFormatsStorage,
6379     VkImageCreateFlags *createFlagsOut)
6380 {
6381     // With the introduction of sRGB related GLES extensions any sample/render target could be
6382     // respecified causing it to be interpreted in a different colorspace.  Create the VkImage
6383     // accordingly.
6384     Renderer *renderer                = context->getRenderer();
6385     const angle::Format &actualFormat = angle::Format::Get(actualFormatID);
6386     angle::FormatID additionalFormat =
6387         actualFormat.isSRGB ? ConvertToLinear(actualFormatID) : ConvertToSRGB(actualFormatID);
6388     (*imageListFormatsStorage)[0] = vk::GetVkFormatFromFormatID(renderer, actualFormatID);
6389     (*imageListFormatsStorage)[1] = vk::GetVkFormatFromFormatID(renderer, additionalFormat);
6390 
6391     if (renderer->getFeatures().supportsImageFormatList.enabled &&
6392         renderer->haveSameFormatFeatureBits(actualFormatID, additionalFormat))
6393     {
6394         // Add VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT to VkImage create flag
6395         *createFlagsOut |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
6396 
6397         // There is just 1 additional format we might use to create a VkImageView for this
6398         // VkImage
6399         imageFormatListInfoStorage->sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR;
6400         imageFormatListInfoStorage->pNext = pNext;
6401         imageFormatListInfoStorage->viewFormatCount = kImageListFormatCount;
6402         imageFormatListInfoStorage->pViewFormats    = imageListFormatsStorage->data();
6403 
6404         pNext = imageFormatListInfoStorage;
6405     }
6406 
6407     return pNext;
6408 }
6409 
6410 // static
FormatSupportsUsage(Renderer * renderer,VkFormat format,VkImageType imageType,VkImageTiling tilingMode,VkImageUsageFlags usageFlags,VkImageCreateFlags createFlags,void * formatInfoPNext,void * propertiesPNext,const FormatSupportCheck formatSupportCheck)6411 bool ImageHelper::FormatSupportsUsage(Renderer *renderer,
6412                                       VkFormat format,
6413                                       VkImageType imageType,
6414                                       VkImageTiling tilingMode,
6415                                       VkImageUsageFlags usageFlags,
6416                                       VkImageCreateFlags createFlags,
6417                                       void *formatInfoPNext,
6418                                       void *propertiesPNext,
6419                                       const FormatSupportCheck formatSupportCheck)
6420 {
6421     VkPhysicalDeviceImageFormatInfo2 imageFormatInfo = {};
6422     imageFormatInfo.sType  = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
6423     imageFormatInfo.pNext  = formatInfoPNext;
6424     imageFormatInfo.format = format;
6425     imageFormatInfo.type   = imageType;
6426     imageFormatInfo.tiling = tilingMode;
6427     imageFormatInfo.usage  = usageFlags;
6428     imageFormatInfo.flags  = createFlags;
6429 
6430     VkImageFormatProperties2 imageFormatProperties2 = {};
6431     imageFormatProperties2.sType                    = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
6432     imageFormatProperties2.pNext                    = propertiesPNext;
6433 
6434     VkResult result = vkGetPhysicalDeviceImageFormatProperties2(
6435         renderer->getPhysicalDevice(), &imageFormatInfo, &imageFormatProperties2);
6436 
6437     if (formatSupportCheck == FormatSupportCheck::RequireMultisampling)
6438     {
6439         // Some drivers return success but sampleCounts == 1 which means no MSRTT
6440         return result == VK_SUCCESS &&
6441                imageFormatProperties2.imageFormatProperties.sampleCounts > 1;
6442     }
6443     return result == VK_SUCCESS;
6444 }
6445 
setImageFormatsFromActualFormat(VkFormat actualFormat,ImageFormats & imageFormatsOut)6446 void ImageHelper::setImageFormatsFromActualFormat(VkFormat actualFormat,
6447                                                   ImageFormats &imageFormatsOut)
6448 {
6449     imageFormatsOut.push_back(actualFormat);
6450 }
6451 
deriveImageViewFormatFromCreateInfoPNext(VkImageCreateInfo & imageInfo,ImageFormats & formatOut)6452 void ImageHelper::deriveImageViewFormatFromCreateInfoPNext(VkImageCreateInfo &imageInfo,
6453                                                            ImageFormats &formatOut)
6454 {
6455     const VkBaseInStructure *pNextChain =
6456         reinterpret_cast<const VkBaseInStructure *>(imageInfo.pNext);
6457     while (pNextChain != nullptr &&
6458            pNextChain->sType != VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR)
6459     {
6460         pNextChain = pNextChain->pNext;
6461     }
6462 
6463     // Clear formatOut in case it has leftovers from previous VkImage in the case of releaseImage
6464     // followed by initExternal.
6465     std::fill(formatOut.begin(), formatOut.begin() + formatOut.max_size(), VK_FORMAT_UNDEFINED);
6466     if (pNextChain != nullptr)
6467     {
6468         const VkImageFormatListCreateInfoKHR *imageFormatCreateInfo =
6469             reinterpret_cast<const VkImageFormatListCreateInfoKHR *>(pNextChain);
6470 
6471         for (uint32_t i = 0; i < imageFormatCreateInfo->viewFormatCount; i++)
6472         {
6473             formatOut.push_back(*(imageFormatCreateInfo->pViewFormats + i));
6474         }
6475     }
6476     else
6477     {
6478         setImageFormatsFromActualFormat(imageInfo.format, formatOut);
6479     }
6480 }
6481 
deriveExternalImageTiling(const void * createInfoChain)6482 void ImageHelper::deriveExternalImageTiling(const void *createInfoChain)
6483 {
6484     const VkBaseInStructure *chain = reinterpret_cast<const VkBaseInStructure *>(createInfoChain);
6485     while (chain != nullptr)
6486     {
6487         if (chain->sType == VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT ||
6488             chain->sType == VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT)
6489         {
6490             mTilingMode = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
6491             return;
6492         }
6493 
6494         chain = reinterpret_cast<const VkBaseInStructure *>(chain->pNext);
6495     }
6496 }
6497 
releaseImage(Renderer * renderer)6498 void ImageHelper::releaseImage(Renderer *renderer)
6499 {
6500     // mDeviceMemory and mVmaAllocation should not be valid at the same time.
6501     ASSERT(!mDeviceMemory.valid() || !mVmaAllocation.valid());
6502     if (mDeviceMemory.valid())
6503     {
6504         renderer->onMemoryDealloc(mMemoryAllocationType, mAllocationSize, mMemoryTypeIndex,
6505                                   mDeviceMemory.getHandle());
6506     }
6507     if (mVmaAllocation.valid())
6508     {
6509         renderer->onMemoryDealloc(mMemoryAllocationType, mAllocationSize, mMemoryTypeIndex,
6510                                   mVmaAllocation.getHandle());
6511     }
6512     mCurrentEvent.release(renderer);
6513     mLastNonShaderReadOnlyEvent.release(renderer);
6514     renderer->collectGarbage(mUse, &mImage, &mDeviceMemory, &mVmaAllocation);
6515     mViewFormats.clear();
6516     mUse.reset();
6517     mImageSerial          = kInvalidImageSerial;
6518     mMemoryAllocationType = MemoryAllocationType::InvalidEnum;
6519     setEntireContentUndefined();
6520 }
6521 
releaseImageFromShareContexts(Renderer * renderer,ContextVk * contextVk,UniqueSerial imageSiblingSerial)6522 void ImageHelper::releaseImageFromShareContexts(Renderer *renderer,
6523                                                 ContextVk *contextVk,
6524                                                 UniqueSerial imageSiblingSerial)
6525 {
6526     finalizeImageLayoutInShareContexts(renderer, contextVk, imageSiblingSerial);
6527     contextVk->addToPendingImageGarbage(mUse, mAllocationSize);
6528     releaseImage(renderer);
6529 }
6530 
finalizeImageLayoutInShareContexts(Renderer * renderer,ContextVk * contextVk,UniqueSerial imageSiblingSerial)6531 void ImageHelper::finalizeImageLayoutInShareContexts(Renderer *renderer,
6532                                                      ContextVk *contextVk,
6533                                                      UniqueSerial imageSiblingSerial)
6534 {
6535     if (contextVk && mImageSerial.valid())
6536     {
6537         for (auto context : contextVk->getShareGroup()->getContexts())
6538         {
6539             vk::GetImpl(context.second)->finalizeImageLayout(this, imageSiblingSerial);
6540         }
6541     }
6542 }
6543 
releaseStagedUpdates(Renderer * renderer)6544 void ImageHelper::releaseStagedUpdates(Renderer *renderer)
6545 {
6546     ASSERT(validateSubresourceUpdateRefCountsConsistent());
6547 
6548     // Remove updates that never made it to the texture.
6549     for (std::vector<SubresourceUpdate> &levelUpdates : mSubresourceUpdates)
6550     {
6551         for (SubresourceUpdate &update : levelUpdates)
6552         {
6553             update.release(renderer);
6554         }
6555     }
6556 
6557     ASSERT(validateSubresourceUpdateRefCountsConsistent());
6558 
6559     mSubresourceUpdates.clear();
6560     mTotalStagedBufferUpdateSize = 0;
6561     mCurrentSingleClearValue.reset();
6562 }
6563 
resetImageWeakReference()6564 void ImageHelper::resetImageWeakReference()
6565 {
6566     mImage.reset();
6567     mImageSerial        = kInvalidImageSerial;
6568     mRotatedAspectRatio = false;
6569     // Caller must ensure ANI semaphores are properly waited or released.
6570     ASSERT(!mAcquireNextImageSemaphore.valid());
6571 }
6572 
initializeNonZeroMemory(Context * context,bool hasProtectedContent,VkMemoryPropertyFlags flags,VkDeviceSize size)6573 angle::Result ImageHelper::initializeNonZeroMemory(Context *context,
6574                                                    bool hasProtectedContent,
6575                                                    VkMemoryPropertyFlags flags,
6576                                                    VkDeviceSize size)
6577 {
6578     // If available, memory mapping should be used.
6579     Renderer *renderer = context->getRenderer();
6580 
6581     if ((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
6582     {
6583         // Wipe memory to an invalid value when the 'allocateNonZeroMemory' feature is enabled. The
6584         // invalid values ensures our testing doesn't assume zero-initialized memory.
6585         constexpr int kNonZeroInitValue = 0x3F;
6586         if (renderer->getFeatures().useVmaForImageSuballocation.enabled)
6587         {
6588             ANGLE_VK_TRY(context,
6589                          renderer->getImageMemorySuballocator().mapMemoryAndInitWithNonZeroValue(
6590                              renderer, &mVmaAllocation, size, kNonZeroInitValue, flags));
6591         }
6592         else
6593         {
6594             ANGLE_TRY(vk::InitMappableDeviceMemory(context, &mDeviceMemory, size, kNonZeroInitValue,
6595                                                    flags));
6596         }
6597 
6598         return angle::Result::Continue;
6599     }
6600 
6601     // If mapping the memory is unavailable, a staging resource is used.
6602     const angle::Format &angleFormat = getActualFormat();
6603     bool isCompressedFormat          = angleFormat.isBlock;
6604 
6605     if (angleFormat.isYUV)
6606     {
6607         // VUID-vkCmdClearColorImage-image-01545
6608         // vkCmdClearColorImage(): format must not be one of the formats requiring sampler YCBCR
6609         // conversion for VK_IMAGE_ASPECT_COLOR_BIT image views
6610         return angle::Result::Continue;
6611     }
6612 
6613     // Since we are going to do a one off out of order submission, there shouldn't any pending
6614     // setEvent.
6615     ASSERT(!mCurrentEvent.valid());
6616 
6617     PrimaryCommandBuffer commandBuffer;
6618     auto protectionType = ConvertProtectionBoolToType(hasProtectedContent);
6619     ANGLE_TRY(renderer->getCommandBufferOneOff(context, protectionType, &commandBuffer));
6620 
6621     // Queue a DMA copy.
6622     VkSemaphore acquireNextImageSemaphore;
6623     barrierImpl(context, getAspectFlags(), ImageLayout::TransferDst, context->getDeviceQueueIndex(),
6624                 nullptr, &commandBuffer, &acquireNextImageSemaphore);
6625     // SwapChain image should not come here
6626     ASSERT(acquireNextImageSemaphore == VK_NULL_HANDLE);
6627 
6628     StagingBuffer stagingBuffer;
6629 
6630     if (isCompressedFormat)
6631     {
6632         // If format is compressed, set its contents through buffer copies.
6633 
6634         // The staging buffer memory is non-zero-initialized in 'init'.
6635         ANGLE_TRY(stagingBuffer.init(context, size, StagingUsage::Write));
6636 
6637         for (LevelIndex level(0); level < LevelIndex(mLevelCount); ++level)
6638         {
6639             VkBufferImageCopy copyRegion = {};
6640 
6641             gl_vk::GetExtent(getLevelExtents(level), &copyRegion.imageExtent);
6642             copyRegion.imageSubresource.aspectMask = getAspectFlags();
6643             copyRegion.imageSubresource.layerCount = mLayerCount;
6644 
6645             // If image has depth and stencil, copy to each individually per Vulkan spec.
6646             bool hasBothDepthAndStencil = isCombinedDepthStencilFormat();
6647             if (hasBothDepthAndStencil)
6648             {
6649                 copyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
6650             }
6651 
6652             commandBuffer.copyBufferToImage(stagingBuffer.getBuffer().getHandle(), mImage,
6653                                             VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copyRegion);
6654 
6655             if (hasBothDepthAndStencil)
6656             {
6657                 copyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
6658 
6659                 commandBuffer.copyBufferToImage(stagingBuffer.getBuffer().getHandle(), mImage,
6660                                                 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1,
6661                                                 &copyRegion);
6662             }
6663         }
6664     }
6665     else
6666     {
6667         // Otherwise issue clear commands.
6668         VkImageSubresourceRange subresource = {};
6669         subresource.aspectMask              = getAspectFlags();
6670         subresource.baseMipLevel            = 0;
6671         subresource.levelCount              = mLevelCount;
6672         subresource.baseArrayLayer          = 0;
6673         subresource.layerCount              = mLayerCount;
6674 
6675         // Arbitrary value to initialize the memory with.  Note: the given uint value, reinterpreted
6676         // as float is about 0.7.
6677         constexpr uint32_t kInitValue   = 0x3F345678;
6678         constexpr float kInitValueFloat = 0.12345f;
6679 
6680         if ((subresource.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != 0)
6681         {
6682             VkClearColorValue clearValue;
6683             clearValue.uint32[0] = kInitValue;
6684             clearValue.uint32[1] = kInitValue;
6685             clearValue.uint32[2] = kInitValue;
6686             clearValue.uint32[3] = kInitValue;
6687 
6688             commandBuffer.clearColorImage(mImage, getCurrentLayout(renderer), clearValue, 1,
6689                                           &subresource);
6690         }
6691         else
6692         {
6693             VkClearDepthStencilValue clearValue;
6694             clearValue.depth   = kInitValueFloat;
6695             clearValue.stencil = kInitValue;
6696 
6697             commandBuffer.clearDepthStencilImage(mImage, getCurrentLayout(renderer), clearValue, 1,
6698                                                  &subresource);
6699         }
6700     }
6701 
6702     ANGLE_VK_TRY(context, commandBuffer.end());
6703 
6704     QueueSerial queueSerial;
6705     ANGLE_TRY(renderer->queueSubmitOneOff(context, std::move(commandBuffer), protectionType,
6706                                           egl::ContextPriority::Medium, VK_NULL_HANDLE, 0,
6707                                           vk::SubmitPolicy::AllowDeferred, &queueSerial));
6708 
6709     if (isCompressedFormat)
6710     {
6711         stagingBuffer.collectGarbage(renderer, queueSerial);
6712     }
6713     mUse.setQueueSerial(queueSerial);
6714 
6715     return angle::Result::Continue;
6716 }
6717 
initMemory(Context * context,const MemoryProperties & memoryProperties,VkMemoryPropertyFlags flags,VkMemoryPropertyFlags excludedFlags,const VkMemoryRequirements * memoryRequirements,const bool allocateDedicatedMemory,MemoryAllocationType allocationType,VkMemoryPropertyFlags * flagsOut,VkDeviceSize * sizeOut)6718 VkResult ImageHelper::initMemory(Context *context,
6719                                  const MemoryProperties &memoryProperties,
6720                                  VkMemoryPropertyFlags flags,
6721                                  VkMemoryPropertyFlags excludedFlags,
6722                                  const VkMemoryRequirements *memoryRequirements,
6723                                  const bool allocateDedicatedMemory,
6724                                  MemoryAllocationType allocationType,
6725                                  VkMemoryPropertyFlags *flagsOut,
6726                                  VkDeviceSize *sizeOut)
6727 {
6728     mMemoryAllocationType = allocationType;
6729 
6730     // To allocate memory here, if possible, we use the image memory suballocator which uses VMA.
6731     ASSERT(excludedFlags < VK_MEMORY_PROPERTY_FLAG_BITS_MAX_ENUM);
6732     Renderer *renderer = context->getRenderer();
6733     if (renderer->getFeatures().useVmaForImageSuballocation.enabled)
6734     {
6735         // While it may be preferable to allocate the image on the device, it should also be
6736         // possible to allocate on other memory types if the device is out of memory.
6737         VkMemoryPropertyFlags requiredFlags  = flags & (~excludedFlags);
6738         VkMemoryPropertyFlags preferredFlags = flags;
6739         VK_RESULT_TRY(renderer->getImageMemorySuballocator().allocateAndBindMemory(
6740             context, &mImage, &mVkImageCreateInfo, requiredFlags, preferredFlags,
6741             memoryRequirements, allocateDedicatedMemory, mMemoryAllocationType, &mVmaAllocation,
6742             flagsOut, &mMemoryTypeIndex, &mAllocationSize));
6743     }
6744     else
6745     {
6746         VK_RESULT_TRY(AllocateImageMemory(context, mMemoryAllocationType, flags, flagsOut, nullptr,
6747                                           &mImage, &mMemoryTypeIndex, &mDeviceMemory,
6748                                           &mAllocationSize));
6749     }
6750 
6751     mCurrentDeviceQueueIndex = context->getDeviceQueueIndex();
6752     mIsReleasedToExternal    = false;
6753     *sizeOut                 = mAllocationSize;
6754 
6755     return VK_SUCCESS;
6756 }
6757 
initMemoryAndNonZeroFillIfNeeded(Context * context,bool hasProtectedContent,const MemoryProperties & memoryProperties,VkMemoryPropertyFlags flags,MemoryAllocationType allocationType)6758 angle::Result ImageHelper::initMemoryAndNonZeroFillIfNeeded(
6759     Context *context,
6760     bool hasProtectedContent,
6761     const MemoryProperties &memoryProperties,
6762     VkMemoryPropertyFlags flags,
6763     MemoryAllocationType allocationType)
6764 {
6765     Renderer *renderer = context->getRenderer();
6766     VkMemoryPropertyFlags outputFlags;
6767     VkDeviceSize outputSize;
6768 
6769     if (hasProtectedContent)
6770     {
6771         flags |= VK_MEMORY_PROPERTY_PROTECTED_BIT;
6772     }
6773 
6774     // Get memory requirements for the allocation.
6775     VkMemoryRequirements memoryRequirements;
6776     mImage.getMemoryRequirements(renderer->getDevice(), &memoryRequirements);
6777     bool allocateDedicatedMemory =
6778         renderer->getImageMemorySuballocator().needsDedicatedMemory(memoryRequirements.size);
6779 
6780     ANGLE_VK_TRY(context,
6781                  initMemory(context, memoryProperties, flags, 0, &memoryRequirements,
6782                             allocateDedicatedMemory, allocationType, &outputFlags, &outputSize));
6783 
6784     if (renderer->getFeatures().allocateNonZeroMemory.enabled)
6785     {
6786         ANGLE_TRY(initializeNonZeroMemory(context, hasProtectedContent, outputFlags, outputSize));
6787     }
6788     return angle::Result::Continue;
6789 }
6790 
initExternalMemory(Context * context,const MemoryProperties & memoryProperties,const VkMemoryRequirements & memoryRequirements,uint32_t extraAllocationInfoCount,const void ** extraAllocationInfo,DeviceQueueIndex currentDeviceQueueIndex,VkMemoryPropertyFlags flags)6791 angle::Result ImageHelper::initExternalMemory(Context *context,
6792                                               const MemoryProperties &memoryProperties,
6793                                               const VkMemoryRequirements &memoryRequirements,
6794                                               uint32_t extraAllocationInfoCount,
6795                                               const void **extraAllocationInfo,
6796                                               DeviceQueueIndex currentDeviceQueueIndex,
6797                                               VkMemoryPropertyFlags flags)
6798 {
6799     // Vulkan allows up to 4 memory planes.
6800     constexpr size_t kMaxMemoryPlanes                                     = 4;
6801     constexpr VkImageAspectFlagBits kMemoryPlaneAspects[kMaxMemoryPlanes] = {
6802         VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT,
6803         VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT,
6804         VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT,
6805         VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT,
6806     };
6807     ASSERT(extraAllocationInfoCount <= kMaxMemoryPlanes);
6808 
6809     VkBindImagePlaneMemoryInfoKHR bindImagePlaneMemoryInfo = {};
6810     bindImagePlaneMemoryInfo.sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO;
6811 
6812     const VkBindImagePlaneMemoryInfoKHR *bindImagePlaneMemoryInfoPtr =
6813         extraAllocationInfoCount == 1 ? nullptr : &bindImagePlaneMemoryInfo;
6814 
6815     mAllocationSize       = memoryRequirements.size;
6816     mMemoryAllocationType = MemoryAllocationType::ImageExternal;
6817 
6818     for (uint32_t memoryPlane = 0; memoryPlane < extraAllocationInfoCount; ++memoryPlane)
6819     {
6820         bindImagePlaneMemoryInfo.planeAspect = kMemoryPlaneAspects[memoryPlane];
6821 
6822         ANGLE_VK_TRY(context, AllocateImageMemoryWithRequirements(
6823                                   context, mMemoryAllocationType, flags, memoryRequirements,
6824                                   extraAllocationInfo[memoryPlane], bindImagePlaneMemoryInfoPtr,
6825                                   &mImage, &mMemoryTypeIndex, &mDeviceMemory));
6826     }
6827     mCurrentDeviceQueueIndex = currentDeviceQueueIndex;
6828     mIsReleasedToExternal    = false;
6829 
6830     return angle::Result::Continue;
6831 }
6832 
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) const6833 angle::Result ImageHelper::initLayerImageView(Context *context,
6834                                               gl::TextureType textureType,
6835                                               VkImageAspectFlags aspectMask,
6836                                               const gl::SwizzleState &swizzleMap,
6837                                               ImageView *imageViewOut,
6838                                               LevelIndex baseMipLevelVk,
6839                                               uint32_t levelCount,
6840                                               uint32_t baseArrayLayer,
6841                                               uint32_t layerCount) const
6842 {
6843     return initLayerImageViewImpl(context, textureType, aspectMask, swizzleMap, imageViewOut,
6844                                   baseMipLevelVk, levelCount, baseArrayLayer, layerCount,
6845                                   GetVkFormatFromFormatID(context->getRenderer(), mActualFormatID),
6846                                   kDefaultImageViewUsageFlags, gl::YuvSamplingMode::Default);
6847 }
6848 
initLayerImageViewWithUsage(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) const6849 angle::Result ImageHelper::initLayerImageViewWithUsage(Context *context,
6850                                                        gl::TextureType textureType,
6851                                                        VkImageAspectFlags aspectMask,
6852                                                        const gl::SwizzleState &swizzleMap,
6853                                                        ImageView *imageViewOut,
6854                                                        LevelIndex baseMipLevelVk,
6855                                                        uint32_t levelCount,
6856                                                        uint32_t baseArrayLayer,
6857                                                        uint32_t layerCount,
6858                                                        VkImageUsageFlags imageUsageFlags) const
6859 {
6860     return initLayerImageViewImpl(context, textureType, aspectMask, swizzleMap, imageViewOut,
6861                                   baseMipLevelVk, levelCount, baseArrayLayer, layerCount,
6862                                   GetVkFormatFromFormatID(context->getRenderer(), mActualFormatID),
6863                                   imageUsageFlags, gl::YuvSamplingMode::Default);
6864 }
6865 
initLayerImageViewWithYuvModeOverride(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::YuvSamplingMode yuvSamplingMode,VkImageUsageFlags imageUsageFlags) const6866 angle::Result ImageHelper::initLayerImageViewWithYuvModeOverride(
6867     Context *context,
6868     gl::TextureType textureType,
6869     VkImageAspectFlags aspectMask,
6870     const gl::SwizzleState &swizzleMap,
6871     ImageView *imageViewOut,
6872     LevelIndex baseMipLevelVk,
6873     uint32_t levelCount,
6874     uint32_t baseArrayLayer,
6875     uint32_t layerCount,
6876     gl::YuvSamplingMode yuvSamplingMode,
6877     VkImageUsageFlags imageUsageFlags) const
6878 {
6879     return initLayerImageViewImpl(context, textureType, aspectMask, swizzleMap, imageViewOut,
6880                                   baseMipLevelVk, levelCount, baseArrayLayer, layerCount,
6881                                   GetVkFormatFromFormatID(context->getRenderer(), mActualFormatID),
6882                                   imageUsageFlags, yuvSamplingMode);
6883 }
6884 
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) const6885 angle::Result ImageHelper::initLayerImageViewImpl(Context *context,
6886                                                   gl::TextureType textureType,
6887                                                   VkImageAspectFlags aspectMask,
6888                                                   const gl::SwizzleState &swizzleMap,
6889                                                   ImageView *imageViewOut,
6890                                                   LevelIndex baseMipLevelVk,
6891                                                   uint32_t levelCount,
6892                                                   uint32_t baseArrayLayer,
6893                                                   uint32_t layerCount,
6894                                                   VkFormat imageFormat,
6895                                                   VkImageUsageFlags usageFlags,
6896                                                   gl::YuvSamplingMode yuvSamplingMode) const
6897 {
6898     VkImageViewCreateInfo viewInfo = {};
6899     viewInfo.sType                 = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
6900     viewInfo.flags                 = 0;
6901     viewInfo.image                 = mImage.getHandle();
6902     viewInfo.viewType              = gl_vk::GetImageViewType(textureType);
6903     viewInfo.format                = imageFormat;
6904 
6905     if (swizzleMap.swizzleRequired() && !mYcbcrConversionDesc.valid())
6906     {
6907         viewInfo.components.r = gl_vk::GetSwizzle(swizzleMap.swizzleRed);
6908         viewInfo.components.g = gl_vk::GetSwizzle(swizzleMap.swizzleGreen);
6909         viewInfo.components.b = gl_vk::GetSwizzle(swizzleMap.swizzleBlue);
6910         viewInfo.components.a = gl_vk::GetSwizzle(swizzleMap.swizzleAlpha);
6911     }
6912     else
6913     {
6914         viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
6915         viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
6916         viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
6917         viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
6918     }
6919     viewInfo.subresourceRange.aspectMask     = aspectMask;
6920     viewInfo.subresourceRange.baseMipLevel   = baseMipLevelVk.get();
6921     viewInfo.subresourceRange.levelCount     = levelCount;
6922     viewInfo.subresourceRange.baseArrayLayer = baseArrayLayer;
6923     viewInfo.subresourceRange.layerCount     = layerCount;
6924 
6925     VkImageViewUsageCreateInfo imageViewUsageCreateInfo = {};
6926     if (usageFlags)
6927     {
6928         imageViewUsageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO;
6929         imageViewUsageCreateInfo.usage = usageFlags;
6930 
6931         viewInfo.pNext = &imageViewUsageCreateInfo;
6932     }
6933 
6934     VkSamplerYcbcrConversionInfo yuvConversionInfo = {};
6935 
6936     auto conversionDesc =
6937         yuvSamplingMode == gl::YuvSamplingMode::Y2Y ? getY2YConversionDesc() : mYcbcrConversionDesc;
6938 
6939     if (conversionDesc.valid())
6940     {
6941         ASSERT((context->getFeatures().supportsYUVSamplerConversion.enabled));
6942         yuvConversionInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO;
6943         yuvConversionInfo.pNext = nullptr;
6944         ANGLE_TRY(context->getRenderer()->getYuvConversionCache().getSamplerYcbcrConversion(
6945             context, conversionDesc, &yuvConversionInfo.conversion));
6946         AddToPNextChain(&viewInfo, &yuvConversionInfo);
6947 
6948         // VUID-VkImageViewCreateInfo-image-02399
6949         // If image has an external format, format must be VK_FORMAT_UNDEFINED
6950         if (conversionDesc.getExternalFormat() != 0)
6951         {
6952             viewInfo.format = VK_FORMAT_UNDEFINED;
6953         }
6954     }
6955     ANGLE_VK_TRY(context, imageViewOut->init(context->getDevice(), viewInfo));
6956     return angle::Result::Continue;
6957 }
6958 
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) const6959 angle::Result ImageHelper::initReinterpretedLayerImageView(Context *context,
6960                                                            gl::TextureType textureType,
6961                                                            VkImageAspectFlags aspectMask,
6962                                                            const gl::SwizzleState &swizzleMap,
6963                                                            ImageView *imageViewOut,
6964                                                            LevelIndex baseMipLevelVk,
6965                                                            uint32_t levelCount,
6966                                                            uint32_t baseArrayLayer,
6967                                                            uint32_t layerCount,
6968                                                            VkImageUsageFlags imageUsageFlags,
6969                                                            angle::FormatID imageViewFormat) const
6970 {
6971     VkImageUsageFlags usageFlags =
6972         imageUsageFlags & GetMaximalImageUsageFlags(context->getRenderer(), imageViewFormat);
6973 
6974     return initLayerImageViewImpl(
6975         context, textureType, aspectMask, swizzleMap, imageViewOut, baseMipLevelVk, levelCount,
6976         baseArrayLayer, layerCount,
6977         vk::GetVkFormatFromFormatID(context->getRenderer(), imageViewFormat), usageFlags,
6978         gl::YuvSamplingMode::Default);
6979 }
6980 
destroy(Renderer * renderer)6981 void ImageHelper::destroy(Renderer *renderer)
6982 {
6983     VkDevice device = renderer->getDevice();
6984 
6985     // mDeviceMemory and mVmaAllocation should not be valid at the same time.
6986     ASSERT(!mDeviceMemory.valid() || !mVmaAllocation.valid());
6987     if (mDeviceMemory.valid())
6988     {
6989         renderer->onMemoryDealloc(mMemoryAllocationType, mAllocationSize, mMemoryTypeIndex,
6990                                   mDeviceMemory.getHandle());
6991     }
6992     if (mVmaAllocation.valid())
6993     {
6994         renderer->onMemoryDealloc(mMemoryAllocationType, mAllocationSize, mMemoryTypeIndex,
6995                                   mVmaAllocation.getHandle());
6996     }
6997 
6998     mCurrentEvent.release(renderer);
6999     mLastNonShaderReadOnlyEvent.release(renderer);
7000     mImage.destroy(device);
7001     mDeviceMemory.destroy(device);
7002     mVmaAllocation.destroy(renderer->getAllocator());
7003     mCurrentLayout        = ImageLayout::Undefined;
7004     mImageType            = VK_IMAGE_TYPE_2D;
7005     mLayerCount           = 0;
7006     mLevelCount           = 0;
7007     mMemoryAllocationType = MemoryAllocationType::InvalidEnum;
7008 
7009     setEntireContentUndefined();
7010 }
7011 
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)7012 void ImageHelper::init2DWeakReference(Context *context,
7013                                       VkImage handle,
7014                                       const gl::Extents &glExtents,
7015                                       bool rotatedAspectRatio,
7016                                       angle::FormatID intendedFormatID,
7017                                       angle::FormatID actualFormatID,
7018                                       VkImageCreateFlags createFlags,
7019                                       VkImageUsageFlags usage,
7020                                       GLint samples,
7021                                       bool isRobustResourceInitEnabled)
7022 {
7023     ASSERT(!valid());
7024     ASSERT(!IsAnySubresourceContentDefined(mContentDefined));
7025     ASSERT(!IsAnySubresourceContentDefined(mStencilContentDefined));
7026     vk::Renderer *renderer = context->getRenderer();
7027 
7028     gl_vk::GetExtent(glExtents, &mExtents);
7029     mRotatedAspectRatio      = rotatedAspectRatio;
7030     mIntendedFormatID        = intendedFormatID;
7031     mActualFormatID          = actualFormatID;
7032     mCreateFlags             = createFlags;
7033     mUsage                   = usage;
7034     mSamples                 = std::max(samples, 1);
7035     mImageSerial             = renderer->getResourceSerialFactory().generateImageSerial();
7036     mCurrentDeviceQueueIndex = context->getDeviceQueueIndex();
7037     mIsReleasedToExternal    = false;
7038     mCurrentLayout           = ImageLayout::Undefined;
7039     mLayerCount              = 1;
7040     mLevelCount              = 1;
7041 
7042     // The view formats and usage flags are used for imageless framebuffers. Here, the former is set
7043     // similar to deriveImageViewFormatFromCreateInfoPNext() when there is no pNext from a
7044     // VkImageCreateInfo object.
7045     setImageFormatsFromActualFormat(GetVkFormatFromFormatID(renderer, actualFormatID),
7046                                     mViewFormats);
7047 
7048     mImage.setHandle(handle);
7049 
7050     stageClearIfEmulatedFormat(isRobustResourceInitEnabled, false);
7051 }
7052 
init2DStaging(Context * context,bool hasProtectedContent,const MemoryProperties & memoryProperties,const gl::Extents & glExtents,angle::FormatID intendedFormatID,angle::FormatID actualFormatID,VkImageUsageFlags usage,uint32_t layerCount)7053 angle::Result ImageHelper::init2DStaging(Context *context,
7054                                          bool hasProtectedContent,
7055                                          const MemoryProperties &memoryProperties,
7056                                          const gl::Extents &glExtents,
7057                                          angle::FormatID intendedFormatID,
7058                                          angle::FormatID actualFormatID,
7059                                          VkImageUsageFlags usage,
7060                                          uint32_t layerCount)
7061 {
7062     gl_vk::GetExtent(glExtents, &mExtents);
7063 
7064     return initStaging(context, hasProtectedContent, memoryProperties, VK_IMAGE_TYPE_2D, mExtents,
7065                        intendedFormatID, actualFormatID, 1, usage, 1, layerCount);
7066 }
7067 
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)7068 angle::Result ImageHelper::initStaging(Context *context,
7069                                        bool hasProtectedContent,
7070                                        const MemoryProperties &memoryProperties,
7071                                        VkImageType imageType,
7072                                        const VkExtent3D &extents,
7073                                        angle::FormatID intendedFormatID,
7074                                        angle::FormatID actualFormatID,
7075                                        GLint samples,
7076                                        VkImageUsageFlags usage,
7077                                        uint32_t mipLevels,
7078                                        uint32_t layerCount)
7079 {
7080     ASSERT(!valid());
7081     ASSERT(!IsAnySubresourceContentDefined(mContentDefined));
7082     ASSERT(!IsAnySubresourceContentDefined(mStencilContentDefined));
7083     vk::Renderer *renderer = context->getRenderer();
7084 
7085     mImageType          = imageType;
7086     mExtents            = extents;
7087     mRotatedAspectRatio = false;
7088     mIntendedFormatID   = intendedFormatID;
7089     mActualFormatID     = actualFormatID;
7090     mSamples            = std::max(samples, 1);
7091     mImageSerial        = renderer->getResourceSerialFactory().generateImageSerial();
7092     mLayerCount         = layerCount;
7093     mLevelCount         = mipLevels;
7094     mUsage              = usage;
7095 
7096     // Validate that mLayerCount is compatible with the image type
7097     ASSERT(imageType != VK_IMAGE_TYPE_3D || mLayerCount == 1);
7098     ASSERT(imageType != VK_IMAGE_TYPE_2D || mExtents.depth == 1);
7099 
7100     mCurrentLayout = ImageLayout::Undefined;
7101 
7102     VkImageCreateInfo imageInfo = {};
7103     imageInfo.sType             = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
7104     imageInfo.flags             = hasProtectedContent ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
7105     imageInfo.imageType         = mImageType;
7106     imageInfo.format            = GetVkFormatFromFormatID(renderer, actualFormatID);
7107     imageInfo.extent            = mExtents;
7108     imageInfo.mipLevels         = mLevelCount;
7109     imageInfo.arrayLayers       = mLayerCount;
7110     imageInfo.samples =
7111         gl_vk::GetSamples(mSamples, context->getFeatures().limitSampleCountTo2.enabled);
7112     imageInfo.tiling                = VK_IMAGE_TILING_OPTIMAL;
7113     imageInfo.usage                 = usage;
7114     imageInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
7115     imageInfo.queueFamilyIndexCount = 0;
7116     imageInfo.pQueueFamilyIndices   = nullptr;
7117     imageInfo.initialLayout         = getCurrentLayout(context->getRenderer());
7118 
7119     ANGLE_VK_TRY(context, mImage.init(context->getDevice(), imageInfo));
7120 
7121     mVkImageCreateInfo               = imageInfo;
7122     mVkImageCreateInfo.pNext         = nullptr;
7123     mVkImageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
7124 
7125     // Allocate and bind device-local memory.
7126     VkMemoryPropertyFlags memoryPropertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
7127     if (hasProtectedContent)
7128     {
7129         memoryPropertyFlags |= VK_MEMORY_PROPERTY_PROTECTED_BIT;
7130     }
7131 
7132     ANGLE_TRY(initMemoryAndNonZeroFillIfNeeded(context, hasProtectedContent, memoryProperties,
7133                                                memoryPropertyFlags,
7134                                                vk::MemoryAllocationType::StagingImage));
7135     return angle::Result::Continue;
7136 }
7137 
initImplicitMultisampledRenderToTexture(Context * context,bool hasProtectedContent,const MemoryProperties & memoryProperties,gl::TextureType textureType,GLint samples,const ImageHelper & resolveImage,const VkExtent3D & multisampleImageExtents,bool isRobustResourceInitEnabled)7138 angle::Result ImageHelper::initImplicitMultisampledRenderToTexture(
7139     Context *context,
7140     bool hasProtectedContent,
7141     const MemoryProperties &memoryProperties,
7142     gl::TextureType textureType,
7143     GLint samples,
7144     const ImageHelper &resolveImage,
7145     const VkExtent3D &multisampleImageExtents,
7146     bool isRobustResourceInitEnabled)
7147 {
7148     ASSERT(!valid());
7149     ASSERT(samples > 1);
7150     ASSERT(!IsAnySubresourceContentDefined(mContentDefined));
7151     ASSERT(!IsAnySubresourceContentDefined(mStencilContentDefined));
7152 
7153     // The image is used as either color or depth/stencil attachment.  Additionally, its memory is
7154     // lazily allocated as the contents are discarded at the end of the renderpass and with tiling
7155     // GPUs no actual backing memory is required.
7156     //
7157     // Note that the Vulkan image is created with or without VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT
7158     // based on whether the memory that will be used to create the image would have
7159     // VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT.  TRANSIENT is provided if there is any memory that
7160     // supports LAZILY_ALLOCATED.  However, based on actual image requirements, such a memory may
7161     // not be suitable for the image.  We don't support such a case, which will result in the
7162     // |initMemory| call below failing.
7163     const bool hasLazilyAllocatedMemory = memoryProperties.hasLazilyAllocatedMemory();
7164 
7165     const VkImageUsageFlags kLazyFlags =
7166         hasLazilyAllocatedMemory ? VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT : 0;
7167     constexpr VkImageUsageFlags kColorFlags =
7168         VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
7169     constexpr VkImageUsageFlags kDepthStencilFlags =
7170         VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
7171 
7172     const VkImageUsageFlags kMultisampledUsageFlags =
7173         kLazyFlags |
7174         (resolveImage.getAspectFlags() == VK_IMAGE_ASPECT_COLOR_BIT ? kColorFlags
7175                                                                     : kDepthStencilFlags);
7176     const VkImageCreateFlags kMultisampledCreateFlags =
7177         hasProtectedContent ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
7178 
7179     // Multisampled images have only 1 level
7180     constexpr uint32_t kLevelCount = 1;
7181 
7182     ANGLE_TRY(initExternal(context, textureType, multisampleImageExtents,
7183                            resolveImage.getIntendedFormatID(), resolveImage.getActualFormatID(),
7184                            samples, kMultisampledUsageFlags, kMultisampledCreateFlags,
7185                            ImageLayout::Undefined, nullptr, resolveImage.getFirstAllocatedLevel(),
7186                            kLevelCount, resolveImage.getLayerCount(), isRobustResourceInitEnabled,
7187                            hasProtectedContent, YcbcrConversionDesc{}, nullptr));
7188 
7189     // Remove the emulated format clear from the multisampled image if any.  There is one already
7190     // staged on the resolve image if needed.
7191     removeStagedUpdates(context, getFirstAllocatedLevel(), getLastAllocatedLevel());
7192 
7193     const VkMemoryPropertyFlags kMultisampledMemoryFlags =
7194         VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
7195         (hasLazilyAllocatedMemory ? VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT : 0) |
7196         (hasProtectedContent ? VK_MEMORY_PROPERTY_PROTECTED_BIT : 0);
7197 
7198     // If this ever fails, it can be retried without the LAZILY_ALLOCATED flag (which will probably
7199     // still fail), but ideally that means GL_EXT_multisampled_render_to_texture should not be
7200     // advertized on this platform in the first place.
7201     ANGLE_TRY(initMemoryAndNonZeroFillIfNeeded(
7202         context, hasProtectedContent, memoryProperties, kMultisampledMemoryFlags,
7203         vk::MemoryAllocationType::ImplicitMultisampledRenderToTextureImage));
7204     return angle::Result::Continue;
7205 }
7206 
getAspectFlags() const7207 VkImageAspectFlags ImageHelper::getAspectFlags() const
7208 {
7209     return GetFormatAspectFlags(angle::Format::Get(mActualFormatID));
7210 }
7211 
isCombinedDepthStencilFormat() const7212 bool ImageHelper::isCombinedDepthStencilFormat() const
7213 {
7214     return (getAspectFlags() & kDepthStencilAspects) == kDepthStencilAspects;
7215 }
7216 
setCurrentImageLayout(Renderer * renderer,ImageLayout newLayout)7217 void ImageHelper::setCurrentImageLayout(Renderer *renderer, ImageLayout newLayout)
7218 {
7219     // Once you transition to ImageLayout::SharedPresent, you never transition out of it.
7220     if (mCurrentLayout == ImageLayout::SharedPresent)
7221     {
7222         return;
7223     }
7224 
7225     const ImageMemoryBarrierData &transitionFrom =
7226         renderer->getImageMemoryBarrierData(mCurrentLayout);
7227     const ImageMemoryBarrierData &transitionTo = renderer->getImageMemoryBarrierData(newLayout);
7228     mLastNonShaderReadOnlyLayout =
7229         !IsShaderReadOnlyLayout(transitionFrom) ? mCurrentLayout : mLastNonShaderReadOnlyLayout;
7230     // Force the use of BarrierType::Pipeline in the next barrierImpl call
7231     mLastNonShaderReadOnlyEvent.release(renderer);
7232     mCurrentShaderReadStageMask =
7233         IsShaderReadOnlyLayout(transitionTo) ? transitionTo.dstStageMask : 0;
7234     mCurrentLayout = newLayout;
7235 }
7236 
getCurrentLayout(Renderer * renderer) const7237 VkImageLayout ImageHelper::getCurrentLayout(Renderer *renderer) const
7238 {
7239     return ConvertImageLayoutToVkImageLayout(renderer, mCurrentLayout);
7240 }
7241 
getLevelExtents(LevelIndex levelVk) const7242 gl::Extents ImageHelper::getLevelExtents(LevelIndex levelVk) const
7243 {
7244     // Level 0 should be the size of the extents, after that every time you increase a level
7245     // you shrink the extents by half.
7246     uint32_t width  = std::max(mExtents.width >> levelVk.get(), 1u);
7247     uint32_t height = std::max(mExtents.height >> levelVk.get(), 1u);
7248     uint32_t depth  = std::max(mExtents.depth >> levelVk.get(), 1u);
7249 
7250     return gl::Extents(width, height, depth);
7251 }
7252 
getLevelExtents2D(LevelIndex levelVk) const7253 gl::Extents ImageHelper::getLevelExtents2D(LevelIndex levelVk) const
7254 {
7255     gl::Extents extents = getLevelExtents(levelVk);
7256     extents.depth       = 1;
7257     return extents;
7258 }
7259 
getRotatedExtents() const7260 const VkExtent3D ImageHelper::getRotatedExtents() const
7261 {
7262     VkExtent3D extents = mExtents;
7263     if (mRotatedAspectRatio)
7264     {
7265         std::swap(extents.width, extents.height);
7266     }
7267     return extents;
7268 }
7269 
getRotatedLevelExtents2D(LevelIndex levelVk) const7270 gl::Extents ImageHelper::getRotatedLevelExtents2D(LevelIndex levelVk) const
7271 {
7272     gl::Extents extents = getLevelExtents2D(levelVk);
7273     if (mRotatedAspectRatio)
7274     {
7275         std::swap(extents.width, extents.height);
7276     }
7277     return extents;
7278 }
7279 
isDepthOrStencil() const7280 bool ImageHelper::isDepthOrStencil() const
7281 {
7282     return getActualFormat().hasDepthOrStencilBits();
7283 }
7284 
setRenderPassUsageFlag(RenderPassUsage flag)7285 void ImageHelper::setRenderPassUsageFlag(RenderPassUsage flag)
7286 {
7287     mRenderPassUsageFlags.set(flag);
7288 }
7289 
clearRenderPassUsageFlag(RenderPassUsage flag)7290 void ImageHelper::clearRenderPassUsageFlag(RenderPassUsage flag)
7291 {
7292     mRenderPassUsageFlags.reset(flag);
7293 }
7294 
resetRenderPassUsageFlags()7295 void ImageHelper::resetRenderPassUsageFlags()
7296 {
7297     mRenderPassUsageFlags.reset();
7298 }
7299 
hasRenderPassUsageFlag(RenderPassUsage flag) const7300 bool ImageHelper::hasRenderPassUsageFlag(RenderPassUsage flag) const
7301 {
7302     return mRenderPassUsageFlags.test(flag);
7303 }
7304 
usedByCurrentRenderPassAsAttachmentAndSampler(RenderPassUsage textureSamplerUsage) const7305 bool ImageHelper::usedByCurrentRenderPassAsAttachmentAndSampler(
7306     RenderPassUsage textureSamplerUsage) const
7307 {
7308     return mRenderPassUsageFlags[RenderPassUsage::RenderTargetAttachment] &&
7309            mRenderPassUsageFlags[textureSamplerUsage];
7310 }
7311 
isReadBarrierNecessary(Renderer * renderer,ImageLayout newLayout) const7312 bool ImageHelper::isReadBarrierNecessary(Renderer *renderer, ImageLayout newLayout) const
7313 {
7314     // If transitioning to a different layout, we need always need a barrier.
7315     if (mCurrentLayout != newLayout)
7316     {
7317         return true;
7318     }
7319 
7320     // RAR (read-after-read) is not a hazard and doesn't require a barrier.
7321     //
7322     // RAW (read-after-write) hazards always require a memory barrier.  This can only happen if the
7323     // layout (same as new layout) is writable which in turn is only possible if the image is
7324     // simultaneously bound for shader write (i.e. the layout is GENERAL or SHARED_PRESENT).
7325     const ImageMemoryBarrierData &layoutData = renderer->getImageMemoryBarrierData(mCurrentLayout);
7326     return HasResourceWriteAccess(layoutData.type);
7327 }
7328 
isReadSubresourceBarrierNecessary(ImageLayout newLayout,gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount) const7329 bool ImageHelper::isReadSubresourceBarrierNecessary(ImageLayout newLayout,
7330                                                     gl::LevelIndex levelStart,
7331                                                     uint32_t levelCount,
7332                                                     uint32_t layerStart,
7333                                                     uint32_t layerCount) const
7334 {
7335     // In case an image has both read and write permissions, the written subresources since the last
7336     // barrier should be checked to avoid RAW and WAR hazards. However, if a layout change is
7337     // necessary regardless, there is no need to check the written subresources.
7338     if (mCurrentLayout != newLayout)
7339     {
7340         return true;
7341     }
7342 
7343     ImageLayerWriteMask layerMask = GetImageLayerWriteMask(layerStart, layerCount);
7344     for (uint32_t levelOffset = 0; levelOffset < levelCount; levelOffset++)
7345     {
7346         uint32_t level = levelStart.get() + levelOffset;
7347         if (areLevelSubresourcesWrittenWithinMaskRange(level, layerMask))
7348         {
7349             return true;
7350         }
7351     }
7352 
7353     return false;
7354 }
7355 
isWriteBarrierNecessary(ImageLayout newLayout,gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount) const7356 bool ImageHelper::isWriteBarrierNecessary(ImageLayout newLayout,
7357                                           gl::LevelIndex levelStart,
7358                                           uint32_t levelCount,
7359                                           uint32_t layerStart,
7360                                           uint32_t layerCount) const
7361 {
7362     // If transitioning to a different layout, we need always need a barrier.
7363     if (mCurrentLayout != newLayout)
7364     {
7365         return true;
7366     }
7367 
7368     if (layerCount >= kMaxParallelLayerWrites)
7369     {
7370         return true;
7371     }
7372 
7373     // If we are writing to the same parts of the image (level/layer), we need a barrier. Otherwise,
7374     // it can be done in parallel.
7375     ImageLayerWriteMask layerMask = GetImageLayerWriteMask(layerStart, layerCount);
7376     for (uint32_t levelOffset = 0; levelOffset < levelCount; levelOffset++)
7377     {
7378         uint32_t level = levelStart.get() + levelOffset;
7379         if (areLevelSubresourcesWrittenWithinMaskRange(level, layerMask))
7380         {
7381             return true;
7382         }
7383     }
7384 
7385     return false;
7386 }
7387 
changeLayoutAndQueue(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,DeviceQueueIndex newDeviceQueueIndex,OutsideRenderPassCommandBuffer * commandBuffer)7388 void ImageHelper::changeLayoutAndQueue(Context *context,
7389                                        VkImageAspectFlags aspectMask,
7390                                        ImageLayout newLayout,
7391                                        DeviceQueueIndex newDeviceQueueIndex,
7392                                        OutsideRenderPassCommandBuffer *commandBuffer)
7393 {
7394     ASSERT(isQueueFamilyChangeNeccesary(newDeviceQueueIndex));
7395     VkSemaphore acquireNextImageSemaphore;
7396     // barrierImpl should detect there is queue switch and fall back to pipelineBarrier properly.
7397     barrierImpl(context, aspectMask, newLayout, newDeviceQueueIndex, nullptr, commandBuffer,
7398                 &acquireNextImageSemaphore);
7399     // SwapChain image should not get here.
7400     ASSERT(acquireNextImageSemaphore == VK_NULL_HANDLE);
7401 }
7402 
acquireFromExternal(Context * context,DeviceQueueIndex externalQueueIndex,DeviceQueueIndex newDeviceQueueIndex,ImageLayout currentLayout,OutsideRenderPassCommandBuffer * commandBuffer)7403 void ImageHelper::acquireFromExternal(Context *context,
7404                                       DeviceQueueIndex externalQueueIndex,
7405                                       DeviceQueueIndex newDeviceQueueIndex,
7406                                       ImageLayout currentLayout,
7407                                       OutsideRenderPassCommandBuffer *commandBuffer)
7408 {
7409     // The image must be newly allocated or have been released to the external
7410     // queue. If this is not the case, it's an application bug, so ASSERT might
7411     // eventually need to change to a warning.
7412     ASSERT(mCurrentLayout == ImageLayout::ExternalPreInitialized ||
7413            mCurrentDeviceQueueIndex.familyIndex() == externalQueueIndex.familyIndex());
7414 
7415     mCurrentLayout           = currentLayout;
7416     mCurrentDeviceQueueIndex = externalQueueIndex;
7417     mIsReleasedToExternal    = false;
7418 
7419     // Only change the layout and queue if the layout is anything by Undefined.  If it is undefined,
7420     // leave it to transition out as the image is used later.
7421     if (currentLayout != ImageLayout::Undefined)
7422     {
7423         changeLayoutAndQueue(context, getAspectFlags(), mCurrentLayout, newDeviceQueueIndex,
7424                              commandBuffer);
7425     }
7426 
7427     // It is unknown how the external has modified the image, so assume every subresource has
7428     // defined content.  That is unless the layout is Undefined.
7429     if (currentLayout == ImageLayout::Undefined)
7430     {
7431         setEntireContentUndefined();
7432     }
7433     else
7434     {
7435         setEntireContentDefined();
7436     }
7437 }
7438 
releaseToExternal(Context * context,DeviceQueueIndex externalQueueIndex,ImageLayout desiredLayout,OutsideRenderPassCommandBuffer * commandBuffer)7439 void ImageHelper::releaseToExternal(Context *context,
7440                                     DeviceQueueIndex externalQueueIndex,
7441                                     ImageLayout desiredLayout,
7442                                     OutsideRenderPassCommandBuffer *commandBuffer)
7443 {
7444     ASSERT(!mIsReleasedToExternal);
7445 
7446     // A layout change is unnecessary if the image that was previously acquired was never used by
7447     // GL!
7448     if (mCurrentDeviceQueueIndex.familyIndex() != externalQueueIndex.familyIndex() ||
7449         mCurrentLayout != desiredLayout)
7450     {
7451         changeLayoutAndQueue(context, getAspectFlags(), desiredLayout, externalQueueIndex,
7452                              commandBuffer);
7453     }
7454 
7455     mIsReleasedToExternal = true;
7456 }
7457 
isReleasedToExternal() const7458 bool ImageHelper::isReleasedToExternal() const
7459 {
7460     return mIsReleasedToExternal;
7461 }
7462 
toVkLevel(gl::LevelIndex levelIndexGL) const7463 LevelIndex ImageHelper::toVkLevel(gl::LevelIndex levelIndexGL) const
7464 {
7465     return gl_vk::GetLevelIndex(levelIndexGL, mFirstAllocatedLevel);
7466 }
7467 
toGLLevel(LevelIndex levelIndexVk) const7468 gl::LevelIndex ImageHelper::toGLLevel(LevelIndex levelIndexVk) const
7469 {
7470     return vk_gl::GetLevelIndex(levelIndexVk, mFirstAllocatedLevel);
7471 }
7472 
initImageMemoryBarrierStruct(Renderer * renderer,VkImageAspectFlags aspectMask,ImageLayout newLayout,uint32_t newQueueFamilyIndex,VkImageMemoryBarrier * imageMemoryBarrier) const7473 ANGLE_INLINE void ImageHelper::initImageMemoryBarrierStruct(
7474     Renderer *renderer,
7475     VkImageAspectFlags aspectMask,
7476     ImageLayout newLayout,
7477     uint32_t newQueueFamilyIndex,
7478     VkImageMemoryBarrier *imageMemoryBarrier) const
7479 {
7480     ASSERT(mCurrentDeviceQueueIndex.familyIndex() != QueueFamily::kInvalidIndex);
7481     ASSERT(newQueueFamilyIndex != QueueFamily::kInvalidIndex);
7482 
7483     const ImageMemoryBarrierData &transitionFrom =
7484         renderer->getImageMemoryBarrierData(mCurrentLayout);
7485     const ImageMemoryBarrierData &transitionTo = renderer->getImageMemoryBarrierData(newLayout);
7486 
7487     imageMemoryBarrier->sType         = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
7488     imageMemoryBarrier->srcAccessMask = transitionFrom.srcAccessMask;
7489     imageMemoryBarrier->dstAccessMask = transitionTo.dstAccessMask;
7490     imageMemoryBarrier->oldLayout     = ConvertImageLayoutToVkImageLayout(renderer, mCurrentLayout);
7491     imageMemoryBarrier->newLayout     = ConvertImageLayoutToVkImageLayout(renderer, newLayout);
7492     imageMemoryBarrier->srcQueueFamilyIndex = mCurrentDeviceQueueIndex.familyIndex();
7493     imageMemoryBarrier->dstQueueFamilyIndex = newQueueFamilyIndex;
7494     imageMemoryBarrier->image               = mImage.getHandle();
7495 
7496     // Transition the whole resource.
7497     imageMemoryBarrier->subresourceRange.aspectMask     = aspectMask;
7498     imageMemoryBarrier->subresourceRange.baseMipLevel   = 0;
7499     imageMemoryBarrier->subresourceRange.levelCount     = mLevelCount;
7500     imageMemoryBarrier->subresourceRange.baseArrayLayer = 0;
7501     imageMemoryBarrier->subresourceRange.layerCount     = mLayerCount;
7502 }
7503 
7504 // Generalized to accept both "primary" and "secondary" command buffers.
7505 template <typename CommandBufferT>
barrierImpl(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,DeviceQueueIndex newDeviceQueueIndex,RefCountedEventCollector * eventCollector,CommandBufferT * commandBuffer,VkSemaphore * acquireNextImageSemaphoreOut)7506 void ImageHelper::barrierImpl(Context *context,
7507                               VkImageAspectFlags aspectMask,
7508                               ImageLayout newLayout,
7509                               DeviceQueueIndex newDeviceQueueIndex,
7510                               RefCountedEventCollector *eventCollector,
7511                               CommandBufferT *commandBuffer,
7512                               VkSemaphore *acquireNextImageSemaphoreOut)
7513 {
7514     Renderer *renderer = context->getRenderer();
7515     // mCurrentEvent must be invalid if useVkEventForImageBarrieris disabled.
7516     ASSERT(context->getFeatures().useVkEventForImageBarrier.enabled || !mCurrentEvent.valid());
7517 
7518     // Release the ANI semaphore to caller to add to the command submission.
7519     ASSERT(acquireNextImageSemaphoreOut != nullptr || !mAcquireNextImageSemaphore.valid());
7520     if (acquireNextImageSemaphoreOut != nullptr)
7521     {
7522         *acquireNextImageSemaphoreOut = mAcquireNextImageSemaphore.release();
7523     }
7524 
7525     if (mCurrentLayout == ImageLayout::SharedPresent)
7526     {
7527         // For now we always use pipelineBarrier for singlebuffer mode. We could use event here in
7528         // future.
7529         mCurrentEvent.release(context);
7530 
7531         const ImageMemoryBarrierData &transition =
7532             renderer->getImageMemoryBarrierData(mCurrentLayout);
7533         VkMemoryBarrier memoryBarrier = {};
7534         memoryBarrier.sType           = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
7535         memoryBarrier.srcAccessMask   = transition.srcAccessMask;
7536         memoryBarrier.dstAccessMask   = transition.dstAccessMask;
7537 
7538         commandBuffer->memoryBarrier(transition.srcStageMask, transition.dstStageMask,
7539                                      memoryBarrier);
7540         return;
7541     }
7542 
7543     // Make sure we never transition out of SharedPresent
7544     ASSERT(mCurrentLayout != ImageLayout::SharedPresent || newLayout == ImageLayout::SharedPresent);
7545 
7546     const ImageMemoryBarrierData &transitionFrom =
7547         renderer->getImageMemoryBarrierData(mCurrentLayout);
7548     const ImageMemoryBarrierData &transitionTo = renderer->getImageMemoryBarrierData(newLayout);
7549 
7550     VkImageMemoryBarrier imageMemoryBarrier = {};
7551     initImageMemoryBarrierStruct(renderer, aspectMask, newLayout, newDeviceQueueIndex.familyIndex(),
7552                                  &imageMemoryBarrier);
7553 
7554     VkPipelineStageFlags dstStageMask = transitionTo.dstStageMask;
7555 
7556     // Fallback to pipelineBarrier if there is no event tracking image.
7557     // VkCmdWaitEvent requires the srcQueueFamilyIndex and dstQueueFamilyIndex members of any
7558     // element of pBufferMemoryBarriers or pImageMemoryBarriers must be equal
7559     // (VUID-vkCmdWaitEvents-srcQueueFamilyIndex-02803).
7560     BarrierType barrierType =
7561         mCurrentEvent.valid() && mCurrentDeviceQueueIndex == newDeviceQueueIndex
7562             ? BarrierType::Event
7563             : BarrierType::Pipeline;
7564 
7565     if (barrierType == BarrierType::Event)
7566     {
7567         // If there is an event, we use the waitEvent to do layout change. Once we have waited, the
7568         // event gets garbage collected (which is GPU completion tracked) to avoid waited again in
7569         // future. We always use DstStageMask since that is what setEvent used and
7570         // VUID-vkCmdWaitEvents-srcStageMask-01158 requires they must match.
7571         VkPipelineStageFlags srcStageMask =
7572             context->getRenderer()->getEventPipelineStageMask(mCurrentEvent);
7573         commandBuffer->imageWaitEvent(mCurrentEvent.getEvent().getHandle(), srcStageMask,
7574                                       dstStageMask, imageMemoryBarrier);
7575         eventCollector->emplace_back(std::move(mCurrentEvent));
7576     }
7577     else
7578     {
7579         // There might be other shaderRead operations there other than the current layout.
7580         VkPipelineStageFlags srcStageMask = transitionFrom.srcStageMask;
7581         if (mCurrentShaderReadStageMask)
7582         {
7583             srcStageMask |= mCurrentShaderReadStageMask;
7584             mCurrentShaderReadStageMask  = 0;
7585             mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
7586         }
7587         commandBuffer->imageBarrier(srcStageMask, dstStageMask, imageMemoryBarrier);
7588         // We use pipelineBarrier here, no needs to wait for events any more.
7589         mCurrentEvent.release(context);
7590     }
7591 
7592     mCurrentLayout           = newLayout;
7593     mCurrentDeviceQueueIndex = newDeviceQueueIndex;
7594     resetSubresourcesWrittenSinceBarrier();
7595 
7596     // We must release the event so that new event will be created and added. If we did not add new
7597     // event, because mCurrentEvent have been released, next barrier will automatically fallback to
7598     // pipelineBarrier. Otherwise if we keep mCurrentEvent here we may accidentally end up waiting
7599     // for an old event which creates sync hazard.
7600     ASSERT(!mCurrentEvent.valid());
7601 }
7602 
7603 template void ImageHelper::barrierImpl<priv::CommandBuffer>(
7604     Context *context,
7605     VkImageAspectFlags aspectMask,
7606     ImageLayout newLayout,
7607     DeviceQueueIndex newDeviceQueueIndex,
7608     RefCountedEventCollector *eventCollector,
7609     priv::CommandBuffer *commandBuffer,
7610     VkSemaphore *acquireNextImageSemaphoreOut);
7611 
setSubresourcesWrittenSinceBarrier(gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount)7612 void ImageHelper::setSubresourcesWrittenSinceBarrier(gl::LevelIndex levelStart,
7613                                                      uint32_t levelCount,
7614                                                      uint32_t layerStart,
7615                                                      uint32_t layerCount)
7616 {
7617     for (uint32_t levelOffset = 0; levelOffset < levelCount; levelOffset++)
7618     {
7619         uint32_t level = levelStart.get() + levelOffset;
7620         if (layerCount >= kMaxParallelLayerWrites)
7621         {
7622             mSubresourcesWrittenSinceBarrier[level].set();
7623         }
7624         else
7625         {
7626             ImageLayerWriteMask layerMask = GetImageLayerWriteMask(layerStart, layerCount);
7627             mSubresourcesWrittenSinceBarrier[level] |= layerMask;
7628         }
7629     }
7630 }
7631 
resetSubresourcesWrittenSinceBarrier()7632 void ImageHelper::resetSubresourcesWrittenSinceBarrier()
7633 {
7634     for (auto &layerWriteMask : mSubresourcesWrittenSinceBarrier)
7635     {
7636         layerWriteMask.reset();
7637     }
7638 }
7639 
recordWriteBarrier(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,OutsideRenderPassCommandBufferHelper * commands)7640 void ImageHelper::recordWriteBarrier(Context *context,
7641                                      VkImageAspectFlags aspectMask,
7642                                      ImageLayout newLayout,
7643                                      gl::LevelIndex levelStart,
7644                                      uint32_t levelCount,
7645                                      uint32_t layerStart,
7646                                      uint32_t layerCount,
7647                                      OutsideRenderPassCommandBufferHelper *commands)
7648 {
7649     if (isWriteBarrierNecessary(newLayout, levelStart, levelCount, layerStart, layerCount))
7650     {
7651         ASSERT(!mCurrentEvent.valid() || !commands->hasSetEventPendingFlush(mCurrentEvent));
7652         VkSemaphore acquireNextImageSemaphore;
7653         barrierImpl(context, aspectMask, newLayout, context->getDeviceQueueIndex(),
7654                     commands->getRefCountedEventCollector(), &commands->getCommandBuffer(),
7655                     &acquireNextImageSemaphore);
7656 
7657         if (acquireNextImageSemaphore != VK_NULL_HANDLE)
7658         {
7659             commands->setAcquireNextImageSemaphore(acquireNextImageSemaphore);
7660         }
7661     }
7662 
7663     setSubresourcesWrittenSinceBarrier(levelStart, levelCount, layerStart, layerCount);
7664 }
7665 
recordReadSubresourceBarrier(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,OutsideRenderPassCommandBufferHelper * commands)7666 void ImageHelper::recordReadSubresourceBarrier(Context *context,
7667                                                VkImageAspectFlags aspectMask,
7668                                                ImageLayout newLayout,
7669                                                gl::LevelIndex levelStart,
7670                                                uint32_t levelCount,
7671                                                uint32_t layerStart,
7672                                                uint32_t layerCount,
7673                                                OutsideRenderPassCommandBufferHelper *commands)
7674 {
7675     // This barrier is used for an image with both read/write permissions, including during mipmap
7676     // generation and self-copy.
7677     if (isReadSubresourceBarrierNecessary(newLayout, levelStart, levelCount, layerStart,
7678                                           layerCount))
7679     {
7680         ASSERT(!mCurrentEvent.valid() || !commands->hasSetEventPendingFlush(mCurrentEvent));
7681         VkSemaphore acquireNextImageSemaphore;
7682         barrierImpl(context, aspectMask, newLayout, context->getDeviceQueueIndex(),
7683                     commands->getRefCountedEventCollector(), &commands->getCommandBuffer(),
7684                     &acquireNextImageSemaphore);
7685 
7686         if (acquireNextImageSemaphore != VK_NULL_HANDLE)
7687         {
7688             commands->setAcquireNextImageSemaphore(acquireNextImageSemaphore);
7689         }
7690     }
7691 
7692     // Levels/layers being read from are also registered to avoid RAW and WAR hazards.
7693     setSubresourcesWrittenSinceBarrier(levelStart, levelCount, layerStart, layerCount);
7694 }
7695 
recordReadBarrier(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,OutsideRenderPassCommandBufferHelper * commands)7696 void ImageHelper::recordReadBarrier(Context *context,
7697                                     VkImageAspectFlags aspectMask,
7698                                     ImageLayout newLayout,
7699                                     OutsideRenderPassCommandBufferHelper *commands)
7700 {
7701     if (!isReadBarrierNecessary(context->getRenderer(), newLayout))
7702     {
7703         return;
7704     }
7705 
7706     ASSERT(!mCurrentEvent.valid() || !commands->hasSetEventPendingFlush(mCurrentEvent));
7707     VkSemaphore acquireNextImageSemaphore;
7708     barrierImpl(context, aspectMask, newLayout, context->getDeviceQueueIndex(),
7709                 commands->getRefCountedEventCollector(), &commands->getCommandBuffer(),
7710                 &acquireNextImageSemaphore);
7711 
7712     if (acquireNextImageSemaphore != VK_NULL_HANDLE)
7713     {
7714         commands->setAcquireNextImageSemaphore(acquireNextImageSemaphore);
7715     }
7716 }
7717 
updateLayoutAndBarrier(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,BarrierType barrierType,const QueueSerial & queueSerial,PipelineBarrierArray * pipelineBarriers,EventBarrierArray * eventBarriers,RefCountedEventCollector * eventCollector,VkSemaphore * semaphoreOut)7718 void ImageHelper::updateLayoutAndBarrier(Context *context,
7719                                          VkImageAspectFlags aspectMask,
7720                                          ImageLayout newLayout,
7721                                          BarrierType barrierType,
7722                                          const QueueSerial &queueSerial,
7723                                          PipelineBarrierArray *pipelineBarriers,
7724                                          EventBarrierArray *eventBarriers,
7725                                          RefCountedEventCollector *eventCollector,
7726                                          VkSemaphore *semaphoreOut)
7727 {
7728     Renderer *renderer = context->getRenderer();
7729     ASSERT(queueSerial.valid());
7730     ASSERT(!mBarrierQueueSerial.valid() ||
7731            mBarrierQueueSerial.getIndex() != queueSerial.getIndex() ||
7732            mBarrierQueueSerial.getSerial() <= queueSerial.getSerial());
7733     ASSERT(renderer->getImageMemoryBarrierData(newLayout).barrierIndex !=
7734            PipelineStage::InvalidEnum);
7735     // mCurrentEvent must be invalid if useVkEventForImageBarrieris disabled.
7736     ASSERT(renderer->getFeatures().useVkEventForImageBarrier.enabled || !mCurrentEvent.valid());
7737 
7738     if (mCurrentDeviceQueueIndex != context->getDeviceQueueIndex())
7739     {
7740         // Fallback to pipelineBarrier if the VkQueue has changed.
7741         barrierType              = BarrierType::Pipeline;
7742         mCurrentDeviceQueueIndex = context->getDeviceQueueIndex();
7743     }
7744     else if (!mCurrentEvent.valid())
7745     {
7746         // Fallback to pipelineBarrier if there is no event tracking image.
7747         barrierType = BarrierType::Pipeline;
7748     }
7749 
7750     // Once you transition to ImageLayout::SharedPresent, you never transition out of it.
7751     if (mCurrentLayout == ImageLayout::SharedPresent)
7752     {
7753         newLayout = ImageLayout::SharedPresent;
7754     }
7755 
7756     if (newLayout == mCurrentLayout)
7757     {
7758         if (mBarrierQueueSerial == queueSerial)
7759         {
7760             ASSERT(!mAcquireNextImageSemaphore.valid());
7761             // If there is no layout change and the previous layout change happened in the same
7762             // render pass, then early out do nothing. This can happen when the same image is
7763             // attached to the multiple attachments of the framebuffer.
7764             return;
7765         }
7766 
7767         const ImageMemoryBarrierData &layoutData =
7768             renderer->getImageMemoryBarrierData(mCurrentLayout);
7769         // RAR is not a hazard and doesn't require a barrier, especially as the image layout hasn't
7770         // changed.  The following asserts that such a barrier is not attempted.
7771         ASSERT(HasResourceWriteAccess(layoutData.type));
7772 
7773         // No layout change, only memory barrier is required
7774         if (barrierType == BarrierType::Event)
7775         {
7776             eventBarriers->addMemoryEvent(renderer, mCurrentEvent, layoutData.dstStageMask,
7777                                           layoutData.dstAccessMask);
7778             // Garbage collect the event, which tracks GPU completion automatically.
7779             eventCollector->emplace_back(std::move(mCurrentEvent));
7780         }
7781         else
7782         {
7783             pipelineBarriers->mergeMemoryBarrier(layoutData.barrierIndex, layoutData.dstStageMask,
7784                                                  layoutData.dstStageMask, layoutData.srcAccessMask,
7785                                                  layoutData.dstAccessMask);
7786 
7787             // Release it. No need to garbage collect since we did not use the event here. ALl
7788             // previous use of event should garbage tracked already.
7789             mCurrentEvent.release(context);
7790         }
7791         mBarrierQueueSerial = queueSerial;
7792     }
7793     else
7794     {
7795         const ImageMemoryBarrierData &transitionFrom =
7796             renderer->getImageMemoryBarrierData(mCurrentLayout);
7797         const ImageMemoryBarrierData &transitionTo = renderer->getImageMemoryBarrierData(newLayout);
7798         VkPipelineStageFlags srcStageMask          = transitionFrom.srcStageMask;
7799         VkPipelineStageFlags dstStageMask          = transitionTo.dstStageMask;
7800 
7801         if (transitionFrom.layout == transitionTo.layout && IsShaderReadOnlyLayout(transitionTo) &&
7802             mBarrierQueueSerial == queueSerial)
7803         {
7804             // If we are switching between different shader stage reads of the same render pass,
7805             // then there is no actual layout change or access type change. We only need a barrier
7806             // if we are making a read that is from a new stage. Also note that we do barrier
7807             // against previous non-shaderRead layout. We do not barrier between one shaderRead and
7808             // another shaderRead.
7809             bool isNewReadStage = (mCurrentShaderReadStageMask & dstStageMask) != dstStageMask;
7810             if (!isNewReadStage)
7811             {
7812                 ASSERT(!mAcquireNextImageSemaphore.valid());
7813                 return;
7814             }
7815 
7816             ASSERT(!mLastNonShaderReadOnlyEvent.valid() ||
7817                    mLastNonShaderReadOnlyEvent.getEventStage() ==
7818                        GetImageLayoutEventStage(mLastNonShaderReadOnlyLayout));
7819             if (!mLastNonShaderReadOnlyEvent.valid())
7820             {
7821                 barrierType = BarrierType::Pipeline;
7822             }
7823 
7824             if (barrierType == BarrierType::Event)
7825             {
7826                 // If we already inserted a barrier in the same renderPass, we has to add
7827                 // the new stage mask to the existing VkCmdWaitEvent call, otherwise VVL will
7828                 // complain.
7829                 eventBarriers->addAdditionalStageAccess(mLastNonShaderReadOnlyEvent, dstStageMask,
7830                                                         transitionTo.dstAccessMask);
7831                 eventCollector->emplace_back(mLastNonShaderReadOnlyEvent);
7832             }
7833             else
7834             {
7835                 const ImageMemoryBarrierData &layoutData =
7836                     renderer->getImageMemoryBarrierData(mLastNonShaderReadOnlyLayout);
7837                 pipelineBarriers->mergeMemoryBarrier(
7838                     transitionTo.barrierIndex, layoutData.srcStageMask, dstStageMask,
7839                     layoutData.srcAccessMask, transitionTo.dstAccessMask);
7840             }
7841 
7842             mBarrierQueueSerial = queueSerial;
7843             // Accumulate new read stage.
7844             mCurrentShaderReadStageMask |= dstStageMask;
7845 
7846             // Since we used pipelineBarrier, release the event now to avoid wait for the
7847             // event again.
7848             if (mCurrentEvent.valid())
7849             {
7850                 eventCollector->emplace_back(std::move(mCurrentEvent));
7851             }
7852         }
7853         else
7854         {
7855             VkImageMemoryBarrier imageMemoryBarrier = {};
7856             initImageMemoryBarrierStruct(renderer, aspectMask, newLayout,
7857                                          context->getDeviceQueueIndex().familyIndex(),
7858                                          &imageMemoryBarrier);
7859 
7860             if (transitionFrom.layout == transitionTo.layout &&
7861                 IsShaderReadOnlyLayout(transitionTo))
7862             {
7863                 // If we are transiting within shaderReadOnly layout, i.e. reading from different
7864                 // shader stages, VkEvent can't handle this right now. In order for VkEvent to
7865                 // handle this properly we have to wait for the previous shaderReadOnly layout
7866                 // transition event and add a new memoryBarrier. But we may have lost that event
7867                 // already if it has been used in a new render pass (because we have to update the
7868                 // event even if there is no barrier needed). To workaround this issue we fall back
7869                 // to pipelineBarrier for now.
7870                 barrierType = BarrierType::Pipeline;
7871             }
7872             else if (mBarrierQueueSerial == queueSerial)
7873             {
7874                 // If we already inserted a barrier in this render pass, force to use
7875                 // pipelineBarrier. Otherwise we will end up inserting a VkCmdWaitEvent that has not
7876                 // been set (See https://issuetracker.google.com/333419317 for example).
7877                 barrierType = BarrierType::Pipeline;
7878             }
7879 
7880             // if we transition from shaderReadOnly, we must add in stashed shader stage masks since
7881             // there might be outstanding shader reads from stages other than current layout. We do
7882             // not insert barrier between one shaderRead to another shaderRead
7883             if (mCurrentShaderReadStageMask)
7884             {
7885                 if ((mCurrentShaderReadStageMask & srcStageMask) != mCurrentShaderReadStageMask)
7886                 {
7887                     // mCurrentShaderReadStageMask has more bits than srcStageMask. This means it
7888                     // has been used by more than one shader stage in the same render pass. These
7889                     // two usages are tracked by two different ImageLayout, even though underline
7890                     // VkImageLayout is the same. This means two different RefCountedEvents since
7891                     // each RefCountedEvent is associated with one ImageLayout. When we transit out
7892                     // of this layout, we must wait for all reads to finish. But Right now
7893                     // ImageHelper only keep track of the last read. To workaround this problem we
7894                     // use pipelineBarrier in this case.
7895                     barrierType = BarrierType::Pipeline;
7896                     srcStageMask |= mCurrentShaderReadStageMask;
7897                 }
7898                 mCurrentShaderReadStageMask  = 0;
7899                 mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
7900                 if (mLastNonShaderReadOnlyEvent.valid())
7901                 {
7902                     mLastNonShaderReadOnlyEvent.release(context);
7903                 }
7904             }
7905 
7906             // If we are transition into shaderRead layout, remember the last
7907             // non-shaderRead layout here.
7908             const bool isShaderReadOnly = IsShaderReadOnlyLayout(transitionTo);
7909             if (isShaderReadOnly)
7910             {
7911                 mLastNonShaderReadOnlyEvent.release(context);
7912                 mLastNonShaderReadOnlyLayout = mCurrentLayout;
7913                 mCurrentShaderReadStageMask  = dstStageMask;
7914             }
7915 
7916             if (barrierType == BarrierType::Event)
7917             {
7918                 eventBarriers->addImageEvent(renderer, mCurrentEvent, dstStageMask,
7919                                              imageMemoryBarrier);
7920                 if (isShaderReadOnly)
7921                 {
7922                     mLastNonShaderReadOnlyEvent = mCurrentEvent;
7923                 }
7924                 eventCollector->emplace_back(std::move(mCurrentEvent));
7925             }
7926             else
7927             {
7928                 pipelineBarriers->mergeImageBarrier(transitionTo.barrierIndex, srcStageMask,
7929                                                     dstStageMask, imageMemoryBarrier);
7930                 mCurrentEvent.release(context);
7931             }
7932 
7933             mBarrierQueueSerial = queueSerial;
7934         }
7935         mCurrentLayout = newLayout;
7936     }
7937 
7938     *semaphoreOut = mAcquireNextImageSemaphore.release();
7939     // We must release the event so that new event will be created and added. If we did not add new
7940     // event, because mCurrentEvent have been released, next barrier will automatically fallback to
7941     // pipelineBarrier. Otherwise if we keep mCurrentEvent here we may accidentally end up waiting
7942     // for an old event which creates sync hazard.
7943     ASSERT(!mCurrentEvent.valid());
7944 }
7945 
setCurrentRefCountedEvent(Context * context,EventMaps & eventMaps)7946 void ImageHelper::setCurrentRefCountedEvent(Context *context, EventMaps &eventMaps)
7947 {
7948     ASSERT(context->getFeatures().useVkEventForImageBarrier.enabled);
7949 
7950     // If there is already an event, release it first.
7951     mCurrentEvent.release(context);
7952 
7953     // VkCmdSetEvent can remove the unnecessary GPU pipeline bubble that comes from false dependency
7954     // between fragment and vertex/transfer/compute stages. But it also comes with higher overhead.
7955     // In order to strike the balance, we exclude the images that are only used by one group of
7956     // pipeline stages in the past N references, where N is the heuristic window that we keep track
7957     // of. Use of VkEvent will not be beneficial if it is only accessed by one group of stages since
7958     // execution within the group is expected to be non-overlap.
7959     if (mPipelineStageAccessHeuristic == kPipelineStageAccessFragmentOnly ||
7960         mPipelineStageAccessHeuristic == kPipelineStageAccessPreFragmentOnly ||
7961         mPipelineStageAccessHeuristic == kPipelineStageAccessComputeOnly)
7962     {
7963         return;
7964     }
7965 
7966     // Create the event if we have not yet so. Otherwise just use the already created event. This
7967     // means all images used in the same render pass that has the same layout will be tracked by the
7968     // same event.
7969     EventStage stage = GetImageLayoutEventStage(mCurrentLayout);
7970     if (!eventMaps.map[stage].valid())
7971     {
7972         if (!eventMaps.map[stage].init(context, stage))
7973         {
7974             // If VkEvent creation fail, we fallback to pipelineBarrier
7975             return;
7976         }
7977         eventMaps.mask.set(stage);
7978     }
7979 
7980     // Copy the event to mCurrentEvent so that we can wait for it in future. This will add extra
7981     // refcount to the underlying VkEvent.
7982     mCurrentEvent = eventMaps.map[stage];
7983 }
7984 
updatePipelineStageAccessHistory()7985 void ImageHelper::updatePipelineStageAccessHistory()
7986 {
7987     const ImageMemoryBarrierData &barrierData = kImageMemoryBarrierData[mCurrentLayout];
7988     mPipelineStageAccessHeuristic.onAccess(barrierData.pipelineStageGroup);
7989 }
7990 
clearColor(Renderer * renderer,const VkClearColorValue & color,LevelIndex baseMipLevelVk,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount,OutsideRenderPassCommandBuffer * commandBuffer)7991 void ImageHelper::clearColor(Renderer *renderer,
7992                              const VkClearColorValue &color,
7993                              LevelIndex baseMipLevelVk,
7994                              uint32_t levelCount,
7995                              uint32_t baseArrayLayer,
7996                              uint32_t layerCount,
7997                              OutsideRenderPassCommandBuffer *commandBuffer)
7998 {
7999     ASSERT(valid());
8000 
8001     ASSERT(mCurrentLayout == ImageLayout::TransferDst ||
8002            mCurrentLayout == ImageLayout::SharedPresent);
8003 
8004     VkImageSubresourceRange range = {};
8005     range.aspectMask              = VK_IMAGE_ASPECT_COLOR_BIT;
8006     range.baseMipLevel            = baseMipLevelVk.get();
8007     range.levelCount              = levelCount;
8008     range.baseArrayLayer          = baseArrayLayer;
8009     range.layerCount              = layerCount;
8010 
8011     if (mImageType == VK_IMAGE_TYPE_3D)
8012     {
8013         ASSERT(baseArrayLayer == 0);
8014         ASSERT(layerCount == 1 ||
8015                layerCount == static_cast<uint32_t>(getLevelExtents(baseMipLevelVk).depth));
8016         range.layerCount = 1;
8017     }
8018 
8019     commandBuffer->clearColorImage(mImage, getCurrentLayout(renderer), color, 1, &range);
8020 }
8021 
clearDepthStencil(Renderer * renderer,VkImageAspectFlags clearAspectFlags,const VkClearDepthStencilValue & depthStencil,LevelIndex baseMipLevelVk,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount,OutsideRenderPassCommandBuffer * commandBuffer)8022 void ImageHelper::clearDepthStencil(Renderer *renderer,
8023                                     VkImageAspectFlags clearAspectFlags,
8024                                     const VkClearDepthStencilValue &depthStencil,
8025                                     LevelIndex baseMipLevelVk,
8026                                     uint32_t levelCount,
8027                                     uint32_t baseArrayLayer,
8028                                     uint32_t layerCount,
8029                                     OutsideRenderPassCommandBuffer *commandBuffer)
8030 {
8031     ASSERT(valid());
8032 
8033     ASSERT(mCurrentLayout == ImageLayout::TransferDst);
8034 
8035     VkImageSubresourceRange range = {};
8036     range.aspectMask              = clearAspectFlags;
8037     range.baseMipLevel            = baseMipLevelVk.get();
8038     range.levelCount              = levelCount;
8039     range.baseArrayLayer          = baseArrayLayer;
8040     range.layerCount              = layerCount;
8041 
8042     if (mImageType == VK_IMAGE_TYPE_3D)
8043     {
8044         ASSERT(baseArrayLayer == 0);
8045         ASSERT(layerCount == 1 ||
8046                layerCount == static_cast<uint32_t>(getLevelExtents(baseMipLevelVk).depth));
8047         range.layerCount = 1;
8048     }
8049 
8050     commandBuffer->clearDepthStencilImage(mImage, getCurrentLayout(renderer), depthStencil, 1,
8051                                           &range);
8052 }
8053 
clear(Renderer * renderer,VkImageAspectFlags aspectFlags,const VkClearValue & value,LevelIndex mipLevel,uint32_t baseArrayLayer,uint32_t layerCount,OutsideRenderPassCommandBuffer * commandBuffer)8054 void ImageHelper::clear(Renderer *renderer,
8055                         VkImageAspectFlags aspectFlags,
8056                         const VkClearValue &value,
8057                         LevelIndex mipLevel,
8058                         uint32_t baseArrayLayer,
8059                         uint32_t layerCount,
8060                         OutsideRenderPassCommandBuffer *commandBuffer)
8061 {
8062     const angle::Format &angleFormat = getActualFormat();
8063     bool isDepthStencil              = angleFormat.hasDepthOrStencilBits();
8064 
8065     if (isDepthStencil)
8066     {
8067         clearDepthStencil(renderer, aspectFlags, value.depthStencil, mipLevel, 1, baseArrayLayer,
8068                           layerCount, commandBuffer);
8069     }
8070     else
8071     {
8072         ASSERT(!angleFormat.isBlock);
8073 
8074         clearColor(renderer, value.color, mipLevel, 1, baseArrayLayer, layerCount, commandBuffer);
8075     }
8076 }
8077 
clearEmulatedChannels(ContextVk * contextVk,VkColorComponentFlags colorMaskFlags,const VkClearValue & value,LevelIndex mipLevel,uint32_t baseArrayLayer,uint32_t layerCount)8078 angle::Result ImageHelper::clearEmulatedChannels(ContextVk *contextVk,
8079                                                  VkColorComponentFlags colorMaskFlags,
8080                                                  const VkClearValue &value,
8081                                                  LevelIndex mipLevel,
8082                                                  uint32_t baseArrayLayer,
8083                                                  uint32_t layerCount)
8084 {
8085     const gl::Extents levelExtents = getLevelExtents(mipLevel);
8086 
8087     if (levelExtents.depth > 1)
8088     {
8089         // Currently not implemented for 3D textures
8090         UNIMPLEMENTED();
8091         return angle::Result::Continue;
8092     }
8093 
8094     UtilsVk::ClearImageParameters params = {};
8095     params.clearArea                     = {0, 0, levelExtents.width, levelExtents.height};
8096     params.dstMip                        = mipLevel;
8097     params.colorMaskFlags                = colorMaskFlags;
8098     params.colorClearValue               = value.color;
8099 
8100     for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex)
8101     {
8102         params.dstLayer = baseArrayLayer + layerIndex;
8103 
8104         ANGLE_TRY(contextVk->getUtils().clearImage(contextVk, this, params));
8105     }
8106 
8107     return angle::Result::Continue;
8108 }
8109 
8110 // 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)8111 void ImageHelper::Copy(Renderer *renderer,
8112                        ImageHelper *srcImage,
8113                        ImageHelper *dstImage,
8114                        const gl::Offset &srcOffset,
8115                        const gl::Offset &dstOffset,
8116                        const gl::Extents &copySize,
8117                        const VkImageSubresourceLayers &srcSubresource,
8118                        const VkImageSubresourceLayers &dstSubresource,
8119                        OutsideRenderPassCommandBuffer *commandBuffer)
8120 {
8121     ASSERT(commandBuffer->valid() && srcImage->valid() && dstImage->valid());
8122 
8123     ASSERT(srcImage->getCurrentLayout(renderer) == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
8124     ASSERT(dstImage->getCurrentLayout(renderer) == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
8125 
8126     VkImageCopy region    = {};
8127     region.srcSubresource = srcSubresource;
8128     region.srcOffset.x    = srcOffset.x;
8129     region.srcOffset.y    = srcOffset.y;
8130     region.srcOffset.z    = srcOffset.z;
8131     region.dstSubresource = dstSubresource;
8132     region.dstOffset.x    = dstOffset.x;
8133     region.dstOffset.y    = dstOffset.y;
8134     region.dstOffset.z    = dstOffset.z;
8135     region.extent.width   = copySize.width;
8136     region.extent.height  = copySize.height;
8137     region.extent.depth   = copySize.depth;
8138 
8139     commandBuffer->copyImage(srcImage->getImage(), srcImage->getCurrentLayout(renderer),
8140                              dstImage->getImage(), dstImage->getCurrentLayout(renderer), 1,
8141                              &region);
8142 }
8143 
8144 // 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)8145 angle::Result ImageHelper::CopyImageSubData(const gl::Context *context,
8146                                             ImageHelper *srcImage,
8147                                             GLint srcLevel,
8148                                             GLint srcX,
8149                                             GLint srcY,
8150                                             GLint srcZ,
8151                                             ImageHelper *dstImage,
8152                                             GLint dstLevel,
8153                                             GLint dstX,
8154                                             GLint dstY,
8155                                             GLint dstZ,
8156                                             GLsizei srcWidth,
8157                                             GLsizei srcHeight,
8158                                             GLsizei srcDepth)
8159 {
8160     ContextVk *contextVk = GetImpl(context);
8161     Renderer *renderer   = contextVk->getRenderer();
8162 
8163     VkImageTiling srcTilingMode  = srcImage->getTilingMode();
8164     VkImageTiling destTilingMode = dstImage->getTilingMode();
8165 
8166     const gl::LevelIndex srcLevelGL = gl::LevelIndex(srcLevel);
8167     const gl::LevelIndex dstLevelGL = gl::LevelIndex(dstLevel);
8168 
8169     if (CanCopyWithTransferForCopyImage(renderer, srcImage, srcTilingMode, dstImage,
8170                                         destTilingMode))
8171     {
8172         bool isSrc3D                         = srcImage->getType() == VK_IMAGE_TYPE_3D;
8173         bool isDst3D                         = dstImage->getType() == VK_IMAGE_TYPE_3D;
8174         const VkImageAspectFlags aspectFlags = srcImage->getAspectFlags();
8175 
8176         ASSERT(srcImage->getAspectFlags() == dstImage->getAspectFlags());
8177 
8178         VkImageCopy region = {};
8179 
8180         region.srcSubresource.aspectMask     = aspectFlags;
8181         region.srcSubresource.mipLevel       = srcImage->toVkLevel(srcLevelGL).get();
8182         region.srcSubresource.baseArrayLayer = isSrc3D ? 0 : srcZ;
8183         region.srcSubresource.layerCount     = isSrc3D ? 1 : srcDepth;
8184 
8185         region.dstSubresource.aspectMask     = aspectFlags;
8186         region.dstSubresource.mipLevel       = dstImage->toVkLevel(dstLevelGL).get();
8187         region.dstSubresource.baseArrayLayer = isDst3D ? 0 : dstZ;
8188         region.dstSubresource.layerCount     = isDst3D ? 1 : srcDepth;
8189 
8190         region.srcOffset.x   = srcX;
8191         region.srcOffset.y   = srcY;
8192         region.srcOffset.z   = isSrc3D ? srcZ : 0;
8193         region.dstOffset.x   = dstX;
8194         region.dstOffset.y   = dstY;
8195         region.dstOffset.z   = isDst3D ? dstZ : 0;
8196         region.extent.width  = srcWidth;
8197         region.extent.height = srcHeight;
8198         region.extent.depth  = (isSrc3D || isDst3D) ? srcDepth : 1;
8199 
8200         CommandBufferAccess access;
8201         if (srcImage == dstImage)
8202         {
8203             access.onImageSelfCopy(srcLevelGL, 1, region.srcSubresource.baseArrayLayer,
8204                                    region.srcSubresource.layerCount, dstLevelGL, 1,
8205                                    region.dstSubresource.baseArrayLayer,
8206                                    region.dstSubresource.layerCount, aspectFlags, srcImage);
8207         }
8208         else
8209         {
8210             access.onImageTransferRead(aspectFlags, srcImage);
8211             access.onImageTransferWrite(dstLevelGL, 1, region.dstSubresource.baseArrayLayer,
8212                                         region.dstSubresource.layerCount, aspectFlags, dstImage);
8213         }
8214 
8215         OutsideRenderPassCommandBuffer *commandBuffer;
8216         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
8217 
8218         ASSERT(srcImage->valid() && dstImage->valid());
8219         ASSERT(srcImage->getCurrentLayout(renderer) == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL ||
8220                srcImage->getCurrentLayout(renderer) == VK_IMAGE_LAYOUT_GENERAL);
8221         ASSERT(dstImage->getCurrentLayout(renderer) == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ||
8222                dstImage->getCurrentLayout(renderer) == VK_IMAGE_LAYOUT_GENERAL);
8223 
8224         commandBuffer->copyImage(srcImage->getImage(), srcImage->getCurrentLayout(renderer),
8225                                  dstImage->getImage(), dstImage->getCurrentLayout(renderer), 1,
8226                                  &region);
8227     }
8228     else if (!srcImage->getIntendedFormat().isBlock && !dstImage->getIntendedFormat().isBlock)
8229     {
8230         // The source and destination image formats may be using a fallback in the case of RGB
8231         // images.  A compute shader is used in such a case to perform the copy.
8232         UtilsVk &utilsVk = contextVk->getUtils();
8233 
8234         UtilsVk::CopyImageBitsParameters params;
8235         params.srcOffset[0]   = srcX;
8236         params.srcOffset[1]   = srcY;
8237         params.srcOffset[2]   = srcZ;
8238         params.srcLevel       = srcLevelGL;
8239         params.dstOffset[0]   = dstX;
8240         params.dstOffset[1]   = dstY;
8241         params.dstOffset[2]   = dstZ;
8242         params.dstLevel       = dstLevelGL;
8243         params.copyExtents[0] = srcWidth;
8244         params.copyExtents[1] = srcHeight;
8245         params.copyExtents[2] = srcDepth;
8246 
8247         ANGLE_TRY(utilsVk.copyImageBits(contextVk, dstImage, srcImage, params));
8248     }
8249     else
8250     {
8251         // No support for emulated compressed formats.
8252         UNIMPLEMENTED();
8253         ANGLE_VK_CHECK(contextVk, false, VK_ERROR_FEATURE_NOT_PRESENT);
8254     }
8255 
8256     return angle::Result::Continue;
8257 }
8258 
generateMipmapsWithBlit(ContextVk * contextVk,LevelIndex baseLevel,LevelIndex maxLevel)8259 angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk,
8260                                                    LevelIndex baseLevel,
8261                                                    LevelIndex maxLevel)
8262 {
8263     Renderer *renderer = contextVk->getRenderer();
8264 
8265     CommandBufferAccess access;
8266     gl::LevelIndex baseLevelGL = toGLLevel(baseLevel);
8267     access.onImageTransferWrite(baseLevelGL + 1, maxLevel.get(), 0, mLayerCount,
8268                                 VK_IMAGE_ASPECT_COLOR_BIT, this);
8269 
8270     OutsideRenderPassCommandBuffer *commandBuffer;
8271     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
8272 
8273     // We are able to use blitImage since the image format we are using supports it.
8274     int32_t mipWidth  = mExtents.width;
8275     int32_t mipHeight = mExtents.height;
8276     int32_t mipDepth  = mExtents.depth;
8277 
8278     // Manually manage the image memory barrier because it uses a lot more parameters than our
8279     // usual one.
8280     VkImageMemoryBarrier barrier            = {};
8281     barrier.sType                           = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
8282     barrier.image                           = mImage.getHandle();
8283     barrier.srcQueueFamilyIndex             = VK_QUEUE_FAMILY_IGNORED;
8284     barrier.dstQueueFamilyIndex             = VK_QUEUE_FAMILY_IGNORED;
8285     barrier.subresourceRange.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
8286     barrier.subresourceRange.baseArrayLayer = 0;
8287     barrier.subresourceRange.layerCount     = mLayerCount;
8288     barrier.subresourceRange.levelCount     = 1;
8289 
8290     const VkFilter filter =
8291         gl_vk::GetFilter(CalculateGenerateMipmapFilter(contextVk, getActualFormatID()));
8292 
8293     for (LevelIndex mipLevel(1); mipLevel <= LevelIndex(mLevelCount); ++mipLevel)
8294     {
8295         int32_t nextMipWidth  = std::max<int32_t>(1, mipWidth >> 1);
8296         int32_t nextMipHeight = std::max<int32_t>(1, mipHeight >> 1);
8297         int32_t nextMipDepth  = std::max<int32_t>(1, mipDepth >> 1);
8298 
8299         if (mipLevel > baseLevel && mipLevel <= maxLevel)
8300         {
8301             barrier.subresourceRange.baseMipLevel = mipLevel.get() - 1;
8302             barrier.oldLayout                     = getCurrentLayout(renderer);
8303             barrier.newLayout                     = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
8304             barrier.srcAccessMask                 = VK_ACCESS_TRANSFER_WRITE_BIT;
8305             barrier.dstAccessMask                 = VK_ACCESS_TRANSFER_READ_BIT;
8306 
8307             // We can do it for all layers at once.
8308             commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
8309                                         VK_PIPELINE_STAGE_TRANSFER_BIT, barrier);
8310             VkImageBlit blit                   = {};
8311             blit.srcOffsets[0]                 = {0, 0, 0};
8312             blit.srcOffsets[1]                 = {mipWidth, mipHeight, mipDepth};
8313             blit.srcSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
8314             blit.srcSubresource.mipLevel       = mipLevel.get() - 1;
8315             blit.srcSubresource.baseArrayLayer = 0;
8316             blit.srcSubresource.layerCount     = mLayerCount;
8317             blit.dstOffsets[0]                 = {0, 0, 0};
8318             blit.dstOffsets[1]                 = {nextMipWidth, nextMipHeight, nextMipDepth};
8319             blit.dstSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
8320             blit.dstSubresource.mipLevel       = mipLevel.get();
8321             blit.dstSubresource.baseArrayLayer = 0;
8322             blit.dstSubresource.layerCount     = mLayerCount;
8323 
8324             commandBuffer->blitImage(mImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, mImage,
8325                                      VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, filter);
8326         }
8327         mipWidth  = nextMipWidth;
8328         mipHeight = nextMipHeight;
8329         mipDepth  = nextMipDepth;
8330     }
8331 
8332     // Transition all mip level to the same layout so we can declare our whole image layout to one
8333     // ImageLayout. FragmentShaderReadOnly is picked here since this is the most reasonable usage
8334     // after glGenerateMipmap call.
8335     barrier.oldLayout     = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
8336     barrier.newLayout     = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
8337     barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
8338     if (baseLevel.get() > 0)
8339     {
8340         // [0:baseLevel-1] from TRANSFER_DST to SHADER_READ
8341         barrier.subresourceRange.baseMipLevel = 0;
8342         barrier.subresourceRange.levelCount   = baseLevel.get();
8343         commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
8344                                     VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, barrier);
8345     }
8346     // [maxLevel:mLevelCount-1] from TRANSFER_DST to SHADER_READ
8347     ASSERT(mLevelCount > maxLevel.get());
8348     barrier.subresourceRange.baseMipLevel = maxLevel.get();
8349     barrier.subresourceRange.levelCount   = mLevelCount - maxLevel.get();
8350     commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
8351                                 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, barrier);
8352     // [baseLevel:maxLevel-1] from TRANSFER_SRC to SHADER_READ
8353     barrier.oldLayout                     = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
8354     barrier.srcAccessMask                 = VK_ACCESS_TRANSFER_READ_BIT;
8355     barrier.subresourceRange.baseMipLevel = baseLevel.get();
8356     barrier.subresourceRange.levelCount   = maxLevel.get() - baseLevel.get();
8357     commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
8358                                 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, barrier);
8359 
8360     // This is just changing the internal state of the image helper so that the next call
8361     // to changeLayout will use this layout as the "oldLayout" argument.
8362     // mLastNonShaderReadOnlyLayout is used to ensure previous write are made visible to reads,
8363     // since the only write here is transfer, hence mLastNonShaderReadOnlyLayout is set to
8364     // ImageLayout::TransferDst.
8365     setCurrentImageLayout(renderer, ImageLayout::FragmentShaderReadOnly);
8366 
8367     contextVk->trackImageWithOutsideRenderPassEvent(this);
8368 
8369     return angle::Result::Continue;
8370 }
8371 
resolve(ImageHelper * dst,const VkImageResolve & region,OutsideRenderPassCommandBuffer * commandBuffer)8372 void ImageHelper::resolve(ImageHelper *dst,
8373                           const VkImageResolve &region,
8374                           OutsideRenderPassCommandBuffer *commandBuffer)
8375 {
8376     ASSERT(mCurrentLayout == ImageLayout::TransferSrc ||
8377            mCurrentLayout == ImageLayout::SharedPresent);
8378     commandBuffer->resolveImage(getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst->getImage(),
8379                                 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
8380 }
8381 
removeSingleSubresourceStagedUpdates(ContextVk * contextVk,gl::LevelIndex levelIndexGL,uint32_t layerIndex,uint32_t layerCount)8382 void ImageHelper::removeSingleSubresourceStagedUpdates(ContextVk *contextVk,
8383                                                        gl::LevelIndex levelIndexGL,
8384                                                        uint32_t layerIndex,
8385                                                        uint32_t layerCount)
8386 {
8387     mCurrentSingleClearValue.reset();
8388 
8389     // Find any staged updates for this index and remove them from the pending list.
8390     std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(levelIndexGL);
8391     if (levelUpdates == nullptr)
8392     {
8393         return;
8394     }
8395 
8396     for (size_t index = 0; index < levelUpdates->size();)
8397     {
8398         auto update = levelUpdates->begin() + index;
8399         if (update->matchesLayerRange(layerIndex, layerCount))
8400         {
8401             // Update total staging buffer size
8402             mTotalStagedBufferUpdateSize -= update->updateSource == UpdateSource::Buffer
8403                                                 ? update->data.buffer.bufferHelper->getSize()
8404                                                 : 0;
8405             update->release(contextVk->getRenderer());
8406             levelUpdates->erase(update);
8407         }
8408         else
8409         {
8410             index++;
8411         }
8412     }
8413 }
8414 
removeSingleStagedClearAfterInvalidate(gl::LevelIndex levelIndexGL,uint32_t layerIndex,uint32_t layerCount)8415 void ImageHelper::removeSingleStagedClearAfterInvalidate(gl::LevelIndex levelIndexGL,
8416                                                          uint32_t layerIndex,
8417                                                          uint32_t layerCount)
8418 {
8419     // When this function is called, it's expected that there may be at most one
8420     // ClearAfterInvalidate update pending to this subresource, and that's a color clear due to
8421     // emulated channels after invalidate.  This function removes that update.
8422 
8423     std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(levelIndexGL);
8424     if (levelUpdates == nullptr)
8425     {
8426         return;
8427     }
8428 
8429     for (size_t index = 0; index < levelUpdates->size(); ++index)
8430     {
8431         auto update = levelUpdates->begin() + index;
8432         if (update->updateSource == UpdateSource::ClearAfterInvalidate &&
8433             update->matchesLayerRange(layerIndex, layerCount))
8434         {
8435             // It's a clear, so doesn't need to be released.
8436             levelUpdates->erase(update);
8437             // There's only one such clear possible.
8438             return;
8439         }
8440     }
8441 }
8442 
removeStagedUpdates(Context * context,gl::LevelIndex levelGLStart,gl::LevelIndex levelGLEnd)8443 void ImageHelper::removeStagedUpdates(Context *context,
8444                                       gl::LevelIndex levelGLStart,
8445                                       gl::LevelIndex levelGLEnd)
8446 {
8447     ASSERT(validateSubresourceUpdateRefCountsConsistent());
8448 
8449     // Remove all updates to levels [start, end].
8450     for (gl::LevelIndex level = levelGLStart; level <= levelGLEnd; ++level)
8451     {
8452         std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(level);
8453         if (levelUpdates == nullptr)
8454         {
8455             ASSERT(static_cast<size_t>(level.get()) >= mSubresourceUpdates.size());
8456             return;
8457         }
8458 
8459         for (SubresourceUpdate &update : *levelUpdates)
8460         {
8461             // Update total staging buffer size
8462             mTotalStagedBufferUpdateSize -= update.updateSource == UpdateSource::Buffer
8463                                                 ? update.data.buffer.bufferHelper->getSize()
8464                                                 : 0;
8465             update.release(context->getRenderer());
8466         }
8467 
8468         levelUpdates->clear();
8469     }
8470 
8471     ASSERT(validateSubresourceUpdateRefCountsConsistent());
8472 }
8473 
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)8474 angle::Result ImageHelper::stageSubresourceUpdateImpl(ContextVk *contextVk,
8475                                                       const gl::ImageIndex &index,
8476                                                       const gl::Extents &glExtents,
8477                                                       const gl::Offset &offset,
8478                                                       const gl::InternalFormat &formatInfo,
8479                                                       const gl::PixelUnpackState &unpack,
8480                                                       GLenum type,
8481                                                       const uint8_t *pixels,
8482                                                       const Format &vkFormat,
8483                                                       ImageAccess access,
8484                                                       const GLuint inputRowPitch,
8485                                                       const GLuint inputDepthPitch,
8486                                                       const GLuint inputSkipBytes,
8487                                                       ApplyImageUpdate applyUpdate,
8488                                                       bool *updateAppliedImmediatelyOut)
8489 {
8490     *updateAppliedImmediatelyOut = false;
8491 
8492     const angle::Format &storageFormat = vkFormat.getActualImageFormat(access);
8493 
8494     size_t outputRowPitch;
8495     size_t outputDepthPitch;
8496     size_t stencilAllocationSize = 0;
8497     uint32_t bufferRowLength;
8498     uint32_t bufferImageHeight;
8499     size_t allocationSize;
8500 
8501     LoadImageFunctionInfo loadFunctionInfo = vkFormat.getTextureLoadFunction(access, type);
8502     LoadImageFunction stencilLoadFunction  = nullptr;
8503 
8504     bool useComputeTransCoding = false;
8505     if (storageFormat.isBlock)
8506     {
8507         const gl::InternalFormat &storageFormatInfo = vkFormat.getInternalFormatInfo(type);
8508         GLuint rowPitch;
8509         GLuint depthPitch;
8510         GLuint totalSize;
8511 
8512         ANGLE_VK_CHECK_MATH(contextVk, storageFormatInfo.computeCompressedImageRowPitch(
8513                                            glExtents.width, &rowPitch));
8514         ANGLE_VK_CHECK_MATH(contextVk, storageFormatInfo.computeCompressedImageDepthPitch(
8515                                            glExtents.height, rowPitch, &depthPitch));
8516 
8517         ANGLE_VK_CHECK_MATH(contextVk,
8518                             storageFormatInfo.computeCompressedImageSize(glExtents, &totalSize));
8519 
8520         outputRowPitch   = rowPitch;
8521         outputDepthPitch = depthPitch;
8522         allocationSize   = totalSize;
8523 
8524         ANGLE_VK_CHECK_MATH(
8525             contextVk, storageFormatInfo.computeBufferRowLength(glExtents.width, &bufferRowLength));
8526         ANGLE_VK_CHECK_MATH(contextVk, storageFormatInfo.computeBufferImageHeight(
8527                                            glExtents.height, &bufferImageHeight));
8528 
8529         if (contextVk->getFeatures().supportsComputeTranscodeEtcToBc.enabled &&
8530             IsETCFormat(vkFormat.getIntendedFormatID()) && IsBCFormat(storageFormat.id))
8531         {
8532             useComputeTransCoding =
8533                 shouldUseComputeForTransCoding(vk::LevelIndex(index.getLevelIndex()));
8534             if (!useComputeTransCoding)
8535             {
8536                 loadFunctionInfo = GetEtcToBcTransCodingFunc(vkFormat.getIntendedFormatID());
8537             }
8538         }
8539     }
8540     else
8541     {
8542         ASSERT(storageFormat.pixelBytes != 0);
8543         const bool stencilOnly = formatInfo.sizedInternalFormat == GL_STENCIL_INDEX8;
8544 
8545         if (!stencilOnly && storageFormat.id == angle::FormatID::D24_UNORM_S8_UINT)
8546         {
8547             switch (type)
8548             {
8549                 case GL_UNSIGNED_INT_24_8:
8550                     stencilLoadFunction = angle::LoadX24S8ToS8;
8551                     break;
8552                 case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
8553                     stencilLoadFunction = angle::LoadX32S8ToS8;
8554                     break;
8555             }
8556         }
8557         if (!stencilOnly && storageFormat.id == angle::FormatID::D32_FLOAT_S8X24_UINT)
8558         {
8559             // If depth is D32FLOAT_S8, we must pack D32F tightly (no stencil) for CopyBufferToImage
8560             outputRowPitch = sizeof(float) * glExtents.width;
8561 
8562             // The generic load functions don't handle tightly packing D32FS8 to D32F & S8 so call
8563             // special case load functions.
8564             switch (type)
8565             {
8566                 case GL_UNSIGNED_INT:
8567                     loadFunctionInfo.loadFunction = angle::LoadD32ToD32F;
8568                     stencilLoadFunction           = nullptr;
8569                     break;
8570                 case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
8571                     loadFunctionInfo.loadFunction = angle::LoadD32FS8X24ToD32F;
8572                     stencilLoadFunction           = angle::LoadX32S8ToS8;
8573                     break;
8574                 case GL_UNSIGNED_INT_24_8:
8575                     loadFunctionInfo.loadFunction = angle::LoadD24S8ToD32F;
8576                     stencilLoadFunction           = angle::LoadX24S8ToS8;
8577                     break;
8578                 default:
8579                     UNREACHABLE();
8580             }
8581         }
8582         else if (!stencilOnly)
8583         {
8584             outputRowPitch = storageFormat.pixelBytes * glExtents.width;
8585         }
8586         else
8587         {
8588             // Some Vulkan implementations do not support S8_UINT, so stencil-only data is
8589             // uploaded using one of combined depth-stencil formats there. Since the uploaded
8590             // stencil data must be tightly packed, the actual storage format should be ignored
8591             // with regards to its load function and output row pitch.
8592             loadFunctionInfo.loadFunction = angle::LoadToNative<GLubyte, 1>;
8593             outputRowPitch                = glExtents.width;
8594         }
8595         outputDepthPitch = outputRowPitch * glExtents.height;
8596 
8597         bufferRowLength   = glExtents.width;
8598         bufferImageHeight = glExtents.height;
8599 
8600         allocationSize = outputDepthPitch * glExtents.depth;
8601 
8602         // Note: because the LoadImageFunctionInfo functions are limited to copying a single
8603         // component, we have to special case packed depth/stencil use and send the stencil as a
8604         // separate chunk.
8605         if (storageFormat.hasDepthAndStencilBits() && formatInfo.depthBits > 0 &&
8606             formatInfo.stencilBits > 0)
8607         {
8608             // Note: Stencil is always one byte
8609             stencilAllocationSize = glExtents.width * glExtents.height * glExtents.depth;
8610             allocationSize += stencilAllocationSize;
8611         }
8612     }
8613 
8614     const uint8_t *source = pixels + static_cast<ptrdiff_t>(inputSkipBytes);
8615 
8616     // If possible, copy the buffer to the image directly on the host, to avoid having to use a temp
8617     // image (and do a double copy).
8618     if (applyUpdate != ApplyImageUpdate::Defer && !loadFunctionInfo.requiresConversion &&
8619         inputRowPitch == outputRowPitch && inputDepthPitch == outputDepthPitch)
8620     {
8621         bool copied = false;
8622         ANGLE_TRY(updateSubresourceOnHost(contextVk, applyUpdate, index, glExtents, offset, source,
8623                                           bufferRowLength, bufferImageHeight, &copied));
8624         if (copied)
8625         {
8626             *updateAppliedImmediatelyOut = true;
8627             return angle::Result::Continue;
8628         }
8629     }
8630 
8631     std::unique_ptr<RefCounted<BufferHelper>> stagingBuffer =
8632         std::make_unique<RefCounted<BufferHelper>>();
8633     BufferHelper *currentBuffer = &stagingBuffer->get();
8634 
8635     uint8_t *stagingPointer;
8636     VkDeviceSize stagingOffset;
8637     ANGLE_TRY(contextVk->initBufferForImageCopy(currentBuffer, allocationSize,
8638                                                 MemoryCoherency::CachedNonCoherent,
8639                                                 storageFormat.id, &stagingOffset, &stagingPointer));
8640 
8641     loadFunctionInfo.loadFunction(
8642         contextVk->getImageLoadContext(), glExtents.width, glExtents.height, glExtents.depth,
8643         source, inputRowPitch, inputDepthPitch, stagingPointer, outputRowPitch, outputDepthPitch);
8644 
8645     // YUV formats need special handling.
8646     if (storageFormat.isYUV)
8647     {
8648         gl::YuvFormatInfo yuvInfo(formatInfo.internalFormat, glExtents);
8649 
8650         constexpr VkImageAspectFlagBits kPlaneAspectFlags[3] = {
8651             VK_IMAGE_ASPECT_PLANE_0_BIT, VK_IMAGE_ASPECT_PLANE_1_BIT, VK_IMAGE_ASPECT_PLANE_2_BIT};
8652 
8653         // We only support mip level 0 and layerCount of 1 for YUV formats.
8654         ASSERT(index.getLevelIndex() == 0);
8655         ASSERT(index.getLayerCount() == 1);
8656 
8657         for (uint32_t plane = 0; plane < yuvInfo.planeCount; plane++)
8658         {
8659             VkBufferImageCopy copy           = {};
8660             copy.bufferOffset                = stagingOffset + yuvInfo.planeOffset[plane];
8661             copy.bufferRowLength             = 0;
8662             copy.bufferImageHeight           = 0;
8663             copy.imageSubresource.mipLevel   = 0;
8664             copy.imageSubresource.layerCount = 1;
8665             gl_vk::GetOffset(offset, &copy.imageOffset);
8666             gl_vk::GetExtent(yuvInfo.planeExtent[plane], &copy.imageExtent);
8667             copy.imageSubresource.baseArrayLayer = 0;
8668             copy.imageSubresource.aspectMask     = kPlaneAspectFlags[plane];
8669             appendSubresourceUpdate(
8670                 gl::LevelIndex(0),
8671                 SubresourceUpdate(stagingBuffer.get(), currentBuffer, copy, storageFormat.id));
8672         }
8673 
8674         stagingBuffer.release();
8675         return angle::Result::Continue;
8676     }
8677 
8678     VkBufferImageCopy copy         = {};
8679     VkImageAspectFlags aspectFlags = GetFormatAspectFlags(storageFormat);
8680 
8681     copy.bufferOffset      = stagingOffset;
8682     copy.bufferRowLength   = bufferRowLength;
8683     copy.bufferImageHeight = bufferImageHeight;
8684 
8685     gl::LevelIndex updateLevelGL(index.getLevelIndex());
8686     copy.imageSubresource.mipLevel   = updateLevelGL.get();
8687     copy.imageSubresource.layerCount = index.getLayerCount();
8688 
8689     gl_vk::GetOffset(offset, &copy.imageOffset);
8690     gl_vk::GetExtent(glExtents, &copy.imageExtent);
8691 
8692     if (gl::IsArrayTextureType(index.getType()))
8693     {
8694         copy.imageSubresource.baseArrayLayer = offset.z;
8695         copy.imageOffset.z                   = 0;
8696         copy.imageExtent.depth               = 1;
8697     }
8698     else
8699     {
8700         copy.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
8701     }
8702 
8703     if (stencilAllocationSize > 0)
8704     {
8705         // Note: Stencil is always one byte
8706         ASSERT((aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) != 0);
8707 
8708         // Skip over depth data.
8709         stagingPointer += outputDepthPitch * glExtents.depth;
8710         stagingOffset += outputDepthPitch * glExtents.depth;
8711 
8712         // recompute pitch for stencil data
8713         outputRowPitch   = glExtents.width;
8714         outputDepthPitch = outputRowPitch * glExtents.height;
8715 
8716         ASSERT(stencilLoadFunction != nullptr);
8717         stencilLoadFunction(contextVk->getImageLoadContext(), glExtents.width, glExtents.height,
8718                             glExtents.depth, source, inputRowPitch, inputDepthPitch, stagingPointer,
8719                             outputRowPitch, outputDepthPitch);
8720 
8721         VkBufferImageCopy stencilCopy = {};
8722 
8723         stencilCopy.bufferOffset                    = stagingOffset;
8724         stencilCopy.bufferRowLength                 = bufferRowLength;
8725         stencilCopy.bufferImageHeight               = bufferImageHeight;
8726         stencilCopy.imageSubresource.mipLevel       = copy.imageSubresource.mipLevel;
8727         stencilCopy.imageSubresource.baseArrayLayer = copy.imageSubresource.baseArrayLayer;
8728         stencilCopy.imageSubresource.layerCount     = copy.imageSubresource.layerCount;
8729         stencilCopy.imageOffset                     = copy.imageOffset;
8730         stencilCopy.imageExtent                     = copy.imageExtent;
8731         stencilCopy.imageSubresource.aspectMask     = VK_IMAGE_ASPECT_STENCIL_BIT;
8732         appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(stagingBuffer.get(), currentBuffer,
8733                                                                  stencilCopy, storageFormat.id));
8734 
8735         aspectFlags &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
8736     }
8737 
8738     if (HasBothDepthAndStencilAspects(aspectFlags))
8739     {
8740         // We still have both depth and stencil aspect bits set. That means we have a destination
8741         // buffer that is packed depth stencil and that the application is only loading one aspect.
8742         // Figure out which aspect the user is touching and remove the unused aspect bit.
8743         if (formatInfo.stencilBits > 0)
8744         {
8745             aspectFlags &= ~VK_IMAGE_ASPECT_DEPTH_BIT;
8746         }
8747         else
8748         {
8749             aspectFlags &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
8750         }
8751     }
8752 
8753     if (aspectFlags)
8754     {
8755         copy.imageSubresource.aspectMask = aspectFlags;
8756         appendSubresourceUpdate(
8757             updateLevelGL, SubresourceUpdate(stagingBuffer.get(), currentBuffer, copy,
8758                                              useComputeTransCoding ? vkFormat.getIntendedFormatID()
8759                                                                    : storageFormat.id));
8760         pruneSupersededUpdatesForLevel(contextVk, updateLevelGL, PruneReason::MemoryOptimization);
8761     }
8762 
8763     stagingBuffer.release();
8764     return angle::Result::Continue;
8765 }
8766 
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)8767 angle::Result ImageHelper::updateSubresourceOnHost(Context *context,
8768                                                    ApplyImageUpdate applyUpdate,
8769                                                    const gl::ImageIndex &index,
8770                                                    const gl::Extents &glExtents,
8771                                                    const gl::Offset &offset,
8772                                                    const uint8_t *source,
8773                                                    const GLuint memoryRowLength,
8774                                                    const GLuint memoryImageHeight,
8775                                                    bool *copiedOut)
8776 {
8777     // If the image is not set up for host copy, it can't be done.
8778     if (!valid() || (mUsage & VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT) == 0)
8779     {
8780         return angle::Result::Continue;
8781     }
8782 
8783     Renderer *renderer = context->getRenderer();
8784     const VkPhysicalDeviceHostImageCopyPropertiesEXT &hostImageCopyProperties =
8785         renderer->getPhysicalDeviceHostImageCopyProperties();
8786 
8787     // The image should be unused by the GPU.
8788     if (!renderer->hasResourceUseFinished(getResourceUse()))
8789     {
8790         ANGLE_TRY(renderer->checkCompletedCommandsAndCleanup(context));
8791         if (!renderer->hasResourceUseFinished(getResourceUse()))
8792         {
8793             return angle::Result::Continue;
8794         }
8795     }
8796 
8797     // The image should not have any pending updates to this subresource.
8798     //
8799     // TODO: if there are any pending updates, see if they can be pruned given the incoming update.
8800     // This would most likely be the case where a clear is automatically staged for robustness or
8801     // other reasons, which would now be superseded by the data upload. http://anglebug.com/42266771
8802     const gl::LevelIndex updateLevelGL(index.getLevelIndex());
8803     const uint32_t layerIndex = index.hasLayer() ? index.getLayerIndex() : 0;
8804     const uint32_t layerCount = index.getLayerCount();
8805     if (hasStagedUpdatesForSubresource(updateLevelGL, layerIndex, layerCount))
8806     {
8807         return angle::Result::Continue;
8808     }
8809 
8810     // The image should be in a layout this is copiable.  If UNDEFINED, it can be transitioned to a
8811     // layout that is copyable.
8812     const VkImageAspectFlags aspectMask = getAspectFlags();
8813     if (mCurrentLayout == ImageLayout::Undefined)
8814     {
8815         VkHostImageLayoutTransitionInfoEXT transition = {};
8816         transition.sType     = VK_STRUCTURE_TYPE_HOST_IMAGE_LAYOUT_TRANSITION_INFO_EXT;
8817         transition.image     = mImage.getHandle();
8818         transition.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
8819         // The GENERAL layout is always guaranteed to be in
8820         // VkPhysicalDeviceHostImageCopyPropertiesEXT::pCopyDstLayouts
8821         transition.newLayout                       = VK_IMAGE_LAYOUT_GENERAL;
8822         transition.subresourceRange.aspectMask     = aspectMask;
8823         transition.subresourceRange.baseMipLevel   = 0;
8824         transition.subresourceRange.levelCount     = mLevelCount;
8825         transition.subresourceRange.baseArrayLayer = 0;
8826         transition.subresourceRange.layerCount     = mLayerCount;
8827 
8828         ANGLE_VK_TRY(context, vkTransitionImageLayoutEXT(renderer->getDevice(), 1, &transition));
8829         mCurrentLayout = ImageLayout::HostCopy;
8830     }
8831     else if (mCurrentLayout != ImageLayout::HostCopy &&
8832              !IsAnyLayout(getCurrentLayout(renderer), hostImageCopyProperties.pCopyDstLayouts,
8833                           hostImageCopyProperties.copyDstLayoutCount))
8834     {
8835         return angle::Result::Continue;
8836     }
8837 
8838     const bool isArray            = gl::IsArrayTextureType(index.getType());
8839     const uint32_t baseArrayLayer = isArray ? offset.z : layerIndex;
8840 
8841     onWrite(updateLevelGL, 1, baseArrayLayer, layerCount, aspectMask);
8842     *copiedOut = true;
8843 
8844     // Perform the copy without holding the lock.  This is important for applications that perform
8845     // the copy on a separate thread, and doing all the work while holding the lock effectively
8846     // destroys all parallelism.  Note that the texture may not be used by the other thread without
8847     // appropriate synchronization (such as through glFenceSync), and because the copy is happening
8848     // in this call (just without holding the lock), the sync function won't be called until the
8849     // copy is done.
8850     auto doCopy = [context, image = mImage.getHandle(), source, memoryRowLength, memoryImageHeight,
8851                    aspectMask, levelVk = toVkLevel(updateLevelGL), isArray, baseArrayLayer,
8852                    layerCount, offset, glExtents,
8853                    layout = getCurrentLayout(renderer)](void *resultOut) {
8854         ANGLE_TRACE_EVENT0("gpu.angle", "Upload image data on host");
8855         ANGLE_UNUSED_VARIABLE(resultOut);
8856 
8857         VkMemoryToImageCopyEXT copyRegion          = {};
8858         copyRegion.sType                           = VK_STRUCTURE_TYPE_MEMORY_TO_IMAGE_COPY_EXT;
8859         copyRegion.pHostPointer                    = source;
8860         copyRegion.memoryRowLength                 = memoryRowLength;
8861         copyRegion.memoryImageHeight               = memoryImageHeight;
8862         copyRegion.imageSubresource.aspectMask     = aspectMask;
8863         copyRegion.imageSubresource.mipLevel       = levelVk.get();
8864         copyRegion.imageSubresource.baseArrayLayer = baseArrayLayer;
8865         copyRegion.imageSubresource.layerCount     = layerCount;
8866         gl_vk::GetOffset(offset, &copyRegion.imageOffset);
8867         gl_vk::GetExtent(glExtents, &copyRegion.imageExtent);
8868 
8869         if (isArray)
8870         {
8871             copyRegion.imageOffset.z     = 0;
8872             copyRegion.imageExtent.depth = 1;
8873         }
8874 
8875         VkCopyMemoryToImageInfoEXT copyInfo = {};
8876         copyInfo.sType                      = VK_STRUCTURE_TYPE_COPY_MEMORY_TO_IMAGE_INFO_EXT;
8877         copyInfo.dstImage                   = image;
8878         copyInfo.dstImageLayout             = layout;
8879         copyInfo.regionCount                = 1;
8880         copyInfo.pRegions                   = &copyRegion;
8881 
8882         VkResult result = vkCopyMemoryToImageEXT(context->getDevice(), &copyInfo);
8883         if (result != VK_SUCCESS)
8884         {
8885             context->handleError(result, __FILE__, ANGLE_FUNCTION, __LINE__);
8886         }
8887     };
8888 
8889     switch (applyUpdate)
8890     {
8891         // If possible, perform the copy in an unlocked tail call.  Then the other threads of the
8892         // application are free to draw.
8893         case ApplyImageUpdate::ImmediatelyInUnlockedTailCall:
8894             egl::Display::GetCurrentThreadUnlockedTailCall()->add(doCopy);
8895             break;
8896 
8897         // In some cases, the copy cannot be delayed.  For example because the contents are
8898         // immediately needed (such as when the generate mipmap hint is set), or because unlocked
8899         // tail calls are not allowed (this is the case with incomplete textures which are lazily
8900         // created at draw, but unlocked tail calls are avoided on draw calls due to overhead).
8901         case ApplyImageUpdate::Immediately:
8902             doCopy(nullptr);
8903             break;
8904 
8905         default:
8906             UNREACHABLE();
8907             doCopy(nullptr);
8908     }
8909 
8910     return angle::Result::Continue;
8911 }
8912 
reformatStagedBufferUpdates(ContextVk * contextVk,angle::FormatID srcFormatID,angle::FormatID dstFormatID)8913 angle::Result ImageHelper::reformatStagedBufferUpdates(ContextVk *contextVk,
8914                                                        angle::FormatID srcFormatID,
8915                                                        angle::FormatID dstFormatID)
8916 {
8917     Renderer *renderer             = contextVk->getRenderer();
8918     const angle::Format &srcFormat = angle::Format::Get(srcFormatID);
8919     const angle::Format &dstFormat = angle::Format::Get(dstFormatID);
8920     const gl::InternalFormat &dstFormatInfo =
8921         gl::GetSizedInternalFormatInfo(dstFormat.glInternalFormat);
8922 
8923     for (std::vector<SubresourceUpdate> &levelUpdates : mSubresourceUpdates)
8924     {
8925         for (SubresourceUpdate &update : levelUpdates)
8926         {
8927             // Right now whenever we stage update from a source image, the formats always match.
8928             ASSERT(valid() || update.updateSource != UpdateSource::Image ||
8929                    update.data.image.formatID == srcFormatID);
8930 
8931             if (update.updateSource == UpdateSource::Buffer &&
8932                 update.data.buffer.formatID == srcFormatID)
8933             {
8934                 const VkBufferImageCopy &copy = update.data.buffer.copyRegion;
8935 
8936                 // Source and dst data are tightly packed
8937                 GLuint srcDataRowPitch = copy.imageExtent.width * srcFormat.pixelBytes;
8938                 GLuint dstDataRowPitch = copy.imageExtent.width * dstFormat.pixelBytes;
8939 
8940                 GLuint srcDataDepthPitch = srcDataRowPitch * copy.imageExtent.height;
8941                 GLuint dstDataDepthPitch = dstDataRowPitch * copy.imageExtent.height;
8942 
8943                 // Retrieve source buffer
8944                 vk::BufferHelper *srcBuffer = update.data.buffer.bufferHelper;
8945                 ASSERT(srcBuffer->isMapped());
8946                 // The bufferOffset is relative to the buffer block. We have to use the buffer
8947                 // block's memory pointer to get the source data pointer.
8948                 uint8_t *srcData = srcBuffer->getBlockMemory() + copy.bufferOffset;
8949 
8950                 // Allocate memory with dstFormat
8951                 std::unique_ptr<RefCounted<BufferHelper>> stagingBuffer =
8952                     std::make_unique<RefCounted<BufferHelper>>();
8953                 BufferHelper *dstBuffer = &stagingBuffer->get();
8954 
8955                 uint8_t *dstData;
8956                 VkDeviceSize dstBufferOffset;
8957                 size_t dstBufferSize = dstDataDepthPitch * copy.imageExtent.depth;
8958                 ANGLE_TRY(contextVk->initBufferForImageCopy(
8959                     dstBuffer, dstBufferSize, MemoryCoherency::CachedNonCoherent, dstFormatID,
8960                     &dstBufferOffset, &dstData));
8961 
8962                 rx::PixelReadFunction pixelReadFunction   = srcFormat.pixelReadFunction;
8963                 rx::PixelWriteFunction pixelWriteFunction = dstFormat.pixelWriteFunction;
8964 
8965                 CopyImageCHROMIUM(srcData, srcDataRowPitch, srcFormat.pixelBytes, srcDataDepthPitch,
8966                                   pixelReadFunction, dstData, dstDataRowPitch, dstFormat.pixelBytes,
8967                                   dstDataDepthPitch, pixelWriteFunction, dstFormatInfo.format,
8968                                   dstFormatInfo.componentType, copy.imageExtent.width,
8969                                   copy.imageExtent.height, copy.imageExtent.depth, false, false,
8970                                   false);
8971 
8972                 // Replace srcBuffer with dstBuffer
8973                 update.data.buffer.bufferHelper            = dstBuffer;
8974                 update.data.buffer.formatID                = dstFormatID;
8975                 update.data.buffer.copyRegion.bufferOffset = dstBufferOffset;
8976 
8977                 // Update total staging buffer size
8978                 mTotalStagedBufferUpdateSize -= srcBuffer->getSize();
8979                 mTotalStagedBufferUpdateSize += dstBuffer->getSize();
8980 
8981                 // Let update structure owns the staging buffer
8982                 if (update.refCounted.buffer)
8983                 {
8984                     update.refCounted.buffer->releaseRef();
8985                     if (!update.refCounted.buffer->isReferenced())
8986                     {
8987                         update.refCounted.buffer->get().release(renderer);
8988                         SafeDelete(update.refCounted.buffer);
8989                     }
8990                 }
8991                 update.refCounted.buffer = stagingBuffer.release();
8992                 update.refCounted.buffer->addRef();
8993             }
8994         }
8995     }
8996 
8997     return angle::Result::Continue;
8998 }
8999 
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)9000 angle::Result ImageHelper::CalculateBufferInfo(ContextVk *contextVk,
9001                                                const gl::Extents &glExtents,
9002                                                const gl::InternalFormat &formatInfo,
9003                                                const gl::PixelUnpackState &unpack,
9004                                                GLenum type,
9005                                                bool is3D,
9006                                                GLuint *inputRowPitch,
9007                                                GLuint *inputDepthPitch,
9008                                                GLuint *inputSkipBytes)
9009 {
9010     // YUV formats need special handling.
9011     if (gl::IsYuvFormat(formatInfo.internalFormat))
9012     {
9013         gl::YuvFormatInfo yuvInfo(formatInfo.internalFormat, glExtents);
9014 
9015         // row pitch = Y plane row pitch
9016         *inputRowPitch = yuvInfo.planePitch[0];
9017         // depth pitch = Y plane size + chroma plane size
9018         *inputDepthPitch = yuvInfo.planeSize[0] + yuvInfo.planeSize[1] + yuvInfo.planeSize[2];
9019         *inputSkipBytes  = 0;
9020 
9021         return angle::Result::Continue;
9022     }
9023 
9024     ANGLE_VK_CHECK_MATH(contextVk,
9025                         formatInfo.computeRowPitch(type, glExtents.width, unpack.alignment,
9026                                                    unpack.rowLength, inputRowPitch));
9027 
9028     ANGLE_VK_CHECK_MATH(contextVk,
9029                         formatInfo.computeDepthPitch(glExtents.height, unpack.imageHeight,
9030                                                      *inputRowPitch, inputDepthPitch));
9031 
9032     ANGLE_VK_CHECK_MATH(
9033         contextVk, formatInfo.computeSkipBytes(type, *inputRowPitch, *inputDepthPitch, unpack, is3D,
9034                                                inputSkipBytes));
9035 
9036     return angle::Result::Continue;
9037 }
9038 
onRenderPassAttach(const QueueSerial & queueSerial)9039 void ImageHelper::onRenderPassAttach(const QueueSerial &queueSerial)
9040 {
9041     setQueueSerial(queueSerial);
9042     // updatePipelineStageAccessHistory uses mCurrentLayout which we dont know yet (deferred until
9043     // endRenderPass time). So update it directly since we know attachment will be accessed by
9044     // fragment and attachment stages.
9045     mPipelineStageAccessHeuristic.onAccess(PipelineStageGroup::FragmentOnly);
9046 }
9047 
onWrite(gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags)9048 void ImageHelper::onWrite(gl::LevelIndex levelStart,
9049                           uint32_t levelCount,
9050                           uint32_t layerStart,
9051                           uint32_t layerCount,
9052                           VkImageAspectFlags aspectFlags)
9053 {
9054     mCurrentSingleClearValue.reset();
9055 
9056     // Mark contents of the given subresource as defined.
9057     setContentDefined(toVkLevel(levelStart), levelCount, layerStart, layerCount, aspectFlags);
9058 }
9059 
hasSubresourceDefinedContent(gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount) const9060 bool ImageHelper::hasSubresourceDefinedContent(gl::LevelIndex level,
9061                                                uint32_t layerIndex,
9062                                                uint32_t layerCount) const
9063 {
9064     if (layerIndex >= kMaxContentDefinedLayerCount)
9065     {
9066         return true;
9067     }
9068 
9069     uint8_t layerRangeBits =
9070         GetContentDefinedLayerRangeBits(layerIndex, layerCount, kMaxContentDefinedLayerCount);
9071     return (getLevelContentDefined(toVkLevel(level)) & LevelContentDefinedMask(layerRangeBits))
9072         .any();
9073 }
9074 
hasSubresourceDefinedStencilContent(gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount) const9075 bool ImageHelper::hasSubresourceDefinedStencilContent(gl::LevelIndex level,
9076                                                       uint32_t layerIndex,
9077                                                       uint32_t layerCount) const
9078 {
9079     if (layerIndex >= kMaxContentDefinedLayerCount)
9080     {
9081         return true;
9082     }
9083 
9084     uint8_t layerRangeBits =
9085         GetContentDefinedLayerRangeBits(layerIndex, layerCount, kMaxContentDefinedLayerCount);
9086     return (getLevelStencilContentDefined(toVkLevel(level)) &
9087             LevelContentDefinedMask(layerRangeBits))
9088         .any();
9089 }
9090 
invalidateSubresourceContent(ContextVk * contextVk,gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount,bool * preferToKeepContentsDefinedOut)9091 void ImageHelper::invalidateSubresourceContent(ContextVk *contextVk,
9092                                                gl::LevelIndex level,
9093                                                uint32_t layerIndex,
9094                                                uint32_t layerCount,
9095                                                bool *preferToKeepContentsDefinedOut)
9096 {
9097     invalidateSubresourceContentImpl(
9098         contextVk, level, layerIndex, layerCount,
9099         static_cast<VkImageAspectFlagBits>(getAspectFlags() & ~VK_IMAGE_ASPECT_STENCIL_BIT),
9100         &getLevelContentDefined(toVkLevel(level)), preferToKeepContentsDefinedOut);
9101 }
9102 
invalidateSubresourceStencilContent(ContextVk * contextVk,gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount,bool * preferToKeepContentsDefinedOut)9103 void ImageHelper::invalidateSubresourceStencilContent(ContextVk *contextVk,
9104                                                       gl::LevelIndex level,
9105                                                       uint32_t layerIndex,
9106                                                       uint32_t layerCount,
9107                                                       bool *preferToKeepContentsDefinedOut)
9108 {
9109     invalidateSubresourceContentImpl(
9110         contextVk, level, layerIndex, layerCount, VK_IMAGE_ASPECT_STENCIL_BIT,
9111         &getLevelStencilContentDefined(toVkLevel(level)), preferToKeepContentsDefinedOut);
9112 }
9113 
invalidateSubresourceContentImpl(ContextVk * contextVk,gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount,VkImageAspectFlagBits aspect,LevelContentDefinedMask * contentDefinedMask,bool * preferToKeepContentsDefinedOut)9114 void ImageHelper::invalidateSubresourceContentImpl(ContextVk *contextVk,
9115                                                    gl::LevelIndex level,
9116                                                    uint32_t layerIndex,
9117                                                    uint32_t layerCount,
9118                                                    VkImageAspectFlagBits aspect,
9119                                                    LevelContentDefinedMask *contentDefinedMask,
9120                                                    bool *preferToKeepContentsDefinedOut)
9121 {
9122     // If the aspect being invalidated doesn't exist, skip invalidation altogether.
9123     if ((getAspectFlags() & aspect) == 0)
9124     {
9125         if (preferToKeepContentsDefinedOut)
9126         {
9127             // Let the caller know that this invalidate request was ignored.
9128             *preferToKeepContentsDefinedOut = true;
9129         }
9130         return;
9131     }
9132 
9133     // If the color format is emulated and has extra channels, those channels need to stay cleared.
9134     // On some devices, it's cheaper to skip invalidating the framebuffer attachment, while on
9135     // others it's cheaper to invalidate but then re-clear the image.
9136     //
9137     // For depth/stencil formats, each channel is separately invalidated, so the invalidate is
9138     // simply skipped for the emulated channel on all devices.
9139     const bool hasEmulatedChannels = hasEmulatedImageChannels();
9140     bool skip                      = false;
9141     switch (aspect)
9142     {
9143         case VK_IMAGE_ASPECT_DEPTH_BIT:
9144             skip = hasEmulatedDepthChannel();
9145             break;
9146         case VK_IMAGE_ASPECT_STENCIL_BIT:
9147             skip = hasEmulatedStencilChannel();
9148             break;
9149         case VK_IMAGE_ASPECT_COLOR_BIT:
9150             skip = hasEmulatedChannels &&
9151                    contextVk->getFeatures().preferSkippingInvalidateForEmulatedFormats.enabled;
9152             break;
9153         default:
9154             UNREACHABLE();
9155             skip = true;
9156     }
9157 
9158     if (preferToKeepContentsDefinedOut)
9159     {
9160         *preferToKeepContentsDefinedOut = skip;
9161     }
9162     if (skip)
9163     {
9164         return;
9165     }
9166 
9167     if (layerIndex >= kMaxContentDefinedLayerCount)
9168     {
9169         const char *aspectName = "color";
9170         if (aspect == VK_IMAGE_ASPECT_DEPTH_BIT)
9171         {
9172             aspectName = "depth";
9173         }
9174         else if (aspect == VK_IMAGE_ASPECT_STENCIL_BIT)
9175         {
9176             aspectName = "stencil";
9177         }
9178         ANGLE_VK_PERF_WARNING(
9179             contextVk, GL_DEBUG_SEVERITY_LOW,
9180             "glInvalidateFramebuffer (%s) ineffective on attachments with layer >= 8", aspectName);
9181         return;
9182     }
9183 
9184     uint8_t layerRangeBits =
9185         GetContentDefinedLayerRangeBits(layerIndex, layerCount, kMaxContentDefinedLayerCount);
9186     *contentDefinedMask &= static_cast<uint8_t>(~layerRangeBits);
9187 
9188     // If there are emulated channels, stage a clear to make sure those channels continue to contain
9189     // valid values.
9190     if (hasEmulatedChannels && aspect == VK_IMAGE_ASPECT_COLOR_BIT)
9191     {
9192         VkClearValue clearValue;
9193         clearValue.color = kEmulatedInitColorValue;
9194 
9195         prependSubresourceUpdate(
9196             level, SubresourceUpdate(aspect, clearValue, level, layerIndex, layerCount));
9197         mSubresourceUpdates[level.get()].front().updateSource = UpdateSource::ClearAfterInvalidate;
9198     }
9199 }
9200 
restoreSubresourceContent(gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount)9201 void ImageHelper::restoreSubresourceContent(gl::LevelIndex level,
9202                                             uint32_t layerIndex,
9203                                             uint32_t layerCount)
9204 {
9205     restoreSubresourceContentImpl(
9206         level, layerIndex, layerCount,
9207         static_cast<VkImageAspectFlagBits>(getAspectFlags() & ~VK_IMAGE_ASPECT_STENCIL_BIT),
9208         &getLevelContentDefined(toVkLevel(level)));
9209 }
9210 
restoreSubresourceStencilContent(gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount)9211 void ImageHelper::restoreSubresourceStencilContent(gl::LevelIndex level,
9212                                                    uint32_t layerIndex,
9213                                                    uint32_t layerCount)
9214 {
9215     restoreSubresourceContentImpl(level, layerIndex, layerCount, VK_IMAGE_ASPECT_STENCIL_BIT,
9216                                   &getLevelStencilContentDefined(toVkLevel(level)));
9217 }
9218 
restoreSubresourceContentImpl(gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount,VkImageAspectFlagBits aspect,LevelContentDefinedMask * contentDefinedMask)9219 void ImageHelper::restoreSubresourceContentImpl(gl::LevelIndex level,
9220                                                 uint32_t layerIndex,
9221                                                 uint32_t layerCount,
9222                                                 VkImageAspectFlagBits aspect,
9223                                                 LevelContentDefinedMask *contentDefinedMask)
9224 {
9225     if (layerIndex >= kMaxContentDefinedLayerCount)
9226     {
9227         return;
9228     }
9229 
9230     uint8_t layerRangeBits =
9231         GetContentDefinedLayerRangeBits(layerIndex, layerCount, kMaxContentDefinedLayerCount);
9232 
9233     switch (aspect)
9234     {
9235         case VK_IMAGE_ASPECT_DEPTH_BIT:
9236             // Emulated depth channel should never have been marked invalid, so it can retain its
9237             // cleared value.
9238             ASSERT(!hasEmulatedDepthChannel() ||
9239                    (contentDefinedMask->bits() & layerRangeBits) == layerRangeBits);
9240             break;
9241         case VK_IMAGE_ASPECT_STENCIL_BIT:
9242             // Emulated stencil channel should never have been marked invalid, so it can retain its
9243             // cleared value.
9244             ASSERT(!hasEmulatedStencilChannel() ||
9245                    (contentDefinedMask->bits() & layerRangeBits) == layerRangeBits);
9246             break;
9247         case VK_IMAGE_ASPECT_COLOR_BIT:
9248             // This function is called on attachments during a render pass when it's determined that
9249             // they should no longer be considered invalidated.  For an attachment with emulated
9250             // format that has extra channels, invalidateSubresourceContentImpl may have proactively
9251             // inserted a clear so that the extra channels continue to have defined values.  That
9252             // clear should be removed.
9253             if (hasEmulatedImageChannels())
9254             {
9255                 removeSingleStagedClearAfterInvalidate(level, layerIndex, layerCount);
9256             }
9257             break;
9258         default:
9259             UNREACHABLE();
9260             break;
9261     }
9262 
9263     // Additionally, as the resource has been rewritten to in the render pass, its no longer cleared
9264     // to the cached value.
9265     mCurrentSingleClearValue.reset();
9266 
9267     *contentDefinedMask |= layerRangeBits;
9268 }
9269 
stagePartialClear(ContextVk * contextVk,const gl::Box & clearArea,const ClearTextureMode clearMode,gl::TextureType textureType,uint32_t levelIndex,uint32_t layerIndex,uint32_t layerCount,GLenum type,const gl::InternalFormat & formatInfo,const Format & vkFormat,ImageAccess access,const uint8_t * data)9270 angle::Result ImageHelper::stagePartialClear(ContextVk *contextVk,
9271                                              const gl::Box &clearArea,
9272                                              const ClearTextureMode clearMode,
9273                                              gl::TextureType textureType,
9274                                              uint32_t levelIndex,
9275                                              uint32_t layerIndex,
9276                                              uint32_t layerCount,
9277                                              GLenum type,
9278                                              const gl::InternalFormat &formatInfo,
9279                                              const Format &vkFormat,
9280                                              ImageAccess access,
9281                                              const uint8_t *data)
9282 {
9283     // If the input data pointer is null, the texture is filled with zeros.
9284     const angle::Format &intendedFormat = vkFormat.getIntendedFormat();
9285     const angle::Format &actualFormat   = vkFormat.getActualImageFormat(access);
9286     auto intendedPixelSize              = static_cast<uint32_t>(intendedFormat.pixelBytes);
9287     auto actualPixelSize                = static_cast<uint32_t>(actualFormat.pixelBytes);
9288 
9289     uint8_t intendedData[16] = {0};
9290     if (data != nullptr)
9291     {
9292         memcpy(intendedData, data, intendedPixelSize);
9293     }
9294 
9295     // The appropriate loading function is used to take the original value as a single pixel and
9296     // convert it into the format actually used for this image.
9297     std::vector<uint8_t> actualData(actualPixelSize, 0);
9298     LoadImageFunctionInfo loadFunctionInfo = vkFormat.getTextureLoadFunction(access, type);
9299 
9300     bool stencilOnly = formatInfo.sizedInternalFormat == GL_STENCIL_INDEX8;
9301     if (stencilOnly)
9302     {
9303         // Some Vulkan implementations do not support S8_UINT, so stencil-only data is
9304         // uploaded using one of combined depth-stencil formats there. Since the uploaded
9305         // stencil data must be tightly packed, the actual storage format should be ignored
9306         // with regards to its load function and output row pitch.
9307         loadFunctionInfo.loadFunction = angle::LoadToNative<GLubyte, 1>;
9308     }
9309 
9310     loadFunctionInfo.loadFunction(contextVk->getImageLoadContext(), 1, 1, 1, intendedData, 1, 1,
9311                                   actualData.data(), 1, 1);
9312 
9313     // VkClearValue is used for renderable images.
9314     VkClearValue clearValue = {};
9315     if (formatInfo.isDepthOrStencil())
9316     {
9317         GetVkClearDepthStencilValueFromBytes(intendedData, intendedFormat, &clearValue);
9318     }
9319     else
9320     {
9321         GetVkClearColorValueFromBytes(actualData.data(), actualFormat, &clearValue);
9322     }
9323 
9324     // Stage a ClearPartial update.
9325     VkImageAspectFlags aspectFlags = 0;
9326     if (!formatInfo.isDepthOrStencil())
9327     {
9328         aspectFlags |= VK_IMAGE_ASPECT_COLOR_BIT;
9329     }
9330     else
9331     {
9332         aspectFlags |= formatInfo.depthBits > 0 ? VK_IMAGE_ASPECT_DEPTH_BIT : 0;
9333         aspectFlags |= formatInfo.stencilBits > 0 ? VK_IMAGE_ASPECT_STENCIL_BIT : 0;
9334     }
9335 
9336     if (clearMode == ClearTextureMode::FullClear)
9337     {
9338         bool useLayerAsDepth = textureType == gl::TextureType::CubeMap ||
9339                                textureType == gl::TextureType::CubeMapArray ||
9340                                textureType == gl::TextureType::_2DArray ||
9341                                textureType == gl::TextureType::_2DMultisampleArray;
9342         const gl::ImageIndex index = gl::ImageIndex::MakeFromType(
9343             textureType, levelIndex, 0, useLayerAsDepth ? clearArea.depth : 1);
9344 
9345         appendSubresourceUpdate(gl::LevelIndex(levelIndex),
9346                                 SubresourceUpdate(aspectFlags, clearValue, index));
9347     }
9348     else
9349     {
9350         appendSubresourceUpdate(gl::LevelIndex(levelIndex),
9351                                 SubresourceUpdate(aspectFlags, clearValue, textureType, levelIndex,
9352                                                   layerIndex, layerCount, clearArea));
9353     }
9354     return angle::Result::Continue;
9355 }
9356 
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)9357 angle::Result ImageHelper::stageSubresourceUpdate(ContextVk *contextVk,
9358                                                   const gl::ImageIndex &index,
9359                                                   const gl::Extents &glExtents,
9360                                                   const gl::Offset &offset,
9361                                                   const gl::InternalFormat &formatInfo,
9362                                                   const gl::PixelUnpackState &unpack,
9363                                                   GLenum type,
9364                                                   const uint8_t *pixels,
9365                                                   const Format &vkFormat,
9366                                                   ImageAccess access,
9367                                                   ApplyImageUpdate applyUpdate,
9368                                                   bool *updateAppliedImmediatelyOut)
9369 {
9370     GLuint inputRowPitch   = 0;
9371     GLuint inputDepthPitch = 0;
9372     GLuint inputSkipBytes  = 0;
9373     ANGLE_TRY(CalculateBufferInfo(contextVk, glExtents, formatInfo, unpack, type, index.usesTex3D(),
9374                                   &inputRowPitch, &inputDepthPitch, &inputSkipBytes));
9375 
9376     ANGLE_TRY(stageSubresourceUpdateImpl(
9377         contextVk, index, glExtents, offset, formatInfo, unpack, type, pixels, vkFormat, access,
9378         inputRowPitch, inputDepthPitch, inputSkipBytes, applyUpdate, updateAppliedImmediatelyOut));
9379 
9380     return angle::Result::Continue;
9381 }
9382 
stageSubresourceUpdateAndGetData(ContextVk * contextVk,size_t allocationSize,const gl::ImageIndex & imageIndex,const gl::Extents & glExtents,const gl::Offset & offset,uint8_t ** dstData,angle::FormatID formatID)9383 angle::Result ImageHelper::stageSubresourceUpdateAndGetData(ContextVk *contextVk,
9384                                                             size_t allocationSize,
9385                                                             const gl::ImageIndex &imageIndex,
9386                                                             const gl::Extents &glExtents,
9387                                                             const gl::Offset &offset,
9388                                                             uint8_t **dstData,
9389                                                             angle::FormatID formatID)
9390 {
9391     std::unique_ptr<RefCounted<BufferHelper>> stagingBuffer =
9392         std::make_unique<RefCounted<BufferHelper>>();
9393     BufferHelper *currentBuffer = &stagingBuffer->get();
9394 
9395     VkDeviceSize stagingOffset;
9396     ANGLE_TRY(contextVk->initBufferForImageCopy(currentBuffer, allocationSize,
9397                                                 MemoryCoherency::CachedNonCoherent, formatID,
9398                                                 &stagingOffset, dstData));
9399 
9400     gl::LevelIndex updateLevelGL(imageIndex.getLevelIndex());
9401 
9402     VkBufferImageCopy copy               = {};
9403     copy.bufferOffset                    = stagingOffset;
9404     copy.bufferRowLength                 = glExtents.width;
9405     copy.bufferImageHeight               = glExtents.height;
9406     copy.imageSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
9407     copy.imageSubresource.mipLevel       = updateLevelGL.get();
9408     copy.imageSubresource.baseArrayLayer = imageIndex.hasLayer() ? imageIndex.getLayerIndex() : 0;
9409     copy.imageSubresource.layerCount     = imageIndex.getLayerCount();
9410 
9411     // Note: Only support color now
9412     ASSERT((mActualFormatID == angle::FormatID::NONE) ||
9413            (getAspectFlags() == VK_IMAGE_ASPECT_COLOR_BIT));
9414 
9415     gl_vk::GetOffset(offset, &copy.imageOffset);
9416     gl_vk::GetExtent(glExtents, &copy.imageExtent);
9417 
9418     appendSubresourceUpdate(
9419         updateLevelGL, SubresourceUpdate(stagingBuffer.release(), currentBuffer, copy, formatID));
9420     return angle::Result::Continue;
9421 }
9422 
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)9423 angle::Result ImageHelper::stageSubresourceUpdateFromFramebuffer(
9424     const gl::Context *context,
9425     const gl::ImageIndex &index,
9426     const gl::Rectangle &sourceArea,
9427     const gl::Offset &dstOffset,
9428     const gl::Extents &dstExtent,
9429     const gl::InternalFormat &formatInfo,
9430     ImageAccess access,
9431     FramebufferVk *framebufferVk)
9432 {
9433     ContextVk *contextVk = GetImpl(context);
9434 
9435     // If the extents and offset is outside the source image, we need to clip.
9436     gl::Rectangle clippedRectangle;
9437     const gl::Extents readExtents = framebufferVk->getReadImageExtents();
9438     if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, readExtents.width, readExtents.height),
9439                        &clippedRectangle))
9440     {
9441         // Empty source area, nothing to do.
9442         return angle::Result::Continue;
9443     }
9444 
9445     bool isViewportFlipEnabled = contextVk->isViewportFlipEnabledForDrawFBO();
9446     if (isViewportFlipEnabled)
9447     {
9448         clippedRectangle.y = readExtents.height - clippedRectangle.y - clippedRectangle.height;
9449     }
9450 
9451     // 1- obtain a buffer handle to copy to
9452     Renderer *renderer = contextVk->getRenderer();
9453 
9454     const Format &vkFormat             = renderer->getFormat(formatInfo.sizedInternalFormat);
9455     const angle::Format &storageFormat = vkFormat.getActualImageFormat(access);
9456     LoadImageFunctionInfo loadFunction = vkFormat.getTextureLoadFunction(access, formatInfo.type);
9457 
9458     size_t outputRowPitch   = storageFormat.pixelBytes * clippedRectangle.width;
9459     size_t outputDepthPitch = outputRowPitch * clippedRectangle.height;
9460 
9461     std::unique_ptr<RefCounted<BufferHelper>> stagingBuffer =
9462         std::make_unique<RefCounted<BufferHelper>>();
9463     BufferHelper *currentBuffer = &stagingBuffer->get();
9464 
9465     uint8_t *stagingPointer;
9466     VkDeviceSize stagingOffset;
9467 
9468     // The destination is only one layer deep.
9469     size_t allocationSize = outputDepthPitch;
9470     ANGLE_TRY(contextVk->initBufferForImageCopy(currentBuffer, allocationSize,
9471                                                 MemoryCoherency::CachedNonCoherent,
9472                                                 storageFormat.id, &stagingOffset, &stagingPointer));
9473 
9474     const angle::Format &copyFormat =
9475         GetFormatFromFormatType(formatInfo.internalFormat, formatInfo.type);
9476     PackPixelsParams params(clippedRectangle, copyFormat, static_cast<GLuint>(outputRowPitch),
9477                             isViewportFlipEnabled, nullptr, 0);
9478 
9479     RenderTargetVk *readRenderTarget = framebufferVk->getColorReadRenderTarget();
9480 
9481     // 2- copy the source image region to the pixel buffer using a cpu readback
9482     if (loadFunction.requiresConversion)
9483     {
9484         // When a conversion is required, we need to use the loadFunction to read from a temporary
9485         // buffer instead so its an even slower path.
9486         size_t bufferSize =
9487             storageFormat.pixelBytes * clippedRectangle.width * clippedRectangle.height;
9488         angle::MemoryBuffer *memoryBuffer = nullptr;
9489         ANGLE_VK_CHECK_ALLOC(contextVk, context->getScratchBuffer(bufferSize, &memoryBuffer));
9490 
9491         // Read into the scratch buffer
9492         ANGLE_TRY(framebufferVk->readPixelsImpl(contextVk, clippedRectangle, params,
9493                                                 VK_IMAGE_ASPECT_COLOR_BIT, readRenderTarget,
9494                                                 memoryBuffer->data()));
9495 
9496         // Load from scratch buffer to our pixel buffer
9497         loadFunction.loadFunction(contextVk->getImageLoadContext(), clippedRectangle.width,
9498                                   clippedRectangle.height, 1, memoryBuffer->data(), outputRowPitch,
9499                                   0, stagingPointer, outputRowPitch, 0);
9500     }
9501     else
9502     {
9503         // We read directly from the framebuffer into our pixel buffer.
9504         ANGLE_TRY(framebufferVk->readPixelsImpl(contextVk, clippedRectangle, params,
9505                                                 VK_IMAGE_ASPECT_COLOR_BIT, readRenderTarget,
9506                                                 stagingPointer));
9507     }
9508 
9509     gl::LevelIndex updateLevelGL(index.getLevelIndex());
9510 
9511     // 3- enqueue the destination image subresource update
9512     VkBufferImageCopy copyToImage               = {};
9513     copyToImage.bufferOffset                    = static_cast<VkDeviceSize>(stagingOffset);
9514     copyToImage.bufferRowLength                 = 0;  // Tightly packed data can be specified as 0.
9515     copyToImage.bufferImageHeight               = clippedRectangle.height;
9516     copyToImage.imageSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
9517     copyToImage.imageSubresource.mipLevel       = updateLevelGL.get();
9518     copyToImage.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
9519     copyToImage.imageSubresource.layerCount     = index.getLayerCount();
9520     gl_vk::GetOffset(dstOffset, &copyToImage.imageOffset);
9521     gl_vk::GetExtent(dstExtent, &copyToImage.imageExtent);
9522 
9523     // 3- enqueue the destination image subresource update
9524     appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(stagingBuffer.release(), currentBuffer,
9525                                                              copyToImage, storageFormat.id));
9526 
9527     return angle::Result::Continue;
9528 }
9529 
stageSubresourceUpdateFromImage(RefCounted<ImageHelper> * image,const gl::ImageIndex & index,LevelIndex srcMipLevel,const gl::Offset & destOffset,const gl::Extents & glExtents,const VkImageType imageType)9530 void ImageHelper::stageSubresourceUpdateFromImage(RefCounted<ImageHelper> *image,
9531                                                   const gl::ImageIndex &index,
9532                                                   LevelIndex srcMipLevel,
9533                                                   const gl::Offset &destOffset,
9534                                                   const gl::Extents &glExtents,
9535                                                   const VkImageType imageType)
9536 {
9537     gl::LevelIndex updateLevelGL(index.getLevelIndex());
9538     VkImageAspectFlags imageAspectFlags = vk::GetFormatAspectFlags(image->get().getActualFormat());
9539 
9540     VkImageCopy copyToImage               = {};
9541     copyToImage.srcSubresource.aspectMask = imageAspectFlags;
9542     copyToImage.srcSubresource.mipLevel   = srcMipLevel.get();
9543     copyToImage.srcSubresource.layerCount = index.getLayerCount();
9544     copyToImage.dstSubresource.aspectMask = imageAspectFlags;
9545     copyToImage.dstSubresource.mipLevel   = updateLevelGL.get();
9546 
9547     if (imageType == VK_IMAGE_TYPE_3D)
9548     {
9549         // These values must be set explicitly to follow the Vulkan spec:
9550         // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkImageCopy.html
9551         // If either of the calling command's srcImage or dstImage parameters are of VkImageType
9552         // VK_IMAGE_TYPE_3D, the baseArrayLayer and layerCount members of the corresponding
9553         // subresource must be 0 and 1, respectively
9554         copyToImage.dstSubresource.baseArrayLayer = 0;
9555         copyToImage.dstSubresource.layerCount     = 1;
9556         // Preserve the assumption that destOffset.z == "dstSubresource.baseArrayLayer"
9557         ASSERT(destOffset.z == (index.hasLayer() ? index.getLayerIndex() : 0));
9558     }
9559     else
9560     {
9561         copyToImage.dstSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
9562         copyToImage.dstSubresource.layerCount     = index.getLayerCount();
9563     }
9564 
9565     gl_vk::GetOffset(destOffset, &copyToImage.dstOffset);
9566     gl_vk::GetExtent(glExtents, &copyToImage.extent);
9567 
9568     appendSubresourceUpdate(
9569         updateLevelGL, SubresourceUpdate(image, copyToImage, image->get().getActualFormatID()));
9570 }
9571 
stageSubresourceUpdatesFromAllImageLevels(RefCounted<ImageHelper> * image,gl::LevelIndex baseLevel)9572 void ImageHelper::stageSubresourceUpdatesFromAllImageLevels(RefCounted<ImageHelper> *image,
9573                                                             gl::LevelIndex baseLevel)
9574 {
9575     for (LevelIndex levelVk(0); levelVk < LevelIndex(image->get().getLevelCount()); ++levelVk)
9576     {
9577         const gl::LevelIndex levelGL = vk_gl::GetLevelIndex(levelVk, baseLevel);
9578         const gl::ImageIndex index =
9579             gl::ImageIndex::Make2DArrayRange(levelGL.get(), 0, image->get().getLayerCount());
9580 
9581         stageSubresourceUpdateFromImage(image, index, levelVk, gl::kOffsetZero,
9582                                         image->get().getLevelExtents(levelVk),
9583                                         image->get().getType());
9584     }
9585 }
9586 
stageClear(const gl::ImageIndex & index,VkImageAspectFlags aspectFlags,const VkClearValue & clearValue)9587 void ImageHelper::stageClear(const gl::ImageIndex &index,
9588                              VkImageAspectFlags aspectFlags,
9589                              const VkClearValue &clearValue)
9590 {
9591     gl::LevelIndex updateLevelGL(index.getLevelIndex());
9592     appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(aspectFlags, clearValue, index));
9593 }
9594 
stageRobustResourceClear(const gl::ImageIndex & index)9595 void ImageHelper::stageRobustResourceClear(const gl::ImageIndex &index)
9596 {
9597     const VkImageAspectFlags aspectFlags = getAspectFlags();
9598 
9599     ASSERT(mActualFormatID != angle::FormatID::NONE);
9600     VkClearValue clearValue = GetRobustResourceClearValue(getIntendedFormat(), getActualFormat());
9601 
9602     gl::LevelIndex updateLevelGL(index.getLevelIndex());
9603     appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(aspectFlags, clearValue, index));
9604 }
9605 
stageResourceClearWithFormat(ContextVk * contextVk,const gl::ImageIndex & index,const gl::Extents & glExtents,const angle::Format & intendedFormat,const angle::Format & imageFormat,const VkClearValue & clearValue)9606 angle::Result ImageHelper::stageResourceClearWithFormat(ContextVk *contextVk,
9607                                                         const gl::ImageIndex &index,
9608                                                         const gl::Extents &glExtents,
9609                                                         const angle::Format &intendedFormat,
9610                                                         const angle::Format &imageFormat,
9611                                                         const VkClearValue &clearValue)
9612 {
9613     // Robust clears must only be staged if we do not have any prior data for this subresource.
9614     ASSERT(!hasStagedUpdatesForSubresource(gl::LevelIndex(index.getLevelIndex()),
9615                                            index.getLayerIndex(), index.getLayerCount()));
9616 
9617     const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(imageFormat);
9618 
9619     gl::LevelIndex updateLevelGL(index.getLevelIndex());
9620 
9621     if (imageFormat.isBlock)
9622     {
9623         // This only supports doing an initial clear to 0, not clearing to a specific encoded RGBA
9624         // value
9625         ASSERT((clearValue.color.int32[0] == 0) && (clearValue.color.int32[1] == 0) &&
9626                (clearValue.color.int32[2] == 0) && (clearValue.color.int32[3] == 0));
9627 
9628         const gl::InternalFormat &formatInfo =
9629             gl::GetSizedInternalFormatInfo(imageFormat.glInternalFormat);
9630         GLuint totalSize;
9631         ANGLE_VK_CHECK_MATH(contextVk,
9632                             formatInfo.computeCompressedImageSize(glExtents, &totalSize));
9633 
9634         std::unique_ptr<RefCounted<BufferHelper>> stagingBuffer =
9635             std::make_unique<RefCounted<BufferHelper>>();
9636         BufferHelper *currentBuffer = &stagingBuffer->get();
9637 
9638         uint8_t *stagingPointer;
9639         VkDeviceSize stagingOffset;
9640         ANGLE_TRY(contextVk->initBufferForImageCopy(
9641             currentBuffer, totalSize, MemoryCoherency::CachedNonCoherent, imageFormat.id,
9642             &stagingOffset, &stagingPointer));
9643         memset(stagingPointer, 0, totalSize);
9644 
9645         VkBufferImageCopy copyRegion               = {};
9646         copyRegion.bufferOffset                    = stagingOffset;
9647         copyRegion.imageExtent.width               = glExtents.width;
9648         copyRegion.imageExtent.height              = glExtents.height;
9649         copyRegion.imageExtent.depth               = glExtents.depth;
9650         copyRegion.imageSubresource.mipLevel       = updateLevelGL.get();
9651         copyRegion.imageSubresource.aspectMask     = aspectFlags;
9652         copyRegion.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
9653         copyRegion.imageSubresource.layerCount     = index.getLayerCount();
9654 
9655         // The update structure owns the staging buffer.
9656         appendSubresourceUpdate(
9657             updateLevelGL,
9658             SubresourceUpdate(stagingBuffer.release(), currentBuffer, copyRegion, imageFormat.id));
9659     }
9660     else
9661     {
9662         appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(aspectFlags, clearValue, index));
9663     }
9664 
9665     return angle::Result::Continue;
9666 }
9667 
stageRobustResourceClearWithFormat(ContextVk * contextVk,const gl::ImageIndex & index,const gl::Extents & glExtents,const angle::Format & intendedFormat,const angle::Format & imageFormat)9668 angle::Result ImageHelper::stageRobustResourceClearWithFormat(ContextVk *contextVk,
9669                                                               const gl::ImageIndex &index,
9670                                                               const gl::Extents &glExtents,
9671                                                               const angle::Format &intendedFormat,
9672                                                               const angle::Format &imageFormat)
9673 {
9674     VkClearValue clearValue          = GetRobustResourceClearValue(intendedFormat, imageFormat);
9675     gl::ImageIndex fullResourceIndex = index;
9676     gl::Extents fullResourceExtents  = glExtents;
9677 
9678     if (gl::IsArrayTextureType(index.getType()))
9679     {
9680         // For 2Darray textures gl::Extents::depth is the layer count.
9681         fullResourceIndex = gl::ImageIndex::MakeFromType(
9682             index.getType(), index.getLevelIndex(), gl::ImageIndex::kEntireLevel, glExtents.depth);
9683         // Vulkan requires depth of 1 for 2Darray textures.
9684         fullResourceExtents.depth = 1;
9685     }
9686 
9687     return stageResourceClearWithFormat(contextVk, fullResourceIndex, fullResourceExtents,
9688                                         intendedFormat, imageFormat, clearValue);
9689 }
9690 
stageClearIfEmulatedFormat(bool isRobustResourceInitEnabled,bool isExternalImage)9691 void ImageHelper::stageClearIfEmulatedFormat(bool isRobustResourceInitEnabled, bool isExternalImage)
9692 {
9693     // Skip staging extra clears if robust resource init is enabled.
9694     if (!hasEmulatedImageChannels() || isRobustResourceInitEnabled)
9695     {
9696         return;
9697     }
9698 
9699     VkClearValue clearValue = {};
9700     if (getIntendedFormat().hasDepthOrStencilBits())
9701     {
9702         clearValue.depthStencil = kRobustInitDepthStencilValue;
9703     }
9704     else
9705     {
9706         clearValue.color = kEmulatedInitColorValue;
9707     }
9708 
9709     const VkImageAspectFlags aspectFlags = getAspectFlags();
9710 
9711     // If the image has an emulated channel and robust resource init is not enabled, always clear
9712     // it. These channels will be masked out in future writes, and shouldn't contain uninitialized
9713     // values.
9714     //
9715     // For external images, we cannot clear the image entirely, as it may contain data in the
9716     // non-emulated channels.  For depth/stencil images, clear is already per aspect, but for color
9717     // images we would need to take a special path where we only clear the emulated channels.
9718 
9719     // Block images are not cleared, since no emulated channels are present if decoded.
9720     if (isExternalImage && getIntendedFormat().isBlock)
9721     {
9722         return;
9723     }
9724 
9725     const bool clearOnlyEmulatedChannels =
9726         isExternalImage && !getIntendedFormat().hasDepthOrStencilBits();
9727     const VkColorComponentFlags colorMaskFlags =
9728         clearOnlyEmulatedChannels ? getEmulatedChannelsMask() : 0;
9729 
9730     for (LevelIndex level(0); level < LevelIndex(mLevelCount); ++level)
9731     {
9732         gl::LevelIndex updateLevelGL = toGLLevel(level);
9733         gl::ImageIndex index =
9734             gl::ImageIndex::Make2DArrayRange(updateLevelGL.get(), 0, mLayerCount);
9735 
9736         if (clearOnlyEmulatedChannels)
9737         {
9738             prependSubresourceUpdate(updateLevelGL,
9739                                      SubresourceUpdate(colorMaskFlags, clearValue.color, index));
9740         }
9741         else
9742         {
9743             prependSubresourceUpdate(updateLevelGL,
9744                                      SubresourceUpdate(aspectFlags, clearValue, index));
9745         }
9746     }
9747 }
9748 
verifyEmulatedClearsAreBeforeOtherUpdates(const std::vector<SubresourceUpdate> & updates)9749 bool ImageHelper::verifyEmulatedClearsAreBeforeOtherUpdates(
9750     const std::vector<SubresourceUpdate> &updates)
9751 {
9752     bool isIteratingEmulatedClears = true;
9753 
9754     for (const SubresourceUpdate &update : updates)
9755     {
9756         // If anything other than ClearEmulatedChannelsOnly is visited, there cannot be any
9757         // ClearEmulatedChannelsOnly updates after that.
9758         if (update.updateSource != UpdateSource::ClearEmulatedChannelsOnly)
9759         {
9760             isIteratingEmulatedClears = false;
9761         }
9762         else if (!isIteratingEmulatedClears)
9763         {
9764             // If ClearEmulatedChannelsOnly is visited after another update, that's an error.
9765             return false;
9766         }
9767     }
9768 
9769     // Additionally, verify that emulated clear is not applied multiple times.
9770     if (updates.size() >= 2 && updates[1].updateSource == UpdateSource::ClearEmulatedChannelsOnly)
9771     {
9772         return false;
9773     }
9774 
9775     return true;
9776 }
9777 
stageSelfAsSubresourceUpdates(ContextVk * contextVk,uint32_t levelCount,gl::TextureType textureType,const gl::CubeFaceArray<gl::TexLevelMask> & skipLevels)9778 void ImageHelper::stageSelfAsSubresourceUpdates(
9779     ContextVk *contextVk,
9780     uint32_t levelCount,
9781     gl::TextureType textureType,
9782     const gl::CubeFaceArray<gl::TexLevelMask> &skipLevels)
9783 
9784 {
9785     // Nothing to do if every level must be skipped
9786     const gl::TexLevelMask levelsMask(angle::BitMask<uint32_t>(levelCount)
9787                                       << mFirstAllocatedLevel.get());
9788     const gl::TexLevelMask skipLevelsAllFaces = AggregateSkipLevels(skipLevels);
9789 
9790     if ((~skipLevelsAllFaces & levelsMask).none())
9791     {
9792         return;
9793     }
9794 
9795     // Because we are cloning this object to another object, we must finalize the layout if it is
9796     // being used by current renderpass as attachment. Otherwise we are copying the incorrect layout
9797     // since it is determined at endRenderPass time.
9798     contextVk->finalizeImageLayout(this, {});
9799 
9800     std::unique_ptr<RefCounted<ImageHelper>> prevImage =
9801         std::make_unique<RefCounted<ImageHelper>>();
9802 
9803     // Move the necessary information for staged update to work, and keep the rest as part of this
9804     // object.
9805 
9806     // Usage info
9807     prevImage->get().Resource::operator=(std::move(*this));
9808 
9809     // Vulkan objects
9810     prevImage->get().mImage         = std::move(mImage);
9811     prevImage->get().mDeviceMemory  = std::move(mDeviceMemory);
9812     prevImage->get().mVmaAllocation = std::move(mVmaAllocation);
9813 
9814     // Barrier information.  Note: mLevelCount is set to levelCount so that only the necessary
9815     // levels are transitioned when flushing the update.
9816     prevImage->get().mIntendedFormatID            = mIntendedFormatID;
9817     prevImage->get().mActualFormatID              = mActualFormatID;
9818     prevImage->get().mCurrentLayout               = mCurrentLayout;
9819     prevImage->get().mCurrentDeviceQueueIndex     = mCurrentDeviceQueueIndex;
9820     prevImage->get().mLastNonShaderReadOnlyLayout = mLastNonShaderReadOnlyLayout;
9821     prevImage->get().mCurrentShaderReadStageMask  = mCurrentShaderReadStageMask;
9822     prevImage->get().mLevelCount                  = levelCount;
9823     prevImage->get().mLayerCount                  = mLayerCount;
9824     prevImage->get().mImageSerial                 = mImageSerial;
9825     prevImage->get().mAllocationSize              = mAllocationSize;
9826     prevImage->get().mMemoryAllocationType        = mMemoryAllocationType;
9827     prevImage->get().mMemoryTypeIndex             = mMemoryTypeIndex;
9828 
9829     // Reset information for current (invalid) image.
9830     mCurrentLayout               = ImageLayout::Undefined;
9831     mCurrentDeviceQueueIndex     = kInvalidDeviceQueueIndex;
9832     mIsReleasedToExternal        = false;
9833     mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
9834     mCurrentShaderReadStageMask  = 0;
9835     mImageSerial                 = kInvalidImageSerial;
9836     mMemoryAllocationType        = MemoryAllocationType::InvalidEnum;
9837 
9838     setEntireContentUndefined();
9839 
9840     // Stage updates from the previous image.
9841     for (LevelIndex levelVk(0); levelVk < LevelIndex(levelCount); ++levelVk)
9842     {
9843         gl::LevelIndex levelGL = toGLLevel(levelVk);
9844         if (!skipLevelsAllFaces.test(levelGL.get()))
9845         {
9846             const gl::ImageIndex index =
9847                 gl::ImageIndex::Make2DArrayRange(levelGL.get(), 0, mLayerCount);
9848 
9849             stageSubresourceUpdateFromImage(prevImage.get(), index, levelVk, gl::kOffsetZero,
9850                                             getLevelExtents(levelVk), mImageType);
9851         }
9852         else if (textureType == gl::TextureType::CubeMap)
9853         {
9854             for (uint32_t face = 0; face < gl::kCubeFaceCount; ++face)
9855             {
9856                 if (!skipLevels[face][levelGL.get()])
9857                 {
9858                     const gl::ImageIndex index =
9859                         gl::ImageIndex::Make2DArrayRange(levelGL.get(), face, 1);
9860 
9861                     stageSubresourceUpdateFromImage(prevImage.get(), index, levelVk,
9862                                                     gl::kOffsetZero, getLevelExtents(levelVk),
9863                                                     mImageType);
9864                 }
9865             }
9866         }
9867     }
9868 
9869     ASSERT(levelCount > 0);
9870     prevImage.release();
9871 }
9872 
flushSingleSubresourceStagedUpdates(ContextVk * contextVk,gl::LevelIndex levelGL,uint32_t layer,uint32_t layerCount,ClearValuesArray * deferredClears,uint32_t deferredClearIndex)9873 angle::Result ImageHelper::flushSingleSubresourceStagedUpdates(ContextVk *contextVk,
9874                                                                gl::LevelIndex levelGL,
9875                                                                uint32_t layer,
9876                                                                uint32_t layerCount,
9877                                                                ClearValuesArray *deferredClears,
9878                                                                uint32_t deferredClearIndex)
9879 {
9880     std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(levelGL);
9881     if (levelUpdates == nullptr || levelUpdates->empty())
9882     {
9883         return angle::Result::Continue;
9884     }
9885 
9886     // Handle deferred clears. Search the updates list for a matching clear index.
9887     if (deferredClears)
9888     {
9889         Optional<size_t> foundClear;
9890 
9891         for (size_t updateIndex = 0; updateIndex < levelUpdates->size(); ++updateIndex)
9892         {
9893             SubresourceUpdate &update = (*levelUpdates)[updateIndex];
9894 
9895             if (update.intersectsLayerRange(layer, layerCount))
9896             {
9897                 // On any data update or the clear does not match exact layer range, we'll need to
9898                 // do a full upload.
9899                 const bool isClear = IsClearOfAllChannels(update.updateSource);
9900                 if (isClear && update.matchesLayerRange(layer, layerCount))
9901                 {
9902                     foundClear = updateIndex;
9903                 }
9904                 else
9905                 {
9906                     foundClear.reset();
9907                     break;
9908                 }
9909             }
9910         }
9911 
9912         // If we have a valid index we defer the clear using the clear reference.
9913         if (foundClear.valid())
9914         {
9915             size_t foundIndex         = foundClear.value();
9916             const ClearUpdate &update = (*levelUpdates)[foundIndex].data.clear;
9917 
9918             // Note that this set command handles combined or separate depth/stencil clears.
9919             deferredClears->store(deferredClearIndex, update.aspectFlags, update.value);
9920 
9921             // Do not call onWrite as it removes mCurrentSingleClearValue, but instead call
9922             // setContentDefined directly.
9923             setContentDefined(toVkLevel(levelGL), 1, layer, layerCount, update.aspectFlags);
9924 
9925             // We process the updates again to erase any clears for this level.
9926             removeSingleSubresourceStagedUpdates(contextVk, levelGL, layer, layerCount);
9927             return angle::Result::Continue;
9928         }
9929 
9930         // Otherwise we proceed with a normal update.
9931     }
9932 
9933     return flushStagedUpdates(contextVk, levelGL, levelGL + 1, layer, layer + layerCount, {});
9934 }
9935 
flushStagedClearEmulatedChannelsUpdates(ContextVk * contextVk,gl::LevelIndex levelGLStart,gl::LevelIndex levelGLLimit,bool * otherUpdatesToFlushOut)9936 angle::Result ImageHelper::flushStagedClearEmulatedChannelsUpdates(ContextVk *contextVk,
9937                                                                    gl::LevelIndex levelGLStart,
9938                                                                    gl::LevelIndex levelGLLimit,
9939                                                                    bool *otherUpdatesToFlushOut)
9940 {
9941     *otherUpdatesToFlushOut = false;
9942     for (gl::LevelIndex updateMipLevelGL = levelGLStart; updateMipLevelGL < levelGLLimit;
9943          ++updateMipLevelGL)
9944     {
9945         // It is expected that the checked mip levels in this loop do not surpass the size of
9946         // mSubresourceUpdates.
9947         std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(updateMipLevelGL);
9948         ASSERT(levelUpdates != nullptr);
9949 
9950         // The levels with no updates should be skipped.
9951         if (levelUpdates->empty())
9952         {
9953             continue;
9954         }
9955 
9956         // Since ClearEmulatedChannelsOnly is expected in the beginning and there cannot be more
9957         // than one such update type, we can process the first update and move on if there is
9958         // another update type in the list.
9959         ASSERT(verifyEmulatedClearsAreBeforeOtherUpdates(*levelUpdates));
9960         std::vector<SubresourceUpdate>::iterator update = (*levelUpdates).begin();
9961 
9962         if (update->updateSource != UpdateSource::ClearEmulatedChannelsOnly)
9963         {
9964             *otherUpdatesToFlushOut = true;
9965             continue;
9966         }
9967 
9968         // If found, ClearEmulatedChannelsOnly should be flushed before the others and removed from
9969         // the update list.
9970         ASSERT(update->updateSource == UpdateSource::ClearEmulatedChannelsOnly);
9971         uint32_t updateBaseLayer, updateLayerCount;
9972         update->getDestSubresource(mLayerCount, &updateBaseLayer, &updateLayerCount);
9973 
9974         const LevelIndex updateMipLevelVk = toVkLevel(updateMipLevelGL);
9975         update->data.clear.levelIndex     = updateMipLevelVk.get();
9976         ANGLE_TRY(clearEmulatedChannels(contextVk, update->data.clear.colorMaskFlags,
9977                                         update->data.clear.value, updateMipLevelVk, updateBaseLayer,
9978                                         updateLayerCount));
9979         // Do not call onWrite. Even though some channels of the image are cleared, don't consider
9980         // the contents defined. Also, since clearing emulated channels is a one-time thing that's
9981         // superseded by Clears, |mCurrentSingleClearValue| is irrelevant and can't have a value.
9982         ASSERT(!mCurrentSingleClearValue.valid());
9983 
9984         levelUpdates->erase(update);
9985         if (!levelUpdates->empty())
9986         {
9987             ASSERT(levelUpdates->begin()->updateSource != UpdateSource::ClearEmulatedChannelsOnly);
9988             *otherUpdatesToFlushOut = true;
9989         }
9990     }
9991 
9992     return angle::Result::Continue;
9993 }
9994 
flushStagedUpdatesImpl(ContextVk * contextVk,gl::LevelIndex levelGLStart,gl::LevelIndex levelGLEnd,uint32_t layerStart,uint32_t layerEnd,const gl::TexLevelMask & skipLevelsAllFaces)9995 angle::Result ImageHelper::flushStagedUpdatesImpl(ContextVk *contextVk,
9996                                                   gl::LevelIndex levelGLStart,
9997                                                   gl::LevelIndex levelGLEnd,
9998                                                   uint32_t layerStart,
9999                                                   uint32_t layerEnd,
10000                                                   const gl::TexLevelMask &skipLevelsAllFaces)
10001 {
10002     Renderer *renderer = contextVk->getRenderer();
10003 
10004     const angle::FormatID &actualformat   = getActualFormatID();
10005     const angle::FormatID &intendedFormat = getIntendedFormatID();
10006 
10007     const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(getActualFormat());
10008 
10009     // Start in TransferDst.  Don't yet mark any subresource as having defined contents; that is
10010     // done with fine granularity as updates are applied.  This is achieved by specifying a layer
10011     // that is outside the tracking range. Under some circumstances, ComputeWrite is also required.
10012     // This need not be applied if the only updates are ClearEmulatedChannels.
10013     CommandBufferAccess transferAccess;
10014     OutsideRenderPassCommandBufferHelper *commandBuffer = nullptr;
10015     bool transCoding = renderer->getFeatures().supportsComputeTranscodeEtcToBc.enabled &&
10016                        IsETCFormat(intendedFormat) && IsBCFormat(actualformat);
10017 
10018     if (transCoding)
10019     {
10020         transferAccess.onImageTransferDstAndComputeWrite(
10021             levelGLStart, 1, kMaxContentDefinedLayerCount, 0, aspectFlags, this);
10022     }
10023     else
10024     {
10025         transferAccess.onImageTransferWrite(levelGLStart, 1, kMaxContentDefinedLayerCount, 0,
10026                                             aspectFlags, this);
10027     }
10028     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBufferHelper(transferAccess, &commandBuffer));
10029 
10030     // Flush the staged updates in each mip level.
10031     for (gl::LevelIndex updateMipLevelGL = levelGLStart; updateMipLevelGL < levelGLEnd;
10032          ++updateMipLevelGL)
10033     {
10034         // If updates to this level are specifically asked to be skipped, skip
10035         // them. This can happen when recreating an image that has been partially incompatibly
10036         // redefined, in which case only updates to the levels that haven't been redefined
10037         // should be flushed.
10038         if (skipLevelsAllFaces.test(updateMipLevelGL.get()))
10039         {
10040             continue;
10041         }
10042 
10043         // It is expected that the checked mip levels in this loop do not surpass the size of
10044         // mSubresourceUpdates.
10045         std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(updateMipLevelGL);
10046         std::vector<SubresourceUpdate> updatesToKeep;
10047         ASSERT(levelUpdates != nullptr);
10048 
10049         // Because updates may have overlapping layer ranges, we must first figure out the actual
10050         // layer ranges that will be flushed. The updatesToKeep list must compare against this
10051         // adjusted layer range. Otherwise you may end up keeping the update even though it is
10052         // overlapped with the update that gets flushed, and then content gets overwritten when
10053         // updatesToKeep gets flushed out.
10054         uint32_t adjustedLayerStart = layerStart, adjustedLayerEnd = layerEnd;
10055         if (levelUpdates->size() > 1)
10056         {
10057             adjustLayerRange(*levelUpdates, &adjustedLayerStart, &adjustedLayerEnd);
10058         }
10059 
10060         for (SubresourceUpdate &update : *levelUpdates)
10061         {
10062             ASSERT(IsClearOfAllChannels(update.updateSource) ||
10063                    (update.updateSource == UpdateSource::ClearPartial) ||
10064                    (update.updateSource == UpdateSource::Buffer &&
10065                     update.data.buffer.bufferHelper != nullptr) ||
10066                    (update.updateSource == UpdateSource::Image &&
10067                     update.refCounted.image != nullptr && update.refCounted.image->isReferenced() &&
10068                     update.refCounted.image->get().valid()));
10069 
10070             uint32_t updateBaseLayer, updateLayerCount;
10071             update.getDestSubresource(mLayerCount, &updateBaseLayer, &updateLayerCount);
10072 
10073             // If the update layers don't intersect the requested layers, skip the update.
10074             const bool areUpdateLayersOutsideRange =
10075                 updateBaseLayer + updateLayerCount <= adjustedLayerStart ||
10076                 updateBaseLayer >= adjustedLayerEnd;
10077             if (areUpdateLayersOutsideRange)
10078             {
10079                 updatesToKeep.emplace_back(std::move(update));
10080                 continue;
10081             }
10082 
10083             const LevelIndex updateMipLevelVk = toVkLevel(updateMipLevelGL);
10084 
10085             // It seems we haven't fully support glCopyImageSubData
10086             // when compressed format emulated by uncompressed format.
10087             // make assumption that there is no data source come from image.
10088             ASSERT(!transCoding || (transCoding && update.updateSource == UpdateSource::Buffer));
10089             // The updates were holding gl::LevelIndex values so that they would not need
10090             // modification when the base level of the texture changes.  Now that the update is
10091             // about to take effect, we need to change miplevel to LevelIndex.
10092             switch (update.updateSource)
10093             {
10094                 case UpdateSource::Clear:
10095                 case UpdateSource::ClearAfterInvalidate:
10096                 {
10097                     update.data.clear.levelIndex = updateMipLevelVk.get();
10098                     break;
10099                 }
10100                 case UpdateSource::ClearPartial:
10101                 {
10102                     update.data.clearPartial.levelIndex = updateMipLevelVk.get();
10103                     break;
10104                 }
10105                 case UpdateSource::Buffer:
10106                 {
10107                     if (!transCoding && !isDataFormatMatchForCopy(update.data.buffer.formatID))
10108                     {
10109                         // TODO: http://anglebug.com/42264884, we should handle this in higher level
10110                         // code. If we have incompatible updates, skip but keep it.
10111                         updatesToKeep.emplace_back(std::move(update));
10112                         continue;
10113                     }
10114                     update.data.buffer.copyRegion.imageSubresource.mipLevel =
10115                         updateMipLevelVk.get();
10116                     break;
10117                 }
10118                 case UpdateSource::Image:
10119                 {
10120                     if (!isDataFormatMatchForCopy(update.data.image.formatID))
10121                     {
10122                         // If we have incompatible updates, skip but keep it.
10123                         updatesToKeep.emplace_back(std::move(update));
10124                         continue;
10125                     }
10126                     update.data.image.copyRegion.dstSubresource.mipLevel = updateMipLevelVk.get();
10127                     break;
10128                 }
10129                 default:
10130                 {
10131                     UNREACHABLE();
10132                     break;
10133                 }
10134             }
10135 
10136             // When a barrier is necessary when uploading updates to a level, we could instead move
10137             // to the next level and continue uploads in parallel.  Once all levels need a barrier,
10138             // a single barrier can be issued and we could continue with the rest of the updates
10139             // from the first level. In case of multiple layer updates within the same level, a
10140             // barrier might be needed if there are multiple updates in the same parts of the image.
10141             ImageLayout barrierLayout =
10142                 transCoding ? ImageLayout::TransferDstAndComputeWrite : ImageLayout::TransferDst;
10143             if (updateLayerCount >= kMaxParallelLayerWrites)
10144             {
10145                 // If there are more subresources than bits we can track, always insert a barrier.
10146                 recordWriteBarrier(contextVk, aspectFlags, barrierLayout, updateMipLevelGL, 1,
10147                                    updateBaseLayer, updateLayerCount, commandBuffer);
10148                 mSubresourcesWrittenSinceBarrier[updateMipLevelGL.get()].set();
10149             }
10150             else
10151             {
10152                 ImageLayerWriteMask subresourceHash =
10153                     GetImageLayerWriteMask(updateBaseLayer, updateLayerCount);
10154 
10155                 if (areLevelSubresourcesWrittenWithinMaskRange(updateMipLevelGL.get(),
10156                                                                subresourceHash))
10157                 {
10158                     // If there's overlap in subresource upload, issue a barrier.
10159                     recordWriteBarrier(contextVk, aspectFlags, barrierLayout, updateMipLevelGL, 1,
10160                                        updateBaseLayer, updateLayerCount, commandBuffer);
10161                     mSubresourcesWrittenSinceBarrier[updateMipLevelGL.get()].reset();
10162                 }
10163                 mSubresourcesWrittenSinceBarrier[updateMipLevelGL.get()] |= subresourceHash;
10164             }
10165 
10166             // Add the necessary commands to the outside command buffer.
10167             switch (update.updateSource)
10168             {
10169                 case UpdateSource::Clear:
10170                 case UpdateSource::ClearAfterInvalidate:
10171                 {
10172                     clear(renderer, update.data.clear.aspectFlags, update.data.clear.value,
10173                           updateMipLevelVk, updateBaseLayer, updateLayerCount,
10174                           &commandBuffer->getCommandBuffer());
10175                     contextVk->getPerfCounters().fullImageClears++;
10176                     // Remember the latest operation is a clear call.
10177                     mCurrentSingleClearValue = update.data.clear;
10178 
10179                     // Do not call onWrite as it removes mCurrentSingleClearValue, but instead call
10180                     // setContentDefined directly.
10181                     setContentDefined(updateMipLevelVk, 1, updateBaseLayer, updateLayerCount,
10182                                       update.data.clear.aspectFlags);
10183                     break;
10184                 }
10185                 case UpdateSource::ClearPartial:
10186                 {
10187                     ClearPartialUpdate &clearPartialUpdate = update.data.clearPartial;
10188                     gl::Box clearArea =
10189                         gl::Box(clearPartialUpdate.offset, clearPartialUpdate.extent);
10190 
10191                     // clearTexture() uses LOAD_OP_CLEAR in a render pass to clear the texture. If
10192                     // the texture has the depth dimension or multiple layers, the clear will be
10193                     // performed layer by layer. In case of the former, the z-dimension will be used
10194                     // as the layer index.
10195                     UtilsVk::ClearTextureParameters params = {};
10196                     params.aspectFlags                     = clearPartialUpdate.aspectFlags;
10197                     params.level                           = updateMipLevelVk;
10198                     params.clearArea                       = clearArea;
10199                     params.clearValue                      = clearPartialUpdate.clearValue;
10200 
10201                     bool shouldUseDepthAsLayer =
10202                         clearPartialUpdate.textureType == gl::TextureType::_3D;
10203                     uint32_t clearBaseLayer =
10204                         shouldUseDepthAsLayer ? clearArea.z : clearPartialUpdate.layerIndex;
10205                     uint32_t clearLayerCount =
10206                         shouldUseDepthAsLayer ? clearArea.depth : clearPartialUpdate.layerCount;
10207 
10208                     for (uint32_t layerIndex = clearBaseLayer;
10209                          layerIndex < clearBaseLayer + clearLayerCount; ++layerIndex)
10210                     {
10211                         params.layer = layerIndex;
10212                         ANGLE_TRY(contextVk->getUtils().clearTexture(contextVk, this, params));
10213                     }
10214 
10215                     // Queue serial index becomes invalid after starting render pass for the op
10216                     // above. Therefore, the outside command buffer should be re-acquired.
10217                     ANGLE_TRY(
10218                         contextVk->getOutsideRenderPassCommandBufferHelper({}, &commandBuffer));
10219                     setContentDefined(updateMipLevelVk, 1, updateBaseLayer, updateLayerCount,
10220                                       clearPartialUpdate.aspectFlags);
10221                     break;
10222                 }
10223                 case UpdateSource::Buffer:
10224                 {
10225                     BufferUpdate &bufferUpdate = update.data.buffer;
10226 
10227                     BufferHelper *currentBuffer = bufferUpdate.bufferHelper;
10228                     ASSERT(currentBuffer && currentBuffer->valid());
10229                     ANGLE_TRY(currentBuffer->flush(renderer));
10230 
10231                     CommandBufferAccess bufferAccess;
10232                     VkBufferImageCopy *copyRegion = &update.data.buffer.copyRegion;
10233 
10234                     if (transCoding && update.data.buffer.formatID != actualformat)
10235                     {
10236                         bufferAccess.onBufferComputeShaderRead(currentBuffer);
10237                         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBufferHelper(
10238                             bufferAccess, &commandBuffer));
10239                         ANGLE_TRY(contextVk->getUtils().transCodeEtcToBc(contextVk, currentBuffer,
10240                                                                          this, copyRegion));
10241                     }
10242                     else
10243                     {
10244                         bufferAccess.onBufferTransferRead(currentBuffer);
10245                         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBufferHelper(
10246                             bufferAccess, &commandBuffer));
10247                         commandBuffer->getCommandBuffer().copyBufferToImage(
10248                             currentBuffer->getBuffer().getHandle(), mImage,
10249                             getCurrentLayout(renderer), 1, copyRegion);
10250                     }
10251                     bool commandBufferWasFlushed = false;
10252                     ANGLE_TRY(contextVk->onCopyUpdate(currentBuffer->getSize(),
10253                                                       &commandBufferWasFlushed));
10254                     onWrite(updateMipLevelGL, 1, updateBaseLayer, updateLayerCount,
10255                             copyRegion->imageSubresource.aspectMask);
10256 
10257                     // Update total staging buffer size.
10258                     mTotalStagedBufferUpdateSize -= bufferUpdate.bufferHelper->getSize();
10259 
10260                     if (commandBufferWasFlushed)
10261                     {
10262                         ANGLE_TRY(
10263                             contextVk->getOutsideRenderPassCommandBufferHelper({}, &commandBuffer));
10264                     }
10265                     break;
10266                 }
10267                 case UpdateSource::Image:
10268                 {
10269                     CommandBufferAccess imageAccess;
10270                     imageAccess.onImageTransferRead(aspectFlags, &update.refCounted.image->get());
10271                     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBufferHelper(imageAccess,
10272                                                                                  &commandBuffer));
10273 
10274                     VkImageCopy *copyRegion = &update.data.image.copyRegion;
10275                     commandBuffer->getCommandBuffer().copyImage(
10276                         update.refCounted.image->get().getImage(),
10277                         update.refCounted.image->get().getCurrentLayout(renderer), mImage,
10278                         getCurrentLayout(renderer), 1, copyRegion);
10279                     onWrite(updateMipLevelGL, 1, updateBaseLayer, updateLayerCount,
10280                             copyRegion->dstSubresource.aspectMask);
10281                     break;
10282                 }
10283                 default:
10284                 {
10285                     UNREACHABLE();
10286                     break;
10287                 }
10288             }
10289 
10290             update.release(renderer);
10291         }
10292 
10293         // Only remove the updates that were actually applied to the image.
10294         *levelUpdates = std::move(updatesToKeep);
10295     }
10296 
10297     // After applying the updates, the image serial should match the current queue serial of the
10298     // outside command buffer.
10299     if (mUse.getSerials()[commandBuffer->getQueueSerial().getIndex()] !=
10300         commandBuffer->getQueueSerial().getSerial())
10301     {
10302         // There has been a submission after the retainImage() call. Update the queue serial again.
10303         setQueueSerial(commandBuffer->getQueueSerial());
10304     }
10305 
10306     return angle::Result::Continue;
10307 }
10308 
flushStagedUpdates(ContextVk * contextVk,gl::LevelIndex levelGLStart,gl::LevelIndex levelGLEnd,uint32_t layerStart,uint32_t layerEnd,const gl::CubeFaceArray<gl::TexLevelMask> & skipLevels)10309 angle::Result ImageHelper::flushStagedUpdates(ContextVk *contextVk,
10310                                               gl::LevelIndex levelGLStart,
10311                                               gl::LevelIndex levelGLEnd,
10312                                               uint32_t layerStart,
10313                                               uint32_t layerEnd,
10314                                               const gl::CubeFaceArray<gl::TexLevelMask> &skipLevels)
10315 {
10316     Renderer *renderer = contextVk->getRenderer();
10317 
10318     if (!hasStagedUpdatesInLevels(levelGLStart, levelGLEnd))
10319     {
10320         return angle::Result::Continue;
10321     }
10322 
10323     const gl::TexLevelMask skipLevelsAllFaces = AggregateSkipLevels(skipLevels);
10324     removeSupersededUpdates(contextVk, skipLevelsAllFaces);
10325 
10326     // If a clear is requested and we know it was previously cleared with the same value, we drop
10327     // the clear.
10328     if (mCurrentSingleClearValue.valid())
10329     {
10330         std::vector<SubresourceUpdate> *levelUpdates =
10331             getLevelUpdates(gl::LevelIndex(mCurrentSingleClearValue.value().levelIndex));
10332         if (levelUpdates && levelUpdates->size() == 1)
10333         {
10334             SubresourceUpdate &update = (*levelUpdates)[0];
10335             if (IsClearOfAllChannels(update.updateSource) &&
10336                 mCurrentSingleClearValue.value() == update.data.clear)
10337             {
10338                 ASSERT(levelGLStart + 1 == levelGLEnd);
10339                 setContentDefined(toVkLevel(levelGLStart), 1, layerStart, layerEnd - layerStart,
10340                                   update.data.clear.aspectFlags);
10341                 ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_LOW,
10342                                       "Repeated Clear on framebuffer attachment dropped");
10343                 update.release(renderer);
10344                 levelUpdates->clear();
10345                 return angle::Result::Continue;
10346             }
10347         }
10348     }
10349 
10350     ASSERT(validateSubresourceUpdateRefCountsConsistent());
10351 
10352     // Process the clear emulated channels from the updates first. They are expected to be at the
10353     // beginning of the level updates.
10354     bool otherUpdatesToFlushOut = false;
10355     clipLevelToUpdateListUpperLimit(&levelGLEnd);
10356     ANGLE_TRY(flushStagedClearEmulatedChannelsUpdates(contextVk, levelGLStart, levelGLEnd,
10357                                                       &otherUpdatesToFlushOut));
10358 
10359     // If updates remain after processing ClearEmulatedChannelsOnly updates, we should acquire the
10360     // outside command buffer and apply the necessary barriers. Otherwise, this function can return
10361     // early, skipping the next loop.
10362     if (otherUpdatesToFlushOut)
10363     {
10364         ANGLE_TRY(flushStagedUpdatesImpl(contextVk, levelGLStart, levelGLEnd, layerStart, layerEnd,
10365                                          skipLevelsAllFaces));
10366     }
10367 
10368     // Compact mSubresourceUpdates, then check if there are any updates left.
10369     size_t compactSize;
10370     for (compactSize = mSubresourceUpdates.size(); compactSize > 0; --compactSize)
10371     {
10372         if (!mSubresourceUpdates[compactSize - 1].empty())
10373         {
10374             break;
10375         }
10376     }
10377     mSubresourceUpdates.resize(compactSize);
10378 
10379     ASSERT(validateSubresourceUpdateRefCountsConsistent());
10380 
10381     // If no updates left, release the staging buffers to save memory.
10382     if (mSubresourceUpdates.empty())
10383     {
10384         ASSERT(mTotalStagedBufferUpdateSize == 0);
10385         onStateChange(angle::SubjectMessage::InitializationComplete);
10386     }
10387 
10388     return angle::Result::Continue;
10389 }
10390 
flushAllStagedUpdates(ContextVk * contextVk)10391 angle::Result ImageHelper::flushAllStagedUpdates(ContextVk *contextVk)
10392 {
10393     return flushStagedUpdates(contextVk, mFirstAllocatedLevel, mFirstAllocatedLevel + mLevelCount,
10394                               0, mLayerCount, {});
10395 }
10396 
hasStagedUpdatesForSubresource(gl::LevelIndex levelGL,uint32_t layer,uint32_t layerCount) const10397 bool ImageHelper::hasStagedUpdatesForSubresource(gl::LevelIndex levelGL,
10398                                                  uint32_t layer,
10399                                                  uint32_t layerCount) const
10400 {
10401     // Check to see if any updates are staged for the given level and layer
10402 
10403     const std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(levelGL);
10404     if (levelUpdates == nullptr || levelUpdates->empty())
10405     {
10406         return false;
10407     }
10408 
10409     for (const SubresourceUpdate &update : *levelUpdates)
10410     {
10411         uint32_t updateBaseLayer, updateLayerCount;
10412         update.getDestSubresource(mLayerCount, &updateBaseLayer, &updateLayerCount);
10413 
10414         const uint32_t updateLayerEnd = updateBaseLayer + updateLayerCount;
10415         const uint32_t layerEnd       = layer + layerCount;
10416 
10417         if ((layer >= updateBaseLayer && layer < updateLayerEnd) ||
10418             (layerEnd > updateBaseLayer && layerEnd <= updateLayerEnd))
10419         {
10420             // The layers intersect with the update range
10421             return true;
10422         }
10423     }
10424 
10425     return false;
10426 }
10427 
removeStagedClearUpdatesAndReturnColor(gl::LevelIndex levelGL,const VkClearColorValue ** color)10428 bool ImageHelper::removeStagedClearUpdatesAndReturnColor(gl::LevelIndex levelGL,
10429                                                          const VkClearColorValue **color)
10430 {
10431     std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(levelGL);
10432     if (levelUpdates == nullptr || levelUpdates->empty())
10433     {
10434         return false;
10435     }
10436 
10437     bool result = false;
10438 
10439     for (size_t index = 0; index < levelUpdates->size();)
10440     {
10441         auto update = levelUpdates->begin() + index;
10442         if (IsClearOfAllChannels(update->updateSource))
10443         {
10444             if (color != nullptr)
10445             {
10446                 *color = &update->data.clear.value.color;
10447             }
10448             levelUpdates->erase(update);
10449             result = true;
10450         }
10451     }
10452 
10453     return result;
10454 }
10455 
adjustLayerRange(const std::vector<SubresourceUpdate> & levelUpdates,uint32_t * layerStart,uint32_t * layerEnd)10456 void ImageHelper::adjustLayerRange(const std::vector<SubresourceUpdate> &levelUpdates,
10457                                    uint32_t *layerStart,
10458                                    uint32_t *layerEnd)
10459 {
10460     for (const SubresourceUpdate &update : levelUpdates)
10461     {
10462         uint32_t updateBaseLayer, updateLayerCount;
10463         update.getDestSubresource(mLayerCount, &updateBaseLayer, &updateLayerCount);
10464         uint32_t updateLayerEnd = updateBaseLayer + updateLayerCount;
10465 
10466         // In some cases, the update has the bigger layer range than the request. If the update
10467         // layers intersect the requested layers, then expand the layer range to the maximum from
10468         // the update and from the request.
10469         const bool areUpdateLayersWithinRange =
10470             updateBaseLayer < *layerEnd && updateLayerEnd > *layerStart;
10471         if (areUpdateLayersWithinRange)
10472         {
10473             *layerStart = std::min(*layerStart, updateBaseLayer);
10474             *layerEnd   = std::max(*layerEnd, updateLayerEnd);
10475         }
10476     }
10477 }
10478 
getLastAllocatedLevel() const10479 gl::LevelIndex ImageHelper::getLastAllocatedLevel() const
10480 {
10481     return mFirstAllocatedLevel + mLevelCount - 1;
10482 }
10483 
hasStagedUpdatesInAllocatedLevels() const10484 bool ImageHelper::hasStagedUpdatesInAllocatedLevels() const
10485 {
10486     return hasStagedUpdatesInLevels(mFirstAllocatedLevel, getLastAllocatedLevel() + 1);
10487 }
10488 
hasStagedUpdatesInLevels(gl::LevelIndex levelStart,gl::LevelIndex levelEnd) const10489 bool ImageHelper::hasStagedUpdatesInLevels(gl::LevelIndex levelStart, gl::LevelIndex levelEnd) const
10490 {
10491     for (gl::LevelIndex level = levelStart; level < levelEnd; ++level)
10492     {
10493         const std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(level);
10494         if (levelUpdates == nullptr)
10495         {
10496             ASSERT(static_cast<size_t>(level.get()) >= mSubresourceUpdates.size());
10497             return false;
10498         }
10499 
10500         if (!levelUpdates->empty())
10501         {
10502             return true;
10503         }
10504     }
10505     return false;
10506 }
10507 
hasStagedImageUpdatesWithMismatchedFormat(gl::LevelIndex levelStart,gl::LevelIndex levelEnd,angle::FormatID formatID) const10508 bool ImageHelper::hasStagedImageUpdatesWithMismatchedFormat(gl::LevelIndex levelStart,
10509                                                             gl::LevelIndex levelEnd,
10510                                                             angle::FormatID formatID) const
10511 {
10512     for (gl::LevelIndex level = levelStart; level < levelEnd; ++level)
10513     {
10514         const std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(level);
10515         if (levelUpdates == nullptr)
10516         {
10517             continue;
10518         }
10519 
10520         for (const SubresourceUpdate &update : *levelUpdates)
10521         {
10522             if (update.updateSource == UpdateSource::Image &&
10523                 update.data.image.formatID != formatID)
10524             {
10525                 return true;
10526             }
10527         }
10528     }
10529     return false;
10530 }
10531 
hasBufferSourcedStagedUpdatesInAllLevels() const10532 bool ImageHelper::hasBufferSourcedStagedUpdatesInAllLevels() const
10533 {
10534     for (gl::LevelIndex level = mFirstAllocatedLevel; level <= getLastAllocatedLevel(); ++level)
10535     {
10536         const std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(level);
10537         if (levelUpdates == nullptr || levelUpdates->empty())
10538         {
10539             return false;
10540         }
10541 
10542         bool hasUpdateSourceWithBufferOrPartialClear = false;
10543         for (const SubresourceUpdate &update : *levelUpdates)
10544         {
10545             if (update.updateSource == UpdateSource::Buffer ||
10546                 update.updateSource == UpdateSource::ClearPartial)
10547             {
10548                 hasUpdateSourceWithBufferOrPartialClear = true;
10549                 break;
10550             }
10551         }
10552         if (!hasUpdateSourceWithBufferOrPartialClear)
10553         {
10554             return false;
10555         }
10556     }
10557     return true;
10558 }
10559 
validateSubresourceUpdateBufferRefConsistent(RefCounted<BufferHelper> * buffer) const10560 bool ImageHelper::validateSubresourceUpdateBufferRefConsistent(
10561     RefCounted<BufferHelper> *buffer) const
10562 {
10563     if (buffer == nullptr)
10564     {
10565         return true;
10566     }
10567 
10568     uint32_t refs = 0;
10569 
10570     for (const std::vector<SubresourceUpdate> &levelUpdates : mSubresourceUpdates)
10571     {
10572         for (const SubresourceUpdate &update : levelUpdates)
10573         {
10574             if (update.updateSource == UpdateSource::Buffer && update.refCounted.buffer == buffer)
10575             {
10576                 ++refs;
10577             }
10578         }
10579     }
10580 
10581     return buffer->isRefCountAsExpected(refs);
10582 }
10583 
validateSubresourceUpdateImageRefConsistent(RefCounted<ImageHelper> * image) const10584 bool ImageHelper::validateSubresourceUpdateImageRefConsistent(RefCounted<ImageHelper> *image) const
10585 {
10586     if (image == nullptr)
10587     {
10588         return true;
10589     }
10590 
10591     uint32_t refs = 0;
10592 
10593     for (const std::vector<SubresourceUpdate> &levelUpdates : mSubresourceUpdates)
10594     {
10595         for (const SubresourceUpdate &update : levelUpdates)
10596         {
10597             if (update.updateSource == UpdateSource::Image && update.refCounted.image == image)
10598             {
10599                 ++refs;
10600             }
10601         }
10602     }
10603 
10604     return image->isRefCountAsExpected(refs);
10605 }
10606 
validateSubresourceUpdateRefCountsConsistent() const10607 bool ImageHelper::validateSubresourceUpdateRefCountsConsistent() const
10608 {
10609     for (const std::vector<SubresourceUpdate> &levelUpdates : mSubresourceUpdates)
10610     {
10611         for (const SubresourceUpdate &update : levelUpdates)
10612         {
10613             if (update.updateSource == UpdateSource::Image)
10614             {
10615                 if (!validateSubresourceUpdateImageRefConsistent(update.refCounted.image))
10616                 {
10617                     return false;
10618                 }
10619             }
10620             else if (update.updateSource == UpdateSource::Buffer)
10621             {
10622                 if (!validateSubresourceUpdateBufferRefConsistent(update.refCounted.buffer))
10623                 {
10624                     return false;
10625                 }
10626             }
10627         }
10628     }
10629 
10630     return true;
10631 }
10632 
pruneSupersededUpdatesForLevel(ContextVk * contextVk,const gl::LevelIndex level,const PruneReason reason)10633 void ImageHelper::pruneSupersededUpdatesForLevel(ContextVk *contextVk,
10634                                                  const gl::LevelIndex level,
10635                                                  const PruneReason reason)
10636 {
10637     constexpr VkDeviceSize kSubresourceUpdateSizeBeforePruning = 16 * 1024 * 1024;  // 16 MB
10638     constexpr int kUpdateCountThreshold                        = 1024;
10639     std::vector<ImageHelper::SubresourceUpdate> *levelUpdates  = getLevelUpdates(level);
10640 
10641     // If we are below pruning threshold, nothing to do.
10642     const int updateCount      = static_cast<int>(levelUpdates->size());
10643     const bool withinThreshold = updateCount < kUpdateCountThreshold &&
10644                                  mTotalStagedBufferUpdateSize < kSubresourceUpdateSizeBeforePruning;
10645     if (updateCount == 1 || (reason == PruneReason::MemoryOptimization && withinThreshold))
10646     {
10647         return;
10648     }
10649 
10650     // Start from the most recent update and define a boundingBox that covers the region to be
10651     // updated. Walk through all earlier updates and if its update region is contained within the
10652     // boundingBox, mark it as superseded, otherwise reset the boundingBox and continue.
10653     //
10654     // Color, depth and stencil are the only types supported for now. The boundingBox for color and
10655     // depth types is at index 0 and index 1 has the boundingBox for stencil type.
10656     VkDeviceSize supersededUpdateSize  = 0;
10657     std::array<gl::Box, 2> boundingBox = {gl::Box(gl::kOffsetZero, gl::Extents())};
10658 
10659     auto canDropUpdate = [this, contextVk, level, &supersededUpdateSize,
10660                           &boundingBox](SubresourceUpdate &update) {
10661         VkDeviceSize updateSize       = 0;
10662         VkImageAspectFlags aspectMask = update.getDestAspectFlags();
10663         gl::Box currentUpdateBox(gl::kOffsetZero, gl::Extents());
10664 
10665         const bool isColor =
10666             (aspectMask & (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_PLANE_0_BIT |
10667                            VK_IMAGE_ASPECT_PLANE_1_BIT | VK_IMAGE_ASPECT_PLANE_2_BIT)) != 0;
10668         const bool isDepth   = (aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0;
10669         const bool isStencil = (aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0;
10670         ASSERT(isColor || isDepth || isStencil);
10671         int aspectIndex = (isColor || isDepth) ? 0 : 1;
10672 
10673         if (update.updateSource == UpdateSource::Buffer)
10674         {
10675             currentUpdateBox = gl::Box(update.data.buffer.copyRegion.imageOffset,
10676                                        update.data.buffer.copyRegion.imageExtent);
10677             updateSize       = update.data.buffer.bufferHelper->getSize();
10678         }
10679         else if (update.updateSource == UpdateSource::Image)
10680         {
10681             currentUpdateBox = gl::Box(update.data.image.copyRegion.dstOffset,
10682                                        update.data.image.copyRegion.extent);
10683         }
10684         else if (update.updateSource == UpdateSource::ClearPartial)
10685         {
10686             currentUpdateBox = gl::Box(
10687                 update.data.clearPartial.offset.x, update.data.clearPartial.offset.z,
10688                 update.data.clearPartial.offset.z, update.data.clearPartial.extent.width,
10689                 update.data.clearPartial.extent.height, update.data.clearPartial.extent.depth);
10690         }
10691         else
10692         {
10693             ASSERT(IsClear(update.updateSource));
10694             currentUpdateBox = gl::Box(gl::kOffsetZero, getLevelExtents(toVkLevel(level)));
10695         }
10696 
10697         // Account for updates to layered images
10698         uint32_t layerIndex = 0;
10699         uint32_t layerCount = 0;
10700         update.getDestSubresource(mLayerCount, &layerIndex, &layerCount);
10701         if (layerIndex > 0 || layerCount > 1)
10702         {
10703             currentUpdateBox.z     = layerIndex;
10704             currentUpdateBox.depth = layerCount;
10705         }
10706 
10707         // Check if current update region is superseded by the accumulated update region
10708         if (boundingBox[aspectIndex].contains(currentUpdateBox))
10709         {
10710             ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_LOW,
10711                                   "Dropped texture update that is superseded by a more recent one");
10712 
10713             // Release the superseded update
10714             update.release(contextVk->getRenderer());
10715 
10716             // Update pruning size
10717             supersededUpdateSize += updateSize;
10718 
10719             return true;
10720         }
10721         else
10722         {
10723             // Extend boundingBox to best accommodate current update's box.
10724             boundingBox[aspectIndex].extend(currentUpdateBox);
10725             // If the volume of the current update box is larger than the extended boundingBox
10726             // use that as the new boundingBox instead.
10727             if (currentUpdateBox.volume() > boundingBox[aspectIndex].volume())
10728             {
10729                 boundingBox[aspectIndex] = currentUpdateBox;
10730             }
10731             return false;
10732         }
10733     };
10734 
10735     levelUpdates->erase(
10736         levelUpdates->begin(),
10737         std::remove_if(levelUpdates->rbegin(), levelUpdates->rend(), canDropUpdate).base());
10738 
10739     // Update total staging buffer size
10740     mTotalStagedBufferUpdateSize -= supersededUpdateSize;
10741 }
10742 
removeSupersededUpdates(ContextVk * contextVk,const gl::TexLevelMask skipLevelsAllFaces)10743 void ImageHelper::removeSupersededUpdates(ContextVk *contextVk,
10744                                           const gl::TexLevelMask skipLevelsAllFaces)
10745 {
10746     ASSERT(validateSubresourceUpdateRefCountsConsistent());
10747 
10748     for (LevelIndex levelVk(0); levelVk < LevelIndex(mLevelCount); ++levelVk)
10749     {
10750         gl::LevelIndex levelGL                       = toGLLevel(levelVk);
10751         std::vector<SubresourceUpdate> *levelUpdates = getLevelUpdates(levelGL);
10752         if (levelUpdates == nullptr || levelUpdates->size() == 0 ||
10753             skipLevelsAllFaces.test(levelGL.get()))
10754         {
10755             // There are no valid updates to process, continue.
10756             continue;
10757         }
10758 
10759         // ClearEmulatedChannelsOnly updates can only be in the beginning of the list of updates.
10760         // They don't entirely clear the image, so they cannot supersede any update.
10761         ASSERT(verifyEmulatedClearsAreBeforeOtherUpdates(*levelUpdates));
10762 
10763         pruneSupersededUpdatesForLevel(contextVk, levelGL, PruneReason::MinimizeWorkBeforeFlush);
10764     }
10765 
10766     ASSERT(validateSubresourceUpdateRefCountsConsistent());
10767 }
10768 
copyImageDataToBuffer(ContextVk * contextVk,gl::LevelIndex sourceLevelGL,uint32_t layerCount,uint32_t baseLayer,const gl::Box & sourceArea,BufferHelper * dstBuffer,uint8_t ** outDataPtr)10769 angle::Result ImageHelper::copyImageDataToBuffer(ContextVk *contextVk,
10770                                                  gl::LevelIndex sourceLevelGL,
10771                                                  uint32_t layerCount,
10772                                                  uint32_t baseLayer,
10773                                                  const gl::Box &sourceArea,
10774                                                  BufferHelper *dstBuffer,
10775                                                  uint8_t **outDataPtr)
10776 {
10777     ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::copyImageDataToBuffer");
10778     Renderer *renderer = contextVk->getRenderer();
10779 
10780     const angle::Format &imageFormat = getActualFormat();
10781 
10782     // As noted in the OpenGL ES 3.2 specs, table 8.13, CopyTexImage cannot
10783     // be used for depth textures. There is no way for the image or buffer
10784     // used in this function to be of some combined depth and stencil format.
10785     ASSERT(getAspectFlags() == VK_IMAGE_ASPECT_COLOR_BIT);
10786 
10787     uint32_t pixelBytes = imageFormat.pixelBytes;
10788     size_t bufferSize =
10789         sourceArea.width * sourceArea.height * sourceArea.depth * pixelBytes * layerCount;
10790 
10791     const VkImageAspectFlags aspectFlags = getAspectFlags();
10792 
10793     // Allocate staging buffer prefer coherent
10794     ASSERT(dstBuffer != nullptr && !dstBuffer->valid());
10795     VkDeviceSize dstOffset;
10796     ANGLE_TRY(contextVk->initBufferForImageCopy(dstBuffer, bufferSize,
10797                                                 MemoryCoherency::CachedPreferCoherent,
10798                                                 imageFormat.id, &dstOffset, outDataPtr));
10799     ANGLE_TRY(dstBuffer->flush(contextVk->getRenderer()));
10800 
10801     VkBuffer bufferHandle = dstBuffer->getBuffer().getHandle();
10802 
10803     LevelIndex sourceLevelVk = toVkLevel(sourceLevelGL);
10804 
10805     VkBufferImageCopy regions = {};
10806     uint32_t regionCount      = 1;
10807     // Default to non-combined DS case
10808     regions.bufferOffset                    = dstOffset;
10809     regions.bufferRowLength                 = 0;
10810     regions.bufferImageHeight               = 0;
10811     regions.imageExtent.width               = sourceArea.width;
10812     regions.imageExtent.height              = sourceArea.height;
10813     regions.imageExtent.depth               = sourceArea.depth;
10814     regions.imageOffset.x                   = sourceArea.x;
10815     regions.imageOffset.y                   = sourceArea.y;
10816     regions.imageOffset.z                   = sourceArea.z;
10817     regions.imageSubresource.aspectMask     = aspectFlags;
10818     regions.imageSubresource.baseArrayLayer = baseLayer;
10819     regions.imageSubresource.layerCount     = layerCount;
10820     regions.imageSubresource.mipLevel       = sourceLevelVk.get();
10821 
10822     CommandBufferAccess access;
10823     access.onBufferTransferWrite(dstBuffer);
10824     access.onImageTransferRead(aspectFlags, this);
10825 
10826     OutsideRenderPassCommandBuffer *commandBuffer;
10827     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
10828 
10829     commandBuffer->copyImageToBuffer(mImage, getCurrentLayout(renderer), bufferHandle, regionCount,
10830                                      &regions);
10831 
10832     return angle::Result::Continue;
10833 }
10834 
copySurfaceImageToBuffer(DisplayVk * displayVk,gl::LevelIndex sourceLevelGL,uint32_t layerCount,uint32_t baseLayer,const gl::Box & sourceArea,vk::BufferHelper * bufferHelper)10835 angle::Result ImageHelper::copySurfaceImageToBuffer(DisplayVk *displayVk,
10836                                                     gl::LevelIndex sourceLevelGL,
10837                                                     uint32_t layerCount,
10838                                                     uint32_t baseLayer,
10839                                                     const gl::Box &sourceArea,
10840                                                     vk::BufferHelper *bufferHelper)
10841 {
10842     ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::copySurfaceImageToBuffer");
10843 
10844     Renderer *renderer = displayVk->getRenderer();
10845 
10846     VkBufferImageCopy region               = {};
10847     region.bufferOffset                    = 0;
10848     region.bufferRowLength                 = 0;
10849     region.bufferImageHeight               = 0;
10850     region.imageExtent.width               = sourceArea.width;
10851     region.imageExtent.height              = sourceArea.height;
10852     region.imageExtent.depth               = sourceArea.depth;
10853     region.imageOffset.x                   = sourceArea.x;
10854     region.imageOffset.y                   = sourceArea.y;
10855     region.imageOffset.z                   = sourceArea.z;
10856     region.imageSubresource.aspectMask     = getAspectFlags();
10857     region.imageSubresource.baseArrayLayer = baseLayer;
10858     region.imageSubresource.layerCount     = layerCount;
10859     region.imageSubresource.mipLevel       = toVkLevel(sourceLevelGL).get();
10860 
10861     // We may have a valid event here but we do not have a collector to collect it. Release the
10862     // event here to force pipelineBarrier.
10863     mCurrentEvent.release(displayVk->getRenderer());
10864 
10865     PrimaryCommandBuffer primaryCommandBuffer;
10866     ANGLE_TRY(renderer->getCommandBufferOneOff(displayVk, ProtectionType::Unprotected,
10867                                                &primaryCommandBuffer));
10868 
10869     VkSemaphore acquireNextImageSemaphore;
10870     barrierImpl(displayVk, getAspectFlags(), ImageLayout::TransferSrc,
10871                 displayVk->getDeviceQueueIndex(), nullptr, &primaryCommandBuffer,
10872                 &acquireNextImageSemaphore);
10873     primaryCommandBuffer.copyImageToBuffer(mImage, getCurrentLayout(renderer),
10874                                            bufferHelper->getBuffer().getHandle(), 1, &region);
10875 
10876     ANGLE_VK_TRY(displayVk, primaryCommandBuffer.end());
10877 
10878     QueueSerial submitQueueSerial;
10879     ANGLE_TRY(renderer->queueSubmitOneOff(
10880         displayVk, std::move(primaryCommandBuffer), ProtectionType::Unprotected,
10881         egl::ContextPriority::Medium, acquireNextImageSemaphore,
10882         kSwapchainAcquireImageWaitStageFlags, vk::SubmitPolicy::AllowDeferred, &submitQueueSerial));
10883 
10884     return renderer->finishQueueSerial(displayVk, submitQueueSerial);
10885 }
10886 
copyBufferToSurfaceImage(DisplayVk * displayVk,gl::LevelIndex sourceLevelGL,uint32_t layerCount,uint32_t baseLayer,const gl::Box & sourceArea,vk::BufferHelper * bufferHelper)10887 angle::Result ImageHelper::copyBufferToSurfaceImage(DisplayVk *displayVk,
10888                                                     gl::LevelIndex sourceLevelGL,
10889                                                     uint32_t layerCount,
10890                                                     uint32_t baseLayer,
10891                                                     const gl::Box &sourceArea,
10892                                                     vk::BufferHelper *bufferHelper)
10893 {
10894     ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::copyBufferToSurfaceImage");
10895 
10896     Renderer *renderer = displayVk->getRenderer();
10897 
10898     VkBufferImageCopy region               = {};
10899     region.bufferOffset                    = 0;
10900     region.bufferRowLength                 = 0;
10901     region.bufferImageHeight               = 0;
10902     region.imageExtent.width               = sourceArea.width;
10903     region.imageExtent.height              = sourceArea.height;
10904     region.imageExtent.depth               = sourceArea.depth;
10905     region.imageOffset.x                   = sourceArea.x;
10906     region.imageOffset.y                   = sourceArea.y;
10907     region.imageOffset.z                   = sourceArea.z;
10908     region.imageSubresource.aspectMask     = getAspectFlags();
10909     region.imageSubresource.baseArrayLayer = baseLayer;
10910     region.imageSubresource.layerCount     = layerCount;
10911     region.imageSubresource.mipLevel       = toVkLevel(sourceLevelGL).get();
10912 
10913     // We may have a valid event here but we do not have a collector to collect it. Release the
10914     // event here to force pipelineBarrier.
10915     mCurrentEvent.release(displayVk->getRenderer());
10916 
10917     PrimaryCommandBuffer commandBuffer;
10918     ANGLE_TRY(
10919         renderer->getCommandBufferOneOff(displayVk, ProtectionType::Unprotected, &commandBuffer));
10920 
10921     VkSemaphore acquireNextImageSemaphore;
10922     barrierImpl(displayVk, getAspectFlags(), ImageLayout::TransferDst,
10923                 displayVk->getDeviceQueueIndex(), nullptr, &commandBuffer,
10924                 &acquireNextImageSemaphore);
10925     commandBuffer.copyBufferToImage(bufferHelper->getBuffer().getHandle(), mImage,
10926                                     getCurrentLayout(renderer), 1, &region);
10927 
10928     ANGLE_VK_TRY(displayVk, commandBuffer.end());
10929 
10930     QueueSerial submitQueueSerial;
10931     ANGLE_TRY(renderer->queueSubmitOneOff(
10932         displayVk, std::move(commandBuffer), ProtectionType::Unprotected,
10933         egl::ContextPriority::Medium, acquireNextImageSemaphore,
10934         kSwapchainAcquireImageWaitStageFlags, vk::SubmitPolicy::AllowDeferred, &submitQueueSerial));
10935 
10936     return renderer->finishQueueSerial(displayVk, submitQueueSerial);
10937 }
10938 
10939 // 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)10940 angle::Result ImageHelper::GetReadPixelsParams(ContextVk *contextVk,
10941                                                const gl::PixelPackState &packState,
10942                                                gl::Buffer *packBuffer,
10943                                                GLenum format,
10944                                                GLenum type,
10945                                                const gl::Rectangle &area,
10946                                                const gl::Rectangle &clippedArea,
10947                                                PackPixelsParams *paramsOut,
10948                                                GLuint *skipBytesOut)
10949 {
10950     const gl::InternalFormat &sizedFormatInfo = gl::GetInternalFormatInfo(format, type);
10951 
10952     GLuint outputPitch = 0;
10953     ANGLE_VK_CHECK_MATH(contextVk,
10954                         sizedFormatInfo.computeRowPitch(type, area.width, packState.alignment,
10955                                                         packState.rowLength, &outputPitch));
10956     ANGLE_VK_CHECK_MATH(contextVk, sizedFormatInfo.computeSkipBytes(type, outputPitch, 0, packState,
10957                                                                     false, skipBytesOut));
10958 
10959     ANGLE_TRY(GetPackPixelsParams(sizedFormatInfo, outputPitch, packState, packBuffer, area,
10960                                   clippedArea, paramsOut, skipBytesOut));
10961     return angle::Result::Continue;
10962 }
10963 
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)10964 angle::Result ImageHelper::readPixelsForGetImage(ContextVk *contextVk,
10965                                                  const gl::PixelPackState &packState,
10966                                                  gl::Buffer *packBuffer,
10967                                                  gl::LevelIndex levelGL,
10968                                                  uint32_t layer,
10969                                                  uint32_t layerCount,
10970                                                  GLenum format,
10971                                                  GLenum type,
10972                                                  void *pixels)
10973 {
10974     const angle::Format &angleFormat = GetFormatFromFormatType(format, type);
10975 
10976     VkImageAspectFlagBits aspectFlags = {};
10977     if (angleFormat.redBits > 0 || angleFormat.blueBits > 0 || angleFormat.greenBits > 0 ||
10978         angleFormat.alphaBits > 0 || angleFormat.luminanceBits > 0)
10979     {
10980         aspectFlags = static_cast<VkImageAspectFlagBits>(aspectFlags | VK_IMAGE_ASPECT_COLOR_BIT);
10981     }
10982     else
10983     {
10984         if (angleFormat.depthBits > 0)
10985         {
10986             aspectFlags =
10987                 static_cast<VkImageAspectFlagBits>(aspectFlags | VK_IMAGE_ASPECT_DEPTH_BIT);
10988         }
10989         if (angleFormat.stencilBits > 0)
10990         {
10991             aspectFlags =
10992                 static_cast<VkImageAspectFlagBits>(aspectFlags | VK_IMAGE_ASPECT_STENCIL_BIT);
10993         }
10994     }
10995 
10996     ASSERT(aspectFlags != 0);
10997 
10998     PackPixelsParams params;
10999     GLuint outputSkipBytes = 0;
11000 
11001     const LevelIndex levelVk     = toVkLevel(levelGL);
11002     const gl::Extents mipExtents = getLevelExtents(levelVk);
11003     gl::Rectangle area(0, 0, mipExtents.width, mipExtents.height);
11004 
11005     ANGLE_TRY(GetReadPixelsParams(contextVk, packState, packBuffer, format, type, area, area,
11006                                   &params, &outputSkipBytes));
11007 
11008     if (mExtents.depth > 1 || layerCount > 1)
11009     {
11010         ASSERT(layer == 0);
11011         ASSERT(layerCount == 1 || mipExtents.depth == 1);
11012 
11013         uint32_t lastLayer = std::max(static_cast<uint32_t>(mipExtents.depth), layerCount);
11014 
11015         // Depth > 1 means this is a 3D texture and we need to copy all layers
11016         for (uint32_t mipLayer = 0; mipLayer < lastLayer; mipLayer++)
11017         {
11018             ANGLE_TRY(readPixels(contextVk, area, params, aspectFlags, levelGL, mipLayer,
11019                                  static_cast<uint8_t *>(pixels) + outputSkipBytes));
11020 
11021             outputSkipBytes += mipExtents.width * mipExtents.height *
11022                                gl::GetInternalFormatInfo(format, type).pixelBytes;
11023         }
11024     }
11025     else
11026     {
11027         ANGLE_TRY(readPixels(contextVk, area, params, aspectFlags, levelGL, layer,
11028                              static_cast<uint8_t *>(pixels) + outputSkipBytes));
11029     }
11030 
11031     return angle::Result::Continue;
11032 }
11033 
readPixelsForCompressedGetImage(ContextVk * contextVk,const gl::PixelPackState & packState,gl::Buffer * packBuffer,gl::LevelIndex levelGL,uint32_t layer,uint32_t layerCount,void * pixels)11034 angle::Result ImageHelper::readPixelsForCompressedGetImage(ContextVk *contextVk,
11035                                                            const gl::PixelPackState &packState,
11036                                                            gl::Buffer *packBuffer,
11037                                                            gl::LevelIndex levelGL,
11038                                                            uint32_t layer,
11039                                                            uint32_t layerCount,
11040                                                            void *pixels)
11041 {
11042     PackPixelsParams params;
11043     GLuint outputSkipBytes = 0;
11044 
11045     const LevelIndex levelVk = toVkLevel(levelGL);
11046     gl::Extents mipExtents   = getLevelExtents(levelVk);
11047     gl::Rectangle area(0, 0, mipExtents.width, mipExtents.height);
11048 
11049     VkImageAspectFlagBits aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT;
11050 
11051     const angle::Format *readFormat = &getActualFormat();
11052 
11053     // TODO(anglebug.com/42264702): Implement encoding for emuluated compression formats
11054     ANGLE_VK_CHECK(contextVk, readFormat->isBlock, VK_ERROR_FORMAT_NOT_SUPPORTED);
11055 
11056     if (mExtents.depth > 1 || layerCount > 1)
11057     {
11058         ASSERT(layer == 0);
11059         ASSERT(layerCount == 1 || mipExtents.depth == 1);
11060 
11061         uint32_t lastLayer = std::max(static_cast<uint32_t>(mipExtents.depth), layerCount);
11062 
11063         const vk::Format &vkFormat = contextVk->getRenderer()->getFormat(readFormat->id);
11064         const gl::InternalFormat &storageFormatInfo =
11065             vkFormat.getInternalFormatInfo(readFormat->componentType);
11066 
11067         // Calculate size for one layer
11068         mipExtents.depth = 1;
11069         GLuint layerSize;
11070         ANGLE_VK_CHECK_MATH(contextVk,
11071                             storageFormatInfo.computeCompressedImageSize(mipExtents, &layerSize));
11072 
11073         // Depth > 1 means this is a 3D texture and we need to copy all layers
11074         for (uint32_t mipLayer = 0; mipLayer < lastLayer; mipLayer++)
11075         {
11076             ANGLE_TRY(readPixels(contextVk, area, params, aspectFlags, levelGL, mipLayer,
11077                                  static_cast<uint8_t *>(pixels) + outputSkipBytes));
11078             outputSkipBytes += layerSize;
11079         }
11080     }
11081     else
11082     {
11083         ANGLE_TRY(readPixels(contextVk, area, params, aspectFlags, levelGL, layer,
11084                              static_cast<uint8_t *>(pixels) + outputSkipBytes));
11085     }
11086 
11087     return angle::Result::Continue;
11088 }
11089 
readPixelsWithCompute(ContextVk * contextVk,ImageHelper * src,const PackPixelsParams & packPixelsParams,const VkOffset3D & srcOffset,const VkExtent3D & srcExtent,ptrdiff_t pixelsOffset,const VkImageSubresourceLayers & srcSubresource)11090 angle::Result ImageHelper::readPixelsWithCompute(ContextVk *contextVk,
11091                                                  ImageHelper *src,
11092                                                  const PackPixelsParams &packPixelsParams,
11093                                                  const VkOffset3D &srcOffset,
11094                                                  const VkExtent3D &srcExtent,
11095                                                  ptrdiff_t pixelsOffset,
11096                                                  const VkImageSubresourceLayers &srcSubresource)
11097 {
11098     ASSERT(srcOffset.z == 0 || srcSubresource.baseArrayLayer == 0);
11099 
11100     UtilsVk::CopyImageToBufferParameters params = {};
11101     params.srcOffset[0]                         = srcOffset.x;
11102     params.srcOffset[1]                         = srcOffset.y;
11103     params.srcLayer        = std::max<uint32_t>(srcOffset.z, srcSubresource.baseArrayLayer);
11104     params.srcMip          = LevelIndex(srcSubresource.mipLevel);
11105     params.size[0]         = srcExtent.width;
11106     params.size[1]         = srcExtent.height;
11107     params.outputOffset    = packPixelsParams.offset + pixelsOffset;
11108     params.outputPitch     = packPixelsParams.outputPitch;
11109     params.reverseRowOrder = packPixelsParams.reverseRowOrder;
11110     params.outputFormat    = packPixelsParams.destFormat;
11111 
11112     BufferHelper &packBuffer = GetImpl(packPixelsParams.packBuffer)->getBuffer();
11113 
11114     return contextVk->getUtils().copyImageToBuffer(contextVk, &packBuffer, src, params);
11115 }
11116 
canCopyWithTransformForReadPixels(const PackPixelsParams & packPixelsParams,const VkExtent3D & srcExtent,const angle::Format * readFormat,ptrdiff_t pixelsOffset)11117 bool ImageHelper::canCopyWithTransformForReadPixels(const PackPixelsParams &packPixelsParams,
11118                                                     const VkExtent3D &srcExtent,
11119                                                     const angle::Format *readFormat,
11120                                                     ptrdiff_t pixelsOffset)
11121 {
11122     ASSERT(mActualFormatID != angle::FormatID::NONE && mIntendedFormatID != angle::FormatID::NONE);
11123 
11124     // Only allow copies to PBOs with identical format.
11125     const bool isSameFormatCopy = *readFormat == *packPixelsParams.destFormat;
11126 
11127     // Disallow any transformation.
11128     const bool needsTransformation =
11129         packPixelsParams.rotation != SurfaceRotation::Identity || packPixelsParams.reverseRowOrder;
11130 
11131     // Disallow copies when the output pitch cannot be correctly specified in Vulkan.
11132     const bool isPitchMultipleOfTexelSize =
11133         packPixelsParams.outputPitch % readFormat->pixelBytes == 0;
11134 
11135     // Disallow copies when PBO offset violates Vulkan bufferOffset alignment requirements.
11136     const BufferHelper &packBuffer = GetImpl(packPixelsParams.packBuffer)->getBuffer();
11137     const VkDeviceSize offset = packBuffer.getOffset() + packPixelsParams.offset + pixelsOffset;
11138     const bool isOffsetMultipleOfTexelSize = offset % readFormat->pixelBytes == 0;
11139 
11140     // Disallow copies when PBO row length is smaller than the source area width.
11141     const bool isRowLengthEnough =
11142         packPixelsParams.outputPitch >= srcExtent.width * readFormat->pixelBytes;
11143 
11144     // Don't allow copies from emulated formats for simplicity.
11145     return !hasEmulatedImageFormat() && isSameFormatCopy && !needsTransformation &&
11146            isPitchMultipleOfTexelSize && isOffsetMultipleOfTexelSize && isRowLengthEnough;
11147 }
11148 
canCopyWithComputeForReadPixels(const PackPixelsParams & packPixelsParams,const VkExtent3D & srcExtent,const angle::Format * readFormat,ptrdiff_t pixelsOffset)11149 bool ImageHelper::canCopyWithComputeForReadPixels(const PackPixelsParams &packPixelsParams,
11150                                                   const VkExtent3D &srcExtent,
11151                                                   const angle::Format *readFormat,
11152                                                   ptrdiff_t pixelsOffset)
11153 {
11154     ASSERT(mActualFormatID != angle::FormatID::NONE && mIntendedFormatID != angle::FormatID::NONE);
11155     const angle::Format *writeFormat = packPixelsParams.destFormat;
11156 
11157     // For now, only float formats are supported with 4-byte 4-channel normalized pixels for output.
11158     const bool isFloat =
11159         !readFormat->isSint() && !readFormat->isUint() && !readFormat->hasDepthOrStencilBits();
11160     const bool isFourByteOutput   = writeFormat->pixelBytes == 4 && writeFormat->channelCount == 4;
11161     const bool isNormalizedOutput = writeFormat->isUnorm() || writeFormat->isSnorm();
11162 
11163     // Disallow rotation.
11164     const bool needsTransformation = packPixelsParams.rotation != SurfaceRotation::Identity;
11165 
11166     // Disallow copies when the output pitch cannot be correctly specified in Vulkan.
11167     const bool isPitchMultipleOfTexelSize =
11168         packPixelsParams.outputPitch % readFormat->pixelBytes == 0;
11169 
11170     // Disallow copies when the output offset is not aligned to uint32_t
11171     const bool isOffsetMultipleOfUint =
11172         (packPixelsParams.offset + pixelsOffset) % readFormat->pixelBytes == 0;
11173 
11174     // Disallow copies when PBO row length is smaller than the source area width.
11175     const bool isRowLengthEnough =
11176         packPixelsParams.outputPitch >= srcExtent.width * readFormat->pixelBytes;
11177 
11178     return isFloat && isFourByteOutput && isNormalizedOutput && !needsTransformation &&
11179            isPitchMultipleOfTexelSize && isOffsetMultipleOfUint && isRowLengthEnough;
11180 }
11181 
readPixels(ContextVk * contextVk,const gl::Rectangle & area,const PackPixelsParams & packPixelsParams,VkImageAspectFlagBits copyAspectFlags,gl::LevelIndex levelGL,uint32_t layer,void * pixels)11182 angle::Result ImageHelper::readPixels(ContextVk *contextVk,
11183                                       const gl::Rectangle &area,
11184                                       const PackPixelsParams &packPixelsParams,
11185                                       VkImageAspectFlagBits copyAspectFlags,
11186                                       gl::LevelIndex levelGL,
11187                                       uint32_t layer,
11188                                       void *pixels)
11189 {
11190     ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::readPixels");
11191 
11192     const angle::Format &readFormat = getActualFormat();
11193 
11194     if (readFormat.depthBits == 0)
11195     {
11196         copyAspectFlags =
11197             static_cast<VkImageAspectFlagBits>(copyAspectFlags & ~VK_IMAGE_ASPECT_DEPTH_BIT);
11198     }
11199     if (readFormat.stencilBits == 0)
11200     {
11201         copyAspectFlags =
11202             static_cast<VkImageAspectFlagBits>(copyAspectFlags & ~VK_IMAGE_ASPECT_STENCIL_BIT);
11203     }
11204 
11205     if (copyAspectFlags == IMAGE_ASPECT_DEPTH_STENCIL)
11206     {
11207         const angle::Format &depthFormat =
11208             GetDepthStencilImageToBufferFormat(readFormat, VK_IMAGE_ASPECT_DEPTH_BIT);
11209         const angle::Format &stencilFormat =
11210             GetDepthStencilImageToBufferFormat(readFormat, VK_IMAGE_ASPECT_STENCIL_BIT);
11211 
11212         int depthOffset   = 0;
11213         int stencilOffset = 0;
11214         switch (readFormat.id)
11215         {
11216             case angle::FormatID::D24_UNORM_S8_UINT:
11217                 depthOffset   = 1;
11218                 stencilOffset = 0;
11219                 break;
11220 
11221             case angle::FormatID::D32_FLOAT_S8X24_UINT:
11222                 depthOffset   = 0;
11223                 stencilOffset = 4;
11224                 break;
11225 
11226             default:
11227                 UNREACHABLE();
11228         }
11229 
11230         ASSERT(depthOffset > 0 || stencilOffset > 0);
11231         ASSERT(depthOffset + depthFormat.depthBits / 8 <= readFormat.pixelBytes);
11232         ASSERT(stencilOffset + stencilFormat.stencilBits / 8 <= readFormat.pixelBytes);
11233 
11234         // Read the depth values, tightly-packed
11235         angle::MemoryBuffer depthBuffer;
11236         ANGLE_VK_CHECK_ALLOC(contextVk,
11237                              depthBuffer.resize(depthFormat.pixelBytes * area.width * area.height));
11238         ANGLE_TRY(
11239             readPixelsImpl(contextVk, area,
11240                            PackPixelsParams(area, depthFormat, depthFormat.pixelBytes * area.width,
11241                                             false, nullptr, 0),
11242                            VK_IMAGE_ASPECT_DEPTH_BIT, levelGL, layer, depthBuffer.data()));
11243 
11244         // Read the stencil values, tightly-packed
11245         angle::MemoryBuffer stencilBuffer;
11246         ANGLE_VK_CHECK_ALLOC(
11247             contextVk, stencilBuffer.resize(stencilFormat.pixelBytes * area.width * area.height));
11248         ANGLE_TRY(readPixelsImpl(
11249             contextVk, area,
11250             PackPixelsParams(area, stencilFormat, stencilFormat.pixelBytes * area.width, false,
11251                              nullptr, 0),
11252             VK_IMAGE_ASPECT_STENCIL_BIT, levelGL, layer, stencilBuffer.data()));
11253 
11254         // Interleave them together
11255         angle::MemoryBuffer readPixelBuffer;
11256         ANGLE_VK_CHECK_ALLOC(
11257             contextVk, readPixelBuffer.resize(readFormat.pixelBytes * area.width * area.height));
11258         readPixelBuffer.fill(0);
11259         for (int i = 0; i < area.width * area.height; i++)
11260         {
11261             uint8_t *readPixel = readPixelBuffer.data() + i * readFormat.pixelBytes;
11262             memcpy(readPixel + depthOffset, depthBuffer.data() + i * depthFormat.pixelBytes,
11263                    depthFormat.depthBits / 8);
11264             memcpy(readPixel + stencilOffset, stencilBuffer.data() + i * stencilFormat.pixelBytes,
11265                    stencilFormat.stencilBits / 8);
11266         }
11267 
11268         // Pack the interleaved depth and stencil into user-provided
11269         // destination, per user's pack pixels params
11270 
11271         // The compressed format path in packReadPixelBuffer isn't applicable
11272         // to our case, let's make extra sure we won't hit it
11273         ASSERT(!readFormat.isBlock);
11274         return packReadPixelBuffer(contextVk, area, packPixelsParams, readFormat, readFormat,
11275                                    readPixelBuffer.data(), levelGL, pixels);
11276     }
11277 
11278     return readPixelsImpl(contextVk, area, packPixelsParams, copyAspectFlags, levelGL, layer,
11279                           pixels);
11280 }
11281 
readPixelsImpl(ContextVk * contextVk,const gl::Rectangle & area,const PackPixelsParams & packPixelsParams,VkImageAspectFlagBits copyAspectFlags,gl::LevelIndex levelGL,uint32_t layer,void * pixels)11282 angle::Result ImageHelper::readPixelsImpl(ContextVk *contextVk,
11283                                           const gl::Rectangle &area,
11284                                           const PackPixelsParams &packPixelsParams,
11285                                           VkImageAspectFlagBits copyAspectFlags,
11286                                           gl::LevelIndex levelGL,
11287                                           uint32_t layer,
11288                                           void *pixels)
11289 {
11290     ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::readPixelsImpl");
11291 
11292     Renderer *renderer = contextVk->getRenderer();
11293 
11294     bool isExternalFormat = getExternalFormat() != 0;
11295     ASSERT(!isExternalFormat || (mActualFormatID >= angle::FormatID::EXTERNAL0 &&
11296                                  mActualFormatID <= angle::FormatID::EXTERNAL7));
11297 
11298     // If the source image is multisampled, we need to resolve it into a temporary image before
11299     // performing a readback.
11300     bool isMultisampled = mSamples > 1;
11301     RendererScoped<ImageHelper> resolvedImage(contextVk->getRenderer());
11302 
11303     ImageHelper *src = this;
11304 
11305     ASSERT(!hasStagedUpdatesForSubresource(levelGL, layer, 1));
11306 
11307     if (isMultisampled)
11308     {
11309         ANGLE_TRY(resolvedImage.get().init2DStaging(
11310             contextVk, contextVk->getState().hasProtectedContent(), renderer->getMemoryProperties(),
11311             gl::Extents(area.width, area.height, 1), mIntendedFormatID, mActualFormatID,
11312             VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
11313                 VK_IMAGE_USAGE_SAMPLED_BIT,
11314             1));
11315     }
11316     else if (isExternalFormat)
11317     {
11318         ANGLE_TRY(resolvedImage.get().init2DStaging(
11319             contextVk, contextVk->getState().hasProtectedContent(), renderer->getMemoryProperties(),
11320             gl::Extents(area.width, area.height, 1), angle::FormatID::R8G8B8A8_UNORM,
11321             angle::FormatID::R8G8B8A8_UNORM,
11322             VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
11323                 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
11324             1));
11325     }
11326 
11327     VkImageAspectFlags layoutChangeAspectFlags = src->getAspectFlags();
11328 
11329     const angle::Format *rgbaFormat = &angle::Format::Get(angle::FormatID::R8G8B8A8_UNORM);
11330     const angle::Format *readFormat = isExternalFormat ? rgbaFormat : &getActualFormat();
11331     const vk::Format &vkFormat      = contextVk->getRenderer()->getFormat(readFormat->id);
11332     const gl::InternalFormat &storageFormatInfo =
11333         vkFormat.getInternalFormatInfo(readFormat->componentType);
11334 
11335     if (copyAspectFlags != VK_IMAGE_ASPECT_COLOR_BIT)
11336     {
11337         readFormat = &GetDepthStencilImageToBufferFormat(*readFormat, copyAspectFlags);
11338     }
11339 
11340     VkOffset3D srcOffset = {area.x, area.y, 0};
11341 
11342     VkImageSubresourceLayers srcSubresource = {};
11343     srcSubresource.aspectMask               = copyAspectFlags;
11344     srcSubresource.mipLevel                 = toVkLevel(levelGL).get();
11345     srcSubresource.baseArrayLayer           = layer;
11346     srcSubresource.layerCount               = 1;
11347 
11348     VkExtent3D srcExtent = {static_cast<uint32_t>(area.width), static_cast<uint32_t>(area.height),
11349                             1};
11350 
11351     if (mExtents.depth > 1)
11352     {
11353         // Depth > 1 means this is a 3D texture and we need special handling
11354         srcOffset.z                   = layer;
11355         srcSubresource.baseArrayLayer = 0;
11356     }
11357 
11358     if (isExternalFormat)
11359     {
11360         CommandBufferAccess access;
11361         access.onImageTransferRead(layoutChangeAspectFlags, this);
11362         OutsideRenderPassCommandBuffer *commandBuffer;
11363         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
11364 
11365         // Create some temp views because copyImage works in terms of them
11366         gl::TextureType textureType = Get2DTextureType(1, resolvedImage.get().getSamples());
11367 
11368         // Surely we have a view of this already!
11369         vk::ImageView srcView;
11370         ANGLE_TRY(src->initLayerImageView(contextVk, textureType, VK_IMAGE_ASPECT_COLOR_BIT,
11371                                           gl::SwizzleState(), &srcView, vk::LevelIndex(0), 1, 0,
11372                                           mLayerCount));
11373         vk::ImageView stagingView;
11374         ANGLE_TRY(resolvedImage.get().initLayerImageView(
11375             contextVk, textureType, VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(), &stagingView,
11376             vk::LevelIndex(0), 1, 0, mLayerCount));
11377 
11378         UtilsVk::CopyImageParameters params = {};
11379         params.srcOffset[0]                 = srcOffset.x;
11380         params.srcOffset[1]                 = srcOffset.y;
11381         params.srcExtents[0]                = srcExtent.width;
11382         params.srcExtents[1]                = srcExtent.height;
11383         params.srcHeight                    = srcExtent.height;
11384         ANGLE_TRY(contextVk->getUtils().copyImage(contextVk, &resolvedImage.get(), &stagingView,
11385                                                   src, &srcView, params));
11386 
11387         CommandBufferAccess readAccess;
11388         readAccess.onImageTransferRead(layoutChangeAspectFlags, &resolvedImage.get());
11389         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(readAccess, &commandBuffer));
11390 
11391         // Make the resolved image the target of buffer copy
11392         src                           = &resolvedImage.get();
11393         srcOffset                     = {0, 0, 0};
11394         srcSubresource.baseArrayLayer = 0;
11395         srcSubresource.layerCount     = 1;
11396         srcSubresource.mipLevel       = 0;
11397 
11398         // Mark our temp views as garbage immediately
11399         contextVk->addGarbage(&srcView);
11400         contextVk->addGarbage(&stagingView);
11401     }
11402 
11403     if (isMultisampled)
11404     {
11405         CommandBufferAccess access;
11406         access.onImageTransferRead(layoutChangeAspectFlags, this);
11407         access.onImageTransferWrite(gl::LevelIndex(0), 1, 0, 1, layoutChangeAspectFlags,
11408                                     &resolvedImage.get());
11409 
11410         OutsideRenderPassCommandBuffer *commandBuffer;
11411         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
11412 
11413         // Note: resolve only works on color images (not depth/stencil).
11414         ASSERT(copyAspectFlags == VK_IMAGE_ASPECT_COLOR_BIT);
11415 
11416         VkImageResolve resolveRegion                = {};
11417         resolveRegion.srcSubresource                = srcSubresource;
11418         resolveRegion.srcOffset                     = srcOffset;
11419         resolveRegion.dstSubresource.aspectMask     = copyAspectFlags;
11420         resolveRegion.dstSubresource.mipLevel       = 0;
11421         resolveRegion.dstSubresource.baseArrayLayer = 0;
11422         resolveRegion.dstSubresource.layerCount     = 1;
11423         resolveRegion.dstOffset                     = {};
11424         resolveRegion.extent                        = srcExtent;
11425 
11426         resolve(&resolvedImage.get(), resolveRegion, commandBuffer);
11427 
11428         // Make the resolved image the target of buffer copy.
11429         src                           = &resolvedImage.get();
11430         srcOffset                     = {0, 0, 0};
11431         srcSubresource.baseArrayLayer = 0;
11432         srcSubresource.layerCount     = 1;
11433         srcSubresource.mipLevel       = 0;
11434     }
11435 
11436     // If PBO and if possible, copy directly on the GPU.
11437     if (packPixelsParams.packBuffer)
11438     {
11439         ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::readPixelsImpl - PBO");
11440 
11441         const ptrdiff_t pixelsOffset = reinterpret_cast<ptrdiff_t>(pixels);
11442         if (canCopyWithTransformForReadPixels(packPixelsParams, srcExtent, readFormat,
11443                                               pixelsOffset))
11444         {
11445             BufferHelper &packBuffer      = GetImpl(packPixelsParams.packBuffer)->getBuffer();
11446             VkDeviceSize packBufferOffset = packBuffer.getOffset();
11447 
11448             CommandBufferAccess copyAccess;
11449             copyAccess.onBufferTransferWrite(&packBuffer);
11450             copyAccess.onImageTransferRead(layoutChangeAspectFlags, src);
11451 
11452             OutsideRenderPassCommandBuffer *copyCommandBuffer;
11453             ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(copyAccess, &copyCommandBuffer));
11454 
11455             ASSERT(packPixelsParams.outputPitch % readFormat->pixelBytes == 0);
11456 
11457             VkBufferImageCopy region = {};
11458             region.bufferImageHeight = srcExtent.height;
11459             region.bufferOffset      = packBufferOffset + packPixelsParams.offset + pixelsOffset;
11460             region.bufferRowLength   = packPixelsParams.outputPitch / readFormat->pixelBytes;
11461             region.imageExtent       = srcExtent;
11462             region.imageOffset       = srcOffset;
11463             region.imageSubresource  = srcSubresource;
11464 
11465             copyCommandBuffer->copyImageToBuffer(src->getImage(), src->getCurrentLayout(renderer),
11466                                                  packBuffer.getBuffer().getHandle(), 1, &region);
11467             return angle::Result::Continue;
11468         }
11469         if (canCopyWithComputeForReadPixels(packPixelsParams, srcExtent, readFormat, pixelsOffset))
11470         {
11471             ANGLE_TRY(readPixelsWithCompute(contextVk, src, packPixelsParams, srcOffset, srcExtent,
11472                                             pixelsOffset, srcSubresource));
11473             return angle::Result::Continue;
11474         }
11475     }
11476 
11477     ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::readPixelsImpl - CPU Readback");
11478 
11479     RendererScoped<vk::BufferHelper> readBuffer(renderer);
11480     vk::BufferHelper *stagingBuffer = &readBuffer.get();
11481 
11482     uint8_t *readPixelBuffer   = nullptr;
11483     VkDeviceSize stagingOffset = 0;
11484     size_t allocationSize      = readFormat->pixelBytes * area.width * area.height;
11485 
11486     ANGLE_TRY(contextVk->initBufferForImageCopy(stagingBuffer, allocationSize,
11487                                                 MemoryCoherency::CachedPreferCoherent,
11488                                                 readFormat->id, &stagingOffset, &readPixelBuffer));
11489     ANGLE_TRY(stagingBuffer->flush(renderer));
11490     VkBuffer bufferHandle = stagingBuffer->getBuffer().getHandle();
11491 
11492     VkBufferImageCopy region = {};
11493     region.bufferImageHeight = srcExtent.height;
11494     region.bufferOffset      = stagingOffset;
11495     region.bufferRowLength   = srcExtent.width;
11496     region.imageExtent       = srcExtent;
11497     region.imageOffset       = srcOffset;
11498     region.imageSubresource  = srcSubresource;
11499 
11500     // For compressed textures, vkCmdCopyImageToBuffer requires
11501     // a region that is a multiple of the block size.
11502     if (readFormat->isBlock)
11503     {
11504         region.bufferRowLength =
11505             roundUp(region.bufferRowLength, storageFormatInfo.compressedBlockWidth);
11506         region.bufferImageHeight =
11507             roundUp(region.bufferImageHeight, storageFormatInfo.compressedBlockHeight);
11508     }
11509 
11510     CommandBufferAccess readbackAccess;
11511     readbackAccess.onBufferTransferWrite(stagingBuffer);
11512     readbackAccess.onImageTransferRead(layoutChangeAspectFlags, src);
11513 
11514     OutsideRenderPassCommandBuffer *readbackCommandBuffer;
11515     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(readbackAccess, &readbackCommandBuffer));
11516 
11517     readbackCommandBuffer->copyImageToBuffer(src->getImage(), src->getCurrentLayout(renderer),
11518                                              bufferHandle, 1, &region);
11519 
11520     ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_HIGH, "GPU stall due to ReadPixels");
11521 
11522     // Triggers a full finish.
11523     ANGLE_TRY(contextVk->finishImpl(RenderPassClosureReason::GLReadPixels));
11524     // invalidate must be called after wait for finish.
11525     ANGLE_TRY(stagingBuffer->invalidate(renderer));
11526 
11527     return packReadPixelBuffer(contextVk, area, packPixelsParams, getActualFormat(), *readFormat,
11528                                readPixelBuffer, levelGL, pixels);
11529 }
11530 
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)11531 angle::Result ImageHelper::packReadPixelBuffer(ContextVk *contextVk,
11532                                                const gl::Rectangle &area,
11533                                                const PackPixelsParams &packPixelsParams,
11534                                                const angle::Format &readFormat,
11535                                                const angle::Format &aspectFormat,
11536                                                const uint8_t *readPixelBuffer,
11537                                                gl::LevelIndex levelGL,
11538                                                void *pixels)
11539 {
11540     const vk::Format &vkFormat = contextVk->getRenderer()->getFormat(readFormat.id);
11541     const gl::InternalFormat &storageFormatInfo =
11542         vkFormat.getInternalFormatInfo(readFormat.componentType);
11543 
11544     if (readFormat.isBlock)
11545     {
11546         ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::packReadPixelBuffer - Block");
11547 
11548         ASSERT(readFormat == aspectFormat);
11549 
11550         const LevelIndex levelVk = toVkLevel(levelGL);
11551         gl::Extents levelExtents = getLevelExtents(levelVk);
11552 
11553         // Calculate size of one layer
11554         levelExtents.depth = 1;
11555         GLuint layerSize;
11556         ANGLE_VK_CHECK_MATH(contextVk,
11557                             storageFormatInfo.computeCompressedImageSize(levelExtents, &layerSize));
11558         memcpy(pixels, readPixelBuffer, layerSize);
11559     }
11560     else if (packPixelsParams.packBuffer)
11561     {
11562         ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::packReadPixelBuffer - PBO");
11563 
11564         // Must map the PBO in order to read its contents (and then unmap it later)
11565         BufferVk *packBufferVk = GetImpl(packPixelsParams.packBuffer);
11566         void *mapPtr           = nullptr;
11567         ANGLE_TRY(packBufferVk->mapImpl(contextVk, GL_MAP_WRITE_BIT, &mapPtr));
11568         uint8_t *dst = static_cast<uint8_t *>(mapPtr) + reinterpret_cast<ptrdiff_t>(pixels);
11569         PackPixels(packPixelsParams, aspectFormat, area.width * aspectFormat.pixelBytes,
11570                    readPixelBuffer, dst);
11571         ANGLE_TRY(packBufferVk->unmapImpl(contextVk));
11572     }
11573     else
11574     {
11575         PackPixels(packPixelsParams, aspectFormat, area.width * aspectFormat.pixelBytes,
11576                    readPixelBuffer, static_cast<uint8_t *>(pixels));
11577     }
11578 
11579     return angle::Result::Continue;
11580 }
11581 
11582 // ImageHelper::SubresourceUpdate implementation
SubresourceUpdate()11583 ImageHelper::SubresourceUpdate::SubresourceUpdate() : updateSource(UpdateSource::Buffer)
11584 {
11585     data.buffer.bufferHelper = nullptr;
11586     refCounted.buffer        = nullptr;
11587 }
11588 
SubresourceUpdate(const VkImageAspectFlags aspectFlags,const VkClearValue & clearValue,const gl::TextureType textureType,const uint32_t levelIndex,const uint32_t layerIndex,const uint32_t layerCount,const gl::Box & clearArea)11589 ImageHelper::SubresourceUpdate::SubresourceUpdate(const VkImageAspectFlags aspectFlags,
11590                                                   const VkClearValue &clearValue,
11591                                                   const gl::TextureType textureType,
11592                                                   const uint32_t levelIndex,
11593                                                   const uint32_t layerIndex,
11594                                                   const uint32_t layerCount,
11595                                                   const gl::Box &clearArea)
11596     : updateSource(UpdateSource::ClearPartial)
11597 {
11598     data.clearPartial.aspectFlags = aspectFlags;
11599     data.clearPartial.levelIndex  = levelIndex;
11600     data.clearPartial.textureType = textureType;
11601     data.clearPartial.layerIndex  = layerIndex;
11602     data.clearPartial.layerCount  = layerCount;
11603     data.clearPartial.offset      = {clearArea.x, clearArea.y, clearArea.z};
11604     data.clearPartial.extent      = {static_cast<uint32_t>(clearArea.width),
11605                                      static_cast<uint32_t>(clearArea.height),
11606                                      static_cast<uint32_t>(clearArea.depth)};
11607     data.clearPartial.clearValue  = clearValue;
11608 }
11609 
~SubresourceUpdate()11610 ImageHelper::SubresourceUpdate::~SubresourceUpdate() {}
11611 
SubresourceUpdate(RefCounted<BufferHelper> * bufferIn,BufferHelper * bufferHelperIn,const VkBufferImageCopy & copyRegionIn,angle::FormatID formatID)11612 ImageHelper::SubresourceUpdate::SubresourceUpdate(RefCounted<BufferHelper> *bufferIn,
11613                                                   BufferHelper *bufferHelperIn,
11614                                                   const VkBufferImageCopy &copyRegionIn,
11615                                                   angle::FormatID formatID)
11616     : updateSource(UpdateSource::Buffer)
11617 {
11618     refCounted.buffer = bufferIn;
11619     if (refCounted.buffer != nullptr)
11620     {
11621         refCounted.buffer->addRef();
11622     }
11623     data.buffer.bufferHelper = bufferHelperIn;
11624     data.buffer.copyRegion   = copyRegionIn;
11625     data.buffer.formatID     = formatID;
11626 }
11627 
SubresourceUpdate(RefCounted<ImageHelper> * imageIn,const VkImageCopy & copyRegionIn,angle::FormatID formatID)11628 ImageHelper::SubresourceUpdate::SubresourceUpdate(RefCounted<ImageHelper> *imageIn,
11629                                                   const VkImageCopy &copyRegionIn,
11630                                                   angle::FormatID formatID)
11631     : updateSource(UpdateSource::Image)
11632 {
11633     refCounted.image = imageIn;
11634     refCounted.image->addRef();
11635     data.image.copyRegion = copyRegionIn;
11636     data.image.formatID   = formatID;
11637 }
11638 
SubresourceUpdate(VkImageAspectFlags aspectFlags,const VkClearValue & clearValue,const gl::ImageIndex & imageIndex)11639 ImageHelper::SubresourceUpdate::SubresourceUpdate(VkImageAspectFlags aspectFlags,
11640                                                   const VkClearValue &clearValue,
11641                                                   const gl::ImageIndex &imageIndex)
11642     : SubresourceUpdate(
11643           aspectFlags,
11644           clearValue,
11645           gl::LevelIndex(imageIndex.getLevelIndex()),
11646           imageIndex.hasLayer() ? imageIndex.getLayerIndex() : 0,
11647           imageIndex.hasLayer() ? imageIndex.getLayerCount() : VK_REMAINING_ARRAY_LAYERS)
11648 {}
11649 
SubresourceUpdate(VkImageAspectFlags aspectFlags,const VkClearValue & clearValue,gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount)11650 ImageHelper::SubresourceUpdate::SubresourceUpdate(VkImageAspectFlags aspectFlags,
11651                                                   const VkClearValue &clearValue,
11652                                                   gl::LevelIndex level,
11653                                                   uint32_t layerIndex,
11654                                                   uint32_t layerCount)
11655     : updateSource(UpdateSource::Clear)
11656 {
11657     refCounted.image          = nullptr;
11658     data.clear.aspectFlags    = aspectFlags;
11659     data.clear.value          = clearValue;
11660     data.clear.levelIndex     = level.get();
11661     data.clear.layerIndex     = layerIndex;
11662     data.clear.layerCount     = layerCount;
11663     data.clear.colorMaskFlags = 0;
11664 }
11665 
SubresourceUpdate(VkColorComponentFlags colorMaskFlags,const VkClearColorValue & clearValue,const gl::ImageIndex & imageIndex)11666 ImageHelper::SubresourceUpdate::SubresourceUpdate(VkColorComponentFlags colorMaskFlags,
11667                                                   const VkClearColorValue &clearValue,
11668                                                   const gl::ImageIndex &imageIndex)
11669     : updateSource(UpdateSource::ClearEmulatedChannelsOnly)
11670 {
11671     refCounted.image       = nullptr;
11672     data.clear.aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT;
11673     data.clear.value.color = clearValue;
11674     data.clear.levelIndex  = imageIndex.getLevelIndex();
11675     data.clear.layerIndex  = imageIndex.hasLayer() ? imageIndex.getLayerIndex() : 0;
11676     data.clear.layerCount =
11677         imageIndex.hasLayer() ? imageIndex.getLayerCount() : VK_REMAINING_ARRAY_LAYERS;
11678     data.clear.colorMaskFlags = colorMaskFlags;
11679 }
11680 
SubresourceUpdate(SubresourceUpdate && other)11681 ImageHelper::SubresourceUpdate::SubresourceUpdate(SubresourceUpdate &&other)
11682     : updateSource(other.updateSource)
11683 {
11684     switch (updateSource)
11685     {
11686         case UpdateSource::Clear:
11687         case UpdateSource::ClearEmulatedChannelsOnly:
11688         case UpdateSource::ClearAfterInvalidate:
11689             data.clear        = other.data.clear;
11690             refCounted.buffer = nullptr;
11691             break;
11692         case UpdateSource::ClearPartial:
11693             data.clearPartial = other.data.clearPartial;
11694             break;
11695         case UpdateSource::Buffer:
11696             data.buffer             = other.data.buffer;
11697             refCounted.buffer       = other.refCounted.buffer;
11698             other.refCounted.buffer = nullptr;
11699             break;
11700         case UpdateSource::Image:
11701             data.image             = other.data.image;
11702             refCounted.image       = other.refCounted.image;
11703             other.refCounted.image = nullptr;
11704             break;
11705         default:
11706             UNREACHABLE();
11707     }
11708 }
11709 
operator =(SubresourceUpdate && other)11710 ImageHelper::SubresourceUpdate &ImageHelper::SubresourceUpdate::operator=(SubresourceUpdate &&other)
11711 {
11712     // Given that the update is a union of three structs, we can't use std::swap on the fields.  For
11713     // example, |this| may be an Image update and |other| may be a Buffer update.
11714     // The following could work:
11715     //
11716     // SubresourceUpdate oldThis;
11717     // Set oldThis to this->field based on updateSource
11718     // Set this->otherField to other.otherField based on other.updateSource
11719     // Set other.field to oldThis->field based on updateSource
11720     // std::Swap(updateSource, other.updateSource);
11721     //
11722     // It's much simpler to just swap the memory instead.
11723 
11724     SubresourceUpdate oldThis;
11725     memcpy(&oldThis, this, sizeof(*this));
11726     memcpy(this, &other, sizeof(*this));
11727     memcpy(&other, &oldThis, sizeof(*this));
11728 
11729     return *this;
11730 }
11731 
release(Renderer * renderer)11732 void ImageHelper::SubresourceUpdate::release(Renderer *renderer)
11733 {
11734     if (updateSource == UpdateSource::Image)
11735     {
11736         refCounted.image->releaseRef();
11737 
11738         if (!refCounted.image->isReferenced())
11739         {
11740             // Staging images won't be used in render pass attachments.
11741             refCounted.image->get().releaseImage(renderer);
11742             refCounted.image->get().releaseStagedUpdates(renderer);
11743             SafeDelete(refCounted.image);
11744         }
11745 
11746         refCounted.image = nullptr;
11747     }
11748     else if (updateSource == UpdateSource::Buffer && refCounted.buffer != nullptr)
11749     {
11750         refCounted.buffer->releaseRef();
11751 
11752         if (!refCounted.buffer->isReferenced())
11753         {
11754             refCounted.buffer->get().release(renderer);
11755             SafeDelete(refCounted.buffer);
11756         }
11757 
11758         refCounted.buffer = nullptr;
11759     }
11760 }
11761 
matchesLayerRange(uint32_t layerIndex,uint32_t layerCount) const11762 bool ImageHelper::SubresourceUpdate::matchesLayerRange(uint32_t layerIndex,
11763                                                        uint32_t layerCount) const
11764 {
11765     uint32_t updateBaseLayer, updateLayerCount;
11766     getDestSubresource(gl::ImageIndex::kEntireLevel, &updateBaseLayer, &updateLayerCount);
11767 
11768     return updateBaseLayer == layerIndex &&
11769            (updateLayerCount == layerCount || updateLayerCount == VK_REMAINING_ARRAY_LAYERS);
11770 }
11771 
intersectsLayerRange(uint32_t layerIndex,uint32_t layerCount) const11772 bool ImageHelper::SubresourceUpdate::intersectsLayerRange(uint32_t layerIndex,
11773                                                           uint32_t layerCount) const
11774 {
11775     uint32_t updateBaseLayer, updateLayerCount;
11776     getDestSubresource(gl::ImageIndex::kEntireLevel, &updateBaseLayer, &updateLayerCount);
11777     uint32_t updateLayerEnd = updateBaseLayer + updateLayerCount;
11778 
11779     return updateBaseLayer < (layerIndex + layerCount) && updateLayerEnd > layerIndex;
11780 }
11781 
getDestSubresource(uint32_t imageLayerCount,uint32_t * baseLayerOut,uint32_t * layerCountOut) const11782 void ImageHelper::SubresourceUpdate::getDestSubresource(uint32_t imageLayerCount,
11783                                                         uint32_t *baseLayerOut,
11784                                                         uint32_t *layerCountOut) const
11785 {
11786     if (IsClear(updateSource))
11787     {
11788         *baseLayerOut  = data.clear.layerIndex;
11789         *layerCountOut = data.clear.layerCount;
11790 
11791         if (*layerCountOut == static_cast<uint32_t>(gl::ImageIndex::kEntireLevel))
11792         {
11793             *layerCountOut = imageLayerCount;
11794         }
11795     }
11796     else if (updateSource == UpdateSource::ClearPartial)
11797     {
11798         *baseLayerOut  = data.clearPartial.layerIndex;
11799         *layerCountOut = data.clearPartial.layerCount;
11800 
11801         if (*layerCountOut == static_cast<uint32_t>(gl::ImageIndex::kEntireLevel))
11802         {
11803             *layerCountOut = imageLayerCount;
11804         }
11805     }
11806     else
11807     {
11808         const VkImageSubresourceLayers &dstSubresource =
11809             updateSource == UpdateSource::Buffer ? data.buffer.copyRegion.imageSubresource
11810                                                  : data.image.copyRegion.dstSubresource;
11811         *baseLayerOut  = dstSubresource.baseArrayLayer;
11812         *layerCountOut = dstSubresource.layerCount;
11813 
11814         ASSERT(*layerCountOut != static_cast<uint32_t>(gl::ImageIndex::kEntireLevel));
11815     }
11816 }
11817 
getDestAspectFlags() const11818 VkImageAspectFlags ImageHelper::SubresourceUpdate::getDestAspectFlags() const
11819 {
11820     if (IsClear(updateSource))
11821     {
11822         return data.clear.aspectFlags;
11823     }
11824     else if (updateSource == UpdateSource::ClearPartial)
11825     {
11826         return data.clearPartial.aspectFlags;
11827     }
11828     else if (updateSource == UpdateSource::Buffer)
11829     {
11830         return data.buffer.copyRegion.imageSubresource.aspectMask;
11831     }
11832     else
11833     {
11834         ASSERT(updateSource == UpdateSource::Image);
11835         return data.image.copyRegion.dstSubresource.aspectMask;
11836     }
11837 }
11838 
getLevelUpdateCount(gl::LevelIndex level) const11839 size_t ImageHelper::getLevelUpdateCount(gl::LevelIndex level) const
11840 {
11841     return static_cast<size_t>(level.get()) < mSubresourceUpdates.size()
11842                ? mSubresourceUpdates[level.get()].size()
11843                : 0;
11844 }
11845 
clipLevelToUpdateListUpperLimit(gl::LevelIndex * level) const11846 void ImageHelper::clipLevelToUpdateListUpperLimit(gl::LevelIndex *level) const
11847 {
11848     gl::LevelIndex levelLimit(static_cast<int>(mSubresourceUpdates.size()));
11849     *level = std::min(*level, levelLimit);
11850 }
11851 
getLevelUpdates(gl::LevelIndex level)11852 std::vector<ImageHelper::SubresourceUpdate> *ImageHelper::getLevelUpdates(gl::LevelIndex level)
11853 {
11854     return static_cast<size_t>(level.get()) < mSubresourceUpdates.size()
11855                ? &mSubresourceUpdates[level.get()]
11856                : nullptr;
11857 }
11858 
getLevelUpdates(gl::LevelIndex level) const11859 const std::vector<ImageHelper::SubresourceUpdate> *ImageHelper::getLevelUpdates(
11860     gl::LevelIndex level) const
11861 {
11862     return static_cast<size_t>(level.get()) < mSubresourceUpdates.size()
11863                ? &mSubresourceUpdates[level.get()]
11864                : nullptr;
11865 }
11866 
appendSubresourceUpdate(gl::LevelIndex level,SubresourceUpdate && update)11867 void ImageHelper::appendSubresourceUpdate(gl::LevelIndex level, SubresourceUpdate &&update)
11868 {
11869     if (mSubresourceUpdates.size() <= static_cast<size_t>(level.get()))
11870     {
11871         mSubresourceUpdates.resize(level.get() + 1);
11872     }
11873     // Update total staging buffer size
11874     mTotalStagedBufferUpdateSize += update.updateSource == UpdateSource::Buffer
11875                                         ? update.data.buffer.bufferHelper->getSize()
11876                                         : 0;
11877     mSubresourceUpdates[level.get()].emplace_back(std::move(update));
11878     onStateChange(angle::SubjectMessage::SubjectChanged);
11879 }
11880 
prependSubresourceUpdate(gl::LevelIndex level,SubresourceUpdate && update)11881 void ImageHelper::prependSubresourceUpdate(gl::LevelIndex level, SubresourceUpdate &&update)
11882 {
11883     if (mSubresourceUpdates.size() <= static_cast<size_t>(level.get()))
11884     {
11885         mSubresourceUpdates.resize(level.get() + 1);
11886     }
11887 
11888     // Update total staging buffer size
11889     mTotalStagedBufferUpdateSize += update.updateSource == UpdateSource::Buffer
11890                                         ? update.data.buffer.bufferHelper->getSize()
11891                                         : 0;
11892     mSubresourceUpdates[level.get()].insert(mSubresourceUpdates[level.get()].begin(),
11893                                             std::move(update));
11894     onStateChange(angle::SubjectMessage::SubjectChanged);
11895 }
11896 
hasEmulatedImageChannels() const11897 bool ImageHelper::hasEmulatedImageChannels() const
11898 {
11899     const angle::Format &angleFmt   = getIntendedFormat();
11900     const angle::Format &textureFmt = getActualFormat();
11901 
11902     // Block formats may be decoded and emulated with a non-block format.
11903     if (angleFmt.isBlock)
11904     {
11905         return !textureFmt.isBlock;
11906     }
11907 
11908     // The red channel is never emulated.
11909     ASSERT((angleFmt.redBits != 0 || angleFmt.luminanceBits != 0 || angleFmt.alphaBits != 0) ==
11910            (textureFmt.redBits != 0));
11911 
11912     return (angleFmt.alphaBits == 0 && textureFmt.alphaBits > 0) ||
11913            (angleFmt.blueBits == 0 && textureFmt.blueBits > 0) ||
11914            (angleFmt.greenBits == 0 && textureFmt.greenBits > 0) ||
11915            (angleFmt.depthBits == 0 && textureFmt.depthBits > 0) ||
11916            (angleFmt.stencilBits == 0 && textureFmt.stencilBits > 0);
11917 }
11918 
hasEmulatedDepthChannel() const11919 bool ImageHelper::hasEmulatedDepthChannel() const
11920 {
11921     return getIntendedFormat().depthBits == 0 && getActualFormat().depthBits > 0;
11922 }
11923 
hasEmulatedStencilChannel() const11924 bool ImageHelper::hasEmulatedStencilChannel() const
11925 {
11926     return getIntendedFormat().stencilBits == 0 && getActualFormat().stencilBits > 0;
11927 }
11928 
hasInefficientlyEmulatedImageFormat() const11929 bool ImageHelper::hasInefficientlyEmulatedImageFormat() const
11930 {
11931     if (hasEmulatedImageFormat())
11932     {
11933         // ETC2 compression is compatible with ETC1
11934         return !(mIntendedFormatID == angle::FormatID::ETC1_R8G8B8_UNORM_BLOCK &&
11935                  mActualFormatID == angle::FormatID::ETC2_R8G8B8_UNORM_BLOCK);
11936     }
11937     return false;
11938 }
11939 
getEmulatedChannelsMask() const11940 VkColorComponentFlags ImageHelper::getEmulatedChannelsMask() const
11941 {
11942     const angle::Format &angleFmt   = getIntendedFormat();
11943     const angle::Format &textureFmt = getActualFormat();
11944 
11945     ASSERT(!angleFmt.hasDepthOrStencilBits());
11946 
11947     VkColorComponentFlags emulatedChannelsMask = 0;
11948 
11949     if (angleFmt.alphaBits == 0 && textureFmt.alphaBits > 0)
11950     {
11951         emulatedChannelsMask |= VK_COLOR_COMPONENT_A_BIT;
11952     }
11953     if (angleFmt.blueBits == 0 && textureFmt.blueBits > 0)
11954     {
11955         emulatedChannelsMask |= VK_COLOR_COMPONENT_B_BIT;
11956     }
11957     if (angleFmt.greenBits == 0 && textureFmt.greenBits > 0)
11958     {
11959         emulatedChannelsMask |= VK_COLOR_COMPONENT_G_BIT;
11960     }
11961 
11962     // The red channel is never emulated.
11963     ASSERT((angleFmt.redBits != 0 || angleFmt.luminanceBits != 0 || angleFmt.alphaBits != 0) ==
11964            (textureFmt.redBits != 0));
11965 
11966     return emulatedChannelsMask;
11967 }
11968 
getCompressionFixedRate(VkImageCompressionControlEXT * compressionInfo,VkImageCompressionFixedRateFlagsEXT * compressionRates,GLenum glCompressionRate) const11969 bool ImageHelper::getCompressionFixedRate(VkImageCompressionControlEXT *compressionInfo,
11970                                           VkImageCompressionFixedRateFlagsEXT *compressionRates,
11971                                           GLenum glCompressionRate) const
11972 {
11973     bool rtn = true;
11974     ASSERT(compressionInfo->sType == VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT);
11975     compressionInfo->compressionControlPlaneCount = 1;
11976 
11977     if (glCompressionRate == GL_SURFACE_COMPRESSION_FIXED_RATE_NONE_EXT)
11978     {
11979         compressionInfo->flags = VK_IMAGE_COMPRESSION_DISABLED_EXT;
11980     }
11981     else if (glCompressionRate == GL_SURFACE_COMPRESSION_FIXED_RATE_DEFAULT_EXT)
11982     {
11983         compressionInfo->flags = VK_IMAGE_COMPRESSION_FIXED_RATE_DEFAULT_EXT;
11984     }
11985     else if (glCompressionRate >= GL_SURFACE_COMPRESSION_FIXED_RATE_1BPC_EXT &&
11986              glCompressionRate <= GL_SURFACE_COMPRESSION_FIXED_RATE_12BPC_EXT)
11987     {
11988         int offset             = glCompressionRate - GL_SURFACE_COMPRESSION_FIXED_RATE_1BPC_EXT;
11989         compressionInfo->flags = VK_IMAGE_COMPRESSION_FIXED_RATE_EXPLICIT_EXT;
11990         *compressionRates      = 1u << offset;
11991         compressionInfo->pFixedRateFlags = compressionRates;
11992     }
11993     else
11994     {
11995         // Invalid value
11996         rtn = false;
11997     }
11998 
11999     return rtn;
12000 }
12001 
GetLayerMode(const vk::ImageHelper & image,uint32_t layerCount)12002 LayerMode GetLayerMode(const vk::ImageHelper &image, uint32_t layerCount)
12003 {
12004     const uint32_t imageLayerCount = GetImageLayerCountForView(image);
12005     const bool allLayers           = layerCount == imageLayerCount;
12006 
12007     ASSERT(allLayers || (layerCount > 0 && layerCount <= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS));
12008     return allLayers ? LayerMode::All : static_cast<LayerMode>(layerCount);
12009 }
12010 
GetComputePipelineOptions(vk::PipelineRobustness robustness,vk::PipelineProtectedAccess protectedAccess)12011 ComputePipelineOptions GetComputePipelineOptions(vk::PipelineRobustness robustness,
12012                                                  vk::PipelineProtectedAccess protectedAccess)
12013 {
12014     vk::ComputePipelineOptions pipelineOptions = {};
12015 
12016     if (robustness == vk::PipelineRobustness::Robust)
12017     {
12018         pipelineOptions.robustness = 1;
12019     }
12020     if (protectedAccess == vk::PipelineProtectedAccess::Protected)
12021     {
12022         pipelineOptions.protectedAccess = 1;
12023     }
12024 
12025     return pipelineOptions;
12026 }
12027 
12028 // ImageViewHelper implementation.
ImageViewHelper()12029 ImageViewHelper::ImageViewHelper()
12030     : mCurrentBaseMaxLevelHash(0),
12031       mReadColorspace(ImageViewColorspace::Invalid),
12032       mWriteColorspace(ImageViewColorspace::Invalid)
12033 {}
12034 
ImageViewHelper(ImageViewHelper && other)12035 ImageViewHelper::ImageViewHelper(ImageViewHelper &&other)
12036 {
12037     std::swap(mCurrentBaseMaxLevelHash, other.mCurrentBaseMaxLevelHash);
12038     std::swap(mReadColorspace, other.mReadColorspace);
12039     std::swap(mWriteColorspace, other.mWriteColorspace);
12040     std::swap(mColorspaceState, other.mColorspaceState);
12041 
12042     std::swap(mPerLevelRangeLinearReadImageViews, other.mPerLevelRangeLinearReadImageViews);
12043     std::swap(mPerLevelRangeSRGBReadImageViews, other.mPerLevelRangeSRGBReadImageViews);
12044     std::swap(mPerLevelRangeLinearCopyImageViews, other.mPerLevelRangeLinearCopyImageViews);
12045     std::swap(mPerLevelRangeSRGBCopyImageViews, other.mPerLevelRangeSRGBCopyImageViews);
12046     std::swap(mPerLevelRangeStencilReadImageViews, other.mPerLevelRangeStencilReadImageViews);
12047     std::swap(mPerLevelRangeSamplerExternal2DY2YEXTImageViews,
12048               other.mPerLevelRangeSamplerExternal2DY2YEXTImageViews);
12049 
12050     std::swap(mLayerLevelDrawImageViews, other.mLayerLevelDrawImageViews);
12051     std::swap(mLayerLevelDrawImageViewsLinear, other.mLayerLevelDrawImageViewsLinear);
12052     std::swap(mSubresourceDrawImageViews, other.mSubresourceDrawImageViews);
12053 
12054     std::swap(mLayerLevelDepthOnlyImageViews, other.mLayerLevelDepthOnlyImageViews);
12055     std::swap(mLayerLevelStencilOnlyImageViews, other.mLayerLevelStencilOnlyImageViews);
12056     std::swap(mSubresourceDepthOnlyImageViews, other.mSubresourceDepthOnlyImageViews);
12057     std::swap(mSubresourceStencilOnlyImageViews, other.mSubresourceStencilOnlyImageViews);
12058 
12059     std::swap(mLevelStorageImageViews, other.mLevelStorageImageViews);
12060     std::swap(mLayerLevelStorageImageViews, other.mLayerLevelStorageImageViews);
12061     std::swap(mFragmentShadingRateImageView, other.mFragmentShadingRateImageView);
12062     std::swap(mImageViewSerial, other.mImageViewSerial);
12063 }
12064 
~ImageViewHelper()12065 ImageViewHelper::~ImageViewHelper() {}
12066 
init(Renderer * renderer)12067 void ImageViewHelper::init(Renderer *renderer)
12068 {
12069     if (!mImageViewSerial.valid())
12070     {
12071         mImageViewSerial = renderer->getResourceSerialFactory().generateImageOrBufferViewSerial();
12072     }
12073 }
12074 
release(Renderer * renderer,const ResourceUse & use)12075 void ImageViewHelper::release(Renderer *renderer, const ResourceUse &use)
12076 {
12077     mCurrentBaseMaxLevelHash = 0;
12078     mReadColorspace          = ImageViewColorspace::Invalid;
12079     mWriteColorspace         = ImageViewColorspace::Invalid;
12080     mColorspaceState.reset();
12081 
12082     std::vector<vk::GarbageObject> garbage;
12083     // Release the read views
12084     ReleaseImageViews(&mPerLevelRangeLinearReadImageViews, &garbage);
12085     ReleaseImageViews(&mPerLevelRangeSRGBReadImageViews, &garbage);
12086     ReleaseImageViews(&mPerLevelRangeLinearCopyImageViews, &garbage);
12087     ReleaseImageViews(&mPerLevelRangeSRGBCopyImageViews, &garbage);
12088     ReleaseImageViews(&mPerLevelRangeStencilReadImageViews, &garbage);
12089     ReleaseImageViews(&mPerLevelRangeSamplerExternal2DY2YEXTImageViews, &garbage);
12090 
12091     // Release the draw views
12092     ReleaseLayerLevelImageViews(&mLayerLevelDrawImageViews, &garbage);
12093     ReleaseLayerLevelImageViews(&mLayerLevelDrawImageViewsLinear, &garbage);
12094     ReleaseSubresourceImageViews(&mSubresourceDrawImageViews, &garbage);
12095 
12096     // Release the depth-xor-stencil input views
12097     ReleaseLayerLevelImageViews(&mLayerLevelDepthOnlyImageViews, &garbage);
12098     ReleaseLayerLevelImageViews(&mLayerLevelStencilOnlyImageViews, &garbage);
12099     ReleaseSubresourceImageViews(&mSubresourceDepthOnlyImageViews, &garbage);
12100     ReleaseSubresourceImageViews(&mSubresourceStencilOnlyImageViews, &garbage);
12101 
12102     // Release the storage views
12103     ReleaseImageViews(&mLevelStorageImageViews, &garbage);
12104     ReleaseLayerLevelImageViews(&mLayerLevelStorageImageViews, &garbage);
12105 
12106     // Release fragment shading rate view
12107     if (mFragmentShadingRateImageView.valid())
12108     {
12109         garbage.emplace_back(GetGarbage(&mFragmentShadingRateImageView));
12110     }
12111 
12112     if (!garbage.empty())
12113     {
12114         renderer->collectGarbage(use, std::move(garbage));
12115     }
12116 
12117     // Update image view serial.
12118     mImageViewSerial = renderer->getResourceSerialFactory().generateImageOrBufferViewSerial();
12119 }
12120 
isImageViewGarbageEmpty() const12121 bool ImageViewHelper::isImageViewGarbageEmpty() const
12122 {
12123     return mPerLevelRangeLinearReadImageViews.empty() &&
12124            mPerLevelRangeLinearCopyImageViews.empty() && mPerLevelRangeSRGBReadImageViews.empty() &&
12125            mPerLevelRangeSRGBCopyImageViews.empty() &&
12126            mPerLevelRangeStencilReadImageViews.empty() &&
12127            mPerLevelRangeSamplerExternal2DY2YEXTImageViews.empty() &&
12128            mLayerLevelDrawImageViews.empty() && mLayerLevelDrawImageViewsLinear.empty() &&
12129            mSubresourceDrawImageViews.empty() && mLayerLevelDepthOnlyImageViews.empty() &&
12130            mLayerLevelStencilOnlyImageViews.empty() && mSubresourceDepthOnlyImageViews.empty() &&
12131            mSubresourceStencilOnlyImageViews.empty() && mLayerLevelStorageImageViews.empty();
12132 }
12133 
destroy(VkDevice device)12134 void ImageViewHelper::destroy(VkDevice device)
12135 {
12136     mCurrentBaseMaxLevelHash = 0;
12137     mReadColorspace          = ImageViewColorspace::Invalid;
12138     mWriteColorspace         = ImageViewColorspace::Invalid;
12139     mColorspaceState.reset();
12140 
12141     // Release the read views
12142     DestroyImageViews(&mPerLevelRangeLinearReadImageViews, device);
12143     DestroyImageViews(&mPerLevelRangeSRGBReadImageViews, device);
12144     DestroyImageViews(&mPerLevelRangeLinearCopyImageViews, device);
12145     DestroyImageViews(&mPerLevelRangeSRGBCopyImageViews, device);
12146     DestroyImageViews(&mPerLevelRangeStencilReadImageViews, device);
12147     DestroyImageViews(&mPerLevelRangeSamplerExternal2DY2YEXTImageViews, device);
12148 
12149     // Release the draw views
12150     DestroyLayerLevelImageViews(&mLayerLevelDrawImageViews, device);
12151     DestroyLayerLevelImageViews(&mLayerLevelDrawImageViewsLinear, device);
12152     DestroySubresourceImageViews(&mSubresourceDrawImageViews, device);
12153 
12154     // Release the depth-xor-stencil input views
12155     DestroyLayerLevelImageViews(&mLayerLevelDepthOnlyImageViews, device);
12156     DestroyLayerLevelImageViews(&mLayerLevelStencilOnlyImageViews, device);
12157     DestroySubresourceImageViews(&mSubresourceDepthOnlyImageViews, device);
12158     DestroySubresourceImageViews(&mSubresourceStencilOnlyImageViews, device);
12159 
12160     // Release the storage views
12161     DestroyImageViews(&mLevelStorageImageViews, device);
12162     DestroyLayerLevelImageViews(&mLayerLevelStorageImageViews, device);
12163 
12164     // Destroy fragment shading rate view
12165     mFragmentShadingRateImageView.destroy(device);
12166 
12167     mImageViewSerial = kInvalidImageOrBufferViewSerial;
12168 }
12169 
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)12170 angle::Result ImageViewHelper::initReadViews(ContextVk *contextVk,
12171                                              gl::TextureType viewType,
12172                                              const ImageHelper &image,
12173                                              const gl::SwizzleState &formatSwizzle,
12174                                              const gl::SwizzleState &readSwizzle,
12175                                              LevelIndex baseLevel,
12176                                              uint32_t levelCount,
12177                                              uint32_t baseLayer,
12178                                              uint32_t layerCount,
12179                                              bool requiresSRGBViews,
12180                                              VkImageUsageFlags imageUsageFlags)
12181 {
12182     ASSERT(levelCount > 0);
12183 
12184     const uint32_t maxLevel = levelCount - 1;
12185     ASSERT(maxLevel < 16);
12186     ASSERT(baseLevel.get() < 16);
12187     mCurrentBaseMaxLevelHash = static_cast<uint8_t>(baseLevel.get() << 4 | maxLevel);
12188     updateColorspace(image);
12189 
12190     if (mCurrentBaseMaxLevelHash >= mPerLevelRangeLinearReadImageViews.size())
12191     {
12192         const uint32_t maxViewCount = mCurrentBaseMaxLevelHash + 1;
12193 
12194         mPerLevelRangeLinearReadImageViews.resize(maxViewCount);
12195         mPerLevelRangeSRGBReadImageViews.resize(maxViewCount);
12196         mPerLevelRangeLinearCopyImageViews.resize(maxViewCount);
12197         mPerLevelRangeSRGBCopyImageViews.resize(maxViewCount);
12198         mPerLevelRangeStencilReadImageViews.resize(maxViewCount);
12199         mPerLevelRangeSamplerExternal2DY2YEXTImageViews.resize(maxViewCount);
12200     }
12201 
12202     // Determine if we already have ImageViews for the new max level
12203     if (getReadImageView().valid())
12204     {
12205         return angle::Result::Continue;
12206     }
12207 
12208     // Since we don't have a readImageView, we must create ImageViews for the new max level
12209     if (requiresSRGBViews)
12210     {
12211         // Initialize image views for both linear and srgb colorspaces
12212         ANGLE_TRY(initLinearAndSrgbReadViewsImpl(contextVk, viewType, image, formatSwizzle,
12213                                                  readSwizzle, baseLevel, levelCount, baseLayer,
12214                                                  layerCount, imageUsageFlags));
12215     }
12216     else
12217     {
12218         // Initialize image view for image's format's colorspace
12219         ANGLE_TRY(initReadViewsImpl(contextVk, viewType, image, formatSwizzle, readSwizzle,
12220                                     baseLevel, levelCount, baseLayer, layerCount, imageUsageFlags));
12221     }
12222 
12223     return angle::Result::Continue;
12224 }
12225 
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)12226 angle::Result ImageViewHelper::initReadViewsImpl(ContextVk *contextVk,
12227                                                  gl::TextureType viewType,
12228                                                  const ImageHelper &image,
12229                                                  const gl::SwizzleState &formatSwizzle,
12230                                                  const gl::SwizzleState &readSwizzle,
12231                                                  LevelIndex baseLevel,
12232                                                  uint32_t levelCount,
12233                                                  uint32_t baseLayer,
12234                                                  uint32_t layerCount,
12235                                                  VkImageUsageFlags imageUsageFlags)
12236 {
12237     ASSERT(mImageViewSerial.valid());
12238     ASSERT(mReadColorspace != ImageViewColorspace::Invalid);
12239 
12240     const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(image.getIntendedFormat());
12241 
12242     if (HasBothDepthAndStencilAspects(aspectFlags))
12243     {
12244         ANGLE_TRY(image.initLayerImageViewWithUsage(
12245             contextVk, viewType, VK_IMAGE_ASPECT_DEPTH_BIT, readSwizzle, &getReadImageView(),
12246             baseLevel, levelCount, baseLayer, layerCount, imageUsageFlags));
12247         ANGLE_TRY(image.initLayerImageViewWithUsage(
12248             contextVk, viewType, VK_IMAGE_ASPECT_STENCIL_BIT, readSwizzle,
12249             &mPerLevelRangeStencilReadImageViews[mCurrentBaseMaxLevelHash], baseLevel, levelCount,
12250             baseLayer, layerCount, imageUsageFlags));
12251     }
12252     else
12253     {
12254         ANGLE_TRY(image.initLayerImageViewWithUsage(contextVk, viewType, aspectFlags, readSwizzle,
12255                                                     &getReadImageView(), baseLevel, levelCount,
12256                                                     baseLayer, layerCount, imageUsageFlags));
12257 
12258         if (image.getActualFormat().isYUV)
12259         {
12260             ANGLE_TRY(image.initLayerImageViewWithYuvModeOverride(
12261                 contextVk, viewType, aspectFlags, readSwizzle,
12262                 &getSamplerExternal2DY2YEXTImageView(), baseLevel, levelCount, baseLayer,
12263                 layerCount, gl::YuvSamplingMode::Y2Y, imageUsageFlags));
12264         }
12265     }
12266 
12267     gl::TextureType fetchType = viewType;
12268     if (viewType == gl::TextureType::CubeMap || viewType == gl::TextureType::_2DArray ||
12269         viewType == gl::TextureType::_2DMultisampleArray)
12270     {
12271         fetchType = Get2DTextureType(layerCount, image.getSamples());
12272     }
12273 
12274     if (!image.getActualFormat().isBlock)
12275     {
12276         ANGLE_TRY(image.initLayerImageViewWithUsage(
12277             contextVk, fetchType, aspectFlags, formatSwizzle, &getCopyImageView(), baseLevel,
12278             levelCount, baseLayer, layerCount, imageUsageFlags));
12279     }
12280     return angle::Result::Continue;
12281 }
12282 
initLinearAndSrgbReadViewsImpl(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)12283 angle::Result ImageViewHelper::initLinearAndSrgbReadViewsImpl(ContextVk *contextVk,
12284                                                               gl::TextureType viewType,
12285                                                               const ImageHelper &image,
12286                                                               const gl::SwizzleState &formatSwizzle,
12287                                                               const gl::SwizzleState &readSwizzle,
12288                                                               LevelIndex baseLevel,
12289                                                               uint32_t levelCount,
12290                                                               uint32_t baseLayer,
12291                                                               uint32_t layerCount,
12292                                                               VkImageUsageFlags imageUsageFlags)
12293 {
12294     ASSERT(mReadColorspace != ImageViewColorspace::Invalid);
12295 
12296     // When we select the linear/srgb counterpart formats, we must first make sure they're
12297     // actually supported by the ICD. If they are not supported by the ICD, then we treat that as if
12298     // there is no counterpart format.
12299     const bool imageFormatIsSrgb      = image.getActualFormat().isSRGB;
12300     const angle::FormatID imageFormat = image.getActualFormatID();
12301     angle::FormatID srgbFormat = imageFormatIsSrgb ? imageFormat : ConvertToSRGB(imageFormat);
12302     if (srgbFormat != angle::FormatID::NONE &&
12303         !HasNonRenderableTextureFormatSupport(contextVk->getRenderer(), srgbFormat))
12304     {
12305         srgbFormat = angle::FormatID::NONE;
12306     }
12307 
12308     angle::FormatID linearFormat = !imageFormatIsSrgb ? imageFormat : ConvertToLinear(imageFormat);
12309     ASSERT(linearFormat != angle::FormatID::NONE);
12310 
12311     const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(image.getIntendedFormat());
12312 
12313     if (HasBothDepthAndStencilAspects(aspectFlags))
12314     {
12315         ANGLE_TRY(image.initReinterpretedLayerImageView(
12316             contextVk, viewType, VK_IMAGE_ASPECT_DEPTH_BIT, readSwizzle,
12317             &mPerLevelRangeLinearReadImageViews[mCurrentBaseMaxLevelHash], baseLevel, levelCount,
12318             baseLayer, layerCount, imageUsageFlags, linearFormat));
12319 
12320         ANGLE_TRY(image.initReinterpretedLayerImageView(
12321             contextVk, viewType, VK_IMAGE_ASPECT_STENCIL_BIT, readSwizzle,
12322             &mPerLevelRangeStencilReadImageViews[mCurrentBaseMaxLevelHash], baseLevel, levelCount,
12323             baseLayer, layerCount, imageUsageFlags, linearFormat));
12324     }
12325     else
12326     {
12327         if (!mPerLevelRangeLinearReadImageViews[mCurrentBaseMaxLevelHash].valid())
12328         {
12329             ANGLE_TRY(image.initReinterpretedLayerImageView(
12330                 contextVk, viewType, aspectFlags, readSwizzle,
12331                 &mPerLevelRangeLinearReadImageViews[mCurrentBaseMaxLevelHash], baseLevel,
12332                 levelCount, baseLayer, layerCount, imageUsageFlags, linearFormat));
12333         }
12334 
12335         if (srgbFormat != angle::FormatID::NONE &&
12336             !mPerLevelRangeSRGBReadImageViews[mCurrentBaseMaxLevelHash].valid())
12337         {
12338             ANGLE_TRY(image.initReinterpretedLayerImageView(
12339                 contextVk, viewType, aspectFlags, readSwizzle,
12340                 &mPerLevelRangeSRGBReadImageViews[mCurrentBaseMaxLevelHash], baseLevel, levelCount,
12341                 baseLayer, layerCount, imageUsageFlags, srgbFormat));
12342         }
12343 
12344         if (image.getActualFormat().isYUV)
12345         {
12346             ANGLE_TRY(image.initLayerImageViewWithYuvModeOverride(
12347                 contextVk, viewType, aspectFlags, readSwizzle,
12348                 &getSamplerExternal2DY2YEXTImageView(), baseLevel, levelCount, baseLayer,
12349                 layerCount, gl::YuvSamplingMode::Y2Y, imageUsageFlags));
12350         }
12351     }
12352 
12353     gl::TextureType fetchType = viewType;
12354 
12355     if (viewType == gl::TextureType::CubeMap || viewType == gl::TextureType::_2DArray ||
12356         viewType == gl::TextureType::_2DMultisampleArray)
12357     {
12358         fetchType = Get2DTextureType(layerCount, image.getSamples());
12359     }
12360 
12361     if (!image.getActualFormat().isBlock)
12362     {
12363         if (!mPerLevelRangeLinearCopyImageViews[mCurrentBaseMaxLevelHash].valid())
12364         {
12365             ANGLE_TRY(image.initReinterpretedLayerImageView(
12366                 contextVk, fetchType, aspectFlags, formatSwizzle,
12367                 &mPerLevelRangeLinearCopyImageViews[mCurrentBaseMaxLevelHash], baseLevel,
12368                 levelCount, baseLayer, layerCount, imageUsageFlags, linearFormat));
12369         }
12370         if (srgbFormat != angle::FormatID::NONE &&
12371             !mPerLevelRangeSRGBCopyImageViews[mCurrentBaseMaxLevelHash].valid())
12372         {
12373             ANGLE_TRY(image.initReinterpretedLayerImageView(
12374                 contextVk, fetchType, aspectFlags, formatSwizzle,
12375                 &mPerLevelRangeSRGBCopyImageViews[mCurrentBaseMaxLevelHash], baseLevel, levelCount,
12376                 baseLayer, layerCount, imageUsageFlags, srgbFormat));
12377         }
12378     }
12379 
12380     return angle::Result::Continue;
12381 }
12382 
getLevelStorageImageView(Context * context,gl::TextureType viewType,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,VkImageUsageFlags imageUsageFlags,angle::FormatID formatID,const ImageView ** imageViewOut)12383 angle::Result ImageViewHelper::getLevelStorageImageView(Context *context,
12384                                                         gl::TextureType viewType,
12385                                                         const ImageHelper &image,
12386                                                         LevelIndex levelVk,
12387                                                         uint32_t layer,
12388                                                         VkImageUsageFlags imageUsageFlags,
12389                                                         angle::FormatID formatID,
12390                                                         const ImageView **imageViewOut)
12391 {
12392     ASSERT(mImageViewSerial.valid());
12393 
12394     ImageView *imageView =
12395         GetLevelImageView(&mLevelStorageImageViews, levelVk, image.getLevelCount());
12396 
12397     *imageViewOut = imageView;
12398     if (imageView->valid())
12399     {
12400         return angle::Result::Continue;
12401     }
12402 
12403     // Create the view.  Note that storage images are not affected by swizzle parameters.
12404     return image.initReinterpretedLayerImageView(context, viewType, image.getAspectFlags(),
12405                                                  gl::SwizzleState(), imageView, levelVk, 1, layer,
12406                                                  image.getLayerCount(), imageUsageFlags, formatID);
12407 }
12408 
getLevelLayerStorageImageView(Context * contextVk,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,VkImageUsageFlags imageUsageFlags,angle::FormatID formatID,const ImageView ** imageViewOut)12409 angle::Result ImageViewHelper::getLevelLayerStorageImageView(Context *contextVk,
12410                                                              const ImageHelper &image,
12411                                                              LevelIndex levelVk,
12412                                                              uint32_t layer,
12413                                                              VkImageUsageFlags imageUsageFlags,
12414                                                              angle::FormatID formatID,
12415                                                              const ImageView **imageViewOut)
12416 {
12417     ASSERT(image.valid());
12418     ASSERT(mImageViewSerial.valid());
12419     ASSERT(!image.getActualFormat().isBlock);
12420 
12421     ImageView *imageView =
12422         GetLevelLayerImageView(&mLayerLevelStorageImageViews, levelVk, layer, image.getLevelCount(),
12423                                GetImageLayerCountForView(image));
12424     *imageViewOut = imageView;
12425 
12426     if (imageView->valid())
12427     {
12428         return angle::Result::Continue;
12429     }
12430 
12431     // Create the view.  Note that storage images are not affected by swizzle parameters.
12432     gl::TextureType viewType = Get2DTextureType(1, image.getSamples());
12433     return image.initReinterpretedLayerImageView(contextVk, viewType, image.getAspectFlags(),
12434                                                  gl::SwizzleState(), imageView, levelVk, 1, layer,
12435                                                  1, imageUsageFlags, formatID);
12436 }
12437 
getLevelLayerDrawImageViewImpl(Context * context,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,uint32_t layerCount,ImageView * imageViewOut)12438 angle::Result ImageViewHelper::getLevelLayerDrawImageViewImpl(Context *context,
12439                                                               const ImageHelper &image,
12440                                                               LevelIndex levelVk,
12441                                                               uint32_t layer,
12442                                                               uint32_t layerCount,
12443                                                               ImageView *imageViewOut)
12444 {
12445     ASSERT(imageViewOut != nullptr);
12446 
12447     // If we are initializing an imageview for use with EXT_srgb_write_control, we need to override
12448     // the format to its linear counterpart. Formats that cannot be reinterpreted are exempt from
12449     // this requirement.
12450     angle::FormatID actualFormat = image.getActualFormatID();
12451     angle::FormatID linearFormat = ConvertToLinear(actualFormat);
12452     angle::FormatID sRGBFormat   = ConvertToSRGB(actualFormat);
12453     if (mWriteColorspace == ImageViewColorspace::Linear && linearFormat != angle::FormatID::NONE)
12454     {
12455         actualFormat = linearFormat;
12456     }
12457     else if (mWriteColorspace == ImageViewColorspace::SRGB && sRGBFormat != angle::FormatID::NONE)
12458     {
12459         actualFormat = sRGBFormat;
12460     }
12461 
12462     // Note that these views are specifically made to be used as framebuffer attachments, and
12463     // therefore don't have swizzle.
12464     return image.initReinterpretedLayerImageView(
12465         context, Get2DTextureType(layerCount, image.getSamples()), image.getAspectFlags(),
12466         gl::SwizzleState(), imageViewOut, levelVk, 1, layer, layerCount,
12467         vk::ImageHelper::kDefaultImageViewUsageFlags, actualFormat);
12468 }
12469 
getLevelDrawImageView(Context * context,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,uint32_t layerCount,const ImageView ** imageViewOut)12470 angle::Result ImageViewHelper::getLevelDrawImageView(Context *context,
12471                                                      const ImageHelper &image,
12472                                                      LevelIndex levelVk,
12473                                                      uint32_t layer,
12474                                                      uint32_t layerCount,
12475                                                      const ImageView **imageViewOut)
12476 {
12477     ASSERT(image.valid());
12478     ASSERT(mImageViewSerial.valid());
12479     ASSERT(!image.getActualFormat().isBlock);
12480 
12481     if (mWriteColorspace == ImageViewColorspace::Invalid)
12482     {
12483         updateColorspace(image);
12484     }
12485     ASSERT(mWriteColorspace != ImageViewColorspace::Invalid);
12486 
12487     ImageSubresourceRange range = MakeImageSubresourceDrawRange(image.toGLLevel(levelVk), layer,
12488                                                                 GetLayerMode(image, layerCount),
12489                                                                 mReadColorspace, mWriteColorspace);
12490 
12491     std::unique_ptr<ImageView> &view = mSubresourceDrawImageViews[range];
12492     if (view)
12493     {
12494         *imageViewOut = view.get();
12495         return angle::Result::Continue;
12496     }
12497 
12498     view          = std::make_unique<ImageView>();
12499     *imageViewOut = view.get();
12500 
12501     return getLevelLayerDrawImageViewImpl(context, image, levelVk, layer, layerCount, view.get());
12502 }
12503 
getLevelLayerDrawImageView(Context * context,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,const ImageView ** imageViewOut)12504 angle::Result ImageViewHelper::getLevelLayerDrawImageView(Context *context,
12505                                                           const ImageHelper &image,
12506                                                           LevelIndex levelVk,
12507                                                           uint32_t layer,
12508                                                           const ImageView **imageViewOut)
12509 {
12510     ASSERT(image.valid());
12511     ASSERT(mImageViewSerial.valid());
12512     ASSERT(!image.getActualFormat().isBlock);
12513 
12514     if (mWriteColorspace == ImageViewColorspace::Invalid)
12515     {
12516         updateColorspace(image);
12517     }
12518     ASSERT(mWriteColorspace != ImageViewColorspace::Invalid);
12519 
12520     LayerLevelImageViewVector &imageViews = (mWriteColorspace == ImageViewColorspace::Linear)
12521                                                 ? mLayerLevelDrawImageViewsLinear
12522                                                 : mLayerLevelDrawImageViews;
12523 
12524     // Lazily allocate the storage for image views
12525     ImageView *imageView = GetLevelLayerImageView(
12526         &imageViews, levelVk, layer, image.getLevelCount(), GetImageLayerCountForView(image));
12527     *imageViewOut = imageView;
12528 
12529     if (imageView->valid())
12530     {
12531         return angle::Result::Continue;
12532     }
12533 
12534     return getLevelLayerDrawImageViewImpl(context, image, levelVk, layer, 1, imageView);
12535 }
12536 
getLevelDepthOrStencilImageView(Context * context,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,uint32_t layerCount,VkImageAspectFlagBits aspect,const ImageView ** imageViewOut)12537 angle::Result ImageViewHelper::getLevelDepthOrStencilImageView(Context *context,
12538                                                                const ImageHelper &image,
12539                                                                LevelIndex levelVk,
12540                                                                uint32_t layer,
12541                                                                uint32_t layerCount,
12542                                                                VkImageAspectFlagBits aspect,
12543                                                                const ImageView **imageViewOut)
12544 {
12545     ASSERT(image.valid());
12546     ASSERT(mImageViewSerial.valid());
12547     ASSERT((image.getAspectFlags() & aspect) != 0);
12548 
12549     ImageSubresourceRange range = MakeImageSubresourceDrawRange(
12550         image.toGLLevel(levelVk), layer, GetLayerMode(image, layerCount),
12551         ImageViewColorspace::Linear, ImageViewColorspace::Linear);
12552 
12553     SubresourceImageViewMap &imageViews = aspect == VK_IMAGE_ASPECT_DEPTH_BIT
12554                                               ? mSubresourceDepthOnlyImageViews
12555                                               : mSubresourceStencilOnlyImageViews;
12556 
12557     std::unique_ptr<ImageView> &view = imageViews[range];
12558     if (view)
12559     {
12560         *imageViewOut = view.get();
12561         return angle::Result::Continue;
12562     }
12563 
12564     view          = std::make_unique<ImageView>();
12565     *imageViewOut = view.get();
12566 
12567     return getLevelLayerDepthOrStencilImageViewImpl(context, image, levelVk, layer, layerCount,
12568                                                     aspect, view.get());
12569 }
12570 
getLevelLayerDepthOrStencilImageView(Context * context,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,VkImageAspectFlagBits aspect,const ImageView ** imageViewOut)12571 angle::Result ImageViewHelper::getLevelLayerDepthOrStencilImageView(Context *context,
12572                                                                     const ImageHelper &image,
12573                                                                     LevelIndex levelVk,
12574                                                                     uint32_t layer,
12575                                                                     VkImageAspectFlagBits aspect,
12576                                                                     const ImageView **imageViewOut)
12577 {
12578     ASSERT(image.valid());
12579     ASSERT(mImageViewSerial.valid());
12580     ASSERT((image.getAspectFlags() & aspect) != 0);
12581 
12582     LayerLevelImageViewVector &imageViews = aspect == VK_IMAGE_ASPECT_DEPTH_BIT
12583                                                 ? mLayerLevelDepthOnlyImageViews
12584                                                 : mLayerLevelStencilOnlyImageViews;
12585 
12586     // Lazily allocate the storage for image views
12587     ImageView *imageView = GetLevelLayerImageView(
12588         &imageViews, levelVk, layer, image.getLevelCount(), GetImageLayerCountForView(image));
12589     *imageViewOut = imageView;
12590 
12591     if (imageView->valid())
12592     {
12593         return angle::Result::Continue;
12594     }
12595 
12596     return getLevelLayerDepthOrStencilImageViewImpl(context, image, levelVk, layer, 1, aspect,
12597                                                     imageView);
12598 }
12599 
getLevelLayerDepthOrStencilImageViewImpl(Context * context,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,uint32_t layerCount,VkImageAspectFlagBits aspect,ImageView * imageViewOut)12600 angle::Result ImageViewHelper::getLevelLayerDepthOrStencilImageViewImpl(
12601     Context *context,
12602     const ImageHelper &image,
12603     LevelIndex levelVk,
12604     uint32_t layer,
12605     uint32_t layerCount,
12606     VkImageAspectFlagBits aspect,
12607     ImageView *imageViewOut)
12608 {
12609     // Note that these views are specifically made to be used as input attachments, and
12610     // therefore don't have swizzle.
12611     return image.initReinterpretedLayerImageView(
12612         context, Get2DTextureType(layerCount, image.getSamples()), aspect, gl::SwizzleState(),
12613         imageViewOut, levelVk, 1, layer, layerCount, vk::ImageHelper::kDefaultImageViewUsageFlags,
12614         image.getActualFormatID());
12615 }
12616 
initFragmentShadingRateView(ContextVk * contextVk,ImageHelper * image)12617 angle::Result ImageViewHelper::initFragmentShadingRateView(ContextVk *contextVk, ImageHelper *image)
12618 {
12619     ASSERT(image->valid());
12620     ASSERT(mImageViewSerial.valid());
12621 
12622     // Determine if we already have ImageView
12623     if (mFragmentShadingRateImageView.valid())
12624     {
12625         return angle::Result::Continue;
12626     }
12627 
12628     // Fragment shading rate image view always have -
12629     // - gl::TextureType    == gl::TextureType::_2D
12630     // - VkImageAspectFlags == VK_IMAGE_ASPECT_COLOR_BIT
12631     // - gl::SwizzleState   == gl::SwizzleState()
12632     // - baseMipLevelVk     == vk::LevelIndex(0)
12633     // - levelCount         == 1
12634     // - baseArrayLayer     == 0
12635     // - layerCount         == 1
12636     return image->initLayerImageViewWithUsage(
12637         contextVk, gl::TextureType::_2D, VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(),
12638         &mFragmentShadingRateImageView, vk::LevelIndex(0), 1, 0, 1, image->getUsage());
12639 }
12640 
getColorspaceOverrideFormatForWrite(angle::FormatID format) const12641 angle::FormatID ImageViewHelper::getColorspaceOverrideFormatForWrite(angle::FormatID format) const
12642 {
12643     ASSERT(mWriteColorspace != ImageViewColorspace::Invalid);
12644 
12645     angle::FormatID colorspaceOverrideFormat = format;
12646     angle::FormatID linearFormat             = ConvertToLinear(format);
12647     angle::FormatID sRGBFormat               = ConvertToSRGB(format);
12648     if (mWriteColorspace == ImageViewColorspace::Linear && linearFormat != angle::FormatID::NONE)
12649     {
12650         colorspaceOverrideFormat = linearFormat;
12651     }
12652     else if (mWriteColorspace == ImageViewColorspace::SRGB && sRGBFormat != angle::FormatID::NONE)
12653     {
12654         colorspaceOverrideFormat = sRGBFormat;
12655     }
12656 
12657     return colorspaceOverrideFormat;
12658 }
12659 
updateColorspace(const ImageHelper & image) const12660 void ImageViewHelper::updateColorspace(const ImageHelper &image) const
12661 {
12662     const angle::Format &imageFormat        = image.getActualFormat();
12663     ImageViewColorspace imageViewColorspace = ImageViewColorspace::Invalid;
12664     mReadColorspace                         = ImageViewColorspace::Invalid;
12665     mWriteColorspace                        = ImageViewColorspace::Invalid;
12666 
12667     // Initialize colorspace based on image's format's colorspace
12668     imageViewColorspace =
12669         imageFormat.isSRGB ? ImageViewColorspace::SRGB : ImageViewColorspace::Linear;
12670 
12671     // Process EGL image colorspace override state
12672     if (!imageFormat.isSRGB && mColorspaceState.eglImageColorspace == egl::ImageColorspace::SRGB)
12673     {
12674         imageViewColorspace = ImageViewColorspace::SRGB;
12675     }
12676     else if (imageFormat.isSRGB &&
12677              mColorspaceState.eglImageColorspace == egl::ImageColorspace::Linear)
12678     {
12679         imageViewColorspace = ImageViewColorspace::Linear;
12680     }
12681     ASSERT(imageViewColorspace != ImageViewColorspace::Invalid);
12682 
12683     mReadColorspace  = imageViewColorspace;
12684     mWriteColorspace = imageViewColorspace;
12685 
12686     // Process srgb decode and srgb override state
12687     if (mReadColorspace == ImageViewColorspace::Linear)
12688     {
12689         if (mColorspaceState.srgbOverride == gl::SrgbOverride::SRGB &&
12690             rx::ConvertToSRGB(imageFormat.id) != angle::FormatID::NONE &&
12691             mColorspaceState.srgbDecode != gl::SrgbDecode::Skip)
12692         {
12693             mReadColorspace = ImageViewColorspace::SRGB;
12694         }
12695     }
12696     else
12697     {
12698         ASSERT(mReadColorspace == ImageViewColorspace::SRGB);
12699 
12700         if (mColorspaceState.srgbDecode == gl::SrgbDecode::Skip &&
12701             !mColorspaceState.hasStaticTexelFetchAccess)
12702         {
12703             mReadColorspace = ImageViewColorspace::Linear;
12704         }
12705     }
12706 
12707     // Process srgb write control state
12708     if (mWriteColorspace == ImageViewColorspace::SRGB &&
12709         mColorspaceState.srgbWriteControl == gl::SrgbWriteControlMode::Linear)
12710     {
12711         mWriteColorspace = ImageViewColorspace::Linear;
12712     }
12713 
12714     ASSERT(mReadColorspace != ImageViewColorspace::Invalid);
12715     ASSERT(mWriteColorspace != ImageViewColorspace::Invalid);
12716 }
12717 
getSubresourceSerial(gl::LevelIndex levelGL,uint32_t levelCount,uint32_t layer,LayerMode layerMode) const12718 ImageOrBufferViewSubresourceSerial ImageViewHelper::getSubresourceSerial(gl::LevelIndex levelGL,
12719                                                                          uint32_t levelCount,
12720                                                                          uint32_t layer,
12721                                                                          LayerMode layerMode) const
12722 {
12723     return getSubresourceSerialForColorspace(levelGL, levelCount, layer, layerMode,
12724                                              mReadColorspace);
12725 }
12726 
getSubresourceSerialForColorspace(gl::LevelIndex levelGL,uint32_t levelCount,uint32_t layer,LayerMode layerMode,ImageViewColorspace readColorspace) const12727 ImageOrBufferViewSubresourceSerial ImageViewHelper::getSubresourceSerialForColorspace(
12728     gl::LevelIndex levelGL,
12729     uint32_t levelCount,
12730     uint32_t layer,
12731     LayerMode layerMode,
12732     ImageViewColorspace readColorspace) const
12733 {
12734     ASSERT(mImageViewSerial.valid());
12735 
12736     ImageOrBufferViewSubresourceSerial serial;
12737     serial.viewSerial  = mImageViewSerial;
12738     serial.subresource = MakeImageSubresourceReadRange(levelGL, levelCount, layer, layerMode,
12739                                                        readColorspace, mWriteColorspace);
12740     return serial;
12741 }
12742 
getSubresourceDrawRange(gl::LevelIndex level,uint32_t layer,LayerMode layerMode) const12743 ImageSubresourceRange ImageViewHelper::getSubresourceDrawRange(gl::LevelIndex level,
12744                                                                uint32_t layer,
12745                                                                LayerMode layerMode) const
12746 {
12747     return MakeImageSubresourceDrawRange(level, layer, layerMode, mReadColorspace,
12748                                          mWriteColorspace);
12749 }
12750 
12751 // BufferViewHelper implementation.
BufferViewHelper()12752 BufferViewHelper::BufferViewHelper() : mInitialized(false), mOffset(0), mSize(0) {}
12753 
BufferViewHelper(BufferViewHelper && other)12754 BufferViewHelper::BufferViewHelper(BufferViewHelper &&other) : Resource(std::move(other))
12755 {
12756     std::swap(mInitialized, other.mInitialized);
12757     std::swap(mOffset, other.mOffset);
12758     std::swap(mSize, other.mSize);
12759     std::swap(mViews, other.mViews);
12760     std::swap(mViewSerial, other.mViewSerial);
12761 }
12762 
~BufferViewHelper()12763 BufferViewHelper::~BufferViewHelper() {}
12764 
init(Renderer * renderer,VkDeviceSize offset,VkDeviceSize size)12765 void BufferViewHelper::init(Renderer *renderer, VkDeviceSize offset, VkDeviceSize size)
12766 {
12767     ASSERT(mViews.empty());
12768 
12769     mOffset = offset;
12770     mSize   = size;
12771 
12772     if (!mViewSerial.valid())
12773     {
12774         mViewSerial = renderer->getResourceSerialFactory().generateImageOrBufferViewSerial();
12775     }
12776 
12777     mInitialized = true;
12778 }
12779 
release(Renderer * renderer)12780 void BufferViewHelper::release(Renderer *renderer)
12781 {
12782     if (!mInitialized)
12783     {
12784         return;
12785     }
12786 
12787     GarbageObjects garbage;
12788 
12789     for (auto &formatAndView : mViews)
12790     {
12791         BufferView &view = formatAndView.second;
12792         ASSERT(view.valid());
12793 
12794         garbage.emplace_back(GetGarbage(&view));
12795     }
12796 
12797     if (!garbage.empty())
12798     {
12799         renderer->collectGarbage(mUse, std::move(garbage));
12800         // Update image view serial.
12801         mViewSerial = renderer->getResourceSerialFactory().generateImageOrBufferViewSerial();
12802     }
12803 
12804     mUse.reset();
12805     mViews.clear();
12806     mOffset      = 0;
12807     mSize        = 0;
12808     mInitialized = false;
12809 }
12810 
release(ContextVk * contextVk)12811 void BufferViewHelper::release(ContextVk *contextVk)
12812 {
12813     if (!mInitialized)
12814     {
12815         return;
12816     }
12817 
12818     contextVk->flushDescriptorSetUpdates();
12819     return release(contextVk->getRenderer());
12820 }
12821 
destroy(VkDevice device)12822 void BufferViewHelper::destroy(VkDevice device)
12823 {
12824     for (auto &formatAndView : mViews)
12825     {
12826         BufferView &view = formatAndView.second;
12827         view.destroy(device);
12828     }
12829 
12830     mViews.clear();
12831 
12832     mOffset = 0;
12833     mSize   = 0;
12834 
12835     mViewSerial = kInvalidImageOrBufferViewSerial;
12836 }
12837 
getView(Context * context,const BufferHelper & buffer,VkDeviceSize bufferOffset,const Format & format,const BufferView ** viewOut)12838 angle::Result BufferViewHelper::getView(Context *context,
12839                                         const BufferHelper &buffer,
12840                                         VkDeviceSize bufferOffset,
12841                                         const Format &format,
12842                                         const BufferView **viewOut)
12843 {
12844     ASSERT(format.valid());
12845 
12846     vk::Renderer *renderer = context->getRenderer();
12847     VkFormat viewVkFormat  = format.getActualBufferVkFormat(renderer, false);
12848 
12849     auto iter = mViews.find(viewVkFormat);
12850     if (iter != mViews.end())
12851     {
12852         *viewOut = &iter->second;
12853         return angle::Result::Continue;
12854     }
12855 
12856     // If the size is not a multiple of pixelBytes, remove the extra bytes.  The last element cannot
12857     // be read anyway, and this is a requirement of Vulkan (for size to be a multiple of format
12858     // texel block size).
12859     const angle::Format &bufferFormat = format.getActualBufferFormat(false);
12860     const GLuint pixelBytes           = bufferFormat.pixelBytes;
12861     VkDeviceSize size                 = mSize - mSize % pixelBytes;
12862 
12863     VkBufferViewCreateInfo viewCreateInfo = {};
12864     viewCreateInfo.sType                  = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
12865     viewCreateInfo.buffer                 = buffer.getBuffer().getHandle();
12866     viewCreateInfo.format                 = viewVkFormat;
12867     viewCreateInfo.offset                 = mOffset + bufferOffset;
12868     viewCreateInfo.range                  = size;
12869 
12870     BufferView view;
12871     ANGLE_VK_TRY(context, view.init(context->getDevice(), viewCreateInfo));
12872 
12873     // Cache the view
12874     auto insertIter = mViews.insert({viewVkFormat, std::move(view)});
12875     *viewOut        = &insertIter.first->second;
12876     ASSERT(insertIter.second);
12877 
12878     return angle::Result::Continue;
12879 }
12880 
getSerial() const12881 ImageOrBufferViewSubresourceSerial BufferViewHelper::getSerial() const
12882 {
12883     ASSERT(mViewSerial.valid());
12884 
12885     ImageOrBufferViewSubresourceSerial serial = {};
12886     serial.viewSerial                         = mViewSerial;
12887     return serial;
12888 }
12889 
12890 // ShaderProgramHelper implementation.
12891 ShaderProgramHelper::ShaderProgramHelper()  = default;
12892 ShaderProgramHelper::~ShaderProgramHelper() = default;
12893 
valid(const gl::ShaderType shaderType) const12894 bool ShaderProgramHelper::valid(const gl::ShaderType shaderType) const
12895 {
12896     return mShaders[shaderType];
12897 }
12898 
destroy(Renderer * renderer)12899 void ShaderProgramHelper::destroy(Renderer *renderer)
12900 {
12901     for (ShaderModulePtr &shader : mShaders)
12902     {
12903         shader.reset();
12904     }
12905 }
12906 
release(ContextVk * contextVk)12907 void ShaderProgramHelper::release(ContextVk *contextVk)
12908 {
12909     for (ShaderModulePtr &shader : mShaders)
12910     {
12911         shader.reset();
12912     }
12913 }
12914 
setShader(gl::ShaderType shaderType,const ShaderModulePtr & shader)12915 void ShaderProgramHelper::setShader(gl::ShaderType shaderType, const ShaderModulePtr &shader)
12916 {
12917     // The shaders must be set once and are not expected to change.
12918     ASSERT(!mShaders[shaderType]);
12919     ASSERT(shader && shader->valid());
12920     mShaders[shaderType] = shader;
12921 }
12922 
createMonolithicPipelineCreationTask(vk::Context * context,PipelineCacheAccess * pipelineCache,const GraphicsPipelineDesc & desc,const PipelineLayout & pipelineLayout,const SpecializationConstants & specConsts,PipelineHelper * pipeline) const12923 void ShaderProgramHelper::createMonolithicPipelineCreationTask(
12924     vk::Context *context,
12925     PipelineCacheAccess *pipelineCache,
12926     const GraphicsPipelineDesc &desc,
12927     const PipelineLayout &pipelineLayout,
12928     const SpecializationConstants &specConsts,
12929     PipelineHelper *pipeline) const
12930 {
12931     std::shared_ptr<CreateMonolithicPipelineTask> monolithicPipelineCreationTask =
12932         std::make_shared<CreateMonolithicPipelineTask>(context->getRenderer(), *pipelineCache,
12933                                                        pipelineLayout, mShaders, specConsts, desc);
12934 
12935     pipeline->setMonolithicPipelineCreationTask(std::move(monolithicPipelineCreationTask));
12936 }
12937 
getOrCreateComputePipeline(vk::Context * context,ComputePipelineCache * computePipelines,PipelineCacheAccess * pipelineCache,const PipelineLayout & pipelineLayout,ComputePipelineOptions pipelineOptions,PipelineSource source,PipelineHelper ** pipelineOut,const char * shaderName,VkSpecializationInfo * specializationInfo) const12938 angle::Result ShaderProgramHelper::getOrCreateComputePipeline(
12939     vk::Context *context,
12940     ComputePipelineCache *computePipelines,
12941     PipelineCacheAccess *pipelineCache,
12942     const PipelineLayout &pipelineLayout,
12943     ComputePipelineOptions pipelineOptions,
12944     PipelineSource source,
12945     PipelineHelper **pipelineOut,
12946     const char *shaderName,
12947     VkSpecializationInfo *specializationInfo) const
12948 {
12949     PipelineHelper *computePipeline = &(*computePipelines)[pipelineOptions.permutationIndex];
12950 
12951     if (computePipeline->valid())
12952     {
12953         *pipelineOut = computePipeline;
12954         return angle::Result::Continue;
12955     }
12956 
12957     VkPipelineShaderStageCreateInfo shaderStage = {};
12958     VkComputePipelineCreateInfo createInfo      = {};
12959 
12960     shaderStage.sType               = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
12961     shaderStage.flags               = 0;
12962     shaderStage.stage               = VK_SHADER_STAGE_COMPUTE_BIT;
12963     shaderStage.module              = mShaders[gl::ShaderType::Compute]->getHandle();
12964     shaderStage.pName               = shaderName ? shaderName : "main";
12965     shaderStage.pSpecializationInfo = specializationInfo;
12966 
12967     createInfo.sType              = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
12968     createInfo.flags              = 0;
12969     createInfo.stage              = shaderStage;
12970     createInfo.layout             = pipelineLayout.getHandle();
12971     createInfo.basePipelineHandle = VK_NULL_HANDLE;
12972     createInfo.basePipelineIndex  = 0;
12973 
12974     VkPipelineRobustnessCreateInfoEXT robustness = {};
12975     robustness.sType = VK_STRUCTURE_TYPE_PIPELINE_ROBUSTNESS_CREATE_INFO_EXT;
12976 
12977     // Enable robustness on the pipeline if needed.  Note that the global robustBufferAccess feature
12978     // must be disabled by default.
12979     if (pipelineOptions.robustness != 0)
12980     {
12981         ASSERT(context->getFeatures().supportsPipelineRobustness.enabled);
12982 
12983         robustness.storageBuffers = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT;
12984         robustness.uniformBuffers = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT;
12985         robustness.vertexInputs   = VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DEVICE_DEFAULT_EXT;
12986         robustness.images         = VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DEVICE_DEFAULT_EXT;
12987 
12988         AddToPNextChain(&createInfo, &robustness);
12989     }
12990 
12991     // Restrict pipeline to protected or unprotected command buffers if possible.
12992     if (pipelineOptions.protectedAccess != 0)
12993     {
12994         ASSERT(context->getFeatures().supportsPipelineProtectedAccess.enabled);
12995         createInfo.flags |= VK_PIPELINE_CREATE_PROTECTED_ACCESS_ONLY_BIT_EXT;
12996     }
12997     else if (context->getFeatures().supportsPipelineProtectedAccess.enabled)
12998     {
12999         createInfo.flags |= VK_PIPELINE_CREATE_NO_PROTECTED_ACCESS_BIT_EXT;
13000     }
13001 
13002     VkPipelineCreationFeedback feedback               = {};
13003     VkPipelineCreationFeedback perStageFeedback       = {};
13004     VkPipelineCreationFeedbackCreateInfo feedbackInfo = {};
13005     feedbackInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CREATION_FEEDBACK_CREATE_INFO;
13006     feedbackInfo.pPipelineCreationFeedback = &feedback;
13007     // Note: see comment in GraphicsPipelineDesc::initializePipeline about why per-stage feedback is
13008     // specified even though unused.
13009     feedbackInfo.pipelineStageCreationFeedbackCount = 1;
13010     feedbackInfo.pPipelineStageCreationFeedbacks    = &perStageFeedback;
13011 
13012     const bool supportsFeedback = context->getFeatures().supportsPipelineCreationFeedback.enabled;
13013     if (supportsFeedback)
13014     {
13015         AddToPNextChain(&createInfo, &feedbackInfo);
13016     }
13017 
13018     vk::Pipeline pipeline;
13019     ANGLE_VK_TRY(context, pipelineCache->createComputePipeline(context, createInfo, &pipeline));
13020 
13021     vk::CacheLookUpFeedback lookUpFeedback = CacheLookUpFeedback::None;
13022 
13023     if (supportsFeedback)
13024     {
13025         const bool cacheHit =
13026             (feedback.flags & VK_PIPELINE_CREATION_FEEDBACK_APPLICATION_PIPELINE_CACHE_HIT_BIT) !=
13027             0;
13028 
13029         lookUpFeedback = cacheHit ? CacheLookUpFeedback::Hit : CacheLookUpFeedback::Miss;
13030         ApplyPipelineCreationFeedback(context, feedback);
13031     }
13032 
13033     computePipeline->setComputePipeline(std::move(pipeline), lookUpFeedback);
13034 
13035     *pipelineOut = computePipeline;
13036     return angle::Result::Continue;
13037 }
13038 
13039 // ActiveHandleCounter implementation.
ActiveHandleCounter()13040 ActiveHandleCounter::ActiveHandleCounter() : mActiveCounts{}, mAllocatedCounts{} {}
13041 
13042 ActiveHandleCounter::~ActiveHandleCounter() = default;
13043 
13044 // CommandBufferAccess implementation.
13045 CommandBufferAccess::CommandBufferAccess()  = default;
13046 CommandBufferAccess::~CommandBufferAccess() = default;
13047 
onBufferRead(VkAccessFlags readAccessType,PipelineStage readStage,BufferHelper * buffer)13048 void CommandBufferAccess::onBufferRead(VkAccessFlags readAccessType,
13049                                        PipelineStage readStage,
13050                                        BufferHelper *buffer)
13051 {
13052     ASSERT(!buffer->isReleasedToExternal());
13053     mReadBuffers.emplace_back(buffer, readAccessType, readStage);
13054 }
13055 
onBufferWrite(VkAccessFlags writeAccessType,PipelineStage writeStage,BufferHelper * buffer)13056 void CommandBufferAccess::onBufferWrite(VkAccessFlags writeAccessType,
13057                                         PipelineStage writeStage,
13058                                         BufferHelper *buffer)
13059 {
13060     ASSERT(!buffer->isReleasedToExternal());
13061     mWriteBuffers.emplace_back(buffer, writeAccessType, writeStage);
13062 }
13063 
onImageRead(VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)13064 void CommandBufferAccess::onImageRead(VkImageAspectFlags aspectFlags,
13065                                       ImageLayout imageLayout,
13066                                       ImageHelper *image)
13067 {
13068     ASSERT(!image->isReleasedToExternal());
13069     ASSERT(image->getImageSerial().valid());
13070     mReadImages.emplace_back(image, aspectFlags, imageLayout);
13071 }
13072 
onImageWrite(gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)13073 void CommandBufferAccess::onImageWrite(gl::LevelIndex levelStart,
13074                                        uint32_t levelCount,
13075                                        uint32_t layerStart,
13076                                        uint32_t layerCount,
13077                                        VkImageAspectFlags aspectFlags,
13078                                        ImageLayout imageLayout,
13079                                        ImageHelper *image)
13080 {
13081     ASSERT(!image->isReleasedToExternal());
13082     ASSERT(image->getImageSerial().valid());
13083     mWriteImages.emplace_back(CommandBufferImageAccess{image, aspectFlags, imageLayout}, levelStart,
13084                               levelCount, layerStart, layerCount);
13085 }
13086 
onImageReadSubresources(gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)13087 void CommandBufferAccess::onImageReadSubresources(gl::LevelIndex levelStart,
13088                                                   uint32_t levelCount,
13089                                                   uint32_t layerStart,
13090                                                   uint32_t layerCount,
13091                                                   VkImageAspectFlags aspectFlags,
13092                                                   ImageLayout imageLayout,
13093                                                   ImageHelper *image)
13094 {
13095     ASSERT(!image->isReleasedToExternal());
13096     ASSERT(image->getImageSerial().valid());
13097     mReadImageSubresources.emplace_back(CommandBufferImageAccess{image, aspectFlags, imageLayout},
13098                                         levelStart, levelCount, layerStart, layerCount);
13099 }
13100 
onBufferExternalAcquireRelease(BufferHelper * buffer)13101 void CommandBufferAccess::onBufferExternalAcquireRelease(BufferHelper *buffer)
13102 {
13103     mExternalAcquireReleaseBuffers.emplace_back(CommandBufferBufferExternalAcquireRelease{buffer});
13104 }
13105 
onResourceAccess(Resource * resource)13106 void CommandBufferAccess::onResourceAccess(Resource *resource)
13107 {
13108     mAccessResources.emplace_back(CommandBufferResourceAccess{resource});
13109 }
13110 
13111 // DescriptorMetaCache implementation.
13112 MetaDescriptorPool::MetaDescriptorPool() = default;
13113 
~MetaDescriptorPool()13114 MetaDescriptorPool::~MetaDescriptorPool()
13115 {
13116     ASSERT(mPayload.empty());
13117 }
13118 
destroy(Renderer * renderer)13119 void MetaDescriptorPool::destroy(Renderer *renderer)
13120 {
13121     for (auto &iter : mPayload)
13122     {
13123         DynamicDescriptorPoolPointer &pool = iter.second;
13124         ASSERT(pool.unique());
13125     }
13126     mPayload.clear();
13127 }
13128 
bindCachedDescriptorPool(Context * context,const DescriptorSetLayoutDesc & descriptorSetLayoutDesc,uint32_t descriptorCountMultiplier,DescriptorSetLayoutCache * descriptorSetLayoutCache,DynamicDescriptorPoolPointer * dynamicDescriptorPoolOut)13129 angle::Result MetaDescriptorPool::bindCachedDescriptorPool(
13130     Context *context,
13131     const DescriptorSetLayoutDesc &descriptorSetLayoutDesc,
13132     uint32_t descriptorCountMultiplier,
13133     DescriptorSetLayoutCache *descriptorSetLayoutCache,
13134     DynamicDescriptorPoolPointer *dynamicDescriptorPoolOut)
13135 {
13136     if (descriptorSetLayoutDesc.empty())
13137     {
13138         // No need for descriptorSet pool.
13139         return angle::Result::Continue;
13140     }
13141 
13142     auto cacheIter = mPayload.find(descriptorSetLayoutDesc);
13143     if (cacheIter != mPayload.end())
13144     {
13145         *dynamicDescriptorPoolOut = cacheIter->second;
13146         return angle::Result::Continue;
13147     }
13148 
13149     DescriptorSetLayoutPtr descriptorSetLayout;
13150     ANGLE_TRY(descriptorSetLayoutCache->getDescriptorSetLayout(context, descriptorSetLayoutDesc,
13151                                                                &descriptorSetLayout));
13152 
13153     DynamicDescriptorPool newDescriptorPool;
13154     ANGLE_TRY(InitDynamicDescriptorPool(context, descriptorSetLayoutDesc, *descriptorSetLayout,
13155                                         descriptorCountMultiplier, &newDescriptorPool));
13156 
13157     ASSERT(newDescriptorPool.valid());
13158     DynamicDescriptorPoolPointer newDynamicDescriptorPoolPtr(context->getDevice(),
13159                                                              std::move(newDescriptorPool));
13160     mPayload.emplace(descriptorSetLayoutDesc, newDynamicDescriptorPoolPtr);
13161     *dynamicDescriptorPoolOut = std::move(newDynamicDescriptorPoolPtr);
13162 
13163     return angle::Result::Continue;
13164 }
13165 
13166 static_assert(static_cast<uint32_t>(PresentMode::ImmediateKHR) == VK_PRESENT_MODE_IMMEDIATE_KHR,
13167               "PresentMode must be updated");
13168 static_assert(static_cast<uint32_t>(PresentMode::MailboxKHR) == VK_PRESENT_MODE_MAILBOX_KHR,
13169               "PresentMode must be updated");
13170 static_assert(static_cast<uint32_t>(PresentMode::FifoKHR) == VK_PRESENT_MODE_FIFO_KHR,
13171               "PresentMode must be updated");
13172 static_assert(static_cast<uint32_t>(PresentMode::FifoRelaxedKHR) ==
13173                   VK_PRESENT_MODE_FIFO_RELAXED_KHR,
13174               "PresentMode must be updated");
13175 static_assert(static_cast<uint32_t>(PresentMode::SharedDemandRefreshKHR) ==
13176                   VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR,
13177               "PresentMode must be updated");
13178 static_assert(static_cast<uint32_t>(PresentMode::SharedContinuousRefreshKHR) ==
13179                   VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR,
13180               "PresentMode must be updated");
13181 
ConvertPresentModeToVkPresentMode(PresentMode presentMode)13182 VkPresentModeKHR ConvertPresentModeToVkPresentMode(PresentMode presentMode)
13183 {
13184     return static_cast<VkPresentModeKHR>(presentMode);
13185 }
13186 
ConvertVkPresentModeToPresentMode(VkPresentModeKHR vkPresentMode)13187 PresentMode ConvertVkPresentModeToPresentMode(VkPresentModeKHR vkPresentMode)
13188 {
13189     return static_cast<PresentMode>(vkPresentMode);
13190 }
13191 
13192 }  // namespace vk
13193 }  // namespace rx
13194