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