• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2018 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // vk_helpers:
7 //   Helper utility classes that manage Vulkan resources.
8 
9 #include "libANGLE/renderer/vulkan/vk_helpers.h"
10 
11 #include "common/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 // Information useful for buffer related barriers
51 struct BufferMemoryBarrierData
52 {
53     VkPipelineStageFlags pipelineStageFlags;
54     // EventStage::InvalidEnum indicates don't use VkEvent for barrier(i.e., use pipelineBarrier
55     // instead)
56     EventStage eventStage;
57 };
58 // clang-format off
59 constexpr angle::PackedEnumMap<PipelineStage, BufferMemoryBarrierData> kBufferMemoryBarrierData = {
60     {PipelineStage::TopOfPipe, {VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, EventStage::InvalidEnum}},
61     {PipelineStage::DrawIndirect, {VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, EventStage::VertexInput}},
62     {PipelineStage::VertexInput, {VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, EventStage::VertexInput}},
63     {PipelineStage::VertexShader, {VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, EventStage::VertexShader}},
64     {PipelineStage::TessellationControl, {VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT, EventStage::InvalidEnum}},
65     {PipelineStage::TessellationEvaluation, {VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT, EventStage::InvalidEnum}},
66     {PipelineStage::GeometryShader, {VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT, EventStage::InvalidEnum}},
67     {PipelineStage::TransformFeedback, {VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT, EventStage::TransformFeedbackWrite}},
68     {PipelineStage::FragmentShadingRate, {0, EventStage::InvalidEnum}},
69     {PipelineStage::EarlyFragmentTest, {0, EventStage::InvalidEnum}},
70     {PipelineStage::FragmentShader, {VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, EventStage::FragmentShader}},
71     {PipelineStage::LateFragmentTest, {0, EventStage::InvalidEnum}},
72     {PipelineStage::ColorAttachmentOutput, {0, EventStage::InvalidEnum}},
73     {PipelineStage::ComputeShader, {VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, EventStage::ComputeShader}},
74     {PipelineStage::Transfer, {VK_PIPELINE_STAGE_TRANSFER_BIT, EventStage::InvalidEnum}},
75     {PipelineStage::BottomOfPipe, BufferMemoryBarrierData{VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, EventStage::InvalidEnum}},
76     {PipelineStage::Host, {VK_PIPELINE_STAGE_HOST_BIT, EventStage::InvalidEnum}},
77 };
78 
79 constexpr gl::ShaderMap<PipelineStage> kPipelineStageShaderMap = {
80     {gl::ShaderType::Vertex, PipelineStage::VertexShader},
81     {gl::ShaderType::TessControl, PipelineStage::TessellationControl},
82     {gl::ShaderType::TessEvaluation, PipelineStage::TessellationEvaluation},
83     {gl::ShaderType::Geometry, PipelineStage::GeometryShader},
84     {gl::ShaderType::Fragment, PipelineStage::FragmentShader},
85     {gl::ShaderType::Compute, PipelineStage::ComputeShader},
86 };
87 
88 constexpr ImageLayoutToMemoryBarrierDataMap kImageMemoryBarrierData = {
89     {
90         ImageLayout::Undefined,
91         ImageMemoryBarrierData{
92             "Undefined",
93             VK_IMAGE_LAYOUT_UNDEFINED,
94             VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
95             VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
96             // Transition to: we don't expect to transition into Undefined.
97             0,
98             // Transition from: there's no data in the image to care about.
99             0,
100             ResourceAccess::ReadOnly,
101             PipelineStage::InvalidEnum,
102             // We do not directly use this layout in SetEvent. We transit to other layout before using
103             EventStage::InvalidEnum,
104             PipelineStageGroup::Other,
105         },
106     },
107     {
108         ImageLayout::ColorWrite,
109         ImageMemoryBarrierData{
110             "ColorWrite",
111             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
112             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
113             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
114             // Transition to: all reads and writes must happen after barrier.
115             VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
116             // Transition from: all writes must finish before barrier.
117             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
118             ResourceAccess::ReadWrite,
119             PipelineStage::ColorAttachmentOutput,
120             EventStage::Attachment,
121             PipelineStageGroup::FragmentOnly,
122         },
123     },
124     {
125         ImageLayout::ColorWriteAndInput,
126         ImageMemoryBarrierData{
127             "ColorWriteAndInput",
128             VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ_KHR,
129             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
130             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
131             // Transition to: all reads and writes must happen after barrier.
132             VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
133             // Transition from: all writes must finish before barrier.
134             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
135             ResourceAccess::ReadWrite,
136             PipelineStage::ColorAttachmentOutput,
137             EventStage::Attachment,
138             PipelineStageGroup::FragmentOnly,
139         },
140     },
141     {
142         ImageLayout::MSRTTEmulationColorUnresolveAndResolve,
143         ImageMemoryBarrierData{
144             "MSRTTEmulationColorUnresolveAndResolve",
145             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
146             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
147             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
148             // Transition to: all reads and writes must happen after barrier.
149             VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
150             // Transition from: all writes must finish before barrier.
151             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
152             ResourceAccess::ReadWrite,
153             PipelineStage::FragmentShader,
154             EventStage::AttachmentAndFragmentShader,
155             PipelineStageGroup::FragmentOnly,
156         },
157     },
158     {
159         ImageLayout::DepthWriteStencilWrite,
160         ImageMemoryBarrierData{
161             "DepthWriteStencilWrite",
162             VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
163             kAllDepthStencilPipelineStageFlags,
164             kAllDepthStencilPipelineStageFlags,
165             // Transition to: all reads and writes must happen after barrier.
166             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
167             // Transition from: all writes must finish before barrier.
168             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
169             ResourceAccess::ReadWrite,
170             PipelineStage::EarlyFragmentTest,
171             EventStage::Attachment,
172             PipelineStageGroup::FragmentOnly,
173         },
174     },
175     {
176         ImageLayout::DepthStencilWriteAndInput,
177         ImageMemoryBarrierData{
178             "DepthStencilWriteAndInput",
179             VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ_KHR,
180             kAllDepthStencilPipelineStageFlags,
181             kAllDepthStencilPipelineStageFlags,
182             // Transition to: all reads and writes must happen after barrier.
183             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
184             // Transition from: all writes must finish before barrier.
185             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
186             ResourceAccess::ReadWrite,
187             PipelineStage::EarlyFragmentTest,
188             EventStage::Attachment,
189             PipelineStageGroup::FragmentOnly,
190         },
191     },
192     {
193         ImageLayout::DepthWriteStencilRead,
194         ImageMemoryBarrierData{
195             "DepthWriteStencilRead",
196             VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL,
197             kAllDepthStencilPipelineStageFlags,
198             kAllDepthStencilPipelineStageFlags,
199             // Transition to: all reads and writes must happen after barrier.
200             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
201             // Transition from: all writes must finish before barrier.
202             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
203             ResourceAccess::ReadWrite,
204             PipelineStage::EarlyFragmentTest,
205             EventStage::Attachment,
206             PipelineStageGroup::FragmentOnly,
207         },
208     },
209     {
210         ImageLayout::DepthWriteStencilReadFragmentShaderStencilRead,
211         ImageMemoryBarrierData{
212             "DepthWriteStencilReadFragmentShaderStencilRead",
213             VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL,
214             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
215             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
216             // Transition to: all reads and writes must happen after barrier.
217             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
218             // Transition from: all writes must finish before barrier.
219             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
220             ResourceAccess::ReadWrite,
221             PipelineStage::EarlyFragmentTest,
222             EventStage::AttachmentAndFragmentShader,
223             PipelineStageGroup::FragmentOnly,
224         },
225     },
226     {
227         ImageLayout::DepthWriteStencilReadAllShadersStencilRead,
228         ImageMemoryBarrierData{
229             "DepthWriteStencilReadAllShadersStencilRead",
230             VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL,
231             kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
232             kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
233             // Transition to: all reads and writes must happen after barrier.
234             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
235             // Transition from: all writes must finish before barrier.
236             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
237             ResourceAccess::ReadWrite,
238             PipelineStage::VertexShader,
239             EventStage::AttachmentAndAllShaders,
240             PipelineStageGroup::Other,
241         },
242     },
243     {
244         ImageLayout::DepthReadStencilWrite,
245         ImageMemoryBarrierData{
246             "DepthReadStencilWrite",
247             VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL,
248             kAllDepthStencilPipelineStageFlags,
249             kAllDepthStencilPipelineStageFlags,
250             // Transition to: all reads and writes must happen after barrier.
251             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
252             // Transition from: all writes must finish before barrier.
253             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
254             ResourceAccess::ReadWrite,
255             PipelineStage::EarlyFragmentTest,
256             EventStage::Attachment,
257             PipelineStageGroup::FragmentOnly,
258         },
259     },
260     {
261         ImageLayout::DepthReadStencilWriteFragmentShaderDepthRead,
262         ImageMemoryBarrierData{
263             "DepthReadStencilWriteFragmentShaderDepthRead",
264             VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL,
265             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
266             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
267             // Transition to: all reads and writes must happen after barrier.
268             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
269             // Transition from: all writes must finish before barrier.
270             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
271             ResourceAccess::ReadWrite,
272             PipelineStage::EarlyFragmentTest,
273             EventStage::AttachmentAndFragmentShader,
274             PipelineStageGroup::FragmentOnly,
275         },
276     },
277     {
278         ImageLayout::DepthReadStencilWriteAllShadersDepthRead,
279         ImageMemoryBarrierData{
280             "DepthReadStencilWriteAllShadersDepthRead",
281             VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL,
282             kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
283             kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
284             // Transition to: all reads and writes must happen after barrier.
285             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
286             // Transition from: all writes must finish before barrier.
287             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
288             ResourceAccess::ReadWrite,
289             PipelineStage::VertexShader,
290             EventStage::AttachmentAndAllShaders,
291             PipelineStageGroup::Other,
292         },
293     },
294     {
295         ImageLayout::DepthReadStencilRead,
296             ImageMemoryBarrierData{
297             "DepthReadStencilRead",
298             VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
299             kAllDepthStencilPipelineStageFlags,
300             kAllDepthStencilPipelineStageFlags,
301             // Transition to: all reads must happen after barrier.
302             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
303             // Transition from: RAR and WAR don't need memory barrier.
304             0,
305             ResourceAccess::ReadOnly,
306             PipelineStage::EarlyFragmentTest,
307             EventStage::Attachment,
308             PipelineStageGroup::FragmentOnly,
309         },
310     },
311 
312     {
313         ImageLayout::DepthReadStencilReadFragmentShaderRead,
314             ImageMemoryBarrierData{
315             "DepthReadStencilReadFragmentShaderRead",
316             VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
317             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
318             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | kAllDepthStencilPipelineStageFlags,
319             // Transition to: all reads must happen after barrier.
320             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
321             // Transition from: RAR and WAR don't need memory barrier.
322             0,
323             ResourceAccess::ReadOnly,
324             PipelineStage::EarlyFragmentTest,
325             EventStage::AttachmentAndFragmentShader,
326             PipelineStageGroup::FragmentOnly,
327         },
328     },
329     {
330         ImageLayout::DepthReadStencilReadAllShadersRead,
331             ImageMemoryBarrierData{
332             "DepthReadStencilReadAllShadersRead",
333             VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
334             kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
335             kAllShadersPipelineStageFlags | kAllDepthStencilPipelineStageFlags,
336             // Transition to: all reads must happen after barrier.
337             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
338             // Transition from: RAR and WAR don't need memory barrier.
339             0,
340             ResourceAccess::ReadOnly,
341             PipelineStage::VertexShader,
342             EventStage::AttachmentAndAllShaders,
343             PipelineStageGroup::Other,
344         },
345     },
346     {
347         ImageLayout::ColorWriteFragmentShaderFeedback,
348         ImageMemoryBarrierData{
349             "ColorWriteFragmentShaderFeedback",
350             VK_IMAGE_LAYOUT_GENERAL,
351             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
352             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
353             // Transition to: all reads and writes must happen after barrier.
354             VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
355             // Transition from: all writes must finish before barrier.
356             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
357             ResourceAccess::ReadWrite,
358             PipelineStage::FragmentShader,
359             EventStage::AttachmentAndFragmentShader,
360             PipelineStageGroup::FragmentOnly,
361         },
362     },
363     {
364         ImageLayout::ColorWriteAllShadersFeedback,
365         ImageMemoryBarrierData{
366             "ColorWriteAllShadersFeedback",
367             VK_IMAGE_LAYOUT_GENERAL,
368             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | kAllShadersPipelineStageFlags,
369             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | kAllShadersPipelineStageFlags,
370             // Transition to: all reads and writes must happen after barrier.
371             VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
372             // Transition from: all writes must finish before barrier.
373             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
374             ResourceAccess::ReadWrite,
375             // In case of multiple destination stages, We barrier the earliest stage
376             PipelineStage::VertexShader,
377             EventStage::AttachmentAndAllShaders,
378             PipelineStageGroup::Other,
379         },
380     },
381     {
382         ImageLayout::DepthStencilFragmentShaderFeedback,
383         ImageMemoryBarrierData{
384             "DepthStencilFragmentShaderFeedback",
385             VK_IMAGE_LAYOUT_GENERAL,
386             kAllDepthStencilPipelineStageFlags | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
387             kAllDepthStencilPipelineStageFlags | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
388             // Transition to: all reads and writes must happen after barrier.
389             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
390             // Transition from: all writes must finish before barrier.
391             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
392             ResourceAccess::ReadWrite,
393             PipelineStage::FragmentShader,
394             EventStage::AttachmentAndFragmentShader,
395             PipelineStageGroup::FragmentOnly,
396         },
397     },
398     {
399         ImageLayout::DepthStencilAllShadersFeedback,
400         ImageMemoryBarrierData{
401             "DepthStencilAllShadersFeedback",
402             VK_IMAGE_LAYOUT_GENERAL,
403             kAllDepthStencilPipelineStageFlags | kAllShadersPipelineStageFlags,
404             kAllDepthStencilPipelineStageFlags | kAllShadersPipelineStageFlags,
405             // Transition to: all reads and writes must happen after barrier.
406             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
407             // Transition from: all writes must finish before barrier.
408             VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
409             ResourceAccess::ReadWrite,
410             // In case of multiple destination stages, We barrier the earliest stage
411             PipelineStage::VertexShader,
412             EventStage::AttachmentAndAllShaders,
413             PipelineStageGroup::Other,
414         },
415     },
416     {
417         ImageLayout::DepthStencilResolve,
418         ImageMemoryBarrierData{
419             "DepthStencilResolve",
420             VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
421             // Note: depth/stencil resolve uses color output stage and mask!
422             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
423             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
424             // Transition to: all reads and writes must happen after barrier.
425             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
426             // Transition from: all writes must finish before barrier.
427             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
428             ResourceAccess::ReadWrite,
429             PipelineStage::ColorAttachmentOutput,
430             EventStage::Attachment,
431             PipelineStageGroup::FragmentOnly,
432         },
433     },
434     {
435         ImageLayout::MSRTTEmulationDepthStencilUnresolveAndResolve,
436         ImageMemoryBarrierData{
437             "MSRTTEmulationDepthStencilUnresolveAndResolve",
438             VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
439             // Note: depth/stencil resolve uses color output stage and mask!
440             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
441             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
442             // Transition to: all reads and writes must happen after barrier.
443             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT,
444             // Transition from: all writes must finish before barrier.
445             VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
446             ResourceAccess::ReadWrite,
447             PipelineStage::FragmentShader,
448             EventStage::AttachmentAndFragmentShader,
449             PipelineStageGroup::FragmentOnly,
450         },
451     },
452     {
453         ImageLayout::Present,
454         ImageMemoryBarrierData{
455             "Present",
456             VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
457             // Transition to: do not delay execution of commands in the second synchronization
458             // scope. Allow layout transition to be delayed until present semaphore is signaled.
459             VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
460             // Transition from: use same stages as in Acquire Image Semaphore stage mask in order to
461             // build a dependency chain from the Acquire Image Semaphore to the layout transition's
462             // first synchronization scope.
463             kSwapchainAcquireImageWaitStageFlags,
464             // Transition to: vkQueuePresentKHR automatically performs the appropriate memory barriers:
465             //
466             // > Any writes to memory backing the images referenced by the pImageIndices and
467             // > pSwapchains members of pPresentInfo, that are available before vkQueuePresentKHR
468             // > is executed, are automatically made visible to the read access performed by the
469             // > presentation engine.
470             0,
471             // Transition from: RAR and WAR don't need memory barrier.
472             0,
473             ResourceAccess::ReadOnly,
474             PipelineStage::BottomOfPipe,
475             // We do not directly use this layout in SetEvent.
476             EventStage::InvalidEnum,
477             PipelineStageGroup::Other,
478         },
479     },
480     {
481         ImageLayout::SharedPresent,
482         ImageMemoryBarrierData{
483             "SharedPresent",
484             VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR,
485             // All currently possible stages for SharedPresent
486             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
487             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
488             // Transition to: all reads and writes must happen after barrier.
489             VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
490             // Transition from: all writes must finish before barrier.
491             VK_ACCESS_MEMORY_WRITE_BIT,
492             ResourceAccess::ReadWrite,
493             PipelineStage::BottomOfPipe,
494             EventStage::AttachmentAndFragmentShaderAndTransfer,
495             PipelineStageGroup::Other,
496         },
497     },
498     {
499         ImageLayout::ExternalPreInitialized,
500         ImageMemoryBarrierData{
501             "ExternalPreInitialized",
502             // Binding a VkImage with an initial layout of VK_IMAGE_LAYOUT_UNDEFINED to external
503             // memory whose content has already been defined does not make the content undefined
504             // (see 12.8.1.  External Resource Sharing).
505             //
506             // Note that for external memory objects, if the content is already defined, the
507             // ownership rules imply that the first operation on the texture must be a call to
508             // glWaitSemaphoreEXT that grants ownership of the image and informs us of the true
509             // layout.  If the content is not already defined, the first operation may not be a
510             // glWaitSemaphore, but in this case undefined layout is appropriate.
511             VK_IMAGE_LAYOUT_UNDEFINED,
512             VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
513             VK_PIPELINE_STAGE_HOST_BIT | VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
514             // Transition to: we don't expect to transition into PreInitialized.
515             0,
516             // Transition from: all writes must finish before barrier.
517             VK_ACCESS_MEMORY_WRITE_BIT,
518             ResourceAccess::ReadOnly,
519             PipelineStage::InvalidEnum,
520             // We do not directly use this layout in SetEvent. We transit to internal layout before using
521             EventStage::InvalidEnum,
522             PipelineStageGroup::Other,
523         },
524     },
525     {
526         ImageLayout::ExternalShadersReadOnly,
527         ImageMemoryBarrierData{
528             "ExternalShadersReadOnly",
529             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
530             VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
531             VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
532             // Transition to: all reads must happen after barrier.
533             VK_ACCESS_SHADER_READ_BIT,
534             // Transition from: RAR and WAR don't need memory barrier.
535             0,
536             ResourceAccess::ReadOnly,
537             // In case of multiple destination stages, We barrier the earliest stage
538             PipelineStage::TopOfPipe,
539             // We do not directly use this layout in SetEvent. We transit to internal layout before using
540             EventStage::InvalidEnum,
541             PipelineStageGroup::Other,
542         },
543     },
544     {
545         ImageLayout::ExternalShadersWrite,
546         ImageMemoryBarrierData{
547             "ExternalShadersWrite",
548             VK_IMAGE_LAYOUT_GENERAL,
549             VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
550             VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
551             // Transition to: all reads and writes must happen after barrier.
552             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
553             // Transition from: all writes must finish before barrier.
554             VK_ACCESS_SHADER_WRITE_BIT,
555             ResourceAccess::ReadWrite,
556             // In case of multiple destination stages, We barrier the earliest stage
557             PipelineStage::TopOfPipe,
558             // We do not directly use this layout in SetEvent. We transit to internal layout before using
559             EventStage::InvalidEnum,
560             PipelineStageGroup::Other,
561         },
562     },
563     {
564         ImageLayout::ForeignAccess,
565         ImageMemoryBarrierData{
566             "ForeignAccess",
567             VK_IMAGE_LAYOUT_GENERAL,
568             // Transition to: we don't expect to transition into ForeignAccess, that's done at
569             // submission time by the CommandQueue; the following value doesn't matter.
570             VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
571             VK_PIPELINE_STAGE_HOST_BIT | VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
572             // Transition to: see dstStageMask
573             0,
574             // Transition from: all writes must finish before barrier; it is unknown how the foreign
575             // entity has access the memory.
576             VK_ACCESS_MEMORY_WRITE_BIT,
577             ResourceAccess::ReadWrite,
578             // In case of multiple destination stages, We barrier the earliest stage
579             PipelineStage::TopOfPipe,
580             // We do not directly use this layout in SetEvent. We transit to internal layout before using
581             EventStage::InvalidEnum,
582             PipelineStageGroup::Other,
583         },
584     },
585     {
586         ImageLayout::TransferSrc,
587         ImageMemoryBarrierData{
588             "TransferSrc",
589             VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
590             VK_PIPELINE_STAGE_TRANSFER_BIT,
591             VK_PIPELINE_STAGE_TRANSFER_BIT,
592             // Transition to: all reads must happen after barrier.
593             VK_ACCESS_TRANSFER_READ_BIT,
594             // Transition from: RAR and WAR don't need memory barrier.
595             0,
596             ResourceAccess::ReadOnly,
597             PipelineStage::Transfer,
598             EventStage::Transfer,
599             PipelineStageGroup::Other,
600         },
601     },
602     {
603         ImageLayout::TransferDst,
604         ImageMemoryBarrierData{
605             "TransferDst",
606             VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
607             VK_PIPELINE_STAGE_TRANSFER_BIT,
608             VK_PIPELINE_STAGE_TRANSFER_BIT,
609             // Transition to: all writes must happen after barrier.
610             VK_ACCESS_TRANSFER_WRITE_BIT,
611             // Transition from: all writes must finish before barrier.
612             VK_ACCESS_TRANSFER_WRITE_BIT,
613             ResourceAccess::ReadWrite,
614             PipelineStage::Transfer,
615             EventStage::Transfer,
616             PipelineStageGroup::Other,
617         },
618     },
619     {
620         ImageLayout::TransferSrcDst,
621         ImageMemoryBarrierData{
622             "TransferSrcDst",
623             VK_IMAGE_LAYOUT_GENERAL,
624             VK_PIPELINE_STAGE_TRANSFER_BIT,
625             VK_PIPELINE_STAGE_TRANSFER_BIT,
626             // Transition to: all reads and writes must happen after barrier.
627             VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
628             // Transition from: all writes must finish before barrier.
629             VK_ACCESS_TRANSFER_WRITE_BIT,
630             ResourceAccess::ReadWrite,
631             PipelineStage::Transfer,
632             EventStage::Transfer,
633             PipelineStageGroup::Other,
634         },
635     },
636     {
637         ImageLayout::HostCopy,
638         ImageMemoryBarrierData{
639             "HostCopy",
640             VK_IMAGE_LAYOUT_GENERAL,
641             VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
642             VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
643             // Transition to: we don't expect to transition into HostCopy on the GPU.
644             0,
645             // Transition from: the data was initialized in the image by the host.  Note that we
646             // only transition to this layout if the image was previously in UNDEFINED, in which
647             // case it didn't contain any data prior to the host copy either.
648             0,
649             ResourceAccess::ReadOnly,
650             PipelineStage::InvalidEnum,
651             // We do not directly use this layout in SetEvent.
652             EventStage::InvalidEnum,
653             PipelineStageGroup::Other,
654         },
655     },
656     {
657         ImageLayout::VertexShaderReadOnly,
658         ImageMemoryBarrierData{
659             "VertexShaderReadOnly",
660             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
661             VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
662             VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
663             // Transition to: all reads must happen after barrier.
664             VK_ACCESS_SHADER_READ_BIT,
665             // Transition from: RAR and WAR don't need memory barrier.
666             0,
667             ResourceAccess::ReadOnly,
668             PipelineStage::VertexShader,
669             EventStage::VertexShader,
670             PipelineStageGroup::PreFragmentOnly,
671         },
672     },
673     {
674         ImageLayout::VertexShaderWrite,
675         ImageMemoryBarrierData{
676             "VertexShaderWrite",
677             VK_IMAGE_LAYOUT_GENERAL,
678             VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
679             VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
680             // Transition to: all reads and writes must happen after barrier.
681             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
682             // Transition from: all writes must finish before barrier.
683             VK_ACCESS_SHADER_WRITE_BIT,
684             ResourceAccess::ReadWrite,
685             PipelineStage::VertexShader,
686             EventStage::VertexShader,
687             PipelineStageGroup::PreFragmentOnly,
688         },
689     },
690     {
691         ImageLayout::PreFragmentShadersReadOnly,
692         ImageMemoryBarrierData{
693             "PreFragmentShadersReadOnly",
694             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
695             kPreFragmentStageFlags,
696             kPreFragmentStageFlags,
697             // Transition to: all reads must happen after barrier.
698             VK_ACCESS_SHADER_READ_BIT,
699             // Transition from: RAR and WAR don't need memory barrier.
700             0,
701             ResourceAccess::ReadOnly,
702             // In case of multiple destination stages, We barrier the earliest stage
703             PipelineStage::VertexShader,
704             EventStage::PreFragmentShaders,
705             PipelineStageGroup::PreFragmentOnly,
706         },
707     },
708     {
709         ImageLayout::PreFragmentShadersWrite,
710         ImageMemoryBarrierData{
711             "PreFragmentShadersWrite",
712             VK_IMAGE_LAYOUT_GENERAL,
713             kPreFragmentStageFlags,
714             kPreFragmentStageFlags,
715             // Transition to: all reads and writes must happen after barrier.
716             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
717             // Transition from: all writes must finish before barrier.
718             VK_ACCESS_SHADER_WRITE_BIT,
719             ResourceAccess::ReadWrite,
720             // In case of multiple destination stages, We barrier the earliest stage
721             PipelineStage::VertexShader,
722             EventStage::PreFragmentShaders,
723             PipelineStageGroup::PreFragmentOnly,
724         },
725     },
726     {
727         ImageLayout::FragmentShadingRateAttachmentReadOnly,
728         ImageMemoryBarrierData{
729             "FragmentShadingRateAttachmentReadOnly",
730             VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR,
731             VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR,
732             VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR,
733             // Transition to: all reads must happen after barrier.
734             VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR,
735             // Transition from: RAR and WAR don't need memory barrier.
736             0,
737             ResourceAccess::ReadOnly,
738             PipelineStage::FragmentShadingRate,
739             EventStage::FragmentShadingRate,
740             PipelineStageGroup::Other,
741         },
742     },
743     {
744         ImageLayout::FragmentShaderReadOnly,
745         ImageMemoryBarrierData{
746             "FragmentShaderReadOnly",
747             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
748             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
749             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
750             // Transition to: all reads must happen after barrier.
751             VK_ACCESS_SHADER_READ_BIT,
752             // Transition from: RAR and WAR don't need memory barrier.
753             0,
754             ResourceAccess::ReadOnly,
755             PipelineStage::FragmentShader,
756             EventStage::FragmentShader,
757             PipelineStageGroup::FragmentOnly,
758         },
759     },
760     {
761         ImageLayout::FragmentShaderWrite,
762         ImageMemoryBarrierData{
763             "FragmentShaderWrite",
764             VK_IMAGE_LAYOUT_GENERAL,
765             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
766             VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
767             // Transition to: all reads and writes must happen after barrier.
768             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
769             // Transition from: all writes must finish before barrier.
770             VK_ACCESS_SHADER_WRITE_BIT,
771             ResourceAccess::ReadWrite,
772             PipelineStage::FragmentShader,
773             EventStage::FragmentShader,
774             PipelineStageGroup::FragmentOnly,
775         },
776     },
777     {
778         ImageLayout::ComputeShaderReadOnly,
779         ImageMemoryBarrierData{
780             "ComputeShaderReadOnly",
781             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
782             VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
783             VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
784             // Transition to: all reads must happen after barrier.
785             VK_ACCESS_SHADER_READ_BIT,
786             // Transition from: RAR and WAR don't need memory barrier.
787             0,
788             ResourceAccess::ReadOnly,
789             PipelineStage::ComputeShader,
790             EventStage::ComputeShader,
791             PipelineStageGroup::ComputeOnly,
792         },
793     },
794     {
795         ImageLayout::ComputeShaderWrite,
796         ImageMemoryBarrierData{
797             "ComputeShaderWrite",
798             VK_IMAGE_LAYOUT_GENERAL,
799             VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
800             VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
801             // Transition to: all reads and writes must happen after barrier.
802             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
803             // Transition from: all writes must finish before barrier.
804             VK_ACCESS_SHADER_WRITE_BIT,
805             ResourceAccess::ReadWrite,
806             PipelineStage::ComputeShader,
807             EventStage::ComputeShader,
808             PipelineStageGroup::ComputeOnly,
809         },
810     },
811     {
812         ImageLayout::AllGraphicsShadersReadOnly,
813         ImageMemoryBarrierData{
814             "AllGraphicsShadersReadOnly",
815             VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
816             kAllShadersPipelineStageFlags,
817             kAllShadersPipelineStageFlags,
818             // Transition to: all reads must happen after barrier.
819             VK_ACCESS_SHADER_READ_BIT,
820             // Transition from: RAR and WAR don't need memory barrier.
821             0,
822             ResourceAccess::ReadOnly,
823             // In case of multiple destination stages, We barrier the earliest stage
824             PipelineStage::VertexShader,
825             EventStage::AllShaders,
826             PipelineStageGroup::Other,
827         },
828     },
829     {
830         ImageLayout::AllGraphicsShadersWrite,
831         ImageMemoryBarrierData{
832             "AllGraphicsShadersWrite",
833             VK_IMAGE_LAYOUT_GENERAL,
834             kAllShadersPipelineStageFlags,
835             kAllShadersPipelineStageFlags,
836             // Transition to: all reads and writes must happen after barrier.
837             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
838             // Transition from: all writes must finish before barrier.
839             VK_ACCESS_SHADER_WRITE_BIT,
840             ResourceAccess::ReadWrite,
841             // In case of multiple destination stages, We barrier the earliest stage
842             PipelineStage::VertexShader,
843             EventStage::AllShaders,
844             PipelineStageGroup::Other,
845         },
846     },
847     {
848         ImageLayout::TransferDstAndComputeWrite,
849         ImageMemoryBarrierData{
850             "TransferDstAndComputeWrite",
851             VK_IMAGE_LAYOUT_GENERAL,
852             VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
853             VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_TRANSFER_BIT,
854             // Transition to: all reads and writes must happen after barrier.
855             VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT,
856             // Transition from: all writes must finish before barrier.
857             VK_ACCESS_SHADER_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
858             ResourceAccess::ReadWrite,
859             // In case of multiple destination stages, We barrier the earliest stage
860             PipelineStage::ComputeShader,
861             EventStage::TransferAndComputeShader,
862             PipelineStageGroup::Other,
863         },
864     },
865 };
866 // clang-format on
867 
GetImageLayoutEventStage(ImageLayout layout)868 EventStage GetImageLayoutEventStage(ImageLayout layout)
869 {
870     const ImageMemoryBarrierData &barrierData = kImageMemoryBarrierData[layout];
871     return barrierData.eventStage;
872 }
873 
HasBothDepthAndStencilAspects(VkImageAspectFlags aspectFlags)874 bool HasBothDepthAndStencilAspects(VkImageAspectFlags aspectFlags)
875 {
876     return IsMaskFlagSet(aspectFlags, kDepthStencilAspects);
877 }
878 
GetContentDefinedLayerRangeBits(uint32_t layerStart,uint32_t layerCount,uint32_t maxLayerCount)879 uint8_t GetContentDefinedLayerRangeBits(uint32_t layerStart,
880                                         uint32_t layerCount,
881                                         uint32_t maxLayerCount)
882 {
883     uint8_t layerRangeBits = layerCount >= maxLayerCount ? static_cast<uint8_t>(~0u)
884                                                          : angle::BitMask<uint8_t>(layerCount);
885     layerRangeBits <<= layerStart;
886 
887     return layerRangeBits;
888 }
889 
GetImageLayerCountForView(const ImageHelper & image)890 uint32_t GetImageLayerCountForView(const ImageHelper &image)
891 {
892     // Depth > 1 means this is a 3D texture and depth is our layer count
893     return image.getExtents().depth > 1 ? image.getExtents().depth : image.getLayerCount();
894 }
895 
ReleaseImageViews(ImageViewVector * imageViewVector,GarbageObjects * garbage)896 void ReleaseImageViews(ImageViewVector *imageViewVector, GarbageObjects *garbage)
897 {
898     for (ImageView &imageView : *imageViewVector)
899     {
900         if (imageView.valid())
901         {
902             garbage->emplace_back(GetGarbage(&imageView));
903         }
904     }
905     imageViewVector->clear();
906 }
907 
DestroyImageViews(ImageViewVector * imageViewVector,VkDevice device)908 void DestroyImageViews(ImageViewVector *imageViewVector, VkDevice device)
909 {
910     for (ImageView &imageView : *imageViewVector)
911     {
912         imageView.destroy(device);
913     }
914     imageViewVector->clear();
915 }
916 
ReleaseLayerLevelImageViews(LayerLevelImageViewVector * imageViewVector,GarbageObjects * garbage)917 void ReleaseLayerLevelImageViews(LayerLevelImageViewVector *imageViewVector,
918                                  GarbageObjects *garbage)
919 {
920     for (ImageViewVector &layerViews : *imageViewVector)
921     {
922         for (ImageView &imageView : layerViews)
923         {
924             if (imageView.valid())
925             {
926                 garbage->emplace_back(GetGarbage(&imageView));
927             }
928         }
929     }
930     imageViewVector->clear();
931 }
932 
DestroyLayerLevelImageViews(LayerLevelImageViewVector * imageViewVector,VkDevice device)933 void DestroyLayerLevelImageViews(LayerLevelImageViewVector *imageViewVector, VkDevice device)
934 {
935     for (ImageViewVector &layerViews : *imageViewVector)
936     {
937         for (ImageView &imageView : layerViews)
938         {
939             imageView.destroy(device);
940         }
941     }
942     imageViewVector->clear();
943 }
944 
ReleaseSubresourceImageViews(SubresourceImageViewMap * imageViews,GarbageObjects * garbage)945 void ReleaseSubresourceImageViews(SubresourceImageViewMap *imageViews, GarbageObjects *garbage)
946 {
947     for (auto &iter : *imageViews)
948     {
949         std::unique_ptr<ImageView> &imageView = iter.second;
950         if (imageView->valid())
951         {
952             garbage->emplace_back(GetGarbage(imageView.get()));
953         }
954     }
955     imageViews->clear();
956 }
957 
DestroySubresourceImageViews(SubresourceImageViewMap * imageViews,VkDevice device)958 void DestroySubresourceImageViews(SubresourceImageViewMap *imageViews, VkDevice device)
959 {
960     for (auto &iter : *imageViews)
961     {
962         std::unique_ptr<ImageView> &imageView = iter.second;
963         imageView->destroy(device);
964     }
965     imageViews->clear();
966 }
967 
GetLevelImageView(ImageViewVector * imageViews,LevelIndex levelVk,uint32_t levelCount)968 ImageView *GetLevelImageView(ImageViewVector *imageViews, LevelIndex levelVk, uint32_t levelCount)
969 {
970     // Lazily allocate the storage for image views. We allocate the full level count because we
971     // don't want to trigger any std::vector reallocations. Reallocations could invalidate our
972     // view pointers.
973     if (imageViews->empty())
974     {
975         imageViews->resize(levelCount);
976     }
977     ASSERT(imageViews->size() > levelVk.get());
978 
979     return &(*imageViews)[levelVk.get()];
980 }
981 
GetLevelLayerImageView(LayerLevelImageViewVector * imageViews,LevelIndex levelVk,uint32_t layer,uint32_t levelCount,uint32_t layerCount)982 ImageView *GetLevelLayerImageView(LayerLevelImageViewVector *imageViews,
983                                   LevelIndex levelVk,
984                                   uint32_t layer,
985                                   uint32_t levelCount,
986                                   uint32_t layerCount)
987 {
988     // Lazily allocate the storage for image views. We allocate the full layer count because we
989     // don't want to trigger any std::vector reallocations. Reallocations could invalidate our
990     // view pointers.
991     if (imageViews->empty())
992     {
993         imageViews->resize(layerCount);
994     }
995     ASSERT(imageViews->size() > layer);
996 
997     return GetLevelImageView(&(*imageViews)[layer], levelVk, levelCount);
998 }
999 
1000 // Special rules apply to VkBufferImageCopy with depth/stencil. The components are tightly packed
1001 // into a depth or stencil section of the destination buffer. See the spec:
1002 // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkBufferImageCopy.html
GetDepthStencilImageToBufferFormat(const angle::Format & imageFormat,VkImageAspectFlagBits copyAspect)1003 const angle::Format &GetDepthStencilImageToBufferFormat(const angle::Format &imageFormat,
1004                                                         VkImageAspectFlagBits copyAspect)
1005 {
1006     if (copyAspect == VK_IMAGE_ASPECT_STENCIL_BIT)
1007     {
1008         ASSERT(imageFormat.id == angle::FormatID::D24_UNORM_S8_UINT ||
1009                imageFormat.id == angle::FormatID::D32_FLOAT_S8X24_UINT ||
1010                imageFormat.id == angle::FormatID::S8_UINT);
1011         return angle::Format::Get(angle::FormatID::S8_UINT);
1012     }
1013 
1014     ASSERT(copyAspect == VK_IMAGE_ASPECT_DEPTH_BIT);
1015 
1016     switch (imageFormat.id)
1017     {
1018         case angle::FormatID::D16_UNORM:
1019             return imageFormat;
1020         case angle::FormatID::D24_UNORM_X8_UINT:
1021             return imageFormat;
1022         case angle::FormatID::D24_UNORM_S8_UINT:
1023             return angle::Format::Get(angle::FormatID::D24_UNORM_X8_UINT);
1024         case angle::FormatID::D32_FLOAT:
1025             return imageFormat;
1026         case angle::FormatID::D32_FLOAT_S8X24_UINT:
1027             return angle::Format::Get(angle::FormatID::D32_FLOAT);
1028         default:
1029             UNREACHABLE();
1030             return imageFormat;
1031     }
1032 }
1033 
GetRobustResourceClearValue(const angle::Format & intendedFormat,const angle::Format & actualFormat)1034 VkClearValue GetRobustResourceClearValue(const angle::Format &intendedFormat,
1035                                          const angle::Format &actualFormat)
1036 {
1037     VkClearValue clearValue = {};
1038     if (intendedFormat.hasDepthOrStencilBits())
1039     {
1040         clearValue.depthStencil = kRobustInitDepthStencilValue;
1041     }
1042     else
1043     {
1044         clearValue.color = HasEmulatedImageChannels(intendedFormat, actualFormat)
1045                                ? kEmulatedInitColorValue
1046                                : kRobustInitColorValue;
1047     }
1048     return clearValue;
1049 }
1050 
IsShaderReadOnlyLayout(const ImageMemoryBarrierData & imageLayout)1051 bool IsShaderReadOnlyLayout(const ImageMemoryBarrierData &imageLayout)
1052 {
1053     // We also use VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL for texture sample from depth
1054     // texture. See GetImageReadLayout() for detail.
1055     return imageLayout.layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ||
1056            imageLayout.layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
1057 }
1058 
IsAnySubresourceContentDefined(const gl::TexLevelArray<angle::BitSet8<8>> & contentDefined)1059 bool IsAnySubresourceContentDefined(const gl::TexLevelArray<angle::BitSet8<8>> &contentDefined)
1060 {
1061     for (const angle::BitSet8<8> &levelContentDefined : contentDefined)
1062     {
1063         if (levelContentDefined.any())
1064         {
1065             return true;
1066         }
1067     }
1068     return false;
1069 }
1070 
ExtendRenderPassInvalidateArea(const gl::Rectangle & invalidateArea,gl::Rectangle * out)1071 void ExtendRenderPassInvalidateArea(const gl::Rectangle &invalidateArea, gl::Rectangle *out)
1072 {
1073     if (out->empty())
1074     {
1075         *out = invalidateArea;
1076     }
1077     else
1078     {
1079         gl::ExtendRectangle(*out, invalidateArea, out);
1080     }
1081 }
1082 
CanCopyWithTransferForCopyImage(Renderer * renderer,ImageHelper * srcImage,ImageHelper * dstImage)1083 bool CanCopyWithTransferForCopyImage(Renderer *renderer,
1084                                      ImageHelper *srcImage,
1085                                      ImageHelper *dstImage)
1086 {
1087     // Neither source nor destination formats can be emulated for copy image through transfer,
1088     // unless they are emulated with the same format!
1089     bool isFormatCompatible =
1090         (!srcImage->hasEmulatedImageFormat() && !dstImage->hasEmulatedImageFormat()) ||
1091         srcImage->getActualFormatID() == dstImage->getActualFormatID();
1092 
1093     // If neither formats are emulated, GL validation ensures that pixelBytes is the same for both.
1094     ASSERT(!isFormatCompatible ||
1095            srcImage->getActualFormat().pixelBytes == dstImage->getActualFormat().pixelBytes);
1096 
1097     return isFormatCompatible &&
1098            CanCopyWithTransfer(renderer, srcImage->getUsage(), dstImage->getActualFormatID(),
1099                                dstImage->getTilingMode());
1100 }
1101 
ReleaseBufferListToRenderer(Context * context,BufferHelperQueue * buffers)1102 void ReleaseBufferListToRenderer(Context *context, BufferHelperQueue *buffers)
1103 {
1104     for (std::unique_ptr<BufferHelper> &toFree : *buffers)
1105     {
1106         toFree->release(context);
1107     }
1108     buffers->clear();
1109 }
1110 
DestroyBufferList(Renderer * renderer,BufferHelperQueue * buffers)1111 void DestroyBufferList(Renderer *renderer, BufferHelperQueue *buffers)
1112 {
1113     for (std::unique_ptr<BufferHelper> &toDestroy : *buffers)
1114     {
1115         toDestroy->destroy(renderer);
1116     }
1117     buffers->clear();
1118 }
1119 
1120 // Helper functions used below
GetLoadOpShorthand(RenderPassLoadOp loadOp)1121 char GetLoadOpShorthand(RenderPassLoadOp loadOp)
1122 {
1123     switch (loadOp)
1124     {
1125         case RenderPassLoadOp::Clear:
1126             return 'C';
1127         case RenderPassLoadOp::Load:
1128             return 'L';
1129         case RenderPassLoadOp::None:
1130             return 'N';
1131         default:
1132             return 'D';
1133     }
1134 }
1135 
GetStoreOpShorthand(RenderPassStoreOp storeOp)1136 char GetStoreOpShorthand(RenderPassStoreOp storeOp)
1137 {
1138     switch (storeOp)
1139     {
1140         case RenderPassStoreOp::Store:
1141             return 'S';
1142         case RenderPassStoreOp::None:
1143             return 'N';
1144         default:
1145             return 'D';
1146     }
1147 }
1148 
IsClear(UpdateSource updateSource)1149 bool IsClear(UpdateSource updateSource)
1150 {
1151     return updateSource == UpdateSource::Clear ||
1152            updateSource == UpdateSource::ClearEmulatedChannelsOnly ||
1153            updateSource == UpdateSource::ClearAfterInvalidate;
1154 }
1155 
IsClearOfAllChannels(UpdateSource updateSource)1156 bool IsClearOfAllChannels(UpdateSource updateSource)
1157 {
1158     return updateSource == UpdateSource::Clear ||
1159            updateSource == UpdateSource::ClearAfterInvalidate;
1160 }
1161 
InitDynamicDescriptorPool(ErrorContext * context,const DescriptorSetLayoutDesc & descriptorSetLayoutDesc,const DescriptorSetLayout & descriptorSetLayout,uint32_t descriptorCountMultiplier,DynamicDescriptorPool * poolToInit)1162 angle::Result InitDynamicDescriptorPool(ErrorContext *context,
1163                                         const DescriptorSetLayoutDesc &descriptorSetLayoutDesc,
1164                                         const DescriptorSetLayout &descriptorSetLayout,
1165                                         uint32_t descriptorCountMultiplier,
1166                                         DynamicDescriptorPool *poolToInit)
1167 {
1168     std::vector<VkDescriptorPoolSize> descriptorPoolSizes;
1169     DescriptorSetLayoutBindingVector bindingVector;
1170     descriptorSetLayoutDesc.unpackBindings(&bindingVector);
1171     descriptorPoolSizes.reserve(bindingVector.size());
1172 
1173     for (const VkDescriptorSetLayoutBinding &binding : bindingVector)
1174     {
1175         if (binding.descriptorCount > 0)
1176         {
1177             VkDescriptorPoolSize poolSize = {};
1178             poolSize.type                 = binding.descriptorType;
1179             poolSize.descriptorCount      = binding.descriptorCount * descriptorCountMultiplier;
1180             descriptorPoolSizes.emplace_back(poolSize);
1181         }
1182     }
1183 
1184     if (!descriptorPoolSizes.empty())
1185     {
1186         ANGLE_TRY(poolToInit->init(context, descriptorPoolSizes.data(), descriptorPoolSizes.size(),
1187                                    descriptorSetLayout));
1188     }
1189 
1190     return angle::Result::Continue;
1191 }
1192 
CheckSubpassCommandBufferCount(uint32_t count)1193 bool CheckSubpassCommandBufferCount(uint32_t count)
1194 {
1195     // When using angle::SharedRingBufferAllocator we must ensure that allocator is attached and
1196     // detached from the same priv::SecondaryCommandBuffer instance.
1197     // Custom command buffer (priv::SecondaryCommandBuffer) may contain commands for multiple
1198     // subpasses, therefore we do not need multiple buffers.
1199     return (count == 1 || !RenderPassCommandBuffer::ExecutesInline());
1200 }
1201 
IsAnyLayout(VkImageLayout needle,const VkImageLayout * haystack,uint32_t haystackCount)1202 bool IsAnyLayout(VkImageLayout needle, const VkImageLayout *haystack, uint32_t haystackCount)
1203 {
1204     const VkImageLayout *haystackEnd = haystack + haystackCount;
1205     return std::find(haystack, haystackEnd, needle) != haystackEnd;
1206 }
1207 
AggregateSkipLevels(const gl::CubeFaceArray<gl::TexLevelMask> & skipLevels)1208 gl::TexLevelMask AggregateSkipLevels(const gl::CubeFaceArray<gl::TexLevelMask> &skipLevels)
1209 {
1210     gl::TexLevelMask skipLevelsAllFaces = skipLevels[0];
1211     for (size_t face = 1; face < gl::kCubeFaceCount; ++face)
1212     {
1213         skipLevelsAllFaces |= skipLevels[face];
1214     }
1215     return skipLevelsAllFaces;
1216 }
1217 
1218 // Get layer mask for a particular image level.
GetImageLayerWriteMask(uint32_t layerStart,uint32_t layerCount)1219 ImageLayerWriteMask GetImageLayerWriteMask(uint32_t layerStart, uint32_t layerCount)
1220 {
1221     ImageLayerWriteMask layerMask = angle::BitMask<uint64_t>(layerCount);
1222     uint32_t rotateShift          = layerStart % kMaxParallelLayerWrites;
1223     layerMask = (layerMask << rotateShift) | (layerMask >> (kMaxParallelLayerWrites - rotateShift));
1224     return layerMask;
1225 }
1226 
MakeImageSubresourceReadRange(gl::LevelIndex level,uint32_t levelCount,uint32_t layer,LayerMode layerMode,ImageViewColorspace readColorspace,ImageViewColorspace writeColorspace)1227 ImageSubresourceRange MakeImageSubresourceReadRange(gl::LevelIndex level,
1228                                                     uint32_t levelCount,
1229                                                     uint32_t layer,
1230                                                     LayerMode layerMode,
1231                                                     ImageViewColorspace readColorspace,
1232                                                     ImageViewColorspace writeColorspace)
1233 {
1234     ImageSubresourceRange range;
1235 
1236     SetBitField(range.level, level.get());
1237     SetBitField(range.levelCount, levelCount);
1238     SetBitField(range.layer, layer);
1239     SetBitField(range.layerMode, layerMode);
1240     SetBitField(range.readColorspace, readColorspace == ImageViewColorspace::SRGB ? 1 : 0);
1241     SetBitField(range.writeColorspace, writeColorspace == ImageViewColorspace::SRGB ? 1 : 0);
1242 
1243     return range;
1244 }
1245 
MakeImageSubresourceDrawRange(gl::LevelIndex level,uint32_t layer,LayerMode layerMode,ImageViewColorspace readColorspace,ImageViewColorspace writeColorspace)1246 ImageSubresourceRange MakeImageSubresourceDrawRange(gl::LevelIndex level,
1247                                                     uint32_t layer,
1248                                                     LayerMode layerMode,
1249                                                     ImageViewColorspace readColorspace,
1250                                                     ImageViewColorspace writeColorspace)
1251 {
1252     ImageSubresourceRange range;
1253 
1254     SetBitField(range.level, level.get());
1255     SetBitField(range.levelCount, 1);
1256     SetBitField(range.layer, layer);
1257     SetBitField(range.layerMode, layerMode);
1258     SetBitField(range.readColorspace, readColorspace == ImageViewColorspace::SRGB ? 1 : 0);
1259     SetBitField(range.writeColorspace, writeColorspace == ImageViewColorspace::SRGB ? 1 : 0);
1260 
1261     return range;
1262 }
1263 
1264 // Obtain VkClearColorValue from input byte data and actual format.
GetVkClearColorValueFromBytes(uint8_t * actualData,const angle::Format & actualFormat,VkClearValue * clearValueOut)1265 void GetVkClearColorValueFromBytes(uint8_t *actualData,
1266                                    const angle::Format &actualFormat,
1267                                    VkClearValue *clearValueOut)
1268 {
1269     ASSERT(actualData != nullptr && !actualFormat.hasDepthOrStencilBits());
1270 
1271     *clearValueOut               = {};
1272     VkClearColorValue colorValue = {{}};
1273     actualFormat.pixelReadFunction(actualData, reinterpret_cast<uint8_t *>(&colorValue));
1274     clearValueOut->color = colorValue;
1275 }
1276 
1277 // Obtain VkClearDepthStencilValue from input byte data and intended format.
GetVkClearDepthStencilValueFromBytes(uint8_t * intendedData,const angle::Format & intendedFormat,VkClearValue * clearValueOut)1278 void GetVkClearDepthStencilValueFromBytes(uint8_t *intendedData,
1279                                           const angle::Format &intendedFormat,
1280                                           VkClearValue *clearValueOut)
1281 {
1282     ASSERT(intendedData != nullptr && intendedFormat.hasDepthOrStencilBits());
1283 
1284     *clearValueOut     = {};
1285     uint32_t dsData[4] = {0};
1286     double depthValue  = 0;
1287 
1288     intendedFormat.pixelReadFunction(intendedData, reinterpret_cast<uint8_t *>(dsData));
1289     memcpy(&depthValue, &dsData[0], sizeof(double));
1290     clearValueOut->depthStencil.depth   = static_cast<float>(depthValue);
1291     clearValueOut->depthStencil.stencil = dsData[2];
1292 }
1293 
ConvertShaderBitSetToVkPipelineStageFlags(const gl::ShaderBitSet & writeShaderStages)1294 VkPipelineStageFlags ConvertShaderBitSetToVkPipelineStageFlags(
1295     const gl::ShaderBitSet &writeShaderStages)
1296 {
1297     VkPipelineStageFlags pipelineStageFlags = 0;
1298     for (gl::ShaderType shaderType : writeShaderStages)
1299     {
1300         const PipelineStage stage = GetPipelineStage(shaderType);
1301         pipelineStageFlags |= kBufferMemoryBarrierData[stage].pipelineStageFlags;
1302     }
1303     return pipelineStageFlags;
1304 }
1305 }  // anonymous namespace
1306 
1307 // This is an arbitrary max. We can change this later if necessary.
1308 uint32_t DynamicDescriptorPool::mMaxSetsPerPool           = 16;
1309 uint32_t DynamicDescriptorPool::mMaxSetsPerPoolMultiplier = 2;
1310 
GetImageLayoutFromGLImageLayout(ErrorContext * context,GLenum layout)1311 ImageLayout GetImageLayoutFromGLImageLayout(ErrorContext *context, GLenum layout)
1312 {
1313     switch (layout)
1314     {
1315         case GL_NONE:
1316             return ImageLayout::Undefined;
1317         case GL_LAYOUT_GENERAL_EXT:
1318             return ImageLayout::ExternalShadersWrite;
1319         case GL_LAYOUT_COLOR_ATTACHMENT_EXT:
1320             return ImageLayout::ColorWrite;
1321         case GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT:
1322             return ImageLayout::DepthWriteStencilWrite;
1323         case GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT:
1324             return ImageLayout::DepthReadStencilRead;
1325         case GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT:
1326             return ImageLayout::DepthReadStencilWrite;
1327         case GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT:
1328             return ImageLayout::DepthWriteStencilRead;
1329         case GL_LAYOUT_SHADER_READ_ONLY_EXT:
1330             return ImageLayout::ExternalShadersReadOnly;
1331         case GL_LAYOUT_TRANSFER_SRC_EXT:
1332             return ImageLayout::TransferSrc;
1333         case GL_LAYOUT_TRANSFER_DST_EXT:
1334             return ImageLayout::TransferDst;
1335         default:
1336             UNREACHABLE();
1337             return vk::ImageLayout::Undefined;
1338     }
1339 }
1340 
ConvertImageLayoutToGLImageLayout(ImageLayout layout)1341 GLenum ConvertImageLayoutToGLImageLayout(ImageLayout layout)
1342 {
1343     switch (kImageMemoryBarrierData[layout].layout)
1344     {
1345         case VK_IMAGE_LAYOUT_UNDEFINED:
1346             return GL_NONE;
1347         case VK_IMAGE_LAYOUT_GENERAL:
1348             return GL_LAYOUT_GENERAL_EXT;
1349         case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
1350             return GL_LAYOUT_COLOR_ATTACHMENT_EXT;
1351         case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
1352             return GL_LAYOUT_DEPTH_STENCIL_ATTACHMENT_EXT;
1353         case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
1354             return GL_LAYOUT_DEPTH_STENCIL_READ_ONLY_EXT;
1355         case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
1356             return GL_LAYOUT_SHADER_READ_ONLY_EXT;
1357         case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
1358             return GL_LAYOUT_TRANSFER_SRC_EXT;
1359         case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
1360             return GL_LAYOUT_TRANSFER_DST_EXT;
1361         case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL:
1362             return GL_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_EXT;
1363         case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL:
1364             return GL_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_EXT;
1365         default:
1366             break;
1367     }
1368     UNREACHABLE();
1369     return GL_NONE;
1370 }
1371 
ConvertImageLayoutToVkImageLayout(ImageLayout imageLayout)1372 VkImageLayout ConvertImageLayoutToVkImageLayout(ImageLayout imageLayout)
1373 {
1374     return kImageMemoryBarrierData[imageLayout].layout;
1375 }
1376 
GetPipelineStageGroupFromStageFlags(VkPipelineStageFlags dstStageMask)1377 PipelineStageGroup GetPipelineStageGroupFromStageFlags(VkPipelineStageFlags dstStageMask)
1378 {
1379     if ((dstStageMask & ~kFragmentAndAttachmentPipelineStageFlags) == 0)
1380     {
1381         return PipelineStageGroup::FragmentOnly;
1382     }
1383     else if (dstStageMask == VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT)
1384     {
1385         return PipelineStageGroup::ComputeOnly;
1386     }
1387     else if ((dstStageMask & ~kPreFragmentStageFlags) == 0)
1388     {
1389         return PipelineStageGroup::PreFragmentOnly;
1390     }
1391     return PipelineStageGroup::Other;
1392 }
1393 
InitializeImageLayoutAndMemoryBarrierDataMap(ImageLayoutToMemoryBarrierDataMap * map,VkPipelineStageFlags supportedVulkanPipelineStageMask)1394 void InitializeImageLayoutAndMemoryBarrierDataMap(
1395     ImageLayoutToMemoryBarrierDataMap *map,
1396     VkPipelineStageFlags supportedVulkanPipelineStageMask)
1397 {
1398     *map = kImageMemoryBarrierData;
1399     for (ImageMemoryBarrierData &barrierData : *map)
1400     {
1401         barrierData.srcStageMask &= supportedVulkanPipelineStageMask;
1402         barrierData.dstStageMask &= supportedVulkanPipelineStageMask;
1403         ASSERT(barrierData.pipelineStageGroup ==
1404                GetPipelineStageGroupFromStageFlags(barrierData.dstStageMask));
1405     }
1406 }
1407 
FormatHasNecessaryFeature(Renderer * renderer,angle::FormatID formatID,VkImageTiling tilingMode,VkFormatFeatureFlags featureBits)1408 bool FormatHasNecessaryFeature(Renderer *renderer,
1409                                angle::FormatID formatID,
1410                                VkImageTiling tilingMode,
1411                                VkFormatFeatureFlags featureBits)
1412 {
1413     return (tilingMode == VK_IMAGE_TILING_OPTIMAL)
1414                ? renderer->hasImageFormatFeatureBits(formatID, featureBits)
1415                : renderer->hasLinearImageFormatFeatureBits(formatID, featureBits);
1416 }
1417 
CanCopyWithTransfer(Renderer * renderer,VkImageUsageFlags srcUsage,angle::FormatID dstFormatID,VkImageTiling dstTilingMode)1418 bool CanCopyWithTransfer(Renderer *renderer,
1419                          VkImageUsageFlags srcUsage,
1420                          angle::FormatID dstFormatID,
1421                          VkImageTiling dstTilingMode)
1422 {
1423     // Checks that the formats in the copy transfer have the appropriate transfer bits
1424     bool srcFormatHasNecessaryFeature = (srcUsage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) != 0;
1425     bool dstFormatHasNecessaryFeature = FormatHasNecessaryFeature(
1426         renderer, dstFormatID, dstTilingMode, VK_FORMAT_FEATURE_TRANSFER_DST_BIT);
1427 
1428     return srcFormatHasNecessaryFeature && dstFormatHasNecessaryFeature;
1429 }
1430 
InitializeEventStageToVkPipelineStageFlagsMap(EventStageToVkPipelineStageFlagsMap * map,VkPipelineStageFlags supportedVulkanPipelineStageMask)1431 void InitializeEventStageToVkPipelineStageFlagsMap(
1432     EventStageToVkPipelineStageFlagsMap *map,
1433     VkPipelineStageFlags supportedVulkanPipelineStageMask)
1434 {
1435     map->fill(0);
1436 
1437     for (const BufferMemoryBarrierData &bufferBarrierData : kBufferMemoryBarrierData)
1438     {
1439         const EventStage eventStage = bufferBarrierData.eventStage;
1440         if (eventStage != EventStage::InvalidEnum)
1441         {
1442             (*map)[eventStage] |=
1443                 bufferBarrierData.pipelineStageFlags & supportedVulkanPipelineStageMask;
1444         }
1445     }
1446 
1447     for (const ImageMemoryBarrierData &imageBarrierData : kImageMemoryBarrierData)
1448     {
1449         const EventStage eventStage = imageBarrierData.eventStage;
1450         if (eventStage != EventStage::InvalidEnum)
1451         {
1452             (*map)[eventStage] |= imageBarrierData.dstStageMask & supportedVulkanPipelineStageMask;
1453         }
1454     }
1455 }
1456 
1457 // Context implementation
Context(Renderer * renderer)1458 Context::Context(Renderer *renderer)
1459     : ErrorContext(renderer), mShareGroupRefCountedEventsGarbageRecycler(nullptr)
1460 {}
1461 
~Context()1462 Context::~Context()
1463 {
1464     ASSERT(mForeignImagesInUse.empty());
1465 }
1466 
onForeignImageUse(ImageHelper * image)1467 void Context::onForeignImageUse(ImageHelper *image)
1468 {
1469     // The image might be used multiple times in the same frame, |mForeignImagesInUse| is a "set"
1470     // so the image is tracked only once.
1471     mForeignImagesInUse.insert(image);
1472 }
1473 
finalizeForeignImage(ImageHelper * image)1474 void Context::finalizeForeignImage(ImageHelper *image)
1475 {
1476     // The image must have been marked as in use, otherwise finalize is called while the initial use
1477     // was missed.
1478     ASSERT(mForeignImagesInUse.find(image) != mForeignImagesInUse.end());
1479     // The image must not already be finalized.
1480     ASSERT(
1481         std::find_if(mImagesToTransitionToForeign.begin(), mImagesToTransitionToForeign.end(),
1482                      [image = image->getImage().getHandle()](const VkImageMemoryBarrier &barrier) {
1483                          return barrier.image == image;
1484                      }) == mImagesToTransitionToForeign.end());
1485 
1486     mImagesToTransitionToForeign.push_back(image->releaseToForeign(mRenderer));
1487     mForeignImagesInUse.erase(image);
1488 }
1489 
finalizeAllForeignImages()1490 void Context::finalizeAllForeignImages()
1491 {
1492     mImagesToTransitionToForeign.reserve(mImagesToTransitionToForeign.size() +
1493                                          mForeignImagesInUse.size());
1494     while (!mForeignImagesInUse.empty())
1495     {
1496         finalizeForeignImage(*mForeignImagesInUse.begin());
1497     }
1498 }
1499 
1500 // PackedClearValuesArray implementation
PackedClearValuesArray()1501 PackedClearValuesArray::PackedClearValuesArray() : mValues{} {}
1502 PackedClearValuesArray::~PackedClearValuesArray() = default;
1503 
1504 PackedClearValuesArray::PackedClearValuesArray(const PackedClearValuesArray &other) = default;
1505 PackedClearValuesArray &PackedClearValuesArray::operator=(const PackedClearValuesArray &rhs) =
1506     default;
1507 
storeColor(PackedAttachmentIndex index,const VkClearValue & clearValue)1508 void PackedClearValuesArray::storeColor(PackedAttachmentIndex index, const VkClearValue &clearValue)
1509 {
1510     mValues[index.get()] = clearValue;
1511 }
1512 
storeDepthStencil(PackedAttachmentIndex index,const VkClearValue & clearValue)1513 void PackedClearValuesArray::storeDepthStencil(PackedAttachmentIndex index,
1514                                                const VkClearValue &clearValue)
1515 {
1516     mValues[index.get()] = clearValue;
1517 }
1518 
1519 // RenderPassAttachment implementation
RenderPassAttachment()1520 RenderPassAttachment::RenderPassAttachment()
1521 {
1522     reset();
1523 }
1524 
init(ImageHelper * image,UniqueSerial imageSiblingSerial,gl::LevelIndex levelIndex,uint32_t layerIndex,uint32_t layerCount,VkImageAspectFlagBits aspect)1525 void RenderPassAttachment::init(ImageHelper *image,
1526                                 UniqueSerial imageSiblingSerial,
1527                                 gl::LevelIndex levelIndex,
1528                                 uint32_t layerIndex,
1529                                 uint32_t layerCount,
1530                                 VkImageAspectFlagBits aspect)
1531 {
1532     ASSERT(mImage == nullptr);
1533 
1534     mImage              = image;
1535     mImageSiblingSerial = imageSiblingSerial;
1536     mLevelIndex         = levelIndex;
1537     mLayerIndex         = layerIndex;
1538     mLayerCount         = layerCount;
1539     mAspect             = aspect;
1540 
1541     mImage->setRenderPassUsageFlag(RenderPassUsage::RenderTargetAttachment);
1542 }
1543 
reset()1544 void RenderPassAttachment::reset()
1545 {
1546     mImage = nullptr;
1547 
1548     mAccess = ResourceAccess::Unused;
1549 
1550     mInvalidatedCmdCount = kInfiniteCmdCount;
1551     mDisabledCmdCount    = kInfiniteCmdCount;
1552     mInvalidateArea      = gl::Rectangle();
1553 }
1554 
onAccess(ResourceAccess access,uint32_t currentCmdCount)1555 void RenderPassAttachment::onAccess(ResourceAccess access, uint32_t currentCmdCount)
1556 {
1557     // Update the access for optimizing this render pass's loadOp
1558     UpdateAccess(&mAccess, access);
1559 
1560     // Update the invalidate state for optimizing this render pass's storeOp
1561     if (onAccessImpl(access, currentCmdCount))
1562     {
1563         // The attachment is no longer invalid, so restore its content.
1564         restoreContent();
1565     }
1566 }
1567 
invalidate(const gl::Rectangle & invalidateArea,bool isAttachmentEnabled,uint32_t currentCmdCount)1568 void RenderPassAttachment::invalidate(const gl::Rectangle &invalidateArea,
1569                                       bool isAttachmentEnabled,
1570                                       uint32_t currentCmdCount)
1571 {
1572     // Keep track of the command count in the render pass at the time of invalidation.  If there are
1573     // more commands in the future, invalidate must be undone.
1574     mInvalidatedCmdCount = currentCmdCount;
1575 
1576     // Also track the command count if the attachment is currently disabled.
1577     mDisabledCmdCount = isAttachmentEnabled ? kInfiniteCmdCount : currentCmdCount;
1578 
1579     // Set/extend the invalidate area.
1580     ExtendRenderPassInvalidateArea(invalidateArea, &mInvalidateArea);
1581 }
1582 
onRenderAreaGrowth(ContextVk * contextVk,const gl::Rectangle & newRenderArea)1583 void RenderPassAttachment::onRenderAreaGrowth(ContextVk *contextVk,
1584                                               const gl::Rectangle &newRenderArea)
1585 {
1586     // Remove invalidate if it's no longer applicable.
1587     if (mInvalidateArea.empty() || mInvalidateArea.encloses(newRenderArea))
1588     {
1589         return;
1590     }
1591 
1592     ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_LOW,
1593                           "InvalidateSubFramebuffer discarded due to increased scissor region");
1594 
1595     mInvalidateArea      = gl::Rectangle();
1596     mInvalidatedCmdCount = kInfiniteCmdCount;
1597 }
1598 
finalizeLoadStore(ErrorContext * context,uint32_t currentCmdCount,bool hasUnresolveAttachment,bool hasResolveAttachment,RenderPassLoadOp * loadOp,RenderPassStoreOp * storeOp,bool * isInvalidatedOut)1599 void RenderPassAttachment::finalizeLoadStore(ErrorContext *context,
1600                                              uint32_t currentCmdCount,
1601                                              bool hasUnresolveAttachment,
1602                                              bool hasResolveAttachment,
1603                                              RenderPassLoadOp *loadOp,
1604                                              RenderPassStoreOp *storeOp,
1605                                              bool *isInvalidatedOut)
1606 {
1607     if (mAspect != VK_IMAGE_ASPECT_COLOR_BIT)
1608     {
1609         const RenderPassUsage readOnlyAttachmentUsage =
1610             mAspect == VK_IMAGE_ASPECT_STENCIL_BIT ? RenderPassUsage::StencilReadOnlyAttachment
1611                                                    : RenderPassUsage::DepthReadOnlyAttachment;
1612         // Ensure we don't write to a read-only attachment. (ReadOnly -> !Write)
1613         ASSERT(!mImage->hasRenderPassUsageFlag(readOnlyAttachmentUsage) ||
1614                !HasResourceWriteAccess(mAccess));
1615     }
1616 
1617     // If the attachment is invalidated, skip the store op.  If we are not loading or clearing the
1618     // attachment and the attachment has not been used, auto-invalidate it.
1619     const bool notLoaded = *loadOp == RenderPassLoadOp::DontCare && !hasUnresolveAttachment;
1620     if (isInvalidated(currentCmdCount) || (notLoaded && !HasResourceWriteAccess(mAccess)))
1621     {
1622         *storeOp          = RenderPassStoreOp::DontCare;
1623         *isInvalidatedOut = true;
1624     }
1625     else if (hasWriteAfterInvalidate(currentCmdCount))
1626     {
1627         // The attachment was invalidated, but is now valid.  Let the image know the contents are
1628         // now defined so a future render pass would use loadOp=LOAD.
1629         restoreContent();
1630     }
1631 
1632     // For read only depth stencil, we can use StoreOpNone if available.  DontCare is still
1633     // preferred, so do this after handling DontCare.
1634     const bool supportsLoadStoreOpNone =
1635         context->getFeatures().supportsRenderPassLoadStoreOpNone.enabled;
1636     const bool supportsStoreOpNone =
1637         supportsLoadStoreOpNone || context->getFeatures().supportsRenderPassStoreOpNone.enabled;
1638     if (mAccess == ResourceAccess::ReadOnly && supportsStoreOpNone)
1639     {
1640         if (*storeOp == RenderPassStoreOp::Store && *loadOp != RenderPassLoadOp::Clear)
1641         {
1642             *storeOp = RenderPassStoreOp::None;
1643         }
1644     }
1645 
1646     if (mAccess == ResourceAccess::Unused)
1647     {
1648         if (*storeOp != RenderPassStoreOp::DontCare)
1649         {
1650             switch (*loadOp)
1651             {
1652                 case RenderPassLoadOp::Clear:
1653                     // Cannot optimize away the ops if the attachment is cleared (even if not used
1654                     // afterwards)
1655                     break;
1656                 case RenderPassLoadOp::Load:
1657                     // Make sure the attachment is neither loaded nor stored (as it's neither used
1658                     // nor invalidated), if possible.
1659                     if (supportsLoadStoreOpNone)
1660                     {
1661                         *loadOp = RenderPassLoadOp::None;
1662                     }
1663                     if (supportsStoreOpNone)
1664                     {
1665                         *storeOp = RenderPassStoreOp::None;
1666                     }
1667                     break;
1668                 case RenderPassLoadOp::DontCare:
1669                     // loadOp=DontCare should be covered by storeOp=DontCare below.
1670                     break;
1671                 case RenderPassLoadOp::None:
1672                 default:
1673                     // loadOp=None is never decided upfront.
1674                     UNREACHABLE();
1675                     break;
1676             }
1677         }
1678     }
1679 
1680     if (mAccess == ResourceAccess::Unused || (mAccess == ResourceAccess::ReadOnly && notLoaded))
1681     {
1682         // If we are loading or clearing the attachment, but the attachment has not been used,
1683         // and the data has also not been stored back into attachment, then just skip the
1684         // load/clear op. If loadOp/storeOp=None is supported, prefer that to reduce the amount
1685         // of synchronization; DontCare is a write operation, while None is not.
1686         //
1687         // Don't optimize away a Load or Clear if there is a resolve attachment. Although the
1688         // storeOp=DontCare the image content needs to be resolved into the resolve attachment.
1689         const bool attachmentNeedsToBeResolved =
1690             hasResolveAttachment &&
1691             (*loadOp == RenderPassLoadOp::Load || *loadOp == RenderPassLoadOp::Clear);
1692         if (*storeOp == RenderPassStoreOp::DontCare && !attachmentNeedsToBeResolved)
1693         {
1694             if (supportsLoadStoreOpNone && !isInvalidated(currentCmdCount))
1695             {
1696                 *loadOp  = RenderPassLoadOp::None;
1697                 *storeOp = RenderPassStoreOp::None;
1698             }
1699             else
1700             {
1701                 *loadOp = RenderPassLoadOp::DontCare;
1702             }
1703         }
1704     }
1705 }
1706 
restoreContent()1707 void RenderPassAttachment::restoreContent()
1708 {
1709     // Note that the image may have been deleted since the render pass has started.
1710     if (mImage)
1711     {
1712         ASSERT(mImage->valid());
1713         if (mAspect == VK_IMAGE_ASPECT_STENCIL_BIT)
1714         {
1715             mImage->restoreSubresourceStencilContent(mLevelIndex, mLayerIndex, mLayerCount);
1716         }
1717         else
1718         {
1719             mImage->restoreSubresourceContent(mLevelIndex, mLayerIndex, mLayerCount);
1720         }
1721         mInvalidateArea = gl::Rectangle();
1722     }
1723 }
1724 
hasWriteAfterInvalidate(uint32_t currentCmdCount) const1725 bool RenderPassAttachment::hasWriteAfterInvalidate(uint32_t currentCmdCount) const
1726 {
1727     return (mInvalidatedCmdCount != kInfiniteCmdCount &&
1728             std::min(mDisabledCmdCount, currentCmdCount) != mInvalidatedCmdCount);
1729 }
1730 
isInvalidated(uint32_t currentCmdCount) const1731 bool RenderPassAttachment::isInvalidated(uint32_t currentCmdCount) const
1732 {
1733     return mInvalidatedCmdCount != kInfiniteCmdCount &&
1734            std::min(mDisabledCmdCount, currentCmdCount) == mInvalidatedCmdCount;
1735 }
1736 
onAccessImpl(ResourceAccess access,uint32_t currentCmdCount)1737 bool RenderPassAttachment::onAccessImpl(ResourceAccess access, uint32_t currentCmdCount)
1738 {
1739     if (mInvalidatedCmdCount == kInfiniteCmdCount)
1740     {
1741         // If never invalidated or no longer invalidated, return early.
1742         return false;
1743     }
1744     if (HasResourceWriteAccess(access))
1745     {
1746         // Drawing to this attachment is being enabled.  Assume that drawing will immediately occur
1747         // after this attachment is enabled, and that means that the attachment will no longer be
1748         // invalidated.
1749         mInvalidatedCmdCount = kInfiniteCmdCount;
1750         mDisabledCmdCount    = kInfiniteCmdCount;
1751         // Return true to indicate that the store op should remain STORE and that mContentDefined
1752         // should be set to true;
1753         return true;
1754     }
1755     // Drawing to this attachment is being disabled.
1756     if (hasWriteAfterInvalidate(currentCmdCount))
1757     {
1758         // The attachment was previously drawn while enabled, and so is no longer invalidated.
1759         mInvalidatedCmdCount = kInfiniteCmdCount;
1760         mDisabledCmdCount    = kInfiniteCmdCount;
1761         // Return true to indicate that the store op should remain STORE and that mContentDefined
1762         // should be set to true;
1763         return true;
1764     }
1765 
1766     // Use the latest CmdCount at the start of being disabled.  At the end of the render pass,
1767     // cmdCountDisabled is <= the actual command count, and so it's compared with
1768     // cmdCountInvalidated.  If the same, the attachment is still invalidated.
1769     mDisabledCmdCount = currentCmdCount;
1770     return false;
1771 }
1772 
1773 // CommandBufferHelperCommon implementation.
CommandBufferHelperCommon()1774 CommandBufferHelperCommon::CommandBufferHelperCommon()
1775     : mCommandPool(nullptr), mHasShaderStorageOutput(false), mHasGLMemoryBarrierIssued(false)
1776 {}
1777 
~CommandBufferHelperCommon()1778 CommandBufferHelperCommon::~CommandBufferHelperCommon() {}
1779 
initializeImpl()1780 void CommandBufferHelperCommon::initializeImpl()
1781 {
1782     mCommandAllocator.init();
1783 }
1784 
resetImpl(ErrorContext * context)1785 void CommandBufferHelperCommon::resetImpl(ErrorContext *context)
1786 {
1787     ASSERT(!mAcquireNextImageSemaphore.valid());
1788     mCommandAllocator.resetAllocator();
1789     ASSERT(!mIsAnyHostVisibleBufferWritten);
1790 
1791     ASSERT(mRefCountedEvents.empty());
1792     ASSERT(mRefCountedEventCollector.empty());
1793 }
1794 
1795 template <class DerivedT>
attachCommandPoolImpl(ErrorContext * context,SecondaryCommandPool * commandPool)1796 angle::Result CommandBufferHelperCommon::attachCommandPoolImpl(ErrorContext *context,
1797                                                                SecondaryCommandPool *commandPool)
1798 {
1799     if constexpr (!DerivedT::ExecutesInline())
1800     {
1801         DerivedT *derived = static_cast<DerivedT *>(this);
1802         ASSERT(commandPool != nullptr);
1803         ASSERT(mCommandPool == nullptr);
1804         ASSERT(!derived->getCommandBuffer().valid());
1805 
1806         mCommandPool = commandPool;
1807 
1808         ANGLE_TRY(derived->initializeCommandBuffer(context));
1809     }
1810     return angle::Result::Continue;
1811 }
1812 
1813 template <class DerivedT, bool kIsRenderPassBuffer>
detachCommandPoolImpl(ErrorContext * context,SecondaryCommandPool ** commandPoolOut)1814 angle::Result CommandBufferHelperCommon::detachCommandPoolImpl(
1815     ErrorContext *context,
1816     SecondaryCommandPool **commandPoolOut)
1817 {
1818     if constexpr (!DerivedT::ExecutesInline())
1819     {
1820         DerivedT *derived = static_cast<DerivedT *>(this);
1821         ASSERT(mCommandPool != nullptr);
1822         ASSERT(derived->getCommandBuffer().valid());
1823 
1824         if constexpr (!kIsRenderPassBuffer)
1825         {
1826             ASSERT(!derived->getCommandBuffer().empty());
1827             ANGLE_TRY(derived->endCommandBuffer(context));
1828         }
1829 
1830         *commandPoolOut = mCommandPool;
1831         mCommandPool    = nullptr;
1832     }
1833     ASSERT(mCommandPool == nullptr);
1834     return angle::Result::Continue;
1835 }
1836 
1837 template <class DerivedT>
releaseCommandPoolImpl()1838 void CommandBufferHelperCommon::releaseCommandPoolImpl()
1839 {
1840     if constexpr (!DerivedT::ExecutesInline())
1841     {
1842         DerivedT *derived = static_cast<DerivedT *>(this);
1843         ASSERT(mCommandPool != nullptr);
1844 
1845         if (derived->getCommandBuffer().valid())
1846         {
1847             ASSERT(derived->getCommandBuffer().empty());
1848             mCommandPool->collect(&derived->getCommandBuffer());
1849         }
1850 
1851         mCommandPool = nullptr;
1852     }
1853     ASSERT(mCommandPool == nullptr);
1854 }
1855 
1856 template <class DerivedT>
attachAllocatorImpl(SecondaryCommandMemoryAllocator * allocator)1857 void CommandBufferHelperCommon::attachAllocatorImpl(SecondaryCommandMemoryAllocator *allocator)
1858 {
1859     if constexpr (DerivedT::ExecutesInline())
1860     {
1861         auto &commandBuffer = static_cast<DerivedT *>(this)->getCommandBuffer();
1862         mCommandAllocator.attachAllocator(allocator);
1863         commandBuffer.attachAllocator(mCommandAllocator.getAllocator());
1864     }
1865 }
1866 
1867 template <class DerivedT>
detachAllocatorImpl()1868 SecondaryCommandMemoryAllocator *CommandBufferHelperCommon::detachAllocatorImpl()
1869 {
1870     SecondaryCommandMemoryAllocator *result = nullptr;
1871     if constexpr (DerivedT::ExecutesInline())
1872     {
1873         auto &commandBuffer = static_cast<DerivedT *>(this)->getCommandBuffer();
1874         commandBuffer.detachAllocator(mCommandAllocator.getAllocator());
1875         result = mCommandAllocator.detachAllocator(commandBuffer.empty());
1876     }
1877     return result;
1878 }
1879 
1880 template <class DerivedT>
assertCanBeRecycledImpl()1881 void CommandBufferHelperCommon::assertCanBeRecycledImpl()
1882 {
1883     DerivedT *derived = static_cast<DerivedT *>(this);
1884     ASSERT(mCommandPool == nullptr);
1885     ASSERT(!mCommandAllocator.hasAllocatorLinks());
1886     // Vulkan secondary command buffers must be invalid (collected).
1887     ASSERT(DerivedT::ExecutesInline() || !derived->getCommandBuffer().valid());
1888     // ANGLEs Custom secondary command buffers must be empty (reset).
1889     ASSERT(!DerivedT::ExecutesInline() || derived->getCommandBuffer().empty());
1890 }
1891 
bufferWrite(Context * context,VkAccessFlags writeAccessType,PipelineStage writeStage,BufferHelper * buffer)1892 void CommandBufferHelperCommon::bufferWrite(Context *context,
1893                                             VkAccessFlags writeAccessType,
1894                                             PipelineStage writeStage,
1895                                             BufferHelper *buffer)
1896 {
1897     VkPipelineStageFlags writePipelineStageFlags =
1898         kBufferMemoryBarrierData[writeStage].pipelineStageFlags;
1899     bufferWriteImpl(context, writeAccessType, writePipelineStageFlags, writeStage, buffer);
1900 }
1901 
bufferWrite(Context * context,VkAccessFlags writeAccessType,const gl::ShaderBitSet & writeShaderStages,BufferHelper * buffer)1902 void CommandBufferHelperCommon::bufferWrite(Context *context,
1903                                             VkAccessFlags writeAccessType,
1904                                             const gl::ShaderBitSet &writeShaderStages,
1905                                             BufferHelper *buffer)
1906 {
1907     VkPipelineStageFlags writePipelineStageFlags =
1908         ConvertShaderBitSetToVkPipelineStageFlags(writeShaderStages);
1909     PipelineStage firstWriteStage = GetPipelineStage(writeShaderStages.first());
1910     bufferWriteImpl(context, writeAccessType, writePipelineStageFlags, firstWriteStage, buffer);
1911 }
1912 
bufferRead(Context * context,VkAccessFlags readAccessType,PipelineStage readStage,BufferHelper * buffer)1913 void CommandBufferHelperCommon::bufferRead(Context *context,
1914                                            VkAccessFlags readAccessType,
1915                                            PipelineStage readStage,
1916                                            BufferHelper *buffer)
1917 {
1918     VkPipelineStageFlags readPipelineStageFlags =
1919         kBufferMemoryBarrierData[readStage].pipelineStageFlags;
1920     bufferReadImpl(context, readAccessType, readPipelineStageFlags, readStage, buffer);
1921 }
1922 
bufferRead(Context * context,VkAccessFlags readAccessType,const gl::ShaderBitSet & readShaderStages,BufferHelper * buffer)1923 void CommandBufferHelperCommon::bufferRead(Context *context,
1924                                            VkAccessFlags readAccessType,
1925                                            const gl::ShaderBitSet &readShaderStages,
1926                                            BufferHelper *buffer)
1927 {
1928     for (const gl::ShaderType shaderType : readShaderStages)
1929     {
1930         PipelineStage readStage = GetPipelineStage(shaderType);
1931         VkPipelineStageFlags readPipelineStageFlags =
1932             kBufferMemoryBarrierData[readStage].pipelineStageFlags;
1933         bufferReadImpl(context, readAccessType, readPipelineStageFlags, readStage, buffer);
1934     }
1935 }
1936 
bufferWriteImpl(Context * context,VkAccessFlags writeAccessType,VkPipelineStageFlags writePipelineStageFlags,PipelineStage writeStage,BufferHelper * buffer)1937 void CommandBufferHelperCommon::bufferWriteImpl(Context *context,
1938                                                 VkAccessFlags writeAccessType,
1939                                                 VkPipelineStageFlags writePipelineStageFlags,
1940                                                 PipelineStage writeStage,
1941                                                 BufferHelper *buffer)
1942 {
1943     buffer->recordWriteBarrier(context, writeAccessType, writePipelineStageFlags, writeStage,
1944                                mQueueSerial, &mPipelineBarriers, &mEventBarriers,
1945                                &mRefCountedEventCollector);
1946 
1947     // Make sure host-visible buffer writes result in a barrier inserted at the end of the frame to
1948     // make the results visible to the host.  The buffer may be mapped by the application in the
1949     // future.
1950     if (buffer->isHostVisible())
1951     {
1952         mIsAnyHostVisibleBufferWritten = true;
1953     }
1954 
1955     buffer->recordWriteEvent(context, writeAccessType, writePipelineStageFlags, mQueueSerial,
1956                              writeStage, &mRefCountedEvents);
1957 }
1958 
bufferReadImpl(Context * context,VkAccessFlags readAccessType,VkPipelineStageFlags readPipelineStageFlags,PipelineStage readStage,BufferHelper * buffer)1959 void CommandBufferHelperCommon::bufferReadImpl(Context *context,
1960                                                VkAccessFlags readAccessType,
1961                                                VkPipelineStageFlags readPipelineStageFlags,
1962                                                PipelineStage readStage,
1963                                                BufferHelper *buffer)
1964 {
1965     buffer->recordReadBarrier(context, readAccessType, readPipelineStageFlags, readStage,
1966                               &mPipelineBarriers, &mEventBarriers, &mRefCountedEventCollector);
1967     ASSERT(!usesBufferForWrite(*buffer));
1968 
1969     buffer->recordReadEvent(context, readAccessType, readPipelineStageFlags, readStage,
1970                             mQueueSerial, kBufferMemoryBarrierData[readStage].eventStage,
1971                             &mRefCountedEvents);
1972 }
1973 
imageReadImpl(Context * context,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,BarrierType barrierType,ImageHelper * image)1974 void CommandBufferHelperCommon::imageReadImpl(Context *context,
1975                                               VkImageAspectFlags aspectFlags,
1976                                               ImageLayout imageLayout,
1977                                               BarrierType barrierType,
1978                                               ImageHelper *image)
1979 {
1980     if (image->isReadBarrierNecessary(context->getRenderer(), imageLayout))
1981     {
1982         updateImageLayoutAndBarrier(context, image, aspectFlags, imageLayout, barrierType);
1983     }
1984 }
1985 
imageWriteImpl(Context * context,gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,BarrierType barrierType,ImageHelper * image)1986 void CommandBufferHelperCommon::imageWriteImpl(Context *context,
1987                                                gl::LevelIndex level,
1988                                                uint32_t layerStart,
1989                                                uint32_t layerCount,
1990                                                VkImageAspectFlags aspectFlags,
1991                                                ImageLayout imageLayout,
1992                                                BarrierType barrierType,
1993                                                ImageHelper *image)
1994 {
1995     image->onWrite(level, 1, layerStart, layerCount, aspectFlags);
1996     if (image->isWriteBarrierNecessary(imageLayout, level, 1, layerStart, layerCount))
1997     {
1998         updateImageLayoutAndBarrier(context, image, aspectFlags, imageLayout, barrierType);
1999     }
2000 }
2001 
updateImageLayoutAndBarrier(Context * context,ImageHelper * image,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,BarrierType barrierType)2002 void CommandBufferHelperCommon::updateImageLayoutAndBarrier(Context *context,
2003                                                             ImageHelper *image,
2004                                                             VkImageAspectFlags aspectFlags,
2005                                                             ImageLayout imageLayout,
2006                                                             BarrierType barrierType)
2007 {
2008     VkSemaphore semaphore = VK_NULL_HANDLE;
2009     image->updateLayoutAndBarrier(context, aspectFlags, imageLayout, barrierType, mQueueSerial,
2010                                   &mPipelineBarriers, &mEventBarriers, &mRefCountedEventCollector,
2011                                   &semaphore);
2012     // If image has an ANI semaphore, move it to command buffer so that we can wait for it in
2013     // next submission.
2014     if (semaphore != VK_NULL_HANDLE)
2015     {
2016         ASSERT(!mAcquireNextImageSemaphore.valid());
2017         mAcquireNextImageSemaphore.setHandle(semaphore);
2018     }
2019 }
2020 
retainImageWithEvent(Context * context,ImageHelper * image)2021 void CommandBufferHelperCommon::retainImageWithEvent(Context *context, ImageHelper *image)
2022 {
2023     image->setQueueSerial(mQueueSerial);
2024     image->updatePipelineStageAccessHistory();
2025 
2026     if (context->getFeatures().useVkEventForImageBarrier.enabled)
2027     {
2028         image->setCurrentRefCountedEvent(context, &mRefCountedEvents);
2029     }
2030 }
2031 
2032 template <typename CommandBufferT>
flushSetEventsImpl(Context * context,CommandBufferT * commandBuffer)2033 void CommandBufferHelperCommon::flushSetEventsImpl(Context *context, CommandBufferT *commandBuffer)
2034 {
2035     if (mRefCountedEvents.empty())
2036     {
2037         return;
2038     }
2039 
2040     // Add VkCmdSetEvent here to track the completion of this renderPass.
2041     mRefCountedEvents.flushSetEvents(context->getRenderer(), commandBuffer);
2042     // We no longer need event, so garbage collect it.
2043     mRefCountedEvents.releaseToEventCollector(&mRefCountedEventCollector);
2044 }
2045 
2046 template void CommandBufferHelperCommon::flushSetEventsImpl<priv::SecondaryCommandBuffer>(
2047     Context *context,
2048     priv::SecondaryCommandBuffer *commandBuffer);
2049 template void CommandBufferHelperCommon::flushSetEventsImpl<VulkanSecondaryCommandBuffer>(
2050     Context *context,
2051     VulkanSecondaryCommandBuffer *commandBuffer);
2052 
executeBarriers(Renderer * renderer,CommandsState * commandsState)2053 void CommandBufferHelperCommon::executeBarriers(Renderer *renderer, CommandsState *commandsState)
2054 {
2055     // Add ANI semaphore to the command submission.
2056     if (mAcquireNextImageSemaphore.valid())
2057     {
2058         commandsState->waitSemaphores.emplace_back(mAcquireNextImageSemaphore.release());
2059         commandsState->waitSemaphoreStageMasks.emplace_back(kSwapchainAcquireImageWaitStageFlags);
2060     }
2061 
2062     mPipelineBarriers.execute(renderer, &commandsState->primaryCommands);
2063     mEventBarriers.execute(renderer, &commandsState->primaryCommands);
2064 }
2065 
addCommandDiagnosticsCommon(std::ostringstream * out)2066 void CommandBufferHelperCommon::addCommandDiagnosticsCommon(std::ostringstream *out)
2067 {
2068     mPipelineBarriers.addDiagnosticsString(*out);
2069     mEventBarriers.addDiagnosticsString(*out);
2070 }
2071 
2072 // OutsideRenderPassCommandBufferHelper implementation.
OutsideRenderPassCommandBufferHelper()2073 OutsideRenderPassCommandBufferHelper::OutsideRenderPassCommandBufferHelper() {}
2074 
~OutsideRenderPassCommandBufferHelper()2075 OutsideRenderPassCommandBufferHelper::~OutsideRenderPassCommandBufferHelper() {}
2076 
initialize(ErrorContext * context)2077 angle::Result OutsideRenderPassCommandBufferHelper::initialize(ErrorContext *context)
2078 {
2079     initializeImpl();
2080     return initializeCommandBuffer(context);
2081 }
initializeCommandBuffer(ErrorContext * context)2082 angle::Result OutsideRenderPassCommandBufferHelper::initializeCommandBuffer(ErrorContext *context)
2083 {
2084     // Skip initialization in the Pool-detached state.
2085     if (!ExecutesInline() && mCommandPool == nullptr)
2086     {
2087         return angle::Result::Continue;
2088     }
2089     return mCommandBuffer.initialize(context, mCommandPool, false,
2090                                      mCommandAllocator.getAllocator());
2091 }
2092 
reset(ErrorContext * context,SecondaryCommandBufferCollector * commandBufferCollector)2093 angle::Result OutsideRenderPassCommandBufferHelper::reset(
2094     ErrorContext *context,
2095     SecondaryCommandBufferCollector *commandBufferCollector)
2096 {
2097     resetImpl(context);
2098 
2099     // Collect/Reset the command buffer
2100     commandBufferCollector->collectCommandBuffer(std::move(mCommandBuffer));
2101     mIsCommandBufferEnded = false;
2102 
2103     // Invalidate the queue serial here. We will get a new queue serial after commands flush.
2104     mQueueSerial = QueueSerial();
2105 
2106     return initializeCommandBuffer(context);
2107 }
2108 
imageRead(Context * context,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)2109 void OutsideRenderPassCommandBufferHelper::imageRead(Context *context,
2110                                                      VkImageAspectFlags aspectFlags,
2111                                                      ImageLayout imageLayout,
2112                                                      ImageHelper *image)
2113 {
2114     if (image->getResourceUse() >= mQueueSerial)
2115     {
2116         // If image is already used by renderPass, it may already set the event to renderPass's
2117         // event. In this case we already lost the previous event to wait for, thus use pipeline
2118         // barrier instead of event
2119         imageReadImpl(context, aspectFlags, imageLayout, BarrierType::Pipeline, image);
2120     }
2121     else
2122     {
2123         imageReadImpl(context, aspectFlags, imageLayout, BarrierType::Event, image);
2124         // Usually an image can only used by a RenderPassCommands or OutsideRenderPassCommands
2125         // because the layout will be different, except with image sampled from compute shader. In
2126         // this case, the renderPassCommands' read will override the outsideRenderPassCommands'
2127         retainImageWithEvent(context, image);
2128     }
2129 }
2130 
imageWrite(Context * context,gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)2131 void OutsideRenderPassCommandBufferHelper::imageWrite(Context *context,
2132                                                       gl::LevelIndex level,
2133                                                       uint32_t layerStart,
2134                                                       uint32_t layerCount,
2135                                                       VkImageAspectFlags aspectFlags,
2136                                                       ImageLayout imageLayout,
2137                                                       ImageHelper *image)
2138 {
2139     imageWriteImpl(context, level, layerStart, layerCount, aspectFlags, imageLayout,
2140                    BarrierType::Event, image);
2141     retainImageWithEvent(context, image);
2142 }
2143 
retainImage(ImageHelper * image)2144 void OutsideRenderPassCommandBufferHelper::retainImage(ImageHelper *image)
2145 {
2146     // We want explicit control on when VkEvent is used for outsideRPCommands to minimize the
2147     // overhead, so do not setEvent here.
2148     image->setQueueSerial(mQueueSerial);
2149     image->updatePipelineStageAccessHistory();
2150 }
2151 
trackImageWithEvent(Context * context,ImageHelper * image)2152 void OutsideRenderPassCommandBufferHelper::trackImageWithEvent(Context *context, ImageHelper *image)
2153 {
2154     image->setCurrentRefCountedEvent(context, &mRefCountedEvents);
2155     flushSetEventsImpl(context, &mCommandBuffer);
2156 }
2157 
collectRefCountedEventsGarbage(RefCountedEventsGarbageRecycler * garbageRecycler)2158 void OutsideRenderPassCommandBufferHelper::collectRefCountedEventsGarbage(
2159     RefCountedEventsGarbageRecycler *garbageRecycler)
2160 {
2161     ASSERT(garbageRecycler != nullptr);
2162     if (!mRefCountedEventCollector.empty())
2163     {
2164         garbageRecycler->collectGarbage(mQueueSerial, std::move(mRefCountedEventCollector));
2165     }
2166 }
2167 
flushToPrimary(Context * context,CommandsState * commandsState)2168 angle::Result OutsideRenderPassCommandBufferHelper::flushToPrimary(Context *context,
2169                                                                    CommandsState *commandsState)
2170 {
2171     ANGLE_TRACE_EVENT0("gpu.angle", "OutsideRenderPassCommandBufferHelper::flushToPrimary");
2172     ASSERT(!empty());
2173 
2174     Renderer *renderer = context->getRenderer();
2175 
2176     // Commands that are added to primary before beginRenderPass command
2177     executeBarriers(renderer, commandsState);
2178 
2179     ANGLE_TRY(endCommandBuffer(context));
2180     ASSERT(mIsCommandBufferEnded);
2181     mCommandBuffer.executeCommands(&commandsState->primaryCommands);
2182 
2183     // Call VkCmdSetEvent to track the completion of this renderPass.
2184     flushSetEventsImpl(context, &commandsState->primaryCommands);
2185 
2186     // Proactively reset all released events before ending command buffer.
2187     context->getRenderer()->getRefCountedEventRecycler()->resetEvents(
2188         context, mQueueSerial, &commandsState->primaryCommands);
2189 
2190     // Restart the command buffer.
2191     return reset(context, &commandsState->secondaryCommands);
2192 }
2193 
endCommandBuffer(ErrorContext * context)2194 angle::Result OutsideRenderPassCommandBufferHelper::endCommandBuffer(ErrorContext *context)
2195 {
2196     ASSERT(ExecutesInline() || mCommandPool != nullptr);
2197     ASSERT(mCommandBuffer.valid());
2198     ASSERT(!mIsCommandBufferEnded);
2199 
2200     ANGLE_TRY(mCommandBuffer.end(context));
2201     mIsCommandBufferEnded = true;
2202 
2203     return angle::Result::Continue;
2204 }
2205 
attachCommandPool(ErrorContext * context,SecondaryCommandPool * commandPool)2206 angle::Result OutsideRenderPassCommandBufferHelper::attachCommandPool(
2207     ErrorContext *context,
2208     SecondaryCommandPool *commandPool)
2209 {
2210     return attachCommandPoolImpl<OutsideRenderPassCommandBufferHelper>(context, commandPool);
2211 }
2212 
detachCommandPool(ErrorContext * context,SecondaryCommandPool ** commandPoolOut)2213 angle::Result OutsideRenderPassCommandBufferHelper::detachCommandPool(
2214     ErrorContext *context,
2215     SecondaryCommandPool **commandPoolOut)
2216 {
2217     return detachCommandPoolImpl<OutsideRenderPassCommandBufferHelper, false>(context,
2218                                                                               commandPoolOut);
2219 }
2220 
releaseCommandPool()2221 void OutsideRenderPassCommandBufferHelper::releaseCommandPool()
2222 {
2223     releaseCommandPoolImpl<OutsideRenderPassCommandBufferHelper>();
2224 }
2225 
attachAllocator(SecondaryCommandMemoryAllocator * allocator)2226 void OutsideRenderPassCommandBufferHelper::attachAllocator(
2227     SecondaryCommandMemoryAllocator *allocator)
2228 {
2229     attachAllocatorImpl<OutsideRenderPassCommandBufferHelper>(allocator);
2230 }
2231 
detachAllocator()2232 SecondaryCommandMemoryAllocator *OutsideRenderPassCommandBufferHelper::detachAllocator()
2233 {
2234     return detachAllocatorImpl<OutsideRenderPassCommandBufferHelper>();
2235 }
2236 
assertCanBeRecycled()2237 void OutsideRenderPassCommandBufferHelper::assertCanBeRecycled()
2238 {
2239     assertCanBeRecycledImpl<OutsideRenderPassCommandBufferHelper>();
2240 }
2241 
getCommandDiagnostics()2242 std::string OutsideRenderPassCommandBufferHelper::getCommandDiagnostics()
2243 {
2244     std::ostringstream out;
2245     addCommandDiagnosticsCommon(&out);
2246 
2247     out << mCommandBuffer.dumpCommands("\\l");
2248 
2249     return out.str();
2250 }
2251 
2252 // RenderPassFramebuffer implementation.
reset()2253 void RenderPassFramebuffer::reset()
2254 {
2255     mInitialFramebuffer.release();
2256     mImageViews.clear();
2257     mIsImageless = false;
2258     mIsDefault   = false;
2259 }
2260 
addResolveAttachment(size_t viewIndex,VkImageView view)2261 void RenderPassFramebuffer::addResolveAttachment(size_t viewIndex, VkImageView view)
2262 {
2263     // The initial framebuffer is no longer usable.
2264     mInitialFramebuffer.release();
2265 
2266     if (viewIndex >= mImageViews.size())
2267     {
2268         mImageViews.resize(viewIndex + 1, VK_NULL_HANDLE);
2269     }
2270 
2271     ASSERT(mImageViews[viewIndex] == VK_NULL_HANDLE);
2272     mImageViews[viewIndex] = view;
2273 }
2274 
packResolveViewsAndCreateFramebuffer(ErrorContext * context,const RenderPass & renderPass,Framebuffer * framebufferOut)2275 angle::Result RenderPassFramebuffer::packResolveViewsAndCreateFramebuffer(
2276     ErrorContext *context,
2277     const RenderPass &renderPass,
2278     Framebuffer *framebufferOut)
2279 {
2280     // This is only called if the initial framebuffer was not usable.  Since this is called when
2281     // the render pass is finalized, the render pass that is passed in is the final one (not a
2282     // compatible one) and the framebuffer that is created is not imageless.
2283     ASSERT(!mInitialFramebuffer.valid());
2284 
2285     PackViews(&mImageViews);
2286     mIsImageless = false;
2287 
2288     VkFramebufferCreateInfo framebufferInfo = {};
2289     framebufferInfo.sType                   = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
2290     framebufferInfo.flags                   = 0;
2291     framebufferInfo.renderPass              = renderPass.getHandle();
2292     framebufferInfo.attachmentCount         = static_cast<uint32_t>(mImageViews.size());
2293     framebufferInfo.pAttachments            = mImageViews.data();
2294     framebufferInfo.width                   = mWidth;
2295     framebufferInfo.height                  = mHeight;
2296     framebufferInfo.layers                  = mLayers;
2297 
2298     ANGLE_VK_TRY(context, framebufferOut->init(context->getDevice(), framebufferInfo));
2299     return angle::Result::Continue;
2300 }
2301 
packResolveViewsForRenderPassBegin(VkRenderPassAttachmentBeginInfo * beginInfoOut)2302 void RenderPassFramebuffer::packResolveViewsForRenderPassBegin(
2303     VkRenderPassAttachmentBeginInfo *beginInfoOut)
2304 {
2305     // Called when using the initial framebuffer which is imageless
2306     ASSERT(mInitialFramebuffer.valid());
2307     ASSERT(mIsImageless);
2308 
2309     PackViews(&mImageViews);
2310 
2311     *beginInfoOut                 = {};
2312     beginInfoOut->sType           = VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO_KHR;
2313     beginInfoOut->attachmentCount = static_cast<uint32_t>(mImageViews.size());
2314     beginInfoOut->pAttachments    = mImageViews.data();
2315 }
2316 
2317 // static
PackViews(FramebufferAttachmentsVector<VkImageView> * views)2318 void RenderPassFramebuffer::PackViews(FramebufferAttachmentsVector<VkImageView> *views)
2319 {
2320     PackedAttachmentIndex packIndex = kAttachmentIndexZero;
2321     for (size_t viewIndex = 0; viewIndex < views->size(); ++viewIndex)
2322     {
2323         if ((*views)[viewIndex] != VK_NULL_HANDLE)
2324         {
2325             (*views)[packIndex.get()] = (*views)[viewIndex];
2326             ++packIndex;
2327         }
2328     }
2329 
2330     views->resize(packIndex.get());
2331 }
2332 
2333 // RenderPassCommandBufferHelper implementation.
RenderPassCommandBufferHelper()2334 RenderPassCommandBufferHelper::RenderPassCommandBufferHelper()
2335     : mCurrentSubpassCommandBufferIndex(0),
2336       mCounter(0),
2337       mClearValues{},
2338       mRenderPassStarted(false),
2339       mTransformFeedbackCounterBuffers{},
2340       mTransformFeedbackCounterBufferOffsets{},
2341       mValidTransformFeedbackBufferCount(0),
2342       mRebindTransformFeedbackBuffers(false),
2343       mIsTransformFeedbackActiveUnpaused(false),
2344       mPreviousSubpassesCmdCount(0),
2345       mDepthStencilAttachmentIndex(kAttachmentIndexInvalid),
2346       mColorAttachmentsCount(0),
2347       mImageOptimizeForPresent(nullptr),
2348       mImageOptimizeForPresentOriginalLayout(ImageLayout::Undefined)
2349 {}
2350 
~RenderPassCommandBufferHelper()2351 RenderPassCommandBufferHelper::~RenderPassCommandBufferHelper() {}
2352 
initialize(ErrorContext * context)2353 angle::Result RenderPassCommandBufferHelper::initialize(ErrorContext *context)
2354 {
2355     initializeImpl();
2356     return initializeCommandBuffer(context);
2357 }
initializeCommandBuffer(ErrorContext * context)2358 angle::Result RenderPassCommandBufferHelper::initializeCommandBuffer(ErrorContext *context)
2359 {
2360     // Skip initialization in the Pool-detached state.
2361     if (!ExecutesInline() && mCommandPool == nullptr)
2362     {
2363         return angle::Result::Continue;
2364     }
2365     return getCommandBuffer().initialize(context, mCommandPool, true,
2366                                          mCommandAllocator.getAllocator());
2367 }
2368 
reset(ErrorContext * context,SecondaryCommandBufferCollector * commandBufferCollector)2369 angle::Result RenderPassCommandBufferHelper::reset(
2370     ErrorContext *context,
2371     SecondaryCommandBufferCollector *commandBufferCollector)
2372 {
2373     resetImpl(context);
2374 
2375     for (PackedAttachmentIndex index = kAttachmentIndexZero; index < mColorAttachmentsCount;
2376          ++index)
2377     {
2378         mColorAttachments[index].reset();
2379         mColorResolveAttachments[index].reset();
2380     }
2381 
2382     mDepthAttachment.reset();
2383     mDepthResolveAttachment.reset();
2384     mStencilAttachment.reset();
2385     mStencilResolveAttachment.reset();
2386 
2387     mFragmentShadingRateAtachment.reset();
2388 
2389     mRenderPassStarted                     = false;
2390     mValidTransformFeedbackBufferCount     = 0;
2391     mRebindTransformFeedbackBuffers        = false;
2392     mHasShaderStorageOutput                = false;
2393     mHasGLMemoryBarrierIssued              = false;
2394     mPreviousSubpassesCmdCount             = 0;
2395     mColorAttachmentsCount                 = PackedAttachmentCount(0);
2396     mDepthStencilAttachmentIndex           = kAttachmentIndexInvalid;
2397     mImageOptimizeForPresent               = nullptr;
2398     mImageOptimizeForPresentOriginalLayout = ImageLayout::Undefined;
2399 
2400     ASSERT(CheckSubpassCommandBufferCount(getSubpassCommandBufferCount()));
2401 
2402     // Collect/Reset the command buffers
2403     for (uint32_t subpass = 0; subpass < getSubpassCommandBufferCount(); ++subpass)
2404     {
2405         commandBufferCollector->collectCommandBuffer(std::move(mCommandBuffers[subpass]));
2406     }
2407 
2408     mCurrentSubpassCommandBufferIndex = 0;
2409 
2410     // Reset the image views used for imageless framebuffer (if any)
2411     mFramebuffer.reset();
2412 
2413     // Invalidate the queue serial here. We will get a new queue serial when we begin renderpass.
2414     mQueueSerial = QueueSerial();
2415 
2416     return initializeCommandBuffer(context);
2417 }
2418 
imageRead(ContextVk * contextVk,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)2419 void RenderPassCommandBufferHelper::imageRead(ContextVk *contextVk,
2420                                               VkImageAspectFlags aspectFlags,
2421                                               ImageLayout imageLayout,
2422                                               ImageHelper *image)
2423 {
2424     imageReadImpl(contextVk, aspectFlags, imageLayout, BarrierType::Event, image);
2425     // As noted in the header we don't support multiple read layouts for Images.
2426     // We allow duplicate uses in the RP to accommodate for normal GL sampler usage.
2427     retainImageWithEvent(contextVk, image);
2428 }
2429 
imageWrite(ContextVk * contextVk,gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)2430 void RenderPassCommandBufferHelper::imageWrite(ContextVk *contextVk,
2431                                                gl::LevelIndex level,
2432                                                uint32_t layerStart,
2433                                                uint32_t layerCount,
2434                                                VkImageAspectFlags aspectFlags,
2435                                                ImageLayout imageLayout,
2436                                                ImageHelper *image)
2437 {
2438     imageWriteImpl(contextVk, level, layerStart, layerCount, aspectFlags, imageLayout,
2439                    BarrierType::Event, image);
2440     retainImageWithEvent(contextVk, image);
2441 }
2442 
colorImagesDraw(gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,ImageHelper * image,ImageHelper * resolveImage,UniqueSerial imageSiblingSerial,PackedAttachmentIndex packedAttachmentIndex)2443 void RenderPassCommandBufferHelper::colorImagesDraw(gl::LevelIndex level,
2444                                                     uint32_t layerStart,
2445                                                     uint32_t layerCount,
2446                                                     ImageHelper *image,
2447                                                     ImageHelper *resolveImage,
2448                                                     UniqueSerial imageSiblingSerial,
2449                                                     PackedAttachmentIndex packedAttachmentIndex)
2450 {
2451     ASSERT(packedAttachmentIndex < mColorAttachmentsCount);
2452 
2453     image->onRenderPassAttach(mQueueSerial);
2454 
2455     mColorAttachments[packedAttachmentIndex].init(image, imageSiblingSerial, level, layerStart,
2456                                                   layerCount, VK_IMAGE_ASPECT_COLOR_BIT);
2457 
2458     if (resolveImage)
2459     {
2460         resolveImage->onRenderPassAttach(mQueueSerial);
2461         mColorResolveAttachments[packedAttachmentIndex].init(resolveImage, imageSiblingSerial,
2462                                                              level, layerStart, layerCount,
2463                                                              VK_IMAGE_ASPECT_COLOR_BIT);
2464     }
2465 }
2466 
depthStencilImagesDraw(gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,ImageHelper * image,ImageHelper * resolveImage,UniqueSerial imageSiblingSerial)2467 void RenderPassCommandBufferHelper::depthStencilImagesDraw(gl::LevelIndex level,
2468                                                            uint32_t layerStart,
2469                                                            uint32_t layerCount,
2470                                                            ImageHelper *image,
2471                                                            ImageHelper *resolveImage,
2472                                                            UniqueSerial imageSiblingSerial)
2473 {
2474     ASSERT(!usesImage(*image));
2475     ASSERT(!resolveImage || !usesImage(*resolveImage));
2476 
2477     // Because depthStencil buffer's read/write property can change while we build renderpass, we
2478     // defer the image layout changes until endRenderPass time or when images going away so that we
2479     // only insert layout change barrier once.
2480     image->onRenderPassAttach(mQueueSerial);
2481 
2482     mDepthAttachment.init(image, imageSiblingSerial, level, layerStart, layerCount,
2483                           VK_IMAGE_ASPECT_DEPTH_BIT);
2484     mStencilAttachment.init(image, imageSiblingSerial, level, layerStart, layerCount,
2485                             VK_IMAGE_ASPECT_STENCIL_BIT);
2486 
2487     if (resolveImage)
2488     {
2489         // Note that the resolve depth/stencil image has the same level/layer index as the
2490         // depth/stencil image as currently it can only ever come from
2491         // multisampled-render-to-texture renderbuffers.
2492         resolveImage->onRenderPassAttach(mQueueSerial);
2493 
2494         mDepthResolveAttachment.init(resolveImage, imageSiblingSerial, level, layerStart,
2495                                      layerCount, VK_IMAGE_ASPECT_DEPTH_BIT);
2496         mStencilResolveAttachment.init(resolveImage, imageSiblingSerial, level, layerStart,
2497                                        layerCount, VK_IMAGE_ASPECT_STENCIL_BIT);
2498     }
2499 }
2500 
fragmentShadingRateImageRead(ImageHelper * image)2501 void RenderPassCommandBufferHelper::fragmentShadingRateImageRead(ImageHelper *image)
2502 {
2503     ASSERT(image && image->valid());
2504     ASSERT(!usesImage(*image));
2505 
2506     image->onRenderPassAttach(mQueueSerial);
2507 
2508     // Initialize RenderPassAttachment for fragment shading rate attachment.
2509     mFragmentShadingRateAtachment.init(image, {}, gl::LevelIndex(0), 0, 1,
2510                                        VK_IMAGE_ASPECT_COLOR_BIT);
2511 
2512     image->resetRenderPassUsageFlags();
2513     image->setRenderPassUsageFlag(RenderPassUsage::FragmentShadingRateReadOnlyAttachment);
2514 }
2515 
onColorAccess(PackedAttachmentIndex packedAttachmentIndex,ResourceAccess access)2516 void RenderPassCommandBufferHelper::onColorAccess(PackedAttachmentIndex packedAttachmentIndex,
2517                                                   ResourceAccess access)
2518 {
2519     ASSERT(packedAttachmentIndex < mColorAttachmentsCount);
2520     mColorAttachments[packedAttachmentIndex].onAccess(access, getRenderPassWriteCommandCount());
2521 }
2522 
onDepthAccess(ResourceAccess access)2523 void RenderPassCommandBufferHelper::onDepthAccess(ResourceAccess access)
2524 {
2525     mDepthAttachment.onAccess(access, getRenderPassWriteCommandCount());
2526 }
2527 
onStencilAccess(ResourceAccess access)2528 void RenderPassCommandBufferHelper::onStencilAccess(ResourceAccess access)
2529 {
2530     mStencilAttachment.onAccess(access, getRenderPassWriteCommandCount());
2531 }
2532 
updateDepthReadOnlyMode(RenderPassUsageFlags dsUsageFlags)2533 void RenderPassCommandBufferHelper::updateDepthReadOnlyMode(RenderPassUsageFlags dsUsageFlags)
2534 {
2535     ASSERT(mRenderPassStarted);
2536     updateStartedRenderPassWithDepthStencilMode(&mDepthResolveAttachment, hasDepthWriteOrClear(),
2537                                                 dsUsageFlags,
2538                                                 RenderPassUsage::DepthReadOnlyAttachment);
2539 }
2540 
updateStencilReadOnlyMode(RenderPassUsageFlags dsUsageFlags)2541 void RenderPassCommandBufferHelper::updateStencilReadOnlyMode(RenderPassUsageFlags dsUsageFlags)
2542 {
2543     ASSERT(mRenderPassStarted);
2544     updateStartedRenderPassWithDepthStencilMode(&mStencilResolveAttachment,
2545                                                 hasStencilWriteOrClear(), dsUsageFlags,
2546                                                 RenderPassUsage::StencilReadOnlyAttachment);
2547 }
2548 
updateDepthStencilReadOnlyMode(RenderPassUsageFlags dsUsageFlags,VkImageAspectFlags dsAspectFlags)2549 void RenderPassCommandBufferHelper::updateDepthStencilReadOnlyMode(
2550     RenderPassUsageFlags dsUsageFlags,
2551     VkImageAspectFlags dsAspectFlags)
2552 {
2553     ASSERT(mRenderPassStarted);
2554     if ((dsAspectFlags & VK_IMAGE_ASPECT_DEPTH_BIT) != 0)
2555     {
2556         updateDepthReadOnlyMode(dsUsageFlags);
2557     }
2558     if ((dsAspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
2559     {
2560         updateStencilReadOnlyMode(dsUsageFlags);
2561     }
2562 }
2563 
updateStartedRenderPassWithDepthStencilMode(RenderPassAttachment * resolveAttachment,bool renderPassHasWriteOrClear,RenderPassUsageFlags dsUsageFlags,RenderPassUsage readOnlyAttachmentUsage)2564 void RenderPassCommandBufferHelper::updateStartedRenderPassWithDepthStencilMode(
2565     RenderPassAttachment *resolveAttachment,
2566     bool renderPassHasWriteOrClear,
2567     RenderPassUsageFlags dsUsageFlags,
2568     RenderPassUsage readOnlyAttachmentUsage)
2569 {
2570     ASSERT(mRenderPassStarted);
2571     ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
2572     ASSERT(mDepthResolveAttachment.getImage() == mStencilResolveAttachment.getImage());
2573 
2574     // Determine read-only mode for depth or stencil
2575     const bool readOnlyMode =
2576         mDepthStencilAttachmentIndex != kAttachmentIndexInvalid &&
2577         resolveAttachment->getImage() == nullptr &&
2578         (dsUsageFlags.test(readOnlyAttachmentUsage) || !renderPassHasWriteOrClear);
2579 
2580     // If readOnlyMode is false, we are switching out of read only mode due to depth/stencil write.
2581     // We must not be in the read only feedback loop mode because the logic in
2582     // DIRTY_BIT_READ_ONLY_DEPTH_FEEDBACK_LOOP_MODE should ensure we end the previous renderpass and
2583     // a new renderpass will start with feedback loop disabled.
2584     ASSERT(readOnlyMode || !dsUsageFlags.test(readOnlyAttachmentUsage));
2585 
2586     ImageHelper *depthStencilImage = mDepthAttachment.getImage();
2587     if (depthStencilImage)
2588     {
2589         if (readOnlyMode)
2590         {
2591             depthStencilImage->setRenderPassUsageFlag(readOnlyAttachmentUsage);
2592         }
2593         else
2594         {
2595             depthStencilImage->clearRenderPassUsageFlag(readOnlyAttachmentUsage);
2596         }
2597     }
2598     // The depth/stencil resolve image is never in read-only mode
2599 }
2600 
finalizeColorImageLayout(Context * context,ImageHelper * image,PackedAttachmentIndex packedAttachmentIndex,bool isResolveImage)2601 void RenderPassCommandBufferHelper::finalizeColorImageLayout(
2602     Context *context,
2603     ImageHelper *image,
2604     PackedAttachmentIndex packedAttachmentIndex,
2605     bool isResolveImage)
2606 {
2607     ASSERT(packedAttachmentIndex < mColorAttachmentsCount);
2608     ASSERT(image != nullptr);
2609 
2610     // Do layout change.
2611     ImageLayout imageLayout;
2612     if (image->usedByCurrentRenderPassAsAttachmentAndSampler(RenderPassUsage::ColorTextureSampler))
2613     {
2614         // texture code already picked layout and inserted barrier
2615         imageLayout = image->getCurrentImageLayout();
2616         ASSERT(imageLayout == ImageLayout::ColorWriteFragmentShaderFeedback ||
2617                imageLayout == ImageLayout::ColorWriteAllShadersFeedback);
2618     }
2619     else
2620     {
2621         // When color is unresolved, use a layout that includes fragment shader reads.  This is done
2622         // for all color resolve attachments even if they are not all unresolved for simplicity.  In
2623         // particular, the GL color index is not available (only the packed index) at this point,
2624         // but that is needed to query whether the attachment is unresolved or not.
2625         const bool hasUnresolve =
2626             isResolveImage && mRenderPassDesc.getColorUnresolveAttachmentMask().any();
2627         imageLayout = hasUnresolve ? ImageLayout::MSRTTEmulationColorUnresolveAndResolve
2628                                    : ImageLayout::ColorWrite;
2629         if (context->getFeatures().preferDynamicRendering.enabled &&
2630             mRenderPassDesc.hasColorFramebufferFetch())
2631         {
2632             // Note MSRTT emulation is not implemented with dynamic rendering.
2633             ASSERT(imageLayout == ImageLayout::ColorWrite);
2634             imageLayout = ImageLayout::ColorWriteAndInput;
2635         }
2636         else if (image->getCurrentImageLayout() == ImageLayout::SharedPresent)
2637         {
2638             // Once you transition to ImageLayout::SharedPresent, you never transition out of it.
2639             ASSERT(imageLayout == ImageLayout::ColorWrite);
2640             imageLayout = ImageLayout::SharedPresent;
2641         }
2642 
2643         updateImageLayoutAndBarrier(context, image, VK_IMAGE_ASPECT_COLOR_BIT, imageLayout,
2644                                     BarrierType::Event);
2645     }
2646 
2647     if (!isResolveImage)
2648     {
2649         mAttachmentOps.setLayouts(packedAttachmentIndex, imageLayout, imageLayout);
2650     }
2651     else
2652     {
2653         SetBitField(mAttachmentOps[packedAttachmentIndex].finalResolveLayout, imageLayout);
2654     }
2655 
2656     // Dynamic rendering does not have implicit layout transitions at render pass boundaries.  This
2657     // optimization is instead done by recording the necessary transition after the render pass
2658     // directly on the primary command buffer.
2659     if (mImageOptimizeForPresent == image)
2660     {
2661         ASSERT(isDefault());
2662         ASSERT(context->getFeatures().supportsPresentation.enabled);
2663         ASSERT(packedAttachmentIndex == kAttachmentIndexZero);
2664         // Shared present mode must not change layout
2665         ASSERT(imageLayout != ImageLayout::SharedPresent);
2666 
2667         // Use finalLayout instead of extra barrier for layout change to present.  For dynamic
2668         // rendering, this is not possible and is done when the render pass is flushed.  However,
2669         // because this function is expected to finalize the image layout, we still have to pretend
2670         // the image is in the present layout already.
2671         mImageOptimizeForPresentOriginalLayout = mImageOptimizeForPresent->getCurrentImageLayout();
2672         mImageOptimizeForPresent->setCurrentImageLayout(context->getRenderer(),
2673                                                         ImageLayout::Present);
2674 
2675         if (!context->getFeatures().preferDynamicRendering.enabled)
2676         {
2677             if (isResolveImage)
2678             {
2679                 SetBitField(mAttachmentOps[packedAttachmentIndex].finalResolveLayout,
2680                             mImageOptimizeForPresent->getCurrentImageLayout());
2681             }
2682             else
2683             {
2684                 SetBitField(mAttachmentOps[packedAttachmentIndex].finalLayout,
2685                             mImageOptimizeForPresent->getCurrentImageLayout());
2686             }
2687             mImageOptimizeForPresent               = nullptr;
2688             mImageOptimizeForPresentOriginalLayout = ImageLayout::Undefined;
2689         }
2690     }
2691 
2692     if (isResolveImage)
2693     {
2694         // Note: the color image will have its flags reset after load/store ops are determined.
2695         image->resetRenderPassUsageFlags();
2696     }
2697 }
2698 
finalizeColorImageLoadStore(Context * context,PackedAttachmentIndex packedAttachmentIndex)2699 void RenderPassCommandBufferHelper::finalizeColorImageLoadStore(
2700     Context *context,
2701     PackedAttachmentIndex packedAttachmentIndex)
2702 {
2703     PackedAttachmentOpsDesc &ops = mAttachmentOps[packedAttachmentIndex];
2704     RenderPassLoadOp loadOp      = static_cast<RenderPassLoadOp>(ops.loadOp);
2705     RenderPassStoreOp storeOp    = static_cast<RenderPassStoreOp>(ops.storeOp);
2706 
2707     // This has to be called after layout been finalized
2708     ASSERT(ops.initialLayout != static_cast<uint16_t>(ImageLayout::Undefined));
2709 
2710     uint32_t currentCmdCount = getRenderPassWriteCommandCount();
2711     bool isInvalidated       = false;
2712 
2713     RenderPassAttachment &colorAttachment = mColorAttachments[packedAttachmentIndex];
2714     colorAttachment.finalizeLoadStore(
2715         context, currentCmdCount, mRenderPassDesc.getColorUnresolveAttachmentMask().any(),
2716         mRenderPassDesc.getColorResolveAttachmentMask().any(), &loadOp, &storeOp, &isInvalidated);
2717 
2718     if (isInvalidated)
2719     {
2720         ops.isInvalidated = true;
2721     }
2722 
2723     if (!ops.isInvalidated)
2724     {
2725         mColorResolveAttachments[packedAttachmentIndex].restoreContent();
2726     }
2727 
2728     // If the image is being written to, mark its contents defined.
2729     // This has to be done after storeOp has been finalized.
2730     if (storeOp == RenderPassStoreOp::Store)
2731     {
2732         colorAttachment.restoreContent();
2733     }
2734 
2735     SetBitField(ops.loadOp, loadOp);
2736     SetBitField(ops.storeOp, storeOp);
2737 }
2738 
finalizeDepthStencilImageLayout(Context * context)2739 void RenderPassCommandBufferHelper::finalizeDepthStencilImageLayout(Context *context)
2740 {
2741     ASSERT(mDepthAttachment.getImage() != nullptr);
2742     ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
2743 
2744     ImageHelper *depthStencilImage = mDepthAttachment.getImage();
2745 
2746     // Do depth stencil layout change.
2747     ImageLayout imageLayout;
2748     bool barrierRequired;
2749 
2750     const bool isDepthAttachmentAndSampler =
2751         depthStencilImage->usedByCurrentRenderPassAsAttachmentAndSampler(
2752             RenderPassUsage::DepthTextureSampler);
2753     const bool isStencilAttachmentAndSampler =
2754         depthStencilImage->usedByCurrentRenderPassAsAttachmentAndSampler(
2755             RenderPassUsage::StencilTextureSampler);
2756     const bool isReadOnlyDepth =
2757         depthStencilImage->hasRenderPassUsageFlag(RenderPassUsage::DepthReadOnlyAttachment);
2758     const bool isReadOnlyStencil =
2759         depthStencilImage->hasRenderPassUsageFlag(RenderPassUsage::StencilReadOnlyAttachment);
2760     BarrierType barrierType = BarrierType::Event;
2761 
2762     if (isDepthAttachmentAndSampler || isStencilAttachmentAndSampler)
2763     {
2764         // texture code already picked layout and inserted barrier
2765         imageLayout = depthStencilImage->getCurrentImageLayout();
2766 
2767         if ((isDepthAttachmentAndSampler && !isReadOnlyDepth) ||
2768             (isStencilAttachmentAndSampler && !isReadOnlyStencil))
2769         {
2770             ASSERT(imageLayout == ImageLayout::DepthStencilFragmentShaderFeedback ||
2771                    imageLayout == ImageLayout::DepthStencilAllShadersFeedback);
2772             barrierRequired = true;
2773         }
2774         else
2775         {
2776             ASSERT(imageLayout == ImageLayout::DepthWriteStencilReadFragmentShaderStencilRead ||
2777                    imageLayout == ImageLayout::DepthWriteStencilReadAllShadersStencilRead ||
2778                    imageLayout == ImageLayout::DepthReadStencilWriteFragmentShaderDepthRead ||
2779                    imageLayout == ImageLayout::DepthReadStencilWriteAllShadersDepthRead ||
2780                    imageLayout == ImageLayout::DepthReadStencilReadFragmentShaderRead ||
2781                    imageLayout == ImageLayout::DepthReadStencilReadAllShadersRead);
2782             barrierRequired =
2783                 depthStencilImage->isReadBarrierNecessary(context->getRenderer(), imageLayout);
2784         }
2785     }
2786     else
2787     {
2788         if (mRenderPassDesc.hasDepthStencilFramebufferFetch())
2789         {
2790             imageLayout = ImageLayout::DepthStencilWriteAndInput;
2791         }
2792         else if (isReadOnlyDepth)
2793         {
2794             imageLayout = isReadOnlyStencil ? ImageLayout::DepthReadStencilRead
2795                                             : ImageLayout::DepthReadStencilWrite;
2796         }
2797         else
2798         {
2799             imageLayout = isReadOnlyStencil ? ImageLayout::DepthWriteStencilRead
2800                                             : ImageLayout::DepthWriteStencilWrite;
2801         }
2802 
2803         barrierRequired =
2804             !isReadOnlyDepth || !isReadOnlyStencil ||
2805             depthStencilImage->isReadBarrierNecessary(context->getRenderer(), imageLayout);
2806     }
2807 
2808     mAttachmentOps.setLayouts(mDepthStencilAttachmentIndex, imageLayout, imageLayout);
2809 
2810     if (barrierRequired)
2811     {
2812         const angle::Format &format = depthStencilImage->getActualFormat();
2813         ASSERT(format.hasDepthOrStencilBits());
2814         VkImageAspectFlags aspectFlags = GetDepthStencilAspectFlags(format);
2815         updateImageLayoutAndBarrier(context, depthStencilImage, aspectFlags, imageLayout,
2816                                     barrierType);
2817     }
2818 }
2819 
finalizeDepthStencilResolveImageLayout(Context * context)2820 void RenderPassCommandBufferHelper::finalizeDepthStencilResolveImageLayout(Context *context)
2821 {
2822     ASSERT(mDepthResolveAttachment.getImage() != nullptr);
2823     ASSERT(mDepthResolveAttachment.getImage() == mStencilResolveAttachment.getImage());
2824 
2825     ImageHelper *depthStencilResolveImage = mDepthResolveAttachment.getImage();
2826 
2827     // When depth/stencil is unresolved, use a layout that includes fragment shader reads.
2828     ImageLayout imageLayout     = mRenderPassDesc.hasDepthStencilUnresolveAttachment()
2829                                       ? ImageLayout::MSRTTEmulationDepthStencilUnresolveAndResolve
2830                                       : ImageLayout::DepthStencilResolve;
2831     const angle::Format &format = depthStencilResolveImage->getActualFormat();
2832     ASSERT(format.hasDepthOrStencilBits());
2833     VkImageAspectFlags aspectFlags = GetDepthStencilAspectFlags(format);
2834 
2835     updateImageLayoutAndBarrier(context, depthStencilResolveImage, aspectFlags, imageLayout,
2836                                 BarrierType::Event);
2837 
2838     // The resolve image can never be read-only.
2839     ASSERT(!depthStencilResolveImage->hasRenderPassUsageFlag(
2840         RenderPassUsage::DepthReadOnlyAttachment));
2841     ASSERT(!depthStencilResolveImage->hasRenderPassUsageFlag(
2842         RenderPassUsage::StencilReadOnlyAttachment));
2843     ASSERT(mDepthStencilAttachmentIndex != kAttachmentIndexInvalid);
2844     const PackedAttachmentOpsDesc &dsOps = mAttachmentOps[mDepthStencilAttachmentIndex];
2845 
2846     // If the image is being written to, mark its contents defined.
2847     if (!dsOps.isInvalidated && mRenderPassDesc.hasDepthResolveAttachment())
2848     {
2849         mDepthResolveAttachment.restoreContent();
2850     }
2851     if (!dsOps.isStencilInvalidated && mRenderPassDesc.hasStencilResolveAttachment())
2852     {
2853         mStencilResolveAttachment.restoreContent();
2854     }
2855 
2856     depthStencilResolveImage->resetRenderPassUsageFlags();
2857 }
2858 
finalizeFragmentShadingRateImageLayout(Context * context)2859 void RenderPassCommandBufferHelper::finalizeFragmentShadingRateImageLayout(Context *context)
2860 {
2861     ImageHelper *image      = mFragmentShadingRateAtachment.getImage();
2862     ImageLayout imageLayout = ImageLayout::FragmentShadingRateAttachmentReadOnly;
2863     ASSERT(image && image->valid());
2864     if (image->isReadBarrierNecessary(context->getRenderer(), imageLayout))
2865     {
2866         updateImageLayoutAndBarrier(context, image, VK_IMAGE_ASPECT_COLOR_BIT, imageLayout,
2867                                     BarrierType::Event);
2868     }
2869     image->resetRenderPassUsageFlags();
2870 }
2871 
finalizeImageLayout(Context * context,const ImageHelper * image,UniqueSerial imageSiblingSerial)2872 void RenderPassCommandBufferHelper::finalizeImageLayout(Context *context,
2873                                                         const ImageHelper *image,
2874                                                         UniqueSerial imageSiblingSerial)
2875 {
2876     if (image->hasRenderPassUsageFlag(RenderPassUsage::RenderTargetAttachment))
2877     {
2878         for (PackedAttachmentIndex index = kAttachmentIndexZero; index < mColorAttachmentsCount;
2879              ++index)
2880         {
2881             if (mColorAttachments[index].hasImage(image, imageSiblingSerial))
2882             {
2883                 finalizeColorImageLayoutAndLoadStore(context, index);
2884                 mColorAttachments[index].reset();
2885             }
2886             else if (mColorResolveAttachments[index].hasImage(image, imageSiblingSerial))
2887             {
2888                 finalizeColorImageLayout(context, mColorResolveAttachments[index].getImage(), index,
2889                                          true);
2890                 mColorResolveAttachments[index].reset();
2891             }
2892         }
2893     }
2894 
2895     if (mDepthAttachment.hasImage(image, imageSiblingSerial))
2896     {
2897         finalizeDepthStencilImageLayoutAndLoadStore(context);
2898         mDepthAttachment.reset();
2899         mStencilAttachment.reset();
2900     }
2901 
2902     if (mDepthResolveAttachment.hasImage(image, imageSiblingSerial))
2903     {
2904         finalizeDepthStencilResolveImageLayout(context);
2905         mDepthResolveAttachment.reset();
2906         mStencilResolveAttachment.reset();
2907     }
2908 
2909     if (mFragmentShadingRateAtachment.hasImage(image, imageSiblingSerial))
2910     {
2911         finalizeFragmentShadingRateImageLayout(context);
2912         mFragmentShadingRateAtachment.reset();
2913     }
2914 }
2915 
finalizeDepthStencilLoadStore(Context * context)2916 void RenderPassCommandBufferHelper::finalizeDepthStencilLoadStore(Context *context)
2917 {
2918     ASSERT(mDepthStencilAttachmentIndex != kAttachmentIndexInvalid);
2919 
2920     PackedAttachmentOpsDesc &dsOps   = mAttachmentOps[mDepthStencilAttachmentIndex];
2921     RenderPassLoadOp depthLoadOp     = static_cast<RenderPassLoadOp>(dsOps.loadOp);
2922     RenderPassStoreOp depthStoreOp   = static_cast<RenderPassStoreOp>(dsOps.storeOp);
2923     RenderPassLoadOp stencilLoadOp   = static_cast<RenderPassLoadOp>(dsOps.stencilLoadOp);
2924     RenderPassStoreOp stencilStoreOp = static_cast<RenderPassStoreOp>(dsOps.stencilStoreOp);
2925 
2926     // This has to be called after layout been finalized
2927     ASSERT(dsOps.initialLayout != static_cast<uint16_t>(ImageLayout::Undefined));
2928 
2929     uint32_t currentCmdCount         = getRenderPassWriteCommandCount();
2930     bool isDepthInvalidated          = false;
2931     bool isStencilInvalidated        = false;
2932     bool hasDepthResolveAttachment   = mRenderPassDesc.hasDepthResolveAttachment();
2933     bool hasStencilResolveAttachment = mRenderPassDesc.hasStencilResolveAttachment();
2934 
2935     mDepthAttachment.finalizeLoadStore(
2936         context, currentCmdCount, mRenderPassDesc.hasDepthUnresolveAttachment(),
2937         hasDepthResolveAttachment, &depthLoadOp, &depthStoreOp, &isDepthInvalidated);
2938     mStencilAttachment.finalizeLoadStore(
2939         context, currentCmdCount, mRenderPassDesc.hasStencilUnresolveAttachment(),
2940         hasStencilResolveAttachment, &stencilLoadOp, &stencilStoreOp, &isStencilInvalidated);
2941 
2942     const bool disableMixedDepthStencilLoadOpNoneAndLoad =
2943         context->getFeatures().disallowMixedDepthStencilLoadOpNoneAndLoad.enabled;
2944 
2945     if (disableMixedDepthStencilLoadOpNoneAndLoad)
2946     {
2947         if (depthLoadOp == RenderPassLoadOp::None && stencilLoadOp != RenderPassLoadOp::None)
2948         {
2949             depthLoadOp = RenderPassLoadOp::Load;
2950         }
2951         if (depthLoadOp != RenderPassLoadOp::None && stencilLoadOp == RenderPassLoadOp::None)
2952         {
2953             stencilLoadOp = RenderPassLoadOp::Load;
2954         }
2955     }
2956 
2957     if (isDepthInvalidated)
2958     {
2959         dsOps.isInvalidated = true;
2960     }
2961     if (isStencilInvalidated)
2962     {
2963         dsOps.isStencilInvalidated = true;
2964     }
2965 
2966     // If any aspect is missing, set the corresponding ops to don't care.
2967     const uint32_t depthStencilIndexGL =
2968         static_cast<uint32_t>(mRenderPassDesc.depthStencilAttachmentIndex());
2969     const angle::FormatID attachmentFormatID = mRenderPassDesc[depthStencilIndexGL];
2970     ASSERT(attachmentFormatID != angle::FormatID::NONE);
2971     const angle::Format &angleFormat = angle::Format::Get(attachmentFormatID);
2972 
2973     if (angleFormat.depthBits == 0)
2974     {
2975         depthLoadOp  = RenderPassLoadOp::DontCare;
2976         depthStoreOp = RenderPassStoreOp::DontCare;
2977     }
2978     if (angleFormat.stencilBits == 0)
2979     {
2980         stencilLoadOp  = RenderPassLoadOp::DontCare;
2981         stencilStoreOp = RenderPassStoreOp::DontCare;
2982     }
2983 
2984     // If the image is being written to, mark its contents defined.
2985     // This has to be done after storeOp has been finalized.
2986     ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
2987     if (!mDepthAttachment.getImage()->hasRenderPassUsageFlag(
2988             RenderPassUsage::DepthReadOnlyAttachment))
2989     {
2990         if (depthStoreOp == RenderPassStoreOp::Store)
2991         {
2992             mDepthAttachment.restoreContent();
2993         }
2994     }
2995     if (!mStencilAttachment.getImage()->hasRenderPassUsageFlag(
2996             RenderPassUsage::StencilReadOnlyAttachment))
2997     {
2998         if (stencilStoreOp == RenderPassStoreOp::Store)
2999         {
3000             mStencilAttachment.restoreContent();
3001         }
3002     }
3003 
3004     SetBitField(dsOps.loadOp, depthLoadOp);
3005     SetBitField(dsOps.storeOp, depthStoreOp);
3006     SetBitField(dsOps.stencilLoadOp, stencilLoadOp);
3007     SetBitField(dsOps.stencilStoreOp, stencilStoreOp);
3008 }
3009 
finalizeColorImageLayoutAndLoadStore(Context * context,PackedAttachmentIndex packedAttachmentIndex)3010 void RenderPassCommandBufferHelper::finalizeColorImageLayoutAndLoadStore(
3011     Context *context,
3012     PackedAttachmentIndex packedAttachmentIndex)
3013 {
3014     finalizeColorImageLayout(context, mColorAttachments[packedAttachmentIndex].getImage(),
3015                              packedAttachmentIndex, false);
3016     finalizeColorImageLoadStore(context, packedAttachmentIndex);
3017 
3018     mColorAttachments[packedAttachmentIndex].getImage()->resetRenderPassUsageFlags();
3019 }
3020 
finalizeDepthStencilImageLayoutAndLoadStore(Context * context)3021 void RenderPassCommandBufferHelper::finalizeDepthStencilImageLayoutAndLoadStore(Context *context)
3022 {
3023     finalizeDepthStencilImageLayout(context);
3024     finalizeDepthStencilLoadStore(context);
3025 
3026     ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
3027     mDepthAttachment.getImage()->resetRenderPassUsageFlags();
3028 }
3029 
collectRefCountedEventsGarbage(Renderer * renderer,RefCountedEventsGarbageRecycler * garbageRecycler)3030 void RenderPassCommandBufferHelper::collectRefCountedEventsGarbage(
3031     Renderer *renderer,
3032     RefCountedEventsGarbageRecycler *garbageRecycler)
3033 {
3034     // For render pass the VkCmdSetEvent works differently from OutsideRenderPassCommands.
3035     // VkCmdEndRenderPass are called in the primary command buffer, and VkCmdSetEvents has to be
3036     // issued after VkCmdEndRenderPass. This means VkCmdSetEvent has to be delayed. Because of this,
3037     // here we simply make a copy of the VkEvent from RefCountedEvent and then add the
3038     // RefCountedEvent to the garbage collector. No VkCmdSetEvent call is issued here (they will be
3039     // issued at flushToPrimary time).
3040     mVkEventArray.init(renderer, mRefCountedEvents);
3041     mRefCountedEvents.releaseToEventCollector(&mRefCountedEventCollector);
3042 
3043     if (!mRefCountedEventCollector.empty())
3044     {
3045         garbageRecycler->collectGarbage(mQueueSerial, std::move(mRefCountedEventCollector));
3046     }
3047 }
3048 
updatePerfCountersForDynamicRenderingInstance(ErrorContext * context,angle::VulkanPerfCounters * countersOut)3049 void RenderPassCommandBufferHelper::updatePerfCountersForDynamicRenderingInstance(
3050     ErrorContext *context,
3051     angle::VulkanPerfCounters *countersOut)
3052 {
3053     mRenderPassDesc.updatePerfCounters(context, mFramebuffer.getUnpackedImageViews(),
3054                                        mAttachmentOps, countersOut);
3055 }
3056 
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)3057 angle::Result RenderPassCommandBufferHelper::beginRenderPass(
3058     ContextVk *contextVk,
3059     RenderPassFramebuffer &&framebuffer,
3060     const gl::Rectangle &renderArea,
3061     const RenderPassDesc &renderPassDesc,
3062     const AttachmentOpsArray &renderPassAttachmentOps,
3063     const PackedAttachmentCount colorAttachmentCount,
3064     const PackedAttachmentIndex depthStencilAttachmentIndex,
3065     const PackedClearValuesArray &clearValues,
3066     const QueueSerial &queueSerial,
3067     RenderPassCommandBuffer **commandBufferOut)
3068 {
3069     ASSERT(!mRenderPassStarted);
3070 
3071     mRenderPassDesc              = renderPassDesc;
3072     mAttachmentOps               = renderPassAttachmentOps;
3073     mDepthStencilAttachmentIndex = depthStencilAttachmentIndex;
3074     mColorAttachmentsCount       = colorAttachmentCount;
3075     mFramebuffer                 = std::move(framebuffer);
3076     mRenderArea                  = renderArea;
3077     mClearValues                 = clearValues;
3078     mQueueSerial                 = queueSerial;
3079     *commandBufferOut            = &getCommandBuffer();
3080 
3081     mRenderPassStarted = true;
3082     mCounter++;
3083 
3084     return beginRenderPassCommandBuffer(contextVk);
3085 }
3086 
beginRenderPassCommandBuffer(ContextVk * contextVk)3087 angle::Result RenderPassCommandBufferHelper::beginRenderPassCommandBuffer(ContextVk *contextVk)
3088 {
3089     VkCommandBufferInheritanceInfo inheritanceInfo;
3090     VkCommandBufferInheritanceRenderingInfo renderingInfo;
3091     gl::DrawBuffersArray<VkFormat> colorFormatStorage;
3092 
3093     ANGLE_TRY(RenderPassCommandBuffer::InitializeRenderPassInheritanceInfo(
3094         contextVk, mFramebuffer.getFramebuffer(), mRenderPassDesc, &inheritanceInfo, &renderingInfo,
3095         &colorFormatStorage));
3096     inheritanceInfo.subpass = mCurrentSubpassCommandBufferIndex;
3097 
3098     return getCommandBuffer().begin(contextVk, inheritanceInfo);
3099 }
3100 
endRenderPass(ContextVk * contextVk)3101 angle::Result RenderPassCommandBufferHelper::endRenderPass(ContextVk *contextVk)
3102 {
3103     ANGLE_TRY(endRenderPassCommandBuffer(contextVk));
3104 
3105     for (PackedAttachmentIndex index = kAttachmentIndexZero; index < mColorAttachmentsCount;
3106          ++index)
3107     {
3108         if (mColorAttachments[index].getImage() != nullptr)
3109         {
3110             finalizeColorImageLayoutAndLoadStore(contextVk, index);
3111         }
3112         if (mColorResolveAttachments[index].getImage() != nullptr)
3113         {
3114             finalizeColorImageLayout(contextVk, mColorResolveAttachments[index].getImage(), index,
3115                                      true);
3116         }
3117     }
3118 
3119     if (mFragmentShadingRateAtachment.getImage() != nullptr)
3120     {
3121         finalizeFragmentShadingRateImageLayout(contextVk);
3122     }
3123 
3124     if (mDepthStencilAttachmentIndex != kAttachmentIndexInvalid)
3125     {
3126         // Do depth stencil layout change and load store optimization.
3127         ASSERT(mDepthAttachment.getImage() == mStencilAttachment.getImage());
3128         ASSERT(mDepthResolveAttachment.getImage() == mStencilResolveAttachment.getImage());
3129         if (mDepthAttachment.getImage() != nullptr)
3130         {
3131             finalizeDepthStencilImageLayoutAndLoadStore(contextVk);
3132         }
3133         if (mDepthResolveAttachment.getImage() != nullptr)
3134         {
3135             finalizeDepthStencilResolveImageLayout(contextVk);
3136         }
3137     }
3138 
3139     return angle::Result::Continue;
3140 }
3141 
endRenderPassCommandBuffer(ContextVk * contextVk)3142 angle::Result RenderPassCommandBufferHelper::endRenderPassCommandBuffer(ContextVk *contextVk)
3143 {
3144     return getCommandBuffer().end(contextVk);
3145 }
3146 
nextSubpass(ContextVk * contextVk,RenderPassCommandBuffer ** commandBufferOut)3147 angle::Result RenderPassCommandBufferHelper::nextSubpass(ContextVk *contextVk,
3148                                                          RenderPassCommandBuffer **commandBufferOut)
3149 {
3150     ASSERT(!contextVk->getFeatures().preferDynamicRendering.enabled);
3151 
3152     if (ExecutesInline())
3153     {
3154         // When using ANGLE secondary command buffers, the commands are inline and are executed on
3155         // the primary command buffer.  This means that vkCmdNextSubpass can be intermixed with the
3156         // rest of the commands, and there is no need to split command buffers.
3157         //
3158         // Note also that the command buffer handle doesn't change in this case.
3159         getCommandBuffer().nextSubpass(VK_SUBPASS_CONTENTS_INLINE);
3160         return angle::Result::Continue;
3161     }
3162 
3163     // When using Vulkan secondary command buffers, each subpass's contents must be recorded in a
3164     // separate command buffer that is vkCmdExecuteCommands'ed in the primary command buffer.
3165     // vkCmdNextSubpass calls must also be issued in the primary command buffer.
3166     //
3167     // To support this, a list of command buffers are kept, one for each subpass.  When moving to
3168     // the next subpass, the previous command buffer is ended and a new one is initialized and
3169     // begun.
3170 
3171     // Accumulate command count for tracking purposes.
3172     mPreviousSubpassesCmdCount = getRenderPassWriteCommandCount();
3173 
3174     ANGLE_TRY(endRenderPassCommandBuffer(contextVk));
3175     markClosed();
3176 
3177     ++mCurrentSubpassCommandBufferIndex;
3178     ASSERT(getSubpassCommandBufferCount() <= kMaxSubpassCount);
3179 
3180     ANGLE_TRY(initializeCommandBuffer(contextVk));
3181     ANGLE_TRY(beginRenderPassCommandBuffer(contextVk));
3182     markOpen();
3183 
3184     // Return the new command buffer handle
3185     *commandBufferOut = &getCommandBuffer();
3186     return angle::Result::Continue;
3187 }
3188 
beginTransformFeedback(size_t validBufferCount,const VkBuffer * counterBuffers,const VkDeviceSize * counterBufferOffsets,bool rebindBuffers)3189 void RenderPassCommandBufferHelper::beginTransformFeedback(size_t validBufferCount,
3190                                                            const VkBuffer *counterBuffers,
3191                                                            const VkDeviceSize *counterBufferOffsets,
3192                                                            bool rebindBuffers)
3193 {
3194     mValidTransformFeedbackBufferCount = static_cast<uint32_t>(validBufferCount);
3195     mRebindTransformFeedbackBuffers    = rebindBuffers;
3196 
3197     for (size_t index = 0; index < validBufferCount; index++)
3198     {
3199         mTransformFeedbackCounterBuffers[index]       = counterBuffers[index];
3200         mTransformFeedbackCounterBufferOffsets[index] = counterBufferOffsets[index];
3201     }
3202 }
3203 
endTransformFeedback()3204 void RenderPassCommandBufferHelper::endTransformFeedback()
3205 {
3206     pauseTransformFeedback();
3207     mValidTransformFeedbackBufferCount = 0;
3208 }
3209 
invalidateRenderPassColorAttachment(const gl::State & state,size_t colorIndexGL,PackedAttachmentIndex attachmentIndex,const gl::Rectangle & invalidateArea)3210 void RenderPassCommandBufferHelper::invalidateRenderPassColorAttachment(
3211     const gl::State &state,
3212     size_t colorIndexGL,
3213     PackedAttachmentIndex attachmentIndex,
3214     const gl::Rectangle &invalidateArea)
3215 {
3216     // Color write is enabled if:
3217     //
3218     // - Draw buffer is enabled (this is implicit, as invalidate only affects enabled draw buffers)
3219     // - Color output is not entirely masked
3220     // - Rasterizer-discard is not enabled
3221     const gl::BlendStateExt &blendStateExt = state.getBlendStateExt();
3222     const bool isColorWriteEnabled =
3223         blendStateExt.getColorMaskIndexed(colorIndexGL) != 0 && !state.isRasterizerDiscardEnabled();
3224     mColorAttachments[attachmentIndex].invalidate(invalidateArea, isColorWriteEnabled,
3225                                                   getRenderPassWriteCommandCount());
3226 }
3227 
invalidateRenderPassDepthAttachment(const gl::DepthStencilState & dsState,const gl::Rectangle & invalidateArea)3228 void RenderPassCommandBufferHelper::invalidateRenderPassDepthAttachment(
3229     const gl::DepthStencilState &dsState,
3230     const gl::Rectangle &invalidateArea)
3231 {
3232     const bool isDepthWriteEnabled = dsState.depthTest && dsState.depthMask;
3233     mDepthAttachment.invalidate(invalidateArea, isDepthWriteEnabled,
3234                                 getRenderPassWriteCommandCount());
3235 }
3236 
invalidateRenderPassStencilAttachment(const gl::DepthStencilState & dsState,GLuint framebufferStencilSize,const gl::Rectangle & invalidateArea)3237 void RenderPassCommandBufferHelper::invalidateRenderPassStencilAttachment(
3238     const gl::DepthStencilState &dsState,
3239     GLuint framebufferStencilSize,
3240     const gl::Rectangle &invalidateArea)
3241 {
3242     const bool isStencilWriteEnabled =
3243         dsState.stencilTest && (!dsState.isStencilNoOp(framebufferStencilSize) ||
3244                                 !dsState.isStencilBackNoOp(framebufferStencilSize));
3245     mStencilAttachment.invalidate(invalidateArea, isStencilWriteEnabled,
3246                                   getRenderPassWriteCommandCount());
3247 }
3248 
flushToPrimary(Context * context,CommandsState * commandsState,const RenderPass & renderPass,VkFramebuffer framebufferOverride)3249 angle::Result RenderPassCommandBufferHelper::flushToPrimary(Context *context,
3250                                                             CommandsState *commandsState,
3251                                                             const RenderPass &renderPass,
3252                                                             VkFramebuffer framebufferOverride)
3253 {
3254     Renderer *renderer = context->getRenderer();
3255     // |framebufferOverride| must only be provided if the initial framebuffer the render pass was
3256     // started with is not usable (due to the addition of resolve attachments after the fact).
3257     ASSERT(framebufferOverride == VK_NULL_HANDLE ||
3258            mFramebuffer.needsNewFramebufferWithResolveAttachments());
3259     // When a new framebuffer had to be created because of addition of resolve attachments, it's
3260     // never imageless.
3261     ASSERT(!(framebufferOverride != VK_NULL_HANDLE && mFramebuffer.isImageless()));
3262 
3263     ANGLE_TRACE_EVENT0("gpu.angle", "RenderPassCommandBufferHelper::flushToPrimary");
3264     ASSERT(mRenderPassStarted);
3265     PrimaryCommandBuffer &primary = commandsState->primaryCommands;
3266 
3267     // Commands that are added to primary before beginRenderPass command
3268     executeBarriers(renderer, commandsState);
3269 
3270     constexpr VkSubpassContents kSubpassContents =
3271         ExecutesInline() ? VK_SUBPASS_CONTENTS_INLINE
3272                          : VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS;
3273 
3274     if (!renderPass.valid())
3275     {
3276         mRenderPassDesc.beginRendering(context, &primary, mRenderArea, kSubpassContents,
3277                                        mFramebuffer.getUnpackedImageViews(), mAttachmentOps,
3278                                        mClearValues, mFramebuffer.getLayers());
3279     }
3280     else
3281     {
3282         // With imageless framebuffers, the attachments should be also added to beginInfo.
3283         VkRenderPassAttachmentBeginInfo attachmentBeginInfo = {};
3284         if (mFramebuffer.isImageless())
3285         {
3286             mFramebuffer.packResolveViewsForRenderPassBegin(&attachmentBeginInfo);
3287 
3288             // If nullColorAttachmentWithExternalFormatResolve is true, there will be no color
3289             // attachment even though mRenderPassDesc indicates so.
3290             ASSERT((mRenderPassDesc.hasYUVResolveAttachment() &&
3291                     renderer->nullColorAttachmentWithExternalFormatResolve()) ||
3292                    attachmentBeginInfo.attachmentCount == mRenderPassDesc.attachmentCount());
3293         }
3294 
3295         mRenderPassDesc.beginRenderPass(
3296             context, &primary, renderPass,
3297             framebufferOverride ? framebufferOverride : mFramebuffer.getFramebuffer().getHandle(),
3298             mRenderArea, kSubpassContents, mClearValues,
3299             mFramebuffer.isImageless() ? &attachmentBeginInfo : nullptr);
3300     }
3301 
3302     // Run commands inside the RenderPass.
3303     for (uint32_t subpass = 0; subpass < getSubpassCommandBufferCount(); ++subpass)
3304     {
3305         if (subpass > 0)
3306         {
3307             ASSERT(!context->getFeatures().preferDynamicRendering.enabled);
3308             primary.nextSubpass(kSubpassContents);
3309         }
3310         mCommandBuffers[subpass].executeCommands(&primary);
3311     }
3312 
3313     if (!renderPass.valid())
3314     {
3315         primary.endRendering();
3316 
3317         if (mImageOptimizeForPresent != nullptr)
3318         {
3319             // finalizeColorImageLayout forces layout to Present.  If this is not the case, that
3320             // code was not run (so mImageOptimizeForPresentOriginalLayout is invalid).
3321             ASSERT(mImageOptimizeForPresent->getCurrentImageLayout() == ImageLayout::Present);
3322 
3323             // Restore the original layout of the image and do the real transition after the render
3324             // pass ends.
3325             mImageOptimizeForPresent->setCurrentImageLayout(renderer,
3326                                                             mImageOptimizeForPresentOriginalLayout);
3327             mImageOptimizeForPresent->recordWriteBarrierOneOff(renderer, ImageLayout::Present,
3328                                                                &primary, nullptr);
3329             mImageOptimizeForPresent               = nullptr;
3330             mImageOptimizeForPresentOriginalLayout = ImageLayout::Undefined;
3331         }
3332     }
3333     else
3334     {
3335         primary.endRenderPass();
3336     }
3337 
3338     // Now issue VkCmdSetEvents to primary command buffer
3339     ASSERT(mRefCountedEvents.empty());
3340     mVkEventArray.flushSetEvents(&primary);
3341 
3342     // Restart the command buffer.
3343     return reset(context, &commandsState->secondaryCommands);
3344 }
3345 
addColorResolveAttachment(size_t colorIndexGL,ImageHelper * image,VkImageView view,gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,UniqueSerial imageSiblingSerial)3346 void RenderPassCommandBufferHelper::addColorResolveAttachment(size_t colorIndexGL,
3347                                                               ImageHelper *image,
3348                                                               VkImageView view,
3349                                                               gl::LevelIndex level,
3350                                                               uint32_t layerStart,
3351                                                               uint32_t layerCount,
3352                                                               UniqueSerial imageSiblingSerial)
3353 {
3354     mFramebuffer.addColorResolveAttachment(colorIndexGL, view);
3355     mRenderPassDesc.packColorResolveAttachment(colorIndexGL);
3356 
3357     PackedAttachmentIndex packedAttachmentIndex =
3358         mRenderPassDesc.getPackedColorAttachmentIndex(colorIndexGL);
3359     ASSERT(mColorResolveAttachments[packedAttachmentIndex].getImage() == nullptr);
3360 
3361     image->onRenderPassAttach(mQueueSerial);
3362     mColorResolveAttachments[packedAttachmentIndex].init(
3363         image, imageSiblingSerial, level, layerStart, layerCount, VK_IMAGE_ASPECT_COLOR_BIT);
3364 }
3365 
addDepthStencilResolveAttachment(ImageHelper * image,VkImageView view,VkImageAspectFlags aspects,gl::LevelIndex level,uint32_t layerStart,uint32_t layerCount,UniqueSerial imageSiblingSerial)3366 void RenderPassCommandBufferHelper::addDepthStencilResolveAttachment(
3367     ImageHelper *image,
3368     VkImageView view,
3369     VkImageAspectFlags aspects,
3370     gl::LevelIndex level,
3371     uint32_t layerStart,
3372     uint32_t layerCount,
3373     UniqueSerial imageSiblingSerial)
3374 {
3375     mFramebuffer.addDepthStencilResolveAttachment(view);
3376     if ((aspects & VK_IMAGE_ASPECT_DEPTH_BIT) != 0)
3377     {
3378         mRenderPassDesc.packDepthResolveAttachment();
3379     }
3380     if ((aspects & VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
3381     {
3382         mRenderPassDesc.packStencilResolveAttachment();
3383     }
3384 
3385     image->onRenderPassAttach(mQueueSerial);
3386     mDepthResolveAttachment.init(image, imageSiblingSerial, level, layerStart, layerCount,
3387                                  VK_IMAGE_ASPECT_DEPTH_BIT);
3388     mStencilResolveAttachment.init(image, imageSiblingSerial, level, layerStart, layerCount,
3389                                    VK_IMAGE_ASPECT_STENCIL_BIT);
3390 }
3391 
resumeTransformFeedback()3392 void RenderPassCommandBufferHelper::resumeTransformFeedback()
3393 {
3394     ASSERT(isTransformFeedbackStarted());
3395 
3396     uint32_t numCounterBuffers =
3397         mRebindTransformFeedbackBuffers ? 0 : mValidTransformFeedbackBufferCount;
3398 
3399     mRebindTransformFeedbackBuffers    = false;
3400     mIsTransformFeedbackActiveUnpaused = true;
3401 
3402     getCommandBuffer().beginTransformFeedback(0, numCounterBuffers,
3403                                               mTransformFeedbackCounterBuffers.data(),
3404                                               mTransformFeedbackCounterBufferOffsets.data());
3405 }
3406 
pauseTransformFeedback()3407 void RenderPassCommandBufferHelper::pauseTransformFeedback()
3408 {
3409     ASSERT(isTransformFeedbackStarted() && isTransformFeedbackActiveUnpaused());
3410     mIsTransformFeedbackActiveUnpaused = false;
3411     getCommandBuffer().endTransformFeedback(0, mValidTransformFeedbackBufferCount,
3412                                             mTransformFeedbackCounterBuffers.data(),
3413                                             mTransformFeedbackCounterBufferOffsets.data());
3414 }
3415 
updateRenderPassColorClear(PackedAttachmentIndex colorIndexVk,const VkClearValue & clearValue)3416 void RenderPassCommandBufferHelper::updateRenderPassColorClear(PackedAttachmentIndex colorIndexVk,
3417                                                                const VkClearValue &clearValue)
3418 {
3419     mAttachmentOps.setClearOp(colorIndexVk);
3420     mClearValues.storeColor(colorIndexVk, clearValue);
3421 }
3422 
updateRenderPassDepthStencilClear(VkImageAspectFlags aspectFlags,const VkClearValue & clearValue)3423 void RenderPassCommandBufferHelper::updateRenderPassDepthStencilClear(
3424     VkImageAspectFlags aspectFlags,
3425     const VkClearValue &clearValue)
3426 {
3427     // Don't overwrite prior clear values for individual aspects.
3428     VkClearValue combinedClearValue = mClearValues[mDepthStencilAttachmentIndex];
3429 
3430     if ((aspectFlags & VK_IMAGE_ASPECT_DEPTH_BIT) != 0)
3431     {
3432         mAttachmentOps.setClearOp(mDepthStencilAttachmentIndex);
3433         combinedClearValue.depthStencil.depth = clearValue.depthStencil.depth;
3434     }
3435 
3436     if ((aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
3437     {
3438         mAttachmentOps.setClearStencilOp(mDepthStencilAttachmentIndex);
3439         combinedClearValue.depthStencil.stencil = clearValue.depthStencil.stencil;
3440     }
3441 
3442     // Bypass special D/S handling. This clear values array stores values packed.
3443     mClearValues.storeDepthStencil(mDepthStencilAttachmentIndex, combinedClearValue);
3444 }
3445 
growRenderArea(ContextVk * contextVk,const gl::Rectangle & newRenderArea)3446 void RenderPassCommandBufferHelper::growRenderArea(ContextVk *contextVk,
3447                                                    const gl::Rectangle &newRenderArea)
3448 {
3449     // The render area is grown such that it covers both the previous and the new render areas.
3450     gl::GetEnclosingRectangle(mRenderArea, newRenderArea, &mRenderArea);
3451 
3452     // Remove invalidates that are no longer applicable.
3453     mDepthAttachment.onRenderAreaGrowth(contextVk, mRenderArea);
3454     mStencilAttachment.onRenderAreaGrowth(contextVk, mRenderArea);
3455 }
3456 
attachCommandPool(ErrorContext * context,SecondaryCommandPool * commandPool)3457 angle::Result RenderPassCommandBufferHelper::attachCommandPool(ErrorContext *context,
3458                                                                SecondaryCommandPool *commandPool)
3459 {
3460     ASSERT(!mRenderPassStarted);
3461     ASSERT(getSubpassCommandBufferCount() == 1);
3462     return attachCommandPoolImpl<RenderPassCommandBufferHelper>(context, commandPool);
3463 }
3464 
detachCommandPool(SecondaryCommandPool ** commandPoolOut)3465 void RenderPassCommandBufferHelper::detachCommandPool(SecondaryCommandPool **commandPoolOut)
3466 {
3467     ASSERT(mRenderPassStarted);
3468     angle::Result result =
3469         detachCommandPoolImpl<RenderPassCommandBufferHelper, true>(nullptr, commandPoolOut);
3470     ASSERT(result == angle::Result::Continue);
3471 }
3472 
releaseCommandPool()3473 void RenderPassCommandBufferHelper::releaseCommandPool()
3474 {
3475     ASSERT(!mRenderPassStarted);
3476     ASSERT(getSubpassCommandBufferCount() == 1);
3477     releaseCommandPoolImpl<RenderPassCommandBufferHelper>();
3478 }
3479 
attachAllocator(SecondaryCommandMemoryAllocator * allocator)3480 void RenderPassCommandBufferHelper::attachAllocator(SecondaryCommandMemoryAllocator *allocator)
3481 {
3482     ASSERT(CheckSubpassCommandBufferCount(getSubpassCommandBufferCount()));
3483     attachAllocatorImpl<RenderPassCommandBufferHelper>(allocator);
3484 }
3485 
detachAllocator()3486 SecondaryCommandMemoryAllocator *RenderPassCommandBufferHelper::detachAllocator()
3487 {
3488     ASSERT(CheckSubpassCommandBufferCount(getSubpassCommandBufferCount()));
3489     return detachAllocatorImpl<RenderPassCommandBufferHelper>();
3490 }
3491 
assertCanBeRecycled()3492 void RenderPassCommandBufferHelper::assertCanBeRecycled()
3493 {
3494     ASSERT(!mRenderPassStarted);
3495     ASSERT(getSubpassCommandBufferCount() == 1);
3496     assertCanBeRecycledImpl<RenderPassCommandBufferHelper>();
3497 }
3498 
getCommandDiagnostics()3499 std::string RenderPassCommandBufferHelper::getCommandDiagnostics()
3500 {
3501     std::ostringstream out;
3502     addCommandDiagnosticsCommon(&out);
3503 
3504     size_t attachmentCount             = mRenderPassDesc.clearableAttachmentCount();
3505     size_t depthStencilAttachmentCount = mRenderPassDesc.hasDepthStencilAttachment() ? 1 : 0;
3506     size_t colorAttachmentCount        = attachmentCount - depthStencilAttachmentCount;
3507 
3508     PackedAttachmentIndex attachmentIndexVk(0);
3509     std::string loadOps, storeOps;
3510 
3511     if (colorAttachmentCount > 0)
3512     {
3513         loadOps += " Color: ";
3514         storeOps += " Color: ";
3515 
3516         for (size_t i = 0; i < colorAttachmentCount; ++i)
3517         {
3518             loadOps += GetLoadOpShorthand(
3519                 static_cast<RenderPassLoadOp>(mAttachmentOps[attachmentIndexVk].loadOp));
3520             storeOps += GetStoreOpShorthand(
3521                 static_cast<RenderPassStoreOp>(mAttachmentOps[attachmentIndexVk].storeOp));
3522             ++attachmentIndexVk;
3523         }
3524     }
3525 
3526     if (depthStencilAttachmentCount > 0)
3527     {
3528         ASSERT(depthStencilAttachmentCount == 1);
3529 
3530         loadOps += " Depth/Stencil: ";
3531         storeOps += " Depth/Stencil: ";
3532 
3533         loadOps += GetLoadOpShorthand(
3534             static_cast<RenderPassLoadOp>(mAttachmentOps[attachmentIndexVk].loadOp));
3535         loadOps += GetLoadOpShorthand(
3536             static_cast<RenderPassLoadOp>(mAttachmentOps[attachmentIndexVk].stencilLoadOp));
3537 
3538         storeOps += GetStoreOpShorthand(
3539             static_cast<RenderPassStoreOp>(mAttachmentOps[attachmentIndexVk].storeOp));
3540         storeOps += GetStoreOpShorthand(
3541             static_cast<RenderPassStoreOp>(mAttachmentOps[attachmentIndexVk].stencilStoreOp));
3542     }
3543 
3544     if (attachmentCount > 0)
3545     {
3546         out << "LoadOp:  " << loadOps << "\\l";
3547         out << "StoreOp: " << storeOps << "\\l";
3548     }
3549 
3550     for (uint32_t subpass = 0; subpass < getSubpassCommandBufferCount(); ++subpass)
3551     {
3552         if (subpass > 0)
3553         {
3554             out << "Next Subpass" << "\\l";
3555         }
3556         out << mCommandBuffers[subpass].dumpCommands("\\l");
3557     }
3558 
3559     return out.str();
3560 }
3561 
3562 // CommandBufferRecycler implementation.
3563 template <typename CommandBufferHelperT>
onDestroy()3564 void CommandBufferRecycler<CommandBufferHelperT>::onDestroy()
3565 {
3566     std::unique_lock<angle::SimpleMutex> lock(mMutex);
3567     for (CommandBufferHelperT *commandBufferHelper : mCommandBufferHelperFreeList)
3568     {
3569         SafeDelete(commandBufferHelper);
3570     }
3571     mCommandBufferHelperFreeList.clear();
3572 }
3573 
3574 template void CommandBufferRecycler<OutsideRenderPassCommandBufferHelper>::onDestroy();
3575 template void CommandBufferRecycler<RenderPassCommandBufferHelper>::onDestroy();
3576 
3577 template <typename CommandBufferHelperT>
getCommandBufferHelper(ErrorContext * context,SecondaryCommandPool * commandPool,SecondaryCommandMemoryAllocator * commandsAllocator,CommandBufferHelperT ** commandBufferHelperOut)3578 angle::Result CommandBufferRecycler<CommandBufferHelperT>::getCommandBufferHelper(
3579     ErrorContext *context,
3580     SecondaryCommandPool *commandPool,
3581     SecondaryCommandMemoryAllocator *commandsAllocator,
3582     CommandBufferHelperT **commandBufferHelperOut)
3583 {
3584     std::unique_lock<angle::SimpleMutex> lock(mMutex);
3585     if (mCommandBufferHelperFreeList.empty())
3586     {
3587         CommandBufferHelperT *commandBuffer = new CommandBufferHelperT();
3588         *commandBufferHelperOut             = commandBuffer;
3589         ANGLE_TRY(commandBuffer->initialize(context));
3590     }
3591     else
3592     {
3593         CommandBufferHelperT *commandBuffer = mCommandBufferHelperFreeList.back();
3594         mCommandBufferHelperFreeList.pop_back();
3595         *commandBufferHelperOut = commandBuffer;
3596     }
3597 
3598     ANGLE_TRY((*commandBufferHelperOut)->attachCommandPool(context, commandPool));
3599 
3600     // Attach functions are only used for ring buffer allocators.
3601     (*commandBufferHelperOut)->attachAllocator(commandsAllocator);
3602 
3603     return angle::Result::Continue;
3604 }
3605 
3606 template angle::Result
3607 CommandBufferRecycler<OutsideRenderPassCommandBufferHelper>::getCommandBufferHelper(
3608     ErrorContext *,
3609     SecondaryCommandPool *,
3610     SecondaryCommandMemoryAllocator *,
3611     OutsideRenderPassCommandBufferHelper **);
3612 template angle::Result CommandBufferRecycler<RenderPassCommandBufferHelper>::getCommandBufferHelper(
3613     ErrorContext *,
3614     SecondaryCommandPool *,
3615     SecondaryCommandMemoryAllocator *,
3616     RenderPassCommandBufferHelper **);
3617 
3618 template <typename CommandBufferHelperT>
recycleCommandBufferHelper(CommandBufferHelperT ** commandBuffer)3619 void CommandBufferRecycler<CommandBufferHelperT>::recycleCommandBufferHelper(
3620     CommandBufferHelperT **commandBuffer)
3621 {
3622     (*commandBuffer)->assertCanBeRecycled();
3623     (*commandBuffer)->markOpen();
3624 
3625     {
3626         std::unique_lock<angle::SimpleMutex> lock(mMutex);
3627         mCommandBufferHelperFreeList.push_back(*commandBuffer);
3628     }
3629 
3630     *commandBuffer = nullptr;
3631 }
3632 
3633 template void
3634 CommandBufferRecycler<OutsideRenderPassCommandBufferHelper>::recycleCommandBufferHelper(
3635     OutsideRenderPassCommandBufferHelper **);
3636 template void CommandBufferRecycler<RenderPassCommandBufferHelper>::recycleCommandBufferHelper(
3637     RenderPassCommandBufferHelper **);
3638 
3639 // SecondaryCommandBufferCollector implementation.
collectCommandBuffer(priv::SecondaryCommandBuffer && commandBuffer)3640 void SecondaryCommandBufferCollector::collectCommandBuffer(
3641     priv::SecondaryCommandBuffer &&commandBuffer)
3642 {
3643     commandBuffer.reset();
3644 }
3645 
collectCommandBuffer(VulkanSecondaryCommandBuffer && commandBuffer)3646 void SecondaryCommandBufferCollector::collectCommandBuffer(
3647     VulkanSecondaryCommandBuffer &&commandBuffer)
3648 {
3649     ASSERT(commandBuffer.valid());
3650     mCollectedCommandBuffers.emplace_back(std::move(commandBuffer));
3651 }
3652 
releaseCommandBuffers()3653 void SecondaryCommandBufferCollector::releaseCommandBuffers()
3654 {
3655     // Note: we currently free the command buffers individually, but we could potentially reset the
3656     // entire command pool.  https://issuetracker.google.com/issues/166793850
3657     for (VulkanSecondaryCommandBuffer &commandBuffer : mCollectedCommandBuffers)
3658     {
3659         commandBuffer.destroy();
3660     }
3661     mCollectedCommandBuffers.clear();
3662 }
3663 
3664 // DynamicBuffer implementation.
DynamicBuffer()3665 DynamicBuffer::DynamicBuffer()
3666     : mUsage(0),
3667       mHostVisible(false),
3668       mInitialSize(0),
3669       mNextAllocationOffset(0),
3670       mSize(0),
3671       mSizeInRecentHistory(0),
3672       mAlignment(0),
3673       mMemoryPropertyFlags(0)
3674 {}
3675 
DynamicBuffer(DynamicBuffer && other)3676 DynamicBuffer::DynamicBuffer(DynamicBuffer &&other)
3677     : mUsage(other.mUsage),
3678       mHostVisible(other.mHostVisible),
3679       mInitialSize(other.mInitialSize),
3680       mBuffer(std::move(other.mBuffer)),
3681       mNextAllocationOffset(other.mNextAllocationOffset),
3682       mSize(other.mSize),
3683       mSizeInRecentHistory(other.mSizeInRecentHistory),
3684       mAlignment(other.mAlignment),
3685       mMemoryPropertyFlags(other.mMemoryPropertyFlags),
3686       mInFlightBuffers(std::move(other.mInFlightBuffers)),
3687       mBufferFreeList(std::move(other.mBufferFreeList))
3688 {}
3689 
init(Renderer * renderer,VkBufferUsageFlags usage,size_t alignment,size_t initialSize,bool hostVisible)3690 void DynamicBuffer::init(Renderer *renderer,
3691                          VkBufferUsageFlags usage,
3692                          size_t alignment,
3693                          size_t initialSize,
3694                          bool hostVisible)
3695 {
3696     mUsage       = usage;
3697     mHostVisible = hostVisible;
3698     mMemoryPropertyFlags =
3699         (hostVisible) ? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT : VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
3700 
3701     if (hostVisible && renderer->getFeatures().preferHostCachedForNonStaticBufferUsage.enabled)
3702     {
3703         mMemoryPropertyFlags |= VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
3704     }
3705 
3706     // Check that we haven't overridden the initial size of the buffer in setMinimumSizeForTesting.
3707     if (mInitialSize == 0)
3708     {
3709         mInitialSize         = initialSize;
3710         mSize                = 0;
3711         mSizeInRecentHistory = initialSize;
3712     }
3713 
3714     // Workaround for the mock ICD not supporting allocations greater than 0x1000.
3715     // Could be removed if https://github.com/KhronosGroup/Vulkan-Tools/issues/84 is fixed.
3716     if (renderer->isMockICDEnabled())
3717     {
3718         mSize = std::min<size_t>(mSize, 0x1000);
3719     }
3720 
3721     requireAlignment(renderer, alignment);
3722 }
3723 
~DynamicBuffer()3724 DynamicBuffer::~DynamicBuffer()
3725 {
3726     ASSERT(mBuffer == nullptr);
3727     ASSERT(mInFlightBuffers.empty());
3728     ASSERT(mBufferFreeList.empty());
3729 }
3730 
allocateNewBuffer(ErrorContext * context)3731 angle::Result DynamicBuffer::allocateNewBuffer(ErrorContext *context)
3732 {
3733     context->getPerfCounters().dynamicBufferAllocations++;
3734 
3735     // Allocate the buffer
3736     ASSERT(!mBuffer);
3737     mBuffer = std::make_unique<BufferHelper>();
3738 
3739     VkBufferCreateInfo createInfo    = {};
3740     createInfo.sType                 = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
3741     createInfo.flags                 = 0;
3742     createInfo.size                  = mSize;
3743     createInfo.usage                 = mUsage;
3744     createInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
3745     createInfo.queueFamilyIndexCount = 0;
3746     createInfo.pQueueFamilyIndices   = nullptr;
3747 
3748     return mBuffer->init(context, createInfo, mMemoryPropertyFlags);
3749 }
3750 
allocateFromCurrentBuffer(size_t sizeInBytes,BufferHelper ** bufferHelperOut)3751 bool DynamicBuffer::allocateFromCurrentBuffer(size_t sizeInBytes, BufferHelper **bufferHelperOut)
3752 {
3753     mNextAllocationOffset =
3754         roundUp<uint32_t>(mNextAllocationOffset, static_cast<uint32_t>(mAlignment));
3755 
3756     ASSERT(bufferHelperOut);
3757     size_t sizeToAllocate                                      = roundUp(sizeInBytes, mAlignment);
3758     angle::base::CheckedNumeric<size_t> checkedNextWriteOffset = mNextAllocationOffset;
3759     checkedNextWriteOffset += sizeToAllocate;
3760 
3761     if (!checkedNextWriteOffset.IsValid() || checkedNextWriteOffset.ValueOrDie() > mSize)
3762     {
3763         return false;
3764     }
3765 
3766     ASSERT(mBuffer != nullptr);
3767     ASSERT(mHostVisible);
3768     ASSERT(mBuffer->getMappedMemory());
3769     mBuffer->setSuballocationOffsetAndSize(mNextAllocationOffset, sizeToAllocate);
3770     *bufferHelperOut = mBuffer.get();
3771 
3772     mNextAllocationOffset += static_cast<uint32_t>(sizeToAllocate);
3773     return true;
3774 }
3775 
allocate(Context * context,size_t sizeInBytes,BufferHelper ** bufferHelperOut,bool * newBufferAllocatedOut)3776 angle::Result DynamicBuffer::allocate(Context *context,
3777                                       size_t sizeInBytes,
3778                                       BufferHelper **bufferHelperOut,
3779                                       bool *newBufferAllocatedOut)
3780 {
3781     bool newBuffer = !allocateFromCurrentBuffer(sizeInBytes, bufferHelperOut);
3782     if (newBufferAllocatedOut)
3783     {
3784         *newBufferAllocatedOut = newBuffer;
3785     }
3786 
3787     if (!newBuffer)
3788     {
3789         return angle::Result::Continue;
3790     }
3791 
3792     size_t sizeToAllocate = roundUp(sizeInBytes, mAlignment);
3793 
3794     if (mBuffer)
3795     {
3796         // Make sure the buffer is not released externally.
3797         ASSERT(mBuffer->valid());
3798         mInFlightBuffers.push_back(std::move(mBuffer));
3799         ASSERT(!mBuffer);
3800     }
3801 
3802     Renderer *renderer = context->getRenderer();
3803 
3804     const size_t minRequiredBlockSize = std::max(mInitialSize, sizeToAllocate);
3805 
3806     // The average required buffer size in recent history is used to determine whether the currently
3807     // used buffer size needs to be reduced (when it goes below 1/8 of the current buffer size).
3808     constexpr uint32_t kDecayCoeffPercent = 20;
3809     static_assert(kDecayCoeffPercent >= 0 && kDecayCoeffPercent <= 100);
3810     mSizeInRecentHistory = (mSizeInRecentHistory * kDecayCoeffPercent +
3811                             minRequiredBlockSize * (100 - kDecayCoeffPercent) + 50) /
3812                            100;
3813 
3814     if (sizeToAllocate > mSize || mSizeInRecentHistory < mSize / 8)
3815     {
3816         mSize = minRequiredBlockSize;
3817         // Clear the free list since the free buffers are now either too small or too big.
3818         ReleaseBufferListToRenderer(context, &mBufferFreeList);
3819     }
3820 
3821     // The front of the free list should be the oldest. Thus if it is in use the rest of the
3822     // free list should be in use as well.
3823     if (mBufferFreeList.empty() ||
3824         !renderer->hasResourceUseFinished(mBufferFreeList.front()->getResourceUse()))
3825     {
3826         ANGLE_TRY(allocateNewBuffer(context));
3827     }
3828     else
3829     {
3830         mBuffer = std::move(mBufferFreeList.front());
3831         mBufferFreeList.pop_front();
3832     }
3833 
3834     ASSERT(mBuffer->getBlockMemorySize() == mSize);
3835 
3836     mNextAllocationOffset = 0;
3837 
3838     ASSERT(mBuffer != nullptr);
3839     mBuffer->setSuballocationOffsetAndSize(mNextAllocationOffset, sizeToAllocate);
3840     *bufferHelperOut = mBuffer.get();
3841 
3842     mNextAllocationOffset += static_cast<uint32_t>(sizeToAllocate);
3843     return angle::Result::Continue;
3844 }
3845 
release(Context * context)3846 void DynamicBuffer::release(Context *context)
3847 {
3848     reset();
3849 
3850     ReleaseBufferListToRenderer(context, &mInFlightBuffers);
3851     ReleaseBufferListToRenderer(context, &mBufferFreeList);
3852 
3853     if (mBuffer)
3854     {
3855         mBuffer->release(context);
3856         mBuffer.reset(nullptr);
3857     }
3858 }
3859 
updateQueueSerialAndReleaseInFlightBuffers(ContextVk * contextVk,const QueueSerial & queueSerial)3860 void DynamicBuffer::updateQueueSerialAndReleaseInFlightBuffers(ContextVk *contextVk,
3861                                                                const QueueSerial &queueSerial)
3862 {
3863     for (std::unique_ptr<BufferHelper> &bufferHelper : mInFlightBuffers)
3864     {
3865         // This function is used only for internal buffers, and they are all read-only.
3866         // It's possible this may change in the future, but there isn't a good way to detect that,
3867         // unfortunately.
3868         bufferHelper->setQueueSerial(queueSerial);
3869 
3870         // We only keep free buffers that have the same size. Note that bufferHelper's size is
3871         // suballocation's size. We need to use the whole block memory size here.
3872         if (bufferHelper->getBlockMemorySize() != mSize)
3873         {
3874             bufferHelper->release(contextVk);
3875         }
3876         else
3877         {
3878             mBufferFreeList.push_back(std::move(bufferHelper));
3879         }
3880     }
3881     mInFlightBuffers.clear();
3882 }
3883 
destroy(Renderer * renderer)3884 void DynamicBuffer::destroy(Renderer *renderer)
3885 {
3886     reset();
3887 
3888     DestroyBufferList(renderer, &mInFlightBuffers);
3889     DestroyBufferList(renderer, &mBufferFreeList);
3890 
3891     if (mBuffer)
3892     {
3893         mBuffer->unmap(renderer);
3894         mBuffer->destroy(renderer);
3895         mBuffer.reset(nullptr);
3896     }
3897 }
3898 
requireAlignment(Renderer * renderer,size_t alignment)3899 void DynamicBuffer::requireAlignment(Renderer *renderer, size_t alignment)
3900 {
3901     ASSERT(alignment > 0);
3902 
3903     size_t prevAlignment = mAlignment;
3904 
3905     // If alignment was never set, initialize it with the atom size limit.
3906     if (prevAlignment == 0)
3907     {
3908         prevAlignment =
3909             static_cast<size_t>(renderer->getPhysicalDeviceProperties().limits.nonCoherentAtomSize);
3910         ASSERT(gl::isPow2(prevAlignment));
3911     }
3912 
3913     // We need lcm(prevAlignment, alignment).  Usually, one divides the other so std::max() could be
3914     // used instead.  Only known case where this assumption breaks is for 3-component types with
3915     // 16- or 32-bit channels, so that's special-cased to avoid a full-fledged lcm implementation.
3916 
3917     if (gl::isPow2(prevAlignment * alignment))
3918     {
3919         ASSERT(alignment % prevAlignment == 0 || prevAlignment % alignment == 0);
3920 
3921         alignment = std::max(prevAlignment, alignment);
3922     }
3923     else
3924     {
3925         ASSERT(prevAlignment % 3 != 0 || gl::isPow2(prevAlignment / 3));
3926         ASSERT(alignment % 3 != 0 || gl::isPow2(alignment / 3));
3927 
3928         prevAlignment = prevAlignment % 3 == 0 ? prevAlignment / 3 : prevAlignment;
3929         alignment     = alignment % 3 == 0 ? alignment / 3 : alignment;
3930 
3931         alignment = std::max(prevAlignment, alignment) * 3;
3932     }
3933 
3934     // If alignment has changed, make sure the next allocation is done at an aligned offset.
3935     if (alignment != mAlignment)
3936     {
3937         mNextAllocationOffset = roundUp(mNextAllocationOffset, static_cast<uint32_t>(alignment));
3938     }
3939 
3940     mAlignment = alignment;
3941 }
3942 
setMinimumSizeForTesting(size_t minSize)3943 void DynamicBuffer::setMinimumSizeForTesting(size_t minSize)
3944 {
3945     // This will really only have an effect next time we call allocate.
3946     mInitialSize = minSize;
3947 
3948     // Forces a new allocation on the next allocate.
3949     mSize                = 0;
3950     mSizeInRecentHistory = 0;
3951 }
3952 
reset()3953 void DynamicBuffer::reset()
3954 {
3955     mSize                 = 0;
3956     mSizeInRecentHistory  = 0;
3957     mNextAllocationOffset = 0;
3958 }
3959 
3960 // BufferPool implementation.
BufferPool()3961 BufferPool::BufferPool()
3962     : mVirtualBlockCreateFlags(vma::VirtualBlockCreateFlagBits::GENERAL),
3963       mUsage(0),
3964       mHostVisible(false),
3965       mSize(0),
3966       mMemoryTypeIndex(0),
3967       mTotalMemorySize(0),
3968       mNumberOfNewBuffersNeededSinceLastPrune(0)
3969 {}
3970 
BufferPool(BufferPool && other)3971 BufferPool::BufferPool(BufferPool &&other)
3972     : mVirtualBlockCreateFlags(other.mVirtualBlockCreateFlags),
3973       mUsage(other.mUsage),
3974       mHostVisible(other.mHostVisible),
3975       mSize(other.mSize),
3976       mMemoryTypeIndex(other.mMemoryTypeIndex)
3977 {}
3978 
initWithFlags(Renderer * renderer,vma::VirtualBlockCreateFlags flags,VkBufferUsageFlags usage,VkDeviceSize initialSize,uint32_t memoryTypeIndex,VkMemoryPropertyFlags memoryPropertyFlags)3979 void BufferPool::initWithFlags(Renderer *renderer,
3980                                vma::VirtualBlockCreateFlags flags,
3981                                VkBufferUsageFlags usage,
3982                                VkDeviceSize initialSize,
3983                                uint32_t memoryTypeIndex,
3984                                VkMemoryPropertyFlags memoryPropertyFlags)
3985 {
3986     mVirtualBlockCreateFlags = flags;
3987     mUsage                   = usage;
3988     mMemoryTypeIndex         = memoryTypeIndex;
3989     if (initialSize)
3990     {
3991         // Should be power of two
3992         ASSERT(gl::isPow2(initialSize));
3993         mSize = initialSize;
3994     }
3995     else
3996     {
3997         mSize = renderer->getPreferedBufferBlockSize(memoryTypeIndex);
3998     }
3999     mHostVisible = ((memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0);
4000     mBufferBlocks.reserve(32);
4001 }
4002 
~BufferPool()4003 BufferPool::~BufferPool()
4004 {
4005     ASSERT(mBufferBlocks.empty());
4006     ASSERT(mEmptyBufferBlocks.empty());
4007 }
4008 
pruneEmptyBuffers(Renderer * renderer)4009 void BufferPool::pruneEmptyBuffers(Renderer *renderer)
4010 {
4011     // Walk through mBuffers and move empty buffers to mEmptyBuffer and remove null
4012     // pointers for allocation performance.
4013     bool needsCompact = false;
4014     size_t nonEmptyBufferCount = 0;
4015     for (std::unique_ptr<BufferBlock> &block : mBufferBlocks)
4016     {
4017         if (block->isEmpty())
4018         {
4019             // We will always free empty buffers that has smaller size. Or if the empty buffer has
4020             // been found empty for long enough time, or we accumulated too many empty buffers, we
4021             // also free it.
4022             if (block->getMemorySize() < mSize)
4023             {
4024                 mTotalMemorySize -= block->getMemorySize();
4025                 block->destroy(renderer);
4026                 block.reset();
4027             }
4028             else
4029             {
4030                 mEmptyBufferBlocks.push_back(std::move(block));
4031             }
4032             needsCompact = true;
4033         }
4034         else
4035         {
4036             if (needsCompact)
4037             {
4038                 mBufferBlocks[nonEmptyBufferCount] = std::move(block);
4039             }
4040             nonEmptyBufferCount++;
4041         }
4042     }
4043 
4044     if (needsCompact)
4045     {
4046         mBufferBlocks.resize(nonEmptyBufferCount);
4047     }
4048 
4049     // Decide how many empty buffers to keep around and trim down the excessive empty buffers. We
4050     // keep track of how many buffers are needed since last prune. Assume we are in stable state,
4051     // which means we may still need that many empty buffers in next prune cycle. To reduce chance
4052     // to call into vulkan driver to allocate new buffers, we try to keep that many empty buffers
4053     // around, subject to the maximum cap. If we overestimate, next cycle they used fewer buffers,
4054     // we will trim excessive empty buffers at next prune call. Or if we underestimate, we will end
4055     // up have to call into vulkan driver allocate new buffers, but next cycle we should correct
4056     // ourselves to keep enough number of empty buffers around.
4057     size_t buffersToKeep = std::min(mNumberOfNewBuffersNeededSinceLastPrune,
4058                                     static_cast<size_t>(kMaxTotalEmptyBufferBytes / mSize));
4059     while (mEmptyBufferBlocks.size() > buffersToKeep)
4060     {
4061         std::unique_ptr<BufferBlock> &block = mEmptyBufferBlocks.back();
4062         mTotalMemorySize -= block->getMemorySize();
4063         block->destroy(renderer);
4064         mEmptyBufferBlocks.pop_back();
4065     }
4066     mNumberOfNewBuffersNeededSinceLastPrune = 0;
4067 }
4068 
allocateNewBuffer(ErrorContext * context,VkDeviceSize sizeInBytes)4069 VkResult BufferPool::allocateNewBuffer(ErrorContext *context, VkDeviceSize sizeInBytes)
4070 {
4071     Renderer *renderer         = context->getRenderer();
4072     const Allocator &allocator = renderer->getAllocator();
4073 
4074     VkDeviceSize heapSize =
4075         renderer->getMemoryProperties().getHeapSizeForMemoryType(mMemoryTypeIndex);
4076 
4077     // First ensure we are not exceeding the heapSize to avoid the validation error.
4078     VK_RESULT_CHECK(sizeInBytes <= heapSize, VK_ERROR_OUT_OF_DEVICE_MEMORY);
4079 
4080     // Double the size until meet the requirement. This also helps reducing the fragmentation. Since
4081     // this is global pool, we have less worry about memory waste.
4082     VkDeviceSize newSize = mSize;
4083     while (newSize < sizeInBytes)
4084     {
4085         newSize <<= 1;
4086     }
4087     mSize = std::min(newSize, heapSize);
4088 
4089     // Allocate buffer
4090     VkBufferCreateInfo createInfo    = {};
4091     createInfo.sType                 = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4092     createInfo.flags                 = 0;
4093     createInfo.size                  = mSize;
4094     createInfo.usage                 = mUsage;
4095     createInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
4096     createInfo.queueFamilyIndexCount = 0;
4097     createInfo.pQueueFamilyIndices   = nullptr;
4098 
4099     VkMemoryPropertyFlags memoryPropertyFlags;
4100     allocator.getMemoryTypeProperties(mMemoryTypeIndex, &memoryPropertyFlags);
4101 
4102     DeviceScoped<Buffer> buffer(renderer->getDevice());
4103     VK_RESULT_TRY(buffer.get().init(context->getDevice(), createInfo));
4104 
4105     DeviceScoped<DeviceMemory> deviceMemory(renderer->getDevice());
4106     VkMemoryPropertyFlags memoryPropertyFlagsOut;
4107     VkDeviceSize sizeOut;
4108     uint32_t memoryTypeIndex;
4109     VK_RESULT_TRY(AllocateBufferMemory(context, MemoryAllocationType::Buffer, memoryPropertyFlags,
4110                                        &memoryPropertyFlagsOut, nullptr, &buffer.get(),
4111                                        &memoryTypeIndex, &deviceMemory.get(), &sizeOut));
4112     ASSERT(sizeOut >= mSize);
4113 
4114     // Allocate bufferBlock
4115     std::unique_ptr<BufferBlock> block = std::make_unique<BufferBlock>();
4116     VK_RESULT_TRY(block->init(context, buffer.get(), memoryTypeIndex, mVirtualBlockCreateFlags,
4117                               deviceMemory.get(), memoryPropertyFlagsOut, mSize));
4118 
4119     if (mHostVisible)
4120     {
4121         VK_RESULT_TRY(block->map(context->getDevice()));
4122     }
4123 
4124     mTotalMemorySize += block->getMemorySize();
4125     // Append the bufferBlock into the pool
4126     mBufferBlocks.push_back(std::move(block));
4127     context->getPerfCounters().allocateNewBufferBlockCalls++;
4128 
4129     return VK_SUCCESS;
4130 }
4131 
allocateBuffer(ErrorContext * context,VkDeviceSize sizeInBytes,VkDeviceSize alignment,BufferSuballocation * suballocation)4132 VkResult BufferPool::allocateBuffer(ErrorContext *context,
4133                                     VkDeviceSize sizeInBytes,
4134                                     VkDeviceSize alignment,
4135                                     BufferSuballocation *suballocation)
4136 {
4137     ASSERT(alignment);
4138     VmaVirtualAllocation allocation;
4139     VkDeviceSize offset;
4140     VkDeviceSize alignedSize = roundUp(sizeInBytes, alignment);
4141 
4142     if (alignedSize >= kMaxBufferSizeForSuballocation)
4143     {
4144         VkDeviceSize heapSize =
4145             context->getRenderer()->getMemoryProperties().getHeapSizeForMemoryType(
4146                 mMemoryTypeIndex);
4147         // First ensure we are not exceeding the heapSize to avoid the validation error.
4148         VK_RESULT_CHECK(sizeInBytes <= heapSize, VK_ERROR_OUT_OF_DEVICE_MEMORY);
4149 
4150         // Allocate buffer
4151         VkBufferCreateInfo createInfo    = {};
4152         createInfo.sType                 = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4153         createInfo.flags                 = 0;
4154         createInfo.size                  = alignedSize;
4155         createInfo.usage                 = mUsage;
4156         createInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
4157         createInfo.queueFamilyIndexCount = 0;
4158         createInfo.pQueueFamilyIndices   = nullptr;
4159 
4160         VkMemoryPropertyFlags memoryPropertyFlags;
4161         const Allocator &allocator = context->getRenderer()->getAllocator();
4162         allocator.getMemoryTypeProperties(mMemoryTypeIndex, &memoryPropertyFlags);
4163 
4164         DeviceScoped<Buffer> buffer(context->getDevice());
4165         VK_RESULT_TRY(buffer.get().init(context->getDevice(), createInfo));
4166 
4167         DeviceScoped<DeviceMemory> deviceMemory(context->getDevice());
4168         VkMemoryPropertyFlags memoryPropertyFlagsOut;
4169         VkDeviceSize sizeOut;
4170         uint32_t memoryTypeIndex;
4171         VK_RESULT_TRY(AllocateBufferMemory(
4172             context, MemoryAllocationType::Buffer, memoryPropertyFlags, &memoryPropertyFlagsOut,
4173             nullptr, &buffer.get(), &memoryTypeIndex, &deviceMemory.get(), &sizeOut));
4174         ASSERT(sizeOut >= alignedSize);
4175 
4176         suballocation->initWithEntireBuffer(context, buffer.get(), MemoryAllocationType::Buffer,
4177                                             memoryTypeIndex, deviceMemory.get(),
4178                                             memoryPropertyFlagsOut, alignedSize, sizeOut);
4179         if (mHostVisible)
4180         {
4181             VK_RESULT_TRY(suballocation->map(context));
4182         }
4183         return VK_SUCCESS;
4184     }
4185 
4186     // We always allocate from reverse order so that older buffers have a chance to be empty. The
4187     // assumption is that to allocate from new buffers first may have a better chance to leave the
4188     // older buffers completely empty and we may able to free it.
4189     for (auto iter = mBufferBlocks.rbegin(); iter != mBufferBlocks.rend();)
4190     {
4191         std::unique_ptr<BufferBlock> &block = *iter;
4192         if (block->isEmpty() && block->getMemorySize() < mSize)
4193         {
4194             // Don't try to allocate from an empty buffer that has smaller size. It will get
4195             // released when pruneEmptyBuffers get called later on.
4196             ++iter;
4197             continue;
4198         }
4199 
4200         if (block->allocate(alignedSize, alignment, &allocation, &offset) == VK_SUCCESS)
4201         {
4202             suballocation->init(block.get(), allocation, offset, alignedSize);
4203             return VK_SUCCESS;
4204         }
4205         ++iter;
4206     }
4207 
4208     // Try to allocate from empty buffers
4209     while (!mEmptyBufferBlocks.empty())
4210     {
4211         std::unique_ptr<BufferBlock> &block = mEmptyBufferBlocks.back();
4212         if (block->getMemorySize() < mSize)
4213         {
4214             mTotalMemorySize -= block->getMemorySize();
4215             block->destroy(context->getRenderer());
4216             mEmptyBufferBlocks.pop_back();
4217         }
4218         else
4219         {
4220             VK_RESULT_TRY(block->allocate(alignedSize, alignment, &allocation, &offset));
4221             suballocation->init(block.get(), allocation, offset, alignedSize);
4222             mBufferBlocks.push_back(std::move(block));
4223             mEmptyBufferBlocks.pop_back();
4224             mNumberOfNewBuffersNeededSinceLastPrune++;
4225             return VK_SUCCESS;
4226         }
4227     }
4228 
4229     // Failed to allocate from empty buffer. Now try to allocate a new buffer.
4230     VK_RESULT_TRY(allocateNewBuffer(context, alignedSize));
4231 
4232     // Sub-allocate from the bufferBlock.
4233     std::unique_ptr<BufferBlock> &block = mBufferBlocks.back();
4234     VK_RESULT_CHECK(block->allocate(alignedSize, alignment, &allocation, &offset) == VK_SUCCESS,
4235                     VK_ERROR_OUT_OF_DEVICE_MEMORY);
4236     suballocation->init(block.get(), allocation, offset, alignedSize);
4237     mNumberOfNewBuffersNeededSinceLastPrune++;
4238 
4239     return VK_SUCCESS;
4240 }
4241 
destroy(Renderer * renderer,bool orphanNonEmptyBufferBlock)4242 void BufferPool::destroy(Renderer *renderer, bool orphanNonEmptyBufferBlock)
4243 {
4244     for (std::unique_ptr<BufferBlock> &block : mBufferBlocks)
4245     {
4246         if (block->isEmpty())
4247         {
4248             block->destroy(renderer);
4249         }
4250         else
4251         {
4252             // When orphan is not allowed, all BufferBlocks must be empty.
4253             ASSERT(orphanNonEmptyBufferBlock);
4254             renderer->addBufferBlockToOrphanList(block.release());
4255         }
4256     }
4257     mBufferBlocks.clear();
4258 
4259     for (std::unique_ptr<BufferBlock> &block : mEmptyBufferBlocks)
4260     {
4261         block->destroy(renderer);
4262     }
4263     mEmptyBufferBlocks.clear();
4264 }
4265 
getTotalEmptyMemorySize() const4266 VkDeviceSize BufferPool::getTotalEmptyMemorySize() const
4267 {
4268     VkDeviceSize totalMemorySize = 0;
4269     for (const std::unique_ptr<BufferBlock> &block : mEmptyBufferBlocks)
4270     {
4271         totalMemorySize += block->getMemorySize();
4272     }
4273     return totalMemorySize;
4274 }
4275 
addStats(std::ostringstream * out) const4276 void BufferPool::addStats(std::ostringstream *out) const
4277 {
4278     VkDeviceSize totalUnusedBytes = 0;
4279     VkDeviceSize totalMemorySize  = 0;
4280     for (size_t i = 0; i < mBufferBlocks.size(); i++)
4281     {
4282         const std::unique_ptr<BufferBlock> &block = mBufferBlocks[i];
4283         vma::StatInfo statInfo;
4284         block->calculateStats(&statInfo);
4285         ASSERT(statInfo.basicInfo.blockCount == 1);
4286         INFO() << "[" << i << "]={" << " allocationCount:" << statInfo.basicInfo.allocationCount
4287                << " blockBytes:" << statInfo.basicInfo.blockBytes
4288                << " allocationBytes:" << statInfo.basicInfo.allocationBytes
4289                << " unusedRangeCount:" << statInfo.unusedRangeCount
4290                << " allocationSizeMin:" << statInfo.allocationSizeMin
4291                << " allocationSizeMax:" << statInfo.allocationSizeMax
4292                << " unusedRangeSizeMin:" << statInfo.unusedRangeSizeMin
4293                << " unusedRangeSizeMax:" << statInfo.unusedRangeSizeMax << " }";
4294         VkDeviceSize unusedBytes =
4295             statInfo.basicInfo.blockBytes - statInfo.basicInfo.allocationBytes;
4296         totalUnusedBytes += unusedBytes;
4297         totalMemorySize += block->getMemorySize();
4298     }
4299     *out << "mBufferBlocks.size():" << mBufferBlocks.size()
4300          << " totalUnusedBytes:" << totalUnusedBytes / 1024
4301          << "KB / totalMemorySize:" << totalMemorySize / 1024 << "KB";
4302     *out << " emptyBuffers [memorySize:" << getTotalEmptyMemorySize() / 1024 << "KB "
4303          << " count:" << mEmptyBufferBlocks.size()
4304          << " needed: " << mNumberOfNewBuffersNeededSinceLastPrune << "]";
4305 }
4306 
4307 // DescriptorSetHelper implementation.
destroy(VkDevice device)4308 void DescriptorSetHelper::destroy(VkDevice device)
4309 {
4310     if (valid())
4311     {
4312         // Since the pool is created without VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, we
4313         // don't call vkFreeDescriptorSets. We always add to garbage list so that it can be
4314         // recycled. Since we dont actually know if it is GPU completed, we always just add to the
4315         // pending garbage list assuming the worst case.
4316         DescriptorPoolPointer pool(device, mPool);
4317         DescriptorSetPointer garbage(device, std::move(*this));
4318         pool->addPendingGarbage(std::move(garbage));
4319         ASSERT(!valid());
4320     }
4321 }
4322 
4323 // DescriptorPoolHelper implementation.
DescriptorPoolHelper()4324 DescriptorPoolHelper::DescriptorPoolHelper()
4325     : mMaxDescriptorSets(0), mValidDescriptorSets(0), mFreeDescriptorSets(0)
4326 {}
4327 
~DescriptorPoolHelper()4328 DescriptorPoolHelper::~DescriptorPoolHelper()
4329 {
4330     ASSERT(mPendingGarbageList.empty());
4331     ASSERT(mFinishedGarbageList.empty());
4332 }
4333 
init(ErrorContext * context,const std::vector<VkDescriptorPoolSize> & poolSizesIn,uint32_t maxSets)4334 angle::Result DescriptorPoolHelper::init(ErrorContext *context,
4335                                          const std::vector<VkDescriptorPoolSize> &poolSizesIn,
4336                                          uint32_t maxSets)
4337 {
4338     Renderer *renderer = context->getRenderer();
4339 
4340     ASSERT(mPendingGarbageList.empty());
4341     ASSERT(mFinishedGarbageList.empty());
4342 
4343     if (mDescriptorPool.valid())
4344     {
4345         mDescriptorPool.destroy(renderer->getDevice());
4346     }
4347 
4348     // Make a copy of the pool sizes, so we can grow them to satisfy the specified maxSets.
4349     std::vector<VkDescriptorPoolSize> poolSizes = poolSizesIn;
4350 
4351     for (VkDescriptorPoolSize &poolSize : poolSizes)
4352     {
4353         poolSize.descriptorCount *= maxSets;
4354     }
4355 
4356     VkDescriptorPoolCreateInfo descriptorPoolInfo = {};
4357     descriptorPoolInfo.sType                      = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
4358     descriptorPoolInfo.flags                      = 0;
4359     descriptorPoolInfo.maxSets                    = maxSets;
4360     descriptorPoolInfo.poolSizeCount              = static_cast<uint32_t>(poolSizes.size());
4361     descriptorPoolInfo.pPoolSizes                 = poolSizes.data();
4362 
4363     mMaxDescriptorSets   = maxSets;
4364     mFreeDescriptorSets  = maxSets;
4365     mValidDescriptorSets = 0;
4366 
4367     ANGLE_VK_TRY(context, mDescriptorPool.init(renderer->getDevice(), descriptorPoolInfo));
4368 
4369     mRenderer = renderer;
4370 
4371     return angle::Result::Continue;
4372 }
4373 
destroy(VkDevice device)4374 void DescriptorPoolHelper::destroy(VkDevice device)
4375 {
4376     ASSERT(mValidDescriptorSets == 0);
4377     ASSERT(mPendingGarbageList.empty());
4378     ASSERT(mFinishedGarbageList.empty());
4379     mDescriptorPool.destroy(device);
4380 }
4381 
allocateVkDescriptorSet(ErrorContext * context,const DescriptorSetLayout & descriptorSetLayout,VkDescriptorSet * descriptorSetOut)4382 bool DescriptorPoolHelper::allocateVkDescriptorSet(ErrorContext *context,
4383                                                    const DescriptorSetLayout &descriptorSetLayout,
4384                                                    VkDescriptorSet *descriptorSetOut)
4385 {
4386     if (mFreeDescriptorSets > 0)
4387     {
4388         VkDescriptorSetAllocateInfo allocInfo = {};
4389         allocInfo.sType                       = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
4390         allocInfo.descriptorPool              = mDescriptorPool.getHandle();
4391         allocInfo.descriptorSetCount          = 1;
4392         allocInfo.pSetLayouts                 = descriptorSetLayout.ptr();
4393 
4394         VkResult result = mDescriptorPool.allocateDescriptorSets(context->getDevice(), allocInfo,
4395                                                                  descriptorSetOut);
4396         ++context->getPerfCounters().descriptorSetAllocations;
4397         // If fail, it means our own accounting has a bug.
4398         ASSERT(result == VK_SUCCESS);
4399         mFreeDescriptorSets--;
4400         mValidDescriptorSets++;
4401         return true;
4402     }
4403 
4404     return false;
4405 }
4406 
cleanupPendingGarbage()4407 void DescriptorPoolHelper::cleanupPendingGarbage()
4408 {
4409     while (!mPendingGarbageList.empty())
4410     {
4411         DescriptorSetPointer &garbage = mPendingGarbageList.front();
4412         if (!mRenderer->hasResourceUseFinished(garbage->getResourceUse()))
4413         {
4414             break;
4415         }
4416         mFinishedGarbageList.push_back(std::move(garbage));
4417         mPendingGarbageList.pop_front();
4418     }
4419 }
4420 
recycleFromGarbage(Renderer * renderer,DescriptorSetPointer * descriptorSetOut)4421 bool DescriptorPoolHelper::recycleFromGarbage(Renderer *renderer,
4422                                               DescriptorSetPointer *descriptorSetOut)
4423 {
4424     if (mFinishedGarbageList.empty())
4425     {
4426         cleanupPendingGarbage();
4427     }
4428 
4429     if (!mFinishedGarbageList.empty())
4430     {
4431         DescriptorSetPointer &garbage = mFinishedGarbageList.front();
4432         *descriptorSetOut             = std::move(garbage);
4433         mFinishedGarbageList.pop_front();
4434         mValidDescriptorSets++;
4435         return true;
4436     }
4437 
4438     return false;
4439 }
4440 
allocateDescriptorSet(ErrorContext * context,const DescriptorSetLayout & descriptorSetLayout,const DescriptorPoolPointer & pool,DescriptorSetPointer * descriptorSetOut)4441 bool DescriptorPoolHelper::allocateDescriptorSet(ErrorContext *context,
4442                                                  const DescriptorSetLayout &descriptorSetLayout,
4443                                                  const DescriptorPoolPointer &pool,
4444                                                  DescriptorSetPointer *descriptorSetOut)
4445 {
4446     ASSERT(pool.get() == this);
4447     VkDescriptorSet descriptorSet;
4448     if (allocateVkDescriptorSet(context, descriptorSetLayout, &descriptorSet))
4449     {
4450         DescriptorSetHelper helper = DescriptorSetHelper(descriptorSet, pool);
4451         *descriptorSetOut          = DescriptorSetPointer(context->getDevice(), std::move(helper));
4452         return true;
4453     }
4454     return false;
4455 }
4456 
destroyGarbage()4457 void DescriptorPoolHelper::destroyGarbage()
4458 {
4459     ASSERT(mPendingGarbageList.empty());
4460 
4461     while (!mFinishedGarbageList.empty())
4462     {
4463         DescriptorSetPointer &garbage = mFinishedGarbageList.front();
4464         ASSERT(garbage.unique());
4465         ASSERT(garbage->valid());
4466         // Because we do not use VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT when pool is
4467         // created, We can't free each individual descriptor set before destroying the pool, we
4468         // simply clear the descriptorSet and the mPool weak pointer so that
4469         // DescriptorSetHelper::destroy will not find it the garbage being valid  and try to add to
4470         // garbage list again.
4471         garbage->mDescriptorSet = VK_NULL_HANDLE;
4472         garbage->mPool.reset();
4473         ASSERT(!garbage->valid());
4474         mFinishedGarbageList.pop_front();
4475     }
4476 }
4477 
4478 // DynamicDescriptorPool implementation.
DynamicDescriptorPool()4479 DynamicDescriptorPool::DynamicDescriptorPool() : mCachedDescriptorSetLayout(VK_NULL_HANDLE)
4480 {
4481     mDescriptorPools.reserve(32);
4482 }
4483 
~DynamicDescriptorPool()4484 DynamicDescriptorPool::~DynamicDescriptorPool()
4485 {
4486     ASSERT(mLRUList.empty());
4487     ASSERT(mDescriptorSetCache.empty());
4488     ASSERT(mDescriptorPools.empty());
4489 }
4490 
DynamicDescriptorPool(DynamicDescriptorPool && other)4491 DynamicDescriptorPool::DynamicDescriptorPool(DynamicDescriptorPool &&other)
4492     : DynamicDescriptorPool()
4493 {
4494     *this = std::move(other);
4495 }
4496 
operator =(DynamicDescriptorPool && other)4497 DynamicDescriptorPool &DynamicDescriptorPool::operator=(DynamicDescriptorPool &&other)
4498 {
4499     std::swap(mDescriptorPools, other.mDescriptorPools);
4500     std::swap(mPoolSizes, other.mPoolSizes);
4501     std::swap(mCachedDescriptorSetLayout, other.mCachedDescriptorSetLayout);
4502     std::swap(mLRUList, other.mLRUList);
4503     std::swap(mDescriptorSetCache, other.mDescriptorSetCache);
4504     return *this;
4505 }
4506 
init(ErrorContext * context,const VkDescriptorPoolSize * setSizes,size_t setSizeCount,const DescriptorSetLayout & descriptorSetLayout)4507 angle::Result DynamicDescriptorPool::init(ErrorContext *context,
4508                                           const VkDescriptorPoolSize *setSizes,
4509                                           size_t setSizeCount,
4510                                           const DescriptorSetLayout &descriptorSetLayout)
4511 {
4512     ASSERT(setSizes);
4513     ASSERT(setSizeCount);
4514     ASSERT(mDescriptorPools.empty());
4515     ASSERT(mCachedDescriptorSetLayout == VK_NULL_HANDLE);
4516     mPoolSizes.reserve(setSizeCount);
4517     mPoolSizes.assign(setSizes, setSizes + setSizeCount);
4518     mCachedDescriptorSetLayout = descriptorSetLayout.getHandle();
4519 
4520     DescriptorPoolPointer newPool = DescriptorPoolPointer::MakeShared(context->getDevice());
4521     ANGLE_TRY(newPool->init(context, mPoolSizes, mMaxSetsPerPool));
4522 
4523     mDescriptorPools.emplace_back(std::move(newPool));
4524 
4525     return angle::Result::Continue;
4526 }
4527 
destroy(VkDevice device)4528 void DynamicDescriptorPool::destroy(VkDevice device)
4529 {
4530     // Destroy cache
4531     mDescriptorSetCache.clear();
4532 
4533     // Destroy LRU list and SharedDescriptorSetCacheKey.
4534     for (auto it = mLRUList.begin(); it != mLRUList.end();)
4535     {
4536         (it->sharedCacheKey)->destroy(device);
4537         it = mLRUList.erase(it);
4538     }
4539     ASSERT(mLRUList.empty());
4540 
4541     for (DescriptorPoolPointer &pool : mDescriptorPools)
4542     {
4543         pool->cleanupPendingGarbage();
4544         pool->destroyGarbage();
4545         ASSERT(pool.unique());
4546     }
4547     mDescriptorPools.clear();
4548 
4549     mCachedDescriptorSetLayout = VK_NULL_HANDLE;
4550 }
4551 
allocateFromExistingPool(ErrorContext * context,const DescriptorSetLayout & descriptorSetLayout,DescriptorSetPointer * descriptorSetOut)4552 bool DynamicDescriptorPool::allocateFromExistingPool(ErrorContext *context,
4553                                                      const DescriptorSetLayout &descriptorSetLayout,
4554                                                      DescriptorSetPointer *descriptorSetOut)
4555 {
4556     for (size_t poolIndex = 0; poolIndex < mDescriptorPools.size(); ++poolIndex)
4557     {
4558         DescriptorPoolPointer &pool = mDescriptorPools[poolIndex];
4559         if (!pool || !pool->valid())
4560         {
4561             continue;
4562         }
4563         if (pool->allocateDescriptorSet(context, descriptorSetLayout, pool, descriptorSetOut))
4564         {
4565             return true;
4566         }
4567     }
4568     return false;
4569 }
4570 
recycleFromGarbage(Renderer * renderer,DescriptorSetPointer * descriptorSetOut)4571 bool DynamicDescriptorPool::recycleFromGarbage(Renderer *renderer,
4572                                                DescriptorSetPointer *descriptorSetOut)
4573 {
4574     for (DescriptorPoolPointer &pool : mDescriptorPools)
4575     {
4576         if (pool->recycleFromGarbage(renderer, descriptorSetOut))
4577         {
4578             return true;
4579         }
4580     }
4581     return false;
4582 }
4583 
evictStaleDescriptorSets(Renderer * renderer,uint32_t oldestFrameToKeep,uint32_t currentFrame)4584 bool DynamicDescriptorPool::evictStaleDescriptorSets(Renderer *renderer,
4585                                                      uint32_t oldestFrameToKeep,
4586                                                      uint32_t currentFrame)
4587 {
4588     ASSERT(oldestFrameToKeep < currentFrame);
4589     size_t descriptorSetEvicted = 0;
4590     // Walk LRU list backwards from oldest to most recent, evict anything that earlier than
4591     // oldestFrameIDToKeep.
4592     auto it = mLRUList.rbegin();
4593     while (it != mLRUList.rend())
4594     {
4595         DescriptorSetPointer &descriptorSet = it->descriptorSet;
4596         if (descriptorSet.unique())
4597         {
4598             // Stop if it is recently being used.
4599             if (descriptorSet->getLastUsedFrame() > oldestFrameToKeep)
4600             {
4601                 break;
4602             }
4603             // Stop if GPU is still busy
4604             if (!renderer->hasResourceUseFinished(descriptorSet->getResourceUse()))
4605             {
4606                 break;
4607             }
4608             // Evict it from the cache and remove it from LRU list.
4609             bool removed = mDescriptorSetCache.eraseDescriptorSet(it->sharedCacheKey->getDesc());
4610             ASSERT(removed);
4611             // Invalidate the sharedCacheKey so that they could be reused.
4612             it->sharedCacheKey->destroy(renderer->getDevice());
4613             ASSERT(!it->sharedCacheKey->valid());
4614 
4615             // Note that erase it from LRU list will "destroy" descriptorSet. Since we
4616             // never actually destroy descriptorSet, it will just add to the garbage list. Here we
4617             // want more explicit control to add it to the front of list (because we know it is
4618             // already GPU completed) instead to the end of the list, so we do it explicitly.
4619             DescriptorPoolWeakPointer pool = descriptorSet->getPool();
4620             pool->addFinishedGarbage(std::move(descriptorSet));
4621             descriptorSetEvicted++;
4622 
4623             // This should destroy descriptorSet, which is already invalid;
4624             it = decltype(it)(mLRUList.erase(std::next(it).base()));
4625             mCacheStats.decrementSize();
4626         }
4627         else
4628         {
4629             // It means it is still bound to one of the programs. Move it to the front of the LRU
4630             // list to avoid repeatedly hitting it for every eviction.
4631             mLRUList.splice(mLRUList.begin(), mLRUList, std::next(it).base());
4632             ++it;
4633             // Update to currentFrame to maintain LRU order
4634             descriptorSet->updateLastUsedFrame(currentFrame);
4635         }
4636     }
4637 
4638     if (descriptorSetEvicted > 0)
4639     {
4640         // If there is any pool that is completely empty, destroy it first so that we can allocate
4641         // from partial pool.
4642         checkAndDestroyUnusedPool(renderer);
4643         return true;
4644     }
4645 
4646     return false;
4647 }
4648 
allocateDescriptorSet(ErrorContext * context,const DescriptorSetLayout & descriptorSetLayout,DescriptorSetPointer * descriptorSetOut)4649 angle::Result DynamicDescriptorPool::allocateDescriptorSet(
4650     ErrorContext *context,
4651     const DescriptorSetLayout &descriptorSetLayout,
4652     DescriptorSetPointer *descriptorSetOut)
4653 {
4654     ASSERT(!mDescriptorPools.empty());
4655     ASSERT(descriptorSetLayout.getHandle() == mCachedDescriptorSetLayout);
4656 
4657     if (allocateFromExistingPool(context, descriptorSetLayout, descriptorSetOut))
4658     {
4659         return angle::Result::Continue;
4660     }
4661 
4662     if (recycleFromGarbage(context->getRenderer(), descriptorSetOut))
4663     {
4664         return angle::Result::Continue;
4665     }
4666 
4667     // Last, try to allocate a new pool (and/or evict an existing pool)
4668     ANGLE_TRY(allocateNewPool(context));
4669     bool success = allocateFromExistingPool(context, descriptorSetLayout, descriptorSetOut);
4670     // Allocate from a new pool must succeed.
4671     ASSERT(success);
4672 
4673     return angle::Result::Continue;
4674 }
4675 
getOrAllocateDescriptorSet(Context * context,uint32_t currentFrame,const DescriptorSetDesc & desc,const DescriptorSetLayout & descriptorSetLayout,DescriptorSetPointer * descriptorSetOut,SharedDescriptorSetCacheKey * newSharedCacheKeyOut)4676 angle::Result DynamicDescriptorPool::getOrAllocateDescriptorSet(
4677     Context *context,
4678     uint32_t currentFrame,
4679     const DescriptorSetDesc &desc,
4680     const DescriptorSetLayout &descriptorSetLayout,
4681     DescriptorSetPointer *descriptorSetOut,
4682     SharedDescriptorSetCacheKey *newSharedCacheKeyOut)
4683 {
4684     Renderer *renderer = context->getRenderer();
4685     ASSERT(context->getFeatures().descriptorSetCache.enabled);
4686     bool success;
4687 
4688     // First scan the descriptorSet cache.
4689     DescriptorSetLRUListIterator listIterator;
4690     if (mDescriptorSetCache.getDescriptorSet(desc, &listIterator))
4691     {
4692         *descriptorSetOut = listIterator->descriptorSet;
4693         (*newSharedCacheKeyOut).reset();
4694         // Move it to the front of the LRU list.
4695         mLRUList.splice(mLRUList.begin(), mLRUList, listIterator);
4696         mCacheStats.hit();
4697         return angle::Result::Continue;
4698     }
4699 
4700     // Try to allocate from the existing pool (or recycle from garbage list)
4701     success = allocateFromExistingPool(context, descriptorSetLayout, descriptorSetOut);
4702 
4703     // Try to recycle from the garbage list.
4704     if (!success)
4705     {
4706         success = recycleFromGarbage(context->getRenderer(), descriptorSetOut);
4707     }
4708 
4709     // Try to evict oldest descriptorSets that has not being used in last
4710     // kDescriptorSetCacheRetireAge.
4711     if (!success && currentFrame > kDescriptorSetCacheRetireAge)
4712     {
4713         uint32_t oldestFrameToKeep = currentFrame - kDescriptorSetCacheRetireAge;
4714         if (evictStaleDescriptorSets(renderer, oldestFrameToKeep, currentFrame))
4715         {
4716             success = recycleFromGarbage(renderer, descriptorSetOut);
4717         }
4718     }
4719 
4720     // Last, try to allocate a new pool
4721     if (!success)
4722     {
4723         ANGLE_TRY(allocateNewPool(context));
4724         success = allocateFromExistingPool(context, descriptorSetLayout, descriptorSetOut);
4725         // Allocate from a new pool must succeed.
4726         ASSERT(success);
4727     }
4728 
4729     ASSERT(descriptorSetOut->unique());
4730     ASSERT((*descriptorSetOut)->valid());
4731 
4732     // Let pool know there is a shared cache key created and destroys the shared cache key
4733     // when it destroys the pool.
4734     SharedDescriptorSetCacheKey sharedCacheKey = CreateSharedDescriptorSetCacheKey(desc, this);
4735 
4736     // Add to the front of the LRU list and add list iterator to the cache
4737     mLRUList.push_front({sharedCacheKey, *descriptorSetOut});
4738     mDescriptorSetCache.insertDescriptorSet(desc, mLRUList.begin());
4739     mCacheStats.missAndIncrementSize();
4740 
4741     *newSharedCacheKeyOut = sharedCacheKey;
4742     return angle::Result::Continue;
4743 }
4744 
allocateNewPool(ErrorContext * context)4745 angle::Result DynamicDescriptorPool::allocateNewPool(ErrorContext *context)
4746 {
4747     static constexpr size_t kMaxPools = 99999;
4748     ANGLE_VK_CHECK(context, mDescriptorPools.size() < kMaxPools, VK_ERROR_TOO_MANY_OBJECTS);
4749     // This pool is getting hot, so grow its max size to try and prevent allocating another pool in
4750     // the future.
4751     if (mMaxSetsPerPool < kMaxSetsPerPoolMax)
4752     {
4753         mMaxSetsPerPool *= mMaxSetsPerPoolMultiplier;
4754     }
4755     DescriptorPoolPointer newPool = DescriptorPoolPointer::MakeShared(context->getDevice());
4756     ANGLE_TRY(newPool->init(context, mPoolSizes, mMaxSetsPerPool));
4757     mDescriptorPools.emplace_back(std::move(newPool));
4758 
4759     return angle::Result::Continue;
4760 }
4761 
releaseCachedDescriptorSet(Renderer * renderer,const DescriptorSetDesc & desc)4762 void DynamicDescriptorPool::releaseCachedDescriptorSet(Renderer *renderer,
4763                                                        const DescriptorSetDesc &desc)
4764 {
4765     ASSERT(renderer->getFeatures().descriptorSetCache.enabled);
4766     DescriptorSetLRUListIterator listIter;
4767     // Remove from the cache hash map. Note that we can't delete it until refcount goes to 0
4768     if (mDescriptorSetCache.eraseDescriptorSet(desc, &listIter))
4769     {
4770         DescriptorSetPointer descriptorSet = std::move(listIter->descriptorSet);
4771         mCacheStats.decrementSize();
4772         mLRUList.erase(listIter);
4773 
4774         if (descriptorSet.unique())
4775         {
4776             DescriptorPoolWeakPointer pool = descriptorSet->getPool();
4777             pool->addPendingGarbage(std::move(descriptorSet));
4778         }
4779     }
4780 }
4781 
destroyCachedDescriptorSet(Renderer * renderer,const DescriptorSetDesc & desc)4782 void DynamicDescriptorPool::destroyCachedDescriptorSet(Renderer *renderer,
4783                                                        const DescriptorSetDesc &desc)
4784 {
4785     ASSERT(renderer->getFeatures().descriptorSetCache.enabled);
4786     DescriptorSetLRUListIterator listIter;
4787     // Remove from the cache hash map. Note that we can't delete it until refcount goes to 0
4788     if (mDescriptorSetCache.eraseDescriptorSet(desc, &listIter))
4789     {
4790         DescriptorSetPointer descriptorSet = std::move(listIter->descriptorSet);
4791         mCacheStats.decrementSize();
4792         mLRUList.erase(listIter);
4793 
4794         if (descriptorSet.unique())
4795         {
4796             DescriptorPoolWeakPointer pool = descriptorSet->getPool();
4797             pool->addFinishedGarbage(std::move(descriptorSet));
4798             if (pool->canDestroy())
4799             {
4800                 destroyUnusedPool(renderer, pool);
4801             }
4802         }
4803     }
4804 }
4805 
destroyUnusedPool(Renderer * renderer,const DescriptorPoolWeakPointer & pool)4806 void DynamicDescriptorPool::destroyUnusedPool(Renderer *renderer,
4807                                               const DescriptorPoolWeakPointer &pool)
4808 {
4809     ASSERT(renderer->getFeatures().descriptorSetCache.enabled);
4810     ASSERT(pool->canDestroy());
4811 
4812     // We always keep at least one pool around.
4813     if (mDescriptorPools.size() < 2)
4814     {
4815         return;
4816     }
4817 
4818     // Erase it from the array
4819     for (auto it = mDescriptorPools.begin(); it != mDescriptorPools.end(); ++it)
4820     {
4821         if (pool.owner_equal(*it))
4822         {
4823             ASSERT(pool->valid());
4824             pool->destroyGarbage();
4825             ASSERT((*it).unique());
4826             it = mDescriptorPools.erase(it);
4827             return;
4828         }
4829     }
4830 }
4831 
checkAndDestroyUnusedPool(Renderer * renderer)4832 void DynamicDescriptorPool::checkAndDestroyUnusedPool(Renderer *renderer)
4833 {
4834     ASSERT(renderer->getFeatures().descriptorSetCache.enabled);
4835     for (auto pool : mDescriptorPools)
4836     {
4837         pool->cleanupPendingGarbage();
4838     }
4839 
4840     // We always keep at least one pool around.
4841     if (mDescriptorPools.size() < 2)
4842     {
4843         return;
4844     }
4845 
4846     // Erase it from the array
4847     for (auto it = mDescriptorPools.begin(); it != mDescriptorPools.end();)
4848     {
4849         if ((*it)->canDestroy())
4850         {
4851             (*it)->destroyGarbage();
4852             ASSERT((*it).unique());
4853             it = mDescriptorPools.erase(it);
4854         }
4855         else
4856         {
4857             ++it;
4858         }
4859     }
4860 }
4861 
4862 // For ASSERT only
hasCachedDescriptorSet(const DescriptorSetDesc & desc) const4863 bool DynamicDescriptorPool::hasCachedDescriptorSet(const DescriptorSetDesc &desc) const
4864 {
4865     DescriptorSetLRUListIterator listIterator;
4866     return mDescriptorSetCache.getDescriptorSet(desc, &listIterator);
4867 }
4868 
4869 // For testing only!
GetMaxSetsPerPoolForTesting()4870 uint32_t DynamicDescriptorPool::GetMaxSetsPerPoolForTesting()
4871 {
4872     return mMaxSetsPerPool;
4873 }
4874 
4875 // For testing only!
SetMaxSetsPerPoolForTesting(uint32_t maxSetsPerPool)4876 void DynamicDescriptorPool::SetMaxSetsPerPoolForTesting(uint32_t maxSetsPerPool)
4877 {
4878     mMaxSetsPerPool = maxSetsPerPool;
4879 }
4880 
4881 // For testing only!
GetMaxSetsPerPoolMultiplierForTesting()4882 uint32_t DynamicDescriptorPool::GetMaxSetsPerPoolMultiplierForTesting()
4883 {
4884     return mMaxSetsPerPoolMultiplier;
4885 }
4886 
4887 // For testing only!
SetMaxSetsPerPoolMultiplierForTesting(uint32_t maxSetsPerPoolMultiplier)4888 void DynamicDescriptorPool::SetMaxSetsPerPoolMultiplierForTesting(uint32_t maxSetsPerPoolMultiplier)
4889 {
4890     mMaxSetsPerPoolMultiplier = maxSetsPerPoolMultiplier;
4891 }
4892 
4893 // DynamicallyGrowingPool implementation
4894 template <typename Pool>
DynamicallyGrowingPool()4895 DynamicallyGrowingPool<Pool>::DynamicallyGrowingPool()
4896     : mPoolSize(0), mCurrentPool(0), mCurrentFreeEntry(0)
4897 {
4898     mPools.reserve(64);
4899 }
4900 
4901 template <typename Pool>
4902 DynamicallyGrowingPool<Pool>::~DynamicallyGrowingPool() = default;
4903 
4904 template <typename Pool>
initEntryPool(ErrorContext * contextVk,uint32_t poolSize)4905 angle::Result DynamicallyGrowingPool<Pool>::initEntryPool(ErrorContext *contextVk,
4906                                                           uint32_t poolSize)
4907 {
4908     ASSERT(mPools.empty());
4909     mPoolSize         = poolSize;
4910     mCurrentFreeEntry = poolSize;
4911     return angle::Result::Continue;
4912 }
4913 
4914 template <typename Pool>
destroyEntryPool(VkDevice device)4915 void DynamicallyGrowingPool<Pool>::destroyEntryPool(VkDevice device)
4916 {
4917     for (PoolResource &resource : mPools)
4918     {
4919         destroyPoolImpl(device, resource.pool);
4920     }
4921     mPools.clear();
4922 }
4923 
4924 template <typename Pool>
findFreeEntryPool(ContextVk * contextVk)4925 bool DynamicallyGrowingPool<Pool>::findFreeEntryPool(ContextVk *contextVk)
4926 {
4927     Renderer *renderer = contextVk->getRenderer();
4928     for (size_t poolIndex = 0; poolIndex < mPools.size(); ++poolIndex)
4929     {
4930         PoolResource &pool = mPools[poolIndex];
4931         if (pool.freedCount == mPoolSize && renderer->hasResourceUseFinished(pool.getResourceUse()))
4932         {
4933             mCurrentPool      = poolIndex;
4934             mCurrentFreeEntry = 0;
4935 
4936             pool.freedCount = 0;
4937 
4938             return true;
4939         }
4940     }
4941 
4942     return false;
4943 }
4944 
4945 template <typename Pool>
allocateNewEntryPool(ContextVk * contextVk,Pool && pool)4946 angle::Result DynamicallyGrowingPool<Pool>::allocateNewEntryPool(ContextVk *contextVk, Pool &&pool)
4947 {
4948     mPools.emplace_back(std::move(pool), 0);
4949 
4950     mCurrentPool      = mPools.size() - 1;
4951     mCurrentFreeEntry = 0;
4952 
4953     return angle::Result::Continue;
4954 }
4955 
4956 template <typename Pool>
onEntryFreed(ContextVk * contextVk,size_t poolIndex,const ResourceUse & use)4957 void DynamicallyGrowingPool<Pool>::onEntryFreed(ContextVk *contextVk,
4958                                                 size_t poolIndex,
4959                                                 const ResourceUse &use)
4960 {
4961     ASSERT(poolIndex < mPools.size() && mPools[poolIndex].freedCount < mPoolSize);
4962     if (!contextVk->getRenderer()->hasResourceUseFinished(use))
4963     {
4964         mPools[poolIndex].mergeResourceUse(use);
4965     }
4966     ++mPools[poolIndex].freedCount;
4967 }
4968 
4969 template <typename Pool>
allocatePoolEntries(ContextVk * contextVk,uint32_t entryCount,uint32_t * poolIndex,uint32_t * currentEntryOut)4970 angle::Result DynamicallyGrowingPool<Pool>::allocatePoolEntries(ContextVk *contextVk,
4971                                                                 uint32_t entryCount,
4972                                                                 uint32_t *poolIndex,
4973                                                                 uint32_t *currentEntryOut)
4974 {
4975     if (mCurrentFreeEntry + entryCount > mPoolSize)
4976     {
4977         if (!findFreeEntryPool(contextVk))
4978         {
4979             Pool newPool;
4980             ANGLE_TRY(allocatePoolImpl(contextVk, newPool, mPoolSize));
4981             ANGLE_TRY(allocateNewEntryPool(contextVk, std::move(newPool)));
4982         }
4983     }
4984 
4985     *poolIndex       = static_cast<uint32_t>(mCurrentPool);
4986     *currentEntryOut = mCurrentFreeEntry;
4987 
4988     mCurrentFreeEntry += entryCount;
4989 
4990     return angle::Result::Continue;
4991 }
4992 
4993 template <typename Pool>
PoolResource(Pool && poolIn,uint32_t freedCountIn)4994 DynamicallyGrowingPool<Pool>::PoolResource::PoolResource(Pool &&poolIn, uint32_t freedCountIn)
4995     : pool(std::move(poolIn)), freedCount(freedCountIn)
4996 {}
4997 
4998 template <typename Pool>
PoolResource(PoolResource && other)4999 DynamicallyGrowingPool<Pool>::PoolResource::PoolResource(PoolResource &&other)
5000     : Resource(std::move(other)), pool(std::move(other.pool)), freedCount(other.freedCount)
5001 {}
5002 
5003 // DynamicQueryPool implementation
5004 DynamicQueryPool::DynamicQueryPool() = default;
5005 
5006 DynamicQueryPool::~DynamicQueryPool() = default;
5007 
init(ContextVk * contextVk,VkQueryType type,uint32_t poolSize)5008 angle::Result DynamicQueryPool::init(ContextVk *contextVk, VkQueryType type, uint32_t poolSize)
5009 {
5010     // SecondaryCommandBuffer's ResetQueryPoolParams would like the query index to fit in 24 bits.
5011     ASSERT(poolSize < (1 << 24));
5012 
5013     ANGLE_TRY(initEntryPool(contextVk, poolSize));
5014     mQueryType = type;
5015     return angle::Result::Continue;
5016 }
5017 
destroy(VkDevice device)5018 void DynamicQueryPool::destroy(VkDevice device)
5019 {
5020     destroyEntryPool(device);
5021 }
5022 
destroyPoolImpl(VkDevice device,QueryPool & poolToDestroy)5023 void DynamicQueryPool::destroyPoolImpl(VkDevice device, QueryPool &poolToDestroy)
5024 {
5025     poolToDestroy.destroy(device);
5026 }
5027 
allocateQuery(ContextVk * contextVk,QueryHelper * queryOut,uint32_t queryCount)5028 angle::Result DynamicQueryPool::allocateQuery(ContextVk *contextVk,
5029                                               QueryHelper *queryOut,
5030                                               uint32_t queryCount)
5031 {
5032     ASSERT(!queryOut->valid());
5033 
5034     uint32_t currentPool = 0;
5035     uint32_t queryIndex  = 0;
5036     ANGLE_TRY(allocatePoolEntries(contextVk, queryCount, &currentPool, &queryIndex));
5037 
5038     queryOut->init(this, currentPool, queryIndex, queryCount);
5039 
5040     return angle::Result::Continue;
5041 }
5042 
allocatePoolImpl(ContextVk * contextVk,QueryPool & poolToAllocate,uint32_t entriesToAllocate)5043 angle::Result DynamicQueryPool::allocatePoolImpl(ContextVk *contextVk,
5044                                                  QueryPool &poolToAllocate,
5045                                                  uint32_t entriesToAllocate)
5046 {
5047     VkQueryPoolCreateInfo queryPoolInfo = {};
5048     queryPoolInfo.sType                 = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO;
5049     queryPoolInfo.flags                 = 0;
5050     queryPoolInfo.queryType             = this->mQueryType;
5051     queryPoolInfo.queryCount            = entriesToAllocate;
5052     queryPoolInfo.pipelineStatistics    = 0;
5053 
5054     if (this->mQueryType == VK_QUERY_TYPE_PIPELINE_STATISTICS)
5055     {
5056         queryPoolInfo.pipelineStatistics = VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT;
5057     }
5058 
5059     ANGLE_VK_TRY(contextVk, poolToAllocate.init(contextVk->getDevice(), queryPoolInfo));
5060     return angle::Result::Continue;
5061 }
5062 
freeQuery(ContextVk * contextVk,QueryHelper * query)5063 void DynamicQueryPool::freeQuery(ContextVk *contextVk, QueryHelper *query)
5064 {
5065     if (query->valid())
5066     {
5067         size_t poolIndex = query->mQueryPoolIndex;
5068         ASSERT(getQueryPool(poolIndex).valid());
5069 
5070         onEntryFreed(contextVk, poolIndex, query->getResourceUse());
5071 
5072         query->deinit();
5073     }
5074 }
5075 
5076 // QueryResult implementation
setResults(uint64_t * results,uint32_t queryCount)5077 void QueryResult::setResults(uint64_t *results, uint32_t queryCount)
5078 {
5079     ASSERT(mResults[0] == 0 && mResults[1] == 0);
5080 
5081     // Accumulate the query results.  For multiview, where multiple query indices are used to return
5082     // the results, it's undefined how the results are distributed between indices, but the sum is
5083     // guaranteed to be the desired result.
5084     for (uint32_t query = 0; query < queryCount; ++query)
5085     {
5086         for (uint32_t perQueryIndex = 0; perQueryIndex < mIntsPerResult; ++perQueryIndex)
5087         {
5088             mResults[perQueryIndex] += results[query * mIntsPerResult + perQueryIndex];
5089         }
5090     }
5091 }
5092 
5093 // QueryHelper implementation
QueryHelper()5094 QueryHelper::QueryHelper()
5095     : mDynamicQueryPool(nullptr),
5096       mQueryPoolIndex(0),
5097       mQuery(0),
5098       mQueryCount(0),
5099       mStatus(QueryStatus::Inactive)
5100 {}
5101 
~QueryHelper()5102 QueryHelper::~QueryHelper() {}
5103 
5104 // Move constructor
QueryHelper(QueryHelper && rhs)5105 QueryHelper::QueryHelper(QueryHelper &&rhs)
5106     : Resource(std::move(rhs)),
5107       mDynamicQueryPool(rhs.mDynamicQueryPool),
5108       mQueryPoolIndex(rhs.mQueryPoolIndex),
5109       mQuery(rhs.mQuery),
5110       mQueryCount(rhs.mQueryCount),
5111       mStatus(rhs.mStatus)
5112 {
5113     rhs.mDynamicQueryPool = nullptr;
5114     rhs.mQueryPoolIndex   = 0;
5115     rhs.mQuery            = 0;
5116     rhs.mQueryCount       = 0;
5117     rhs.mStatus           = QueryStatus::Inactive;
5118 }
5119 
operator =(QueryHelper && rhs)5120 QueryHelper &QueryHelper::operator=(QueryHelper &&rhs)
5121 {
5122     Resource::operator=(std::move(rhs));
5123     std::swap(mDynamicQueryPool, rhs.mDynamicQueryPool);
5124     std::swap(mQueryPoolIndex, rhs.mQueryPoolIndex);
5125     std::swap(mQuery, rhs.mQuery);
5126     std::swap(mQueryCount, rhs.mQueryCount);
5127     std::swap(mStatus, rhs.mStatus);
5128     return *this;
5129 }
5130 
init(const DynamicQueryPool * dynamicQueryPool,const size_t queryPoolIndex,uint32_t query,uint32_t queryCount)5131 void QueryHelper::init(const DynamicQueryPool *dynamicQueryPool,
5132                        const size_t queryPoolIndex,
5133                        uint32_t query,
5134                        uint32_t queryCount)
5135 {
5136     mDynamicQueryPool = dynamicQueryPool;
5137     mQueryPoolIndex   = queryPoolIndex;
5138     mQuery            = query;
5139     mQueryCount       = queryCount;
5140 
5141     ASSERT(mQueryCount <= gl::IMPLEMENTATION_ANGLE_MULTIVIEW_MAX_VIEWS);
5142 }
5143 
deinit()5144 void QueryHelper::deinit()
5145 {
5146     mDynamicQueryPool = nullptr;
5147     mQueryPoolIndex   = 0;
5148     mQuery            = 0;
5149     mQueryCount       = 0;
5150     mUse.reset();
5151     mStatus = QueryStatus::Inactive;
5152 }
5153 
5154 template <typename CommandBufferT>
beginQueryImpl(ContextVk * contextVk,OutsideRenderPassCommandBuffer * resetCommandBuffer,CommandBufferT * commandBuffer)5155 void QueryHelper::beginQueryImpl(ContextVk *contextVk,
5156                                  OutsideRenderPassCommandBuffer *resetCommandBuffer,
5157                                  CommandBufferT *commandBuffer)
5158 {
5159     ASSERT(mStatus != QueryStatus::Active);
5160     const QueryPool &queryPool = getQueryPool();
5161     resetQueryPoolImpl(contextVk, queryPool, resetCommandBuffer);
5162     commandBuffer->beginQuery(queryPool, mQuery, 0);
5163     mStatus = QueryStatus::Active;
5164 }
5165 
5166 template <typename CommandBufferT>
endQueryImpl(ContextVk * contextVk,CommandBufferT * commandBuffer)5167 void QueryHelper::endQueryImpl(ContextVk *contextVk, CommandBufferT *commandBuffer)
5168 {
5169     ASSERT(mStatus != QueryStatus::Ended);
5170     commandBuffer->endQuery(getQueryPool(), mQuery);
5171     mStatus = QueryStatus::Ended;
5172 }
5173 
beginQuery(ContextVk * contextVk)5174 angle::Result QueryHelper::beginQuery(ContextVk *contextVk)
5175 {
5176     if (contextVk->hasActiveRenderPass())
5177     {
5178         ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass(
5179             RenderPassClosureReason::BeginNonRenderPassQuery));
5180     }
5181 
5182     OutsideRenderPassCommandBuffer *commandBuffer;
5183     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer({}, &commandBuffer));
5184 
5185     ANGLE_TRY(contextVk->handleGraphicsEventLog(rx::GraphicsEventCmdBuf::InOutsideCmdBufQueryCmd));
5186 
5187     beginQueryImpl(contextVk, commandBuffer, commandBuffer);
5188 
5189     return angle::Result::Continue;
5190 }
5191 
endQuery(ContextVk * contextVk)5192 angle::Result QueryHelper::endQuery(ContextVk *contextVk)
5193 {
5194     if (contextVk->hasActiveRenderPass())
5195     {
5196         ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass(
5197             RenderPassClosureReason::EndNonRenderPassQuery));
5198     }
5199 
5200     CommandBufferAccess access;
5201     OutsideRenderPassCommandBuffer *commandBuffer;
5202     access.onQueryAccess(this);
5203     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
5204 
5205     ANGLE_TRY(contextVk->handleGraphicsEventLog(rx::GraphicsEventCmdBuf::InOutsideCmdBufQueryCmd));
5206 
5207     endQueryImpl(contextVk, commandBuffer);
5208 
5209     return angle::Result::Continue;
5210 }
5211 
5212 template <typename CommandBufferT>
resetQueryPoolImpl(ContextVk * contextVk,const QueryPool & queryPool,CommandBufferT * commandBuffer)5213 void QueryHelper::resetQueryPoolImpl(ContextVk *contextVk,
5214                                      const QueryPool &queryPool,
5215                                      CommandBufferT *commandBuffer)
5216 {
5217     Renderer *renderer = contextVk->getRenderer();
5218     if (renderer->getFeatures().supportsHostQueryReset.enabled)
5219     {
5220         vkResetQueryPoolEXT(contextVk->getDevice(), queryPool.getHandle(), mQuery, mQueryCount);
5221     }
5222     else
5223     {
5224         commandBuffer->resetQueryPool(queryPool, mQuery, mQueryCount);
5225     }
5226 }
5227 
beginRenderPassQuery(ContextVk * contextVk)5228 angle::Result QueryHelper::beginRenderPassQuery(ContextVk *contextVk)
5229 {
5230     OutsideRenderPassCommandBuffer *outsideRenderPassCommandBuffer;
5231     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer({}, &outsideRenderPassCommandBuffer));
5232 
5233     RenderPassCommandBuffer *renderPassCommandBuffer =
5234         &contextVk->getStartedRenderPassCommands().getCommandBuffer();
5235 
5236     beginQueryImpl(contextVk, outsideRenderPassCommandBuffer, renderPassCommandBuffer);
5237 
5238     return angle::Result::Continue;
5239 }
5240 
endRenderPassQuery(ContextVk * contextVk)5241 void QueryHelper::endRenderPassQuery(ContextVk *contextVk)
5242 {
5243     if (mStatus == QueryStatus::Active)
5244     {
5245         endQueryImpl(contextVk, &contextVk->getStartedRenderPassCommands().getCommandBuffer());
5246         contextVk->getStartedRenderPassCommands().retainResource(this);
5247     }
5248 }
5249 
flushAndWriteTimestamp(ContextVk * contextVk)5250 angle::Result QueryHelper::flushAndWriteTimestamp(ContextVk *contextVk)
5251 {
5252     if (contextVk->hasActiveRenderPass())
5253     {
5254         ANGLE_TRY(
5255             contextVk->flushCommandsAndEndRenderPass(RenderPassClosureReason::TimestampQuery));
5256     }
5257 
5258     CommandBufferAccess access;
5259     OutsideRenderPassCommandBuffer *commandBuffer;
5260     access.onQueryAccess(this);
5261     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
5262     writeTimestamp(contextVk, commandBuffer);
5263     return angle::Result::Continue;
5264 }
5265 
writeTimestampToPrimary(ContextVk * contextVk,PrimaryCommandBuffer * primary)5266 void QueryHelper::writeTimestampToPrimary(ContextVk *contextVk, PrimaryCommandBuffer *primary)
5267 {
5268     // Note that commands may not be flushed at this point.
5269 
5270     const QueryPool &queryPool = getQueryPool();
5271     resetQueryPoolImpl(contextVk, queryPool, primary);
5272     primary->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, queryPool, mQuery);
5273 }
5274 
writeTimestamp(ContextVk * contextVk,OutsideRenderPassCommandBuffer * commandBuffer)5275 void QueryHelper::writeTimestamp(ContextVk *contextVk,
5276                                  OutsideRenderPassCommandBuffer *commandBuffer)
5277 {
5278     const QueryPool &queryPool = getQueryPool();
5279     resetQueryPoolImpl(contextVk, queryPool, commandBuffer);
5280     commandBuffer->writeTimestamp(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, queryPool, mQuery);
5281 }
5282 
hasSubmittedCommands() const5283 bool QueryHelper::hasSubmittedCommands() const
5284 {
5285     return mUse.valid();
5286 }
5287 
getUint64ResultNonBlocking(ContextVk * contextVk,QueryResult * resultOut,bool * availableOut)5288 angle::Result QueryHelper::getUint64ResultNonBlocking(ContextVk *contextVk,
5289                                                       QueryResult *resultOut,
5290                                                       bool *availableOut)
5291 {
5292     ASSERT(valid());
5293     VkResult result;
5294 
5295     // Ensure that we only wait if we have inserted a query in command buffer. Otherwise you will
5296     // wait forever and trigger GPU timeout.
5297     if (hasSubmittedCommands())
5298     {
5299         constexpr VkQueryResultFlags kFlags = VK_QUERY_RESULT_64_BIT;
5300         result                              = getResultImpl(contextVk, kFlags, resultOut);
5301     }
5302     else
5303     {
5304         result     = VK_SUCCESS;
5305         *resultOut = 0;
5306     }
5307 
5308     if (result == VK_NOT_READY)
5309     {
5310         *availableOut = false;
5311         return angle::Result::Continue;
5312     }
5313     else
5314     {
5315         ANGLE_VK_TRY(contextVk, result);
5316         *availableOut = true;
5317     }
5318     return angle::Result::Continue;
5319 }
5320 
getUint64Result(ContextVk * contextVk,QueryResult * resultOut)5321 angle::Result QueryHelper::getUint64Result(ContextVk *contextVk, QueryResult *resultOut)
5322 {
5323     ASSERT(valid());
5324     if (hasSubmittedCommands())
5325     {
5326         constexpr VkQueryResultFlags kFlags = VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WAIT_BIT;
5327         ANGLE_VK_TRY(contextVk, getResultImpl(contextVk, kFlags, resultOut));
5328     }
5329     else
5330     {
5331         *resultOut = 0;
5332     }
5333     return angle::Result::Continue;
5334 }
5335 
getResultImpl(ContextVk * contextVk,const VkQueryResultFlags flags,QueryResult * resultOut)5336 VkResult QueryHelper::getResultImpl(ContextVk *contextVk,
5337                                     const VkQueryResultFlags flags,
5338                                     QueryResult *resultOut)
5339 {
5340     std::array<uint64_t, 2 * gl::IMPLEMENTATION_ANGLE_MULTIVIEW_MAX_VIEWS> results;
5341 
5342     VkDevice device = contextVk->getDevice();
5343     VkResult result = getQueryPool().getResults(device, mQuery, mQueryCount, sizeof(results),
5344                                                 results.data(), sizeof(uint64_t), flags);
5345 
5346     if (result == VK_SUCCESS)
5347     {
5348         resultOut->setResults(results.data(), mQueryCount);
5349     }
5350 
5351     return result;
5352 }
5353 
5354 // SemaphoreHelper implementation
SemaphoreHelper()5355 SemaphoreHelper::SemaphoreHelper() : mSemaphorePoolIndex(0), mSemaphore(0) {}
5356 
~SemaphoreHelper()5357 SemaphoreHelper::~SemaphoreHelper() {}
5358 
SemaphoreHelper(SemaphoreHelper && other)5359 SemaphoreHelper::SemaphoreHelper(SemaphoreHelper &&other)
5360     : mSemaphorePoolIndex(other.mSemaphorePoolIndex), mSemaphore(other.mSemaphore)
5361 {
5362     other.mSemaphore = nullptr;
5363 }
5364 
operator =(SemaphoreHelper && other)5365 SemaphoreHelper &SemaphoreHelper::operator=(SemaphoreHelper &&other)
5366 {
5367     std::swap(mSemaphorePoolIndex, other.mSemaphorePoolIndex);
5368     std::swap(mSemaphore, other.mSemaphore);
5369     return *this;
5370 }
5371 
init(const size_t semaphorePoolIndex,const Semaphore * semaphore)5372 void SemaphoreHelper::init(const size_t semaphorePoolIndex, const Semaphore *semaphore)
5373 {
5374     mSemaphorePoolIndex = semaphorePoolIndex;
5375     mSemaphore          = semaphore;
5376 }
5377 
deinit()5378 void SemaphoreHelper::deinit()
5379 {
5380     mSemaphorePoolIndex = 0;
5381     mSemaphore          = nullptr;
5382 }
5383 
GetPipelineStage(gl::ShaderType stage)5384 PipelineStage GetPipelineStage(gl::ShaderType stage)
5385 {
5386     const PipelineStage pipelineStage = kPipelineStageShaderMap[stage];
5387     ASSERT(pipelineStage == PipelineStage::VertexShader ||
5388            pipelineStage == PipelineStage::TessellationControl ||
5389            pipelineStage == PipelineStage::TessellationEvaluation ||
5390            pipelineStage == PipelineStage::GeometryShader ||
5391            pipelineStage == PipelineStage::FragmentShader ||
5392            pipelineStage == PipelineStage::ComputeShader);
5393     return pipelineStage;
5394 }
5395 
5396 // PipelineBarrier implementation.
addDiagnosticsString(std::ostringstream & out) const5397 void PipelineBarrier::addDiagnosticsString(std::ostringstream &out) const
5398 {
5399     if (mMemoryBarrierSrcAccess != 0 || mMemoryBarrierDstAccess != 0)
5400     {
5401         out << "Src: 0x" << std::hex << mMemoryBarrierSrcAccess << " &rarr; Dst: 0x" << std::hex
5402             << mMemoryBarrierDstAccess << std::endl;
5403     }
5404 }
5405 
5406 // PipelineBarrierArray implementation.
execute(Renderer * renderer,PrimaryCommandBuffer * primary)5407 void PipelineBarrierArray::execute(Renderer *renderer, PrimaryCommandBuffer *primary)
5408 {
5409     // make a local copy for faster access
5410     PipelineStagesMask mask = mBarrierMask;
5411     if (mask.none())
5412     {
5413         return;
5414     }
5415 
5416     if (renderer->getFeatures().preferAggregateBarrierCalls.enabled)
5417     {
5418         PipelineStagesMask::Iterator iter = mask.begin();
5419         PipelineBarrier &barrier          = mBarriers[*iter];
5420         for (++iter; iter != mask.end(); ++iter)
5421         {
5422             barrier.merge(&mBarriers[*iter]);
5423         }
5424         barrier.execute(primary);
5425     }
5426     else
5427     {
5428         for (PipelineStage pipelineStage : mask)
5429         {
5430             PipelineBarrier &barrier = mBarriers[pipelineStage];
5431             barrier.execute(primary);
5432         }
5433     }
5434     mBarrierMask.reset();
5435 }
5436 
addDiagnosticsString(std::ostringstream & out) const5437 void PipelineBarrierArray::addDiagnosticsString(std::ostringstream &out) const
5438 {
5439     out << "Memory Barrier: ";
5440     for (PipelineStage pipelineStage : mBarrierMask)
5441     {
5442         const PipelineBarrier &barrier = mBarriers[pipelineStage];
5443         if (!barrier.isEmpty())
5444         {
5445             barrier.addDiagnosticsString(out);
5446         }
5447     }
5448     out << "\\l";
5449 }
5450 
5451 // BufferHelper implementation.
BufferHelper()5452 BufferHelper::BufferHelper()
5453     : mCurrentWriteAccess(0),
5454       mCurrentReadAccess(0),
5455       mCurrentWriteStages(0),
5456       mCurrentReadStages(0),
5457       mSerial(),
5458       mClientBuffer(nullptr),
5459       mIsReleasedToExternal(false)
5460 {}
5461 
~BufferHelper()5462 BufferHelper::~BufferHelper()
5463 {
5464     // We must have released external buffer properly
5465     ASSERT(mClientBuffer == nullptr);
5466 }
5467 
BufferHelper(BufferHelper && other)5468 BufferHelper::BufferHelper(BufferHelper &&other)
5469 {
5470     *this = std::move(other);
5471 }
5472 
operator =(BufferHelper && other)5473 BufferHelper &BufferHelper::operator=(BufferHelper &&other)
5474 {
5475     ReadWriteResource::operator=(std::move(other));
5476 
5477     mSuballocation      = std::move(other.mSuballocation);
5478     mBufferWithUserSize = std::move(other.mBufferWithUserSize);
5479 
5480     mCurrentDeviceQueueIndex = other.mCurrentDeviceQueueIndex;
5481     mIsReleasedToExternal    = other.mIsReleasedToExternal;
5482     mCurrentWriteAccess      = other.mCurrentWriteAccess;
5483     mCurrentReadAccess       = other.mCurrentReadAccess;
5484     mCurrentWriteStages      = other.mCurrentWriteStages;
5485     mCurrentReadStages       = other.mCurrentReadStages;
5486     if (other.mCurrentWriteEvent.valid())
5487     {
5488         mCurrentWriteEvent = std::move(other.mCurrentWriteEvent);
5489     }
5490     if (!other.mCurrentReadEvents.empty())
5491     {
5492         mCurrentReadEvents = std::move(other.mCurrentReadEvents);
5493     }
5494     mTransformFeedbackWriteHeuristicBits = std::move(other.mTransformFeedbackWriteHeuristicBits);
5495     mSerial                  = other.mSerial;
5496     mClientBuffer            = std::move(other.mClientBuffer);
5497 
5498     return *this;
5499 }
5500 
init(ErrorContext * context,const VkBufferCreateInfo & requestedCreateInfo,VkMemoryPropertyFlags memoryPropertyFlags)5501 angle::Result BufferHelper::init(ErrorContext *context,
5502                                  const VkBufferCreateInfo &requestedCreateInfo,
5503                                  VkMemoryPropertyFlags memoryPropertyFlags)
5504 {
5505     Renderer *renderer         = context->getRenderer();
5506     const Allocator &allocator = renderer->getAllocator();
5507 
5508     initializeBarrierTracker(context);
5509 
5510     VkBufferCreateInfo modifiedCreateInfo;
5511     const VkBufferCreateInfo *createInfo = &requestedCreateInfo;
5512 
5513     if (renderer->getFeatures().padBuffersToMaxVertexAttribStride.enabled)
5514     {
5515         const VkDeviceSize maxVertexAttribStride = renderer->getMaxVertexAttribStride();
5516         ASSERT(maxVertexAttribStride);
5517         modifiedCreateInfo = requestedCreateInfo;
5518         modifiedCreateInfo.size += maxVertexAttribStride;
5519         createInfo = &modifiedCreateInfo;
5520     }
5521 
5522     VkMemoryPropertyFlags requiredFlags =
5523         (memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
5524     VkMemoryPropertyFlags preferredFlags =
5525         (memoryPropertyFlags & (~VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
5526 
5527     bool persistentlyMapped = renderer->getFeatures().persistentlyMappedBuffers.enabled;
5528 
5529     // Check that the allocation is not too large.
5530     uint32_t memoryTypeIndex = kInvalidMemoryTypeIndex;
5531     ANGLE_VK_TRY(context, allocator.findMemoryTypeIndexForBufferInfo(
5532                               *createInfo, requiredFlags, preferredFlags, persistentlyMapped,
5533                               &memoryTypeIndex));
5534 
5535     VkDeviceSize heapSize =
5536         renderer->getMemoryProperties().getHeapSizeForMemoryType(memoryTypeIndex);
5537 
5538     ANGLE_VK_CHECK(context, createInfo->size <= heapSize, VK_ERROR_OUT_OF_DEVICE_MEMORY);
5539 
5540     VkMemoryPropertyFlags memoryPropertyFlagsOut;
5541     allocator.getMemoryTypeProperties(memoryTypeIndex, &memoryPropertyFlagsOut);
5542     // Allocate buffer object
5543     DeviceScoped<Buffer> buffer(renderer->getDevice());
5544     ANGLE_VK_TRY(context, buffer.get().init(context->getDevice(), *createInfo));
5545 
5546     DeviceScoped<DeviceMemory> deviceMemory(renderer->getDevice());
5547     VkDeviceSize sizeOut;
5548     uint32_t bufferMemoryTypeIndex;
5549     ANGLE_VK_TRY(context,
5550                  AllocateBufferMemory(context, MemoryAllocationType::Buffer, memoryPropertyFlagsOut,
5551                                       &memoryPropertyFlagsOut, nullptr, &buffer.get(),
5552                                       &bufferMemoryTypeIndex, &deviceMemory.get(), &sizeOut));
5553     ASSERT(sizeOut >= createInfo->size);
5554 
5555     mSuballocation.initWithEntireBuffer(context, buffer.get(), MemoryAllocationType::Buffer,
5556                                         bufferMemoryTypeIndex, deviceMemory.get(),
5557                                         memoryPropertyFlagsOut, requestedCreateInfo.size, sizeOut);
5558     if (isHostVisible())
5559     {
5560         uint8_t *ptrOut;
5561         ANGLE_TRY(map(context, &ptrOut));
5562     }
5563 
5564     if (renderer->getFeatures().allocateNonZeroMemory.enabled)
5565     {
5566         ANGLE_TRY(initializeNonZeroMemory(context, createInfo->usage, createInfo->size));
5567     }
5568 
5569     return angle::Result::Continue;
5570 }
5571 
initExternal(ErrorContext * context,VkMemoryPropertyFlags memoryProperties,const VkBufferCreateInfo & requestedCreateInfo,GLeglClientBufferEXT clientBuffer)5572 angle::Result BufferHelper::initExternal(ErrorContext *context,
5573                                          VkMemoryPropertyFlags memoryProperties,
5574                                          const VkBufferCreateInfo &requestedCreateInfo,
5575                                          GLeglClientBufferEXT clientBuffer)
5576 {
5577     ASSERT(IsAndroid());
5578 
5579     Renderer *renderer = context->getRenderer();
5580 
5581     initializeBarrierTracker(context);
5582 
5583     VkBufferCreateInfo modifiedCreateInfo             = requestedCreateInfo;
5584     VkExternalMemoryBufferCreateInfo externCreateInfo = {};
5585     externCreateInfo.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO;
5586     externCreateInfo.handleTypes =
5587         VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
5588     externCreateInfo.pNext   = nullptr;
5589     modifiedCreateInfo.pNext = &externCreateInfo;
5590 
5591     DeviceScoped<Buffer> buffer(renderer->getDevice());
5592     ANGLE_VK_TRY(context, buffer.get().init(renderer->getDevice(), modifiedCreateInfo));
5593 
5594     DeviceScoped<DeviceMemory> deviceMemory(renderer->getDevice());
5595     VkMemoryPropertyFlags memoryPropertyFlagsOut;
5596     VkDeviceSize allocatedSize = 0;
5597     uint32_t memoryTypeIndex;
5598     ANGLE_TRY(InitAndroidExternalMemory(context, clientBuffer, memoryProperties, &buffer.get(),
5599                                         &memoryPropertyFlagsOut, &memoryTypeIndex,
5600                                         &deviceMemory.get(), &allocatedSize));
5601     mClientBuffer = clientBuffer;
5602 
5603     mSuballocation.initWithEntireBuffer(context, buffer.get(), MemoryAllocationType::BufferExternal,
5604                                         memoryTypeIndex, deviceMemory.get(), memoryPropertyFlagsOut,
5605                                         requestedCreateInfo.size, allocatedSize);
5606     if (isHostVisible())
5607     {
5608         uint8_t *ptrOut;
5609         ANGLE_TRY(map(context, &ptrOut));
5610     }
5611     return angle::Result::Continue;
5612 }
5613 
initSuballocation(Context * context,uint32_t memoryTypeIndex,size_t size,size_t alignment,BufferUsageType usageType,BufferPool * pool)5614 VkResult BufferHelper::initSuballocation(Context *context,
5615                                          uint32_t memoryTypeIndex,
5616                                          size_t size,
5617                                          size_t alignment,
5618                                          BufferUsageType usageType,
5619                                          BufferPool *pool)
5620 {
5621     ASSERT(pool != nullptr);
5622     Renderer *renderer = context->getRenderer();
5623 
5624     // We should reset these in case the BufferHelper object has been released and called
5625     // initSuballocation again.
5626     initializeBarrierTracker(context);
5627 
5628     if (renderer->getFeatures().padBuffersToMaxVertexAttribStride.enabled)
5629     {
5630         const VkDeviceSize maxVertexAttribStride = renderer->getMaxVertexAttribStride();
5631         ASSERT(maxVertexAttribStride);
5632         size += maxVertexAttribStride;
5633     }
5634 
5635     VK_RESULT_TRY(pool->allocateBuffer(context, size, alignment, &mSuballocation));
5636 
5637     context->getPerfCounters().bufferSuballocationCalls++;
5638 
5639     return VK_SUCCESS;
5640 }
5641 
initializeBarrierTracker(ErrorContext * context)5642 void BufferHelper::initializeBarrierTracker(ErrorContext *context)
5643 {
5644     Renderer *renderer       = context->getRenderer();
5645     mCurrentDeviceQueueIndex = context->getDeviceQueueIndex();
5646     mIsReleasedToExternal    = false;
5647     mCurrentWriteEvent.release(renderer);
5648     mCurrentReadEvents.release(renderer);
5649     mSerial                  = renderer->getResourceSerialFactory().generateBufferSerial();
5650     mCurrentWriteAccess      = 0;
5651     mCurrentReadAccess       = 0;
5652     mCurrentWriteStages      = 0;
5653     mCurrentReadStages       = 0;
5654 }
5655 
initializeNonZeroMemory(ErrorContext * context,VkBufferUsageFlags usage,VkDeviceSize size)5656 angle::Result BufferHelper::initializeNonZeroMemory(ErrorContext *context,
5657                                                     VkBufferUsageFlags usage,
5658                                                     VkDeviceSize size)
5659 {
5660     Renderer *renderer = context->getRenderer();
5661 
5662     // This memory can't be mapped, so the buffer must be marked as a transfer destination so we
5663     // can use a staging resource to initialize it to a non-zero value. If the memory is
5664     // mappable we do the initialization in AllocateBufferMemory.
5665     if (!isHostVisible() && (usage & VK_BUFFER_USAGE_TRANSFER_DST_BIT) != 0)
5666     {
5667         ASSERT((usage & VK_BUFFER_USAGE_TRANSFER_DST_BIT) != 0);
5668         // Staging buffer memory is non-zero-initialized in 'init'.
5669         StagingBuffer stagingBuffer;
5670         ANGLE_TRY(stagingBuffer.init(context, size, StagingUsage::Both));
5671 
5672         // Queue a DMA copy.
5673         VkBufferCopy copyRegion = {};
5674         copyRegion.srcOffset    = 0;
5675         copyRegion.dstOffset    = getOffset();
5676         copyRegion.size         = size;
5677 
5678         ScopedPrimaryCommandBuffer scopedCommandBuffer(renderer->getDevice());
5679         ANGLE_TRY(renderer->getCommandBufferOneOff(context, ProtectionType::Unprotected,
5680                                                    &scopedCommandBuffer));
5681         PrimaryCommandBuffer &commandBuffer = scopedCommandBuffer.get();
5682 
5683         commandBuffer.copyBuffer(stagingBuffer.getBuffer(), getBuffer(), 1, &copyRegion);
5684 
5685         ANGLE_VK_TRY(context, commandBuffer.end());
5686 
5687         QueueSerial queueSerial;
5688         ANGLE_TRY(renderer->queueSubmitOneOff(
5689             context, std::move(scopedCommandBuffer), ProtectionType::Unprotected,
5690             egl::ContextPriority::Medium, VK_NULL_HANDLE, 0, &queueSerial));
5691 
5692         stagingBuffer.collectGarbage(renderer, queueSerial);
5693         // Update both ResourceUse objects, since mReadOnlyUse tracks when the buffer can be
5694         // destroyed, and mReadWriteUse tracks when the write has completed.
5695         setWriteQueueSerial(queueSerial);
5696     }
5697     else if (isHostVisible())
5698     {
5699         // Can map the memory.
5700         // Pick an arbitrary value to initialize non-zero memory for sanitization.
5701         constexpr int kNonZeroInitValue = 55;
5702         uint8_t *mapPointer             = mSuballocation.getMappedMemory();
5703         memset(mapPointer, kNonZeroInitValue, static_cast<size_t>(getSize()));
5704         if (!isCoherent())
5705         {
5706             mSuballocation.flush(renderer);
5707         }
5708     }
5709 
5710     return angle::Result::Continue;
5711 }
5712 
getBufferForVertexArray(ContextVk * contextVk,VkDeviceSize actualDataSize,VkDeviceSize * offsetOut)5713 const Buffer &BufferHelper::getBufferForVertexArray(ContextVk *contextVk,
5714                                                     VkDeviceSize actualDataSize,
5715                                                     VkDeviceSize *offsetOut)
5716 {
5717     ASSERT(mSuballocation.valid());
5718     ASSERT(actualDataSize <= mSuballocation.getSize());
5719 
5720     if (!contextVk->hasRobustAccess() || !mSuballocation.isSuballocated() ||
5721         actualDataSize == mSuballocation.getSize())
5722     {
5723         *offsetOut = mSuballocation.getOffset();
5724         return mSuballocation.getBuffer();
5725     }
5726 
5727     if (!mBufferWithUserSize.valid())
5728     {
5729         // Allocate buffer that is backed by sub-range of the memory for vertex array usage. This is
5730         // only needed when robust resource init is enabled so that vulkan driver will know the
5731         // exact size of the vertex buffer it is supposedly to use and prevent out of bound access.
5732         VkBufferCreateInfo createInfo    = {};
5733         createInfo.sType                 = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
5734         createInfo.flags                 = 0;
5735         createInfo.size                  = actualDataSize;
5736         createInfo.usage                 = kVertexBufferUsageFlags | kIndexBufferUsageFlags;
5737         createInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
5738         createInfo.queueFamilyIndexCount = 0;
5739         createInfo.pQueueFamilyIndices   = nullptr;
5740         mBufferWithUserSize.init(contextVk->getDevice(), createInfo);
5741 
5742         VkMemoryRequirements memoryRequirements;
5743         mBufferWithUserSize.getMemoryRequirements(contextVk->getDevice(), &memoryRequirements);
5744         ASSERT(contextVk->getRenderer()->isMockICDEnabled() ||
5745                mSuballocation.getSize() >= memoryRequirements.size);
5746         ASSERT(!contextVk->getRenderer()->isMockICDEnabled() ||
5747                mSuballocation.getOffset() % memoryRequirements.alignment == 0);
5748 
5749         mBufferWithUserSize.bindMemory(contextVk->getDevice(), mSuballocation.getDeviceMemory(),
5750                                        mSuballocation.getOffset());
5751     }
5752     *offsetOut = 0;
5753     return mBufferWithUserSize;
5754 }
5755 
onBufferUserSizeChange(Renderer * renderer)5756 bool BufferHelper::onBufferUserSizeChange(Renderer *renderer)
5757 {
5758     // Buffer's user size and allocation size may be different due to alignment requirement. In
5759     // normal usage we just use the actual allocation size and it is good enough. But when
5760     // robustResourceInit is enabled, mBufferWithUserSize is created to mjatch the exact user
5761     // size. Thus when user size changes, we must clear and recreate this mBufferWithUserSize.
5762     if (mBufferWithUserSize.valid())
5763     {
5764         BufferSuballocation unusedSuballocation;
5765         renderer->collectSuballocationGarbage(mUse, std::move(unusedSuballocation),
5766                                               std::move(mBufferWithUserSize));
5767         mSerial = renderer->getResourceSerialFactory().generateBufferSerial();
5768         return true;
5769     }
5770     return false;
5771 }
5772 
destroy(Renderer * renderer)5773 void BufferHelper::destroy(Renderer *renderer)
5774 {
5775     mCurrentWriteEvent.release(renderer);
5776     mCurrentReadEvents.release(renderer);
5777     ASSERT(mDescriptorSetCacheManager.allValidEntriesAreCached(nullptr));
5778     mDescriptorSetCacheManager.destroyKeys(renderer);
5779     unmap(renderer);
5780     mBufferWithUserSize.destroy(renderer->getDevice());
5781     mSuballocation.destroy(renderer);
5782     if (mClientBuffer != nullptr)
5783     {
5784         ReleaseAndroidExternalMemory(renderer, mClientBuffer);
5785         mClientBuffer = nullptr;
5786     }
5787 }
5788 
release(Renderer * renderer)5789 void BufferHelper::release(Renderer *renderer)
5790 {
5791     mCurrentWriteEvent.release(renderer);
5792     mCurrentReadEvents.release(renderer);
5793     releaseImpl(renderer);
5794 }
5795 
release(Context * context)5796 void BufferHelper::release(Context *context)
5797 {
5798     mCurrentWriteEvent.release(context);
5799     mCurrentReadEvents.release(context);
5800     releaseImpl(context->getRenderer());
5801 }
5802 
releaseImpl(Renderer * renderer)5803 void BufferHelper::releaseImpl(Renderer *renderer)
5804 {
5805     ASSERT(mDescriptorSetCacheManager.empty());
5806     unmap(renderer);
5807 
5808     if (mSuballocation.valid())
5809     {
5810         renderer->collectSuballocationGarbage(mUse, std::move(mSuballocation),
5811                                               std::move(mBufferWithUserSize));
5812     }
5813     mUse.reset();
5814     mWriteUse.reset();
5815     ASSERT(!mBufferWithUserSize.valid());
5816 
5817     if (mClientBuffer != nullptr)
5818     {
5819         ReleaseAndroidExternalMemory(renderer, mClientBuffer);
5820         mClientBuffer = nullptr;
5821     }
5822 }
5823 
releaseBufferAndDescriptorSetCache(ContextVk * contextVk)5824 void BufferHelper::releaseBufferAndDescriptorSetCache(ContextVk *contextVk)
5825 {
5826     Renderer *renderer = contextVk->getRenderer();
5827 
5828     ASSERT(mDescriptorSetCacheManager.allValidEntriesAreCached(contextVk));
5829     if (renderer->hasResourceUseFinished(getResourceUse()))
5830     {
5831         mDescriptorSetCacheManager.destroyKeys(renderer);
5832     }
5833     else
5834     {
5835         mDescriptorSetCacheManager.releaseKeys(renderer);
5836     }
5837 
5838     release(contextVk);
5839 }
5840 
map(ErrorContext * context,uint8_t ** ptrOut)5841 angle::Result BufferHelper::map(ErrorContext *context, uint8_t **ptrOut)
5842 {
5843     if (!mSuballocation.isMapped())
5844     {
5845         ANGLE_VK_TRY(context, mSuballocation.map(context));
5846     }
5847     *ptrOut = mSuballocation.getMappedMemory();
5848     return angle::Result::Continue;
5849 }
5850 
mapWithOffset(ErrorContext * context,uint8_t ** ptrOut,size_t offset)5851 angle::Result BufferHelper::mapWithOffset(ErrorContext *context, uint8_t **ptrOut, size_t offset)
5852 {
5853     uint8_t *mapBufPointer;
5854     ANGLE_TRY(map(context, &mapBufPointer));
5855     *ptrOut = mapBufPointer + offset;
5856     return angle::Result::Continue;
5857 }
5858 
flush(Renderer * renderer,VkDeviceSize offset,VkDeviceSize size)5859 angle::Result BufferHelper::flush(Renderer *renderer, VkDeviceSize offset, VkDeviceSize size)
5860 {
5861     mSuballocation.flush(renderer);
5862     return angle::Result::Continue;
5863 }
flush(Renderer * renderer)5864 angle::Result BufferHelper::flush(Renderer *renderer)
5865 {
5866     return flush(renderer, 0, getSize());
5867 }
5868 
invalidate(Renderer * renderer,VkDeviceSize offset,VkDeviceSize size)5869 angle::Result BufferHelper::invalidate(Renderer *renderer, VkDeviceSize offset, VkDeviceSize size)
5870 {
5871     mSuballocation.invalidate(renderer);
5872     return angle::Result::Continue;
5873 }
invalidate(Renderer * renderer)5874 angle::Result BufferHelper::invalidate(Renderer *renderer)
5875 {
5876     return invalidate(renderer, 0, getSize());
5877 }
5878 
changeQueueFamily(uint32_t srcQueueFamilyIndex,uint32_t dstQueueFamilyIndex,OutsideRenderPassCommandBuffer * commandBuffer)5879 void BufferHelper::changeQueueFamily(uint32_t srcQueueFamilyIndex,
5880                                      uint32_t dstQueueFamilyIndex,
5881                                      OutsideRenderPassCommandBuffer *commandBuffer)
5882 {
5883     VkBufferMemoryBarrier bufferMemoryBarrier = {};
5884     bufferMemoryBarrier.sType                 = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
5885     bufferMemoryBarrier.srcAccessMask         = 0;
5886     bufferMemoryBarrier.dstAccessMask         = 0;
5887     bufferMemoryBarrier.srcQueueFamilyIndex   = srcQueueFamilyIndex;
5888     bufferMemoryBarrier.dstQueueFamilyIndex   = dstQueueFamilyIndex;
5889     bufferMemoryBarrier.buffer                = getBuffer().getHandle();
5890     bufferMemoryBarrier.offset                = getOffset();
5891     bufferMemoryBarrier.size                  = getSize();
5892 
5893     commandBuffer->bufferBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
5894                                  VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, &bufferMemoryBarrier);
5895 }
5896 
acquireFromExternal(DeviceQueueIndex externalQueueFamilyIndex,DeviceQueueIndex newDeviceQueueIndex,OutsideRenderPassCommandBuffer * commandBuffer)5897 void BufferHelper::acquireFromExternal(DeviceQueueIndex externalQueueFamilyIndex,
5898                                        DeviceQueueIndex newDeviceQueueIndex,
5899                                        OutsideRenderPassCommandBuffer *commandBuffer)
5900 {
5901     changeQueueFamily(externalQueueFamilyIndex.familyIndex(), newDeviceQueueIndex.familyIndex(),
5902                       commandBuffer);
5903     mCurrentDeviceQueueIndex = newDeviceQueueIndex;
5904     mIsReleasedToExternal    = false;
5905 }
5906 
releaseToExternal(DeviceQueueIndex externalQueueIndex,OutsideRenderPassCommandBuffer * commandBuffer)5907 void BufferHelper::releaseToExternal(DeviceQueueIndex externalQueueIndex,
5908                                      OutsideRenderPassCommandBuffer *commandBuffer)
5909 {
5910     if (mCurrentDeviceQueueIndex.familyIndex() != externalQueueIndex.familyIndex())
5911     {
5912         changeQueueFamily(mCurrentDeviceQueueIndex.familyIndex(), externalQueueIndex.familyIndex(),
5913                           commandBuffer);
5914         mCurrentDeviceQueueIndex = kInvalidDeviceQueueIndex;
5915     }
5916     mIsReleasedToExternal = true;
5917 }
5918 
recordReadBarrier(Context * context,VkAccessFlags readAccessType,VkPipelineStageFlags readPipelineStageFlags,PipelineStage stageIndex,PipelineBarrierArray * pipelineBarriers,EventBarrierArray * eventBarriers,RefCountedEventCollector * eventCollector)5919 void BufferHelper::recordReadBarrier(Context *context,
5920                                      VkAccessFlags readAccessType,
5921                                      VkPipelineStageFlags readPipelineStageFlags,
5922                                      PipelineStage stageIndex,
5923                                      PipelineBarrierArray *pipelineBarriers,
5924                                      EventBarrierArray *eventBarriers,
5925                                      RefCountedEventCollector *eventCollector)
5926 {
5927     // If the type of read already tracked by mCurrentReadEvents, it means we must already inserted
5928     // the barrier when mCurrentReadEvents is set. No new barrier is needed.
5929     EventStage eventStage = kBufferMemoryBarrierData[stageIndex].eventStage;
5930     if (mCurrentReadEvents.hasEventAndAccess(eventStage, readAccessType))
5931     {
5932         ASSERT((context->getRenderer()->getPipelineStageMask(eventStage) &
5933                 readPipelineStageFlags) == readPipelineStageFlags);
5934         ASSERT((mCurrentReadEvents.getAccessFlags(eventStage) & readAccessType) == readAccessType);
5935         return;
5936     }
5937 
5938     // If the type of read already tracked by mCurrentReadAccess, it means we must already inserted
5939     // the barrier when mCurrentReadAccess is set. No new barrier is needed.
5940     if ((mCurrentReadAccess & readAccessType) == readAccessType &&
5941         (mCurrentReadStages & readPipelineStageFlags) == readPipelineStageFlags)
5942     {
5943         return;
5944     }
5945 
5946     // Barrier against prior write VkEvent.
5947     if (mCurrentWriteEvent.valid())
5948     {
5949         eventBarriers->addEventMemoryBarrier(context->getRenderer(), mCurrentWriteEvent.getEvent(),
5950                                              mCurrentWriteEvent.getAccessFlags(),
5951                                              readPipelineStageFlags, readAccessType);
5952     }
5953 
5954     // Barrier against prior access that not tracked by VkEvent using pipelineBarrier.
5955     if (mCurrentWriteAccess != 0)
5956     {
5957         pipelineBarriers->mergeMemoryBarrier(stageIndex, mCurrentWriteStages,
5958                                              readPipelineStageFlags, mCurrentWriteAccess,
5959                                              readAccessType);
5960     }
5961 }
5962 
recordReadEvent(Context * context,VkAccessFlags readAccessType,VkPipelineStageFlags readPipelineStageFlags,PipelineStage readStage,const QueueSerial & queueSerial,EventStage eventStage,RefCountedEventArray * refCountedEventArray)5963 void BufferHelper::recordReadEvent(Context *context,
5964                                    VkAccessFlags readAccessType,
5965                                    VkPipelineStageFlags readPipelineStageFlags,
5966                                    PipelineStage readStage,
5967                                    const QueueSerial &queueSerial,
5968                                    EventStage eventStage,
5969                                    RefCountedEventArray *refCountedEventArray)
5970 {
5971     bool useVkEvent = false;
5972     if (context->getFeatures().useVkEventForBufferBarrier.enabled &&
5973         eventStage != EventStage::InvalidEnum)
5974     {
5975         // VkCmdSetEvent can remove the unnecessary GPU pipeline bubble that comes from false
5976         // dependency between fragment and vertex/transfer/compute stages. But it also comes with
5977         // higher overhead. In order to strike the balance, right now we only track it with VkEvent
5978         // if it ever written by transform feedback.
5979         useVkEvent = mTransformFeedbackWriteHeuristicBits.any();
5980     }
5981 
5982     if (useVkEvent && refCountedEventArray->initEventAtStage(context, eventStage))
5983     {
5984         // Replace the mCurrentReadEvents so that it tracks the current read so that we can
5985         // waitEvent later.
5986         mCurrentReadEvents.replaceEventAtStage(
5987             context, eventStage, refCountedEventArray->getEvent(eventStage), readAccessType);
5988     }
5989     else
5990     {
5991         // Accumulate new read usage to be used in pipelineBarrier.
5992         mCurrentReadAccess |= readAccessType;
5993         mCurrentReadStages |= readPipelineStageFlags;
5994     }
5995 
5996     if (getResourceUse() >= queueSerial)
5997     {
5998         // We should not run into situation that RP is writing to it while we are reading it here
5999         ASSERT(!(getWriteResourceUse() >= queueSerial));
6000         // A buffer could have read accessed by both renderPassCommands and
6001         // outsideRenderPassCommands and there is no need to endRP or flush. In this case, the
6002         // renderPassCommands' read will override the outsideRenderPassCommands' read, since its
6003         // queueSerial must be greater than outsideRP.
6004     }
6005     else
6006     {
6007         setQueueSerial(queueSerial);
6008     }
6009 }
6010 
recordWriteBarrier(Context * context,VkAccessFlags writeAccessType,VkPipelineStageFlags writeStage,PipelineStage stageIndex,const QueueSerial & queueSerial,PipelineBarrierArray * pipelineBarriers,EventBarrierArray * eventBarriers,RefCountedEventCollector * eventCollector)6011 void BufferHelper::recordWriteBarrier(Context *context,
6012                                       VkAccessFlags writeAccessType,
6013                                       VkPipelineStageFlags writeStage,
6014                                       PipelineStage stageIndex,
6015                                       const QueueSerial &queueSerial,
6016                                       PipelineBarrierArray *pipelineBarriers,
6017                                       EventBarrierArray *eventBarriers,
6018                                       RefCountedEventCollector *eventCollector)
6019 {
6020     Renderer *renderer = context->getRenderer();
6021 
6022     // Barrier against prior read VkEvents.
6023     if (!mCurrentReadEvents.empty())
6024     {
6025         // If we already have a event in the same command buffer, fall back to pipeline. Otherwise
6026         // you may run into wait an event that has not been set. This may be can be removed once we
6027         // fix https://issuetracker.google.com/392968868
6028         if (usedByCommandBuffer(queueSerial))
6029         {
6030             for (EventStage eventStage : mCurrentReadEvents.getBitMask())
6031             {
6032                 mCurrentReadStages |= renderer->getPipelineStageMask(eventStage);
6033                 mCurrentReadAccess |= mCurrentReadEvents.getAccessFlags(eventStage);
6034             }
6035         }
6036         else
6037         {
6038             for (EventStage eventStage : mCurrentReadEvents.getBitMask())
6039             {
6040                 const RefCountedEvent &waitEvent = mCurrentReadEvents.getEvent(eventStage);
6041                 const VkAccessFlags srcAccess    = mCurrentReadEvents.getAccessFlags(eventStage);
6042                 eventBarriers->addEventMemoryBarrier(renderer, waitEvent, srcAccess, writeStage,
6043                                                      writeAccessType);
6044             }
6045         }
6046         // Garbage collect the event, which tracks GPU completion automatically.
6047         mCurrentReadEvents.releaseToEventCollector(eventCollector);
6048     }
6049 
6050     // Barrier against prior write VkEvent.
6051     if (mCurrentWriteEvent.valid())
6052     {
6053         const VkPipelineStageFlags srcStageFlags =
6054             renderer->getPipelineStageMask(mCurrentWriteEvent.getEventStage());
6055 
6056         // If we already have a write event in the same command buffer, fall back to pipeline
6057         // barrier. Using VkEvent to track multiple writes either requires tracking multiple write
6058         // events or has to replace existing event with another event that tracks more pipeline
6059         // stage bits. Both are a bit complex. Without evidence showing we are hitting performance
6060         // issue in real world situation, this will just use pipeline barriers to track extra stages
6061         // that not captured by mCurrentWriteEvent.
6062         if (writtenByCommandBuffer(queueSerial))
6063         {
6064             mCurrentWriteStages |= srcStageFlags;
6065             mCurrentWriteAccess |= mCurrentWriteEvent.getAccessFlags();
6066         }
6067         else
6068         {
6069             eventBarriers->addEventMemoryBarrier(
6070                 context->getRenderer(), mCurrentWriteEvent.getEvent(),
6071                 mCurrentWriteEvent.getAccessFlags(), writeStage, writeAccessType);
6072         }
6073         // Garbage collect the event, which tracks GPU completion automatically.
6074         mCurrentWriteEvent.releaseToEventCollector(eventCollector);
6075     }
6076 
6077     // We don't need to check mCurrentReadStages here since if it is not zero,
6078     // mCurrentReadAccess must not be zero as well. stage is finer grain than accessType.
6079     ASSERT((!mCurrentReadStages && !mCurrentReadAccess) ||
6080            (mCurrentReadStages && mCurrentReadAccess));
6081 
6082     // Barrier against prior access that not tracked by VkEvent using pipelineBarrier.
6083     if (mCurrentReadAccess != 0 || mCurrentWriteAccess != 0)
6084     {
6085         // If there are more pipeline stage bits not captured by eventBarrier, use pipelineBarrier.
6086         VkPipelineStageFlags srcStageMask = mCurrentWriteStages | mCurrentReadStages;
6087         if (srcStageMask)
6088         {
6089             pipelineBarriers->mergeMemoryBarrier(stageIndex, srcStageMask, writeStage,
6090                                                  mCurrentWriteAccess, writeAccessType);
6091         }
6092 
6093         mCurrentReadStages  = 0;
6094         mCurrentReadAccess  = 0;
6095         mCurrentWriteStages = 0;
6096         mCurrentWriteAccess = 0;
6097     }
6098 }
6099 
recordWriteEvent(Context * context,VkAccessFlags writeAccessType,VkPipelineStageFlags writePipelineStageFlags,const QueueSerial & writeQueueSerial,PipelineStage writeStage,RefCountedEventArray * refCountedEventArray)6100 void BufferHelper::recordWriteEvent(Context *context,
6101                                     VkAccessFlags writeAccessType,
6102                                     VkPipelineStageFlags writePipelineStageFlags,
6103                                     const QueueSerial &writeQueueSerial,
6104                                     PipelineStage writeStage,
6105                                     RefCountedEventArray *refCountedEventArray)
6106 {
6107     EventStage eventStage = kBufferMemoryBarrierData[writeStage].eventStage;
6108     bool useVkEvent       = false;
6109 
6110     if (context->getFeatures().useVkEventForBufferBarrier.enabled &&
6111         eventStage != EventStage::InvalidEnum)
6112     {
6113         ASSERT(mCurrentReadEvents.empty());
6114         updatePipelineStageWriteHistory(writeStage);
6115 
6116         // VkCmdSetEvent can remove the unnecessary GPU pipeline bubble that comes from false
6117         // dependency between fragment and vertex/transfer/compute stages. But it also comes with
6118         // higher overhead. In order to strike the balance, right now we only track it with VkEvent
6119         // if it ever written by transform feedback.
6120         useVkEvent = mTransformFeedbackWriteHeuristicBits.any();
6121 
6122         // We only track one write event. In case of multiple writes like write from different
6123         // shader stages in the same render pass, only the first write is tracked by event,
6124         // additional writes will still be tracked by pipelineBarriers.
6125         if (mCurrentWriteEvent.valid())
6126         {
6127             useVkEvent = false;
6128         }
6129     }
6130 
6131     if (useVkEvent && refCountedEventArray->initEventAtStage(context, eventStage))
6132     {
6133         // Copy the event to mCurrentEvent so that we can wait for it in future. This will add extra
6134         // refcount to the underlying VkEvent.
6135         mCurrentWriteEvent.setEventAndAccessFlags(refCountedEventArray->getEvent(eventStage),
6136                                                   writeAccessType);
6137     }
6138     else
6139     {
6140         // Reset usages on the new write to be used by pipelineBarrier later.
6141         mCurrentWriteAccess = writeAccessType;
6142         mCurrentWriteStages = writePipelineStageFlags;
6143     }
6144 
6145     setWriteQueueSerial(writeQueueSerial);
6146 }
6147 
fillWithColor(const angle::Color<uint8_t> & color,const gl::InternalFormat & internalFormat)6148 void BufferHelper::fillWithColor(const angle::Color<uint8_t> &color,
6149                                  const gl::InternalFormat &internalFormat)
6150 {
6151     uint32_t count =
6152         static_cast<uint32_t>(getSize()) / static_cast<uint32_t>(internalFormat.pixelBytes);
6153     void *buffer = static_cast<void *>(getMappedMemory());
6154 
6155     switch (internalFormat.internalFormat)
6156     {
6157         case GL_RGB565:
6158         {
6159             uint16_t pixelColor =
6160                 ((color.blue & 0xF8) << 11) | ((color.green & 0xFC) << 5) | (color.red & 0xF8);
6161             uint16_t *pixelPtr = static_cast<uint16_t *>(buffer);
6162             std::fill_n<uint16_t *, uint32_t, uint16_t>(pixelPtr, count, pixelColor);
6163         }
6164         break;
6165         case GL_RGBA8:
6166         {
6167             uint32_t pixelColor =
6168                 (color.alpha << 24) | (color.blue << 16) | (color.green << 8) | (color.red);
6169             uint32_t *pixelPtr = static_cast<uint32_t *>(buffer);
6170             std::fill_n<uint32_t *, uint32_t, uint32_t>(pixelPtr, count, pixelColor);
6171         }
6172         break;
6173         case GL_BGR565_ANGLEX:
6174         {
6175             uint16_t pixelColor =
6176                 ((color.red & 0xF8) << 11) | ((color.green & 0xFC) << 5) | (color.blue & 0xF8);
6177             uint16_t *pixelPtr = static_cast<uint16_t *>(buffer);
6178             std::fill_n<uint16_t *, uint32_t, uint16_t>(pixelPtr, count, pixelColor);
6179         }
6180         break;
6181         case GL_BGRA8_EXT:
6182         {
6183             uint32_t pixelColor =
6184                 (color.alpha << 24) | (color.red << 16) | (color.green << 8) | (color.blue);
6185             uint32_t *pixelPtr = static_cast<uint32_t *>(buffer);
6186             std::fill_n<uint32_t *, uint32_t, uint32_t>(pixelPtr, count, pixelColor);
6187         }
6188         break;
6189         default:
6190             UNREACHABLE();  // Unsupported format
6191     }
6192 }
6193 
fillWithPattern(const void * pattern,size_t patternSize,size_t offset,size_t size)6194 void BufferHelper::fillWithPattern(const void *pattern,
6195                                    size_t patternSize,
6196                                    size_t offset,
6197                                    size_t size)
6198 {
6199     ASSERT(offset + size <= getSize());
6200     ASSERT((size % patternSize) == 0);
6201     ASSERT((offset % patternSize) == 0);
6202 
6203     uint8_t *buffer = getMappedMemory() + offset;
6204     std::memcpy(buffer, pattern, patternSize);
6205     size_t remaining = size - patternSize;
6206     while (remaining > patternSize)
6207     {
6208         std::memcpy(buffer + patternSize, buffer, patternSize);
6209         remaining -= patternSize;
6210         patternSize *= 2;
6211     }
6212     std::memcpy(buffer + patternSize, buffer, remaining);
6213     return;
6214 }
6215 
6216 // Used for ImageHelper non-zero memory allocation when useVmaForImageSuballocation is disabled.
InitMappableDeviceMemory(ErrorContext * context,DeviceMemory * deviceMemory,VkDeviceSize size,int value,VkMemoryPropertyFlags memoryPropertyFlags)6217 angle::Result InitMappableDeviceMemory(ErrorContext *context,
6218                                        DeviceMemory *deviceMemory,
6219                                        VkDeviceSize size,
6220                                        int value,
6221                                        VkMemoryPropertyFlags memoryPropertyFlags)
6222 {
6223     ASSERT(!context->getFeatures().useVmaForImageSuballocation.enabled);
6224     VkDevice device = context->getDevice();
6225 
6226     uint8_t *mapPointer;
6227     ANGLE_VK_TRY(context, deviceMemory->map(device, 0, VK_WHOLE_SIZE, 0, &mapPointer));
6228     memset(mapPointer, value, static_cast<size_t>(size));
6229 
6230     // if the memory type is not host coherent, we perform an explicit flush.
6231     if ((memoryPropertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0)
6232     {
6233         VkMappedMemoryRange mappedRange = {};
6234         mappedRange.sType               = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
6235         mappedRange.memory              = deviceMemory->getHandle();
6236         mappedRange.size                = VK_WHOLE_SIZE;
6237         ANGLE_VK_TRY(context, vkFlushMappedMemoryRanges(device, 1, &mappedRange));
6238     }
6239 
6240     deviceMemory->unmap(device);
6241 
6242     return angle::Result::Continue;
6243 }
6244 
6245 // ImageHelper implementation.
ImageHelper()6246 ImageHelper::ImageHelper()
6247 {
6248     resetCachedProperties();
6249     // Reserve reasonable amount of space to avoid storage reallocation.
6250     mSubresourceUpdates.reserve(12);
6251 }
6252 
~ImageHelper()6253 ImageHelper::~ImageHelper()
6254 {
6255     ASSERT(!valid());
6256     ASSERT(!mAcquireNextImageSemaphore.valid());
6257 }
6258 
resetCachedProperties()6259 void ImageHelper::resetCachedProperties()
6260 {
6261     mImageType                   = VK_IMAGE_TYPE_2D;
6262     mTilingMode                  = VK_IMAGE_TILING_OPTIMAL;
6263     mCreateFlags                 = kVkImageCreateFlagsNone;
6264     mUsage                       = 0;
6265     mExtents                     = {};
6266     mRotatedAspectRatio          = false;
6267     mIntendedFormatID            = angle::FormatID::NONE;
6268     mActualFormatID              = angle::FormatID::NONE;
6269     mSamples                     = 1;
6270     mImageSerial                 = kInvalidImageSerial;
6271     mCurrentLayout               = ImageLayout::Undefined;
6272     mCurrentDeviceQueueIndex     = kInvalidDeviceQueueIndex;
6273     mIsReleasedToExternal        = false;
6274     mIsForeignImage              = false;
6275     mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
6276     mCurrentShaderReadStageMask  = 0;
6277     mFirstAllocatedLevel         = gl::LevelIndex(0);
6278     mLayerCount                  = 0;
6279     mLevelCount                  = 0;
6280     mTotalStagedBufferUpdateSize = 0;
6281     mAllocationSize              = 0;
6282     mMemoryAllocationType        = MemoryAllocationType::InvalidEnum;
6283     mMemoryTypeIndex             = kInvalidMemoryTypeIndex;
6284     std::fill(mViewFormats.begin(), mViewFormats.begin() + mViewFormats.max_size(),
6285               VK_FORMAT_UNDEFINED);
6286     mYcbcrConversionDesc.reset();
6287     mCurrentSingleClearValue.reset();
6288     mRenderPassUsageFlags.reset();
6289 
6290     setEntireContentUndefined();
6291 }
6292 
setEntireContentDefined()6293 void ImageHelper::setEntireContentDefined()
6294 {
6295     for (LevelContentDefinedMask &levelContentDefined : mContentDefined)
6296     {
6297         levelContentDefined.set();
6298     }
6299     for (LevelContentDefinedMask &levelContentDefined : mStencilContentDefined)
6300     {
6301         levelContentDefined.set();
6302     }
6303 }
6304 
setEntireContentUndefined()6305 void ImageHelper::setEntireContentUndefined()
6306 {
6307     for (LevelContentDefinedMask &levelContentDefined : mContentDefined)
6308     {
6309         levelContentDefined.reset();
6310     }
6311     for (LevelContentDefinedMask &levelContentDefined : mStencilContentDefined)
6312     {
6313         levelContentDefined.reset();
6314     }
6315 
6316     // Note: this function is typically called during init/release, but also when importing an image
6317     // from Vulkan, so unlike invalidateSubresourceContentImpl, it doesn't attempt to make sure
6318     // emulated formats have a clear staged.
6319 }
6320 
setContentDefined(LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags)6321 void ImageHelper::setContentDefined(LevelIndex levelStart,
6322                                     uint32_t levelCount,
6323                                     uint32_t layerStart,
6324                                     uint32_t layerCount,
6325                                     VkImageAspectFlags aspectFlags)
6326 {
6327     // Mark the range as defined.  Layers above 8 are discarded, and are always assumed to have
6328     // defined contents.
6329     if (layerStart >= kMaxContentDefinedLayerCount)
6330     {
6331         return;
6332     }
6333 
6334     uint8_t layerRangeBits =
6335         GetContentDefinedLayerRangeBits(layerStart, layerCount, kMaxContentDefinedLayerCount);
6336 
6337     for (uint32_t levelOffset = 0; levelOffset < levelCount; ++levelOffset)
6338     {
6339         LevelIndex level = levelStart + levelOffset;
6340 
6341         if ((aspectFlags & ~VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
6342         {
6343             getLevelContentDefined(level) |= layerRangeBits;
6344         }
6345         if ((aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) != 0)
6346         {
6347             getLevelStencilContentDefined(level) |= layerRangeBits;
6348         }
6349     }
6350 }
6351 
getLevelContentDefined(LevelIndex level)6352 ImageHelper::LevelContentDefinedMask &ImageHelper::getLevelContentDefined(LevelIndex level)
6353 {
6354     return mContentDefined[level.get()];
6355 }
6356 
getLevelStencilContentDefined(LevelIndex level)6357 ImageHelper::LevelContentDefinedMask &ImageHelper::getLevelStencilContentDefined(LevelIndex level)
6358 {
6359     return mStencilContentDefined[level.get()];
6360 }
6361 
getLevelContentDefined(LevelIndex level) const6362 const ImageHelper::LevelContentDefinedMask &ImageHelper::getLevelContentDefined(
6363     LevelIndex level) const
6364 {
6365     return mContentDefined[level.get()];
6366 }
6367 
getLevelStencilContentDefined(LevelIndex level) const6368 const ImageHelper::LevelContentDefinedMask &ImageHelper::getLevelStencilContentDefined(
6369     LevelIndex level) const
6370 {
6371     return mStencilContentDefined[level.get()];
6372 }
6373 
deriveConversionDesc(ErrorContext * context,angle::FormatID actualFormatID,angle::FormatID intendedFormatID)6374 YcbcrConversionDesc ImageHelper::deriveConversionDesc(ErrorContext *context,
6375                                                       angle::FormatID actualFormatID,
6376                                                       angle::FormatID intendedFormatID)
6377 {
6378     YcbcrConversionDesc conversionDesc{};
6379     const angle::Format &actualFormat = angle::Format::Get(actualFormatID);
6380 
6381     if (actualFormat.isYUV)
6382     {
6383         // Build a suitable conversionDesc; the image is not external but may be YUV
6384         // if app is using ANGLE's YUV internalformat extensions.
6385         Renderer *renderer = context->getRenderer();
6386 
6387         // The Vulkan spec states: The potential format features of the sampler YCBCR conversion
6388         // must support VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT or
6389         // VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT
6390         constexpr VkFormatFeatureFlags kChromaSubSampleFeatureBits =
6391             VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT |
6392             VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT |
6393             VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT;
6394 
6395         VkFormatFeatureFlags supportedFeatureBits =
6396             renderer->getImageFormatFeatureBits(actualFormatID, kChromaSubSampleFeatureBits);
6397 
6398         VkChromaLocation supportedLocation =
6399             (supportedFeatureBits & VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT) != 0
6400                 ? VK_CHROMA_LOCATION_COSITED_EVEN
6401                 : VK_CHROMA_LOCATION_MIDPOINT;
6402         vk::YcbcrLinearFilterSupport linearFilterSupported =
6403             (supportedFeatureBits &
6404              VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT) != 0
6405                 ? vk::YcbcrLinearFilterSupport::Supported
6406                 : vk::YcbcrLinearFilterSupport::Unsupported;
6407 
6408         VkSamplerYcbcrModelConversion conversionModel = VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601;
6409         VkSamplerYcbcrRange colorRange                = VK_SAMPLER_YCBCR_RANGE_ITU_NARROW;
6410         VkFilter chromaFilter                         = kDefaultYCbCrChromaFilter;
6411         VkComponentMapping components                 = {
6412             VK_COMPONENT_SWIZZLE_IDENTITY,
6413             VK_COMPONENT_SWIZZLE_IDENTITY,
6414             VK_COMPONENT_SWIZZLE_IDENTITY,
6415             VK_COMPONENT_SWIZZLE_IDENTITY,
6416         };
6417 
6418         conversionDesc.update(renderer, 0, conversionModel, colorRange, supportedLocation,
6419                               supportedLocation, chromaFilter, components, intendedFormatID,
6420                               linearFilterSupported);
6421     }
6422 
6423     return conversionDesc;
6424 }
6425 
init(ErrorContext * 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)6426 angle::Result ImageHelper::init(ErrorContext *context,
6427                                 gl::TextureType textureType,
6428                                 const VkExtent3D &extents,
6429                                 const Format &format,
6430                                 GLint samples,
6431                                 VkImageUsageFlags usage,
6432                                 gl::LevelIndex firstLevel,
6433                                 uint32_t mipLevels,
6434                                 uint32_t layerCount,
6435                                 bool isRobustResourceInitEnabled,
6436                                 bool hasProtectedContent)
6437 {
6438     return initExternal(context, textureType, extents, format.getIntendedFormatID(),
6439                         format.getActualRenderableImageFormatID(), samples, usage,
6440                         kVkImageCreateFlagsNone, ImageLayout::Undefined, nullptr, firstLevel,
6441                         mipLevels, layerCount, isRobustResourceInitEnabled, hasProtectedContent,
6442                         deriveConversionDesc(context, format.getActualRenderableImageFormatID(),
6443                                              format.getIntendedFormatID()),
6444                         nullptr);
6445 }
6446 
initFromCreateInfo(ErrorContext * context,const VkImageCreateInfo & requestedCreateInfo,VkMemoryPropertyFlags memoryPropertyFlags)6447 angle::Result ImageHelper::initFromCreateInfo(ErrorContext *context,
6448                                               const VkImageCreateInfo &requestedCreateInfo,
6449                                               VkMemoryPropertyFlags memoryPropertyFlags)
6450 {
6451     ASSERT(!valid());
6452     ASSERT(!IsAnySubresourceContentDefined(mContentDefined));
6453     ASSERT(!IsAnySubresourceContentDefined(mStencilContentDefined));
6454 
6455     mImageType          = requestedCreateInfo.imageType;
6456     mExtents            = requestedCreateInfo.extent;
6457     mRotatedAspectRatio = false;
6458     mSamples            = std::max((int)requestedCreateInfo.samples, 1);
6459     mImageSerial        = context->getRenderer()->getResourceSerialFactory().generateImageSerial();
6460     mLayerCount         = requestedCreateInfo.arrayLayers;
6461     mLevelCount         = requestedCreateInfo.mipLevels;
6462     mUsage              = requestedCreateInfo.usage;
6463 
6464     // Validate that mLayerCount is compatible with the image type
6465     ASSERT(requestedCreateInfo.imageType != VK_IMAGE_TYPE_3D || mLayerCount == 1);
6466     ASSERT(requestedCreateInfo.imageType != VK_IMAGE_TYPE_2D || mExtents.depth == 1);
6467 
6468     mCurrentLayout = ImageLayout::Undefined;
6469 
6470     ANGLE_VK_TRY(context, mImage.init(context->getDevice(), requestedCreateInfo));
6471 
6472     mVkImageCreateInfo               = requestedCreateInfo;
6473     mVkImageCreateInfo.pNext         = nullptr;
6474     mVkImageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
6475 
6476     MemoryProperties memoryProperties = {};
6477 
6478     ANGLE_TRY(initMemoryAndNonZeroFillIfNeeded(context, false, memoryProperties,
6479                                                memoryPropertyFlags,
6480                                                vk::MemoryAllocationType::StagingImage));
6481     return angle::Result::Continue;
6482 }
6483 
copyToBufferOneOff(ErrorContext * context,BufferHelper * stagingBuffer,VkBufferImageCopy copyRegion)6484 angle::Result ImageHelper::copyToBufferOneOff(ErrorContext *context,
6485                                               BufferHelper *stagingBuffer,
6486                                               VkBufferImageCopy copyRegion)
6487 {
6488     Renderer *renderer = context->getRenderer();
6489     ScopedPrimaryCommandBuffer scopedCommandBuffer(renderer->getDevice());
6490     ANGLE_TRY(renderer->getCommandBufferOneOff(context, ProtectionType::Unprotected,
6491                                                &scopedCommandBuffer));
6492     PrimaryCommandBuffer &commandBuffer = scopedCommandBuffer.get();
6493 
6494     VkSemaphore acquireNextImageSemaphore;
6495     recordBarrierOneOffImpl(renderer, getAspectFlags(), ImageLayout::TransferDst,
6496                             renderer->getQueueFamilyIndex(), &commandBuffer,
6497                             &acquireNextImageSemaphore);
6498     commandBuffer.copyBufferToImage(stagingBuffer->getBuffer().getHandle(), getImage(),
6499                                     getCurrentLayout(), 1, &copyRegion);
6500     ANGLE_VK_TRY(context, commandBuffer.end());
6501 
6502     QueueSerial submitQueueSerial;
6503     ANGLE_TRY(renderer->queueSubmitOneOff(
6504         context, std::move(scopedCommandBuffer), ProtectionType::Unprotected,
6505         egl::ContextPriority::Medium, acquireNextImageSemaphore,
6506         kSwapchainAcquireImageWaitStageFlags, &submitQueueSerial));
6507 
6508     return renderer->finishQueueSerial(context, submitQueueSerial);
6509 }
6510 
initMSAASwapchain(ErrorContext * context,gl::TextureType textureType,const VkExtent3D & extents,bool rotatedAspectRatio,angle::FormatID intendedFormatID,angle::FormatID actualFormatID,GLint samples,VkImageUsageFlags usage,gl::LevelIndex firstLevel,uint32_t mipLevels,uint32_t layerCount,bool isRobustResourceInitEnabled,bool hasProtectedContent)6511 angle::Result ImageHelper::initMSAASwapchain(ErrorContext *context,
6512                                              gl::TextureType textureType,
6513                                              const VkExtent3D &extents,
6514                                              bool rotatedAspectRatio,
6515                                              angle::FormatID intendedFormatID,
6516                                              angle::FormatID actualFormatID,
6517                                              GLint samples,
6518                                              VkImageUsageFlags usage,
6519                                              gl::LevelIndex firstLevel,
6520                                              uint32_t mipLevels,
6521                                              uint32_t layerCount,
6522                                              bool isRobustResourceInitEnabled,
6523                                              bool hasProtectedContent)
6524 {
6525     ANGLE_TRY(initExternal(context, textureType, extents, intendedFormatID, actualFormatID, samples,
6526                            usage, kVkImageCreateFlagsNone, ImageLayout::Undefined, nullptr,
6527                            firstLevel, mipLevels, layerCount, isRobustResourceInitEnabled,
6528                            hasProtectedContent, YcbcrConversionDesc{}, nullptr));
6529     if (rotatedAspectRatio)
6530     {
6531         std::swap(mExtents.width, mExtents.height);
6532     }
6533     mRotatedAspectRatio = rotatedAspectRatio;
6534     return angle::Result::Continue;
6535 }
6536 
initExternal(ErrorContext * 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)6537 angle::Result ImageHelper::initExternal(ErrorContext *context,
6538                                         gl::TextureType textureType,
6539                                         const VkExtent3D &extents,
6540                                         angle::FormatID intendedFormatID,
6541                                         angle::FormatID actualFormatID,
6542                                         GLint samples,
6543                                         VkImageUsageFlags usage,
6544                                         VkImageCreateFlags additionalCreateFlags,
6545                                         ImageLayout initialLayout,
6546                                         const void *externalImageCreateInfo,
6547                                         gl::LevelIndex firstLevel,
6548                                         uint32_t mipLevels,
6549                                         uint32_t layerCount,
6550                                         bool isRobustResourceInitEnabled,
6551                                         bool hasProtectedContent,
6552                                         YcbcrConversionDesc conversionDesc,
6553                                         const void *compressionControl)
6554 {
6555     ASSERT(!valid());
6556     ASSERT(!IsAnySubresourceContentDefined(mContentDefined));
6557     ASSERT(!IsAnySubresourceContentDefined(mStencilContentDefined));
6558 
6559     Renderer *renderer = context->getRenderer();
6560 
6561     mImageType           = gl_vk::GetImageType(textureType);
6562     mExtents             = extents;
6563     mRotatedAspectRatio  = false;
6564     mIntendedFormatID    = intendedFormatID;
6565     mActualFormatID      = actualFormatID;
6566     mSamples             = std::max(samples, 1);
6567     mImageSerial         = renderer->getResourceSerialFactory().generateImageSerial();
6568     mFirstAllocatedLevel = firstLevel;
6569     mLevelCount          = mipLevels;
6570     mLayerCount          = layerCount;
6571     mCreateFlags =
6572         vk::GetMinimalImageCreateFlags(renderer, textureType, usage) | additionalCreateFlags;
6573     mUsage = usage;
6574 
6575     // Validate that mLayerCount is compatible with the texture type
6576     ASSERT(textureType != gl::TextureType::_3D || mLayerCount == 1);
6577     ASSERT(textureType != gl::TextureType::_2DArray || mExtents.depth == 1);
6578     ASSERT(textureType != gl::TextureType::External || mLayerCount == 1);
6579     ASSERT(textureType != gl::TextureType::Rectangle || mLayerCount == 1);
6580     ASSERT(textureType != gl::TextureType::CubeMap || mLayerCount == gl::kCubeFaceCount);
6581     ASSERT(textureType != gl::TextureType::CubeMapArray || mLayerCount % gl::kCubeFaceCount == 0);
6582 
6583     // If externalImageCreateInfo is provided, use that directly.  Otherwise derive the necessary
6584     // pNext chain.
6585     const void *imageCreateInfoPNext = externalImageCreateInfo;
6586     VkImageFormatListCreateInfoKHR imageFormatListInfoStorage;
6587     ImageListFormats imageListFormatsStorage;
6588 
6589     if (externalImageCreateInfo == nullptr)
6590     {
6591         imageCreateInfoPNext = DeriveCreateInfoPNext(
6592             context, mUsage, actualFormatID, compressionControl, &imageFormatListInfoStorage,
6593             &imageListFormatsStorage, &mCreateFlags);
6594     }
6595     else
6596     {
6597         // Derive the tiling for external images.
6598         deriveExternalImageTiling(externalImageCreateInfo);
6599     }
6600 
6601     mYcbcrConversionDesc = conversionDesc;
6602 
6603     const angle::Format &actualFormat   = angle::Format::Get(actualFormatID);
6604     const angle::Format &intendedFormat = angle::Format::Get(intendedFormatID);
6605     VkFormat actualVkFormat             = GetVkFormatFromFormatID(renderer, actualFormatID);
6606 
6607     ANGLE_TRACE_EVENT_INSTANT("gpu.angle.texture_metrics", "ImageHelper::initExternal",
6608                               "intended_format", intendedFormat.glInternalFormat, "actual_format",
6609                               actualFormat.glInternalFormat, "width", extents.width, "height",
6610                               extents.height);
6611 
6612     if (actualFormat.isYUV)
6613     {
6614         ASSERT(mYcbcrConversionDesc.valid());
6615 
6616         // The Vulkan spec states: If the pNext chain includes a VkExternalFormatANDROID structure
6617         // whose externalFormat member is not 0, flags must not include
6618         // VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT
6619         if (!IsYUVExternalFormat(actualFormatID))
6620         {
6621             // The Vulkan spec states: If sampler is used and the VkFormat of the image is a
6622             // multi-planar format, the image must have been created with
6623             // VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT
6624             mCreateFlags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
6625         }
6626     }
6627 
6628     if (hasProtectedContent)
6629     {
6630         mCreateFlags |= VK_IMAGE_CREATE_PROTECTED_BIT;
6631     }
6632 
6633     VkImageCreateInfo imageInfo = {};
6634     imageInfo.sType             = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
6635     imageInfo.pNext             = imageCreateInfoPNext;
6636     imageInfo.flags             = mCreateFlags;
6637     imageInfo.imageType         = mImageType;
6638     imageInfo.format            = actualVkFormat;
6639     imageInfo.extent            = mExtents;
6640     imageInfo.mipLevels         = mLevelCount;
6641     imageInfo.arrayLayers       = mLayerCount;
6642     imageInfo.samples =
6643         gl_vk::GetSamples(mSamples, context->getFeatures().limitSampleCountTo2.enabled);
6644     imageInfo.tiling                = mTilingMode;
6645     imageInfo.usage                 = mUsage;
6646     imageInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
6647     imageInfo.queueFamilyIndexCount = 0;
6648     imageInfo.pQueueFamilyIndices   = nullptr;
6649     imageInfo.initialLayout         = ConvertImageLayoutToVkImageLayout(initialLayout);
6650 
6651     mCurrentLayout               = initialLayout;
6652     mCurrentDeviceQueueIndex     = kInvalidDeviceQueueIndex;
6653     mIsReleasedToExternal        = false;
6654     mIsForeignImage              = false;
6655     mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
6656     mCurrentShaderReadStageMask  = 0;
6657 
6658     ANGLE_VK_TRY(context, mImage.init(context->getDevice(), imageInfo));
6659 
6660     // Find the image formats in pNext chain in imageInfo.
6661     deriveImageViewFormatFromCreateInfoPNext(imageInfo, mViewFormats);
6662 
6663     mVkImageCreateInfo               = imageInfo;
6664     mVkImageCreateInfo.pNext         = nullptr;
6665     mVkImageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
6666 
6667     stageClearIfEmulatedFormat(isRobustResourceInitEnabled, externalImageCreateInfo != nullptr);
6668 
6669     // Consider the contents defined for any image that has the PREINITIALIZED layout, or is
6670     // imported from external.
6671     if (initialLayout != ImageLayout::Undefined || externalImageCreateInfo != nullptr)
6672     {
6673         setEntireContentDefined();
6674     }
6675 
6676     return angle::Result::Continue;
6677 }
6678 
6679 // static
DeriveCreateInfoPNext(ErrorContext * context,VkImageUsageFlags usage,angle::FormatID actualFormatID,const void * pNext,VkImageFormatListCreateInfoKHR * imageFormatListInfoStorage,std::array<VkFormat,kImageListFormatCount> * imageListFormatsStorage,VkImageCreateFlags * createFlagsOut)6680 const void *ImageHelper::DeriveCreateInfoPNext(
6681     ErrorContext *context,
6682     VkImageUsageFlags usage,
6683     angle::FormatID actualFormatID,
6684     const void *pNext,
6685     VkImageFormatListCreateInfoKHR *imageFormatListInfoStorage,
6686     std::array<VkFormat, kImageListFormatCount> *imageListFormatsStorage,
6687     VkImageCreateFlags *createFlagsOut)
6688 {
6689     // With the introduction of sRGB related GLES extensions any sample/render target could be
6690     // respecified causing it to be interpreted in a different colorspace.  Create the VkImage
6691     // accordingly.
6692     Renderer *renderer                = context->getRenderer();
6693     const angle::Format &actualFormat = angle::Format::Get(actualFormatID);
6694     angle::FormatID additionalFormat =
6695         actualFormat.isSRGB ? ConvertToLinear(actualFormatID) : ConvertToSRGB(actualFormatID);
6696     (*imageListFormatsStorage)[0] = vk::GetVkFormatFromFormatID(renderer, actualFormatID);
6697     (*imageListFormatsStorage)[1] = vk::GetVkFormatFromFormatID(renderer, additionalFormat);
6698 
6699     // Don't add the format list if the storage bit is enabled for the image; framebuffer
6700     // compression is already disabled in that case, and GL allows many formats to alias
6701     // the original format for storage images (more than ANGLE provides in the format list).
6702     if (renderer->getFeatures().supportsImageFormatList.enabled &&
6703         renderer->haveSameFormatFeatureBits(actualFormatID, additionalFormat) &&
6704         (usage & VK_IMAGE_USAGE_STORAGE_BIT) == 0)
6705     {
6706         // Add VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT to VkImage create flag
6707         *createFlagsOut |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
6708 
6709         // There is just 1 additional format we might use to create a VkImageView for this
6710         // VkImage
6711         imageFormatListInfoStorage->sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR;
6712         imageFormatListInfoStorage->pNext = pNext;
6713         imageFormatListInfoStorage->viewFormatCount = kImageListFormatCount;
6714         imageFormatListInfoStorage->pViewFormats    = imageListFormatsStorage->data();
6715 
6716         pNext = imageFormatListInfoStorage;
6717     }
6718 
6719     return pNext;
6720 }
6721 
6722 // static
FormatSupportsUsage(Renderer * renderer,VkFormat format,VkImageType imageType,VkImageTiling tilingMode,VkImageUsageFlags usageFlags,VkImageCreateFlags createFlags,void * formatInfoPNext,void * propertiesPNext,const FormatSupportCheck formatSupportCheck)6723 bool ImageHelper::FormatSupportsUsage(Renderer *renderer,
6724                                       VkFormat format,
6725                                       VkImageType imageType,
6726                                       VkImageTiling tilingMode,
6727                                       VkImageUsageFlags usageFlags,
6728                                       VkImageCreateFlags createFlags,
6729                                       void *formatInfoPNext,
6730                                       void *propertiesPNext,
6731                                       const FormatSupportCheck formatSupportCheck)
6732 {
6733     VkPhysicalDeviceImageFormatInfo2 imageFormatInfo = {};
6734     imageFormatInfo.sType  = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2;
6735     imageFormatInfo.pNext  = formatInfoPNext;
6736     imageFormatInfo.format = format;
6737     imageFormatInfo.type   = imageType;
6738     imageFormatInfo.tiling = tilingMode;
6739     imageFormatInfo.usage  = usageFlags;
6740     imageFormatInfo.flags  = createFlags;
6741 
6742     VkImageFormatProperties2 imageFormatProperties2 = {};
6743     imageFormatProperties2.sType                    = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
6744     imageFormatProperties2.pNext                    = propertiesPNext;
6745 
6746     VkResult result = vkGetPhysicalDeviceImageFormatProperties2(
6747         renderer->getPhysicalDevice(), &imageFormatInfo, &imageFormatProperties2);
6748 
6749     if (formatSupportCheck == FormatSupportCheck::RequireMultisampling)
6750     {
6751         // Some drivers return success but sampleCounts == 1 which means no MSRTT
6752         return result == VK_SUCCESS &&
6753                imageFormatProperties2.imageFormatProperties.sampleCounts > 1;
6754     }
6755     return result == VK_SUCCESS;
6756 }
6757 
setImageFormatsFromActualFormat(VkFormat actualFormat,ImageFormats & imageFormatsOut)6758 void ImageHelper::setImageFormatsFromActualFormat(VkFormat actualFormat,
6759                                                   ImageFormats &imageFormatsOut)
6760 {
6761     imageFormatsOut.push_back(actualFormat);
6762 }
6763 
deriveImageViewFormatFromCreateInfoPNext(VkImageCreateInfo & imageInfo,ImageFormats & formatOut)6764 void ImageHelper::deriveImageViewFormatFromCreateInfoPNext(VkImageCreateInfo &imageInfo,
6765                                                            ImageFormats &formatOut)
6766 {
6767     const VkBaseInStructure *pNextChain =
6768         reinterpret_cast<const VkBaseInStructure *>(imageInfo.pNext);
6769     while (pNextChain != nullptr &&
6770            pNextChain->sType != VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR)
6771     {
6772         pNextChain = pNextChain->pNext;
6773     }
6774 
6775     // Clear formatOut in case it has leftovers from previous VkImage in the case of releaseImage
6776     // followed by initExternal.
6777     std::fill(formatOut.begin(), formatOut.begin() + formatOut.max_size(), VK_FORMAT_UNDEFINED);
6778     if (pNextChain != nullptr)
6779     {
6780         const VkImageFormatListCreateInfoKHR *imageFormatCreateInfo =
6781             reinterpret_cast<const VkImageFormatListCreateInfoKHR *>(pNextChain);
6782 
6783         for (uint32_t i = 0; i < imageFormatCreateInfo->viewFormatCount; i++)
6784         {
6785             formatOut.push_back(*(imageFormatCreateInfo->pViewFormats + i));
6786         }
6787     }
6788     else
6789     {
6790         setImageFormatsFromActualFormat(imageInfo.format, formatOut);
6791     }
6792 }
6793 
deriveExternalImageTiling(const void * createInfoChain)6794 void ImageHelper::deriveExternalImageTiling(const void *createInfoChain)
6795 {
6796     const VkBaseInStructure *chain = reinterpret_cast<const VkBaseInStructure *>(createInfoChain);
6797     while (chain != nullptr)
6798     {
6799         if (chain->sType == VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT ||
6800             chain->sType == VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT)
6801         {
6802             mTilingMode = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
6803             return;
6804         }
6805 
6806         chain = reinterpret_cast<const VkBaseInStructure *>(chain->pNext);
6807     }
6808 }
6809 
releaseImage(Renderer * renderer)6810 void ImageHelper::releaseImage(Renderer *renderer)
6811 {
6812     if (mImage.valid())
6813     {
6814         GarbageObjects garbageObjects;
6815         garbageObjects.reserve(2);
6816         garbageObjects.emplace_back(GarbageObject::Get(&mImage));
6817 
6818         // mDeviceMemory and mVmaAllocation should not be valid at the same time.
6819         ASSERT(!mDeviceMemory.valid() || !mVmaAllocation.valid());
6820         if (mDeviceMemory.valid())
6821         {
6822             renderer->onMemoryDealloc(mMemoryAllocationType, mAllocationSize, mMemoryTypeIndex,
6823                                       mDeviceMemory.getHandle());
6824             garbageObjects.emplace_back(GarbageObject::Get(&mDeviceMemory));
6825         }
6826         if (mVmaAllocation.valid())
6827         {
6828             renderer->onMemoryDealloc(mMemoryAllocationType, mAllocationSize, mMemoryTypeIndex,
6829                                       mVmaAllocation.getHandle());
6830             garbageObjects.emplace_back(GarbageObject::Get(&mVmaAllocation));
6831         }
6832         renderer->collectGarbage(mUse, std::move(garbageObjects));
6833     }
6834     else
6835     {
6836         ASSERT(!mDeviceMemory.valid());
6837         ASSERT(!mVmaAllocation.valid());
6838     }
6839 
6840     mCurrentEvent.release(renderer);
6841     mLastNonShaderReadOnlyEvent.release(renderer);
6842     mViewFormats.clear();
6843     mUse.reset();
6844     mImageSerial          = kInvalidImageSerial;
6845     mMemoryAllocationType = MemoryAllocationType::InvalidEnum;
6846     setEntireContentUndefined();
6847 }
6848 
releaseImageFromShareContexts(Renderer * renderer,ContextVk * contextVk,UniqueSerial imageSiblingSerial)6849 void ImageHelper::releaseImageFromShareContexts(Renderer *renderer,
6850                                                 ContextVk *contextVk,
6851                                                 UniqueSerial imageSiblingSerial)
6852 {
6853     finalizeImageLayoutInShareContexts(renderer, contextVk, imageSiblingSerial);
6854     contextVk->addToPendingImageGarbage(mUse, mAllocationSize);
6855     releaseImage(renderer);
6856 }
6857 
finalizeImageLayoutInShareContexts(Renderer * renderer,ContextVk * contextVk,UniqueSerial imageSiblingSerial)6858 void ImageHelper::finalizeImageLayoutInShareContexts(Renderer *renderer,
6859                                                      ContextVk *contextVk,
6860                                                      UniqueSerial imageSiblingSerial)
6861 {
6862     if (contextVk && mImageSerial.valid())
6863     {
6864         for (auto context : contextVk->getShareGroup()->getContexts())
6865         {
6866             vk::GetImpl(context.second)->finalizeImageLayout(this, imageSiblingSerial);
6867         }
6868     }
6869 }
6870 
releaseStagedUpdates(Renderer * renderer)6871 void ImageHelper::releaseStagedUpdates(Renderer *renderer)
6872 {
6873     ASSERT(validateSubresourceUpdateRefCountsConsistent());
6874 
6875     // Remove updates that never made it to the texture.
6876     for (SubresourceUpdates &levelUpdates : mSubresourceUpdates)
6877     {
6878         while (!levelUpdates.empty())
6879         {
6880             levelUpdates.front().release(renderer);
6881             levelUpdates.pop_front();
6882         }
6883     }
6884 
6885     ASSERT(validateSubresourceUpdateRefCountsConsistent());
6886 
6887     mSubresourceUpdates.clear();
6888     mTotalStagedBufferUpdateSize = 0;
6889     mCurrentSingleClearValue.reset();
6890 }
6891 
resetImageWeakReference()6892 void ImageHelper::resetImageWeakReference()
6893 {
6894     mImage.reset();
6895     mImageSerial        = kInvalidImageSerial;
6896     mRotatedAspectRatio = false;
6897     // Caller must ensure ANI semaphores are properly waited or released.
6898     ASSERT(!mAcquireNextImageSemaphore.valid());
6899 }
6900 
initializeNonZeroMemory(ErrorContext * context,bool hasProtectedContent,VkMemoryPropertyFlags flags,VkDeviceSize size)6901 angle::Result ImageHelper::initializeNonZeroMemory(ErrorContext *context,
6902                                                    bool hasProtectedContent,
6903                                                    VkMemoryPropertyFlags flags,
6904                                                    VkDeviceSize size)
6905 {
6906     // If available, memory mapping should be used.
6907     Renderer *renderer = context->getRenderer();
6908 
6909     if ((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
6910     {
6911         // Wipe memory to an invalid value when the 'allocateNonZeroMemory' feature is enabled. The
6912         // invalid values ensures our testing doesn't assume zero-initialized memory.
6913         constexpr int kNonZeroInitValue = 0x3F;
6914         if (renderer->getFeatures().useVmaForImageSuballocation.enabled)
6915         {
6916             ANGLE_VK_TRY(context,
6917                          renderer->getImageMemorySuballocator().mapMemoryAndInitWithNonZeroValue(
6918                              renderer, &mVmaAllocation, size, kNonZeroInitValue, flags));
6919         }
6920         else
6921         {
6922             ANGLE_TRY(vk::InitMappableDeviceMemory(context, &mDeviceMemory, size, kNonZeroInitValue,
6923                                                    flags));
6924         }
6925 
6926         return angle::Result::Continue;
6927     }
6928 
6929     // If mapping the memory is unavailable, a staging resource is used.
6930     const angle::Format &angleFormat = getActualFormat();
6931     bool isCompressedFormat          = angleFormat.isBlock;
6932 
6933     if (angleFormat.isYUV)
6934     {
6935         // VUID-vkCmdClearColorImage-image-01545
6936         // vkCmdClearColorImage(): format must not be one of the formats requiring sampler YCBCR
6937         // conversion for VK_IMAGE_ASPECT_COLOR_BIT image views
6938         return angle::Result::Continue;
6939     }
6940 
6941     // Since we are going to do a one off out of order submission, there shouldn't any pending
6942     // setEvent.
6943     ASSERT(!mCurrentEvent.valid());
6944 
6945     ScopedPrimaryCommandBuffer scopedCommandBuffer(renderer->getDevice());
6946     auto protectionType = ConvertProtectionBoolToType(hasProtectedContent);
6947     ANGLE_TRY(renderer->getCommandBufferOneOff(context, protectionType, &scopedCommandBuffer));
6948     PrimaryCommandBuffer &commandBuffer = scopedCommandBuffer.get();
6949 
6950     // Queue a DMA copy.
6951     VkSemaphore acquireNextImageSemaphore;
6952     recordBarrierOneOffImpl(renderer, getAspectFlags(), ImageLayout::TransferDst,
6953                             context->getDeviceQueueIndex(), &commandBuffer,
6954                             &acquireNextImageSemaphore);
6955     // SwapChain image should not come here
6956     ASSERT(acquireNextImageSemaphore == VK_NULL_HANDLE);
6957 
6958     StagingBuffer stagingBuffer;
6959 
6960     if (isCompressedFormat)
6961     {
6962         // If format is compressed, set its contents through buffer copies.
6963 
6964         // The staging buffer memory is non-zero-initialized in 'init'.
6965         ANGLE_TRY(stagingBuffer.init(context, size, StagingUsage::Write));
6966 
6967         for (LevelIndex level(0); level < LevelIndex(mLevelCount); ++level)
6968         {
6969             VkBufferImageCopy copyRegion = {};
6970 
6971             gl_vk::GetExtent(getLevelExtents(level), &copyRegion.imageExtent);
6972             copyRegion.imageSubresource.aspectMask = getAspectFlags();
6973             copyRegion.imageSubresource.layerCount = mLayerCount;
6974 
6975             // If image has depth and stencil, copy to each individually per Vulkan spec.
6976             bool hasBothDepthAndStencil = isCombinedDepthStencilFormat();
6977             if (hasBothDepthAndStencil)
6978             {
6979                 copyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
6980             }
6981 
6982             commandBuffer.copyBufferToImage(stagingBuffer.getBuffer().getHandle(), mImage,
6983                                             VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copyRegion);
6984 
6985             if (hasBothDepthAndStencil)
6986             {
6987                 copyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
6988 
6989                 commandBuffer.copyBufferToImage(stagingBuffer.getBuffer().getHandle(), mImage,
6990                                                 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1,
6991                                                 &copyRegion);
6992             }
6993         }
6994     }
6995     else
6996     {
6997         // Otherwise issue clear commands.
6998         VkImageSubresourceRange subresource = {};
6999         subresource.aspectMask              = getAspectFlags();
7000         subresource.baseMipLevel            = 0;
7001         subresource.levelCount              = mLevelCount;
7002         subresource.baseArrayLayer          = 0;
7003         subresource.layerCount              = mLayerCount;
7004 
7005         // Arbitrary value to initialize the memory with.  Note: the given uint value, reinterpreted
7006         // as float is about 0.7.
7007         constexpr uint32_t kInitValue   = 0x3F345678;
7008         constexpr float kInitValueFloat = 0.12345f;
7009 
7010         if ((subresource.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != 0)
7011         {
7012             VkClearColorValue clearValue;
7013             clearValue.uint32[0] = kInitValue;
7014             clearValue.uint32[1] = kInitValue;
7015             clearValue.uint32[2] = kInitValue;
7016             clearValue.uint32[3] = kInitValue;
7017 
7018             commandBuffer.clearColorImage(mImage, getCurrentLayout(), clearValue, 1, &subresource);
7019         }
7020         else
7021         {
7022             VkClearDepthStencilValue clearValue;
7023             clearValue.depth   = kInitValueFloat;
7024             clearValue.stencil = kInitValue;
7025 
7026             commandBuffer.clearDepthStencilImage(mImage, getCurrentLayout(), clearValue, 1,
7027                                                  &subresource);
7028         }
7029     }
7030 
7031     ANGLE_VK_TRY(context, commandBuffer.end());
7032 
7033     QueueSerial queueSerial;
7034     ANGLE_TRY(renderer->queueSubmitOneOff(context, std::move(scopedCommandBuffer), protectionType,
7035                                           egl::ContextPriority::Medium, VK_NULL_HANDLE, 0,
7036                                           &queueSerial));
7037 
7038     if (isCompressedFormat)
7039     {
7040         stagingBuffer.collectGarbage(renderer, queueSerial);
7041     }
7042     setQueueSerial(queueSerial);
7043     ASSERT(!mIsForeignImage);
7044 
7045     return angle::Result::Continue;
7046 }
7047 
initMemory(ErrorContext * context,const MemoryProperties & memoryProperties,VkMemoryPropertyFlags flags,VkMemoryPropertyFlags excludedFlags,const VkMemoryRequirements * memoryRequirements,const bool allocateDedicatedMemory,MemoryAllocationType allocationType,VkMemoryPropertyFlags * flagsOut,VkDeviceSize * sizeOut)7048 VkResult ImageHelper::initMemory(ErrorContext *context,
7049                                  const MemoryProperties &memoryProperties,
7050                                  VkMemoryPropertyFlags flags,
7051                                  VkMemoryPropertyFlags excludedFlags,
7052                                  const VkMemoryRequirements *memoryRequirements,
7053                                  const bool allocateDedicatedMemory,
7054                                  MemoryAllocationType allocationType,
7055                                  VkMemoryPropertyFlags *flagsOut,
7056                                  VkDeviceSize *sizeOut)
7057 {
7058     mMemoryAllocationType = allocationType;
7059 
7060     // To allocate memory here, if possible, we use the image memory suballocator which uses VMA.
7061     ASSERT(excludedFlags < VK_MEMORY_PROPERTY_FLAG_BITS_MAX_ENUM);
7062     Renderer *renderer = context->getRenderer();
7063     if (renderer->getFeatures().useVmaForImageSuballocation.enabled)
7064     {
7065         // While it may be preferable to allocate the image on the device, it should also be
7066         // possible to allocate on other memory types if the device is out of memory.
7067         VkMemoryPropertyFlags requiredFlags  = flags & (~excludedFlags);
7068         VkMemoryPropertyFlags preferredFlags = flags;
7069         VK_RESULT_TRY(renderer->getImageMemorySuballocator().allocateAndBindMemory(
7070             context, &mImage, &mVkImageCreateInfo, requiredFlags, preferredFlags,
7071             memoryRequirements, allocateDedicatedMemory, mMemoryAllocationType, &mVmaAllocation,
7072             flagsOut, &mMemoryTypeIndex, &mAllocationSize));
7073     }
7074     else
7075     {
7076         VK_RESULT_TRY(AllocateImageMemory(context, mMemoryAllocationType, flags, flagsOut, nullptr,
7077                                           &mImage, &mMemoryTypeIndex, &mDeviceMemory,
7078                                           &mAllocationSize));
7079     }
7080 
7081     mCurrentDeviceQueueIndex = context->getDeviceQueueIndex();
7082     mIsReleasedToExternal    = false;
7083     mIsForeignImage          = false;
7084     *sizeOut                 = mAllocationSize;
7085 
7086     return VK_SUCCESS;
7087 }
7088 
initMemoryAndNonZeroFillIfNeeded(ErrorContext * context,bool hasProtectedContent,const MemoryProperties & memoryProperties,VkMemoryPropertyFlags flags,MemoryAllocationType allocationType)7089 angle::Result ImageHelper::initMemoryAndNonZeroFillIfNeeded(
7090     ErrorContext *context,
7091     bool hasProtectedContent,
7092     const MemoryProperties &memoryProperties,
7093     VkMemoryPropertyFlags flags,
7094     MemoryAllocationType allocationType)
7095 {
7096     Renderer *renderer = context->getRenderer();
7097     VkMemoryPropertyFlags outputFlags;
7098     VkDeviceSize outputSize;
7099 
7100     if (hasProtectedContent)
7101     {
7102         flags |= VK_MEMORY_PROPERTY_PROTECTED_BIT;
7103     }
7104 
7105     // Get memory requirements for the allocation.
7106     VkMemoryRequirements memoryRequirements;
7107     mImage.getMemoryRequirements(renderer->getDevice(), &memoryRequirements);
7108     bool allocateDedicatedMemory =
7109         renderer->getImageMemorySuballocator().needsDedicatedMemory(memoryRequirements.size);
7110 
7111     ANGLE_VK_TRY(context,
7112                  initMemory(context, memoryProperties, flags, 0, &memoryRequirements,
7113                             allocateDedicatedMemory, allocationType, &outputFlags, &outputSize));
7114 
7115     // Memory can only be non-zero initialized if the TRANSFER_DST usage is set.  This is normally
7116     // the case, but not with |initImplicitMultisampledRenderToTexture| which creates a
7117     // lazy-allocated transient image.
7118     if (renderer->getFeatures().allocateNonZeroMemory.enabled &&
7119         (mUsage & VK_IMAGE_USAGE_TRANSFER_DST_BIT) != 0)
7120     {
7121         ANGLE_TRY(initializeNonZeroMemory(context, hasProtectedContent, outputFlags, outputSize));
7122     }
7123     return angle::Result::Continue;
7124 }
7125 
initExternalMemory(ErrorContext * context,const MemoryProperties & memoryProperties,const VkMemoryRequirements & memoryRequirements,uint32_t extraAllocationInfoCount,const void ** extraAllocationInfo,DeviceQueueIndex currentDeviceQueueIndex,VkMemoryPropertyFlags flags)7126 angle::Result ImageHelper::initExternalMemory(ErrorContext *context,
7127                                               const MemoryProperties &memoryProperties,
7128                                               const VkMemoryRequirements &memoryRequirements,
7129                                               uint32_t extraAllocationInfoCount,
7130                                               const void **extraAllocationInfo,
7131                                               DeviceQueueIndex currentDeviceQueueIndex,
7132                                               VkMemoryPropertyFlags flags)
7133 {
7134     // Vulkan allows up to 4 memory planes.
7135     constexpr size_t kMaxMemoryPlanes                                     = 4;
7136     constexpr VkImageAspectFlagBits kMemoryPlaneAspects[kMaxMemoryPlanes] = {
7137         VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT,
7138         VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT,
7139         VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT,
7140         VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT,
7141     };
7142     ASSERT(extraAllocationInfoCount <= kMaxMemoryPlanes);
7143 
7144     VkBindImagePlaneMemoryInfoKHR bindImagePlaneMemoryInfo = {};
7145     bindImagePlaneMemoryInfo.sType = VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO;
7146 
7147     const VkBindImagePlaneMemoryInfoKHR *bindImagePlaneMemoryInfoPtr =
7148         extraAllocationInfoCount == 1 ? nullptr : &bindImagePlaneMemoryInfo;
7149 
7150     mAllocationSize       = memoryRequirements.size;
7151     mMemoryAllocationType = MemoryAllocationType::ImageExternal;
7152 
7153     for (uint32_t memoryPlane = 0; memoryPlane < extraAllocationInfoCount; ++memoryPlane)
7154     {
7155         bindImagePlaneMemoryInfo.planeAspect = kMemoryPlaneAspects[memoryPlane];
7156 
7157         ANGLE_VK_TRY(context, AllocateImageMemoryWithRequirements(
7158                                   context, mMemoryAllocationType, flags, memoryRequirements,
7159                                   extraAllocationInfo[memoryPlane], bindImagePlaneMemoryInfoPtr,
7160                                   &mImage, &mMemoryTypeIndex, &mDeviceMemory));
7161     }
7162     mCurrentDeviceQueueIndex = currentDeviceQueueIndex;
7163     mIsReleasedToExternal    = false;
7164     mIsForeignImage          = currentDeviceQueueIndex == kForeignDeviceQueueIndex;
7165 
7166     return angle::Result::Continue;
7167 }
7168 
initLayerImageView(ErrorContext * context,gl::TextureType textureType,VkImageAspectFlags aspectMask,const gl::SwizzleState & swizzleMap,ImageView * imageViewOut,LevelIndex baseMipLevelVk,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount) const7169 angle::Result ImageHelper::initLayerImageView(ErrorContext *context,
7170                                               gl::TextureType textureType,
7171                                               VkImageAspectFlags aspectMask,
7172                                               const gl::SwizzleState &swizzleMap,
7173                                               ImageView *imageViewOut,
7174                                               LevelIndex baseMipLevelVk,
7175                                               uint32_t levelCount,
7176                                               uint32_t baseArrayLayer,
7177                                               uint32_t layerCount) const
7178 {
7179     return initLayerImageViewImpl(context, textureType, aspectMask, swizzleMap, imageViewOut,
7180                                   baseMipLevelVk, levelCount, baseArrayLayer, layerCount,
7181                                   GetVkFormatFromFormatID(context->getRenderer(), mActualFormatID),
7182                                   kDefaultImageViewUsageFlags, gl::YuvSamplingMode::Default);
7183 }
7184 
initLayerImageViewWithUsage(ErrorContext * 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) const7185 angle::Result ImageHelper::initLayerImageViewWithUsage(ErrorContext *context,
7186                                                        gl::TextureType textureType,
7187                                                        VkImageAspectFlags aspectMask,
7188                                                        const gl::SwizzleState &swizzleMap,
7189                                                        ImageView *imageViewOut,
7190                                                        LevelIndex baseMipLevelVk,
7191                                                        uint32_t levelCount,
7192                                                        uint32_t baseArrayLayer,
7193                                                        uint32_t layerCount,
7194                                                        VkImageUsageFlags imageUsageFlags) const
7195 {
7196     return initLayerImageViewImpl(context, textureType, aspectMask, swizzleMap, imageViewOut,
7197                                   baseMipLevelVk, levelCount, baseArrayLayer, layerCount,
7198                                   GetVkFormatFromFormatID(context->getRenderer(), mActualFormatID),
7199                                   imageUsageFlags, gl::YuvSamplingMode::Default);
7200 }
7201 
initLayerImageViewWithYuvModeOverride(ErrorContext * 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) const7202 angle::Result ImageHelper::initLayerImageViewWithYuvModeOverride(
7203     ErrorContext *context,
7204     gl::TextureType textureType,
7205     VkImageAspectFlags aspectMask,
7206     const gl::SwizzleState &swizzleMap,
7207     ImageView *imageViewOut,
7208     LevelIndex baseMipLevelVk,
7209     uint32_t levelCount,
7210     uint32_t baseArrayLayer,
7211     uint32_t layerCount,
7212     gl::YuvSamplingMode yuvSamplingMode,
7213     VkImageUsageFlags imageUsageFlags) const
7214 {
7215     return initLayerImageViewImpl(context, textureType, aspectMask, swizzleMap, imageViewOut,
7216                                   baseMipLevelVk, levelCount, baseArrayLayer, layerCount,
7217                                   GetVkFormatFromFormatID(context->getRenderer(), mActualFormatID),
7218                                   imageUsageFlags, yuvSamplingMode);
7219 }
7220 
initLayerImageViewImpl(ErrorContext * 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) const7221 angle::Result ImageHelper::initLayerImageViewImpl(ErrorContext *context,
7222                                                   gl::TextureType textureType,
7223                                                   VkImageAspectFlags aspectMask,
7224                                                   const gl::SwizzleState &swizzleMap,
7225                                                   ImageView *imageViewOut,
7226                                                   LevelIndex baseMipLevelVk,
7227                                                   uint32_t levelCount,
7228                                                   uint32_t baseArrayLayer,
7229                                                   uint32_t layerCount,
7230                                                   VkFormat imageFormat,
7231                                                   VkImageUsageFlags usageFlags,
7232                                                   gl::YuvSamplingMode yuvSamplingMode) const
7233 {
7234     VkImageViewCreateInfo viewInfo = {};
7235     viewInfo.sType                 = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
7236     viewInfo.flags                 = 0;
7237     viewInfo.image                 = mImage.getHandle();
7238     viewInfo.viewType              = gl_vk::GetImageViewType(textureType);
7239     viewInfo.format                = imageFormat;
7240 
7241     if (swizzleMap.swizzleRequired() && !mYcbcrConversionDesc.valid())
7242     {
7243         viewInfo.components.r = gl_vk::GetSwizzle(swizzleMap.swizzleRed);
7244         viewInfo.components.g = gl_vk::GetSwizzle(swizzleMap.swizzleGreen);
7245         viewInfo.components.b = gl_vk::GetSwizzle(swizzleMap.swizzleBlue);
7246         viewInfo.components.a = gl_vk::GetSwizzle(swizzleMap.swizzleAlpha);
7247     }
7248     else
7249     {
7250         viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
7251         viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
7252         viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
7253         viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
7254     }
7255     viewInfo.subresourceRange.aspectMask     = aspectMask;
7256     viewInfo.subresourceRange.baseMipLevel   = baseMipLevelVk.get();
7257     viewInfo.subresourceRange.levelCount     = levelCount;
7258     viewInfo.subresourceRange.baseArrayLayer = baseArrayLayer;
7259     viewInfo.subresourceRange.layerCount     = layerCount;
7260 
7261     VkImageViewUsageCreateInfo imageViewUsageCreateInfo = {};
7262     if (usageFlags)
7263     {
7264         imageViewUsageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO;
7265         imageViewUsageCreateInfo.usage = usageFlags;
7266 
7267         viewInfo.pNext = &imageViewUsageCreateInfo;
7268     }
7269 
7270     VkSamplerYcbcrConversionInfo yuvConversionInfo = {};
7271 
7272     auto conversionDesc =
7273         yuvSamplingMode == gl::YuvSamplingMode::Y2Y ? getY2YConversionDesc() : mYcbcrConversionDesc;
7274 
7275     if (conversionDesc.valid())
7276     {
7277         ASSERT((context->getFeatures().supportsYUVSamplerConversion.enabled));
7278         yuvConversionInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO;
7279         yuvConversionInfo.pNext = nullptr;
7280         ANGLE_TRY(context->getRenderer()->getYuvConversionCache().getSamplerYcbcrConversion(
7281             context, conversionDesc, &yuvConversionInfo.conversion));
7282         AddToPNextChain(&viewInfo, &yuvConversionInfo);
7283 
7284         // VUID-VkImageViewCreateInfo-image-02399
7285         // If image has an external format, format must be VK_FORMAT_UNDEFINED
7286         if (conversionDesc.getExternalFormat() != 0)
7287         {
7288             viewInfo.format = VK_FORMAT_UNDEFINED;
7289         }
7290     }
7291     ANGLE_VK_TRY(context, imageViewOut->init(context->getDevice(), viewInfo));
7292     return angle::Result::Continue;
7293 }
7294 
initReinterpretedLayerImageView(ErrorContext * 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) const7295 angle::Result ImageHelper::initReinterpretedLayerImageView(ErrorContext *context,
7296                                                            gl::TextureType textureType,
7297                                                            VkImageAspectFlags aspectMask,
7298                                                            const gl::SwizzleState &swizzleMap,
7299                                                            ImageView *imageViewOut,
7300                                                            LevelIndex baseMipLevelVk,
7301                                                            uint32_t levelCount,
7302                                                            uint32_t baseArrayLayer,
7303                                                            uint32_t layerCount,
7304                                                            VkImageUsageFlags imageUsageFlags,
7305                                                            angle::FormatID imageViewFormat) const
7306 {
7307     VkImageUsageFlags usageFlags =
7308         imageUsageFlags & GetMaximalImageUsageFlags(context->getRenderer(), imageViewFormat);
7309 
7310     return initLayerImageViewImpl(
7311         context, textureType, aspectMask, swizzleMap, imageViewOut, baseMipLevelVk, levelCount,
7312         baseArrayLayer, layerCount,
7313         vk::GetVkFormatFromFormatID(context->getRenderer(), imageViewFormat), usageFlags,
7314         gl::YuvSamplingMode::Default);
7315 }
7316 
destroy(Renderer * renderer)7317 void ImageHelper::destroy(Renderer *renderer)
7318 {
7319     VkDevice device = renderer->getDevice();
7320 
7321     // mDeviceMemory and mVmaAllocation should not be valid at the same time.
7322     ASSERT(!mDeviceMemory.valid() || !mVmaAllocation.valid());
7323     if (mDeviceMemory.valid())
7324     {
7325         renderer->onMemoryDealloc(mMemoryAllocationType, mAllocationSize, mMemoryTypeIndex,
7326                                   mDeviceMemory.getHandle());
7327     }
7328     if (mVmaAllocation.valid())
7329     {
7330         renderer->onMemoryDealloc(mMemoryAllocationType, mAllocationSize, mMemoryTypeIndex,
7331                                   mVmaAllocation.getHandle());
7332     }
7333 
7334     mCurrentEvent.release(renderer);
7335     mLastNonShaderReadOnlyEvent.release(renderer);
7336     mImage.destroy(device);
7337     mDeviceMemory.destroy(device);
7338     mVmaAllocation.destroy(renderer->getAllocator());
7339     mCurrentLayout        = ImageLayout::Undefined;
7340     mImageType            = VK_IMAGE_TYPE_2D;
7341     mLayerCount           = 0;
7342     mLevelCount           = 0;
7343     mMemoryAllocationType = MemoryAllocationType::InvalidEnum;
7344 
7345     setEntireContentUndefined();
7346 }
7347 
init2DWeakReference(ErrorContext * context,VkImage handle,const gl::Extents & glExtents,bool rotatedAspectRatio,angle::FormatID intendedFormatID,angle::FormatID actualFormatID,VkImageCreateFlags createFlags,VkImageUsageFlags usage,GLint samples,bool isRobustResourceInitEnabled)7348 void ImageHelper::init2DWeakReference(ErrorContext *context,
7349                                       VkImage handle,
7350                                       const gl::Extents &glExtents,
7351                                       bool rotatedAspectRatio,
7352                                       angle::FormatID intendedFormatID,
7353                                       angle::FormatID actualFormatID,
7354                                       VkImageCreateFlags createFlags,
7355                                       VkImageUsageFlags usage,
7356                                       GLint samples,
7357                                       bool isRobustResourceInitEnabled)
7358 {
7359     ASSERT(!valid());
7360     ASSERT(!IsAnySubresourceContentDefined(mContentDefined));
7361     ASSERT(!IsAnySubresourceContentDefined(mStencilContentDefined));
7362     vk::Renderer *renderer = context->getRenderer();
7363 
7364     gl_vk::GetExtent(glExtents, &mExtents);
7365     mRotatedAspectRatio      = rotatedAspectRatio;
7366     mIntendedFormatID        = intendedFormatID;
7367     mActualFormatID          = actualFormatID;
7368     mCreateFlags             = createFlags;
7369     mUsage                   = usage;
7370     mSamples                 = std::max(samples, 1);
7371     mImageSerial             = renderer->getResourceSerialFactory().generateImageSerial();
7372     mCurrentDeviceQueueIndex = context->getDeviceQueueIndex();
7373     mIsReleasedToExternal    = false;
7374     mIsForeignImage          = false;
7375     mCurrentLayout           = ImageLayout::Undefined;
7376     mLayerCount              = 1;
7377     mLevelCount              = 1;
7378 
7379     // The view formats and usage flags are used for imageless framebuffers. Here, the former is set
7380     // similar to deriveImageViewFormatFromCreateInfoPNext() when there is no pNext from a
7381     // VkImageCreateInfo object.
7382     setImageFormatsFromActualFormat(GetVkFormatFromFormatID(renderer, actualFormatID),
7383                                     mViewFormats);
7384 
7385     mImage.setHandle(handle);
7386 
7387     stageClearIfEmulatedFormat(isRobustResourceInitEnabled, false);
7388 }
7389 
init2DStaging(ErrorContext * context,bool hasProtectedContent,const MemoryProperties & memoryProperties,const gl::Extents & glExtents,angle::FormatID intendedFormatID,angle::FormatID actualFormatID,VkImageUsageFlags usage,uint32_t layerCount)7390 angle::Result ImageHelper::init2DStaging(ErrorContext *context,
7391                                          bool hasProtectedContent,
7392                                          const MemoryProperties &memoryProperties,
7393                                          const gl::Extents &glExtents,
7394                                          angle::FormatID intendedFormatID,
7395                                          angle::FormatID actualFormatID,
7396                                          VkImageUsageFlags usage,
7397                                          uint32_t layerCount)
7398 {
7399     gl_vk::GetExtent(glExtents, &mExtents);
7400 
7401     return initStaging(context, hasProtectedContent, memoryProperties, VK_IMAGE_TYPE_2D, mExtents,
7402                        intendedFormatID, actualFormatID, 1, usage, 1, layerCount);
7403 }
7404 
initStaging(ErrorContext * 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)7405 angle::Result ImageHelper::initStaging(ErrorContext *context,
7406                                        bool hasProtectedContent,
7407                                        const MemoryProperties &memoryProperties,
7408                                        VkImageType imageType,
7409                                        const VkExtent3D &extents,
7410                                        angle::FormatID intendedFormatID,
7411                                        angle::FormatID actualFormatID,
7412                                        GLint samples,
7413                                        VkImageUsageFlags usage,
7414                                        uint32_t mipLevels,
7415                                        uint32_t layerCount)
7416 {
7417     ASSERT(!valid());
7418     ASSERT(!IsAnySubresourceContentDefined(mContentDefined));
7419     ASSERT(!IsAnySubresourceContentDefined(mStencilContentDefined));
7420     vk::Renderer *renderer = context->getRenderer();
7421 
7422     mImageType          = imageType;
7423     mExtents            = extents;
7424     mRotatedAspectRatio = false;
7425     mIntendedFormatID   = intendedFormatID;
7426     mActualFormatID     = actualFormatID;
7427     mSamples            = std::max(samples, 1);
7428     mImageSerial        = renderer->getResourceSerialFactory().generateImageSerial();
7429     mLayerCount         = layerCount;
7430     mLevelCount         = mipLevels;
7431     mUsage              = usage;
7432 
7433     // Validate that mLayerCount is compatible with the image type
7434     ASSERT(imageType != VK_IMAGE_TYPE_3D || mLayerCount == 1);
7435     ASSERT(imageType != VK_IMAGE_TYPE_2D || mExtents.depth == 1);
7436 
7437     mCurrentLayout = ImageLayout::Undefined;
7438 
7439     VkImageCreateInfo imageInfo = {};
7440     imageInfo.sType             = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
7441     imageInfo.flags             = hasProtectedContent ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
7442     imageInfo.imageType         = mImageType;
7443     imageInfo.format            = GetVkFormatFromFormatID(renderer, actualFormatID);
7444     imageInfo.extent            = mExtents;
7445     imageInfo.mipLevels         = mLevelCount;
7446     imageInfo.arrayLayers       = mLayerCount;
7447     imageInfo.samples =
7448         gl_vk::GetSamples(mSamples, context->getFeatures().limitSampleCountTo2.enabled);
7449     imageInfo.tiling                = VK_IMAGE_TILING_OPTIMAL;
7450     imageInfo.usage                 = usage;
7451     imageInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
7452     imageInfo.queueFamilyIndexCount = 0;
7453     imageInfo.pQueueFamilyIndices   = nullptr;
7454     imageInfo.initialLayout         = getCurrentLayout();
7455 
7456     ANGLE_VK_TRY(context, mImage.init(context->getDevice(), imageInfo));
7457 
7458     mVkImageCreateInfo               = imageInfo;
7459     mVkImageCreateInfo.pNext         = nullptr;
7460     mVkImageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
7461 
7462     // Allocate and bind device-local memory.
7463     VkMemoryPropertyFlags memoryPropertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
7464     if (hasProtectedContent)
7465     {
7466         memoryPropertyFlags |= VK_MEMORY_PROPERTY_PROTECTED_BIT;
7467     }
7468 
7469     ANGLE_TRY(initMemoryAndNonZeroFillIfNeeded(context, hasProtectedContent, memoryProperties,
7470                                                memoryPropertyFlags,
7471                                                vk::MemoryAllocationType::StagingImage));
7472     return angle::Result::Continue;
7473 }
7474 
initImplicitMultisampledRenderToTexture(ErrorContext * context,bool hasProtectedContent,const MemoryProperties & memoryProperties,gl::TextureType textureType,GLint samples,const ImageHelper & resolveImage,const VkExtent3D & multisampleImageExtents,bool isRobustResourceInitEnabled)7475 angle::Result ImageHelper::initImplicitMultisampledRenderToTexture(
7476     ErrorContext *context,
7477     bool hasProtectedContent,
7478     const MemoryProperties &memoryProperties,
7479     gl::TextureType textureType,
7480     GLint samples,
7481     const ImageHelper &resolveImage,
7482     const VkExtent3D &multisampleImageExtents,
7483     bool isRobustResourceInitEnabled)
7484 {
7485     ASSERT(!valid());
7486     ASSERT(samples > 1);
7487     ASSERT(!IsAnySubresourceContentDefined(mContentDefined));
7488     ASSERT(!IsAnySubresourceContentDefined(mStencilContentDefined));
7489 
7490     // The image is used as either color or depth/stencil attachment.  Additionally, its memory is
7491     // lazily allocated as the contents are discarded at the end of the renderpass and with tiling
7492     // GPUs no actual backing memory is required.
7493     //
7494     // Note that the Vulkan image is created with or without VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT
7495     // based on whether the memory that will be used to create the image would have
7496     // VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT.  TRANSIENT is provided if there is any memory that
7497     // supports LAZILY_ALLOCATED.  However, based on actual image requirements, such a memory may
7498     // not be suitable for the image.  We don't support such a case, which will result in the
7499     // |initMemory| call below failing.
7500     const bool hasLazilyAllocatedMemory = memoryProperties.hasLazilyAllocatedMemory();
7501 
7502     const VkImageUsageFlags kLazyFlags =
7503         hasLazilyAllocatedMemory ? VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT : 0;
7504     constexpr VkImageUsageFlags kColorFlags =
7505         VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
7506 
7507     // Request input attachment flag iff supportsShaderFramebufferFetchDepthStencil is enabled.
7508     const VkImageUsageFlags depthStencilFlags =
7509         VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
7510         ((context->getFeatures().supportsShaderFramebufferFetchDepthStencil.enabled)
7511              ? VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT
7512              : 0);
7513 
7514     const VkImageUsageFlags kMultisampledUsageFlags =
7515         kLazyFlags |
7516         (resolveImage.getAspectFlags() == VK_IMAGE_ASPECT_COLOR_BIT ? kColorFlags
7517                                                                     : depthStencilFlags);
7518     const VkImageCreateFlags kMultisampledCreateFlags =
7519         hasProtectedContent ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
7520 
7521     // Multisampled images have only 1 level
7522     constexpr uint32_t kLevelCount = 1;
7523 
7524     ANGLE_TRY(initExternal(context, textureType, multisampleImageExtents,
7525                            resolveImage.getIntendedFormatID(), resolveImage.getActualFormatID(),
7526                            samples, kMultisampledUsageFlags, kMultisampledCreateFlags,
7527                            ImageLayout::Undefined, nullptr, resolveImage.getFirstAllocatedLevel(),
7528                            kLevelCount, resolveImage.getLayerCount(), isRobustResourceInitEnabled,
7529                            hasProtectedContent, YcbcrConversionDesc{}, nullptr));
7530 
7531     // Remove the emulated format clear from the multisampled image if any.  There is one already
7532     // staged on the resolve image if needed.
7533     removeStagedUpdates(context, getFirstAllocatedLevel(), getLastAllocatedLevel());
7534 
7535     const VkMemoryPropertyFlags kMultisampledMemoryFlags =
7536         VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
7537         (hasLazilyAllocatedMemory ? VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT : 0) |
7538         (hasProtectedContent ? VK_MEMORY_PROPERTY_PROTECTED_BIT : 0);
7539 
7540     // If this ever fails, it can be retried without the LAZILY_ALLOCATED flag (which will probably
7541     // still fail), but ideally that means GL_EXT_multisampled_render_to_texture should not be
7542     // advertised on this platform in the first place.
7543     ANGLE_TRY(initMemoryAndNonZeroFillIfNeeded(
7544         context, hasProtectedContent, memoryProperties, kMultisampledMemoryFlags,
7545         vk::MemoryAllocationType::ImplicitMultisampledRenderToTextureImage));
7546     return angle::Result::Continue;
7547 }
7548 
getAspectFlags() const7549 VkImageAspectFlags ImageHelper::getAspectFlags() const
7550 {
7551     return GetFormatAspectFlags(angle::Format::Get(mActualFormatID));
7552 }
7553 
isCombinedDepthStencilFormat() const7554 bool ImageHelper::isCombinedDepthStencilFormat() const
7555 {
7556     return (getAspectFlags() & kDepthStencilAspects) == kDepthStencilAspects;
7557 }
7558 
setCurrentImageLayout(Renderer * renderer,ImageLayout newLayout)7559 void ImageHelper::setCurrentImageLayout(Renderer *renderer, ImageLayout newLayout)
7560 {
7561     // Once you transition to ImageLayout::SharedPresent, you never transition out of it.
7562     if (mCurrentLayout == ImageLayout::SharedPresent)
7563     {
7564         return;
7565     }
7566 
7567     const ImageMemoryBarrierData &transitionFrom =
7568         renderer->getImageMemoryBarrierData(mCurrentLayout);
7569     const ImageMemoryBarrierData &transitionTo = renderer->getImageMemoryBarrierData(newLayout);
7570     mLastNonShaderReadOnlyLayout =
7571         !IsShaderReadOnlyLayout(transitionFrom) ? mCurrentLayout : mLastNonShaderReadOnlyLayout;
7572     // Force the use of BarrierType::Pipeline in the next barrierImpl call
7573     mLastNonShaderReadOnlyEvent.release(renderer);
7574     mCurrentShaderReadStageMask =
7575         IsShaderReadOnlyLayout(transitionTo) ? transitionTo.dstStageMask : 0;
7576     mCurrentLayout = newLayout;
7577 }
7578 
getCurrentLayout() const7579 VkImageLayout ImageHelper::getCurrentLayout() const
7580 {
7581     return ConvertImageLayoutToVkImageLayout(mCurrentLayout);
7582 }
7583 
getLevelExtents(LevelIndex levelVk) const7584 gl::Extents ImageHelper::getLevelExtents(LevelIndex levelVk) const
7585 {
7586     // Level 0 should be the size of the extents, after that every time you increase a level
7587     // you shrink the extents by half.
7588     uint32_t width  = std::max(mExtents.width >> levelVk.get(), 1u);
7589     uint32_t height = std::max(mExtents.height >> levelVk.get(), 1u);
7590     uint32_t depth  = std::max(mExtents.depth >> levelVk.get(), 1u);
7591 
7592     return gl::Extents(width, height, depth);
7593 }
7594 
getLevelExtents2D(LevelIndex levelVk) const7595 gl::Extents ImageHelper::getLevelExtents2D(LevelIndex levelVk) const
7596 {
7597     gl::Extents extents = getLevelExtents(levelVk);
7598     extents.depth       = 1;
7599     return extents;
7600 }
7601 
getRotatedExtents() const7602 const VkExtent3D ImageHelper::getRotatedExtents() const
7603 {
7604     VkExtent3D extents = mExtents;
7605     if (mRotatedAspectRatio)
7606     {
7607         std::swap(extents.width, extents.height);
7608     }
7609     return extents;
7610 }
7611 
getRotatedLevelExtents2D(LevelIndex levelVk) const7612 gl::Extents ImageHelper::getRotatedLevelExtents2D(LevelIndex levelVk) const
7613 {
7614     gl::Extents extents = getLevelExtents2D(levelVk);
7615     if (mRotatedAspectRatio)
7616     {
7617         std::swap(extents.width, extents.height);
7618     }
7619     return extents;
7620 }
7621 
isDepthOrStencil() const7622 bool ImageHelper::isDepthOrStencil() const
7623 {
7624     return getActualFormat().hasDepthOrStencilBits();
7625 }
7626 
setRenderPassUsageFlag(RenderPassUsage flag)7627 void ImageHelper::setRenderPassUsageFlag(RenderPassUsage flag)
7628 {
7629     mRenderPassUsageFlags.set(flag);
7630 }
7631 
clearRenderPassUsageFlag(RenderPassUsage flag)7632 void ImageHelper::clearRenderPassUsageFlag(RenderPassUsage flag)
7633 {
7634     mRenderPassUsageFlags.reset(flag);
7635 }
7636 
resetRenderPassUsageFlags()7637 void ImageHelper::resetRenderPassUsageFlags()
7638 {
7639     mRenderPassUsageFlags.reset();
7640 }
7641 
hasRenderPassUsageFlag(RenderPassUsage flag) const7642 bool ImageHelper::hasRenderPassUsageFlag(RenderPassUsage flag) const
7643 {
7644     return mRenderPassUsageFlags.test(flag);
7645 }
7646 
hasAnyRenderPassUsageFlags() const7647 bool ImageHelper::hasAnyRenderPassUsageFlags() const
7648 {
7649     return mRenderPassUsageFlags.any();
7650 }
7651 
usedByCurrentRenderPassAsAttachmentAndSampler(RenderPassUsage textureSamplerUsage) const7652 bool ImageHelper::usedByCurrentRenderPassAsAttachmentAndSampler(
7653     RenderPassUsage textureSamplerUsage) const
7654 {
7655     return mRenderPassUsageFlags[RenderPassUsage::RenderTargetAttachment] &&
7656            mRenderPassUsageFlags[textureSamplerUsage];
7657 }
7658 
isReadBarrierNecessary(Renderer * renderer,ImageLayout newLayout) const7659 bool ImageHelper::isReadBarrierNecessary(Renderer *renderer, ImageLayout newLayout) const
7660 {
7661     // If transitioning to a different layout, we need always need a barrier.
7662     if (mCurrentLayout != newLayout)
7663     {
7664         return true;
7665     }
7666 
7667     // RAR (read-after-read) is not a hazard and doesn't require a barrier.
7668     //
7669     // RAW (read-after-write) hazards always require a memory barrier.  This can only happen if the
7670     // layout (same as new layout) is writable which in turn is only possible if the image is
7671     // simultaneously bound for shader write (i.e. the layout is GENERAL or SHARED_PRESENT).
7672     const ImageMemoryBarrierData &layoutData = renderer->getImageMemoryBarrierData(mCurrentLayout);
7673     return HasResourceWriteAccess(layoutData.type);
7674 }
7675 
isReadSubresourceBarrierNecessary(ImageLayout newLayout,gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount) const7676 bool ImageHelper::isReadSubresourceBarrierNecessary(ImageLayout newLayout,
7677                                                     gl::LevelIndex levelStart,
7678                                                     uint32_t levelCount,
7679                                                     uint32_t layerStart,
7680                                                     uint32_t layerCount) const
7681 {
7682     // In case an image has both read and write permissions, the written subresources since the last
7683     // barrier should be checked to avoid RAW and WAR hazards. However, if a layout change is
7684     // necessary regardless, there is no need to check the written subresources.
7685     if (mCurrentLayout != newLayout)
7686     {
7687         return true;
7688     }
7689 
7690     ImageLayerWriteMask layerMask = GetImageLayerWriteMask(layerStart, layerCount);
7691     for (uint32_t levelOffset = 0; levelOffset < levelCount; levelOffset++)
7692     {
7693         uint32_t level = levelStart.get() + levelOffset;
7694         if (areLevelSubresourcesWrittenWithinMaskRange(level, layerMask))
7695         {
7696             return true;
7697         }
7698     }
7699 
7700     return false;
7701 }
7702 
isWriteBarrierNecessary(ImageLayout newLayout,gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount) const7703 bool ImageHelper::isWriteBarrierNecessary(ImageLayout newLayout,
7704                                           gl::LevelIndex levelStart,
7705                                           uint32_t levelCount,
7706                                           uint32_t layerStart,
7707                                           uint32_t layerCount) const
7708 {
7709     // If transitioning to a different layout, we need always need a barrier.
7710     if (mCurrentLayout != newLayout)
7711     {
7712         return true;
7713     }
7714 
7715     if (layerCount >= kMaxParallelLayerWrites)
7716     {
7717         return true;
7718     }
7719 
7720     // If we are writing to the same parts of the image (level/layer), we need a barrier. Otherwise,
7721     // it can be done in parallel.
7722     ImageLayerWriteMask layerMask = GetImageLayerWriteMask(layerStart, layerCount);
7723     for (uint32_t levelOffset = 0; levelOffset < levelCount; levelOffset++)
7724     {
7725         uint32_t level = levelStart.get() + levelOffset;
7726         if (areLevelSubresourcesWrittenWithinMaskRange(level, layerMask))
7727         {
7728             return true;
7729         }
7730     }
7731 
7732     return false;
7733 }
7734 
changeLayoutAndQueue(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,DeviceQueueIndex newDeviceQueueIndex,OutsideRenderPassCommandBuffer * commandBuffer)7735 void ImageHelper::changeLayoutAndQueue(Context *context,
7736                                        VkImageAspectFlags aspectMask,
7737                                        ImageLayout newLayout,
7738                                        DeviceQueueIndex newDeviceQueueIndex,
7739                                        OutsideRenderPassCommandBuffer *commandBuffer)
7740 {
7741     ASSERT(!mIsForeignImage);
7742 
7743     ASSERT(isQueueFamilyChangeNeccesary(newDeviceQueueIndex));
7744     VkSemaphore acquireNextImageSemaphore;
7745     // recordBarrierImpl should detect there is queue switch and fall back to pipelineBarrier
7746     // properly.
7747     recordBarrierImpl(context, aspectMask, newLayout, newDeviceQueueIndex, nullptr, commandBuffer,
7748                       &acquireNextImageSemaphore);
7749     // SwapChain image should not get here.
7750     ASSERT(acquireNextImageSemaphore == VK_NULL_HANDLE);
7751 }
7752 
acquireFromExternal(Context * context,DeviceQueueIndex externalQueueIndex,DeviceQueueIndex newDeviceQueueIndex,ImageLayout currentLayout,OutsideRenderPassCommandBuffer * commandBuffer)7753 void ImageHelper::acquireFromExternal(Context *context,
7754                                       DeviceQueueIndex externalQueueIndex,
7755                                       DeviceQueueIndex newDeviceQueueIndex,
7756                                       ImageLayout currentLayout,
7757                                       OutsideRenderPassCommandBuffer *commandBuffer)
7758 {
7759     // The image must be newly allocated or have been released to the external
7760     // queue. If this is not the case, it's an application bug, so ASSERT might
7761     // eventually need to change to a warning.
7762     ASSERT(mCurrentLayout == ImageLayout::ExternalPreInitialized ||
7763            mCurrentDeviceQueueIndex.familyIndex() == externalQueueIndex.familyIndex());
7764 
7765     mCurrentLayout           = currentLayout;
7766     mCurrentDeviceQueueIndex = externalQueueIndex;
7767     mIsReleasedToExternal    = false;
7768 
7769     // Only change the layout and queue if the layout is anything by Undefined.  If it is undefined,
7770     // leave it to transition out as the image is used later.
7771     if (currentLayout != ImageLayout::Undefined)
7772     {
7773         changeLayoutAndQueue(context, getAspectFlags(), mCurrentLayout, newDeviceQueueIndex,
7774                              commandBuffer);
7775     }
7776 
7777     // It is unknown how the external has modified the image, so assume every subresource has
7778     // defined content.  That is unless the layout is Undefined.
7779     if (currentLayout == ImageLayout::Undefined)
7780     {
7781         setEntireContentUndefined();
7782     }
7783     else
7784     {
7785         setEntireContentDefined();
7786     }
7787 }
7788 
releaseToExternal(Context * context,DeviceQueueIndex externalQueueIndex,ImageLayout desiredLayout,OutsideRenderPassCommandBuffer * commandBuffer)7789 void ImageHelper::releaseToExternal(Context *context,
7790                                     DeviceQueueIndex externalQueueIndex,
7791                                     ImageLayout desiredLayout,
7792                                     OutsideRenderPassCommandBuffer *commandBuffer)
7793 {
7794     ASSERT(!mIsReleasedToExternal);
7795 
7796     // A layout change is unnecessary if the image that was previously acquired was never used by
7797     // GL!
7798     if (mCurrentDeviceQueueIndex.familyIndex() != externalQueueIndex.familyIndex() ||
7799         mCurrentLayout != desiredLayout)
7800     {
7801         changeLayoutAndQueue(context, getAspectFlags(), desiredLayout, externalQueueIndex,
7802                              commandBuffer);
7803     }
7804 
7805     mIsReleasedToExternal = true;
7806 }
7807 
releaseToForeign(Renderer * renderer)7808 VkImageMemoryBarrier ImageHelper::releaseToForeign(Renderer *renderer)
7809 {
7810     ASSERT(mIsForeignImage);
7811 
7812     const ImageMemoryBarrierData barrierData = renderer->getImageMemoryBarrierData(mCurrentLayout);
7813 
7814     VkImageMemoryBarrier barrier        = {};
7815     barrier.sType                       = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
7816     barrier.srcAccessMask               = barrierData.srcAccessMask;
7817     barrier.dstAccessMask               = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
7818     barrier.oldLayout                   = barrierData.layout;
7819     barrier.newLayout                   = VK_IMAGE_LAYOUT_GENERAL;
7820     barrier.srcQueueFamilyIndex         = renderer->getQueueFamilyIndex();
7821     barrier.dstQueueFamilyIndex         = VK_QUEUE_FAMILY_FOREIGN_EXT;
7822     barrier.image                       = mImage.getHandle();
7823     barrier.subresourceRange.aspectMask = getAspectFlags();
7824     barrier.subresourceRange.levelCount = mLevelCount;
7825     barrier.subresourceRange.layerCount = mLayerCount;
7826 
7827     mCurrentLayout               = ImageLayout::ForeignAccess;
7828     mCurrentDeviceQueueIndex     = kForeignDeviceQueueIndex;
7829     mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
7830     mCurrentShaderReadStageMask  = 0;
7831 
7832     return barrier;
7833 }
7834 
toVkLevel(gl::LevelIndex levelIndexGL) const7835 LevelIndex ImageHelper::toVkLevel(gl::LevelIndex levelIndexGL) const
7836 {
7837     return gl_vk::GetLevelIndex(levelIndexGL, mFirstAllocatedLevel);
7838 }
7839 
toGLLevel(LevelIndex levelIndexVk) const7840 gl::LevelIndex ImageHelper::toGLLevel(LevelIndex levelIndexVk) const
7841 {
7842     return vk_gl::GetLevelIndex(levelIndexVk, mFirstAllocatedLevel);
7843 }
7844 
initImageMemoryBarrierStruct(Renderer * renderer,VkImageAspectFlags aspectMask,ImageLayout newLayout,uint32_t newQueueFamilyIndex,VkImageMemoryBarrier * imageMemoryBarrier) const7845 ANGLE_INLINE void ImageHelper::initImageMemoryBarrierStruct(
7846     Renderer *renderer,
7847     VkImageAspectFlags aspectMask,
7848     ImageLayout newLayout,
7849     uint32_t newQueueFamilyIndex,
7850     VkImageMemoryBarrier *imageMemoryBarrier) const
7851 {
7852     ASSERT(mCurrentDeviceQueueIndex.familyIndex() != QueueFamily::kInvalidIndex);
7853     ASSERT(newQueueFamilyIndex != QueueFamily::kInvalidIndex);
7854 
7855     const ImageMemoryBarrierData &transitionFrom =
7856         renderer->getImageMemoryBarrierData(mCurrentLayout);
7857     const ImageMemoryBarrierData &transitionTo = renderer->getImageMemoryBarrierData(newLayout);
7858 
7859     imageMemoryBarrier->sType         = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
7860     imageMemoryBarrier->srcAccessMask = transitionFrom.srcAccessMask;
7861     imageMemoryBarrier->dstAccessMask = transitionTo.dstAccessMask;
7862     imageMemoryBarrier->oldLayout           = ConvertImageLayoutToVkImageLayout(mCurrentLayout);
7863     imageMemoryBarrier->newLayout           = ConvertImageLayoutToVkImageLayout(newLayout);
7864     imageMemoryBarrier->srcQueueFamilyIndex = mCurrentDeviceQueueIndex.familyIndex();
7865     imageMemoryBarrier->dstQueueFamilyIndex = newQueueFamilyIndex;
7866     imageMemoryBarrier->image               = mImage.getHandle();
7867 
7868     // Transition the whole resource.
7869     imageMemoryBarrier->subresourceRange.aspectMask     = aspectMask;
7870     imageMemoryBarrier->subresourceRange.baseMipLevel   = 0;
7871     imageMemoryBarrier->subresourceRange.levelCount     = mLevelCount;
7872     imageMemoryBarrier->subresourceRange.baseArrayLayer = 0;
7873     imageMemoryBarrier->subresourceRange.layerCount     = mLayerCount;
7874 }
7875 
7876 // Generalized to accept both "primary" and "secondary" command buffers.
7877 template <typename CommandBufferT>
barrierImpl(Renderer * renderer,VkImageAspectFlags aspectMask,ImageLayout newLayout,DeviceQueueIndex newDeviceQueueIndex,RefCountedEventCollector * eventCollector,CommandBufferT * commandBuffer,VkSemaphore * acquireNextImageSemaphoreOut)7878 void ImageHelper::barrierImpl(Renderer *renderer,
7879                               VkImageAspectFlags aspectMask,
7880                               ImageLayout newLayout,
7881                               DeviceQueueIndex newDeviceQueueIndex,
7882                               RefCountedEventCollector *eventCollector,
7883                               CommandBufferT *commandBuffer,
7884                               VkSemaphore *acquireNextImageSemaphoreOut)
7885 {
7886     // Release the ANI semaphore to caller to add to the command submission.
7887     ASSERT(acquireNextImageSemaphoreOut != nullptr || !mAcquireNextImageSemaphore.valid());
7888     if (acquireNextImageSemaphoreOut != nullptr)
7889     {
7890         *acquireNextImageSemaphoreOut = mAcquireNextImageSemaphore.release();
7891     }
7892 
7893     if (mCurrentLayout == ImageLayout::SharedPresent)
7894     {
7895         const ImageMemoryBarrierData &transition =
7896             renderer->getImageMemoryBarrierData(mCurrentLayout);
7897         VkMemoryBarrier memoryBarrier = {};
7898         memoryBarrier.sType           = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
7899         memoryBarrier.srcAccessMask   = transition.srcAccessMask;
7900         memoryBarrier.dstAccessMask   = transition.dstAccessMask;
7901 
7902         commandBuffer->memoryBarrier(transition.srcStageMask, transition.dstStageMask,
7903                                      memoryBarrier);
7904         return;
7905     }
7906 
7907     // Make sure we never transition out of SharedPresent
7908     ASSERT(mCurrentLayout != ImageLayout::SharedPresent || newLayout == ImageLayout::SharedPresent);
7909 
7910     const ImageMemoryBarrierData &transitionFrom =
7911         renderer->getImageMemoryBarrierData(mCurrentLayout);
7912     const ImageMemoryBarrierData &transitionTo = renderer->getImageMemoryBarrierData(newLayout);
7913 
7914     VkImageMemoryBarrier imageMemoryBarrier = {};
7915     initImageMemoryBarrierStruct(renderer, aspectMask, newLayout, newDeviceQueueIndex.familyIndex(),
7916                                  &imageMemoryBarrier);
7917 
7918     VkPipelineStageFlags dstStageMask = transitionTo.dstStageMask;
7919 
7920     // Fallback to pipelineBarrier if there is no event tracking image.
7921     // VkCmdWaitEvent requires the srcQueueFamilyIndex and dstQueueFamilyIndex members of any
7922     // element of pBufferMemoryBarriers or pImageMemoryBarriers must be equal
7923     // (VUID-vkCmdWaitEvents-srcQueueFamilyIndex-02803).
7924     BarrierType barrierType =
7925         mCurrentEvent.valid() && mCurrentDeviceQueueIndex == newDeviceQueueIndex
7926             ? BarrierType::Event
7927             : BarrierType::Pipeline;
7928 
7929     if (barrierType == BarrierType::Event)
7930     {
7931         // If there is an event, we use the waitEvent to do layout change. Once we have waited, the
7932         // event gets garbage collected (which is GPU completion tracked) to avoid waited again in
7933         // future. We always use DstStageMask since that is what setEvent used and
7934         // VUID-vkCmdWaitEvents-srcStageMask-01158 requires they must match.
7935         VkPipelineStageFlags srcStageMask =
7936             renderer->getPipelineStageMask(mCurrentEvent.getEventStage());
7937         commandBuffer->imageWaitEvent(mCurrentEvent.getEvent().getHandle(), srcStageMask,
7938                                       dstStageMask, imageMemoryBarrier);
7939         eventCollector->emplace_back(std::move(mCurrentEvent));
7940     }
7941     else
7942     {
7943         // There might be other shaderRead operations there other than the current layout.
7944         VkPipelineStageFlags srcStageMask = transitionFrom.srcStageMask;
7945         if (mCurrentShaderReadStageMask)
7946         {
7947             srcStageMask |= mCurrentShaderReadStageMask;
7948             mCurrentShaderReadStageMask  = 0;
7949             mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
7950         }
7951         commandBuffer->imageBarrier(srcStageMask, dstStageMask, imageMemoryBarrier);
7952     }
7953 
7954     mCurrentLayout           = newLayout;
7955     mCurrentDeviceQueueIndex = newDeviceQueueIndex;
7956     resetSubresourcesWrittenSinceBarrier();
7957 }
7958 
7959 template <typename CommandBufferT>
recordBarrierImpl(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,DeviceQueueIndex newDeviceQueueIndex,RefCountedEventCollector * eventCollector,CommandBufferT * commandBuffer,VkSemaphore * acquireNextImageSemaphoreOut)7960 void ImageHelper::recordBarrierImpl(Context *context,
7961                                     VkImageAspectFlags aspectMask,
7962                                     ImageLayout newLayout,
7963                                     DeviceQueueIndex newDeviceQueueIndex,
7964                                     RefCountedEventCollector *eventCollector,
7965                                     CommandBufferT *commandBuffer,
7966                                     VkSemaphore *acquireNextImageSemaphoreOut)
7967 {
7968     Renderer *renderer = context->getRenderer();
7969     // mCurrentEvent must be invalid if useVkEventForImageBarrieris disabled.
7970     ASSERT(renderer->getFeatures().useVkEventForImageBarrier.enabled || !mCurrentEvent.valid());
7971 
7972     if (mCurrentLayout == ImageLayout::SharedPresent)
7973     {
7974         // For now we always use pipelineBarrier for singlebuffer mode. We could use event here in
7975         // future.
7976         mCurrentEvent.release(context);
7977     }
7978 
7979     // The image has transitioned out of the FOREIGN queue.  Remember it so it can be transitioned
7980     // back on submission.
7981     if (mCurrentDeviceQueueIndex == kForeignDeviceQueueIndex)
7982     {
7983         context->onForeignImageUse(this);
7984     }
7985 
7986     barrierImpl(renderer, aspectMask, newLayout, newDeviceQueueIndex, eventCollector, commandBuffer,
7987                 acquireNextImageSemaphoreOut);
7988 
7989     // We must release the event so that new event will be created and added. If we did not add new
7990     // event, because mCurrentEvent have been released, next barrier will automatically fallback to
7991     // pipelineBarrier. Otherwise if we keep mCurrentEvent here we may accidentally end up waiting
7992     // for an old event which creates sync hazard.
7993     mCurrentEvent.release(context);
7994 }
7995 
recordBarrierOneOffImpl(Renderer * renderer,VkImageAspectFlags aspectMask,ImageLayout newLayout,DeviceQueueIndex newDeviceQueueIndex,PrimaryCommandBuffer * commandBuffer,VkSemaphore * acquireNextImageSemaphoreOut)7996 void ImageHelper::recordBarrierOneOffImpl(Renderer *renderer,
7997                                           VkImageAspectFlags aspectMask,
7998                                           ImageLayout newLayout,
7999                                           DeviceQueueIndex newDeviceQueueIndex,
8000                                           PrimaryCommandBuffer *commandBuffer,
8001                                           VkSemaphore *acquireNextImageSemaphoreOut)
8002 {
8003     // Release the event here to force pipelineBarrier.
8004     mCurrentEvent.release(renderer);
8005     ASSERT(mCurrentDeviceQueueIndex != kForeignDeviceQueueIndex);
8006 
8007     barrierImpl(renderer, aspectMask, newLayout, newDeviceQueueIndex, nullptr, commandBuffer,
8008                 acquireNextImageSemaphoreOut);
8009 }
8010 
setSubresourcesWrittenSinceBarrier(gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount)8011 void ImageHelper::setSubresourcesWrittenSinceBarrier(gl::LevelIndex levelStart,
8012                                                      uint32_t levelCount,
8013                                                      uint32_t layerStart,
8014                                                      uint32_t layerCount)
8015 {
8016     for (uint32_t levelOffset = 0; levelOffset < levelCount; levelOffset++)
8017     {
8018         uint32_t level = levelStart.get() + levelOffset;
8019         if (layerCount >= kMaxParallelLayerWrites)
8020         {
8021             mSubresourcesWrittenSinceBarrier[level].set();
8022         }
8023         else
8024         {
8025             ImageLayerWriteMask layerMask = GetImageLayerWriteMask(layerStart, layerCount);
8026             mSubresourcesWrittenSinceBarrier[level] |= layerMask;
8027         }
8028     }
8029 }
8030 
resetSubresourcesWrittenSinceBarrier()8031 void ImageHelper::resetSubresourcesWrittenSinceBarrier()
8032 {
8033     for (auto &layerWriteMask : mSubresourcesWrittenSinceBarrier)
8034     {
8035         layerWriteMask.reset();
8036     }
8037 }
8038 
recordWriteBarrier(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,OutsideRenderPassCommandBufferHelper * commands)8039 void ImageHelper::recordWriteBarrier(Context *context,
8040                                      VkImageAspectFlags aspectMask,
8041                                      ImageLayout newLayout,
8042                                      gl::LevelIndex levelStart,
8043                                      uint32_t levelCount,
8044                                      uint32_t layerStart,
8045                                      uint32_t layerCount,
8046                                      OutsideRenderPassCommandBufferHelper *commands)
8047 {
8048     if (isWriteBarrierNecessary(newLayout, levelStart, levelCount, layerStart, layerCount))
8049     {
8050         ASSERT(!mCurrentEvent.valid() || !commands->hasSetEventPendingFlush(mCurrentEvent));
8051         VkSemaphore acquireNextImageSemaphore;
8052         recordBarrierImpl(context, aspectMask, newLayout, context->getDeviceQueueIndex(),
8053                           commands->getRefCountedEventCollector(), &commands->getCommandBuffer(),
8054                           &acquireNextImageSemaphore);
8055 
8056         if (acquireNextImageSemaphore != VK_NULL_HANDLE)
8057         {
8058             commands->setAcquireNextImageSemaphore(acquireNextImageSemaphore);
8059         }
8060     }
8061 
8062     setSubresourcesWrittenSinceBarrier(levelStart, levelCount, layerStart, layerCount);
8063 }
8064 
recordReadSubresourceBarrier(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,OutsideRenderPassCommandBufferHelper * commands)8065 void ImageHelper::recordReadSubresourceBarrier(Context *context,
8066                                                VkImageAspectFlags aspectMask,
8067                                                ImageLayout newLayout,
8068                                                gl::LevelIndex levelStart,
8069                                                uint32_t levelCount,
8070                                                uint32_t layerStart,
8071                                                uint32_t layerCount,
8072                                                OutsideRenderPassCommandBufferHelper *commands)
8073 {
8074     // This barrier is used for an image with both read/write permissions, including during mipmap
8075     // generation and self-copy.
8076     if (isReadSubresourceBarrierNecessary(newLayout, levelStart, levelCount, layerStart,
8077                                           layerCount))
8078     {
8079         ASSERT(!mCurrentEvent.valid() || !commands->hasSetEventPendingFlush(mCurrentEvent));
8080         VkSemaphore acquireNextImageSemaphore;
8081         recordBarrierImpl(context, aspectMask, newLayout, context->getDeviceQueueIndex(),
8082                           commands->getRefCountedEventCollector(), &commands->getCommandBuffer(),
8083                           &acquireNextImageSemaphore);
8084 
8085         if (acquireNextImageSemaphore != VK_NULL_HANDLE)
8086         {
8087             commands->setAcquireNextImageSemaphore(acquireNextImageSemaphore);
8088         }
8089     }
8090 
8091     // Levels/layers being read from are also registered to avoid RAW and WAR hazards.
8092     setSubresourcesWrittenSinceBarrier(levelStart, levelCount, layerStart, layerCount);
8093 }
8094 
recordReadBarrier(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,OutsideRenderPassCommandBufferHelper * commands)8095 void ImageHelper::recordReadBarrier(Context *context,
8096                                     VkImageAspectFlags aspectMask,
8097                                     ImageLayout newLayout,
8098                                     OutsideRenderPassCommandBufferHelper *commands)
8099 {
8100     if (!isReadBarrierNecessary(context->getRenderer(), newLayout))
8101     {
8102         return;
8103     }
8104 
8105     ASSERT(!mCurrentEvent.valid() || !commands->hasSetEventPendingFlush(mCurrentEvent));
8106     VkSemaphore acquireNextImageSemaphore;
8107     recordBarrierImpl(context, aspectMask, newLayout, context->getDeviceQueueIndex(),
8108                       commands->getRefCountedEventCollector(), &commands->getCommandBuffer(),
8109                       &acquireNextImageSemaphore);
8110 
8111     if (acquireNextImageSemaphore != VK_NULL_HANDLE)
8112     {
8113         commands->setAcquireNextImageSemaphore(acquireNextImageSemaphore);
8114     }
8115 }
8116 
updateLayoutAndBarrier(Context * context,VkImageAspectFlags aspectMask,ImageLayout newLayout,BarrierType barrierType,const QueueSerial & queueSerial,PipelineBarrierArray * pipelineBarriers,EventBarrierArray * eventBarriers,RefCountedEventCollector * eventCollector,VkSemaphore * semaphoreOut)8117 void ImageHelper::updateLayoutAndBarrier(Context *context,
8118                                          VkImageAspectFlags aspectMask,
8119                                          ImageLayout newLayout,
8120                                          BarrierType barrierType,
8121                                          const QueueSerial &queueSerial,
8122                                          PipelineBarrierArray *pipelineBarriers,
8123                                          EventBarrierArray *eventBarriers,
8124                                          RefCountedEventCollector *eventCollector,
8125                                          VkSemaphore *semaphoreOut)
8126 {
8127     Renderer *renderer = context->getRenderer();
8128     ASSERT(queueSerial.valid());
8129     ASSERT(!mBarrierQueueSerial.valid() ||
8130            mBarrierQueueSerial.getIndex() != queueSerial.getIndex() ||
8131            mBarrierQueueSerial.getSerial() <= queueSerial.getSerial());
8132     ASSERT(renderer->getImageMemoryBarrierData(newLayout).barrierIndex !=
8133            PipelineStage::InvalidEnum);
8134     // mCurrentEvent must be invalid if useVkEventForImageBarrieris disabled.
8135     ASSERT(renderer->getFeatures().useVkEventForImageBarrier.enabled || !mCurrentEvent.valid());
8136 
8137     const bool hasQueueChange = mCurrentDeviceQueueIndex != context->getDeviceQueueIndex();
8138     if (hasQueueChange)
8139     {
8140         // Fallback to pipelineBarrier if the VkQueue has changed.
8141         barrierType              = BarrierType::Pipeline;
8142         if (mCurrentDeviceQueueIndex == kForeignDeviceQueueIndex)
8143         {
8144             context->onForeignImageUse(this);
8145         }
8146     }
8147     else if (!mCurrentEvent.valid())
8148     {
8149         // Fallback to pipelineBarrier if there is no event tracking image.
8150         barrierType = BarrierType::Pipeline;
8151     }
8152 
8153     // Once you transition to ImageLayout::SharedPresent, you never transition out of it.
8154     if (mCurrentLayout == ImageLayout::SharedPresent)
8155     {
8156         newLayout = ImageLayout::SharedPresent;
8157     }
8158 
8159     if (newLayout == mCurrentLayout && !hasQueueChange)
8160     {
8161         if (mBarrierQueueSerial == queueSerial)
8162         {
8163             ASSERT(!mAcquireNextImageSemaphore.valid());
8164             // If there is no layout change and the previous layout change happened in the same
8165             // render pass, then early out do nothing. This can happen when the same image is
8166             // attached to the multiple attachments of the framebuffer.
8167             return;
8168         }
8169 
8170         const ImageMemoryBarrierData &layoutData =
8171             renderer->getImageMemoryBarrierData(mCurrentLayout);
8172         // RAR is not a hazard and doesn't require a barrier, especially as the image layout hasn't
8173         // changed.  The following asserts that such a barrier is not attempted.
8174         ASSERT(HasResourceWriteAccess(layoutData.type));
8175 
8176         // No layout change, only memory barrier is required
8177         if (barrierType == BarrierType::Event)
8178         {
8179             eventBarriers->addEventMemoryBarrier(renderer, mCurrentEvent, layoutData.dstAccessMask,
8180                                                  layoutData.dstStageMask, layoutData.dstAccessMask);
8181             // Garbage collect the event, which tracks GPU completion automatically.
8182             eventCollector->emplace_back(std::move(mCurrentEvent));
8183         }
8184         else
8185         {
8186             pipelineBarriers->mergeMemoryBarrier(layoutData.barrierIndex, layoutData.dstStageMask,
8187                                                  layoutData.dstStageMask, layoutData.srcAccessMask,
8188                                                  layoutData.dstAccessMask);
8189 
8190             // Release it. No need to garbage collect since we did not use the event here. ALl
8191             // previous use of event should garbage tracked already.
8192             mCurrentEvent.release(context);
8193         }
8194         mBarrierQueueSerial = queueSerial;
8195     }
8196     else
8197     {
8198         const ImageMemoryBarrierData &transitionFrom =
8199             renderer->getImageMemoryBarrierData(mCurrentLayout);
8200         const ImageMemoryBarrierData &transitionTo = renderer->getImageMemoryBarrierData(newLayout);
8201         VkPipelineStageFlags srcStageMask          = transitionFrom.srcStageMask;
8202         VkPipelineStageFlags dstStageMask          = transitionTo.dstStageMask;
8203 
8204         if (transitionFrom.layout == transitionTo.layout && IsShaderReadOnlyLayout(transitionTo) &&
8205             mBarrierQueueSerial == queueSerial && !hasQueueChange)
8206         {
8207             // If we are switching between different shader stage reads of the same render pass,
8208             // then there is no actual layout change or access type change. We only need a barrier
8209             // if we are making a read that is from a new stage. Also note that we do barrier
8210             // against previous non-shaderRead layout. We do not barrier between one shaderRead and
8211             // another shaderRead.
8212             bool isNewReadStage = (mCurrentShaderReadStageMask & dstStageMask) != dstStageMask;
8213             if (!isNewReadStage)
8214             {
8215                 ASSERT(!mAcquireNextImageSemaphore.valid());
8216                 return;
8217             }
8218 
8219             ASSERT(!mLastNonShaderReadOnlyEvent.valid() ||
8220                    mLastNonShaderReadOnlyEvent.getEventStage() ==
8221                        GetImageLayoutEventStage(mLastNonShaderReadOnlyLayout));
8222             if (!mLastNonShaderReadOnlyEvent.valid())
8223             {
8224                 barrierType = BarrierType::Pipeline;
8225             }
8226 
8227             if (barrierType == BarrierType::Event)
8228             {
8229                 // If we already inserted a barrier in the same renderPass, we has to add
8230                 // the new stage mask to the existing VkCmdWaitEvent call, otherwise VVL will
8231                 // complain.
8232                 eventBarriers->addAdditionalStageAccess(mLastNonShaderReadOnlyEvent, dstStageMask,
8233                                                         transitionTo.dstAccessMask);
8234                 eventCollector->emplace_back(mLastNonShaderReadOnlyEvent);
8235             }
8236             else
8237             {
8238                 const ImageMemoryBarrierData &layoutData =
8239                     renderer->getImageMemoryBarrierData(mLastNonShaderReadOnlyLayout);
8240                 pipelineBarriers->mergeMemoryBarrier(
8241                     transitionTo.barrierIndex, layoutData.srcStageMask, dstStageMask,
8242                     layoutData.srcAccessMask, transitionTo.dstAccessMask);
8243             }
8244 
8245             mBarrierQueueSerial = queueSerial;
8246             // Accumulate new read stage.
8247             mCurrentShaderReadStageMask |= dstStageMask;
8248 
8249             // Since we used pipelineBarrier, release the event now to avoid wait for the
8250             // event again.
8251             if (mCurrentEvent.valid())
8252             {
8253                 eventCollector->emplace_back(std::move(mCurrentEvent));
8254             }
8255         }
8256         else
8257         {
8258             VkImageMemoryBarrier imageMemoryBarrier = {};
8259             initImageMemoryBarrierStruct(renderer, aspectMask, newLayout,
8260                                          context->getDeviceQueueIndex().familyIndex(),
8261                                          &imageMemoryBarrier);
8262 
8263             if (transitionFrom.layout == transitionTo.layout &&
8264                 IsShaderReadOnlyLayout(transitionTo))
8265             {
8266                 // If we are transiting within shaderReadOnly layout, i.e. reading from different
8267                 // shader stages, VkEvent can't handle this right now. In order for VkEvent to
8268                 // handle this properly we have to wait for the previous shaderReadOnly layout
8269                 // transition event and add a new memoryBarrier. But we may have lost that event
8270                 // already if it has been used in a new render pass (because we have to update the
8271                 // event even if there is no barrier needed). To workaround this issue we fall back
8272                 // to pipelineBarrier for now.
8273                 barrierType = BarrierType::Pipeline;
8274             }
8275             else if (mBarrierQueueSerial == queueSerial)
8276             {
8277                 // If we already inserted a barrier in this render pass, force to use
8278                 // pipelineBarrier. Otherwise we will end up inserting a VkCmdWaitEvent that has not
8279                 // been set (See https://issuetracker.google.com/333419317 for example).
8280                 barrierType = BarrierType::Pipeline;
8281             }
8282 
8283             // if we transition from shaderReadOnly, we must add in stashed shader stage masks since
8284             // there might be outstanding shader reads from stages other than current layout. We do
8285             // not insert barrier between one shaderRead to another shaderRead
8286             if (mCurrentShaderReadStageMask)
8287             {
8288                 if ((mCurrentShaderReadStageMask & srcStageMask) != mCurrentShaderReadStageMask)
8289                 {
8290                     // mCurrentShaderReadStageMask has more bits than srcStageMask. This means it
8291                     // has been used by more than one shader stage in the same render pass. These
8292                     // two usages are tracked by two different ImageLayout, even though underline
8293                     // VkImageLayout is the same. This means two different RefCountedEvents since
8294                     // each RefCountedEvent is associated with one ImageLayout. When we transit out
8295                     // of this layout, we must wait for all reads to finish. But Right now
8296                     // ImageHelper only keep track of the last read. To workaround this problem we
8297                     // use pipelineBarrier in this case.
8298                     barrierType = BarrierType::Pipeline;
8299                     srcStageMask |= mCurrentShaderReadStageMask;
8300                 }
8301                 mCurrentShaderReadStageMask  = 0;
8302                 mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
8303                 if (mLastNonShaderReadOnlyEvent.valid())
8304                 {
8305                     mLastNonShaderReadOnlyEvent.release(context);
8306                 }
8307             }
8308 
8309             // If we are transition into shaderRead layout, remember the last
8310             // non-shaderRead layout here.
8311             const bool isShaderReadOnly = IsShaderReadOnlyLayout(transitionTo);
8312             if (isShaderReadOnly)
8313             {
8314                 mLastNonShaderReadOnlyEvent.release(context);
8315                 mLastNonShaderReadOnlyLayout = mCurrentLayout;
8316                 mCurrentShaderReadStageMask  = dstStageMask;
8317             }
8318 
8319             if (barrierType == BarrierType::Event)
8320             {
8321                 eventBarriers->addEventImageBarrier(renderer, mCurrentEvent, dstStageMask,
8322                                                     imageMemoryBarrier);
8323                 if (isShaderReadOnly)
8324                 {
8325                     mLastNonShaderReadOnlyEvent = mCurrentEvent;
8326                 }
8327                 eventCollector->emplace_back(std::move(mCurrentEvent));
8328             }
8329             else
8330             {
8331                 pipelineBarriers->mergeImageBarrier(transitionTo.barrierIndex, srcStageMask,
8332                                                     dstStageMask, imageMemoryBarrier);
8333                 mCurrentEvent.release(context);
8334             }
8335 
8336             mBarrierQueueSerial = queueSerial;
8337         }
8338         mCurrentLayout = newLayout;
8339     }
8340 
8341     mCurrentDeviceQueueIndex = context->getDeviceQueueIndex();
8342 
8343     *semaphoreOut = mAcquireNextImageSemaphore.release();
8344     // We must release the event so that new event will be created and added. If we did not add new
8345     // event, because mCurrentEvent have been released, next barrier will automatically fallback to
8346     // pipelineBarrier. Otherwise if we keep mCurrentEvent here we may accidentally end up waiting
8347     // for an old event which creates sync hazard.
8348     ASSERT(!mCurrentEvent.valid());
8349 }
8350 
setCurrentRefCountedEvent(Context * context,RefCountedEventArray * refCountedEventArray)8351 void ImageHelper::setCurrentRefCountedEvent(Context *context,
8352                                             RefCountedEventArray *refCountedEventArray)
8353 {
8354     ASSERT(context->getFeatures().useVkEventForImageBarrier.enabled);
8355 
8356     // If there is already an event, release it first.
8357     mCurrentEvent.release(context);
8358 
8359     // VkCmdSetEvent can remove the unnecessary GPU pipeline bubble that comes from false dependency
8360     // between fragment and vertex/transfer/compute stages. But it also comes with higher overhead.
8361     // In order to strike the balance, we exclude the images that are only used by one group of
8362     // pipeline stages in the past N references, where N is the heuristic window that we keep track
8363     // of. Use of VkEvent will not be beneficial if it is only accessed by one group of stages since
8364     // execution within the group is expected to be non-overlap.
8365     if (mPipelineStageAccessHeuristic == kPipelineStageAccessFragmentOnly ||
8366         mPipelineStageAccessHeuristic == kPipelineStageAccessPreFragmentOnly ||
8367         mPipelineStageAccessHeuristic == kPipelineStageAccessComputeOnly)
8368     {
8369         return;
8370     }
8371 
8372     // Create the event if we have not yet so. Otherwise just use the already created event. This
8373     // means all images used in the same render pass that has the same layout will be tracked by the
8374     // same event.
8375     EventStage eventStage = GetImageLayoutEventStage(mCurrentLayout);
8376     if (!refCountedEventArray->getEvent(eventStage).valid() &&
8377         !refCountedEventArray->initEventAtStage(context, eventStage))
8378     {
8379         // If VkEvent creation fail, we fallback to pipelineBarrier
8380         return;
8381     }
8382 
8383     // Copy the event to mCurrentEvent so that we can wait for it in future. This will add extra
8384     // refcount to the underlying VkEvent.
8385     mCurrentEvent = refCountedEventArray->getEvent(eventStage);
8386 }
8387 
updatePipelineStageAccessHistory()8388 void ImageHelper::updatePipelineStageAccessHistory()
8389 {
8390     const ImageMemoryBarrierData &barrierData = kImageMemoryBarrierData[mCurrentLayout];
8391     mPipelineStageAccessHeuristic.onAccess(barrierData.pipelineStageGroup);
8392 }
8393 
clearColor(Renderer * renderer,const VkClearColorValue & color,LevelIndex baseMipLevelVk,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount,OutsideRenderPassCommandBuffer * commandBuffer)8394 void ImageHelper::clearColor(Renderer *renderer,
8395                              const VkClearColorValue &color,
8396                              LevelIndex baseMipLevelVk,
8397                              uint32_t levelCount,
8398                              uint32_t baseArrayLayer,
8399                              uint32_t layerCount,
8400                              OutsideRenderPassCommandBuffer *commandBuffer)
8401 {
8402     ASSERT(valid());
8403 
8404     ASSERT(mCurrentLayout == ImageLayout::TransferDst ||
8405            mCurrentLayout == ImageLayout::SharedPresent);
8406 
8407     VkImageSubresourceRange range = {};
8408     range.aspectMask              = VK_IMAGE_ASPECT_COLOR_BIT;
8409     range.baseMipLevel            = baseMipLevelVk.get();
8410     range.levelCount              = levelCount;
8411     range.baseArrayLayer          = baseArrayLayer;
8412     range.layerCount              = layerCount;
8413 
8414     if (mImageType == VK_IMAGE_TYPE_3D)
8415     {
8416         ASSERT(baseArrayLayer == 0);
8417         ASSERT(layerCount == 1 ||
8418                layerCount == static_cast<uint32_t>(getLevelExtents(baseMipLevelVk).depth));
8419         range.layerCount = 1;
8420     }
8421 
8422     commandBuffer->clearColorImage(mImage, getCurrentLayout(), color, 1, &range);
8423 }
8424 
clearDepthStencil(Renderer * renderer,VkImageAspectFlags clearAspectFlags,const VkClearDepthStencilValue & depthStencil,LevelIndex baseMipLevelVk,uint32_t levelCount,uint32_t baseArrayLayer,uint32_t layerCount,OutsideRenderPassCommandBuffer * commandBuffer)8425 void ImageHelper::clearDepthStencil(Renderer *renderer,
8426                                     VkImageAspectFlags clearAspectFlags,
8427                                     const VkClearDepthStencilValue &depthStencil,
8428                                     LevelIndex baseMipLevelVk,
8429                                     uint32_t levelCount,
8430                                     uint32_t baseArrayLayer,
8431                                     uint32_t layerCount,
8432                                     OutsideRenderPassCommandBuffer *commandBuffer)
8433 {
8434     ASSERT(valid());
8435 
8436     ASSERT(mCurrentLayout == ImageLayout::TransferDst);
8437 
8438     VkImageSubresourceRange range = {};
8439     range.aspectMask              = clearAspectFlags;
8440     range.baseMipLevel            = baseMipLevelVk.get();
8441     range.levelCount              = levelCount;
8442     range.baseArrayLayer          = baseArrayLayer;
8443     range.layerCount              = layerCount;
8444 
8445     if (mImageType == VK_IMAGE_TYPE_3D)
8446     {
8447         ASSERT(baseArrayLayer == 0);
8448         ASSERT(layerCount == 1 ||
8449                layerCount == static_cast<uint32_t>(getLevelExtents(baseMipLevelVk).depth));
8450         range.layerCount = 1;
8451     }
8452 
8453     commandBuffer->clearDepthStencilImage(mImage, getCurrentLayout(), depthStencil, 1, &range);
8454 }
8455 
clear(Renderer * renderer,VkImageAspectFlags aspectFlags,const VkClearValue & value,LevelIndex mipLevel,uint32_t baseArrayLayer,uint32_t layerCount,OutsideRenderPassCommandBuffer * commandBuffer)8456 void ImageHelper::clear(Renderer *renderer,
8457                         VkImageAspectFlags aspectFlags,
8458                         const VkClearValue &value,
8459                         LevelIndex mipLevel,
8460                         uint32_t baseArrayLayer,
8461                         uint32_t layerCount,
8462                         OutsideRenderPassCommandBuffer *commandBuffer)
8463 {
8464     const angle::Format &angleFormat = getActualFormat();
8465     bool isDepthStencil              = angleFormat.hasDepthOrStencilBits();
8466 
8467     if (isDepthStencil)
8468     {
8469         clearDepthStencil(renderer, aspectFlags, value.depthStencil, mipLevel, 1, baseArrayLayer,
8470                           layerCount, commandBuffer);
8471     }
8472     else
8473     {
8474         ASSERT(!angleFormat.isBlock);
8475 
8476         clearColor(renderer, value.color, mipLevel, 1, baseArrayLayer, layerCount, commandBuffer);
8477     }
8478 }
8479 
clearEmulatedChannels(ContextVk * contextVk,VkColorComponentFlags colorMaskFlags,const VkClearValue & value,LevelIndex mipLevel,uint32_t baseArrayLayer,uint32_t layerCount)8480 angle::Result ImageHelper::clearEmulatedChannels(ContextVk *contextVk,
8481                                                  VkColorComponentFlags colorMaskFlags,
8482                                                  const VkClearValue &value,
8483                                                  LevelIndex mipLevel,
8484                                                  uint32_t baseArrayLayer,
8485                                                  uint32_t layerCount)
8486 {
8487     const gl::Extents levelExtents = getLevelExtents(mipLevel);
8488 
8489     if (levelExtents.depth > 1)
8490     {
8491         // Currently not implemented for 3D textures
8492         UNIMPLEMENTED();
8493         return angle::Result::Continue;
8494     }
8495 
8496     UtilsVk::ClearImageParameters params = {};
8497     params.clearArea                     = {0, 0, levelExtents.width, levelExtents.height};
8498     params.dstMip                        = mipLevel;
8499     params.colorMaskFlags                = colorMaskFlags;
8500     params.colorClearValue               = value.color;
8501 
8502     for (uint32_t layerIndex = 0; layerIndex < layerCount; ++layerIndex)
8503     {
8504         params.dstLayer = baseArrayLayer + layerIndex;
8505 
8506         ANGLE_TRY(contextVk->getUtils().clearImage(contextVk, this, params));
8507     }
8508 
8509     return angle::Result::Continue;
8510 }
8511 
8512 // 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)8513 void ImageHelper::Copy(Renderer *renderer,
8514                        ImageHelper *srcImage,
8515                        ImageHelper *dstImage,
8516                        const gl::Offset &srcOffset,
8517                        const gl::Offset &dstOffset,
8518                        const gl::Extents &copySize,
8519                        const VkImageSubresourceLayers &srcSubresource,
8520                        const VkImageSubresourceLayers &dstSubresource,
8521                        OutsideRenderPassCommandBuffer *commandBuffer)
8522 {
8523     ASSERT(commandBuffer->valid() && srcImage->valid() && dstImage->valid());
8524 
8525     ASSERT(srcImage->getCurrentLayout() == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
8526     ASSERT(dstImage->getCurrentLayout() == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
8527 
8528     VkImageCopy region    = {};
8529     region.srcSubresource = srcSubresource;
8530     region.srcOffset.x    = srcOffset.x;
8531     region.srcOffset.y    = srcOffset.y;
8532     region.srcOffset.z    = srcOffset.z;
8533     region.dstSubresource = dstSubresource;
8534     region.dstOffset.x    = dstOffset.x;
8535     region.dstOffset.y    = dstOffset.y;
8536     region.dstOffset.z    = dstOffset.z;
8537     region.extent.width   = copySize.width;
8538     region.extent.height  = copySize.height;
8539     region.extent.depth   = copySize.depth;
8540 
8541     commandBuffer->copyImage(srcImage->getImage(), srcImage->getCurrentLayout(),
8542                              dstImage->getImage(), dstImage->getCurrentLayout(), 1, &region);
8543 }
8544 
8545 // 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)8546 angle::Result ImageHelper::CopyImageSubData(const gl::Context *context,
8547                                             ImageHelper *srcImage,
8548                                             GLint srcLevel,
8549                                             GLint srcX,
8550                                             GLint srcY,
8551                                             GLint srcZ,
8552                                             ImageHelper *dstImage,
8553                                             GLint dstLevel,
8554                                             GLint dstX,
8555                                             GLint dstY,
8556                                             GLint dstZ,
8557                                             GLsizei srcWidth,
8558                                             GLsizei srcHeight,
8559                                             GLsizei srcDepth)
8560 {
8561     ContextVk *contextVk = GetImpl(context);
8562     Renderer *renderer   = contextVk->getRenderer();
8563 
8564     const gl::LevelIndex srcLevelGL = gl::LevelIndex(srcLevel);
8565     const gl::LevelIndex dstLevelGL = gl::LevelIndex(dstLevel);
8566 
8567     if (CanCopyWithTransferForCopyImage(renderer, srcImage, dstImage))
8568     {
8569         bool isSrc3D                         = srcImage->getType() == VK_IMAGE_TYPE_3D;
8570         bool isDst3D                         = dstImage->getType() == VK_IMAGE_TYPE_3D;
8571         const VkImageAspectFlags aspectFlags = srcImage->getAspectFlags();
8572 
8573         ASSERT(srcImage->getAspectFlags() == dstImage->getAspectFlags());
8574 
8575         VkImageCopy region = {};
8576 
8577         region.srcSubresource.aspectMask     = aspectFlags;
8578         region.srcSubresource.mipLevel       = srcImage->toVkLevel(srcLevelGL).get();
8579         region.srcSubresource.baseArrayLayer = isSrc3D ? 0 : srcZ;
8580         region.srcSubresource.layerCount     = isSrc3D ? 1 : srcDepth;
8581 
8582         region.dstSubresource.aspectMask     = aspectFlags;
8583         region.dstSubresource.mipLevel       = dstImage->toVkLevel(dstLevelGL).get();
8584         region.dstSubresource.baseArrayLayer = isDst3D ? 0 : dstZ;
8585         region.dstSubresource.layerCount     = isDst3D ? 1 : srcDepth;
8586 
8587         region.srcOffset.x   = srcX;
8588         region.srcOffset.y   = srcY;
8589         region.srcOffset.z   = isSrc3D ? srcZ : 0;
8590         region.dstOffset.x   = dstX;
8591         region.dstOffset.y   = dstY;
8592         region.dstOffset.z   = isDst3D ? dstZ : 0;
8593         region.extent.width  = srcWidth;
8594         region.extent.height = srcHeight;
8595         region.extent.depth  = (isSrc3D || isDst3D) ? srcDepth : 1;
8596 
8597         CommandBufferAccess access;
8598         if (srcImage == dstImage)
8599         {
8600             access.onImageSelfCopy(srcLevelGL, 1, region.srcSubresource.baseArrayLayer,
8601                                    region.srcSubresource.layerCount, dstLevelGL, 1,
8602                                    region.dstSubresource.baseArrayLayer,
8603                                    region.dstSubresource.layerCount, aspectFlags, srcImage);
8604         }
8605         else
8606         {
8607             access.onImageTransferRead(aspectFlags, srcImage);
8608             access.onImageTransferWrite(dstLevelGL, 1, region.dstSubresource.baseArrayLayer,
8609                                         region.dstSubresource.layerCount, aspectFlags, dstImage);
8610         }
8611 
8612         OutsideRenderPassCommandBuffer *commandBuffer;
8613         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
8614 
8615         ASSERT(srcImage->valid() && dstImage->valid());
8616         ASSERT(srcImage->getCurrentLayout() == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL ||
8617                srcImage->getCurrentLayout() == VK_IMAGE_LAYOUT_GENERAL);
8618         ASSERT(dstImage->getCurrentLayout() == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ||
8619                dstImage->getCurrentLayout() == VK_IMAGE_LAYOUT_GENERAL);
8620 
8621         commandBuffer->copyImage(srcImage->getImage(), srcImage->getCurrentLayout(),
8622                                  dstImage->getImage(), dstImage->getCurrentLayout(), 1, &region);
8623     }
8624     else if (!srcImage->getIntendedFormat().isBlock && !dstImage->getIntendedFormat().isBlock)
8625     {
8626         // The source and destination image formats may be using a fallback in the case of RGB
8627         // images.  A compute shader is used in such a case to perform the copy.
8628         UtilsVk &utilsVk = contextVk->getUtils();
8629 
8630         UtilsVk::CopyImageBitsParameters params;
8631         params.srcOffset[0]   = srcX;
8632         params.srcOffset[1]   = srcY;
8633         params.srcOffset[2]   = srcZ;
8634         params.srcLevel       = srcLevelGL;
8635         params.dstOffset[0]   = dstX;
8636         params.dstOffset[1]   = dstY;
8637         params.dstOffset[2]   = dstZ;
8638         params.dstLevel       = dstLevelGL;
8639         params.copyExtents[0] = srcWidth;
8640         params.copyExtents[1] = srcHeight;
8641         params.copyExtents[2] = srcDepth;
8642 
8643         ANGLE_TRY(utilsVk.copyImageBits(contextVk, dstImage, srcImage, params));
8644     }
8645     else
8646     {
8647         // No support for emulated compressed formats.
8648         UNIMPLEMENTED();
8649         ANGLE_VK_CHECK(contextVk, false, VK_ERROR_FEATURE_NOT_PRESENT);
8650     }
8651 
8652     return angle::Result::Continue;
8653 }
8654 
generateMipmapsWithBlit(ContextVk * contextVk,LevelIndex baseLevel,LevelIndex maxLevel)8655 angle::Result ImageHelper::generateMipmapsWithBlit(ContextVk *contextVk,
8656                                                    LevelIndex baseLevel,
8657                                                    LevelIndex maxLevel)
8658 {
8659     Renderer *renderer = contextVk->getRenderer();
8660 
8661     CommandBufferAccess access;
8662     gl::LevelIndex baseLevelGL = toGLLevel(baseLevel);
8663     access.onImageTransferWrite(baseLevelGL + 1, maxLevel.get(), 0, mLayerCount,
8664                                 VK_IMAGE_ASPECT_COLOR_BIT, this);
8665 
8666     OutsideRenderPassCommandBuffer *commandBuffer;
8667     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
8668 
8669     // We are able to use blitImage since the image format we are using supports it.
8670     int32_t mipWidth  = mExtents.width;
8671     int32_t mipHeight = mExtents.height;
8672     int32_t mipDepth  = mExtents.depth;
8673 
8674     // Manually manage the image memory barrier because it uses a lot more parameters than our
8675     // usual one.
8676     VkImageMemoryBarrier barrier            = {};
8677     barrier.sType                           = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
8678     barrier.image                           = mImage.getHandle();
8679     barrier.srcQueueFamilyIndex             = VK_QUEUE_FAMILY_IGNORED;
8680     barrier.dstQueueFamilyIndex             = VK_QUEUE_FAMILY_IGNORED;
8681     barrier.subresourceRange.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
8682     barrier.subresourceRange.baseArrayLayer = 0;
8683     barrier.subresourceRange.layerCount     = mLayerCount;
8684     barrier.subresourceRange.levelCount     = 1;
8685 
8686     const VkFilter filter =
8687         gl_vk::GetFilter(CalculateGenerateMipmapFilter(contextVk, getActualFormatID()));
8688 
8689     for (LevelIndex mipLevel(1); mipLevel <= LevelIndex(mLevelCount); ++mipLevel)
8690     {
8691         int32_t nextMipWidth  = std::max<int32_t>(1, mipWidth >> 1);
8692         int32_t nextMipHeight = std::max<int32_t>(1, mipHeight >> 1);
8693         int32_t nextMipDepth  = std::max<int32_t>(1, mipDepth >> 1);
8694 
8695         if (mipLevel > baseLevel && mipLevel <= maxLevel)
8696         {
8697             barrier.subresourceRange.baseMipLevel = mipLevel.get() - 1;
8698             barrier.oldLayout                     = getCurrentLayout();
8699             barrier.newLayout                     = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
8700             barrier.srcAccessMask                 = VK_ACCESS_TRANSFER_WRITE_BIT;
8701             barrier.dstAccessMask                 = VK_ACCESS_TRANSFER_READ_BIT;
8702 
8703             // We can do it for all layers at once.
8704             commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
8705                                         VK_PIPELINE_STAGE_TRANSFER_BIT, barrier);
8706             VkImageBlit blit                   = {};
8707             blit.srcOffsets[0]                 = {0, 0, 0};
8708             blit.srcOffsets[1]                 = {mipWidth, mipHeight, mipDepth};
8709             blit.srcSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
8710             blit.srcSubresource.mipLevel       = mipLevel.get() - 1;
8711             blit.srcSubresource.baseArrayLayer = 0;
8712             blit.srcSubresource.layerCount     = mLayerCount;
8713             blit.dstOffsets[0]                 = {0, 0, 0};
8714             blit.dstOffsets[1]                 = {nextMipWidth, nextMipHeight, nextMipDepth};
8715             blit.dstSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
8716             blit.dstSubresource.mipLevel       = mipLevel.get();
8717             blit.dstSubresource.baseArrayLayer = 0;
8718             blit.dstSubresource.layerCount     = mLayerCount;
8719 
8720             commandBuffer->blitImage(mImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, mImage,
8721                                      VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, filter);
8722         }
8723         mipWidth  = nextMipWidth;
8724         mipHeight = nextMipHeight;
8725         mipDepth  = nextMipDepth;
8726     }
8727 
8728     // Transition all mip level to the same layout so we can declare our whole image layout to one
8729     // ImageLayout. FragmentShaderReadOnly is picked here since this is the most reasonable usage
8730     // after glGenerateMipmap call.
8731     barrier.oldLayout     = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
8732     barrier.newLayout     = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
8733     barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
8734     if (baseLevel.get() > 0)
8735     {
8736         // [0:baseLevel-1] from TRANSFER_DST to SHADER_READ
8737         barrier.subresourceRange.baseMipLevel = 0;
8738         barrier.subresourceRange.levelCount   = baseLevel.get();
8739         commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
8740                                     VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, barrier);
8741     }
8742     // [maxLevel:mLevelCount-1] from TRANSFER_DST to SHADER_READ
8743     ASSERT(mLevelCount > maxLevel.get());
8744     barrier.subresourceRange.baseMipLevel = maxLevel.get();
8745     barrier.subresourceRange.levelCount   = mLevelCount - maxLevel.get();
8746     commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
8747                                 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, barrier);
8748     // [baseLevel:maxLevel-1] from TRANSFER_SRC to SHADER_READ
8749     barrier.oldLayout                     = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
8750     barrier.srcAccessMask                 = VK_ACCESS_TRANSFER_READ_BIT;
8751     barrier.subresourceRange.baseMipLevel = baseLevel.get();
8752     barrier.subresourceRange.levelCount   = maxLevel.get() - baseLevel.get();
8753     commandBuffer->imageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT,
8754                                 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, barrier);
8755 
8756     // This is just changing the internal state of the image helper so that the next call
8757     // to changeLayout will use this layout as the "oldLayout" argument.
8758     // mLastNonShaderReadOnlyLayout is used to ensure previous write are made visible to reads,
8759     // since the only write here is transfer, hence mLastNonShaderReadOnlyLayout is set to
8760     // ImageLayout::TransferDst.
8761     setCurrentImageLayout(renderer, ImageLayout::FragmentShaderReadOnly);
8762 
8763     contextVk->trackImageWithOutsideRenderPassEvent(this);
8764 
8765     return angle::Result::Continue;
8766 }
8767 
resolve(ImageHelper * dst,const VkImageResolve & region,OutsideRenderPassCommandBuffer * commandBuffer)8768 void ImageHelper::resolve(ImageHelper *dst,
8769                           const VkImageResolve &region,
8770                           OutsideRenderPassCommandBuffer *commandBuffer)
8771 {
8772     ASSERT(mCurrentLayout == ImageLayout::TransferSrc ||
8773            mCurrentLayout == ImageLayout::SharedPresent);
8774     commandBuffer->resolveImage(getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst->getImage(),
8775                                 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
8776 }
8777 
removeSingleSubresourceStagedUpdates(ContextVk * contextVk,gl::LevelIndex levelIndexGL,uint32_t layerIndex,uint32_t layerCount)8778 void ImageHelper::removeSingleSubresourceStagedUpdates(ContextVk *contextVk,
8779                                                        gl::LevelIndex levelIndexGL,
8780                                                        uint32_t layerIndex,
8781                                                        uint32_t layerCount)
8782 {
8783     mCurrentSingleClearValue.reset();
8784 
8785     // Find any staged updates for this index and remove them from the pending list.
8786     SubresourceUpdates *levelUpdates = getLevelUpdates(levelIndexGL);
8787     if (levelUpdates == nullptr)
8788     {
8789         return;
8790     }
8791 
8792     for (size_t index = 0; index < levelUpdates->size();)
8793     {
8794         auto update = levelUpdates->begin() + index;
8795         if (update->matchesLayerRange(layerIndex, layerCount))
8796         {
8797             // Update total staging buffer size
8798             mTotalStagedBufferUpdateSize -= update->updateSource == UpdateSource::Buffer
8799                                                 ? update->data.buffer.bufferHelper->getSize()
8800                                                 : 0;
8801             update->release(contextVk->getRenderer());
8802             levelUpdates->erase(update);
8803         }
8804         else
8805         {
8806             index++;
8807         }
8808     }
8809 }
8810 
removeSingleStagedClearAfterInvalidate(gl::LevelIndex levelIndexGL,uint32_t layerIndex,uint32_t layerCount)8811 void ImageHelper::removeSingleStagedClearAfterInvalidate(gl::LevelIndex levelIndexGL,
8812                                                          uint32_t layerIndex,
8813                                                          uint32_t layerCount)
8814 {
8815     // When this function is called, it's expected that there may be at most one
8816     // ClearAfterInvalidate update pending to this subresource, and that's a color clear due to
8817     // emulated channels after invalidate.  This function removes that update.
8818 
8819     SubresourceUpdates *levelUpdates = getLevelUpdates(levelIndexGL);
8820     if (levelUpdates == nullptr)
8821     {
8822         return;
8823     }
8824 
8825     for (size_t index = 0; index < levelUpdates->size(); ++index)
8826     {
8827         auto update = levelUpdates->begin() + index;
8828         if (update->updateSource == UpdateSource::ClearAfterInvalidate &&
8829             update->matchesLayerRange(layerIndex, layerCount))
8830         {
8831             // It's a clear, so doesn't need to be released.
8832             levelUpdates->erase(update);
8833             // There's only one such clear possible.
8834             return;
8835         }
8836     }
8837 }
8838 
removeStagedUpdates(ErrorContext * context,gl::LevelIndex levelGLStart,gl::LevelIndex levelGLEnd)8839 void ImageHelper::removeStagedUpdates(ErrorContext *context,
8840                                       gl::LevelIndex levelGLStart,
8841                                       gl::LevelIndex levelGLEnd)
8842 {
8843     ASSERT(validateSubresourceUpdateRefCountsConsistent());
8844 
8845     // Remove all updates to levels [start, end].
8846     for (gl::LevelIndex level = levelGLStart; level <= levelGLEnd; ++level)
8847     {
8848         SubresourceUpdates *levelUpdates = getLevelUpdates(level);
8849         if (levelUpdates == nullptr)
8850         {
8851             ASSERT(static_cast<size_t>(level.get()) >= mSubresourceUpdates.size());
8852             return;
8853         }
8854 
8855         for (SubresourceUpdate &update : *levelUpdates)
8856         {
8857             // Update total staging buffer size
8858             mTotalStagedBufferUpdateSize -= update.updateSource == UpdateSource::Buffer
8859                                                 ? update.data.buffer.bufferHelper->getSize()
8860                                                 : 0;
8861             update.release(context->getRenderer());
8862         }
8863 
8864         levelUpdates->clear();
8865     }
8866 
8867     ASSERT(validateSubresourceUpdateRefCountsConsistent());
8868 }
8869 
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)8870 angle::Result ImageHelper::stageSubresourceUpdateImpl(ContextVk *contextVk,
8871                                                       const gl::ImageIndex &index,
8872                                                       const gl::Extents &glExtents,
8873                                                       const gl::Offset &offset,
8874                                                       const gl::InternalFormat &formatInfo,
8875                                                       const gl::PixelUnpackState &unpack,
8876                                                       GLenum type,
8877                                                       const uint8_t *pixels,
8878                                                       const Format &vkFormat,
8879                                                       ImageAccess access,
8880                                                       const GLuint inputRowPitch,
8881                                                       const GLuint inputDepthPitch,
8882                                                       const GLuint inputSkipBytes,
8883                                                       ApplyImageUpdate applyUpdate,
8884                                                       bool *updateAppliedImmediatelyOut)
8885 {
8886     *updateAppliedImmediatelyOut = false;
8887 
8888     const angle::Format &storageFormat = vkFormat.getActualImageFormat(access);
8889 
8890     size_t outputRowPitch;
8891     size_t outputDepthPitch;
8892     size_t stencilAllocationSize = 0;
8893     uint32_t bufferRowLength;
8894     uint32_t bufferImageHeight;
8895     size_t allocationSize;
8896 
8897     LoadImageFunctionInfo loadFunctionInfo = vkFormat.getTextureLoadFunction(access, type);
8898     LoadImageFunction stencilLoadFunction  = nullptr;
8899 
8900     bool useComputeTransCoding = false;
8901     if (storageFormat.isBlock)
8902     {
8903         const gl::InternalFormat &storageFormatInfo = vkFormat.getInternalFormatInfo(type);
8904         GLuint rowPitch;
8905         GLuint depthPitch;
8906         GLuint totalSize;
8907 
8908         ANGLE_VK_CHECK_MATH(contextVk, storageFormatInfo.computeCompressedImageRowPitch(
8909                                            glExtents.width, &rowPitch));
8910         ANGLE_VK_CHECK_MATH(contextVk, storageFormatInfo.computeCompressedImageDepthPitch(
8911                                            glExtents.height, rowPitch, &depthPitch));
8912 
8913         ANGLE_VK_CHECK_MATH(contextVk,
8914                             storageFormatInfo.computeCompressedImageSize(glExtents, &totalSize));
8915 
8916         outputRowPitch   = rowPitch;
8917         outputDepthPitch = depthPitch;
8918         allocationSize   = totalSize;
8919 
8920         ANGLE_VK_CHECK_MATH(
8921             contextVk, storageFormatInfo.computeBufferRowLength(glExtents.width, &bufferRowLength));
8922         ANGLE_VK_CHECK_MATH(contextVk, storageFormatInfo.computeBufferImageHeight(
8923                                            glExtents.height, &bufferImageHeight));
8924 
8925         if (contextVk->getFeatures().supportsComputeTranscodeEtcToBc.enabled &&
8926             IsETCFormat(vkFormat.getIntendedFormatID()) && IsBCFormat(storageFormat.id))
8927         {
8928             useComputeTransCoding =
8929                 shouldUseComputeForTransCoding(vk::LevelIndex(index.getLevelIndex()));
8930             if (!useComputeTransCoding)
8931             {
8932                 loadFunctionInfo = GetEtcToBcTransCodingFunc(vkFormat.getIntendedFormatID());
8933             }
8934         }
8935     }
8936     else
8937     {
8938         ASSERT(storageFormat.pixelBytes != 0);
8939         const bool stencilOnly = formatInfo.sizedInternalFormat == GL_STENCIL_INDEX8;
8940 
8941         if (!stencilOnly && storageFormat.id == angle::FormatID::D24_UNORM_S8_UINT)
8942         {
8943             switch (type)
8944             {
8945                 case GL_UNSIGNED_INT_24_8:
8946                     stencilLoadFunction = angle::LoadX24S8ToS8;
8947                     break;
8948                 case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
8949                     stencilLoadFunction = angle::LoadX32S8ToS8;
8950                     break;
8951             }
8952         }
8953         if (!stencilOnly && storageFormat.id == angle::FormatID::D32_FLOAT_S8X24_UINT)
8954         {
8955             // If depth is D32FLOAT_S8, we must pack D32F tightly (no stencil) for CopyBufferToImage
8956             outputRowPitch = sizeof(float) * glExtents.width;
8957 
8958             // The generic load functions don't handle tightly packing D32FS8 to D32F & S8 so call
8959             // special case load functions.
8960             switch (type)
8961             {
8962                 case GL_UNSIGNED_INT:
8963                     loadFunctionInfo.loadFunction = angle::LoadD32ToD32F;
8964                     stencilLoadFunction           = nullptr;
8965                     break;
8966                 case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
8967                     loadFunctionInfo.loadFunction = angle::LoadD32FS8X24ToD32F;
8968                     stencilLoadFunction           = angle::LoadX32S8ToS8;
8969                     break;
8970                 case GL_UNSIGNED_INT_24_8:
8971                     loadFunctionInfo.loadFunction = angle::LoadD24S8ToD32F;
8972                     stencilLoadFunction           = angle::LoadX24S8ToS8;
8973                     break;
8974                 default:
8975                     UNREACHABLE();
8976             }
8977         }
8978         else if (!stencilOnly)
8979         {
8980             outputRowPitch = storageFormat.pixelBytes * glExtents.width;
8981         }
8982         else
8983         {
8984             // Some Vulkan implementations do not support S8_UINT, so stencil-only data is
8985             // uploaded using one of combined depth-stencil formats there. Since the uploaded
8986             // stencil data must be tightly packed, the actual storage format should be ignored
8987             // with regards to its load function and output row pitch.
8988             loadFunctionInfo.loadFunction = angle::LoadToNative<GLubyte, 1>;
8989             outputRowPitch                = glExtents.width;
8990         }
8991         outputDepthPitch = outputRowPitch * glExtents.height;
8992 
8993         bufferRowLength   = glExtents.width;
8994         bufferImageHeight = glExtents.height;
8995 
8996         allocationSize = outputDepthPitch * glExtents.depth;
8997 
8998         // Note: because the LoadImageFunctionInfo functions are limited to copying a single
8999         // component, we have to special case packed depth/stencil use and send the stencil as a
9000         // separate chunk.
9001         if (storageFormat.hasDepthAndStencilBits() && formatInfo.depthBits > 0 &&
9002             formatInfo.stencilBits > 0)
9003         {
9004             // Note: Stencil is always one byte
9005             stencilAllocationSize = glExtents.width * glExtents.height * glExtents.depth;
9006             allocationSize += stencilAllocationSize;
9007         }
9008     }
9009 
9010     const uint8_t *source = pixels + static_cast<ptrdiff_t>(inputSkipBytes);
9011 
9012     // If possible, copy the buffer to the image directly on the host, to avoid having to use a temp
9013     // image (and do a double copy).
9014     if (applyUpdate != ApplyImageUpdate::Defer && !loadFunctionInfo.requiresConversion &&
9015         inputRowPitch == outputRowPitch && inputDepthPitch == outputDepthPitch)
9016     {
9017         bool copied = false;
9018         ANGLE_TRY(updateSubresourceOnHost(contextVk, applyUpdate, index, glExtents, offset, source,
9019                                           bufferRowLength, bufferImageHeight, &copied));
9020         if (copied)
9021         {
9022             *updateAppliedImmediatelyOut = true;
9023             return angle::Result::Continue;
9024         }
9025     }
9026 
9027     std::unique_ptr<RefCounted<BufferHelper>> stagingBuffer =
9028         std::make_unique<RefCounted<BufferHelper>>();
9029     BufferHelper *currentBuffer = &stagingBuffer->get();
9030 
9031     uint8_t *stagingPointer;
9032     VkDeviceSize stagingOffset;
9033     ANGLE_TRY(contextVk->initBufferForImageCopy(currentBuffer, allocationSize,
9034                                                 MemoryCoherency::CachedNonCoherent,
9035                                                 storageFormat.id, &stagingOffset, &stagingPointer));
9036 
9037     loadFunctionInfo.loadFunction(
9038         contextVk->getImageLoadContext(), glExtents.width, glExtents.height, glExtents.depth,
9039         source, inputRowPitch, inputDepthPitch, stagingPointer, outputRowPitch, outputDepthPitch);
9040 
9041     // YUV formats need special handling.
9042     if (storageFormat.isYUV)
9043     {
9044         gl::YuvFormatInfo yuvInfo(formatInfo.internalFormat, glExtents);
9045 
9046         constexpr VkImageAspectFlagBits kPlaneAspectFlags[3] = {
9047             VK_IMAGE_ASPECT_PLANE_0_BIT, VK_IMAGE_ASPECT_PLANE_1_BIT, VK_IMAGE_ASPECT_PLANE_2_BIT};
9048 
9049         // We only support mip level 0 and layerCount of 1 for YUV formats.
9050         ASSERT(index.getLevelIndex() == 0);
9051         ASSERT(index.getLayerCount() == 1);
9052 
9053         for (uint32_t plane = 0; plane < yuvInfo.planeCount; plane++)
9054         {
9055             VkBufferImageCopy copy           = {};
9056             copy.bufferOffset                = stagingOffset + yuvInfo.planeOffset[plane];
9057             copy.bufferRowLength             = 0;
9058             copy.bufferImageHeight           = 0;
9059             copy.imageSubresource.mipLevel   = 0;
9060             copy.imageSubresource.layerCount = 1;
9061             gl_vk::GetOffset(offset, &copy.imageOffset);
9062             gl_vk::GetExtent(yuvInfo.planeExtent[plane], &copy.imageExtent);
9063             copy.imageSubresource.baseArrayLayer = 0;
9064             copy.imageSubresource.aspectMask     = kPlaneAspectFlags[plane];
9065             appendSubresourceUpdate(
9066                 gl::LevelIndex(0),
9067                 SubresourceUpdate(stagingBuffer.get(), currentBuffer, copy, storageFormat.id));
9068         }
9069 
9070         stagingBuffer.release();
9071         return angle::Result::Continue;
9072     }
9073 
9074     VkBufferImageCopy copy         = {};
9075     VkImageAspectFlags aspectFlags = GetFormatAspectFlags(storageFormat);
9076 
9077     copy.bufferOffset      = stagingOffset;
9078     copy.bufferRowLength   = bufferRowLength;
9079     copy.bufferImageHeight = bufferImageHeight;
9080 
9081     gl::LevelIndex updateLevelGL(index.getLevelIndex());
9082     copy.imageSubresource.mipLevel   = updateLevelGL.get();
9083     copy.imageSubresource.layerCount = index.getLayerCount();
9084 
9085     gl_vk::GetOffset(offset, &copy.imageOffset);
9086     gl_vk::GetExtent(glExtents, &copy.imageExtent);
9087 
9088     if (gl::IsArrayTextureType(index.getType()))
9089     {
9090         copy.imageSubresource.baseArrayLayer = offset.z;
9091         copy.imageOffset.z                   = 0;
9092         copy.imageExtent.depth               = 1;
9093     }
9094     else
9095     {
9096         copy.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
9097     }
9098 
9099     if (stencilAllocationSize > 0)
9100     {
9101         // Note: Stencil is always one byte
9102         ASSERT((aspectFlags & VK_IMAGE_ASPECT_STENCIL_BIT) != 0);
9103 
9104         // Skip over depth data.
9105         stagingPointer += outputDepthPitch * glExtents.depth;
9106         stagingOffset += outputDepthPitch * glExtents.depth;
9107 
9108         // recompute pitch for stencil data
9109         outputRowPitch   = glExtents.width;
9110         outputDepthPitch = outputRowPitch * glExtents.height;
9111 
9112         ASSERT(stencilLoadFunction != nullptr);
9113         stencilLoadFunction(contextVk->getImageLoadContext(), glExtents.width, glExtents.height,
9114                             glExtents.depth, source, inputRowPitch, inputDepthPitch, stagingPointer,
9115                             outputRowPitch, outputDepthPitch);
9116 
9117         VkBufferImageCopy stencilCopy = {};
9118 
9119         stencilCopy.bufferOffset                    = stagingOffset;
9120         stencilCopy.bufferRowLength                 = bufferRowLength;
9121         stencilCopy.bufferImageHeight               = bufferImageHeight;
9122         stencilCopy.imageSubresource.mipLevel       = copy.imageSubresource.mipLevel;
9123         stencilCopy.imageSubresource.baseArrayLayer = copy.imageSubresource.baseArrayLayer;
9124         stencilCopy.imageSubresource.layerCount     = copy.imageSubresource.layerCount;
9125         stencilCopy.imageOffset                     = copy.imageOffset;
9126         stencilCopy.imageExtent                     = copy.imageExtent;
9127         stencilCopy.imageSubresource.aspectMask     = VK_IMAGE_ASPECT_STENCIL_BIT;
9128         appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(stagingBuffer.get(), currentBuffer,
9129                                                                  stencilCopy, storageFormat.id));
9130 
9131         aspectFlags &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
9132     }
9133 
9134     if (HasBothDepthAndStencilAspects(aspectFlags))
9135     {
9136         // We still have both depth and stencil aspect bits set. That means we have a destination
9137         // buffer that is packed depth stencil and that the application is only loading one aspect.
9138         // Figure out which aspect the user is touching and remove the unused aspect bit.
9139         if (formatInfo.stencilBits > 0)
9140         {
9141             aspectFlags &= ~VK_IMAGE_ASPECT_DEPTH_BIT;
9142         }
9143         else
9144         {
9145             aspectFlags &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
9146         }
9147     }
9148 
9149     if (aspectFlags)
9150     {
9151         copy.imageSubresource.aspectMask = aspectFlags;
9152         appendSubresourceUpdate(
9153             updateLevelGL, SubresourceUpdate(stagingBuffer.get(), currentBuffer, copy,
9154                                              useComputeTransCoding ? vkFormat.getIntendedFormatID()
9155                                                                    : storageFormat.id));
9156         pruneSupersededUpdatesForLevel(contextVk, updateLevelGL, PruneReason::MemoryOptimization);
9157     }
9158 
9159     stagingBuffer.release();
9160     return angle::Result::Continue;
9161 }
9162 
updateSubresourceOnHost(ErrorContext * 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)9163 angle::Result ImageHelper::updateSubresourceOnHost(ErrorContext *context,
9164                                                    ApplyImageUpdate applyUpdate,
9165                                                    const gl::ImageIndex &index,
9166                                                    const gl::Extents &glExtents,
9167                                                    const gl::Offset &offset,
9168                                                    const uint8_t *source,
9169                                                    const GLuint memoryRowLength,
9170                                                    const GLuint memoryImageHeight,
9171                                                    bool *copiedOut)
9172 {
9173     // If the image is not set up for host copy, it can't be done.
9174     if (!valid() || (mUsage & VK_IMAGE_USAGE_HOST_TRANSFER_BIT_EXT) == 0)
9175     {
9176         return angle::Result::Continue;
9177     }
9178 
9179     Renderer *renderer = context->getRenderer();
9180     const VkPhysicalDeviceHostImageCopyPropertiesEXT &hostImageCopyProperties =
9181         renderer->getPhysicalDeviceHostImageCopyProperties();
9182 
9183     // The image should be unused by the GPU.
9184     if (!renderer->hasResourceUseFinished(getResourceUse()))
9185     {
9186         ANGLE_TRY(renderer->checkCompletedCommandsAndCleanup(context));
9187         if (!renderer->hasResourceUseFinished(getResourceUse()))
9188         {
9189             return angle::Result::Continue;
9190         }
9191     }
9192 
9193     // The image should not have any pending updates to this subresource.
9194     //
9195     // TODO: if there are any pending updates, see if they can be pruned given the incoming update.
9196     // This would most likely be the case where a clear is automatically staged for robustness or
9197     // other reasons, which would now be superseded by the data upload. http://anglebug.com/42266771
9198     const gl::LevelIndex updateLevelGL(index.getLevelIndex());
9199     const uint32_t layerIndex = index.hasLayer() ? index.getLayerIndex() : 0;
9200     const uint32_t layerCount = index.getLayerCount();
9201     if (hasStagedUpdatesForSubresource(updateLevelGL, layerIndex, layerCount))
9202     {
9203         return angle::Result::Continue;
9204     }
9205 
9206     // The image should be in a layout this is copiable.  If UNDEFINED, it can be transitioned to a
9207     // layout that is copyable.
9208     const VkImageAspectFlags aspectMask = getAspectFlags();
9209     if (mCurrentLayout == ImageLayout::Undefined)
9210     {
9211         VkHostImageLayoutTransitionInfoEXT transition = {};
9212         transition.sType     = VK_STRUCTURE_TYPE_HOST_IMAGE_LAYOUT_TRANSITION_INFO_EXT;
9213         transition.image     = mImage.getHandle();
9214         transition.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
9215         // The GENERAL layout is always guaranteed to be in
9216         // VkPhysicalDeviceHostImageCopyPropertiesEXT::pCopyDstLayouts
9217         transition.newLayout                       = VK_IMAGE_LAYOUT_GENERAL;
9218         transition.subresourceRange.aspectMask     = aspectMask;
9219         transition.subresourceRange.baseMipLevel   = 0;
9220         transition.subresourceRange.levelCount     = mLevelCount;
9221         transition.subresourceRange.baseArrayLayer = 0;
9222         transition.subresourceRange.layerCount     = mLayerCount;
9223 
9224         ANGLE_VK_TRY(context, vkTransitionImageLayoutEXT(renderer->getDevice(), 1, &transition));
9225         mCurrentLayout = ImageLayout::HostCopy;
9226     }
9227     else if (mCurrentLayout != ImageLayout::HostCopy &&
9228              !IsAnyLayout(getCurrentLayout(), hostImageCopyProperties.pCopyDstLayouts,
9229                           hostImageCopyProperties.copyDstLayoutCount))
9230     {
9231         return angle::Result::Continue;
9232     }
9233 
9234     const bool isArray            = gl::IsArrayTextureType(index.getType());
9235     const uint32_t baseArrayLayer = isArray ? offset.z : layerIndex;
9236 
9237     onWrite(updateLevelGL, 1, baseArrayLayer, layerCount, aspectMask);
9238     *copiedOut = true;
9239 
9240     // Perform the copy without holding the lock.  This is important for applications that perform
9241     // the copy on a separate thread, and doing all the work while holding the lock effectively
9242     // destroys all parallelism.  Note that the texture may not be used by the other thread without
9243     // appropriate synchronization (such as through glFenceSync), and because the copy is happening
9244     // in this call (just without holding the lock), the sync function won't be called until the
9245     // copy is done.
9246     auto doCopy = [context, image = mImage.getHandle(), source, memoryRowLength, memoryImageHeight,
9247                    aspectMask, levelVk = toVkLevel(updateLevelGL), isArray, baseArrayLayer,
9248                    layerCount, offset, glExtents, layout = getCurrentLayout()](void *resultOut) {
9249         ANGLE_TRACE_EVENT0("gpu.angle", "Upload image data on host");
9250         ANGLE_UNUSED_VARIABLE(resultOut);
9251 
9252         VkMemoryToImageCopyEXT copyRegion          = {};
9253         copyRegion.sType                           = VK_STRUCTURE_TYPE_MEMORY_TO_IMAGE_COPY_EXT;
9254         copyRegion.pHostPointer                    = source;
9255         copyRegion.memoryRowLength                 = memoryRowLength;
9256         copyRegion.memoryImageHeight               = memoryImageHeight;
9257         copyRegion.imageSubresource.aspectMask     = aspectMask;
9258         copyRegion.imageSubresource.mipLevel       = levelVk.get();
9259         copyRegion.imageSubresource.baseArrayLayer = baseArrayLayer;
9260         copyRegion.imageSubresource.layerCount     = layerCount;
9261         gl_vk::GetOffset(offset, &copyRegion.imageOffset);
9262         gl_vk::GetExtent(glExtents, &copyRegion.imageExtent);
9263 
9264         if (isArray)
9265         {
9266             copyRegion.imageOffset.z     = 0;
9267             copyRegion.imageExtent.depth = 1;
9268         }
9269 
9270         VkCopyMemoryToImageInfoEXT copyInfo = {};
9271         copyInfo.sType                      = VK_STRUCTURE_TYPE_COPY_MEMORY_TO_IMAGE_INFO_EXT;
9272         copyInfo.dstImage                   = image;
9273         copyInfo.dstImageLayout             = layout;
9274         copyInfo.regionCount                = 1;
9275         copyInfo.pRegions                   = &copyRegion;
9276 
9277         VkResult result = vkCopyMemoryToImageEXT(context->getDevice(), &copyInfo);
9278         if (result != VK_SUCCESS)
9279         {
9280             context->handleError(result, __FILE__, ANGLE_FUNCTION, __LINE__);
9281         }
9282     };
9283 
9284     switch (applyUpdate)
9285     {
9286         // If possible, perform the copy in an unlocked tail call.  Then the other threads of the
9287         // application are free to draw.
9288         case ApplyImageUpdate::ImmediatelyInUnlockedTailCall:
9289             egl::Display::GetCurrentThreadUnlockedTailCall()->add(doCopy);
9290             break;
9291 
9292         // In some cases, the copy cannot be delayed.  For example because the contents are
9293         // immediately needed (such as when the generate mipmap hint is set), or because unlocked
9294         // tail calls are not allowed (this is the case with incomplete textures which are lazily
9295         // created at draw, but unlocked tail calls are avoided on draw calls due to overhead).
9296         case ApplyImageUpdate::Immediately:
9297             doCopy(nullptr);
9298             break;
9299 
9300         default:
9301             UNREACHABLE();
9302             doCopy(nullptr);
9303     }
9304 
9305     return angle::Result::Continue;
9306 }
9307 
reformatStagedBufferUpdates(ContextVk * contextVk,angle::FormatID srcFormatID,angle::FormatID dstFormatID)9308 angle::Result ImageHelper::reformatStagedBufferUpdates(ContextVk *contextVk,
9309                                                        angle::FormatID srcFormatID,
9310                                                        angle::FormatID dstFormatID)
9311 {
9312     const angle::Format &srcFormat = angle::Format::Get(srcFormatID);
9313     const angle::Format &dstFormat = angle::Format::Get(dstFormatID);
9314     const gl::InternalFormat &dstFormatInfo =
9315         gl::GetSizedInternalFormatInfo(dstFormat.glInternalFormat);
9316 
9317     for (SubresourceUpdates &levelUpdates : mSubresourceUpdates)
9318     {
9319         for (SubresourceUpdate &update : levelUpdates)
9320         {
9321             // Right now whenever we stage update from a source image, the formats always match.
9322             ASSERT(valid() || update.updateSource != UpdateSource::Image ||
9323                    update.data.image.formatID == srcFormatID);
9324 
9325             if (update.updateSource == UpdateSource::Buffer &&
9326                 update.data.buffer.formatID == srcFormatID)
9327             {
9328                 const VkBufferImageCopy &copy = update.data.buffer.copyRegion;
9329 
9330                 // Source and dst data are tightly packed
9331                 GLuint srcDataRowPitch = copy.imageExtent.width * srcFormat.pixelBytes;
9332                 GLuint dstDataRowPitch = copy.imageExtent.width * dstFormat.pixelBytes;
9333 
9334                 GLuint srcDataDepthPitch = srcDataRowPitch * copy.imageExtent.height;
9335                 GLuint dstDataDepthPitch = dstDataRowPitch * copy.imageExtent.height;
9336 
9337                 // Retrieve source buffer
9338                 vk::BufferHelper *srcBuffer = update.data.buffer.bufferHelper;
9339                 ASSERT(srcBuffer->isMapped());
9340                 // The bufferOffset is relative to the buffer block. We have to use the buffer
9341                 // block's memory pointer to get the source data pointer.
9342                 uint8_t *srcData = srcBuffer->getBlockMemory() + copy.bufferOffset;
9343 
9344                 // Allocate memory with dstFormat
9345                 std::unique_ptr<RefCounted<BufferHelper>> stagingBuffer =
9346                     std::make_unique<RefCounted<BufferHelper>>();
9347                 BufferHelper *dstBuffer = &stagingBuffer->get();
9348 
9349                 uint8_t *dstData;
9350                 VkDeviceSize dstBufferOffset;
9351                 size_t dstBufferSize = dstDataDepthPitch * copy.imageExtent.depth;
9352                 ANGLE_TRY(contextVk->initBufferForImageCopy(
9353                     dstBuffer, dstBufferSize, MemoryCoherency::CachedNonCoherent, dstFormatID,
9354                     &dstBufferOffset, &dstData));
9355 
9356                 rx::PixelReadFunction pixelReadFunction   = srcFormat.pixelReadFunction;
9357                 rx::PixelWriteFunction pixelWriteFunction = dstFormat.pixelWriteFunction;
9358 
9359                 CopyImageCHROMIUM(srcData, srcDataRowPitch, srcFormat.pixelBytes, srcDataDepthPitch,
9360                                   pixelReadFunction, dstData, dstDataRowPitch, dstFormat.pixelBytes,
9361                                   dstDataDepthPitch, pixelWriteFunction, dstFormatInfo.format,
9362                                   dstFormatInfo.componentType, copy.imageExtent.width,
9363                                   copy.imageExtent.height, copy.imageExtent.depth, false, false,
9364                                   false);
9365 
9366                 // Replace srcBuffer with dstBuffer
9367                 update.data.buffer.bufferHelper            = dstBuffer;
9368                 update.data.buffer.formatID                = dstFormatID;
9369                 update.data.buffer.copyRegion.bufferOffset = dstBufferOffset;
9370 
9371                 // Update total staging buffer size
9372                 mTotalStagedBufferUpdateSize -= srcBuffer->getSize();
9373                 mTotalStagedBufferUpdateSize += dstBuffer->getSize();
9374 
9375                 // Let update structure owns the staging buffer
9376                 if (update.refCounted.buffer)
9377                 {
9378                     update.refCounted.buffer->releaseRef();
9379                     if (!update.refCounted.buffer->isReferenced())
9380                     {
9381                         update.refCounted.buffer->get().release(contextVk);
9382                         SafeDelete(update.refCounted.buffer);
9383                     }
9384                 }
9385                 update.refCounted.buffer = stagingBuffer.release();
9386                 update.refCounted.buffer->addRef();
9387             }
9388         }
9389     }
9390 
9391     return angle::Result::Continue;
9392 }
9393 
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)9394 angle::Result ImageHelper::calculateBufferInfo(ContextVk *contextVk,
9395                                                const gl::Extents &glExtents,
9396                                                const gl::InternalFormat &formatInfo,
9397                                                const gl::PixelUnpackState &unpack,
9398                                                GLenum type,
9399                                                bool is3D,
9400                                                GLuint *inputRowPitch,
9401                                                GLuint *inputDepthPitch,
9402                                                GLuint *inputSkipBytes)
9403 {
9404     // YUV formats need special handling.
9405     if (gl::IsYuvFormat(formatInfo.internalFormat))
9406     {
9407         gl::YuvFormatInfo yuvInfo(formatInfo.internalFormat, glExtents);
9408 
9409         // row pitch = Y plane row pitch
9410         *inputRowPitch = yuvInfo.planePitch[0];
9411         // depth pitch = Y plane size + chroma plane size
9412         *inputDepthPitch = yuvInfo.planeSize[0] + yuvInfo.planeSize[1] + yuvInfo.planeSize[2];
9413         *inputSkipBytes  = 0;
9414 
9415         return angle::Result::Continue;
9416     }
9417 
9418     ANGLE_VK_CHECK_MATH(contextVk,
9419                         formatInfo.computeRowPitch(type, glExtents.width, unpack.alignment,
9420                                                    unpack.rowLength, inputRowPitch));
9421 
9422     ANGLE_VK_CHECK_MATH(contextVk,
9423                         formatInfo.computeDepthPitch(glExtents.height, unpack.imageHeight,
9424                                                      *inputRowPitch, inputDepthPitch));
9425 
9426     ANGLE_VK_CHECK_MATH(
9427         contextVk, formatInfo.computeSkipBytes(type, *inputRowPitch, *inputDepthPitch, unpack, is3D,
9428                                                inputSkipBytes));
9429 
9430     return angle::Result::Continue;
9431 }
9432 
onRenderPassAttach(const QueueSerial & queueSerial)9433 void ImageHelper::onRenderPassAttach(const QueueSerial &queueSerial)
9434 {
9435     setQueueSerial(queueSerial);
9436     // updatePipelineStageAccessHistory uses mCurrentLayout which we dont know yet (deferred until
9437     // endRenderPass time). So update it directly since we know attachment will be accessed by
9438     // fragment and attachment stages.
9439     mPipelineStageAccessHeuristic.onAccess(PipelineStageGroup::FragmentOnly);
9440 }
9441 
onWrite(gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags)9442 void ImageHelper::onWrite(gl::LevelIndex levelStart,
9443                           uint32_t levelCount,
9444                           uint32_t layerStart,
9445                           uint32_t layerCount,
9446                           VkImageAspectFlags aspectFlags)
9447 {
9448     mCurrentSingleClearValue.reset();
9449 
9450     // Mark contents of the given subresource as defined.
9451     setContentDefined(toVkLevel(levelStart), levelCount, layerStart, layerCount, aspectFlags);
9452 
9453     setSubresourcesWrittenSinceBarrier(levelStart, levelCount, layerStart, layerCount);
9454 }
9455 
hasSubresourceDefinedContent(gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount) const9456 bool ImageHelper::hasSubresourceDefinedContent(gl::LevelIndex level,
9457                                                uint32_t layerIndex,
9458                                                uint32_t layerCount) const
9459 {
9460     if (layerIndex >= kMaxContentDefinedLayerCount)
9461     {
9462         return true;
9463     }
9464 
9465     uint8_t layerRangeBits =
9466         GetContentDefinedLayerRangeBits(layerIndex, layerCount, kMaxContentDefinedLayerCount);
9467     return (getLevelContentDefined(toVkLevel(level)) & LevelContentDefinedMask(layerRangeBits))
9468         .any();
9469 }
9470 
hasSubresourceDefinedStencilContent(gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount) const9471 bool ImageHelper::hasSubresourceDefinedStencilContent(gl::LevelIndex level,
9472                                                       uint32_t layerIndex,
9473                                                       uint32_t layerCount) const
9474 {
9475     if (layerIndex >= kMaxContentDefinedLayerCount)
9476     {
9477         return true;
9478     }
9479 
9480     uint8_t layerRangeBits =
9481         GetContentDefinedLayerRangeBits(layerIndex, layerCount, kMaxContentDefinedLayerCount);
9482     return (getLevelStencilContentDefined(toVkLevel(level)) &
9483             LevelContentDefinedMask(layerRangeBits))
9484         .any();
9485 }
9486 
invalidateEntireLevelContent(vk::ErrorContext * context,gl::LevelIndex level)9487 void ImageHelper::invalidateEntireLevelContent(vk::ErrorContext *context, gl::LevelIndex level)
9488 {
9489     invalidateSubresourceContentImpl(
9490         context, level, 0, mLayerCount,
9491         static_cast<VkImageAspectFlagBits>(getAspectFlags() & ~VK_IMAGE_ASPECT_STENCIL_BIT),
9492         &getLevelContentDefined(toVkLevel(level)), nullptr, nullptr);
9493 }
9494 
invalidateSubresourceContent(ContextVk * contextVk,gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount,bool * preferToKeepContentsDefinedOut)9495 void ImageHelper::invalidateSubresourceContent(ContextVk *contextVk,
9496                                                gl::LevelIndex level,
9497                                                uint32_t layerIndex,
9498                                                uint32_t layerCount,
9499                                                bool *preferToKeepContentsDefinedOut)
9500 {
9501     const VkImageAspectFlagBits aspect =
9502         static_cast<VkImageAspectFlagBits>(getAspectFlags() & ~VK_IMAGE_ASPECT_STENCIL_BIT);
9503     bool layerLimitReached = false;
9504     invalidateSubresourceContentImpl(contextVk, level, layerIndex, layerCount, aspect,
9505                                      &getLevelContentDefined(toVkLevel(level)),
9506                                      preferToKeepContentsDefinedOut, &layerLimitReached);
9507     if (layerLimitReached)
9508     {
9509         const char *aspectName = (aspect == VK_IMAGE_ASPECT_DEPTH_BIT ? "depth" : "color");
9510         ANGLE_VK_PERF_WARNING(
9511             contextVk, GL_DEBUG_SEVERITY_LOW,
9512             "glInvalidateFramebuffer (%s) ineffective on attachments with layer >= 8", aspectName);
9513     }
9514 }
9515 
invalidateEntireLevelStencilContent(vk::ErrorContext * context,gl::LevelIndex level)9516 void ImageHelper::invalidateEntireLevelStencilContent(vk::ErrorContext *context,
9517                                                       gl::LevelIndex level)
9518 {
9519     invalidateSubresourceContentImpl(context, level, 0, mLayerCount, VK_IMAGE_ASPECT_STENCIL_BIT,
9520                                      &getLevelStencilContentDefined(toVkLevel(level)), nullptr,
9521                                      nullptr);
9522 }
9523 
invalidateSubresourceStencilContent(ContextVk * contextVk,gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount,bool * preferToKeepContentsDefinedOut)9524 void ImageHelper::invalidateSubresourceStencilContent(ContextVk *contextVk,
9525                                                       gl::LevelIndex level,
9526                                                       uint32_t layerIndex,
9527                                                       uint32_t layerCount,
9528                                                       bool *preferToKeepContentsDefinedOut)
9529 {
9530     bool layerLimitReached = false;
9531     invalidateSubresourceContentImpl(contextVk, level, layerIndex, layerCount,
9532                                      VK_IMAGE_ASPECT_STENCIL_BIT,
9533                                      &getLevelStencilContentDefined(toVkLevel(level)),
9534                                      preferToKeepContentsDefinedOut, &layerLimitReached);
9535     if (layerLimitReached)
9536     {
9537         ANGLE_VK_PERF_WARNING(
9538             contextVk, GL_DEBUG_SEVERITY_LOW,
9539             "glInvalidateFramebuffer (stencil) ineffective on attachments with layer >= 8");
9540     }
9541 }
9542 
invalidateSubresourceContentImpl(vk::ErrorContext * context,gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount,VkImageAspectFlagBits aspect,LevelContentDefinedMask * contentDefinedMask,bool * preferToKeepContentsDefinedOut,bool * layerLimitReachedOut)9543 void ImageHelper::invalidateSubresourceContentImpl(vk::ErrorContext *context,
9544                                                    gl::LevelIndex level,
9545                                                    uint32_t layerIndex,
9546                                                    uint32_t layerCount,
9547                                                    VkImageAspectFlagBits aspect,
9548                                                    LevelContentDefinedMask *contentDefinedMask,
9549                                                    bool *preferToKeepContentsDefinedOut,
9550                                                    bool *layerLimitReachedOut)
9551 {
9552     // If the aspect being invalidated doesn't exist, skip invalidation altogether.
9553     if ((getAspectFlags() & aspect) == 0)
9554     {
9555         if (preferToKeepContentsDefinedOut)
9556         {
9557             // Let the caller know that this invalidate request was ignored.
9558             *preferToKeepContentsDefinedOut = true;
9559         }
9560         return;
9561     }
9562 
9563     // If the color format is emulated and has extra channels, those channels need to stay cleared.
9564     // On some devices, it's cheaper to skip invalidating the framebuffer attachment, while on
9565     // others it's cheaper to invalidate but then re-clear the image.
9566     //
9567     // For depth/stencil formats, each channel is separately invalidated, so the invalidate is
9568     // simply skipped for the emulated channel on all devices.
9569     const bool hasEmulatedChannels = hasEmulatedImageChannels();
9570     bool skip                      = false;
9571     switch (aspect)
9572     {
9573         case VK_IMAGE_ASPECT_DEPTH_BIT:
9574             skip = hasEmulatedDepthChannel();
9575             break;
9576         case VK_IMAGE_ASPECT_STENCIL_BIT:
9577             skip = hasEmulatedStencilChannel();
9578             break;
9579         case VK_IMAGE_ASPECT_COLOR_BIT:
9580             skip = hasEmulatedChannels &&
9581                    context->getFeatures().preferSkippingInvalidateForEmulatedFormats.enabled;
9582             break;
9583         default:
9584             UNREACHABLE();
9585             skip = true;
9586     }
9587 
9588     if (preferToKeepContentsDefinedOut)
9589     {
9590         *preferToKeepContentsDefinedOut = skip;
9591     }
9592     if (skip)
9593     {
9594         return;
9595     }
9596 
9597     if (layerIndex >= kMaxContentDefinedLayerCount)
9598     {
9599         ASSERT(layerLimitReachedOut != nullptr);
9600         *layerLimitReachedOut = true;
9601         return;
9602     }
9603 
9604     uint8_t layerRangeBits =
9605         GetContentDefinedLayerRangeBits(layerIndex, layerCount, kMaxContentDefinedLayerCount);
9606     *contentDefinedMask &= static_cast<uint8_t>(~layerRangeBits);
9607 
9608     // If there are emulated channels, stage a clear to make sure those channels continue to contain
9609     // valid values.
9610     if (hasEmulatedChannels && aspect == VK_IMAGE_ASPECT_COLOR_BIT)
9611     {
9612         VkClearValue clearValue;
9613         clearValue.color = kEmulatedInitColorValue;
9614 
9615         prependSubresourceUpdate(
9616             level, SubresourceUpdate(aspect, clearValue, level, layerIndex, layerCount));
9617         mSubresourceUpdates[level.get()].front().updateSource = UpdateSource::ClearAfterInvalidate;
9618     }
9619 }
9620 
restoreSubresourceContent(gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount)9621 void ImageHelper::restoreSubresourceContent(gl::LevelIndex level,
9622                                             uint32_t layerIndex,
9623                                             uint32_t layerCount)
9624 {
9625     restoreSubresourceContentImpl(
9626         level, layerIndex, layerCount,
9627         static_cast<VkImageAspectFlagBits>(getAspectFlags() & ~VK_IMAGE_ASPECT_STENCIL_BIT),
9628         &getLevelContentDefined(toVkLevel(level)));
9629 }
9630 
restoreSubresourceStencilContent(gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount)9631 void ImageHelper::restoreSubresourceStencilContent(gl::LevelIndex level,
9632                                                    uint32_t layerIndex,
9633                                                    uint32_t layerCount)
9634 {
9635     restoreSubresourceContentImpl(level, layerIndex, layerCount, VK_IMAGE_ASPECT_STENCIL_BIT,
9636                                   &getLevelStencilContentDefined(toVkLevel(level)));
9637 }
9638 
restoreSubresourceContentImpl(gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount,VkImageAspectFlagBits aspect,LevelContentDefinedMask * contentDefinedMask)9639 void ImageHelper::restoreSubresourceContentImpl(gl::LevelIndex level,
9640                                                 uint32_t layerIndex,
9641                                                 uint32_t layerCount,
9642                                                 VkImageAspectFlagBits aspect,
9643                                                 LevelContentDefinedMask *contentDefinedMask)
9644 {
9645     if (layerIndex >= kMaxContentDefinedLayerCount)
9646     {
9647         return;
9648     }
9649 
9650     uint8_t layerRangeBits =
9651         GetContentDefinedLayerRangeBits(layerIndex, layerCount, kMaxContentDefinedLayerCount);
9652 
9653     switch (aspect)
9654     {
9655         case VK_IMAGE_ASPECT_DEPTH_BIT:
9656             // Emulated depth channel should never have been marked invalid, so it can retain its
9657             // cleared value.
9658             ASSERT(!hasEmulatedDepthChannel() ||
9659                    (contentDefinedMask->bits() & layerRangeBits) == layerRangeBits);
9660             break;
9661         case VK_IMAGE_ASPECT_STENCIL_BIT:
9662             // Emulated stencil channel should never have been marked invalid, so it can retain its
9663             // cleared value.
9664             ASSERT(!hasEmulatedStencilChannel() ||
9665                    (contentDefinedMask->bits() & layerRangeBits) == layerRangeBits);
9666             break;
9667         case VK_IMAGE_ASPECT_COLOR_BIT:
9668         {
9669             // This function is called on attachments during a render pass when it's determined that
9670             // they should no longer be considered invalidated.  For an attachment with emulated
9671             // format that has extra channels, invalidateSubresourceContentImpl may have proactively
9672             // inserted a clear so that the extra channels continue to have defined values.
9673             // |FramebufferVk::invalidateImpl| closes the render pass right away however in that
9674             // case, so it should be impossible for the contents of such formats to need to be
9675             // restored.
9676             const bool hasClearAfterInvalidateUpdate =
9677                 getLevelUpdates(level) != nullptr && getLevelUpdates(level)->size() != 0 &&
9678                 getLevelUpdates(level)->at(0).updateSource == UpdateSource::ClearAfterInvalidate;
9679             ASSERT(!hasEmulatedImageChannels() || !hasClearAfterInvalidateUpdate);
9680 
9681             break;
9682         }
9683         default:
9684             UNREACHABLE();
9685             break;
9686     }
9687 
9688     // Additionally, as the resource has been rewritten to in the render pass, its no longer cleared
9689     // to the cached value.
9690     mCurrentSingleClearValue.reset();
9691 
9692     *contentDefinedMask |= layerRangeBits;
9693 }
9694 
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)9695 angle::Result ImageHelper::stagePartialClear(ContextVk *contextVk,
9696                                              const gl::Box &clearArea,
9697                                              const ClearTextureMode clearMode,
9698                                              gl::TextureType textureType,
9699                                              uint32_t levelIndex,
9700                                              uint32_t layerIndex,
9701                                              uint32_t layerCount,
9702                                              GLenum type,
9703                                              const gl::InternalFormat &formatInfo,
9704                                              const Format &vkFormat,
9705                                              ImageAccess access,
9706                                              const uint8_t *data)
9707 {
9708     // If the input data pointer is null, the texture is filled with zeros.
9709     const angle::Format &intendedFormat = vkFormat.getIntendedFormat();
9710     const angle::Format &actualFormat   = vkFormat.getActualImageFormat(access);
9711     auto intendedPixelSize              = static_cast<uint32_t>(intendedFormat.pixelBytes);
9712     auto actualPixelSize                = static_cast<uint32_t>(actualFormat.pixelBytes);
9713 
9714     uint8_t intendedData[16] = {0};
9715     if (data != nullptr)
9716     {
9717         memcpy(intendedData, data, intendedPixelSize);
9718     }
9719 
9720     // The appropriate loading function is used to take the original value as a single pixel and
9721     // convert it into the format actually used for this image.
9722     std::vector<uint8_t> actualData(actualPixelSize, 0);
9723     LoadImageFunctionInfo loadFunctionInfo = vkFormat.getTextureLoadFunction(access, type);
9724 
9725     bool stencilOnly = formatInfo.sizedInternalFormat == GL_STENCIL_INDEX8;
9726     if (stencilOnly)
9727     {
9728         // Some Vulkan implementations do not support S8_UINT, so stencil-only data is
9729         // uploaded using one of combined depth-stencil formats there. Since the uploaded
9730         // stencil data must be tightly packed, the actual storage format should be ignored
9731         // with regards to its load function and output row pitch.
9732         loadFunctionInfo.loadFunction = angle::LoadToNative<GLubyte, 1>;
9733     }
9734 
9735     loadFunctionInfo.loadFunction(contextVk->getImageLoadContext(), 1, 1, 1, intendedData, 1, 1,
9736                                   actualData.data(), 1, 1);
9737 
9738     // VkClearValue is used for renderable images.
9739     VkClearValue clearValue = {};
9740     if (formatInfo.isDepthOrStencil())
9741     {
9742         GetVkClearDepthStencilValueFromBytes(intendedData, intendedFormat, &clearValue);
9743     }
9744     else
9745     {
9746         GetVkClearColorValueFromBytes(actualData.data(), actualFormat, &clearValue);
9747     }
9748 
9749     // Stage a ClearPartial update.
9750     VkImageAspectFlags aspectFlags = 0;
9751     if (!formatInfo.isDepthOrStencil())
9752     {
9753         aspectFlags |= VK_IMAGE_ASPECT_COLOR_BIT;
9754     }
9755     else
9756     {
9757         aspectFlags |= formatInfo.depthBits > 0 ? VK_IMAGE_ASPECT_DEPTH_BIT : 0;
9758         aspectFlags |= formatInfo.stencilBits > 0 ? VK_IMAGE_ASPECT_STENCIL_BIT : 0;
9759     }
9760 
9761     if (clearMode == ClearTextureMode::FullClear)
9762     {
9763         bool useLayerAsDepth = textureType == gl::TextureType::CubeMap ||
9764                                textureType == gl::TextureType::CubeMapArray ||
9765                                textureType == gl::TextureType::_2DArray ||
9766                                textureType == gl::TextureType::_2DMultisampleArray;
9767         const gl::ImageIndex index = gl::ImageIndex::MakeFromType(
9768             textureType, levelIndex, 0, useLayerAsDepth ? clearArea.depth : 1);
9769 
9770         appendSubresourceUpdate(gl::LevelIndex(levelIndex),
9771                                 SubresourceUpdate(aspectFlags, clearValue, index));
9772     }
9773     else
9774     {
9775         appendSubresourceUpdate(gl::LevelIndex(levelIndex),
9776                                 SubresourceUpdate(aspectFlags, clearValue, textureType, levelIndex,
9777                                                   layerIndex, layerCount, clearArea));
9778     }
9779     return angle::Result::Continue;
9780 }
9781 
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)9782 angle::Result ImageHelper::stageSubresourceUpdate(ContextVk *contextVk,
9783                                                   const gl::ImageIndex &index,
9784                                                   const gl::Extents &glExtents,
9785                                                   const gl::Offset &offset,
9786                                                   const gl::InternalFormat &formatInfo,
9787                                                   const gl::PixelUnpackState &unpack,
9788                                                   GLenum type,
9789                                                   const uint8_t *pixels,
9790                                                   const Format &vkFormat,
9791                                                   ImageAccess access,
9792                                                   ApplyImageUpdate applyUpdate,
9793                                                   bool *updateAppliedImmediatelyOut)
9794 {
9795     GLuint inputRowPitch   = 0;
9796     GLuint inputDepthPitch = 0;
9797     GLuint inputSkipBytes  = 0;
9798     ANGLE_TRY(calculateBufferInfo(contextVk, glExtents, formatInfo, unpack, type, index.usesTex3D(),
9799                                   &inputRowPitch, &inputDepthPitch, &inputSkipBytes));
9800 
9801     ANGLE_TRY(stageSubresourceUpdateImpl(
9802         contextVk, index, glExtents, offset, formatInfo, unpack, type, pixels, vkFormat, access,
9803         inputRowPitch, inputDepthPitch, inputSkipBytes, applyUpdate, updateAppliedImmediatelyOut));
9804 
9805     return angle::Result::Continue;
9806 }
9807 
stageSubresourceUpdateAndGetData(ContextVk * contextVk,size_t allocationSize,const gl::ImageIndex & imageIndex,const gl::Extents & glExtents,const gl::Offset & offset,uint8_t ** dstData,angle::FormatID formatID)9808 angle::Result ImageHelper::stageSubresourceUpdateAndGetData(ContextVk *contextVk,
9809                                                             size_t allocationSize,
9810                                                             const gl::ImageIndex &imageIndex,
9811                                                             const gl::Extents &glExtents,
9812                                                             const gl::Offset &offset,
9813                                                             uint8_t **dstData,
9814                                                             angle::FormatID formatID)
9815 {
9816     std::unique_ptr<RefCounted<BufferHelper>> stagingBuffer =
9817         std::make_unique<RefCounted<BufferHelper>>();
9818     BufferHelper *currentBuffer = &stagingBuffer->get();
9819 
9820     VkDeviceSize stagingOffset;
9821     ANGLE_TRY(contextVk->initBufferForImageCopy(currentBuffer, allocationSize,
9822                                                 MemoryCoherency::CachedNonCoherent, formatID,
9823                                                 &stagingOffset, dstData));
9824 
9825     gl::LevelIndex updateLevelGL(imageIndex.getLevelIndex());
9826 
9827     VkBufferImageCopy copy               = {};
9828     copy.bufferOffset                    = stagingOffset;
9829     copy.bufferRowLength                 = glExtents.width;
9830     copy.bufferImageHeight               = glExtents.height;
9831     copy.imageSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
9832     copy.imageSubresource.mipLevel       = updateLevelGL.get();
9833     copy.imageSubresource.baseArrayLayer = imageIndex.hasLayer() ? imageIndex.getLayerIndex() : 0;
9834     copy.imageSubresource.layerCount     = imageIndex.getLayerCount();
9835 
9836     // Note: Only support color now
9837     ASSERT((mActualFormatID == angle::FormatID::NONE) ||
9838            (getAspectFlags() == VK_IMAGE_ASPECT_COLOR_BIT));
9839 
9840     gl_vk::GetOffset(offset, &copy.imageOffset);
9841     gl_vk::GetExtent(glExtents, &copy.imageExtent);
9842 
9843     appendSubresourceUpdate(
9844         updateLevelGL, SubresourceUpdate(stagingBuffer.release(), currentBuffer, copy, formatID));
9845     return angle::Result::Continue;
9846 }
9847 
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)9848 angle::Result ImageHelper::stageSubresourceUpdateFromFramebuffer(
9849     const gl::Context *context,
9850     const gl::ImageIndex &index,
9851     const gl::Rectangle &sourceArea,
9852     const gl::Offset &dstOffset,
9853     const gl::Extents &dstExtent,
9854     const gl::InternalFormat &formatInfo,
9855     ImageAccess access,
9856     FramebufferVk *framebufferVk)
9857 {
9858     ContextVk *contextVk = GetImpl(context);
9859 
9860     // If the extents and offset is outside the source image, we need to clip.
9861     gl::Rectangle clippedRectangle;
9862     const gl::Extents readExtents = framebufferVk->getReadImageExtents();
9863     if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, readExtents.width, readExtents.height),
9864                        &clippedRectangle))
9865     {
9866         // Empty source area, nothing to do.
9867         return angle::Result::Continue;
9868     }
9869 
9870     bool isViewportFlipEnabled = contextVk->isViewportFlipEnabledForDrawFBO();
9871     if (isViewportFlipEnabled)
9872     {
9873         clippedRectangle.y = readExtents.height - clippedRectangle.y - clippedRectangle.height;
9874     }
9875 
9876     // 1- obtain a buffer handle to copy to
9877     Renderer *renderer = contextVk->getRenderer();
9878 
9879     const Format &vkFormat             = renderer->getFormat(formatInfo.sizedInternalFormat);
9880     const angle::Format &storageFormat = vkFormat.getActualImageFormat(access);
9881     LoadImageFunctionInfo loadFunction = vkFormat.getTextureLoadFunction(access, formatInfo.type);
9882 
9883     size_t outputRowPitch   = storageFormat.pixelBytes * clippedRectangle.width;
9884     size_t outputDepthPitch = outputRowPitch * clippedRectangle.height;
9885 
9886     std::unique_ptr<RefCounted<BufferHelper>> stagingBuffer =
9887         std::make_unique<RefCounted<BufferHelper>>();
9888     BufferHelper *currentBuffer = &stagingBuffer->get();
9889 
9890     uint8_t *stagingPointer;
9891     VkDeviceSize stagingOffset;
9892 
9893     // The destination is only one layer deep.
9894     size_t allocationSize = outputDepthPitch;
9895     ANGLE_TRY(contextVk->initBufferForImageCopy(currentBuffer, allocationSize,
9896                                                 MemoryCoherency::CachedNonCoherent,
9897                                                 storageFormat.id, &stagingOffset, &stagingPointer));
9898 
9899     const angle::Format &copyFormat =
9900         GetFormatFromFormatType(formatInfo.internalFormat, formatInfo.type);
9901     PackPixelsParams params(clippedRectangle, copyFormat, static_cast<GLuint>(outputRowPitch),
9902                             isViewportFlipEnabled, nullptr, 0);
9903 
9904     RenderTargetVk *readRenderTarget = framebufferVk->getColorReadRenderTarget();
9905 
9906     // 2- copy the source image region to the pixel buffer using a cpu readback
9907     if (loadFunction.requiresConversion)
9908     {
9909         // When a conversion is required, we need to use the loadFunction to read from a temporary
9910         // buffer instead so its an even slower path.
9911         size_t bufferSize =
9912             storageFormat.pixelBytes * clippedRectangle.width * clippedRectangle.height;
9913         angle::MemoryBuffer *memoryBuffer = nullptr;
9914         ANGLE_VK_CHECK_ALLOC(contextVk, context->getScratchBuffer(bufferSize, &memoryBuffer));
9915 
9916         // Read into the scratch buffer
9917         ANGLE_TRY(framebufferVk->readPixelsImpl(contextVk, clippedRectangle, params,
9918                                                 VK_IMAGE_ASPECT_COLOR_BIT, readRenderTarget,
9919                                                 memoryBuffer->data()));
9920 
9921         // Load from scratch buffer to our pixel buffer
9922         loadFunction.loadFunction(contextVk->getImageLoadContext(), clippedRectangle.width,
9923                                   clippedRectangle.height, 1, memoryBuffer->data(), outputRowPitch,
9924                                   0, stagingPointer, outputRowPitch, 0);
9925     }
9926     else
9927     {
9928         // We read directly from the framebuffer into our pixel buffer.
9929         ANGLE_TRY(framebufferVk->readPixelsImpl(contextVk, clippedRectangle, params,
9930                                                 VK_IMAGE_ASPECT_COLOR_BIT, readRenderTarget,
9931                                                 stagingPointer));
9932     }
9933 
9934     gl::LevelIndex updateLevelGL(index.getLevelIndex());
9935 
9936     // 3- enqueue the destination image subresource update
9937     VkBufferImageCopy copyToImage               = {};
9938     copyToImage.bufferOffset                    = static_cast<VkDeviceSize>(stagingOffset);
9939     copyToImage.bufferRowLength                 = 0;  // Tightly packed data can be specified as 0.
9940     copyToImage.bufferImageHeight               = clippedRectangle.height;
9941     copyToImage.imageSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
9942     copyToImage.imageSubresource.mipLevel       = updateLevelGL.get();
9943     copyToImage.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
9944     copyToImage.imageSubresource.layerCount     = index.getLayerCount();
9945     gl_vk::GetOffset(dstOffset, &copyToImage.imageOffset);
9946     gl_vk::GetExtent(dstExtent, &copyToImage.imageExtent);
9947 
9948     // 3- enqueue the destination image subresource update
9949     appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(stagingBuffer.release(), currentBuffer,
9950                                                              copyToImage, storageFormat.id));
9951 
9952     return angle::Result::Continue;
9953 }
9954 
stageSubresourceUpdateFromImage(RefCounted<ImageHelper> * image,const gl::ImageIndex & index,LevelIndex srcMipLevel,const gl::Offset & destOffset,const gl::Extents & glExtents,const VkImageType imageType)9955 void ImageHelper::stageSubresourceUpdateFromImage(RefCounted<ImageHelper> *image,
9956                                                   const gl::ImageIndex &index,
9957                                                   LevelIndex srcMipLevel,
9958                                                   const gl::Offset &destOffset,
9959                                                   const gl::Extents &glExtents,
9960                                                   const VkImageType imageType)
9961 {
9962     gl::LevelIndex updateLevelGL(index.getLevelIndex());
9963     VkImageAspectFlags imageAspectFlags = vk::GetFormatAspectFlags(image->get().getActualFormat());
9964 
9965     VkImageCopy copyToImage               = {};
9966     copyToImage.srcSubresource.aspectMask = imageAspectFlags;
9967     copyToImage.srcSubresource.mipLevel   = srcMipLevel.get();
9968     copyToImage.srcSubresource.layerCount = index.getLayerCount();
9969     copyToImage.dstSubresource.aspectMask = imageAspectFlags;
9970     copyToImage.dstSubresource.mipLevel   = updateLevelGL.get();
9971 
9972     if (imageType == VK_IMAGE_TYPE_3D)
9973     {
9974         // These values must be set explicitly to follow the Vulkan spec:
9975         // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/man/html/VkImageCopy.html
9976         // If either of the calling command's srcImage or dstImage parameters are of VkImageType
9977         // VK_IMAGE_TYPE_3D, the baseArrayLayer and layerCount members of the corresponding
9978         // subresource must be 0 and 1, respectively
9979         copyToImage.dstSubresource.baseArrayLayer = 0;
9980         copyToImage.dstSubresource.layerCount     = 1;
9981         // Preserve the assumption that destOffset.z == "dstSubresource.baseArrayLayer"
9982         ASSERT(destOffset.z == (index.hasLayer() ? index.getLayerIndex() : 0));
9983     }
9984     else
9985     {
9986         copyToImage.dstSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
9987         copyToImage.dstSubresource.layerCount     = index.getLayerCount();
9988     }
9989 
9990     gl_vk::GetOffset(destOffset, &copyToImage.dstOffset);
9991     gl_vk::GetExtent(glExtents, &copyToImage.extent);
9992 
9993     appendSubresourceUpdate(
9994         updateLevelGL, SubresourceUpdate(image, copyToImage, image->get().getActualFormatID()));
9995 }
9996 
stageSubresourceUpdatesFromAllImageLevels(RefCounted<ImageHelper> * image,gl::LevelIndex baseLevel)9997 void ImageHelper::stageSubresourceUpdatesFromAllImageLevels(RefCounted<ImageHelper> *image,
9998                                                             gl::LevelIndex baseLevel)
9999 {
10000     for (LevelIndex levelVk(0); levelVk < LevelIndex(image->get().getLevelCount()); ++levelVk)
10001     {
10002         const gl::LevelIndex levelGL = vk_gl::GetLevelIndex(levelVk, baseLevel);
10003         const gl::ImageIndex index =
10004             gl::ImageIndex::Make2DArrayRange(levelGL.get(), 0, image->get().getLayerCount());
10005 
10006         stageSubresourceUpdateFromImage(image, index, levelVk, gl::kOffsetZero,
10007                                         image->get().getLevelExtents(levelVk),
10008                                         image->get().getType());
10009     }
10010 }
10011 
stageClear(const gl::ImageIndex & index,VkImageAspectFlags aspectFlags,const VkClearValue & clearValue)10012 void ImageHelper::stageClear(const gl::ImageIndex &index,
10013                              VkImageAspectFlags aspectFlags,
10014                              const VkClearValue &clearValue)
10015 {
10016     gl::LevelIndex updateLevelGL(index.getLevelIndex());
10017     appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(aspectFlags, clearValue, index));
10018 }
10019 
stageRobustResourceClear(const gl::ImageIndex & index)10020 void ImageHelper::stageRobustResourceClear(const gl::ImageIndex &index)
10021 {
10022     const VkImageAspectFlags aspectFlags = getAspectFlags();
10023 
10024     ASSERT(mActualFormatID != angle::FormatID::NONE);
10025     VkClearValue clearValue = GetRobustResourceClearValue(getIntendedFormat(), getActualFormat());
10026 
10027     gl::LevelIndex updateLevelGL(index.getLevelIndex());
10028     appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(aspectFlags, clearValue, index));
10029 }
10030 
stageResourceClearWithFormat(ContextVk * contextVk,const gl::ImageIndex & index,const gl::Extents & glExtents,const angle::Format & intendedFormat,const angle::Format & imageFormat,const VkClearValue & clearValue)10031 angle::Result ImageHelper::stageResourceClearWithFormat(ContextVk *contextVk,
10032                                                         const gl::ImageIndex &index,
10033                                                         const gl::Extents &glExtents,
10034                                                         const angle::Format &intendedFormat,
10035                                                         const angle::Format &imageFormat,
10036                                                         const VkClearValue &clearValue)
10037 {
10038     // Robust clears must only be staged if we do not have any prior data for this subresource.
10039     ASSERT(!hasStagedUpdatesForSubresource(gl::LevelIndex(index.getLevelIndex()),
10040                                            index.getLayerIndex(), index.getLayerCount()));
10041 
10042     const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(imageFormat);
10043 
10044     gl::LevelIndex updateLevelGL(index.getLevelIndex());
10045 
10046     if (imageFormat.isBlock)
10047     {
10048         // This only supports doing an initial clear to 0, not clearing to a specific encoded RGBA
10049         // value
10050         ASSERT((clearValue.color.int32[0] == 0) && (clearValue.color.int32[1] == 0) &&
10051                (clearValue.color.int32[2] == 0) && (clearValue.color.int32[3] == 0));
10052 
10053         const gl::InternalFormat &formatInfo =
10054             gl::GetSizedInternalFormatInfo(imageFormat.glInternalFormat);
10055         GLuint totalSize;
10056         ANGLE_VK_CHECK_MATH(contextVk,
10057                             formatInfo.computeCompressedImageSize(glExtents, &totalSize));
10058 
10059         std::unique_ptr<RefCounted<BufferHelper>> stagingBuffer =
10060             std::make_unique<RefCounted<BufferHelper>>();
10061         BufferHelper *currentBuffer = &stagingBuffer->get();
10062 
10063         uint8_t *stagingPointer;
10064         VkDeviceSize stagingOffset;
10065         ANGLE_TRY(contextVk->initBufferForImageCopy(
10066             currentBuffer, totalSize, MemoryCoherency::CachedNonCoherent, imageFormat.id,
10067             &stagingOffset, &stagingPointer));
10068         memset(stagingPointer, 0, totalSize);
10069 
10070         VkBufferImageCopy copyRegion               = {};
10071         copyRegion.bufferOffset                    = stagingOffset;
10072         copyRegion.imageExtent.width               = glExtents.width;
10073         copyRegion.imageExtent.height              = glExtents.height;
10074         copyRegion.imageExtent.depth               = glExtents.depth;
10075         copyRegion.imageSubresource.mipLevel       = updateLevelGL.get();
10076         copyRegion.imageSubresource.aspectMask     = aspectFlags;
10077         copyRegion.imageSubresource.baseArrayLayer = index.hasLayer() ? index.getLayerIndex() : 0;
10078         copyRegion.imageSubresource.layerCount     = index.getLayerCount();
10079 
10080         // The update structure owns the staging buffer.
10081         appendSubresourceUpdate(
10082             updateLevelGL,
10083             SubresourceUpdate(stagingBuffer.release(), currentBuffer, copyRegion, imageFormat.id));
10084     }
10085     else
10086     {
10087         appendSubresourceUpdate(updateLevelGL, SubresourceUpdate(aspectFlags, clearValue, index));
10088     }
10089 
10090     return angle::Result::Continue;
10091 }
10092 
stageRobustResourceClearWithFormat(ContextVk * contextVk,const gl::ImageIndex & index,const gl::Extents & glExtents,const angle::Format & intendedFormat,const angle::Format & imageFormat)10093 angle::Result ImageHelper::stageRobustResourceClearWithFormat(ContextVk *contextVk,
10094                                                               const gl::ImageIndex &index,
10095                                                               const gl::Extents &glExtents,
10096                                                               const angle::Format &intendedFormat,
10097                                                               const angle::Format &imageFormat)
10098 {
10099     VkClearValue clearValue          = GetRobustResourceClearValue(intendedFormat, imageFormat);
10100     gl::ImageIndex fullResourceIndex = index;
10101     gl::Extents fullResourceExtents  = glExtents;
10102 
10103     if (gl::IsArrayTextureType(index.getType()))
10104     {
10105         // For 2Darray textures gl::Extents::depth is the layer count.
10106         fullResourceIndex = gl::ImageIndex::MakeFromType(
10107             index.getType(), index.getLevelIndex(), gl::ImageIndex::kEntireLevel, glExtents.depth);
10108         // Vulkan requires depth of 1 for 2Darray textures.
10109         fullResourceExtents.depth = 1;
10110     }
10111 
10112     return stageResourceClearWithFormat(contextVk, fullResourceIndex, fullResourceExtents,
10113                                         intendedFormat, imageFormat, clearValue);
10114 }
10115 
stageClearIfEmulatedFormat(bool isRobustResourceInitEnabled,bool isExternalImage)10116 void ImageHelper::stageClearIfEmulatedFormat(bool isRobustResourceInitEnabled, bool isExternalImage)
10117 {
10118     // Skip staging extra clears if robust resource init is enabled.
10119     if (!hasEmulatedImageChannels() || isRobustResourceInitEnabled)
10120     {
10121         return;
10122     }
10123 
10124     VkClearValue clearValue = {};
10125     if (getIntendedFormat().hasDepthOrStencilBits())
10126     {
10127         clearValue.depthStencil = kRobustInitDepthStencilValue;
10128     }
10129     else
10130     {
10131         clearValue.color = kEmulatedInitColorValue;
10132     }
10133 
10134     const VkImageAspectFlags aspectFlags = getAspectFlags();
10135 
10136     // If the image has an emulated channel and robust resource init is not enabled, always clear
10137     // it. These channels will be masked out in future writes, and shouldn't contain uninitialized
10138     // values.
10139     //
10140     // For external images, we cannot clear the image entirely, as it may contain data in the
10141     // non-emulated channels.  For depth/stencil images, clear is already per aspect, but for color
10142     // images we would need to take a special path where we only clear the emulated channels.
10143 
10144     // Block images are not cleared, since no emulated channels are present if decoded.
10145     if (isExternalImage && getIntendedFormat().isBlock)
10146     {
10147         return;
10148     }
10149 
10150     const bool clearOnlyEmulatedChannels =
10151         isExternalImage && !getIntendedFormat().hasDepthOrStencilBits();
10152     const VkColorComponentFlags colorMaskFlags =
10153         clearOnlyEmulatedChannels ? getEmulatedChannelsMask() : 0;
10154 
10155     for (LevelIndex level(0); level < LevelIndex(mLevelCount); ++level)
10156     {
10157         gl::LevelIndex updateLevelGL = toGLLevel(level);
10158         gl::ImageIndex index =
10159             gl::ImageIndex::Make2DArrayRange(updateLevelGL.get(), 0, mLayerCount);
10160 
10161         if (clearOnlyEmulatedChannels)
10162         {
10163             prependSubresourceUpdate(updateLevelGL,
10164                                      SubresourceUpdate(colorMaskFlags, clearValue.color, index));
10165         }
10166         else
10167         {
10168             prependSubresourceUpdate(updateLevelGL,
10169                                      SubresourceUpdate(aspectFlags, clearValue, index));
10170         }
10171     }
10172 }
10173 
verifyEmulatedClearsAreBeforeOtherUpdates(const SubresourceUpdates & updates)10174 bool ImageHelper::verifyEmulatedClearsAreBeforeOtherUpdates(const SubresourceUpdates &updates)
10175 {
10176     bool isIteratingEmulatedClears = true;
10177 
10178     for (const SubresourceUpdate &update : updates)
10179     {
10180         // If anything other than ClearEmulatedChannelsOnly is visited, there cannot be any
10181         // ClearEmulatedChannelsOnly updates after that.
10182         if (update.updateSource != UpdateSource::ClearEmulatedChannelsOnly)
10183         {
10184             isIteratingEmulatedClears = false;
10185         }
10186         else if (!isIteratingEmulatedClears)
10187         {
10188             // If ClearEmulatedChannelsOnly is visited after another update, that's an error.
10189             return false;
10190         }
10191     }
10192 
10193     // Additionally, verify that emulated clear is not applied multiple times.
10194     if (updates.size() >= 2 && updates[1].updateSource == UpdateSource::ClearEmulatedChannelsOnly)
10195     {
10196         return false;
10197     }
10198 
10199     return true;
10200 }
10201 
stageSelfAsSubresourceUpdates(ContextVk * contextVk,uint32_t levelCount,gl::TextureType textureType,const gl::CubeFaceArray<gl::TexLevelMask> & skipLevels)10202 void ImageHelper::stageSelfAsSubresourceUpdates(
10203     ContextVk *contextVk,
10204     uint32_t levelCount,
10205     gl::TextureType textureType,
10206     const gl::CubeFaceArray<gl::TexLevelMask> &skipLevels)
10207 
10208 {
10209     // Nothing to do if every level must be skipped
10210     const gl::TexLevelMask levelsMask(angle::BitMask<uint32_t>(levelCount)
10211                                       << mFirstAllocatedLevel.get());
10212     const gl::TexLevelMask skipLevelsAllFaces = AggregateSkipLevels(skipLevels);
10213 
10214     if ((~skipLevelsAllFaces & levelsMask).none())
10215     {
10216         return;
10217     }
10218 
10219     // Because we are cloning this object to another object, we must finalize the layout if it is
10220     // being used by current renderpass as attachment. Otherwise we are copying the incorrect layout
10221     // since it is determined at endRenderPass time.
10222     contextVk->finalizeImageLayout(this, {});
10223 
10224     std::unique_ptr<RefCounted<ImageHelper>> prevImage =
10225         std::make_unique<RefCounted<ImageHelper>>();
10226 
10227     // Move the necessary information for staged update to work, and keep the rest as part of this
10228     // object.
10229 
10230     // Usage info
10231     prevImage->get().Resource::operator=(std::move(*this));
10232 
10233     // Vulkan objects
10234     prevImage->get().mImage         = std::move(mImage);
10235     prevImage->get().mDeviceMemory  = std::move(mDeviceMemory);
10236     prevImage->get().mVmaAllocation = std::move(mVmaAllocation);
10237 
10238     // Barrier information.  Note: mLevelCount is set to levelCount so that only the necessary
10239     // levels are transitioned when flushing the update.
10240     prevImage->get().mIntendedFormatID            = mIntendedFormatID;
10241     prevImage->get().mActualFormatID              = mActualFormatID;
10242     prevImage->get().mCurrentLayout               = mCurrentLayout;
10243     prevImage->get().mCurrentDeviceQueueIndex     = mCurrentDeviceQueueIndex;
10244     prevImage->get().mLastNonShaderReadOnlyLayout = mLastNonShaderReadOnlyLayout;
10245     prevImage->get().mCurrentShaderReadStageMask  = mCurrentShaderReadStageMask;
10246     prevImage->get().mLevelCount                  = levelCount;
10247     prevImage->get().mLayerCount                  = mLayerCount;
10248     prevImage->get().mImageSerial                 = mImageSerial;
10249     prevImage->get().mAllocationSize              = mAllocationSize;
10250     prevImage->get().mMemoryAllocationType        = mMemoryAllocationType;
10251     prevImage->get().mMemoryTypeIndex             = mMemoryTypeIndex;
10252 
10253     // Reset information for current (invalid) image.
10254     mCurrentLayout               = ImageLayout::Undefined;
10255     mCurrentDeviceQueueIndex     = kInvalidDeviceQueueIndex;
10256     mIsReleasedToExternal        = false;
10257     mIsForeignImage              = false;
10258     mLastNonShaderReadOnlyLayout = ImageLayout::Undefined;
10259     mCurrentShaderReadStageMask  = 0;
10260     mImageSerial                 = kInvalidImageSerial;
10261     mMemoryAllocationType        = MemoryAllocationType::InvalidEnum;
10262 
10263     setEntireContentUndefined();
10264 
10265     // Stage updates from the previous image.
10266     for (LevelIndex levelVk(0); levelVk < LevelIndex(levelCount); ++levelVk)
10267     {
10268         gl::LevelIndex levelGL = toGLLevel(levelVk);
10269         if (!skipLevelsAllFaces.test(levelGL.get()))
10270         {
10271             const gl::ImageIndex index =
10272                 gl::ImageIndex::Make2DArrayRange(levelGL.get(), 0, mLayerCount);
10273 
10274             stageSubresourceUpdateFromImage(prevImage.get(), index, levelVk, gl::kOffsetZero,
10275                                             getLevelExtents(levelVk), mImageType);
10276         }
10277         else if (textureType == gl::TextureType::CubeMap)
10278         {
10279             for (uint32_t face = 0; face < gl::kCubeFaceCount; ++face)
10280             {
10281                 if (!skipLevels[face][levelGL.get()])
10282                 {
10283                     const gl::ImageIndex index =
10284                         gl::ImageIndex::Make2DArrayRange(levelGL.get(), face, 1);
10285 
10286                     stageSubresourceUpdateFromImage(prevImage.get(), index, levelVk,
10287                                                     gl::kOffsetZero, getLevelExtents(levelVk),
10288                                                     mImageType);
10289                 }
10290             }
10291         }
10292     }
10293 
10294     ASSERT(levelCount > 0);
10295     prevImage.release();
10296 }
10297 
flushSingleSubresourceStagedUpdates(ContextVk * contextVk,gl::LevelIndex levelGL,uint32_t layer,uint32_t layerCount,ClearValuesArray * deferredClears,uint32_t deferredClearIndex)10298 angle::Result ImageHelper::flushSingleSubresourceStagedUpdates(ContextVk *contextVk,
10299                                                                gl::LevelIndex levelGL,
10300                                                                uint32_t layer,
10301                                                                uint32_t layerCount,
10302                                                                ClearValuesArray *deferredClears,
10303                                                                uint32_t deferredClearIndex)
10304 {
10305     SubresourceUpdates *levelUpdates = getLevelUpdates(levelGL);
10306     if (levelUpdates == nullptr || levelUpdates->empty())
10307     {
10308         return angle::Result::Continue;
10309     }
10310 
10311     // Handle deferred clears. Search the updates list for a matching clear index.
10312     if (deferredClears)
10313     {
10314         Optional<size_t> foundClear;
10315 
10316         for (size_t updateIndex = 0; updateIndex < levelUpdates->size(); ++updateIndex)
10317         {
10318             SubresourceUpdate &update = (*levelUpdates)[updateIndex];
10319 
10320             if (update.intersectsLayerRange(layer, layerCount))
10321             {
10322                 // On any data update or the clear does not match exact layer range, we'll need to
10323                 // do a full upload.
10324                 const bool isClear = IsClearOfAllChannels(update.updateSource);
10325                 if (isClear && update.matchesLayerRange(layer, layerCount))
10326                 {
10327                     foundClear = updateIndex;
10328                 }
10329                 else
10330                 {
10331                     foundClear.reset();
10332                     break;
10333                 }
10334             }
10335         }
10336 
10337         // If we have a valid index we defer the clear using the clear reference.
10338         if (foundClear.valid())
10339         {
10340             size_t foundIndex         = foundClear.value();
10341             const ClearUpdate &update = (*levelUpdates)[foundIndex].data.clear;
10342 
10343             // Note that this set command handles combined or separate depth/stencil clears.
10344             deferredClears->store(deferredClearIndex, update.aspectFlags, update.value);
10345 
10346             // Do not call onWrite as it removes mCurrentSingleClearValue, but instead call
10347             // setContentDefined directly.
10348             setContentDefined(toVkLevel(levelGL), 1, layer, layerCount, update.aspectFlags);
10349 
10350             // We process the updates again to erase any clears for this level.
10351             removeSingleSubresourceStagedUpdates(contextVk, levelGL, layer, layerCount);
10352             return angle::Result::Continue;
10353         }
10354 
10355         // Otherwise we proceed with a normal update.
10356     }
10357 
10358     return flushStagedUpdates(contextVk, levelGL, levelGL + 1, layer, layer + layerCount, {});
10359 }
10360 
flushStagedClearEmulatedChannelsUpdates(ContextVk * contextVk,gl::LevelIndex levelGLStart,gl::LevelIndex levelGLLimit,bool * otherUpdatesToFlushOut)10361 angle::Result ImageHelper::flushStagedClearEmulatedChannelsUpdates(ContextVk *contextVk,
10362                                                                    gl::LevelIndex levelGLStart,
10363                                                                    gl::LevelIndex levelGLLimit,
10364                                                                    bool *otherUpdatesToFlushOut)
10365 {
10366     *otherUpdatesToFlushOut = false;
10367     for (gl::LevelIndex updateMipLevelGL = levelGLStart; updateMipLevelGL < levelGLLimit;
10368          ++updateMipLevelGL)
10369     {
10370         // It is expected that the checked mip levels in this loop do not surpass the size of
10371         // mSubresourceUpdates.
10372         SubresourceUpdates *levelUpdates = getLevelUpdates(updateMipLevelGL);
10373         ASSERT(levelUpdates != nullptr);
10374 
10375         // The levels with no updates should be skipped.
10376         if (levelUpdates->empty())
10377         {
10378             continue;
10379         }
10380 
10381         // Since ClearEmulatedChannelsOnly is expected in the beginning and there cannot be more
10382         // than one such update type, we can process the first update and move on if there is
10383         // another update type in the list.
10384         ASSERT(verifyEmulatedClearsAreBeforeOtherUpdates(*levelUpdates));
10385         SubresourceUpdate *update = &(*levelUpdates).front();
10386 
10387         if (update->updateSource != UpdateSource::ClearEmulatedChannelsOnly)
10388         {
10389             *otherUpdatesToFlushOut = true;
10390             continue;
10391         }
10392 
10393         // If found, ClearEmulatedChannelsOnly should be flushed before the others and removed from
10394         // the update list.
10395         ASSERT(update->updateSource == UpdateSource::ClearEmulatedChannelsOnly);
10396         uint32_t updateBaseLayer, updateLayerCount;
10397         update->getDestSubresource(mLayerCount, &updateBaseLayer, &updateLayerCount);
10398 
10399         const LevelIndex updateMipLevelVk = toVkLevel(updateMipLevelGL);
10400         update->data.clear.levelIndex     = updateMipLevelVk.get();
10401         ANGLE_TRY(clearEmulatedChannels(contextVk, update->data.clear.colorMaskFlags,
10402                                         update->data.clear.value, updateMipLevelVk, updateBaseLayer,
10403                                         updateLayerCount));
10404         // Do not call onWrite. Even though some channels of the image are cleared, don't consider
10405         // the contents defined. Also, since clearing emulated channels is a one-time thing that's
10406         // superseded by Clears, |mCurrentSingleClearValue| is irrelevant and can't have a value.
10407         ASSERT(!mCurrentSingleClearValue.valid());
10408 
10409         levelUpdates->pop_front();
10410         if (!levelUpdates->empty())
10411         {
10412             ASSERT(levelUpdates->begin()->updateSource != UpdateSource::ClearEmulatedChannelsOnly);
10413             *otherUpdatesToFlushOut = true;
10414         }
10415     }
10416 
10417     return angle::Result::Continue;
10418 }
10419 
flushStagedUpdatesImpl(ContextVk * contextVk,gl::LevelIndex levelGLStart,gl::LevelIndex levelGLEnd,uint32_t layerStart,uint32_t layerEnd,const gl::TexLevelMask & skipLevelsAllFaces)10420 angle::Result ImageHelper::flushStagedUpdatesImpl(ContextVk *contextVk,
10421                                                   gl::LevelIndex levelGLStart,
10422                                                   gl::LevelIndex levelGLEnd,
10423                                                   uint32_t layerStart,
10424                                                   uint32_t layerEnd,
10425                                                   const gl::TexLevelMask &skipLevelsAllFaces)
10426 {
10427     Renderer *renderer = contextVk->getRenderer();
10428 
10429     const angle::FormatID &actualformat   = getActualFormatID();
10430     const angle::FormatID &intendedFormat = getIntendedFormatID();
10431 
10432     const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(getActualFormat());
10433 
10434     // Start in TransferDst.  Don't yet mark any subresource as having defined contents; that is
10435     // done with fine granularity as updates are applied.  This is achieved by specifying a layer
10436     // that is outside the tracking range. Under some circumstances, ComputeWrite is also required.
10437     // This need not be applied if the only updates are ClearEmulatedChannels.
10438     CommandBufferAccess transferAccess;
10439     OutsideRenderPassCommandBufferHelper *commandBuffer = nullptr;
10440     bool transCoding = renderer->getFeatures().supportsComputeTranscodeEtcToBc.enabled &&
10441                        IsETCFormat(intendedFormat) && IsBCFormat(actualformat);
10442 
10443     if (transCoding)
10444     {
10445         transferAccess.onImageTransferDstAndComputeWrite(
10446             levelGLStart, 1, kMaxContentDefinedLayerCount, 0, aspectFlags, this);
10447     }
10448     else
10449     {
10450         transferAccess.onImageTransferWrite(levelGLStart, 1, kMaxContentDefinedLayerCount, 0,
10451                                             aspectFlags, this);
10452     }
10453     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBufferHelper(transferAccess, &commandBuffer));
10454 
10455     // Flush the staged updates in each mip level.
10456     for (gl::LevelIndex updateMipLevelGL = levelGLStart; updateMipLevelGL < levelGLEnd;
10457          ++updateMipLevelGL)
10458     {
10459         // If updates to this level are specifically asked to be skipped, skip
10460         // them. This can happen when recreating an image that has been partially incompatibly
10461         // redefined, in which case only updates to the levels that haven't been redefined
10462         // should be flushed.
10463         if (skipLevelsAllFaces.test(updateMipLevelGL.get()))
10464         {
10465             continue;
10466         }
10467 
10468         // It is expected that the checked mip levels in this loop do not surpass the size of
10469         // mSubresourceUpdates.
10470         SubresourceUpdates *levelUpdates = getLevelUpdates(updateMipLevelGL);
10471         SubresourceUpdates updatesToKeep;
10472         ASSERT(levelUpdates != nullptr);
10473 
10474         // Because updates may have overlapping layer ranges, we must first figure out the actual
10475         // layer ranges that will be flushed. The updatesToKeep list must compare against this
10476         // adjusted layer range. Otherwise you may end up keeping the update even though it is
10477         // overlapped with the update that gets flushed, and then content gets overwritten when
10478         // updatesToKeep gets flushed out.
10479         uint32_t adjustedLayerStart = layerStart, adjustedLayerEnd = layerEnd;
10480         if (levelUpdates->size() > 1)
10481         {
10482             adjustLayerRange(*levelUpdates, &adjustedLayerStart, &adjustedLayerEnd);
10483         }
10484 
10485         for (SubresourceUpdate &update : *levelUpdates)
10486         {
10487             ASSERT(IsClearOfAllChannels(update.updateSource) ||
10488                    (update.updateSource == UpdateSource::ClearPartial) ||
10489                    (update.updateSource == UpdateSource::Buffer &&
10490                     update.data.buffer.bufferHelper != nullptr) ||
10491                    (update.updateSource == UpdateSource::Image &&
10492                     update.refCounted.image != nullptr && update.refCounted.image->isReferenced() &&
10493                     update.refCounted.image->get().valid()));
10494 
10495             uint32_t updateBaseLayer, updateLayerCount;
10496             update.getDestSubresource(mLayerCount, &updateBaseLayer, &updateLayerCount);
10497 
10498             // If the update layers don't intersect the requested layers, skip the update.
10499             const bool areUpdateLayersOutsideRange =
10500                 updateBaseLayer + updateLayerCount <= adjustedLayerStart ||
10501                 updateBaseLayer >= adjustedLayerEnd;
10502             if (areUpdateLayersOutsideRange)
10503             {
10504                 updatesToKeep.emplace_back(std::move(update));
10505                 continue;
10506             }
10507 
10508             const LevelIndex updateMipLevelVk = toVkLevel(updateMipLevelGL);
10509 
10510             // It seems we haven't fully support glCopyImageSubData
10511             // when compressed format emulated by uncompressed format.
10512             // make assumption that there is no data source come from image.
10513             ASSERT(!transCoding || (transCoding && update.updateSource == UpdateSource::Buffer));
10514             // The updates were holding gl::LevelIndex values so that they would not need
10515             // modification when the base level of the texture changes.  Now that the update is
10516             // about to take effect, we need to change miplevel to LevelIndex.
10517             switch (update.updateSource)
10518             {
10519                 case UpdateSource::Clear:
10520                 case UpdateSource::ClearAfterInvalidate:
10521                 {
10522                     update.data.clear.levelIndex = updateMipLevelVk.get();
10523                     break;
10524                 }
10525                 case UpdateSource::ClearPartial:
10526                 {
10527                     update.data.clearPartial.levelIndex = updateMipLevelVk.get();
10528                     break;
10529                 }
10530                 case UpdateSource::Buffer:
10531                 {
10532                     if (!transCoding && !isDataFormatMatchForCopy(update.data.buffer.formatID))
10533                     {
10534                         // TODO: http://anglebug.com/42264884, we should handle this in higher level
10535                         // code. If we have incompatible updates, skip but keep it.
10536                         updatesToKeep.emplace_back(std::move(update));
10537                         continue;
10538                     }
10539                     update.data.buffer.copyRegion.imageSubresource.mipLevel =
10540                         updateMipLevelVk.get();
10541                     break;
10542                 }
10543                 case UpdateSource::Image:
10544                 {
10545                     if (!isDataFormatMatchForCopy(update.data.image.formatID))
10546                     {
10547                         // If we have incompatible updates, skip but keep it.
10548                         updatesToKeep.emplace_back(std::move(update));
10549                         continue;
10550                     }
10551                     update.data.image.copyRegion.dstSubresource.mipLevel = updateMipLevelVk.get();
10552                     break;
10553                 }
10554                 default:
10555                 {
10556                     UNREACHABLE();
10557                     break;
10558                 }
10559             }
10560 
10561             // When a barrier is necessary when uploading updates to a level, we could instead move
10562             // to the next level and continue uploads in parallel.  Once all levels need a barrier,
10563             // a single barrier can be issued and we could continue with the rest of the updates
10564             // from the first level. In case of multiple layer updates within the same level, a
10565             // barrier might be needed if there are multiple updates in the same parts of the image.
10566             ImageLayout barrierLayout =
10567                 transCoding ? ImageLayout::TransferDstAndComputeWrite : ImageLayout::TransferDst;
10568             if (updateLayerCount >= kMaxParallelLayerWrites)
10569             {
10570                 // If there are more subresources than bits we can track, always insert a barrier.
10571                 recordWriteBarrier(contextVk, aspectFlags, barrierLayout, updateMipLevelGL, 1,
10572                                    updateBaseLayer, updateLayerCount, commandBuffer);
10573                 mSubresourcesWrittenSinceBarrier[updateMipLevelGL.get()].set();
10574             }
10575             else
10576             {
10577                 ImageLayerWriteMask subresourceHash =
10578                     GetImageLayerWriteMask(updateBaseLayer, updateLayerCount);
10579 
10580                 if (areLevelSubresourcesWrittenWithinMaskRange(updateMipLevelGL.get(),
10581                                                                subresourceHash))
10582                 {
10583                     // If there's overlap in subresource upload, issue a barrier.
10584                     recordWriteBarrier(contextVk, aspectFlags, barrierLayout, updateMipLevelGL, 1,
10585                                        updateBaseLayer, updateLayerCount, commandBuffer);
10586                     mSubresourcesWrittenSinceBarrier[updateMipLevelGL.get()].reset();
10587                 }
10588                 mSubresourcesWrittenSinceBarrier[updateMipLevelGL.get()] |= subresourceHash;
10589             }
10590 
10591             // Add the necessary commands to the outside command buffer.
10592             switch (update.updateSource)
10593             {
10594                 case UpdateSource::Clear:
10595                 case UpdateSource::ClearAfterInvalidate:
10596                 {
10597                     clear(renderer, update.data.clear.aspectFlags, update.data.clear.value,
10598                           updateMipLevelVk, updateBaseLayer, updateLayerCount,
10599                           &commandBuffer->getCommandBuffer());
10600                     contextVk->getPerfCounters().fullImageClears++;
10601                     // Remember the latest operation is a clear call.
10602                     mCurrentSingleClearValue = update.data.clear;
10603 
10604                     // Do not call onWrite as it removes mCurrentSingleClearValue, but instead call
10605                     // setContentDefined directly.
10606                     setContentDefined(updateMipLevelVk, 1, updateBaseLayer, updateLayerCount,
10607                                       update.data.clear.aspectFlags);
10608                     break;
10609                 }
10610                 case UpdateSource::ClearPartial:
10611                 {
10612                     ClearPartialUpdate &clearPartialUpdate = update.data.clearPartial;
10613                     gl::Box clearArea =
10614                         gl::Box(clearPartialUpdate.offset, clearPartialUpdate.extent);
10615 
10616                     // clearTexture() uses LOAD_OP_CLEAR in a render pass to clear the texture. If
10617                     // the texture has the depth dimension or multiple layers, the clear will be
10618                     // performed layer by layer. In case of the former, the z-dimension will be used
10619                     // as the layer index.
10620                     UtilsVk::ClearTextureParameters params = {};
10621                     params.aspectFlags                     = clearPartialUpdate.aspectFlags;
10622                     params.level                           = updateMipLevelVk;
10623                     params.clearArea                       = clearArea;
10624                     params.clearValue                      = clearPartialUpdate.clearValue;
10625 
10626                     bool shouldUseDepthAsLayer =
10627                         clearPartialUpdate.textureType == gl::TextureType::_3D;
10628                     uint32_t clearBaseLayer =
10629                         shouldUseDepthAsLayer ? clearArea.z : clearPartialUpdate.layerIndex;
10630                     uint32_t clearLayerCount =
10631                         shouldUseDepthAsLayer ? clearArea.depth : clearPartialUpdate.layerCount;
10632 
10633                     for (uint32_t layerIndex = clearBaseLayer;
10634                          layerIndex < clearBaseLayer + clearLayerCount; ++layerIndex)
10635                     {
10636                         params.layer = layerIndex;
10637                         ANGLE_TRY(contextVk->getUtils().clearTexture(contextVk, this, params));
10638                     }
10639 
10640                     // Queue serial index becomes invalid after starting render pass for the op
10641                     // above. Therefore, the outside command buffer should be re-acquired.
10642                     ANGLE_TRY(
10643                         contextVk->getOutsideRenderPassCommandBufferHelper({}, &commandBuffer));
10644                     setContentDefined(updateMipLevelVk, 1, updateBaseLayer, updateLayerCount,
10645                                       clearPartialUpdate.aspectFlags);
10646                     break;
10647                 }
10648                 case UpdateSource::Buffer:
10649                 {
10650                     BufferUpdate &bufferUpdate = update.data.buffer;
10651 
10652                     BufferHelper *currentBuffer = bufferUpdate.bufferHelper;
10653                     ASSERT(currentBuffer && currentBuffer->valid());
10654                     ANGLE_TRY(currentBuffer->flush(renderer));
10655 
10656                     CommandBufferAccess bufferAccess;
10657                     VkBufferImageCopy *copyRegion = &update.data.buffer.copyRegion;
10658 
10659                     if (transCoding && update.data.buffer.formatID != actualformat)
10660                     {
10661                         bufferAccess.onBufferComputeShaderRead(currentBuffer);
10662                         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBufferHelper(
10663                             bufferAccess, &commandBuffer));
10664                         ANGLE_TRY(contextVk->getUtils().transCodeEtcToBc(contextVk, currentBuffer,
10665                                                                          this, copyRegion));
10666                     }
10667                     else
10668                     {
10669                         bufferAccess.onBufferTransferRead(currentBuffer);
10670                         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBufferHelper(
10671                             bufferAccess, &commandBuffer));
10672                         commandBuffer->getCommandBuffer().copyBufferToImage(
10673                             currentBuffer->getBuffer().getHandle(), mImage, getCurrentLayout(), 1,
10674                             copyRegion);
10675                     }
10676                     bool commandBufferWasFlushed = false;
10677                     ANGLE_TRY(contextVk->onCopyUpdate(currentBuffer->getSize(),
10678                                                       &commandBufferWasFlushed));
10679                     onWrite(updateMipLevelGL, 1, updateBaseLayer, updateLayerCount,
10680                             copyRegion->imageSubresource.aspectMask);
10681 
10682                     // Update total staging buffer size.
10683                     mTotalStagedBufferUpdateSize -= bufferUpdate.bufferHelper->getSize();
10684 
10685                     if (commandBufferWasFlushed)
10686                     {
10687                         ANGLE_TRY(
10688                             contextVk->getOutsideRenderPassCommandBufferHelper({}, &commandBuffer));
10689                     }
10690                     break;
10691                 }
10692                 case UpdateSource::Image:
10693                 {
10694                     CommandBufferAccess imageAccess;
10695                     imageAccess.onImageTransferRead(aspectFlags, &update.refCounted.image->get());
10696                     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBufferHelper(imageAccess,
10697                                                                                  &commandBuffer));
10698 
10699                     VkImageCopy *copyRegion = &update.data.image.copyRegion;
10700                     commandBuffer->getCommandBuffer().copyImage(
10701                         update.refCounted.image->get().getImage(),
10702                         update.refCounted.image->get().getCurrentLayout(), mImage,
10703                         getCurrentLayout(), 1, copyRegion);
10704                     onWrite(updateMipLevelGL, 1, updateBaseLayer, updateLayerCount,
10705                             copyRegion->dstSubresource.aspectMask);
10706                     break;
10707                 }
10708                 default:
10709                 {
10710                     UNREACHABLE();
10711                     break;
10712                 }
10713             }
10714 
10715             update.release(renderer);
10716         }
10717 
10718         // Only remove the updates that were actually applied to the image.
10719         *levelUpdates = std::move(updatesToKeep);
10720     }
10721 
10722     // After applying the updates, the image serial should match the current queue serial of the
10723     // outside command buffer.
10724     if (mUse.getSerials()[commandBuffer->getQueueSerial().getIndex()] !=
10725         commandBuffer->getQueueSerial().getSerial())
10726     {
10727         // There has been a submission after the retainImage() call. Update the queue serial again.
10728         setQueueSerial(commandBuffer->getQueueSerial());
10729     }
10730 
10731     return angle::Result::Continue;
10732 }
10733 
flushStagedUpdates(ContextVk * contextVk,gl::LevelIndex levelGLStart,gl::LevelIndex levelGLEnd,uint32_t layerStart,uint32_t layerEnd,const gl::CubeFaceArray<gl::TexLevelMask> & skipLevels)10734 angle::Result ImageHelper::flushStagedUpdates(ContextVk *contextVk,
10735                                               gl::LevelIndex levelGLStart,
10736                                               gl::LevelIndex levelGLEnd,
10737                                               uint32_t layerStart,
10738                                               uint32_t layerEnd,
10739                                               const gl::CubeFaceArray<gl::TexLevelMask> &skipLevels)
10740 {
10741     Renderer *renderer = contextVk->getRenderer();
10742 
10743     if (!hasStagedUpdatesInLevels(levelGLStart, levelGLEnd))
10744     {
10745         return angle::Result::Continue;
10746     }
10747 
10748     const gl::TexLevelMask skipLevelsAllFaces = AggregateSkipLevels(skipLevels);
10749     removeSupersededUpdates(contextVk, skipLevelsAllFaces);
10750 
10751     // If a clear is requested and we know it was previously cleared with the same value, we drop
10752     // the clear.
10753     if (mCurrentSingleClearValue.valid())
10754     {
10755         SubresourceUpdates *levelUpdates =
10756             getLevelUpdates(gl::LevelIndex(mCurrentSingleClearValue.value().levelIndex));
10757         if (levelUpdates && levelUpdates->size() == 1)
10758         {
10759             SubresourceUpdate &update = (*levelUpdates)[0];
10760             if (IsClearOfAllChannels(update.updateSource) &&
10761                 mCurrentSingleClearValue.value() == update.data.clear)
10762             {
10763                 ASSERT(levelGLStart + 1 == levelGLEnd);
10764                 setContentDefined(toVkLevel(levelGLStart), 1, layerStart, layerEnd - layerStart,
10765                                   update.data.clear.aspectFlags);
10766                 ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_LOW,
10767                                       "Repeated Clear on framebuffer attachment dropped");
10768                 update.release(renderer);
10769                 levelUpdates->clear();
10770                 return angle::Result::Continue;
10771             }
10772         }
10773     }
10774 
10775     ASSERT(validateSubresourceUpdateRefCountsConsistent());
10776 
10777     // Process the clear emulated channels from the updates first. They are expected to be at the
10778     // beginning of the level updates.
10779     bool otherUpdatesToFlushOut = false;
10780     clipLevelToUpdateListUpperLimit(&levelGLEnd);
10781     ANGLE_TRY(flushStagedClearEmulatedChannelsUpdates(contextVk, levelGLStart, levelGLEnd,
10782                                                       &otherUpdatesToFlushOut));
10783 
10784     // If updates remain after processing ClearEmulatedChannelsOnly updates, we should acquire the
10785     // outside command buffer and apply the necessary barriers. Otherwise, this function can return
10786     // early, skipping the next loop.
10787     if (otherUpdatesToFlushOut)
10788     {
10789         ANGLE_TRY(flushStagedUpdatesImpl(contextVk, levelGLStart, levelGLEnd, layerStart, layerEnd,
10790                                          skipLevelsAllFaces));
10791     }
10792 
10793     // Compact mSubresourceUpdates, then check if there are any updates left.
10794     size_t compactSize;
10795     for (compactSize = mSubresourceUpdates.size(); compactSize > 0; --compactSize)
10796     {
10797         if (!mSubresourceUpdates[compactSize - 1].empty())
10798         {
10799             break;
10800         }
10801     }
10802     mSubresourceUpdates.resize(compactSize);
10803 
10804     ASSERT(validateSubresourceUpdateRefCountsConsistent());
10805 
10806     // If no updates left, release the staging buffers to save memory.
10807     if (mSubresourceUpdates.empty())
10808     {
10809         ASSERT(mTotalStagedBufferUpdateSize == 0);
10810         onStateChange(angle::SubjectMessage::InitializationComplete);
10811     }
10812 
10813     return angle::Result::Continue;
10814 }
10815 
flushAllStagedUpdates(ContextVk * contextVk)10816 angle::Result ImageHelper::flushAllStagedUpdates(ContextVk *contextVk)
10817 {
10818     return flushStagedUpdates(contextVk, mFirstAllocatedLevel, mFirstAllocatedLevel + mLevelCount,
10819                               0, mLayerCount, {});
10820 }
10821 
hasStagedUpdatesForSubresource(gl::LevelIndex levelGL,uint32_t layer,uint32_t layerCount) const10822 bool ImageHelper::hasStagedUpdatesForSubresource(gl::LevelIndex levelGL,
10823                                                  uint32_t layer,
10824                                                  uint32_t layerCount) const
10825 {
10826     // Check to see if any updates are staged for the given level and layer
10827 
10828     const SubresourceUpdates *levelUpdates = getLevelUpdates(levelGL);
10829     if (levelUpdates == nullptr || levelUpdates->empty())
10830     {
10831         return false;
10832     }
10833 
10834     for (const SubresourceUpdate &update : *levelUpdates)
10835     {
10836         uint32_t updateBaseLayer, updateLayerCount;
10837         update.getDestSubresource(mLayerCount, &updateBaseLayer, &updateLayerCount);
10838 
10839         const uint32_t updateLayerEnd = updateBaseLayer + updateLayerCount;
10840         const uint32_t layerEnd       = layer + layerCount;
10841 
10842         if ((layer >= updateBaseLayer && layer < updateLayerEnd) ||
10843             (layerEnd > updateBaseLayer && layerEnd <= updateLayerEnd))
10844         {
10845             // The layers intersect with the update range
10846             return true;
10847         }
10848     }
10849 
10850     return false;
10851 }
10852 
removeStagedClearUpdatesAndReturnColor(gl::LevelIndex levelGL,const VkClearColorValue ** color)10853 bool ImageHelper::removeStagedClearUpdatesAndReturnColor(gl::LevelIndex levelGL,
10854                                                          const VkClearColorValue **color)
10855 {
10856     SubresourceUpdates *levelUpdates = getLevelUpdates(levelGL);
10857     if (levelUpdates == nullptr || levelUpdates->empty())
10858     {
10859         return false;
10860     }
10861 
10862     bool result = false;
10863 
10864     for (size_t index = 0; index < levelUpdates->size();)
10865     {
10866         auto update = levelUpdates->begin() + index;
10867         if (IsClearOfAllChannels(update->updateSource))
10868         {
10869             if (color != nullptr)
10870             {
10871                 *color = &update->data.clear.value.color;
10872             }
10873             levelUpdates->erase(update);
10874             result = true;
10875         }
10876     }
10877 
10878     return result;
10879 }
10880 
adjustLayerRange(const SubresourceUpdates & levelUpdates,uint32_t * layerStart,uint32_t * layerEnd)10881 void ImageHelper::adjustLayerRange(const SubresourceUpdates &levelUpdates,
10882                                    uint32_t *layerStart,
10883                                    uint32_t *layerEnd)
10884 {
10885     for (const SubresourceUpdate &update : levelUpdates)
10886     {
10887         uint32_t updateBaseLayer, updateLayerCount;
10888         update.getDestSubresource(mLayerCount, &updateBaseLayer, &updateLayerCount);
10889         uint32_t updateLayerEnd = updateBaseLayer + updateLayerCount;
10890 
10891         // In some cases, the update has the bigger layer range than the request. If the update
10892         // layers intersect the requested layers, then expand the layer range to the maximum from
10893         // the update and from the request.
10894         const bool areUpdateLayersWithinRange =
10895             updateBaseLayer < *layerEnd && updateLayerEnd > *layerStart;
10896         if (areUpdateLayersWithinRange)
10897         {
10898             *layerStart = std::min(*layerStart, updateBaseLayer);
10899             *layerEnd   = std::max(*layerEnd, updateLayerEnd);
10900         }
10901     }
10902 }
10903 
getLastAllocatedLevel() const10904 gl::LevelIndex ImageHelper::getLastAllocatedLevel() const
10905 {
10906     return mFirstAllocatedLevel + mLevelCount - 1;
10907 }
10908 
hasStagedUpdatesInAllocatedLevels() const10909 bool ImageHelper::hasStagedUpdatesInAllocatedLevels() const
10910 {
10911     return hasStagedUpdatesInLevels(mFirstAllocatedLevel, getLastAllocatedLevel() + 1);
10912 }
10913 
hasStagedUpdatesInLevels(gl::LevelIndex levelStart,gl::LevelIndex levelEnd) const10914 bool ImageHelper::hasStagedUpdatesInLevels(gl::LevelIndex levelStart, gl::LevelIndex levelEnd) const
10915 {
10916     for (gl::LevelIndex level = levelStart; level < levelEnd; ++level)
10917     {
10918         const SubresourceUpdates *levelUpdates = getLevelUpdates(level);
10919         if (levelUpdates == nullptr)
10920         {
10921             ASSERT(static_cast<size_t>(level.get()) >= mSubresourceUpdates.size());
10922             return false;
10923         }
10924 
10925         if (!levelUpdates->empty())
10926         {
10927             return true;
10928         }
10929     }
10930     return false;
10931 }
10932 
hasStagedImageUpdatesWithMismatchedFormat(gl::LevelIndex levelStart,gl::LevelIndex levelEnd,angle::FormatID formatID) const10933 bool ImageHelper::hasStagedImageUpdatesWithMismatchedFormat(gl::LevelIndex levelStart,
10934                                                             gl::LevelIndex levelEnd,
10935                                                             angle::FormatID formatID) const
10936 {
10937     for (gl::LevelIndex level = levelStart; level < levelEnd; ++level)
10938     {
10939         const SubresourceUpdates *levelUpdates = getLevelUpdates(level);
10940         if (levelUpdates == nullptr)
10941         {
10942             continue;
10943         }
10944 
10945         for (const SubresourceUpdate &update : *levelUpdates)
10946         {
10947             if (update.updateSource == UpdateSource::Image &&
10948                 update.data.image.formatID != formatID)
10949             {
10950                 return true;
10951             }
10952         }
10953     }
10954     return false;
10955 }
10956 
hasBufferSourcedStagedUpdatesInAllLevels() const10957 bool ImageHelper::hasBufferSourcedStagedUpdatesInAllLevels() const
10958 {
10959     for (gl::LevelIndex level = mFirstAllocatedLevel; level <= getLastAllocatedLevel(); ++level)
10960     {
10961         const SubresourceUpdates *levelUpdates = getLevelUpdates(level);
10962         if (levelUpdates == nullptr || levelUpdates->empty())
10963         {
10964             return false;
10965         }
10966 
10967         bool hasUpdateSourceWithBufferOrPartialClear = false;
10968         for (const SubresourceUpdate &update : *levelUpdates)
10969         {
10970             if (update.updateSource == UpdateSource::Buffer ||
10971                 update.updateSource == UpdateSource::ClearPartial)
10972             {
10973                 hasUpdateSourceWithBufferOrPartialClear = true;
10974                 break;
10975             }
10976         }
10977         if (!hasUpdateSourceWithBufferOrPartialClear)
10978         {
10979             return false;
10980         }
10981     }
10982     return true;
10983 }
10984 
validateSubresourceUpdateBufferRefConsistent(RefCounted<BufferHelper> * buffer) const10985 bool ImageHelper::validateSubresourceUpdateBufferRefConsistent(
10986     RefCounted<BufferHelper> *buffer) const
10987 {
10988     if (buffer == nullptr)
10989     {
10990         return true;
10991     }
10992 
10993     uint32_t refs = 0;
10994 
10995     for (const SubresourceUpdates &levelUpdates : mSubresourceUpdates)
10996     {
10997         for (const SubresourceUpdate &update : levelUpdates)
10998         {
10999             if (update.updateSource == UpdateSource::Buffer && update.refCounted.buffer == buffer)
11000             {
11001                 ++refs;
11002             }
11003         }
11004     }
11005 
11006     return buffer->isRefCountAsExpected(refs);
11007 }
11008 
validateSubresourceUpdateImageRefConsistent(RefCounted<ImageHelper> * image) const11009 bool ImageHelper::validateSubresourceUpdateImageRefConsistent(RefCounted<ImageHelper> *image) const
11010 {
11011     if (image == nullptr)
11012     {
11013         return true;
11014     }
11015 
11016     uint32_t refs = 0;
11017 
11018     for (const SubresourceUpdates &levelUpdates : mSubresourceUpdates)
11019     {
11020         for (const SubresourceUpdate &update : levelUpdates)
11021         {
11022             if (update.updateSource == UpdateSource::Image && update.refCounted.image == image)
11023             {
11024                 ++refs;
11025             }
11026         }
11027     }
11028 
11029     return image->isRefCountAsExpected(refs);
11030 }
11031 
validateSubresourceUpdateRefCountsConsistent() const11032 bool ImageHelper::validateSubresourceUpdateRefCountsConsistent() const
11033 {
11034     for (const SubresourceUpdates &levelUpdates : mSubresourceUpdates)
11035     {
11036         for (const SubresourceUpdate &update : levelUpdates)
11037         {
11038             if (update.updateSource == UpdateSource::Image)
11039             {
11040                 if (!validateSubresourceUpdateImageRefConsistent(update.refCounted.image))
11041                 {
11042                     return false;
11043                 }
11044             }
11045             else if (update.updateSource == UpdateSource::Buffer)
11046             {
11047                 if (!validateSubresourceUpdateBufferRefConsistent(update.refCounted.buffer))
11048                 {
11049                     return false;
11050                 }
11051             }
11052         }
11053     }
11054 
11055     return true;
11056 }
11057 
pruneSupersededUpdatesForLevel(ContextVk * contextVk,const gl::LevelIndex level,const PruneReason reason)11058 void ImageHelper::pruneSupersededUpdatesForLevel(ContextVk *contextVk,
11059                                                  const gl::LevelIndex level,
11060                                                  const PruneReason reason)
11061 {
11062     constexpr VkDeviceSize kSubresourceUpdateSizeBeforePruning = 16 * 1024 * 1024;  // 16 MB
11063     constexpr int kUpdateCountThreshold                        = 1024;
11064     SubresourceUpdates *levelUpdates                           = getLevelUpdates(level);
11065 
11066     // If we are below pruning threshold, nothing to do.
11067     const int updateCount      = static_cast<int>(levelUpdates->size());
11068     const bool withinThreshold = updateCount < kUpdateCountThreshold &&
11069                                  mTotalStagedBufferUpdateSize < kSubresourceUpdateSizeBeforePruning;
11070     if (updateCount == 1 || (reason == PruneReason::MemoryOptimization && withinThreshold))
11071     {
11072         return;
11073     }
11074 
11075     // Start from the most recent update and define a boundingBox that covers the region to be
11076     // updated. Walk through all earlier updates and if its update region is contained within the
11077     // boundingBox, mark it as superseded, otherwise reset the boundingBox and continue.
11078     //
11079     // Color, depth and stencil are the only types supported for now. The boundingBox for color and
11080     // depth types is at index 0 and index 1 has the boundingBox for stencil type.
11081     VkDeviceSize supersededUpdateSize  = 0;
11082     std::array<gl::Box, 2> boundingBox = {gl::Box(gl::kOffsetZero, gl::Extents())};
11083 
11084     auto canDropUpdate = [this, contextVk, level, &supersededUpdateSize,
11085                           &boundingBox](SubresourceUpdate &update) {
11086         VkDeviceSize updateSize       = 0;
11087         VkImageAspectFlags aspectMask = update.getDestAspectFlags();
11088         gl::Box currentUpdateBox(gl::kOffsetZero, gl::Extents());
11089 
11090         const bool isColor =
11091             (aspectMask & (VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_PLANE_0_BIT |
11092                            VK_IMAGE_ASPECT_PLANE_1_BIT | VK_IMAGE_ASPECT_PLANE_2_BIT)) != 0;
11093         const bool isDepth   = (aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0;
11094         const bool isStencil = (aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0;
11095         ASSERT(isColor || isDepth || isStencil);
11096         int aspectIndex = (isColor || isDepth) ? 0 : 1;
11097 
11098         if (update.updateSource == UpdateSource::Buffer)
11099         {
11100             currentUpdateBox = gl::Box(update.data.buffer.copyRegion.imageOffset,
11101                                        update.data.buffer.copyRegion.imageExtent);
11102             updateSize       = update.data.buffer.bufferHelper->getSize();
11103         }
11104         else if (update.updateSource == UpdateSource::Image)
11105         {
11106             currentUpdateBox = gl::Box(update.data.image.copyRegion.dstOffset,
11107                                        update.data.image.copyRegion.extent);
11108         }
11109         else if (update.updateSource == UpdateSource::ClearPartial)
11110         {
11111             currentUpdateBox = gl::Box(
11112                 update.data.clearPartial.offset.x, update.data.clearPartial.offset.z,
11113                 update.data.clearPartial.offset.z, update.data.clearPartial.extent.width,
11114                 update.data.clearPartial.extent.height, update.data.clearPartial.extent.depth);
11115         }
11116         else
11117         {
11118             ASSERT(IsClear(update.updateSource));
11119             currentUpdateBox = gl::Box(gl::kOffsetZero, getLevelExtents(toVkLevel(level)));
11120         }
11121 
11122         // Account for updates to layered images
11123         uint32_t layerIndex = 0;
11124         uint32_t layerCount = 0;
11125         update.getDestSubresource(mLayerCount, &layerIndex, &layerCount);
11126         if (layerIndex > 0 || layerCount > 1)
11127         {
11128             currentUpdateBox.z     = layerIndex;
11129             currentUpdateBox.depth = layerCount;
11130         }
11131 
11132         // Check if current update region is superseded by the accumulated update region
11133         if (boundingBox[aspectIndex].contains(currentUpdateBox))
11134         {
11135             ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_LOW,
11136                                   "Dropped texture update that is superseded by a more recent one");
11137 
11138             // Release the superseded update
11139             update.release(contextVk->getRenderer());
11140 
11141             // Update pruning size
11142             supersededUpdateSize += updateSize;
11143 
11144             return true;
11145         }
11146         else
11147         {
11148             // Extend boundingBox to best accommodate current update's box.
11149             boundingBox[aspectIndex].extend(currentUpdateBox);
11150             // If the volume of the current update box is larger than the extended boundingBox
11151             // use that as the new boundingBox instead.
11152             if (currentUpdateBox.volume() > boundingBox[aspectIndex].volume())
11153             {
11154                 boundingBox[aspectIndex] = currentUpdateBox;
11155             }
11156             return false;
11157         }
11158     };
11159 
11160     levelUpdates->erase(
11161         levelUpdates->begin(),
11162         std::remove_if(levelUpdates->rbegin(), levelUpdates->rend(), canDropUpdate).base());
11163 
11164     // Update total staging buffer size
11165     mTotalStagedBufferUpdateSize -= supersededUpdateSize;
11166 }
11167 
removeSupersededUpdates(ContextVk * contextVk,const gl::TexLevelMask skipLevelsAllFaces)11168 void ImageHelper::removeSupersededUpdates(ContextVk *contextVk,
11169                                           const gl::TexLevelMask skipLevelsAllFaces)
11170 {
11171     ASSERT(validateSubresourceUpdateRefCountsConsistent());
11172 
11173     for (LevelIndex levelVk(0); levelVk < LevelIndex(mLevelCount); ++levelVk)
11174     {
11175         gl::LevelIndex levelGL                       = toGLLevel(levelVk);
11176         SubresourceUpdates *levelUpdates             = getLevelUpdates(levelGL);
11177         if (levelUpdates == nullptr || levelUpdates->size() == 0 ||
11178             skipLevelsAllFaces.test(levelGL.get()))
11179         {
11180             // There are no valid updates to process, continue.
11181             continue;
11182         }
11183 
11184         // ClearEmulatedChannelsOnly updates can only be in the beginning of the list of updates.
11185         // They don't entirely clear the image, so they cannot supersede any update.
11186         ASSERT(verifyEmulatedClearsAreBeforeOtherUpdates(*levelUpdates));
11187 
11188         pruneSupersededUpdatesForLevel(contextVk, levelGL, PruneReason::MinimizeWorkBeforeFlush);
11189     }
11190 
11191     ASSERT(validateSubresourceUpdateRefCountsConsistent());
11192 }
11193 
copyImageDataToBuffer(ContextVk * contextVk,gl::LevelIndex sourceLevelGL,uint32_t layerCount,uint32_t baseLayer,const gl::Box & sourceArea,BufferHelper * dstBuffer,uint8_t ** outDataPtr)11194 angle::Result ImageHelper::copyImageDataToBuffer(ContextVk *contextVk,
11195                                                  gl::LevelIndex sourceLevelGL,
11196                                                  uint32_t layerCount,
11197                                                  uint32_t baseLayer,
11198                                                  const gl::Box &sourceArea,
11199                                                  BufferHelper *dstBuffer,
11200                                                  uint8_t **outDataPtr)
11201 {
11202     ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::copyImageDataToBuffer");
11203     const angle::Format &imageFormat = getActualFormat();
11204 
11205     // As noted in the OpenGL ES 3.2 specs, table 8.13, CopyTexImage cannot
11206     // be used for depth textures. There is no way for the image or buffer
11207     // used in this function to be of some combined depth and stencil format.
11208     ASSERT(getAspectFlags() == VK_IMAGE_ASPECT_COLOR_BIT);
11209 
11210     uint32_t pixelBytes = imageFormat.pixelBytes;
11211     size_t bufferSize =
11212         sourceArea.width * sourceArea.height * sourceArea.depth * pixelBytes * layerCount;
11213 
11214     const VkImageAspectFlags aspectFlags = getAspectFlags();
11215 
11216     // Allocate staging buffer prefer coherent
11217     ASSERT(dstBuffer != nullptr && !dstBuffer->valid());
11218     VkDeviceSize dstOffset;
11219     ANGLE_TRY(contextVk->initBufferForImageCopy(dstBuffer, bufferSize,
11220                                                 MemoryCoherency::CachedPreferCoherent,
11221                                                 imageFormat.id, &dstOffset, outDataPtr));
11222     ANGLE_TRY(dstBuffer->flush(contextVk->getRenderer()));
11223 
11224     VkBuffer bufferHandle = dstBuffer->getBuffer().getHandle();
11225 
11226     LevelIndex sourceLevelVk = toVkLevel(sourceLevelGL);
11227 
11228     VkBufferImageCopy regions = {};
11229     uint32_t regionCount      = 1;
11230     // Default to non-combined DS case
11231     regions.bufferOffset                    = dstOffset;
11232     regions.bufferRowLength                 = 0;
11233     regions.bufferImageHeight               = 0;
11234     regions.imageExtent.width               = sourceArea.width;
11235     regions.imageExtent.height              = sourceArea.height;
11236     regions.imageExtent.depth               = sourceArea.depth;
11237     regions.imageOffset.x                   = sourceArea.x;
11238     regions.imageOffset.y                   = sourceArea.y;
11239     regions.imageOffset.z                   = sourceArea.z;
11240     regions.imageSubresource.aspectMask     = aspectFlags;
11241     regions.imageSubresource.baseArrayLayer = baseLayer;
11242     regions.imageSubresource.layerCount     = layerCount;
11243     regions.imageSubresource.mipLevel       = sourceLevelVk.get();
11244 
11245     CommandBufferAccess access;
11246     access.onBufferTransferWrite(dstBuffer);
11247     access.onImageTransferRead(aspectFlags, this);
11248 
11249     OutsideRenderPassCommandBuffer *commandBuffer;
11250     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
11251 
11252     commandBuffer->copyImageToBuffer(mImage, getCurrentLayout(), bufferHandle, regionCount,
11253                                      &regions);
11254 
11255     return angle::Result::Continue;
11256 }
11257 
copySurfaceImageToBuffer(DisplayVk * displayVk,gl::LevelIndex sourceLevelGL,uint32_t layerCount,uint32_t baseLayer,const gl::Box & sourceArea,vk::BufferHelper * bufferHelper)11258 angle::Result ImageHelper::copySurfaceImageToBuffer(DisplayVk *displayVk,
11259                                                     gl::LevelIndex sourceLevelGL,
11260                                                     uint32_t layerCount,
11261                                                     uint32_t baseLayer,
11262                                                     const gl::Box &sourceArea,
11263                                                     vk::BufferHelper *bufferHelper)
11264 {
11265     ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::copySurfaceImageToBuffer");
11266 
11267     Renderer *renderer = displayVk->getRenderer();
11268 
11269     VkBufferImageCopy region               = {};
11270     region.bufferOffset                    = 0;
11271     region.bufferRowLength                 = 0;
11272     region.bufferImageHeight               = 0;
11273     region.imageExtent.width               = sourceArea.width;
11274     region.imageExtent.height              = sourceArea.height;
11275     region.imageExtent.depth               = sourceArea.depth;
11276     region.imageOffset.x                   = sourceArea.x;
11277     region.imageOffset.y                   = sourceArea.y;
11278     region.imageOffset.z                   = sourceArea.z;
11279     region.imageSubresource.aspectMask     = getAspectFlags();
11280     region.imageSubresource.baseArrayLayer = baseLayer;
11281     region.imageSubresource.layerCount     = layerCount;
11282     region.imageSubresource.mipLevel       = toVkLevel(sourceLevelGL).get();
11283 
11284     ScopedPrimaryCommandBuffer scopedCommandBuffer(renderer->getDevice());
11285     ANGLE_TRY(renderer->getCommandBufferOneOff(displayVk, ProtectionType::Unprotected,
11286                                                &scopedCommandBuffer));
11287     PrimaryCommandBuffer &primaryCommandBuffer = scopedCommandBuffer.get();
11288 
11289     VkSemaphore acquireNextImageSemaphore;
11290     recordBarrierOneOffImpl(renderer, getAspectFlags(), ImageLayout::TransferSrc,
11291                             displayVk->getDeviceQueueIndex(), &primaryCommandBuffer,
11292                             &acquireNextImageSemaphore);
11293     primaryCommandBuffer.copyImageToBuffer(mImage, getCurrentLayout(),
11294                                            bufferHelper->getBuffer().getHandle(), 1, &region);
11295 
11296     ANGLE_VK_TRY(displayVk, primaryCommandBuffer.end());
11297 
11298     QueueSerial submitQueueSerial;
11299     ANGLE_TRY(renderer->queueSubmitOneOff(
11300         displayVk, std::move(scopedCommandBuffer), ProtectionType::Unprotected,
11301         egl::ContextPriority::Medium, acquireNextImageSemaphore,
11302         kSwapchainAcquireImageWaitStageFlags, &submitQueueSerial));
11303 
11304     return renderer->finishQueueSerial(displayVk, submitQueueSerial);
11305 }
11306 
copyBufferToSurfaceImage(DisplayVk * displayVk,gl::LevelIndex sourceLevelGL,uint32_t layerCount,uint32_t baseLayer,const gl::Box & sourceArea,vk::BufferHelper * bufferHelper)11307 angle::Result ImageHelper::copyBufferToSurfaceImage(DisplayVk *displayVk,
11308                                                     gl::LevelIndex sourceLevelGL,
11309                                                     uint32_t layerCount,
11310                                                     uint32_t baseLayer,
11311                                                     const gl::Box &sourceArea,
11312                                                     vk::BufferHelper *bufferHelper)
11313 {
11314     ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::copyBufferToSurfaceImage");
11315 
11316     Renderer *renderer = displayVk->getRenderer();
11317 
11318     VkBufferImageCopy region               = {};
11319     region.bufferOffset                    = 0;
11320     region.bufferRowLength                 = 0;
11321     region.bufferImageHeight               = 0;
11322     region.imageExtent.width               = sourceArea.width;
11323     region.imageExtent.height              = sourceArea.height;
11324     region.imageExtent.depth               = sourceArea.depth;
11325     region.imageOffset.x                   = sourceArea.x;
11326     region.imageOffset.y                   = sourceArea.y;
11327     region.imageOffset.z                   = sourceArea.z;
11328     region.imageSubresource.aspectMask     = getAspectFlags();
11329     region.imageSubresource.baseArrayLayer = baseLayer;
11330     region.imageSubresource.layerCount     = layerCount;
11331     region.imageSubresource.mipLevel       = toVkLevel(sourceLevelGL).get();
11332 
11333     ScopedPrimaryCommandBuffer scopedCommandBuffer(renderer->getDevice());
11334     ANGLE_TRY(renderer->getCommandBufferOneOff(displayVk, ProtectionType::Unprotected,
11335                                                &scopedCommandBuffer));
11336     PrimaryCommandBuffer &commandBuffer = scopedCommandBuffer.get();
11337 
11338     VkSemaphore acquireNextImageSemaphore;
11339     recordBarrierOneOffImpl(renderer, getAspectFlags(), ImageLayout::TransferDst,
11340                             displayVk->getDeviceQueueIndex(), &commandBuffer,
11341                             &acquireNextImageSemaphore);
11342     commandBuffer.copyBufferToImage(bufferHelper->getBuffer().getHandle(), mImage,
11343                                     getCurrentLayout(), 1, &region);
11344 
11345     ANGLE_VK_TRY(displayVk, commandBuffer.end());
11346 
11347     QueueSerial submitQueueSerial;
11348     ANGLE_TRY(renderer->queueSubmitOneOff(
11349         displayVk, std::move(scopedCommandBuffer), ProtectionType::Unprotected,
11350         egl::ContextPriority::Medium, acquireNextImageSemaphore,
11351         kSwapchainAcquireImageWaitStageFlags, &submitQueueSerial));
11352 
11353     return renderer->finishQueueSerial(displayVk, submitQueueSerial);
11354 }
11355 
11356 // 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)11357 angle::Result ImageHelper::GetReadPixelsParams(ContextVk *contextVk,
11358                                                const gl::PixelPackState &packState,
11359                                                gl::Buffer *packBuffer,
11360                                                GLenum format,
11361                                                GLenum type,
11362                                                const gl::Rectangle &area,
11363                                                const gl::Rectangle &clippedArea,
11364                                                PackPixelsParams *paramsOut,
11365                                                GLuint *skipBytesOut)
11366 {
11367     const gl::InternalFormat &sizedFormatInfo = gl::GetInternalFormatInfo(format, type);
11368 
11369     GLuint outputPitch = 0;
11370     ANGLE_VK_CHECK_MATH(contextVk,
11371                         sizedFormatInfo.computeRowPitch(type, area.width, packState.alignment,
11372                                                         packState.rowLength, &outputPitch));
11373     ANGLE_VK_CHECK_MATH(contextVk, sizedFormatInfo.computeSkipBytes(type, outputPitch, 0, packState,
11374                                                                     false, skipBytesOut));
11375 
11376     ANGLE_TRY(GetPackPixelsParams(sizedFormatInfo, outputPitch, packState, packBuffer, area,
11377                                   clippedArea, paramsOut, skipBytesOut));
11378     return angle::Result::Continue;
11379 }
11380 
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)11381 angle::Result ImageHelper::readPixelsForGetImage(ContextVk *contextVk,
11382                                                  const gl::PixelPackState &packState,
11383                                                  gl::Buffer *packBuffer,
11384                                                  gl::LevelIndex levelGL,
11385                                                  uint32_t layer,
11386                                                  uint32_t layerCount,
11387                                                  GLenum format,
11388                                                  GLenum type,
11389                                                  void *pixels)
11390 {
11391     const angle::Format &angleFormat = GetFormatFromFormatType(format, type);
11392 
11393     VkImageAspectFlagBits aspectFlags = {};
11394     if (angleFormat.redBits > 0 || angleFormat.blueBits > 0 || angleFormat.greenBits > 0 ||
11395         angleFormat.alphaBits > 0 || angleFormat.luminanceBits > 0)
11396     {
11397         aspectFlags = static_cast<VkImageAspectFlagBits>(aspectFlags | VK_IMAGE_ASPECT_COLOR_BIT);
11398     }
11399     else
11400     {
11401         if (angleFormat.depthBits > 0)
11402         {
11403             aspectFlags =
11404                 static_cast<VkImageAspectFlagBits>(aspectFlags | VK_IMAGE_ASPECT_DEPTH_BIT);
11405         }
11406         if (angleFormat.stencilBits > 0)
11407         {
11408             aspectFlags =
11409                 static_cast<VkImageAspectFlagBits>(aspectFlags | VK_IMAGE_ASPECT_STENCIL_BIT);
11410         }
11411     }
11412 
11413     ASSERT(aspectFlags != 0);
11414 
11415     PackPixelsParams params;
11416     GLuint outputSkipBytes = 0;
11417 
11418     const LevelIndex levelVk     = toVkLevel(levelGL);
11419     const gl::Extents mipExtents = getLevelExtents(levelVk);
11420     gl::Rectangle area(0, 0, mipExtents.width, mipExtents.height);
11421 
11422     ANGLE_TRY(GetReadPixelsParams(contextVk, packState, packBuffer, format, type, area, area,
11423                                   &params, &outputSkipBytes));
11424 
11425     if (mExtents.depth > 1 || layerCount > 1)
11426     {
11427         ASSERT(layer == 0);
11428         ASSERT(layerCount == 1 || mipExtents.depth == 1);
11429 
11430         uint32_t lastLayer = std::max(static_cast<uint32_t>(mipExtents.depth), layerCount);
11431 
11432         // Depth > 1 means this is a 3D texture and we need to copy all layers
11433         for (uint32_t mipLayer = 0; mipLayer < lastLayer; mipLayer++)
11434         {
11435             ANGLE_TRY(readPixels(contextVk, area, params, aspectFlags, levelGL, mipLayer,
11436                                  static_cast<uint8_t *>(pixels) + outputSkipBytes));
11437 
11438             outputSkipBytes += mipExtents.width * mipExtents.height *
11439                                gl::GetInternalFormatInfo(format, type).pixelBytes;
11440         }
11441     }
11442     else
11443     {
11444         ANGLE_TRY(readPixels(contextVk, area, params, aspectFlags, levelGL, layer,
11445                              static_cast<uint8_t *>(pixels) + outputSkipBytes));
11446     }
11447 
11448     return angle::Result::Continue;
11449 }
11450 
readPixelsForCompressedGetImage(ContextVk * contextVk,const gl::PixelPackState & packState,gl::Buffer * packBuffer,gl::LevelIndex levelGL,uint32_t layer,uint32_t layerCount,void * pixels)11451 angle::Result ImageHelper::readPixelsForCompressedGetImage(ContextVk *contextVk,
11452                                                            const gl::PixelPackState &packState,
11453                                                            gl::Buffer *packBuffer,
11454                                                            gl::LevelIndex levelGL,
11455                                                            uint32_t layer,
11456                                                            uint32_t layerCount,
11457                                                            void *pixels)
11458 {
11459     PackPixelsParams params;
11460     GLuint outputSkipBytes = 0;
11461 
11462     const LevelIndex levelVk = toVkLevel(levelGL);
11463     gl::Extents mipExtents   = getLevelExtents(levelVk);
11464     gl::Rectangle area(0, 0, mipExtents.width, mipExtents.height);
11465 
11466     VkImageAspectFlagBits aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT;
11467 
11468     const angle::Format *readFormat = &getActualFormat();
11469 
11470     // TODO(anglebug.com/42264702): Implement encoding for emuluated compression formats
11471     ANGLE_VK_CHECK(contextVk, readFormat->isBlock, VK_ERROR_FORMAT_NOT_SUPPORTED);
11472 
11473     if (mExtents.depth > 1 || layerCount > 1)
11474     {
11475         ASSERT(layer == 0);
11476         ASSERT(layerCount == 1 || mipExtents.depth == 1);
11477 
11478         uint32_t lastLayer = std::max(static_cast<uint32_t>(mipExtents.depth), layerCount);
11479 
11480         const vk::Format &vkFormat = contextVk->getRenderer()->getFormat(readFormat->id);
11481         const gl::InternalFormat &storageFormatInfo =
11482             vkFormat.getInternalFormatInfo(readFormat->componentType);
11483 
11484         // Calculate size for one layer
11485         mipExtents.depth = 1;
11486         GLuint layerSize;
11487         ANGLE_VK_CHECK_MATH(contextVk,
11488                             storageFormatInfo.computeCompressedImageSize(mipExtents, &layerSize));
11489 
11490         // Depth > 1 means this is a 3D texture and we need to copy all layers
11491         for (uint32_t mipLayer = 0; mipLayer < lastLayer; mipLayer++)
11492         {
11493             ANGLE_TRY(readPixels(contextVk, area, params, aspectFlags, levelGL, mipLayer,
11494                                  static_cast<uint8_t *>(pixels) + outputSkipBytes));
11495             outputSkipBytes += layerSize;
11496         }
11497     }
11498     else
11499     {
11500         ANGLE_TRY(readPixels(contextVk, area, params, aspectFlags, levelGL, layer,
11501                              static_cast<uint8_t *>(pixels) + outputSkipBytes));
11502     }
11503 
11504     return angle::Result::Continue;
11505 }
11506 
readPixelsWithCompute(ContextVk * contextVk,ImageHelper * src,const PackPixelsParams & packPixelsParams,const VkOffset3D & srcOffset,const VkExtent3D & srcExtent,ptrdiff_t pixelsOffset,const VkImageSubresourceLayers & srcSubresource)11507 angle::Result ImageHelper::readPixelsWithCompute(ContextVk *contextVk,
11508                                                  ImageHelper *src,
11509                                                  const PackPixelsParams &packPixelsParams,
11510                                                  const VkOffset3D &srcOffset,
11511                                                  const VkExtent3D &srcExtent,
11512                                                  ptrdiff_t pixelsOffset,
11513                                                  const VkImageSubresourceLayers &srcSubresource)
11514 {
11515     ASSERT(srcOffset.z == 0 || srcSubresource.baseArrayLayer == 0);
11516 
11517     UtilsVk::CopyImageToBufferParameters params = {};
11518     params.srcOffset[0]                         = srcOffset.x;
11519     params.srcOffset[1]                         = srcOffset.y;
11520     params.srcLayer        = std::max<uint32_t>(srcOffset.z, srcSubresource.baseArrayLayer);
11521     params.srcMip          = LevelIndex(srcSubresource.mipLevel);
11522     params.size[0]         = srcExtent.width;
11523     params.size[1]         = srcExtent.height;
11524     params.outputOffset    = packPixelsParams.offset + pixelsOffset;
11525     params.outputPitch     = packPixelsParams.outputPitch;
11526     params.reverseRowOrder = packPixelsParams.reverseRowOrder;
11527     params.outputFormat    = packPixelsParams.destFormat;
11528 
11529     BufferHelper &packBuffer = GetImpl(packPixelsParams.packBuffer)->getBuffer();
11530 
11531     return contextVk->getUtils().copyImageToBuffer(contextVk, &packBuffer, src, params);
11532 }
11533 
canCopyWithTransformForReadPixels(const PackPixelsParams & packPixelsParams,const VkExtent3D & srcExtent,const angle::Format * readFormat,ptrdiff_t pixelsOffset)11534 bool ImageHelper::canCopyWithTransformForReadPixels(const PackPixelsParams &packPixelsParams,
11535                                                     const VkExtent3D &srcExtent,
11536                                                     const angle::Format *readFormat,
11537                                                     ptrdiff_t pixelsOffset)
11538 {
11539     ASSERT(mActualFormatID != angle::FormatID::NONE && mIntendedFormatID != angle::FormatID::NONE);
11540 
11541     // Only allow copies to PBOs with identical format.
11542     const bool isSameFormatCopy = *readFormat == *packPixelsParams.destFormat;
11543 
11544     // Disallow any transformation.
11545     const bool needsTransformation =
11546         packPixelsParams.rotation != SurfaceRotation::Identity || packPixelsParams.reverseRowOrder;
11547 
11548     // Disallow copies when the output pitch cannot be correctly specified in Vulkan.
11549     const bool isPitchMultipleOfTexelSize =
11550         packPixelsParams.outputPitch % readFormat->pixelBytes == 0;
11551 
11552     // Disallow copies when PBO offset violates Vulkan bufferOffset alignment requirements.
11553     const BufferHelper &packBuffer = GetImpl(packPixelsParams.packBuffer)->getBuffer();
11554     const VkDeviceSize offset = packBuffer.getOffset() + packPixelsParams.offset + pixelsOffset;
11555     const bool isOffsetMultipleOfTexelSize = offset % readFormat->pixelBytes == 0;
11556 
11557     // Disallow copies when PBO row length is smaller than the source area width.
11558     const bool isRowLengthEnough =
11559         packPixelsParams.outputPitch >= srcExtent.width * readFormat->pixelBytes;
11560 
11561     // Don't allow copies from emulated formats for simplicity.
11562     return !hasEmulatedImageFormat() && isSameFormatCopy && !needsTransformation &&
11563            isPitchMultipleOfTexelSize && isOffsetMultipleOfTexelSize && isRowLengthEnough;
11564 }
11565 
canCopyWithComputeForReadPixels(const PackPixelsParams & packPixelsParams,const VkExtent3D & srcExtent,const angle::Format * readFormat,ptrdiff_t pixelsOffset)11566 bool ImageHelper::canCopyWithComputeForReadPixels(const PackPixelsParams &packPixelsParams,
11567                                                   const VkExtent3D &srcExtent,
11568                                                   const angle::Format *readFormat,
11569                                                   ptrdiff_t pixelsOffset)
11570 {
11571     ASSERT(mActualFormatID != angle::FormatID::NONE && mIntendedFormatID != angle::FormatID::NONE);
11572     const angle::Format *writeFormat = packPixelsParams.destFormat;
11573 
11574     // For now, only float formats are supported with 4-byte 4-channel normalized pixels for output.
11575     const bool isFloat =
11576         !readFormat->isSint() && !readFormat->isUint() && !readFormat->hasDepthOrStencilBits();
11577     const bool isFourByteOutput   = writeFormat->pixelBytes == 4 && writeFormat->channelCount == 4;
11578     const bool isNormalizedOutput = writeFormat->isUnorm() || writeFormat->isSnorm();
11579 
11580     // Disallow rotation.
11581     const bool needsTransformation = packPixelsParams.rotation != SurfaceRotation::Identity;
11582 
11583     // Disallow copies when the output pitch cannot be correctly specified in Vulkan.
11584     const bool isPitchMultipleOfTexelSize =
11585         packPixelsParams.outputPitch % readFormat->pixelBytes == 0;
11586 
11587     // Disallow copies when the output offset is not aligned to uint32_t
11588     const bool isOffsetMultipleOfUint =
11589         (packPixelsParams.offset + pixelsOffset) % readFormat->pixelBytes == 0;
11590 
11591     // Disallow copies when PBO row length is smaller than the source area width.
11592     const bool isRowLengthEnough =
11593         packPixelsParams.outputPitch >= srcExtent.width * readFormat->pixelBytes;
11594 
11595     return isFloat && isFourByteOutput && isNormalizedOutput && !needsTransformation &&
11596            isPitchMultipleOfTexelSize && isOffsetMultipleOfUint && isRowLengthEnough;
11597 }
11598 
readPixels(ContextVk * contextVk,const gl::Rectangle & area,const PackPixelsParams & packPixelsParams,VkImageAspectFlagBits copyAspectFlags,gl::LevelIndex levelGL,uint32_t layer,void * pixels)11599 angle::Result ImageHelper::readPixels(ContextVk *contextVk,
11600                                       const gl::Rectangle &area,
11601                                       const PackPixelsParams &packPixelsParams,
11602                                       VkImageAspectFlagBits copyAspectFlags,
11603                                       gl::LevelIndex levelGL,
11604                                       uint32_t layer,
11605                                       void *pixels)
11606 {
11607     ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::readPixels");
11608 
11609     const angle::Format &readFormat = getActualFormat();
11610 
11611     if (readFormat.depthBits == 0)
11612     {
11613         copyAspectFlags =
11614             static_cast<VkImageAspectFlagBits>(copyAspectFlags & ~VK_IMAGE_ASPECT_DEPTH_BIT);
11615     }
11616     if (readFormat.stencilBits == 0)
11617     {
11618         copyAspectFlags =
11619             static_cast<VkImageAspectFlagBits>(copyAspectFlags & ~VK_IMAGE_ASPECT_STENCIL_BIT);
11620     }
11621 
11622     if (copyAspectFlags == IMAGE_ASPECT_DEPTH_STENCIL)
11623     {
11624         const angle::Format &depthFormat =
11625             GetDepthStencilImageToBufferFormat(readFormat, VK_IMAGE_ASPECT_DEPTH_BIT);
11626         const angle::Format &stencilFormat =
11627             GetDepthStencilImageToBufferFormat(readFormat, VK_IMAGE_ASPECT_STENCIL_BIT);
11628 
11629         int depthOffset   = 0;
11630         int stencilOffset = 0;
11631         switch (readFormat.id)
11632         {
11633             case angle::FormatID::D24_UNORM_S8_UINT:
11634                 depthOffset   = 1;
11635                 stencilOffset = 0;
11636                 break;
11637 
11638             case angle::FormatID::D32_FLOAT_S8X24_UINT:
11639                 depthOffset   = 0;
11640                 stencilOffset = 4;
11641                 break;
11642 
11643             default:
11644                 UNREACHABLE();
11645         }
11646 
11647         ASSERT(depthOffset > 0 || stencilOffset > 0);
11648         ASSERT(depthOffset + depthFormat.depthBits / 8 <= readFormat.pixelBytes);
11649         ASSERT(stencilOffset + stencilFormat.stencilBits / 8 <= readFormat.pixelBytes);
11650 
11651         // Read the depth values, tightly-packed
11652         angle::MemoryBuffer depthBuffer;
11653         ANGLE_VK_CHECK_ALLOC(contextVk,
11654                              depthBuffer.resize(depthFormat.pixelBytes * area.width * area.height));
11655         ANGLE_TRY(
11656             readPixelsImpl(contextVk, area,
11657                            PackPixelsParams(area, depthFormat, depthFormat.pixelBytes * area.width,
11658                                             false, nullptr, 0),
11659                            VK_IMAGE_ASPECT_DEPTH_BIT, levelGL, layer, depthBuffer.data()));
11660 
11661         // Read the stencil values, tightly-packed
11662         angle::MemoryBuffer stencilBuffer;
11663         ANGLE_VK_CHECK_ALLOC(
11664             contextVk, stencilBuffer.resize(stencilFormat.pixelBytes * area.width * area.height));
11665         ANGLE_TRY(readPixelsImpl(
11666             contextVk, area,
11667             PackPixelsParams(area, stencilFormat, stencilFormat.pixelBytes * area.width, false,
11668                              nullptr, 0),
11669             VK_IMAGE_ASPECT_STENCIL_BIT, levelGL, layer, stencilBuffer.data()));
11670 
11671         // Interleave them together
11672         angle::MemoryBuffer readPixelBuffer;
11673         ANGLE_VK_CHECK_ALLOC(
11674             contextVk, readPixelBuffer.resize(readFormat.pixelBytes * area.width * area.height));
11675         readPixelBuffer.fill(0);
11676         for (int i = 0; i < area.width * area.height; i++)
11677         {
11678             uint8_t *readPixel = readPixelBuffer.data() + i * readFormat.pixelBytes;
11679             memcpy(readPixel + depthOffset, depthBuffer.data() + i * depthFormat.pixelBytes,
11680                    depthFormat.depthBits / 8);
11681             memcpy(readPixel + stencilOffset, stencilBuffer.data() + i * stencilFormat.pixelBytes,
11682                    stencilFormat.stencilBits / 8);
11683         }
11684 
11685         // Pack the interleaved depth and stencil into user-provided
11686         // destination, per user's pack pixels params
11687 
11688         // The compressed format path in packReadPixelBuffer isn't applicable
11689         // to our case, let's make extra sure we won't hit it
11690         ASSERT(!readFormat.isBlock);
11691         return packReadPixelBuffer(contextVk, area, packPixelsParams, readFormat, readFormat,
11692                                    readPixelBuffer.data(), levelGL, pixels);
11693     }
11694 
11695     return readPixelsImpl(contextVk, area, packPixelsParams, copyAspectFlags, levelGL, layer,
11696                           pixels);
11697 }
11698 
readPixelsImpl(ContextVk * contextVk,const gl::Rectangle & area,const PackPixelsParams & packPixelsParams,VkImageAspectFlagBits copyAspectFlags,gl::LevelIndex levelGL,uint32_t layer,void * pixels)11699 angle::Result ImageHelper::readPixelsImpl(ContextVk *contextVk,
11700                                           const gl::Rectangle &area,
11701                                           const PackPixelsParams &packPixelsParams,
11702                                           VkImageAspectFlagBits copyAspectFlags,
11703                                           gl::LevelIndex levelGL,
11704                                           uint32_t layer,
11705                                           void *pixels)
11706 {
11707     ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::readPixelsImpl");
11708 
11709     Renderer *renderer = contextVk->getRenderer();
11710 
11711     bool isExternalFormat = getExternalFormat() != 0;
11712     ASSERT(!isExternalFormat || (mActualFormatID >= angle::FormatID::EXTERNAL0 &&
11713                                  mActualFormatID <= angle::FormatID::EXTERNAL7));
11714 
11715     // If the source image is multisampled, we need to resolve it into a temporary image before
11716     // performing a readback.
11717     bool isMultisampled = mSamples > 1;
11718     RendererScoped<ImageHelper> resolvedImage(contextVk->getRenderer());
11719 
11720     ImageHelper *src = this;
11721 
11722     ASSERT(!hasStagedUpdatesForSubresource(levelGL, layer, 1));
11723 
11724     if (isMultisampled)
11725     {
11726         ANGLE_TRY(resolvedImage.get().init2DStaging(
11727             contextVk, contextVk->getState().hasProtectedContent(), renderer->getMemoryProperties(),
11728             gl::Extents(area.width, area.height, 1), mIntendedFormatID, mActualFormatID,
11729             VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
11730                 VK_IMAGE_USAGE_SAMPLED_BIT,
11731             1));
11732     }
11733     else if (isExternalFormat)
11734     {
11735         ANGLE_TRY(resolvedImage.get().init2DStaging(
11736             contextVk, contextVk->getState().hasProtectedContent(), renderer->getMemoryProperties(),
11737             gl::Extents(area.width, area.height, 1), angle::FormatID::R8G8B8A8_UNORM,
11738             angle::FormatID::R8G8B8A8_UNORM,
11739             VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
11740                 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
11741             1));
11742     }
11743 
11744     VkImageAspectFlags layoutChangeAspectFlags = src->getAspectFlags();
11745 
11746     const angle::Format *rgbaFormat = &angle::Format::Get(angle::FormatID::R8G8B8A8_UNORM);
11747     const angle::Format *readFormat = isExternalFormat ? rgbaFormat : &getActualFormat();
11748     const vk::Format &vkFormat      = contextVk->getRenderer()->getFormat(readFormat->id);
11749     const gl::InternalFormat &storageFormatInfo =
11750         vkFormat.getInternalFormatInfo(readFormat->componentType);
11751 
11752     if (copyAspectFlags != VK_IMAGE_ASPECT_COLOR_BIT)
11753     {
11754         readFormat = &GetDepthStencilImageToBufferFormat(*readFormat, copyAspectFlags);
11755     }
11756 
11757     VkOffset3D srcOffset = {area.x, area.y, 0};
11758 
11759     VkImageSubresourceLayers srcSubresource = {};
11760     srcSubresource.aspectMask               = copyAspectFlags;
11761     srcSubresource.mipLevel                 = toVkLevel(levelGL).get();
11762     srcSubresource.baseArrayLayer           = layer;
11763     srcSubresource.layerCount               = 1;
11764 
11765     VkExtent3D srcExtent = {static_cast<uint32_t>(area.width), static_cast<uint32_t>(area.height),
11766                             1};
11767 
11768     if (mExtents.depth > 1)
11769     {
11770         // Depth > 1 means this is a 3D texture and we need special handling
11771         srcOffset.z                   = layer;
11772         srcSubresource.baseArrayLayer = 0;
11773     }
11774 
11775     if (isExternalFormat)
11776     {
11777         // Make sure the render pass is closed, per UtilsVk::copyImage's requirements.
11778         ANGLE_TRY(
11779             contextVk->flushCommandsAndEndRenderPass(RenderPassClosureReason::PrepareForImageCopy));
11780 
11781         CommandBufferAccess access;
11782         OutsideRenderPassCommandBuffer *commandBuffer;
11783         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
11784 
11785         // Create some temp views because copyImage works in terms of them
11786         gl::TextureType textureType = Get2DTextureType(1, resolvedImage.get().getSamples());
11787 
11788         // Surely we have a view of this already!
11789         vk::ImageView srcView;
11790         ANGLE_TRY(src->initLayerImageView(contextVk, textureType, VK_IMAGE_ASPECT_COLOR_BIT,
11791                                           gl::SwizzleState(), &srcView, vk::LevelIndex(0), 1, 0,
11792                                           mLayerCount));
11793         vk::ImageView stagingView;
11794         ANGLE_TRY(resolvedImage.get().initLayerImageView(
11795             contextVk, textureType, VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(), &stagingView,
11796             vk::LevelIndex(0), 1, 0, mLayerCount));
11797 
11798         UtilsVk::CopyImageParameters params = {};
11799         params.srcOffset[0]                 = srcOffset.x;
11800         params.srcOffset[1]                 = srcOffset.y;
11801         params.srcExtents[0]                = srcExtent.width;
11802         params.srcExtents[1]                = srcExtent.height;
11803         params.srcHeight                    = srcExtent.height;
11804         ANGLE_TRY(contextVk->getUtils().copyImage(contextVk, &resolvedImage.get(), &stagingView,
11805                                                   src, &srcView, params));
11806 
11807         CommandBufferAccess readAccess;
11808         readAccess.onImageTransferRead(layoutChangeAspectFlags, &resolvedImage.get());
11809         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(readAccess, &commandBuffer));
11810 
11811         // Make the resolved image the target of buffer copy
11812         src                           = &resolvedImage.get();
11813         srcOffset                     = {0, 0, 0};
11814         srcSubresource.baseArrayLayer = 0;
11815         srcSubresource.layerCount     = 1;
11816         srcSubresource.mipLevel       = 0;
11817 
11818         // Mark our temp views as garbage immediately
11819         contextVk->addGarbage(&srcView);
11820         contextVk->addGarbage(&stagingView);
11821     }
11822 
11823     if (isMultisampled)
11824     {
11825         CommandBufferAccess access;
11826         access.onImageTransferRead(layoutChangeAspectFlags, this);
11827         access.onImageTransferWrite(gl::LevelIndex(0), 1, 0, 1, layoutChangeAspectFlags,
11828                                     &resolvedImage.get());
11829 
11830         OutsideRenderPassCommandBuffer *commandBuffer;
11831         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
11832 
11833         // Note: resolve only works on color images (not depth/stencil).
11834         ASSERT(copyAspectFlags == VK_IMAGE_ASPECT_COLOR_BIT);
11835 
11836         VkImageResolve resolveRegion                = {};
11837         resolveRegion.srcSubresource                = srcSubresource;
11838         resolveRegion.srcOffset                     = srcOffset;
11839         resolveRegion.dstSubresource.aspectMask     = copyAspectFlags;
11840         resolveRegion.dstSubresource.mipLevel       = 0;
11841         resolveRegion.dstSubresource.baseArrayLayer = 0;
11842         resolveRegion.dstSubresource.layerCount     = 1;
11843         resolveRegion.dstOffset                     = {};
11844         resolveRegion.extent                        = srcExtent;
11845 
11846         resolve(&resolvedImage.get(), resolveRegion, commandBuffer);
11847 
11848         // Make the resolved image the target of buffer copy.
11849         src                           = &resolvedImage.get();
11850         srcOffset                     = {0, 0, 0};
11851         srcSubresource.baseArrayLayer = 0;
11852         srcSubresource.layerCount     = 1;
11853         srcSubresource.mipLevel       = 0;
11854     }
11855 
11856     // If PBO and if possible, copy directly on the GPU.
11857     if (packPixelsParams.packBuffer)
11858     {
11859         ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::readPixelsImpl - PBO");
11860 
11861         const ptrdiff_t pixelsOffset = reinterpret_cast<ptrdiff_t>(pixels);
11862         if (canCopyWithTransformForReadPixels(packPixelsParams, srcExtent, readFormat,
11863                                               pixelsOffset))
11864         {
11865             BufferHelper &packBuffer      = GetImpl(packPixelsParams.packBuffer)->getBuffer();
11866             VkDeviceSize packBufferOffset = packBuffer.getOffset();
11867 
11868             CommandBufferAccess copyAccess;
11869             copyAccess.onBufferTransferWrite(&packBuffer);
11870             copyAccess.onImageTransferRead(layoutChangeAspectFlags, src);
11871 
11872             OutsideRenderPassCommandBuffer *copyCommandBuffer;
11873             ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(copyAccess, &copyCommandBuffer));
11874 
11875             ASSERT(packPixelsParams.outputPitch % readFormat->pixelBytes == 0);
11876 
11877             VkBufferImageCopy region = {};
11878             region.bufferImageHeight = srcExtent.height;
11879             region.bufferOffset      = packBufferOffset + packPixelsParams.offset + pixelsOffset;
11880             region.bufferRowLength   = packPixelsParams.outputPitch / readFormat->pixelBytes;
11881             region.imageExtent       = srcExtent;
11882             region.imageOffset       = srcOffset;
11883             region.imageSubresource  = srcSubresource;
11884 
11885             copyCommandBuffer->copyImageToBuffer(src->getImage(), src->getCurrentLayout(),
11886                                                  packBuffer.getBuffer().getHandle(), 1, &region);
11887             return angle::Result::Continue;
11888         }
11889         if (canCopyWithComputeForReadPixels(packPixelsParams, srcExtent, readFormat, pixelsOffset))
11890         {
11891             ANGLE_TRY(readPixelsWithCompute(contextVk, src, packPixelsParams, srcOffset, srcExtent,
11892                                             pixelsOffset, srcSubresource));
11893             return angle::Result::Continue;
11894         }
11895     }
11896 
11897     ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::readPixelsImpl - CPU Readback");
11898 
11899     RendererScoped<vk::BufferHelper> readBuffer(renderer);
11900     vk::BufferHelper *stagingBuffer = &readBuffer.get();
11901 
11902     uint8_t *readPixelBuffer   = nullptr;
11903     VkDeviceSize stagingOffset = 0;
11904     size_t allocationSize      = readFormat->pixelBytes * area.width * area.height;
11905 
11906     ANGLE_TRY(contextVk->initBufferForImageCopy(stagingBuffer, allocationSize,
11907                                                 MemoryCoherency::CachedPreferCoherent,
11908                                                 readFormat->id, &stagingOffset, &readPixelBuffer));
11909     ANGLE_TRY(stagingBuffer->flush(renderer));
11910     VkBuffer bufferHandle = stagingBuffer->getBuffer().getHandle();
11911 
11912     VkBufferImageCopy region = {};
11913     region.bufferImageHeight = srcExtent.height;
11914     region.bufferOffset      = stagingOffset;
11915     region.bufferRowLength   = srcExtent.width;
11916     region.imageExtent       = srcExtent;
11917     region.imageOffset       = srcOffset;
11918     region.imageSubresource  = srcSubresource;
11919 
11920     // For compressed textures, vkCmdCopyImageToBuffer requires
11921     // a region that is a multiple of the block size.
11922     if (readFormat->isBlock)
11923     {
11924         region.bufferRowLength =
11925             roundUp(region.bufferRowLength, storageFormatInfo.compressedBlockWidth);
11926         region.bufferImageHeight =
11927             roundUp(region.bufferImageHeight, storageFormatInfo.compressedBlockHeight);
11928     }
11929 
11930     CommandBufferAccess readbackAccess;
11931     readbackAccess.onBufferTransferWrite(stagingBuffer);
11932     readbackAccess.onImageTransferRead(layoutChangeAspectFlags, src);
11933 
11934     OutsideRenderPassCommandBuffer *readbackCommandBuffer;
11935     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(readbackAccess, &readbackCommandBuffer));
11936 
11937     readbackCommandBuffer->copyImageToBuffer(src->getImage(), src->getCurrentLayout(), bufferHandle,
11938                                              1, &region);
11939 
11940     ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_HIGH, "GPU stall due to ReadPixels");
11941 
11942     // Triggers a full finish.
11943     ANGLE_TRY(contextVk->finishImpl(RenderPassClosureReason::GLReadPixels));
11944     // invalidate must be called after wait for finish.
11945     ANGLE_TRY(stagingBuffer->invalidate(renderer));
11946 
11947     return packReadPixelBuffer(contextVk, area, packPixelsParams, getActualFormat(), *readFormat,
11948                                readPixelBuffer, levelGL, pixels);
11949 }
11950 
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)11951 angle::Result ImageHelper::packReadPixelBuffer(ContextVk *contextVk,
11952                                                const gl::Rectangle &area,
11953                                                const PackPixelsParams &packPixelsParams,
11954                                                const angle::Format &readFormat,
11955                                                const angle::Format &aspectFormat,
11956                                                const uint8_t *readPixelBuffer,
11957                                                gl::LevelIndex levelGL,
11958                                                void *pixels)
11959 {
11960     const vk::Format &vkFormat = contextVk->getRenderer()->getFormat(readFormat.id);
11961     const gl::InternalFormat &storageFormatInfo =
11962         vkFormat.getInternalFormatInfo(readFormat.componentType);
11963 
11964     if (readFormat.isBlock)
11965     {
11966         ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::packReadPixelBuffer - Block");
11967 
11968         ASSERT(readFormat == aspectFormat);
11969 
11970         const LevelIndex levelVk = toVkLevel(levelGL);
11971         gl::Extents levelExtents = getLevelExtents(levelVk);
11972 
11973         // Calculate size of one layer
11974         levelExtents.depth = 1;
11975         GLuint layerSize;
11976         ANGLE_VK_CHECK_MATH(contextVk,
11977                             storageFormatInfo.computeCompressedImageSize(levelExtents, &layerSize));
11978         memcpy(pixels, readPixelBuffer, layerSize);
11979     }
11980     else if (packPixelsParams.packBuffer)
11981     {
11982         ANGLE_TRACE_EVENT0("gpu.angle", "ImageHelper::packReadPixelBuffer - PBO");
11983 
11984         // Must map the PBO in order to read its contents (and then unmap it later)
11985         BufferVk *packBufferVk = GetImpl(packPixelsParams.packBuffer);
11986         void *mapPtr           = nullptr;
11987         ANGLE_TRY(packBufferVk->mapImpl(contextVk, GL_MAP_WRITE_BIT, &mapPtr));
11988         uint8_t *dst = static_cast<uint8_t *>(mapPtr) + reinterpret_cast<ptrdiff_t>(pixels);
11989         PackPixels(packPixelsParams, aspectFormat, area.width * aspectFormat.pixelBytes,
11990                    readPixelBuffer, dst);
11991         ANGLE_TRY(packBufferVk->unmapImpl(contextVk));
11992     }
11993     else
11994     {
11995         PackPixels(packPixelsParams, aspectFormat, area.width * aspectFormat.pixelBytes,
11996                    readPixelBuffer, static_cast<uint8_t *>(pixels));
11997     }
11998 
11999     return angle::Result::Continue;
12000 }
12001 
12002 // ImageHelper::SubresourceUpdate implementation
SubresourceUpdate()12003 ImageHelper::SubresourceUpdate::SubresourceUpdate() : updateSource(UpdateSource::Buffer)
12004 {
12005     data.buffer.bufferHelper = nullptr;
12006     refCounted.buffer        = nullptr;
12007 }
12008 
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)12009 ImageHelper::SubresourceUpdate::SubresourceUpdate(const VkImageAspectFlags aspectFlags,
12010                                                   const VkClearValue &clearValue,
12011                                                   const gl::TextureType textureType,
12012                                                   const uint32_t levelIndex,
12013                                                   const uint32_t layerIndex,
12014                                                   const uint32_t layerCount,
12015                                                   const gl::Box &clearArea)
12016     : updateSource(UpdateSource::ClearPartial)
12017 {
12018     data.clearPartial.aspectFlags = aspectFlags;
12019     data.clearPartial.levelIndex  = levelIndex;
12020     data.clearPartial.textureType = textureType;
12021     data.clearPartial.layerIndex  = layerIndex;
12022     data.clearPartial.layerCount  = layerCount;
12023     data.clearPartial.offset      = {clearArea.x, clearArea.y, clearArea.z};
12024     data.clearPartial.extent      = {static_cast<uint32_t>(clearArea.width),
12025                                      static_cast<uint32_t>(clearArea.height),
12026                                      static_cast<uint32_t>(clearArea.depth)};
12027     data.clearPartial.clearValue  = clearValue;
12028 }
12029 
~SubresourceUpdate()12030 ImageHelper::SubresourceUpdate::~SubresourceUpdate() {}
12031 
SubresourceUpdate(RefCounted<BufferHelper> * bufferIn,BufferHelper * bufferHelperIn,const VkBufferImageCopy & copyRegionIn,angle::FormatID formatID)12032 ImageHelper::SubresourceUpdate::SubresourceUpdate(RefCounted<BufferHelper> *bufferIn,
12033                                                   BufferHelper *bufferHelperIn,
12034                                                   const VkBufferImageCopy &copyRegionIn,
12035                                                   angle::FormatID formatID)
12036     : updateSource(UpdateSource::Buffer)
12037 {
12038     refCounted.buffer = bufferIn;
12039     if (refCounted.buffer != nullptr)
12040     {
12041         refCounted.buffer->addRef();
12042     }
12043     data.buffer.bufferHelper = bufferHelperIn;
12044     data.buffer.copyRegion   = copyRegionIn;
12045     data.buffer.formatID     = formatID;
12046 }
12047 
SubresourceUpdate(RefCounted<ImageHelper> * imageIn,const VkImageCopy & copyRegionIn,angle::FormatID formatID)12048 ImageHelper::SubresourceUpdate::SubresourceUpdate(RefCounted<ImageHelper> *imageIn,
12049                                                   const VkImageCopy &copyRegionIn,
12050                                                   angle::FormatID formatID)
12051     : updateSource(UpdateSource::Image)
12052 {
12053     refCounted.image = imageIn;
12054     refCounted.image->addRef();
12055     data.image.copyRegion = copyRegionIn;
12056     data.image.formatID   = formatID;
12057 }
12058 
SubresourceUpdate(VkImageAspectFlags aspectFlags,const VkClearValue & clearValue,const gl::ImageIndex & imageIndex)12059 ImageHelper::SubresourceUpdate::SubresourceUpdate(VkImageAspectFlags aspectFlags,
12060                                                   const VkClearValue &clearValue,
12061                                                   const gl::ImageIndex &imageIndex)
12062     : SubresourceUpdate(
12063           aspectFlags,
12064           clearValue,
12065           gl::LevelIndex(imageIndex.getLevelIndex()),
12066           imageIndex.hasLayer() ? imageIndex.getLayerIndex() : 0,
12067           imageIndex.hasLayer() ? imageIndex.getLayerCount() : VK_REMAINING_ARRAY_LAYERS)
12068 {}
12069 
SubresourceUpdate(VkImageAspectFlags aspectFlags,const VkClearValue & clearValue,gl::LevelIndex level,uint32_t layerIndex,uint32_t layerCount)12070 ImageHelper::SubresourceUpdate::SubresourceUpdate(VkImageAspectFlags aspectFlags,
12071                                                   const VkClearValue &clearValue,
12072                                                   gl::LevelIndex level,
12073                                                   uint32_t layerIndex,
12074                                                   uint32_t layerCount)
12075     : updateSource(UpdateSource::Clear)
12076 {
12077     refCounted.image          = nullptr;
12078     data.clear.aspectFlags    = aspectFlags;
12079     data.clear.value          = clearValue;
12080     data.clear.levelIndex     = level.get();
12081     data.clear.layerIndex     = layerIndex;
12082     data.clear.layerCount     = layerCount;
12083     data.clear.colorMaskFlags = 0;
12084 }
12085 
SubresourceUpdate(VkColorComponentFlags colorMaskFlags,const VkClearColorValue & clearValue,const gl::ImageIndex & imageIndex)12086 ImageHelper::SubresourceUpdate::SubresourceUpdate(VkColorComponentFlags colorMaskFlags,
12087                                                   const VkClearColorValue &clearValue,
12088                                                   const gl::ImageIndex &imageIndex)
12089     : updateSource(UpdateSource::ClearEmulatedChannelsOnly)
12090 {
12091     refCounted.image       = nullptr;
12092     data.clear.aspectFlags = VK_IMAGE_ASPECT_COLOR_BIT;
12093     data.clear.value.color = clearValue;
12094     data.clear.levelIndex  = imageIndex.getLevelIndex();
12095     data.clear.layerIndex  = imageIndex.hasLayer() ? imageIndex.getLayerIndex() : 0;
12096     data.clear.layerCount =
12097         imageIndex.hasLayer() ? imageIndex.getLayerCount() : VK_REMAINING_ARRAY_LAYERS;
12098     data.clear.colorMaskFlags = colorMaskFlags;
12099 }
12100 
SubresourceUpdate(const SubresourceUpdate & other)12101 ImageHelper::SubresourceUpdate::SubresourceUpdate(const SubresourceUpdate &other)
12102     : updateSource(other.updateSource)
12103 {
12104     switch (updateSource)
12105     {
12106         case UpdateSource::Clear:
12107         case UpdateSource::ClearEmulatedChannelsOnly:
12108         case UpdateSource::ClearAfterInvalidate:
12109             data.clear        = other.data.clear;
12110             refCounted.buffer = nullptr;
12111             break;
12112         case UpdateSource::ClearPartial:
12113             data.clearPartial = other.data.clearPartial;
12114             break;
12115         case UpdateSource::Buffer:
12116             data.buffer       = other.data.buffer;
12117             refCounted.buffer = other.refCounted.buffer;
12118             break;
12119         case UpdateSource::Image:
12120             data.image       = other.data.image;
12121             refCounted.image = other.refCounted.image;
12122             break;
12123         default:
12124             UNREACHABLE();
12125     }
12126 }
12127 
SubresourceUpdate(SubresourceUpdate && other)12128 ImageHelper::SubresourceUpdate::SubresourceUpdate(SubresourceUpdate &&other)
12129     : updateSource(other.updateSource)
12130 {
12131     switch (updateSource)
12132     {
12133         case UpdateSource::Clear:
12134         case UpdateSource::ClearEmulatedChannelsOnly:
12135         case UpdateSource::ClearAfterInvalidate:
12136             data.clear        = other.data.clear;
12137             refCounted.buffer = nullptr;
12138             break;
12139         case UpdateSource::ClearPartial:
12140             data.clearPartial = other.data.clearPartial;
12141             break;
12142         case UpdateSource::Buffer:
12143             data.buffer             = other.data.buffer;
12144             refCounted.buffer       = other.refCounted.buffer;
12145             other.refCounted.buffer = nullptr;
12146             break;
12147         case UpdateSource::Image:
12148             data.image             = other.data.image;
12149             refCounted.image       = other.refCounted.image;
12150             other.refCounted.image = nullptr;
12151             break;
12152         default:
12153             UNREACHABLE();
12154     }
12155 }
12156 
operator =(SubresourceUpdate && other)12157 ImageHelper::SubresourceUpdate &ImageHelper::SubresourceUpdate::operator=(SubresourceUpdate &&other)
12158 {
12159     // Given that the update is a union of three structs, we can't use std::swap on the fields.  For
12160     // example, |this| may be an Image update and |other| may be a Buffer update.
12161     // The following could work:
12162     //
12163     // SubresourceUpdate oldThis;
12164     // Set oldThis to this->field based on updateSource
12165     // Set this->otherField to other.otherField based on other.updateSource
12166     // Set other.field to oldThis->field based on updateSource
12167     // std::Swap(updateSource, other.updateSource);
12168     //
12169     // It's much simpler to just swap the memory instead.
12170 
12171     SubresourceUpdate oldThis;
12172     memcpy(&oldThis, this, sizeof(*this));
12173     memcpy(this, &other, sizeof(*this));
12174     memcpy(&other, &oldThis, sizeof(*this));
12175 
12176     return *this;
12177 }
12178 
release(Renderer * renderer)12179 void ImageHelper::SubresourceUpdate::release(Renderer *renderer)
12180 {
12181     if (updateSource == UpdateSource::Image)
12182     {
12183         refCounted.image->releaseRef();
12184 
12185         if (!refCounted.image->isReferenced())
12186         {
12187             // Staging images won't be used in render pass attachments.
12188             refCounted.image->get().releaseImage(renderer);
12189             refCounted.image->get().releaseStagedUpdates(renderer);
12190             SafeDelete(refCounted.image);
12191         }
12192 
12193         refCounted.image = nullptr;
12194     }
12195     else if (updateSource == UpdateSource::Buffer && refCounted.buffer != nullptr)
12196     {
12197         refCounted.buffer->releaseRef();
12198 
12199         if (!refCounted.buffer->isReferenced())
12200         {
12201             refCounted.buffer->get().release(renderer);
12202             SafeDelete(refCounted.buffer);
12203         }
12204 
12205         refCounted.buffer = nullptr;
12206     }
12207 }
12208 
matchesLayerRange(uint32_t layerIndex,uint32_t layerCount) const12209 bool ImageHelper::SubresourceUpdate::matchesLayerRange(uint32_t layerIndex,
12210                                                        uint32_t layerCount) const
12211 {
12212     uint32_t updateBaseLayer, updateLayerCount;
12213     getDestSubresource(gl::ImageIndex::kEntireLevel, &updateBaseLayer, &updateLayerCount);
12214 
12215     return updateBaseLayer == layerIndex &&
12216            (updateLayerCount == layerCount || updateLayerCount == VK_REMAINING_ARRAY_LAYERS);
12217 }
12218 
intersectsLayerRange(uint32_t layerIndex,uint32_t layerCount) const12219 bool ImageHelper::SubresourceUpdate::intersectsLayerRange(uint32_t layerIndex,
12220                                                           uint32_t layerCount) const
12221 {
12222     uint32_t updateBaseLayer, updateLayerCount;
12223     getDestSubresource(gl::ImageIndex::kEntireLevel, &updateBaseLayer, &updateLayerCount);
12224     uint32_t updateLayerEnd = updateBaseLayer + updateLayerCount;
12225 
12226     return updateBaseLayer < (layerIndex + layerCount) && updateLayerEnd > layerIndex;
12227 }
12228 
getDestSubresource(uint32_t imageLayerCount,uint32_t * baseLayerOut,uint32_t * layerCountOut) const12229 void ImageHelper::SubresourceUpdate::getDestSubresource(uint32_t imageLayerCount,
12230                                                         uint32_t *baseLayerOut,
12231                                                         uint32_t *layerCountOut) const
12232 {
12233     if (IsClear(updateSource))
12234     {
12235         *baseLayerOut  = data.clear.layerIndex;
12236         *layerCountOut = data.clear.layerCount;
12237 
12238         if (*layerCountOut == static_cast<uint32_t>(gl::ImageIndex::kEntireLevel))
12239         {
12240             *layerCountOut = imageLayerCount;
12241         }
12242     }
12243     else if (updateSource == UpdateSource::ClearPartial)
12244     {
12245         *baseLayerOut  = data.clearPartial.layerIndex;
12246         *layerCountOut = data.clearPartial.layerCount;
12247 
12248         if (*layerCountOut == static_cast<uint32_t>(gl::ImageIndex::kEntireLevel))
12249         {
12250             *layerCountOut = imageLayerCount;
12251         }
12252     }
12253     else
12254     {
12255         const VkImageSubresourceLayers &dstSubresource =
12256             updateSource == UpdateSource::Buffer ? data.buffer.copyRegion.imageSubresource
12257                                                  : data.image.copyRegion.dstSubresource;
12258         *baseLayerOut  = dstSubresource.baseArrayLayer;
12259         *layerCountOut = dstSubresource.layerCount;
12260 
12261         ASSERT(*layerCountOut != static_cast<uint32_t>(gl::ImageIndex::kEntireLevel));
12262     }
12263 }
12264 
getDestAspectFlags() const12265 VkImageAspectFlags ImageHelper::SubresourceUpdate::getDestAspectFlags() const
12266 {
12267     if (IsClear(updateSource))
12268     {
12269         return data.clear.aspectFlags;
12270     }
12271     else if (updateSource == UpdateSource::ClearPartial)
12272     {
12273         return data.clearPartial.aspectFlags;
12274     }
12275     else if (updateSource == UpdateSource::Buffer)
12276     {
12277         return data.buffer.copyRegion.imageSubresource.aspectMask;
12278     }
12279     else
12280     {
12281         ASSERT(updateSource == UpdateSource::Image);
12282         return data.image.copyRegion.dstSubresource.aspectMask;
12283     }
12284 }
12285 
getLevelUpdateCount(gl::LevelIndex level) const12286 size_t ImageHelper::getLevelUpdateCount(gl::LevelIndex level) const
12287 {
12288     return static_cast<size_t>(level.get()) < mSubresourceUpdates.size()
12289                ? mSubresourceUpdates[level.get()].size()
12290                : 0;
12291 }
12292 
clipLevelToUpdateListUpperLimit(gl::LevelIndex * level) const12293 void ImageHelper::clipLevelToUpdateListUpperLimit(gl::LevelIndex *level) const
12294 {
12295     gl::LevelIndex levelLimit(static_cast<int>(mSubresourceUpdates.size()));
12296     *level = std::min(*level, levelLimit);
12297 }
12298 
getLevelUpdates(gl::LevelIndex level)12299 ImageHelper::SubresourceUpdates *ImageHelper::getLevelUpdates(gl::LevelIndex level)
12300 {
12301     return static_cast<size_t>(level.get()) < mSubresourceUpdates.size()
12302                ? &mSubresourceUpdates[level.get()]
12303                : nullptr;
12304 }
12305 
getLevelUpdates(gl::LevelIndex level) const12306 const ImageHelper::SubresourceUpdates *ImageHelper::getLevelUpdates(gl::LevelIndex level) const
12307 {
12308     return static_cast<size_t>(level.get()) < mSubresourceUpdates.size()
12309                ? &mSubresourceUpdates[level.get()]
12310                : nullptr;
12311 }
12312 
appendSubresourceUpdate(gl::LevelIndex level,SubresourceUpdate && update)12313 void ImageHelper::appendSubresourceUpdate(gl::LevelIndex level, SubresourceUpdate &&update)
12314 {
12315     if (mSubresourceUpdates.size() <= static_cast<size_t>(level.get()))
12316     {
12317         mSubresourceUpdates.resize(level.get() + 1);
12318     }
12319     // Update total staging buffer size
12320     mTotalStagedBufferUpdateSize += update.updateSource == UpdateSource::Buffer
12321                                         ? update.data.buffer.bufferHelper->getSize()
12322                                         : 0;
12323     mSubresourceUpdates[level.get()].emplace_back(std::move(update));
12324     onStateChange(angle::SubjectMessage::SubjectChanged);
12325 }
12326 
prependSubresourceUpdate(gl::LevelIndex level,SubresourceUpdate && update)12327 void ImageHelper::prependSubresourceUpdate(gl::LevelIndex level, SubresourceUpdate &&update)
12328 {
12329     if (mSubresourceUpdates.size() <= static_cast<size_t>(level.get()))
12330     {
12331         mSubresourceUpdates.resize(level.get() + 1);
12332     }
12333 
12334     // Update total staging buffer size
12335     mTotalStagedBufferUpdateSize += update.updateSource == UpdateSource::Buffer
12336                                         ? update.data.buffer.bufferHelper->getSize()
12337                                         : 0;
12338     mSubresourceUpdates[level.get()].emplace_front(std::move(update));
12339     onStateChange(angle::SubjectMessage::SubjectChanged);
12340 }
12341 
hasEmulatedImageChannels() const12342 bool ImageHelper::hasEmulatedImageChannels() const
12343 {
12344     const angle::Format &angleFmt   = getIntendedFormat();
12345     const angle::Format &textureFmt = getActualFormat();
12346 
12347     // Block formats may be decoded and emulated with a non-block format.
12348     if (angleFmt.isBlock)
12349     {
12350         return !textureFmt.isBlock;
12351     }
12352 
12353     // The red channel is never emulated.
12354     ASSERT((angleFmt.redBits != 0 || angleFmt.luminanceBits != 0 || angleFmt.alphaBits != 0) ==
12355            (textureFmt.redBits != 0));
12356 
12357     return (angleFmt.alphaBits == 0 && textureFmt.alphaBits > 0) ||
12358            (angleFmt.blueBits == 0 && textureFmt.blueBits > 0) ||
12359            (angleFmt.greenBits == 0 && textureFmt.greenBits > 0) ||
12360            (angleFmt.depthBits == 0 && textureFmt.depthBits > 0) ||
12361            (angleFmt.stencilBits == 0 && textureFmt.stencilBits > 0);
12362 }
12363 
hasEmulatedDepthChannel() const12364 bool ImageHelper::hasEmulatedDepthChannel() const
12365 {
12366     return getIntendedFormat().depthBits == 0 && getActualFormat().depthBits > 0;
12367 }
12368 
hasEmulatedStencilChannel() const12369 bool ImageHelper::hasEmulatedStencilChannel() const
12370 {
12371     return getIntendedFormat().stencilBits == 0 && getActualFormat().stencilBits > 0;
12372 }
12373 
hasInefficientlyEmulatedImageFormat() const12374 bool ImageHelper::hasInefficientlyEmulatedImageFormat() const
12375 {
12376     if (hasEmulatedImageFormat())
12377     {
12378         // ETC2 compression is compatible with ETC1
12379         return !(mIntendedFormatID == angle::FormatID::ETC1_R8G8B8_UNORM_BLOCK &&
12380                  mActualFormatID == angle::FormatID::ETC2_R8G8B8_UNORM_BLOCK);
12381     }
12382     return false;
12383 }
12384 
getEmulatedChannelsMask() const12385 VkColorComponentFlags ImageHelper::getEmulatedChannelsMask() const
12386 {
12387     const angle::Format &angleFmt   = getIntendedFormat();
12388     const angle::Format &textureFmt = getActualFormat();
12389 
12390     ASSERT(!angleFmt.hasDepthOrStencilBits());
12391 
12392     VkColorComponentFlags emulatedChannelsMask = 0;
12393 
12394     if (angleFmt.alphaBits == 0 && textureFmt.alphaBits > 0)
12395     {
12396         emulatedChannelsMask |= VK_COLOR_COMPONENT_A_BIT;
12397     }
12398     if (angleFmt.blueBits == 0 && textureFmt.blueBits > 0)
12399     {
12400         emulatedChannelsMask |= VK_COLOR_COMPONENT_B_BIT;
12401     }
12402     if (angleFmt.greenBits == 0 && textureFmt.greenBits > 0)
12403     {
12404         emulatedChannelsMask |= VK_COLOR_COMPONENT_G_BIT;
12405     }
12406 
12407     // The red channel is never emulated.
12408     ASSERT((angleFmt.redBits != 0 || angleFmt.luminanceBits != 0 || angleFmt.alphaBits != 0) ==
12409            (textureFmt.redBits != 0));
12410 
12411     return emulatedChannelsMask;
12412 }
12413 
GetLayerMode(const vk::ImageHelper & image,uint32_t layerCount)12414 LayerMode GetLayerMode(const vk::ImageHelper &image, uint32_t layerCount)
12415 {
12416     const uint32_t imageLayerCount = GetImageLayerCountForView(image);
12417     const bool allLayers           = layerCount == imageLayerCount;
12418 
12419     ASSERT(allLayers || (layerCount > 0 && layerCount <= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS));
12420     return allLayers ? LayerMode::All : static_cast<LayerMode>(layerCount);
12421 }
12422 
GetComputePipelineOptions(vk::PipelineRobustness robustness,vk::PipelineProtectedAccess protectedAccess)12423 ComputePipelineOptions GetComputePipelineOptions(vk::PipelineRobustness robustness,
12424                                                  vk::PipelineProtectedAccess protectedAccess)
12425 {
12426     vk::ComputePipelineOptions pipelineOptions = {};
12427 
12428     if (robustness == vk::PipelineRobustness::Robust)
12429     {
12430         pipelineOptions.robustness = 1;
12431     }
12432     if (protectedAccess == vk::PipelineProtectedAccess::Protected)
12433     {
12434         pipelineOptions.protectedAccess = 1;
12435     }
12436 
12437     return pipelineOptions;
12438 }
12439 
12440 // ImageViewHelper implementation.
ImageViewHelper()12441 ImageViewHelper::ImageViewHelper()
12442     : mCurrentBaseMaxLevelHash(0),
12443       mIsCopyImageViewShared(false),
12444       mReadColorspace(ImageViewColorspace::Invalid),
12445       mWriteColorspace(ImageViewColorspace::Invalid)
12446 {}
12447 
ImageViewHelper(ImageViewHelper && other)12448 ImageViewHelper::ImageViewHelper(ImageViewHelper &&other)
12449 {
12450     std::swap(mCurrentBaseMaxLevelHash, other.mCurrentBaseMaxLevelHash);
12451     std::swap(mReadColorspace, other.mReadColorspace);
12452     std::swap(mWriteColorspace, other.mWriteColorspace);
12453     std::swap(mColorspaceState, other.mColorspaceState);
12454 
12455     std::swap(mPerLevelRangeLinearReadImageViews, other.mPerLevelRangeLinearReadImageViews);
12456     std::swap(mPerLevelRangeSRGBReadImageViews, other.mPerLevelRangeSRGBReadImageViews);
12457     std::swap(mPerLevelRangeLinearCopyImageViews, other.mPerLevelRangeLinearCopyImageViews);
12458     std::swap(mPerLevelRangeSRGBCopyImageViews, other.mPerLevelRangeSRGBCopyImageViews);
12459     std::swap(mIsCopyImageViewShared, other.mIsCopyImageViewShared);
12460     std::swap(mPerLevelRangeStencilReadImageViews, other.mPerLevelRangeStencilReadImageViews);
12461     std::swap(mPerLevelRangeSamplerExternal2DY2YEXTImageViews,
12462               other.mPerLevelRangeSamplerExternal2DY2YEXTImageViews);
12463 
12464     std::swap(mLayerLevelDrawImageViews, other.mLayerLevelDrawImageViews);
12465     std::swap(mLayerLevelDrawImageViewsLinear, other.mLayerLevelDrawImageViewsLinear);
12466     std::swap(mSubresourceDrawImageViews, other.mSubresourceDrawImageViews);
12467 
12468     std::swap(mLayerLevelDepthOnlyImageViews, other.mLayerLevelDepthOnlyImageViews);
12469     std::swap(mLayerLevelStencilOnlyImageViews, other.mLayerLevelStencilOnlyImageViews);
12470     std::swap(mSubresourceDepthOnlyImageViews, other.mSubresourceDepthOnlyImageViews);
12471     std::swap(mSubresourceStencilOnlyImageViews, other.mSubresourceStencilOnlyImageViews);
12472 
12473     std::swap(mLevelStorageImageViews, other.mLevelStorageImageViews);
12474     std::swap(mLayerLevelStorageImageViews, other.mLayerLevelStorageImageViews);
12475     std::swap(mFragmentShadingRateImageView, other.mFragmentShadingRateImageView);
12476     std::swap(mImageViewSerial, other.mImageViewSerial);
12477 }
12478 
~ImageViewHelper()12479 ImageViewHelper::~ImageViewHelper() {}
12480 
init(Renderer * renderer)12481 void ImageViewHelper::init(Renderer *renderer)
12482 {
12483     if (!mImageViewSerial.valid())
12484     {
12485         mImageViewSerial = renderer->getResourceSerialFactory().generateImageOrBufferViewSerial();
12486     }
12487 }
12488 
release(Renderer * renderer,const ResourceUse & use)12489 void ImageViewHelper::release(Renderer *renderer, const ResourceUse &use)
12490 {
12491     mCurrentBaseMaxLevelHash = 0;
12492     mReadColorspace          = ImageViewColorspace::Invalid;
12493     mWriteColorspace         = ImageViewColorspace::Invalid;
12494     // Clear shared flag
12495     mIsCopyImageViewShared = false;
12496     mColorspaceState.reset();
12497 
12498     GarbageObjects garbage;
12499     // Reserve reasonable amount of storage
12500     garbage.reserve(4);
12501 
12502     // Release the read views
12503     ReleaseImageViews(&mPerLevelRangeLinearReadImageViews, &garbage);
12504     ReleaseImageViews(&mPerLevelRangeSRGBReadImageViews, &garbage);
12505     ReleaseImageViews(&mPerLevelRangeLinearCopyImageViews, &garbage);
12506     ReleaseImageViews(&mPerLevelRangeSRGBCopyImageViews, &garbage);
12507     ReleaseImageViews(&mPerLevelRangeStencilReadImageViews, &garbage);
12508     ReleaseImageViews(&mPerLevelRangeSamplerExternal2DY2YEXTImageViews, &garbage);
12509 
12510     // Release the draw views
12511     ReleaseLayerLevelImageViews(&mLayerLevelDrawImageViews, &garbage);
12512     ReleaseLayerLevelImageViews(&mLayerLevelDrawImageViewsLinear, &garbage);
12513     ReleaseSubresourceImageViews(&mSubresourceDrawImageViews, &garbage);
12514 
12515     // Release the depth-xor-stencil input views
12516     ReleaseLayerLevelImageViews(&mLayerLevelDepthOnlyImageViews, &garbage);
12517     ReleaseLayerLevelImageViews(&mLayerLevelStencilOnlyImageViews, &garbage);
12518     ReleaseSubresourceImageViews(&mSubresourceDepthOnlyImageViews, &garbage);
12519     ReleaseSubresourceImageViews(&mSubresourceStencilOnlyImageViews, &garbage);
12520 
12521     // Release the storage views
12522     ReleaseImageViews(&mLevelStorageImageViews, &garbage);
12523     ReleaseLayerLevelImageViews(&mLayerLevelStorageImageViews, &garbage);
12524 
12525     // Release fragment shading rate view
12526     if (mFragmentShadingRateImageView.valid())
12527     {
12528         garbage.emplace_back(GetGarbage(&mFragmentShadingRateImageView));
12529     }
12530 
12531     if (!garbage.empty())
12532     {
12533         renderer->collectGarbage(use, std::move(garbage));
12534     }
12535 
12536     // Update image view serial.
12537     mImageViewSerial = renderer->getResourceSerialFactory().generateImageOrBufferViewSerial();
12538 }
12539 
isImageViewGarbageEmpty() const12540 bool ImageViewHelper::isImageViewGarbageEmpty() const
12541 {
12542     return mPerLevelRangeLinearReadImageViews.empty() &&
12543            mPerLevelRangeLinearCopyImageViews.empty() && mPerLevelRangeSRGBReadImageViews.empty() &&
12544            mPerLevelRangeSRGBCopyImageViews.empty() &&
12545            mPerLevelRangeStencilReadImageViews.empty() &&
12546            mPerLevelRangeSamplerExternal2DY2YEXTImageViews.empty() &&
12547            mLayerLevelDrawImageViews.empty() && mLayerLevelDrawImageViewsLinear.empty() &&
12548            mSubresourceDrawImageViews.empty() && mLayerLevelDepthOnlyImageViews.empty() &&
12549            mLayerLevelStencilOnlyImageViews.empty() && mSubresourceDepthOnlyImageViews.empty() &&
12550            mSubresourceStencilOnlyImageViews.empty() && mLayerLevelStorageImageViews.empty();
12551 }
12552 
destroy(VkDevice device)12553 void ImageViewHelper::destroy(VkDevice device)
12554 {
12555     mCurrentBaseMaxLevelHash = 0;
12556     mReadColorspace          = ImageViewColorspace::Invalid;
12557     mWriteColorspace         = ImageViewColorspace::Invalid;
12558     mColorspaceState.reset();
12559 
12560     // Release the read views
12561     DestroyImageViews(&mPerLevelRangeLinearReadImageViews, device);
12562     DestroyImageViews(&mPerLevelRangeSRGBReadImageViews, device);
12563     DestroyImageViews(&mPerLevelRangeLinearCopyImageViews, device);
12564     DestroyImageViews(&mPerLevelRangeSRGBCopyImageViews, device);
12565     DestroyImageViews(&mPerLevelRangeStencilReadImageViews, device);
12566     DestroyImageViews(&mPerLevelRangeSamplerExternal2DY2YEXTImageViews, device);
12567 
12568     // Release the draw views
12569     DestroyLayerLevelImageViews(&mLayerLevelDrawImageViews, device);
12570     DestroyLayerLevelImageViews(&mLayerLevelDrawImageViewsLinear, device);
12571     DestroySubresourceImageViews(&mSubresourceDrawImageViews, device);
12572 
12573     // Release the depth-xor-stencil input views
12574     DestroyLayerLevelImageViews(&mLayerLevelDepthOnlyImageViews, device);
12575     DestroyLayerLevelImageViews(&mLayerLevelStencilOnlyImageViews, device);
12576     DestroySubresourceImageViews(&mSubresourceDepthOnlyImageViews, device);
12577     DestroySubresourceImageViews(&mSubresourceStencilOnlyImageViews, device);
12578 
12579     // Release the storage views
12580     DestroyImageViews(&mLevelStorageImageViews, device);
12581     DestroyLayerLevelImageViews(&mLayerLevelStorageImageViews, device);
12582 
12583     // Destroy fragment shading rate view
12584     mFragmentShadingRateImageView.destroy(device);
12585 
12586     mImageViewSerial = kInvalidImageOrBufferViewSerial;
12587 }
12588 
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)12589 angle::Result ImageViewHelper::initReadViews(ContextVk *contextVk,
12590                                              gl::TextureType viewType,
12591                                              const ImageHelper &image,
12592                                              const gl::SwizzleState &formatSwizzle,
12593                                              const gl::SwizzleState &readSwizzle,
12594                                              LevelIndex baseLevel,
12595                                              uint32_t levelCount,
12596                                              uint32_t baseLayer,
12597                                              uint32_t layerCount,
12598                                              bool requiresSRGBViews,
12599                                              VkImageUsageFlags imageUsageFlags)
12600 {
12601     ASSERT(levelCount > 0);
12602 
12603     const uint32_t maxLevel = levelCount - 1;
12604     ASSERT(maxLevel < 16);
12605     ASSERT(baseLevel.get() < 16);
12606     mCurrentBaseMaxLevelHash = static_cast<uint8_t>(baseLevel.get() << 4 | maxLevel);
12607     updateColorspace(image);
12608 
12609     if (mCurrentBaseMaxLevelHash >= mPerLevelRangeLinearReadImageViews.size())
12610     {
12611         const uint32_t maxViewCount = mCurrentBaseMaxLevelHash + 1;
12612 
12613         mPerLevelRangeLinearReadImageViews.resize(maxViewCount);
12614         mPerLevelRangeSRGBReadImageViews.resize(maxViewCount);
12615         mPerLevelRangeLinearCopyImageViews.resize(maxViewCount);
12616         mPerLevelRangeSRGBCopyImageViews.resize(maxViewCount);
12617         mPerLevelRangeStencilReadImageViews.resize(maxViewCount);
12618         mPerLevelRangeSamplerExternal2DY2YEXTImageViews.resize(maxViewCount);
12619     }
12620 
12621     // Determine if we already have ImageViews for the new max level
12622     if (getReadImageView().valid())
12623     {
12624         return angle::Result::Continue;
12625     }
12626 
12627     // Since we don't have a readImageView, we must create ImageViews for the new max level
12628     if (requiresSRGBViews)
12629     {
12630         // Initialize image views for both linear and srgb colorspaces
12631         ANGLE_TRY(initLinearAndSrgbReadViewsImpl(contextVk, viewType, image, formatSwizzle,
12632                                                  readSwizzle, baseLevel, levelCount, baseLayer,
12633                                                  layerCount, imageUsageFlags));
12634     }
12635     else
12636     {
12637         // Initialize image view for image's format's colorspace
12638         ANGLE_TRY(initReadViewsImpl(contextVk, viewType, image, formatSwizzle, readSwizzle,
12639                                     baseLevel, levelCount, baseLayer, layerCount, imageUsageFlags));
12640     }
12641 
12642     return angle::Result::Continue;
12643 }
12644 
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)12645 angle::Result ImageViewHelper::initReadViewsImpl(ContextVk *contextVk,
12646                                                  gl::TextureType viewType,
12647                                                  const ImageHelper &image,
12648                                                  const gl::SwizzleState &formatSwizzle,
12649                                                  const gl::SwizzleState &readSwizzle,
12650                                                  LevelIndex baseLevel,
12651                                                  uint32_t levelCount,
12652                                                  uint32_t baseLayer,
12653                                                  uint32_t layerCount,
12654                                                  VkImageUsageFlags imageUsageFlags)
12655 {
12656     ASSERT(mImageViewSerial.valid());
12657     ASSERT(mReadColorspace != ImageViewColorspace::Invalid);
12658 
12659     const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(image.getIntendedFormat());
12660 
12661     if (HasBothDepthAndStencilAspects(aspectFlags))
12662     {
12663         ANGLE_TRY(image.initLayerImageViewWithUsage(
12664             contextVk, viewType, VK_IMAGE_ASPECT_DEPTH_BIT, readSwizzle, &getReadImageView(),
12665             baseLevel, levelCount, baseLayer, layerCount, imageUsageFlags));
12666         ANGLE_TRY(image.initLayerImageViewWithUsage(
12667             contextVk, viewType, VK_IMAGE_ASPECT_STENCIL_BIT, readSwizzle,
12668             &mPerLevelRangeStencilReadImageViews[mCurrentBaseMaxLevelHash], baseLevel, levelCount,
12669             baseLayer, layerCount, imageUsageFlags));
12670     }
12671     else
12672     {
12673         ANGLE_TRY(image.initLayerImageViewWithUsage(contextVk, viewType, aspectFlags, readSwizzle,
12674                                                     &getReadImageView(), baseLevel, levelCount,
12675                                                     baseLayer, layerCount, imageUsageFlags));
12676 
12677         if (image.getActualFormat().isYUV)
12678         {
12679             ANGLE_TRY(image.initLayerImageViewWithYuvModeOverride(
12680                 contextVk, viewType, aspectFlags, readSwizzle,
12681                 &getSamplerExternal2DY2YEXTImageView(), baseLevel, levelCount, baseLayer,
12682                 layerCount, gl::YuvSamplingMode::Y2Y, imageUsageFlags));
12683         }
12684     }
12685 
12686     gl::TextureType fetchType = viewType;
12687     if (viewType == gl::TextureType::CubeMap || viewType == gl::TextureType::_2DArray ||
12688         viewType == gl::TextureType::_2DMultisampleArray)
12689     {
12690         fetchType = Get2DTextureType(layerCount, image.getSamples());
12691     }
12692 
12693     if (!image.getActualFormat().isBlock)
12694     {
12695         if (fetchType != viewType || readSwizzle != formatSwizzle ||
12696             HasBothDepthAndStencilAspects(aspectFlags))
12697         {
12698             ANGLE_TRY(image.initLayerImageViewWithUsage(
12699                 contextVk, fetchType, aspectFlags, formatSwizzle, &getCopyImageViewStorage(),
12700                 baseLevel, levelCount, baseLayer, layerCount, imageUsageFlags));
12701         }
12702         else
12703         {
12704             mIsCopyImageViewShared = true;
12705         }
12706     }
12707     return angle::Result::Continue;
12708 }
12709 
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)12710 angle::Result ImageViewHelper::initLinearAndSrgbReadViewsImpl(ContextVk *contextVk,
12711                                                               gl::TextureType viewType,
12712                                                               const ImageHelper &image,
12713                                                               const gl::SwizzleState &formatSwizzle,
12714                                                               const gl::SwizzleState &readSwizzle,
12715                                                               LevelIndex baseLevel,
12716                                                               uint32_t levelCount,
12717                                                               uint32_t baseLayer,
12718                                                               uint32_t layerCount,
12719                                                               VkImageUsageFlags imageUsageFlags)
12720 {
12721     ASSERT(mReadColorspace != ImageViewColorspace::Invalid);
12722 
12723     // When we select the linear/srgb counterpart formats, we must first make sure they're
12724     // actually supported by the ICD. If they are not supported by the ICD, then we treat that as if
12725     // there is no counterpart format.
12726     const bool imageFormatIsSrgb      = image.getActualFormat().isSRGB;
12727     const angle::FormatID imageFormat = image.getActualFormatID();
12728     angle::FormatID srgbFormat = imageFormatIsSrgb ? imageFormat : ConvertToSRGB(imageFormat);
12729     if (srgbFormat != angle::FormatID::NONE &&
12730         !HasNonRenderableTextureFormatSupport(contextVk->getRenderer(), srgbFormat))
12731     {
12732         srgbFormat = angle::FormatID::NONE;
12733     }
12734 
12735     angle::FormatID linearFormat = !imageFormatIsSrgb ? imageFormat : ConvertToLinear(imageFormat);
12736     ASSERT(linearFormat != angle::FormatID::NONE);
12737 
12738     const VkImageAspectFlags aspectFlags = GetFormatAspectFlags(image.getIntendedFormat());
12739 
12740     if (HasBothDepthAndStencilAspects(aspectFlags))
12741     {
12742         ANGLE_TRY(image.initReinterpretedLayerImageView(
12743             contextVk, viewType, VK_IMAGE_ASPECT_DEPTH_BIT, readSwizzle,
12744             &mPerLevelRangeLinearReadImageViews[mCurrentBaseMaxLevelHash], baseLevel, levelCount,
12745             baseLayer, layerCount, imageUsageFlags, linearFormat));
12746 
12747         ANGLE_TRY(image.initReinterpretedLayerImageView(
12748             contextVk, viewType, VK_IMAGE_ASPECT_STENCIL_BIT, readSwizzle,
12749             &mPerLevelRangeStencilReadImageViews[mCurrentBaseMaxLevelHash], baseLevel, levelCount,
12750             baseLayer, layerCount, imageUsageFlags, linearFormat));
12751     }
12752     else
12753     {
12754         if (!mPerLevelRangeLinearReadImageViews[mCurrentBaseMaxLevelHash].valid())
12755         {
12756             ANGLE_TRY(image.initReinterpretedLayerImageView(
12757                 contextVk, viewType, aspectFlags, readSwizzle,
12758                 &mPerLevelRangeLinearReadImageViews[mCurrentBaseMaxLevelHash], baseLevel,
12759                 levelCount, baseLayer, layerCount, imageUsageFlags, linearFormat));
12760         }
12761 
12762         if (srgbFormat != angle::FormatID::NONE &&
12763             !mPerLevelRangeSRGBReadImageViews[mCurrentBaseMaxLevelHash].valid())
12764         {
12765             ANGLE_TRY(image.initReinterpretedLayerImageView(
12766                 contextVk, viewType, aspectFlags, readSwizzle,
12767                 &mPerLevelRangeSRGBReadImageViews[mCurrentBaseMaxLevelHash], baseLevel, levelCount,
12768                 baseLayer, layerCount, imageUsageFlags, srgbFormat));
12769         }
12770 
12771         if (image.getActualFormat().isYUV)
12772         {
12773             ANGLE_TRY(image.initLayerImageViewWithYuvModeOverride(
12774                 contextVk, viewType, aspectFlags, readSwizzle,
12775                 &getSamplerExternal2DY2YEXTImageView(), baseLevel, levelCount, baseLayer,
12776                 layerCount, gl::YuvSamplingMode::Y2Y, imageUsageFlags));
12777         }
12778     }
12779 
12780     gl::TextureType fetchType = viewType;
12781 
12782     if (viewType == gl::TextureType::CubeMap || viewType == gl::TextureType::_2DArray ||
12783         viewType == gl::TextureType::_2DMultisampleArray)
12784     {
12785         fetchType = Get2DTextureType(layerCount, image.getSamples());
12786     }
12787 
12788     if (!image.getActualFormat().isBlock)
12789     {
12790         if (fetchType != viewType || formatSwizzle != readSwizzle ||
12791             HasBothDepthAndStencilAspects(aspectFlags))
12792         {
12793             if (!mPerLevelRangeLinearCopyImageViews[mCurrentBaseMaxLevelHash].valid())
12794             {
12795                 ANGLE_TRY(image.initReinterpretedLayerImageView(
12796                     contextVk, fetchType, aspectFlags, formatSwizzle,
12797                     &mPerLevelRangeLinearCopyImageViews[mCurrentBaseMaxLevelHash], baseLevel,
12798                     levelCount, baseLayer, layerCount, imageUsageFlags, linearFormat));
12799             }
12800             if (srgbFormat != angle::FormatID::NONE &&
12801                 !mPerLevelRangeSRGBCopyImageViews[mCurrentBaseMaxLevelHash].valid())
12802             {
12803                 ANGLE_TRY(image.initReinterpretedLayerImageView(
12804                     contextVk, fetchType, aspectFlags, formatSwizzle,
12805                     &mPerLevelRangeSRGBCopyImageViews[mCurrentBaseMaxLevelHash], baseLevel,
12806                     levelCount, baseLayer, layerCount, imageUsageFlags, srgbFormat));
12807             }
12808         }
12809         else
12810         {
12811             mIsCopyImageViewShared = true;
12812         }
12813     }
12814 
12815     return angle::Result::Continue;
12816 }
12817 
getLevelStorageImageView(ErrorContext * context,gl::TextureType viewType,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,VkImageUsageFlags imageUsageFlags,angle::FormatID formatID,const ImageView ** imageViewOut)12818 angle::Result ImageViewHelper::getLevelStorageImageView(ErrorContext *context,
12819                                                         gl::TextureType viewType,
12820                                                         const ImageHelper &image,
12821                                                         LevelIndex levelVk,
12822                                                         uint32_t layer,
12823                                                         VkImageUsageFlags imageUsageFlags,
12824                                                         angle::FormatID formatID,
12825                                                         const ImageView **imageViewOut)
12826 {
12827     ASSERT(mImageViewSerial.valid());
12828 
12829     ImageView *imageView =
12830         GetLevelImageView(&mLevelStorageImageViews, levelVk, image.getLevelCount());
12831 
12832     *imageViewOut = imageView;
12833     if (imageView->valid())
12834     {
12835         return angle::Result::Continue;
12836     }
12837 
12838     // Create the view.  Note that storage images are not affected by swizzle parameters.
12839     return image.initReinterpretedLayerImageView(context, viewType, image.getAspectFlags(),
12840                                                  gl::SwizzleState(), imageView, levelVk, 1, layer,
12841                                                  image.getLayerCount(), imageUsageFlags, formatID);
12842 }
12843 
getLevelLayerStorageImageView(ErrorContext * contextVk,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,VkImageUsageFlags imageUsageFlags,angle::FormatID formatID,const ImageView ** imageViewOut)12844 angle::Result ImageViewHelper::getLevelLayerStorageImageView(ErrorContext *contextVk,
12845                                                              const ImageHelper &image,
12846                                                              LevelIndex levelVk,
12847                                                              uint32_t layer,
12848                                                              VkImageUsageFlags imageUsageFlags,
12849                                                              angle::FormatID formatID,
12850                                                              const ImageView **imageViewOut)
12851 {
12852     ASSERT(image.valid());
12853     ASSERT(mImageViewSerial.valid());
12854     ASSERT(!image.getActualFormat().isBlock);
12855 
12856     ImageView *imageView =
12857         GetLevelLayerImageView(&mLayerLevelStorageImageViews, levelVk, layer, image.getLevelCount(),
12858                                GetImageLayerCountForView(image));
12859     *imageViewOut = imageView;
12860 
12861     if (imageView->valid())
12862     {
12863         return angle::Result::Continue;
12864     }
12865 
12866     // Create the view.  Note that storage images are not affected by swizzle parameters.
12867     gl::TextureType viewType = Get2DTextureType(1, image.getSamples());
12868     return image.initReinterpretedLayerImageView(contextVk, viewType, image.getAspectFlags(),
12869                                                  gl::SwizzleState(), imageView, levelVk, 1, layer,
12870                                                  1, imageUsageFlags, formatID);
12871 }
12872 
getLevelLayerDrawImageViewImpl(ErrorContext * context,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,uint32_t layerCount,ImageView * imageViewOut)12873 angle::Result ImageViewHelper::getLevelLayerDrawImageViewImpl(ErrorContext *context,
12874                                                               const ImageHelper &image,
12875                                                               LevelIndex levelVk,
12876                                                               uint32_t layer,
12877                                                               uint32_t layerCount,
12878                                                               ImageView *imageViewOut)
12879 {
12880     ASSERT(imageViewOut != nullptr);
12881 
12882     // If we are initializing an imageview for use with EXT_srgb_write_control, we need to override
12883     // the format to its linear counterpart. Formats that cannot be reinterpreted are exempt from
12884     // this requirement.
12885     angle::FormatID actualFormat = image.getActualFormatID();
12886     angle::FormatID linearFormat = ConvertToLinear(actualFormat);
12887     angle::FormatID sRGBFormat   = ConvertToSRGB(actualFormat);
12888     if (mWriteColorspace == ImageViewColorspace::Linear && linearFormat != angle::FormatID::NONE)
12889     {
12890         actualFormat = linearFormat;
12891     }
12892     else if (mWriteColorspace == ImageViewColorspace::SRGB && sRGBFormat != angle::FormatID::NONE)
12893     {
12894         actualFormat = sRGBFormat;
12895     }
12896 
12897     // Note that these views are specifically made to be used as framebuffer attachments, and
12898     // therefore don't have swizzle.
12899     return image.initReinterpretedLayerImageView(
12900         context, Get2DTextureType(layerCount, image.getSamples()), image.getAspectFlags(),
12901         gl::SwizzleState(), imageViewOut, levelVk, 1, layer, layerCount,
12902         vk::ImageHelper::kDefaultImageViewUsageFlags, actualFormat);
12903 }
12904 
getLevelDrawImageView(ErrorContext * context,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,uint32_t layerCount,const ImageView ** imageViewOut)12905 angle::Result ImageViewHelper::getLevelDrawImageView(ErrorContext *context,
12906                                                      const ImageHelper &image,
12907                                                      LevelIndex levelVk,
12908                                                      uint32_t layer,
12909                                                      uint32_t layerCount,
12910                                                      const ImageView **imageViewOut)
12911 {
12912     ASSERT(image.valid());
12913     ASSERT(mImageViewSerial.valid());
12914     ASSERT(!image.getActualFormat().isBlock);
12915 
12916     if (mWriteColorspace == ImageViewColorspace::Invalid)
12917     {
12918         updateColorspace(image);
12919     }
12920     ASSERT(mWriteColorspace != ImageViewColorspace::Invalid);
12921 
12922     ImageSubresourceRange range = MakeImageSubresourceDrawRange(image.toGLLevel(levelVk), layer,
12923                                                                 GetLayerMode(image, layerCount),
12924                                                                 mReadColorspace, mWriteColorspace);
12925 
12926     std::unique_ptr<ImageView> &view = mSubresourceDrawImageViews[range];
12927     if (view)
12928     {
12929         *imageViewOut = view.get();
12930         return angle::Result::Continue;
12931     }
12932 
12933     view          = std::make_unique<ImageView>();
12934     *imageViewOut = view.get();
12935 
12936     return getLevelLayerDrawImageViewImpl(context, image, levelVk, layer, layerCount, view.get());
12937 }
12938 
getLevelLayerDrawImageView(ErrorContext * context,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,const ImageView ** imageViewOut)12939 angle::Result ImageViewHelper::getLevelLayerDrawImageView(ErrorContext *context,
12940                                                           const ImageHelper &image,
12941                                                           LevelIndex levelVk,
12942                                                           uint32_t layer,
12943                                                           const ImageView **imageViewOut)
12944 {
12945     ASSERT(image.valid());
12946     ASSERT(mImageViewSerial.valid());
12947     ASSERT(!image.getActualFormat().isBlock);
12948 
12949     if (mWriteColorspace == ImageViewColorspace::Invalid)
12950     {
12951         updateColorspace(image);
12952     }
12953     ASSERT(mWriteColorspace != ImageViewColorspace::Invalid);
12954 
12955     LayerLevelImageViewVector &imageViews = (mWriteColorspace == ImageViewColorspace::Linear)
12956                                                 ? mLayerLevelDrawImageViewsLinear
12957                                                 : mLayerLevelDrawImageViews;
12958 
12959     // Lazily allocate the storage for image views
12960     ImageView *imageView = GetLevelLayerImageView(
12961         &imageViews, levelVk, layer, image.getLevelCount(), GetImageLayerCountForView(image));
12962     *imageViewOut = imageView;
12963 
12964     if (imageView->valid())
12965     {
12966         return angle::Result::Continue;
12967     }
12968 
12969     return getLevelLayerDrawImageViewImpl(context, image, levelVk, layer, 1, imageView);
12970 }
12971 
getLevelDepthOrStencilImageView(ErrorContext * context,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,uint32_t layerCount,VkImageAspectFlagBits aspect,const ImageView ** imageViewOut)12972 angle::Result ImageViewHelper::getLevelDepthOrStencilImageView(ErrorContext *context,
12973                                                                const ImageHelper &image,
12974                                                                LevelIndex levelVk,
12975                                                                uint32_t layer,
12976                                                                uint32_t layerCount,
12977                                                                VkImageAspectFlagBits aspect,
12978                                                                const ImageView **imageViewOut)
12979 {
12980     ASSERT(image.valid());
12981     ASSERT(mImageViewSerial.valid());
12982     ASSERT((image.getAspectFlags() & aspect) != 0);
12983 
12984     ImageSubresourceRange range = MakeImageSubresourceDrawRange(
12985         image.toGLLevel(levelVk), layer, GetLayerMode(image, layerCount),
12986         ImageViewColorspace::Linear, ImageViewColorspace::Linear);
12987 
12988     SubresourceImageViewMap &imageViews = aspect == VK_IMAGE_ASPECT_DEPTH_BIT
12989                                               ? mSubresourceDepthOnlyImageViews
12990                                               : mSubresourceStencilOnlyImageViews;
12991 
12992     std::unique_ptr<ImageView> &view = imageViews[range];
12993     if (view)
12994     {
12995         *imageViewOut = view.get();
12996         return angle::Result::Continue;
12997     }
12998 
12999     view          = std::make_unique<ImageView>();
13000     *imageViewOut = view.get();
13001 
13002     return getLevelLayerDepthOrStencilImageViewImpl(context, image, levelVk, layer, layerCount,
13003                                                     aspect, view.get());
13004 }
13005 
getLevelLayerDepthOrStencilImageView(ErrorContext * context,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,VkImageAspectFlagBits aspect,const ImageView ** imageViewOut)13006 angle::Result ImageViewHelper::getLevelLayerDepthOrStencilImageView(ErrorContext *context,
13007                                                                     const ImageHelper &image,
13008                                                                     LevelIndex levelVk,
13009                                                                     uint32_t layer,
13010                                                                     VkImageAspectFlagBits aspect,
13011                                                                     const ImageView **imageViewOut)
13012 {
13013     ASSERT(image.valid());
13014     ASSERT(mImageViewSerial.valid());
13015     ASSERT((image.getAspectFlags() & aspect) != 0);
13016 
13017     LayerLevelImageViewVector &imageViews = aspect == VK_IMAGE_ASPECT_DEPTH_BIT
13018                                                 ? mLayerLevelDepthOnlyImageViews
13019                                                 : mLayerLevelStencilOnlyImageViews;
13020 
13021     // Lazily allocate the storage for image views
13022     ImageView *imageView = GetLevelLayerImageView(
13023         &imageViews, levelVk, layer, image.getLevelCount(), GetImageLayerCountForView(image));
13024     *imageViewOut = imageView;
13025 
13026     if (imageView->valid())
13027     {
13028         return angle::Result::Continue;
13029     }
13030 
13031     return getLevelLayerDepthOrStencilImageViewImpl(context, image, levelVk, layer, 1, aspect,
13032                                                     imageView);
13033 }
13034 
getLevelLayerDepthOrStencilImageViewImpl(ErrorContext * context,const ImageHelper & image,LevelIndex levelVk,uint32_t layer,uint32_t layerCount,VkImageAspectFlagBits aspect,ImageView * imageViewOut)13035 angle::Result ImageViewHelper::getLevelLayerDepthOrStencilImageViewImpl(
13036     ErrorContext *context,
13037     const ImageHelper &image,
13038     LevelIndex levelVk,
13039     uint32_t layer,
13040     uint32_t layerCount,
13041     VkImageAspectFlagBits aspect,
13042     ImageView *imageViewOut)
13043 {
13044     // Note that these views are specifically made to be used as input attachments, and
13045     // therefore don't have swizzle.
13046     return image.initReinterpretedLayerImageView(
13047         context, Get2DTextureType(layerCount, image.getSamples()), aspect, gl::SwizzleState(),
13048         imageViewOut, levelVk, 1, layer, layerCount, vk::ImageHelper::kDefaultImageViewUsageFlags,
13049         image.getActualFormatID());
13050 }
13051 
initFragmentShadingRateView(ContextVk * contextVk,ImageHelper * image)13052 angle::Result ImageViewHelper::initFragmentShadingRateView(ContextVk *contextVk, ImageHelper *image)
13053 {
13054     ASSERT(image->valid());
13055     ASSERT(mImageViewSerial.valid());
13056 
13057     // Determine if we already have ImageView
13058     if (mFragmentShadingRateImageView.valid())
13059     {
13060         return angle::Result::Continue;
13061     }
13062 
13063     // Fragment shading rate image view always have -
13064     // - gl::TextureType    == gl::TextureType::_2D
13065     // - VkImageAspectFlags == VK_IMAGE_ASPECT_COLOR_BIT
13066     // - gl::SwizzleState   == gl::SwizzleState()
13067     // - baseMipLevelVk     == vk::LevelIndex(0)
13068     // - levelCount         == 1
13069     // - baseArrayLayer     == 0
13070     // - layerCount         == 1
13071     return image->initLayerImageViewWithUsage(
13072         contextVk, gl::TextureType::_2D, VK_IMAGE_ASPECT_COLOR_BIT, gl::SwizzleState(),
13073         &mFragmentShadingRateImageView, vk::LevelIndex(0), 1, 0, 1, image->getUsage());
13074 }
13075 
getColorspaceOverrideFormatForWrite(angle::FormatID format) const13076 angle::FormatID ImageViewHelper::getColorspaceOverrideFormatForWrite(angle::FormatID format) const
13077 {
13078     ASSERT(mWriteColorspace != ImageViewColorspace::Invalid);
13079 
13080     angle::FormatID colorspaceOverrideFormat = format;
13081     angle::FormatID linearFormat             = ConvertToLinear(format);
13082     angle::FormatID sRGBFormat               = ConvertToSRGB(format);
13083     if (mWriteColorspace == ImageViewColorspace::Linear && linearFormat != angle::FormatID::NONE)
13084     {
13085         colorspaceOverrideFormat = linearFormat;
13086     }
13087     else if (mWriteColorspace == ImageViewColorspace::SRGB && sRGBFormat != angle::FormatID::NONE)
13088     {
13089         colorspaceOverrideFormat = sRGBFormat;
13090     }
13091 
13092     return colorspaceOverrideFormat;
13093 }
13094 
updateColorspace(const ImageHelper & image) const13095 void ImageViewHelper::updateColorspace(const ImageHelper &image) const
13096 {
13097     const angle::Format &imageFormat        = image.getActualFormat();
13098     ImageViewColorspace imageViewColorspace = ImageViewColorspace::Invalid;
13099     mReadColorspace                         = ImageViewColorspace::Invalid;
13100     mWriteColorspace                        = ImageViewColorspace::Invalid;
13101 
13102     // Initialize colorspace based on image's format's colorspace
13103     imageViewColorspace =
13104         imageFormat.isSRGB ? ImageViewColorspace::SRGB : ImageViewColorspace::Linear;
13105 
13106     // Process EGL image colorspace override state
13107     if (!imageFormat.isSRGB && mColorspaceState.eglImageColorspace == egl::ImageColorspace::SRGB)
13108     {
13109         imageViewColorspace = ImageViewColorspace::SRGB;
13110     }
13111     else if (imageFormat.isSRGB &&
13112              mColorspaceState.eglImageColorspace == egl::ImageColorspace::Linear)
13113     {
13114         imageViewColorspace = ImageViewColorspace::Linear;
13115     }
13116     ASSERT(imageViewColorspace != ImageViewColorspace::Invalid);
13117 
13118     mReadColorspace  = imageViewColorspace;
13119     mWriteColorspace = imageViewColorspace;
13120 
13121     // Process srgb decode and srgb override state
13122     if (mReadColorspace == ImageViewColorspace::Linear)
13123     {
13124         if (mColorspaceState.srgbOverride == gl::SrgbOverride::SRGB &&
13125             rx::ConvertToSRGB(imageFormat.id) != angle::FormatID::NONE &&
13126             mColorspaceState.srgbDecode != gl::SrgbDecode::Skip)
13127         {
13128             mReadColorspace = ImageViewColorspace::SRGB;
13129         }
13130     }
13131     else
13132     {
13133         ASSERT(mReadColorspace == ImageViewColorspace::SRGB);
13134 
13135         if (mColorspaceState.srgbDecode == gl::SrgbDecode::Skip &&
13136             !mColorspaceState.hasStaticTexelFetchAccess)
13137         {
13138             mReadColorspace = ImageViewColorspace::Linear;
13139         }
13140     }
13141 
13142     // Process srgb write control state
13143     if (mWriteColorspace == ImageViewColorspace::SRGB &&
13144         mColorspaceState.srgbWriteControl == gl::SrgbWriteControlMode::Linear)
13145     {
13146         mWriteColorspace = ImageViewColorspace::Linear;
13147     }
13148 
13149     ASSERT(mReadColorspace != ImageViewColorspace::Invalid);
13150     ASSERT(mWriteColorspace != ImageViewColorspace::Invalid);
13151 }
13152 
getSubresourceSerial(gl::LevelIndex levelGL,uint32_t levelCount,uint32_t layer,LayerMode layerMode) const13153 ImageOrBufferViewSubresourceSerial ImageViewHelper::getSubresourceSerial(gl::LevelIndex levelGL,
13154                                                                          uint32_t levelCount,
13155                                                                          uint32_t layer,
13156                                                                          LayerMode layerMode) const
13157 {
13158     return getSubresourceSerialForColorspace(levelGL, levelCount, layer, layerMode,
13159                                              mReadColorspace);
13160 }
13161 
getSubresourceSerialForColorspace(gl::LevelIndex levelGL,uint32_t levelCount,uint32_t layer,LayerMode layerMode,ImageViewColorspace readColorspace) const13162 ImageOrBufferViewSubresourceSerial ImageViewHelper::getSubresourceSerialForColorspace(
13163     gl::LevelIndex levelGL,
13164     uint32_t levelCount,
13165     uint32_t layer,
13166     LayerMode layerMode,
13167     ImageViewColorspace readColorspace) const
13168 {
13169     ASSERT(mImageViewSerial.valid());
13170 
13171     ImageOrBufferViewSubresourceSerial serial;
13172     serial.viewSerial  = mImageViewSerial;
13173     serial.subresource = MakeImageSubresourceReadRange(levelGL, levelCount, layer, layerMode,
13174                                                        readColorspace, mWriteColorspace);
13175     return serial;
13176 }
13177 
getSubresourceDrawRange(gl::LevelIndex level,uint32_t layer,LayerMode layerMode) const13178 ImageSubresourceRange ImageViewHelper::getSubresourceDrawRange(gl::LevelIndex level,
13179                                                                uint32_t layer,
13180                                                                LayerMode layerMode) const
13181 {
13182     return MakeImageSubresourceDrawRange(level, layer, layerMode, mReadColorspace,
13183                                          mWriteColorspace);
13184 }
13185 
13186 // BufferViewHelper implementation.
BufferViewHelper()13187 BufferViewHelper::BufferViewHelper() : mInitialized(false), mOffset(0), mSize(0) {}
13188 
BufferViewHelper(BufferViewHelper && other)13189 BufferViewHelper::BufferViewHelper(BufferViewHelper &&other) : Resource(std::move(other))
13190 {
13191     std::swap(mInitialized, other.mInitialized);
13192     std::swap(mOffset, other.mOffset);
13193     std::swap(mSize, other.mSize);
13194     std::swap(mViews, other.mViews);
13195     std::swap(mViewSerial, other.mViewSerial);
13196 }
13197 
~BufferViewHelper()13198 BufferViewHelper::~BufferViewHelper() {}
13199 
init(Renderer * renderer,VkDeviceSize offset,VkDeviceSize size)13200 void BufferViewHelper::init(Renderer *renderer, VkDeviceSize offset, VkDeviceSize size)
13201 {
13202     ASSERT(mViews.empty());
13203 
13204     mOffset = offset;
13205     mSize   = size;
13206 
13207     if (!mViewSerial.valid())
13208     {
13209         mViewSerial = renderer->getResourceSerialFactory().generateImageOrBufferViewSerial();
13210     }
13211 
13212     mInitialized = true;
13213 }
13214 
release(Renderer * renderer)13215 void BufferViewHelper::release(Renderer *renderer)
13216 {
13217     if (!mInitialized)
13218     {
13219         return;
13220     }
13221 
13222     GarbageObjects garbage;
13223 
13224     for (auto &formatAndView : mViews)
13225     {
13226         BufferView &view = formatAndView.second;
13227         ASSERT(view.valid());
13228 
13229         garbage.emplace_back(GetGarbage(&view));
13230     }
13231 
13232     if (!garbage.empty())
13233     {
13234         renderer->collectGarbage(mUse, std::move(garbage));
13235         // Update image view serial.
13236         mViewSerial = renderer->getResourceSerialFactory().generateImageOrBufferViewSerial();
13237     }
13238 
13239     mUse.reset();
13240     mViews.clear();
13241     mOffset      = 0;
13242     mSize        = 0;
13243     mInitialized = false;
13244 }
13245 
release(ContextVk * contextVk)13246 void BufferViewHelper::release(ContextVk *contextVk)
13247 {
13248     if (!mInitialized)
13249     {
13250         return;
13251     }
13252 
13253     contextVk->flushDescriptorSetUpdates();
13254     return release(contextVk->getRenderer());
13255 }
13256 
destroy(VkDevice device)13257 void BufferViewHelper::destroy(VkDevice device)
13258 {
13259     for (auto &formatAndView : mViews)
13260     {
13261         BufferView &view = formatAndView.second;
13262         view.destroy(device);
13263     }
13264 
13265     mViews.clear();
13266 
13267     mOffset = 0;
13268     mSize   = 0;
13269 
13270     mViewSerial = kInvalidImageOrBufferViewSerial;
13271 }
13272 
getView(ErrorContext * context,const BufferHelper & buffer,VkDeviceSize bufferOffset,const Format & format,const BufferView ** viewOut)13273 angle::Result BufferViewHelper::getView(ErrorContext *context,
13274                                         const BufferHelper &buffer,
13275                                         VkDeviceSize bufferOffset,
13276                                         const Format &format,
13277                                         const BufferView **viewOut)
13278 {
13279     ASSERT(format.valid());
13280 
13281     vk::Renderer *renderer = context->getRenderer();
13282     VkFormat viewVkFormat  = format.getActualBufferVkFormat(renderer, false);
13283 
13284     auto iter = mViews.find(viewVkFormat);
13285     if (iter != mViews.end())
13286     {
13287         *viewOut = &iter->second;
13288         return angle::Result::Continue;
13289     }
13290 
13291     // If the size is not a multiple of pixelBytes, remove the extra bytes.  The last element cannot
13292     // be read anyway, and this is a requirement of Vulkan (for size to be a multiple of format
13293     // texel block size).
13294     const angle::Format &bufferFormat = format.getActualBufferFormat(false);
13295     const GLuint pixelBytes           = bufferFormat.pixelBytes;
13296     VkDeviceSize size                 = mSize - mSize % pixelBytes;
13297 
13298     VkBufferViewCreateInfo viewCreateInfo = {};
13299     viewCreateInfo.sType                  = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO;
13300     viewCreateInfo.buffer                 = buffer.getBuffer().getHandle();
13301     viewCreateInfo.format                 = viewVkFormat;
13302     viewCreateInfo.offset                 = mOffset + bufferOffset;
13303     viewCreateInfo.range                  = size;
13304 
13305     BufferView view;
13306     ANGLE_VK_TRY(context, view.init(context->getDevice(), viewCreateInfo));
13307 
13308     // Cache the view
13309     auto insertIter = mViews.insert({viewVkFormat, std::move(view)});
13310     *viewOut        = &insertIter.first->second;
13311     ASSERT(insertIter.second);
13312 
13313     return angle::Result::Continue;
13314 }
13315 
getSerial() const13316 ImageOrBufferViewSubresourceSerial BufferViewHelper::getSerial() const
13317 {
13318     ASSERT(mViewSerial.valid());
13319 
13320     ImageOrBufferViewSubresourceSerial serial = {};
13321     serial.viewSerial                         = mViewSerial;
13322     return serial;
13323 }
13324 
13325 // ShaderProgramHelper implementation.
13326 ShaderProgramHelper::ShaderProgramHelper()  = default;
13327 ShaderProgramHelper::~ShaderProgramHelper() = default;
13328 
valid(const gl::ShaderType shaderType) const13329 bool ShaderProgramHelper::valid(const gl::ShaderType shaderType) const
13330 {
13331     return mShaders[shaderType];
13332 }
13333 
destroy(Renderer * renderer)13334 void ShaderProgramHelper::destroy(Renderer *renderer)
13335 {
13336     for (ShaderModulePtr &shader : mShaders)
13337     {
13338         shader.reset();
13339     }
13340 }
13341 
release(ContextVk * contextVk)13342 void ShaderProgramHelper::release(ContextVk *contextVk)
13343 {
13344     for (ShaderModulePtr &shader : mShaders)
13345     {
13346         shader.reset();
13347     }
13348 }
13349 
setShader(gl::ShaderType shaderType,const ShaderModulePtr & shader)13350 void ShaderProgramHelper::setShader(gl::ShaderType shaderType, const ShaderModulePtr &shader)
13351 {
13352     // The shaders must be set once and are not expected to change.
13353     ASSERT(!mShaders[shaderType]);
13354     ASSERT(shader && shader->valid());
13355     mShaders[shaderType] = shader;
13356 }
13357 
createMonolithicPipelineCreationTask(vk::ErrorContext * context,PipelineCacheAccess * pipelineCache,const GraphicsPipelineDesc & desc,const PipelineLayout & pipelineLayout,const SpecializationConstants & specConsts,PipelineHelper * pipeline) const13358 void ShaderProgramHelper::createMonolithicPipelineCreationTask(
13359     vk::ErrorContext *context,
13360     PipelineCacheAccess *pipelineCache,
13361     const GraphicsPipelineDesc &desc,
13362     const PipelineLayout &pipelineLayout,
13363     const SpecializationConstants &specConsts,
13364     PipelineHelper *pipeline) const
13365 {
13366     std::shared_ptr<CreateMonolithicPipelineTask> monolithicPipelineCreationTask =
13367         std::make_shared<CreateMonolithicPipelineTask>(context->getRenderer(), *pipelineCache,
13368                                                        pipelineLayout, mShaders, specConsts, desc);
13369 
13370     pipeline->setMonolithicPipelineCreationTask(std::move(monolithicPipelineCreationTask));
13371 }
13372 
getOrCreateComputePipeline(vk::ErrorContext * context,ComputePipelineCache * computePipelines,PipelineCacheAccess * pipelineCache,const PipelineLayout & pipelineLayout,ComputePipelineOptions pipelineOptions,PipelineSource source,PipelineHelper ** pipelineOut,const char * shaderName,VkSpecializationInfo * specializationInfo) const13373 angle::Result ShaderProgramHelper::getOrCreateComputePipeline(
13374     vk::ErrorContext *context,
13375     ComputePipelineCache *computePipelines,
13376     PipelineCacheAccess *pipelineCache,
13377     const PipelineLayout &pipelineLayout,
13378     ComputePipelineOptions pipelineOptions,
13379     PipelineSource source,
13380     PipelineHelper **pipelineOut,
13381     const char *shaderName,
13382     VkSpecializationInfo *specializationInfo) const
13383 {
13384     return computePipelines->getOrCreatePipeline(context, pipelineCache, pipelineLayout,
13385                                                  pipelineOptions, source, pipelineOut, shaderName,
13386                                                  specializationInfo, mShaders);
13387 }
13388 
13389 // ActiveHandleCounter implementation.
ActiveHandleCounter()13390 ActiveHandleCounter::ActiveHandleCounter() : mActiveCounts{}, mAllocatedCounts{} {}
13391 
13392 ActiveHandleCounter::~ActiveHandleCounter() = default;
13393 
13394 // CommandBufferAccess implementation.
13395 CommandBufferAccess::CommandBufferAccess()  = default;
13396 CommandBufferAccess::~CommandBufferAccess() = default;
13397 
onBufferRead(VkAccessFlags readAccessType,PipelineStage readStage,BufferHelper * buffer)13398 void CommandBufferAccess::onBufferRead(VkAccessFlags readAccessType,
13399                                        PipelineStage readStage,
13400                                        BufferHelper *buffer)
13401 {
13402     ASSERT(!buffer->isReleasedToExternal());
13403     mReadBuffers.emplace_back(buffer, readAccessType, readStage);
13404 }
13405 
onBufferWrite(VkAccessFlags writeAccessType,PipelineStage writeStage,BufferHelper * buffer)13406 void CommandBufferAccess::onBufferWrite(VkAccessFlags writeAccessType,
13407                                         PipelineStage writeStage,
13408                                         BufferHelper *buffer)
13409 {
13410     ASSERT(!buffer->isReleasedToExternal());
13411     mWriteBuffers.emplace_back(buffer, writeAccessType, writeStage);
13412 }
13413 
onImageRead(VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)13414 void CommandBufferAccess::onImageRead(VkImageAspectFlags aspectFlags,
13415                                       ImageLayout imageLayout,
13416                                       ImageHelper *image)
13417 {
13418     ASSERT(!image->isReleasedToExternal());
13419     ASSERT(image->getImageSerial().valid());
13420     mReadImages.emplace_back(image, aspectFlags, imageLayout);
13421 }
13422 
onImageWrite(gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)13423 void CommandBufferAccess::onImageWrite(gl::LevelIndex levelStart,
13424                                        uint32_t levelCount,
13425                                        uint32_t layerStart,
13426                                        uint32_t layerCount,
13427                                        VkImageAspectFlags aspectFlags,
13428                                        ImageLayout imageLayout,
13429                                        ImageHelper *image)
13430 {
13431     ASSERT(!image->isReleasedToExternal());
13432     ASSERT(image->getImageSerial().valid());
13433     mWriteImages.emplace_back(CommandBufferImageAccess{image, aspectFlags, imageLayout}, levelStart,
13434                               levelCount, layerStart, layerCount);
13435 }
13436 
onImageReadSubresources(gl::LevelIndex levelStart,uint32_t levelCount,uint32_t layerStart,uint32_t layerCount,VkImageAspectFlags aspectFlags,ImageLayout imageLayout,ImageHelper * image)13437 void CommandBufferAccess::onImageReadSubresources(gl::LevelIndex levelStart,
13438                                                   uint32_t levelCount,
13439                                                   uint32_t layerStart,
13440                                                   uint32_t layerCount,
13441                                                   VkImageAspectFlags aspectFlags,
13442                                                   ImageLayout imageLayout,
13443                                                   ImageHelper *image)
13444 {
13445     ASSERT(!image->isReleasedToExternal());
13446     ASSERT(image->getImageSerial().valid());
13447     mReadImageSubresources.emplace_back(CommandBufferImageAccess{image, aspectFlags, imageLayout},
13448                                         levelStart, levelCount, layerStart, layerCount);
13449 }
13450 
onBufferExternalAcquireRelease(BufferHelper * buffer)13451 void CommandBufferAccess::onBufferExternalAcquireRelease(BufferHelper *buffer)
13452 {
13453     mExternalAcquireReleaseBuffers.emplace_back(CommandBufferBufferExternalAcquireRelease{buffer});
13454 }
13455 
onResourceAccess(Resource * resource)13456 void CommandBufferAccess::onResourceAccess(Resource *resource)
13457 {
13458     mAccessResources.emplace_back(CommandBufferResourceAccess{resource});
13459 }
13460 
13461 // DescriptorMetaCache implementation.
13462 MetaDescriptorPool::MetaDescriptorPool() = default;
13463 
~MetaDescriptorPool()13464 MetaDescriptorPool::~MetaDescriptorPool()
13465 {
13466     ASSERT(mPayload.empty());
13467 }
13468 
destroy(Renderer * renderer)13469 void MetaDescriptorPool::destroy(Renderer *renderer)
13470 {
13471     for (auto &iter : mPayload)
13472     {
13473         DynamicDescriptorPoolPointer &pool = iter.second;
13474         ASSERT(pool.unique());
13475     }
13476     mPayload.clear();
13477 }
13478 
bindCachedDescriptorPool(ErrorContext * context,const DescriptorSetLayoutDesc & descriptorSetLayoutDesc,uint32_t descriptorCountMultiplier,DescriptorSetLayoutCache * descriptorSetLayoutCache,DynamicDescriptorPoolPointer * dynamicDescriptorPoolOut)13479 angle::Result MetaDescriptorPool::bindCachedDescriptorPool(
13480     ErrorContext *context,
13481     const DescriptorSetLayoutDesc &descriptorSetLayoutDesc,
13482     uint32_t descriptorCountMultiplier,
13483     DescriptorSetLayoutCache *descriptorSetLayoutCache,
13484     DynamicDescriptorPoolPointer *dynamicDescriptorPoolOut)
13485 {
13486     if (descriptorSetLayoutDesc.empty())
13487     {
13488         // No need for descriptorSet pool.
13489         return angle::Result::Continue;
13490     }
13491 
13492     auto cacheIter = mPayload.find(descriptorSetLayoutDesc);
13493     if (cacheIter != mPayload.end())
13494     {
13495         *dynamicDescriptorPoolOut = cacheIter->second;
13496         return angle::Result::Continue;
13497     }
13498 
13499     DescriptorSetLayoutPtr descriptorSetLayout;
13500     ANGLE_TRY(descriptorSetLayoutCache->getDescriptorSetLayout(context, descriptorSetLayoutDesc,
13501                                                                &descriptorSetLayout));
13502 
13503     DynamicDescriptorPool newDescriptorPool;
13504     ANGLE_TRY(InitDynamicDescriptorPool(context, descriptorSetLayoutDesc, *descriptorSetLayout,
13505                                         descriptorCountMultiplier, &newDescriptorPool));
13506 
13507     ASSERT(newDescriptorPool.valid());
13508     DynamicDescriptorPoolPointer newDynamicDescriptorPoolPtr(context->getDevice(),
13509                                                              std::move(newDescriptorPool));
13510     mPayload.emplace(descriptorSetLayoutDesc, newDynamicDescriptorPoolPtr);
13511     *dynamicDescriptorPoolOut = std::move(newDynamicDescriptorPoolPtr);
13512 
13513     return angle::Result::Continue;
13514 }
13515 
13516 static_assert(static_cast<uint32_t>(PresentMode::ImmediateKHR) == VK_PRESENT_MODE_IMMEDIATE_KHR,
13517               "PresentMode must be updated");
13518 static_assert(static_cast<uint32_t>(PresentMode::MailboxKHR) == VK_PRESENT_MODE_MAILBOX_KHR,
13519               "PresentMode must be updated");
13520 static_assert(static_cast<uint32_t>(PresentMode::FifoKHR) == VK_PRESENT_MODE_FIFO_KHR,
13521               "PresentMode must be updated");
13522 static_assert(static_cast<uint32_t>(PresentMode::FifoRelaxedKHR) ==
13523                   VK_PRESENT_MODE_FIFO_RELAXED_KHR,
13524               "PresentMode must be updated");
13525 static_assert(static_cast<uint32_t>(PresentMode::SharedDemandRefreshKHR) ==
13526                   VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR,
13527               "PresentMode must be updated");
13528 static_assert(static_cast<uint32_t>(PresentMode::SharedContinuousRefreshKHR) ==
13529                   VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR,
13530               "PresentMode must be updated");
13531 
ConvertPresentModeToVkPresentMode(PresentMode presentMode)13532 VkPresentModeKHR ConvertPresentModeToVkPresentMode(PresentMode presentMode)
13533 {
13534     return static_cast<VkPresentModeKHR>(presentMode);
13535 }
13536 
ConvertVkPresentModeToPresentMode(VkPresentModeKHR vkPresentMode)13537 PresentMode ConvertVkPresentModeToPresentMode(VkPresentModeKHR vkPresentMode)
13538 {
13539     return static_cast<PresentMode>(vkPresentMode);
13540 }
13541 
13542 }  // namespace vk
13543 }  // namespace rx
13544